2 Copyright (c) 2012, Broadcom Europe Ltd
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.
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.
31 #include "containers/containers.h"
32 #include "containers/core/containers_common.h"
33 #include "containers/core/containers_utils.h"
35 /******************************************************************************
37 ******************************************************************************/
38 #define BITMAPINFOHEADER_SIZE_MAX 40
39 #define MAX_EXTENSION_SIZE 4
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)
45 /*****************************************************************************/
46 typedef struct VC_CONTAINER_ES_FORMAT_PRIVATE_T
48 VC_CONTAINER_ES_FORMAT_T format;
49 VC_CONTAINER_ES_SPECIFIC_FORMAT_T type;
53 unsigned int extradata_size;
56 uint8_t buffer[EXTRADATA_SIZE_DEFAULT];
58 } VC_CONTAINER_ES_FORMAT_PRIVATE_T;
60 /*****************************************************************************/
61 VC_CONTAINER_ES_FORMAT_T *vc_container_format_create(unsigned int extradata_size)
63 VC_CONTAINER_ES_FORMAT_PRIVATE_T *private;
64 VC_CONTAINER_STATUS_T status;
66 private = malloc(sizeof(*private));
67 if(!private) return 0;
68 memset(private, 0, sizeof(*private));
70 private->magic = VC_CONTAINER_ES_FORMAT_MAGIC;
71 private->format.type = (void *)&private->type;
72 private->extradata_size = EXTRADATA_SIZE_DEFAULT;
74 status = vc_container_format_extradata_alloc(&private->format, extradata_size);
75 if(status != VC_CONTAINER_SUCCESS)
81 return &private->format;
84 /*****************************************************************************/
85 void vc_container_format_delete(VC_CONTAINER_ES_FORMAT_T *format)
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);
93 /*****************************************************************************/
94 VC_CONTAINER_STATUS_T vc_container_format_extradata_alloc(
95 VC_CONTAINER_ES_FORMAT_T *format, unsigned int size)
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);
100 /* Sanity check the size requested */
101 if(size > EXTRADATA_SIZE_MAX)
102 return VC_CONTAINER_ERROR_CORRUPTED;
104 /* Allocate memory if needed */
105 if(private->extradata_size < size)
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;
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;
118 return VC_CONTAINER_SUCCESS;
121 /*****************************************************************************/
122 VC_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)
126 void *type = p_out->type;
127 uint8_t *extradata = p_out->extradata;
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;
134 *p_out->type = *p_in->type;
137 p_out->extradata = extradata;
138 if(p_in->extradata_size)
139 memcpy(p_out->extradata, p_in->extradata, p_in->extradata_size);
141 return VC_CONTAINER_SUCCESS;
144 /*****************************************************************************/
145 int utf8_from_charset(const char *charset, char *out, unsigned int out_size,
146 const void *in, unsigned int in_size)
149 const uint16_t *in16 = (const uint16_t *)in;
150 const uint8_t *in8 = (const uint8_t *)in;
152 if(out_size < 1) return 1;
153 if(!strcmp(charset, "UTF16-LE")) goto utf16le;
154 if(!strcmp(charset, "UTF8")) goto utf8;
158 for(i = 0; i < in_size / 2 && in16[i] && i < out_size - 1; i++)
166 for(i = 0; i < in_size && in8[i] && i < out_size - 1; i++)
174 /*****************************************************************************/
175 unsigned int vc_container_es_format_to_waveformatex(VC_CONTAINER_ES_FORMAT_T *format,
176 uint8_t *buffer, unsigned int buffer_size)
178 uint16_t waveformat = codec_to_waveformat(format->codec);
180 if(format->es_type != VC_CONTAINER_ES_TYPE_AUDIO ||
181 waveformat == WAVE_FORMAT_UNKNOWN) return 0;
183 if(!buffer) return format->extradata_size + 18;
185 if(buffer_size < format->extradata_size + 18) return 0;
187 /* Build a waveformatex header */
188 buffer[0] = waveformat;
189 buffer[1] = waveformat >> 8;
190 buffer[2] = format->type->audio.channels;
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;
210 /*****************************************************************************/
211 VC_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)
215 VC_CONTAINER_FOURCC_T fourcc;
216 uint32_t waveformat_id;
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);
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];
231 if(waveformat_id == WAVE_FORMAT_PCM && format->type->audio.bits_per_sample == 8)
232 fourcc = VC_CONTAINER_CODEC_PCM_UNSIGNED_LE;
234 if(buffer_size >= 18)
238 *extra_size = (p[17] << 8) | p[16];
239 if(*extra_size + 18 > buffer_size) *extra_size = buffer_size - 18;
241 if(extra_offset) *extra_offset = 18;
244 /* Skip the MPEGLAYER3WAVEFORMAT structure */
245 if(waveformat_id == WAVE_FORMAT_MPEGLAYER3 && extra_size)
247 if(extra_offset) *extra_offset += *extra_size;
251 format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
252 format->codec = fourcc;
254 return VC_CONTAINER_SUCCESS;
257 /*****************************************************************************/
258 unsigned int vc_container_es_format_to_bitmapinfoheader(VC_CONTAINER_ES_FORMAT_T *format,
259 uint8_t *buffer, unsigned int buffer_size)
261 uint32_t fourcc = codec_to_vfw_fourcc(format->codec);
262 uint32_t size = BITMAPINFOHEADER_SIZE_MAX + format->extradata_size;
264 if(format->es_type != VC_CONTAINER_ES_TYPE_VIDEO ||
265 fourcc == VC_CONTAINER_CODEC_UNKNOWN) return 0;
267 if(!buffer) return size;
268 if(buffer_size < size) return 0;
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);
289 /*****************************************************************************/
290 VC_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)
294 VC_CONTAINER_FOURCC_T fourcc;
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);
302 format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
303 format->codec = vfw_fourcc_to_codec(fourcc);
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;
309 if(extra_offset) *extra_offset = BITMAPINFOHEADER_SIZE_MAX;
312 if (buffer_size > BITMAPINFOHEADER_SIZE_MAX)
313 *extra_size = buffer_size - BITMAPINFOHEADER_SIZE_MAX;
318 return VC_CONTAINER_SUCCESS;
321 /*****************************************************************************/
323 VC_CONTAINER_METADATA_KEY_T key;
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} };
336 /*****************************************************************************/
337 const char *vc_container_metadata_id_to_string(VC_CONTAINER_METADATA_KEY_T key)
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;
345 /*****************************************************************************/
346 int64_t vc_container_maths_gcd(int64_t a, int64_t b)
357 /*****************************************************************************/
358 void vc_container_maths_rational_simplify(uint32_t *num, uint32_t *den)
360 int64_t div = vc_container_maths_gcd((int64_t)*num, (int64_t)*den);