]> git.sesse.net Git - ffmpeg/blob - libavformat/swfdec.c
avidec: return 0, not packet size from read_packet().
[ffmpeg] / libavformat / swfdec.c
1 /*
2  * Flash Compatible Streaming Format demuxer
3  * Copyright (c) 2000 Fabrice Bellard
4  * Copyright (c) 2003 Tinic Uro
5  *
6  * This file is part of Libav.
7  *
8  * Libav is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * Libav is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with Libav; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23 #include "libavutil/intreadwrite.h"
24 #include "swf.h"
25
26 static const AVCodecTag swf_audio_codec_tags[] = {
27     { AV_CODEC_ID_PCM_S16LE,  0x00 },
28     { AV_CODEC_ID_ADPCM_SWF,  0x01 },
29     { AV_CODEC_ID_MP3,        0x02 },
30     { AV_CODEC_ID_PCM_S16LE,  0x03 },
31 //  { AV_CODEC_ID_NELLYMOSER, 0x06 },
32     { AV_CODEC_ID_NONE,          0 },
33 };
34
35 static int get_swf_tag(AVIOContext *pb, int *len_ptr)
36 {
37     int tag, len;
38
39     if (pb->eof_reached)
40         return -1;
41
42     tag = avio_rl16(pb);
43     len = tag & 0x3f;
44     tag = tag >> 6;
45     if (len == 0x3f) {
46         len = avio_rl32(pb);
47     }
48 //    av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);
49     *len_ptr = len;
50     return tag;
51 }
52
53
54 static int swf_probe(AVProbeData *p)
55 {
56     /* check file header */
57     if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
58         p->buf[2] == 'S')
59         return AVPROBE_SCORE_MAX;
60     else
61         return 0;
62 }
63
64 static int swf_read_header(AVFormatContext *s)
65 {
66     SWFContext *swf = s->priv_data;
67     AVIOContext *pb = s->pb;
68     int nbits, len, tag;
69
70     tag = avio_rb32(pb) & 0xffffff00;
71
72     if (tag == MKBETAG('C', 'W', 'S', 0)) {
73         av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
74         return AVERROR(EIO);
75     }
76     if (tag != MKBETAG('F', 'W', 'S', 0))
77         return AVERROR(EIO);
78     avio_rl32(pb);
79     /* skip rectangle size */
80     nbits = avio_r8(pb) >> 3;
81     len = (4 * nbits - 3 + 7) / 8;
82     avio_skip(pb, len);
83     swf->frame_rate = avio_rl16(pb); /* 8.8 fixed */
84     avio_rl16(pb); /* frame count */
85
86     swf->samples_per_frame = 0;
87     s->ctx_flags |= AVFMTCTX_NOHEADER;
88     return 0;
89 }
90
91 static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
92 {
93     SWFContext *swf = s->priv_data;
94     AVIOContext *pb = s->pb;
95     AVStream *vst = NULL, *ast = NULL, *st = 0;
96     int tag, len, i, frame, v, res;
97
98     for(;;) {
99         uint64_t pos = avio_tell(pb);
100         tag = get_swf_tag(pb, &len);
101         if (tag < 0)
102             return AVERROR(EIO);
103         if (tag == TAG_VIDEOSTREAM) {
104             int ch_id = avio_rl16(pb);
105             len -= 2;
106
107             for (i=0; i<s->nb_streams; i++) {
108                 st = s->streams[i];
109                 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->id == ch_id)
110                     goto skip;
111             }
112
113             avio_rl16(pb);
114             avio_rl16(pb);
115             avio_rl16(pb);
116             avio_r8(pb);
117             /* Check for FLV1 */
118             vst = avformat_new_stream(s, NULL);
119             if (!vst)
120                 return -1;
121             vst->id = ch_id;
122             vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
123             vst->codec->codec_id = ff_codec_get_id(ff_swf_codec_tags, avio_r8(pb));
124             avpriv_set_pts_info(vst, 16, 256, swf->frame_rate);
125             len -= 8;
126         } else if (tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) {
127             /* streaming found */
128             int sample_rate_code;
129
130             for (i=0; i<s->nb_streams; i++) {
131                 st = s->streams[i];
132                 if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->id == -1)
133                     goto skip;
134             }
135
136             avio_r8(pb);
137             v = avio_r8(pb);
138             swf->samples_per_frame = avio_rl16(pb);
139             ast = avformat_new_stream(s, NULL);
140             if (!ast)
141                 return -1;
142             ast->id = -1; /* -1 to avoid clash with video stream ch_id */
143             ast->codec->channels = 1 + (v&1);
144             ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
145             ast->codec->codec_id = ff_codec_get_id(swf_audio_codec_tags, (v>>4) & 15);
146             ast->need_parsing = AVSTREAM_PARSE_FULL;
147             sample_rate_code= (v>>2) & 3;
148             ast->codec->sample_rate = 44100 >> (3 - sample_rate_code);
149             avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
150             len -= 4;
151         } else if (tag == TAG_VIDEOFRAME) {
152             int ch_id = avio_rl16(pb);
153             len -= 2;
154             for(i=0; i<s->nb_streams; i++) {
155                 st = s->streams[i];
156                 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->id == ch_id) {
157                     frame = avio_rl16(pb);
158                     if ((res = av_get_packet(pb, pkt, len-2)) < 0)
159                         return res;
160                     pkt->pos = pos;
161                     pkt->pts = frame;
162                     pkt->stream_index = st->index;
163                     return pkt->size;
164                 }
165             }
166         } else if (tag == TAG_STREAMBLOCK) {
167             for (i = 0; i < s->nb_streams; i++) {
168                 st = s->streams[i];
169                 if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->id == -1) {
170             if (st->codec->codec_id == AV_CODEC_ID_MP3) {
171                 avio_skip(pb, 4);
172                 if ((res = av_get_packet(pb, pkt, len-4)) < 0)
173                     return res;
174             } else { // ADPCM, PCM
175                 if ((res = av_get_packet(pb, pkt, len)) < 0)
176                     return res;
177             }
178             pkt->pos = pos;
179             pkt->stream_index = st->index;
180             return pkt->size;
181                 }
182             }
183         } else if (tag == TAG_JPEG2) {
184             for (i=0; i<s->nb_streams; i++) {
185                 st = s->streams[i];
186                 if (st->codec->codec_id == AV_CODEC_ID_MJPEG && st->id == -2)
187                     break;
188             }
189             if (i == s->nb_streams) {
190                 vst = avformat_new_stream(s, NULL);
191                 if (!vst)
192                     return -1;
193                 vst->id = -2; /* -2 to avoid clash with video stream and audio stream */
194                 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
195                 vst->codec->codec_id = AV_CODEC_ID_MJPEG;
196                 avpriv_set_pts_info(vst, 64, 256, swf->frame_rate);
197                 st = vst;
198             }
199             avio_rl16(pb); /* BITMAP_ID */
200             if ((res = av_new_packet(pkt, len-2)) < 0)
201                 return res;
202             avio_read(pb, pkt->data, 4);
203             if (AV_RB32(pkt->data) == 0xffd8ffd9 ||
204                 AV_RB32(pkt->data) == 0xffd9ffd8) {
205                 /* old SWF files containing SOI/EOI as data start */
206                 /* files created by swink have reversed tag */
207                 pkt->size -= 4;
208                 avio_read(pb, pkt->data, pkt->size);
209             } else {
210                 avio_read(pb, pkt->data + 4, pkt->size - 4);
211             }
212             pkt->pos = pos;
213             pkt->stream_index = st->index;
214             return pkt->size;
215         }
216     skip:
217         avio_skip(pb, len);
218     }
219 }
220
221 AVInputFormat ff_swf_demuxer = {
222     .name           = "swf",
223     .long_name      = NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash)"),
224     .priv_data_size = sizeof(SWFContext),
225     .read_probe     = swf_probe,
226     .read_header    = swf_read_header,
227     .read_packet    = swf_read_packet,
228 };