summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/wmavoice.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/wmavoice.c')
-rw-r--r--lib/rbcodec/codecs/wmavoice.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/wmavoice.c b/lib/rbcodec/codecs/wmavoice.c
new file mode 100644
index 0000000000..9cf5a49f1a
--- /dev/null
+++ b/lib/rbcodec/codecs/wmavoice.c
@@ -0,0 +1,195 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Mohamed Tarek
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 "libwmavoice/wmavoice.h"
25
26CODEC_HEADER
27
28static AVCodecContext avctx;
29static AVPacket avpkt;
30
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
34static int32_t decoded[BUFSIZE] IBSS_ATTR;
35
36
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. */
41static void init_codec_ctx(AVCodecContext *avctx, asf_waveformatex_t *wfx)
42{
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));
47
48 avctx->block_align = wfx->blockalign;
49 avctx->sample_rate = wfx->rate;
50 avctx->channels = wfx->channels;
51
52}
53
54/* this is the codec entry point */
55enum codec_status codec_main(enum codec_entry_call_reason reason)
56{
57 if (reason == CODEC_LOAD) {
58 /* Generic codec initialisation */
59 ci->configure(DSP_SET_SAMPLE_DEPTH, 31);
60 }
61
62 return CODEC_OK;
63}
64
65/* this is called for each file to process */
66enum codec_status codec_run(void)
67{
68 uint32_t elapsedtime;
69 asf_waveformatex_t wfx; /* Holds the stream properties */
70 size_t resume_offset;
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 */
77 intptr_t param;
78
79 /* Remember the resume position */
80 resume_offset = ci->id3->offset;
81restart_track:
82 if (codec_init()) {
83 LOGF("(WMA Voice) Error: Error initialising codec\n");
84 return CODEC_ERROR;
85 }
86
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));
92
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);
97
98 ci->seek_buffer(0);
99
100 /* Initialise the AVCodecContext */
101 init_codec_ctx(&avctx, &wfx);
102
103 if (wmavoice_decode_init(&avctx) < 0) {
104 LOGF("(WMA Voice) Error: Unsupported or corrupt file\n");
105 return CODEC_ERROR;
106 }
107
108 /* Now advance the file position to the first frame */
109 ci->seek_buffer(ci->id3->first_frame_offset);
110
111 elapsedtime = 0;
112 ci->set_elapsed(0);
113
114 resume_offset = 0;
115
116 /* The main decoding loop */
117
118 while (pktcnt < wfx.numpackets)
119 {
120 enum codec_command_action action = ci->get_command(&param);
121
122 if (action == CODEC_ACTION_HALT)
123 break;
124
125 /* Deal with any pending seek requests */
126 if (action == CODEC_ACTION_SEEK_TIME) {
127 ci->set_elapsed(param);
128
129 if (param == 0) {
130 ci->set_elapsed(0);
131 ci->seek_complete();
132 goto restart_track; /* Pretend you never saw this... */
133 }
134
135 elapsedtime = asf_seek(param, &wfx);
136 if (elapsedtime < 1){
137 ci->set_elapsed(0);
138 ci->seek_complete();
139 goto next_track;
140 }
141
142 ci->set_elapsed(elapsedtime);
143 ci->seek_complete();
144 }
145
146new_packet:
147 res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx);
148
149 if (res < 0) {
150 LOGF("(WMA Voice) read_packet error %d\n",res);
151 return CODEC_ERROR;
152 } else {
153 avpkt.data = audiobuf;
154 avpkt.size = audiobufsize;
155 pktcnt++;
156
157 while(avpkt.size > 0)
158 {
159 /* wmavoice_decode_packet checks for the output buffer size to
160 avoid overflows */
161 outlen = BUFSIZE*sizeof(int32_t);
162
163 res = wmavoice_decode_packet(&avctx, decoded, &outlen, &avpkt);
164 if(res < 0) {
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);
169 goto new_packet;
170 }
171 else {
172 return CODEC_ERROR;
173 }
174 }
175 avpkt.data += res;
176 avpkt.size -= res;
177 if(outlen) {
178 ci->yield ();
179 outlen /= sizeof(int32_t);
180 ci->pcmbuf_insert(decoded, NULL, outlen);
181 elapsedtime += outlen*10/(wfx.rate/100);
182 ci->set_elapsed(elapsedtime);
183 ci->yield ();
184 }
185 }
186
187 }
188
189 /* Advance to the next logical packet */
190 ci->advance_buffer(packetlength);
191 }
192
193 return CODEC_OK;
194}
195