1
2 /*****************************************************************************
3 * mkv.cpp : matroska demuxer
4 *****************************************************************************
5 * Copyright (C) 2003-2004 VLC authors and VideoLAN
6 * $Id: 6fa2418dd2b8f0544ec0b00fe54b71fcbc03ac11 $
7 *
8 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * Steve Lhomme <steve.lhomme@free.fr>
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
15 *
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 Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
25
26 #include "demux.hpp"
27 #include "stream_io_callback.hpp"
28 #include "Ebml_parser.hpp"
29
30 #include <vlc_actions.h>
31
event_thread_t(demux_t * p_demux)32 event_thread_t::event_thread_t(demux_t *p_demux) : p_demux(p_demux)
33 {
34 vlc_mutex_init( &lock );
35 vlc_cond_init( &wait );
36 is_running = false;
37 }
~event_thread_t()38 event_thread_t::~event_thread_t()
39 {
40 ResetPci();
41 vlc_cond_destroy( &wait );
42 vlc_mutex_destroy( &lock );
43 }
44
SetPci(const pci_t * data)45 void event_thread_t::SetPci(const pci_t *data)
46 {
47 vlc_mutex_locker l(&lock);
48
49 memcpy(&pci_packet, data, sizeof(pci_packet));
50
51 #ifndef WORDS_BIGENDIAN
52 for( uint8_t button = 1; button <= pci_packet.hli.hl_gi.btn_ns &&
53 button < ARRAY_SIZE(pci_packet.hli.btnit); button++) {
54 btni_t *button_ptr = &(pci_packet.hli.btnit[button-1]);
55 binary *p_data = (binary*) button_ptr;
56
57 uint16 i_x_start = ((p_data[0] & 0x3F) << 4 ) + ( p_data[1] >> 4 );
58 uint16 i_x_end = ((p_data[1] & 0x03) << 8 ) + p_data[2];
59 uint16 i_y_start = ((p_data[3] & 0x3F) << 4 ) + ( p_data[4] >> 4 );
60 uint16 i_y_end = ((p_data[4] & 0x03) << 8 ) + p_data[5];
61 button_ptr->x_start = i_x_start;
62 button_ptr->x_end = i_x_end;
63 button_ptr->y_start = i_y_start;
64 button_ptr->y_end = i_y_end;
65
66 }
67 for ( uint8_t i = 0; i<3; i++ )
68 for ( uint8_t j = 0; j<2; j++ )
69 pci_packet.hli.btn_colit.btn_coli[i][j] = U32_AT( &pci_packet.hli.btn_colit.btn_coli[i][j] );
70 #endif
71 if( !is_running )
72 {
73 b_abort = false;
74 is_running = !vlc_clone( &thread, EventThread, this, VLC_THREAD_PRIORITY_LOW );
75 }
76 }
ResetPci()77 void event_thread_t::ResetPci()
78 {
79 if( !is_running )
80 return;
81
82 vlc_mutex_lock( &lock );
83 b_abort = true;
84 vlc_cond_signal( &wait );
85 vlc_mutex_unlock( &lock );
86
87 vlc_join( thread, NULL );
88 is_running = false;
89 }
EventMouse(vlc_object_t * p_this,char const * psz_var,vlc_value_t,vlc_value_t,void * p_data)90 int event_thread_t::EventMouse( vlc_object_t *p_this, char const *psz_var,
91 vlc_value_t, vlc_value_t, void *p_data )
92 {
93 event_thread_t *p_ev = (event_thread_t *) p_data;
94 vlc_mutex_lock( &p_ev->lock );
95 if( psz_var[6] == 'c' )
96 {
97 p_ev->b_clicked = true;
98 msg_Dbg( p_this, "Event Mouse: clicked");
99 }
100 else if( psz_var[6] == 'm' )
101 p_ev->b_moved = true;
102 vlc_cond_signal( &p_ev->wait );
103 vlc_mutex_unlock( &p_ev->lock );
104
105 return VLC_SUCCESS;
106 }
107
EventKey(vlc_object_t * p_this,char const *,vlc_value_t,vlc_value_t newval,void * p_data)108 int event_thread_t::EventKey( vlc_object_t *p_this, char const *,
109 vlc_value_t, vlc_value_t newval, void *p_data )
110 {
111 event_thread_t *p_ev = (event_thread_t *) p_data;
112 vlc_mutex_lock( &p_ev->lock );
113 p_ev->i_key_action = newval.i_int;
114 vlc_cond_signal( &p_ev->wait );
115 vlc_mutex_unlock( &p_ev->lock );
116 msg_Dbg( p_this, "Event Key");
117
118 return VLC_SUCCESS;
119 }
120
EventInput(vlc_object_t * p_this,char const *,vlc_value_t,vlc_value_t newval,void * p_data)121 int event_thread_t::EventInput( vlc_object_t *p_this, char const *,
122 vlc_value_t, vlc_value_t newval, void *p_data )
123 {
124 VLC_UNUSED( p_this );
125 event_thread_t *p_ev = (event_thread_t *) p_data;
126 vlc_mutex_lock( &p_ev->lock );
127 if( newval.i_int == INPUT_EVENT_VOUT )
128 {
129 p_ev->b_vout |= true;
130 vlc_cond_signal( &p_ev->wait );
131 }
132 vlc_mutex_unlock( &p_ev->lock );
133
134 return VLC_SUCCESS;
135 }
136
EventThread()137 void event_thread_t::EventThread()
138 {
139 demux_sys_t *p_sys = p_demux->p_sys;
140 vlc_object_t *p_vout = NULL;
141 int canc = vlc_savecancel ();
142
143 b_moved = false;
144 b_clicked = false;
145 i_key_action = 0;
146 b_vout = true;
147
148 /* catch all key event */
149 var_AddCallback( p_demux->obj.libvlc, "key-action", EventKey, this );
150 /* catch input event */
151 var_AddCallback( p_demux->p_input, "intf-event", EventInput, this );
152
153 /* main loop */
154 for( ;; )
155 {
156 vlc_mutex_lock( &lock );
157 while( !b_abort && !i_key_action && !b_moved && !b_clicked && !b_vout)
158 vlc_cond_wait( &wait, &lock );
159
160 if( b_abort )
161 {
162 vlc_mutex_unlock( &lock );
163 break;
164 }
165
166 /* KEY part */
167 if( i_key_action )
168 {
169 msg_Dbg( p_demux, "Handle Key Event");
170
171 pci_t *pci = &pci_packet;
172
173 uint16 i_curr_button = p_sys->dvd_interpretor.GetSPRM( 0x88 );
174
175 switch( i_key_action )
176 {
177 case ACTIONID_NAV_LEFT:
178 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
179 {
180 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
181 if ( p_button_ptr->left > 0 && p_button_ptr->left <= pci->hli.hl_gi.btn_ns )
182 {
183 i_curr_button = p_button_ptr->left;
184 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
185 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
186 if ( button_ptr.auto_action_mode )
187 {
188 vlc_mutex_unlock( &lock );
189 vlc_mutex_lock( &p_sys->lock_demuxer );
190
191 // process the button action
192 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
193
194 vlc_mutex_unlock( &p_sys->lock_demuxer );
195 vlc_mutex_lock( &lock );
196 }
197 }
198 }
199 break;
200 case ACTIONID_NAV_RIGHT:
201 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
202 {
203 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
204 if ( p_button_ptr->right > 0 && p_button_ptr->right <= pci->hli.hl_gi.btn_ns )
205 {
206 i_curr_button = p_button_ptr->right;
207 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
208 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
209 if ( button_ptr.auto_action_mode )
210 {
211 vlc_mutex_unlock( &lock );
212 vlc_mutex_lock( &p_sys->lock_demuxer );
213
214 // process the button action
215 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
216
217 vlc_mutex_unlock( &p_sys->lock_demuxer );
218 vlc_mutex_lock( &lock );
219 }
220 }
221 }
222 break;
223 case ACTIONID_NAV_UP:
224 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
225 {
226 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
227 if ( p_button_ptr->up > 0 && p_button_ptr->up <= pci->hli.hl_gi.btn_ns )
228 {
229 i_curr_button = p_button_ptr->up;
230 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
231 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
232 if ( button_ptr.auto_action_mode )
233 {
234 vlc_mutex_unlock( &lock );
235 vlc_mutex_lock( &p_sys->lock_demuxer );
236
237 // process the button action
238 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
239
240 vlc_mutex_unlock( &p_sys->lock_demuxer );
241 vlc_mutex_lock( &lock );
242 }
243 }
244 }
245 break;
246 case ACTIONID_NAV_DOWN:
247 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
248 {
249 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
250 if ( p_button_ptr->down > 0 && p_button_ptr->down <= pci->hli.hl_gi.btn_ns )
251 {
252 i_curr_button = p_button_ptr->down;
253 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
254 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
255 if ( button_ptr.auto_action_mode )
256 {
257 vlc_mutex_unlock( &lock );
258 vlc_mutex_lock( &p_sys->lock_demuxer );
259
260 // process the button action
261 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
262
263 vlc_mutex_unlock( &p_sys->lock_demuxer );
264 vlc_mutex_lock( &lock );
265 }
266 }
267 }
268 break;
269 case ACTIONID_NAV_ACTIVATE:
270 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
271 {
272 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
273
274 vlc_mutex_unlock( &lock );
275 vlc_mutex_lock( &p_sys->lock_demuxer );
276
277 // process the button action
278 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
279
280 vlc_mutex_unlock( &p_sys->lock_demuxer );
281 vlc_mutex_lock( &lock );
282 }
283 break;
284 default:
285 break;
286 }
287 i_key_action = 0;
288 }
289
290 /* MOUSE part */
291 if( p_vout && ( b_moved || b_clicked ) )
292 {
293 int x, y;
294
295 var_GetCoords( p_vout, "mouse-moved", &x, &y );
296 pci_t *pci = &pci_packet;
297
298 if( b_clicked )
299 {
300 int32_t button;
301 int32_t best,dist,d;
302 int32_t mx,my,dx,dy;
303
304 msg_Dbg( p_demux, "Handle Mouse Event: Mouse clicked x(%d)*y(%d)", x, y);
305
306 // get current button
307 best = 0;
308 dist = 0x08000000; /* >> than (720*720)+(567*567); */
309 for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++)
310 {
311 btni_t *button_ptr = &(pci->hli.btnit[button-1]);
312
313 if(((unsigned)x >= button_ptr->x_start)
314 && ((unsigned)x <= button_ptr->x_end)
315 && ((unsigned)y >= button_ptr->y_start)
316 && ((unsigned)y <= button_ptr->y_end))
317 {
318 mx = (button_ptr->x_start + button_ptr->x_end)/2;
319 my = (button_ptr->y_start + button_ptr->y_end)/2;
320 dx = mx - x;
321 dy = my - y;
322 d = (dx*dx) + (dy*dy);
323 /* If the mouse is within the button and the mouse is closer
324 * to the center of this button then it is the best choice. */
325 if(d < dist) {
326 dist = d;
327 best = button;
328 }
329 }
330 }
331
332 if ( best != 0)
333 {
334 btni_t button_ptr = pci->hli.btnit[best-1];
335 uint16 i_curr_button = p_sys->dvd_interpretor.GetSPRM( 0x88 );
336
337 msg_Dbg( &p_sys->demuxer, "Clicked button %d", best );
338 vlc_mutex_unlock( &lock );
339 vlc_mutex_lock( &p_sys->lock_demuxer );
340
341 // process the button action
342 p_sys->dvd_interpretor.SetSPRM( 0x88, best );
343 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
344
345 msg_Dbg( &p_sys->demuxer, "Processed button %d", best );
346
347 // select new button
348 if ( best != i_curr_button )
349 {
350 uint32_t i_palette;
351
352 if(button_ptr.btn_coln != 0) {
353 i_palette = pci->hli.btn_colit.btn_coli[button_ptr.btn_coln-1][1];
354 } else {
355 i_palette = 0;
356 }
357
358 for( int i = 0; i < 4; i++ )
359 {
360 uint32_t i_yuv = 0xFF;//p_sys->clut[(hl.palette>>(16+i*4))&0x0f];
361 uint8_t i_alpha = (i_palette>>(i*4))&0x0f;
362 i_alpha = i_alpha == 0xf ? 0xff : i_alpha << 4;
363
364 p_sys->palette[i][0] = (i_yuv >> 16) & 0xff;
365 p_sys->palette[i][1] = (i_yuv >> 0) & 0xff;
366 p_sys->palette[i][2] = (i_yuv >> 8) & 0xff;
367 p_sys->palette[i][3] = i_alpha;
368 }
369
370 vlc_global_lock( VLC_HIGHLIGHT_MUTEX );
371 var_SetInteger( p_demux->p_input, "x-start",
372 button_ptr.x_start );
373 var_SetInteger( p_demux->p_input, "x-end",
374 button_ptr.x_end );
375 var_SetInteger( p_demux->p_input, "y-start",
376 button_ptr.y_start );
377 var_SetInteger( p_demux->p_input, "y-end",
378 button_ptr.y_end );
379 var_SetAddress( p_demux->p_input, "menu-palette",
380 p_sys->palette );
381 var_SetBool( p_demux->p_input, "highlight", true );
382 vlc_global_unlock( VLC_HIGHLIGHT_MUTEX );
383 }
384 vlc_mutex_unlock( &p_sys->lock_demuxer );
385 vlc_mutex_lock( &lock );
386 }
387 }
388 else if( b_moved )
389 {
390 // dvdnav_mouse_select( NULL, pci, x, y );
391 }
392
393 b_moved = false;
394 b_clicked = false;
395 }
396
397 b_vout = false;
398 vlc_mutex_unlock( &lock );
399
400 /* Always check vout */
401 if( p_vout == NULL )
402 {
403 p_vout = (vlc_object_t*) input_GetVout(p_demux->p_input);
404 if( p_vout)
405 {
406 var_AddCallback( p_vout, "mouse-moved", EventMouse, this );
407 var_AddCallback( p_vout, "mouse-clicked", EventMouse, this );
408 }
409 }
410 }
411
412 /* Release callback */
413 if( p_vout )
414 {
415 var_DelCallback( p_vout, "mouse-moved", EventMouse, this );
416 var_DelCallback( p_vout, "mouse-clicked", EventMouse, this );
417 vlc_object_release( p_vout );
418 }
419 var_DelCallback( p_demux->p_input, "intf-event", EventInput, this );
420 var_DelCallback( p_demux->obj.libvlc, "key-action", EventKey, this );
421
422 vlc_restorecancel (canc);
423 }
424
EventThread(void * data)425 void *event_thread_t::EventThread(void *data)
426 {
427 static_cast<event_thread_t*>(data)->EventThread();
428 return NULL;
429 }
430
431
~demux_sys_t()432 demux_sys_t::~demux_sys_t()
433 {
434 CleanUi();
435 size_t i;
436 for ( i=0; i<streams.size(); i++ )
437 delete streams[i];
438 for ( i=0; i<opened_segments.size(); i++ )
439 delete opened_segments[i];
440 for ( i=0; i<used_vsegments.size(); i++ )
441 delete used_vsegments[i];
442 for ( i=0; i<stored_attachments.size(); i++ )
443 delete stored_attachments[i];
444 if( meta ) vlc_meta_Delete( meta );
445
446 while( titles.size() )
447 { vlc_input_title_Delete( titles.back() ); titles.pop_back();}
448
449 vlc_mutex_destroy( &lock_demuxer );
450 }
451
452
AnalyseAllSegmentsFound(demux_t * p_demux,matroska_stream_c * p_stream1,bool b_initial)453 bool demux_sys_t::AnalyseAllSegmentsFound( demux_t *p_demux, matroska_stream_c *p_stream1, bool b_initial )
454 {
455 int i_upper_lvl = 0;
456 EbmlElement *p_l0;
457 bool b_keep_stream = false, b_keep_segment = false;
458
459 /* verify the EBML Header... it shouldn't be bigger than 1kB */
460 p_l0 = p_stream1->estream.FindNextID(EBML_INFO(EbmlHead), 1024);
461 if (p_l0 == NULL)
462 {
463 msg_Err( p_demux, "No EBML header found" );
464 return false;
465 }
466
467 /* verify we can read this Segment */
468 try
469 {
470 p_l0->Read( p_stream1->estream, EBML_CLASS_CONTEXT(EbmlHead), i_upper_lvl, p_l0, true);
471 }
472 catch(...)
473 {
474 msg_Err(p_demux, "EBML Header Read failed");
475 return false;
476 }
477
478 EDocType doc_type = GetChild<EDocType>(*static_cast<EbmlHead*>(p_l0));
479 if (std::string(doc_type) != "matroska" && std::string(doc_type) != "webm" )
480 {
481 msg_Err( p_demux, "Not a Matroska file : DocType = %s ", std::string(doc_type).c_str());
482 return false;
483 }
484
485 EDocTypeReadVersion doc_read_version = GetChild<EDocTypeReadVersion>(*static_cast<EbmlHead*>(p_l0));
486 if (uint64(doc_read_version) > 2)
487 {
488 msg_Err( p_demux, "matroska file needs version %" PRId64 " but only versions 1 & 2 supported", uint64(doc_read_version));
489 return false;
490 }
491
492 delete p_l0;
493
494
495 // find all segments in this file
496 p_l0 = p_stream1->estream.FindNextID(EBML_INFO(KaxSegment), UINT64_MAX);
497 if (p_l0 == NULL)
498 {
499 msg_Err( p_demux, "No segment found" );
500 return false;
501 }
502
503 while (p_l0 != 0)
504 {
505 bool b_l0_handled = false;
506
507 if ( MKV_IS_ID( p_l0, KaxSegment) )
508 {
509 matroska_segment_c *p_segment1 = new matroska_segment_c( *this, p_stream1->estream, (KaxSegment*)p_l0 );
510
511 p_segment1->Preload();
512
513 if ( !p_segment1->p_segment_uid ||
514 (b_keep_segment = (FindSegment( *p_segment1->p_segment_uid ) == NULL)))
515 {
516 opened_segments.push_back( p_segment1 );
517 b_keep_stream = true;
518 p_stream1->segments.push_back( p_segment1 );
519 }
520 else
521 {
522 p_segment1->segment = NULL;
523 delete p_segment1;
524 }
525
526 b_l0_handled = true;
527 }
528
529 EbmlElement* p_l0_prev = p_l0;
530
531 bool b_seekable;
532 vlc_stream_Control( demuxer.s, STREAM_CAN_SEEK, &b_seekable );
533
534 if (p_l0->IsFiniteSize() && b_seekable )
535 {
536 p_l0->SkipData(p_stream1->estream, KaxMatroska_Context);
537 p_l0 = p_stream1->estream.FindNextID(EBML_INFO(KaxSegment), UINT64_MAX);
538 }
539 else
540 {
541 p_l0 = NULL;
542 }
543
544 if( b_l0_handled == false )
545 delete p_l0_prev;
546 }
547
548 if ( !b_keep_stream )
549 return false;
550
551 return true;
552 }
553
InitUi()554 void demux_sys_t::InitUi()
555 {
556 msg_Dbg( &demuxer, "Starting the UI Hook" );
557
558 /* FIXME hack hack hack hack FIXME */
559 /* Get p_input and create variable */
560 p_input = demuxer.p_input;
561 if( p_input )
562 {
563 var_Create( p_input, "x-start", VLC_VAR_INTEGER );
564 var_Create( p_input, "y-start", VLC_VAR_INTEGER );
565 var_Create( p_input, "x-end", VLC_VAR_INTEGER );
566 var_Create( p_input, "y-end", VLC_VAR_INTEGER );
567 var_Create( p_input, "color", VLC_VAR_ADDRESS );
568 var_Create( p_input, "menu-palette", VLC_VAR_ADDRESS );
569 var_Create( p_input, "highlight", VLC_VAR_BOOL );
570 }
571
572 /* Now create our event thread catcher */
573 p_ev = new event_thread_t(&demuxer);
574 }
575
CleanUi()576 void demux_sys_t::CleanUi()
577 {
578 delete p_ev;
579 p_ev = NULL;
580
581 if( p_input )
582 {
583 var_Destroy( p_input, "highlight" );
584 var_Destroy( p_input, "x-start" );
585 var_Destroy( p_input, "x-end" );
586 var_Destroy( p_input, "y-start" );
587 var_Destroy( p_input, "y-end" );
588 var_Destroy( p_input, "color" );
589 var_Destroy( p_input, "menu-palette" );
590 }
591
592 msg_Dbg( &demuxer, "Stopping the UI Hook" );
593 }
594
PreloadFamily(const matroska_segment_c & of_segment)595 void demux_sys_t::PreloadFamily( const matroska_segment_c & of_segment )
596 {
597 for (size_t i=0; i<opened_segments.size(); i++)
598 {
599 opened_segments[i]->PreloadFamily( of_segment );
600 }
601 }
602
603 // preload all the linked segments for all preloaded segments
PreloadLinked()604 bool demux_sys_t::PreloadLinked()
605 {
606 size_t i, j, ij = 0;
607 virtual_segment_c *p_vseg;
608
609 if ( unlikely(opened_segments.size() == 0) )
610 return false;
611
612 p_current_vsegment = new (std::nothrow) virtual_segment_c( *(opened_segments[0]), opened_segments );
613 if ( !p_current_vsegment )
614 return false;
615
616 if ( unlikely(p_current_vsegment->CurrentEdition() == NULL) )
617 return false;
618
619 /* Set current chapter */
620 p_current_vsegment->p_current_vchapter = p_current_vsegment->CurrentEdition()->getChapterbyTimecode(0);
621 msg_Dbg( &demuxer, "NEW START CHAPTER uid=%" PRId64, p_current_vsegment->p_current_vchapter && p_current_vsegment->p_current_vchapter->p_chapter ?
622 p_current_vsegment->p_current_vchapter->p_chapter->i_uid : 0 );
623
624 used_vsegments.push_back( p_current_vsegment );
625
626 for ( i=1; i< opened_segments.size(); i++ )
627 {
628 /* add segments from the same family to used_segments */
629 if ( opened_segments[0]->SameFamily( *(opened_segments[i]) ) )
630 {
631 virtual_segment_c *p_vsegment = new (std::nothrow) virtual_segment_c( *(opened_segments[i]), opened_segments );
632 if ( likely(p_vsegment != NULL) )
633 used_vsegments.push_back( p_vsegment );
634 }
635 }
636
637 // publish all editions of all usable segment
638 for ( i=0; i< used_vsegments.size(); i++ )
639 {
640 p_vseg = used_vsegments[i];
641 if ( p_vseg->Editions() != NULL )
642 {
643 for ( j=0; j<p_vseg->Editions()->size(); j++ )
644 {
645 virtual_edition_c * p_ved = (*p_vseg->Editions())[j];
646 input_title_t *p_title = vlc_input_title_New();
647 int i_chapters;
648
649 // TODO use a name for each edition, let the TITLE deal with a codec name
650 if ( p_title->psz_name == NULL )
651 {
652 if( p_ved->GetMainName().length() )
653 p_title->psz_name = strdup( p_ved->GetMainName().c_str() );
654 else
655 {
656 /* Check in tags if the edition has a name */
657
658 /* We use only the tags of the first segment as it contains the edition */
659 matroska_segment_c::tags_t const& tags = opened_segments[0]->tags;
660 uint64_t i_ed_uid = 0;
661 if( p_ved->p_edition )
662 i_ed_uid = (uint64_t) p_ved->p_edition->i_uid;
663
664 for( size_t k = 0; k < tags.size(); k++ )
665 {
666 if( tags[k].i_tag_type == EDITION_UID && tags[k].i_uid == i_ed_uid )
667 for( size_t l = 0; l < tags[k].simple_tags.size(); l++ )
668 {
669 SimpleTag const& st = tags[k].simple_tags[l];
670 if ( st.tag_name == "TITLE" )
671 {
672 msg_Dbg( &demuxer, "Using title \"%s\" from tag for edition %" PRIu64, st.value.c_str (), i_ed_uid );
673 p_title->psz_name = strdup( st.value.c_str () );
674 break;
675 }
676 }
677 }
678
679 if( !p_title->psz_name &&
680 asprintf(&(p_title->psz_name), "%s %d", "Segment", (int)ij) == -1 )
681 p_title->psz_name = NULL;
682 }
683 }
684
685 ij++;
686 i_chapters = 0;
687 p_ved->PublishChapters( *p_title, i_chapters, 0 );
688
689 // Input duration into i_length
690 p_title->i_length = p_ved->i_duration;
691
692 titles.push_back( p_title );
693 }
694 }
695 p_vseg->i_sys_title = p_vseg->i_current_edition;
696 }
697
698 // TODO decide which segment should be first used (VMG for DVD)
699
700 return true;
701 }
702
FreeUnused()703 bool demux_sys_t::FreeUnused()
704 {
705 auto sIt = std::remove_if(begin(streams), end(streams), [](const matroska_stream_c* p_s) {
706 return !p_s->isUsed();
707 });
708 for (auto it = sIt; it != end(streams); ++it)
709 delete *it;
710 streams.erase(sIt, end(streams));
711
712 auto sgIt = std::remove_if(begin(opened_segments), end(opened_segments),
713 [](const matroska_segment_c* p_sg) {
714 return !p_sg->b_preloaded;
715 });
716 for (auto it = sgIt; it != end(opened_segments); ++it)
717 delete *it;
718 opened_segments.erase(sgIt, end(opened_segments));
719
720 return !streams.empty() && !opened_segments.empty();
721 }
722
PreparePlayback(virtual_segment_c & new_vsegment,mtime_t i_mk_date)723 bool demux_sys_t::PreparePlayback( virtual_segment_c & new_vsegment, mtime_t i_mk_date )
724 {
725 if ( p_current_vsegment != &new_vsegment )
726 {
727 if ( p_current_vsegment->CurrentSegment() != NULL )
728 p_current_vsegment->CurrentSegment()->ESDestroy();
729
730 p_current_vsegment = &new_vsegment;
731 p_current_vsegment->CurrentSegment()->ESCreate();
732 i_current_title = p_current_vsegment->i_sys_title;
733 }
734 if( !p_current_vsegment->CurrentSegment() )
735 return false;
736 if( !p_current_vsegment->CurrentSegment()->b_cues )
737 msg_Warn( &p_current_vsegment->CurrentSegment()->sys.demuxer, "no cues/empty cues found->seek won't be precise" );
738
739 f_duration = p_current_vsegment->Duration();
740
741 /* add information */
742 p_current_vsegment->CurrentSegment()->InformationCreate( );
743 p_current_vsegment->CurrentSegment()->ESCreate( );
744
745 /* Seek to the beginning */
746 p_current_vsegment->Seek(p_current_vsegment->CurrentSegment()->sys.demuxer,
747 i_mk_date, p_current_vsegment->p_current_vchapter );
748
749 return true;
750 }
751
JumpTo(virtual_segment_c & vsegment,virtual_chapter_c & vchapter)752 void demux_sys_t::JumpTo( virtual_segment_c & vsegment, virtual_chapter_c & vchapter )
753 {
754 if ( !vchapter.p_chapter || !vchapter.p_chapter->Enter( true ) )
755 {
756 // jump to the location in the found segment
757 vsegment.Seek( demuxer, vchapter.i_mk_virtual_start_time, &vchapter );
758 }
759 }
760
FindSegment(const EbmlBinary & uid) const761 matroska_segment_c *demux_sys_t::FindSegment( const EbmlBinary & uid ) const
762 {
763 for (size_t i=0; i<opened_segments.size(); i++)
764 {
765 if ( opened_segments[i]->p_segment_uid && *opened_segments[i]->p_segment_uid == uid )
766 return opened_segments[i];
767 }
768 return NULL;
769 }
770
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_vsegment_found)771 virtual_chapter_c *demux_sys_t::BrowseCodecPrivate( unsigned int codec_id,
772 bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ),
773 const void *p_cookie,
774 size_t i_cookie_size,
775 virtual_segment_c * &p_vsegment_found )
776 {
777 virtual_chapter_c *p_result = NULL;
778 for (size_t i=0; i<used_vsegments.size(); i++)
779 {
780 p_result = used_vsegments[i]->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
781 if ( p_result != NULL )
782 {
783 p_vsegment_found = used_vsegments[i];
784 break;
785 }
786 }
787 return p_result;
788 }
789
FindChapter(int64_t i_find_uid,virtual_segment_c * & p_vsegment_found)790 virtual_chapter_c *demux_sys_t::FindChapter( int64_t i_find_uid, virtual_segment_c * & p_vsegment_found )
791 {
792 virtual_chapter_c *p_result = NULL;
793 for (size_t i=0; i<used_vsegments.size(); i++)
794 {
795 p_result = used_vsegments[i]->FindChapter( i_find_uid );
796 if ( p_result != NULL )
797 {
798 p_vsegment_found = used_vsegments[i];
799 break;
800 }
801 }
802 return p_result;
803 }
804
805