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; }
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; }
void lsmash_cleanup_summary( lsmash_summary_t *summary ) { if( !summary ) return; if( summary->opaque ) { for( lsmash_entry_t *entry = summary->opaque->list.head; entry; ) { lsmash_entry_t *next = entry->next; lsmash_destroy_codec_specific_data( (lsmash_codec_specific_t *)entry->data ); lsmash_free( entry ); entry = next; } lsmash_free( summary->opaque ); } lsmash_free( summary ); }
/* 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 write_headers( hnd_t handle, x264_nal_t *p_nal ) { mp4_hnd_t *p_mp4 = handle; uint32_t sps_size = p_nal[0].i_payload - H264_NALU_LENGTH_SIZE; uint32_t pps_size = p_nal[1].i_payload - H264_NALU_LENGTH_SIZE; uint32_t sei_size = p_nal[2].i_payload; uint8_t *sps = p_nal[0].p_payload + H264_NALU_LENGTH_SIZE; uint8_t *pps = p_nal[1].p_payload + H264_NALU_LENGTH_SIZE; uint8_t *sei = p_nal[2].p_payload; lsmash_codec_specific_t *cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED ); lsmash_h264_specific_parameters_t *param = (lsmash_h264_specific_parameters_t *)cs->data.structured; param->lengthSizeMinusOne = H264_NALU_LENGTH_SIZE - 1; /* SPS * The remaining parameters are automatically set by SPS. */ if( lsmash_append_h264_parameter_set( param, H264_PARAMETER_SET_TYPE_SPS, sps, sps_size ) ) { MP4_LOG_ERROR( "failed to append SPS.\n" ); return -1; } /* PPS */ if( lsmash_append_h264_parameter_set( param, H264_PARAMETER_SET_TYPE_PPS, pps, pps_size ) ) { MP4_LOG_ERROR( "failed to append PPS.\n" ); return -1; } if( lsmash_add_codec_specific_data( (lsmash_summary_t *)p_mp4->summary, cs ) ) { MP4_LOG_ERROR( "failed to add H.264 specific info.\n" ); return -1; } lsmash_destroy_codec_specific_data( cs ); /* Additional extensions */ /* Bitrate info */ cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED ); if( cs ) lsmash_add_codec_specific_data( (lsmash_summary_t *)p_mp4->summary, cs ); lsmash_destroy_codec_specific_data( cs ); p_mp4->i_sample_entry = lsmash_add_sample_entry( p_mp4->p_root, p_mp4->i_track, p_mp4->summary ); MP4_FAIL_IF_ERR( !p_mp4->i_sample_entry, "failed to add sample entry for video.\n" ); /* SEI */ p_mp4->p_sei_buffer = malloc( sei_size ); MP4_FAIL_IF_ERR( !p_mp4->p_sei_buffer, "failed to allocate sei transition buffer.\n" ); memcpy( p_mp4->p_sei_buffer, sei, sei_size ); p_mp4->i_sei_size = sei_size; return sei_size + sps_size + pps_size; }
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; }