LCOV - code coverage report
Current view: top level - src/libavformat - amr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 41 66 62.1 %
Date: 2017-01-28 02:43:52 Functions: 3 5 60.0 %

          Line data    Source code
       1             : /*
       2             :  * amr file format
       3             :  * Copyright (c) 2001 FFmpeg project
       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             : /*
      23             : Write and read amr data according to RFC3267, http://www.ietf.org/rfc/rfc3267.txt?number=3267
      24             : 
      25             : Only mono files are supported.
      26             : 
      27             : */
      28             : 
      29             : #include "libavutil/channel_layout.h"
      30             : #include "avformat.h"
      31             : #include "internal.h"
      32             : 
      33             : typedef struct {
      34             :     uint64_t cumulated_size;
      35             :     uint64_t block_count;
      36             : } AMRContext;
      37             : 
      38             : static const char AMR_header[]   = "#!AMR\n";
      39             : static const char AMRWB_header[] = "#!AMR-WB\n";
      40             : 
      41             : #if CONFIG_AMR_MUXER
      42           0 : static int amr_write_header(AVFormatContext *s)
      43             : {
      44           0 :     AVIOContext    *pb  = s->pb;
      45           0 :     AVCodecParameters *par = s->streams[0]->codecpar;
      46             : 
      47           0 :     s->priv_data = NULL;
      48             : 
      49           0 :     if (par->codec_id == AV_CODEC_ID_AMR_NB) {
      50           0 :         avio_write(pb, AMR_header,   sizeof(AMR_header)   - 1); /* magic number */
      51           0 :     } else if (par->codec_id == AV_CODEC_ID_AMR_WB) {
      52           0 :         avio_write(pb, AMRWB_header, sizeof(AMRWB_header) - 1); /* magic number */
      53             :     } else {
      54           0 :         return -1;
      55             :     }
      56           0 :     avio_flush(pb);
      57           0 :     return 0;
      58             : }
      59             : 
      60           0 : static int amr_write_packet(AVFormatContext *s, AVPacket *pkt)
      61             : {
      62           0 :     avio_write(s->pb, pkt->data, pkt->size);
      63           0 :     return 0;
      64             : }
      65             : #endif /* CONFIG_AMR_MUXER */
      66             : 
      67        5565 : static int amr_probe(AVProbeData *p)
      68             : {
      69             :     // Only check for "#!AMR" which could be amr-wb, amr-nb.
      70             :     // This will also trigger multichannel files: "#!AMR_MC1.0\n" and
      71             :     // "#!AMR-WB_MC1.0\n" (not supported)
      72             : 
      73        5565 :     if (!memcmp(p->buf, AMR_header, 5))
      74           8 :         return AVPROBE_SCORE_MAX;
      75             :     else
      76        5557 :         return 0;
      77             : }
      78             : 
      79             : /* amr input */
      80           8 : static int amr_read_header(AVFormatContext *s)
      81             : {
      82           8 :     AVIOContext *pb = s->pb;
      83             :     AVStream *st;
      84             :     uint8_t header[9];
      85             : 
      86           8 :     avio_read(pb, header, 6);
      87             : 
      88           8 :     st = avformat_new_stream(s, NULL);
      89           8 :     if (!st)
      90           0 :         return AVERROR(ENOMEM);
      91           8 :     if (memcmp(header, AMR_header, 6)) {
      92           0 :         avio_read(pb, header + 6, 3);
      93           0 :         if (memcmp(header, AMRWB_header, 9)) {
      94           0 :             return -1;
      95             :         }
      96             : 
      97           0 :         st->codecpar->codec_tag   = MKTAG('s', 'a', 'w', 'b');
      98           0 :         st->codecpar->codec_id    = AV_CODEC_ID_AMR_WB;
      99           0 :         st->codecpar->sample_rate = 16000;
     100             :     } else {
     101           8 :         st->codecpar->codec_tag   = MKTAG('s', 'a', 'm', 'r');
     102           8 :         st->codecpar->codec_id    = AV_CODEC_ID_AMR_NB;
     103           8 :         st->codecpar->sample_rate = 8000;
     104             :     }
     105           8 :     st->codecpar->channels   = 1;
     106           8 :     st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
     107           8 :     st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
     108           8 :     avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
     109             : 
     110           8 :     return 0;
     111             : }
     112             : 
     113        2280 : static int amr_read_packet(AVFormatContext *s, AVPacket *pkt)
     114             : {
     115        2280 :     AVCodecParameters *par = s->streams[0]->codecpar;
     116        2280 :     int read, size = 0, toc, mode;
     117        2280 :     int64_t pos = avio_tell(s->pb);
     118        2280 :     AMRContext *amr = s->priv_data;
     119             : 
     120        2280 :     if (avio_feof(s->pb)) {
     121           0 :         return AVERROR(EIO);
     122             :     }
     123             : 
     124             :     // FIXME this is wrong, this should rather be in an AVParser
     125        2280 :     toc  = avio_r8(s->pb);
     126        2280 :     mode = (toc >> 3) & 0x0F;
     127             : 
     128        2280 :     if (par->codec_id == AV_CODEC_ID_AMR_NB) {
     129             :         static const uint8_t packed_size[16] = {
     130             :             12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0
     131             :         };
     132             : 
     133        2280 :         size = packed_size[mode] + 1;
     134           0 :     } else if (par->codec_id == AV_CODEC_ID_AMR_WB) {
     135             :         static const uint8_t packed_size[16] = {
     136             :             18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1
     137             :         };
     138             : 
     139           0 :         size = packed_size[mode];
     140             :     }
     141             : 
     142        2280 :     if (!size || av_new_packet(pkt, size))
     143           0 :         return AVERROR(EIO);
     144             : 
     145        2280 :     if (amr->cumulated_size < UINT64_MAX - size) {
     146        2280 :         amr->cumulated_size += size;
     147             :         /* Both AMR formats have 50 frames per second */
     148        2280 :         s->streams[0]->codecpar->bit_rate = amr->cumulated_size / ++amr->block_count * 8 * 50;
     149             :     }
     150             : 
     151        2280 :     pkt->stream_index = 0;
     152        2280 :     pkt->pos          = pos;
     153        2280 :     pkt->data[0]      = toc;
     154        2280 :     pkt->duration     = par->codec_id == AV_CODEC_ID_AMR_NB ? 160 : 320;
     155        2280 :     read              = avio_read(s->pb, pkt->data + 1, size - 1);
     156             : 
     157        2280 :     if (read != size - 1) {
     158           8 :         av_packet_unref(pkt);
     159           8 :         return AVERROR(EIO);
     160             :     }
     161             : 
     162        2272 :     return 0;
     163             : }
     164             : 
     165             : #if CONFIG_AMR_DEMUXER
     166             : AVInputFormat ff_amr_demuxer = {
     167             :     .name           = "amr",
     168             :     .long_name      = NULL_IF_CONFIG_SMALL("3GPP AMR"),
     169             :     .priv_data_size = sizeof(AMRContext),
     170             :     .read_probe     = amr_probe,
     171             :     .read_header    = amr_read_header,
     172             :     .read_packet    = amr_read_packet,
     173             :     .flags          = AVFMT_GENERIC_INDEX,
     174             : };
     175             : #endif
     176             : 
     177             : #if CONFIG_AMR_MUXER
     178             : AVOutputFormat ff_amr_muxer = {
     179             :     .name              = "amr",
     180             :     .long_name         = NULL_IF_CONFIG_SMALL("3GPP AMR"),
     181             :     .mime_type         = "audio/amr",
     182             :     .extensions        = "amr",
     183             :     .audio_codec       = AV_CODEC_ID_AMR_NB,
     184             :     .video_codec       = AV_CODEC_ID_NONE,
     185             :     .write_header      = amr_write_header,
     186             :     .write_packet      = amr_write_packet,
     187             :     .flags             = AVFMT_NOTIMESTAMPS,
     188             : };
     189             : #endif

Generated by: LCOV version 1.12