From 1c3990dbba6a1e594c8a273e85c8460d90d29643 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Thu, 28 Oct 2004 10:12:57 +0000 Subject: H.261 encoder by (Maarten Daniels ) Originally committed as revision 3643 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/h261.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) (limited to 'libavcodec/h261.c') diff --git a/libavcodec/h261.c b/libavcodec/h261.c index ca8f29716e..0992e76be0 100644 --- a/libavcodec/h261.c +++ b/libavcodec/h261.c @@ -47,6 +47,7 @@ typedef struct H261Context{ MpegEncContext s; int current_mba; + int previous_mba; int mba_diff; int mtype; int current_mv_x; @@ -76,11 +77,330 @@ void ff_h261_loop_filter(MpegEncContext *s){ s->dsp.h261_loop_filter(dest_cr, uvlinesize); } +int ff_h261_get_picture_format(int width, int height){ + // QCIF + if (width == 176 && height == 144) + return 0; + // CIF + else if (width == 352 && height == 288) + return 1; + // ERROR + else + return -1; +} + +static void h261_encode_block(H261Context * h, DCTELEM * block, + int n); static int h261_decode_block(H261Context *h, DCTELEM *block, int n, int coded); static int h261_decode_mb(H261Context *h); void ff_set_qscale(MpegEncContext * s, int qscale); +void ff_h261_encode_picture_header(MpegEncContext * s, int picture_number){ + H261Context * h = (H261Context *) s; + int format, coded_frame_rate, coded_frame_rate_base, temp_ref; + int best_clock_code=1; + int best_divisor=60; + coded_frame_rate= 1800000; + coded_frame_rate_base= (1000+best_clock_code)*best_divisor; + + align_put_bits(&s->pb); + + /* Update the pointer to last GOB */ + s->ptr_lastgob = pbBufPtr(&s->pb); + + put_bits(&s->pb, 20, 0x10); /* PSC */ + + temp_ref= s->picture_number * (int64_t)coded_frame_rate * s->avctx->frame_rate_base / + (coded_frame_rate_base * (int64_t)s->avctx->frame_rate); + put_bits(&s->pb, 5, temp_ref & 0x1f); /* TemporalReference */ + + put_bits(&s->pb, 1, 0); /* split screen off */ + put_bits(&s->pb, 1, 0); /* camera off */ + put_bits(&s->pb, 1, 0); /* freeze picture release off */ + + format = ff_h261_get_picture_format(s->width, s->height); + + put_bits(&s->pb, 1, format); /* 0 == QCIF, 1 == CIF */ + + put_bits(&s->pb, 1, 0); /* still image mode */ + put_bits(&s->pb, 1, 0); /* reserved */ + + put_bits(&s->pb, 1, 0); /* no PEI */ + if(format == 0) + h->gob_number = -1; + else + h->gob_number = 0; + h->current_mba = 0; +} + +/** + * Encodes a group of blocks header. + */ +static void h261_encode_gob_header(MpegEncContext * s, int mb_line){ + H261Context * h = (H261Context *)s; + if(ff_h261_get_picture_format(s->width, s->height) == 0){ + h->gob_number+=2; // QCIF + } + else{ + h->gob_number++; // CIF + } + put_bits(&s->pb, 16, 1); /* GBSC */ + put_bits(&s->pb, 4, h->gob_number); /* GN */ + put_bits(&s->pb, 5, s->qscale); /* GQUANT */ + put_bits(&s->pb, 1, 0); /* no GEI */ + h->current_mba = 0; + h->previous_mba = 0; + h->current_mv_x=0; + h->current_mv_y=0; +} + +void ff_h261_reorder_mb_index(MpegEncContext* s){ + /* for CIF the GOB's are fragmented in the middle of a scanline + that's why we need to adjust the x and y index of the macroblocks */ + if(ff_h261_get_picture_format(s->width,s->height) == 1){ // CIF + if((s->mb_x == 0 && (s->mb_y % 3 == 0) ) || (s->mb_x == 11 && ((s->mb_y -1 )% 3 == 0) )) + h261_encode_gob_header(s,0); + if(s->mb_x < 11 ){ + if((s->mb_y % 3) == 1 ){ + s->mb_x += 0; + s->mb_y += 1; + } + else if( (s->mb_y % 3) == 2 ){ + s->mb_x += 11; + s->mb_y -= 1; + } + } + else{ + if((s->mb_y % 3) == 1 ){ + s->mb_x += 0; + s->mb_y -= 1; + } + else if( (s->mb_y % 3) == 0 ){ + s->mb_x -= 11; + s->mb_y += 1; + } + } + ff_init_block_index(s); + ff_update_block_index(s); + /* for QCIF we don't need to reorder MB's + there the GOB's aren't fragmented in the middle of a scanline */ + }else if(ff_h261_get_picture_format(s->width,s->height) == 0){ // QCIF + if(s->mb_y % 3 == 0 && s->mb_x == 0) + h261_encode_gob_header(s,0); + } +} + +static void h261_encode_motion(H261Context * h, int val){ + MpegEncContext * const s = &h->s; + int sign, code; + if(val==0){ + code = 0; + put_bits(&s->pb,h261_mv_tab[code][1],h261_mv_tab[code][0]); + } + else{ + if(val > 16) + val -=32; + if(val < -16) + val+=32; + sign = val < 0; + code = sign ? -val : val; + put_bits(&s->pb,h261_mv_tab[code][1],h261_mv_tab[code][0]); + put_bits(&s->pb,1,sign); + } +} + +static inline int get_cbp(MpegEncContext * s, + DCTELEM block[6][64]) +{ + int i, cbp; + cbp= 0; + for (i = 0; i < 6; i++) { + if (s->block_last_index[i] >= 0) + cbp |= 1 << (5 - i); + } + return cbp; +} +void ff_h261_encode_mb(MpegEncContext * s, + DCTELEM block[6][64], + int motion_x, int motion_y) +{ + H261Context * h = (H261Context *)s; + int old_mtype, mvd, mv_diff_x, mv_diff_y, i, cbp; + cbp = 63; // avoid warning + mvd = 0; + + h->current_mba++; + old_mtype = h->mtype; + h->mtype = 0; + + if (!s->mb_intra){ + /* compute cbp */ + cbp= get_cbp(s, block); + + /* mvd indicates if this block is motion compensated */ + if(((motion_x >> 1) - h->current_mv_x != 0) || ((motion_y >> 1 ) - h->current_mv_y) != 0){ + mvd = 1; + } + else if((motion_x >> 1 == 0) && (motion_y >> 1 == 0)){ + mvd = 0; + } + else + mvd = 1; + if((cbp | mvd | s->dquant ) == 0) { + /* skip macroblock */ + s->skip_count++; + h->current_mv_x=0; + h->current_mv_y=0; + return; + } + } + + /* MB is not skipped, encode MBA */ + put_bits(&s->pb, h261_mba_bits[(h->current_mba-h->previous_mba)-1], h261_mba_code[(h->current_mba-h->previous_mba)-1]); + + /* calculate MTYPE */ + if(!s->mb_intra){ + h->mtype+=2; + if(mvd == 1){ + h->mtype+=2; + if(cbp!=0) + h->mtype+=1; + if(s->loop_filter) + h->mtype+=3; + } + } + + if(s->dquant) + h->mtype++; + + put_bits(&s->pb, h261_mtype_bits[h->mtype], h261_mtype_code[h->mtype]); + + h->mtype = h261_mtype_map[h->mtype]; + + if(IS_QUANT(h->mtype)){ + ff_set_qscale(s,s->qscale+s->dquant); + put_bits(&s->pb, 5, s->qscale); + } + + if(IS_16X16(h->mtype)){ + mv_diff_x = (motion_x >> 1) - h->current_mv_x; + mv_diff_y = (motion_y >> 1) - h->current_mv_y; + h->current_mv_x = (motion_x >> 1); + h->current_mv_y = (motion_y >> 1); + h261_encode_motion(h,mv_diff_x); + h261_encode_motion(h,mv_diff_y); + } + + h->previous_mba = h->current_mba; + + if(HAS_CBP(h->mtype)){ + put_bits(&s->pb,h261_cbp_tab[cbp-1][1],h261_cbp_tab[cbp-1][0]); + } + for(i=0; i<6; i++) { + /* encode each block */ + h261_encode_block(h, block[i], i); + } + + if ( ( h->current_mba == 11 ) || ( h->current_mba == 22 ) || ( h->current_mba == 33 ) || ( !IS_16X16 ( h->mtype ) )){ + h->current_mv_x=0; + h->current_mv_y=0; + } +} + +void ff_h261_encode_init(MpegEncContext *s){ + static int done = 0; + + if (!done) { + done = 1; + init_rl(&h261_rl_tcoeff); + } + + s->min_qcoeff= -127; + s->max_qcoeff= 127; + s->y_dc_scale_table= + s->c_dc_scale_table= ff_mpeg1_dc_scale_table; +} + + +/** + * encodes a 8x8 block. + * @param block the 8x8 block + * @param n block index (0-3 are luma, 4-5 are chroma) + */ +static void h261_encode_block(H261Context * h, DCTELEM * block, int n){ + MpegEncContext * const s = &h->s; + int level, run, last, i, j, last_index, last_non_zero, sign, slevel, code; + RLTable *rl; + + rl = &h261_rl_tcoeff; + if (s->mb_intra) { + /* DC coef */ + level = block[0]; + /* 255 cannot be represented, so we clamp */ + if (level > 254) { + level = 254; + block[0] = 254; + } + /* 0 cannot be represented also */ + else if (level < 1) { + level = 1; + block[0] = 1; + } + if (level == 128) + put_bits(&s->pb, 8, 0xff); + else + put_bits(&s->pb, 8, level); + i = 1; + } else if((block[0]==1 || block[0] == -1) && (s->block_last_index[n] > -1)){ + //special case + put_bits(&s->pb,1,1); + put_bits(&s->pb,1,block[0]>0 ? 0 : 1 ); + i = 1; + } else { + i = 0; + } + + /* AC coefs */ + last_index = s->block_last_index[n]; + last_non_zero = i - 1; + for (; i <= last_index; i++) { + j = s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + run = i - last_non_zero - 1; + last = (i == last_index); + sign = 0; + slevel = level; + if (level < 0) { + sign = 1; + level = -level; + } + code = get_rl_index(rl, 0 /*no last in H.261, EOB is used*/, run, level); + if(run==0 && level < 16) + code+=1; + put_bits(&s->pb, rl->table_vlc[code][1], rl->table_vlc[code][0]); + if (code == rl->n) { + put_bits(&s->pb, 6, run); + assert(slevel != 0); + if(slevel < -127){ + slevel = -127; + } + else if(slevel > 127){ + slevel = 127; + } + put_bits(&s->pb, 8, slevel & 0xff); + } else { + put_bits(&s->pb, 1, sign); + } + last_non_zero = i; + } + } + if(last_index > -1){ + put_bits(&s->pb, rl->table_vlc[0][1], rl->table_vlc[0][0]);// END OF BLOCK + } +} + /***********************************************/ /* decoding */ @@ -767,6 +1087,16 @@ static int h261_decode_end(AVCodecContext *avctx) return 0; } +AVCodec h261_encoder = { + "h261", + CODEC_TYPE_VIDEO, + CODEC_ID_H261, + sizeof(H261Context), + MPV_encode_init, + MPV_encode_picture, + MPV_encode_end, +}; + AVCodec h261_decoder = { "h261", CODEC_TYPE_VIDEO, -- cgit v1.2.3