libmp3lame: use planar sample formats
[ffmpeg.git] / libavcodec / libmp3lame.c
index 7a76d1f..871156f 100644 (file)
@@ -33,6 +33,7 @@
 #include "libavutil/opt.h"
 #include "avcodec.h"
 #include "audio_frame_queue.h"
+#include "dsputil.h"
 #include "internal.h"
 #include "mpegaudio.h"
 #include "mpegaudiodecheader.h"
@@ -46,8 +47,9 @@ typedef struct LAMEContext {
     uint8_t buffer[BUFFER_SIZE];
     int buffer_index;
     int reservoir;
-    void *planar_samples[2];
+    float *samples_flt[2];
     AudioFrameQueue afq;
+    DSPContext dsp;
 } LAMEContext;
 
 
@@ -58,8 +60,8 @@ static av_cold int mp3lame_encode_close(AVCodecContext *avctx)
 #if FF_API_OLD_ENCODE_AUDIO
     av_freep(&avctx->coded_frame);
 #endif
-    av_freep(&s->planar_samples[0]);
-    av_freep(&s->planar_samples[1]);
+    av_freep(&s->samples_flt[0]);
+    av_freep(&s->samples_flt[1]);
 
     ff_af_queue_close(&s->afq);
 
@@ -126,93 +128,63 @@ static av_cold int mp3lame_encode_init(AVCodecContext *avctx)
     }
 #endif
 
-    /* sample format */
-    if (avctx->sample_fmt == AV_SAMPLE_FMT_S32 ||
-        avctx->sample_fmt == AV_SAMPLE_FMT_FLT) {
+    /* allocate float sample buffers */
+    if (avctx->sample_fmt == AV_SAMPLE_FMT_FLTP) {
         int ch;
         for (ch = 0; ch < avctx->channels; ch++) {
-            s->planar_samples[ch] = av_malloc(avctx->frame_size *
-                                              av_get_bytes_per_sample(avctx->sample_fmt));
-            if (!s->planar_samples[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;
             }
         }
     }
 
+    ff_dsputil_init(&s->dsp, avctx);
+
     return 0;
 error:
     mp3lame_encode_close(avctx);
     return ret;
 }
 
-#define DEINTERLEAVE(type, scale) do {                  \
-    int ch, i;                                          \
-    for (ch = 0; ch < s->avctx->channels; ch++) {       \
-        const type *input = samples;                    \
-        type      *output = s->planar_samples[ch];      \
-        input += ch;                                    \
-        for (i = 0; i < nb_samples; i++) {              \
-            output[i] = *input * scale;                 \
-            input += s->avctx->channels;                \
-        }                                               \
-    }                                                   \
+#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,                         \
+                       BUFFER_SIZE - s->buffer_index);                      \
 } while (0)
 
-static int encode_frame_int16(LAMEContext *s, void *samples, int nb_samples)
-{
-    if (s->avctx->channels > 1) {
-        return lame_encode_buffer_interleaved(s->gfp, samples,
-                                              nb_samples,
-                                              s->buffer + s->buffer_index,
-                                              BUFFER_SIZE - s->buffer_index);
-    } else {
-        return lame_encode_buffer(s->gfp, samples, NULL, nb_samples,
-                                  s->buffer + s->buffer_index,
-                                  BUFFER_SIZE - s->buffer_index);
-    }
-}
-
-static int encode_frame_int32(LAMEContext *s, void *samples, int nb_samples)
-{
-    DEINTERLEAVE(int32_t, 1);
-
-    return lame_encode_buffer_int(s->gfp,
-                                  s->planar_samples[0], s->planar_samples[1],
-                                  nb_samples,
-                                  s->buffer + s->buffer_index,
-                                  BUFFER_SIZE - s->buffer_index);
-}
-
-static int encode_frame_float(LAMEContext *s, void *samples, int nb_samples)
-{
-    DEINTERLEAVE(float, 32768.0f);
-
-    return lame_encode_buffer_float(s->gfp,
-                                    s->planar_samples[0], s->planar_samples[1],
-                                    nb_samples,
-                                    s->buffer + s->buffer_index,
-                                    BUFFER_SIZE - s->buffer_index);
-}
-
 static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
                                 const AVFrame *frame, int *got_packet_ptr)
 {
     LAMEContext *s = avctx->priv_data;
     MPADecodeHeader hdr;
-    int len, ret;
+    int len, ret, ch;
     int lame_result;
 
     if (frame) {
         switch (avctx->sample_fmt) {
-        case AV_SAMPLE_FMT_S16:
-            lame_result = encode_frame_int16(s, frame->data[0], frame->nb_samples);
+        case AV_SAMPLE_FMT_S16P:
+            ENCODE_BUFFER(lame_encode_buffer, int16_t, frame->data);
             break;
-        case AV_SAMPLE_FMT_S32:
-            lame_result = encode_frame_int32(s, frame->data[0], frame->nb_samples);
+        case AV_SAMPLE_FMT_S32P:
+            ENCODE_BUFFER(lame_encode_buffer_int, int32_t, frame->data);
             break;
-        case AV_SAMPLE_FMT_FLT:
-            lame_result = encode_frame_float(s, frame->data[0], frame->nb_samples);
+        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->dsp.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;
@@ -300,9 +272,9 @@ AVCodec ff_libmp3lame_encoder = {
     .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_S32,
-                                                             AV_SAMPLE_FMT_FLT,
-                                                             AV_SAMPLE_FMT_S16,
+    .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,