1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2010 Mohamed Tarek
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 #include "libasf/asf.h"
24 #include "libwmavoice/wmavoice.h"
28 static AVCodecContext avctx
;
29 static AVPacket avpkt
;
31 #define MAX_FRAMES 3 /*maximum number of frames per superframe*/
32 #define MAX_FRAMESIZE 160 /* maximum number of samples per frame */
33 #define BUFSIZE MAX_FRAMES*MAX_FRAMESIZE
34 static int32_t decoded
[BUFSIZE
] IBSS_ATTR
;
37 /* This function initialises AVCodecContext with the data needed for the wmapro
38 * decoder to work. The required data is taken from asf_waveformatex_t because that's
39 * what the rockbox asf metadata parser fill/work with. In the future, when the
40 * codec is being optimised for on-target playback this function should not be needed. */
41 static void init_codec_ctx(AVCodecContext
*avctx
, asf_waveformatex_t
*wfx
)
43 /* Copy the extra-data */
44 avctx
->extradata_size
= wfx
->datalen
;
45 avctx
->extradata
= (uint8_t *)malloc(wfx
->datalen
*sizeof(uint8_t));
46 memcpy(avctx
->extradata
, wfx
->data
, wfx
->datalen
*sizeof(uint8_t));
48 avctx
->block_align
= wfx
->blockalign
;
49 avctx
->sample_rate
= wfx
->rate
;
50 avctx
->channels
= wfx
->channels
;
54 /* this is the codec entry point */
55 enum codec_status
codec_main(void)
59 asf_waveformatex_t wfx
; /* Holds the stream properties */
61 int res
; /* Return values from asf_read_packet() and decode_packet() */
62 uint8_t* audiobuf
; /* Pointer to the payload of one wma pro packet */
63 int audiobufsize
; /* Payload size */
64 int packetlength
= 0; /* Logical packet size (minus the header size) */
65 int outlen
= 0; /* Number of bytes written to the output buffer */
66 int pktcnt
= 0; /* Count of the packets played */
68 /* Generic codec initialisation */
69 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 31);
74 /* Wait for the metadata to be read */
75 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
80 /* Remember the resume position */
81 resume_offset
= ci
->id3
->offset
;
84 LOGF("(WMA Voice) Error: Error initialising codec\n");
89 /* Copy the format metadata we've stored in the id3 TOC field. This
90 saves us from parsing it again here. */
91 memcpy(&wfx
, ci
->id3
->toc
, sizeof(wfx
));
92 memset(&avctx
, 0, sizeof(AVCodecContext
));
93 memset(&avpkt
, 0, sizeof(AVPacket
));
95 ci
->configure(DSP_SWITCH_FREQUENCY
, wfx
.rate
);
96 ci
->configure(DSP_SET_STEREO_MODE
, wfx
.channels
== 1 ?
97 STEREO_MONO
: STEREO_INTERLEAVED
);
98 codec_set_replaygain(ci
->id3
);
100 /* Initialise the AVCodecContext */
101 init_codec_ctx(&avctx
, &wfx
);
103 if (wmavoice_decode_init(&avctx
) < 0) {
104 LOGF("(WMA Voice) Error: Unsupported or corrupt file\n");
105 retval
= CODEC_ERROR
;
109 /* Now advance the file position to the first frame */
110 ci
->seek_buffer(ci
->id3
->first_frame_offset
);
115 /* The main decoding loop */
117 while (pktcnt
< wfx
.numpackets
)
120 if (ci
->stop_codec
|| ci
->new_track
) {
124 /* Deal with any pending seek requests */
127 if (ci
->seek_time
== 1) {
129 goto restart_track
; /* Pretend you never saw this... */
132 elapsedtime
= asf_seek(ci
->seek_time
, &wfx
);
133 if (elapsedtime
< 1){
138 ci
->set_elapsed(elapsedtime
);
143 res
= asf_read_packet(&audiobuf
, &audiobufsize
, &packetlength
, &wfx
);
146 LOGF("(WMA Voice) read_packet error %d\n",res
);
149 avpkt
.data
= audiobuf
;
150 avpkt
.size
= audiobufsize
;
153 while(avpkt
.size
> 0)
155 /* wmavoice_decode_packet checks for the output buffer size to
157 outlen
= BUFSIZE
*sizeof(int32_t);
159 res
= wmavoice_decode_packet(&avctx
, decoded
, &outlen
, &avpkt
);
161 LOGF("(WMA Voice) Error: decode_packet returned %d", res
);
162 if(res
== ERROR_WMAPRO_IN_WMAVOICE
){
163 /* Just skip this packet */
164 ci
->advance_buffer(packetlength
);
174 outlen
/= sizeof(int32_t);
175 ci
->pcmbuf_insert(decoded
, NULL
, outlen
);
176 elapsedtime
+= outlen
*10/(wfx
.rate
/100);
177 ci
->set_elapsed(elapsedtime
);
184 /* Advance to the next logical packet */
185 ci
->advance_buffer(packetlength
);
190 if (ci
->request_next_track())