]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/libmp3lame.c
hevc: reduce variable scope
[ffmpeg] / libavcodec / libmp3lame.c
index b8ccb2611553778ae23e38ec8a8e32bf5c611acf..23f1581e1375df88f5f8088fad4e21b9f3044d18 100644 (file)
  * Interface to libmp3lame for mp3 encoding.
  */
 
+#include <lame/lame.h>
+
+#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 <lame/lame.h>
+#include "mpegaudiodecheader.h"
 
 #define BUFFER_SIZE (7200 + 2 * MPA_FRAME_SIZE + MPA_FRAME_SIZE / 4)
-typedef struct Mp3AudioContext {
+
+typedef struct LAMEContext {
     AVClass *class;
+    AVCodecContext *avctx;
     lame_global_flags *gfp;
-    uint8_t buffer[BUFFER_SIZE];
+    uint8_t *buffer;
     int buffer_index;
+    int buffer_size;
     int reservoir;
-} Mp3AudioContext;
-
-static av_cold int MP3lame_encode_init(AVCodecContext *avctx)
-{
-    Mp3AudioContext *s = avctx->priv_data;
+    int joint_stereo;
+    int abr;
+    float *samples_flt[2];
+    AudioFrameQueue afq;
+    AVFloatDSPContext fdsp;
+} LAMEContext;
 
-    if (avctx->channels > 2)
-        return -1;
 
-    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);
-    lame_set_num_channels(s->gfp, avctx->channels);
-    if (avctx->compression_level == FF_COMPRESSION_DEFAULT) {
-        lame_set_quality(s->gfp, 5);
-    } else {
-        lame_set_quality(s->gfp, avctx->compression_level);
-    }
-    lame_set_mode(s->gfp, avctx->channels > 1 ? JOINT_STEREO : MONO);
-    lame_set_brate(s->gfp, avctx->bit_rate / 1000);
-    if (avctx->flags & CODEC_FLAG_QSCALE) {
-        lame_set_brate(s->gfp, 0);
-        lame_set_VBR(s->gfp, vbr_default);
-        lame_set_VBR_quality(s->gfp, avctx->global_quality / (float)FF_QP2LAMBDA);
+static int realloc_buffer(LAMEContext *s)
+{
+    if (!s->buffer || s->buffer_size - s->buffer_index < BUFFER_SIZE) {
+        int new_size = s->buffer_index + 2 * BUFFER_SIZE, err;
+
+        av_dlog(s->avctx, "resizing output buffer: %d -> %d\n", s->buffer_size,
+                new_size);
+        if ((err = av_reallocp(&s->buffer, new_size)) < 0) {
+            s->buffer_size = s->buffer_index = 0;
+            return err;
+        }
+        s->buffer_size = new_size;
     }
-    lame_set_bWriteVbrTag(s->gfp,0);
-    lame_set_disable_reservoir(s->gfp, !s->reservoir);
-    if (lame_init_params(s->gfp) < 0)
-        goto err_close;
+    return 0;
+}
 
-    avctx->frame_size             = lame_get_framesize(s->gfp);
-    avctx->coded_frame            = avcodec_alloc_frame();
-    avctx->coded_frame->key_frame = 1;
+static av_cold int mp3lame_encode_close(AVCodecContext *avctx)
+{
+    LAMEContext *s = avctx->priv_data;
 
-    return 0;
+    av_freep(&s->samples_flt[0]);
+    av_freep(&s->samples_flt[1]);
+    av_freep(&s->buffer);
+
+    ff_af_queue_close(&s->afq);
 
-err_close:
     lame_close(s->gfp);
-err:
-    return -1;
+    return 0;
 }
 
-static const int sSampleRates[] = {
-    44100, 48000,  32000, 22050, 24000, 16000, 11025, 12000, 8000, 0
-};
+static av_cold int mp3lame_encode_init(AVCodecContext *avctx)
+{
+    LAMEContext *s = avctx->priv_data;
+    int ret;
 
-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 }
-    },
-};
+    s->avctx = avctx;
 
-static const int sSamplesPerFrame[2][3] = {
-    { 384, 1152, 1152 },
-    { 384, 1152,  576 }
-};
+    /* initialize LAME and get defaults */
+    if (!(s->gfp = lame_init()))
+        return AVERROR(ENOMEM);
 
-static const int sBitsPerSlot[3] = { 32, 8, 8 };
+    lame_set_num_channels(s->gfp, avctx->channels);
+    lame_set_mode(s->gfp, avctx->channels > 1 ? s->joint_stereo ? JOINT_STEREO : STEREO : MONO);
 
-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;
+    /* 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
+        lame_set_quality(s->gfp, avctx->compression_level);
+
+    /* rate control */
+    if (avctx->flags & CODEC_FLAG_QSCALE) { // VBR
+        lame_set_VBR(s->gfp, vbr_default);
+        lame_set_VBR_quality(s->gfp, avctx->global_quality / (float)FF_QP2LAMBDA);
+    } else {
+        if (avctx->bit_rate) {
+            if (s->abr) {                   // ABR
+                lame_set_VBR(s->gfp, vbr_abr);
+                lame_set_VBR_mean_bitrate_kbps(s->gfp, avctx->bit_rate / 1000);
+            } else                          // CBR
+                lame_set_brate(s->gfp, avctx->bit_rate / 1000);
+        }
+    }
+
+    /* do not get a Xing VBR header frame from LAME */
+    lame_set_bWriteVbrTag(s->gfp,0);
+
+    /* bit reservoir usage */
+    lame_set_disable_reservoir(s->gfp, !s->reservoir);
+
+    /* set specified parameters */
+    if (lame_init_params(s->gfp) < 0) {
+        ret = -1;
+        goto error;
     }
 
-    if (!samplesPerFrame)
-        samplesPerFrame = &temp0;
-    if (!sampleRate)
-        sampleRate      = &temp1;
+    /* get encoder delay */
+    avctx->initial_padding = lame_get_encoder_delay(s->gfp) + 528 + 1;
+    ff_af_queue_init(avctx, &s->afq);
+
+    avctx->frame_size  = lame_get_framesize(s->gfp);
+
+    /* 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;
+            }
+        }
+    }
 
-    //*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 (avctx->channels > 1) {
-            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);
+    uint32_t h;
+
+    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);
+                                        s->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);
+                   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;
+    }
 
+    /* add current frame to the queue */
+    if (frame) {
+        if ((ret = ff_af_queue_add(&s->afq, frame)) < 0)
+            return ret;
+    }
+
+    /* 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;
-
-    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);
+    h = AV_RB32(s->buffer);
+    if (ff_mpa_check_header(h) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid mp3 header at start of buffer\n");
+        return AVERROR_BUG;
+    }
+    if (avpriv_mpegaudio_decode_header(&hdr, h)) {
+        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) {
-        memcpy(frame, s->buffer, len);
+        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);
-        // FIXME fix the audio codec API, so we do not need the memcpy()
-        /*for(i=0; i<len; i++) {
-            av_log(avctx, AV_LOG_DEBUG, "%2X ", frame[i]);
-        }*/
-        return len;
-    } else
-        return 0;
-}
 
-static av_cold int MP3lame_encode_close(AVCodecContext *avctx)
-{
-    Mp3AudioContext *s = avctx->priv_data;
+        /* Get the next frame pts/duration */
+        ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts,
+                           &avpkt->duration);
 
-    av_freep(&avctx->coded_frame);
-
-    lame_close(s->gfp);
+        avpkt->size = len;
+        *got_packet_ptr = 1;
+    }
     return 0;
 }
 
-#define OFFSET(x) offsetof(Mp3AudioContext, x)
+#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, { 1 }, 0, 1, AE },
+    { "reservoir", "Use bit reservoir.", OFFSET(reservoir), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
+    { "joint_stereo", "Use joint stereo.", OFFSET(joint_stereo), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
+    { "abr", "Use ABR", OFFSET(abr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE },
     { NULL },
 };
 
@@ -222,18 +285,33 @@ static const AVClass libmp3lame_class = {
     .version    = LIBAVUTIL_VERSION_INT,
 };
 
+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 = {
     .name                  = "libmp3lame",
+    .long_name             = NULL_IF_CONFIG_SMALL("libmp3lame MP3 (MPEG audio layer 3)"),
     .type                  = AVMEDIA_TYPE_AUDIO,
-    .id                    = CODEC_ID_MP3,
-    .priv_data_size        = sizeof(Mp3AudioContext),
-    .init                  = MP3lame_encode_init,
-    .encode                = MP3lame_encode_frame,
-    .close                 = MP3lame_encode_close,
-    .capabilities          = CODEC_CAP_DELAY,
-    .sample_fmts           = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16,
+    .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 = sSampleRates,
-    .long_name             = NULL_IF_CONFIG_SMALL("libmp3lame MP3 (MPEG audio layer 3)"),
+    .supported_samplerates = libmp3lame_sample_rates,
+    .channel_layouts       = (const uint64_t[]) { AV_CH_LAYOUT_MONO,
+                                                  AV_CH_LAYOUT_STEREO,
+                                                  0 },
     .priv_class            = &libmp3lame_class,
+    .defaults              = libmp3lame_defaults,
 };