diff --git a/apps/codecs/libwmapro/SOURCES b/apps/codecs/libwmapro/SOURCES new file mode 100644 index 0000000000..da2d2860d8 --- /dev/null +++ b/apps/codecs/libwmapro/SOURCES @@ -0,0 +1,9 @@ +wmaprodec.c +wma.c +dsputil.c +mdct.c +fft.c +bitstream.c +libavutil/log.c +libavutil/mem.c +libavutil/mathematics.c diff --git a/apps/codecs/libwmapro/bitstream.c b/apps/codecs/libwmapro/bitstream.c index 47234e10e1..deb1d631e2 100644 --- a/apps/codecs/libwmapro/bitstream.c +++ b/apps/codecs/libwmapro/bitstream.c @@ -296,7 +296,7 @@ int init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes, av_log(NULL,AV_LOG_DEBUG,"build table nb_codes=%d\n", nb_codes); #endif - assert(symbols_size <= 2 || !symbols); + //assert(symbols_size <= 2 || !symbols); j = 0; #define COPY(condition)\ for (i = 0; i < nb_codes; i++) {\ diff --git a/apps/codecs/libwmapro/dsputil.h b/apps/codecs/libwmapro/dsputil.h index d1816e66ba..80bc3ab262 100644 --- a/apps/codecs/libwmapro/dsputil.h +++ b/apps/codecs/libwmapro/dsputil.h @@ -443,7 +443,7 @@ typedef struct DSPContext { * @param v2 second input vector, difference output, 16-byte aligned * @param len length of vectors, multiple of 4 */ - void (*butterflies_float)(float *restrict v1, float *restrict v2, int len); + void (*butterflies_float)(float * v1, float * v2, int len); /* C version: convert floats from the range [384.0,386.0] to ints in [-32768,32767] * simd versions: convert floats from [-32768.0,32767.0] without rescaling and arrays are 16byte aligned */ diff --git a/apps/codecs/libwmapro/fft.c b/apps/codecs/libwmapro/fft.c index bc1b4f1796..b0e6e11cd3 100644 --- a/apps/codecs/libwmapro/fft.c +++ b/apps/codecs/libwmapro/fft.c @@ -102,11 +102,11 @@ av_cold int ff_fft_init(FFTContext *s, int nbits, int inverse) s->fft_permute = ff_fft_permute_c; s->fft_calc = ff_fft_calc_c; -#if CONFIG_MDCT +//#if CONFIG_MDCT s->imdct_calc = ff_imdct_calc_c; s->imdct_half = ff_imdct_half_c; s->mdct_calc = ff_mdct_calc_c; -#endif +//#endif s->exptab1 = NULL; s->split_radix = 1; #if 0 diff --git a/apps/codecs/libwmapro/get_bits.h b/apps/codecs/libwmapro/get_bits.h index c325778d67..a21d05210f 100644 --- a/apps/codecs/libwmapro/get_bits.h +++ b/apps/codecs/libwmapro/get_bits.h @@ -28,7 +28,7 @@ #include #include -#include +//#include #include "libavutil/bswap.h" #include "libavutil/common.h" #include "libavutil/intreadwrite.h" diff --git a/apps/codecs/libwmapro/libavutil/internal.h b/apps/codecs/libwmapro/libavutil/internal.h index 2b8da1d8c2..97087e462a 100644 --- a/apps/codecs/libwmapro/libavutil/internal.h +++ b/apps/codecs/libwmapro/libavutil/internal.h @@ -33,7 +33,7 @@ #include #include #include -#include +//#include //#include "config.h" #include "attributes.h" //#include "timer.h" @@ -142,8 +142,8 @@ #endif /* avoid usage of dangerous/inappropriate system functions */ -#undef malloc -#define malloc please_use_av_malloc +//#undef malloc +//#define malloc please_use_av_malloc #undef free #define free please_use_av_free #undef realloc @@ -163,8 +163,8 @@ #undef exit #define exit exit_is_forbidden #ifndef LIBAVFORMAT_BUILD -#undef printf -#define printf please_use_av_log_instead_of_printf +//#undef printf +//#define printf please_use_av_log_instead_of_printf #undef fprintf #define fprintf please_use_av_log_instead_of_fprintf #undef puts diff --git a/apps/codecs/libwmapro/libavutil/log.c b/apps/codecs/libwmapro/libavutil/log.c index 166e724b07..6cbe0da8b8 100644 --- a/apps/codecs/libwmapro/libavutil/log.c +++ b/apps/codecs/libwmapro/libavutil/log.c @@ -54,10 +54,10 @@ void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl) return; } if(count>0){ - fprintf(stderr, " Last message repeated %d times\n", count); + //fprintf(stderr, " Last message repeated %d times\n", count); count=0; } - fputs(line, stderr); + //fputs(line, stderr); strcpy(prev, line); } diff --git a/apps/codecs/libwmapro/libavutil/mathematics.c b/apps/codecs/libwmapro/libavutil/mathematics.c index 04f3e870d1..7af0104516 100644 --- a/apps/codecs/libwmapro/libavutil/mathematics.c +++ b/apps/codecs/libwmapro/libavutil/mathematics.c @@ -23,7 +23,7 @@ * miscellaneous math routines and tables */ -#include +//#include #include #include #include "mathematics.h" @@ -76,9 +76,9 @@ int64_t av_gcd(int64_t a, int64_t b){ int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd){ int64_t r=0; - assert(c > 0); - assert(b >=0); - assert(rnd >=0 && rnd<=5 && rnd!=4); + //assert(c > 0); + //assert(b >=0); + //assert(rnd >=0 && rnd<=5 && rnd!=4); if(a<0 && a != INT64_MIN) return -av_rescale_rnd(-a, b, c, rnd ^ ((rnd>>1)&1)); diff --git a/apps/codecs/libwmapro/libwmapro.make b/apps/codecs/libwmapro/libwmapro.make new file mode 100644 index 0000000000..9177eafb20 --- /dev/null +++ b/apps/codecs/libwmapro/libwmapro.make @@ -0,0 +1,18 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +# libwmapro +WMAPROLIB := $(CODECDIR)/libwmapro.a +WMAPROLIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libwmapro/SOURCES) +WMAPROLIB_OBJ := $(call c2obj, $(WMAPROLIB_SRC)) +OTHER_SRC += $(WMAPROLIB_SRC) + +$(WMAPROLIB): $(WMAPROLIB_OBJ) + $(SILENT)$(shell rm -f $@) + $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null diff --git a/apps/codecs/libwmapro/mdct_tablegen.h b/apps/codecs/libwmapro/mdct_tablegen.h index 9f130aa6b5..998f86f283 100644 --- a/apps/codecs/libwmapro/mdct_tablegen.h +++ b/apps/codecs/libwmapro/mdct_tablegen.h @@ -20,7 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +//#include // do not use libavutil/mathematics.h since this is compiled both // for the host and the target and config.h is only valid for the target #include @@ -53,7 +53,7 @@ av_cold void ff_sine_window_init(float *window, int n) { } av_cold void ff_init_ff_sine_windows(int index) { - assert(index >= 0 && index < FF_ARRAY_ELEMS(ff_sine_windows)); + //assert(index >= 0 && index < FF_ARRAY_ELEMS(ff_sine_windows)); #if !CONFIG_HARDCODED_TABLES ff_sine_window_init(ff_sine_windows[index], 1 << index); #endif diff --git a/apps/codecs/libwmapro/put_bits.h b/apps/codecs/libwmapro/put_bits.h index c0139661a5..9f66256b79 100644 --- a/apps/codecs/libwmapro/put_bits.h +++ b/apps/codecs/libwmapro/put_bits.h @@ -28,7 +28,7 @@ #include #include -#include +//#include #include "libavutil/bswap.h" #include "libavutil/common.h" #include "libavutil/intreadwrite.h" @@ -153,7 +153,7 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value) int bit_left; // printf("put_bits=%d %x\n", n, value); - assert(n <= 31 && value < (1U << n)); + //assert(n <= 31 && value < (1U << n)); bit_buf = s->bit_buf; bit_left = s->bit_left; @@ -264,7 +264,7 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value) static inline void put_sbits(PutBitContext *pb, int n, int32_t value) { - assert(n >= 0 && n <= 31); + //assert(n >= 0 && n <= 31); put_bits(pb, n, value & ((1<index += n<<3; #else - assert(s->bit_left==32); + //assert(s->bit_left==32); s->buf_ptr += n; #endif } diff --git a/apps/codecs/libwmapro/wma.c b/apps/codecs/libwmapro/wma.c index 5306634c7c..4b36c84aad 100644 --- a/apps/codecs/libwmapro/wma.c +++ b/apps/codecs/libwmapro/wma.c @@ -23,8 +23,8 @@ #include "wma.h" //#include "wmadata.h" -#undef NDEBUG -#include +//#undef NDEBUG +//#include #if 0 /* XXX: use same run/length optimization as mpeg decoders */ //FIXME maybe split decode / encode or pass flag diff --git a/apps/codecs/libwmapro/wmaprodec.c b/apps/codecs/libwmapro/wmaprodec.c index 88d317d5f6..e72919434c 100644 --- a/apps/codecs/libwmapro/wmaprodec.c +++ b/apps/codecs/libwmapro/wmaprodec.c @@ -93,13 +93,11 @@ #include "wmaprodata.h" #include "dsputil.h" #include "wma.h" +#include "wmaprodec.h" /* Some defines to make it compile */ #define AVERROR_INVALIDDATA -1 #define AVERROR_PATCHWELCOME -2 -#ifndef M_PI -#define M_PI 3.14159265358979323846 /* pi */ -#endif #define av_log_ask_for_sample(...) /** current decoder limitations */ @@ -238,8 +236,8 @@ typedef struct WMAProDecodeCtx { */ static void av_cold dump_context(WMAProDecodeCtx *s) { -#define PRINT(a, b) av_log(s->avctx, AV_LOG_DEBUG, " %s = %d\n", a, b); -#define PRINT_HEX(a, b) av_log(s->avctx, AV_LOG_DEBUG, " %s = %x\n", a, b); +#define PRINT(a, b) printf(" %s = %d\n", a, b); +#define PRINT_HEX(a, b) printf(" %s = %x\n", a, b); PRINT("ed sample bit depth", s->bits_per_sample); PRINT_HEX("ed decode flags", s->decode_flags); @@ -255,7 +253,7 @@ static void av_cold dump_context(WMAProDecodeCtx *s) *@param avctx codec context *@return 0 on success, < 0 otherwise */ -static av_cold int decode_end(AVCodecContext *avctx) +av_cold int decode_end(AVCodecContext *avctx) { WMAProDecodeCtx *s = avctx->priv_data; int i; @@ -271,8 +269,10 @@ static av_cold int decode_end(AVCodecContext *avctx) *@param avctx codec context *@return 0 on success, -1 otherwise */ -static av_cold int decode_init(AVCodecContext *avctx) +av_cold int decode_init(AVCodecContext *avctx) { + avctx->priv_data = malloc(sizeof(WMAProDecodeCtx)); + memset(avctx->priv_data, 0, sizeof(WMAProDecodeCtx)); WMAProDecodeCtx *s = avctx->priv_data; uint8_t *edata_ptr = avctx->extradata; unsigned int channel_mask; @@ -454,7 +454,6 @@ static av_cold int decode_init(AVCodecContext *avctx) sin64[i] = sin(i*M_PI / 64.0); #if 0 if (avctx->debug & FF_DEBUG_BITSTREAM) - dump_context(s); #endif avctx->channel_layout = channel_mask; @@ -1379,7 +1378,7 @@ static int decode_frame(WMAProDecodeCtx *s) if (len != (get_bits_count(gb) - s->frame_offset) + 2) { /** FIXME: not sure if this is always an error */ av_log(s->avctx, AV_LOG_ERROR, "frame[%i] would have to skip %i bits\n", - s->frame_num, len - (get_bits_count(gb) - s->frame_offset) - 1); + (int)s->frame_num, len - (get_bits_count(gb) - s->frame_offset) - 1); s->packet_loss = 1; return 0; } @@ -1465,7 +1464,7 @@ static void save_bits(WMAProDecodeCtx *s, GetBitContext* gb, int len, *@param avpkt input packet *@return number of bytes that were read from the input buffer */ -static int decode_packet(AVCodecContext *avctx, +int decode_packet(AVCodecContext *avctx, void *data, int *data_size, AVPacket* avpkt) { WMAProDecodeCtx *s = avctx->priv_data; @@ -1549,6 +1548,20 @@ static int decode_packet(AVCodecContext *avctx, *data_size = (int8_t *)s->samples - (int8_t *)data; s->packet_offset = get_bits_count(gb) & 7; +/* Convert the pcm samples to signed 16-bit integers. This is the format that + * the rockbox simulator works with. */ +#ifdef ROCKBOX + float* fptr = data; + int32_t* ptr = data; + int x; + for(x = 0; x < *data_size; x++) + { + fptr[x] *= ((float)(INT32_MAX)); + ptr[x] = (int32_t)fptr[x]; + + } +#endif + return (s->packet_loss) ? AVERROR_INVALIDDATA : get_bits_count(gb) >> 3; } diff --git a/apps/codecs/libwmapro/wmaprodec.h b/apps/codecs/libwmapro/wmaprodec.h new file mode 100644 index 0000000000..045481b529 --- /dev/null +++ b/apps/codecs/libwmapro/wmaprodec.h @@ -0,0 +1,6 @@ +#include "avcodec.h" + +av_cold int decode_end(AVCodecContext *avctx); +av_cold int decode_init(AVCodecContext *avctx); +int decode_packet(AVCodecContext *avctx, + void *data, int *data_size, AVPacket* avpkt); diff --git a/apps/codecs/wmapro.c b/apps/codecs/wmapro.c index e15a610679..9e03555917 100644 --- a/apps/codecs/wmapro.c +++ b/apps/codecs/wmapro.c @@ -20,14 +20,166 @@ ****************************************************************************/ #include "codeclib.h" +#include "libasf/asf.h" +#include "libwmapro/wmaprodec.h" CODEC_HEADER +#define MAXSAMPLES (1L << 12) /* Max number of samples in a wma pro subframe */ +#define MAXCHANNELS 8 +#define BUFSIZE MAXCHANNELS * MAXSAMPLES +static int32_t decoded[BUFSIZE] IBSS_ATTR; + +AVCodecContext avctx; +AVPacket avpkt; + +/* This function initialises AVCodecContext with the data needed for the wmapro + * decoder to work. The required data is taken from asf_waveformatex_t because that's + * what the rockbox asf metadata parser fill/work with. In the future, when the + * codec is being optimised for on-target playback this function should not be needed, + * as we will be working directly with WMAProDecodeCtx (declared in wmaprodec.c) */ +static void init_codec_ctx(AVCodecContext *avctx, asf_waveformatex_t *wfx) +{ + /* Copy the extra-data */ + avctx->extradata_size = wfx->datalen; + avctx->extradata = (uint8_t *)malloc(wfx->datalen*sizeof(uint8_t)); + memcpy(avctx->extradata, wfx->data, wfx->datalen*sizeof(uint8_t)); + + avctx->block_align = wfx->blockalign; + avctx->sample_rate = wfx->rate; + avctx->channels = wfx->channels; + +} + /* this is the codec entry point */ enum codec_status codec_main(void) { - DEBUGF("WMA: WMA Professional has not been implemented yet\n"); + uint32_t elapsedtime; + int retval; + asf_waveformatex_t wfx; /* Holds the stream properties */ + size_t resume_offset; + int res; /* Return values from asf_read_packet() and decode_packet() */ + uint8_t* audiobuf; /* Pointer to the payload of one wma pro packet */ + int audiobufsize; /* Payload size */ + int packetlength = 0; /* Logical packet size (minus the header size) */ + int outlen = 0; /* Number of bytes written to the output buffer */ + int pktcnt = 0; /* Count of the packets played */ + + /* Generic codec initialisation */ + ci->configure(DSP_SET_SAMPLE_DEPTH, 32); - return CODEC_ERROR; + +next_track: + + /* Wait for the metadata to be read */ + while (!*ci->taginfo_ready && !ci->stop_codec) + ci->sleep(1); + + retval = CODEC_OK; + + /* Remember the resume position */ + resume_offset = ci->id3->offset; + restart_track: + if (codec_init()) { + LOGF("(WMA PRO) Error: Error initialising codec\n"); + retval = CODEC_ERROR; + goto done; + } + + /* Copy the format metadata we've stored in the id3 TOC field. This + saves us from parsing it again here. */ + memcpy(&wfx, ci->id3->toc, sizeof(wfx)); + + ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate); + ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ? + STEREO_MONO : STEREO_INTERLEAVED); + codec_set_replaygain(ci->id3); + + /* Initialise the AVCodecContext */ + init_codec_ctx(&avctx, &wfx); + + if (decode_init(&avctx) < 0) { + LOGF("(WMA PRO) Error: Unsupported or corrupt file\n"); + retval = CODEC_ERROR; + goto done; + } + + /* Now advance the file position to the first frame */ + ci->seek_buffer(ci->id3->first_frame_offset); + + elapsedtime = 0; + resume_offset = 0; + + /* The main decoding loop */ + + while (pktcnt < wfx.numpackets) + { + ci->yield(); + if (ci->stop_codec || ci->new_track) { + goto done; + } + + /* Deal with any pending seek requests */ + if (ci->seek_time){ + + if (ci->seek_time == 1) { + ci->seek_complete(); + goto restart_track; /* Pretend you never saw this... */ + } + + elapsedtime = asf_seek(ci->seek_time, &wfx); + if (elapsedtime < 1){ + ci->seek_complete(); + goto next_track; + } + + ci->set_elapsed(elapsedtime); + ci->seek_complete(); + } + + res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx); + + if (res < 0) { + LOGF("(WMA PRO) Warning: asf_read_packet returned %d", res); + goto done; + } else { + avpkt.data = audiobuf; + avpkt.size = audiobufsize; + pktcnt++; + + /* We now loop on the packet, decoding and outputting the subframes + * one-by-one. For more information about how wma pro structures its + * audio frames, see libwmapro/wmaprodec.c */ + while(avpkt.size > 0) + { + outlen = BUFSIZE; /* decode_packet needs to know the size of the output buffer */ + res = decode_packet(&avctx, decoded, &outlen, &avpkt); + avpkt.data += res; + avpkt.size -= res; + avctx.frame_number++; + if(outlen) { + ci->yield (); + /* outlen now holds the size of the data in bytes - we want the + * number of samples. */ + outlen /= (sizeof(int32_t) * wfx.channels); + ci->pcmbuf_insert(decoded, NULL, outlen); + elapsedtime += outlen*10/(wfx.rate/100); + ci->set_elapsed(elapsedtime); + ci->yield (); + } + } + + } + + /* Advance to the next logical packet */ + ci->advance_buffer(packetlength); + } + retval = CODEC_OK; + +done: + if (ci->request_next_track()) + goto next_track; + + return retval; } diff --git a/apps/metadata/asf.c b/apps/metadata/asf.c index db806ea17f..ba1b8972af 100644 --- a/apps/metadata/asf.c +++ b/apps/metadata/asf.c @@ -274,9 +274,14 @@ static int asf_parse_header(int fd, struct mp3entry* id3, } fileprop = 1; - /* All we want is the play duration - uint64_t at offset 40 */ - lseek(fd, 40, SEEK_CUR); - + + /* Get the number of logical packets - uint16_t at offset 31 + * (Big endian byte order) */ + lseek(fd, 31, SEEK_CUR); + read_uint16be(fd, &wfx->numpackets); + + /* Now get the play duration - uint64_t at offset 40 */ + lseek(fd, 7, SEEK_CUR); read_uint64le(fd, &play_duration); id3->length = play_duration / 10000; @@ -346,8 +351,9 @@ static int asf_parse_header(int fd, struct mp3entry* id3, lseek(fd,current.size - 24 - 72 - 6,SEEK_CUR); wfx->audiostream = flags&0x7f; } else if (wfx->codec_id == ASF_CODEC_ID_WMAPRO) { - read(fd, wfx->data, 10); - lseek(fd,current.size - 24 - 72 - 10,SEEK_CUR); + /* wma pro decoder needs the extra-data */ + read(fd, wfx->data, wfx->datalen); + lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR); wfx->audiostream = flags&0x7f; /* Correct codectype to redirect playback to the proper .codec */ id3->codectype = AFMT_WMAPRO;