1/* 2 * Interface to libtwolame for mp2 encoding 3 * Copyright (c) 2012 Paul B Mahol 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 * @file 24 * Interface to libtwolame for mp2 encoding. 25 */ 26 27#include <twolame.h> 28 29#include "libavutil/channel_layout.h" 30#include "libavutil/common.h" 31#include "libavutil/opt.h" 32 33#include "avcodec.h" 34#include "codec_internal.h" 35#include "encode.h" 36#include "internal.h" 37#include "mpegaudio.h" 38 39typedef struct TWOLAMEContext { 40 AVClass *class; 41 int mode; 42 int psymodel; 43 int energy; 44 int error_protection; 45 int copyright; 46 int original; 47 int verbosity; 48 49 twolame_options *glopts; 50 int64_t next_pts; 51} TWOLAMEContext; 52 53static av_cold int twolame_encode_close(AVCodecContext *avctx) 54{ 55 TWOLAMEContext *s = avctx->priv_data; 56 twolame_close(&s->glopts); 57 return 0; 58} 59 60static av_cold int twolame_encode_init(AVCodecContext *avctx) 61{ 62 TWOLAMEContext *s = avctx->priv_data; 63 int ret; 64 65 avctx->frame_size = TWOLAME_SAMPLES_PER_FRAME; 66 avctx->initial_padding = 512 - 32 + 1; 67 68 s->glopts = twolame_init(); 69 if (!s->glopts) 70 return AVERROR(ENOMEM); 71 72 twolame_set_verbosity(s->glopts, s->verbosity); 73 twolame_set_mode(s->glopts, s->mode); 74 twolame_set_psymodel(s->glopts, s->psymodel); 75 twolame_set_energy_levels(s->glopts, s->energy); 76 twolame_set_error_protection(s->glopts, s->error_protection); 77 twolame_set_copyright(s->glopts, s->copyright); 78 twolame_set_original(s->glopts, s->original); 79 80 twolame_set_num_channels(s->glopts, avctx->ch_layout.nb_channels); 81 twolame_set_in_samplerate(s->glopts, avctx->sample_rate); 82 twolame_set_out_samplerate(s->glopts, avctx->sample_rate); 83 84 if (!avctx->bit_rate) { 85 if ((s->mode == TWOLAME_AUTO_MODE && avctx->ch_layout.nb_channels == 1) || s->mode == TWOLAME_MONO) 86 avctx->bit_rate = avctx->sample_rate < 28000 ? 80000 : 192000; 87 else 88 avctx->bit_rate = avctx->sample_rate < 28000 ? 160000 : 384000; 89 } 90 91 if (avctx->flags & AV_CODEC_FLAG_QSCALE || !avctx->bit_rate) { 92 twolame_set_VBR(s->glopts, TRUE); 93 twolame_set_VBR_level(s->glopts, 94 avctx->global_quality / (float) FF_QP2LAMBDA); 95 av_log(avctx, AV_LOG_WARNING, 96 "VBR in MP2 is a hack, use another codec that supports it.\n"); 97 } else { 98 twolame_set_bitrate(s->glopts, avctx->bit_rate / 1000); 99 } 100 101 ret = twolame_init_params(s->glopts); 102 if (ret) { 103 twolame_encode_close(avctx); 104 return AVERROR_UNKNOWN; 105 } 106 107 return 0; 108} 109 110static int twolame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, 111 const AVFrame *frame, int *got_packet_ptr) 112{ 113 TWOLAMEContext *s = avctx->priv_data; 114 int ret; 115 116 if ((ret = ff_alloc_packet(avctx, avpkt, MPA_MAX_CODED_FRAME_SIZE)) < 0) 117 return ret; 118 119 if (frame) { 120 switch (avctx->sample_fmt) { 121 case AV_SAMPLE_FMT_FLT: 122 ret = twolame_encode_buffer_float32_interleaved(s->glopts, 123 (const float *)frame->data[0], 124 frame->nb_samples, 125 avpkt->data, 126 avpkt->size); 127 break; 128 case AV_SAMPLE_FMT_FLTP: 129 ret = twolame_encode_buffer_float32(s->glopts, 130 (const float *)frame->data[0], 131 (const float *)frame->data[1], 132 frame->nb_samples, 133 avpkt->data, avpkt->size); 134 break; 135 case AV_SAMPLE_FMT_S16: 136 ret = twolame_encode_buffer_interleaved(s->glopts, 137 (const short int *)frame->data[0], 138 frame->nb_samples, 139 avpkt->data, avpkt->size); 140 break; 141 case AV_SAMPLE_FMT_S16P: 142 ret = twolame_encode_buffer(s->glopts, 143 (const short int *)frame->data[0], 144 (const short int *)frame->data[1], 145 frame->nb_samples, 146 avpkt->data, avpkt->size); 147 break; 148 default: 149 av_log(avctx, AV_LOG_ERROR, 150 "Unsupported sample format %d.\n", avctx->sample_fmt); 151 return AVERROR_BUG; 152 } 153 } else { 154 ret = twolame_encode_flush(s->glopts, avpkt->data, avpkt->size); 155 } 156 157 if (!ret) // no bytes written 158 return 0; 159 if (ret < 0) // twolame error 160 return AVERROR_UNKNOWN; 161 162 if (frame) { 163 avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples); 164 if (frame->pts != AV_NOPTS_VALUE) 165 avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding); 166 } else { 167 avpkt->pts = s->next_pts; 168 } 169 // this is for setting pts for flushed packet(s). 170 if (avpkt->pts != AV_NOPTS_VALUE) 171 s->next_pts = avpkt->pts + avpkt->duration; 172 173 av_shrink_packet(avpkt, ret); 174 *got_packet_ptr = 1; 175 return 0; 176} 177 178#define OFFSET(x) offsetof(TWOLAMEContext, x) 179#define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM 180static const AVOption options[] = { 181 { "mode", "Mpeg Mode", OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = TWOLAME_AUTO_MODE }, TWOLAME_AUTO_MODE, TWOLAME_MONO, AE, "mode"}, 182 { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_AUTO_MODE }, 0, 0, AE, "mode" }, 183 { "stereo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_STEREO }, 0, 0, AE, "mode" }, 184 { "joint_stereo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_JOINT_STEREO }, 0, 0, AE, "mode" }, 185 { "dual_channel", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_DUAL_CHANNEL }, 0, 0, AE, "mode" }, 186 { "mono", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_MONO }, 0, 0, AE, "mode" }, 187 { "psymodel", "Psychoacoustic Model", OFFSET(psymodel), AV_OPT_TYPE_INT, { .i64 = 3 }, -1, 4, AE}, 188 { "energy_levels","enable energy levels", OFFSET(energy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, 189 { "error_protection","enable CRC error protection", OFFSET(error_protection), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, 190 { "copyright", "set MPEG Audio Copyright flag", OFFSET(copyright), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, 191 { "original", "set MPEG Audio Original flag", OFFSET(original), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, 192 { "verbosity", "set library optput level (0-10)", OFFSET(verbosity), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 10, AE}, 193 { NULL }, 194}; 195 196static const AVClass twolame_class = { 197 .class_name = "libtwolame encoder", 198 .item_name = av_default_item_name, 199 .option = options, 200 .version = LIBAVUTIL_VERSION_INT, 201}; 202 203static const FFCodecDefault twolame_defaults[] = { 204 { "b", "0" }, 205 { NULL }, 206}; 207 208static const int twolame_samplerates[] = { 209 16000, 22050, 24000, 32000, 44100, 48000, 0 210}; 211 212const FFCodec ff_libtwolame_encoder = { 213 .p.name = "libtwolame", 214 .p.long_name = NULL_IF_CONFIG_SMALL("libtwolame MP2 (MPEG audio layer 2)"), 215 .p.type = AVMEDIA_TYPE_AUDIO, 216 .p.id = AV_CODEC_ID_MP2, 217 .priv_data_size = sizeof(TWOLAMEContext), 218 .init = twolame_encode_init, 219 FF_CODEC_ENCODE_CB(twolame_encode_frame), 220 .close = twolame_encode_close, 221 .p.capabilities = AV_CODEC_CAP_DELAY, 222 .defaults = twolame_defaults, 223 .p.priv_class = &twolame_class, 224 .p.sample_fmts = (const enum AVSampleFormat[]) { 225 AV_SAMPLE_FMT_FLT, 226 AV_SAMPLE_FMT_FLTP, 227 AV_SAMPLE_FMT_S16, 228 AV_SAMPLE_FMT_S16P, 229 AV_SAMPLE_FMT_NONE 230 }, 231#if FF_API_OLD_CHANNEL_LAYOUT 232 .p.channel_layouts = (const uint64_t[]) { 233 AV_CH_LAYOUT_MONO, 234 AV_CH_LAYOUT_STEREO, 235 0 }, 236#endif 237 .p.ch_layouts = (const AVChannelLayout[]) { 238 AV_CHANNEL_LAYOUT_MONO, 239 AV_CHANNEL_LAYOUT_STEREO, 240 { 0 }, 241 }, 242 .p.supported_samplerates = twolame_samplerates, 243 .p.wrapper_name = "libtwolame", 244}; 245