diff options
author | Baptiste Coudurier <baptiste.coudurier@gmail.com> | 2006-05-16 15:19:54 +0000 |
---|---|---|
committer | Baptiste Coudurier <baptiste.coudurier@gmail.com> | 2006-05-16 15:19:54 +0000 |
commit | 2d974017b03503c09082eff5558c3b2606dbcdaf (patch) | |
tree | 675a111c8620a323985d87f5e8d537a34132e0f8 /libavcodec | |
parent | c2f69579bb9cb929fb2cfcba426f524f0f107169 (diff) | |
download | ffmpeg-2d974017b03503c09082eff5558c3b2606dbcdaf.tar.gz |
MPEG-2 4:2:2 encoding support
Originally committed as revision 5387 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/mpeg12.c | 69 | ||||
-rw-r--r-- | libavcodec/mpegvideo.c | 125 | ||||
-rw-r--r-- | libavcodec/mpegvideo.h | 2 |
3 files changed, 134 insertions, 62 deletions
diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 86377850d2..d805ae5903 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -232,6 +232,12 @@ static int encode_init(AVCodecContext *avctx) } } + if(avctx->profile == FF_PROFILE_UNKNOWN) + avctx->profile = s->chroma_format == CHROMA_420 ? 4 : 0; + + if(avctx->level == FF_LEVEL_UNKNOWN) + avctx->level = s->chroma_format == CHROMA_420 ? 8 : 5; + return 0; } @@ -319,22 +325,14 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) if(s->codec_id == CODEC_ID_MPEG2VIDEO){ put_header(s, EXT_START_CODE); put_bits(&s->pb, 4, 1); //seq ext - put_bits(&s->pb, 1, 0); //esc - if(s->avctx->profile == FF_PROFILE_UNKNOWN){ - put_bits(&s->pb, 3, 4); //profile - }else{ - put_bits(&s->pb, 3, s->avctx->profile); //profile - } + put_bits(&s->pb, 1, s->chroma_format == CHROMA_422); //escx - if(s->avctx->level == FF_LEVEL_UNKNOWN){ - put_bits(&s->pb, 4, 8); //level - }else{ - put_bits(&s->pb, 4, s->avctx->level); //level - } + put_bits(&s->pb, 3, s->avctx->profile); //profile + put_bits(&s->pb, 4, s->avctx->level); //level put_bits(&s->pb, 1, s->progressive_sequence); - put_bits(&s->pb, 2, 1); //chroma format 4:2:0 + put_bits(&s->pb, 2, s->chroma_format); put_bits(&s->pb, 2, 0); //horizontal size ext put_bits(&s->pb, 2, 0); //vertical size ext put_bits(&s->pb, 12, v>>18); //bitrate ext @@ -468,7 +466,7 @@ void mpeg1_encode_picture_header(MpegEncContext *s, int picture_number) put_bits(&s->pb, 1, s->alternate_scan); put_bits(&s->pb, 1, s->repeat_first_field); s->progressive_frame = s->progressive_sequence; - put_bits(&s->pb, 1, s->chroma_420_type=s->progressive_frame); + put_bits(&s->pb, 1, s->chroma_format == CHROMA_420 ? s->progressive_frame : 0); /* chroma_420_type */ put_bits(&s->pb, 1, s->progressive_frame); put_bits(&s->pb, 1, 0); //composite_display_flag } @@ -496,9 +494,10 @@ static inline void put_mb_modes(MpegEncContext *s, int n, int bits, } } -void mpeg1_encode_mb(MpegEncContext *s, - DCTELEM block[6][64], - int motion_x, int motion_y) +static always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, + DCTELEM block[6][64], + int motion_x, int motion_y, + int mb_block_count) { int i, cbp; const int mb_x = s->mb_x; @@ -507,9 +506,9 @@ void mpeg1_encode_mb(MpegEncContext *s, /* compute cbp */ cbp = 0; - for(i=0;i<6;i++) { + for(i=0;i<mb_block_count;i++) { if (s->block_last_index[i] >= 0) - cbp |= 1 << (5 - i); + cbp |= 1 << (mb_block_count - 1 - i); } if (cbp == 0 && !first_mb && s->mv_type == MV_TYPE_16X16 && @@ -615,8 +614,14 @@ void mpeg1_encode_mb(MpegEncContext *s, } s->mv_bits+= get_bits_diff(s); } - if(cbp) - put_bits(&s->pb, mbPatTable[cbp][1], mbPatTable[cbp][0]); + if(cbp) { + if (s->chroma_y_shift) { + put_bits(&s->pb, mbPatTable[cbp][1], mbPatTable[cbp][0]); + } else { + put_bits(&s->pb, mbPatTable[cbp>>2][1], mbPatTable[cbp>>2][0]); + put_bits(&s->pb, 2, cbp & 3); + } + } s->f_count++; } else{ static const int mb_type_len[4]={0,3,4,2}; //bak,for,bi @@ -694,11 +699,17 @@ void mpeg1_encode_mb(MpegEncContext *s, } } s->mv_bits += get_bits_diff(s); - if(cbp) - put_bits(&s->pb, mbPatTable[cbp][1], mbPatTable[cbp][0]); + if(cbp) { + if (s->chroma_y_shift) { + put_bits(&s->pb, mbPatTable[cbp][1], mbPatTable[cbp][0]); + } else { + put_bits(&s->pb, mbPatTable[cbp>>2][1], mbPatTable[cbp>>2][0]); + put_bits(&s->pb, 2, cbp & 3); + } + } } - for(i=0;i<6;i++) { - if (cbp & (1 << (5 - i))) { + for(i=0;i<mb_block_count;i++) { + if (cbp & (1 << (mb_block_count - 1 - i))) { mpeg1_encode_block(s, block[i], i); } } @@ -710,6 +721,12 @@ void mpeg1_encode_mb(MpegEncContext *s, } } +void mpeg1_encode_mb(MpegEncContext *s, DCTELEM block[6][64], int motion_x, int motion_y) +{ + if (s->chroma_format == CHROMA_420) mpeg1_encode_mb_internal(s, block, motion_x, motion_y, 6); + else mpeg1_encode_mb_internal(s, block, motion_x, motion_y, 8); +} + // RAL: Parameter added: f_or_b_code static void mpeg1_encode_motion(MpegEncContext *s, int val, int f_or_b_code) { @@ -905,7 +922,7 @@ static void mpeg1_encode_block(MpegEncContext *s, /* DC coef */ if (s->mb_intra) { - component = (n <= 3 ? 0 : n - 4 + 1); + component = (n <= 3 ? 0 : (n&1) + 1); dc = block[0]; /* overflow is impossible */ diff = dc - s->last_dc[component]; encode_dc(s, diff, component); @@ -3249,7 +3266,7 @@ AVCodec mpeg2video_encoder = { MPV_encode_picture, MPV_encode_end, .supported_framerates= frame_rate_tab+1, - .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_YUV422P, -1}, .capabilities= CODEC_CAP_DELAY, }; #endif diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 803f2c4702..f5d514c8ff 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -927,23 +927,39 @@ int MPV_encode_init(AVCodecContext *avctx) MPV_encode_defaults(s); - if(avctx->pix_fmt != PIX_FMT_YUVJ420P && avctx->pix_fmt != PIX_FMT_YUV420P){ - av_log(avctx, AV_LOG_ERROR, "only YUV420 is supported\n"); - return -1; - } - - if(avctx->codec_id == CODEC_ID_MJPEG || avctx->codec_id == CODEC_ID_LJPEG){ - if(avctx->strict_std_compliance>FF_COMPLIANCE_INOFFICIAL && avctx->pix_fmt != PIX_FMT_YUVJ420P){ + switch (avctx->codec_id) { + case CODEC_ID_MPEG2VIDEO: + if(avctx->pix_fmt != PIX_FMT_YUV420P && avctx->pix_fmt != PIX_FMT_YUV422P){ + av_log(avctx, AV_LOG_ERROR, "only YUV420 and YUV422 are supported\n"); + return -1; + } + break; + case CODEC_ID_LJPEG: + case CODEC_ID_MJPEG: + if(avctx->pix_fmt != PIX_FMT_YUVJ420P && (avctx->pix_fmt != PIX_FMT_YUV420P || avctx->strict_std_compliance>FF_COMPLIANCE_INOFFICIAL)){ av_log(avctx, AV_LOG_ERROR, "colorspace not supported in jpeg\n"); return -1; } - }else{ - if(avctx->strict_std_compliance>FF_COMPLIANCE_INOFFICIAL && avctx->pix_fmt != PIX_FMT_YUV420P){ - av_log(avctx, AV_LOG_ERROR, "colorspace not supported\n"); + break; + default: + if(avctx->pix_fmt != PIX_FMT_YUV420P){ + av_log(avctx, AV_LOG_ERROR, "only YUV420 is supported\n"); return -1; } } + switch (avctx->pix_fmt) { + case PIX_FMT_YUVJ422P: + case PIX_FMT_YUV422P: + s->chroma_format = CHROMA_422; + break; + case PIX_FMT_YUVJ420P: + case PIX_FMT_YUV420P: + default: + s->chroma_format = CHROMA_420; + break; + } + s->bit_rate = avctx->bit_rate; s->width = avctx->width; s->height = avctx->height; @@ -2466,11 +2482,6 @@ int MPV_encode_picture(AVCodecContext *avctx, AVFrame *pic_arg = data; int i, stuffing_count; - if(avctx->pix_fmt != PIX_FMT_YUV420P && avctx->pix_fmt != PIX_FMT_YUVJ420P){ - av_log(avctx, AV_LOG_ERROR, "this codec supports only YUV420P\n"); - return -1; - } - for(i=0; i<avctx->thread_count; i++){ int start_y= s->thread_context[i]->start_mb_y; int end_y= s->thread_context[i]-> end_mb_y; @@ -3968,8 +3979,17 @@ static always_inline void MPV_decode_mb_internal(MpegEncContext *s, DCTELEM bloc add_dequant_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); if(!(s->flags&CODEC_FLAG_GRAY)){ - add_dequant_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); - add_dequant_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); + if (s->chroma_y_shift){ + add_dequant_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); + add_dequant_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); + }else{ + dct_linesize >>= 1; + dct_offset >>=1; + add_dequant_dct(s, block[4], 4, dest_cb, dct_linesize, s->chroma_qscale); + add_dequant_dct(s, block[5], 5, dest_cr, dct_linesize, s->chroma_qscale); + add_dequant_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->chroma_qscale); + add_dequant_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->chroma_qscale); + } } } else if(s->codec_id != CODEC_ID_WMV2){ add_dct(s, block[0], 0, dest_y , dct_linesize); @@ -4011,8 +4031,17 @@ static always_inline void MPV_decode_mb_internal(MpegEncContext *s, DCTELEM bloc put_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); if(!(s->flags&CODEC_FLAG_GRAY)){ - put_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); - put_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); + if(s->chroma_y_shift){ + put_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); + put_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); + }else{ + dct_offset >>=1; + dct_linesize >>=1; + put_dct(s, block[4], 4, dest_cb, dct_linesize, s->chroma_qscale); + put_dct(s, block[5], 5, dest_cr, dct_linesize, s->chroma_qscale); + put_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->chroma_qscale); + put_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->chroma_qscale); + } } }else{ s->dsp.idct_put(dest_y , dct_linesize, block[0]); @@ -4234,19 +4263,19 @@ static void get_vissual_weight(int16_t *weight, uint8_t *ptr, int stride){ } } -static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) +static always_inline void encode_mb_internal(MpegEncContext *s, int motion_x, int motion_y, int mb_block_height, int mb_block_count) { - int16_t weight[6][64]; - DCTELEM orig[6][64]; + int16_t weight[8][64]; + DCTELEM orig[8][64]; const int mb_x= s->mb_x; const int mb_y= s->mb_y; int i; - int skip_dct[6]; + int skip_dct[8]; int dct_offset = s->linesize*8; //default for progressive frames uint8_t *ptr_y, *ptr_cb, *ptr_cr; int wrap_y, wrap_c; - for(i=0; i<6; i++) skip_dct[i]=0; + for(i=0; i<mb_block_count; i++) skip_dct[i]=0; if(s->adaptive_quant){ const int last_qp= s->qscale; @@ -4282,16 +4311,16 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) wrap_y = s->linesize; wrap_c = s->uvlinesize; ptr_y = s->new_picture.data[0] + (mb_y * 16 * wrap_y) + mb_x * 16; - ptr_cb = s->new_picture.data[1] + (mb_y * 8 * wrap_c) + mb_x * 8; - ptr_cr = s->new_picture.data[2] + (mb_y * 8 * wrap_c) + mb_x * 8; + ptr_cb = s->new_picture.data[1] + (mb_y * mb_block_height * wrap_c) + mb_x * 8; + ptr_cr = s->new_picture.data[2] + (mb_y * mb_block_height * wrap_c) + mb_x * 8; if(mb_x*16+16 > s->width || mb_y*16+16 > s->height){ uint8_t *ebuf= s->edge_emu_buffer + 32; ff_emulated_edge_mc(ebuf , ptr_y , wrap_y,16,16,mb_x*16,mb_y*16, s->width , s->height); ptr_y= ebuf; - ff_emulated_edge_mc(ebuf+18*wrap_y , ptr_cb, wrap_c, 8, 8, mb_x*8, mb_y*8, s->width>>1, s->height>>1); + ff_emulated_edge_mc(ebuf+18*wrap_y , ptr_cb, wrap_c, 8, mb_block_height, mb_x*8, mb_y*8, s->width>>1, s->height>>1); ptr_cb= ebuf+18*wrap_y; - ff_emulated_edge_mc(ebuf+18*wrap_y+8, ptr_cr, wrap_c, 8, 8, mb_x*8, mb_y*8, s->width>>1, s->height>>1); + ff_emulated_edge_mc(ebuf+18*wrap_y+8, ptr_cr, wrap_c, 8, mb_block_height, mb_x*8, mb_y*8, s->width>>1, s->height>>1); ptr_cr= ebuf+18*wrap_y+8; } @@ -4311,6 +4340,8 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) dct_offset= wrap_y; wrap_y<<=1; + if (s->chroma_format == CHROMA_422) + wrap_c<<=1; } } } @@ -4326,6 +4357,10 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) }else{ s->dsp.get_pixels(s->block[4], ptr_cb, wrap_c); s->dsp.get_pixels(s->block[5], ptr_cr, wrap_c); + if(!s->chroma_y_shift){ /* 422 */ + s->dsp.get_pixels(s->block[6], ptr_cb + (dct_offset>>1), wrap_c); + s->dsp.get_pixels(s->block[7], ptr_cr + (dct_offset>>1), wrap_c); + } } }else{ op_pixels_func (*op_pix)[4]; @@ -4371,6 +4406,8 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) dct_offset= wrap_y; wrap_y<<=1; + if (s->chroma_format == CHROMA_422) + wrap_c<<=1; } } } @@ -4386,6 +4423,10 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) }else{ s->dsp.diff_pixels(s->block[4], ptr_cb, dest_cb, wrap_c); s->dsp.diff_pixels(s->block[5], ptr_cr, dest_cr, wrap_c); + if(!s->chroma_y_shift){ /* 422 */ + s->dsp.diff_pixels(s->block[6], ptr_cb + (dct_offset>>1), dest_cb + (dct_offset>>1), wrap_c); + s->dsp.diff_pixels(s->block[7], ptr_cr + (dct_offset>>1), dest_cr + (dct_offset>>1), wrap_c); + } } /* pre quantization */ if(s->current_picture.mc_mb_var[s->mb_stride*mb_y+ mb_x]<2*s->qscale*s->qscale){ @@ -4396,6 +4437,10 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) if(s->dsp.sad[1](NULL, ptr_y +dct_offset+ 8, dest_y +dct_offset+ 8, wrap_y, 8) < 20*s->qscale) skip_dct[3]= 1; if(s->dsp.sad[1](NULL, ptr_cb , dest_cb , wrap_c, 8) < 20*s->qscale) skip_dct[4]= 1; if(s->dsp.sad[1](NULL, ptr_cr , dest_cr , wrap_c, 8) < 20*s->qscale) skip_dct[5]= 1; + if(!s->chroma_y_shift){ /* 422 */ + if(s->dsp.sad[1](NULL, ptr_cb +(dct_offset>>1), dest_cb +(dct_offset>>1), wrap_c, 8) < 20*s->qscale) skip_dct[6]= 1; + if(s->dsp.sad[1](NULL, ptr_cr +(dct_offset>>1), dest_cr +(dct_offset>>1), wrap_c, 8) < 20*s->qscale) skip_dct[7]= 1; + } } } @@ -4406,13 +4451,17 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) if(!skip_dct[3]) get_vissual_weight(weight[3], ptr_y + dct_offset + 8, wrap_y); if(!skip_dct[4]) get_vissual_weight(weight[4], ptr_cb , wrap_c); if(!skip_dct[5]) get_vissual_weight(weight[5], ptr_cr , wrap_c); - memcpy(orig[0], s->block[0], sizeof(DCTELEM)*64*6); + if(!s->chroma_y_shift){ /* 422 */ + if(!skip_dct[6]) get_vissual_weight(weight[6], ptr_cb + (dct_offset>>1), wrap_c); + if(!skip_dct[7]) get_vissual_weight(weight[7], ptr_cr + (dct_offset>>1), wrap_c); + } + memcpy(orig[0], s->block[0], sizeof(DCTELEM)*64*mb_block_count); } /* DCT & quantize */ assert(s->out_format!=FMT_MJPEG || s->qscale==8); { - for(i=0;i<6;i++) { + for(i=0;i<mb_block_count;i++) { if(!skip_dct[i]){ int overflow; s->block_last_index[i] = s->dct_quantize(s, s->block[i], i, s->qscale, &overflow); @@ -4424,7 +4473,7 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) s->block_last_index[i]= -1; } if(s->avctx->quantizer_noise_shaping){ - for(i=0;i<6;i++) { + for(i=0;i<mb_block_count;i++) { if(!skip_dct[i]){ s->block_last_index[i] = dct_quantize_refine(s, s->block[i], weight[i], orig[i], i, s->qscale); } @@ -4435,11 +4484,11 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) for(i=0; i<4; i++) dct_single_coeff_elimination(s, i, s->luma_elim_threshold); if(s->chroma_elim_threshold && !s->mb_intra) - for(i=4; i<6; i++) + for(i=4; i<mb_block_count; i++) dct_single_coeff_elimination(s, i, s->chroma_elim_threshold); if(s->flags & CODEC_FLAG_CBP_RD){ - for(i=0;i<6;i++) { + for(i=0;i<mb_block_count;i++) { if(s->block_last_index[i] == -1) s->coded_score[i]= INT_MAX/256; } @@ -4455,7 +4504,7 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) //non c quantize code returns incorrect block_last_index FIXME if(s->alternate_scan && s->dct_quantize != dct_quantize_c){ - for(i=0; i<6; i++){ + for(i=0; i<mb_block_count; i++){ int j; if(s->block_last_index[i]>0){ for(j=63; j>0; j--){ @@ -4496,6 +4545,12 @@ static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) } } +static always_inline void encode_mb(MpegEncContext *s, int motion_x, int motion_y) +{ + if (s->chroma_format == CHROMA_420) encode_mb_internal(s, motion_x, motion_y, 8, 6); + else encode_mb_internal(s, motion_x, motion_y, 16, 8); +} + #endif //CONFIG_ENCODERS void ff_mpeg_flush(AVCodecContext *avctx){ @@ -4605,7 +4660,7 @@ static inline void copy_context_after_encode(MpegEncContext *d, MpegEncContext * d->tex_pb= s->tex_pb; } d->block= s->block; - for(i=0; i<6; i++) + for(i=0; i<8; i++) d->block_last_index[i]= s->block_last_index[i]; d->interlaced_dct= s->interlaced_dct; d->qscale= s->qscale; diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index d2584e91db..7fc90235bd 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -486,7 +486,7 @@ typedef struct MpegEncContext { uint8_t *chroma_dc_vlc_length; #define UNI_AC_ENC_INDEX(run,level) ((run)*128 + (level)) - int coded_score[6]; + int coded_score[8]; /** precomputed matrix (combine qscale and DCT renorm) */ int (*q_intra_matrix)[64]; |