1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * RTP parser for loss tolerant payload format for MP3 audio (RFC 5219) 3cabdff1aSopenharmony_ci * Copyright (c) 2015 Gilles Chanteperdrix <gch@xenomai.org> 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/attributes.h" 23cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "avio_internal.h" 26cabdff1aSopenharmony_ci#include "rtpdec_formats.h" 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_cistruct PayloadContext { 29cabdff1aSopenharmony_ci unsigned adu_size; 30cabdff1aSopenharmony_ci unsigned cur_size; 31cabdff1aSopenharmony_ci uint32_t timestamp; 32cabdff1aSopenharmony_ci uint8_t *split_buf; 33cabdff1aSopenharmony_ci int split_pos, split_buf_size, split_pkts; 34cabdff1aSopenharmony_ci AVIOContext *fragment; 35cabdff1aSopenharmony_ci}; 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_cistatic void mpa_robust_close_context(PayloadContext *data) 38cabdff1aSopenharmony_ci{ 39cabdff1aSopenharmony_ci ffio_free_dyn_buf(&data->fragment); 40cabdff1aSopenharmony_ci av_free(data->split_buf); 41cabdff1aSopenharmony_ci} 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_cistatic int mpa_robust_parse_rtp_header(AVFormatContext *ctx, 44cabdff1aSopenharmony_ci const uint8_t *buf, int len, 45cabdff1aSopenharmony_ci unsigned *adu_size, unsigned *cont) 46cabdff1aSopenharmony_ci{ 47cabdff1aSopenharmony_ci unsigned header_size; 48cabdff1aSopenharmony_ci 49cabdff1aSopenharmony_ci if (len < 2) { 50cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Invalid %d bytes packet\n", len); 51cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 52cabdff1aSopenharmony_ci } 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_ci *cont = !!(buf[0] & 0x80); 55cabdff1aSopenharmony_ci if (!(buf[0] & 0x40)) { 56cabdff1aSopenharmony_ci header_size = 1; 57cabdff1aSopenharmony_ci *adu_size = buf[0] & ~0xc0; 58cabdff1aSopenharmony_ci } else { 59cabdff1aSopenharmony_ci header_size = 2; 60cabdff1aSopenharmony_ci *adu_size = AV_RB16(buf) & ~0xc000; 61cabdff1aSopenharmony_ci } 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci return header_size; 64cabdff1aSopenharmony_ci} 65cabdff1aSopenharmony_ci 66cabdff1aSopenharmony_cistatic int mpa_robust_parse_packet(AVFormatContext *ctx, PayloadContext *data, 67cabdff1aSopenharmony_ci AVStream *st, AVPacket *pkt, 68cabdff1aSopenharmony_ci uint32_t *timestamp, const uint8_t *buf, 69cabdff1aSopenharmony_ci int len, uint16_t seq, int flags) 70cabdff1aSopenharmony_ci{ 71cabdff1aSopenharmony_ci unsigned adu_size, continuation; 72cabdff1aSopenharmony_ci int err, header_size; 73cabdff1aSopenharmony_ci 74cabdff1aSopenharmony_ci if (!buf) { 75cabdff1aSopenharmony_ci buf = &data->split_buf[data->split_pos]; 76cabdff1aSopenharmony_ci len = data->split_buf_size - data->split_pos; 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_ci header_size = mpa_robust_parse_rtp_header(ctx, buf, len, &adu_size, 79cabdff1aSopenharmony_ci &continuation); 80cabdff1aSopenharmony_ci if (header_size < 0) { 81cabdff1aSopenharmony_ci av_freep(&data->split_buf); 82cabdff1aSopenharmony_ci return header_size; 83cabdff1aSopenharmony_ci } 84cabdff1aSopenharmony_ci buf += header_size; 85cabdff1aSopenharmony_ci len -= header_size; 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci if (continuation || adu_size > len) { 88cabdff1aSopenharmony_ci av_freep(&data->split_buf); 89cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Invalid frame\n"); 90cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 91cabdff1aSopenharmony_ci } 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci if ((err = av_new_packet(pkt, adu_size)) < 0) { 94cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); 95cabdff1aSopenharmony_ci return err; 96cabdff1aSopenharmony_ci } 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_ci pkt->stream_index = st->index; 99cabdff1aSopenharmony_ci memcpy(pkt->data, buf, adu_size); 100cabdff1aSopenharmony_ci 101cabdff1aSopenharmony_ci data->split_pos += header_size + adu_size; 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_ci if (data->split_pos == data->split_buf_size) { 104cabdff1aSopenharmony_ci av_freep(&data->split_buf); 105cabdff1aSopenharmony_ci return 0; 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci return 1; 109cabdff1aSopenharmony_ci } 110cabdff1aSopenharmony_ci 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_ci header_size = mpa_robust_parse_rtp_header(ctx, buf, len, &adu_size, 113cabdff1aSopenharmony_ci &continuation); 114cabdff1aSopenharmony_ci if (header_size < 0) 115cabdff1aSopenharmony_ci return header_size; 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci buf += header_size; 118cabdff1aSopenharmony_ci len -= header_size; 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_ci if (!continuation && adu_size <= len) { 121cabdff1aSopenharmony_ci /* One or more complete frames */ 122cabdff1aSopenharmony_ci 123cabdff1aSopenharmony_ci if ((err = av_new_packet(pkt, adu_size)) < 0) { 124cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); 125cabdff1aSopenharmony_ci return err; 126cabdff1aSopenharmony_ci } 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_ci pkt->stream_index = st->index; 129cabdff1aSopenharmony_ci memcpy(pkt->data, buf, adu_size); 130cabdff1aSopenharmony_ci 131cabdff1aSopenharmony_ci buf += adu_size; 132cabdff1aSopenharmony_ci len -= adu_size; 133cabdff1aSopenharmony_ci if (len) { 134cabdff1aSopenharmony_ci data->split_buf_size = len; 135cabdff1aSopenharmony_ci data->split_buf = av_malloc(data->split_buf_size); 136cabdff1aSopenharmony_ci data->split_pos = 0; 137cabdff1aSopenharmony_ci if (!data->split_buf) { 138cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); 139cabdff1aSopenharmony_ci av_packet_unref(pkt); 140cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 141cabdff1aSopenharmony_ci } 142cabdff1aSopenharmony_ci memcpy(data->split_buf, buf, data->split_buf_size); 143cabdff1aSopenharmony_ci return 1; 144cabdff1aSopenharmony_ci } 145cabdff1aSopenharmony_ci return 0; 146cabdff1aSopenharmony_ci } else if (!continuation) { /* && adu_size > len */ 147cabdff1aSopenharmony_ci /* First fragment */ 148cabdff1aSopenharmony_ci ffio_free_dyn_buf(&data->fragment); 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci data->adu_size = adu_size; 151cabdff1aSopenharmony_ci data->cur_size = len; 152cabdff1aSopenharmony_ci data->timestamp = *timestamp; 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_ci err = avio_open_dyn_buf(&data->fragment); 155cabdff1aSopenharmony_ci if (err < 0) 156cabdff1aSopenharmony_ci return err; 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci avio_write(data->fragment, buf, len); 159cabdff1aSopenharmony_ci return AVERROR(EAGAIN); 160cabdff1aSopenharmony_ci } 161cabdff1aSopenharmony_ci /* else continuation == 1 */ 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci /* Fragment other than first */ 164cabdff1aSopenharmony_ci if (!data->fragment) { 165cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_WARNING, 166cabdff1aSopenharmony_ci "Received packet without a start fragment; dropping.\n"); 167cabdff1aSopenharmony_ci return AVERROR(EAGAIN); 168cabdff1aSopenharmony_ci } 169cabdff1aSopenharmony_ci if (adu_size != data->adu_size || 170cabdff1aSopenharmony_ci data->timestamp != *timestamp) { 171cabdff1aSopenharmony_ci ffio_free_dyn_buf(&data->fragment); 172cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Invalid packet received\n"); 173cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 174cabdff1aSopenharmony_ci } 175cabdff1aSopenharmony_ci 176cabdff1aSopenharmony_ci avio_write(data->fragment, buf, len); 177cabdff1aSopenharmony_ci data->cur_size += len; 178cabdff1aSopenharmony_ci 179cabdff1aSopenharmony_ci if (data->cur_size < data->adu_size) 180cabdff1aSopenharmony_ci return AVERROR(EAGAIN); 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci err = ff_rtp_finalize_packet(pkt, &data->fragment, st->index); 183cabdff1aSopenharmony_ci if (err < 0) { 184cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, 185cabdff1aSopenharmony_ci "Error occurred when getting fragment buffer.\n"); 186cabdff1aSopenharmony_ci return err; 187cabdff1aSopenharmony_ci } 188cabdff1aSopenharmony_ci 189cabdff1aSopenharmony_ci return 0; 190cabdff1aSopenharmony_ci} 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ciconst RTPDynamicProtocolHandler ff_mpeg_audio_robust_dynamic_handler = { 193cabdff1aSopenharmony_ci .enc_name = "mpa-robust", 194cabdff1aSopenharmony_ci .codec_type = AVMEDIA_TYPE_AUDIO, 195cabdff1aSopenharmony_ci .codec_id = AV_CODEC_ID_MP3ADU, 196cabdff1aSopenharmony_ci .need_parsing = AVSTREAM_PARSE_HEADERS, 197cabdff1aSopenharmony_ci .priv_data_size = sizeof(PayloadContext), 198cabdff1aSopenharmony_ci .close = mpa_robust_close_context, 199cabdff1aSopenharmony_ci .parse_packet = mpa_robust_parse_packet, 200cabdff1aSopenharmony_ci}; 201