diff options
40 files changed, 882 insertions, 2445 deletions
diff --git a/contrib/ffmpeg/A01-mpegleak.patch b/contrib/ffmpeg/A01-mpegleak.patch deleted file mode 100644 index 214e9caf9..000000000 --- a/contrib/ffmpeg/A01-mpegleak.patch +++ /dev/null @@ -1,62 +0,0 @@ -diff --git a/libavcodec/h264.c b/libavcodec/h264.c -index 9889224..041fccf 100644 ---- a/libavcodec/h264.c -+++ b/libavcodec/h264.c -@@ -3848,7 +3848,7 @@ static int decode_frame(AVCodecContext *avctx, - if(!(s->flags2 & CODEC_FLAG2_CHUNKS) && !s->current_picture_ptr){ - if (avctx->skip_frame >= AVDISCARD_NONREF) - return 0; -- av_log(avctx, AV_LOG_ERROR, "no frame!\n"); -+ av_log(avctx, AV_LOG_DEBUG, "no frame!\n"); - return -1; - } - -diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c -index 1f30916..dce88f3 100644 ---- a/libavcodec/h264_refs.c -+++ b/libavcodec/h264_refs.c -@@ -634,7 +634,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){ - * stream. Need to discard one frame. Prevents overrun of the - * short_ref and long_ref buffers. - */ -- av_log(h->s.avctx, AV_LOG_ERROR, -+ av_log(h->s.avctx, AV_LOG_DEBUG, - "number of reference frames (%d+%d) exceeds max (%d; probably " - "corrupt input), discarding one\n", - h->long_ref_count, h->short_ref_count, h->sps.ref_frame_count); -diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c -index e418e95..87cb73c 100644 ---- a/libavcodec/mpegvideo.c -+++ b/libavcodec/mpegvideo.c -@@ -1004,19 +1004,18 @@ int ff_find_unused_picture(MpegEncContext *s, int shared){ - } - - av_log(s->avctx, AV_LOG_FATAL, "Internal error, picture buffer overflow\n"); -- /* We could return -1, but the codec would crash trying to draw into a -- * non-existing frame anyway. This is safer than waiting for a random crash. -- * Also the return of this is never useful, an encoder must only allocate -- * as much as allowed in the specification. This has no relationship to how -- * much libavcodec could allocate (and MAX_PICTURE_COUNT is always large -- * enough for such valid streams). -- * Plus, a decoder has to check stream validity and remove frames if too -- * many reference frames are around. Waiting for "OOM" is not correct at -- * all. Similarly, missing reference frames have to be replaced by -- * interpolated/MC frames, anything else is a bug in the codec ... -- */ -- abort(); -- return -1; -+ /* XXX there seems to be a leak caused by h264 in mpeg transport -+ * streams: Over-the-air streams have a lot of errors. A picture -+ * may be marked as referenced but the actual references get lost -+ * so it never gets released. We take care of that here by releasing -+ * the oldest we have & reusing its slot. */ -+ int oldest=0; -+ for(i=0; i<MAX_PICTURE_COUNT; i++){ -+ if (s->picture[i].f.coded_picture_number < s->picture[oldest].f.coded_picture_number) -+ oldest = i; -+ } -+ s->avctx->release_buffer(s->avctx, (AVFrame*)&s->picture[oldest]); -+ return oldest; - } - - static void update_noise_reduction(MpegEncContext *s){ diff --git a/contrib/ffmpeg/A01-swscale-assert.patch b/contrib/ffmpeg/A01-swscale-assert.patch new file mode 100644 index 000000000..8136a35b2 --- /dev/null +++ b/contrib/ffmpeg/A01-swscale-assert.patch @@ -0,0 +1,15 @@ +diff --git a/libswscale/utils.c b/libswscale/utils.c +index d8fee58..b96a771 100644 +--- a/libswscale/utils.c ++++ b/libswscale/utils.c +@@ -508,7 +508,9 @@ static int initFilter(int16_t **outFilter, int32_t **filterPos, + // FIXME try to align filterPos if possible + + // fix borders +- if (is_horizontal) { ++ // This "horizontal" only check causes a subsequent assert when ++ // upscaling. ++ /*if (is_horizontal)*/ { + for (i = 0; i < dstW; i++) { + int j; + if ((*filterPos)[i] < 0) { diff --git a/contrib/ffmpeg/A02-audioconvert.patch b/contrib/ffmpeg/A02-audioconvert.patch deleted file mode 100644 index 5248a9fd3..000000000 --- a/contrib/ffmpeg/A02-audioconvert.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index 3c4e2f8..fe84b8c 100644 ---- a/libavcodec/Makefile -+++ b/libavcodec/Makefile -@@ -1,7 +1,7 @@ - NAME = avcodec - FFLIBS = avutil - --HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vdpau.h version.h xvmc.h -+HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vdpau.h version.h xvmc.h audioconvert.h - - OBJS = allcodecs.o \ - audioconvert.o \ diff --git a/contrib/ffmpeg/A03-png-sequences.patch b/contrib/ffmpeg/A03-png-sequences.patch index 66fe1f7c3..6098c3150 100644 --- a/contrib/ffmpeg/A03-png-sequences.patch +++ b/contrib/ffmpeg/A03-png-sequences.patch @@ -1,8 +1,8 @@ diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c -index a40cebb..26239e2 100644 +index 871f2b2..cba2e90 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c -@@ -599,6 +599,18 @@ static int decode_frame(AVCodecContext *avctx, +@@ -592,6 +592,24 @@ static int decode_frame(AVCodecContext *avctx, } } exit_loop: @@ -16,12 +16,18 @@ index a40cebb..26239e2 100644 + * It offers a similar solution; forces code block to be skipped. + * + * --kb ++ * ++ * The "fix" in r19079 was a hack placed in avcodec_decode_video. ++ * avcodec_decode_video was obsoleted and no longer exists. The ++ * "fix" disappeared with it. ++ * ++ * --jas + */ +#if 0 /* handle p-frames only if a predecessor frame is available */ if(s->last_picture->data[0] != NULL) { if(!(avpkt->flags & AV_PKT_FLAG_KEY)) { -@@ -615,6 +627,7 @@ static int decode_frame(AVCodecContext *avctx, +@@ -608,6 +626,7 @@ static int decode_frame(AVCodecContext *avctx, } } } diff --git a/contrib/ffmpeg/A04-channel-layout-order.patch b/contrib/ffmpeg/A04-channel-layout-order.patch index 99faa5ddc..2326e7d3e 100644 --- a/contrib/ffmpeg/A04-channel-layout-order.patch +++ b/contrib/ffmpeg/A04-channel-layout-order.patch @@ -1,84 +1,39 @@ -diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index 3c4e2f8..5cfd1bf 100644 ---- a/libavcodec/Makefile -+++ b/libavcodec/Makefile -@@ -142,7 +142,7 @@ OBJS-$(CONFIG_FFV1_DECODER) += ffv1.o rangecoder.o - OBJS-$(CONFIG_FFV1_ENCODER) += ffv1.o rangecoder.o - OBJS-$(CONFIG_FFVHUFF_DECODER) += huffyuv.o - OBJS-$(CONFIG_FFVHUFF_ENCODER) += huffyuv.o --OBJS-$(CONFIG_FLAC_DECODER) += flacdec.o flacdata.o flac.o -+OBJS-$(CONFIG_FLAC_DECODER) += flacdec.o flacdata.o flac.o vorbis_data.o - OBJS-$(CONFIG_FLAC_ENCODER) += flacenc.o flacdata.o flac.o - OBJS-$(CONFIG_FLASHSV_DECODER) += flashsv.o - OBJS-$(CONFIG_FLASHSV_ENCODER) += flashsvenc.o -diff --git a/libavcodec/flac.c b/libavcodec/flac.c -index e6a427a..397155e 100644 ---- a/libavcodec/flac.c -+++ b/libavcodec/flac.c -@@ -22,6 +22,7 @@ - #include "libavutil/crc.h" - #include "flac.h" - #include "flacdata.h" -+#include "vorbis.h" - - static const int8_t sample_size_table[] = { 0, 8, 12, 0, 16, 20, 24, 0 }; - -@@ -54,9 +55,12 @@ int ff_flac_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb, - fi->ch_mode = get_bits(gb, 4); - if (fi->ch_mode < FLAC_MAX_CHANNELS) { - fi->channels = fi->ch_mode + 1; -+ if (fi->ch_mode <= 5) -+ avctx->channel_layout = ff_vorbis_channel_layouts[fi->ch_mode]; - fi->ch_mode = FLAC_CHMODE_INDEPENDENT; - } else if (fi->ch_mode <= FLAC_CHMODE_MID_SIDE) { - fi->channels = 2; -+ avctx->channel_layout = AV_CH_LAYOUT_STEREO; - } else { - av_log(avctx, AV_LOG_ERROR + log_level_offset, - "invalid channel mode: %d\n", fi->ch_mode); diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c -index c90285a..58235c8 100644 +index 91efaf3..e6c5c8e 100644 --- a/libavcodec/mlpdec.c +++ b/libavcodec/mlpdec.c -@@ -133,6 +133,9 @@ typedef struct MLPDecodeContext { - //! Index of the last substream to decode - further substreams are skipped. - uint8_t max_decoded_substream; - -+ //! Stream needs channel reordering to comply with FFmpeg's channel order -+ uint8_t needs_reordering; -+ - //! number of PCM samples contained in each frame - int access_unit_size; - //! next power of two above the number of samples in each frame -@@ -326,6 +329,8 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb) - for (substr = 0; substr < MAX_SUBSTREAMS; substr++) - m->substream[substr].restart_seen = 0; - -+ m->needs_reordering = mh.channels_mlp >= 18 && mh.channels_mlp <= 20; -+ - return 0; - } - -@@ -436,6 +441,24 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, +@@ -30,6 +30,7 @@ + #include "dsputil.h" + #include "libavutil/intreadwrite.h" + #include "get_bits.h" ++#include "libavutil/audioconvert.h" + #include "libavutil/crc.h" + #include "parser.h" + #include "mlp_parser.h" +@@ -434,6 +435,28 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, s->ch_assign[ch_assign] = ch; } -+ if (m->avctx->codec_id == CODEC_ID_MLP && m->needs_reordering) { -+ if (m->avctx->channel_layout == (AV_CH_LAYOUT_2_2|AV_CH_LOW_FREQUENCY) || -+ m->avctx->channel_layout == AV_CH_LAYOUT_5POINT0) { -+ int i = s->ch_assign[4]; -+ s->ch_assign[4] = s->ch_assign[3]; -+ s->ch_assign[3] = s->ch_assign[2]; -+ s->ch_assign[2] = i; -+ } else if (m->avctx->channel_layout == AV_CH_LAYOUT_5POINT1) { -+ FFSWAP(int, s->ch_assign[2], s->ch_assign[4]); -+ FFSWAP(int, s->ch_assign[3], s->ch_assign[5]); ++ if (m->avctx->codec_id == CODEC_ID_TRUEHD) { ++ switch (m->avctx->channel_layout) { ++ case AV_CH_LAYOUT_6POINT1: ++ case (AV_CH_LAYOUT_6POINT1|AV_CH_TOP_CENTER): ++ case (AV_CH_LAYOUT_6POINT1|AV_CH_TOP_FRONT_CENTER): ++ { ++ int i = s->ch_assign[6]; ++ s->ch_assign[6] = s->ch_assign[5]; ++ s->ch_assign[5] = s->ch_assign[4]; ++ s->ch_assign[4] = i; ++ break; ++ } ++ case AV_CH_LAYOUT_7POINT1: ++ case (AV_CH_LAYOUT_5POINT1|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER): ++ FFSWAP(int, s->ch_assign[4], s->ch_assign[6]); ++ FFSWAP(int, s->ch_assign[5], s->ch_assign[7]); ++ break; ++ default: ++ break; + } -+ } -+ if (m->avctx->codec_id == CODEC_ID_TRUEHD && -+ m->avctx->channel_layout == AV_CH_LAYOUT_7POINT1) { -+ FFSWAP(int, s->ch_assign[4], s->ch_assign[6]); -+ FFSWAP(int, s->ch_assign[5], s->ch_assign[7]); + } + checksum = ff_mlp_restart_checksum(buf, get_bits_count(gbp) - start_count); diff --git a/contrib/ffmpeg/A05-asf-seek.patch b/contrib/ffmpeg/A05-asf-seek.patch deleted file mode 100644 index c19ad496b..000000000 --- a/contrib/ffmpeg/A05-asf-seek.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c -index 0245340..85b2649 100644 ---- a/libavformat/asfdec.c -+++ b/libavformat/asfdec.c -@@ -1172,7 +1172,10 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, - return AV_NOPTS_VALUE; - } - -- pts= pkt->pts; -+ if (pkt->pts == AV_NOPTS_VALUE) -+ pts = pkt->dts; -+ else -+ pts = pkt->pts; - - av_free_packet(pkt); - if(pkt->flags&AV_PKT_FLAG_KEY){ diff --git a/contrib/ffmpeg/A06-h264-recovery-point.patch b/contrib/ffmpeg/A06-h264-recovery-point.patch index 61442bd44..d018dd6b1 100644 --- a/contrib/ffmpeg/A06-h264-recovery-point.patch +++ b/contrib/ffmpeg/A06-h264-recovery-point.patch @@ -1,41 +1,41 @@ diff --git a/libavcodec/h264.c b/libavcodec/h264.c -index 9889224..ae77285 100644 +index 6ed251e..a3242ce 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c -@@ -2229,6 +2229,7 @@ static void flush_dpb(AVCodecContext *avctx){ - h->s.first_field= 0; +@@ -2627,6 +2627,7 @@ static void flush_dpb(AVCodecContext *avctx) + h->s.first_field = 0; ff_h264_reset_sei(h); ff_mpeg_flush(avctx); + h->recovery_frame= -1; } - static int init_poc(H264Context *h){ -@@ -3654,9 +3655,18 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size){ - if((err = decode_slice_header(hx, h))) - break; + static int init_poc(H264Context *h) +@@ -4289,9 +4290,18 @@ again: + if ((err = decode_slice_header(hx, h))) + break; -+ if (h->sei_recovery_frame_cnt >= 0 && h->recovery_frame < 0) { -+ h->recovery_frame = (h->frame_num + h->sei_recovery_frame_cnt) % -+ (1 << h->sps.log2_max_frame_num); -+ } ++ if (h->sei_recovery_frame_cnt >= 0 && h->recovery_frame < 0) { ++ h->recovery_frame = (h->frame_num + h->sei_recovery_frame_cnt) % ++ (1 << h->sps.log2_max_frame_num); ++ } + - s->current_picture_ptr->f.key_frame |= + s->current_picture_ptr->f.key_frame |= - (hx->nal_unit_type == NAL_IDR_SLICE) || - (h->sei_recovery_frame_cnt >= 0); -+ (hx->nal_unit_type == NAL_IDR_SLICE); ++ (hx->nal_unit_type == NAL_IDR_SLICE); + -+ if (h->recovery_frame == h->frame_num) { -+ s->current_picture_ptr->f.key_frame |= 1; -+ h->recovery_frame = -1; -+ } ++ if (h->recovery_frame == h->frame_num) { ++ s->current_picture_ptr->f.key_frame |= 1; ++ h->recovery_frame = -1; ++ } - if (h->current_slice == 1) { - if(!(s->flags2 & CODEC_FLAG2_CHUNKS)) { + if (h->current_slice == 1) { + if (!(s->flags2 & CODEC_FLAG2_CHUNKS)) diff --git a/libavcodec/h264.h b/libavcodec/h264.h -index 122a54a..cd044b0 100644 +index 570ce2f..454b755 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h -@@ -575,6 +575,13 @@ typedef struct H264Context{ +@@ -569,6 +569,13 @@ typedef struct H264Context { * frames. */ int sei_recovery_frame_cnt; @@ -47,10 +47,10 @@ index 122a54a..cd044b0 100644 + */ + int recovery_frame; - int luma_weight_flag[2]; ///< 7.4.3.2 luma_weight_lX_flag - int chroma_weight_flag[2]; ///< 7.4.3.2 chroma_weight_lX_flag + int luma_weight_flag[2]; ///< 7.4.3.2 luma_weight_lX_flag + int chroma_weight_flag[2]; ///< 7.4.3.2 chroma_weight_lX_flag diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c -index 4f52bbe..8d3c40b 100644 +index 2e5fb65..ea33a18 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -38,6 +38,7 @@ static const uint8_t sei_num_clock_ts_table[9]={ diff --git a/contrib/ffmpeg/A07-swscale-stack-alignment.patch b/contrib/ffmpeg/A07-swscale-stack-alignment.patch deleted file mode 100644 index 6d3bb35ce..000000000 --- a/contrib/ffmpeg/A07-swscale-stack-alignment.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/libswscale/swscale_unscaled.c b/libswscale/swscale_unscaled.c -index c0161c2..c7e6a28 100644 ---- a/libswscale/swscale_unscaled.c -+++ b/libswscale/swscale_unscaled.c -@@ -806,7 +806,7 @@ static int check_image_pointers(uint8_t *data[4], enum PixelFormat pix_fmt, - * swscale wrapper, so we don't need to export the SwsContext. - * Assumes planar YUV to be in YUV order instead of YVU. - */ --int sws_scale(struct SwsContext *c, const uint8_t* const srcSlice[], -+int attribute_align_arg sws_scale(struct SwsContext *c, const uint8_t* const srcSlice[], - const int srcStride[], int srcSliceY, int srcSliceH, - uint8_t* const dst[], const int dstStride[]) - { diff --git a/contrib/ffmpeg/A08-vc1-decode.patch b/contrib/ffmpeg/A08-vc1-decode.patch deleted file mode 100644 index 61c0724a0..000000000 --- a/contrib/ffmpeg/A08-vc1-decode.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c -index 60cca33..1b03215 100644 ---- a/libavcodec/vc1dec.c -+++ b/libavcodec/vc1dec.c -@@ -3317,7 +3317,7 @@ static int vc1_decode_p_block(VC1Context *v, DCTELEM block[64], int n, - i += skip; - if (i > 63) - break; -- if (!v->interlace) -+ if (!v->fcm) - idx = v->zz_8x8[0][i++]; - else - idx = v->zzi_8x8[i++]; -@@ -3345,7 +3345,7 @@ static int vc1_decode_p_block(VC1Context *v, DCTELEM block[64], int n, - i += skip; - if (i > 15) - break; -- if (!v->interlace) -+ if (!v->fcm) - idx = ff_vc1_simple_progressive_4x4_zz[i++]; - else - idx = ff_vc1_adv_interlaced_4x4_zz[i++]; -@@ -3372,7 +3372,7 @@ static int vc1_decode_p_block(VC1Context *v, DCTELEM block[64], int n, - i += skip; - if (i > 31) - break; -- if (!v->interlace) -+ if (!v->fcm) - idx = v->zz_8x4[i++] + off; - else - idx = ff_vc1_adv_interlaced_8x4_zz[i++] + off; -@@ -3399,7 +3399,7 @@ static int vc1_decode_p_block(VC1Context *v, DCTELEM block[64], int n, - i += skip; - if (i > 31) - break; -- if (!v->interlace) -+ if (!v->fcm) - idx = v->zz_4x8[i++] + off; - else - idx = ff_vc1_adv_interlaced_4x8_zz[i++] + off; diff --git a/contrib/ffmpeg/A09-pgs-pts.patch b/contrib/ffmpeg/A09-pgs-pts.patch index b03f5acce..fe6a6dc93 100644 --- a/contrib/ffmpeg/A09-pgs-pts.patch +++ b/contrib/ffmpeg/A09-pgs-pts.patch @@ -1,18 +1,20 @@ -diff -Naur ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/avcodec.h ffmpeg-v0.7-1696-gcae4f4b/libavcodec/avcodec.h ---- ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/avcodec.h 2011-11-03 12:29:48.000000000 +0100 -+++ ffmpeg-v0.7-1696-gcae4f4b/libavcodec/avcodec.h 2012-04-22 10:59:41.122351884 +0200 -@@ -3193,6 +3193,7 @@ +diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h +index 102df3a..aa40c78 100644 +--- a/libavcodec/avcodec.h ++++ b/libavcodec/avcodec.h +@@ -3093,6 +3093,7 @@ typedef struct AVSubtitle { unsigned num_rects; AVSubtitleRect **rects; int64_t pts; ///< Same as packet pts, in AV_TIME_BASE + uint8_t forced; } AVSubtitle; - /* packet functions */ -diff -Naur ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/pgssubdec.c ffmpeg-v0.7-1696-gcae4f4b/libavcodec/pgssubdec.c ---- ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/pgssubdec.c 2011-11-03 12:29:48.000000000 +0100 -+++ ffmpeg-v0.7-1696-gcae4f4b/libavcodec/pgssubdec.c 2012-04-22 13:09:29.499671541 +0200 -@@ -45,6 +45,8 @@ + /** +diff --git a/libavcodec/pgssubdec.c b/libavcodec/pgssubdec.c +index 3335412..3f14a2d 100644 +--- a/libavcodec/pgssubdec.c ++++ b/libavcodec/pgssubdec.c +@@ -45,6 +45,8 @@ typedef struct PGSSubPresentation { int y; int id_number; int object_number; @@ -21,7 +23,7 @@ diff -Naur ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/pgssubdec.c ffmpeg-v0.7-169 } PGSSubPresentation; typedef struct PGSSubPicture { -@@ -271,7 +273,8 @@ +@@ -271,7 +273,8 @@ static void parse_palette_segment(AVCodecContext *avctx, * @todo TODO: Implement forcing of subtitles */ static void parse_presentation_segment(AVCodecContext *avctx, @@ -31,7 +33,7 @@ diff -Naur ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/pgssubdec.c ffmpeg-v0.7-169 { PGSSubContext *ctx = avctx->priv_data; -@@ -280,6 +283,8 @@ +@@ -280,6 +283,8 @@ static void parse_presentation_segment(AVCodecContext *avctx, int w = bytestream_get_be16(&buf); int h = bytestream_get_be16(&buf); @@ -40,7 +42,7 @@ diff -Naur ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/pgssubdec.c ffmpeg-v0.7-169 av_dlog(avctx, "Video Dimensions %dx%d\n", w, h); if (av_image_check_size(w, h, 0, avctx) >= 0) -@@ -299,16 +304,17 @@ +@@ -299,16 +304,17 @@ static void parse_presentation_segment(AVCodecContext *avctx, buf += 3; ctx->presentation.object_number = bytestream_get_byte(&buf); @@ -61,7 +63,7 @@ diff -Naur ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/pgssubdec.c ffmpeg-v0.7-169 x = bytestream_get_be16(&buf); y = bytestream_get_be16(&buf); -@@ -356,6 +362,9 @@ +@@ -356,6 +362,9 @@ static int display_end_segment(AVCodecContext *avctx, void *data, */ memset(sub, 0, sizeof(*sub)); @@ -71,7 +73,7 @@ diff -Naur ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/pgssubdec.c ffmpeg-v0.7-169 // Blank if last object_number was 0. // Note that this may be wrong for more complex subtitles. if (!ctx->presentation.object_number) -@@ -441,7 +450,7 @@ +@@ -441,7 +450,7 @@ static int decode(AVCodecContext *avctx, void *data, int *data_size, parse_picture_segment(avctx, buf, segment_length); break; case PRESENTATION_SEGMENT: diff --git a/contrib/ffmpeg/P01-solaris.patch b/contrib/ffmpeg/P01-solaris.patch index d9bb05be2..8266d0914 100644 --- a/contrib/ffmpeg/P01-solaris.patch +++ b/contrib/ffmpeg/P01-solaris.patch @@ -1,5 +1,5 @@ diff --git a/configure b/configure -index e01d9fd..69ba7ea 100755 +index 07baa2f..4597a0d 100755 --- a/configure +++ b/configure @@ -54,6 +54,9 @@ if test "$E1" != 0 || test "$E2" = 0; then @@ -12,7 +12,7 @@ index e01d9fd..69ba7ea 100755 show_help(){ cat <<EOF Usage: configure [options] -@@ -2603,7 +2606,7 @@ EOF +@@ -2688,7 +2691,7 @@ EOF check_cc <<EOF || die "endian test failed" unsigned int endian = 'B' << 24 | 'I' << 16 | 'G' << 8 | 'E'; EOF diff --git a/contrib/ffmpeg/P02-darwin-pic.patch b/contrib/ffmpeg/P02-darwin-pic.patch index e93180fd3..e9d8dfc00 100644 --- a/contrib/ffmpeg/P02-darwin-pic.patch +++ b/contrib/ffmpeg/P02-darwin-pic.patch @@ -1,8 +1,8 @@ diff --git a/configure b/configure -index e01d9fd..d5d6aec 100755 +index 07baa2f..8a2a581 100755 --- a/configure +++ b/configure -@@ -2413,6 +2413,7 @@ case $target_os in +@@ -2494,6 +2494,7 @@ case $target_os in AVSERVERLDFLAGS=-Wl,-bind_at_load objformat="macho" enabled x86_64 && objformat="macho64" @@ -10,9 +10,9 @@ index e01d9fd..d5d6aec 100755 enabled_any pic shared || { check_cflags -mdynamic-no-pic && add_asflags -mdynamic-no-pic; } ;; -@@ -2530,7 +2531,7 @@ esac +@@ -2614,7 +2615,7 @@ esc(){ - echo "config:$arch:$subarch:$cpu:$target_os:$cc_ident:$LIBAV_CONFIGURATION" >config.fate + echo "config:$arch:$subarch:$cpu:$target_os:$(esc $cc_ident):$(esc $LIBAV_CONFIGURATION)" >config.fate -check_cpp_condition stdlib.h "defined(__PIC__) || defined(__pic__) || defined(PIC)" && enable pic +#check_cpp_condition stdlib.h "defined(__PIC__) || defined(__pic__) || defined(PIC)" && enable pic diff --git a/contrib/ffmpeg/P04-darwin-memalign.patch b/contrib/ffmpeg/P04-darwin-memalign.patch index 7c669b35b..0747dfa3c 100644 --- a/contrib/ffmpeg/P04-darwin-memalign.patch +++ b/contrib/ffmpeg/P04-darwin-memalign.patch @@ -1,8 +1,8 @@ diff --git a/libavutil/mem.c b/libavutil/mem.c -index 27bb30b..6f29363 100644 +index bf1a542..a32d400 100644 --- a/libavutil/mem.c +++ b/libavutil/mem.c -@@ -80,6 +80,11 @@ void *av_malloc(size_t size) +@@ -82,6 +82,11 @@ void *av_malloc(size_t size) ptr = (char*)ptr + diff; ((char*)ptr)[-1]= diff; #elif HAVE_POSIX_MEMALIGN diff --git a/contrib/ffmpeg/module.defs b/contrib/ffmpeg/module.defs index 0d4f4eaac..a6a824fda 100644 --- a/contrib/ffmpeg/module.defs +++ b/contrib/ffmpeg/module.defs @@ -1,7 +1,7 @@ $(eval $(call import.MODULE.defs,FFMPEG,ffmpeg,YASM BZIP2 ZLIB)) $(eval $(call import.CONTRIB.defs,FFMPEG)) -FFMPEG.FETCH.url = http://download.handbrake.fr/handbrake/contrib/ffmpeg-v0.7-1696-gcae4f4b.tar.bz2 +FFMPEG.FETCH.url = http://download.handbrake.fr/handbrake/contrib/libav-v0.8-2197-g1a068bf.tar.bz2 FFMPEG.CONFIGURE.deps = FFMPEG.CONFIGURE.env = @@ -11,7 +11,8 @@ FFMPEG.CONFIGURE.extra = \ --disable-doc \ --disable-bsfs \ --disable-encoders \ - --disable-ffmpeg \ + --disable-vda \ + --disable-vdpau \ --disable-avconv \ --disable-avplay \ --disable-avprobe \ @@ -30,7 +31,6 @@ FFMPEG.CONFIGURE.extra = \ --enable-gpl \ --enable-zlib \ --cc="$(FFMPEG.GCC.gcc)" \ - --extra-cflags="$(call fn.ARGS,FFMPEG.GCC,*archs *sysroot *minver ?extra) -I$(call fn.ABSOLUTE,$(CONTRIB.build/)include)" \ --extra-ldflags="$(call fn.ARGS,FFMPEG.GCC,*archs *sysroot *minver ?extra) -L$(call fn.ABSOLUTE,$(CONTRIB.build/)lib)" ## check against tuple: B-SYSTEM where B is { 0 | 1 } for cross-compiling flag @@ -54,8 +54,16 @@ endif ifneq (none,$(FFMPEG.GCC.g)) FFMPEG.CONFIGURE.extra += --enable-debug + +ifeq (max,$(FFMPEG.GCC.g)) + FFMPEG.CONFIGURE.extra += --extra-cflags="$(call fn.ARGS,FFMPEG.GCC,*archs *sysroot *minver ?extra) -I$(call fn.ABSOLUTE,$(CONTRIB.build/)include) -DDEBUG" +else + FFMPEG.CONFIGURE.extra += --extra-cflags="$(call fn.ARGS,FFMPEG.GCC,*archs *sysroot *minver ?extra) -I$(call fn.ABSOLUTE,$(CONTRIB.build/)include) -DNDEBUG" +endif + else FFMPEG.CONFIGURE.extra += --disable-debug + FFMPEG.CONFIGURE.extra += --extra-cflags="$(call fn.ARGS,FFMPEG.GCC,*archs *sysroot *minver ?extra) -I$(call fn.ABSOLUTE,$(CONTRIB.build/)include) -DNDEBUG" endif ifeq (none,$(FFMPEG.GCC.O)) diff --git a/gtk/src/Makefile.am b/gtk/src/Makefile.am index 9c1dbd2cd..da65bc926 100644 --- a/gtk/src/Makefile.am +++ b/gtk/src/Makefile.am @@ -2,15 +2,15 @@ if MINGW HB_LIBS= \ - -lhb -la52 -lmkv -lavformat -lavcodec -lavutil -ldca -ldvdnav -ldvdread \ - -lfaac -lmp3lame -lmpeg2 -lvorbis -lvorbisenc -logg -lsamplerate \ - -lx264 -lmp4v2 -lswscale -ltheora -lz \ + -lhb -la52 -lmkv -lavresample -lavformat -lavcodec -lavutil -ldca \ + -ldvdnav -ldvdread -lfaac -lmp3lame -lmpeg2 -lvorbis -lvorbisenc \ + -logg -lsamplerate -lx264 -lmp4v2 -lswscale -ltheora -lz \ -lbz2 -liberty -lpthreadGC2 -lbluray -lass -lfontconfig -lfreetype else HB_LIBS= \ - -lhb -la52 -lmkv -lavformat -lavcodec -lavutil -ldca -ldvdnav -ldvdread \ - -lfaac -lmp3lame -lmpeg2 -lvorbis -lvorbisenc -logg -lsamplerate \ - -lx264 -lmp4v2 -lswscale -ltheora -lz \ + -lhb -la52 -lmkv -lavresample -lavformat -lavcodec -lavutil -ldca \ + -ldvdnav -ldvdread -lfaac -lmp3lame -lmpeg2 -lvorbis -lvorbisenc \ + -logg -lsamplerate -lx264 -lmp4v2 -lswscale -ltheora -lz \ -lbz2 -lpthread -lbluray -lass -lfontconfig -lfreetype endif diff --git a/libhb/audio_remap.c b/libhb/audio_remap.c new file mode 100644 index 000000000..6d3877d3d --- /dev/null +++ b/libhb/audio_remap.c @@ -0,0 +1,148 @@ +/* audio_remap.c + * + * Copyright (c) 2003-2012 HandBrake Team + * This file is part of the HandBrake source code + * Homepage: <http://handbrake.fr/> + * It may be used under the terms of the GNU General Public License v2. + * For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html + */ + +#include "common.h" +#include "hbffmpeg.h" +#include "audio_remap.h" + +// source: libavutil/audioconvert.h +hb_chan_map_t hb_libav_chan_map = +{ + { + AV_CH_FRONT_LEFT, + AV_CH_FRONT_RIGHT, + AV_CH_FRONT_CENTER, + AV_CH_LOW_FREQUENCY, + AV_CH_BACK_LEFT, + AV_CH_BACK_RIGHT, + AV_CH_FRONT_LEFT_OF_CENTER, + AV_CH_FRONT_RIGHT_OF_CENTER, + AV_CH_BACK_CENTER, + AV_CH_SIDE_LEFT, + AV_CH_SIDE_RIGHT, + 0 + } +}; + +// source: liba52 documentation +hb_chan_map_t hb_liba52_chan_map = +{ + { + AV_CH_LOW_FREQUENCY, + AV_CH_FRONT_LEFT, + AV_CH_FRONT_CENTER, + AV_CH_FRONT_RIGHT, + AV_CH_BACK_CENTER, + AV_CH_SIDE_LEFT, + AV_CH_SIDE_RIGHT, + 0 + } +}; + +// source: libdca documentation and libavcodec/dca.c +hb_chan_map_t hb_libdca_chan_map = +{ + { + AV_CH_FRONT_LEFT_OF_CENTER, + AV_CH_FRONT_CENTER, + AV_CH_FRONT_RIGHT_OF_CENTER, + AV_CH_FRONT_LEFT, + AV_CH_FRONT_RIGHT, + AV_CH_SIDE_LEFT, + AV_CH_SIDE_RIGHT, + AV_CH_LOW_FREQUENCY, + 0 + } +}; + +// source: http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 +hb_chan_map_t hb_vorbis_chan_map = +{ + { + AV_CH_FRONT_LEFT, + AV_CH_FRONT_CENTER, + AV_CH_FRONT_RIGHT, + AV_CH_SIDE_LEFT, + AV_CH_SIDE_RIGHT, + AV_CH_BACK_LEFT, + AV_CH_BACK_CENTER, + AV_CH_BACK_RIGHT, + AV_CH_LOW_FREQUENCY, + 0 + } +}; + +// source: https://developer.apple.com/library/mac/#documentation/musicaudio/reference/CoreAudioDataTypesRef/Reference/reference.html +hb_chan_map_t hb_aac_chan_map = +{ + { + AV_CH_FRONT_CENTER, + AV_CH_FRONT_LEFT_OF_CENTER, + AV_CH_FRONT_RIGHT_OF_CENTER, + AV_CH_FRONT_LEFT, + AV_CH_FRONT_RIGHT, + AV_CH_SIDE_LEFT, + AV_CH_SIDE_RIGHT, + AV_CH_BACK_LEFT, + AV_CH_BACK_RIGHT, + AV_CH_BACK_CENTER, + AV_CH_LOW_FREQUENCY, + 0 + } +}; + +int* hb_audio_remap_build_table(uint64_t layout, hb_chan_map_t *map_in, hb_chan_map_t *map_out) +{ + int ii, jj, idx, remap_idx, *remap_table; + uint64_t *input_order, *output_order; + + remap_table = calloc(HB_AUDIO_REMAP_MAX_CHANNELS, sizeof(int)); + if (!remap_table) + return NULL; + + idx = 0; + input_order = map_in->channel_order; + output_order = map_out->channel_order; + for (ii = 0; output_order[ii]; ii++) + { + if (layout & output_order[ii]) + { + remap_idx = 0; + for (jj = 0; input_order[jj]; jj++) + { + if (output_order[ii] == input_order[jj]) + { + remap_table[idx++] = remap_idx++; + } + else if (layout & input_order[jj]) + { + remap_idx++; + } + } + } + } + + return remap_table; +} + +void hb_audio_remap(int nchannels, int nsamples, hb_sample_t *samples, int *remap_table) +{ + int ii, jj; + hb_sample_t tmp[HB_AUDIO_REMAP_MAX_CHANNELS]; + + for (ii = 0; ii < nsamples; ii++) + { + memcpy(tmp, samples, nchannels * sizeof(hb_sample_t)); + for (jj = 0; jj < nchannels; jj++) + { + samples[jj] = tmp[remap_table[jj]]; + } + samples += nchannels; + } +}
\ No newline at end of file diff --git a/libhb/audio_remap.h b/libhb/audio_remap.h new file mode 100644 index 000000000..32ee3e9cb --- /dev/null +++ b/libhb/audio_remap.h @@ -0,0 +1,53 @@ +/* audio_remap.h + * + * Copyright (c) 2003-2012 HandBrake Team + * This file is part of the HandBrake source code + * Homepage: <http://handbrake.fr/> + * It may be used under the terms of the GNU General Public License v2. + * For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html + */ + +/* This file handles the following two scenarios: + * + * 1) remapping from liba52/libdca order to libav order + * - this allows downmixing liba52/libdca sources with libavresample + * + * 2) remapping from libav order to aac/vorbis order + * - this allows encoding audio without libavcodec (faac, ca_aac, libvorbis) + * + * Thus we only need to support: + * + * a) channels found in liba52/libdca layouts + * b) channels found in HB_AMIXDOWN_* layouts + * + * Notes: + * + * Left/Right Surround -> Side Left/Right + * Left/Right Rear Surround -> Back Left/Right */ + +#ifndef AUDIO_REMAP_H +#define AUDIO_REMAP_H + +#include <stdint.h> + +// we only need to support the 11 "most common" channels +#define HB_AUDIO_REMAP_MAX_CHANNELS 11 + +typedef float hb_sample_t; + +typedef struct +{ + uint64_t channel_order[HB_AUDIO_REMAP_MAX_CHANNELS+1]; +} hb_chan_map_t; + +// used to convert between various channel orders +extern hb_chan_map_t hb_libav_chan_map; +extern hb_chan_map_t hb_liba52_chan_map; +extern hb_chan_map_t hb_libdca_chan_map; +extern hb_chan_map_t hb_vorbis_chan_map; +extern hb_chan_map_t hb_aac_chan_map; + +int* hb_audio_remap_build_table(uint64_t layout, hb_chan_map_t *map_in, hb_chan_map_t *map_out); +void hb_audio_remap(int nchannels, int nsamples, hb_sample_t *samples, int *remap_table); + +#endif /* AUDIO_REMAP_H */ diff --git a/libhb/common.h b/libhb/common.h index 16c7acff8..99aae30a1 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -20,7 +20,6 @@ #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> -#include "libavutil/audioconvert.h" /* * It seems WinXP doesn't align the stack of new threads to 16 bytes. @@ -99,7 +98,8 @@ typedef struct hb_lock_s hb_lock_t; #else #define PRIVATE const #endif -#include "downmix.h" +#include "audio_remap.h" +#include "libavutil/audioconvert.h" hb_list_t * hb_list_init(); int hb_list_count( hb_list_t * ); diff --git a/libhb/deca52.c b/libhb/deca52.c index 22bfb55da..0c1708de2 100644 --- a/libhb/deca52.c +++ b/libhb/deca52.c @@ -8,7 +8,7 @@ */ #include "hb.h" -#include "downmix.h" +#include "audio_remap.h" #include "a52dec/a52.h" #include "libavutil/crc.h" @@ -484,7 +484,7 @@ static int deca52BSInfo( hb_work_object_t *w, const hb_buffer_t *b, info->channel_layout |= AV_CH_LOW_FREQUENCY; } - info->channel_map = &hb_ac3_chan_map; + info->channel_map = &hb_liba52_chan_map; return 1; } diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index 875a94c67..a32228bf1 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -40,8 +40,7 @@ #include "hb.h" #include "hbffmpeg.h" -#include "downmix.h" -#include "libavcodec/audioconvert.h" +#include "audio_remap.h" static void compute_frame_duration( hb_work_private_t *pv ); static void flushDelayQueue( hb_work_private_t *pv ); @@ -98,9 +97,16 @@ struct hb_work_private_s int sws_width; int sws_height; int sws_pix_fmt; - hb_downmix_t *downmix; int cadence[12]; int wait_for_keyframe; + + AVAudioResampleContext *avresample; + int resample; + int out_channels; + int stereo_downmix_mode; + uint64_t out_channel_layout; + uint64_t resample_channel_layout; + enum AVSampleFormat resample_sample_fmt; }; static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *data, int size, int64_t pts ); @@ -178,19 +184,19 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job ) hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); w->private_data = pv; - pv->job = job; - if ( job ) + pv->job = job; + if (job) pv->title = job->title; else pv->title = w->title; - pv->list = hb_list_init(); + pv->list = hb_list_init(); - int codec_id = w->codec_param; - /*XXX*/ - if ( codec_id == 0 ) - codec_id = CODEC_ID_MP2; + // initialize output settings for avresample + pv->out_channels = hb_mixdown_get_discrete_channel_count(w->audio->config.out.mixdown); + pv->out_channel_layout = hb_ff_mixdown_xlat(w->audio->config.out.mixdown, + &pv->stereo_downmix_mode); - codec = avcodec_find_decoder( codec_id ); + codec = avcodec_find_decoder( w->codec_param ); if ( pv->title->opaque_priv ) { AVFormatContext *ic = (AVFormatContext*)pv->title->opaque_priv; @@ -200,7 +206,7 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job ) } else { - pv->parser = av_parser_init( codec_id ); + pv->parser = av_parser_init( w->codec_param ); pv->context = avcodec_alloc_context3(codec); hb_ff_set_sample_fmt( pv->context, codec ); @@ -211,36 +217,6 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job ) return 1; } - // DTS: work around lack of 6.0/6.1 support in libhb - if (hb_ff_dts_disable_xch(pv->context)) - { - hb_deep_log(2, "decavcodecaInit: found DTS-ES, requesting DTS core"); - } - else if ((!pv->context->channels || !pv->context->channel_layout) && - (w->audio->config.in.codec == HB_ACODEC_DCA_HD) && - ((w->audio->config.in.channel_layout & ~AV_CH_LOW_FREQUENCY) == AV_CH_LAYOUT_5POINT0)) - { - /* XXX: when we are demuxing the stream ourselves, it seems we have no - * channel count/layout info in the context until we decode audio for - * the first time. If the scan info says the source is 5.0 or 5.1, - * make sure XCh processing is disabled in Libav before decoding. */ - pv->context->request_channels = pv->context->channels = - av_get_channel_layout_nb_channels(w->audio->config.in.channel_layout); - pv->context->channel_layout = w->audio->config.in.channel_layout; - hb_deep_log(2, "decavcodecaInit: scan detected DTS 5.0/5.1, disabling XCh processing"); - } - - if ( w->audio != NULL ) - { - if ( hb_need_downmix( w->audio->config.in.channel_layout, - w->audio->config.out.mixdown) ) - { - pv->downmix = hb_downmix_init(w->audio->config.in.channel_layout, - w->audio->config.out.mixdown); - hb_downmix_set_chan_map( pv->downmix, &hb_smpte_chan_map, &hb_smpte_chan_map ); - } - } - return 0; } @@ -283,14 +259,9 @@ static void closePrivData( hb_work_private_t ** ppv ) { hb_list_empty( &pv->list ); } - if ( pv->buffer ) - { - av_free( pv->buffer ); - pv->buffer = NULL; - } - if ( pv->downmix ) + if ( pv->avresample ) { - hb_downmix_close( &(pv->downmix) ); + avresample_free( &pv->avresample ); } free( pv ); } @@ -366,10 +337,9 @@ static int decavcodecaWork( hb_work_object_t * w, hb_buffer_t ** buf_in, // total samples to per-channel samples. 'sample_rate' converts // per-channel samples to seconds per sample and the 90000 // is mpeg ticks per second. - if ( pv->context->sample_rate && pv->context->channels ) + if ( pv->context->sample_rate ) { - pv->duration = 90000. / - (double)( pv->context->sample_rate * pv->context->channels ); + pv->duration = 90000. / (double)( pv->context->sample_rate ); } decodeAudio( w->audio, pv, pout, pout_len, cur ); } @@ -409,11 +379,8 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf, { return decavcodecaInfo( w, info ); } - // XXX - // We should parse the bitstream to find its parameters but for right - // now we just return dummy values if there's a codec that will handle it. - AVCodec *codec = avcodec_find_decoder( w->codec_param? w->codec_param : - CODEC_ID_MP2 ); + + AVCodec *codec = avcodec_find_decoder( w->codec_param ); if ( ! codec ) { // there's no ffmpeg codec for this audio type - give up @@ -430,8 +397,6 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf, { return -1; } - uint8_t *buffer = av_malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE ); - int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; unsigned char *pbuffer; int pos, pbuffer_size; @@ -457,21 +422,16 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf, pos += len; if ( pbuffer_size > 0 ) { + AVFrame frame; + int got_frame; AVPacket avp; av_init_packet( &avp ); avp.data = pbuffer; avp.size = pbuffer_size; - len = avcodec_decode_audio3( context, (int16_t*)buffer, - &out_size, &avp ); + len = avcodec_decode_audio4( context, &frame, &got_frame, &avp ); if ( len > 0 && context->sample_rate > 0 ) { - // DTS: work around lack of 6.0/6.1 support in libhb - if( hb_ff_dts_disable_xch( context ) ) - { - hb_deep_log( 2, "decavcodecaBSInfo: found DTS-ES, requesting DTS core" ); - } - int isamp = av_get_bytes_per_sample( context->sample_fmt ); info->bitrate = context->bit_rate; info->rate = context->sample_rate; info->rate_base = 1; @@ -479,11 +439,7 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf, hb_ff_layout_xlat(context->channel_layout, context->channels); ret = 1; - if ( context->channels && isamp ) - { - info->samples_per_frame = out_size / - (isamp * context->channels); - } + info->samples_per_frame = frame.nb_samples; break; } } @@ -493,9 +449,8 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf, info->profile = context->profile; info->level = context->level; - info->channel_map = &hb_smpte_chan_map; + info->channel_map = &hb_libav_chan_map; - av_free( buffer ); if ( parser != NULL ) av_parser_close( parser ); hb_avcodec_close( context ); @@ -1007,6 +962,8 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job ) pv->title = w->title; pv->list = hb_list_init(); + // XXX: A bug in libav prores decoder causes incorrect decoding when + // threaded decode is enabled. So disable it till this bug is fixed. if( pv->job && pv->job->title && !pv->job->title->has_resolution_change && w->codec_param != CODEC_ID_PRORES ) { @@ -1024,8 +981,6 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job ) pv->context = avcodec_alloc_context3(codec); avcodec_copy_context( pv->context, ic->streams[pv->title->video_id]->codec); pv->context->workaround_bugs = FF_BUG_AUTODETECT; - // Depricated but still used by Libav (twits!) - pv->context->error_recognition = FF_ER_CAREFUL; pv->context->err_recognition = AV_EF_CRCCHECK; pv->context->error_concealment = FF_EC_GUESS_MVS|FF_EC_DEBLOCK; @@ -1049,8 +1004,6 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job ) pv->parser = av_parser_init( w->codec_param ); pv->context = avcodec_alloc_context3( codec ); pv->context->workaround_bugs = FF_BUG_AUTODETECT; - // Depricated but still used by Libav (twits!) - pv->context->error_recognition = FF_ER_CAREFUL; pv->context->err_recognition = AV_EF_CRCCHECK; pv->context->error_concealment = FF_EC_GUESS_MVS|FF_EC_DEBLOCK; init_video_avcodec_context( pv ); @@ -1451,28 +1404,81 @@ hb_work_object_t hb_decavcodecv = .bsinfo = decavcodecvBSInfo }; -static hb_buffer_t * downmixAudio( - hb_audio_t *audio, - hb_work_private_t *pv, - hb_sample_t *buffer, - int channels, - int nsamples ) +static hb_buffer_t * downmixAudio(hb_work_private_t *pv, + hb_audio_t *audio, + AVFrame *frame) { - hb_buffer_t * buf = NULL; + uint64_t in_layout; + int resample_changed; + + in_layout = hb_ff_layout_xlat(pv->context->channel_layout, pv->context->channels); + pv->resample = (pv->resample || + pv->out_channel_layout != in_layout || + pv->context->sample_fmt != AV_SAMPLE_FMT_FLT); + resample_changed = (pv->resample && + (pv->resample_channel_layout != in_layout || + pv->resample_sample_fmt != pv->context->sample_fmt)); - if ( pv->downmix ) + if (resample_changed || (pv->resample && pv->avresample == NULL)) { - int n_ch_samples = nsamples / channels; - int out_channels = hb_mixdown_get_discrete_channel_count( audio->config.out.mixdown ); + if (pv->avresample == NULL) + { + pv->avresample = avresample_alloc_context(); + if (pv->avresample == NULL) + { + hb_error("Failed to initialize avresample"); + return NULL; + } + // output settings only need to be set once + av_opt_set_int(pv->avresample, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0); + av_opt_set_int(pv->avresample, "out_channel_layout", pv->out_channel_layout, 0); + av_opt_set_int(pv->avresample, "matrix_encoding", pv->stereo_downmix_mode, 0); + } + else if (resample_changed) + { + avresample_close(pv->avresample); + } - buf = hb_buffer_init( n_ch_samples * out_channels * sizeof(float) ); - hb_sample_t *samples = (hb_sample_t *)buf->data; - hb_downmix(pv->downmix, samples, buffer, n_ch_samples); + av_opt_set_int(pv->avresample, "in_channel_layout", in_layout, 0); + av_opt_set_int(pv->avresample, "in_sample_fmt", pv->context->sample_fmt, 0); + if (av_get_bytes_per_sample(pv->context->sample_fmt) <= 2) + av_opt_set_int(pv->avresample, "internal_sample_fmt", AV_SAMPLE_FMT_S16P, 0); + + if (avresample_open(pv->avresample) < 0) + { + hb_error("Failed to open libavresample"); + return NULL; + } + + pv->resample_channel_layout = in_layout; + pv->resample_sample_fmt = pv->context->sample_fmt; + } + + hb_buffer_t *buf; + int out_size, out_linesize, sample_size; + sample_size = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT); + out_size = av_samples_get_buffer_size(&out_linesize, pv->out_channels, + frame->nb_samples, AV_SAMPLE_FMT_FLT, !pv->resample); + buf = hb_buffer_init(out_size); + + if (pv->resample) + { + int out_samples; + out_samples = avresample_convert(pv->avresample, + (void**)&buf->data, out_linesize, frame->nb_samples, + (void**)frame->data, frame->linesize[0], frame->nb_samples); + + if (out_samples < 0) + { + hb_error("avresample_convert() failed"); + return NULL; + } + buf->size = out_samples * sample_size * pv->out_channels; } else { - buf = hb_buffer_init( nsamples * sizeof(float) ); - memcpy( buf->data, buffer, nsamples * sizeof(float) ); + memcpy(buf->data, frame->data[0], out_size); + buf->size = frame->nb_samples * sample_size * pv->out_channels; } return buf; @@ -1490,13 +1496,8 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat pv->pts_next = pts; while ( pos < size ) { - float *buffer = pv->buffer; - if ( buffer == NULL ) - { - pv->buffer = av_malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE ); - buffer = pv->buffer; - } - + AVFrame frame; + int got_frame; AVPacket avp; av_init_packet( &avp ); avp.data = data + pos; @@ -1504,14 +1505,12 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat avp.pts = pv->pts_next; avp.dts = AV_NOPTS_VALUE; - int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; - int nsamples; - int len = avcodec_decode_audio3( context, (int16_t*)buffer, &out_size, &avp ); + int len = avcodec_decode_audio4( context, &frame, &got_frame, &avp ); if ( len < 0 ) { return; } - if ( len == 0 ) + if ( !got_frame ) { if ( !(loop_limit--) ) return; @@ -1520,11 +1519,9 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat loop_limit = 256; pos += len; - if( out_size > 0 ) + if( got_frame ) { - int isamp = av_get_bytes_per_sample( context->sample_fmt ); - nsamples = out_size / isamp; - double duration = nsamples * pv->duration; + double duration = frame.nb_samples * pv->duration; double pts_next = pv->pts_next + duration; // DTS-HD can be passed through to mkv @@ -1545,50 +1542,15 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat continue; } - // We require floats for the output format. If - // we got something different convert it. - if ( context->sample_fmt != AV_SAMPLE_FMT_FLT ) + hb_buffer_t * buf = downmixAudio( pv, audio, &frame ); + if ( buf != NULL ) { - // Note: av_audio_convert seems to be a work-in-progress but - // looks like it will eventually handle general audio - // mixdowns which would allow us much more flexibility - // in handling multichannel audio in HB. If we were doing - // anything more complicated than a one-for-one format - // conversion we'd probably want to cache the converter - // context in the pv. - AVAudioConvert *ctx; - - ctx = av_audio_convert_alloc( AV_SAMPLE_FMT_FLT, 1, - context->sample_fmt, 1, - NULL, 0 ); - - // get output buffer size then malloc a buffer - buffer = av_malloc( nsamples * sizeof(hb_sample_t) ); - - // we're doing straight sample format conversion which - // behaves as if there were only one channel. - const void * const ibuf[6] = { pv->buffer }; - void * const obuf[6] = { buffer }; - const int istride[6] = { isamp }; - const int ostride[6] = { sizeof(hb_sample_t) }; - - av_audio_convert( ctx, obuf, ostride, ibuf, istride, nsamples ); - av_audio_convert_free( ctx ); - } - - hb_buffer_t * buf; - buf = downmixAudio( audio, pv, buffer, context->channels, nsamples ); - buf->s.start = pv->pts_next; - buf->s.duration = duration; - buf->s.stop = pts_next; - hb_list_add( pv->list, buf ); - - pv->pts_next = pts_next; + buf->s.start = pv->pts_next; + buf->s.duration = duration; + buf->s.stop = pts_next; + hb_list_add( pv->list, buf ); - // if we allocated a buffer for sample format conversion, free it - if ( buffer != pv->buffer ) - { - av_free( buffer ); + pv->pts_next = pts_next; } } } diff --git a/libhb/decdca.c b/libhb/decdca.c index 9f426d6a4..17d0e7755 100644 --- a/libhb/decdca.c +++ b/libhb/decdca.c @@ -8,7 +8,7 @@ */ #include "hb.h" -#include "downmix.h" +#include "audio_remap.h" #include "dca.h" @@ -425,7 +425,7 @@ static int decdcaBSInfo( hb_work_object_t *w, const hb_buffer_t *b, info->channel_layout |= AV_CH_LOW_FREQUENCY; } - info->channel_map = &hb_qt_chan_map; + info->channel_map = &hb_libdca_chan_map; dca_free( state ); return 1; diff --git a/libhb/declpcm.c b/libhb/declpcm.c index 5c6a0e4a1..86dd6e823 100644 --- a/libhb/declpcm.c +++ b/libhb/declpcm.c @@ -8,14 +8,14 @@ */ #include "hb.h" -#include "downmix.h" +#include "audio_remap.h" struct hb_work_private_s { hb_job_t *job; uint32_t size; /* frame size in bytes */ - uint32_t chunks; /* number of samples pairs if paired */ - uint32_t samples; /* frame size in samples */ + uint32_t nchunks; /* number of samples pairs if paired */ + uint32_t nsamples; /* frame size in samples */ uint32_t pos; /* buffer offset for next input data */ int64_t next_pts; /* pts for next output frame */ @@ -29,6 +29,15 @@ struct hb_work_private_s uint8_t sample_size; /* bits per sample */ uint8_t frame[HB_DVD_READ_BUFFER_SIZE*2]; + uint8_t * data; + uint32_t alloc_size; + + AVAudioResampleContext *avresample; + int resample; + int out_channels; + int stereo_downmix_mode; + uint64_t out_channel_layout; + uint64_t resample_channel_layout; }; static hb_buffer_t * Decode( hb_work_object_t * w ); @@ -53,12 +62,85 @@ static const int hdr2samplerate[] = { 48000, 96000, 44100, 32000 }; static const int hdr2samplesize[] = { 16, 20, 24, 16 }; static const uint64_t hdr2layout[] = { - AV_CH_LAYOUT_MONO, AV_CH_LAYOUT_STEREO, - AV_CH_LAYOUT_2_1, AV_CH_LAYOUT_2_2, - AV_CH_LAYOUT_5POINT0, AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER, - AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_MONO, AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_2_1, AV_CH_LAYOUT_QUAD, + AV_CH_LAYOUT_5POINT0_BACK, AV_CH_LAYOUT_6POINT0_FRONT, + AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_STEREO, }; +static hb_buffer_t * downmixAudio(hb_work_private_t *pv, + hb_audio_t *audio) +{ + int64_t in_layout; + int resample_changed; + + in_layout = hdr2layout[pv->nchannels - 1]; + pv->resample = pv->resample || (pv->out_channel_layout != in_layout); + resample_changed = pv->resample && (pv->resample_channel_layout != in_layout); + + if (resample_changed || (pv->resample && pv->avresample == NULL)) + { + if (pv->avresample == NULL) + { + pv->avresample = avresample_alloc_context(); + if (pv->avresample == NULL) + { + hb_error("Failed to initialize avresample"); + return NULL; + } + // some settings only need to be set once + av_opt_set_int(pv->avresample, "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0); + av_opt_set_int(pv->avresample, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0); + av_opt_set_int(pv->avresample, "out_channel_layout", pv->out_channel_layout, 0); + av_opt_set_int(pv->avresample, "matrix_encoding", pv->stereo_downmix_mode, 0); + } + else if (resample_changed) + { + avresample_close(pv->avresample); + } + + av_opt_set_int(pv->avresample, "in_channel_layout", in_layout, 0); + + if (avresample_open(pv->avresample) < 0) + { + hb_error("Failed to open libavresample"); + return NULL; + } + + pv->resample_channel_layout = in_layout; + } + + hb_buffer_t *buf; + int out_size, out_linesize, sample_size; + sample_size = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT); + out_size = av_samples_get_buffer_size(&out_linesize, pv->out_channels, + pv->nsamples, AV_SAMPLE_FMT_FLT, !pv->resample); + buf = hb_buffer_init(out_size); + + if (pv->resample) + { + int in_linesize, out_samples; + in_linesize = pv->nsamples * pv->nchannels * sample_size; + out_samples = avresample_convert(pv->avresample, + (void**)&buf->data, out_linesize, pv->nsamples, + (void**)&pv->data, in_linesize, pv->nsamples); + + if (out_samples < 0) + { + hb_error("avresample_convert() failed"); + return NULL; + } + buf->size = out_samples * sample_size * pv->out_channels; + } + else + { + memcpy(buf->data, pv->data, out_size); + buf->size = pv->nsamples * sample_size * pv->out_channels; + } + + return buf; +} + static void lpcmInfo( hb_work_object_t *w, hb_buffer_t *in ) { hb_work_private_t * pv = w->private_data; @@ -99,8 +181,8 @@ static void lpcmInfo( hb_work_object_t *w, hb_buffer_t *in ) hb_log( "declpcm: illegal frame offset %d", pv->offset ); pv->offset = 2; /*XXX*/ } - pv->samplerate = hdr2samplerate[ ( in->data[4] >> 4 ) & 0x3 ]; - pv->nchannels = ( in->data[4] & 7 ) + 1; + pv->nchannels = ( in->data[4] & 7 ) + 1; + pv->samplerate = hdr2samplerate[ ( in->data[4] >> 4 ) & 0x3 ]; pv->sample_size = hdr2samplesize[in->data[4] >> 6]; // 20 and 24 bit lpcm is always encoded in sample pairs. So take this @@ -142,10 +224,10 @@ static void lpcmInfo( hb_work_object_t *w, hb_buffer_t *in ) 149 ) / 150; pv->duration = frames * 150; - pv->chunks = ( pv->duration * pv->nchannels * pv->samplerate + + pv->nchunks = ( pv->duration * pv->nchannels * pv->samplerate + samples_per_chunk - 1 ) / ( 90000 * samples_per_chunk ); - pv->samples = ( pv->duration * pv->nchannels * pv->samplerate ) / 90000; - pv->size = pv->chunks * chunk_size; + pv->nsamples = ( pv->duration * pv->samplerate ) / 90000; + pv->size = pv->nchunks * chunk_size; pv->next_pts = in->s.start; } @@ -154,7 +236,13 @@ static int declpcmInit( hb_work_object_t * w, hb_job_t * job ) { hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); w->private_data = pv; - pv->job = job; + pv->job = job; + + // initialize output settings for avresample + pv->out_channels = hb_mixdown_get_discrete_channel_count(w->audio->config.out.mixdown); + pv->out_channel_layout = hb_ff_mixdown_xlat(w->audio->config.out.mixdown, + &pv->stereo_downmix_mode); + return 0; } @@ -215,20 +303,19 @@ static int declpcmWork( hb_work_object_t * w, hb_buffer_t ** buf_in, static hb_buffer_t *Decode( hb_work_object_t *w ) { hb_work_private_t *pv = w->private_data; - hb_buffer_t *out; - if (pv->samples == 0) + if (pv->nsamples == 0) return NULL; - out = hb_buffer_init( pv->samples * sizeof( float ) ); - - out->s.start = pv->next_pts; - out->s.duration = pv->duration; - pv->next_pts += pv->duration; - out->s.stop = pv->next_pts; + int size = pv->nsamples * pv->nchannels * sizeof( float ); + if (pv->alloc_size != size) + { + pv->data = realloc( pv->data, size ); + pv->alloc_size = size; + } - float *odat = (float *)out->data; - int count = pv->chunks / pv->nchannels; + float *odat = (float *)pv->data; + int count = pv->nchunks / pv->nchannels; switch( pv->sample_size ) { @@ -312,14 +399,30 @@ static hb_buffer_t *Decode( hb_work_object_t *w ) } } break; } + + hb_buffer_t *out; + out = downmixAudio( pv, w->audio ); + + out->s.start = pv->next_pts; + out->s.duration = pv->duration; + pv->next_pts += pv->duration; + out->s.stop = pv->next_pts; + return out; } static void declpcmClose( hb_work_object_t * w ) { - if ( w->private_data ) + hb_work_private_t * pv = w->private_data; + + if ( pv ) { - free( w->private_data ); + if ( pv->avresample ) + { + avresample_free( &pv->avresample ); + } + free( pv->data ); + free( pv ); w->private_data = 0; } } @@ -342,7 +445,7 @@ static int declpcmBSInfo( hb_work_object_t *w, const hb_buffer_t *b, info->bitrate = bitrate; info->flags = ( b->data[3] << 16 ) | ( b->data[4] << 8 ) | b->data[5]; info->channel_layout = hdr2layout[nchannels - 1]; - info->channel_map = &hb_qt_chan_map; + info->channel_map = &hb_libav_chan_map; info->samples_per_frame = ( duration * rate ) / 90000; return 1; diff --git a/libhb/downmix.c b/libhb/downmix.c index e5ed1c599..e69de29bb 100644 --- a/libhb/downmix.c +++ b/libhb/downmix.c @@ -1,1640 +0,0 @@ -/* downmix.c - - Copyright (c) 2003-2012 HandBrake Team - This file is part of the HandBrake source code - Homepage: <http://handbrake.fr/>. - It may be used under the terms of the GNU General Public License v2. - For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html - */ - -#include <string.h> -#include <stdlib.h> -#include <inttypes.h> -#include "common.h" -#include "downmix.h" - -#define LVL_PLUS6DB 2.0 -#define LVL_PLUS3DB 1.4142135623730951 -#define LVL_3DB 0.7071067811865476 -#define LVL_45DB 0.5946035575013605 -#define LVL_6DB 0.5 - -#define LVL_SQRT_1_4 0.5 -#define LVL_SQRT_3_4 0.866025404 - -#define HB_CH_FRONT_LEFT 0x00000001 -#define HB_CH_FRONT_RIGHT 0x00000002 -#define HB_CH_FRONT_CENTER 0x00000004 -#define HB_CH_LOW_FREQUENCY 0x00000008 -#define HB_CH_BACK_LEFT 0x00000010 -#define HB_CH_BACK_RIGHT 0x00000020 -#define HB_CH_BACK_CENTER 0x00000040 -#define HB_CH_SIDE_LEFT 0x00000080 -#define HB_CH_SIDE_RIGHT 0x00000100 - -#define HB_CH_SURROUND_MASK 0x000001f0 -#define HB_CH_MASK 0x000007ff - -#define HB_CH_DOLBY 0x00000800 -#define HB_CH_DPLII 0x00001000 - -#define DOWNMIX_MONO 0 -#define DOWNMIX_STEREO 1 -#define DOWNMIX_3F 2 -#define DOWNMIX_2F1R 3 -#define DOWNMIX_3F1R 4 -#define DOWNMIX_2F2R 5 -#define DOWNMIX_3F2R 6 -#define DOWNMIX_3F4R 7 -#define DOWNMIX_DOLBY 8 -#define DOWNMIX_DPLII 9 -#define DOWNMIX_NUM_MODES 10 - -#define DOWNMIX_CHANNEL_MASK 0x0f - -#define DOWNMIX_LFE_FLAG 0x10 -#define DOWNMIX_FLAGS_MASK 0x10 - -hb_sample_t downmix_matrix[DOWNMIX_NUM_MODES][DOWNMIX_NUM_MODES][8][8] = -{ -// MONO in -{ - // MONO out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // STEREO out - { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F out - { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F1R out - { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F1R out - { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F2R out - { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F2R out - { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F4R out - { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 1 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DOLBY out - { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DPLII out - { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, -}, -// STEREO in -{ - // MONO out - { { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // STEREO out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F out - { { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F1R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F1R out - { { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F2R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F2R out - { { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F4R out - { { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 1 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DOLBY out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DPLII out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, -}, -// 3F in -{ - // MONO out - { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // STEREO out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F1R out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F1R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F2R out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F2R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F4R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 1 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DOLBY out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DPLII out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, -}, -// 2F1R in -{ - // MONO out - { { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // STEREO out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F out - { { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F1R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F1R out - { { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F2R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F2R out - { { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F4R out - { { 0, 1, 0, 0, 0, 0, 0 , 0 }, - { 0, 0, 1, 0, 0, 0, 0 , 0 }, - { 0, 0, 0, 0, 0, LVL_3DB, LVL_3DB, 0 }, - { 0, 0, 0, 0, 0, 0, 0 , 1 }, - { 0, 0, 0, 0, 0, 0, 0 , 0 }, - { 0, 0, 0, 0, 0, 0, 0 , 0 }, - { 0, 0, 0, 0, 0, 0, 0 , 0 }, - { 0, 0, 0, 0, 0, 0, 0 , 0 } }, - // DOLBY out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DPLII out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, -}, -// 3F1R in -{ - // MONO out - { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // STEREO out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F1R out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F1R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F2R out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F2R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F4R out - { { 1, 0, 0, 0, 0, 0, 0 , 0 }, - { 0, 1, 0, 0, 0, 0, 0 , 0 }, - { 0, 0, 1, 0, 0, 0, 0 , 0 }, - { 0, 0, 0, 0, 0, LVL_3DB, LVL_3DB, 0 }, - { 0, 0, 0, 0, 0, 0, 0 , 1 }, - { 0, 0, 0, 0, 0, 0, 0 , 0 }, - { 0, 0, 0, 0, 0, 0, 0 , 0 }, - { 0, 0, 0, 0, 0, 0, 0 , 0 } }, - // DOLBY out - { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DPLII out - { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, -}, -// 2F2R in -{ - // MONO out - { { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // STEREO out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F out - { { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F1R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F1R out - { { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F2R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F2R out - { { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F4R out - { { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 1, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 1 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DOLBY out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { -LVL_6DB, LVL_6DB, 0, 0, 0, 0, 0, 0 }, - { -LVL_6DB, LVL_6DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DPLII out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { -LVL_SQRT_3_4, LVL_SQRT_1_4, 0, 0, 0, 0, 0, 0 }, - { -LVL_SQRT_1_4, LVL_SQRT_3_4, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, -}, -// 3F2R in -{ - // MONO out - { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // STEREO out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F1R out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F1R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 2F2R out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F2R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // 3F4R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 1, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 1 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DOLBY out - { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, - // DPLII out - { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { -LVL_SQRT_3_4, LVL_SQRT_1_4, 0, 0, 0, 0, 0, 0 }, - { -LVL_SQRT_1_4, LVL_SQRT_3_4, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } }, -}, -// 3F4R in -{ - // MONO out - { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 }, - { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 } }, - // STEREO out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 }, - { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 } }, - // 3F out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 } }, - // 2F1R out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 } }, - // 3F1R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 } }, - // 2F2R out - { { 1, 1, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, - { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 } }, - // 3F2R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, - { 0, 0, 0, 0, LVL_3DB, 0, 0, 0 }, - { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 }, - { 0, 0, 0, 0, LVL_3DB, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0 } }, - // 3F4R out - { { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 1, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 1 } }, - // DOLBY out - { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 } }, - // DPLII out - { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0, 0, 0 }, - { -LVL_SQRT_3_4*LVL_3DB, LVL_SQRT_1_4*LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { -LVL_SQRT_1_4*LVL_3DB, LVL_SQRT_3_4*LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { -LVL_SQRT_3_4*LVL_3DB, LVL_SQRT_1_4*LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { -LVL_SQRT_1_4*LVL_3DB, LVL_SQRT_3_4*LVL_3DB, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 } } -}, -}; - -static int channel_layout_map[DOWNMIX_NUM_MODES] = -{ - // DOWNMIX_MONO - (HB_CH_FRONT_CENTER), - // DOWNMIX_STEREO - (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT), - // DOWNMIX_3F - (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER), - // DOWNMIX_2F1R - (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_BACK_CENTER), - // DOWNMIX_3F1R - (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER|HB_CH_BACK_CENTER), - // DOWNMIX_2F2R - (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT), - // DOWNMIX_3F2R - (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER|HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT), - // DOWNMIX_3F4R - (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER|HB_CH_SIDE_LEFT| - HB_CH_SIDE_RIGHT|HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT), - // DOWNMIX_DOLBY - (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT), - // DOWNMIX_DPLII - (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT) -}; - -int hb_layout_to_mode(uint64_t layout) -{ - int mode = 0; - if (layout & AV_CH_LOW_FREQUENCY) - mode |= DOWNMIX_LFE_FLAG; - switch (layout & ~AV_CH_LOW_FREQUENCY) - { - case AV_CH_LAYOUT_MONO: - mode |= DOWNMIX_MONO; - break; - case AV_CH_LAYOUT_STEREO: - case AV_CH_LAYOUT_STEREO_DOWNMIX: - mode |= DOWNMIX_STEREO; - break; - case AV_CH_LAYOUT_SURROUND: - mode |= DOWNMIX_3F; - break; - case AV_CH_LAYOUT_2_1: - mode |= DOWNMIX_2F1R; - break; - case AV_CH_LAYOUT_4POINT0: - mode |= DOWNMIX_3F1R; - break; - case AV_CH_LAYOUT_2_2: - case AV_CH_LAYOUT_QUAD: - mode |= DOWNMIX_2F2R; - break; - case AV_CH_LAYOUT_5POINT0: - case AV_CH_LAYOUT_5POINT0_BACK: - mode |= DOWNMIX_3F2R; - break; - case AV_CH_LAYOUT_7POINT0: - mode |= DOWNMIX_3F4R; - break; - default: - { - switch (av_get_channel_layout_nb_channels(layout)) - { - case 1: - mode = DOWNMIX_MONO; - break; - case 2: - mode = DOWNMIX_STEREO; - break; - case 3: - mode = DOWNMIX_3F; - break; - case 4: - mode = DOWNMIX_2F2R; - break; - case 5: - mode = DOWNMIX_3F2R; - break; - case 6: - mode = DOWNMIX_3F2R|DOWNMIX_LFE_FLAG; - break; - case 7: - mode = DOWNMIX_3F4R; - break; - case 8: - mode = DOWNMIX_3F4R|DOWNMIX_LFE_FLAG; - break; - default: - // This will likely not sound very good ;) - mode = DOWNMIX_STEREO; - hb_error("hb_layout_to_mode: unsupported layout 0x%"PRIx64" with %d channels", - layout, av_get_channel_layout_nb_channels(layout)); - break; - } - } break; - } - return mode; -} - -int hb_mixdown_to_mode(uint32_t mixdown) -{ - switch (mixdown) - { - case HB_AMIXDOWN_MONO: - return DOWNMIX_MONO; - case HB_AMIXDOWN_STEREO: - return DOWNMIX_STEREO; - case HB_AMIXDOWN_DOLBY: - return DOWNMIX_DOLBY; - case HB_AMIXDOWN_DOLBYPLII: - return DOWNMIX_DPLII; - case HB_AMIXDOWN_6CH: - return DOWNMIX_3F2R|DOWNMIX_LFE_FLAG; - default: - return DOWNMIX_STEREO; - } -} - - -// ffmpeg gives us SMPTE channel layout -// We could use this layout and remap channels in encfaac, -// but VLC may have problems with remapping, so lets -// allow remapping to the default QuickTime order which is: -// -// C L R LS RS Rls Rrs LFE -// -// This arrangement also makes it possible to use half as -// many downmix matrices since the matrix with and without -// LFE are the same. -// -// Use hb_layout_remap to accomplish this. For convenience -// I've provided the necessary maps. -// -// SMPTE channel layout -// -// DUAL-MONO L R -// DUAL-MONO-LFE L R LFE -// MONO M -// MONO-LFE M LFE -// STEREO L R -// STEREO-LFE L R LFE -// 3F L R C -// 3F-LFE L R C LFE -// 2F1 L R S -// 2F1-LFE L R LFE S -// 3F1 L R C S -// 3F1-LFE L R C LFE S -// 2F2 L R LS RS -// 2F2-LFE L R LFE LS RS -// 3F2 L R C LS RS -// 3F2-LFE L R C LFE LS RS -// 3F4 L R C Rls Rrs LS RS -// 3F4-LFE L R C LFE Rls Rrs LS RS -// - -#define CH_C 0 -#define CH_L 1 -#define CH_R 2 -#define CH_CS 3 -#define CH_LS 3 -#define CH_RS 4 -#define CH_Rls 5 -#define CH_Rrs 6 -#define CH_LFE 7 - -hb_chan_map_t hb_qt_chan_map = -{ -{ - {{ CH_C, }, - { CH_C, CH_LFE, }}, // MONO - - {{ CH_L, CH_R, }, - { CH_L, CH_R, CH_LFE, }}, // STEREO - - {{ CH_C, CH_L, CH_R, }, - { CH_C, CH_L, CH_R, CH_LFE, }}, // 3F - - {{ CH_L, CH_R, CH_CS, }, - { CH_L, CH_R, CH_CS, CH_LFE, }}, // 2F1R - - {{ CH_C, CH_L, CH_R, CH_CS, }, - { CH_C, CH_L, CH_R, CH_CS, CH_LFE, }}, // 3F1R - - {{ CH_L, CH_R, CH_LS, CH_RS, }, - { CH_L, CH_R, CH_LS, CH_RS, CH_LFE, }}, // 2F2R - - {{ CH_C, CH_L, CH_R, CH_LS, CH_RS, }, - { CH_C, CH_L, CH_R, CH_LS, CH_RS, CH_LFE, }}, // 3F2R - - {{ CH_C, CH_L, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs, }, - { CH_C, CH_L, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs, CH_LFE }}, // 3F4R - - {{ CH_L, CH_R, }, - { CH_L, CH_R, }}, // DOLBY - - {{ CH_L, CH_R, }, - { CH_L, CH_R, }} // DPLII -}, -{ - // CH_C CH_L CH_R CH_LS/CS CH_RS CH_Rls CH_Rrs CH_LFE - {{ 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 1 }}, // MONO - - {{ 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 2 }}, // STEREO - - {{ 0, 1, 2, 0, 0, 0, 0, 0 }, - { 0, 1, 2, 0, 0, 0, 0, 3 }}, // 3F - - {{ 0, 0, 1, 2, 0, 0, 0, 0 }, - { 0, 0, 1, 2, 0, 0, 0, 3 }}, // 2F1R - - {{ 0, 1, 2, 3, 0, 0, 0, 0 }, - { 0, 1, 2, 3, 0, 0, 0, 4 }}, // 3F1R - - {{ 0, 0, 1, 2, 3, 0, 0, 0 }, - { 0, 0, 1, 2, 3, 0, 0, 4 }}, // 2F2R - - {{ 0, 1, 2, 3, 4, 0, 0, 0 }, - { 0, 1, 2, 3, 4, 0, 0, 5 }}, // 3F2R - - {{ 0, 1, 2, 3, 4, 5, 6, 0 }, - { 0, 1, 2, 3, 4, 5, 6, 7 }}, // 3F4R - - {{ 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }}, // DOLBY - - {{ 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }} // DPLII -} -}; - -hb_chan_map_t hb_smpte_chan_map = -{ -{ - {{ CH_C, }, - { CH_C, CH_LFE, }}, // MONO - - {{ CH_L, CH_R, }, - { CH_L, CH_R, CH_LFE, }}, // STEREO - - {{ CH_L, CH_R, CH_C, }, - { CH_L, CH_R, CH_C, CH_LFE, }}, // 3F - - {{ CH_L, CH_R, CH_CS, }, - { CH_L, CH_R, CH_LFE, CH_CS, }}, // 2F1R - - {{ CH_L, CH_R, CH_C, CH_CS, }, - { CH_L, CH_R, CH_LFE, CH_CS, }}, // 3F1R - - {{ CH_L, CH_R, CH_LS, CH_RS, }, - { CH_L, CH_R, CH_LFE, CH_LS, CH_RS, }}, // 2F2R - - {{ CH_L, CH_R, CH_C, CH_LS, CH_RS, }, - { CH_L, CH_R, CH_C, CH_LFE, CH_LS, CH_RS, }}, // 3F2R - - {{ CH_L, CH_R, CH_C, CH_Rls, CH_Rrs, CH_LS, CH_RS }, - { CH_L, CH_R, CH_C, CH_LFE, CH_Rls, CH_Rrs, CH_LS, CH_RS }}, // 3F4R - - {{ CH_L, CH_R, }, - { CH_L, CH_R, }}, // DOLBY - - {{ CH_L, CH_R, }, - { CH_L, CH_R, }} // DPLII -}, -{ - // CH_C CH_L CH_R CH_LS/CS CH_RS CH_Rls CH_Rrs CH_LFE - {{ 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 1 }}, // MONO - - {{ 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 2 }}, // STEREO - - {{ 2, 0, 1, 0, 0, 0, 0, 0 }, - { 2, 0, 1, 0, 0, 0, 0, 3 }}, // 3F - - {{ 0, 0, 1, 2, 0, 0, 0, 0 }, - { 0, 0, 1, 3, 0, 0, 0, 2 }}, // 2F1R - - {{ 2, 0, 1, 3, 0, 0, 0, 0 }, - { 2, 0, 1, 4, 0, 0, 0, 3 }}, // 3F1R - - {{ 0, 0, 1, 2, 3, 0, 0, 0 }, - { 0, 0, 1, 3, 4, 0, 0, 2 }}, // 2F2R - - {{ 2, 0, 1, 3, 4, 0, 0, 0 }, - { 2, 0, 1, 4, 5, 0, 0, 3 }}, // 3F2R - - {{ 2, 0, 1, 5, 6, 3, 4, 0 }, - { 2, 0, 1, 6, 7, 4, 5, 3 }}, // 3F4R - - {{ 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }}, // DOLBY - - {{ 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }} // DPLII -} -}; - -hb_chan_map_t hb_ac3_chan_map = -{ -{ - {{ CH_C, }, - { CH_LFE, CH_C, }}, // MONO - - {{ CH_L, CH_R, }, - { CH_LFE, CH_L, CH_R, }}, // STEREO - - {{ CH_L, CH_C, CH_R, }, - { CH_LFE, CH_L, CH_C, CH_R, }}, // 3F - - {{ CH_L, CH_R, CH_CS, }, - { CH_LFE, CH_L, CH_R, CH_CS, }}, // 2F1R - - {{ CH_L, CH_C, CH_R, CH_CS, }, - { CH_LFE, CH_L, CH_C, CH_R, CH_CS, }}, // 3F1R - - {{ CH_L, CH_R, CH_LS, CH_RS, }, - { CH_LFE, CH_L, CH_R, CH_LS, CH_RS, }}, // 2F2R - - {{ CH_L, CH_C, CH_R, CH_LS, CH_RS, }, - { CH_LFE, CH_L, CH_C, CH_R, CH_LS, CH_RS, }}, // 3F2R - - {{ CH_L, CH_C, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs, }, - { CH_LFE, CH_L, CH_C, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs }}, // 3F4R - - {{ CH_L, CH_R, }, - { CH_L, CH_R, }}, // DOLBY - - {{ CH_L, CH_R, }, - { CH_L, CH_R, }} // DPLII -}, -{ - // CH_C CH_L CH_R CH_LS/CS CH_RS CH_Rls CH_Rrs CH_LFE - {{ 0, 0, 0, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0, 0, 0 }}, // MONO - - {{ 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 1, 2, 0, 0, 0, 0, 0 }}, // STEREO - - {{ 1, 0, 2, 0, 0, 0, 0, 0 }, - { 2, 1, 3, 0, 0, 0, 0, 0 }}, // 3F - - {{ 0, 0, 1, 2, 0, 0, 0, 0 }, - { 0, 1, 2, 3, 0, 0, 0, 0 }}, // 2F1R - - {{ 1, 0, 2, 3, 0, 0, 0, 0 }, - { 2, 1, 3, 4, 0, 0, 0, 0 }}, // 3F1R - - {{ 0, 0, 1, 2, 3, 0, 0, 0 }, - { 0, 1, 2, 3, 4, 0, 0, 0 }}, // 2F2R - - {{ 1, 0, 2, 3, 4, 0, 0, 0 }, - { 2, 1, 3, 4, 5, 0, 0, 0 }}, // 3F2R - - {{ 1, 0, 2, 3, 4, 5, 6, 0 }, - { 2, 1, 3, 4, 5, 6, 7, 0 }}, // 3F4R - - {{ 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }}, // DOLBY - - {{ 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, 0, 0, 0 }} // DPLII -} -}; - -static const uint8_t nchans_tbl[] = {1, 2, 3, 3, 4, 4, 5, 7, 2, 2}; - -// Takes a set of samples and remaps the channel layout -void hb_layout_remap(hb_chan_map_t *map_in, - hb_chan_map_t *map_out, - uint64_t layout, - hb_sample_t *samples, - int nsamples) -{ - int nchans; - int ii, jj; - int lfe; - int * map; - int * inv_map; - int mode; - hb_sample_t tmp[8]; - - mode = hb_layout_to_mode(layout); - lfe = ((mode & DOWNMIX_LFE_FLAG) != 0); - mode = mode & DOWNMIX_CHANNEL_MASK; - nchans = nchans_tbl[mode] + lfe; - inv_map = map_in->inv_chan_map[mode][lfe]; - map = map_out->chan_map[mode][lfe]; - - for (ii = 0; ii < nsamples; ii++) - { - for (jj = 0; jj < nchans; jj++) - { - tmp[jj] = samples[jj]; - } - for (jj = 0; jj < nchans; jj++) - { - int ord = map[jj]; - samples[jj] = tmp[inv_map[ord]]; - } - samples += nchans; - } -} - -static void matrix_mul( - hb_sample_t * dst, - hb_sample_t * src, - int nchans_out, - int nchans_in, - int nsamples, - hb_sample_t (*matrix)[8], - hb_sample_t bias) -{ - int nn, ii, jj; - hb_sample_t val; - - for (nn = 0; nn < nsamples; nn++) - { - for (ii = 0; ii < nchans_out; ii++) - { - val = 0; - for (jj = 0; jj < nchans_in; jj++) - { - val += src[jj] * matrix[jj][ii]; - } - dst[ii] = val + bias; - } - src += nchans_in; - dst += nchans_out; - } -} - -static void set_level( hb_downmix_t * downmix ) -{ - int ii, jj; - int layout_in, layout_out; - int mode_in; - int mode_out; - - mode_in = downmix->mode_in & ~DOWNMIX_FLAGS_MASK; - mode_out = downmix->mode_out & ~DOWNMIX_FLAGS_MASK; - - for (ii = 0; ii < 8; ii++) - { - for (jj = 0; jj < 8; jj++) - { - downmix->matrix[ii][jj] *= downmix->level; - } - } - if (mode_out >= DOWNMIX_DOLBY) - return; - - layout_in = channel_layout_map[mode_in]; - layout_out = channel_layout_map[mode_out]; - - if (layout_in & HB_CH_FRONT_CENTER) - { - if (!(layout_out & HB_CH_FRONT_CENTER)) - { - for (jj = 0; jj < 8; jj++) - { - downmix->matrix[downmix->center][jj] *= downmix->clev; - } - } - } - if (layout_in & (HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT|HB_CH_BACK_CENTER|HB_CH_SIDE_LEFT|HB_CH_SIDE_RIGHT)) - { - if (layout_out & (HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT|HB_CH_BACK_CENTER|HB_CH_SIDE_LEFT|HB_CH_SIDE_RIGHT)) - { - // Note, slev only gets set if input has surround, and output has none. - return; - } - } - for (jj = 0; jj < 8; jj++) - { - if ( downmix->left_surround >= 0 ) - downmix->matrix[downmix->left_surround][jj] *= downmix->slev; - if ( downmix->right_surround >= 0 ) - downmix->matrix[downmix->right_surround][jj] *= downmix->slev; - if ( downmix->rear_left_surround >= 0 ) - downmix->matrix[downmix->rear_left_surround][jj] *= downmix->slev; - if ( downmix->rear_right_surround >= 0 ) - downmix->matrix[downmix->rear_right_surround][jj] *= downmix->slev; - } -} - -#define MIXMODE(x,y) (((x)<<4)|(y)) -// The downmix operation can result in new sample values that are -// outside the original range of sample values. If you wish to -// guarantee that the levels to not exceed the original range, -// call this function after initializing downmix and setting -// your initial levels. -// -// Note that this can result in generally lower volume levels -// in the resulting downmixed audio. -void hb_downmix_adjust_level( hb_downmix_t * downmix ) -{ - int mode_in, mode_out; - hb_sample_t level = downmix->level; - hb_sample_t clev = downmix->clev; - hb_sample_t slev = downmix->slev; - - mode_in = downmix->mode_in & DOWNMIX_CHANNEL_MASK; - mode_out = downmix->mode_out & DOWNMIX_CHANNEL_MASK; - - switch MIXMODE(mode_in, mode_out) - { - case MIXMODE(DOWNMIX_STEREO, DOWNMIX_MONO): - case MIXMODE(DOWNMIX_2F2R, DOWNMIX_2F1R): - case MIXMODE(DOWNMIX_2F2R, DOWNMIX_3F1R): - case MIXMODE(DOWNMIX_3F2R, DOWNMIX_3F1R): - case MIXMODE(DOWNMIX_3F4R, DOWNMIX_3F1R): - case MIXMODE(DOWNMIX_3F4R, DOWNMIX_3F2R): - level_3db: - level /= LVL_PLUS3DB; - break; - - case MIXMODE(DOWNMIX_3F, DOWNMIX_MONO): - level /= LVL_PLUS3DB + clev * LVL_PLUS3DB; - break; - - case MIXMODE(DOWNMIX_3F2R, DOWNMIX_2F1R): - case MIXMODE(DOWNMIX_3F4R, DOWNMIX_2F1R): - case MIXMODE(DOWNMIX_3F4R, DOWNMIX_2F2R): - if (1 + clev < LVL_PLUS3DB) - goto level_3db; - case MIXMODE(DOWNMIX_3F, DOWNMIX_STEREO): - case MIXMODE(DOWNMIX_3F, DOWNMIX_2F1R): - case MIXMODE(DOWNMIX_3F, DOWNMIX_2F2R): - case MIXMODE(DOWNMIX_3F, DOWNMIX_DOLBY): - case MIXMODE(DOWNMIX_3F, DOWNMIX_DPLII): - case MIXMODE(DOWNMIX_3F1R, DOWNMIX_2F1R): - case MIXMODE(DOWNMIX_3F1R, DOWNMIX_2F2R): - case MIXMODE(DOWNMIX_3F2R, DOWNMIX_2F2R): - level /= 1 + clev; - break; - - - case MIXMODE(DOWNMIX_2F1R, DOWNMIX_MONO): - level /= LVL_PLUS3DB + LVL_3DB * clev; - break; - - case MIXMODE(DOWNMIX_2F1R, DOWNMIX_DOLBY): - level /= 1 + LVL_3DB; - break; - - case MIXMODE(DOWNMIX_2F1R, DOWNMIX_STEREO): - case MIXMODE(DOWNMIX_2F1R, DOWNMIX_3F): - case MIXMODE(DOWNMIX_3F1R, DOWNMIX_3F): - level /= 1 + LVL_3DB * slev; - break; - - case MIXMODE(DOWNMIX_3F1R, DOWNMIX_MONO): - level /= LVL_PLUS3DB + LVL_PLUS3DB * clev + LVL_3DB * slev; - break; - - case MIXMODE(DOWNMIX_3F1R, DOWNMIX_STEREO): - level /= 1 + clev + LVL_3DB * slev; - break; - - case MIXMODE(DOWNMIX_3F1R, DOWNMIX_DOLBY): - case MIXMODE(DOWNMIX_3F1R, DOWNMIX_DPLII): - case MIXMODE(DOWNMIX_2F2R, DOWNMIX_DOLBY): - level /= 1 + LVL_PLUS3DB; - break; - - case MIXMODE(DOWNMIX_2F2R, DOWNMIX_MONO): - level /= LVL_PLUS3DB + LVL_PLUS3DB * slev; - break; - - case MIXMODE(DOWNMIX_2F2R, DOWNMIX_STEREO): - case MIXMODE(DOWNMIX_2F2R, DOWNMIX_3F): - case MIXMODE(DOWNMIX_3F2R, DOWNMIX_3F): - level /= 1 + slev; - break; - - case MIXMODE(DOWNMIX_2F2R, DOWNMIX_DPLII): - level /= 1 + LVL_SQRT_1_4 + LVL_SQRT_3_4; - break; - - case MIXMODE(DOWNMIX_3F2R, DOWNMIX_MONO): - case MIXMODE(DOWNMIX_3F4R, DOWNMIX_MONO): - level /= LVL_PLUS3DB + LVL_PLUS3DB * clev * LVL_PLUS3DB * slev; - break; - - case MIXMODE(DOWNMIX_3F2R, DOWNMIX_STEREO): - level /= 1 + clev + slev; - break; - - case MIXMODE(DOWNMIX_3F2R, DOWNMIX_DOLBY): - level /= 1 + 3 * LVL_3DB; - break; - - case MIXMODE(DOWNMIX_3F2R, DOWNMIX_DPLII): - level /= 1 + LVL_3DB + LVL_SQRT_1_4 + LVL_SQRT_3_4; - break; - - case MIXMODE(DOWNMIX_3F4R, DOWNMIX_STEREO): - level /= 1 + clev + LVL_PLUS3DB * slev; - break; - - case MIXMODE(DOWNMIX_3F4R, DOWNMIX_3F): - level /= 1 + LVL_PLUS3DB * slev; - break; - - case MIXMODE(DOWNMIX_3F4R, DOWNMIX_DOLBY): - level /= 1 + 5 * LVL_3DB; - break; - - case MIXMODE(DOWNMIX_3F4R, DOWNMIX_DPLII): - level /= 1 + LVL_3DB + 2 * LVL_SQRT_1_4 + 2 * LVL_SQRT_3_4; - } - - downmix->level = level; - downmix->matrix_initialized = 0; -} - -void hb_downmix_set_bias( hb_downmix_t * downmix, hb_sample_t bias ) -{ - downmix->bias = bias; -} - -// Changes the downmix mode if it needs changing after initialization -static void set_mode( hb_downmix_t * downmix ) -{ - int ii, jj; - int mode_in, mode_out; - hb_sample_t (*matrix)[8]; - - mode_in = downmix->mode_in & ~DOWNMIX_FLAGS_MASK; - mode_out = downmix->mode_out & ~DOWNMIX_FLAGS_MASK; - - matrix = downmix_matrix[mode_in][mode_out]; - - for (ii = 0; ii < 8; ii++) - { - for (jj = 0; jj < 8; jj++) - { - downmix->matrix[ii][jj] = matrix[ii][jj]; - } - } -} - -// Changes the downmix mode if it needs changing after initialization -int hb_downmix_set_mode( hb_downmix_t * downmix, int layout, int mixdown ) -{ - int lfe_in, lfe_out; - int mode_in, mode_out; - - if ( downmix == NULL ) - return -1; - - mode_in = hb_layout_to_mode(layout); - mode_out = hb_mixdown_to_mode(mixdown); - downmix->mode_in = mode_in; - downmix->mode_out = mode_out; - - mode_in = downmix->mode_in & ~DOWNMIX_FLAGS_MASK; - mode_out = downmix->mode_out & ~DOWNMIX_FLAGS_MASK; - - if (mode_in >= DOWNMIX_NUM_MODES || mode_out >= DOWNMIX_NUM_MODES) - return -1; - - lfe_in = ((downmix->mode_in & DOWNMIX_LFE_FLAG) != 0); - lfe_out = ((downmix->mode_out & DOWNMIX_LFE_FLAG) != 0); - - downmix->nchans_in = nchans_tbl[mode_in] + lfe_in; - downmix->nchans_out = nchans_tbl[mode_out] + lfe_out; - - downmix->matrix_initialized = 0; - return 0; -} - -// Changes the downmix levels if they need changing after initialization -void hb_downmix_set_level( hb_downmix_t * downmix, hb_sample_t clev, hb_sample_t slev, hb_sample_t level ) -{ - if ( downmix == NULL ) - return; - - downmix->clev = clev; - downmix->slev = slev; - downmix->level = level; - downmix->matrix_initialized = 0; -} - -static void set_chan_map( hb_downmix_t * downmix ) -{ - int nchans; - int ii, jj; - int lfe; - int * map; - int * inv_map; - int mode; - hb_sample_t matrix[8][8]; - - // Copy the matrix - for ( ii = 0; ii < 8; ii++ ) - { - for ( jj = 0; jj < 8; jj++ ) - { - matrix[ii][jj] = downmix->matrix[ii][jj]; - } - } - - // Rearrange the rows to correspond to the input channel order - lfe = ((downmix->mode_in & DOWNMIX_LFE_FLAG) != 0); - mode = downmix->mode_in & DOWNMIX_CHANNEL_MASK; - nchans = nchans_tbl[mode] + lfe; - map = downmix->map_in.chan_map[mode][lfe]; - inv_map = hb_qt_chan_map.inv_chan_map[mode][lfe]; - - downmix->center = -1; - downmix->left_surround = -1; - downmix->right_surround = -1; - downmix->rear_left_surround = -1; - downmix->rear_right_surround = -1; - for ( ii = 0; ii < nchans; ii++ ) - { - int ord = map[ii]; - int row = inv_map[ord]; - switch (ord) - { - case CH_C: - downmix->center = ii; - break; - case CH_LS: - downmix->left_surround = ii; - break; - case CH_RS: - downmix->right_surround = ii; - break; - case CH_Rls: - downmix->rear_right_surround = ii; - break; - case CH_Rrs: - downmix->rear_left_surround = ii; - break; - } - for ( jj = 0; jj < 8; jj++ ) - { - downmix->matrix[ii][jj] = matrix[row][jj]; - } - } - - // Copy the matrix - for ( ii = 0; ii < 8; ii++ ) - { - for ( jj = 0; jj < 8; jj++ ) - { - matrix[ii][jj] = downmix->matrix[ii][jj]; - } - } - - // Rearrange the columns to correspond to the output channel order - lfe = ((downmix->mode_out & DOWNMIX_LFE_FLAG) != 0); - mode = downmix->mode_out & DOWNMIX_CHANNEL_MASK; - nchans = nchans_tbl[mode] + lfe; - map = downmix->map_out.chan_map[mode][lfe]; - inv_map = hb_qt_chan_map.inv_chan_map[mode][lfe]; - for ( ii = 0; ii < nchans; ii++ ) - { - int ord = map[ii]; - int col = inv_map[ord]; - for ( jj = 0; jj < 8; jj++ ) - { - downmix->matrix[jj][ii] = matrix[jj][col]; - } - } -} - -void hb_downmix_set_chan_map( - hb_downmix_t * downmix, - hb_chan_map_t * map_in, - hb_chan_map_t * map_out ) -{ - downmix->map_in = *map_in; - downmix->map_out = *map_out; - downmix->matrix_initialized = 0; -} - -hb_downmix_t * hb_downmix_init(int layout, int mixdown) -{ - hb_downmix_t * downmix = calloc(1, sizeof(hb_downmix_t)); - - if (downmix == NULL) - return NULL; - if ( hb_downmix_set_mode( downmix, layout, mixdown ) < 0 ) - { - free( downmix ); - return NULL; - } - // Set some good default values - hb_downmix_set_level( downmix, LVL_3DB, LVL_3DB, 1.0 ); - downmix->bias = 0.0; - downmix->matrix_initialized = 0; - // The default input and output channel order is QT - hb_downmix_set_chan_map( downmix, &hb_qt_chan_map, &hb_qt_chan_map ); - return downmix; -} - -void hb_downmix_close( hb_downmix_t **downmix ) -{ - if (*downmix != NULL) - free(*downmix); - *downmix = NULL; -} - -static void init_matrix( hb_downmix_t * downmix ) -{ - if ( !downmix->matrix_initialized ) - { - set_mode( downmix ); - set_chan_map( downmix ); - set_level(downmix); - downmix->matrix_initialized = 1; - } -} - -void hb_downmix( hb_downmix_t * downmix, hb_sample_t * dst, hb_sample_t * src, int nsamples) -{ - init_matrix( downmix ); - matrix_mul( dst, src, downmix->nchans_out, downmix->nchans_in, - nsamples, downmix->matrix, downmix->bias ); -} - -int hb_need_downmix( int layout, int mixdown ) -{ - int mode_in, mode_out; - - mode_in = hb_layout_to_mode(layout); - mode_out = hb_mixdown_to_mode(mixdown); - - return (mode_in != mode_out); -} diff --git a/libhb/downmix.h b/libhb/downmix.h index b67889f56..e69de29bb 100644 --- a/libhb/downmix.h +++ b/libhb/downmix.h @@ -1,67 +0,0 @@ -/* downmix.h - - Copyright (c) 2003-2012 HandBrake Team - This file is part of the HandBrake source code - Homepage: <http://handbrake.fr/>. - It may be used under the terms of the GNU General Public License v2. - For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html - */ -#ifndef DOWNMIX_H -#define DOWNMIX_H - -typedef float hb_sample_t; - -typedef struct -{ - int chan_map[10][2][8]; - int inv_chan_map[10][2][8]; -} hb_chan_map_t; - -typedef struct -{ - int mode_in; - int mode_out; - int nchans_in; - int nchans_out; - hb_sample_t matrix[8][8]; - int matrix_initialized; - hb_sample_t clev; - hb_sample_t slev; - hb_sample_t level; - hb_sample_t bias; - hb_chan_map_t map_in; - hb_chan_map_t map_out; - - int center; - int left_surround; - int right_surround; - int rear_left_surround; - int rear_right_surround; -} hb_downmix_t; - -// For convenience, a map to convert smpte channel layout -// to QuickTime channel layout. -// Map Indicies are mode, lfe, channel respectively -extern hb_chan_map_t hb_smpte_chan_map; -extern hb_chan_map_t hb_ac3_chan_map; -extern hb_chan_map_t hb_qt_chan_map; - -hb_downmix_t * hb_downmix_init(int layout, int mixdown); -void hb_downmix_close( hb_downmix_t **downmix ); -int hb_downmix_set_mode( hb_downmix_t * downmix, int layout, int mixdown ); -void hb_downmix_set_level( hb_downmix_t * downmix, hb_sample_t clev, hb_sample_t slev, hb_sample_t level ); -void hb_downmix_adjust_level( hb_downmix_t * downmix ); -void hb_downmix_set_bias( hb_downmix_t * downmix, hb_sample_t bias ); -void hb_downmix_set_chan_map( - hb_downmix_t * downmix, - hb_chan_map_t * map_in, - hb_chan_map_t * map_out ); -void hb_downmix( hb_downmix_t * downmix, hb_sample_t * dst, hb_sample_t * src, int nsamples); -void hb_layout_remap(hb_chan_map_t *map_in, - hb_chan_map_t *map_out, - uint64_t layout, - hb_sample_t *samples, - int nsamples); -int hb_need_downmix( int layout, int mixdown ); - -#endif /* DOWNMIX_H */ diff --git a/libhb/dvd.c b/libhb/dvd.c index 19325c1d4..6af2e7908 100644 --- a/libhb/dvd.c +++ b/libhb/dvd.c @@ -363,6 +363,7 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur case 0x03: audio->id = 0xc0 + position; audio->config.in.codec = HB_ACODEC_FFMPEG; + audio->config.in.codec_param = CODEC_ID_MP2; codec_name = "MPEG"; break; diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c index 2e4918095..d6e97c1a5 100644 --- a/libhb/dvdnav.c +++ b/libhb/dvdnav.c @@ -512,6 +512,7 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura case 0x03: audio->id = 0xc0 + position; audio->config.in.codec = HB_ACODEC_FFMPEG; + audio->config.in.codec_param = CODEC_ID_MP2; codec_name = "MPEG"; break; diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c index 037a7aef2..44453477f 100644 --- a/libhb/encavcodec.c +++ b/libhb/encavcodec.c @@ -451,17 +451,25 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, if ( pv->context->codec ) { + int ret; + AVPacket pkt; + int got_packet; + + av_init_packet(&pkt); /* Should be way too large */ buf = hb_video_buffer_init( job->width, job->height ); - buf->size = avcodec_encode_video( pv->context, buf->data, buf->alloc, - frame ); - if ( buf->size <= 0 ) + pkt.data = buf->data; + pkt.size = buf->alloc; + + ret = avcodec_encode_video2( pv->context, &pkt, frame, &got_packet ); + if ( ret < 0 || pkt.size <= 0 || !got_packet ) { hb_buffer_close( &buf ); } else { - int64_t frameno = pv->context->coded_frame->pts; + int64_t frameno = pkt.pts; + buf->size = pkt.size; buf->s.start = get_frame_start( pv, frameno ); buf->s.stop = get_frame_stop( pv, frameno ); buf->s.flags &= ~HB_FRAME_REF; @@ -492,7 +500,7 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, case AV_PICTURE_TYPE_I: { buf->s.flags |= HB_FRAME_REF; - if ( pv->context->coded_frame->key_frame ) + if ( pkt.flags & AV_PKT_FLAG_KEY ) { buf->s.frametype = HB_FRAME_IDR; } @@ -504,7 +512,7 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, default: { - if ( pv->context->coded_frame->key_frame ) + if ( pkt.flags & AV_PKT_FLAG_KEY ) { buf->s.flags |= HB_FRAME_REF; buf->s.frametype = HB_FRAME_KEY; diff --git a/libhb/encavcodecaudio.c b/libhb/encavcodecaudio.c index 14df3f317..001000b9a 100644 --- a/libhb/encavcodecaudio.c +++ b/libhb/encavcodecaudio.c @@ -9,8 +9,7 @@ #include "hb.h" #include "hbffmpeg.h" -#include "downmix.h" -#include "libavcodec/audioconvert.h" +#include "audio_remap.h" struct hb_work_private_s { @@ -23,6 +22,9 @@ struct hb_work_private_s unsigned long output_bytes; hb_list_t * list; uint8_t * buf; + + AVAudioResampleContext *avresample; + int *remap_table; }; static int encavcodecaInit( hb_work_object_t *, hb_job_t * ); @@ -49,8 +51,6 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job ) pv->job = job; - pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count( audio->config.out.mixdown ); - codec = avcodec_find_encoder( w->codec_param ); if( !codec ) { @@ -60,40 +60,30 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job ) } context = avcodec_alloc_context3(codec); - AVDictionary *av_opts = NULL; - if ( w->codec_param == CODEC_ID_AAC ) + int mode; + context->channel_layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, &mode); + pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); + + if (pv->out_discrete_channels > 2 && + audio->config.in.channel_map != &hb_libav_chan_map) { - av_dict_set( &av_opts, "stereo_mode", "ms_off", 0 ); + pv->remap_table = hb_audio_remap_build_table(context->channel_layout, + audio->config.in.channel_map, + &hb_libav_chan_map); } - if ( w->codec_param == CODEC_ID_AC3 ) + else { - if( audio->config.out.mixdown == HB_AMIXDOWN_DOLBY || - audio->config.out.mixdown == HB_AMIXDOWN_DOLBYPLII ) - { - av_dict_set( &av_opts, "dsur_mode", "on", 0 ); - } + pv->remap_table = NULL; } - switch (audio->config.out.mixdown) + AVDictionary *av_opts = NULL; + if (w->codec_param == CODEC_ID_AAC) + { + av_dict_set(&av_opts, "stereo_mode", "ms_off", 0); + } + else if (w->codec_param == CODEC_ID_AC3 && mode != AV_MATRIX_ENCODING_NONE) { - case HB_AMIXDOWN_MONO: - context->channel_layout = AV_CH_LAYOUT_MONO; - break; - - case HB_AMIXDOWN_STEREO: - case HB_AMIXDOWN_DOLBY: - case HB_AMIXDOWN_DOLBYPLII: - context->channel_layout = AV_CH_LAYOUT_STEREO; - break; - - case HB_AMIXDOWN_6CH: - context->channel_layout = AV_CH_LAYOUT_5POINT1; - break; - - default: - context->channel_layout = AV_CH_LAYOUT_STEREO; - hb_log("encavcodecaInit: bad mixdown"); - break; + av_dict_set(&av_opts, "dsur_mode", "on", 0); } if( audio->config.out.bitrate > 0 ) @@ -146,6 +136,31 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job ) w->config->extradata.length = context->extradata_size; } + // Check if sample format conversion is necessary + if (AV_SAMPLE_FMT_FLT != pv->context->sample_fmt) + { + // Set up avresample to do conversion + pv->avresample = avresample_alloc_context(); + if (pv->avresample == NULL) + { + hb_error("Failed to initialize avresample"); + return 1; + } + + uint64_t layout; + layout = hb_ff_layout_xlat(context->channel_layout, context->channels); + av_opt_set_int(pv->avresample, "in_channel_layout", layout, 0); + av_opt_set_int(pv->avresample, "out_channel_layout", layout, 0); + av_opt_set_int(pv->avresample, "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0); + av_opt_set_int(pv->avresample, "out_sample_fmt", context->sample_fmt, 0); + + if (avresample_open(pv->avresample) < 0) + { + hb_error("Failed to open avresample"); + avresample_free(&pv->avresample); + return 1; + } + } return 0; } @@ -159,11 +174,20 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job ) static void Finalize( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; - hb_buffer_t * buf = hb_buffer_init( pv->output_bytes ); + hb_buffer_t * buf; // Finalize with NULL input needed by FLAC to generate md5sum // in context extradata - avcodec_encode_audio( pv->context, buf->data, buf->alloc, NULL ); + + // Prepare output packet + AVPacket pkt; + int got_packet; + buf = hb_buffer_init( pv->output_bytes ); + av_init_packet(&pkt); + pkt.data = buf->data; + pkt.size = buf->alloc; + + avcodec_encode_audio2( pv->context, &pkt, NULL, &got_packet); hb_buffer_close( &buf ); // Then we need to recopy the header since it was modified @@ -198,11 +222,36 @@ static void encavcodecaClose( hb_work_object_t * w ) if ( pv->list ) hb_list_empty( &pv->list ); + if (pv->avresample != NULL) + { + avresample_free(&pv->avresample); + } + free( pv ); w->private_data = NULL; } } +static void convertAudioFormat( hb_work_private_t *pv, AVFrame *frame ) +{ + if (pv->avresample != NULL) + { + int out_samples, out_linesize; + + av_samples_get_buffer_size(&out_linesize, pv->context->channels, + frame->nb_samples, pv->context->sample_fmt, 0); + + out_samples = avresample_convert(pv->avresample, + (void **)frame->data, out_linesize, frame->nb_samples, + (void **)frame->data, frame->linesize[0], frame->nb_samples); + + if (out_samples < 0) + { + hb_error("avresample_convert() failed"); + } + } +} + static hb_buffer_t * Encode( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; @@ -217,65 +266,67 @@ static hb_buffer_t * Encode( hb_work_object_t * w ) hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ), &pts, &pos); - - // XXX: ffaac fails to remap from the internal libav* channel map (SMPTE) to the native AAC channel map - // do it here - this hack should be removed if Libav fixes the bug - hb_chan_map_t * out_map = ( w->codec_param == CODEC_ID_AAC ) ? &hb_qt_chan_map : &hb_smpte_chan_map; - - if (audio->config.in.channel_map != out_map) + if (pv->remap_table != NULL) { - hb_layout_remap(audio->config.in.channel_map, out_map, - pv->context->channel_layout, (float*)pv->buf, - pv->samples_per_frame); + hb_audio_remap(pv->out_discrete_channels, pv->samples_per_frame, + (hb_sample_t*)pv->buf, pv->remap_table); } + // Prepare input frame + AVFrame frame; + frame.nb_samples= pv->samples_per_frame; + int size = av_samples_get_buffer_size(NULL, pv->context->channels, + frame.nb_samples, pv->context->sample_fmt, 1); + avcodec_fill_audio_frame(&frame, pv->context->channels, + pv->context->sample_fmt, pv->buf, size, 1); + frame.pts = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate; + + // libav requires that timebase of audio input frames to be + // in sample_rate units. + frame.pts = av_rescale( frame.pts, pv->context->sample_rate, 90000); + // Do we need to convert our internal float format? - if ( pv->context->sample_fmt != AV_SAMPLE_FMT_FLT ) + convertAudioFormat(pv, &frame); + + // Prepare output packet + AVPacket pkt; + int got_packet; + buf = hb_buffer_init( pv->output_bytes ); + av_init_packet(&pkt); + pkt.data = buf->data; + pkt.size = buf->alloc; + + // Encode + int ret = avcodec_encode_audio2( pv->context, &pkt, &frame, &got_packet); + if ( ret < 0 ) { - int isamp, osamp; - AVAudioConvert *ctx; - - isamp = av_get_bytes_per_sample( AV_SAMPLE_FMT_FLT ); - osamp = av_get_bytes_per_sample( pv->context->sample_fmt ); - ctx = av_audio_convert_alloc( pv->context->sample_fmt, 1, - AV_SAMPLE_FMT_FLT, 1, - NULL, 0 ); - - // get output buffer size then malloc a buffer - //nsamples = out_size / isamp; - //buffer = av_malloc( nsamples * sizeof(hb_sample_t) ); - - // we're doing straight sample format conversion which - // behaves as if there were only one channel. - const void * const ibuf[6] = { pv->buf }; - void * const obuf[6] = { pv->buf }; - const int istride[6] = { isamp }; - const int ostride[6] = { osamp }; - - av_audio_convert( ctx, obuf, ostride, ibuf, istride, pv->input_samples ); - av_audio_convert_free( ctx ); + hb_log( "encavcodeca: avcodec_encode_audio failed" ); + hb_buffer_close( &buf ); + return NULL; } - - buf = hb_buffer_init( pv->output_bytes ); - buf->size = avcodec_encode_audio( pv->context, buf->data, buf->alloc, - (short*)pv->buf ); - buf->s.start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate; - buf->s.stop = buf->s.start + 90000 * pv->samples_per_frame / audio->config.out.samplerate; + if ( got_packet && pkt.size ) + { + buf->size = pkt.size; - buf->s.type = AUDIO_BUF; - buf->s.frametype = HB_FRAME_AUDIO; + // The output pts from libav is in context->time_base. Convert + // it back to our timebase. + // + // Also account for the "delay" factor that libav seems to arbitrarily + // subtract from the packet. Not sure WTH they think they are doing + // by offseting the value in a negative direction. + buf->s.start = av_rescale_q( pkt.pts + pv->context->delay, + pv->context->time_base, (AVRational){ 1, 90000 }); - if ( !buf->size ) - { - hb_buffer_close( &buf ); - return Encode( w ); + buf->s.stop = buf->s.start + 90000 * pv->samples_per_frame / audio->config.out.samplerate; + + buf->s.type = AUDIO_BUF; + buf->s.frametype = HB_FRAME_AUDIO; } - else if (buf->size < 0) + else { - hb_log( "encavcodeca: avcodec_encode_audio failed" ); hb_buffer_close( &buf ); - return NULL; + return Encode( w ); } return buf; diff --git a/libhb/encfaac.c b/libhb/encfaac.c index d01afce8a..6782605e9 100644 --- a/libhb/encfaac.c +++ b/libhb/encfaac.c @@ -8,6 +8,7 @@ */ #include "hb.h" +#include "audio_remap.h" #include "faac.h" @@ -72,7 +73,7 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) pv->job = job; /* pass the number of channels used into the private work data */ - pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count( audio->config.out.mixdown ); + pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); /* if the sample rate is 'auto' and that has given us an invalid output */ /* rate, map it to the next highest output rate or 48K if above the highest. */ @@ -109,13 +110,20 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) cfg->aacObjectType = LOW; cfg->allowMidside = 1; - if (pv->out_discrete_channels == 6) { - /* we are preserving 5.1 audio into 6-channel AAC, - so indicate that we have an lfe channel */ - cfg->useLfe = 1; - } else { - cfg->useLfe = 0; - } + // LFE, remapping + uint64_t layout; + layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL); + cfg->useLfe = !!(layout & AV_CH_LOW_FREQUENCY); + if (pv->out_discrete_channels > 2 && + audio->config.in.channel_map != &hb_aac_chan_map) + { + int *remap_table; + remap_table = hb_audio_remap_build_table(layout, + audio->config.in.channel_map, + &hb_aac_chan_map); + // faac does its own remapping + memcpy(cfg->channel_map, remap_table, pv->out_discrete_channels * sizeof(int)); + } cfg->useTns = 0; cfg->bitRate = audio->config.out.bitrate * 1000 / pv->out_discrete_channels; /* Per channel */ @@ -123,28 +131,6 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) cfg->outputFormat = 0; cfg->inputFormat = FAAC_INPUT_FLOAT; - if( ( audio->config.out.mixdown == HB_AMIXDOWN_6CH ) && ( audio->config.in.channel_map != &hb_qt_chan_map ) ) - { - if( audio->config.in.channel_map == &hb_ac3_chan_map ) - { - cfg->channel_map[0] = 2; - cfg->channel_map[1] = 1; - cfg->channel_map[2] = 3; - cfg->channel_map[3] = 4; - cfg->channel_map[4] = 5; - cfg->channel_map[5] = 0; - } - else if( audio->config.in.channel_map == &hb_smpte_chan_map ) - { - cfg->channel_map[0] = 2; - cfg->channel_map[1] = 0; - cfg->channel_map[2] = 1; - cfg->channel_map[3] = 4; - cfg->channel_map[4] = 5; - cfg->channel_map[5] = 3; - } - } - if( !faacEncSetConfiguration( pv->faac, cfg ) ) { hb_log( "faacEncSetConfiguration failed" ); diff --git a/libhb/encvorbis.c b/libhb/encvorbis.c index b0c7ea0ce..da631592c 100644 --- a/libhb/encvorbis.c +++ b/libhb/encvorbis.c @@ -8,6 +8,7 @@ */ #include "hb.h" +#include "audio_remap.h" #include "vorbis/vorbisenc.h" @@ -40,9 +41,9 @@ struct hb_work_private_s uint64_t pts; hb_list_t * list; - int out_discrete_channels; - int channel_map[6]; - int64_t prev_blocksize; + int out_discrete_channels; + int * remap_table; + int64_t prev_blocksize; }; int encvorbisInit( hb_work_object_t * w, hb_job_t * job ) @@ -53,7 +54,7 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job ) hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); w->private_data = pv; - pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count( audio->config.out.mixdown ); + pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); pv->job = job; @@ -134,48 +135,13 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job ) pv->list = hb_list_init(); - switch (pv->out_discrete_channels) { - case 1: - pv->channel_map[0] = 0; - break; - case 6: - // Vorbis uses the following channel map = L C R Ls Rs Lfe - if( audio->config.in.channel_map == &hb_ac3_chan_map ) - { - pv->channel_map[0] = 1; - pv->channel_map[1] = 2; - pv->channel_map[2] = 3; - pv->channel_map[3] = 4; - pv->channel_map[4] = 5; - pv->channel_map[5] = 0; - } - else if( audio->config.in.channel_map == &hb_smpte_chan_map ) - { - pv->channel_map[0] = 0; - pv->channel_map[1] = 2; - pv->channel_map[2] = 1; - pv->channel_map[3] = 4; - pv->channel_map[4] = 5; - pv->channel_map[5] = 3; - } - else // &hb_qt_chan_map - { - pv->channel_map[0] = 1; - pv->channel_map[1] = 0; - pv->channel_map[2] = 2; - pv->channel_map[3] = 3; - pv->channel_map[4] = 4; - pv->channel_map[5] = 5; - } - break; - default: - hb_log("encvorbis.c: Unable to correctly proccess %d channels, assuming stereo.", pv->out_discrete_channels); - case 2: - // Assume stereo - pv->channel_map[0] = 0; - pv->channel_map[1] = 1; - break; - } + // remapping + uint64_t layout; + layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL); + pv->remap_table = hb_audio_remap_build_table(layout, + audio->config.in.channel_map, + &hb_vorbis_chan_map); + return 0; } @@ -273,7 +239,7 @@ static hb_buffer_t * Encode( hb_work_object_t * w ) { for( j = 0; j < pv->out_discrete_channels; j++) { - buffer[j][i] = ((float *) pv->buf)[(pv->out_discrete_channels * i + pv->channel_map[j])]; + buffer[j][i] = ((float *) pv->buf)[(pv->out_discrete_channels * i + pv->remap_table[j])]; } } diff --git a/libhb/hb.c b/libhb/hb.c index b5c721953..c6b569caf 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -105,15 +105,16 @@ void hb_avcodec_init() av_register_all(); } -int hb_avcodec_open(AVCodecContext *avctx, AVCodec *codec, AVDictionary **av_opts, int thread_count) +int hb_avcodec_open(AVCodecContext *avctx, AVCodec *codec, + AVDictionary **av_opts, int thread_count) { int ret; - if ( ( thread_count == HB_FFMPEG_THREADS_AUTO || thread_count > 0 ) && - ( codec->type == AVMEDIA_TYPE_VIDEO ) ) + if ((thread_count == HB_FFMPEG_THREADS_AUTO || thread_count > 0) && + (codec->type == AVMEDIA_TYPE_VIDEO)) { - avctx->thread_count = ( thread_count == HB_FFMPEG_THREADS_AUTO ) ? - hb_get_cpu_count() / 2 + 1 : thread_count; + avctx->thread_count = (thread_count == HB_FFMPEG_THREADS_AUTO) ? + hb_get_cpu_count() / 2 + 1 : thread_count; avctx->thread_type = FF_THREAD_FRAME|FF_THREAD_SLICE; avctx->thread_safe_callbacks = 1; } @@ -134,16 +135,16 @@ int hb_avcodec_close(AVCodecContext *avctx) } -int hb_avpicture_fill( AVPicture *pic, hb_buffer_t *buf ) +int hb_avpicture_fill(AVPicture *pic, hb_buffer_t *buf) { int ret, ii; - for( ii = 0; ii < 4; ii++ ) + for (ii = 0; ii < 4; ii++) pic->linesize[ii] = buf->plane[ii].stride; - ret = av_image_fill_pointers( pic->data, buf->f.fmt, - buf->plane[0].height_stride, - buf->data, pic->linesize ); + ret = av_image_fill_pointers(pic->data, buf->f.fmt, + buf->plane[0].height_stride, + buf->data, pic->linesize); if (ret != buf->size) { hb_error("Internal error hb_avpicture_fill expected %d, got %d", @@ -209,45 +210,61 @@ hb_sws_get_context(int srcW, int srcH, enum PixelFormat srcFormat, return ctx; } +uint64_t hb_ff_mixdown_xlat(int hb_mixdown, int *downmix_mode) +{ + uint64_t ff_layout = 0; + int mode = AV_MATRIX_ENCODING_NONE; + switch (hb_mixdown) + { + // Passthru + case HB_AMIXDOWN_NONE: + break; + + case HB_AMIXDOWN_MONO: + ff_layout = AV_CH_LAYOUT_MONO; + break; + + case HB_AMIXDOWN_DOLBY: + ff_layout = AV_CH_LAYOUT_STEREO; + mode = AV_MATRIX_ENCODING_DOLBY; + break; + + case HB_AMIXDOWN_DOLBYPLII: + ff_layout = AV_CH_LAYOUT_STEREO; + mode = AV_MATRIX_ENCODING_DPLII; + break; + + case HB_AMIXDOWN_STEREO: + ff_layout = AV_CH_LAYOUT_STEREO; + break; + + case HB_AMIXDOWN_6CH: + ff_layout = AV_CH_LAYOUT_5POINT1; + break; + + default: + ff_layout = AV_CH_LAYOUT_STEREO; + hb_log("unrecognized channel layout"); + break; + } + if (downmix_mode != NULL) + *downmix_mode = mode; + return ff_layout; +} + uint64_t hb_ff_layout_xlat(uint64_t ff_channel_layout, int nchannels) { uint64_t hb_layout = ff_channel_layout; if (!hb_layout || av_get_channel_layout_nb_channels(hb_layout) != nchannels) { - switch (nchannels) + hb_layout = av_get_default_channel_layout(nchannels); + if (!hb_layout) { - // TODO: use av_get_default_channel_layout when available - case 1: - hb_layout = AV_CH_LAYOUT_MONO; - break; - case 2: - hb_layout = AV_CH_LAYOUT_STEREO; - break; - case 3: - hb_layout = AV_CH_LAYOUT_SURROUND; - break; - case 4: - hb_layout = AV_CH_LAYOUT_QUAD; - break; - case 5: - hb_layout = AV_CH_LAYOUT_5POINT0; - break; - case 6: - hb_layout = AV_CH_LAYOUT_5POINT1; - break; - case 7: - hb_layout = AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER; - break; - case 8: - hb_layout = AV_CH_LAYOUT_7POINT1; - break; - default: - // This will likely not sound very good ;) - hb_layout = AV_CH_LAYOUT_STEREO; - hb_error("hb_ff_layout_xlat: unsupported layout 0x%"PRIx64" with %d channels", - ff_channel_layout, nchannels); - break; + // This will likely not sound very good ;) + hb_layout = AV_CH_LAYOUT_STEREO; + hb_error("hb_ff_layout_xlat: unsupported layout 0x%"PRIx64" with %d channels", + ff_channel_layout, nchannels); } } return hb_layout; diff --git a/libhb/hbffmpeg.h b/libhb/hbffmpeg.h index e4cf63474..138094bc8 100644 --- a/libhb/hbffmpeg.h +++ b/libhb/hbffmpeg.h @@ -14,16 +14,20 @@ #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libswscale/swscale.h" +#include "libavresample/avresample.h" #define HB_FFMPEG_THREADS_AUTO (-1) // let hb_avcodec_open decide thread_count void hb_avcodec_init(void); -int hb_avcodec_open( AVCodecContext *, struct AVCodec *, AVDictionary **av_opts, int thread_count ); -int hb_avcodec_close( AVCodecContext * ); +int hb_avcodec_open(AVCodecContext *, AVCodec *, AVDictionary **av_opts, int thread_count); +int hb_avcodec_close(AVCodecContext *); + uint64_t hb_ff_layout_xlat(uint64_t ff_channel_layout, int nchannels); -struct SwsContext* hb_sws_get_context( int srcW, int srcH, - enum PixelFormat srcFormat, int dstW, int dstH, - enum PixelFormat dstFormat, int flags); -void hb_ff_set_sample_fmt(AVCodecContext *context, AVCodec *codec); -int hb_ff_dts_disable_xch( AVCodecContext *c ); -int hb_avpicture_fill( AVPicture *pic, hb_buffer_t *buf ); +uint64_t hb_ff_mixdown_xlat(int hb_mixdown, int *downmix_mode); +void hb_ff_set_sample_fmt(AVCodecContext *context, AVCodec *codec); + +struct SwsContext* +hb_sws_get_context(int srcW, int srcH, enum PixelFormat srcFormat, + int dstW, int dstH, enum PixelFormat dstFormat, + int flags); +int hb_avpicture_fill(AVPicture *pic, hb_buffer_t *buf); diff --git a/libhb/mcdeint.c b/libhb/mcdeint.c index 2ffb722f7..4c4c10cef 100644 --- a/libhb/mcdeint.c +++ b/libhb/mcdeint.c @@ -58,7 +58,6 @@ void mcdeint_init( mcdeint_private_t * pv, avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY; avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; avctx_enc->global_quality = 1; - avctx_enc->flags2 = CODEC_FLAG2_MEMC_ONLY; avctx_enc->me_cmp = FF_CMP_SAD; //SSE; avctx_enc->me_sub_cmp = FF_CMP_SAD; //SSE; avctx_enc->mb_cmp = FF_CMP_SSE; @@ -80,8 +79,7 @@ void mcdeint_init( mcdeint_private_t * pv, } pv->mcdeint_frame = avcodec_alloc_frame(); - pv->mcdeint_outbuf_size = width * height * 10; - pv->mcdeint_outbuf = malloc( pv->mcdeint_outbuf_size ); + av_new_packet( &pv->mcdeint_pkt, width * height * 10 ); } } @@ -96,10 +94,7 @@ void mcdeint_close( mcdeint_private_t * pv ) hb_avcodec_close( pv->mcdeint_avctx_enc ); av_freep( &pv->mcdeint_avctx_enc ); } - if( pv->mcdeint_outbuf ) - { - free( pv->mcdeint_outbuf ); - } + av_free_packet( &pv->mcdeint_pkt ); } } @@ -127,10 +122,10 @@ void mcdeint_filter( uint8_t ** dst, pv->mcdeint_avctx_enc->me_sub_cmp = FF_CMP_SAD; pv->mcdeint_frame->quality = pv->mcdeint_qp * FF_QP2LAMBDA; - avcodec_encode_video( pv->mcdeint_avctx_enc, - pv->mcdeint_outbuf, - pv->mcdeint_outbuf_size, - pv->mcdeint_frame ); + int got_packet; + + avcodec_encode_video2( pv->mcdeint_avctx_enc, + &pv->mcdeint_pkt, pv->mcdeint_frame, &got_packet ); pv->mcdeint_frame_dec = pv->mcdeint_avctx_enc->coded_frame; diff --git a/libhb/mcdeint.h b/libhb/mcdeint.h index 2c47e1ce6..35b5a76fc 100644 --- a/libhb/mcdeint.h +++ b/libhb/mcdeint.h @@ -12,8 +12,7 @@ struct mcdeint_private_s int mcdeint_mode; int mcdeint_qp; - int mcdeint_outbuf_size; - uint8_t * mcdeint_outbuf; + AVPacket mcdeint_pkt; AVCodecContext * mcdeint_avctx_enc; AVFrame * mcdeint_frame; AVFrame * mcdeint_frame_dec; diff --git a/libhb/module.defs b/libhb/module.defs index 3fefae82d..63acb9b9d 100644 --- a/libhb/module.defs +++ b/libhb/module.defs @@ -92,7 +92,7 @@ LIBHB.dll = $(LIBHB.build/)hb.dll LIBHB.lib = $(LIBHB.build/)hb.lib LIBHB.dll.libs = $(foreach n, \ - a52 ass avcodec avformat avutil dca dvdnav dvdread faac fontconfig freetype mkv mpeg2 mp3lame mp4v2 \ + a52 ass avcodec avformat avutil avresample dca dvdnav dvdread faac fontconfig freetype mkv mpeg2 mp3lame mp4v2 \ ogg samplerate swscale theora vorbis vorbisenc x264 xml2 bluray, \ $(CONTRIB.build/)lib/lib$(n).a ) diff --git a/libhb/platform/macosx/encca_aac.c b/libhb/platform/macosx/encca_aac.c index d67e039b2..7839ed930 100644 --- a/libhb/platform/macosx/encca_aac.c +++ b/libhb/platform/macosx/encca_aac.c @@ -8,7 +8,7 @@ */ #include "hb.h" -#include "downmix.h" +#include "audio_remap.h" #include <AudioToolbox/AudioToolbox.h> #include <CoreAudio/CoreAudio.h> @@ -49,8 +49,7 @@ struct hb_work_private_s uint64_t pts, ibytes; Float64 osamplerate; - uint64_t layout; - hb_chan_map_t *ichanmap; + int *remap_table; }; #define MP4ESDescrTag 0x03 @@ -289,22 +288,17 @@ int encCoreAudioInit(hb_work_object_t *w, hb_job_t *job, enum AAC_MODE mode) pv->osamplerate = output.mSampleRate; audio->config.out.samples_per_frame = pv->isamples; - // set channel map and layout (for remapping) - pv->ichanmap = audio->config.in.channel_map; - switch (audio->config.out.mixdown) + // channel remapping + if (pv->nchannels > 2 && audio->config.in.channel_map != &hb_aac_chan_map) { - case HB_AMIXDOWN_MONO: - pv->layout = AV_CH_LAYOUT_MONO; - break; - case HB_AMIXDOWN_STEREO: - case HB_AMIXDOWN_DOLBY: - case HB_AMIXDOWN_DOLBYPLII: - pv->layout = AV_CH_LAYOUT_STEREO; - break; - case HB_AMIXDOWN_6CH: - default: - pv->layout = AV_CH_LAYOUT_5POINT1; - break; + uint64_t layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL); + pv->remap_table = hb_audio_remap_build_table(layout, + audio->config.in.channel_map, + &hb_aac_chan_map); + } + else + { + pv->remap_table = NULL; } // get maximum output size @@ -350,6 +344,10 @@ void encCoreAudioClose(hb_work_object_t *w) { free(pv->buf); } + if (pv->remap_table != NULL) + { + free(pv->remap_table); + } hb_list_empty(&pv->list); free(pv); w->private_data = NULL; @@ -394,10 +392,11 @@ static OSStatus inInputDataProc(AudioConverterRef converter, UInt32 *npackets, *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz; pv->ibytes -= buffers->mBuffers[0].mDataByteSize; - if (pv->ichanmap != &hb_qt_chan_map) + if (pv->remap_table != NULL) { - hb_layout_remap(pv->ichanmap, &hb_qt_chan_map, pv->layout, - (float*)buffers->mBuffers[0].mData, *npackets); + hb_audio_remap(pv->nchannels, *npackets, + (hb_sample_t*)buffers->mBuffers[0].mData, + pv->remap_table); } return noErr; diff --git a/libhb/stream.c b/libhb/stream.c index 3e4a682e3..4c9cb347c 100644 --- a/libhb/stream.c +++ b/libhb/stream.c @@ -5085,13 +5085,13 @@ static int ffmpeg_open( hb_stream_t *stream, hb_title_t *title, int scan ) return 1; fail: - if ( info_ic ) av_close_input_file( info_ic ); + if ( info_ic ) avformat_close_input( &info_ic ); return 0; } static void ffmpeg_close( hb_stream_t *d ) { - av_close_input_file( d->ffmpeg_ic ); + avformat_close_input( &d->ffmpeg_ic ); if ( d->ffmpeg_pkt != NULL ) { free( d->ffmpeg_pkt ); @@ -5104,23 +5104,9 @@ static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id ) AVStream *st = stream->ffmpeg_ic->streams[id]; AVCodecContext *codec = st->codec; AVDictionaryEntry *tag; - int layout; - // DTS: work around lack of 6.0/6.1 support in libhb - if( hb_ff_dts_disable_xch( codec ) ) - { - hb_deep_log( 2, "add_ffmpeg_audio: found DTS-ES, requesting DTS core" ); - } - - // scan will ignore any audio without a bitrate. Since we've already - // typed the audio in order to determine its codec we set up the audio - // paramters here. - layout = hb_ff_layout_xlat( codec->channel_layout, codec->channels ); - if ( !layout ) - { - // Unsupported layout - return; - } + // scan will ignore any audio without a bitrate. Since we've already typed the + // audio in order to determine its codec we set up the audio parameters here. if ( codec->bit_rate || codec->sample_rate ) { hb_audio_t *audio = calloc( 1, sizeof(*audio) );; @@ -5173,8 +5159,9 @@ static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id ) audio->config.in.bitrate = 1; audio->config.in.samplerate = codec->sample_rate; audio->config.in.samples_per_frame = codec->frame_size; - audio->config.in.channel_layout = layout; - audio->config.in.channel_map = &hb_smpte_chan_map; + audio->config.in.channel_map = &hb_libav_chan_map; + audio->config.in.channel_layout = hb_ff_layout_xlat(codec->channel_layout, + codec->channels); } tag = av_dict_get( st->metadata, "language", NULL, 0 ); diff --git a/libhb/sync.c b/libhb/sync.c index 181d0acb3..fc01c3b12 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -922,7 +922,6 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) gap */ AVCodec * codec; AVCodecContext * c; - short * zeros; switch ( w->audio->config.out.codec ) { @@ -966,8 +965,18 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) return; } - int input_size = c->frame_size * av_get_bytes_per_sample( c->sample_fmt ) * c->channels; + // Prepare input frame + AVFrame frame; + uint8_t * zeros; + + frame.nb_samples= c->frame_size; + int input_size = av_samples_get_buffer_size(NULL, c->channels, + frame.nb_samples, c->sample_fmt, 1); zeros = calloc( 1, input_size ); + avcodec_fill_audio_frame(&frame, c->channels, + c->sample_fmt, zeros, input_size, 1); + frame.pts = 0; + // Allocate enough space for the encoded silence // The output should be < the input sync->silence_buf = malloc( input_size ); @@ -977,19 +986,26 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) int ii; for ( ii = 0; ii < 10; ii++ ) { - sync->silence_size = avcodec_encode_audio( c, sync->silence_buf, - input_size, zeros ); + // Prepare output packet + AVPacket pkt; + int got_packet; + av_init_packet(&pkt); + pkt.data = zeros; + pkt.size = input_size; + + int ret = avcodec_encode_audio2( c, &pkt, &frame, &got_packet); + if ( ret < 0 ) + { + hb_log( "sync: avcodec_encode_audio failed" ); + break; + } - if (sync->silence_size) + if ( got_packet ) { + sync->silence_size = pkt.size; break; } } - if (!sync->silence_size) - { - hb_log( "sync: avcodec_encode_audio failed" ); - } - free( zeros ); hb_avcodec_close( c ); av_free( c ); diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index 073b9448b..a15584b30 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -96,6 +96,8 @@ 27D6C74614B102DA00B785E4 /* libavcodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72914B102DA00B785E4 /* libavcodec.a */; }; 27D6C74714B102DA00B785E4 /* libavformat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72A14B102DA00B785E4 /* libavformat.a */; }; 27D6C74814B102DA00B785E4 /* libavformat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72A14B102DA00B785E4 /* libavformat.a */; }; + 226268E01572CC7300477B4E /* libavresample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 226268DF1572CC7300477B4E /* libavresample.a */; }; + 226268E11572CC7300477B4E /* libavresample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 226268DF1572CC7300477B4E /* libavresample.a */; }; 27D6C74914B102DA00B785E4 /* libavutil.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72B14B102DA00B785E4 /* libavutil.a */; }; 27D6C74A14B102DA00B785E4 /* libavutil.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72B14B102DA00B785E4 /* libavutil.a */; }; 27D6C74B14B102DA00B785E4 /* libbluray.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72C14B102DA00B785E4 /* libbluray.a */; }; @@ -288,6 +290,7 @@ 27D6C72814B102DA00B785E4 /* libass.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libass.a; path = external/contrib/lib/libass.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C72914B102DA00B785E4 /* libavcodec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavcodec.a; path = external/contrib/lib/libavcodec.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C72A14B102DA00B785E4 /* libavformat.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavformat.a; path = external/contrib/lib/libavformat.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 226268DF1572CC7300477B4E /* libavresample.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavresample.a; path = external/contrib/lib/libavresample.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C72B14B102DA00B785E4 /* libavutil.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavutil.a; path = external/contrib/lib/libavutil.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C72C14B102DA00B785E4 /* libbluray.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbluray.a; path = external/contrib/lib/libbluray.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C72D14B102DA00B785E4 /* libdca.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdca.a; path = external/contrib/lib/libdca.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -328,6 +331,7 @@ 27D6C74414B102DA00B785E4 /* libass.a in Frameworks */, 27D6C74614B102DA00B785E4 /* libavcodec.a in Frameworks */, 27D6C74814B102DA00B785E4 /* libavformat.a in Frameworks */, + 226268E11572CC7300477B4E /* libavresample.a in Frameworks */, 27D6C74A14B102DA00B785E4 /* libavutil.a in Frameworks */, 27D6C74C14B102DA00B785E4 /* libbluray.a in Frameworks */, 27D6C74E14B102DA00B785E4 /* libdca.a in Frameworks */, @@ -370,6 +374,7 @@ 27D6C74314B102DA00B785E4 /* libass.a in Frameworks */, 27D6C74514B102DA00B785E4 /* libavcodec.a in Frameworks */, 27D6C74714B102DA00B785E4 /* libavformat.a in Frameworks */, + 226268E01572CC7300477B4E /* libavresample.a in Frameworks */, 27D6C74914B102DA00B785E4 /* libavutil.a in Frameworks */, 27D6C74B14B102DA00B785E4 /* libbluray.a in Frameworks */, 27D6C74D14B102DA00B785E4 /* libdca.a in Frameworks */, @@ -405,6 +410,7 @@ 27D6C72814B102DA00B785E4 /* libass.a */, 27D6C72914B102DA00B785E4 /* libavcodec.a */, 27D6C72A14B102DA00B785E4 /* libavformat.a */, + 226268DF1572CC7300477B4E /* libavresample.a */, 27D6C72B14B102DA00B785E4 /* libavutil.a */, 27D6C72C14B102DA00B785E4 /* libbluray.a */, 27D6C72D14B102DA00B785E4 /* libdca.a */, diff --git a/test/module.defs b/test/module.defs index 5030e6f29..45f6fea82 100644 --- a/test/module.defs +++ b/test/module.defs @@ -10,7 +10,7 @@ TEST.c.o = $(patsubst $(SRC/)%.c,$(BUILD/)%.o,$(TEST.c)) TEST.exe = $(BUILD/)$(call TARGET.exe,$(HB.name)CLI) TEST.libs = $(LIBHB.a) $(foreach n, \ - a52 ass avcodec avformat avutil dca dvdnav dvdread faac fontconfig freetype mkv mpeg2 mp3lame mp4v2 \ + a52 ass avcodec avformat avutil avresample dca dvdnav dvdread faac fontconfig freetype mkv mpeg2 mp3lame mp4v2 \ ogg samplerate swscale theora vorbis vorbisenc x264 xml2 bluray, \ $(CONTRIB.build/)lib/lib$(n).a ) |