1 /*
2  * iLBC storage file format
3  * Copyright (c) 2012 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 "config_components.h"
23 
24 #include "avformat.h"
25 #include "internal.h"
26 #include "rawenc.h"
27 
28 static const char mode20_header[] = "#!iLBC20\n";
29 static const char mode30_header[] = "#!iLBC30\n";
30 
ilbc_write_header(AVFormatContext *s)31 static int ilbc_write_header(AVFormatContext *s)
32 {
33     AVIOContext *pb = s->pb;
34     AVCodecParameters *par;
35 
36     if (s->nb_streams != 1) {
37         av_log(s, AV_LOG_ERROR, "Unsupported number of streams\n");
38         return AVERROR(EINVAL);
39     }
40     par = s->streams[0]->codecpar;
41 
42     if (par->codec_id != AV_CODEC_ID_ILBC) {
43         av_log(s, AV_LOG_ERROR, "Unsupported codec\n");
44         return AVERROR(EINVAL);
45     }
46 
47     if (par->block_align == 50) {
48         avio_write(pb, mode30_header, sizeof(mode30_header) - 1);
49     } else if (par->block_align == 38) {
50         avio_write(pb, mode20_header, sizeof(mode20_header) - 1);
51     } else {
52         av_log(s, AV_LOG_ERROR, "Unsupported mode\n");
53         return AVERROR(EINVAL);
54     }
55     return 0;
56 }
57 
ilbc_probe(const AVProbeData *p)58 static int ilbc_probe(const AVProbeData *p)
59 {
60     // Only check for "#!iLBC" which matches both formats
61     if (!memcmp(p->buf, mode20_header, 6))
62         return AVPROBE_SCORE_MAX;
63     else
64         return 0;
65 }
66 
ilbc_read_header(AVFormatContext *s)67 static int ilbc_read_header(AVFormatContext *s)
68 {
69     AVIOContext *pb = s->pb;
70     AVStream *st;
71     uint8_t header[9];
72 
73     avio_read(pb, header, 9);
74 
75     st = avformat_new_stream(s, NULL);
76     if (!st)
77         return AVERROR(ENOMEM);
78     st->codecpar->codec_id = AV_CODEC_ID_ILBC;
79     st->codecpar->sample_rate = 8000;
80     st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
81     st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
82     st->start_time = 0;
83     avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
84     if (!memcmp(header, mode20_header, sizeof(mode20_header) - 1)) {
85         st->codecpar->block_align = 38;
86         st->codecpar->bit_rate = 15200;
87     } else if (!memcmp(header, mode30_header, sizeof(mode30_header) - 1)) {
88         st->codecpar->block_align = 50;
89         st->codecpar->bit_rate = 13333;
90     } else {
91         av_log(s, AV_LOG_ERROR, "Unrecognized iLBC file header\n");
92         return AVERROR_INVALIDDATA;
93     }
94 
95     return 0;
96 }
97 
ilbc_read_packet(AVFormatContext *s, AVPacket *pkt)98 static int ilbc_read_packet(AVFormatContext *s,
99                           AVPacket *pkt)
100 {
101     AVCodecParameters *par = s->streams[0]->codecpar;
102     int ret;
103 
104     if ((ret = av_get_packet(s->pb, pkt, par->block_align)) != par->block_align)
105         return ret < 0 ? ret : AVERROR_INVALIDDATA;
106 
107     pkt->stream_index = 0;
108     pkt->duration = par->block_align == 38 ? 160 : 240;
109 
110     return 0;
111 }
112 
113 const AVInputFormat ff_ilbc_demuxer = {
114     .name         = "ilbc",
115     .long_name    = NULL_IF_CONFIG_SMALL("iLBC storage"),
116     .read_probe   = ilbc_probe,
117     .read_header  = ilbc_read_header,
118     .read_packet  = ilbc_read_packet,
119     .flags        = AVFMT_GENERIC_INDEX,
120 };
121 
122 #if CONFIG_ILBC_MUXER
123 const AVOutputFormat ff_ilbc_muxer = {
124     .name         = "ilbc",
125     .long_name    = NULL_IF_CONFIG_SMALL("iLBC storage"),
126     .mime_type    = "audio/iLBC",
127     .extensions   = "lbc",
128     .audio_codec  = AV_CODEC_ID_ILBC,
129     .write_header = ilbc_write_header,
130     .write_packet = ff_raw_write_packet,
131     .flags        = AVFMT_NOTIMESTAMPS,
132 };
133 #endif
134