You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
369 lines
11 KiB
369 lines
11 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd.. 2016-2019. All rights reserved.
|
|
* Description: bootvideo player
|
|
*/
|
|
|
|
#include "BootvideoPlayer.h"
|
|
#include <fcntl.h>
|
|
#include <pthread.h>
|
|
#include <android/log.h>
|
|
#include <cutils/klog.h>
|
|
#include <cutils/properties.h>
|
|
#include <sys/times.h>
|
|
#include <utils/threads.h>
|
|
|
|
#include <media/IMediaPlayerService.h>
|
|
#include <media/IMediaPlayer.h>
|
|
#include <media/DataSource.h>
|
|
#include <media/IMediaHTTPService.h>
|
|
#include <media/mediaplayer.h>
|
|
#include <media/stagefright/MediaSource.h>
|
|
#include <media/stagefright/foundation/ADebug.h>
|
|
#include <media/stagefright/foundation/AMessage.h>
|
|
#include <media/stagefright/MPEG2TSWriter.h>
|
|
#include <media/stagefright/MediaExtractor.h>
|
|
#include <media/stagefright/MediaExtractorFactory.h>
|
|
#include <media/stagefright/MetaData.h>
|
|
|
|
#include "BootvideoConfiger.h"
|
|
#include "BootvideoDftevent.h"
|
|
#undef LOG_TAG
|
|
#define LOG_TAG "BootVideo"
|
|
|
|
namespace android {
|
|
using std::string;
|
|
// player state control
|
|
Mutex g_mtxPlayerCtr;
|
|
Condition g_mCdtPlayerCtr;
|
|
// client msg control
|
|
Mutex g_mtxClientCtr;
|
|
Condition g_mCdtClientCtr;
|
|
|
|
BootvideoClient::BootvideoClient()
|
|
: isPrepared(false), isFirstFrame(false), isComplete(false), isError(false), isForceStop(false)
|
|
{
|
|
}
|
|
|
|
BootvideoClient::~BootvideoClient()
|
|
{
|
|
}
|
|
|
|
bool BootvideoClient::WaitForPrepared() const
|
|
{
|
|
Mutex::Autolock autoLock(g_mtxClientCtr);
|
|
while (!isPrepared) {
|
|
if (isError || isForceStop) {
|
|
break;
|
|
}
|
|
g_mCdtClientCtr.wait(g_mtxClientCtr);
|
|
}
|
|
if (isPrepared) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool BootvideoClient::WaitForFirstFrame() const
|
|
{
|
|
Mutex::Autolock autoLock(g_mtxClientCtr);
|
|
while (!isFirstFrame) {
|
|
if (isError || isForceStop) {
|
|
break;
|
|
}
|
|
g_mCdtClientCtr.wait(g_mtxClientCtr);
|
|
}
|
|
if (isFirstFrame) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool BootvideoClient::IsComplete() const
|
|
{
|
|
return isComplete;
|
|
}
|
|
|
|
bool BootvideoClient::IsError() const
|
|
{
|
|
return isError;
|
|
}
|
|
|
|
void BootvideoClient::ForceStop()
|
|
{
|
|
Mutex::Autolock autoLock(g_mtxClientCtr);
|
|
isForceStop = true;
|
|
g_mCdtClientCtr.signal();
|
|
}
|
|
|
|
void BootvideoClient::notify(int msg, int ext1 __unused, int ext2 __unused, const Parcel *obj __unused)
|
|
{
|
|
ALOGD("BootvideoClient notify: msg = %d, ext1 = %d", msg, ext1);
|
|
Mutex::Autolock autoLock(g_mtxClientCtr);
|
|
if (msg == MEDIA_ERROR) { // media error, msg is 100
|
|
isError = true;
|
|
g_mCdtClientCtr.signal();
|
|
}
|
|
if (msg == MEDIA_PREPARED) { // media preared suc, msg is 1
|
|
isPrepared = true;
|
|
g_mCdtClientCtr.signal();
|
|
}
|
|
if (msg == MEDIA_PLAYBACK_COMPLETE) { // media play complete, msg is 2
|
|
isComplete = true;
|
|
g_mCdtClientCtr.signal();
|
|
}
|
|
if (msg == MEDIA_INFO) { // media info, msg is 200
|
|
switch (ext1) {
|
|
case MEDIA_INFO_RENDERING_START: // first video frame, ext1 is 3
|
|
case MEDIA_INFO_FIRST_AUDIO_FRAME: // fisrt audio frame, ext1 is 5011
|
|
ALOGD("BootvideoClient notify: first video or audio frame");
|
|
isFirstFrame = true;
|
|
g_mCdtClientCtr.signal();
|
|
break;
|
|
case MEDIA_INFO_NOT_SUPPORT: // player not support, ext1 is 1004
|
|
ALOGE("BootvideoClient notify: player not support");
|
|
isError = true;
|
|
g_mCdtClientCtr.signal();
|
|
break;
|
|
case MEDIA_INFO_PLAY_VIDEO_ERROR: // Video streaming abnormal, ext1 is 805
|
|
ALOGE("BootvideoClient notify: video can not be played");
|
|
isError = true;
|
|
g_mCdtClientCtr.signal();
|
|
break;
|
|
case MEDIA_INFO_PLAY_AUDIO_ERROR: // Audio streaming abnormal, ext1 is 804
|
|
ALOGD("BootvideoClient notify: audio can not be played");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
BootvideoPlayer::BootvideoPlayer() : fd(-1), client(nullptr), player(nullptr)
|
|
{
|
|
sp<ProcessState> proc(ProcessState::self());
|
|
ProcessState::self()->startThreadPool();
|
|
}
|
|
|
|
BootvideoPlayer::~BootvideoPlayer()
|
|
{
|
|
StopPlay();
|
|
}
|
|
|
|
bool BootvideoPlayer::IsPlayEnd() const
|
|
{
|
|
if (client == nullptr) {
|
|
ALOGE("IsPlayEnd: video client is NULL");
|
|
return false;
|
|
}
|
|
return client->IsComplete();
|
|
}
|
|
|
|
bool BootvideoPlayer::IsPlayFail() const
|
|
{
|
|
if (client == nullptr) {
|
|
ALOGE("IsPlayFail: video client is NULL");
|
|
return false;
|
|
}
|
|
return client->IsError();
|
|
}
|
|
|
|
// set player volume, the volume range is 0 to 100
|
|
bool BootvideoPlayer::SetVolume(int mute, int volume) const
|
|
{
|
|
const float percentConvert = 100.0; // IMediaPlayer volume convert
|
|
if (player == nullptr) {
|
|
ALOGE("setVolume: video player is NULL");
|
|
return false;
|
|
}
|
|
if (mute) {
|
|
volume = 0; // if mute state, set player volume 0
|
|
ALOGD("setVolume: set video mute state");
|
|
}
|
|
float percentVol = volume / percentConvert;
|
|
if (player->setVolume(percentVol, percentVol) == NO_ERROR) {
|
|
ALOGD("setVolume: set video volume %f is success", percentVol);
|
|
return true;
|
|
} else {
|
|
ALOGD("setVolume: set video volume %f is failure", percentVol);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool BootvideoPlayer::SetDataSource(std::string path)
|
|
{
|
|
if (player == nullptr) {
|
|
ALOGE("SetDataSource: video player is NULL");
|
|
return false;
|
|
}
|
|
char trustPath[PATH_MAX] = {0};
|
|
this->bootvideoPath = path;
|
|
if (realpath(path.c_str(), trustPath) == NULL) {
|
|
BootvideoDfteventReport(E_955050800, "SetDataSource", "StartPlayBootvideo", path);
|
|
ALOGE("path is not canonical %s", path.c_str());
|
|
return false;
|
|
}
|
|
fd = open(trustPath, O_RDONLY);
|
|
if (fd == -1) {
|
|
switch (errno) {
|
|
case ENOENT:
|
|
ALOGE("SetDataSource: open %s failure, no such file or directory", trustPath);
|
|
break;
|
|
case EACCES:
|
|
ALOGE("SetDataSource: open %s failure, no has ermission denied", trustPath);
|
|
break;
|
|
default:
|
|
ALOGE("SetDataSource: open %s failure, err=%d", trustPath, errno);
|
|
break;
|
|
}
|
|
BootvideoDfteventReport(E_955050800, "SetDataSource", "StartPlayBootvideo", path);
|
|
return false;
|
|
}
|
|
ALOGD("BootvideoPlayer: path %s\n", trustPath);
|
|
|
|
if (player->setDataSource(fd, 0, 0x7fffffffffLL) == NO_ERROR) {
|
|
ALOGD("SetDataSource: set video path is success");
|
|
return true;
|
|
} else {
|
|
BootvideoDfteventReport(E_955050801, "SetDataSource", "StartPlayBootvideo", path);
|
|
ALOGD("SetDataSource: set video path is failure");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool BootvideoPlayer::SetSideBand(const sp<IGraphicBufferProducer>& bufferProducer) const
|
|
{
|
|
if (player == nullptr) {
|
|
ALOGE("SetSideBand: video player is NULL");
|
|
return false;
|
|
}
|
|
if (bufferProducer == nullptr) {
|
|
ALOGE("SetSideBand: bufferProducer is NULL");
|
|
return false;
|
|
}
|
|
int ret = player->setVideoSurfaceTexture(bufferProducer);
|
|
if (ret == NO_ERROR) {
|
|
ALOGD("SetSideBand: set video surface texture is success");
|
|
return true;
|
|
} else {
|
|
ALOGD("SetSideBand: set video surface texture is failure(%d)", ret);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool BootvideoPlayer::GetPlayTimeInfo(int& currentMsec, int& durationMsec) const
|
|
{
|
|
if (player == nullptr) {
|
|
ALOGE("GetPlayTimeInfo: video player is NULL");
|
|
return false;
|
|
}
|
|
int tempCurrent = -1;
|
|
int tempDuration = -1;
|
|
player->getCurrentPosition(&tempCurrent);
|
|
player->getDuration(&tempDuration);
|
|
if (tempCurrent < 0 || tempDuration < 0) {
|
|
ALOGE("GetPlayTimeInfo: msec is error");
|
|
return false;
|
|
} else {
|
|
// unit is ms
|
|
currentMsec = tempCurrent;
|
|
durationMsec = tempDuration;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool BootvideoPlayer::InitPlay()
|
|
{
|
|
sp<IServiceManager> sm = nullptr;
|
|
sp<IBinder> binder = nullptr;
|
|
sp<IMediaPlayerService> service = nullptr;
|
|
const int checkServiceCount = 5; // try to get service 5 count
|
|
const int checkServiceDelay = 10000; // delay is 10ms
|
|
for (int retry = 0; retry < checkServiceCount; retry++) {
|
|
if (sm == nullptr) {
|
|
sm = defaultServiceManager();
|
|
}
|
|
if (sm == nullptr) {
|
|
ALOGD("InitPlay: IServiceManager is NULL, retry is %d", retry);
|
|
usleep(checkServiceDelay);
|
|
continue;
|
|
}
|
|
if (binder == nullptr) {
|
|
binder = sm->getService(String16("media.player"));
|
|
}
|
|
if (binder == nullptr) {
|
|
ALOGD("InitPlay: IBinder is NULL, retry is %d", retry);
|
|
usleep(checkServiceDelay);
|
|
continue;
|
|
} else {
|
|
service = interface_cast<IMediaPlayerService>(binder);
|
|
break;
|
|
}
|
|
}
|
|
if (service == nullptr) {
|
|
ALOGE("InitPlay: IMediaPlayerService is NULL");
|
|
return false;
|
|
} else {
|
|
ALOGE("InitPlay: IMediaPlayerService is success");
|
|
}
|
|
client = new BootvideoClient();
|
|
player = service->create(client, AUDIO_SESSION_ALLOCATE);
|
|
if (player == nullptr) {
|
|
ALOGE("InitPlay: player is NULL");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool BootvideoPlayer::StartPlay(int volume)
|
|
{
|
|
if (client == nullptr) {
|
|
ALOGE("StartPlay: video client is NULL");
|
|
return false;
|
|
}
|
|
if (player == nullptr) {
|
|
ALOGE("StartPlay: video player is NULL");
|
|
return false;
|
|
}
|
|
if (player->prepareAsync() != NO_ERROR) {
|
|
BootvideoDfteventReport(E_955050801, "prepareAsync", "StartPlay", this->bootvideoPath);
|
|
ALOGE("StartPlay: video player prepareAsync failure");
|
|
return false;
|
|
}
|
|
if (!client->WaitForPrepared()) {
|
|
BootvideoDfteventReport(E_955050801, "WaitForPrepared", "StartPlay", this->bootvideoPath);
|
|
ALOGE("StartPlay: Wait preparing has error");
|
|
return false;
|
|
}
|
|
SetVolume(0, volume); // init player volume and Ban on mute
|
|
if (player->start() != NO_ERROR) {
|
|
BootvideoDfteventReport(E_955050801, "start", "StartPlay", this->bootvideoPath);
|
|
ALOGE("StartPlay: video player start failure");
|
|
return false;
|
|
}
|
|
if (!client->WaitForFirstFrame()) {
|
|
BootvideoDfteventReport(E_955050801, "WaitForFirstFrame", "StartPlay", this->bootvideoPath);
|
|
ALOGE("StartPlay: Wait first frame has error");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool BootvideoPlayer::StopPlay()
|
|
{
|
|
if (fd != -1) {
|
|
close(fd);
|
|
fd = -1;
|
|
}
|
|
if (client != nullptr) {
|
|
client->ForceStop();
|
|
client = nullptr;
|
|
}
|
|
if (player != nullptr) {
|
|
player->stop();
|
|
player->disconnect();
|
|
player = nullptr;
|
|
}
|
|
return true;
|
|
}
|
|
} // namespace android
|