Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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;
  32.     uint8_t *split_buf;
  33.     int split_pos, split_buf_size, split_pkts;
  34.     AVIOContext *fragment;
  35. };
  36.  
  37. static void mpa_robust_close_context(PayloadContext *data)
  38. {
  39.     ffio_free_dyn_buf(&data->fragment);
  40.     av_free(data->split_buf);
  41. }
  42.  
  43. static 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.  
  66. static 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 (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.  
  192. 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.