Define AVMediaType enum, and use it instead of enum CodecType, which
[ffmpeg.git] / libavformat / siff.c
1 /*
2  * Beam Software SIFF demuxer
3  * Copyright (c) 2007 Konstantin Shishkov
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include "libavutil/intreadwrite.h"
23 #include "avformat.h"
24
25 enum SIFFTags{
26     TAG_SIFF = MKTAG('S', 'I', 'F', 'F'),
27     TAG_BODY = MKTAG('B', 'O', 'D', 'Y'),
28     TAG_VBHD = MKTAG('V', 'B', 'H', 'D'),
29     TAG_SHDR = MKTAG('S', 'H', 'D', 'R'),
30     TAG_VBV1 = MKTAG('V', 'B', 'V', '1'),
31     TAG_SOUN = MKTAG('S', 'O', 'U', 'N'),
32 };
33
34 enum VBFlags{
35     VB_HAS_GMC     = 0x01,
36     VB_HAS_AUDIO   = 0x04,
37     VB_HAS_VIDEO   = 0x08,
38     VB_HAS_PALETTE = 0x10,
39     VB_HAS_LENGTH  = 0x20
40 };
41
42 typedef struct SIFFContext{
43     int frames;
44     int cur_frame;
45     int rate;
46     int bits;
47     int block_align;
48
49     int has_video;
50     int has_audio;
51
52     int curstrm;
53     int pktsize;
54     int gmcsize;
55     int sndsize;
56
57     int flags;
58     uint8_t gmc[4];
59 }SIFFContext;
60
61 static int siff_probe(AVProbeData *p)
62 {
63     uint32_t tag = AV_RL32(p->buf + 8);
64     /* check file header */
65     if (AV_RL32(p->buf) != TAG_SIFF ||
66         (tag != TAG_VBV1 && tag != TAG_SOUN))
67         return 0;
68     return AVPROBE_SCORE_MAX;
69 }
70
71 static int create_audio_stream(AVFormatContext *s, SIFFContext *c)
72 {
73     AVStream *ast;
74     ast = av_new_stream(s, 0);
75     if (!ast)
76         return -1;
77     ast->codec->codec_type      = AVMEDIA_TYPE_AUDIO;
78     ast->codec->codec_id        = CODEC_ID_PCM_U8;
79     ast->codec->channels        = 1;
80     ast->codec->bits_per_coded_sample = c->bits;
81     ast->codec->sample_rate     = c->rate;
82     ast->codec->frame_size      = c->block_align;
83     av_set_pts_info(ast, 16, 1, c->rate);
84     return 0;
85 }
86
87 static int siff_parse_vbv1(AVFormatContext *s, SIFFContext *c, ByteIOContext *pb)
88 {
89     AVStream *st;
90     int width, height;
91
92     if (get_le32(pb) != TAG_VBHD){
93         av_log(s, AV_LOG_ERROR, "Header chunk is missing\n");
94         return -1;
95     }
96     if(get_be32(pb) != 32){
97         av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n");
98         return -1;
99     }
100     if(get_le16(pb) != 1){
101         av_log(s, AV_LOG_ERROR, "Incorrect header version\n");
102         return -1;
103     }
104     width = get_le16(pb);
105     height = get_le16(pb);
106     url_fskip(pb, 4);
107     c->frames = get_le16(pb);
108     if(!c->frames){
109         av_log(s, AV_LOG_ERROR, "File contains no frames ???\n");
110         return -1;
111     }
112     c->bits = get_le16(pb);
113     c->rate = get_le16(pb);
114     c->block_align = c->rate * (c->bits >> 3);
115
116     url_fskip(pb, 16); //zeroes
117
118     st = av_new_stream(s, 0);
119     if (!st)
120         return -1;
121     st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
122     st->codec->codec_id   = CODEC_ID_VB;
123     st->codec->codec_tag  = MKTAG('V', 'B', 'V', '1');
124     st->codec->width      = width;
125     st->codec->height     = height;
126     st->codec->pix_fmt    = PIX_FMT_PAL8;
127     av_set_pts_info(st, 16, 1, 12);
128
129     c->cur_frame = 0;
130     c->has_video = 1;
131     c->has_audio = !!c->rate;
132     c->curstrm = -1;
133     if (c->has_audio && create_audio_stream(s, c) < 0)
134         return -1;
135     return 0;
136 }
137
138 static int siff_parse_soun(AVFormatContext *s, SIFFContext *c, ByteIOContext *pb)
139 {
140     if (get_le32(pb) != TAG_SHDR){
141         av_log(s, AV_LOG_ERROR, "Header chunk is missing\n");
142         return -1;
143     }
144     if(get_be32(pb) != 8){
145         av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n");
146         return -1;
147     }
148     url_fskip(pb, 4); //unknown value
149     c->rate = get_le16(pb);
150     c->bits = get_le16(pb);
151     c->block_align = c->rate * (c->bits >> 3);
152     return create_audio_stream(s, c);
153 }
154
155 static int siff_read_header(AVFormatContext *s, AVFormatParameters *ap)
156 {
157     ByteIOContext *pb = s->pb;
158     SIFFContext *c = s->priv_data;
159     uint32_t tag;
160
161     if (get_le32(pb) != TAG_SIFF)
162         return -1;
163     url_fskip(pb, 4); //ignore size
164     tag = get_le32(pb);
165
166     if (tag != TAG_VBV1 && tag != TAG_SOUN){
167         av_log(s, AV_LOG_ERROR, "Not a VBV file\n");
168         return -1;
169     }
170
171     if (tag == TAG_VBV1 && siff_parse_vbv1(s, c, pb) < 0)
172         return -1;
173     if (tag == TAG_SOUN && siff_parse_soun(s, c, pb) < 0)
174         return -1;
175     if (get_le32(pb) != MKTAG('B', 'O', 'D', 'Y')){
176         av_log(s, AV_LOG_ERROR, "'BODY' chunk is missing\n");
177         return -1;
178     }
179     url_fskip(pb, 4); //ignore size
180
181     return 0;
182 }
183
184 static int siff_read_packet(AVFormatContext *s, AVPacket *pkt)
185 {
186     SIFFContext *c = s->priv_data;
187     int size;
188
189     if (c->has_video){
190         if (c->cur_frame >= c->frames)
191             return AVERROR(EIO);
192         if (c->curstrm == -1){
193             c->pktsize = get_le32(s->pb) - 4;
194             c->flags = get_le16(s->pb);
195             c->gmcsize = (c->flags & VB_HAS_GMC) ? 4 : 0;
196             if (c->gmcsize)
197                 get_buffer(s->pb, c->gmc, c->gmcsize);
198             c->sndsize = (c->flags & VB_HAS_AUDIO) ? get_le32(s->pb): 0;
199             c->curstrm = !!(c->flags & VB_HAS_AUDIO);
200         }
201
202         if (!c->curstrm){
203             size = c->pktsize - c->sndsize;
204             if (av_new_packet(pkt, size) < 0)
205                 return AVERROR(ENOMEM);
206             AV_WL16(pkt->data, c->flags);
207             if (c->gmcsize)
208                 memcpy(pkt->data + 2, c->gmc, c->gmcsize);
209             get_buffer(s->pb, pkt->data + 2 + c->gmcsize, size - c->gmcsize - 2);
210             pkt->stream_index = 0;
211             c->curstrm = -1;
212         }else{
213             if (av_get_packet(s->pb, pkt, c->sndsize - 4) < 0)
214                 return AVERROR(EIO);
215             pkt->stream_index = 1;
216             c->curstrm = 0;
217         }
218         if(!c->cur_frame || c->curstrm)
219             pkt->flags |= PKT_FLAG_KEY;
220         if (c->curstrm == -1)
221             c->cur_frame++;
222     }else{
223         size = av_get_packet(s->pb, pkt, c->block_align);
224         if(size <= 0)
225             return AVERROR(EIO);
226     }
227     return pkt->size;
228 }
229
230 AVInputFormat siff_demuxer = {
231     "siff",
232     NULL_IF_CONFIG_SMALL("Beam Software SIFF"),
233     sizeof(SIFFContext),
234     siff_probe,
235     siff_read_header,
236     siff_read_packet,
237     .extensions = "vb,son"
238 };