Mercurial > libavcodec.hg
changeset 2327:5e5cf598a48b libavcodec
H.261 encoder by (Maarten Daniels <maarten dot daniels at luc dot ac dot be>)
author | michael |
---|---|
date | Thu, 28 Oct 2004 10:12:57 +0000 |
parents | fe1986d6230f |
children | 7b5353eb0dd8 |
files | allcodecs.c avcodec.h h261.c i386/mpegvideo_mmx_template.c motion_est.c motion_est_template.c mpegvideo.c mpegvideo.h |
diffstat | 8 files changed, 379 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/allcodecs.c Wed Oct 27 21:42:26 2004 +0000 +++ b/allcodecs.c Thu Oct 28 10:12:57 2004 +0000 @@ -59,6 +59,7 @@ // register_avcodec(&h264_encoder); #ifdef CONFIG_RISKY register_avcodec(&mpeg2video_encoder); + register_avcodec(&h261_encoder); register_avcodec(&h263_encoder); register_avcodec(&h263p_encoder); register_avcodec(&flv_encoder);
--- a/avcodec.h Wed Oct 27 21:42:26 2004 +0000 +++ b/avcodec.h Thu Oct 28 10:12:57 2004 +0000 @@ -1786,6 +1786,7 @@ extern AVCodec xvid_encoder; extern AVCodec mpeg1video_encoder; extern AVCodec mpeg2video_encoder; +extern AVCodec h261_encoder; extern AVCodec h263_encoder; extern AVCodec h263p_encoder; extern AVCodec flv_encoder;
--- a/h261.c Wed Oct 27 21:42:26 2004 +0000 +++ b/h261.c Thu Oct 28 10:12:57 2004 +0000 @@ -47,6 +47,7 @@ MpegEncContext s; int current_mba; + int previous_mba; int mba_diff; int mtype; int current_mv_x; @@ -76,11 +77,330 @@ 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 @@ 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,
--- a/i386/mpegvideo_mmx_template.c Wed Oct 27 21:42:26 2004 +0000 +++ b/i386/mpegvideo_mmx_template.c Thu Oct 28 10:12:57 2004 +0000 @@ -88,7 +88,7 @@ qmat = s->q_inter_matrix16[qscale][0]; } - if(s->out_format == FMT_H263 && s->mpeg_quant==0){ + if((s->out_format == FMT_H263 || s->out_format == FMT_H261) && s->mpeg_quant==0){ asm volatile( "movd %%"REG_a", %%mm3 \n\t" // last_non_zero_p1
--- a/motion_est.c Wed Oct 27 21:42:26 2004 +0000 +++ b/motion_est.c Thu Oct 28 10:12:57 2004 +0000 @@ -279,6 +279,10 @@ c->hpel_put[2][2]= c->hpel_put[2][3]= zero_hpel; } + if(s->codec_id == CODEC_ID_H261){ + c->sub_motion_search= no_sub_motion_search; + } + c->temp= c->scratchpad; } @@ -691,6 +695,12 @@ c->ymin = - y - 16; c->xmax = - x + s->mb_width *16; c->ymax = - y + s->mb_height*16; + } else if (s->out_format == FMT_H261){ + // Search range of H261 is different from other codec standards + c->xmin = (x > 15) ? - 15 : 0; + c->ymin = (y > 15) ? - 15 : 0; + c->xmax = (x < s->mb_width * 16 - 16) ? 15 : 0; + c->ymax = (y < s->mb_height * 16 - 16) ? 15 : 0; } else { c->xmin = - x; c->ymin = - y;
--- a/motion_est_template.c Wed Oct 27 21:42:26 2004 +0000 +++ b/motion_est_template.c Thu Oct 28 10:12:57 2004 +0000 @@ -221,6 +221,16 @@ } #endif +static int no_sub_motion_search(MpegEncContext * s, + int *mx_ptr, int *my_ptr, int dmin, + int src_index, int ref_index, + int size, int h) +{ + (*mx_ptr)<<=1; + (*my_ptr)<<=1; + return dmin; +} + int inline ff_get_mb_score(MpegEncContext * s, int mx, int my, int src_index, int ref_index, int size, int h, int add_rate) {
--- a/mpegvideo.c Wed Oct 27 21:42:26 2004 +0000 +++ b/mpegvideo.c Thu Oct 28 10:12:57 2004 +0000 @@ -1080,6 +1080,11 @@ s->low_delay=1; break; #ifdef CONFIG_RISKY + case CODEC_ID_H261: + s->out_format = FMT_H261; + avctx->delay=0; + s->low_delay=1; + break; case CODEC_ID_H263: if (h263_get_picture_format(s->width, s->height) == 7) { av_log(avctx, AV_LOG_INFO, "Input picture size isn't suitable for h263 codec! try h263+\n"); @@ -1199,6 +1204,8 @@ #ifdef CONFIG_ENCODERS #ifdef CONFIG_RISKY + if (s->out_format == FMT_H261) + ff_h261_encode_init(s); if (s->out_format == FMT_H263) h263_encode_init(s); if(s->msmpeg4_version) @@ -1215,7 +1222,7 @@ if(s->codec_id==CODEC_ID_MPEG4 && s->mpeg_quant){ s->intra_matrix[j] = ff_mpeg4_default_intra_matrix[i]; s->inter_matrix[j] = ff_mpeg4_default_non_intra_matrix[i]; - }else if(s->out_format == FMT_H263){ + }else if(s->out_format == FMT_H263 || s->out_format == FMT_H261){ s->intra_matrix[j] = s->inter_matrix[j] = ff_mpeg1_default_non_intra_matrix[i]; }else @@ -4127,6 +4134,8 @@ msmpeg4_encode_mb(s, s->block, motion_x, motion_y); break; case CODEC_ID_WMV2: ff_wmv2_encode_mb(s, s->block, motion_x, motion_y); break; + case CODEC_ID_H261: + ff_h261_encode_mb(s, s->block, motion_x, motion_y); break; case CODEC_ID_H263: case CODEC_ID_H263P: case CODEC_ID_FLV1: @@ -4495,15 +4504,21 @@ ff_init_block_index(s); for(mb_x=0; mb_x < s->mb_width; mb_x++) { - const int xy= mb_y*s->mb_stride + mb_x; + int xy= mb_y*s->mb_stride + mb_x; // removed const, H261 needs to adjust this int mb_type= s->mb_type[xy]; // int d; int dmin= INT_MAX; int dir; s->mb_x = mb_x; + s->mb_y = mb_y; // moved into loop, can get changed by H.261 ff_update_block_index(s); + if(s->codec_id == CODEC_ID_H261){ + ff_h261_reorder_mb_index(s); + xy= s->mb_y*s->mb_stride + s->mb_x; + } + /* write gob / video packet header */ #ifdef CONFIG_RISKY if(s->rtp_mode){ @@ -5215,6 +5230,9 @@ mjpeg_picture_header(s); break; #ifdef CONFIG_RISKY + case FMT_H261: + ff_h261_encode_picture_header(s, picture_number); + break; case FMT_H263: if (s->codec_id == CODEC_ID_WMV2) ff_wmv2_encode_picture_header(s, picture_number);
--- a/mpegvideo.h Wed Oct 27 21:42:26 2004 +0000 +++ b/mpegvideo.h Thu Oct 28 10:12:57 2004 +0000 @@ -865,6 +865,12 @@ /* h261.c */ void ff_h261_loop_filter(MpegEncContext *s); +void ff_h261_reorder_mb_index(MpegEncContext* s); +void ff_h261_encode_mb(MpegEncContext *s, + DCTELEM block[6][64], + int motion_x, int motion_y); +void ff_h261_encode_picture_header(MpegEncContext * s, int picture_number); +void ff_h261_encode_init(MpegEncContext *s); /* h263.c, h263dec.c */