WMA Voice now plays and seeks in the sim. The code is still in floating point, and is not added to the main build. There's still a bug with the decoder in the current state that it outputs a fewer number of samples than ffmpeg's.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27744 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
eb369699c6
commit
4ff2cf4f0c
9 changed files with 296 additions and 7 deletions
|
@ -7,6 +7,7 @@
|
|||
#define ASF_CODEC_ID_WMAV1 0x160
|
||||
#define ASF_CODEC_ID_WMAV2 0x161
|
||||
#define ASF_CODEC_ID_WMAPRO 0x162
|
||||
#define ASF_CODEC_ID_WMAVOICE 0x00A
|
||||
|
||||
enum asf_error_e {
|
||||
ASF_ERROR_INTERNAL = -1, /* incorrect input to API calls */
|
||||
|
@ -33,7 +34,7 @@ struct asf_waveformatex_s {
|
|||
uint16_t bitspersample;
|
||||
uint16_t datalen;
|
||||
uint16_t numpackets;
|
||||
uint8_t data[18];
|
||||
uint8_t data[46];
|
||||
};
|
||||
typedef struct asf_waveformatex_s asf_waveformatex_t;
|
||||
|
||||
|
|
17
apps/codecs/libwmavoice/SOURCES
Normal file
17
apps/codecs/libwmavoice/SOURCES
Normal file
|
@ -0,0 +1,17 @@
|
|||
acelp_filters.c
|
||||
acelp_vectors.c
|
||||
avfft.c
|
||||
bitstream.c
|
||||
celp_filters.c
|
||||
celp_math.c
|
||||
dct.c
|
||||
fft.c
|
||||
lsp.c
|
||||
mdct.c
|
||||
rdft.c
|
||||
utils.c
|
||||
wmavoice.c
|
||||
libavutil/log.c
|
||||
libavutil/lzo.c
|
||||
libavutil/mem.c
|
||||
libavutil/mathematics.c
|
37
apps/codecs/libwmavoice/libwmavoice.make
Normal file
37
apps/codecs/libwmavoice/libwmavoice.make
Normal file
|
@ -0,0 +1,37 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id: libwmavoice.make 27586 2010-07-27 06:48:15Z nls $
|
||||
#
|
||||
|
||||
# libwmavoice
|
||||
WMAVOICELIB := $(CODECDIR)/libwmavoice.a
|
||||
WMAVOICELIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libwmavoice/SOURCES)
|
||||
WMAVOICELIB_OBJ := $(call c2obj, $(WMAVOICELIB_SRC))
|
||||
OTHER_SRC += $(WMAVOICELIB_SRC)
|
||||
|
||||
$(WMAVOICELIB): $(WMAVOICELIB_OBJ)
|
||||
$(SILENT)$(shell rm -f $@)
|
||||
$(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
|
||||
|
||||
WMAVOICEFLAGS = -I$(APPSDIR)/codecs/libwmavoice $(filter-out -O%,$(CODECFLAGS))
|
||||
|
||||
ifeq ($(CPU),coldfire)
|
||||
WMAVOICEFLAGS += -O2
|
||||
else
|
||||
WMAVOICEFLAGS += -O1
|
||||
endif
|
||||
|
||||
ifeq ($(APP_TYPE),sdl-sim)
|
||||
# wmavoice needs libm in the simulator
|
||||
$(CODECDIR)/wmavoice.codec: $(CODECDIR)/wmavoice.o
|
||||
$(call PRINTS,LD $(@F))$(CC) $(CODECFLAGS) -o $(CODECDIR)/wmavoice.elf \
|
||||
$(filter %.o, $^) \
|
||||
$(filter %.a, $+) \
|
||||
-lgcc -lm $(CODECLDFLAGS)
|
||||
$(SILENT)cp $(CODECDIR)/wmavoice.elf $@
|
||||
endif
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "avcodec.h"
|
||||
#include "wmavoice.h"
|
||||
#include "get_bits.h"
|
||||
#include "put_bits.h"
|
||||
#include "wmavoice_data.h"
|
||||
|
@ -286,6 +286,10 @@ typedef struct {
|
|||
*/
|
||||
} WMAVoiceContext;
|
||||
|
||||
/* global decode context */
|
||||
static WMAVoiceContext globWMAVoiceCtx;
|
||||
|
||||
|
||||
/**
|
||||
* Set up the variable bit mode (VBM) tree from container extradata.
|
||||
* @param gb bit I/O context.
|
||||
|
@ -330,9 +334,10 @@ static av_cold int decode_vbmtree(GetBitContext *gb, int8_t vbm_tree[25])
|
|||
/**
|
||||
* Set up decoder with parameters from demuxer (extradata etc.).
|
||||
*/
|
||||
static av_cold int wmavoice_decode_init(AVCodecContext *ctx)
|
||||
av_cold int wmavoice_decode_init(AVCodecContext *ctx)
|
||||
{
|
||||
int n, flags, pitch_range, lsp16_flag;
|
||||
ctx->priv_data = &globWMAVoiceCtx;
|
||||
WMAVoiceContext *s = ctx->priv_data;
|
||||
|
||||
/**
|
||||
|
@ -1743,7 +1748,7 @@ static int synth_superframe(AVCodecContext *ctx,
|
|||
* the wild yet. */
|
||||
if (!get_bits1(gb)) {
|
||||
av_log_missing_feature(ctx, "WMAPro-in-WMAVoice support", 1);
|
||||
return -1;
|
||||
return ERROR_WMAPRO_IN_WMAVOICE;
|
||||
}
|
||||
|
||||
/* (optional) nr. of samples in superframe; always <= 480 and >= 0 */
|
||||
|
@ -1893,7 +1898,7 @@ static void copy_bits(PutBitContext *pb,
|
|||
*
|
||||
* For more information about frames, see #synth_superframe().
|
||||
*/
|
||||
static int wmavoice_decode_packet(AVCodecContext *ctx, void *data,
|
||||
int wmavoice_decode_packet(AVCodecContext *ctx, void *data,
|
||||
int *data_size, AVPacket *avpkt)
|
||||
{
|
||||
WMAVoiceContext *s = ctx->priv_data;
|
||||
|
@ -1936,6 +1941,15 @@ static int wmavoice_decode_packet(AVCodecContext *ctx, void *data,
|
|||
s->sframe_cache_size += s->spillover_nbits;
|
||||
if ((res = synth_superframe(ctx, data, data_size)) == 0 &&
|
||||
*data_size > 0) {
|
||||
/* convert the float values to int32 for rockbox */
|
||||
int i;
|
||||
int32_t *iptr = data;
|
||||
float *fptr = data;
|
||||
for(i = 0; i < *data_size/sizeof(float); i++)
|
||||
{
|
||||
fptr[i] *= (float)(INT32_MAX);
|
||||
iptr[i] = (int32_t)fptr[i];
|
||||
}
|
||||
cnt += s->spillover_nbits;
|
||||
s->skip_bits_next = cnt & 7;
|
||||
return cnt >> 3;
|
||||
|
@ -1957,12 +1971,21 @@ static int wmavoice_decode_packet(AVCodecContext *ctx, void *data,
|
|||
} else if (*data_size > 0) {
|
||||
int cnt = get_bits_count(gb);
|
||||
s->skip_bits_next = cnt & 7;
|
||||
/* convert the float values to int32 for rockbox */
|
||||
int i;
|
||||
int32_t *iptr = data;
|
||||
float *fptr = data;
|
||||
for(i = 0; i < *data_size/sizeof(float); i++)
|
||||
{
|
||||
fptr[i] *= (float)(INT32_MAX);
|
||||
iptr[i] = (int32_t)fptr[i];
|
||||
}
|
||||
return cnt >> 3;
|
||||
} else if ((s->sframe_cache_size = pos) > 0) {
|
||||
/* rewind bit reader to start of last (incomplete) superframe... */
|
||||
init_get_bits(gb, avpkt->data, size << 3);
|
||||
skip_bits_long(gb, (size << 3) - pos);
|
||||
assert(get_bits_left(gb) == pos);
|
||||
//assert(get_bits_left(gb) == pos);
|
||||
|
||||
/* ...and cache it for spillover in next packet */
|
||||
init_put_bits(&s->pb, s->sframe_cache, SFRAME_CACHE_MAXSIZE);
|
||||
|
|
7
apps/codecs/libwmavoice/wmavoice.h
Normal file
7
apps/codecs/libwmavoice/wmavoice.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include "avcodec.h"
|
||||
|
||||
#define ERROR_WMAPRO_IN_WMAVOICE -0x162
|
||||
|
||||
av_cold int wmavoice_decode_init(AVCodecContext *ctx);
|
||||
int wmavoice_decode_packet(AVCodecContext *ctx, void *data,
|
||||
int *data_size, AVPacket *avpkt);
|
195
apps/codecs/wmavoice.c
Normal file
195
apps/codecs/wmavoice.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2010 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 "codeclib.h"
|
||||
#include "libasf/asf.h"
|
||||
#include "libwmavoice/wmavoice.h"
|
||||
|
||||
CODEC_HEADER
|
||||
|
||||
static AVCodecContext avctx;
|
||||
static AVPacket avpkt;
|
||||
|
||||
#define MAX_FRAMES 3 /*maximum number of frames per superframe*/
|
||||
#define MAX_FRAMESIZE 160 /* maximum number of samples per frame */
|
||||
#define BUFSIZE MAX_FRAMES*MAX_FRAMESIZE
|
||||
static int32_t decoded[BUFSIZE] IBSS_ATTR;
|
||||
|
||||
|
||||
/* 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. */
|
||||
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)
|
||||
{
|
||||
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, 31);
|
||||
|
||||
|
||||
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 Voice) 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));
|
||||
memset(&avctx, 0, sizeof(AVCodecContext));
|
||||
memset(&avpkt, 0, sizeof(AVPacket));
|
||||
|
||||
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 (wmavoice_decode_init(&avctx) < 0) {
|
||||
LOGF("(WMA Voice) 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();
|
||||
}
|
||||
|
||||
new_packet:
|
||||
res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx);
|
||||
|
||||
if (res < 0) {
|
||||
LOGF("(WMA Voice) read_packet error %d\n",res);
|
||||
goto done;
|
||||
} else {
|
||||
avpkt.data = audiobuf;
|
||||
avpkt.size = audiobufsize;
|
||||
pktcnt++;
|
||||
|
||||
while(avpkt.size > 0)
|
||||
{
|
||||
/* wmavoice_decode_packet checks for the output buffer size to
|
||||
avoid overflows */
|
||||
outlen = BUFSIZE*sizeof(int32_t);
|
||||
|
||||
res = wmavoice_decode_packet(&avctx, decoded, &outlen, &avpkt);
|
||||
if(res < 0) {
|
||||
LOGF("(WMA Voice) Error: decode_packet returned %d", res);
|
||||
if(res == ERROR_WMAPRO_IN_WMAVOICE){
|
||||
/* Just skip this packet */
|
||||
ci->advance_buffer(packetlength);
|
||||
goto new_packet;
|
||||
}
|
||||
else
|
||||
goto done;
|
||||
}
|
||||
avpkt.data += res;
|
||||
avpkt.size -= res;
|
||||
if(outlen) {
|
||||
ci->yield ();
|
||||
outlen /= sizeof(int32_t);
|
||||
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;
|
||||
}
|
||||
|
|
@ -182,6 +182,9 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
|
|||
/* True Audio */
|
||||
[AFMT_TTA] =
|
||||
AFMT_ENTRY("TTA", "tta", NULL, "tta\0" ),
|
||||
/* WMA Voice in ASF */
|
||||
[AFMT_WMAVOICE] =
|
||||
AFMT_ENTRY("WMAVoice", "wmavoice", NULL, "wma\0wmv\0asf\0" ),
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ enum
|
|||
AFMT_VOX, /* VOX */
|
||||
AFMT_WAVE64, /* Wave64 */
|
||||
AFMT_TTA, /* True Audio */
|
||||
AFMT_WMAVOICE, /* WMA Voice in ASF */
|
||||
#endif
|
||||
|
||||
/* add new formats at any index above this line to have a sensible order -
|
||||
|
|
|
@ -357,6 +357,11 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
|
|||
wfx->audiostream = flags&0x7f;
|
||||
/* Correct codectype to redirect playback to the proper .codec */
|
||||
id3->codectype = AFMT_WMAPRO;
|
||||
} else if (wfx->codec_id == ASF_CODEC_ID_WMAVOICE) {
|
||||
read(fd, wfx->data, wfx->datalen);
|
||||
lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR);
|
||||
wfx->audiostream = flags&0x7f;
|
||||
id3->codectype = AFMT_WMAVOICE;
|
||||
} else {
|
||||
DEBUGF("Unsupported WMA codec (Lossless, Voice, etc)\n");
|
||||
lseek(fd,current.size - 24 - 72,SEEK_CUR);
|
||||
|
|
Loading…
Reference in a new issue