summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndree Buschmann <AndreeBuschmann@t-online.de>2011-12-10 22:28:16 +0000
committerAndree Buschmann <AndreeBuschmann@t-online.de>2011-12-10 22:28:16 +0000
commita6653a9bb6c35e01dc44365b51f816198656acf7 (patch)
tree4a271828aa91694403a4e3688b9106b062084dcd
parent09722dd28db02bf7cb34d1a7d42729ce66ebe302 (diff)
Fix decoding of multichannel flac, refactor sample buffer handling and decorrelation (taken from ffmpeg sources) and add some flac details to the manual. Solves FS#12371.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31207 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs/flac.c22
-rw-r--r--apps/codecs/libffmpegFLAC/decoder.c80
-rw-r--r--apps/codecs/libffmpegFLAC/decoder.h8
-rw-r--r--manual/appendix/file_formats.tex2
4 files changed, 42 insertions, 70 deletions
diff --git a/apps/codecs/flac.c b/apps/codecs/flac.c
index c91a173f4a..72bb26663a 100644
--- a/apps/codecs/flac.c
+++ b/apps/codecs/flac.c
@@ -27,6 +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];
#define MAX_SUPPORTED_SEEKTABLE_SIZE 5000
@@ -80,11 +81,26 @@ static bool flac_init(FLACContext* fc, int first_frame_offset)
uint16_t blocksize;
int endofmetadata=0;
uint32_t blocklength;
+ int ch;
ci->memset(fc,0,sizeof(FLACContext));
nseekpoints=0;
fc->sample_skip = 0;
+
+ /* Reset sample buffers */
+ memset(decoded0, 0, sizeof(decoded0));
+ memset(decoded1, 0, sizeof(decoded1));
+ memset(dummydec, 0, sizeof(dummydec));
+
+ /* Set sample buffers in decoder structure */
+ fc->decoded[0] = decoded0;
+ fc->decoded[1] = decoded1;
+ for (ch=2; ch<MAX_CHANNELS; ++ch)
+ {
+ /* Only channel 0 and 1 are used, the other are decoded to scratch */
+ fc->decoded[ch] = dummydec;
+ }
/* Skip any foreign tags at start of file */
ci->seek_buffer(first_frame_offset);
@@ -231,7 +247,7 @@ static bool frame_sync(FLACContext* fc) {
/* Decode the frame to verify the frame crc and
* fill fc with its metadata.
*/
- if(flac_decode_frame(fc, decoded0, decoded1,
+ if(flac_decode_frame(fc,
bit_buffer, buff_size, ci->yield) < 0) {
return false;
}
@@ -485,7 +501,7 @@ enum codec_status codec_run(void)
ci->seek_complete();
}
- if((res=flac_decode_frame(&fc,decoded0,decoded1,buf,
+ if((res=flac_decode_frame(&fc,buf,
bytesleft,ci->yield)) < 0) {
LOGF("FLAC: Frame %d, error %d\n",frame,res);
return CODEC_ERROR;
@@ -494,7 +510,7 @@ enum codec_status codec_run(void)
frame++;
ci->yield();
- ci->pcmbuf_insert(&decoded0[fc.sample_skip], &decoded1[fc.sample_skip],
+ ci->pcmbuf_insert(&fc.decoded[0][fc.sample_skip], &fc.decoded[1][fc.sample_skip],
fc.blocksize - fc.sample_skip);
fc.sample_skip = 0;
diff --git a/apps/codecs/libffmpegFLAC/decoder.c b/apps/codecs/libffmpegFLAC/decoder.c
index 1fafec17fb..2dbedf3110 100644
--- a/apps/codecs/libffmpegFLAC/decoder.c
+++ b/apps/codecs/libffmpegFLAC/decoder.c
@@ -381,17 +381,13 @@ static inline int decode_subframe(FLACContext *s, int channel, int32_t* decoded)
}
static int decode_frame(FLACContext *s,
- int32_t* decoded0,
- int32_t* decoded1,
void (*yield)(void)) ICODE_ATTR_FLAC;
static int decode_frame(FLACContext *s,
- int32_t* decoded0,
- int32_t* decoded1,
void (*yield)(void))
{
int blocksize_code, sample_rate_code, sample_size_code, assignment, crc8;
int decorrelation, bps, blocksize, samplerate;
- int res;
+ int res, ch;
blocksize_code = get_bits(&s->gb, 4);
@@ -477,16 +473,10 @@ static int decode_frame(FLACContext *s,
s->bps = bps;
s->decorrelation= decorrelation;
- yield();
- /* subframes */
- if ((res=decode_subframe(s, 0, decoded0)) < 0)
- return res-100;
-
- yield();
-
- if (s->channels==2) {
- if ((res=decode_subframe(s, 1, decoded1)) < 0)
- return res-200;
+ for (ch=0; ch<s->channels; ++ch) {
+ yield();
+ if ((res=decode_subframe(s, ch, s->decoded[ch])) < 0)
+ return res-100;
}
yield();
@@ -499,8 +489,6 @@ static int decode_frame(FLACContext *s,
}
int flac_decode_frame(FLACContext *s,
- int32_t* decoded0,
- int32_t* decoded1,
uint8_t *buf, int buf_size,
void (*yield)(void))
{
@@ -516,68 +504,36 @@ int flac_decode_frame(FLACContext *s,
return -41;
}
- if ((framesize=decode_frame(s,decoded0,decoded1,yield)) < 0){
+ if ((framesize=decode_frame(s,yield)) < 0){
s->bitstream_size=0;
s->bitstream_index=0;
return framesize;
}
yield();
+
+#define DECORRELATE(left, right)\
+ for (i = 0; i < s->blocksize; i++) {\
+ int a = s->decoded[0][i];\
+ int b = s->decoded[1][i];\
+ s->decoded[0][i] = (left) << scale;\
+ s->decoded[1][i] = (right) << scale;\
+ }\
scale=FLAC_OUTPUT_DEPTH-s->bps;
switch(s->decorrelation)
{
case INDEPENDENT:
- if (s->channels==1) {;
- for (i = 0; i < s->blocksize; i++)
- {
- decoded0[i] = decoded0[i] << scale;
- }
- } else {
- for (i = 0; i < s->blocksize; i++)
- {
- decoded0[i] = decoded0[i] << scale;
- decoded1[i] = decoded1[i] << scale;
- }
- }
+ DECORRELATE(a, b) /* Always decorrelate exactly the two supported channels. */
break;
case LEFT_SIDE:
- //assert(s->channels == 2);
- for (i = 0; i < s->blocksize; i++)
- {
- decoded1[i] = (decoded0[i] - decoded1[i]) << scale;
- decoded0[i] = decoded0[i] << scale;
- }
+ DECORRELATE(a, a-b)
break;
case RIGHT_SIDE:
- //assert(s->channels == 2);
- for (i = 0; i < s->blocksize; i++)
- {
- decoded0[i] = (decoded0[i] + decoded1[i]) << scale;
- decoded1[i] = decoded1[i] << scale;
- }
+ DECORRELATE(a+b, a)
break;
case MID_SIDE:
- //assert(s->channels == 2);
- for (i = 0; i < s->blocksize; i++)
- {
- int mid, side;
- mid = decoded0[i];
- side = decoded1[i];
-
-#if 1 //needs to be checked but IMHO it should be binary identical
- mid -= side>>1;
- decoded0[i] = (mid + side) << scale;
- decoded1[i] = mid << scale;
-#else
-
- mid <<= 1;
- if (side & 1)
- mid++;
- decoded0[i] = ((mid + side) >> 1) << scale;
- decoded1[i] = ((mid - side) >> 1) << scale;
-#endif
- }
+ DECORRELATE( (a-=b>>1) + b, a)
break;
}
diff --git a/apps/codecs/libffmpegFLAC/decoder.h b/apps/codecs/libffmpegFLAC/decoder.h
index 0b148df916..677a21ac98 100644
--- a/apps/codecs/libffmpegFLAC/decoder.h
+++ b/apps/codecs/libffmpegFLAC/decoder.h
@@ -3,9 +3,9 @@
#include "bitstream.h"
-#define MAX_CHANNELS 2 /* Maximum supported channels */
+#define MAX_CHANNELS 6 /* Maximum supported channels, only left/right will be played back */
#define MAX_BLOCKSIZE 4608 /* Maxsize in samples of one uncompressed frame */
-#define MAX_FRAMESIZE 32768 /* Maxsize in bytes of one compressed frame */
+#define MAX_FRAMESIZE 65536 /* Maxsize in bytes of one compressed frame */
#define FLAC_OUTPUT_DEPTH 29 /* Provide samples left-shifted to 28 bits+sign */
@@ -38,11 +38,11 @@ typedef struct FLACContext {
int sample_skip;
int framesize;
+
+ int32_t *decoded[MAX_CHANNELS];
} FLACContext;
int flac_decode_frame(FLACContext *s,
- int32_t* decoded0,
- int32_t* decoded1,
uint8_t *buf, int buf_size,
void (*yield)(void)) ICODE_ATTR_FLAC;
diff --git a/manual/appendix/file_formats.tex b/manual/appendix/file_formats.tex
index 3c361f7996..f9f2e0a020 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).\\
Apple Lossless
& \fname{.m4a}, \fname{.mp4}
& \\