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
This commit is contained in:
parent
03fe562a95
commit
e184ef1027
22 changed files with 967 additions and 327 deletions
|
@ -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
|
||||
|
|
|
@ -9,6 +9,7 @@ wavpack.c
|
|||
#ifndef RB_PROFILE
|
||||
alac.c
|
||||
#endif
|
||||
cook.c
|
||||
mpc.c
|
||||
wma.c
|
||||
sid.c
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
144
apps/codecs/cook.c
Normal file
144
apps/codecs/cook.c
Normal file
|
@ -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 <string.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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
|
||||
|
|
3
apps/codecs/libcook/SOURCES
Normal file
3
apps/codecs/libcook/SOURCES
Normal file
|
@ -0,0 +1,3 @@
|
|||
cook.c
|
||||
bitstream.c
|
||||
../librm/rm.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<words; i++) put_bits(pb, 16, AV_RB16(&srcw[i]));
|
||||
}else{
|
||||
for(i=0; put_bits_count(pb)&31; i++)
|
||||
put_bits(pb, 8, src[i]);
|
||||
flush_put_bits(pb);
|
||||
memcpy(pbBufPtr(pb), src+i, 2*words-i);
|
||||
skip_put_bytes(pb, 2*words-i);
|
||||
}
|
||||
|
||||
put_bits(pb, bits, AV_RB16(&srcw[words])>>(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<<n);
|
||||
#ifdef DEBUG_VLC
|
||||
printf("%4x: code=%d n=%d\n",
|
||||
DEBUGF("%4x: code=%d n=%d\n",
|
||||
j, i, n);
|
||||
#endif
|
||||
if (table[j][1] /*bits*/ != 0) {
|
||||
printf("incorrect codes\n");
|
||||
DEBUGF("incorrect codes\n");
|
||||
return -1;
|
||||
}
|
||||
table[j][1] = n; //bits
|
||||
|
@ -207,7 +164,7 @@ static int build_table(VLC *vlc, int table_nb_bits,
|
|||
n -= table_nb_bits;
|
||||
j = (code >> ((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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
@ -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 */
|
||||
|
|
|
@ -1,86 +1,137 @@
|
|||
/*
|
||||
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
|
||||
*
|
||||
* 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
|
||||
#ifndef __BSWAP_H__
|
||||
#define __BSWAP_H__
|
||||
|
||||
#include <stdint.h>
|
||||
//#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_16
|
||||
static inline uint16_t bswap_16(uint16_t x)
|
||||
{
|
||||
x= (x>>8) | (x<<8);
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef bswap_32
|
||||
static inline uint32_t bswap_32(uint32_t x)
|
||||
{
|
||||
x= ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF);
|
||||
x= (x>>16) | (x<<16);
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef bswap_64
|
||||
static inline uint64_t bswap_64(uint64_t x)
|
||||
{
|
||||
#if 0
|
||||
x= ((x<< 8)&0xFF00FF00FF00FF00ULL) | ((x>> 8)&0x00FF00FF00FF00FFULL);
|
||||
x= ((x<<16)&0xFFFF0000FFFF0000ULL) | ((x>>16)&0x0000FFFF0000FFFFULL);
|
||||
return (x>>32) | (x<<32);
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
#include <byteswap.h>
|
||||
#else
|
||||
union {
|
||||
|
||||
#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)
|
||||
{
|
||||
union {
|
||||
uint64_t ll;
|
||||
uint32_t l[2];
|
||||
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)
|
||||
|
||||
#elif defined(ARCH_X86)
|
||||
static inline unsigned short ByteSwap16(unsigned short x)
|
||||
{
|
||||
__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)
|
||||
|
||||
static inline unsigned long long int ByteSwap64(unsigned long long int x)
|
||||
{
|
||||
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
|
||||
|
||||
#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];
|
||||
} 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)
|
||||
|
||||
// be2me ... big-endian to machine-endian
|
||||
// le2me ... little-endian to machine-endian
|
||||
#endif /* !ARCH_X86 */
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#endif /* !HAVE_BYTESWAP_H */
|
||||
|
||||
// be2me ... BigEndian to MachineEndian
|
||||
// le2me ... LittleEndian to MachineEndian
|
||||
|
||||
#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__ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#ifndef _COOK_H
|
||||
#define _COOK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#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 */
|
||||
|
|
|
@ -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 <codecs/lib/codeclib.h>
|
||||
|
||||
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.
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* fixed point data types and constants
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
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,
|
||||
|
|
18
apps/codecs/libcook/libcook.make
Normal file
18
apps/codecs/libcook/libcook.make
Normal file
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -21,28 +21,34 @@
|
|||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "rm.h"
|
||||
|
||||
|
||||
#if 0
|
||||
#define DEBUG
|
||||
#define DEBUGF printf
|
||||
#else
|
||||
#define DEBUGF(...)
|
||||
#ifdef ROCKBOX
|
||||
#include "codeclib.h"
|
||||
#endif
|
||||
|
||||
/* Some Rockbox-like functions (these should be implemented in metadata_common.[ch] */
|
||||
|
||||
void advance_buffer(uint8_t **buf, int val)
|
||||
{
|
||||
*buf += val;
|
||||
}
|
||||
|
||||
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 <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
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
|
||||
|
|
|
@ -22,17 +22,21 @@
|
|||
#define _RM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 -
|
||||
|
|
|
@ -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);
|
||||
|
|
420
apps/metadata/rm.c
Normal file
420
apps/metadata/rm.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <codecs/librm/rm.h>
|
||||
#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;
|
||||
}
|
Loading…
Reference in a new issue