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