print: Avoid Variable Length Arrays.
[L-SMASH.git] / importer / vc1_imp.c
blobd69e32b816255961550a926598ab2cf4e9e590d6
1 /*****************************************************************************
2 * vc1_imp.c
3 *****************************************************************************
4 * Copyright (C) 2011-2014 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #include "common/internal.h" /* must be placed first */
25 #include <string.h>
26 #include <inttypes.h>
28 #define LSMASH_IMPORTER_INTERNAL
29 #include "importer.h"
31 /***************************************************************************
32 SMPTE VC-1 importer (only for Advanced Profile)
33 SMPTE 421M-2006
34 SMPTE RP 2025-2007
35 ***************************************************************************/
36 #include "codecs/vc1.h"
38 typedef struct
40 vc1_info_t info;
41 vc1_sequence_header_t first_sequence;
42 lsmash_media_ts_list_t ts_list;
43 uint8_t composition_reordering_present;
44 uint32_t max_au_length;
45 uint32_t num_undecodable;
46 uint64_t last_ref_intra_cts;
47 } vc1_importer_t;
49 static void remove_vc1_importer( vc1_importer_t *vc1_imp )
51 if( !vc1_imp )
52 return;
53 vc1_cleanup_parser( &vc1_imp->info );
54 lsmash_free( vc1_imp->ts_list.timestamp );
55 lsmash_free( vc1_imp );
58 static void vc1_importer_cleanup( importer_t *importer )
60 debug_if( importer && importer->info )
61 remove_vc1_importer( importer->info );
64 static vc1_importer_t *create_vc1_importer( importer_t *importer )
66 vc1_importer_t *vc1_imp = lsmash_malloc_zero( sizeof(vc1_importer_t) );
67 if( !vc1_imp )
68 return NULL;
69 if( vc1_setup_parser( &vc1_imp->info, 0 ) < 0 )
71 remove_vc1_importer( vc1_imp );
72 return NULL;
74 return vc1_imp;
77 static inline int vc1_complete_au( vc1_access_unit_t *access_unit, vc1_picture_info_t *picture, int probe )
79 if( !picture->present )
80 return 0;
81 if( !probe )
82 memcpy( access_unit->data, access_unit->incomplete_data, access_unit->incomplete_data_length );
83 access_unit->data_length = access_unit->incomplete_data_length;
84 access_unit->incomplete_data_length = 0;
85 vc1_update_au_property( access_unit, picture );
86 return 1;
89 static inline void vc1_append_ebdu_to_au( vc1_access_unit_t *access_unit, uint8_t *ebdu, uint32_t ebdu_length, int probe )
91 if( !probe )
92 memcpy( access_unit->incomplete_data + access_unit->incomplete_data_length, ebdu, ebdu_length );
93 /* Note: access_unit->incomplete_data_length shall be 0 immediately after AU has completed.
94 * Therefore, possible_au_length in vc1_get_access_unit_internal() can't be used here
95 * to avoid increasing AU length monotonously through the entire stream. */
96 access_unit->incomplete_data_length += ebdu_length;
99 static int vc1_get_au_internal_succeeded( vc1_importer_t *vc1_imp )
101 vc1_access_unit_t *access_unit = &vc1_imp->info.access_unit;
102 access_unit->number += 1;
103 return 0;
106 static int vc1_get_au_internal_failed( vc1_importer_t *vc1_imp, int complete_au, int ret )
108 vc1_access_unit_t *access_unit = &vc1_imp->info.access_unit;
109 if( complete_au )
110 access_unit->number += 1;
111 return ret;
114 static int vc1_importer_get_access_unit_internal( importer_t *importer, int probe )
116 vc1_importer_t *vc1_imp = (vc1_importer_t *)importer->info;
117 vc1_info_t *info = &vc1_imp->info;
118 vc1_stream_buffer_t *sb = &info->buffer;
119 vc1_access_unit_t *access_unit = &info->access_unit;
120 lsmash_bs_t *bs = importer->bs;
121 int complete_au = 0;
122 access_unit->data_length = 0;
123 while( 1 )
125 int err;
126 uint8_t bdu_type;
127 uint64_t trailing_zero_bytes;
128 uint64_t ebdu_length = vc1_find_next_start_code_prefix( bs, &bdu_type, &trailing_zero_bytes );
129 if( ebdu_length <= VC1_START_CODE_LENGTH && lsmash_bs_is_end( bs, ebdu_length ) )
131 /* For the last EBDU.
132 * This EBDU already has been appended into the latest access unit and parsed. */
133 vc1_complete_au( access_unit, &info->picture, probe );
134 return vc1_get_au_internal_succeeded( vc1_imp );
136 else if( bdu_type == 0xFF )
138 lsmash_log( importer, LSMASH_LOG_ERROR, "a forbidden BDU type is detected.\n" );
139 return vc1_get_au_internal_failed( vc1_imp, complete_au, LSMASH_ERR_INVALID_DATA );
141 uint64_t next_ebdu_head_pos = info->ebdu_head_pos
142 + ebdu_length
143 + trailing_zero_bytes;
144 #if 0
145 if( probe )
147 fprintf( stderr, "BDU type: %"PRIu8" \n", bdu_type );
148 fprintf( stderr, " EBDU position: %"PRIx64" \n", info->ebdu_head_pos );
149 fprintf( stderr, " EBDU length: %"PRIx64" (%"PRIu64")\n", ebdu_length, ebdu_length );
150 fprintf( stderr, " trailing_zero_bytes: %"PRIx64" \n", trailing_zero_bytes );
151 fprintf( stderr, " Next EBDU position: %"PRIx64" \n", next_ebdu_head_pos );
153 #endif
154 if( bdu_type >= 0x0A && bdu_type <= 0x0F )
156 /* Complete the current access unit if encountered delimiter of current access unit. */
157 if( vc1_find_au_delimit_by_bdu_type( bdu_type, info->prev_bdu_type ) )
158 /* The last video coded EBDU belongs to the access unit you want at this time. */
159 complete_au = vc1_complete_au( access_unit, &info->picture, probe );
160 /* Increase the buffer if needed. */
161 uint64_t possible_au_length = access_unit->incomplete_data_length + ebdu_length;
162 if( sb->bank->buffer_size < possible_au_length
163 && (err = vc1_supplement_buffer( sb, access_unit, 2 * possible_au_length )) < 0 )
165 lsmash_log( importer, LSMASH_LOG_ERROR, "failed to increase the buffer size.\n" );
166 return vc1_get_au_internal_failed( vc1_imp, complete_au, err );
168 /* Process EBDU by its BDU type and append it to access unit. */
169 uint8_t *ebdu = lsmash_bs_get_buffer_data( bs );
170 switch( bdu_type )
172 /* FRM_SC: Frame start code
173 * FLD_SC: Field start code
174 * SLC_SC: Slice start code
175 * SEQ_SC: Sequence header start code
176 * EP_SC: Entry-point start code
177 * PIC_L: Picture layer
178 * SLC_L: Slice layer
179 * SEQ_L: Sequence layer
180 * EP_L: Entry-point layer */
181 case 0x0D : /* Frame
182 * For the Progressive or Frame Interlace mode, shall signal the beginning of a new video frame.
183 * For the Field Interlace mode, shall signal the beginning of a sequence of two independently coded video fields.
184 * [FRM_SC][PIC_L][[FLD_SC][PIC_L] (optional)][[SLC_SC][SLC_L] (optional)] ... */
185 if( (err = vc1_parse_advanced_picture( info->bits, &info->sequence, &info->picture, sb->rbdu, ebdu, ebdu_length )) < 0 )
187 lsmash_log( importer, LSMASH_LOG_ERROR, "failed to parse a frame.\n" );
188 return vc1_get_au_internal_failed( vc1_imp, complete_au, err );
190 case 0x0C : /* Field
191 * Shall only be used for Field Interlaced frames
192 * and shall only be used to signal the beginning of the second field of the frame.
193 * [FRM_SC][PIC_L][FLD_SC][PIC_L][[SLC_SC][SLC_L] (optional)] ...
194 * Field start code is followed by INTERLACE_FIELD_PICTURE_FIELD2() which doesn't have info of its field picture type.*/
195 break;
196 case 0x0B : /* Slice
197 * Shall not be used for start code of the first slice of a frame.
198 * Shall not be used for start code of the first slice of an interlace field coded picture.
199 * [FRM_SC][PIC_L][[FLD_SC][PIC_L] (optional)][SLC_SC][SLC_L][[SLC_SC][SLC_L] (optional)] ...
200 * Slice layer may repeat frame header. We just ignore it. */
201 info->dvc1_param.slice_present = 1;
202 break;
203 case 0x0E : /* Entry-point header
204 * Entry-point indicates the direct followed frame is a start of group of frames.
205 * Entry-point doesn't indicates the frame is a random access point when multiple sequence headers are present,
206 * since it is necessary to decode sequence header which subsequent frames belong to for decoding them.
207 * Entry point shall be followed by
208 * 1. I-picture - progressive or frame interlace
209 * 2. I/I-picture, I/P-picture, or P/I-picture - field interlace
210 * [[SEQ_SC][SEQ_L] (optional)][EP_SC][EP_L][FRM_SC][PIC_L] ... */
211 if( (err = vc1_parse_entry_point_header( info, ebdu, ebdu_length, probe )) < 0 )
213 lsmash_log( importer, LSMASH_LOG_ERROR, "failed to parse an entry point.\n" );
214 return vc1_get_au_internal_failed( vc1_imp, complete_au, err );
216 /* Signal random access type of the frame that follows this entry-point header. */
217 info->picture.closed_gop = info->entry_point.closed_entry_point;
218 info->picture.random_accessible = info->dvc1_param.multiple_sequence ? info->picture.start_of_sequence : 1;
219 break;
220 case 0x0F : /* Sequence header
221 * [SEQ_SC][SEQ_L][EP_SC][EP_L][FRM_SC][PIC_L] ... */
222 if( (err = vc1_parse_sequence_header( info, ebdu, ebdu_length, probe )) < 0 )
224 lsmash_log( importer, LSMASH_LOG_ERROR, "failed to parse a sequence header.\n" );
225 return vc1_get_au_internal_failed( vc1_imp, complete_au, err );
227 /* The frame that is the first frame after this sequence header shall be a random accessible point. */
228 info->picture.start_of_sequence = 1;
229 if( probe && !vc1_imp->first_sequence.present )
230 vc1_imp->first_sequence = info->sequence;
231 break;
232 default : /* End-of-sequence (0x0A) */
233 break;
235 /* Append the current EBDU into the end of an incomplete access unit. */
236 vc1_append_ebdu_to_au( access_unit, ebdu, ebdu_length, probe );
238 else /* We don't support other BDU types such as user data yet. */
239 return vc1_get_au_internal_failed( vc1_imp, complete_au, LSMASH_ERR_PATCH_WELCOME );
240 /* Move to the first byte of the next EBDU. */
241 info->prev_bdu_type = bdu_type;
242 if( lsmash_bs_read_seek( bs, next_ebdu_head_pos, SEEK_SET ) != next_ebdu_head_pos )
244 lsmash_log( importer, LSMASH_LOG_ERROR, "failed to seek the next start code suffix.\n" );
245 return vc1_get_au_internal_failed( vc1_imp, complete_au, LSMASH_ERR_NAMELESS );
247 /* Check if no more data to read from the stream. */
248 if( !lsmash_bs_is_end( bs, VC1_START_CODE_PREFIX_LENGTH ) )
249 info->ebdu_head_pos = next_ebdu_head_pos;
250 /* If there is no more data in the stream, and flushed chunk of EBDUs, flush it as complete AU here. */
251 else if( access_unit->incomplete_data_length && access_unit->data_length == 0 )
253 vc1_complete_au( access_unit, &info->picture, probe );
254 return vc1_get_au_internal_succeeded( vc1_imp );
256 if( complete_au )
257 return vc1_get_au_internal_succeeded( vc1_imp );
261 static inline void vc1_importer_check_eof( importer_t *importer, vc1_access_unit_t *access_unit )
263 if( lsmash_bs_is_end( importer->bs, 0 ) && access_unit->incomplete_data_length == 0 )
264 importer->status = IMPORTER_EOF;
265 else
266 importer->status = IMPORTER_OK;
269 static int vc1_importer_get_accessunit( importer_t *importer, uint32_t track_number, lsmash_sample_t **p_sample )
271 if( !importer->info )
272 return LSMASH_ERR_NAMELESS;
273 if( track_number != 1 )
274 return LSMASH_ERR_FUNCTION_PARAM;
275 vc1_importer_t *vc1_imp = (vc1_importer_t *)importer->info;
276 vc1_info_t *info = &vc1_imp->info;
277 importer_status current_status = importer->status;
278 if( current_status == IMPORTER_ERROR )
279 return LSMASH_ERR_NAMELESS;
280 if( current_status == IMPORTER_EOF )
281 return IMPORTER_EOF;
282 int err = vc1_importer_get_access_unit_internal( importer, 0 );
283 if( err < 0 )
285 importer->status = IMPORTER_ERROR;
286 return err;
288 lsmash_sample_t *sample = lsmash_create_sample( vc1_imp->max_au_length );
289 if( !sample )
290 return LSMASH_ERR_MEMORY_ALLOC;
291 *p_sample = sample;
292 vc1_access_unit_t *access_unit = &info->access_unit;
293 vc1_importer_check_eof( importer, access_unit );
294 sample->dts = vc1_imp->ts_list.timestamp[ access_unit->number - 1 ].dts;
295 sample->cts = vc1_imp->ts_list.timestamp[ access_unit->number - 1 ].cts;
296 sample->prop.leading = access_unit->independent
297 || access_unit->non_bipredictive
298 || sample->cts >= vc1_imp->last_ref_intra_cts
299 ? ISOM_SAMPLE_IS_NOT_LEADING : ISOM_SAMPLE_IS_UNDECODABLE_LEADING;
300 if( access_unit->independent && !access_unit->disposable )
301 vc1_imp->last_ref_intra_cts = sample->cts;
302 if( vc1_imp->composition_reordering_present && !access_unit->disposable && !access_unit->closed_gop )
303 sample->prop.allow_earlier = QT_SAMPLE_EARLIER_PTS_ALLOWED;
304 sample->prop.independent = access_unit->independent ? ISOM_SAMPLE_IS_INDEPENDENT : ISOM_SAMPLE_IS_NOT_INDEPENDENT;
305 sample->prop.disposable = access_unit->disposable ? ISOM_SAMPLE_IS_DISPOSABLE : ISOM_SAMPLE_IS_NOT_DISPOSABLE;
306 sample->prop.redundant = ISOM_SAMPLE_HAS_NO_REDUNDANCY;
307 if( access_unit->random_accessible )
308 /* All random access point is a sync sample even if it's an open RAP. */
309 sample->prop.ra_flags = ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
310 sample->length = access_unit->data_length;
311 memcpy( sample->data, access_unit->data, access_unit->data_length );
312 return current_status;
315 static lsmash_video_summary_t *vc1_create_summary( vc1_info_t *info, vc1_sequence_header_t *sequence, uint32_t max_au_length )
317 if( !info->sequence.present || !info->entry_point.present )
318 return NULL;
319 lsmash_video_summary_t *summary = (lsmash_video_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_VIDEO );
320 if( !summary )
321 return NULL;
322 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1,
323 LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
324 specific->data.unstructured = lsmash_create_vc1_specific_info( &info->dvc1_param, &specific->size );
325 if( !specific->data.unstructured
326 || lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
328 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
329 lsmash_destroy_codec_specific_data( specific );
330 return NULL;
332 summary->sample_type = ISOM_CODEC_TYPE_VC_1_VIDEO;
333 summary->max_au_length = max_au_length;
334 summary->timescale = sequence->framerate_numerator;
335 summary->timebase = sequence->framerate_denominator;
336 summary->vfr = !sequence->framerate_flag;
337 summary->sample_per_field = 0;
338 summary->width = sequence->disp_horiz_size;
339 summary->height = sequence->disp_vert_size;
340 summary->par_h = sequence->aspect_width;
341 summary->par_v = sequence->aspect_height;
342 summary->color.primaries_index = sequence->color_prim;
343 summary->color.transfer_index = sequence->transfer_char;
344 summary->color.matrix_index = sequence->matrix_coef;
345 return summary;
348 static int vc1_analyze_whole_stream
350 importer_t *importer
353 /* Parse all EBDU in the stream for preparation of calculating timestamps. */
354 uint32_t cts_alloc = (1 << 12) * sizeof(uint64_t);
355 uint64_t *cts = lsmash_malloc( cts_alloc );
356 if( !cts )
357 return LSMASH_ERR_MEMORY_ALLOC; /* Failed to allocate CTS list */
358 uint32_t num_access_units = 0;
359 uint32_t num_consecutive_b = 0;
360 lsmash_class_t *logger = &(lsmash_class_t){ "VC-1" };
361 lsmash_log( &logger, LSMASH_LOG_INFO, "Analyzing stream as VC-1\r" );
362 vc1_importer_t *vc1_imp = (vc1_importer_t *)importer->info;
363 vc1_info_t *info = &vc1_imp->info;
364 importer->status = IMPORTER_OK;
365 int err;
366 while( importer->status != IMPORTER_EOF )
368 #if 0
369 lsmash_log( &logger, LSMASH_LOG_INFO, "Analyzing stream as VC-1: %"PRIu32"\n", num_access_units + 1 );
370 #endif
371 if( (err = vc1_importer_get_access_unit_internal( importer, 1 )) < 0 )
372 goto fail;
373 vc1_importer_check_eof( importer, &info->access_unit );
374 /* In the case where B-pictures exist
375 * Decode order
376 * I[0]P[1]P[2]B[3]B[4]P[5]...
377 * DTS
378 * 0 1 2 3 4 5 ...
379 * Composition order
380 * I[0]P[1]B[3]B[4]P[2]P[5]...
381 * CTS
382 * 1 2 3 4 5 6 ...
383 * We assumes B or BI-pictures always be present in the stream here. */
384 if( !info->access_unit.disposable )
386 /* Apply CTS of the last B-picture plus 1 to the last non-B-picture. */
387 if( num_access_units > num_consecutive_b )
388 cts[ num_access_units - num_consecutive_b - 1 ] = num_access_units;
389 num_consecutive_b = 0;
391 else /* B or BI-picture */
393 /* B and BI-pictures shall be output or displayed in the same order as they are encoded. */
394 cts[ num_access_units ] = num_access_units;
395 ++num_consecutive_b;
396 info->dvc1_param.bframe_present = 1;
398 if( cts_alloc <= num_access_units * sizeof(uint64_t) )
400 uint32_t alloc = 2 * num_access_units * sizeof(uint64_t);
401 uint64_t *temp = lsmash_realloc( cts, alloc );
402 if( !temp )
404 err = LSMASH_ERR_MEMORY_ALLOC;
405 goto fail; /* Failed to re-allocate CTS list */
407 cts = temp;
408 cts_alloc = alloc;
410 vc1_imp->max_au_length = LSMASH_MAX( info->access_unit.data_length, vc1_imp->max_au_length );
411 ++num_access_units;
413 if( num_access_units > num_consecutive_b )
414 cts[ num_access_units - num_consecutive_b - 1 ] = num_access_units;
415 else
417 err = LSMASH_ERR_INVALID_DATA;
418 goto fail;
420 /* Construct timestamps. */
421 lsmash_media_ts_t *timestamp = lsmash_malloc( num_access_units * sizeof(lsmash_media_ts_t) );
422 if( !timestamp )
424 err = LSMASH_ERR_MEMORY_ALLOC;
425 goto fail; /* Failed to allocate timestamp list */
427 for( uint32_t i = 1; i < num_access_units; i++ )
428 if( cts[i] < cts[i - 1] )
430 vc1_imp->composition_reordering_present = 1;
431 break;
433 if( vc1_imp->composition_reordering_present )
434 for( uint32_t i = 0; i < num_access_units; i++ )
436 timestamp[i].cts = cts[i];
437 timestamp[i].dts = i;
439 else
440 for( uint32_t i = 0; i < num_access_units; i++ )
441 timestamp[i].cts = timestamp[i].dts = i;
442 lsmash_free( cts );
443 lsmash_log_refresh_line( &logger );
444 #if 0
445 for( uint32_t i = 0; i < num_access_units; i++ )
446 fprintf( stderr, "Timestamp[%"PRIu32"]: DTS=%"PRIu64", CTS=%"PRIu64"\n", i, timestamp[i].dts, timestamp[i].cts );
447 #endif
448 vc1_imp->ts_list.sample_count = num_access_units;
449 vc1_imp->ts_list.timestamp = timestamp;
450 return 0;
451 fail:
452 lsmash_log_refresh_line( &logger );
453 lsmash_free( cts );
454 return err;
457 static int vc1_importer_probe( importer_t *importer )
459 /* Find the first start code. */
460 vc1_importer_t *vc1_imp = create_vc1_importer( importer );
461 if( !vc1_imp )
462 return LSMASH_ERR_MEMORY_ALLOC;
463 lsmash_bs_t *bs = importer->bs;
464 uint64_t first_ebdu_head_pos = 0;
465 int err;
466 while( 1 )
468 /* The first EBDU in decoding order of the stream shall have start code (0x000001). */
469 if( 0x000001 == lsmash_bs_show_be24( bs, first_ebdu_head_pos ) )
470 break;
471 /* Invalid if encountered any value of non-zero before the first start code. */
472 if( lsmash_bs_show_byte( bs, first_ebdu_head_pos ) )
474 err = LSMASH_ERR_INVALID_DATA;
475 goto fail;
477 ++first_ebdu_head_pos;
479 /* OK. It seems the stream has a sequence header of VC-1. */
480 importer->info = vc1_imp;
481 vc1_info_t *info = &vc1_imp->info;
482 lsmash_bs_read_seek( bs, first_ebdu_head_pos, SEEK_SET );
483 info->ebdu_head_pos = first_ebdu_head_pos;
484 if( (err = vc1_analyze_whole_stream( importer )) < 0 )
485 goto fail;
486 lsmash_video_summary_t *summary = vc1_create_summary( info, &vc1_imp->first_sequence, vc1_imp->max_au_length );
487 if( !summary )
489 err = LSMASH_ERR_NAMELESS;
490 goto fail;
492 if( lsmash_add_entry( importer->summaries, summary ) < 0 )
494 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
495 err = LSMASH_ERR_MEMORY_ALLOC;
496 goto fail;
498 /* Go back to layer of the first EBDU. */
499 importer->status = IMPORTER_OK;
500 lsmash_bs_read_seek( bs, first_ebdu_head_pos, SEEK_SET );
501 info->prev_bdu_type = 0xFF; /* 0xFF is a forbidden value. */
502 info->ebdu_head_pos = first_ebdu_head_pos;
503 uint8_t *temp_access_unit = info->access_unit.data;
504 uint8_t *temp_incomplete_access_unit = info->access_unit.incomplete_data;
505 memset( &info->access_unit, 0, sizeof(vc1_access_unit_t) );
506 info->access_unit.data = temp_access_unit;
507 info->access_unit.incomplete_data = temp_incomplete_access_unit;
508 memset( &info->picture, 0, sizeof(vc1_picture_info_t) );
509 return 0;
510 fail:
511 remove_vc1_importer( vc1_imp );
512 importer->info = NULL;
513 lsmash_remove_entries( importer->summaries, lsmash_cleanup_summary );
514 return err;
517 static uint32_t vc1_importer_get_last_delta( importer_t *importer, uint32_t track_number )
519 debug_if( !importer || !importer->info )
520 return 0;
521 vc1_importer_t *vc1_imp = (vc1_importer_t *)importer->info;
522 if( !vc1_imp || track_number != 1 || importer->status != IMPORTER_EOF )
523 return 0;
524 return vc1_imp->ts_list.sample_count
526 : UINT32_MAX; /* arbitrary */
529 const importer_functions vc1_importer =
531 { "VC-1", offsetof( importer_t, log_level ) },
533 vc1_importer_probe,
534 vc1_importer_get_accessunit,
535 vc1_importer_get_last_delta,
536 vc1_importer_cleanup