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

/*
* 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