From 226e5b53948b43de33f9b1a6751365be7962a98e Mon Sep 17 00:00:00 2001 From: DragonMinded Date: Fri, 29 Jan 2016 07:37:20 +0000 Subject: [PATCH] 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. --- Makefile | 4 +- Video.cpp | 509 +++++++++++++++++++++++++++++++++++------------------- Video.h | 1 + 3 files changed, 334 insertions(+), 180 deletions(-) diff --git a/Makefile b/Makefile index 77dd9ed..b2bbdff 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ 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 +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 -pthread -o dvdemu DVDEmu.cpp Serial.cpp Video.cpp Toshiba_SD-B100.cpp Victor_XV-D701.cpp -ggdb .DUMMY: clean clean: diff --git a/Video.cpp b/Video.cpp index efc362a..fee0315 100644 --- a/Video.cpp +++ b/Video.cpp @@ -1,178 +1,331 @@ -#include -#include -#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; -} +#include +#include +#include +#include +#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 &"); + sleep( 1 ); + exec_shell("killall dbus-daemon 2> /dev/null"); + exec_shell("killall omxplayer 2> /dev/null"); + exec_shell("killall omxplayer.bin 2> /dev/null"); + loaded = 0; + } + break; + case OPCODE_PAUSE: + /* Pause */ + if( loaded ) + { + exec_shell("./control.sh pause &"); + } + break; + case OPCODE_UNPAUSE: + /* Pause */ + if( loaded ) + { + if( private_state->pause_delay ) + { + printf("Sleeping %d ms!\n", private_state->pause_delay); + usleep( private_state->pause_delay * 1000 ); + } + exec_shell("./control.sh pause &"); + } + break; + case OPCODE_PLAY: + /* Play */ + if( !loaded ) + { + char syscall[256]; + sprintf(syscall, "omxplayer -b --no-osd %s%02d.m4v >/dev/null &", private_state->dvd_path, arg); + exec_shell(syscall); + sleep( 1 ); + loaded = 1; + } + break; + } + } + else + { + /* Sleep for a bit */ + usleep( 10000 ); + } + } +} + +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; +} diff --git a/Video.h b/Video.h index 0141cbe..78ee5ba 100644 --- a/Video.h +++ b/Video.h @@ -2,6 +2,7 @@ #define __VIDEO_H void VideoInit( char * path, int chapters ); +void VideoSetPauseDelay( unsigned int milliseconds ); void PowerOn(); void PowerOff();