summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/wma.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/wma.c')
-rwxr-xr-xlib/rbcodec/codecs/wma.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/wma.c b/lib/rbcodec/codecs/wma.c
new file mode 100755
index 0000000000..f9501ffad3
--- /dev/null
+++ b/lib/rbcodec/codecs/wma.c
@@ -0,0 +1,196 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Dave Chapman
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "codeclib.h"
23#include "libasf/asf.h"
24#include "libwma/wmadec.h"
25
26CODEC_HEADER
27
28/* NOTE: WMADecodeContext is 120152 bytes (on x86) */
29static WMADecodeContext wmadec;
30
31/* this is the codec entry point */
32enum codec_status codec_main(enum codec_entry_call_reason reason)
33{
34 if (reason == CODEC_LOAD) {
35 /* Generic codec initialisation */
36 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
37 }
38
39 return CODEC_OK;
40}
41
42/* this is called for each file to process */
43enum codec_status codec_run(void)
44{
45 uint32_t elapsedtime;
46 asf_waveformatex_t wfx;
47 size_t resume_offset;
48 int i;
49 int wmares = 0;
50 int res = 0;
51 uint8_t* audiobuf;
52 int audiobufsize;
53 int packetlength = 0;
54 int errcount = 0;
55 intptr_t param;
56
57 /* Remember the resume position - when the codec is opened, the
58 playback engine will reset it. */
59 resume_offset = ci->id3->offset;
60
61restart_track:
62
63 /* Proper reset of the decoder context. */
64 memset(&wmadec, 0, sizeof(wmadec));
65
66 if (codec_init()) {
67 LOGF("WMA: Error initialising codec\n");
68 return CODEC_ERROR;
69 }
70
71 /* Copy the format metadata we've stored in the id3 TOC field. This
72 saves us from parsing it again here. */
73 memcpy(&wfx, ci->id3->toc, sizeof(wfx));
74
75 ci->seek_buffer(ci->id3->first_frame_offset);
76 if (wma_decode_init(&wmadec,&wfx) < 0) {
77 LOGF("WMA: Unsupported or corrupt file\n");
78 return CODEC_ERROR;
79 }
80
81 if (resume_offset > ci->id3->first_frame_offset)
82 {
83 /* Get start of current packet */
84 int packet_offset = (resume_offset - ci->id3->first_frame_offset)
85 % wfx.packet_size;
86 ci->seek_buffer(resume_offset - packet_offset);
87 elapsedtime = asf_get_timestamp(&i);
88 }
89 else
90 {
91 /* Now advance the file position to the first frame */
92 ci->seek_buffer(ci->id3->first_frame_offset);
93 elapsedtime = 0;
94 }
95
96 ci->set_elapsed(elapsedtime);
97
98 resume_offset = 0;
99 ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate);
100 ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ?
101 STEREO_MONO : STEREO_NONINTERLEAVED);
102 codec_set_replaygain(ci->id3);
103
104 /* The main decoding loop */
105 while (res >= 0)
106 {
107 enum codec_command_action action = ci->get_command(&param);
108
109 if (action == CODEC_ACTION_HALT)
110 break;
111
112 /* Deal with any pending seek requests */
113 if (action == CODEC_ACTION_SEEK_TIME) {
114
115 /*flush the wma decoder state*/
116 wmadec.last_superframe_len = 0;
117 wmadec.last_bitoffset = 0;
118
119 /*zero the frame out buffer so we don't overlap with a
120 stale samples*/
121 memset((*(wmadec.frame_out)), 0,
122 sizeof(fixed32) * MAX_CHANNELS * BLOCK_MAX_SIZE * 2);
123
124 if (param == 0) {
125 ci->set_elapsed(0);
126 ci->seek_complete();
127 goto restart_track; /* Pretend you never saw this... */
128 }
129
130 elapsedtime = asf_seek(param, &wfx);
131 if (elapsedtime < 1){
132 ci->set_elapsed(0);
133 ci->seek_complete();
134 break;
135 }
136 /*DEBUGF("Seek returned %d\n", (int)elapsedtime);*/
137
138 ci->set_elapsed(elapsedtime);
139 ci->seek_complete();
140 }
141 errcount = 0;
142new_packet:
143 res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx);
144
145 if (res < 0) {
146 /* We'll try to recover from a parse error a certain number of
147 * times. If we succeed, the error counter will be reset.
148 */
149
150 if (res == ASF_ERROR_EOF) {
151 /* File ended - not an error */
152 break;
153 }
154
155 errcount++;
156 DEBUGF("read_packet error %d, errcount %d\n",wmares, errcount);
157 if (errcount > 5) {
158 return CODEC_ERROR;
159 } else {
160 ci->advance_buffer(packetlength);
161 goto new_packet;
162 }
163 } else if (res > 0) {
164 wma_decode_superframe_init(&wmadec, audiobuf, audiobufsize);
165
166 for (i=0; i < wmadec.nb_frames; i++)
167 {
168 wmares = wma_decode_superframe_frame(&wmadec,
169 audiobuf, audiobufsize);
170
171 ci->yield ();
172
173 if (wmares < 0) {
174 /* Do the above, but for errors in decode. */
175 errcount++;
176 DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount);
177 if (errcount > 5) {
178 return CODEC_ERROR;
179 } else {
180 ci->advance_buffer(packetlength);
181 goto new_packet;
182 }
183 } else if (wmares > 0) {
184 ci->pcmbuf_insert((*wmadec.frame_out)[0], (*wmadec.frame_out)[1], wmares);
185 elapsedtime += (wmares*10)/(wfx.rate/100);
186 ci->set_elapsed(elapsedtime);
187 }
188 }
189 }
190
191 ci->advance_buffer(packetlength);
192 }
193
194 /*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/
195 return CODEC_OK;
196}