diff -urN faad2-2.7/common/mp4ff/mp4atom.c faad2-2.7-patched/common/mp4ff/mp4atom.c --- faad2-2.7/common/mp4ff/mp4atom.c 2009-01-19 18:56:30.000000000 -0500 +++ faad2-2.7-patched/common/mp4ff/mp4atom.c 2010-05-16 18:36:31.000000000 -0400 @@ -224,6 +224,8 @@ return ATOM_DESCRIPTION; else if (mp4ff_atom_compare(a,b,c,d, 'p','c','s','t')) return ATOM_PODCAST; + else if (mp4ff_atom_compare(a,b,c,d, 'a','l','a','c')) + return ATOM_ALAC; else return ATOM_UNKNOWN; } @@ -375,6 +377,65 @@ return 0; } +static int32_t mp4ff_read_alac_desc(mp4ff_t *f, uint64_t size, uint8_t header_size) +{ + f->track[f->total_tracks - 1]->decoderConfigLen = size - header_size; + + if (f->track[f->total_tracks - 1]->decoderConfig) + free(f->track[f->total_tracks - 1]->decoderConfig); + f->track[f->total_tracks - 1]->decoderConfig = malloc(f->track[f->total_tracks - 1]->decoderConfigLen); + if (f->track[f->total_tracks - 1]->decoderConfig) + { + mp4ff_read_data(f, f->track[f->total_tracks - 1]->decoderConfig, f->track[f->total_tracks - 1]->decoderConfigLen); + } else { + f->track[f->total_tracks - 1]->decoderConfigLen = 0; + } + + /* will skip the remainder of the atom */ + return 0; +} + +static int32_t mp4ff_read_alac(mp4ff_t *f) +{ + uint64_t size; + int32_t i; + uint8_t atom_type = 0; + uint8_t header_size = 0; + int version; + + for (i = 0; i < 6; i++) + { + mp4ff_read_char(f); /* reserved */ + } + + version = mp4ff_read_int16(f); + if (version != 1) { + return 1; + } + + mp4ff_read_int16(f); /* revision level */ + mp4ff_read_int32(f); /* vendor */ + mp4ff_read_int16(f); /* ?? */ + + f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f); + f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f); + + mp4ff_read_int16(f); /* compression id */ + mp4ff_read_int16(f); /* packet size */ + + f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f); + + mp4ff_read_int16(f); /* ?? */ + + size = mp4ff_atom_read_header(f, &atom_type, &header_size); + if (atom_type == ATOM_ALAC) + { + mp4ff_read_alac_desc(f, size, header_size); + } + + return 0; +} + static int32_t mp4ff_read_stsd(mp4ff_t *f) { int32_t i; @@ -395,12 +456,15 @@ if (atom_type == ATOM_MP4A) { - f->track[f->total_tracks - 1]->type = TRACK_AUDIO; + f->track[f->total_tracks - 1]->type = TRACK_AUDIO_AAC; mp4ff_read_mp4a(f); } else if (atom_type == ATOM_MP4V) { f->track[f->total_tracks - 1]->type = TRACK_VIDEO; } else if (atom_type == ATOM_MP4S) { f->track[f->total_tracks - 1]->type = TRACK_SYSTEM; + } else if (atom_type == ATOM_ALAC) { + f->track[f->total_tracks - 1]->type = TRACK_AUDIO_ALAC; + mp4ff_read_alac(f); } else { f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN; } diff -urN faad2-2.7/common/mp4ff/mp4ff.c faad2-2.7-patched/common/mp4ff/mp4ff.c --- faad2-2.7/common/mp4ff/mp4ff.c 2009-01-26 18:01:40.000000000 -0500 +++ faad2-2.7-patched/common/mp4ff/mp4ff.c 2010-05-16 18:36:31.000000000 -0400 @@ -312,6 +312,11 @@ return f->track[track]->sampleRate; } +uint32_t mp4ff_get_sample_size(const mp4ff_t *f, const int32_t track) +{ + return f->track[track]->sampleSize; +} + uint32_t mp4ff_get_channel_count(const mp4ff_t * f,const int32_t track) { return f->track[track]->channelCount; diff -urN faad2-2.7/common/mp4ff/mp4ff.h faad2-2.7-patched/common/mp4ff/mp4ff.h --- faad2-2.7/common/mp4ff/mp4ff.h 2009-01-28 19:41:08.000000000 -0500 +++ faad2-2.7-patched/common/mp4ff/mp4ff.h 2010-05-16 18:36:31.000000000 -0400 @@ -54,6 +54,11 @@ /* mp4 main file structure */ typedef void* mp4ff_t; +#define TRACK_UNKNOWN 0 +#define TRACK_AUDIO_AAC 1 +#define TRACK_VIDEO 2 +#define TRACK_SYSTEM 3 +#define TRACK_AUDIO_ALAC 4 /* API */ @@ -87,6 +92,7 @@ int64_t mp4ff_get_track_duration(const mp4ff_t *f, const int32_t track); //returns (-1) if unknown int64_t mp4ff_get_track_duration_use_offsets(const mp4ff_t *f, const int32_t track); //returns (-1) if unknown uint32_t mp4ff_get_sample_rate(const mp4ff_t *f, const int32_t track); +uint32_t mp4ff_get_sample_size(const mp4ff_t *f, const int32_t track); uint32_t mp4ff_get_channel_count(const mp4ff_t * f,const int32_t track); uint32_t mp4ff_get_audio_type(const mp4ff_t * f,const int32_t track); diff -urN faad2-2.7/common/mp4ff/mp4ffint.h faad2-2.7-patched/common/mp4ff/mp4ffint.h --- faad2-2.7/common/mp4ff/mp4ffint.h 2009-01-25 15:14:34.000000000 -0500 +++ faad2-2.7-patched/common/mp4ff/mp4ffint.h 2010-05-16 18:36:31.000000000 -0400 @@ -40,10 +40,10 @@ #define MAX_TRACKS 1024 #define TRACK_UNKNOWN 0 -#define TRACK_AUDIO 1 +#define TRACK_AUDIO_AAC 1 #define TRACK_VIDEO 2 #define TRACK_SYSTEM 3 - +#define TRACK_AUDIO_ALAC 4 #define SUBATOMIC 128 @@ -93,6 +93,7 @@ #define ATOM_SEASON 170 #define ATOM_EPISODE 171 #define ATOM_PODCAST 172 +#define ATOM_ALAC 173 #define ATOM_UNKNOWN 255 #define ATOM_FREE ATOM_UNKNOWN diff -urN faad2-2.7/frontend/Makefile.in faad2-2.7-patched/frontend/Makefile.in --- faad2-2.7/frontend/Makefile.in 2009-02-10 03:36:11.000000000 -0500 +++ faad2-2.7-patched/frontend/Makefile.in 2010-05-16 18:36:31.000000000 -0400 @@ -49,7 +49,7 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(manmdir)" binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) -am_faad_OBJECTS = main.$(OBJEXT) audio.$(OBJEXT) getopt.$(OBJEXT) +am_faad_OBJECTS = main.$(OBJEXT) audio.$(OBJEXT) getopt.$(OBJEXT) alac.$(OBJEXT) faad_OBJECTS = $(am_faad_OBJECTS) faad_DEPENDENCIES = $(top_builddir)/libfaad/libfaad.la \ $(top_builddir)/common/mp4ff/libmp4ff.a @@ -190,7 +190,7 @@ faad_LDADD = $(top_builddir)/libfaad/libfaad.la \ $(top_builddir)/common/mp4ff/libmp4ff.a -faad_SOURCES = main.c \ +faad_SOURCES = main.c alac.c \ audio.c audio.h \ $(top_srcdir)/common/faad/getopt.c @@ -268,6 +268,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alac.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ diff -urN faad2-2.7/frontend/alac.c faad2-2.7-patched/frontend/alac.c --- faad2-2.7/frontend/alac.c 1969-12-31 19:00:00.000000000 -0500 +++ faad2-2.7-patched/frontend/alac.c 2010-05-16 18:36:31.000000000 -0400 @@ -0,0 +1,1237 @@ +/* + * 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. + * + */ + + +#include +#include +#include +#ifdef _WIN32 + #include "stdint_win.h" +#else + #include +#endif + +// #include "decomp.h" + +#define _Swap32(v) do { \ + v = (((v) & 0x000000FF) << 0x18) | \ + (((v) & 0x0000FF00) << 0x08) | \ + (((v) & 0x00FF0000) >> 0x08) | \ + (((v) & 0xFF000000) >> 0x18); } while(0) + +#define _Swap16(v) do { \ + v = (((v) & 0x00FF) << 0x08) | \ + (((v) & 0xFF00) >> 0x08); } while (0) + +#if defined(PADRE) +static __inline__ int32_t S32XS32(int32_t x, int32_t y) +{ + int32_t z; + __asm__ ( + " nop\n" + " nop\n" + " smul %1,%2,%0" + : "=r"(z) + : "r"(x), "r"(y) + ); + return z; +} +#else +static __inline__ int32_t S32XS32(int32_t x, int32_t y) +{ + int32_t z; + z = x * y; + return z; +} +#endif + +struct {signed int x:24;} se_struct_24; +#define SignExtend24(val) (se_struct_24.x = val) + +extern int host_bigendian; + +typedef 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; + + int32_t *uncompressed_bytes_buffer_a; + int32_t *uncompressed_bytes_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 */ /* max sample size?? */ + uint32_t setinfo_86; /* 0x00069fe4 */ /* bit rate (avarge)?? */ + uint32_t setinfo_8a_rate; /* 0x0000ac44 */ + /* end setinfo stuff */ + +} alac_file; + + +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); + + alac->uncompressed_bytes_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4); + alac->uncompressed_bytes_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4); +} + +static void alac_set_info(alac_file *alac, const char *inputbuffer) +{ + const char *ptr = 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); + ptr += 4; + alac->setinfo_7a = *(uint8_t*)ptr; + ptr += 1; + alac->setinfo_sample_size = *(uint8_t*)ptr; + ptr += 1; + alac->setinfo_rice_historymult = *(uint8_t*)ptr; + ptr += 1; + alac->setinfo_rice_initialhistory = *(uint8_t*)ptr; + ptr += 1; + alac->setinfo_rice_kmodifier = *(uint8_t*)ptr; + ptr += 1; + alac->setinfo_7f = *(uint8_t*)ptr; + ptr += 1; + alac->setinfo_80 = *(uint16_t*)ptr; + if (!host_bigendian) + _Swap16(alac->setinfo_80); + ptr += 2; + alac->setinfo_82 = *(uint32_t*)ptr; + if (!host_bigendian) + _Swap32(alac->setinfo_82); + ptr += 4; + alac->setinfo_86 = *(uint32_t*)ptr; + if (!host_bigendian) + _Swap32(alac->setinfo_86); + ptr += 4; + alac->setinfo_8a_rate = *(uint32_t*)ptr; + if (!host_bigendian) + _Swap32(alac->setinfo_8a_rate); + ptr += 4; + + allocate_buffers(alac); + +} + +/* stream reading */ + +/* supports reading 1 to 16 bits, in big endian format */ +static uint32_t readbits_16(alac_file *alac, int bits) +{ + uint32_t result = 0; + int new_accumulator; + + /* Bug 16025: make sure we only read as many bytes as needed, + * to avoid reading beyond the end of buffer */ + switch ((bits + alac->input_buffer_bitaccumulator - 1) >> 3) { + case 2: + result = alac->input_buffer[2]; + case 1: + result |= alac->input_buffer[1] << 8; + case 0: + result |= alac->input_buffer[0] << 16; + } + + /* shift left by the number of bits we've already read, + * so that the top 'n' bits of the 24 bits we read will + * be the return bits */ + result = result << alac->input_buffer_bitaccumulator; + + result = result & 0x00ffffff; + + /* and then only want the top 'n' bits from that, where + * n is 'bits' */ + result = result >> (24 - bits); + + new_accumulator = (alac->input_buffer_bitaccumulator + bits); + + /* increase the buffer pointer if we've read over n bytes. */ + alac->input_buffer += (new_accumulator >> 3); + + /* and the remainder goes back into the bit accumulator */ + alac->input_buffer_bitaccumulator = (new_accumulator & 7); + + return result; +} + +/* supports reading 1 to 32 bits, in big endian format */ +static uint32_t readbits(alac_file *alac, int bits) +{ + int32_t result = 0; + + if (bits > 16) + { + bits -= 16; + result = readbits_16(alac, 16) << bits; + } + + result |= readbits_16(alac, bits); + + return result; +} + +/* reads a single bit */ +static int readbit(alac_file *alac) +{ + int result; + int new_accumulator; + + result = alac->input_buffer[0]; + + result = result << alac->input_buffer_bitaccumulator; + + result = result >> 7 & 1; + + new_accumulator = (alac->input_buffer_bitaccumulator + 1); + + alac->input_buffer += (new_accumulator / 8); + + alac->input_buffer_bitaccumulator = (new_accumulator % 8); + + return result; +} + +static void unreadbits(alac_file *alac, int bits) +{ + int new_accumulator = (alac->input_buffer_bitaccumulator - bits); + + alac->input_buffer += (new_accumulator >> 3); + + alac->input_buffer_bitaccumulator = (new_accumulator & 7); + if (alac->input_buffer_bitaccumulator < 0) + alac->input_buffer_bitaccumulator *= -1; +} + +/* various implementations of count_leading_zero: + * the first one is the original one, the simplest and most + * obvious for what it's doing. never use this. + * then there are the asm ones. fill in as necessary + * and finally an unrolled and optimised c version + * to fall back to + */ +#if 0 +/* hideously inefficient. could use a bitmask search, + * alternatively bsr on x86, + */ +static int count_leading_zeros(int32_t input) +{ + int i = 0; + while (!(0x80000000 & input) && i < 32) + { + i++; + input = input << 1; + } + return i; +} +#elif defined(__GNUC__) && (defined(_X86) || defined(__i386) || defined(i386)) +/* for some reason the unrolled version (below) is + * actually faster than this. yay intel! + */ +static int count_leading_zeros(int input) +{ + int output = 0; + if (!input) return 32; + __asm("bsr %1, %0\n" + : "=r" (output) + : "r" (input)); + return (0x1f - output); +} +#elif defined(_MSC_VER) && defined(_M_IX86) +static int count_leading_zeros(int input) +{ + int output = 0; + if (!input) return 32; + __asm + { + mov eax, input; + mov edx, 0x1f; + bsr ecx, eax; + sub edx, ecx; + mov output, edx; + } + return output; +} +#elif defined(PADRE) +static int count_leading_zeros(int input) +{ + int output; + if (!input) + return 32; + output = 1; + if (!((unsigned int)input >> 16)) {output += 16; input <<= 16;} + if (!((unsigned int)input >> 24)) {output += 8; input <<= 8;} + if (!((unsigned int)input >> 28)) {output += 4; input <<= 4;} + if (!((unsigned int)input >> 30)) {output += 2; input <<= 2;} + output -= ((unsigned int)input >> 31); + return output; +} +#else +#warning using generic count leading zeroes. You may wish to write one for your CPU / compiler +static int count_leading_zeros(int input) +{ + int output = 0; + int curbyte = 0; + + curbyte = input >> 24; + if (curbyte) goto found; + output += 8; + + curbyte = input >> 16; + if (curbyte & 0xff) goto found; + output += 8; + + curbyte = input >> 8; + if (curbyte & 0xff) goto found; + output += 8; + + curbyte = input; + if (curbyte & 0xff) goto found; + output += 8; + + return output; + +found: + if (!(curbyte & 0xf0)) + { + output += 4; + } + else + curbyte >>= 4; + + if (curbyte & 0x8) + return output; + if (curbyte & 0x4) + return output + 1; + if (curbyte & 0x2) + return output + 2; + if (curbyte & 0x1) + return output + 3; + + /* shouldn't get here: */ + return output + 4; +} +#endif + +#define RICE_THRESHOLD 8 // maximum number of bits for a rice prefix. + +int32_t entropy_decode_value(alac_file* alac, + int readSampleSize, + int k, + int rice_kmodifier_mask) +{ + int32_t x = 0; // decoded value + + // read x, number of 1s before 0 represent the rice value. + while (x <= RICE_THRESHOLD && readbit(alac)) + { + x++; + } + + if (x > RICE_THRESHOLD) + { + // read the number from the bit stream (raw value) + int32_t value; + + value = readbits(alac, readSampleSize); + + // mask value + value &= (((uint32_t)0xffffffff) >> (32 - readSampleSize)); + + x = value; + } + else + { + if (k != 1) + { + int extraBits = readbits(alac, k); + + // x = x * (2^k - 1) + x *= (((1 << k) - 1) & rice_kmodifier_mask); + + if (extraBits > 1) + x += extraBits - 1; + else + unreadbits(alac, 1); + } + } + + return x; +} + +void entropy_rice_decode(alac_file* alac, + int32_t* outputBuffer, + int outputSize, + int readSampleSize, + int rice_initialhistory, + int rice_kmodifier, + int rice_historymult, + int rice_kmodifier_mask) +{ + int outputCount; + int history = rice_initialhistory; + int signModifier = 0; + + for (outputCount = 0; outputCount < outputSize; outputCount++) + { + int32_t decodedValue; + int32_t finalValue; + int32_t k; + + k = 31 - rice_kmodifier - count_leading_zeros((history >> 9) + 3); + + if (k < 0) k += rice_kmodifier; + else k = rice_kmodifier; + + // note: don't use rice_kmodifier_mask here (set mask to 0xFFFFFFFF) + decodedValue = entropy_decode_value(alac, readSampleSize, k, 0xFFFFFFFF); + + decodedValue += signModifier; + finalValue = (decodedValue + 1) / 2; // inc by 1 and shift out sign bit + if (decodedValue & 1) // the sign is stored in the low bit + finalValue *= -1; + + outputBuffer[outputCount] = finalValue; + + signModifier = 0; + + // update history + history += S32XS32(decodedValue, rice_historymult) + - (S32XS32(history, rice_historymult) >> 9); + + if (decodedValue > 0xFFFF) + history = 0xFFFF; + + // special case, for compressed blocks of 0 + if ((history < 128) && (outputCount + 1 < outputSize)) + { + int32_t blockSize; + + signModifier = 1; + + k = count_leading_zeros(history) + ((history + 16) >> 6) - 24; + + // note: blockSize is always 16bit + blockSize = entropy_decode_value(alac, 16, k, rice_kmodifier_mask); + + // got blockSize 0s + if (blockSize > 0) + { + memset(&outputBuffer[outputCount + 1], 0, blockSize * sizeof(*outputBuffer)); + outputCount += blockSize; + } + + if (blockSize > 0xFFFF) + signModifier = 0; + + history = 0; + } + } +} + +#define SIGN_EXTENDED32(val, bits) ((val << (32 - bits)) >> (32 - bits)) + +#define SIGN_ONLY(v) \ + ((v < 0) ? (-1) : \ + ((v > 0) ? (1) : \ + (0))) + +static void predictor_decompress_fir_adapt(int32_t *error_buffer, + int32_t *buffer_out, + int output_size, + int readsamplesize, + int16_t *predictor_coef_table, + int predictor_coef_num, + int predictor_quantitization) +{ + int i; + + /* first sample always copies */ + *buffer_out = *error_buffer; + + if (!predictor_coef_num) + { + if (output_size <= 1) return; + memcpy(buffer_out+1, error_buffer+1, (output_size-1) << 2); + return; + } + + if (predictor_coef_num == 0x1f) /* 11111 - max value of predictor_coef_num */ + { /* second-best case scenario for fir decompression, + * error describes a small difference from the previous sample only + */ + if (output_size <= 1) return; + for (i = 0; i < output_size - 1; i++) + { + int32_t prev_value; + int32_t error_value; + + prev_value = buffer_out[i]; + error_value = error_buffer[i+1]; + buffer_out[i+1] = SIGN_EXTENDED32((prev_value + error_value), readsamplesize); + } + return; + } + + /* read warm-up samples */ + if (predictor_coef_num > 0) + { + int i; + for (i = 0; i < predictor_coef_num; i++) + { + int32_t val; + + val = buffer_out[i] + error_buffer[i+1]; + + val = SIGN_EXTENDED32(val, readsamplesize); + + buffer_out[i+1] = val; + } + } + +#if 0 + /* 4 and 8 are very common cases (the only ones i've seen). these + * should be unrolled and optimised + */ + if (predictor_coef_num == 4) + { + /* FIXME: optimised general case */ + return; + } + + if (predictor_coef_table == 8) + { + /* FIXME: optimised general case */ + return; + } +#endif + + + /* general case */ + if (predictor_coef_num > 0) + { + for (i = predictor_coef_num + 1; + i < output_size; + i++) + { + int j; + int sum = 0; + int outval; + int error_val = error_buffer[i]; + + for (j = 0; j < predictor_coef_num; j++) + { + sum += S32XS32( + buffer_out[predictor_coef_num-j] - buffer_out[0], + predictor_coef_table[j] + ); + } + + outval = (1 << (predictor_quantitization-1)) + sum; + outval = outval >> predictor_quantitization; + outval = outval + buffer_out[0] + error_val; + outval = SIGN_EXTENDED32(outval, readsamplesize); + + buffer_out[predictor_coef_num+1] = outval; + + if (error_val > 0) + { + int predictor_num = predictor_coef_num - 1; + + while (predictor_num >= 0 && error_val > 0) + { + int val = buffer_out[0] - buffer_out[predictor_coef_num - predictor_num]; + int sign = SIGN_ONLY(val); + + predictor_coef_table[predictor_num] -= sign; + +#if defined(PADRE) + if (sign<0) val = -val; +#else + val *= sign; /* absolute value */ +#endif + + error_val -= S32XS32(val >> predictor_quantitization, predictor_coef_num - predictor_num); + + predictor_num--; + } + } + else if (error_val < 0) + { + int predictor_num = predictor_coef_num - 1; + + while (predictor_num >= 0 && error_val < 0) + { + int val = buffer_out[0] - buffer_out[predictor_coef_num - predictor_num]; + int sign = - SIGN_ONLY(val); + + predictor_coef_table[predictor_num] -= sign; + +#if defined(PADRE) + if (sign<0) val = -val; +#else + val *= sign; /* neg value */ +#endif + + error_val -= S32XS32(val >> predictor_quantitization, predictor_coef_num - predictor_num); + + predictor_num--; + } + } + + buffer_out++; + } + } +} + +void deinterlace_16(int32_t *buffer_a, int32_t *buffer_b, + int16_t *buffer_out, + int numchannels, int numsamples, + uint8_t interlacing_shift, + uint8_t interlacing_leftweight) +{ + int i; + if (numsamples <= 0) return; + + /* weighted interlacing */ + if (interlacing_leftweight) + { + 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 - (S32XS32(difference, interlacing_leftweight) >> interlacing_shift); + left = right + difference; + + /* output is always little endian */ + if (host_bigendian) + { + _Swap16(left); + _Swap16(right); + } + + buffer_out[i*numchannels] = left; + buffer_out[i*numchannels + 1] = right; + } + + return; + } + + /* 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; + } +} + +void deinterlace_24(int32_t *buffer_a, int32_t *buffer_b, + int uncompressed_bytes, + int32_t *uncompressed_bytes_buffer_a, int32_t *uncompressed_bytes_buffer_b, + void *buffer_out, + int numchannels, int numsamples, + uint8_t interlacing_shift, + uint8_t interlacing_leftweight) +{ + int i; + if (numsamples <= 0) return; + + /* weighted interlacing */ + if (interlacing_leftweight) + { + for (i = 0; i < numsamples; i++) + { + int32_t difference, midright; + int32_t left; + int32_t right; + + midright = buffer_a[i]; + difference = buffer_b[i]; + + right = midright - ((difference * interlacing_leftweight) >> interlacing_shift); + left = right + difference; + + if (uncompressed_bytes) + { + uint32_t mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8)); + left <<= (uncompressed_bytes * 8); + right <<= (uncompressed_bytes * 8); + + left |= uncompressed_bytes_buffer_a[i] & mask; + right |= uncompressed_bytes_buffer_b[i] & mask; + } + + ((uint8_t*)buffer_out)[i * numchannels * 3] = (left) & 0xFF; + ((uint8_t*)buffer_out)[i * numchannels * 3 + 1] = (left >> 8) & 0xFF; + ((uint8_t*)buffer_out)[i * numchannels * 3 + 2] = (left >> 16) & 0xFF; + + ((uint8_t*)buffer_out)[i * numchannels * 3 + 3] = (right) & 0xFF; + ((uint8_t*)buffer_out)[i * numchannels * 3 + 4] = (right >> 8) & 0xFF; + ((uint8_t*)buffer_out)[i * numchannels * 3 + 5] = (right >> 16) & 0xFF; + } + + return; + } + + /* otherwise basic interlacing took place */ + for (i = 0; i < numsamples; i++) + { + int32_t left, right; + + left = buffer_a[i]; + right = buffer_b[i]; + + if (uncompressed_bytes) + { + uint32_t mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8)); + left <<= (uncompressed_bytes * 8); + right <<= (uncompressed_bytes * 8); + + left |= uncompressed_bytes_buffer_a[i] & mask; + right |= uncompressed_bytes_buffer_b[i] & mask; + } + + ((uint8_t*)buffer_out)[i * numchannels * 3] = (left) & 0xFF; + ((uint8_t*)buffer_out)[i * numchannels * 3 + 1] = (left >> 8) & 0xFF; + ((uint8_t*)buffer_out)[i * numchannels * 3 + 2] = (left >> 16) & 0xFF; + + ((uint8_t*)buffer_out)[i * numchannels * 3 + 3] = (right) & 0xFF; + ((uint8_t*)buffer_out)[i * numchannels * 3 + 4] = (right >> 8) & 0xFF; + ((uint8_t*)buffer_out)[i * numchannels * 3 + 5] = (right >> 16) & 0xFF; + + } + +} + +long alac_decode_frame(alac_file *alac, + unsigned char *inbuffer, + void *outbuffer, int *outputsize) +{ + int channels; + int32_t outputsamples = alac->setinfo_max_samples_per_frame; + int max_outputsize = *outputsize; + + /* setup the stream */ + alac->input_buffer = inbuffer; + alac->input_buffer_bitaccumulator = 0; + + channels = readbits(alac, 3); + + *outputsize = S32XS32(outputsamples, alac->bytespersample); + + if (*outputsize > max_outputsize) { + fprintf(stderr, "Output sample buffer size %d, needed %d\n", max_outputsize, *outputsize); + return 0; + } + + switch(channels) + { + case 0: /* 1 channel */ + { + int hassize; + int isnotcompressed; + int readsamplesize; + + int uncompressed_bytes; + int ricemodifier; + + /* 2^result = something to do with output waiting. + * perhaps matters if we read > 1 frame in a pass? + */ + readbits(alac, 4); + + readbits(alac, 12); /* unknown, skip 12 bits */ + + hassize = readbits(alac, 1); /* the output sample size is stored soon */ + + uncompressed_bytes = readbits(alac, 2); /* number of bytes in the (compressed) stream that are not compressed */ + + isnotcompressed = readbits(alac, 1); /* whether the frame is compressed */ + + if (hassize) + { + /* now read the number of samples, + * as a 32bit integer */ + outputsamples = readbits(alac, 32); + *outputsize = S32XS32(outputsamples, alac->bytespersample); + if (*outputsize > max_outputsize) { + fprintf(stderr, "Output sample buffer size %d, needed %d\n", max_outputsize, *outputsize); + return 0; + } + } + + readsamplesize = alac->setinfo_sample_size - (uncompressed_bytes * 8); + + if (!isnotcompressed) + { /* so it is compressed */ + int16_t predictor_coef_table[32]; + int predictor_coef_num; + int prediction_type; + int prediction_quantitization; + int i; + + /* skip 16 bits, not sure what they are. seem to be used in + * two channel case */ + readbits(alac, 8); + readbits(alac, 8); + + prediction_type = readbits(alac, 4); + prediction_quantitization = readbits(alac, 4); + + ricemodifier = readbits(alac, 3); + predictor_coef_num = readbits(alac, 5); + + /* read the predictor table */ + for (i = 0; i < predictor_coef_num; i++) + { + predictor_coef_table[i] = (int16_t)readbits(alac, 16); + } + + if (uncompressed_bytes) + { + int i; + for (i = 0; i < outputsamples; i++) + { + alac->uncompressed_bytes_buffer_a[i] = readbits(alac, uncompressed_bytes * 8); + } + } + + entropy_rice_decode(alac, + alac->predicterror_buffer_a, + outputsamples, + readsamplesize, + alac->setinfo_rice_initialhistory, + alac->setinfo_rice_kmodifier, + S32XS32(ricemodifier, alac->setinfo_rice_historymult >> 2), + (1 << alac->setinfo_rice_kmodifier) - 1); + + if (prediction_type == 0) + { /* adaptive fir */ + predictor_decompress_fir_adapt(alac->predicterror_buffer_a, + alac->outputsamples_buffer_a, + outputsamples, + readsamplesize, + predictor_coef_table, + predictor_coef_num, + prediction_quantitization); + } + else + { + 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, ...) + * predictor_decompress_fir_adapt(predictor_error, outputsamples ...) + * little strange.. + */ + } + + } + else + { /* not compressed, easy case */ + if (alac->setinfo_sample_size <= 16) + { + int i; + for (i = 0; i < outputsamples; i++) + { + int32_t audiobits = readbits(alac, alac->setinfo_sample_size); + + audiobits = SIGN_EXTENDED32(audiobits, alac->setinfo_sample_size); + + alac->outputsamples_buffer_a[i] = audiobits; + } + } + else + { + int i; + for (i = 0; i < outputsamples; i++) + { + int32_t audiobits; + + audiobits = readbits(alac, 16); + /* special case of sign extension.. + * as we'll be ORing the low 16bits into this */ + audiobits = audiobits << (alac->setinfo_sample_size - 16); + audiobits |= readbits(alac, alac->setinfo_sample_size - 16); + audiobits = SignExtend24(audiobits); + + alac->outputsamples_buffer_a[i] = audiobits; + } + } + uncompressed_bytes = 0; // always 0 for uncompressed + } + + switch(alac->setinfo_sample_size) + { + case 16: + { + 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; + } + break; + } + case 24: + { + int i; + for (i = 0; i < outputsamples; i++) + { + int32_t sample = alac->outputsamples_buffer_a[i]; + + if (uncompressed_bytes) + { + uint32_t mask; + sample = sample << (uncompressed_bytes * 8); + mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8)); + sample |= alac->uncompressed_bytes_buffer_a[i] & mask; + } + + ((uint8_t*)outbuffer)[i * alac->numchannels * 3] = (sample) & 0xFF; + ((uint8_t*)outbuffer)[i * alac->numchannels * 3 + 1] = (sample >> 8) & 0xFF; + ((uint8_t*)outbuffer)[i * alac->numchannels * 3 + 2] = (sample >> 16) & 0xFF; + } + break; + } + case 20: + case 32: + fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); + break; + default: + break; + } + break; + } + case 1: /* 2 channels */ + { + int hassize; + int isnotcompressed; + int readsamplesize; + + int uncompressed_bytes; + + uint8_t interlacing_shift; + uint8_t interlacing_leftweight; + + /* 2^result = something to do with output waiting. + * perhaps matters if we read > 1 frame in a pass? + */ + readbits(alac, 4); + + readbits(alac, 12); /* unknown, skip 12 bits */ + + hassize = readbits(alac, 1); /* the output sample size is stored soon */ + + uncompressed_bytes = readbits(alac, 2); /* the number of bytes in the (compressed) stream that are not compressed */ + + isnotcompressed = readbits(alac, 1); /* whether the frame is compressed */ + + if (hassize) + { + /* now read the number of samples, + * as a 32bit integer */ + outputsamples = readbits(alac, 32); + *outputsize = S32XS32(outputsamples, alac->bytespersample); + } + + readsamplesize = alac->setinfo_sample_size - (uncompressed_bytes * 8) + 1; + + 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; + int ricemodifier_b; + + int i; + + interlacing_shift = readbits(alac, 8); + interlacing_leftweight = readbits(alac, 8); + + /******** channel 1 ***********/ + prediction_type_a = readbits(alac, 4); + prediction_quantitization_a = readbits(alac, 4); + + ricemodifier_a = readbits(alac, 3); + predictor_coef_num_a = readbits(alac, 5); + + /* read the predictor table */ + for (i = 0; i < predictor_coef_num_a; i++) + { + predictor_coef_table_a[i] = (int16_t)readbits(alac, 16); + } + + /******** channel 2 *********/ + prediction_type_b = readbits(alac, 4); + prediction_quantitization_b = readbits(alac, 4); + + ricemodifier_b = readbits(alac, 3); + predictor_coef_num_b = readbits(alac, 5); + + /* read the predictor table */ + for (i = 0; i < predictor_coef_num_b; i++) + { + predictor_coef_table_b[i] = (int16_t)readbits(alac, 16); + } + + /*********************/ + if (uncompressed_bytes) + { /* see mono case */ + int i; + for (i = 0; i < outputsamples; i++) + { + alac->uncompressed_bytes_buffer_a[i] = readbits(alac, uncompressed_bytes * 8); + alac->uncompressed_bytes_buffer_b[i] = readbits(alac, uncompressed_bytes * 8); + } + } + + /* channel 1 */ + entropy_rice_decode(alac, + alac->predicterror_buffer_a, + outputsamples, + readsamplesize, + alac->setinfo_rice_initialhistory, + alac->setinfo_rice_kmodifier, + S32XS32(ricemodifier_a, alac->setinfo_rice_historymult >> 2), + (1 << alac->setinfo_rice_kmodifier) - 1); + + if (prediction_type_a == 0) + { /* adaptive fir */ + predictor_decompress_fir_adapt(alac->predicterror_buffer_a, + alac->outputsamples_buffer_a, + outputsamples, + readsamplesize, + predictor_coef_table_a, + predictor_coef_num_a, + prediction_quantitization_a); + } + else + { /* see mono case */ + fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_a); + } + + /* channel 2 */ + entropy_rice_decode(alac, + alac->predicterror_buffer_b, + outputsamples, + readsamplesize, + alac->setinfo_rice_initialhistory, + alac->setinfo_rice_kmodifier, + S32XS32(ricemodifier_b, alac->setinfo_rice_historymult >> 2), + (1 << alac->setinfo_rice_kmodifier) - 1); + + if (prediction_type_b == 0) + { /* adaptive fir */ + predictor_decompress_fir_adapt(alac->predicterror_buffer_b, + alac->outputsamples_buffer_b, + outputsamples, + readsamplesize, + predictor_coef_table_b, + predictor_coef_num_b, + prediction_quantitization_b); + } + else + { + fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_b); + } + } + else + { /* not compressed, easy case */ + if (alac->setinfo_sample_size <= 16) + { + int i; + for (i = 0; i < outputsamples; i++) + { + int32_t audiobits_a, audiobits_b; + + audiobits_a = readbits(alac, alac->setinfo_sample_size); + audiobits_b = readbits(alac, alac->setinfo_sample_size); + + 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; + } + } + else + { + int i; + for (i = 0; i < outputsamples; i++) + { + int32_t audiobits_a, audiobits_b; + + audiobits_a = readbits(alac, 16); + audiobits_a = audiobits_a << (alac->setinfo_sample_size - 16); + audiobits_a |= readbits(alac, alac->setinfo_sample_size - 16); + audiobits_a = SignExtend24(audiobits_a); + + audiobits_b = readbits(alac, 16); + audiobits_b = audiobits_b << (alac->setinfo_sample_size - 16); + audiobits_b |= readbits(alac, alac->setinfo_sample_size - 16); + audiobits_b = SignExtend24(audiobits_b); + + alac->outputsamples_buffer_a[i] = audiobits_a; + alac->outputsamples_buffer_b[i] = audiobits_b; + } + } + uncompressed_bytes = 0; // always 0 for uncompressed + interlacing_shift = 0; + interlacing_leftweight = 0; + } + + switch(alac->setinfo_sample_size) + { + case 16: + { + deinterlace_16(alac->outputsamples_buffer_a, + alac->outputsamples_buffer_b, + (int16_t*)outbuffer, + alac->numchannels, + outputsamples, + interlacing_shift, + interlacing_leftweight); + break; + } + case 24: + { + deinterlace_24(alac->outputsamples_buffer_a, + alac->outputsamples_buffer_b, + uncompressed_bytes, + alac->uncompressed_bytes_buffer_a, + alac->uncompressed_bytes_buffer_b, + (int16_t*)outbuffer, + alac->numchannels, + outputsamples, + interlacing_shift, + interlacing_leftweight); + break; + } + case 20: + case 32: + fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); + break; + default: + break; + } + + break; + } + } + return outputsamples * alac->numchannels; +} + +int host_bigendian = 0; +static void set_endian() +{ + uint32_t integer = 0x000000aa; + unsigned char *p = (unsigned char*)&integer; + + if (p[0] == 0xaa) host_bigendian = 0; + else host_bigendian = 1; +} + +alac_file *alac_init(int *samplesize, int numchannels, unsigned long * samplerate, const char *config) +{ + alac_file *newfile = malloc(sizeof(alac_file)); + + newfile->samplesize = *samplesize; // as specified in initial 'alac' box, possibly incorrect + newfile->numchannels = numchannels; + newfile->bytespersample = (newfile->samplesize / 8) * numchannels; + + set_endian(); + alac_set_info(newfile, config); + + *samplesize = newfile->setinfo_sample_size; + *samplerate = newfile->setinfo_8a_rate; + + return newfile; +} + diff -urN faad2-2.7/frontend/audio.c faad2-2.7-patched/frontend/audio.c --- faad2-2.7/frontend/audio.c 2008-09-19 18:50:17.000000000 -0400 +++ faad2-2.7-patched/frontend/audio.c 2010-05-16 18:36:31.000000000 -0400 @@ -40,7 +40,7 @@ audio_file *open_audio_file(char *infile, int samplerate, int channels, - int outputFormat, int fileType, long channelMask) + int outputFormat, int fileType, long channelMask, unsigned long expectedSamples) { audio_file *aufile = malloc(sizeof(audio_file)); @@ -48,7 +48,7 @@ aufile->samplerate = samplerate; aufile->channels = channels; - aufile->total_samples = 0; + aufile->total_samples = expectedSamples; aufile->fileType = fileType; aufile->channelMask = channelMask; @@ -95,6 +95,8 @@ write_wav_header(aufile); } + aufile->total_samples = 0; + return aufile; } @@ -118,6 +120,15 @@ return 0; } +int write_audio_file_raw(audio_file *aufile, void *sample_buffer, + unsigned int samples) +{ + aufile->total_samples += samples; + + return fwrite(sample_buffer, samples, aufile->bits_per_sample/8, aufile->sndfile); +} + + void close_audio_file(audio_file *aufile) { if ((aufile->fileType == OUTPUT_WAV) && (aufile->toStdio == 0)) @@ -141,12 +152,12 @@ unsigned char header[44]; unsigned char* p = header; unsigned int bytes = (aufile->bits_per_sample + 7) / 8; - float data_size = (float)bytes * aufile->total_samples; + double data_size = (double)bytes * aufile->total_samples; unsigned long word32; *p++ = 'R'; *p++ = 'I'; *p++ = 'F'; *p++ = 'F'; - word32 = (data_size + (44 - 8) < (float)MAXWAVESIZE) ? + word32 = (data_size + (44 - 8) < (double)MAXWAVESIZE) ? (unsigned long)data_size + (44 - 8) : (unsigned long)MAXWAVESIZE; *p++ = (unsigned char)(word32 >> 0); *p++ = (unsigned char)(word32 >> 8); diff -urN faad2-2.7/frontend/audio.h faad2-2.7-patched/frontend/audio.h --- faad2-2.7/frontend/audio.h 2007-11-01 08:33:29.000000000 -0400 +++ faad2-2.7-patched/frontend/audio.h 2010-05-16 18:36:31.000000000 -0400 @@ -54,8 +54,9 @@ } audio_file; audio_file *open_audio_file(char *infile, int samplerate, int channels, - int outputFormat, int fileType, long channelMask); + int outputFormat, int fileType, long channelMask, unsigned long expectedSamples); int write_audio_file(audio_file *aufile, void *sample_buffer, int samples, int offset); +int write_audio_file_rawS(audio_file *aufile, void *sample_buffer, int samples, int offset); void close_audio_file(audio_file *aufile); static int write_wav_header(audio_file *aufile); static int write_wav_extensible_header(audio_file *aufile, long channelMask); diff -urN faad2-2.7/frontend/main.c faad2-2.7-patched/frontend/main.c --- faad2-2.7/frontend/main.c 2008-09-22 13:55:09.000000000 -0400 +++ faad2-2.7-patched/frontend/main.c 2010-05-16 18:36:31.000000000 -0400 @@ -36,6 +36,8 @@ #include #endif +#define WITH_ALAC + #include #include #include @@ -55,7 +57,6 @@ #define MAX_CHANNELS 6 /* make this higher to support files with more channels */ - static int quiet = 0; static void faad_fprintf(FILE *stream, const char *fmt, ...) @@ -137,6 +138,31 @@ b->bytes_into_buffer = 0; } +static void lookforheader(aac_buffer *b) +{ + int i = 0; + while (!b->at_eof ) + { + if (b->bytes_into_buffer > 4) + { + if( ((b->buffer[0+i] == 0xff) && ((b->buffer[1+i] & 0xf6) == 0xf0)) || + (b->buffer[0+i] == 'A' && b->buffer[1+i] == 'D' && b->buffer[2+i] == 'I' && b->buffer[3+i] == 'F')) + { + fill_buffer(b); + break; + } else { + i++; + b->file_offset += 1; + b->bytes_consumed += 1; + b->bytes_into_buffer -= 1; + } + } else { + fill_buffer(b); + i = 0; + } + } +} + static int adts_sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,7350,0,0,0}; static int adts_parse(aac_buffer *b, int *bitrate, float *length) @@ -387,6 +413,8 @@ faad_fprintf(stdout, " -w Write output to stdio instead of a file.\n"); faad_fprintf(stdout, " -g Disable gapless decoding.\n"); faad_fprintf(stdout, " -q Quiet - suppresses status messages.\n"); + faad_fprintf(stdout, " -j X Jump - start output X seconds into track (MP4 files only).\n"); + faad_fprintf(stdout, " -e X End - end output X seconds into track (MP4 files only).\n"); faad_fprintf(stdout, "Example:\n"); faad_fprintf(stdout, " %s infile.aac\n", progName); faad_fprintf(stdout, " %s infile.mp4\n", progName); @@ -424,6 +452,8 @@ float length = 0; int first_time = 1; + int retval; + int streaminput = 0; aac_buffer b; @@ -439,17 +469,39 @@ } } - b.infile = fopen(aacfile, "rb"); - if (b.infile == NULL) + if (0 == strcmp(aacfile, "-")) { - /* unable to open file */ - faad_fprintf(stderr, "Error opening file: %s\n", aacfile); - return 1; + b.infile = stdin; +#ifdef _WIN32 + setmode(fileno(stdin), O_BINARY); +#endif + + } else + { + b.infile = fopen(aacfile, "rb"); + if (b.infile == NULL) + { + /* unable to open file */ + faad_fprintf(stderr, "Error opening file: %s\n", aacfile); + return 1; + } } - fseek(b.infile, 0, SEEK_END); - fileread = ftell(b.infile); - fseek(b.infile, 0, SEEK_SET); + retval = fseek(b.infile, 0, SEEK_END); +#ifdef _WIN32 + if (0 == strcmp(aacfile, "-")) { + retval = -1; + } +#endif + if (retval ) + { + faad_fprintf(stderr, "Input not seekable %s\n", aacfile); + fileread = -1; + streaminput = 1; + } else { + fileread = ftell(b.infile); + fseek(b.infile, 0, SEEK_SET); + }; if (!(b.buffer = (unsigned char*)malloc(FAAD_MIN_STREAMSIZE*MAX_CHANNELS))) { @@ -494,19 +546,39 @@ /* get AAC infos for printing */ header_type = 0; + if (streaminput == 1 ) + lookforheader(&b); + if ((b.buffer[0] == 0xFF) && ((b.buffer[1] & 0xF6) == 0xF0)) { - adts_parse(&b, &bitrate, &length); - fseek(b.infile, tagsize, SEEK_SET); - - bread = fread(b.buffer, 1, FAAD_MIN_STREAMSIZE*MAX_CHANNELS, b.infile); - if (bread != FAAD_MIN_STREAMSIZE*MAX_CHANNELS) - b.at_eof = 1; - else - b.at_eof = 0; - b.bytes_into_buffer = bread; - b.bytes_consumed = 0; - b.file_offset = tagsize; + if (streaminput ==1) + { + int frames, frame_length; + int samplerate; + float frames_per_sec, bytes_per_frame; + samplerate = adts_sample_rates[(b.buffer[2]&0x3c)>>2]; + frame_length = ((((unsigned int)b.buffer[3] & 0x3)) << 11) + | (((unsigned int)b.buffer[4]) << 3) | (b.buffer[5] >> 5); + + frames_per_sec = (float)samplerate/1024.0f; + bytes_per_frame = (float)frame_length/(float)(1000); + bitrate = (int)(8. * bytes_per_frame * frames_per_sec + 0.5); + length = 1; + faad_fprintf(stderr, "Streamed input format samplerate %d channels %d.\n",samplerate,channels); + + } else { + adts_parse(&b, &bitrate, &length); + fseek(b.infile, tagsize, SEEK_SET); + + bread = fread(b.buffer, 1, FAAD_MIN_STREAMSIZE*MAX_CHANNELS, b.infile); + if (bread != FAAD_MIN_STREAMSIZE*MAX_CHANNELS) + b.at_eof = 1; + else + b.at_eof = 0; + b.bytes_into_buffer = bread; + b.bytes_consumed = 0; + b.file_offset = tagsize; + } header_type = 1; } else if (memcmp(b.buffer, "ADIF", 4) == 0) { @@ -538,7 +610,8 @@ if (b.buffer) free(b.buffer); NeAACDecClose(hDecoder); - fclose(b.infile); + if (b.infile != stdin) + fclose(b.infile); return 1; } advance_buffer(&b, bread); @@ -564,7 +637,8 @@ if (infoOnly) { NeAACDecClose(hDecoder); - fclose(b.infile); + if (b.infile != stdin) + fclose(b.infile); if (b.buffer) free(b.buffer); return 0; @@ -611,17 +685,18 @@ if (!to_stdout) { aufile = open_audio_file(sndfile, frameInfo.samplerate, frameInfo.channels, - outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo)); + outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo), 0); } else { aufile = open_audio_file("-", frameInfo.samplerate, frameInfo.channels, - outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo)); + outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo), 0); } if (aufile == NULL) { if (b.buffer) free(b.buffer); NeAACDecClose(hDecoder); - fclose(b.infile); + if (b.infile != stdin) + fclose(b.infile); return 0; } } else { @@ -662,7 +737,8 @@ fclose(adtsFile); } - fclose(b.infile); + if (b.infile != stdin) + fclose(b.infile); if (!first_time && !adts_out) close_audio_file(aufile); @@ -702,27 +778,27 @@ return -1; } + + static const unsigned long srates[] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 }; -static int decodeMP4file(char *mp4file, char *sndfile, char *adts_fn, int to_stdout, +static int decodeMP4fileAAC(mp4ff_t *infile, char *sndfile, char *adts_fn, int to_stdout, int outputFormat, int fileType, int downMatrix, int noGapless, - int infoOnly, int adts_out, float *song_length) + int infoOnly, int adts_out, float *song_length, float seek_to, float seek_end) { int track; unsigned long samplerate; unsigned char channels; void *sample_buffer; - mp4ff_t *infile; - long sampleId, numSamples; + long sampleId, numSamples, startSampleId, endSampleId; audio_file *aufile; - FILE *mp4File; FILE *adtsFile; unsigned char *adtsData; int adtsDataSize; @@ -746,16 +822,6 @@ unsigned int framesize; unsigned long timescale; - - /* initialise the callback structure */ - mp4ff_callback_t *mp4cb = malloc(sizeof(mp4ff_callback_t)); - - mp4File = fopen(mp4file, "rb"); - mp4cb->read = read_callback; - mp4cb->seek = seek_callback; - mp4cb->user_data = mp4File; - - hDecoder = NeAACDecOpen(); /* Set configuration */ @@ -775,21 +841,10 @@ } } - infile = mp4ff_open_read(mp4cb); - if (!infile) - { - /* unable to open file */ - faad_fprintf(stderr, "Error opening file: %s\n", mp4file); - return 1; - } - if ((track = GetAACTrack(infile)) < 0) { faad_fprintf(stderr, "Unable to find correct AAC sound track in the MP4 file.\n"); NeAACDecClose(hDecoder); - mp4ff_close(infile); - free(mp4cb); - fclose(mp4File); return 1; } @@ -803,9 +858,6 @@ /* If some error initializing occured, skip the file */ faad_fprintf(stderr, "Error initializing decoder library.\n"); NeAACDecClose(hDecoder); - mp4ff_close(infile); - free(mp4cb); - fclose(mp4File); return 1; } @@ -824,7 +876,7 @@ } /* print some mp4 file info */ - faad_fprintf(stderr, "%s file info:\n\n", mp4file); + faad_fprintf(stderr, "file info:\n\n"); { char *tag = NULL, *item = NULL; int k, j; @@ -865,20 +917,35 @@ if (infoOnly) { NeAACDecClose(hDecoder); - mp4ff_close(infile); - free(mp4cb); - fclose(mp4File); return 0; } numSamples = mp4ff_num_samples(infile, track); - for (sampleId = 0; sampleId < numSamples; sampleId++) + startSampleId = 0; + endSampleId = 0; + + if (seek_to > 0.1) { + int32_t sample = mp4ff_find_sample(infile, track, (int64_t)(seek_to * timescale), NULL); + if (sample > 0 && sample < numSamples) + startSampleId = sample; + } + + if (seek_end > 0.1) { + int32_t sample = mp4ff_find_sample(infile, track, (int64_t)(seek_end * timescale), NULL); + if (sample > 0 && sample <= numSamples) + endSampleId = sample; + } + + for (sampleId = startSampleId; sampleId < numSamples; sampleId++) { int rc; long dur; unsigned int sample_count; unsigned int delay = 0; + + if (endSampleId && endSampleId == sampleId) + break; /* get acces unit from MP4 file */ buffer = NULL; @@ -890,9 +957,6 @@ { faad_fprintf(stderr, "Reading from MP4 file failed.\n"); NeAACDecClose(hDecoder); - mp4ff_close(infile); - free(mp4cb); - fclose(mp4File); return 1; } @@ -947,20 +1011,19 @@ if(!to_stdout) { aufile = open_audio_file(sndfile, frameInfo.samplerate, frameInfo.channels, - outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo)); + outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo), + mp4ff_get_track_duration(infile, track) * channels); } else { #ifdef _WIN32 setmode(fileno(stdout), O_BINARY); #endif aufile = open_audio_file("-", frameInfo.samplerate, frameInfo.channels, - outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo)); + outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo), + mp4ff_get_track_duration(infile, track) * channels); } if (aufile == NULL) { NeAACDecClose(hDecoder); - mp4ff_close(infile); - free(mp4cb); - fclose(mp4File); return 0; } } @@ -973,7 +1036,7 @@ if (percent > old_percent) { old_percent = percent; - sprintf(percents, "%d%% decoding %s.", percent, mp4file); + sprintf(percents, "%d%% decoding.", percent); faad_fprintf(stderr, "%s\r", percents); #ifdef _WIN32 SetConsoleTitle(percents); @@ -1000,27 +1063,232 @@ fclose(adtsFile); } - mp4ff_close(infile); - if (!first_time && !adts_out) close_audio_file(aufile); - free(mp4cb); - fclose(mp4File); - return frameInfo.error; } +static int GetALACTrack(mp4ff_t *infile) +{ + /* find ALAC track */ + int i, rc; + int numTracks = mp4ff_total_tracks(infile); + + for (i = 0; i < numTracks; i++) + { + if (mp4ff_get_track_type(infile, i) == TRACK_AUDIO_ALAC) + return i; + } + + /* can't decode this */ + return -1; +} + +#ifdef WITH_ALAC + +extern struct alac_file *alac_init(int * samplesize, int numchannels, unsigned long *samplerate, const char *config); +extern unsigned long alac_decode_frame(struct alac_file *alac, + unsigned char *inbuffer, + void *outbuffer, int *outputsize); + +static int decodeMP4fileALAC(mp4ff_t *infile, char *sndfile, int to_stdout, + int fileType, int downMatrix, + int infoOnly, float *song_length, float seek_to, float seek_end) +{ + int track; + unsigned long samplerate; + unsigned char channels; + unsigned long timescale; + int samplesize; + int outputFormat; + char sample_buffer[100*1024]; + + long sampleId, numSamples, startSampleId, endSampleId; + + audio_file *aufile; + struct alac_file *alac; + + unsigned char *buffer; + int buffer_size; + + char percents[200]; + int percent, old_percent = -1; + + if ((track = GetALACTrack(infile)) < 0) + { + faad_fprintf(stderr, "Unable to find correct ALAC sound track in the MP4 file.\n"); + return 1; + } + + samplerate = mp4ff_get_sample_rate(infile, track); /* quite possibly garbage */ + channels = mp4ff_get_channel_count(infile, track); + timescale = mp4ff_time_scale(infile, track); + samplesize = mp4ff_get_sample_size(infile, track); + + buffer = NULL; + buffer_size = 0; + mp4ff_get_decoder_config(infile, track, &buffer, &buffer_size); + + alac = alac_init(&samplesize, channels, &samplerate, buffer); /* updates samplesize & samplerate from codec config */ + if (buffer) + free(buffer); + + switch (samplesize) { + + case 16: + outputFormat = FAAD_FMT_16BIT; + break; + case 24: + outputFormat = FAAD_FMT_24BIT; + break; + case 32: + outputFormat = FAAD_FMT_32BIT; + break; + default: + faad_fprintf(stderr, "Unsupported sample size %d for ALAC file\n", samplesize); + return 1; + } + + /* print some mp4 file info */ + faad_fprintf(stderr, "file info:\n\n"); + { + char *tag = NULL, *item = NULL; + int k, j; + long samples = mp4ff_num_samples(infile, track); + float f = 1024.0; + float seconds; + + seconds = (float)mp4ff_get_track_duration(infile, track)/(float)samplerate; + + *song_length = seconds; + + faad_fprintf(stderr, "%.3f secs, %d ch, samplerate=%ld, timescale=%ld\n\n", + seconds, channels, samplerate, timescale); + +#define PRINT_MP4_METADATA +#ifdef PRINT_MP4_METADATA + j = mp4ff_meta_get_num_items(infile); + for (k = 0; k < j; k++) + { + if (mp4ff_meta_get_by_index(infile, k, &item, &tag)) + { + if (item != NULL && tag != NULL) + { + faad_fprintf(stderr, "%s: %s\n", item, tag); + free(item); item = NULL; + free(tag); tag = NULL; + } + } + } + if (j > 0) faad_fprintf(stderr, "\n"); +#endif + } + + if (infoOnly) + return 0; + + /* open the sound file now that the number of channels are known */ + if(!to_stdout) + { + aufile = open_audio_file(sndfile, samplerate, channels, + outputFormat, fileType, 0, mp4ff_get_track_duration(infile, track) * channels); + } else { +#ifdef _WIN32 + setmode(fileno(stdout), O_BINARY); +#endif + aufile = open_audio_file("-", samplerate, channels, + outputFormat, fileType, 0, mp4ff_get_track_duration(infile, track) * channels); + } + if (aufile == NULL) + return 0; + + numSamples = mp4ff_num_samples(infile, track); + + startSampleId = 0; + endSampleId = 0; + + if (seek_to > 0.1) { + int32_t sample = mp4ff_find_sample(infile, track, (int64_t)(seek_to * timescale), NULL); + if (sample > 0 && sample < numSamples) + startSampleId = sample; + } + + if (seek_end > 0.1) { + int32_t sample = mp4ff_find_sample(infile, track, (int64_t)(seek_end * timescale), NULL); + if (sample > 0 && sample <= numSamples) + endSampleId = sample; + } + + for (sampleId = startSampleId; sampleId < numSamples; sampleId++) + { + int rc; + long dur; + long sample_count; + unsigned int delay = 0; + int output_len; + + /* get acces unit from MP4 file */ + buffer = NULL; + buffer_size = 0; + + if (endSampleId && endSampleId == sampleId) + break; + + dur = mp4ff_get_sample_duration(infile, track, sampleId); + rc = mp4ff_read_sample(infile, track, sampleId, &buffer, &buffer_size); + if (rc == 0) + { + faad_fprintf(stderr, "Reading from MP4 file failed.\n"); + close_audio_file(aufile); + return 1; + } + + output_len = sizeof sample_buffer; + sample_count = alac_decode_frame(alac, buffer, sample_buffer, &output_len); + + if (buffer) free(buffer); + + percent = min((int)(sampleId*100)/numSamples, 100); + if (percent > old_percent) + { + old_percent = percent; + sprintf(percents, "%d%% decoding.", percent); + faad_fprintf(stderr, "%s\r", percents); +#ifdef _WIN32 + SetConsoleTitle(percents); +#endif + } + + if (sample_count > 0) + { + if (write_audio_file_raw(aufile, sample_buffer, sample_count, delay) == 0) + break; + } + + if (sample_count < 0) + break; + } + + close_audio_file(aufile); + + return !(sampleId > startSampleId); +} + +#endif /* WITH_ALAC */ + int main(int argc, char *argv[]) { int result; int infoOnly = 0; int writeToStdio = 0; + int readFromStdin = 0; int object_type = LC; int def_srate = 0; int downMatrix = 0; int format = 1; int outputFormat = FAAD_FMT_16BIT; + int outputFormatSet = 0; int outfile_set = 0; int adts_out = 0; int old_format = 0; @@ -1031,6 +1299,8 @@ char aacFileName[255]; char audioFileName[255]; char adtsFileName[255]; + float seekTo = 0; + float seekEnd = 0; unsigned char header[8]; float length = 0; FILE *hMP4File; @@ -1063,11 +1333,13 @@ { "info", 0, 0, 'i' }, { "stdio", 0, 0, 'w' }, { "stdio", 0, 0, 'g' }, + { "seek", 1, 0, 'j' }, + { "seek_end", 1, 0, 'e' }, { "help", 0, 0, 'h' }, { 0, 0, 0, 0 } }; - c = getopt_long(argc, argv, "o:a:s:f:b:l:wgdhitq", + c = getopt_long(argc, argv, "o:a:s:f:b:l:j:e:wgdhitq", long_options, &option_index); if (c == -1) @@ -1124,6 +1396,7 @@ outputFormat = atoi(dr); if ((outputFormat < 1) || (outputFormat > 5)) showHelp = 1; + outputFormatSet = 1; } } break; @@ -1146,6 +1419,18 @@ } } break; + case 'j': + if (optarg) + { + seekTo = atof(optarg); + } + break; + case 'e': + if (optarg) + { + seekEnd = atof(optarg); + } + break; case 't': old_format = 1; break; @@ -1167,13 +1452,18 @@ case 'q': quiet = 1; break; - default: + default: break; } } faad_fprintf(stderr, " *********** Ahead Software MPEG-4 AAC Decoder V%s ******************\n\n", FAAD2_VERSION); + faad_fprintf(stderr, " Patched for Squeezebox Server:\n"); + faad_fprintf(stderr, " * ALAC decoder integrated\n"); + faad_fprintf(stderr, " * Seeking support with -j and -e switches\n"); + faad_fprintf(stderr, " * STDIN support\n"); + faad_fprintf(stderr, " * Source at http://svn.slimdevices.com/repos/slim/7.5/trunk/vendor/faad2\n\n"); faad_fprintf(stderr, " Build: %s\n", __DATE__); faad_fprintf(stderr, " Copyright 2002-2004: Ahead Software AG\n"); faad_fprintf(stderr, " http://www.audiocoding.com\n"); @@ -1229,23 +1519,119 @@ } /* check for mp4 file */ - mp4file = 0; - hMP4File = fopen(aacFileName, "rb"); - if (!hMP4File) - { - faad_fprintf(stderr, "Error opening file: %s\n", aacFileName); - return 1; + if (0 == strcmp(aacFileName, "-")) { + faad_fprintf(stderr, "Reading from stdin: %s\n", aacFileName); + readFromStdin = 1; + hMP4File = stdin; +#ifdef _WIN32 + setmode(fileno(stdin), O_BINARY); +#endif + + } else { + + mp4file = 0; + hMP4File = fopen(aacFileName, "rb"); + if (!hMP4File) + { + faad_fprintf(stderr, "Error opening file: %s\n", aacFileName); + return 1; + } } + fread(header, 1, 8, hMP4File); - fclose(hMP4File); + + if (! readFromStdin ) + fclose(hMP4File); + if (header[4] == 'f' && header[5] == 't' && header[6] == 'y' && header[7] == 'p') mp4file = 1; + if (!mp4file && (seekTo != 0 || seekEnd != 0)) { + faad_fprintf(stderr, "Warning: can only seek in MP4 files"); + } + if (mp4file) { - result = decodeMP4file(aacFileName, audioFileName, adtsFileName, writeToStdio, - outputFormat, format, downMatrix, noGapless, infoOnly, adts_out, &length); + mp4ff_t *infile; + FILE *mp4File; + mp4ff_callback_t *mp4cb; + + if (def_srate) + { + faad_fprintf(stderr, "Cannot resample MP4 file %s\n", aacFileName); + return 1; + } + + /* initialise the callback structure */ + mp4cb = malloc(sizeof(mp4ff_callback_t)); + + mp4File = fopen(aacFileName , "rb"); + mp4cb->read = read_callback; + mp4cb->seek = seek_callback; + mp4cb->user_data = mp4File; + + infile = mp4ff_open_read(mp4cb); + if (!infile) + { + /* unable to open file */ + faad_fprintf(stderr, "Error opening file: %s\n", mp4file); + free(mp4cb); + fclose(mp4File); + return 1; + } + + if (GetALACTrack(infile) < 0) { + result = decodeMP4fileAAC(infile, audioFileName, adtsFileName, writeToStdio, + outputFormat, format, downMatrix, noGapless, infoOnly, adts_out, &length, seekTo, seekEnd); + } else { + +#ifdef WITH_ALAC + if (adts_out) + { + faad_fprintf(stderr, "Cannot output ADTS format from ALAC file %s\n", aacFileName); + mp4ff_close(infile); + free(mp4cb); + fclose(mp4File); + return 1; + } + + if (outputFormatSet) + { + faad_fprintf(stderr, "Cannot specify output format for ALAC file %s\n", aacFileName); + mp4ff_close(infile); + free(mp4cb); + fclose(mp4File); + return 1; + } + + result = decodeMP4fileALAC(infile, audioFileName, writeToStdio, + format, downMatrix, infoOnly, &length, seekTo, seekEnd); +#else + faad_fprintf(stderr, "Unsupported ALAC file %s\n", aacFileName); + mp4ff_close(infile); + free(mp4cb); + fclose(mp4File); + return 1; +#endif + } + + mp4ff_close(infile); + free(mp4cb); + fclose(mp4File); + } else { + + if (readFromStdin == 1) { + ungetc(header[7],hMP4File); + ungetc(header[6],hMP4File); + ungetc(header[5],hMP4File); + ungetc(header[4],hMP4File); + ungetc(header[3],hMP4File); + ungetc(header[2],hMP4File); + ungetc(header[1],hMP4File); + ungetc(header[0],hMP4File); + } + result = decodeAACfile(aacFileName, audioFileName, adtsFileName, writeToStdio, def_srate, object_type, outputFormat, format, downMatrix, infoOnly, adts_out, old_format, &length); diff -urN faad2-2.7/frontend/stdint_win.h faad2-2.7-patched/frontend/stdint_win.h --- faad2-2.7/frontend/stdint_win.h 1969-12-31 19:00:00.000000000 -0500 +++ faad2-2.7-patched/frontend/stdint_win.h 2010-05-16 18:36:31.000000000 -0400 @@ -0,0 +1,14 @@ + +#ifndef ALAC_STDINT_WIN_H__ +#define ALAC_STDINT_WIN_H__ + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; + +#endif // ALAC_STDINT_WIN_H__ \ No newline at end of file diff -urN faad2-2.7/libfaad/fixed.h faad2-2.7-patched/libfaad/fixed.h --- faad2-2.7/libfaad/fixed.h 2007-11-01 08:33:30.000000000 -0400 +++ faad2-2.7-patched/libfaad/fixed.h 2010-05-16 18:36:38.000000000 -0400 @@ -152,7 +152,7 @@ *y1 = MUL_F(x1, c1) + MUL_F(x2, c2); *y2 = MUL_F(x2, c1) - MUL_F(x1, c2); } -#endif +#endif /* defined(_WIN32) && !defined(_WIN32_WCE) */ #elif defined(__GNUC__) && defined (__arm__) @@ -230,12 +230,15 @@ *y2 = yt2 << (FRAC_SIZE-FRAC_BITS); } -#else +#else /* defined(__GNUC__) && defined (__arm__) */ +#ifndef PADRE /* multiply with real shift */ #define MUL_R(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (REAL_BITS-1))) >> REAL_BITS) /* multiply with coef shift */ #define MUL_C(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (COEF_BITS-1))) >> COEF_BITS) +#endif + /* multiply with fractional shift */ #if defined(_WIN32_WCE) && defined(_ARM_) /* eVC for PocketPC has an intrinsic function that returns only the high 32 bits of a 32x32 bit multiply */ @@ -243,7 +246,7 @@ { return _MulHigh(A,B) << (32-FRAC_BITS); } -#else +#else /* defined(_WIN32_WCE) && defined(_ARM_) */ #ifdef __BFIN__ #define _MulHigh(X,Y) ({ int __xxo; \ asm ( \ @@ -260,12 +263,93 @@ "a1 = a1 >>> 16;\n\t" \ "%0 = (a0 += a1);\n\t" \ : "=d" (__xxo) : "d" (X), "d" (Y) : "A0","A1"); __xxo; }) -#else +#elif defined(__GNUC__) && defined (PADRE) +static INLINE real_t MUL_R(real_t A, real_t B) +{ + real_t __hi; + real_t __lo; + real_t __result; + __asm__ __volatile__ ( + " nop\n" + " nop\n" + " smul %3, %4, %0\n" + " mov %%y, %1\n" + " srl %0, %5, %0\n" + " sll %1, %6, %1\n" + " add %0, %1, %2\n" + : "=&r"(__lo), "=&r"(__hi), "=r"(__result) + : "%r"(A), "r"(B), "r"(REAL_BITS), "r"(32 - REAL_BITS) + : "cc" + ); + return __result; +} + +static INLINE real_t MUL_C(real_t A, real_t B) +{ + real_t __hi; + real_t __lo; + real_t __result; + __asm__ __volatile__ ( + " nop\n" + " nop\n" + " smul %3, %4, %0\n" + " mov %%y, %1\n" + " srl %0, %5, %0\n" + " sll %1, %6, %1\n" + " add %0, %1, %2\n" + : "=&r"(__lo), "=&r"(__hi), "=r"(__result) + : "%r"(A), "r"(B), "r"(COEF_BITS), "r"(32 - COEF_BITS) + : "cc" + ); + return __result; +} + +static INLINE real_t MUL_Q2(real_t A, real_t B) +{ + real_t __hi; + real_t __lo; + real_t __result; + __asm__ __volatile__ ( + " nop\n" + " nop\n" + " smul %3, %4, %0\n" + " mov %%y, %1\n" + " srl %0, %5, %0\n" + " sll %1, %6, %1\n" + " add %0, %1, %2\n" + : "=&r"(__lo), "=&r"(__hi), "=r"(__result) + : "%r"(A), "r"(B), "r"(Q2_BITS), "r"(32 - Q2_BITS) + : "cc" + ); + return __result; +} + +static INLINE real_t _MulHigh(real_t x, real_t y) +{ + register int z; + __asm__ __volatile__ ( + " nop\n" + " nop\n" + " smul %1,%2,%%g0\n" + " mov %%y,%0\n" + : "=r"(z) + : "r"(x), "r"(y) + ); + return z; +} + +static INLINE real_t MUL_F(real_t A, real_t B) +{ + return _MulHigh(A, B) << (FRAC_SIZE-FRAC_BITS); +} +#else /* __BFIN__ */ #define _MulHigh(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (FRAC_SIZE-1))) >> FRAC_SIZE) #define MUL_F(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (FRAC_BITS-1))) >> FRAC_BITS) #endif #endif +#ifndef PADRE #define MUL_Q2(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (Q2_BITS-1))) >> Q2_BITS) +#endif #define MUL_SHIFT6(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (6-1))) >> 6) #define MUL_SHIFT23(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (23-1))) >> 23)