FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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_free_packet(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 };