[Ffmpeg-devel] [PATCH] fix swf demuxing

Michael Niedermayer michaelni
Mon Dec 18 19:16:52 CET 2006


Hi

On Mon, Dec 18, 2006 at 12:32:13PM +0100, Baptiste Coudurier wrote:
> Hi
> 
> This patch fix swf demuxing of ffmpeg own created files.
> Don't skip too many bytes if tag is STREAMHEAD2 and mp3. Generic skip of
>  non read bytes.
> 
> How to reproduce:
> ffmpeg -i <file> test.swf, with mp3 audio and video track.
> 
> ffmpeg -i test.swf will only see mp3 track.
> 
> Cannot confirm if original bug is not reappearing since no broken file
> was supplied, that fix seems generic though.

the swf muxer is broken, the demuxer too ...

a long time ago i tried to clean it up but was to lazy to finish, my half
finished work (assuming i found the right patch) is attached (ill try to
apply some parts of it, feel free to finish it in case i give up again if 
you like), it also changes the code you change, but differently, dunno
which solution is correcter ...

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

The worst form of inequality is to try to make unequal things equal.
-- Aristotle
-------------- next part --------------
Index: swf.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/swf.c,v
retrieving revision 1.23
diff -u -r1.23 swf.c
--- swf.c	29 Dec 2004 18:31:28 -0000	1.23
+++ swf.c	30 Jan 2005 13:44:01 -0000
@@ -30,7 +30,7 @@
 #define TAG_FREECHARACTER 3
 #define TAG_PLACEOBJECT   4
 #define TAG_REMOVEOBJECT  5
-#define TAG_STREAMHEAD    45
+#define TAG_STREAMHEAD    18
 #define TAG_STREAMBLOCK   19
 #define TAG_JPEG2         21
 #define TAG_PLACEOBJECT2  26
@@ -47,8 +47,6 @@
 
 #define SWF_VIDEO_CODEC_FLV1	0x02
 
-#define AUDIO_FIFO_SIZE 65536
-
 /* character id used */
 #define BITMAP_ID 0
 #define VIDEO_ID 0
@@ -63,97 +61,20 @@
     offset_t tag_pos;
     
     int samples_per_frame;
-    int sound_samples;
-    int video_samples;
     int swf_frame_number;
     int video_frame_number;
     int ms_per_frame;
     int ch_id;
     int tag;
-
-    uint8_t *audio_fifo;
-    int audio_in_pos;
-    int audio_out_pos;
-    int audio_size;
-
-    int video_type;
-    int audio_type;
 } SWFContext;
 
-static const int sSampleRates[3][4] = {
-    {44100, 48000, 32000, 0},
-    {22050, 24000, 16000, 0},
-    {11025, 12000,  8000, 0},
-};
-
-static const int sBitRates[2][3][15] = {
-    {   {  0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448},
-        {  0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384},
-        {  0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320}
-    },
-    {   {  0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256},
-        {  0,  8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160},
-        {  0,  8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}
-    },
-};
-
-static const int sSamplesPerFrame[3][3] =
-{
-    {  384,     1152,    1152 },
-    {  384,     1152,     576 },
-    {  384,     1152,     576 }
-};
-
-static const int sBitsPerSlot[3] = {
-    32,
-    8,
-    8
-};
-
-static int swf_mp3_info(void *data, int *byteSize, int *samplesPerFrame, int *sampleRate, int *isMono )
-{
-    uint8_t *dataTmp = (uint8_t *)data;
-    uint32_t header = ( (uint32_t)dataTmp[0] << 24 ) | ( (uint32_t)dataTmp[1] << 16 ) | ( (uint32_t)dataTmp[2] << 8 ) | (uint32_t)dataTmp[3];
-    int layerID = 3 - ((header >> 17) & 0x03);
-    int bitRateID = ((header >> 12) & 0x0f);
-    int sampleRateID = ((header >> 10) & 0x03);
-    int bitRate = 0;
-    int bitsPerSlot = sBitsPerSlot[layerID];
-    int isPadded = ((header >> 9) & 0x01);
-    
-    if ( (( header >> 21 ) & 0x7ff) != 0x7ff ) {
-        return 0;
-    }
-
-    *isMono = ((header >>  6) & 0x03) == 0x03;
-
-    if ( (header >> 19 ) & 0x01 ) {
-        *sampleRate = sSampleRates[0][sampleRateID];
-        bitRate = sBitRates[0][layerID][bitRateID] * 1000;
-        *samplesPerFrame = sSamplesPerFrame[0][layerID];
-    } else {
-        if ( (header >> 20) & 0x01 ) {
-            *sampleRate = sSampleRates[1][sampleRateID];
-            bitRate = sBitRates[1][layerID][bitRateID] * 1000;
-            *samplesPerFrame = sSamplesPerFrame[1][layerID];
-        } else {
-            *sampleRate = sSampleRates[2][sampleRateID];
-            bitRate = sBitRates[1][layerID][bitRateID] * 1000;
-            *samplesPerFrame = sSamplesPerFrame[2][layerID];
-        }
-    }
-
-    *byteSize = ( ( ( ( *samplesPerFrame * (bitRate / bitsPerSlot) ) / *sampleRate ) + isPadded ) );
-
-    return 1;
-}
-
 #ifdef CONFIG_ENCODERS
 static void put_swf_tag(AVFormatContext *s, int tag)
 {
     SWFContext *swf = s->priv_data;
     ByteIOContext *pb = &s->pb;
 
+//            av_log(NULL, AV_LOG_DEBUG, "tag:%d\n", tag);
     swf->tag_pos = url_ftell(pb);
     swf->tag = tag;
     /* reserve some room for the tag */
@@ -312,12 +233,6 @@
     s->priv_data = swf;
 
     swf->ch_id = -1;
-    swf->audio_in_pos = 0;
-    swf->audio_out_pos = 0;
-    swf->audio_size = 0;
-    swf->audio_fifo = av_malloc(AUDIO_FIFO_SIZE);
-    swf->sound_samples = 0;
-    swf->video_samples = 0;
     swf->swf_frame_number = 0;
     swf->video_frame_number = 0;
 
@@ -339,13 +254,11 @@
 
     if (!video_enc) {
         /* currenty, cannot work correctly if audio only */
-        swf->video_type = 0;
         width = 320;
         height = 200;
         rate = 10;
         rate_base= 1;
     } else {
-        swf->video_type = video_enc->codec_id;
         width = video_enc->width;
         height = video_enc->height;
         rate = video_enc->frame_rate;
@@ -353,10 +266,8 @@
     }
 
     if (!audio_enc ) {
-        swf->audio_type = 0;
         swf->samples_per_frame = ( 44100. * rate_base ) / rate;
     } else {
-        swf->audio_type = audio_enc->codec_id;
         swf->samples_per_frame = ( ( audio_enc->sample_rate ) * rate_base ) / rate;
     }
 
@@ -438,7 +349,6 @@
             break;
         default:
             /* not supported */
-            av_free(swf->audio_fifo);
             av_free(swf);
             return -1;
         }
@@ -463,56 +373,8 @@
 {
     SWFContext *swf = s->priv_data;
     ByteIOContext *pb = &s->pb;
-    int c = 0;
-    int outSize = 0;
-    int outSamples = 0;
-    
-    /* Flash Player limit */
-    if ( swf->swf_frame_number == 16000 ) {
-        av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
-    }
-
-    if ( swf->audio_type ) {
-        /* Prescan audio data for this swf frame */
-retry_swf_audio_packet:
-        if ( ( swf->audio_size-outSize ) >= 4 ) {
-            int mp3FrameSize = 0;
-            int mp3SampleRate = 0;
-            int mp3IsMono = 0;
-            int mp3SamplesPerFrame = 0;
-            
-            /* copy out mp3 header from ring buffer */
-            uint8_t header[4];
-            for (c=0; c<4; c++) {
-                header[c] = swf->audio_fifo[(swf->audio_in_pos+outSize+c) % AUDIO_FIFO_SIZE];
-            }
-            
-            if ( swf_mp3_info(header,&mp3FrameSize,&mp3SamplesPerFrame,&mp3SampleRate,&mp3IsMono) ) {
-                if ( ( swf->audio_size-outSize ) >= mp3FrameSize ) {
-                    outSize += mp3FrameSize;
-                    outSamples += mp3SamplesPerFrame;
-                    if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
-                        goto retry_swf_audio_packet;
-                    }
-                }
-            } else {
-                /* invalid mp3 data, skip forward
-                we need to do this since the Flash Player 
-                does not like custom headers */
-                swf->audio_in_pos ++;
-                swf->audio_size --;
-                swf->audio_in_pos %= AUDIO_FIFO_SIZE;
-                goto retry_swf_audio_packet;
-            }
-        }
-        
-        /* audio stream is behind video stream, bail */
-        if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
-            return 0;
-        }
-    }
-
-            if ( swf->video_type == CODEC_ID_FLV1 ) {
+    
+            if ( enc->codec_id == CODEC_ID_FLV1 ) {
                 if ( swf->video_frame_number == 0 ) {
                     /* create a new video object */
                     put_swf_tag(s, TAG_VIDEOSTREAM);
@@ -553,7 +415,7 @@
                     put_le16(pb, swf->video_frame_number++ );
                     put_buffer(pb, buf, size);
                     put_swf_end_tag(s);
-            } else if ( swf->video_type == CODEC_ID_MJPEG ) {
+            } else if ( enc->codec_id == CODEC_ID_MJPEG ) {
                 if (swf->swf_frame_number > 0) {
                     /* remove the shape */
                     put_swf_tag(s, TAG_REMOVEOBJECT);
@@ -594,25 +456,6 @@
     
             swf->swf_frame_number ++;
 
-    swf->video_samples += swf->samples_per_frame;
-
-    /* streaming sound always should be placed just before showframe tags */
-    if ( outSize > 0 ) {
-        put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
-        put_le16(pb, outSamples);
-        put_le16(pb, 0);
-        for (c=0; c<outSize; c++) {
-            put_byte(pb,swf->audio_fifo[(swf->audio_in_pos+c) % AUDIO_FIFO_SIZE]);
-        }
-        put_swf_end_tag(s);
-    
-        /* update FIFO */
-        swf->sound_samples += outSamples;
-        swf->audio_in_pos += outSize;
-        swf->audio_size -= outSize;
-        swf->audio_in_pos %= AUDIO_FIFO_SIZE;
-    }
-
     /* output the frame */
     put_swf_tag(s, TAG_SHOWFRAME);
     put_swf_end_tag(s);
@@ -625,27 +468,14 @@
 static int swf_write_audio(AVFormatContext *s, 
                            AVCodecContext *enc, const uint8_t *buf, int size)
 {
-    SWFContext *swf = s->priv_data;
-    int c = 0;
+    ByteIOContext *pb = &s->pb;
 
-    /* Flash Player limit */
-    if ( swf->swf_frame_number == 16000 ) {
-        av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
-    }
+    put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
 
-    if (enc->codec_id == CODEC_ID_MP3 ) {
-        for (c=0; c<size; c++) {
-            swf->audio_fifo[(swf->audio_out_pos+c)%AUDIO_FIFO_SIZE] = buf[c];
-        }
-        swf->audio_size += size;
-        swf->audio_out_pos += size;
-        swf->audio_out_pos %= AUDIO_FIFO_SIZE;
-    }
-
-    /* if audio only stream make sure we add swf frames */
-    if ( swf->video_type == 0 ) {
-        swf_write_video(s, enc, 0, 0);
-    }
+    put_buffer(pb, buf, size);
+    
+    put_swf_end_tag(s);
+    put_flush_packet(&s->pb);
 
     return 0;
 }
@@ -687,8 +517,6 @@
         put_le16(pb, video_enc->frame_number);
     }
     
-    av_free(swf->audio_fifo);
-
     return 0;
 }
 #endif //CONFIG_ENCODERS
@@ -764,6 +592,7 @@
     firstTagOff = url_ftell(pb);
     for(;;) {
         tag = get_swf_tag(pb, &len);
+
         if (tag < 0) {
             if ( ast || vst ) {
                 if ( vst && ast ) {
@@ -798,22 +627,18 @@
             get_byte(pb);
             v = get_byte(pb);
             swf->samples_per_frame = get_le16(pb);
-            if (len!=4)
-                url_fskip(pb,len-4);
             /* if mp3 streaming found, OK */
             if ((v & 0x20) != 0) {
                 if ( tag == TAG_STREAMHEAD2 ) {
                     get_le16(pb);
+                    len-=2;
                 }
                 ast = av_new_stream(s, 1);
                 av_set_pts_info(ast, 24, 1, 1000); /* 24 bit pts in ms */
                 if (!ast)
                     return -ENOMEM;
 
-                if (v & 0x01)
-                    ast->codec.channels = 2;
-                else
-                    ast->codec.channels = 1;
+                ast->codec.channels = 1 + (v&1);
 
                 switch((v>> 2) & 0x03) {
                 case 1:
@@ -832,6 +657,8 @@
                 ast->codec.codec_type = CODEC_TYPE_AUDIO;
                 ast->codec.codec_id = CODEC_ID_MP3;
             }
+            if (len>4)
+                url_fskip(pb,len-4);
         } else {
             url_fskip(pb, len);
         }



More information about the ffmpeg-devel mailing list