cosmetics: Remove pointless period after copyright statement non-sentences.
[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     /* check file header */
64     if (AV_RL32(p->buf) == TAG_SIFF)
65         return AVPROBE_SCORE_MAX;
66     else
67         return 0;
68 }
69
70 static int create_audio_stream(AVFormatContext *s, SIFFContext *c)
71 {
72     AVStream *ast;
73     ast = av_new_stream(s, 0);
74     if (!ast)
75         return -1;
76     ast->codec->codec_type      = CODEC_TYPE_AUDIO;
77     ast->codec->codec_id        = CODEC_ID_PCM_U8;
78     ast->codec->channels        = 1;
79     ast->codec->bits_per_coded_sample = c->bits;
80     ast->codec->sample_rate     = c->rate;
81     ast->codec->frame_size      = c->block_align;
82     av_set_pts_info(ast, 16, 1, c->rate);
83     return 0;
84 }
85
86 static int siff_parse_vbv1(AVFormatContext *s, SIFFContext *c, ByteIOContext *pb)
87 {
88     AVStream *st;
89     int width, height;
90
91     if (get_le32(pb) != TAG_VBHD){
92         av_log(s, AV_LOG_ERROR, "Header chunk is missing\n");
93         return -1;
94     }
95     if(get_be32(pb) != 32){
96         av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n");
97         return -1;
98     }
99     if(get_le16(pb) != 1){
100         av_log(s, AV_LOG_ERROR, "Incorrect header version\n");
101         return -1;
102     }
103     width = get_le16(pb);
104     height = get_le16(pb);
105     url_fskip(pb, 4);
106     c->frames = get_le16(pb);
107     if(!c->frames){
108         av_log(s, AV_LOG_ERROR, "File contains no frames ???\n");
109         return -1;
110     }
111     c->bits = get_le16(pb);
112     c->rate = get_le16(pb);
113     c->block_align = c->rate * (c->bits >> 3);
114
115     url_fskip(pb, 16); //zeroes
116
117     st = av_new_stream(s, 0);
118     if (!st)
119         return -1;
120     st->codec->codec_type = CODEC_TYPE_VIDEO;
121     st->codec->codec_id   = CODEC_ID_VB;
122     st->codec->codec_tag  = MKTAG('V', 'B', 'V', '1');
123     st->codec->width      = width;
124     st->codec->height     = height;
125     st->codec->pix_fmt    = PIX_FMT_PAL8;
126     av_set_pts_info(st, 16, 1, 12);
127
128     c->cur_frame = 0;
129     c->has_video = 1;
130     c->has_audio = !!c->rate;
131     c->curstrm = -1;
132     if (c->has_audio && create_audio_stream(s, c) < 0)
133         return -1;
134     return 0;
135 }
136
137 static int siff_parse_soun(AVFormatContext *s, SIFFContext *c, ByteIOContext *pb)
138 {
139     if (get_le32(pb) != TAG_SHDR){
140         av_log(s, AV_LOG_ERROR, "Header chunk is missing\n");
141         return -1;
142     }
143     if(get_be32(pb) != 8){
144         av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n");
145         return -1;
146     }
147     url_fskip(pb, 4); //unknown value
148     c->rate = get_le16(pb);
149     c->bits = get_le16(pb);
150     c->block_align = c->rate * (c->bits >> 3);
151     return create_audio_stream(s, c);
152 }
153
154 static int siff_read_header(AVFormatContext *s, AVFormatParameters *ap)
155 {
156     ByteIOContext *pb = s->pb;
157     SIFFContext *c = s->priv_data;
158     uint32_t tag;
159
160     if (get_le32(pb) != TAG_SIFF)
161         return -1;
162     url_fskip(pb, 4); //ignore size
163     tag = get_le32(pb);
164
165     if (tag != TAG_VBV1 && tag != TAG_SOUN){
166         av_log(s, AV_LOG_ERROR, "Not a VBV file\n");
167         return -1;
168     }
169
170     if (tag == TAG_VBV1 && siff_parse_vbv1(s, c, pb) < 0)
171         return -1;
172     if (tag == TAG_SOUN && siff_parse_soun(s, c, pb) < 0)
173         return -1;
174     if (get_le32(pb) != MKTAG('B', 'O', 'D', 'Y')){
175         av_log(s, AV_LOG_ERROR, "'BODY' chunk is missing\n");
176         return -1;
177     }
178     url_fskip(pb, 4); //ignore size
179
180     return 0;
181 }
182
183 static int siff_read_packet(AVFormatContext *s, AVPacket *pkt)
184 {
185     SIFFContext *c = s->priv_data;
186     int size;
187
188     if (c->has_video){
189         if (c->cur_frame >= c->frames)
190             return AVERROR(EIO);
191         if (c->curstrm == -1){
192             c->pktsize = get_le32(s->pb) - 4;
193             c->flags = get_le16(s->pb);
194             c->gmcsize = (c->flags & VB_HAS_GMC) ? 4 : 0;
195             if (c->gmcsize)
196                 get_buffer(s->pb, c->gmc, c->gmcsize);
197             c->sndsize = (c->flags & VB_HAS_AUDIO) ? get_le32(s->pb): 0;
198             c->curstrm = !!(c->flags & VB_HAS_AUDIO);
199         }
200
201         if (!c->curstrm){
202             size = c->pktsize - c->sndsize;
203             if (av_new_packet(pkt, size) < 0)
204                 return AVERROR(ENOMEM);
205             AV_WL16(pkt->data, c->flags);
206             if (c->gmcsize)
207                 memcpy(pkt->data + 2, c->gmc, c->gmcsize);
208             get_buffer(s->pb, pkt->data + 2 + c->gmcsize, size - c->gmcsize - 2);
209             pkt->stream_index = 0;
210             c->curstrm = -1;
211         }else{
212             if (av_get_packet(s->pb, pkt, c->sndsize - 4) < 0)
213                 return AVERROR(EIO);
214             pkt->stream_index = 1;
215             c->curstrm = 0;
216         }
217         if(!c->cur_frame || c->curstrm)
218             pkt->flags |= PKT_FLAG_KEY;
219         if (c->curstrm == -1)
220             c->cur_frame++;
221     }else{
222         size = av_get_packet(s->pb, pkt, c->block_align);
223         if(size <= 0)
224             return AVERROR(EIO);
225     }
226     return pkt->size;
227 }
228
229 AVInputFormat siff_demuxer = {
230     "siff",
231     NULL_IF_CONFIG_SMALL("Beam Software SIFF"),
232     sizeof(SIFFContext),
233     siff_probe,
234     siff_read_header,
235     siff_read_packet,
236     .extensions = "vb,son"
237 };