1 /*
2 * Vivo stream demuxer
3 * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
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 /**
23 * @file
24 * @brief Vivo stream demuxer
25 * @author Daniel Verkamp <daniel at drv.nu>
26 * @sa http://wiki.multimedia.cx/index.php?title=Vivo
27 */
28
29 #include "libavutil/avstring.h"
30 #include "libavutil/parseutils.h"
31 #include "avformat.h"
32 #include "internal.h"
33
34 typedef struct VivoContext {
35 int version;
36
37 int type;
38 int sequence;
39 int length;
40 int duration;
41
42 uint8_t text[1024 + 1];
43 } VivoContext;
44
vivo_probe(const AVProbeData *p)45 static int vivo_probe(const AVProbeData *p)
46 {
47 const unsigned char *buf = p->buf;
48 unsigned c, length = 0;
49
50 // stream must start with packet of type 0 and sequence number 0
51 if (*buf++ != 0)
52 return 0;
53
54 // read at most 2 bytes of coded length
55 c = *buf++;
56 length = c & 0x7F;
57 if (c & 0x80) {
58 c = *buf++;
59 length = (length << 7) | (c & 0x7F);
60 }
61 if (c & 0x80 || length > 1024 || length < 21)
62 return 0;
63
64 buf += 2;
65 if (memcmp(buf, "Version:Vivo/", 13))
66 return 0;
67 buf += 13;
68
69 if (*buf < '0' || *buf > '2')
70 return 0;
71
72 return AVPROBE_SCORE_MAX;
73 }
74
vivo_get_packet_header(AVFormatContext *s)75 static int vivo_get_packet_header(AVFormatContext *s)
76 {
77 VivoContext *vivo = s->priv_data;
78 AVIOContext *pb = s->pb;
79 unsigned c, get_length = 0;
80
81 if (avio_feof(pb))
82 return AVERROR_EOF;
83
84 c = avio_r8(pb);
85 if (c == 0x82) {
86 get_length = 1;
87 c = avio_r8(pb);
88 }
89
90 vivo->type = c >> 4;
91 vivo->sequence = c & 0xF;
92
93 switch (vivo->type) {
94 case 0: get_length = 1; break;
95 case 1: vivo->length = 128; break;
96 case 2: get_length = 1; break;
97 case 3: vivo->length = 40; break;
98 case 4: vivo->length = 24; break;
99 default:
100 av_log(s, AV_LOG_ERROR, "unknown packet type %d\n", vivo->type);
101 return AVERROR_INVALIDDATA;
102 }
103
104 if (get_length) {
105 c = avio_r8(pb);
106 vivo->length = c & 0x7F;
107 if (c & 0x80) {
108 c = avio_r8(pb);
109 vivo->length = (vivo->length << 7) | (c & 0x7F);
110
111 if (c & 0x80) {
112 av_log(s, AV_LOG_ERROR, "coded length is more than two bytes\n");
113 return AVERROR_INVALIDDATA;
114 }
115 }
116 }
117
118 return 0;
119 }
120
vivo_read_header(AVFormatContext *s)121 static int vivo_read_header(AVFormatContext *s)
122 {
123 VivoContext *vivo = s->priv_data;
124 AVRational fps = { 0 };
125 AVStream *ast, *vst;
126 unsigned char *line, *line_end, *key, *value;
127 long value_int;
128 int ret, value_used;
129 int64_t duration = 0;
130 char *end_value;
131
132 vst = avformat_new_stream(s, NULL);
133 ast = avformat_new_stream(s, NULL);
134 if (!ast || !vst)
135 return AVERROR(ENOMEM);
136
137 ast->codecpar->sample_rate = 8000;
138
139 while (1) {
140 if ((ret = vivo_get_packet_header(s)) < 0)
141 return ret;
142
143 // done reading all text header packets?
144 if (vivo->sequence || vivo->type)
145 break;
146
147 if (vivo->length <= 1024) {
148 avio_read(s->pb, vivo->text, vivo->length);
149 vivo->text[vivo->length] = 0;
150 } else {
151 av_log(s, AV_LOG_WARNING, "too big header, skipping\n");
152 avio_skip(s->pb, vivo->length);
153 continue;
154 }
155
156 line = vivo->text;
157 while (*line) {
158 line_end = strstr(line, "\r\n");
159 if (!line_end)
160 break;
161
162 *line_end = 0;
163 key = line;
164 line = line_end + 2; // skip \r\n
165
166 if (line_end == key) // skip blank lines
167 continue;
168
169 value = strchr(key, ':');
170 if (!value) {
171 av_log(s, AV_LOG_WARNING, "missing colon in key:value pair '%s'\n",
172 key);
173 continue;
174 }
175
176 *value++ = 0;
177
178 av_log(s, AV_LOG_DEBUG, "header: '%s' = '%s'\n", key, value);
179
180 value_int = strtol(value, &end_value, 10);
181 value_used = 0;
182 if (*end_value == 0) { // valid integer
183 av_log(s, AV_LOG_DEBUG, "got a valid integer (%ld)\n", value_int);
184 value_used = 1;
185 if (!strcmp(key, "Duration")) {
186 duration = value_int;
187 } else if (!strcmp(key, "Width")) {
188 vst->codecpar->width = value_int;
189 } else if (!strcmp(key, "Height")) {
190 vst->codecpar->height = value_int;
191 } else if (!strcmp(key, "TimeUnitNumerator")) {
192 fps.num = value_int / 1000;
193 } else if (!strcmp(key, "TimeUnitDenominator")) {
194 fps.den = value_int;
195 } else if (!strcmp(key, "SamplingFrequency")) {
196 ast->codecpar->sample_rate = value_int;
197 } else if (!strcmp(key, "NominalBitrate")) {
198 } else if (!strcmp(key, "Length")) {
199 // size of file
200 } else {
201 value_used = 0;
202 }
203 }
204
205 if (!strcmp(key, "Version")) {
206 if (sscanf(value, "Vivo/%d.", &vivo->version) != 1)
207 return AVERROR_INVALIDDATA;
208 value_used = 1;
209 } else if (!strcmp(key, "FPS")) {
210 double d;
211 if (av_sscanf(value, "%f", &d) != 1)
212 return AVERROR_INVALIDDATA;
213
214 value_used = 1;
215 if (!fps.num && !fps.den)
216 fps = av_inv_q(av_d2q(d, 10000));
217 }
218
219 if (!value_used)
220 av_dict_set(&s->metadata, key, value, 0);
221 }
222 }
223 if (!fps.num || !fps.den)
224 fps = (AVRational){ 1, 25 };
225
226 avpriv_set_pts_info(ast, 64, 1, ast->codecpar->sample_rate);
227 avpriv_set_pts_info(vst, 64, fps.num, fps.den);
228 if (duration)
229 s->duration = av_rescale(duration, 1000, 1);
230
231 vst->start_time = 0;
232 vst->codecpar->codec_tag = 0;
233 vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
234
235 if (vivo->version == 1) {
236 vst->codecpar->codec_id = AV_CODEC_ID_H263;
237 ast->codecpar->codec_id = AV_CODEC_ID_G723_1;
238 ast->codecpar->bits_per_coded_sample = 8;
239 ast->codecpar->block_align = 24;
240 ast->codecpar->bit_rate = 6400;
241 } else {
242 ast->codecpar->codec_id = AV_CODEC_ID_SIREN;
243 ast->codecpar->bits_per_coded_sample = 16;
244 ast->codecpar->block_align = 40;
245 ast->codecpar->bit_rate = 6400;
246 vivo->duration = 320;
247 }
248
249 ast->start_time = 0;
250 ast->codecpar->codec_tag = 0;
251 ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
252 ast->codecpar->ch_layout.nb_channels = 1;
253
254 return 0;
255 }
256
vivo_read_packet(AVFormatContext *s, AVPacket *pkt)257 static int vivo_read_packet(AVFormatContext *s, AVPacket *pkt)
258 {
259 VivoContext *vivo = s->priv_data;
260 AVIOContext *pb = s->pb;
261 unsigned old_sequence = vivo->sequence, old_type = vivo->type;
262 int stream_index, duration, ret = 0;
263
264 restart:
265
266 if (avio_feof(pb))
267 return AVERROR_EOF;
268
269 switch (vivo->type) {
270 case 0:
271 avio_skip(pb, vivo->length);
272 if ((ret = vivo_get_packet_header(s)) < 0)
273 return ret;
274 goto restart;
275 case 1:
276 case 2: // video
277 stream_index = 0;
278 duration = 1;
279 break;
280 case 3:
281 case 4: // audio
282 stream_index = 1;
283 duration = vivo->duration;
284 break;
285 default:
286 av_log(s, AV_LOG_ERROR, "unknown packet type %d\n", vivo->type);
287 return AVERROR_INVALIDDATA;
288 }
289
290 if ((ret = av_get_packet(pb, pkt, vivo->length)) < 0)
291 return ret;
292
293 // get next packet header
294 if ((ret = vivo_get_packet_header(s)) < 0)
295 return ret;
296
297 while (vivo->sequence == old_sequence &&
298 (((vivo->type - 1) >> 1) == ((old_type - 1) >> 1))) {
299 if (avio_feof(pb)) {
300 return AVERROR_EOF;
301 }
302
303 if ((ret = av_append_packet(pb, pkt, vivo->length)) < 0)
304 return ret;
305
306 // get next packet header
307 if ((ret = vivo_get_packet_header(s)) < 0)
308 return ret;
309 }
310
311 pkt->stream_index = stream_index;
312 pkt->duration = duration;
313
314 return ret;
315 }
316
317 const AVInputFormat ff_vivo_demuxer = {
318 .name = "vivo",
319 .long_name = NULL_IF_CONFIG_SMALL("Vivo"),
320 .priv_data_size = sizeof(VivoContext),
321 .read_probe = vivo_probe,
322 .read_header = vivo_read_header,
323 .read_packet = vivo_read_packet,
324 .extensions = "viv",
325 };
326