1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 Dave Chapman
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
21 #include "libwma/asf.h"
22 #include "libwma/wmadec.h"
26 /* The output buffer containing the decoded samples (channels 0 and 1)
27 BLOCK_MAX_SIZE is 2048 (samples) and MAX_CHANNELS is 2.
30 static uint16_t decoded
[BLOCK_MAX_SIZE
* MAX_CHANNELS
];
32 /* NOTE: WMADecodeContext is 120152 bytes (on x86) */
33 static WMADecodeContext wmadec
;
36 ASF_ERROR_INTERNAL
= -1, /* incorrect input to API calls */
37 ASF_ERROR_OUTOFMEM
= -2, /* some malloc inside program failed */
38 ASF_ERROR_EOF
= -3, /* unexpected end of file */
39 ASF_ERROR_IO
= -4, /* error reading or writing to file */
40 ASF_ERROR_INVALID_LENGTH
= -5, /* length value conflict in input data */
41 ASF_ERROR_INVALID_VALUE
= -6, /* other value conflict in input data */
42 ASF_ERROR_INVALID_OBJECT
= -7, /* ASF object missing or in wrong place */
43 ASF_ERROR_OBJECT_SIZE
= -8, /* invalid ASF object size (too small) */
44 ASF_ERROR_SEEKABLE
= -9, /* file not seekable */
45 ASF_ERROR_SEEK
= -10 /* file is seekable but seeking failed */
48 /* Read an unaligned 32-bit little endian long from buffer. */
49 static unsigned long get_long_le(void* buf
)
51 unsigned char* p
= (unsigned char*) buf
;
53 return p
[0] | (p
[1] << 8) | (p
[2] << 16) | (p
[3] << 24);
56 /* Read an unaligned 16-bit little endian short from buffer. */
57 static unsigned short get_short_le(void* buf
)
59 unsigned char* p
= (unsigned char*) buf
;
61 return p
[0] | (p
[1] << 8);
64 #define GETLEN2b(bits) (((bits) == 0x03) ? 4 : bits)
66 #define GETVALUE2b(bits, data) \
67 (((bits) != 0x03) ? ((bits) != 0x02) ? ((bits) != 0x01) ? \
68 0 : *(data) : get_short_le(data) : get_long_le(data))
70 static int asf_read_packet(uint8_t** audiobuf
, int* audiobufsize
, int* packetlength
, asf_waveformatex_t
* wfx
)
72 uint8_t tmp8
, packet_flags
, packet_property
;
74 int ec_length
, opaque_data
, ec_length_type
;
79 uint32_t padding_length
;
82 uint16_t payload_count
;
83 int payload_length_type
;
84 uint32_t payload_hdrlen
;
87 uint32_t replicated_length
;
88 uint32_t media_object_number
;
89 uint32_t media_object_offset
;
90 uint32_t bytesread
= 0;
95 if (ci
->read_filebuf(&tmp8
, 1) == 0) {
100 //DEBUGF("tmp8=0x%02x\n",tmp8);
101 /* TODO: We need a better way to detect endofstream */
102 if (tmp8
!= 0x82) { return -1; }
106 ec_length
= tmp8
& 0x0f;
107 opaque_data
= (tmp8
>> 4) & 0x01;
108 ec_length_type
= (tmp8
>> 5) & 0x03;
110 if (ec_length_type
!= 0x00 || opaque_data
!= 0 || ec_length
!= 0x02) {
111 DEBUGF("incorrect error correction flags\n");
112 return ASF_ERROR_INVALID_VALUE
;
116 ci
->advance_buffer(ec_length
);
117 bytesread
+= ec_length
;
122 if (ci
->read_filebuf(&packet_flags
, 1) == 0) { return ASF_ERROR_EOF
; }
123 if (ci
->read_filebuf(&packet_property
, 1) == 0) { return ASF_ERROR_EOF
; }
126 datalen
= GETLEN2b((packet_flags
>> 1) & 0x03) +
127 GETLEN2b((packet_flags
>> 3) & 0x03) +
128 GETLEN2b((packet_flags
>> 5) & 0x03) + 6;
131 if (datalen
> sizeof(data
)) {
132 DEBUGF("Unexpectedly long datalen in data - %d\n",datalen
);
133 return ASF_ERROR_OUTOFMEM
;
137 if (ci
->read_filebuf(data
, datalen
) == 0) {
138 return ASF_ERROR_EOF
;
141 bytesread
+= datalen
;
144 length
= GETVALUE2b((packet_flags
>> 5) & 0x03, datap
);
145 datap
+= GETLEN2b((packet_flags
>> 5) & 0x03);
146 /* sequence value is not used */
147 GETVALUE2b((packet_flags
>> 1) & 0x03, datap
);
148 datap
+= GETLEN2b((packet_flags
>> 1) & 0x03);
149 padding_length
= GETVALUE2b((packet_flags
>> 3) & 0x03, datap
);
150 datap
+= GETLEN2b((packet_flags
>> 3) & 0x03);
151 send_time
= get_long_le(datap
);
153 duration
= get_short_le(datap
);
156 /* this is really idiotic, packet length can (and often will) be
157 * undefined and we just have to use the header packet size as the size
159 if (!((packet_flags
>> 5) & 0x03)) {
160 length
= wfx
->packet_size
;
163 /* this is also really idiotic, if packet length is smaller than packet
164 * size, we need to manually add the additional bytes into padding length
166 if (length
< wfx
->packet_size
) {
167 padding_length
+= wfx
->packet_size
- length
;
168 length
= wfx
->packet_size
;
171 if (length
> wfx
->packet_size
) {
172 DEBUGF("packet with too big length value\n");
173 return ASF_ERROR_INVALID_LENGTH
;
176 /* check if we have multiple payloads */
177 if (packet_flags
& 0x01) {
178 if (ci
->read_filebuf(&tmp8
, 1) == 0) {
179 return ASF_ERROR_EOF
;
181 payload_count
= tmp8
& 0x3f;
182 payload_length_type
= (tmp8
>> 6) & 0x03;
186 payload_length_type
= 0x02; /* not used */
189 if (length
< bytesread
) {
190 DEBUGF("header exceeded packet size, invalid file - length=%d, bytesread=%d\n",(int)length
,(int)bytesread
);
191 /* FIXME: should this be checked earlier? */
192 return ASF_ERROR_INVALID_LENGTH
;
196 /* We now parse the individual payloads, and move all payloads
197 belonging to our audio stream to a contiguous block, starting at
198 the location of the first payload.
203 *packetlength
= length
- bytesread
;
205 buf
= ci
->request_buffer(&bufsize
, length
);
208 if (bufsize
!= length
) {
209 /* This should only happen with packets larger than 32KB (the
210 guard buffer size). All the streams I've seen have
211 relatively small packets less than about 8KB), but I don't
212 know what is expected.
214 DEBUGF("Could not read packet (requested %d bytes, received %d), curpos=%d, aborting\n",
215 (int)length
,(int)bufsize
,(int)ci
->curpos
);
219 for (i
=0; i
<payload_count
; i
++) {
220 stream_id
= datap
[0]&0x7f;
224 payload_hdrlen
= GETLEN2b(packet_property
& 0x03) +
225 GETLEN2b((packet_property
>> 2) & 0x03) +
226 GETLEN2b((packet_property
>> 4) & 0x03);
228 //DEBUGF("payload_hdrlen = %d\n",payload_hdrlen);
231 if (payload_hdrlen
> size
) {
232 return ASF_ERROR_INVALID_LENGTH
;
235 if (payload_hdrlen
> sizeof(data
)) {
236 DEBUGF("Unexpectedly long datalen in data - %d\n",datalen
);
237 return ASF_ERROR_OUTOFMEM
;
240 bytesread
+= payload_hdrlen
;
241 media_object_number
= GETVALUE2b((packet_property
>> 4) & 0x03, datap
);
242 datap
+= GETLEN2b((packet_property
>> 4) & 0x03);
243 media_object_offset
= GETVALUE2b((packet_property
>> 2) & 0x03, datap
);
244 datap
+= GETLEN2b((packet_property
>> 2) & 0x03);
245 replicated_length
= GETVALUE2b(packet_property
& 0x03, datap
);
246 datap
+= GETLEN2b(packet_property
& 0x03);
248 /* TODO: Validate replicated_length */
249 /* TODO: Is the content of this important for us? */
250 datap
+= replicated_length
;
251 bytesread
+= replicated_length
;
253 multiple
= packet_flags
& 0x01;
258 x
= GETLEN2b(payload_length_type
);
261 /* in multiple payloads datalen should be a word */
262 return ASF_ERROR_INVALID_VALUE
;
266 if (skip
+ tmp
> datalen
) {
267 /* not enough data */
268 return ASF_ERROR_INVALID_LENGTH
;
271 payload_datalen
= GETVALUE2b(payload_length_type
, datap
);
275 payload_datalen
= length
- bytesread
- padding_length
;
278 if (stream_id
== wfx
->audiostream
)
280 if (*audiobuf
== NULL
) {
281 /* The first payload can stay where it is */
283 *audiobufsize
= payload_datalen
;
285 /* The second and subsequent payloads in this packet
286 that belong to the audio stream need to be moved to be
287 contiguous with the first payload.
289 memmove(*audiobuf
+ *audiobufsize
, datap
, payload_datalen
);
290 *audiobufsize
+= payload_datalen
;
293 datap
+= payload_datalen
;
294 bytesread
+= payload_datalen
;
297 if (*audiobuf
!= NULL
)
303 /* this is the codec entry point */
304 enum codec_status
codec_main(void)
306 uint32_t samplesdone
;
307 uint32_t elapsedtime
;
309 asf_waveformatex_t wfx
;
310 uint32_t currentframe
;
311 size_t resume_offset
;
318 /* Generic codec initialisation */
319 ci
->configure(CODEC_SET_FILEBUF_WATERMARK
, 1024*512);
320 ci
->configure(CODEC_SET_FILEBUF_CHUNKSIZE
, 1024*128);
322 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 15);
326 /* Wait for the metadata to be read */
327 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
332 /* Remember the resume position - when the codec is opened, the
333 playback engine will reset it. */
334 resume_offset
= ci
->id3
->offset
;
337 LOGF("WMA: Error initialising codec\n");
338 retval
= CODEC_ERROR
;
342 /* Copy the format metadata we've stored in the id3 TOC field. This
343 saves us from parsing it again here. */
344 memcpy(&wfx
, ci
->id3
->toc
, sizeof(wfx
));
346 if (wma_decode_init(&wmadec
,&wfx
) < 0) {
347 LOGF("WMA: Unsupported or corrupt file\n");
348 retval
= CODEC_ERROR
;
352 /* Now advance the file position to the first frame */
353 ci
->seek_buffer(ci
->id3
->first_frame_offset
);
355 ci
->configure(DSP_SWITCH_FREQUENCY
, wfx
.rate
);
356 ci
->configure(DSP_SET_STEREO_MODE
, wfx
.channels
== 1 ?
357 STEREO_MONO
: STEREO_INTERLEAVED
);
358 codec_set_replaygain(ci
->id3
);
360 /* The main decoding loop */
365 DEBUGF("**************** IN WMA.C ******************\n");
366 wma_decode_init(&wmadec
,&wfx
);
372 if (ci
->stop_codec
|| ci
->new_track
) {
376 /* Deal with any pending seek requests - ignore them */
382 res
= asf_read_packet(&audiobuf
, &audiobufsize
, &packetlength
, &wfx
);
384 wma_decode_superframe_init(&wmadec
,
385 audiobuf
, audiobufsize
);
387 for (i
=0; i
< wmadec
.nb_frames
; i
++)
389 wmares
= wma_decode_superframe_frame(&wmadec
,
391 audiobuf
, audiobufsize
);
397 LOGF("WMA decode error %d\n",wmares
);
399 } else if (wmares
> 0) {
400 ci
->pcmbuf_insert(decoded
, NULL
, wmares
);
401 samplesdone
+= wmares
;
402 elapsedtime
= (samplesdone
*10)/(wfx
.rate
/100);
403 ci
->set_elapsed(elapsedtime
);
409 ci
->advance_buffer(packetlength
);
414 LOGF("WMA: Decoded %ld samples\n",samplesdone
);
416 if (ci
->request_next_track())