Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
  • abdsaber000/vlc
  • falbrechtskirchinger/vlc
  • b.sullender/vlc
  • hulxv/vlc
  • zyad-ayad/vlc
408 results
Show changes
Commits on Source (17)
Showing
with 1329 additions and 1242 deletions
......@@ -196,6 +196,8 @@ libmkv_plugin_la_SOURCES = \
demux/mkv/Ebml_dispatcher.hpp \
demux/mkv/chapters.hpp demux/mkv/chapters.cpp \
demux/mkv/chapter_command.hpp demux/mkv/chapter_command.cpp \
demux/mkv/chapter_command_dvd.hpp demux/mkv/chapter_command_dvd.cpp \
demux/mkv/chapter_command_script.hpp demux/mkv/chapter_command_script.cpp \
demux/mkv/stream_io_callback.hpp demux/mkv/stream_io_callback.cpp \
demux/mkv/vlc_colors.c demux/mkv/vlc_colors.h \
demux/vobsub.h \
......
......@@ -273,6 +273,8 @@ if libebml_dep.found() and libmatroska_dep.found()
'mkv/Ebml_parser.cpp',
'mkv/chapters.cpp',
'mkv/chapter_command.cpp',
'mkv/chapter_command_dvd.cpp',
'mkv/chapter_command_script.cpp',
'mkv/stream_io_callback.cpp',
'mkv/vlc_colors.c',
'mp4/libmp4.c',
......
......@@ -27,8 +27,6 @@
#include <ebml/EbmlElement.h>
#include <ebml/EbmlId.h>
#include <vlc_threads.h>
#include <algorithm>
#include <typeinfo>
#include <vector>
......
......@@ -22,19 +22,18 @@
*****************************************************************************/
#include "chapter_command.hpp"
#include "demux.hpp"
#include <vlc_subpicture.h> // vlc_spu_highlight_t
#include <algorithm>
#include <vlc_arrays.h>
namespace mkv {
constexpr binary MATROSKA_DVD_LEVEL_SS = 0x30;
constexpr binary MATROSKA_DVD_LEVEL_LU = 0x2A;
constexpr binary MATROSKA_DVD_LEVEL_TT = 0x28;
constexpr binary MATROSKA_DVD_LEVEL_PGC = 0x20;
constexpr binary MATROSKA_DVD_LEVEL_PG = 0x18;
constexpr binary MATROSKA_DVD_LEVEL_PTT = 0x10;
constexpr binary MATROSKA_DVD_LEVEL_CN = 0x08;
chapter_codec_cmds_c::~chapter_codec_cmds_c()
{
delete p_private_data;
vlc_delete_all( enter_cmds );
vlc_delete_all( leave_cmds );
vlc_delete_all( during_cmds );
}
void chapter_codec_cmds_c::AddCommand( const KaxChapterProcessCommand & command )
{
......@@ -64,894 +63,4 @@ void chapter_codec_cmds_c::AddCommand( const KaxChapterProcessCommand & command
}
}
int16_t dvd_chapter_codec_c::GetTitleNumber() const
{
if ( p_private_data->GetSize() >= 3)
{
const binary* p_data = p_private_data->GetBuffer();
if ( p_data[0] == MATROSKA_DVD_LEVEL_SS )
{
return int16_t( (p_data[2] << 8) + p_data[3] );
}
}
return -1;
}
bool dvd_chapter_codec_c::Enter()
{
return EnterLeaveHelper( "Matroska DVD enter command", &enter_cmds );
}
bool dvd_chapter_codec_c::Leave()
{
return EnterLeaveHelper( "Matroska DVD leave command", &leave_cmds );
}
bool dvd_chapter_codec_c::EnterLeaveHelper( char const * str_diag, std::vector<KaxChapterProcessData*> * p_container )
{
bool f_result = false;
std::vector<KaxChapterProcessData*>::iterator it = p_container->begin ();
while( it != p_container->end() )
{
if( (*it)->GetSize() )
{
binary *p_data = (*it)->GetBuffer();
size_t i_size = std::min<size_t>( *p_data++, ( (*it)->GetSize() - 1 ) >> 3 ); // avoid reading too much
for( ; i_size > 0; i_size -=1, p_data += 8 )
{
vlc_debug( l, "%s", str_diag);
f_result |= intepretor.Interpret( p_data );
}
}
++it;
}
return f_result;
}
std::string dvd_chapter_codec_c::GetCodecName( bool f_for_title ) const
{
std::string result;
if ( p_private_data->GetSize() >= 3)
{
const binary* p_data = p_private_data->GetBuffer();
/* if ( p_data[0] == MATROSKA_DVD_LEVEL_TT )
{
uint16_t i_title = (p_data[1] << 8) + p_data[2];
char psz_str[11];
sprintf( psz_str, " %d ---", i_title );
result = "--- DVD Title";
result += psz_str;
}
else */ if ( p_data[0] == MATROSKA_DVD_LEVEL_LU )
{
char psz_str[11];
snprintf( psz_str, ARRAY_SIZE(psz_str), " (%c%c) ---", p_data[1], p_data[2] );
result = "--- DVD Menu";
result += psz_str;
}
else if ( p_data[0] == MATROSKA_DVD_LEVEL_SS && f_for_title )
{
if ( p_data[1] == 0x00 )
result = "First Played";
else if ( p_data[1] == 0xC0 )
result = "Video Manager";
else if ( p_data[1] == 0x80 )
{
uint16_t i_title = (p_data[2] << 8) + p_data[3];
char psz_str[20];
snprintf( psz_str, ARRAY_SIZE(psz_str), " %d -----", i_title );
result = "----- Title";
result += psz_str;
}
}
}
return 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_vsegment = NULL;
virtual_chapter_c *p_vchapter = NULL;
bool f_result = false;
uint16_t 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 = true;//(i_command & CMD_DVD_IF_NOT) == 0;
bool b_test_value = (i_command & CMD_DVD_TEST_VALUE) != 0;
uint8_t i_test = i_command & 0x70;
uint16_t i_value;
// see http://dvd.sourceforge.net/dvdinfo/vmi.html
uint8_t i_cr1;
uint16_t i_cr2;
switch ( i_command >> 12 )
{
default:
i_cr1 = p_command[3];
i_cr2 = (p_command[4] << 8) + p_command[5];
break;
case 3:
case 4:
case 5:
i_cr1 = p_command[6];
i_cr2 = p_command[7];
b_test_value = false;
break;
case 6:
case 7:
if ( ((p_command[1] >> 4) & 0x7) == 0)
{
i_cr1 = p_command[4];
i_cr2 = (p_command[6] << 8) + p_command[7];
}
else
{
i_cr1 = p_command[5];
i_cr2 = (p_command[6] << 8) + p_command[7];
}
break;
}
if ( b_test_value )
i_value = i_cr2;
else
i_value = GetPRM( i_cr2 );
switch ( i_test )
{
case CMD_DVD_IF_GPREG_EQUAL:
// if equals
vlc_debug( l, "IF %s EQUALS %s", GetRegTypeName( false, i_cr1 ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) == i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_NOT_EQUAL:
// if not equals
vlc_debug( l, "IF %s NOT EQUALS %s", GetRegTypeName( false, i_cr1 ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) != i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_INF:
// if inferior
vlc_debug( l, "IF %s < %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) < i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_INF_EQUAL:
// if inferior or equal
vlc_debug( l, "IF %s < %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) <= i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_AND:
// if logical and
vlc_debug( l, "IF %s & %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) & i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_SUP:
// if superior
vlc_debug( l, "IF %s >= %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) > i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_SUP_EQUAL:
// if superior or equal
vlc_debug( l, "IF %s >= %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) >= i_value ))
{
b_test_positive = false;
}
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:
{
vlc_debug( l, "NOP" );
break;
}
case CMD_DVD_BREAK:
{
vlc_debug( l, "Break" );
// TODO
break;
}
case CMD_DVD_JUMP_TT:
{
uint8_t i_title = p_command[5];
vlc_debug( l, "JumpTT %d", i_title );
// find in the ChapProcessPrivate matching this Title level
p_vchapter = vm.BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_title](const chapter_codec_cmds_c &data) {
return MatchTitleNumber(data, i_title);
}, p_vsegment );
if ( p_vsegment != NULL && p_vchapter != NULL )
{
/* enter via the First Cell */
uint8_t i_cell = 1;
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_cell](const chapter_codec_cmds_c &data) {
return MatchCellNumber( data, i_cell );
});
if ( p_vchapter != NULL )
{
vm.JumpTo( *p_vsegment, *p_vchapter );
f_result = true;
}
}
break;
}
case CMD_DVD_CALLSS_VTSM1:
{
vlc_debug( l, "CallSS" );
binary p_type;
switch( (p_command[6] & 0xC0) >> 6 ) {
case 0:
p_type = p_command[5] & 0x0F;
switch ( p_type )
{
case 0x00:
vlc_debug( l, "CallSS PGC (rsm_cell %x)", p_command[4]);
break;
case 0x02:
vlc_debug( l, "CallSS Title Entry (rsm_cell %x)", p_command[4]);
break;
case 0x03:
vlc_debug( l, "CallSS Root Menu (rsm_cell %x)", p_command[4]);
break;
case 0x04:
vlc_debug( l, "CallSS Subpicture Menu (rsm_cell %x)", p_command[4]);
break;
case 0x05:
vlc_debug( l, "CallSS Audio Menu (rsm_cell %x)", p_command[4]);
break;
case 0x06:
vlc_debug( l, "CallSS Angle Menu (rsm_cell %x)", p_command[4]);
break;
case 0x07:
vlc_debug( l, "CallSS Chapter Menu (rsm_cell %x)", p_command[4]);
break;
default:
vlc_debug( l, "CallSS <unknown> (rsm_cell %x)", p_command[4]);
break;
}
p_vchapter = vm.BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[p_type](const chapter_codec_cmds_c &data) {
return MatchPgcType( data, p_type );
}, p_vsegment );
if ( p_vsegment != NULL && p_vchapter != NULL )
{
/* enter via the first Cell */
uint8_t i_cell = 1;
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_cell](const chapter_codec_cmds_c &data) {
return MatchCellNumber( data, i_cell ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *p_vsegment, *p_vchapter );
f_result = true;
}
}
break;
case 1:
vlc_debug( l, "CallSS VMGM (menu %d, rsm_cell %x)", p_command[5] & 0x0F, p_command[4]);
break;
case 2:
vlc_debug( l, "CallSS VTSM (menu %d, rsm_cell %x)", p_command[5] & 0x0F, p_command[4]);
break;
case 3:
vlc_debug( l, "CallSS VMGM (pgc %d, rsm_cell %x)", (p_command[2] << 8) + p_command[3], p_command[4]);
break;
}
break;
}
case CMD_DVD_JUMP_SS:
{
vlc_debug( l, "JumpSS");
binary p_type;
switch( (p_command[5] & 0xC0) >> 6 ) {
case 0:
vlc_debug( l, "JumpSS FP");
break;
case 1:
p_type = p_command[5] & 0x0F;
switch ( p_type )
{
case 0x02:
vlc_debug( l, "JumpSS VMGM Title Entry");
break;
case 0x03:
vlc_debug( l, "JumpSS VMGM Root Menu");
break;
case 0x04:
vlc_debug( l, "JumpSS VMGM Subpicture Menu");
break;
case 0x05:
vlc_debug( l, "JumpSS VMGM Audio Menu");
break;
case 0x06:
vlc_debug( l, "JumpSS VMGM Angle Menu");
break;
case 0x07:
vlc_debug( l, "JumpSS VMGM Chapter Menu");
break;
default:
vlc_debug( l, "JumpSS <unknown>");
break;
}
// find the VMG
p_vchapter = vm.BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[](const chapter_codec_cmds_c &data) {
return MatchIsVMG( data); }, p_vsegment );
if ( p_vsegment != NULL )
{
p_vchapter = p_vsegment->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[p_type](const chapter_codec_cmds_c &data) {
return MatchPgcType( data, p_type ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *p_vsegment, *p_vchapter );
f_result = true;
}
}
break;
case 2:
p_type = p_command[5] & 0x0F;
switch ( p_type )
{
case 0x02:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Title Entry", p_command[4], p_command[3]);
break;
case 0x03:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Root Menu", p_command[4], p_command[3]);
break;
case 0x04:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Subpicture Menu", p_command[4], p_command[3]);
break;
case 0x05:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Audio Menu", p_command[4], p_command[3]);
break;
case 0x06:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Angle Menu", p_command[4], p_command[3]);
break;
case 0x07:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Chapter Menu", p_command[4], p_command[3]);
break;
default:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) <unknown>", p_command[4], p_command[3]);
break;
}
{
uint8_t i_vts = p_command[4];
p_vchapter = vm.BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_vts](const chapter_codec_cmds_c &data) {
return MatchVTSMNumber( data, i_vts ); }, p_vsegment );
if ( p_vsegment != NULL && p_vchapter != NULL )
{
// find the title in the VTS
uint8_t i_title = p_command[3];
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_title](const chapter_codec_cmds_c &data) {
return MatchTitleNumber( data, i_title ); } );
if ( p_vchapter != NULL )
{
// find the specified menu in the VTSM
p_vchapter = p_vsegment->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[p_type](const chapter_codec_cmds_c &data) {
return MatchPgcType( data, p_type ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *p_vsegment, *p_vchapter );
f_result = true;
}
}
else
vlc_debug( l, "Title (%d) does not exist in this VTS", i_title );
}
else
vlc_debug( l, "DVD Domain VTS (%d) not found", i_vts );
}
break;
case 3:
vlc_debug( l, "JumpSS VMGM (pgc %d)", (p_command[2] << 8) + p_command[3]);
break;
}
break;
}
case CMD_DVD_JUMPVTS_PTT:
{
uint8_t i_title = p_command[5];
uint8_t i_ptt = p_command[3];
vlc_debug( l, "JumpVTS Title (%d) PTT (%d)", i_title, i_ptt);
// find the current VTS content segment
p_vchapter = vm.GetCurrentVSegment()->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[](const chapter_codec_cmds_c &data) {
return MatchIsDomain( data); } );
if ( p_vchapter != NULL )
{
int16_t i_curr_title = ( p_vchapter->p_chapter )? p_vchapter->p_chapter->GetTitleNumber() : 0;
if ( i_curr_title > 0 )
{
p_vchapter = vm.BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_curr_title](const chapter_codec_cmds_c &data) {
return MatchVTSNumber( data, i_curr_title ); }, p_vsegment );
if ( p_vsegment != NULL && p_vchapter != NULL )
{
// find the title in the VTS
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_title](const chapter_codec_cmds_c &data) {
return MatchTitleNumber( data, i_title ); } );
if ( p_vchapter != NULL )
{
// find the chapter in the title
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_ptt](const chapter_codec_cmds_c &data) {
return MatchChapterNumber( data, i_ptt ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *p_vsegment, *p_vchapter );
f_result = true;
}
}
else
vlc_debug( l, "Title (%d) does not exist in this VTS", i_title );
}
else
vlc_debug( l, "DVD Domain VTS (%d) not found", i_curr_title );
}
else
vlc_debug( l, "JumpVTS_PTT command found but not in a VTS(M)");
}
else
vlc_debug( l, "JumpVTS_PTT command but the DVD domain wasn't found");
break;
}
case CMD_DVD_SET_GPRMMD:
{
vlc_debug( l, "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] ) )
vlc_debug( l, "Set GPRMMD failed" );
break;
}
case CMD_DVD_LINKPGCN:
{
uint16_t i_pgcn = (p_command[6] << 8) + p_command[7];
vlc_debug( l, "Link PGCN(%d)", i_pgcn );
p_vchapter = vm.GetCurrentVSegment()->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_pgcn](const chapter_codec_cmds_c &data) {
return MatchPgcNumber( data, i_pgcn ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *vm.GetCurrentVSegment(), *p_vchapter );
f_result = true;
}
break;
}
case CMD_DVD_LINKCN:
{
uint8_t i_cn = p_command[7];
p_vchapter = vm.GetCurrentVSegment()->CurrentChapter();
vlc_debug( l, "LinkCN (cell %d)", i_cn );
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_cn](const chapter_codec_cmds_c &data) {
return MatchCellNumber( data, i_cn ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *vm.GetCurrentVSegment(), *p_vchapter );
f_result = true;
}
break;
}
case CMD_DVD_GOTO_LINE:
{
vlc_debug( l, "GotoLine (%d)", (p_command[6] << 8) + p_command[7] );
// TODO
break;
}
case CMD_DVD_SET_HL_BTNN1:
{
vlc_debug( l, "SetHL_BTN (%d)", p_command[4] );
SetSPRM( 0x88, p_command[4] );
break;
}
default:
{
vlc_debug( l, "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;
}
void dvd_command_interpretor_c::ProcessNavAction( uint16_t button )
{
const pci_t & pci = pci_packet;
if( button <= 0 || button > pci.hli.hl_gi.btn_ns )
return;
SetSPRM( 0x88, button );
const btni_t & button_ptr = pci.hli.btnit[button-1];
if ( button_ptr.auto_action_mode )
{
// process the button action
Interpret( button_ptr.cmd.bytes, 8 );
}
}
void dvd_command_interpretor_c::HandleKeyEvent( NavivationKey key )
{
const pci_t & pci = pci_packet;
uint16_t i_curr_button = GetSPRM( 0x88 );
if( i_curr_button <= 0 || i_curr_button > pci.hli.hl_gi.btn_ns )
return;
const btni_t & button_ptr = pci.hli.btnit[i_curr_button-1];
switch( key )
{
case LEFT: return ProcessNavAction( button_ptr.left );
case RIGHT: return ProcessNavAction( button_ptr.right );
case UP: return ProcessNavAction( button_ptr.up );
case DOWN: return ProcessNavAction( button_ptr.down );
case OK:
// process the button action
Interpret( button_ptr.cmd.bytes, 8 );
break;
default:
break;
}
}
void dvd_command_interpretor_c::HandleMousePressed( unsigned x, unsigned y )
{
const pci_t & pci = pci_packet;
int32_t button;
int32_t best,dist,d;
int32_t mx,my,dx,dy;
// get current button
best = 0;
dist = 0x08000000; /* >> than (720*720)+(567*567); */
for(button = 1; button <= pci.hli.hl_gi.btn_ns; button++)
{
const btni_t & button_ptr = pci.hli.btnit[button-1];
if((x >= button_ptr.x_start)
&& (x <= button_ptr.x_end)
&& (y >= button_ptr.y_start)
&& (y <= button_ptr.y_end))
{
mx = (button_ptr.x_start + button_ptr.x_end)/2;
my = (button_ptr.y_start + button_ptr.y_end)/2;
dx = mx - x;
dy = my - y;
d = (dx*dx) + (dy*dy);
/* If the mouse is within the button and the mouse is closer
* to the center of this button then it is the best choice. */
if(d < dist) {
dist = d;
best = button;
}
}
}
if ( best == 0)
return;
const btni_t & button_ptr = pci.hli.btnit[best-1];
uint16_t i_curr_button = GetSPRM( 0x88 );
vlc_debug( l, "Clicked button %d", best );
// process the button action
SetSPRM( 0x88, best );
Interpret( button_ptr.cmd.bytes, 8 );
vlc_debug( l, "Processed button %d", best );
// select new button
if ( best != i_curr_button )
{
// TODO: make sure we do not overflow in the conversion
vlc_spu_highlight_t spu_hl = vlc_spu_highlight_t();
spu_hl.x_start = (int)button_ptr.x_start;
spu_hl.y_start = (int)button_ptr.y_start;
spu_hl.x_end = (int)button_ptr.x_end;
spu_hl.y_end = (int)button_ptr.y_end;
uint32_t i_palette;
if(button_ptr.btn_coln != 0) {
i_palette = pci.hli.btn_colit.btn_coli[button_ptr.btn_coln-1][1];
} else {
i_palette = 0;
}
for( int i = 0; i < 4; i++ )
{
uint32_t i_yuv = 0xFF;//p_sys->clut[(hl.palette>>(16+i*4))&0x0f];
uint8_t i_alpha = (i_palette>>(i*4))&0x0f;
i_alpha = i_alpha == 0xf ? 0xff : i_alpha << 4;
spu_hl.palette.palette[i][0] = (i_yuv >> 16) & 0xff;
spu_hl.palette.palette[i][1] = (i_yuv >> 0) & 0xff;
spu_hl.palette.palette[i][2] = (i_yuv >> 8) & 0xff;
spu_hl.palette.palette[i][3] = i_alpha;
}
vm.SetHighlight( spu_hl );
}
}
bool dvd_command_interpretor_c::MatchIsDomain( const chapter_codec_cmds_c &data )
{
return ( data.p_private_data != NULL && data.p_private_data->GetBuffer()[0] == MATROSKA_DVD_LEVEL_SS );
}
bool dvd_command_interpretor_c::MatchIsVMG( const chapter_codec_cmds_c &data )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 2 )
return false;
return ( data.p_private_data->GetBuffer()[0] == MATROSKA_DVD_LEVEL_SS && data.p_private_data->GetBuffer()[1] == 0xC0);
}
bool dvd_command_interpretor_c::MatchVTSNumber( const chapter_codec_cmds_c &data, uint16_t i_title )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_SS || data.p_private_data->GetBuffer()[1] != 0x80 )
return false;
uint16_t i_gtitle = (data.p_private_data->GetBuffer()[2] << 8 ) + data.p_private_data->GetBuffer()[3];
return (i_gtitle == i_title);
}
bool dvd_command_interpretor_c::MatchVTSMNumber( const chapter_codec_cmds_c &data, uint8_t i_title )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_SS || data.p_private_data->GetBuffer()[1] != 0x40 )
return false;
uint8_t i_gtitle = data.p_private_data->GetBuffer()[3];
return (i_gtitle == i_title);
}
bool dvd_command_interpretor_c::MatchTitleNumber( const chapter_codec_cmds_c &data, uint8_t i_title )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_TT )
return false;
uint16_t i_gtitle = (data.p_private_data->GetBuffer()[1] << 8 ) + data.p_private_data->GetBuffer()[2];
return (i_gtitle == i_title);
}
bool dvd_command_interpretor_c::MatchPgcType( const chapter_codec_cmds_c &data, uint8_t i_pgc )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 8 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PGC )
return false;
uint8_t i_pgc_type = data.p_private_data->GetBuffer()[3] & 0x0F;
return (i_pgc_type == i_pgc);
}
bool dvd_command_interpretor_c::MatchPgcNumber( const chapter_codec_cmds_c &data, uint16_t i_pgc_n )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 8 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PGC )
return false;
uint16_t i_pgc_num = (data.p_private_data->GetBuffer()[1] << 8) + data.p_private_data->GetBuffer()[2];
return (i_pgc_num == i_pgc_n);
}
bool dvd_command_interpretor_c::MatchChapterNumber( const chapter_codec_cmds_c &data, uint8_t i_ptt )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 2 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PTT )
return false;
uint8_t i_chapter = data.p_private_data->GetBuffer()[1];
return (i_chapter == i_ptt);
}
bool dvd_command_interpretor_c::MatchCellNumber( const chapter_codec_cmds_c &data, uint8_t i_cell_n )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 5 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_CN )
return false;
uint8_t i_cell_num = data.p_private_data->GetBuffer()[3];
return (i_cell_num == i_cell_n);
}
void dvd_command_interpretor_c::SetPci(const pci_t *data)
{
memcpy(&pci_packet, data, sizeof(pci_packet));
#ifndef WORDS_BIGENDIAN
for( uint8_t button = 1; button <= pci_packet.hli.hl_gi.btn_ns &&
button < ARRAY_SIZE(pci_packet.hli.btnit); button++) {
btni_t & button_ptr = pci_packet.hli.btnit[button-1];
binary *p_data = (binary*) &button_ptr;
uint16_t i_x_start = ((p_data[0] & 0x3F) << 4 ) + ( p_data[1] >> 4 );
uint16_t i_x_end = ((p_data[1] & 0x03) << 8 ) + p_data[2];
uint16_t i_y_start = ((p_data[3] & 0x3F) << 4 ) + ( p_data[4] >> 4 );
uint16_t 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 ( uint8_t i = 0; i<3; i++ )
for ( uint8_t 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
}
const std::string matroska_script_interpretor_c::CMD_MS_GOTO_AND_PLAY = "GotoAndPlay";
// 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;
std::string sz_command( reinterpret_cast<const char*> (p_command), i_size );
vlc_debug( l, "command : %s", sz_command.c_str() );
if ( sz_command.compare( 0, CMD_MS_GOTO_AND_PLAY.size(), CMD_MS_GOTO_AND_PLAY ) == 0 )
{
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 );
chapter_uid i_chapter_uid = std::stoul( st );
virtual_segment_c *p_vsegment;
virtual_chapter_c *p_vchapter = vm.FindVChapter( i_chapter_uid, p_vsegment );
if ( p_vchapter == NULL )
vlc_debug( l, "Chapter %" PRId64 " not found", i_chapter_uid);
else
{
if ( !p_vchapter->EnterAndLeave( vm.GetCurrentVSegment()->CurrentChapter(), false ) )
vm.JumpTo( *p_vsegment, *p_vchapter );
b_result = true;
}
}
return b_result;
}
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() )
{
vlc_debug( l, "Matroska Script enter command" );
f_result |= interpreter.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() )
{
vlc_debug( l, "Matroska Script leave command" );
f_result |= interpreter.Interpret( (*index)->GetBuffer(), (*index)->GetSize() );
}
++index;
}
return f_result;
}
} // namespace
......@@ -24,9 +24,7 @@
#ifndef VLC_MKV_CHAPTER_COMMAND_HPP_
#define VLC_MKV_CHAPTER_COMMAND_HPP_
#include <vlc_arrays.h>
#include "mkv.hpp"
#include "dvd_types.hpp"
struct vlc_spu_highlight_t;
......@@ -62,13 +60,7 @@ public:
,vm( vm_ )
{}
virtual ~chapter_codec_cmds_c()
{
delete p_private_data;
vlc_delete_all( enter_cmds );
vlc_delete_all( leave_cmds );
vlc_delete_all( during_cmds );
}
virtual ~chapter_codec_cmds_c();
void SetPrivate( const KaxChapterProcessPrivate & private_data )
{
......@@ -96,231 +88,6 @@ protected:
chapter_codec_vm & vm;
};
class dvd_command_interpretor_c
{
public:
dvd_command_interpretor_c( struct vlc_logger *log, chapter_codec_vm & vm_ )
:l( log )
,vm( vm_ )
{
memset( p_PRMs, 0, sizeof(p_PRMs) );
p_PRMs[ 0x80 + 1 ] = 15;
p_PRMs[ 0x80 + 2 ] = 62;
p_PRMs[ 0x80 + 3 ] = 1;
p_PRMs[ 0x80 + 4 ] = 1;
p_PRMs[ 0x80 + 7 ] = 1;
p_PRMs[ 0x80 + 8 ] = 1;
p_PRMs[ 0x80 + 16 ] = 0xFFFFu;
p_PRMs[ 0x80 + 18 ] = 0xFFFFu;
}
bool Interpret( const binary * p_command, size_t i_size = 8 );
void HandleKeyEvent( NavivationKey );
void HandleMousePressed( unsigned x, unsigned y );
void SetPci(const pci_t *data);
protected:
uint16_t GetPRM( size_t index ) const
{
if ( index < 256 )
return p_PRMs[ index ];
else return 0;
}
uint16_t GetGPRM( size_t index ) const
{
if ( index < 16 )
return p_PRMs[ index ];
else return 0;
}
uint16_t GetSPRM( size_t index ) const
{
// 21,22,23 reserved for future use
if ( index >= 0x80 && index < 0x95 )
return p_PRMs[ index ];
else return 0;
}
bool SetPRM( size_t index, uint16_t value )
{
if ( index < 16 )
{
p_PRMs[ index ] = value;
return true;
}
return false;
}
bool SetGPRM( size_t index, uint16_t value )
{
if ( index < 16 )
{
p_PRMs[ index ] = value;
return true;
}
return false;
}
bool SetSPRM( size_t index, uint16_t value )
{
if ( index > 0x80 && index <= 0x8D && index != 0x8C )
{
p_PRMs[ index ] = value;
return true;
}
return false;
}
void ProcessNavAction( uint16_t button );
std::string GetRegTypeName( bool b_value, uint16_t value ) const
{
std::string result;
char s_value[6], s_reg_value[6];
snprintf( s_value, ARRAY_SIZE(s_value), "%.5d", value );
if ( b_value )
{
result = "value (";
result += s_value;
result += ")";
}
else if ( value < 0x80 )
{
snprintf( s_reg_value, ARRAY_SIZE(s_reg_value), "%.5d", GetPRM( value ) );
result = "GPreg[";
result += s_value;
result += "] (";
result += s_reg_value;
result += ")";
}
else
{
snprintf( s_reg_value, ARRAY_SIZE(s_reg_value), "%.5d", GetPRM( value ) );
result = "SPreg[";
result += s_value;
result += "] (";
result += s_reg_value;
result += ")";
}
return result;
}
uint16_t p_PRMs[256];
struct vlc_logger *l;
chapter_codec_vm & vm;
pci_t pci_packet = {};
// DVD command IDs
// Tests
// whether it's a comparison on the value or register
static const uint16_t CMD_DVD_TEST_VALUE = 0x80;
static const uint16_t CMD_DVD_IF_GPREG_AND = (1 << 4);
static const uint16_t CMD_DVD_IF_GPREG_EQUAL = (2 << 4);
static const uint16_t CMD_DVD_IF_GPREG_NOT_EQUAL = (3 << 4);
static const uint16_t CMD_DVD_IF_GPREG_SUP_EQUAL = (4 << 4);
static const uint16_t CMD_DVD_IF_GPREG_SUP = (5 << 4);
static const uint16_t CMD_DVD_IF_GPREG_INF_EQUAL = (6 << 4);
static const uint16_t CMD_DVD_IF_GPREG_INF = (7 << 4);
static const uint16_t CMD_DVD_NOP = 0x0000;
static const uint16_t CMD_DVD_GOTO_LINE = 0x0001;
static const uint16_t CMD_DVD_BREAK = 0x0002;
// Links
static const uint16_t CMD_DVD_NOP2 = 0x2001;
static const uint16_t CMD_DVD_LINKPGCN = 0x2004;
static const uint16_t CMD_DVD_LINKPGN = 0x2006;
static const uint16_t CMD_DVD_LINKCN = 0x2007;
static const uint16_t CMD_DVD_JUMP_TT = 0x3002;
static const uint16_t CMD_DVD_JUMPVTS_TT = 0x3003;
static const uint16_t CMD_DVD_JUMPVTS_PTT = 0x3005;
static const uint16_t CMD_DVD_JUMP_SS = 0x3006;
static const uint16_t CMD_DVD_CALLSS_VTSM1 = 0x3008;
//
static const uint16_t CMD_DVD_SET_HL_BTNN2 = 0x4600;
static const uint16_t CMD_DVD_SET_HL_BTNN_LINKPGCN1 = 0x4604;
static const uint16_t CMD_DVD_SET_STREAM = 0x5100;
static const uint16_t CMD_DVD_SET_GPRMMD = 0x5300;
static const uint16_t CMD_DVD_SET_HL_BTNN1 = 0x5600;
static const uint16_t CMD_DVD_SET_HL_BTNN_LINKPGCN2 = 0x5604;
static const uint16_t CMD_DVD_SET_HL_BTNN_LINKCN = 0x5607;
// Operations
static const uint16_t CMD_DVD_MOV_SPREG_PREG = 0x6100;
static const uint16_t CMD_DVD_GPREG_MOV_VALUE = 0x7100;
static const uint16_t CMD_DVD_SUB_GPREG = 0x7400;
static const uint16_t CMD_DVD_MULT_GPREG = 0x7500;
static const uint16_t CMD_DVD_GPREG_DIV_VALUE = 0x7600;
static const uint16_t CMD_DVD_GPREG_AND_VALUE = 0x7900;
// callbacks when browsing inside CodecPrivate
static bool MatchIsDomain ( const chapter_codec_cmds_c & );
static bool MatchIsVMG ( const chapter_codec_cmds_c & );
static bool MatchVTSNumber ( const chapter_codec_cmds_c &, uint16_t i_title );
static bool MatchVTSMNumber ( const chapter_codec_cmds_c &, uint8_t i_title );
static bool MatchTitleNumber ( const chapter_codec_cmds_c &, uint8_t i_title );
static bool MatchPgcType ( const chapter_codec_cmds_c &, uint8_t i_pgc );
static bool MatchPgcNumber ( const chapter_codec_cmds_c &, uint16_t i_pgc_n );
static bool MatchChapterNumber( const chapter_codec_cmds_c &, uint8_t i_ptt );
static bool MatchCellNumber ( const chapter_codec_cmds_c &, uint8_t i_cell_n );
};
class dvd_chapter_codec_c : public chapter_codec_cmds_c
{
public:
dvd_chapter_codec_c( struct vlc_logger *log, chapter_codec_vm & vm_, dvd_command_interpretor_c & intepretor_ )
:chapter_codec_cmds_c( log, vm_, MATROSKA_CHAPTER_CODEC_DVD )
,intepretor(intepretor_)
{}
bool Enter() override;
bool Leave() override;
std::string GetCodecName( bool f_for_title = false ) const override;
int16_t GetTitleNumber() const override;
protected:
bool EnterLeaveHelper( char const*, std::vector<KaxChapterProcessData*>* );
dvd_command_interpretor_c & intepretor;
};
class matroska_script_interpretor_c
{
public:
matroska_script_interpretor_c( struct vlc_logger *log, chapter_codec_vm & vm_ )
:l( log )
,vm( vm_ )
{}
bool Interpret( const binary * p_command, size_t i_size );
// DVD command IDs
static const std::string CMD_MS_GOTO_AND_PLAY;
protected:
struct vlc_logger *l;
chapter_codec_vm & vm;
};
class matroska_script_codec_c : public chapter_codec_cmds_c
{
public:
matroska_script_codec_c( struct vlc_logger *log, chapter_codec_vm & vm_ )
:chapter_codec_cmds_c( log, vm_, MATROSKA_CHAPTER_CODEC_NATIVE )
,interpreter( log, vm_ )
{}
bool Enter();
bool Leave();
protected:
matroska_script_interpretor_c interpreter;
};
} // namespace
#endif
// Copyright (C) 2003-2024 VLC authors and VideoLAN
// SPDX-License-Identifier: LGPL-2.1-or-later
//
// chapter_command_dvd.cpp : DVD codec for Matroska Chapter Codecs
// Authors: Laurent Aimar <fenrir@via.ecp.fr>
// Steve Lhomme <steve.lhomme@free.fr>
#include "chapter_command_dvd.hpp"
#include "virtual_segment.hpp"
#include <vlc_subpicture.h> // vlc_spu_highlight_t
namespace mkv {
constexpr binary MATROSKA_DVD_LEVEL_SS = 0x30;
constexpr binary MATROSKA_DVD_LEVEL_LU = 0x2A;
constexpr binary MATROSKA_DVD_LEVEL_TT = 0x28;
constexpr binary MATROSKA_DVD_LEVEL_PGC = 0x20;
// constexpr binary MATROSKA_DVD_LEVEL_PG = 0x18;
constexpr binary MATROSKA_DVD_LEVEL_PTT = 0x10;
constexpr binary MATROSKA_DVD_LEVEL_CN = 0x08;
int16_t dvd_chapter_codec_c::GetTitleNumber() const
{
if ( p_private_data->GetSize() >= 3)
{
const binary* p_data = p_private_data->GetBuffer();
if ( p_data[0] == MATROSKA_DVD_LEVEL_SS )
{
return int16_t( (p_data[2] << 8) + p_data[3] );
}
}
return -1;
}
bool dvd_chapter_codec_c::Enter()
{
return EnterLeaveHelper( "Matroska DVD enter command", &enter_cmds );
}
bool dvd_chapter_codec_c::Leave()
{
return EnterLeaveHelper( "Matroska DVD leave command", &leave_cmds );
}
bool dvd_chapter_codec_c::EnterLeaveHelper( char const * str_diag, std::vector<KaxChapterProcessData*> * p_container )
{
bool f_result = false;
std::vector<KaxChapterProcessData*>::iterator it = p_container->begin ();
while( it != p_container->end() )
{
if( (*it)->GetSize() )
{
binary *p_data = (*it)->GetBuffer();
size_t i_size = std::min<size_t>( *p_data++, ( (*it)->GetSize() - 1 ) >> 3 ); // avoid reading too much
for( ; i_size > 0; i_size -=1, p_data += 8 )
{
vlc_debug( l, "%s", str_diag);
f_result |= intepretor.Interpret( p_data );
}
}
++it;
}
return f_result;
}
std::string dvd_chapter_codec_c::GetCodecName( bool f_for_title ) const
{
std::string result;
if ( p_private_data->GetSize() >= 3)
{
const binary* p_data = p_private_data->GetBuffer();
/* if ( p_data[0] == MATROSKA_DVD_LEVEL_TT )
{
uint16_t i_title = (p_data[1] << 8) + p_data[2];
char psz_str[11];
sprintf( psz_str, " %d ---", i_title );
result = "--- DVD Title";
result += psz_str;
}
else */ if ( p_data[0] == MATROSKA_DVD_LEVEL_LU )
{
char psz_str[11];
snprintf( psz_str, ARRAY_SIZE(psz_str), " (%c%c) ---", p_data[1], p_data[2] );
result = "--- DVD Menu";
result += psz_str;
}
else if ( p_data[0] == MATROSKA_DVD_LEVEL_SS && f_for_title )
{
if ( p_data[1] == 0x00 )
result = "First Played";
else if ( p_data[1] == 0xC0 )
result = "Video Manager";
else if ( p_data[1] == 0x80 )
{
uint16_t i_title = (p_data[2] << 8) + p_data[3];
char psz_str[20];
snprintf( psz_str, ARRAY_SIZE(psz_str), " %d -----", i_title );
result = "----- Title";
result += psz_str;
}
}
}
return 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_vsegment = NULL;
virtual_chapter_c *p_vchapter = NULL;
bool f_result = false;
uint16_t 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 = true;//(i_command & CMD_DVD_IF_NOT) == 0;
bool b_test_value = (i_command & CMD_DVD_TEST_VALUE) != 0;
uint8_t i_test = i_command & 0x70;
uint16_t i_value;
// see http://dvd.sourceforge.net/dvdinfo/vmi.html
uint8_t i_cr1;
uint16_t i_cr2;
switch ( i_command >> 12 )
{
default:
i_cr1 = p_command[3];
i_cr2 = (p_command[4] << 8) + p_command[5];
break;
case 3:
case 4:
case 5:
i_cr1 = p_command[6];
i_cr2 = p_command[7];
b_test_value = false;
break;
case 6:
case 7:
if ( ((p_command[1] >> 4) & 0x7) == 0)
{
i_cr1 = p_command[4];
i_cr2 = (p_command[6] << 8) + p_command[7];
}
else
{
i_cr1 = p_command[5];
i_cr2 = (p_command[6] << 8) + p_command[7];
}
break;
}
if ( b_test_value )
i_value = i_cr2;
else
i_value = GetPRM( i_cr2 );
switch ( i_test )
{
case CMD_DVD_IF_GPREG_EQUAL:
// if equals
vlc_debug( l, "IF %s EQUALS %s", GetRegTypeName( false, i_cr1 ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) == i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_NOT_EQUAL:
// if not equals
vlc_debug( l, "IF %s NOT EQUALS %s", GetRegTypeName( false, i_cr1 ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) != i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_INF:
// if inferior
vlc_debug( l, "IF %s < %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) < i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_INF_EQUAL:
// if inferior or equal
vlc_debug( l, "IF %s < %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) <= i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_AND:
// if logical and
vlc_debug( l, "IF %s & %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) & i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_SUP:
// if superior
vlc_debug( l, "IF %s >= %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) > i_value ))
{
b_test_positive = false;
}
break;
case CMD_DVD_IF_GPREG_SUP_EQUAL:
// if superior or equal
vlc_debug( l, "IF %s >= %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
if (!( GetPRM( i_cr1 ) >= i_value ))
{
b_test_positive = false;
}
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:
{
vlc_debug( l, "NOP" );
break;
}
case CMD_DVD_BREAK:
{
vlc_debug( l, "Break" );
// TODO
break;
}
case CMD_DVD_JUMP_TT:
{
uint8_t i_title = p_command[5];
vlc_debug( l, "JumpTT %d", i_title );
// find in the ChapProcessPrivate matching this Title level
p_vchapter = vm.BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_title](const chapter_codec_cmds_c &data) {
return MatchTitleNumber(data, i_title);
}, p_vsegment );
if ( p_vsegment != NULL && p_vchapter != NULL )
{
/* enter via the First Cell */
uint8_t i_cell = 1;
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_cell](const chapter_codec_cmds_c &data) {
return MatchCellNumber( data, i_cell );
});
if ( p_vchapter != NULL )
{
vm.JumpTo( *p_vsegment, *p_vchapter );
f_result = true;
}
}
break;
}
case CMD_DVD_CALLSS_VTSM1:
{
vlc_debug( l, "CallSS" );
binary p_type;
switch( (p_command[6] & 0xC0) >> 6 ) {
case 0:
p_type = p_command[5] & 0x0F;
switch ( p_type )
{
case 0x00:
vlc_debug( l, "CallSS PGC (rsm_cell %x)", p_command[4]);
break;
case 0x02:
vlc_debug( l, "CallSS Title Entry (rsm_cell %x)", p_command[4]);
break;
case 0x03:
vlc_debug( l, "CallSS Root Menu (rsm_cell %x)", p_command[4]);
break;
case 0x04:
vlc_debug( l, "CallSS Subpicture Menu (rsm_cell %x)", p_command[4]);
break;
case 0x05:
vlc_debug( l, "CallSS Audio Menu (rsm_cell %x)", p_command[4]);
break;
case 0x06:
vlc_debug( l, "CallSS Angle Menu (rsm_cell %x)", p_command[4]);
break;
case 0x07:
vlc_debug( l, "CallSS Chapter Menu (rsm_cell %x)", p_command[4]);
break;
default:
vlc_debug( l, "CallSS <unknown> (rsm_cell %x)", p_command[4]);
break;
}
p_vchapter = vm.BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[p_type](const chapter_codec_cmds_c &data) {
return MatchPgcType( data, p_type );
}, p_vsegment );
if ( p_vsegment != NULL && p_vchapter != NULL )
{
/* enter via the first Cell */
uint8_t i_cell = 1;
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_cell](const chapter_codec_cmds_c &data) {
return MatchCellNumber( data, i_cell ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *p_vsegment, *p_vchapter );
f_result = true;
}
}
break;
case 1:
vlc_debug( l, "CallSS VMGM (menu %d, rsm_cell %x)", p_command[5] & 0x0F, p_command[4]);
break;
case 2:
vlc_debug( l, "CallSS VTSM (menu %d, rsm_cell %x)", p_command[5] & 0x0F, p_command[4]);
break;
case 3:
vlc_debug( l, "CallSS VMGM (pgc %d, rsm_cell %x)", (p_command[2] << 8) + p_command[3], p_command[4]);
break;
}
break;
}
case CMD_DVD_JUMP_SS:
{
vlc_debug( l, "JumpSS");
binary p_type;
switch( (p_command[5] & 0xC0) >> 6 ) {
case 0:
vlc_debug( l, "JumpSS FP");
break;
case 1:
p_type = p_command[5] & 0x0F;
switch ( p_type )
{
case 0x02:
vlc_debug( l, "JumpSS VMGM Title Entry");
break;
case 0x03:
vlc_debug( l, "JumpSS VMGM Root Menu");
break;
case 0x04:
vlc_debug( l, "JumpSS VMGM Subpicture Menu");
break;
case 0x05:
vlc_debug( l, "JumpSS VMGM Audio Menu");
break;
case 0x06:
vlc_debug( l, "JumpSS VMGM Angle Menu");
break;
case 0x07:
vlc_debug( l, "JumpSS VMGM Chapter Menu");
break;
default:
vlc_debug( l, "JumpSS <unknown>");
break;
}
// find the VMG
p_vchapter = vm.BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[](const chapter_codec_cmds_c &data) {
return MatchIsVMG( data); }, p_vsegment );
if ( p_vsegment != NULL )
{
p_vchapter = p_vsegment->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[p_type](const chapter_codec_cmds_c &data) {
return MatchPgcType( data, p_type ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *p_vsegment, *p_vchapter );
f_result = true;
}
}
break;
case 2:
p_type = p_command[5] & 0x0F;
switch ( p_type )
{
case 0x02:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Title Entry", p_command[4], p_command[3]);
break;
case 0x03:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Root Menu", p_command[4], p_command[3]);
break;
case 0x04:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Subpicture Menu", p_command[4], p_command[3]);
break;
case 0x05:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Audio Menu", p_command[4], p_command[3]);
break;
case 0x06:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Angle Menu", p_command[4], p_command[3]);
break;
case 0x07:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) Chapter Menu", p_command[4], p_command[3]);
break;
default:
vlc_debug( l, "JumpSS VTSM (vts %d, ttn %d) <unknown>", p_command[4], p_command[3]);
break;
}
{
uint8_t i_vts = p_command[4];
p_vchapter = vm.BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_vts](const chapter_codec_cmds_c &data) {
return MatchVTSMNumber( data, i_vts ); }, p_vsegment );
if ( p_vsegment != NULL && p_vchapter != NULL )
{
// find the title in the VTS
uint8_t i_title = p_command[3];
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_title](const chapter_codec_cmds_c &data) {
return MatchTitleNumber( data, i_title ); } );
if ( p_vchapter != NULL )
{
// find the specified menu in the VTSM
p_vchapter = p_vsegment->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[p_type](const chapter_codec_cmds_c &data) {
return MatchPgcType( data, p_type ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *p_vsegment, *p_vchapter );
f_result = true;
}
}
else
vlc_debug( l, "Title (%d) does not exist in this VTS", i_title );
}
else
vlc_debug( l, "DVD Domain VTS (%d) not found", i_vts );
}
break;
case 3:
vlc_debug( l, "JumpSS VMGM (pgc %d)", (p_command[2] << 8) + p_command[3]);
break;
}
break;
}
case CMD_DVD_JUMPVTS_PTT:
{
uint8_t i_title = p_command[5];
uint8_t i_ptt = p_command[3];
vlc_debug( l, "JumpVTS Title (%d) PTT (%d)", i_title, i_ptt);
// find the current VTS content segment
p_vchapter = vm.GetCurrentVSegment()->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[](const chapter_codec_cmds_c &data) {
return MatchIsDomain( data); } );
if ( p_vchapter != NULL )
{
int16_t i_curr_title = ( p_vchapter->p_chapter )? p_vchapter->p_chapter->GetTitleNumber() : 0;
if ( i_curr_title > 0 )
{
p_vchapter = vm.BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_curr_title](const chapter_codec_cmds_c &data) {
return MatchVTSNumber( data, i_curr_title ); }, p_vsegment );
if ( p_vsegment != NULL && p_vchapter != NULL )
{
// find the title in the VTS
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_title](const chapter_codec_cmds_c &data) {
return MatchTitleNumber( data, i_title ); } );
if ( p_vchapter != NULL )
{
// find the chapter in the title
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_ptt](const chapter_codec_cmds_c &data) {
return MatchChapterNumber( data, i_ptt ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *p_vsegment, *p_vchapter );
f_result = true;
}
}
else
vlc_debug( l, "Title (%d) does not exist in this VTS", i_title );
}
else
vlc_debug( l, "DVD Domain VTS (%d) not found", i_curr_title );
}
else
vlc_debug( l, "JumpVTS_PTT command found but not in a VTS(M)");
}
else
vlc_debug( l, "JumpVTS_PTT command but the DVD domain wasn't found");
break;
}
case CMD_DVD_SET_GPRMMD:
{
vlc_debug( l, "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] ) )
vlc_debug( l, "Set GPRMMD failed" );
break;
}
case CMD_DVD_LINKPGCN:
{
uint16_t i_pgcn = (p_command[6] << 8) + p_command[7];
vlc_debug( l, "Link PGCN(%d)", i_pgcn );
p_vchapter = vm.GetCurrentVSegment()->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_pgcn](const chapter_codec_cmds_c &data) {
return MatchPgcNumber( data, i_pgcn ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *vm.GetCurrentVSegment(), *p_vchapter );
f_result = true;
}
break;
}
case CMD_DVD_LINKCN:
{
uint8_t i_cn = p_command[7];
p_vchapter = vm.GetCurrentVSegment()->CurrentChapter();
vlc_debug( l, "LinkCN (cell %d)", i_cn );
p_vchapter = p_vchapter->BrowseCodecPrivate( MATROSKA_CHAPTER_CODEC_DVD,
[i_cn](const chapter_codec_cmds_c &data) {
return MatchCellNumber( data, i_cn ); } );
if ( p_vchapter != NULL )
{
vm.JumpTo( *vm.GetCurrentVSegment(), *p_vchapter );
f_result = true;
}
break;
}
case CMD_DVD_GOTO_LINE:
{
vlc_debug( l, "GotoLine (%d)", (p_command[6] << 8) + p_command[7] );
// TODO
break;
}
case CMD_DVD_SET_HL_BTNN1:
{
vlc_debug( l, "SetHL_BTN (%d)", p_command[4] );
SetSPRM( 0x88, p_command[4] );
break;
}
default:
{
vlc_debug( l, "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;
}
void dvd_command_interpretor_c::ProcessNavAction( uint16_t button )
{
const pci_t & pci = pci_packet;
if( button <= 0 || button > pci.hli.hl_gi.btn_ns )
return;
SetSPRM( 0x88, button );
const btni_t & button_ptr = pci.hli.btnit[button-1];
if ( button_ptr.auto_action_mode )
{
// process the button action
Interpret( button_ptr.cmd.bytes, 8 );
}
}
void dvd_command_interpretor_c::HandleKeyEvent( NavivationKey key )
{
const pci_t & pci = pci_packet;
uint16_t i_curr_button = GetSPRM( 0x88 );
if( i_curr_button <= 0 || i_curr_button > pci.hli.hl_gi.btn_ns )
return;
const btni_t & button_ptr = pci.hli.btnit[i_curr_button-1];
switch( key )
{
case LEFT: return ProcessNavAction( button_ptr.left );
case RIGHT: return ProcessNavAction( button_ptr.right );
case UP: return ProcessNavAction( button_ptr.up );
case DOWN: return ProcessNavAction( button_ptr.down );
case OK:
// process the button action
Interpret( button_ptr.cmd.bytes, 8 );
break;
default:
break;
}
}
void dvd_command_interpretor_c::HandleMousePressed( unsigned x, unsigned y )
{
const pci_t & pci = pci_packet;
int32_t button;
int32_t best,dist,d;
int32_t mx,my,dx,dy;
// get current button
best = 0;
dist = 0x08000000; /* >> than (720*720)+(567*567); */
for(button = 1; button <= pci.hli.hl_gi.btn_ns; button++)
{
const btni_t & button_ptr = pci.hli.btnit[button-1];
if((x >= button_ptr.x_start)
&& (x <= button_ptr.x_end)
&& (y >= button_ptr.y_start)
&& (y <= button_ptr.y_end))
{
mx = (button_ptr.x_start + button_ptr.x_end)/2;
my = (button_ptr.y_start + button_ptr.y_end)/2;
dx = mx - x;
dy = my - y;
d = (dx*dx) + (dy*dy);
/* If the mouse is within the button and the mouse is closer
* to the center of this button then it is the best choice. */
if(d < dist) {
dist = d;
best = button;
}
}
}
if ( best == 0)
return;
const btni_t & button_ptr = pci.hli.btnit[best-1];
uint16_t i_curr_button = GetSPRM( 0x88 );
vlc_debug( l, "Clicked button %d", best );
// process the button action
SetSPRM( 0x88, best );
Interpret( button_ptr.cmd.bytes, 8 );
vlc_debug( l, "Processed button %d", best );
// select new button
if ( best != i_curr_button )
{
// TODO: make sure we do not overflow in the conversion
vlc_spu_highlight_t spu_hl = vlc_spu_highlight_t();
spu_hl.x_start = (int)button_ptr.x_start;
spu_hl.y_start = (int)button_ptr.y_start;
spu_hl.x_end = (int)button_ptr.x_end;
spu_hl.y_end = (int)button_ptr.y_end;
uint32_t i_palette;
if(button_ptr.btn_coln != 0) {
i_palette = pci.hli.btn_colit.btn_coli[button_ptr.btn_coln-1][1];
} else {
i_palette = 0;
}
for( int i = 0; i < 4; i++ )
{
uint32_t i_yuv = 0xFF;//p_sys->clut[(hl.palette>>(16+i*4))&0x0f];
uint8_t i_alpha = (i_palette>>(i*4))&0x0f;
i_alpha = i_alpha == 0xf ? 0xff : i_alpha << 4;
spu_hl.palette.palette[i][0] = (i_yuv >> 16) & 0xff;
spu_hl.palette.palette[i][1] = (i_yuv >> 0) & 0xff;
spu_hl.palette.palette[i][2] = (i_yuv >> 8) & 0xff;
spu_hl.palette.palette[i][3] = i_alpha;
}
vm.SetHighlight( spu_hl );
}
}
bool dvd_command_interpretor_c::MatchIsDomain( const chapter_codec_cmds_c &data )
{
return ( data.p_private_data != NULL && data.p_private_data->GetBuffer()[0] == MATROSKA_DVD_LEVEL_SS );
}
bool dvd_command_interpretor_c::MatchIsVMG( const chapter_codec_cmds_c &data )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 2 )
return false;
return ( data.p_private_data->GetBuffer()[0] == MATROSKA_DVD_LEVEL_SS && data.p_private_data->GetBuffer()[1] == 0xC0);
}
bool dvd_command_interpretor_c::MatchVTSNumber( const chapter_codec_cmds_c &data, uint16_t i_title )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_SS || data.p_private_data->GetBuffer()[1] != 0x80 )
return false;
uint16_t i_gtitle = (data.p_private_data->GetBuffer()[2] << 8 ) + data.p_private_data->GetBuffer()[3];
return (i_gtitle == i_title);
}
bool dvd_command_interpretor_c::MatchVTSMNumber( const chapter_codec_cmds_c &data, uint8_t i_title )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_SS || data.p_private_data->GetBuffer()[1] != 0x40 )
return false;
uint8_t i_gtitle = data.p_private_data->GetBuffer()[3];
return (i_gtitle == i_title);
}
bool dvd_command_interpretor_c::MatchTitleNumber( const chapter_codec_cmds_c &data, uint8_t i_title )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_TT )
return false;
uint16_t i_gtitle = (data.p_private_data->GetBuffer()[1] << 8 ) + data.p_private_data->GetBuffer()[2];
return (i_gtitle == i_title);
}
bool dvd_command_interpretor_c::MatchPgcType( const chapter_codec_cmds_c &data, uint8_t i_pgc )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 8 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PGC )
return false;
uint8_t i_pgc_type = data.p_private_data->GetBuffer()[3] & 0x0F;
return (i_pgc_type == i_pgc);
}
bool dvd_command_interpretor_c::MatchPgcNumber( const chapter_codec_cmds_c &data, uint16_t i_pgc_n )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 8 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PGC )
return false;
uint16_t i_pgc_num = (data.p_private_data->GetBuffer()[1] << 8) + data.p_private_data->GetBuffer()[2];
return (i_pgc_num == i_pgc_n);
}
bool dvd_command_interpretor_c::MatchChapterNumber( const chapter_codec_cmds_c &data, uint8_t i_ptt )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 2 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PTT )
return false;
uint8_t i_chapter = data.p_private_data->GetBuffer()[1];
return (i_chapter == i_ptt);
}
bool dvd_command_interpretor_c::MatchCellNumber( const chapter_codec_cmds_c &data, uint8_t i_cell_n )
{
if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 5 )
return false;
if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_CN )
return false;
uint8_t i_cell_num = data.p_private_data->GetBuffer()[3];
return (i_cell_num == i_cell_n);
}
void dvd_command_interpretor_c::SetPci(const uint8_t *data, unsigned size)
{
if (size < sizeof(pci_packet))
return;
memcpy(&pci_packet, data, sizeof(pci_packet));
#ifndef WORDS_BIGENDIAN
for( uint8_t button = 1; button <= pci_packet.hli.hl_gi.btn_ns &&
button < ARRAY_SIZE(pci_packet.hli.btnit); button++) {
btni_t & button_ptr = pci_packet.hli.btnit[button-1];
binary *p_data = (binary*) &button_ptr;
uint16_t i_x_start = ((p_data[0] & 0x3F) << 4 ) + ( p_data[1] >> 4 );
uint16_t i_x_end = ((p_data[1] & 0x03) << 8 ) + p_data[2];
uint16_t i_y_start = ((p_data[3] & 0x3F) << 4 ) + ( p_data[4] >> 4 );
uint16_t 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 ( uint8_t i = 0; i<3; i++ )
for ( uint8_t 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
}
} // namespace
// Copyright (C) 2003-2024 VLC authors and VideoLAN
// SPDX-License-Identifier: LGPL-2.1-or-later
//
// chapter_command_dvd.hpp : DVD codec for Matroska Chapter Codecs
// Authors: Laurent Aimar <fenrir@via.ecp.fr>
// Steve Lhomme <steve.lhomme@free.fr>
#ifndef VLC_MKV_CHAPTER_COMMAND_DVD_HPP_
#define VLC_MKV_CHAPTER_COMMAND_DVD_HPP_
#include "chapter_command.hpp"
#include "dvd_types.hpp"
namespace mkv {
class dvd_command_interpretor_c
{
public:
dvd_command_interpretor_c( struct vlc_logger *log, chapter_codec_vm & vm_ )
:l( log )
,vm( vm_ )
{
memset( p_PRMs, 0, sizeof(p_PRMs) );
p_PRMs[ 0x80 + 1 ] = 15;
p_PRMs[ 0x80 + 2 ] = 62;
p_PRMs[ 0x80 + 3 ] = 1;
p_PRMs[ 0x80 + 4 ] = 1;
p_PRMs[ 0x80 + 7 ] = 1;
p_PRMs[ 0x80 + 8 ] = 1;
p_PRMs[ 0x80 + 16 ] = 0xFFFFu;
p_PRMs[ 0x80 + 18 ] = 0xFFFFu;
}
bool Interpret( const binary * p_command, size_t i_size = 8 );
void HandleKeyEvent( NavivationKey );
void HandleMousePressed( unsigned x, unsigned y );
void SetPci(const uint8_t *, unsigned size);
protected:
uint16_t GetPRM( size_t index ) const
{
if ( index < 256 )
return p_PRMs[ index ];
else return 0;
}
uint16_t GetGPRM( size_t index ) const
{
if ( index < 16 )
return p_PRMs[ index ];
else return 0;
}
uint16_t GetSPRM( size_t index ) const
{
// 21,22,23 reserved for future use
if ( index >= 0x80 && index < 0x95 )
return p_PRMs[ index ];
else return 0;
}
bool SetPRM( size_t index, uint16_t value )
{
if ( index < 16 )
{
p_PRMs[ index ] = value;
return true;
}
return false;
}
bool SetGPRM( size_t index, uint16_t value )
{
if ( index < 16 )
{
p_PRMs[ index ] = value;
return true;
}
return false;
}
bool SetSPRM( size_t index, uint16_t value )
{
if ( index > 0x80 && index <= 0x8D && index != 0x8C )
{
p_PRMs[ index ] = value;
return true;
}
return false;
}
void ProcessNavAction( uint16_t button );
std::string GetRegTypeName( bool b_value, uint16_t value ) const
{
std::string result;
char s_value[6], s_reg_value[6];
snprintf( s_value, ARRAY_SIZE(s_value), "%.5d", value );
if ( b_value )
{
result = "value (";
result += s_value;
result += ")";
}
else if ( value < 0x80 )
{
snprintf( s_reg_value, ARRAY_SIZE(s_reg_value), "%.5d", GetPRM( value ) );
result = "GPreg[";
result += s_value;
result += "] (";
result += s_reg_value;
result += ")";
}
else
{
snprintf( s_reg_value, ARRAY_SIZE(s_reg_value), "%.5d", GetPRM( value ) );
result = "SPreg[";
result += s_value;
result += "] (";
result += s_reg_value;
result += ")";
}
return result;
}
uint16_t p_PRMs[256];
struct vlc_logger *l;
chapter_codec_vm & vm;
pci_t pci_packet = {};
// DVD command IDs
// Tests
// whether it's a comparison on the value or register
static const uint16_t CMD_DVD_TEST_VALUE = 0x80;
static const uint16_t CMD_DVD_IF_GPREG_AND = (1 << 4);
static const uint16_t CMD_DVD_IF_GPREG_EQUAL = (2 << 4);
static const uint16_t CMD_DVD_IF_GPREG_NOT_EQUAL = (3 << 4);
static const uint16_t CMD_DVD_IF_GPREG_SUP_EQUAL = (4 << 4);
static const uint16_t CMD_DVD_IF_GPREG_SUP = (5 << 4);
static const uint16_t CMD_DVD_IF_GPREG_INF_EQUAL = (6 << 4);
static const uint16_t CMD_DVD_IF_GPREG_INF = (7 << 4);
static const uint16_t CMD_DVD_NOP = 0x0000;
static const uint16_t CMD_DVD_GOTO_LINE = 0x0001;
static const uint16_t CMD_DVD_BREAK = 0x0002;
// Links
static const uint16_t CMD_DVD_NOP2 = 0x2001;
static const uint16_t CMD_DVD_LINKPGCN = 0x2004;
static const uint16_t CMD_DVD_LINKPGN = 0x2006;
static const uint16_t CMD_DVD_LINKCN = 0x2007;
static const uint16_t CMD_DVD_JUMP_TT = 0x3002;
static const uint16_t CMD_DVD_JUMPVTS_TT = 0x3003;
static const uint16_t CMD_DVD_JUMPVTS_PTT = 0x3005;
static const uint16_t CMD_DVD_JUMP_SS = 0x3006;
static const uint16_t CMD_DVD_CALLSS_VTSM1 = 0x3008;
//
static const uint16_t CMD_DVD_SET_HL_BTNN2 = 0x4600;
static const uint16_t CMD_DVD_SET_HL_BTNN_LINKPGCN1 = 0x4604;
static const uint16_t CMD_DVD_SET_STREAM = 0x5100;
static const uint16_t CMD_DVD_SET_GPRMMD = 0x5300;
static const uint16_t CMD_DVD_SET_HL_BTNN1 = 0x5600;
static const uint16_t CMD_DVD_SET_HL_BTNN_LINKPGCN2 = 0x5604;
static const uint16_t CMD_DVD_SET_HL_BTNN_LINKCN = 0x5607;
// Operations
static const uint16_t CMD_DVD_MOV_SPREG_PREG = 0x6100;
static const uint16_t CMD_DVD_GPREG_MOV_VALUE = 0x7100;
static const uint16_t CMD_DVD_SUB_GPREG = 0x7400;
static const uint16_t CMD_DVD_MULT_GPREG = 0x7500;
static const uint16_t CMD_DVD_GPREG_DIV_VALUE = 0x7600;
static const uint16_t CMD_DVD_GPREG_AND_VALUE = 0x7900;
// callbacks when browsing inside CodecPrivate
static bool MatchIsDomain ( const chapter_codec_cmds_c & );
static bool MatchIsVMG ( const chapter_codec_cmds_c & );
static bool MatchVTSNumber ( const chapter_codec_cmds_c &, uint16_t i_title );
static bool MatchVTSMNumber ( const chapter_codec_cmds_c &, uint8_t i_title );
static bool MatchTitleNumber ( const chapter_codec_cmds_c &, uint8_t i_title );
static bool MatchPgcType ( const chapter_codec_cmds_c &, uint8_t i_pgc );
static bool MatchPgcNumber ( const chapter_codec_cmds_c &, uint16_t i_pgc_n );
static bool MatchChapterNumber( const chapter_codec_cmds_c &, uint8_t i_ptt );
static bool MatchCellNumber ( const chapter_codec_cmds_c &, uint8_t i_cell_n );
};
class dvd_chapter_codec_c : public chapter_codec_cmds_c
{
public:
dvd_chapter_codec_c( struct vlc_logger *log, chapter_codec_vm & vm_, dvd_command_interpretor_c & intepretor_ )
:chapter_codec_cmds_c( log, vm_, MATROSKA_CHAPTER_CODEC_DVD )
,intepretor(intepretor_)
{}
bool Enter() override;
bool Leave() override;
std::string GetCodecName( bool f_for_title = false ) const override;
int16_t GetTitleNumber() const override;
protected:
bool EnterLeaveHelper( char const*, std::vector<KaxChapterProcessData*>* );
dvd_command_interpretor_c & intepretor;
};
} // namespace
#endif // VLC_MKV_CHAPTER_COMMAND_DVD_HPP_
// Copyright (C) 2003-2024 VLC authors and VideoLAN
// SPDX-License-Identifier: LGPL-2.1-or-later
//
// chapter_command_script.cpp : DVD codec for Matroska Chapter Codecs
// Authors: Laurent Aimar <fenrir@via.ecp.fr>
// Steve Lhomme <steve.lhomme@free.fr>
#include "chapter_command_script.hpp"
#include "virtual_segment.hpp"
namespace mkv {
const std::string matroska_script_interpretor_c::CMD_MS_GOTO_AND_PLAY = "GotoAndPlay";
// 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;
std::string sz_command( reinterpret_cast<const char*> (p_command), i_size );
vlc_debug( l, "command : %s", sz_command.c_str() );
if ( sz_command.compare( 0, CMD_MS_GOTO_AND_PLAY.size(), CMD_MS_GOTO_AND_PLAY ) == 0 )
{
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 );
chapter_uid i_chapter_uid = std::stoul( st );
virtual_segment_c *p_vsegment;
virtual_chapter_c *p_vchapter = vm.FindVChapter( i_chapter_uid, p_vsegment );
if ( p_vchapter == NULL )
vlc_debug( l, "Chapter %" PRId64 " not found", i_chapter_uid);
else
{
if ( !p_vchapter->EnterAndLeave( vm.GetCurrentVSegment()->CurrentChapter(), false ) )
vm.JumpTo( *p_vsegment, *p_vchapter );
b_result = true;
}
}
return b_result;
}
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() )
{
vlc_debug( l, "Matroska Script enter command" );
f_result |= interpreter.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() )
{
vlc_debug( l, "Matroska Script leave command" );
f_result |= interpreter.Interpret( (*index)->GetBuffer(), (*index)->GetSize() );
}
++index;
}
return f_result;
}
} // namespace
// Copyright (C) 2003-2024 VLC authors and VideoLAN
// SPDX-License-Identifier: LGPL-2.1-or-later
//
// chapter_command_script.hpp : MatroskaScript codec for Matroska Chapter Codecs
// Authors: Laurent Aimar <fenrir@via.ecp.fr>
// Steve Lhomme <steve.lhomme@free.fr>
#ifndef VLC_MKV_CHAPTER_COMMAND_SCRIPT_HPP_
#define VLC_MKV_CHAPTER_COMMAND_SCRIPT_HPP_
#include "chapter_command.hpp"
namespace mkv {
class matroska_script_interpretor_c
{
public:
matroska_script_interpretor_c( struct vlc_logger *log, chapter_codec_vm & vm_ )
:l( log )
,vm( vm_ )
{}
bool Interpret( const binary * p_command, size_t i_size );
// DVD command IDs
static const std::string CMD_MS_GOTO_AND_PLAY;
protected:
struct vlc_logger *l;
chapter_codec_vm & vm;
};
class matroska_script_codec_c : public chapter_codec_cmds_c
{
public:
matroska_script_codec_c( struct vlc_logger *log, chapter_codec_vm & vm_ )
:chapter_codec_cmds_c( log, vm_, MATROSKA_CHAPTER_CODEC_NATIVE )
,interpreter( log, vm_ )
{}
bool Enter();
bool Leave();
protected:
matroska_script_interpretor_c interpreter;
};
} // namespace
#endif // VLC_MKV_CHAPTER_COMMAND_SCRIPT_HPP_
......@@ -25,6 +25,8 @@
#include "chapter_command.hpp"
#include <vlc_arrays.h>
#include <functional>
#include <algorithm>
......
......@@ -25,6 +25,7 @@
#include "demux.hpp"
#include "stream_io_callback.hpp"
#include "Ebml_parser.hpp"
#include "virtual_segment.hpp"
#include <vlc_actions.h>
......
......@@ -27,8 +27,7 @@
#include "mkv.hpp"
#include "chapter_command.hpp"
#include "virtual_segment.hpp"
#include "dvd_types.hpp"
#include "chapter_command_dvd.hpp"
#include "events.hpp"
#include <memory>
......
......@@ -24,6 +24,8 @@
#ifndef VLC_MKV_DVD_TYPES_HPP
#define VLC_MKV_DVD_TYPES_HPP
#include <cstdint>
namespace mkv {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#undef ATTRIBUTE_PACKED
......@@ -273,7 +275,7 @@ typedef struct {
/**
* PCI packet
*/
typedef struct {
typedef struct pci_t {
pci_gi_t pci_gi;
nsml_agli_t nsml_agli;
hli_t hli;
......
......@@ -24,6 +24,7 @@
#include "mkv.hpp"
#include "demux.hpp"
#include "events.hpp"
#include "chapter_command_dvd.hpp"
#include <vlc_actions.h>
#include <vlc_threads.h>
......@@ -40,52 +41,77 @@ event_thread_t::event_thread_t(demux_t *p_demux) : p_demux(p_demux)
}
event_thread_t::~event_thread_t()
{
ResetPci();
AbortThread();
}
void event_thread_t::SetPci(const pci_t *data)
void event_thread_t::SendData( mkv_track_t &track, block_t * p_block )
{
demux_sys_t* p_sys = (demux_sys_t*)p_demux->p_sys;
vlc_mutex_locker l(&lock);
if ( track.codec == "B_VOBBTN")
{
if( p_block->i_size > 0)
{
demux_sys_t* p_sys = (demux_sys_t*)p_demux->p_sys;
vlc_mutex_locker l(&lock);
if(es_list.empty())
return;
if(es_list.empty())
return;
auto interpretor = p_sys->GetDVDInterpretor();
if (!interpretor)
return;
auto interpretor = p_sys->GetDVDInterpretor();
if (!interpretor)
return;
interpretor->SetPci( data );
if( !is_running )
{
b_abort = false;
is_running = !vlc_clone( &thread, EventThread, this );
interpretor->SetPci( &p_block->p_buffer[1], p_block->i_size - 1 );
EnsureThreadLocked();
}
}
block_Release( p_block );
}
void event_thread_t::ResetPci()
void event_thread_t::EnsureThreadLocked()
{
if (is_running || b_abort)
return;
is_running = !vlc_clone( &thread, EventThread, this );
}
void event_thread_t::AbortThread()
{
if( !is_running )
return;
vlc_mutex_lock( &lock );
b_abort = true;
vlc_cond_signal( &wait );
vlc_mutex_unlock( &lock );
{
vlc_mutex_locker lock_guard(&lock);
b_abort = true;
vlc_cond_signal( &wait );
}
vlc_join( thread, NULL );
is_running = false;
}
int event_thread_t::SendEventNav( int nav_query )
int event_thread_t::SendEventNav( demux_query_e nav_query )
{
NavivationKey key;
switch( nav_query )
{
case DEMUX_NAV_LEFT: key = NavivationKey::LEFT; break;
case DEMUX_NAV_RIGHT: key = NavivationKey::RIGHT; break;
case DEMUX_NAV_UP: key = NavivationKey::UP; break;
case DEMUX_NAV_DOWN: key = NavivationKey::DOWN; break;
case DEMUX_NAV_ACTIVATE: key = NavivationKey::OK; break;
case DEMUX_NAV_MENU: key = NavivationKey::MENU; break;
case DEMUX_NAV_POPUP: key = NavivationKey::POPUP; break;
default:
assert(false); // invalid navigation query received
return VLC_ENOTSUP;
}
if( !is_running )
return VLC_EGENERIC;
vlc_mutex_locker lock_guard( &lock );
pending_events.push_back( EventInfo( nav_query ) );
vlc_cond_signal( &wait );
QueueEvent( EventInfo{ key } );
return VLC_SUCCESS;
}
......@@ -93,15 +119,11 @@ int event_thread_t::SendEventNav( int nav_query )
void event_thread_t::EventMouse( vlc_mouse_t const* new_state, void* userdata )
{
ESInfo* info = static_cast<ESInfo*>( userdata );
vlc_mutex_locker lock_guard( &info->owner.lock );
if( !new_state )
return vlc_mouse_Init( &info->mouse_state );
info->owner.pending_events.push_back(
EventInfo( info, info->mouse_state, *new_state ) );
vlc_cond_signal( &info->owner.wait );
info->owner.QueueEvent( EventInfo{ info->mouse_state, *new_state } );
info->mouse_state = *new_state;
}
......@@ -121,8 +143,10 @@ void event_thread_t::EventThread()
while( !pending_events.empty() )
{
EventInfo const& ev = pending_events.front();
const EventInfo ev = pending_events.front();
pending_events.pop_front();
vlc_mutex_unlock( &lock );
switch( ev.type )
{
case EventInfo::ESMouseEvent:
......@@ -133,8 +157,7 @@ void event_thread_t::EventThread()
HandleKeyEvent( ev );
break;
}
pending_events.pop_front();
vlc_mutex_lock( &lock );
}
}
......@@ -151,20 +174,7 @@ void event_thread_t::HandleKeyEvent( EventInfo const& ev )
{
msg_Dbg( p_demux, "Handle Key Event");
NavivationKey key;
switch( ev.nav.query )
{
case DEMUX_NAV_LEFT: key = NavivationKey::LEFT;
case DEMUX_NAV_RIGHT: key = NavivationKey::RIGHT;
case DEMUX_NAV_UP: key = NavivationKey::UP;
case DEMUX_NAV_DOWN: key = NavivationKey::DOWN;
case DEMUX_NAV_ACTIVATE: key = NavivationKey::OK;
case DEMUX_NAV_MENU: key = NavivationKey::MENU;
case DEMUX_NAV_POPUP: key = NavivationKey::POPUP;
default: return;
}
HandleKeyEvent( key );
HandleKeyEvent( ev.nav.key );
}
void event_thread_t::HandleKeyEvent( NavivationKey key )
......@@ -175,14 +185,10 @@ void event_thread_t::HandleKeyEvent( NavivationKey key )
if (!interpretor)
return;
vlc_mutex_unlock( &lock );
vlc_mutex_lock( &p_sys->lock_demuxer );
vlc_mutex_locker demux_lock ( &p_sys->lock_demuxer );
// process the button action
interpretor->HandleKeyEvent( key );
vlc_mutex_unlock( &p_sys->lock_demuxer );
vlc_mutex_lock( &lock );
}
void event_thread_t::HandleMouseEvent( EventInfo const& event )
......@@ -211,11 +217,9 @@ void event_thread_t::HandleMousePressed( unsigned x, unsigned y )
msg_Dbg( p_demux, "Handle Mouse Event: Mouse clicked x(%d)*y(%d)", x, y);
vlc_mutex_unlock( &lock );
vlc_mutex_lock( &p_sys->lock_demuxer );
vlc_mutex_locker demux_lock ( &p_sys->lock_demuxer );
interpretor->HandleMousePressed( x, y );
vlc_mutex_unlock( &p_sys->lock_demuxer );
vlc_mutex_lock( &lock );
}
void event_thread_t::SetHighlight( vlc_spu_highlight_t & spu_hl )
......@@ -223,24 +227,28 @@ void event_thread_t::SetHighlight( vlc_spu_highlight_t & spu_hl )
/* TODO: only control relevant SPU_ES given who fired the event */
for( auto it : es_list )
{
if( it.category != SPU_ES )
if( it.track.fmt.i_cat != SPU_ES )
continue;
es_out_Control( p_demux->out, ES_OUT_SPU_SET_HIGHLIGHT, it.es, &spu_hl );
es_out_Control( p_demux->out, ES_OUT_SPU_SET_HIGHLIGHT, it.track.p_es, &spu_hl );
}
}
bool event_thread_t::AddES( es_out_id_t* es, int category )
bool event_thread_t::AddTrack( mkv_track_t & track )
{
es_out_id_t* es = track.p_es;
int category = track.fmt.i_cat;
vlc_mutex_locker lock_guard( &lock );
es_list.push_front( ESInfo( es, category, *this ) );
es_list.push_front( ESInfo( track, *this ) );
es_list_t::iterator info = es_list.begin();
if( category == VIDEO_ES )
{
if( es_out_Control( p_demux->out, ES_OUT_VOUT_SET_MOUSE_EVENT,
es, EventMouse, static_cast<void*>( &*info ) ) )
es, static_cast<vlc_mouse_event>(EventMouse),
static_cast<void*>( &*info ) ) )
{
msg_Warn( p_demux, "Unable to subscribe to mouse events" );
es_list.erase( info );
......@@ -250,10 +258,10 @@ bool event_thread_t::AddES( es_out_id_t* es, int category )
return true;
}
void event_thread_t::DelES( es_out_id_t* es )
void event_thread_t::DelTrack( mkv_track_t &track )
{
vlc_mutex_locker lock_guard( &lock );
es_list_t::iterator info = std::find( es_list.begin(), es_list.end(), es );
es_list_t::iterator info = std::find( es_list.begin(), es_list.end(), track );
if( info != es_list.end() )
es_list.erase( info );
}
......
......@@ -29,15 +29,13 @@
#include <vlc_actions.h>
#include <vlc_mouse.h>
#include "dvd_types.hpp"
#include <list>
struct vlc_spu_highlight_t;
namespace mkv {
struct demux_sys_t;
struct p_block;
class event_thread_t
{
......@@ -45,30 +43,28 @@ public:
event_thread_t(demux_t *);
virtual ~event_thread_t();
void SetPci(const pci_t *data);
void ResetPci();
int SendEventNav( int );
void SendData( mkv_track_t &, block_t * );
void AbortThread();
int SendEventNav( demux_query_e );
void SetHighlight( vlc_spu_highlight_t & spu_hl );
bool AddES( es_out_id_t* es, int category );
void DelES( es_out_id_t* es );
bool AddTrack( mkv_track_t & );
void DelTrack( mkv_track_t & );
private:
struct ESInfo {
ESInfo( es_out_id_t* es, int category, event_thread_t& owner )
: es( es )
, category( category )
ESInfo( mkv_track_t & track_, event_thread_t& owner )
: track( track_ )
, owner( owner )
{
vlc_mouse_Init( &mouse_state );
}
bool operator==( es_out_id_t* es ) const {
return this->es == es;
bool operator==( const mkv_track_t & t ) const {
return track.p_es == t.p_es;
}
es_out_id_t* es;
int category;
mkv_track_t & track;
event_thread_t& owner;
vlc_mouse_t mouse_state;
};
......@@ -79,35 +75,33 @@ private:
ActionEvent,
} type;
EventInfo( ESInfo* info, vlc_mouse_t state_old, vlc_mouse_t state_new )
EventInfo( const vlc_mouse_t & state_old, const vlc_mouse_t & state_new )
: type( ESMouseEvent )
, mouse{ state_old, state_new }
{
mouse.es_info = info;
mouse.state_old = state_old;
mouse.state_new = state_new;
}
EventInfo( int query )
EventInfo( NavivationKey key )
: type( ActionEvent )
, nav{ key }
{
nav.query = query;
}
union {
struct {
ESInfo* es_info;
vlc_mouse_t state_old;
vlc_mouse_t state_new;
const vlc_mouse_t state_old;
const vlc_mouse_t state_new;
} mouse;
struct {
int query;
const NavivationKey key;
} nav;
};
};
void EventThread();
static void *EventThread(void *);
void EnsureThreadLocked();
static void EventMouse( vlc_mouse_t const* state, void* userdata );
......@@ -121,15 +115,24 @@ private:
vlc_mutex_t lock;
vlc_cond_t wait;
bool b_abort;
bool b_abort = false;
typedef std::list<ESInfo> es_list_t;
es_list_t es_list;
es_list_t es_list; //protected by "lock"
typedef std::list<EventInfo> pending_events_t;
pending_events_t pending_events;
pending_events_t pending_events; // protected by "lock"
void QueueEvent(const EventInfo e)
{
vlc_mutex_locker lock_guard( &lock );
EnsureThreadLocked();
pending_events.push_back( e );
vlc_cond_signal( &wait );
}
private:
void HandleKeyEvent( NavivationKey key );
void HandleMousePressed( unsigned x, unsigned y );
};
......
......@@ -27,6 +27,8 @@
#include "util.hpp"
#include "Ebml_dispatcher.hpp"
#include <vlc_arrays.h>
#include <new>
#include <iterator>
#include <limits>
......@@ -1132,7 +1134,7 @@ bool matroska_segment_c::ESCreate()
track.p_es = es_out_Add( sys.demuxer.out, &track.fmt );
if( track.p_es &&
!sys.ev.AddES( track.p_es, track.fmt.i_cat ) )
!sys.ev.AddTrack( track ) )
{
msg_Warn( &sys.demuxer, "Could not register events, interactive menus will not work");
}
......@@ -1162,7 +1164,7 @@ bool matroska_segment_c::ESCreate()
void matroska_segment_c::ESDestroy( )
{
sys.ev.ResetPci();
sys.ev.AbortThread();
for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
{
......@@ -1171,7 +1173,7 @@ void matroska_segment_c::ESDestroy( )
if( track.p_es != NULL )
{
es_out_Del( sys.demuxer.out, track.p_es );
sys.ev.DelES( track.p_es );
sys.ev.DelTrack( track );
track.p_es = NULL;
}
}
......
......@@ -28,6 +28,7 @@
#include "Ebml_dispatcher.hpp"
#include "string_dispatcher.hpp"
#include "util.hpp"
#include "chapter_command_script.hpp"
extern "C" {
#include "../vobsub.h"
......
......@@ -26,7 +26,7 @@
#include "matroska_segment.hpp"
#include "demux.hpp"
#include "virtual_segment.hpp"
#include "chapters.hpp"
#include "Ebml_parser.hpp"
......@@ -483,7 +483,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
case DEMUX_NAV_RIGHT:
case DEMUX_NAV_POPUP:
case DEMUX_NAV_MENU:
return p_sys->ev.SendEventNav( i_query );
return p_sys->ev.SendEventNav( static_cast<demux_query_e>(i_query) );
case DEMUX_CAN_PAUSE:
case DEMUX_SET_PAUSE_STATE:
......@@ -753,9 +753,7 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
if ( track.fmt.i_cat == DATA_ES )
{
// TODO handle the start/stop times of this packet
if( p_block->i_size >= sizeof(pci_t))
p_sys->ev.SetPci( (const pci_t *)&p_block->p_buffer[1]);
block_Release( p_block );
p_sys->ev.SendData( track, p_block );
return;
}
p_block->i_dts = p_block->i_pts = i_pts;
......
......@@ -23,6 +23,7 @@
#include "mkv.hpp"
#include "util.hpp"
#include "demux.hpp"
#include "virtual_segment.hpp"
#include "../../codec/webvtt/helpers.h"
namespace mkv {
......
......@@ -21,10 +21,10 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include <vector>
#include <new>
#include "demux.hpp"
#include "virtual_segment.hpp"
#include <new>
namespace mkv {
......