1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the following conditions are met: |
7 | * Redistributions of source code must retain the above copyright |
8 | notice, this list of conditions and the following disclaimer. |
9 | * Redistributions in binary form must reproduce the above copyright |
10 | notice, this list of conditions and the following disclaimer in the |
11 | documentation and/or other materials provided with the distribution. |
12 | * Neither the name of the copyright holder nor the |
13 | names of its contributors may be used to endorse or promote products |
14 | derived from this software without specific prior written permission. |
15 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | #include <stdlib.h> |
28 | #include <string.h> |
29 | |
30 | #include "containers/core/containers_private.h" |
31 | #include "containers/core/containers_io_helpers.h" |
32 | #include "containers/core/containers_utils.h" |
33 | #include "containers/core/containers_logging.h" |
34 | |
35 | /****************************************************************************** |
36 | Defines. |
37 | ******************************************************************************/ |
38 | |
39 | #define BI32(b) (((b)[0]<<24)|((b)[1]<<16)|((b)[2]<<8)|((b)[3])) |
40 | #define BI16(b) (((b)[0]<<8)|((b)[1])) |
41 | |
42 | #define 14 |
43 | #define MAX_TRACKS 128 |
44 | |
45 | /****************************************************************************** |
46 | Type definitions |
47 | ******************************************************************************/ |
48 | struct _QSYNTH_SEGMENT_T { |
49 | struct _QSYNTH_SEGMENT_T *next; |
50 | uint32_t len; |
51 | uint8_t *data; |
52 | }; |
53 | typedef struct _QSYNTH_SEGMENT_T QSYNTH_SEGMENT_T; |
54 | |
55 | typedef struct VC_CONTAINER_MODULE_T |
56 | { |
57 | VC_CONTAINER_TRACK_T *track; |
58 | uint32_t filesize; |
59 | QSYNTH_SEGMENT_T *seg; |
60 | QSYNTH_SEGMENT_T *pass; |
61 | uint32_t sent; |
62 | int64_t timestamp; |
63 | uint32_t seek; |
64 | } VC_CONTAINER_MODULE_T; |
65 | |
66 | /****************************************************************************** |
67 | Function prototypes |
68 | ******************************************************************************/ |
69 | VC_CONTAINER_STATUS_T qsynth_reader_open( VC_CONTAINER_T * ); |
70 | |
71 | /****************************************************************************** |
72 | Local Functions |
73 | ******************************************************************************/ |
74 | |
75 | static VC_CONTAINER_STATUS_T (uint8_t *data, uint32_t *tracks, |
76 | uint32_t *division, uint8_t *fps, uint8_t *dpf) |
77 | { |
78 | if(data[0] != 'M' || data[1] != 'T' || data[2] != 'h' || data[3] != 'd' || |
79 | data[4] != 0 || data[5] != 0 || data[6] != 0 || data[7] != 6) |
80 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
81 | |
82 | if(data[12] < 0x80) |
83 | { |
84 | if(division) *division = BI16(data+12); |
85 | } |
86 | else |
87 | { |
88 | if(fps) *fps = 256-data[12]; |
89 | if(dpf) *dpf = data[13]; |
90 | } |
91 | |
92 | if(tracks) *tracks = BI16(data+10); |
93 | |
94 | return VC_CONTAINER_SUCCESS; |
95 | } |
96 | |
97 | static int qsynth_read_variable(uint8_t *data, uint32_t *val) |
98 | { |
99 | int i = 0; |
100 | *val = 0; |
101 | do { |
102 | *val = (*val << 7) + (data[i] & 0x7f); |
103 | } while(data[i++] & 0x80); |
104 | |
105 | return i; |
106 | } |
107 | |
108 | static VC_CONTAINER_STATUS_T qsynth_read_event(uint8_t *data, uint32_t *used, uint8_t *last, |
109 | uint32_t *time, uint32_t *tempo, uint32_t *end) |
110 | { |
111 | int read; |
112 | |
113 | // need at least 4 bytes here |
114 | read = qsynth_read_variable(data, time); |
115 | |
116 | if(data[read] == 0xff) // meta event |
117 | { |
118 | uint32_t len; |
119 | uint8_t type = data[read+1]; |
120 | |
121 | read += 2; |
122 | read += qsynth_read_variable(data+read, &len); |
123 | |
124 | if(type == 0x2f) // end of track |
125 | { |
126 | if(len != 0) |
127 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
128 | |
129 | *end = 1; |
130 | } |
131 | else if(type == 0x51) // tempo event |
132 | { |
133 | if(len != 3) |
134 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
135 | |
136 | *tempo = (data[read]<<16) | (data[read+1]<<8) | data[read+2]; |
137 | } |
138 | |
139 | read += len; |
140 | } |
141 | else if(data[read] == 0xf0 || data[read] == 0xf7) // sysex events |
142 | { |
143 | uint32_t len; |
144 | read += 1; |
145 | read += qsynth_read_variable(data+read, &len) + len; |
146 | } |
147 | else // midi event |
148 | { |
149 | uint8_t type; |
150 | |
151 | if(data[read] < 128) |
152 | type = *last; |
153 | else |
154 | { |
155 | type = data[read] >> 4; |
156 | *last = type; |
157 | read++; |
158 | } |
159 | |
160 | switch(type) { |
161 | case 8: case 9: case 0xa: case 0xb: case 0xe: |
162 | read += 2; |
163 | break; |
164 | case 0xc: case 0xd: |
165 | read += 1; |
166 | break; |
167 | default: |
168 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
169 | } |
170 | } |
171 | |
172 | *used = read; |
173 | return VC_CONTAINER_SUCCESS; |
174 | } |
175 | |
176 | static VC_CONTAINER_STATUS_T qsynth_read_track(QSYNTH_SEGMENT_T *seg, |
177 | uint32_t *ticks, int64_t *time, |
178 | uint32_t *us_perclock, uint32_t *tempo_ticks) |
179 | { |
180 | uint32_t total_ticks = 0; |
181 | uint32_t used = 8; |
182 | uint8_t last = 0; |
183 | |
184 | *time = 0LL; |
185 | *tempo_ticks = 0; |
186 | |
187 | while(used < seg->len) |
188 | { |
189 | VC_CONTAINER_STATUS_T status; |
190 | uint32_t event_ticks, new_tempo = 0, end = 0, event_used; |
191 | if((status = qsynth_read_event(seg->data+used, &event_used, &last, &event_ticks, &new_tempo, &end)) != VC_CONTAINER_SUCCESS) |
192 | return status; |
193 | |
194 | used += event_used; |
195 | total_ticks += event_ticks; |
196 | |
197 | if(new_tempo != 0) |
198 | { |
199 | *time += ((int64_t) (total_ticks - *tempo_ticks)) * (*us_perclock); |
200 | *us_perclock = new_tempo; |
201 | *tempo_ticks = total_ticks; |
202 | } |
203 | |
204 | if(end) |
205 | break; |
206 | } |
207 | |
208 | *ticks = total_ticks; |
209 | return VC_CONTAINER_SUCCESS; |
210 | } |
211 | |
212 | static VC_CONTAINER_STATUS_T qsynth_get_duration(VC_CONTAINER_T *p_ctx) |
213 | { |
214 | VC_CONTAINER_MODULE_T *module = p_ctx->priv->module; |
215 | VC_CONTAINER_STATUS_T status; |
216 | QSYNTH_SEGMENT_T **seg = &(module->seg); |
217 | uint32_t i, tracks, division = 0, max_ticks = 0, us_perclock = 500000; |
218 | uint32_t end_uspc = 0, end_ticks = 0; |
219 | int64_t end_time = 0; |
220 | uint8_t fps = 1, dpf = 1; |
221 | |
222 | if((*seg = malloc(sizeof(QSYNTH_SEGMENT_T) + HEADER_LENGTH)) == NULL) |
223 | return VC_CONTAINER_ERROR_OUT_OF_MEMORY; |
224 | |
225 | (*seg)->next = NULL; |
226 | (*seg)->len = HEADER_LENGTH; |
227 | (*seg)->data = (uint8_t *) ((*seg) + 1); |
228 | |
229 | if(PEEK_BYTES(p_ctx, (*seg)->data, HEADER_LENGTH) != HEADER_LENGTH) |
230 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
231 | |
232 | if((status = qsynth_read_header((*seg)->data, &tracks, &division, &fps, &dpf)) != VC_CONTAINER_SUCCESS) |
233 | return status; |
234 | |
235 | // if we have a suspiciously large number of tracks, this is probably a bad file |
236 | if(tracks > MAX_TRACKS) |
237 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
238 | |
239 | SKIP_BYTES(p_ctx, HEADER_LENGTH); |
240 | |
241 | seg = &((*seg)->next); |
242 | module->filesize = HEADER_LENGTH; |
243 | |
244 | if(division == 0) |
245 | { |
246 | us_perclock = 1000000 / (fps * dpf); |
247 | division = 1; |
248 | } |
249 | |
250 | for(i=0; i<tracks; i++) |
251 | { |
252 | uint32_t len, ticks, tempo_ticks; |
253 | int64_t time; |
254 | uint8_t dummy[8]; |
255 | |
256 | if(READ_BYTES(p_ctx, dummy, sizeof(dummy)) != sizeof(dummy) || |
257 | dummy[0] != 'M' || dummy[1] != 'T' || dummy[2] != 'r' || dummy[3] != 'k') |
258 | return VC_CONTAINER_ERROR_FORMAT_INVALID; |
259 | |
260 | len = BI32(dummy+4); |
261 | |
262 | // impose a 1mb limit on track size |
263 | if(len > (1<<20) || (*seg = malloc(sizeof(QSYNTH_SEGMENT_T) + 8 + len)) == NULL) |
264 | return VC_CONTAINER_ERROR_OUT_OF_MEMORY; |
265 | |
266 | module->filesize += len+8; |
267 | (*seg)->next = NULL; |
268 | (*seg)->len = len + 8; |
269 | (*seg)->data = (uint8_t *) ((*seg) + 1); |
270 | |
271 | memcpy((*seg)->data, dummy, 8); |
272 | if(READ_BYTES(p_ctx, (*seg)->data+8, len) != len) |
273 | return VC_CONTAINER_ERROR_FORMAT_INVALID; |
274 | |
275 | if((status = qsynth_read_track(*seg, &ticks, &time, &us_perclock, &tempo_ticks)) != VC_CONTAINER_SUCCESS) |
276 | return status; |
277 | |
278 | if(end_uspc == 0) |
279 | { |
280 | end_uspc = us_perclock; |
281 | end_ticks = tempo_ticks; |
282 | end_time = time; |
283 | } |
284 | |
285 | if(ticks > max_ticks) |
286 | max_ticks = ticks; |
287 | |
288 | seg = &((*seg)->next); |
289 | } |
290 | |
291 | if(end_uspc == 0) |
292 | return VC_CONTAINER_ERROR_FORMAT_INVALID; |
293 | |
294 | module->pass = module->seg; |
295 | module->sent = 0; |
296 | p_ctx->duration = (end_time + (((int64_t) (max_ticks - end_ticks)) * end_uspc)) / division; |
297 | module->track->format->extradata = (uint8_t *) &module->filesize; |
298 | module->track->format->extradata_size = 4; |
299 | return VC_CONTAINER_SUCCESS; |
300 | } |
301 | |
302 | |
303 | /***************************************************************************** |
304 | Functions exported as part of the Container Module API |
305 | *****************************************************************************/ |
306 | static VC_CONTAINER_STATUS_T qsynth_reader_read( VC_CONTAINER_T *p_ctx, |
307 | VC_CONTAINER_PACKET_T *packet, |
308 | uint32_t flags ) |
309 | { |
310 | VC_CONTAINER_MODULE_T *module = p_ctx->priv->module; |
311 | |
312 | if(module->pass) |
313 | { |
314 | packet->size = module->pass->len - module->sent; |
315 | packet->dts = packet->pts = 0; |
316 | packet->track = 0; |
317 | packet->flags = module->sent ? 0 : VC_CONTAINER_PACKET_FLAG_FRAME_START; |
318 | } |
319 | else |
320 | { |
321 | if(module->timestamp > p_ctx->duration) |
322 | return VC_CONTAINER_ERROR_EOS; |
323 | |
324 | packet->size = 5; |
325 | packet->dts = packet->pts = module->timestamp; |
326 | packet->track = 0; |
327 | packet->flags = VC_CONTAINER_PACKET_FLAG_FRAME; |
328 | } |
329 | |
330 | if(flags & VC_CONTAINER_READ_FLAG_SKIP) |
331 | { |
332 | if(module->pass) |
333 | { |
334 | module->pass = module->pass->next; |
335 | module->sent = 0; |
336 | } |
337 | else |
338 | { |
339 | // if we're playing then we can't really skip, but have to simulate a seek instead |
340 | module->seek = 1; |
341 | module->timestamp += 40; |
342 | } |
343 | |
344 | return VC_CONTAINER_SUCCESS; |
345 | } |
346 | |
347 | if(flags & VC_CONTAINER_READ_FLAG_INFO) |
348 | return VC_CONTAINER_SUCCESS; |
349 | |
350 | // read frame into packet->data |
351 | if(module->pass) |
352 | { |
353 | uint32_t copy = MIN(packet->size, packet->buffer_size); |
354 | memcpy(packet->data, module->pass->data + module->sent, copy); |
355 | packet->size = copy; |
356 | |
357 | if((module->sent += copy) == module->pass->len) |
358 | { |
359 | module->pass = module->pass->next; |
360 | module->sent = 0; |
361 | packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END; |
362 | } |
363 | } |
364 | else |
365 | { |
366 | if(packet->buffer_size < packet->size) |
367 | return VC_CONTAINER_ERROR_BUFFER_TOO_SMALL; |
368 | |
369 | if(module->seek) |
370 | { |
371 | uint32_t current_time = module->timestamp / 1000; |
372 | |
373 | packet->data[0] = 'S'; |
374 | packet->data[1] = (uint8_t)((current_time >> 24) & 0xFF); |
375 | packet->data[2] = (uint8_t)((current_time >> 16) & 0xFF); |
376 | packet->data[3] = (uint8_t)((current_time >> 8) & 0xFF); |
377 | packet->data[4] = (uint8_t)((current_time ) & 0xFF); |
378 | module->seek = 0; |
379 | } |
380 | else |
381 | { |
382 | packet->data[0] = 'P'; |
383 | packet->data[1] = 0; |
384 | packet->data[2] = 0; |
385 | packet->data[3] = 0; |
386 | packet->data[4] = 40; |
387 | module->timestamp += 40 * 1000; |
388 | } |
389 | } |
390 | |
391 | return VC_CONTAINER_SUCCESS; |
392 | } |
393 | |
394 | /*****************************************************************************/ |
395 | static VC_CONTAINER_STATUS_T qsynth_reader_seek( VC_CONTAINER_T *p_ctx, |
396 | int64_t *offset, |
397 | VC_CONTAINER_SEEK_MODE_T mode, |
398 | VC_CONTAINER_SEEK_FLAGS_T flags) |
399 | { |
400 | VC_CONTAINER_MODULE_T *module = p_ctx->priv->module; |
401 | VC_CONTAINER_PARAM_UNUSED(flags); |
402 | |
403 | if (mode != VC_CONTAINER_SEEK_MODE_TIME) |
404 | return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION; |
405 | |
406 | if(*offset < 0) |
407 | *offset = 0; |
408 | else if(*offset > p_ctx->duration) |
409 | *offset = p_ctx->duration; |
410 | |
411 | module->timestamp = *offset; |
412 | module->seek = 1; |
413 | |
414 | return VC_CONTAINER_SUCCESS; |
415 | } |
416 | |
417 | /*****************************************************************************/ |
418 | static VC_CONTAINER_STATUS_T qsynth_reader_close( VC_CONTAINER_T *p_ctx ) |
419 | { |
420 | VC_CONTAINER_MODULE_T *module = p_ctx->priv->module; |
421 | QSYNTH_SEGMENT_T *seg = module->seg; |
422 | for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--) |
423 | vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]); |
424 | while(seg != NULL) |
425 | { |
426 | QSYNTH_SEGMENT_T *next = seg->next; |
427 | free(seg); |
428 | seg = next; |
429 | } |
430 | free(module); |
431 | return VC_CONTAINER_SUCCESS; |
432 | } |
433 | |
434 | /*****************************************************************************/ |
435 | VC_CONTAINER_STATUS_T qsynth_reader_open( VC_CONTAINER_T *p_ctx ) |
436 | { |
437 | VC_CONTAINER_MODULE_T *module = 0; |
438 | VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
439 | uint8_t [HEADER_LENGTH]; |
440 | |
441 | /* Check the file header */ |
442 | if((PEEK_BYTES(p_ctx, header, HEADER_LENGTH) != HEADER_LENGTH) || |
443 | qsynth_read_header(header, 0, 0, 0, 0) != VC_CONTAINER_SUCCESS) |
444 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
445 | |
446 | /* Allocate our context */ |
447 | module = malloc(sizeof(*module)); |
448 | if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; } |
449 | memset(module, 0, sizeof(*module)); |
450 | p_ctx->priv->module = module; |
451 | p_ctx->tracks_num = 1; |
452 | p_ctx->tracks = &module->track; |
453 | p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0); |
454 | if(!p_ctx->tracks[0]) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; } |
455 | p_ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO; |
456 | p_ctx->tracks[0]->format->codec = VC_CONTAINER_CODEC_MIDI; |
457 | p_ctx->tracks[0]->is_enabled = true; |
458 | |
459 | if((status = qsynth_get_duration(p_ctx)) != VC_CONTAINER_SUCCESS) goto error; |
460 | |
461 | LOG_DEBUG(p_ctx, "using qsynth reader" ); |
462 | |
463 | p_ctx->capabilities = VC_CONTAINER_CAPS_CAN_SEEK; |
464 | |
465 | p_ctx->priv->pf_close = qsynth_reader_close; |
466 | p_ctx->priv->pf_read = qsynth_reader_read; |
467 | p_ctx->priv->pf_seek = qsynth_reader_seek; |
468 | return VC_CONTAINER_SUCCESS; |
469 | |
470 | error: |
471 | LOG_DEBUG(p_ctx, "qsynth: error opening stream (%i)" , status); |
472 | if(module) qsynth_reader_close(p_ctx); |
473 | return status; |
474 | } |
475 | |
476 | /******************************************************************************** |
477 | Entrypoint function |
478 | ********************************************************************************/ |
479 | |
480 | #if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__) |
481 | # pragma weak reader_open qsynth_reader_open |
482 | #endif |
483 | |