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 HEADER_LENGTH 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
qsynth_read_header(uint8_t * data,uint32_t * tracks,uint32_t * division,uint8_t * fps,uint8_t * dpf)75 static VC_CONTAINER_STATUS_T qsynth_read_header(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
qsynth_read_variable(uint8_t * data,uint32_t * val)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
qsynth_read_event(uint8_t * data,uint32_t * used,uint8_t * last,uint32_t * time,uint32_t * tempo,uint32_t * end)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
qsynth_read_track(QSYNTH_SEGMENT_T * seg,uint32_t * ticks,int64_t * time,uint32_t * us_perclock,uint32_t * tempo_ticks)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
qsynth_get_duration(VC_CONTAINER_T * p_ctx)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 Functions exported as part of the Container Module API
304 *****************************************************************************/
qsynth_reader_read(VC_CONTAINER_T * p_ctx,VC_CONTAINER_PACKET_T * packet,uint32_t flags)305 static VC_CONTAINER_STATUS_T qsynth_reader_read( VC_CONTAINER_T *p_ctx,
306 VC_CONTAINER_PACKET_T *packet,
307 uint32_t flags )
308 {
309 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
310
311 if(module->pass)
312 {
313 packet->size = module->pass->len - module->sent;
314 packet->dts = packet->pts = 0;
315 packet->track = 0;
316 packet->flags = module->sent ? 0 : VC_CONTAINER_PACKET_FLAG_FRAME_START;
317 }
318 else
319 {
320 if(module->timestamp > p_ctx->duration)
321 return VC_CONTAINER_ERROR_EOS;
322
323 packet->size = 5;
324 packet->dts = packet->pts = module->timestamp;
325 packet->track = 0;
326 packet->flags = VC_CONTAINER_PACKET_FLAG_FRAME;
327 }
328
329 if(flags & VC_CONTAINER_READ_FLAG_SKIP)
330 {
331 if(module->pass)
332 {
333 module->pass = module->pass->next;
334 module->sent = 0;
335 }
336 else
337 {
338 // if we're playing then we can't really skip, but have to simulate a seek instead
339 module->seek = 1;
340 module->timestamp += 40;
341 }
342
343 return VC_CONTAINER_SUCCESS;
344 }
345
346 if(flags & VC_CONTAINER_READ_FLAG_INFO)
347 return VC_CONTAINER_SUCCESS;
348
349 // read frame into packet->data
350 if(module->pass)
351 {
352 uint32_t copy = MIN(packet->size, packet->buffer_size);
353 memcpy(packet->data, module->pass->data + module->sent, copy);
354 packet->size = copy;
355
356 if((module->sent += copy) == module->pass->len)
357 {
358 module->pass = module->pass->next;
359 module->sent = 0;
360 packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
361 }
362 }
363 else
364 {
365 if(packet->buffer_size < packet->size)
366 return VC_CONTAINER_ERROR_BUFFER_TOO_SMALL;
367
368 if(module->seek)
369 {
370 uint32_t current_time = module->timestamp / 1000;
371
372 packet->data[0] = 'S';
373 packet->data[1] = (uint8_t)((current_time >> 24) & 0xFF);
374 packet->data[2] = (uint8_t)((current_time >> 16) & 0xFF);
375 packet->data[3] = (uint8_t)((current_time >> 8) & 0xFF);
376 packet->data[4] = (uint8_t)((current_time ) & 0xFF);
377 module->seek = 0;
378 }
379 else
380 {
381 packet->data[0] = 'P';
382 packet->data[1] = 0;
383 packet->data[2] = 0;
384 packet->data[3] = 0;
385 packet->data[4] = 40;
386 module->timestamp += 40 * 1000;
387 }
388 }
389
390 return VC_CONTAINER_SUCCESS;
391 }
392
393 /*****************************************************************************/
qsynth_reader_seek(VC_CONTAINER_T * p_ctx,int64_t * offset,VC_CONTAINER_SEEK_MODE_T mode,VC_CONTAINER_SEEK_FLAGS_T flags)394 static VC_CONTAINER_STATUS_T qsynth_reader_seek( VC_CONTAINER_T *p_ctx,
395 int64_t *offset,
396 VC_CONTAINER_SEEK_MODE_T mode,
397 VC_CONTAINER_SEEK_FLAGS_T flags)
398 {
399 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
400 VC_CONTAINER_PARAM_UNUSED(flags);
401
402 if (mode != VC_CONTAINER_SEEK_MODE_TIME)
403 return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
404
405 if(*offset < 0)
406 *offset = 0;
407 else if(*offset > p_ctx->duration)
408 *offset = p_ctx->duration;
409
410 module->timestamp = *offset;
411 module->seek = 1;
412
413 return VC_CONTAINER_SUCCESS;
414 }
415
416 /*****************************************************************************/
qsynth_reader_close(VC_CONTAINER_T * p_ctx)417 static VC_CONTAINER_STATUS_T qsynth_reader_close( VC_CONTAINER_T *p_ctx )
418 {
419 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
420 QSYNTH_SEGMENT_T *seg = module->seg;
421 for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
422 vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
423 while(seg != NULL)
424 {
425 QSYNTH_SEGMENT_T *next = seg->next;
426 free(seg);
427 seg = next;
428 }
429 free(module);
430 return VC_CONTAINER_SUCCESS;
431 }
432
433 /*****************************************************************************/
qsynth_reader_open(VC_CONTAINER_T * p_ctx)434 VC_CONTAINER_STATUS_T qsynth_reader_open( VC_CONTAINER_T *p_ctx )
435 {
436 VC_CONTAINER_MODULE_T *module = 0;
437 VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
438 uint8_t header[HEADER_LENGTH];
439
440 /* Check the file header */
441 if((PEEK_BYTES(p_ctx, header, HEADER_LENGTH) != HEADER_LENGTH) ||
442 qsynth_read_header(header, 0, 0, 0, 0) != VC_CONTAINER_SUCCESS)
443 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
444
445 /* Allocate our context */
446 module = malloc(sizeof(*module));
447 if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
448 memset(module, 0, sizeof(*module));
449 p_ctx->priv->module = module;
450 p_ctx->tracks_num = 1;
451 p_ctx->tracks = &module->track;
452 p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
453 if(!p_ctx->tracks[0]) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
454 p_ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
455 p_ctx->tracks[0]->format->codec = VC_CONTAINER_CODEC_MIDI;
456 p_ctx->tracks[0]->is_enabled = true;
457
458 if((status = qsynth_get_duration(p_ctx)) != VC_CONTAINER_SUCCESS) goto error;
459
460 LOG_DEBUG(p_ctx, "using qsynth reader");
461
462 p_ctx->capabilities = VC_CONTAINER_CAPS_CAN_SEEK;
463
464 p_ctx->priv->pf_close = qsynth_reader_close;
465 p_ctx->priv->pf_read = qsynth_reader_read;
466 p_ctx->priv->pf_seek = qsynth_reader_seek;
467 return VC_CONTAINER_SUCCESS;
468
469 error:
470 LOG_DEBUG(p_ctx, "qsynth: error opening stream (%i)", status);
471 if(module) qsynth_reader_close(p_ctx);
472 return status;
473 }
474
475 /********************************************************************************
476 Entrypoint function
477 ********************************************************************************/
478
479 #if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
480 # pragma weak reader_open qsynth_reader_open
481 #endif
482