From 5b8ed62922fce346dc1c92db264e7ceff8c4796e Mon Sep 17 00:00:00 2001 From: Andree Buschmann Date: Wed, 14 Dec 2011 18:02:57 +0000 Subject: FS#12443: Implement downmixing to stereo for multichannel flac. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31253 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/flac.c | 5 +- apps/codecs/libffmpegFLAC/decoder.c | 93 +++++++++++++++++++++++++++++++++++-- manual/appendix/file_formats.tex | 5 +- 3 files changed, 94 insertions(+), 9 deletions(-) diff --git a/apps/codecs/flac.c b/apps/codecs/flac.c index 72bb26663a..b9f6654f92 100644 --- a/apps/codecs/flac.c +++ b/apps/codecs/flac.c @@ -27,7 +27,7 @@ CODEC_HEADER /* The output buffers containing the decoded samples (channels 0 and 1) */ static int32_t decoded0[MAX_BLOCKSIZE] IBSS_ATTR_FLAC_DECODED0; static int32_t decoded1[MAX_BLOCKSIZE] IBSS_ATTR; -static int32_t dummydec[MAX_BLOCKSIZE]; +static int32_t dummydec[4][MAX_BLOCKSIZE]; #define MAX_SUPPORTED_SEEKTABLE_SIZE 5000 @@ -98,8 +98,7 @@ static bool flac_init(FLACContext* fc, int first_frame_offset) fc->decoded[1] = decoded1; for (ch=2; chdecoded[ch] = dummydec; + fc->decoded[ch] = dummydec[ch-2]; } /* Skip any foreign tags at start of file */ diff --git a/apps/codecs/libffmpegFLAC/decoder.c b/apps/codecs/libffmpegFLAC/decoder.c index ec96307383..1be5fbb6ef 100644 --- a/apps/codecs/libffmpegFLAC/decoder.c +++ b/apps/codecs/libffmpegFLAC/decoder.c @@ -488,9 +488,87 @@ static int decode_frame(FLACContext *s, return 0; } +static int flac_downmix(FLACContext *s) +{ + int32_t *FL, *FR, *FC, *SB, *RL, *RR; + int32_t *outL = s->decoded[0]; + int32_t *outR = s->decoded[1]; + int i, scale=FLAC_OUTPUT_DEPTH-s->bps; + + switch(s->channels) + { + case 3: /* 3.0 channel order: FL FR FC */ + FL = s->decoded[0]; + FR = s->decoded[1]; + FC = s->decoded[2]; + /* LF = 0.66 LF + 0.33 FC + LR = 0.66 LR + 0.33 FC */ + for (i=0; iblocksize; ++i) { + int32_t a = *(FL)*2 + *(FC); + int32_t b = *(FR)*2 + *(FC); + *outL++ = ((a + (a<<2))>>4) << scale; /* 1/3 ~= 5>>4 */ + *outR++ = ((b + (b<<2))>>4) << scale; /* 1/3 ~= 5>>4 */ + FL++; FR++; FC++; + } + break; + case 4: /* 4.0 channel order: FL FR RL RR */ + FL = s->decoded[0]; + FR = s->decoded[1]; + RL = s->decoded[2]; + RR = s->decoded[3]; + /* LF = 0.50 LF + 0.50 RL + 0.00 RR + LR = 0.50 LR + 0.00 RL + 0.50 RR */ + for (i=0; iblocksize; ++i) { + int32_t a = *(FL) + *(RL); + int32_t b = *(FR) + *(RR); + *outL++ = (a>>1) << scale; + *outR++ = (b>>1) << scale; + FL++; FR++; RL++; RR++; + } + break; + case 5: /* 5.0 channel order: FL FR FC RL RR */ + FL = s->decoded[0]; + FR = s->decoded[1]; + FC = s->decoded[2]; + RL = s->decoded[3]; + RR = s->decoded[4]; + /* LF = 0.40 LF + 0.20 FC + 0.40 RL + 0.00 RR + LR = 0.40 LR + 0.20 FC + 0.00 RL + 0.40 RR */ + for (i=0; iblocksize; ++i) { + int32_t a = *(FL)*2 + *(FC) + *(RL)*2; + int32_t b = *(FR)*2 + *(FC) + *(RR)*2; + *outL++ = ((a + (a<<1))>>4) << scale; /* 3>>4 ~= 1/5 */ + *outR++ = ((b + (b<<1))>>4) << scale; /* 3>>4 ~= 1/5 */ + FL++; FR++; FC++; RL++; RR++; + } + break; + case 6: /* 5.1 channel order: FL FR FC SUB RL RR */ + FL = s->decoded[0]; + FR = s->decoded[1]; + FC = s->decoded[2]; + SB = s->decoded[3]; + RL = s->decoded[4]; + RR = s->decoded[5]; + /* LF = 0.33 LF + 0.16 SUB + 0.16 FC + 0.33 RL + 0.00 RR + LR = 0.33 LR + 0.16 SUB + 0.16 FC + 0.00 RL + 0.33 RR */ + for (i=0; iblocksize; ++i) { + int32_t a = *(FL)*2 + *(SB) + *(FC) + *(RL)*2; + int32_t b = *(FR)*2 + *(SB) + *(FC) + *(RR)*2; + *outL++ = ((a + (a<<2))>>5) << scale; /* 5>>5 ~= 1/6 */ + *outR++ = ((b + (b<<2))>>5) << scale; /* 5>>5 ~= 1/6 */ + FL++; FR++; SB++; FC++; RL++; RR++; + } + break; + default: /* 1.0 and 2.0 do not need downmix, other formats unknown. */ + return -501; + break; + } + return 0; +} + int flac_decode_frame(FLACContext *s, - uint8_t *buf, int buf_size, - void (*yield)(void)) + uint8_t *buf, int buf_size, + void (*yield)(void)) { int tmp; int i; @@ -514,8 +592,8 @@ int flac_decode_frame(FLACContext *s, #define DECORRELATE(left, right)\ for (i = 0; i < s->blocksize; i++) {\ - int a = s->decoded[0][i];\ - int b = s->decoded[1][i];\ + int32_t a = s->decoded[0][i];\ + int32_t b = s->decoded[1][i];\ s->decoded[0][i] = (left) << scale;\ s->decoded[1][i] = (right) << scale;\ }\ @@ -524,7 +602,12 @@ int flac_decode_frame(FLACContext *s, switch(s->decorrelation) { case INDEPENDENT: - DECORRELATE(a, b) /* Always decorrelate exactly the two supported channels. */ + if (s->channels <= 2) { + DECORRELATE(a, b) /* Always decorrelate exactly the two supported channels. */ + } else { + if ((tmp=flac_downmix(s)) != 0) + return tmp; + } break; case LEFT_SIDE: DECORRELATE(a, a-b) diff --git a/manual/appendix/file_formats.tex b/manual/appendix/file_formats.tex index f9f2e0a020..a086c5d2f7 100644 --- a/manual/appendix/file_formats.tex +++ b/manual/appendix/file_formats.tex @@ -176,7 +176,7 @@ & Linear PCM 8/16/24/32 bit, IEEE float 32/64 bit, ITU-T G.711 a-law/$\mu$-law\\ Free Lossless Audio & \fname{.flac} - & Supports multichannel tracks w/o downmixing (only left/right is played).\\ + & Supports multichannel playback including downmixing to stereo.\\ Apple Lossless & \fname{.m4a}, \fname{.mp4} & \\ @@ -198,6 +198,9 @@ & \fname{.wv} & \\ \end{rbtabular} + + \note{Free Lossless Audio multichannel tracks may not play in realtime on all devices due to CPU + performance requirements.} \subsection{Other Codecs} \begin{rbtabular}{\textwidth}{l>{\raggedright}p{6em}X}% -- cgit v1.2.3