diff options
Diffstat (limited to 'apps/codecs/wmavoice.c')
-rw-r--r-- | apps/codecs/wmavoice.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/apps/codecs/wmavoice.c b/apps/codecs/wmavoice.c new file mode 100644 index 0000000000..904af23b99 --- /dev/null +++ b/apps/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 | |||
26 | CODEC_HEADER | ||
27 | |||
28 | static AVCodecContext avctx; | ||
29 | static 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 | ||
34 | static 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. */ | ||
41 | static 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 */ | ||
55 | enum codec_status codec_main(void) | ||
56 | { | ||
57 | uint32_t elapsedtime; | ||
58 | int retval; | ||
59 | asf_waveformatex_t wfx; /* Holds the stream properties */ | ||
60 | size_t resume_offset; | ||
61 | int res; /* Return values from asf_read_packet() and decode_packet() */ | ||
62 | uint8_t* audiobuf; /* Pointer to the payload of one wma pro packet */ | ||
63 | int audiobufsize; /* Payload size */ | ||
64 | int packetlength = 0; /* Logical packet size (minus the header size) */ | ||
65 | int outlen = 0; /* Number of bytes written to the output buffer */ | ||
66 | int pktcnt = 0; /* Count of the packets played */ | ||
67 | |||
68 | /* Generic codec initialisation */ | ||
69 | ci->configure(DSP_SET_SAMPLE_DEPTH, 31); | ||
70 | |||
71 | |||
72 | next_track: | ||
73 | |||
74 | /* Wait for the metadata to be read */ | ||
75 | while (!*ci->taginfo_ready && !ci->stop_codec) | ||
76 | ci->sleep(1); | ||
77 | |||
78 | retval = CODEC_OK; | ||
79 | |||
80 | /* Remember the resume position */ | ||
81 | resume_offset = ci->id3->offset; | ||
82 | restart_track: | ||
83 | if (codec_init()) { | ||
84 | LOGF("(WMA Voice) Error: Error initialising codec\n"); | ||
85 | retval = CODEC_ERROR; | ||
86 | goto done; | ||
87 | } | ||
88 | |||
89 | /* Copy the format metadata we've stored in the id3 TOC field. This | ||
90 | saves us from parsing it again here. */ | ||
91 | memcpy(&wfx, ci->id3->toc, sizeof(wfx)); | ||
92 | memset(&avctx, 0, sizeof(AVCodecContext)); | ||
93 | memset(&avpkt, 0, sizeof(AVPacket)); | ||
94 | |||
95 | ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate); | ||
96 | ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ? | ||
97 | STEREO_MONO : STEREO_INTERLEAVED); | ||
98 | codec_set_replaygain(ci->id3); | ||
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 | retval = CODEC_ERROR; | ||
106 | goto done; | ||
107 | } | ||
108 | |||
109 | /* Now advance the file position to the first frame */ | ||
110 | ci->seek_buffer(ci->id3->first_frame_offset); | ||
111 | |||
112 | elapsedtime = 0; | ||
113 | resume_offset = 0; | ||
114 | |||
115 | /* The main decoding loop */ | ||
116 | |||
117 | while (pktcnt < wfx.numpackets) | ||
118 | { | ||
119 | ci->yield(); | ||
120 | if (ci->stop_codec || ci->new_track) { | ||
121 | goto done; | ||
122 | } | ||
123 | |||
124 | /* Deal with any pending seek requests */ | ||
125 | if (ci->seek_time){ | ||
126 | |||
127 | if (ci->seek_time == 1) { | ||
128 | ci->seek_complete(); | ||
129 | goto restart_track; /* Pretend you never saw this... */ | ||
130 | } | ||
131 | |||
132 | elapsedtime = asf_seek(ci->seek_time, &wfx); | ||
133 | if (elapsedtime < 1){ | ||
134 | ci->seek_complete(); | ||
135 | goto next_track; | ||
136 | } | ||
137 | |||
138 | ci->set_elapsed(elapsedtime); | ||
139 | ci->seek_complete(); | ||
140 | } | ||
141 | |||
142 | new_packet: | ||
143 | res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx); | ||
144 | |||
145 | if (res < 0) { | ||
146 | LOGF("(WMA Voice) read_packet error %d\n",res); | ||
147 | goto done; | ||
148 | } else { | ||
149 | avpkt.data = audiobuf; | ||
150 | avpkt.size = audiobufsize; | ||
151 | pktcnt++; | ||
152 | |||
153 | while(avpkt.size > 0) | ||
154 | { | ||
155 | /* wmavoice_decode_packet checks for the output buffer size to | ||
156 | avoid overflows */ | ||
157 | outlen = BUFSIZE*sizeof(int32_t); | ||
158 | |||
159 | res = wmavoice_decode_packet(&avctx, decoded, &outlen, &avpkt); | ||
160 | if(res < 0) { | ||
161 | LOGF("(WMA Voice) Error: decode_packet returned %d", res); | ||
162 | if(res == ERROR_WMAPRO_IN_WMAVOICE){ | ||
163 | /* Just skip this packet */ | ||
164 | ci->advance_buffer(packetlength); | ||
165 | goto new_packet; | ||
166 | } | ||
167 | else | ||
168 | goto done; | ||
169 | } | ||
170 | avpkt.data += res; | ||
171 | avpkt.size -= res; | ||
172 | if(outlen) { | ||
173 | ci->yield (); | ||
174 | outlen /= sizeof(int32_t); | ||
175 | ci->pcmbuf_insert(decoded, NULL, outlen); | ||
176 | elapsedtime += outlen*10/(wfx.rate/100); | ||
177 | ci->set_elapsed(elapsedtime); | ||
178 | ci->yield (); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | } | ||
183 | |||
184 | /* Advance to the next logical packet */ | ||
185 | ci->advance_buffer(packetlength); | ||
186 | } | ||
187 | retval = CODEC_OK; | ||
188 | |||
189 | done: | ||
190 | if (ci->request_next_track()) | ||
191 | goto next_track; | ||
192 | |||
193 | return retval; | ||
194 | } | ||
195 | |||