mcu_hi3321_watch/tjd/ui/app/main/online_wf/TjdUiAppOnlineWfVideoPage.cpp
2025-05-26 20:15:20 +08:00

567 lines
17 KiB
C++

/*----------------------------------------------------------------------------
* Copyright (c) TJD Technologies Co., Ltd. 2024. All rights reserved.
*
* Description:
*
* Author: huangshuyi
*
* Create: 2024-8
*--------------------------------------------------------------------------*/
//brandy-native-tjd -nhso -release
#include "TjdUiAppOnlineWfVideoPage.h"
#include "wearable_log.h"
#include "common/image_cache_manager.h"
#include <time.h>
#include <unordered_map>
#include "gfx_utils/image_info.h"
#include "gfx_utils/heap_base.h"
#include "TjdUiImageIds.h"
#include "power_display_service.h"
#include "TjdUiMemManage.h"
#include "sys_config.h"
#include "rtc_api.h"
#include "product_evb4_standard.h"
#include "common/key_code.h"
#include "common/image_cache_manager.h"
#include "sql_setting.h"
using namespace OHOS;
using namespace OHOS::Media;
using OHOS::Media::Player;
namespace TJD {
#define ENABLE_PRINT_INFO 1
#if ENABLE_PRINT_INFO
#define static_print_info(...) sys_ui_log_i(__VA_ARGS__) //一般信息打印宏控制
#define static_print_warn(...) sys_ui_log_w(__VA_ARGS__) //警告信息打印一般常开
#define static_print_error(...) sys_ui_log_e(__VA_ARGS__) //错误信息打印一般常开
#define static_print_debug(...) sys_ui_log_d(__VA_ARGS__)
#else
#define static_print_info(...)
#define static_print_warn(...)
#define static_print_error(...)
#define static_print_debug(...)
#endif
static constexpr int16_t VIDEO_WIDTH = HORIZONTAL_RESOLUTION;
static constexpr int16_t VIDEO_HEIGHT = VERTICAL_RESOLUTION;
static constexpr int16_t STRIDE_ALIGNMENT_VALUE = 128;
static constexpr int16_t BUFFER_QUEUE_SIZE = 3;
static constexpr int16_t JPEG_HEIGHT_DIVISOR = 2;
static constexpr int16_t JPEG_WIDTH_BYTE_ALIGNMENT = 128;
static constexpr int16_t JPEG_HEIGHT_BYTE_ALIGNMENT = 16;
static const int32_t WAIT_VIDEO_EXIT_SUCCESS_MS = 10;
static const int32_t REQUEST_BUFFER_REPET_COUNT = 10;
static const uint32_t WAIT_VIDEO_EXIT_MAX_RETRY_COUNT = 100;
static AudioManager &g_amInstance = AudioManager::GetInstance();
#define MEDIA_OK 0
#define MEDIA_INVALID_PARAM (-1)
#define MEDIA_INIT_FAIL (-2)
#define MEDIA_ERR (-3)
#define MEDIA_PERMISSION_DENIED (-4)
TjdUiAppOnlineWfVideoPage::TjdUiAppOnlineWfVideoPage(UIView* parent, std::string uri, std::string previewPath) : Parent_(parent),uri_(uri),previewPath_(previewPath)
{
InitView();
}
TjdUiAppOnlineWfVideoPage::~TjdUiAppOnlineWfVideoPage()
{
if (videoPlay_ != nullptr) {
delete videoPlay_;
videoPlay_ = nullptr;
static_print_debug("delete videoPlay\n");
}
ImageCacheManager::GetInstance().UnloadSingleRes(previewPath_.c_str());
}
UIView *TjdUiAppOnlineWfVideoPage::GetView(void)
{
return surfaceView_;
}
bool TjdUiAppOnlineWfVideoPage::InitView(void)
{
surfaceView_ = new UILiteSurfaceView();
if (surfaceView_ == nullptr) {
GRAPHIC_LOGE("surfaceView is nullptr\n");
return false;
}
UIViewGroup *p = (UIViewGroup *)Parent_;
p->Add(surfaceView_);
ImageInfo* imgInfo;
imgInfo = ImageCacheManager::GetInstance().LoadSingleRes(previewPath_.c_str());
surfaceView_->SetPreview(imgInfo);
colorKey_.full = 0xff202020;
surfaceView_->SetViewId("sur");
surfaceView_->SetPosition(0, 0, VIDEO_WIDTH, VIDEO_HEIGHT);
surfaceView_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
surfaceView_->SetSurfaceColorkey(colorKey_);
Surface *surface = surfaceView_->GetSurface();
surface->SetStrideAlignment(STRIDE_ALIGNMENT_VALUE);
surface->SetWidthAndHeight(VIDEO_WIDTH, VIDEO_HEIGHT);
surface->SetQueueSize(BUFFER_QUEUE_SIZE);
surface->SetFormat(PIXEL_FMT_YCBCR_420_SP);
// jpeg decoder output buffer size calculation formula
int32_t ySize = ALIGN_BYTE(VIDEO_WIDTH, JPEG_WIDTH_BYTE_ALIGNMENT) * VIDEO_HEIGHT;
int32_t uvSize = ALIGN_BYTE(VIDEO_WIDTH, JPEG_WIDTH_BYTE_ALIGNMENT) *
ALIGN_BYTE(VIDEO_HEIGHT, JPEG_HEIGHT_BYTE_ALIGNMENT) / JPEG_HEIGHT_DIVISOR;
int32_t bufferSize = ySize + uvSize;
surface->SetSize(bufferSize);
if (videoPlay_ == nullptr) {
videoPlay_ = new TjdUiVideoCommon(surface, uri_, false);
videoPlay_->SetSyncExitMode(true);
}
//videoPlay_->StartVideoPlay();
return true;
}
static bool InitPlayerResources(TjdUiVideoCommon *videoPlay)
{
videoPlay->mutex_ = MediaMutexCreate(nullptr);
if (videoPlay->mutex_ == nullptr) {
static_print_error("create mutex failed\n");
return false;
}
videoPlay->cond_ = MediaThreadCondCreate();
if (videoPlay->cond_ == nullptr) {
static_print_error("create thread cond failed\n");
MediaMutexDestroy(&videoPlay->mutex_);
return false;
}
shared_ptr<Player> player = std::make_shared<Player>();
if (player == nullptr || player.get() == nullptr) {
static_print_error("player is nullptr\n");
MediaMutexDestroy(&videoPlay->mutex_);
MediaThreadCondDestroy(&videoPlay->cond_);
return false;
}
videoPlay->player_ = player;
videoPlay->isPlaybackCompleted_ = false;
videoPlay->playError_ = false;
videoPlay->interruptHintStop_ = false;
return true;
}
static void DeinitPlayerResources(TjdUiVideoCommon *videoPlay)
{
(void)videoPlay->player_.reset();
videoPlay->isExited_ = true;
videoPlay->isEntered_ = false;
(void)MediaThreadCondDestroy(&videoPlay->cond_);
(void)MediaMutexDestroy(&videoPlay->mutex_);
}
static int32_t VideoPlay(TjdUiVideoCommon *videoPlay)
{
std::shared_ptr<PlayerCallback> callback = std::make_shared<TjdUiAppOnlineWfVideoPage::VideoPlayCallback>(videoPlay);
if (callback == nullptr || callback.get() == nullptr) {
static_print_error("AlbumVideoPlayer::%s: callback is nullptr", __func__);
return MEDIA_ERR;
}
videoPlay->player_->SetPlayerCallback(callback);
int32_t ret = videoPlay->player_->Play();
if (ret != 0) {
static_print_error("play failed\n");
(void)videoPlay->player_->Reset();
(void)videoPlay->player_->Release();
return MEDIA_ERR;
}
videoPlay->player_->EnableSingleLooping(videoPlay->isLoop_);
MediaMutexLock(videoPlay->mutex_);
videoPlay->isPlayed_ = true;
/*若有自定义组件在开始时需要改变,在这里修改*/
//videoPlay->button_->SetText("Pause");
while (!videoPlay->isPlaybackCompleted_ && !videoPlay->isPlaybackStopped_ && !videoPlay->interruptHintStop_ &&
!videoPlay->playError_) {
MediaThreadCondWait(videoPlay->cond_, videoPlay->mutex_);
}
MediaMutexUnLock(videoPlay->mutex_);
return 0;
}
static void VideoStopAndExit(TjdUiVideoCommon *videoPlay)
{
MediaMutexLock(videoPlay->mutex_);
int32_t ret = videoPlay->player_->Stop();
if (ret != 0) {
static_print_error("stop failed");
}
ret = videoPlay->player_->Reset();
if (ret != 0) {
static_print_error("reset failed");
}
videoPlay->isPlaybackCompleted_ = false;
videoPlay->isPlayed_ = false;
videoPlay->isPause_ = false;
/*若有自定义组件需要结束时改变,在这里在修改*/
//videoPlay->button_->SetText("Play");
MediaMutexUnLock(videoPlay->mutex_);
}
static int32_t ReleasePlayer(TjdUiVideoCommon *videoPlay)
{
(void)videoPlay->player_->Reset();
(void)videoPlay->player_->Release();
(void)DeinitPlayerResources(videoPlay);
return MEDIA_ERR;
}
static void SendBackgroundFrame(TjdUiVideoCommon *videoPlay)
{
int32_t ret = videoPlay->player_->Release();
if (ret != 0) {
static_print_error("release failed");
}
if (!videoPlay->needSendBackgroundFrame_) {
(void)DeinitPlayerResources(videoPlay);
return;
}
SurfaceBuffer *buf = nullptr;
int32_t requestCount = 0;
while ((buf = videoPlay->surface_->RequestBuffer()) == nullptr) {
if (requestCount++ > REQUEST_BUFFER_REPET_COUNT) {
static_print_error("request the last buffer failed");
break;
}
LiteSurface *liteSurface = dynamic_cast<LiteSurface *>(videoPlay->surface_);
if (liteSurface == nullptr) {
static_print_error("liteSurface is null!");
break;
}
videoPlay->surface_->CancelBuffer(liteSurface->GetBackBuf());
}
if (buf != nullptr) {
buf->format = PIXEL_FMT_BUTT;
videoPlay->surface_->FlushBuffer(buf);
}
(void)DeinitPlayerResources(videoPlay);
}
static Source GetVideoPlaySource(TjdUiVideoCommon *videoPlay)
{
Source source;
if (!videoPlay->uri_.empty()) {
std::map<std::string, std::string> header;
source = Source(videoPlay->uri_, header);
} else if (videoPlay->fd_ > 0) {
if (videoPlay->isLoop_) {
int32_t ret = lseek(videoPlay->fd_, 0, SEEK_SET);
if (ret == -1) {
static_print_error("lseek[fd = %d] file fail, error[%d]\n", videoPlay->fd_, errno);
return source;
}
}
source = Source(videoPlay->fd_, videoPlay->offset_, 0);
}
return source;
}
static int32_t SetAudioSessionIdAndStreamType(TjdUiVideoCommon *videoPlay)
{
int32_t ret = MEDIA_OK;
if (!videoPlay->isPureVideo_) {
ret = videoPlay->player_->SetAudioSessionId(videoPlay->sessionId_);
if (ret != MEDIA_OK) {
static_print_error("AlbumVideoPlayer::%s: set audio sessionId failed", __func__);
return ret;
}
ret = videoPlay->player_->SetAudioStreamType(AUDIO_STREAM_FITNESS_VIDEO);
if (ret != MEDIA_OK) {
static_print_error("AlbumVideoPlayer::%s: set audio stream type failed", __func__);
return ret;
}
}
return ret;
}
static int32_t RunVideoPlay(TjdUiVideoCommon *videoPlay)
{
bool success = InitPlayerResources(videoPlay);
if (!success) {
static_print_error("init player resources failed\n");
return MEDIA_ERR;
}
int32_t ret = 0;
char filePath[PATH_MAX];
if (realpath(videoPlay->uri_.c_str(), filePath) == nullptr) {
static_print_error("no %s resource", videoPlay->uri_.c_str());
return MEDIA_ERR;
}
Source source = GetVideoPlaySource(videoPlay);
ret = videoPlay->player_->SetSource(source);
if (ret != 0) {
static_print_error("set source failed\n");
(void)DeinitPlayerResources(videoPlay);
return MEDIA_ERR;
}
ret = videoPlay->player_->Prepare();
if (ret != 0) {
static_print_error("prepare failed\n");
return ReleasePlayer(videoPlay);
}
ret = SetAudioSessionIdAndStreamType(videoPlay);
if (ret != 0) {
return ReleasePlayer(videoPlay);
}
ret = videoPlay->player_->SetVideoSurface(videoPlay->surface_);
if (ret != 0) {
static_print_error("set video surface failed\n");
return ReleasePlayer(videoPlay);
}
ret = VideoPlay(videoPlay);
if (ret != 0) {
return ReleasePlayer(videoPlay);
}
VideoStopAndExit(videoPlay);
SendBackgroundFrame(videoPlay);
return 0;
}
static bool RequsetAudioFocus(TjdUiVideoCommon *videoPlay)
{
if (videoPlay->isPureVideo_) {
return true;
}
bool success = g_amInstance.Initialize();
if (!success) {
static_print_error("AlbumVideoPlayer::%s: audiomanager init failed", __func__);
return false;
}
AudioSession sessionId = g_amInstance.MakeSessionId();
if (sessionId == AUDIO_SESSION_ID_NONE) {
static_print_error("AlbumVideoPlayer::%s: audio session id invalid", __func__);
return false;
}
std::shared_ptr<TjdUiAppOnlineWfVideoPage::VideoPlayerInterruptListener> interruptListener =
std::make_shared<TjdUiAppOnlineWfVideoPage::VideoPlayerInterruptListener>(videoPlay);
if (interruptListener == nullptr || interruptListener.get() == nullptr) {
static_print_error("AlbumVideoPlayer::%s: video player interrupt listener is nullptr", __func__);
return false;
}
AudioInterrupt interrupt = {AUDIO_STREAM_FITNESS_VIDEO, sessionId, interruptListener};
if (g_amInstance.ActivateAudioInterrupt(interrupt) == INTERRUPT_FAILED) {
static_print_error("AlbumVideoPlayer::%s: activate audio interrupt failed", __func__);
return false;
}
videoPlay->sessionId_ = sessionId;
videoPlay->interrupt_ = interrupt;
return true;
}
static bool ReleaseAudioFocus(TjdUiVideoCommon *videoPlay)
{
if (videoPlay->isPureVideo_) {
return true;
}
if (g_amInstance.DeactivateAudioInterrupt(videoPlay->interrupt_) != 0) {
static_print_error("AlbumVideoPlayer::%s: deactivate audio interrupt failed", __func__);
return false;
}
return true;
}
int32_t TjdUiVideoCommon::StartVideoPlay(void)
{
if (isEntered_) {
static_print_info("video play is not stop, can not start!");
return MEDIA_OK;
}
isExited_ = false;
isEntered_ = true;
MediaThreadattr attr = {"VideoPlayThread", 0x2000, THREAD_SCHED_INVALID, 0, true};
if (isSyncExitMode_) {
attr.detached = false;
}
threadHandle_ = MediaThreadCreate(VideoPlayThread, this, &attr);
if (threadHandle_ == NULL) {
static_print_error("create thread failed\n");
return MEDIA_ERR;
}
//play = this;
return MEDIA_OK;
}
int32_t TjdUiVideoCommon::PauseVideoPlay(void)
{
MediaMutexLock(mutex_);
if (player_ == NULL) {
static_print_error("can not pause play");
MediaMutexUnLock(mutex_);
return MEDIA_ERR;
}
if (isPlaybackStopped_ || isPlaybackCompleted_ || interruptHintStop_) {
static_print_error("current state is stop, can not pause play");
MediaMutexUnLock(mutex_);
return MEDIA_ERR;
}
int32_t ret = player_->Pause();
if (ret != MEDIA_OK) {
static_print_error("pause failed");
MediaMutexUnLock(mutex_);
return MEDIA_ERR;
}
isPause_ = true;
MediaMutexUnLock(mutex_);
return ret;
}
int32_t TjdUiVideoCommon::ResumeVideoPlay(void)
{
MediaMutexLock(mutex_);
if (player_ == NULL) {
static_print_error("can not resume play");
MediaMutexUnLock(mutex_);
return MEDIA_ERR;
}
if (isPlaybackStopped_ || isPlaybackCompleted_ || interruptHintStop_) {
static_print_error("current state is stop, can not resume play");
MediaMutexUnLock(mutex_);
return MEDIA_ERR;
}
int32_t ret = player_->Play();
if (ret != MEDIA_OK) {
static_print_error("resume failed");
MediaMutexUnLock(mutex_);
return ret;
}
isPause_ = false;
MediaMutexUnLock(mutex_);
return ret;
}
int32_t TjdUiVideoCommon::StopVideoPlay(void)
{
MediaMutexLock(mutex_);
if (isPlaybackStopped_ || isPlaybackCompleted_ || interruptHintStop_) {
if (isLoop_) {
if (!isPlaybackCompleted_) {
static_print_info("video play already stopped");
MediaMutexUnLock(mutex_);
return MEDIA_OK;
}
} else {
static_print_info("video play already stopped");
MediaMutexUnLock(mutex_);
return MEDIA_OK;
}
}
isPlaybackStopped_ = true;
MediaThreadCondSignal(cond_);
MediaMutexUnLock(mutex_);
if (isSyncExitMode_) {
MediaThreadJoin(&threadHandle_);
isPlaybackStopped_ = false;
dynamic_cast<LiteSurface *>(surface_)
->ClearBuffers(); // clear buffers safely in sync mode to reduce peak memory
}
//play = nullptr;
return MEDIA_OK;
}
void TjdUiVideoCommon::DestroyVideoPlaySource(void)
{
needSendBackgroundFrame_ = false;
StopVideoPlay();
uint32_t count = 0;
while (!IsExitCompletely()) {
count++;
if (count == WAIT_VIDEO_EXIT_MAX_RETRY_COUNT) {
static_print_error("media video play exit timeout\n");
break;
}
usleep(WAIT_VIDEO_EXIT_SUCCESS_MS);
}
}
void *TjdUiVideoCommon::VideoPlayThread(void *arg)
{
TjdUiVideoCommon *videoPlay = (TjdUiVideoCommon *)arg;
if (videoPlay->isPlayed_) {
static_print_error("the video is playing.\n");
return nullptr;
}
bool success = RequsetAudioFocus(videoPlay);
if (!success) {
static_print_error("AlbumVideoPlayer::%s: requset audio focus failed", __func__);
return nullptr;
}
int32_t ret = RunVideoPlay(videoPlay);
if (ret != 0) {
static_print_error("run video play failed\n");
(void)ReleaseAudioFocus(videoPlay);
return nullptr;
}
success = ReleaseAudioFocus(videoPlay);
if (!success) {
static_print_error("AlbumVideoPlayer::%s: release audio focus failed", __func__);
return nullptr;
}
static_print_error("exit all!\n");
return nullptr;
}
int32_t TjdUiVideoCommon::GetDumpInfo(PlayerDebugInfo *playerInfo)
{
MediaMutexLock(mutex_);
if (player_ == NULL) {
static_print_error("can not get dump info!");
MediaMutexUnLock(mutex_);
return MEDIA_ERR;
}
int32_t ret = player_->DumpInfo(playerInfo);
if (ret != MEDIA_OK) {
static_print_error("get dump info failed");
MediaMutexUnLock(mutex_);
return ret;
}
MediaMutexUnLock(mutex_);
return ret;
}
void TjdUiVideoCommon::SetVideoPlayLoop(bool isLoop)
{
MediaMutexLock(mutex_);
isLoop_ = isLoop;
MediaMutexUnLock(mutex_);
}
void TjdUiVideoCommon::SetSyncExitMode(bool isSyncExitMode)
{
MediaMutexLock(mutex_);
if (!isEntered_) {
isSyncExitMode_ = isSyncExitMode;
}
MediaMutexUnLock(mutex_);
}
bool TjdUiVideoCommon::IsExitCompletely(void) { return isExited_; }
}