1/* 2 * RTP parser for AC3 payload format (RFC 4184) 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 "avformat.h" 23#include "avio_internal.h" 24#include "rtpdec_formats.h" 25 26#define RTP_AC3_PAYLOAD_HEADER_SIZE 2 27 28struct PayloadContext { 29 unsigned nr_frames; 30 unsigned last_frame; 31 uint32_t timestamp; 32 AVIOContext *fragment; 33}; 34 35static void ac3_close_context(PayloadContext *data) 36{ 37 ffio_free_dyn_buf(&data->fragment); 38} 39 40static int ac3_handle_packet(AVFormatContext *ctx, PayloadContext *data, 41 AVStream *st, AVPacket *pkt, uint32_t *timestamp, 42 const uint8_t *buf, int len, uint16_t seq, 43 int flags) 44{ 45 unsigned frame_type; 46 unsigned nr_frames; 47 int err; 48 49 if (len < RTP_AC3_PAYLOAD_HEADER_SIZE + 1) { 50 av_log(ctx, AV_LOG_ERROR, "Invalid %d bytes packet\n", len); 51 return AVERROR_INVALIDDATA; 52 } 53 54 frame_type = buf[0] & 0x3; 55 nr_frames = buf[1]; 56 buf += RTP_AC3_PAYLOAD_HEADER_SIZE; 57 len -= RTP_AC3_PAYLOAD_HEADER_SIZE; 58 59 switch (frame_type) { 60 case 0: /* One or more complete frames */ 61 if (!nr_frames) { 62 av_log(ctx, AV_LOG_ERROR, "Invalid AC3 packet data\n"); 63 return AVERROR_INVALIDDATA; 64 } 65 if ((err = av_new_packet(pkt, len)) < 0) { 66 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); 67 return err; 68 } 69 70 pkt->stream_index = st->index; 71 memcpy(pkt->data, buf, len); 72 return 0; 73 74 case 1: 75 case 2: /* First fragment */ 76 ffio_free_dyn_buf(&data->fragment); 77 78 data->last_frame = 1; 79 data->nr_frames = nr_frames; 80 err = avio_open_dyn_buf(&data->fragment); 81 if (err < 0) 82 return err; 83 84 avio_write(data->fragment, buf, len); 85 data->timestamp = *timestamp; 86 return AVERROR(EAGAIN); 87 88 case 3: /* Fragment other than first */ 89 if (!data->fragment) { 90 av_log(ctx, AV_LOG_WARNING, 91 "Received packet without a start fragment; dropping.\n"); 92 return AVERROR(EAGAIN); 93 } 94 if (nr_frames != data->nr_frames || 95 data->timestamp != *timestamp) { 96 ffio_free_dyn_buf(&data->fragment); 97 av_log(ctx, AV_LOG_ERROR, "Invalid packet received\n"); 98 return AVERROR_INVALIDDATA; 99 } 100 101 avio_write(data->fragment, buf, len); 102 data->last_frame++; 103 } 104 105 if (!(flags & RTP_FLAG_MARKER)) 106 return AVERROR(EAGAIN); 107 108 if (data->last_frame != data->nr_frames) { 109 ffio_free_dyn_buf(&data->fragment); 110 av_log(ctx, AV_LOG_ERROR, "Missed %d packets\n", 111 data->nr_frames - data->last_frame); 112 return AVERROR_INVALIDDATA; 113 } 114 115 err = ff_rtp_finalize_packet(pkt, &data->fragment, st->index); 116 if (err < 0) { 117 av_log(ctx, AV_LOG_ERROR, 118 "Error occurred when getting fragment buffer.\n"); 119 return err; 120 } 121 122 return 0; 123} 124 125const RTPDynamicProtocolHandler ff_ac3_dynamic_handler = { 126 .enc_name = "ac3", 127 .codec_type = AVMEDIA_TYPE_AUDIO, 128 .codec_id = AV_CODEC_ID_AC3, 129 .need_parsing = AVSTREAM_PARSE_FULL, 130 .priv_data_size = sizeof(PayloadContext), 131 .close = ac3_close_context, 132 .parse_packet = ac3_handle_packet, 133}; 134