H.264 lossless mode
[ffmpeg.git] / libavcodec / h264.c
index 977ce5f..f9c0bfc 100644 (file)
@@ -61,6 +61,7 @@ typedef struct SPS{
     
     int profile_idc;
     int level_idc;
+    int transform_bypass;              ///< qpprime_y_zero_transform_bypass_flag
     int log2_max_frame_num;            ///< log2_max_frame_num_minus4 + 4
     int poc_type;                      ///< pic_order_cnt_type
     int log2_max_poc_lsb;              ///< log2_max_pic_order_cnt_lsb_minus4
@@ -236,6 +237,7 @@ typedef struct H264Context{
      */
     PPS pps; //FIXME move to Picture perhaps? (->no) do we need that?
 
+    uint16_t (*dequant4_coeff)[16]; // FIXME quant matrices should be per SPS or PPS
     uint16_t (*dequant8_coeff)[64];
 
     int slice_num;
@@ -344,6 +346,8 @@ typedef struct H264Context{
 
     uint8_t zigzag_scan[16];
     uint8_t field_scan[16];
+    const uint8_t *zigzag_scan_q0;
+    const uint8_t *field_scan_q0;
 }H264Context;
 
 static VLC coeff_token_vlc[4];
@@ -2904,6 +2908,7 @@ static void free_tables(H264Context *h){
     av_freep(&h->mb2b_xy);
     av_freep(&h->mb2b8_xy);
 
+    av_freep(&h->dequant4_coeff);
     av_freep(&h->dequant8_coeff);
 
     av_freep(&h->s.obmc_scratchpad);
@@ -2949,7 +2954,9 @@ static int alloc_tables(H264Context *h){
         }
     }
 
+    CHECKED_ALLOCZ(h->dequant4_coeff, 52*16 * sizeof(uint16_t));
     CHECKED_ALLOCZ(h->dequant8_coeff, 52*64 * sizeof(uint16_t));
+    memcpy(h->dequant4_coeff, dequant_coeff, 52*16 * sizeof(uint16_t));
     for(q=0; q<52; q++){
         int shift = div6[q];
         int idx = rem6[q];
@@ -2959,6 +2966,12 @@ static int alloc_tables(H264Context *h){
             h->dequant8_coeff[q][x] = dequant8_coeff_init[idx][
                 dequant8_coeff_init_scan[(x>>1)&12 | x&3] ] << shift;
     }
+    if(h->sps.transform_bypass){
+        for(x=0; x<16; x++)
+            h->dequant4_coeff[0][x] = 1;
+        for(x=0; x<64; x++)
+            h->dequant8_coeff[0][x] = 1<<2;
+    }
 
     s->obmc_scratchpad = NULL;
 
@@ -3210,6 +3223,8 @@ static void hl_decode_mb(H264Context *h){
     int i;
     int *block_offset = &h->block_offset[0];
     const unsigned int bottom = mb_y & 1;
+    const int transform_bypass = (s->qscale == 0 && h->sps.transform_bypass);
+    void (*idct_add)(uint8_t *dst, DCTELEM *block, int stride);
 
     if(!s->decode)
         return;
@@ -3232,6 +3247,10 @@ static void hl_decode_mb(H264Context *h){
         uvlinesize = s->uvlinesize;
 //        dct_offset = s->linesize * 16;
     }
+    
+    idct_add = transform_bypass
+             ? IS_8x8DCT(mb_type) ? s->dsp.add_pixels8 : s->dsp.add_pixels4
+             : IS_8x8DCT(mb_type) ? s->dsp.h264_idct8_add : s->dsp.h264_idct_add;
 
     if (IS_INTRA_PCM(mb_type)) {
         unsigned int x, y;
@@ -3284,7 +3303,7 @@ static void hl_decode_mb(H264Context *h){
                             h->pred8x8l[ dir ](ptr, (h->topleft_samples_available<<i)&0x8000,
                                                    (h->topright_samples_available<<(i+1))&0x8000, linesize);
                             if(h->non_zero_count_cache[ scan8[i] ])
-                                s->dsp.h264_idct8_add(ptr, h->mb + i*16, linesize);
+                                idct_add(ptr, h->mb + i*16, linesize);
                         }
                     }else
                     for(i=0; i<16; i++){
@@ -3307,7 +3326,7 @@ static void hl_decode_mb(H264Context *h){
                         h->pred4x4[ dir ](ptr, topright, linesize);
                         if(h->non_zero_count_cache[ scan8[i] ]){
                             if(s->codec_id == CODEC_ID_H264)
-                                s->dsp.h264_idct_add(ptr, h->mb + i*16, linesize);
+                                idct_add(ptr, h->mb + i*16, linesize);
                             else
                                 svq3_add_idct_c(ptr, h->mb + i*16, linesize, s->qscale, 0);
                         }
@@ -3315,9 +3334,10 @@ static void hl_decode_mb(H264Context *h){
                 }
             }else{
                 h->pred16x16[ h->intra16x16_pred_mode ](dest_y , linesize);
-                if(s->codec_id == CODEC_ID_H264)
-                    h264_luma_dc_dequant_idct_c(h->mb, s->qscale);
-                else
+                if(s->codec_id == CODEC_ID_H264){
+                    if(!transform_bypass)
+                        h264_luma_dc_dequant_idct_c(h->mb, s->qscale);
+                }else
                     svq3_luma_dc_dequant_idct_c(h->mb, s->qscale);
             }
             if(h->deblocking_filter) {
@@ -3345,12 +3365,10 @@ static void hl_decode_mb(H264Context *h){
         if(!IS_INTRA4x4(mb_type)){
             if(s->codec_id == CODEC_ID_H264){
                 const int di = IS_8x8DCT(mb_type) ? 4 : 1;
-                void (*idct)(uint8_t *dst, DCTELEM *block, int stride) =
-                    IS_8x8DCT(mb_type) ? s->dsp.h264_idct8_add : s->dsp.h264_idct_add;
                 for(i=0; i<16; i+=di){
                     if(h->non_zero_count_cache[ scan8[i] ] || h->mb[i*16]){ //FIXME benchmark weird rule, & below
                         uint8_t * const ptr= dest_y + block_offset[i];
-                        idct(ptr, h->mb + i*16, linesize);
+                        idct_add(ptr, h->mb + i*16, linesize);
                     }
                 }
             }else{
@@ -3364,19 +3382,22 @@ static void hl_decode_mb(H264Context *h){
         }
 
         if(!(s->flags&CODEC_FLAG_GRAY)){
-            chroma_dc_dequant_idct_c(h->mb + 16*16, h->chroma_qp);
-            chroma_dc_dequant_idct_c(h->mb + 16*16+4*16, h->chroma_qp);
+            idct_add = transform_bypass ? s->dsp.add_pixels4 : s->dsp.h264_idct_add;
+            if(!transform_bypass){
+                chroma_dc_dequant_idct_c(h->mb + 16*16, h->chroma_qp);
+                chroma_dc_dequant_idct_c(h->mb + 16*16+4*16, h->chroma_qp);
+            }
             if(s->codec_id == CODEC_ID_H264){
                 for(i=16; i<16+4; i++){
                     if(h->non_zero_count_cache[ scan8[i] ] || h->mb[i*16]){
                         uint8_t * const ptr= dest_cb + block_offset[i];
-                        s->dsp.h264_idct_add(ptr, h->mb + i*16, uvlinesize);
+                        idct_add(ptr, h->mb + i*16, uvlinesize);
                     }
                 }
                 for(i=20; i<20+4; i++){
                     if(h->non_zero_count_cache[ scan8[i] ] || h->mb[i*16]){
                         uint8_t * const ptr= dest_cr + block_offset[i];
-                        s->dsp.h264_idct_add(ptr, h->mb + i*16, uvlinesize);
+                        idct_add(ptr, h->mb + i*16, uvlinesize);
                     }
                 }
             }else{
@@ -4173,6 +4194,13 @@ static int decode_slice_header(H264Context *h){
                 h-> field_scan[i] = T( field_scan[i]);
             }
         }
+        if(h->sps.transform_bypass){ //FIXME same ugly
+            h->zigzag_scan_q0 = zigzag_scan;
+            h->field_scan_q0 = field_scan;
+        }else{
+            h->zigzag_scan_q0 = h->zigzag_scan;
+            h->field_scan_q0 = h->field_scan;
+        }
 
         alloc_tables(h);
 
@@ -4921,10 +4949,10 @@ decode_intra_mb:
 //        fill_non_zero_count_cache(h);
 
         if(IS_INTERLACED(mb_type)){
-            scan= h->field_scan;
+            scan= s->qscale ? h->field_scan : h->field_scan_q0;
             dc_scan= luma_dc_field_scan;
         }else{
-            scan= h->zigzag_scan;
+            scan= s->qscale ? h->zigzag_scan : h->zigzag_scan_q0;
             dc_scan= luma_dc_zigzag_scan;
         }
 
@@ -4943,7 +4971,7 @@ decode_intra_mb:
         
         h->chroma_qp= chroma_qp= get_chroma_qp(h->pps.chroma_qp_index_offset, s->qscale);
         if(IS_INTRA16x16(mb_type)){
-            if( decode_residual(h, h->intra_gb_ptr, h->mb, LUMA_DC_BLOCK_INDEX, dc_scan, dequant_coeff[s->qscale], 16) < 0){
+            if( decode_residual(h, h->intra_gb_ptr, h->mb, LUMA_DC_BLOCK_INDEX, dc_scan, h->dequant4_coeff[s->qscale], 16) < 0){
                 return -1; //FIXME continue if partitioned and other return -1 too
             }
 
@@ -4953,7 +4981,7 @@ decode_intra_mb:
                 for(i8x8=0; i8x8<4; i8x8++){
                     for(i4x4=0; i4x4<4; i4x4++){
                         const int index= i4x4 + 4*i8x8;
-                        if( decode_residual(h, h->intra_gb_ptr, h->mb + 16*index, index, scan + 1, dequant_coeff[s->qscale], 15) < 0 ){
+                        if( decode_residual(h, h->intra_gb_ptr, h->mb + 16*index, index, scan + 1, h->dequant4_coeff[s->qscale], 15) < 0 ){
                             return -1;
                         }
                     }
@@ -4983,7 +5011,7 @@ decode_intra_mb:
                         for(i4x4=0; i4x4<4; i4x4++){
                             const int index= i4x4 + 4*i8x8;
                         
-                            if( decode_residual(h, gb, h->mb + 16*index, index, scan, dequant_coeff[s->qscale], 16) <0 ){
+                            if( decode_residual(h, gb, h->mb + 16*index, index, scan, h->dequant4_coeff[s->qscale], 16) <0 ){
                                 return -1;
                             }
                         }
@@ -4997,7 +5025,7 @@ decode_intra_mb:
         
         if(cbp&0x30){
             for(chroma_idx=0; chroma_idx<2; chroma_idx++)
-                if( decode_residual(h, gb, h->mb + 256 + 16*4*chroma_idx, CHROMA_DC_BLOCK_INDEX, chroma_dc_scan, dequant_coeff[chroma_qp], 4) < 0){
+                if( decode_residual(h, gb, h->mb + 256 + 16*4*chroma_idx, CHROMA_DC_BLOCK_INDEX, chroma_dc_scan, h->dequant4_coeff[chroma_qp], 4) < 0){
                     return -1;
                 }
         }
@@ -5006,7 +5034,7 @@ decode_intra_mb:
             for(chroma_idx=0; chroma_idx<2; chroma_idx++){
                 for(i4x4=0; i4x4<4; i4x4++){
                     const int index= 16 + 4*chroma_idx + i4x4;
-                    if( decode_residual(h, gb, h->mb + 16*index, index, scan + 1, dequant_coeff[chroma_qp], 15) < 0){
+                    if( decode_residual(h, gb, h->mb + 16*index, index, scan + 1, h->dequant4_coeff[chroma_qp], 15) < 0){
                         return -1;
                     }
                 }
@@ -5980,10 +6008,10 @@ decode_intra_mb:
         int dqp;
 
         if(IS_INTERLACED(mb_type)){
-            scan= h->field_scan;
+            scan= s->qscale ? h->field_scan : h->field_scan_q0;
             dc_scan= luma_dc_field_scan;
         }else{
-            scan= h->zigzag_scan;
+            scan= s->qscale ? h->zigzag_scan : h->zigzag_scan_q0;
             dc_scan= luma_dc_zigzag_scan;
         }
 
@@ -5998,12 +6026,12 @@ decode_intra_mb:
         if( IS_INTRA16x16( mb_type ) ) {
             int i;
             //av_log( s->avctx, AV_LOG_ERROR, "INTRA16x16 DC\n" );
-            if( decode_cabac_residual( h, h->mb, 0, 0, dc_scan, dequant_coeff[s->qscale], 16) < 0)
+            if( decode_cabac_residual( h, h->mb, 0, 0, dc_scan, h->dequant4_coeff[s->qscale], 16) < 0)
                 return -1;
             if( cbp&15 ) {
                 for( i = 0; i < 16; i++ ) {
                     //av_log( s->avctx, AV_LOG_ERROR, "INTRA16x16 AC:%d\n", i );
-                    if( decode_cabac_residual(h, h->mb + 16*i, 1, i, scan + 1, dequant_coeff[s->qscale], 15) < 0 )
+                    if( decode_cabac_residual(h, h->mb + 16*i, 1, i, scan + 1, h->dequant4_coeff[s->qscale], 15) < 0 )
                         return -1;
                 }
             } else {
@@ -6026,7 +6054,7 @@ decode_intra_mb:
                     for( i4x4 = 0; i4x4 < 4; i4x4++ ) {
                         const int index = 4*i8x8 + i4x4;
                         //av_log( s->avctx, AV_LOG_ERROR, "Luma4x4: %d\n", index );
-                        if( decode_cabac_residual(h, h->mb + 16*index, 2, index, scan, dequant_coeff[s->qscale], 16) < 0 )
+                        if( decode_cabac_residual(h, h->mb + 16*index, 2, index, scan, h->dequant4_coeff[s->qscale], 16) < 0 )
                             return -1;
                     }
                 } else {
@@ -6040,7 +6068,7 @@ decode_intra_mb:
             int c;
             for( c = 0; c < 2; c++ ) {
                 //av_log( s->avctx, AV_LOG_ERROR, "INTRA C%d-DC\n",c );
-                if( decode_cabac_residual(h, h->mb + 256 + 16*4*c, 3, c, chroma_dc_scan, dequant_coeff[h->chroma_qp], 4) < 0)
+                if( decode_cabac_residual(h, h->mb + 256 + 16*4*c, 3, c, chroma_dc_scan, h->dequant4_coeff[h->chroma_qp], 4) < 0)
                     return -1;
             }
         }
@@ -6051,7 +6079,7 @@ decode_intra_mb:
                 for( i = 0; i < 4; i++ ) {
                     const int index = 16 + 4 * c + i;
                     //av_log( s->avctx, AV_LOG_ERROR, "INTRA C%d-AC %d\n",c, index - 16 );
-                    if( decode_cabac_residual(h, h->mb + 16*index, 4, index - 16, scan + 1, dequant_coeff[h->chroma_qp], 15) < 0)
+                    if( decode_cabac_residual(h, h->mb + 16*index, 4, index - 16, scan + 1, h->dequant4_coeff[h->chroma_qp], 15) < 0)
                         return -1;
                 }
             }
@@ -6897,7 +6925,7 @@ static inline int decode_seq_parameter_set(H264Context *h){
             get_bits1(&s->gb);  //residual_color_transform_flag
         get_ue_golomb(&s->gb);  //bit_depth_luma_minus8
         get_ue_golomb(&s->gb);  //bit_depth_chroma_minus8
-        get_bits1(&s->gb);      //qpprime_y_zero_transform_bypass_flag
+        sps->transform_bypass = get_bits1(&s->gb);
         if(get_bits1(&s->gb)){  //seq_scaling_matrix_present_flag
             av_log(h->s.avctx, AV_LOG_ERROR, "custom scaling matrix not implemented\n");
             return -1;