chapter_command.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:28k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * mkv.cpp : matroska demuxer
  3.  *****************************************************************************
  4.  * Copyright (C) 2003-2004 the VideoLAN team
  5.  * $Id: 764e95bd44fc3a6ead4afc1f575b8725c9bd66dc $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  8.  *          Steve Lhomme <steve.lhomme@free.fr>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. #include "chapter_command.hpp"
  25. void chapter_codec_cmds_c::AddCommand( const KaxChapterProcessCommand & command )
  26. {
  27.     size_t i;
  28.     uint32 codec_time = uint32(-1);
  29.     for( i = 0; i < command.ListSize(); i++ )
  30.     {
  31.         const EbmlElement *k = command[i];
  32.         if( MKV_IS_ID( k, KaxChapterProcessTime ) )
  33.         {
  34.             codec_time = uint32( *static_cast<const KaxChapterProcessTime*>( k ) );
  35.             break;
  36.         }
  37.     }
  38.     for( i = 0; i < command.ListSize(); i++ )
  39.     {
  40.         const EbmlElement *k = command[i];
  41.         if( MKV_IS_ID( k, KaxChapterProcessData ) )
  42.         {
  43.             KaxChapterProcessData *p_data =  new KaxChapterProcessData( *static_cast<const KaxChapterProcessData*>( k ) );
  44.             switch ( codec_time )
  45.             {
  46.             case 0:
  47.                 during_cmds.push_back( p_data );
  48.                 break;
  49.             case 1:
  50.                 enter_cmds.push_back( p_data );
  51.                 break;
  52.             case 2:
  53.                 leave_cmds.push_back( p_data );
  54.                 break;
  55.             default:
  56.                 delete p_data;
  57.             }
  58.         }
  59.     }
  60. }
  61. int16 dvd_chapter_codec_c::GetTitleNumber()
  62. {
  63.     if ( p_private_data->GetSize() >= 3)
  64.     {
  65.         const binary* p_data = p_private_data->GetBuffer();
  66.         if ( p_data[0] == MATROSKA_DVD_LEVEL_SS )
  67.         {
  68.             return int16( (p_data[2] << 8) + p_data[3] );
  69.         }
  70.     }
  71.     return -1;
  72. }
  73. bool dvd_chapter_codec_c::Enter()
  74. {
  75.     bool f_result = false;
  76.     std::vector<KaxChapterProcessData*>::iterator index = enter_cmds.begin();
  77.     while ( index != enter_cmds.end() )
  78.     {
  79.         if ( (*index)->GetSize() )
  80.         {
  81.             binary *p_data = (*index)->GetBuffer();
  82.             size_t i_size = *p_data++;
  83.             // avoid reading too much from the buffer
  84.             i_size = __MIN( i_size, ((*index)->GetSize() - 1) >> 3 );
  85.             for ( ; i_size > 0; i_size--, p_data += 8 )
  86.             {
  87.                 msg_Dbg( &sys.demuxer, "Matroska DVD enter command" );
  88.                 f_result |= sys.dvd_interpretor.Interpret( p_data );
  89.             }
  90.         }
  91.         index++;
  92.     }
  93.     return f_result;
  94. }
  95. bool dvd_chapter_codec_c::Leave()
  96. {
  97.     bool f_result = false;
  98.     std::vector<KaxChapterProcessData*>::iterator index = leave_cmds.begin();
  99.     while ( index != leave_cmds.end() )
  100.     {
  101.         if ( (*index)->GetSize() )
  102.         {
  103.             binary *p_data = (*index)->GetBuffer();
  104.             size_t i_size = *p_data++;
  105.             // avoid reading too much from the buffer
  106.             i_size = __MIN( i_size, ((*index)->GetSize() - 1) >> 3 );
  107.             for ( ; i_size > 0; i_size--, p_data += 8 )
  108.             {
  109.                 msg_Dbg( &sys.demuxer, "Matroska DVD leave command" );
  110.                 f_result |= sys.dvd_interpretor.Interpret( p_data );
  111.             }
  112.         }
  113.         index++;
  114.     }
  115.     return f_result;
  116. }
  117. std::string dvd_chapter_codec_c::GetCodecName( bool f_for_title ) const
  118. {
  119.     std::string result;
  120.     if ( p_private_data->GetSize() >= 3)
  121.     {
  122.         const binary* p_data = p_private_data->GetBuffer();
  123. /*        if ( p_data[0] == MATROSKA_DVD_LEVEL_TT )
  124.         {
  125.             uint16_t i_title = (p_data[1] << 8) + p_data[2];
  126.             char psz_str[11];
  127.             sprintf( psz_str, " %d  ---", i_title );
  128.             result = N_("---  DVD Title");
  129.             result += psz_str;
  130.         }
  131.         else */ if ( p_data[0] == MATROSKA_DVD_LEVEL_LU )
  132.         {
  133.             char psz_str[11];
  134.             sprintf( psz_str, " (%c%c)  ---", p_data[1], p_data[2] );
  135.             result = N_("---  DVD Menu");
  136.             result += psz_str;
  137.         }
  138.         else if ( p_data[0] == MATROSKA_DVD_LEVEL_SS && f_for_title )
  139.         {
  140.             if ( p_data[1] == 0x00 )
  141.                 result = N_("First Played");
  142.             else if ( p_data[1] == 0xC0 )
  143.                 result = N_("Video Manager");
  144.             else if ( p_data[1] == 0x80 )
  145.             {
  146.                 uint16_t i_title = (p_data[2] << 8) + p_data[3];
  147.                 char psz_str[20];
  148.                 sprintf( psz_str, " %d -----", i_title );
  149.                 result = N_("----- Title");
  150.                 result += psz_str;
  151.             }
  152.         }
  153.     }
  154.     return result;
  155. }
  156. class virtual_segment_c;
  157. class chapter_item_c;
  158. // see http://www.dvd-replica.com/DVD/vmcmdset.php for a description of DVD commands
  159. bool dvd_command_interpretor_c::Interpret( const binary * p_command, size_t i_size )
  160. {
  161.     if ( i_size != 8 )
  162.         return false;
  163.     virtual_segment_c *p_segment = NULL;
  164.     chapter_item_c *p_chapter = NULL;
  165.     bool f_result = false;
  166.     uint16 i_command = ( p_command[0] << 8 ) + p_command[1];
  167.     // handle register tests if there are some
  168.     if ( (i_command & 0xF0) != 0 )
  169.     {
  170.         bool b_test_positive = true;//(i_command & CMD_DVD_IF_NOT) == 0;
  171.         bool b_test_value    = (i_command & CMD_DVD_TEST_VALUE) != 0;
  172.         uint8 i_test = i_command & 0x70;
  173.         uint16 i_value;
  174.         // see http://dvd.sourceforge.net/dvdinfo/vmi.html
  175.         uint8  i_cr1;
  176.         uint16 i_cr2;
  177.         switch ( i_command >> 12 )
  178.         {
  179.         default:
  180.             i_cr1 = p_command[3];
  181.             i_cr2 = (p_command[4] << 8) + p_command[5];
  182.             break;
  183.         case 3:
  184.         case 4:
  185.         case 5:
  186.             i_cr1 = p_command[6];
  187.             i_cr2 = p_command[7];
  188.             b_test_value = false;
  189.             break;
  190.         case 6:
  191.         case 7:
  192.             if ( ((p_command[1] >> 4) & 0x7) == 0)
  193.             {
  194.                 i_cr1 = p_command[2];
  195.                 i_cr2 = (p_command[6] << 8) + p_command[7];
  196.             }
  197.             else
  198.             {
  199.                 i_cr1 = p_command[2];
  200.                 i_cr2 = (p_command[6] << 8) + p_command[7];
  201.             }
  202.             break;
  203.         }
  204.         if ( b_test_value )
  205.             i_value = i_cr2;
  206.         else
  207.             i_value = GetPRM( i_cr2 );
  208.         switch ( i_test )
  209.         {
  210.         case CMD_DVD_IF_GPREG_EQUAL:
  211.             // if equals
  212.             msg_Dbg( &sys.demuxer, "IF %s EQUALS %s", GetRegTypeName( false, i_cr1 ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
  213.             if (!( GetPRM( i_cr1 ) == i_value ))
  214.             {
  215.                 b_test_positive = false;
  216.             }
  217.             break;
  218.         case CMD_DVD_IF_GPREG_NOT_EQUAL:
  219.             // if not equals
  220.             msg_Dbg( &sys.demuxer, "IF %s NOT EQUALS %s", GetRegTypeName( false, i_cr1 ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
  221.             if (!( GetPRM( i_cr1 ) != i_value ))
  222.             {
  223.                 b_test_positive = false;
  224.             }
  225.             break;
  226.         case CMD_DVD_IF_GPREG_INF:
  227.             // if inferior
  228.             msg_Dbg( &sys.demuxer, "IF %s < %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
  229.             if (!( GetPRM( i_cr1 ) < i_value ))
  230.             {
  231.                 b_test_positive = false;
  232.             }
  233.             break;
  234.         case CMD_DVD_IF_GPREG_INF_EQUAL:
  235.             // if inferior or equal
  236.             msg_Dbg( &sys.demuxer, "IF %s < %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
  237.             if (!( GetPRM( i_cr1 ) <= i_value ))
  238.             {
  239.                 b_test_positive = false;
  240.             }
  241.             break;
  242.         case CMD_DVD_IF_GPREG_AND:
  243.             // if logical and
  244.             msg_Dbg( &sys.demuxer, "IF %s & %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
  245.             if (!( GetPRM( i_cr1 ) & i_value ))
  246.             {
  247.                 b_test_positive = false;
  248.             }
  249.             break;
  250.         case CMD_DVD_IF_GPREG_SUP:
  251.             // if superior
  252.             msg_Dbg( &sys.demuxer, "IF %s >= %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
  253.             if (!( GetPRM( i_cr1 ) > i_value ))
  254.             {
  255.                 b_test_positive = false;
  256.             }
  257.             break;
  258.         case CMD_DVD_IF_GPREG_SUP_EQUAL:
  259.             // if superior or equal
  260.             msg_Dbg( &sys.demuxer, "IF %s >= %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
  261.             if (!( GetPRM( i_cr1 ) >= i_value ))
  262.             {
  263.                 b_test_positive = false;
  264.             }
  265.             break;
  266.         }
  267.         if ( !b_test_positive )
  268.             return false;
  269.     }
  270.  
  271.     // strip the test command
  272.     i_command &= 0xFF0F;
  273.  
  274.     switch ( i_command )
  275.     {
  276.     case CMD_DVD_NOP:
  277.     case CMD_DVD_NOP2:
  278.         {
  279.             msg_Dbg( &sys.demuxer, "NOP" );
  280.             break;
  281.         }
  282.     case CMD_DVD_BREAK:
  283.         {
  284.             msg_Dbg( &sys.demuxer, "Break" );
  285.             // TODO
  286.             break;
  287.         }
  288.     case CMD_DVD_JUMP_TT:
  289.         {
  290.             uint8 i_title = p_command[5];
  291.             msg_Dbg( &sys.demuxer, "JumpTT %d", i_title );
  292.             // find in the ChapProcessPrivate matching this Title level
  293.             p_chapter = sys.BrowseCodecPrivate( 1, MatchTitleNumber, &i_title, sizeof(i_title), p_segment );
  294.             if ( p_segment != NULL )
  295.             {
  296.                 sys.JumpTo( *p_segment, p_chapter );
  297.                 f_result = true;
  298.             }
  299.             break;
  300.         }
  301.     case CMD_DVD_CALLSS_VTSM1:
  302.         {
  303.             msg_Dbg( &sys.demuxer, "CallSS" );
  304.             binary p_type;
  305.             switch( (p_command[6] & 0xC0) >> 6 ) {
  306.                 case 0:
  307.                     p_type = p_command[5] & 0x0F;
  308.                     switch ( p_type )
  309.                     {
  310.                     case 0x00:
  311.                         msg_Dbg( &sys.demuxer, "CallSS PGC (rsm_cell %x)", p_command[4]);
  312.                         break;
  313.                     case 0x02:
  314.                         msg_Dbg( &sys.demuxer, "CallSS Title Entry (rsm_cell %x)", p_command[4]);
  315.                         break;
  316.                     case 0x03:
  317.                         msg_Dbg( &sys.demuxer, "CallSS Root Menu (rsm_cell %x)", p_command[4]);
  318.                         break;
  319.                     case 0x04:
  320.                         msg_Dbg( &sys.demuxer, "CallSS Subpicture Menu (rsm_cell %x)", p_command[4]);
  321.                         break;
  322.                     case 0x05:
  323.                         msg_Dbg( &sys.demuxer, "CallSS Audio Menu (rsm_cell %x)", p_command[4]);
  324.                         break;
  325.                     case 0x06:
  326.                         msg_Dbg( &sys.demuxer, "CallSS Angle Menu (rsm_cell %x)", p_command[4]);
  327.                         break;
  328.                     case 0x07:
  329.                         msg_Dbg( &sys.demuxer, "CallSS Chapter Menu (rsm_cell %x)", p_command[4]);
  330.                         break;
  331.                     default:
  332.                         msg_Dbg( &sys.demuxer, "CallSS <unknown> (rsm_cell %x)", p_command[4]);
  333.                         break;
  334.                     }
  335.                     p_chapter = sys.BrowseCodecPrivate( 1, MatchPgcType, &p_type, 1, p_segment );
  336.                     if ( p_segment != NULL )
  337.                     {
  338.                         sys.JumpTo( *p_segment, p_chapter );
  339.                         f_result = true;
  340.                     }
  341.                 break;
  342.                 case 1:
  343.                     msg_Dbg( &sys.demuxer, "CallSS VMGM (menu %d, rsm_cell %x)", p_command[5] & 0x0F, p_command[4]);
  344.                 break;
  345.                 case 2:
  346.                     msg_Dbg( &sys.demuxer, "CallSS VTSM (menu %d, rsm_cell %x)", p_command[5] & 0x0F, p_command[4]);
  347.                 break;
  348.                 case 3:
  349.                     msg_Dbg( &sys.demuxer, "CallSS VMGM (pgc %d, rsm_cell %x)", (p_command[2] << 8) + p_command[3], p_command[4]);
  350.                 break;
  351.             }
  352.             break;
  353.         }
  354.     case CMD_DVD_JUMP_SS:
  355.         {
  356.             msg_Dbg( &sys.demuxer, "JumpSS");
  357.             binary p_type;
  358.             switch( (p_command[5] & 0xC0) >> 6 ) {
  359.                 case 0:
  360.                     msg_Dbg( &sys.demuxer, "JumpSS FP");
  361.                 break;
  362.                 case 1:
  363.                     p_type = p_command[5] & 0x0F;
  364.                     switch ( p_type )
  365.                     {
  366.                     case 0x02:
  367.                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Title Entry");
  368.                         break;
  369.                     case 0x03:
  370.                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Root Menu");
  371.                         break;
  372.                     case 0x04:
  373.                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Subpicture Menu");
  374.                         break;
  375.                     case 0x05:
  376.                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Audio Menu");
  377.                         break;
  378.                     case 0x06:
  379.                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Angle Menu");
  380.                         break;
  381.                     case 0x07:
  382.                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Chapter Menu");
  383.                         break;
  384.                     default:
  385.                         msg_Dbg( &sys.demuxer, "JumpSS <unknown>");
  386.                         break;
  387.                     }
  388.                     // find the VMG
  389.                     p_chapter = sys.BrowseCodecPrivate( 1, MatchIsVMG, NULL, 0, p_segment );
  390.                     if ( p_segment != NULL )
  391.                     {
  392.                         p_chapter = p_segment->BrowseCodecPrivate( 1, MatchPgcType, &p_type, 1 );
  393.                         if ( p_chapter != NULL )
  394.                         {
  395.                             sys.JumpTo( *p_segment, p_chapter );
  396.                             f_result = true;
  397.                         }
  398.                     }
  399.                 break;
  400.                 case 2:
  401.                     p_type = p_command[5] & 0x0F;
  402.                     switch ( p_type )
  403.                     {
  404.                     case 0x02:
  405.                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Title Entry", p_command[4], p_command[3]);
  406.                         break;
  407.                     case 0x03:
  408.                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Root Menu", p_command[4], p_command[3]);
  409.                         break;
  410.                     case 0x04:
  411.                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Subpicture Menu", p_command[4], p_command[3]);
  412.                         break;
  413.                     case 0x05:
  414.                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Audio Menu", p_command[4], p_command[3]);
  415.                         break;
  416.                     case 0x06:
  417.                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Angle Menu", p_command[4], p_command[3]);
  418.                         break;
  419.                     case 0x07:
  420.                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Chapter Menu", p_command[4], p_command[3]);
  421.                         break;
  422.                     default:
  423.                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) <unknown>", p_command[4], p_command[3]);
  424.                         break;
  425.                     }
  426.                     p_chapter = sys.BrowseCodecPrivate( 1, MatchVTSMNumber, &p_command[4], 1, p_segment );
  427.                     if ( p_segment != NULL && p_chapter != NULL )
  428.                     {
  429.                         // find the title in the VTS
  430.                         p_chapter = p_chapter->BrowseCodecPrivate( 1, MatchTitleNumber, &p_command[3], 1 );
  431.                         if ( p_chapter != NULL )
  432.                         {
  433.                             // find the specified menu in the VTSM
  434.                             p_chapter = p_segment->BrowseCodecPrivate( 1, MatchPgcType, &p_type, 1 );
  435.                             if ( p_chapter != NULL )
  436.                             {
  437.                                 sys.JumpTo( *p_segment, p_chapter );
  438.                                 f_result = true;
  439.                             }
  440.                         }
  441.                         else
  442.                             msg_Dbg( &sys.demuxer, "Title (%d) does not exist in this VTS", p_command[3] );
  443.                     }
  444.                     else
  445.                         msg_Dbg( &sys.demuxer, "DVD Domain VTS (%d) not found", p_command[4] );
  446.                 break;
  447.                 case 3:
  448.                     msg_Dbg( &sys.demuxer, "JumpSS VMGM (pgc %d)", (p_command[2] << 8) + p_command[3]);
  449.                 break;
  450.             }
  451.             break;
  452.         }
  453.     case CMD_DVD_JUMPVTS_PTT:
  454.         {
  455.             uint8 i_title = p_command[5];
  456.             uint8 i_ptt = p_command[3];
  457.             msg_Dbg( &sys.demuxer, "JumpVTS Title (%d) PTT (%d)", i_title, i_ptt);
  458.             // find the current VTS content segment
  459.             p_chapter = sys.p_current_segment->BrowseCodecPrivate( 1, MatchIsDomain, NULL, 0 );
  460.             if ( p_chapter != NULL )
  461.             {
  462.                 int16 i_curr_title = p_chapter->GetTitleNumber( );
  463.                 if ( i_curr_title > 0 )
  464.                 {
  465.                     p_chapter = sys.BrowseCodecPrivate( 1, MatchVTSNumber, &i_curr_title, sizeof(i_curr_title), p_segment );
  466.                     if ( p_segment != NULL && p_chapter != NULL )
  467.                     {
  468.                         // find the title in the VTS
  469.                         p_chapter = p_chapter->BrowseCodecPrivate( 1, MatchTitleNumber, &i_title, sizeof(i_title) );
  470.                         if ( p_chapter != NULL )
  471.                         {
  472.                             // find the chapter in the title
  473.                             p_chapter = p_chapter->BrowseCodecPrivate( 1, MatchChapterNumber, &i_ptt, sizeof(i_ptt) );
  474.                             if ( p_chapter != NULL )
  475.                             {
  476.                                 sys.JumpTo( *p_segment, p_chapter );
  477.                                 f_result = true;
  478.                             }
  479.                         }
  480.                     else
  481.                         msg_Dbg( &sys.demuxer, "Title (%d) does not exist in this VTS", i_title );
  482.                     }
  483.                     else
  484.                         msg_Dbg( &sys.demuxer, "DVD Domain VTS (%d) not found", i_curr_title );
  485.                 }
  486.                 else
  487.                     msg_Dbg( &sys.demuxer, "JumpVTS_PTT command found but not in a VTS(M)");
  488.             }
  489.             else
  490.                 msg_Dbg( &sys.demuxer, "JumpVTS_PTT command but the DVD domain wasn't found");
  491.             break;
  492.         }
  493.     case CMD_DVD_SET_GPRMMD:
  494.         {
  495.             msg_Dbg( &sys.demuxer, "Set GPRMMD [%d]=%d", (p_command[4] << 8) + p_command[5], (p_command[2] << 8) + p_command[3]);
  496.  
  497.             if ( !SetGPRM( (p_command[4] << 8) + p_command[5], (p_command[2] << 8) + p_command[3] ) )
  498.                 msg_Dbg( &sys.demuxer, "Set GPRMMD failed" );
  499.             break;
  500.         }
  501.     case CMD_DVD_LINKPGCN:
  502.         {
  503.             uint16 i_pgcn = (p_command[6] << 8) + p_command[7];
  504.  
  505.             msg_Dbg( &sys.demuxer, "Link PGCN(%d)", i_pgcn );
  506.             p_chapter = sys.p_current_segment->BrowseCodecPrivate( 1, MatchPgcNumber, &i_pgcn, 2 );
  507.             if ( p_chapter != NULL )
  508.             {
  509.                 if ( !p_chapter->Enter( true ) )
  510.                     // jump to the location in the found segment
  511.                     sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
  512.                 f_result = true;
  513.             }
  514.             break;
  515.         }
  516.     case CMD_DVD_LINKCN:
  517.         {
  518.             uint8 i_cn = p_command[7];
  519.  
  520.             p_chapter = sys.p_current_segment->CurrentChapter();
  521.             msg_Dbg( &sys.demuxer, "LinkCN (cell %d)", i_cn );
  522.             p_chapter = p_chapter->BrowseCodecPrivate( 1, MatchCellNumber, &i_cn, 1 );
  523.             if ( p_chapter != NULL )
  524.             {
  525.                 if ( !p_chapter->Enter( true ) )
  526.                     // jump to the location in the found segment
  527.                     sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
  528.                 f_result = true;
  529.             }
  530.             break;
  531.         }
  532.     case CMD_DVD_GOTO_LINE:
  533.         {
  534.             msg_Dbg( &sys.demuxer, "GotoLine (%d)", (p_command[6] << 8) + p_command[7] );
  535.             // TODO
  536.             break;
  537.         }
  538.     case CMD_DVD_SET_HL_BTNN1:
  539.         {
  540.             msg_Dbg( &sys.demuxer, "SetHL_BTN (%d)", p_command[4] );
  541.             SetSPRM( 0x88, p_command[4] );
  542.             break;
  543.         }
  544.     default:
  545.         {
  546.             msg_Dbg( &sys.demuxer, "unsupported command : %02X %02X %02X %02X %02X %02X %02X %02X"
  547.                      ,p_command[0]
  548.                      ,p_command[1]
  549.                      ,p_command[2]
  550.                      ,p_command[3]
  551.                      ,p_command[4]
  552.                      ,p_command[5]
  553.                      ,p_command[6]
  554.                      ,p_command[7]);
  555.             break;
  556.         }
  557.     }
  558.     return f_result;
  559. }
  560. bool dvd_command_interpretor_c::MatchIsDomain( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
  561. {
  562.     return ( data.p_private_data != NULL && data.p_private_data->GetBuffer()[0] == MATROSKA_DVD_LEVEL_SS );
  563. }
  564. bool dvd_command_interpretor_c::MatchIsVMG( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
  565. {
  566.     if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 2 )
  567.         return false;
  568.     return ( data.p_private_data->GetBuffer()[0] == MATROSKA_DVD_LEVEL_SS && data.p_private_data->GetBuffer()[1] == 0xC0);
  569. }
  570. bool dvd_command_interpretor_c::MatchVTSNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
  571. {
  572.     if ( i_cookie_size != 2 || data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
  573.         return false;
  574.  
  575.     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_SS || data.p_private_data->GetBuffer()[1] != 0x80 )
  576.         return false;
  577.     uint16 i_gtitle = (data.p_private_data->GetBuffer()[2] << 8 ) + data.p_private_data->GetBuffer()[3];
  578.     uint16 i_title = *(uint16*)p_cookie;
  579.     return (i_gtitle == i_title);
  580. }
  581. bool dvd_command_interpretor_c::MatchVTSMNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
  582. {
  583.     if ( i_cookie_size != 1 || data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
  584.         return false;
  585.  
  586.     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_SS || data.p_private_data->GetBuffer()[1] != 0x40 )
  587.         return false;
  588.     uint8 i_gtitle = data.p_private_data->GetBuffer()[3];
  589.     uint8 i_title = *(uint8*)p_cookie;
  590.     return (i_gtitle == i_title);
  591. }
  592. bool dvd_command_interpretor_c::MatchTitleNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
  593. {
  594.     if ( i_cookie_size != 1 || data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
  595.         return false;
  596.  
  597.     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_TT )
  598.         return false;
  599.     uint16 i_gtitle = (data.p_private_data->GetBuffer()[1] << 8 ) + data.p_private_data->GetBuffer()[2];
  600.     uint8 i_title = *(uint8*)p_cookie;
  601.     return (i_gtitle == i_title);
  602. }
  603. bool dvd_command_interpretor_c::MatchPgcType( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
  604. {
  605.     if ( i_cookie_size != 1 || data.p_private_data == NULL || data.p_private_data->GetSize() < 8 )
  606.         return false;
  607.  
  608.     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PGC )
  609.         return false;
  610.     uint8 i_pgc_type = data.p_private_data->GetBuffer()[3] & 0x0F;
  611.     uint8 i_pgc = *(uint8*)p_cookie;
  612.     return (i_pgc_type == i_pgc);
  613. }
  614. bool dvd_command_interpretor_c::MatchPgcNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
  615. {
  616.     if ( i_cookie_size != 2 || data.p_private_data == NULL || data.p_private_data->GetSize() < 8 )
  617.         return false;
  618.  
  619.     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PGC )
  620.         return false;
  621.     uint16 *i_pgc_n = (uint16 *)p_cookie;
  622.     uint16 i_pgc_num = (data.p_private_data->GetBuffer()[1] << 8) + data.p_private_data->GetBuffer()[2];
  623.     return (i_pgc_num == *i_pgc_n);
  624. }
  625. bool dvd_command_interpretor_c::MatchChapterNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
  626. {
  627.     if ( i_cookie_size != 1 || data.p_private_data == NULL || data.p_private_data->GetSize() < 2 )
  628.         return false;
  629.  
  630.     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PTT )
  631.         return false;
  632.     uint8 i_chapter = data.p_private_data->GetBuffer()[1];
  633.     uint8 i_ptt = *(uint8*)p_cookie;
  634.     return (i_chapter == i_ptt);
  635. }
  636. bool dvd_command_interpretor_c::MatchCellNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
  637. {
  638.     if ( i_cookie_size != 1 || data.p_private_data == NULL || data.p_private_data->GetSize() < 5 )
  639.         return false;
  640.  
  641.     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_CN )
  642.         return false;
  643.     uint8 *i_cell_n = (uint8 *)p_cookie;
  644.     uint8 i_cell_num = data.p_private_data->GetBuffer()[3];
  645.     return (i_cell_num == *i_cell_n);
  646. }
  647. const std::string matroska_script_interpretor_c::CMD_MS_GOTO_AND_PLAY = "GotoAndPlay";
  648. // see http://www.matroska.org/technical/specs/chapters/index.html#mscript
  649. //  for a description of existing commands
  650. bool matroska_script_interpretor_c::Interpret( const binary * p_command, size_t i_size )
  651. {
  652.     bool b_result = false;
  653.     char *psz_str = (char*) malloc( i_size + 1 );
  654.     memcpy( psz_str, p_command, i_size );
  655.     psz_str[ i_size ] = '';
  656.     std::string sz_command = psz_str;
  657.     free( psz_str );
  658.     msg_Dbg( &sys.demuxer, "command : %s", sz_command.c_str() );
  659. #if defined(__GNUC__) && (__GNUC__ < 3)
  660.     if ( sz_command.compare( CMD_MS_GOTO_AND_PLAY, 0, CMD_MS_GOTO_AND_PLAY.size() ) == 0 )
  661. #else
  662.     if ( sz_command.compare( 0, CMD_MS_GOTO_AND_PLAY.size(), CMD_MS_GOTO_AND_PLAY ) == 0 )
  663. #endif
  664.     {
  665.         size_t i,j;
  666.         // find the (
  667.         for ( i=CMD_MS_GOTO_AND_PLAY.size(); i<sz_command.size(); i++)
  668.         {
  669.             if ( sz_command[i] == '(' )
  670.             {
  671.                 i++;
  672.                 break;
  673.             }
  674.         }
  675.         // find the )
  676.         for ( j=i; j<sz_command.size(); j++)
  677.         {
  678.             if ( sz_command[j] == ')' )
  679.             {
  680.                 i--;
  681.                 break;
  682.             }
  683.         }
  684.         std::string st = sz_command.substr( i+1, j-i-1 );
  685.         int64_t i_chapter_uid = atoi( st.c_str() );
  686.         virtual_segment_c *p_segment;
  687.         chapter_item_c *p_chapter = sys.FindChapter( i_chapter_uid, p_segment );
  688.         if ( p_chapter == NULL )
  689.             msg_Dbg( &sys.demuxer, "Chapter %"PRId64" not found", i_chapter_uid);
  690.         else
  691.         {
  692.             if ( !p_chapter->EnterAndLeave( sys.p_current_segment->CurrentChapter() ) )
  693.                 p_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
  694.             b_result = true;
  695.         }
  696.     }
  697.     return b_result;
  698. }
  699. bool matroska_script_codec_c::Enter()
  700. {
  701.     bool f_result = false;
  702.     std::vector<KaxChapterProcessData*>::iterator index = enter_cmds.begin();
  703.     while ( index != enter_cmds.end() )
  704.     {
  705.         if ( (*index)->GetSize() )
  706.         {
  707.             msg_Dbg( &sys.demuxer, "Matroska Script enter command" );
  708.             f_result |= interpretor.Interpret( (*index)->GetBuffer(), (*index)->GetSize() );
  709.         }
  710.         index++;
  711.     }
  712.     return f_result;
  713. }
  714. bool matroska_script_codec_c::Leave()
  715. {
  716.     bool f_result = false;
  717.     std::vector<KaxChapterProcessData*>::iterator index = leave_cmds.begin();
  718.     while ( index != leave_cmds.end() )
  719.     {
  720.         if ( (*index)->GetSize() )
  721.         {
  722.             msg_Dbg( &sys.demuxer, "Matroska Script leave command" );
  723.             f_result |= interpretor.Interpret( (*index)->GetBuffer(), (*index)->GetSize() );
  724.         }
  725.         index++;
  726.     }
  727.     return f_result;
  728. }