1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON 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
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include <stdlib.h>
29#include <string.h>
30
31#include "containers/containers.h"
32#include "containers/core/containers_common.h"
33#include "containers/core/containers_utils.h"
34
35/******************************************************************************
36Defines.
37******************************************************************************/
38#define BITMAPINFOHEADER_SIZE_MAX 40
39#define MAX_EXTENSION_SIZE 4
40
41#define VC_CONTAINER_ES_FORMAT_MAGIC ((uint32_t)VC_FOURCC('m','a','g','f'))
42#define EXTRADATA_SIZE_DEFAULT 32
43#define EXTRADATA_SIZE_MAX (10*1024)
44
45/*****************************************************************************/
46typedef struct VC_CONTAINER_ES_FORMAT_PRIVATE_T
47{
48 VC_CONTAINER_ES_FORMAT_T format;
49 VC_CONTAINER_ES_SPECIFIC_FORMAT_T type;
50
51 uint32_t magic;
52
53 unsigned int extradata_size;
54 uint8_t *extradata;
55
56 uint8_t buffer[EXTRADATA_SIZE_DEFAULT];
57
58} VC_CONTAINER_ES_FORMAT_PRIVATE_T;
59
60/*****************************************************************************/
61VC_CONTAINER_ES_FORMAT_T *vc_container_format_create(unsigned int extradata_size)
62{
63 VC_CONTAINER_ES_FORMAT_PRIVATE_T *private;
64 VC_CONTAINER_STATUS_T status;
65
66 private = malloc(sizeof(*private));
67 if(!private) return 0;
68 memset(private, 0, sizeof(*private));
69
70 private->magic = VC_CONTAINER_ES_FORMAT_MAGIC;
71 private->format.type = (void *)&private->type;
72 private->extradata_size = EXTRADATA_SIZE_DEFAULT;
73
74 status = vc_container_format_extradata_alloc(&private->format, extradata_size);
75 if(status != VC_CONTAINER_SUCCESS)
76 {
77 free(private);
78 return NULL;
79 }
80
81 return &private->format;
82}
83
84/*****************************************************************************/
85void vc_container_format_delete(VC_CONTAINER_ES_FORMAT_T *format)
86{
87 VC_CONTAINER_ES_FORMAT_PRIVATE_T *private = (VC_CONTAINER_ES_FORMAT_PRIVATE_T *)format;
88 vc_container_assert(private->magic == VC_CONTAINER_ES_FORMAT_MAGIC);
89 if(private->extradata) free(private->extradata);
90 free(private);
91}
92
93/*****************************************************************************/
94VC_CONTAINER_STATUS_T vc_container_format_extradata_alloc(
95 VC_CONTAINER_ES_FORMAT_T *format, unsigned int size)
96{
97 VC_CONTAINER_ES_FORMAT_PRIVATE_T *private = (VC_CONTAINER_ES_FORMAT_PRIVATE_T *)format;
98 vc_container_assert(private->magic == VC_CONTAINER_ES_FORMAT_MAGIC);
99
100 /* Sanity check the size requested */
101 if(size > EXTRADATA_SIZE_MAX)
102 return VC_CONTAINER_ERROR_CORRUPTED;
103
104 /* Allocate memory if needed */
105 if(private->extradata_size < size)
106 {
107 if(private->extradata) free(private->extradata);
108 private->extradata = malloc(size);
109 if(!private->extradata)
110 return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
111 private->extradata_size = size;
112 }
113
114 /* Set the fields in the actual format structure */
115 if(private->extradata) private->format.extradata = private->extradata;
116 else private->format.extradata = private->buffer;
117
118 return VC_CONTAINER_SUCCESS;
119}
120
121/*****************************************************************************/
122VC_CONTAINER_STATUS_T vc_container_format_copy( VC_CONTAINER_ES_FORMAT_T *p_out,
123 VC_CONTAINER_ES_FORMAT_T *p_in,
124 unsigned int extra_buffer_size)
125{
126 void *type = p_out->type;
127 uint8_t *extradata = p_out->extradata;
128
129 /* Check we have a sufficient buffer to copy the extra data */
130 if(p_in->extradata_size > extra_buffer_size ||
131 (p_in->extradata_size && !p_out->extradata))
132 return VC_CONTAINER_ERROR_BUFFER_TOO_SMALL;
133
134 *p_out->type = *p_in->type;
135 *p_out = *p_in;
136 p_out->type = type;
137 p_out->extradata = extradata;
138 if(p_in->extradata_size)
139 memcpy(p_out->extradata, p_in->extradata, p_in->extradata_size);
140
141 return VC_CONTAINER_SUCCESS;
142}
143
144/*****************************************************************************/
145int utf8_from_charset(const char *charset, char *out, unsigned int out_size,
146 const void *in, unsigned int in_size)
147{
148 unsigned int i;
149 const uint16_t *in16 = (const uint16_t *)in;
150 const uint8_t *in8 = (const uint8_t *)in;
151
152 if(out_size < 1) return 1;
153 if(!strcmp(charset, "UTF16-LE")) goto utf16le;
154 if(!strcmp(charset, "UTF8")) goto utf8;
155 else return 1;
156
157 utf16le:
158 for(i = 0; i < in_size / 2 && in16[i] && i < out_size - 1; i++)
159 {
160 out[i] = in16[i];
161 }
162 out[i] = 0;
163 return 0;
164
165 utf8:
166 for(i = 0; i < in_size && in8[i] && i < out_size - 1; i++)
167 {
168 out[i] = in8[i];
169 }
170 out[i] = 0;
171 return 0;
172}
173
174/*****************************************************************************/
175unsigned int vc_container_es_format_to_waveformatex(VC_CONTAINER_ES_FORMAT_T *format,
176 uint8_t *buffer, unsigned int buffer_size)
177{
178 uint16_t waveformat = codec_to_waveformat(format->codec);
179
180 if(format->es_type != VC_CONTAINER_ES_TYPE_AUDIO ||
181 waveformat == WAVE_FORMAT_UNKNOWN) return 0;
182
183 if(!buffer) return format->extradata_size + 18;
184
185 if(buffer_size < format->extradata_size + 18) return 0;
186
187 /* Build a waveformatex header */
188 buffer[0] = waveformat;
189 buffer[1] = waveformat >> 8;
190 buffer[2] = format->type->audio.channels;
191 buffer[3] = 0;
192 buffer[4] = (format->type->audio.sample_rate >> 0) & 0xFF;
193 buffer[5] = (format->type->audio.sample_rate >> 8) & 0xFF;
194 buffer[6] = (format->type->audio.sample_rate >> 16) & 0xFF;
195 buffer[7] = (format->type->audio.sample_rate >> 24) & 0xFF;
196 buffer[8] = (format->bitrate >> 3) & 0xFF;
197 buffer[9] = (format->bitrate >> 11) & 0xFF;
198 buffer[10] = (format->bitrate >> 19) & 0xFF;
199 buffer[11] = (format->bitrate >> 27) & 0xFF;
200 buffer[12] = (format->type->audio.block_align >> 0) & 0xFF;
201 buffer[13] = (format->type->audio.block_align >> 8) & 0xFF;
202 buffer[14] = (format->type->audio.bits_per_sample >> 0) & 0xFF;
203 buffer[15] = (format->type->audio.bits_per_sample >> 8) & 0xFF;
204 buffer[16] = (format->extradata_size >> 0) & 0xFF;
205 buffer[17] = (format->extradata_size >> 8) & 0xFF;
206 memcpy(buffer+18, format->extradata, format->extradata_size);
207 return format->extradata_size + 18;
208}
209
210/*****************************************************************************/
211VC_CONTAINER_STATUS_T vc_container_waveformatex_to_es_format(uint8_t *p,
212 unsigned int buffer_size, unsigned int *extra_offset, unsigned int *extra_size,
213 VC_CONTAINER_ES_FORMAT_T *format)
214{
215 VC_CONTAINER_FOURCC_T fourcc;
216 uint32_t waveformat_id;
217
218 if(!p || buffer_size < 16) return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
219 waveformat_id = (p[1] << 8) | p[0];
220 fourcc = waveformat_to_codec(waveformat_id);
221
222 /* Read the waveformatex header */
223 if(extra_offset) *extra_offset = 16;
224 if(extra_size) *extra_size = 0;
225 format->type->audio.channels = p[2];
226 format->type->audio.sample_rate = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
227 format->bitrate = ((p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]) * 8;
228 format->type->audio.block_align = (p[13] << 8) | p[12];
229 format->type->audio.bits_per_sample = (p[15] << 8) | p[14];
230
231 if(waveformat_id == WAVE_FORMAT_PCM && format->type->audio.bits_per_sample == 8)
232 fourcc = VC_CONTAINER_CODEC_PCM_UNSIGNED_LE;
233
234 if(buffer_size >= 18)
235 {
236 if(extra_size)
237 {
238 *extra_size = (p[17] << 8) | p[16];
239 if(*extra_size + 18 > buffer_size) *extra_size = buffer_size - 18;
240 }
241 if(extra_offset) *extra_offset = 18;
242 }
243
244 /* Skip the MPEGLAYER3WAVEFORMAT structure */
245 if(waveformat_id == WAVE_FORMAT_MPEGLAYER3 && extra_size)
246 {
247 if(extra_offset) *extra_offset += *extra_size;
248 *extra_size = 0;
249 }
250
251 format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
252 format->codec = fourcc;
253
254 return VC_CONTAINER_SUCCESS;
255}
256
257/*****************************************************************************/
258unsigned int vc_container_es_format_to_bitmapinfoheader(VC_CONTAINER_ES_FORMAT_T *format,
259 uint8_t *buffer, unsigned int buffer_size)
260{
261 uint32_t fourcc = codec_to_vfw_fourcc(format->codec);
262 uint32_t size = BITMAPINFOHEADER_SIZE_MAX + format->extradata_size;
263
264 if(format->es_type != VC_CONTAINER_ES_TYPE_VIDEO ||
265 fourcc == VC_CONTAINER_CODEC_UNKNOWN) return 0;
266
267 if(!buffer) return size;
268 if(buffer_size < size) return 0;
269
270 /* Build a bitmapinfoheader header */
271 memset(buffer, 0, BITMAPINFOHEADER_SIZE_MAX);
272 buffer[0] = (size >> 0) & 0xFF;
273 buffer[1] = (size >> 8) & 0xFF;
274 buffer[2] = (size >> 16) & 0xFF;
275 buffer[3] = (size >> 24) & 0xFF;
276 buffer[4] = (format->type->video.width >> 0) & 0xFF;
277 buffer[5] = (format->type->video.width >> 8) & 0xFF;
278 buffer[6] = (format->type->video.width >> 16) & 0xFF;
279 buffer[7] = (format->type->video.width >> 24) & 0xFF;
280 buffer[8] = (format->type->video.height >> 0) & 0xFF;
281 buffer[9] = (format->type->video.height >> 8) & 0xFF;
282 buffer[10] = (format->type->video.height >> 16) & 0xFF;
283 buffer[11] = (format->type->video.height >> 24) & 0xFF;
284 memcpy(buffer + 16, &fourcc, 4);
285 memcpy(buffer + BITMAPINFOHEADER_SIZE_MAX, format->extradata, format->extradata_size);
286 return size;
287}
288
289/*****************************************************************************/
290VC_CONTAINER_STATUS_T vc_container_bitmapinfoheader_to_es_format(uint8_t *p,
291 unsigned int buffer_size, unsigned int *extra_offset, unsigned int *extra_size,
292 VC_CONTAINER_ES_FORMAT_T *format)
293{
294 VC_CONTAINER_FOURCC_T fourcc;
295
296 if(!p || buffer_size < BITMAPINFOHEADER_SIZE_MAX) return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
297 /* size = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; */
298 format->type->video.width = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
299 format->type->video.height = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
300 memcpy(&fourcc, p + 16, 4);
301
302 format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
303 format->codec = vfw_fourcc_to_codec(fourcc);
304
305 /* If no mapping is found from vfw, try a more generic one */
306 if (format->codec == fourcc && (fourcc = fourcc_to_codec(fourcc)) != VC_CONTAINER_CODEC_UNKNOWN)
307 format->codec = fourcc;
308
309 if(extra_offset) *extra_offset = BITMAPINFOHEADER_SIZE_MAX;
310 if(extra_size)
311 {
312 if (buffer_size > BITMAPINFOHEADER_SIZE_MAX)
313 *extra_size = buffer_size - BITMAPINFOHEADER_SIZE_MAX;
314 else
315 *extra_size = 0;
316 }
317
318 return VC_CONTAINER_SUCCESS;
319}
320
321/*****************************************************************************/
322static struct {
323 VC_CONTAINER_METADATA_KEY_T key;
324 const char *name;
325} meta_key_conv[] =
326{ {VC_CONTAINER_METADATA_KEY_TITLE, "title"},
327 {VC_CONTAINER_METADATA_KEY_ARTIST, "artist"},
328 {VC_CONTAINER_METADATA_KEY_ALBUM, "album"},
329 {VC_CONTAINER_METADATA_KEY_DESCRIPTION, "description"},
330 {VC_CONTAINER_METADATA_KEY_YEAR, "year"},
331 {VC_CONTAINER_METADATA_KEY_GENRE, "genre"},
332 {VC_CONTAINER_METADATA_KEY_TRACK, "track"},
333 {VC_CONTAINER_METADATA_KEY_LYRICS, "lyrics"},
334 {VC_CONTAINER_METADATA_KEY_UNKNOWN, 0} };
335
336/*****************************************************************************/
337const char *vc_container_metadata_id_to_string(VC_CONTAINER_METADATA_KEY_T key)
338{
339 int i;
340 for(i = 0; meta_key_conv[i].key != VC_CONTAINER_METADATA_KEY_UNKNOWN; i++ )
341 if(meta_key_conv[i].key == key) break;
342 return meta_key_conv[i].name;
343}
344
345/*****************************************************************************/
346int64_t vc_container_maths_gcd(int64_t a, int64_t b)
347{
348 while(b != 0)
349 {
350 int64_t t = b;
351 b = a % b;
352 a = t;
353 }
354 return a;
355}
356
357/*****************************************************************************/
358void vc_container_maths_rational_simplify(uint32_t *num, uint32_t *den)
359{
360 int64_t div = vc_container_maths_gcd((int64_t)*num, (int64_t)*den);
361 if(div)
362 {
363 *num /= div;
364 *den /= div;
365 }
366}
367