#include "ebml/StdIOCallback.h"
+#if LIBMATROSKA_VERSION < 0x000706
+START_LIBMATROSKA_NAMESPACE
+extern const EbmlSemanticContext MATROSKA_DLL_API KaxMatroska_Context;
+END_LIBMATROSKA_NAMESPACE
+#endif
+
#include "vlc_keys.h"
extern "C" {
N_("Chapter codecs"),
N_("Use chapter codecs found in the segment."), VLC_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)."), VLC_TRUE );
+
add_bool( "mkv-seek-percent", 0, NULL,
- N_("Seek based on percent not time."),
+ N_("Seek based on percent not time"),
N_("Seek based on percent not time."), VLC_TRUE );
add_bool( "mkv-use-dummy", 0, NULL,
uint64_t i_default_duration;
float f_timecodescale;
+ mtime_t i_last_dts;
/* video */
es_format_t fmt;
std::vector<chapter_codec_cmds_c*> codecs;
- static bool CompareTimecode( const chapter_item_c * & itemA, const chapter_item_c * & itemB )
+ static bool CompareTimecode( const chapter_item_c * itemA, const chapter_item_c * itemB )
{
return ( itemA->i_user_start_time < itemB->i_user_start_time || (itemA->i_user_start_time == itemB->i_user_start_time && itemA->i_user_end_time < itemB->i_user_end_time) );
}
{
free( tracks[i_track]->fmt.psz_description );
}
-/* if( tracks[i_track]->psz_codec )
+ if( tracks[i_track]->psz_codec )
{
free( tracks[i_track]->psz_codec );
}
if( tracks[i_track]->fmt.psz_language )
{
free( tracks[i_track]->fmt.psz_language );
- }*/
+ }
delete tracks[i_track];
}
free( p_indexes );
delete ep;
+ delete segment;
delete p_segment_uid;
delete p_prev_segment_uid;
delete p_next_segment_uid;
delete (*indext);
indext++;
}
+ std::vector<KaxSegmentFamily*>::iterator indexf = families.begin();
+ while ( indexf != families.end() )
+ {
+ delete (*indexf);
+ indexf++;
+ }
}
KaxSegment *segment;
int i_default_edition;
std::vector<chapter_translation_c*> translations;
- std::vector<KaxSegmentFamily> families;
+ std::vector<KaxSegmentFamily*> families;
demux_sys_t & sys;
EbmlParser *ep;
demux_sys_t( demux_t & demux )
:demuxer(demux)
,i_pts(0)
- ,i_last_dts(0)
,i_start_pts(0)
,i_chapter_time(0)
,meta(NULL)
demux_t & demuxer;
mtime_t i_pts;
- mtime_t i_last_dts;
mtime_t i_start_pts;
mtime_t i_chapter_time;
void PreloadFamily( const matroska_segment_c & of_segment );
void PreloadLinked( matroska_segment_c *p_segment );
bool PreparePlayback( virtual_segment_c *p_new_segment );
- matroska_stream_c *AnalyseAllSegmentsFound( EbmlStream *p_estream );
+ matroska_stream_c *AnalyseAllSegmentsFound( demux_t *p_demux, EbmlStream *p_estream, bool b_initial = false );
void JumpTo( virtual_segment_c & p_segment, chapter_item_c * p_chapter );
void StartUiThread();
return VLC_EGENERIC;
}
- p_stream = p_sys->AnalyseAllSegmentsFound( p_io_stream );
+ p_stream = p_sys->AnalyseAllSegmentsFound( p_demux, p_io_stream, true );
if( p_stream == NULL )
{
msg_Err( p_demux, "cannot find KaxSegment" );
p_stream->p_in->setFilePointer( p_segment->cluster->GetElementPosition() );
}
- /* 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 (config_GetInt( p_demux, "mkv-preload-local-dir" ))
{
- // 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 = s_path.substr(0,s_path.length()-1);
- }
- else
+ /* 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 (s_path.find_last_of(DIRECTORY_SEPARATOR) > 0)
+ // 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 = s_path.substr(0,s_path.find_last_of(DIRECTORY_SEPARATOR));
+ s_path = s_path.substr(0,s_path.length()-1);
+ }
+ else
+ {
+ if (s_path.find_last_of(DIRECTORY_SEPARATOR) > 0)
+ {
+ s_path = s_path.substr(0,s_path.find_last_of(DIRECTORY_SEPARATOR));
+ }
}
- }
- struct dirent *p_file_item;
- DIR *p_src_dir = opendir(s_path.c_str());
+ struct dirent *p_file_item;
+ DIR *p_src_dir = opendir(s_path.c_str());
- if (p_src_dir != NULL)
- {
- while ((p_file_item = (dirent *) readdir(p_src_dir)))
+ if (p_src_dir != NULL)
{
- if (strlen(p_file_item->d_name) > 4)
+ while ((p_file_item = (dirent *) readdir(p_src_dir)))
{
- s_filename = s_path + DIRECTORY_SEPARATOR + p_file_item->d_name;
+ if (strlen(p_file_item->d_name) > 4)
+ {
+ s_filename = s_path + DIRECTORY_SEPARATOR + p_file_item->d_name;
- if (!s_filename.compare(p_demux->psz_path))
- continue; // don't reuse the original opened file
+ if (!s_filename.compare(p_demux->psz_path))
+ 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))
+ 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"))
+ 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
- stream_t *p_file_stream = stream_UrlNew( p_demux, s_filename.c_str());
- if ( p_file_stream != NULL )
{
- vlc_stream_io_callback *p_file_io = new vlc_stream_io_callback( p_file_stream, VLC_TRUE );
- EbmlStream *p_estream = new EbmlStream(*p_file_io);
+ // test wether this file belongs to our family
+ stream_t *p_file_stream = stream_UrlNew( p_demux, s_filename.c_str());
+ if ( p_file_stream != NULL )
+ {
+ vlc_stream_io_callback *p_file_io = new vlc_stream_io_callback( p_file_stream, VLC_TRUE );
+ EbmlStream *p_estream = new EbmlStream(*p_file_io);
- p_stream = p_sys->AnalyseAllSegmentsFound( p_estream );
+ p_stream = p_sys->AnalyseAllSegmentsFound( p_demux, p_estream );
- if ( p_stream == NULL )
- {
- msg_Dbg( p_demux, "the file '%s' will not be used", s_filename.c_str() );
- delete p_estream;
- delete p_file_io;
+ if ( p_stream == NULL )
+ {
+ msg_Dbg( p_demux, "the file '%s' will not be used", s_filename.c_str() );
+ delete p_estream;
+ delete p_file_io;
+ }
+ else
+ {
+ p_stream->p_in = p_file_io;
+ p_stream->p_es = p_estream;
+ p_sys->streams.push_back( p_stream );
+ }
}
else
{
- p_stream->p_in = p_file_io;
- p_stream->p_es = p_estream;
- p_sys->streams.push_back( p_stream );
+ msg_Dbg( p_demux, "the file '%s' cannot be opened", s_filename.c_str() );
}
}
- else
- {
- msg_Dbg( p_demux, "the file '%s' cannot be opened", s_filename.c_str() );
- }
}
}
+ closedir( p_src_dir );
}
- closedir( p_src_dir );
}
+
+ p_sys->PreloadFamily( *p_segment );
}
- p_sys->PreloadFamily( *p_segment );
p_sys->PreloadLinked( p_segment );
+
if ( !p_sys->PreparePlayback( NULL ) )
{
msg_Err( p_demux, "cannot use the segment" );
}
static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
- mtime_t i_duration )
+ mtime_t i_duration, bool f_unreferenced )
{
demux_sys_t *p_sys = p_demux->p_sys;
matroska_segment_c *p_segment = p_sys->p_current_segment->Segment();
{
if( !strcmp( tk->psz_codec, "V_MS/VFW/FOURCC" ) )
{
+ // in VFW we have no idea about B frames
p_block->i_pts = 0;
+ p_block->i_dts = i_pts;
}
else
{
p_block->i_pts = i_pts;
+ if ( f_unreferenced )
+ p_block->i_dts = p_block->i_pts;
+ else
+ p_block->i_dts = min( i_pts, tk->i_last_dts + (tk->i_default_duration >> 10));
+ p_sys->i_pts = p_block->i_dts;
}
- p_block->i_dts = p_sys->i_pts;
}
+ tk->i_last_dts = p_block->i_dts;
-#if 0
+#if 1
msg_Dbg( p_demux, "block i_dts: "I64Fd" / i_pts: "I64Fd, p_block->i_dts, p_block->i_pts);
#endif
if( strcmp( tk->psz_codec, "S_VOBSUB" ) )
#undef tk
}
-matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( EbmlStream *p_estream )
+matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( demux_t *p_demux, EbmlStream *p_estream, bool b_initial )
{
int i_upper_lvl = 0;
size_t i;
{
return NULL;
}
- p_l0->SkipData(*p_estream, EbmlHead_Context);
+
+ // verify we can read this Segment, we only support Matroska version 1 for now
+ p_l0->Read(*p_estream, EbmlHead::ClassInfos.Context, i_upper_lvl, p_l0, true);
+
+ EDocType doc_type = GetChild<EDocType>(*static_cast<EbmlHead*>(p_l0));
+ if (std::string(doc_type) != "matroska")
+ {
+ msg_Dbg( p_demux, "Not a Matroska file : %s ", std::string(doc_type).c_str());
+ return NULL;
+ }
+
+ EDocTypeReadVersion doc_read_version = GetChild<EDocTypeReadVersion>(*static_cast<EbmlHead*>(p_l0));
+ if (uint64(doc_read_version) != 1)
+ {
+ msg_Dbg( p_demux, "Matroska Read version not matching : "I64Fd, uint64(doc_read_version));
+ return NULL;
+ }
+
delete p_l0;
+
// find all segments in this file
p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFFLL);
if (p_l0 == NULL)
{
EbmlParser *ep;
matroska_segment_c *p_segment1 = new matroska_segment_c( *this, *p_estream );
- b_keep_segment = false;
+ b_keep_segment = b_initial;
ep = new EbmlParser(p_estream, p_l0, &demuxer );
p_segment1->ep = ep;
else if( MKV_IS_ID( l, KaxSegmentFamily ) )
{
KaxSegmentFamily *p_fam = new KaxSegmentFamily( *static_cast<KaxSegmentFamily*>(l) );
- p_segment1->families.push_back( *p_fam );
+ p_segment1->families.push_back( p_fam );
}
}
break;
else
delete p_segment1;
}
-
- p_l0->SkipData(*p_estream, EbmlHead_Context);
- p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
+ if (p_l0->IsFiniteSize() )
+ {
+ p_l0->SkipData(*p_estream, KaxMatroska_Context);
+ p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
+ }
+ else
+ p_l0 = p_l0->SkipData(*p_estream, KaxSegment_Context);
}
if ( !b_keep_stream )
else if( !strcmp( tracks[i_track]->psz_codec, "V_MPEG4/ISO/AVC" ) )
{
tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'a', 'v', 'c', '1' );
- tracks[i_track]->fmt.b_packetized = VLC_FALSE;
tracks[i_track]->fmt.i_extra = tracks[i_track]->i_extra_data;
tracks[i_track]->fmt.p_extra = malloc( tracks[i_track]->i_extra_data );
memcpy( tracks[i_track]->fmt.p_extra,tracks[i_track]->p_extra_data, tracks[i_track]->i_extra_data );
event_thread_t *p_ev = (event_thread_t *) p_data;
vlc_mutex_lock( &p_ev->lock );
if( psz_var[6] == 'c' )
+ {
p_ev->b_clicked = VLC_TRUE;
+ msg_Dbg( p_this, "Event Mouse: clicked");
+ }
else if( psz_var[6] == 'm' )
p_ev->b_moved = VLC_TRUE;
vlc_mutex_unlock( &p_ev->lock );
vlc_mutex_lock( &p_ev->lock );
p_ev->b_key = VLC_TRUE;
vlc_mutex_unlock( &p_ev->lock );
+ msg_Dbg( p_this, "Event Key");
return VLC_SUCCESS;
}
struct vlc_t::hotkey *p_hotkeys = p_ev->p_vlc->p_hotkeys;
int i, i_action = -1;
+ msg_Dbg( p_ev->p_demux, "Handle Key Event");
+
vlc_mutex_lock( &p_ev->lock );
pci_t *pci = (pci_t *) &p_sys->pci_packet;
int32_t best,dist,d;
int32_t mx,my,dx,dy;
+ msg_Dbg( p_ev->p_demux, "Handle Mouse Event: Mouse clicked x(%d)*y(%d)", (unsigned)valx.i_int, (unsigned)valy.i_int);
+
b_activated = VLC_TRUE;
// get current button
best = 0;
if ( p_chap->i_user_start_time == p_chap->i_user_start_time )
p_vsegment->SelectNext();
*/
- p_sys->i_last_dts = p_sys->i_pts = p_chap->i_user_end_time;
+ p_sys->i_pts = p_chap->i_user_end_time;
p_sys->i_pts++; // trick to avoid staying on segments with no duration and no content
i_return = 1;
}
}
- mtime_t i_pts, i_dts;
-
- mtime_t i_time = block->GlobalTimecode();
- if ( i_block_ref1 != 0 )
- i_time += min( 0, i_block_ref1 );
- if ( i_block_ref2 != 0 )
- i_time += min( 0, i_block_ref2 );
-
- i_pts = (p_sys->i_chapter_time + block->GlobalTimecode()) / (mtime_t) 1000;
- i_dts = (p_sys->i_chapter_time + i_time) / (mtime_t) 1000;
-
- if ( i_dts != i_pts && p_sys->i_last_dts >= i_dts )
- p_sys->i_last_dts += 200;
- else
- p_sys->i_last_dts = i_dts;
-
- p_sys->i_pts = i_pts;
+ p_sys->i_pts = (p_sys->i_chapter_time + block->GlobalTimecode()) / (mtime_t) 1000;
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( i_pts >= p_sys->i_start_pts )
if ( p_vsegment->UpdateCurrentToChapter( *p_demux ) )
{
i_return = 1;
+ delete block;
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() )
+ {
+ delete block;
break;
+ }
p_segment->UnSelect( );
es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
if ( !p_segment->Select( 0 ) )
{
msg_Err( p_demux, "Failed to select new segment" );
+ delete block;
break;
}
+ delete block;
continue;
}
- BlockDecode( p_demux, block, i_pts, i_block_duration );
+ BlockDecode( p_demux, block, p_sys->i_pts, i_block_duration, i_block_ref1 >= 0 || i_block_ref2 > 0 );
delete block;
i_block_count++;
{
KaxTrackLanguage &lang = *(KaxTrackLanguage*)l;
+ if ( tk->fmt.psz_language != NULL )
+ free( tk->fmt.psz_language );
tk->fmt.psz_language = strdup( string( lang ).c_str() );
msg_Dbg( &sys.demuxer,
"| | | + Track Language=`%s'", tk->fmt.psz_language );
if( MKV_IS_ID( l, KaxSegmentUID ) )
{
- p_segment_uid = new KaxSegmentUID(*static_cast<KaxSegmentUID*>(l));
+ if ( p_segment_uid == NULL )
+ p_segment_uid = new KaxSegmentUID(*static_cast<KaxSegmentUID*>(l));
msg_Dbg( &sys.demuxer, "| | + UID=%d", *(uint32*)p_segment_uid->GetBuffer() );
}
else if( MKV_IS_ID( l, KaxPrevUID ) )
{
- p_prev_segment_uid = new KaxPrevUID(*static_cast<KaxPrevUID*>(l));
+ if ( p_prev_segment_uid == NULL )
+ p_prev_segment_uid = new KaxPrevUID(*static_cast<KaxPrevUID*>(l));
msg_Dbg( &sys.demuxer, "| | + PrevUID=%d", *(uint32*)p_prev_segment_uid->GetBuffer() );
}
else if( MKV_IS_ID( l, KaxNextUID ) )
{
- p_next_segment_uid = new KaxNextUID(*static_cast<KaxNextUID*>(l));
+ if ( p_next_segment_uid == NULL )
+ p_next_segment_uid = new KaxNextUID(*static_cast<KaxNextUID*>(l));
msg_Dbg( &sys.demuxer, "| | + NextUID=%d", *(uint32*)p_next_segment_uid->GetBuffer() );
}
{
KaxSegmentFamily *uid = static_cast<KaxSegmentFamily*>(l);
- families.push_back(*uid);
+ families.push_back( new KaxSegmentFamily(*uid) );
msg_Dbg( &sys.demuxer, "| | + family=%d", *(uint32*)uid->GetBuffer() );
}
for (k = 0; k < i_level; k++)
chapters.psz_name += '+';
chapters.psz_name += ' ';
- chapters.psz_name += ToUTF8( UTFstring( name ) );
+ char *psz_tmp_utf8 = ToUTF8( UTFstring( name ) );
+ chapters.psz_name += psz_tmp_utf8;
chapters.b_user_display = true;
- msg_Dbg( &sys.demuxer, "| | | | | + ChapterString '%s'", ToUTF8(UTFstring(name)) );
+ msg_Dbg( &sys.demuxer, "| | | | | + ChapterString '%s'", psz_tmp_utf8 );
+ free( psz_tmp_utf8 );
}
else if( MKV_IS_ID( l, KaxChapterLanguage ) )
{
{
for (size_t j=0; j<of_segment.families.size(); j++)
{
- if ( families[i] == of_segment.families[j] )
+ if ( *(families[i]) == *(of_segment.families[j]) )
return Preload( );
}
}
// check if it's not already in here
for ( i=0; i<linked_segments.size(); i++ )
{
- if ( *p_segment->p_segment_uid == *linked_segments[i]->p_segment_uid )
+ if ( linked_segments[i]->p_segment_uid != NULL
+ && p_segment->p_segment_uid != NULL
+ && *p_segment->p_segment_uid == *linked_segments[i]->p_segment_uid )
return 0;
}
}
}
- sys.i_last_dts = sys.i_pts = (sys.i_chapter_time + block->GlobalTimecode()) / (mtime_t) 1000;
+ sys.i_pts = (sys.i_chapter_time + block->GlobalTimecode()) / (mtime_t) 1000;
if( i_track < tracks.size() )
{
}
if( !tracks[i_track]->b_search_keyframe )
{
- BlockDecode( &sys.demuxer, block, sys.i_pts, 0 );
+ BlockDecode( &sys.demuxer, block, sys.i_pts, 0, i_block_ref1 >= 0 || i_block_ref2 > 0 );
}
}
}
if ( i_size != 8 )
return false;
- virtual_segment_c *p_segment;
- chapter_item_c *p_chapter;
+ virtual_segment_c *p_segment = NULL;
+ chapter_item_c *p_chapter = NULL;
bool f_result = false;
uint16 i_command = ( p_command[0] << 8 ) + p_command[1];