[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