2 /*****************************************************************************
3 * mkv.cpp : matroska demuxer
4 *****************************************************************************
5 * Copyright (C) 2003-2004 the VideoLAN team
8 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * Steve Lhomme <steve.lhomme@free.fr>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
28 #include "Ebml_parser.hpp"
30 event_thread_t::event_thread_t(demux_t *p_demux) : p_demux(p_demux)
32 vlc_mutex_init( &lock );
33 vlc_cond_init( &wait );
36 event_thread_t::~event_thread_t()
39 vlc_cond_destroy( &wait );
40 vlc_mutex_destroy( &lock );
43 void event_thread_t::SetPci(const pci_t *data)
45 vlc_mutex_locker l(&lock);
49 #ifndef WORDS_BIGENDIAN
50 for( uint8_t button = 1; button <= pci_packet.hli.hl_gi.btn_ns; button++) {
51 btni_t *button_ptr = &(pci_packet.hli.btnit[button-1]);
52 binary *p_data = (binary*) button_ptr;
54 uint16 i_x_start = ((p_data[0] & 0x3F) << 4 ) + ( p_data[1] >> 4 );
55 uint16 i_x_end = ((p_data[1] & 0x03) << 8 ) + p_data[2];
56 uint16 i_y_start = ((p_data[3] & 0x3F) << 4 ) + ( p_data[4] >> 4 );
57 uint16 i_y_end = ((p_data[4] & 0x03) << 8 ) + p_data[5];
58 button_ptr->x_start = i_x_start;
59 button_ptr->x_end = i_x_end;
60 button_ptr->y_start = i_y_start;
61 button_ptr->y_end = i_y_end;
64 for ( uint8_t i = 0; i<3; i++ )
65 for ( uint8_t j = 0; j<2; j++ )
66 pci_packet.hli.btn_colit.btn_coli[i][j] = U32_AT( &pci_packet.hli.btn_colit.btn_coli[i][j] );
71 is_running = !vlc_clone( &thread, EventThread, this, VLC_THREAD_PRIORITY_LOW );
74 void event_thread_t::ResetPci()
79 vlc_mutex_lock( &lock );
81 vlc_cond_signal( &wait );
82 vlc_mutex_unlock( &lock );
84 vlc_join( thread, NULL );
87 int event_thread_t::EventMouse( vlc_object_t *p_this, char const *psz_var,
88 vlc_value_t oldval, vlc_value_t newval, void *p_data )
90 VLC_UNUSED( oldval ); VLC_UNUSED( newval );
91 event_thread_t *p_ev = (event_thread_t *) p_data;
92 vlc_mutex_lock( &p_ev->lock );
93 if( psz_var[6] == 'c' )
95 p_ev->b_clicked = true;
96 msg_Dbg( p_this, "Event Mouse: clicked");
98 else if( psz_var[6] == 'm' )
100 vlc_cond_signal( &p_ev->wait );
101 vlc_mutex_unlock( &p_ev->lock );
106 int event_thread_t::EventKey( vlc_object_t *p_this, char const *,
107 vlc_value_t, vlc_value_t newval, void *p_data )
109 event_thread_t *p_ev = (event_thread_t *) p_data;
110 vlc_mutex_lock( &p_ev->lock );
111 p_ev->i_key_action = newval.i_int;
112 vlc_cond_signal( &p_ev->wait );
113 vlc_mutex_unlock( &p_ev->lock );
114 msg_Dbg( p_this, "Event Key");
119 int event_thread_t::EventInput( vlc_object_t *p_this, char const *,
120 vlc_value_t, vlc_value_t newval, void *p_data )
122 VLC_UNUSED( p_this );
123 event_thread_t *p_ev = (event_thread_t *) p_data;
124 vlc_mutex_lock( &p_ev->lock );
125 if( newval.i_int == INPUT_EVENT_VOUT )
127 p_ev->b_vout |= true;
128 vlc_cond_signal( &p_ev->wait );
130 vlc_mutex_unlock( &p_ev->lock );
135 void event_thread_t::EventThread()
137 demux_sys_t *p_sys = p_demux->p_sys;
138 vlc_object_t *p_vout = NULL;
139 int canc = vlc_savecancel ();
146 /* catch all key event */
147 var_AddCallback( p_demux->p_libvlc, "key-action", EventKey, this );
148 /* catch input event */
149 var_AddCallback( p_sys->p_input, "intf-event", EventInput, this );
154 vlc_mutex_lock( &lock );
155 while( !b_abort && !i_key_action && !b_moved && !b_clicked && !b_vout)
156 vlc_cond_wait( &wait, &lock );
160 vlc_mutex_unlock( &lock );
167 msg_Dbg( p_demux, "Handle Key Event");
169 pci_t *pci = &pci_packet;
171 uint16 i_curr_button = p_sys->dvd_interpretor.GetSPRM( 0x88 );
173 switch( i_key_action )
175 case ACTIONID_NAV_LEFT:
176 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
178 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
179 if ( p_button_ptr->left > 0 && p_button_ptr->left <= pci->hli.hl_gi.btn_ns )
181 i_curr_button = p_button_ptr->left;
182 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
183 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
184 if ( button_ptr.auto_action_mode )
186 vlc_mutex_unlock( &lock );
187 vlc_mutex_lock( &p_sys->lock_demuxer );
189 // process the button action
190 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
192 vlc_mutex_unlock( &p_sys->lock_demuxer );
193 vlc_mutex_lock( &lock );
198 case ACTIONID_NAV_RIGHT:
199 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
201 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
202 if ( p_button_ptr->right > 0 && p_button_ptr->right <= pci->hli.hl_gi.btn_ns )
204 i_curr_button = p_button_ptr->right;
205 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
206 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
207 if ( button_ptr.auto_action_mode )
209 vlc_mutex_unlock( &lock );
210 vlc_mutex_lock( &p_sys->lock_demuxer );
212 // process the button action
213 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
215 vlc_mutex_unlock( &p_sys->lock_demuxer );
216 vlc_mutex_lock( &lock );
221 case ACTIONID_NAV_UP:
222 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
224 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
225 if ( p_button_ptr->up > 0 && p_button_ptr->up <= pci->hli.hl_gi.btn_ns )
227 i_curr_button = p_button_ptr->up;
228 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
229 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
230 if ( button_ptr.auto_action_mode )
232 vlc_mutex_unlock( &lock );
233 vlc_mutex_lock( &p_sys->lock_demuxer );
235 // process the button action
236 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
238 vlc_mutex_unlock( &p_sys->lock_demuxer );
239 vlc_mutex_lock( &lock );
244 case ACTIONID_NAV_DOWN:
245 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
247 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
248 if ( p_button_ptr->down > 0 && p_button_ptr->down <= pci->hli.hl_gi.btn_ns )
250 i_curr_button = p_button_ptr->down;
251 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
252 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
253 if ( button_ptr.auto_action_mode )
255 vlc_mutex_unlock( &lock );
256 vlc_mutex_lock( &p_sys->lock_demuxer );
258 // process the button action
259 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
261 vlc_mutex_unlock( &p_sys->lock_demuxer );
262 vlc_mutex_lock( &lock );
267 case ACTIONID_NAV_ACTIVATE:
268 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
270 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
272 vlc_mutex_unlock( &lock );
273 vlc_mutex_lock( &p_sys->lock_demuxer );
275 // process the button action
276 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
278 vlc_mutex_unlock( &p_sys->lock_demuxer );
279 vlc_mutex_lock( &lock );
289 if( p_vout && ( b_moved || b_clicked ) )
293 var_GetCoords( p_vout, "mouse-moved", &x, &y );
294 pci_t *pci = &pci_packet;
302 msg_Dbg( p_demux, "Handle Mouse Event: Mouse clicked x(%d)*y(%d)", x, y);
304 // get current button
306 dist = 0x08000000; /* >> than (720*720)+(567*567); */
307 for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++)
309 btni_t *button_ptr = &(pci->hli.btnit[button-1]);
311 if(((unsigned)x >= button_ptr->x_start)
312 && ((unsigned)x <= button_ptr->x_end)
313 && ((unsigned)y >= button_ptr->y_start)
314 && ((unsigned)y <= button_ptr->y_end))
316 mx = (button_ptr->x_start + button_ptr->x_end)/2;
317 my = (button_ptr->y_start + button_ptr->y_end)/2;
320 d = (dx*dx) + (dy*dy);
321 /* If the mouse is within the button and the mouse is closer
322 * to the center of this button then it is the best choice. */
332 btni_t button_ptr = pci->hli.btnit[best-1];
333 uint16 i_curr_button = p_sys->dvd_interpretor.GetSPRM( 0x88 );
335 msg_Dbg( &p_sys->demuxer, "Clicked button %d", best );
336 vlc_mutex_unlock( &lock );
337 vlc_mutex_lock( &p_sys->lock_demuxer );
339 // process the button action
340 p_sys->dvd_interpretor.SetSPRM( 0x88, best );
341 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
343 msg_Dbg( &p_sys->demuxer, "Processed button %d", best );
346 if ( best != i_curr_button )
350 if( var_Get( p_sys->p_input, "highlight-mutex", &val ) == VLC_SUCCESS )
352 vlc_mutex_t *p_mutex = (vlc_mutex_t *) val.p_address;
355 if(button_ptr.btn_coln != 0) {
356 i_palette = pci->hli.btn_colit.btn_coli[button_ptr.btn_coln-1][1];
361 for( int i = 0; i < 4; i++ )
363 uint32_t i_yuv = 0xFF;//p_sys->clut[(hl.palette>>(16+i*4))&0x0f];
364 uint8_t i_alpha = (i_palette>>(i*4))&0x0f;
365 i_alpha = i_alpha == 0xf ? 0xff : i_alpha << 4;
367 p_sys->palette[i][0] = (i_yuv >> 16) & 0xff;
368 p_sys->palette[i][1] = (i_yuv >> 0) & 0xff;
369 p_sys->palette[i][2] = (i_yuv >> 8) & 0xff;
370 p_sys->palette[i][3] = i_alpha;
373 vlc_mutex_lock( p_mutex );
374 val.i_int = button_ptr.x_start; var_Set( p_sys->p_input, "x-start", val );
375 val.i_int = button_ptr.x_end; var_Set( p_sys->p_input, "x-end", val );
376 val.i_int = button_ptr.y_start; var_Set( p_sys->p_input, "y-start", val );
377 val.i_int = button_ptr.y_end; var_Set( p_sys->p_input, "y-end", val );
379 val.p_address = (void *)p_sys->palette;
380 var_Set( p_sys->p_input, "menu-palette", val );
382 val.b_bool = true; var_Set( p_sys->p_input, "highlight", val );
383 vlc_mutex_unlock( p_mutex );
386 vlc_mutex_unlock( &p_sys->lock_demuxer );
387 vlc_mutex_lock( &lock );
392 // dvdnav_mouse_select( NULL, pci, x, y );
400 vlc_mutex_unlock( &lock );
402 /* Always check vout */
403 if( p_vout && !vlc_object_alive (p_vout) )
405 var_DelCallback( p_vout, "mouse-moved", EventMouse, this );
406 var_DelCallback( p_vout, "mouse-clicked", EventMouse, this );
407 vlc_object_release( p_vout );
411 else if( p_vout == NULL )
413 p_vout = (vlc_object_t*) input_GetVout(p_sys->p_input);
416 var_AddCallback( p_vout, "mouse-moved", EventMouse, this );
417 var_AddCallback( p_vout, "mouse-clicked", EventMouse, this );
422 /* Release callback */
425 var_DelCallback( p_vout, "mouse-moved", EventMouse, this );
426 var_DelCallback( p_vout, "mouse-clicked", EventMouse, this );
427 vlc_object_release( p_vout );
429 var_DelCallback( p_sys->p_input, "intf-event", EventInput, this );
430 var_DelCallback( p_demux->p_libvlc, "key-action", EventKey, this );
432 vlc_restorecancel (canc);
435 void *event_thread_t::EventThread(void *data)
437 static_cast<event_thread_t*>(data)->EventThread();
442 demux_sys_t::~demux_sys_t()
446 for ( i=0; i<streams.size(); i++ )
448 for ( i=0; i<opened_segments.size(); i++ )
449 delete opened_segments[i];
450 for ( i=0; i<used_segments.size(); i++ )
451 delete used_segments[i];
452 for ( i=0; i<stored_attachments.size(); i++ )
453 delete stored_attachments[i];
454 if( meta ) vlc_meta_Delete( meta );
456 while( titles.size() )
457 { vlc_input_title_Delete( titles.back() ); titles.pop_back();}
459 vlc_mutex_destroy( &lock_demuxer );
463 matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( demux_t *p_demux, EbmlStream *p_estream, bool b_initial )
466 EbmlElement *p_l0, *p_l1, *p_l2;
467 bool b_keep_stream = false, b_keep_segment;
469 // verify the EBML Header
470 p_l0 = p_estream->FindNextID(EBML_INFO(EbmlHead), 0xFFFFFFFFL);
473 msg_Err( p_demux, "No EBML header found" );
477 // verify we can read this Segment, we only support Matroska version 1 for now
478 p_l0->Read(*p_estream, EBML_CLASS_CONTEXT(EbmlHead), i_upper_lvl, p_l0, true);
480 EDocType doc_type = GetChild<EDocType>(*static_cast<EbmlHead*>(p_l0));
481 if (std::string(doc_type) != "matroska" && std::string(doc_type) != "webm" )
483 msg_Err( p_demux, "Not a Matroska file : DocType = %s ", std::string(doc_type).c_str());
487 EDocTypeReadVersion doc_read_version = GetChild<EDocTypeReadVersion>(*static_cast<EbmlHead*>(p_l0));
488 if (uint64(doc_read_version) > 2)
490 msg_Err( p_demux, "matroska file needs version %"PRId64" but only versions 1 & 2 supported", uint64(doc_read_version));
497 // find all segments in this file
498 p_l0 = p_estream->FindNextID(EBML_INFO(KaxSegment), 0xFFFFFFFFFLL);
504 matroska_stream_c *p_stream1 = new matroska_stream_c( *this );
508 if ( MKV_IS_ID( p_l0, KaxSegment) )
511 matroska_segment_c *p_segment1 = new matroska_segment_c( *this, *p_estream );
512 b_keep_segment = b_initial;
514 ep = new EbmlParser(p_estream, p_l0, &demuxer );
516 p_segment1->segment = (KaxSegment*)p_l0;
518 while ((p_l1 = ep->Get()))
520 if (MKV_IS_ID(p_l1, KaxInfo))
522 // find the families of this segment
523 KaxInfo *p_info = static_cast<KaxInfo*>(p_l1);
525 p_info->Read(*p_estream, EBML_CLASS_CONTEXT(KaxInfo), i_upper_lvl, p_l2, true);
526 for( size_t i = 0; i < p_info->ListSize(); i++ )
528 EbmlElement *l = (*p_info)[i];
530 if( MKV_IS_ID( l, KaxSegmentUID ) )
532 KaxSegmentUID *p_uid = static_cast<KaxSegmentUID*>(l);
533 b_keep_segment = (FindSegment( *p_uid ) == NULL);
534 if ( !b_keep_segment )
535 break; // this segment is already known
536 opened_segments.push_back( p_segment1 );
537 delete p_segment1->p_segment_uid;
538 p_segment1->p_segment_uid = new KaxSegmentUID(*p_uid);
540 else if( MKV_IS_ID( l, KaxPrevUID ) )
542 p_segment1->p_prev_segment_uid = new KaxPrevUID( *static_cast<KaxPrevUID*>(l) );
544 else if( MKV_IS_ID( l, KaxNextUID ) )
546 p_segment1->p_next_segment_uid = new KaxNextUID( *static_cast<KaxNextUID*>(l) );
548 else if( MKV_IS_ID( l, KaxSegmentFamily ) )
550 KaxSegmentFamily *p_fam = new KaxSegmentFamily( *static_cast<KaxSegmentFamily*>(l) );
551 p_segment1->families.push_back( p_fam );
557 if ( b_keep_segment )
559 b_keep_stream = true;
560 p_stream1->segments.push_back( p_segment1 );
564 p_segment1->segment = NULL;
568 if (p_l0->IsFiniteSize() )
570 p_l0->SkipData(*p_estream, KaxMatroska_Context);
571 p_l0 = p_estream->FindNextID(EBML_INFO(KaxSegment), 0xFFFFFFFFL);
579 if ( !b_keep_stream )
588 void demux_sys_t::InitUi()
590 msg_Dbg( &demuxer, "Starting the UI Hook" );
592 /* FIXME hack hack hack hack FIXME */
593 /* Get p_input and create variable */
594 p_input = demux_GetParentInput( &demuxer );
595 var_Create( p_input, "x-start", VLC_VAR_INTEGER );
596 var_Create( p_input, "y-start", VLC_VAR_INTEGER );
597 var_Create( p_input, "x-end", VLC_VAR_INTEGER );
598 var_Create( p_input, "y-end", VLC_VAR_INTEGER );
599 var_Create( p_input, "color", VLC_VAR_ADDRESS );
600 var_Create( p_input, "menu-palette", VLC_VAR_ADDRESS );
601 var_Create( p_input, "highlight", VLC_VAR_BOOL );
602 var_Create( p_input, "highlight-mutex", VLC_VAR_MUTEX );
604 /* Now create our event thread catcher */
605 p_ev = new event_thread_t(&demuxer);
608 void demux_sys_t::CleanUi()
613 var_Destroy( p_input, "highlight-mutex" );
614 var_Destroy( p_input, "highlight" );
615 var_Destroy( p_input, "x-start" );
616 var_Destroy( p_input, "x-end" );
617 var_Destroy( p_input, "y-start" );
618 var_Destroy( p_input, "y-end" );
619 var_Destroy( p_input, "color" );
620 var_Destroy( p_input, "menu-palette" );
622 vlc_object_release( p_input );
624 msg_Dbg( &demuxer, "Stopping the UI Hook" );
627 void demux_sys_t::PreloadFamily( const matroska_segment_c & of_segment )
629 for (size_t i=0; i<opened_segments.size(); i++)
631 opened_segments[i]->PreloadFamily( of_segment );
635 // preload all the linked segments for all preloaded segments
636 void demux_sys_t::PreloadLinked( matroska_segment_c *p_segment )
638 size_t i_preloaded, i, j;
639 virtual_segment_c *p_seg;
641 p_current_segment = VirtualFromSegments( p_segment );
643 used_segments.push_back( p_current_segment );
645 // create all the other virtual segments of the family
648 for ( i=0; i< opened_segments.size(); i++ )
650 if ( opened_segments[i]->b_preloaded && !IsUsedSegment( *opened_segments[i] ) )
652 p_seg = VirtualFromSegments( opened_segments[i] );
653 used_segments.push_back( p_seg );
657 } while ( i_preloaded ); // worst case: will stop when all segments are found as family related
659 // publish all editions of all usable segment
660 for ( i=0; i< used_segments.size(); i++ )
662 p_seg = used_segments[i];
663 if ( p_seg->Editions() != NULL )
665 input_title_t *p_title = vlc_input_title_New();
666 p_seg->i_sys_title = i;
669 // TODO use a name for each edition, let the TITLE deal with a codec name
670 for ( j=0; j<p_seg->Editions()->size(); j++ )
672 if ( p_title->psz_name == NULL )
674 const char* psz_tmp = (*p_seg->Editions())[j]->GetMainName().c_str();
675 if( *psz_tmp != '\0' )
676 p_title->psz_name = strdup( psz_tmp );
679 chapter_edition_c *p_edition = (*p_seg->Editions())[j];
682 p_edition->PublishChapters( *p_title, i_chapters, 0 );
685 // create a name if there is none
686 if ( p_title->psz_name == NULL )
688 if( asprintf(&(p_title->psz_name), "%s %d", N_("Segment"), (int)i) == -1 )
689 p_title->psz_name = NULL;
692 titles.push_back( p_title );
696 // TODO decide which segment should be first used (VMG for DVD)
699 bool demux_sys_t::IsUsedSegment( matroska_segment_c &segment ) const
701 for ( size_t i=0; i< used_segments.size(); i++ )
703 if ( used_segments[i]->FindUID( *segment.p_segment_uid ) )
709 virtual_segment_c *demux_sys_t::VirtualFromSegments( matroska_segment_c *p_segment ) const
711 virtual_segment_c *p_result = new virtual_segment_c( p_segment );
712 p_result->AddSegments( opened_segments );
717 bool demux_sys_t::PreparePlayback( virtual_segment_c *p_new_segment )
719 if ( p_new_segment != NULL && p_new_segment != p_current_segment )
721 if ( p_current_segment != NULL && p_current_segment->CurrentSegment() != NULL )
722 p_current_segment->CurrentSegment()->UnSelect();
724 p_current_segment = p_new_segment;
725 i_current_title = p_new_segment->i_sys_title;
727 if( !p_current_segment->CurrentSegment()->b_cues )
728 msg_Warn( &p_current_segment->CurrentSegment()->sys.demuxer, "no cues/empty cues found->seek won't be precise" );
730 f_duration = p_current_segment->Duration();
732 /* add information */
733 p_current_segment->CurrentSegment()->InformationCreate( );
734 p_current_segment->CurrentSegment()->Select( 0 );
739 void demux_sys_t::JumpTo( virtual_segment_c & vsegment, chapter_item_c * p_chapter )
741 // if the segment is not part of the current segment, select the new one
742 if ( &vsegment != p_current_segment )
744 PreparePlayback( &vsegment );
747 if ( p_chapter != NULL )
749 if ( !p_chapter->Enter( true ) )
751 // jump to the location in the found segment
752 vsegment.Seek( demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
758 matroska_segment_c *demux_sys_t::FindSegment( const EbmlBinary & uid ) const
760 for (size_t i=0; i<opened_segments.size(); i++)
762 if ( *opened_segments[i]->p_segment_uid == uid )
763 return opened_segments[i];
768 chapter_item_c *demux_sys_t::BrowseCodecPrivate( unsigned int codec_id,
769 bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ),
770 const void *p_cookie,
771 size_t i_cookie_size,
772 virtual_segment_c * &p_segment_found )
774 chapter_item_c *p_result = NULL;
775 for (size_t i=0; i<used_segments.size(); i++)
777 p_result = used_segments[i]->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
778 if ( p_result != NULL )
780 p_segment_found = used_segments[i];
787 chapter_item_c *demux_sys_t::FindChapter( int64_t i_find_uid, virtual_segment_c * & p_segment_found )
789 chapter_item_c *p_result = NULL;
790 for (size_t i=0; i<used_segments.size(); i++)
792 p_result = used_segments[i]->FindChapter( i_find_uid );
793 if ( p_result != NULL )
795 p_segment_found = used_segments[i];