FFmpeg  4.0
rtpdec_mpa_robust.c
Go to the documentation of this file.
1 /*
2  * RTP parser for loss tolerant payload format for MP3 audio (RFC 5219)
3  * Copyright (c) 2015 Gilles Chanteperdrix <gch@xenomai.org>
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 #include "libavutil/attributes.h"
23 #include "libavutil/intreadwrite.h"
24 
25 #include "avio_internal.h"
26 #include "rtpdec_formats.h"
27 
28 struct PayloadContext {
29  unsigned adu_size;
30  unsigned cur_size;
31  uint32_t timestamp;
35 };
36 
38 {
40  av_free(data->split_buf);
41 }
42 
44  const uint8_t *buf, int len,
45  unsigned *adu_size, unsigned *cont)
46 {
47  unsigned header_size;
48 
49  if (len < 2) {
50  av_log(ctx, AV_LOG_ERROR, "Invalid %d bytes packet\n", len);
51  return AVERROR_INVALIDDATA;
52  }
53 
54  *cont = !!(buf[0] & 0x80);
55  if (!(buf[0] & 0x40)) {
56  header_size = 1;
57  *adu_size = buf[0] & ~0xc0;
58  } else {
59  header_size = 2;
60  *adu_size = AV_RB16(buf) & ~0xc000;
61  }
62 
63  return header_size;
64 }
65 
67  AVStream *st, AVPacket *pkt,
68  uint32_t *timestamp, const uint8_t *buf,
69  int len, uint16_t seq, int flags)
70 {
71  unsigned adu_size, continuation;
72  int err, header_size;
73 
74  if (!buf) {
75  buf = &data->split_buf[data->split_pos];
76  len = data->split_buf_size - data->split_pos;
77 
78  header_size = mpa_robust_parse_rtp_header(ctx, buf, len, &adu_size,
79  &continuation);
80  if (header_size < 0) {
81  av_freep(&data->split_buf);
82  return header_size;
83  }
84  buf += header_size;
85  len -= header_size;
86 
87  if (continuation || adu_size > len) {
88  av_freep(&data->split_buf);
89  av_log(ctx, AV_LOG_ERROR, "Invalid frame\n");
90  return AVERROR_INVALIDDATA;
91  }
92 
93  if (av_new_packet(pkt, adu_size)) {
94  av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
95  return AVERROR(ENOMEM);
96  }
97 
98  pkt->stream_index = st->index;
99  memcpy(pkt->data, buf, adu_size);
100 
101  data->split_pos += header_size + adu_size;
102 
103  if (data->split_pos == data->split_buf_size) {
104  av_freep(&data->split_buf);
105  return 0;
106  }
107 
108  return 1;
109  }
110 
111 
112  header_size = mpa_robust_parse_rtp_header(ctx, buf, len, &adu_size,
113  &continuation);
114  if (header_size < 0)
115  return header_size;
116 
117  buf += header_size;
118  len -= header_size;
119 
120  if (!continuation && adu_size <= len) {
121  /* One or more complete frames */
122 
123  if (av_new_packet(pkt, adu_size)) {
124  av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
125  return AVERROR(ENOMEM);
126  }
127 
128  pkt->stream_index = st->index;
129  memcpy(pkt->data, buf, adu_size);
130 
131  buf += adu_size;
132  len -= adu_size;
133  if (len) {
134  data->split_buf_size = len;
135  data->split_buf = av_malloc(data->split_buf_size);
136  data->split_pos = 0;
137  if (!data->split_buf) {
138  av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
139  av_packet_unref(pkt);
140  return AVERROR(ENOMEM);
141  }
142  memcpy(data->split_buf, buf, data->split_buf_size);
143  return 1;
144  }
145  return 0;
146  } else if (!continuation) { /* && adu_size > len */
147  /* First fragment */
148  ffio_free_dyn_buf(&data->fragment);
149 
150  data->adu_size = adu_size;
151  data->cur_size = len;
152  data->timestamp = *timestamp;
153 
154  err = avio_open_dyn_buf(&data->fragment);
155  if (err < 0)
156  return err;
157 
158  avio_write(data->fragment, buf, len);
159  return AVERROR(EAGAIN);
160  }
161  /* else continuation == 1 */
162 
163  /* Fragment other than first */
164  if (!data->fragment) {
165  av_log(ctx, AV_LOG_WARNING,
166  "Received packet without a start fragment; dropping.\n");
167  return AVERROR(EAGAIN);
168  }
169  if (adu_size != data->adu_size ||
170  data->timestamp != *timestamp) {
171  ffio_free_dyn_buf(&data->fragment);
172  av_log(ctx, AV_LOG_ERROR, "Invalid packet received\n");
173  return AVERROR_INVALIDDATA;
174  }
175 
176  avio_write(data->fragment, buf, len);
177  data->cur_size += len;
178 
179  if (data->cur_size < data->adu_size)
180  return AVERROR(EAGAIN);
181 
182  err = ff_rtp_finalize_packet(pkt, &data->fragment, st->index);
183  if (err < 0) {
184  av_log(ctx, AV_LOG_ERROR,
185  "Error occurred when getting fragment buffer.\n");
186  return err;
187  }
188 
189  return 0;
190 }
191 
193  .enc_name = "mpa-robust",
194  .codec_type = AVMEDIA_TYPE_AUDIO,
195  .codec_id = AV_CODEC_ID_MP3ADU,
196  .need_parsing = AVSTREAM_PARSE_HEADERS,
197  .priv_data_size = sizeof(PayloadContext),
198  .close = mpa_robust_close_context,
200 };
AVPacket pkt
Definition: rtpdec_qt.c:37
Bytestream IO Context.
Definition: avio.h:161
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
RTP/JPEG specific private data.
Definition: rdt.c:83
int index
stream index in AVFormatContext
Definition: avformat.h:874
const RTPDynamicProtocolHandler ff_mpeg_audio_robust_dynamic_handler
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:1391
Macro definitions for various function/variable attributes.
Format I/O context.
Definition: avformat.h:1342
static int mpa_robust_parse_rtp_header(AVFormatContext *ctx, const uint8_t *buf, int len, unsigned *adu_size, unsigned *cont)
uint8_t
#define av_malloc(s)
uint8_t * data
Definition: avcodec.h:1430
static int flags
Definition: log.c:55
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:218
#define av_log(a,...)
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:86
uint32_t timestamp
current frame timestamp
Definition: rtpdec_ac3.c:31
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define AV_RB16
Definition: intreadwrite.h:53
#define AVERROR(e)
Definition: error.h:43
Only parse headers, do not repack.
Definition: avformat.h:794
AVFormatContext * ctx
Definition: movenc.c:48
static void mpa_robust_close_context(PayloadContext *data)
void ffio_free_dyn_buf(AVIOContext **s)
Free a dynamic buffer.
Definition: aviobuf.c:1450
Stream structure.
Definition: avformat.h:873
AVIOContext * fragment
buffer for split payloads
Definition: rtpdec_ac3.c:32
static int mpa_robust_parse_packet(AVFormatContext *ctx, PayloadContext *data, AVStream *st, AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len, uint16_t seq, int flags)
AVIOContext * data
Definition: rtpdec_vp8.c:36
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:592
uint8_t * buf
the temporary storage buffer
Definition: rtpdec_asf.c:183
const char * enc_name
Definition: rtpdec.h:116
int ff_rtp_finalize_packet(AVPacket *pkt, AVIOContext **dyn_buf, int stream_idx)
Close the dynamic buffer and make a packet from it.
Definition: rtpdec.c:927
static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
Parse a packet, add all split parts to parse_queue.
Definition: utils.c:1437
#define av_free(p)
#define av_freep(p)
int stream_index
Definition: avcodec.h:1432
This structure stores compressed data.
Definition: avcodec.h:1407