static int isom_add_chpl_entry( isom_chpl_t *chpl, isom_chapter_entry_t *chap_data ) { if( !chap_data->chapter_name || !chpl || !chpl->list ) return LSMASH_ERR_FUNCTION_PARAM; isom_chpl_entry_t *data = lsmash_malloc( sizeof(isom_chpl_entry_t) ); if( !data ) return LSMASH_ERR_MEMORY_ALLOC; data->start_time = chap_data->start_time; data->chapter_name_length = strlen( chap_data->chapter_name ); data->chapter_name = (char *)lsmash_malloc( data->chapter_name_length + 1 ); if( !data->chapter_name ) { lsmash_free( data ); return LSMASH_ERR_MEMORY_ALLOC; } memcpy( data->chapter_name, chap_data->chapter_name, data->chapter_name_length ); data->chapter_name[ data->chapter_name_length ] = '\0'; if( lsmash_add_entry( chpl->list, data ) < 0 ) { lsmash_free( data->chapter_name ); lsmash_free( data ); return LSMASH_ERR_MEMORY_ALLOC; } return 0; }
static int dts_importer_probe( importer_t *importer ) { dts_importer_t *dts_imp = create_dts_importer( importer ); if( !dts_imp ) return LSMASH_ERR_MEMORY_ALLOC; lsmash_bits_t *bits = dts_imp->info.bits; lsmash_bs_t *bs = bits->bs; bs->buffer.max_size = DTS_MAX_EXSS_SIZE; importer->info = dts_imp; int err = dts_importer_get_next_accessunit_internal( importer ); if( err < 0 ) goto fail; lsmash_audio_summary_t *summary = dts_create_summary( &dts_imp->info ); if( !summary ) { err = LSMASH_ERR_NAMELESS; goto fail; } if( importer->status != IMPORTER_EOF ) importer->status = IMPORTER_OK; dts_imp->au_number = 0; if( lsmash_add_entry( importer->summaries, summary ) < 0 ) { lsmash_cleanup_summary( (lsmash_summary_t *)summary ); err = LSMASH_ERR_MEMORY_ALLOC; goto fail; } return 0; fail: remove_dts_importer( dts_imp ); importer->info = NULL; return err; }
static lsmash_video_summary_t *vc1_create_summary( vc1_info_t *info, vc1_sequence_header_t *sequence, uint32_t max_au_length ) { if( !info->sequence.present || !info->entry_point.present ) return NULL; lsmash_video_summary_t *summary = (lsmash_video_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_VIDEO ); if( !summary ) return NULL; lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED ); specific->data.unstructured = lsmash_create_vc1_specific_info( &info->dvc1_param, &specific->size ); if( !specific->data.unstructured || lsmash_add_entry( &summary->opaque->list, specific ) < 0 ) { lsmash_cleanup_summary( (lsmash_summary_t *)summary ); lsmash_destroy_codec_specific_data( specific ); return NULL; } summary->sample_type = ISOM_CODEC_TYPE_VC_1_VIDEO; summary->max_au_length = max_au_length; summary->timescale = sequence->framerate_numerator; summary->timebase = sequence->framerate_denominator; summary->vfr = !sequence->framerate_flag; summary->sample_per_field = 0; summary->width = sequence->disp_horiz_size; summary->height = sequence->disp_vert_size; summary->par_h = sequence->aspect_width; summary->par_v = sequence->aspect_height; summary->color.primaries_index = sequence->color_prim; summary->color.transfer_index = sequence->transfer_char; summary->color.matrix_index = sequence->matrix_coef; return summary; }
static int vc1_importer_probe( importer_t *importer ) { /* Find the first start code. */ vc1_importer_t *vc1_imp = create_vc1_importer( importer ); if( !vc1_imp ) return LSMASH_ERR_MEMORY_ALLOC; lsmash_bs_t *bs = importer->bs; uint64_t first_ebdu_head_pos = 0; int err; while( 1 ) { /* The first EBDU in decoding order of the stream shall have start code (0x000001). */ if( 0x000001 == lsmash_bs_show_be24( bs, first_ebdu_head_pos ) ) break; /* Invalid if encountered any value of non-zero before the first start code. */ if( lsmash_bs_show_byte( bs, first_ebdu_head_pos ) ) { err = LSMASH_ERR_INVALID_DATA; goto fail; } ++first_ebdu_head_pos; } /* OK. It seems the stream has a sequence header of VC-1. */ importer->info = vc1_imp; vc1_info_t *info = &vc1_imp->info; lsmash_bs_read_seek( bs, first_ebdu_head_pos, SEEK_SET ); info->ebdu_head_pos = first_ebdu_head_pos; if( (err = vc1_analyze_whole_stream( importer )) < 0 ) goto fail; lsmash_video_summary_t *summary = vc1_create_summary( info, &vc1_imp->first_sequence, vc1_imp->max_au_length ); if( !summary ) { err = LSMASH_ERR_NAMELESS; goto fail; } if( lsmash_add_entry( importer->summaries, summary ) < 0 ) { lsmash_cleanup_summary( (lsmash_summary_t *)summary ); err = LSMASH_ERR_MEMORY_ALLOC; goto fail; } /* Go back to layer of the first EBDU. */ importer->status = IMPORTER_OK; lsmash_bs_read_seek( bs, first_ebdu_head_pos, SEEK_SET ); info->prev_bdu_type = 0xFF; /* 0xFF is a forbidden value. */ info->ebdu_head_pos = first_ebdu_head_pos; uint8_t *temp_access_unit = info->access_unit.data; uint8_t *temp_incomplete_access_unit = info->access_unit.incomplete_data; memset( &info->access_unit, 0, sizeof(vc1_access_unit_t) ); info->access_unit.data = temp_access_unit; info->access_unit.incomplete_data = temp_incomplete_access_unit; memset( &info->picture, 0, sizeof(vc1_picture_info_t) ); return 0; fail: remove_vc1_importer( vc1_imp ); importer->info = NULL; lsmash_remove_entries( importer->summaries, lsmash_cleanup_summary ); return err; }
int lsmash_add_codec_specific_data( lsmash_summary_t *summary, lsmash_codec_specific_t *specific ) { if( !summary || !summary->opaque || !specific ) return LSMASH_ERR_FUNCTION_PARAM; lsmash_codec_specific_t *dup = isom_duplicate_codec_specific_data( specific ); if( !dup ) return LSMASH_ERR_NAMELESS; if( lsmash_add_entry( &summary->opaque->list, dup ) < 0 ) { lsmash_destroy_codec_specific_data( dup ); return LSMASH_ERR_MEMORY_ALLOC; } return 0; }
/* create AudioSpecificConfig as memory block from summary, and set it into that summary itself */ int lsmash_setup_AudioSpecificConfig( lsmash_audio_summary_t *summary ) { if( !summary || !summary->opaque ) return LSMASH_ERR_FUNCTION_PARAM; /* Remove an old one. */ for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next ) { lsmash_codec_specific_t *cs = (lsmash_codec_specific_t *)entry->data; if( !cs || cs->type != LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG ) continue; lsmash_remove_entry_direct( &summary->opaque->list, entry, lsmash_destroy_codec_specific_data ); } /* Create and add a new one. */ uint32_t data_length; uint8_t *data = mp4a_export_AudioSpecificConfig( summary->aot, summary->frequency, summary->channels, summary->sbr_mode, NULL, /* FIXME */ 0, /* FIXME */ &data_length ); if( !data ) return LSMASH_ERR_NAMELESS; lsmash_codec_specific_t *cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED ); if( !cs ) { lsmash_free( data ); return LSMASH_ERR_MEMORY_ALLOC; } lsmash_mp4sys_decoder_parameters_t *param = (lsmash_mp4sys_decoder_parameters_t *)cs->data.structured; param->objectTypeIndication = MP4SYS_OBJECT_TYPE_Audio_ISO_14496_3; param->streamType = MP4SYS_STREAM_TYPE_AudioStream; int err = lsmash_set_mp4sys_decoder_specific_info( param, data, data_length ); lsmash_free( data ); if( err < 0 || (err = lsmash_add_entry( &summary->opaque->list, cs )) < 0 ) { lsmash_destroy_codec_specific_data( cs ); return err; } return 0; }
static int wave_importer_probe( importer_t *importer ) { wave_importer_t *wave_imp = create_wave_importer( importer ); if( !wave_imp ) return LSMASH_ERR_MEMORY_ALLOC; int err = 0; uint32_t filesize; lsmash_bs_t *bs = importer->bs; if( lsmash_bs_get_be32( bs ) != LSMASH_4CC( 'R', 'I', 'F', 'F' ) || ((filesize = lsmash_bs_get_le32( bs ) + 8) < WAVE_MIN_FILESIZE && filesize > 8) || lsmash_bs_get_be32( bs ) != LSMASH_4CC( 'W', 'A', 'V', 'E' ) ) { err = LSMASH_ERR_INVALID_DATA; goto fail; } int fmt_chunk_present = 0; int data_chunk_present = 0; while( !bs->eob && !(fmt_chunk_present && data_chunk_present) ) { uint32_t ckID = lsmash_bs_get_be32( bs ); uint32_t ckSize = lsmash_bs_get_le32( bs ); lsmash_bs_reset_counter( bs ); switch( ckID ) { case LSMASH_4CC( 'f', 'm', 't', ' ' ) : if( ckSize < 16 ) { err = LSMASH_ERR_INVALID_DATA; goto fail; } if( (err = wave_parse_fmt_chunk( wave_imp, bs )) < 0 ) goto fail; fmt_chunk_present = 1; break; case LSMASH_4CC( 'd', 'a', 't', 'a' ) : if( !fmt_chunk_present ) { /* The 'fmt ' chunk must be present before the 'data' chunk. */ err = LSMASH_ERR_INVALID_DATA; goto fail; } wave_imp->chunk.data_offset = lsmash_bs_get_stream_pos( bs ); wave_imp->chunk.length = ckSize; wave_imp->chunk.number = 1; wave_imp->chunk.file = importer->file; wave_imp->number_of_samples = ckSize / wave_imp->fmt.wfx.nBlockAlign; data_chunk_present = 1; break; default : break; } if( !data_chunk_present ) { /* Skip the rest of this chunk. * Note that ckData is word-aligned even if ckSize is an odd number. */ uint32_t skip_size = ckSize; if( skip_size & 1 ) skip_size++; if( skip_size > lsmash_bs_count( bs ) ) { skip_size -= lsmash_bs_count( bs ); lsmash_bs_read_seek( bs, skip_size, SEEK_CUR ); } } } if( !(fmt_chunk_present && data_chunk_present) ) { err = LSMASH_ERR_INVALID_DATA; goto fail; } /* Make fake movie. * Treat WAVE file format as if it's QuickTime file format. */ uint32_t track_ID; lsmash_movie_parameters_t movie_param = { 0 }; lsmash_track_parameters_t track_param = { 0 }; lsmash_media_parameters_t media_param = { 0 }; importer->file->qt_compatible = 1; if( (err = lsmash_importer_make_fake_movie( importer )) < 0 || (err = lsmash_importer_make_fake_track( importer, ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK, &track_ID )) < 0 || (err = lsmash_get_movie_parameters( importer->root, &movie_param )) < 0 || (err = lsmash_get_track_parameters( importer->root, track_ID, &track_param )) < 0 || (err = lsmash_get_media_parameters( importer->root, track_ID, &media_param )) < 0 ) goto fail; movie_param.timescale = wave_imp->fmt.wfx.nSamplesPerSec; media_param.timescale = wave_imp->fmt.wfx.nSamplesPerSec; if( (err = lsmash_set_movie_parameters( importer->root, &movie_param )) < 0 || (err = lsmash_set_track_parameters( importer->root, track_ID, &track_param )) < 0 || (err = lsmash_set_media_parameters( importer->root, track_ID, &media_param )) < 0 ) goto fail; lsmash_audio_summary_t *summary = wave_create_summary( &wave_imp->fmt ); if( !summary || lsmash_add_sample_entry( importer->root, track_ID, summary ) != 1 ) { lsmash_cleanup_summary( (lsmash_summary_t *)summary ); err = LSMASH_ERR_NAMELESS; goto fail; } if( (err = lsmash_add_entry( importer->summaries, summary )) < 0 ) { lsmash_cleanup_summary( (lsmash_summary_t *)summary ); goto fail; } importer->info = wave_imp; importer->status = IMPORTER_OK; return 0; fail: lsmash_importer_break_fake_movie( importer ); remove_wave_importer( wave_imp ); importer->file->qt_compatible = 0; importer->info = NULL; return err; }
static lsmash_audio_summary_t *wave_create_summary( waveformat_extensible_t *fmt ) { lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO ); if( !summary ) return NULL; waveformat_extended_t *wfx = &fmt->wfx; summary->sample_type = QT_CODEC_TYPE_LPCM_AUDIO; summary->aot = MP4A_AUDIO_OBJECT_TYPE_NULL; summary->frequency = wfx->nSamplesPerSec; summary->channels = wfx->nChannels; summary->sample_size = wfx->wFormatTag == WAVE_FORMAT_TYPE_ID_EXTENSIBLE ? fmt->Samples.wValidBitsPerSample : wfx->wBitsPerSample; summary->samples_in_frame = 1000; /* arbitrary */ summary->sbr_mode = MP4A_AAC_SBR_NOT_SPECIFIED; summary->bytes_per_frame = wfx->nBlockAlign * summary->samples_in_frame; summary->max_au_length = summary->bytes_per_frame; lsmash_codec_specific_t *cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED ); if( !cs ) goto fail; lsmash_qt_audio_format_specific_flags_t *lpcm = (lsmash_qt_audio_format_specific_flags_t *)cs->data.structured; if( (summary->sample_size & 7) == 0 ) lpcm->format_flags |= QT_AUDIO_FORMAT_FLAG_PACKED; else lpcm->format_flags |= QT_AUDIO_FORMAT_FLAG_ALIGNED_HIGH; if( summary->sample_size > 8 ) lpcm->format_flags |= QT_AUDIO_FORMAT_FLAG_SIGNED_INTEGER; if( lsmash_add_entry( &summary->opaque->list, cs ) < 0 ) { lsmash_destroy_codec_specific_data( cs ); goto fail; } if( wfx->wFormatTag == WAVE_FORMAT_TYPE_ID_EXTENSIBLE || wfx->nChannels > 2 ) { cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED ); if( !cs ) goto fail; lsmash_qt_audio_channel_layout_t *layout = (lsmash_qt_audio_channel_layout_t *)cs->data.structured; if( wfx->wFormatTag == WAVE_FORMAT_TYPE_ID_EXTENSIBLE ) { layout->channelLayoutTag = QT_CHANNEL_LAYOUT_USE_CHANNEL_BITMAP; layout->channelBitmap = fmt->dwChannelMask; } else { layout->channelLayoutTag = QT_CHANNEL_LAYOUT_UNKNOWN | wfx->nChannels; layout->channelBitmap = 0; } if( lsmash_add_entry( &summary->opaque->list, cs ) < 0 ) { lsmash_destroy_codec_specific_data( cs ); goto fail; } } return summary; fail: lsmash_cleanup_summary( (lsmash_summary_t *)summary ); return NULL; }
static lsmash_audio_summary_t *dts_create_summary( dts_info_t *info ) { lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO ); if( !summary ) return NULL; lsmash_dts_specific_parameters_t *param = &info->ddts_param; lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED ); specific->data.unstructured = lsmash_create_dts_specific_info( param, &specific->size ); if( !specific->data.unstructured || lsmash_add_entry( &summary->opaque->list, specific ) < 0 ) { lsmash_cleanup_summary( (lsmash_summary_t *)summary ); lsmash_destroy_codec_specific_data( specific ); return NULL; } /* The CODEC identifiers probably should not be the combination of 'mp4a' and * the objectTypeIndications for DTS audio since there is no public specification * which defines the encapsulation of the stream as the MPEG-4 Audio context yet. * In the world, there are muxers which is using such doubtful implementation. * The objectTypeIndications are registered at MP4RA, but this does not always * mean we can mux by using those objectTypeIndications. * If available, there shall be the specification which defines the existence of * DecoderSpecificInfo and its semantics, and what access unit consists of. */ summary->sample_type = lsmash_dts_get_codingname( param ); summary->aot = MP4A_AUDIO_OBJECT_TYPE_NULL; /* make no sense */ summary->sbr_mode = MP4A_AAC_SBR_NOT_SPECIFIED; /* make no sense */ switch( param->DTSSamplingFrequency ) { case 12000 : /* Invalid? (No reference in the spec) */ case 24000 : case 48000 : case 96000 : case 192000 : case 384000 : /* Invalid? (No reference in the spec) */ summary->frequency = 48000; break; case 22050 : case 44100 : case 88200 : case 176400 : case 352800 : /* Invalid? (No reference in the spec) */ summary->frequency = 44100; break; case 8000 : /* Invalid? (No reference in the spec) */ case 16000 : case 32000 : case 64000 : case 128000 : summary->frequency = 32000; break; default : summary->frequency = 0; break; } summary->samples_in_frame = (summary->frequency * info->frame_duration) / param->DTSSamplingFrequency; summary->max_au_length = DTS_MAX_CORE_SIZE + DTS_MAX_NUM_EXSS * DTS_MAX_EXSS_SIZE; summary->sample_size = param->pcmSampleDepth; summary->channels = dts_get_max_channel_count( info ); return summary; }