1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Dave Chapman 2005-09-22 20:46:58 +00:00
parent 567718d837
commit debbe9747e
8 changed files with 405 additions and 197 deletions

View file

@ -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)

View file

@ -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 <stdint.h> were replaced with <inttypes.h> 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.

View file

@ -0,0 +1,2 @@
alac.c
demux.c

View file

@ -33,8 +33,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#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;
}

View file

@ -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 */

View file

@ -32,9 +32,11 @@
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#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;
}

View file

@ -1,7 +1,7 @@
#ifndef DEMUX_H
#define DEMUX_H
#include <stdint.h>
#include <inttypes.h>
#include "stream.h"
typedef uint32_t fourcc_t;

View file

@ -3,9 +3,11 @@
/* stream.h */
#include <stdint.h>
#include <inttypes.h>
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 */