Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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.  
  28. struct PayloadContext {
  29.     unsigned nr_frames;
  30.     unsigned last_frame;
  31.     uint32_t timestamp;
  32.     AVIOContext *fragment;
  33. };
  34.  
  35. static void ac3_close_context(PayloadContext *data)
  36. {
  37.     ffio_free_dyn_buf(&data->fragment);
  38. }
  39.  
  40. static 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 (av_new_packet(pkt, len)) {
  66.             av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
  67.             return AVERROR(ENOMEM);
  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.  
  125. 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.