FFmpeg
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/base64.h"
29 #include "libavutil/avstring.h"
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/mem.h"
32 #include "rtpdec_formats.h"
33 #include "rtsp.h"
34 #include "asf.h"
35 #include "avio_internal.h"
36 #include "demux.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  int skip = 6 * 8 + 3 * 4 + sizeof(ff_asf_guid) * 2;
58  if (memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) {
59  if (chunksize < sizeof(ff_asf_guid) + 8)
60  return -1;
61  if (chunksize > end - p)
62  return -1;
63  p += chunksize;
64  continue;
65  }
66 
67  if (end - p < 8 + skip)
68  break;
69  /* skip most of the file header, to min_pktsize */
70  p += skip;
71  if (AV_RL32(p) == AV_RL32(p + 4)) {
72  /* and set that to zero */
73  AV_WL32(p, 0);
74  return 0;
75  }
76  break;
77  } while (end - p >= sizeof(ff_asf_guid) + 8);
78 
79  return -1;
80 }
81 
82 /**
83  * The following code is basically a buffered AVIOContext,
84  * with the added benefit of returning -EAGAIN (instead of 0)
85  * on packet boundaries, such that the ASF demuxer can return
86  * safely and resume business at the next packet.
87  */
88 static int packetizer_read(void *opaque, uint8_t *buf, int buf_size)
89 {
90  return AVERROR(EAGAIN);
91 }
92 
93 static void init_packetizer(FFIOContext *pb, uint8_t *buf, int len)
94 {
96 
97  /* this "fills" the buffer with its current content */
98  pb->pub.pos = len;
99  pb->pub.buf_end = buf + len;
100 }
101 
103 {
104  int ret = 0;
105  if (av_strstart(p, "pgmpu:data:application/vnd.ms.wms-hdr.asfv1;base64,", &p)) {
106  FFIOContext pb;
107  RTSPState *rt = s->priv_data;
109  int len = strlen(p) * 6 / 8;
110  char *buf = av_mallocz(len);
111  const AVInputFormat *iformat;
112 
113  if (!buf)
114  return AVERROR(ENOMEM);
115  av_base64_decode(buf, p, len);
116 
117  if (rtp_asf_fix_header(buf, len) < 0)
119  "Failed to fix invalid RTSP-MS/ASF min_pktsize\n");
120  init_packetizer(&pb, buf, len);
121  if (rt->asf_ctx) {
123  }
124 
125  if (!(iformat = av_find_input_format("asf"))) {
126  av_free(buf);
128  }
129 
131  if (!rt->asf_ctx) {
132  av_free(buf);
133  return AVERROR(ENOMEM);
134  }
135  rt->asf_ctx->pb = &pb.pub;
136  av_dict_set(&opts, "no_resync_search", "1", 0);
137 
138  if ((ret = ff_copy_whiteblacklists(rt->asf_ctx, s)) < 0) {
139  av_dict_free(&opts);
140  return ret;
141  }
142 
143  ret = avformat_open_input(&rt->asf_ctx, "", iformat, &opts);
144  av_dict_free(&opts);
145  if (ret < 0) {
146  av_free(pb.pub.buffer);
147  return ret;
148  }
149  av_dict_copy(&s->metadata, rt->asf_ctx->metadata, 0);
150  rt->asf_pb_pos = avio_tell(&pb.pub);
151  av_free(pb.pub.buffer);
152  rt->asf_ctx->pb = NULL;
153  }
154  return ret;
155 }
156 
157 static int asfrtp_parse_sdp_line(AVFormatContext *s, int stream_index,
158  PayloadContext *asf, const char *line)
159 {
160  if (stream_index < 0)
161  return 0;
162  if (av_strstart(line, "stream:", &line)) {
163  RTSPState *rt = s->priv_data;
164 
165  s->streams[stream_index]->id = strtol(line, NULL, 10);
166 
167  if (rt->asf_ctx) {
168  int i;
169 
170  for (i = 0; i < rt->asf_ctx->nb_streams; i++) {
171  if (s->streams[stream_index]->id == rt->asf_ctx->streams[i]->id) {
172  avcodec_parameters_copy(s->streams[stream_index]->codecpar,
173  rt->asf_ctx->streams[i]->codecpar);
174  ffstream(s->streams[stream_index])->need_parsing =
176  avpriv_set_pts_info(s->streams[stream_index], 32, 1, 1000);
177  }
178  }
179  }
180  }
181 
182  return 0;
183 }
184 
185 struct PayloadContext {
188  uint8_t *buf;
189 };
190 
191 /**
192  * @return 0 when a packet was written into /p pkt, and no more data is left;
193  * 1 when a packet was written into /p pkt, and more packets might be left;
194  * <0 when not enough data was provided to return a full packet, or on error.
195  */
197  AVStream *st, AVPacket *pkt,
198  uint32_t *timestamp,
199  const uint8_t *buf, int len, uint16_t seq,
200  int flags)
201 {
202  FFIOContext *const pb0 = &asf->pb;
203  AVIOContext *const pb = &pb0->pub;
204  int res, mflags, len_off;
205  RTSPState *rt = s->priv_data;
206 
207  if (!rt->asf_ctx)
208  return -1;
209 
210  if (len > 0) {
211  int off, out_len = 0;
212 
213  if (len < 4)
214  return -1;
215 
216  av_freep(&asf->buf);
217 
218  ffio_init_read_context(pb0, buf, len);
219 
220  while (avio_tell(pb) + 4 < len) {
221  int start_off = avio_tell(pb);
222 
223  mflags = avio_r8(pb);
224  len_off = avio_rb24(pb);
225  if (mflags & 0x20) /**< relative timestamp */
226  avio_skip(pb, 4);
227  if (mflags & 0x10) /**< has duration */
228  avio_skip(pb, 4);
229  if (mflags & 0x8) /**< has location ID */
230  avio_skip(pb, 4);
231  off = avio_tell(pb);
232 
233  if (!(mflags & 0x40)) {
234  /**
235  * If 0x40 is not set, the len_off field specifies an offset
236  * of this packet's payload data in the complete (reassembled)
237  * ASF packet. This is used to spread one ASF packet over
238  * multiple RTP packets.
239  */
240  if (asf->pktbuf && len_off != avio_tell(asf->pktbuf)) {
241  ffio_free_dyn_buf(&asf->pktbuf);
242  }
243  if (!len_off && !asf->pktbuf &&
244  (res = avio_open_dyn_buf(&asf->pktbuf)) < 0)
245  return res;
246  if (!asf->pktbuf)
247  return AVERROR(EIO);
248 
249  avio_write(asf->pktbuf, buf + off, len - off);
250  avio_skip(pb, len - off);
251  if (!(flags & RTP_FLAG_MARKER))
252  return -1;
253  out_len = avio_close_dyn_buf(asf->pktbuf, &asf->buf);
254  asf->pktbuf = NULL;
255  } else {
256  /**
257  * If 0x40 is set, the len_off field specifies the length of
258  * the next ASF packet that can be read from this payload
259  * data alone. This is commonly the same as the payload size,
260  * but could be less in case of packet splitting (i.e.
261  * multiple ASF packets in one RTP packet).
262  */
263 
264  int cur_len = start_off + len_off - off;
265  int prev_len = out_len;
266  out_len += cur_len;
267  if (FFMIN(cur_len, len - off) < 0)
268  return -1;
269  if ((res = av_reallocp(&asf->buf, out_len)) < 0)
270  return res;
271  memcpy(asf->buf + prev_len, buf + off,
272  FFMIN(cur_len, len - off));
273  avio_skip(pb, cur_len);
274  }
275  }
276 
277  init_packetizer(pb0, asf->buf, out_len);
278  pb->pos += rt->asf_pb_pos;
279  pb->eof_reached = 0;
280  rt->asf_ctx->pb = pb;
281  }
282 
283  for (;;) {
284  int i;
285 
286  res = ff_read_packet(rt->asf_ctx, pkt);
287  rt->asf_pb_pos = avio_tell(pb);
288  if (res != 0)
289  break;
290  for (i = 0; i < s->nb_streams; i++) {
291  if (s->streams[i]->id == rt->asf_ctx->streams[pkt->stream_index]->id) {
292  pkt->stream_index = i;
293  return 1; // FIXME: return 0 if last packet
294  }
295  }
297  }
298 
299  return res == 1 ? -1 : res;
300 }
301 
303 {
304  ffio_free_dyn_buf(&asf->pktbuf);
305  av_freep(&asf->buf);
306 }
307 
308 #define RTP_ASF_HANDLER(n, s, t) \
309 const RTPDynamicProtocolHandler ff_ms_rtp_ ## n ## _handler = { \
310  .enc_name = s, \
311  .codec_type = t, \
312  .codec_id = AV_CODEC_ID_NONE, \
313  .priv_data_size = sizeof(PayloadContext), \
314  .parse_sdp_a_line = asfrtp_parse_sdp_line, \
315  .close = asfrtp_close_context, \
316  .parse_packet = asfrtp_parse_packet, \
317 }
318 
319 RTP_ASF_HANDLER(asf_pfv, "x-asf-pf", AVMEDIA_TYPE_VIDEO);
320 RTP_ASF_HANDLER(asf_pfa, "x-asf-pf", AVMEDIA_TYPE_AUDIO);
packetizer_read
static int packetizer_read(void *opaque, uint8_t *buf, int buf_size)
The following code is basically a buffered AVIOContext, with the added benefit of returning -EAGAIN (...
Definition: rtpdec_asf.c:88
flags
const SwsFlags flags[]
Definition: swscale.c:85
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: packet.c:434
ffio_init_context
void ffio_init_context(FFIOContext *s, unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, const uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Definition: aviobuf.c:50
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
AV_WL32
#define AV_WL32(p, v)
Definition: intreadwrite.h:422
AV_RL64
uint64_t_TMPL AV_RL64
Definition: bytestream.h:91
rtpdec_formats.h
asfrtp_close_context
static void asfrtp_close_context(PayloadContext *asf)
Definition: rtpdec_asf.c:302
AVFormatContext::streams
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1382
RTP_FLAG_MARKER
#define RTP_FLAG_MARKER
RTP marker bit was set for this packet.
Definition: rtpdec.h:94
AVDictionary
Definition: dict.c:32
ffio_init_read_context
void ffio_init_read_context(FFIOContext *s, const uint8_t *buffer, int buffer_size)
Wrap a buffer in an AVIOContext for reading.
Definition: aviobuf.c:99
FFIOContext
Definition: avio_internal.h:28
RTSPState::asf_ctx
AVFormatContext * asf_ctx
The following are used for RTP/ASF streams.
Definition: rtsp.h:337
avformat_close_input
void avformat_close_input(AVFormatContext **s)
Close an opened input AVFormatContext.
Definition: demux.c:377
avpriv_set_pts_info
void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: avformat.c:829
ffstream
static av_always_inline FFStream * ffstream(AVStream *st)
Definition: internal.h:358
AVIOContext::pos
int64_t pos
position in the file of the current buffer
Definition: avio.h:237
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:494
rtsp.h
avio_close_dyn_buf
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
Return the written size and a pointer to the buffer.
Definition: aviobuf.c:1410
PayloadContext::pktbuf
AVIOContext * pktbuf
Definition: rtpdec_asf.c:187
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
AVFormatContext::metadata
AVDictionary * metadata
Metadata that applies to the whole file.
Definition: avformat.h:1546
AVInputFormat
Definition: avformat.h:546
avformat_open_input
int avformat_open_input(AVFormatContext **ps, const char *url, const AVInputFormat *fmt, AVDictionary **options)
Open an input stream and read the header.
Definition: demux.c:231
avio_open_dyn_buf
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:1365
intreadwrite.h
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:201
RTP_ASF_HANDLER
#define RTP_ASF_HANDLER(n, s, t)
Definition: rtpdec_asf.c:308
PayloadContext::pb
FFIOContext pb
Definition: rtpdec_asf.c:186
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
AVERROR_DEMUXER_NOT_FOUND
#define AVERROR_DEMUXER_NOT_FOUND
Demuxer not found.
Definition: error.h:55
FFStream::need_parsing
enum AVStreamParseType need_parsing
Definition: internal.h:314
AVFormatContext
Format I/O context.
Definition: avformat.h:1314
internal.h
opts
static AVDictionary * opts
Definition: movenc.c:51
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:770
NULL
#define NULL
Definition: coverity.c:32
RTSPState::asf_pb_pos
uint64_t asf_pb_pos
cache for position of the asf demuxer, since we load a new data packet in the bytecontext for each in...
Definition: rtsp.h:341
ff_asf_guid
uint8_t ff_asf_guid[16]
Definition: riff.h:96
ff_copy_whiteblacklists
int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src)
Copies the whilelists from one context to the other.
Definition: avformat.c:874
AVFormatContext::pb
AVIOContext * pb
I/O context.
Definition: avformat.h:1356
init_packetizer
static void init_packetizer(FFIOContext *pb, uint8_t *buf, int len)
Definition: rtpdec_asf.c:93
av_base64_decode
int av_base64_decode(uint8_t *out, const char *in_str, int out_size)
Decode a base64-encoded string.
Definition: base64.c:81
base64.h
AVFormatContext::nb_streams
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1370
ff_asf_file_header
const ff_asf_guid ff_asf_file_header
Definition: asf_tags.c:27
asfrtp_parse_sdp_line
static int asfrtp_parse_sdp_line(AVFormatContext *s, int stream_index, PayloadContext *asf, const char *line)
Definition: rtpdec_asf.c:157
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
avio_rb24
unsigned int avio_rb24(AVIOContext *s)
Definition: aviobuf.c:757
avformat_alloc_context
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:164
AVIOContext::buf_end
unsigned char * buf_end
End of the data, may be less than buffer+buffer_size if the read function returned less data than req...
Definition: avio.h:228
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
FFIOContext::pub
AVIOContext pub
Definition: avio_internal.h:29
RTSPState
Private data for the RTSP demuxer.
Definition: rtsp.h:226
av_reallocp
int av_reallocp(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory through a pointer to a pointer.
Definition: mem.c:188
avio_write
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:206
avio_r8
int avio_r8(AVIOContext *s)
Definition: aviobuf.c:606
line
Definition: graph2dot.c:48
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:233
av_strstart
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:36
iformat
static const AVInputFormat * iformat
Definition: ffprobe.c:345
avio_internal.h
ff_read_packet
int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
Read a transport packet from a media file.
Definition: demux.c:629
s
uint8_t s
Definition: llvidencdsp.c:39
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
demux.h
len
int len
Definition: vorbis_enc_data.h:426
AVCodecParameters::avcodec_parameters_copy
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Copy the contents of src to dst.
Definition: codec_par.c:107
ffio_free_dyn_buf
void ffio_free_dyn_buf(AVIOContext **s)
Free a dynamic buffer.
Definition: aviobuf.c:1438
AVStream::id
int id
Format-specific stream ID.
Definition: avformat.h:759
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:747
ff_wms_parse_sdp_a_line
int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p)
Parse a Windows Media Server-specific SDP line.
Definition: rtpdec_asf.c:102
asf.h
AV_RL32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_RL32
Definition: bytestream.h:92
PayloadContext::buf
uint8_t * buf
the temporary storage buffer
Definition: rtpdec_asf.c:188
rtp_asf_fix_header
static int rtp_asf_fix_header(uint8_t *buf, int len)
From MSDN 2.2.1.4, we learn that ASF data packets over RTP should not contain any padding.
Definition: rtpdec_asf.c:46
AVIOContext::eof_reached
int eof_reached
true if was unable to read due to error or eof
Definition: avio.h:238
av_find_input_format
const AVInputFormat * av_find_input_format(const char *short_name)
Find AVInputFormat based on the short name of the input format.
Definition: format.c:146
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
AVPacket::stream_index
int stream_index
Definition: packet.h:605
avio_skip
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: aviobuf.c:321
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:200
mem.h
AVIOContext::buffer
unsigned char * buffer
Start of the buffer.
Definition: avio.h:225
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVPacket
This structure stores compressed data.
Definition: packet.h:580
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:86
av_dict_copy
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:247
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
ff_asf_header
const ff_asf_guid ff_asf_header
Definition: asf_tags.c:23
pkt
static AVPacket * pkt
Definition: demux_decode.c:55
avstring.h
PayloadContext
RTP/AV1 specific private data.
Definition: rdt.c:85
skip
static void BS_FUNC() skip(BSCTX *bc, unsigned int n)
Skip n bits in the buffer.
Definition: bitstream_template.h:383
asfrtp_parse_packet
static int asfrtp_parse_packet(AVFormatContext *s, PayloadContext *asf, AVStream *st, AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len, uint16_t seq, int flags)
Definition: rtpdec_asf.c:196