From debbe9747eb6eecfd79aab648212b55220922eb6 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Thu, 22 Sep 2005 20:46:58 +0000 Subject: First Rockbox version of ALAC decoder - porting to work in Rockbox environment and some simple (but significant) optimisations git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7544 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/libalac/Makefile | 47 +++++ apps/codecs/libalac/README.rockbox | 80 +++++++++ apps/codecs/libalac/SOURCES | 2 + apps/codecs/libalac/alac.c | 345 ++++++++++++++++++++++--------------- apps/codecs/libalac/decomp.h | 30 +++- apps/codecs/libalac/demux.c | 85 +++++---- apps/codecs/libalac/demux.h | 2 +- apps/codecs/libalac/stream.h | 11 +- 8 files changed, 405 insertions(+), 197 deletions(-) create mode 100644 apps/codecs/libalac/Makefile create mode 100644 apps/codecs/libalac/README.rockbox create mode 100644 apps/codecs/libalac/SOURCES (limited to 'apps') diff --git a/apps/codecs/libalac/Makefile b/apps/codecs/libalac/Makefile new file mode 100644 index 0000000000..b815db54b7 --- /dev/null +++ b/apps/codecs/libalac/Makefile @@ -0,0 +1,47 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +INCLUDES=-I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \ + -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(BUILDDIR) + +ifdef APPEXTRA +INCLUDES += -I$(APPSDIR)/$(APPEXTRA) +endif + +ALACOPTS = -O3 +CFLAGS = $(GCCOPTS) $(ALACOPTS) $(INCLUDES) $(TARGET) $(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} + +# This sets up 'SRC' based on the files mentioned in SOURCES +include $(TOOLSDIR)/makesrc.inc + +SOURCES = $(SRC) +OBJS2 := $(SRC:%.c=$(OBJDIR)/%.o) +OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2)) +DEPFILE = $(OBJDIR)/dep-libalac +DIRS = + +OUTPUT = $(BUILDDIR)/libalac.a + +all: $(OUTPUT) + +$(OUTPUT): $(OBJS) + @echo "AR $@" + @$(AR) ruv $@ $+ >/dev/null 2>&1 + +$(OBJDIR)/libalac/%.o: $(APPSDIR)/codecs/libalac/%.c + @echo "(libalac) CC $<" + @$(CC) -c $(CFLAGS) -I$(APPSDIR)/codecs/libalac/ $< -o $@ + +include $(TOOLSDIR)/make.inc + +clean: + @echo "cleaning libalac" + @rm -f $(OBJS) $(OUTPUT) $(DEPFILE) + +-include $(DEPFILE) diff --git a/apps/codecs/libalac/README.rockbox b/apps/codecs/libalac/README.rockbox new file mode 100644 index 0000000000..891e581cfc --- /dev/null +++ b/apps/codecs/libalac/README.rockbox @@ -0,0 +1,80 @@ +Library: Reverse-engineered ALAC decoder v0.1.0 +Imported: 2005-08-14 by Dave Chapman + + +This directory contains a local version of an ALAC (Apple Lossless Audio +Codec) for use by Rockbox for software decoding of ALAC files. It is +based on the reverse-engineered decoder by David Hamilton. + +LICENSING INFORMATION + +/* + * ALAC (Apple Lossless Audio Codec) decoder + * Copyright (c) 2005 David Hammerton + * All rights reserved. + * + * This is the actual decoder. + * + * http://crazney.net/programs/itunes/alac.html + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +IMPORT DETAILS + +The base version first imported into Rockbox was the first release +(v0.1.0) of the ALAC decoder by David Hammerton. + +Only the files alac.[ch], demux.[ch] and stream.h were used. + +stream.c (the original FILE* based I/O implementation) was replaced with +functions in the ALAC codec - to interface with the Rockbox audio playback +system. + +References to were replaced with and debugging +calls to fprintf were removed. + +The ALAC decoder itself was modified to return samples in host-endian +order, instead of little-endian. + +The run-time detection of CPU endianness was replaced with +compile-time tests of the ROCKBOX_LITTLE_ENDIAN define. + +All malloc calls were removed from alac.c, but some are still present +in the metadata parser in demux.c - to store unbounded data such as +the size in bytes of each compressed block in the file. + +The only changes to demux.c were to remove debugging calls to fprintf. + +The most-used buffers (the temporary 32-bit output buffer) were moved +into IRAM (on the iRiver). This was enough to make the decoder work +in real-time. + +A point of interest - the -O3 gcc option (the setting used in the +original Makefile provided with the alac decoder) gives a significant +speedup compared to -O2. With -O2, the Coldfire runs at a constant +120MHz, but with -O3, it can power-down to 40MHz for a small amount of +time. + +The file alac.c contained some hints from the original author for +places where major optimisations can be made - specifically the +unrolling and optimisation of certain cases of general loops. diff --git a/apps/codecs/libalac/SOURCES b/apps/codecs/libalac/SOURCES new file mode 100644 index 0000000000..0c4615619f --- /dev/null +++ b/apps/codecs/libalac/SOURCES @@ -0,0 +1,2 @@ +alac.c +demux.c diff --git a/apps/codecs/libalac/alac.c b/apps/codecs/libalac/alac.c index 575bbf5abc..ae1b413eab 100644 --- a/apps/codecs/libalac/alac.c +++ b/apps/codecs/libalac/alac.c @@ -33,8 +33,9 @@ #include #include #include -#include +#include +#include "../codec.h" #include "decomp.h" #define _Swap32(v) do { \ @@ -47,53 +48,13 @@ v = (((v) & 0x00FF) << 0x08) | \ (((v) & 0xFF00) >> 0x08); } while (0) - -extern int host_bigendian; - -struct alac_file -{ - unsigned char *input_buffer; - int input_buffer_bitaccumulator; /* used so we can do arbitary - bit reads */ - - int samplesize; - int numchannels; - int bytespersample; - - - /* buffers */ - int32_t *predicterror_buffer_a; - int32_t *predicterror_buffer_b; - - int32_t *outputsamples_buffer_a; - int32_t *outputsamples_buffer_b; - - - /* stuff from setinfo */ - uint32_t setinfo_max_samples_per_frame; /* 0x1000 = 4096 */ /* max samples per frame? */ - uint8_t setinfo_7a; /* 0x00 */ - uint8_t setinfo_sample_size; /* 0x10 */ - uint8_t setinfo_rice_historymult; /* 0x28 */ - uint8_t setinfo_rice_initialhistory; /* 0x0a */ - uint8_t setinfo_rice_kmodifier; /* 0x0e */ - uint8_t setinfo_7f; /* 0x02 */ - uint16_t setinfo_80; /* 0x00ff */ - uint32_t setinfo_82; /* 0x000020e7 */ - uint32_t setinfo_86; /* 0x00069fe4 */ - uint32_t setinfo_8a_rate; /* 0x0000ac44 */ - /* end setinfo stuff */ - -}; - - -static void allocate_buffers(alac_file *alac) -{ - alac->predicterror_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4); - alac->predicterror_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4); - - alac->outputsamples_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4); - alac->outputsamples_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4); -} +int16_t predictor_coef_table[32] IDATA_ATTR; +int16_t predictor_coef_table_a[32] IDATA_ATTR; +int16_t predictor_coef_table_b[32] IDATA_ATTR; +int32_t predicterror_buffer_a[4096]; +int32_t predicterror_buffer_b[4096]; +int32_t outputsamples_buffer_a[4096] IDATA_ATTR; +int32_t outputsamples_buffer_b[4096] IDATA_ATTR; void alac_set_info(alac_file *alac, char *inputbuffer) { @@ -107,8 +68,9 @@ void alac_set_info(alac_file *alac, char *inputbuffer) ptr += 4; /* 0 ? */ alac->setinfo_max_samples_per_frame = *(uint32_t*)ptr; /* buffer size / 2 ? */ - if (!host_bigendian) - _Swap32(alac->setinfo_max_samples_per_frame); +#ifdef ROCKBOX_LITTLE_ENDIAN + _Swap32(alac->setinfo_max_samples_per_frame); +#endif ptr += 4; alac->setinfo_7a = *(uint8_t*)ptr; ptr += 1; @@ -123,24 +85,25 @@ void alac_set_info(alac_file *alac, char *inputbuffer) alac->setinfo_7f = *(uint8_t*)ptr; ptr += 1; alac->setinfo_80 = *(uint16_t*)ptr; - if (!host_bigendian) - _Swap16(alac->setinfo_80); +#ifdef ROCKBOX_LITTLE_ENDIAN + _Swap16(alac->setinfo_80); +#endif ptr += 2; alac->setinfo_82 = *(uint32_t*)ptr; - if (!host_bigendian) - _Swap32(alac->setinfo_82); +#ifdef ROCKBOX_LITTLE_ENDIAN + _Swap32(alac->setinfo_82); +#endif ptr += 4; alac->setinfo_86 = *(uint32_t*)ptr; - if (!host_bigendian) - _Swap32(alac->setinfo_86); +#ifdef ROCKBOX_LITTLE_ENDIAN + _Swap32(alac->setinfo_86); +#endif ptr += 4; alac->setinfo_8a_rate = *(uint32_t*)ptr; - if (!host_bigendian) - _Swap32(alac->setinfo_8a_rate); +#ifdef ROCKBOX_LITTLE_ENDIAN + _Swap32(alac->setinfo_8a_rate); +#endif ptr += 4; - - allocate_buffers(alac); - } /* stream reading */ @@ -432,23 +395,150 @@ static void predictor_decompress_fir_adapt(int32_t *error_buffer, } } -#if 0 - /* 4 and 8 are very common cases (the only ones i've seen). these - * should be unrolled and optimised + /* 4 and 8 are very common cases (the only ones i've seen). + + The following code is an initial attempt to unroll and optimise + these two cases by the Rockbox project. More work is needed. */ + + /* optimised case: 4 */ if (predictor_coef_num == 4) { - /* FIXME: optimised general case */ + for (i = 4 + 1; i < output_size; i++) + { + int sum = 0; + int outval; + int error_val = error_buffer[i]; + + sum = (buffer_out[4] - buffer_out[0]) * predictor_coef_table[0] + + (buffer_out[3] - buffer_out[0]) * predictor_coef_table[1] + + (buffer_out[2] - buffer_out[0]) * predictor_coef_table[2] + + (buffer_out[1] - buffer_out[0]) * predictor_coef_table[3]; + + outval = (1 << (predictor_quantitization-1)) + sum; + outval = outval >> predictor_quantitization; + outval = outval + buffer_out[0] + error_val; + outval = SIGN_EXTENDED32(outval, readsamplesize); + + buffer_out[4+1] = outval; + + if (error_val > 0) + { + int predictor_num = 4 - 1; + + while (predictor_num >= 0 && error_val > 0) + { + int val = buffer_out[0] - buffer_out[4 - predictor_num]; + + if (val!=0) { + if (val < 0) { + predictor_coef_table[predictor_num]++; + val=-val; + } else { + predictor_coef_table[predictor_num]--;; + } + error_val -= ((val >> predictor_quantitization) * (4 - predictor_num)); + } + predictor_num--; + } + } + else if (error_val < 0) + { + int predictor_num = 4 - 1; + + while (predictor_num >= 0 && error_val < 0) + { + int val = buffer_out[0] - buffer_out[4 - predictor_num]; + + if (val != 0) { + if (val > 0) { + predictor_coef_table[predictor_num]++; + val=-val; /* neg value */ + } else { + predictor_coef_table[predictor_num]--; + } + error_val -= ((val >> predictor_quantitization) * (4 - predictor_num)); + } + predictor_num--; + } + } + + buffer_out++; + } return; } - if (predictor_coef_table == 8) + /* optimised case: 8 */ + if (predictor_coef_num == 8) { - /* FIXME: optimised general case */ - return; - } -#endif + for (i = 8 + 1; + i < output_size; + i++) + { + int sum; + int outval; + int error_val = error_buffer[i]; + + sum = (buffer_out[8] - buffer_out[0]) * predictor_coef_table[0] + + (buffer_out[7] - buffer_out[0]) * predictor_coef_table[1] + + (buffer_out[6] - buffer_out[0]) * predictor_coef_table[2] + + (buffer_out[5] - buffer_out[0]) * predictor_coef_table[3] + + (buffer_out[4] - buffer_out[0]) * predictor_coef_table[4] + + (buffer_out[3] - buffer_out[0]) * predictor_coef_table[5] + + (buffer_out[2] - buffer_out[0]) * predictor_coef_table[6] + + (buffer_out[1] - buffer_out[0]) * predictor_coef_table[7]; + + outval = (1 << (predictor_quantitization-1)) + sum; + outval = outval >> predictor_quantitization; + outval = outval + buffer_out[0] + error_val; + outval = SIGN_EXTENDED32(outval, readsamplesize); + + buffer_out[8+1] = outval; + + if (error_val > 0) + { + int predictor_num = 8 - 1; + + while (predictor_num >= 0 && error_val > 0) + { + int val = buffer_out[0] - buffer_out[8 - predictor_num]; + + if (val!=0) { + if (val < 0) { + predictor_coef_table[predictor_num]++; + val=-val; + } else { + predictor_coef_table[predictor_num]--;; + } + error_val -= ((val >> predictor_quantitization) * (8 - predictor_num)); + } + predictor_num--; + } + } + else if (error_val < 0) + { + int predictor_num = 8 - 1; + while (predictor_num >= 0 && error_val < 0) + { + int val = buffer_out[0] - buffer_out[8 - predictor_num]; + if (val != 0) { + if (val > 0) { + predictor_coef_table[predictor_num]++; + val=-val; /* neg value */ + } else { + predictor_coef_table[predictor_num]--; + } + error_val -= ((val >> predictor_quantitization) * (8 - predictor_num)); + } + predictor_num--; + } + } + + buffer_out++; + } + return; + } /* general case */ if (predictor_coef_num > 0) @@ -534,26 +624,12 @@ void deinterlace_16(int32_t *buffer_a, int32_t *buffer_b, for (i = 0; i < numsamples; i++) { int32_t difference, midright; - int16_t left; - int16_t right; midright = buffer_a[i]; difference = buffer_b[i]; - - right = midright - ((difference * interlacing_leftweight) >> interlacing_shift); - left = (midright - ((difference * interlacing_leftweight) >> interlacing_shift)) - + difference; - - /* output is always little endian */ - if (host_bigendian) - { - _Swap16(left); - _Swap16(right); - } - - buffer_out[i*numchannels] = left; - buffer_out[i*numchannels + 1] = right; + buffer_out[i*numchannels] = (midright - ((difference * interlacing_leftweight) >> interlacing_shift)) + difference; + buffer_out[i*numchannels + 1] = midright - ((difference * interlacing_leftweight) >> interlacing_shift); } return; @@ -562,34 +638,27 @@ void deinterlace_16(int32_t *buffer_a, int32_t *buffer_b, /* otherwise basic interlacing took place */ for (i = 0; i < numsamples; i++) { - int16_t left, right; - - left = buffer_a[i]; - right = buffer_b[i]; - - /* output is always little endian */ - if (host_bigendian) - { - _Swap16(left); - _Swap16(right); - } - - buffer_out[i*numchannels] = left; - buffer_out[i*numchannels + 1] = right; + buffer_out[i*numchannels] = buffer_a[i]; + buffer_out[i*numchannels + 1] = buffer_b[i]; } } -void decode_frame(alac_file *alac, +int16_t* decode_frame(alac_file *alac, unsigned char *inbuffer, - void *outbuffer, int *outputsize) + int *outputsize) { int channels; + int16_t* outbuffer; int32_t outputsamples = alac->setinfo_max_samples_per_frame; /* setup the stream */ alac->input_buffer = inbuffer; alac->input_buffer_bitaccumulator = 0; + /* We can share the same buffer for outputbuffer + and outputsamples_buffer_b - and hence have them both in IRAM*/ + outbuffer=(int16_t*)outputsamples_buffer_b; + channels = readbits(alac, 3); *outputsize = outputsamples * alac->bytespersample; @@ -631,7 +700,6 @@ void decode_frame(alac_file *alac, if (!isnotcompressed) { /* so it is compressed */ - int16_t predictor_coef_table[32]; int predictor_coef_num; int prediction_type; int prediction_quantitization; @@ -659,11 +727,11 @@ void decode_frame(alac_file *alac, /* these bytes seem to have something to do with * > 2 channel files. */ - fprintf(stderr, "FIXME: unimplemented, unhandling of wasted_bytes\n"); + //fprintf(stderr, "FIXME: unimplemented, unhandling of wasted_bytes\n"); } basterdised_rice_decompress(alac, - alac->predicterror_buffer_a, + predicterror_buffer_a, outputsamples, readsamplesize, alac->setinfo_rice_initialhistory, @@ -673,8 +741,8 @@ void decode_frame(alac_file *alac, if (prediction_type == 0) { /* adaptive fir */ - predictor_decompress_fir_adapt(alac->predicterror_buffer_a, - alac->outputsamples_buffer_a, + predictor_decompress_fir_adapt(predicterror_buffer_a, + outputsamples_buffer_a, outputsamples, readsamplesize, predictor_coef_table, @@ -683,7 +751,7 @@ void decode_frame(alac_file *alac, } else { - fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type); + //fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type); /* i think the only other prediction type (or perhaps this is just a * boolean?) runs adaptive fir twice.. like: * predictor_decompress_fir_adapt(predictor_error, tempout, ...) @@ -704,7 +772,7 @@ void decode_frame(alac_file *alac, audiobits = SIGN_EXTENDED32(audiobits, readsamplesize); - alac->outputsamples_buffer_a[i] = audiobits; + outputsamples_buffer_a[i] = audiobits; } } else @@ -722,7 +790,7 @@ void decode_frame(alac_file *alac, audiobits |= readbits(alac, readsamplesize - 16); - alac->outputsamples_buffer_a[i] = audiobits; + outputsamples_buffer_a[i] = audiobits; } } /* wasted_bytes = 0; // unused */ @@ -735,17 +803,16 @@ void decode_frame(alac_file *alac, int i; for (i = 0; i < outputsamples; i++) { - int16_t sample = alac->outputsamples_buffer_a[i]; - if (host_bigendian) - _Swap16(sample); - ((int16_t*)outbuffer)[i * alac->numchannels] = sample; + /* Output mono data as stereo */ + outbuffer[i*2] = outputsamples_buffer_a[i]; + outbuffer[i*2+1] = outputsamples_buffer_a[i]; } break; } case 20: case 24: case 32: - fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); + //fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); break; default: break; @@ -788,13 +855,11 @@ void decode_frame(alac_file *alac, if (!isnotcompressed) { /* compressed */ - int16_t predictor_coef_table_a[32]; int predictor_coef_num_a; int prediction_type_a; int prediction_quantitization_a; int ricemodifier_a; - int16_t predictor_coef_table_b[32]; int predictor_coef_num_b; int prediction_type_b; int prediction_quantitization_b; @@ -834,12 +899,12 @@ void decode_frame(alac_file *alac, /*********************/ if (wasted_bytes) { /* see mono case */ - fprintf(stderr, "FIXME: unimplemented, unhandling of wasted_bytes\n"); + //fprintf(stderr, "FIXME: unimplemented, unhandling of wasted_bytes\n"); } /* channel 1 */ basterdised_rice_decompress(alac, - alac->predicterror_buffer_a, + predicterror_buffer_a, outputsamples, readsamplesize, alac->setinfo_rice_initialhistory, @@ -849,8 +914,8 @@ void decode_frame(alac_file *alac, if (prediction_type_a == 0) { /* adaptive fir */ - predictor_decompress_fir_adapt(alac->predicterror_buffer_a, - alac->outputsamples_buffer_a, + predictor_decompress_fir_adapt(predicterror_buffer_a, + outputsamples_buffer_a, outputsamples, readsamplesize, predictor_coef_table_a, @@ -859,12 +924,12 @@ void decode_frame(alac_file *alac, } else { /* see mono case */ - fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_a); + //fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_a); } /* channel 2 */ basterdised_rice_decompress(alac, - alac->predicterror_buffer_b, + predicterror_buffer_b, outputsamples, readsamplesize, alac->setinfo_rice_initialhistory, @@ -874,8 +939,8 @@ void decode_frame(alac_file *alac, if (prediction_type_b == 0) { /* adaptive fir */ - predictor_decompress_fir_adapt(alac->predicterror_buffer_b, - alac->outputsamples_buffer_b, + predictor_decompress_fir_adapt(predicterror_buffer_b, + outputsamples_buffer_b, outputsamples, readsamplesize, predictor_coef_table_b, @@ -884,7 +949,7 @@ void decode_frame(alac_file *alac, } else { - fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_b); + //fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_b); } } else @@ -902,8 +967,8 @@ void decode_frame(alac_file *alac, audiobits_a = SIGN_EXTENDED32(audiobits_a, alac->setinfo_sample_size); audiobits_b = SIGN_EXTENDED32(audiobits_b, alac->setinfo_sample_size); - alac->outputsamples_buffer_a[i] = audiobits_a; - alac->outputsamples_buffer_b[i] = audiobits_b; + outputsamples_buffer_a[i] = audiobits_a; + outputsamples_buffer_b[i] = audiobits_b; } } else @@ -923,8 +988,8 @@ void decode_frame(alac_file *alac, audiobits_b = audiobits_b >> (32 - alac->setinfo_sample_size); audiobits_b |= readbits(alac, alac->setinfo_sample_size - 16); - alac->outputsamples_buffer_a[i] = audiobits_a; - alac->outputsamples_buffer_b[i] = audiobits_b; + outputsamples_buffer_a[i] = audiobits_a; + outputsamples_buffer_b[i] = audiobits_b; } } /* wasted_bytes = 0; */ @@ -936,8 +1001,8 @@ void decode_frame(alac_file *alac, { case 16: { - deinterlace_16(alac->outputsamples_buffer_a, - alac->outputsamples_buffer_b, + deinterlace_16(outputsamples_buffer_a, + outputsamples_buffer_b, (int16_t*)outbuffer, alac->numchannels, outputsamples, @@ -948,7 +1013,7 @@ void decode_frame(alac_file *alac, case 20: case 24: case 32: - fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); + //fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); break; default: break; @@ -957,16 +1022,12 @@ void decode_frame(alac_file *alac, break; } } + return outbuffer; } -alac_file *create_alac(int samplesize, int numchannels) +void create_alac(int samplesize, int numchannels, alac_file* alac) { - alac_file *newfile = malloc(sizeof(alac_file)); - - newfile->samplesize = samplesize; - newfile->numchannels = numchannels; - newfile->bytespersample = (samplesize / 8) * numchannels; - - return newfile; + alac->samplesize = samplesize; + alac->numchannels = numchannels; + alac->bytespersample = (samplesize / 8) * numchannels; } - diff --git a/apps/codecs/libalac/decomp.h b/apps/codecs/libalac/decomp.h index 23dbc52779..e6fa82d3d7 100644 --- a/apps/codecs/libalac/decomp.h +++ b/apps/codecs/libalac/decomp.h @@ -1,12 +1,34 @@ #ifndef __ALAC__DECOMP_H #define __ALAC__DECOMP_H -typedef struct alac_file alac_file; +typedef struct +{ + unsigned char *input_buffer; + int input_buffer_bitaccumulator; /* used so we can do arbitary + bit reads */ + int samplesize; + int numchannels; + int bytespersample; -alac_file *create_alac(int samplesize, int numchannels); -void decode_frame(alac_file *alac, + /* stuff from setinfo */ + uint32_t setinfo_max_samples_per_frame; /* 0x1000 = 4096 */ /* max samples per frame? */ + uint8_t setinfo_7a; /* 0x00 */ + uint8_t setinfo_sample_size; /* 0x10 */ + uint8_t setinfo_rice_historymult; /* 0x28 */ + uint8_t setinfo_rice_initialhistory; /* 0x0a */ + uint8_t setinfo_rice_kmodifier; /* 0x0e */ + uint8_t setinfo_7f; /* 0x02 */ + uint16_t setinfo_80; /* 0x00ff */ + uint32_t setinfo_82; /* 0x000020e7 */ + uint32_t setinfo_86; /* 0x00069fe4 */ + uint32_t setinfo_8a_rate; /* 0x0000ac44 */ + /* end setinfo stuff */ +} alac_file; + +void create_alac(int samplesize, int numchannels, alac_file* alac); +int16_t* decode_frame(alac_file *alac, unsigned char *inbuffer, - void *outbuffer, int *outputsize); + int *outputsize); void alac_set_info(alac_file *alac, char *inputbuffer); #endif /* __ALAC__DECOMP_H */ diff --git a/apps/codecs/libalac/demux.c b/apps/codecs/libalac/demux.c index 7263a763d4..634dc01ee7 100644 --- a/apps/codecs/libalac/demux.c +++ b/apps/codecs/libalac/demux.c @@ -32,9 +32,11 @@ #include #include -#include +#include #include +#include "../codec.h" + #include "stream.h" #include "demux.h" @@ -56,7 +58,7 @@ static void read_chunk_ftyp(qtmovie_t *qtmovie, size_t chunk_len) size_remaining-=4; if (type != MAKEFOURCC('M','4','A',' ')) { - fprintf(stderr, "not M4A file\n"); + //fprintf(stderr, "not M4A file\n"); return; } minor_ver = stream_read_uint32(qtmovie->stream); @@ -151,7 +153,7 @@ static void read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len) if (numentries != 1) { - fprintf(stderr, "only expecting one entry in sample description atom!\n"); + //fprintf(stderr, "only expecting one entry in sample description atom!\n"); return; } @@ -173,8 +175,8 @@ static void read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len) entry_remaining -= 6; version = stream_read_uint16(qtmovie->stream); - if (version != 1) - fprintf(stderr, "unknown version??\n"); + // if (version != 1) + //fprintf(stderr, "unknown version??\n"); entry_remaining -= 2; /* revision level */ @@ -245,8 +247,8 @@ static void read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len) if (qtmovie->res->format != MAKEFOURCC('a','l','a','c')) { - fprintf(stderr, "expecting 'alac' data format, got %c%c%c%c\n", - SPLITFOURCC(qtmovie->res->format)); +// fprintf(stderr, "expecting 'alac' data format, got %c%c%c%c\n", +// SPLITFOURCC(qtmovie->res->format)); return; } } @@ -282,7 +284,7 @@ static void read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len) if (size_remaining) { - fprintf(stderr, "ehm, size remianing?\n"); + //fprintf(stderr, "ehm, size remianing?\n"); stream_skip(qtmovie->stream, size_remaining); } } @@ -305,7 +307,7 @@ static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len) /* default sample size */ if (stream_read_uint32(qtmovie->stream) != 0) { - fprintf(stderr, "i was expecting variable samples sizes\n"); + //fprintf(stderr, "i was expecting variable samples sizes\n"); stream_read_uint32(qtmovie->stream); size_remaining -= 4; return; @@ -326,7 +328,7 @@ static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len) if (size_remaining) { - fprintf(stderr, "ehm, size remianing?\n"); + //fprintf(stderr, "ehm, size remianing?\n"); stream_skip(qtmovie->stream, size_remaining); } } @@ -343,7 +345,7 @@ static void read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len) sub_chunk_len = stream_read_uint32(qtmovie->stream); if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining) { - fprintf(stderr, "strange size for chunk inside stbl\n"); + //fprintf(stderr, "strange size for chunk inside stbl\n"); return; } @@ -366,8 +368,8 @@ static void read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len) stream_skip(qtmovie->stream, sub_chunk_len - 8); break; default: - fprintf(stderr, "(stbl) unknown chunk id: %c%c%c%c\n", - SPLITFOURCC(sub_chunk_id)); +// fprintf(stderr, "(stbl) unknown chunk id: %c%c%c%c\n", +// SPLITFOURCC(sub_chunk_id)); return; } @@ -383,12 +385,12 @@ static void read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len) /**** SOUND HEADER CHUNK ****/ if (stream_read_uint32(qtmovie->stream) != 16) { - fprintf(stderr, "unexpected size in media info\n"); + //fprintf(stderr, "unexpected size in media info\n"); return; } if (stream_read_uint32(qtmovie->stream) != MAKEFOURCC('s','m','h','d')) { - fprintf(stderr, "not a sound header! can't handle this.\n"); + //fprintf(stderr, "not a sound header! can't handle this.\n"); return; } /* now skip the rest */ @@ -400,7 +402,7 @@ static void read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len) dinf_size = stream_read_uint32(qtmovie->stream); if (stream_read_uint32(qtmovie->stream) != MAKEFOURCC('d','i','n','f')) { - fprintf(stderr, "expected dinf, didn't get it.\n"); + //fprintf(stderr, "expected dinf, didn't get it.\n"); return; } /* skip it */ @@ -413,7 +415,7 @@ static void read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len) stbl_size = stream_read_uint32(qtmovie->stream); if (stream_read_uint32(qtmovie->stream) != MAKEFOURCC('s','t','b','l')) { - fprintf(stderr, "expected stbl, didn't get it.\n"); + //fprintf(stderr, "expected stbl, didn't get it.\n"); return; } read_chunk_stbl(qtmovie, stbl_size); @@ -421,7 +423,7 @@ static void read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len) if (size_remaining) { - fprintf(stderr, "oops\n"); + //fprintf(stderr, "oops\n"); stream_skip(qtmovie->stream, size_remaining); } } @@ -438,7 +440,7 @@ static void read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len) sub_chunk_len = stream_read_uint32(qtmovie->stream); if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining) { - fprintf(stderr, "strange size for chunk inside mdia\n"); + //fprintf(stderr, "strange size for chunk inside mdia\n"); return; } @@ -456,8 +458,8 @@ static void read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len) read_chunk_minf(qtmovie, sub_chunk_len); break; default: - fprintf(stderr, "(mdia) unknown chunk id: %c%c%c%c\n", - SPLITFOURCC(sub_chunk_id)); +// fprintf(stderr, "(mdia) unknown chunk id: %c%c%c%c\n", +// SPLITFOURCC(sub_chunk_id)); return; } @@ -478,7 +480,7 @@ static void read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len) sub_chunk_len = stream_read_uint32(qtmovie->stream); if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining) { - fprintf(stderr, "strange size for chunk inside trak\n"); + //fprintf(stderr, "strange size for chunk inside trak\n"); return; } @@ -493,8 +495,8 @@ static void read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len) read_chunk_mdia(qtmovie, sub_chunk_len); break; default: - fprintf(stderr, "(trak) unknown chunk id: %c%c%c%c\n", - SPLITFOURCC(sub_chunk_id)); +// fprintf(stderr, "(trak) unknown chunk id: %c%c%c%c\n", +// SPLITFOURCC(sub_chunk_id)); return; } @@ -533,7 +535,7 @@ static void read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len) sub_chunk_len = stream_read_uint32(qtmovie->stream); if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining) { - fprintf(stderr, "strange size for chunk inside moov\n"); + //fprintf(stderr, "strange size for chunk inside moov\n"); return; } @@ -551,8 +553,8 @@ static void read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len) read_chunk_udta(qtmovie, sub_chunk_len); break; default: - fprintf(stderr, "(moov) unknown chunk id: %c%c%c%c\n", - SPLITFOURCC(sub_chunk_id)); +// fprintf(stderr, "(moov) unknown chunk id: %c%c%c%c\n", +// SPLITFOURCC(sub_chunk_id)); return; } @@ -574,14 +576,11 @@ static void read_chunk_mdat(qtmovie_t *qtmovie, size_t chunk_len) int qtmovie_read(stream_t *file, demux_res_t *demux_res) { - qtmovie_t *qtmovie; - - qtmovie = (qtmovie_t*)malloc(sizeof(qtmovie_t)); + qtmovie_t qtmovie; /* construct the stream */ - qtmovie->stream = file; - - qtmovie->res = demux_res; + qtmovie.stream = file; + qtmovie.res = demux_res; /* read the chunks */ while (1) @@ -589,26 +588,26 @@ int qtmovie_read(stream_t *file, demux_res_t *demux_res) size_t chunk_len; fourcc_t chunk_id; - chunk_len = stream_read_uint32(qtmovie->stream); - if (stream_eof(qtmovie->stream)) + chunk_len = stream_read_uint32(qtmovie.stream); + if (stream_eof(qtmovie.stream)) { return 0; } if (chunk_len == 1) { - fprintf(stderr, "need 64bit support\n"); + //fprintf(stderr, "need 64bit support\n"); return 0; } - chunk_id = stream_read_uint32(qtmovie->stream); + chunk_id = stream_read_uint32(qtmovie.stream); switch (chunk_id) { case MAKEFOURCC('f','t','y','p'): - read_chunk_ftyp(qtmovie, chunk_len); + read_chunk_ftyp(&qtmovie, chunk_len); break; case MAKEFOURCC('m','o','o','v'): - read_chunk_moov(qtmovie, chunk_len); + read_chunk_moov(&qtmovie, chunk_len); break; /* once we hit mdat we stop reading and return. * this is on the assumption that there is no furhter interesting @@ -617,16 +616,16 @@ int qtmovie_read(stream_t *file, demux_res_t *demux_res) * for the decoder. And we don't want to rely on fseek/ftell, * as they may not always be avilable */ case MAKEFOURCC('m','d','a','t'): - read_chunk_mdat(qtmovie, chunk_len); + read_chunk_mdat(&qtmovie, chunk_len); return 1; /* these following atoms can be skipped !!!! */ case MAKEFOURCC('f','r','e','e'): - stream_skip(qtmovie->stream, chunk_len - 8); /* FIXME not 8 */ + stream_skip(qtmovie.stream, chunk_len - 8); /* FIXME not 8 */ break; default: - fprintf(stderr, "(top) unknown chunk id: %c%c%c%c\n", - SPLITFOURCC(chunk_id)); +// fprintf(stderr, "(top) unknown chunk id: %c%c%c%c\n", +// SPLITFOURCC(chunk_id)); return 0; } diff --git a/apps/codecs/libalac/demux.h b/apps/codecs/libalac/demux.h index 62b949fa3b..27c9e826c5 100644 --- a/apps/codecs/libalac/demux.h +++ b/apps/codecs/libalac/demux.h @@ -1,7 +1,7 @@ #ifndef DEMUX_H #define DEMUX_H -#include +#include #include "stream.h" typedef uint32_t fourcc_t; diff --git a/apps/codecs/libalac/stream.h b/apps/codecs/libalac/stream.h index 31f93d9059..95be0b56d0 100644 --- a/apps/codecs/libalac/stream.h +++ b/apps/codecs/libalac/stream.h @@ -3,9 +3,11 @@ /* stream.h */ -#include +#include -typedef struct stream_tTAG stream_t; +typedef struct { + int eof; +} stream_t; void stream_read(stream_t *stream, size_t len, void *buf); @@ -22,9 +24,4 @@ void stream_skip(stream_t *stream, size_t skip); int stream_eof(stream_t *stream); -stream_t *stream_create_file(FILE *file, - int bigendian); -void stream_destroy(stream_t *stream); - #endif /* STREAM_H */ - -- cgit v1.2.3