[FFmpeg-devel] [PATCH] electronicarts: demux alpha stream

Peter Ross pross at xvid.org
Tue Jun 23 16:31:56 CEST 2015


.vp6 files may contain two video streams: one for the primary video
stream and another for the alpha mask. The file format uses identical
data structures for both streams.

Signed-off-by: Peter Ross <pross at xvid.org>
---
 libavformat/electronicarts.c | 136 +++++++++++++++++++++++++------------------
 1 file changed, 80 insertions(+), 56 deletions(-)

diff --git a/libavformat/electronicarts.c b/libavformat/electronicarts.c
index d999a0b..1c35e2d 100644
--- a/libavformat/electronicarts.c
+++ b/libavformat/electronicarts.c
@@ -59,18 +59,25 @@
 #define MVhd_TAG MKTAG('M', 'V', 'h', 'd')
 #define MV0K_TAG MKTAG('M', 'V', '0', 'K')
 #define MV0F_TAG MKTAG('M', 'V', '0', 'F')
+#define AVhd_TAG MKTAG('A', 'V', 'h', 'd')
+#define AV0K_TAG MKTAG('A', 'V', '0', 'K')
+#define AV0F_TAG MKTAG('A', 'V', '0', 'F')
 #define MVIh_TAG MKTAG('M', 'V', 'I', 'h')  /* CMV header */
 #define MVIf_TAG MKTAG('M', 'V', 'I', 'f')  /* CMV I-frame */
 #define AVP6_TAG MKTAG('A', 'V', 'P', '6')
 
-typedef struct EaDemuxContext {
-    int big_endian;
-
-    enum AVCodecID video_codec;
+typedef struct VideoProperties {
+    enum AVCodecID codec;
     AVRational time_base;
     int width, height;
     int nb_frames;
-    int video_stream_index;
+    int stream_index;
+} VideoProperties;
+
+typedef struct EaDemuxContext {
+    int big_endian;
+
+    VideoProperties video, alpha;
 
     enum AVCodecID audio_codec;
     int audio_stream_index;
@@ -302,46 +309,43 @@ static void process_audio_header_sead(AVFormatContext *s)
     ea->audio_codec  = AV_CODEC_ID_ADPCM_IMA_EA_SEAD;
 }
 
-static void process_video_header_mdec(AVFormatContext *s)
+static void process_video_header_mdec(AVFormatContext *s, VideoProperties *video)
 {
-    EaDemuxContext *ea = s->priv_data;
     AVIOContext *pb    = s->pb;
     avio_skip(pb, 4);
-    ea->width       = avio_rl16(pb);
-    ea->height      = avio_rl16(pb);
-    ea->time_base   = (AVRational) { 1, 15 };
-    ea->video_codec = AV_CODEC_ID_MDEC;
+    video->width       = avio_rl16(pb);
+    video->height      = avio_rl16(pb);
+    video->time_base   = (AVRational) { 1, 15 };
+    video->codec = AV_CODEC_ID_MDEC;
 }
 
-static int process_video_header_vp6(AVFormatContext *s)
+static int process_video_header_vp6(AVFormatContext *s, VideoProperties *video)
 {
-    EaDemuxContext *ea = s->priv_data;
-    AVIOContext *pb    = s->pb;
+    AVIOContext *pb = s->pb;
 
     avio_skip(pb, 8);
-    ea->nb_frames = avio_rl32(pb);
+    video->nb_frames = avio_rl32(pb);
     avio_skip(pb, 4);
-    ea->time_base.den = avio_rl32(pb);
-    ea->time_base.num = avio_rl32(pb);
-    if (ea->time_base.den <= 0 || ea->time_base.num <= 0) {
+    video->time_base.den = avio_rl32(pb);
+    video->time_base.num = avio_rl32(pb);
+    if (video->time_base.den <= 0 || video->time_base.num <= 0) {
         av_log(s, AV_LOG_ERROR, "Timebase is invalid\n");
         return AVERROR_INVALIDDATA;
     }
-    ea->video_codec   = AV_CODEC_ID_VP6;
+    video->codec   = AV_CODEC_ID_VP6;
 
     return 1;
 }
 
-static void process_video_header_cmv(AVFormatContext *s)
+static void process_video_header_cmv(AVFormatContext *s, VideoProperties *video)
 {
-    EaDemuxContext *ea = s->priv_data;
     int fps;
 
     avio_skip(s->pb, 10);
     fps = avio_rl16(s->pb);
     if (fps)
-        ea->time_base = (AVRational) { 1, fps };
-    ea->video_codec = AV_CODEC_ID_CMV;
+        video->time_base = (AVRational) { 1, fps };
+    video->codec = AV_CODEC_ID_CMV;
 }
 
 /* Process EA file header.
@@ -353,7 +357,7 @@ static int process_ea_header(AVFormatContext *s)
     AVIOContext *pb    = s->pb;
     int i;
 
-    for (i = 0; i < 5 && (!ea->audio_codec || !ea->video_codec); i++) {
+    for (i = 0; i < 5 && (!ea->audio_codec || !ea->video.codec); i++) {
         uint64_t startpos     = avio_tell(pb);
         int err               = 0;
 
@@ -395,40 +399,44 @@ static int process_ea_header(AVFormatContext *s)
             break;
 
         case MVIh_TAG:
-            process_video_header_cmv(s);
+            process_video_header_cmv(s, &ea->video);
             break;
 
         case kVGT_TAG:
-            ea->video_codec = AV_CODEC_ID_TGV;
+            ea->video.codec = AV_CODEC_ID_TGV;
             break;
 
         case mTCD_TAG:
-            process_video_header_mdec(s);
+            process_video_header_mdec(s, &ea->video);
             break;
 
         case MPCh_TAG:
-            ea->video_codec = AV_CODEC_ID_MPEG2VIDEO;
+            ea->video.codec = AV_CODEC_ID_MPEG2VIDEO;
             break;
 
         case pQGT_TAG:
         case TGQs_TAG:
-            ea->video_codec = AV_CODEC_ID_TGQ;
-            ea->time_base   = (AVRational) { 1, 15 };
+            ea->video.codec = AV_CODEC_ID_TGQ;
+            ea->video.time_base   = (AVRational) { 1, 15 };
             break;
 
         case pIQT_TAG:
-            ea->video_codec = AV_CODEC_ID_TQI;
-            ea->time_base   = (AVRational) { 1, 15 };
+            ea->video.codec = AV_CODEC_ID_TQI;
+            ea->video.time_base   = (AVRational) { 1, 15 };
             break;
 
         case MADk_TAG:
-            ea->video_codec = AV_CODEC_ID_MAD;
+            ea->video.codec = AV_CODEC_ID_MAD;
             avio_skip(pb, 6);
-            ea->time_base = (AVRational) { avio_rl16(pb), 1000 };
+            ea->video.time_base = (AVRational) { avio_rl16(pb), 1000 };
             break;
 
         case MVhd_TAG:
-            err = process_video_header_vp6(s);
+            err = process_video_header_vp6(s, &ea->video);
+            break;
+
+        case AVhd_TAG:
+            err = process_video_header_vp6(s, &ea->alpha);
             break;
         }
 
@@ -458,6 +466,7 @@ static int ea_probe(AVProbeData *p)
     case MADk_TAG:
     case MPCh_TAG:
     case MVhd_TAG:
+    case AVhd_TAG:
     case MVIh_TAG:
     case AVP6_TAG:
         break;
@@ -474,6 +483,34 @@ static int ea_probe(AVProbeData *p)
     return AVPROBE_SCORE_MAX;
 }
 
+static int init_video_stream(AVFormatContext *s, VideoProperties *video)
+{
+    AVStream *st;
+
+    if (!video->codec)
+        return 0;
+
+    /* initialize the video decoder stream */
+    st = avformat_new_stream(s, NULL);
+    if (!st)
+        return AVERROR(ENOMEM);
+    video->stream_index = st->index;
+    st->codec->codec_type  = AVMEDIA_TYPE_VIDEO;
+    st->codec->codec_id    = video->codec;
+    // parsing is necessary to make FFmpeg generate correct timestamps
+    if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO)
+        st->need_parsing = AVSTREAM_PARSE_HEADERS;
+    st->codec->codec_tag   = 0; /* no fourcc */
+    st->codec->width       = video->width;
+    st->codec->height      = video->height;
+    st->duration           = st->nb_frames = video->nb_frames;
+    if (video->time_base.num)
+        avpriv_set_pts_info(st, 64, video->time_base.num, video->time_base.den);
+    st->r_frame_rate       =
+    st->avg_frame_rate     = av_inv_q(video->time_base);
+    return 0;
+}
+
 static int ea_read_header(AVFormatContext *s)
 {
     EaDemuxContext *ea = s->priv_data;
@@ -482,26 +519,8 @@ static int ea_read_header(AVFormatContext *s)
     if (process_ea_header(s)<=0)
         return AVERROR(EIO);
 
-    if (ea->video_codec) {
-        /* initialize the video decoder stream */
-        st = avformat_new_stream(s, NULL);
-        if (!st)
-            return AVERROR(ENOMEM);
-        ea->video_stream_index = st->index;
-        st->codec->codec_type  = AVMEDIA_TYPE_VIDEO;
-        st->codec->codec_id    = ea->video_codec;
-        // parsing is necessary to make FFmpeg generate correct timestamps
-        if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO)
-            st->need_parsing = AVSTREAM_PARSE_HEADERS;
-        st->codec->codec_tag   = 0; /* no fourcc */
-        st->codec->width       = ea->width;
-        st->codec->height      = ea->height;
-        st->duration           = st->nb_frames = ea->nb_frames;
-        if (ea->time_base.num)
-            avpriv_set_pts_info(st, 64, ea->time_base.num, ea->time_base.den);
-        st->r_frame_rate       =
-        st->avg_frame_rate     = av_inv_q(ea->time_base);
-    }
+    if (init_video_stream(s, &ea->video) || init_video_stream(s, &ea->alpha))
+        return AVERROR(ENOMEM);
 
     if (ea->audio_codec) {
         if (ea->num_channels <= 0 || ea->num_channels > 2) {
@@ -661,10 +680,12 @@ static int ea_read_packet(AVFormatContext *s, AVPacket *pkt)
             goto get_video_packet;
 
         case MV0K_TAG:
+        case AV0K_TAG:
         case MPCh_TAG:
         case pIQT_TAG:
             key = AV_PKT_FLAG_KEY;
         case MV0F_TAG:
+        case AV0F_TAG:
 get_video_packet:
             if (!chunk_size)
                 continue;
@@ -678,7 +699,10 @@ get_video_packet:
                 break;
             }
             partial_packet = chunk_type == MVIh_TAG;
-            pkt->stream_index = ea->video_stream_index;
+            if (chunk_type == AV0K_TAG || chunk_type == AV0F_TAG)
+                pkt->stream_index = ea->alpha.stream_index;
+            else
+                pkt->stream_index = ea->video.stream_index;
             pkt->flags       |= key;
             packet_read       = 1;
             break;
-- 
2.1.4

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20150624/651e9b85/attachment.asc>


More information about the ffmpeg-devel mailing list