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