FFmpeg
rtpdec_qdm2.c
Go to the documentation of this file.
1 /*
2  * QDesign Music 2 (QDM2) payload for RTP
3  * Copyright (c) 2010 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 RTP support for the QDM2 payload (todo: wiki)
25  * @author Ronald S. Bultje <rbultje@ronald.bitfreak.net>
26  */
27 
28 #include <string.h>
29 #include "libavutil/avassert.h"
30 #include "libavutil/intreadwrite.h"
31 #include "internal.h"
32 #include "rtp.h"
33 #include "rtpdec.h"
34 #include "rtpdec_formats.h"
35 
36 struct PayloadContext {
37  /** values read from the config header, used as packet headers */
38  //@{
39  int block_type; ///< superblock type, value 2 .. 8
40  int block_size; ///< from extradata, used as pkt length
41  int subpkts_per_block; ///< max. nr. of subpackets to add per output buffer
42  //@}
43 
44  /** Temporary storage for superblock restoring, per packet ID (0x80 total) */
45  //@{
46  uint16_t len[0x80]; ///< how much the temporary buffer is filled
47  uint8_t buf[0x80][0x800]; ///< the temporary storage buffer
48 
49  unsigned int cache; ///< number of data packets that we have cached right now
50  unsigned int n_pkts; ///< number of RTP packets received since last packet output / config
51  uint32_t timestamp; ///< timestamp of next-to-be-returned packet
52  //@}
53 };
54 
55 /**
56  * Parse configuration (basically the codec-specific extradata) from
57  * an RTP config subpacket (starts with 0xff).
58  *
59  * Layout of the config subpacket (in bytes):
60  * 1: 0xFF <- config ID
61  * then an array {
62  * 1: size <- of the current item
63  * 1: item type <- 0 .. 4
64  * size-2: data <- data depends on the item type
65  * }
66  *
67  * Item 0 implies the end of the config subpacket, and has no data.
68  * Item 1 implies a stream configuration without extradata.
69  * Item 2 max. nr. of subpackets per superblock
70  * Item 3 superblock type for the stream
71  * Item 4 implies a stream configuration with extradata (size >= 0x1c).
72  *
73  * @return <0 on error, otherwise the number of bytes parsed from the
74  * input buffer.
75  */
77  const uint8_t *buf, const uint8_t *end)
78 {
79  const uint8_t *p = buf;
80  int ret;
81 
82  while (end - p >= 2) {
83  unsigned int item_len = p[0], config_item = p[1];
84 
85  if (item_len < 2 || end - p < item_len || config_item > 4)
86  return AVERROR_INVALIDDATA;
87 
88  switch (config_item) {
89  case 0: /* end of config block */
90  return p - buf + item_len;
91  case 1: /* stream without extradata */
92  /* FIXME: set default qdm->block_size */
93  break;
94  case 2: /**< subpackets per block */
95  if (item_len < 3)
96  return AVERROR_INVALIDDATA;
97  qdm->subpkts_per_block = p[2];
98  break;
99  case 3: /* superblock type */
100  if (item_len < 4)
101  return AVERROR_INVALIDDATA;
102  qdm->block_type = AV_RB16(p + 2);
103  break;
104  case 4: /* stream with extradata */
105  if (item_len < 30)
106  return AVERROR_INVALIDDATA;
107 
108  ret = ff_alloc_extradata(st->codecpar, 26 + item_len);
109  if (ret < 0) {
110  return ret;
111  }
112  AV_WB32(st->codecpar->extradata, 12);
113  memcpy(st->codecpar->extradata + 4, "frma", 4);
114  memcpy(st->codecpar->extradata + 8, "QDM2", 4);
115  AV_WB32(st->codecpar->extradata + 12, 6 + item_len);
116  memcpy(st->codecpar->extradata + 16, "QDCA", 4);
117  memcpy(st->codecpar->extradata + 20, p + 2, item_len - 2);
118  AV_WB32(st->codecpar->extradata + 18 + item_len, 8);
119  AV_WB32(st->codecpar->extradata + 22 + item_len, 0);
120 
121  qdm->block_size = AV_RB32(p + 26);
122  break;
123  }
124 
125  p += item_len;
126  }
127 
128  return AVERROR(EAGAIN); /* not enough data */
129 }
130 
131 /**
132  * Parse a single subpacket. We store this subpacket in an intermediate
133  * buffer (position depends on the ID (byte[0]). When called, at least
134  * 4 bytes are available for reading (see qdm2_parse_packet()).
135  *
136  * Layout of a single subpacket (RTP packets commonly contain multiple
137  * such subpackets) - length in bytes:
138  * 1: ordering ID <- 0 .. 0x7F
139  * 1: subpacket type <- 0 .. 0x7F; value & 0x80 means subpacket length = 2 bytes, else 1 byte
140  * 1/2: subpacket length <- length of the data following the flags/length fields
141  * if (subpacket type & 0x7F) == 0x7F
142  * 1: subpacket type, higher bits
143  * size: subpacket data
144  *
145  * The subpackets come in randomly, and should be encapsulated into 1
146  * or more superblocks (containing qdm->subpkts_per_block subpackets
147  * each) per RTP packet, in order of ascending "ordering ID", see
148  * qdm2_restore_block().
149  *
150  * @return <0 on error, otherwise the number of bytes parsed from the
151  * input buffer.
152  */
154  const uint8_t *buf, const uint8_t *end)
155 {
156  const uint8_t *p = buf;
157  unsigned int id, len, type, to_copy;
158 
159  /* parse header so we know the size of the header/data */
160  id = *p++;
161  type = *p++;
162  if (type & 0x80) {
163  len = AV_RB16(p);
164  p += 2;
165  type &= 0x7F;
166  } else
167  len = *p++;
168 
169  if (end - p < len + (type == 0x7F) || id >= 0x80)
170  return AVERROR_INVALIDDATA;
171  if (type == 0x7F)
172  type |= *p++ << 8;
173 
174  /* copy data into a temporary buffer */
175  to_copy = FFMIN(len + (p - &buf[1]), 0x800 - qdm->len[id]);
176  memcpy(&qdm->buf[id][qdm->len[id]], buf + 1, to_copy);
177  qdm->len[id] += to_copy;
178 
179  return p + len - buf;
180 }
181 
182 /**
183  * Add a superblock header around a set of subpackets.
184  *
185  * @return <0 on error, else 0.
186  */
188 {
189  int to_copy, n, res, include_csum;
190  uint8_t *p, *csum_pos = NULL;
191 
192  /* create packet to hold subpkts into a superblock */
193  av_assert0(qdm->cache > 0);
194  for (n = 0; n < 0x80; n++)
195  if (qdm->len[n] > 0)
196  break;
197  av_assert0(n < 0x80);
198 
199  if ((res = av_new_packet(pkt, qdm->block_size)) < 0)
200  return res;
201  memset(pkt->data, 0, pkt->size);
202  pkt->stream_index = st->index;
203  p = pkt->data;
204 
205  /* superblock header */
206  if (qdm->len[n] > 0xff) {
207  *p++ = qdm->block_type | 0x80;
208  AV_WB16(p, qdm->len[n]);
209  p += 2;
210  } else {
211  *p++ = qdm->block_type;
212  *p++ = qdm->len[n];
213  }
214  if ((include_csum = (qdm->block_type == 2 || qdm->block_type == 4))) {
215  csum_pos = p;
216  p += 2;
217  }
218 
219  /* subpacket data */
220  to_copy = FFMIN(qdm->len[n], pkt->size - (p - pkt->data));
221  memcpy(p, qdm->buf[n], to_copy);
222  qdm->len[n] = 0;
223 
224  /* checksum header */
225  if (include_csum) {
226  unsigned int total = 0;
227  uint8_t *q;
228 
229  for (q = pkt->data; q < &pkt->data[qdm->block_size]; q++)
230  total += *q;
231  AV_WB16(csum_pos, (uint16_t) total);
232  }
233 
234  return 0;
235 }
236 
237 /** return 0 on packet, no more left, 1 on packet, -1 on partial packet... */
239  AVStream *st, AVPacket *pkt,
240  uint32_t *timestamp,
241  const uint8_t *buf, int len, uint16_t seq,
242  int flags)
243 {
244  int res = AVERROR_INVALIDDATA, n;
245  const uint8_t *end = buf + len, *p = buf;
246 
247  if (len > 0) {
248  if (len < 2)
249  return AVERROR_INVALIDDATA;
250 
251  /* configuration block */
252  if (*p == 0xff) {
253  if (qdm->n_pkts > 0) {
255  "Out of sequence config - dropping queue\n");
256  qdm->n_pkts = 0;
257  memset(qdm->len, 0, sizeof(qdm->len));
258  }
259 
260  if ((res = qdm2_parse_config(qdm, st, ++p, end)) < 0)
261  return res;
262  p += res;
263 
264  /* We set codec_id to AV_CODEC_ID_NONE initially to
265  * delay decoder initialization since extradata is
266  * carried within the RTP stream, not SDP. Here,
267  * by setting codec_id to AV_CODEC_ID_QDM2, we are signalling
268  * to the decoder that it is OK to initialize. */
270  }
271  if (st->codecpar->codec_id == AV_CODEC_ID_NONE)
272  return AVERROR(EAGAIN);
273 
274  /* subpackets */
275  while (end - p >= 4) {
276  if ((res = qdm2_parse_subpacket(qdm, st, p, end)) < 0)
277  return res;
278  p += res;
279  }
280 
281  qdm->timestamp = *timestamp;
282  if (++qdm->n_pkts < qdm->subpkts_per_block)
283  return AVERROR(EAGAIN);
284  qdm->cache = 0;
285  for (n = 0; n < 0x80; n++)
286  if (qdm->len[n] > 0)
287  qdm->cache++;
288  }
289 
290  /* output the subpackets into freshly created superblock structures */
291  if (!qdm->cache || (res = qdm2_restore_block(qdm, st, pkt)) < 0)
292  return res;
293  if (--qdm->cache == 0)
294  qdm->n_pkts = 0;
295 
296  *timestamp = qdm->timestamp;
297  qdm->timestamp = RTP_NOTS_VALUE;
298 
299  return (qdm->cache > 0) ? 1 : 0;
300 }
301 
303  .enc_name = "X-QDM",
304  .codec_type = AVMEDIA_TYPE_AUDIO,
305  .codec_id = AV_CODEC_ID_NONE,
306  .priv_data_size = sizeof(PayloadContext),
308 };
PayloadContext::n_pkts
unsigned int n_pkts
number of RTP packets received since last packet output / config
Definition: rtpdec_qdm2.c:50
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVCodecParameters::extradata
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:69
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
rtpdec_formats.h
AVPacket::data
uint8_t * data
Definition: packet.h:524
data
const char data[16]
Definition: mxf.c:148
PayloadContext::timestamp
uint32_t timestamp
current frame timestamp
Definition: rtpdec_ac3.c:31
RTPDynamicProtocolHandler::enc_name
const char * enc_name
Definition: rtpdec.h:117
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
qdm2_parse_subpacket
static int qdm2_parse_subpacket(PayloadContext *qdm, AVStream *st, const uint8_t *buf, const uint8_t *end)
Parse a single subpacket.
Definition: rtpdec_qdm2.c:153
avassert.h
pkt
AVPacket * pkt
Definition: movenc.c:60
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
av_new_packet
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: packet.c:98
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
RTP_NOTS_VALUE
#define RTP_NOTS_VALUE
Definition: rtpdec.h:41
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
PayloadContext::len
int len
Definition: rtpdec_latm.c:32
AVFormatContext
Format I/O context.
Definition: avformat.h:1255
internal.h
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:766
NULL
#define NULL
Definition: coverity.c:32
AV_WB16
#define AV_WB16(p, v)
Definition: intreadwrite.h:403
qdm2_restore_block
static int qdm2_restore_block(PayloadContext *qdm, AVStream *st, AVPacket *pkt)
Add a superblock header around a set of subpackets.
Definition: rtpdec_qdm2.c:187
PayloadContext::block_size
int block_size
from extradata, used as pkt length
Definition: rtpdec_qdm2.c:40
AV_CODEC_ID_QDM2
@ AV_CODEC_ID_QDM2
Definition: codec_id.h:459
rtpdec.h
qdm2_parse_packet
static int qdm2_parse_packet(AVFormatContext *s, PayloadContext *qdm, AVStream *st, AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len, uint16_t seq, int flags)
return 0 on packet, no more left, 1 on packet, -1 on partial packet...
Definition: rtpdec_qdm2.c:238
AV_WB32
#define AV_WB32(p, v)
Definition: intreadwrite.h:417
PayloadContext::subpkts_per_block
int subpkts_per_block
max. nr. of subpackets to add per output buffer
Definition: rtpdec_qdm2.c:41
AVPacket::size
int size
Definition: packet.h:525
AV_RB32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:96
qdm2_parse_config
static int qdm2_parse_config(PayloadContext *qdm, AVStream *st, const uint8_t *buf, const uint8_t *end)
Parse configuration (basically the codec-specific extradata) from an RTP config subpacket (starts wit...
Definition: rtpdec_qdm2.c:76
rtp.h
AV_CODEC_ID_NONE
@ AV_CODEC_ID_NONE
Definition: codec_id.h:50
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
len
int len
Definition: vorbis_enc_data.h:426
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:743
id
enum AVCodecID id
Definition: dts2pts.c:365
PayloadContext::buf
uint8_t * buf
the temporary storage buffer
Definition: rtpdec_asf.c:184
AVStream::index
int index
stream index in AVFormatContext
Definition: avformat.h:749
PayloadContext::block_type
int block_type
values read from the config header, used as packet headers
Definition: rtpdec_qdm2.c:39
PayloadContext::cache
unsigned int cache
number of data packets that we have cached right now
Definition: rtpdec_qdm2.c:49
AVPacket::stream_index
int stream_index
Definition: packet.h:526
parse_packet
static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index, int flush)
Parse a packet, add all split parts to parse_queue.
Definition: demux.c:1155
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:55
AVPacket
This structure stores compressed data.
Definition: packet.h:501
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
ff_qdm2_dynamic_handler
const RTPDynamicProtocolHandler ff_qdm2_dynamic_handler
Definition: rtpdec_qdm2.c:302
PayloadContext
RTP/JPEG specific private data.
Definition: rdt.c:85
RTPDynamicProtocolHandler
Definition: rtpdec.h:116
AV_RB16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:98
ff_alloc_extradata
int ff_alloc_extradata(AVCodecParameters *par, int size)
Allocate extradata with additional AV_INPUT_BUFFER_PADDING_SIZE at end which is always set to 0.
Definition: utils.c:240