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(enum codec_entry_call_reason reason
)
57 if (reason
== CODEC_LOAD
) {
58 /* Generic codec initialisation */
59 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 31);
65 /* this is called for each file to process */
66 enum codec_status
codec_run(void)
69 asf_waveformatex_t wfx
; /* Holds the stream properties */
71 int res
; /* Return values from asf_read_packet() and decode_packet() */
72 uint8_t* audiobuf
; /* Pointer to the payload of one wma pro packet */
73 int audiobufsize
; /* Payload size */
74 int packetlength
= 0; /* Logical packet size (minus the header size) */
75 int outlen
= 0; /* Number of bytes written to the output buffer */
76 int pktcnt
= 0; /* Count of the packets played */
79 /* Remember the resume position */
80 resume_offset
= ci
->id3
->offset
;
83 LOGF("(WMA Voice) Error: Error initialising codec\n");
87 /* Copy the format metadata we've stored in the id3 TOC field. This
88 saves us from parsing it again here. */
89 memcpy(&wfx
, ci
->id3
->toc
, sizeof(wfx
));
90 memset(&avctx
, 0, sizeof(AVCodecContext
));
91 memset(&avpkt
, 0, sizeof(AVPacket
));
93 ci
->configure(DSP_SWITCH_FREQUENCY
, wfx
.rate
);
94 ci
->configure(DSP_SET_STEREO_MODE
, wfx
.channels
== 1 ?
95 STEREO_MONO
: STEREO_INTERLEAVED
);
96 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");
108 /* Now advance the file position to the first frame */
109 ci
->seek_buffer(ci
->id3
->first_frame_offset
);
116 /* The main decoding loop */
118 while (pktcnt
< wfx
.numpackets
)
120 enum codec_command_action action
= ci
->get_command(¶m
);
122 if (action
== CODEC_ACTION_HALT
)
125 /* Deal with any pending seek requests */
126 if (action
== CODEC_ACTION_SEEK_TIME
) {
127 ci
->set_elapsed(param
);
132 goto restart_track
; /* Pretend you never saw this... */
135 elapsedtime
= asf_seek(param
, &wfx
);
136 if (elapsedtime
< 1){
142 ci
->set_elapsed(elapsedtime
);
147 res
= asf_read_packet(&audiobuf
, &audiobufsize
, &packetlength
, &wfx
);
150 LOGF("(WMA Voice) read_packet error %d\n",res
);
153 avpkt
.data
= audiobuf
;
154 avpkt
.size
= audiobufsize
;
157 while(avpkt
.size
> 0)
159 /* wmavoice_decode_packet checks for the output buffer size to
161 outlen
= BUFSIZE
*sizeof(int32_t);
163 res
= wmavoice_decode_packet(&avctx
, decoded
, &outlen
, &avpkt
);
165 LOGF("(WMA Voice) Error: decode_packet returned %d", res
);
166 if(res
== ERROR_WMAPRO_IN_WMAVOICE
){
167 /* Just skip this packet */
168 ci
->advance_buffer(packetlength
);
179 outlen
/= sizeof(int32_t);
180 ci
->pcmbuf_insert(decoded
, NULL
, outlen
);
181 elapsedtime
+= outlen
*10/(wfx
.rate
/100);
182 ci
->set_elapsed(elapsedtime
);
189 /* Advance to the next logical packet */
190 ci
->advance_buffer(packetlength
);