SmartAudio/package/allwinner/tina_multimedia/libcedarx/android_adapter/awplayer/awplayer.cpp

2066 lines
66 KiB
C++
Raw Normal View History

2018-07-13 01:31:50 +00:00
/*
* Copyright (c) 2008-2016 Allwinner Technology Co. Ltd.
* All rights reserved.
*
* File : awplayer.cpp
* Description : mediaplayer adapter for operator
* History :
* Author : AL3
* Date : 2015/05/05
* Comment : first version
*
*/
#define LOG_TAG "awplayer"
#include "cdx_log.h"
#include "awplayer.h"
#include "subtitleUtils.h"
#include "awStreamingSource.h"
#include <string.h>
#include <media/Metadata.h>
#include <media/mediaplayer.h>
#include <binder/IPCThreadState.h>
#include <media/IAudioFlinger.h>
#include <fcntl.h>
#include <cutils/properties.h> // for property_get
#include <hardware/hwcomposer.h>
#include <version.h>
#include "xplayer.h"
#include "player.h"
#include "mediaInfo.h"
#include "AwMessageQueue.h"
#include "awLogRecorder.h"
#include "AwHDCPModule.h"
#include "outputCtrl.h"
#include "awLogRecorder.h"
#include "cdx_config.h"
#include "soundControl.h"
//wasu livemode4 , apk set seekTo after start, we should call start after seek
#define CMCC_LIVEMODE_4_BUG (1)
// the cmcc apk bug, change channel when buffering icon is displayed,
// the buffering icon is not diappered, so we send a buffer end message in prepare/prepareAsync
#define BUFFERING_ICON_BUG (1)
// 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)
#if (!((CONF_ANDROID_MAJOR_VER == 4)&&(CONF_ANDROID_SUB_VER == 2)))
//* android 4.4 use IGraphicBufferProducer instead of ISurfaceTexture in android 4.2.
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
#endif
static const char *WASU_APP_NAME = "net.sunniwell.app.ott.chinamobile";
static const char *CMCC_LOCAL_APP_NAME = "net.sunniwell.app.swplayer";
// static const char *MANGGUO_APP_NAME = "com.starcor.hunan";
static int XPlayerCallbackProcess(void* pUser, int eMessageId, int ext1, void* ext2);
static int GetCallingApkName(char* strApkName, int nMaxNameSize);
static int SubCallbackProcess(void* pUser, int eMessageId, void* param);
typedef struct PlayerPriData
{
XPlayer* mXPlayer;
XPlayerConfig_t mConfigInfo;
uid_t mUID; //* no use.
//* surface.
#if (!((CONF_ANDROID_MAJOR_VER == 4)&&(CONF_ANDROID_SUB_VER == 2)))
//* android 4.4 use IGraphicBufferProducer instead of ISurfaceTexture in android 4.2.
sp<IGraphicBufferProducer> mGraphicBufferProducer;
#else
sp<ISurfaceTexture> mSurfaceTexture;
#endif
sp<ANativeWindow> mNativeWindow;
char strApkName[128];
#if (CONF_ANDROID_MAJOR_VER >= 5)
sp<IMediaHTTPService> mHTTPService;
#endif
//* 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;
//* note whether the sutitle is in text or in bitmap format.
int mIsSubtitleInTextFormat;
//* 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;
//* save the currentSelectTrackIndex;
int mCurrentSelectVidoeTrackIndex;
int mCurrentSelectAudioTrackIndex;
int mCurrentSelectSubTrackIndex;
AwLogRecorder* mLogRecorder;
int mbIsDiagnose;
int64_t mPlayTimeMs;
int64_t mBufferTimeMs;
int mFirstStart;
int mKeepLastFrame;
//* for subtitle.
int mIsFirstItem;
}PlayerPriData;
static int resumeMediaScanner(const char* strApkName)
{
CEDARX_UNUSE(strApkName);
return property_set("mediasw.stopscaner", "0");
}
static int pauseMediaScanner(const char* strApkName)
{
CEDARX_UNUSE(strApkName);
return property_set("mediasw.stopscaner", "1");
}
void enableMediaBoost(MediaInfo* mi);
void disableMediaBoost();
AwPlayer::Instance AwPlayer::instance = {0, PTHREAD_MUTEX_INITIALIZER};
AwPlayer::AwPlayer()
{
logd("AwPlayer construct.");
pthread_mutex_lock(&instance.lock);
instance.count++;
pthread_mutex_unlock(&instance.lock);
mPriData = (PlayerPriData*)malloc(sizeof(PlayerPriData));
memset(mPriData,0x00,sizeof(PlayerPriData));
mPriData->mLogRecorder = NULL;
mPriData->mIsSubtitleDisable = 1;
mPriData->mIsFirstItem = 0;
#if (!((CONF_ANDROID_MAJOR_VER == 4)&&(CONF_ANDROID_SUB_VER == 2)))
//* android 4.4 use IGraphicBufferProducer instead of ISurfaceTexture in android 4.2.
mPriData->mGraphicBufferProducer = NULL;
#else
mPriData->mSurfaceTexture = NULL;
#endif
mPriData->mNativeWindow = NULL;
mPriData->mKeepLastFrame = 0;
GetCallingApkName(mPriData->strApkName, sizeof(mPriData->strApkName));
mPriData->mXPlayer = XPlayerCreate();
if(mPriData->mXPlayer != NULL)
{
struct HdcpOpsS hdcpOps;
hdcpOps.init = HDCP_Init;
hdcpOps.deinit = HDCP_Deinit;
hdcpOps.decrypt = HDCP_Decrypt;
XPlayerSetHdcpOps(mPriData->mXPlayer, &hdcpOps);
XPlayerSetNotifyCallback(mPriData->mXPlayer, XPlayerCallbackProcess, this);
SubCtrl* pSubCtrl = NULL;
#if (CONF_ANDROID_MAJOR_VER < 6)
if (!strcmp(mPriData->strApkName, CMCC_LOCAL_APP_NAME))
pSubCtrl = SubNativeRenderCreate();
else
#endif
pSubCtrl = SubtitleCreate(SubCallbackProcess, this);
XPlayerSetSubCtrl(mPriData->mXPlayer, pSubCtrl);
Deinterlace* di = DeinterlaceCreate();
XPlayerSetDeinterlace(mPriData->mXPlayer, di);
}
mPriData->mFirstStart = 1;
strcpy(mPriData->mDefaultTextFormat, "GBK");
//* clear the mSubtitleDisplayIds
memset(mPriData->mSubtitleDisplayIds,0xff,64*sizeof(unsigned int));
mPriData->mSubtitleDisplayIdsUpdateIndex = 0;
}
AwPlayer::~AwPlayer()
{
if(mPriData->mLogRecorder)
{
AwLogRecorderDestroy(mPriData->mLogRecorder);
mPriData->mLogRecorder = NULL;
}
if(mPriData->mXPlayer != NULL)
XPlayerDestroy(mPriData->mXPlayer);
free(mPriData);
mPriData = NULL;
pthread_mutex_lock(&instance.lock);
instance.count--;
if (instance.count == 0)
disableMediaBoost();
pthread_mutex_unlock(&instance.lock);
logd("~AwPlayer");
}
status_t AwPlayer::initCheck()
{
logv("initCheck");
if(mPriData->mXPlayer == NULL)
{
loge("initCheck() fail, XPlayer::mplayer = %p", mPriData->mXPlayer);
return NO_INIT;
}
return (status_t)XPlayerInitCheck(mPriData->mXPlayer);
}
status_t AwPlayer::setUID(uid_t uid)
{
logv("setUID(), uid = %d", uid);
mPriData->mUID = uid;
return OK;
}
static int cmccParseHeaders(CdxKeyedVectorT **header,
const KeyedVector<String8, String8>* pHeaders)
{
int nHeaderSize;
int i;
if (pHeaders == NULL)
return 0;
//*remove "x-hide-urls-from-log" ?
nHeaderSize = pHeaders->size();
if (nHeaderSize <= 0)
return -1;
*header = CdxKeyedVectorCreate(nHeaderSize);
if (*header == NULL)
{
logw("CdxKeyedVectorCreate() failed");
return -1;
}
String8 key;
String8 value;
for (i = 0; i < nHeaderSize; i++)
{
key = pHeaders->keyAt(i);
value = pHeaders->valueAt(i);
if (CdxKeyedVectorAdd(*header, key.string(), value.string()) != 0)
{
CdxKeyedVectorDestroy(*header);
return -1;
}
}
return 0;
}
#if (CONF_ANDROID_MAJOR_VER >= 5)
status_t AwPlayer::setDataSource(const sp<IMediaHTTPService> &httpService,
const char* pUrl,
const KeyedVector<String8,
String8>* pHeaders)
#else
status_t AwPlayer::setDataSource(const char* pUrl,
const KeyedVector<String8, String8>* pHeaders)
#endif
{
logd("setDataSource(url), url='%s'", pUrl);
void* pHttpService = NULL;
CdxKeyedVectorT* header = NULL;
#if (CONF_ANDROID_MAJOR_VER >= 5)
pHttpService = (void*)httpService.get();
#endif
int ret = cmccParseHeaders(&header, pHeaders);
if (ret < 0)
{
loge("parse Headers failed.");
return NO_MEMORY;
}
int livemode;
if(strstr(pUrl, "livemode=1"))
{
livemode = 1;
}
else if(strstr(pUrl, "livemode=2"))
{
livemode = 2;
}
else if(strstr(pUrl, "livemode=4"))
{
livemode = 4;
}
else
{
livemode = 0;
}
if (strstr(pUrl, "diagnose=deep"))
{
logd("In cmcc deep diagnose");
mPriData->mbIsDiagnose = 1;
}
else
{
mPriData->mbIsDiagnose = 0;
}
mPriData->mConfigInfo.livemode = livemode;
if (!strcmp(mPriData->strApkName, WASU_APP_NAME))
mPriData->mConfigInfo.appType = APP_CMCC_WASU;
else
mPriData->mConfigInfo.appType = APP_DEFAULT;
mPriData->mLogRecorder = NULL;
#if defined(CONF_CMCC)
mPriData->mLogRecorder = AwLogRecorderCreate();
#endif
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
snprintf(cmccLog, sizeof(cmccLog), "[info][%s %s %d]setDataSource, url: %s",
LOG_TAG, __FUNCTION__, __LINE__, pUrl);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
snprintf(cmccLog, sizeof(cmccLog), "[info][%s %s %d]create a new player",
LOG_TAG, __FUNCTION__, __LINE__);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
XPlayerConfig(mPriData->mXPlayer, &mPriData->mConfigInfo);
XPlayerSetDataSourceUrl(mPriData->mXPlayer, pUrl, pHttpService, header);
CdxKeyedVectorDestroy(header);
return OK;
}
//* Warning: The filedescriptor passed into this method will only be valid until
//* the method returns, if you want to keep it, dup it!
status_t AwPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
int ret;
if (!strcmp(mPriData->strApkName, CMCC_LOCAL_APP_NAME))
mPriData->mConfigInfo.appType = APP_CMCC_LOCAL;
else
mPriData->mConfigInfo.appType = APP_DEFAULT;
XPlayerConfig(mPriData->mXPlayer, &mPriData->mConfigInfo);
ret = XPlayerSetDataSourceFd(mPriData->mXPlayer, fd, offset, length);
return (status_t)ret;
}
status_t AwPlayer::setDataSource(const sp<IStreamSource> &source)
{
int ret;
logd("setDataSource(IStreamSource)");
unsigned int numBuffer, bufferSize;
const char *suffix = "";
if(!strcmp(mPriData->strApkName, "com.hpplay.happyplay.aw"))
{
numBuffer = 32;
bufferSize = 32*1024;
suffix = ".awts";
}
else if(!strcmp(mPriData->strApkName, "com.softwinner.miracastReceiver"))
{
numBuffer = 1024;
bufferSize = 188*8;
suffix = ".ts";
}
else
{
CDX_LOGW("this type is unknown.");
numBuffer = 16;
bufferSize = 4*1024;
}
CdxStreamT *stream = StreamingSourceOpen(source, numBuffer, bufferSize);
if(stream == NULL)
{
loge("StreamingSourceOpen fail!");
return UNKNOWN_ERROR;
}
char str[128];
sprintf(str, "customer://%p%s",stream, suffix);
//* send a set data source message.
mPriData->mConfigInfo.appType = APP_STREAMING;
XPlayerConfig(mPriData->mXPlayer, &mPriData->mConfigInfo);
ret = XPlayerSetDataSourceStream(mPriData->mXPlayer, str);
return (status_t)ret;
}
#if (!((CONF_ANDROID_MAJOR_VER == 4)&&(CONF_ANDROID_SUB_VER == 2)))
//* android 4.4 use IGraphicBufferProducer instead of ISurfaceTexture in android 4.2.
status_t AwPlayer::setVideoSurfaceTexture(const sp<IGraphicBufferProducer>& bufferProducer)
#else
status_t AwPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture)
#endif
{
int ret;
sp<ANativeWindow> anw;
logd("process message AWPLAYER_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.
#if (!((CONF_ANDROID_MAJOR_VER == 4)&&(CONF_ANDROID_SUB_VER == 2)))
if(bufferProducer.get() != NULL)
anw = new Surface(bufferProducer);
#else
if(surfaceTexture.get() != NULL)
anw = new SurfaceTextureClient(surfaceTexture);
#endif
else
anw = NULL;
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]setVideoSurfaceTexture", LOG_TAG, __FUNCTION__, __LINE__);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
LayerCtrl* lc;
lc = LayerCreate(anw.get());
ret = XPlayerSetVideoSurfaceTexture(mPriData->mXPlayer, lc);
//* save the new surface.
#if (!((CONF_ANDROID_MAJOR_VER == 4)&&(CONF_ANDROID_SUB_VER == 2)))
mPriData->mGraphicBufferProducer = bufferProducer;
#else
mPriData->mSurfaceTexture = surfaceTexture;
#endif
if(mPriData->mNativeWindow != NULL)
native_window_api_disconnect(mPriData->mNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
mPriData->mNativeWindow = anw;
return (status_t)ret;
}
void AwPlayer::setAudioSink(const sp<AudioSink> &audioSink)
{
logv("setAudioSink");
SoundCtrl* sc = SoundDeviceCreate(audioSink.get());
//SoundCtrl* sc = DefaultSoundDeviceCreate();
XPlayerSetAudioSink(mPriData->mXPlayer, sc);
//* super class MediaPlayerInterface has mAudioSink.
MediaPlayerInterface::setAudioSink(audioSink);
return;
}
#if (CONF_ANDROID_MAJOR_VER > 5)
status_t AwPlayer::setPlaybackSettings(const AudioPlaybackRate &rate)
{
XAudioPlaybackRate xrate;
xrate.mSpeed = rate.mSpeed;
xrate.mPitch= rate.mPitch;
xrate.mStretchMode= (XAudioTimestretchStretchMode)rate.mStretchMode;
xrate.mFallbackMode= (XAudioTimestretchFallbackMode)rate.mFallbackMode;
int ret=XPlayerSetPlaybackSettings(mPriData->mXPlayer,&xrate);
return ret;
}
status_t AwPlayer::getPlaybackSettings(AudioPlaybackRate *rate)
{
XAudioPlaybackRate xrate;
XPlayerGetPlaybackSettings(mPriData->mXPlayer,&xrate);
rate->mSpeed = xrate.mSpeed;
rate->mPitch = xrate.mPitch;
rate->mStretchMode = (AudioTimestretchStretchMode)xrate.mStretchMode;
rate->mFallbackMode = (AudioTimestretchFallbackMode)xrate.mFallbackMode;
return 0;
}
#endif
status_t AwPlayer::prepareAsync()
{
int ret;
logd("prepareAsync");
char prop_value[512];
int displayRatio = 1;
//* set scaling mode by default setting.
property_get("epg.default_screen_ratio", prop_value, "1");
if(atoi(prop_value) == 0)
{
logd("++++++++ IPTV_PLAYER_CONTENTMODE_LETTERBOX");
displayRatio = 0;
}
else
{
logd( "+++++++ IPTV_PLAYER_CONTENTMODE_FULL");
displayRatio = 1;
}
#if defined(CONF_PRODUCT_STB)
if(mPriData->mNativeWindow != NULL)
{
mPriData->mNativeWindow.get()->perform(mPriData->mNativeWindow.get(),
NATIVE_WINDOW_SETPARAMETER,
DISPLAY_CMD_SETSCREENRADIO,
displayRatio);
}
#endif
struct timeval tv;
int64_t startTimeMs = 0;
int64_t endTimeMs;
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]prepareAysnc start", LOG_TAG, __FUNCTION__, __LINE__);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
gettimeofday(&tv, NULL);
startTimeMs = (tv.tv_sec * 1000000ll + tv.tv_usec)/1000;
}
ret = XPlayerPrepareAsync(mPriData->mXPlayer);
if(0 == ret && mPriData->mLogRecorder != NULL)
{
gettimeofday(&tv, NULL);
endTimeMs = (tv.tv_sec * 1000000ll + tv.tv_usec)/1000;
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]Playback is ready, spend time: %lldms",
LOG_TAG, __FUNCTION__, __LINE__, (long long int)(endTimeMs - startTimeMs));
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
return (status_t)ret;
}
status_t AwPlayer::prepare()
{
int ret;
logd("prepare");
char prop_value[512];
int displayRatio = 1;
//* set scaling mode by default setting.
property_get("epg.default_screen_ratio", prop_value, "1");
if(atoi(prop_value) == 0)
{
logd("++++++++ IPTV_PLAYER_CONTENTMODE_LETTERBOX");
displayRatio = 0;
}
else
{
logd( "+++++++ IPTV_PLAYER_CONTENTMODE_FULL");
displayRatio = 1;
}
#if defined(CONF_PRODUCT_STB)
if(mPriData->mNativeWindow != NULL)
{
mPriData->mNativeWindow.get()->perform(mPriData->mNativeWindow.get(),
NATIVE_WINDOW_SETPARAMETER,
DISPLAY_CMD_SETSCREENRADIO,
displayRatio);
}
#endif
ret = XPlayerPrepare(mPriData->mXPlayer);
return (status_t)ret;
}
status_t AwPlayer::start()
{
int ret;
MediaInfo* mi;
pauseMediaScanner(mPriData->strApkName);
mi = XPlayerGetMediaInfo(mPriData->mXPlayer);
enableMediaBoost(mi);
mPriData->mCurrentSelectVidoeTrackIndex = 0;
mPriData->mCurrentSelectAudioTrackIndex = mi->nVideoStreamNum;
mPriData->mCurrentSelectSubTrackIndex = mi->nVideoStreamNum + mi->nAudioStreamNum;
// for livemode 4, cmcc apk invoke start before seekTo,
// it will get a frame between start and seekTo,
#if CMCC_LIVEMODE_4_BUG
if(mPriData->mConfigInfo.livemode == 4 && mPriData->mFirstStart &&
mPriData->mConfigInfo.appType == APP_CMCC_WASU)
{
return 0;
}
#endif
ret = XPlayerStart(mPriData->mXPlayer);
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]start", LOG_TAG, __FUNCTION__, __LINE__);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
struct timeval tv;
gettimeofday(&tv, NULL);
mPriData->mPlayTimeMs = (tv.tv_sec * 1000000ll + tv.tv_usec)/1000;
}
return (status_t)ret;
}
status_t AwPlayer::stop()
{
int ret;
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]stop", LOG_TAG, __FUNCTION__, __LINE__);
logd("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]destory this player", LOG_TAG, __FUNCTION__, __LINE__);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
ret = XPlayerStop(mPriData->mXPlayer);
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]Playback end", LOG_TAG, __FUNCTION__, __LINE__);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
//* clear the mSubtitleDisplayIds
memset(mPriData->mSubtitleDisplayIds,0xff,64*sizeof(unsigned int));
mPriData->mSubtitleDisplayIdsUpdateIndex = 0;
return (status_t)ret;
}
status_t AwPlayer::pause()
{
int ret;
logd(" pause ");
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]pause", LOG_TAG, __FUNCTION__, __LINE__);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
ret = XPlayerPause(mPriData->mXPlayer);
return (status_t)ret;
}
status_t AwPlayer::seekTo(int nSeekTimeMs)
{
logd("==== seekTo");
int ret;
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]seekTo, totime: %dms",
LOG_TAG, __FUNCTION__, __LINE__, nSeekTimeMs);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
#if CMCC_LIVEMODE_4_BUG
//for livemode4 , apk set seekTo after start, we should call start after seek
if(mPriData->mConfigInfo.livemode == 4 && mPriData->mFirstStart &&
mPriData->mConfigInfo.appType == APP_CMCC_WASU)
{
int status;
mPriData->mFirstStart = 0;
status = XPlayerSeekTo(mPriData->mXPlayer, nSeekTimeMs);
XPlayerStart(mPriData->mXPlayer);
return status;
}
#endif
/* 用户seek到约最后一秒我们认为用户真正的意图是seek到最后相关的bug有三个
*
* 1. parser内部的duration单位是微妙60000123 us
* duration是毫秒60000 ms
* seek到最后退
*
* 2. yunos上的应用在seek到最后时duration - 1000 ms作为seekto的位置
* HLS不开启切片内seek时seek到duration - 10 * 1000 ms的位置
* bug报出来
*
* 3. cmcc本地播放器舍去了duration里小于1秒的零头seek到最后
* mp4视频退seek失败
*/
if (mPriData->mConfigInfo.livemode == 0)
{
int dura = 0;
ret = XPlayerGetDuration(mPriData->mXPlayer, &dura);
int n = nSeekTimeMs + 1000;
if (ret == 0 && dura > 0 && n >= dura)
{
logd("change seek position from %d to %d", nSeekTimeMs, n);
nSeekTimeMs = n;
}
}
ret = XPlayerSeekTo(mPriData->mXPlayer, nSeekTimeMs);
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]seek complete", LOG_TAG, __FUNCTION__, __LINE__);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
return (status_t)ret;
}
status_t AwPlayer::reset()
{
int ret;
logd("... reset");
resumeMediaScanner(mPriData->strApkName);
ret = XPlayerReset(mPriData->mXPlayer);
//* clear suface.
if(mPriData->mKeepLastFrame == 0)
{
if(mPriData->mNativeWindow != NULL)
native_window_api_disconnect(mPriData->mNativeWindow.get(),
NATIVE_WINDOW_API_MEDIA);
mPriData->mNativeWindow.clear();
#if (!((CONF_ANDROID_MAJOR_VER == 4)&&(CONF_ANDROID_SUB_VER == 2)))
mPriData->mGraphicBufferProducer.clear();
#else
mPriData->mSurfaceTexture.clear();
#endif
}
//* clear audio sink.
mAudioSink.clear();
//* clear the mSubtitleDisplayIds
memset(mPriData->mSubtitleDisplayIds,0xff,64*sizeof(unsigned int));
mPriData->mSubtitleDisplayIdsUpdateIndex = 0;
return (status_t)ret;
}
status_t AwPlayer::setSpeed(int nSpeed)
{
int ret;
ret = XPlayerSetSpeed(mPriData->mXPlayer, nSpeed);
return (status_t)ret;
}
bool AwPlayer::isPlaying()
{
int ret;
ret = XPlayerIsPlaying(mPriData->mXPlayer);
return (ret == 1)? true : false;
}
status_t AwPlayer::getCurrentPosition(int* msec)
{
int ret;
ret = XPlayerGetCurrentPosition(mPriData->mXPlayer, msec);
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]current playtime: %dms",
LOG_TAG, __FUNCTION__, __LINE__, *msec);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
return (status_t)ret;
}
status_t AwPlayer::getDuration(int *msec)
{
int ret;
ret = XPlayerGetDuration(mPriData->mXPlayer, msec);
return (status_t)ret;
}
status_t AwPlayer::setLooping(int loop)
{
int ret;
ret = XPlayerSetLooping(mPriData->mXPlayer, loop);
return (status_t)ret;
}
player_type AwPlayer::playerType()
{
logv("playerType");
return AW_PLAYER;
}
status_t AwPlayer::invoke(const Parcel &request, Parcel *reply)
{
int nMethodId;
int ret;
MediaInfo* mi;
logv("invoke()");
ret = request.readInt32(&nMethodId);
if(ret != OK)
return ret;
mi = XPlayerGetMediaInfo(mPriData->mXPlayer);
switch(nMethodId)
{
case INVOKE_ID_GET_TRACK_INFO: //* get media stream counts.
{
logv("invode::INVOKE_ID_GET_TRACK_INFO");
if(mi == NULL)
{
return NO_INIT;
}
else
{
int i;
int nTrackCount;
const char* lang;
nTrackCount = mi->nVideoStreamNum + mi->nAudioStreamNum +
mi->nSubtitleStreamNum;
#if AWPLAYER_CONFIG_DISABLE_VIDEO
nTrackCount -= mi->nVideoStreamNum;
#endif
#if AWPLAYER_CONFIG_DISABLE_AUDIO
nTrackCount -= mi->nAudioStreamNum;
#endif
#if AWPLAYER_CONFIG_DISABLE_SUBTITLE
nTrackCount -= mi->nSubtitleStreamNum;
#endif
reply->writeInt32(nTrackCount);
#if !AWPLAYER_CONFIG_DISABLE_VIDEO
for(i=0; i<mi->nVideoStreamNum; i++)
{
#if defined(CONF_DETAIL_TRACK_INFO)
reply->writeInt32(4);
#else
reply->writeInt32(2);
#endif
reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO);
#if (CONF_ANDROID_MAJOR_VER >= 6)
reply->writeString16(String16("video/"));
#endif
lang = " ";
reply->writeString16(String16(lang));
#if defined(CONF_DETAIL_TRACK_INFO)
reply->writeInt32(mi->pVideoStreamInfo[i].bIs3DStream);
//Please refer to the "enum EVIDEOCODECFORMAT" in "vdecoder.h"
reply->writeInt32(mi->pVideoStreamInfo[i].eCodecFormat);
#endif
}
#endif
#if !AWPLAYER_CONFIG_DISABLE_AUDIO
for(i=0; i<mi->nAudioStreamNum; i++)
{
#if defined(CONF_DETAIL_TRACK_INFO)
reply->writeInt32(6);
#else
reply->writeInt32(2);
#endif
reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO);
#if (CONF_ANDROID_MAJOR_VER >= 6)
reply->writeString16(String16("audio/"));
#endif
if(mi->pAudioStreamInfo[i].strLang[0] != 0)
{
lang = (const char*)mi->pAudioStreamInfo[i].strLang;
reply->writeString16(String16(lang));
}
else
{
lang = "";
reply->writeString16(String16(lang));
}
#if defined(CONF_DETAIL_TRACK_INFO)
reply->writeInt32(mi->pAudioStreamInfo[i].nChannelNum);
reply->writeInt32(mi->pAudioStreamInfo[i].nSampleRate);
reply->writeInt32(mi->pAudioStreamInfo[i].nAvgBitrate);
//Please refer to the "enum EAUDIOCODECFORMAT" in "adecoder.h"
reply->writeInt32(mi->pAudioStreamInfo[i].eCodecFormat);
#endif
}
#endif
#if !AWPLAYER_CONFIG_DISABLE_SUBTITLE
for(i=0; i<mi->nSubtitleStreamNum; i++)
{
#if defined(CONF_DETAIL_TRACK_INFO)
reply->writeInt32(4);
#else
reply->writeInt32(2);
#endif
reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
#if (CONF_ANDROID_MAJOR_VER >= 6)
reply->writeString16(String16("text/3gpp-tt"));
#endif
if (mi->pSubtitleStreamInfo[i].strLang[0] != 0)
{
lang = (const char*)mi->pSubtitleStreamInfo[i].strLang;
reply->writeString16(String16(lang));
}
else
{
lang = "";
reply->writeString16(String16(lang));
}
#if defined(CONF_DETAIL_TRACK_INFO)
//Please refer to the "ESubtitleCodec" in "sdecoder.h"
reply->writeInt32(mi->pSubtitleStreamInfo[i].eCodecFormat);
reply->writeInt32(mi->pSubtitleStreamInfo[i].bExternal);
#endif
}
#endif
return OK;
}
}
case INVOKE_ID_ADD_EXTERNAL_SOURCE:
case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD:
{
logd("=== INVOKE_ID_ADD_EXTERNAL_SOURCE");
int fd;
int64_t nOffset;
int64_t nLength;
int fdSub;
if(nMethodId == INVOKE_ID_ADD_EXTERNAL_SOURCE)
{
//* string values written in Parcel are UTF-16 values.
String8 uri(request.readString16());
String8 mimeType(request.readString16());
//* if mimeType == "application/sub" and mIndexFileHasBeenSet == 0,
//* the .sub file is a common .sub subtitle, not index+sub subtitle.
if(strcmp((char*)mimeType.string(), "application/sub") == 0 &&
mPriData->mIndexFileHasBeenSet == 1)
{
//* the .sub file of index+sub subtitle.
//* no need to use the .sub file url, because subtitle decoder will
//* find the .sub file by itself by using the .idx file's url.
//* mimetype "application/sub" is defined in
//* "android/base/media/java/android/media/MediaPlayer.java".
//* clear the flag for adding more subtitle.
mPriData->mIndexFileHasBeenSet = 0;
return OK;
}
else if(strcmp((char*)mimeType.string(), "application/idx+sub") == 0)
{
//* set this flag to process the .sub file passed in at next call.
mPriData->mIndexFileHasBeenSet = 1;
}
//* probe subtitle info
XPlayerSetExternalSubUrl(mPriData->mXPlayer, uri.string());
}
else
{
fd = request.readFileDescriptor();
nOffset = request.readInt64();
nLength = request.readInt64();
fdSub = -1;
String8 mimeType(request.readString16());
//* if mimeType == "application/sub" and mIndexFileHasBeenSet == 0,
//* the .sub file is a common .sub subtitle, not index+sub subtitle.
if(strcmp((char*)mimeType.string(), "application/idx-sub") == 0)
{
//* the .idx file of index+sub subtitle.
mPriData->mIndexFileFdOfIndexSubtitle = dup(fd);
mPriData->mIndexFileHasBeenSet = 1;
return OK;
}
else if(strcmp((char*)mimeType.string(), "application/sub") == 0 &&
mPriData->mIndexFileHasBeenSet == 1)
{
//* the .sub file of index+sub subtitle.
//* for index+sub subtitle, PlayerProbeSubtitleStreamInfoFd() method need
//* the .idx file's descriptor for probe.
fdSub = fd; //* save the .sub file's descriptor to fdSub.
//* set the .idx file's descriptor to fd.
fd = mPriData->mIndexFileFdOfIndexSubtitle;
mPriData->mIndexFileFdOfIndexSubtitle = -1;
mPriData->mIndexFileHasBeenSet = 0;//* clear the flag for adding more subtitle.
}
//* probe subtitle info
XPlayerSetExternalSubFd(mPriData->mXPlayer, fd,nOffset,nLength, fdSub);
}
break;
}
case INVOKE_ID_SELECT_TRACK:
case INVOKE_ID_UNSELECT_TRACK:
{
int nStreamIndex;
int nTrackCount;
nStreamIndex = request.readInt32();
logd("invode::INVOKE_ID_SELECT_TRACK, stream index = %d", nStreamIndex);
if(mi == NULL)
{
loge("can not switch audio or subtitle, there is no media stream.");
return NO_INIT;
}
nTrackCount = mi->nVideoStreamNum + mi->nAudioStreamNum +
mi->nSubtitleStreamNum;
if(nTrackCount == 0)
{
loge("can not switch audio or subtitle, there is no media stream.");
return NO_INIT;
}
if(nStreamIndex >= mi->nVideoStreamNum &&
nStreamIndex < (mi->nVideoStreamNum + mi->nAudioStreamNum))
{
if(nMethodId == INVOKE_ID_SELECT_TRACK)
{
//* switch audio.
mPriData->mCurrentSelectAudioTrackIndex = nStreamIndex;
nStreamIndex -= mi->nVideoStreamNum;
if(XPlayerSwitchAudio(mPriData->mXPlayer, nStreamIndex) != 0)
{
loge("can not switch audio, call PlayerSwitchAudio() return fail.");
return UNKNOWN_ERROR;
}
}
else
{
mPriData->mCurrentSelectAudioTrackIndex = -1;
loge("Deselect an audio track (%d) is not supported", nStreamIndex);
return INVALID_OPERATION;
}
return OK;
}
else if(nStreamIndex >= (mi->nVideoStreamNum + mi->nAudioStreamNum) &&
nStreamIndex < nTrackCount)
{
if(nMethodId == INVOKE_ID_SELECT_TRACK)
{
logv("==== INVOKE_ID_SELECT_TRACK, nStreamIndex: %d", nStreamIndex);
//* enable subtitle.
mPriData->mIsSubtitleDisable = 0;
mPriData->mCurrentSelectSubTrackIndex = nStreamIndex;
//* switch subtitle.
nStreamIndex -= (mi->nVideoStreamNum + mi->nAudioStreamNum);
if(XPlayerSwitchSubtitle(mPriData->mXPlayer, nStreamIndex) != 0)
{
loge("can not switch subtitle, call PlayerSwitchSubtitle() return fail.");
return UNKNOWN_ERROR;
}
mPriData->mIsFirstItem = 1;
logv("mIsFirstItem: %d", mPriData->mIsFirstItem);
}
else
{
logv("==== INVOKE_ID_DESELECT_TRACK, nStreamIndex: %d", nStreamIndex);
if(mPriData->mCurrentSelectSubTrackIndex != nStreamIndex)
{
logw("the unselectTrack is not right: %d, %d",
mPriData->mCurrentSelectSubTrackIndex,nStreamIndex);
return INVALID_OPERATION;
}
mPriData->mIsSubtitleDisable = 1; //* disable subtitle show.
sendEvent(MEDIA_TIMED_TEXT);//* clear all the displaying subtitle
//* clear the mSubtitleDisplayIds
memset(mPriData->mSubtitleDisplayIds,0xff,64*sizeof(unsigned int));
mPriData->mSubtitleDisplayIdsUpdateIndex = 0;
mPriData->mCurrentSelectSubTrackIndex = -1;
}
return OK;
}
if(nMethodId == INVOKE_ID_SELECT_TRACK)
{
loge("can not switch audio or subtitle to track %d, \
stream index exceed.(%d stream in total).",
nStreamIndex, nTrackCount);
}
else
{
loge("can not unselect track %d, stream index exceed.(%d stream in total).",
nStreamIndex, nTrackCount);
}
return BAD_INDEX;
break;
}
case INVOKE_ID_SET_VIDEO_SCALING_MODE:
{
int nStreamIndex;
nStreamIndex = request.readInt32();
logv("invode::INVOKE_ID_SET_VIDEO_SCALING_MODE");
//* TODO.
return OK;
}
#if defined(CONF_PRODUCT_STB)
case INVOKE_ID_SET_3D_MODE:
{
logd(" donot set 3d mode");
break;
}
case INVOKE_ID_GET_3D_MODE:
{
break;
}
#endif
#if (CONF_ANDROID_MAJOR_VER >= 5)
case INVOKE_ID_GET_SELECTED_TRACK:
{
int trackType = request.readInt32();
logd("==== invoke: INVOKE_ID_GET_SELECTED_TRACK, trackType(%d)", trackType);
logd("=== mCurrentSelectSubTrackIndex: %d", mPriData->mCurrentSelectSubTrackIndex);
if(trackType == MEDIA_TRACK_TYPE_VIDEO)
reply->writeInt32(mPriData->mCurrentSelectVidoeTrackIndex);
else if(trackType == MEDIA_TRACK_TYPE_AUDIO)
reply->writeInt32(mPriData->mCurrentSelectAudioTrackIndex);
else if(trackType == MEDIA_TRACK_TYPE_TIMEDTEXT ||
trackType == MEDIA_TRACK_TYPE_SUBTITLE)
reply->writeInt32(mPriData->mCurrentSelectSubTrackIndex);
else
logw("invoke: INVOKE_ID_GET_SELECTED_TRACK, trackType(%d) unkown", trackType);
break;
}
#endif
default:
{
logv("unknown invode command %d", nMethodId);
return UNKNOWN_ERROR;
}
}
return OK;
}
status_t AwPlayer::setParameter(int key, const Parcel &request)
{
logv("setParameter(key=%d)", key);
(void)key;
(void)request;
return OK;
#if 0
switch(key)
{
case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS:
{
int nCacheReportIntervalMs;
logv("setParameter::KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS");
nCacheReportIntervalMs = request.readInt32();
if(DemuxCompSetCacheStatReportInterval(mPriData->mDemux, nCacheReportIntervalMs) == 0)
return OK;
else
return UNKNOWN_ERROR;
}
case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE:
{
logv("setParameter::KEY_PARAMETER_PLAYBACK_RATE_PERMILLE");
//* TODO.
return OK;
}
default:
{
logv("unknown setParameter command %d", key);
return UNKNOWN_ERROR;
}
}
#endif
}
status_t AwPlayer::getParameter(int key, Parcel *reply)
{
logv("getParameter");
(void)(key);
(void)(reply);
return OK;
#if 0
switch(key)
{
case KEY_PARAMETER_AUDIO_CHANNEL_COUNT:
{
logv("getParameter::KEY_PARAMETER_AUDIO_CHANNEL_COUNT");
//* TODO.
return OK;
}
#if 0// use define CONF_PRODUCT_STB/CONF_CMCC/CONF_YUNOS instead
case KEY_PARAMETER_GET_CURRENT_BITRATE:
{
logd("getParameter::PARAM_KEY_GET_CURRENT_BITRATE");
if(mPriData->mXPlayer != NULL)
{
int currentVideoBitrate = 0;
int currentAudioBitrate = 0;
int currentBitrate = 0;
currentVideoBitrate = PlayerGetVideoBitrate(mPriData->mXPlayer);
currentAudioBitrate = PlayerGetAudioBitrate(mPriData->mXPlayer);
currentBitrate = currentVideoBitrate + currentAudioBitrate;
logd("current Bitrate: video(%d)b/s + audio(%d)b/s = (%d)b/s",
currentVideoBitrate, currentAudioBitrate, currentBitrate);
reply->writeInt32(currentBitrate);
}
return OK;
}
case KEY_PARAMETER_GET_CURRENT_CACHE_DATA_DURATION:
{
logv("getParameter::PARAM_KEY_GET_CURRENT_CACHE_DATA_DURATION");
if(mPriData->mXPlayer != NULL)
{
int currentBitrate = 0;
int currentCacheDataSize = 0;
int currentCacheDataDuration = 0;
currentBitrate = PlayerGetVideoBitrate(mPriData->mXPlayer) +
PlayerGetAudioBitrate(mPriData->mXPlayer);
currentCacheDataSize = DemuxCompGetCacheSize(mPriData->mDemux);
if(currentBitrate <= 0)
{
currentCacheDataDuration = 0;
reply->writeInt32((int)currentCacheDataDuration);
}
else
{
int64_t tmp = (float)currentCacheDataSize*8.0*1000.0;
tmp /= (float)currentBitrate;
currentCacheDataDuration = (int)tmp;
reply->writeInt32((int)currentCacheDataDuration);
}
logd("currentDataSize(%d)B currentBitrate(%d)b/s currentDataDuration(%d)ms",
currentCacheDataSize, currentBitrate, currentCacheDataDuration);
}
return OK;
}
#endif
default:
{
loge("unknown getParameter command %d", key);
return UNKNOWN_ERROR;
}
}
#endif
}
status_t AwPlayer::getMetadata(const media::Metadata::Filter& ids, Parcel *records)
{
using media::Metadata;
Metadata metadata(records);
MediaInfo* mi;
mi = XPlayerGetMediaInfo(mPriData->mXPlayer);
CEDARX_UNUSE(ids);
if(mi == NULL)
{
return NO_INIT;
}
if(mi->nDurationMs > 0)
metadata.appendBool(Metadata::kPauseAvailable , true);
else
metadata.appendBool(Metadata::kPauseAvailable , false); //* live stream, can not pause.
if(mi->bSeekable)
{
metadata.appendBool(Metadata::kSeekBackwardAvailable, true);
metadata.appendBool(Metadata::kSeekForwardAvailable, true);
metadata.appendBool(Metadata::kSeekAvailable, true);
}
else
{
metadata.appendBool(Metadata::kSeekBackwardAvailable, false);
metadata.appendBool(Metadata::kSeekForwardAvailable, false);
metadata.appendBool(Metadata::kSeekAvailable, false);
}
return OK;
//* other metadata in include/media/Metadata.h, Keep in sync with android/media/Metadata.java.
/*
Metadata::kTitle; // String
Metadata::kComment; // String
Metadata::kCopyright; // String
Metadata::kAlbum; // String
Metadata::kArtist; // String
Metadata::kAuthor; // String
Metadata::kComposer; // String
Metadata::kGenre; // String
Metadata::kDate; // Date
Metadata::kDuration; // Integer(millisec)
Metadata::kCdTrackNum; // Integer 1-based
Metadata::kCdTrackMax; // Integer
Metadata::kRating; // String
Metadata::kAlbumArt; // byte[]
Metadata::kVideoFrame; // Bitmap
Metadata::kBitRate; // Integer, Aggregate rate of
Metadata::kAudioBitRate; // Integer, bps
Metadata::kVideoBitRate; // Integer, bps
Metadata::kAudioSampleRate; // Integer, Hz
Metadata::kVideoframeRate; // Integer, Hz
// See RFC2046 and RFC4281.
Metadata::kMimeType; // String
Metadata::kAudioCodec; // String
Metadata::kVideoCodec; // String
Metadata::kVideoHeight; // Integer
Metadata::kVideoWidth; // Integer
Metadata::kNumTracks; // Integer
Metadata::kDrmCrippled; // Boolean
*/
}
status_t AwPlayer::setSubCharset(const char* strFormat)
{
if(strFormat != NULL)
{
int i;
for(i=0; strTextCodecFormats[i]; i++)
{
if(!strcmp(strTextCodecFormats[i], strFormat))
break;
}
if(strTextCodecFormats[i] != NULL)
strcpy(mPriData->mDefaultTextFormat, strTextCodecFormats[i]);
}
else
strcpy(mPriData->mDefaultTextFormat, "UTF-8");
return OK;
}
status_t AwPlayer::getSubCharset(char *charset)
{
if(mPriData->mXPlayer == NULL)
{
return -1;
}
strcpy(charset, mPriData->mDefaultTextFormat);
return OK;
}
status_t AwPlayer::setSubDelay(int nTimeMs)
{
if(mPriData->mXPlayer == NULL)
{
return -1;
}
return XPlayerSetSubDelay(mPriData->mXPlayer, nTimeMs);
}
int AwPlayer::getSubDelay()
{
if(mPriData->mXPlayer == NULL)
{
return -1;
}
return XPlayerGetSubDelay(mPriData->mXPlayer);
}
status_t AwPlayer::callbackProcess(int messageId, int ext1, void* param)
{
switch(messageId)
{
case AWPLAYER_MEDIA_PREPARED:
{
#if BUFFERING_ICON_BUG
if (!mPriData->mbIsDiagnose &&
mPriData->mConfigInfo.appType == APP_CMCC_WASU)
{
sendEvent(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
}
#endif
sendEvent(MEDIA_PREPARED, 0, 0);
break;
}
case AWPLAYER_MEDIA_PLAYBACK_COMPLETE:
{
sendEvent(MEDIA_PLAYBACK_COMPLETE, 0, 0);
break;
}
case AWPLAYER_MEDIA_SEEK_COMPLETE:
{
sendEvent(MEDIA_SEEK_COMPLETE, 0, 0);
break;
}
case AWPLAYER_MEDIA_LOG_RECORDER:
{
if(mPriData->mLogRecorder != NULL)
{
logv("AwLogRecorderRecord %s.", (char*)param);
AwLogRecorderRecord(mPriData->mLogRecorder, (char*)param);
}
break;
}
case AWPLAYER_MEDIA_BUFFERING_UPDATE:
{
int nTotalPercentage;
int nBufferPercentage;
int nLoadingPercentage;
nTotalPercentage = ((int*)param)[0]; //* read positon to total file size.
nBufferPercentage = ((int*)param)[1]; //* cache buffer fullness.
nLoadingPercentage = ((int*)param)[2]; //* loading percentage to start play.
sendEvent(MEDIA_BUFFERING_UPDATE, nTotalPercentage,
nBufferPercentage<<16 | nLoadingPercentage);
break;
}
case AWPLAYER_MEDIA_ERROR:
{
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[error][%s %s %d]Error happened, event: %d",
LOG_TAG, __FUNCTION__, __LINE__, ext1);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
#if defined(CONF_PRODUCT_STB)
if(ext1 == AW_MEDIA_ERROR_UNKNOWN)
sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, 0);
else if(ext1 == AW_MEDIA_ERROR_IO)
sendEvent(MEDIA_ERROR, MEDIA_ERROR_IO, 0);
else if(ext1 == AW_MEDIA_ERROR_UNSUPPORTED)
sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNSUPPORTED, 0);
else
{
logw("unkown ext1: %d", ext1);
sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, 0);
}
#else
sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, 0);
#endif
break;
}
case AWPLAYER_MEDIA_INFO:
{
switch(ext1)
{
case AW_MEDIA_INFO_UNKNOWN:
sendEvent(MEDIA_INFO, MEDIA_INFO_UNKNOWN);
break;
case AW_MEDIA_INFO_RENDERING_START:
{
if(mPriData->mLogRecorder != NULL)
{
struct timeval tv;
int64_t renderTimeMs;
gettimeofday(&tv, NULL);
renderTimeMs = (tv.tv_sec * 1000000ll + tv.tv_usec)/1000;
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]show the first video frame,"
" spend time: %lldms",
LOG_TAG, __FUNCTION__, __LINE__,
(long long int)(renderTimeMs - mPriData->mPlayTimeMs));
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
sendEvent(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0);
sendEvent(MEDIA_STARTED, 0, 0);
break;
}
case AW_MEDIA_INFO_BUFFERING_START:
{
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
int *pNeedBufferSize = (int*)param;
sprintf(cmccLog, "[info][%s %s %d]buffering start, "
"need buffer data size: %.2fMB",
LOG_TAG, __FUNCTION__, __LINE__,
*pNeedBufferSize/(1024*1024.0f));
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
struct timeval tv;
gettimeofday(&tv, NULL);
mPriData->mBufferTimeMs = (tv.tv_sec * 1000000ll + tv.tv_usec)/1000;
}
sendEvent(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
break;
}
case AW_MEDIA_INFO_BUFFERING_END:
{
if(mPriData->mLogRecorder != NULL)
{
struct timeval tv;
gettimeofday(&tv, NULL);
int64_t bufferEndTimeMs = (tv.tv_sec * 1000000ll + tv.tv_usec)/1000;
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]buffering end, lasting time: %lldms",
LOG_TAG, __FUNCTION__, __LINE__,
(long long int)(bufferEndTimeMs - mPriData->mBufferTimeMs));
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
sendEvent(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
break;
}
case AW_MEDIA_INFO_NOT_SEEKABLE:
sendEvent(MEDIA_INFO, MEDIA_INFO_NOT_SEEKABLE, 0);
break;
#if defined(CONF_PRODUCT_STB)
case AW_MEDIA_INFO_DOWNLOAD_START:
{
DownloadObject* obj = (DownloadObject*)param;
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]ts segment download is start, "
"number: %d, filesize: %.2fMB, duration: %lldms",
LOG_TAG, __FUNCTION__, __LINE__, obj->seqNum,
(float)obj->seqSize/(1024*1024.0f), obj->seqDuration/1000);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
sendEvent(MEDIA_INFO, MEDIA_INFO_DOWNLOAD_START, obj->seqNum);
break;
}
case AW_MEDIA_INFO_DOWNLOAD_END:
{
DownloadObject* obj = (DownloadObject*)param;
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[info][%s %s %d]ts segment download is complete, "
"recvsize: %.2fMB, spend time: %lldms, rate: %lldbps",
LOG_TAG, __FUNCTION__, __LINE__,
(float)obj->seqSize/(1024*1024.0f),
obj->spendTime, obj->rate);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
sendEvent(MEDIA_INFO, MEDIA_INFO_DOWNLOAD_END, (int)obj->spendTime);
break;
}
case AW_MEDIA_INFO_DOWNLOAD_ERROR:
{
DownloadObject* obj = (DownloadObject*)param;
if(mPriData->mLogRecorder != NULL)
{
char cmccLog[4096] = "";
sprintf(cmccLog, "[error][%s %s %d]Error happened, event: %d", LOG_TAG,
__FUNCTION__, __LINE__, MEDIA_INFO_DOWNLOAD_ERROR);
logv("AwLogRecorderRecord %s.", cmccLog);
AwLogRecorderRecord(mPriData->mLogRecorder, cmccLog);
}
sendEvent(MEDIA_INFO, MEDIA_INFO_DOWNLOAD_ERROR, obj->statusCode);
break;
}
#endif
default:
logw("unkown info msg");
break;
}
break;
}
#if !(defined(CONF_NEW_BDMV_STREAM))
case AWPLAYER_EXTEND_MEDIA_INFO:
{
switch(ext1)
{
case AW_EX_IOREQ_ACCESS:
{
char *filePath = (char *)((uintptr_t *)param)[0];
int mode = ((uintptr_t *)param)[1];
int *pRet = (int *)((uintptr_t *)param)[2];
Parcel parcel;
Parcel replyParcel;
*pRet = -1;
// write path string as a byte array
parcel.writeInt32(strlen(filePath));
parcel.write(filePath, strlen(filePath));
parcel.writeInt32(mode);
sendEvent(AWEXTEND_MEDIA_INFO,
AWEXTEND_MEDIA_INFO_CHECK_ACCESS_RIGHRS,
0, &parcel, &replyParcel);
replyParcel.setDataPosition(0);
*pRet = replyParcel.readInt32();
break;
}
case AW_EX_IOREQ_OPEN:
{
char *filePath = (char *)((uintptr_t *)param)[0];
int *pFd = (int *)((uintptr_t *)param)[1];
int fd = -1;
Parcel parcel;
Parcel replyParcel;
bool bFdValid = false;
*pFd = -1;
// write path string as a byte array
parcel.writeInt32(strlen(filePath));
parcel.write(filePath, strlen(filePath));
sendEvent(AWEXTEND_MEDIA_INFO,
AWEXTEND_MEDIA_INFO_REQUEST_OPEN_FILE,
0, &parcel, &replyParcel);
replyParcel.setDataPosition(0);
bFdValid = replyParcel.readInt32();
if (bFdValid == true)
{
fd = replyParcel.readFileDescriptor();
if (fd < 0)
{
loge("invalid fd '%d'", fd);
*pFd = -1;
break;
}
*pFd = dup(fd);
if (*pFd < 0)
{
loge("dup fd failure, errno(%d) '%d'", errno, fd);
}
close(fd);
}
break;
}
case AW_EX_IOREQ_OPENDIR:
{
char *dirPath = (char *)((uintptr_t *)param)[0];
int *pDirId = (int *)((uintptr_t *)param)[1];
Parcel parcel;
Parcel replyParcel;
*pDirId = -1;
// write path string as a byte array
parcel.writeInt32(strlen(dirPath));
parcel.write(dirPath, strlen(dirPath));
sendEvent(AWEXTEND_MEDIA_INFO,
AWEXTEND_MEDIA_INFO_REQUEST_OPEN_DIR,
0, &parcel, &replyParcel);
replyParcel.setDataPosition(0);
*pDirId = replyParcel.readInt32();
break;
}
case AW_EX_IOREQ_READDIR:
{
int dirId = ((uintptr_t *)param)[0];
int *pRet = (int *)((uintptr_t *)param)[1];
char *buf = (char *)((uintptr_t *)param)[2];
int bufLen = ((uintptr_t *)param)[3];
loge("** aw-read-dir: dirId = %d, buf = %p, bufLen = %d",
dirId,buf,bufLen);
Parcel parcel;
Parcel replyParcel;
int fileNameLen = -1;
int32_t replyRet = -1;
*pRet = -1;
// write path string as a byte array
parcel.writeInt32(dirId);
sendEvent(AWEXTEND_MEDIA_INFO, AWEXTEND_MEDIA_INFO_REQUEST_READ_DIR,
0, &parcel, &replyParcel);
replyParcel.setDataPosition(0);
replyRet = replyParcel.readInt32();
if (0 == replyRet)
{
fileNameLen = replyParcel.readInt32();
if (fileNameLen > 0 && fileNameLen < bufLen)
{
const char* strdata = (const char*)replyParcel.readInplace(fileNameLen);
memcpy(buf, strdata, fileNameLen);
buf[fileNameLen] = 0;
*pRet = 0;
}
}
break;
}
case AW_EX_IOREQ_CLOSEDIR:
{
int dirId = ((uintptr_t *)param)[0];
int *pRet = (int *)((uintptr_t *)param)[1];
Parcel parcel;
Parcel replyParcel;
// write path string as a byte array
parcel.writeInt32(dirId);
sendEvent(AWEXTEND_MEDIA_INFO,
AWEXTEND_MEDIA_INFO_REQUEST_CLOSE_DIR,
0, &parcel, &replyParcel);
replyParcel.setDataPosition(0);
*pRet = replyParcel.readInt32();
break;
}
}
}
#endif
case SUBCTRL_SUBTITLE_AVAILABLE:
{
Parcel parcel;
unsigned int nSubtitleId = (unsigned int)((uintptr_t*)param)[0];
SubtitleItem* pSubtitleItem = (SubtitleItem*)((uintptr_t*)param)[1];
logd("subtitle available. id = %d, pSubtitleItem = %p",nSubtitleId,pSubtitleItem);
if(pSubtitleItem == NULL)
{
logw("pSubtitleItem == NULL");
break;
}
mPriData->mIsSubtitleInTextFormat = !!pSubtitleItem->bText; //* 0 or 1.
if(mPriData->mIsSubtitleDisable == 0)
{
if(mPriData->mIsSubtitleInTextFormat)
{
SubtitleUtilsFillTextSubtitleToParcel(&parcel,
pSubtitleItem,
nSubtitleId,
mPriData->mDefaultTextFormat,
&mPriData->mIsFirstItem);
}
else
{
//* clear the mSubtitleDisplayIds
memset(mPriData->mSubtitleDisplayIds,0xff,64*sizeof(unsigned int));
mPriData->mSubtitleDisplayIdsUpdateIndex = 0;
sendEvent(MEDIA_TIMED_TEXT); //* clear bmp subtitle first
SubtitleUtilsFillBitmapSubtitleToParcel(&parcel, pSubtitleItem, nSubtitleId);
}
//*record subtitile id
mPriData->mSubtitleDisplayIds[mPriData->mSubtitleDisplayIdsUpdateIndex] =
nSubtitleId;
mPriData->mSubtitleDisplayIdsUpdateIndex++;
if(mPriData->mSubtitleDisplayIdsUpdateIndex>=64)
mPriData->mSubtitleDisplayIdsUpdateIndex = 0;
logd("notify available message.");
sendEvent(MEDIA_TIMED_TEXT, 0, 0, &parcel);
}
break;
}
case SUBCTRL_SUBTITLE_EXPIRED:
{
logd("subtitle expired.");
Parcel parcel;
unsigned int nSubtitleId;
int i;
nSubtitleId = *(unsigned int*)param;
if(mPriData->mIsSubtitleDisable == 0)
{
//* match the subtitle id which is displaying ,or we may clear null subtitle
for(i=0;i<64;i++)
{
if(nSubtitleId==mPriData->mSubtitleDisplayIds[i])
break;
}
if(i!=64)
{
mPriData->mSubtitleDisplayIds[i] = 0xffffffff;
if(mPriData->mIsSubtitleInTextFormat == 1)
{
//* set subtitle id
parcel.writeInt32(KEY_GLOBAL_SETTING);
//* nofity app to hide this subtitle
parcel.writeInt32(KEY_STRUCT_AWEXTEND_HIDESUB);
parcel.writeInt32(1);
parcel.writeInt32(KEY_SUBTITLE_ID);
parcel.writeInt32(nSubtitleId);
logd("notify text expired message.");
sendEvent(MEDIA_TIMED_TEXT, 0, 0, &parcel);
}
else
{
//* clear the mSubtitleDisplayIds
memset(mPriData->mSubtitleDisplayIds,0xff,64*sizeof(unsigned int));
mPriData->mSubtitleDisplayIdsUpdateIndex = 0;
//* if the sub is bmp ,we just send "clear all" command,
//* nSubtitleId is not sent.
logd("notify subtitle expired message.");
sendEvent(MEDIA_TIMED_TEXT);
}
}
}
break;
}
case AWPLAYER_MEDIA_SET_VIDEO_SIZE:
{
int nWidth = ((int*)param)[0];
int nHeight = ((int*)param)[1];
logd("=== set videosize (%d, %d)", nWidth, nHeight);
sendEvent(MEDIA_SET_VIDEO_SIZE, nWidth, nHeight);
break;
}
#if (CONF_ANDROID_MAJOR_VER > 6)
case AWPLAYER_MEDIA_META_DATA:
{
Parcel parcel;
int size;
char* buffer;
int64_t timeUs = ((unsigned int*)param)[0];
timeUs <<= 32;
timeUs |= ((unsigned int*)param)[1];
size = ((int*)param)[2];
buffer = (char*)((unsigned int*)param)[3];
parcel.writeInt64(timeUs);
parcel.writeInt32(size);
parcel.writeInt32(size);
parcel.write(buffer, size);
logv("notify meta data message.");
sendEvent(MEDIA_META_DATA, 0, 0, &parcel);
break;
}
#endif
default:
{
logw("message 0x%x not handled.", messageId);
break;
}
}
return OK;
}
static int XPlayerCallbackProcess(void* pUser, int eMessageId, int ext1, void* param)
{
AwPlayer *p = (AwPlayer*)pUser;
p->callbackProcess(eMessageId, ext1, param);
return 0;
}
static int SubCallbackProcess(void* pUser, int eMessageId, void* param)
{
AwPlayer* p = (AwPlayer*)pUser;
p->callbackProcess(eMessageId, 0, param);
return 0;
}
static int GetCallingApkName(char* strApkName, int nMaxNameSize)
{
int fd;
snprintf(strApkName, nMaxNameSize, "/proc/%d/cmdline",
IPCThreadState::self()->getCallingPid());
fd = ::open(strApkName, O_RDONLY);
strApkName[0] = '\0';
if (fd >= 0)
{
strApkName[nMaxNameSize - 1] = '\0';
::read(fd, strApkName, nMaxNameSize - 1);
::close(fd);
logd("Calling process is: %s", strApkName);
}
return 0;
}
void enableMediaBoost(MediaInfo* mi)
{
char cmd[PROP_VALUE_MAX] = {0};
int total = 0;
struct ScMemOpsS *memops = NULL;
if(mi == NULL || mi->pVideoStreamInfo == NULL)
{
logd("input invalid args.");
return;
}
#if defined(CONF_MEDIA_BOOST_MEM)
if(mi->pVideoStreamInfo->bSecureStreamFlagLevel1 == 1)
{
memops = SecureMemAdapterGetOpsS();
}
else
{
memops = MemAdapterGetOpsS();
}
CdcMemOpen(memops);
total = CdcMemTotalSize(memops);
CdcMemClose(memops);
//set the mem property
if((mi->pVideoStreamInfo->nWidth >= WIDTH_4K || mi->pVideoStreamInfo->nHeight >= HEIGHT_4K)
&& total < 190000 )
{
sprintf(cmd, "model%d:3", getpid());
logd("setprop media.boost.pref %s", cmd);
property_set("media.boost.pref", cmd);
}
#endif
//setprop media.boost.pref mode123:0:c:num
//attention!!! Just for h5, num(1,2,3,4) lock cpu num; num(5) lock freq.
#if defined(CONF_MEDIA_BOOST_CPU)
sprintf(cmd, "mode%d:0:c:5", getpid());
logd("setprop media.boost.pref %s", cmd);
property_set("media.boost.pref", cmd);
#endif
}
void disableMediaBoost()
{
char value[PROP_VALUE_MAX] = {0};
property_get("media.boost.pref", value, "0");
size_t len = strlen(value);
if (len > 1 && value[len - 1] > '0')
{
value[len - 1] = '0';
logd("setprop media.boost.pref %s", value);
property_set("media.boost.pref", value);
}
}