3573 lines
121 KiB
C
Executable File
3573 lines
121 KiB
C
Executable File
/*
|
||
* Copyright (c) 2008-2016 Allwinner Technology Co. Ltd.
|
||
* All rights reserved.
|
||
*
|
||
* File : xplayer.c
|
||
* Description : xplayer
|
||
* History :
|
||
* Author : AL3
|
||
* Date : 2015/05/05
|
||
* Comment : first version
|
||
*
|
||
*/
|
||
|
||
#include "cdx_log.h"
|
||
#include "xplayer.h"
|
||
#include "demuxComponent.h"
|
||
#include <string.h>
|
||
#include <inttypes.h>
|
||
|
||
#include <version.h>
|
||
|
||
#include "player.h"
|
||
#include "demuxComponent.h"
|
||
#include "AwMessageQueue.h"
|
||
#include "layerControl.h"
|
||
#include "soundControl.h"
|
||
#include "subtitleControl.h"
|
||
#include "deinterlace.h"
|
||
#include "CdxParser.h"
|
||
#include <sys/time.h>
|
||
#include "CdxTime.h"
|
||
|
||
// pause then start to display, the cmcc apk call seekTo, it will flush the buffering cache(livemod)
|
||
// or seek some frames in cache ( vod) , it will discontinue
|
||
#define PAUSE_THEN_SEEK_BUG (1)
|
||
|
||
//* player status.
|
||
static const int XPLAYER_STATUS_IDLE = 0;
|
||
static const int XPLAYER_STATUS_INITIALIZED = 1<<0;
|
||
static const int XPLAYER_STATUS_PREPARING = 1<<1;
|
||
static const int XPLAYER_STATUS_PREPARED = 1<<2;
|
||
static const int XPLAYER_STATUS_STARTED = 1<<3;
|
||
static const int XPLAYER_STATUS_PAUSED = 1<<4;
|
||
static const int XPLAYER_STATUS_STOPPED = 1<<5;
|
||
static const int XPLAYER_STATUS_COMPLETE = 1<<6;
|
||
static const int XPLAYER_STATUS_ERROR = 1<<7;
|
||
|
||
//* command id.
|
||
static const int XPLAYER_COMMAND_SET_SOURCE = 0x101;
|
||
static const int XPLAYER_COMMAND_SET_SURFACE = 0x102;
|
||
static const int XPLAYER_COMMAND_SET_AUDIOSINK = 0x103;
|
||
static const int XPLAYER_COMMAND_PREPARE = 0x104;
|
||
static const int XPLAYER_COMMAND_START = 0x105;
|
||
static const int XPLAYER_COMMAND_STOP = 0x106;
|
||
static const int XPLAYER_COMMAND_PAUSE = 0x107;
|
||
static const int XPLAYER_COMMAND_RESET = 0x108;
|
||
static const int XPLAYER_COMMAND_QUIT = 0x109;
|
||
static const int XPLAYER_COMMAND_SEEK = 0x10a;
|
||
static const int XPLAYER_COMMAND_RESETURL = 0x10b;
|
||
static const int XPLAYER_COMMAND_SETSPEED = 0x10c;
|
||
static const int XPLAYER_COMMAND_SET_SUBCTRL = 0x10d;
|
||
static const int XPLAYER_COMMAND_SET_DI = 0x10e;
|
||
static const int XPLAYER_COMMAND_SET_PLAYRATE = 0x10f;
|
||
|
||
typedef struct PlayerContext
|
||
{
|
||
AwMessageQueue* mMessageQueue;
|
||
Player* mPlayer;
|
||
DemuxComp* mDemux;
|
||
pthread_t mThreadId;
|
||
int mThreadCreated;
|
||
uid_t mUID; //* no use.
|
||
|
||
//* data source.
|
||
char* mSourceUrl; //* file path or network stream url.
|
||
CdxStreamT* mSourceStream; //* outside streaming source like miracast.
|
||
|
||
int mSourceFd; //* file descriptor.
|
||
int64_t mSourceFdOffset;
|
||
int64_t mSourceFdLength;
|
||
|
||
//for setting scale down
|
||
//* bSetScaleDown = 0 means do not set scale down.
|
||
//* bSetScaleDown = 1 means scaling when the resolution is larger than 2k.
|
||
//* here the case of the VR9 call bSetScaleDown = 1.
|
||
//* bSetScaleDown = 2 means scaling at any resolution.
|
||
int bSetScaleDown;
|
||
|
||
//* media information.
|
||
MediaInfo* mMediaInfo;
|
||
|
||
//* text codec format of the subtitle, used to transform subtitle text to
|
||
//* utf8 when the subtitle text codec format is unknown.
|
||
char mDefaultTextFormat[32];
|
||
|
||
//* whether enable subtitle show.
|
||
int mIsSubtitleDisable;
|
||
|
||
//* file descriptor of .idx file of index+sub subtitle.
|
||
//* we save the .idx file's fd here because application set .idx file and .sub file
|
||
//* seperately, we need to wait for the .sub file's fd, see
|
||
//* INVOKE_ID_ADD_EXTERNAL_SOURCE_FD command in invoke() method.
|
||
int mIndexFileHasBeenSet;
|
||
int mIndexFileFdOfIndexSubtitle;
|
||
|
||
//* for status and synchronize control.
|
||
int mStatus;
|
||
pthread_mutex_t mMutexMediaInfo; //* for media info protection.
|
||
//* for mStatus protection in start/stop/pause operation and complete/seek finish callback.
|
||
pthread_mutex_t mMutexStatus;
|
||
sem_t mSemSetDataSource;
|
||
sem_t mSemPrepare;
|
||
sem_t mSemStart;
|
||
sem_t mSemStop;
|
||
sem_t mSemPause;
|
||
sem_t mSemQuit;
|
||
sem_t mSemReset;
|
||
sem_t mSemSeek;
|
||
sem_t mSemSetSurface;
|
||
sem_t mSemSetAudioSink;
|
||
sem_t mSemPrepareFinish;//* for signal prepare finish, used in prepare().
|
||
sem_t mSemSetSpeed;
|
||
sem_t mSemSetSubCtrl;
|
||
sem_t mSemSetDeinterlace;
|
||
sem_t mSemSetPlayBackSettings;
|
||
|
||
//* status control.
|
||
int mSetDataSourceReply;
|
||
int mPrepareReply;
|
||
int mStartReply;
|
||
int mStopReply;
|
||
int mPauseReply;
|
||
int mResetReply;
|
||
int mSeekReply;
|
||
int mSetSurfaceReply;
|
||
int mSetAudioSinkReply;
|
||
int mPrepareFinishResult; //* save the prepare result for prepare().
|
||
int mSetSpeedReply;
|
||
int mSetSubCtrlReply;
|
||
int mSetDeinterlaceReply;
|
||
int mSetPlayBackSettingsReply;
|
||
|
||
int mPrepareSync; //* synchroized prarare() call, don't call back to user.
|
||
int mSeeking;
|
||
int mSeekByInner;
|
||
|
||
//* use to check whether seek callback is for current seek operation or previous.
|
||
int mSeekTime;
|
||
SeekModeType mSeekModeType;
|
||
int mSeekSync; //* internal seek, don't call back to user.
|
||
int mLoop;
|
||
int mKeepLastFrame;
|
||
int mVideoSizeWidth; //* use to record videoSize which had send to app
|
||
int mVideoSizeHeight;
|
||
|
||
enum AwApplicationType mApplicationType;
|
||
|
||
void* mHTTPService;
|
||
|
||
//* record the id of subtitle which is displaying
|
||
//* we set the Nums to 64 .(32 may be not enough)
|
||
unsigned int mSubtitleDisplayIds[64];
|
||
int mSubtitleDisplayIdsUpdateIndex;
|
||
|
||
//* save the currentSelectTrackIndex;
|
||
int mCurrentSelectTrackIndex;
|
||
int mRawOccupyFlag;
|
||
|
||
int mLivemode;
|
||
int mPauseLivemode;
|
||
int mbIsDiagnose;
|
||
int64_t mPauseTimeStamp; //us
|
||
int64_t mShiftTimeStamp; //us
|
||
int mDisplayRatio;
|
||
int64_t mCurShiftTimeStamp; //us
|
||
int64_t mTimeShiftDuration; //ms
|
||
|
||
int mSeekTobug;
|
||
|
||
// the cmcc player should change pause state when buffer start, to fix getposition bug
|
||
int mDemuxNotifyPause;
|
||
int64_t mDemuxPauseTimeStamp;
|
||
|
||
//*
|
||
|
||
int mPreSeekTimeMs;
|
||
int mTimeMsBeforeStop; //softdetector
|
||
|
||
int mSpeed;
|
||
int mbFast;
|
||
int mFastTime;
|
||
int mSpeedThreadRuning;
|
||
pthread_t mSpeedThreadId;
|
||
|
||
int mScaledownFlag;
|
||
|
||
int mWidthScaledownRatio;
|
||
int mHeightScaledownRatio;
|
||
|
||
XPlayerNotifyCallback mCallback;
|
||
void* pUser;
|
||
AwBufferingSettings* pBuffering;
|
||
float gain;
|
||
}PlayerContext;
|
||
|
||
static void* XPlayerThread(void* arg);
|
||
static int ShiftTimeMode(int Shiftedms, char *buf);
|
||
static void clearMediaInfo(XPlayer* p);
|
||
static int callbackProcess(void *player, int messageId, void* param);
|
||
|
||
struct AwMessage {
|
||
AWMESSAGE_COMMON_MEMBERS
|
||
uintptr_t params[8];
|
||
};
|
||
|
||
XPlayer* XPlayerCreate()
|
||
{
|
||
logd("XPlayerCreate.");
|
||
XPlayer* mPriData;
|
||
LogVersionInfo();
|
||
mPriData = (PlayerContext*)malloc(sizeof(PlayerContext));
|
||
memset(mPriData,0x00,sizeof(PlayerContext));
|
||
|
||
mPriData->mUID = -1;
|
||
mPriData->mSourceUrl = NULL;
|
||
mPriData->mSourceFd = -1;
|
||
mPriData->mSourceFdOffset = 0;
|
||
mPriData->mSourceFdLength = 0;
|
||
mPriData->mSourceStream = NULL;
|
||
mPriData->mStatus = XPLAYER_STATUS_IDLE;
|
||
mPriData->mSeeking = 0;
|
||
mPriData->mSeekByInner = 0;
|
||
mPriData->mSeekSync = 0;
|
||
mPriData->mLoop = 0;
|
||
mPriData->mKeepLastFrame = 0;
|
||
mPriData->mMediaInfo = NULL;
|
||
mPriData->mMessageQueue = NULL;
|
||
mPriData->mVideoSizeWidth = 0;
|
||
mPriData->mVideoSizeHeight= 0;
|
||
mPriData->mScaledownFlag =0;
|
||
mPriData->mWidthScaledownRatio = 0;
|
||
mPriData->mHeightScaledownRatio = 0;
|
||
mPriData->mCurrentSelectTrackIndex = -1;
|
||
|
||
mPriData->mDemuxNotifyPause = 0;
|
||
|
||
#if PAUSE_THEN_SEEK_BUG
|
||
mPriData->mSeekTobug = 0;
|
||
#endif
|
||
|
||
mPriData->gain = DEFAULT_GAIN_IHW;
|
||
|
||
pthread_mutex_init(&mPriData->mMutexMediaInfo, NULL);
|
||
pthread_mutex_init(&mPriData->mMutexStatus, NULL);
|
||
sem_init(&mPriData->mSemSetDataSource, 0, 0);
|
||
sem_init(&mPriData->mSemPrepare, 0, 0);
|
||
sem_init(&mPriData->mSemStart, 0, 0);
|
||
sem_init(&mPriData->mSemStop, 0, 0);
|
||
sem_init(&mPriData->mSemPause, 0, 0);
|
||
sem_init(&mPriData->mSemReset, 0, 0);
|
||
sem_init(&mPriData->mSemQuit, 0, 0);
|
||
sem_init(&mPriData->mSemSeek, 0, 0);
|
||
sem_init(&mPriData->mSemSetSurface, 0, 0);
|
||
sem_init(&mPriData->mSemSetAudioSink, 0, 0);
|
||
sem_init(&mPriData->mSemSetSubCtrl, 0, 0);
|
||
sem_init(&mPriData->mSemSetDeinterlace, 0, 0);
|
||
|
||
sem_init(&mPriData->mSemPrepareFinish, 0, 0); //* for signal prepare finish, used in prepare().
|
||
sem_init(&mPriData->mSemSetSpeed, 0, 0);
|
||
sem_init(&mPriData->mSemSetPlayBackSettings, 0, 0);
|
||
|
||
mPriData->mMessageQueue = AwMessageQueueCreate(64, "XPlayer");
|
||
mPriData->mPlayer = PlayerCreate();
|
||
mPriData->mDemux = DemuxCompCreate();
|
||
|
||
if(mPriData->mPlayer != NULL)
|
||
PlayerSetCallback(mPriData->mPlayer, callbackProcess, (void*)mPriData);
|
||
|
||
if(mPriData->mDemux != NULL)
|
||
{
|
||
DemuxCompSetCallback(mPriData->mDemux, callbackProcess, (void*)mPriData);
|
||
DemuxCompSetPlayer(mPriData->mDemux, mPriData->mPlayer);
|
||
}
|
||
|
||
if(pthread_create(&mPriData->mThreadId, NULL, XPlayerThread, mPriData) == 0)
|
||
mPriData->mThreadCreated = 1;
|
||
else
|
||
mPriData->mThreadCreated = 0;
|
||
|
||
strcpy(mPriData->mDefaultTextFormat, "GBK");
|
||
|
||
mPriData->mIndexFileFdOfIndexSubtitle = -1;
|
||
mPriData->mIndexFileHasBeenSet = 0;
|
||
memset(mPriData->mSubtitleDisplayIds,0xff,64*sizeof(unsigned int));
|
||
mPriData->mSubtitleDisplayIdsUpdateIndex = 0;
|
||
mPriData->mApplicationType = APP_DEFAULT;
|
||
mPriData->mRawOccupyFlag = 0;
|
||
|
||
mPriData->mSpeed = 1;
|
||
mPriData->mbFast = 0;
|
||
mPriData->mFastTime = 0;
|
||
mPriData->mSpeedThreadRuning = 0;
|
||
|
||
return mPriData;
|
||
}
|
||
|
||
|
||
void XPlayerDestroy(XPlayer* p)
|
||
{
|
||
AwMessage msg;
|
||
XPlayer* mPriData;
|
||
int param_occupy[3] = {1,0,0};
|
||
int param_release[3] = {0,0,0};
|
||
logw("XPlayerDestroy");
|
||
|
||
mPriData = (XPlayer*)p;
|
||
if(mPriData->mThreadCreated)
|
||
{
|
||
void* status;
|
||
|
||
XPlayerReset(p); //* stop demux and player.
|
||
|
||
//* send a quit message to quit the main thread.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_QUIT;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemQuit;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemQuit, -1);
|
||
pthread_join(mPriData->mThreadId, &status);
|
||
}
|
||
|
||
if (mPriData->mSpeedThreadRuning == 1)
|
||
{
|
||
void* status;
|
||
mPriData->mSpeedThreadRuning = 0;
|
||
pthread_join(mPriData->mSpeedThreadId,&status);
|
||
}
|
||
|
||
if(mPriData->mDemux != NULL)
|
||
DemuxCompDestroy(mPriData->mDemux);
|
||
|
||
if(mPriData->mPlayer != NULL)
|
||
PlayerDestroy(mPriData->mPlayer);
|
||
|
||
if(mPriData->mMessageQueue != NULL)
|
||
{
|
||
AwMessageQueueDestroy(mPriData->mMessageQueue);
|
||
mPriData->mMessageQueue = NULL;
|
||
}
|
||
|
||
pthread_mutex_destroy(&mPriData->mMutexMediaInfo);
|
||
pthread_mutex_destroy(&mPriData->mMutexStatus);
|
||
sem_destroy(&mPriData->mSemSetDataSource);
|
||
sem_destroy(&mPriData->mSemPrepare);
|
||
sem_destroy(&mPriData->mSemStart);
|
||
sem_destroy(&mPriData->mSemStop);
|
||
sem_destroy(&mPriData->mSemPause);
|
||
sem_destroy(&mPriData->mSemReset);
|
||
sem_destroy(&mPriData->mSemQuit);
|
||
sem_destroy(&mPriData->mSemSeek);
|
||
sem_destroy(&mPriData->mSemSetSurface);
|
||
sem_destroy(&mPriData->mSemSetAudioSink);
|
||
sem_destroy(&mPriData->mSemPrepareFinish);
|
||
sem_destroy(&mPriData->mSemSetSpeed);
|
||
sem_destroy(&mPriData->mSemSetSubCtrl);
|
||
sem_destroy(&mPriData->mSemSetDeinterlace);
|
||
sem_destroy(&mPriData->mSemSetPlayBackSettings);
|
||
|
||
if(mPriData->mMediaInfo != NULL)
|
||
clearMediaInfo(p);
|
||
|
||
if(mPriData->mSourceUrl != NULL)
|
||
free(mPriData->mSourceUrl);
|
||
|
||
if(mPriData->mSourceFd != -1)
|
||
close(mPriData->mSourceFd);
|
||
|
||
if(mPriData->mIndexFileFdOfIndexSubtitle != -1)
|
||
close(mPriData->mIndexFileFdOfIndexSubtitle);
|
||
|
||
if (mPriData)
|
||
{
|
||
free(mPriData);
|
||
mPriData = NULL;
|
||
}
|
||
}
|
||
|
||
int XPlayerConfig(XPlayer* p, const XPlayerConfig_t *config)
|
||
{
|
||
p->mLivemode = config->livemode;
|
||
p->mApplicationType = config->appType;
|
||
return 0;
|
||
}
|
||
|
||
int XPlayerInitCheck(XPlayer* p)
|
||
{
|
||
logv("initCheck");
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(mPriData->mPlayer == NULL || mPriData->mDemux == NULL || mPriData->mThreadCreated == 0)
|
||
{
|
||
loge("initCheck() fail, XPlayer::mplayer = %p, XPlayer::mDemux = %p",
|
||
mPriData->mPlayer, mPriData->mDemux);
|
||
return -1;
|
||
}
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
|
||
int XPlayerSetUID(XPlayer* p, int nUid)
|
||
{
|
||
(void)nUid;
|
||
(void)p;
|
||
logv("setUID(), uid = %d", nUid);
|
||
//mPriData->mUID = uid;
|
||
return 0;
|
||
}
|
||
|
||
int XPlayerSetHdcpOps(XPlayer* p, struct HdcpOpsS* pHdcp)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(mPriData->mStatus != XPLAYER_STATUS_IDLE &&
|
||
mPriData->mStatus != XPLAYER_STATUS_INITIALIZED)
|
||
{
|
||
logw("set hdcp ops incorrect. status: %d", mPriData->mStatus);
|
||
return -1;
|
||
}
|
||
|
||
if(p->mDemux)
|
||
DemuxCompSetHdcpOps(p->mDemux, pHdcp);
|
||
return 0;
|
||
}
|
||
|
||
int XPlayerSetScaleDown(XPlayer* p,int bSetScaleDown)
|
||
{
|
||
if(p != NULL)
|
||
{
|
||
p->bSetScaleDown = bSetScaleDown;
|
||
logd("XPlayer set scale down.p->bSetScaleDown:%d",p->bSetScaleDown);
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
loge("xplayer set scale down error!");
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
int XPlayerSetDataSourceUrl(XPlayer* p,
|
||
const char* pUrl,
|
||
void* httpService,
|
||
const CdxKeyedVectorT* pHeaders)
|
||
{
|
||
AwMessage msg;
|
||
int ret;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
if(pUrl == NULL)
|
||
{
|
||
loge("setDataSource(url), url=NULL");
|
||
return -1;
|
||
}
|
||
|
||
logd("setDataSource(url), url='%s'", pUrl);
|
||
|
||
DemuxCompSetLiveMode(mPriData->mDemux, p->mLivemode);
|
||
|
||
mPriData->mHTTPService = httpService;
|
||
PlayerConfigDispErrorFrame(mPriData->mPlayer, 0);
|
||
|
||
//* send a set data source message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SET_SOURCE;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSetDataSource;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSetDataSourceReply;
|
||
msg.params[2] = SOURCE_TYPE_URL;
|
||
msg.params[3] = (uintptr_t)pUrl;
|
||
msg.params[4] = (uintptr_t)pHeaders;
|
||
msg.params[5] = (uintptr_t)(mPriData->mHTTPService);
|
||
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSetDataSource, -1);
|
||
|
||
if(mPriData->mSetDataSourceReply != 0)
|
||
return mPriData->mSetDataSourceReply;
|
||
|
||
//* for local file, I think we should ack like file descriptor source,
|
||
//* so here we call prepare().
|
||
//* local file list: 'bdmv://---', '/---'
|
||
if (strncmp(pUrl, "bdmv://", 7) == 0 || strncmp(pUrl, "file://", 7) == 0 || pUrl[0] == '/')
|
||
{
|
||
//* for local file source set as a file descriptor,
|
||
//* the application will call invoke() by command INVOKE_ID_GET_TRACK_INFO
|
||
//* to get track info, so we need call prepare() here to obtain media information before
|
||
//* application call prepareAsync().
|
||
//* here I think for local file source set as a url, we should ack the same as the file
|
||
//* descriptor case.
|
||
ret = XPlayerPrepare(p);
|
||
if (ret != 0)
|
||
{
|
||
loge("prepare failure, ret(%d)", ret);
|
||
}
|
||
return ret;
|
||
}
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
|
||
//* Warning: The filedescriptor passed into this method will only be valid until
|
||
//* the method returns, if you want to keep it, dup it!
|
||
int XPlayerSetDataSourceFd(XPlayer* p, int fd, int64_t offset, int64_t length)
|
||
{
|
||
AwMessage msg;
|
||
int ret = 0;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
logv("setDataSource(fd), fd=%d", fd);
|
||
|
||
PlayerConfigDispErrorFrame(mPriData->mPlayer, 0);
|
||
//* send a set data source message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SET_SOURCE;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSetDataSource;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSetDataSourceReply;
|
||
msg.params[2] = SOURCE_TYPE_FD;
|
||
msg.params[3] = fd;
|
||
msg.params[4] = (uintptr_t)(offset>>32); //* params[4] = high 32 bits of offset.
|
||
msg.params[5] = (uintptr_t)(offset & 0xffffffff);//* params[5] = low 32 bits of offset.
|
||
msg.params[6] = (uintptr_t)(length>>32); //* params[6] = high 32 bits of length.
|
||
msg.params[7] = (uintptr_t)(length & 0xffffffff);//* params[7] = low 32 bits of length.
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSetDataSource, -1);
|
||
|
||
if(mPriData->mSetDataSourceReply != 0)
|
||
return mPriData->mSetDataSourceReply;
|
||
|
||
#if !defined(CONF_SET_SCALEDOWN_MODE)
|
||
//* for local files, the application will call invoke() by command INVOKE_ID_GET_TRACK_INFO
|
||
//* to get track info, so we need call prepare() here to obtain media information before
|
||
//* application call prepareAsync().
|
||
ret = XPlayerPrepare(p);
|
||
if (ret != 0)
|
||
{
|
||
loge("prepare failure, ret(%d)", ret);
|
||
}
|
||
#endif
|
||
return ret;
|
||
}
|
||
|
||
int XPlayerSetDataSourceStream(XPlayer* p, const char* streamStr)
|
||
{
|
||
AwMessage msg;
|
||
logd("setDataSource(IStreamSource)");
|
||
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
PlayerConfigDispErrorFrame(mPriData->mPlayer, 1);
|
||
|
||
//* send a set data source message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SET_SOURCE;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSetDataSource;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSetDataSourceReply;
|
||
msg.params[2] = SOURCE_TYPE_ISTREAMSOURCE;
|
||
msg.params[3] = (uintptr_t)streamStr;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSetDataSource, -1);
|
||
return mPriData->mSetDataSourceReply;
|
||
}
|
||
|
||
int XPlayerSetMediaDataSource(XPlayer* p, const char* streamStr)
|
||
{
|
||
AwMessage msg;
|
||
logd("setDataSource(MediaDataSource)");
|
||
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
PlayerConfigDispErrorFrame(mPriData->mPlayer, 1);
|
||
|
||
//* send a set data source message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SET_SOURCE;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSetDataSource;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSetDataSourceReply;
|
||
msg.params[2] = SOURCE_TYPE_DATASOURCE;
|
||
msg.params[3] = (uintptr_t)streamStr;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSetDataSource, -1);
|
||
return mPriData->mSetDataSourceReply;
|
||
}
|
||
|
||
|
||
//* set video layer control ops
|
||
int XPlayerSetVideoSurfaceTexture(XPlayer* p, const LayerCtrl* surfaceTexture)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logd("setVideoSurfaceTexture, surface = %p", surfaceTexture);
|
||
|
||
//* send a set surface message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SET_SURFACE;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSetSurface;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSetSurfaceReply;
|
||
msg.params[2] = (uintptr_t)surfaceTexture;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSetSurface, -1);
|
||
|
||
return mPriData->mSetSurfaceReply;
|
||
}
|
||
|
||
void XPlayerSetAudioSink(XPlayer* p, const SoundCtrl* audioSink)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logv("setAudioSink");
|
||
|
||
//* send a set audio sink message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SET_AUDIOSINK;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSetAudioSink;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSetAudioSinkReply;
|
||
msg.params[2] = (uintptr_t)audioSink;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSetAudioSink, -1);
|
||
|
||
return;
|
||
}
|
||
|
||
int XPlayerSetPlaybackSettings(XPlayer* p,const XAudioPlaybackRate *rate)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
//* send a set set playback message.
|
||
AwMessage msg;
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SET_PLAYRATE;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSetPlayBackSettings;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSetPlayBackSettingsReply;
|
||
msg.params[2] = (uintptr_t)rate;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSetPlayBackSettings, -1);
|
||
|
||
if (rate->mSpeed == 0.f && mPriData->mStatus == XPLAYER_STATUS_STARTED)
|
||
{
|
||
logd("PlayerPause");
|
||
XPlayerPause(p);
|
||
}
|
||
else if (rate->mSpeed != 0.f && (mPriData->mStatus == XPLAYER_STATUS_PAUSED
|
||
|| mPriData->mStatus == XPLAYER_STATUS_PREPARED
|
||
|| mPriData->mStatus == XPLAYER_STATUS_COMPLETE))
|
||
{
|
||
XPlayerStart(p);
|
||
}
|
||
|
||
return mPriData->mSetPlayBackSettingsReply;
|
||
}
|
||
|
||
int XPlayerGetPlaybackSettings(XPlayer* p,XAudioPlaybackRate *rate)
|
||
{
|
||
logd("XPlayerGetPlaybackSettings");
|
||
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
int ret = PlayerGetPlayBackSettings(mPriData->mPlayer,rate);
|
||
|
||
if (ret == 0)
|
||
{
|
||
if (mPriData->mStatus == XPLAYER_STATUS_PAUSED)
|
||
{
|
||
rate->mSpeed = 0.f;
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
void XPlayerSetSubCtrl(XPlayer* p, const SubCtrl* subctrl)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logv("setSubRender");
|
||
//* send a set audio sink message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SET_SUBCTRL;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSetSubCtrl;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSetSubCtrlReply;
|
||
msg.params[2] = (uintptr_t)subctrl;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSetSubCtrl, -1);
|
||
|
||
return;
|
||
}
|
||
|
||
void XPlayerSetDeinterlace(XPlayer* p, const Deinterlace* di)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logd("set deinterlace");
|
||
//* send a set audio sink message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SET_DI;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSetDeinterlace;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSetDeinterlaceReply;
|
||
msg.params[2] = (uintptr_t)di;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSetDeinterlace, -1);
|
||
|
||
return;
|
||
}
|
||
|
||
int XPlayerSetNotifyCallback(XPlayer* p,
|
||
XPlayerNotifyCallback notifier,
|
||
void* pUserData)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
mPriData->mCallback = notifier;
|
||
mPriData->pUser = pUserData;
|
||
|
||
return 0;
|
||
}
|
||
|
||
int XPlayerPrepareAsync(XPlayer* p)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logd("prepareAsync");
|
||
|
||
//* send a prepare.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_PREPARE;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemPrepare;
|
||
msg.params[1] = (uintptr_t)&mPriData->mPrepareReply;
|
||
msg.params[2] = 0;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemPrepare, -1);
|
||
|
||
return mPriData->mPrepareReply;
|
||
}
|
||
|
||
|
||
int XPlayerPrepare(XPlayer* p)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logd("prepare");
|
||
|
||
//* clear the mSemPrepareFinish semaphore.
|
||
while(sem_trywait(&mPriData->mSemPrepareFinish) == 0);
|
||
|
||
//* send a prepare message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_PREPARE;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemPrepare;
|
||
msg.params[1] = (uintptr_t)&mPriData->mPrepareReply;
|
||
msg.params[2] = 1; //* params[2] = mPrepareSync.
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemPrepare, -1);
|
||
|
||
if(mPriData->mPrepareReply == 0)
|
||
{
|
||
//* wait for the prepare finish.
|
||
SemTimedWait(&mPriData->mSemPrepareFinish, -1);
|
||
return mPriData->mPrepareFinishResult;
|
||
}
|
||
|
||
//* call DemuxCompPrepareAsync() fail, or status error.
|
||
return mPriData->mPrepareReply;
|
||
}
|
||
|
||
int XPlayerStart(XPlayer* p)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logd("start");
|
||
|
||
// in washu cmcc for livemode 1, we should call seekTo when paused longer than 30s
|
||
mPriData->mLivemode = DemuxCompGetLiveMode(mPriData->mDemux);
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PAUSED &&
|
||
mPriData->mLivemode == 1 &&
|
||
mPriData->mApplicationType == APP_CMCC_WASU)
|
||
{
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
int shiftTimeMs = (tv.tv_sec * 1000000ll + tv.tv_usec - mPriData->mPauseTimeStamp)/1000;
|
||
if(shiftTimeMs > 30*1000 && !mPriData->mSeekTobug && (mPriData->mPauseLivemode!=2))
|
||
{
|
||
logd("pause time longer than 30s in livemode 1, seekTo(%d)", shiftTimeMs);
|
||
XPlayerSeekTo(p, shiftTimeMs, mPriData->mSeekModeType);
|
||
}
|
||
}
|
||
|
||
#if (PAUSE_THEN_SEEK_BUG)
|
||
if(mPriData->mSeekTobug && mPriData->mApplicationType == APP_CMCC_WASU)
|
||
{
|
||
mPriData->mSeekTobug = 0;
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_SEEK_COMPLETE, 0, 0);
|
||
}
|
||
#endif
|
||
|
||
//* send a start message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_START;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemStart;
|
||
msg.params[1] = (uintptr_t)&mPriData->mStartReply;
|
||
msg.params[2] = (uintptr_t)&mPriData->gain;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemStart, -1);
|
||
return mPriData->mStartReply;
|
||
}
|
||
|
||
int XPlayerStartWithGain(XPlayer * p, float gain)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
mPriData->gain = gain;
|
||
XPlayerStart(p);
|
||
return 0;
|
||
}
|
||
|
||
int XPlayerStop(XPlayer* p)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logd("stop");
|
||
XPlayerGetCurrentPosition(mPriData, &mPriData->mTimeMsBeforeStop); //softdetector
|
||
|
||
//* send a stop message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_STOP;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemStop;
|
||
msg.params[1] = (uintptr_t)&mPriData->mStopReply;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemStop, -1);
|
||
|
||
logd("=== stop end");
|
||
return mPriData->mStopReply;
|
||
}
|
||
|
||
|
||
int XPlayerPause(XPlayer* p)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logd("pause");
|
||
|
||
mPriData->mLivemode = DemuxCompGetLiveMode(mPriData->mDemux);
|
||
mPriData->mPauseLivemode = mPriData->mLivemode;
|
||
if(mPriData->mLivemode == 1)
|
||
{
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
mPriData->mPauseTimeStamp = tv.tv_sec * 1000000ll + tv.tv_usec;
|
||
logd("livemode1, get current position inmPauseTimeStamp = %" PRId64 "",
|
||
mPriData->mPauseTimeStamp);
|
||
}
|
||
else if(mPriData->mLivemode == 2)
|
||
{
|
||
int msec;
|
||
XPlayerGetCurrentPosition(p, &msec);
|
||
logd("get current position in pause: %d", msec);
|
||
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
mPriData->mPauseTimeStamp = tv.tv_sec * 1000000ll + tv.tv_usec - (int64_t)msec*1000;
|
||
logd("get current position in pause, nowUs = %ld, mPauseTimeStamp = %" PRId64 "",
|
||
tv.tv_sec * 1000000 + tv.tv_usec, mPriData->mPauseTimeStamp);
|
||
}
|
||
|
||
//* send a pause message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_PAUSE;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemPause;
|
||
msg.params[1] = (uintptr_t)&mPriData->mPauseReply;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemPause, -1);
|
||
return mPriData->mPauseReply;
|
||
}
|
||
|
||
int XPlayerSeekTo(XPlayer* p, int nSeekTimeMs, SeekModeType nSeekModeType)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logd("seekTo [%dms]", nSeekTimeMs);
|
||
mPriData->mSeekModeType = nSeekModeType;
|
||
|
||
mPriData->mLivemode = DemuxCompGetLiveMode(mPriData->mDemux);
|
||
|
||
#if (PAUSE_THEN_SEEK_BUG)
|
||
if((mPriData->mStatus == XPLAYER_STATUS_PAUSED
|
||
/*|| mPriData->mStatus == XPLAYER_STATUS_STARTED */) &&
|
||
mPriData->mApplicationType == APP_CMCC_WASU)
|
||
{
|
||
int pos;
|
||
XPlayerGetCurrentPosition(p, &pos);
|
||
int diff = pos - nSeekTimeMs;
|
||
logd("diff = %d", diff);
|
||
if(-1000 < diff && diff < 1000)
|
||
{
|
||
if(mPriData->mLivemode == 1 && mPriData->mStatus == XPLAYER_STATUS_PAUSED)
|
||
{
|
||
// if livemod1, we should change it to livemode2
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
DemuxCompSetLiveMode(mPriData->mDemux, 2);
|
||
mPriData->mShiftTimeStamp = tv.tv_sec * 1000000ll + tv.tv_usec - nSeekTimeMs*1000ll;
|
||
}
|
||
mPriData->mSeekTobug = 1;
|
||
return XPlayerStart(p);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
if(mPriData->mLivemode == 1 || mPriData->mLivemode == 2)
|
||
{
|
||
logd("++++++ reset url");
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
mPriData->mShiftTimeStamp = tv.tv_sec * 1000000ll + tv.tv_usec;
|
||
mPriData->mPreSeekTimeMs = nSeekTimeMs + 20000; //* for timeshift
|
||
|
||
//* send a start message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_RESETURL;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSeek;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSeekReply;
|
||
msg.params[2] = nSeekTimeMs; //* params[2] = mSeekTime.
|
||
//* params[3] = mSeekSync.
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSeek, -1);
|
||
}
|
||
else
|
||
{
|
||
logd("seek");
|
||
mPriData->mSeekByInner = 0;
|
||
//* send a start message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SEEK;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSeek;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSeekReply;
|
||
msg.params[2] = nSeekTimeMs; //* params[2] = mSeekTime.
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSeek, -1);
|
||
|
||
}
|
||
|
||
return mPriData->mSeekReply;
|
||
}
|
||
|
||
int XPlayerReset(XPlayer* p)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logw("reset...");
|
||
XPlayerGetCurrentPosition(mPriData, &mPriData->mTimeMsBeforeStop); //softdetector
|
||
|
||
//* send a start message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_RESET;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemReset;
|
||
msg.params[1] = (uintptr_t)&mPriData->mResetReply;
|
||
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemReset, -1);
|
||
return mPriData->mResetReply;
|
||
}
|
||
|
||
int XPlayerSetSpeed(XPlayer* p, int nSpeed)
|
||
{
|
||
AwMessage msg;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logd("XPlayerSetSpeed %d",nSpeed);
|
||
mPriData->mSpeed = nSpeed;
|
||
//PlayerSetSpeed(mPriData->mPlayer, nSpeed);
|
||
|
||
if(nSpeed == 1)
|
||
{
|
||
mPriData->mbFast = 0;
|
||
mPriData->mSpeed = 1;
|
||
mPriData->mFastTime = 0;
|
||
XPlayerStart(p);
|
||
PlayerSetDiscardAudio(mPriData->mPlayer, 0);
|
||
return 0;
|
||
}
|
||
|
||
//* send a start message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SETSPEED;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSetSpeed;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSetSpeedReply;
|
||
msg.params[2] = nSpeed;
|
||
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
SemTimedWait(&mPriData->mSemSetSpeed, -1);
|
||
|
||
return mPriData->mSetSpeedReply;
|
||
}
|
||
|
||
int XPlayerIsPlaying(XPlayer* p)
|
||
{
|
||
logi("isPlaying");
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(mPriData->mStatus == XPLAYER_STATUS_STARTED ||
|
||
(mPriData->mStatus == XPLAYER_STATUS_COMPLETE && mPriData->mLoop != 0))
|
||
return 1;
|
||
|
||
return 0;
|
||
}
|
||
|
||
MediaInfo* XPlayerGetMediaInfo(XPlayer* p)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PREPARING ||
|
||
mPriData->mStatus == XPLAYER_STATUS_INITIALIZED||
|
||
mPriData->mStatus == XPLAYER_STATUS_IDLE )
|
||
{
|
||
loge("cannot get mediainfo in this status");
|
||
return NULL;
|
||
}
|
||
|
||
return mPriData->mMediaInfo;
|
||
}
|
||
|
||
int XPlayerGetCurrentPosition(XPlayer* p, int* msec)
|
||
{
|
||
int64_t nPositionUs;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
logv("getCurrentPosition");
|
||
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PREPARED ||
|
||
mPriData->mStatus == XPLAYER_STATUS_STARTED ||
|
||
mPriData->mStatus == XPLAYER_STATUS_PAUSED ||
|
||
mPriData->mStatus == XPLAYER_STATUS_COMPLETE)
|
||
{
|
||
if(mPriData->mSeeking != 0)
|
||
{
|
||
*msec = mPriData->mSeekTime;
|
||
return 0;
|
||
}
|
||
|
||
mPriData->mLivemode = DemuxCompGetLiveMode(mPriData->mDemux);
|
||
if(mPriData->mLivemode == 1)
|
||
{
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PAUSED)
|
||
{
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
*msec = (tv.tv_sec * 1000000ll + tv.tv_usec - mPriData->mPauseTimeStamp)/1000;
|
||
}
|
||
else if(mPriData->mDemuxNotifyPause)
|
||
{
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
*msec = (tv.tv_sec * 1000000ll + tv.tv_usec - mPriData->mDemuxPauseTimeStamp)/1000;
|
||
}
|
||
else
|
||
{
|
||
*msec = 0;
|
||
}
|
||
|
||
if(*msec < 0) *msec = 0;
|
||
|
||
return 0;
|
||
}
|
||
else if(mPriData->mLivemode == 2)
|
||
{
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PAUSED)
|
||
{
|
||
*msec = (tv.tv_sec * 1000000 + tv.tv_usec - mPriData->mPauseTimeStamp)/1000;
|
||
logd("livemode2, nowUs = %ld, mPauseTimeStamp = %" PRId64 "",
|
||
tv.tv_sec * 1000000 + tv.tv_usec, mPriData->mPauseTimeStamp);
|
||
}
|
||
else
|
||
{
|
||
//cmcc livemode2 only support ts
|
||
nPositionUs = PlayerGetPositionCMCC(mPriData->mPlayer);
|
||
logd("-- nPositionUs = %" PRId64 "", nPositionUs);
|
||
*msec = (tv.tv_sec * 1000000LL + tv.tv_usec -
|
||
mPriData->mShiftTimeStamp + nPositionUs)/1000;
|
||
}
|
||
|
||
if(*msec < 0)
|
||
{
|
||
logd("positon < 0 ,check it!!");
|
||
*msec = 0;
|
||
}
|
||
logd("livemode = 2, getCurrentPosition %d", *msec);
|
||
|
||
return 0;
|
||
}
|
||
|
||
//* in complete status, the prepare() method maybe called and it change the media info.
|
||
pthread_mutex_lock(&mPriData->mMutexMediaInfo);
|
||
if(mPriData->mMediaInfo != NULL)
|
||
{
|
||
//* ts stream's pts is not started at 0.
|
||
if(mPriData->mMediaInfo->eContainerType == CONTAINER_TYPE_TS ||
|
||
mPriData->mMediaInfo->eContainerType == CONTAINER_TYPE_BD ||
|
||
mPriData->mMediaInfo->eContainerType == CONTAINER_TYPE_HLS)
|
||
nPositionUs = PlayerGetPosition(mPriData->mPlayer);
|
||
else //* generally, stream pts is started at 0 except ts stream.
|
||
nPositionUs = PlayerGetPts(mPriData->mPlayer);
|
||
*msec = (nPositionUs + 500)/1000;
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
loge("getCurrentPosition() fail, mMediaInfo==NULL.");
|
||
*msec = 0;
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
return 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
*msec = 0;
|
||
|
||
if(mPriData->mStatus == XPLAYER_COMMAND_STOP && mPriData->mTimeMsBeforeStop >= 0)
|
||
*msec = mPriData->mTimeMsBeforeStop;
|
||
|
||
if(mPriData->mStatus == XPLAYER_STATUS_ERROR)
|
||
return -1;
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
|
||
int XPlayerGetDuration(XPlayer* p, int *msec)
|
||
{
|
||
logv("getDuration");
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PREPARED ||
|
||
mPriData->mStatus == XPLAYER_STATUS_STARTED ||
|
||
mPriData->mStatus == XPLAYER_STATUS_PAUSED ||
|
||
mPriData->mStatus == XPLAYER_STATUS_STOPPED ||
|
||
mPriData->mStatus == XPLAYER_STATUS_COMPLETE)
|
||
{
|
||
//* in complete status, the prepare() method maybe called and it change the media info.
|
||
pthread_mutex_lock(&mPriData->mMutexMediaInfo);
|
||
if(mPriData->mMediaInfo != NULL)
|
||
*msec = mPriData->mMediaInfo->nDurationMs;
|
||
else
|
||
{
|
||
loge("getCurrentPosition() fail, mPriData->mMediaInfo==NULL.");
|
||
*msec = 0;
|
||
}
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
return 0;
|
||
}
|
||
|
||
loge("invalid getDuration() call, player not in valid status.");
|
||
return -1;
|
||
}
|
||
|
||
|
||
int XPlayerSetLooping(XPlayer* p, int loop)
|
||
{
|
||
logd("setLooping");
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
if(mPriData->mStatus == XPLAYER_STATUS_ERROR)
|
||
return -1;
|
||
|
||
mPriData->mLoop = loop;
|
||
return 0;
|
||
}
|
||
|
||
int updateVideoInfo(XPlayer* p)
|
||
{
|
||
//* get media information.
|
||
MediaInfo* mi;
|
||
VideoStreamInfo* vi;
|
||
int ret;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
pthread_mutex_lock(&mPriData->mMutexMediaInfo);
|
||
|
||
mi = DemuxCompGetMediaInfo(mPriData->mDemux);
|
||
if(mi == NULL)
|
||
{
|
||
loge("can not get media info from demux.");
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
return -1;
|
||
}
|
||
clearMediaInfo(p);
|
||
mPriData->mMediaInfo = mi;
|
||
|
||
#if !AWPLAYER_CONFIG_DISABLE_VIDEO
|
||
if(mi->pVideoStreamInfo != NULL)
|
||
{
|
||
#if !defined(CONF_3D_ENABLE)
|
||
if(mi->pVideoStreamInfo->bIs3DStream == 1)
|
||
mi->pVideoStreamInfo->bIs3DStream = 0;
|
||
#endif
|
||
|
||
ret = PlayerSetVideoStreamInfo(mPriData->mPlayer, mi->pVideoStreamInfo);
|
||
if(ret != 0)
|
||
{
|
||
logw("PlayerSetVideoStreamInfo() fail, video stream not supported.");
|
||
}
|
||
}
|
||
#endif
|
||
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
return 0;
|
||
}
|
||
|
||
int updateAudioInfo(XPlayer* p)
|
||
{
|
||
//* get media information.
|
||
MediaInfo* mi;
|
||
AudioStreamInfo* vi;
|
||
int ret;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
pthread_mutex_lock(&mPriData->mMutexMediaInfo);
|
||
|
||
mi = DemuxCompGetMediaInfo(mPriData->mDemux);
|
||
if(mi == NULL)
|
||
{
|
||
loge("can not get media info from demux.");
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
return -1;
|
||
}
|
||
clearMediaInfo(p);
|
||
mPriData->mMediaInfo = mi;
|
||
|
||
#if !AWPLAYER_CONFIG_DISABLE_AUDIO
|
||
if(mi->pAudioStreamInfo != NULL)
|
||
{
|
||
int i;
|
||
int nDefaultAudioIndex;
|
||
|
||
nDefaultAudioIndex = -1;
|
||
for(i=0; i<mi->nAudioStreamNum; i++)
|
||
{
|
||
if(PlayerCanSupportAudioStream(mPriData->mPlayer, &mi->pAudioStreamInfo[i]))
|
||
{
|
||
nDefaultAudioIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(nDefaultAudioIndex < 0)
|
||
{
|
||
logw("no audio stream supported.");
|
||
nDefaultAudioIndex = 0;
|
||
}
|
||
|
||
//* 1. stop audio
|
||
PlayerStopAudio(mPriData->mPlayer);
|
||
//* 2. set stream info
|
||
ret = PlayerSetAudioStreamInfo(mPriData->mPlayer, mi->pAudioStreamInfo,
|
||
mi->nAudioStreamNum, nDefaultAudioIndex);
|
||
if(ret != 0)
|
||
{
|
||
logw("PlayerSetAudioStreamInfo() fail, audio stream not supported.");
|
||
}
|
||
}
|
||
#endif
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
return 0;
|
||
}
|
||
|
||
|
||
/*
|
||
*ret 1 means need to scale down
|
||
* 0 is do nothing
|
||
* -1 is unknown error
|
||
* */
|
||
/*A80 general 4K -> do nothing (0)*/
|
||
/*H3/H8 general 4K -> Scale down (1)*/
|
||
/*H3 H265 4K -> do nothing (0)*/
|
||
int getScaledownFlag(const MediaInfo *mi,int bSetScaleDown)
|
||
{
|
||
int ret = 0; /* default not scaledown */
|
||
|
||
if(bSetScaleDown == 1)
|
||
{
|
||
if(mi->pVideoStreamInfo->nWidth > WIDTH_1080P || mi->pVideoStreamInfo->nHeight > HEIGHT_1080P)
|
||
{
|
||
logd("###source file larger than 2k,scale down.");
|
||
ret = 1;
|
||
}
|
||
}
|
||
else if(bSetScaleDown == 2)
|
||
{
|
||
logd("set scale down in any resolution.");
|
||
ret = 1;
|
||
}
|
||
|
||
if(mi->pVideoStreamInfo->nWidth >= WIDTH_4K || mi->pVideoStreamInfo->nHeight >= HEIGHT_4K)
|
||
{
|
||
if (mi->pVideoStreamInfo->eCodecFormat == VIDEO_CODEC_FORMAT_H265)
|
||
{
|
||
#if !defined(CONF_H265_4K_P2P) /* only H3/H5 support H.265 p2p */
|
||
ret = 1;
|
||
#endif
|
||
}
|
||
else if (mi->pVideoStreamInfo->eCodecFormat == VIDEO_CODEC_FORMAT_H264)
|
||
{
|
||
#if !defined(CONF_H264_4K_P2P) /* only A80 support H.264 p2p */
|
||
ret = 1;
|
||
#endif
|
||
}
|
||
else if (mi->pVideoStreamInfo->eCodecFormat == VIDEO_CODEC_FORMAT_VP9)
|
||
{
|
||
ret = 0;
|
||
}
|
||
else /* all other codec format should scaledown for 4K size */
|
||
{
|
||
ret = 1;
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
int XPlayerSetScaleDownRatio(XPlayer* p,int widthRatio,int heightRatio){
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if((mPriData != NULL)&& (mPriData->mStatus==XPLAYER_STATUS_IDLE
|
||
|| mPriData->mStatus==XPLAYER_STATUS_INITIALIZED
|
||
|| mPriData->mStatus==XPLAYER_STATUS_PREPARING) ){
|
||
mPriData->mWidthScaledownRatio = widthRatio;
|
||
mPriData->mHeightScaledownRatio = heightRatio;
|
||
return 0;
|
||
}else{
|
||
loge("XPlayerSetScaleDownRatio err,mPriData->mStatus = %d",mPriData->mStatus);
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/*
|
||
*ret 0 means supported, -1 is unsupported.
|
||
* */
|
||
int checkVideoSupported(const MediaInfo *mi)
|
||
{
|
||
int ret = 0; //default is supported
|
||
|
||
/*A80/H8 H265 4K unsupported*/
|
||
/*H3/H5 H265 4K supported*/
|
||
if (mi->pVideoStreamInfo->nWidth * mi->pVideoStreamInfo->nHeight >= PIXELS_4K)
|
||
{
|
||
#if !defined(CONF_H265_4K)
|
||
if (mi->pVideoStreamInfo->eCodecFormat == VIDEO_CODEC_FORMAT_H265)
|
||
{
|
||
loge("Not support H265 4K video !!");
|
||
ret = -1;
|
||
}
|
||
#endif
|
||
if (mi->pVideoStreamInfo->eCodecFormat == VIDEO_CODEC_FORMAT_WMV3)
|
||
{
|
||
loge("Not support VC1(WMV3) 4K video !!");
|
||
ret = -1;
|
||
}
|
||
}
|
||
else if (mi->pVideoStreamInfo->nWidth > WIDTH_1080P ||
|
||
mi->pVideoStreamInfo->nHeight > HEIGHT_1080P)
|
||
{
|
||
/* for all chip, WMV1/WMV2/VP6 specs unsupported, play effect too bad... */
|
||
if (mi->pVideoStreamInfo->eCodecFormat == VIDEO_CODEC_FORMAT_WMV1
|
||
|| mi->pVideoStreamInfo->eCodecFormat == VIDEO_CODEC_FORMAT_WMV2
|
||
|| mi->pVideoStreamInfo->eCodecFormat == VIDEO_CODEC_FORMAT_VP6)
|
||
{
|
||
loge("Not support WMV1/WMV2/VP6 1080P video !!");
|
||
ret = -1;
|
||
}
|
||
}
|
||
else /* < 1080P */
|
||
{
|
||
/* we support this*/
|
||
}
|
||
|
||
logv("check video support ret = [%d]", ret);
|
||
return ret;
|
||
}
|
||
|
||
static int initializePlayer(XPlayer* p)
|
||
{
|
||
//* get media information.
|
||
MediaInfo* mi;
|
||
VideoStreamInfo* vi;
|
||
AudioStreamInfo* ai;
|
||
SubtitleStreamInfo* si;
|
||
int i;
|
||
int nDefaultAudioIndex;
|
||
int nDefaultSubtitleIndex;
|
||
int ret;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
pthread_mutex_lock(&mPriData->mMutexMediaInfo);
|
||
|
||
mi = DemuxCompGetMediaInfo(mPriData->mDemux);
|
||
if(mi == NULL)
|
||
{
|
||
loge("can not get media info from demux.");
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
return -1;
|
||
}
|
||
|
||
if(mi->nBitrate > 0)
|
||
PlayerSetVideoAvgByteRate(mPriData->mPlayer, mi->nBitrate/8);
|
||
|
||
PlayerSetFirstPts(mPriData->mPlayer,mi->nFirstPts);
|
||
mPriData->mMediaInfo = mi;
|
||
if(mi->pVideoStreamInfo != NULL)
|
||
{
|
||
/*detect if support*/
|
||
if(checkVideoSupported(mi))
|
||
{
|
||
loge("this video is outof specs, unsupported.");
|
||
return -1;
|
||
}
|
||
if(mPriData->mWidthScaledownRatio == 0 && mPriData->mHeightScaledownRatio == 0){
|
||
/*if the app not set scaledownRatio,use the default*/
|
||
/*check if need scaledown*/
|
||
if(getScaledownFlag(mi,mPriData->bSetScaleDown)==1) /*1 means need to scale down*/
|
||
{
|
||
ret = PlayerConfigVideoScaleDownRatio(mPriData->mPlayer, 1, 1);
|
||
if(ret != 0)
|
||
{
|
||
logw("PlayerConfigVideoScaleDownRatio() fail, ret = %d",ret);
|
||
}
|
||
else
|
||
mPriData->mScaledownFlag = 1;
|
||
}
|
||
}else{
|
||
ret = PlayerConfigVideoScaleDownRatio(mPriData->mPlayer,mPriData->mWidthScaledownRatio,mPriData->mHeightScaledownRatio);
|
||
if(ret != 0)
|
||
{
|
||
logw("PlayerConfigVideoScaleDownRatio() fail, ret = %d",ret);
|
||
}
|
||
else
|
||
mPriData->mScaledownFlag = 1;
|
||
}
|
||
}
|
||
|
||
//* initialize the player.
|
||
#if !AWPLAYER_CONFIG_DISABLE_VIDEO
|
||
if(mi->pVideoStreamInfo != NULL)
|
||
{
|
||
#if !defined(CONF_3D_ENABLE)
|
||
if(mi->pVideoStreamInfo->bIs3DStream == 1)
|
||
mi->pVideoStreamInfo->bIs3DStream = 0;
|
||
#endif
|
||
//* set the rotation
|
||
int nRotateDegree;
|
||
int nRotation = atoi((const char*)mPriData->mMediaInfo->cRotation);
|
||
|
||
if(nRotation == 0)
|
||
nRotateDegree = 0;
|
||
else if(nRotation == 90)
|
||
nRotateDegree = 1;
|
||
else if(nRotation == 180)
|
||
nRotateDegree = 2;
|
||
else if(nRotation == 270)
|
||
nRotateDegree = 3;
|
||
else
|
||
nRotateDegree = 0;
|
||
|
||
ret = PlayerConfigVideoRotateDegree(mPriData->mPlayer, nRotateDegree);
|
||
if(ret != 0)
|
||
{
|
||
logw("PlayerConfigVideoRotateDegree() fail, ret = %d",ret);
|
||
}
|
||
|
||
//* set the video streamInfo
|
||
ret = PlayerSetVideoStreamInfo(mPriData->mPlayer, mi->pVideoStreamInfo);
|
||
if(ret != 0)
|
||
{
|
||
logw("PlayerSetVideoStreamInfo() fail, video stream not supported.");
|
||
}
|
||
|
||
ret = PlayerConfigDropDelayFrame(mPriData->mPlayer, 1);
|
||
if(ret != 0)
|
||
{
|
||
logw("PlayerConfigDropDelayFrame() fail.");
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
#if !AWPLAYER_CONFIG_DISABLE_AUDIO
|
||
if(mi->pAudioStreamInfo != NULL)
|
||
{
|
||
nDefaultAudioIndex = -1;
|
||
for(i=0; i<mi->nAudioStreamNum; i++)
|
||
{
|
||
if(PlayerCanSupportAudioStream(mPriData->mPlayer, &mi->pAudioStreamInfo[i]))
|
||
{
|
||
nDefaultAudioIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(nDefaultAudioIndex < 0)
|
||
{
|
||
logw("no audio stream supported.");
|
||
nDefaultAudioIndex = 0;
|
||
}
|
||
|
||
ret = PlayerSetAudioStreamInfo(mPriData->mPlayer, mi->pAudioStreamInfo,
|
||
mi->nAudioStreamNum, nDefaultAudioIndex);
|
||
if(ret != 0)
|
||
{
|
||
logw("PlayerSetAudioStreamInfo() fail, audio stream not supported.");
|
||
}
|
||
}
|
||
#endif
|
||
|
||
if(PlayerHasVideo(mPriData->mPlayer) == 0 && PlayerHasAudio(mPriData->mPlayer) == 0)
|
||
{
|
||
loge("neither video nor audio stream can be played.");
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
return -1;
|
||
}
|
||
|
||
#if !AWPLAYER_CONFIG_DISABLE_SUBTITLE
|
||
//* set subtitle stream to the text decoder.
|
||
if(mi->pSubtitleStreamInfo != NULL)
|
||
{
|
||
nDefaultSubtitleIndex = -1;
|
||
for(i=0; i<mi->nSubtitleStreamNum; i++)
|
||
{
|
||
if(PlayerCanSupportSubtitleStream(mPriData->mPlayer, &mi->pSubtitleStreamInfo[i]))
|
||
{
|
||
nDefaultSubtitleIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(nDefaultSubtitleIndex < 0)
|
||
{
|
||
logw("no subtitle stream supported.");
|
||
nDefaultSubtitleIndex = 0;
|
||
}
|
||
|
||
ret = PlayerSetSubtitleStreamInfo(mPriData->mPlayer,
|
||
mi->pSubtitleStreamInfo, mi->nSubtitleStreamNum, nDefaultSubtitleIndex);
|
||
if(ret != 0)
|
||
{
|
||
logw("PlayerSetSubtitleStreamInfo() fail, subtitle stream not supported.");
|
||
}
|
||
}
|
||
#endif
|
||
|
||
//* report not seekable.
|
||
if(mi->bSeekable == 0)
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_INFO,
|
||
AW_MEDIA_INFO_NOT_SEEKABLE, 0);
|
||
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
static void clearMediaInfo(XPlayer* p)
|
||
{
|
||
int i;
|
||
VideoStreamInfo* v;
|
||
AudioStreamInfo* a;
|
||
SubtitleStreamInfo* s;
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
|
||
if(mPriData->mMediaInfo != NULL)
|
||
{
|
||
//* free video stream info.
|
||
if(mPriData->mMediaInfo->pVideoStreamInfo != NULL)
|
||
{
|
||
for(i=0; i<mPriData->mMediaInfo->nVideoStreamNum; i++)
|
||
{
|
||
v = &mPriData->mMediaInfo->pVideoStreamInfo[i];
|
||
if(v->pCodecSpecificData != NULL && v->nCodecSpecificDataLen > 0)
|
||
free(v->pCodecSpecificData);
|
||
}
|
||
free(mPriData->mMediaInfo->pVideoStreamInfo);
|
||
mPriData->mMediaInfo->pVideoStreamInfo = NULL;
|
||
}
|
||
|
||
//* free audio stream info.
|
||
if(mPriData->mMediaInfo->pAudioStreamInfo != NULL)
|
||
{
|
||
for(i=0; i<mPriData->mMediaInfo->nAudioStreamNum; i++)
|
||
{
|
||
a = &mPriData->mMediaInfo->pAudioStreamInfo[i];
|
||
if(a->pCodecSpecificData != NULL && a->nCodecSpecificDataLen > 0)
|
||
free(a->pCodecSpecificData);
|
||
}
|
||
free(mPriData->mMediaInfo->pAudioStreamInfo);
|
||
mPriData->mMediaInfo->pAudioStreamInfo = NULL;
|
||
}
|
||
|
||
//* free subtitle stream info.
|
||
if(mPriData->mMediaInfo->pSubtitleStreamInfo != NULL)
|
||
{
|
||
for(i=0; i<mPriData->mMediaInfo->nSubtitleStreamNum; i++)
|
||
{
|
||
s = &mPriData->mMediaInfo->pSubtitleStreamInfo[i];
|
||
if(s->pUrl != NULL)
|
||
{
|
||
free(s->pUrl);
|
||
s->pUrl = NULL;
|
||
}
|
||
if(s->fd >= 0)
|
||
{
|
||
close(s->fd);
|
||
s->fd = -1;
|
||
}
|
||
if(s->fdSub >= 0)
|
||
{
|
||
close(s->fdSub);
|
||
s->fdSub = -1;
|
||
}
|
||
}
|
||
free(mPriData->mMediaInfo->pSubtitleStreamInfo);
|
||
mPriData->mMediaInfo->pSubtitleStreamInfo = NULL;
|
||
}
|
||
|
||
//* free the media info.
|
||
free(mPriData->mMediaInfo);
|
||
mPriData->mMediaInfo = NULL;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
static void* sendSpeedCmdThread(void* arg)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)arg;
|
||
mPriData->mSpeedThreadRuning = 1;
|
||
int needPauseNext =0;
|
||
logd("sendSpeedCmdThread start");
|
||
|
||
while(mPriData->mSpeedThreadRuning)
|
||
{
|
||
if (mPriData->mbFast == 1)
|
||
{
|
||
sleep(1);
|
||
|
||
if (mPriData->mSpeedThreadRuning != 1)
|
||
break;
|
||
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PAUSED ||
|
||
mPriData->mStatus == XPLAYER_STATUS_STOPPED ||
|
||
mPriData->mStatus == XPLAYER_STATUS_COMPLETE ||
|
||
mPriData->mStatus == XPLAYER_STATUS_ERROR ||
|
||
mPriData->mStatus == XPLAYER_STATUS_IDLE)
|
||
{
|
||
mPriData->mbFast = 0;
|
||
continue;
|
||
}
|
||
|
||
if ( needPauseNext == 1 || mPriData->mSpeed == 0 )
|
||
{
|
||
needPauseNext = 0;
|
||
AwMessage msg;
|
||
//* send a pause message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_PAUSE;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemPause;
|
||
msg.params[1] = (uintptr_t)&mPriData->mPauseReply;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
continue;
|
||
}
|
||
|
||
mPriData->mFastTime += mPriData->mSpeed*1000;
|
||
if (mPriData->mFastTime < 0)
|
||
{
|
||
mPriData->mFastTime = 0;
|
||
needPauseNext = 1;
|
||
}
|
||
else
|
||
needPauseNext = 0;
|
||
|
||
if(mPriData->mFastTime >= 0 && mPriData->mbFast == 1 )
|
||
{
|
||
AwMessage msg;
|
||
//* send a seek message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SEEK;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSeek;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSeekReply;
|
||
msg.params[2] = mPriData->mFastTime; //* params[2] = mSeekTime.
|
||
msg.params[3] = 0; //* params[3] = mSeekSync.
|
||
logd("speed mode seek, mFastTime: %d, mSpeed: %d",
|
||
mPriData->mFastTime, mPriData->mSpeed);
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
}
|
||
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PAUSED ||
|
||
mPriData->mStatus == XPLAYER_STATUS_STOPPED ||
|
||
mPriData->mStatus == XPLAYER_STATUS_COMPLETE ||
|
||
mPriData->mStatus == XPLAYER_STATUS_ERROR ||
|
||
mPriData->mStatus == XPLAYER_STATUS_IDLE )
|
||
{
|
||
mPriData->mbFast = 0;
|
||
continue;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
usleep(1000);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static void* XPlayerThread(void* arg)
|
||
{
|
||
AwMessage msg;
|
||
int ret;
|
||
sem_t* pReplySem;
|
||
int* pReplyValue;
|
||
PlayerContext* mPriData = (PlayerContext*)arg;
|
||
|
||
while(1)
|
||
{
|
||
if(AwMessageQueueGetMessage(mPriData->mMessageQueue, &msg) < 0)
|
||
{
|
||
loge("get message fail.");
|
||
continue;
|
||
}
|
||
|
||
pReplySem = (sem_t*)msg.params[0];
|
||
pReplyValue = (int*)msg.params[1];
|
||
|
||
if(msg.messageId == XPLAYER_COMMAND_SET_SOURCE)
|
||
{
|
||
logi("process message XPLAYER_COMMAND_SET_SOURCE.");
|
||
//* check status.
|
||
if(mPriData->mStatus != XPLAYER_STATUS_IDLE &&
|
||
mPriData->mStatus != XPLAYER_STATUS_INITIALIZED)
|
||
{
|
||
loge("invalid setDataSource() operation, player not in IDLE or INITIALIZED status");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = -1;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
if((int)msg.params[2] == SOURCE_TYPE_URL)
|
||
{
|
||
CdxKeyedVectorT* pHeaders;
|
||
//* data source is a url string.
|
||
if(mPriData->mSourceUrl != NULL)
|
||
free(mPriData->mSourceUrl);
|
||
mPriData->mSourceUrl = strdup((char*)msg.params[3]);
|
||
pHeaders = (CdxKeyedVectorT*) msg.params[4];
|
||
|
||
ret = DemuxCompSetUrlSource(mPriData->mDemux,
|
||
(void*)msg.params[5], mPriData->mSourceUrl, pHeaders);
|
||
if(ret == 0)
|
||
{
|
||
mPriData->mStatus = XPLAYER_STATUS_INITIALIZED;
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = 0;
|
||
}
|
||
else
|
||
{
|
||
loge("DemuxCompSetUrlSource() return fail.");
|
||
mPriData->mStatus = XPLAYER_STATUS_IDLE;
|
||
free(mPriData->mSourceUrl);
|
||
mPriData->mSourceUrl = NULL;
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = -1;
|
||
}
|
||
}
|
||
else if((int)msg.params[2] == SOURCE_TYPE_FD)
|
||
{
|
||
//* data source is a file descriptor.
|
||
int fd;
|
||
int64_t nOffset;
|
||
int64_t nLength;
|
||
|
||
fd = msg.params[3];
|
||
nOffset = msg.params[4];
|
||
nOffset<<=32;
|
||
nOffset |= msg.params[5];
|
||
nLength = msg.params[6];
|
||
nLength<<=32;
|
||
nLength |= msg.params[7];
|
||
|
||
if(mPriData->mSourceFd != -1)
|
||
close(mPriData->mSourceFd);
|
||
|
||
mPriData->mSourceFd = dup(fd);
|
||
mPriData->mSourceFdOffset = nOffset;
|
||
mPriData->mSourceFdLength = nLength;
|
||
ret = DemuxCompSetFdSource(mPriData->mDemux,
|
||
mPriData->mSourceFd, mPriData->mSourceFdOffset,
|
||
mPriData->mSourceFdLength);
|
||
if(ret == 0)
|
||
{
|
||
mPriData->mStatus = XPLAYER_STATUS_INITIALIZED;
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
}
|
||
else
|
||
{
|
||
loge("DemuxCompSetFdSource() return fail.");
|
||
mPriData->mStatus = XPLAYER_STATUS_IDLE;
|
||
close(mPriData->mSourceFd);
|
||
mPriData->mSourceFd = -1;
|
||
mPriData->mSourceFdOffset = 0;
|
||
mPriData->mSourceFdLength = 0;
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
}
|
||
}
|
||
else if((int)msg.params[2] == SOURCE_TYPE_DATASOURCE)
|
||
{
|
||
//* data source is a mediadatasource interface.
|
||
char *uri = (char *)msg.params[3];
|
||
int ret;
|
||
void *handle;
|
||
ret = sscanf(uri, "datasource://%p", &handle);
|
||
if (ret != 1)
|
||
{
|
||
CDX_LOGE("sscanf failure...(%s)", uri);
|
||
mPriData->mSourceStream = NULL;
|
||
}
|
||
else
|
||
{
|
||
mPriData->mSourceStream = (CdxStreamT *)handle;
|
||
}
|
||
ret = DemuxCompSetMediaDataSource(mPriData->mDemux, uri);
|
||
if(ret == 0)
|
||
{
|
||
mPriData->mStatus = XPLAYER_STATUS_INITIALIZED;
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
}
|
||
else
|
||
{
|
||
loge("DemuxCompSetStreamSource() return fail.");
|
||
mPriData->mStatus = XPLAYER_STATUS_IDLE;
|
||
if(mPriData->mSourceStream)
|
||
{
|
||
CdxStreamClose(mPriData->mSourceStream);
|
||
mPriData->mSourceStream = NULL;
|
||
}
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//* data source is a IStreamSource interface.
|
||
char *uri = (char *)msg.params[3];
|
||
int ret;
|
||
void *handle;
|
||
ret = sscanf(uri, "customer://%p", &handle);
|
||
if (ret != 1)
|
||
{
|
||
CDX_LOGE("sscanf failure...(%s)", uri);
|
||
mPriData->mSourceStream = NULL;
|
||
}
|
||
else
|
||
{
|
||
mPriData->mSourceStream = (CdxStreamT *)handle;
|
||
}
|
||
ret = DemuxCompSetStreamSource(mPriData->mDemux, uri);
|
||
if(ret == 0)
|
||
{
|
||
mPriData->mStatus = XPLAYER_STATUS_INITIALIZED;
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
}
|
||
else
|
||
{
|
||
loge("DemuxCompSetStreamSource() return fail.");
|
||
mPriData->mStatus = XPLAYER_STATUS_IDLE;
|
||
if(mPriData->mSourceStream)
|
||
{
|
||
CdxStreamClose(mPriData->mSourceStream);
|
||
mPriData->mSourceStream = NULL;
|
||
}
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
}
|
||
}
|
||
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
} //* end XPLAYER_COMMAND_SET_SOURCE.
|
||
else if(msg.messageId == XPLAYER_COMMAND_SET_SURFACE)
|
||
{
|
||
LayerCtrl* lc;
|
||
|
||
logd("process message XPLAYER_COMMAND_SET_SURFACE.");
|
||
|
||
//* set native window before delete the old one.
|
||
//* because the player's render thread may use the old surface
|
||
//* before it receive the new surface.
|
||
lc = (LayerCtrl*)msg.params[2];
|
||
|
||
ret = PlayerSetWindow(mPriData->mPlayer, lc);
|
||
if(ret == 0)
|
||
{
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
}
|
||
else
|
||
{
|
||
loge("PlayerSetWindow() return fail.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
}
|
||
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
} //* end XPLAYER_COMMAND_SET_SURFACE.
|
||
else if(msg.messageId == XPLAYER_COMMAND_SET_AUDIOSINK)
|
||
{
|
||
void* audioSink;
|
||
|
||
logv("process message XPLAYER_COMMAND_SET_AUDIOSINK.");
|
||
|
||
audioSink = (SoundCtrl*)msg.params[2];
|
||
PlayerSetAudioSink(mPriData->mPlayer, audioSink);
|
||
|
||
//* super class MediaPlayerInterface has mAudioSink.
|
||
//MediaPlayerInterface::setAudioSink(audioSink);
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
} //* end XPLAYER_COMMAND_SET_AUDIOSINK.
|
||
else if (msg.messageId == XPLAYER_COMMAND_SET_PLAYRATE)
|
||
{
|
||
XAudioPlaybackRate *rate;
|
||
rate = (XAudioPlaybackRate*)msg.params[2];
|
||
|
||
//do set playback setting in playback
|
||
int ret = PlayerSetPlayBackSettings(mPriData->mPlayer,rate);
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = ret;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
|
||
continue;
|
||
}//* end XPLAYER_COMMAND_SET_PLAYRATE.
|
||
else if(msg.messageId == XPLAYER_COMMAND_SET_SUBCTRL)
|
||
{
|
||
SubCtrl* subctrl;
|
||
|
||
logd("==== process message XPLAYER_COMMAND_SET_SUBCTRL.");
|
||
|
||
subctrl = (SubCtrl*)msg.params[2];
|
||
PlayerSetSubCtrl(mPriData->mPlayer, subctrl);
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
} //* end XPLAYER_COMMAND_SET_SUBCTRL.
|
||
else if(msg.messageId == XPLAYER_COMMAND_SET_DI)
|
||
{
|
||
Deinterlace* di;
|
||
|
||
logd("==== process message XPLAYER_COMMAND_SET_SUBCTRL.");
|
||
|
||
di = (Deinterlace*)msg.params[2];
|
||
PlayerSetDeinterlace(mPriData->mPlayer, di);
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
} //* end XPLAYER_COMMAND_SET_DI
|
||
else if(msg.messageId == XPLAYER_COMMAND_PREPARE)
|
||
{
|
||
logd("process message XPLAYER_COMMAND_PREPARE. mPriData->mStatus: %d",
|
||
mPriData->mStatus);
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PREPARED)
|
||
{
|
||
//* for data source set by fd(file descriptor), the prepare() method
|
||
//* is called in setDataSource(), so the player is already in PREPARED
|
||
//* status, here we just notify a prepared message.
|
||
|
||
//* when app call prepareAsync(), we callback video-size to app here,
|
||
if(mPriData->mMediaInfo->pVideoStreamInfo != NULL)
|
||
{
|
||
if(mPriData->mMediaInfo->pVideoStreamInfo->nWidth !=
|
||
mPriData->mVideoSizeWidth
|
||
&& mPriData->mMediaInfo->pVideoStreamInfo->nHeight !=
|
||
mPriData->mVideoSizeHeight)
|
||
{
|
||
int nRotation;
|
||
|
||
nRotation = atoi((const char*)mPriData->mMediaInfo->cRotation);
|
||
if((nRotation%180)==0)//* when the rotation is 0 and 180
|
||
{
|
||
mPriData->mVideoSizeWidth =
|
||
mPriData->mMediaInfo->pVideoStreamInfo->nWidth;
|
||
mPriData->mVideoSizeHeight =
|
||
mPriData->mMediaInfo->pVideoStreamInfo->nHeight;
|
||
}
|
||
else
|
||
{
|
||
//* when the rotation is 90 and 270,
|
||
//* we should exchange nHeight and nwidth
|
||
mPriData->mVideoSizeWidth =
|
||
mPriData->mMediaInfo->pVideoStreamInfo->nHeight;
|
||
mPriData->mVideoSizeHeight =
|
||
mPriData->mMediaInfo->pVideoStreamInfo->nWidth;
|
||
}
|
||
|
||
logi("xxxxxxxxxx video size: width = %d, height = %d",
|
||
mPriData->mVideoSizeWidth, mPriData->mVideoSizeHeight);
|
||
|
||
int size[2];
|
||
size[0] = mPriData->mVideoSizeWidth;
|
||
size[1] = mPriData->mVideoSizeHeight;
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_SET_VIDEO_SIZE,
|
||
0,
|
||
size);
|
||
}
|
||
}
|
||
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_PREPARED, 0, 0);
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
if(mPriData->mStatus != XPLAYER_STATUS_INITIALIZED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_STOPPED)
|
||
{
|
||
logd("invalid prepareAsync() call, player not in initialized or stopped status.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
mPriData->mStatus = XPLAYER_STATUS_PREPARING;
|
||
mPriData->mPrepareSync = msg.params[2];
|
||
ret = DemuxCompPrepareAsync(mPriData->mDemux);
|
||
if(ret != 0)
|
||
{
|
||
loge("DemuxCompPrepareAsync return fail immediately.");
|
||
mPriData->mStatus = XPLAYER_STATUS_IDLE;
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
}
|
||
else
|
||
{
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
}
|
||
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
} //* end XPLAYER_COMMAND_PREPARE.
|
||
else if(msg.messageId == XPLAYER_COMMAND_SETSPEED)
|
||
{
|
||
logd("process message XPLAYER_COMMAND_SETSPEED.");
|
||
if(mPriData->mStatus != XPLAYER_STATUS_PREPARED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_STARTED )
|
||
{
|
||
logd("invalid start() call, player not in prepared, \
|
||
started, paused or complete status.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
if(mPriData->mMediaInfo == NULL || mPriData->mMediaInfo->bSeekable == 0)
|
||
{
|
||
if(mPriData->mMediaInfo == NULL)
|
||
{
|
||
loge("setspeed fail because mMediaInfo == NULL.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = -1;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
loge("media not seekable. cannot fast");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = 0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
if(mPriData->mSeeking)
|
||
{
|
||
DemuxCompCancelSeek(mPriData->mDemux);
|
||
mPriData->mSeeking = 0;
|
||
}
|
||
|
||
//* protect mSeeking and mSeekTime from being changed by the seek finish callback.
|
||
pthread_mutex_lock(&mPriData->mMutexStatus);
|
||
|
||
int curTime;
|
||
XPlayerGetCurrentPosition(mPriData, &curTime);
|
||
|
||
mPriData->mSeeking = 1;
|
||
mPriData->mbFast = 1;
|
||
mPriData->mFastTime = curTime + mPriData->mSpeed*1000;
|
||
mPriData->mSeekTime = mPriData->mFastTime;
|
||
mPriData->mSeekSync = 0;
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
|
||
//PlayerFastForeward(mPriData->mPlayer);
|
||
PlayerSetDiscardAudio(mPriData->mPlayer, 1);
|
||
|
||
if(PlayerGetStatus(mPriData->mPlayer) == PLAYER_STATUS_STOPPED)
|
||
{
|
||
//* if in prepared status, the player is in stopped status,
|
||
//* this will make the player not record the nSeekTime at PlayerReset() operation
|
||
//* called at seek finish callback.
|
||
PlayerStart(mPriData->mPlayer,0,0);
|
||
}
|
||
|
||
PlayerPause(mPriData->mPlayer);
|
||
DemuxCompSeekTo(mPriData->mDemux, mPriData->mSeekTime, mPriData->mSeekModeType);
|
||
|
||
if (mPriData->mSpeedThreadRuning == 0)
|
||
{
|
||
int ret = pthread_create(&mPriData->mSpeedThreadId, NULL,
|
||
sendSpeedCmdThread, (void*)mPriData );
|
||
if (ret != 0)
|
||
{
|
||
loge("create sendSpeedCmdThread error!");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = 0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}//* end XPLAYER_COMMAND_SETSPEED.
|
||
else if(msg.messageId == XPLAYER_COMMAND_START)
|
||
{
|
||
logd("process message XPLAYER_COMMAND_START.");
|
||
|
||
mPriData->gain = *(float*)msg.params[2];
|
||
//WK_PRINT("gain_ihw orginal:%f",gain_ihw);
|
||
if(mPriData->gain > 0){
|
||
|
||
} else {
|
||
mPriData->gain = DEFAULT_GAIN_IHW;
|
||
}
|
||
|
||
if(mPriData->mStatus != XPLAYER_STATUS_PREPARED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_STARTED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_PAUSED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_COMPLETE)
|
||
{
|
||
logd("invalid start() call, player not in prepared, \
|
||
started, paused or complete status.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
if(mPriData->mbFast == 1)
|
||
{
|
||
PlayerSetDiscardAudio(mPriData->mPlayer, 0);
|
||
mPriData->mbFast = 0;
|
||
mPriData->mSpeed = 1;
|
||
mPriData->mFastTime = 0;
|
||
}
|
||
|
||
//* synchronize with the seek or complete callback and the status may be changed.
|
||
pthread_mutex_lock(&mPriData->mMutexStatus);
|
||
|
||
if(mPriData->mStatus == XPLAYER_STATUS_STARTED)
|
||
{
|
||
if(PlayerGetStatus(mPriData->mPlayer) == PLAYER_STATUS_PAUSED
|
||
&& mPriData->mSeeking == 0)
|
||
{
|
||
//* player is paused for buffering, start it.
|
||
//* see XPLAYER_MESSAGE_DEMUX_PAUSE_PLAYER callback message.
|
||
PlayerStart(mPriData->mPlayer,0,0);
|
||
DemuxCompStart(mPriData->mDemux);
|
||
}
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
logv("player already in started status.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
if(mPriData->mSeeking)
|
||
{
|
||
//* player and demux will be started at the seek callback.
|
||
mPriData->mStatus = XPLAYER_STATUS_STARTED;
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
//* for complete status, we seek to the begin of the file.
|
||
if(mPriData->mStatus == XPLAYER_STATUS_COMPLETE)
|
||
{
|
||
AwMessage newMsg;
|
||
|
||
if(mPriData->mMediaInfo->bSeekable)
|
||
{
|
||
if(mPriData->mSeeking)
|
||
{
|
||
DemuxCompCancelSeek(mPriData->mDemux);
|
||
mPriData->mSeeking = 0;
|
||
}
|
||
|
||
mPriData->mSeeking = 1;
|
||
mPriData->mSeekTime = 0;
|
||
mPriData->mSeekSync = 0;
|
||
mPriData->mSeekByInner = 1;
|
||
logd("seekTo %.2f secs", mPriData->mSeekTime / 1E3);
|
||
|
||
PlayerPause(mPriData->mPlayer);
|
||
DemuxCompSeekTo(mPriData->mDemux, mPriData->mSeekTime, mPriData->mSeekModeType);
|
||
|
||
//* player and demux will be started at the seek callback.
|
||
mPriData->mStatus = XPLAYER_STATUS_STARTED;
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
//* post a stop message.
|
||
memset(&newMsg, 0, sizeof(AwMessage));
|
||
newMsg.messageId = XPLAYER_COMMAND_STOP;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &newMsg);
|
||
|
||
//* post a prepare message.
|
||
memset(&newMsg, 0, sizeof(AwMessage));
|
||
newMsg.messageId = XPLAYER_COMMAND_PREPARE;
|
||
newMsg.params[0] = 0;
|
||
newMsg.params[1] = 0;
|
||
newMsg.params[2] = 1; //* params[2] = mPrepareSync.
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &newMsg);
|
||
|
||
//* post a start message.
|
||
memset(&newMsg, 0, sizeof(AwMessage));
|
||
newMsg.messageId = XPLAYER_COMMAND_START;
|
||
newMsg.params[0] = 0;
|
||
newMsg.params[1] = 0;
|
||
newMsg.params[2] = (unsigned int)&mPriData->gain;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &newMsg);
|
||
|
||
//* should I reply 0 to the user at this moment?
|
||
//* or just set the semaphore and reply variable to the start message to
|
||
//* make it reply when start message done?
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
|
||
mPriData->mPlayer = PlayerGainSet(mPriData->mPlayer, mPriData->gain);
|
||
|
||
if(mPriData->mApplicationType == APP_STREAMING)
|
||
{
|
||
PlayerFast(mPriData->mPlayer, 0);
|
||
}
|
||
else
|
||
{
|
||
PlayerStart(mPriData->mPlayer,0,0);
|
||
}
|
||
|
||
DemuxCompStart(mPriData->mDemux);
|
||
mPriData->mStatus = XPLAYER_STATUS_STARTED;
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
|
||
} //* end XPLAYER_COMMAND_START.
|
||
else if(msg.messageId == XPLAYER_COMMAND_STOP)
|
||
{
|
||
logv("process message XPLAYER_COMMAND_STOP.");
|
||
if(mPriData->mStatus != XPLAYER_STATUS_PREPARED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_STARTED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_PAUSED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_COMPLETE &&
|
||
mPriData->mStatus != XPLAYER_STATUS_STOPPED)
|
||
{
|
||
logd("invalid stop() call, player not in prepared, paused, \
|
||
started, stopped or complete status.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
if(mPriData->mStatus == XPLAYER_STATUS_STOPPED)
|
||
{
|
||
logv("player already in stopped status.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
//* the prepare callback may happen at this moment.
|
||
//* so the mStatus may be changed to PREPARED asynchronizely.
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PREPARING)
|
||
{
|
||
logw("stop() called at preparing status, cancel demux prepare.");
|
||
DemuxCompCancelPrepare(mPriData->mDemux);
|
||
}
|
||
|
||
if(mPriData->mSeeking)
|
||
{
|
||
DemuxCompCancelSeek(mPriData->mDemux);
|
||
mPriData->mSeeking = 0;
|
||
}
|
||
|
||
DemuxCompStop(mPriData->mDemux);
|
||
PlayerStop(mPriData->mPlayer);
|
||
PlayerClear(mPriData->mPlayer); //* clear all media information in player.
|
||
|
||
//*clear the mSubtitleDisplayIds
|
||
memset(mPriData->mSubtitleDisplayIds,0xff,64*sizeof(unsigned int));
|
||
mPriData->mSubtitleDisplayIdsUpdateIndex = 0;
|
||
|
||
mPriData->mStatus = XPLAYER_STATUS_STOPPED;
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
} //* end XPLAYER_COMMAND_STOP.
|
||
else if(msg.messageId == XPLAYER_COMMAND_PAUSE)
|
||
{
|
||
logv("process message XPLAYER_COMMAND_PAUSE.");
|
||
if(mPriData->mStatus != XPLAYER_STATUS_STARTED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_PAUSED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_COMPLETE)
|
||
{
|
||
logd("invalid pause() call, player not in started, paused or complete status.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PAUSED)
|
||
{
|
||
logv("player already in paused or complete status.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
//* sync with the seek, complete or pause_player/resume_player call back.
|
||
pthread_mutex_lock(&mPriData->mMutexStatus);
|
||
|
||
if(mPriData->mSeeking)
|
||
{
|
||
//* player and demux will be paused at the seek callback.
|
||
mPriData->mStatus = XPLAYER_STATUS_PAUSED;
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
PlayerPause(mPriData->mPlayer);
|
||
mPriData->mStatus = XPLAYER_STATUS_PAUSED;
|
||
|
||
//* sync with the seek, complete or pause_player/resume_player call back.
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
} //* end XPLAYER_COMMAND_PAUSE.
|
||
else if(msg.messageId == XPLAYER_COMMAND_RESET)
|
||
{
|
||
logv("process message XPLAYER_COMMAND_RESET.");
|
||
//* the prepare callback may happen at this moment.
|
||
//* so the mStatus may be changed to PREPARED asynchronizely.
|
||
if(mPriData->mStatus == XPLAYER_STATUS_PREPARING)
|
||
{
|
||
logw("reset() called at preparing status, cancel demux prepare.");
|
||
DemuxCompCancelPrepare(mPriData->mDemux);
|
||
}
|
||
|
||
if(mPriData->mSeeking)
|
||
{
|
||
DemuxCompCancelSeek(mPriData->mDemux);
|
||
mPriData->mSeeking = 0;
|
||
}
|
||
|
||
//* stop and clear the demux.
|
||
//* this will stop the seeking if demux is currently processing seeking message.
|
||
//* it will clear the data source keep inside, this is important for the IStreamSource.
|
||
DemuxCompStop(mPriData->mDemux);
|
||
DemuxCompClear(mPriData->mDemux);
|
||
|
||
//* stop and clear the player.
|
||
PlayerStop(mPriData->mPlayer);
|
||
PlayerClear(mPriData->mPlayer); //* it will clear media info config to the player.
|
||
|
||
//* clear suface.
|
||
if(mPriData->mKeepLastFrame == 0)
|
||
{
|
||
|
||
}
|
||
|
||
//* clear data source.
|
||
if(mPriData->mSourceUrl != NULL)
|
||
{
|
||
free(mPriData->mSourceUrl);
|
||
mPriData->mSourceUrl = NULL;
|
||
}
|
||
if(mPriData->mSourceFd != -1)
|
||
{
|
||
close(mPriData->mSourceFd);
|
||
mPriData->mSourceFd = -1;
|
||
mPriData->mSourceFdOffset = 0;
|
||
mPriData->mSourceFdLength = 0;
|
||
}
|
||
mPriData->mSourceStream = NULL;
|
||
|
||
//* clear media info.
|
||
clearMediaInfo(mPriData);
|
||
|
||
//* clear loop setting.
|
||
mPriData->mLoop = 0;
|
||
|
||
//* clear the mSubtitleDisplayIds
|
||
memset(mPriData->mSubtitleDisplayIds,0xff,64*sizeof(unsigned int));
|
||
mPriData->mSubtitleDisplayIdsUpdateIndex = 0;
|
||
|
||
//* set status to IDLE.
|
||
mPriData->mStatus = XPLAYER_STATUS_IDLE;
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
else if(msg.messageId == XPLAYER_COMMAND_SEEK)
|
||
{
|
||
logd("process message XPLAYER_COMMAND_SEEK.");
|
||
if(mPriData->mStatus != XPLAYER_STATUS_PREPARED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_STARTED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_PAUSED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_COMPLETE)
|
||
{
|
||
logd("invalid seekTo() call, player not in prepared, \
|
||
started, paused or complete status.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
//* the application will call seekTo() when player is in complete status.
|
||
//* after seekTo(), the player should still stay on complete status until
|
||
//* application call start().
|
||
//* cts test requires this implement.
|
||
if(mPriData->mStatus == XPLAYER_STATUS_COMPLETE)
|
||
{
|
||
//* protect mSeeking and mSeekTime from being changed by the seek finish callback.
|
||
pthread_mutex_lock(&mPriData->mMutexStatus);
|
||
mPriData->mSeekTime = msg.params[2];
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_SEEK_COMPLETE, 0, 0);
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
if(mPriData->mMediaInfo == NULL || mPriData->mMediaInfo->bSeekable == 0)
|
||
{
|
||
if(mPriData->mMediaInfo == NULL)
|
||
{
|
||
loge("seekTo fail because mMediaInfo == NULL.");
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_SEEK_COMPLETE, 0, 0);
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = -1;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
loge("media not seekable.");
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_SEEK_COMPLETE, 0, 0);
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = 0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
if(mPriData->mSeeking)
|
||
{
|
||
DemuxCompCancelSeek(mPriData->mDemux);
|
||
mPriData->mSeeking = 0;
|
||
}
|
||
|
||
//* protect mSeeking and mSeekTime from being changed by the seek finish callback.
|
||
pthread_mutex_lock(&mPriData->mMutexStatus);
|
||
mPriData->mSeeking = 1;
|
||
mPriData->mSeekTime = msg.params[2];
|
||
mPriData->mSeekSync = msg.params[3];
|
||
logv("seekTo %.2f secs", mPriData->mSeekTime / 1E3);
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
|
||
if(PlayerGetStatus(mPriData->mPlayer) == PLAYER_STATUS_STOPPED)
|
||
{
|
||
//* if in prepared status, the player is in stopped status,
|
||
//* this will make the player not record the nSeekTime at PlayerReset() operation
|
||
//* called at seek finish callback.
|
||
PlayerStart(mPriData->mPlayer,0,0);
|
||
}
|
||
PlayerPause(mPriData->mPlayer);
|
||
DemuxCompSeekTo(mPriData->mDemux, mPriData->mSeekTime, mPriData->mSeekModeType);
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
} //* end XPLAYER_COMMAND_SEEK.
|
||
else if(msg.messageId == XPLAYER_COMMAND_RESETURL)
|
||
{
|
||
logd("process message XPLAYER_COMMAND_RESETURL.");
|
||
if(mPriData->mStatus != XPLAYER_STATUS_PREPARED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_STARTED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_PAUSED &&
|
||
mPriData->mStatus != XPLAYER_STATUS_COMPLETE)
|
||
{
|
||
logd("invalid seekTo() call, player not in prepared, started, \
|
||
paused or complete status.");
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)-1;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
|
||
if(mPriData->mSeeking)
|
||
{
|
||
DemuxCompCancelSeek(mPriData->mDemux);
|
||
mPriData->mSeeking = 0;
|
||
}
|
||
|
||
//* protect mSeeking and mSeekTime from being changed by the seek finish callback.
|
||
pthread_mutex_lock(&mPriData->mMutexStatus);
|
||
mPriData->mSeeking = 1;
|
||
mPriData->mSeekTime = msg.params[2];
|
||
mPriData->mSeekSync = msg.params[3];
|
||
logd("seekTo %.2f secs", mPriData->mSeekTime / 1E3);
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
|
||
if(PlayerGetStatus(mPriData->mPlayer) == PLAYER_STATUS_STOPPED)
|
||
{
|
||
//* if in prepared status, the player is in stopped status,
|
||
//* this will make the player not record the nSeekTime at PlayerReset() operation
|
||
//* called at seek finish callback.
|
||
PlayerStart(mPriData->mPlayer,0,0);
|
||
}
|
||
PlayerPause(mPriData->mPlayer);
|
||
DemuxCompSeekToResetUrl(mPriData->mDemux, mPriData->mSeekTime);
|
||
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
continue;
|
||
}
|
||
else if(msg.messageId == XPLAYER_COMMAND_QUIT)
|
||
{
|
||
if(pReplyValue != NULL)
|
||
*pReplyValue = (int)0;
|
||
if(pReplySem != NULL)
|
||
sem_post(pReplySem);
|
||
break; //* break the thread.
|
||
} //* end XPLAYER_COMMAND_QUIT.
|
||
else
|
||
{
|
||
logw("unknow message with id %d, ignore.", msg.messageId);
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int XPlayerSwitchSubtitle(XPlayer* p, int nStreamIndex)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(mPriData->mPlayer == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
return PlayerSwitchSubtitle(mPriData->mPlayer, nStreamIndex);
|
||
}
|
||
|
||
int XPlayerSwitchAudio(XPlayer* p, int nStreamIndex)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(mPriData->mPlayer == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
return PlayerSwitchAudio(mPriData->mPlayer, nStreamIndex);
|
||
}
|
||
|
||
static int setSubtitleStream(PlayerContext* mPriData, int nStreamNum,
|
||
SubtitleStreamInfo* pNewStreamInfo)
|
||
{
|
||
int i;
|
||
SubtitleStreamInfo* pStreamInfo;
|
||
if(pNewStreamInfo == NULL || nStreamNum == 0)
|
||
{
|
||
loge("PlayerProbeSubtitleStreamInfo failed!");
|
||
return -1;
|
||
}
|
||
|
||
pthread_mutex_lock(&mPriData->mMutexMediaInfo);
|
||
|
||
//* set reference video size.
|
||
if(mPriData->mMediaInfo->pVideoStreamInfo != NULL)
|
||
{
|
||
for(i=0; i<nStreamNum; i++)
|
||
{
|
||
if(pNewStreamInfo[i].nReferenceVideoFrameRate == 0)
|
||
pNewStreamInfo[i].nReferenceVideoFrameRate =
|
||
mPriData->mMediaInfo->pVideoStreamInfo->nFrameRate;
|
||
if(pNewStreamInfo[i].nReferenceVideoHeight == 0 ||
|
||
pNewStreamInfo[i].nReferenceVideoWidth == 0)
|
||
{
|
||
pNewStreamInfo[i].nReferenceVideoHeight =
|
||
mPriData->mMediaInfo->pVideoStreamInfo->nHeight;
|
||
pNewStreamInfo[i].nReferenceVideoWidth =
|
||
mPriData->mMediaInfo->pVideoStreamInfo->nWidth;
|
||
}
|
||
}
|
||
}
|
||
|
||
//* add stream info to the mMediaInfo,
|
||
//* put external subtitle streams ahead of the embedded subtitle streams.
|
||
if(mPriData->mMediaInfo->pSubtitleStreamInfo == NULL)
|
||
{
|
||
mPriData->mMediaInfo->pSubtitleStreamInfo = pNewStreamInfo;
|
||
mPriData->mMediaInfo->nSubtitleStreamNum = nStreamNum;
|
||
pNewStreamInfo = NULL;
|
||
nStreamNum = 0;
|
||
}
|
||
else
|
||
{
|
||
pStreamInfo = (SubtitleStreamInfo*)malloc(sizeof(SubtitleStreamInfo)*
|
||
(mPriData->mMediaInfo->nSubtitleStreamNum + nStreamNum));
|
||
if(pStreamInfo == NULL)
|
||
{
|
||
loge("invode::INVOKE_ID_ADD_EXTERNAL_SOURCE fail, can not malloc memory.");
|
||
for(i=0; i<nStreamNum; i++)
|
||
{
|
||
if(pNewStreamInfo[i].pUrl != NULL)
|
||
{
|
||
free(pNewStreamInfo[i].pUrl);
|
||
pNewStreamInfo[i].pUrl = NULL;
|
||
}
|
||
|
||
if(pNewStreamInfo[i].fd >= 0)
|
||
{
|
||
close(pNewStreamInfo[i].fd);
|
||
pNewStreamInfo[i].fd = -1;
|
||
}
|
||
|
||
if(pNewStreamInfo[i].fdSub >= 0)
|
||
{
|
||
close(pNewStreamInfo[i].fdSub);
|
||
pNewStreamInfo[i].fdSub = -1;
|
||
}
|
||
}
|
||
|
||
free(pNewStreamInfo);
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
return -1;
|
||
}
|
||
|
||
//* make the internal subtitle in front of external subtitle
|
||
memcpy(&pStreamInfo[mPriData->mMediaInfo->nSubtitleStreamNum],
|
||
pNewStreamInfo, sizeof(SubtitleStreamInfo)*nStreamNum);
|
||
memcpy(pStreamInfo, mPriData->mMediaInfo->pSubtitleStreamInfo,
|
||
sizeof(SubtitleStreamInfo)*mPriData->mMediaInfo->nSubtitleStreamNum);
|
||
|
||
free(mPriData->mMediaInfo->pSubtitleStreamInfo);
|
||
mPriData->mMediaInfo->pSubtitleStreamInfo = pStreamInfo;
|
||
mPriData->mMediaInfo->nSubtitleStreamNum += nStreamNum;
|
||
|
||
free(pNewStreamInfo);
|
||
pNewStreamInfo = NULL;
|
||
nStreamNum = 0;
|
||
}
|
||
|
||
//* re-arrange the stream index.
|
||
for(i=0; i<mPriData->mMediaInfo->nSubtitleStreamNum; i++)
|
||
mPriData->mMediaInfo->pSubtitleStreamInfo[i].nStreamIndex = i;
|
||
|
||
//* set subtitle stream info to player again.
|
||
//* here mMediaInfo != NULL, so initializePlayer() had been called.
|
||
if(mPriData->mPlayer != NULL)
|
||
{
|
||
int nDefaultSubtitleIndex = -1;
|
||
for(i=0; i<mPriData->mMediaInfo->nSubtitleStreamNum; i++)
|
||
{
|
||
if(PlayerCanSupportSubtitleStream(mPriData->mPlayer,
|
||
&mPriData->mMediaInfo->pSubtitleStreamInfo[i]))
|
||
{
|
||
nDefaultSubtitleIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(nDefaultSubtitleIndex < 0)
|
||
{
|
||
logw("no subtitle stream supported.");
|
||
nDefaultSubtitleIndex = 0;
|
||
}
|
||
|
||
if(0 != PlayerSetSubtitleStreamInfo(mPriData->mPlayer,
|
||
mPriData->mMediaInfo->pSubtitleStreamInfo,
|
||
mPriData->mMediaInfo->nSubtitleStreamNum,
|
||
nDefaultSubtitleIndex))
|
||
{
|
||
logw("PlayerSetSubtitleStreamInfo() fail, subtitle stream not supported.");
|
||
}
|
||
}
|
||
|
||
pthread_mutex_unlock(&mPriData->mMutexMediaInfo);
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
int XPlayerSetExternalSubUrl(XPlayer* p, const char* fileName)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
SubtitleStreamInfo* pStreamInfo;
|
||
SubtitleStreamInfo* pNewStreamInfo = NULL;
|
||
int nStreamNum = 0;
|
||
int i;
|
||
|
||
if(mPriData->mStatus != XPLAYER_STATUS_PREPARED || mPriData->mMediaInfo == NULL)
|
||
{
|
||
loge("can not add external text source, player not in prepared status \
|
||
or there is no media stream.");
|
||
return -1;
|
||
}
|
||
|
||
//* probe subtitle info
|
||
PlayerProbeSubtitleStreamInfo(fileName, &nStreamNum, &pNewStreamInfo);
|
||
|
||
if(pNewStreamInfo == NULL || nStreamNum == 0)
|
||
{
|
||
loge("PlayerProbeSubtitleStreamInfo failed!");
|
||
return -1;
|
||
}
|
||
|
||
return setSubtitleStream(mPriData, nStreamNum, pNewStreamInfo);
|
||
}
|
||
|
||
|
||
int XPlayerSetExternalSubFd(XPlayer* p, int fd, int64_t offset, int64_t len, int fdSub)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
SubtitleStreamInfo* pStreamInfo;
|
||
SubtitleStreamInfo* pNewStreamInfo = NULL;
|
||
int nStreamNum = 0;
|
||
int i;
|
||
|
||
if(mPriData->mStatus != XPLAYER_STATUS_PREPARED || mPriData->mMediaInfo == NULL)
|
||
{
|
||
loge("can not add external text source, player not in prepared status \
|
||
or there is no media stream.");
|
||
return -1;
|
||
}
|
||
|
||
//* probe subtitle info
|
||
PlayerProbeSubtitleStreamInfoFd(fd, offset, len, &nStreamNum, &pNewStreamInfo);
|
||
|
||
if(nStreamNum > 0 && pNewStreamInfo[0].eCodecFormat == SUBTITLE_CODEC_IDXSUB)
|
||
{
|
||
if(fdSub >= 0)
|
||
{
|
||
//* for index+sub subtitle,
|
||
//* we set the .sub file's descriptor to pNewStreamInfo[i].fdSub.
|
||
for(i=0; i<nStreamNum; i++)
|
||
pNewStreamInfo[i].fdSub = dup(fdSub);
|
||
}
|
||
else
|
||
{
|
||
loge("index sub subtitle stream without .sub file fd.");
|
||
for(i=0; i<nStreamNum; i++)
|
||
{
|
||
if(pNewStreamInfo[i].fd >= 0)
|
||
{
|
||
close(pNewStreamInfo[i].fd);
|
||
pNewStreamInfo[i].fd = -1;
|
||
}
|
||
}
|
||
free(pNewStreamInfo);
|
||
pNewStreamInfo = NULL;
|
||
nStreamNum = 0;
|
||
}
|
||
}
|
||
|
||
//* fdSub is the file descriptor of .sub file of a index+sub subtitle.
|
||
if(fdSub >= 0)
|
||
{
|
||
//* close the file descriptor of .idx file, we dup it when
|
||
//* INVOKE_ID_ADD_EXTERNAL_SOURCE_FD is called to set the .idx file
|
||
if(fd >= 0)
|
||
close(fd);
|
||
}
|
||
|
||
if(pNewStreamInfo == NULL || nStreamNum == 0)
|
||
{
|
||
loge("PlayerProbeSubtitleStreamInfo failed!");
|
||
return -1;
|
||
}
|
||
|
||
return setSubtitleStream(mPriData, nStreamNum, pNewStreamInfo);
|
||
}
|
||
|
||
int XPlayerSetSubCharset(XPlayer* p, const char* strFormat)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(strFormat != NULL && (strlen(strFormat) < 31))
|
||
{
|
||
strcpy(mPriData->mDefaultTextFormat, strFormat);
|
||
}
|
||
else
|
||
{
|
||
strcpy(mPriData->mDefaultTextFormat, "UTF-8");
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int XPlayerGetSubCharset(XPlayer* p, char *charset)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(mPriData->mPlayer == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
strcpy(charset, mPriData->mDefaultTextFormat);
|
||
|
||
return 0;
|
||
}
|
||
|
||
int XPlayerSetSubDelay(XPlayer* p, int nTimeMs)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(mPriData->mPlayer!=NULL)
|
||
return PlayerSetSubtitleShowTimeAdjustment(mPriData->mPlayer, nTimeMs);
|
||
else
|
||
return -1;
|
||
}
|
||
|
||
int XPlayerGetSubDelay(XPlayer* p)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(mPriData->mPlayer!=NULL)
|
||
return PlayerGetSubtitleShowTimeAdjustment(mPriData->mPlayer);
|
||
else
|
||
return -1;
|
||
}
|
||
|
||
int XPlayerGetBitrate(XPlayer* p)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(mPriData->mPlayer!=NULL)
|
||
return PlayerGetVideoBitrate(mPriData->mPlayer) +
|
||
PlayerGetAudioBitrate(mPriData->mPlayer);
|
||
else
|
||
return -1;
|
||
}
|
||
|
||
int XPlayerGetCacheSize(XPlayer* p)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
if(mPriData->mPlayer!=NULL)
|
||
return DemuxCompGetCacheSize(mPriData->mDemux);
|
||
else
|
||
return -1;
|
||
}
|
||
int XPlayerSetBufferingSettings(XPlayer* p, AwBufferingSettings* pBuffering)
|
||
{
|
||
if(pBuffering == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
mPriData->pBuffering = pBuffering;
|
||
DemuxCompSetBufferingSettings(mPriData->mDemux, mPriData->pBuffering);
|
||
return 0;
|
||
}
|
||
int XPlayerGetBufferingSettings(XPlayer* p, AwBufferingSettings* pBuffering)
|
||
{
|
||
if(p == NULL || pBuffering == NULL)
|
||
{
|
||
logd("input is NULL. Please check it.");
|
||
return -1;
|
||
}
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
return DemuxCompGetBufferingSettings(mPriData->mDemux, pBuffering);
|
||
}
|
||
|
||
int XPlayerGetVideoDispFramerate(XPlayer* p,float* dispFramerate){
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
return PlayerGetVideoDispFramerate(mPriData->mPlayer,dispFramerate);
|
||
}
|
||
|
||
int XPlayerSetHoldLastPicture(XPlayer* p,int bHoldFlag){
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
return PlayerSetHoldLastPicture(mPriData->mPlayer,bHoldFlag);
|
||
}
|
||
|
||
static int callbackProcess(void *p, int messageId, void* param)
|
||
{
|
||
PlayerContext* mPriData = (PlayerContext*)p;
|
||
switch(messageId)
|
||
{
|
||
case DEMUX_NOTIFY_PREPARED:
|
||
{
|
||
uintptr_t tmpPtr = (uintptr_t)param;
|
||
int err = tmpPtr;
|
||
if(err != 0)
|
||
{
|
||
//* demux prepare return fail.
|
||
//* notify a media error event.
|
||
mPriData->mStatus = XPLAYER_STATUS_ERROR;
|
||
if(mPriData->mPrepareSync == 0)
|
||
{
|
||
if(err == DEMUX_ERROR_IO)
|
||
{
|
||
mPriData->mCallback(mPriData->pUser,
|
||
AWPLAYER_MEDIA_ERROR, AW_MEDIA_ERROR_IO, 0);
|
||
}
|
||
else if(err == DEMUX_ERROR_USER_CANCEL)
|
||
{
|
||
logd("preparing canceled by user");
|
||
}
|
||
else
|
||
{
|
||
mPriData->mCallback(mPriData->pUser,
|
||
AWPLAYER_MEDIA_ERROR, AW_MEDIA_ERROR_UNKNOWN, 0);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if(err == DEMUX_ERROR_IO)
|
||
mPriData->mPrepareFinishResult = AW_MEDIA_ERROR_IO;
|
||
else
|
||
mPriData->mPrepareFinishResult = -1;
|
||
sem_post(&mPriData->mSemPrepareFinish);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//* demux prepare success, initialize the player.
|
||
if(initializePlayer(p) == 0)
|
||
{
|
||
//* initialize player success, notify a prepared event.
|
||
mPriData->mStatus = XPLAYER_STATUS_PREPARED;
|
||
if(mPriData->mPrepareSync == 0)
|
||
{
|
||
|
||
if(mPriData->mMediaInfo->pVideoStreamInfo!=NULL)
|
||
{
|
||
if(mPriData->mMediaInfo->pVideoStreamInfo->nWidth !=
|
||
mPriData->mVideoSizeWidth
|
||
&& mPriData->mMediaInfo->pVideoStreamInfo->nHeight !=
|
||
mPriData->mVideoSizeHeight)
|
||
{
|
||
int nRotation;
|
||
|
||
nRotation = atoi((const char*)mPriData->mMediaInfo->cRotation);
|
||
if((nRotation%180)==0)//* when the rotation is 0 and 180
|
||
{
|
||
mPriData->mVideoSizeWidth =
|
||
mPriData->mMediaInfo->pVideoStreamInfo->nWidth;
|
||
mPriData->mVideoSizeHeight =
|
||
mPriData->mMediaInfo->pVideoStreamInfo->nHeight;
|
||
}
|
||
else
|
||
{
|
||
//* when the rotation is 90 and 270,
|
||
//* we should exchange nHeight and nwidth
|
||
mPriData->mVideoSizeWidth =
|
||
mPriData->mMediaInfo->pVideoStreamInfo->nHeight;
|
||
mPriData->mVideoSizeHeight =
|
||
mPriData->mMediaInfo->pVideoStreamInfo->nWidth;
|
||
}
|
||
logi("xxxxxxxxxx video size: width = %d, height = %d",
|
||
mPriData->mVideoSizeWidth, mPriData->mVideoSizeHeight);
|
||
int size[2];
|
||
size[0] = mPriData->mVideoSizeWidth;
|
||
size[1] = mPriData->mVideoSizeHeight;
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_SET_VIDEO_SIZE,
|
||
0, size);
|
||
}
|
||
else
|
||
{
|
||
//<2F><>ʱmVideoSizeWidth<74><68><EFBFBD><EFBFBD>0
|
||
logi("xxxxxxxxxx video size: width = 0, height = 0");
|
||
mPriData->mCallback(mPriData->pUser,
|
||
AWPLAYER_MEDIA_SET_VIDEO_SIZE, 0, (int []){0, 0});
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//<2F><>ʱmVideoSizeWidth<74><68><EFBFBD><EFBFBD>0
|
||
logi("xxxxxxxxxx video size: width = 0, height = 0");
|
||
mPriData->mCallback(mPriData->pUser,
|
||
AWPLAYER_MEDIA_SET_VIDEO_SIZE, 0, (int []){0, 0});
|
||
}
|
||
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_PREPARED, 0, 0);
|
||
}
|
||
else
|
||
{
|
||
mPriData->mPrepareFinishResult = 0;
|
||
sem_post(&mPriData->mSemPrepareFinish);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//* initialize player fail, notify a media error event.
|
||
mPriData->mStatus = XPLAYER_STATUS_ERROR;
|
||
if(mPriData->mPrepareSync == 0)
|
||
mPriData->mCallback(mPriData->pUser,
|
||
AWPLAYER_MEDIA_ERROR, DEMUX_ERROR_UNKNOWN, 0);
|
||
else
|
||
{
|
||
mPriData->mPrepareFinishResult = -1;
|
||
sem_post(&mPriData->mSemPrepareFinish);
|
||
}
|
||
}
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
case DEMUX_NOTIFY_EOS:
|
||
{
|
||
if(mPriData->mLivemode == 2) //* timeshift
|
||
{
|
||
int seekTimeMs = 0;
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
mPriData->mCurShiftTimeStamp = tv.tv_sec * 1000000ll + tv.tv_usec;
|
||
logd("mCurShiftTimeStamp=%" PRId64 " ms", mPriData->mCurShiftTimeStamp/1000);
|
||
seekTimeMs = (mPriData->mCurShiftTimeStamp - mPriData->mShiftTimeStamp)/1000
|
||
- mPriData->mTimeShiftDuration + mPriData->mPreSeekTimeMs;
|
||
logd("===== seekTimeMs=%d ms, mPriData->mCurShiftTimeStamp=%" PRId64 " us,"
|
||
"mPriData->mShiftTimeStamp=%" PRId64 " us,"
|
||
" mPriData->mTimeShiftDuration=%" PRId64 " ms, mPreSeekTimeMs=%d ms",
|
||
seekTimeMs,
|
||
mPriData->mCurShiftTimeStamp, mPriData->mShiftTimeStamp,
|
||
mPriData->mTimeShiftDuration, mPriData->mPreSeekTimeMs);
|
||
XPlayerSeekTo(p, seekTimeMs, mPriData->mSeekModeType);
|
||
}
|
||
else
|
||
{
|
||
logw("eos...");
|
||
PlayerSetEos(mPriData->mPlayer);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case DEMUX_NOTIFY_IOERROR:
|
||
{
|
||
loge("io error...");
|
||
//* should we report a MEDIA_INFO event of "MEDIA_INFO_NETWORK_ERROR" and
|
||
//* try reconnect for sometimes before a MEDIA_ERROR_IO event reported ?
|
||
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_ERROR, AW_MEDIA_ERROR_IO, 0);
|
||
break;
|
||
}
|
||
|
||
case DEMUX_NOTIFY_CACHE_STAT:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_BUFFERING_UPDATE,
|
||
0, param);
|
||
break;
|
||
}
|
||
|
||
case DEMUX_NOTIFY_BUFFER_START:
|
||
{
|
||
logd("MEDIA_INFO_BUFFERING_START,mDisplayRatio = %d",mPriData->mDisplayRatio);
|
||
|
||
// for live mode 1, getposition when network broken
|
||
mPriData->mDemuxNotifyPause = 1;
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
mPriData->mDemuxPauseTimeStamp = tv.tv_sec * 1000000ll + tv.tv_usec;
|
||
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_INFO,
|
||
AW_MEDIA_INFO_BUFFERING_START, param);
|
||
break;
|
||
}
|
||
|
||
case DEMUX_NOTIFY_BUFFER_END:
|
||
{
|
||
logd("MEDIA_INFO_BUFFERING_END ...");
|
||
|
||
mPriData->mDemuxNotifyPause = 0;
|
||
mPriData->mDemuxPauseTimeStamp = 0;
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_INFO,
|
||
AW_MEDIA_INFO_BUFFERING_END, 0);
|
||
break;
|
||
}
|
||
|
||
case DEMUX_NOTIFY_PAUSE_PLAYER:
|
||
{
|
||
logd("XPLAYER_MESSAGE_DEMUX_PAUSE_PLAYER, mStatus = %d", mPriData->mStatus);
|
||
//* be careful to check whether there is any player callback lock the mMutexStatus,
|
||
//* if so, the PlayerPause() call may fall into dead lock if the player
|
||
//* callback is requesting mMutexStatus.
|
||
//* currently we do not lock mMutexStatus in any player callback.
|
||
pthread_mutex_lock(&mPriData->mMutexStatus);
|
||
if(mPriData->mStatus == XPLAYER_STATUS_STARTED)
|
||
PlayerPause(mPriData->mPlayer);
|
||
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
break;
|
||
}
|
||
|
||
case DEMUX_NOTIFY_RESUME_PLAYER:
|
||
{
|
||
//* be careful to check whether there is any player callback lock the mMutexStatus,
|
||
//* if so, the PlayerPause() call may fall into dead lock if the player
|
||
//* callback is requesting mMutexStatus.
|
||
//* currently we do not lock mMutexStatus in any player callback.
|
||
pthread_mutex_lock(&mPriData->mMutexStatus);
|
||
if (mPriData->mStatus == XPLAYER_STATUS_STARTED /*&& bBuffering == false*/)
|
||
{
|
||
PlayerStart(mPriData->mPlayer,0,0);
|
||
}
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
break;
|
||
}
|
||
|
||
#if !(defined(CONF_NEW_BDMV_STREAM))
|
||
|
||
case DEMUX_IOREQ_ACCESS:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_EXTEND_MEDIA_INFO,
|
||
AW_EX_IOREQ_ACCESS, param);
|
||
break;
|
||
}
|
||
|
||
case DEMUX_IOREQ_OPEN:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_EXTEND_MEDIA_INFO,
|
||
AW_EX_IOREQ_OPEN, param);
|
||
break;
|
||
}
|
||
|
||
case DEMUX_IOREQ_OPENDIR:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_EXTEND_MEDIA_INFO,
|
||
AW_EX_IOREQ_OPENDIR, param);
|
||
break;
|
||
}
|
||
|
||
case DEMUX_IOREQ_READDIR:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_EXTEND_MEDIA_INFO,
|
||
AW_EX_IOREQ_READDIR, param);
|
||
break;
|
||
}
|
||
|
||
case DEMUX_IOREQ_CLOSEDIR:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_EXTEND_MEDIA_INFO,
|
||
AW_EX_IOREQ_CLOSEDIR, param);
|
||
break;
|
||
}
|
||
|
||
#endif
|
||
|
||
case PLAYBACK_NOTIFY_EOS:
|
||
{
|
||
mPriData->mStatus = XPLAYER_STATUS_COMPLETE;
|
||
if(mPriData->mLoop == 0)
|
||
{
|
||
logd("player notify eos.");
|
||
mPriData->mSeekTime = 0; //* clear the seek flag.
|
||
mPriData->mbFast = 0;
|
||
mPriData->mSpeed = 1;
|
||
mPriData->mFastTime = 0;
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_PLAYBACK_COMPLETE, 0, 0);
|
||
}
|
||
else
|
||
{
|
||
AwMessage msg;
|
||
|
||
logv("player notify eos, loop is set, send start command.");
|
||
mPriData->mSeekTime = 0; //* seek to the file start and replay.
|
||
//* send a start message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_START;
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case PLAYBACK_NOTIFY_FIRST_PICTURE:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_INFO,
|
||
AW_MEDIA_INFO_RENDERING_START, 0);
|
||
DemuxCompNotifyFirstFrameShowed(mPriData->mDemux);
|
||
|
||
break;
|
||
}
|
||
case DEMUX_NOTIFY_RESET_PLAYER:
|
||
{
|
||
logd("DEMUX_NOTIFY_RESET_PLAYER");
|
||
mPriData->mLivemode = DemuxCompGetLiveMode(mPriData->mDemux);
|
||
if(mPriData->mLivemode == 1)
|
||
{
|
||
mPriData->mSeekTime = 0;
|
||
}
|
||
pthread_mutex_lock(&mPriData->mMutexStatus);
|
||
PlayerReset(mPriData->mPlayer, ((int64_t)mPriData->mSeekTime)*1000);
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
break;
|
||
}
|
||
case DEMUX_NOTIFY_SEEK_FINISH:
|
||
{
|
||
logd("DEMUX_NOTIFY_SEEK_FINISH");
|
||
int seekResult;
|
||
int nSeekTimeMs;
|
||
int nFinalSeekTimeMs;
|
||
|
||
//* be careful to check whether there is any player callback lock the mMutexStatus,
|
||
//* if so, the PlayerPause() call may fall into dead lock if the player
|
||
//* callback is requesting mMutexStatus.
|
||
//* currently we do not lock mMutexStatus in any player callback.
|
||
pthread_mutex_lock(&mPriData->mMutexStatus);
|
||
|
||
seekResult = ((int*)param)[0];
|
||
nSeekTimeMs = ((int*)param)[1];
|
||
nFinalSeekTimeMs = ((int*)param)[2];
|
||
|
||
int bSeekClosest = 0;
|
||
if(mPriData->mSeekModeType == AW_SEEK_CLOSEST)
|
||
{
|
||
bSeekClosest = 1;
|
||
}
|
||
|
||
if (seekResult == 0)
|
||
{
|
||
PlayerReset(mPriData->mPlayer, ((int64_t)nFinalSeekTimeMs)*1000);
|
||
|
||
if (nSeekTimeMs == mPriData->mSeekTime)
|
||
{
|
||
mPriData->mSeeking = 0;
|
||
if (mPriData->mStatus == XPLAYER_STATUS_STARTED)
|
||
{
|
||
PlayerStart(mPriData->mPlayer,bSeekClosest,nSeekTimeMs);
|
||
DemuxCompStart(mPriData->mDemux);
|
||
|
||
//check if seek call by xplayer inner case
|
||
//inner case seek no need to callback app
|
||
if (mPriData->mSeekByInner == 1)
|
||
{
|
||
mPriData->mSeekByInner = 0;
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
logv("seek time not match, there may be another seek operation happening.");
|
||
}
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_SEEK_COMPLETE, 0, 0);
|
||
}
|
||
else if(seekResult == DEMUX_ERROR_USER_CANCEL)
|
||
{
|
||
// do nothing , do not start player
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_SEEK_COMPLETE, 0, 0);
|
||
}
|
||
else
|
||
{
|
||
pthread_mutex_unlock(&mPriData->mMutexStatus);
|
||
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_ERROR, AW_MEDIA_ERROR_IO, 0);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case PLAYBACK_NOTIFY_SUBTITLE_ITEM_AVAILABLE:
|
||
{
|
||
|
||
//logd("subtitle available. id = %d, pSubtitleItem = %p",nSubtitleId,pSubtitleItem);
|
||
|
||
break;
|
||
}
|
||
|
||
case PLAYBACK_NOTIFY_SUBTITLE_ITEM_EXPIRED:
|
||
{
|
||
logd("subtitle expired.");
|
||
unsigned int nSubtitleId;
|
||
int i;
|
||
|
||
break;
|
||
}
|
||
|
||
case PLAYBACK_NOTIFY_VIDEO_SIZE:
|
||
{
|
||
int nWidth = ((int*)param)[0];
|
||
int nHeight = ((int*)param)[1];
|
||
logd("*************decoded nWidth = %d,nHeight = %d********",nWidth,nHeight);
|
||
int decodedSize[2];
|
||
decodedSize[0] = nWidth;
|
||
decodedSize[1] = nHeight;
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_DECODED_VIDEO_SIZE,
|
||
0, decodedSize);
|
||
//* if had scale down, we should zoom the widht and height
|
||
//* here the case of the VR9 we should not zoom the width and height
|
||
if(mPriData->mScaledownFlag == 1 && mPriData->bSetScaleDown != 1)
|
||
{
|
||
nWidth = 2*nWidth;
|
||
nHeight = 2*nHeight;
|
||
}
|
||
|
||
//if(nWidth != mVideoSizeWidth || nHeight != mVideoSizeHeight)
|
||
{
|
||
logi("xxxxxxxxxx video size : width = %d, height = %d", nWidth, nHeight);
|
||
|
||
mPriData->mVideoSizeWidth = nWidth;
|
||
mPriData->mVideoSizeHeight = nHeight;
|
||
int size[2];
|
||
size[0] = mPriData->mVideoSizeWidth;
|
||
size[1] = mPriData->mVideoSizeHeight;
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_SET_VIDEO_SIZE,
|
||
0, size);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case PLAYBACK_NOTIFY_AUDIORAWPLAY:
|
||
{
|
||
break;
|
||
}
|
||
case PLAYBACK_NOTIFY_VIDEO_CROP:
|
||
//* TODO
|
||
break;
|
||
|
||
case PLAYBACK_NOTIFY_VIDEO_UNSUPPORTED:
|
||
if(mPriData->mMediaInfo->nVideoStreamNum < 2)
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_ERROR,
|
||
AW_MEDIA_ERROR_UNSUPPORTED, 0);
|
||
}
|
||
|
||
break;
|
||
|
||
case PLAYBACK_NOTIFY_AUDIO_UNSUPPORTED:
|
||
if(mPriData->mMediaInfo->nVideoStreamNum == 0)
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_ERROR,
|
||
AW_MEDIA_ERROR_UNSUPPORTED, 0);
|
||
}
|
||
//* TODO
|
||
break;
|
||
|
||
case PLAYBACK_NOTIFY_SUBTITLE_UNSUPPORTED:
|
||
//* TODO
|
||
break;
|
||
|
||
case DEMUX_VIDEO_STREAM_CHANGE:
|
||
logd("update video info");
|
||
int a_change = ((int*)param)[0];
|
||
if(!a_change)
|
||
updateVideoInfo(p);
|
||
else
|
||
{
|
||
updateVideoInfo(p);
|
||
updateAudioInfo(p);
|
||
}
|
||
break;
|
||
case DEMUX_AUDIO_STREAM_CHANGE:
|
||
logd("update audio info");
|
||
updateAudioInfo(p);
|
||
break;
|
||
|
||
case PLAYBACK_NOTIFY_VIDEO_RENDER_FRAME:
|
||
#if 0
|
||
if(mPriData->mbFast)
|
||
{
|
||
logd("==== video key frame in fast mode, mFastTime: %d, mSpeed: %d",
|
||
mPriData->mFastTime, mPriData->mSpeed);
|
||
if(mPriData->mSpeed == 0)
|
||
{
|
||
break;
|
||
}
|
||
|
||
int sleepTime = (mPriData->mSpeed > 0) ? 2000000/mPriData->mSpeed :
|
||
(-2000000/mPriData->mSpeed);
|
||
//usleep(sleepTime);
|
||
|
||
mPriData->mFastTime += mPriData->mSpeed*1000;
|
||
if(mPriData->mFastTime > 0 && mPriData->mbFast)
|
||
{
|
||
AwMessage msg;
|
||
|
||
//* send a seek message.
|
||
memset(&msg, 0, sizeof(AwMessage));
|
||
msg.messageId = XPLAYER_COMMAND_SEEK;
|
||
msg.params[0] = (uintptr_t)&mPriData->mSemSeek;
|
||
msg.params[1] = (uintptr_t)&mPriData->mSeekReply;
|
||
msg.params[2] = mPriData->mFastTime; //* params[2] = mSeekTime.
|
||
msg.params[3] = 0; //* params[3] = mSeekSync.
|
||
|
||
AwMessageQueuePostMessage(mPriData->mMessageQueue, &msg);
|
||
}
|
||
else if(mPriData->mFastTime <= 0)
|
||
{
|
||
PlayerSetDiscardAudio(mPriData->mPlayer, 0);
|
||
mPriData->mbFast = 0;
|
||
}
|
||
}
|
||
#endif
|
||
break;
|
||
|
||
case DEMUX_NOTIFY_HLS_DOWNLOAD_START:
|
||
{
|
||
logd("--- hls message, DEMUX_NOTIFY_HLS_DOWNLOAD_START");
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_INFO,
|
||
AW_MEDIA_INFO_DOWNLOAD_START, param);
|
||
break;
|
||
}
|
||
case DEMUX_NOTIFY_HLS_DOWNLOAD_END:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_INFO,
|
||
AW_MEDIA_INFO_DOWNLOAD_END, param);
|
||
break;
|
||
}
|
||
case DEMUX_NOTIFY_HLS_DOWNLOAD_ERROR:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_INFO,
|
||
AW_MEDIA_INFO_DOWNLOAD_ERROR, param);
|
||
|
||
break;
|
||
}
|
||
case DEMUX_NOTIFY_LOG_RECORDER:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_LOG_RECORDER, 0, param);
|
||
break;
|
||
}
|
||
case DEMUX_NOTIFY_TIMESHIFT_DURATION:
|
||
{
|
||
if(mPriData->mLivemode == 2)
|
||
{
|
||
mPriData->mTimeShiftDuration = *(cdx_int64*)param;
|
||
logd("xxxxxxxxx mPriData->mTimeShiftDuration=%" PRId64 "",
|
||
mPriData->mTimeShiftDuration);
|
||
}
|
||
break;
|
||
}
|
||
case DEMUX_NOTIFY_METADATA:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_META_DATA,
|
||
0, param);
|
||
break;
|
||
}
|
||
|
||
case PLAYBACK_RESET_BUFFER_FINISHED:
|
||
{
|
||
mPriData->mCallback(mPriData->pUser, AWPLAYER_MEDIA_RESET_BUFFER_FINISHED,0, NULL);
|
||
break;
|
||
}
|
||
|
||
default:
|
||
{
|
||
logw("message 0x%x not handled.", messageId);
|
||
break;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|