Remove unnecessary parameter (struct codec_api* ci) passed to libasf functions, and...
[kugel-rb.git] / apps / codecs / wma.c
blob235f1a38c9d2d90e699e38615b99abda07ea98a3
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Dave Chapman
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 ****************************************************************************/
22 #include "codeclib.h"
23 #include "libasf/asf.h"
24 #include "libwma/wmadec.h"
26 CODEC_HEADER
28 /* The output buffer containing the decoded samples (channels 0 and 1)
29 BLOCK_MAX_SIZE is 2048 (samples) and MAX_CHANNELS is 2.
32 static uint32_t decoded[BLOCK_MAX_SIZE * MAX_CHANNELS] IBSS_ATTR;
34 /* NOTE: WMADecodeContext is 120152 bytes (on x86) */
35 static WMADecodeContext wmadec;
37 /*entry point for seeks*/
38 static int seek(int ms, asf_waveformatex_t* wfx)
40 int time, duration, delta, temp, count=0;
42 /*estimate packet number from bitrate*/
43 int initial_packet = ci->curpos/wfx->packet_size;
44 int packet_num = (((int64_t)ms)*(wfx->bitrate>>3))/wfx->packet_size/1000;
45 int last_packet = ci->id3->filesize / wfx->packet_size;
47 if (packet_num > last_packet) {
48 packet_num = last_packet;
51 /*calculate byte address of the start of that packet*/
52 int packet_offset = packet_num*wfx->packet_size;
54 /*seek to estimated packet*/
55 ci->seek_buffer(ci->id3->first_frame_offset+packet_offset);
56 temp = ms;
57 while (1)
59 /*for very large files it can be difficult and unimportant to find the exact packet*/
60 count++;
62 /*check the time stamp of our packet*/
63 time = asf_get_timestamp(&duration);
64 DEBUGF("seeked to %d ms with duration %d\n", time, duration);
66 if (time < 0) {
67 /*unknown error, try to recover*/
68 DEBUGF("UKNOWN SEEK ERROR\n");
69 ci->seek_buffer(ci->id3->first_frame_offset+initial_packet*wfx->packet_size);
70 /*seek failed so return time stamp of the initial packet*/
71 return asf_get_timestamp(&duration);
74 if ((time+duration>=ms && time<=ms) || count > 10) {
75 DEBUGF("Found our packet! Now at %d packet\n", packet_num);
76 return time;
77 } else {
78 /*seek again*/
79 delta = ms-time;
80 /*estimate new packet number from bitrate and our current position*/
81 temp += delta;
82 packet_num = ((temp/1000)*(wfx->bitrate>>3) - (wfx->packet_size>>1))/wfx->packet_size; //round down!
83 packet_offset = packet_num*wfx->packet_size;
84 ci->seek_buffer(ci->id3->first_frame_offset+packet_offset);
91 /* this is the codec entry point */
92 enum codec_status codec_main(void)
94 uint32_t elapsedtime;
95 int retval;
96 asf_waveformatex_t wfx;
97 size_t resume_offset;
98 int i;
99 int wmares, res;
100 uint8_t* audiobuf;
101 int audiobufsize;
102 int packetlength = 0;
103 int errcount = 0;
105 /* Generic codec initialisation */
106 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
108 next_track:
110 /* Wait for the metadata to be read */
111 while (!*ci->taginfo_ready && !ci->stop_codec)
112 ci->sleep(1);
114 retval = CODEC_OK;
116 /* Remember the resume position - when the codec is opened, the
117 playback engine will reset it. */
118 resume_offset = ci->id3->offset;
119 restart_track:
120 if (codec_init()) {
121 LOGF("WMA: Error initialising codec\n");
122 retval = CODEC_ERROR;
123 goto exit;
126 /* Copy the format metadata we've stored in the id3 TOC field. This
127 saves us from parsing it again here. */
128 memcpy(&wfx, ci->id3->toc, sizeof(wfx));
130 if (wma_decode_init(&wmadec,&wfx) < 0) {
131 LOGF("WMA: Unsupported or corrupt file\n");
132 retval = CODEC_ERROR;
133 goto exit;
136 DEBUGF("**************** IN WMA.C ******************\n");
138 if (resume_offset > ci->id3->first_frame_offset)
140 /* Get start of current packet */
141 int packet_offset = (resume_offset - ci->id3->first_frame_offset)
142 % wfx.packet_size;
143 ci->seek_buffer(resume_offset - packet_offset);
144 elapsedtime = asf_get_timestamp(&i);
145 ci->set_elapsed(elapsedtime);
147 else
149 /* Now advance the file position to the first frame */
150 ci->seek_buffer(ci->id3->first_frame_offset);
151 elapsedtime = 0;
154 resume_offset = 0;
155 ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate);
156 ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ?
157 STEREO_MONO : STEREO_INTERLEAVED);
158 codec_set_replaygain(ci->id3);
160 /* The main decoding loop */
162 res = 1;
163 while (res >= 0)
165 ci->yield();
166 if (ci->stop_codec || ci->new_track) {
167 goto done;
170 /* Deal with any pending seek requests */
171 if (ci->seek_time){
173 if (ci->seek_time == 1) {
174 ci->seek_complete();
175 goto restart_track; /* Pretend you never saw this... */
178 elapsedtime = seek(ci->seek_time, &wfx);
179 if (elapsedtime < 1){
180 ci->seek_complete();
181 goto next_track;
183 /*DEBUGF("Seek returned %d\n", (int)elapsedtime);*/
184 ci->set_elapsed(elapsedtime);
186 /*flush the wma decoder state*/
187 wmadec.last_superframe_len = 0;
188 wmadec.last_bitoffset = 0;
189 ci->seek_complete();
191 errcount = 0;
192 new_packet:
193 res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx);
195 if (res < 0) {
196 /* We'll try to recover from a parse error a certain number of
197 * times. If we succeed, the error counter will be reset.
200 errcount++;
201 DEBUGF("read_packet error %d, errcount %d\n",wmares, errcount);
202 if (errcount > 5) {
203 goto done;
204 } else {
205 ci->advance_buffer(packetlength);
206 goto new_packet;
208 } else if (res > 0) {
209 wma_decode_superframe_init(&wmadec, audiobuf, audiobufsize);
211 for (i=0; i < wmadec.nb_frames; i++)
213 wmares = wma_decode_superframe_frame(&wmadec,
214 decoded,
215 audiobuf, audiobufsize);
217 ci->yield ();
219 if (wmares < 0) {
220 /* Do the above, but for errors in decode. */
221 errcount++;
222 DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount);
223 if (errcount > 5) {
224 goto done;
225 } else {
226 ci->advance_buffer(packetlength);
227 goto new_packet;
229 } else if (wmares > 0) {
230 ci->pcmbuf_insert(decoded, NULL, wmares);
231 elapsedtime += (wmares*10)/(wfx.rate/100);
232 ci->set_elapsed(elapsedtime);
234 ci->yield();
238 ci->advance_buffer(packetlength);
240 retval = CODEC_OK;
242 done:
243 /*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/
245 if (ci->request_next_track())
246 goto next_track;
247 exit:
248 return retval;