FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavformat
vivo.c
Go to the documentation of this file.
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
33
typedef
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
43
static
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
72
static
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
(
avio_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
118
static
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
244
static
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
251
restart:
252
253
if
(
avio_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
(
avio_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
299
fail:
300
if
(ret < 0)
301
av_free_packet
(pkt);
302
return
ret
;
303
}
304
305
AVInputFormat
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
};
Generated on Fri Dec 5 2014 04:42:14 for FFmpeg by
1.8.2