You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
342 lines
8.8 KiB
342 lines
8.8 KiB
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <memory.h>
|
|
#include "Video.h"
|
|
#include "DVDEmu.h"
|
|
|
|
#define OPCODE_STOP 1
|
|
#define OPCODE_PLAY 2
|
|
#define OPCODE_PAUSE 3
|
|
#define OPCODE_UNPAUSE 4
|
|
|
|
/* Emulator state */
|
|
struct video_state
|
|
{
|
|
pthread_t thread;
|
|
pthread_mutex_t lock;
|
|
unsigned char queue[256];
|
|
unsigned int queue_pos;
|
|
unsigned int power_state;
|
|
unsigned int playing_state;
|
|
unsigned int paused_state;
|
|
unsigned int pause_delay;
|
|
unsigned int chapter;
|
|
unsigned int max_chapter;
|
|
char * dvd_path;
|
|
} video_state;
|
|
|
|
void *VideoThread( void *state )
|
|
{
|
|
/* Get state to read from */
|
|
struct video_state *private_state = (struct video_state *)state;
|
|
int loaded = 0;
|
|
|
|
while( true )
|
|
{
|
|
/* Process video commands, safe to read this because
|
|
* if it is non-zero we will try locking anyway. */
|
|
if( private_state->queue_pos > 0 )
|
|
{
|
|
pthread_mutex_lock(&private_state->lock);
|
|
unsigned int amount = 0;
|
|
unsigned int opcode = private_state->queue[0];
|
|
unsigned int arg = private_state->queue[1];
|
|
switch( opcode )
|
|
{
|
|
case OPCODE_STOP:
|
|
/* Stop */
|
|
amount = 1;
|
|
break;
|
|
case OPCODE_PAUSE:
|
|
/* Pause */
|
|
amount = 1;
|
|
break;
|
|
case OPCODE_UNPAUSE:
|
|
/* Pause */
|
|
amount = 1;
|
|
break;
|
|
case OPCODE_PLAY:
|
|
/* Seek */
|
|
amount = 2;
|
|
break;
|
|
}
|
|
|
|
/* Remove if needed */
|
|
if( amount < private_state->queue_pos )
|
|
{
|
|
memmove(&private_state->queue[0], &private_state->queue[amount], private_state->queue_pos - amount);
|
|
}
|
|
private_state->queue_pos -= amount;
|
|
|
|
pthread_mutex_unlock(&private_state->lock);
|
|
|
|
/* Perform operation */
|
|
switch( opcode )
|
|
{
|
|
case OPCODE_STOP:
|
|
/* Stop */
|
|
if( loaded )
|
|
{
|
|
exec_shell("./control.sh stop > /dev/null 2> /dev/null");
|
|
exec_shell("killall dbus-daemon > /dev/null 2> /dev/null");
|
|
exec_shell("killall omxplayer > /dev/null 2> /dev/null");
|
|
exec_shell("killall omxplayer.bin > /dev/null 2> /dev/null");
|
|
loaded = 0;
|
|
}
|
|
break;
|
|
case OPCODE_PAUSE:
|
|
/* Pause */
|
|
if( loaded )
|
|
{
|
|
exec_shell("./control.sh pause > /dev/null 2> /dev/null");
|
|
}
|
|
break;
|
|
case OPCODE_UNPAUSE:
|
|
/* Pause */
|
|
if( loaded )
|
|
{
|
|
if( private_state->pause_delay )
|
|
{
|
|
usleep( private_state->pause_delay * 1000 );
|
|
}
|
|
exec_shell("./control.sh pause > /dev/null 2> /dev/null");
|
|
}
|
|
break;
|
|
case OPCODE_PLAY:
|
|
/* Play */
|
|
if( !loaded )
|
|
{
|
|
/* TODO: Search for videos based on prepended zero or not.
|
|
* Also accept any extension that we support.
|
|
*/
|
|
char syscall[256];
|
|
sprintf(syscall, "omxplayer --loop -b --no-osd %s%02d.m4v > /dev/null 2> /dev/null &", private_state->dvd_path, arg);
|
|
exec_shell(syscall);
|
|
/* Wait for it to start */
|
|
while( 1 )
|
|
{
|
|
int exitcode = exec_shell("./control.sh status > /dev/null 2> /dev/null");
|
|
if( exitcode == 0 )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
loaded = 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Sleep for a bit */
|
|
usleep( 10000 );
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void VideoThreadAction( unsigned int opcode, unsigned int argument )
|
|
{
|
|
pthread_mutex_lock(&video_state.lock);
|
|
|
|
switch(opcode)
|
|
{
|
|
case OPCODE_STOP:
|
|
/* Stop */
|
|
video_state.queue[video_state.queue_pos] = OPCODE_STOP;
|
|
video_state.queue_pos++;
|
|
break;
|
|
case OPCODE_PAUSE:
|
|
/* Pause */
|
|
video_state.queue[video_state.queue_pos] = OPCODE_PAUSE;
|
|
video_state.queue_pos++;
|
|
break;
|
|
case OPCODE_UNPAUSE:
|
|
/* Pause */
|
|
video_state.queue[video_state.queue_pos] = OPCODE_UNPAUSE;
|
|
video_state.queue_pos++;
|
|
break;
|
|
case OPCODE_PLAY:
|
|
/* Seek */
|
|
video_state.queue[video_state.queue_pos] = OPCODE_PLAY;
|
|
video_state.queue_pos++;
|
|
video_state.queue[video_state.queue_pos] = argument;
|
|
video_state.queue_pos++;
|
|
break;
|
|
}
|
|
|
|
pthread_mutex_unlock(&video_state.lock);
|
|
}
|
|
|
|
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;
|
|
video_state.pause_delay = 0;
|
|
|
|
verbose_printf( "Disc has %d chapters.\n", video_state.max_chapter );
|
|
|
|
/* Start video playback thread */
|
|
memset( video_state.queue, 0, sizeof(video_state.queue) );
|
|
video_state.queue_pos = 0;
|
|
pthread_mutex_init(&video_state.lock, NULL);
|
|
pthread_create(&video_state.thread, NULL, VideoThread, &video_state);
|
|
}
|
|
|
|
void VideoSetPauseDelay( unsigned int milliseconds )
|
|
{
|
|
video_state.pause_delay = milliseconds;
|
|
}
|
|
|
|
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" );
|
|
|
|
VideoThreadAction( OPCODE_PAUSE, 0 );
|
|
|
|
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" );
|
|
|
|
VideoThreadAction( OPCODE_UNPAUSE, 0 );
|
|
|
|
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 */
|
|
VideoThreadAction( OPCODE_STOP, 0 );
|
|
|
|
/* Seek */
|
|
VideoThreadAction( OPCODE_PLAY, chapter );
|
|
video_state.playing_state = 1;
|
|
|
|
/* Repause if needed */
|
|
if( video_state.paused_state )
|
|
{
|
|
VideoThreadAction( OPCODE_PAUSE, 0 );
|
|
}
|
|
|
|
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" );
|
|
|
|
VideoThreadAction( OPCODE_STOP, 0 );
|
|
|
|
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;
|
|
}
|
|
|