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 28struct PayloadContext { 29 unsigned adu_size; 30 unsigned cur_size; 31 uint32_t timestamp; 32 uint8_t *split_buf; 33 int split_pos, split_buf_size, split_pkts; 34 AVIOContext *fragment; 35}; 36 37static void mpa_robust_close_context(PayloadContext *data) 38{ 39 ffio_free_dyn_buf(&data->fragment); 40 av_free(data->split_buf); 41} 42 43static int mpa_robust_parse_rtp_header(AVFormatContext *ctx, 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 66static int mpa_robust_parse_packet(AVFormatContext *ctx, PayloadContext *data, 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 ((err = av_new_packet(pkt, adu_size)) < 0) { 94 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); 95 return err; 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 ((err = av_new_packet(pkt, adu_size)) < 0) { 124 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); 125 return err; 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 192const RTPDynamicProtocolHandler ff_mpeg_audio_robust_dynamic_handler = { 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, 199 .parse_packet = mpa_robust_parse_packet, 200}; 201