From a6653a9bb6c35e01dc44365b51f816198656acf7 Mon Sep 17 00:00:00 2001 From: Andree Buschmann Date: Sat, 10 Dec 2011 22:28:16 +0000 Subject: 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 --- apps/codecs/flac.c | 22 ++++++++-- apps/codecs/libffmpegFLAC/decoder.c | 80 +++++++++---------------------------- apps/codecs/libffmpegFLAC/decoder.h | 8 ++-- manual/appendix/file_formats.tex | 2 +- 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; chdecoded[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; chchannels; ++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} & \\ -- cgit v1.2.3