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/core/containers_private.h"
32#include "containers/core/containers_io.h"
33#include "containers/core/containers_filters.h"
34#include "containers/core/containers_loader.h"
35#include "containers/core/containers_logging.h"
36#include "containers/core/containers_utils.h"
37
38#define WRITER_SPACE_SAFETY_MARGIN (10*1024)
39#define PACKETIZER_BUFFER_SIZE (32*1024)
40
41/*****************************************************************************/
42VC_CONTAINER_T *vc_container_open_reader_with_io( struct VC_CONTAINER_IO_T *io,
43 const char *uri, VC_CONTAINER_STATUS_T *p_status,
44 VC_CONTAINER_PROGRESS_REPORT_FUNC_T pfn_progress, void *progress_userdata)
45{
46 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
47 VC_CONTAINER_T *p_ctx = 0;
48 const char *extension;
49
50 VC_CONTAINER_PARAM_UNUSED(pfn_progress);
51 VC_CONTAINER_PARAM_UNUSED(progress_userdata);
52 VC_CONTAINER_PARAM_UNUSED(uri);
53
54 /* Sanity check the i/o */
55 if (!io || !io->pf_read || !io->pf_seek)
56 {
57 LOG_ERROR(0, "invalid i/o instance: %p", io);
58 status = VC_CONTAINER_ERROR_INVALID_ARGUMENT;
59 goto error;
60 }
61
62 /* Allocate our context before trying out the different readers / writers */
63 p_ctx = malloc( sizeof(*p_ctx) + sizeof(*p_ctx->priv) + sizeof(*p_ctx->drm));
64 if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
65 memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*p_ctx->priv) + sizeof(*p_ctx->drm));
66 p_ctx->priv = (VC_CONTAINER_PRIVATE_T *)(p_ctx + 1);
67 p_ctx->priv->verbosity = vc_container_log_get_default_verbosity();
68 p_ctx->drm = (VC_CONTAINER_DRM_T *)(p_ctx->priv + 1);
69 p_ctx->size = io->size;
70 p_ctx->priv->io = io;
71 p_ctx->priv->uri = io->uri_parts;
72
73 /* If the uri has an extension, use it as a hint when loading the container */
74 extension = vc_uri_path_extension(p_ctx->priv->uri);
75 /* If the user has specified a container, then use that instead */
76 vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
77
78 status = vc_container_load_reader(p_ctx, extension);
79 if (status != VC_CONTAINER_SUCCESS)
80 goto error;
81
82 p_ctx->priv->drm_filter = vc_container_filter_open(VC_FOURCC('d','r','m',' '),
83 VC_FOURCC('u','n','k','n'), p_ctx, &status);
84 if (status != VC_CONTAINER_SUCCESS)
85 {
86 /* Some other problem occurred aside from the filter not being appropriate or
87 the stream not needing it. */
88 if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
89
90 /* Report no DRM and continue as normal */
91 p_ctx->drm = NULL;
92 status = VC_CONTAINER_SUCCESS;
93 }
94
95end:
96 if(p_status) *p_status = status;
97 return p_ctx;
98
99error:
100 if (p_ctx)
101 {
102 p_ctx->priv->io = NULL; /* The i/o doesn't belong to us */
103 vc_container_close(p_ctx);
104 p_ctx = NULL;
105 }
106 goto end;
107}
108
109/*****************************************************************************/
110VC_CONTAINER_T *vc_container_open_reader( const char *uri, VC_CONTAINER_STATUS_T *p_status,
111 VC_CONTAINER_PROGRESS_REPORT_FUNC_T pfn_progress, void *progress_userdata)
112{
113 VC_CONTAINER_IO_T *io;
114 VC_CONTAINER_T *ctx;
115
116 /* Start by opening the URI */
117 io = vc_container_io_open( uri, VC_CONTAINER_IO_MODE_READ, p_status );
118 if (!io)
119 return 0;
120
121 ctx = vc_container_open_reader_with_io( io, uri, p_status, pfn_progress, progress_userdata);
122 if (!ctx)
123 vc_container_io_close(io);
124 return ctx;
125}
126
127/*****************************************************************************/
128VC_CONTAINER_T *vc_container_open_writer( const char *uri, VC_CONTAINER_STATUS_T *p_status,
129 VC_CONTAINER_PROGRESS_REPORT_FUNC_T pfn_progress, void *progress_userdata)
130{
131 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
132 VC_CONTAINER_T *p_ctx = 0;
133 VC_CONTAINER_IO_T *io;
134 const char *extension;
135 VC_CONTAINER_PARAM_UNUSED(pfn_progress);
136 VC_CONTAINER_PARAM_UNUSED(progress_userdata);
137
138 /* Start by opening the URI */
139 io = vc_container_io_open( uri, VC_CONTAINER_IO_MODE_WRITE, &status );
140 if(!io) goto error;
141
142 /* Make sure we have enough space available to start writing */
143 if(io->max_size && io->max_size < WRITER_SPACE_SAFETY_MARGIN)
144 {
145 LOG_DEBUG(p_ctx, "not enough space available to open a writer");
146 status = VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
147 goto error;
148 }
149
150 /* Allocate our context before trying out the different readers / writers */
151 p_ctx = malloc( sizeof(*p_ctx) + sizeof(*p_ctx->priv));
152 if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
153 memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*p_ctx->priv));
154 p_ctx->priv = (VC_CONTAINER_PRIVATE_T *)(p_ctx + 1);
155 p_ctx->priv->verbosity = vc_container_log_get_default_verbosity();
156 p_ctx->priv->io = io;
157 p_ctx->priv->uri = io->uri_parts;
158 io = NULL; /* io now owned by the context */
159
160 /* If the uri has an extension, use it as a hint when loading the container */
161 extension = vc_uri_path_extension(p_ctx->priv->uri);
162 /* If the user has specified a container, then use that instead */
163 vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
164
165 status = vc_container_load_writer(p_ctx, extension);
166 if(status != VC_CONTAINER_SUCCESS) goto error;
167
168 end:
169 if(p_status) *p_status = status;
170 return p_ctx;
171
172error:
173 if(io) vc_container_io_close(io);
174 if (p_ctx) vc_container_close(p_ctx);
175 p_ctx = NULL;
176 goto end;
177}
178
179/*****************************************************************************/
180VC_CONTAINER_STATUS_T vc_container_close( VC_CONTAINER_T *p_ctx )
181{
182 unsigned int i;
183
184 if(!p_ctx)
185 return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
186
187 for(i = 0; i < p_ctx->tracks_num; i++)
188 if(p_ctx->tracks[i]->priv->packetizer)
189 vc_packetizer_close(p_ctx->tracks[i]->priv->packetizer);
190 if(p_ctx->priv->packetizer_buffer) free(p_ctx->priv->packetizer_buffer);
191 if(p_ctx->priv->drm_filter) vc_container_filter_close(p_ctx->priv->drm_filter);
192 if(p_ctx->priv->pf_close) p_ctx->priv->pf_close(p_ctx);
193 if(p_ctx->priv->io) vc_container_io_close(p_ctx->priv->io);
194 if(p_ctx->priv->module_handle) vc_container_unload(p_ctx);
195 for(i = 0; i < p_ctx->meta_num; i++) free(p_ctx->meta[i]);
196 if(p_ctx->meta_num) free(p_ctx->meta);
197 p_ctx->meta_num = 0;
198 free(p_ctx);
199
200 return VC_CONTAINER_SUCCESS;
201}
202
203/*****************************************************************************/
204static VC_CONTAINER_STATUS_T container_read_packet( VC_CONTAINER_T *p_ctx,
205 VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
206{
207 VC_CONTAINER_STATUS_T status;
208
209 while(1)
210 {
211 status = p_ctx->priv->pf_read(p_ctx, p_packet, flags);
212 if(status == VC_CONTAINER_ERROR_CONTINUE)
213 continue;
214
215 if(!p_packet || (flags & VC_CONTAINER_READ_FLAG_SKIP))
216 return status; /* We've just been requested to skip the data */
217
218 if(status != VC_CONTAINER_SUCCESS)
219 return status;
220
221 /* Skip data from out of bounds tracks, disabled tracks or packets that are encrypted
222 and cannot be decrypted */
223 if(p_packet->track >= p_ctx->tracks_num ||
224 !p_ctx->tracks[p_packet->track]->is_enabled ||
225 ((p_packet->flags & VC_CONTAINER_PACKET_FLAG_ENCRYPTED) && !p_ctx->priv->drm_filter))
226 {
227 if(flags & VC_CONTAINER_READ_FLAG_INFO)
228 status = p_ctx->priv->pf_read(p_ctx, p_packet, VC_CONTAINER_READ_FLAG_SKIP);
229 if(status == VC_CONTAINER_SUCCESS || status == VC_CONTAINER_ERROR_CONTINUE)
230 continue;
231 }
232 if(status != VC_CONTAINER_SUCCESS)
233 return status;
234
235 if(p_ctx->priv->drm_filter)
236 status = vc_container_filter_process(p_ctx->priv->drm_filter, p_packet);
237
238 break;
239 }
240 return status;
241}
242
243/*****************************************************************************/
244VC_CONTAINER_STATUS_T vc_container_read( VC_CONTAINER_T *p_ctx, VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
245{
246 VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_CONTINUE;
247 VC_PACKETIZER_FLAGS_T packetizer_flags = 0;
248 VC_PACKETIZER_T *packetizer;
249 uint32_t force = flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK;
250 unsigned int i;
251
252 if(!p_packet && !(flags & VC_CONTAINER_READ_FLAG_SKIP))
253 return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
254 if(!p_packet && (flags & VC_CONTAINER_READ_FLAG_INFO))
255 return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
256 if(p_packet && !p_packet->data && !(flags & (VC_CONTAINER_READ_FLAG_INFO | VC_CONTAINER_READ_FLAG_SKIP)))
257 return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
258 if((flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK) &&
259 (!p_packet || p_packet->track >= p_ctx->tracks_num || !p_ctx->tracks[p_packet->track]->is_enabled))
260 return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
261
262 /* Always having a packet structure to work with simplifies things */
263 if(!p_packet)
264 p_packet = &p_ctx->priv->packetizer_packet;
265
266 /* Simple/Fast case first */
267 if(!p_ctx->priv->packetizing)
268 {
269 status = container_read_packet( p_ctx, p_packet, flags );
270 goto end;
271 }
272
273 if(flags & VC_CONTAINER_READ_FLAG_INFO)
274 packetizer_flags |= VC_PACKETIZER_FLAG_INFO;
275 if(flags & VC_CONTAINER_READ_FLAG_SKIP)
276 packetizer_flags |= VC_PACKETIZER_FLAG_SKIP;
277
278 /* Loop through all the packetized tracks first to see if we've got any
279 * data to consume there */
280 for(i = 0; i < p_ctx->tracks_num; i++)
281 {
282 VC_PACKETIZER_T *packetizer = p_ctx->tracks[i]->priv->packetizer;
283 if(!p_ctx->tracks[i]->is_enabled || !packetizer ||
284 (force && i != p_packet->track))
285 continue;
286
287 status = vc_packetizer_read(packetizer, p_packet, packetizer_flags);
288 p_packet->track = i;
289 if(status == VC_CONTAINER_SUCCESS)
290 break;
291 }
292 if(i < p_ctx->tracks_num) /* We've got some data */
293 goto end;
294
295 /* Let's go and read some data from the actual container */
296 while(1)
297 {
298 VC_CONTAINER_PACKET_T *tmp = &p_ctx->priv->packetizer_packet;
299 tmp->track = p_packet->track;
300
301 /* Let's check what the container has to offer */
302 status = container_read_packet( p_ctx, tmp, force|VC_PACKETIZER_FLAG_INFO );
303 if(status != VC_CONTAINER_SUCCESS)
304 return status;
305
306 if(!p_ctx->tracks[tmp->track]->priv->packetizer)
307 {
308 status = container_read_packet( p_ctx, p_packet, flags );
309 break;
310 }
311
312 /* Feed data from the container onto the packetizer */
313 packetizer = p_ctx->tracks[tmp->track]->priv->packetizer;
314
315 tmp->data = p_ctx->priv->packetizer_buffer;
316 tmp->buffer_size = PACKETIZER_BUFFER_SIZE;
317 tmp->size = 0;
318 status = container_read_packet( p_ctx, tmp, force );
319 if(status != VC_CONTAINER_SUCCESS)
320 return status;
321
322 p_packet->track = tmp->track;
323 vc_packetizer_push(packetizer, tmp);
324 vc_packetizer_pop(packetizer, &tmp, VC_PACKETIZER_FLAG_FORCE_RELEASE_INPUT);
325
326 status = vc_packetizer_read(packetizer, p_packet, packetizer_flags);
327 if(status == VC_CONTAINER_SUCCESS)
328 break;
329 }
330
331 end:
332 if(status != VC_CONTAINER_SUCCESS)
333 return status;
334
335 if(p_packet && p_packet->dts > p_ctx->position)
336 p_ctx->position = p_packet->dts;
337 if(p_packet && p_packet->pts > p_ctx->position)
338 p_ctx->position = p_packet->pts;
339
340 return VC_CONTAINER_SUCCESS;
341}
342
343/*****************************************************************************/
344VC_CONTAINER_STATUS_T vc_container_write( VC_CONTAINER_T *p_ctx, VC_CONTAINER_PACKET_T *p_packet )
345{
346 VC_CONTAINER_STATUS_T status;
347 void * p_metadata_buffer = NULL;
348 uint32_t metadata_length = 0;
349
350 /* TODO: check other similar argument errors and non-stateless errors */
351 if (!p_packet || !p_packet->data || p_packet->track >= p_ctx->tracks_num)
352 return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
353
354 /* Check for a previous error */
355 if(p_ctx->priv->status != VC_CONTAINER_SUCCESS && p_ctx->priv->status != VC_CONTAINER_ERROR_NOT_READY)
356 return p_ctx->priv->status;
357
358 /* Check we have enough space to write the data */
359 if(p_ctx->priv->max_size &&
360 p_ctx->size + p_packet->size + WRITER_SPACE_SAFETY_MARGIN > p_ctx->priv->max_size)
361 {status = VC_CONTAINER_ERROR_LIMIT_REACHED; goto end;}
362 if(p_ctx->priv->io->max_size &&
363 p_ctx->size + p_packet->size + WRITER_SPACE_SAFETY_MARGIN +
364 (p_ctx->priv->tmp_io ? p_ctx->priv->tmp_io->offset : 0) > p_ctx->priv->io->max_size)
365 {status = VC_CONTAINER_ERROR_OUT_OF_SPACE; goto end;}
366
367 /* If a filter is created, then send the packet to the filter for encryption. */
368 if(p_ctx->priv->drm_filter)
369 {
370 status = vc_container_filter_process(p_ctx->priv->drm_filter, p_packet);
371
372 if(status == VC_CONTAINER_SUCCESS)
373 {
374 /* Get the encryption metadata and send it to the output first. */
375 if(vc_container_control(p_ctx, VC_CONTAINER_CONTROL_GET_DRM_METADATA,
376 &p_metadata_buffer, &metadata_length) == VC_CONTAINER_SUCCESS && metadata_length > 0)
377 {
378 /* Make a packet up with the metadata in the payload and write it. */
379 VC_CONTAINER_PACKET_T metadata_packet;
380 metadata_packet.data = p_metadata_buffer;
381 metadata_packet.buffer_size = metadata_length;
382 metadata_packet.size = metadata_length;
383 metadata_packet.frame_size = p_packet->frame_size + metadata_length;
384 metadata_packet.pts = p_packet->pts;
385 metadata_packet.dts = p_packet->dts;
386 metadata_packet.num = p_packet->num;
387 metadata_packet.track = p_packet->track;
388 /* As this packet is written first, we must transfer any frame start
389 flag from the following packet. Also, this packet can never have the end flag set. */
390 metadata_packet.flags = p_packet->flags & ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
391
392 p_packet->pts = p_packet->dts = VC_CONTAINER_TIME_UNKNOWN;
393 p_packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_START;
394 if(p_ctx->priv->pf_write(p_ctx, &metadata_packet) != VC_CONTAINER_SUCCESS) goto end;
395 }
396 }
397 else if (status != VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION)
398 {
399 /* Encryption was appropriate but a problem has occurred. Skip the write of data
400 to the io and return the status to the caller. */
401 goto end;
402 }
403 }
404
405 status = p_ctx->priv->pf_write(p_ctx, p_packet);
406
407 end:
408 p_ctx->priv->status = status;
409 return status;
410}
411
412/*****************************************************************************/
413VC_CONTAINER_STATUS_T vc_container_seek( VC_CONTAINER_T *p_ctx, int64_t *p_offset,
414 VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
415{
416 VC_CONTAINER_STATUS_T status;
417 int64_t offset = *p_offset;
418 unsigned int i;
419
420 /* Reset all packetizers */
421 for(i = 0; i < p_ctx->tracks_num; i++)
422 if(p_ctx->tracks[i]->priv->packetizer)
423 vc_packetizer_reset(p_ctx->tracks[i]->priv->packetizer);
424
425 status = p_ctx->priv->pf_seek(p_ctx, p_offset, mode, flags);
426
427 /* */
428 if(status == VC_CONTAINER_SUCCESS && (flags & VC_CONTAINER_SEEK_FLAG_FORWARD) &&
429 *p_offset < offset)
430 {
431 LOG_DEBUG(p_ctx, "container didn't seek forward as requested (%"PRIi64"/%"PRIi64")",
432 *p_offset, offset);
433 for(i = 1; i <= 5 && *p_offset < offset; i++)
434 {
435 *p_offset = offset + i * i * 100000;
436 status = p_ctx->priv->pf_seek(p_ctx, p_offset, mode, flags);
437 if(status != VC_CONTAINER_SUCCESS) break;
438 }
439 }
440
441 return status;
442}
443
444/*****************************************************************************/
445VC_CONTAINER_STATUS_T vc_container_control( VC_CONTAINER_T *p_ctx, VC_CONTAINER_CONTROL_T operation, ... )
446{
447 VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
448 va_list args;
449
450 va_start( args, operation );
451
452 if(operation == VC_CONTAINER_CONTROL_ENCRYPT_TRACK)
453 {
454 VC_CONTAINER_FOURCC_T type = va_arg(args, VC_CONTAINER_FOURCC_T);
455
456 uint32_t track_num = va_arg(args, uint32_t);
457 void *p_drm_data = va_arg(args, void *);
458 int drm_data_size = va_arg(args, uint32_t);
459
460 if(!p_ctx->priv->drm_filter && track_num < p_ctx->tracks_num)
461 {
462 VC_CONTAINER_TRACK_T * p_track = p_ctx->tracks[track_num];
463
464 if ((status = vc_container_track_allocate_drmdata(p_ctx, p_track, drm_data_size)) != VC_CONTAINER_SUCCESS)
465 {
466 LOG_DEBUG(p_ctx, "failed to allocate memory for 'drm data' (%d bytes)", drm_data_size);
467 goto end;
468 }
469 memcpy(p_track->priv->drmdata, p_drm_data, drm_data_size);
470
471 /* Track encryption enabled and no filter - create one now. */
472 p_ctx->priv->drm_filter = vc_container_filter_open(VC_FOURCC('d','r','m',' '), type, p_ctx, &status);
473 if(status != VC_CONTAINER_SUCCESS)
474 goto end;
475
476 status = vc_container_filter_control(p_ctx->priv->drm_filter, operation, track_num);
477 }
478 }
479 else if(operation == VC_CONTAINER_CONTROL_GET_DRM_METADATA)
480 {
481 void *p_drm_data = va_arg(args, void *);
482 int *drm_data_size = va_arg(args, int *);
483 status = vc_container_filter_control(p_ctx->priv->drm_filter, operation, p_drm_data, drm_data_size);
484 }
485
486 if(status == VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION && p_ctx->priv->pf_control)
487 status = p_ctx->priv->pf_control(p_ctx, operation, args);
488
489 /* If the request has already been handled then we're done */
490 if(status != VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION)
491 goto end;
492
493 switch(operation)
494 {
495 case VC_CONTAINER_CONTROL_DRM_PLAY:
496 if (p_ctx->priv->drm_filter)
497 status = vc_container_filter_control(p_ctx->priv->drm_filter, operation, args);
498 break;
499
500 case VC_CONTAINER_CONTROL_SET_MAXIMUM_SIZE:
501 p_ctx->priv->max_size = (uint64_t)va_arg( args, uint64_t );
502 if(p_ctx->priv->io->max_size &&
503 p_ctx->priv->max_size > p_ctx->priv->io->max_size)
504 p_ctx->priv->max_size = p_ctx->priv->io->max_size;
505 status = VC_CONTAINER_SUCCESS;
506 break;
507
508 case VC_CONTAINER_CONTROL_TRACK_PACKETIZE:
509 {
510 unsigned int track_num = va_arg(args, unsigned int);
511 VC_CONTAINER_FOURCC_T fourcc = va_arg(args, VC_CONTAINER_FOURCC_T);
512 VC_CONTAINER_TRACK_T *p_track;
513
514 if(track_num >= p_ctx->tracks_num)
515 {
516 status = VC_CONTAINER_ERROR_INVALID_ARGUMENT;
517 break;
518 }
519 if(p_ctx->tracks[track_num]->priv->packetizer)
520 {
521 status = VC_CONTAINER_SUCCESS;
522 break;
523 }
524
525 p_track = p_ctx->tracks[track_num];
526 p_track->priv->packetizer = vc_packetizer_open( p_track->format, fourcc, &status );
527 if(!p_track->priv->packetizer)
528 break;
529
530 if(!p_ctx->priv->packetizer_buffer)
531 {
532 p_ctx->priv->packetizer_buffer = malloc(PACKETIZER_BUFFER_SIZE);
533 if(!p_ctx->priv->packetizer_buffer)
534 {
535 status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
536 vc_packetizer_close(p_track->priv->packetizer);
537 p_track->priv->packetizer = NULL;
538 break;
539 }
540 }
541
542 vc_container_format_copy(p_track->format, p_track->priv->packetizer->out,
543 p_track->format->extradata_size);
544 p_track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
545 p_ctx->priv->packetizing = true;
546 }
547 break;
548
549 default: break;
550 }
551
552 if (status == VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION)
553 status = vc_container_io_control_list(p_ctx->priv->io, operation, args);
554
555 end:
556 va_end( args );
557 return status;
558}
559
560/*****************************************************************************/
561VC_CONTAINER_TRACK_T *vc_container_allocate_track( VC_CONTAINER_T *context, unsigned int extra_size )
562{
563 VC_CONTAINER_TRACK_T *p_ctx;
564 unsigned int size;
565 VC_CONTAINER_PARAM_UNUSED(context);
566
567 size = sizeof(*p_ctx) + sizeof(*p_ctx->priv) + sizeof(*p_ctx->format) +
568 sizeof(*p_ctx->format->type) + extra_size;
569
570 p_ctx = malloc(size);
571 if(!p_ctx) return 0;
572
573 memset(p_ctx, 0, size);
574 p_ctx->priv = (VC_CONTAINER_TRACK_PRIVATE_T *)(p_ctx + 1);
575 p_ctx->format = (VC_CONTAINER_ES_FORMAT_T *)(p_ctx->priv + 1);
576 p_ctx->format->type = (void *)(p_ctx->format + 1);
577 p_ctx->priv->module = (struct VC_CONTAINER_TRACK_MODULE_T *)(p_ctx->format->type + 1);
578 return p_ctx;
579}
580
581/*****************************************************************************/
582void vc_container_free_track( VC_CONTAINER_T *context, VC_CONTAINER_TRACK_T *p_track )
583{
584 VC_CONTAINER_PARAM_UNUSED(context);
585 if(p_track)
586 {
587 if(p_track->priv->extradata) free(p_track->priv->extradata);
588 if(p_track->priv->drmdata) free(p_track->priv->drmdata);
589 free(p_track);
590 }
591}
592
593/*****************************************************************************/
594VC_CONTAINER_STATUS_T vc_container_track_allocate_extradata( VC_CONTAINER_T *context,
595 VC_CONTAINER_TRACK_T *p_track, unsigned int extra_size )
596{
597 VC_CONTAINER_PARAM_UNUSED(context);
598
599 /* Sanity check the size of the extra data */
600 if(extra_size > 100*1024) return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
601
602 /* Check if we need to allocate a buffer */
603 if(extra_size > p_track->priv->extradata_size)
604 {
605 p_track->priv->extradata_size = 0;
606 if(p_track->priv->extradata) free(p_track->priv->extradata);
607 p_track->priv->extradata = malloc(extra_size);
608 p_track->format->extradata = p_track->priv->extradata;
609 if(!p_track->priv->extradata) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
610 p_track->priv->extradata_size = extra_size;
611 }
612 p_track->format->extradata = p_track->priv->extradata;
613
614 return VC_CONTAINER_SUCCESS;
615}
616
617/*****************************************************************************/
618VC_CONTAINER_STATUS_T vc_container_track_allocate_drmdata( VC_CONTAINER_T *context,
619 VC_CONTAINER_TRACK_T *p_track, unsigned int size )
620{
621 VC_CONTAINER_PARAM_UNUSED(context);
622
623 /* Sanity check the size of the drm data */
624 if(size > 200*1024) return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
625
626 /* Check if we need to allocate a buffer */
627 if(size > p_track->priv->drmdata_size)
628 {
629 p_track->priv->drmdata_size = 0;
630 if(p_track->priv->drmdata) free(p_track->priv->drmdata);
631 p_track->priv->drmdata = malloc(size);
632 if(!p_track->priv->drmdata) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
633 p_track->priv->drmdata_size = size;
634 }
635
636 return VC_CONTAINER_SUCCESS;
637}
638