Merge remote-tracking branch 'qatar/master'
authorMichael Niedermayer <michaelni@gmx.at>
Wed, 15 Aug 2012 13:41:01 +0000 (15:41 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Wed, 15 Aug 2012 13:55:24 +0000 (15:55 +0200)
* qatar/master:
  rtmp: Add support for SWFVerification
  api-example: use new video encoding API.
  x86: avcodec: Appropriately name files containing only init functions
  mpegvideo_mmx_template: drop some commented-out cruft
  libavresample: add mix level normalization option
  w32pthreads: Add missing #includes to make header compile standalone
  rtmp: Gracefully ignore _checkbw errors by tracking them
  rtmp: Do not send _checkbw calls as notifications
  prores: interlaced ProRes encoding

Conflicts:
doc/examples/decoding_encoding.c
libavcodec/proresenc_kostya.c
libavcodec/w32pthreads.h
libavcodec/x86/Makefile
libavformat/version.h

Merged-by: Michael Niedermayer <michaelni@gmx.at>
16 files changed:
doc/examples/decoding_encoding.c
doc/protocols.texi
libavcodec/proresenc_kostya.c
libavcodec/w32pthreads.h
libavcodec/x86/Makefile
libavcodec/x86/ac3dsp_init.c [moved from libavcodec/x86/ac3dsp_mmx.c with 100% similarity]
libavcodec/x86/fft_init.c [moved from libavcodec/x86/fft.c with 100% similarity]
libavcodec/x86/fmtconvert_init.c [moved from libavcodec/x86/fmtconvert_mmx.c with 100% similarity]
libavcodec/x86/h264dsp_init.c [moved from libavcodec/x86/h264dsp_mmx.c with 100% similarity]
libavcodec/x86/mpegvideo_mmx_template.c
libavformat/rtmp.h
libavformat/rtmpproto.c
libavformat/version.h
libavresample/audio_mix.c
libavresample/internal.h
libavresample/options.c

index 6295001..919ee48 100644 (file)
 
 #include <math.h>
 
-#include <libavutil/imgutils.h>
 #include <libavutil/opt.h>
 #include <libavcodec/avcodec.h>
 #include <libavutil/audioconvert.h>
+#include <libavutil/imgutils.h>
 #include <libavutil/mathematics.h>
 #include <libavutil/samplefmt.h>
 
@@ -315,11 +315,11 @@ static void video_encode_example(const char *filename, int codec_id)
 {
     AVCodec *codec;
     AVCodecContext *c= NULL;
-    int i, out_size, x, y, outbuf_size;
+    int i, ret, x, y, got_output;
     FILE *f;
     AVFrame *picture;
-    uint8_t *outbuf;
-    int had_output=0;
+    AVPacket pkt;
+    uint8_t endcode[] = { 0, 0, 1, 0xb7 };
 
     printf("Encode video file %s\n", filename);
 
@@ -359,17 +359,25 @@ static void video_encode_example(const char *filename, int codec_id)
         exit(1);
     }
 
-    /* alloc image and output buffer */
-    outbuf_size = 100000 + 12*c->width*c->height;
-    outbuf = malloc(outbuf_size);
-
     /* the image can be allocated by any means and av_image_alloc() is
      * just the most convenient way if av_malloc() is to be used */
-    av_image_alloc(picture->data, picture->linesize,
-                   c->width, c->height, c->pix_fmt, 1);
+    ret = av_image_alloc(picture->data, picture->linesize, c->width, c->height,
+                         c->pix_fmt, 32);
+    if (ret < 0) {
+        fprintf(stderr, "could not alloc raw picture buffer\n");
+        exit(1);
+    }
+
+    picture->format = c->pix_fmt;
+    picture->width  = c->width;
+    picture->height = c->height;
 
     /* encode 1 second of video */
     for(i=0;i<25;i++) {
+        av_init_packet(&pkt);
+        pkt.data = NULL;    // packet data will be allocated by the encoder
+        pkt.size = 0;
+
         fflush(stdout);
         /* prepare a dummy image */
         /* Y */
@@ -387,35 +395,46 @@ static void video_encode_example(const char *filename, int codec_id)
             }
         }
 
+        picture->pts = i;
+
         /* encode the image */
-        out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture);
-        had_output |= out_size;
-        printf("encoding frame %3d (size=%5d)\n", i, out_size);
-        fwrite(outbuf, 1, out_size, f);
+        ret = avcodec_encode_video2(c, &pkt, picture, &got_output);
+        if (ret < 0) {
+            fprintf(stderr, "error encoding frame\n");
+            exit(1);
+        }
+
+        if (got_output) {
+            printf("encoding frame %3d (size=%5d)\n", i, pkt.size);
+            fwrite(pkt.data, 1, pkt.size, f);
+            av_free_packet(&pkt);
+        }
     }
 
     /* get the delayed frames */
-    for(; out_size || !had_output; i++) {
+    for (got_output = 1; got_output; i++) {
         fflush(stdout);
 
-        out_size = avcodec_encode_video(c, outbuf, outbuf_size, NULL);
-        had_output |= out_size;
-        printf("write frame %3d (size=%5d)\n", i, out_size);
-        fwrite(outbuf, 1, out_size, f);
+        ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
+        if (ret < 0) {
+            fprintf(stderr, "error encoding frame\n");
+            exit(1);
+        }
+
+        if (got_output) {
+            printf("write frame %3d (size=%5d)\n", i, pkt.size);
+            fwrite(pkt.data, 1, pkt.size, f);
+            av_free_packet(&pkt);
+        }
     }
 
     /* add sequence end code to have a real mpeg file */
-    outbuf[0] = 0x00;
-    outbuf[1] = 0x00;
-    outbuf[2] = 0x01;
-    outbuf[3] = 0xb7;
-    fwrite(outbuf, 1, 4, f);
+    fwrite(endcode, 1, sizeof(endcode), f);
     fclose(f);
-    free(outbuf);
 
     avcodec_close(c);
     av_free(c);
-    av_free(picture->data[0]);
+    av_freep(&picture->data[0]);
     av_free(picture);
     printf("\n");
 }
index 3a82c7f..be19239 100644 (file)
@@ -272,6 +272,12 @@ Name of live stream to subscribe to. By default no value will be sent.
 It is only sent if the option is specified or if rtmp_live
 is set to live.
 
+@item rtmp_swfhash
+SHA256 hash of the decompressed SWF file (32 bytes).
+
+@item rtmp_swfsize
+Size of the decompressed SWF file, required for SWFVerification.
+
 @item rtmp_swfurl
 URL of the SWF player for the media. By default no value will be sent.
 
index 440f254..d69892d 100644 (file)
@@ -406,10 +406,15 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
     int total_size = 0;
     const uint16_t *src;
     int slice_width_factor = av_log2(mbs_per_slice);
-    int num_cblocks, pwidth, linesize, line_offset;
+    int num_cblocks, pwidth, linesize, line_add;
     int plane_factor, is_chroma;
     uint16_t *qmat;
 
+    if (ctx->pictures_per_frame == 1)
+        line_add = 0;
+    else
+        line_add = ctx->cur_picture_idx ^ !pic->top_field_first;
+
     if (ctx->force_quant) {
         qmat = ctx->quants[0];
     } else if (quant < MAX_STORED_Q) {
@@ -437,15 +442,14 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
             pwidth      = avctx->width >> 1;
         }
 
-        line_offset = ((ctx->cur_picture_idx ^ !pic->top_field_first) &
-                       (ctx->pictures_per_frame - 1)) * pic->linesize[i];
         linesize = pic->linesize[i] * ctx->pictures_per_frame;
-        src = (const uint16_t*)(pic->data[i] + yp * linesize + line_offset) + xp;
+        src = (const uint16_t*)(pic->data[i] + yp * linesize +
+                                line_add * pic->linesize[i]) + xp;
 
         get_slice_data(ctx, src, linesize, xp, yp,
                        pwidth, avctx->height / ctx->pictures_per_frame,
-                       ctx->blocks[0], ctx->emu_buf, mbs_per_slice,
-                       num_cblocks, is_chroma);
+                       ctx->blocks[0], ctx->emu_buf,
+                       mbs_per_slice, num_cblocks, is_chroma);
         sizes[i] = encode_slice_plane(ctx, pb, src, linesize,
                                       mbs_per_slice, ctx->blocks[0],
                                       num_cblocks, plane_factor,
@@ -579,8 +583,12 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
     int slice_bits[TRELLIS_WIDTH], slice_score[TRELLIS_WIDTH];
     int overquant;
     uint16_t *qmat;
-    int linesize[4], line_offset;
+    int linesize[4], line_add;
 
+    if (ctx->pictures_per_frame == 1)
+        line_add = 0;
+    else
+        line_add = ctx->cur_picture_idx ^ !pic->top_field_first;
     mbs = x + mbs_per_slice;
 
     for (i = 0; i < ctx->num_planes; i++) {
@@ -600,15 +608,14 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
             pwidth         = avctx->width >> 1;
         }
 
-        line_offset = ((ctx->cur_picture_idx ^ !pic->top_field_first) &
-                       (ctx->pictures_per_frame - 1)) * pic->linesize[i];
         linesize[i] = pic->linesize[i] * ctx->pictures_per_frame;
-        src = (const uint16_t*)(pic->data[i] + yp * linesize[i] + line_offset) + xp;
+        src = (const uint16_t*)(pic->data[i] + yp * linesize[i] +
+                                line_add * pic->linesize[i]) + xp;
 
         get_slice_data(ctx, src, linesize[i], xp, yp,
                        pwidth, avctx->height / ctx->pictures_per_frame,
-                       td->blocks[i], td->emu_buf, mbs_per_slice,
-                       num_cblocks[i], is_chroma[i]);
+                       td->blocks[i], td->emu_buf,
+                       mbs_per_slice, num_cblocks[i], is_chroma[i]);
     }
 
     for (q = min_quant; q < max_quant + 2; q++) {
@@ -767,9 +774,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
     bytestream_put_be16  (&buf, avctx->height);
 
     frame_flags = ctx->chroma_factor << 6;
-    if (avctx->flags & CODEC_FLAG_INTERLACED_DCT) {
+    if (avctx->flags & CODEC_FLAG_INTERLACED_DCT)
         frame_flags |= pic->top_field_first ? 0x04 : 0x08;
-    }
     bytestream_put_byte  (&buf, frame_flags);
 
     bytestream_put_byte  (&buf, 0);             // reserved
@@ -791,7 +797,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
     }
     bytestream_put_be16  (&tmp, buf - orig_buf); // write back frame header size
 
-    for (ctx->cur_picture_idx = 0; ctx->cur_picture_idx < ctx->pictures_per_frame; ++ctx->cur_picture_idx) {
+    for (ctx->cur_picture_idx = 0;
+         ctx->cur_picture_idx < ctx->pictures_per_frame;
+         ctx->cur_picture_idx++) {
         // picture header
         picture_size_pos = buf + 1;
         bytestream_put_byte  (&buf, 0x40);          // picture header size (in bits)
@@ -845,7 +853,6 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
     frame_size = buf - orig_buf;
     bytestream_put_be32(&orig_buf, frame_size);
 
-
     pkt->size   = frame_size;
     pkt->flags |= AV_PKT_FLAG_KEY;
     *got_packet = 1;
@@ -927,7 +934,8 @@ static av_cold int encode_init(AVCodecContext *avctx)
     if (!ctx->force_quant) {
         if (!ctx->bits_per_mb) {
             for (i = 0; i < NUM_MB_LIMITS - 1; i++)
-                if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height * ctx->pictures_per_frame)
+                if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height *
+                                           ctx->pictures_per_frame)
                     break;
             ctx->bits_per_mb   = ctx->profile_info->br_tab[i];
         } else if (ctx->bits_per_mb < 128) {
@@ -991,12 +999,15 @@ static av_cold int encode_init(AVCodecContext *avctx)
     ctx->frame_size_upper_bound = ctx->pictures_per_frame *
                                   ctx->slices_per_picture *
                                   (2 + 2 * ctx->num_planes +
-                                   (mps * ctx->bits_per_mb) / 8) + 200;
+                                   (mps * ctx->bits_per_mb) / 8)
+                                  + 200;
 
     avctx->codec_tag   = ctx->profile_info->tag;
 
-    av_log(avctx, AV_LOG_DEBUG, "profile %d, %d slices/pic, %d pics/frame, %d bits per MB\n",
-           ctx->profile, ctx->slices_per_picture, ctx->pictures_per_frame, ctx->bits_per_mb);
+    av_log(avctx, AV_LOG_DEBUG,
+           "profile %d, %d slices, interlacing: %s, %d bits per MB\n",
+           ctx->profile, ctx->slices_per_picture * ctx->pictures_per_frame,
+           interlaced ? "yes" : "no", ctx->bits_per_mb);
     av_log(avctx, AV_LOG_DEBUG, "frame size upper bound: %d\n",
            ctx->frame_size_upper_bound);
 
index fbc183a..c4bbb9a 100644 (file)
@@ -40,6 +40,8 @@
 #include <process.h>
 
 #include "libavutil/common.h"
+#include "libavutil/internal.h"
+#include "libavutil/mem.h"
 
 typedef struct {
     void *handle;
index e01454a..0ad3457 100644 (file)
@@ -5,7 +5,7 @@ OBJS-$(CONFIG_XMM_CLOBBER_TEST)        += x86/w64xmmtest.o
 
 MMX-OBJS                               += x86/dsputil_mmx.o             \
                                           x86/fdct_mmx.o                \
-                                          x86/fmtconvert_mmx.o          \
+                                          x86/fmtconvert_init.o         \
                                           x86/idct_mmx_xvid.o           \
                                           x86/idct_sse2_xvid.o          \
                                           x86/motion_est_mmx.o          \
@@ -13,15 +13,15 @@ MMX-OBJS                               += x86/dsputil_mmx.o             \
                                           x86/simple_idct_mmx.o         \
 
 MMX-OBJS-$(CONFIG_AAC_DECODER)         += x86/sbrdsp_init.o
-MMX-OBJS-$(CONFIG_AC3DSP)              += x86/ac3dsp_mmx.o
+MMX-OBJS-$(CONFIG_AC3DSP)              += x86/ac3dsp_init.o
 MMX-OBJS-$(CONFIG_CAVS_DECODER)        += x86/cavsdsp_mmx.o
 MMX-OBJS-$(CONFIG_DNXHD_ENCODER)       += x86/dnxhd_mmx.o
 MMX-OBJS-$(CONFIG_DWT)                 += x86/snowdsp_mmx.o \
                                           x86/dwt.o
 MMX-OBJS-$(CONFIG_ENCODERS)            += x86/dsputilenc_mmx.o
-MMX-OBJS-$(CONFIG_FFT)                 += x86/fft.o
+MMX-OBJS-$(CONFIG_FFT)                 += x86/fft_init.o
 MMX-OBJS-$(CONFIG_GPL)                 += x86/idct_mmx.o
-MMX-OBJS-$(CONFIG_H264DSP)             += x86/h264dsp_mmx.o
+MMX-OBJS-$(CONFIG_H264DSP)             += x86/h264dsp_init.o
 MMX-OBJS-$(CONFIG_H264PRED)            += x86/h264_intrapred_init.o
 MMX-OBJS-$(CONFIG_LPC)                 += x86/lpc_mmx.o
 MMX-OBJS-$(CONFIG_MPEGAUDIODSP)        += x86/mpegaudiodec_mmx.o
index 82e4ffa..d538a39 100644 (file)
@@ -360,13 +360,5 @@ static int RENAME(dct_quantize)(MpegEncContext *s,
         block[0x3E] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F];
     }
     end:
-/*
-    for(i=0; i<last_non_zero_p1; i++)
-    {
-       int j= zigzag_direct_noperm[i];
-       block[block_permute_op(j)]= temp_block[j];
-    }
-*/
-
     return last_non_zero_p1 - 1;
 }
index bdac6fd..7c9bb6d 100644 (file)
 #define HMAC_OPAD_VAL 0x5C
 
 /**
- * A non-zero transaction id requires the server to send back
- * a _result or _error response.
- * Setting it to 0 marks the message as a notification not
- * requiring feedback.
- */
-
-#define RTMP_NOTIFICATION 0
-
-/**
  * emulated Flash client version - 9.0.124.2 on Linux
  * @{
  */
index 4f57cb8..e3bcf3d 100644 (file)
@@ -91,7 +91,11 @@ typedef struct RTMPContext {
     int           nb_invokes;                 ///< keeps track of invoke messages
     char*         tcurl;                      ///< url of the target stream
     char*         flashver;                   ///< version of the flash plugin
+    char*         swfhash;                    ///< SHA256 hash of the decompressed SWF file (32 bytes)
+    int           swfhash_len;                ///< length of the SHA256 hash
+    int           swfsize;                    ///< size of the decompressed SWF file
     char*         swfurl;                     ///< url of the swf player
+    char          swfverification[42];        ///< hash of the SWF verification
     char*         pageurl;                    ///< url of the web page
     char*         subscribe;                  ///< name of live stream to subscribe
     int           server_bw;                  ///< server bandwidth
@@ -593,6 +597,27 @@ static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
 }
 
 /**
+ * Generate SWF verification message and send it to the server.
+ */
+static int gen_swf_verification(URLContext *s, RTMPContext *rt)
+{
+    RTMPPacket pkt;
+    uint8_t *p;
+    int ret;
+
+    av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
+    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
+                                     0, 44)) < 0)
+        return ret;
+
+    p = pkt.data;
+    bytestream_put_be16(&p, 27);
+    memcpy(p, rt->swfverification, 42);
+
+    return rtmp_send_packet(rt, &pkt, 0);
+}
+
+/**
  * Generate server bandwidth message and send it to the server.
  */
 static int gen_server_bw(URLContext *s, RTMPContext *rt)
@@ -626,10 +651,10 @@ static int gen_check_bw(URLContext *s, RTMPContext *rt)
 
     p = pkt.data;
     ff_amf_write_string(&p, "_checkbw");
-    ff_amf_write_number(&p, RTMP_NOTIFICATION);
+    ff_amf_write_number(&p, ++rt->nb_invokes);
     ff_amf_write_null(&p);
 
-    return rtmp_send_packet(rt, &pkt, 0);
+    return rtmp_send_packet(rt, &pkt, 1);
 }
 
 /**
@@ -776,6 +801,30 @@ static int rtmp_validate_digest(uint8_t *buf, int off)
     return 0;
 }
 
+static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
+                                      uint8_t *buf)
+{
+    uint8_t *p;
+    int ret;
+
+    if (rt->swfhash_len != 32) {
+        av_log(s, AV_LOG_ERROR,
+               "Hash of the decompressed SWF file is not 32 bytes long.\n");
+        return AVERROR(EINVAL);
+    }
+
+    p = &rt->swfverification[0];
+    bytestream_put_byte(&p, 1);
+    bytestream_put_byte(&p, 1);
+    bytestream_put_be32(&p, rt->swfsize);
+    bytestream_put_be32(&p, rt->swfsize);
+
+    if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
+        return ret;
+
+    return 0;
+}
+
 /**
  * Perform handshake with the server by means of exchanging pseudorandom data
  * signed with HMAC-SHA2 digest.
@@ -866,6 +915,14 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
             }
         }
 
+        /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
+         * key are the last 32 bytes of the server handshake. */
+        if (rt->swfsize) {
+            if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
+                                                  RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
+                return ret;
+        }
+
         ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
                                   rtmp_server_key, sizeof(rtmp_server_key),
                                   digest);
@@ -1001,6 +1058,13 @@ static int handle_ping(URLContext *s, RTMPPacket *pkt)
     if (t == 6) {
         if ((ret = gen_pong(s, rt, pkt)) < 0)
             return ret;
+    } else if (t == 26) {
+        if (rt->swfsize) {
+            if ((ret = gen_swf_verification(s, rt)) < 0)
+                return ret;
+        } else {
+            av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
+        }
     }
 
     return 0;
@@ -1055,15 +1119,27 @@ static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
 {
     const uint8_t *data_end = pkt->data + pkt->data_size;
+    char *tracked_method = NULL;
+    int level = AV_LOG_ERROR;
     uint8_t tmpstr[256];
+    int ret;
+
+    if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
+        return ret;
 
     if (!ff_amf_get_field_value(pkt->data + 9, data_end,
                                 "description", tmpstr, sizeof(tmpstr))) {
-        av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
-        return -1;
+        if (tracked_method && !strcmp(tracked_method, "_checkbw")) {
+            /* Ignore _checkbw errors. */
+            level = AV_LOG_WARNING;
+            ret = 0;
+        } else
+            ret = -1;
+        av_log(s, level, "Server error: %s\n", tmpstr);
     }
 
-    return 0;
+    av_free(tracked_method);
+    return ret;
 }
 
 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
@@ -1705,6 +1781,8 @@ static const AVOption rtmp_options[] = {
     {"rtmp_pageurl", "URL of the web page in which the media was embedded. By default no value will be sent.", OFFSET(pageurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
     {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
     {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
+    {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
+    {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {0}, 0, INT_MAX, DEC},
     {"rtmp_swfurl", "URL of the SWF player. By default no value will be sent", OFFSET(swfurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
     {"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
     { NULL },
index 99a8ddf..f68805c 100644 (file)
@@ -31,7 +31,7 @@
 
 #define LIBAVFORMAT_VERSION_MAJOR 54
 #define LIBAVFORMAT_VERSION_MINOR 23
-#define LIBAVFORMAT_VERSION_MICRO 100
+#define LIBAVFORMAT_VERSION_MICRO 101
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \
index e8ab2e3..f948c82 100644 (file)
@@ -335,7 +335,9 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
                                       avr->out_channel_layout,
                                       avr->center_mix_level,
                                       avr->surround_mix_level,
-                                      avr->lfe_mix_level, 1, matrix_dbl,
+                                      avr->lfe_mix_level,
+                                      avr->normalize_mix_level,
+                                      matrix_dbl,
                                       avr->in_channels,
                                       avr->matrix_encoding);
         if (ret < 0) {
index 7b7648f..006b6fd 100644 (file)
@@ -45,6 +45,7 @@ struct AVAudioResampleContext {
     double center_mix_level;                    /**< center mix level       */
     double surround_mix_level;                  /**< surround mix level     */
     double lfe_mix_level;                       /**< lfe mix level          */
+    int normalize_mix_level;                    /**< enable mix level normalization */
     int force_resampling;                       /**< force resampling       */
     int filter_size;                            /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */
     int phase_shift;                            /**< log2 of the number of entries in the resampling polyphase filterbank */
index 02e1f86..e7e0c27 100644 (file)
@@ -47,6 +47,7 @@ static const AVOption options[] = {
     { "center_mix_level",       "Center Mix Level",         OFFSET(center_mix_level),       AV_OPT_TYPE_DOUBLE, { M_SQRT1_2             }, -32.0,                32.0,                   PARAM },
     { "surround_mix_level",     "Surround Mix Level",       OFFSET(surround_mix_level),     AV_OPT_TYPE_DOUBLE, { M_SQRT1_2             }, -32.0,                32.0,                   PARAM },
     { "lfe_mix_level",          "LFE Mix Level",            OFFSET(lfe_mix_level),          AV_OPT_TYPE_DOUBLE, { 0.0                   }, -32.0,                32.0,                   PARAM },
+    { "normalize_mix_level",    "Normalize Mix Level",      OFFSET(normalize_mix_level),    AV_OPT_TYPE_INT,    { 1                     }, 0,                    1,                      PARAM },
     { "force_resampling",       "Force Resampling",         OFFSET(force_resampling),       AV_OPT_TYPE_INT,    { 0                     }, 0,                    1,                      PARAM },
     { "filter_size",            "Resampling Filter Size",   OFFSET(filter_size),            AV_OPT_TYPE_INT,    { 16                    }, 0,                    32, /* ??? */           PARAM },
     { "phase_shift",            "Resampling Phase Shift",   OFFSET(phase_shift),            AV_OPT_TYPE_INT,    { 10                    }, 0,                    30, /* ??? */           PARAM },