[PATCH] Chinese AVS encoder
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, as announced before here is my encoder for Chinese AVS. Features that it does support: - - Intra macroblocks - - P_SKIP macroblocks - - P_16x16 macroblocks - - one or two reference frames - - constant quantizer encoding - - motion estimation using hexagon search and qpel refinement Features that it does not support: - - P_16x8, P_8x16 and P_8x8 macroblocks - - B macroblocks/frames - - rate control - - anything else you might think of To test it, here is a sample command line ./ffmpeg -i in.avi -vcodec cavs -strict -2 -cqp 30 -refs 2 -psnr out.avi - -strict -2 is required for the encoder's experimental nature, I have not thought much about its standard conformance, just that it decodes with my decoder. - -cqp n with n in the range 0 to 63 is required as only fixed quantizer encoding is supported - -refs 2 is optional, one reference frame would be the default - -psnr is optional Michael, regarding your question on cvslog (sorry for crossposting, I wasn't subscribed to cvslog at the time):
Author: stefang Date: Sat Jul 7 09:14:58 2007 New Revision: 9518
Log: move dequantization into it's own inline function
why inline? same question for the other inline functions is there some speed gain from duplicating them in the object files between encoder and decoder?
To be honest I did not think much about object size, it just seemed to be a convenient way to share functions this way instead of having to create ff_cavs_foobar names and without creating function call overhead that was not there before. If you think object size would be a problem I can of course move some functions back from cavs.h to cavs.c. Stefan -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGocyhYpYOlpT3vNMRArJrAKC5aQQ40GEmegoLh8u0b0HCc0f60QCgzgc4 tMea5NiHbnlzxikJYvkl9Q4= =0R8q -----END PGP SIGNATURE-----
Hi On Sat, Jul 21, 2007 at 11:06:42AM +0200, Stefan Gehrer wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hi,
as announced before here is my encoder for Chinese AVS. Features that it does support: - - Intra macroblocks - - P_SKIP macroblocks - - P_16x16 macroblocks - - one or two reference frames - - constant quantizer encoding - - motion estimation using hexagon search and qpel refinement Features that it does not support: - - P_16x8, P_8x16 and P_8x8 macroblocks - - B macroblocks/frames - - rate control - - anything else you might think of
To test it, here is a sample command line ./ffmpeg -i in.avi -vcodec cavs -strict -2 -cqp 30 -refs 2 -psnr out.avi
- -strict -2 is required for the encoder's experimental nature, I have not thought much about its standard conformance, just that it decodes with my decoder. - -cqp n with n in the range 0 to 63 is required as only fixed quantizer encoding is supported - -refs 2 is optional, one reference frame would be the default - -psnr is optional
Michael, regarding your question on cvslog (sorry for crossposting, I wasn't subscribed to cvslog at the time):
Author: stefang Date: Sat Jul 7 09:14:58 2007 New Revision: 9518
Log: move dequantization into it's own inline function
why inline? same question for the other inline functions is there some speed gain from duplicating them in the object files between encoder and decoder?
To be honest I did not think much about object size, it just seemed to be a convenient way to share functions this way instead of having to create ff_cavs_foobar names and without creating function call overhead that was not there before. If you think object size would be a problem I can of course move some functions back from cavs.h to cavs.c.
yes please do unless theres a real speed loss from doing so [...]
+/** + * eliminate residual blocks that only have insignificant coefficients, + * inspired from x264 and JVT-B118 + */ +static inline int decimate_block(uint8_t *run, DCTELEM *level, int count) { + static const uint8_t run_score[30] = { + 0,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 }; + int i; + int score = 0; + + if(count>4) + return 9; + for(i=0;i<count;i++) { + int abslevel = FFABS(level[i]); + if(abslevel > 1) + return 9; + score += run_score[FFMIN(run[i],29)]; + } + return score; +}
how much psnr/bitrate is gained by this? if none then please drop it [...]
+ av_reduce(&frame_rate.den, &frame_rate.num, + s->avctx->time_base.num, s->avctx->time_base.den, 60000);
if the exact one isnt support then the code should failm its the user apps job to choose a supported one
+ for(i=0;i<15;i++) + if((ff_frame_rate_tab[i].den == frame_rate.den) && + (ff_frame_rate_tab[i].num == frame_rate.num)) + frame_rate_code = i; + if(frame_rate_code < 0) { + av_log(h->s.avctx, AV_LOG_ERROR, "unsupported framerate %d/%d\n", + frame_rate.num, frame_rate.den); + return -1; + }
[...]
+ put_bits(&s->pb,16,0); + put_bits(&s->pb,16,CAVS_START_CODE);
add a put_bits_long() to bitstrea.c, document the issue with 32bits and fix vorbis_enc.c :) [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB It is dangerous to be right in matters on which the established authorities are wrong. -- Voltaire
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, Michael Niedermayer wrote:
Michael, regarding your question on cvslog (sorry for crossposting, I wasn't subscribed to cvslog at the time):
Author: stefang Date: Sat Jul 7 09:14:58 2007 New Revision: 9518
Log: move dequantization into it's own inline function why inline? same question for the other inline functions is there some speed gain from duplicating them in the object files between encoder and decoder? To be honest I did not think much about object size, it just seemed to be a convenient way to share functions this way instead of having to create ff_cavs_foobar names and without creating function call overhead that was not there before. If you think object size would be a problem I can of course move some functions back from cavs.h to cavs.c.
yes please do unless theres a real speed loss from doing so
done
[...]
+/** + * eliminate residual blocks that only have insignificant coefficients, + * inspired from x264 and JVT-B118 + */ +static inline int decimate_block(uint8_t *run, DCTELEM *level, int count) { + static const uint8_t run_score[30] = { + 0,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 }; + int i; + int score = 0; + + if(count>4) + return 9; + for(i=0;i<count;i++) { + int abslevel = FFABS(level[i]); + if(abslevel > 1) + return 9; + score += run_score[FFMIN(run[i],29)]; + } + return score; +}
how much psnr/bitrate is gained by this? if none then please drop it
I tested on the popular foreman (300 CIF frames). When encoding at around 800kbps, roughly 0.1dB are gained by this. When encoding at around 200kbps, this increases to a gain of around 0.15dB. So I would like to keep it.
[...]
+ av_reduce(&frame_rate.den, &frame_rate.num, + s->avctx->time_base.num, s->avctx->time_base.den, 60000);
if the exact one isnt support then the code should failm its the user apps job to choose a supported one
removed
+ for(i=0;i<15;i++) + if((ff_frame_rate_tab[i].den == frame_rate.den) && + (ff_frame_rate_tab[i].num == frame_rate.num)) + frame_rate_code = i; + if(frame_rate_code < 0) { + av_log(h->s.avctx, AV_LOG_ERROR, "unsupported framerate %d/%d\n", + frame_rate.num, frame_rate.den); + return -1; + }
[...]
+ put_bits(&s->pb,16,0); + put_bits(&s->pb,16,CAVS_START_CODE);
add a put_bits_long() to bitstrea.c, document the issue with 32bits and fix vorbis_enc.c :)
I looked a bit into this and I think a better way would be to fix put_bits() to support up to 32 bits instead of up to 31 bits. I am not so sure, but after a bit of checking in vorbis_enc.c it seems there is never any writing with more than 32 bits even though the local put_bits() function takes a 64bit argument. Attached a new encoder patch and a proposed fix for put_bits(). Stefan -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGpuSZYpYOlpT3vNMRAtZHAJwPWbgFJii6LsNPccX00FwvcdgIRwCguewG GaR3Ox/qNiru79+7Jrq58sc= =NtuI -----END PGP SIGNATURE-----
Hi On Wed, Jul 25, 2007 at 07:50:17AM +0200, Stefan Gehrer wrote: [...]
[...]
+/** + * eliminate residual blocks that only have insignificant coefficients, + * inspired from x264 and JVT-B118 + */ +static inline int decimate_block(uint8_t *run, DCTELEM *level, int count) { + static const uint8_t run_score[30] = { + 0,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 }; + int i; + int score = 0; + + if(count>4) + return 9; + for(i=0;i<count;i++) { + int abslevel = FFABS(level[i]); + if(abslevel > 1) + return 9; + score += run_score[FFMIN(run[i],29)]; + } + return score; +}
how much psnr/bitrate is gained by this? if none then please drop it
I tested on the popular foreman (300 CIF frames). When encoding at around 800kbps, roughly 0.1dB are gained by this. When encoding at around 200kbps, this increases to a gain of around 0.15dB. So I would like to keep it.
ok, but i think there is something wrong elsewhere if there is such a large gain from this ... maybe a simple change to the bias would help? or maybe there is something else wrong with the quantization code ... [...]
+ for(i=0;i<15;i++) + if((ff_frame_rate_tab[i].den == frame_rate.den) && + (ff_frame_rate_tab[i].num == frame_rate.num)) + frame_rate_code = i; + if(frame_rate_code < 0) { + av_log(h->s.avctx, AV_LOG_ERROR, "unsupported framerate %d/%d\n", + frame_rate.num, frame_rate.den); + return -1; + }
[...]
+ put_bits(&s->pb,16,0); + put_bits(&s->pb,16,CAVS_START_CODE);
add a put_bits_long() to bitstrea.c, document the issue with 32bits and fix vorbis_enc.c :)
I looked a bit into this and I think a better way would be to fix put_bits() to support up to 32 bits instead of up to 31 bits. I am not so sure, but after a bit of checking in vorbis_enc.c it seems there is never any writing with more than 32 bits even though the local put_bits() function takes a 64bit argument.
argh, ive not noticed that vorbis is using a private put_bits iam starting to hate vorbis_enc.c ...
Attached a new encoder patch
and a proposed fix for put_bits().
the fix to put_bits is rejected due to a likely huge slowdown [...]
/***************************************************************************** * + * quantization + * + ****************************************************************************/ + +static void cavs_quant_c(DCTELEM *block, const uint16_t *norm, int mul, + int bias) { + int i; + + for(i=0;i<64;i++) { + if(block[i] > 0) + block[i] = ((((1<<18) + block[i]*norm[i])>>19)*mul+bias)>>15; + else + block[i] = -(((((1<<18) - block[i]*norm[i])>>19)*mul+bias)>>15); + }
this is a duplicate of dct_quantize* its just much slower and smaller [...]
+ int level = abs(level_buf[coeff_num])-1; + int sign = (level_buf[coeff_num]>>31)&1;
MASK_ABS() [...]
+ h->lambda = h->qp/3;
if i understand it correctly then qp is a logarithmic scale, if so this is likely completely wrong h->lambda = C*quant_mul[h->qp]; might be more correct [...]
+ mode = (i == 4) ? predpred : i + (i >= predpred); + mode = modify(h->flags, block, mode); + if(mode >= 0) { + h->intra_pred_l[mode](d, top, left, h->l_stride); + diff = h->s.dsp.sse[1](NULL, s, d, h->l_stride, 8); + if((bitcost[i]*h->lambda + diff) < min_cost) {
with SSE its likely lambda*lambda with the above definition of lambda [...]
+ h->dist[0] = (h->picture.poc - h->DPB[0].poc + 512) % 512; + h->dist[1] = (h->picture.poc - h->DPB[1].poc + 512) % 512;
&511 ? [...]
+ memcpy(&h->DPB[1], &h->DPB[0], sizeof(Picture));
h->DPB[1]= h->DPB[0]; [...]
+ h->levels[0] = av_mallocz(6*64*sizeof(DCTELEM)); + h->runs[0] = av_mallocz(6*64); + for(i=1;i<6;i++) { + h->levels[i] = h->levels[i-1] + 64; + h->runs[i] = h->runs[i-1] + 64; + }
why is this allocated with malloc instead of being part of the context? [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB it is not once nor twice but times without number that the same ideas make their appearance in the world. -- Aristotle
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Michael Niedermayer wrote:
Hi
On Wed, Jul 25, 2007 at 07:50:17AM +0200, Stefan Gehrer wrote: [...]
[...]
+/** + * eliminate residual blocks that only have insignificant coefficients, + * inspired from x264 and JVT-B118 + */ +static inline int decimate_block(uint8_t *run, DCTELEM *level, int count) { + static const uint8_t run_score[30] = { + 0,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 }; + int i; + int score = 0; + + if(count>4) + return 9; + for(i=0;i<count;i++) { + int abslevel = FFABS(level[i]); + if(abslevel > 1) + return 9; + score += run_score[FFMIN(run[i],29)]; + } + return score; +} how much psnr/bitrate is gained by this? if none then please drop it I tested on the popular foreman (300 CIF frames). When encoding at around 800kbps, roughly 0.1dB are gained by this. When encoding at around 200kbps, this increases to a gain of around 0.15dB. So I would like to keep it.
ok, but i think there is something wrong elsewhere if there is such a large gain from this ... maybe a simple change to the bias would help? or maybe there is something else wrong with the quantization code ...
why? It seems clear to me that coding a macroblock as skipped is so much cheaper than coding type/cbp/mv/coefficients that it might be worth throwing some real information away. By real I mean coefficients that come out of a fully correct quantization code, though I am not claiming my code to be that.
[...]
+ for(i=0;i<15;i++) + if((ff_frame_rate_tab[i].den == frame_rate.den) && + (ff_frame_rate_tab[i].num == frame_rate.num)) + frame_rate_code = i; + if(frame_rate_code < 0) { + av_log(h->s.avctx, AV_LOG_ERROR, "unsupported framerate %d/%d\n", + frame_rate.num, frame_rate.den); + return -1; + }
+ put_bits(&s->pb,16,0); + put_bits(&s->pb,16,CAVS_START_CODE); add a put_bits_long() to bitstrea.c, document the issue with 32bits and fix vorbis_enc.c :) I looked a bit into this and I think a better way would be to fix
[...] put_bits() to support up to 32 bits instead of up to 31 bits. I am not so sure, but after a bit of checking in vorbis_enc.c it seems there is never any writing with more than 32 bits even though the local put_bits() function takes a 64bit argument.
argh, ive not noticed that vorbis is using a private put_bits iam starting to hate vorbis_enc.c ...
Attached a new encoder patch
and a proposed fix for put_bits().
the fix to put_bits is rejected due to a likely huge slowdown
It is in the else branch and only executed every 32 bits of bitstream writing, so I don't think the slowdown will be "huge". But if it's not acceptable I will think about adding a put_bits_long again.
[...]
/***************************************************************************** * + * quantization + * + ****************************************************************************/ + +static void cavs_quant_c(DCTELEM *block, const uint16_t *norm, int mul, + int bias) { + int i; + + for(i=0;i<64;i++) { + if(block[i] > 0) + block[i] = ((((1<<18) + block[i]*norm[i])>>19)*mul+bias)>>15; + else + block[i] = -(((((1<<18) - block[i]*norm[i])>>19)*mul+bias)>>15); + }
this is a duplicate of dct_quantize* its just much slower and smaller
Looks quite different to me, but I will see if I can reuse it somehow.
[...]
+ int level = abs(level_buf[coeff_num])-1; + int sign = (level_buf[coeff_num]>>31)&1;
MASK_ABS()
[...]
+ h->lambda = h->qp/3;
if i understand it correctly then qp is a logarithmic scale, if so this is likely completely wrong
h->lambda = C*quant_mul[h->qp]; might be more correct
[...]
with SSE its likely lambda*lambda with the above definition of lambda
Yes, my lambda has no mathematical background. With many of the parameters I just hand-tuned them and found that a lambda close to zero seemed to give the best results. Similarly the quantization biases and the threshold for the intra/inter decision are just derived from trial and error.
[...]
+ h->dist[0] = (h->picture.poc - h->DPB[0].poc + 512) % 512; + h->dist[1] = (h->picture.poc - h->DPB[1].poc + 512) % 512;
&511 ?
It is not speed critical, and then I find the modulo more readable.
[...]
+ memcpy(&h->DPB[1], &h->DPB[0], sizeof(Picture));
h->DPB[1]= h->DPB[0];
Right, will change.
[...]
+ h->levels[0] = av_mallocz(6*64*sizeof(DCTELEM)); + h->runs[0] = av_mallocz(6*64); + for(i=1;i<6;i++) { + h->levels[i] = h->levels[i-1] + 64; + h->runs[i] = h->runs[i-1] + 64; + }
why is this allocated with malloc instead of being part of the context?
It keeps the context smaller when only the decoder is running. Stefan -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGqDJhYpYOlpT3vNMRAhmtAJ4rHB9KbjPBesfl0bws0XBwAAPyrwCeJRcO onkNRnkGiZctJtsmVi3pZME= =VVSC -----END PGP SIGNATURE-----
Hi On Thu, Jul 26, 2007 at 07:34:26AM +0200, Stefan Gehrer wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Michael Niedermayer wrote:
Hi
On Wed, Jul 25, 2007 at 07:50:17AM +0200, Stefan Gehrer wrote: [...]
[...]
+/** + * eliminate residual blocks that only have insignificant coefficients, + * inspired from x264 and JVT-B118 + */ +static inline int decimate_block(uint8_t *run, DCTELEM *level, int count) { + static const uint8_t run_score[30] = { + 0,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 }; + int i; + int score = 0; + + if(count>4) + return 9; + for(i=0;i<count;i++) { + int abslevel = FFABS(level[i]); + if(abslevel > 1) + return 9; + score += run_score[FFMIN(run[i],29)]; + } + return score; +} how much psnr/bitrate is gained by this? if none then please drop it I tested on the popular foreman (300 CIF frames). When encoding at around 800kbps, roughly 0.1dB are gained by this. When encoding at around 200kbps, this increases to a gain of around 0.15dB. So I would like to keep it.
ok, but i think there is something wrong elsewhere if there is such a large gain from this ... maybe a simple change to the bias would help? or maybe there is something else wrong with the quantization code ...
why? It seems clear to me that coding a macroblock as skipped is so much cheaper than coding type/cbp/mv/coefficients that it might be worth throwing some real information away. By real I mean coefficients that come out of a fully correct quantization code, though I am not claiming my code to be that.
you should just make RD optimal decissions (IIRC you do calculate the RD all over the place anyway), if you do no heuristic like above will help
[...]
+ for(i=0;i<15;i++) + if((ff_frame_rate_tab[i].den == frame_rate.den) && + (ff_frame_rate_tab[i].num == frame_rate.num)) + frame_rate_code = i; + if(frame_rate_code < 0) { + av_log(h->s.avctx, AV_LOG_ERROR, "unsupported framerate %d/%d\n", + frame_rate.num, frame_rate.den); + return -1; + }
+ put_bits(&s->pb,16,0); + put_bits(&s->pb,16,CAVS_START_CODE); add a put_bits_long() to bitstrea.c, document the issue with 32bits and fix vorbis_enc.c :) I looked a bit into this and I think a better way would be to fix
[...] put_bits() to support up to 32 bits instead of up to 31 bits. I am not so sure, but after a bit of checking in vorbis_enc.c it seems there is never any writing with more than 32 bits even though the local put_bits() function takes a 64bit argument.
argh, ive not noticed that vorbis is using a private put_bits iam starting to hate vorbis_enc.c ...
Attached a new encoder patch
and a proposed fix for put_bits().
the fix to put_bits is rejected due to a likely huge slowdown
It is in the else branch and only executed every 32 bits of bitstream writing, so I don't think the slowdown will be "huge". But if it's not acceptable I will think about adding a put_bits_long again.
the slowdown would affect all codecs, and i think it would be a significant slowdown its totally unacceptable just so you can replace put_bits(16); put_bits(16); by put_bits(32) in 1 or 2 codecs and without any benchmarks ... [...]
[...]
+ h->dist[0] = (h->picture.poc - h->DPB[0].poc + 512) % 512; + h->dist[1] = (h->picture.poc - h->DPB[1].poc + 512) % 512;
&511 ?
It is not speed critical, and then I find the modulo more readable.
its +% vs &, ( 2 vs. 1 operations) so the modulo likely does make the binary by a byte or 2 larger ... [...]
[...]
+ h->levels[0] = av_mallocz(6*64*sizeof(DCTELEM)); + h->runs[0] = av_mallocz(6*64); + for(i=1;i<6;i++) { + h->levels[i] = h->levels[i-1] + 64; + h->runs[i] = h->runs[i-1] + 64; + }
why is this allocated with malloc instead of being part of the context?
It keeps the context smaller when only the decoder is running.
hmm, ok, still its not ideal, as this requires an extra pointer dereference to access [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Observe your enemies, for they first find out your faults. -- Antisthenes
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi Michael Niedermayer wrote:
[...]
+/** + * eliminate residual blocks that only have insignificant coefficients, + * inspired from x264 and JVT-B118 + */ +static inline int decimate_block(uint8_t *run, DCTELEM *level, int count) { + static const uint8_t run_score[30] = { + 0,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 }; + int i; + int score = 0; + + if(count>4) + return 9; + for(i=0;i<count;i++) { + int abslevel = FFABS(level[i]); + if(abslevel > 1) + return 9; + score += run_score[FFMIN(run[i],29)]; + } + return score; +} how much psnr/bitrate is gained by this? if none then please drop it I tested on the popular foreman (300 CIF frames). When encoding at around 800kbps, roughly 0.1dB are gained by this. When encoding at around 200kbps, this increases to a gain of around 0.15dB. So I would like to keep it. ok, but i think there is something wrong elsewhere if there is such a large gain from this ... maybe a simple change to the bias would help? or maybe there is something else wrong with the quantization code ...
why? It seems clear to me that coding a macroblock as skipped is so much cheaper than coding type/cbp/mv/coefficients that it might be worth throwing some real information away. By real I mean coefficients that come out of a fully correct quantization code, though I am not claiming my code to be that.
you should just make RD optimal decissions (IIRC you do calculate the RD all over the place anyway), if you do no heuristic like above will help
Okay, I think I see what you mean. Currently I use RD-decisions to select intra prediction modes and for the motion estimation, but for the macroblock mode decision there are some heuristics roughly like this: if(only insignificant coefficients) encode mb as skipped else RD = P motion estimation if(RD < threshold) encode mb as p else encode mb as intra By using RD optimal decisions do you mean I should encode every macroblock in all three modes (skipped/p/intra) and select the best of three, or rather I should try one mode and if its RD cost is below a certain threshold I should take it, otherwise I should move on to the next mode?
[...]
+ for(i=0;i<15;i++) + if((ff_frame_rate_tab[i].den == frame_rate.den) && + (ff_frame_rate_tab[i].num == frame_rate.num)) + frame_rate_code = i; + if(frame_rate_code < 0) { + av_log(h->s.avctx, AV_LOG_ERROR, "unsupported framerate %d/%d\n", + frame_rate.num, frame_rate.den); + return -1; + } [...] + put_bits(&s->pb,16,0); + put_bits(&s->pb,16,CAVS_START_CODE); add a put_bits_long() to bitstrea.c, document the issue with 32bits and fix vorbis_enc.c :) I looked a bit into this and I think a better way would be to fix put_bits() to support up to 32 bits instead of up to 31 bits. I am not so sure, but after a bit of checking in vorbis_enc.c it seems there is never any writing with more than 32 bits even though the local put_bits() function takes a 64bit argument. argh, ive not noticed that vorbis is using a private put_bits iam starting to hate vorbis_enc.c ...
Attached a new encoder patch and a proposed fix for put_bits(). the fix to put_bits is rejected due to a likely huge slowdown
It is in the else branch and only executed every 32 bits of bitstream writing, so I don't think the slowdown will be "huge". But if it's not acceptable I will think about adding a put_bits_long again.
the slowdown would affect all codecs, and i think it would be a significant slowdown its totally unacceptable just so you can replace put_bits(16); put_bits(16); by put_bits(32) in 1 or 2 codecs and without any benchmarks ...
So the problem is: h263.c has put_bits_(16);put_bits(16); cavsenc.c has put_bits_(16);put_bits(16); vorbis_enc.c has it's own put_bits implementation Solutions: keep as is (you complained) fix as I proposed (too slow) create a proper put_bits_long function (seems overkill) what about a silly and untested void put_bits_long(PutBitContext *s, int n, uint64_t value) { int rem = n>>1; put_bits(s,n-rem,value>>rem); put_bits(s,rem,value&((1<<rem)-1)); } to encode 0..62 bits ?
[...]
[...]
+ h->dist[0] = (h->picture.poc - h->DPB[0].poc + 512) % 512; + h->dist[1] = (h->picture.poc - h->DPB[1].poc + 512) % 512; &511 ?
It is not speed critical, and then I find the modulo more readable.
its +% vs &, ( 2 vs. 1 operations) so the modulo likely does make the binary by a byte or 2 larger ...
[...]
[...]
+ h->levels[0] = av_mallocz(6*64*sizeof(DCTELEM)); + h->runs[0] = av_mallocz(6*64); + for(i=1;i<6;i++) { + h->levels[i] = h->levels[i-1] + 64; + h->runs[i] = h->runs[i-1] + 64; + } why is this allocated with malloc instead of being part of the context? It keeps the context smaller when only the decoder is running.
hmm, ok, still its not ideal, as this requires an extra pointer dereference to access
Ok, I will change this in the next round. Stefan -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGqQVHYpYOlpT3vNMRAsF+AKCXSeEzTDNKssm3PkHFHsVQpzXgJwCg5nI2 F7ydbEy1vt/XaBQjvA34GKs= =4EuI -----END PGP SIGNATURE-----
Hi On Thu, Jul 26, 2007 at 10:34:15PM +0200, Stefan Gehrer wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hi
Michael Niedermayer wrote:
[...] > +/** > + * eliminate residual blocks that only have insignificant coefficients, > + * inspired from x264 and JVT-B118 > + */ > +static inline int decimate_block(uint8_t *run, DCTELEM *level, int count) { > + static const uint8_t run_score[30] = { > + 0,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 }; > + int i; > + int score = 0; > + > + if(count>4) > + return 9; > + for(i=0;i<count;i++) { > + int abslevel = FFABS(level[i]); > + if(abslevel > 1) > + return 9; > + score += run_score[FFMIN(run[i],29)]; > + } > + return score; > +} how much psnr/bitrate is gained by this? if none then please drop it I tested on the popular foreman (300 CIF frames). When encoding at around 800kbps, roughly 0.1dB are gained by this. When encoding at around 200kbps, this increases to a gain of around 0.15dB. So I would like to keep it. ok, but i think there is something wrong elsewhere if there is such a large gain from this ... maybe a simple change to the bias would help? or maybe there is something else wrong with the quantization code ...
why? It seems clear to me that coding a macroblock as skipped is so much cheaper than coding type/cbp/mv/coefficients that it might be worth throwing some real information away. By real I mean coefficients that come out of a fully correct quantization code, though I am not claiming my code to be that.
you should just make RD optimal decissions (IIRC you do calculate the RD all over the place anyway), if you do no heuristic like above will help
Okay, I think I see what you mean. Currently I use RD-decisions to select intra prediction modes and for the motion estimation, but for the macroblock mode decision there are some heuristics roughly like this:
if(only insignificant coefficients) encode mb as skipped else RD = P motion estimation if(RD < threshold) encode mb as p else encode mb as intra
By using RD optimal decisions do you mean I should encode every macroblock in all three modes (skipped/p/intra) and select the best of three,
yes, thats also what every document about video encoding recommands for high quality ... you could make it optional and make it dependant on mb_decision but it doesnt make much sense, noone these days encodes with simple mb_decision except for realtime encoding on slow hw ...
or rather I should try one mode and if its RD cost is below a certain threshold I should take it, otherwise I should move on to the next mode?
[...]
> + for(i=0;i<15;i++) > + if((ff_frame_rate_tab[i].den == frame_rate.den) && > + (ff_frame_rate_tab[i].num == frame_rate.num)) > + frame_rate_code = i; > + if(frame_rate_code < 0) { > + av_log(h->s.avctx, AV_LOG_ERROR, "unsupported framerate %d/%d\n", > + frame_rate.num, frame_rate.den); > + return -1; > + } [...] > + put_bits(&s->pb,16,0); > + put_bits(&s->pb,16,CAVS_START_CODE); add a put_bits_long() to bitstrea.c, document the issue with 32bits and fix vorbis_enc.c :) I looked a bit into this and I think a better way would be to fix put_bits() to support up to 32 bits instead of up to 31 bits. I am not so sure, but after a bit of checking in vorbis_enc.c it seems there is never any writing with more than 32 bits even though the local put_bits() function takes a 64bit argument. argh, ive not noticed that vorbis is using a private put_bits iam starting to hate vorbis_enc.c ...
Attached a new encoder patch and a proposed fix for put_bits(). the fix to put_bits is rejected due to a likely huge slowdown
It is in the else branch and only executed every 32 bits of bitstream writing, so I don't think the slowdown will be "huge". But if it's not acceptable I will think about adding a put_bits_long again.
the slowdown would affect all codecs, and i think it would be a significant slowdown its totally unacceptable just so you can replace put_bits(16); put_bits(16); by put_bits(32) in 1 or 2 codecs and without any benchmarks ...
So the problem is: h263.c has put_bits_(16);put_bits(16); cavsenc.c has put_bits_(16);put_bits(16); vorbis_enc.c has it's own put_bits implementation
Solutions: keep as is (you complained) fix as I proposed (too slow) create a proper put_bits_long function (seems overkill)
what about a silly and untested void put_bits_long(PutBitContext *s, int n, uint64_t value) { int rem = n>>1; put_bits(s,n-rem,value>>rem); put_bits(s,rem,value&((1<<rem)-1)); } to encode 0..62 bits ?
i dont like it maybe we should just leave the 16;16 code i guess it doesnt really hurt [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Dictatorship naturally arises out of democracy, and the most aggravated form of tyranny and slavery out of the most extreme liberty. -- Plato
On 07/25/2007 07:50 AM, Stefan Gehrer wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hi,
Michael Niedermayer wrote:
Michael, regarding your question on cvslog (sorry for crossposting, I wasn't subscribed to cvslog at the time):
Author: stefang Date: Sat Jul 7 09:14:58 2007 New Revision: 9518
Log: move dequantization into it's own inline function why inline? same question for the other inline functions is there some speed gain from duplicating them in the object files between encoder and decoder? To be honest I did not think much about object size, it just seemed to be a convenient way to share functions this way instead of having to create ff_cavs_foobar names and without creating function call overhead that was not there before. If you think object size would be a problem I can of course move some functions back from cavs.h to cavs.c.
yes please do unless theres a real speed loss from doing so
done
[...]
+/** + * eliminate residual blocks that only have insignificant coefficients, + * inspired from x264 and JVT-B118 + */ +static inline int decimate_block(uint8_t *run, DCTELEM *level, int count) { + static const uint8_t run_score[30] = { + 0,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 }; + int i; + int score = 0; + + if(count>4) + return 9; + for(i=0;i<count;i++) { + int abslevel = FFABS(level[i]); + if(abslevel> 1) + return 9; + score += run_score[FFMIN(run[i],29)]; + } + return score; +}
how much psnr/bitrate is gained by this? if none then please drop it
I tested on the popular foreman (300 CIF frames). When encoding at around 800kbps, roughly 0.1dB are gained by this. When encoding at around 200kbps, this increases to a gain of around 0.15dB. So I would like to keep it.
[...]
+ av_reduce(&frame_rate.den,&frame_rate.num, + s->avctx->time_base.num, s->avctx->time_base.den, 60000);
if the exact one isnt support then the code should failm its the user apps job to choose a supported one
removed
+ for(i=0;i<15;i++) + if((ff_frame_rate_tab[i].den == frame_rate.den)&& + (ff_frame_rate_tab[i].num == frame_rate.num)) + frame_rate_code = i; + if(frame_rate_code< 0) { + av_log(h->s.avctx, AV_LOG_ERROR, "unsupported framerate %d/%d\n", + frame_rate.num, frame_rate.den); + return -1; + }
[...]
+ put_bits(&s->pb,16,0); + put_bits(&s->pb,16,CAVS_START_CODE);
add a put_bits_long() to bitstrea.c, document the issue with 32bits and fix vorbis_enc.c :)
I looked a bit into this and I think a better way would be to fix put_bits() to support up to 32 bits instead of up to 31 bits. I am not so sure, but after a bit of checking in vorbis_enc.c it seems there is never any writing with more than 32 bits even though the local put_bits() function takes a 64bit argument.
Attached a new encoder patch and a proposed fix for put_bits().
Git-friendly patches attached so patchwork will catch it up. -Vitor
From stefan.gehreratgmx.de Sun Jan 23 16:19:30 2011 From: stefan.gehreratgmx.de (Stefan Gehrer) Date: Sun, 23 Jan 2011 16:19:30 +0100 Subject: [PATCH 1/2] Make put_bits() support 32 bits instead of 31 Message-ID: <mailman.461.1295796257.1307.ffmpeg-devel@mplayerhq.hu>
--- libavcodec/bitstream.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream.h index fd1b4a9..04942a0 100644 --- a/libavcodec/bitstream.h +++ b/libavcodec/bitstream.h @@ -226,7 +226,7 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value) bit_buf = (bit_buf<<n) | value; bit_left-=n; } else { - bit_buf<<=bit_left; + bit_buf = (uint64_t)bit_buf << bit_left; bit_buf |= value >> (n - bit_left); #ifdef UNALIGNED_STORES_ARE_BAD if (3 & (intptr_t) s->buf_ptr) { -- 1.7.1 --------------010605070306040906030502 Content-Type: text/x-patch; name="0002-Chinese-AVS-encoder.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0002-Chinese-AVS-encoder.patch"
From stefan.gehreratgmx.de Sun Jan 23 16:21:20 2011 From: stefan.gehreratgmx.de (Stefan Gehrer) Date: Sun, 23 Jan 2011 16:21:20 +0100 Subject: [PATCH 2/2] Chinese AVS encoder Message-ID: <mailman.462.1295796257.1307.ffmpeg-devel@mplayerhq.hu>
--- Changelog | 1 + doc/ffmpeg-doc.texi | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 2 +- libavcodec/allcodecs.h | 1 + libavcodec/cavs.c | 4 +- libavcodec/cavs.h | 27 ++- libavcodec/cavsdsp.c | 99 +++++++- libavcodec/cavsenc.c | 687 ++++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/dsputil.h | 3 + 10 files changed, 821 insertions(+), 5 deletions(-) create mode 100644 libavcodec/cavsenc.c diff --git a/Changelog b/Changelog index 6ecbdb7..d8d177b 100644 --- a/Changelog +++ b/Changelog @@ -90,6 +90,7 @@ version <next> - RoQ video encoder - QTRLE encoder - OS/2 support removed +- Chinese AVS encoder version 0.4.9-pre1: diff --git a/doc/ffmpeg-doc.texi b/doc/ffmpeg-doc.texi index fca90cc..0e99c29 100644 --- a/doc/ffmpeg-doc.texi +++ b/doc/ffmpeg-doc.texi @@ -1072,6 +1072,7 @@ following image formats are supported: @item THP @tab @tab X @tab Used on the Nintendo GameCube. @item Bethsoft VID @tab @tab X @tab Used in some games from Bethesda Softworks. @item Renderware TXD @tab @tab X @tab Texture dictionaries used by the Renderware Engine. + at item Chinese AVS @tab X @tab X @tab JiZhun Profile @end multitable @code{X} means that encoding (resp. decoding) is supported. diff --git a/libavcodec/Makefile b/libavcodec/Makefile index e1685fe..47ffdae 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -45,6 +45,7 @@ OBJS-$(CONFIG_BMP_DECODER) += bmp.o OBJS-$(CONFIG_BMP_ENCODER) += bmpenc.o OBJS-$(CONFIG_C93_DECODER) += c93.o OBJS-$(CONFIG_CAVS_DECODER) += cavs.o cavsdec.o cavsdsp.o golomb.o +OBJS-$(CONFIG_CAVS_ENCODER) += cavs.o cavsenc.o cavsdsp.o golomb.o OBJS-$(CONFIG_CINEPAK_DECODER) += cinepak.o OBJS-$(CONFIG_CLJR_DECODER) += cljr.o OBJS-$(CONFIG_CLJR_ENCODER) += cljr.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 8153e41..5a8f69b 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -63,7 +63,7 @@ void avcodec_register_all(void) REGISTER_DECODER(BETHSOFTVID, bethsoftvid); REGISTER_ENCDEC (BMP, bmp); REGISTER_DECODER(C93, c93); - REGISTER_DECODER(CAVS, cavs); + REGISTER_ENCDEC (CAVS, cavs); REGISTER_DECODER(CINEPAK, cinepak); REGISTER_DECODER(CLJR, cljr); REGISTER_DECODER(CSCD, cscd); diff --git a/libavcodec/allcodecs.h b/libavcodec/allcodecs.h index 3e18ca0..3d32945 100644 --- a/libavcodec/allcodecs.h +++ b/libavcodec/allcodecs.h @@ -27,6 +27,7 @@ extern AVCodec ac3_encoder; extern AVCodec asv1_encoder; extern AVCodec asv2_encoder; extern AVCodec bmp_encoder; +extern AVCodec cavs_encoder; extern AVCodec dvvideo_encoder; extern AVCodec ffv1_encoder; extern AVCodec ffvhuff_encoder; diff --git a/libavcodec/cavs.c b/libavcodec/cavs.c index 31b7e58..323989b 100644 --- a/libavcodec/cavs.c +++ b/libavcodec/cavs.c @@ -1,5 +1,5 @@ /* - * Chinese AVS video (AVS1-P2, JiZhun profile) decoder. + * Chinese AVS video (AVS1-P2, JiZhun profile) codec * Copyright (c) 2006 Stefan Gehrer <stefan.gehrer at gmx.de> * * This file is part of FFmpeg. @@ -21,7 +21,7 @@ /** * @file cavs.c - * Chinese AVS video (AVS1-P2, JiZhun profile) decoder + * Chinese AVS video (AVS1-P2, JiZhun profile) codec * @author Stefan Gehrer <stefan.gehrer at gmx.de> */ diff --git a/libavcodec/cavs.h b/libavcodec/cavs.h index adc9c24..fad084a 100644 --- a/libavcodec/cavs.h +++ b/libavcodec/cavs.h @@ -55,6 +55,13 @@ #define MV_BWD_OFFS 12 #define MV_STRIDE 4 +#define CAVS_MAX_RUN 25 +#define CAVS_MAX_LEVEL 26 +#define INTRA_BIAS 38<<8 +#define INTER_BIAS 28<<8 +#define ME_THRES 77000 +#define ME_ITER 20 + enum mb_t { I_8X8 = 0, P_SKIP, @@ -104,7 +111,8 @@ enum mv_pred_t { MV_PRED_TOP, MV_PRED_TOPRIGHT, MV_PRED_PSKIP, - MV_PRED_BSKIP + MV_PRED_BSKIP, + MV_PRED_ENC }; enum block_t { @@ -153,9 +161,16 @@ typedef struct dec_2dvlc_t { } dec_2dvlc_t; typedef struct { + int8_t rlcode[CAVS_MAX_RUN+1][CAVS_MAX_LEVEL+1]; + int end_code; + const dec_2dvlc_t *dec; +} enc_2dvlc_t; + +typedef struct { MpegEncContext s; Picture picture; ///< currently decoded frame Picture DPB[2]; ///< reference frames + Picture input_picture; ///< encoder input int dist[2]; ///< temporal distances from current frame to ref frames int profile, level; int aspect_ratio; @@ -171,6 +186,7 @@ typedef struct { int flags; ///< availability flags of neighbouring macroblocks int stc; ///< last start code uint8_t *cy, *cu, *cv; ///< current MB sample pointers + uint8_t *ey, *eu, *ev; ///< encoded MB sample pointers int left_qp; uint8_t *top_qp; @@ -222,6 +238,15 @@ typedef struct { int got_keyframe; DCTELEM *block; + + /* encoder only */ + DCTELEM *levels[6]; + uint8_t *runs[6]; + int total_coeff[6]; + int lambda; + int mrefs; ///< flag: one reference frame (0) or two (1) + int skip_count; + int poc; ///< picture order count } AVSContext; extern const uint8_t ff_cavs_dequant_shift[64]; diff --git a/libavcodec/cavsdsp.c b/libavcodec/cavsdsp.c index fd744cc..5db9abd 100644 --- a/libavcodec/cavsdsp.c +++ b/libavcodec/cavsdsp.c @@ -1,5 +1,5 @@ /* - * Chinese AVS video (AVS1-P2, JiZhun profile) decoder. + * Chinese AVS video (AVS1-P2, JiZhun profile) codec * * DSP functions * @@ -177,6 +177,101 @@ static void cavs_filter_ch_c(uint8_t *d, int stride, int alpha, int beta, int tc /***************************************************************************** * + * quantization + * + ****************************************************************************/ + +static void cavs_quant_c(DCTELEM *block, const uint16_t *norm, int mul, + int bias) { + int i; + + for(i=0;i<64;i++) { + if(block[i] > 0) + block[i] = ((((1<<18) + block[i]*norm[i])>>19)*mul+bias)>>15; + else + block[i] = -(((((1<<18) - block[i]*norm[i])>>19)*mul+bias)>>15); + } +} + +/***************************************************************************** + * + * forward transform + * + ****************************************************************************/ + +static void cavs_sub_dct8_c(uint8_t *src1, uint8_t *src2, DCTELEM *block, int stride1, int stride2) { + int i,j; + DCTELEM (*dst)[8] = (DCTELEM(*)[8])block; + + for(j=0;j<8;j++) { + for(i=0;i<8;i++) + dst[j][i] = src1[i] - src2[i]; + src1 += stride1; + src2 += stride2; + } + + for(i = 0; i < 8; i++) { + const int a0 = dst[i][0] + dst[i][7]; + const int a1 = dst[i][1] + dst[i][6]; + const int a2 = dst[i][2] + dst[i][5]; + const int a3 = dst[i][3] + dst[i][4]; + const int a4 = dst[i][0] - dst[i][7]; + const int a5 = dst[i][1] - dst[i][6]; + const int a6 = dst[i][2] - dst[i][5]; + const int a7 = dst[i][3] - dst[i][4]; + + const int b0 = a0 + a3; + const int b1 = a1 + a2; + const int b2 = a0 - a3; + const int b3 = a1 - a2; + + const int b4 = ((a4 - a7)<<1) + a4; + const int b5 = ((a6 + a5)<<1) + a5; + const int b6 = ((a6 - a5)<<1) + a6; + const int b7 = ((a4 + a7)<<1) + a7; + + dst[i][0] = (b0 + b1)<<3; + dst[i][1] = ((b4 + b5 + b7)<<1) + b5; + dst[i][2] = b2*10 + b3*4; + dst[i][3] = ((b4 - b5 - b6)<<1) + b4; + dst[i][4] = (b0 - b1)<<3; + dst[i][5] = ((b7 - b5 + b6)<<1) + b7; + dst[i][6] = b2*4 - b3*10; + dst[i][7] = ((b4 + b6 - b7)<<1) + b6; + } + for(i = 0; i < 8; i++) { + const int a0 = dst[0][i] + dst[7][i]; + const int a1 = dst[1][i] + dst[6][i]; + const int a2 = dst[2][i] + dst[5][i]; + const int a3 = dst[3][i] + dst[4][i]; + const int a4 = dst[0][i] - dst[7][i]; + const int a5 = dst[1][i] - dst[6][i]; + const int a6 = dst[2][i] - dst[5][i]; + const int a7 = dst[3][i] - dst[4][i]; + + const int b0 = a0 + a3 + 2; + const int b1 = a1 + a2; + const int b2 = a0 - a3; + const int b3 = a1 - a2; + + const int b4 = ((a4 - a7)<<1) + a4; + const int b5 = ((a6 + a5)<<1) + a5; + const int b6 = ((a6 - a5)<<1) + a6; + const int b7 = ((a4 + a7)<<1) + a7; + + dst[0][i] = (((b0 + b1)<<3) + 0)>>5; + dst[1][i] = ((((b4 + b5 + b7)<<1) + b5)+16)>>5; + dst[2][i] = ((b2*10 + b3*4) +16)>>5; + dst[3][i] = ((((b4 - b5 - b6)<<1) + b4)+16)>>5; + dst[4][i] = (((b0 - b1)<<3) + 0)>>5; + dst[5][i] = ((((b7 - b5 + b6)<<1) + b7)+16)>>5; + dst[6][i] = ((b2*4 - b3*10) +16)>>5; + dst[7][i] = ((((b4 + b6 - b7)<<1) + b6)+16)>>5; + } +} + +/***************************************************************************** + * * inverse transform * ****************************************************************************/ @@ -543,4 +638,6 @@ void ff_cavsdsp_init(DSPContext* c, AVCodecContext *avctx) { c->cavs_filter_cv = cavs_filter_cv_c; c->cavs_filter_ch = cavs_filter_ch_c; c->cavs_idct8_add = cavs_idct8_add_c; + c->cavs_sub_dct8 = cavs_sub_dct8_c; + c->cavs_quant = cavs_quant_c; } diff --git a/libavcodec/cavsenc.c b/libavcodec/cavsenc.c new file mode 100644 index 0000000..d2d2743 --- /dev/null +++ b/libavcodec/cavsenc.c @@ -0,0 +1,687 @@ +/* + * Chinese AVS video (AVS1-P2, JiZhun profile) encoder + * Copyright (c) 2006 Stefan Gehrer <stefan.gehrer at gmx.de> + * + * 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 + */ + +/** + * @file cavsenc.c + * Chinese AVS video (AVS1-P2, JiZhun profile) encoder + * @author Stefan Gehrer <stefan.gehrer at gmx.de> + */ + +#include "avcodec.h" +#include "golomb.h" +#include "cavs.h" + +static const uint8_t cbp_enc_tab[64][2] = { + { 4, 0},{16,19},{17,16},{19,15},{14,18},{ 9,11},{22,31},{ 8,13}, + {11,17},{21,30},{10,12},{ 7, 9},{12,10},{ 6, 7},{ 5, 8},{ 1, 1}, + {35, 4},{47,42},{48,38},{38,27},{46,39},{36,33},{50,59},{26,26}, + {45,40},{52,58},{41,35},{28,25},{37,29},{23,24},{31,28},{ 2, 3}, + {43, 5},{51,51},{56,52},{39,37},{55,50},{33,43},{62,63},{27,44}, + {54,53},{60,62},{40,48},{32,47},{42,34},{24,45},{29,49},{ 3, 6}, + {49,14},{53,55},{57,56},{25,36},{58,54},{30,41},{59,60},{15,21}, + {61,57},{63,61},{44,46},{18,22},{34,32},{13,20},{20,23},{ 0, 2} +}; + +/* + * taken from AVS paper by Lu Yu/Feng Yi/Jie Dong/Cixun Zhang + * this is used to post-normalise the rounding errors of the + * forward transform in the encoder as well as pre-normalise the + * rounding errors of the inverse transform in the decoder, + * both due to using non-orthogonal integer matrices + */ +static const uint16_t quant_norm[64] = { + 32768, 37958, 36158, 37958, 32768, 37958, 36158, 37958, + 37958, 43969, 41884, 43969, 37958, 43969, 41884, 43969, + 36158, 41884, 39898, 41884, 36158, 41884, 39898, 41884, + 37958, 43969, 41884, 43969, 37958, 43969, 41884, 43969, + 32768, 37958, 36158, 37958, 32768, 37958, 36158, 37958, + 37958, 43969, 41884, 43969, 37958, 43969, 41884, 43969, + 36158, 41884, 39898, 41884, 36158, 41884, 39898, 41884, + 37958, 43969, 41884, 43969, 37958, 43969, 41884, 43969, +}; + +static const uint16_t quant_mul[64] = { + 32768,29775,27554,25268,23170,21247,19369,17770, + 16302,15024,13777,12634,11626,10624, 9742, 8958, + 8192, 7512, 6889, 6305, 5793, 5303, 4878, 4467, + 4091, 3756, 3444, 3161, 2894, 2654, 2435, 2235, + 2048, 1878, 1722, 1579, 1449, 1329, 1218, 1117, + 1024, 939, 861, 790, 724, 664, 609, 558, + 512, 470, 430, 395, 362, 332, 304, 279, + 256, 235, 215, 197, 181, 166, 152, 140 +}; + +static enc_2dvlc_t intra_enc[7]; +static enc_2dvlc_t inter_enc[7]; +static enc_2dvlc_t chroma_enc[5]; + +/***************************************************************************** + * + * residual data encoding + * + ****************************************************************************/ + +/** kth-order exponential golomb code */ +static inline void put_ue_code(PutBitContext *pb, int order, int value) { + set_ue_golomb(pb, value>>order); + put_bits(pb, order, value & ((1<<order)-1)); +} + +/** + * entropy coding of one residual 8x8 block + * @param enc pointer to 2D VLC encoding table + * @param esc_golomb_order escape codes are k-golomb with this order k + * @param qp quantizer + * @param block block number [0..5] + */ +static void encode_residual_block(AVSContext *h, PutBitContext *pb, + const enc_2dvlc_t *enc, int esc_golomb_order, + int qp, int block) { + int run = 0; + int coeff_num, level_code; + DCTELEM *level_buf = h->levels[block]; + uint8_t *run_buf = h->runs[block]; + const dec_2dvlc_t *dec = enc->dec; + + for(coeff_num=0;coeff_num<h->total_coeff[block];coeff_num++) { + int level = abs(level_buf[coeff_num])-1; + int sign = (level_buf[coeff_num]>>31)&1; + run = run_buf[coeff_num] - 1; + if((level > CAVS_MAX_LEVEL)||(run > CAVS_MAX_RUN) + ||((level_code = enc->rlcode[run][level])<0)) { + put_ue_code(pb,dec->golomb_order,run*2+ESCAPE_CODE+1-sign); + if(run >= dec->max_run) + put_ue_code(pb,esc_golomb_order, level); + else + put_ue_code(pb,esc_golomb_order, level + 1 - + dec->level_add[run+1]); + while(level >= dec->inc_limit) { + dec++; + enc++; + } + } else { + put_ue_code(pb,dec->golomb_order,level_code+sign); + enc += dec->rltab[level_code][2]; + dec += dec->rltab[level_code][2]; + } + } + put_ue_code(pb,dec->golomb_order,enc->end_code); +} + +/** + * entropy coding of one macroblock + * @param intra flag inter=0 intra=1 + */ +static void encode_residual(AVSContext *h, int intra) { + PutBitContext *pb = &h->s.pb; + int block; + + for(block=0;block<4;block++) + if(h->cbp & (1<<block)) { + if(intra) + encode_residual_block(h,pb,intra_enc,1,h->qp,block); + else + encode_residual_block(h,pb,inter_enc,0,h->qp,block); + } + if(h->cbp & (1<<4)) + encode_residual_block(h,pb,chroma_enc,0,ff_cavs_chroma_qp[h->qp], 4); + if(h->cbp & (1<<5)) + encode_residual_block(h,pb,chroma_enc,0,ff_cavs_chroma_qp[h->qp], 5); +} + +/** + * eliminate residual blocks that only have insignificant coefficients, + * inspired from x264 and JVT-B118 + */ +static inline int decimate_block(uint8_t *run, DCTELEM *level, int count) { + static const uint8_t run_score[30] = { + 0,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 }; + int i; + int score = 0; + + if(count>4) + return 9; + for(i=0;i<count;i++) { + int abslevel = FFABS(level[i]); + if(abslevel > 1) + return 9; + score += run_score[FFMIN(run[i],29)]; + } + return score; +} + +/***************************************************************************** + * + * reconstruction as the decoder sees it + * + ****************************************************************************/ + +static int recon_block(AVSContext *h, uint8_t *src1, uint8_t *src2, int stride, + int block, int qp, int intra) { + int i,pos; + int score = 9; + int run = 0; + const uint8_t *scantab = ff_zigzag_direct; + + h->s.dsp.cavs_sub_dct8(src1, src2, h->block, stride, stride); + h->s.dsp.cavs_quant(h->block, quant_norm, quant_mul[qp], + intra ? INTRA_BIAS : INTER_BIAS); + /* forward scan */ + for(pos=63,i=0;pos>=0;pos--) { + if(h->block[scantab[pos]]) { + if(i) + h->runs[block][i-1] = run+1; + h->levels[block][i++] = h->block[scantab[pos]]; + run = 0; + } else + run++; + } + /* eliminate empty or insignificant blocks */ + if(!i) + return 0; + h->runs[block][i-1] = run+1; + if(!intra) { + score = decimate_block(h->runs[block],h->levels[block],i); + h->total_coeff[block] = 0; + if(score < 4) + return score; + } + h->cbp |= (1 << block); + h->total_coeff[block] = i; + /* dequantise and restore blocks */ + dequant(h , h->levels[block], h->runs[block], h->block, + ff_cavs_dequant_mul[qp], ff_cavs_dequant_shift[qp], i); + h->s.dsp.cavs_idct8_add(src2, h->block, stride); + return score; +} + +static inline void recon_mb(AVSContext *h, int *lscore, int *cscore) { + int block; + + for(block=0;block<4;block++) + *lscore += recon_block(h, h->ey + h->luma_scan[block], + h->cy + h->luma_scan[block], + h->l_stride, block, h->qp, 0); + *cscore += recon_block(h, h->eu, h->cu, h->c_stride, 4, + ff_cavs_chroma_qp[h->qp], 0); + *cscore += recon_block(h, h->ev, h->cv, h->c_stride, 5, + ff_cavs_chroma_qp[h->qp], 0); +} + +/***************************************************************************** + * + * intra encoding + * + ****************************************************************************/ + +static inline int modify(int flags, int block, int mode) { + if(!(flags & A_AVAIL) && !(block & 1)) + mode = ff_left_modifier_l[mode]; + if(!(flags & B_AVAIL) && !(block & 2) && (mode >= 0)) + mode = ff_top_modifier_l[mode]; + return mode; +} + +static void encode_mb_i(AVSContext *h) { + PutBitContext *pb = &h->s.pb; + int block, i, pred_mode_uv, min_cost, mode, best_mode, diff; + int coded_mode[5]; + uint8_t top[18]; + uint8_t *left = NULL; + uint8_t *d; + uint8_t *s; + + assert(h->mbx || (!(h->flags & A_AVAIL))); + h->lambda = h->qp/3; + h->cbp = pred_mode_uv = best_mode = 0; + for(block=0;block<4;block++) { + int pos = ff_cavs_scan3x3[block]; + int predpred = FFMIN(h->pred_mode_Y[pos-1], h->pred_mode_Y[pos-3]); + + min_cost = INT_MAX; + s = h->ey + h->luma_scan[block]; + d = h->cy + h->luma_scan[block]; + ff_cavs_load_intra_pred_luma(h, top, &left, block); + if(predpred == NOT_AVAIL) // if either is not available + predpred = INTRA_L_LP; + + /* try all luma intra prediction modes */ + for(i=0;i<5;i++) { + const int bitcost[5] = {3,3,3,3,1}; + + mode = (i == 4) ? predpred : i + (i >= predpred); + mode = modify(h->flags, block, mode); + if(mode >= 0) { + h->intra_pred_l[mode](d, top, left, h->l_stride); + diff = h->s.dsp.sse[1](NULL, s, d, h->l_stride, 8); + if((bitcost[i]*h->lambda + diff) < min_cost) { + min_cost = bitcost[i]*h->lambda + diff; + coded_mode[block] = i; + best_mode = mode; + h->pred_mode_Y[pos] = (i == 4) ? predpred : i + (i >= predpred); + } + } + } + /* reconstruct block for next one */ + h->intra_pred_l[best_mode](d, top, left, h->l_stride); + recon_block(h, s, d, h->l_stride, block, h->qp, 1); + } + + /* try all chroma intra prediction modes */ + ff_cavs_load_intra_pred_chroma(h); + min_cost = INT_MAX; + for(i=0;i<4;i++) { + const int bitcost[4] = {1,3,3,5}; + + mode = i; + if(!(h->flags & A_AVAIL)) + mode = ff_left_modifier_c[mode]; + if(!(h->flags & B_AVAIL) && (mode >=0)) + mode = ff_top_modifier_c[mode]; + if(mode >= 0) { + h->intra_pred_c[mode](h->cu, &h->top_border_u[h->mbx*10], + h->left_border_u, h->c_stride); + diff = h->s.dsp.sse[1](NULL, h->eu, h->cu, h->c_stride, 8); + h->intra_pred_c[mode](h->cv, &h->top_border_v[h->mbx*10], + h->left_border_v, h->c_stride); + diff += h->s.dsp.sse[1](NULL, h->ev, h->cv, h->c_stride, 8); + if((bitcost[i]*h->lambda + diff) < min_cost) { + min_cost = bitcost[i]*h->lambda + diff; + pred_mode_uv = mode; + coded_mode[4] = i; + } + } + } + + /* reconstruct blocks */ + h->intra_pred_c[pred_mode_uv](h->cu, &h->top_border_u[h->mbx*10], + h->left_border_u, h->c_stride); + recon_block(h, h->eu, h->cu, h->c_stride, 4, ff_cavs_chroma_qp[h->qp], 1); + h->intra_pred_c[pred_mode_uv](h->cv, &h->top_border_v[h->mbx*10], + h->left_border_v, h->c_stride); + recon_block(h, h->ev, h->cv, h->c_stride, 5, ff_cavs_chroma_qp[h->qp], 1); + + ff_cavs_modify_mb_i(h,&pred_mode_uv); + + if(h->pic_type != FF_I_TYPE) + set_ue_golomb(pb, cbp_enc_tab[h->cbp][0] + 4); + for(block=0;block<4;block++) + if(coded_mode[block] == 4) + put_bits(pb,1,1); + else + put_bits(pb,3,coded_mode[block]); + set_ue_golomb(pb,coded_mode[4]); + if(h->pic_type == FF_I_TYPE) + set_ue_golomb(pb, cbp_enc_tab[h->cbp][0]); + encode_residual(h, 1); + ff_cavs_filter(h,I_8X8); + set_mv_intra(h); +} + +/***************************************************************************** + * + * inter P encoding + * + ****************************************************************************/ + +static inline int mv_cost(vector_t *mv, vector_t *pmv) { + int x = FFABS(mv->x - pmv->x); + int y = FFABS(mv->y - pmv->y); + return 2*(av_log2(x*2)+av_log2(y*2))+2; +} + +static inline int check_mv(AVSContext *h, int x, int y, vector_t *pmv, + vector_t *mvmin, int *min_cost) { + int diff; + + h->mv[MV_FWD_X0].x = x; + h->mv[MV_FWD_X0].y = y; + ff_cavs_inter(h, P_16X16); + diff = h->s.dsp.sse[0](NULL, h->ey, h->cy, h->l_stride, 16); + if((mv_cost(&h->mv[MV_FWD_X0],pmv)*h->lambda + diff) < *min_cost) { + *mvmin = h->mv[MV_FWD_X0]; + *min_cost = mv_cost(&h->mv[MV_FWD_X0],pmv)*h->lambda + diff; + return 1; + } + return 0; +} + +static void encode_mb_p(AVSContext *h) { + PutBitContext *pb = &h->s.pb; + int lscore = 0; + int cscore = 0; + + h->lambda = h->qp/8; + + /* test if we can skip */ + ff_cavs_mv(h, MV_FWD_X0, MV_FWD_C2, MV_PRED_PSKIP, BLK_16X16, 0); + ff_cavs_inter(h, P_SKIP); + recon_mb(h, &lscore, &cscore); + if(lscore < 6 && cscore < 7) { + h->skip_count++; + if(h->cbp) //there can be an undecimated block + ff_cavs_inter(h, P_SKIP); + set_intra_mode_default(h); + ff_cavs_filter(h,P_SKIP); + } else { + int hex[6][2] = {{-4,-8},{4,-8},{8,0},{4,8},{-4,8},{-8,0}}; + vector_t pmv[2], mv[2], mvmin; + int i, sub, x, y, min_cost[2], ref, count; + int newmv = 1; + + set_ue_golomb(pb,h->skip_count); + h->skip_count = h->cbp = 0; + + for(ref=0;ref<=h->mrefs;ref++) { + /* get predicted mv */ + h->mv[MV_FWD_X0].ref=mv[ref].ref=pmv[ref].ref=mvmin.ref = ref; + ff_cavs_mv(h, MV_FWD_X0, MV_FWD_C2, MV_PRED_ENC, BLK_16X16, ref); + pmv[ref] = h->mv[MV_FWD_X0]; + + /* predicted full-pel mv as reference */ + h->mv[MV_FWD_X0].x = mv[ref].x = mvmin.x = (pmv[ref].x+2) & ~3; + h->mv[MV_FWD_X0].y = mv[ref].y = mvmin.y = (pmv[ref].y+2) & ~3; + ff_cavs_inter(h, P_16X16); + min_cost[ref] = h->s.dsp.sse[0](NULL,h->ey,h->cy,h->l_stride,16) + + mv_cost(&mv[ref],&pmv[ref])*h->lambda; + + /* iterative hex search */ + count = ME_ITER; + while(newmv && count--) { + newmv = 0; + for(i=0;i<6;i++) + if(check_mv(h, mv[ref].x+hex[i][0], mv[ref].y+hex[i][1], + &pmv[ref], &mvmin, &min_cost[ref])) + newmv = 1; + mv[ref] = mvmin; + } + + /* refinement (full,half,quarter) */ + for(sub=4;sub>0;sub>>=1) { + for(x=-sub;x<=sub;x+=sub) + for(y=-sub;y<=sub;y+=sub) + if(x|y) + check_mv(h, mv[ref].x+x, mv[ref].y+y, + &pmv[ref], &mvmin, &min_cost[ref]); + mv[ref] = mvmin; + } + } + ref = (h->mrefs && (min_cost[1] < min_cost[0])); + if(min_cost[ref] < ME_THRES) { + h->mv[MV_FWD_X0] = mv[ref]; + set_mvs(&h->mv[MV_FWD_X0],BLK_16X16); + ff_cavs_inter(h, P_16X16); + recon_mb(h,&lscore,&cscore); + set_intra_mode_default(h); + set_ue_golomb(pb,0); //mb_type is P_16X16 + if(h->mrefs) + put_bits(pb,1,ref); + set_se_golomb(pb,mv[ref].x - pmv[ref].x); //mvd + set_se_golomb(pb,mv[ref].y - pmv[ref].y); + set_ue_golomb(pb, cbp_enc_tab[h->cbp][1]); + encode_residual(h, 0); + ff_cavs_filter(h,P_16X16); + } else { + encode_mb_i(h); + } + } +} + +/***************************************************************************** + * + * header encoding + * + ****************************************************************************/ + +static int encode_pic(AVSContext *h, Picture *p) { + MpegEncContext *s = &h->s; + int deblock = 1; + + if (!s->context_initialized) { + s->avctx->idct_algo = FF_IDCT_CAVS; + if (MPV_common_init(s) < 0) + return -1; + ff_init_scantable(s->dsp.idct_permutation,&h->scantable,ff_zigzag_direct); + } + put_bits(&s->pb,16,0xdeaf); //TODO correct bbv_dwlay + if(h->pic_type == FF_I_TYPE) + put_bits(&s->pb,1,0); //time_code not present + else + put_bits(&s->pb,2,1); //picture type P + s->avctx->get_buffer(s->avctx, (AVFrame *)&h->picture); + ff_cavs_init_pic(h); + put_bits(&s->pb,8,h->poc); + h->picture.poc = h->poc*2; + h->dist[0] = (h->picture.poc - h->DPB[0].poc + 512) % 512; + h->dist[1] = (h->picture.poc - h->DPB[1].poc + 512) % 512; + h->scale_den[0] = h->dist[0] ? 512/h->dist[0] : 0; + h->scale_den[1] = h->dist[1] ? 512/h->dist[1] : 0; + h->poc = (h->poc + 1) & 0x7F; + + if(s->low_delay) + set_ue_golomb(&s->pb,0); //TODO correct bbv_check_times? + put_bits(&s->pb,1,1); //set progressive + + put_bits(&s->pb,1,1); //top_field_first + put_bits(&s->pb,1,0); //repeat_first_field + put_bits(&s->pb,1,1); //set qp_fixed + put_bits(&s->pb,6,h->qp); + if(h->pic_type == FF_I_TYPE) { + put_bits(&s->pb,4,0); //reserved bits + } else { + h->mrefs = !!h->DPB[1].data[0] && (s->avctx->refs > 1); + if(!(h->pic_type == FF_B_TYPE)) + put_bits(&s->pb,1,!h->mrefs); //multiple references + put_bits(&s->pb,4,0); //reserved bits + put_bits(&s->pb,1,1); //skip_mode_flag + } + put_bits(&s->pb,1,!deblock); + if(deblock) { + if(h->s.avctx->deblockalpha || h->s.avctx->deblockbeta) { + put_bits(&s->pb,1,1); //deblocking params coded + set_se_golomb(&s->pb, h->s.avctx->deblockalpha); + set_se_golomb(&s->pb, h->s.avctx->deblockbeta); + } else { + put_bits(&s->pb,1,0); //deblocking params not coded + } + } + h->skip_count = 0; + do { + h->ey = p->data[0] + h->mby*16*h->l_stride + h->mbx*16; + h->eu = p->data[1] + h->mby*8*h->c_stride + h->mbx*8; + h->ev = p->data[2] + h->mby*8*h->c_stride + h->mbx*8; + ff_cavs_init_mb(h); + if(h->pic_type == FF_I_TYPE) + encode_mb_i(h); + else + encode_mb_p(h); + } while(ff_cavs_next_mb(h)); + if(h->DPB[1].data[0]) + s->avctx->release_buffer(s->avctx, (AVFrame *)&h->DPB[1]); + memcpy(&h->DPB[1], &h->DPB[0], sizeof(Picture)); + memcpy(&h->DPB[0], &h->picture, sizeof(Picture)); + return 0; +} + +static int encode_seq_header(AVSContext *h) { + MpegEncContext *s = &h->s; + int frame_rate_code = -1; + int i; + + s->width = h->s.avctx->width; + s->height = h->s.avctx->height; + put_bits(&s->pb,8,h->profile); + put_bits(&s->pb,8,h->level); + put_bits(&s->pb,1,1); //progressive sequence only + put_bits(&s->pb,14,s->width); + put_bits(&s->pb,14,s->height); + put_bits(&s->pb,2,1); // 1 = YUV 4:2:0, 2 = YUV 4:2:2 + put_bits(&s->pb,3,1); //sample_precision 8bits + put_bits(&s->pb,4,h->aspect_ratio); + for(i=0;i<15;i++) + if((ff_frame_rate_tab[i].den == s->avctx->time_base.num) && + (ff_frame_rate_tab[i].num == s->avctx->time_base.den)) + frame_rate_code = i; + if(frame_rate_code < 0) { + av_log(h->s.avctx, AV_LOG_ERROR, "unsupported framerate %d/%d\n", + s->avctx->time_base.den, s->avctx->time_base.num); + return -1; + } + put_bits(&s->pb,4,frame_rate_code & 0xF); + put_bits(&s->pb,18,0); //bit_rate_lower + put_bits(&s->pb,1,1); //marker_bit + put_bits(&s->pb,12,1); //bit_rate_upper + put_bits(&s->pb,1,s->low_delay); + put_bits(&s->pb,1,1); //marker_bit + put_bits(&s->pb,18,225); //bbv_buffer_size, enough for level 6.2 + put_bits(&s->pb,3,0); //reserved_bits + + h->mb_width = (s->width + 15) >> 4; + h->mb_height = (s->height + 15) >> 4; + if(!h->top_qp) { + ff_cavs_init_top_lines(h); + h->levels[0] = av_mallocz(6*64*sizeof(DCTELEM)); + h->runs[0] = av_mallocz(6*64); + for(i=1;i<6;i++) { + h->levels[i] = h->levels[i-1] + 64; + h->runs[i] = h->runs[i-1] + 64; + } + } + return 0; +} + +static int cavs_encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){ + AVSContext *h = avctx->priv_data; + MpegEncContext * const s = &h->s; + AVFrame *pict = data; + const int width= s->avctx->width; + const int height= s->avctx->height; + int size, i, y; + + for(i=0; i<3; i++){ + int shift= !!i; + for(y=0; y<(height>>shift); y++) + memcpy(&h->input_picture.data[i][y * h->input_picture.linesize[i]], + &pict->data[i][y * pict->linesize[i]], + width>>shift); + } + if(avctx->gop_size == 0 || h->poc % avctx->gop_size == 0) { + h->input_picture.pict_type= I_TYPE; + h->pic_type= FF_I_TYPE; + h->input_picture.key_frame= 1; + } else { + h->input_picture.pict_type= P_TYPE; + h->pic_type= FF_P_TYPE; + } + + init_put_bits(&s->pb, buf, buf_size); + if(h->pic_type == FF_I_TYPE) { + if(h->DPB[0].data[0]) + avctx->release_buffer(avctx, (AVFrame *)&h->DPB[0]); + if(h->DPB[1].data[0]) + avctx->release_buffer(avctx, (AVFrame *)&h->DPB[1]); + put_bits(&s->pb,16,0); + put_bits(&s->pb,16,CAVS_START_CODE); + if(encode_seq_header(h) < 0) + return -1; + align_put_bits(&s->pb); + put_bits(&s->pb,16,0); + put_bits(&s->pb,16,PIC_I_START_CODE); + } else { + put_bits(&s->pb,16,0); + put_bits(&s->pb,16,PIC_PB_START_CODE); + } + encode_pic(h, &h->input_picture); + align_put_bits(&s->pb); + flush_put_bits(&s->pb); + size = put_bits_count(&s->pb)/8; + if(avctx->flags&CODEC_FLAG_PSNR) { + int i,x,y; + for(i=0;i<3;i++) { + int wi = s->width >> (!!i); + int he = s->height >> (!!i); + int64_t error = 0; + for(y=0;y<he;y++) + for(x=0;x<wi;x++) { + int d = h->picture.data[i][y*h->picture.linesize[i] + x] + - pict->data[i][y* pict->linesize[i] + x]; + error += d*d; + } + s->avctx->error[i] += error; + h->picture.error[i] = error; + } + } + memset(&h->picture,0,sizeof(Picture)); + return size; +} + +static void init_enc_vlc(enc_2dvlc_t *enc, const dec_2dvlc_t *dec, int count) { + int i,j; + + for(j=0;j<count;j++) { + memset(enc, -1, sizeof(enc_2dvlc_t)); + for(i=0;i<ESCAPE_CODE;i++) { + if(dec->rltab[i][0]) { + enc->rlcode[dec->rltab[i][1]-1][dec->rltab[i][0]-1] = i; + i++; //skip negative level + } else + enc->end_code = i; + } + enc->dec = dec; + enc++; + dec++; + } +} + +static int cavs_encode_init(AVCodecContext * avctx) { + AVSContext *h = avctx->priv_data; + MpegEncContext * const s = &h->s; + + if(avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL){ + av_log(avctx, AV_LOG_ERROR, "Chinese AVS encoder has not been tested for standard compliance.\n" + "use vstrict=-2 / -strict -2 to use it anyway\n"); + return -1; + } + if(avctx->cqp > -1) + h->qp = avctx->cqp; + else { + av_log(avctx, AV_LOG_ERROR, "fixed qp encoding only, use -cqp\n"); + return -1; + } + ff_cavs_init(avctx); + init_enc_vlc(intra_enc, ff_cavs_intra_dec, 7); + init_enc_vlc(inter_enc, ff_cavs_inter_dec, 7); + init_enc_vlc(chroma_enc, ff_cavs_chroma_dec, 5); + s->avctx = avctx; + s->avctx->get_buffer(s->avctx, (AVFrame *)&h->input_picture); + h->poc = 0; + return 0; +} + +AVCodec cavs_encoder = { + "cavs", + CODEC_TYPE_VIDEO, + CODEC_ID_CAVS, + sizeof(AVSContext), + cavs_encode_init, + cavs_encode_frame, + ff_cavs_end, +}; diff --git a/libavcodec/dsputil.h b/libavcodec/dsputil.h index 2d312e5..d5ede49 100644 --- a/libavcodec/dsputil.h +++ b/libavcodec/dsputil.h @@ -297,6 +297,9 @@ typedef struct DSPContext { void (*cavs_filter_cv)(uint8_t *pix, int stride, int alpha, int beta, int tc, int bs1, int bs2); void (*cavs_filter_ch)(uint8_t *pix, int stride, int alpha, int beta, int tc, int bs1, int bs2); void (*cavs_idct8_add)(uint8_t *dst, DCTELEM *block, int stride); + void (*cavs_sub_dct8)(uint8_t *src1, uint8_t *src2, DCTELEM *block, + int stride1, int stride2); + void (*cavs_quant)(DCTELEM *block, const uint16_t *norm,int mul, int bias); me_cmp_func pix_abs[2][4]; -- 1.7.1 --------------010605070306040906030502--
On Sun, Jan 23, 2011 at 04:24:06PM +0100, Vitor Sessak wrote:
Git-friendly patches attached so patchwork will catch it up.
--- /dev/null +++ b/libavcodec/cavsenc.c @@ -0,0 +1,687 @@ + +/** + * @file cavsenc.c
Drop the filename. This file could use some K&R loving. There's also inconsistent indentation that switches between 2 and 4 spaces. Diego
Diego Biurrun <diego at biurrun.de> writes:
On Sun, Jan 23, 2011 at 04:24:06PM +0100, Vitor Sessak wrote:
Git-friendly patches attached so patchwork will catch it up.
--- /dev/null +++ b/libavcodec/cavsenc.c @@ -0,0 +1,687 @@ + +/** + * @file cavsenc.c
Drop the filename.
This file could use some K&R loving. There's also inconsistent indentation that switches between 2 and 4 spaces.
I would consider this entire patch obsoleted by the xavs project, which we even support as external lib. -- M?ns Rullg?rd mans at mansr.com
participants (5)
-
diego@biurrun.de -
mans@mansr.com -
michaelni@gmx.at -
stefan.gehrer@gmx.de -
vitor1001@gmail.com