📄 mp4.c
字号:
continue; } if( !strncmp( psz_ref, "http://", 7 ) || !strncmp( psz_ref, "rtsp://", 7 ) ) { ; } else { char *psz_absolute; char *psz_path = strdup( p_demux->psz_path ); char *end = strrchr( psz_path, '/' ); if( end ) end[1] = '\0'; else *psz_path = '\0'; asprintf( &psz_absolute, "%s://%s%s", p_demux->psz_access, psz_path, psz_ref ); if( psz_ref ) free( psz_ref ); psz_ref = psz_absolute; free( psz_path ); } msg_Dbg( p_demux, "adding ref = `%s'", psz_ref ); if( p_item ) { playlist_item_t *p_child = playlist_ItemNew( p_playlist, psz_ref, psz_ref ); if( p_child ) { playlist_NodeAddItem( p_playlist, p_child, p_item->pp_parents[0]->i_view, p_item, PLAYLIST_APPEND, PLAYLIST_END ); playlist_CopyParents( p_item, p_child ); b_play = VLC_TRUE; } } } else { msg_Err( p_demux, "unknown ref type=%4.4s FIXME (send a bug report)", (char*)&p_rdrf->data.p_rdrf->i_ref_type ); } if( psz_ref ) free( psz_ref ); } if( b_play == VLC_TRUE ) { playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, p_playlist->status.i_view, p_playlist->status.p_item, NULL ); } vlc_object_release( p_playlist ); } else { msg_Err( p_demux, "can't find playlist" ); } } if( !(p_mvhd = MP4_BoxGet( p_sys->p_root, "/moov/mvhd" ) ) ) { if( !p_rmra ) { msg_Err( p_demux, "cannot find /moov/mvhd" ); goto error; } else { msg_Warn( p_demux, "cannot find /moov/mvhd (pure ref file)" ); p_demux->pf_demux = DemuxRef; return VLC_SUCCESS; } } else { p_sys->i_timescale = p_mvhd->data.p_mvhd->i_timescale; p_sys->i_duration = p_mvhd->data.p_mvhd->i_duration; } if( !( p_sys->i_tracks = MP4_BoxCount( p_sys->p_root, "/moov/trak" ) ) ) { msg_Err( p_demux, "cannot find any /moov/trak" ); goto error; } msg_Dbg( p_demux, "find %d track%c", p_sys->i_tracks, p_sys->i_tracks ? 's':' ' ); /* allocate memory */ p_sys->track = calloc( p_sys->i_tracks, sizeof( mp4_track_t ) ); memset( p_sys->track, 0, p_sys->i_tracks * sizeof( mp4_track_t ) ); /* now process each track and extract all usefull information */ for( i = 0; i < p_sys->i_tracks; i++ ) { p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[%d]", i ); MP4_TrackCreate( p_demux, &p_sys->track[i], p_trak ); if( p_sys->track[i].b_ok ) { char *psz_cat; switch( p_sys->track[i].fmt.i_cat ) { case( VIDEO_ES ): psz_cat = "video"; break; case( AUDIO_ES ): psz_cat = "audio"; break; case( SPU_ES ): psz_cat = "subtitle"; break; default: psz_cat = "unknown"; break; } msg_Dbg( p_demux, "adding track[Id 0x%x] %s (%s) language %s", p_sys->track[i].i_track_ID, psz_cat, p_sys->track[i].b_enable ? "enable":"disable", p_sys->track[i].fmt.psz_language ? p_sys->track[i].fmt.psz_language : "undef" ); } else { msg_Dbg( p_demux, "ignoring track[Id 0x%x]", p_sys->track[i].i_track_ID ); } } return VLC_SUCCESS;error: if( p_sys->p_root ) { MP4_BoxFree( p_demux->s, p_sys->p_root ); } free( p_sys ); return VLC_EGENERIC;}/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * TODO check for newly selected track (ie audio upt to now ) *****************************************************************************/static int Demux( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; unsigned int i_track; unsigned int i_track_selected; /* check for newly selected/unselected track */ for( i_track = 0, i_track_selected = 0; i_track < p_sys->i_tracks; i_track++ ) { mp4_track_t *tk = &p_sys->track[i_track]; vlc_bool_t b; if( !tk->b_ok || ( tk->b_selected && tk->i_sample >= tk->i_sample_count ) ) { continue; } es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b ); if( tk->b_selected && !b ) { MP4_TrackUnselect( p_demux, tk ); } else if( !tk->b_selected && b) { MP4_TrackSelect( p_demux, tk, MP4_GetMoviePTS( p_sys ) ); } if( tk->b_selected ) { i_track_selected++; } } if( i_track_selected <= 0 ) { p_sys->i_time += __MAX( p_sys->i_timescale / 10 , 1 ); if( p_sys->i_timescale > 0 ) { int64_t i_length = (mtime_t)1000000 * (mtime_t)p_sys->i_duration / (mtime_t)p_sys->i_timescale; if( MP4_GetMoviePTS( p_sys ) >= i_length ) return 0; return 1; } msg_Warn( p_demux, "no track selected, exiting..." ); return 0; } /* first wait for the good time to read a packet */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr + 1 ); p_sys->i_pcr = MP4_GetMoviePTS( p_sys ); /* we will read 100ms for each stream so ...*/ p_sys->i_time += __MAX( p_sys->i_timescale / 10 , 1 ); for( i_track = 0; i_track < p_sys->i_tracks; i_track++ ) { mp4_track_t *tk = &p_sys->track[i_track]; if( !tk->b_ok || !tk->b_selected || tk->i_sample >= tk->i_sample_count ) { continue; } while( MP4_TrackGetDTS( p_demux, tk ) < MP4_GetMoviePTS( p_sys ) ) {#if 0 msg_Dbg( p_demux, "tk(%i)=%lld mv=%lld", i_track, MP4_TrackGetDTS( p_demux, tk ), MP4_GetMoviePTS( p_sys ) );#endif if( MP4_TrackSampleSize( tk ) > 0 ) { block_t *p_block; int64_t i_delta; /* go,go go ! */ if( stream_Seek( p_demux->s, MP4_TrackGetPos( tk ) ) ) { msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)", tk->i_track_ID ); MP4_TrackUnselect( p_demux, tk ); break; } /* now read pes */ if( !(p_block = stream_Block( p_demux->s, MP4_TrackSampleSize(tk) )) ) { msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)", tk->i_track_ID ); MP4_TrackUnselect( p_demux, tk ); break; } if( tk->b_drms && tk->p_drms ) { drms_decrypt( tk->p_drms, (uint32_t*)p_block->p_buffer, p_block->i_buffer ); } else if( tk->fmt.i_cat == SPU_ES ) { if( tk->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) && p_block->i_buffer >= 2 ) { uint16_t i_size = GetWBE( p_block->p_buffer ); if( i_size + 2 <= p_block->i_buffer ) { char *p; /* remove the length field, and append a '\0' */ memmove( &p_block->p_buffer[0], &p_block->p_buffer[2], i_size ); p_block->p_buffer[i_size] = '\0'; p_block->i_buffer = i_size + 1; /* convert \r -> \n */ while( ( p = strchr( (char*)p_block->p_buffer, '\r' ) ) ) { *p = '\n'; } } else { /* Invalid */ p_block->i_buffer = 0; } } } /* dts */ p_block->i_dts = MP4_TrackGetDTS( p_demux, tk ) + 1; /* pts */ i_delta = MP4_TrackGetPTSDelta( p_demux, tk ); if( i_delta != -1 ) p_block->i_pts = p_block->i_dts + i_delta; else if( tk->fmt.i_cat != VIDEO_ES ) p_block->i_pts = p_block->i_dts; else p_block->i_pts = 0; if( !tk->b_drms || ( tk->b_drms && tk->p_drms ) ) es_out_Send( p_demux->out, tk->p_es, p_block ); } /* Next sample */ if( MP4_TrackNextSample( p_demux, tk ) ) { break; } } } return 1;}/***************************************************************************** * Seek: Got to i_date******************************************************************************/static int Seek( demux_t *p_demux, mtime_t i_date ){ demux_sys_t *p_sys = p_demux->p_sys; unsigned int i_track; /* First update update global time */ p_sys->i_time = i_date * p_sys->i_timescale / 1000000; p_sys->i_pcr = i_date; /* Now for each stream try to go to this time */ for( i_track = 0; i_track < p_sys->i_tracks; i_track++ ) { mp4_track_t *tk = &p_sys->track[i_track]; MP4_TrackSeek( p_demux, tk, i_date ); } return VLC_SUCCESS;}/***************************************************************************** * Control: *****************************************************************************/static int Control( demux_t *p_demux, int i_query, va_list args ){ demux_sys_t *p_sys = p_demux->p_sys; double f, *pf; int64_t i64, *pi64; switch( i_query ) { case DEMUX_GET_POSITION: pf = (double*)va_arg( args, double * ); if( p_sys->i_duration > 0 ) { *pf = (double)p_sys->i_time / (double)p_sys->i_duration; } else { *pf = 0.0; } return VLC_SUCCESS; case DEMUX_SET_POSITION: f = (double)va_arg( args, double ); if( p_sys->i_timescale > 0 ) { i64 = (int64_t)( f * (double)1000000 * (double)p_sys->i_duration / (double)p_sys->i_timescale ); return Seek( p_demux, i64 ); } else return VLC_SUCCESS; case DEMUX_GET_TIME: pi64 = (int64_t*)va_arg( args, int64_t * ); if( p_sys->i_timescale > 0 ) { *pi64 = (mtime_t)1000000 * (mtime_t)p_sys->i_time / (mtime_t)p_sys->i_timescale; } else *pi64 = 0; return VLC_SUCCESS; case DEMUX_SET_TIME: i64 = (int64_t)va_arg( args, int64_t ); return Seek( p_demux, i64 ); case DEMUX_GET_LENGTH:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -