Move video playback commands to their own thread.

Twinkle didn't really care about timing, but PPP 2nd is very sensitive,
so these delays cause it to error out. Fix that by moving the DVD functions
to their own thread so they don't delay the serial thread.
This commit is contained in:
DragonMinded 2016-01-29 07:37:20 +00:00
parent 01b0311492
commit 226e5b5394
3 changed files with 334 additions and 180 deletions

View File

@ -1,7 +1,7 @@
all: dvdemu all: dvdemu
dvdemu: DVDEmu.cpp dvdemu: DVDEmu.cpp DVDEmu.h Serial.cpp Serial.h Video.cpp Video.h Toshiba_SD-B100.cpp Toshiba_SD-B100.h Victor_XV-D701.cpp Victor_XV-D701.h
g++ -Wall -Werror -D_BSD_SOURCE -o dvdemu DVDEmu.cpp Serial.cpp Video.cpp Toshiba_SD-B100.cpp Victor_XV-D701.cpp -ggdb g++ -Wall -Werror -D_BSD_SOURCE -pthread -o dvdemu DVDEmu.cpp Serial.cpp Video.cpp Toshiba_SD-B100.cpp Victor_XV-D701.cpp -ggdb
.DUMMY: clean .DUMMY: clean
clean: clean:

509
Video.cpp
View File

@ -1,178 +1,331 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "Video.h" #include <pthread.h>
#include "DVDEmu.h" #include <memory.h>
#include "Video.h"
/* Emulator state */ #include "DVDEmu.h"
struct video_state
{ #define OPCODE_STOP 1
unsigned int power_state; #define OPCODE_PLAY 2
unsigned int playing_state; #define OPCODE_PAUSE 3
unsigned int paused_state; #define OPCODE_UNPAUSE 4
unsigned int chapter;
unsigned int max_chapter; /* Emulator state */
char * dvd_path; struct video_state
} video_state; {
pthread_t thread;
void VideoInit( char * path, int chapters ) pthread_mutex_t lock;
{ unsigned char queue[256];
video_state.power_state = 0; unsigned int queue_pos;
video_state.playing_state = 0; unsigned int power_state;
video_state.paused_state = 0; unsigned int playing_state;
video_state.chapter = 1; unsigned int paused_state;
video_state.dvd_path = path; unsigned int pause_delay;
video_state.max_chapter = chapters; unsigned int chapter;
unsigned int max_chapter;
verbose_printf( "Disc has %d chapters.\n", video_state.max_chapter ); char * dvd_path;
} } video_state;
void PowerOn() void *VideoThread( void *state )
{ {
if( !video_state.power_state ) /* Get state to read from */
{ struct video_state *private_state = (struct video_state *)state;
verbose_printf( "* Exit standby mode.\n" ); int loaded = 0;
video_state.power_state = 1; while( true )
Stop(); {
} /* Process video commands, safe to read this because
} * if it is non-zero we will try locking anyway. */
if( private_state->queue_pos > 0 )
void PowerOff() {
{ pthread_mutex_lock(&private_state->lock);
if( video_state.power_state ) unsigned int amount = 0;
{ unsigned int opcode = private_state->queue[0];
Stop(); unsigned int arg = private_state->queue[1];
switch( opcode )
verbose_printf( "* Enter standby mode.\n" ); {
case OPCODE_STOP:
video_state.power_state = 0; /* Stop */
} amount = 1;
} break;
case OPCODE_PAUSE:
void Play() /* Pause */
{ amount = 1;
if( !video_state.power_state ) break;
{ case OPCODE_UNPAUSE:
PowerOn(); /* Pause */
} amount = 1;
break;
if( !video_state.playing_state ) case OPCODE_PLAY:
{ /* Seek */
verbose_printf( "* Enter playing state.\n" ); amount = 2;
break;
SeekToChapter(video_state.chapter); }
video_state.playing_state = 1; /* Remove if needed */
video_state.paused_state = 0; if( amount < private_state->queue_pos )
} {
else memmove(&private_state->queue[0], &private_state->queue[amount], private_state->queue_pos - amount);
{ }
/* Unpause only if we need to */ private_state->queue_pos -= amount;
Unpause();
} pthread_mutex_unlock(&private_state->lock);
}
/* Perform operation */
void Pause() switch( opcode )
{ {
if( video_state.power_state && case OPCODE_STOP:
video_state.playing_state && /* Stop */
!video_state.paused_state ) if( loaded )
{ {
verbose_printf( "* Enter paused state.\n" ); exec_shell("./control.sh stop &");
sleep( 1 );
exec_shell("./control.sh pause &"); exec_shell("killall dbus-daemon 2> /dev/null");
exec_shell("killall omxplayer 2> /dev/null");
video_state.playing_state = 1; exec_shell("killall omxplayer.bin 2> /dev/null");
video_state.paused_state = 1; loaded = 0;
} }
} break;
case OPCODE_PAUSE:
void Unpause() /* Pause */
{ if( loaded )
if( video_state.power_state && {
video_state.playing_state && exec_shell("./control.sh pause &");
video_state.paused_state ) }
{ break;
verbose_printf( "* Exit paused state.\n" ); case OPCODE_UNPAUSE:
/* Pause */
exec_shell("./control.sh pause &"); if( loaded )
{
video_state.playing_state = 1; if( private_state->pause_delay )
video_state.paused_state = 0; {
} printf("Sleeping %d ms!\n", private_state->pause_delay);
} usleep( private_state->pause_delay * 1000 );
}
int SeekToChapter( unsigned int chapter ) exec_shell("./control.sh pause &");
{ }
if( video_state.power_state ) break;
{ case OPCODE_PLAY:
/* Is the chapter in bounds? */ /* Play */
if( chapter >= 1 && chapter <= video_state.max_chapter ) if( !loaded )
{ {
verbose_printf( "* Seek to chapter %d.\n", chapter ); char syscall[256];
sprintf(syscall, "omxplayer -b --no-osd %s%02d.m4v >/dev/null &", private_state->dvd_path, arg);
/* Kill player */ exec_shell(syscall);
exec_shell("./control.sh stop 2>/dev/null &"); sleep( 1 );
sleep( 1 ); loaded = 1;
exec_shell("killall dbus-daemon"); }
break;
/* Seek */ }
char syscall[256]; }
sprintf(syscall, "omxplayer -b --no-osd %s%02d.m4v >/dev/null &", video_state.dvd_path, chapter); else
exec_shell(syscall); {
video_state.playing_state = 1; /* Sleep for a bit */
sleep( 1 ); usleep( 10000 );
}
/* Repause if needed */ }
if( video_state.paused_state ) { exec_shell("./control.sh pause 2>/dev/null &"); } }
video_state.chapter = chapter; void VideoThreadAction( unsigned int opcode, unsigned int argument )
return 1; {
} pthread_mutex_lock(&video_state.lock);
else
{ switch(opcode)
return 0; {
} case OPCODE_STOP:
} /* Stop */
else video_state.queue[video_state.queue_pos] = OPCODE_STOP;
{ video_state.queue_pos++;
/* Nothing seek-wise while off */ break;
return 0; case OPCODE_PAUSE:
} /* Pause */
} video_state.queue[video_state.queue_pos] = OPCODE_PAUSE;
video_state.queue_pos++;
void Stop() break;
{ case OPCODE_UNPAUSE:
if( video_state.power_state && /* Pause */
( video_state.playing_state || video_state.queue[video_state.queue_pos] = OPCODE_UNPAUSE;
video_state.paused_state ) ) video_state.queue_pos++;
{ break;
/* If we are paused, exit the pause state */ case OPCODE_PLAY:
Unpause(); /* Seek */
video_state.queue[video_state.queue_pos] = OPCODE_PLAY;
verbose_printf( "* Enter idle state.\n" ); video_state.queue_pos++;
video_state.queue[video_state.queue_pos] = argument;
exec_shell("./control.sh stop &"); video_state.queue_pos++;
sleep(1); break;
exec_shell("killall dbus-daemon"); }
video_state.playing_state = 0; pthread_mutex_unlock(&video_state.lock);
video_state.paused_state = 0; }
video_state.chapter = 1;
} void VideoInit( char * path, int chapters )
} {
video_state.power_state = 0;
int GetChapter() video_state.playing_state = 0;
{ video_state.paused_state = 0;
return video_state.chapter; video_state.chapter = 1;
} video_state.dvd_path = path;
video_state.max_chapter = chapters;
int IsPowered() video_state.pause_delay = 0;
{
return video_state.power_state; verbose_printf( "Disc has %d chapters.\n", video_state.max_chapter );
}
/* Start video playback thread */
int IsPlaying() memset( video_state.queue, 0, sizeof(video_state.queue) );
{ video_state.queue_pos = 0;
return video_state.playing_state; 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;
}

View File

@ -2,6 +2,7 @@
#define __VIDEO_H #define __VIDEO_H
void VideoInit( char * path, int chapters ); void VideoInit( char * path, int chapters );
void VideoSetPauseDelay( unsigned int milliseconds );
void PowerOn(); void PowerOn();
void PowerOff(); void PowerOff();