diff options
Diffstat (limited to 'lib/rbcodec/codecs/cook.c')
-rw-r--r-- | lib/rbcodec/codecs/cook.c | 106 |
1 files changed, 68 insertions, 38 deletions
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; |