diff options
-rw-r--r-- | lib/rbcodec/codecs/a52_rm.c | 109 | ||||
-rw-r--r-- | lib/rbcodec/codecs/atrac3_rm.c | 91 | ||||
-rw-r--r-- | lib/rbcodec/codecs/cook.c | 106 | ||||
-rw-r--r-- | lib/rbcodec/codecs/librm/rm.c | 59 | ||||
-rw-r--r-- | lib/rbcodec/codecs/librm/rm.h | 5 | ||||
-rw-r--r-- | lib/rbcodec/codecs/raac.c | 3 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata.c | 4 | ||||
-rw-r--r-- | lib/rbcodec/metadata/rm.c | 56 |
8 files changed, 309 insertions, 124 deletions
diff --git a/lib/rbcodec/codecs/a52_rm.c b/lib/rbcodec/codecs/a52_rm.c index bbfd1c735f..e5204762f4 100644 --- a/lib/rbcodec/codecs/a52_rm.c +++ b/lib/rbcodec/codecs/a52_rm.c | |||
@@ -44,6 +44,14 @@ static void init_rm(RMContext *rmctx) | |||
44 | 44 | ||
45 | /* used outside liba52 */ | 45 | /* used outside liba52 */ |
46 | static uint8_t buf[3840] IBSS_ATTR; | 46 | static uint8_t buf[3840] IBSS_ATTR; |
47 | static uint8_t *bufptr = buf; | ||
48 | static uint8_t *bufpos = buf + 7; | ||
49 | |||
50 | static void a52_decoder_reset(void) | ||
51 | { | ||
52 | bufptr = buf; | ||
53 | bufpos = buf + 7; | ||
54 | } | ||
47 | 55 | ||
48 | /* The following two functions, a52_decode_data and output_audio are taken from a52.c */ | 56 | /* The following two functions, a52_decode_data and output_audio are taken from a52.c */ |
49 | static inline void output_audio(sample_t *samples) | 57 | static inline void output_audio(sample_t *samples) |
@@ -52,10 +60,8 @@ static inline void output_audio(sample_t *samples) | |||
52 | ci->pcmbuf_insert(&samples[0], &samples[256], 256); | 60 | ci->pcmbuf_insert(&samples[0], &samples[256], 256); |
53 | } | 61 | } |
54 | 62 | ||
55 | static void a52_decode_data(uint8_t *start, uint8_t *end) | 63 | static size_t a52_decode_data(uint8_t *start, uint8_t *end) |
56 | { | 64 | { |
57 | static uint8_t *bufptr = buf; | ||
58 | static uint8_t *bufpos = buf + 7; | ||
59 | /* | 65 | /* |
60 | * sample_rate and flags are static because this routine could | 66 | * sample_rate and flags are static because this routine could |
61 | * exit between the a52_syncinfo() and the ao_setup(), and we want | 67 | * exit between the a52_syncinfo() and the ao_setup(), and we want |
@@ -65,6 +71,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) | |||
65 | static int flags; | 71 | static int flags; |
66 | int bit_rate; | 72 | int bit_rate; |
67 | int len; | 73 | int len; |
74 | size_t consumed = 0; | ||
68 | 75 | ||
69 | while (1) { | 76 | while (1) { |
70 | len = end - start; | 77 | len = end - start; |
@@ -75,6 +82,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) | |||
75 | memcpy(bufptr, start, len); | 82 | memcpy(bufptr, start, len); |
76 | bufptr += len; | 83 | bufptr += len; |
77 | start += len; | 84 | start += len; |
85 | consumed += len; | ||
78 | if (bufptr == bufpos) { | 86 | if (bufptr == bufpos) { |
79 | if (bufpos == buf + 7) { | 87 | if (bufpos == buf + 7) { |
80 | int length; | 88 | int length; |
@@ -114,7 +122,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) | |||
114 | ci->set_elapsed(samplesdone/(frequency/1000)); | 122 | ci->set_elapsed(samplesdone/(frequency/1000)); |
115 | bufptr = buf; | 123 | bufptr = buf; |
116 | bufpos = buf + 7; | 124 | bufpos = buf + 7; |
117 | continue; | 125 | break; |
118 | error: | 126 | error: |
119 | //logf("Error decoding A52 stream\n"); | 127 | //logf("Error decoding A52 stream\n"); |
120 | bufptr = buf; | 128 | bufptr = buf; |
@@ -122,6 +130,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) | |||
122 | } | 130 | } |
123 | } | 131 | } |
124 | } | 132 | } |
133 | return consumed; | ||
125 | } | 134 | } |
126 | 135 | ||
127 | /* this is the codec entry point */ | 136 | /* this is the codec entry point */ |
@@ -143,11 +152,13 @@ enum codec_status codec_main(enum codec_entry_call_reason reason) | |||
143 | /* this is called for each file to process */ | 152 | /* this is called for each file to process */ |
144 | enum codec_status codec_run(void) | 153 | enum codec_status codec_run(void) |
145 | { | 154 | { |
146 | size_t n; | 155 | size_t consumed = 0, n = 0; |
147 | uint8_t *filebuf; | 156 | uint8_t *filebuf; |
148 | int consumed, packet_offset; | 157 | int packet_offset; |
149 | int playback_on = -1; | 158 | int playback_on = -1; |
150 | size_t resume_offset; | 159 | size_t resume_offset; |
160 | size_t data_offset; | ||
161 | size_t packet_size; | ||
151 | long action; | 162 | long action; |
152 | intptr_t param; | 163 | intptr_t param; |
153 | 164 | ||
@@ -162,21 +173,28 @@ enum codec_status codec_run(void) | |||
162 | ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); | 173 | ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); |
163 | codec_set_replaygain(ci->id3); | 174 | codec_set_replaygain(ci->id3); |
164 | 175 | ||
165 | ci->seek_buffer(ci->id3->first_frame_offset); | 176 | ci->seek_buffer(0); |
166 | 177 | ||
167 | /* Intializations */ | 178 | /* Initializations */ |
168 | state = a52_init(0); | 179 | state = a52_init(0); |
169 | ci->memset(&rmctx,0,sizeof(RMContext)); | 180 | ci->memset(&rmctx,0,sizeof(RMContext)); |
170 | ci->memset(&pkt,0,sizeof(RMPacket)); | 181 | ci->memset(&pkt,0,sizeof(RMPacket)); |
171 | init_rm(&rmctx); | 182 | init_rm(&rmctx); |
183 | data_offset = rmctx.data_offset + | ||
184 | ((rmctx.flags & RM_RAW_DATASTREAM) ? 0 : DATA_HEADER_SIZE); | ||
185 | packet_size = rmctx.block_align + | ||
186 | ((rmctx.flags & RM_RAW_DATASTREAM) ? | ||
187 | 0 : | ||
188 | (PACKET_HEADER_SIZE + | ||
189 | ((rmctx.flags & RM_PKT_V1) ? 1 : 0))); | ||
172 | 190 | ||
173 | samplesdone = 0; | 191 | samplesdone = 0; |
174 | 192 | ||
175 | /* check for a mid-track resume and force a seek time accordingly */ | 193 | /* check for a mid-track resume and force a seek time accordingly */ |
176 | if (resume_offset) { | 194 | if (resume_offset) { |
177 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); | 195 | resume_offset -= MIN(resume_offset, data_offset); |
178 | /* put number of subpackets to skip in resume_offset */ | 196 | /* put number of subpackets to skip in resume_offset */ |
179 | resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); | 197 | resume_offset /= packet_size; |
180 | param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); | 198 | param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); |
181 | } | 199 | } |
182 | 200 | ||
@@ -186,11 +204,11 @@ enum codec_status codec_run(void) | |||
186 | else { | 204 | else { |
187 | /* Seek to the first packet */ | 205 | /* Seek to the first packet */ |
188 | ci->set_elapsed(0); | 206 | ci->set_elapsed(0); |
189 | ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE ); | 207 | ci->advance_buffer(data_offset); |
190 | } | 208 | } |
191 | 209 | ||
192 | /* The main decoding loop */ | 210 | /* The main decoding loop */ |
193 | while((unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) { | 211 | while ((rmctx.flags & RM_RAW_DATASTREAM) || (unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) { |
194 | if (action == CODEC_ACTION_NULL) | 212 | if (action == CODEC_ACTION_NULL) |
195 | action = ci->get_command(¶m); | 213 | action = ci->get_command(¶m); |
196 | 214 | ||
@@ -198,34 +216,69 @@ enum codec_status codec_run(void) | |||
198 | break; | 216 | break; |
199 | 217 | ||
200 | if (action == CODEC_ACTION_SEEK_TIME) { | 218 | if (action == CODEC_ACTION_SEEK_TIME) { |
219 | /* Do not allow seeking beyond the file's length */ | ||
220 | if ((unsigned) param > ci->id3->length) { | ||
221 | ci->set_elapsed(ci->id3->length); | ||
222 | ci->seek_complete(); | ||
223 | break; | ||
224 | } | ||
225 | |||
226 | if (n) | ||
227 | rm_ac3_swap_bytes(filebuf, (rmctx.flags & RM_RAW_DATASTREAM) ? n : rmctx.block_align); | ||
201 | packet_offset = param / ((rmctx.block_align*8*1000)/rmctx.bit_rate); | 228 | packet_offset = param / ((rmctx.block_align*8*1000)/rmctx.bit_rate); |
202 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + | 229 | ci->seek_buffer(data_offset + packet_offset * packet_size); |
203 | packet_offset*(rmctx.block_align + PACKET_HEADER_SIZE)); | ||
204 | rmctx.audio_pkt_cnt = packet_offset; | 230 | rmctx.audio_pkt_cnt = packet_offset; |
205 | samplesdone = (rmctx.sample_rate/1000 * param); | 231 | samplesdone = packet_offset * A52_SAMPLESPERFRAME; |
206 | ci->set_elapsed(samplesdone/(frequency/1000)); | 232 | ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); |
207 | ci->seek_complete(); | 233 | ci->seek_complete(); |
234 | a52_decoder_reset(); | ||
235 | consumed = 0; | ||
236 | n = 0; | ||
208 | } | 237 | } |
209 | 238 | ||
210 | action = CODEC_ACTION_NULL; | 239 | action = CODEC_ACTION_NULL; |
211 | 240 | ||
212 | filebuf = ci->request_buffer(&n, rmctx.block_align + PACKET_HEADER_SIZE); | 241 | if (rmctx.flags & RM_RAW_DATASTREAM) { |
213 | consumed = rm_get_packet(&filebuf, &rmctx, &pkt); | 242 | if (n > consumed) { |
214 | 243 | consumed += a52_decode_data(filebuf + consumed, filebuf + n); | |
215 | if(consumed < 0 && playback_on != 0) { | 244 | ci->set_offset(ci->curpos + consumed); |
216 | if(playback_on == -1) { | ||
217 | /* Error only if packet-parsing failed and playback hadn't started */ | ||
218 | DEBUGF("rm_get_packet failed\n"); | ||
219 | return CODEC_ERROR; | ||
220 | } | 245 | } |
221 | else { | 246 | else { |
222 | break; | 247 | if (n) { |
248 | rm_ac3_swap_bytes(filebuf, n); | ||
249 | ci->advance_buffer(n); | ||
250 | } | ||
251 | filebuf = ci->request_buffer(&n, BUFFER_SIZE); | ||
252 | if (n == 0) | ||
253 | break; | ||
254 | rm_ac3_swap_bytes(filebuf, n); | ||
255 | consumed = 0; | ||
223 | } | 256 | } |
224 | } | 257 | } |
258 | else { | ||
259 | filebuf = ci->request_buffer(&n, packet_size); | ||
260 | |||
261 | if (n == 0) | ||
262 | break; | ||
263 | |||
264 | if (rm_get_packet(&filebuf, &rmctx, &pkt) < 0 && playback_on != 0) { | ||
265 | if(playback_on == -1) { | ||
266 | /* Error only if packet-parsing failed and playback hadn't started */ | ||
267 | DEBUGF("rm_get_packet failed\n"); | ||
268 | return CODEC_ERROR; | ||
269 | } | ||
270 | else { | ||
271 | break; | ||
272 | } | ||
273 | } | ||
225 | 274 | ||
226 | playback_on = 1; | 275 | playback_on = 1; |
227 | a52_decode_data(filebuf, filebuf + rmctx.block_align); | 276 | consumed = 0; |
228 | ci->advance_buffer(pkt.length); | 277 | while (consumed < rmctx.block_align) |
278 | consumed += a52_decode_data(filebuf + consumed, filebuf + rmctx.block_align); | ||
279 | rm_ac3_swap_bytes(filebuf, rmctx.block_align); | ||
280 | ci->advance_buffer(pkt.length); | ||
281 | } | ||
229 | } | 282 | } |
230 | 283 | ||
231 | return CODEC_OK; | 284 | return CODEC_OK; |
diff --git a/lib/rbcodec/codecs/atrac3_rm.c b/lib/rbcodec/codecs/atrac3_rm.c index 59dbd29cad..af38b79fc4 100644 --- a/lib/rbcodec/codecs/atrac3_rm.c +++ b/lib/rbcodec/codecs/atrac3_rm.c | |||
@@ -21,7 +21,6 @@ | |||
21 | 21 | ||
22 | #include <string.h> | 22 | #include <string.h> |
23 | 23 | ||
24 | #include "logf.h" | ||
25 | #include "codeclib.h" | 24 | #include "codeclib.h" |
26 | #include "inttypes.h" | 25 | #include "inttypes.h" |
27 | #include "libatrac/atrac3.h" | 26 | #include "libatrac/atrac3.h" |
@@ -37,10 +36,26 @@ static void init_rm(RMContext *rmctx) | |||
37 | /* initialize the RMContext */ | 36 | /* initialize the RMContext */ |
38 | memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext)); | 37 | memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext)); |
39 | 38 | ||
40 | /* and atrac3 expects extadata in id3v2buf, so we shall give it that */ | 39 | /* and atrac3 expects extradata in id3v2buf, so we shall give it that */ |
41 | memcpy(ci->id3->id3v2buf, (char*)rmctx->codec_extradata, rmctx->extradata_size*sizeof(char)); | 40 | memcpy(ci->id3->id3v2buf, (char*)rmctx->codec_extradata, rmctx->extradata_size*sizeof(char)); |
42 | } | 41 | } |
43 | 42 | ||
43 | static int request_packet(int size) | ||
44 | { | ||
45 | int consumed = 0; | ||
46 | while (1) | ||
47 | { | ||
48 | uint8_t *buffer = ci->request_buffer((size_t *)(&consumed), size); | ||
49 | if (!consumed) | ||
50 | break; | ||
51 | consumed = rm_get_packet(&buffer, &rmctx, &pkt); | ||
52 | if (consumed < 0 || consumed == size) | ||
53 | break; | ||
54 | ci->advance_buffer(size); | ||
55 | } | ||
56 | return consumed; | ||
57 | } | ||
58 | |||
44 | /* this is the codec entry point */ | 59 | /* this is the codec entry point */ |
45 | enum codec_status codec_main(enum codec_entry_call_reason reason) | 60 | enum codec_status codec_main(enum codec_entry_call_reason reason) |
46 | { | 61 | { |
@@ -52,12 +67,10 @@ enum codec_status codec_main(enum codec_entry_call_reason reason) | |||
52 | /* this is called for each file to process */ | 67 | /* this is called for each file to process */ |
53 | enum codec_status codec_run(void) | 68 | enum codec_status codec_run(void) |
54 | { | 69 | { |
55 | static size_t buff_size; | ||
56 | int datasize, res, consumed, i, time_offset; | 70 | int datasize, res, consumed, i, time_offset; |
57 | uint8_t *bit_buffer; | ||
58 | uint16_t fs,sps,h; | 71 | uint16_t fs,sps,h; |
59 | uint32_t packet_count; | 72 | uint32_t packet_count; |
60 | int scrambling_unit_size, num_units, elapsed; | 73 | int spn, packet_header_size, scrambling_unit_size, num_units, elapsed; |
61 | int playback_on = -1; | 74 | int playback_on = -1; |
62 | size_t resume_offset; | 75 | size_t resume_offset; |
63 | intptr_t param; | 76 | intptr_t param; |
@@ -85,14 +98,17 @@ enum codec_status codec_run(void) | |||
85 | ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ? | 98 | ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ? |
86 | STEREO_MONO : STEREO_NONINTERLEAVED); | 99 | STEREO_MONO : STEREO_NONINTERLEAVED); |
87 | 100 | ||
101 | packet_header_size = PACKET_HEADER_SIZE + | ||
102 | ((rmctx.flags & RM_PKT_V1) ? 1 : 0); | ||
88 | packet_count = rmctx.nb_packets; | 103 | packet_count = rmctx.nb_packets; |
89 | rmctx.audio_framesize = rmctx.block_align; | 104 | rmctx.audio_framesize = rmctx.block_align; |
90 | rmctx.block_align = rmctx.sub_packet_size; | 105 | rmctx.block_align = rmctx.sub_packet_size; |
91 | fs = rmctx.audio_framesize; | 106 | fs = rmctx.audio_framesize; |
92 | sps= rmctx.block_align; | 107 | sps= rmctx.block_align; |
93 | h = rmctx.sub_packet_h; | 108 | h = rmctx.sub_packet_h; |
94 | scrambling_unit_size = h * (fs + PACKET_HEADER_SIZE); | 109 | scrambling_unit_size = h * (fs + packet_header_size); |
95 | 110 | spn = h * fs / sps; | |
111 | |||
96 | res = atrac3_decode_init(&q, ci->id3); | 112 | res = atrac3_decode_init(&q, ci->id3); |
97 | if(res < 0) { | 113 | if(res < 0) { |
98 | DEBUGF("failed to initialize RM atrac decoder\n"); | 114 | DEBUGF("failed to initialize RM atrac decoder\n"); |
@@ -102,10 +118,10 @@ enum codec_status codec_run(void) | |||
102 | /* check for a mid-track resume and force a seek time accordingly */ | 118 | /* check for a mid-track resume and force a seek time accordingly */ |
103 | if(resume_offset) { | 119 | if(resume_offset) { |
104 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); | 120 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); |
105 | num_units = (int)resume_offset / scrambling_unit_size; | 121 | num_units = (int)resume_offset / scrambling_unit_size; |
106 | /* put number of subpackets to skip in resume_offset */ | 122 | /* put number of packets to skip in resume_offset */ |
107 | resume_offset /= (sps + PACKET_HEADER_SIZE); | 123 | resume_offset = num_units * h; |
108 | elapsed = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); | 124 | elapsed = (int)resume_offset * ((8000LL * fs)/rmctx.bit_rate); |
109 | } | 125 | } |
110 | 126 | ||
111 | if (elapsed > 0) { | 127 | if (elapsed > 0) { |
@@ -123,8 +139,9 @@ enum codec_status codec_run(void) | |||
123 | seek_start : | 139 | seek_start : |
124 | while((unsigned)elapsed < rmctx.duration) | 140 | while((unsigned)elapsed < rmctx.duration) |
125 | { | 141 | { |
126 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); | 142 | consumed = request_packet(scrambling_unit_size); |
127 | consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); | 143 | if (!consumed) |
144 | break; | ||
128 | if(consumed < 0 && playback_on != 0) { | 145 | if(consumed < 0 && playback_on != 0) { |
129 | if(playback_on == -1) { | 146 | if(playback_on == -1) { |
130 | /* Error only if packet-parsing failed and playback hadn't started */ | 147 | /* Error only if packet-parsing failed and playback hadn't started */ |
@@ -135,7 +152,7 @@ seek_start : | |||
135 | return CODEC_OK; | 152 | return CODEC_OK; |
136 | } | 153 | } |
137 | 154 | ||
138 | for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) | 155 | for (i = 0; i < spn; i++) |
139 | { | 156 | { |
140 | if (action == CODEC_ACTION_NULL) | 157 | if (action == CODEC_ACTION_NULL) |
141 | action = ci->get_command(¶m); | 158 | action = ci->get_command(¶m); |
@@ -164,10 +181,11 @@ seek_start : | |||
164 | action = CODEC_ACTION_NULL; | 181 | action = CODEC_ACTION_NULL; |
165 | goto seek_start; | 182 | goto seek_start; |
166 | } | 183 | } |
167 | num_units = (param/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps)); | 184 | num_units = (param/(sps*1000*8/rmctx.bit_rate))/spn; |
168 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units); | 185 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units); |
169 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); | 186 | consumed = request_packet(scrambling_unit_size); |
170 | consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); | 187 | if (!consumed) |
188 | return CODEC_OK; | ||
171 | if(consumed < 0 && playback_on != 0) { | 189 | if(consumed < 0 && playback_on != 0) { |
172 | if(playback_on == -1) { | 190 | if(playback_on == -1) { |
173 | /* Error only if packet-parsing failed and playback hadn't started */ | 191 | /* Error only if packet-parsing failed and playback hadn't started */ |
@@ -178,19 +196,32 @@ seek_start : | |||
178 | return CODEC_OK; | 196 | return CODEC_OK; |
179 | } | 197 | } |
180 | 198 | ||
181 | packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units; | 199 | packet_count = rmctx.nb_packets - h * num_units; |
182 | rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate)); | 200 | rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate)); |
183 | while(rmctx.audiotimestamp > (unsigned) param) { | 201 | while (rmctx.audiotimestamp > (unsigned)param && num_units-- > 0) { |
184 | rmctx.audio_pkt_cnt = 0; | 202 | rmctx.audio_pkt_cnt = 0; |
185 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1)); | 203 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units); |
186 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); | 204 | consumed = request_packet(scrambling_unit_size); |
187 | consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); | 205 | if (!consumed) |
188 | packet_count += rmctx.audio_pkt_cnt; | 206 | return CODEC_OK; |
189 | num_units--; | 207 | if(consumed < 0 && playback_on != 0) { |
208 | if(playback_on == -1) { | ||
209 | /* Error only if packet-parsing failed and playback hadn't started */ | ||
210 | DEBUGF("rm_get_packet failed\n"); | ||
211 | return CODEC_ERROR; | ||
212 | } | ||
213 | else | ||
214 | return CODEC_OK; | ||
215 | } | ||
216 | |||
217 | packet_count += h; | ||
190 | } | 218 | } |
219 | |||
220 | if (num_units < 0) | ||
221 | rmctx.audiotimestamp = 0; | ||
191 | time_offset = param - rmctx.audiotimestamp; | 222 | time_offset = param - rmctx.audiotimestamp; |
192 | i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate)); | 223 | i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate)); |
193 | elapsed = rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i; | 224 | elapsed = param; |
194 | ci->set_elapsed(elapsed); | 225 | ci->set_elapsed(elapsed); |
195 | ci->seek_complete(); | 226 | ci->seek_complete(); |
196 | } | 227 | } |
@@ -198,11 +229,11 @@ seek_start : | |||
198 | action = CODEC_ACTION_NULL; | 229 | action = CODEC_ACTION_NULL; |
199 | 230 | ||
200 | if(pkt.length) | 231 | if(pkt.length) |
201 | res = atrac3_decode_frame(rmctx.block_align, &q, &datasize, pkt.frames[i], rmctx.block_align); | 232 | res = atrac3_decode_frame(sps, &q, &datasize, pkt.frames[i], sps); |
202 | else /* indicates that there are no remaining frames */ | 233 | else /* indicates that there are no remaining frames */ |
203 | return CODEC_OK; | 234 | return CODEC_OK; |
204 | 235 | ||
205 | if(res != rmctx.block_align) { | 236 | if (res != sps) { |
206 | DEBUGF("codec error\n"); | 237 | DEBUGF("codec error\n"); |
207 | return CODEC_ERROR; | 238 | return CODEC_ERROR; |
208 | } | 239 | } |
@@ -214,9 +245,9 @@ seek_start : | |||
214 | ci->set_elapsed(elapsed); | 245 | ci->set_elapsed(elapsed); |
215 | rmctx.frame_number++; | 246 | rmctx.frame_number++; |
216 | } | 247 | } |
217 | packet_count -= rmctx.audio_pkt_cnt; | 248 | packet_count -= h; |
218 | rmctx.audio_pkt_cnt = 0; | 249 | rmctx.audio_pkt_cnt = 0; |
219 | ci->advance_buffer(consumed); | 250 | ci->advance_buffer(scrambling_unit_size); |
220 | } | 251 | } |
221 | 252 | ||
222 | return CODEC_OK; | 253 | return CODEC_OK; |
diff --git a/lib/rbcodec/codecs/cook.c b/lib/rbcodec/codecs/cook.c index af1f5e1a87..254e71f576 100644 --- a/lib/rbcodec/codecs/cook.c +++ b/lib/rbcodec/codecs/cook.c | |||
@@ -21,7 +21,6 @@ | |||
21 | 21 | ||
22 | #include <string.h> | 22 | #include <string.h> |
23 | 23 | ||
24 | #include "logf.h" | ||
25 | #include "codeclib.h" | 24 | #include "codeclib.h" |
26 | #include "inttypes.h" | 25 | #include "inttypes.h" |
27 | #include "libcook/cook.h" | 26 | #include "libcook/cook.h" |
@@ -38,6 +37,22 @@ static void init_rm(RMContext *rmctx) | |||
38 | memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext)); | 37 | memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext)); |
39 | } | 38 | } |
40 | 39 | ||
40 | static int request_packet(int size) | ||
41 | { | ||
42 | int consumed = 0; | ||
43 | while (1) | ||
44 | { | ||
45 | uint8_t *buffer = ci->request_buffer((size_t *)(&consumed), size); | ||
46 | if (!consumed) | ||
47 | break; | ||
48 | consumed = rm_get_packet(&buffer, &rmctx, &pkt); | ||
49 | if (consumed < 0 || consumed == size) | ||
50 | break; | ||
51 | ci->advance_buffer(size); | ||
52 | } | ||
53 | return consumed; | ||
54 | } | ||
55 | |||
41 | /* this is the codec entry point */ | 56 | /* this is the codec entry point */ |
42 | enum codec_status codec_main(enum codec_entry_call_reason reason) | 57 | enum codec_status codec_main(enum codec_entry_call_reason reason) |
43 | { | 58 | { |
@@ -49,12 +64,10 @@ enum codec_status codec_main(enum codec_entry_call_reason reason) | |||
49 | /* this is called for each file to process */ | 64 | /* this is called for each file to process */ |
50 | enum codec_status codec_run(void) | 65 | enum codec_status codec_run(void) |
51 | { | 66 | { |
52 | static size_t buff_size; | ||
53 | int datasize, res, consumed, i, time_offset; | 67 | int datasize, res, consumed, i, time_offset; |
54 | uint8_t *bit_buffer; | ||
55 | uint16_t fs,sps,h; | 68 | uint16_t fs,sps,h; |
56 | uint32_t packet_count; | 69 | uint32_t packet_count; |
57 | int scrambling_unit_size, num_units; | 70 | int spn, packet_header_size, scrambling_unit_size, num_units; |
58 | size_t resume_offset; | 71 | size_t resume_offset; |
59 | intptr_t param; | 72 | intptr_t param; |
60 | long action; | 73 | long action; |
@@ -84,14 +97,17 @@ enum codec_status codec_run(void) | |||
84 | ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ? | 97 | ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ? |
85 | STEREO_MONO : STEREO_NONINTERLEAVED); | 98 | STEREO_MONO : STEREO_NONINTERLEAVED); |
86 | 99 | ||
100 | packet_header_size = PACKET_HEADER_SIZE + | ||
101 | ((rmctx.flags & RM_PKT_V1) ? 1 : 0); | ||
87 | packet_count = rmctx.nb_packets; | 102 | packet_count = rmctx.nb_packets; |
88 | rmctx.audio_framesize = rmctx.block_align; | 103 | rmctx.audio_framesize = rmctx.block_align; |
89 | rmctx.block_align = rmctx.sub_packet_size; | 104 | rmctx.block_align = rmctx.sub_packet_size; |
90 | fs = rmctx.audio_framesize; | 105 | fs = rmctx.audio_framesize; |
91 | sps= rmctx.block_align; | 106 | sps= rmctx.block_align; |
92 | h = rmctx.sub_packet_h; | 107 | h = rmctx.sub_packet_h; |
93 | scrambling_unit_size = h * (fs + PACKET_HEADER_SIZE); | 108 | scrambling_unit_size = h * (fs + packet_header_size); |
94 | 109 | spn = h * fs / sps; | |
110 | |||
95 | res =cook_decode_init(&rmctx, &q); | 111 | res =cook_decode_init(&rmctx, &q); |
96 | if(res < 0) { | 112 | if(res < 0) { |
97 | DEBUGF("failed to initialize cook decoder\n"); | 113 | DEBUGF("failed to initialize cook decoder\n"); |
@@ -101,10 +117,10 @@ enum codec_status codec_run(void) | |||
101 | /* check for a mid-track resume and force a seek time accordingly */ | 117 | /* check for a mid-track resume and force a seek time accordingly */ |
102 | if(resume_offset) { | 118 | if(resume_offset) { |
103 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); | 119 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); |
104 | num_units = (int)resume_offset / scrambling_unit_size; | 120 | num_units = (int)resume_offset / scrambling_unit_size; |
105 | /* put number of subpackets to skip in resume_offset */ | 121 | /* put number of packets to skip in resume_offset */ |
106 | resume_offset /= (sps + PACKET_HEADER_SIZE); | 122 | resume_offset = num_units * h; |
107 | param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); | 123 | param = (int)resume_offset * ((8000LL * fs)/rmctx.bit_rate); |
108 | } | 124 | } |
109 | 125 | ||
110 | if (param) { | 126 | if (param) { |
@@ -120,14 +136,15 @@ enum codec_status codec_run(void) | |||
120 | seek_start : | 136 | seek_start : |
121 | while(packet_count) | 137 | while(packet_count) |
122 | { | 138 | { |
123 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); | 139 | consumed = request_packet(scrambling_unit_size); |
124 | consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); | 140 | if (!consumed) |
141 | break; | ||
125 | if(consumed < 0) { | 142 | if(consumed < 0) { |
126 | DEBUGF("rm_get_packet failed\n"); | 143 | DEBUGF("rm_get_packet failed\n"); |
127 | return CODEC_ERROR; | 144 | return CODEC_ERROR; |
128 | } | 145 | } |
129 | 146 | ||
130 | for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) | 147 | for (i = 0; i < spn; i++) |
131 | { | 148 | { |
132 | if (action == CODEC_ACTION_NULL) | 149 | if (action == CODEC_ACTION_NULL) |
133 | action = ci->get_command(¶m); | 150 | action = ci->get_command(¶m); |
@@ -155,52 +172,65 @@ seek_start : | |||
155 | action = CODEC_ACTION_NULL; | 172 | action = CODEC_ACTION_NULL; |
156 | goto seek_start; | 173 | goto seek_start; |
157 | } | 174 | } |
158 | num_units = (param/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps)); | 175 | num_units = (param/(sps*1000*8/rmctx.bit_rate))/spn; |
159 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units); | 176 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units); |
160 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); | 177 | consumed = request_packet(scrambling_unit_size); |
161 | consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); | 178 | if (!consumed) { |
179 | ci->seek_complete(); | ||
180 | return CODEC_OK; | ||
181 | } | ||
162 | if(consumed < 0) { | 182 | if(consumed < 0) { |
163 | DEBUGF("rm_get_packet failed\n"); | 183 | DEBUGF("rm_get_packet failed\n"); |
164 | ci->seek_complete(); | 184 | ci->seek_complete(); |
165 | return CODEC_ERROR; | 185 | return CODEC_ERROR; |
166 | } | 186 | } |
167 | packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units; | 187 | |
188 | packet_count = rmctx.nb_packets - h * num_units; | ||
168 | rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate)); | 189 | rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate)); |
169 | while(rmctx.audiotimestamp > (unsigned) param) { | 190 | while(rmctx.audiotimestamp > (unsigned)param && num_units-- > 0) { |
170 | rmctx.audio_pkt_cnt = 0; | 191 | rmctx.audio_pkt_cnt = 0; |
171 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1)); | 192 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units); |
172 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); | 193 | consumed = request_packet(scrambling_unit_size); |
173 | consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); | 194 | if (!consumed) { |
174 | packet_count += rmctx.audio_pkt_cnt; | 195 | ci->seek_complete(); |
175 | num_units--; | 196 | return CODEC_OK; |
197 | } | ||
198 | if(consumed < 0) { | ||
199 | ci->seek_complete(); | ||
200 | DEBUGF("rm_get_packet failed\n"); | ||
201 | return CODEC_ERROR; | ||
202 | } | ||
203 | |||
204 | packet_count += h; | ||
176 | } | 205 | } |
206 | |||
207 | if (num_units < 0) | ||
208 | rmctx.audiotimestamp = 0; | ||
177 | time_offset = param - rmctx.audiotimestamp; | 209 | time_offset = param - rmctx.audiotimestamp; |
178 | i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate)); | 210 | i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate)); |
179 | ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i); | 211 | ci->set_elapsed(param); |
180 | ci->seek_complete(); | 212 | ci->seek_complete(); |
181 | } | 213 | } |
182 | 214 | ||
183 | action = CODEC_ACTION_NULL; | 215 | action = CODEC_ACTION_NULL; |
184 | 216 | ||
185 | res = cook_decode_frame(&rmctx,&q, rm_outbuf, &datasize, pkt.frames[i], rmctx.block_align); | 217 | res = cook_decode_frame(&rmctx,&q, rm_outbuf, &datasize, pkt.frames[i], sps); |
186 | rmctx.frame_number++; | ||
187 | |||
188 | /* skip the first two frames; no valid audio */ | ||
189 | if(rmctx.frame_number < 3) continue; | ||
190 | 218 | ||
191 | if(res != rmctx.block_align) { | 219 | if (res != sps) { |
192 | DEBUGF("codec error\n"); | 220 | DEBUGF("codec error\n"); |
193 | return CODEC_ERROR; | 221 | return CODEC_ERROR; |
194 | } | 222 | } |
195 | 223 | ||
196 | ci->pcmbuf_insert(rm_outbuf, | 224 | if(datasize) |
197 | rm_outbuf+q.samples_per_channel, | 225 | ci->pcmbuf_insert(rm_outbuf, |
198 | q.samples_per_channel); | 226 | rm_outbuf+q.samples_per_channel, |
227 | q.samples_per_channel); | ||
199 | ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i); | 228 | ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i); |
229 | rmctx.frame_number++; | ||
200 | } | 230 | } |
201 | packet_count -= rmctx.audio_pkt_cnt; | 231 | packet_count -= h; |
202 | rmctx.audio_pkt_cnt = 0; | 232 | rmctx.audio_pkt_cnt = 0; |
203 | ci->advance_buffer(consumed); | 233 | ci->advance_buffer(scrambling_unit_size); |
204 | } | 234 | } |
205 | 235 | ||
206 | return CODEC_OK; | 236 | return CODEC_OK; |
diff --git a/lib/rbcodec/codecs/librm/rm.c b/lib/rbcodec/codecs/librm/rm.c index eabbe5d92a..e499961a7f 100644 --- a/lib/rbcodec/codecs/librm/rm.c +++ b/lib/rbcodec/codecs/librm/rm.c | |||
@@ -27,8 +27,6 @@ | |||
27 | #include "codeclib.h" | 27 | #include "codeclib.h" |
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | #define SWAP(a, b) do{uint8_t SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) | ||
31 | |||
32 | #ifdef TEST | 30 | #ifdef TEST |
33 | #include <fcntl.h> | 31 | #include <fcntl.h> |
34 | #include <unistd.h> | 32 | #include <unistd.h> |
@@ -500,17 +498,33 @@ void rm_get_packet_fd(int fd,RMContext *rmctx, RMPacket *pkt) | |||
500 | } | 498 | } |
501 | #endif /*TEST*/ | 499 | #endif /*TEST*/ |
502 | 500 | ||
501 | void rm_ac3_swap_bytes(uint8_t *buf, int bufsize) | ||
502 | { | ||
503 | uint8_t *bufptr; | ||
504 | for (bufptr = buf; bufptr < buf + bufsize - 1; bufptr += 2) | ||
505 | { | ||
506 | bufptr[0] ^= bufptr[1]; | ||
507 | bufptr[1] ^= bufptr[0]; | ||
508 | bufptr[0] ^= bufptr[1]; | ||
509 | } | ||
510 | } | ||
511 | |||
503 | int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) | 512 | int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) |
504 | { | 513 | { |
505 | int consumed = 0; | 514 | int consumed = 0; |
515 | int headerlen; | ||
506 | /* rockbox: comment 'set but unused' variables | 516 | /* rockbox: comment 'set but unused' variables |
507 | uint8_t unknown; | 517 | uint8_t unknown; |
508 | */ | 518 | */ |
509 | uint16_t x, place; | 519 | uint16_t x; |
510 | uint16_t sps = rmctx->sub_packet_size; | 520 | uint16_t sps = rmctx->sub_packet_size; |
511 | uint16_t h = rmctx->sub_packet_h; | 521 | uint16_t h = rmctx->sub_packet_h; |
512 | uint16_t y = rmctx->sub_packet_cnt; | 522 | uint16_t y = 0; |
513 | uint16_t w = rmctx->audio_framesize; | 523 | uint16_t w = rmctx->audio_framesize; |
524 | |||
525 | rmctx->sub_packet_cnt = 0; | ||
526 | rmctx->audio_pkt_cnt = 0; | ||
527 | |||
514 | do | 528 | do |
515 | { | 529 | { |
516 | y = rmctx->sub_packet_cnt; | 530 | y = rmctx->sub_packet_cnt; |
@@ -523,6 +537,7 @@ int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) | |||
523 | return -1; | 537 | return -1; |
524 | } | 538 | } |
525 | 539 | ||
540 | headerlen = PACKET_HEADER_SIZE + (pkt->version ? 1 : 0); | ||
526 | pkt->length = rm_get_uint16be(*src+2); | 541 | pkt->length = rm_get_uint16be(*src+2); |
527 | pkt->stream_number = rm_get_uint16be(*src+4); | 542 | pkt->stream_number = rm_get_uint16be(*src+4); |
528 | pkt->timestamp = rm_get_uint32be(*src+6); | 543 | pkt->timestamp = rm_get_uint32be(*src+6); |
@@ -534,25 +549,27 @@ int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) | |||
534 | pkt->flags = rm_get_uint8(*src+11); | 549 | pkt->flags = rm_get_uint8(*src+11); |
535 | 550 | ||
536 | if(pkt->version == 1) | 551 | if(pkt->version == 1) |
537 | /* unknown = */ rm_get_uint8(*src+10); | 552 | /* unknown = */ rm_get_uint8(*src+12); |
538 | 553 | ||
539 | if (pkt->flags & 2) /* keyframe */ | 554 | if (pkt->flags & 2) { /* keyframe */ |
540 | y = rmctx->sub_packet_cnt = 0; | 555 | if (y) |
556 | return consumed; | ||
557 | y = 0; | ||
558 | } | ||
541 | if (!y) | 559 | if (!y) |
542 | rmctx->audiotimestamp = pkt->timestamp; | 560 | rmctx->audiotimestamp = pkt->timestamp; |
543 | 561 | ||
544 | /* Skip packet header */ | 562 | /* Skip packet header */ |
545 | advance_buffer(src, PACKET_HEADER_SIZE); | 563 | advance_buffer(src, headerlen); |
546 | consumed += PACKET_HEADER_SIZE; | 564 | consumed += headerlen; |
547 | if (rmctx->codec_type == CODEC_COOK || rmctx->codec_type == CODEC_ATRAC) { | 565 | if (rmctx->codec_type == CODEC_COOK || rmctx->codec_type == CODEC_ATRAC) { |
548 | for(x = 0 ; x < w/sps; x++) | 566 | for(x = 0 ; x < w/sps; x++) |
549 | { | 567 | { |
550 | place = sps*(h*x+((h+1)/2)*(y&1)+(y>>1)); | 568 | pkt->frames[h*x+((h+1)/2)*(y&1)+(y>>1)] = *src; |
551 | pkt->frames[place/sps] = *src; | ||
552 | advance_buffer(src,sps); | 569 | advance_buffer(src,sps); |
553 | consumed += sps; | 570 | consumed += sps; |
554 | } | 571 | } |
555 | } | 572 | } |
556 | else if (rmctx->codec_type == CODEC_AAC) { | 573 | else if (rmctx->codec_type == CODEC_AAC) { |
557 | rmctx->sub_packet_cnt = (rm_get_uint16be(*src) & 0xf0) >> 4; | 574 | rmctx->sub_packet_cnt = (rm_get_uint16be(*src) & 0xf0) >> 4; |
558 | advance_buffer(src, 2); | 575 | advance_buffer(src, 2); |
@@ -563,22 +580,22 @@ int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) | |||
563 | advance_buffer(src, 2); | 580 | advance_buffer(src, 2); |
564 | consumed += 2; | 581 | consumed += 2; |
565 | } | 582 | } |
566 | rmctx->audio_pkt_cnt = --rmctx->sub_packet_cnt; | 583 | rmctx->audio_pkt_cnt = rmctx->sub_packet_cnt; |
567 | } | 584 | } |
585 | break; | ||
568 | } | 586 | } |
569 | 587 | ||
570 | else if (rmctx->codec_type == CODEC_AC3) { | 588 | else if (rmctx->codec_type == CODEC_AC3) { |
571 | /* The byte order of the data is reversed from standard AC3 */ | 589 | /* The byte order of the data is reversed from standard AC3 */ |
572 | for(x = 0; x < pkt->length - PACKET_HEADER_SIZE; x+=2) { | 590 | rm_ac3_swap_bytes(*src, pkt->length - headerlen); |
573 | SWAP((*src)[0], (*src)[1]); | 591 | break; |
574 | *src += 2; | ||
575 | } | ||
576 | *src -= x; | ||
577 | } | 592 | } |
593 | else return -1; /* invalid codec type */ | ||
594 | |||
578 | rmctx->audio_pkt_cnt++; | 595 | rmctx->audio_pkt_cnt++; |
579 | }while(++(rmctx->sub_packet_cnt) < h); | 596 | }while(++(rmctx->sub_packet_cnt) < h); |
580 | 597 | ||
581 | return consumed; | 598 | return consumed; |
582 | } | 599 | } |
583 | 600 | ||
584 | #ifdef DEBUG | 601 | #ifdef DEBUG |
@@ -587,6 +604,6 @@ void dump_rm_context(RMContext *rmctx) | |||
587 | DEBUGF("block_align = %d\n", rmctx->block_align); | 604 | DEBUGF("block_align = %d\n", rmctx->block_align); |
588 | DEBUGF("nb_channels = %d\n", rmctx->nb_channels); | 605 | DEBUGF("nb_channels = %d\n", rmctx->nb_channels); |
589 | DEBUGF("sample_rate = %d\n", rmctx->sample_rate); | 606 | DEBUGF("sample_rate = %d\n", rmctx->sample_rate); |
590 | DEBUGF("bit_rate = %d\n", rmctx->bit_rate ); | 607 | DEBUGF("bit_rate = %ld\n", rmctx->bit_rate ); |
591 | } | 608 | } |
592 | #endif | 609 | #endif |
diff --git a/lib/rbcodec/codecs/librm/rm.h b/lib/rbcodec/codecs/librm/rm.h index c4a4e3a77e..47ea559f2e 100644 --- a/lib/rbcodec/codecs/librm/rm.h +++ b/lib/rbcodec/codecs/librm/rm.h | |||
@@ -25,6 +25,9 @@ | |||
25 | #include <inttypes.h> | 25 | #include <inttypes.h> |
26 | #include "bytestream.h" | 26 | #include "bytestream.h" |
27 | 27 | ||
28 | #define RM_RAW_DATASTREAM 0x0100 | ||
29 | #define RM_PKT_V1 0x0200 | ||
30 | |||
28 | #define MAX_EXTRADATA_SIZE 16 | 31 | #define MAX_EXTRADATA_SIZE 16 |
29 | #define DATA_HEADER_SIZE 18 | 32 | #define DATA_HEADER_SIZE 18 |
30 | #define PACKET_HEADER_SIZE 12 | 33 | #define PACKET_HEADER_SIZE 12 |
@@ -86,6 +89,8 @@ typedef struct rm_context | |||
86 | 89 | ||
87 | int real_parse_header(int fd, RMContext *rmctx); | 90 | int real_parse_header(int fd, RMContext *rmctx); |
88 | 91 | ||
92 | void rm_ac3_swap_bytes(uint8_t *buf, int bufsize); | ||
93 | |||
89 | /* Get a (sub_packet_h*frames_per_packet) number of audio frames from a memory buffer */ | 94 | /* Get a (sub_packet_h*frames_per_packet) number of audio frames from a memory buffer */ |
90 | int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt); | 95 | int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt); |
91 | 96 | ||
diff --git a/lib/rbcodec/codecs/raac.c b/lib/rbcodec/codecs/raac.c index e77d432680..6856afc52e 100644 --- a/lib/rbcodec/codecs/raac.c +++ b/lib/rbcodec/codecs/raac.c | |||
@@ -109,7 +109,8 @@ enum codec_status codec_run(void) | |||
109 | if (resume_offset) { | 109 | if (resume_offset) { |
110 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); | 110 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); |
111 | /* put number of subpackets to skip in resume_offset */ | 111 | /* put number of subpackets to skip in resume_offset */ |
112 | resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); | 112 | resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE + |
113 | ((rmctx.flags & RM_PKT_V1) ? 1 : 0)); | ||
113 | param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); | 114 | param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); |
114 | } | 115 | } |
115 | 116 | ||
diff --git a/lib/rbcodec/metadata/metadata.c b/lib/rbcodec/metadata/metadata.c index 87ea922788..7ca4b1afd2 100644 --- a/lib/rbcodec/metadata/metadata.c +++ b/lib/rbcodec/metadata/metadata.c | |||
@@ -444,13 +444,13 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname) | |||
444 | /* Load codec specific track tag information and confirm the codec type. */ | 444 | /* Load codec specific track tag information and confirm the codec type. */ |
445 | if (!entry->parse_func) | 445 | if (!entry->parse_func) |
446 | { | 446 | { |
447 | DEBUGF("nothing to parse for %s (format %s)", trackname, entry->label); | 447 | DEBUGF("nothing to parse for %s (format %s)\n", trackname, entry->label); |
448 | return false; | 448 | return false; |
449 | } | 449 | } |
450 | 450 | ||
451 | if (!entry->parse_func(fd, id3)) | 451 | if (!entry->parse_func(fd, id3)) |
452 | { | 452 | { |
453 | DEBUGF("parsing %s failed (format: %s)", trackname, entry->label); | 453 | DEBUGF("parsing %s failed (format: %s)\n", trackname, entry->label); |
454 | return false; | 454 | return false; |
455 | } | 455 | } |
456 | 456 | ||
diff --git a/lib/rbcodec/metadata/rm.c b/lib/rbcodec/metadata/rm.c index 2a5a2892a3..1e33f0b0ac 100644 --- a/lib/rbcodec/metadata/rm.c +++ b/lib/rbcodec/metadata/rm.c | |||
@@ -89,7 +89,7 @@ static char* fourcc2str(uint32_t f) | |||
89 | } | 89 | } |
90 | #endif | 90 | #endif |
91 | 91 | ||
92 | static inline int real_read_audio_stream_info(int fd, RMContext *rmctx) | 92 | static int real_read_audio_stream_info(int fd, RMContext *rmctx) |
93 | { | 93 | { |
94 | int skipped = 0; | 94 | int skipped = 0; |
95 | uint32_t version; | 95 | uint32_t version; |
@@ -111,6 +111,7 @@ static inline int real_read_audio_stream_info(int fd, RMContext *rmctx) | |||
111 | DEBUGF(" version=0x%04lx\n",((version >> 16) & 0xff)); | 111 | DEBUGF(" version=0x%04lx\n",((version >> 16) & 0xff)); |
112 | if (((version >> 16) & 0xff) == 3) { | 112 | if (((version >> 16) & 0xff) == 3) { |
113 | /* Very old version */ | 113 | /* Very old version */ |
114 | return -1; | ||
114 | } else { | 115 | } else { |
115 | #ifdef SIMULATOR | 116 | #ifdef SIMULATOR |
116 | real_read_object_header(fd, &obj); | 117 | real_read_object_header(fd, &obj); |
@@ -218,7 +219,7 @@ static inline int real_read_audio_stream_info(int fd, RMContext *rmctx) | |||
218 | return skipped; | 219 | return skipped; |
219 | } | 220 | } |
220 | 221 | ||
221 | static int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3) | 222 | static inline int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3) |
222 | { | 223 | { |
223 | struct real_object_t obj; | 224 | struct real_object_t obj; |
224 | int res; | 225 | int res; |
@@ -242,6 +243,7 @@ static int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3) | |||
242 | uint32_t max_bitrate; | 243 | uint32_t max_bitrate; |
243 | uint16_t num_streams; | 244 | uint16_t num_streams; |
244 | uint32_t next_data_off; | 245 | uint32_t next_data_off; |
246 | uint16_t pkt_version; | ||
245 | uint8_t header_end; | 247 | uint8_t header_end; |
246 | 248 | ||
247 | memset(&obj,0,sizeof(obj)); | 249 | memset(&obj,0,sizeof(obj)); |
@@ -250,6 +252,35 @@ static int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3) | |||
250 | 252 | ||
251 | if (obj.fourcc == FOURCC('.','r','a',0xfd)) | 253 | if (obj.fourcc == FOURCC('.','r','a',0xfd)) |
252 | { | 254 | { |
255 | lseek(fd, 4, SEEK_SET); | ||
256 | skipped = real_read_audio_stream_info(fd, rmctx); | ||
257 | if (skipped > 0 && rmctx->codec_type == CODEC_AC3) | ||
258 | { | ||
259 | read_uint8(fd,&len); | ||
260 | skipped += (int)read_string(fd, id3->id3v1buf[0], sizeof(id3->id3v1buf[0]), '\0', len); | ||
261 | read_uint8(fd,&len); | ||
262 | skipped += (int)read_string(fd, id3->id3v1buf[1], sizeof(id3->id3v1buf[1]), '\0', len); | ||
263 | read_uint8(fd,&len); | ||
264 | skipped += (int)read_string(fd, id3->id3v1buf[2], sizeof(id3->id3v1buf[2]), '\0', len); | ||
265 | read_uint8(fd,&len); | ||
266 | skipped += (int)read_string(fd, id3->id3v1buf[3], sizeof(id3->id3v1buf[3]), '\0', len); | ||
267 | rmctx->data_offset = skipped + 8; | ||
268 | rmctx->bit_rate = rmctx->block_align * rmctx->sample_rate / 192; | ||
269 | if (rmctx->block_align) | ||
270 | rmctx->nb_packets = (filesize(fd) - rmctx->data_offset) / rmctx->block_align; | ||
271 | if (rmctx->sample_rate) | ||
272 | rmctx->duration = (uint32_t)(256LL * 6 * 1000 * rmctx->nb_packets / rmctx->sample_rate); | ||
273 | rmctx->flags |= RM_RAW_DATASTREAM; | ||
274 | |||
275 | DEBUGF(" data_offset = %ld\n",rmctx->data_offset); | ||
276 | DEBUGF(" avg_bitrate = %ld\n",rmctx->bit_rate); | ||
277 | DEBUGF(" duration = %ld\n",rmctx->duration); | ||
278 | DEBUGF(" title=\"%s\"\n",id3->id3v1buf[0]); | ||
279 | DEBUGF(" author=\"%s\"\n",id3->id3v1buf[1]); | ||
280 | DEBUGF(" copyright=\"%s\"\n",id3->id3v1buf[2]); | ||
281 | DEBUGF(" comment=\"%s\"\n",id3->id3v1buf[3]); | ||
282 | return 0; | ||
283 | } | ||
253 | /* Very old .ra format - not yet supported */ | 284 | /* Very old .ra format - not yet supported */ |
254 | return -1; | 285 | return -1; |
255 | } | 286 | } |
@@ -305,6 +336,8 @@ static int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3) | |||
305 | DEBUGF(" data_offset = %ld\n",rmctx->data_offset); | 336 | DEBUGF(" data_offset = %ld\n",rmctx->data_offset); |
306 | DEBUGF(" num_streams = %d\n",num_streams); | 337 | DEBUGF(" num_streams = %d\n",num_streams); |
307 | DEBUGF(" flags=0x%04x\n",rmctx->flags); | 338 | DEBUGF(" flags=0x%04x\n",rmctx->flags); |
339 | |||
340 | rmctx->flags &= 0x00FF; | ||
308 | break; | 341 | break; |
309 | 342 | ||
310 | case FOURCC('C','O','N','T'): | 343 | case FOURCC('C','O','N','T'): |
@@ -409,7 +442,22 @@ static int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3) | |||
409 | 442 | ||
410 | DEBUGF(" data_nb_packets = %ld\n",rmctx->nb_packets); | 443 | DEBUGF(" data_nb_packets = %ld\n",rmctx->nb_packets); |
411 | DEBUGF(" next DATA offset = %ld\n",next_data_off); | 444 | DEBUGF(" next DATA offset = %ld\n",next_data_off); |
412 | header_end = 1; | 445 | |
446 | if (!next_data_off) | ||
447 | { | ||
448 | if (rmctx->duration == 0 && rmctx->bit_rate != 0) | ||
449 | { | ||
450 | rmctx->duration = (uint32_t)(8000LL * rmctx->nb_packets * rmctx->block_align / rmctx->bit_rate); | ||
451 | DEBUGF(" estimated duration = %ld\n",rmctx->duration); | ||
452 | } | ||
453 | read_uint16be(fd, &pkt_version); | ||
454 | skipped += 2; | ||
455 | DEBUGF(" pkt_version=0x%04x\n", pkt_version); | ||
456 | if (pkt_version) | ||
457 | rmctx->flags |= RM_PKT_V1; | ||
458 | rmctx->data_offset = curpos; | ||
459 | header_end = 1; | ||
460 | } | ||
413 | break; | 461 | break; |
414 | } | 462 | } |
415 | if(header_end) break; | 463 | if(header_end) break; |
@@ -456,7 +504,7 @@ bool get_rm_metadata(int fd, struct mp3entry* id3) | |||
456 | 504 | ||
457 | id3->channels = rmctx->nb_channels; | 505 | id3->channels = rmctx->nb_channels; |
458 | id3->extradata_size = rmctx->extradata_size; | 506 | id3->extradata_size = rmctx->extradata_size; |
459 | id3->bitrate = rmctx->bit_rate / 1000; | 507 | id3->bitrate = (rmctx->bit_rate + 500) / 1000; |
460 | id3->frequency = rmctx->sample_rate; | 508 | id3->frequency = rmctx->sample_rate; |
461 | id3->length = rmctx->duration; | 509 | id3->length = rmctx->duration; |
462 | id3->filesize = filesize(fd); | 510 | id3->filesize = filesize(fd); |