From e184ef1027ba8f41aca65dbae2af05662b23c722 Mon Sep 17 00:00:00 2001 From: Mohamed Tarek Date: Mon, 6 Jul 2009 22:40:45 +0000 Subject: Adding support for rm playback. Only cook codec is supported for now and no seeking. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21695 a1c6a512-1295-4272-9138-f99709370657 --- apps/SOURCES | 1 + apps/codecs/SOURCES | 1 + apps/codecs/codecs.make | 4 +- apps/codecs/cook.c | 144 +++++++++++ apps/codecs/libcook/Makefile.test | 4 +- apps/codecs/libcook/SOURCES | 3 + apps/codecs/libcook/bitstream.c | 85 ++----- apps/codecs/libcook/bitstream.h | 21 +- apps/codecs/libcook/bswap.h | 173 ++++++++----- apps/codecs/libcook/cook.c | 15 +- apps/codecs/libcook/cook.h | 4 +- apps/codecs/libcook/cook_fixpoint.h | 53 ++-- apps/codecs/libcook/cookdata_fixpoint.h | 6 +- apps/codecs/libcook/libcook.make | 18 ++ apps/codecs/libcook/main.c | 25 +- apps/codecs/librm/rm.c | 250 ++++++++++--------- apps/codecs/librm/rm.h | 32 ++- apps/filetypes.c | 2 + apps/metadata.c | 11 + apps/metadata.h | 1 + apps/metadata/metadata_parsers.h | 1 + apps/metadata/rm.c | 420 ++++++++++++++++++++++++++++++++ 22 files changed, 957 insertions(+), 317 deletions(-) create mode 100644 apps/codecs/cook.c create mode 100644 apps/codecs/libcook/SOURCES create mode 100644 apps/codecs/libcook/libcook.make create mode 100644 apps/metadata/rm.c diff --git a/apps/SOURCES b/apps/SOURCES index f3acef1739..8166dbe4e2 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -167,6 +167,7 @@ metadata/wave.c metadata/wavpack.c metadata/a52.c metadata/asap.c +metadata/rm.c #endif #ifdef HAVE_TAGCACHE tagcache.c diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES index 4e4f994a2a..44a8498fa9 100644 --- a/apps/codecs/SOURCES +++ b/apps/codecs/SOURCES @@ -9,6 +9,7 @@ wavpack.c #ifndef RB_PROFILE alac.c #endif +cook.c mpc.c wma.c sid.c diff --git a/apps/codecs/codecs.make b/apps/codecs/codecs.make index 7b56ced575..a8c0085cb4 100644 --- a/apps/codecs/codecs.make +++ b/apps/codecs/codecs.make @@ -33,6 +33,7 @@ include $(APPSDIR)/codecs/libspeex/libspeex.make include $(APPSDIR)/codecs/libtremor/libtremor.make include $(APPSDIR)/codecs/libwavpack/libwavpack.make include $(APPSDIR)/codecs/libwma/libwma.make +include $(APPSDIR)/codecs/libcook/libcook.make # compile flags for codecs CODECFLAGS = $(CFLAGS) -I$(APPSDIR)/codecs -I$(APPSDIR)/codecs/lib \ @@ -47,7 +48,7 @@ CODEC_CRT0 := $(CODECDIR)/codec_crt0.o CODECLIBS := $(DEMACLIB) $(A52LIB) $(ALACLIB) $(ASAPLIB) \ $(FAADLIB) $(FFMPEGFLACLIB) $(M4ALIB) $(MADLIB) $(MUSEPACKLIB) \ - $(SPCLIB) $(SPEEXLIB) $(TREMORLIB) $(WAVPACKLIB) $(WMALIB) \ + $(SPCLIB) $(SPEEXLIB) $(TREMORLIB) $(WAVPACKLIB) $(WMALIB) $(COOKLIB) \ $(CODECLIB) $(CODECS): $(CODEC_CRT0) $(CODECLINK_LDS) @@ -73,6 +74,7 @@ $(CODECDIR)/ape.codec : $(CODECDIR)/libdemac.a $(CODECDIR)/wma.codec : $(CODECDIR)/libwma.a $(CODECDIR)/wavpack_enc.codec: $(CODECDIR)/libwavpack.a $(CODECDIR)/asap.codec : $(CODECDIR)/libasap.a +$(CODECDIR)/cook.codec : $(CODECDIR)/libcook.a $(CODECS): $(CODECLIB) # this must be last in codec dependency list diff --git a/apps/codecs/cook.c b/apps/codecs/cook.c new file mode 100644 index 0000000000..7b4b8e7461 --- /dev/null +++ b/apps/codecs/cook.c @@ -0,0 +1,144 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * Copyright (C) 2009 Mohamed Tarek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include + +#include "logf.h" +#include "codeclib.h" +#include "inttypes.h" +#include "libcook/cook.h" + +#define DATA_HEADER_SIZE 18 /* size of DATA chunk header in a rm file */ + +CODEC_HEADER + +RMContext rmctx; +RMPacket pkt; +COOKContext q; + +static void init_rm(RMContext *rmctx) +{ + memcpy(rmctx, ci->id3->id3v2buf, sizeof(RMContext)); +} + +/* this is the codec entry point */ +enum codec_status codec_main(void) +{ + static size_t buff_size; + int datasize, res, consumed,i; + uint8_t *bit_buffer; + int16_t outbuf[2048] __attribute__((aligned(32))); + uint16_t fs,sps,h; + uint32_t packet_count; + int scrambling_unit_size; + +next_track: + if (codec_init()) { + DEBUGF("codec init failed\n"); + return CODEC_ERROR; + } + while (!*ci->taginfo_ready && !ci->stop_codec) + ci->sleep(1); + + codec_set_replaygain(ci->id3); + ci->memset(&rmctx,0,sizeof(RMContext)); + ci->memset(&pkt,0,sizeof(RMPacket)); + ci->memset(&q,0,sizeof(COOKContext)); + + init_rm(&rmctx); + + ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); + ci->configure(DSP_SET_SAMPLE_DEPTH, 16); + ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ? + STEREO_MONO : STEREO_INTERLEAVED); + + packet_count = rmctx.nb_packets; + rmctx.audio_framesize = rmctx.block_align; + rmctx.block_align = rmctx.sub_packet_size; + fs = rmctx.audio_framesize; + sps= rmctx.block_align; + h = rmctx.sub_packet_h; + scrambling_unit_size = h*fs; + + res =cook_decode_init(&rmctx, &q); + if(res < 0) { + DEBUGF("failed to initialize cook decoder\n"); + return CODEC_ERROR; + } + + ci->set_elapsed(0); + ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); + + /* The main decoder loop */ + while (1) + { + /*if (ci->seek_time) { + + ci->set_elapsed(ci->seek_time); + n = ci->seek_time/10; + memset(buf,0,BUF_SIZE); + ci->seek_complete(); + }*/ + + while(packet_count) + { + bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); + consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); + if(consumed < 0) { + DEBUGF("rm_get_packet failed\n"); + return CODEC_ERROR; + } + /*DEBUGF(" version = %d\n" + " length = %d\n" + " stream = %d\n" + " timestamp= %d\n",pkt.version,pkt.length,pkt.stream_number,pkt.timestamp);*/ + + for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) + { + ci->yield(); + if (ci->stop_codec || ci->new_track) + goto done; + + res = cook_decode_frame(&rmctx,&q, outbuf, &datasize, pkt.frames[i], rmctx.block_align); + rmctx.frame_number++; + + /* skip the first two frames; no valid audio */ + if(rmctx.frame_number < 3) continue; + + if(res != rmctx.block_align) { + DEBUGF("codec error\n"); + return CODEC_ERROR; + } + + ci->pcmbuf_insert(outbuf, NULL, rmctx.samples_pf_pc / rmctx.nb_channels); + ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i); + } + packet_count -= rmctx.audio_pkt_cnt; + rmctx.audio_pkt_cnt = 0; + ci->advance_buffer(consumed); + } + goto done; + + } + done : + if (ci->request_next_track()) + goto next_track; + + return CODEC_OK; +} diff --git a/apps/codecs/libcook/Makefile.test b/apps/codecs/libcook/Makefile.test index 493ab8f623..c8a3236935 100644 --- a/apps/codecs/libcook/Makefile.test +++ b/apps/codecs/libcook/Makefile.test @@ -1,4 +1,4 @@ -CFLAGS = -Wall -O3 +CFLAGS = -Wall -O3 -DTEST -D"DEBUGF=printf" OBJS = main.o bitstream.o cook.o ../librm/rm.o cooktest: $(OBJS) gcc -o cooktest $(OBJS) @@ -7,4 +7,4 @@ cooktest: $(OBJS) $(CC) $(CFLAGS) -c -o $@ $< clean: - rm -f cooktest $(OBJS) *~ + rm -f cooktest $(OBJS) *~ output.wav diff --git a/apps/codecs/libcook/SOURCES b/apps/codecs/libcook/SOURCES new file mode 100644 index 0000000000..7b2cd967ea --- /dev/null +++ b/apps/codecs/libcook/SOURCES @@ -0,0 +1,3 @@ +cook.c +bitstream.c +../librm/rm.c diff --git a/apps/codecs/libcook/bitstream.c b/apps/codecs/libcook/bitstream.c index 4bc706ffb7..1375134b21 100644 --- a/apps/codecs/libcook/bitstream.c +++ b/apps/codecs/libcook/bitstream.c @@ -22,13 +22,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * @file libavcodec/bitstream.c - * bitstream api. - */ - #include "bitstream.h" +#ifdef ROCKBOX +#undef DEBUGF +#define DEBUGF(...) +#endif + const uint8_t ff_log2_run[32]={ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, @@ -46,24 +46,6 @@ const uint8_t ff_log2_run[32]={ * and should correctly use static arrays */ -#if 0 -attribute_deprecated av_alloc_size(2) -static void *ff_realloc_static(void *ptr, unsigned int size); - -static void *ff_realloc_static(void *ptr, unsigned int size) -{ - return av_realloc(ptr, size); -} - -void align_put_bits(PutBitContext *s) -{ -#ifdef ALT_BITSTREAM_WRITER - put_bits(s,( - s->index) & 7,0); -#else - put_bits(s,s->bit_left & 7,0); -#endif -} -#endif void ff_put_string(PutBitContext * pbc, const char *s, int put_zero) { @@ -75,30 +57,6 @@ void ff_put_string(PutBitContext * pbc, const char *s, int put_zero) put_bits(pbc, 8, 0); } -#if 0 -void ff_copy_bits(PutBitContext *pb, const uint8_t *src, int length) -{ - const uint16_t *srcw= (const uint16_t*)src; - int words= length>>4; - int bits= length&15; - int i; - - if(length==0) return; - - if(CONFIG_SMALL || words < 16 || put_bits_count(pb)&7){ - for(i=0; i>(16-bits)); -} -#endif - /* VLC decoding */ //#define DEBUG_VLC @@ -127,8 +85,7 @@ static int alloc_table(VLC *vlc, int size, int use_static) vlc->table_size += size; if (vlc->table_size > vlc->table_allocated) { if(use_static>1){ - printf("init_vlc() used with too little memory : table_size > allocated_memory\n"); - abort(); //cant do anything, init_vlc() is used with too little memory + DEBUGF("init_vlc() used with too little memory : table_size > allocated_memory\n"); } if (!vlc->table) @@ -151,7 +108,7 @@ static int build_table(VLC *vlc, int table_nb_bits, table_size = 1 << table_nb_bits; table_index = alloc_table(vlc, table_size, flags & (INIT_VLC_USE_STATIC|INIT_VLC_USE_NEW_STATIC)); #ifdef DEBUG_VLC - printf("new table index=%d size=%d code_prefix=%x n=%d\n", + DEBUGF("new table index=%d size=%d code_prefix=%x n=%d\n", table_index, table_size, code_prefix, n_prefix); #endif if (table_index < 0) @@ -175,15 +132,15 @@ static int build_table(VLC *vlc, int table_nb_bits, else GET_DATA(symbol, symbols, i, symbols_wrap, symbols_size); #if defined(DEBUG_VLC) && 0 - printf("i=%d n=%d code=0x%x\n", i, n, code); + DEBUGF("i=%d n=%d code=0x%x\n", i, n, code); #endif /* if code matches the prefix, it is in the table */ n -= n_prefix; if(flags & INIT_VLC_LE) - code_prefix2= code & (n_prefix>=32 ? 0xffffffff : (1 << n_prefix)-1); + code_prefix2= code & (n_prefix>=32 ? (int)0xffffffff : (1 << n_prefix)-1); else code_prefix2= code >> n; - if (n > 0 && code_prefix2 == code_prefix) { + if (n > 0 && code_prefix2 == (int)code_prefix) { if (n <= table_nb_bits) { /* no need to add another table */ j = (code << (table_nb_bits - n)) & (table_size - 1); @@ -192,11 +149,11 @@ static int build_table(VLC *vlc, int table_nb_bits, if(flags & INIT_VLC_LE) j = (code >> n_prefix) + (k<> ((flags & INIT_VLC_LE) ? n_prefix : n)) & ((1 << table_nb_bits) - 1); #ifdef DEBUG_VLC - printf("%4x: n=%d (subtable)\n", + DEBUGF("%4x: n=%d (subtable)\n", j, n); #endif /* compute table size */ @@ -282,7 +239,7 @@ int init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes, if(vlc->table_size && vlc->table_size == vlc->table_allocated){ return 0; }else if(vlc->table_size){ - abort(); // fatal error, we are called on a partially initialized table + return -1; // fatal error, we are called on a partially initialized table } }else if(!(flags & INIT_VLC_USE_STATIC)) { vlc->table = NULL; @@ -296,7 +253,7 @@ int init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes, } #ifdef DEBUG_VLC - printf("build table nb_codes=%d\n", nb_codes); + DEBUGF("build table nb_codes=%d\n", nb_codes); #endif if (build_table(vlc, nb_bits, nb_codes, @@ -304,20 +261,16 @@ int init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes, codes, codes_wrap, codes_size, symbols, symbols_wrap, symbols_size, 0, 0, flags) < 0) { - free(&vlc->table); + //free(&vlc->table); return -1; } /* Changed the following condition to be true if table_size > table_allocated. * * This would be more sensible for static tables since we want warnings for * * memory shortages only. */ +#ifdef TEST if((flags & INIT_VLC_USE_NEW_STATIC) && vlc->table_size > vlc->table_allocated) - printf("needed %d had %d\n", vlc->table_size, vlc->table_allocated); + DEBUGF("needed %d had %d\n", vlc->table_size, vlc->table_allocated); +#endif return 0; } - -void free_vlc(VLC *vlc) -{ - free(&vlc->table); -} - diff --git a/apps/codecs/libcook/bitstream.h b/apps/codecs/libcook/bitstream.h index 085d0a1566..9be8e65690 100644 --- a/apps/codecs/libcook/bitstream.h +++ b/apps/codecs/libcook/bitstream.h @@ -18,15 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * @file libavcodec/bitstream.h - * bitstream api header. - */ +#ifndef BITSTREAM_H +#define BITSTREAM_H -#ifndef AVCODEC_BITSTREAM_H -#define AVCODEC_BITSTREAM_H - -#include +#include #include #include #include @@ -51,7 +46,7 @@ //#define ALT_BITSTREAM_WRITER //#define ALIGNED_BITSTREAM_WRITER #if !defined(LIBMPEG2_BITSTREAM_READER) && !defined(A32_BITSTREAM_READER) && !defined(ALT_BITSTREAM_READER) -# if ARCH_ARM +# if defined(ARCH_ARM) # define A32_BITSTREAM_READER # else # define ALT_BITSTREAM_READER @@ -62,7 +57,7 @@ extern const uint8_t ff_reverse[256]; -#if ARCH_X86 +#if defined(ARCH_X86) // avoid +32 for shift optimization (gcc should do that ...) static inline int32_t NEG_SSR32( int32_t a, int8_t s){ __asm__ ("sarl %1, %0\n\t" @@ -226,7 +221,7 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value) } else { bit_buf<<=bit_left; bit_buf |= value >> (n - bit_left); -#if !HAVE_FAST_UNALIGNED +#if !defined(HAVE_FAST_UNALIGNED) if (3 & (intptr_t) s->buf_ptr) { AV_WB32(s->buf_ptr, bit_buf); } else @@ -736,6 +731,7 @@ static inline unsigned int show_bits_long(GetBitContext *s, int n){ } } +#if 0 static inline int check_marker(GetBitContext *s, const char *msg) { int bit= get_bits1(s); @@ -744,6 +740,7 @@ static inline int check_marker(GetBitContext *s, const char *msg) return bit; } +#endif /** * init GetBitContext. @@ -963,4 +960,4 @@ static inline int decode210(GetBitContext *gb){ return 2 - get_bits1(gb); } -#endif /* AVCODEC_BITSTREAM_H */ +#endif /* BITSTREAM_H */ diff --git a/apps/codecs/libcook/bswap.h b/apps/codecs/libcook/bswap.h index 443cd1c3f9..b083d10ed0 100644 --- a/apps/codecs/libcook/bswap.h +++ b/apps/codecs/libcook/bswap.h @@ -1,86 +1,137 @@ -/* - * copyright (c) 2006 Michael Niedermayer - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - /** - * @file libavutil/bswap.h - * byte swapping routines + * @file bswap.h + * byte swap. */ -#ifndef AVUTIL_BSWAP_H -#define AVUTIL_BSWAP_H - -#include -//#include "ffmpeg_config.h" -//#include "common.h" - -#if ARCH_ARM -# include "arm/bswap.h" -#elif ARCH_BFIN -# include "bfin/bswap.h" -#elif ARCH_SH4 -# include "sh4/bswap.h" -#elif ARCH_X86 -# include "x86/bswap.h" -#endif +#ifndef __BSWAP_H__ +#define __BSWAP_H__ + +#ifdef HAVE_BYTESWAP_H +#include +#else -#ifndef bswap_16 -static inline uint16_t bswap_16(uint16_t x) +#ifdef ROCKBOX +#include "codecs.h" + +/* rockbox' optimised inline functions */ +#define bswap_16(x) swap16(x) +#define bswap_32(x) swap32(x) + +static inline uint64_t ByteSwap64(uint64_t x) { - x= (x>>8) | (x<<8); - return x; + union { + uint64_t ll; + struct { + uint32_t l,h; + } l; + } r; + r.l.l = bswap_32 (x); + r.l.h = bswap_32 (x>>32); + return r.ll; } -#endif +#define bswap_64(x) ByteSwap64(x) -#ifndef bswap_32 -static inline uint32_t bswap_32(uint32_t x) +#elif defined(ARCH_X86) +static inline unsigned short ByteSwap16(unsigned short x) { - x= ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF); - x= (x>>16) | (x<<16); + __asm("xchgb %b0,%h0" : + "=q" (x) : + "0" (x)); return x; } +#define bswap_16(x) ByteSwap16(x) + +static inline unsigned int ByteSwap32(unsigned int x) +{ +#if __CPU__ > 386 + __asm("bswap %0": + "=r" (x) : +#else + __asm("xchgb %b0,%h0\n" + " rorl $16,%0\n" + " xchgb %b0,%h0": + "=q" (x) : #endif + "0" (x)); + return x; +} +#define bswap_32(x) ByteSwap32(x) -#ifndef bswap_64 -static inline uint64_t bswap_64(uint64_t x) +static inline unsigned long long int ByteSwap64(unsigned long long int x) { -#if 0 - x= ((x<< 8)&0xFF00FF00FF00FF00ULL) | ((x>> 8)&0x00FF00FF00FF00FFULL); - x= ((x<<16)&0xFFFF0000FFFF0000ULL) | ((x>>16)&0x0000FFFF0000FFFFULL); - return (x>>32) | (x<<32); + register union { __extension__ uint64_t __ll; + uint32_t __l[2]; } __x; + asm("xchgl %0,%1": + "=r"(__x.__l[0]),"=r"(__x.__l[1]): + "0"(bswap_32((unsigned long)x)),"1"(bswap_32((unsigned long)(x>>32)))); + return __x.__ll; +} +#define bswap_64(x) ByteSwap64(x) + +#elif defined(ARCH_SH4) + +static inline uint16_t ByteSwap16(uint16_t x) { + __asm__("swap.b %0,%0":"=r"(x):"0"(x)); + return x; +} + +static inline uint32_t ByteSwap32(uint32_t x) { + __asm__( + "swap.b %0,%0\n" + "swap.w %0,%0\n" + "swap.b %0,%0\n" + :"=r"(x):"0"(x)); + return x; +} + +#define bswap_16(x) ByteSwap16(x) +#define bswap_32(x) ByteSwap32(x) + +static inline uint64_t ByteSwap64(uint64_t x) +{ + union { + uint64_t ll; + struct { + uint32_t l,h; + } l; + } r; + r.l.l = bswap_32 (x); + r.l.h = bswap_32 (x>>32); + return r.ll; +} +#define bswap_64(x) ByteSwap64(x) + #else - union { + +#define bswap_16(x) (((x) & 0x00ff) << 8 | ((x) & 0xff00) >> 8) + + +// code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. +#define bswap_32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +static inline uint64_t ByteSwap64(uint64_t x) +{ + union { uint64_t ll; - uint32_t l[2]; + uint32_t l[2]; } w, r; w.ll = x; r.l[0] = bswap_32 (w.l[1]); r.l[1] = bswap_32 (w.l[0]); return r.ll; -#endif } -#endif +#define bswap_64(x) ByteSwap64(x) + +#endif /* !ARCH_X86 */ + +#endif /* !HAVE_BYTESWAP_H */ -// be2me ... big-endian to machine-endian -// le2me ... little-endian to machine-endian +// be2me ... BigEndian to MachineEndian +// le2me ... LittleEndian to MachineEndian -#ifdef WORDS_BIGENDIAN +#ifdef ROCKBOX_BIG_ENDIAN #define be2me_16(x) (x) #define be2me_32(x) (x) #define be2me_64(x) (x) @@ -96,4 +147,4 @@ static inline uint64_t bswap_64(uint64_t x) #define le2me_64(x) (x) #endif -#endif /* AVUTIL_BSWAP_H */ +#endif /* __BSWAP_H__ */ diff --git a/apps/codecs/libcook/cook.c b/apps/codecs/libcook/cook.c index 8caa3992bd..ba5fbab6a1 100644 --- a/apps/codecs/libcook/cook.c +++ b/apps/codecs/libcook/cook.c @@ -21,7 +21,7 @@ */ /** - * @file libavcodec/cook.c + * @file cook.c * Cook compatible decoder. Bastardization of the G.722.1 standard. * This decoder handles RealNetworks, RealAudio G2 data. * Cook is identified by the codec name cook in RM files. @@ -60,16 +60,15 @@ #define SUBBAND_SIZE 20 #define MAX_SUBPACKETS 5 //#define COOKDEBUG -#if 0 -#define DEBUGF(message,args ...) printf -#else +#ifndef COOKDEBUG +#undef DEBUGF #define DEBUGF(...) -#endif +#endif /** * Random bit stream generator. */ -static int inline cook_random(COOKContext *q) +static inline int cook_random(COOKContext *q) { q->random_state = q->random_state * 214013 + 2531011; /* typical RNG numbers */ @@ -200,7 +199,7 @@ static void decode_gain_info(GetBitContext *gb, int *gaininfo) i = 0; while (n--) { int index = get_bits(gb, 3); - int gain = get_bits1(gb) ? get_bits(gb, 4) - 7 : -1; + int gain = get_bits1(gb) ? (int)get_bits(gb, 4) - 7 : -1; while (i <= index) gaininfo[i++] = gain; } @@ -789,7 +788,7 @@ int cook_decode_init(RMContext *rmctx, COOKContext *q) return -1; - if(q->block_align >= UINT_MAX/2) + if(rmctx->block_align >= UINT16_MAX/2) return -1; q->gains1.now = q->gain_1; diff --git a/apps/codecs/libcook/cook.h b/apps/codecs/libcook/cook.h index ca982076ec..03d6d3254c 100644 --- a/apps/codecs/libcook/cook.h +++ b/apps/codecs/libcook/cook.h @@ -22,7 +22,7 @@ #ifndef _COOK_H #define _COOK_H -#include +#include #include "bitstream.h" #include "../librm/rm.h" #include "cookdata_fixpoint.h" @@ -99,4 +99,4 @@ int cook_decode_init(RMContext *rmctx, COOKContext *q); int cook_decode_frame(RMContext *rmctx,COOKContext *q, int16_t *outbuffer, int *data_size, const uint8_t *inbuffer, int buf_size); -#endif +#endif /*_COOK_H */ diff --git a/apps/codecs/libcook/cook_fixpoint.h b/apps/codecs/libcook/cook_fixpoint.h index 0f12b1340a..e416bc4ef5 100644 --- a/apps/codecs/libcook/cook_fixpoint.h +++ b/apps/codecs/libcook/cook_fixpoint.h @@ -53,29 +53,6 @@ static const FIXPU* cplscales[5] = { cplscale2, cplscale3, cplscale4, cplscale5, cplscale6 }; -/** - * Initialise fixed point implementation. - * Nothing to do for fixed point. - * - * @param q pointer to the COOKContext - */ -static inline int init_cook_math(COOKContext *q) -{ - return 0; -} - -/** - * Free resources used by floating point implementation. - * Nothing to do for fixed point. - * - * @param q pointer to the COOKContext - */ -static inline void free_cook_math(COOKContext *q) -{ - return; -} - - /** * Fixed point multiply by power of two. * @@ -167,7 +144,7 @@ static void scalar_dequant_math(COOKContext *q, int index, } } - +#ifdef TEST /** * The modulated lapped transform, this takes transform coefficients * and transforms them into timedomain samples. @@ -205,7 +182,35 @@ static inline void imlt_math(COOKContext *q, FIXP *in) q->mono_mdct_output[n + i] = fixp_mult_su(tmp, sincos_lookup[j]); } while (++i < n); } +#else +#include + +static inline void imlt_math(COOKContext *q, FIXP *in) +{ + const int n = q->samples_per_channel; + const int step = 4 << (10 - av_log2(n)); + int i = 0, j = step>>1; + + mdct_backward(2 * n, in, q->mono_mdct_output); + do { + FIXP tmp = q->mono_mdct_output[i]; + + q->mono_mdct_output[i] = + fixp_mult_su(-q->mono_mdct_output[n + i], sincos_lookup[j]); + q->mono_mdct_output[n + i] = fixp_mult_su(tmp, sincos_lookup[j+1]); + j += step; + } while (++i < n/2); + do { + FIXP tmp = q->mono_mdct_output[i]; + + j -= step; + q->mono_mdct_output[i] = + fixp_mult_su(-q->mono_mdct_output[n + i], sincos_lookup[j+1]); + q->mono_mdct_output[n + i] = fixp_mult_su(tmp, sincos_lookup[j]); + } while (++i < n); +} +#endif /** * Perform buffer overlapping. diff --git a/apps/codecs/libcook/cookdata_fixpoint.h b/apps/codecs/libcook/cookdata_fixpoint.h index b394c46a27..7a9440c664 100644 --- a/apps/codecs/libcook/cookdata_fixpoint.h +++ b/apps/codecs/libcook/cookdata_fixpoint.h @@ -26,7 +26,7 @@ * fixed point data types and constants */ -#include +#include typedef int32_t FIXP; /* Fixed point variable type */ typedef uint16_t FIXPU; /* Fixed point fraction 0<=x<1 */ @@ -39,11 +39,11 @@ typedef FIXP REAL_T; typedef struct { } realvars_t; - +#ifdef TEST #define cPI1_8 0xec83 /* 1pi/8 2^16 */ #define cPI2_8 0xb505 /* 2pi/8 2^16 */ #define cPI3_8 0x61f8 /* 3pi/8 2^16 */ - +#endif static const FIXPU sincos_lookup[2050] = { /* x_i = 2^16 sin(i 2pi/8192), 2^16 cos(i 2pi/8192); i=0..1024 */ 0x0000, 0xffff, 0x0032, 0xffff, 0x0065, 0xffff, 0x0097, 0xffff, diff --git a/apps/codecs/libcook/libcook.make b/apps/codecs/libcook/libcook.make new file mode 100644 index 0000000000..07836913d7 --- /dev/null +++ b/apps/codecs/libcook/libcook.make @@ -0,0 +1,18 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id:$ +# + +# libcook +COOKLIB := $(CODECDIR)/libcook.a +COOKLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libcook/SOURCES) +COOKLIB_OBJ := $(call c2obj, $(COOKLIB_SRC)) +OTHER_SRC += $(COOKLIB_SRC) + +$(COOKLIB): $(COOKLIB_OBJ) + $(SILENT)$(shell rm -f $@) + $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null \ No newline at end of file diff --git a/apps/codecs/libcook/main.c b/apps/codecs/libcook/main.c index 87f65845e8..fd20f98871 100644 --- a/apps/codecs/libcook/main.c +++ b/apps/codecs/libcook/main.c @@ -29,13 +29,6 @@ #include "cook.h" //#define DUMP_RAW_FRAMES -#ifndef DEBUGF -# if 0 -# define DEBUGF(message,args ...) printf -# else -# define DEBUGF(...) -# endif -#endif #define DATA_HEADER_SIZE 18 /* size of DATA chunk header in a rm file */ static unsigned char wav_header[44]={ @@ -151,8 +144,8 @@ int main(int argc, char *argv[]) /* copy the input rm file to a memory buffer */ uint8_t * filebuf = (uint8_t *)calloc((int)filesize(fd),sizeof(uint8_t)); - read(fd,filebuf,filesize(fd)); - + res = read(fd,filebuf,filesize(fd)); + fd_dec = open_wav("output.wav"); if (fd_dec < 0) { DEBUGF("Error creating output file\n"); @@ -166,27 +159,25 @@ int main(int argc, char *argv[]) sps= rmctx.block_align; h = rmctx.sub_packet_h; cook_decode_init(&rmctx,&q); - DEBUGF("nb_frames = %d\n",nb_frames); - + /* change the buffer pointer to point at the first audio frame */ advance_buffer(&filebuf, rmctx.data_offset+ DATA_HEADER_SIZE); while(packet_count) { - rm_get_packet_membuf(&filebuf, &rmctx, &pkt); - DEBUGF("total frames = %d packet count = %d output counter = %d \n",rmctx.audio_pkt_cnt*(fs/sps), packet_count,rmctx.audio_pkt_cnt); + rm_get_packet(&filebuf, &rmctx, &pkt); + //DEBUGF("total frames = %d packet count = %d output counter = %d \n",rmctx.audio_pkt_cnt*(fs/sps), packet_count,rmctx.audio_pkt_cnt); for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) { /* output raw audio frames that are sent to the decoder into separate files */ - #ifdef DUMP_RAW_FRAMES +#ifdef DUMP_RAW_FRAMES snprintf(filename,sizeof(filename),"dump%d.raw",++x); fd_out = open(filename,O_WRONLY|O_CREAT|O_APPEND); write(fd_out,pkt.frames[i],sps); close(fd_out); - #endif - +#endif nb_frames = cook_decode_frame(&rmctx,&q, outbuf, &datasize, pkt.frames[i] , rmctx.block_align); rmctx.frame_number++; - write(fd_dec,outbuf,datasize); + res = write(fd_dec,outbuf,datasize); } packet_count -= rmctx.audio_pkt_cnt; rmctx.audio_pkt_cnt = 0; diff --git a/apps/codecs/librm/rm.c b/apps/codecs/librm/rm.c index 86c4378d56..4f7ebe9bef 100644 --- a/apps/codecs/librm/rm.c +++ b/apps/codecs/librm/rm.c @@ -21,28 +21,34 @@ ****************************************************************************/ #include #include -#include -#include -#include -#include -#include #include "rm.h" +#ifdef ROCKBOX +#include "codeclib.h" +#endif +void advance_buffer(uint8_t **buf, int val) +{ + *buf += val; +} -#if 0 -#define DEBUG -#define DEBUGF printf -#else -#define DEBUGF(...) -#endif - -/* Some Rockbox-like functions (these should be implemented in metadata_common.[ch] */ static uint8_t get_uint8(uint8_t *buf) { return (uint8_t)buf[0]; } +#ifdef ROCKBOX_BIG_ENDIAN +static uint16_t get_uint16be(uint8_t *buf) +{ + return (uint16_t)((buf[1] << 8)|buf[0]); +} + +static uint32_t get_uint32be(uint8_t *buf) +{ + return (uint32_t)((buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]); +} + +#else static uint16_t get_uint16be(uint8_t *buf) { return (uint16_t)((buf[0] << 8)|buf[1]); @@ -52,6 +58,24 @@ static uint32_t get_uint32be(uint8_t *buf) { return (uint32_t)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); } +#endif /* ROCKBOX_BIG_ENDIAN */ + +#ifdef TEST +#include +#include +#include +#include + +int filesize(int fd) +{ + struct stat buf; + + if (fstat(fd,&buf) == -1) { + return -1; + } else { + return (int)buf.st_size; + } +} static int read_uint8(int fd, uint8_t* buf) { @@ -83,23 +107,9 @@ static int read_uint32be(int fd, uint32_t* buf) return res; } -off_t filesize(int fd) -{ - struct stat buf; - if (fstat(fd,&buf) == -1) { - return -1; - } else { - return buf.st_size; - } -} -void advance_buffer(uint8_t **buf, int val) -{ - *buf += val; -} - -int read_cook_extradata(int fd, RMContext *rmctx) { +static int read_cook_extradata(int fd, RMContext *rmctx) { read_uint32be(fd, &rmctx->cook_version); read_uint16be(fd, &rmctx->samples_pf_pc); read_uint16be(fd, &rmctx->nb_subbands); @@ -111,14 +121,14 @@ int read_cook_extradata(int fd, RMContext *rmctx) { return rmctx->extradata_size; /* for 'skipped' */ } -void print_cook_extradata(RMContext *rmctx) { +static void print_cook_extradata(RMContext *rmctx) { - printf(" cook_version = 0x%08x\n", rmctx->cook_version); - printf(" samples_per_frame_per_channel = %d\n", rmctx->samples_pf_pc); - printf(" number_of_subbands_in_freq_domain = %d\n", rmctx->nb_subbands); + DEBUGF(" cook_version = 0x%08x\n", rmctx->cook_version); + DEBUGF(" samples_per_frame_per_channel = %d\n", rmctx->samples_pf_pc); + DEBUGF(" number_of_subbands_in_freq_domain = %d\n", rmctx->nb_subbands); if(rmctx->extradata_size == 16) { - printf(" joint_stereo_subband_start = %d\n",rmctx->js_subband_start); - printf(" joint_stereo_vlc_bits = %d\n", rmctx->js_vlc_bits); + DEBUGF(" joint_stereo_subband_start = %d\n",rmctx->js_subband_start); + DEBUGF(" joint_stereo_vlc_bits = %d\n", rmctx->js_vlc_bits); } } @@ -196,7 +206,7 @@ static int real_read_audio_stream_info(int fd, RMContext *rmctx) read_uint32be(fd, &version); skipped += 4; - printf(" version=0x%04x\n",((version >> 16) & 0xff)); + DEBUGF(" version=0x%04x\n",((version >> 16) & 0xff)); if (((version >> 16) & 0xff) == 3) { /* Very old version */ } else { @@ -205,7 +215,7 @@ static int real_read_audio_stream_info(int fd, RMContext *rmctx) read_uint32be(fd, &header_size); skipped += 4; /* obj.size will be filled with an unknown value, replaced with header_size */ - printf(" Object: %s, size: %d bytes, version: 0x%04x\n",fourcc2str(obj.fourcc),header_size,obj.version); + DEBUGF(" Object: %s, size: %d bytes, version: 0x%04x\n",fourcc2str(obj.fourcc),header_size,obj.version); read_uint16be(fd, &flavor); read_uint32be(fd, &coded_framesize); @@ -253,20 +263,22 @@ static int real_read_audio_stream_info(int fd, RMContext *rmctx) read_uint32be(fd, &rmctx->extradata_size); skipped += 4; - if(!strncmp(fourcc2str(fourcc),"cook",4)) + if(!strncmp(fourcc2str(fourcc),"cook",4)){ skipped += read_cook_extradata(fd, rmctx); + rmctx->codec_type = cook; + } - printf(" flavor = %d\n",flavor); - printf(" coded_frame_size = %d\n",coded_framesize); - printf(" sub_packet_h = %d\n",rmctx->sub_packet_h); - printf(" frame_size = %d\n",rmctx->block_align); - printf(" sub_packet_size = %d\n",rmctx->sub_packet_size); - printf(" sample_rate= %d\n",rmctx->sample_rate); - printf(" channels= %d\n",rmctx->nb_channels); - printf(" fourcc = %s\n",fourcc2str(fourcc)); - printf(" codec_extra_data_length = %d\n",rmctx->extradata_size); - printf(" codec_extradata :\n"); + DEBUGF(" flavor = %d\n",flavor); + DEBUGF(" coded_frame_size = %d\n",coded_framesize); + DEBUGF(" sub_packet_h = %d\n",rmctx->sub_packet_h); + DEBUGF(" frame_size = %d\n",rmctx->block_align); + DEBUGF(" sub_packet_size = %d\n",rmctx->sub_packet_size); + DEBUGF(" sample_rate= %d\n",rmctx->sample_rate); + DEBUGF(" channels= %d\n",rmctx->nb_channels); + DEBUGF(" fourcc = %s\n",fourcc2str(fourcc)); + DEBUGF(" codec_extra_data_length = %d\n",rmctx->extradata_size); + DEBUGF(" codec_extradata :\n"); print_cook_extradata(rmctx); } @@ -327,18 +339,18 @@ int real_parse_header(int fd, RMContext *rmctx) read_uint32be(fd, &unknown1); read_uint32be(fd, &unknown2); - printf("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos); - printf(" unknown1=%d (0x%08x)\n",unknown1,unknown1); - printf(" unknown2=%d (0x%08x)\n",unknown2,unknown2); + DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos); + DEBUGF(" unknown1=%d (0x%08x)\n",unknown1,unknown1); + DEBUGF(" unknown2=%d (0x%08x)\n",unknown2,unknown2); res = real_read_object_header(fd, &obj); header_end = 0; while(res) { - printf("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos); + DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos); skipped = 10; - if(obj.fourcc == FOURCC('I','N','D','X')) - break; + if(obj.fourcc == FOURCC('I','N','D','X')) + break; switch (obj.fourcc) { case FOURCC('P','R','O','P'): /* File properties */ @@ -347,7 +359,7 @@ int real_parse_header(int fd, RMContext *rmctx) read_uint32be(fd, &max_packet_size); read_uint32be(fd, &avg_packet_size); read_uint32be(fd, &packet_count); - read_uint32be(fd, &duration); + read_uint32be(fd, &rmctx->duration); read_uint32be(fd, &preroll); read_uint32be(fd, &index_offset); read_uint32be(fd, &rmctx->data_offset); @@ -355,17 +367,17 @@ int real_parse_header(int fd, RMContext *rmctx) read_uint16be(fd, &rmctx->flags); skipped += 40; - printf(" max_bitrate = %d\n",max_bitrate); - printf(" avg_bitrate = %d\n",avg_bitrate); - printf(" max_packet_size = %d\n",max_packet_size); - printf(" avg_packet_size = %d\n",avg_packet_size); - printf(" packet_count = %d\n",packet_count); - printf(" duration = %d\n",duration); - printf(" preroll = %d\n",preroll); - printf(" index_offset = %d\n",index_offset); - printf(" data_offset = %d\n",rmctx->data_offset); - printf(" num_streams = %d\n",num_streams); - printf(" flags=0x%04x\n",flags); + DEBUGF(" max_bitrate = %d\n",max_bitrate); + DEBUGF(" avg_bitrate = %d\n",avg_bitrate); + DEBUGF(" max_packet_size = %d\n",max_packet_size); + DEBUGF(" avg_packet_size = %d\n",avg_packet_size); + DEBUGF(" packet_count = %d\n",packet_count); + DEBUGF(" duration = %d\n",rmctx->duration); + DEBUGF(" preroll = %d\n",preroll); + DEBUGF(" index_offset = %d\n",index_offset); + DEBUGF(" data_offset = %d\n",rmctx->data_offset); + DEBUGF(" num_streams = %d\n",num_streams); + DEBUGF(" flags=0x%04x\n",flags); break; case FOURCC('C','O','N','T'): @@ -375,10 +387,10 @@ int real_parse_header(int fd, RMContext *rmctx) skipped += read_str(fd,copyright); skipped += read_str(fd,comment); - printf(" title=\"%s\"\n",title); - printf(" author=\"%s\"\n",author); - printf(" copyright=\"%s\"\n",copyright); - printf(" comment=\"%s\"\n",comment); + DEBUGF(" title=\"%s\"\n",title); + DEBUGF(" author=\"%s\"\n",author); + DEBUGF(" copyright=\"%s\"\n",copyright); + DEBUGF(" comment=\"%s\"\n",comment); break; case FOURCC('M','D','P','R'): /* Media properties */ @@ -406,18 +418,18 @@ int real_parse_header(int fd, RMContext *rmctx) read_uint32be(fd,&v); skipped += 4; - printf(" stream_id = 0x%04x\n",stream_id); - printf(" max_bitrate = %d\n",max_bitrate); - printf(" avg_bitrate = %d\n",avg_bitrate); - printf(" max_packet_size = %d\n",max_packet_size); - printf(" avg_packet_size = %d\n",avg_packet_size); - printf(" start_time = %d\n",start_time); - printf(" preroll = %d\n",preroll); - printf(" duration = %d\n",duration); - printf(" desc=\"%s\"\n",desc); - printf(" mimetype=\"%s\"\n",mimetype); - printf(" codec_data_size = %d\n",codec_data_size); - printf(" v=\"%s\"\n", fourcc2str(v)); + DEBUGF(" stream_id = 0x%04x\n",stream_id); + DEBUGF(" max_bitrate = %d\n",max_bitrate); + DEBUGF(" avg_bitrate = %d\n",avg_bitrate); + DEBUGF(" max_packet_size = %d\n",max_packet_size); + DEBUGF(" avg_packet_size = %d\n",avg_packet_size); + DEBUGF(" start_time = %d\n",start_time); + DEBUGF(" preroll = %d\n",preroll); + DEBUGF(" duration = %d\n",duration); + DEBUGF(" desc=\"%s\"\n",desc); + DEBUGF(" mimetype=\"%s\"\n",mimetype); + DEBUGF(" codec_data_size = %d\n",codec_data_size); + DEBUGF(" v=\"%s\"\n", fourcc2str(v)); if (v == FOURCC('.','r','a',0xfd)) { @@ -428,10 +440,10 @@ int real_parse_header(int fd, RMContext *rmctx) case FOURCC('D','A','T','A'): - read_uint32be(fd,&rmctx->nb_packets); - skipped += 4; - read_uint32be(fd,&next_data_off); - skipped += 4; + read_uint32be(fd,&rmctx->nb_packets); + skipped += 4; + read_uint32be(fd,&next_data_off); + skipped += 4; if (!rmctx->nb_packets && (rmctx->flags & 4)) rmctx->nb_packets = 3600 * 25; @@ -445,8 +457,8 @@ int real_parse_header(int fd, RMContext *rmctx) if(rmctx->nb_packets % rmctx->sub_packet_h) rmctx->nb_packets += rmctx->sub_packet_h - (rmctx->nb_packets % rmctx->sub_packet_h); - printf(" data_nb_packets = %d\n",rmctx->nb_packets); - printf(" next DATA offset = %d\n",next_data_off); + DEBUGF(" data_nb_packets = %d\n",rmctx->nb_packets); + DEBUGF(" next DATA offset = %d\n",next_data_off); header_end = 1; break; } @@ -459,7 +471,7 @@ int real_parse_header(int fd, RMContext *rmctx) return 0; } -void rm_get_packet(int fd,RMContext *rmctx, RMPacket *pkt) +void rm_get_packet_fd(int fd,RMContext *rmctx, RMPacket *pkt) { uint8_t unknown,packet_group; uint16_t x, place; @@ -467,10 +479,19 @@ void rm_get_packet(int fd,RMContext *rmctx, RMPacket *pkt) uint16_t h = rmctx->sub_packet_h; uint16_t y = rmctx->sub_packet_cnt; uint16_t w = rmctx->audio_framesize; + int res; do { y = rmctx->sub_packet_cnt; read_uint16be(fd,&pkt->version); + + /* Simple error checking */ + if(pkt->version != 0 && pkt->version != 1) + { + DEBUGF("parsing packets failed\n"); + return -1; + } + read_uint16be(fd,&pkt->length); read_uint16be(fd,&pkt->stream_number); read_uint32be(fd,&pkt->timestamp); @@ -495,22 +516,17 @@ void rm_get_packet(int fd,RMContext *rmctx, RMPacket *pkt) for(x = 0 ; x < w/sps; x++) { - place = sps*(h*x+((h+1)/2)*(y&1)+(y>>1)); - read(fd,pkt->data+place, sps); - //DEBUGF("place = %d data[place] = %d\n",place,pkt->data[place]); + res = read(fd,pkt->data+(sps*(h*x+((h+1)/2)*(y&1)+(y>>1))), sps); } rmctx->audio_pkt_cnt++; }while(++(rmctx->sub_packet_cnt) < h); - //return pkt->data; } +#endif /*TEST*/ -/** - * Another version of rm_get_packet which reads from a memory buffer - * instead of readind from a file descriptor. - **/ -void rm_get_packet_membuf(uint8_t **filebuf,RMContext *rmctx, RMPacket *pkt) +int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) { + int consumed = 0; uint8_t unknown; uint16_t x, place; uint16_t sps = rmctx->sub_packet_size; @@ -520,36 +536,46 @@ void rm_get_packet_membuf(uint8_t **filebuf,RMContext *rmctx, RMPacket *pkt) do { y = rmctx->sub_packet_cnt; - pkt->version = get_uint16be(*filebuf); - pkt->length = get_uint16be(*filebuf+2); - pkt->stream_number = get_uint16be(*filebuf+4); - pkt->timestamp = get_uint32be(*filebuf+6); - DEBUGF(" version = %d\n" + pkt->version = get_uint16be(*src); + + /* Simple error checking */ + if(pkt->version != 0 && pkt->version != 1) + { + DEBUGF("parsing packets failed\n"); + return -1; + } + + pkt->length = get_uint16be(*src+2); + pkt->stream_number = get_uint16be(*src+4); + pkt->timestamp = get_uint32be(*src+6); + /*DEBUGF(" version = %d\n" " length = %d\n" " stream = %d\n" - " timestamp= %d\n",pkt->version,pkt->length,pkt->stream_number,pkt->timestamp); - - unknown = get_uint8(*filebuf+10); - pkt->flags = get_uint8(*filebuf+11); + " timestamp= %d\n\n",pkt->version,pkt->length,pkt->stream_number,pkt->timestamp);*/ + unknown = get_uint8(*src+10); + pkt->flags = get_uint8(*src+11); if(pkt->version == 1) - unknown = get_uint8(*filebuf+10); + unknown = get_uint8(*src+10); if (pkt->flags & 2) /* keyframe */ y = rmctx->sub_packet_cnt = 0; - if (!y) /* if keyframe update playback elapsed time */ + if (!y) rmctx->audiotimestamp = pkt->timestamp; - advance_buffer(filebuf,12); - + advance_buffer(src,12); + consumed += 12; for(x = 0 ; x < w/sps; x++) { place = sps*(h*x+((h+1)/2)*(y&1)+(y>>1)); - pkt->frames[place/sps] = *filebuf; - advance_buffer(filebuf,sps); + pkt->frames[place/sps] = *src; + advance_buffer(src,sps); + consumed += sps; } rmctx->audio_pkt_cnt++; }while(++(rmctx->sub_packet_cnt) < h); + +return consumed; } #ifdef DEBUG diff --git a/apps/codecs/librm/rm.h b/apps/codecs/librm/rm.h index bdd03f3db2..a0c386e824 100644 --- a/apps/codecs/librm/rm.h +++ b/apps/codecs/librm/rm.h @@ -22,17 +22,21 @@ #define _RM_H #include -#include +#include +enum codecs{cook}; typedef struct rm_packet { - uint8_t data[30000]; /* Reordered data. No malloc, hence the size */ uint8_t *frames[100]; /* Pointers to ordered audio frames in buffer */ uint16_t version; uint16_t length; uint32_t timestamp; uint16_t stream_number; uint8_t flags; + +#ifdef TEST + uint8_t data[30000]; /* Reordered data. No malloc, hence the size */ +#endif }RMPacket; typedef struct rm_context @@ -46,6 +50,7 @@ typedef struct rm_context /* Stream Variables */ uint32_t data_offset; + uint32_t duration; uint32_t audiotimestamp; /* Audio packet timestamp*/ uint16_t sub_packet_cnt; /* Subpacket counter, used while reading */ uint16_t sub_packet_size, sub_packet_h, coded_framesize; /* Descrambling parameters from container */ @@ -53,6 +58,7 @@ typedef struct rm_context uint16_t sub_packet_lengths[16]; /* Length of each subpacket */ /* Codec Context */ + enum codecs codec_type; uint16_t block_align; uint32_t nb_packets; int frame_number; @@ -66,18 +72,26 @@ typedef struct rm_context uint32_t cook_version; uint16_t samples_pf_pc; /* samples per frame per channel */ uint16_t nb_subbands; /* number of subbands in the frequency domain */ - /* extra 8 bytes for stereo data */ + /* extra 8 bytes for joint-stereo data */ uint32_t unused; uint16_t js_subband_start; /* joint stereo subband start */ uint16_t js_vlc_bits; } RMContext; -int open_wav(char* filename); -void close_wav(int fd, RMContext *rmctx); int real_parse_header(int fd, RMContext *rmctx); -void rm_get_packet(int fd,RMContext *rmctx, RMPacket *pkt); -void rm_get_packet_membuf(uint8_t **filebuf,RMContext *rmctx, RMPacket *pkt); -off_t filesize(int fd); + +/* Get a (sub_packet_h*frames_per_packet) number of audio frames from a memory buffer */ +int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt); + +#ifdef TEST + +int filesize(int fd); void advance_buffer(uint8_t **buf, int val); -#endif + +/* Get a (sub_packet_h*frames_per_packet) number of audio frames from a file descriptor */ +void rm_get_packet_fd(int fd,RMContext *rmctx, RMPacket *pkt); + +#endif /* TEST */ + +#endif /* _RM_H */ diff --git a/apps/filetypes.c b/apps/filetypes.c index 680ca57727..1772cac7ee 100644 --- a/apps/filetypes.c +++ b/apps/filetypes.c @@ -83,6 +83,8 @@ static const struct filetype inbuilt_filetypes[] = { { "ape", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, { "mac", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, { "sap" ,FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, + { "rm", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, + { "ra", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, #endif { "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, { "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, diff --git a/apps/metadata.c b/apps/metadata.c index 0892fc65fd..6003e1977e 100644 --- a/apps/metadata.c +++ b/apps/metadata.c @@ -115,6 +115,9 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = /* Amiga SAP File */ [AFMT_SAP] = AFMT_ENTRY("SAP", "asap", NULL, "sap\0" ), + /* Cook in RM/RA */ + [AFMT_COOK] = + AFMT_ENTRY("Cook", "cook", NULL, "rm\0ra\0" ), #endif }; @@ -372,6 +375,14 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname) id3->filesize = filesize(fd); id3->genre_string = id3_get_num_genre(36); break; + + case AFMT_COOK: + if (!get_rm_metadata(fd, id3)) + { + DEBUGF("get_rm_metadata error\n"); + return false; + } + break; #endif /* CONFIG_CODEC == SWCODEC */ diff --git a/apps/metadata.h b/apps/metadata.h index 55a5907731..6c0201781a 100644 --- a/apps/metadata.h +++ b/apps/metadata.h @@ -61,6 +61,7 @@ enum AFMT_WMA, /* WMAV1/V2 in ASF */ AFMT_MOD, /* Amiga MOD File Format */ AFMT_SAP, /* Amiga 8Bit SAP Format */ + AFMT_COOK, /* Cook in RM/RA */ #endif /* add new formats at any index above this line to have a sensible order - diff --git a/apps/metadata/metadata_parsers.h b/apps/metadata/metadata_parsers.h index 1521f1301d..760d9a0da3 100644 --- a/apps/metadata/metadata_parsers.h +++ b/apps/metadata/metadata_parsers.h @@ -39,3 +39,4 @@ bool get_wavpack_metadata(int fd, struct mp3entry* id3); bool get_a52_metadata(int fd, struct mp3entry* id3); bool get_asf_metadata(int fd, struct mp3entry* id3); bool get_asap_metadata(int fd, struct mp3entry* id3); +bool get_rm_metadata(int fd, struct mp3entry* id3); diff --git a/apps/metadata/rm.c b/apps/metadata/rm.c new file mode 100644 index 0000000000..4fefdeb00d --- /dev/null +++ b/apps/metadata/rm.c @@ -0,0 +1,420 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id:$ + * + * Copyright (C) 2009 Mohamed Tarek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include +#include +#include +#include + +#include +#include "system.h" +#include "metadata.h" +#include "metadata_common.h" +#include "metadata_parsers.h" +#include "logf.h" + +//#define DEBUG_RM +#ifndef DEBUG_RM +#undef DEBUGF +#define DEBUGF(...) +#endif + +static inline int read_cook_extradata(int fd, RMContext *rmctx) { + read_uint32be(fd, &rmctx->cook_version); + read_uint16be(fd, &rmctx->samples_pf_pc); + read_uint16be(fd, &rmctx->nb_subbands); + if(rmctx->extradata_size == 16) { + lseek(fd, sizeof(uint32_t), SEEK_CUR); /* reserved */ + read_uint16be(fd, &rmctx->js_subband_start); + read_uint16be(fd, &rmctx->js_vlc_bits); + } + return rmctx->extradata_size; /* for 'skipped' */ +} + +static inline void print_cook_extradata(RMContext *rmctx) { + + DEBUGF(" cook_version = 0x%08lx\n", rmctx->cook_version); + DEBUGF(" samples_per_frame_per_channel = %d\n", rmctx->samples_pf_pc); + DEBUGF(" number_of_subbands_in_freq_domain = %d\n", rmctx->nb_subbands); + if(rmctx->extradata_size == 16) { + DEBUGF(" joint_stereo_subband_start = %d\n",rmctx->js_subband_start); + DEBUGF(" joint_stereo_vlc_bits = %d\n", rmctx->js_vlc_bits); + } +} + + +struct real_object_t +{ + uint32_t fourcc; + uint32_t size; + uint16_t version; +}; + +#define FOURCC(a,b,c,d) (((a)<<24) | ((b) << 16) | ((c) << 8) | (d)) + +static int real_read_object_header(int fd, struct real_object_t* obj) +{ + int n; + + if ((n = read_uint32be(fd, &obj->fourcc)) <= 0) return n; + if ((n = read_uint32be(fd, &obj->size)) <= 0) return n; + if ((n = read_uint16be(fd, &obj->version)) <= 0) return n; + + return 1; +} + +#if (defined(SIMULATOR) && defined(DEBUG_RM)) +static char* fourcc2str(uint32_t f) +{ + static char res[5]; + + res[0] = (f & 0xff000000) >> 24; + res[1] = (f & 0xff0000) >> 16; + res[2] = (f & 0xff00) >> 8; + res[3] = (f & 0xff); + res[4] = 0; + + return res; +} +#endif + +static inline int real_read_audio_stream_info(int fd, RMContext *rmctx) +{ + int skipped = 0; + uint32_t version; + struct real_object_t obj; +#ifdef SIMULATOR + uint32_t header_size; + uint16_t flavor; + uint32_t coded_framesize; + uint8_t interleaver_id_length; + uint8_t fourcc_length; +#endif + uint32_t interleaver_id; + uint32_t fourcc = 0; + + memset(&obj,0,sizeof(obj)); + read_uint32be(fd, &version); + skipped += 4; + + DEBUGF(" version=0x%04lx\n",((version >> 16) & 0xff)); + if (((version >> 16) & 0xff) == 3) { + /* Very old version */ + } else { +#ifdef SIMULATOR + real_read_object_header(fd, &obj); + read_uint32be(fd, &header_size); + /* obj.size will be filled with an unknown value, replaced with header_size */ + DEBUGF(" Object: %s, size: %ld bytes, version: 0x%04x\n",fourcc2str(obj.fourcc),header_size,obj.version); + + read_uint16be(fd, &flavor); + read_uint32be(fd, &coded_framesize); +#else + lseek(fd, 20, SEEK_CUR); +#endif + lseek(fd, 12, SEEK_CUR); /* unknown */ + read_uint16be(fd, &rmctx->sub_packet_h); + read_uint16be(fd, &rmctx->block_align); + read_uint16be(fd, &rmctx->sub_packet_size); + lseek(fd, 2, SEEK_CUR); /* unknown */ + skipped += 40; + if (((version >> 16) & 0xff) == 5) + { + lseek(fd, 6, SEEK_CUR); /* unknown */ + skipped += 6; + } + read_uint16be(fd, &rmctx->sample_rate); + lseek(fd, 4, SEEK_CUR); /* unknown */ + read_uint16be(fd, &rmctx->nb_channels); + skipped += 8; + if (((version >> 16) & 0xff) == 4) + { +#ifdef SIMULATOR + read_uint8(fd, &interleaver_id_length); + read_uint32be(fd, &interleaver_id); + read_uint8(fd, &fourcc_length); +#else + lseek(fd, 6, SEEK_CUR); +#endif + read_uint32be(fd, &fourcc); + skipped += 10; + } + if (((version >> 16) & 0xff) == 5) + { + read_uint32be(fd, &interleaver_id); + read_uint32be(fd, &fourcc); + skipped += 8; + } + lseek(fd, 3, SEEK_CUR); /* unknown */ + skipped += 3; + if (((version >> 16) & 0xff) == 5) + { + lseek(fd, 1, SEEK_CUR); /* unknown */ + skipped += 1; + } + + read_uint32be(fd, &rmctx->extradata_size); + skipped += 4; + /*if(!strncmp(fourcc2str(fourcc),"cook",4)){ + skipped += read_cook_extradata(fd, rmctx); + rmctx->codec_type = cook; + }*/ + switch(fourcc) { + case FOURCC('c','o','o','k'): + skipped += read_cook_extradata(fd, rmctx); + rmctx->codec_type = cook; + break; + + default: /* Not a supported codec */ + return -1; + } + + DEBUGF(" flavor = %d\n",flavor); + DEBUGF(" coded_frame_size = %ld\n",coded_framesize); + DEBUGF(" sub_packet_h = %d\n",rmctx->sub_packet_h); + DEBUGF(" frame_size = %d\n",rmctx->block_align); + DEBUGF(" sub_packet_size = %d\n",rmctx->sub_packet_size); + DEBUGF(" sample_rate= %d\n",rmctx->sample_rate); + DEBUGF(" channels= %d\n",rmctx->nb_channels); + DEBUGF(" fourcc = %s\n",fourcc2str(fourcc)); + DEBUGF(" codec_extra_data_length = %ld\n",rmctx->extradata_size); + DEBUGF(" codec_extradata :\n"); + print_cook_extradata(rmctx); + + } + + return skipped; +} + +static int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3) +{ + struct real_object_t obj; + int res; + int skipped; + off_t curpos; + uint8_t len; /* Holds a string_length, which is then passed to read_string() */ + +#ifdef SIMULATOR + uint32_t avg_bitrate = 0; + uint32_t max_packet_size; + uint32_t avg_packet_size; + uint32_t packet_count; + uint32_t duration; + uint32_t preroll; + uint32_t index_offset; + uint16_t stream_id; + uint32_t start_time; + uint32_t codec_data_size; +#endif + uint32_t v; + uint32_t max_bitrate; + uint16_t num_streams; + uint32_t next_data_off; + uint8_t header_end; + + memset(&obj,0,sizeof(obj)); + curpos = lseek(fd, 0, SEEK_SET); + res = real_read_object_header(fd, &obj); + + if (obj.fourcc == FOURCC('.','r','a',0xfd)) + { + /* Very old .ra format - not yet supported */ + return -1; + } + else if (obj.fourcc != FOURCC('.','R','M','F')) + { + return -1; + } + + lseek(fd, 8, SEEK_CUR); /* unknown */ + + DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos); + + res = real_read_object_header(fd, &obj); + header_end = 0; + while(res) + { + DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos); + skipped = 10; + if(obj.fourcc == FOURCC('I','N','D','X')) + break; + switch (obj.fourcc) + { + case FOURCC('P','R','O','P'): /* File properties */ + read_uint32be(fd, &max_bitrate); + read_uint32be(fd, &rmctx->bit_rate); /*avg bitrate*/ +#ifdef SIMULATOR + read_uint32be(fd, &max_packet_size); + read_uint32be(fd, &avg_packet_size); + read_uint32be(fd, &packet_count); +#else + lseek(fd, 3*sizeof(uint32_t), SEEK_CUR); +#endif + read_uint32be(fd, &rmctx->duration); +#ifdef SIMULATOR + read_uint32be(fd, &preroll); + read_uint32be(fd, &index_offset); +#else + lseek(fd, 2*sizeof(uint32_t), SEEK_CUR); +#endif + read_uint32be(fd, &rmctx->data_offset); + read_uint16be(fd, &num_streams); + read_uint16be(fd, &rmctx->flags); + skipped += 40; + + DEBUGF(" max_bitrate = %ld\n",max_bitrate); + DEBUGF(" avg_bitrate = %ld\n",rmctx->bit_Rate); + DEBUGF(" max_packet_size = %ld\n",max_packet_size); + DEBUGF(" avg_packet_size = %ld\n",avg_packet_size); + DEBUGF(" packet_count = %ld\n",packet_count); + DEBUGF(" duration = %ld\n",rmctx->duration); + DEBUGF(" preroll = %ld\n",preroll); + DEBUGF(" index_offset = %ld\n",index_offset); + DEBUGF(" data_offset = %ld\n",rmctx->data_offset); + DEBUGF(" num_streams = %d\n",num_streams); + DEBUGF(" flags=0x%04x\n",rmctx->flags); + break; + + case FOURCC('C','O','N','T'): + /* Four strings - Title, Author, Copyright, Comment */ + read_uint8(fd,&len); + skipped += (int)read_string(fd, id3->id3v1buf[0], sizeof(id3->id3v1buf[0]), '\0', len); + read_uint8(fd,&len); + skipped += (int)read_string(fd, id3->id3v1buf[1], sizeof(id3->id3v1buf[1]), '\0', len); + read_uint8(fd,&len); + skipped += (int)read_string(fd, id3->id3v1buf[2], sizeof(id3->id3v1buf[2]), '\0', len); + read_uint8(fd,&len); + skipped += (int)read_string(fd, id3->id3v1buf[3], sizeof(id3->id3v1buf[3]), '\0', len); + skipped += 4; + + DEBUGF(" title=\"%s\"\n",id3->id3v1buf[0]); + DEBUGF(" author=\"%s\"\n",id3->id3v1buf[1]); + DEBUGF(" copyright=\"%s\"\n",id3->id3v1buf[2]); + DEBUGF(" comment=\"%s\"\n",id3->id3v1buf[3]); + break; + + case FOURCC('M','D','P','R'): /* Media properties */ +#ifdef SIMULATOR + read_uint16be(fd,&stream_id); + read_uint32be(fd,&max_bitrate); + read_uint32be(fd,&avg_bitrate); + read_uint32be(fd,&max_packet_size); + read_uint32be(fd,&avg_packet_size); + read_uint32be(fd,&start_time); + read_uint32be(fd,&preroll); + read_uint32be(fd,&duration); +#else + lseek(fd, 30, SEEK_CUR); +#endif + skipped += 30; + read_uint8(fd,&len); + skipped += 1; + lseek(fd, len, SEEK_CUR); /* desc */ + skipped += len; + read_uint8(fd,&len); + skipped += 1; +#ifdef SIMULATOR + lseek(fd, len, SEEK_CUR); /* mimetype */ + read_uint32be(fd,&codec_data_size); +#else + lseek(fd, len + 4, SEEK_CUR); +#endif + skipped += len + 4; + //From ffmpeg: codec_pos = url_ftell(pb); + read_uint32be(fd,&v); + skipped += 4; + + DEBUGF(" stream_id = 0x%04x\n",stream_id); + DEBUGF(" max_bitrate = %ld\n",max_bitrate); + DEBUGF(" avg_bitrate = %ld\n",avg_bitrate); + DEBUGF(" max_packet_size = %ld\n",max_packet_size); + DEBUGF(" avg_packet_size = %ld\n",avg_packet_size); + DEBUGF(" start_time = %ld\n",start_time); + DEBUGF(" preroll = %ld\n",preroll); + DEBUGF(" duration = %ld\n",duration); + DEBUGF(" codec_data_size = %ld\n",codec_data_size); + DEBUGF(" v=\"%s\"\n", fourcc2str(v)); + + if (v == FOURCC('.','r','a',0xfd)) + { + skipped += real_read_audio_stream_info(fd, rmctx); + if(skipped < 0) + return -1; + } + + break; + + case FOURCC('D','A','T','A'): + read_uint32be(fd,&rmctx->nb_packets); + skipped += 4; + read_uint32be(fd,&next_data_off); + skipped += 4; + + /*** + * nb_packets correction : + * in some samples, number of packets may not exactly form + * an integer number of scrambling units. This is corrected + * by constructing a partially filled unit out of the few + * remaining samples at the end of decoding. + ***/ + if(rmctx->nb_packets % rmctx->sub_packet_h) + rmctx->nb_packets += rmctx->sub_packet_h - (rmctx->nb_packets % rmctx->sub_packet_h); + + DEBUGF(" data_nb_packets = %ld\n",rmctx->nb_packets); + DEBUGF(" next DATA offset = %ld\n",next_data_off); + header_end = 1; + break; + } + if(header_end) break; + curpos = lseek(fd, obj.size - skipped, SEEK_CUR); + res = real_read_object_header(fd, &obj); + } + + + return 0; +} + + +bool get_rm_metadata(int fd, struct mp3entry* id3) +{ + RMContext *rmctx = (RMContext*)id3->id3v2buf; + memset(rmctx,0,sizeof(RMContext)); + if(rm_parse_header(fd, rmctx, id3) < 0) + return false; + + /* Copy tags */ + id3->title = id3->id3v1buf[0]; + id3->artist = id3->id3v1buf[1]; + id3->comment = id3->id3v1buf[3]; + + /*switch(rmctx->codec_type) + { + case cook: + id3->codectype = AFMT_COOK; + break; + }*/ + + id3->bitrate = rmctx->bit_rate / 1000; + id3->frequency = rmctx->sample_rate; + id3->length = rmctx->duration; + id3->filesize = filesize(fd); + return true; +} -- cgit v1.2.3