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
rtpdec_asf.c
Go to the documentation of this file.
1
/*
2
* Microsoft RTP/ASF support.
3
* Copyright (c) 2008 Ronald S. Bultje
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 Microsoft RTP/ASF support
25
* @author Ronald S. Bultje <rbultje@ronald.bitfreak.net>
26
*/
27
28
#include "
libavutil/avassert.h
"
29
#include "
libavutil/base64.h
"
30
#include "
libavutil/avstring.h
"
31
#include "
libavutil/intreadwrite.h
"
32
#include "
rtp.h
"
33
#include "
rtpdec_formats.h
"
34
#include "
rtsp.h
"
35
#include "
asf.h
"
36
#include "
avio_internal.h
"
37
#include "
internal.h
"
38
39
/**
40
* From MSDN 2.2.1.4, we learn that ASF data packets over RTP should not
41
* contain any padding. Unfortunately, the header min/max_pktsize are not
42
* updated (thus making min_pktsize invalid). Here, we "fix" these faulty
43
* min_pktsize values in the ASF file header.
44
* @return 0 on success, <0 on failure (currently -1).
45
*/
46
static
int
rtp_asf_fix_header
(
uint8_t
*
buf
,
int
len
)
47
{
48
uint8_t
*p =
buf
, *
end
= buf +
len
;
49
50
if
(len <
sizeof
(
ff_asf_guid
) * 2 + 22 ||
51
memcmp(p,
ff_asf_header
,
sizeof
(
ff_asf_guid
))) {
52
return
-1;
53
}
54
p +=
sizeof
(
ff_asf_guid
) + 14;
55
do
{
56
uint64_t chunksize =
AV_RL64
(p +
sizeof
(
ff_asf_guid
));
57
if
(memcmp(p,
ff_asf_file_header
,
sizeof
(
ff_asf_guid
))) {
58
if
(chunksize > end - p)
59
return
-1;
60
p += chunksize;
61
continue
;
62
}
63
64
/* skip most of the file header, to min_pktsize */
65
p += 6 * 8 + 3 * 4 +
sizeof
(
ff_asf_guid
) * 2;
66
if
(p + 8 <= end &&
AV_RL32
(p) ==
AV_RL32
(p + 4)) {
67
/* and set that to zero */
68
AV_WL32
(p, 0);
69
return
0;
70
}
71
break
;
72
}
while
(end - p >=
sizeof
(
ff_asf_guid
) + 8);
73
74
return
-1;
75
}
76
77
/**
78
* The following code is basically a buffered AVIOContext,
79
* with the added benefit of returning -EAGAIN (instead of 0)
80
* on packet boundaries, such that the ASF demuxer can return
81
* safely and resume business at the next packet.
82
*/
83
static
int
packetizer_read
(
void
*opaque,
uint8_t
*
buf
,
int
buf_size)
84
{
85
return
AVERROR
(EAGAIN);
86
}
87
88
static
void
init_packetizer
(
AVIOContext
*pb,
uint8_t
*
buf
,
int
len
)
89
{
90
ffio_init_context
(pb, buf, len, 0,
NULL
,
packetizer_read
,
NULL
,
NULL
);
91
92
/* this "fills" the buffer with its current content */
93
pb->
pos
=
len
;
94
pb->
buf_end
= buf +
len
;
95
}
96
97
int
ff_wms_parse_sdp_a_line
(
AVFormatContext
*
s
,
const
char
*p)
98
{
99
int
ret
= 0;
100
if
(
av_strstart
(p,
"pgmpu:data:application/vnd.ms.wms-hdr.asfv1;base64,"
, &p)) {
101
AVIOContext
pb;
102
RTSPState
*rt = s->
priv_data
;
103
AVDictionary
*opts =
NULL
;
104
int
len
= strlen(p) * 6 / 8;
105
char
*
buf
=
av_mallocz
(len);
106
AVInputFormat
*
iformat
;
107
108
av_base64_decode
(buf, p, len);
109
110
if
(
rtp_asf_fix_header
(buf, len) < 0)
111
av_log
(s,
AV_LOG_ERROR
,
112
"Failed to fix invalid RTSP-MS/ASF min_pktsize\n"
);
113
init_packetizer
(&pb, buf, len);
114
if
(rt->
asf_ctx
) {
115
avformat_close_input
(&rt->
asf_ctx
);
116
}
117
if
(!(iformat =
av_find_input_format
(
"asf"
)))
118
return
AVERROR_DEMUXER_NOT_FOUND
;
119
if
(!(rt->
asf_ctx
=
avformat_alloc_context
()))
120
return
AVERROR
(ENOMEM);
121
rt->
asf_ctx
->
pb
= &pb;
122
av_dict_set
(&opts,
"no_resync_search"
,
"1"
, 0);
123
124
if
((ret =
ff_copy_whitelists
(rt->
asf_ctx
, s)) < 0) {
125
av_dict_free
(&opts);
126
return
ret
;
127
}
128
129
ret =
avformat_open_input
(&rt->
asf_ctx
,
""
, iformat, &opts);
130
av_dict_free
(&opts);
131
if
(ret < 0)
132
return
ret
;
133
av_dict_copy
(&s->
metadata
, rt->
asf_ctx
->
metadata
, 0);
134
rt->
asf_pb_pos
=
avio_tell
(&pb);
135
av_free
(buf);
136
rt->
asf_ctx
->
pb
=
NULL
;
137
}
138
return
ret
;
139
}
140
141
static
int
asfrtp_parse_sdp_line
(
AVFormatContext
*
s
,
int
stream_index,
142
PayloadContext
*asf,
const
char
*
line
)
143
{
144
if
(stream_index < 0)
145
return
0;
146
if
(
av_strstart
(line,
"stream:"
, &line)) {
147
RTSPState
*rt = s->
priv_data
;
148
149
s->
streams
[stream_index]->
id
= strtol(line,
NULL
, 10);
150
151
if
(rt->
asf_ctx
) {
152
int
i;
153
154
for
(i = 0; i < rt->
asf_ctx
->
nb_streams
; i++) {
155
if
(s->
streams
[stream_index]->
id
== rt->
asf_ctx
->
streams
[i]->
id
) {
156
*s->
streams
[stream_index]->
codec
=
157
*rt->
asf_ctx
->
streams
[i]->
codec
;
158
s->
streams
[stream_index]->
need_parsing
=
159
rt->
asf_ctx
->
streams
[i]->
need_parsing
;
160
rt->
asf_ctx
->
streams
[i]->
codec
->
extradata_size
= 0;
161
rt->
asf_ctx
->
streams
[i]->
codec
->
extradata
=
NULL
;
162
avpriv_set_pts_info
(s->
streams
[stream_index], 32, 1, 1000);
163
}
164
}
165
}
166
}
167
168
return
0;
169
}
170
171
struct
PayloadContext
{
172
AVIOContext
*
pktbuf
,
pb
;
173
uint8_t
*
buf
;
174
};
175
176
/**
177
* @return 0 when a packet was written into /p pkt, and no more data is left;
178
* 1 when a packet was written into /p pkt, and more packets might be left;
179
* <0 when not enough data was provided to return a full packet, or on error.
180
*/
181
static
int
asfrtp_parse_packet
(
AVFormatContext
*
s
,
PayloadContext
*asf,
182
AVStream
*st,
AVPacket
*
pkt
,
183
uint32_t *timestamp,
184
const
uint8_t
*
buf
,
int
len
, uint16_t seq,
185
int
flags
)
186
{
187
AVIOContext
*pb = &asf->
pb
;
188
int
res, mflags, len_off;
189
RTSPState
*rt = s->
priv_data
;
190
191
if
(!rt->
asf_ctx
)
192
return
-1;
193
194
if
(len > 0) {
195
int
off, out_len = 0;
196
197
if
(len < 4)
198
return
-1;
199
200
av_freep
(&asf->
buf
);
201
202
ffio_init_context
(pb, (
uint8_t
*)buf, len, 0,
NULL
,
NULL
,
NULL
,
NULL
);
203
204
while
(
avio_tell
(pb) + 4 < len) {
205
int
start_off =
avio_tell
(pb);
206
207
mflags =
avio_r8
(pb);
208
len_off =
avio_rb24
(pb);
209
if
(mflags & 0x20)
/**< relative timestamp */
210
avio_skip
(pb, 4);
211
if
(mflags & 0x10)
/**< has duration */
212
avio_skip
(pb, 4);
213
if
(mflags & 0x8)
/**< has location ID */
214
avio_skip
(pb, 4);
215
off =
avio_tell
(pb);
216
217
if
(!(mflags & 0x40)) {
218
/**
219
* If 0x40 is not set, the len_off field specifies an offset
220
* of this packet's payload data in the complete (reassembled)
221
* ASF packet. This is used to spread one ASF packet over
222
* multiple RTP packets.
223
*/
224
if
(asf->
pktbuf
&& len_off !=
avio_tell
(asf->
pktbuf
)) {
225
ffio_free_dyn_buf
(&asf->
pktbuf
);
226
}
227
if
(!len_off && !asf->
pktbuf
&&
228
(res =
avio_open_dyn_buf
(&asf->
pktbuf
)) < 0)
229
return
res;
230
if
(!asf->
pktbuf
)
231
return
AVERROR
(EIO);
232
233
avio_write
(asf->
pktbuf
, buf + off, len - off);
234
avio_skip
(pb, len - off);
235
if
(!(flags &
RTP_FLAG_MARKER
))
236
return
-1;
237
out_len =
avio_close_dyn_buf
(asf->
pktbuf
, &asf->
buf
);
238
asf->
pktbuf
=
NULL
;
239
}
else
{
240
/**
241
* If 0x40 is set, the len_off field specifies the length of
242
* the next ASF packet that can be read from this payload
243
* data alone. This is commonly the same as the payload size,
244
* but could be less in case of packet splitting (i.e.
245
* multiple ASF packets in one RTP packet).
246
*/
247
248
int
cur_len = start_off + len_off - off;
249
int
prev_len = out_len;
250
out_len += cur_len;
251
if
(
FFMIN
(cur_len, len - off) < 0)
252
return
-1;
253
if
((res =
av_reallocp
(&asf->
buf
, out_len)) < 0)
254
return
res;
255
memcpy(asf->
buf
+ prev_len, buf + off,
256
FFMIN
(cur_len, len - off));
257
avio_skip
(pb, cur_len);
258
}
259
}
260
261
init_packetizer
(pb, asf->
buf
, out_len);
262
pb->
pos
+= rt->
asf_pb_pos
;
263
pb->
eof_reached
= 0;
264
rt->
asf_ctx
->
pb
= pb;
265
}
266
267
for
(;;) {
268
int
i;
269
270
res =
ff_read_packet
(rt->
asf_ctx
, pkt);
271
rt->
asf_pb_pos
=
avio_tell
(pb);
272
if
(res != 0)
273
break
;
274
for
(i = 0; i < s->
nb_streams
; i++) {
275
if
(s->
streams
[i]->
id
== rt->
asf_ctx
->
streams
[pkt->
stream_index
]->
id
) {
276
pkt->
stream_index
= i;
277
return
1;
// FIXME: return 0 if last packet
278
}
279
}
280
av_free_packet
(pkt);
281
}
282
283
return
res == 1 ? -1 : res;
284
}
285
286
static
void
asfrtp_close_context
(
PayloadContext
*asf)
287
{
288
ffio_free_dyn_buf
(&asf->
pktbuf
);
289
av_freep
(&asf->
buf
);
290
}
291
292
#define RTP_ASF_HANDLER(n, s, t) \
293
RTPDynamicProtocolHandler ff_ms_rtp_ ## n ## _handler = { \
294
.enc_name = s, \
295
.codec_type = t, \
296
.codec_id = AV_CODEC_ID_NONE, \
297
.priv_data_size = sizeof(PayloadContext), \
298
.parse_sdp_a_line = asfrtp_parse_sdp_line, \
299
.close = asfrtp_close_context, \
300
.parse_packet = asfrtp_parse_packet, \
301
}
302
303
RTP_ASF_HANDLER
(asf_pfv,
"x-asf-pf"
,
AVMEDIA_TYPE_VIDEO
);
304
RTP_ASF_HANDLER
(asf_pfa,
"x-asf-pf"
,
AVMEDIA_TYPE_AUDIO
);
Generated on Sun Mar 8 2015 02:35:12 for FFmpeg by
1.8.2