diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index d8409bd78e..c63a308856 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -59,6 +59,7 @@ void avcodec_register_all(void) // 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); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 2856a75f9c..ae4c6f14c1 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1786,6 +1786,7 @@ extern AVCodec faac_encoder; 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; 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, diff --git a/libavcodec/i386/mpegvideo_mmx_template.c b/libavcodec/i386/mpegvideo_mmx_template.c index 8520daab34..c9354dc1bb 100644 --- a/libavcodec/i386/mpegvideo_mmx_template.c +++ b/libavcodec/i386/mpegvideo_mmx_template.c @@ -88,7 +88,7 @@ static int RENAME(dct_quantize)(MpegEncContext *s, 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 diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c index 64550edffc..cf36d931a4 100644 --- a/libavcodec/motion_est.c +++ b/libavcodec/motion_est.c @@ -279,6 +279,10 @@ void ff_init_me(MpegEncContext *s){ 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 @@ static inline void get_limits(MpegEncContext *s, int x, int y) 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; diff --git a/libavcodec/motion_est_template.c b/libavcodec/motion_est_template.c index 567202149e..1f5c742a41 100644 --- a/libavcodec/motion_est_template.c +++ b/libavcodec/motion_est_template.c @@ -221,6 +221,16 @@ static int hpel_motion_search(MpegEncContext * s, } #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) { diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index fc7cd00540..12ce8a6a0a 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -1080,6 +1080,11 @@ int MPV_encode_init(AVCodecContext *avctx) 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 @@ int MPV_encode_init(AVCodecContext *avctx) #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 @@ int MPV_encode_init(AVCodecContext *avctx) 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 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) 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 @@ static int encode_thread(AVCodecContext *c, void *arg){ 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 @@ static void encode_picture(MpegEncContext *s, int picture_number) 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); diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 17c2dab05d..775b6bcbf0 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -865,6 +865,12 @@ extern const uint8_t ff_h263_loop_filter_strength[32]; /* 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 */ diff --git a/libavformat/raw.c b/libavformat/raw.c index 2ae744943d..bfb5e1ae5c 100644 --- a/libavformat/raw.c +++ b/libavformat/raw.c @@ -344,6 +344,21 @@ AVInputFormat h261_iformat = { .value = CODEC_ID_H261, }; +#ifdef CONFIG_ENCODERS +AVOutputFormat h261_oformat = { + "h261", + "raw h261", + "video/x-h261", + "h261", + 0, + 0, + CODEC_ID_H261, + raw_write_header, + raw_write_packet, + raw_write_trailer, +}; +#endif //CONFIG_ENCODERS + AVInputFormat h263_iformat = { "h263", "raw h263", @@ -648,6 +663,7 @@ int raw_init(void) av_register_input_format(&dts_iformat); av_register_input_format(&h261_iformat); + av_register_output_format(&h261_oformat); av_register_input_format(&h263_iformat); av_register_output_format(&h263_oformat);