X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=modules%2Fdemux%2Fmkv%2Fmkv.cpp;h=16d6b7d4180e4229e72a776414c49c68fdd7c387;hb=73160f1a9bd3b3fa666abdd0c65ad7a083ea3b93;hp=d0af0350a2069daae2f617232a01c01dc3dba696;hpb=7615bbd6b14d507de986486409795166ddcaa4cd;p=vlc diff --git a/modules/demux/mkv/mkv.cpp b/modules/demux/mkv/mkv.cpp index d0af0350a2..16d6b7d418 100644 --- a/modules/demux/mkv/mkv.cpp +++ b/modules/demux/mkv/mkv.cpp @@ -1,7 +1,7 @@ /***************************************************************************** * mkv.cpp : matroska demuxer ***************************************************************************** - * Copyright (C) 2003-2004 the VideoLAN team + * Copyright (C) 2003-2005, 2008, 2010 the VideoLAN team * $Id$ * * Authors: Laurent Aimar @@ -33,49 +33,51 @@ #include "stream_io_callback.hpp" +#include +#include + /***************************************************************************** * Module descriptor *****************************************************************************/ static int Open ( vlc_object_t * ); static void Close( vlc_object_t * ); -vlc_module_begin(); - set_shortname( "Matroska" ); - set_description( N_("Matroska stream demuxer" ) ); - set_capability( "demux", 0 ); - set_callbacks( Open, Close ); - set_category( CAT_INPUT ); - set_subcategory( SUBCAT_INPUT_DEMUX ); +vlc_module_begin () + set_shortname( "Matroska" ) + set_description( N_("Matroska stream demuxer" ) ) + set_capability( "demux", 50 ) + set_callbacks( Open, Close ) + set_category( CAT_INPUT ) + set_subcategory( SUBCAT_INPUT_DEMUX ) - add_bool( "mkv-use-ordered-chapters", 1, NULL, - N_("Ordered chapters"), - N_("Play ordered chapters as specified in the segment."), true ); + add_bool( "mkv-use-ordered-chapters", true, + N_("Respect ordered chapters"), + N_("Play chapters in the order specified in the segment."), false ); - add_bool( "mkv-use-chapter-codec", 1, NULL, + add_bool( "mkv-use-chapter-codec", true, N_("Chapter codecs"), N_("Use chapter codecs found in the segment."), true ); - add_bool( "mkv-preload-local-dir", 1, NULL, - N_("Preload Directory"), - N_("Preload matroska files from the same family in the same directory (not good for broken files)."), true ); + add_bool( "mkv-preload-local-dir", false, + N_("Preload MKV files in the same directory"), + N_("Preload matroska files in the same directory to find linked segments (not good for broken files)."), false ); - add_bool( "mkv-seek-percent", 0, NULL, + add_bool( "mkv-seek-percent", false, N_("Seek based on percent not time"), N_("Seek based on percent not time."), true ); - add_bool( "mkv-use-dummy", 0, NULL, + add_bool( "mkv-use-dummy", false, N_("Dummy Elements"), N_("Read and discard unknown EBML elements (not good for broken files)."), true ); - add_shortcut( "mka" ); - add_shortcut( "mkv" ); -vlc_module_end(); + add_shortcut( "mka", "mkv" ) +vlc_module_end () class demux_sys_t; static int Demux ( demux_t * ); static int Control( demux_t *, int, va_list ); -static void Seek ( demux_t *, mtime_t i_date, double f_percent, chapter_item_c *psz_chapter ); +static void Seek ( demux_t *, mtime_t i_date, double f_percent, virtual_chapter_c *p_chapter ); /***************************************************************************** * Open: initializes matroska demux structures @@ -122,8 +124,8 @@ static int Open( vlc_object_t * p_this ) } p_sys->streams.push_back( p_stream ); - p_stream->p_in = p_io_callback; - p_stream->p_es = p_io_stream; + p_stream->p_io_callback = p_io_callback; + p_stream->p_estream = p_io_stream; for (size_t i=0; isegments.size(); i++) { @@ -137,61 +139,57 @@ static int Open( vlc_object_t * p_this ) goto error; } - if (config_GetInt( p_demux, "mkv-preload-local-dir" )) + if (var_InheritBool( p_demux, "mkv-preload-local-dir" )) { /* get the files from the same dir from the same family (based on p_demux->psz_path) */ - if (p_demux->psz_path[0] != '\0' && !strcmp(p_demux->psz_access, "")) + if ( p_demux->psz_file && !strcmp( p_demux->psz_access, "file" ) ) { // assume it's a regular file // get the directory path - s_path = p_demux->psz_path; - if (s_path.at(s_path.length() - 1) == DIRECTORY_SEPARATOR) + s_path = p_demux->psz_file; + if (s_path.at(s_path.length() - 1) == DIR_SEP_CHAR) { s_path = s_path.substr(0,s_path.length()-1); } else { - if (s_path.find_last_of(DIRECTORY_SEPARATOR) > 0) + if (s_path.find_last_of(DIR_SEP_CHAR) > 0) { - s_path = s_path.substr(0,s_path.find_last_of(DIRECTORY_SEPARATOR)); + s_path = s_path.substr(0,s_path.find_last_of(DIR_SEP_CHAR)); } } - DIR *p_src_dir = utf8_opendir(s_path.c_str()); + DIR *p_src_dir = vlc_opendir(s_path.c_str()); if (p_src_dir != NULL) { char *psz_file; - while ((psz_file = utf8_readdir(p_src_dir)) != NULL) + while ((psz_file = vlc_readdir(p_src_dir)) != NULL) { if (strlen(psz_file) > 4) { - s_filename = s_path + DIRECTORY_SEPARATOR + psz_file; + s_filename = s_path + DIR_SEP_CHAR + psz_file; #ifdef WIN32 - if (!strcasecmp(s_filename.c_str(), p_demux->psz_path)) + if (!strcasecmp(s_filename.c_str(), p_demux->psz_file)) #else - if (!s_filename.compare(p_demux->psz_path)) + if (!s_filename.compare(p_demux->psz_file)) #endif { free (psz_file); continue; // don't reuse the original opened file } -#if defined(__GNUC__) && (__GNUC__ < 3) - if (!s_filename.compare("mkv", s_filename.length() - 3, 3) || - !s_filename.compare("mka", s_filename.length() - 3, 3)) -#else if (!s_filename.compare(s_filename.length() - 3, 3, "mkv") || !s_filename.compare(s_filename.length() - 3, 3, "mka")) -#endif { // test wether this file belongs to our family const uint8_t *p_peek; bool file_ok = false; + std::string s_url = make_URI( s_filename.c_str(), "file" ); stream_t *p_file_stream = stream_UrlNew( p_demux, - s_filename.c_str()); + s_url.c_str() ); /* peek the begining */ if( p_file_stream && stream_Peek( p_file_stream, &p_peek, 4 ) >= 4 @@ -213,8 +211,8 @@ static int Open( vlc_object_t * p_this ) } else { - p_stream->p_in = p_file_io; - p_stream->p_es = p_estream; + p_stream->p_io_callback = p_file_io; + p_stream->p_estream = p_estream; p_sys->streams.push_back( p_stream ); } } @@ -236,16 +234,15 @@ static int Open( vlc_object_t * p_this ) p_sys->PreloadFamily( *p_segment ); } - p_sys->PreloadLinked( p_segment ); - - if ( !p_sys->PreparePlayback( NULL ) ) + if ( !p_sys->PreloadLinked() || + !p_sys->PreparePlayback( NULL ) ) { msg_Err( p_demux, "cannot use the segment" ); goto error; } - p_sys->StartUiThread(); - + p_sys->InitUi(); + return VLC_SUCCESS; error: @@ -270,7 +267,7 @@ static void Close( vlc_object_t *p_this ) static int Control( demux_t *p_demux, int i_query, va_list args ) { demux_sys_t *p_sys = p_demux->p_sys; - int64_t *pi64; + int64_t *pi64, i64; double *pf, f; int i_skp; size_t i_idx; @@ -278,7 +275,6 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) vlc_meta_t *p_meta; input_attachment_t ***ppp_attach; int *pi_int; - int i; switch( i_query ) { @@ -294,11 +290,11 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) p_sys->stored_attachments.size() ); if( !(*ppp_attach) ) return VLC_ENOMEM; - for( i = 0; i < p_sys->stored_attachments.size(); i++ ) + for( size_t i = 0; i < p_sys->stored_attachments.size(); i++ ) { attachment_c *a = p_sys->stored_attachments[i]; - (*ppp_attach)[i] = vlc_input_attachment_New( a->psz_file_name.c_str(), a->psz_mime_type.c_str(), NULL, - a->p_data, a->i_size ); + (*ppp_attach)[i] = vlc_input_attachment_New( a->fileName(), a->mimeType(), NULL, + a->p_data, a->size() ); } return VLC_SUCCESS; @@ -375,9 +371,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) case DEMUX_GET_FPS: pf = (double *)va_arg( args, double * ); *pf = 0.0; - if( p_sys->p_current_segment && p_sys->p_current_segment->Segment() ) + if( p_sys->p_current_segment && p_sys->p_current_segment->CurrentSegment() ) { - const matroska_segment_c *p_segment = p_sys->p_current_segment->Segment(); + const matroska_segment_c *p_segment = p_sys->p_current_segment->CurrentSegment(); for( size_t i = 0; i < p_segment->tracks.size(); i++ ) { mkv_track_t *tk = p_segment->tracks[i]; @@ -391,17 +387,21 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) return VLC_SUCCESS; case DEMUX_SET_TIME: + i64 = (int64_t) va_arg( args, int64_t ); + msg_Dbg(p_demux,"SET_TIME to %"PRId64, i64 ); + Seek( p_demux, i64, -1, NULL ); + return VLC_SUCCESS; default: return VLC_EGENERIC; } } /* Seek */ -static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_item_c *psz_chapter ) +static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, virtual_chapter_c *p_chapter ) { demux_sys_t *p_sys = p_demux->p_sys; virtual_segment_c *p_vsegment = p_sys->p_current_segment; - matroska_segment_c *p_segment = p_vsegment->Segment(); + matroska_segment_c *p_segment = p_vsegment->CurrentSegment(); mtime_t i_time_offset = 0; int64_t i_global_position = -1; @@ -420,7 +420,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it } /* seek without index or without date */ - if( f_percent >= 0 && (config_GetInt( p_demux, "mkv-seek-percent" ) || !p_segment->b_cues || i_date < 0 )) + if( f_percent >= 0 && (var_InheritBool( p_demux, "mkv-seek-percent" ) || !p_segment->b_cues || i_date < 0 )) { if( p_sys->f_duration >= 0 && p_segment->b_cues ) { @@ -453,30 +453,30 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it } } - p_vsegment->Seek( *p_demux, i_date, i_time_offset, psz_chapter, i_global_position ); + p_vsegment->Seek( *p_demux, i_date, i_time_offset, p_chapter, i_global_position ); } /* Utility function for BlockDecode */ -static block_t *MemToBlock( demux_t *p_demux, uint8_t *p_mem, int i_mem, size_t offset) +static block_t *MemToBlock( uint8_t *p_mem, size_t i_mem, size_t offset) { - block_t *p_block; - if( !(p_block = block_New( p_demux, i_mem + offset ) ) ) return NULL; - memcpy( p_block->p_buffer + offset, p_mem, i_mem ); - //p_block->i_rate = p_input->stream.control.i_rate; + block_t *p_block = block_New( p_demux, i_mem + offset ); + if( likely(p_block != NULL) ) + { + memcpy( p_block->p_buffer + offset, p_mem, i_mem ); + } return p_block; } -/* Needed by matroska_segment::Seek() */ -static void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock, +/* Needed by matroska_segment::Seek() and Seek */ +void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock, mtime_t i_pts, mtime_t i_duration, bool f_mandatory ) { demux_sys_t *p_sys = p_demux->p_sys; - matroska_segment_c *p_segment = p_sys->p_current_segment->Segment(); + matroska_segment_c *p_segment = p_sys->p_current_segment->CurrentSegment(); - size_t i_track; - unsigned int i; - bool b; + if( !p_segment ) return; + size_t i_track; if( p_segment->BlockFindTrackIndex( &i_track, block, simpleblock ) ) { msg_Err( p_demux, "invalid track number" ); @@ -497,6 +497,7 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simp if ( tk->fmt.i_cat != NAV_ES ) { + bool b; es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b ); if( !b ) @@ -513,14 +514,14 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simp block_t *p_init; msg_Dbg( p_demux, "sending header (%d bytes)", tk->i_data_init ); - p_init = MemToBlock( p_demux, tk->p_data_init, tk->i_data_init, 0 ); + p_init = MemToBlock( tk->p_data_init, tk->i_data_init, 0 ); if( p_init ) es_out_Send( p_demux->out, tk->p_es, p_init ); } tk->b_inited = true; - for( i = 0; - (block != NULL && i < block->NumberFrames()) || (simpleblock != NULL && i < simpleblock->NumberFrames()); + for( unsigned int i = 0; + ( block != NULL && i < block->NumberFrames()) || ( simpleblock != NULL && i < simpleblock->NumberFrames() ); i++ ) { block_t *p_block; @@ -535,11 +536,13 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simp { data = &block->GetBuffer(i); } + if( !data->Buffer() || data->Size() > SIZE_MAX ) + break; if( tk->i_compression_type == MATROSKA_COMPRESSION_HEADER && tk->p_compression_data != NULL ) - p_block = MemToBlock( p_demux, data->Buffer(), data->Size(), tk->p_compression_data->GetSize() ); + p_block = MemToBlock( data->Buffer(), data->Size(), tk->p_compression_data->GetSize() ); else - p_block = MemToBlock( p_demux, data->Buffer(), data->Size(), 0 ); + p_block = MemToBlock( data->Buffer(), data->Size(), 0 ); if( p_block == NULL ) { @@ -550,6 +553,8 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simp if( tk->i_compression_type == MATROSKA_COMPRESSION_ZLIB ) { p_block = block_zlib_decompress( VLC_OBJECT(p_demux), p_block ); + if( p_block == NULL ) + break; } else #endif @@ -561,15 +566,8 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simp if ( tk->fmt.i_cat == NAV_ES ) { // TODO handle the start/stop times of this packet - if ( p_sys->b_ui_hooked ) - { - vlc_mutex_lock( &p_sys->p_ev->lock ); - memcpy( &p_sys->pci_packet, &p_block->p_buffer[1], sizeof(pci_t) ); - p_sys->SwapButtons(); - p_sys->b_pci_packet_set = true; - vlc_mutex_unlock( &p_sys->p_ev->lock ); - block_Release( p_block ); - } + p_sys->p_ev->SetPci( (const pci_t *)&p_block->p_buffer[1]); + block_Release( p_block ); return; } // correct timestamping when B frames are used @@ -579,10 +577,14 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simp } else { - if( !strcmp( tk->psz_codec, "V_MS/VFW/FOURCC" ) ) + if( tk->b_dts_only ) { - // in VFW we have no idea about B frames - p_block->i_pts = 0; + p_block->i_pts = VLC_TS_INVALID; + p_block->i_dts = i_pts; + } + else if( tk->b_pts_only ) + { + p_block->i_pts = i_pts; p_block->i_dts = i_pts; } else @@ -592,7 +594,6 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simp p_block->i_dts = p_block->i_pts; else p_block->i_dts = min( i_pts, tk->i_last_dts + (mtime_t)(tk->i_default_duration >> 10)); - p_sys->i_pts = p_block->i_dts; } } tk->i_last_dts = p_block->i_dts; @@ -605,166 +606,19 @@ msg_Dbg( p_demux, "block i_dts: %"PRId64" / i_pts: %"PRId64, p_block->i_dts, p_b p_block->i_length = i_duration * 1000; } + /* FIXME remove when VLC_TS_INVALID work is done */ + if( i == 0 || p_block->i_dts > VLC_TS_INVALID ) + p_block->i_dts += VLC_TS_0; + if( !tk->b_dts_only && ( i == 0 || p_block->i_pts > VLC_TS_INVALID ) ) + p_block->i_pts += VLC_TS_0; + es_out_Send( p_demux->out, tk->p_es, p_block ); /* use time stamp only for first block */ - i_pts = 0; + i_pts = VLC_TS_INVALID; } } - -void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_global_position ) -{ - KaxBlock *block; - KaxSimpleBlock *simpleblock; - int i_track_skipping; - int64_t i_block_duration; - int64_t i_block_ref1; - int64_t i_block_ref2; - size_t i_track; - int64_t i_seek_position = i_start_pos; - int64_t i_seek_time = i_start_time; - - if( i_global_position >= 0 ) - { - /* Special case for seeking in files with no cues */ - EbmlElement *el = NULL; - es.I_O().setFilePointer( i_start_pos, seek_beginning ); - delete ep; - ep = new EbmlParser( &es, segment, &sys.demuxer ); - cluster = NULL; - - while( ( el = ep->Get() ) != NULL ) - { - if( MKV_IS_ID( el, KaxCluster ) ) - { - cluster = (KaxCluster *)el; - i_cluster_pos = cluster->GetElementPosition(); - if( i_index == 0 || - ( i_index > 0 && p_indexes[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) ) - { - IndexAppendCluster( cluster ); - } - if( es.I_O().getFilePointer() >= i_global_position ) - { - ParseCluster(); - msg_Dbg( &sys.demuxer, "we found a cluster that is in the neighbourhood" ); - es_out_Control( sys.demuxer.out, ES_OUT_RESET_PCR ); - return; - } - } - } - msg_Err( &sys.demuxer, "This file has no cues, and we were unable to seek to the requested position by parsing." ); - return; - } - - if ( i_index > 0 ) - { - int i_idx = 0; - - for( ; i_idx < i_index; i_idx++ ) - { - if( p_indexes[i_idx].i_time + i_time_offset > i_date ) - { - break; - } - } - - if( i_idx > 0 ) - { - i_idx--; - } - - i_seek_position = p_indexes[i_idx].i_position; - i_seek_time = p_indexes[i_idx].i_time; - } - - msg_Dbg( &sys.demuxer, "seek got %"PRId64" (%d%%)", - i_seek_time, (int)( 100 * i_seek_position / stream_Size( sys.demuxer.s ) ) ); - - es.I_O().setFilePointer( i_seek_position, seek_beginning ); - - delete ep; - ep = new EbmlParser( &es, segment, &sys.demuxer ); - cluster = NULL; - - sys.i_start_pts = i_date; - - es_out_Control( sys.demuxer.out, ES_OUT_RESET_PCR ); - - /* now parse until key frame */ - i_track_skipping = 0; - for( i_track = 0; i_track < tracks.size(); i_track++ ) - { - if( tracks[i_track]->fmt.i_cat == VIDEO_ES ) - { - tracks[i_track]->b_search_keyframe = true; - i_track_skipping++; - } - es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, tracks[i_track]->p_es, i_date ); - } - - while( i_track_skipping > 0 ) - { - if( BlockGet( block, simpleblock, &i_block_ref1, &i_block_ref2, &i_block_duration ) ) - { - msg_Warn( &sys.demuxer, "cannot get block EOF?" ); - - return; - } - ep->Down(); - - for( i_track = 0; i_track < tracks.size(); i_track++ ) - { - if( (simpleblock && tracks[i_track]->i_number == simpleblock->TrackNum()) || - (block && tracks[i_track]->i_number == block->TrackNum()) ) - { - break; - } - } - - if( simpleblock ) - sys.i_pts = (sys.i_chapter_time + simpleblock->GlobalTimecode()) / (mtime_t) 1000; - else - sys.i_pts = (sys.i_chapter_time + block->GlobalTimecode()) / (mtime_t) 1000; - - if( i_track < tracks.size() ) - { - if( sys.i_pts >= sys.i_start_pts ) - { - cluster = static_cast(ep->UnGet( i_block_pos, i_cluster_pos )); - i_track_skipping = 0; - } - else if( tracks[i_track]->fmt.i_cat == VIDEO_ES ) - { - if( i_block_ref1 == 0 && tracks[i_track]->b_search_keyframe ) - { - tracks[i_track]->b_search_keyframe = false; - i_track_skipping--; - } - if( !tracks[i_track]->b_search_keyframe ) - { - //es_out_Control( sys.demuxer.out, ES_OUT_SET_PCR, sys.i_pts ); - BlockDecode( &sys.demuxer, block, simpleblock, sys.i_pts, 0, i_block_ref1 >= 0 || i_block_ref2 > 0 ); - } - } - } - - delete block; - } - - /* FIXME current ES_OUT_SET_NEXT_DISPLAY_TIME does not work that well if - * the delay is too high. */ - if( sys.i_pts + 500*1000 < sys.i_start_pts ) - { - sys.i_start_pts = sys.i_pts; - - for( i_track = 0; i_track < tracks.size(); i_track++ ) - es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, tracks[i_track]->p_es, sys.i_start_pts ); - } -} - - /***************************************************************************** * Demux: reads and demuxes data packets ***************************************************************************** @@ -777,7 +631,7 @@ static int Demux( demux_t *p_demux) vlc_mutex_lock( &p_sys->lock_demuxer ); virtual_segment_c *p_vsegment = p_sys->p_current_segment; - matroska_segment_c *p_segment = p_vsegment->Segment(); + matroska_segment_c *p_segment = p_vsegment->CurrentSegment(); if ( p_segment == NULL ) return 0; int i_block_count = 0; int i_return = 0; @@ -793,45 +647,29 @@ static int Demux( demux_t *p_demux) i_return = 1; break; } - - if ( p_vsegment->Edition() && p_vsegment->Edition()->b_ordered && p_vsegment->CurrentChapter() == NULL ) - { - /* nothing left to read in this ordered edition */ - if ( !p_vsegment->SelectNext() ) - break; - p_segment->UnSelect( ); - - es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); - /* switch to the next segment */ - p_segment = p_vsegment->Segment(); - if ( !p_segment->Select( 0 ) ) - { - msg_Err( p_demux, "Failed to select new segment" ); - break; - } - continue; - } + if ( p_vsegment->CurrentEdition() && + p_vsegment->CurrentEdition()->b_ordered && + p_vsegment->CurrentChapter() == NULL ) + /* nothing left to read in this ordered edition */ + break; KaxBlock *block; KaxSimpleBlock *simpleblock; int64_t i_block_duration = 0; - int64_t i_block_ref1; - int64_t i_block_ref2; - - if( p_segment->BlockGet( block, simpleblock, &i_block_ref1, &i_block_ref2, &i_block_duration ) ) + bool b_key_picture; + bool b_discardable_picture; + if( p_segment->BlockGet( block, simpleblock, &b_key_picture, &b_discardable_picture, &i_block_duration ) ) { - if ( p_vsegment->Edition() && p_vsegment->Edition()->b_ordered ) + if ( p_vsegment->CurrentEdition() && p_vsegment->CurrentEdition()->b_ordered ) { - const chapter_item_c *p_chap = p_vsegment->CurrentChapter(); + const virtual_chapter_c *p_chap = p_vsegment->CurrentChapter(); // check if there are more chapters to read if ( p_chap != NULL ) { /* TODO handle successive chapters with the same user_start_time/user_end_time - if ( p_chap->i_user_start_time == p_chap->i_user_start_time ) - p_vsegment->SelectNext(); */ - p_sys->i_pts = p_chap->i_user_end_time; + p_sys->i_pts = p_chap->i_virtual_stop_time; p_sys->i_pts++; // trick to avoid staying on segments with no duration and no content i_return = 1; @@ -842,34 +680,24 @@ static int Demux( demux_t *p_demux) else { msg_Warn( p_demux, "cannot get block EOF?" ); - p_segment->UnSelect( ); - - es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); - - /* switch to the next segment */ - if ( !p_vsegment->SelectNext() ) - // no more segments in this stream - break; - p_segment = p_vsegment->Segment(); - if ( !p_segment->Select( 0 ) ) - { - msg_Err( p_demux, "Failed to select new segment" ); - break; - } + p_segment->UnSelect(); - continue; + es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); + break; } } if( simpleblock != NULL ) - p_sys->i_pts = (p_sys->i_chapter_time + simpleblock->GlobalTimecode()) / (mtime_t) 1000; + p_sys->i_pts = p_sys->i_chapter_time + ( simpleblock->GlobalTimecode() / (mtime_t) 1000 ); else - p_sys->i_pts = (p_sys->i_chapter_time + block->GlobalTimecode()) / (mtime_t) 1000; + p_sys->i_pts = p_sys->i_chapter_time + ( block->GlobalTimecode() / (mtime_t) 1000 ); + + /* The blocks are in coding order so we can safely consider that only references are in chronological order */ + if( simpleblock == NULL || b_key_picture ) + es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_pts ); if( p_sys->i_pts >= p_sys->i_start_pts ) { - es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pts ); - if ( p_vsegment->UpdateCurrentToChapter( *p_demux ) ) { i_return = 1; @@ -877,32 +705,17 @@ static int Demux( demux_t *p_demux) break; } } - - if ( p_vsegment->Edition() && p_vsegment->Edition()->b_ordered && p_vsegment->CurrentChapter() == NULL ) + + if ( p_vsegment->CurrentEdition() && + p_vsegment->CurrentEdition()->b_ordered && + p_vsegment->CurrentChapter() == NULL ) { /* nothing left to read in this ordered edition */ - if ( !p_vsegment->SelectNext() ) - { - delete block; - break; - } - p_segment->UnSelect( ); - - es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); - - /* switch to the next segment */ - p_segment = p_vsegment->Segment(); - if ( !p_segment->Select( 0 ) ) - { - msg_Err( p_demux, "Failed to select new segment" ); - delete block; - break; - } delete block; - continue; + break; } - BlockDecode( p_demux, block, simpleblock, p_sys->i_pts, i_block_duration, i_block_ref1 >= 0 || i_block_ref2 > 0 ); + BlockDecode( p_demux, block, simpleblock, p_sys->i_pts, i_block_duration, b_key_picture || b_discardable_picture ); delete block; i_block_count++;