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 demux_sys_t::~demux_sys_t()
34 for ( i=0; i<streams.size(); i++ )
36 for ( i=0; i<opened_segments.size(); i++ )
37 delete opened_segments[i];
38 for ( i=0; i<used_segments.size(); i++ )
39 delete used_segments[i];
40 for ( i=0; i<stored_attachments.size(); i++ )
41 delete stored_attachments[i];
42 if( meta ) vlc_meta_Delete( meta );
44 while( titles.size() )
45 { vlc_input_title_Delete( titles.back() ); titles.pop_back();}
47 vlc_mutex_destroy( &lock_demuxer );
51 matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( demux_t *p_demux, EbmlStream *p_estream, bool b_initial )
55 EbmlElement *p_l0, *p_l1, *p_l2;
56 bool b_keep_stream = false, b_keep_segment;
58 // verify the EBML Header
59 p_l0 = p_estream->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL);
62 msg_Err( p_demux, "No EBML header found" );
66 // verify we can read this Segment, we only support Matroska version 1 for now
67 p_l0->Read(*p_estream, EbmlHead::ClassInfos.Context, i_upper_lvl, p_l0, true);
69 EDocType doc_type = GetChild<EDocType>(*static_cast<EbmlHead*>(p_l0));
70 if (std::string(doc_type) != "matroska")
72 msg_Err( p_demux, "Not a Matroska file : DocType = %s ", std::string(doc_type).c_str());
76 EDocTypeReadVersion doc_read_version = GetChild<EDocTypeReadVersion>(*static_cast<EbmlHead*>(p_l0));
77 if (uint64(doc_read_version) > 2)
79 msg_Err( p_demux, "This matroska file is needs version %"PRId64" and this VLC only supports version 1 & 2", uint64(doc_read_version));
86 // find all segments in this file
87 p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFFLL);
93 matroska_stream_c *p_stream1 = new matroska_stream_c( *this );
97 if (EbmlId(*p_l0) == KaxSegment::ClassInfos.GlobalId)
100 matroska_segment_c *p_segment1 = new matroska_segment_c( *this, *p_estream );
101 b_keep_segment = b_initial;
103 ep = new EbmlParser(p_estream, p_l0, &demuxer );
105 p_segment1->segment = (KaxSegment*)p_l0;
107 while ((p_l1 = ep->Get()))
109 if (MKV_IS_ID(p_l1, KaxInfo))
111 // find the families of this segment
112 KaxInfo *p_info = static_cast<KaxInfo*>(p_l1);
114 p_info->Read(*p_estream, KaxInfo::ClassInfos.Context, i_upper_lvl, p_l2, true);
115 for( i = 0; i < p_info->ListSize(); i++ )
117 EbmlElement *l = (*p_info)[i];
119 if( MKV_IS_ID( l, KaxSegmentUID ) )
121 KaxSegmentUID *p_uid = static_cast<KaxSegmentUID*>(l);
122 b_keep_segment = (FindSegment( *p_uid ) == NULL);
123 if ( !b_keep_segment )
124 break; // this segment is already known
125 opened_segments.push_back( p_segment1 );
126 delete p_segment1->p_segment_uid;
127 p_segment1->p_segment_uid = new KaxSegmentUID(*p_uid);
129 else if( MKV_IS_ID( l, KaxPrevUID ) )
131 p_segment1->p_prev_segment_uid = new KaxPrevUID( *static_cast<KaxPrevUID*>(l) );
133 else if( MKV_IS_ID( l, KaxNextUID ) )
135 p_segment1->p_next_segment_uid = new KaxNextUID( *static_cast<KaxNextUID*>(l) );
137 else if( MKV_IS_ID( l, KaxSegmentFamily ) )
139 KaxSegmentFamily *p_fam = new KaxSegmentFamily( *static_cast<KaxSegmentFamily*>(l) );
140 p_segment1->families.push_back( p_fam );
146 if ( b_keep_segment )
148 b_keep_stream = true;
149 p_stream1->segments.push_back( p_segment1 );
153 p_segment1->segment = NULL;
157 if (p_l0->IsFiniteSize() )
159 p_l0->SkipData(*p_estream, KaxMatroska_Context);
160 p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
163 p_l0 = p_l0->SkipData(*p_estream, KaxSegment_Context);
166 if ( !b_keep_stream )
175 void demux_sys_t::StartUiThread()
179 msg_Dbg( &demuxer, "Starting the UI Hook" );
181 /* FIXME hack hack hack hack FIXME */
182 /* Get p_input and create variable */
183 p_input = (input_thread_t *) vlc_object_find( &demuxer, VLC_OBJECT_INPUT, FIND_PARENT );
184 var_Create( p_input, "x-start", VLC_VAR_INTEGER );
185 var_Create( p_input, "y-start", VLC_VAR_INTEGER );
186 var_Create( p_input, "x-end", VLC_VAR_INTEGER );
187 var_Create( p_input, "y-end", VLC_VAR_INTEGER );
188 var_Create( p_input, "color", VLC_VAR_ADDRESS );
189 var_Create( p_input, "menu-palette", VLC_VAR_ADDRESS );
190 var_Create( p_input, "highlight", VLC_VAR_BOOL );
191 var_Create( p_input, "highlight-mutex", VLC_VAR_MUTEX );
193 /* Now create our event thread catcher */
194 p_ev = (event_thread_t *) vlc_object_create( &demuxer, sizeof( event_thread_t ) );
195 p_ev->p_demux = &demuxer;
197 vlc_mutex_init( &p_ev->lock );
198 vlc_thread_create( p_ev, "mkv event thread handler", EventThread,
199 VLC_THREAD_PRIORITY_LOW );
203 void demux_sys_t::StopUiThread()
207 vlc_object_kill( p_ev );
208 vlc_thread_join( p_ev );
209 vlc_object_release( p_ev );
213 var_Destroy( p_input, "highlight-mutex" );
214 var_Destroy( p_input, "highlight" );
215 var_Destroy( p_input, "x-start" );
216 var_Destroy( p_input, "x-end" );
217 var_Destroy( p_input, "y-start" );
218 var_Destroy( p_input, "y-end" );
219 var_Destroy( p_input, "color" );
220 var_Destroy( p_input, "menu-palette" );
222 vlc_object_release( p_input );
224 msg_Dbg( &demuxer, "Stopping the UI Hook" );
229 int demux_sys_t::EventMouse( vlc_object_t *p_this, char const *psz_var,
230 vlc_value_t oldval, vlc_value_t newval, void *p_data )
232 event_thread_t *p_ev = (event_thread_t *) p_data;
233 vlc_mutex_lock( &p_ev->lock );
234 if( psz_var[6] == 'c' )
236 p_ev->b_clicked = true;
237 msg_Dbg( p_this, "Event Mouse: clicked");
239 else if( psz_var[6] == 'm' )
240 p_ev->b_moved = true;
241 vlc_mutex_unlock( &p_ev->lock );
246 int demux_sys_t::EventKey( vlc_object_t *p_this, char const *,
247 vlc_value_t, vlc_value_t newval, void *p_data )
249 event_thread_t *p_ev = (event_thread_t *) p_data;
250 vlc_mutex_lock( &p_ev->lock );
251 p_ev->i_key_action = newval.i_int;
252 vlc_mutex_unlock( &p_ev->lock );
253 msg_Dbg( p_this, "Event Key");
258 void * demux_sys_t::EventThread( vlc_object_t *p_this )
260 event_thread_t *p_ev = (event_thread_t*)p_this;
261 demux_sys_t *p_sys = p_ev->p_demux->p_sys;
262 vlc_object_t *p_vout = NULL;
263 int canc = vlc_savecancel ();
265 p_ev->b_moved = false;
266 p_ev->b_clicked = false;
267 p_ev->i_key_action = 0;
269 /* catch all key event */
270 var_AddCallback( p_ev->p_libvlc, "key-action", EventKey, p_ev );
273 while( vlc_object_alive (p_ev) )
275 if ( !p_sys->b_pci_packet_set )
282 bool b_activated = false;
285 if( p_ev->i_key_action )
287 msg_Dbg( p_ev->p_demux, "Handle Key Event");
289 vlc_mutex_lock( &p_ev->lock );
291 pci_t *pci = (pci_t *) &p_sys->pci_packet;
293 uint16 i_curr_button = p_sys->dvd_interpretor.GetSPRM( 0x88 );
295 switch( p_ev->i_key_action )
297 case ACTIONID_NAV_LEFT:
298 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
300 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
301 if ( p_button_ptr->left > 0 && p_button_ptr->left <= pci->hli.hl_gi.btn_ns )
303 i_curr_button = p_button_ptr->left;
304 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
305 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
306 if ( button_ptr.auto_action_mode )
308 vlc_mutex_unlock( &p_ev->lock );
309 vlc_mutex_lock( &p_sys->lock_demuxer );
311 // process the button action
312 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
314 vlc_mutex_unlock( &p_sys->lock_demuxer );
315 vlc_mutex_lock( &p_ev->lock );
320 case ACTIONID_NAV_RIGHT:
321 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
323 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
324 if ( p_button_ptr->right > 0 && p_button_ptr->right <= pci->hli.hl_gi.btn_ns )
326 i_curr_button = p_button_ptr->right;
327 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
328 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
329 if ( button_ptr.auto_action_mode )
331 vlc_mutex_unlock( &p_ev->lock );
332 vlc_mutex_lock( &p_sys->lock_demuxer );
334 // process the button action
335 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
337 vlc_mutex_unlock( &p_sys->lock_demuxer );
338 vlc_mutex_lock( &p_ev->lock );
343 case ACTIONID_NAV_UP:
344 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
346 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
347 if ( p_button_ptr->up > 0 && p_button_ptr->up <= pci->hli.hl_gi.btn_ns )
349 i_curr_button = p_button_ptr->up;
350 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
351 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
352 if ( button_ptr.auto_action_mode )
354 vlc_mutex_unlock( &p_ev->lock );
355 vlc_mutex_lock( &p_sys->lock_demuxer );
357 // process the button action
358 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
360 vlc_mutex_unlock( &p_sys->lock_demuxer );
361 vlc_mutex_lock( &p_ev->lock );
366 case ACTIONID_NAV_DOWN:
367 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
369 btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
370 if ( p_button_ptr->down > 0 && p_button_ptr->down <= pci->hli.hl_gi.btn_ns )
372 i_curr_button = p_button_ptr->down;
373 p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
374 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
375 if ( button_ptr.auto_action_mode )
377 vlc_mutex_unlock( &p_ev->lock );
378 vlc_mutex_lock( &p_sys->lock_demuxer );
380 // process the button action
381 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
383 vlc_mutex_unlock( &p_sys->lock_demuxer );
384 vlc_mutex_lock( &p_ev->lock );
389 case ACTIONID_NAV_ACTIVATE:
392 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
394 btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
396 vlc_mutex_unlock( &p_ev->lock );
397 vlc_mutex_lock( &p_sys->lock_demuxer );
399 // process the button action
400 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
402 vlc_mutex_unlock( &p_sys->lock_demuxer );
403 vlc_mutex_lock( &p_ev->lock );
409 p_ev->i_key_action = 0;
410 vlc_mutex_unlock( &p_ev->lock );
414 if( p_vout && ( p_ev->b_moved || p_ev->b_clicked ) )
416 vlc_value_t valx, valy;
418 vlc_mutex_lock( &p_ev->lock );
419 pci_t *pci = (pci_t *) &p_sys->pci_packet;
420 var_Get( p_vout, "mouse-x", &valx );
421 var_Get( p_vout, "mouse-y", &valy );
423 if( p_ev->b_clicked )
429 msg_Dbg( p_ev->p_demux, "Handle Mouse Event: Mouse clicked x(%d)*y(%d)", (unsigned)valx.i_int, (unsigned)valy.i_int);
432 // get current button
434 dist = 0x08000000; /* >> than (720*720)+(567*567); */
435 for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++)
437 btni_t *button_ptr = &(pci->hli.btnit[button-1]);
439 if(((unsigned)valx.i_int >= button_ptr->x_start)
440 && ((unsigned)valx.i_int <= button_ptr->x_end)
441 && ((unsigned)valy.i_int >= button_ptr->y_start)
442 && ((unsigned)valy.i_int <= button_ptr->y_end))
444 mx = (button_ptr->x_start + button_ptr->x_end)/2;
445 my = (button_ptr->y_start + button_ptr->y_end)/2;
446 dx = mx - valx.i_int;
447 dy = my - valy.i_int;
448 d = (dx*dx) + (dy*dy);
449 /* If the mouse is within the button and the mouse is closer
450 * to the center of this button then it is the best choice. */
460 btni_t button_ptr = pci->hli.btnit[best-1];
461 uint16 i_curr_button = p_sys->dvd_interpretor.GetSPRM( 0x88 );
463 msg_Dbg( &p_sys->demuxer, "Clicked button %d", best );
464 vlc_mutex_unlock( &p_ev->lock );
465 vlc_mutex_lock( &p_sys->lock_demuxer );
467 // process the button action
468 p_sys->dvd_interpretor.SetSPRM( 0x88, best );
469 p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
471 msg_Dbg( &p_sys->demuxer, "Processed button %d", best );
474 if ( best != i_curr_button )
478 if( var_Get( p_sys->p_input, "highlight-mutex", &val ) == VLC_SUCCESS )
480 vlc_mutex_t *p_mutex = (vlc_mutex_t *) val.p_address;
483 if(button_ptr.btn_coln != 0) {
484 i_palette = pci->hli.btn_colit.btn_coli[button_ptr.btn_coln-1][1];
489 for( int i = 0; i < 4; i++ )
491 uint32_t i_yuv = 0xFF;//p_sys->clut[(hl.palette>>(16+i*4))&0x0f];
492 uint8_t i_alpha = (i_palette>>(i*4))&0x0f;
493 i_alpha = i_alpha == 0xf ? 0xff : i_alpha << 4;
495 p_sys->palette[i][0] = (i_yuv >> 16) & 0xff;
496 p_sys->palette[i][1] = (i_yuv >> 0) & 0xff;
497 p_sys->palette[i][2] = (i_yuv >> 8) & 0xff;
498 p_sys->palette[i][3] = i_alpha;
501 vlc_mutex_lock( p_mutex );
502 val.i_int = button_ptr.x_start; var_Set( p_sys->p_input, "x-start", val );
503 val.i_int = button_ptr.x_end; var_Set( p_sys->p_input, "x-end", val );
504 val.i_int = button_ptr.y_start; var_Set( p_sys->p_input, "y-start", val );
505 val.i_int = button_ptr.y_end; var_Set( p_sys->p_input, "y-end", val );
507 val.p_address = (void *)p_sys->palette;
508 var_Set( p_sys->p_input, "menu-palette", val );
510 val.b_bool = true; var_Set( p_sys->p_input, "highlight", val );
511 vlc_mutex_unlock( p_mutex );
514 vlc_mutex_unlock( &p_sys->lock_demuxer );
515 vlc_mutex_lock( &p_ev->lock );
518 else if( p_ev->b_moved )
520 // dvdnav_mouse_select( NULL, pci, valx.i_int, valy.i_int );
523 p_ev->b_moved = false;
524 p_ev->b_clicked = false;
525 vlc_mutex_unlock( &p_ev->lock );
529 if( p_vout && !vlc_object_alive (p_vout) )
531 var_DelCallback( p_vout, "mouse-moved", EventMouse, p_ev );
532 var_DelCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
533 vlc_object_release( p_vout );
537 else if( p_vout == NULL )
539 p_vout = (vlc_object_t*) vlc_object_find( p_sys->p_input, VLC_OBJECT_VOUT,
543 var_AddCallback( p_vout, "mouse-moved", EventMouse, p_ev );
544 var_AddCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
548 /* Wait a bit, 10ms */
552 /* Release callback */
555 var_DelCallback( p_vout, "mouse-moved", EventMouse, p_ev );
556 var_DelCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
557 vlc_object_release( p_vout );
559 var_DelCallback( p_ev->p_libvlc, "key-action", EventKey, p_ev );
561 vlc_mutex_destroy( &p_ev->lock );
563 vlc_restorecancel (canc);
567 void demux_sys_t::PreloadFamily( const matroska_segment_c & of_segment )
569 for (size_t i=0; i<opened_segments.size(); i++)
571 opened_segments[i]->PreloadFamily( of_segment );
575 // preload all the linked segments for all preloaded segments
576 void demux_sys_t::PreloadLinked( matroska_segment_c *p_segment )
578 size_t i_preloaded, i, j;
579 virtual_segment_c *p_seg;
581 p_current_segment = VirtualFromSegments( p_segment );
583 used_segments.push_back( p_current_segment );
585 // create all the other virtual segments of the family
588 for ( i=0; i< opened_segments.size(); i++ )
590 if ( opened_segments[i]->b_preloaded && !IsUsedSegment( *opened_segments[i] ) )
592 p_seg = VirtualFromSegments( opened_segments[i] );
593 used_segments.push_back( p_seg );
597 } while ( i_preloaded ); // worst case: will stop when all segments are found as family related
599 // publish all editions of all usable segment
600 for ( i=0; i< used_segments.size(); i++ )
602 p_seg = used_segments[i];
603 if ( p_seg->p_editions != NULL )
605 input_title_t *p_title = vlc_input_title_New();
606 p_seg->i_sys_title = i;
609 // TODO use a name for each edition, let the TITLE deal with a codec name
610 for ( j=0; j<p_seg->p_editions->size(); j++ )
612 if ( p_title->psz_name == NULL )
614 const char* psz_tmp = (*p_seg->p_editions)[j]->GetMainName().c_str();
615 if( *psz_tmp != '\0' )
616 p_title->psz_name = strdup( psz_tmp );
619 chapter_edition_c *p_edition = (*p_seg->p_editions)[j];
622 p_edition->PublishChapters( *p_title, i_chapters, 0 );
625 // create a name if there is none
626 if ( p_title->psz_name == NULL )
628 if( asprintf(&(p_title->psz_name), "%s %d", N_("Segment"), (int)i) == -1 )
629 p_title->psz_name = NULL;
632 titles.push_back( p_title );
636 // TODO decide which segment should be first used (VMG for DVD)
639 bool demux_sys_t::IsUsedSegment( matroska_segment_c &segment ) const
641 for ( size_t i=0; i< used_segments.size(); i++ )
643 if ( used_segments[i]->FindUID( *segment.p_segment_uid ) )
649 virtual_segment_c *demux_sys_t::VirtualFromSegments( matroska_segment_c *p_segment ) const
651 size_t i_preloaded, i;
653 virtual_segment_c *p_result = new virtual_segment_c( p_segment );
655 // fill our current virtual segment with all hard linked segments
658 for ( i=0; i< opened_segments.size(); i++ )
660 i_preloaded += p_result->AddSegment( opened_segments[i] );
662 } while ( i_preloaded ); // worst case: will stop when all segments are found as linked
666 p_result->PreloadLinked( );
668 p_result->PrepareChapters( );
673 bool demux_sys_t::PreparePlayback( virtual_segment_c *p_new_segment )
675 if ( p_new_segment != NULL && p_new_segment != p_current_segment )
677 if ( p_current_segment != NULL && p_current_segment->Segment() != NULL )
678 p_current_segment->Segment()->UnSelect();
680 p_current_segment = p_new_segment;
681 i_current_title = p_new_segment->i_sys_title;
683 if( !p_current_segment->Segment()->b_cues )
684 msg_Warn( &p_current_segment->Segment()->sys.demuxer, "no cues/empty cues found->seek won't be precise" );
686 f_duration = p_current_segment->Duration();
688 /* add information */
689 p_current_segment->Segment()->InformationCreate( );
690 p_current_segment->Segment()->Select( 0 );
695 void demux_sys_t::JumpTo( virtual_segment_c & vsegment, chapter_item_c * p_chapter )
697 // if the segment is not part of the current segment, select the new one
698 if ( &vsegment != p_current_segment )
700 PreparePlayback( &vsegment );
703 if ( p_chapter != NULL )
705 if ( !p_chapter->Enter( true ) )
707 // jump to the location in the found segment
708 vsegment.Seek( demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
714 matroska_segment_c *demux_sys_t::FindSegment( const EbmlBinary & uid ) const
716 for (size_t i=0; i<opened_segments.size(); i++)
718 if ( *opened_segments[i]->p_segment_uid == uid )
719 return opened_segments[i];
724 chapter_item_c *demux_sys_t::BrowseCodecPrivate( unsigned int codec_id,
725 bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ),
726 const void *p_cookie,
727 size_t i_cookie_size,
728 virtual_segment_c * &p_segment_found )
730 chapter_item_c *p_result = NULL;
731 for (size_t i=0; i<used_segments.size(); i++)
733 p_result = used_segments[i]->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
734 if ( p_result != NULL )
736 p_segment_found = used_segments[i];
743 chapter_item_c *demux_sys_t::FindChapter( int64_t i_find_uid, virtual_segment_c * & p_segment_found )
745 chapter_item_c *p_result = NULL;
746 for (size_t i=0; i<used_segments.size(); i++)
748 p_result = used_segments[i]->FindChapter( i_find_uid );
749 if ( p_result != NULL )
751 p_segment_found = used_segments[i];
758 void demux_sys_t::SwapButtons()
760 #ifndef WORDS_BIGENDIAN
761 uint8_t button, i, j;
763 for( button = 1; button <= pci_packet.hli.hl_gi.btn_ns; button++) {
764 btni_t *button_ptr = &(pci_packet.hli.btnit[button-1]);
765 binary *p_data = (binary*) button_ptr;
767 uint16 i_x_start = ((p_data[0] & 0x3F) << 4 ) + ( p_data[1] >> 4 );
768 uint16 i_x_end = ((p_data[1] & 0x03) << 8 ) + p_data[2];
769 uint16 i_y_start = ((p_data[3] & 0x3F) << 4 ) + ( p_data[4] >> 4 );
770 uint16 i_y_end = ((p_data[4] & 0x03) << 8 ) + p_data[5];
771 button_ptr->x_start = i_x_start;
772 button_ptr->x_end = i_x_end;
773 button_ptr->y_start = i_y_start;
774 button_ptr->y_end = i_y_end;
777 for ( i = 0; i<3; i++ )
779 for ( j = 0; j<2; j++ )
781 pci_packet.hli.btn_colit.btn_coli[i][j] = U32_AT( &pci_packet.hli.btn_colit.btn_coli[i][j] );