]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/mpeg12.c
parse aac extradata to fetch channels and sample rate, patch from Netgem
[ffmpeg] / libavcodec / mpeg12.c
index 0f9f649c9a37784e15c43097984a54af5055d9e7..6cf03356dea77d105a4c13bf3ec1d448255164f3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * MPEG-1/2 decoder
- * Copyright (c) 2000,2001 Fabrice Bellard.
+ * Copyright (c) 2000,2001 Fabrice Bellard
  * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
  *
  * This file is part of FFmpeg.
@@ -21,7 +21,7 @@
  */
 
 /**
- * @file mpeg12.c
+ * @file libavcodec/mpeg12.c
  * MPEG-1/2 decoder
  */
 
@@ -34,6 +34,8 @@
 #include "mpeg12data.h"
 #include "mpeg12decdata.h"
 #include "bytestream.h"
+#include "vdpau_internal.h"
+#include "xvmc_internal.h"
 
 //#undef NDEBUG
 //#include <assert.h>
@@ -48,9 +50,6 @@
 static inline int mpeg1_decode_block_inter(MpegEncContext *s,
                               DCTELEM *block,
                               int n);
-static inline int mpeg1_decode_block_intra(MpegEncContext *s,
-                              DCTELEM *block,
-                              int n);
 static inline int mpeg1_fast_decode_block_inter(MpegEncContext *s, DCTELEM *block, int n);
 static inline int mpeg2_decode_block_non_intra(MpegEncContext *s,
                                         DCTELEM *block,
@@ -63,14 +62,6 @@ static inline int mpeg2_fast_decode_block_intra(MpegEncContext *s, DCTELEM *bloc
 static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred);
 static void exchange_uv(MpegEncContext *s);
 
-extern int XVMC_field_start(MpegEncContext *s, AVCodecContext *avctx);
-extern int XVMC_field_end(MpegEncContext *s);
-extern void XVMC_pack_pblocks(MpegEncContext *s,int cbp);
-extern void XVMC_init_block(MpegEncContext *s);//set s->block
-
-static const enum PixelFormat pixfmt_yuv_420[]= {PIX_FMT_YUV420P,PIX_FMT_NONE};
-static const enum PixelFormat pixfmt_yuv_422[]= {PIX_FMT_YUV422P,PIX_FMT_NONE};
-static const enum PixelFormat pixfmt_yuv_444[]= {PIX_FMT_YUV444P,PIX_FMT_NONE};
 static const enum PixelFormat pixfmt_xvmc_mpg2_420[] = {
                                            PIX_FMT_XVMC_MPEG2_IDCT,
                                            PIX_FMT_XVMC_MPEG2_MC,
@@ -148,7 +139,7 @@ static VLC mb_ptype_vlc;
 static VLC mb_btype_vlc;
 static VLC mb_pat_vlc;
 
-av_cold void ff_init_vlcs(void)
+av_cold void ff_mpeg12_init_vlcs(void)
 {
     static int done = 0;
 
@@ -306,15 +297,13 @@ static int mpeg_decode_mb(MpegEncContext *s,
         }else
             memset(s->last_mv, 0, sizeof(s->last_mv)); /* reset mv prediction */
         s->mb_intra = 1;
-#ifdef HAVE_XVMC
         //if 1, we memcpy blocks in xvmcvideo
-        if(s->avctx->xvmc_acceleration > 1){
-            XVMC_pack_pblocks(s,-1);//inter are always full blocks
+        if(CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration > 1){
+            ff_xvmc_pack_pblocks(s,-1);//inter are always full blocks
             if(s->swap_uv){
                 exchange_uv(s);
             }
         }
-#endif
 
         if (s->codec_id == CODEC_ID_MPEG2VIDEO) {
             if(s->flags2 & CODEC_FLAG2_FAST){
@@ -329,7 +318,7 @@ static int mpeg_decode_mb(MpegEncContext *s,
             }
         } else {
             for(i=0;i<6;i++) {
-                if (mpeg1_decode_block_intra(s, s->pblocks[i], i) < 0)
+                if (ff_mpeg1_decode_block_intra(s, s->pblocks[i], i) < 0)
                     return -1;
             }
         }
@@ -519,15 +508,13 @@ static int mpeg_decode_mb(MpegEncContext *s,
                 return -1;
             }
 
-#ifdef HAVE_XVMC
             //if 1, we memcpy blocks in xvmcvideo
-            if(s->avctx->xvmc_acceleration > 1){
-                XVMC_pack_pblocks(s,cbp);
+            if(CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration > 1){
+                ff_xvmc_pack_pblocks(s,cbp);
                 if(s->swap_uv){
                     exchange_uv(s);
                 }
             }
-#endif
 
             if (s->codec_id == CODEC_ID_MPEG2VIDEO) {
                 if(s->flags2 & CODEC_FLAG2_FAST){
@@ -616,7 +603,7 @@ static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred)
     return val;
 }
 
-static inline int mpeg1_decode_block_intra(MpegEncContext *s,
+inline int ff_mpeg1_decode_block_intra(MpegEncContext *s,
                                DCTELEM *block,
                                int n)
 {
@@ -635,7 +622,7 @@ static inline int mpeg1_decode_block_intra(MpegEncContext *s,
     dc = s->last_dc[component];
     dc += diff;
     s->last_dc[component] = dc;
-    block[0] = dc<<3;
+    block[0] = dc*quant_matrix[0];
     dprintf(s->avctx, "dc=%d diff=%d\n", dc, diff);
     i = 0;
     {
@@ -1194,7 +1181,7 @@ static av_cold int mpeg_decode_init(AVCodecContext *avctx)
     s->mpeg_enc_ctx.flags= avctx->flags;
     s->mpeg_enc_ctx.flags2= avctx->flags2;
     ff_mpeg12_common_init(&s->mpeg_enc_ctx);
-    ff_init_vlcs();
+    ff_mpeg12_init_vlcs();
 
     s->mpeg_enc_ctx_allocated = 0;
     s->mpeg_enc_ctx.picture_number = 0;
@@ -1215,6 +1202,27 @@ static void quant_matrix_rebuild(uint16_t *matrix, const uint8_t *old_perm,
     }
 }
 
+static enum PixelFormat mpeg_get_pixelformat(AVCodecContext *avctx){
+    Mpeg1Context *s1 = avctx->priv_data;
+    MpegEncContext *s = &s1->mpeg_enc_ctx;
+
+    if(avctx->xvmc_acceleration)
+        return avctx->get_format(avctx,pixfmt_xvmc_mpg2_420);
+    else if(avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU){
+        if(avctx->codec_id == CODEC_ID_MPEG1VIDEO)
+            return PIX_FMT_VDPAU_MPEG1;
+        else
+            return PIX_FMT_VDPAU_MPEG2;
+    }else{
+        if(s->chroma_format <  2)
+            return PIX_FMT_YUV420P;
+        else if(s->chroma_format == 2)
+            return PIX_FMT_YUV422P;
+        else
+            return PIX_FMT_YUV444P;
+    }
+}
+
 /* Call this function when we know all parameters.
  * It may be called in different places for MPEG-1 and MPEG-2. */
 static int mpeg_decode_postinit(AVCodecContext *avctx){
@@ -1252,7 +1260,8 @@ static int mpeg_decode_postinit(AVCodecContext *avctx){
          * that behave like P-frames. */
         avctx->has_b_frames = !(s->low_delay);
 
-        if(avctx->sub_id==1){//s->codec_id==avctx->codec_id==CODEC_ID
+        assert((avctx->sub_id==1) == (avctx->codec_id==CODEC_ID_MPEG1VIDEO));
+        if(avctx->codec_id==CODEC_ID_MPEG1VIDEO){
             //MPEG-1 fps
             avctx->time_base.den= ff_frame_rate_tab[s->frame_rate_index].num;
             avctx->time_base.num= ff_frame_rate_tab[s->frame_rate_index].den;
@@ -1270,7 +1279,9 @@ static int mpeg_decode_postinit(AVCodecContext *avctx){
                 1<<30);
         //MPEG-2 aspect
             if(s->aspect_ratio_info > 1){
-                if( (s1->pan_scan.width == 0 )||(s1->pan_scan.height == 0) ){
+                //we ignore the spec here as reality does not match the spec, see for example
+                // res_change_ffmpeg_aspect.ts and sequence-display-aspect.mpg
+                if( (s1->pan_scan.width == 0 )||(s1->pan_scan.height == 0) || 1){
                     s->avctx->sample_aspect_ratio=
                         av_div_q(
                          ff_mpeg2_aspect[s->aspect_ratio_info],
@@ -1289,21 +1300,10 @@ static int mpeg_decode_postinit(AVCodecContext *avctx){
             }
         }//MPEG-2
 
-        if(avctx->xvmc_acceleration){
-            avctx->pix_fmt = avctx->get_format(avctx,pixfmt_xvmc_mpg2_420);
-        }else{
-            if(s->chroma_format <  2){
-                avctx->pix_fmt = avctx->get_format(avctx,pixfmt_yuv_420);
-            }else
-            if(s->chroma_format == 2){
-                avctx->pix_fmt = avctx->get_format(avctx,pixfmt_yuv_422);
-            }else
-            if(s->chroma_format >  2){
-                avctx->pix_fmt = avctx->get_format(avctx,pixfmt_yuv_444);
-            }
-        }
+        avctx->pix_fmt = mpeg_get_pixelformat(avctx);
         //until then pix_fmt may be changed right after codec init
-        if( avctx->pix_fmt == PIX_FMT_XVMC_MPEG2_IDCT )
+        if( avctx->pix_fmt == PIX_FMT_XVMC_MPEG2_IDCT ||
+            s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU )
             if( avctx->idct_algo == FF_IDCT_AUTO )
                 avctx->idct_algo = FF_IDCT_SIMPLE;
 
@@ -1345,7 +1345,7 @@ static int mpeg1_decode_picture(AVCodecContext *avctx,
     if (s->pict_type == FF_P_TYPE || s->pict_type == FF_B_TYPE) {
         s->full_pel[0] = get_bits1(&s->gb);
         f_code = get_bits(&s->gb, 3);
-        if (f_code == 0 && avctx->error_resilience >= FF_ER_COMPLIANT)
+        if (f_code == 0 && avctx->error_recognition >= FF_ER_COMPLIANT)
             return -1;
         s->mpeg_f_code[0][0] = f_code;
         s->mpeg_f_code[0][1] = f_code;
@@ -1353,7 +1353,7 @@ static int mpeg1_decode_picture(AVCodecContext *avctx,
     if (s->pict_type == FF_B_TYPE) {
         s->full_pel[1] = get_bits1(&s->gb);
         f_code = get_bits(&s->gb, 3);
-        if (f_code == 0 && avctx->error_resilience >= FF_ER_COMPLIANT)
+        if (f_code == 0 && avctx->error_recognition >= FF_ER_COMPLIANT)
             return -1;
         s->mpeg_f_code[1][0] = f_code;
         s->mpeg_f_code[1][1] = f_code;
@@ -1502,13 +1502,28 @@ static void mpeg_decode_quant_matrix_extension(MpegEncContext *s)
     }
 }
 
-static void mpeg_decode_picture_coding_extension(MpegEncContext *s)
+static void mpeg_decode_picture_coding_extension(Mpeg1Context *s1)
 {
+    MpegEncContext *s= &s1->mpeg_enc_ctx;
+
     s->full_pel[0] = s->full_pel[1] = 0;
     s->mpeg_f_code[0][0] = get_bits(&s->gb, 4);
     s->mpeg_f_code[0][1] = get_bits(&s->gb, 4);
     s->mpeg_f_code[1][0] = get_bits(&s->gb, 4);
     s->mpeg_f_code[1][1] = get_bits(&s->gb, 4);
+    if(!s->pict_type && s1->mpeg_enc_ctx_allocated){
+        av_log(s->avctx, AV_LOG_ERROR, "Missing picture start code, guessing missing values\n");
+        if(s->mpeg_f_code[1][0] == 15 && s->mpeg_f_code[1][1]==15){
+            if(s->mpeg_f_code[0][0] == 15 && s->mpeg_f_code[0][1] == 15)
+                s->pict_type= FF_I_TYPE;
+            else
+                s->pict_type= FF_P_TYPE;
+        }else
+            s->pict_type= FF_B_TYPE;
+        s->current_picture.pict_type= s->pict_type;
+        s->current_picture.key_frame= s->pict_type == FF_I_TYPE;
+        s->first_slice= 1;
+    }
     s->intra_dc_precision = get_bits(&s->gb, 2);
     s->picture_structure = get_bits(&s->gb, 2);
     s->top_field_first = get_bits1(&s->gb);
@@ -1574,7 +1589,7 @@ static void mpeg_decode_extension(AVCodecContext *avctx,
         mpeg_decode_picture_display_extension(s1);
         break;
     case 0x8:
-        mpeg_decode_picture_coding_extension(s);
+        mpeg_decode_picture_coding_extension(s1);
         break;
     }
 }
@@ -1625,12 +1640,11 @@ static int mpeg_field_start(MpegEncContext *s){
                 }
             }
     }
-#ifdef HAVE_XVMC
 // MPV_frame_start will call this function too,
 // but we need to call it on every field
-    if(s->avctx->xvmc_acceleration)
-         XVMC_field_start(s,avctx);
-#endif
+    if(CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration)
+        if(ff_xvmc_field_start(s,avctx) < 0)
+            return -1;
 
     return 0;
 }
@@ -1716,11 +1730,9 @@ static int mpeg_decode_slice(Mpeg1Context *s1, int mb_y,
     }
 
     for(;;) {
-#ifdef HAVE_XVMC
         //If 1, we memcpy blocks in xvmcvideo.
-        if(s->avctx->xvmc_acceleration > 1)
-            XVMC_init_block(s);//set s->block
-#endif
+        if(CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration > 1)
+            ff_xvmc_init_block(s);//set s->block
 
         if(mpeg_decode_mb(s, s->block) < 0)
             return -1;
@@ -1777,7 +1789,7 @@ static int mpeg_decode_slice(Mpeg1Context *s1, int mb_y,
                             && s->progressive_frame == 0 /* vbv_delay == 0xBBB || 0xE10*/;
 
                 if(left < 0 || (left && show_bits(&s->gb, FFMIN(left, 23)) && !is_d10)
-                   || (avctx->error_resilience >= FF_ER_AGGRESSIVE && left>8)){
+                   || (avctx->error_recognition >= FF_ER_AGGRESSIVE && left>8)){
                     av_log(avctx, AV_LOG_ERROR, "end mismatch left=%d %0X\n", left, show_bits(&s->gb, FFMIN(left, 23)));
                     return -1;
                 }else
@@ -1852,7 +1864,7 @@ eos: // end of slice
 }
 
 static int slice_decode_thread(AVCodecContext *c, void *arg){
-    MpegEncContext *s= arg;
+    MpegEncContext *s= *(void**)arg;
     const uint8_t *buf= s->gb.buffer;
     int mb_y= s->start_mb_y;
 
@@ -1898,10 +1910,9 @@ static int slice_end(AVCodecContext *avctx, AVFrame *pict)
     if (!s1->mpeg_enc_ctx_allocated || !s->current_picture_ptr)
         return 0;
 
-#ifdef HAVE_XVMC
-    if(s->avctx->xvmc_acceleration)
-        XVMC_field_end(s);
-#endif
+    if(CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration)
+        ff_xvmc_field_end(s);
+
     /* end of slice reached */
     if (/*s->mb_y<<field_pic == s->mb_height &&*/ !s->first_field) {
         /* end of image */
@@ -1948,7 +1959,7 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx,
     s->aspect_ratio_info= get_bits(&s->gb, 4);
     if (s->aspect_ratio_info == 0) {
         av_log(avctx, AV_LOG_ERROR, "aspect ratio has forbidden 0 value\n");
-        if (avctx->error_resilience >= FF_ER_COMPLIANT)
+        if (avctx->error_recognition >= FF_ER_COMPLIANT)
             return -1;
     }
     s->frame_rate_index = get_bits(&s->gb, 4);
@@ -2055,13 +2066,10 @@ static int vcr2_init_sequence(AVCodecContext *avctx)
     avctx->has_b_frames= 0; //true?
     s->low_delay= 1;
 
-    if(avctx->xvmc_acceleration){
-        avctx->pix_fmt = avctx->get_format(avctx,pixfmt_xvmc_mpg2_420);
-    }else{
-        avctx->pix_fmt = avctx->get_format(avctx,pixfmt_yuv_420);
-    }
+    avctx->pix_fmt = mpeg_get_pixelformat(avctx);
 
-    if( avctx->pix_fmt == PIX_FMT_XVMC_MPEG2_IDCT )
+    if( avctx->pix_fmt == PIX_FMT_XVMC_MPEG2_IDCT ||
+        s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU )
         if( avctx->idct_algo == FF_IDCT_AUTO )
             avctx->idct_algo = FF_IDCT_SIMPLE;
 
@@ -2255,7 +2263,7 @@ static int mpeg_decode_frame(AVCodecContext *avctx,
     }
 #endif
 
-    if(s->mpeg_enc_ctx_allocated==0 && avctx->codec_tag == ff_get_fourcc("VCR2"))
+    if(s->mpeg_enc_ctx_allocated==0 && avctx->codec_tag == AV_RL32("VCR2"))
         vcr2_init_sequence(avctx);
 
     s->slice_count= 0;
@@ -2285,15 +2293,20 @@ static int decode_chunks(AVCodecContext *avctx,
                 if(avctx->thread_count > 1){
                     int i;
 
-                    avctx->execute(avctx, slice_decode_thread,  (void**)&(s2->thread_context[0]), NULL, s->slice_count);
+                    avctx->execute(avctx, slice_decode_thread,  (void**)&(s2->thread_context[0]), NULL, s->slice_count, sizeof(void*));
                     for(i=0; i<s->slice_count; i++)
                         s2->error_count += s2->thread_context[i]->error_count;
                 }
+
+                if (CONFIG_MPEG_VDPAU_DECODER && avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
+                    ff_vdpau_mpeg_picture_complete(s2, buf, buf_size, s->slice_count);
+
                 if (slice_end(avctx, picture)) {
                     if(s2->last_picture_ptr || s2->low_delay) //FIXME merge with the stuff in mpeg_decode_slice
                         *data_size = sizeof(AVPicture);
                 }
             }
+            s2->pict_type= 0;
             return FFMAX(0, buf_ptr - buf - s2->parse_context.last_index);
         }
 
@@ -2312,8 +2325,9 @@ static int decode_chunks(AVCodecContext *avctx,
 
         case PICTURE_START_CODE:
             /* we have a complete image: we try to decompress it */
-            mpeg1_decode_picture(avctx,
-                                    buf_ptr, input_size);
+            if(mpeg1_decode_picture(avctx,
+                                    buf_ptr, input_size) < 0)
+                s2->pict_type=0;
             break;
         case EXT_START_CODE:
             mpeg_decode_extension(avctx,
@@ -2357,16 +2371,26 @@ static int decode_chunks(AVCodecContext *avctx,
                         break;
                 }
 
+                if(!s2->pict_type){
+                    av_log(avctx, AV_LOG_ERROR, "Missing picture start code\n");
+                    break;
+                }
+
                 if(s2->first_slice){
                     s2->first_slice=0;
-                            if(mpeg_field_start(s2) < 0)
+                    if(mpeg_field_start(s2) < 0)
                         return -1;
-                    }
+                }
                 if(!s2->current_picture_ptr){
                     av_log(avctx, AV_LOG_ERROR, "current_picture not initialized\n");
                     return -1;
                 }
 
+                if (avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU) {
+                    s->slice_count++;
+                    break;
+                }
+
                 if(avctx->thread_count > 1){
                     int threshold= (s2->mb_height*s->slice_count + avctx->thread_count/2) / avctx->thread_count;
                     if(threshold <= mb_y){
@@ -2451,7 +2475,7 @@ AVCodec mpegvideo_decoder = {
     .long_name= NULL_IF_CONFIG_SMALL("MPEG-1 video"),
 };
 
-#ifdef HAVE_XVMC
+#if CONFIG_MPEG_XVMC_DECODER
 static av_cold int mpeg_mc_decode_init(AVCodecContext *avctx){
     Mpeg1Context *s;
 
@@ -2486,3 +2510,36 @@ AVCodec mpeg_xvmc_decoder = {
 };
 
 #endif
+
+#if CONFIG_MPEG_VDPAU_DECODER
+AVCodec mpeg_vdpau_decoder = {
+    "mpegvideo_vdpau",
+    CODEC_TYPE_VIDEO,
+    CODEC_ID_MPEG2VIDEO,
+    sizeof(Mpeg1Context),
+    mpeg_decode_init,
+    NULL,
+    mpeg_decode_end,
+    mpeg_decode_frame,
+    CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED | CODEC_CAP_HWACCEL_VDPAU | CODEC_CAP_DELAY,
+    .flush= ff_mpeg_flush,
+    .long_name = NULL_IF_CONFIG_SMALL("MPEG-1/2 video (VDPAU acceleration)"),
+};
+#endif
+
+#if CONFIG_MPEG1_VDPAU_DECODER
+AVCodec mpeg1_vdpau_decoder = {
+    "mpeg1video_vdpau",
+    CODEC_TYPE_VIDEO,
+    CODEC_ID_MPEG1VIDEO,
+    sizeof(Mpeg1Context),
+    mpeg_decode_init,
+    NULL,
+    mpeg_decode_end,
+    mpeg_decode_frame,
+    CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED | CODEC_CAP_HWACCEL_VDPAU | CODEC_CAP_DELAY,
+    .flush= ff_mpeg_flush,
+    .long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video (VDPAU acceleration)"),
+};
+#endif
+