1/* 2 * iLBC decoder/encoder stub 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 <ilbc.h> 23 24#include "libavutil/channel_layout.h" 25#include "libavutil/common.h" 26#include "libavutil/opt.h" 27#include "avcodec.h" 28#include "codec_internal.h" 29#include "encode.h" 30#include "internal.h" 31 32#ifndef LIBILBC_VERSION_MAJOR 33#define LIBILBC_VERSION_MAJOR 2 34#endif 35 36static int get_mode(AVCodecContext *avctx) 37{ 38 if (avctx->block_align == 38) 39 return 20; 40 else if (avctx->block_align == 50) 41 return 30; 42 else if (avctx->bit_rate > 0) 43 return avctx->bit_rate <= 14000 ? 30 : 20; 44 else 45 return -1; 46} 47 48typedef struct ILBCDecContext { 49 const AVClass *class; 50#if LIBILBC_VERSION_MAJOR < 3 51 iLBC_Dec_Inst_t decoder; 52#else 53 IlbcDecoder decoder; 54#endif 55 int enhance; 56} ILBCDecContext; 57 58static const AVOption ilbc_dec_options[] = { 59 { "enhance", "Enhance the decoded audio (adds delay)", offsetof(ILBCDecContext, enhance), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM }, 60 { NULL } 61}; 62 63static const AVClass ilbc_dec_class = { 64 .class_name = "libilbc", 65 .item_name = av_default_item_name, 66 .option = ilbc_dec_options, 67 .version = LIBAVUTIL_VERSION_INT, 68}; 69 70static av_cold int ilbc_decode_init(AVCodecContext *avctx) 71{ 72 ILBCDecContext *s = avctx->priv_data; 73 int mode; 74 75 if ((mode = get_mode(avctx)) < 0) { 76 av_log(avctx, AV_LOG_ERROR, "iLBC frame mode not indicated\n"); 77 return AVERROR(EINVAL); 78 } 79 80 WebRtcIlbcfix_InitDecode(&s->decoder, mode, s->enhance); 81 82 av_channel_layout_uninit(&avctx->ch_layout); 83 avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; 84 avctx->sample_rate = 8000; 85 avctx->sample_fmt = AV_SAMPLE_FMT_S16; 86 87 return 0; 88} 89 90static int ilbc_decode_frame(AVCodecContext *avctx, AVFrame *frame, 91 int *got_frame_ptr, AVPacket *avpkt) 92{ 93 const uint8_t *buf = avpkt->data; 94 int buf_size = avpkt->size; 95 ILBCDecContext *s = avctx->priv_data; 96 int ret; 97 98 if (s->decoder.no_of_bytes > buf_size) { 99#if LIBILBC_VERSION_MAJOR < 3 100 av_log(avctx, AV_LOG_ERROR, "iLBC frame too short (%u, should be %u)\n", 101#else 102 av_log(avctx, AV_LOG_ERROR, "iLBC frame too short (%u, should be " 103 "%"SIZE_SPECIFIER")\n", 104#endif 105 buf_size, s->decoder.no_of_bytes); 106 return AVERROR_INVALIDDATA; 107 } 108 109 frame->nb_samples = s->decoder.blockl; 110 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 111 return ret; 112 113 WebRtcIlbcfix_DecodeImpl((int16_t *) frame->data[0], (const uint16_t *) buf, &s->decoder, 1); 114 115 *got_frame_ptr = 1; 116 117 return s->decoder.no_of_bytes; 118} 119 120const FFCodec ff_libilbc_decoder = { 121 .p.name = "libilbc", 122 .p.long_name = NULL_IF_CONFIG_SMALL("iLBC (Internet Low Bitrate Codec)"), 123 .p.type = AVMEDIA_TYPE_AUDIO, 124 .p.id = AV_CODEC_ID_ILBC, 125 .priv_data_size = sizeof(ILBCDecContext), 126 .init = ilbc_decode_init, 127 FF_CODEC_DECODE_CB(ilbc_decode_frame), 128 .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, 129 .p.priv_class = &ilbc_dec_class, 130}; 131 132typedef struct ILBCEncContext { 133 const AVClass *class; 134#if LIBILBC_VERSION_MAJOR < 3 135 iLBC_Enc_Inst_t encoder; 136#else 137 IlbcEncoder encoder; 138#endif 139 int mode; 140} ILBCEncContext; 141 142static const AVOption ilbc_enc_options[] = { 143 { "mode", "iLBC mode (20 or 30 ms frames)", offsetof(ILBCEncContext, mode), AV_OPT_TYPE_INT, { .i64 = 20 }, 20, 30, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, 144 { NULL } 145}; 146 147static const AVClass ilbc_enc_class = { 148 .class_name = "libilbc", 149 .item_name = av_default_item_name, 150 .option = ilbc_enc_options, 151 .version = LIBAVUTIL_VERSION_INT, 152}; 153 154static av_cold int ilbc_encode_init(AVCodecContext *avctx) 155{ 156 ILBCEncContext *s = avctx->priv_data; 157 int mode; 158 159 if (avctx->sample_rate != 8000) { 160 av_log(avctx, AV_LOG_ERROR, "Only 8000Hz sample rate supported\n"); 161 return AVERROR(EINVAL); 162 } 163 164 if (avctx->ch_layout.nb_channels != 1) { 165 av_log(avctx, AV_LOG_ERROR, "Only mono supported\n"); 166 return AVERROR(EINVAL); 167 } 168 169 if ((mode = get_mode(avctx)) > 0) 170 s->mode = mode; 171 else 172 s->mode = s->mode != 30 ? 20 : 30; 173 WebRtcIlbcfix_InitEncode(&s->encoder, s->mode); 174 175 avctx->block_align = s->encoder.no_of_bytes; 176 avctx->frame_size = s->encoder.blockl; 177 178 return 0; 179} 180 181static int ilbc_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, 182 const AVFrame *frame, int *got_packet_ptr) 183{ 184 ILBCEncContext *s = avctx->priv_data; 185 int ret; 186 187 if ((ret = ff_alloc_packet(avctx, avpkt, 50)) < 0) 188 return ret; 189 190 WebRtcIlbcfix_EncodeImpl((uint16_t *) avpkt->data, (const int16_t *) frame->data[0], &s->encoder); 191 192 avpkt->size = s->encoder.no_of_bytes; 193 *got_packet_ptr = 1; 194 return 0; 195} 196 197static const FFCodecDefault ilbc_encode_defaults[] = { 198 { "b", "0" }, 199 { NULL } 200}; 201 202const FFCodec ff_libilbc_encoder = { 203 .p.name = "libilbc", 204 .p.long_name = NULL_IF_CONFIG_SMALL("iLBC (Internet Low Bitrate Codec)"), 205 .p.type = AVMEDIA_TYPE_AUDIO, 206 .p.id = AV_CODEC_ID_ILBC, 207 .priv_data_size = sizeof(ILBCEncContext), 208 .init = ilbc_encode_init, 209 FF_CODEC_ENCODE_CB(ilbc_encode_frame), 210 .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, 211 AV_SAMPLE_FMT_NONE }, 212 .defaults = ilbc_encode_defaults, 213 .p.priv_class = &ilbc_enc_class, 214 .p.wrapper_name = "libbilbc", 215}; 216