static void bs_alloc( lsmash_bs_t *bs, size_t alloc ) { if( (bs->buffer.alloc >= alloc) || bs->error ) return; if( !bs->buffer.internal ) { /* We cannot re-allocate the memory block. */ bs->error = 1; return; } alloc += (1 << 16); alloc = LSMASH_MAX( alloc, bs->buffer.max_size ); uint8_t *data; if( !bs->buffer.data ) data = lsmash_malloc( alloc ); else data = lsmash_realloc( bs->buffer.data, alloc ); if( !data ) { bs_buffer_free( bs ); bs->error = 1; return; } bs->buffer.internal = 1; bs->buffer.data = data; bs->buffer.alloc = alloc; }
static int isom_set_brands ( lsmash_file_t *file, lsmash_brand_type major_brand, uint32_t minor_version, lsmash_brand_type *brands, uint32_t brand_count ) { if( brand_count > 50 ) return LSMASH_ERR_FUNCTION_PARAM; /* We support setting brands up to 50. */ if( major_brand == 0 && (!brands || brand_count == 0 || brands[0] == 0) ) { if( file->flags & LSMASH_FILE_MODE_INITIALIZATION ) { /* Absence of File Type Box means this file is a QuickTime or MP4 version 1 format file. */ isom_remove_box_by_itself( file->ftyp ); /* Anyway we use QTFF as a default file format. */ isom_clear_compat_flags( file ); file->qt_compatible = 1; } else { /* The absence of the Segment Type Box is allowed. * We set brands from the initialization segment after switching to this segment. */ for( lsmash_entry_t *entry = file->styp_list.head; entry; entry = entry->next ) isom_remove_box_by_itself( entry->data ); if( file->initializer ) { /* Copy flags for compatibility. */ memcpy( (int8_t *)file + COMPAT_FLAGS_OFFSET, file->initializer, sizeof(lsmash_file_t) - COMPAT_FLAGS_OFFSET ); file->isom_compatible = 1; file->allow_moof_base = 1; file->media_segment = 1; if( file->min_isom_version < 5 ) file->min_isom_version = 5; if( file->max_isom_version < 6 ) file->max_isom_version = 6; } } return 0; } else if( major_brand == 0 ) { major_brand = brands[0]; lsmash_log( NULL, LSMASH_LOG_WARNING, "major_brand is not specified. Use the first brand in the compatible brand list as major_brand.\n" ); } else if( !brands ) brand_count = 0; isom_ftyp_t *ftyp; if( file->flags & LSMASH_FILE_MODE_INITIALIZATION ) { /* Add File Type Box if absent yet. */ if( !file->ftyp && !isom_add_ftyp( file ) ) return LSMASH_ERR_NAMELESS; ftyp = file->ftyp; } else { /* Add Segment Type Box if absent yet. */ ftyp = file->styp_list.head && file->styp_list.head->data ? (isom_styp_t *)file->styp_list.head->data : isom_add_styp( file ); if( !ftyp ) return LSMASH_ERR_NAMELESS; } /* Allocate an array of compatible brands. * ISO/IEC 14496-12 doesn't forbid the absence of brands in the compatible brand list. * For a reason of safety, however, we set at least one brand in the list. */ size_t alloc_size = (brand_count ? brand_count : 1) * sizeof(uint32_t); lsmash_brand_type *compatible_brands; if( !file->compatible_brands ) compatible_brands = lsmash_malloc( alloc_size ); else compatible_brands = lsmash_realloc( file->compatible_brands, alloc_size ); if( !compatible_brands ) return LSMASH_ERR_MEMORY_ALLOC; /* Set compatible brands. */ if( brand_count ) for( uint32_t i = 0; i < brand_count; i++ ) compatible_brands[i] = brands[i]; else { /* At least one compatible brand. */ compatible_brands[0] = major_brand; brand_count = 1; } file->compatible_brands = compatible_brands; /* Duplicate an array of compatible brands. */ lsmash_free( ftyp->compatible_brands ); ftyp->compatible_brands = lsmash_memdup( compatible_brands, alloc_size ); if( !ftyp->compatible_brands ) { lsmash_freep( &file->compatible_brands ); return LSMASH_ERR_MEMORY_ALLOC; } ftyp->size = ISOM_BASEBOX_COMMON_SIZE + 8 + brand_count * 4; ftyp->major_brand = major_brand; ftyp->minor_version = minor_version; ftyp->brand_count = brand_count; file->brand_count = brand_count; return isom_check_compatibility( file ); }
static int vc1_analyze_whole_stream ( importer_t *importer ) { /* Parse all EBDU in the stream for preparation of calculating timestamps. */ uint32_t cts_alloc = (1 << 12) * sizeof(uint64_t); uint64_t *cts = lsmash_malloc( cts_alloc ); if( !cts ) return LSMASH_ERR_MEMORY_ALLOC; /* Failed to allocate CTS list */ uint32_t num_access_units = 0; uint32_t num_consecutive_b = 0; lsmash_class_t *logger = &(lsmash_class_t){ "VC-1" }; lsmash_log( &logger, LSMASH_LOG_INFO, "Analyzing stream as VC-1\r" ); vc1_importer_t *vc1_imp = (vc1_importer_t *)importer->info; vc1_info_t *info = &vc1_imp->info; importer->status = IMPORTER_OK; int err; while( importer->status != IMPORTER_EOF ) { #if 0 lsmash_log( &logger, LSMASH_LOG_INFO, "Analyzing stream as VC-1: %"PRIu32"\n", num_access_units + 1 ); #endif if( (err = vc1_importer_get_access_unit_internal( importer, 1 )) < 0 ) goto fail; vc1_importer_check_eof( importer, &info->access_unit ); /* In the case where B-pictures exist * Decode order * I[0]P[1]P[2]B[3]B[4]P[5]... * DTS * 0 1 2 3 4 5 ... * Composition order * I[0]P[1]B[3]B[4]P[2]P[5]... * CTS * 1 2 3 4 5 6 ... * We assumes B or BI-pictures always be present in the stream here. */ if( !info->access_unit.disposable ) { /* Apply CTS of the last B-picture plus 1 to the last non-B-picture. */ if( num_access_units > num_consecutive_b ) cts[ num_access_units - num_consecutive_b - 1 ] = num_access_units; num_consecutive_b = 0; } else /* B or BI-picture */ { /* B and BI-pictures shall be output or displayed in the same order as they are encoded. */ cts[ num_access_units ] = num_access_units; ++num_consecutive_b; info->dvc1_param.bframe_present = 1; } if( cts_alloc <= num_access_units * sizeof(uint64_t) ) { uint32_t alloc = 2 * num_access_units * sizeof(uint64_t); uint64_t *temp = lsmash_realloc( cts, alloc ); if( !temp ) { err = LSMASH_ERR_MEMORY_ALLOC; goto fail; /* Failed to re-allocate CTS list */ } cts = temp; cts_alloc = alloc; } vc1_imp->max_au_length = LSMASH_MAX( info->access_unit.data_length, vc1_imp->max_au_length ); ++num_access_units; } if( num_access_units > num_consecutive_b ) cts[ num_access_units - num_consecutive_b - 1 ] = num_access_units; else { err = LSMASH_ERR_INVALID_DATA; goto fail; } /* Construct timestamps. */ lsmash_media_ts_t *timestamp = lsmash_malloc( num_access_units * sizeof(lsmash_media_ts_t) ); if( !timestamp ) { err = LSMASH_ERR_MEMORY_ALLOC; goto fail; /* Failed to allocate timestamp list */ } for( uint32_t i = 1; i < num_access_units; i++ ) if( cts[i] < cts[i - 1] ) { vc1_imp->composition_reordering_present = 1; break; } if( vc1_imp->composition_reordering_present ) for( uint32_t i = 0; i < num_access_units; i++ ) { timestamp[i].cts = cts[i]; timestamp[i].dts = i; } else for( uint32_t i = 0; i < num_access_units; i++ ) timestamp[i].cts = timestamp[i].dts = i; lsmash_free( cts ); lsmash_log_refresh_line( &logger ); #if 0 for( uint32_t i = 0; i < num_access_units; i++ ) fprintf( stderr, "Timestamp[%"PRIu32"]: DTS=%"PRIu64", CTS=%"PRIu64"\n", i, timestamp[i].dts, timestamp[i].cts ); #endif vc1_imp->ts_list.sample_count = num_access_units; vc1_imp->ts_list.timestamp = timestamp; return 0; fail: lsmash_log_refresh_line( &logger ); lsmash_free( cts ); return err; }