Initial commit of DVD emulator sources.

This commit is contained in:
DragonMinded 2016-01-29 03:58:07 +00:00
commit 93cc758fa9
11 changed files with 1152 additions and 0 deletions

237
DVDEmu.cpp Normal file
View File

@ -0,0 +1,237 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "DVDEmu.h"
#include "Serial.h"
#include "Video.h"
#include "Victor_XV-D701.h"
#include "Toshiba_SD-B100.h"
#define VERBOSE_DEBUG 1
int getDirectoryCount( const char * const directory )
{
int file_count = 0;
DIR * dirp;
struct dirent * entry;
dirp = opendir(directory);
while ((entry = readdir(dirp)) != NULL)
{
if (entry->d_type == DT_REG)
{
file_count++;
}
}
closedir(dirp);
return file_count;
}
int getDvdType( const char * const directory )
{
char file[256];
FILE *fp;
int type = DVD_TYPE_UNKNOWN;
sprintf(file, "%sdisc.cfg", directory);
fp = fopen( file, "r" );
if( fp )
{
char value[128];
fscanf(fp, "%s", value);
if( strcmp( value, "XV-D701-VCD" ) == 0 )
{
type = DVD_TYPE_VICTOR_XV_D701_VCD;
}
else if( strcmp( value, "XV-D701-DVD" ) == 0 )
{
type = DVD_TYPE_VICTOR_XV_D701_DVD;
}
else if( strcmp( value, "SD-B100-DVD" ) == 0 )
{
type = DVD_TYPE_TOSHIBA_SD_B100_DVD;
}
fclose( fp );
}
return type;
}
void verbose_printf( const char * const fmt, ... )
{
if( VERBOSE_DEBUG )
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
}
void exec_shell( const char * shellcmd )
{
if( fork() == 0 )
{
execl("/bin/bash","/bin/bash","-c",shellcmd,NULL);
}
else
{
int status;
wait(&status);
}
}
void PrintHex( const char * prepend, const unsigned char * const data, int length )
{
if( prepend )
{
printf( "%s", prepend );
}
for( int x = 0; x < length; x++ )
{
printf( "%02X ", data[x] );
}
printf( " (Length: %d bytes)\n", length );
}
void PrintInstructions( char * name )
{
fprintf( stderr, "\n" );
fprintf( stderr, "%s port folder\n", name );
fprintf( stderr, "\tport - a com port, such as COM1.\n" );
fprintf( stderr, "\tfolder - a folder of M4Vs, such as /home/root/dvd/. Must end in \"/\".\n" );
}
int main( int argc, char *argv[] )
{
/* Ensure command is good */
if( argc < 2 )
{
fprintf( stderr, "Missing serial port argument!\n" );
PrintInstructions( argv[0] );
return 1;
}
if( argc < 3 )
{
fprintf( stderr, "Missing m4v folder!\n" );
PrintInstructions( argv[0] );
return 1;
}
/* Attempt to ascertain the type */
int dvd_type = getDvdType( argv[2] );
if( dvd_type == DVD_TYPE_UNKNOWN )
{
fprintf( stderr, "Couldn't get DVD information. Be sure your DVD directory has a disc.cfg specifying the type!\n" );
return 1;
}
/* Set up DVD player serial */
int serial;
if( dvd_type == DVD_TYPE_VICTOR_XV_D701_VCD || dvd_type == DVD_TYPE_VICTOR_XV_D701_DVD )
{
serial = OpenSerial( argv[1], 9600, PARITY_EVEN );
}
else if( dvd_type == DVD_TYPE_TOSHIBA_SD_B100_DVD )
{
serial = OpenSerial( argv[1], 9600, PARITY_NONE );
}
else
{
fprintf( stderr, "Unknown DVD type, can't init!\n" );
return 1;
}
if( serial < 0 )
{
fprintf( stderr, "Failed to open serial port '%s'!\n", argv[1] );
return 1;
}
/* Ensure we start fresh */
PurgeComm( serial );
/* Set up defaults, making sure not to include the type file */
VideoInit( argv[2], getDirectoryCount(argv[2]) - 1 );
/* Set up DVD emulator */
if( dvd_type == DVD_TYPE_VICTOR_XV_D701_VCD )
{
VictorInit( VICTOR_VCD );
}
else if( dvd_type == DVD_TYPE_VICTOR_XV_D701_DVD )
{
VictorInit( VICTOR_DVD );
}
else if( dvd_type == DVD_TYPE_TOSHIBA_SD_B100_DVD )
{
ToshibaInit();
}
while( 1 )
{
/* Since JLIP has a start of message and a checksum, as well as the
* start of message can't be a mistake given that the top bit is set
* and no command or argument uses the top bit, we can simply feed
* every byte we get into a small buffer and attempt to handle it as
* a packet.
*/
unsigned char byte;
if( ReadSerial( serial, &byte, 1 ) == 1 )
{
/* Got one */
int response;
if( dvd_type == DVD_TYPE_VICTOR_XV_D701_VCD || dvd_type == DVD_TYPE_VICTOR_XV_D701_DVD )
{
response = VictorReceiveByte( byte );
}
else if( dvd_type == DVD_TYPE_TOSHIBA_SD_B100_DVD )
{
response = ToshibaReceiveByte( byte );
}
if( response )
{
int length = 0;
unsigned char *packet = NULL;
if( dvd_type == DVD_TYPE_VICTOR_XV_D701_VCD || dvd_type == DVD_TYPE_VICTOR_XV_D701_DVD )
{
packet = VictorGetResponse( &length );
}
else if( dvd_type == DVD_TYPE_TOSHIBA_SD_B100_DVD )
{
packet = ToshibaGetResponse( &length );
}
if( packet && length > 0 )
{
WriteSerial( serial, packet, length );
}
}
}
}
/* Close the connection */
CloseSerial( serial );
return 0;
}

17
DVDEmu.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef __DVDEMU_H
#define __DVDEMU_H
// The disc type is unknown
#define DVD_TYPE_UNKNOWN 0
// The DVD player is emulating a Victor XV-D701 VCD
#define DVD_TYPE_VICTOR_XV_D701_VCD 1
// The DVD player is emulating a Victor XV-D701 DVD
#define DVD_TYPE_VICTOR_XV_D701_DVD 2
// The DVD player is emulating a Toshiba SD-B100
#define DVD_TYPE_TOSHIBA_SD_B100_DVD 3
void verbose_printf( const char * const fmt, ... );
void exec_shell( const char * shellcmd );
void PrintHex( const char * prepend, const unsigned char * const data, int length );
#endif

9
Makefile Normal file
View File

@ -0,0 +1,9 @@
all: dvdemu
dvdemu: DVDEmu.cpp
g++ -Wall -Werror -D_BSD_SOURCE -o dvdemu DVDEmu.cpp Serial.cpp Video.cpp Toshiba_SD-B100.cpp Victor_XV-D701.cpp -ggdb
.DUMMY: clean
clean:
rm -rf dvdemu

182
Serial.cpp Normal file
View File

@ -0,0 +1,182 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <dirent.h>
#include "Serial.h"
/* Blocking wait time */
#define WAIT_TIME 1000
int OpenSerial( const char *port, int baud, int parity )
{
int rate;
switch( baud )
{
case 9600:
rate = B9600;
break;
case 19200:
rate = B19200;
break;
case 38400:
rate = B38400;
break;
case 57600:
rate = B57600;
break;
case 115200:
rate = B115200;
break;
default:
/* Invalid baud rate */
return -1;
}
struct termios tio;
int hSerial = 0;
memset(&tio,0,sizeof(tio));
tio.c_iflag=0;
tio.c_oflag=0;
tio.c_cflag=CS8|CREAD|PARENB|CLOCAL;
tio.c_lflag=0;
tio.c_cc[VMIN]=1;
tio.c_cc[VTIME]=0;
hSerial=open(port, O_RDWR | O_NONBLOCK);
if( hSerial < 0 ) { return -1; }
cfsetospeed(&tio,rate);
cfsetispeed(&tio,rate);
tcsetattr(hSerial,TCSANOW,&tio);
return hSerial;
}
uint64_t getMS()
{
struct timeval tv;
gettimeofday(&tv, NULL );
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}
bool ReadFile ( int file, void *buf, uint32_t length, uint32_t *readAmt, void *reserved )
{
uint64_t start = getMS();
*readAmt = 0;
while( true )
{
int amount = read( file, buf, length );
if( amount < 0 )
{
if( errno == EAGAIN || errno == EWOULDBLOCK )
{
if( (getMS() - start) > WAIT_TIME )
{
return false;
}
/* Try again */
continue;
}
return false;
}
*readAmt = amount;
return true;
}
}
bool WriteFile( int file, const void * const buf, uint32_t length, uint32_t *writeAmt, void *reserved )
{
uint64_t start = getMS();
while( true )
{
int amount = write( file, buf, length );
if( amount < 0 )
{
if( errno == EAGAIN || errno == EWOULDBLOCK )
{
if( (getMS() - start) > 1000 )
{
return false;
}
/* Try again */
continue;
}
return false;
}
else
{
*writeAmt = amount;
return true;
}
}
}
void SetFilePointer ( int file, int off, void *reserved, int origin )
{
lseek( file, off, origin );
}
void CloseHandle( int file )
{
close( file );
}
bool PurgeComm( int serial )
{
/* Clear out old data */
do
{
unsigned char data[1024];
uint32_t length;
ReadFile( serial, data, sizeof( data ), &length, 0 );
if( length <= 0 ) { break; }
} while( 1 );
return true;
}
uint32_t ReadSerial( int serial, unsigned char *data, unsigned int length )
{
uint32_t readLength = 0;
ReadFile( serial, data, length, &readLength, 0 );
return readLength;
}
uint32_t WriteSerial( int serial, const unsigned char *data, unsigned int length )
{
uint32_t wroteLength = 0;
WriteFile( serial, data, length, &wroteLength, 0 );
return wroteLength;
}
void CloseSerial( int serial )
{
CloseHandle( serial );
}

14
Serial.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef __SERIAL_H
#define __SERIAL_H
#define PARITY_EVEN 1
#define PARITY_ODD 2
#define PARITY_NONE 3
int OpenSerial( const char *port, int baud, int parity );
uint32_t ReadSerial( int serial, unsigned char *data, unsigned int length );
uint32_t WriteSerial( int serial, const unsigned char *data, unsigned int length );
void CloseSerial( int serial );
bool PurgeComm( int serial );
#endif

21
Toshiba_SD-B100.cpp Normal file
View File

@ -0,0 +1,21 @@
#include <stdio.h>
#include <stdint.h>
#include "Toshiba_SD-B100.h"
void ToshibaInit()
{
/* TODO: Init packet buffer and response buffer */
}
int ToshibaReceiveByte( unsigned char byte )
{
/* TODO: Read and parse bytes, return 1 if there is a response to send */
return 0;
}
unsigned char *ToshibaGetResponse( int *length )
{
/* TODO: Return response buffer */
*length = 0;
return NULL;
}

8
Toshiba_SD-B100.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __TOSHIBA_SD_B100
#define __TOSHIBA_SD_B100
void ToshibaInit();
int ToshibaReceiveByte( unsigned char byte );
unsigned char *ToshibaGetResponse( int *length );
#endif

457
Victor_XV-D701.cpp Normal file
View File

@ -0,0 +1,457 @@
#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <memory.h>
#include "Victor_XV-D701.h"
#include "Video.h"
#include "DVDEmu.h"
#define PACKET_DEBUG 0
/* Wait for serial */
#define WAIT() usleep( 100000 )
#define LONGWAIT() usleep( 1000000 )
/* Requests */
#define PREAMBLE_LOC 0
#define JLIP_ID_LOC 2
#define COMMAND_LOC 3
#define PARAMS_LOC 6
/* Responses */
#define PREAMBLE_LOC 0
#define JLIP_ID_LOC 2
#define STATUS_LOC 3
#define DATA_LOC 4
/* Generic */
#define PACKET_LEN 11
#define CRC_LOC 10
unsigned char NO_RESPONSE[6] = { 0, 0, 0, 0, 0, 0 };
// The command sent was unknown
#define STATUS_UNKNOWN_CMD 0x01
// The command sent was executed properly
#define STATUS_OK 0x03
// The command sent was unable to be executed
#define STATUS_ERROR 0x05
typedef unsigned char * packet_t;
/* Emulator state */
struct victor_state
{
unsigned int jlip_id;
unsigned int dvd_type;
unsigned char packet[PACKET_LEN];
packet_t response;
} victor_state;
unsigned char CalcChecksum( const packet_t packet )
{
unsigned char sum = 0x80;
for( uint32_t i = 0; i < (PACKET_LEN - 1); i++ )
{
sum = sum - (packet[i] & 0x7F);
}
return sum & 0x7F;
}
packet_t CreatePacket( unsigned int id, unsigned int status, unsigned char response[6] )
{
packet_t data = (packet_t)malloc(PACKET_LEN);
/* Create preamble */
data[PREAMBLE_LOC + 0] = 0xFC;
data[PREAMBLE_LOC + 1] = 0xFF;
/* Stuff in ID */
data[JLIP_ID_LOC] = id & 0xFF;
/* Stuff in response status */
data[STATUS_LOC] = status & 0xFF;
/* Stuff in data */
memcpy(&data[DATA_LOC], response, 6);
/* Calculate CRC */
data[CRC_LOC] = CalcChecksum(data);
/* Send it */
return data;
}
int IsPacketGood( packet_t packet )
{
if( packet[PREAMBLE_LOC + 0] != 0xFF ||
packet[PREAMBLE_LOC + 1] != 0xFF )
{
/* Not a response packet */
return 0;
}
if( CalcChecksum( packet ) != packet[CRC_LOC] )
{
/* Invalid CRC */
return 0;
}
return 1;
}
void DestroyPacket( packet_t packet )
{
free( packet );
}
packet_t HandleMediaPacket( packet_t packet )
{
switch( packet[COMMAND_LOC + 1] )
{
case 0x41:
{
/* TODO: Drive commands */
break;
}
case 0x43:
{
/* Play commands */
if( packet[COMMAND_LOC + 2] == 0x6D )
{
/* Pause */
verbose_printf( "Device pause request.\n" );
Pause();
return CreatePacket( victor_state.jlip_id, STATUS_OK, NO_RESPONSE );
}
else if( packet[COMMAND_LOC + 2] == 0x75 )
{
/* Play */
verbose_printf( "Device play request.\n" );
Play();
return CreatePacket( victor_state.jlip_id, STATUS_OK, NO_RESPONSE );
}
break;
}
case 0x44:
{
/* Stop commands */
if( packet[COMMAND_LOC + 2] == 0x60 )
{
/* Stop */
verbose_printf( "Device stop request.\n" );
Stop();
return CreatePacket( victor_state.jlip_id, STATUS_OK, NO_RESPONSE );
}
break;
}
case 0x4C:
{
/* TODO; Disk parameter commands */
break;
}
case 0x4E:
{
/* TODO: Disk status commands */
break;
}
case 0x50:
{
/* Seek commands */
if( packet[COMMAND_LOC + 2] == 0x20 )
{
/* Seek to chapter */
unsigned int chapter = ((packet[PARAMS_LOC + 0] % 10) * 100) + ((packet[PARAMS_LOC + 1] % 10) * 10) + (packet[PARAMS_LOC + 2] % 10);
if( victor_state.dvd_type == VICTOR_VCD )
{
/* VCD can only go to 99, so it sicks the data in the first two spots */
chapter /= 10;
}
verbose_printf( "Device seek to chapter %d request.\n", chapter );
if( SeekToChapter( chapter ) )
{
return CreatePacket( victor_state.jlip_id, STATUS_OK, NO_RESPONSE );
}
else
{
return CreatePacket( victor_state.jlip_id, STATUS_ERROR, NO_RESPONSE );
}
}
else if( packet[COMMAND_LOC + 2] == 0x61 )
{
/* Previous chapter */
verbose_printf( "Device seek to previous chapter request.\n" );
unsigned int chapter = GetChapter() - 1;
/* Special case where if we're idle and seek backwards, we start at chapter 1 */
if( !IsPlaying() && chapter == 0 )
{
chapter = 1;
}
if( SeekToChapter( chapter ) )
{
return CreatePacket( victor_state.jlip_id, STATUS_OK, NO_RESPONSE );
}
else
{
return CreatePacket( victor_state.jlip_id, STATUS_ERROR, NO_RESPONSE );
}
}
else if( packet[COMMAND_LOC + 2] == 0x73 )
{
/* Next chapter */
verbose_printf( "Device seek to next chapter request.\n" );
unsigned int chapter = GetChapter() + 1;
if( SeekToChapter( chapter ) )
{
return CreatePacket( victor_state.jlip_id, STATUS_OK, NO_RESPONSE );
}
else
{
return CreatePacket( victor_state.jlip_id, STATUS_ERROR, NO_RESPONSE );
}
}
break;
}
}
return NULL;
}
packet_t HandlePowerPacket( packet_t packet )
{
switch( packet[COMMAND_LOC + 1] )
{
case 0x40:
{
/* Power commands */
if( packet[COMMAND_LOC + 2] == 0x60 )
{
/* Turn off device */
verbose_printf( "Device turn off request.\n" );
int status = IsPowered() ? STATUS_OK : STATUS_ERROR;
if( status == STATUS_OK )
{
PowerOff();
}
return CreatePacket( victor_state.jlip_id, status, NO_RESPONSE );
}
else if( packet[COMMAND_LOC + 2] == 0x70 )
{
/* Turn on device */
verbose_printf( "Device turn on request.\n" );
int status = IsPowered() ? STATUS_ERROR : STATUS_OK;
if( status == STATUS_OK )
{
PowerOn();
}
return CreatePacket( victor_state.jlip_id, status, NO_RESPONSE );
}
break;
}
case 0x4E:
{
/* Power status commands */
if( packet[COMMAND_LOC + 2] == 0x20 )
{
/* Status */
verbose_printf( "Device power status request.\n" );
unsigned char response[6] = { 0, 0x20, 0, 0, 0, 0 };
response[0] = IsPowered() ? 0x01 : 0x0;
return CreatePacket( victor_state.jlip_id, STATUS_OK, response );
}
break;
}
}
/* Unknown, let the master handler send back a failure */
return NULL;
}
packet_t HandleDevicePacket( packet_t packet )
{
if( packet[COMMAND_LOC + 1] == 0x41 )
{
/* Change JLIP ID packet */
unsigned int new_id = packet[COMMAND_LOC + 2];
if( new_id >= 1 && new_id <= 63 )
{
/* Switch IDs */
verbose_printf( "Change JLIP ID to %d\n", new_id );
packet_t response = CreatePacket( victor_state.jlip_id, STATUS_OK, NO_RESPONSE );
victor_state.jlip_id = new_id; /* TODO: Save this to file */
return response;
}
else
{
/* Out of range */
return CreatePacket( victor_state.jlip_id, STATUS_ERROR, NO_RESPONSE );
}
}
else if( packet[COMMAND_LOC + 1] == 0x45 &&
packet[COMMAND_LOC + 2] == 0x00 )
{
/* Get machine code */
verbose_printf( "Machine code request.\n");
unsigned char response[6] = { 0x00, 0x01, 0x03, 0x00, 0x03, 0x01 };
return CreatePacket( victor_state.jlip_id, STATUS_OK, response );
}
else if( packet[COMMAND_LOC + 1] == 0x48 &&
packet[COMMAND_LOC + 2] == 0x20 )
{
/* Get max baud rate */
verbose_printf( "Baud rate request.\n");
/* Hardcode to 9600 baud for now */
unsigned char response[6] = { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 };
return CreatePacket( victor_state.jlip_id, STATUS_OK, response );
}
else if( packet[COMMAND_LOC + 1] == 0x49 &&
packet[COMMAND_LOC + 2] == 0x00 )
{
/* Get machine code */
verbose_printf( "Device code request.\n");
unsigned char response[6] = { 0x03, 0x0C, 0x7F, 0x7F, 0x7F, 0x7F };
return CreatePacket( victor_state.jlip_id, STATUS_OK, response );
}
else if( packet[COMMAND_LOC + 1] == 0x4C &&
packet[COMMAND_LOC + 2] == 0x00 )
{
/* Get first 6 bytes of name */
verbose_printf( "Device name first half request.\n" );
unsigned char response[6] = { 'D', 'V', 'D', ' ', 'P', 'L' };
return CreatePacket( victor_state.jlip_id, STATUS_OK, response );
}
else if( packet[COMMAND_LOC + 1] == 0x4D &&
packet[COMMAND_LOC + 2] == 0x00 )
{
/* Get first 6 bytes of name */
verbose_printf( "Device name last half request.\n" );
unsigned char response[6] = { 'A', 'Y', 'E', 'R', 0x7F, 0x7F };
return CreatePacket( victor_state.jlip_id, STATUS_OK, response );
}
else if( packet[COMMAND_LOC + 1] == 0x4E &&
packet[COMMAND_LOC + 2] == 0x20 )
{
/* Get machine code */
verbose_printf( "NOP request.\n");
unsigned char response[6] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
return CreatePacket( victor_state.jlip_id, STATUS_OK, response );
}
return NULL;
}
packet_t HandlePacket( packet_t packet )
{
/* Check that the checksum is good first */
if( !IsPacketGood( packet ) )
{
/* In the case its invalid or unrecognized, we do nothing */
return NULL;
}
/* Check to see that it's the right ID */
if( packet[JLIP_ID_LOC] != victor_state.jlip_id )
{
/* If it isn't destined for us, we do nothing */
return NULL;
}
if( PACKET_DEBUG ) { PrintHex( "= Incoming: ", packet, PACKET_LEN ); }
/* Parse the packet out */
packet_t response = NULL;
switch( packet[COMMAND_LOC] )
{
case 0x0C:
response = HandleMediaPacket( packet );
break;
case 0x3E:
response = HandlePowerPacket( packet );
break;
case 0x7C:
response = HandleDevicePacket( packet );
break;
}
if( !response )
{
/* Unknown */
PrintHex( "Unknown packet ", packet, PACKET_LEN );
response = CreatePacket( victor_state.jlip_id, STATUS_UNKNOWN_CMD, NO_RESPONSE );
}
return response;
}
void VictorInit( int type )
{
victor_state.jlip_id = 33; /* TODO: Read this from file */
victor_state.dvd_type = type;
memset( victor_state.packet, 0, PACKET_LEN );
victor_state.response = NULL;
verbose_printf( "Emulating Victor XV-D701 %s.\n", victor_state.dvd_type == VICTOR_VCD ? "VCD" : "DVD" );
}
int VictorReceiveByte( unsigned char byte )
{
memmove( &victor_state.packet[0], &victor_state.packet[1], PACKET_LEN - 1 );
victor_state.packet[PACKET_LEN - 1] = byte;
if( victor_state.response )
{
/* Destroy previous packet */
DestroyPacket( victor_state.response );
}
victor_state.response = HandlePacket( victor_state.packet );
if( victor_state.response )
{
if( PACKET_DEBUG ) { PrintHex( "= Outgoing: ", victor_state.response, PACKET_LEN ); }
return 1;
}
return 0;
}
unsigned char *VictorGetResponse( int *length )
{
if( victor_state.response )
{
*length = PACKET_LEN;
return (unsigned char *)victor_state.response;
}
*length = 0;
return NULL;
}

11
Victor_XV-D701.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef __Victor_XV_D701_H
#define __Victor_XV_D701_H
#define VICTOR_DVD 0
#define VICTOR_VCD 1
void VictorInit( int type );
int VictorReceiveByte( unsigned char byte );
unsigned char *VictorGetResponse( int *length );
#endif

178
Video.cpp Normal file
View File

@ -0,0 +1,178 @@
#include <stdio.h>
#include <unistd.h>
#include "Video.h"
#include "DVDEmu.h"
/* Emulator state */
struct video_state
{
unsigned int power_state;
unsigned int playing_state;
unsigned int paused_state;
unsigned int chapter;
unsigned int max_chapter;
char * dvd_path;
} video_state;
void VideoInit( char * path, int chapters )
{
video_state.power_state = 0;
video_state.playing_state = 0;
video_state.paused_state = 0;
video_state.chapter = 1;
video_state.dvd_path = path;
video_state.max_chapter = chapters;
verbose_printf( "Disc has %d chapters.\n", video_state.max_chapter );
}
void PowerOn()
{
if( !video_state.power_state )
{
verbose_printf( "* Exit standby mode.\n" );
video_state.power_state = 1;
Stop();
}
}
void PowerOff()
{
if( video_state.power_state )
{
Stop();
verbose_printf( "* Enter standby mode.\n" );
video_state.power_state = 0;
}
}
void Play()
{
if( !video_state.power_state )
{
PowerOn();
}
if( !video_state.playing_state )
{
verbose_printf( "* Enter playing state.\n" );
SeekToChapter(video_state.chapter);
video_state.playing_state = 1;
video_state.paused_state = 0;
}
else
{
/* Unpause only if we need to */
Unpause();
}
}
void Pause()
{
if( video_state.power_state &&
video_state.playing_state &&
!video_state.paused_state )
{
verbose_printf( "* Enter paused state.\n" );
exec_shell("./control.sh pause &");
video_state.playing_state = 1;
video_state.paused_state = 1;
}
}
void Unpause()
{
if( video_state.power_state &&
video_state.playing_state &&
video_state.paused_state )
{
verbose_printf( "* Exit paused state.\n" );
exec_shell("./control.sh pause &");
video_state.playing_state = 1;
video_state.paused_state = 0;
}
}
int SeekToChapter( unsigned int chapter )
{
if( video_state.power_state )
{
/* Is the chapter in bounds? */
if( chapter >= 1 && chapter <= video_state.max_chapter )
{
verbose_printf( "* Seek to chapter %d.\n", chapter );
/* Kill player */
exec_shell("./control.sh stop 2>/dev/null &");
sleep( 1 );
exec_shell("killall dbus-daemon");
/* Seek */
char syscall[256];
sprintf(syscall, "omxplayer -b --no-osd %s%02d.m4v >/dev/null &", video_state.dvd_path, chapter);
exec_shell(syscall);
video_state.playing_state = 1;
sleep( 1 );
/* Repause if needed */
if( video_state.paused_state ) { exec_shell("./control.sh pause 2>/dev/null &"); }
video_state.chapter = chapter;
return 1;
}
else
{
return 0;
}
}
else
{
/* Nothing seek-wise while off */
return 0;
}
}
void Stop()
{
if( video_state.power_state &&
( video_state.playing_state ||
video_state.paused_state ) )
{
/* If we are paused, exit the pause state */
Unpause();
verbose_printf( "* Enter idle state.\n" );
exec_shell("./control.sh stop &");
sleep(1);
exec_shell("killall dbus-daemon");
video_state.playing_state = 0;
video_state.paused_state = 0;
video_state.chapter = 1;
}
}
int GetChapter()
{
return video_state.chapter;
}
int IsPowered()
{
return video_state.power_state;
}
int IsPlaying()
{
return video_state.playing_state;
}

18
Video.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __VIDEO_H
#define __VIDEO_H
void VideoInit( char * path, int chapters );
void PowerOn();
void PowerOff();
void Play();
void Pause();
void Unpause();
int SeekToChapter( unsigned int chapter );
void Stop();
int GetChapter();
int IsPowered();
int IsPlaying();
#endif