+
+void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset )
+{
+ KaxBlock *block;
+ int i_track_skipping;
+ int64_t i_block_duration;
+ int64_t i_block_ref1;
+ int64_t i_block_ref2;
+ size_t i_track;
+ int64_t i_seek_position = i_start_pos;
+ int64_t i_seek_time = i_start_time;
+
+ if ( i_index > 0 )
+ {
+ int i_idx = 0;
+
+ for( ; i_idx < i_index; i_idx++ )
+ {
+ if( index[i_idx].i_time + i_time_offset > i_date )
+ {
+ break;
+ }
+ }
+
+ if( i_idx > 0 )
+ {
+ i_idx--;
+ }
+
+ i_seek_position = index[i_idx].i_position;
+ i_seek_time = index[i_idx].i_time;
+ }
+
+ msg_Dbg( &sys.demuxer, "seek got "I64Fd" (%d%%)",
+ i_seek_time, (int)( 100 * i_seek_position / stream_Size( sys.demuxer.s ) ) );
+
+ es.I_O().setFilePointer( i_seek_position, seek_beginning );
+
+ delete ep;
+ ep = new EbmlParser( &es, segment, &sys.demuxer );
+ cluster = NULL;
+
+ sys.i_start_pts = i_date;
+
+ es_out_Control( sys.demuxer.out, ES_OUT_RESET_PCR );
+
+ /* now parse until key frame */
+ i_track_skipping = 0;
+ for( i_track = 0; i_track < tracks.size(); i_track++ )
+ {
+ if( tracks[i_track]->fmt.i_cat == VIDEO_ES )
+ {
+ tracks[i_track]->b_search_keyframe = VLC_TRUE;
+ i_track_skipping++;
+ }
+ es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, tracks[i_track]->p_es, i_date );
+ }
+
+
+ while( i_track_skipping > 0 )
+ {
+ if( BlockGet( &block, &i_block_ref1, &i_block_ref2, &i_block_duration ) )
+ {
+ msg_Warn( &sys.demuxer, "cannot get block EOF?" );
+
+ return;
+ }
+
+ for( i_track = 0; i_track < tracks.size(); i_track++ )
+ {
+ if( tracks[i_track]->i_number == block->TrackNum() )
+ {
+ break;
+ }
+ }
+
+ sys.i_pts = sys.i_chapter_time + block->GlobalTimecode() / (mtime_t) 1000;
+
+ if( i_track < tracks.size() )
+ {
+ if( sys.i_pts >= sys.i_start_pts )
+ {
+ BlockDecode( &sys.demuxer, block, sys.i_pts, 0 );
+ i_track_skipping = 0;
+ }
+ else if( tracks[i_track]->fmt.i_cat == VIDEO_ES )
+ {
+ if( i_block_ref1 == -1 && tracks[i_track]->b_search_keyframe )
+ {
+ tracks[i_track]->b_search_keyframe = VLC_FALSE;
+ i_track_skipping--;
+ }
+ if( !tracks[i_track]->b_search_keyframe )
+ {
+ BlockDecode( &sys.demuxer, block, sys.i_pts, 0 );
+ }
+ }
+ }
+
+ delete block;
+ }
+}
+
+void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter )
+{
+ demux_sys_t *p_sys = demuxer.p_sys;
+ size_t i;
+
+ // find the actual time for an ordered edition
+ if ( psz_chapter == NULL )
+ {
+ if ( Edition() && Edition()->b_ordered )
+ {
+ /* 1st, we need to know in which chapter we are */
+ psz_chapter = (*p_editions)[i_current_edition]->FindTimecode( i_date );
+ }
+ }
+
+ if ( psz_chapter != NULL )
+ {
+ psz_current_chapter = psz_chapter;
+ p_sys->i_chapter_time = i_time_offset = psz_chapter->i_user_start_time - psz_chapter->i_start_time;
+ if ( psz_chapter->i_seekpoint_num > 0 )
+ {
+ demuxer.info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
+ demuxer.info.i_title = p_sys->i_current_title = i_sys_title;
+ demuxer.info.i_seekpoint = psz_chapter->i_seekpoint_num - 1;
+ }
+ }
+
+ // find the best matching segment
+ for ( i=0; i<linked_segments.size(); i++ )
+ {
+ if ( i_date < linked_segments[i]->i_start_time )
+ break;
+ }
+
+ if ( i > 0 )
+ i--;
+
+ if ( i_current_segment != i )
+ {
+ linked_segments[i_current_segment]->UnSelect();
+ linked_segments[i]->Select( i_date );
+ i_current_segment = i;
+ }
+
+ linked_segments[i]->Seek( i_date, i_time_offset );
+}
+
+void chapter_codec_cmds_c::AddCommand( const KaxChapterProcessCommand & command )
+{
+ size_t i;
+
+ uint32 codec_time = uint32(-1);
+ for( i = 0; i < command.ListSize(); i++ )
+ {
+ const EbmlElement *k = command[i];
+
+ if( MKV_IS_ID( k, KaxChapterProcessTime ) )
+ {
+ codec_time = uint32( *static_cast<const KaxChapterProcessTime*>( k ) );
+ break;
+ }
+ }
+
+ for( i = 0; i < command.ListSize(); i++ )
+ {
+ const EbmlElement *k = command[i];
+
+ if( MKV_IS_ID( k, KaxChapterProcessData ) )
+ {
+ KaxChapterProcessData *p_data = new KaxChapterProcessData( *static_cast<const KaxChapterProcessData*>( k ) );
+ switch ( codec_time )
+ {
+ case 0:
+ during_cmds.push_back( *p_data );
+ break;
+ case 1:
+ enter_cmds.push_back( *p_data );
+ break;
+ case 2:
+ leave_cmds.push_back( *p_data );
+ break;
+ default:
+ delete p_data;
+ }
+ }
+ }
+}
+
+bool chapter_item_c::Enter( bool b_do_subs )
+{
+ bool f_result = false;
+ std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
+ while ( index != codecs.end() )
+ {
+ f_result |= (*index)->Enter();
+ index++;
+ }
+
+ if ( b_do_subs )
+ {
+ // sub chapters
+ std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
+ while ( index_ != sub_chapters.end() )
+ {
+ f_result |= (*index_)->Enter( true );
+ index_++;
+ }
+ }
+ return f_result;
+}
+
+bool chapter_item_c::Leave( bool b_do_subs )
+{
+ bool f_result = false;
+ b_is_leaving = true;
+ std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
+ while ( index != codecs.end() )
+ {
+ f_result |= (*index)->Leave();
+ index++;
+ }
+
+ if ( b_do_subs )
+ {
+ // sub chapters
+ std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
+ while ( index_ != sub_chapters.end() )
+ {
+ f_result |= (*index_)->Leave( true );
+ index_++;
+ }
+ }
+ b_is_leaving = false;
+ return f_result;
+}
+
+bool chapter_item_c::EnterAndLeave( chapter_item_c *p_item )
+{
+ chapter_item_c *p_common_parent = p_item;
+
+ // leave, up to a common parent
+ while ( p_common_parent != NULL && !p_common_parent->ParentOf( *this ) )
+ {
+ if ( !p_common_parent->b_is_leaving && p_common_parent->Leave( false ) )
+ return true;
+ p_common_parent = p_common_parent->psz_parent;
+ }
+
+ // enter from the parent to <this>
+ if ( p_common_parent != NULL )
+ {
+ do
+ {
+ if ( p_common_parent == this )
+ return Enter( true );
+
+ for ( size_t i = 0; i<p_common_parent->sub_chapters.size(); i++ )
+ {
+ if ( p_common_parent->sub_chapters[i]->ParentOf( *this ) )
+ {
+ p_common_parent = p_common_parent->sub_chapters[i];
+ if ( p_common_parent != this )
+ if ( p_common_parent->Enter( false ) )
+ return true;
+
+ break;
+ }
+ }
+ } while ( 1 );
+ }
+
+ return Enter( true );
+}
+
+bool dvd_chapter_codec_c::Enter()
+{
+ bool f_result = false;
+ std::vector<KaxChapterProcessData>::iterator index = enter_cmds.begin();
+ while ( index != enter_cmds.end() )
+ {
+ if ( (*index).GetSize() )
+ {
+ binary *p_data = (*index).GetBuffer();
+ size_t i_size = *p_data++;
+ // avoid reading too much from the buffer
+ i_size = min( i_size, ((*index).GetSize() - 1) >> 3 );
+ for ( ; i_size > 0; i_size--, p_data += 8 )
+ {
+ msg_Dbg( &sys.demuxer, "Matroska DVD enter command" );
+ f_result |= sys.dvd_interpretor.Interpret( p_data );
+ }
+ }
+ index++;
+ }
+ return f_result;
+}
+
+bool dvd_chapter_codec_c::Leave()
+{
+ bool f_result = false;
+ std::vector<KaxChapterProcessData>::iterator index = leave_cmds.begin();
+ while ( index != leave_cmds.end() )
+ {
+ if ( (*index).GetSize() )
+ {
+ binary *p_data = (*index).GetBuffer();
+ size_t i_size = *p_data++;
+ // avoid reading too much from the buffer
+ i_size = min( i_size, ((*index).GetSize() - 1) >> 3 );
+ for ( ; i_size > 0; i_size--, p_data += 8 )
+ {
+ msg_Dbg( &sys.demuxer, "Matroska DVD leave command" );
+ f_result |= sys.dvd_interpretor.Interpret( p_data );
+ }
+ }
+ index++;
+ }
+ return f_result;
+}
+
+// see http://www.dvd-replica.com/DVD/vmcmdset.php for a description of DVD commands
+bool dvd_command_interpretor_c::Interpret( const binary * p_command, size_t i_size )
+{
+ if ( i_size != 8 )
+ return false;
+
+ virtual_segment_c *p_segment;
+ chapter_item_c *p_chapter;
+ bool f_result = false;
+ uint16 i_command = ( p_command[0] << 8 ) + p_command[1];
+
+ // handle register tests if there are some
+ if ( (i_command & 0xF0) != 0 )
+ {
+ bool b_test_positive = (i_command & CMD_DVD_IF_NOT) == 0;
+ bool b_test_value = (i_command & CMD_DVD_TEST_VALUE) != 0;
+ uint8 i_test = i_command & 0x70;
+ uint16 i_value;
+
+ if ( b_test_value )
+ i_value = ( p_command[4] << 8 ) + p_command[5];
+ else
+ i_value = GetPRM( p_command[7] );
+
+ switch ( i_test )
+ {
+ case CMD_DVD_IF_GPREG_EQUAL:
+ // if equals
+ msg_Dbg( &sys.demuxer, "IF %s EQUALS %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
+ if (!( GetPRM( p_command[3] ) == i_value ))
+ {
+ b_test_positive = !b_test_positive;
+ }
+ break;
+ case CMD_DVD_IF_GPREG_INF:
+ // if inferior
+ msg_Dbg( &sys.demuxer, "IF %s < %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
+ if (!( GetPRM( p_command[3] ) < i_value ))
+ {
+ b_test_positive = !b_test_positive;
+ }
+ break;
+ case CMD_DVD_IF_GPREG_AND:
+ // if logical and
+ msg_Dbg( &sys.demuxer, "IF %s & %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
+ if (!( GetPRM( p_command[3] ) & i_value ))
+ {
+ b_test_positive = !b_test_positive;
+ }
+ break;
+ case CMD_DVD_IF_GPREG_SUP_EQUAL:
+ // if superior or equal
+ msg_Dbg( &sys.demuxer, "IF %s >= %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
+ if (!( GetPRM( p_command[3] ) >= i_value ))
+ {
+ b_test_positive = !b_test_positive;
+ }
+ break;
+ }
+
+ if ( !b_test_positive )
+ return false;
+ }
+
+ // strip the test command
+ i_command &= 0xFF0F;
+
+ switch ( i_command )
+ {
+ case CMD_DVD_NOP:
+ case CMD_DVD_NOP2:
+ {
+ msg_Dbg( &sys.demuxer, "NOP" );
+ break;
+ }
+ case CMD_DVD_BREAK:
+ {
+ msg_Dbg( &sys.demuxer, "Break" );
+ // TODO
+ break;
+ }
+ case CMD_DVD_JUMP_TT:
+ {
+ uint8 i_title = p_command[5];
+ msg_Dbg( &sys.demuxer, "JumpTT %d", i_title );
+
+ // find in the ChapProcessPrivate matching this Title level
+ p_chapter = sys.BrowseCodecPrivate( 1, MatchTitleNumber, &i_title, sizeof(i_title), p_segment );
+ if ( p_chapter != NULL )
+ {
+ // if the segment is not part of the current segment, select the new one
+ if ( p_segment != sys.p_current_segment )
+ {
+ sys.PreparePlayback( p_segment );
+ }
+
+ // jump to the location in the found segment
+ p_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, NULL );
+ p_chapter->Enter( true );
+
+ f_result = true;
+ }
+
+ break;
+ }
+ case CMD_DVD_CALLSS_VTSM1:
+ {
+ msg_Dbg( &sys.demuxer, "CallSS VTSM" );
+ switch( (p_command[6] & 0xC0) >> 6 ) {
+ case 0:
+ switch ( p_command[5] )
+ {
+ case 0x00:
+ msg_Dbg( &sys.demuxer, "CallSS PGC (rsm_cell %x)", p_command[5]);
+ break;
+ case 0x82:
+ msg_Dbg( &sys.demuxer, "CallSS Title Entry (rsm_cell %x)", p_command[5]);
+ break;
+ case 0x83:
+ msg_Dbg( &sys.demuxer, "CallSS Root Menu (rsm_cell %x)", p_command[5]);
+ break;
+ case 0x84:
+ msg_Dbg( &sys.demuxer, "CallSS Subpicture Menu (rsm_cell %x)", p_command[5]);
+ break;
+ case 0x85:
+ msg_Dbg( &sys.demuxer, "CallSS Audio Menu (rsm_cell %x)", p_command[5]);
+ break;
+ case 0x86:
+ msg_Dbg( &sys.demuxer, "CallSS Angle Menu (rsm_cell %x)", p_command[5]);
+ break;
+ case 0x87:
+ msg_Dbg( &sys.demuxer, "CallSS Chapter Menu (rsm_cell %x)", p_command[5]);
+ break;
+ default:
+ msg_Dbg( &sys.demuxer, "CallSS <unknown> (rsm_cell %x)", p_command[5]);
+ break;
+ }
+ p_chapter = sys.BrowseCodecPrivate( 1, MatchPgcType, &p_command[5], 1, p_segment );
+ if ( p_chapter != NULL )
+ {
+ // if the segment is not part of the current segment, select the new one
+ if ( p_segment != sys.p_current_segment )
+ {
+ sys.PreparePlayback( p_segment );
+ }
+
+ p_chapter->Enter( true );
+
+ // jump to the location in the found segment
+ p_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter );
+ f_result = true;
+ }
+ break;
+ case 1:
+ msg_Dbg( &sys.demuxer, "CallSS VMGM (menu %d, rsm_cell %x)", p_command[6] & 0x0F, p_command[5]);
+ break;
+ case 2:
+ msg_Dbg( &sys.demuxer, "CallSS VTSM (menu %d, rsm_cell %x)", p_command[6] & 0x0F, p_command[5]);
+ break;
+ case 3:
+ msg_Dbg( &sys.demuxer, "CallSS VMGM (pgc %d, rsm_cell %x)", (p_command[3] << 8) + p_command[4], p_command[5]);
+ break;
+ }
+ break;
+ }
+ case CMD_DVD_SET_GPRMMD:
+ {
+ msg_Dbg( &sys.demuxer, "Set GPRMMD [%d]=%d", (p_command[4] << 8) + p_command[5], (p_command[2] << 8) + p_command[3]);
+
+ if ( !SetGPRM( (p_command[4] << 8) + p_command[5], (p_command[2] << 8) + p_command[3] ) )
+ msg_Dbg( &sys.demuxer, "Set GPRMMD failed" );
+ break;
+ }
+ case CMD_DVD_LINKPGCN:
+ {
+ uint16 i_pgcn = (p_command[6] << 8) + p_command[7];
+
+ msg_Dbg( &sys.demuxer, "Link PGCN(%d)", i_pgcn );
+ p_chapter = sys.p_current_segment->BrowseCodecPrivate( 1, MatchPgcNumber, &i_pgcn, 2 );
+ if ( p_chapter != NULL )
+ {
+ p_chapter->Enter( true );
+
+ // jump to the location in the found segment
+ sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter );
+ f_result = true;
+ }
+ break;
+ }
+ case CMD_DVD_LINKCN:
+ {
+ uint8 i_cn = p_command[7];
+
+ p_chapter = sys.p_current_segment->CurrentChapter();
+
+ msg_Dbg( &sys.demuxer, "LinkCN (cell %d)", i_cn );
+ p_chapter = p_chapter->BrowseCodecPrivate( 1, MatchCellNumber, &i_cn, 1 );
+ if ( p_chapter != NULL )
+ {
+ p_chapter->Enter( true );
+
+ // jump to the location in the found segment
+ sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter );
+ f_result = true;
+ }
+ break;
+ }
+ case CMD_DVD_GOTO_LINE:
+ {
+ msg_Dbg( &sys.demuxer, "GotoLine (%d)", (p_command[6] << 8) + p_command[7] );
+ // TODO
+ break;
+ }
+ default:
+ {
+ msg_Dbg( &sys.demuxer, "unsupported command : %02X %02X %02X %02X %02X %02X %02X %02X"
+ ,p_command[0]
+ ,p_command[1]
+ ,p_command[2]
+ ,p_command[3]
+ ,p_command[4]
+ ,p_command[5]
+ ,p_command[6]
+ ,p_command[7]);
+ break;
+ }
+ }
+
+ return f_result;
+}
+
+bool dvd_command_interpretor_c::MatchTitleNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
+{
+ if ( i_cookie_size != 1 || data.m_private_data.GetSize() < 4 )
+ return false;
+
+ if ( data.m_private_data.GetBuffer()[0] != MATROSKA_DVD_LEVEL_TT )
+ return false;
+
+ uint16 i_gtitle = (data.m_private_data.GetBuffer()[1] << 8 ) + data.m_private_data.GetBuffer()[2];
+ uint8 i_title = *(uint8*)p_cookie;
+
+ return (i_gtitle == i_title);
+}
+
+bool dvd_command_interpretor_c::MatchPgcType( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
+{
+ if ( i_cookie_size != 1 || data.m_private_data.GetSize() < 8 )
+ return false;
+
+ if ( data.m_private_data.GetBuffer()[0] != MATROSKA_DVD_LEVEL_PGC )
+ return false;
+
+ uint8 i_pgc_type = data.m_private_data.GetBuffer()[3];
+ uint8 i_pgc = *(uint8*)p_cookie;
+
+ return (i_pgc_type == i_pgc);
+}
+
+bool dvd_command_interpretor_c::MatchPgcNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
+{
+ if ( i_cookie_size != 2 || data.m_private_data.GetSize() < 8 )
+ return false;
+
+ if ( data.m_private_data.GetBuffer()[0] != MATROSKA_DVD_LEVEL_PGC )
+ return false;
+
+ uint16 *i_pgc_n = (uint16 *)p_cookie;
+ uint16 i_pgc_num = (data.m_private_data.GetBuffer()[1] << 8) + data.m_private_data.GetBuffer()[2];
+
+ return (i_pgc_num == *i_pgc_n);
+}
+
+bool dvd_command_interpretor_c::MatchCellNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
+{
+ if ( i_cookie_size != 1 || data.m_private_data.GetSize() < 5 )
+ return false;
+
+ if ( data.m_private_data.GetBuffer()[0] != MATROSKA_DVD_LEVEL_CN )
+ return false;
+
+ uint8 *i_cell_n = (uint8 *)p_cookie;
+ uint8 i_cell_num = data.m_private_data.GetBuffer()[3];
+
+ return (i_cell_num == *i_cell_n);
+}
+
+bool matroska_script_codec_c::Enter()
+{
+ bool f_result = false;
+ std::vector<KaxChapterProcessData>::iterator index = enter_cmds.begin();
+ while ( index != enter_cmds.end() )
+ {
+ if ( (*index).GetSize() )
+ {
+ msg_Dbg( &sys.demuxer, "Matroska Script enter command" );
+ f_result |= interpretor.Interpret( (*index).GetBuffer(), (*index).GetSize() );
+ }
+ index++;
+ }
+ return f_result;
+}
+
+bool matroska_script_codec_c::Leave()
+{
+ bool f_result = false;
+ std::vector<KaxChapterProcessData>::iterator index = leave_cmds.begin();
+ while ( index != leave_cmds.end() )
+ {
+ if ( (*index).GetSize() )
+ {
+ msg_Dbg( &sys.demuxer, "Matroska Script leave command" );
+ f_result |= interpretor.Interpret( (*index).GetBuffer(), (*index).GetSize() );
+ }
+ index++;
+ }
+ return f_result;
+}
+
+// see http://www.matroska.org/technical/specs/chapters/index.html#mscript
+// for a description of existing commands
+bool matroska_script_interpretor_c::Interpret( const binary * p_command, size_t i_size )
+{
+ bool b_result = false;
+
+ char *psz_str = (char*) malloc( i_size + 1 );
+ memcpy( psz_str, p_command, i_size );
+ psz_str[ i_size ] = '\0';
+
+ std::string sz_command = psz_str;
+ free( psz_str );
+
+ msg_Dbg( &sys.demuxer, "command : %s", sz_command.c_str() );
+
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ if ( sz_command.compare( CMD_MS_GOTO_AND_PLAY, 0, CMD_MS_GOTO_AND_PLAY.size() ) == 0 )
+#else
+ if ( sz_command.compare( 0, CMD_MS_GOTO_AND_PLAY.size(), CMD_MS_GOTO_AND_PLAY ) == 0 )
+#endif
+ {
+ size_t i,j;
+
+ // find the (
+ for ( i=CMD_MS_GOTO_AND_PLAY.size(); i<sz_command.size(); i++)
+ {
+ if ( sz_command[i] == '(' )
+ {
+ i++;
+ break;
+ }
+ }
+ // find the )
+ for ( j=i; j<sz_command.size(); j++)
+ {
+ if ( sz_command[j] == ')' )
+ {
+ i--;
+ break;
+ }
+ }
+
+ std::string st = sz_command.substr( i+1, j-i-1 );
+ int64_t i_chapter_uid = atoi( st.c_str() );
+
+ virtual_segment_c *p_segment;
+ chapter_item_c *p_chapter = sys.FindChapter( i_chapter_uid, p_segment );
+
+ if ( p_chapter == NULL )
+ msg_Dbg( &sys.demuxer, "Chapter "I64Fd" not found", i_chapter_uid);
+ else
+ {
+ if ( !p_chapter->EnterAndLeave( sys.p_current_segment->CurrentChapter() ) )
+ p_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter );
+ b_result = true;
+ }
+ }
+
+ return b_result;
+}
+
+void demux_sys_t::SwapButtons()
+{
+#ifndef WORDS_BIGENDIAN
+ uint8_t button, i, j;
+
+ for( button = 1; button <= pci_packet.hli.hl_gi.btn_ns; button++) {
+ btni_t *button_ptr = &(pci_packet.hli.btnit[button-1]);
+ binary *p_data = (binary*) button_ptr;
+
+ uint16 i_x_start = ((p_data[0] & 0x3F) << 4 ) + ( p_data[1] >> 4 );
+ uint16 i_x_end = ((p_data[1] & 0x03) << 8 ) + p_data[2];
+ uint16 i_y_start = ((p_data[3] & 0x3F) << 4 ) + ( p_data[4] >> 4 );
+ uint16 i_y_end = ((p_data[4] & 0x03) << 8 ) + p_data[5];
+ button_ptr->x_start = i_x_start;
+ button_ptr->x_end = i_x_end;
+ button_ptr->y_start = i_y_start;
+ button_ptr->y_end = i_y_end;
+
+ }
+ for ( i = 0; i<3; i++ )
+ {
+ for ( j = 0; j<2; j++ )
+ {
+ pci_packet.hli.btn_colit.btn_coli[i][j] = U32_AT( &pci_packet.hli.btn_colit.btn_coli[i][j] );
+ }
+ }
+#endif
+}