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.
tdemultimedia/mpeglib/lib/decoder/decoderPlugin.cpp

429 lines
8.9 KiB

/*
base class for the player plugin
Copyright (C) 1999 Martin Vogt
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as published by
the Free Software Foundation.
For more information look at the file COPYRIGHT in this package
*/
#include "decoderPlugin.h"
#include <iostream>
using namespace std;
static void *playerThread(void *arg){
((DecoderPlugin*)arg)->idleThread();
return NULL;
}
static int instanceCnt=0;
DecoderPlugin::DecoderPlugin(){
input=NULL;
output=NULL;
commandPipe=new CommandPipe();
threadCommand=new Command(_COMMAND_NONE);
abs_thread_cond_init(&streamStateCond);
abs_thread_mutex_init(&streamStateMut);
abs_thread_mutex_init(&shutdownMut);
lCreatorLoop=true;
lDecoderLoop=false;
linDecoderLoop=false;
streamState=_STREAM_STATE_EOF;
lDecode=false;
lhasLength=false;
// this default is necessary. if you have a blocking
// device and we start automatic the thread
// may block on it and all commands (including play)
// blocks everything
// *you should not use autoplay*
lAutoPlay=false;
pluginInfo=new PluginInfo();
runCheck_Counter=0;
decode_loopCounter=0;
instance=instanceCnt;
instanceCnt++;
abs_thread_create(&tr,playerThread,this);
// we send a ping. because this signal is synchron
// we block until the thread is started and
// has read the ping singnal
Command cmd(_COMMAND_PING);
insertSyncCommand(&cmd);
}
DecoderPlugin::~DecoderPlugin(){
void* ret;
lCreatorLoop=false;
Command cmd(_COMMAND_CLOSE);
insertAsyncCommand(&cmd);
abs_thread_join(tr,&ret);
abs_thread_cond_destroy(&streamStateCond);
abs_thread_mutex_destroy(&streamStateMut);
abs_thread_mutex_destroy(&shutdownMut);
delete commandPipe;
delete threadCommand;
delete pluginInfo;
}
void DecoderPlugin::close(){
// from here we can only walk to init or eof
// in both cases we sometimes catch out decoderMut :-)
Command cmd(_COMMAND_CLOSE);
insertAsyncCommand(&cmd);
shutdownLock();
if (input != NULL) {
input->close();
}
shutdownUnlock();
insertSyncCommand(&cmd);
waitForStreamState(_STREAM_STATE_EOF);
input=NULL;
}
void DecoderPlugin::pause() {
Command cmd(_COMMAND_PAUSE);
insertSyncCommand(&cmd);
}
int DecoderPlugin::play() {
Command cmd(_COMMAND_PLAY);
insertSyncCommand(&cmd);
return true;
}
int DecoderPlugin::seek(int second) {
Command cmd(_COMMAND_SEEK,second);
insertSyncCommand(&cmd);
return true;
}
void DecoderPlugin::insertAsyncCommand(Command* cmd) {
commandPipe->sendCommandNoWait(*cmd);
}
void DecoderPlugin::insertSyncCommand(Command* cmd) {
commandPipe->sendCommand(*cmd);
}
void DecoderPlugin::shutdownLock() {
abs_thread_mutex_lock(&shutdownMut);
}
void DecoderPlugin::shutdownUnlock() {
abs_thread_mutex_unlock(&shutdownMut);
}
int DecoderPlugin::getTime(int lCurrent) {
int secLen=getTotalLength();
if (lCurrent==false) {
return secLen;
}
shutdownLock();
int byteLen=1;
int pos=1;
if (input != NULL) {
pos=input->getBytePosition()+1;
byteLen=input->getByteLength()+1;
}
int back=(int)(((double)pos/(double)byteLen) * (double)secLen);
shutdownUnlock();
return back;
}
int DecoderPlugin::getTotalLength() {
cout << "plugin does not support total playtime reporting"<<endl;
return 0;
}
int DecoderPlugin::seek_impl(int) {
cout << "plugin does not support seek"<<endl;
return false;
}
void DecoderPlugin::setOutputPlugin(OutputStream* output) {
this->output=output;
}
int DecoderPlugin::setInputPlugin(InputStream* input) {
this->input=input;
if (!input) {
cout << "input is NULL"<<endl;
exit(0);
}
pluginInfo->setUrl(input->getUrl());
// the command is synchron we block until the
// thread has read it
Command cmd(_COMMAND_START);
insertSyncCommand(&cmd);
// now that we know he has read it, we send another
// command, this is only read if the thread is in the
// decode_loop, and we then know that the streamState
// is FIRST_INIT
Command ping(_COMMAND_PING);
insertSyncCommand(&ping);
if (lAutoPlay) {
play();
}
return true;
}
void DecoderPlugin::config(const char* key,const char* value,void* ){
if (strcmp(key,"-y")==0) {
if (strcmp(value,"on")==0) {
lAutoPlay=true;
} else {
lAutoPlay=false;
}
}
}
/**
during shutdown the streamState is undefined until
the thread has left the decode_loop().
Make sure we wait for this.
*/
int DecoderPlugin::getStreamState() {
shutdownLock();
int back=streamState;
shutdownUnlock();
return back;
}
int DecoderPlugin::waitForStreamState(int state) {
int back;
abs_thread_mutex_lock(&streamStateMut);
while ((streamState & state) == false) {
abs_thread_cond_wait(&streamStateCond,&streamStateMut);
}
back=streamState;
abs_thread_mutex_unlock(&streamStateMut);
return back;
}
void DecoderPlugin::setStreamState(int streamState) {
abs_thread_mutex_lock(&streamStateMut);
this->streamState=streamState;
abs_thread_cond_signal(&streamStateCond);
abs_thread_mutex_unlock(&streamStateMut);
}
void DecoderPlugin::decoder_loop() {
cout << "direct call decoder loop->plugin not found ???"<<endl;
TimeWrapper::usleep(100000);
}
void* DecoderPlugin::idleThread() {
while(lCreatorLoop) {
linDecoderLoop=true;
commandPipe->waitForCommand();
commandPipe->hasCommand(threadCommand);
int id=threadCommand->getID();
switch(id) {
case _COMMAND_START:
lDecoderLoop=true;
break;
case _COMMAND_PING:
break;
/*
default:
threadCommand->print("ignoring non START command in idleThread");
*/
}
if (lDecoderLoop) {
setStreamState(_STREAM_STATE_FIRST_INIT);
linDecoderLoop=false;
decode_loopCounter++;
runCheck_Counter=0;
shutdownLock();
decoder_loop();
lDecode=false;
lDecoderLoop=false;
lhasLength=false;
setStreamState(_STREAM_STATE_EOF);
shutdownUnlock();
}
}
return NULL;
}
PluginInfo* DecoderPlugin::getPluginInfo() {
return pluginInfo;
}
int DecoderPlugin::runCheck() {
if (runCheck_Counter==0) {
shutdownUnlock();
}
runCheck_Counter++;
while (lDecoderLoop && lCreatorLoop) {
// if we have an eof this always leads to
// a shutdown of the decode_loop thread
// it has more priority than the resyn request
if (input->eof()) {
setStreamState(_STREAM_STATE_WAIT_FOR_END);
}
//
// if we are in _STREAM_STATE_RESYNC_COMMIT
// we only leave it if command is _COMMAND_RESYNC_END
// (or close)
//
// check user commands
//
if (lDecode==false) {
commandPipe->waitForCommand();
commandPipe->hasCommand(threadCommand);
} else {
if (commandPipe->hasCommand(threadCommand)==false) {
// no commands and lDecode=true
return true;
}
}
// here we forward the command to a special
// method who can handle everything
// (the default method should work fine);
int nextCheck= processThreadCommand(threadCommand);
switch(nextCheck) {
case _RUN_CHECK_CONTINUE:
break;
case _RUN_CHECK_FALSE:
shutdownLock();
return false;
case _RUN_CHECK_TRUE:
return true;
default:
cout << "unknown runCheck return command"<<endl;
exit(0);
}
}
shutdownLock();
return false;
}
int DecoderPlugin::processThreadCommand(Command* command) {
int id=command->getID();
int intArg;
//
// if we are in _STREAM_STATE_RESYNC_COMMIT
// we only leave it if command is _COMMAND_RESYNC_END
//
if (streamState==_STREAM_STATE_RESYNC_COMMIT) {
switch(id) {
case _COMMAND_RESYNC_END:
setStreamState(_STREAM_STATE_INIT);
input->clear();
break;
case _COMMAND_CLOSE:
//
// we return false so that the plugin clears
// all its allocated classes
// its a _must_ !!
// in the next call we exit immediately
return _RUN_CHECK_FALSE;
/*
default:
command->print("ignore command in _STREAM_STATE_RESYNC_COMMIT");
*/
}
return _RUN_CHECK_CONTINUE;
}
switch(id) {
case _COMMAND_NONE:
break;
case _COMMAND_PING:
break;
case _COMMAND_PAUSE:
lDecode=false;
break;
case _COMMAND_PLAY:
lDecode=true;
break;
case _COMMAND_SEEK: {
if (streamState==_STREAM_STATE_FIRST_INIT) {
command->print("ignore command seek in _STREAM_STATE_FIRST_INIT");
} else {
intArg=command->getIntArg();
seek_impl(intArg);
}
break;
}
case _COMMAND_CLOSE:
//
// we return false so that the plugin clears
// all its allocated classes
// its a _must_ !!
// in the next call we exit immediately
return _RUN_CHECK_FALSE;
case _COMMAND_RESYNC_START:
setStreamState(_STREAM_STATE_RESYNC_COMMIT);
input->clear();
break;
/*
default:
cout << "unknown command id in Command::print"<<endl;
*/
}
return _RUN_CHECK_CONTINUE;
}