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 "rtp.h"
32 #include "rtpdec_formats.h"
33 #include "rtsp.h"
34 #include "asf.h"
35 #include "avio_internal.h"
36 #include "internal.h"
37 
38 /**
39  * From MSDN 2.2.1.4, we learn that ASF data packets over RTP should not
40  * contain any padding. Unfortunately, the header min/max_pktsize are not
41  * updated (thus making min_pktsize invalid). Here, we "fix" these faulty
42  * min_pktsize values in the ASF file header.
43  * @return 0 on success, <0 on failure (currently -1).
44  */
45 static int rtp_asf_fix_header(uint8_t *buf, int len)
46 {
47  uint8_t *p = buf, *end = buf + len;
48 
49  if (len < sizeof(ff_asf_guid) * 2 + 22 ||
50  memcmp(p, ff_asf_header, sizeof(ff_asf_guid))) {
51  return -1;
52  }
53  p += sizeof(ff_asf_guid) + 14;
54  do {
55  uint64_t chunksize = AV_RL64(p + sizeof(ff_asf_guid));
56  if (memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) {
57  if (chunksize > end - p)
58  return -1;
59  p += chunksize;
60  continue;
61  }
62 
63  /* skip most of the file header, to min_pktsize */
64  p += 6 * 8 + 3 * 4 + sizeof(ff_asf_guid) * 2;
65  if (p + 8 <= end && AV_RL32(p) == AV_RL32(p + 4)) {
66  /* and set that to zero */
67  AV_WL32(p, 0);
68  return 0;
69  }
70  break;
71  } while (end - p >= sizeof(ff_asf_guid) + 8);
72 
73  return -1;
74 }
75 
76 /**
77  * The following code is basically a buffered AVIOContext,
78  * with the added benefit of returning -EAGAIN (instead of 0)
79  * on packet boundaries, such that the ASF demuxer can return
80  * safely and resume business at the next packet.
81  */
82 static int packetizer_read(void *opaque, uint8_t *buf, int buf_size)
83 {
84  return AVERROR(EAGAIN);
85 }
86 
87 static void init_packetizer(AVIOContext *pb, uint8_t *buf, int len)
88 {
89  ffio_init_context(pb, buf, len, 0, NULL, packetizer_read, NULL, NULL);
90 
91  /* this "fills" the buffer with its current content */
92  pb->pos = len;
93  pb->buf_end = buf + len;
94 }
95 
97 {
98  int ret = 0;
99  if (av_strstart(p, "pgmpu:data:application/vnd.ms.wms-hdr.asfv1;base64,", &p)) {
100  AVIOContext pb;
101  RTSPState *rt = s->priv_data;
102  AVDictionary *opts = NULL;
103  int len = strlen(p) * 6 / 8;
104  char *buf = av_mallocz(len);
105  av_base64_decode(buf, p, len);
106 
107  if (rtp_asf_fix_header(buf, len) < 0)
108  av_log(s, AV_LOG_ERROR,
109  "Failed to fix invalid RTSP-MS/ASF min_pktsize\n");
110  init_packetizer(&pb, buf, len);
111  if (rt->asf_ctx) {
113  }
114  if (!(rt->asf_ctx = avformat_alloc_context()))
115  return AVERROR(ENOMEM);
116  rt->asf_ctx->pb = &pb;
117  av_dict_set(&opts, "no_resync_search", "1", 0);
118  ret = avformat_open_input(&rt->asf_ctx, "", &ff_asf_demuxer, &opts);
119  av_dict_free(&opts);
120  if (ret < 0)
121  return ret;
122  av_dict_copy(&s->metadata, rt->asf_ctx->metadata, 0);
123  rt->asf_pb_pos = avio_tell(&pb);
124  av_free(buf);
125  rt->asf_ctx->pb = NULL;
126  }
127  return ret;
128 }
129 
130 static int asfrtp_parse_sdp_line(AVFormatContext *s, int stream_index,
131  PayloadContext *asf, const char *line)
132 {
133  if (stream_index < 0)
134  return 0;
135  if (av_strstart(line, "stream:", &line)) {
136  RTSPState *rt = s->priv_data;
137 
138  s->streams[stream_index]->id = strtol(line, NULL, 10);
139 
140  if (rt->asf_ctx) {
141  int i;
142 
143  for (i = 0; i < rt->asf_ctx->nb_streams; i++) {
144  if (s->streams[stream_index]->id == rt->asf_ctx->streams[i]->id) {
145  *s->streams[stream_index]->codec =
146  *rt->asf_ctx->streams[i]->codec;
147  rt->asf_ctx->streams[i]->codec->extradata_size = 0;
148  rt->asf_ctx->streams[i]->codec->extradata = NULL;
149  avpriv_set_pts_info(s->streams[stream_index], 32, 1, 1000);
150  }
151  }
152  }
153  }
154 
155  return 0;
156 }
157 
158 struct PayloadContext {
161 };
162 
163 /**
164  * @return 0 when a packet was written into /p pkt, and no more data is left;
165  * 1 when a packet was written into /p pkt, and more packets might be left;
166  * <0 when not enough data was provided to return a full packet, or on error.
167  */
169  AVStream *st, AVPacket *pkt,
170  uint32_t *timestamp,
171  const uint8_t *buf, int len, uint16_t seq,
172  int flags)
173 {
174  AVIOContext *pb = &asf->pb;
175  int res, mflags, len_off;
176  RTSPState *rt = s->priv_data;
177 
178  if (!rt->asf_ctx)
179  return -1;
180 
181  if (len > 0) {
182  int off, out_len = 0;
183 
184  if (len < 4)
185  return -1;
186 
187  av_freep(&asf->buf);
188 
189  ffio_init_context(pb, buf, len, 0, NULL, NULL, NULL, NULL);
190 
191  while (avio_tell(pb) + 4 < len) {
192  int start_off = avio_tell(pb);
193 
194  mflags = avio_r8(pb);
195  if (mflags & 0x80)
196  flags |= RTP_FLAG_KEY;
197  len_off = avio_rb24(pb);
198  if (mflags & 0x20) /**< relative timestamp */
199  avio_skip(pb, 4);
200  if (mflags & 0x10) /**< has duration */
201  avio_skip(pb, 4);
202  if (mflags & 0x8) /**< has location ID */
203  avio_skip(pb, 4);
204  off = avio_tell(pb);
205 
206  if (!(mflags & 0x40)) {
207  /**
208  * If 0x40 is not set, the len_off field specifies an offset
209  * of this packet's payload data in the complete (reassembled)
210  * ASF packet. This is used to spread one ASF packet over
211  * multiple RTP packets.
212  */
213  if (asf->pktbuf && len_off != avio_tell(asf->pktbuf)) {
214  uint8_t *p;
215  avio_close_dyn_buf(asf->pktbuf, &p);
216  asf->pktbuf = NULL;
217  av_free(p);
218  }
219  if (!len_off && !asf->pktbuf &&
220  (res = avio_open_dyn_buf(&asf->pktbuf)) < 0)
221  return res;
222  if (!asf->pktbuf)
223  return AVERROR(EIO);
224 
225  avio_write(asf->pktbuf, buf + off, len - off);
226  avio_skip(pb, len - off);
227  if (!(flags & RTP_FLAG_MARKER))
228  return -1;
229  out_len = avio_close_dyn_buf(asf->pktbuf, &asf->buf);
230  asf->pktbuf = NULL;
231  } else {
232  /**
233  * If 0x40 is set, the len_off field specifies the length of
234  * the next ASF packet that can be read from this payload
235  * data alone. This is commonly the same as the payload size,
236  * but could be less in case of packet splitting (i.e.
237  * multiple ASF packets in one RTP packet).
238  */
239 
240  int cur_len = start_off + len_off - off;
241  int prev_len = out_len;
242  void *newmem;
243  out_len += cur_len;
244  if (FFMIN(cur_len, len - off) < 0)
245  return -1;
246  newmem = av_realloc(asf->buf, out_len);
247  if (!newmem)
248  return -1;
249  asf->buf = newmem;
250  memcpy(asf->buf + prev_len, buf + off,
251  FFMIN(cur_len, len - off));
252  avio_skip(pb, cur_len);
253  }
254  }
255 
256  init_packetizer(pb, asf->buf, out_len);
257  pb->pos += rt->asf_pb_pos;
258  pb->eof_reached = 0;
259  rt->asf_ctx->pb = pb;
260  }
261 
262  for (;;) {
263  int i;
264 
265  res = ff_read_packet(rt->asf_ctx, pkt);
266  rt->asf_pb_pos = avio_tell(pb);
267  if (res != 0)
268  break;
269  for (i = 0; i < s->nb_streams; i++) {
270  if (s->streams[i]->id == rt->asf_ctx->streams[pkt->stream_index]->id) {
271  pkt->stream_index = i;
272  return 1; // FIXME: return 0 if last packet
273  }
274  }
275  av_free_packet(pkt);
276  }
277 
278  return res == 1 ? -1 : res;
279 }
280 
282 {
283  return av_mallocz(sizeof(PayloadContext));
284 }
285 
287 {
288  if (asf->pktbuf) {
289  uint8_t *p = NULL;
290  avio_close_dyn_buf(asf->pktbuf, &p);
291  asf->pktbuf = NULL;
292  av_free(p);
293  }
294  av_freep(&asf->buf);
295  av_free(asf);
296 }
297 
298 #define RTP_ASF_HANDLER(n, s, t) \
299 RTPDynamicProtocolHandler ff_ms_rtp_ ## n ## _handler = { \
300  .enc_name = s, \
301  .codec_type = t, \
302  .codec_id = AV_CODEC_ID_NONE, \
303  .parse_sdp_a_line = asfrtp_parse_sdp_line, \
304  .alloc = asfrtp_new_context, \
305  .free = asfrtp_free_context, \
306  .parse_packet = asfrtp_parse_packet, \
307 }
308 
309 RTP_ASF_HANDLER(asf_pfv, "x-asf-pf", AVMEDIA_TYPE_VIDEO);
310 RTP_ASF_HANDLER(asf_pfa, "x-asf-pf", AVMEDIA_TYPE_AUDIO);
AVPacket pkt
Definition: rtpdec_qt.c:37
const ff_asf_guid ff_asf_header
Definition: asf.c:23
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:205
int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p)
Parse a Windows Media Server-specific SDP line.
Definition: rtpdec_asf.c:96
const char * s
Definition: avisynth_c.h:668
Bytestream IO Context.
Definition: avio.h:68
void av_free_packet(AVPacket *pkt)
Free a packet.
Definition: avpacket.c:242
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
Return the written size and a pointer to the buffer.
Definition: aviobuf.c:988
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:85
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
Open an input stream and read the header.
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
RTP/JPEG specific private data.
Definition: rdt.c:83
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: aviobuf.c:256
void * av_realloc(void *ptr, size_t size)
Allocate or reallocate a block of memory.
Definition: mem.c:141
uint8_t * buf
the temporary storage buffer
Definition: rtpdec_asf.c:160
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:976
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
Format I/O context.
Definition: avformat.h:944
#define AV_RL64
#define AV_WL32(p, darg)
Definition: intreadwrite.h:282
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:45
uint8_t
int id
Format-specific stream ID.
Definition: avformat.h:650
end end
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
AVStream ** streams
Definition: avformat.h:992
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:248
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:173
void av_dict_copy(AVDictionary **dst, AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:176
uint32_t timestamp
current frame timestamp
Private data for the RTSP demuxer.
Definition: rtsp.h:217
AVDictionary * metadata
Definition: avformat.h:1092
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
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:168
#define RTP_FLAG_MARKER
RTP marker bit was set for this packet.
Definition: rtpdec.h:97
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:82
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:162
Definition: graph2dot.c:48
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
int avio_r8(AVIOContext *s)
Definition: aviobuf.c:469
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:310
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
AVIOContext * pktbuf
Definition: rtpdec_asf.c:159
unsigned int nb_streams
A list of all streams in the file.
Definition: avformat.h:991
AVFormatContext * asf_ctx
The following are used for RTP/ASF streams.
Definition: rtsp.h:306
unsigned int avio_rb24(AVIOContext *s)
Definition: aviobuf.c:603
#define FFMIN(a, b)
Definition: common.h:58
static int asfrtp_parse_sdp_line(AVFormatContext *s, int stream_index, PayloadContext *asf, const char *line)
Definition: rtpdec_asf.c:130
ret
Definition: avfilter.c:821
static void init_packetizer(AVIOContext *pb, uint8_t *buf, int len)
Definition: rtpdec_asf.c:87
#define AV_RL32
int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
Read a transport packet from a media file.
uint8_t ff_asf_guid[16]
Definition: riff.h:59
Stream structure.
Definition: avformat.h:643
NULL
Definition: eval.c:55
const ff_asf_guid ff_asf_file_header
Definition: asf.c:27
#define RTP_FLAG_KEY
RTP packet contains a keyframe.
Definition: rtpdec.h:96
AVIOContext * pb
I/O context.
Definition: avformat.h:977
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
AVInputFormat ff_asf_demuxer
Definition: asfdec.c:1541
void * buf
Definition: avisynth_c.h:594
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:62
static void asfrtp_free_context(PayloadContext *asf)
Definition: rtpdec_asf.c:286
synthesis window for stochastic i
static PayloadContext * asfrtp_new_context(void)
Definition: rtpdec_asf.c:281
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer 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.Buffer references ownership and permissions
static int flags
Definition: cpu.c:23
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:33
#define RTP_ASF_HANDLER(n, s, t)
Definition: rtpdec_asf.c:298
int ffio_init_context(AVIOContext *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, uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Definition: aviobuf.c:71
int64_t pos
position in the file of the current buffer
Definition: avio.h:94
void avformat_close_input(AVFormatContext **s)
Close an opened input AVFormatContext.
int eof_reached
true if eof reached
Definition: avio.h:96
int len
void * priv_data
Format private data.
Definition: avformat.h:964
int av_base64_decode(uint8_t *out, const char *in_str, int out_size)
Decode a base64-encoded string.
AVIOContext pb
Definition: rtpdec_asf.c:159
This structure stores compressed data.