From 67695617a13e9f37f17e3718b03046f6d748a9e1 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Sat, 9 May 2009 01:21:49 +0000 Subject: The first part of Mohamed Tarek's Google Summer of Code work to implement RealAudio support in Rockbox. This is a self-contained Cook decoder using the original ffmpeg (still floating point) decoder and a new RM parser started by me in 2008 and continued by MT over the past few months. This is the equivalent of libcook.patch1 from FS#10182, but with further cleaning by both MT and me to minimise the differences to the original ffmpeg files. See README.rockbox for more details. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20883 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/libcook/Makefile.test | 10 + apps/codecs/libcook/README.rockbox | 40 ++ apps/codecs/libcook/avcodec.h | 3 + apps/codecs/libcook/bitstream.c | 2 + apps/codecs/libcook/bitstream.h | 4 +- apps/codecs/libcook/cook.c | 264 +++++++----- apps/codecs/libcook/dsputil.h | 10 + apps/codecs/libcook/ffmpeg_config.h | 14 + apps/codecs/libcook/libavutil/avutil.h | 8 +- apps/codecs/libcook/libavutil/bswap.h | 2 +- apps/codecs/libcook/libavutil/common.h | 6 +- apps/codecs/libcook/libavutil/internal.h | 12 +- apps/codecs/libcook/libavutil/intreadwrite.h | 2 +- apps/codecs/libcook/libavutil/mem.c | 1 - apps/codecs/libcook/rm2wav.c | 584 +++++++++++++++++++++++++++ apps/codecs/libcook/rm2wav.h | 74 ++++ 16 files changed, 925 insertions(+), 111 deletions(-) create mode 100644 apps/codecs/libcook/Makefile.test create mode 100644 apps/codecs/libcook/README.rockbox create mode 100644 apps/codecs/libcook/ffmpeg_config.h create mode 100644 apps/codecs/libcook/rm2wav.c create mode 100644 apps/codecs/libcook/rm2wav.h diff --git a/apps/codecs/libcook/Makefile.test b/apps/codecs/libcook/Makefile.test new file mode 100644 index 0000000000..98ee7ffcb4 --- /dev/null +++ b/apps/codecs/libcook/Makefile.test @@ -0,0 +1,10 @@ +CFLAGS = -Wall -O3 +OBJS = bitstream.o cook.o fft.o libavutil/log.o mdct.o libavutil/mem.o libavutil/lfg.o libavutil/md5.o rm2wav.o +cooktest: $(OBJS) + gcc -o cooktest $(OBJS) -lm + +.c.o : + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + rm -f cooktest $(OBJS) *~ diff --git a/apps/codecs/libcook/README.rockbox b/apps/codecs/libcook/README.rockbox new file mode 100644 index 0000000000..9447b96be5 --- /dev/null +++ b/apps/codecs/libcook/README.rockbox @@ -0,0 +1,40 @@ +Library: libcook +Imported by : Mohamed Tarek + +These files comprise a rm parser and a cook decoder based on the decoder +from ffmpeg. + +LICENSING INFORMATION + +ffmpeg is licensed under the Lesser GNU General Public License and the +file cook.c is Copyright 2003 Sascha Sommer and 2005 Benjamin Larsson. + +IMPORT DETAILS + +The decoder is based on ffmpeg-svn r18079. + +The file libavcodec/cook.c was modified to remove all ffmpeg-specific +code and to use the current rm parser. + +In initializing random_state in COOKContext, ffmpeg used a random_seed() +function that was weird in the way it gets the random number. So it was +decided to not use this function at all,and the value was initialized to 1, +because according to Benjamin Larsson random_seed() could just be +replaced by any value. + +The current files contain lots of code which is either not needed by +the decoder or totally disabled (#if 0 .. #endif) to enable +compiling. This was during the isolation of the decoder from ffmpeg, +the intention was to take as few files as possible to be able to +compile cook.c and the related files outside ffmpeg. + +The decoder still uses floating point and relies on dynamic allocations +in some parts of it. It's still not ready to be ported to rockbox. + +TESTING + +The test program should compile in any Unix-like environment using the +command "make -f Makefile.test". + +Running "./cooktest file.rm" will decode the audio data to a WAV file +called "output.wav" in the current directory. diff --git a/apps/codecs/libcook/avcodec.h b/apps/codecs/libcook/avcodec.h index a520340162..08eb800d4b 100644 --- a/apps/codecs/libcook/avcodec.h +++ b/apps/codecs/libcook/avcodec.h @@ -406,6 +406,7 @@ enum SampleFormat { #define FF_MIN_BUFFER_SIZE 16384 +#if 0/* MT : DELETE THIS LINE.*/ /** * motion estimation type. */ @@ -3429,4 +3430,6 @@ void av_register_hwaccel(AVHWAccel *hwaccel); */ AVHWAccel *av_hwaccel_next(AVHWAccel *hwaccel); +#endif/* MT : DELETE THIS LINE.*/ + #endif /* AVCODEC_AVCODEC_H */ diff --git a/apps/codecs/libcook/bitstream.c b/apps/codecs/libcook/bitstream.c index 6781fe6cb0..f32e88fdbf 100644 --- a/apps/codecs/libcook/bitstream.c +++ b/apps/codecs/libcook/bitstream.c @@ -73,6 +73,7 @@ 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; @@ -94,6 +95,7 @@ void ff_copy_bits(PutBitContext *pb, const uint8_t *src, int length) put_bits(pb, bits, AV_RB16(&srcw[words])>>(16-bits)); } +#endif /* VLC decoding */ diff --git a/apps/codecs/libcook/bitstream.h b/apps/codecs/libcook/bitstream.h index 3670285904..e3e3d77595 100644 --- a/apps/codecs/libcook/bitstream.h +++ b/apps/codecs/libcook/bitstream.h @@ -33,7 +33,7 @@ #include "libavutil/common.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" -#include "mathops.h" +//#include "mathops.h" #if defined(ALT_BITSTREAM_READER_LE) && !defined(ALT_BITSTREAM_READER) # define ALT_BITSTREAM_READER @@ -707,12 +707,14 @@ static inline unsigned int get_bits_long(GetBitContext *s, int n){ } } +#if 0 /** * reads 0-32 bits as a signed integer. */ static inline int get_sbits_long(GetBitContext *s, int n) { return sign_extend(get_bits_long(s, n), n); } +#endif /** * shows 0-32 bits. diff --git a/apps/codecs/libcook/cook.c b/apps/codecs/libcook/cook.c index cee69fe14a..856004f31b 100644 --- a/apps/codecs/libcook/cook.c +++ b/apps/codecs/libcook/cook.c @@ -45,15 +45,30 @@ #include #include #include +#include +#include +#include +#include #include "libavutil/lfg.h" -#include "libavutil/random_seed.h" -#include "avcodec.h" #include "bitstream.h" #include "dsputil.h" #include "bytestream.h" #include "cookdata.h" +#include "rm2wav.h" + +/* The following table is taken from libavutil/mathematics.c */ +const uint8_t ff_log2_tab[256]={ + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; /* the different Cook versions */ #define MONO 0x1000001 @@ -64,6 +79,8 @@ #define SUBBAND_SIZE 20 #define MAX_SUBPACKETS 5 //#define COOKDEBUG +//#define DUMP_RAW_FRAMES +#define DEBUGF(message,args ...) av_log(NULL,AV_LOG_ERROR,message,## args) typedef struct { int *now; @@ -93,8 +110,10 @@ typedef struct cook { void (* saturate_output) (struct cook *q, int chan, int16_t *out); - AVCodecContext* avctx; GetBitContext gb; + int frame_number; + int block_align; + int extradata_size; /* stream data */ int nb_channels; int joint_stereo; @@ -112,7 +131,6 @@ typedef struct cook { int cookversion; /* states */ AVLFG random_state; - /* transform data */ MDCTContext mdct_ctx; float* mlt_window; @@ -138,7 +156,7 @@ typedef struct cook { /* data buffers */ uint8_t* decoded_bytes_buffer; - DECLARE_ALIGNED_16(float,mono_mdct_output[2048]); + float mono_mdct_output[2048] __attribute__ ((aligned(16))); //DECLARE_ALIGNED_16(float,mono_mdct_output[2048]); float mono_previous_buffer1[1024]; float mono_previous_buffer2[1024]; float decode_buffer_1[1024]; @@ -214,7 +232,7 @@ static av_cold int init_cook_vlc_tables(COOKContext *q) { envelope_quant_index_huffbits[i], 1, 1, envelope_quant_index_huffcodes[i], 2, 2, 0); } - av_log(q->avctx,AV_LOG_DEBUG,"sqvh VLC init\n"); + av_log(NULL,AV_LOG_DEBUG,"sqvh VLC init\n"); for (i=0 ; i<7 ; i++) { result |= init_vlc (&q->sqvh[i], vhvlcsize_tab[i], vhsize_tab[i], cvh_huffbits[i], 1, 1, @@ -225,10 +243,10 @@ static av_cold int init_cook_vlc_tables(COOKContext *q) { result |= init_vlc (&q->ccpl, 6, (1<js_vlc_bits)-1, ccpl_huffbits[q->js_vlc_bits-2], 1, 1, ccpl_huffcodes[q->js_vlc_bits-2], 2, 2, 0); - av_log(q->avctx,AV_LOG_DEBUG,"Joint-stereo VLC used.\n"); + av_log(NULL,AV_LOG_DEBUG,"Joint-stereo VLC used.\n"); } - av_log(q->avctx,AV_LOG_DEBUG,"VLC tables initialized.\n"); + av_log(NULL,AV_LOG_ERROR,"VLC tables initialized. Result = %d\n",result); return result; } @@ -249,8 +267,8 @@ static av_cold int init_cook_mlt(COOKContext *q) { av_free(q->mlt_window); return -1; } - av_log(q->avctx,AV_LOG_DEBUG,"MDCT initialized, order = %d.\n", - av_log2(mlt_size)+1); + av_log(NULL,AV_LOG_ERROR,"MDCT initialized, order = %d. mlt_window = %d\n", + av_log2(mlt_size)+1,sizeof(q->mlt_window)*mlt_size); return 0; } @@ -317,11 +335,11 @@ static inline int decode_bytes(const uint8_t* inbuffer, uint8_t* out, int bytes) * Cook uninit */ -static av_cold int cook_decode_close(AVCodecContext *avctx) +static av_cold int cook_decode_close(COOKContext *q) { int i; - COOKContext *q = avctx->priv_data; - av_log(avctx,AV_LOG_DEBUG, "Deallocating memory.\n"); + //COOKContext *q = avctx->priv_data; + av_log(NULL,AV_LOG_ERROR, "Deallocating memory.\n"); /* Free allocated memory buffers. */ av_free(q->mlt_window); @@ -341,7 +359,7 @@ static av_cold int cook_decode_close(AVCodecContext *avctx) free_vlc(&q->ccpl); } - av_log(avctx,AV_LOG_DEBUG,"Memory deallocated.\n"); + av_log(NULL,AV_LOG_ERROR,"Memory deallocated.\n"); return 0; } @@ -864,6 +882,8 @@ static void joint_decode(COOKContext *q, float* mlt_buffer1, * @param gain_ptr array of current/prev gain pointers */ +#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) + static inline void decode_bytes_and_gain(COOKContext *q, const uint8_t *inbuffer, cook_gains *gains_ptr) @@ -938,9 +958,9 @@ static int decode_subpacket(COOKContext *q, const uint8_t *inbuffer, int sub_packet_size, int16_t *outbuffer) { /* packet dump */ // for (i=0 ; iavctx, AV_LOG_ERROR, "%02x", inbuffer[i]); +// av_log(NULL, AV_LOG_ERROR, "%02x", inbuffer[i]); // } -// av_log(q->avctx, AV_LOG_ERROR, "\n"); +// av_log(NULL, AV_LOG_ERROR, "\n"); decode_bytes_and_gain(q, inbuffer, &q->gains1); @@ -974,37 +994,37 @@ static int decode_subpacket(COOKContext *q, const uint8_t *inbuffer, /** * Cook frame decoding * - * @param avctx pointer to the AVCodecContext + * @param rmctx pointer to the RMContext */ -static int cook_decode_frame(AVCodecContext *avctx, - void *data, int *data_size, - const uint8_t *buf, int buf_size) { - COOKContext *q = avctx->priv_data; +static int cook_decode_frame(RMContext *rmctx,COOKContext *q, + int16_t *outbuffer, int *data_size, + const uint8_t *inbuffer, int buf_size) { + //COOKContext *q = avctx->priv_data; + //COOKContext *q; - if (buf_size < avctx->block_align) + if (buf_size < rmctx->block_align) return buf_size; - *data_size = decode_subpacket(q, buf, avctx->block_align, data); + *data_size = decode_subpacket(q, inbuffer, rmctx->block_align, outbuffer); /* Discard the first two frames: no valid audio. */ - if (avctx->frame_number < 2) *data_size = 0; + if (rmctx->frame_number < 2) *data_size = 0; - return avctx->block_align; + return rmctx->block_align; } #ifdef COOKDEBUG static void dump_cook_context(COOKContext *q) { //int i=0; -#define PRINT(a,b) av_log(q->avctx,AV_LOG_ERROR," %s = %d\n", a, b); - av_log(q->avctx,AV_LOG_ERROR,"COOKextradata\n"); - av_log(q->avctx,AV_LOG_ERROR,"cookversion=%x\n",q->cookversion); +#define PRINT(a,b) av_log(NULL,AV_LOG_ERROR," %s = %d\n", a, b); + av_log(NULL,AV_LOG_ERROR,"COOKextradata\n"); + av_log(NULL,AV_LOG_ERROR,"cookversion=%x\n",q->cookversion); if (q->cookversion > STEREO) { PRINT("js_subband_start",q->js_subband_start); PRINT("js_vlc_bits",q->js_vlc_bits); } - av_log(q->avctx,AV_LOG_ERROR,"COOKContext\n"); PRINT("nb_channels",q->nb_channels); PRINT("bit_rate",q->bit_rate); PRINT("sample_rate",q->sample_rate); @@ -1031,76 +1051,60 @@ static av_cold int cook_count_channels(unsigned int mask){ /** * Cook initialization - * - * @param avctx pointer to the AVCodecContext */ -static av_cold int cook_decode_init(AVCodecContext *avctx) -{ - COOKContext *q = avctx->priv_data; - const uint8_t *edata_ptr = avctx->extradata; - q->avctx = avctx; - - /* Take care of the codec specific extradata. */ - if (avctx->extradata_size <= 0) { - av_log(avctx,AV_LOG_ERROR,"Necessary extradata missing!\n"); - return -1; - } else { - /* 8 for mono, 16 for stereo, ? for multichannel - Swap to right endianness so we don't need to care later on. */ - av_log(avctx,AV_LOG_DEBUG,"codecdata_length=%d\n",avctx->extradata_size); - if (avctx->extradata_size >= 8){ - q->cookversion = bytestream_get_be32(&edata_ptr); - q->samples_per_frame = bytestream_get_be16(&edata_ptr); - q->subbands = bytestream_get_be16(&edata_ptr); - } - if (avctx->extradata_size >= 16){ - bytestream_get_be32(&edata_ptr); //Unknown unused - q->js_subband_start = bytestream_get_be16(&edata_ptr); - q->js_vlc_bits = bytestream_get_be16(&edata_ptr); - } +static av_cold int cook_decode_init(RMContext *rmctx, COOKContext *q) +{ + /* cook extradata */ + q->cookversion = rmctx->cook_version; + q->samples_per_frame = rmctx->samples_pf_pc; + q->subbands = rmctx->nb_subbands; + q->extradata_size = rmctx->extradata_size; + if (q->extradata_size >= 16){ + q->js_subband_start = rmctx->js_subband_start; + q->js_vlc_bits = rmctx->js_vlc_bits; } - /* Take data from the AVCodecContext (RM container). */ - q->sample_rate = avctx->sample_rate; - q->nb_channels = avctx->channels; - q->bit_rate = avctx->bit_rate; + /* Take data from the RMContext (RM container). */ + q->sample_rate = rmctx->sample_rate; + q->nb_channels = rmctx->nb_channels; + q->bit_rate = rmctx->bit_rate; /* Initialize RNG. */ - av_lfg_init(&q->random_state, ff_random_get_seed()); + av_lfg_init(&q->random_state, 1); /* Initialize extradata related variables. */ q->samples_per_channel = q->samples_per_frame / q->nb_channels; - q->bits_per_subpacket = avctx->block_align * 8; + q->bits_per_subpacket = rmctx->block_align * 8; /* Initialize default data states. */ q->log2_numvector_size = 5; q->total_subbands = q->subbands; /* Initialize version-dependent variables */ - av_log(avctx,AV_LOG_DEBUG,"q->cookversion=%x\n",q->cookversion); + av_log(NULL,AV_LOG_DEBUG,"q->cookversion=%x\n",q->cookversion); q->joint_stereo = 0; switch (q->cookversion) { case MONO: if (q->nb_channels != 1) { - av_log(avctx,AV_LOG_ERROR,"Container channels != 1, report sample!\n"); + av_log(NULL,AV_LOG_ERROR,"Container channels != 1, report sample!\n"); return -1; } - av_log(avctx,AV_LOG_DEBUG,"MONO\n"); + av_log(NULL,AV_LOG_DEBUG,"MONO\n"); break; case STEREO: if (q->nb_channels != 1) { q->bits_per_subpacket = q->bits_per_subpacket/2; } - av_log(avctx,AV_LOG_DEBUG,"STEREO\n"); + av_log(NULL,AV_LOG_DEBUG,"STEREO\n"); break; case JOINT_STEREO: if (q->nb_channels != 2) { - av_log(avctx,AV_LOG_ERROR,"Container channels != 2, report sample!\n"); + av_log(NULL,AV_LOG_ERROR,"Container channels != 2, report sample!\n"); return -1; } - av_log(avctx,AV_LOG_DEBUG,"JOINT_STEREO\n"); - if (avctx->extradata_size >= 16){ + av_log(NULL,AV_LOG_ERROR,"JOINT_STEREO\n"); + if (q->extradata_size >= 16){ q->total_subbands = q->subbands + q->js_subband_start; q->joint_stereo = 1; } @@ -1112,11 +1116,11 @@ static av_cold int cook_decode_init(AVCodecContext *avctx) } break; case MC_COOK: - av_log(avctx,AV_LOG_ERROR,"MC_COOK not supported!\n"); + av_log(NULL,AV_LOG_ERROR,"MC_COOK not supported!\n"); return -1; break; default: - av_log(avctx,AV_LOG_ERROR,"Unknown Cook version, report sample!\n"); + av_log(NULL,AV_LOG_ERROR,"Unknown Cook version, report sample!\n"); return -1; break; } @@ -1133,22 +1137,24 @@ static av_cold int cook_decode_init(AVCodecContext *avctx) return -1; - if(avctx->block_align >= UINT_MAX/2) + if(q->block_align >= UINT_MAX/2) return -1; /* Pad the databuffer with: DECODE_BYTES_PAD1 or DECODE_BYTES_PAD2 for decode_bytes(), - FF_INPUT_BUFFER_PADDING_SIZE, for the bitstreamreader. */ + INPUT_BUFFER_PADDING_SIZE, for the bitstreamreader. */ + +#define INPUT_BUFFER_PADDING_SIZE 8 if (q->nb_channels==2 && q->joint_stereo==0) { q->decoded_bytes_buffer = - av_mallocz(avctx->block_align/2 - + DECODE_BYTES_PAD2(avctx->block_align/2) - + FF_INPUT_BUFFER_PADDING_SIZE); + av_mallocz(rmctx->block_align/2 + + DECODE_BYTES_PAD2(q->block_align/2) + + INPUT_BUFFER_PADDING_SIZE); } else { q->decoded_bytes_buffer = - av_mallocz(avctx->block_align - + DECODE_BYTES_PAD1(avctx->block_align) - + FF_INPUT_BUFFER_PADDING_SIZE); + av_mallocz(rmctx->block_align + + DECODE_BYTES_PAD1(q->block_align) + + INPUT_BUFFER_PADDING_SIZE); } if (q->decoded_bytes_buffer == NULL) return -1; @@ -1173,25 +1179,23 @@ static av_cold int cook_decode_init(AVCodecContext *avctx) /* Try to catch some obviously faulty streams, othervise it might be exploitable */ if (q->total_subbands > 53) { - av_log(avctx,AV_LOG_ERROR,"total_subbands > 53, report sample!\n"); + av_log(NULL,AV_LOG_ERROR,"total_subbands > 53, report sample!\n"); return -1; } if (q->subbands > 50) { - av_log(avctx,AV_LOG_ERROR,"subbands > 50, report sample!\n"); + av_log(NULL,AV_LOG_ERROR,"subbands > 50, report sample!\n"); return -1; } if ((q->samples_per_channel == 256) || (q->samples_per_channel == 512) || (q->samples_per_channel == 1024)) { } else { - av_log(avctx,AV_LOG_ERROR,"unknown amount of samples_per_channel = %d, report sample!\n",q->samples_per_channel); + av_log(NULL,AV_LOG_ERROR,"unknown amount of samples_per_channel = %d, report sample!\n",q->samples_per_channel); return -1; } if ((q->js_vlc_bits > 6) || (q->js_vlc_bits < 0)) { - av_log(avctx,AV_LOG_ERROR,"q->js_vlc_bits = %d, only >= 0 and <= 6 allowed!\n",q->js_vlc_bits); + av_log(NULL,AV_LOG_ERROR,"q->js_vlc_bits = %d, only >= 0 and <= 6 allowed!\n",q->js_vlc_bits); return -1; } - avctx->sample_fmt = SAMPLE_FMT_S16; - avctx->channel_layout = (avctx->channels==2) ? CH_LAYOUT_STEREO : CH_LAYOUT_MONO; #ifdef COOKDEBUG dump_cook_context(q); @@ -1200,14 +1204,86 @@ static av_cold int cook_decode_init(AVCodecContext *avctx) } -AVCodec cook_decoder = +int main(int argc, char *argv[]) { - .name = "cook", - .type = CODEC_TYPE_AUDIO, - .id = CODEC_ID_COOK, - .priv_data_size = sizeof(COOKContext), - .init = cook_decode_init, - .close = cook_decode_close, - .decode = cook_decode_frame, - .long_name = NULL_IF_CONFIG_SMALL("COOK"), -}; + int fd, fd_dec; + int res, datasize,x,i; + int nb_frames = 0; +#ifdef DUMP_RAW_FRAMES + char filename[15]; + int fd_out; +#endif + int16_t outbuf[2048]; + uint8_t inbuf[1024]; + uint16_t fs,sps,h; + uint32_t packet_count; + COOKContext q; + RMContext rmctx; + RMPacket pkt; + + memset(&q,0,sizeof(COOKContext)); + memset(&rmctx,0,sizeof(RMContext)); + memset(&pkt,0,sizeof(RMPacket)); + + if (argc != 2) { + av_log(NULL,AV_LOG_ERROR,"Incorrect number of arguments\n"); + return -1; + } + + fd = open(argv[1],O_RDONLY); + if (fd < 0) { + av_log(NULL,AV_LOG_ERROR,"Error opening file %s\n", argv[1]); + return -1; + } + + fd_dec = open_wav("output.wav"); + if (fd_dec < 0) { + av_log(NULL,AV_LOG_ERROR,"Error creating output file\n"); + return -1; + } + res = real_parse_header(fd, &rmctx); + 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; + cook_decode_init(&rmctx,&q); + av_log(NULL,AV_LOG_ERROR,"nb_frames = %d\n",nb_frames); + x = 0; + if(packet_count % h) + { + packet_count += h - (packet_count % h); + rmctx.nb_packets = packet_count; + } + while(packet_count) + { + + memset(pkt.data,0,sizeof(pkt.data)); + rm_get_packet(fd, &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 + snprintf(filename,sizeof(filename),"dump%d.raw",++x); + fd_out = open(filename,O_WRONLY|O_CREAT|O_APPEND); + write(fd_out,pkt.data+i*sps,sps); + close(fd_out); + #endif + + memcpy(inbuf,pkt.data+i*sps,sps); + nb_frames = cook_decode_frame(&rmctx,&q, outbuf, &datasize, inbuf , rmctx.block_align); + rmctx.frame_number++; + write(fd_dec,outbuf,datasize); + } + packet_count -= rmctx.audio_pkt_cnt; + rmctx.audio_pkt_cnt = 0; + } + cook_decode_close(&q); + close_wav(fd_dec,&rmctx); + close(fd); + + + return 0; +} diff --git a/apps/codecs/libcook/dsputil.h b/apps/codecs/libcook/dsputil.h index e9c2bfc77e..4573c17a62 100644 --- a/apps/codecs/libcook/dsputil.h +++ b/apps/codecs/libcook/dsputil.h @@ -36,6 +36,7 @@ //#define DEBUG /* dct code */ +#if 0 /*MT : DELETE THIS LINE.*/ typedef short DCTELEM; typedef int DWTELEM; typedef short IDWTELEM; @@ -590,8 +591,10 @@ void dsputil_init_ppc(DSPContext* c, AVCodecContext *avctx); void dsputil_init_sh4(DSPContext* c, AVCodecContext *avctx); void dsputil_init_vis(DSPContext* c, AVCodecContext *avctx); +#endif /*MT : DELETE THIS LINE ONLY. */ #define DECLARE_ALIGNED_16(t, v) DECLARE_ALIGNED(16, t, v) +#if 0 /*MT : DELETE THIS LINE ONLY. */ #if HAVE_MMX #undef emms_c @@ -644,10 +647,12 @@ extern int mm_flags; #endif +#endif /* MT : DELETE THIS LINE ONLY */ #ifndef DECLARE_ALIGNED_8 # define DECLARE_ALIGNED_8(t, v) DECLARE_ALIGNED(8, t, v) #endif +#if 0 /* MT : DELETE THIS LINE ONLY */ #ifndef STRIDE_ALIGN # define STRIDE_ALIGN 8 #endif @@ -657,6 +662,7 @@ void get_psnr(uint8_t *orig_image[3], uint8_t *coded_image[3], int orig_linesize[3], int coded_linesize, AVCodecContext *avctx); +#endif /*MT : DELETE THIS LINE.*/ /* FFT computation */ /* NOTE: soon integer code will be added, so you must use the @@ -715,6 +721,7 @@ static inline void ff_fft_calc(FFTContext *s, FFTComplex *z) } void ff_fft_end(FFTContext *s); +#endif /*MT : DELETE THIS LINE.*/ /* MDCT computation */ typedef struct MDCTContext { @@ -735,6 +742,7 @@ static inline void ff_imdct_half(MDCTContext *s, FFTSample *output, const FFTSam s->fft.imdct_half(s, output, input); } +#if 0 /* MT : DELETE THIS LINE. */ /** * Generate a Kaiser-Bessel Derived Window. * @param window pointer to half window @@ -742,6 +750,7 @@ static inline void ff_imdct_half(MDCTContext *s, FFTSample *output, const FFTSam * @param n size of half window */ void ff_kbd_window_init(float *window, float alpha, int n); +#endif /* MT : DELETE THIS LINE.*/ /** * Generate a sine window. @@ -769,6 +778,7 @@ void ff_imdct_half_sse(MDCTContext *s, FFTSample *output, const FFTSample *input void ff_mdct_calc(MDCTContext *s, FFTSample *out, const FFTSample *input); void ff_mdct_end(MDCTContext *s); +#if 0 /* MT : DELETE THIS LINE.*/ /* Real Discrete Fourier Transform */ enum RDFTransformType { diff --git a/apps/codecs/libcook/ffmpeg_config.h b/apps/codecs/libcook/ffmpeg_config.h new file mode 100644 index 0000000000..707e14df52 --- /dev/null +++ b/apps/codecs/libcook/ffmpeg_config.h @@ -0,0 +1,14 @@ +/* Automatically generated by configure - do not modify */ +#ifndef _FFMPEG_CONFIG_H +#define _FFMPEG_CONFIG_H +// CHECK THIS : #include "codecs.h" + +#ifdef CPU_ARM +#define CONFIG_ALIGN 1 +#endif + +#ifdef ROCKBOX_BIG_ENDIAN +#define WORDS_BIGENDIAN +#endif + +#endif diff --git a/apps/codecs/libcook/libavutil/avutil.h b/apps/codecs/libcook/libavutil/avutil.h index c57e69f10c..c07e44d660 100644 --- a/apps/codecs/libcook/libavutil/avutil.h +++ b/apps/codecs/libcook/libavutil/avutil.h @@ -54,10 +54,10 @@ unsigned avutil_version(void); #include "common.h" -#include "mathematics.h" -#include "rational.h" -#include "intfloat_readwrite.h" +//#include "mathematics.h" +//#include "rational.h" +//#include "intfloat_readwrite.h" #include "log.h" -#include "pixfmt.h" +//#include "pixfmt.h" #endif /* AVUTIL_AVUTIL_H */ diff --git a/apps/codecs/libcook/libavutil/bswap.h b/apps/codecs/libcook/libavutil/bswap.h index cf68c43c72..9175cb24a5 100644 --- a/apps/codecs/libcook/libavutil/bswap.h +++ b/apps/codecs/libcook/libavutil/bswap.h @@ -27,7 +27,7 @@ #define AVUTIL_BSWAP_H #include -#include "config.h" +//#include "ffmpeg_config.h" #include "common.h" #if ARCH_ARM diff --git a/apps/codecs/libcook/libavutil/common.h b/apps/codecs/libcook/libavutil/common.h index 15eaf9849d..949f093d35 100644 --- a/apps/codecs/libcook/libavutil/common.h +++ b/apps/codecs/libcook/libavutil/common.h @@ -278,9 +278,9 @@ static inline av_const float av_clipf(float a, float amin, float amax) #include "mem.h" -#ifdef HAVE_AV_CONFIG_H -# include "config.h" +//#ifdef HAVE_AV_CONFIG_H +//# include "ffmpeg_config.h" # include "internal.h" -#endif /* HAVE_AV_CONFIG_H */ +//#endif /* HAVE_AV_CONFIG_H */ #endif /* AVUTIL_COMMON_H */ diff --git a/apps/codecs/libcook/libavutil/internal.h b/apps/codecs/libcook/libavutil/internal.h index 4191aa8e52..f8f9418a76 100644 --- a/apps/codecs/libcook/libavutil/internal.h +++ b/apps/codecs/libcook/libavutil/internal.h @@ -34,10 +34,10 @@ #include #include #include -#include "config.h" +//#include "ffmpeg_config.h" #include "common.h" #include "mem.h" -#include "timer.h" +//#include "timer.h" #ifndef attribute_align_arg #if (!defined(__ICC) || __ICC > 1100) && AV_GCC_VERSION_AT_LEAST(4,2) @@ -223,10 +223,10 @@ if((y)<(x)){\ #define realloc please_use_av_realloc #undef time #define time time_is_forbidden_due_to_security_issues -#undef rand -#define rand rand_is_forbidden_due_to_state_trashing_use_av_random -#undef srand -#define srand srand_is_forbidden_due_to_state_trashing_use_av_random_init +//#undef rand +//#define rand rand_is_forbidden_due_to_state_trashing_use_av_random +//#undef srand +//#define srand srand_is_forbidden_due_to_state_trashing_use_av_random_init #undef random #define random random_is_forbidden_due_to_state_trashing_use_av_random #undef sprintf diff --git a/apps/codecs/libcook/libavutil/intreadwrite.h b/apps/codecs/libcook/libavutil/intreadwrite.h index 7c5909ea51..d27a50061e 100644 --- a/apps/codecs/libcook/libavutil/intreadwrite.h +++ b/apps/codecs/libcook/libavutil/intreadwrite.h @@ -20,7 +20,7 @@ #define AVUTIL_INTREADWRITE_H #include -#include "config.h" +//#include "ffmpeg_config.h" #include "bswap.h" #ifdef __GNUC__ diff --git a/apps/codecs/libcook/libavutil/mem.c b/apps/codecs/libcook/libavutil/mem.c index 741450b53f..7307df2384 100644 --- a/apps/codecs/libcook/libavutil/mem.c +++ b/apps/codecs/libcook/libavutil/mem.c @@ -24,7 +24,6 @@ * default memory allocator for libavutil */ -#include "config.h" #include #include diff --git a/apps/codecs/libcook/rm2wav.c b/apps/codecs/libcook/rm2wav.c new file mode 100644 index 0000000000..4ef1ec4f66 --- /dev/null +++ b/apps/codecs/libcook/rm2wav.c @@ -0,0 +1,584 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 Dave Chapman + * 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 + +#include "rm2wav.h" + +#define MAX_PATH 260 +#define PKT_HEADER_SIZE 12 +#define RAW_AUDIO_DATA packet_length-PKT_HEADER_SIZE + + +#if 0 +#define DEBUG +#define DEBUGF printf +#else +#define DEBUGF(...) +#endif + +/* ASF codec IDs */ +#define CODEC_ID_WMAV1 0x160 +#define CODEC_ID_WMAV2 0x161 + +static unsigned char wav_header[44]={ + 'R','I','F','F',// 0 - ChunkID + 0,0,0,0, // 4 - ChunkSize (filesize-8) + 'W','A','V','E',// 8 - Format + 'f','m','t',' ',// 12 - SubChunkID + 16,0,0,0, // 16 - SubChunk1ID // 16 for PCM + 1,0, // 20 - AudioFormat (1=Uncompressed) + 2,0, // 22 - NumChannels + 0,0,0,0, // 24 - SampleRate in Hz + 0,0,0,0, // 28 - Byte Rate (SampleRate*NumChannels*(BitsPerSample/8) + 4,0, // 32 - BlockAlign (== NumChannels * BitsPerSample/8) + 16,0, // 34 - BitsPerSample + 'd','a','t','a',// 36 - Subchunk2ID + 0,0,0,0 // 40 - Subchunk2Size +}; + +int open_wav(char* filename) { + int fd,res; + + fd=open(filename,O_CREAT|O_WRONLY|O_TRUNC,S_IRUSR|S_IWUSR); + if (fd >= 0) { + res = write(fd,wav_header,sizeof(wav_header)); + } + + return(fd); +} + +void close_wav(int fd, RMContext *rmctx) { + int x,res; + int filesize; + int bytes_per_sample = 2; + int samples_per_frame = rmctx->samples_pf_pc; + int nb_channels = rmctx->nb_channels; + int sample_rate = rmctx->sample_rate; + int nb_frames = rmctx->audio_framesize/rmctx->block_align * rmctx->nb_packets - 2; // first 2 frames have no valid audio; skipped in output + + filesize= samples_per_frame*bytes_per_sample*nb_frames +44; + printf("Filesize = %d\n",filesize); + + // ChunkSize + x=filesize-8; + wav_header[4]=(x&0xff); + wav_header[5]=(x&0xff00)>>8; + wav_header[6]=(x&0xff0000)>>16; + wav_header[7]=(x&0xff000000)>>24; + + // Number of channels + wav_header[22]=nb_channels; + + // Samplerate + wav_header[24]=sample_rate&0xff; + wav_header[25]=(sample_rate&0xff00)>>8; + wav_header[26]=(sample_rate&0xff0000)>>16; + wav_header[27]=(sample_rate&0xff000000)>>24; + + // ByteRate + x=sample_rate*bytes_per_sample*nb_channels; + wav_header[28]=(x&0xff); + wav_header[29]=(x&0xff00)>>8; + wav_header[30]=(x&0xff0000)>>16; + wav_header[31]=(x&0xff000000)>>24; + + // BlockAlign + wav_header[32]=rmctx->block_align;//2*rmctx->nb_channels; + + // Bits per sample + wav_header[34]=16; + + // Subchunk2Size + x=filesize-44; + wav_header[40]=(x&0xff); + wav_header[41]=(x&0xff00)>>8; + wav_header[42]=(x&0xff0000)>>16; + wav_header[43]=(x&0xff000000)>>24; + + lseek(fd,0,SEEK_SET); + res = write(fd,wav_header,sizeof(wav_header)); + close(fd); +} + +/* Some Rockbox-like functions (these should be implemented in metadata_common.[ch] */ +struct cook_extradata { + 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 */ + uint32_t unused; + uint16_t js_subband_start; /* joint stereo subband start */ + uint16_t js_vlc_bits; +}; + +static int read_uint8(int fd, uint8_t* buf) +{ + unsigned char tmp[1]; + int res; + + res=read(fd, tmp, 1); + *buf = tmp[0]; + return res; +} + +static int read_uint16be(int fd, uint16_t* buf) +{ + unsigned char tmp[2]; + int res; + + res=read(fd, tmp, 2); + *buf = (tmp[0] << 8) | tmp[1]; + return res; +} + +static int read_uint32be(int fd, uint32_t* buf) +{ + unsigned char tmp[4]; + int res; + + res=read(fd, tmp, 4); + *buf = (tmp[0] << 24) | (tmp[1] << 16) | (tmp[2] << 8) | tmp[3]; + return res; +} + +off_t filesize(int fd) +{ + struct stat buf; + + if (fstat(fd,&buf) == -1) { + return -1; + } else { + return buf.st_size; + } +} + +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) { + read_uint32be(fd, &rmctx->unused); + read_uint16be(fd, &rmctx->js_subband_start); + read_uint16be(fd, &rmctx->js_vlc_bits); + } + return rmctx->extradata_size; /* for 'skipped' */ +} + +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); + 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); + } +} + + +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; +} + +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; +} + +static int read_str(int fd, char* buf) +{ + uint8_t len; + int res; + + res = read(fd, &len, 1); + res = read(fd, buf, len); + buf[len]=0; + + return len+1; +} + +static int real_read_audio_stream_info(int fd, RMContext *rmctx) +{ + int skipped = 0; + uint32_t version; + struct real_object_t obj; + memset(&obj,0,sizeof(obj)); + uint32_t header_size; + uint16_t flavor; + uint32_t coded_framesize; + uint32_t unknown1; + uint32_t unknown2; + uint32_t unknown3; + uint16_t unknown4; + uint16_t unknown5; + uint16_t unknown6; + uint16_t unknown7; + uint32_t unknown8; + uint8_t interleaver_id_length; + uint32_t interleaver_id; + uint8_t fourcc_length; + uint32_t fourcc = 0; + uint8_t unknown9; + uint16_t unknown10; + uint8_t unknown11; + + read_uint32be(fd, &version); + skipped += 4; + + printf(" version=0x%04x\n",((version >> 16) & 0xff)); + if (((version >> 16) & 0xff) == 3) { + /* Very old version */ + } else { + real_read_object_header(fd, &obj); + skipped += 10; + 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); + + read_uint16be(fd, &flavor); + read_uint32be(fd, &coded_framesize); + read_uint32be(fd, &unknown1); + read_uint32be(fd, &unknown2); + read_uint32be(fd, &unknown3); + read_uint16be(fd, &rmctx->sub_packet_h); + read_uint16be(fd, &rmctx->block_align); + read_uint16be(fd, &rmctx->sub_packet_size); + read_uint16be(fd, &unknown4); + skipped += 26; + if (((version >> 16) & 0xff) == 5) + { + read_uint16be(fd, &unknown5); + read_uint16be(fd, &unknown6); + read_uint16be(fd, &unknown7); + skipped += 6; + } + read_uint16be(fd, &rmctx->sample_rate); + read_uint32be(fd, &unknown8); + read_uint16be(fd, &rmctx->nb_channels); + skipped += 8; + if (((version >> 16) & 0xff) == 4) + { + read_uint8(fd, &interleaver_id_length); + read_uint32be(fd, &interleaver_id); + read_uint8(fd, &fourcc_length); + read_uint32be(fd, &fourcc); + skipped += 10; + } + if (((version >> 16) & 0xff) == 5) + { + read_uint32be(fd, &interleaver_id); + read_uint32be(fd, &fourcc); + skipped += 8; + } + read_uint8(fd,&unknown9); + read_uint16be(fd,&unknown10); + skipped += 3; + if (((version >> 16) & 0xff) == 5) + { + read_uint8(fd, &unknown11); + skipped += 1; + } + + read_uint32be(fd, &rmctx->extradata_size); + skipped += 4; + if(!strncmp(fourcc2str(fourcc),"cook",4)) + skipped += read_cook_extradata(fd, rmctx); + + + 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"); + print_cook_extradata(rmctx); + + } + + return skipped; +} + +int real_parse_header(int fd, RMContext *rmctx) +{ + struct real_object_t obj; + memset(&obj,0,sizeof(obj)); + int res; + int skipped; + off_t curpos; + + uint32_t unknown1; + uint32_t unknown2; + + uint32_t max_bitrate; + 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; + uint32_t data_offset; + uint16_t num_streams; + uint16_t flags = 0; + + uint16_t stream_id; + uint32_t start_time; + char desc[256]; + char mimetype[256]; + uint32_t codec_data_size; + uint32_t v; + + char title[256]; + char author[256]; + char copyright[256]; + char comment[256]; + + uint32_t next_data_off; + uint8_t header_end; + + 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; + } + + 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); + + 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); + 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*/ + read_uint32be(fd, &max_packet_size); + read_uint32be(fd, &avg_packet_size); + read_uint32be(fd, &packet_count); + read_uint32be(fd, &duration); + read_uint32be(fd, &preroll); + read_uint32be(fd, &index_offset); + read_uint32be(fd, &data_offset); + read_uint16be(fd, &num_streams); + 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",data_offset); + printf(" num_streams = %d\n",num_streams); + printf(" flags=0x%04x\n",flags); + break; + + case FOURCC('C','O','N','T'): + /* Four strings - Title, Author, Copyright, Comment */ + skipped += read_str(fd,title); + skipped += read_str(fd,author); + 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); + break; + + case FOURCC('M','D','P','R'): /* Media properties */ + read_uint16be(fd,&stream_id); + skipped += 2; + read_uint32be(fd,&max_bitrate); + skipped += 4; + read_uint32be(fd,&avg_bitrate); + skipped += 4; + read_uint32be(fd,&max_packet_size); + skipped += 4; + read_uint32be(fd,&avg_packet_size); + skipped += 4; + read_uint32be(fd,&start_time); + skipped += 4; + read_uint32be(fd,&preroll); + skipped += 4; + read_uint32be(fd,&duration); + skipped += 4; + skipped += read_str(fd,desc); + skipped += read_str(fd,mimetype); + read_uint32be(fd,&codec_data_size); + skipped += 4; + //From ffmpeg: codec_pos = url_ftell(pb); + 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)); + + if (v == FOURCC('.','r','a',0xfd)) + { + skipped += real_read_audio_stream_info(fd, rmctx); + } + + break; + + case FOURCC('D','A','T','A'): + + 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; + printf(" data_nb_packets = %d\n",rmctx->nb_packets); + printf(" next DATA offset = %d\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; +} + +void rm_get_packet(int fd,RMContext *rmctx, RMPacket *pkt) +{ + uint8_t unknown,packet_group; + uint16_t x, place; + uint16_t sps = rmctx->sub_packet_size; + uint16_t h = rmctx->sub_packet_h; + uint16_t y = rmctx->sub_packet_cnt; + uint16_t w = rmctx->audio_framesize; + do + { + y = rmctx->sub_packet_cnt; + read_uint16be(fd,&pkt->version); + read_uint16be(fd,&pkt->length); + read_uint16be(fd,&pkt->stream_number); + read_uint32be(fd,&pkt->timestamp); + DEBUGF(" version = %d\n" + " length = %d\n" + " stream = %d\n" + " timestmp= %d\n",pkt->version,pkt->length,pkt->stream_number,pkt->timestamp); + + //getchar(); + if(pkt->version == 0) + { + read_uint8(fd,&packet_group); + read_uint8(fd,&pkt->flags); + } + if(pkt->version == 1) + read_uint8(fd,&unknown); + + if (pkt->flags & 2) /* keyframe */ + y = rmctx->sub_packet_cnt = 0; + if (!y) /* if keyframe update playback elapsed time */ + rmctx->audiotimestamp = pkt->timestamp; + + 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]); + } + rmctx->audio_pkt_cnt++; + }while(++(rmctx->sub_packet_cnt) < h); + + //return pkt->data; +} +#ifdef DEBUG +void dump_rm_context(RMContext *rmctx) +{ + DEBUGF("block_align = %d\n", rmctx->block_align); + DEBUGF("nb_channels = %d\n", rmctx->nb_channels); + DEBUGF("sample_rate = %d\n", rmctx->sample_rate); + DEBUGF("bit_rate = %d\n", rmctx->bit_rate ); +} +#endif diff --git a/apps/codecs/libcook/rm2wav.h b/apps/codecs/libcook/rm2wav.h new file mode 100644 index 0000000000..09b20c7fa6 --- /dev/null +++ b/apps/codecs/libcook/rm2wav.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * __________ __ ___. + * 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 + +typedef struct rm_packet +{ + uint8_t data[30000]; /* Reordered data. No malloc, hence the size */ + uint16_t version; + uint16_t length; + uint32_t timestamp; + uint16_t stream_number; + uint8_t flags; +}RMPacket; + +typedef struct rm_context +{ + /* Demux Context */ + int old_format; + int current_stream; + int remaining_len; + int audio_stream_num; /*< Stream number for audio packets*/ + int audio_pkt_cnt; /* Output packet counter*/ + + /* Stream Variables */ + 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 */ + uint16_t audio_framesize; /* Audio frame size from container */ + uint16_t sub_packet_lengths[16]; /* Length of each subpacket */ + + /* Codec Context */ + uint16_t block_align; + uint32_t nb_packets; + int frame_number; + uint32_t extradata_size; + uint16_t sample_rate; + uint16_t nb_channels; + uint32_t bit_rate; + uint16_t flags; + + /*cook extradata*/ + 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 */ + 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); -- cgit v1.2.3