Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * RTP AMR Depacketizer, RFC 3267
  3.  * Copyright (c) 2010 Martin Storsjo
  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/channel_layout.h"
  23. #include "avformat.h"
  24. #include "rtpdec_formats.h"
  25. #include "libavutil/avstring.h"
  26.  
  27. static const uint8_t frame_sizes_nb[16] = {
  28.     12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0
  29. };
  30. static const uint8_t frame_sizes_wb[16] = {
  31.     17, 23, 32, 36, 40, 46, 50, 58, 60, 5, 5, 0, 0, 0, 0, 0
  32. };
  33.  
  34. struct PayloadContext {
  35.     int octet_align;
  36.     int crc;
  37.     int interleaving;
  38.     int channels;
  39. };
  40.  
  41. static av_cold int amr_init(AVFormatContext *s, int st_index, PayloadContext *data)
  42. {
  43.     data->channels = 1;
  44.     return 0;
  45. }
  46.  
  47. static int amr_handle_packet(AVFormatContext *ctx, PayloadContext *data,
  48.                              AVStream *st, AVPacket *pkt, uint32_t *timestamp,
  49.                              const uint8_t *buf, int len, uint16_t seq,
  50.                              int flags)
  51. {
  52.     const uint8_t *frame_sizes = NULL;
  53.     int frames;
  54.     int i;
  55.     const uint8_t *speech_data;
  56.     uint8_t *ptr;
  57.  
  58.     if (st->codec->codec_id == AV_CODEC_ID_AMR_NB) {
  59.         frame_sizes = frame_sizes_nb;
  60.     } else if (st->codec->codec_id == AV_CODEC_ID_AMR_WB) {
  61.         frame_sizes = frame_sizes_wb;
  62.     } else {
  63.         av_log(ctx, AV_LOG_ERROR, "Bad codec ID\n");
  64.         return AVERROR_INVALIDDATA;
  65.     }
  66.  
  67.     if (st->codec->channels != 1) {
  68.         av_log(ctx, AV_LOG_ERROR, "Only mono AMR is supported\n");
  69.         return AVERROR_INVALIDDATA;
  70.     }
  71.     st->codec->channel_layout = AV_CH_LAYOUT_MONO;
  72.  
  73.     /* The AMR RTP packet consists of one header byte, followed
  74.      * by one TOC byte for each AMR frame in the packet, followed
  75.      * by the speech data for all the AMR frames.
  76.      *
  77.      * The header byte contains only a codec mode request, for
  78.      * requesting what kind of AMR data the sender wants to
  79.      * receive. Not used at the moment.
  80.      */
  81.  
  82.     /* Count the number of frames in the packet. The highest bit
  83.      * is set in a TOC byte if there are more frames following.
  84.      */
  85.     for (frames = 1; frames < len && (buf[frames] & 0x80); frames++) ;
  86.  
  87.     if (1 + frames >= len) {
  88.         /* We hit the end of the packet while counting frames. */
  89.         av_log(ctx, AV_LOG_ERROR, "No speech data found\n");
  90.         return AVERROR_INVALIDDATA;
  91.     }
  92.  
  93.     speech_data = buf + 1 + frames;
  94.  
  95.     /* Everything except the codec mode request byte should be output. */
  96.     if (av_new_packet(pkt, len - 1)) {
  97.         av_log(ctx, AV_LOG_ERROR, "Out of memory\n");
  98.         return AVERROR(ENOMEM);
  99.     }
  100.     pkt->stream_index = st->index;
  101.     ptr = pkt->data;
  102.  
  103.     for (i = 0; i < frames; i++) {
  104.         uint8_t toc = buf[1 + i];
  105.         int frame_size = frame_sizes[(toc >> 3) & 0x0f];
  106.  
  107.         if (speech_data + frame_size > buf + len) {
  108.             /* Too little speech data */
  109.             av_log(ctx, AV_LOG_WARNING, "Too little speech data in the RTP packet\n");
  110.             /* Set the unwritten part of the packet to zero. */
  111.             memset(ptr, 0, pkt->data + pkt->size - ptr);
  112.             pkt->size = ptr - pkt->data;
  113.             return 0;
  114.         }
  115.  
  116.         /* Extract the AMR frame mode from the TOC byte */
  117.         *ptr++ = toc & 0x7C;
  118.  
  119.         /* Copy the speech data */
  120.         memcpy(ptr, speech_data, frame_size);
  121.         speech_data += frame_size;
  122.         ptr += frame_size;
  123.     }
  124.  
  125.     if (speech_data < buf + len) {
  126.         av_log(ctx, AV_LOG_WARNING, "Too much speech data in the RTP packet?\n");
  127.         /* Set the unwritten part of the packet to zero. */
  128.         memset(ptr, 0, pkt->data + pkt->size - ptr);
  129.         pkt->size = ptr - pkt->data;
  130.     }
  131.  
  132.     return 0;
  133. }
  134.  
  135. static int amr_parse_fmtp(AVFormatContext *s,
  136.                           AVStream *stream, PayloadContext *data,
  137.                           const char *attr, const char *value)
  138. {
  139.     /* Some AMR SDP configurations contain "octet-align", without
  140.      * the trailing =1. Therefore, if the value is empty,
  141.      * interpret it as "1".
  142.      */
  143.     if (!strcmp(value, "")) {
  144.         av_log(s, AV_LOG_WARNING, "AMR fmtp attribute %s had "
  145.                                   "nonstandard empty value\n", attr);
  146.         value = "1";
  147.     }
  148.     if (!strcmp(attr, "octet-align"))
  149.         data->octet_align = atoi(value);
  150.     else if (!strcmp(attr, "crc"))
  151.         data->crc = atoi(value);
  152.     else if (!strcmp(attr, "interleaving"))
  153.         data->interleaving = atoi(value);
  154.     else if (!strcmp(attr, "channels"))
  155.         data->channels = atoi(value);
  156.     return 0;
  157. }
  158.  
  159. static int amr_parse_sdp_line(AVFormatContext *s, int st_index,
  160.                               PayloadContext *data, const char *line)
  161. {
  162.     const char *p;
  163.     int ret;
  164.  
  165.     if (st_index < 0)
  166.         return 0;
  167.  
  168.     /* Parse an fmtp line this one:
  169.      * a=fmtp:97 octet-align=1; interleaving=0
  170.      * That is, a normal fmtp: line followed by semicolon & space
  171.      * separated key/value pairs.
  172.      */
  173.     if (av_strstart(line, "fmtp:", &p)) {
  174.         ret = ff_parse_fmtp(s, s->streams[st_index], data, p, amr_parse_fmtp);
  175.         if (!data->octet_align || data->crc ||
  176.             data->interleaving || data->channels != 1) {
  177.             av_log(s, AV_LOG_ERROR, "Unsupported RTP/AMR configuration!\n");
  178.             return -1;
  179.         }
  180.         return ret;
  181.     }
  182.     return 0;
  183. }
  184.  
  185. RTPDynamicProtocolHandler ff_amr_nb_dynamic_handler = {
  186.     .enc_name         = "AMR",
  187.     .codec_type       = AVMEDIA_TYPE_AUDIO,
  188.     .codec_id         = AV_CODEC_ID_AMR_NB,
  189.     .priv_data_size   = sizeof(PayloadContext),
  190.     .init             = amr_init,
  191.     .parse_sdp_a_line = amr_parse_sdp_line,
  192.     .parse_packet     = amr_handle_packet,
  193. };
  194.  
  195. RTPDynamicProtocolHandler ff_amr_wb_dynamic_handler = {
  196.     .enc_name         = "AMR-WB",
  197.     .codec_type       = AVMEDIA_TYPE_AUDIO,
  198.     .codec_id         = AV_CODEC_ID_AMR_WB,
  199.     .priv_data_size   = sizeof(PayloadContext),
  200.     .init             = amr_init,
  201.     .parse_sdp_a_line = amr_parse_sdp_line,
  202.     .parse_packet     = amr_handle_packet,
  203. };
  204.