diff --git a/doc/general.texi b/doc/general.texi index 585ed8c12e..b486d08503 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -920,7 +920,7 @@ following image formats are supported: @item Monkey's Audio @tab @tab X @item MP1 (MPEG audio layer 1) @tab @tab IX @item MP2 (MPEG audio layer 2) @tab IX @tab IX - @tab libtwolame can be used alternatively for encoding. + @tab encoding supported also through external library TwoLAME @item MP3 (MPEG audio layer 3) @tab E @tab IX @tab encoding supported through external library LAME, ADU MP3 and MP3onMP4 also supported @item MPEG-4 Audio Lossless Coding (ALS) @tab @tab X diff --git a/libavcodec/libtwolame.c b/libavcodec/libtwolame.c index dc4efe58ba..88a708a4a3 100644 --- a/libavcodec/libtwolame.c +++ b/libavcodec/libtwolame.c @@ -26,22 +26,25 @@ #include +#include "libavutil/common.h" #include "libavutil/opt.h" + #include "avcodec.h" #include "internal.h" #include "mpegaudio.h" typedef struct TWOLAMEContext { - AVClass *class; - int mode; - int psymodel; - int energy; - int error_protection; - int copyright; - int original; + AVClass *class; + int mode; + int psymodel; + int energy; + int error_protection; + int copyright; + int original; + int verbosity; twolame_options *glopts; - int64_t next_pts; + int64_t next_pts; } TWOLAMEContext; static av_cold int twolame_encode_close(AVCodecContext *avctx) @@ -57,12 +60,13 @@ static av_cold int twolame_encode_init(AVCodecContext *avctx) int ret; avctx->frame_size = TWOLAME_SAMPLES_PER_FRAME; + avctx->delay = 512 - 32 + 1; s->glopts = twolame_init(); if (!s->glopts) return AVERROR(ENOMEM); - twolame_set_verbosity(s->glopts, 0); + twolame_set_verbosity(s->glopts, s->verbosity); twolame_set_mode(s->glopts, s->mode); twolame_set_psymodel(s->glopts, s->psymodel); twolame_set_energy_levels(s->glopts, s->energy); @@ -75,19 +79,21 @@ static av_cold int twolame_encode_init(AVCodecContext *avctx) twolame_set_out_samplerate(s->glopts, avctx->sample_rate); if (avctx->flags & CODEC_FLAG_QSCALE || !avctx->bit_rate) { twolame_set_VBR(s->glopts, TRUE); - twolame_set_VBR_level(s->glopts, avctx->global_quality); - av_log(avctx, AV_LOG_WARNING, "VBR mode is experimental!\n"); + twolame_set_VBR_level(s->glopts, + avctx->global_quality / (float) FF_QP2LAMBDA); + av_log(avctx, AV_LOG_WARNING, + "VBR in MP2 is a hack, use another codec that supports it.\n"); } else { twolame_set_bitrate(s->glopts, avctx->bit_rate / 1000); } - if ((ret = twolame_init_params(s->glopts))) - goto error; + ret = twolame_init_params(s->glopts); + if (ret) { + twolame_encode_close(avctx); + return AVERROR_UNKNOWN; + } return 0; -error: - twolame_encode_close(avctx); - return ret; } static int twolame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, @@ -103,96 +109,118 @@ static int twolame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, switch (avctx->sample_fmt) { case AV_SAMPLE_FMT_FLT: ret = twolame_encode_buffer_float32_interleaved(s->glopts, - frame->data[0], - frame->nb_samples, - avpkt->data, avpkt->size); + (const float *)frame->data[0], + frame->nb_samples, + avpkt->data, + avpkt->size); break; case AV_SAMPLE_FMT_FLTP: ret = twolame_encode_buffer_float32(s->glopts, - frame->data[0], frame->data[1], - frame->nb_samples, - avpkt->data, avpkt->size); + (const float *)frame->data[0], + (const float *)frame->data[1], + frame->nb_samples, + avpkt->data, avpkt->size); break; case AV_SAMPLE_FMT_S16: ret = twolame_encode_buffer_interleaved(s->glopts, - frame->data[0], - frame->nb_samples, - avpkt->data, avpkt->size); + (const short int *)frame->data[0], + frame->nb_samples, + avpkt->data, avpkt->size); break; case AV_SAMPLE_FMT_S16P: ret = twolame_encode_buffer(s->glopts, - frame->data[0], frame->data[1], + (const short int *)frame->data[0], + (const short int *)frame->data[1], frame->nb_samples, avpkt->data, avpkt->size); break; default: + av_log(avctx, AV_LOG_ERROR, + "Unsupported sample format %d.\n", avctx->sample_fmt); return AVERROR_BUG; } } else { ret = twolame_encode_flush(s->glopts, avpkt->data, avpkt->size); } - if (ret > 0) { - avpkt->duration = ff_samples_to_time_base(avctx, avctx->frame_size); - if (frame) { - if (frame->pts != AV_NOPTS_VALUE) - avpkt->pts = frame->pts; - } else { - avpkt->pts = s->next_pts; - } - if (avpkt->pts != AV_NOPTS_VALUE) - s->next_pts = avpkt->pts + avpkt->duration; - - avpkt->size = ret; - *got_packet_ptr = 1; + if (!ret) // no bytes written return 0; - } + if (ret < 0) // twolame error + return AVERROR_UNKNOWN; - return ret; + avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples); + if (frame) { + if (frame->pts != AV_NOPTS_VALUE) + avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->delay); + } else { + avpkt->pts = s->next_pts; + } + // this is for setting pts for flushed packet(s). + if (avpkt->pts != AV_NOPTS_VALUE) + s->next_pts = avpkt->pts + avpkt->duration; + + av_shrink_packet(avpkt, ret); + *got_packet_ptr = 1; + return 0; } #define OFFSET(x) offsetof(TWOLAMEContext, x) #define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "mode", "Mpeg Mode", OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = TWOLAME_AUTO_MODE }, TWOLAME_AUTO_MODE, TWOLAME_MONO, AE, "mode"}, - { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_AUTO_MODE }, 0, 0, AE, "mode" }, - { "stereo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_STEREO }, 0, 0, AE, "mode" }, - { "joint_stereo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_JOINT_STEREO }, 0, 0, AE, "mode" }, - { "dual_channel", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_DUAL_CHANNEL }, 0, 0, AE, "mode" }, - { "mono", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_MONO }, 0, 0, AE, "mode" }, - { "psymodel", "Psychoacoustic Model", OFFSET(psymodel), AV_OPT_TYPE_INT, { .i64 = 3 }, -1, 4, AE}, - { "energy_levels","enable energy levels", OFFSET(energy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, + { "mode", "Mpeg Mode", OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = TWOLAME_AUTO_MODE }, TWOLAME_AUTO_MODE, TWOLAME_MONO, AE, "mode"}, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_AUTO_MODE }, 0, 0, AE, "mode" }, + { "stereo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_STEREO }, 0, 0, AE, "mode" }, + { "joint_stereo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_JOINT_STEREO }, 0, 0, AE, "mode" }, + { "dual_channel", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_DUAL_CHANNEL }, 0, 0, AE, "mode" }, + { "mono", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_MONO }, 0, 0, AE, "mode" }, + { "psymodel", "Psychoacoustic Model", OFFSET(psymodel), AV_OPT_TYPE_INT, { .i64 = 3 }, -1, 4, AE}, + { "energy_levels","enable energy levels", OFFSET(energy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, { "error_protection","enable CRC error protection", OFFSET(error_protection), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, - { "copyright", "set MPEG Audio Copyright flag", OFFSET(copyright), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, - { "original", "set MPEG Audio Original flag", OFFSET(original), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, + { "copyright", "set MPEG Audio Copyright flag", OFFSET(copyright), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, + { "original", "set MPEG Audio Original flag", OFFSET(original), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, + { "verbosity", "set library optput level (0-10)", OFFSET(verbosity), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 10, AE}, { NULL }, }; -static const AVClass libtwolame_class = { +static const AVClass twolame_class = { .class_name = "libtwolame encoder", .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, }; -AVCodec ff_libtwolame_encoder = { - .name = "libtwolame", - .long_name = NULL_IF_CONFIG_SMALL("libtwolame MP2 (MPEG audio layer 2)"), - .type = AVMEDIA_TYPE_AUDIO, - .id = AV_CODEC_ID_MP2, - .priv_data_size = sizeof(TWOLAMEContext), - .init = twolame_encode_init, - .encode2 = twolame_encode_frame, - .close = twolame_encode_close, - .capabilities = CODEC_CAP_DELAY, - .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, - .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, - AV_CH_LAYOUT_STEREO, - 0 }, - .supported_samplerates = (const int[]){ 16000, 22050, 24000, 32000, 44100, 48000, 0 }, - .priv_class = &libtwolame_class, +static const AVCodecDefault twolame_defaults[] = { + { "b", "384000" }, + { "ar", "48000" }, + { NULL }, +}; + +static const int twolame_samplerates[] = { + 16000, 22050, 24000, 32000, 44100, 48000, 0 +}; + +AVCodec ff_libtwolame_encoder = { + .name = "libtwolame", + .long_name = NULL_IF_CONFIG_SMALL("libtwolame MP2 (MPEG audio layer 2)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_MP2, + .priv_data_size = sizeof(TWOLAMEContext), + .init = twolame_encode_init, + .encode2 = twolame_encode_frame, + .close = twolame_encode_close, + .capabilities = CODEC_CAP_DELAY, + .defaults = twolame_defaults, + .priv_class = &twolame_class, + .sample_fmts = (const enum AVSampleFormat[]) { + AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_NONE + }, + .channel_layouts = (const uint64_t[]) { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + 0 }, + .supported_samplerates = twolame_samplerates, }; diff --git a/libavcodec/version.h b/libavcodec/version.h index d50016abce..3fbf8ab208 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -30,7 +30,7 @@ #define LIBAVCODEC_VERSION_MAJOR 55 #define LIBAVCODEC_VERSION_MINOR 58 -#define LIBAVCODEC_VERSION_MICRO 102 +#define LIBAVCODEC_VERSION_MICRO 103 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \