📄 mp4.c
字号:
p_soun = p_sample->data.p_sample_soun; if( p_soun->i_qt_version == 0 ) { switch( p_sample->i_type ) { case VLC_FOURCC( 'i', 'm', 'a', '4' ): p_soun->i_qt_version = 1; p_soun->i_sample_per_packet = 64; p_soun->i_bytes_per_packet = 34; p_soun->i_bytes_per_frame = 34 * p_soun->i_channelcount; p_soun->i_bytes_per_sample = 2; break; case VLC_FOURCC( 'M', 'A', 'C', '3' ): p_soun->i_qt_version = 1; p_soun->i_sample_per_packet = 6; p_soun->i_bytes_per_packet = 2; p_soun->i_bytes_per_frame = 2 * p_soun->i_channelcount; p_soun->i_bytes_per_sample = 2; break; case VLC_FOURCC( 'M', 'A', 'C', '6' ): p_soun->i_qt_version = 1; p_soun->i_sample_per_packet = 12; p_soun->i_bytes_per_packet = 2; p_soun->i_bytes_per_frame = 2 * p_soun->i_channelcount; p_soun->i_bytes_per_sample = 2; break; default: break; } } else if( p_soun->i_qt_version == 1 && p_soun->i_sample_per_packet <= 0 ) { p_soun->i_qt_version = 0; } } /* It's a little ugly but .. there are special cases */ switch( p_sample->i_type ) { case( VLC_FOURCC( '.', 'm', 'p', '3' ) ): case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ): p_track->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' ); break; case( VLC_FOURCC( 'r', 'a', 'w', ' ' ) ): p_track->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' ); break; case( VLC_FOURCC( 's', '2', '6', '3' ) ): p_track->fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '3' ); break; default: p_track->fmt.i_codec = p_sample->i_type; break; } /* now see if esds is present and if so create a data packet with decoder_specific_info */#define p_decconfig p_esds->data.p_esds->es_descriptor.p_decConfigDescr if( ( ( p_esds = MP4_BoxGet( p_sample, "esds" ) ) || ( p_esds = MP4_BoxGet( p_sample, "wave/esds" ) ) )&& ( p_esds->data.p_esds )&& ( p_decconfig ) ) { /* First update information based on i_objectTypeIndication */ switch( p_decconfig->i_objectTypeIndication ) { case( 0x20 ): /* MPEG4 VIDEO */ p_track->fmt.i_codec = VLC_FOURCC( 'm','p','4','v' ); break; case( 0x40): p_track->fmt.i_codec = VLC_FOURCC( 'm','p','4','a' ); break; case( 0x60): case( 0x61): case( 0x62): case( 0x63): case( 0x64): case( 0x65): /* MPEG2 video */ p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','v' ); break; /* Theses are MPEG2-AAC */ case( 0x66): /* main profile */ case( 0x67): /* Low complexity profile */ case( 0x68): /* Scaleable Sampling rate profile */ p_track->fmt.i_codec = VLC_FOURCC( 'm','p','4','a' ); break; /* true MPEG 2 audio */ case( 0x69): p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','a' ); break; case( 0x6a): /* MPEG1 video */ p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','v' ); break; case( 0x6b): /* MPEG1 audio */ p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','a' ); break; case( 0x6c ): /* jpeg */ p_track->fmt.i_codec = VLC_FOURCC( 'j','p','e','g' ); break; default: /* Unknown entry, but don't touch i_fourcc */ msg_Warn( p_input, "unknown objectTypeIndication(0x%x) (Track[ID 0x%x])", p_decconfig->i_objectTypeIndication, p_track->i_track_ID ); break; } p_track->fmt.i_extra = p_decconfig->i_decoder_specific_info_len; if( p_track->fmt.i_extra > 0 ) { p_track->fmt.p_extra = malloc( p_track->fmt.i_extra ); memcpy( p_track->fmt.p_extra, p_decconfig->p_decoder_specific_info, p_track->fmt.i_extra ); } } else { switch( p_sample->i_type ) { /* qt decoder, send the complete chunk */ case VLC_FOURCC( 'S', 'V', 'Q', '3' ): case VLC_FOURCC( 'S', 'V', 'Q', '1' ): case VLC_FOURCC( 'V', 'P', '3', '1' ): case VLC_FOURCC( '3', 'I', 'V', '1' ): case VLC_FOURCC( 'Z', 'y', 'G', 'o' ): p_track->fmt.i_extra = p_sample->data.p_sample_vide->i_qt_image_description; if( p_track->fmt.i_extra > 0 ) { p_track->fmt.p_extra = malloc( p_track->fmt.i_extra ); memcpy( p_track->fmt.p_extra, p_sample->data.p_sample_vide->p_qt_image_description, p_track->fmt.i_extra); } break; case VLC_FOURCC( 'Q', 'D', 'M', 'C' ): case VLC_FOURCC( 'Q', 'D', 'M', '2' ): case VLC_FOURCC( 'Q', 'c', 'l', 'p' ): case VLC_FOURCC( 's', 'a', 'm', 'r' ): p_track->fmt.i_extra = p_sample->data.p_sample_soun->i_qt_description; if( p_track->fmt.i_extra > 0 ) { p_track->fmt.p_extra = malloc( p_track->fmt.i_extra ); memcpy( p_track->fmt.p_extra, p_sample->data.p_sample_soun->p_qt_description, p_track->fmt.i_extra); } break; default: break; } }#undef p_decconfig /* some last initialisation */ switch( p_track->fmt.i_cat ) { case( VIDEO_ES ): p_track->fmt.video.i_width = p_sample->data.p_sample_vide->i_width; p_track->fmt.video.i_height = p_sample->data.p_sample_vide->i_height; /* fall on display size */ if( p_track->fmt.video.i_width <= 0 ) p_track->fmt.video.i_width = p_track->i_width; if( p_track->fmt.video.i_height <= 0 ) p_track->fmt.video.i_height = p_track->i_height; /* Find out apect ratio from display size */ if( p_track->i_width > 0 && p_track->i_height > 0 ) p_track->fmt.video.i_aspect = VOUT_ASPECT_FACTOR * p_track->i_width / p_track->i_height; break; case( AUDIO_ES ): p_track->fmt.audio.i_channels = p_sample->data.p_sample_soun->i_channelcount; p_track->fmt.audio.i_rate = p_sample->data.p_sample_soun->i_sampleratehi; p_track->fmt.i_bitrate = p_sample->data.p_sample_soun->i_channelcount * p_sample->data.p_sample_soun->i_sampleratehi * p_sample->data.p_sample_soun->i_samplesize; p_track->fmt.audio.i_bitspersample = p_sample->data.p_sample_soun->i_samplesize; break; default: break; } *pp_es = es_out_Add( p_input->p_es_out, &p_track->fmt ); return VLC_SUCCESS;}/* given a time it return sample/chunk * it also update elst field of the track */static int TrackTimeToSampleChunk( input_thread_t *p_input, mp4_track_t *p_track, int64_t i_start, uint32_t *pi_chunk, uint32_t *pi_sample ){ demux_sys_t *p_sys = p_input->p_demux_data; MP4_Box_t *p_stss; uint64_t i_dts; unsigned int i_sample; unsigned int i_chunk; int i_index; /* FIXME see if it's needed to check p_track->i_chunk_count */ if( !p_track->b_ok || p_track->i_chunk_count == 0 ) { return( VLC_EGENERIC ); } /* handle elst (find the correct one) */ MP4_TrackSetELST( p_input, p_track, i_start ); if( p_track->p_elst && p_track->p_elst->data.p_elst->i_entry_count > 0 ) { MP4_Box_data_elst_t *elst = p_track->p_elst->data.p_elst; int64_t i_mvt= i_start * p_sys->i_timescale / (int64_t)1000000; /* now calculate i_start for this elst */ /* offset */ i_start -= p_track->i_elst_time * (int64_t)1000000 / p_sys->i_timescale; if( i_start < 0 ) { *pi_chunk = 0; *pi_sample= 0; return VLC_SUCCESS; } /* to track time scale */ i_start = i_start * p_track->i_timescale / (int64_t)1000000; /* add elst offset */ if( ( elst->i_media_rate_integer[p_track->i_elst] > 0 || elst->i_media_rate_fraction[p_track->i_elst] > 0 ) && elst->i_media_time[p_track->i_elst] > 0 ) { i_start += elst->i_media_time[p_track->i_elst]; } msg_Dbg( p_input, "elst (%d) gives "I64Fd"ms (movie)-> "I64Fd"ms (track)", p_track->i_elst, i_mvt * 1000 / p_sys->i_timescale, i_start * 1000 / p_track->i_timescale ); } else { /* convert absolute time to in timescale unit */ i_start = i_start * p_track->i_timescale / (int64_t)1000000; } /* we start from sample 0/chunk 0, hope it won't take too much time */ /* *** find good chunk *** */ for( i_chunk = 0; ; i_chunk++ ) { if( i_chunk + 1 >= p_track->i_chunk_count ) { /* at the end and can't check if i_start in this chunk, it will be check while searching i_sample */ i_chunk = p_track->i_chunk_count - 1; break; } if( i_start >= p_track->chunk[i_chunk].i_first_dts && i_start < p_track->chunk[i_chunk + 1].i_first_dts ) { break; } } /* *** find sample in the chunk *** */ i_sample = p_track->chunk[i_chunk].i_sample_first; i_dts = p_track->chunk[i_chunk].i_first_dts; for( i_index = 0; i_sample < p_track->chunk[i_chunk].i_sample_count; ) { if( i_dts + p_track->chunk[i_chunk].p_sample_count_dts[i_index] * p_track->chunk[i_chunk].p_sample_delta_dts[i_index] < i_start ) { i_dts += p_track->chunk[i_chunk].p_sample_count_dts[i_index] * p_track->chunk[i_chunk].p_sample_delta_dts[i_index]; i_sample += p_track->chunk[i_chunk].p_sample_count_dts[i_index]; i_index++; } else { if( p_track->chunk[i_chunk].p_sample_delta_dts[i_index] <= 0 ) { break; } i_sample += ( i_start - i_dts ) / p_track->chunk[i_chunk].p_sample_delta_dts[i_index]; break; } } if( i_sample >= p_track->i_sample_count ) { msg_Warn( p_input, "track[Id 0x%x] will be disabled (seeking too far) chunk=%d sample=%d", p_track->i_track_ID, i_chunk, i_sample ); return( VLC_EGENERIC ); } /* *** Try to find nearest sync points *** */ if( ( p_stss = MP4_BoxGet( p_track->p_stbl, "stss" ) ) ) { unsigned int i_index; msg_Dbg( p_input, "track[Id 0x%x] using Sync Sample Box (stss)", p_track->i_track_ID ); for( i_index = 0; i_index < p_stss->data.p_stss->i_entry_count; i_index++ ) { if( p_stss->data.p_stss->i_sample_number[i_index] >= i_sample ) { if( i_index > 0 ) { msg_Dbg( p_input, "stts gives %d --> %d (sample number)", i_sample, p_stss->data.p_stss->i_sample_number[i_index-1] ); i_sample = p_stss->data.p_stss->i_sample_number[i_index-1]; /* new i_sample is less than old so i_chunk can only decreased */ while( i_chunk > 0 && i_sample < p_track->chunk[i_chunk].i_sample_first ) { i_chunk--; } } else { msg_Dbg( p_input, "stts gives %d --> %d (sample number)", i_sample, p_stss->data.p_stss->i_sample_number[i_index] ); i_sample = p_stss->data.p_stss->i_sample_number[i_index]; /* new i_sample is more than old so i_chunk can only increased */ while( i_chunk < p_track->i_chunk_count - 1 && i_sample >= p_track->chunk[i_chunk].i_sample_first + p_track->chunk[i_chunk].i_sample_count ) { i_chunk++; } } break; } } } else { msg_Dbg( p_input, "track[Id 0x%x] does not provide Sync Sample Box (stss)", p_track->i_track_ID ); } *pi_chunk = i_chunk; *pi_sample = i_sample; return VLC_SUCCESS;}static int TrackGotoChunkSample( input_thread_t *p_input, mp4_track_t *p_track, unsigned int i_chunk, unsigned int i_sample ){ vlc_bool_t b_reselect = VLC_FALSE; /* now see if actual es is ok */ if( p_track->i_chunk < 0 || p_track->i_chunk >= p_track->i_chunk_count || p_track->chunk[p_track->i_chunk].i_sample_description_index != p_track->chunk[i_chunk].i_sample_description_index ) { msg_Warn( p_input, "recreate ES" ); es_out_Control( p_input->p_es_out, ES_OUT_GET_ES_STATE, p_track->p_es, &b_reselect ); es_out_Del( p_input->p_es_out, p_track->p_es ); p_track->p_es = NULL; if( TrackCreateES( p_input, p_track, i_chunk, &p_track->p_es ) ) { msg_Err( p_input, "cannot create es for track[Id 0x%x]", p_track->i_track_ID ); p_track->b_ok = VLC_FALSE; p_track->b_selected = VLC_FALSE; return VLC_EGENERIC; } } /* select again the new decoder */ if( b_reselect ) { es_out_Control( p_input->p_es_out, ES_OUT_SET_ES, p_track->p_es ); } p_track->i_chunk = i_chunk; p_track->i_sample = i_sample; return p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC;}/**************************************************************************** * MP4_TrackCreate: **************************************************************************** * Parse track information and create all needed data to run a track * If it succeed b_ok is set to 1 else to 0 ****************************************************************************/static void MP4_TrackCreate( input_thread_t *p_input, mp4_track_t *p_track, MP4_Box_t * p_box_trak ){ demux_sys_t *p_sys = p_input->p_demux_data; MP4_Box_t *p_tkhd = MP4_BoxGet( p_box_trak, "tkhd" ); MP4_Box_t *p_tref = MP4_BoxGet( p_box_trak, "tref" ); MP4_Box_t *p_elst; MP4_Box_t *p_mdhd; MP4_Box_t *p_hdlr; MP4_Box_t *p_vmhd; MP4_Box_t *p_smhd; MP4_Box_t *p_drms; unsigned int i; char language[4]; /* hint track unsuported */ /* set default value (-> track unusable) */ p_track->b_ok = VLC_FALSE; p_track->b_enable = VLC_FALSE; p_track->b_selected = VLC_FALSE; es_format_Init( &p_track->fmt, UNKNOWN_ES, 0 ); if( !p_tkhd ) { return; } /* do we launch this track by default ? */ p_track->b_enable = ( ( p_tkhd->data.p_tkhd->i_flags&MP4_TRACK_ENABLED ) != 0 ); p_track->i_track_ID = p_tkhd->data.p_tkhd->i_track_ID;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -