[Ffmpeg-devel] H.264 encoder
Panagiotis Issaris
takis.issaris
Thu Oct 5 18:11:19 CEST 2006
Hi,
On Wed, Oct 04, 2006 at 01:11:07PM +0200, Michael Niedermayer wrote:
> > > [...]
> > >
> > >
> > >> + for (i = 0 ; i < rbsplen ; i++)
> > >> + {
> > >> + if (i + 2 < rbsplen && (rbsp[i] == 0 && rbsp[i+1] == 0 && rbsp[i+2] < 4))
> > >> + {
> > >> + dest[destpos++] = rbsp[i++];
> > >> + dest[destpos++] = rbsp[i];
> > >> + dest[destpos++] = 0x03; // emulation prevention byte
> > >> + }
> > >> + else
> > >> + dest[destpos++] = rbsp[i];
> > >> + }
> > >>
> > >
> > > instead of a loop which checks every byte, you could check just every 2nd
> > > also see encode_nal() un h264.c maybe you can use some parts from that
Fixed by borrowing code from encode_nal(). So, now there's a first run over
the bytes looking for any occurrence of the to be escaped byte sequence. If
not there's a copy, if there is such an occurrence, the previous and slower
method is used.
I've attached an updated patch, with this issue fixed. The patch also removes
encode_nal() as it is not used anywhere else. Hope that's okay :)
I haven't changed the line length yet as I was not sure what to change it to
(see my next e-mail).
With friendly regards,
Takis
-------------- next part --------------
diff --git a/Changelog b/Changelog
index 1bcfe36..b9e1917 100644
--- a/Changelog
+++ b/Changelog
@@ -59,6 +59,7 @@ version <next>
- VP5 video decoder
- VP6 video decoder
- WavPack lossless audio decoder
+- Native H.264 encoder
version 0.4.9-pre1:
diff --git a/doc/ffmpeg-doc.texi b/doc/ffmpeg-doc.texi
index c41807d..76644eb 100644
--- a/doc/ffmpeg-doc.texi
+++ b/doc/ffmpeg-doc.texi
@@ -772,7 +772,7 @@ following image formats are supported:
@item WMV8 @tab X @tab X @tab not completely working
@item H.261 @tab X @tab X
@item H.263(+) @tab X @tab X @tab also known as RealVideo 1.0
- at item H.264 @tab @tab X
+ at item H.264 @tab X @tab X
@item RealVideo 1.0 @tab X @tab X
@item RealVideo 2.0 @tab X @tab X
@item MJPEG @tab X @tab X
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index fbf8e0b..74b90f9 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -87,6 +87,7 @@ OBJS-$(CONFIG_FRAPS_DECODER) +
OBJS-$(CONFIG_H261_DECODER) += h261.o
OBJS-$(CONFIG_H261_ENCODER) += h261.o
OBJS-$(CONFIG_H264_DECODER) += h264.o
+OBJS-$(CONFIG_H264_ENCODER) += h264enc.o h264cavlc.o h264dsp.o
OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o
OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o
OBJS-$(CONFIG_IDCIN_DECODER) += idcinvideo.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index fdd80fc..d575908 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -75,7 +75,7 @@ #ifdef CONFIG_MPEG1VIDEO_ENCODER
register_avcodec(&mpeg1video_encoder);
#endif //CONFIG_MPEG1VIDEO_ENCODER
#ifdef CONFIG_H264_ENCODER
-// register_avcodec(&h264_encoder);
+ register_avcodec(&h264_encoder);
#endif //CONFIG_H264_ENCODER
#ifdef CONFIG_MPEG2VIDEO_ENCODER
register_avcodec(&mpeg2video_encoder);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index ad7c776..db9e8a3 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -142,6 +142,7 @@ enum CodecID {
CODEC_ID_VP5,
CODEC_ID_VP6,
CODEC_ID_VP6F,
+ CODEC_ID_FFH264,
/* various pcm "codecs" */
CODEC_ID_PCM_S16LE= 0x10000,
diff --git a/libavcodec/dsputil.c b/libavcodec/dsputil.c
index ae5902f..1e3ce7f 100644
--- a/libavcodec/dsputil.c
+++ b/libavcodec/dsputil.c
@@ -2624,6 +2624,11 @@ void ff_put_vc1_mspel_mc00_c(uint8_t *ds
}
#endif /* CONFIG_VC1_DECODER||CONFIG_WMV3_DECODER */
+#if defined(CONFIG_H264_ENCODER)
+/* H264 specific */
+void ff_h264dsp_init(DSPContext* c, AVCodecContext *avctx);
+#endif /* CONFIG_H264_ENCODER */
+
static void wmv2_mspel8_v_lowpass(uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int w){
uint8_t *cm = cropTbl + MAX_NEG_CROP;
int i;
@@ -4081,6 +4086,9 @@ #endif
#if defined(CONFIG_VC1_DECODER) || defined(CONFIG_WMV3_DECODER)
ff_vc1dsp_init(c,avctx);
#endif
+#if defined(CONFIG_H264_ENCODER)
+ ff_h264dsp_init(c,avctx);
+#endif
c->put_mspel_pixels_tab[0]= put_mspel8_mc00_c;
c->put_mspel_pixels_tab[1]= put_mspel8_mc10_c;
diff --git a/libavcodec/dsputil.h b/libavcodec/dsputil.h
index 34d91ab..1038e5d 100644
--- a/libavcodec/dsputil.h
+++ b/libavcodec/dsputil.h
@@ -57,6 +57,13 @@ void ff_h264_idct8_dc_add_c(uint8_t *dst
void ff_h264_idct_dc_add_c(uint8_t *dst, DCTELEM *block, int stride);
void ff_h264_lowres_idct_add_c(uint8_t *dst, int stride, DCTELEM *block);
void ff_h264_lowres_idct_put_c(uint8_t *dst, int stride, DCTELEM *block);
+void ff_h264_dct_c(DCTELEM inblock[4][4], DCTELEM outblock[4][4]);
+void ff_h264_hadamard_mult4x4_c(DCTELEM Y[4][4]);
+void ff_h264_transform_dct_quant_c(int16_t block[4][4], int QP, int dontscaleDC);
+void ff_h264_hadamard_quant_4x4_c(DCTELEM Y[4][4], int QP);
+void ff_h264_hadamard_quant_2x2_c(int16_t Y[2][2], int QP);
+void ff_h264_hadamard_invquant_4x4_c(DCTELEM Y[4][4], int QP);
+void ff_h264_transform_inverse_quant_dct_add_c(int16_t block[4][4], int QP, int dontscaleDC, uint8_t *dst, int stride);
void ff_vector_fmul_add_add_c(float *dst, const float *src0, const float *src1,
const float *src2, int src3, int blocksize, int step);
@@ -376,10 +383,19 @@ #define FF_PARTTRANS_IDCT_PERM 5
#define BASIS_SHIFT 16
#define RECON_SHIFT 6
+ /* h264 functions */
void (*h264_idct_add)(uint8_t *dst, DCTELEM *block, int stride);
void (*h264_idct8_add)(uint8_t *dst, DCTELEM *block, int stride);
void (*h264_idct_dc_add)(uint8_t *dst, DCTELEM *block, int stride);
void (*h264_idct8_dc_add)(uint8_t *dst, DCTELEM *block, int stride);
+ void (*h264_dct)(DCTELEM inblock[4][4], DCTELEM outblock[4][4]);
+ void (*h264_idct_notranspose_add)(uint8_t *dst, DCTELEM *block, int stride);
+ void (*h264_hadamard_mult4x4)(DCTELEM Y[4][4]);
+ void (*h264_hadamard_quant_2x2)(int16_t Y[2][2], int QP);
+ void (*h264_hadamard_quant_4x4)(DCTELEM Y[4][4], int QP);
+ void (*h264_hadamard_invquant_4x4)(DCTELEM Y[4][4], int QP);
+ void (*h264_transform_dct_quant)(int16_t block[4][4], int QP, int dontscaleDC);
+ void (*h264_transform_inverse_quant_dct_add)(int16_t block[4][4], int QP, int dontscaleDC, uint8_t *dst, int stride);
/* snow wavelet */
void (*vertical_compose97i)(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2, DWTELEM *b3, DWTELEM *b4, DWTELEM *b5, int width);
diff --git a/libavcodec/h264.c b/libavcodec/h264.c
index 8602276..e0e3499 100644
--- a/libavcodec/h264.c
+++ b/libavcodec/h264.c
@@ -163,20 +163,6 @@ typedef struct H264Context{
MpegEncContext s;
int nal_ref_idc;
int nal_unit_type;
-#define NAL_SLICE 1
-#define NAL_DPA 2
-#define NAL_DPB 3
-#define NAL_DPC 4
-#define NAL_IDR_SLICE 5
-#define NAL_SEI 6
-#define NAL_SPS 7
-#define NAL_PPS 8
-#define NAL_AUD 9
-#define NAL_END_SEQUENCE 10
-#define NAL_END_STREAM 11
-#define NAL_FILLER_DATA 12
-#define NAL_SPS_EXT 13
-#define NAL_AUXILIARY_SLICE 19
uint8_t *rbsp_buffer;
unsigned int rbsp_buffer_size;
@@ -420,13 +406,22 @@ #else
#endif
}
+const uint8_t rem6[52]={
+0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3,
+};
+
+const uint8_t div6[52]={
+0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
+};
+
+
/**
* fill a rectangle.
* @param h height of the rectangle, should be a constant
* @param w width of the rectangle, should be a constant
* @param size the size of val (1 or 4), should be a constant
*/
-static always_inline void fill_rectangle(void *vp, int w, int h, int stride, uint32_t val, int size){
+always_inline void fill_rectangle(void *vp, int w, int h, int stride, uint32_t val, int size){
uint8_t *p= (uint8_t*)vp;
assert(size==1 || size==4);
assert(w<=4);
@@ -1806,70 +1801,7 @@ #endif
return dst;
}
-#if 0
-/**
- * @param src the data which should be escaped
- * @param dst the target buffer, dst+1 == src is allowed as a special case
- * @param length the length of the src data
- * @param dst_length the length of the dst array
- * @returns length of escaped data in bytes or -1 if an error occured
- */
-static int encode_nal(H264Context *h, uint8_t *dst, uint8_t *src, int length, int dst_length){
- int i, escape_count, si, di;
- uint8_t *temp;
-
- assert(length>=0);
- assert(dst_length>0);
-
- dst[0]= (h->nal_ref_idc<<5) + h->nal_unit_type;
-
- if(length==0) return 1;
-
- escape_count= 0;
- for(i=0; i<length; i+=2){
- if(src[i]) continue;
- if(i>0 && src[i-1]==0)
- i--;
- if(i+2<length && src[i+1]==0 && src[i+2]<=3){
- escape_count++;
- i+=2;
- }
- }
-
- if(escape_count==0){
- if(dst+1 != src)
- memcpy(dst+1, src, length);
- return length + 1;
- }
-
- if(length + escape_count + 1> dst_length)
- return -1;
-
- //this should be damn rare (hopefully)
-
- h->rbsp_buffer= av_fast_realloc(h->rbsp_buffer, &h->rbsp_buffer_size, length + escape_count);
- temp= h->rbsp_buffer;
-//printf("encoding esc\n");
-
- si= 0;
- di= 0;
- while(si < length){
- if(si+2<length && src[si]==0 && src[si+1]==0 && src[si+2]<=3){
- temp[di++]= 0; si++;
- temp[di++]= 0; si++;
- temp[di++]= 3;
- temp[di++]= src[si++];
- }
- else
- temp[di++]= src[si++];
- }
- memcpy(dst+1, temp, length+escape_count);
-
- assert(di == length+escape_count);
-
- return di + 1;
-}
-
+#if 1
/**
* write 1,10,100,1000,... for alignment, yes its exactly inverse to mpeg4
*/
@@ -2033,42 +1965,6 @@ static inline int get_chroma_qp(int chro
return chroma_qp[clip(qscale + chroma_qp_index_offset, 0, 51)];
}
-
-#if 0
-static void h264_diff_dct_c(DCTELEM *block, uint8_t *src1, uint8_t *src2, int stride){
- int i;
- //FIXME try int temp instead of block
-
- for(i=0; i<4; i++){
- const int d0= src1[0 + i*stride] - src2[0 + i*stride];
- const int d1= src1[1 + i*stride] - src2[1 + i*stride];
- const int d2= src1[2 + i*stride] - src2[2 + i*stride];
- const int d3= src1[3 + i*stride] - src2[3 + i*stride];
- const int z0= d0 + d3;
- const int z3= d0 - d3;
- const int z1= d1 + d2;
- const int z2= d1 - d2;
-
- block[0 + 4*i]= z0 + z1;
- block[1 + 4*i]= 2*z3 + z2;
- block[2 + 4*i]= z0 - z1;
- block[3 + 4*i]= z3 - 2*z2;
- }
-
- for(i=0; i<4; i++){
- const int z0= block[0*4 + i] + block[3*4 + i];
- const int z3= block[0*4 + i] - block[3*4 + i];
- const int z1= block[1*4 + i] + block[2*4 + i];
- const int z2= block[1*4 + i] - block[2*4 + i];
-
- block[0*4 + i]= z0 + z1;
- block[1*4 + i]= 2*z3 + z2;
- block[2*4 + i]= z0 - z1;
- block[3*4 + i]= z3 - 2*z2;
- }
-}
-#endif
-
//FIXME need to check that this doesnt overflow signed 32 bit for low qp, i am not sure, it's very close
//FIXME check that gcc inlines this (and optimizes intra & seperate_dc stuff away)
static inline int quantize_c(DCTELEM *block, uint8_t *scantable, int qscale, int intra, int seperate_dc){
@@ -2355,7 +2251,7 @@ static void pred4x4_horizontal_down_c(ui
src[1+3*stride]=(l1 + 2*l2 + l3 + 2)>>2;
}
-static void pred16x16_vertical_c(uint8_t *src, int stride){
+void pred16x16_vertical_c(uint8_t *src, int stride){
int i;
const uint32_t a= ((uint32_t*)(src-stride))[0];
const uint32_t b= ((uint32_t*)(src-stride))[1];
@@ -2370,7 +2266,7 @@ static void pred16x16_vertical_c(uint8_t
}
}
-static void pred16x16_horizontal_c(uint8_t *src, int stride){
+void pred16x16_horizontal_c(uint8_t *src, int stride){
int i;
for(i=0; i<16; i++){
@@ -2381,7 +2277,7 @@ static void pred16x16_horizontal_c(uint8
}
}
-static void pred16x16_dc_c(uint8_t *src, int stride){
+void pred16x16_dc_c(uint8_t *src, int stride){
int i, dc=0;
for(i=0;i<16; i++){
@@ -2435,7 +2331,7 @@ static void pred16x16_top_dc_c(uint8_t *
}
}
-static void pred16x16_128_dc_c(uint8_t *src, int stride){
+void pred16x16_128_dc_c(uint8_t *src, int stride){
int i;
for(i=0; i<16; i++){
@@ -2486,11 +2382,11 @@ static inline void pred16x16_plane_compa
}
}
-static void pred16x16_plane_c(uint8_t *src, int stride){
+void pred16x16_plane_c(uint8_t *src, int stride){
pred16x16_plane_compat_c(src, stride, 0);
}
-static void pred8x8_vertical_c(uint8_t *src, int stride){
+void pred8x8_vertical_c(uint8_t *src, int stride){
int i;
const uint32_t a= ((uint32_t*)(src-stride))[0];
const uint32_t b= ((uint32_t*)(src-stride))[1];
@@ -2501,7 +2397,7 @@ static void pred8x8_vertical_c(uint8_t *
}
}
-static void pred8x8_horizontal_c(uint8_t *src, int stride){
+void pred8x8_horizontal_c(uint8_t *src, int stride){
int i;
for(i=0; i<8; i++){
@@ -2510,7 +2406,7 @@ static void pred8x8_horizontal_c(uint8_t
}
}
-static void pred8x8_128_dc_c(uint8_t *src, int stride){
+void pred8x8_128_dc_c(uint8_t *src, int stride){
int i;
for(i=0; i<8; i++){
@@ -2564,7 +2460,7 @@ static void pred8x8_top_dc_c(uint8_t *sr
}
-static void pred8x8_dc_c(uint8_t *src, int stride){
+void pred8x8_dc_c(uint8_t *src, int stride){
int i;
int dc0, dc1, dc2, dc3;
@@ -2589,7 +2485,7 @@ static void pred8x8_dc_c(uint8_t *src, i
}
}
-static void pred8x8_plane_c(uint8_t *src, int stride){
+void pred8x8_plane_c(uint8_t *src, int stride){
int j, k;
int a;
uint8_t *cm = cropTbl + MAX_NEG_CROP;
diff --git a/libavcodec/h264cavlc.c b/libavcodec/h264cavlc.c
new file mode 100644
index 0000000..61d9637
--- /dev/null
+++ b/libavcodec/h264cavlc.c
@@ -0,0 +1,311 @@
+/*
+ * H.264 encoder
+ * Copyright (c) 2006 Expertisecentrum Digitale Media, UHasselt
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "common.h"
+#include "dsputil.h"
+#include "avcodec.h"
+#include "bitstream.h"
+#include "mpegvideo.h"
+#include "h264data.h"
+#include "h264encdata.h"
+
+//#define DEBUG_H264CAVLC
+
+static int length_table[7][4095];
+static int code_table[7][4095];
+
+void h264cavlc_generate_tables()
+{
+ int vlcnum, level;
+ for (vlcnum=0; vlcnum<7; vlcnum++)
+ {
+ for(level=-2047; level<2048; level++)
+ {
+ int sign = level < 0;
+ int levabs = ABS(level);
+ int len, inf;
+
+ if (vlcnum == 0)
+ {
+
+ if (levabs < 8)
+ {
+ len = levabs * 2 + sign - 1;
+ inf = 1;
+ }
+ else if (levabs < 8+8)
+ {
+ len = 14 + 1 + 4;
+ inf = (1 << 4) | ((levabs - 8) << 1) | sign;
+ }
+ else
+ {
+ len = 14 + 2 + 12;
+ inf = (0x1 << 12) | ((levabs - 16)<< 1) | sign;
+ }
+ length_table[vlcnum][level+2047] = len;
+ code_table[vlcnum][level+2047] = inf;
+ }
+ else
+ {
+ int iCodeword;
+ int iLength;
+ int shift = vlcnum-1;
+ int escape = (15<<shift)+1;
+ int numPrefix;
+ int sufmask = ~((0xffffffff)<<shift);
+ int suffix;
+
+ numPrefix = (levabs-1)>>shift;
+ suffix = (levabs-1)&sufmask;
+
+#ifdef DEBUG_H264CAVLC
+ printf("numPrefix %d | suffix %d | levabs %d | escape %d | sufmask %d | vlcnum %d | level %d | sign %d\n",
+ numPrefix,suffix,levabs,escape,sufmask,vlcnum,level,sign);
+#endif // DEBUG_H264CAVLC
+ if (levabs < escape)
+ {
+ iLength = numPrefix + vlcnum + 1;
+ iCodeword = (1<<(shift+1))|(suffix<<1)|sign;
+ }
+ else
+ {
+ iLength = 28;
+ iCodeword = (1<<12)|((levabs-escape)<<1)|sign;
+ }
+ len = iLength;
+ inf = iCodeword;
+
+#ifdef DEBUG_H264CAVLC
+ printf("len %d | code %d\n",len,inf);
+#endif // DEBUG_H264CAVLC
+
+ length_table[vlcnum][level+2047] = len;
+ code_table[vlcnum][level+2047] = inf;
+ }
+ }
+ }
+}
+
+static inline void h264cavlc_encode_vlc_level(PutBitContext *b, int vlcnum, int16_t level)
+{
+ int16_t index;
+ index = level+2047;
+ put_bits(b,length_table[vlcnum][index],code_table[vlcnum][index]);
+#ifdef DEBUG_H264CAVLC
+// av_log(NULL, AV_LOG_DEBUG, "Encoded level with number %d\n",code_table[vlcnum][index]);
+#endif
+}
+
+static inline void h264cavlc_encode_vlc_totalzeros(PutBitContext *b, int vlcnum, int total_zeros)
+{
+ put_bits(b,total_zeros_len[vlcnum][total_zeros],total_zeros_bits[vlcnum][total_zeros]);
+}
+
+static inline void h264cavlc_encode_vlc_run(PutBitContext *b, int vlcnum, int runbefore)
+{
+ put_bits(b,run_len[vlcnum][runbefore],run_bits[vlcnum][runbefore]);
+}
+
+static inline void h264cavlc_encode_vlc_coefftoken(PutBitContext *b, int lookup_table, int total_coeffs, int trailing_ones)
+{
+ put_bits(b,coeff_token_len[lookup_table][trailing_ones+total_coeffs*4],coeff_token_bits[lookup_table][trailing_ones+total_coeffs*4]);
+}
+
+static inline void h264cavlc_encode_vlc_coefftoken_chromadc(PutBitContext *b, int total_coeffs, int trailing_ones)
+{
+ put_bits(b,chroma_dc_coeff_token_len[trailing_ones + total_coeffs * 4],chroma_dc_coeff_token_bits[trailing_ones + total_coeffs * 4]);
+}
+
+static inline void h264cavlc_encode_vlc_totalzeros_chromadc(PutBitContext *b, int vlcnum, int value)
+{
+ if(vlcnum + value == 3) put_bits(b, value , 0);
+ else put_bits(b, value+1, 1);
+}
+
+static inline int h264cavlc_get_lookup_table(int na, int nb)
+{
+ int nc = 0;
+ int8_t lookup_table[8] = {0, 0, 1, 1, 2, 2, 2, 2};
+
+ if (na >= 0 && nb >= 0)
+ {
+ nc = na+nb+1;
+ nc >>= 1;
+ }
+ else
+ {
+ if (na >= 0) // nB < 0
+ nc = na;
+ else if (nb >= 0) // nA < 0
+ nc = nb;
+ }
+
+ return (nc < 8) ? lookup_table[nc] : 3;
+}
+
+int h264cavlc_encode(PutBitContext *b, int16_t *coefficients, int len, int na, int nb, int is_chroma_dc)
+{
+ static const int8_t increment_vlcnum[6] = { 0, 3, 6, 12, 24, 48 };
+
+ int i, t;
+ int total_coeffs;
+ int trailing_ones;
+ int total_zeros;
+ int numlevels;
+ int16_t levels[256];
+ int16_t zeros[256];
+
+#ifdef DEBUG_H264CAVLC
+ for (i = 0 ; i < len ; i++)
+ av_log(NULL, AV_LOG_DEBUG, "%6d",coefficients[i]);
+ av_log(NULL, AV_LOG_DEBUG, "\n");
+#endif
+
+ // Count traling ones, total non-zero coefficients and the number of non-trailing zeros
+
+ total_coeffs = 0;
+ trailing_ones = 0;
+ total_zeros = 0; // For now, we'll count the number of zeros at the end
+ for (i = 0 ; i < len ; i++)
+ {
+ int16_t val = coefficients[i];
+ if (val != 0)
+ {
+ levels[total_coeffs] = val;
+ zeros[total_coeffs] = total_zeros;
+ if (val == -1 || val == +1)
+ trailing_ones++;
+ else
+ trailing_ones = 0;
+ total_coeffs++;
+ total_zeros = 0;
+ }
+ else
+ total_zeros++;
+ }
+ if (trailing_ones > 3)
+ trailing_ones = 3;
+
+ total_zeros = len - total_zeros - total_coeffs; // The actual value of zeros (except the zeros at the end)
+ numlevels = total_coeffs - trailing_ones;
+
+ // Encode coeff_token. This is different for Chroma DC values
+
+ if (!is_chroma_dc)
+ {
+ int lookupTable = h264cavlc_get_lookup_table(na,nb);
+#ifdef DEBUG_H264CAVLC
+// av_log(NULL, AV_LOG_DEBUG, "Luma: vlc=%d #c=%d #t1=%d\n", lookupTable, total_coeffs, trailing_ones);
+#endif
+ h264cavlc_encode_vlc_coefftoken(b,lookupTable,total_coeffs,trailing_ones);
+ }
+ else
+ {
+#ifdef DEBUG_H264CAVLC
+// av_log(NULL, AV_LOG_DEBUG, "Chroma: #c=%d #t1=%d\n", total_coeffs, trailing_ones);
+#endif
+ h264cavlc_encode_vlc_coefftoken_chromadc(b,total_coeffs,trailing_ones);
+ }
+ if (total_coeffs == 0) // Only zeros here, nothing left to do
+ return 0;
+
+ // Encode the trailing one sign bits
+
+ for (i = total_coeffs-1, t = trailing_ones ; t > 0 ; i--, t--)
+ {
+ put_bits(b,1, levels[i] <= 0);
+ }
+
+ // Encode levels of the remaining nonzero coefficients
+
+ if (numlevels > 0)
+ {
+ int level_two_or_higher = 1;
+ int firstlevel = 1;
+ int vlcnum;
+
+ if (total_coeffs > 3 && trailing_ones == 3)
+ level_two_or_higher = 0;
+
+ vlcnum = total_coeffs > 10 && trailing_ones < 3;
+
+ for (i = numlevels-1 ; i >= 0 ; i--)
+ {
+ int16_t val = levels[i];
+ int16_t level = ABS(val);
+
+ if (level_two_or_higher)
+ {
+ val -= (val>>15)|1;
+ level_two_or_higher = 0;
+ }
+
+#ifdef DEBUG_H264CAVLC
+// av_log(NULL, AV_LOG_DEBUG, "Encoding level %d with vlc %d\n",val,vlcnum);
+#endif
+ h264cavlc_encode_vlc_level(b,vlcnum,val);
+
+ // update VLC table
+ if (vlcnum < 6 && level > increment_vlcnum[vlcnum])
+ vlcnum++;
+
+ if (firstlevel)
+ {
+ firstlevel = 0;
+ if (level > 3)
+ vlcnum = 2;
+ }
+ }
+ }
+
+ // If necessary, encode the amount of non-trailing zeros
+
+ if (total_coeffs < len)
+ {
+ int vlcnum = total_coeffs-1;
+
+#ifdef DEBUG_H264CAVLC
+// av_log(NULL, AV_LOG_DEBUG, "Encoding total_zeros %d with vlc %d\n",total_zeros,vlcnum);
+#endif
+
+ if (!is_chroma_dc)
+ h264cavlc_encode_vlc_totalzeros(b,vlcnum,total_zeros);
+ else
+ h264cavlc_encode_vlc_totalzeros_chromadc(b,vlcnum,total_zeros);
+ }
+
+ // If necessary, encode the run_before values
+
+ for (i = total_coeffs-1 ; i > 0 && total_zeros > 0 ; i--)
+ {
+ int runbefore = zeros[i];
+ int vlcnum = FFMIN(total_zeros-1, 6);
+
+#ifdef DEBUG_H264CAVLC
+// av_log(NULL, AV_LOG_DEBUG, "Encoding run %d with vlc %d\n",runbefore,vlcnum);
+#endif
+
+ h264cavlc_encode_vlc_run(b,vlcnum,runbefore);
+ total_zeros -= runbefore;
+ }
+
+ return total_coeffs;
+}
+
diff --git a/libavcodec/h264data.h b/libavcodec/h264data.h
index 1dd9daf..6ee2204 100644
--- a/libavcodec/h264data.h
+++ b/libavcodec/h264data.h
@@ -51,6 +51,24 @@ #define DC_128_PRED8x8 6
#define EXTENDED_SAR 255
+/* NAL unit types */
+enum {
+NAL_SLICE=1,
+NAL_DPA,
+NAL_DPB,
+NAL_DPC,
+NAL_IDR_SLICE,
+NAL_SEI,
+NAL_SPS,
+NAL_PPS,
+NAL_AUD,
+NAL_END_SEQUENCE,
+NAL_END_STREAM,
+NAL_FILLER_DATA,
+NAL_SPS_EXT,
+NAL_AUXILIARY_SLICE=19
+};
+
static const AVRational pixel_aspect[14]={
{0, 1},
{1, 1},
@@ -486,15 +504,6 @@ static const PMbInfo b_sub_mb_type_info[
{MB_TYPE_8x8 |MB_TYPE_P0L0|MB_TYPE_P0L1|MB_TYPE_P1L0|MB_TYPE_P1L1, 4, },
};
-
-static const uint8_t rem6[52]={
-0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3,
-};
-
-static const uint8_t div6[52]={
-0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
-};
-
static const uint8_t default_scaling4[2][16]={
{ 6,13,20,28,
13,20,28,32,
diff --git a/libavcodec/h264dsp.c b/libavcodec/h264dsp.c
new file mode 100644
index 0000000..ba2292f
--- /dev/null
+++ b/libavcodec/h264dsp.c
@@ -0,0 +1,260 @@
+/*
+ * H.264/MPEG-4 Part 10 (Base profile) encoder.
+ *
+ * DSP functions
+ *
+ * Copyright (c) 2006 Expertisecentrum Digitale Media, UHasselt
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file h264dsp.c
+ * H.264 encoder related DSP utils
+ *
+ */
+
+
+#include <stdio.h>
+#include "dsputil.h"
+
+extern const int16_t ff_h264_MF00[6];
+extern const int16_t ff_h264_V00[6];
+extern const uint8_t div6[52];
+extern const uint8_t rem6[52];
+
+#define COPY_SIGN(A, B) ((A ^ (B>>31)) - (B>>31))
+
+#define FF_H264_TRANSFORM_DCT_QUANT_C_ELEMENT(X, Y) \
+ block[X][Y] = COPY_SIGN(((ABS((int32_t)outblock[X][Y])*MF[mod][X][Y]+f) >> qbits), outblock[X][Y])
+
+#define FF_H264_TRANSFORM_DCT_QUANT_C_LINE(X) \
+ FF_H264_TRANSFORM_DCT_QUANT_C_ELEMENT(X,0); \
+ FF_H264_TRANSFORM_DCT_QUANT_C_ELEMENT(X,1); \
+ FF_H264_TRANSFORM_DCT_QUANT_C_ELEMENT(X,2); \
+ FF_H264_TRANSFORM_DCT_QUANT_C_ELEMENT(X,3);
+
+// we'll always work with transposed input blocks, to avoid having to make a distinction between
+// C and mmx implementations
+void ff_h264_transform_dct_quant_c(int16_t block[4][4], int QP, int dontscaleDC) // y,x indexing
+{
+ static const int16_t MF[6][4][4] =
+ {
+ { { 13107, 8066, 13107, 8066}, { 8066, 5243, 8066, 5243}, { 13107, 8066, 13107, 8066}, { 8066, 5243, 8066, 5243} },
+ { { 11916, 7490, 11916, 7490}, { 7490, 4660, 7490, 4660}, { 11916, 7490, 11916, 7490}, { 7490, 4660, 7490, 4660} },
+ { { 10082, 6554, 10082, 6554}, { 6554, 4194, 6554, 4194}, { 10082, 6554, 10082, 6554}, { 6554, 4194, 6554, 4194} },
+ { { 9362, 5825, 9362, 5825}, { 5825, 3647, 5825, 3647}, { 9362, 5825, 9362, 5825}, { 5825, 3647, 5825, 3647} },
+ { { 8192, 5243, 8192, 5243}, { 5243, 3355, 5243, 3355}, { 8192, 5243, 8192, 5243}, { 5243, 3355, 5243, 3355} },
+ { { 7282, 4559, 7282, 4559}, { 4559, 2893, 4559, 2893}, { 7282, 4559, 7282, 4559}, { 4559, 2893, 4559, 2893} }
+ };
+ int32_t qbits = 15 + div6[QP];
+ int32_t f = (1<<qbits)/3;
+ int mod = rem6[QP];
+ DCTELEM outblock[4][4];
+
+ ff_h264_dct_c(block, outblock);
+
+ if (dontscaleDC)
+ block[0][0] = outblock[0][0];
+ else
+ FF_H264_TRANSFORM_DCT_QUANT_C_ELEMENT(0,0);
+ FF_H264_TRANSFORM_DCT_QUANT_C_ELEMENT(0,1);
+ FF_H264_TRANSFORM_DCT_QUANT_C_ELEMENT(0,2);
+ FF_H264_TRANSFORM_DCT_QUANT_C_ELEMENT(0,3);
+
+ FF_H264_TRANSFORM_DCT_QUANT_C_LINE(1);
+ FF_H264_TRANSFORM_DCT_QUANT_C_LINE(2);
+ FF_H264_TRANSFORM_DCT_QUANT_C_LINE(3);
+}
+
+#define H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT(X, Y) \
+ elem[X][Y] = ((int32_t)block[X][Y]*V[mod][X][Y]) << shift;
+
+#define H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_LINE(X) \
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT(X, 0) \
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT(X, 1) \
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT(X, 2) \
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT(X, 3)
+
+#define H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT2(X, Y) \
+ elem[X][Y] = ((int32_t)block[X][Y]*V[mod][X][Y]+add) >> shift;
+
+#define H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_LINE2(X) \
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT2(X, 0) \
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT2(X, 1) \
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT2(X, 2) \
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT2(X, 3)
+
+void ff_h264_transform_inverse_quant_dct_add_c(int16_t block[4][4], int QP, int dontscaleDC, uint8_t *dst, int stride) // y,x indexing
+{
+ static const int16_t V[6][4][4] =
+ {
+ { { 10*16, 13*16, 10*16, 13*16}, { 13*16, 16*16, 13*16, 16*16}, { 10*16, 13*16, 10*16, 13*16}, { 13*16, 16*16, 13*16, 16*16} },
+ { { 11*16, 14*16, 11*16, 14*16}, { 14*16, 18*16, 14*16, 18*16}, { 11*16, 14*16, 11*16, 14*16}, { 14*16, 18*16, 14*16, 18*16} },
+ { { 13*16, 16*16, 13*16, 16*16}, { 16*16, 20*16, 16*16, 20*16}, { 13*16, 16*16, 13*16, 16*16}, { 16*16, 20*16, 16*16, 20*16} },
+ { { 14*16, 18*16, 14*16, 18*16}, { 18*16, 23*16, 18*16, 23*16}, { 14*16, 18*16, 14*16, 18*16}, { 18*16, 23*16, 18*16, 23*16} },
+ { { 16*16, 20*16, 16*16, 20*16}, { 20*16, 25*16, 20*16, 25*16}, { 16*16, 20*16, 16*16, 20*16}, { 20*16, 25*16, 20*16, 25*16} },
+ { { 18*16, 23*16, 18*16, 23*16}, { 23*16, 29*16, 23*16, 29*16}, { 18*16, 23*16, 18*16, 23*16}, { 23*16, 29*16, 23*16, 29*16} }
+ };
+ DCTELEM elem[4][4];
+ int mod = rem6[QP];
+
+ if (QP >= 24)
+ {
+ int shift = div6[QP]-4;
+
+ if (dontscaleDC)
+ elem[0][0] = block[0][0];
+ else
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT(0, 0);
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT(0, 1);
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT(0, 2);
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT(0, 3);
+
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_LINE(1);
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_LINE(2);
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_LINE(3);
+ }
+ else
+ {
+ int add = (1<<(3-div6[QP]));
+ int shift = (4-div6[QP]);
+ if (dontscaleDC)
+ elem[0][0] = block[0][0];
+ else
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT2(0, 0);
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT2(0, 1);
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT2(0, 2);
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_ELEMENT2(0, 3);
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_LINE2(1);
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_LINE2(2);
+ H264_TRANSFORM_INVERSE_QUANT_DCT_ADD_C_LINE2(3);
+ if (dontscaleDC)
+ elem[0][0] = block[0][0];
+ }
+
+ ff_h264_idct_add_c(dst,&(elem[0][0]),stride);
+}
+
+#define FF_H264_HADAMARD_QUANT_4X4_C_ELEMENT(A, B) \
+ Y[A][B] = COPY_SIGN((((ABS(Y[A][B])>>1) * MF + f2) >> shift), Y[A][B]);
+
+#define FF_H264_HADAMARD_QUANT_4X4_C_LINE(X) \
+ FF_H264_HADAMARD_QUANT_4X4_C_ELEMENT(X, 0); \
+ FF_H264_HADAMARD_QUANT_4X4_C_ELEMENT(X, 1); \
+ FF_H264_HADAMARD_QUANT_4X4_C_ELEMENT(X, 2); \
+ FF_H264_HADAMARD_QUANT_4X4_C_ELEMENT(X, 3);
+
+/**
+ * |ZD(i,j)| = (|YD(i,j)| MF(0,0) + 2 f) >> (qbits + 1)
+ *
+ */
+void ff_h264_hadamard_quant_4x4_c(DCTELEM Y[4][4], int QP)
+{
+ int qbits = 15 + div6[QP];
+ int f2 = (1 << qbits) * (2/3);
+ int shift = (qbits + 1);
+ int mod = rem6[QP];
+
+ int32_t MF = ff_h264_MF00[mod];
+
+ FF_H264_HADAMARD_QUANT_4X4_C_LINE(0);
+ FF_H264_HADAMARD_QUANT_4X4_C_LINE(1);
+ FF_H264_HADAMARD_QUANT_4X4_C_LINE(2);
+ FF_H264_HADAMARD_QUANT_4X4_C_LINE(3);
+}
+
+#define H264_HADAMARD_INVQUANT_4X4_C_LOWQP_ELEMENT(A, B) \
+ Y[A][B] = (Y[A][B]*V + f) >> shift;
+
+#define H264_HADAMARD_INVQUANT_4X4_C_LOWQP_LINE(A) \
+ H264_HADAMARD_INVQUANT_4X4_C_LOWQP_ELEMENT(A, 0) \
+ H264_HADAMARD_INVQUANT_4X4_C_LOWQP_ELEMENT(A, 1) \
+ H264_HADAMARD_INVQUANT_4X4_C_LOWQP_ELEMENT(A, 2) \
+ H264_HADAMARD_INVQUANT_4X4_C_LOWQP_ELEMENT(A, 3)
+
+#define H264_HADAMARD_INVQUANT_4X4_C_HIGHQP_ELEMENT(A,B) \
+ Y[A][B] = (Y[A][B]*V) << shift ;
+
+#define H264_HADAMARD_INVQUANT_4X4_C_HIGHQP_LINE(A) \
+ H264_HADAMARD_INVQUANT_4X4_C_HIGHQP_ELEMENT(A, 0) \
+ H264_HADAMARD_INVQUANT_4X4_C_HIGHQP_ELEMENT(A, 1) \
+ H264_HADAMARD_INVQUANT_4X4_C_HIGHQP_ELEMENT(A, 2) \
+ H264_HADAMARD_INVQUANT_4X4_C_HIGHQP_ELEMENT(A, 3)
+
+/*
+ * Only if qpprime_y_zero_transform_bypass_flag == 0
+ */
+void ff_h264_hadamard_invquant_4x4_c(DCTELEM Y[4][4], int QP)
+{
+ int mod = rem6[QP];
+
+ if (QP < 36)
+ {
+ int qbits = div6[QP];
+ int shift = 6-qbits;
+ int f = (1 << (5-qbits));
+
+ int32_t V = ff_h264_V00[mod];
+
+ H264_HADAMARD_INVQUANT_4X4_C_LOWQP_LINE(0);
+ H264_HADAMARD_INVQUANT_4X4_C_LOWQP_LINE(1);
+ H264_HADAMARD_INVQUANT_4X4_C_LOWQP_LINE(2);
+ H264_HADAMARD_INVQUANT_4X4_C_LOWQP_LINE(3);
+ }
+ else
+ {
+ int shift = div6[QP] - 6;
+ int32_t V = ff_h264_V00[mod];
+
+ H264_HADAMARD_INVQUANT_4X4_C_HIGHQP_LINE(0);
+ H264_HADAMARD_INVQUANT_4X4_C_HIGHQP_LINE(1);
+ H264_HADAMARD_INVQUANT_4X4_C_HIGHQP_LINE(2);
+ H264_HADAMARD_INVQUANT_4X4_C_HIGHQP_LINE(3);
+ }
+}
+
+#define FF_H264_HADAMARD_QUANT_2X2_C_ELEMENT(A, B) \
+ Y[A][B] = COPY_SIGN(((ABS(Y[A][B])*MF + f2) >> shift),Y[A][B])
+
+/**
+ * |ZD(i,j)| = (|YD(i,j)| MF(0,0) + 2 f) >> (qbits + 1)
+ *
+ */
+void ff_h264_hadamard_quant_2x2_c(int16_t Y[2][2], int QP)
+{
+ int qbits = 15 + div6[QP];
+ int f2 = ((1 << qbits) / 3)*2;
+ int shift = qbits+1;
+ int32_t MF = ff_h264_MF00[rem6[QP]];
+
+ FF_H264_HADAMARD_QUANT_2X2_C_ELEMENT(0, 0);
+ FF_H264_HADAMARD_QUANT_2X2_C_ELEMENT(0, 1);
+ FF_H264_HADAMARD_QUANT_2X2_C_ELEMENT(1, 0);
+ FF_H264_HADAMARD_QUANT_2X2_C_ELEMENT(1, 1);
+}
+
+void ff_h264dsp_init(DSPContext* c, AVCodecContext *avctx)
+{
+ c->h264_dct = ff_h264_dct_c;
+ c->h264_idct_notranspose_add = ff_h264_idct_add_c;
+ c->h264_hadamard_mult4x4 = ff_h264_hadamard_mult4x4_c;
+ c->h264_hadamard_quant_2x2 = ff_h264_hadamard_quant_2x2_c;
+ c->h264_hadamard_quant_4x4 = ff_h264_hadamard_quant_4x4_c;
+ c->h264_hadamard_invquant_4x4 = ff_h264_hadamard_invquant_4x4_c;
+ c->h264_transform_dct_quant = ff_h264_transform_dct_quant_c;
+ c->h264_transform_inverse_quant_dct_add = ff_h264_transform_inverse_quant_dct_add_c;
+}
+
diff --git a/libavcodec/h264enc.c b/libavcodec/h264enc.c
new file mode 100644
index 0000000..91b7eaa
--- /dev/null
+++ b/libavcodec/h264enc.c
@@ -0,0 +1,2501 @@
+/*
+ * H.264 encoder
+ * Copyright (c) 2006 Expertisecentrum Digitale Media, UHasselt
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "common.h"
+#include "avcodec.h"
+#include "bitstream.h"
+#include "golomb.h"
+#include "mpegvideo.h"
+#include "h264data.h"
+#include "dsputil.h"
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "h264enc.h"
+
+
+#define DEFAULT_QP 30
+#define NUMBER_OF_FRAMES 2
+#define RATECONTROLINTERVAL 0.5
+#define CHROMA_QP_INDEX_OFFSET_MAX 12
+#define CHROMA_QP_INDEX_OFFSET_MIN -12
+
+#define H264_COPY_4X4BLOCK_TRANSPOSED_PART(A, xoffset, yoffset, dest, src1, src2) \
+ dest[0][A] = src1[yoffset+A][xoffset+0]-src2[yoffset+A][xoffset+0]; \
+ dest[1][A] = src1[yoffset+A][xoffset+1]-src2[yoffset+A][xoffset+1]; \
+ dest[2][A] = src1[yoffset+A][xoffset+2]-src2[yoffset+A][xoffset+2]; \
+ dest[3][A] = src1[yoffset+A][xoffset+3]-src2[yoffset+A][xoffset+3];
+
+#define H264_COPY_4X4BLOCK_TRANSPOSED(xoffset,yoffset,dest,src1,src2) \
+{ \
+ H264_COPY_4X4BLOCK_TRANSPOSED_PART(0, xoffset, yoffset, dest, src1, src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED_PART(1, xoffset, yoffset, dest, src1, src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED_PART(2, xoffset, yoffset, dest, src1, src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED_PART(3, xoffset, yoffset, dest, src1, src2); \
+}
+
+#define H264_COPY_16X16BLOCK(dest,src1,src2) \
+{ \
+ H264_COPY_4X4BLOCK_TRANSPOSED(0,0,dest[0][0],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(4,0,dest[0][1],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(8,0,dest[0][2],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(12,0,dest[0][3],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(0,4,dest[1][0],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(4,4,dest[1][1],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(8,4,dest[1][2],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(12,4,dest[1][3],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(0,8,dest[2][0],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(4,8,dest[2][1],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(8,8,dest[2][2],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(12,8,dest[2][3],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(0,12,dest[3][0],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(4,12,dest[3][1],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(8,12,dest[3][2],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(12,12,dest[3][3],src1,src2); \
+}
+
+#define H264_COPY_8X8BLOCK(dest,src1,src2) \
+{ \
+ H264_COPY_4X4BLOCK_TRANSPOSED(0,0,dest[0][0],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(4,0,dest[0][1],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(0,4,dest[1][0],src1,src2); \
+ H264_COPY_4X4BLOCK_TRANSPOSED(4,4,dest[1][1],src1,src2); \
+}
+
+int h264cavlc_encode(PutBitContext *b, int16_t *coefficients, int len, int nA, int nB, int isChromaDC);
+void h264cavlc_generate_tables();
+void ff_h264_idct_add_c(uint8_t *dst, DCTELEM *block, int stride);
+
+void pred16x16_vertical_c(uint8_t *src, int stride);
+void pred8x8_vertical_c(uint8_t *src, int stride);
+void pred16x16_horizontal_c(uint8_t *src, int stride);
+void pred8x8_horizontal_c(uint8_t *src, int stride);
+void pred16x16_plane_c(uint8_t *src, int stride);
+void pred8x8_plane_c(uint8_t *src, int stride);
+void pred16x16_128_dc_c(uint8_t *src, int stride);
+void pred8x8_128_dc_c(uint8_t *src, int stride);
+void fill_rectangle(void *vp, int w, int h, int stride, uint32_t val, int size);
+
+static int8_t mbtype_map[4][3][2];
+
+/**
+ * For a specific picture, this function sets the correct Y,U and V start addresses for each macroblock
+ */
+static void ff_h264_assign_macroblocks(AVPicture *p, MacroBlock **mb_map, int mb_width, int mb_height, int setneighbours)
+{
+ int y,x,i;
+ int Ylinesize = p->linesize[0];
+ int Ulinesize = p->linesize[1];
+ int Vlinesize = p->linesize[2];
+
+ if (!setneighbours)
+ {
+ for (y = 0 ; y < mb_height ; y++)
+ {
+ int y16 = y << 4;
+ int y8 = y << 3;
+
+ for (x = 0 ; x < mb_width ; x++)
+ {
+ int x16 = x << 4;
+ int x8 = x << 3;
+
+ for (i = 0 ; i < 8 ; i++)
+ {
+ int ypos = y8+i;
+ mb_map[y][x].U[i] = p->data[1]+(x8+ypos*Ulinesize);
+ mb_map[y][x].V[i] = p->data[2]+(x8+ypos*Vlinesize);
+ }
+ for (i = 0 ; i < 16 ; i++)
+ mb_map[y][x].Y[i] = p->data[0]+(x16+(y16+i)*Ylinesize);
+
+ mb_map[y][x].topblock = NULL;
+ mb_map[y][x].leftblock = NULL;
+ mb_map[y][x].rightblock = NULL;
+ mb_map[y][x].available = 0;
+ }
+ }
+ }
+ else
+ {
+ y = 0;
+ x = 0;
+ for (i = 0 ; i < 8 ; i++)
+ {
+ mb_map[y][x].U[i] = p->data[1]+((x<<3)+((y<<3)+i)*Ulinesize);
+ mb_map[y][x].V[i] = p->data[2]+((x<<3)+((y<<3)+i)*Vlinesize);
+ }
+ for (i = 0 ; i < 16 ; i++)
+ mb_map[y][x].Y[i] = p->data[0]+((x<<4)+((y<<4)+i)*Ylinesize);
+
+ mb_map[y][x].topblock = NULL;
+ mb_map[y][x].leftblock = NULL;
+
+ if (x < mb_width-1)
+ mb_map[y][x].rightblock = &(mb_map[y][x+1]);
+ else
+ mb_map[y][x].rightblock = NULL;
+ mb_map[y][x].available = 0;
+
+ y = 0;
+ for (x = 1 ; x < mb_width ; x++)
+ {
+ for (i = 0 ; i < 8 ; i++)
+ {
+ mb_map[y][x].U[i] = p->data[1]+((x<<3)+((y<<3)+i)*Ulinesize);
+ mb_map[y][x].V[i] = p->data[2]+((x<<3)+((y<<3)+i)*Vlinesize);
+ }
+ for (i = 0 ; i < 16 ; i++)
+ mb_map[y][x].Y[i] = p->data[0]+((x<<4)+((y<<4)+i)*Ylinesize);
+
+ mb_map[y][x].topblock = NULL;
+ mb_map[y][x].leftblock = &(mb_map[y][x-1]);
+ if (x < mb_width-1)
+ mb_map[y][x].rightblock = &(mb_map[y][x+1]);
+ else
+ mb_map[y][x].rightblock = NULL;
+ mb_map[y][x].available = 0;
+ }
+
+ x = 0;
+ for (y = 1 ; y < mb_height ; y++)
+ {
+ for (i = 0 ; i < 8 ; i++)
+ {
+ mb_map[y][x].U[i] = p->data[1]+((x<<3)+((y<<3)+i)*Ulinesize);
+ mb_map[y][x].V[i] = p->data[2]+((x<<3)+((y<<3)+i)*Vlinesize);
+ }
+ for (i = 0 ; i < 16 ; i++)
+ mb_map[y][x].Y[i] = p->data[0]+((x<<4)+((y<<4)+i)*Ylinesize);
+
+ mb_map[y][x].topblock = &(mb_map[y-1][x]);
+ mb_map[y][x].leftblock = NULL;
+ if (x < mb_width-1)
+ mb_map[y][x].rightblock = &(mb_map[y][x+1]);
+ else
+ mb_map[y][x].rightblock = NULL;
+ mb_map[y][x].available = 0;
+ }
+
+ for (y = 1 ; y < mb_height ; y++)
+ {
+ for (x = 1 ; x < mb_width ; x++)
+ {
+ for (i = 0 ; i < 8 ; i++)
+ {
+ mb_map[y][x].U[i] = p->data[1]+((x<<3)+((y<<3)+i)*Ulinesize);
+ mb_map[y][x].V[i] = p->data[2]+((x<<3)+((y<<3)+i)*Vlinesize);
+ }
+ for (i = 0 ; i < 16 ; i++)
+ mb_map[y][x].Y[i] = p->data[0]+((x<<4)+((y<<4)+i)*Ylinesize);
+
+ mb_map[y][x].topblock = &(mb_map[y-1][x]);
+ mb_map[y][x].leftblock = &(mb_map[y][x-1]);
+ if (x < mb_width-1)
+ mb_map[y][x].rightblock = &(mb_map[y][x+1]);
+ else
+ mb_map[y][x].rightblock = NULL;
+ mb_map[y][x].available = 0;
+ }
+ }
+ }
+}
+
+static void ff_h264_clear_nonzero_markers(MacroBlock **mb_map, int mb_width, int mb_height)
+{
+ int x,y;
+
+ for (y = 0 ; y < mb_height ; y++)
+ {
+ for (x = 0 ; x < mb_width ; x++)
+ {
+ // mark as not available
+
+ memset(&(mb_map[y][x].Y_nonzero[0][0]),0xff,sizeof(int)*16); // set to -1
+ memset(&(mb_map[y][x].U_nonzero[0][0]),0xff,sizeof(int)*4); // set to -1
+ memset(&(mb_map[y][x].V_nonzero[0][0]),0xff,sizeof(int)*4); // set to -1
+
+ mb_map[y][x].available = 0;
+ }
+ }
+}
+
+static void ff_h264_init_tables()
+{
+ int a, b, c;
+ for(a=0; a<4; a++)
+ for(b=0; b<3; b++)
+ for(c=0; c<2; c++)
+ mbtype_map[a][b][c] = 1 + a + 4*(b + 3*c);
+}
+
+static int ff_h264_encoder_init(AVCodecContext *avctx)
+{
+ H264Context *t = (H264Context *)avctx->priv_data;
+ uint8_t *buf;
+ int s, x, y, i, res;
+ int width, height;
+
+ switch(avctx->pix_fmt){
+ case PIX_FMT_YUV420P:
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "format not supported\n");
+ return -1;
+ }
+
+ t->frame_cropping_flag = 0;
+ t->frame_crop_left_offset = 0;
+ t->frame_crop_right_offset = 0;
+ t->frame_crop_top_offset = 0;
+ t->frame_crop_bottom_offset = 0;
+
+ width = avctx->width;
+ height = avctx->height;
+
+ t->mb_width = width/16;
+ t->mb_height = height/16;
+ t->frame_width = width;
+ t->frame_height = height;
+
+ /* If the width is not a multiple of 16, enabling cropping */
+ if (( width % 16) !=0 )
+ {
+ t->frame_cropping_flag = 1;
+ t->frame_crop_left_offset = 0;
+ t->frame_crop_right_offset = (width%16)/2;
+ t->mb_width++;
+ }
+
+ /* If the height is not a multiple of 16, enabling cropping */
+ if (( height % 16) !=0 )
+ {
+ t->frame_cropping_flag = 1;
+ t->frame_crop_top_offset = 0;
+ t->frame_crop_bottom_offset = (height%16)/2;
+ t->mb_height++;
+ }
+
+ /* Round the framesize upwards to a multiple of 16 */
+ width = t->mb_width * 16;
+ height = t->mb_height * 16;
+ t->refframe_width = width;
+ t->refframe_height = height;
+
+ s = avpicture_get_size(avctx->pix_fmt, width, height);
+ res = avpicture_alloc(&t->pi, avctx->pix_fmt, width, height);
+ if (res) {
+ av_log(avctx, AV_LOG_ERROR, "Problem allocating picture\n");
+ return -1;
+ }
+ res = avpicture_alloc(&t->po, avctx->pix_fmt, width, height);
+ if (res) {
+ av_log(avctx, AV_LOG_ERROR, "Problem allocating picture\n");
+ return -1;
+ }
+
+ t->pi_data0 = (uint8_t *)t->pi.data[0];
+ t->po_data0 = (uint8_t *)t->po.data[0];
+ t->bufsize = s*2;
+ t->frame_num = 0;
+
+ t->mb_map = (MacroBlock **)av_malloc(sizeof(MacroBlock*) * t->mb_height);
+ for (y = 0 ; y < t->mb_height ; y++)
+ {
+ t->mb_map[y] = (MacroBlock *)av_malloc(sizeof(MacroBlock) * t->mb_width);
+ for (x = 0 ; x < t->mb_width ; x++)
+ {
+ t->mb_map[y][x].Y_width = 16;
+ t->mb_map[y][x].Y_height = 16;
+ }
+ }
+
+ t->framebufsize = NUMBER_OF_FRAMES;
+ t->reconstructed_frames = (FrameInfo **)av_malloc(sizeof(FrameInfo *)*t->framebufsize);
+
+ for (i = 0 ; i < t->framebufsize ; i++)
+ {
+ t->reconstructed_frames[i] = (FrameInfo *)av_malloc(sizeof(FrameInfo));
+
+ buf = av_malloc(s);
+ avpicture_fill(&(t->reconstructed_frames[i]->reconstructed_picture), buf, PIX_FMT_YUV420P, width, height);
+
+ t->reconstructed_frames[i]->reconstructed_mb_map = (MacroBlock **)av_malloc(sizeof(MacroBlock*) * t->mb_height);
+ for (y = 0 ; y < t->mb_height ; y++)
+ {
+ t->reconstructed_frames[i]->reconstructed_mb_map[y] = (MacroBlock *)av_malloc(sizeof(MacroBlock) * t->mb_width);
+ for (x = 0 ; x < t->mb_width ; x++)
+ {
+ t->reconstructed_frames[i]->reconstructed_mb_map[y][x].Y_width = 16;
+ t->reconstructed_frames[i]->reconstructed_mb_map[y][x].Y_height = 16;
+ }
+ }
+ ff_h264_assign_macroblocks(&(t->reconstructed_frames[i]->reconstructed_picture),t->reconstructed_frames[i]->reconstructed_mb_map,t->mb_width,t->mb_height,1);
+ }
+
+ if (!avctx->global_quality)
+ {
+ t->QP = DEFAULT_QP;
+ t->use_fixed_qp = 0;
+ }
+ else
+ {
+ t->QP = avctx->global_quality / FF_QP2LAMBDA;
+ t->use_fixed_qp = 1;
+ }
+ t->PPS_QP = t->QP;
+
+ t->chroma_qp_index_offset = avctx->chromaoffset;
+ t->chroma_qp_index_offset = clip(t->chroma_qp_index_offset, CHROMA_QP_INDEX_OFFSET_MIN, CHROMA_QP_INDEX_OFFSET_MAX);
+ t->IDRcount = 64;
+ t->IDR_frame_num = 0;
+
+ // init dsp
+ dsputil_init(&(t->dspcontext),avctx);
+ t->Y_stride = t->reconstructed_frames[0]->reconstructed_picture.linesize[0];
+ t->U_stride = t->reconstructed_frames[0]->reconstructed_picture.linesize[1];
+ t->V_stride = t->reconstructed_frames[0]->reconstructed_picture.linesize[2];
+
+ // Create an AVPicture instance with the same dimensions as the reference pictures to hold a copy
+ // of the input frame
+ buf = (uint8_t *)av_malloc(s);
+ avpicture_fill(&(t->input_frame_copy), buf, PIX_FMT_YUV420P, width, height);
+ memset(buf,0,s);
+
+ // Assign the macroblock map to this copy of the input image
+ ff_h264_assign_macroblocks(&(t->input_frame_copy),t->mb_map,t->mb_width,t->mb_height,0);
+
+ // Blocksize history, we use a separate history for I and P frame
+ t->milliseconds_per_frame = (1000*avctx->time_base.num)/avctx->time_base.den;
+ t->blocksize_history_length = (RATECONTROLINTERVAL*avctx->time_base.den)/avctx->time_base.num;
+ t->blocksize_history = (int64_t *)av_malloc(sizeof(int64_t)*t->blocksize_history_length);
+ t->blocksize_history_pos = 0;
+ t->blocksize_history_num_filled = 0;
+ t->blocksize_history_total_milliseconds = 0;
+ t->blocksize_history_sum = 0;
+ for (i = 0 ; i < t->blocksize_history_length ; i++)
+ t->blocksize_history[i] = 0;
+
+ h264cavlc_generate_tables();
+ ff_h264_init_tables();
+ return 0;
+}
+
+/**
+ * @param b2 the data which should be escaped
+ * @param dest the target buffer, dst+1 == src is allowed as a special case
+ * @param length the length of the src data
+ * @param destsize the length of the dst array
+ * @returns pointer to current position in the output buffer or NULL if an error occured
+ */
+static uint8_t *ff_h264_write_nal_unit(int nal_ref_idc, int nal_unit_type, uint8_t *dest, int *destsize,
+ PutBitContext *b2)
+{
+ PutBitContext b;
+ int i, destpos, rbsplen, escape_count;
+ uint8_t *rbsp, temp;
+
+ // Align b2 on a byte boundary
+
+ align_put_bits(b2);
+ rbsplen = put_bits_count(b2)/8;
+ flush_put_bits(b2);
+ rbsp = b2->buf;
+
+ init_put_bits(&b,dest,*destsize);
+
+ put_bits(&b,16,0);
+ put_bits(&b,16,0x01);
+
+ put_bits(&b,1,0); // forbidden zero bit
+ put_bits(&b,2,nal_ref_idc); // nal_ref_idc
+ put_bits(&b,5,nal_unit_type); // nal_unit_type
+
+ flush_put_bits(&b);
+
+ destpos = 5;
+ escape_count= 0;
+ for(i=0; i<rbsplen; i+=2){
+ if(rbsp[i]) continue;
+ if(i>0 && rbsp[i-1]==0)
+ i--;
+ if(i+2<rbsplen && rbsp[i+1]==0 && rbsp[i+2]<=3){
+ escape_count++;
+ i+=2;
+ }
+ }
+
+ if(escape_count==0){
+ if(dest+destpos != rbsp) {
+ memcpy(dest+destpos, rbsp, rbsplen);
+ *destsize -= (rbsplen+destpos);
+ }
+ return dest+rbsplen+destpos;
+ }
+ if(rbsplen + escape_count + 1> *destsize)
+ {
+ av_log(NULL, AV_LOG_ERROR, "Destination buffer too small!\n");
+ return NULL;
+ }
+ //this should be damn rare (hopefully)
+ for (i = 0 ; i < rbsplen ; i++)
+ {
+ if (i + 2 < rbsplen && (rbsp[i] == 0 && rbsp[i+1] == 0 && rbsp[i+2] < 4))
+ {
+ dest[destpos++] = rbsp[i++];
+ dest[destpos++] = rbsp[i];
+ dest[destpos++] = 0x03; // emulation prevention byte
+ }
+ else
+ dest[destpos++] = rbsp[i];
+ }
+ *destsize -= destpos;
+ return dest+destpos;
+}
+
+static void ff_h264_encode_I_PCM(MacroBlock *mb, PutBitContext *b, MacroBlock *copy_mb)
+{
+ int w = mb->Y_width;
+ int h = mb->Y_height;
+ int x,y;
+
+ set_ue_golomb(b, 25); // mb_type = I_PCM
+ align_put_bits(b);
+
+ // Y
+
+ for (y = 0 ; y < h ; y++)
+ {
+ for (x = 0 ; x < w ; x++)
+ put_bits(b,8,mb->Y[y][x]);
+ for ( ; x < 16 ; x++)
+ put_bits(b,8,0);
+ }
+ for ( ; y < 16 ; y++)
+ {
+ for (x = 0 ; x < 16 ; x++)
+ put_bits(b,8,0);
+ }
+
+ // copy Y
+
+ for (y = 0 ; y < h ; y++)
+ for (x = 0 ; x < w ; x++)
+ copy_mb->Y[y][x] = mb->Y[y][x];
+
+ w >>= 1;
+ h >>= 1;
+
+ // U
+
+ for (y = 0 ; y < h ; y++)
+ {
+ for (x = 0 ; x < w ; x++)
+ put_bits(b,8,mb->U[y][x]);
+ for ( ; x < 8 ; x++)
+ put_bits(b,8,0);
+ }
+ for ( ; y < 8 ; y++)
+ {
+ for (x = 0 ; x < 8 ; x++)
+ put_bits(b,8,0);
+ }
+
+ // V
+
+ for (y = 0 ; y < h ; y++)
+ {
+ for (x = 0 ; x < w ; x++)
+ put_bits(b,8,mb->V[y][x]);
+ for ( ; x < 8 ; x++)
+ put_bits(b,8,0);
+ }
+ for ( ; y < 8 ; y++)
+ {
+ for (x = 0 ; x < 8 ; x++)
+ put_bits(b,8,0);
+ }
+
+ // copy U and V
+
+ for (y = 0 ; y < h ; y++)
+ {
+ for (x = 0 ; x < w ; x++)
+ {
+ copy_mb->U[y][x] = mb->U[y][x];
+ copy_mb->V[y][x] = mb->V[y][x];
+ }
+ }
+
+ // store the nonzero counts (set to 16 for I_PCM blocks)
+ fill_rectangle(copy_mb->Y_nonzero, 4, 4, 4, 16, sizeof(int));
+ fill_rectangle(copy_mb->U_nonzero, 2, 2, 2, 16, sizeof(int));
+ fill_rectangle(copy_mb->V_nonzero, 2, 2, 2, 16, sizeof(int));
+
+ copy_mb->available = 1;
+}
+
+// inblock is transposed, outblock isn't
+void ff_h264_dct_c(DCTELEM inblock[4][4],DCTELEM outblock[4][4])
+{
+ DCTELEM pieces[4][4];
+
+ pieces[0][0] = inblock[0][0]+inblock[1][0]+inblock[2][0]+inblock[3][0];
+ pieces[0][1] = inblock[0][1]+inblock[1][1]+inblock[2][1]+inblock[3][1];
+ pieces[0][2] = inblock[0][2]+inblock[1][2]+inblock[2][2]+inblock[3][2];
+ pieces[0][3] = inblock[0][3]+inblock[1][3]+inblock[2][3]+inblock[3][3];
+
+ pieces[1][0] = (inblock[0][0]<<1)+inblock[1][0]-inblock[2][0]-(inblock[3][0]<<1);
+ pieces[1][1] = (inblock[0][1]<<1)+inblock[1][1]-inblock[2][1]-(inblock[3][1]<<1);
+ pieces[1][2] = (inblock[0][2]<<1)+inblock[1][2]-inblock[2][2]-(inblock[3][2]<<1);
+ pieces[1][3] = (inblock[0][3]<<1)+inblock[1][3]-inblock[2][3]-(inblock[3][3]<<1);
+
+ pieces[2][0] = inblock[0][0]-inblock[1][0]-inblock[2][0]+inblock[3][0];
+ pieces[2][1] = inblock[0][1]-inblock[1][1]-inblock[2][1]+inblock[3][1];
+ pieces[2][2] = inblock[0][2]-inblock[1][2]-inblock[2][2]+inblock[3][2];
+ pieces[2][3] = inblock[0][3]-inblock[1][3]-inblock[2][3]+inblock[3][3];
+
+ pieces[3][0] = inblock[0][0]-(inblock[1][0]<<1)+(inblock[2][0]<<1)-inblock[3][0];
+ pieces[3][1] = inblock[0][1]-(inblock[1][1]<<1)+(inblock[2][1]<<1)-inblock[3][1];
+ pieces[3][2] = inblock[0][2]-(inblock[1][2]<<1)+(inblock[2][2]<<1)-inblock[3][2];
+ pieces[3][3] = inblock[0][3]-(inblock[1][3]<<1)+(inblock[2][3]<<1)-inblock[3][3];
+
+ outblock[0][0] = pieces[0][0]+pieces[0][1]+pieces[0][2]+pieces[0][3];
+ outblock[0][1] = pieces[1][0]+pieces[1][1]+pieces[1][2]+pieces[1][3];
+ outblock[0][2] = pieces[2][0]+pieces[2][1]+pieces[2][2]+pieces[2][3];
+ outblock[0][3] = pieces[3][0]+pieces[3][1]+pieces[3][2]+pieces[3][3];
+
+ outblock[1][0] = (pieces[0][0] << 1)+pieces[0][1]-pieces[0][2]-(pieces[0][3]<<1);
+ outblock[1][1] = (pieces[1][0] << 1)+pieces[1][1]-pieces[1][2]-(pieces[1][3]<<1);
+ outblock[1][2] = (pieces[2][0] << 1)+pieces[2][1]-pieces[2][2]-(pieces[2][3]<<1);
+ outblock[1][3] = (pieces[3][0] << 1)+pieces[3][1]-pieces[3][2]-(pieces[3][3]<<1);
+
+ outblock[2][0] = pieces[0][0]-pieces[0][1]-pieces[0][2]+pieces[0][3];
+ outblock[2][1] = pieces[1][0]-pieces[1][1]-pieces[1][2]+pieces[1][3];
+ outblock[2][2] = pieces[2][0]-pieces[2][1]-pieces[2][2]+pieces[2][3];
+ outblock[2][3] = pieces[3][0]-pieces[3][1]-pieces[3][2]+pieces[3][3];
+
+ outblock[3][0] = pieces[0][0]-(pieces[0][1]<<1)+(pieces[0][2]<<1)-pieces[0][3];
+ outblock[3][1] = pieces[1][0]-(pieces[1][1]<<1)+(pieces[1][2]<<1)-pieces[1][3];
+ outblock[3][2] = pieces[2][0]-(pieces[2][1]<<1)+(pieces[2][2]<<1)-pieces[2][3];
+ outblock[3][3] = pieces[3][0]-(pieces[3][1]<<1)+(pieces[3][2]<<1)-pieces[3][3];
+}
+
+
+void ff_h264_hadamard_mult4x4_c(DCTELEM Y[4][4])
+{
+ DCTELEM pieces[4][4];
+
+ pieces[0][0] = Y[0][0]+Y[0][1]+Y[0][2]+Y[0][3];
+ pieces[0][1] = Y[1][0]+Y[1][1]+Y[1][2]+Y[1][3];
+ pieces[0][2] = Y[2][0]+Y[2][1]+Y[2][2]+Y[2][3];
+ pieces[0][3] = Y[3][0]+Y[3][1]+Y[3][2]+Y[3][3];
+
+ pieces[1][0] = Y[0][0]+Y[0][1]-Y[0][2]-Y[0][3];
+ pieces[1][1] = Y[1][0]+Y[1][1]-Y[1][2]-Y[1][3];
+ pieces[1][2] = Y[2][0]+Y[2][1]-Y[2][2]-Y[2][3];
+ pieces[1][3] = Y[3][0]+Y[3][1]-Y[3][2]-Y[3][3];
+
+ pieces[2][0] = Y[0][0]-Y[0][1]-Y[0][2]+Y[0][3];
+ pieces[2][1] = Y[1][0]-Y[1][1]-Y[1][2]+Y[1][3];
+ pieces[2][2] = Y[2][0]-Y[2][1]-Y[2][2]+Y[2][3];
+ pieces[2][3] = Y[3][0]-Y[3][1]-Y[3][2]+Y[3][3];
+
+ pieces[3][0] = Y[0][0]-Y[0][1]+Y[0][2]-Y[0][3];
+ pieces[3][1] = Y[1][0]-Y[1][1]+Y[1][2]-Y[1][3];
+ pieces[3][2] = Y[2][0]-Y[2][1]+Y[2][2]-Y[2][3];
+ pieces[3][3] = Y[3][0]-Y[3][1]+Y[3][2]-Y[3][3];
+
+ Y[0][0] = pieces[0][0]+pieces[0][1]+pieces[0][2]+pieces[0][3];
+ Y[0][1] = pieces[1][0]+pieces[1][1]+pieces[1][2]+pieces[1][3];
+ Y[0][2] = pieces[2][0]+pieces[2][1]+pieces[2][2]+pieces[2][3];
+ Y[0][3] = pieces[3][0]+pieces[3][1]+pieces[3][2]+pieces[3][3];
+
+ Y[1][0] = pieces[0][0]+pieces[0][1]-pieces[0][2]-pieces[0][3];
+ Y[1][1] = pieces[1][0]+pieces[1][1]-pieces[1][2]-pieces[1][3];
+ Y[1][2] = pieces[2][0]+pieces[2][1]-pieces[2][2]-pieces[2][3];
+ Y[1][3] = pieces[3][0]+pieces[3][1]-pieces[3][2]-pieces[3][3];
+
+ Y[2][0] = pieces[0][0]-pieces[0][1]-pieces[0][2]+pieces[0][3];
+ Y[2][1] = pieces[1][0]-pieces[1][1]-pieces[1][2]+pieces[1][3];
+ Y[2][2] = pieces[2][0]-pieces[2][1]-pieces[2][2]+pieces[2][3];
+ Y[2][3] = pieces[3][0]-pieces[3][1]-pieces[3][2]+pieces[3][3];
+
+ Y[3][0] = pieces[0][0]-pieces[0][1]+pieces[0][2]-pieces[0][3];
+ Y[3][1] = pieces[1][0]-pieces[1][1]+pieces[1][2]-pieces[1][3];
+ Y[3][2] = pieces[2][0]-pieces[2][1]+pieces[2][2]-pieces[2][3];
+ Y[3][3] = pieces[3][0]-pieces[3][1]+pieces[3][2]-pieces[3][3];
+}
+
+static inline void ff_h264_hadamard_mult_2x2(int16_t Y[2][2])
+{
+ int16_t pieces[2][2];
+
+ pieces[0][0] = Y[0][0]+Y[0][1];
+ pieces[0][1] = Y[1][0]+Y[1][1];
+ pieces[1][0] = Y[0][0]-Y[0][1];
+ pieces[1][1] = Y[1][0]-Y[1][1];
+ Y[0][0] = pieces[0][0]+pieces[0][1];
+ Y[0][1] = pieces[1][0]+pieces[1][1];
+ Y[1][0] = pieces[0][0]-pieces[0][1];
+ Y[1][1] = pieces[1][0]-pieces[1][1];
+}
+
+const int16_t ff_h264_MF00[6] = {13107, 11916, 10082, 9362, 8192, 7282};
+const int16_t ff_h264_V00[6] = {10*16, 11*16, 13*16, 14*16, 16*16, 18*16};
+
+static inline void ff_h264_hadamard_invquant_2x2(int16_t Y[2][2], int QP)
+{
+ int32_t V = ff_h264_V00[QP%6];
+ int div = QP/6;
+
+ V <<= div;
+ Y[0][0] = (Y[0][0]*V) >> 5;
+ Y[0][1] = (Y[0][1]*V) >> 5;
+ Y[1][0] = (Y[1][0]*V) >> 5;
+ Y[1][1] = (Y[1][1]*V) >> 5;
+}
+
+#define NEIGHBOUR_SUBTYPE_Y 0
+#define NEIGHBOUR_SUBTYPE_U 1
+#define NEIGHBOUR_SUBTYPE_V 2
+
+#define H264_NEIGHBOUR_COUNT_NONZERO_PLANE(PLANE, P) \
+ { \
+ if (x == 0) \
+ { \
+ MacroBlock *leftmb = mb->leftblock; \
+ if (!leftmb) \
+ *nA = -1; \
+ else \
+ *nA = leftmb->PLANE[y][P]; \
+ } \
+ else \
+ *nA = mb->PLANE[y][x-1]; \
+ if (y == 0) \
+ { \
+ MacroBlock *topmb = mb->topblock; \
+ if (!topmb) \
+ *nB = -1; \
+ else \
+ *nB = topmb->PLANE[P][x]; \
+ } \
+ else \
+ *nB = mb->PLANE[y-1][x]; \
+ }
+
+static inline void ff_h264_neighbour_count_nonzero(MacroBlock *mb, int type, int x, int y, int *nA, int *nB)
+{
+ if (type == NEIGHBOUR_SUBTYPE_Y)
+ H264_NEIGHBOUR_COUNT_NONZERO_PLANE(Y_nonzero, 3)
+ else if (type == NEIGHBOUR_SUBTYPE_U)
+ H264_NEIGHBOUR_COUNT_NONZERO_PLANE(U_nonzero, 1)
+ else
+ H264_NEIGHBOUR_COUNT_NONZERO_PLANE(V_nonzero, 1)
+}
+
+#define H264_COUNT_AND_CLIP(x,count) \
+{\
+ if (x != 0)\
+ count++;\
+ clip(x, -2047, 2047);\
+}
+
+#define H264_COUNT_AND_CLIP_SUBBLOCK(x,count)\
+{\
+ H264_COUNT_AND_CLIP(x[0][1],count);\
+ H264_COUNT_AND_CLIP(x[0][2],count);\
+ H264_COUNT_AND_CLIP(x[0][3],count);\
+ H264_COUNT_AND_CLIP(x[1][0],count);\
+ H264_COUNT_AND_CLIP(x[1][1],count);\
+ H264_COUNT_AND_CLIP(x[1][2],count);\
+ H264_COUNT_AND_CLIP(x[1][3],count);\
+ H264_COUNT_AND_CLIP(x[2][0],count);\
+ H264_COUNT_AND_CLIP(x[2][1],count);\
+ H264_COUNT_AND_CLIP(x[2][2],count);\
+ H264_COUNT_AND_CLIP(x[2][3],count);\
+ H264_COUNT_AND_CLIP(x[3][0],count);\
+ H264_COUNT_AND_CLIP(x[3][1],count);\
+ H264_COUNT_AND_CLIP(x[3][2],count);\
+ H264_COUNT_AND_CLIP(x[3][3],count);\
+}
+
+static const int8_t zigzagx[16] = { 0,1,0,0,1,2,3,2,1,0,1,2,3,3,2,3 };
+static const int8_t zigzagy[16] = { 0,0,1,2,1,0,0,1,2,3,3,2,1,2,3,3 };
+
+#define H264_ENCODE_INTRA16X16_RESIDUAL_COEFFICIENTS(PLANE) \
+ coefficients[0] = PLANE[0][0]; \
+ coefficients[1] = PLANE[0][1]; \
+ coefficients[2] = PLANE[1][0]; \
+ coefficients[3] = PLANE[1][1]; \
+ h264cavlc_encode(b,coefficients,4,-1,-1,1); // nA and nB are not used in this case
+
+static void ff_h264_encode_intra16x16_residual(PutBitContext *b,DCTELEM YD[4][4],DCTELEM UD[2][2],DCTELEM VD[2][2],
+ Residual *residual, int lumamode, int chromamode, MacroBlock *mb)
+{
+ int lumaACcount = 0;
+ int chromaDCcount = 0;
+ int chromaACcount = 0;
+ int CodedBlockPatternChroma = 0;
+ int CodedBlockPatternLuma = 0;
+ int x,y,i,j;
+ int16_t coefficients[256];
+ int nA,nB;
+
+
+ for (y = 0 ; y < 4 ; y++)
+ for (x = 0 ; x < 4 ; x++)
+ H264_COUNT_AND_CLIP_SUBBLOCK(residual->part4x4Y[y][x],lumaACcount);
+
+ for (y = 0 ; y < 2 ; y++)
+ {
+ for (x = 0 ; x < 2 ; x++)
+ {
+ H264_COUNT_AND_CLIP_SUBBLOCK(residual->part4x4U[y][x],chromaACcount);
+ H264_COUNT_AND_CLIP_SUBBLOCK(residual->part4x4V[y][x],chromaACcount);
+ }
+ }
+
+ for (y = 0 ; y < 2 ; y++)
+ {
+ for (x = 0 ; x < 2 ; x++)
+ {
+ H264_COUNT_AND_CLIP(UD[y][x],chromaDCcount);
+ H264_COUNT_AND_CLIP(VD[y][x],chromaDCcount);
+ }
+ }
+
+ for (y = 0 ; y < 4 ; y++)
+ for (x = 0 ; x < 4 ; x++)
+ clip(YD[y][x], -2047, 2047);
+
+ if(chromaACcount)
+ CodedBlockPatternChroma= 2;
+ else
+ CodedBlockPatternChroma= !!chromaDCcount;
+
+ if (lumaACcount == 0)
+ CodedBlockPatternLuma = 0;
+ else
+ CodedBlockPatternLuma = 1; // actually it is 15 in the ITU spec, but I'd like to use it as an array index
+
+ set_ue_golomb(b, mbtype_map[lumamode][CodedBlockPatternChroma][CodedBlockPatternLuma]); // mb_type
+ set_ue_golomb(b, chromamode); // intra_chroma_pred_mode
+ set_se_golomb(b, 0); // mb_qp_delta
+
+ // encode luma DC coefficients
+
+ ff_h264_neighbour_count_nonzero(mb,NEIGHBOUR_SUBTYPE_Y,0,0,&nA,&nB);
+ for (i = 0 ; i < 16 ; i++)
+ coefficients[i] = YD[zigzagy[i]][zigzagx[i]];
+ h264cavlc_encode(b,coefficients,16,nA,nB,0);
+
+ if (CodedBlockPatternLuma > 0)
+ {
+ for (j = 0 ; j < 4 ; j++)
+ {
+ int X = (j&1) << 1;
+ int Y = j&2;
+
+ for (i = 0 ; i < 4 ; i++)
+ {
+ int x = (i&1)+X;
+ int y = (i>>1)+Y;
+
+ int k;
+
+ for (k = 0 ; k < 15 ; k++)
+ coefficients[k] = residual->part4x4Y[y][x][zigzagy[k+1]][zigzagx[k+1]];
+ ff_h264_neighbour_count_nonzero(mb,NEIGHBOUR_SUBTYPE_Y,x,y,&nA,&nB);
+ mb->Y_nonzero[y][x] = h264cavlc_encode(b,coefficients,15,nA,nB,0);
+ }
+ }
+ }
+ else
+ memset(mb->Y_nonzero, 0, sizeof(mb->Y_nonzero));
+
+ if (CodedBlockPatternChroma == 0)
+ {
+ memset(mb->U_nonzero, 0, sizeof(mb->U_nonzero));
+ memset(mb->V_nonzero, 0, sizeof(mb->V_nonzero));
+ return;
+ }
+
+ if (CodedBlockPatternChroma != 0)
+ {
+ H264_ENCODE_INTRA16X16_RESIDUAL_COEFFICIENTS(UD);
+ H264_ENCODE_INTRA16X16_RESIDUAL_COEFFICIENTS(VD);
+ }
+
+ if (CodedBlockPatternChroma == 2)
+ {
+ for (i = 0 ; i < 4 ; i++)
+ {
+ int x = i&1;
+ int y = i>>1;
+
+ int k;
+
+ for (k = 0 ; k < 15 ; k++)
+ coefficients[k] = residual->part4x4U[y][x][zigzagy[k+1]][zigzagx[k+1]];
+ ff_h264_neighbour_count_nonzero(mb,NEIGHBOUR_SUBTYPE_U,x,y,&nA,&nB);
+ mb->U_nonzero[y][x] = h264cavlc_encode(b,coefficients,15,nA,nB,0);
+ }
+
+ for (i = 0 ; i < 4 ; i++)
+ {
+ int x = i&1;
+ int y = i>>1;
+
+ int k;
+
+ for (k = 0 ; k < 15 ; k++)
+ coefficients[k] = residual->part4x4V[y][x][zigzagy[k+1]][zigzagx[k+1]];
+ ff_h264_neighbour_count_nonzero(mb,NEIGHBOUR_SUBTYPE_V,x,y,&nA,&nB);
+ mb->V_nonzero[y][x] = h264cavlc_encode(b,coefficients,15,nA,nB,0);
+ }
+ }
+ else
+ {
+ memset(mb->U_nonzero, 0, sizeof(mb->U_nonzero));
+ memset(mb->V_nonzero, 0, sizeof(mb->V_nonzero));
+ }
+}
+
+static void ff_h264_encode_Intra_16x16(H264Context *t, MacroBlock *targetmb, PutBitContext *b,
+ MacroBlock *destmb)
+{
+ int x,y;
+ int w,h,w2,h2;
+ DCTELEM YD[4][4];
+ DCTELEM UD[2][2];
+ DCTELEM VD[2][2];
+ int qPI;
+ int QPc;
+ int QPy = t->QP;
+ int lumapredmode = 2;
+ int chromapredmode = 0;
+ int leftavail = 0;
+ int topavail = 0;
+
+ qPI = t->QP + t->chroma_qp_index_offset;
+ qPI = clip(qPI, 0, 51);
+ QPc = chroma_qp[qPI];
+
+ w = targetmb->Y_width;
+ h = targetmb->Y_height;
+ w2 = w>>1;
+ h2 = h>>1;
+
+ if (destmb->leftblock != NULL && destmb->leftblock->available)
+ leftavail = 1;
+ if (destmb->topblock != NULL && destmb->topblock->available)
+ topavail = 1;
+
+ // TODO: use better strategy to determine intra16x16 encoding mode
+
+ if (leftavail)
+ {
+ MacroBlock *srcleft = destmb->leftblock;
+
+ if (topavail && w == 16 && h == 16 && srcleft->topblock != 0 && srcleft->topblock->available)
+ {
+ // Plane prediction
+ pred16x16_plane_c(destmb->Y[0], t->refframe_width);
+ pred8x8_plane_c(destmb->U[0], t->refframe_width>>1);
+ pred8x8_plane_c(destmb->V[0], t->refframe_width>>1);
+ lumapredmode = PLANE_PRED8x8;
+ chromapredmode = PLANE_PRED8x8;
+ }
+ else
+ {
+ // Horizontal prediction
+ pred16x16_horizontal_c(destmb->Y[0], t->refframe_width);
+ pred8x8_horizontal_c(destmb->U[0], t->refframe_width>>1);
+ pred8x8_horizontal_c(destmb->V[0], t->refframe_width>>1);
+ lumapredmode = HOR_PRED8x8;
+ chromapredmode = HOR_PRED8x8;
+ }
+ }
+ else // no left neighbour
+ {
+ if (topavail)
+ {
+ // Vertical prediction
+ pred16x16_vertical_c(destmb->Y[0], t->refframe_width);
+ pred8x8_vertical_c(destmb->U[0], t->refframe_width>>1);
+ pred8x8_vertical_c(destmb->V[0], t->refframe_width>>1);
+ lumapredmode = VERT_PRED;
+ chromapredmode = VERT_PRED8x8;
+ }
+ else // nothing available, encode a standard DC block
+ {
+ pred16x16_128_dc_c(destmb->Y[0], t->refframe_width);
+ pred8x8_128_dc_c(destmb->U[0], t->refframe_width>>1);
+ pred8x8_128_dc_c(destmb->V[0], t->refframe_width>>1);
+ lumapredmode = DC_PRED;
+ chromapredmode = DC_PRED8x8;
+ }
+ }
+
+ H264_COPY_16X16BLOCK(t->residual.part4x4Y,(int16_t)targetmb->Y,(int16_t)destmb->Y);
+ H264_COPY_8X8BLOCK(t->residual.part4x4U,(int16_t)targetmb->U,(int16_t)destmb->U);
+ H264_COPY_8X8BLOCK(t->residual.part4x4V,(int16_t)targetmb->V,(int16_t)destmb->V);
+
+ // Transform residual: DCT
+
+ for (y = 0 ; y < 4 ; y++)
+ {
+ for (x = 0 ; x < 4 ; x++)
+ {
+ t->dspcontext.h264_transform_dct_quant(t->residual.part4x4Y[y][x],QPy,1);
+ }
+ }
+ for (y = 0 ; y < 2 ; y++)
+ {
+ for (x = 0 ; x < 2 ; x++)
+ {
+ t->dspcontext.h264_transform_dct_quant(t->residual.part4x4U[y][x],QPc,1);
+ t->dspcontext.h264_transform_dct_quant(t->residual.part4x4V[y][x],QPc,1);
+ }
+ }
+
+ // Hadamard
+
+ // For luma
+ for (y = 0 ; y < 4 ; y++)
+ for (x = 0 ; x < 4 ; x++)
+ YD[y][x] = t->residual.part4x4Y[y][x][0][0];
+
+ t->dspcontext.h264_hadamard_mult4x4(YD);
+ t->dspcontext.h264_hadamard_quant_4x4(YD,QPy);
+
+ // For U
+ for (y = 0 ; y < 2 ; y++)
+ for (x = 0 ; x < 2 ; x++)
+ UD[y][x] = t->residual.part4x4U[y][x][0][0];
+ ff_h264_hadamard_mult_2x2(UD);
+ t->dspcontext.h264_hadamard_quant_2x2(UD,QPc);
+
+ // For V
+ for (y = 0 ; y < 2 ; y++)
+ for (x = 0 ; x < 2 ; x++)
+ VD[y][x] = t->residual.part4x4V[y][x][0][0];
+ ff_h264_hadamard_mult_2x2(VD);
+ t->dspcontext.h264_hadamard_quant_2x2(VD,QPc);
+ // Encode macroblock
+
+ ff_h264_encode_intra16x16_residual(b,YD,UD,VD,&(t->residual),lumapredmode,chromapredmode,destmb);
+
+ // Inverse hadamard
+
+ // For luma
+ t->dspcontext.h264_hadamard_mult4x4(YD);
+ t->dspcontext.h264_hadamard_invquant_4x4(YD,QPy);
+ for (y = 0 ; y < 4 ; y++)
+ for (x = 0 ; x < 4 ; x++)
+ t->residual.part4x4Y[y][x][0][0] = YD[y][x];
+
+ // For U
+ ff_h264_hadamard_mult_2x2(UD);
+ ff_h264_hadamard_invquant_2x2(UD,QPc);
+ for (y = 0 ; y < 2 ; y++)
+ for (x = 0 ; x < 2 ; x++)
+ t->residual.part4x4U[y][x][0][0] = UD[y][x];
+ // For V
+ ff_h264_hadamard_mult_2x2(VD);
+ ff_h264_hadamard_invquant_2x2(VD,QPc);
+ for (y = 0 ; y < 2 ; y++)
+ for (x = 0 ; x < 2 ; x++)
+ t->residual.part4x4V[y][x][0][0] = VD[y][x];
+
+ // Inverse DCT and add
+
+ for (y = 0 ; y < 4 ; y++)
+ {
+ for (x = 0 ; x < 4 ; x++)
+ {
+ t->dspcontext.h264_transform_inverse_quant_dct_add(t->residual.part4x4Y[y][x],QPy,1,&(destmb->Y[y*4][x*4]),t->Y_stride);
+ }
+ }
+ for (y = 0 ; y < 2 ; y++)
+ {
+ for (x = 0 ; x < 2 ; x++)
+ {
+ t->dspcontext.h264_transform_inverse_quant_dct_add(t->residual.part4x4U[y][x],QPc,1,&(destmb->U[y*4][x*4]),t->U_stride);
+ t->dspcontext.h264_transform_inverse_quant_dct_add(t->residual.part4x4V[y][x],QPc,1,&(destmb->V[y*4][x*4]),t->V_stride);
+ }
+ }
+
+ destmb->available = 1;
+}
+
+#define H264_CODEDBLOCKPATTERN_4X4CHECK(a,b) \
+ for (y = 0 ; !done && y < 4 ; y++)\
+ for (x = 0 ; !done && x < 4 ; x++)\
+ if (residual->part4x4Y[a][b][y][x] != 0) \
+ done = 1;
+#define H264_CODEDBLOCKPATTERN_8X8CHECK(i,j,shift) \
+ done = 0;\
+ H264_CODEDBLOCKPATTERN_4X4CHECK(i+0,j+0)\
+ H264_CODEDBLOCKPATTERN_4X4CHECK(i+0,j+1)\
+ H264_CODEDBLOCKPATTERN_4X4CHECK(i+1,j+0)\
+ H264_CODEDBLOCKPATTERN_4X4CHECK(i+1,j+1)\
+ if (done)\
+ CodedBlockPatternLuma |= (1 << shift);
+
+static void ff_h264_encode_inter16x16_residual(H264Context *t, PutBitContext *b,int mv_x,int mv_y,int mv_x2,int mv_y2,
+ Residual *residual,
+ DCTELEM UD[2][2],DCTELEM VD[2][2],int pred_frame_index,MacroBlock *mb,
+ int last_macroblock)
+{
+ static const int8_t me_map[] = { 0, 2, 3, 7, 4, 8,17,13, 5,18, 9,14,10,15,16,
+ 11, 1,32,33,36,34,37,44,40,35,45,38,41,39,42,
+ 43,19, 6,24,25,20,26,21,46,28,27,47,22,29,23,
+ 30,31,12};
+ int coded_block_pattern;
+ int CodedBlockPatternLuma;
+ int CodedBlockPatternChroma;
+ int16_t coefficients[256];
+ int x,y,i,j;
+ int done;
+ int chromaACcount;
+ int chromaDCcount;
+ int nA,nB;
+
+ // coded_block_pattern
+
+ CodedBlockPatternLuma = 0;
+
+ // first 8x8 block
+ H264_CODEDBLOCKPATTERN_8X8CHECK(0,0,0)
+
+ // second 8x8 block
+ H264_CODEDBLOCKPATTERN_8X8CHECK(0,2,1)
+
+ // third 8x8 block
+ H264_CODEDBLOCKPATTERN_8X8CHECK(2,0,2)
+
+ // fourth 8x8 block
+ H264_CODEDBLOCKPATTERN_8X8CHECK(2,2,3)
+
+ // check for too large values in luma
+ for (y = 0 ; y < 4 ; y++)
+ {
+ for (x = 0 ; x < 4 ; x++)
+ {
+ clip(residual->part4x4Y[y][x][0][0], -2047, 2047);
+ clip(residual->part4x4Y[y][x][0][1], -2047, 2047);
+ clip(residual->part4x4Y[y][x][0][2], -2047, 2047);
+ clip(residual->part4x4Y[y][x][0][3], -2047, 2047);
+ clip(residual->part4x4Y[y][x][1][0], -2047, 2047);
+ clip(residual->part4x4Y[y][x][1][1], -2047, 2047);
+ clip(residual->part4x4Y[y][x][1][2], -2047, 2047);
+ clip(residual->part4x4Y[y][x][1][3], -2047, 2047);
+ clip(residual->part4x4Y[y][x][2][0], -2047, 2047);
+ clip(residual->part4x4Y[y][x][2][1], -2047, 2047);
+ clip(residual->part4x4Y[y][x][2][2], -2047, 2047);
+ clip(residual->part4x4Y[y][x][2][3], -2047, 2047);
+ clip(residual->part4x4Y[y][x][3][0], -2047, 2047);
+ clip(residual->part4x4Y[y][x][3][1], -2047, 2047);
+ clip(residual->part4x4Y[y][x][3][2], -2047, 2047);
+ clip(residual->part4x4Y[y][x][3][3], -2047, 2047);
+ }
+ }
+
+ chromaDCcount = 0;
+ chromaACcount = 0;
+ for (y = 0 ; y < 2 ; y++)
+ {
+ for (x = 0 ; x < 2 ; x++)
+ {
+ H264_COUNT_AND_CLIP_SUBBLOCK(residual->part4x4U[y][x],chromaACcount);
+ H264_COUNT_AND_CLIP_SUBBLOCK(residual->part4x4V[y][x],chromaACcount);
+ }
+ }
+ for (y = 0 ; y < 2 ; y++)
+ {
+ for (x = 0 ; x < 2 ; x++)
+ {
+ H264_COUNT_AND_CLIP(UD[y][x],chromaDCcount);
+ H264_COUNT_AND_CLIP(VD[y][x],chromaDCcount);
+ }
+ }
+
+ if (chromaACcount)
+ CodedBlockPatternChroma= 2;
+ else
+ CodedBlockPatternChroma= !!chromaDCcount;
+
+ if (mv_x2 == 0 && mv_y2 == 0 && CodedBlockPatternChroma == 0 && CodedBlockPatternLuma == 0) // entirely predictable
+ {
+ t->mb_skip_run++;
+ if (last_macroblock)
+ set_se_golomb(b, t->mb_skip_run);
+ }
+ else
+ {
+ set_ue_golomb(b, t->mb_skip_run); // mb_skip_run
+ t->mb_skip_run = 0;
+
+ set_ue_golomb(b, 0); // mb_type = P_L0_16x16
+
+ // mb_pred()
+
+ set_se_golomb(b, mv_x);
+ set_se_golomb(b, mv_y);
+
+ coded_block_pattern = (CodedBlockPatternChroma << 4)|CodedBlockPatternLuma;
+ set_ue_golomb(b,me_map[coded_block_pattern]);
+ }
+
+ // residual()
+
+ if (CodedBlockPatternLuma == 0 && CodedBlockPatternChroma == 0) // nothing left to do
+ {
+ memset(mb->Y_nonzero, 0, sizeof(mb->Y_nonzero));
+ memset(mb->U_nonzero, 0, sizeof(mb->U_nonzero));
+ memset(mb->V_nonzero, 0, sizeof(mb->V_nonzero));
+ return;
+ }
+
+ set_se_golomb(b, 0); // mb_qp_delta
+
+ // encode luma levels
+ for (j = 0 ; j < 4 ; j++)
+ {
+ int X = (j&1) << 1;
+ int Y = j&2;
+
+ if ((CodedBlockPatternLuma >> j)&1)
+ {
+ for (i = 0 ; i < 4 ; i++)
+ {
+ int x = (i&1)+X;
+ int y = (i>>1)+Y;
+
+ int k;
+
+ for (k = 0 ; k < 16 ; k++)
+ coefficients[k] = residual->part4x4Y[y][x][zigzagy[k]][zigzagx[k]];
+ ff_h264_neighbour_count_nonzero(mb,NEIGHBOUR_SUBTYPE_Y,x,y,&nA,&nB);
+ mb->Y_nonzero[y][x] = h264cavlc_encode(b,coefficients,16,nA,nB,0);
+ }
+ }
+ else
+ {
+ for (i = 0 ; i < 4 ; i++)
+ {
+ int x = (i&1)+X;
+ int y = (i>>1)+Y;
+ mb->Y_nonzero[y][x] = 0;
+ }
+ }
+ }
+
+ // chroma DC levels
+ if (CodedBlockPatternChroma != 0)
+ {
+ coefficients[0] = UD[0][0];
+ coefficients[1] = UD[0][1];
+ coefficients[2] = UD[1][0];
+ coefficients[3] = UD[1][1];
+ h264cavlc_encode(b,coefficients,4,-1,-1,1); // nA and nB are not used in this case
+
+ coefficients[0] = VD[0][0];
+ coefficients[1] = VD[0][1];
+ coefficients[2] = VD[1][0];
+ coefficients[3] = VD[1][1];
+ h264cavlc_encode(b,coefficients,4,-1,-1,1); // nA and nB are not used in this case
+ }
+
+ if (CodedBlockPatternChroma == 2)
+ {
+ for (i = 0 ; i < 4 ; i++)
+ {
+ int x = i&1;
+ int y = i>>1;
+
+ int k;
+
+ for (k = 0 ; k < 15 ; k++)
+ coefficients[k] = residual->part4x4U[y][x][zigzagy[k+1]][zigzagx[k+1]];
+ ff_h264_neighbour_count_nonzero(mb,NEIGHBOUR_SUBTYPE_U,x,y,&nA,&nB);
+ mb->U_nonzero[y][x] = h264cavlc_encode(b,coefficients,15,nA,nB,0);
+ }
+
+ for (i = 0 ; i < 4 ; i++)
+ {
+ int x = i&1;
+ int y = i>>1;
+
+ int k;
+
+ for (k = 0 ; k < 15 ; k++)
+ coefficients[k] = residual->part4x4V[y][x][zigzagy[k+1]][zigzagx[k+1]];
+ ff_h264_neighbour_count_nonzero(mb,NEIGHBOUR_SUBTYPE_V,x,y,&nA,&nB);
+ mb->V_nonzero[y][x] = h264cavlc_encode(b,coefficients,15,nA,nB,0);
+ }
+ }
+ else
+ {
+ int x,y;
+
+ for (y = 0 ; y < 2 ; y++)
+ {
+ for (x = 0 ; x < 2 ; x++)
+ {
+ mb->U_nonzero[y][x] = 0;
+ mb->V_nonzero[y][x] = 0;
+ }
+ }
+ }
+}
+
+static void ff_h264_predict(H264Context *t, MacroBlock *destmb, FrameInfo *refframe, int mbx, int mby, int mvx, int mvy)
+{
+ int x = mbx << 4;
+ int y = mby << 4;
+ AVPicture *refpic = &(refframe->reconstructed_picture);
+ uint8_t *data;
+ int linesize;
+ int i,j;
+ int startx,starty;
+ int w,h,w2,h2;
+ int xmod,ymod;
+
+ w = destmb->Y_width;
+ h = destmb->Y_height;
+ w2 = w>>1;
+ h2 = h>>1;
+
+ startx = x+(mvx/4);
+ starty = y+(mvy/4);
+
+ linesize = refpic->linesize[0];
+ data = refpic->data[0]+starty*linesize+startx;
+
+ for (i = 0 ; i < h ; i++)
+ {
+ for (j = 0 ; j < w ; j++)
+ destmb->Y[i][j] = data[j];
+ data += linesize;
+ }
+
+ linesize = refpic->linesize[1];
+ data = refpic->data[1]+(starty/2)*linesize+startx/2;
+
+ xmod = startx & 1;
+ ymod = starty & 1;
+
+ if (xmod == 0 && ymod == 0)
+ {
+ for (i = 0 ; i < h2 ; i++)
+ {
+ for (j = 0 ; j < w2 ; j++)
+ destmb->U[i][j] = data[j];
+ data += linesize;
+ }
+
+ linesize = refpic->linesize[2];
+ data = refpic->data[2]+(starty/2)*linesize+startx/2;
+ for (i = 0 ; i < h2 ; i++)
+ {
+ for (j = 0 ; j < w2 ; j++)
+ destmb->V[i][j] = data[j];
+ data += linesize;
+ }
+ }
+ else if (xmod == 0 && ymod != 0)
+ {
+ for (i = 0 ; i < h2 ; i++)
+ {
+ for (j = 0 ; j < w2 ; j++)
+ destmb->U[i][j] = (uint8_t)(((int)data[j]+(int)data[j+linesize]+1)/2);
+ data += linesize;
+ }
+
+ linesize = refpic->linesize[2];
+ data = refpic->data[2]+(starty/2)*linesize+startx/2;
+ for (i = 0 ; i < h2 ; i++)
+ {
+ for (j = 0 ; j < w2 ; j++)
+ destmb->V[i][j] = (uint8_t)(((int)data[j]+(int)data[j+linesize]+1)/2);
+ data += linesize;
+ }
+ }
+ else if (xmod != 0 && ymod == 0)
+ {
+ for (i = 0 ; i < h2 ; i++)
+ {
+ for (j = 0 ; j < w2 ; j++)
+ destmb->U[i][j] = (uint8_t)(((int)data[j]+(int)data[j+1]+1)/2);
+ data += linesize;
+ }
+
+ linesize = refpic->linesize[2];
+ data = refpic->data[2]+(starty/2)*linesize+startx/2;
+ for (i = 0 ; i < h2 ; i++)
+ {
+ for (j = 0 ; j < w2 ; j++)
+ destmb->V[i][j] = (uint8_t)(((int)data[j]+(int)data[j+1]+1)/2);
+ data += linesize;
+ }
+ }
+ else // xmod != 0 && ymod != 0
+ {
+ for (i = 0 ; i < h2 ; i++)
+ {
+ for (j = 0 ; j < w2 ; j++)
+ destmb->U[i][j] = (uint8_t)(((int)data[j]+(int)data[j+1]+(int)data[j+linesize+1]+(int)data[j+linesize]+2)/4);
+ data += linesize;
+ }
+
+ linesize = refpic->linesize[2];
+ data = refpic->data[2]+(starty/2)*linesize+startx/2;
+ for (i = 0 ; i < h2 ; i++)
+ {
+ for (j = 0 ; j < w2 ; j++)
+ destmb->V[i][j] = (uint8_t)(((int)data[j]+(int)data[j+1]+(int)data[j+linesize+1]+(int)data[j+linesize]+2)/4);
+ data += linesize;
+ }
+ }
+}
+
+#define MAXSEARCHSTEPS 8
+#define SEARCHWIDTH 1
+
+static void ff_h264_find_motion_vector_and_prediction(H264Context *t, MacroBlock *targetmb, FrameInfo *refframe,
+ int mbx, int mby, int *mvx, int *mvy,
+ int pred_mvx, int pred_mvy, MacroBlock *destmb)
+{
+ int x = mbx << 4;
+ int y = mby << 4;
+ int bestx, besty;
+ int curx, cury;
+ int minbitsize = 0x7FFFFFFF;
+ int QP = t->QP;
+ int done = 0;
+ int numsteps = 0;
+
+ bestx = x;
+ besty = y;
+ curx = x;
+ cury = y;
+
+ {
+ int scanx = x;
+ int scany = y;
+ int weight;
+ int xvec = -pred_mvx; // it's actually this difference which will be encoded!
+ int yvec = -pred_mvy;
+ int sae = t->dspcontext.pix_abs[0][0](0,targetmb->Y[0],
+ refframe->reconstructed_picture.data[0] + scany * refframe->reconstructed_picture.linesize[0] + scanx,
+ refframe->reconstructed_picture.linesize[0], 16);
+ sae += t->dspcontext.pix_abs[1][0](0,targetmb->U[0],
+ refframe->reconstructed_picture.data[1] + (scany/2) * refframe->reconstructed_picture.linesize[1] + scanx/2,
+ refframe->reconstructed_picture.linesize[1], 8);
+ sae += t->dspcontext.pix_abs[1][0](0,targetmb->V[0],
+ refframe->reconstructed_picture.data[2] + (scany/2) * refframe->reconstructed_picture.linesize[2] + scanx/2,
+ refframe->reconstructed_picture.linesize[2], 8);
+ sae = FFMIN(sae>>4, 2047);
+ minbitsize = mv_len_table[xvec+MVTABLE_OFFSET]
+ + mv_len_table[yvec+MVTABLE_OFFSET];
+ weight = sae_codeblocksize_relation[QP>>2][sae>>8];
+ weight += (sae_codeblocksize_relation[QP>>2][FFMIN(((sae>>8)+1), 8)]
+ - sae_codeblocksize_relation[QP>>2][sae>>8] )
+ * (sae - ((sae>>8) << 8)) / ( (FFMIN(((sae>>8)+1), 8) << 8)
+ - ((sae>>8) << 8) );
+ minbitsize += weight;
+ }
+
+ while (!done && numsteps < MAXSEARCHSTEPS)
+ {
+ int startx = curx - SEARCHWIDTH;
+ int starty = cury - SEARCHWIDTH;
+ int stopx = curx + SEARCHWIDTH + 1;
+ int stopy = cury + SEARCHWIDTH + 1;
+ int foundbetter = 0;
+ int scanx, scany;
+
+ if (startx < 0)
+ startx = 0;
+ if (starty < 0)
+ starty = 0;
+ if (stopx > t->refframe_width - 16 + 1)
+ stopx = t->refframe_width - 16 + 1;
+ if (stopy > t->refframe_height - 16 + 1)
+ stopy = t->refframe_height -16 + 1;
+
+ for(scany = starty; scany < stopy; scany++)
+ {
+ for(scanx = startx; scanx < stopx; scanx++)
+ {
+ if (!(curx == scanx && cury == scany))
+ {
+ int xvec = (scanx-x)*4-pred_mvx; // it's actually this difference which will be encoded!
+ int yvec = (scany-y)*4-pred_mvy;
+ int bitsize;
+ int weight;
+ int xmod = scanx%2;
+ int ymod = scany%2;
+ int absnum = xmod+ymod*2;
+ int sae = t->dspcontext.pix_abs[0][0](0,targetmb->Y[0],
+ refframe->reconstructed_picture.data[0] + scany * refframe->reconstructed_picture.linesize[0] + scanx,
+ refframe->reconstructed_picture.linesize[0], 16);
+
+ sae += t->dspcontext.pix_abs[1][absnum](0,targetmb->U[0],
+ refframe->reconstructed_picture.data[1] + (scany/2) * refframe->reconstructed_picture.linesize[1] + scanx/2,
+ refframe->reconstructed_picture.linesize[1], 8);
+ sae += t->dspcontext.pix_abs[1][absnum](0,targetmb->V[0],
+ refframe->reconstructed_picture.data[2] + (scany/2) * refframe->reconstructed_picture.linesize[2] + scanx/2,
+ refframe->reconstructed_picture.linesize[2], 8);
+ sae = FFMIN(sae>>4, 2047);
+ bitsize = mv_len_table[xvec+MVTABLE_OFFSET]
+ + mv_len_table[yvec+MVTABLE_OFFSET];
+ weight = sae_codeblocksize_relation[QP>>2][sae>>8];
+ weight += (sae_codeblocksize_relation[QP>>2][FFMIN(((sae>>8)+1), 8)]
+ - sae_codeblocksize_relation[QP>>2][sae>>8] )
+ * (sae - ((sae>>8) << 8)) / ( (FFMIN(((sae>>8)+1), 8) << 8)
+ - ((sae>>8) << 8) );
+ bitsize += weight;
+ if (bitsize < minbitsize)
+ {
+ minbitsize = bitsize;
+ bestx = scanx;
+ besty = scany;
+ foundbetter = 1;
+ }
+ }
+ }
+ }
+
+ if (foundbetter)
+ {
+ curx = bestx;
+ cury = besty;
+ numsteps++;
+ }
+ else
+ done = 1;
+ }
+ {
+ int mvx = (bestx - x) * 4;
+ int mvy = (besty - y) * 4;
+
+ ff_h264_predict(t, destmb, refframe, mbx, mby, mvx, mvy);
+ }
+
+ *mvx = (bestx - x) * 4;
+ *mvy = (besty - y) * 4;
+}
+
+// Adjust the values of mvx and mvy based on the prediction from the neighbouring macroblocks
+static void ff_h264_estimate_motion_vectors(MacroBlock *destmb, int *mvpred_x, int *mvpred_y, int *mvpred_x2, int *mvpred_y2)
+{
+ int mvAx = 0, mvAy = 0;
+ int mvBx = 0, mvBy = 0;
+ int mvCx = 0, mvCy = 0;
+ int mvDx = 0, mvDy = 0;
+ int Aavail = 0;
+ int Bavail = 0;
+ int Cavail = 0;
+ int Davail = 0;
+
+ if (destmb->leftblock != NULL && destmb->leftblock->available)
+ {
+ Aavail = 1;
+ mvAx = destmb->leftblock->mv_x;
+ mvAy = destmb->leftblock->mv_y;
+ }
+ if (destmb->topblock != NULL)
+ {
+ MacroBlock *topblock = destmb->topblock;
+
+ if (topblock->available)
+ {
+ Bavail = 1;
+ mvBx = topblock->mv_x;
+ mvBy = topblock->mv_y;
+ }
+ if (topblock->leftblock != NULL && topblock->leftblock->available)
+ {
+ Davail = 1;
+ mvDx = topblock->leftblock->mv_x;
+ mvDy = topblock->leftblock->mv_y;
+ }
+ if (topblock->rightblock != NULL && topblock->rightblock->available)
+ {
+ Cavail = 1;
+ mvCx = topblock->rightblock->mv_x;
+ mvCy = topblock->rightblock->mv_y;
+ }
+ }
+
+ if (!Cavail)
+ {
+ Cavail = Davail;
+ mvCx = mvDx;
+ mvCy = mvDy;
+ }
+
+ if (!Bavail && !Cavail && Aavail)
+ {
+ mvBx = mvAx;
+ mvBy = mvAy;
+ mvCx = mvAx;
+ mvCy = mvAy;
+ }
+
+ *mvpred_x = mid_pred(mvAx,mvBx,mvCx);
+ *mvpred_y = mid_pred(mvAy,mvBy,mvCy);
+
+ if (!Aavail || !Bavail || (Aavail && mvAx == 0 && mvAy == 0) || (Bavail && mvBx == 0 && mvBy == 0))
+ {
+ *mvpred_x2 = 0;
+ *mvpred_y2 = 0;
+ }
+ else
+ {
+ *mvpred_x2 = *mvpred_x;
+ *mvpred_y2 = *mvpred_y;
+ }
+}
+
+/*
+ *
+ * Book p. 184, spec p. 182
+ */
+static inline void ff_h264_deblocking_filter_line_luma(int p[4], int q[4], int QP, int bS)
+{
+ int delta0, delta0i, deltap1i, deltaq1i, deltap1, deltaq1;
+ int pa0, pa1, pa2, qa0, qa1, qa2;
+ int alpha, beta;
+
+ if (bS == 0)
+ return;
+
+ alpha = alpha_table[QP];
+ beta = beta_table[QP];
+
+ if (!(
+ (ABS(p[0] - q[0]) < alpha) /* (1) */
+ &&
+ (ABS(p[1] - p[0]) < beta) /* (2) */
+ &&
+ (ABS(q[1] - q[0]) < beta) /* (3) */
+ ))
+ return;
+
+ pa0 = p[0];
+ pa1 = p[1];
+ pa2 = p[2];
+ qa0 = q[0];
+ qa1 = q[1];
+ qa2 = q[2];
+
+ if (bS == 4)
+ {
+ int aP = ABS(p[2] - p[0]);
+ int aQ = ABS(q[2] - q[0]);
+
+ if (aP < beta && ABS(p[0] - q[0]) < ((alpha>>2) + 2))
+ {
+ // Luminance filtering
+ pa0 = (p[2] + 2*p[1] + 2*p[0] + 2*q[0] + q[1] + 4) >> 3; /* (20) */
+ pa1 = (p[2] + p[1] + p[0] + q[0] + 2) >> 2; /* (21) */
+ pa2 = (2*p[3] + 3*p[2] + p[1] + p[0] + q[0] + 4) >> 3; /* (22) */
+ }
+ else
+ pa0 = (2*p[1] + p[0] + q[1] + 2) >> 2; /* (23) */
+
+ if (aQ < beta && ABS(p[0] - q[0]) < ((alpha>>2) + 2))
+ {
+ // Luminance filtering
+ qa0 = (p[1] + 2*p[0] + 2*q[0] + 2*q[1] + q[2] + 4) >> 3; /* (20) */
+ qa1 = (p[0] + q[0] + q[1] + q[2] + 2) >> 2; /* (21) */
+ qa2 = (2*q[3] + 3*q[2] + q[1] + q[0] + p[0] + 4) >> 3; /* (22) */
+ }
+ else
+ qa0 = (2*q[1] + q[0] + p[1] + 2) >> 2; /* (23) */
+ }
+ else
+ {
+ int aP = ABS(p[2] - p[0]);
+ int aQ = ABS(q[2] - q[0]);
+ int c0, c1;
+
+ c0 = c1 = tc0_table[QP][bS-1];
+
+ // All conditions are met to filter this line of samples
+
+ delta0i = (((q[0] - p[0])<<2) + (p[1] - q[1]) + 4) >> 3;
+
+ if (aP < beta) /* condition (8) */
+ {
+ /* c0 should be incremented for each condition being true, 8-473 */
+ c0++;
+
+ deltap1i = (p[2] + ((p[0] + q[0] + 1) >> 1) - (p[1]<<1)) >> 1;
+ deltap1 = clip(deltap1i, -c1, c1);
+ pa1 = p[1] + deltap1;
+ }
+
+ if (aQ < beta) /* condition (9) */
+ {
+ /* c0 should be incremented for each condition being true, 8-473 */
+ c0++;
+
+ deltaq1i = (q[2] + ((p[0] + q[0] + 1) >> 1) - (q[1]<<1)) >> 1;
+ deltaq1 = clip(deltaq1i, -c1, c1);
+ qa1 = q[1] + deltaq1;
+ }
+
+ delta0 = clip(delta0i, -c0, c0);
+ pa0 = clip_uint8(p[0] + delta0);
+ qa0 = clip_uint8(q[0] - delta0);
+ }
+ p[0] = pa0;
+ p[1] = pa1;
+ p[2] = pa2;
+ q[0] = qa0;
+ q[1] = qa1;
+ q[2] = qa2;
+}
+
+static inline void ff_h264_deblocking_filter_line_chroma(int p[4], int q[4], int QP, int bS)
+{
+ int delta0i, delta0;
+ int pa0, pa1, pa2, qa0, qa1, qa2;
+ int alpha, beta;
+
+ if (bS == 0)
+ return;
+
+ alpha = alpha_table[QP];
+ beta = beta_table[QP];
+
+ if (!(
+ (ABS(p[0] - q[0]) < alpha) /* (1) */
+ &&
+ (ABS(p[1] - p[0]) < beta) /* (2) */
+ &&
+ (ABS(q[1] - q[0]) < beta) /* (3) */
+ ))
+ return;
+
+ pa0 = p[0];
+ pa1 = p[1];
+ pa2 = p[2];
+ qa0 = q[0];
+ qa1 = q[1];
+ qa2 = q[2];
+
+ if (bS == 4)
+ {
+ pa0 = ((p[1]<<1) + p[0] + q[1] + 2) >> 2; /* (23) */
+ qa0 = ((q[1]<<1) + q[0] + p[1] + 2) >> 2; /* (23) */
+ }
+ else
+ {
+ int c0, c1;
+
+ c0 = c1 = tc0_table[QP][bS-1];
+
+ // All conditions are met to filter this line of samples
+
+ delta0i = (((q[0] - p[0])<<2) + (p[1] - q[1]) + 4) >> 3;
+
+ c0++; /* p. 191, (8-474) */
+
+ delta0 = clip(delta0i, -c0, c0);
+ pa0 = clip_uint8(p[0] + delta0);
+ qa0 = clip_uint8(q[0] - delta0);
+ }
+ p[0] = pa0;
+ p[1] = pa1;
+ p[2] = pa2;
+ q[0] = qa0;
+ q[1] = qa1;
+ q[2] = qa2;
+}
+
+static void ff_h264_deblock_macroblock(MacroBlock *mb, int filter_left_edge, int filter_top_edge, int isIDR, int QPYav, int QPCav)
+{
+ int p[4],q[4];
+ int x,y;
+ int bS[4][16];
+
+ // First step is filtering of vertical edges
+
+ // first filter left edge
+ if (filter_left_edge)
+ {
+ MacroBlock *leftmb = mb->leftblock;
+
+ // first Y
+ for (y = 0 ; y < 16 ; y++)
+ {
+ if (isIDR)
+ bS[0][y] = 4;
+ else
+ {
+ if (leftmb->Y_nonzero[y>>2][3] != 0 || mb->Y_nonzero[y>>2][0] != 0)
+ bS[0][y] = 2;
+ else
+ {
+ if (ABS(leftmb->mv_x - mb->mv_x) >= 4 || ABS(leftmb->mv_y - mb->mv_y) >= 4)
+ bS[0][y] = 1;
+ else
+ bS[0][y] = 0;
+ }
+ }
+
+ p[0] = leftmb->Y[y][15];
+ p[1] = leftmb->Y[y][14];
+ p[2] = leftmb->Y[y][13];
+ p[3] = leftmb->Y[y][12];
+ q[0] = mb->Y[y][0];
+ q[1] = mb->Y[y][1];
+ q[2] = mb->Y[y][2];
+ q[3] = mb->Y[y][3];
+
+ ff_h264_deblocking_filter_line_luma(p,q,QPYav,bS[0][y]);
+
+ leftmb->Y[y][15] = p[0];
+ leftmb->Y[y][14] = p[1];
+ leftmb->Y[y][13] = p[2];
+ mb->Y[y][0] = q[0];
+ mb->Y[y][1] = q[1];
+ mb->Y[y][2] = q[2];
+ }
+
+ // then U and V
+
+ for (y = 0 ; y < 8 ; y++)
+ {
+ p[0] = leftmb->U[y][7];
+ p[1] = leftmb->U[y][6];
+ p[2] = leftmb->U[y][5];
+ p[3] = leftmb->U[y][4];
+ q[0] = mb->U[y][0];
+ q[1] = mb->U[y][1];
+ q[2] = mb->U[y][2];
+ q[3] = mb->U[y][3];
+
+ ff_h264_deblocking_filter_line_chroma(p,q,QPCav,bS[0][y<<1]);
+
+ leftmb->U[y][7] = p[0];
+ leftmb->U[y][6] = p[1];
+ leftmb->U[y][5] = p[2];
+ mb->U[y][0] = q[0];
+ mb->U[y][1] = q[1];
+ mb->U[y][2] = q[2];
+
+ p[0] = leftmb->V[y][7];
+ p[1] = leftmb->V[y][6];
+ p[2] = leftmb->V[y][5];
+ p[3] = leftmb->V[y][4];
+ q[0] = mb->V[y][0];
+ q[1] = mb->V[y][1];
+ q[2] = mb->V[y][2];
+ q[3] = mb->V[y][3];
+
+ ff_h264_deblocking_filter_line_chroma(p,q,QPCav,bS[0][y<<1]);
+
+ leftmb->V[y][7] = p[0];
+ leftmb->V[y][6] = p[1];
+ leftmb->V[y][5] = p[2];
+ mb->V[y][0] = q[0];
+ mb->V[y][1] = q[1];
+ mb->V[y][2] = q[2];
+ }
+ }
+
+ // then the internal vertical edges
+
+ for (x = 4 ; x < 16 ; x += 4)
+ {
+ int xidx = x >> 2;
+
+ // first Y
+ for (y = 0 ; y < 16 ; y++)
+ {
+ if (isIDR)
+ bS[xidx][y] = 3;
+ else
+ {
+ if (mb->Y_nonzero[y>>2][(x>>2)-1] != 0 || mb->Y_nonzero[y>>2][x>>2] != 0)
+ bS[xidx][y] = 2;
+ else
+ {
+ // one motion vector per 16x16 block, so there will be no difference
+ // between the motion vectors
+ bS[xidx][y] = 0;
+ }
+ }
+
+ p[0] = mb->Y[y][x-1];
+ p[1] = mb->Y[y][x-2];
+ p[2] = mb->Y[y][x-3];
+ p[3] = mb->Y[y][x-4];
+ q[0] = mb->Y[y][x+0];
+ q[1] = mb->Y[y][x+1];
+ q[2] = mb->Y[y][x+2];
+ q[3] = mb->Y[y][x+3];
+
+ ff_h264_deblocking_filter_line_luma(p,q,QPYav,bS[xidx][y]);
+
+ mb->Y[y][x-1] = p[0];
+ mb->Y[y][x-2] = p[1];
+ mb->Y[y][x-3] = p[2];
+ mb->Y[y][x+0] = q[0];
+ mb->Y[y][x+1] = q[1];
+ mb->Y[y][x+2] = q[2];
+ }
+ }
+
+ // then U and V
+
+ for (y = 0 ; y < 8 ; y++)
+ {
+ p[0] = mb->U[y][3];
+ p[1] = mb->U[y][2];
+ p[2] = mb->U[y][1];
+ p[3] = mb->U[y][0];
+ q[0] = mb->U[y][4];
+ q[1] = mb->U[y][5];
+ q[2] = mb->U[y][6];
+ q[3] = mb->U[y][7];
+
+ ff_h264_deblocking_filter_line_chroma(p,q,QPCav,bS[2][y<<1]);
+
+ mb->U[y][3] = p[0];
+ mb->U[y][2] = p[1];
+ mb->U[y][1] = p[2];
+ mb->U[y][4] = q[0];
+ mb->U[y][5] = q[1];
+ mb->U[y][6] = q[2];
+
+ p[0] = mb->V[y][3];
+ p[1] = mb->V[y][2];
+ p[2] = mb->V[y][1];
+ p[3] = mb->V[y][0];
+ q[0] = mb->V[y][4];
+ q[1] = mb->V[y][5];
+ q[2] = mb->V[y][6];
+ q[3] = mb->V[y][7];
+
+ ff_h264_deblocking_filter_line_chroma(p,q,QPCav,bS[2][y<<1]);
+
+ mb->V[y][3] = p[0];
+ mb->V[y][2] = p[1];
+ mb->V[y][1] = p[2];
+ mb->V[y][4] = q[0];
+ mb->V[y][5] = q[1];
+ mb->V[y][6] = q[2];
+ }
+
+ // Next step is filtering of horizontal edges
+
+ // first, filter top edge
+
+ if (filter_top_edge)
+ {
+ MacroBlock *topmb = mb->topblock;
+
+ // first Y
+ for (x = 0 ; x < 16 ; x++)
+ {
+ if (isIDR)
+ bS[0][x] = 4;
+ else
+ {
+ if (topmb->Y_nonzero[3][x>>2] != 0 || mb->Y_nonzero[0][x>>2] != 0)
+ bS[0][x] = 2;
+ else
+ {
+ if (ABS(topmb->mv_x - mb->mv_x) >= 4 || ABS(topmb->mv_y - mb->mv_y) >= 4)
+ bS[0][x] = 1;
+ else
+ bS[0][x] = 0;
+ }
+ }
+
+ p[0] = topmb->Y[15][x];
+ p[1] = topmb->Y[14][x];
+ p[2] = topmb->Y[13][x];
+ p[3] = topmb->Y[12][x];
+ q[0] = mb->Y[0][x];
+ q[1] = mb->Y[1][x];
+ q[2] = mb->Y[2][x];
+ q[3] = mb->Y[3][x];
+
+ ff_h264_deblocking_filter_line_luma(p,q,QPYav,bS[0][x]);
+
+ topmb->Y[15][x] = p[0];
+ topmb->Y[14][x] = p[1];
+ topmb->Y[13][x] = p[2];
+ mb->Y[0][x] = q[0];
+ mb->Y[1][x] = q[1];
+ mb->Y[2][x] = q[2];
+ }
+
+ // then U and V
+
+ for (x = 0 ; x < 8 ; x++)
+ {
+ p[0] = topmb->U[7][x];
+ p[1] = topmb->U[6][x];
+ p[2] = topmb->U[5][x];
+ p[3] = topmb->U[4][x];
+ q[0] = mb->U[0][x];
+ q[1] = mb->U[1][x];
+ q[2] = mb->U[2][x];
+ q[3] = mb->U[3][x];
+
+ ff_h264_deblocking_filter_line_chroma(p,q,QPCav,bS[0][x<<1]);
+
+ topmb->U[7][x] = p[0];
+ topmb->U[6][x] = p[1];
+ topmb->U[5][x] = p[2];
+ mb->U[0][x] = q[0];
+ mb->U[1][x] = q[1];
+ mb->U[2][x] = q[2];
+
+ p[0] = topmb->V[7][x];
+ p[1] = topmb->V[6][x];
+ p[2] = topmb->V[5][x];
+ p[3] = topmb->V[4][x];
+ q[0] = mb->V[0][x];
+ q[1] = mb->V[1][x];
+ q[2] = mb->V[2][x];
+ q[3] = mb->V[3][x];
+
+ ff_h264_deblocking_filter_line_chroma(p,q,QPCav,bS[0][x<<1]);
+
+ topmb->V[7][x] = p[0];
+ topmb->V[6][x] = p[1];
+ topmb->V[5][x] = p[2];
+ mb->V[0][x] = q[0];
+ mb->V[1][x] = q[1];
+ mb->V[2][x] = q[2];
+ }
+ }
+
+ // then the internal horizontal edges
+
+ for (y = 4 ; y < 16 ; y += 4)
+ {
+ int yidx = y >> 2;
+
+ // first Y
+ for (x = 0 ; x < 16 ; x++)
+ {
+ if (isIDR)
+ bS[yidx][x] = 3;
+ else
+ {
+ if (mb->Y_nonzero[(y>>2)-1][(x>>2)] != 0 || mb->Y_nonzero[y>>2][x>>2] != 0)
+ bS[yidx][x] = 2;
+ else
+ {
+ // one motion vector per 16x16 block, so there will be no difference
+ // between the motion vectors
+ bS[yidx][x] = 0;
+ }
+ }
+
+ p[0] = mb->Y[y-1][x];
+ p[1] = mb->Y[y-2][x];
+ p[2] = mb->Y[y-3][x];
+ p[3] = mb->Y[y-4][x];
+ q[0] = mb->Y[y+0][x];
+ q[1] = mb->Y[y+1][x];
+ q[2] = mb->Y[y+2][x];
+ q[3] = mb->Y[y+3][x];
+
+ ff_h264_deblocking_filter_line_luma(p,q,QPYav,bS[yidx][x]);
+
+ mb->Y[y-1][x] = p[0];
+ mb->Y[y-2][x] = p[1];
+ mb->Y[y-3][x] = p[2];
+ mb->Y[y+0][x] = q[0];
+ mb->Y[y+1][x] = q[1];
+ mb->Y[y+2][x] = q[2];
+ }
+ }
+
+ // then U and V
+
+ for (x = 0 ; x < 8 ; x++)
+ {
+ p[0] = mb->U[3][x];
+ p[1] = mb->U[2][x];
+ p[2] = mb->U[1][x];
+ p[3] = mb->U[0][x];
+ q[0] = mb->U[4][x];
+ q[1] = mb->U[5][x];
+ q[2] = mb->U[6][x];
+ q[3] = mb->U[7][x];
+
+ ff_h264_deblocking_filter_line_chroma(p,q,QPCav,bS[2][x<<1]);
+
+ mb->U[3][x] = p[0];
+ mb->U[2][x] = p[1];
+ mb->U[1][x] = p[2];
+ mb->U[4][x] = q[0];
+ mb->U[5][x] = q[1];
+ mb->U[6][x] = q[2];
+
+ p[0] = mb->V[3][x];
+ p[1] = mb->V[2][x];
+ p[2] = mb->V[1][x];
+ p[3] = mb->V[0][x];
+ q[0] = mb->V[4][x];
+ q[1] = mb->V[5][x];
+ q[2] = mb->V[6][x];
+ q[3] = mb->V[7][x];
+
+ ff_h264_deblocking_filter_line_chroma(p,q,QPCav,bS[2][x<<1]);
+
+ mb->V[3][x] = p[0];
+ mb->V[2][x] = p[1];
+ mb->V[1][x] = p[2];
+ mb->V[4][x] = q[0];
+ mb->V[5][x] = q[1];
+ mb->V[6][x] = q[2];
+ }
+}
+
+static void ff_h264_deblock(H264Context *t, FrameInfo *frame, int isIDR, int QPYav, int QPCav)
+{
+ int y,x;
+ int w,h;
+
+ w = t->mb_width;
+ h = t->mb_height;
+
+ // for the top row, only vertical filtering is done at the edges, for the top-left block, no filtering is
+ // done at the edge
+
+ ff_h264_deblock_macroblock(&(frame->reconstructed_mb_map[0][0]),0,0,isIDR,QPYav,QPCav);
+ for (x = 1 ; x < w ; x++)
+ ff_h264_deblock_macroblock(&(frame->reconstructed_mb_map[0][x]),1,0,isIDR,QPYav,QPCav);
+ for (y = 1 ; y < h ; y++)
+ {
+ ff_h264_deblock_macroblock(&(frame->reconstructed_mb_map[y][0]),0,1,isIDR,QPYav,QPCav);
+ for (x = 1 ; x < w ; x++)
+ ff_h264_deblock_macroblock(&(frame->reconstructed_mb_map[y][x]),1,1,isIDR,QPYav,QPCav);
+ }
+}
+
+static void ff_h264_encode_Inter_16x16(H264Context *t, MacroBlock *targetmb, PutBitContext *b,
+ MacroBlock *destmb, FrameInfo **previous_frames,
+ int num_prev_frames, int mbx, int mby)
+{
+ int y,h,x,w;
+ int w2,h2;
+ int qPI;
+ int QPc;
+ int QPy = t->QP;
+ int16_t UD[2][2];
+ int16_t VD[2][2];
+ int mvx = 0;
+ int mvy = 0;
+ int pred_mvx = 0;
+ int pred_mvy = 0;
+ int pred_mvx2 = 0;
+ int pred_mvy2 = 0;
+
+ qPI = t->QP + t->chroma_qp_index_offset;
+ qPI = clip(qPI, 0, 51);
+ QPc = chroma_qp[qPI];
+
+ w = targetmb->Y_width;
+ h = targetmb->Y_height;
+ w2 = w>>1;
+ h2 = h>>1;
+
+ // Find motion vector and prediction
+
+ ff_h264_estimate_motion_vectors(destmb, &pred_mvx, &pred_mvy, &pred_mvx2, &pred_mvy2);
+ ff_h264_find_motion_vector_and_prediction(t, targetmb, previous_frames[0], mbx, mby, &mvx, &mvy,
+ pred_mvx, pred_mvy, destmb);
+
+ // Calculate residual
+
+ H264_COPY_16X16BLOCK(t->residual.part4x4Y,(int16_t)targetmb->Y,(int16_t)destmb->Y);
+ H264_COPY_8X8BLOCK(t->residual.part4x4U,(int16_t)targetmb->U,(int16_t)destmb->U);
+ H264_COPY_8X8BLOCK(t->residual.part4x4V,(int16_t)targetmb->V,(int16_t)destmb->V);
+
+ // Transform residual: DCT
+
+ for (y = 0 ; y < 4 ; y++)
+ {
+ for (x = 0 ; x < 4 ; x++)
+ {
+ t->dspcontext.h264_transform_dct_quant(t->residual.part4x4Y[y][x],QPy,0);
+ }
+ }
+ for (y = 0 ; y < 2 ; y++)
+ {
+ for (x = 0 ; x < 2 ; x++)
+ {
+ t->dspcontext.h264_transform_dct_quant(t->residual.part4x4U[y][x],QPc,1);
+ t->dspcontext.h264_transform_dct_quant(t->residual.part4x4V[y][x],QPc,1);
+ }
+ }
+ // For U
+ for (y = 0 ; y < 2 ; y++)
+ for (x = 0 ; x < 2 ; x++)
+ UD[y][x] = t->residual.part4x4U[y][x][0][0];
+ ff_h264_hadamard_mult_2x2(UD);
+ t->dspcontext.h264_hadamard_quant_2x2(UD, QPc);
+
+ // For V
+ for (y = 0 ; y < 2 ; y++)
+ for (x = 0 ; x < 2 ; x++)
+ VD[y][x] = t->residual.part4x4V[y][x][0][0];
+ ff_h264_hadamard_mult_2x2(VD);
+ t->dspcontext.h264_hadamard_quant_2x2(VD,QPc);
+
+ // Encode motion vectors, residual, ...
+
+ destmb->mv_x = mvx;
+ destmb->mv_y = mvy;
+
+ ff_h264_encode_inter16x16_residual(t, b, mvx-pred_mvx, mvy-pred_mvy, mvx-pred_mvx2, mvy-pred_mvy2,
+ &(t->residual), UD, VD, 0, destmb, (mbx == t->mb_width-1 && mby == t->mb_height-1));
+
+ // Inverse hadamard
+
+ // For U
+ ff_h264_hadamard_mult_2x2(UD);
+ ff_h264_hadamard_invquant_2x2(UD,QPc);
+ for (y = 0 ; y < 2 ; y++)
+ for (x = 0 ; x < 2 ; x++)
+ t->residual.part4x4U[y][x][0][0] = UD[y][x];
+ // For V
+ ff_h264_hadamard_mult_2x2(VD);
+ ff_h264_hadamard_invquant_2x2(VD,QPc);
+ for (y = 0 ; y < 2 ; y++)
+ for (x = 0 ; x < 2 ; x++)
+ t->residual.part4x4V[y][x][0][0] = VD[y][x];
+
+ // Inverse DCT and add
+
+ for (y = 0 ; y < 4 ; y++)
+ {
+ for (x = 0 ; x < 4 ; x++)
+ {
+ t->dspcontext.h264_transform_inverse_quant_dct_add(t->residual.part4x4Y[y][x],QPy,0,&(destmb->Y[y*4][x*4]),t->Y_stride);
+ }
+ }
+ for (y = 0 ; y < 2 ; y++)
+ {
+ for (x = 0 ; x < 2 ; x++)
+ {
+ t->dspcontext.h264_transform_inverse_quant_dct_add(t->residual.part4x4U[y][x],QPc,1,&(destmb->U[y*4][x*4]),t->V_stride);
+ t->dspcontext.h264_transform_inverse_quant_dct_add(t->residual.part4x4V[y][x],QPc,1,&(destmb->V[y*4][x*4]),t->U_stride);
+ }
+ }
+
+ destmb->available = 1;
+}
+
+static void ff_h264_control_bitrate(AVCodecContext *avctx, H264Context *t)
+{
+ if (t->blocksize_history_total_milliseconds)
+ {
+ int64_t bitrate = (t->blocksize_history_sum*1000)/t->blocksize_history_total_milliseconds;
+
+ if (avctx->bit_rate > bitrate) // increase quality
+ {
+ if (t->QP > 0)
+ t->QP--;
+ }
+ else // decrease quality
+ {
+ if (t->QP < 51)
+ t->QP++;
+ }
+ }
+}
+
+static int ff_h264_encode(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data)
+{
+ H264Context *t = (H264Context *)avctx->priv_data;
+ PutBitContext b;
+ int mbx, mby;
+ uint8_t *dest;
+ int destlen, i;
+ FrameInfo *tmp;
+ int QPy, QPc, qPI, isIDR = 0;
+
+ if (t->frame_num % t->IDRcount == 0)
+ isIDR = 1;
+
+ destlen = t->bufsize;
+ dest = t->po_data0;
+
+ // Copy the input image. Macroblocks were already assigned in the initialization step
+ img_copy(&(t->input_frame_copy),(AVPicture *)data,PIX_FMT_YUV420P,t->frame_width,t->frame_height);
+
+ // reconstructed_frames[0] will be used to reconstruct the image
+ ff_h264_clear_nonzero_markers(t->reconstructed_frames[0]->reconstructed_mb_map,t->mb_width,t->mb_height);
+
+ if (isIDR)
+ {
+ // sequence parameter set rbsp
+
+ init_put_bits(&b,t->pi_data0,t->bufsize);
+
+ put_bits(&b,8,66); // profile_idc = 66 in Baseline
+ put_bits(&b,1,0); // constraint_set0_flag
+ put_bits(&b,1,0); // constraint_set1_flag
+ put_bits(&b,1,0); // constraint_set2_flag
+ put_bits(&b,1,0); // constraint_set3_flag
+ put_bits(&b,4,0); // reserved_zero_bits
+ put_bits(&b,8,40); // level_idc, p. 262, 10*level number
+
+ set_ue_golomb(&b,0); // seq_parameter_set_id
+ set_ue_golomb(&b,2); // log2_max_frame_num_minus4
+ set_ue_golomb(&b,2); // pic_order_cnt
+ set_ue_golomb(&b,16); // num_ref_frames [0, 16] (make sure we can use enough)
+
+ put_bits(&b,1,0); // gaps_in_frame_num_value_allowed_flag
+
+ set_ue_golomb(&b,t->mb_width-1); // pic_width_in_mbs_minus1
+ set_ue_golomb(&b,t->mb_height-1); // pic_height_in_map_units_minus1
+
+ put_bits(&b, 1, 1); // frame_mbs_only_flag = 1 in Baseline
+ put_bits(&b, 1, 0); // direct_8x8_inference_flag
+ put_bits(&b, 1, t->frame_cropping_flag); // frame_cropping_flag
+
+ if (t->frame_cropping_flag)
+ {
+ set_ue_golomb(&b, t->frame_crop_left_offset);
+ set_ue_golomb(&b, t->frame_crop_right_offset);
+ set_ue_golomb(&b, t->frame_crop_top_offset);
+ set_ue_golomb(&b, t->frame_crop_bottom_offset);
+ }
+
+ put_bits(&b, 1, 0); // vui_parameters_present_flag
+ put_bits(&b, 1, 1); // rbsp_stop_one_bit
+
+ dest = ff_h264_write_nal_unit(1,NAL_SPS,dest,&destlen,&b);
+
+ // Baseline: nal_unit_type not in [2,4]
+
+ // picture parameter set
+
+ init_put_bits(&b,t->pi_data0,t->bufsize);
+
+ set_ue_golomb(&b,0); // pic_parameter_set_id
+ set_ue_golomb(&b,0); // seq_parameter_set_id
+ put_bits(&b,1,0); // entropy_coding_mode 0 = CAVLC
+ put_bits(&b,1,0); // pic_order_present_flag
+ set_ue_golomb(&b,0); // num_slice_groups_minus1 Only one slice group
+ // List0 is needed for enabling P-slices
+ set_ue_golomb(&b,0); // num_ref_idx_l0_active_minus1 Using at most the previous frame for prediction
+ set_ue_golomb(&b,0); // num_ref_idx_l1_active_minus1 Definitely not using list 1 in baseline
+ put_bits(&b,1,0); // weighted_pred_flag Is 0 in baseline
+ put_bits(&b,2,0); // weighted_bipred_idc Is 0 in baseline
+
+ set_se_golomb(&b,t->PPS_QP-26); // pic_init_qp_minus26
+ set_se_golomb(&b,0); // pic_init_qs_minus26
+
+ set_se_golomb(&b,t->chroma_qp_index_offset); // chroma_qp_index_offset
+
+ put_bits(&b,1,0); // deblocking_filter_control_present_flag
+
+ put_bits(&b,1,0); // constrained_intra_pred_flag
+ put_bits(&b,1,0); // redundant_pic_cnt_present
+
+ put_bits(&b,1,1); // rbsp_stop_one_bit
+
+ dest = ff_h264_write_nal_unit(1,NAL_PPS,dest,&destlen,&b);
+
+ }
+
+ // IDR slice or P slice
+
+ init_put_bits(&b,t->pi_data0,t->bufsize);
+
+ // Slice header
+ set_ue_golomb(&b, 0); // first_mb_in_slice
+
+ if (isIDR)
+ set_ue_golomb(&b, 7); // slice_type
+ else
+ set_ue_golomb(&b, 5); // slice_type
+ // 0: current slice is P-slice
+ // 2: current slice is I-slice
+ // 5: current and all other slices are P-slices (0 or 5)
+ // 7: current and all other slices are I-slices (2 or 7)
+
+ set_ue_golomb(&b, 0); // pic_parameter_set_id
+ put_bits(&b, 6, t->frame_num%t->IDRcount); // frame_num
+ //put_bits(&b, 4, 0); // frame_num
+ if (isIDR)
+ set_ue_golomb(&b, t->IDR_frame_num); // idr_pic_id
+ else
+ put_bits(&b, 1, 0); // num_ref_idx_active_override_flag
+
+ // dec_ref_pic_marking() ...
+ put_bits(&b, 1, 0); // no_output_of_prior_pics_flag
+ put_bits(&b, 1, 0); // long_term_reference_flag
+ // ... dec_ref_pic_marking()
+ set_se_golomb(&b, t->QP - t->PPS_QP); // slice_qp_delta
+
+ // Slice data
+
+ if (isIDR)
+ {
+ for(mby = 0; mby < t->mb_height ; mby++)
+ for(mbx = 0 ; mbx < t->mb_width ; mbx++)
+ ff_h264_encode_Intra_16x16(t,&(t->mb_map[mby][mbx]),&b,&(t->reconstructed_frames[0]->reconstructed_mb_map[mby][mbx]));
+ }
+ else // Inter encoded frame
+ {
+ t->mb_skip_run = 0;
+
+ for(mby = 0; mby < t->mb_height ; mby++)
+ for(mbx = 0 ; mbx < t->mb_width ; mbx++)
+ ff_h264_encode_Inter_16x16(t,&(t->mb_map[mby][mbx]),&b,&(t->reconstructed_frames[0]->reconstructed_mb_map[mby][mbx]),&(t->reconstructed_frames[1]),t->framebufsize-1,mbx,mby);
+ }
+
+ QPy = t->QP;
+
+ qPI = t->QP + t->chroma_qp_index_offset;
+ qPI = clip(qPI, 0, 51);
+ QPc = chroma_qp[qPI];
+
+ ff_h264_deblock(t,t->reconstructed_frames[0],isIDR,QPy,QPc);
+
+ // Trailing bits
+
+ put_bits(&b,1,1); // rbsp_stop_one_bit
+
+ if (isIDR)
+ dest = ff_h264_write_nal_unit(1,NAL_IDR_SLICE,dest,&destlen,&b);
+ else
+ dest = ff_h264_write_nal_unit(1,NAL_SLICE,dest,&destlen,&b);
+
+ // cycle frame buffer
+
+ tmp = t->reconstructed_frames[t->framebufsize-1];
+ for (i = t->framebufsize-1 ; i > 0 ; i--)
+ t->reconstructed_frames[i] = t->reconstructed_frames[i-1];
+ t->reconstructed_frames[0] = tmp;
+
+ // copy the encoded bytes
+ memcpy(buf,t->po_data0,t->bufsize-destlen);
+
+ // update history information
+ t->blocksize_history_sum -= t->blocksize_history[t->blocksize_history_pos];
+ t->blocksize_history_sum += (t->bufsize-destlen)*8;
+ t->blocksize_history[t->blocksize_history_pos] = (t->bufsize-destlen)*8;
+
+ t->blocksize_history_pos++;
+ if (t->blocksize_history_pos == t->blocksize_history_length)
+ t->blocksize_history_pos = 0;
+ if (t->blocksize_history_num_filled < t->blocksize_history_length)
+ {
+ t->blocksize_history_num_filled++;
+ t->blocksize_history_total_milliseconds += t->milliseconds_per_frame;
+ }
+
+ if (!t->use_fixed_qp)
+ ff_h264_control_bitrate(avctx,t);
+
+ // adjust frame numbers
+ t->frame_num++;
+ if (isIDR)
+ t->IDR_frame_num++;
+ return (t->bufsize-destlen);
+}
+
+static int ff_h264_encoder_close(AVCodecContext *avctx)
+{
+ PutBitContext b;
+ H264Context *t = (H264Context *)avctx->priv_data;
+ uint8_t *dest;
+ int destlen;
+ int y,i;
+
+ destlen = t->bufsize;
+ dest = t->po_data0;
+
+ init_put_bits(&b,t->pi_data0,t->bufsize);
+
+ // write end of stream
+
+ dest = ff_h264_write_nal_unit(0,NAL_END_STREAM,dest,&destlen,&b);
+
+ *dest = 0;
+ dest++;
+ destlen--;
+
+ // clean up
+
+ avpicture_free(&t->pi);
+ avpicture_free(&t->po);
+
+ for (y = 0 ; y < t->mb_height ; y++)
+ av_free(t->mb_map[y]);
+
+ av_free(t->mb_map);
+
+ for (i = 0 ; i < t->framebufsize ; i++)
+ {
+ av_free(t->reconstructed_frames[i]->reconstructed_picture.data[0]);
+
+ for (y = 0 ; y < t->mb_height ; y++)
+ av_free(t->reconstructed_frames[i]->reconstructed_mb_map[y]);
+
+ av_free(t->reconstructed_frames[i]->reconstructed_mb_map);
+ av_free(t->reconstructed_frames[i]);
+ }
+
+ av_free(t->reconstructed_frames);
+
+ av_free(t->input_frame_copy.data[0]);
+
+ av_free(t->blocksize_history);
+
+ return 0;
+}
+
+#ifdef CONFIG_ENCODERS
+AVCodec h264_encoder = {
+ "ffh264",
+ CODEC_TYPE_VIDEO,
+ CODEC_ID_FFH264,
+ sizeof(H264Context),
+ ff_h264_encoder_init,
+ ff_h264_encode,
+ ff_h264_encoder_close,
+ .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1},
+};
+#endif
+
diff --git a/libavcodec/h264enc.h b/libavcodec/h264enc.h
new file mode 100644
index 0000000..c962618
--- /dev/null
+++ b/libavcodec/h264enc.h
@@ -0,0 +1,105 @@
+/*
+ * H.264 encoder
+ * Copyright (c) 2006 Expertisecentrum Digitale Media, UHasselt
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "h264encdata.h"
+
+/**
+ * Can contain pointers to the relevant starting points in a picture
+ */
+typedef struct MacroBlock
+{
+ uint8_t *Y[16];
+ uint8_t *U[8];
+ uint8_t *V[8];
+ int Y_width;
+ int Y_height;
+ int Y_nonzero[4][4]; ///< y,x
+ int U_nonzero[2][2];
+ int V_nonzero[2][2];
+ struct MacroBlock *leftblock,*topblock,*rightblock;
+ int available;
+ int mv_x;
+ int mv_y;
+} MacroBlock;
+
+typedef struct Residual
+{
+ int16_t part4x4Y[4][4][4][4]; ///< ypos and xpos of 4x4 part, followed by y,x of pixel
+ int16_t part4x4U[2][2][4][4]; ///< ypos and xpos of 4x4 part, followed by y,x of pixel
+ int16_t part4x4V[2][2][4][4]; ///< ypos and xpos of 4x4 part, followed by y,x of pixel
+} Residual;
+
+typedef struct FrameInfo
+{
+ AVPicture reconstructed_picture;
+ MacroBlock **reconstructed_mb_map; ///< macroblock map of reconstructed picture
+} FrameInfo;
+
+typedef struct H264Context
+{
+ uint8_t *pi_data0;
+ uint8_t *po_data0;
+ int bufsize;
+ int frame_num;
+ int IDR_frame_num;
+ MacroBlock **mb_map; ///< macroblock map for input picture
+ FrameInfo **reconstructed_frames;
+ int framebufsize; ///< length of previous array
+ int mb_width; ///< width in macroblocks
+ int mb_height; ///< height in macroblock
+ int QP;
+ int PPS_QP; //< The QP value stored in the picture parameter set
+ int chroma_qp_index_offset;
+ int IDRcount;
+ int frame_cropping_flag;
+ int frame_crop_left_offset;
+ int frame_crop_right_offset;
+ int frame_crop_top_offset;
+ int frame_crop_bottom_offset;
+ Residual residual;
+
+ MpegEncContext s;
+ AVPicture pi, po;
+
+ DSPContext dspcontext;
+ int Y_stride;
+ int U_stride;
+ int V_stride;
+
+ int frame_width;
+ int frame_height;
+ int refframe_width;
+ int refframe_height;
+
+ AVPicture input_frame_copy; ///< buffer to hold copy of input frame
+ int mb_skip_run;
+
+ int64_t *blocksize_history;
+ int blocksize_history_length;
+ int blocksize_history_total_milliseconds;
+ int milliseconds_per_frame;
+ int blocksize_history_pos;
+ int blocksize_history_num_filled;
+ int64_t blocksize_history_sum;
+
+ int use_fixed_qp;
+
+} H264Context;
+
+
diff --git a/libavcodec/h264encdata.h b/libavcodec/h264encdata.h
new file mode 100644
index 0000000..93bb647
--- /dev/null
+++ b/libavcodec/h264encdata.h
@@ -0,0 +1,110 @@
+/*
+ * H.264 encoder
+ * Copyright (c) 2006 Expertisecentrum Digitale Media, UHasselt
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define MVTABLE_OFFSET (128*4)
+
+static const char mv_len_table[MVTABLE_OFFSET*2+1] =
+{
+ 21,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,9,9,9,9,9,9,9,9,7,7,7,7,5,
+ 5,3,1,3,5,5,7,7,7,7,9,9,9,9,9,
+ 9,9,9,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,21
+};
+
+static const int sae_codeblocksize_relation[13][8] = {
+{55,1590,1796,1865,1925,1977,2010,2021},
+{27,1328,1525,1593,1649,1699,1729,1741},
+{20,1097,1288,1353,1405,1449,1479,1485},
+{17,878,1063,1130,1177,1217,1244,1250},
+{16,667,875,945,992,1027,1051,1055},
+{18,491,704,790,835,869,891,895},
+{0,352,538,658,718,747,769,774},
+{0,243,398,500,561,643,672,683},
+{0,163,278,363,446,487,518,568},
+{0,98,197,259,313,368,425,453},
+{0,53,133,186,224,259,293,326},
+{0,22,81,126,162,188,210,231},
+{0,14,47,79,106,135,156,173}
+};
+
diff --git a/tests/Makefile b/tests/Makefile
index 835fab6..892484a 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -20,7 +20,7 @@ test-server: vsynth1/0.pgm asynth1.sw
@$(VPATH)/server-regression.sh $(SERVER_REFFILE) $(VPATH)/test.conf
# fast regression tests for all codecs
-codectest mpeg4 mpeg ac3 snow snowll: vsynth1/0.pgm vsynth2/0.pgm asynth1.sw tiny_psnr$(EXESUF)
+codectest mpeg4 mpeg ac3 snow snowll ffh264: vsynth1/0.pgm vsynth2/0.pgm asynth1.sw tiny_psnr$(EXESUF)
@$(VPATH)/regression.sh $@ $(REFFILE1) vsynth1
@$(VPATH)/regression.sh $@ $(REFFILE2) vsynth2
diff --git a/tests/ffmpeg.regression.ref b/tests/ffmpeg.regression.ref
index 1aec954..3cf62d7 100644
--- a/tests/ffmpeg.regression.ref
+++ b/tests/ffmpeg.regression.ref
@@ -59,6 +59,10 @@ stddev: 8.08 PSNR:29.97 bytes:7602176
2415378 ./data/a-h263p.avi
28fd12ac0b168252d81df6f6e60a5d17 *./data/out.yuv
stddev: 2.07 PSNR:41.76 bytes:7602176
+5b4fae455aa041e99d3467f2a67dd76b *./data/a-ffh264.mp4
+3014465 ./data/a-ffh264.mp4
+ba88c2a8e9bba81581dea8c1bbc03ad5 *./data/out.yuv
+stddev: 0.68 PSNR:51.39 bytes:7602176
d84b65558cd386064ab7a126d66c4744 *./data/a-odivx.mp4
554499 ./data/a-odivx.mp4
57aed19df5cbada4b05991527ee72ebe *./data/out.yuv
diff --git a/tests/regression.sh b/tests/regression.sh
index 9ded777..1e1663d 100755
--- a/tests/regression.sh
+++ b/tests/regression.sh
@@ -40,6 +40,8 @@ elif [ "$1" = "snow" ] ; then
do_snow=y
elif [ "$1" = "snowll" ] ; then
do_snowll=y
+elif [ "$1" = "ffh264" ] ; then
+ do_ffh264=y
elif [ "$1" = "libavtest" ] ; then
do_libav=y
logfile="$datadir/libav.regression"
@@ -82,6 +84,7 @@ else
do_svq1=y
do_snow=y
do_snowll=y
+ do_ffh264=y
do_adpcm_yam=y
do_dv=y
do_dv50=y
@@ -297,6 +300,16 @@ do_ffmpeg $raw_dst -y -i $file -f rawvid
fi
###################################
+if [ -n "$do_ffh264" ] ; then
+# h264 encoding
+file=${outfile}ffh264.mp4
+do_ffmpeg $file -y -qscale 10 -f pgmyuv -i $raw_src -an -vcodec ffh264 -vtag avc1 $file
+
+# h264 decoding
+do_ffmpeg $raw_dst -y -i $file -f rawvideo $raw_dst
+fi
+
+###################################
if [ -n "$do_mpeg4" ] ; then
# mpeg4
file=${outfile}odivx.mp4
diff --git a/tests/rotozoom.regression.ref b/tests/rotozoom.regression.ref
index 5652f2d..1a80264 100644
--- a/tests/rotozoom.regression.ref
+++ b/tests/rotozoom.regression.ref
@@ -59,6 +59,10 @@ stddev: 5.44 PSNR:33.41 bytes:7602176
869200 ./data/a-h263p.avi
80fb224bebbe2e04f228da7485b905c5 *./data/out.yuv
stddev: 1.91 PSNR:42.49 bytes:7602176
+f42c060a951e4711a1bcf91b06936021 *./data/a-ffh264.mp4
+2219112 ./data/a-ffh264.mp4
+c390adcb2747e35c4aaef623d1e17837 *./data/out.yuv
+stddev: 0.71 PSNR:51.06 bytes:7602176
286c5a5fca0d3e17ba6ede970b8318b8 *./data/a-odivx.mp4
120150 ./data/a-odivx.mp4
e8c90899c32e11e7e4d1354dab0b8f28 *./data/out.yuv
More information about the ffmpeg-devel
mailing list