📄 mkv.cpp
字号:
} bool SelectNext() { if ( i_current_segment < linked_segments.size()-1 ) { i_current_segment++; return true; } return false; } bool FindUID( KaxSegmentUID & uid ) const { for ( size_t i=0; i<linked_uids.size(); i++ ) { if ( linked_uids[i] == uid ) return true; } return false; } bool UpdateCurrentToChapter( demux_t & demux ); void PrepareChapters( ); chapter_item_c *BrowseCodecPrivate( unsigned int codec_id, bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ), const void *p_cookie, size_t i_cookie_size ); chapter_item_c *FindChapter( int64_t i_find_uid ); std::vector<chapter_edition_c*> *p_editions; int i_sys_title;protected: std::vector<matroska_segment_c*> linked_segments; std::vector<KaxSegmentUID> linked_uids; size_t i_current_segment; int i_current_edition; chapter_item_c *psz_current_chapter; void AppendUID( const EbmlBinary * UID );};class matroska_stream_c{public: matroska_stream_c( demux_sys_t & demuxer ) :p_in(NULL) ,p_es(NULL) ,sys(demuxer) {} virtual ~matroska_stream_c() { delete p_in; delete p_es; } IOCallback *p_in; EbmlStream *p_es; std::vector<matroska_segment_c*> segments; demux_sys_t & sys;};typedef struct{ VLC_COMMON_MEMBERS demux_t *p_demux; vlc_mutex_t lock; vlc_bool_t b_moved; vlc_bool_t b_clicked; vlc_bool_t b_key;} event_thread_t;class demux_sys_t{public: demux_sys_t( demux_t & demux ) :demuxer(demux) ,i_pts(0) ,i_start_pts(0) ,i_chapter_time(0) ,meta(NULL) ,i_current_title(0) ,p_current_segment(NULL) ,dvd_interpretor( *this ) ,f_duration(-1.0) ,b_ui_hooked(false) ,p_input(NULL) ,b_pci_packet_set(false) ,p_ev(NULL) { vlc_mutex_init( &demuxer, &lock_demuxer ); } virtual ~demux_sys_t() { StopUiThread(); size_t i; for ( i=0; i<streams.size(); i++ ) delete streams[i]; for ( i=0; i<opened_segments.size(); i++ ) delete opened_segments[i]; for ( i=0; i<used_segments.size(); i++ ) delete used_segments[i]; if( meta ) vlc_meta_Delete( meta ); while( titles.size() ) { vlc_input_title_Delete( titles.back() ); titles.pop_back();} vlc_mutex_destroy( &lock_demuxer ); } /* current data */ demux_t & demuxer; mtime_t i_pts; mtime_t i_start_pts; mtime_t i_chapter_time; vlc_meta_t *meta; std::vector<input_title_t*> titles; // matroska editions size_t i_current_title; std::vector<matroska_stream_c*> streams; std::vector<matroska_segment_c*> opened_segments; std::vector<virtual_segment_c*> used_segments; virtual_segment_c *p_current_segment; dvd_command_interpretor_c dvd_interpretor; /* duration of the stream */ float f_duration; matroska_segment_c *FindSegment( const EbmlBinary & uid ) const; chapter_item_c *BrowseCodecPrivate( unsigned int codec_id, bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ), const void *p_cookie, size_t i_cookie_size, virtual_segment_c * & p_segment_found ); chapter_item_c *FindChapter( int64_t i_find_uid, virtual_segment_c * & p_segment_found ); 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( 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(); void StopUiThread(); bool b_ui_hooked; inline void SwapButtons(); /* for spu variables */ input_thread_t *p_input; pci_t pci_packet; bool b_pci_packet_set; uint8_t palette[4][4]; vlc_mutex_t lock_demuxer; /* event */ event_thread_t *p_ev; static int EventThread( vlc_object_t *p_this ); static int EventMouse( vlc_object_t *p_this, char const *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data ); static int EventKey( vlc_object_t *p_this, char const *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data );protected: virtual_segment_c *VirtualFromSegments( matroska_segment_c *p_segment ) const; bool IsUsedSegment( matroska_segment_c &p_segment ) const;};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 );#define MKV_IS_ID( el, C ) ( EbmlId( (*el) ) == C::ClassInfos.GlobalId )static inline char * ToUTF8( const UTFstring &u ){ return strdup( u.GetUTF8().c_str() );}/***************************************************************************** * Open: initializes matroska demux structures *****************************************************************************/static int Open( vlc_object_t * p_this ){ demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; matroska_stream_c *p_stream; matroska_segment_c *p_segment; uint8_t *p_peek; std::string s_path, s_filename; vlc_stream_io_callback *p_io_callback; EbmlStream *p_io_stream; /* peek the begining */ if( stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) return VLC_EGENERIC; /* is a valid file */ if( p_peek[0] != 0x1a || p_peek[1] != 0x45 || p_peek[2] != 0xdf || p_peek[3] != 0xa3 ) return VLC_EGENERIC; /* Set the demux function */ p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys = new demux_sys_t( *p_demux ); p_io_callback = new vlc_stream_io_callback( p_demux->s, VLC_FALSE ); p_io_stream = new EbmlStream( *p_io_callback ); if( p_io_stream == NULL ) { msg_Err( p_demux, "failed to create EbmlStream" ); delete p_io_callback; delete p_sys; return VLC_EGENERIC; } p_stream = p_sys->AnalyseAllSegmentsFound( p_demux, p_io_stream, true ); if( p_stream == NULL ) { msg_Err( p_demux, "cannot find KaxSegment" ); goto error; } p_sys->streams.push_back( p_stream ); p_stream->p_in = p_io_callback; p_stream->p_es = p_io_stream; for (size_t i=0; i<p_stream->segments.size(); i++) { p_stream->segments[i]->Preload(); } p_segment = p_stream->segments[0]; if( p_segment->cluster != NULL ) { msg_Warn( p_demux, "cannot find any cluster, damaged file ?" ); // reset the stream reading to the first cluster of the segment used p_stream->p_in->setFilePointer( p_segment->cluster->GetElementPosition() ); } if (config_GetInt( 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, "")) { // 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 { if (s_path.find_last_of(DIRECTORY_SEPARATOR) > 0) { s_path = s_path.substr(0,s_path.find_last_of(DIRECTORY_SEPARATOR)); } } DIR *p_src_dir = (DIR *)utf8_opendir(s_path.c_str()); if (p_src_dir != NULL) { const char *psz_file; while ((psz_file = utf8_readdir(p_src_dir)) != NULL) { if (strlen(psz_file) > 4) { s_filename = s_path + DIRECTORY_SEPARATOR + psz_file;#ifdef WIN32 if (!strcasecmp(s_filename.c_str(), p_demux->psz_path))#else if (!s_filename.compare(p_demux->psz_path))#endif 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 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_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; } else { p_stream->p_in = p_file_io; p_stream->p_es = p_estream; p_sys->streams.push_back( p_stream ); } } else { msg_Dbg( p_demux, "the file '%s' cannot be opened", s_filename.c_str() ); } } } LocaleFree (psz_file); } vlc_closedir_wrapper( p_src_dir ); } } p_sys->PreloadFamily( *p_segment ); } p_sys->PreloadLinked( p_segment ); if ( !p_sys->PreparePlayback( NULL ) ) { msg_Err( p_demux, "cannot use the segment" ); goto error; } p_sys->StartUiThread(); return VLC_SUCCESS;error: delete p_sys; return VLC_EGENERIC;}/***************************************************************************** * Close: frees unused data *****************************************************************************/static void Close( vlc_object_t *p_this ){ demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys = p_demux->p_sys; delete p_sys;}/***************************************************************************** * Control: *****************************************************************************/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; double *pf, f; int i_skp; size_t i_idx; vlc_meta_t **pp_meta; switch( i_query ) { case DEMUX_GET_META: pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** ); *pp_meta = vlc_meta_Duplicate( p_sys->meta ); return VLC_SUCCESS; case DEMUX_GET_LENGTH: pi64 = (int64_t*)va_arg( args, int64_t * ); if( p_sys->f_duration > 0.0 ) { *pi64 = (int64_t)(p_sys->f_duration * 1000); return VLC_SUCCESS; } return VLC_EGENERIC; case DEMUX_GET_POSITION: pf = (double*)va_arg( args, double * ); if ( p_sys->f_duration > 0.0 ) *pf = (double)(p_sys->i_pts >= p_sys->i_start_pts ? p_sys->i_pts : p_sys->i_start_pts ) / (1000.0 * p_sys->f_duration); return VLC_SUCCESS; case DEMUX_SET_POSITION: f = (double)va_arg( args, double ); Seek( p_demux, -1, f, NULL ); return VLC_SUCCESS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -