| /* ------------------------------------------------------------------ |
| * Copyright (C) 2008 PacketVideo |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| * express or implied. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * ------------------------------------------------------------------- |
| */ |
| #ifndef SAMPLE_PLAYER_APP_H_INCLUDED |
| #include "sample_player_app.h" |
| #endif |
| |
| #ifndef OSCL_MEM_H_INCLUDED |
| #include "oscl_mem.h" |
| #endif |
| |
| #ifndef OSCL_MEM_AUDIT_H_INCLUDED |
| #include "oscl_mem_audit.h" |
| #endif |
| |
| #ifndef OSCL_ERROR_H_INCLUDED |
| #include "oscl_error.h" |
| #endif |
| |
| #ifndef OSCL_ERROR_PANIC_H_INCLUDED |
| #include "oscl_error_panic.h" |
| #endif |
| |
| #ifndef OSCL_SCHEDULER_H_INCLUDED |
| #include "oscl_scheduler.h" |
| #endif |
| |
| #ifndef PVLOGGER_H_INCLUDED |
| #include "pvlogger.h" |
| #endif |
| |
| #ifndef PVLOGGER_FILE_APPENDER_H_INCLUDED |
| #include "pvlogger_file_appender.h" |
| #endif |
| |
| #ifndef OSCL_UTF8CONV_H |
| #include "oscl_utf8conv.h" |
| #endif |
| |
| #ifndef SAMPLE_PLAYER_APP_CONFIG_H_INCLUDED |
| #include "sample_player_app_config.h" |
| #endif |
| |
| #ifndef OSCL_STRING_UTILS_H_INCLUDED |
| #include "oscl_string_utils.h" |
| #endif |
| |
| #ifndef PV_PLAYER_TEST_MIO_FACTORY_H_INCLUDED |
| #include "pv_player_test_mio_factory.h" |
| #endif |
| |
| #ifndef PV_MEDIA_OUTPUT_NODE_FACTORY_H_INCLUDED |
| #include "pv_media_output_node_factory.h" |
| #endif |
| |
| #ifndef PV_PLAYER_DATASINKPVMFNODE_H_INCLUDED |
| #include "pv_player_datasinkpvmfnode.h" |
| #endif |
| |
| #ifndef DEFAULTSOURCEFILENAME |
| #error // The default source file needs to be defined in config file |
| #endif |
| |
| #ifndef DEFAULTSOURCEFORMATTYPE |
| #error // The format type for default source file needs to be defined in config file |
| #endif |
| |
| int _local_main(); |
| |
| // printing to console |
| FILE* file = stdout; |
| |
| char* input_file_name = NULL; |
| |
| /*! |
| * A sample application to demostrate the normal engine sequence of playing a specified source till end of clip |
| * - Data Source: defaults to "testqvga30fps.mp4" |
| * - Data Sink(s): Video[FileOutputNode-sample_player_app_[SRCFILENAME]_video.dat] |
| * Audio[FileOutputNode-sample_player_app__[SRCFILENAME]_audio.dat] |
| * Text[FileOutputNode-sample_player_app__[SRCFILENAME]_text.dat] |
| * |
| * - Sequence |
| * -# CreatePlayer() |
| * -# AddDataSource() |
| * -# Init() |
| * -# AddDataSink() (video) |
| * -# AddDataSink() (audio) |
| * -# AddDataSink() (text) |
| * -# GetMetadataValues() |
| * -# Prepare() |
| * -# Start() |
| * -# Play till EOS |
| * -# Stop() |
| * -# RemoveDataSink() (video) |
| * -# RemoveDataSink() (audio) |
| * -# RemoveDataSink() (text) |
| * -# Reset() |
| * -# RemoveDataSource() |
| * -# DeletePlayer() |
| * |
| */ |
| |
| |
| // Entry point for sample program |
| int main(int argc, char **argv) |
| { |
| if (argc > 1) |
| { |
| input_file_name = argv[1]; |
| } |
| |
| fprintf(file, "Sample application for pvPlayer engine:\n"); |
| |
| //Init Oscl |
| OsclBase::Init(); |
| OsclErrorTrap::Init(); |
| OsclMem::Init(); |
| |
| //Run the test under a trap |
| int result = -1; |
| int32 err; |
| TPVErrorPanic panic; |
| |
| OSCL_PANIC_TRAP(err, panic, result = _local_main();); |
| |
| //Show any exception. |
| if (err != 0) |
| { |
| fprintf(file, "Error! Leave %d\n", err); |
| } |
| if (panic.iReason != 0) |
| { |
| fprintf(file, "Error! Panic %s %d\n", panic.iCategory.Str(), panic.iReason); |
| } |
| |
| //Cleanup |
| #if !(OSCL_BYPASS_MEMMGT) |
| //Check for memory leaks before cleaning up OsclMem. |
| OsclAuditCB auditCB; |
| OsclMemInit(auditCB); |
| if (auditCB.pAudit) |
| { |
| MM_Stats_t* stats = auditCB.pAudit->MM_GetStats(""); |
| if (stats) |
| { |
| fprintf(file, "\nAfter Playback Memory Stats:\n"); |
| fprintf(file, " peakNumAllocs %d\n", stats->peakNumAllocs); |
| fprintf(file, " peakNumBytes %d\n", stats->peakNumBytes); |
| fprintf(file, " totalNumAllocs %d\n", stats->totalNumAllocs); |
| fprintf(file, " totalNumBytes %d\n", stats->totalNumBytes); |
| fprintf(file, " numAllocFails %d\n", stats->numAllocFails); |
| if (stats->numAllocs) |
| { |
| fprintf(file, " ERROR: Memory Leaks! numAllocs %d, numBytes %d\n", stats->numAllocs, stats->numBytes); |
| } |
| } |
| uint32 leaks = auditCB.pAudit->MM_GetNumAllocNodes(); |
| if (leaks != 0) |
| { |
| fprintf(file, "ERROR: %d Memory leaks detected!\n", leaks); |
| MM_AllocQueryInfo*info = auditCB.pAudit->MM_CreateAllocNodeInfo(leaks); |
| uint32 leakinfo = auditCB.pAudit->MM_GetAllocNodeInfo(info, leaks, 0); |
| if (leakinfo != leaks) |
| { |
| fprintf(file, "ERROR: Leak info is incomplete.\n"); |
| } |
| for (uint32 i = 0;i < leakinfo;i++) |
| { |
| fprintf(file, "Leak Info:\n"); |
| fprintf(file, " allocNum %d\n", info[i].allocNum); |
| fprintf(file, " fileName %s\n", info[i].fileName); |
| fprintf(file, " lineNo %d\n", info[i].lineNo); |
| fprintf(file, " size %d\n", info[i].size); |
| fprintf(file, " pMemBlock 0x%x\n", info[i].pMemBlock); |
| fprintf(file, " tag %s\n", info[i].tag); |
| } |
| auditCB.pAudit->MM_ReleaseAllocNodeInfo(info); |
| } |
| } |
| #endif |
| |
| OsclMem::Cleanup(); |
| OsclErrorTrap::Cleanup(); |
| OsclBase::Cleanup(); |
| |
| return result; |
| } |
| |
| //////// |
| |
| int _local_main() |
| { |
| // default source filename is "test.mp4" |
| OSCL_HeapString<OsclMemAllocator> filenameinfo; |
| filenameinfo = SOURCENAME_PREPEND_STRING; |
| |
| if (input_file_name != NULL) |
| { |
| filenameinfo += input_file_name; |
| } |
| else |
| { |
| filenameinfo += DEFAULTSOURCEFILENAME; |
| } |
| |
| // default source file format is MP4 |
| PVMFFormatType inputformattype = DEFAULTSOURCEFORMATTYPE; |
| |
| fprintf(file, " Input file name '%s'\n", filenameinfo.get_cstr()); |
| |
| // instantiate a player engine |
| pvplayer_engine_interface *engine_interface = new pvplayer_engine_interface(filenameinfo.get_str(), inputformattype); |
| if (engine_interface) |
| { |
| #if !(OSCL_BYPASS_MEMMGT) |
| // Obtain the current mem stats before running the test case |
| OsclAuditCB auditCB; |
| OsclMemInit(auditCB); |
| if (auditCB.pAudit) |
| { |
| MM_Stats_t* stats = auditCB.pAudit->MM_GetStats(""); |
| if (stats) |
| { |
| fprintf(file, "\nBefore Playback Memory Stats:\n"); |
| fprintf(file, " totalNumAllocs %d\n", stats->totalNumAllocs); |
| fprintf(file, " totalNumBytes %d\n", stats->totalNumBytes); |
| fprintf(file, " numAllocFails %d\n", stats->numAllocFails); |
| fprintf(file, " numAllocs %d\n", stats->numAllocs); |
| } |
| else |
| { |
| fprintf(file, "Retrieving memory statistics before running test case failed! Memory statistics result would be invalid.\n"); |
| } |
| } |
| else |
| { |
| fprintf(file, "Memory audit not available! Memory statistics result would be invalid.\n"); |
| } |
| #endif |
| |
| fprintf(file, "\nStarting Playback\n "); |
| |
| // Enable the following code for logging |
| PVLogger::Init(); |
| PVLoggerAppender *appender = NULL; |
| OsclRefCounter *refCounter = NULL; |
| |
| // Log all nodes, for errors only, to the stdout |
| appender = new StdErrAppender<TimeAndIdLayout, 1024>(); |
| OsclRefCounterSA<LogAppenderDestructDealloc<StdErrAppender<TimeAndIdLayout, 1024> > > *appenderRefCounter = |
| new OsclRefCounterSA<LogAppenderDestructDealloc<StdErrAppender<TimeAndIdLayout, 1024> > >(appender); |
| refCounter = appenderRefCounter; |
| |
| OsclSharedPtr<PVLoggerAppender> appenderPtr(appender, refCounter); |
| |
| #if 0 |
| // log everything at DEBUG |
| PVLogger *rootnode = PVLogger::GetLoggerObject(""); |
| rootnode->AddAppender(appenderPtr); |
| rootnode->SetLogLevel(PVLOGMSG_DEBUG); |
| #endif |
| #if 0 |
| // log specific components |
| PVLogger *node; |
| |
| node = PVLogger::GetLoggerObject("PVPlayerEngine"); |
| node->AddAppender(appenderPtr); |
| node->SetLogLevel(PVLOGMSG_DEBUG); |
| |
| node = PVLogger::GetLoggerObject("PVMFMP4FFParserNode"); |
| node->AddAppender(appenderPtr); |
| node->SetLogLevel(PVLOGMSG_DEBUG); |
| |
| node = PVLogger::GetLoggerObject("PVMFFileOutputNode"); |
| node->AddAppender(appenderPtr); |
| node->SetLogLevel(PVLOGMSG_DEBUG); |
| |
| // Log datapath only |
| node = PVLogger::GetLoggerObject("datapath"); |
| node->AddAppender(appenderPtr); |
| //info level logs ports & synchronization info. |
| node->SetLogLevel(PVLOGMSG_INFO); |
| #endif |
| |
| // Construct and install the active scheduler |
| OsclScheduler::Init("PVPlayerEngineScheduler"); |
| |
| OsclExecScheduler *sched = OsclExecScheduler::Current(); |
| if (sched) |
| { |
| // Start playback |
| engine_interface->StartPlayback(); |
| |
| // Start the scheduler |
| // control is transfered to the player engine when StartScheduler() is called |
| // control is regained when StopScheduler() is called |
| fprintf(file, "\nStarting Scheduler\n "); |
| #if USE_NATIVE_SCHEDULER |
| // Have PV scheduler use the scheduler native to the system |
| sched->StartNativeScheduler(); |
| #else |
| // Have PV scheduler use its own implementation of the scheduler |
| sched->StartScheduler(); |
| #endif |
| } |
| else |
| { |
| fprintf(file, "ERROR! Scheduler is not available. Test case could not run."); |
| } |
| |
| // when playback completes, StopScheduler is called |
| // and control is returned to this location |
| |
| // Shutdown PVLogger and scheduler before checking mem stats |
| OsclScheduler::Cleanup(); |
| PVLogger::Cleanup(); |
| |
| // done with playback, free resources |
| OSCL_DELETE(engine_interface); |
| engine_interface = NULL; |
| |
| return 0; |
| } |
| else |
| { |
| fprintf(file, "ERROR! pvplayer_engine_interface could not be instantiated.\n"); |
| return 1; |
| } |
| } |
| |
| |
| //////// |
| |
| pvplayer_engine_interface::pvplayer_engine_interface(char *aFileName, PVMFFormatType aFileType) : OsclTimerObject(OsclActiveObject::EPriorityNominal, "PVPlayerEngine"), |
| iState(STATE_UNKNOWN), |
| iPlayer(NULL), |
| iDataSource(NULL), |
| iDataSinkVideo(NULL), |
| iDataSinkAudio(NULL), |
| iDataSinkText(NULL), |
| iCurrentCmdId(0), |
| iFileName(NULL), |
| iFileType(0), |
| iContextObjectRefValue(0), |
| iContextObject(0), |
| iNumValues(0), |
| iClipDuration(0) |
| { |
| iFileName = aFileName; |
| iFileType = aFileType; |
| |
| // Initialize the variables with some random number to use for context data testing |
| iContextObject = iContextObjectRefValue = 0x5C7A; |
| |
| PVPlayerTestMioFactory::DeviceInit(this); |
| } |
| |
| |
| //////// |
| |
| pvplayer_engine_interface::~pvplayer_engine_interface() |
| { |
| PVPlayerTestMioFactory::DeviceDeInit(this); |
| } |
| |
| //////// |
| void pvplayer_engine_interface::StartPlayback() |
| { |
| // add this timer object to the scheduler |
| AddToScheduler(); |
| // use iState to drive the playback for this simple app |
| // a command queuing mechanism may be desired |
| // where by the end user requests, such as pause playback or |
| // resume playback, are put on the queue in a separate thread |
| // and are dequeued by Run() |
| iState = STATE_CREATE; |
| // schedule this timer object to run immediately |
| RunIfNotReady(); |
| } |
| |
| //////// |
| |
| // this is called by the PV scheduler |
| void pvplayer_engine_interface::Run() |
| { |
| int error = 0; |
| |
| // in this simple app, state transition is used to drive the engine |
| // in proper deployment, user requests may be used instead to drive engine |
| // end user requests may be queued by in a separate thread and dequeued here |
| switch (iState) |
| { |
| case STATE_CREATE: |
| { |
| iPlayer = NULL; |
| |
| OSCL_TRY(error, iPlayer = PVPlayerFactory::CreatePlayer(this, this, this)); |
| if (error) |
| { |
| // clean up |
| fprintf(file, "\nStopping Scheduler\n"); |
| |
| // Stop the scheduler |
| OsclExecScheduler *sched = OsclExecScheduler::Current(); |
| if (sched) |
| { |
| sched->StopScheduler(); |
| } |
| } |
| else |
| { |
| // player created successfully |
| // next step is to add the data source |
| iState = STATE_ADDDATASOURCE; |
| // schedule to run immediately |
| RunIfNotReady(); |
| } |
| } |
| break; |
| |
| case STATE_ADDDATASOURCE: |
| { |
| // create a datasource |
| iDataSource = new PVPlayerDataSourceURL; |
| |
| // convert to wchar |
| oscl_UTF8ToUnicode(iFileName, oscl_strlen(iFileName), output, 512); |
| wFileName.set(output, oscl_strlen(output)); |
| |
| iDataSource->SetDataSourceURL(wFileName); |
| iDataSource->SetDataSourceFormatType(iFileType); |
| |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->AddDataSource(*iDataSource, (OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| |
| break; |
| |
| case STATE_INIT: |
| { |
| // initialize the player |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->Init((OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_ADDDATASINK_VIDEO: |
| { |
| // create video sink |
| // use a file output sink for now |
| // output format is defined in config |
| |
| OSCL_wHeapString<OsclMemAllocator> SinkFileName; |
| SinkFileName = OUTPUTNAME_PREPEND_WSTRING; |
| SinkFileName += _STRLIT_WCHAR("sample_player_app_"); |
| OSCL_wHeapString<OsclMemAllocator> inputfilename; |
| RetrieveFilename(wFileName.get_str(), inputfilename); |
| SinkFileName += inputfilename; |
| SinkFileName += _STRLIT_WCHAR("_video.dat"); |
| |
| iMIOFileOutVideo = PVPlayerTestMioFactory::CreateVideoOutput |
| ((OsclAny*) & SinkFileName, |
| NULL, // aObserver |
| true, // aActiveTiming |
| 50, // aQueueLimit |
| false, // aSimFlowControl |
| false // logStrings |
| ); |
| iIONodeVideo = PVMediaOutputNodeFactory::CreateMediaOutputNode(iMIOFileOutVideo); |
| iDataSinkVideo = new PVPlayerDataSinkPVMFNode; |
| |
| ((PVPlayerDataSinkPVMFNode*)iDataSinkVideo)->SetDataSinkNode(iIONodeVideo); |
| ((PVPlayerDataSinkPVMFNode*)iDataSinkVideo)->SetDataSinkFormatType(VIDEOSINK_FORMAT_TYPE); |
| |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->AddDataSink(*iDataSinkVideo, (OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_ADDDATASINK_AUDIO: |
| { |
| // create audio sink |
| // use a file output sink for now |
| // default output format is PCM16 |
| |
| OSCL_wHeapString<OsclMemAllocator> SinkFileName; |
| SinkFileName = OUTPUTNAME_PREPEND_WSTRING; |
| SinkFileName += _STRLIT_WCHAR("sample_player_app_"); |
| OSCL_wHeapString<OsclMemAllocator> inputfilename; |
| RetrieveFilename(wFileName.get_str(), inputfilename); |
| SinkFileName += inputfilename; |
| SinkFileName += _STRLIT_WCHAR("_audio.dat"); |
| |
| iMIOFileOutAudio = PVPlayerTestMioFactory::CreateAudioOutput |
| ((OsclAny*) & SinkFileName, |
| NULL, // aObserver |
| true, // aActiveTiming |
| 50, // aQueueLimit |
| false, // aSimFlowControl |
| false // logStrings |
| ); |
| |
| iIONodeAudio = PVMediaOutputNodeFactory::CreateMediaOutputNode(iMIOFileOutAudio); |
| iDataSinkAudio = new PVPlayerDataSinkPVMFNode; |
| |
| ((PVPlayerDataSinkPVMFNode*)iDataSinkAudio)->SetDataSinkNode(iIONodeAudio); |
| |
| ((PVPlayerDataSinkPVMFNode*)iDataSinkAudio)->SetDataSinkFormatType(AUDIOSINK_FORMAT_TYPE); |
| |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->AddDataSink(*iDataSinkAudio, (OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_ADDDATASINK_TEXT: |
| { |
| // create text sink |
| // use a file output sink for now |
| // default output format is 3GPP timed text |
| |
| OSCL_wHeapString<OsclMemAllocator> SinkFileName; |
| SinkFileName = OUTPUTNAME_PREPEND_WSTRING; |
| SinkFileName += _STRLIT_WCHAR("sample_player_app_"); |
| OSCL_wHeapString<OsclMemAllocator> inputfilename; |
| RetrieveFilename(wFileName.get_str(), inputfilename); |
| SinkFileName += inputfilename; |
| SinkFileName += _STRLIT_WCHAR("_text.dat"); |
| |
| iMIOFileOutText = PVPlayerTestMioFactory::CreateTextOutput((OsclAny*) & SinkFileName); // simple form |
| iIONodeText = PVMediaOutputNodeFactory::CreateMediaOutputNode(iMIOFileOutText); |
| iDataSinkText = new PVPlayerDataSinkPVMFNode; |
| |
| ((PVPlayerDataSinkPVMFNode*)iDataSinkText)->SetDataSinkNode(iIONodeText); |
| ((PVPlayerDataSinkPVMFNode*)iDataSinkText)->SetDataSinkFormatType(PVMF_3GPP_TIMEDTEXT); |
| |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->AddDataSink(*iDataSinkText, (OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_GETMETADATAVALUES: |
| { |
| // find out the source clip duration |
| // the duration is retrieved from the metadata |
| iMetadataKeyList.push_back(OSCL_HeapString<OsclMemAllocator>("duration")); |
| iMetadataValueList.clear(); |
| iNumValues = 0; |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->GetMetadataValues(iMetadataKeyList, 0, -1, iNumValues, iMetadataValueList, (OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_PREPARE: |
| { |
| // prepare the player |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->Prepare((OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_START: |
| { |
| // start playback from the beginning of the clip |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->Start((OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_EOSNOTREACHED: |
| { |
| // stop the playback |
| iState = STATE_STOP; |
| RunIfNotReady(); |
| } |
| break; |
| |
| case STATE_STOP: |
| { |
| // stop the player |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->Stop((OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_REMOVEDATASINK_VIDEO: |
| { |
| // remove the video sink, which is a currently a file output sink |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->RemoveDataSink(*iDataSinkVideo, (OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_REMOVEDATASINK_AUDIO: |
| { |
| // remove the audio sink, which is a currently a file output sink |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->RemoveDataSink(*iDataSinkAudio, (OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_REMOVEDATASINK_TEXT: |
| { |
| // remove the text sink, which is a currently a file output sink |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->RemoveDataSink(*iDataSinkText, (OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_RESET: |
| { |
| // reset the player |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->Reset((OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_REMOVEDATASOURCE: |
| { |
| // remove the data souce |
| OSCL_TRY(error, iCurrentCmdId = iPlayer->RemoveDataSource(*iDataSource, (OsclAny*) & iContextObject)); |
| OSCL_FIRST_CATCH_ANY(error, iState = STATE_CLEANUPANDCOMPLETE; RunIfNotReady()); |
| } |
| break; |
| |
| case STATE_CLEANUPANDCOMPLETE: |
| { |
| // free up all resources |
| PVPlayerFactory::DeletePlayer(iPlayer); |
| iPlayer = NULL; |
| |
| OSCL_DELETE(iDataSource); |
| iDataSource = NULL; |
| |
| OSCL_DELETE(iDataSinkVideo); |
| iDataSinkVideo = NULL; |
| |
| OSCL_DELETE(iDataSinkAudio); |
| iDataSinkAudio = NULL; |
| |
| OSCL_DELETE(iDataSinkText); |
| iDataSinkText = NULL; |
| |
| PVMediaOutputNodeFactory::DeleteMediaOutputNode(iIONodeVideo); |
| iIONodeVideo = NULL; |
| |
| PVMediaOutputNodeFactory::DeleteMediaOutputNode(iIONodeAudio); |
| iIONodeAudio = NULL; |
| |
| PVMediaOutputNodeFactory::DeleteMediaOutputNode(iIONodeText); |
| iIONodeText = NULL; |
| |
| PVPlayerTestMioFactory::DestroyVideoOutput(iMIOFileOutVideo); |
| iMIOFileOutVideo = NULL; |
| |
| PVPlayerTestMioFactory::DestroyAudioOutput(iMIOFileOutAudio); |
| iMIOFileOutAudio = NULL; |
| |
| PVPlayerTestMioFactory::DestroyTextOutput(iMIOFileOutText); |
| iMIOFileOutText = NULL; |
| |
| fprintf(file, "\nStopping Scheduler\n"); |
| |
| // Stop the scheduler |
| OsclExecScheduler *sched = OsclExecScheduler::Current(); |
| if (sched) |
| { |
| sched->StopScheduler(); |
| } |
| } |
| break; |
| |
| default: |
| break; |
| |
| } |
| } |
| |
| //////// |
| |
| // callback by PV engine when a request has been completed |
| void pvplayer_engine_interface::CommandCompleted(const PVCmdResponse& aResponse) |
| { |
| if (aResponse.GetCmdId() != iCurrentCmdId) |
| { |
| // Wrong command ID. |
| fprintf(file, "\nCommandCompleted Mismatched Id\n"); |
| iState = STATE_CLEANUPANDCOMPLETE; |
| RunIfNotReady(); |
| return; |
| } |
| |
| if (aResponse.GetContext() != NULL) |
| { |
| if (aResponse.GetContext() == (OsclAny*)&iContextObject) |
| { |
| if (iContextObject != iContextObjectRefValue) |
| { |
| // Context data value was corrupted |
| iState = STATE_CLEANUPANDCOMPLETE; |
| RunIfNotReady(); |
| return; |
| } |
| } |
| else |
| { |
| // Context data pointer was corrupted |
| iState = STATE_CLEANUPANDCOMPLETE; |
| RunIfNotReady(); |
| return; |
| } |
| } |
| |
| if (aResponse.GetCmdStatus() != PVMFSuccess) |
| { |
| // Treat as unrecoverable error |
| iState = STATE_CLEANUPANDCOMPLETE; |
| RunIfNotReady(); |
| return; |
| } |
| |
| bool bWait = false; |
| |
| switch (iState) |
| { |
| case STATE_ADDDATASOURCE: |
| // Data source was added |
| // Initialize the player |
| iState = STATE_INIT; |
| break; |
| |
| case STATE_INIT: |
| // Player was initialized |
| // Add video sink |
| iState = STATE_ADDDATASINK_VIDEO; |
| break; |
| |
| case STATE_ADDDATASINK_VIDEO: |
| // Video sink was added |
| // Add audio sink |
| iState = STATE_ADDDATASINK_AUDIO; |
| break; |
| |
| case STATE_ADDDATASINK_AUDIO: |
| // Audio sink was added |
| // Add text sink |
| iState = STATE_ADDDATASINK_TEXT; |
| break; |
| |
| case STATE_ADDDATASINK_TEXT: |
| // Text sink was added |
| // Retrieve metadata values (clip duration in particular) |
| iState = STATE_GETMETADATAVALUES; |
| break; |
| |
| case STATE_GETMETADATAVALUES: |
| // If duration is available, get it. Default is 10 sec |
| iClipDuration = 10000; |
| if (iMetadataValueList.empty() == false) |
| { |
| for (uint32 i = 0; i < iMetadataValueList.size(); ++i) |
| { |
| // Search for timescale and duration info |
| char* substr = oscl_strstr(iMetadataValueList[i].key, _STRLIT_CHAR("duration;valtype=uint32;timescale=")); |
| if (substr != NULL) |
| { |
| uint32 timescale = 1000; |
| if (PV_atoi((substr + 34), 'd', timescale) == false) |
| { |
| // No timescale info, default to 1000 |
| timescale = 1000; |
| } |
| uint32 duration = iMetadataValueList[i].value.uint32_value; |
| if (duration > 0 && timescale > 0) |
| { |
| // Save the clip duration in milliseconds |
| iClipDuration = ((duration * 1000) / timescale); |
| } |
| } |
| } |
| } |
| |
| fprintf(file, " clip duration %d\n ", iClipDuration); |
| |
| // Prepare for playback |
| iState = STATE_PREPARE; |
| break; |
| |
| case STATE_PREPARE: |
| // Prepare succeeded |
| // Start playback |
| iState = STATE_START; |
| break; |
| |
| case STATE_START: |
| // Wait until EOS |
| iState = STATE_EOSNOTREACHED; |
| bWait = true; |
| break; |
| |
| case STATE_STOP: |
| // Engine stopped |
| // Remove the video sink |
| iState = STATE_REMOVEDATASINK_VIDEO; |
| break; |
| |
| case STATE_REMOVEDATASINK_VIDEO: |
| // Video sink removed |
| // Remove audio sink |
| iState = STATE_REMOVEDATASINK_AUDIO; |
| break; |
| |
| case STATE_REMOVEDATASINK_AUDIO: |
| // Audio sink removed |
| // Remove text sink |
| iState = STATE_REMOVEDATASINK_TEXT; |
| break; |
| |
| case STATE_REMOVEDATASINK_TEXT: |
| // Text sink removed |
| // Reset engine |
| iState = STATE_RESET; |
| break; |
| |
| case STATE_RESET: |
| // Engine reset |
| // Remove data source |
| iState = STATE_REMOVEDATASOURCE; |
| break; |
| |
| case STATE_REMOVEDATASOURCE: |
| // Data source removed |
| // Free resouces |
| iState = STATE_CLEANUPANDCOMPLETE; |
| break; |
| |
| default: |
| // engine error if this is reached |
| fprintf(file, "\nCommandCompleted unknown state %d\n ", iState); |
| iState = STATE_CLEANUPANDCOMPLETE; |
| break; |
| } // end switch |
| |
| if (bWait == false) |
| { |
| // schedule this object to run immediately |
| RunIfNotReady(); |
| } |
| |
| } |
| |
| |
| //////// |
| |
| // callback by PV engine when an error is encountered |
| void pvplayer_engine_interface::HandleErrorEvent(const PVAsyncErrorEvent& aEvent) |
| { |
| switch (aEvent.GetEventType()) |
| { |
| case PVMFErrResourceConfiguration: |
| case PVMFErrResource: |
| case PVMFErrCorrupt: |
| case PVMFErrProcessing: |
| // Just log the error for now |
| fprintf(file, "\nHandleErrorEvent event type %d\n ", aEvent.GetEventType()); |
| break; |
| |
| default: |
| // Unknown error and just log the error |
| fprintf(file, "\nHandleErrorEvent unknown event type %d\n ", aEvent.GetEventType()); |
| break; |
| } |
| } |
| |
| |
| //////// |
| |
| // callback by PV engine when information is available |
| void pvplayer_engine_interface::HandleInformationalEvent(const PVAsyncInformationalEvent& aEvent) |
| { |
| PVInterface* iface = (PVInterface*)(aEvent.GetEventExtensionInterface()); |
| |
| // Check for end of clip event and clip position event |
| if ((aEvent.GetEventType() == PVMFInfoEndOfData) || (aEvent.GetEventType() == PVMFInfoPositionStatus)) |
| { |
| if (iface == NULL) |
| { |
| return; |
| } |
| |
| PVUuid infomsguuid = PVMFErrorInfoMessageInterfaceUUID; |
| PVMFErrorInfoMessageInterface* infomsgiface = NULL; |
| if (iface->queryInterface(infomsguuid, (PVInterface*&)infomsgiface) == true) |
| { |
| int32 infocode; |
| PVUuid infouuid; |
| infomsgiface->GetCodeUUID(infocode, infouuid); |
| |
| if (infouuid == PVPlayerErrorInfoEventTypesUUID) |
| { |
| if (infocode == PVPlayerInfoEndOfClipReached) |
| { |
| fprintf(file, "\nEnd of Clip Reached\n "); |
| |
| // Playback has reached end of clip |
| // Stop the player |
| iState = STATE_STOP; |
| Cancel(); |
| RunIfNotReady(); |
| } |
| else if (infocode == PVPlayerInfoPlaybackPositionStatus) |
| { |
| // position update |
| // retrieve and display the media time |
| uint32 aPos = 0; |
| |
| uint8* localbuf = aEvent.GetLocalBuffer(); |
| if (aEvent.GetLocalBufferSize() == 8 && localbuf[0] == 1) |
| { |
| oscl_memcpy(&aPos, &localbuf[4], sizeof(uint32)); |
| } |
| |
| fprintf(file, " media time %d\r ", aPos); |
| fflush(file); |
| } |
| } |
| } |
| } |
| } |
| |
| |