Hi, The following patch adds a wmv3 encoder (i removed the vc1 encoder because it doesn't generate an elementary stream). I don't think i can split the patch without breaking compilation between two patches. Please comment (particularly the vc1enc.h include in mpegvideo.c). Thanks, Denis
Hi On Mon, Jun 25, 2007 at 09:23:12PM +0200, Denis Fortin wrote:
Hi, The following patch adds a wmv3 encoder (i removed the vc1 encoder because it doesn't generate an elementary stream). I don't think i can split the patch without breaking compilation between two patches.
Please comment (particularly the vc1enc.h include in mpegvideo.c). [...]
@@ -4585,6 +4598,10 @@ if (ENABLE_WMV2_ENCODER) ff_wmv2_encode_mb(s, s->block, motion_x, motion_y); break; + case CODEC_ID_WMV3: + if (ENABLE_WMV3_ENCODER) + ff_vc1_encode_mb(s,s->block,motion_x,motion_y); + break; case CODEC_ID_H261: if (ENABLE_H261_ENCODER) ff_h261_encode_mb(s, s->block, motion_x, motion_y);
nitpick: please align the () and arguments vertically to match the 2 surrounding function calls [...]
+/** + * Unquantize a block + * + * @param s Encoder context + * @param block Block to quantize + * @param n index of block + * @param qscale quantizer scale + */ +void vc1_unquantize_c(MpegEncContext *s, DCTELEM *block, int n, int qscale)
ff prefix is missing
+{ + VC1Context * const t= s->avctx->priv_data; + int i, level, nCoeffs, q; + ScanTable scantable; + + if(s->pict_type == I_TYPE) + scantable = s->intra_scantable; + else { + scantable = s->inter_scantable;
+ if( P_TYPE == s->pict_type ) + for(i=0;i<64;i++) + block[i] += 128;
this looks wrong [...]
+ if (s->mb_intra){ + for(i=0;i<64;i++) + block[i] -= 128; + }
this can be done simpler after the transform
+ } + + s->dsp.vc1_fwd_trans_8x8(block); + + if (n < 4) + q = s->y_dc_scale; + else + q = s->c_dc_scale; + + block[0] /= q; + q = 2 * qscale + t->halfpq; + + for(i=63;i>=start_i;i--) { + j = scantable[i]; + level = (block[j] - t->pquantizer*(FFSIGN(block[j]) * qscale)) / q; + if(level){ + last_non_zero = i; + break; + } + }
if it wherent a encoder for an obscure and useless format i would reject this inefficient mess, but as it is i dont mind ... [...]
+ if( t->pqindex<=8 ) { + ff_code012(&s->pb, s->rl_chroma_table_index%3);//TRANSACFRM (UV) + ff_code012(&s->pb, s->rl_table_index%3); //TRANSACFRM2 (Y) + } else { + ff_code012(&s->pb, s->rl_chroma_table_index);//TRANSACFRM (UV) + ff_code012(&s->pb, s->rl_table_index); //TRANSACFRM2 (Y) + }
ff_code012 can only encode 0-2 so what is this if good for the %3 case should work for both [...]
+ avctx->extradata_size = 32; + avctx->extradata = av_mallocz(avctx->extradata_size + 10);
+ 10 ? [...]
+fail: + return 1;
whats the fail label good for? [...]
Index: libavcodec/vc1.c =================================================================== --- libavcodec/vc1.c (r??vision 9426) +++ libavcodec/vc1.c (copie de travail) @@ -2278,7 +2278,7 @@ * @{ */
-static inline int vc1_coded_block_pred(MpegEncContext * s, int n, uint8_t **coded_block_ptr) +inline int vc1_coded_block_pred(MpegEncContext * s, int n, uint8_t **coded_block_ptr) { int xy, wrap, pred, a, b, c;
Index: libavcodec/vc1.h =================================================================== --- libavcodec/vc1.h (r??vision 9426) +++ libavcodec/vc1.h (copie de travail) @@ -304,4 +304,6 @@ int bi_type; } VC1Context;
+inline int vc1_coded_block_pred(MpegEncContext * s, int n, uint8_t **coded_block_ptr); +
completely unacceptable gnu shit, go and read the c spec about inline
#endif // AVCODEC_VC1_H Index: libavcodec/vc1dsp.c =================================================================== --- libavcodec/vc1dsp.c (r??vision 9426) +++ libavcodec/vc1dsp.c (copie de travail) [...] + dest[0] = 12 * (t1 + t3 + t5 + t7); + dest[8] = 16 * t2 + 15 * t4 + 9 * t6 + 4 * t8; + dest[16] = 16 * (t1 - t7) + 6 * ( t3 - t5); + dest[24] = 15 * t2 - 4 * t4 - 16 * t6 - 9 * t8; + dest[32] = 12 * ( t1 - t3 - t5 + t7); + dest[40] = 9 * t2 - 16 * t4 + 4 * t6 + 15 * t8; + dest[48] = 6 * (t1 - t7) - 16 * (t3 - t5); + dest[56] = 4 * t2 - 9 * t4 + 15 * t6 - 16 * t8;
vertical align please
+ + dest++; + src++; + } + + dest = block; + src = block; + + norm_mat = norm_8; + for(i=0 ; i < 8 ; i++){ + t1 = dest[0] + dest[7]; + t2 = dest[0] - dest[7]; + t3 = dest[1] + dest[6]; + t4 = dest[1] - dest[6]; + + t5 = dest[2] + dest[5]; + t6 = dest[2] - dest[5]; + t7 = dest[3] + dest[4]; + t8 = dest[3] - dest[4]; + + src[0] = ( (12 * (t1 + t3 + t5 + t7)) << 6 ) / (norm_mat[0]); + src[1] = ( (16 * t2 + 15 * t4 + 9 * t6 + 4 * t8) << 6) / (norm_mat[1]); + src[2] = ( (16 * (t1 - t7) + 6 * ( t3 - t5)) << 6) / (norm_mat[2]); + src[3] = ( (15 * t2 - 4 * t4 - 16 * t6 - 9 * t8) << 6) / (norm_mat[3]); + src[4] = ( (12 * ( t1 - t3 - t5 + t7)) << 6) / (norm_mat[4]); + src[5] = ( (9 * t2 - 16 * t4 + 4 * t6 + 15 * t8) << 6) / (norm_mat[5]); + src[6] = ( (6 * (t1 - t7) - 16 * (t3 - t5)) << 6) / (norm_mat[6]); + src[7] = ( (4 * t2 - 9 * t4 + 15 * t6 - 16 * t8) << 6) / (norm_mat[7]); + + dest+=8; + src+=8; + norm_mat+=8; + } +} + + +void ff_vc1_inv_trans_put(uint8_t *dest, int linesize, DCTELEM block[64]) +{ + int i,j; + uint8_t *cm = ff_cropTbl + MAX_NEG_CROP; + + vc1_inv_trans_8x8_c(block); + + /* read the pixels */ + for(i=0;i<8;i++) { + dest[0] = cm[block[0]]; + dest[1] = cm[block[1]]; + dest[2] = cm[block[2]]; + dest[3] = cm[block[3]]; + dest[4] = cm[block[4]]; + dest[5] = cm[block[5]]; + dest[6] = cm[block[6]]; + dest[7] = cm[block[7]]; + + dest += linesize; + block += 8; + } +}
duplicate of put_pixels_clamped* all encoder specific things MUST be in files seperate from the decoder so that compilation of them can be skiped if the user doesnt want the encoder [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB The educated differ from the uneducated as much as the living from the dead. -- Aristotle
Michael Niedermayer a ?crit :
Hi [...]
+void ff_vc1_inv_trans_put(uint8_t *dest, int linesize, DCTELEM block[64]) +{ + int i,j; + uint8_t *cm = ff_cropTbl + MAX_NEG_CROP; + + vc1_inv_trans_8x8_c(block); + + /* read the pixels */ + for(i=0;i<8;i++) { + dest[0] = cm[block[0]]; + dest[1] = cm[block[1]]; + dest[2] = cm[block[2]]; + dest[3] = cm[block[3]]; + dest[4] = cm[block[4]]; + dest[5] = cm[block[5]]; + dest[6] = cm[block[6]]; + dest[7] = cm[block[7]]; + + dest += linesize; + block += 8; + } +}
duplicate of put_pixels_clamped*
all encoder specific things MUST be in files seperate from the decoder so that compilation of them can be skiped if the user doesnt want the encoder
Actually i checked and it's not the correct way to reconstruct a mb. I must inv transf dct coeff, do overlap smoothing if enabled, add constant 128 and then clamp to 0-255. So clamping should not happen here and i need a way to plug this vc1 specific decoding procedure into mpegvideo.c. But i have the strange feeling that a patch like above will get rejected by you : inside s->encoding part of MPV_decode_mb : if(codec_id= wmv3 ) {vc1_decode_mb} Am i right? If so do you have suggestions about the path i should take to support overlap filtering ? BTW reading vc1 decoder, it seems that clamping is done prior to overlap which is not correct (overlap should work on 10 bits values). Denis
Hi On Wed, Jun 27, 2007 at 10:31:35PM +0200, Denis Fortin wrote:
Michael Niedermayer a ?crit :
Hi [...]
+void ff_vc1_inv_trans_put(uint8_t *dest, int linesize, DCTELEM block[64]) +{ + int i,j; + uint8_t *cm = ff_cropTbl + MAX_NEG_CROP; + + vc1_inv_trans_8x8_c(block); + + /* read the pixels */ + for(i=0;i<8;i++) { + dest[0] = cm[block[0]]; + dest[1] = cm[block[1]]; + dest[2] = cm[block[2]]; + dest[3] = cm[block[3]]; + dest[4] = cm[block[4]]; + dest[5] = cm[block[5]]; + dest[6] = cm[block[6]]; + dest[7] = cm[block[7]]; + + dest += linesize; + block += 8; + } +}
duplicate of put_pixels_clamped*
all encoder specific things MUST be in files seperate from the decoder so that compilation of them can be skiped if the user doesnt want the encoder
Actually i checked and it's not the correct way to reconstruct a mb. I must inv transf dct coeff, do overlap smoothing if enabled, add constant 128 and then clamp to 0-255. So clamping should not happen here and i need a way to plug this vc1 specific decoding procedure into mpegvideo.c. But i have the strange feeling that a patch like above will get rejected by you : inside s->encoding part of MPV_decode_mb : if(codec_id= wmv3 ) {vc1_decode_mb}
Am i right? If so do you have suggestions about the path i should take to support overlap filtering ?
the whole wmv3/vc1 things is an incredible mess and i would wish thouse who designed it where never born or that at least smpte would have given MS a kick in the ass and told them to get lost ... so the options are * do something wrong and simple, its irrelevant anyway as no sane person would encode to this format unless she has no other options also doing something wrong would fit well in the whole wmv design ... * write a clean, simple and minimal implementation which is correct and which doesnt mess with speed critical functions from mpegvideo
BTW reading vc1 decoder, it seems that clamping is done prior to overlap which is not correct (overlap should work on 10 bits values).
who cares? if you have a sample which is decoded vissibly wrong, id guess kostya will eventually fix it when he has time otherwise i dont see why this would matter OTOH if you are insane and want to waste your time on this, i wont stop you, a patch fixing this _cleanly_ is not unwelcome [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB I hate to see young programmers poisoned by the kind of thinking Ulrich Drepper puts forward since it is simply too narrow -- Roman Shaposhnik
Hi Denis. Could you please update me about the status of this patch? Can it be applied to any version of FFMPEG, or needs a specific version number? Thanks, Stas. 2007/6/25, Denis Fortin <fortin at nerim.net>:
Hi, The following patch adds a wmv3 encoder (i removed the vc1 encoder because it doesn't generate an elementary stream). I don't think i can split the patch without breaking compilation between two patches.
Please comment (particularly the vc1enc.h include in mpegvideo.c).
Thanks, Denis
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel at mplayerhq.hu http://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-devel
On 06/25/2007 09:23 PM, Denis Fortin wrote:
Hi, The following patch adds a wmv3 encoder (i removed the vc1 encoder because it doesn't generate an elementary stream). I don't think i can split the patch without breaking compilation between two patches.
Please comment (particularly the vc1enc.h include in mpegvideo.c).
Git-friendly patch attached so patchwork will catch it up. -Vitor
From fortinatnerim.net Sun Jan 23 17:56:30 2011 From: fortinatnerim.net (Denis Fortin) Date: Sun, 23 Jan 2011 17:56:30 +0100 Subject: [PATCH] WMV3 encoder Message-ID: <mailman.466.1295801872.1307.ffmpeg-devel@mplayerhq.hu>
--- libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 2 +- libavcodec/allcodecs.h | 1 + libavcodec/avcodec.h | 1 + libavcodec/dsputil.h | 1 + libavcodec/mpegvideo.c | 19 +++ libavcodec/vc1.c | 2 +- libavcodec/vc1.h | 2 + libavcodec/vc1dsp.c | 108 +++++++++++++ libavcodec/vc1enc.c | 397 ++++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/vc1enc.h | 30 ++++ 11 files changed, 562 insertions(+), 2 deletions(-) create mode 100644 libavcodec/vc1enc.c create mode 100644 libavcodec/vc1enc.h diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 7ab4eb2..b77b463 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -193,6 +193,7 @@ OBJS-$(CONFIG_WMAV2_ENCODER) += wmaenc.o wma.o mdct.o fft.o OBJS-$(CONFIG_WMV2_DECODER) += msmpeg4.o msmpeg4data.o OBJS-$(CONFIG_WMV2_ENCODER) += msmpeg4.o msmpeg4data.o OBJS-$(CONFIG_WMV3_DECODER) += vc1.o vc1data.o vc1dsp.o +OBJS-$(CONFIG_WMV3_ENCODER) += vc1.o vc1data.o vc1dsp.o msmpeg4data.o vc1enc.o msmpeg4.o OBJS-$(CONFIG_WNV1_DECODER) += wnv1.o OBJS-$(CONFIG_WS_SND1_DECODER) += ws-snd1.o OBJS-$(CONFIG_XAN_DPCM_DECODER) += dpcm.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 7805fa5..e823ff2 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -156,7 +156,7 @@ void avcodec_register_all(void) REGISTER_DECODER(VQA, vqa); REGISTER_ENCDEC (WMV1, wmv1); REGISTER_ENCDEC (WMV2, wmv2); - REGISTER_DECODER(WMV3, wmv3); + REGISTER_ENCDEC (WMV3, wmv3); REGISTER_DECODER(WNV1, wnv1); REGISTER_DECODER(XAN_WC3, xan_wc3); REGISTER_DECODER(XL, xl); diff --git a/libavcodec/allcodecs.h b/libavcodec/allcodecs.h index 606d17a..b823fff 100644 --- a/libavcodec/allcodecs.h +++ b/libavcodec/allcodecs.h @@ -73,6 +73,7 @@ extern AVCodec wmav1_encoder; extern AVCodec wmav2_encoder; extern AVCodec wmv1_encoder; extern AVCodec wmv2_encoder; +extern AVCodec wmv3_encoder; extern AVCodec zmbv_encoder; extern AVCodec aasc_decoder; diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index acb7445..6a495a7 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1277,6 +1277,7 @@ typedef struct AVCodecContext { #define FF_IDCT_CAVS 15 #define FF_IDCT_SIMPLEARMV5TE 16 #define FF_IDCT_SIMPLEARMV6 17 +#define FF_IDCT_VC1 18 /** * slice count diff --git a/libavcodec/dsputil.h b/libavcodec/dsputil.h index ecf8e62..738950d 100644 --- a/libavcodec/dsputil.h +++ b/libavcodec/dsputil.h @@ -398,6 +398,7 @@ typedef struct DSPContext { void (*shrink[4])(uint8_t *dst, int dst_wrap, const uint8_t *src, int src_wrap, int width, int height); /* vc1 functions */ + void (*vc1_fwd_trans_8x8)(DCTELEM *b); void (*vc1_inv_trans_8x8)(DCTELEM *b); void (*vc1_inv_trans_8x4)(DCTELEM *b, int n); void (*vc1_inv_trans_4x8)(DCTELEM *b, int n); diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 9233ff3..bc89b9d 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -33,6 +33,7 @@ #include "mjpegenc.h" #include "msmpeg4.h" #include "faandct.h" +#include "vc1enc.h" #include <limits.h> //#undef NDEBUG @@ -1328,6 +1329,18 @@ int MPV_encode_init(AVCodecContext *avctx) avctx->delay=0; s->low_delay=1; break; + case CODEC_ID_WMV3: + case CODEC_ID_VC1: + s->out_format = FMT_H263; + s->h263_msmpeg4 = 1; + s->h263_pred = 1; + s->unrestricted_mv = 1; + s->msmpeg4_version= 6; + s->flipflop_rounding=1; + s->quarter_sample=1; + avctx->delay=0; + s->low_delay=1; + break; default: return -1; } @@ -4585,6 +4598,10 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, int motion_x, if (ENABLE_WMV2_ENCODER) ff_wmv2_encode_mb(s, s->block, motion_x, motion_y); break; + case CODEC_ID_WMV3: + if (ENABLE_WMV3_ENCODER) + ff_vc1_encode_mb(s,s->block,motion_x,motion_y); + break; case CODEC_ID_H261: if (ENABLE_H261_ENCODER) ff_h261_encode_mb(s, s->block, motion_x, motion_y); @@ -5775,6 +5792,8 @@ static int encode_picture(MpegEncContext *s, int picture_number) case FMT_H263: if (ENABLE_WMV2_ENCODER && s->codec_id == CODEC_ID_WMV2) ff_wmv2_encode_picture_header(s, picture_number); + else if (ENABLE_WMV3_ENCODER && s->codec_id == CODEC_ID_WMV3) + ff_vc1_encode_picture_header(s, picture_number); else if (ENABLE_MSMPEG4_ENCODER && s->h263_msmpeg4) msmpeg4_encode_picture_header(s, picture_number); else if (s->h263_pred) diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c index 391d4e1..a482baf 100644 --- a/libavcodec/vc1.c +++ b/libavcodec/vc1.c @@ -2278,7 +2278,7 @@ static inline int vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, * @{ */ -static inline int vc1_coded_block_pred(MpegEncContext * s, int n, uint8_t **coded_block_ptr) +inline int vc1_coded_block_pred(MpegEncContext * s, int n, uint8_t **coded_block_ptr) { int xy, wrap, pred, a, b, c; diff --git a/libavcodec/vc1.h b/libavcodec/vc1.h index c57dfff..4163745 100644 --- a/libavcodec/vc1.h +++ b/libavcodec/vc1.h @@ -304,4 +304,6 @@ typedef struct VC1Context{ int bi_type; } VC1Context; +inline int vc1_coded_block_pred(MpegEncContext * s, int n, uint8_t **coded_block_ptr); + #endif // AVCODEC_VC1_H diff --git a/libavcodec/vc1dsp.c b/libavcodec/vc1dsp.c index 6102c09..49a0a67 100644 --- a/libavcodec/vc1dsp.c +++ b/libavcodec/vc1dsp.c @@ -322,6 +322,106 @@ static void vc1_inv_trans_4x4_c(DCTELEM block[64], int n) } } + +void vc1_fwd_trans_8x8_c(DCTELEM block[64]) +{ + int i; + register int t1,t2,t3,t4,t5,t6,t7,t8; + const int *norm_mat; + DCTELEM *dest, *src; + + static const int norm_8[64] = { + 82944, 83232, 84096, 83232, 82944, 83232, 84096, 83232, + 83232, 83521, 84388, 83521, 83232, 83521, 84388, 83521, + 84096, 84388, 85264, 84388, 84096, 84388, 85264, 84388, + 83232, 83521, 84388, 83521, 83232, 83521, 84388, 83521, + 82944, 83232, 84096, 83232, 82944, 83232, 84096, 83232, + 83232, 83521, 84388, 83521, 83232, 83521, 84388, 83521, + 84096, 84388, 85264, 84388, 84096, 84388, 85264, 84388, + 83232, 83521, 84388, 83521, 83232, 83521, 84388, 83521 + }; + + src = block; + dest = block; + + for(i=0 ; i < 8 ; i++){ + t1 = src[0] + src[56]; + t2 = src[0] - src[56]; + t3 = src[8] + src[48]; + t4 = src[8] - src[48]; + t5 = src[16] + src[40]; + t6 = src[16] - src[40]; + t7 = src[24] + src[32]; + t8 = src[24] - src[32]; + + dest[0] = 12 * (t1 + t3 + t5 + t7); + dest[8] = 16 * t2 + 15 * t4 + 9 * t6 + 4 * t8; + dest[16] = 16 * (t1 - t7) + 6 * ( t3 - t5); + dest[24] = 15 * t2 - 4 * t4 - 16 * t6 - 9 * t8; + dest[32] = 12 * ( t1 - t3 - t5 + t7); + dest[40] = 9 * t2 - 16 * t4 + 4 * t6 + 15 * t8; + dest[48] = 6 * (t1 - t7) - 16 * (t3 - t5); + dest[56] = 4 * t2 - 9 * t4 + 15 * t6 - 16 * t8; + + dest++; + src++; + } + + dest = block; + src = block; + + norm_mat = norm_8; + for(i=0 ; i < 8 ; i++){ + t1 = dest[0] + dest[7]; + t2 = dest[0] - dest[7]; + t3 = dest[1] + dest[6]; + t4 = dest[1] - dest[6]; + + t5 = dest[2] + dest[5]; + t6 = dest[2] - dest[5]; + t7 = dest[3] + dest[4]; + t8 = dest[3] - dest[4]; + + src[0] = ( (12 * (t1 + t3 + t5 + t7)) << 6 ) / (norm_mat[0]); + src[1] = ( (16 * t2 + 15 * t4 + 9 * t6 + 4 * t8) << 6) / (norm_mat[1]); + src[2] = ( (16 * (t1 - t7) + 6 * ( t3 - t5)) << 6) / (norm_mat[2]); + src[3] = ( (15 * t2 - 4 * t4 - 16 * t6 - 9 * t8) << 6) / (norm_mat[3]); + src[4] = ( (12 * ( t1 - t3 - t5 + t7)) << 6) / (norm_mat[4]); + src[5] = ( (9 * t2 - 16 * t4 + 4 * t6 + 15 * t8) << 6) / (norm_mat[5]); + src[6] = ( (6 * (t1 - t7) - 16 * (t3 - t5)) << 6) / (norm_mat[6]); + src[7] = ( (4 * t2 - 9 * t4 + 15 * t6 - 16 * t8) << 6) / (norm_mat[7]); + + dest+=8; + src+=8; + norm_mat+=8; + } +} + + +void ff_vc1_inv_trans_put(uint8_t *dest, int linesize, DCTELEM block[64]) +{ + int i,j; + uint8_t *cm = ff_cropTbl + MAX_NEG_CROP; + + vc1_inv_trans_8x8_c(block); + + /* read the pixels */ + for(i=0;i<8;i++) { + dest[0] = cm[block[0]]; + dest[1] = cm[block[1]]; + dest[2] = cm[block[2]]; + dest[3] = cm[block[3]]; + dest[4] = cm[block[4]]; + dest[5] = cm[block[5]]; + dest[6] = cm[block[6]]; + dest[7] = cm[block[7]]; + + dest += linesize; + block += 8; + } +} + + /* motion compensation functions */ /** Filter used to interpolate fractional pel values @@ -444,6 +544,14 @@ void ff_vc1dsp_init(DSPContext* dsp, AVCodecContext *avctx) { dsp->vc1_h_overlap = vc1_h_overlap_c; dsp->vc1_v_overlap = vc1_v_overlap_c; + if( ENABLE_WMV3_ENCODER ) { + dsp->vc1_fwd_trans_8x8 = vc1_fwd_trans_8x8_c; + if(avctx->idct_algo == FF_IDCT_VC1) { + dsp->idct_put = ff_vc1_inv_trans_put; + dsp->idct_permutation_type = FF_NO_IDCT_PERM; + } + } + dsp->put_vc1_mspel_pixels_tab[ 0] = ff_put_vc1_mspel_mc00_c; dsp->put_vc1_mspel_pixels_tab[ 1] = ff_put_vc1_mspel_mc10_c; dsp->put_vc1_mspel_pixels_tab[ 2] = ff_put_vc1_mspel_mc20_c; diff --git a/libavcodec/vc1enc.c b/libavcodec/vc1enc.c new file mode 100644 index 0000000..81b1868 --- /dev/null +++ b/libavcodec/vc1enc.c @@ -0,0 +1,397 @@ +/* + * VC-1 and WMV3 encoder + * copyright (c) 2007 Denis Fortin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "common.h" +#include "msmpeg4data.h" +#include "vc1.h" +#include "vc1data.h" +#include "vc1enc.h" + +/* msmpeg4 externs*/ +extern void ff_msmpeg4_encode_block(MpegEncContext * s, DCTELEM * block, int n); +extern void ff_find_best_tables(MpegEncContext * s); +extern void ff_code012(PutBitContext *pb, int n); + +/** + * Unquantize a block + * + * @param s Encoder context + * @param block Block to quantize + * @param n index of block + * @param qscale quantizer scale + */ +void vc1_unquantize_c(MpegEncContext *s, DCTELEM *block, int n, int qscale) +{ + VC1Context * const t= s->avctx->priv_data; + int i, level, nCoeffs, q; + ScanTable scantable; + + if(s->pict_type == I_TYPE) + scantable = s->intra_scantable; + else { + scantable = s->inter_scantable; + if( P_TYPE == s->pict_type ) + for(i=0;i<64;i++) + block[i] += 128; + } + + nCoeffs= s->block_last_index[n]; + + if (n < 4) + block[0] *= s->y_dc_scale; + else + block[0] *= s->c_dc_scale; + + q = 2 * qscale + t->halfpq; + + for(i=1; i<= nCoeffs; i++) { + int j= scantable.permutated[i]; + level = block[j]; + if (level) { + level = level * q + t->pquantizer*(FFSIGN(block[j]) * qscale); + } + block[j]=level; + } + + for(; i< 64; i++) { + int j= scantable.permutated[i]; + block[j]=0; + } + +} + + +/** + * Transform and quantize a block + * + * @param s Encoder Context + * @param block block to encode + * @param n block index + * @param qscale quantizer scale + * @param overflow + * + * @return last significant coeff in zz order + */ +int vc1_quantize_c(MpegEncContext *s, DCTELEM *block, int n, int qscale, int *overflow) +{ + VC1Context * const t= s->avctx->priv_data; + const uint8_t *scantable; + int q, i, j, level, last_non_zero, start_i; + + if( I_TYPE == s->pict_type ) { + scantable = s->intra_scantable.scantable; + last_non_zero = 0; + start_i = 1; + } else { + scantable = s->inter_scantable.scantable; + last_non_zero = -1; + start_i = 0; + if (s->mb_intra){ + for(i=0;i<64;i++) + block[i] -= 128; + } + } + + s->dsp.vc1_fwd_trans_8x8(block); + + if (n < 4) + q = s->y_dc_scale; + else + q = s->c_dc_scale; + + block[0] /= q; + q = 2 * qscale + t->halfpq; + + for(i=63;i>=start_i;i--) { + j = scantable[i]; + level = (block[j] - t->pquantizer*(FFSIGN(block[j]) * qscale)) / q; + if(level){ + last_non_zero = i; + break; + } + } + for(i=start_i; i<=last_non_zero; i++) { + j = scantable[i]; + block[j] = (block[j] - t->pquantizer*(FFSIGN(block[j]) * qscale)) / q ; + } + *overflow = 0; + return last_non_zero; +} + + +/** + * Intra picture MB layer bitstream encoder + * @param s Mpeg encoder context + * @param block macroblock to encode + */ +void vc1_intra_picture_encode_mb(MpegEncContext * s, DCTELEM block[6][64]) +{ + int cbp, coded_cbp, i; + uint8_t *coded_block; + + /* compute cbp */ + cbp = 0; + coded_cbp = 0; + for (i = 0; i < 6; i++) { + int val, pred; + val = (s->block_last_index[i] >= 1); + cbp |= val << (5 - i); + if (i < 4) { + /* predict value for close blocks only for luma */ + pred = vc1_coded_block_pred(s, i, &coded_block); + *coded_block = val; + val = val ^ pred; + } + coded_cbp |= val << (5 - i); + } + put_bits(&s->pb,ff_msmp4_mb_i_table[coded_cbp][1], + ff_msmp4_mb_i_table[coded_cbp][0]);//CBPCY + + //predict dc_val and dc_direction for each block + + //brute force test to switch ACPRED on/off + put_bits(&s->pb,1,0);//ACPRED + + for (i = 0; i < 6; i++) + ff_msmpeg4_encode_block(s, block[i], i); + + s->i_tex_bits += get_bits_diff(s); + s->i_count++; +} + + + + +/** + * MB layer bitstream encoder + * @param s Mpeg encoder context + * @param block macroblock to encode + * @param motion_x x component of mv's macroblock + * @param motion_y y component of mv's macroblock + */ +void ff_vc1_encode_mb(MpegEncContext * s, DCTELEM block[6][64], + int motion_x, int motion_y) +{ + if ( I_TYPE == s->pict_type ) { + vc1_intra_picture_encode_mb(s, block); + } +} + + + + + +/** + * Progressive I picture layer bitstream encoder for Simple and Main Profile + * @param s Mpeg encoder context + * @param picture_number number of the frame to encode + */ +void vc1_encode_i_sm_picture_header(MpegEncContext * s, int picture_number) +{ + VC1Context * const t= s->avctx->priv_data; + if( t->finterpflag ) { + t->interpfrm = 0;//INTERPFRM + put_bits(&s->pb,1,t->interpfrm); + } + + put_bits(&s->pb,2,picture_number);//FRMCNT + + if( t->rangered ){ + t->rangeredfrm = 0;//RANGEREDFRM + put_bits(&s->pb,1,t->rangeredfrm); + } + + put_bits(&s->pb,1,s->pict_type-1);//PTYPE + + put_bits(&s->pb,7,50);//BF + + t->pquantizer = 1;//always use non uniform quantizer + + if(s->qscale > 8 ) { + t->halfpq = 0; + } else { + t->halfpq = 1; + } + + if( t->quantizer_mode == QUANT_FRAME_IMPLICIT){ + //TODO create table + // put_bits(&s->pb,5,t->pqindex);//PQINDEX + } else { + t->pqindex = s->qscale; + put_bits(&s->pb,5,t->pqindex);//PQINDEX + } + + if( t->pqindex <= 8 ) + put_bits(&s->pb,1,t->halfpq);//HALFQP + + if( t->quantizer_mode == QUANT_FRAME_EXPLICIT ) + put_bits(&s->pb,1,t->pquantizer);//PQUANTIZER : NON_UNIFOMR 0 / UNIFORM 1 + + if( t->extended_mv ) { + t->mvrange = 0; + put_bits(&s->pb,1,t->mvrange);//TODO fix this: num bits is not fixed + } + + if( t->multires ) { + t->respic = 0; + put_bits(&s->pb,2,t->respic); + } + + if( t->pqindex<=8 ) { + ff_code012(&s->pb, s->rl_chroma_table_index%3);//TRANSACFRM (UV) + ff_code012(&s->pb, s->rl_table_index%3); //TRANSACFRM2 (Y) + } else { + ff_code012(&s->pb, s->rl_chroma_table_index);//TRANSACFRM (UV) + ff_code012(&s->pb, s->rl_table_index); //TRANSACFRM2 (Y) + } + + put_bits(&s->pb, 1, s->dc_table_index);//TRANSDCTAB +} + + + +/** + * Picture layer bitstream encoder + * @param s Mpeg encoder context + * @param picture_number number of the frame to encode + */ +void ff_vc1_encode_picture_header(MpegEncContext * s, int picture_number) +{ + + ff_find_best_tables(s); + + if( I_TYPE == s->pict_type) + vc1_encode_i_sm_picture_header(s, picture_number) ; + + s->esc3_level_length = 0; + s->esc3_run_length = 0; + +} + + +/** + * Sequence layer bitstream encoder + * @param t VC1 context + */ +void vc1_encode_ext_header(VC1Context *t) +{ + MpegEncContext * const s= &t->s; + PutBitContext pb; + init_put_bits(&pb, s->avctx->extradata, s->avctx->extradata_size); + + t->profile = PROFILE_MAIN; + put_bits(&pb, 2, t->profile); //Profile + if(t->profile == PROFILE_ADVANCED) { + t->level = 2; + put_bits(&pb, 3, t->level); //Level + t->chromaformat = 1; //4:2:0 + put_bits(&pb, 2, t->chromaformat); + } else { + put_bits(&pb, 2, 0); //Unused + } + + put_bits(&pb, 3, 0); //TODO: Q frame rate + put_bits(&pb, 5, 0); //TODO: Q bit rate + + s->loop_filter = 0;//TODO: loop_filter + put_bits(&pb, 1, s->loop_filter); + + if(t->profile < PROFILE_ADVANCED) { + put_bits(&pb, 1, 0); //Reserved + put_bits(&pb, 1, 0); //Multires + put_bits(&pb, 1, 1); //Reserved + } + + t->fastuvmc = 0;//TODO : FAST U/V MC + put_bits(&pb, 1, t->fastuvmc); + + t->extended_mv = 0;//TODO : Extended MV + put_bits(&pb, 1, t->extended_mv); + + t->dquant = 0;//TODO : MB dequant + put_bits(&pb, 2, t->dquant); + + t->vstransform = 0;//TODO : Variable size transform + put_bits(&pb, 1, t->vstransform); + + if (t->profile < PROFILE_ADVANCED) { + put_bits(&pb, 1, 0); //Reserved + } + + t->overlap = 0; //TODO : Overlap + put_bits(&pb, 1, t->overlap); + + if (t->profile < PROFILE_ADVANCED) { + s->resync_marker = 0;//TODO : Resync marker + put_bits(&pb, 1, s->resync_marker); + t->rangered = 0;// TODO: Range red + put_bits(&pb, 1, t->rangered); + } + + put_bits(&pb, 3, 0); //Max B-frames + + t->quantizer_mode = QUANT_FRAME_EXPLICIT; + put_bits(&pb, 2, t->quantizer_mode); //Quantizer + + if (t->profile < PROFILE_ADVANCED) { + t->finterpflag = 0; //TODO : Frame interpol + put_bits(&pb, 1, t->finterpflag); + put_bits(&pb, 1, 1); //Reserved + } + flush_put_bits(&pb); +} + + +static int vc1_encode_init(AVCodecContext *avctx){ + VC1Context * const t= avctx->priv_data; + MpegEncContext *s = &t->s; + + if(avctx->idct_algo==FF_IDCT_AUTO) + avctx->idct_algo=FF_IDCT_VC1; + + if(MPV_encode_init(avctx) < 0) + return -1; + + avctx->extradata_size = 32; + avctx->extradata = av_mallocz(avctx->extradata_size + 10); + s->dct_quantize = vc1_quantize_c; + s->dct_unquantize_intra = + s->dct_unquantize_inter = vc1_unquantize_c; + + vc1_encode_ext_header(t); + + return 0; +fail: + return 1; + +} + +AVCodec wmv3_encoder = { + "wmv3", + CODEC_TYPE_VIDEO, + CODEC_ID_WMV3, + sizeof(VC1Context), + vc1_encode_init, + MPV_encode_picture, + MPV_encode_end, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, +}; diff --git a/libavcodec/vc1enc.h b/libavcodec/vc1enc.h new file mode 100644 index 0000000..858746d --- /dev/null +++ b/libavcodec/vc1enc.h @@ -0,0 +1,30 @@ +/* + * VC-1 and WMV3 encoder + * copyright (c) 2007 Denis Fortin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef VC1ENC_H +#define VC1ENC_H + +void ff_vc1_encode_picture_header(MpegEncContext * s, int picture_number); + +void ff_vc1_encode_mb(MpegEncContext * s, DCTELEM block[6][64], + int motion_x, int motion_y); + + +#endif /* VC1ENC_H */ -- 1.7.1 --------------030605000501070403060801--
On Sun, Jan 23, 2011 at 05:57:43PM +0100, Vitor Sessak wrote:
Git-friendly patch attached so patchwork will catch it up.
missing changelog update, docs entry
--- /dev/null +++ b/libavcodec/vc1enc.c @@ -0,0 +1,397 @@ + +/* msmpeg4 externs*/ +extern void ff_msmpeg4_encode_block(MpegEncContext * s, DCTELEM * block, int n); +extern void ff_find_best_tables(MpegEncContext * s); +extern void ff_code012(PutBitContext *pb, int n);
Ugly, this should be a header.
+AVCodec wmv3_encoder = { + "wmv3", + CODEC_TYPE_VIDEO, + CODEC_ID_WMV3, + sizeof(VC1Context),
long_name is missing.
--- /dev/null +++ b/libavcodec/vc1enc.h @@ -0,0 +1,30 @@ +/* + * VC-1 and WMV3 encoder + * copyright (c) 2007 Denis Fortin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef VC1ENC_H +#define VC1ENC_H + +#endif /* VC1ENC_H */
Not our standard multiple inclusion guards. Diego
participants (5)
-
diego@biurrun.de -
fortin@nerim.net -
michaelni@gmx.at -
stas.oskin@gmail.com -
vitor1001@gmail.com