Mohamed Tarek | cd4d80a | 2010-05-09 21:42:09 +0000 | [diff] [blame] | 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" |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 23 | #include "libasf/asf.h" |
| 24 | #include "libwmapro/wmaprodec.h" |
Mohamed Tarek | cd4d80a | 2010-05-09 21:42:09 +0000 | [diff] [blame] | 25 | |
| 26 | CODEC_HEADER |
| 27 | |
Nils Wallménius | 7c6056b | 2011-06-01 10:28:26 +0000 | [diff] [blame] | 28 | static int32_t *dec[2]; /* pointers to the output buffers in WMAProDecodeCtx in |
| 29 | wmaprodec.c */ |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 30 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 31 | |
Mohamed Tarek | cd4d80a | 2010-05-09 21:42:09 +0000 | [diff] [blame] | 32 | /* this is the codec entry point */ |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 33 | enum codec_status codec_main(enum codec_entry_call_reason reason) |
| 34 | { |
| 35 | if (reason == CODEC_LOAD) { |
| 36 | /* Generic codec initialisation */ |
| 37 | ci->configure(DSP_SET_SAMPLE_DEPTH, WMAPRO_DSP_SAMPLE_DEPTH); |
| 38 | } |
| 39 | |
| 40 | return CODEC_OK; |
| 41 | } |
| 42 | |
| 43 | /* this is called for each file to process */ |
| 44 | enum codec_status codec_run(void) |
Mohamed Tarek | cd4d80a | 2010-05-09 21:42:09 +0000 | [diff] [blame] | 45 | { |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 46 | uint32_t elapsedtime; |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 47 | asf_waveformatex_t wfx; /* Holds the stream properties */ |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 48 | int res; /* Return values from asf_read_packet() and decode_packet() */ |
| 49 | uint8_t* audiobuf; /* Pointer to the payload of one wma pro packet */ |
| 50 | int audiobufsize; /* Payload size */ |
| 51 | int packetlength = 0; /* Logical packet size (minus the header size) */ |
| 52 | int outlen = 0; /* Number of bytes written to the output buffer */ |
| 53 | int pktcnt = 0; /* Count of the packets played */ |
Andree Buschmann | aa2fca3 | 2010-07-29 22:18:04 +0000 | [diff] [blame] | 54 | uint8_t *data; /* Pointer to decoder input buffer */ |
| 55 | int size; /* Size of the input frame to the decoder */ |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 56 | intptr_t param; |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 57 | |
Michael Sevakis | 85e4025 | 2011-02-20 15:27:10 +0000 | [diff] [blame] | 58 | restart_track: |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 59 | if (codec_init()) { |
| 60 | LOGF("(WMA PRO) Error: Error initialising codec\n"); |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 61 | return CODEC_ERROR; |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 62 | } |
| 63 | |
| 64 | /* Copy the format metadata we've stored in the id3 TOC field. This |
| 65 | saves us from parsing it again here. */ |
| 66 | memcpy(&wfx, ci->id3->toc, sizeof(wfx)); |
| 67 | |
| 68 | ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate); |
| 69 | ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ? |
Mohamed Tarek | 5dd8c53 | 2010-07-26 22:03:20 +0000 | [diff] [blame] | 70 | STEREO_MONO : STEREO_NONINTERLEAVED); |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 71 | codec_set_replaygain(ci->id3); |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 72 | |
Mohamed Tarek | 387af97 | 2010-07-15 05:38:09 +0000 | [diff] [blame] | 73 | if (decode_init(&wfx) < 0) { |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 74 | LOGF("(WMA PRO) Error: Unsupported or corrupt file\n"); |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 75 | return CODEC_ERROR; |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | /* Now advance the file position to the first frame */ |
| 79 | ci->seek_buffer(ci->id3->first_frame_offset); |
| 80 | |
| 81 | elapsedtime = 0; |
Michael Sevakis | 7ad2cad | 2011-08-28 07:45:35 +0000 | [diff] [blame^] | 82 | ci->set_elapsed(0); |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 83 | |
| 84 | /* The main decoding loop */ |
| 85 | |
| 86 | while (pktcnt < wfx.numpackets) |
Andree Buschmann | e75018a | 2011-05-01 11:42:41 +0000 | [diff] [blame] | 87 | { |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 88 | enum codec_command_action action = ci->get_command(¶m); |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 89 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 90 | if (action == CODEC_ACTION_HALT) |
| 91 | break; |
| 92 | |
| 93 | /* Deal with any pending seek requests */ |
| 94 | if (action == CODEC_ACTION_SEEK_TIME) { |
| 95 | if (param == 0) { |
| 96 | ci->set_elapsed(0); |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 97 | ci->seek_complete(); |
| 98 | goto restart_track; /* Pretend you never saw this... */ |
| 99 | } |
| 100 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 101 | elapsedtime = asf_seek(param, &wfx); |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 102 | if (elapsedtime < 1){ |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 103 | ci->set_elapsed(0); |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 104 | ci->seek_complete(); |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 105 | break; |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | ci->set_elapsed(elapsedtime); |
| 109 | ci->seek_complete(); |
| 110 | } |
| 111 | |
| 112 | res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx); |
| 113 | |
| 114 | if (res < 0) { |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 115 | LOGF("(WMA PRO) Warning: asf_read_packet returned %d", res); |
| 116 | return CODEC_ERROR; |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 117 | } else { |
Mohamed Tarek | 387af97 | 2010-07-15 05:38:09 +0000 | [diff] [blame] | 118 | data = audiobuf; |
| 119 | size = audiobufsize; |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 120 | pktcnt++; |
| 121 | |
| 122 | /* We now loop on the packet, decoding and outputting the subframes |
| 123 | * one-by-one. For more information about how wma pro structures its |
| 124 | * audio frames, see libwmapro/wmaprodec.c */ |
Mohamed Tarek | 387af97 | 2010-07-15 05:38:09 +0000 | [diff] [blame] | 125 | while(size > 0) |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 126 | { |
Mohamed Tarek | 5dd8c53 | 2010-07-26 22:03:20 +0000 | [diff] [blame] | 127 | res = decode_packet(&wfx, dec, &outlen, data, size); |
Mohamed Tarek | f98e803 | 2010-07-17 09:55:38 +0000 | [diff] [blame] | 128 | if(res < 0) { |
| 129 | LOGF("(WMA PRO) Error: decode_packet returned %d", res); |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 130 | return CODEC_ERROR; |
Mohamed Tarek | f98e803 | 2010-07-17 09:55:38 +0000 | [diff] [blame] | 131 | } |
Mohamed Tarek | 387af97 | 2010-07-15 05:38:09 +0000 | [diff] [blame] | 132 | data += res; |
| 133 | size -= res; |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 134 | if(outlen) { |
| 135 | ci->yield (); |
Mohamed Tarek | 5da2304 | 2010-08-03 22:59:03 +0000 | [diff] [blame] | 136 | outlen /= (wfx.channels); |
Mohamed Tarek | 5dd8c53 | 2010-07-26 22:03:20 +0000 | [diff] [blame] | 137 | ci->pcmbuf_insert(dec[0], dec[1], outlen ); |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 138 | elapsedtime += outlen*10/(wfx.rate/100); |
| 139 | ci->set_elapsed(elapsedtime); |
| 140 | ci->yield (); |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | } |
| 145 | |
| 146 | /* Advance to the next logical packet */ |
| 147 | ci->advance_buffer(packetlength); |
| 148 | } |
Mohamed Tarek | 816fca8 | 2010-06-21 10:48:34 +0000 | [diff] [blame] | 149 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame] | 150 | return CODEC_OK; |
Mohamed Tarek | cd4d80a | 2010-05-09 21:42:09 +0000 | [diff] [blame] | 151 | } |
| 152 | |