X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Flibmp3lame.c;h=156665c0d61fdaa19308a7d12de8d1a2fb5ea35d;hb=437211ae73ef1ed8285b4fed7620502ea4999e11;hp=62b55c933799713638a247973d28ec6153ec9cf5;hpb=2912e87a6c9264d556734e2bf94a99c64cf9b102;p=ffmpeg diff --git a/libavcodec/libmp3lame.c b/libavcodec/libmp3lame.c index 62b55c93379..156665c0d61 100644 --- a/libavcodec/libmp3lame.c +++ b/libavcodec/libmp3lame.c @@ -24,205 +24,294 @@ * Interface to libmp3lame for mp3 encoding. */ +#include + +#include "libavutil/channel_layout.h" +#include "libavutil/common.h" +#include "libavutil/float_dsp.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" #include "avcodec.h" +#include "audio_frame_queue.h" +#include "internal.h" #include "mpegaudio.h" -#include +#include "mpegaudiodecheader.h" -#define BUFFER_SIZE (7200 + 2*MPA_FRAME_SIZE + MPA_FRAME_SIZE/4) -typedef struct Mp3AudioContext { +#define BUFFER_SIZE (7200 + 2 * MPA_FRAME_SIZE + MPA_FRAME_SIZE / 4) + +typedef struct LAMEContext { + AVClass *class; + AVCodecContext *avctx; lame_global_flags *gfp; - int stereo; - uint8_t buffer[BUFFER_SIZE]; + uint8_t *buffer; int buffer_index; -} Mp3AudioContext; + int buffer_size; + int reservoir; + float *samples_flt[2]; + AudioFrameQueue afq; + AVFloatDSPContext fdsp; +} LAMEContext; + -static av_cold int MP3lame_encode_init(AVCodecContext *avctx) +static int realloc_buffer(LAMEContext *s) { - Mp3AudioContext *s = avctx->priv_data; + if (!s->buffer || s->buffer_size - s->buffer_index < BUFFER_SIZE) { + uint8_t *tmp; + int new_size = s->buffer_index + 2 * BUFFER_SIZE; + + av_dlog(s->avctx, "resizing output buffer: %d -> %d\n", s->buffer_size, + new_size); + tmp = av_realloc(s->buffer, new_size); + if (!tmp) { + av_freep(&s->buffer); + s->buffer_size = s->buffer_index = 0; + return AVERROR(ENOMEM); + } + s->buffer = tmp; + s->buffer_size = new_size; + } + return 0; +} - if (avctx->channels > 2) - return -1; +static av_cold int mp3lame_encode_close(AVCodecContext *avctx) +{ + LAMEContext *s = avctx->priv_data; + +#if FF_API_OLD_ENCODE_AUDIO + av_freep(&avctx->coded_frame); +#endif + av_freep(&s->samples_flt[0]); + av_freep(&s->samples_flt[1]); + av_freep(&s->buffer); + + ff_af_queue_close(&s->afq); + + lame_close(s->gfp); + return 0; +} + +static av_cold int mp3lame_encode_init(AVCodecContext *avctx) +{ + LAMEContext *s = avctx->priv_data; + int ret; - s->stereo = avctx->channels > 1 ? 1 : 0; + s->avctx = avctx; + /* initialize LAME and get defaults */ if ((s->gfp = lame_init()) == NULL) - goto err; - lame_set_in_samplerate(s->gfp, avctx->sample_rate); - lame_set_out_samplerate(s->gfp, avctx->sample_rate); + return AVERROR(ENOMEM); + lame_set_num_channels(s->gfp, avctx->channels); - if(avctx->compression_level == FF_COMPRESSION_DEFAULT) { + lame_set_mode(s->gfp, avctx->channels > 1 ? JOINT_STEREO : MONO); + + /* sample rate */ + lame_set_in_samplerate (s->gfp, avctx->sample_rate); + lame_set_out_samplerate(s->gfp, avctx->sample_rate); + + /* algorithmic quality */ + if (avctx->compression_level == FF_COMPRESSION_DEFAULT) lame_set_quality(s->gfp, 5); - } else { + else lame_set_quality(s->gfp, avctx->compression_level); - } - lame_set_mode(s->gfp, s->stereo ? JOINT_STEREO : MONO); - lame_set_brate(s->gfp, avctx->bit_rate/1000); - if(avctx->flags & CODEC_FLAG_QSCALE) { - lame_set_brate(s->gfp, 0); + + /* rate control */ + if (avctx->flags & CODEC_FLAG_QSCALE) { lame_set_VBR(s->gfp, vbr_default); - lame_set_VBR_quality(s->gfp, avctx->global_quality/(float)FF_QP2LAMBDA); + lame_set_VBR_quality(s->gfp, avctx->global_quality / (float)FF_QP2LAMBDA); + } else { + if (avctx->bit_rate) + lame_set_brate(s->gfp, avctx->bit_rate / 1000); } - lame_set_bWriteVbrTag(s->gfp,0); - lame_set_disable_reservoir(s->gfp, avctx->flags2 & CODEC_FLAG2_BIT_RESERVOIR ? 0 : 1); - if (lame_init_params(s->gfp) < 0) - goto err_close; - avctx->frame_size = lame_get_framesize(s->gfp); + /* do not get a Xing VBR header frame from LAME */ + lame_set_bWriteVbrTag(s->gfp,0); - avctx->coded_frame= avcodec_alloc_frame(); - avctx->coded_frame->key_frame= 1; + /* bit reservoir usage */ + lame_set_disable_reservoir(s->gfp, !s->reservoir); - return 0; - -err_close: - lame_close(s->gfp); -err: - return -1; -} - -static const int sSampleRates[] = { - 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000, 0 -}; - -static const int sBitRates[2][3][15] = { - { { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448}, - { 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384}, - { 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320} - }, - { { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256}, - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}, - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160} - }, -}; + /* set specified parameters */ + if (lame_init_params(s->gfp) < 0) { + ret = -1; + goto error; + } -static const int sSamplesPerFrame[2][3] = -{ - { 384, 1152, 1152 }, - { 384, 1152, 576 } -}; + /* get encoder delay */ + avctx->delay = lame_get_encoder_delay(s->gfp) + 528 + 1; + ff_af_queue_init(avctx, &s->afq); -static const int sBitsPerSlot[3] = { - 32, - 8, - 8 -}; + avctx->frame_size = lame_get_framesize(s->gfp); -static int mp3len(void *data, int *samplesPerFrame, int *sampleRate) -{ - uint32_t header = AV_RB32(data); - int layerID = 3 - ((header >> 17) & 0x03); - int bitRateID = ((header >> 12) & 0x0f); - int sampleRateID = ((header >> 10) & 0x03); - int bitsPerSlot = sBitsPerSlot[layerID]; - int isPadded = ((header >> 9) & 0x01); - static int const mode_tab[4]= {2,3,1,0}; - int mode= mode_tab[(header >> 19) & 0x03]; - int mpeg_id= mode>0; - int temp0, temp1, bitRate; - - if ( (( header >> 21 ) & 0x7ff) != 0x7ff || mode == 3 || layerID==3 || sampleRateID==3) { - return -1; +#if FF_API_OLD_ENCODE_AUDIO + avctx->coded_frame = avcodec_alloc_frame(); + if (!avctx->coded_frame) { + ret = AVERROR(ENOMEM); + goto error; + } +#endif + + /* allocate float sample buffers */ + if (avctx->sample_fmt == AV_SAMPLE_FMT_FLTP) { + int ch; + for (ch = 0; ch < avctx->channels; ch++) { + s->samples_flt[ch] = av_malloc(avctx->frame_size * + sizeof(*s->samples_flt[ch])); + if (!s->samples_flt[ch]) { + ret = AVERROR(ENOMEM); + goto error; + } + } } - if(!samplesPerFrame) samplesPerFrame= &temp0; - if(!sampleRate ) sampleRate = &temp1; - -// *isMono = ((header >> 6) & 0x03) == 0x03; + ret = realloc_buffer(s); + if (ret < 0) + goto error; - *sampleRate = sSampleRates[sampleRateID]>>mode; - bitRate = sBitRates[mpeg_id][layerID][bitRateID] * 1000; - *samplesPerFrame = sSamplesPerFrame[mpeg_id][layerID]; -//av_log(NULL, AV_LOG_DEBUG, "sr:%d br:%d spf:%d l:%d m:%d\n", *sampleRate, bitRate, *samplesPerFrame, layerID, mode); + avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT); - return *samplesPerFrame * bitRate / (bitsPerSlot * *sampleRate) + isPadded; + return 0; +error: + mp3lame_encode_close(avctx); + return ret; } -static int MP3lame_encode_frame(AVCodecContext *avctx, - unsigned char *frame, int buf_size, void *data) +#define ENCODE_BUFFER(func, buf_type, buf_name) do { \ + lame_result = func(s->gfp, \ + (const buf_type *)buf_name[0], \ + (const buf_type *)buf_name[1], frame->nb_samples, \ + s->buffer + s->buffer_index, \ + s->buffer_size - s->buffer_index); \ +} while (0) + +static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) { - Mp3AudioContext *s = avctx->priv_data; - int len; + LAMEContext *s = avctx->priv_data; + MPADecodeHeader hdr; + int len, ret, ch; int lame_result; - /* lame 3.91 dies on '1-channel interleaved' data */ - - if(data){ - if (s->stereo) { - lame_result = lame_encode_buffer_interleaved( - s->gfp, - data, - avctx->frame_size, - s->buffer + s->buffer_index, - BUFFER_SIZE - s->buffer_index - ); - } else { - lame_result = lame_encode_buffer( - s->gfp, - data, - data, - avctx->frame_size, - s->buffer + s->buffer_index, - BUFFER_SIZE - s->buffer_index - ); + if (frame) { + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_S16P: + ENCODE_BUFFER(lame_encode_buffer, int16_t, frame->data); + break; + case AV_SAMPLE_FMT_S32P: + ENCODE_BUFFER(lame_encode_buffer_int, int32_t, frame->data); + break; + case AV_SAMPLE_FMT_FLTP: + if (frame->linesize[0] < 4 * FFALIGN(frame->nb_samples, 8)) { + av_log(avctx, AV_LOG_ERROR, "inadequate AVFrame plane padding\n"); + return AVERROR(EINVAL); + } + for (ch = 0; ch < avctx->channels; ch++) { + s->fdsp.vector_fmul_scalar(s->samples_flt[ch], + (const float *)frame->data[ch], + 32768.0f, + FFALIGN(frame->nb_samples, 8)); + } + ENCODE_BUFFER(lame_encode_buffer_float, float, s->samples_flt); + break; + default: + return AVERROR_BUG; } - }else{ - lame_result= lame_encode_flush( - s->gfp, - s->buffer + s->buffer_index, - BUFFER_SIZE - s->buffer_index - ); + } else { + lame_result = lame_encode_flush(s->gfp, s->buffer + s->buffer_index, + BUFFER_SIZE - s->buffer_index); } - - if(lame_result < 0){ - if(lame_result==-1) { - /* output buffer too small */ - av_log(avctx, AV_LOG_ERROR, "lame: output buffer too small (buffer index: %d, free bytes: %d)\n", s->buffer_index, BUFFER_SIZE - s->buffer_index); + if (lame_result < 0) { + if (lame_result == -1) { + av_log(avctx, AV_LOG_ERROR, + "lame: output buffer too small (buffer index: %d, free bytes: %d)\n", + s->buffer_index, s->buffer_size - s->buffer_index); } return -1; } - s->buffer_index += lame_result; + ret = realloc_buffer(s); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "error reallocating output buffer\n"); + return ret; + } - if(s->buffer_index<4) - return 0; + /* add current frame to the queue */ + if (frame) { + if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) + return ret; + } - len= mp3len(s->buffer, NULL, NULL); -//av_log(avctx, AV_LOG_DEBUG, "in:%d packet-len:%d index:%d\n", avctx->frame_size, len, s->buffer_index); - if(len <= s->buffer_index){ - memcpy(frame, s->buffer, len); + /* Move 1 frame from the LAME buffer to the output packet, if available. + We have to parse the first frame header in the output buffer to + determine the frame size. */ + if (s->buffer_index < 4) + return 0; + if (avpriv_mpegaudio_decode_header(&hdr, AV_RB32(s->buffer))) { + av_log(avctx, AV_LOG_ERROR, "free format output not supported\n"); + return -1; + } + len = hdr.frame_size; + av_dlog(avctx, "in:%d packet-len:%d index:%d\n", avctx->frame_size, len, + s->buffer_index); + if (len <= s->buffer_index) { + if ((ret = ff_alloc_packet(avpkt, len))) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n"); + return ret; + } + memcpy(avpkt->data, s->buffer, len); s->buffer_index -= len; + memmove(s->buffer, s->buffer + len, s->buffer_index); - memmove(s->buffer, s->buffer+len, s->buffer_index); - //FIXME fix the audio codec API, so we do not need the memcpy() -/*for(i=0; iafq, avctx->frame_size, &avpkt->pts, + &avpkt->duration); + + avpkt->size = len; + *got_packet_ptr = 1; + } + return 0; } -static av_cold int MP3lame_encode_close(AVCodecContext *avctx) -{ - Mp3AudioContext *s = avctx->priv_data; +#define OFFSET(x) offsetof(LAMEContext, x) +#define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "reservoir", "Use bit reservoir.", OFFSET(reservoir), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE }, + { NULL }, +}; - av_freep(&avctx->coded_frame); +static const AVClass libmp3lame_class = { + .class_name = "libmp3lame encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; - lame_close(s->gfp); - return 0; -} +static const AVCodecDefault libmp3lame_defaults[] = { + { "b", "0" }, + { NULL }, +}; +static const int libmp3lame_sample_rates[] = { + 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000, 0 +}; AVCodec ff_libmp3lame_encoder = { - "libmp3lame", - AVMEDIA_TYPE_AUDIO, - CODEC_ID_MP3, - sizeof(Mp3AudioContext), - MP3lame_encode_init, - MP3lame_encode_frame, - MP3lame_encode_close, - .capabilities= CODEC_CAP_DELAY, - .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_NONE}, - .supported_samplerates= sSampleRates, - .long_name= NULL_IF_CONFIG_SMALL("libmp3lame MP3 (MPEG audio layer 3)"), + .name = "libmp3lame", + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_MP3, + .priv_data_size = sizeof(LAMEContext), + .init = mp3lame_encode_init, + .encode2 = mp3lame_encode_frame, + .close = mp3lame_encode_close, + .capabilities = CODEC_CAP_DELAY | CODEC_CAP_SMALL_LAST_FRAME, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_NONE }, + .supported_samplerates = libmp3lame_sample_rates, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + 0 }, + .long_name = NULL_IF_CONFIG_SMALL("libmp3lame MP3 (MPEG audio layer 3)"), + .priv_class = &libmp3lame_class, + .defaults = libmp3lame_defaults, };