-/*\r
- * Copyright (c) 2020-2023 Huawei Device Co., Ltd.\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-#include "liteplayer.h"\r
-\r
-#ifdef SUPPORT_SYS_PRCTL\r
-#include <sys/prctl.h>\r
-#endif\r
-#include <unistd.h>\r
-#include "player_check.h"\r
-#include "hi_liteplayer_err.h"\r
-#include "liteplayer_comm.h"\r
-#if !defined(UNSUPPORT_AUDIO_DECODER) || !defined(UNSUPPORT_VIDEO_DECODER)\r
-#include "decoder.h"\r
-#endif\r
-\r
-#if !defined(UNSUPPORT_AUDIO_DECODER) || !defined(UNSUPPORT_VIDEO_DECODER)\r
-using OHOS::Media::Decoder;\r
-#endif\r
-using OHOS::Media::PlayerSource;\r
-using OHOS::Media::SinkManager;\r
-\r
-namespace OHOS {\r
-namespace Media {\r
-/* DEFAULT_VID_BUFSIZE: 2 * 1024 * 1024 */\r
-const uint32_t DEFAULT_VID_BUFSIZE = 2097152;\r
-/* DEFAULT_AUD_BUFSIZE: 256 * 1024 */\r
-const uint32_t DEFAULT_AUD_BUFSIZE = 262144;\r
-\r
-const uint32_t GET_BUFFER_TIMEOUT_MS = 0u;\r
-const uint32_t RENDER_FULL_SLEEP_TIME_US = 10000u;\r
-// 1. waiting app response playback complete callback event\r
-// 2. waiting interval time for loop playback\r
-const uint32_t RENDER_EOS_SLEEP_TIME_US = 3000000u;\r
-const uint32_t WAIT_BUFFER_EMPTY_SLEEP_TIME_US = 1000000u;\r
-const uint32_t DECODER_DEFAULT_WIDTH = 1920;\r
-const uint32_t DECODER_DEFAULT_HEIGHT = 1080;\r
-const uint32_t QUEUE_BUFFER_FULL_SLEEP_TIME_US = 10000u;\r
-const uint32_t NO_DATA_READ_SLEEP_TIME_US = 5000u;\r
-const uint32_t MAX_EVENT_MESSAGE_NUM = 128;\r
-const uint32_t MAX_THREAD_STACK_SIZE = 0x1800u;\r
-const uint32_t REQUEST_BUFFER_RETRY_WAIT_TIME_US = 10000u;\r
-const float YCBCR420SP_BUFFER_SIZE_COEFFICIENT = 1.5;\r
-#ifdef DEBUG_LOW_POWER\r
-const uint32_t RENDER_FULL_SLEEP_THRESHOLD_MS_MP3_AACLC_OPUS = 5;\r
-const uint32_t RENDER_FULL_SLEEP_THRESHOLD_MS_PCM = 25;\r
-const uint32_t RENDER_FULL_SLEEP_THRESHOLD_MS_FLAC = 50;\r
-#endif\r
-// In a single-process system, only one thread can work at a time.\r
-// Subthreads need to give CPU resources to the main thread to switch to the playback state.\r
-const uint32_t WAIT_MAIN_THREAD_SWITCH_TO_PLAY_STATUS_TIME_US = 10000u;\r
-// maximum number of consecutive surface buffer request failures retries(converted to time: 100 * 10ms = 1s)\r
-const uint32_t MAX_CONTINOUS_REQUEST_SURFACE_BUFFER_FAIL_COUNT = 100;\r
-\r
-static AudioCodecFormat g_fromCodecFormatToAudioManager[CODEC_BUT + 1] = {\r
- FORMAT_INVALID, FORMAT_INVALID, FORMAT_INVALID, FORMAT_INVALID,\r
- AAC_LC, G711A, G711U, PCM, MP3, G726, OPUS, FLAC, VORBIS, APE, SILK, SBC, FORMAT_INVALID\r
-};\r
-static EsFrameType g_fromDemuxTypeToSinkType[FRAME_TYPE_BUT + 1] = {\r
- ESFRAME_TYPE_NONE, ESFRAME_TYPE_AUDIO, ESFRAME_TYPE_VIDEO, ESFRAME_TYPE_IMAGE, ESFRAME_TYPE_SUB,\r
- ESFRAME_TYPE_DATA, ESFRAME_INVALID_TYPE\r
-};\r
-\r
-static CodecFormatAndMimePair g_avCodecFormatInfo[CODEC_BUT + 1] = {\r
- { CODEC_H264, MEDIA_MIMETYPE_VIDEO_AVC },\r
- { CODEC_H265, MEDIA_MIMETYPE_VIDEO_HEVC },\r
- { CODEC_JPEG, MEDIA_MIMETYPE_IMAGE_JPEG },\r
- { CODEC_MJPEG, MEDIA_MIMETYPE_IMAGE_MJPEG },\r
- { CODEC_AAC, MEDIA_MIMETYPE_AUDIO_AAC },\r
- { CODEC_G711A, MEDIA_MIMETYPE_AUDIO_G711A },\r
- { CODEC_G711U, MEDIA_MIMETYPE_AUDIO_G711U },\r
- { CODEC_PCM, MEDIA_MIMETYPE_AUDIO_PCM },\r
- { CODEC_MP3, MEDIA_MIMETYPE_AUDIO_MP3 },\r
- { CODEC_G726, MEDIA_MIMETYPE_AUDIO_G726 },\r
- { CODEC_BUT, MEDIA_MIMETYPE_INVALID },\r
-};\r
-\r
-namespace {\r
-/* playing position notify interval in ms */\r
-const uint32_t DEFAULT_POS_NOFITY_INTERVAL = 300;\r
-}\r
-\r
-#ifdef DEBUG_LOW_POWER\r
-const int32_t US_2_MS = 1000;\r
-#endif\r
-\r
-void PlayerControl::RecordTime(struct timeval &timeStart)\r
-{\r
- gettimeofday(&timeStart, nullptr);\r
-}\r
-\r
-uint64_t PlayerControl::CalcTimeDiffUsPrint(const struct timeval &timeStart, struct timeval &timeEnd,\r
- std::string outString, bool showlog)\r
-{\r
- gettimeofday(&timeEnd, nullptr);\r
- const uint64_t timeUs = 1000000;\r
- uint64_t diffSecToUs = 0;\r
- bool isOverflow =\r
- UIntMulIsOverflow64(static_cast<uint64_t>(timeEnd.tv_sec - timeStart.tv_sec), timeUs, &diffSecToUs);\r
- if (isOverflow) {\r
- MEDIA_ERR_LOG("PlayerControl::CalcTimeDiffUsPrint calculate reslut overflow!");\r
- return INVALID_TIME;\r
- }\r
- uint64_t diffUsec = static_cast<uint64_t>(timeEnd.tv_usec - timeStart.tv_usec);\r
- uint64_t diffTimeUS = diffSecToUs + diffUsec;\r
- if (showlog) {\r
- MEDIA_INFO_LOG("%s elapsed time: %lld us", outString.c_str(), diffTimeUS);\r
- }\r
- return diffTimeUS;\r
-}\r
-\r
-int32_t PlayerControl::GetPlayerControlDumpInfo(PlayerControlDebugInfo &playerControlInfo)\r
-{\r
- playerControlInfo.currentPosition = currentPosition_;\r
- playerControlInfo.hasRenderAudioEos = hasRenderAudioEos_;\r
- playerControlInfo.hasRenderVideoEos = hasRenderVideoEos_;\r
- playerControlInfo.isAudioStarted = isAudioStarted_;\r
- playerControlInfo.isVideoStarted = isVideoStarted_;\r
- playerControlInfo.offloadAudio = offloadAudio_;\r
- playerControlInfo.outDevice = outDeviceId_;\r
- playerControlInfo.sessionId = audioSession_;\r
- return 0;\r
-}\r
-\r
-int32_t PlayerControl::GetPlayerVideoDumpInfo(PlayerVideoDebugInfo &videoDebugInfo)\r
-{\r
- videoDebugInfo.frameBufCnt = vdecAttr_.frameBufCnt;\r
- videoDebugInfo.u32Height = vdecAttr_.maxHeight;\r
- videoDebugInfo.u32Width = vdecAttr_.maxWidth;\r
- videoDebugInfo.enVideoType = vdecAttr_.type;\r
- return 0;\r
-}\r
-\r
-int32_t PlayerControl::GetPlayerAudioDumpInfo(PlayerAudioDebugInfo &audioDebugInfo)\r
-{\r
- audioDebugInfo.bitWidth = adecAttr_.bitWidth;\r
- audioDebugInfo.enAudioType = adecAttr_.type;\r
- return 0;\r
-}\r
-\r
-int32_t PlayerControl::GetPlayerFileDumpInfo(PlayerFileDebugInfo &fileDebugInfo)\r
-{\r
- fileDebugInfo.filePath = filePath_;\r
- fileDebugInfo.fd = fd_;\r
- fileDebugInfo.offset = offset_;\r
- return 0;\r
-}\r
-\r
-void PlayerControl::PrintKpiTime()\r
-{\r
-#ifdef PLAYER_KPI_ON\r
- if (!recordFirstFrameCost_ && currentPosition_ >= 0) {\r
- std::string startPlay("KPI_PlayNewFileTime");\r
- CalcTimeDiffUsPrint(startPlayStartTime_, startPlayEndTime_, startPlay, KPI_PRINT);\r
- recordFirstFrameCost_ = true;\r
- }\r
-#endif\r
-}\r
-\r
-PlayerControl::PlayerControl()\r
- : isInited_(false),\r
- isPlayEnd_(false),\r
- isAudPlayEos_(false),\r
- cachedPacket_(false),\r
- lastRendPos_(0),\r
- lastNotifyTime_(0),\r
- lastReadPktStrmIdx_(-1),\r
- lastReadPktPts_(0),\r
- lastSendPktPts_(0),\r
- isVideoStarted_(false),\r
- isAudioStarted_(false),\r
- strmReadEnd_(false),\r
- isPlayErr_(false),\r
- lastSendAdecPts_(AV_INVALID_PTS),\r
- currentPosition_(0),\r
- paused_(false),\r
- schThreadExit_(false),\r
- loop_(false),\r
- hasRenderAudioEos_(false),\r
- hasRenderVideoEos_(false),\r
- renderSleepTime_(0),\r
- leftVolume_(-1.0f),\r
- rightVolume_(-1.0f),\r
- schMutex_(nullptr),\r
- schCond_(nullptr),\r
- schProcess_(nullptr),\r
- seekToTimeMs_(-1),\r
- sourceType_(SOURCE_TYPE_BUT),\r
- firstAudioFrameAfterSeek_(false),\r
- firstPosAfterSeek_(0),\r
- fd_(-1),\r
- offset_(0),\r
- playerSource_(nullptr),\r
- sinkManager_(nullptr),\r
- surface_(nullptr),\r
- surfaceBuf_(nullptr),\r
- curState_(PLAY_STATUS_IDLE),\r
- offloadAudio_(false),\r
- audioSession_(0),\r
- streamType_(AUDIO_STREAM_MUSIC),\r
- recordFirstFrameCost_(false),\r
- renderEsTotalTime_(0),\r
- readPktTotalTime_(0),\r
- renderEsFrameCnt_(0),\r
- readPacketCnt_(0),\r
- outDeviceId_(OUT_BUILTIN_SPEAKER),\r
- headInSendSuccessInterval_(-1),\r
- tailInSendSuccessInterval_(-1),\r
- hasAudio_(false),\r
- hasVideo_(false),\r
- isAudio_(false),\r
- isVideo_(false)\r
-{\r
- eventCallback_.player = nullptr;\r
- eventCallback_.callbackFun = nullptr;\r
- if (memset_s(&fmtFileInfo_, sizeof(fmtFileInfo_), 0, sizeof(FormatFileInfo)) != EOK) {\r
- MEDIA_ERR_LOG("memset_s failed");\r
- }\r
- fmtFileInfo_.s32UsedAudioStreamIndex = HI_DEMUXER_NO_MEDIA_STREAM;\r
- fmtFileInfo_.s32UsedVideoStreamIndex = HI_DEMUXER_NO_MEDIA_STREAM;\r
- playerParam_.u32PlayPosNotifyIntervalMs = DEFAULT_POS_NOFITY_INTERVAL;\r
- playerParam_.u32VideoEsBufSize = DEFAULT_POS_NOFITY_INTERVAL;\r
- playerParam_.u32AudioEsBufSize = DEFAULT_POS_NOFITY_INTERVAL;\r
- playerParam_.u32VdecFrameBufCnt = DEFAULT_POS_NOFITY_INTERVAL;\r
- if (memset_s(&formatPacket_, sizeof(formatPacket_), 0, sizeof(FormatFrame)) != EOK) {\r
- MEDIA_ERR_LOG("memset_s failed");\r
- }\r
- streamAttr_.videoBufSize = 0;\r
- streamAttr_.audioBufSize = 0;\r
- adecAttr_.type = 0;\r
- adecAttr_.sampleRate = 0;\r
- adecAttr_.channel = 0;\r
- adecAttr_.bitWidth = 0;\r
- streamSource_.param.sampleRate = 0;\r
- streamSource_.param.sampleFormat = 0;\r
- streamSource_.param.channelCount = 0;\r
- streamSource_.param.channelLayout = 0;\r
- streamSource_.stream.ReadData = nullptr;\r
- streamSource_.stream.GetReadableSize = nullptr;\r
- streamSource_.stream.handle = nullptr;\r
- eventQueue_.clear();\r
- startPlayStartTime_.tv_sec = 0;\r
- startPlayStartTime_.tv_usec = 0;\r
- startPlayEndTime_.tv_sec = 0;\r
- startPlayEndTime_.tv_usec = 0;\r
- streamEndTime_.tv_sec = 0;\r
- streamEndTime_.tv_usec = 0;\r
- metaData_.key = 0;\r
- metaData_.size = 0;\r
-#if !defined(UNSUPPORT_AUDIO_DECODER)\r
- audioDecoder_ = nullptr;\r
-#endif\r
-#if !defined(UNSUPPORT_VIDEO_DECODER)\r
- videoDecoder_ = nullptr;\r
-#endif\r
-}\r
-\r
-PlayerControl::~PlayerControl()\r
-{\r
- (void)Deinit();\r
- eventQueue_.clear();\r
-}\r
-\r
-int32_t PlayerControl::InitAttr(const PlayerControlParam &createParam)\r
-{\r
- if (memset_s(&fmtFileInfo_, sizeof(fmtFileInfo_), 0x00, sizeof(FormatFileInfo)) != EOK) {\r
- MEDIA_ERR_LOG("memset_s failed");\r
- return HI_ERR_PLAYERCONTROL_MEM_SET;\r
- }\r
- fmtFileInfo_.s32UsedAudioStreamIndex = HI_DEMUXER_NO_MEDIA_STREAM;\r
- fmtFileInfo_.s32UsedVideoStreamIndex = HI_DEMUXER_NO_MEDIA_STREAM;\r
- streamAttr_.playMode = RENDER_MODE_NORMAL;\r
- streamAttr_.videoBufSize = DEFAULT_VID_BUFSIZE;\r
- streamAttr_.audioBufSize = DEFAULT_AUD_BUFSIZE;\r
-\r
- lastReadPktPts_ = 0;\r
- lastSendPktPts_ = 0;\r
- CHECK_FAILED_PRINT(memcpy_s(&playerParam_, sizeof(playerParam_), &createParam, sizeof(PlayerControlParam)), EOK,\r
- "copy playerParam_ fail");\r
- playerParam_.u32PlayPosNotifyIntervalMs = (createParam.u32PlayPosNotifyIntervalMs == 0) ?\r
- DEFAULT_POS_NOFITY_INTERVAL :\r
- createParam.u32PlayPosNotifyIntervalMs;\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::Init(const PlayerControlParam &createParam)\r
-{\r
- MEDIA_INFO_LOG("Init in");\r
- CHECK_TRUE_CONDITION_RETURN(isInited_, HI_SUCCESS, "already be inited");\r
- CHECK_FAILED_RETURN(InitAttr(createParam), HI_SUCCESS, HI_FAILURE, "InitAttr failed");\r
- schMutex_ = MediaMutexCreate(nullptr);\r
- if (schMutex_ == nullptr) {\r
- MEDIA_ERR_LOG("create mutex failed");\r
- return HI_FAILURE;\r
- }\r
- schCond_ = MediaThreadCondCreate();\r
- if (schCond_ == nullptr) {\r
- MEDIA_ERR_LOG("create cond failed");\r
- MediaMutexDestroy(&schMutex_);\r
- return HI_FAILURE;\r
- }\r
- isInited_ = true;\r
-#ifdef PLAYER_KPI_ON\r
- RecordTime(startPlayStartTime_);\r
-#endif\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::Deinit()\r
-{\r
- if (!isInited_) {\r
- return HI_SUCCESS;\r
- }\r
- DestroyDecoder();\r
- MediaMutexDestroy(&schMutex_);\r
- MediaThreadCondDestroy(&schCond_);\r
- isInited_ = false;\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::RegCallback(PlayerCtrlCallbackParam &eventCallback)\r
-{\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_REGCALLBACK;\r
- msg.msgData = static_cast<void *>(&eventCallback);\r
- msg.msgDataLen = 0;\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-int32_t PlayerControl::SetDataSource(const std::string filepath)\r
-{\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_SET_DATASOURCE_URI;\r
- msg.msgData = const_cast<void *>(static_cast<const void *>(filepath.c_str()));\r
- msg.msgDataLen = 0;\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-int32_t PlayerControl::SetDataSource(SourceFdParam &fdSrc)\r
-{\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_SET_DATASOURCE_FD;\r
- msg.msgData = static_cast<void *>(&fdSrc);\r
- msg.msgDataLen = 0;\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-int32_t PlayerControl::SetDataSource(StreamSourceParam &streamSource)\r
-{\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_SET_DATASOURCE_STREAM;\r
- msg.msgData = static_cast<void *>(&streamSource);\r
- msg.msgDataLen = 0;\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-int32_t PlayerControl::Prepare()\r
-{\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_PREPARE;\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-int32_t PlayerControl::Play()\r
-{\r
- int32_t ret;\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_PLAY;\r
- ret = OnMessageReceived(msg);\r
- CHECK_FAILED_PRINT(ret, HI_SUCCESS, "play failed");\r
- return ret;\r
-}\r
-\r
-int32_t PlayerControl::SetVolume(const VolumeAttr &volumeAttr)\r
-{\r
- VolumeAttr attr = volumeAttr;\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_SET_VOLUME;\r
- msg.msgData = static_cast<void *>(&attr);\r
- msg.msgDataLen = 0;\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-int32_t PlayerControl::Stop()\r
-{\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_STOP;\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-int32_t PlayerControl::Pause()\r
-{\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_PAUSE;\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-int32_t PlayerControl::Seek(int64_t timeInMs)\r
-{\r
- if (fmtFileInfo_.enVideoType == CODEC_JPEG) {\r
- MEDIA_ERR_LOG("seek action not support for play picture");\r
- return HI_ERR_PLAYERCONTROL_NOT_SUPPORT;\r
- }\r
- if ((fmtFileInfo_.s64Duration > 0) && (fmtFileInfo_.s64Duration < timeInMs)) {\r
- return HI_ERR_PLAYERCONTROL_ILLEGAL_PARAM;\r
- }\r
- seekToTimeMs_ = timeInMs;\r
- MediaThreadCondSignal(schCond_);\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::GetFileInfo(FormatFileInfo &formatInfo)\r
-{\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_GETFILEINFO;\r
- msg.msgData = &formatInfo;\r
- msg.msgDataLen = sizeof(FormatFileInfo);\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-int32_t PlayerControl::SetMedia(PlayerControlStreamAttr &mediaAttr)\r
-{\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_SETATTR;\r
- msg.msgData = &mediaAttr;\r
- msg.msgDataLen = sizeof(PlayerControlStreamAttr);\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-#if defined(ENABLE_UIKIT)\r
-int32_t PlayerControl::SetSurface(Surface *surface)\r
-#elif defined(ENABLE_LVGL)\r
-int32_t PlayerControl::SetSurface(LvSurfaceView *surface)\r
-#endif\r
-{\r
- surface_ = surface;\r
- return 0;\r
-}\r
-\r
-int32_t PlayerControl::SetPlaybackSpeed(float speed)\r
-{\r
- float setSpeed = speed;\r
- MsgInfo msg = {};\r
- msg.what = PLAYERCONTROL_MSG_SETSPEED;\r
- msg.msgData = static_cast<void *>(&setSpeed);\r
- msg.msgDataLen = 0;\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-void PlayerControl::ClearCachePacket()\r
-{\r
- if (cachedPacket_) {\r
- if (formatPacket_.data != nullptr) {\r
- if (playerSource_ != nullptr && playerSource_->FreeFrame(formatPacket_) != 0) {\r
- MEDIA_ERR_LOG("FreeFrame failed \n");\r
- }\r
- formatPacket_.data = nullptr;\r
- formatPacket_.len = 0;\r
- formatPacket_.trackId = -1;\r
- }\r
- /* end packet is null do not need to demux free */\r
- cachedPacket_ = false;\r
- }\r
-}\r
-\r
-void PlayerControl::OnVideoEndOfStream()\r
-{\r
- if (!hasAudio_ && (lastSendVdecPts_ > AV_INVALID_PTS)) {\r
- EventCallback(PLAYERCONTROL_EVENT_PROGRESS, &lastSendVdecPts_);\r
- }\r
- isVidPlayEos_ = true;\r
- isPlayEnd_ = IsPlayEos() ? true : isPlayEnd_;\r
-}\r
-\r
-void PlayerControl::EventProcess(EventCbType event)\r
-{\r
- PlayerControlError playerError;\r
- MEDIA_DEBUG_LOG("handleEvent %d", event);\r
- switch (event) {\r
- case EVNET_VIDEO_PLAY_EOS:\r
- OnVideoEndOfStream();\r
- break;\r
- case EVNET_VIDEO_PLAY_SOS:\r
- MEDIA_INFO_LOG("video sos recv");\r
- break;\r
- case EVNET_AUDIO_PLAY_EOS:\r
- isAudPlayEos_ = true;\r
- isPlayEnd_ = IsPlayEos() ? true : isPlayEnd_;\r
- if (lastSendAdecPts_ > AV_INVALID_PTS) {\r
- EventCallback(PLAYERCONTROL_EVENT_PROGRESS, &lastSendAdecPts_);\r
- }\r
- break;\r
- case EVNET_VIDEO_RUNNING_ERR:\r
- case EVNET_AUDIO_RUNNING_ERR:\r
- playerError = PLAYERCONTROL_ERROR_AUD_PLAY_FAIL;\r
- isPlayErr_ = true;\r
- EventCallback(PLAYERCONTROL_EVENT_ERROR, &playerError);\r
- break;\r
- default:\r
- break;\r
- }\r
-}\r
-\r
-void PlayerControl::EventQueueProcess(void)\r
-{\r
- size_t queSize;\r
- PalayControlEventItem *item = nullptr;\r
-\r
- queSize = eventQueue_.size();\r
- if (queSize > MAX_EVENT_MESSAGE_NUM) {\r
- MEDIA_WARNING_LOG("mesaage except, num:%u", queSize);\r
- }\r
- for (size_t i = 0; i < queSize && i < MAX_EVENT_MESSAGE_NUM; i++) {\r
- item = &eventQueue_[i];\r
- EventProcess(item->event);\r
- }\r
- eventQueue_.clear();\r
-}\r
-\r
-int32_t PlayerControl::OnPlayControlEvent(void *priv, const EventCbType event) const\r
-{\r
- // audio play eos event needs to be handled immediately\r
- if (event == EVNET_AUDIO_PLAY_EOS) {\r
- MEDIA_INFO_LOG("Received audio play eos event");\r
- EventCallback(PLAYERCONTROL_EVENT_EOF, nullptr);\r
- return HI_SUCCESS;\r
- } else if (event == EVNET_AUDIO_BUFFER_EMPTY) {\r
- EventCallback(PLAYERCONTROL_BUFFER_EMPTY, nullptr);\r
- return HI_SUCCESS;\r
- } else if (event == EVNET_OUTPUT_DEVICE_CHANGED) {\r
- PlayerControl *player = static_cast<PlayerControl *>(priv);\r
- player->RecordLastPosition();\r
- return HI_SUCCESS;\r
- } else if (event == EVNET_AUDIO_RUNNING_ERR ||\r
- event == EVNET_VIDEO_RUNNING_ERR) {\r
- PlayerControlError playerError = PLAYERCONTROL_ERROR_AUD_PLAY_FAIL;\r
- EventCallback(PLAYERCONTROL_EVENT_ERROR, &playerError);\r
- return HI_SUCCESS;\r
- }\r
-\r
- PalayControlEventItem item;\r
- PlayerControl *player = static_cast<PlayerControl *>(priv);\r
-\r
- item.event = event;\r
- player->eventQueue_.push_back(item);\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::PauseResume(void)\r
-{\r
- CHECK_NULL_RETURN(sinkManager_, HI_ERR_PLAYERCONTROL_NULL_PTR, "sinkManager_ nullptr");\r
- MediaMutexLock(schMutex_);\r
- int32_t ret = sinkManager_->Resume();\r
- if (ret != HI_SUCCESS) {\r
- if (ret != NOT_FOUND_ACTIVE_STREAME) {\r
- MEDIA_ERR_LOG("resume failed");\r
- hasVideo_ ? NotifyError(PLAYERCONTROL_ERROR_VID_PLAY_FAIL) : NotifyError(PLAYERCONTROL_ERROR_AUD_PLAY_FAIL);\r
- }\r
- MediaMutexUnLock(schMutex_);\r
- return ret;\r
- }\r
- paused_ = false;\r
- // played to the end no need to signal\r
- if (!IsPlayEos()) {\r
- MediaThreadCondSignal(schCond_);\r
- }\r
- MediaMutexUnLock(schMutex_);\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::CheckMediaInfo(void) const\r
-{\r
- if (fmtFileInfo_.s32UsedAudioStreamIndex >= HI_DEMUXER_RESOLUTION_CNT ||\r
- fmtFileInfo_.s32UsedVideoStreamIndex >= HI_DEMUXER_RESOLUTION_CNT) {\r
- MEDIA_ERR_LOG("input file error video track: %d audio %d", fmtFileInfo_.s32UsedVideoStreamIndex,\r
- fmtFileInfo_.s32UsedAudioStreamIndex);\r
- return HI_ERR_PLAYERCONTROL_DEMUX_ERROR;\r
- }\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::GetVideoResolution(int32_t streamIdx, StreamResolution &resolution)\r
-{\r
- if (streamIdx == HI_DEMUXER_NO_MEDIA_STREAM) {\r
- MEDIA_ERR_LOG("stream id [%d] in invalid", streamIdx);\r
- return HI_FAILURE;\r
- }\r
-\r
- for (uint32_t i = 0; i < HI_DEMUXER_RESOLUTION_CNT; i++) {\r
- if (fmtFileInfo_.stSteamResolution[i].s32VideoStreamIndex == streamIdx) {\r
- resolution.enVideoType = fmtFileInfo_.stSteamResolution[i].enVideoType;\r
- resolution.s32VideoStreamIndex = fmtFileInfo_.stSteamResolution[i].s32VideoStreamIndex;\r
- resolution.u32Width = fmtFileInfo_.stSteamResolution[i].u32Width;\r
- resolution.u32Height = fmtFileInfo_.stSteamResolution[i].u32Height;\r
- return HI_SUCCESS;\r
- }\r
- }\r
-\r
- MEDIA_ERR_LOG("not found stream[%d] in file", streamIdx);\r
- return HI_FAILURE;\r
-}\r
-\r
-int32_t PlayerControl::SetVDecAttr(void)\r
-{\r
- StreamResolution resolution = {};\r
- if (GetVideoResolution(fmtFileInfo_.s32UsedVideoStreamIndex, resolution) != HI_SUCCESS) {\r
- MEDIA_ERR_LOG("GetVideoResolution failed");\r
- return HI_FAILURE;\r
- }\r
- vdecAttr_.maxWidth = resolution.u32Width;\r
- vdecAttr_.maxHeight = resolution.u32Height;\r
- vdecAttr_.type = resolution.enVideoType;\r
- vdecAttr_.frameBufCnt = playerParam_.u32VdecFrameBufCnt;\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::SetADecAttr(void)\r
-{\r
- adecAttr_.bitWidth = AUDIO_BITWIDTH;\r
- adecAttr_.channel = fmtFileInfo_.u32AudioChannelCnt;\r
- adecAttr_.sampleRate = fmtFileInfo_.u32SampleRate;\r
- adecAttr_.type = fmtFileInfo_.enAudioType;\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::SetStreamAttr()\r
-{\r
- if (hasVideo_) {\r
- StreamResolution resolution = {};\r
- if (GetVideoResolution(fmtFileInfo_.s32UsedVideoStreamIndex, resolution) != HI_SUCCESS) {\r
- MEDIA_ERR_LOG("GetVideoResolution failed");\r
- return HI_ERR_PLAYERCONTROL_ILLEGAL_PARAM;\r
- }\r
- streamAttr_.videoBufSize = playerParam_.u32VideoEsBufSize;\r
- }\r
-\r
- if (hasAudio_) {\r
- streamAttr_.audioBufSize =\r
- (playerParam_.u32AudioEsBufSize) ? (playerParam_.u32AudioEsBufSize) : streamAttr_.audioBufSize;\r
- }\r
-\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::SetDecoderAndStreamAttr(void)\r
-{\r
- int ret;\r
-\r
- if (hasAudio_) {\r
- ret = SetADecAttr();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SetADecAttr failed");\r
- }\r
-\r
- if (hasVideo_) {\r
- ret = SetVDecAttr();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SetVDecAttr failed");\r
- }\r
-\r
- ret = SetStreamAttr();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SetStreamAttr failed");\r
- return HI_SUCCESS;\r
-}\r
-\r
-#if !defined(UNSUPPORT_VIDEO_DECODER) || !defined(UNSUPPORT_AUDIO_DECODER)\r
-static AvCodecMime TransformCodecFormatToAvCodecMime(CodecFormat format)\r
-{\r
- AvCodecMime mime = MEDIA_MIMETYPE_INVALID;\r
- uint32_t size = sizeof(g_avCodecFormatInfo) / sizeof(CodecFormatAndMimePair);\r
-\r
- for (uint32_t i = 0; i < size; i++) {\r
- if (g_avCodecFormatInfo[i].format == format) {\r
- mime = g_avCodecFormatInfo[i].mime;\r
- break;\r
- }\r
- }\r
-\r
- return mime;\r
-}\r
-#endif\r
-\r
-#ifndef UNSUPPORT_VIDEO_DECODER\r
-static void GetCurVideoSolution(const FormatFileInfo &info, uint32_t &width, uint32_t &height)\r
-{\r
- for (int i = 0; i < HI_DEMUXER_RESOLUTION_CNT; i++) {\r
- if (info.stSteamResolution[i].s32VideoStreamIndex == info.s32UsedVideoStreamIndex) {\r
- width = info.stSteamResolution[i].u32Width;\r
- height = info.stSteamResolution[i].u32Height;\r
- break;\r
- }\r
- }\r
-}\r
-#endif\r
-\r
-#ifndef UNSUPPORT_AUDIO_DECODER\r
-static std::string GetAudioNameByAvCodecMime(AvCodecMime mime)\r
-{\r
- std::string audioName = "codec.unknow.soft.decoder";\r
- switch (mime) {\r
- case MEDIA_MIMETYPE_AUDIO_AAC:\r
- audioName = "codec.aac.soft.decoder";\r
- break;\r
- case MEDIA_MIMETYPE_AUDIO_MP3:\r
- audioName = "codec.mp3.soft.decoder";\r
- break;\r
- default:\r
- MEDIA_ERR_LOG("not support codec type:%d", mime);\r
- break;\r
- }\r
- return audioName;\r
-}\r
-\r
-int32_t PlayerControl::AudioDecoderStart(void)\r
-{\r
- AvCodecMime mime = TransformCodecFormatToAvCodecMime(fmtFileInfo_.enAudioType);\r
- if (mime == MEDIA_MIMETYPE_INVALID) {\r
- MEDIA_ERR_LOG("DecoderStart not support codec:%d", fmtFileInfo_.enAudioType);\r
- return -1;\r
- }\r
- audioDecoder_ = std::make_shared<Decoder>();\r
- CHECK_NULL_RETURN(audioDecoder_, -1, "new decoder failed");\r
- AvAttribute attr;\r
- attr.type = AUDIO_DECODER;\r
- attr.adecAttr.mime = mime;\r
- attr.adecAttr.priv = nullptr;\r
- attr.adecAttr.bufSize = 0x400; /* 1024 */\r
- attr.adecAttr.channelCnt = (mime == MEDIA_MIMETYPE_AUDIO_PCM) ? fmtFileInfo_.u32AudioChannelCnt : 0;\r
- const std::string audioName = GetAudioNameByAvCodecMime(mime);\r
- int32_t ret = audioDecoder_->CreateHandle(audioName, attr);\r
- CHECK_FAILED_RETURN(ret, 0, -1, "create audio decoder failed");\r
- ret = audioDecoder_->StartDec();\r
- CHECK_FAILED_RETURN(ret, 0, -1, "start audio decoder failed");\r
- MEDIA_INFO_LOG("audio decoder started");\r
-\r
- return 0;\r
-}\r
-#endif\r
-\r
-#if !defined(UNSUPPORT_VIDEO_DECODER)\r
-int32_t PlayerControl::VideoDecoderStart(void)\r
-{\r
- AvAttribute attr;\r
- uint32_t width = DECODER_DEFAULT_WIDTH;\r
- uint32_t height = DECODER_DEFAULT_HEIGHT;\r
-\r
- AvCodecMime mime = TransformCodecFormatToAvCodecMime(fmtFileInfo_.enVideoType);\r
- if (mime == MEDIA_MIMETYPE_INVALID) {\r
- MEDIA_ERR_LOG("DecoderStart not support codec:%d", fmtFileInfo_.enVideoType);\r
- return -1;\r
- }\r
- GetCurVideoSolution(fmtFileInfo_, width, height);\r
-\r
- videoDecoder_ = std::make_shared<Decoder>();\r
- CHECK_NULL_RETURN(videoDecoder_, -1, "new decoder failed");\r
- attr.type = VIDEO_DECODER;\r
- attr.vdecAttr.mime = mime;\r
- attr.vdecAttr.priv = nullptr;\r
- attr.vdecAttr.bufSize = 0;\r
- attr.vdecAttr.maxWidth = width;\r
- attr.vdecAttr.maxHeight = height;\r
- const std::string videoName = "codec.avc.soft.decoder";\r
- int32_t ret = videoDecoder_->CreateHandle(videoName, attr);\r
- CHECK_FAILED_RETURN(ret, 0, -1, "create video decoder failed");\r
- ret = videoDecoder_->StartDec();\r
- CHECK_FAILED_RETURN(ret, 0, -1, "start video decoder failed");\r
- MEDIA_INFO_LOG("video decoder started");\r
-\r
- return 0;\r
-}\r
-#endif\r
-\r
-int32_t PlayerControl::DecoderStart(void)\r
-{\r
- if (!hasAudio_ && !hasVideo_) {\r
- MEDIA_ERR_LOG("not decoder need start");\r
- return -1;\r
- }\r
-\r
- MEDIA_INFO_LOG("audio stream id: %d, video stream id: %d", fmtFileInfo_.s32UsedAudioStreamIndex,\r
- fmtFileInfo_.s32UsedVideoStreamIndex);\r
-\r
- /* if offload audio is false, need audio decoder, not support */\r
- if (hasAudio_) {\r
- if (!offloadAudio_) {\r
- MEDIA_ERR_LOG("not support offload, need audio decoder, return failed");\r
- return -1;\r
- }\r
- }\r
-\r
- if (hasVideo_) {\r
-#if !defined(UNSUPPORT_VIDEO_DECODER)\r
- if (VideoDecoderStart() != 0) {\r
- return -1;\r
- }\r
-#endif\r
- }\r
- return 0;\r
-}\r
-\r
-void PlayerControl::DestroyDecoder() const\r
-{\r
-#ifndef UNSUPPORT_AUDIO_DECODER\r
- if (audioDecoder_ != nullptr) {\r
- audioDecoder_->DestroyHandle();\r
- }\r
-#endif\r
-#if !defined(UNSUPPORT_VIDEO_DECODER)\r
- if (videoDecoder_ != nullptr) {\r
- videoDecoder_->DestroyHandle();\r
- }\r
-#endif\r
-}\r
-\r
-void PlayerControl::StopSinkAndDecoder()\r
-{\r
- OutputInfo outInfo = {};\r
- EsFrameInfo frameInfo = {};\r
- if (sinkManager_ != nullptr) {\r
- sinkManager_->Stop();\r
-#ifdef UNSUPPORT_AUDIO_DECODER\r
- while (sinkManager_->DequeReleaseEsFrame(true, frameInfo) == HI_SUCCESS) {\r
- }\r
-#else\r
- if (audioDecoder_ != nullptr) {\r
- while (sinkManager_->DequeReleaseFrame(true, outInfo) == 0) {\r
- audioDecoder_->QueueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);\r
- }\r
- audioDecoder_->StopDec();\r
- }\r
-#endif\r
-#if !defined(UNSUPPORT_VIDEO_DECODER)\r
- if (videoDecoder_ != nullptr) {\r
- while (sinkManager_->DequeReleaseFrame(false, outInfo) == 0) {\r
- videoDecoder_->QueueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);\r
- }\r
- videoDecoder_->StopDec();\r
- }\r
-#endif\r
- }\r
-\r
- isVideoStarted_ = false;\r
- isAudioStarted_ = false;\r
-}\r
-\r
-int32_t PlayerControl::AddAudioSink(void)\r
-{\r
- CHECK_TRUE_CONDITION_RETURN(isAudioStarted_, HI_SUCCESS, "already started");\r
- SinkAttr attr;\r
- attr.sinkType = SINK_TYPE_AUDIO;\r
- attr.trackId = fmtFileInfo_.s32UsedAudioStreamIndex;\r
- attr.audAttr.format = g_fromCodecFormatToAudioManager[fmtFileInfo_.enAudioType];\r
- attr.audAttr.sampleRate = adecAttr_.sampleRate;\r
- attr.audAttr.channel = fmtFileInfo_.u32AudioChannelCnt;\r
- attr.audAttr.sessionID = audioSession_;\r
- attr.audAttr.streamType = streamType_;\r
- attr.audAttr.bitWidth = adecAttr_.bitWidth;\r
- attr.audAttr.sampleFmt = fmtFileInfo_.sampleFmt;\r
- MEDIA_INFO_LOG("AddAudioSink, format:%d, sampleRate:%d, channel:%d, session:%d, streamType:%d, bitWidth:%d",\r
- attr.audAttr.format, attr.audAttr.sampleRate, attr.audAttr.channel, attr.audAttr.sessionID,\r
- attr.audAttr.streamType, attr.audAttr.bitWidth);\r
- if (sinkManager_->AddNewSink(attr) != 0) {\r
- MEDIA_ERR_LOG("AddNewSink failed");\r
- return -1;\r
- }\r
- isAudioStarted_ = true;\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::GetOffloadSupport(void)\r
-{\r
- if (sinkManager_ == nullptr) {\r
- MEDIA_ERR_LOG("sinkManager_ is invalid");\r
- return -1;\r
- }\r
- AudioOffloadParam curOffloadInfo;\r
- curOffloadInfo.streamType = streamType_;\r
- curOffloadInfo.format = g_fromCodecFormatToAudioManager[fmtFileInfo_.enAudioType];\r
- curOffloadInfo.sampleRate = adecAttr_.sampleRate;\r
- curOffloadInfo.channel = fmtFileInfo_.u32AudioChannelCnt;\r
- curOffloadInfo.bitWidth = 0;\r
- MEDIA_INFO_LOG("GetOffloadSupport format:%d, audio:%d", curOffloadInfo.format, fmtFileInfo_.enAudioType);\r
- offloadAudio_ = sinkManager_->IsOffloadSupported(curOffloadInfo);\r
- MEDIA_INFO_LOG("%s audio offload", offloadAudio_ ? "supported" : "unsupported");\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::AddVideoSink()\r
-{\r
- CHECK_TRUE_CONDITION_RETURN(isVideoStarted_, HI_SUCCESS, "already started");\r
- SinkAttr attr;\r
- attr.sinkType = SINK_TYPE_VIDEO;\r
- attr.trackId = fmtFileInfo_.s32UsedVideoStreamIndex;\r
- attr.vidAttr.width = fmtFileInfo_.u32Width;\r
- attr.vidAttr.height = fmtFileInfo_.u32Height;\r
- attr.vidAttr.frameRate = fmtFileInfo_.fFrameRate;\r
- attr.vidAttr.format = fmtFileInfo_.enVideoType;\r
- attr.vidAttr.surface = surface_;\r
- if (sinkManager_->AddNewSink(attr) != 0) {\r
- MEDIA_ERR_LOG("AddNewSink failed");\r
- return -1;\r
- }\r
- isVideoStarted_ = true;\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::SinkStart(void)\r
-{\r
- int32_t ret;\r
- sinkManager_ = std::make_shared<SinkManager>();\r
- CHECK_NULL_RETURN(sinkManager_, HI_FAILURE, "new sinkManager_ nullptr");\r
- if (hasVideo_ && !isVideoStarted_) {\r
- ret = AddVideoSink();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "AddVideoSink failed");\r
- isVideoStarted_ = true;\r
- }\r
- if (hasAudio_ && !isAudioStarted_) {\r
- ret = AddAudioSink();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "AddAudioSink failed");\r
- isAudioStarted_ = true;\r
- }\r
-\r
- PlayEventCallback callback;\r
- GetPlayElementEventCallBack(callback);\r
- ret = sinkManager_->RegisterCallBack(callback);\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "RegisterCallBack failed");\r
- /* get offload flag */\r
- GetOffloadSupport();\r
-\r
- if (metaData_.key == KEY_TYPE_EXTRADATA && hasAudio_) {\r
- std::string key("extradata");\r
- ret = sinkManager_->SetParam(key, DATA_TYPE_PTR, metaData_.value.pValue, metaData_.size);\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "sinkManager_ SetParam failed");\r
- }\r
-\r
- ret = sinkManager_->Start();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "sinkManager_ Start failed");\r
-\r
- if (leftVolume_ >= 0.0f || rightVolume_ >= 0.0f) {\r
- sinkManager_->SetVolume(leftVolume_, rightVolume_);\r
- }\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::ReadFrameFromSource(FormatFrame &fmtFrame)\r
-{\r
- CHECK_NULL_RETURN(playerSource_, HI_ERR_PLAYERCONTROL_NULL_PTR, "playerSource_ nullptr");\r
- int ret = playerSource_->ReadFrame(fmtFrame);\r
- // Check consistency of fmtFrame\r
- if ((ret == HI_SUCCESS) && (fmtFrame.data != nullptr) && (fmtFrame.len == 0)) {\r
- MEDIA_ERR_LOG("ReadFrame ERROR : u32Size is invalid");\r
- ret = HI_FAILURE;\r
- }\r
- return ret;\r
-}\r
-\r
-// message begin\r
-int32_t PlayerControl::DoRegCallback(const PlayerCtrlCallbackParam &eventCallback)\r
-{\r
- if (eventCallback_.callbackFun != nullptr) {\r
- MEDIA_WARNING_LOG("you have reg callback,now the before callback fun pointer will be overwrite");\r
- }\r
- eventCallback_ = eventCallback;\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::DoSetDataSource(const char *filepath)\r
-{\r
- filePath_ = std::string(filepath);\r
- sourceType_ = SOURCE_TYPE_URI;\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::DoSetDataSource(const SourceFdParam &fdSrc)\r
-{\r
- fd_ = fdSrc.fd;\r
- offset_ = fdSrc.offset;\r
- sourceType_ = SOURCE_TYPE_FD;\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::DoSetDataSource(const StreamSourceParam &streamSource)\r
-{\r
- streamSource_ = streamSource;\r
- sourceType_ = SOURCE_TYPE_STREAM;\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::DoPrepare(void)\r
-{\r
- MEDIA_DEBUG_LOG("Process in");\r
- CHECK_NULL_RETURN(eventCallback_.callbackFun, HI_ERR_PLAYERCONTROL_CALLBACK_ERROR, "callbackFun nullptr");\r
- isPlayEnd_ = false;\r
- int32_t ret = SyncPrepare();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, HI_ERR_PLAYERCONTROL_OTHER, "SyncPrepare failed");\r
- if (playerParam_.u32PlayPosNotifyIntervalMs >= fmtFileInfo_.s64Duration) {\r
- MEDIA_WARNING_LOG("play postion notify interval %d ms oversize file duration, user will never receive notify",\r
- playerParam_.u32PlayPosNotifyIntervalMs);\r
- }\r
- MEDIA_DEBUG_LOG("Process out");\r
- return HI_SUCCESS;\r
-}\r
-\r
-#if !defined(UNSUPPORT_VIDEO_DECODER) || !defined(UNSUPPORT_AUDIO_DECODER)\r
-static void InitOutputBuffer(OutputInfo &outInfo, CodecType type)\r
-{\r
- if (outInfo.buffers != nullptr) {\r
- free(outInfo.buffers);\r
- outInfo.buffers = nullptr;\r
- }\r
-\r
- outInfo.bufferCnt = 0;\r
- outInfo.buffers = nullptr;\r
- outInfo.timeStamp = -1;\r
- outInfo.sequence = 0;\r
- outInfo.flag = 0;\r
- outInfo.type = type;\r
- outInfo.vendorPrivate = nullptr;\r
-}\r
-#endif\r
-\r
-#ifndef UNSUPPORT_AUDIO_DECODER\r
-void PlayerControl::ReleaseADecoderOutputFrame(void)\r
-{\r
- if (audioDecoder_ == nullptr || sinkManager_ == nullptr) {\r
- return;\r
- }\r
- while (true) {\r
- OutputInfo outInfo;\r
- if (sinkManager_->DequeReleaseFrame(true, outInfo) != 0) {\r
- break;\r
- }\r
- audioDecoder_->QueueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);\r
- }\r
-}\r
-#endif\r
-\r
-void PlayerControl::ReleaseAudioSinkESFrame(void)\r
-{\r
- CHECK_NULL_RETURN_NONE(sinkManager_, "sink manager is null");\r
-\r
- EsFrameInfo outInfo = {};\r
- while (sinkManager_->DequeReleaseEsFrame(true, outInfo) == HI_SUCCESS) {\r
- }\r
-}\r
-\r
-#if !defined(UNSUPPORT_VIDEO_DECODER)\r
-void PlayerControl::ReleaseVDecoderOutputFrame(void) const\r
-{\r
- if (videoDecoder_ == nullptr || sinkManager_ == nullptr) {\r
- return;\r
- }\r
- while (true) {\r
- OutputInfo outInfo;\r
- if (sinkManager_->DequeReleaseFrame(false, outInfo) != 0) {\r
- break;\r
- }\r
- }\r
-}\r
-#endif\r
-\r
-void PlayerControl::ReportRenderPosition(void)\r
-{\r
- int64_t position = -1;\r
- CHECK_NULL_RETURN_NONE(sinkManager_, "sinkManager_ nullptr");\r
- sinkManager_->GetRenderPosition(position);\r
- if (position >= 0 && currentPosition_ != position) {\r
- if (lastRendPos_ >= 0) {\r
- currentPosition_ = position - lastRendPos_ + firstPosAfterSeek_;\r
- } else {\r
- currentPosition_ = position;\r
- }\r
- EventCallback(PLAYERCONTROL_EVENT_PROGRESS, ¤tPosition_);\r
- }\r
-}\r
-\r
-void PlayerControl::GetRenderFullSleepThresholdTime(AudioCodecFormat codecFormat)\r
-{\r
-#ifdef DEBUG_LOW_POWER\r
- if (codecFormat == PCM) {\r
- renderFullSleepThresholdMs_ = RENDER_FULL_SLEEP_THRESHOLD_MS_PCM;\r
- } else if (codecFormat == MP3 || codecFormat == AAC_LC || codecFormat == OPUS) {\r
- renderFullSleepThresholdMs_ = RENDER_FULL_SLEEP_THRESHOLD_MS_MP3_AACLC_OPUS;\r
- } else if (codecFormat == FLAC) {\r
- renderFullSleepThresholdMs_ = RENDER_FULL_SLEEP_THRESHOLD_MS_FLAC;\r
- }\r
-#else\r
- MEDIA_UNUSED(codecFormat);\r
-#endif\r
-}\r
-\r
-void PlayerControl::DataSchPreProcess(PlayerControl *play, bool *isContinue)\r
-{\r
- if (play->hasRenderAudioEos_) {\r
- int32_t info = PLAYERCONTROL_ERROR_AUD_PLAY_FAIL;\r
- play->EventCallback(PLAYERCONTROL_EVENT_ERROR, &info);\r
- MEDIA_ERR_LOG("player waiting for the EOS callback timed out.");\r
- }\r
- play->DoSeekIfNeed();\r
-\r
- play->renderSleepTime_ = 0;\r
-\r
- if (play->paused_) {\r
- // blocking wait ensures that the system goes into deep sleep for reducing power consumption\r
- MediaThreadCondWait(play->schCond_, play->schMutex_);\r
- *isContinue = true;\r
- }\r
-}\r
-\r
-void PlayerControl::DataSchPostProcess(PlayerControl *play)\r
-{\r
- play->EventQueueProcess();\r
-\r
- play->ReportRenderPosition();\r
-\r
- play->PrintKpiTime();\r
-\r
- // process pure video eos\r
- if (play->hasVideo_ && !play->hasAudio_ && play->hasRenderVideoEos_) {\r
- MEDIA_INFO_LOG("Received video play eos flag");\r
- play->EventCallback(PLAYERCONTROL_EVENT_EOF, nullptr);\r
- }\r
-\r
- if (play->IsPlayEos()) {\r
- play->renderSleepTime_ = RENDER_EOS_SLEEP_TIME_US;\r
- }\r
-}\r
-\r
-#if !defined(UNSUPPORT_VIDEO_DECODER) || !defined(UNSUPPORT_AUDIO_DECODER)\r
-inline static bool IsValidPacket(FormatFrame &packet)\r
-{\r
- return (packet.data != nullptr && packet.len != 0) ? true : false;\r
-}\r
-#endif\r
-\r
-int32_t PlayerControl::DequeueInputDataFromDemuxer(void)\r
-{\r
- if (GetCurState() != PLAY_STATUS_PLAY) {\r
- renderSleepTime_ = WAIT_MAIN_THREAD_SWITCH_TO_PLAY_STATUS_TIME_US;\r
- return HI_FAILURE;\r
- }\r
-\r
- CHECK_TRUE_CONDITION_RETURN(strmReadEnd_, HI_SUCCESS, "read stream end");\r
-\r
-#ifdef PLAYER_KPI_ON\r
- struct timeval readPacketStartTime;\r
- RecordTime(readPacketStartTime);\r
-#endif\r
-\r
- int32_t ret = ReadPacket();\r
- if (ret == HI_RET_NODATA) {\r
- renderSleepTime_ = NO_DATA_READ_SLEEP_TIME_US;\r
- goto RE_SEND;\r
- } else if (ret != HI_SUCCESS) {\r
- goto RE_SEND;\r
- }\r
-\r
-#ifdef PLAYER_KPI_ON\r
- ReadPacketAvgCostTime(readPacketStartTime);\r
-#endif\r
-\r
- if (formatPacket_.data == nullptr && formatPacket_.len == 0) {\r
- strmReadEnd_ = true;\r
- formatPacket_.timestampUs = -1;\r
- gettimeofday(&streamEndTime_, nullptr);\r
- if (loop_) {\r
- seekToTimeMs_ = 0;\r
- return HI_FAILURE;\r
- }\r
- }\r
-\r
- isAudio_ = (formatPacket_.frameType == FRAME_TYPE_AUDIO) ? true : false;\r
- isVideo_ = (formatPacket_.frameType == FRAME_TYPE_VIDEO) ? true : false;\r
-\r
- return HI_SUCCESS;\r
-\r
-RE_SEND:\r
- ClearCachePacket();\r
- return ret;\r
-}\r
-\r
-int32_t PlayerControl::QueueInputDataToAudioSink(void)\r
-{\r
- CHECK_NULL_RETURN(sinkManager_, HI_FAILURE, "sink manager is null");\r
- CHECK_TRUE_CONDITION_RETURN(hasRenderAudioEos_, HI_FAILURE, "has render audio eos");\r
-\r
- if (strmReadEnd_) {\r
- sinkManager_->RenderEos(true);\r
- } else {\r
- CHECK_FALSE_CONDITION_RETURN(cachedPacket_, HI_FAILURE, "no cache packet");\r
- }\r
-\r
- EsFrameInfo outInfo = {};\r
- FillAudioFrameInfo(outInfo);\r
- int32_t ret = sinkManager_->RenderEsFrame(outInfo);\r
- if (ret == SINK_RENDER_FULL || ret == SINK_RENDER_DELAY) {\r
-#ifdef DEBUG_LOW_POWER\r
- static uint32_t renderSuccessCount = 0;\r
- LowPowerProcess(outInfo.pts, renderSuccessCount, false);\r
-#else\r
- if (ret == SINK_RENDER_FULL && fmtFileInfo_.s32UsedVideoStreamIndex < 0) {\r
- renderSleepTime_ = WAIT_BUFFER_EMPTY_SLEEP_TIME_US;\r
- } else {\r
- renderSleepTime_ = RENDER_FULL_SLEEP_TIME_US;\r
- }\r
-#endif\r
- return ret;\r
- } else {\r
-#ifdef DEBUG_LOW_POWER\r
- LowPowerProcess(outInfo.pts, renderSuccessCount, true);\r
-#endif\r
- renderSleepTime_ = 0;\r
- }\r
- ReleaseAudioSinkESFrame();\r
- if (ret == SINK_RENDER_EOS) {\r
- hasRenderAudioEos_ = true;\r
- MEDIA_INFO_LOG("have render audio eos");\r
- if (IsPlayEos()) {\r
- isPlayEnd_ = true;\r
- }\r
- }\r
- if (firstAudioFrameAfterSeek_) {\r
- firstAudioFrameAfterSeek_ = false;\r
- sinkManager_->GetRenderPosition(lastRendPos_);\r
- firstPosAfterSeek_ = formatPacket_.timestampUs;\r
- MEDIA_INFO_LOG("push firstAudioFrameAfterSeek_ success, pts:%lld", formatPacket_.timestampUs);\r
- }\r
- if (formatPacket_.data != nullptr || formatPacket_.len != 0) {\r
- lastSendAdecPts_ = formatPacket_.timestampUs;\r
- }\r
- ClearCachePacket();\r
- return ret;\r
-}\r
-\r
-#ifndef UNSUPPORT_AUDIO_DECODER\r
-void PlayerControl::QueueInputDataToAudioDecoder(void)\r
-{\r
- CHECK_NULL_RETURN_NONE(audioDecoder_, "audio decoder is null");\r
- CHECK_TRUE_CONDITION_RETURN_NONE(cachedPacket_, "no cache packet");\r
-\r
- InputInfo inputData = { 0, nullptr, 0, 0 };\r
- CodecBufferInfo inBufInfo = {};\r
-\r
- int32_t ret = audioDecoder_->DequeInputBuffer(inputData, GET_BUFFER_TIMEOUT_MS);\r
- CHECK_FAILED_RETURN_NONE(ret, HI_SUCCESS, "deque input buffer failed");\r
-\r
- inBufInfo.addr = formatPacket_.data;\r
- inBufInfo.length = formatPacket_.len;\r
- inputData.bufferCnt = 1;\r
- inputData.buffers = &inBufInfo;\r
- inputData.pts = formatPacket_.timestampUs;\r
- inputData.flag = 0;\r
- ret = audioDecoder_->QueueInputBuffer(inputData, GET_BUFFER_TIMEOUT_MS);\r
- if (ret == CODEC_ERR_STREAM_BUF_FULL) {\r
- renderSleepTime_ = QUEUE_BUFFER_FULL_SLEEP_TIME_US;\r
- return;\r
- }\r
- if (firstAudioFrameAfterSeek_ && IsValidPacket(formatPacket_)) {\r
- firstAudioFrameAfterSeek_ = false;\r
- MEDIA_INFO_LOG("push firstAudioFrameAfterSeek_ success, pts:%lld", inputData.pts);\r
- }\r
- if (formatPacket_.data != nullptr || formatPacket_.len != 0) {\r
- lastSendAdecPts_ = formatPacket_.timestampUs;\r
- }\r
- ClearCachePacket();\r
-}\r
-\r
-void PlayerControl::DequeueOutputBufferAndRenderAudioFrame(void)\r
-{\r
- CHECK_NULL_RETURN_NONE(audioDecoder_, "audio decoder is null");\r
- CHECK_NULL_RETURN_NONE(sinkManager_, "sink manager is null");\r
- CHECK_FAILED_RETURN_NONE(hasRenderAudioEos_, false, "has render audio eos");\r
-\r
- OutputInfo outInfo = {};\r
- int32_t ret = audioDecoder_->DequeueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);\r
- if (ret != HI_SUCCESS) {\r
- InitOutputBuffer(outInfo, AUDIO_DECODER);\r
- if (ret == CODEC_RECEIVE_EOS && strmReadEnd_) {\r
- // all frame have been send to audio sink\r
- sinkManager_->RenderEos(true);\r
- }\r
- }\r
-\r
- ret = sinkManager_->RenderFrame(outInfo);\r
- if (ret == SINK_RENDER_FULL || ret == SINK_RENDER_DELAY) {\r
- renderSleepTime_ = RENDER_FULL_SLEEP_TIME_US;\r
- } else if (ret == SINK_QUE_EMPTY) {\r
- renderSleepTime_ = 0;\r
- }\r
- ReleaseADecoderOutputFrame();\r
- // all frame in frameCacheQue_ is processed\r
- if (ret == SINK_RENDER_EOS) {\r
- hasRenderAudioEos_ = true;\r
- MEDIA_INFO_LOG("have render audio eos");\r
- if (IsPlayEos()) {\r
- isPlayEnd_ = true;\r
- }\r
- }\r
-}\r
-#endif\r
-\r
-#if !defined(UNSUPPORT_VIDEO_DECODER)\r
-int32_t PlayerControl::QueueOutputBufferToVideoDecoder(void)\r
-{\r
- CHECK_NULL_RETURN(surface_, HI_FAILURE, "surface is null");\r
- CHECK_NULL_RETURN(sinkManager_, HI_FAILURE, "sink manager is null");\r
- CHECK_NULL_RETURN(videoDecoder_, HI_FAILURE, "video decoder is null");\r
-\r
- // 1. if video sink have cache, means have remain buffer not send to surface, don't need request buffer from surface\r
- bool haveCache = sinkManager_->HaveCacheFrame(false);\r
- if (haveCache) {\r
- MEDIA_DEBUG_LOG("have cache frame skip this");\r
- return HI_SUCCESS;\r
- }\r
-\r
- // 2. request video output buffer from surface\r
-#if defined(ENABLE_UIKIT)\r
- surfaceBuf_ = surface_->RequestBuffer();\r
-#elif defined(ENABLE_LVGL)\r
- surfaceBuf_ = LvRequestBuffer(reinterpret_cast<lv_obj_t *>(surface_), 0);\r
-#endif\r
- if (surfaceBuf_ == nullptr) {\r
- if (continousRequestSurfaceBufferFailCount_ == MAX_CONTINOUS_REQUEST_SURFACE_BUFFER_FAIL_COUNT) {\r
- PalayControlEventItem item = { EVNET_VIDEO_RUNNING_ERR };\r
- eventQueue_.push_back(item);\r
- MEDIA_FATAL_LOG("continous request buffer fail count exceed upper limit");\r
- return REQUEST_SURFACE_BUFFER_FATAL;\r
- }\r
- MEDIA_DEBUG_LOG("no free surface buffer retry");\r
- renderSleepTime_ = REQUEST_BUFFER_RETRY_WAIT_TIME_US;\r
- continousRequestSurfaceBufferFailCount_++;\r
- return HI_FAILURE;\r
- }\r
- continousRequestSurfaceBufferFailCount_ = 0;\r
-\r
- // 3. queue output buffer to video decoder\r
- OutputInfo outInfo = {};\r
- outInfo.type = VIDEO_DECODER;\r
- outInfo.bufferCnt = 1;\r
- outInfo.buffers = (CodecBufferInfo *)malloc(sizeof(CodecBufferInfo));\r
- if (outInfo.buffers == nullptr) {\r
- MEDIA_ERR_LOG("malloc failed");\r
- return HI_FAILURE;\r
- }\r
- outInfo.buffers[0].type = BUFFER_TYPE_VIRTUAL;\r
- outInfo.buffers[0].addr = reinterpret_cast<uint8_t *>(surfaceBuf_->addr);\r
- outInfo.buffers[0].length = surfaceBuf_->width * surfaceBuf_->height * YCBCR420SP_BUFFER_SIZE_COEFFICIENT;\r
- outInfo.vendorPrivate = surfaceBuf_;\r
-\r
- int32_t ret = videoDecoder_->QueueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);\r
- if (ret != HI_SUCCESS) {\r
- free(outInfo.buffers);\r
- MEDIA_ERR_LOG("queue output buffer to video decoder failed: 0x%x", ret);\r
- return HI_FAILURE;\r
- }\r
-\r
- free(outInfo.buffers);\r
- return HI_SUCCESS;\r
-}\r
-\r
-void PlayerControl::QueueInputDataToVideoDecoder(void)\r
-{\r
- CHECK_NULL_RETURN_NONE(videoDecoder_, "video decoder is null");\r
- CHECK_NULL_RETURN_NONE(sinkManager_, "sink manager is null");\r
-\r
- bool haveCache = sinkManager_->HaveCacheFrame(false);\r
- if (haveCache) {\r
- MEDIA_DEBUG_LOG("have cache frame skip this");\r
- return;\r
- }\r
-\r
- if (!strmReadEnd_) {\r
- CHECK_FALSE_CONDITION_RETURN_NONE(cachedPacket_, "no cache packet");\r
- }\r
-\r
- InputInfo inputData = { 0, nullptr, 0, 0 };\r
- CodecBufferInfo inBufInfo = {};\r
-\r
- int32_t ret = videoDecoder_->DequeInputBuffer(inputData, GET_BUFFER_TIMEOUT_MS);\r
- CHECK_FAILED_RETURN_NONE(ret, HI_SUCCESS, "deque input buffer failed");\r
-\r
- MEDIA_DEBUG_LOG("queue input buffer len: %u, pts: %lld", formatPacket_.len, formatPacket_.timestampUs);\r
-\r
- inBufInfo.addr = formatPacket_.data;\r
- inBufInfo.length = formatPacket_.len;\r
- inputData.bufferCnt = 1;\r
- inputData.buffers = &inBufInfo;\r
- inputData.pts = formatPacket_.timestampUs;\r
- inputData.flag = (formatPacket_.data == nullptr && formatPacket_.len == 0) ? STREAM_FLAG_EOS : 0;\r
- ret = videoDecoder_->QueueInputBuffer(inputData, GET_BUFFER_TIMEOUT_MS);\r
- if (ret == CODEC_ERR_STREAM_BUF_FULL) {\r
- renderSleepTime_ = QUEUE_BUFFER_FULL_SLEEP_TIME_US;\r
- return;\r
- }\r
- if (firstVideoFrameAfterSeek_ && IsValidPacket(formatPacket_)) {\r
- firstVideoFrameAfterSeek_ = false;\r
- MEDIA_INFO_LOG("push firstVideoFrameAfterSeek_ success, pts:%lld", inputData.pts);\r
- }\r
- if (formatPacket_.data != nullptr && formatPacket_.len != 0) {\r
- lastSendVdecPts_ = formatPacket_.timestampUs;\r
- }\r
- ClearCachePacket();\r
-}\r
-\r
-void PlayerControl::DequeueOutputBufferAndRenderVideoFrame(void)\r
-{\r
- CHECK_NULL_RETURN_NONE(videoDecoder_, "video decoder is null");\r
- CHECK_NULL_RETURN_NONE(sinkManager_, "sink manager is null");\r
- CHECK_TRUE_CONDITION_RETURN_NONE(hasRenderVideoEos_, "has render video eos");\r
-\r
- OutputInfo outInfo = {};\r
- outInfo.buffers = (CodecBufferInfo *)malloc(sizeof(CodecBufferInfo));\r
- if (outInfo.buffers == nullptr) {\r
- MEDIA_ERR_LOG("malloc failed");\r
- return;\r
- }\r
- int ret = videoDecoder_->DequeueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);\r
- if (ret != 0) {\r
- InitOutputBuffer(outInfo, VIDEO_DECODER);\r
- if (surface_ != nullptr) {\r
-#if defined(ENABLE_UIKIT)\r
- surface_->CancelBuffer(surfaceBuf_);\r
-#elif defined(ENABLE_LVGL)\r
- LvCancelBuffer(reinterpret_cast<lv_obj_t *>(surface_), surfaceBuf_);\r
-#endif\r
- }\r
- if (ret == CODEC_RECEIVE_EOS) {\r
- sinkManager_->RenderEos(false); /* all frame have been send to video sink */\r
- } else {\r
- goto EXIT;\r
- }\r
- }\r
-\r
- ret = sinkManager_->RenderFrame(outInfo);\r
- if (ret == SINK_RENDER_FULL || ret == SINK_RENDER_DELAY) {\r
- renderSleepTime_ = RENDER_FULL_SLEEP_TIME_US;\r
- } else if (ret == SINK_QUE_EMPTY) {\r
- renderSleepTime_ = 0;\r
- }\r
-EXIT:\r
- ReleaseVDecoderOutputFrame();\r
- /* fuction RenderFrame will return SINK_RENDER_EOS when all frame in queue that have been processed */\r
- if (ret == SINK_RENDER_EOS) {\r
- hasRenderVideoEos_ = true;\r
- MEDIA_INFO_LOG("have render video eos");\r
- if (IsPlayEos()) {\r
- isPlayEnd_ = true;\r
- }\r
- }\r
-\r
- if (outInfo.buffers != nullptr) {\r
- free(outInfo.buffers);\r
- }\r
- return;\r
-}\r
-#endif\r
-\r
-int32_t PlayerControl::DealWithInputEos(bool hasAudio, bool hasVideo)\r
-{\r
- if (hasAudio) {\r
-#ifdef UNSUPPORT_AUDIO_DECODER\r
- QueueInputDataToAudioSink();\r
-#else\r
- QueueInputDataToAudioDecoder();\r
- DequeueOutputBufferAndRenderAudioFrame();\r
-#endif\r
- }\r
-\r
- if (hasVideo) {\r
-#if !defined(UNSUPPORT_VIDEO_DECODER)\r
- int32_t ret = QueueOutputBufferToVideoDecoder();\r
- if (ret != HI_SUCCESS) {\r
- return ret;\r
- }\r
- QueueInputDataToVideoDecoder();\r
- DequeueOutputBufferAndRenderVideoFrame();\r
-#endif\r
- }\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::ProcessInputData(bool isAudio, bool isVideo)\r
-{\r
- if (isAudio) {\r
-#ifdef UNSUPPORT_AUDIO_DECODER\r
- return QueueInputDataToAudioSink();\r
-#else\r
- QueueInputDataToAudioDecoder();\r
- DequeueOutputBufferAndRenderAudioFrame();\r
-#endif\r
- } else if (isVideo) {\r
-#if !defined(UNSUPPORT_VIDEO_DECODER)\r
- int32_t retValue = QueueOutputBufferToVideoDecoder();\r
- if (retValue != HI_SUCCESS) {\r
- return retValue;\r
- }\r
- QueueInputDataToVideoDecoder();\r
- DequeueOutputBufferAndRenderVideoFrame();\r
-#endif\r
- }\r
- return HI_SUCCESS;\r
-}\r
-\r
-void *PlayerControl::DataSchProcess(void *priv)\r
-{\r
- CHECK_NULL_RETURN(priv, nullptr, "priv is null");\r
-\r
- PlayerControl *play = (PlayerControl *)priv;\r
-\r
-#ifdef SUPPORT_SYS_PRCTL\r
- prctl(PR_SET_NAME, "PlaySch", 0, 0, 0);\r
-#endif\r
-\r
- MEDIA_INFO_LOG("start work");\r
-\r
- // for low power\r
- play->GetRenderFullSleepThresholdTime(g_fromCodecFormatToAudioManager[play->fmtFileInfo_.enAudioType]);\r
-\r
- int32_t ret = HI_FAILURE;\r
- while (true) {\r
- MediaMutexLock(play->schMutex_);\r
- if (play->schThreadExit_) {\r
- MediaMutexUnLock(play->schMutex_);\r
- break;\r
- }\r
-\r
- bool isContinue = false;\r
- DataSchPreProcess(play, &isContinue);\r
- if (isContinue) {\r
- goto CONTINUE;\r
- }\r
-\r
- if (play->DequeueInputDataFromDemuxer() != HI_SUCCESS) {\r
- goto CONTINUE;\r
- }\r
-\r
- if (play->strmReadEnd_) {\r
- ret = play->DealWithInputEos(play->hasAudio_, play->hasVideo_);\r
- } else {\r
- ret = play->ProcessInputData(play->isAudio_, play->isVideo_);\r
- }\r
-\r
- if (ret == SINK_RENDER_FATEL || ret == REQUEST_SURFACE_BUFFER_FATAL) {\r
- play->EventQueueProcess();\r
- MediaMutexUnLock(play->schMutex_);\r
- break;\r
- } else if (ret != HI_SUCCESS) {\r
- goto CONTINUE;\r
- }\r
-\r
- DataSchPostProcess(play);\r
-\r
- CONTINUE:\r
- if (play->renderSleepTime_ > 0) {\r
- MediaThreadCondTimeWait(play->schCond_, play->schMutex_, play->renderSleepTime_);\r
- }\r
- MediaMutexUnLock(play->schMutex_);\r
- }\r
-\r
- MediaMutexLock(play->schMutex_);\r
- play->schThreadExit_ = true;\r
- MediaMutexUnLock(play->schMutex_);\r
-\r
- MEDIA_INFO_LOG("end work");\r
- return nullptr;\r
-}\r
-\r
-int32_t PlayerControl::DoPlay()\r
-{\r
- MEDIA_DEBUG_LOG("Process in");\r
- CHECK_NULL_RETURN(playerSource_, HI_ERR_PLAYERCONTROL_NULL_PTR, "playerSource_ nullptr");\r
-\r
- int32_t ret = HI_SUCCESS;\r
- PlayerStatus playerState = GetCurState();\r
- CHECK_STATE_SAME_RETURN(playerState, PLAY_STATUS_PLAY, "state same");\r
- if (playerState == PLAY_STATUS_PREPARED) {\r
- ret = CheckMediaInfo();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "CheckMediaInfo failed");\r
- ret = SetDecoderAndStreamAttr();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SetDecoderAndStreamAttr failed");\r
- ret = SinkStart();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SinkStart failed");\r
- ret = DecoderStart();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "DecoderStart failed");\r
- ret = playerSource_->Start();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "playerSource_ Start failed");\r
- MediaMutexLock(schMutex_);\r
- paused_ = true;\r
- MediaThreadattr attr = { "PlaySch", MAX_THREAD_STACK_SIZE, THREAD_SCHED_INVALID, 80, false };\r
- schProcess_ = MediaThreadCreate(DataSchProcess, this, &attr);\r
- if (schProcess_ == nullptr) {\r
- MEDIA_ERR_LOG("thread create failed %d", ret);\r
- schThreadExit_ = false;\r
- MediaMutexUnLock(schMutex_);\r
- return -1;\r
- }\r
- paused_ = false;\r
- MediaMutexUnLock(schMutex_);\r
- } else if (playerState == PLAY_STATUS_PAUSE) {\r
- ret = PauseResume();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "PauseResume failed");\r
- } else {\r
- return HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION;\r
- }\r
- return ret;\r
-}\r
-\r
-int32_t PlayerControl::DoSetVolume(const VolumeAttr &volumeAttr)\r
-{\r
- leftVolume_ = volumeAttr.leftVolume;\r
- rightVolume_ = volumeAttr.rightVolume;\r
- CHECK_NULL_RETURN(sinkManager_, HI_SUCCESS, "sinkManager_ nullptr, it will be setted after play");\r
- return sinkManager_->SetVolume(volumeAttr.leftVolume, volumeAttr.rightVolume);\r
-}\r
-\r
-int32_t PlayerControl::ReadPacket()\r
-{\r
- int32_t ret = HI_SUCCESS;\r
- if (cachedPacket_) {\r
- return ret;\r
- }\r
- ret = ReadFrameFromSource(formatPacket_);\r
- if (ret != HI_RET_FILE_EOF && formatPacket_.data == nullptr && formatPacket_.len == 0) {\r
- return HI_RET_NODATA;\r
- }\r
- if (ret == HI_RET_FILE_EOF) {\r
- CHECK_FAILED_RETURN(memset_s(&formatPacket_, sizeof(formatPacket_), 0, sizeof(FormatFrame)), EOK, -1,\r
- "memset_s failed");\r
- ret = HI_SUCCESS;\r
- } else if (ret == HI_RET_NODATA) {\r
- CHECK_FAILED_RETURN(memset_s(&formatPacket_, sizeof(formatPacket_), 0, sizeof(FormatFrame)), EOK, -1,\r
- "memset_s failed");\r
- strmReadEnd_ = false;\r
- return ret;\r
- } else if (ret != HI_SUCCESS) {\r
- MEDIA_ERR_LOG("ReadFrameFromSource failed , ret:%d", ret);\r
- NotifyError(PLAYERCONTROL_ERROR_DEMUX_FAIL);\r
- return HI_FAILURE;\r
- }\r
- strmReadEnd_ = false;\r
- cachedPacket_ = true;\r
- return ret;\r
-}\r
-\r
-#ifdef PLAYER_KPI_ON\r
-void PlayerControl::PrintRenderEsTime(const struct timeval &esFrameStartTime)\r
-{\r
- std::string renderEsFrame("KPI_PlayerRenderEsFrame");\r
- struct timeval esFrameEndTime = {};\r
- uint64_t renderEsOnceTime = CalcTimeDiffUsPrint(esFrameStartTime, esFrameEndTime, renderEsFrame, false);\r
- if (renderEsOnceTime != INVALID_TIME) {\r
- renderEsTotalTime_ += renderEsOnceTime;\r
- renderEsFrameCnt_++;\r
- }\r
- if (renderEsFrameCnt_ == 500) { /* 500:Print Interval */\r
- MEDIA_INFO_LOG("KPI_PlayerRenderEsFrame avg time: %lld us", renderEsTotalTime_ /= renderEsFrameCnt_);\r
- renderEsTotalTime_ = 0;\r
- renderEsFrameCnt_ = 0;\r
- }\r
-}\r
-#endif\r
-\r
-void PlayerControl::FillAudioFrameInfo(EsFrameInfo &outInfo)\r
-{\r
- if (memset_s(&outInfo, sizeof(outInfo), 0, sizeof(EsFrameInfo)) != EOK) {\r
- return;\r
- }\r
-\r
- outInfo.addr = formatPacket_.data;\r
- outInfo.size = formatPacket_.len;\r
- outInfo.pts = formatPacket_.timestampUs;\r
- outInfo.flag = 0;\r
- EsFrameType frameType = g_fromDemuxTypeToSinkType[formatPacket_.frameType];\r
- outInfo.type = (frameType == ESFRAME_TYPE_NONE) ? ESFRAME_TYPE_AUDIO : frameType;\r
-}\r
-\r
-#ifdef DEBUG_LOW_POWER\r
-void PlayerControl::LowPowerProcess(int64_t pts, uint32_t &renderSuccessCount, bool renderFrameSuccess)\r
-{\r
- if (renderFrameSuccess) {\r
- if (headInSendSuccessInterval_ == -1) {\r
- headInSendSuccessInterval_ = pts;\r
- tailInSendSuccessInterval_ = -1;\r
- }\r
- renderSuccessCount++;\r
- } else {\r
- if (tailInSendSuccessInterval_ == -1) {\r
- tailInSendSuccessInterval_ = pts;\r
- int64_t diffMs = tailInSendSuccessInterval_ - headInSendSuccessInterval_ - renderFullSleepThresholdMs_;\r
- renderSleepTime_ = (diffMs > 0) ? (diffMs * US_2_MS) : RENDER_FULL_SLEEP_TIME_US;\r
- }\r
-\r
- /* MEAIA_XXX_LOG have performance problem, use printf instead */\r
- printf("render %d audio frames, from %lldms to %lldms, thread wait %ums\n", renderSuccessCount,\r
- tailInSendSuccessInterval_, headInSendSuccessInterval_, renderSleepTime_ / US_2_MS);\r
-\r
- headInSendSuccessInterval_ = -1;\r
- renderSuccessCount = 0;\r
- }\r
-}\r
-#endif\r
-\r
-#ifdef PLAYER_KPI_ON\r
-void PlayerControl::ReadPacketAvgCostTime(const struct timeval &readPacketStartTime)\r
-{\r
- struct timeval readPacketEndTime;\r
- std::string readPacketCost("KPI_Player_demux_cost_time");\r
- uint64_t readPktOnceTime = CalcTimeDiffUsPrint(readPacketStartTime, readPacketEndTime, readPacketCost, false);\r
- if (readPktOnceTime != INVALID_TIME) {\r
- readPktTotalTime_ += readPktOnceTime;\r
- readPacketCnt_++;\r
- }\r
- if (readPacketCnt_ == 500) { /* 500:Print Interval */\r
- MEDIA_INFO_LOG("KPI_Player_demux_cost_time avg time: %lld us", readPktTotalTime_ /= readPacketCnt_);\r
- readPktTotalTime_ = 0;\r
- readPacketCnt_ = 0;\r
- }\r
-}\r
-#endif\r
-\r
-int32_t PlayerControl::DoStop()\r
-{\r
- int32_t ret = HI_SUCCESS;\r
- PlayerStatus playerState = GetCurState();\r
- CHECK_STATE_SAME_RETURN(playerState, PLAY_STATUS_IDLE, "state same");\r
-\r
- if (schProcess_ != nullptr) {\r
- MediaMutexLock(schMutex_);\r
- schThreadExit_ = true;\r
- MediaThreadCondSignal(schCond_);\r
- MediaMutexUnLock(schMutex_);\r
- MediaThreadJoin(&schProcess_);\r
- }\r
- StopSinkAndDecoder();\r
- ClearCachePacket();\r
- if (playerSource_ != nullptr) {\r
- ret = playerSource_->Stop();\r
- CHECK_FAILED_PRINT(ret, HI_SUCCESS, "playerSource_ stop failed");\r
- }\r
- isPlayEnd_ = false;\r
- strmReadEnd_ = false;\r
- isPlayErr_ = false;\r
- lastRendPos_ = 0;\r
- lastReadPktPts_ = 0;\r
- lastSendPktPts_ = 0;\r
- isAudPlayEos_ = false;\r
- hasRenderAudioEos_ = false;\r
- hasRenderAudioEos_ = false;\r
- lastNotifyTime_ = 0;\r
- seekToTimeMs_ = -1;\r
- if (memset_s(&(fmtFileInfo_), sizeof(fmtFileInfo_), 0, sizeof(FormatFileInfo)) != EOK) {\r
- MEDIA_ERR_LOG("memset_s failed");\r
- return HI_ERR_PLAYERCONTROL_MEM_SET;\r
- }\r
- return ret;\r
-}\r
-\r
-int32_t PlayerControl::DoPause(void)\r
-{\r
- PlayerStatus playerState = GetCurState();\r
- CHECK_STATE_SAME_RETURN(playerState, PLAY_STATUS_PAUSE, "state same");\r
- CHECK_NULL_RETURN(sinkManager_, HI_FAILURE, "sinkManager_ nullptr");\r
-\r
- if (playerState == PLAY_STATUS_PLAY) {\r
- MediaMutexLock(schMutex_);\r
- int32_t ret = sinkManager_->Pause();\r
- CHECK_FAILED_PRINT(ret, 0, "sinkManager_ pause failed:%d");\r
- paused_ = true;\r
- MediaMutexUnLock(schMutex_);\r
- } else {\r
- return HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION;\r
- }\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::DoSeekIfNeed(void)\r
-{\r
- if (seekToTimeMs_ == -1) {\r
- return HI_SUCCESS;\r
- }\r
- MEDIA_INFO_LOG("seek start");\r
- int32_t ret = AyncSeek(seekToTimeMs_);\r
- if (ret != HI_SUCCESS) {\r
- MEDIA_ERR_LOG(" AyncSeek failed , ret:%d", ret);\r
- NotifyError(PLAYERCONTROL_ERROR_AUD_PLAY_FAIL);\r
- return ret;\r
- }\r
- strmReadEnd_ = false;\r
- isAudPlayEos_ = false;\r
- isVidPlayEos_ = false;\r
- hasRenderVideoEos_ = false;\r
- hasRenderAudioEos_ = false;\r
- isPlayEnd_ = false;\r
- seekToTimeMs_ = -1;\r
- firstAudioFrameAfterSeek_ = true;\r
- firstVideoFrameAfterSeek_ = true;\r
- MEDIA_INFO_LOG("seek end");\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::DoSeek(int64_t timeInMs)\r
-{\r
- seekToTimeMs_ = timeInMs;\r
- return DoSeekIfNeed();\r
-}\r
-\r
-int32_t PlayerControl::DoGetFileInfo(FormatFileInfo &fileInfo) const\r
-{\r
- return memcpy_s(&fileInfo, sizeof(FormatFileInfo), &fmtFileInfo_, sizeof(fmtFileInfo_));\r
-}\r
-\r
-int32_t PlayerControl::DoSetMedia(const PlayerControlStreamAttr &mediaAttr)\r
-{\r
- CHECK_NULL_RETURN(playerSource_, HI_ERR_PLAYERCONTROL_NULL_PTR, "playerSource_ nullptr");\r
-\r
- int32_t ret = HI_SUCCESS;\r
- if (hasVideo_) {\r
- ret = playerSource_->SelectTrack(0, mediaAttr.s32VidStreamId);\r
- CHECK_FAILED_RETURN(ret, 0, HI_ERR_PLAYERCONTROL_DEMUX_ERROR, "select video track failed");\r
- }\r
- if (hasAudio_) {\r
- ret = playerSource_->SelectTrack(0, mediaAttr.s32AudStreamId);\r
- CHECK_FAILED_RETURN(ret, 0, HI_ERR_PLAYERCONTROL_DEMUX_ERROR, "select audio track failed");\r
- }\r
-\r
- fmtFileInfo_.s32UsedVideoStreamIndex = mediaAttr.s32VidStreamId;\r
- fmtFileInfo_.s32UsedAudioStreamIndex = mediaAttr.s32AudStreamId;\r
-\r
- hasAudio_ = (fmtFileInfo_.s32UsedAudioStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) ? true : false;\r
- hasVideo_ = (fmtFileInfo_.s32UsedVideoStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) ? true : false;\r
-\r
- return ret;\r
-}\r
-\r
-int32_t PlayerControl::DoSetPlaybackSpeed(float speed) const\r
-{\r
- MediaMutexLock(schMutex_);\r
- int ret = sinkManager_->SetSpeed(speed);\r
- if (ret != HI_SUCCESS) {\r
- MEDIA_ERR_LOG("DoSetPlaybackSpeed failed:%d", ret);\r
- }\r
- MediaMutexUnLock(schMutex_);\r
- return HI_SUCCESS;\r
-}\r
-\r
-void PlayerControl::RecordLastPosition()\r
-{\r
- sinkManager_->RecordLastPosition();\r
-}\r
-\r
-// util bigein\r
-void PlayerControl::EventCallback(PlayerControlEvent event, const void *data) const\r
-{\r
- CHECK_NULL_RETURN_NONE(eventCallback_.callbackFun, "callbackFun nullptr");\r
- eventCallback_.callbackFun(eventCallback_.player, event, data);\r
-}\r
-\r
-void PlayerControl::PlayerControlCondSignal(void)\r
-{\r
- if (fmtFileInfo_.s32UsedVideoStreamIndex < 0) {\r
- MediaThreadCondSignal(schCond_);\r
- }\r
-}\r
-\r
-void PlayerControl::EnableSingleLooping(bool loop)\r
-{\r
- MediaMutexLock(schMutex_);\r
- loop_ = loop;\r
- MediaMutexUnLock(schMutex_);\r
-}\r
-\r
-int32_t PlayerControl::SetParam(const std::string &key, const void *value, uint32_t len)\r
-{\r
- CHECK_NULL_RETURN(sinkManager_, HI_ERR_PLAYERCONTROL_NULL_PTR, "sinkManager_ nullptr");\r
- MediaMutexLock(schMutex_);\r
- int32_t ret = sinkManager_->SetParam(key, DATA_TYPE_STRING, value, len);\r
- if (ret != HI_SUCCESS) {\r
- MediaMutexUnLock(schMutex_);\r
- return ret;\r
- }\r
- MediaMutexUnLock(schMutex_);\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::GetParam(const std::string &key, void *value, uint32_t size)\r
-{\r
- CHECK_NULL_RETURN(sinkManager_, HI_ERR_PLAYERCONTROL_NULL_PTR, "sinkManager_ nullptr");\r
- MediaMutexLock(schMutex_);\r
- int32_t ret = sinkManager_->GetParam(key, DATA_TYPE_PTR, value, size);\r
- if (ret != HI_SUCCESS) {\r
- MediaMutexUnLock(schMutex_);\r
- return ret;\r
- }\r
- MediaMutexUnLock(schMutex_);\r
- return HI_SUCCESS;\r
-}\r
-\r
-void PlayerControl::NotifyError(PlayerControlError playerError) const\r
-{\r
- EventCallback(PLAYERCONTROL_EVENT_ERROR, static_cast<void *>(&playerError));\r
-}\r
-\r
-void PlayerControl::StateChangeCallback(PlayerStatus state) const\r
-{\r
- EventCallback(PLAYERCONTROL_EVENT_STATE_CHANGED, static_cast<void *>(&state));\r
-}\r
-\r
-void PlayerControl::FlushDecoder(void) const\r
-{\r
-#ifndef UNSUPPORT_AUDIO_DECODER\r
- ReleaseADecoderOutputFrame();\r
- if (audioDecoder_ != nullptr) {\r
- audioDecoder_->FlushDec();\r
- }\r
-#endif\r
-\r
-#if !defined(UNSUPPORT_VIDEO_DECODER)\r
- ReleaseVDecoderOutputFrame();\r
- if (videoDecoder_ != nullptr) {\r
- videoDecoder_->FlushDec();\r
- }\r
-#endif\r
-}\r
-\r
-int32_t PlayerControl::DecoderAndSinkReset(void)\r
-{\r
- if (strmReadEnd_ && loop_) {\r
- return HI_SUCCESS;\r
- }\r
- int32_t ret;\r
- bool isNeedResume = false;\r
- ret = sinkManager_->Pause();\r
- if ((ret == HI_SUCCESS) && (!paused_)) {\r
- isNeedResume = true;\r
- }\r
- ret = sinkManager_->Reset();\r
- if (ret != HI_SUCCESS) {\r
- MEDIA_ERR_LOG("m_render reset failed");\r
- (void)sinkManager_->Resume();\r
- return ret;\r
- }\r
- FlushDecoder();\r
- if (isNeedResume) {\r
- ret = sinkManager_->Resume();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, HI_FAILURE, "sinkManager_ Resume failed");\r
- }\r
- return HI_SUCCESS;\r
-}\r
-\r
-int32_t PlayerControl::AyncSeek(int64_t seekTime)\r
-{\r
- CHECK_NULL_RETURN(playerSource_, HI_FAILURE, "playerSource_ nullptr");\r
- int64_t seekTimeInMs = seekTime;\r
- int32_t ret = 0;\r
- ClearCachePacket();\r
- if (fmtFileInfo_.s32UsedVideoStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) {\r
- ret = playerSource_->Seek(fmtFileInfo_.s32UsedVideoStreamIndex, seekTimeInMs, FORMAT_SEEK_MODE_BACKWARD_KEY);\r
- if (ret != HI_SUCCESS) {\r
- MEDIA_INFO_LOG("exec fmt_seek video stream failed, ret:%d", ret);\r
- seekTimeInMs = currentPosition_;\r
- }\r
- }\r
- if (fmtFileInfo_.s32UsedAudioStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) {\r
- ret = playerSource_->Seek(fmtFileInfo_.s32UsedAudioStreamIndex, seekTimeInMs, FORMAT_SEEK_MODE_BACKWARD_KEY);\r
- if (ret != HI_SUCCESS) {\r
- MEDIA_INFO_LOG("exec fmt_seek audio stream failed, ret:%d", ret);\r
- seekTimeInMs = currentPosition_;\r
- }\r
- }\r
- currentPosition_ = seekTimeInMs;\r
- EventCallback(PLAYERCONTROL_EVENT_PROGRESS, ¤tPosition_);\r
- EventCallback(PLAYERCONTROL_EVENT_SEEK_END, static_cast<void *>(&seekTimeInMs));\r
- return HI_SUCCESS;\r
-}\r
-\r
-void PlayerControl::GetPlayElementEventCallBack(PlayEventCallback &callback)\r
-{\r
- callback.onEventCallback = PlayerControlOnEvent;\r
- callback.priv = static_cast<void *>(this);\r
-}\r
-int32_t PlayerControl::SyncPrepare()\r
-{\r
- int ret;\r
- playerSource_ = std::make_shared<PlayerSource>();\r
- CHECK_NULL_RETURN(playerSource_, HI_FAILURE, "new playerSource_ nullptr");\r
- playerSource_->Init();\r
-\r
- if (sourceType_ == SOURCE_TYPE_FD) {\r
- playerSource_->SetSource(fd_, offset_);\r
- } else if (sourceType_ == SOURCE_TYPE_STREAM) {\r
- playerSource_->SetSource(streamSource_);\r
- } else {\r
- playerSource_->SetSource(filePath_.c_str());\r
- }\r
-\r
- PlayEventCallback callback;\r
- GetPlayElementEventCallBack(callback);\r
- ret = playerSource_->SetCallBack(callback);\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SetCallBack failed");\r
-\r
- ret = playerSource_->Prepare();\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "Prepare failed");\r
- ret = playerSource_->GetFileInfo(fmtFileInfo_);\r
- CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "GetFileInfo failed");\r
- metaData_.key = KEY_TYPE_EXTRADATA;\r
- ret = playerSource_->GetParam(0, metaData_);\r
- if (ret != HI_SUCCESS) {\r
- MEDIA_INFO_LOG("no extradata metadata");\r
- metaData_.key = 0;\r
- }\r
-\r
- hasAudio_ = (fmtFileInfo_.s32UsedAudioStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) ? true : false;\r
- hasVideo_ = (fmtFileInfo_.s32UsedVideoStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) ? true : false;\r
-\r
- MEDIA_INFO_LOG("used audiostream index %d", fmtFileInfo_.s32UsedAudioStreamIndex);\r
- MEDIA_INFO_LOG("used videostream index %d", fmtFileInfo_.s32UsedVideoStreamIndex);\r
-\r
- return HI_SUCCESS;\r
-}\r
-\r
-bool PlayerControl::IsPlayEos() const\r
-{\r
- bool isEos = false;\r
- if (hasAudio_) {\r
- if (hasVideo_) {\r
- return (!isAudioStarted_ || hasRenderAudioEos_) && (!isVideoStarted_ || hasRenderVideoEos_);\r
- } else {\r
- return (!isAudioStarted_ || hasRenderAudioEos_);\r
- }\r
- } else {\r
- if (hasVideo_) {\r
- return (!isVideoStarted_ || hasRenderVideoEos_);\r
- } else {\r
- MEDIA_ERR_LOG("neither audio nor video");\r
- isEos = false;\r
- }\r
- }\r
-\r
- return isEos;\r
-}\r
-\r
-int32_t PlayerControl::Invoke(PlayerInvoke invokeId, const void *param)\r
-{\r
- MsgInfo msg = {};\r
- InvokeParameter invokeParam;\r
- invokeParam.id = invokeId;\r
- invokeParam.param = param;\r
-\r
- msg.what = PLAYERCONTROL_MSG_INVOKE;\r
- msg.msgData = &invokeParam;\r
- msg.msgDataLen = sizeof(InvokeParameter);\r
- return OnMessageReceived(msg);\r
-}\r
-\r
-int32_t PlayerControl::DoInvoke(const InvokeParameter &invokeParam)\r
-{\r
- switch (invokeParam.id) {\r
- case INVOKE_ENABLE_PAUSE_AFTER_PLAYER:\r
- if (invokeParam.param == nullptr) {\r
- return -1;\r
- }\r
- break;\r
-\r
- case INVOKE_SET_AUDIO_SESSION:\r
- if (invokeParam.param == nullptr) {\r
- return -1;\r
- }\r
- audioSession_ = *(static_cast<const uint32_t *>(invokeParam.param));\r
- MEDIA_INFO_LOG("audio sessionId: %d", audioSession_);\r
- break;\r
-\r
- case INVOKE_SET_OUTPUT_DEVICE:\r
- if (invokeParam.param == nullptr) {\r
- return -1;\r
- }\r
- outDeviceId_ = *(static_cast<const uint32_t *>(invokeParam.param));\r
- MEDIA_INFO_LOG("outputDevice: 0x%x", outDeviceId_);\r
- if (sinkManager_ != nullptr) {\r
- return sinkManager_->SetOutputDevice(outDeviceId_);\r
- }\r
- break;\r
-\r
- case INVOKE_SET_AUDIOSTREAM_TYPE:\r
- if (invokeParam.param == nullptr) {\r
- return -1;\r
- }\r
- streamType_ = *(static_cast<const uint32_t *>(invokeParam.param));\r
- MEDIA_INFO_LOG("streamType: 0x%x", streamType_);\r
- break;\r
- default:\r
- MEDIA_ERR_LOG("unsupport invoke: 0x%x", invokeParam.id);\r
- return -1;\r
- }\r
- return 0;\r
-}\r
-\r
-int PlayerControl::HandleMsgWithParam(const MsgInfo &msgInfo)\r
-{\r
- int32_t ret;\r
- if (msgInfo.msgData == nullptr) {\r
- MEDIA_ERR_LOG("data is null, msg:%d", msgInfo.what);\r
- return HI_ERR_PLAYERCONTROL_NULL_PTR;\r
- }\r
- switch (msgInfo.what) {\r
- case PLAYERCONTROL_MSG_REGCALLBACK:\r
- ret = DoRegCallback(*static_cast<PlayerCtrlCallbackParam *>(msgInfo.msgData));\r
- break;\r
- case PLAYERCONTROL_MSG_SET_DATASOURCE_URI:\r
- ret = DoSetDataSource(static_cast<const char *>(msgInfo.msgData));\r
- break;\r
- case PLAYERCONTROL_MSG_SET_DATASOURCE_FD:\r
- ret = DoSetDataSource(*static_cast<SourceFdParam *>(msgInfo.msgData));\r
- break;\r
- case PLAYERCONTROL_MSG_SET_DATASOURCE_STREAM:\r
- ret = DoSetDataSource(*static_cast<StreamSourceParam *>(msgInfo.msgData));\r
- break;\r
- case PLAYERCONTROL_MSG_SETATTR:\r
- ret = DoSetMedia(*static_cast<PlayerControlStreamAttr *>(msgInfo.msgData));\r
- break;\r
- case PLAYERCONTROL_MSG_SETSPEED:\r
- ret = DoSetPlaybackSpeed(*static_cast<const float *>(msgInfo.msgData));\r
- break;\r
- case PLAYERCONTROL_MSG_SET_VOLUME:\r
- ret = DoSetVolume(*static_cast<VolumeAttr *>(msgInfo.msgData));\r
- break;\r
- case PLAYERCONTROL_MSG_SEEK:\r
- ret = DoSeek(*static_cast<int64_t *>(msgInfo.msgData));\r
- break;\r
- case PLAYERCONTROL_MSG_GETFILEINFO:\r
- ret = DoGetFileInfo(*static_cast<FormatFileInfo *>(msgInfo.msgData));\r
- break;\r
- case PLAYERCONTROL_MSG_INVOKE:\r
- ret = DoInvoke(*static_cast<InvokeParameter *>(msgInfo.msgData));\r
- break;\r
- default:\r
- ret = HI_ERR_PLAYERCONTROL_ILLEGAL_PARAM;\r
- break;\r
- }\r
-\r
- return ret;\r
-}\r
-\r
-int PlayerControl::HandleMsgWithNoParam(const MsgInfo &msgInfo)\r
-{\r
- int32_t ret;\r
- switch (msgInfo.what) {\r
- case PLAYERCONTROL_MSG_PREPARE:\r
- ret = DoPrepare();\r
- break;\r
- case PLAYERCONTROL_MSG_PLAY:\r
- ret = DoPlay();\r
- break;\r
- case PLAYERCONTROL_MSG_PAUSE:\r
- ret = DoPause();\r
- break;\r
- case PLAYERCONTROL_MSG_STOP:\r
- ret = DoStop();\r
- break;\r
- case PLAYERCONTROL_MSG_HANDLEDATA:\r
- ret = HI_SUCCESS;\r
- break;\r
- default:\r
- ret = HI_ERR_PLAYERCONTROL_ILLEGAL_PARAM;\r
- break;\r
- }\r
-\r
- return ret;\r
-}\r
-\r
-int PlayerControl::HandleMessage(const MsgInfo &msgInfo)\r
-{\r
- int32_t ret = HI_FAILURE;\r
- if (!EventValidAtCurState(static_cast<PlayerControlMsgType>(msgInfo.what))) {\r
- MEDIA_ERR_LOG("invalid event :%d at current state: %d", msgInfo.what, GetCurState());\r
- return HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION;\r
- }\r
-\r
- switch (msgInfo.what) {\r
- case PLAYERCONTROL_MSG_REGCALLBACK:\r
- case PLAYERCONTROL_MSG_SET_DATASOURCE_URI:\r
- case PLAYERCONTROL_MSG_SET_DATASOURCE_FD:\r
- case PLAYERCONTROL_MSG_SET_DATASOURCE_STREAM:\r
- case PLAYERCONTROL_MSG_SETATTR:\r
- case PLAYERCONTROL_MSG_SETSPEED:\r
- case PLAYERCONTROL_MSG_SET_VOLUME:\r
- case PLAYERCONTROL_MSG_SEEK:\r
- case PLAYERCONTROL_MSG_GETFILEINFO:\r
- case PLAYERCONTROL_MSG_INVOKE:\r
- ret = HandleMsgWithParam(msgInfo);\r
- break;\r
- case PLAYERCONTROL_MSG_PAUSE:\r
- case PLAYERCONTROL_MSG_PREPARE:\r
- case PLAYERCONTROL_MSG_PLAY:\r
- case PLAYERCONTROL_MSG_HANDLEDATA:\r
- case PLAYERCONTROL_MSG_STOP:\r
- ret = HandleMsgWithNoParam(msgInfo);\r
- break;\r
- default:\r
- break;\r
- }\r
- return ret;\r
-}\r
-\r
-void PlayerControl::OnEventHandled(int event, int result) const\r
-{\r
- if ((result == HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION) && (event == PLAYERCONTROL_MSG_SEEK)) {\r
- NotifyError(PLAYERCONTROL_ERROR_ILLEGAL_STATEACTION);\r
- }\r
-}\r
-\r
-int32_t PlayerControl::OnMessageReceived(const MsgInfo &msg)\r
-{\r
- int32_t ret = HandleMessage(msg);\r
- if (ret == HI_SUCCESS) {\r
- PlayerStatus nextState = FindTransition(GetCurState(), msg.what);\r
- curState_ = nextState;\r
- StateChangeCallback(curState_);\r
- }\r
- OnEventHandled(msg.what, ret);\r
- return ret;\r
-}\r
-\r
-PlayerStatus PlayerControl::GetCurState(void)\r
-{\r
- return curState_;\r
-}\r
-\r
-PlayerStatus PlayerControl::FindTransition(PlayerStatus state, int32_t event) const\r
-{\r
- for (uint32_t i = 0; i < STATE_TRANS_STATE_SIZE; i++) {\r
- if (event == STATE_MACHINE[state][i].msgType) {\r
- return STATE_MACHINE[state][i].newState;\r
- }\r
- }\r
- return state;\r
-}\r
-\r
-bool PlayerControl::EventValidAtCurState(PlayerControlMsgType type)\r
-{\r
- if (type < PLAYERCONTROL_MSG_SETATTR || type >= PLAYERCONTROL_MSG_BUTT) {\r
- MEDIA_ERR_LOG("EventValidAtCurState MSG type not support %d", type);\r
- return false;\r
- }\r
- if (GetCurState() < 0 || GetCurState() >= PLAY_STATUS_BUTT) {\r
- MEDIA_ERR_LOG("EventValidAtCurState cur state not support %d", GetCurState());\r
- return false;\r
- }\r
- return LITEPLAY_STATE[type][GetCurState()];\r
-}\r
-bool PlayerControl::UIntMulIsOverflow64(uint64_t a, uint64_t b, uint64_t *value) const\r
-{\r
- if (a == 0 || b == 0) {\r
- return false;\r
- }\r
- if (UINT64_MAX / a < b) {\r
- return true;\r
- }\r
-\r
- uint64_t result = static_cast<uint64_t>((a) * (b));\r
- if (value != nullptr) {\r
- *value = result;\r
- }\r
- return false;\r
-}\r
-bool PlayerControl::UIntMulIsOverflow32(uint32_t a, uint32_t b, uint32_t *value) const\r
-{\r
- if (a == 0 || b == 0) {\r
- return false;\r
- }\r
- if (UINT32_MAX / a < b) {\r
- return true;\r
- }\r
-\r
- long long result = static_cast<long long>((a) * (b));\r
- if (value != nullptr) {\r
- *value = static_cast<uint32_t>(result);\r
- }\r
- return false;\r
-}\r
-}\r
-}\r
+/*
+ * Copyright (c) 2020-2023 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "liteplayer.h"
+
+#ifdef SUPPORT_SYS_PRCTL
+#include <sys/prctl.h>
+#endif
+#include <unistd.h>
+#include "player_check.h"
+#include "hi_liteplayer_err.h"
+#include "liteplayer_comm.h"
+#if !defined(UNSUPPORT_AUDIO_DECODER) || !defined(UNSUPPORT_VIDEO_DECODER)
+#include "decoder.h"
+#endif
+
+#if !defined(UNSUPPORT_AUDIO_DECODER) || !defined(UNSUPPORT_VIDEO_DECODER)
+using OHOS::Media::Decoder;
+#endif
+using OHOS::Media::PlayerSource;
+using OHOS::Media::SinkManager;
+
+namespace OHOS {
+namespace Media {
+/* DEFAULT_VID_BUFSIZE: 2 * 1024 * 1024 */
+const uint32_t DEFAULT_VID_BUFSIZE = 2097152;
+/* DEFAULT_AUD_BUFSIZE: 256 * 1024 */
+const uint32_t DEFAULT_AUD_BUFSIZE = 262144;
+
+const uint32_t GET_BUFFER_TIMEOUT_MS = 0u;
+const uint32_t RENDER_FULL_SLEEP_TIME_US = 10000u;
+// 1. waiting app response playback complete callback event
+// 2. waiting interval time for loop playback
+const uint32_t RENDER_EOS_SLEEP_TIME_US = 3000000u;
+const uint32_t WAIT_BUFFER_EMPTY_SLEEP_TIME_US = 1000000u;
+const uint32_t DECODER_DEFAULT_WIDTH = 1920;
+const uint32_t DECODER_DEFAULT_HEIGHT = 1080;
+const uint32_t QUEUE_BUFFER_FULL_SLEEP_TIME_US = 10000u;
+const uint32_t NO_DATA_READ_SLEEP_TIME_US = 5000u;
+const uint32_t MAX_EVENT_MESSAGE_NUM = 128;
+const uint32_t MAX_THREAD_STACK_SIZE = 0x1800u;
+const uint32_t REQUEST_BUFFER_RETRY_WAIT_TIME_US = 10000u;
+const float YCBCR420SP_BUFFER_SIZE_COEFFICIENT = 1.5;
+#ifdef DEBUG_LOW_POWER
+const uint32_t RENDER_FULL_SLEEP_THRESHOLD_MS_MP3_AACLC_OPUS = 5;
+const uint32_t RENDER_FULL_SLEEP_THRESHOLD_MS_PCM = 25;
+const uint32_t RENDER_FULL_SLEEP_THRESHOLD_MS_FLAC = 50;
+#endif
+// In a single-process system, only one thread can work at a time.
+// Subthreads need to give CPU resources to the main thread to switch to the playback state.
+const uint32_t WAIT_MAIN_THREAD_SWITCH_TO_PLAY_STATUS_TIME_US = 10000u;
+// maximum number of consecutive surface buffer request failures retries(converted to time: 100 * 10ms = 1s)
+const uint32_t MAX_CONTINOUS_REQUEST_SURFACE_BUFFER_FAIL_COUNT = 100;
+
+static AudioCodecFormat g_fromCodecFormatToAudioManager[CODEC_BUT + 1] = {
+ FORMAT_INVALID, FORMAT_INVALID, FORMAT_INVALID, FORMAT_INVALID,
+ AAC_LC, G711A, G711U, PCM, MP3, G726, OPUS, FLAC, VORBIS, APE, SILK, SBC, FORMAT_INVALID
+};
+static EsFrameType g_fromDemuxTypeToSinkType[FRAME_TYPE_BUT + 1] = {
+ ESFRAME_TYPE_NONE, ESFRAME_TYPE_AUDIO, ESFRAME_TYPE_VIDEO, ESFRAME_TYPE_IMAGE, ESFRAME_TYPE_SUB,
+ ESFRAME_TYPE_DATA, ESFRAME_INVALID_TYPE
+};
+
+static CodecFormatAndMimePair g_avCodecFormatInfo[CODEC_BUT + 1] = {
+ { CODEC_H264, MEDIA_MIMETYPE_VIDEO_AVC },
+ { CODEC_H265, MEDIA_MIMETYPE_VIDEO_HEVC },
+ { CODEC_JPEG, MEDIA_MIMETYPE_IMAGE_JPEG },
+ { CODEC_MJPEG, MEDIA_MIMETYPE_IMAGE_MJPEG },
+ { CODEC_AAC, MEDIA_MIMETYPE_AUDIO_AAC },
+ { CODEC_G711A, MEDIA_MIMETYPE_AUDIO_G711A },
+ { CODEC_G711U, MEDIA_MIMETYPE_AUDIO_G711U },
+ { CODEC_PCM, MEDIA_MIMETYPE_AUDIO_PCM },
+ { CODEC_MP3, MEDIA_MIMETYPE_AUDIO_MP3 },
+ { CODEC_G726, MEDIA_MIMETYPE_AUDIO_G726 },
+ { CODEC_BUT, MEDIA_MIMETYPE_INVALID },
+};
+
+namespace {
+/* playing position notify interval in ms */
+const uint32_t DEFAULT_POS_NOFITY_INTERVAL = 300;
+}
+
+#ifdef DEBUG_LOW_POWER
+const int32_t US_2_MS = 1000;
+#endif
+
+void PlayerControl::RecordTime(struct timeval &timeStart)
+{
+ gettimeofday(&timeStart, nullptr);
+}
+
+uint64_t PlayerControl::CalcTimeDiffUsPrint(const struct timeval &timeStart, struct timeval &timeEnd,
+ std::string outString, bool showlog)
+{
+ gettimeofday(&timeEnd, nullptr);
+ const uint64_t timeUs = 1000000;
+ uint64_t diffSecToUs = 0;
+ bool isOverflow =
+ UIntMulIsOverflow64(static_cast<uint64_t>(timeEnd.tv_sec - timeStart.tv_sec), timeUs, &diffSecToUs);
+ if (isOverflow) {
+ MEDIA_ERR_LOG("PlayerControl::CalcTimeDiffUsPrint calculate reslut overflow!");
+ return INVALID_TIME;
+ }
+ uint64_t diffUsec = static_cast<uint64_t>(timeEnd.tv_usec - timeStart.tv_usec);
+ uint64_t diffTimeUS = diffSecToUs + diffUsec;
+ if (showlog) {
+ MEDIA_INFO_LOG("%s elapsed time: %lld us", outString.c_str(), diffTimeUS);
+ }
+ return diffTimeUS;
+}
+
+int32_t PlayerControl::GetPlayerControlDumpInfo(PlayerControlDebugInfo &playerControlInfo)
+{
+ playerControlInfo.currentPosition = currentPosition_;
+ playerControlInfo.hasRenderAudioEos = hasRenderAudioEos_;
+ playerControlInfo.hasRenderVideoEos = hasRenderVideoEos_;
+ playerControlInfo.isAudioStarted = isAudioStarted_;
+ playerControlInfo.isVideoStarted = isVideoStarted_;
+ playerControlInfo.offloadAudio = offloadAudio_;
+ playerControlInfo.outDevice = outDeviceId_;
+ playerControlInfo.sessionId = audioSession_;
+ return 0;
+}
+
+int32_t PlayerControl::GetPlayerVideoDumpInfo(PlayerVideoDebugInfo &videoDebugInfo)
+{
+ videoDebugInfo.frameBufCnt = vdecAttr_.frameBufCnt;
+ videoDebugInfo.u32Height = vdecAttr_.maxHeight;
+ videoDebugInfo.u32Width = vdecAttr_.maxWidth;
+ videoDebugInfo.enVideoType = vdecAttr_.type;
+ return 0;
+}
+
+int32_t PlayerControl::GetPlayerAudioDumpInfo(PlayerAudioDebugInfo &audioDebugInfo)
+{
+ audioDebugInfo.bitWidth = adecAttr_.bitWidth;
+ audioDebugInfo.enAudioType = adecAttr_.type;
+ return 0;
+}
+
+int32_t PlayerControl::GetPlayerFileDumpInfo(PlayerFileDebugInfo &fileDebugInfo)
+{
+ fileDebugInfo.filePath = filePath_;
+ fileDebugInfo.fd = fd_;
+ fileDebugInfo.offset = offset_;
+ return 0;
+}
+
+void PlayerControl::PrintKpiTime()
+{
+#ifdef PLAYER_KPI_ON
+ if (!recordFirstFrameCost_ && currentPosition_ >= 0) {
+ std::string startPlay("KPI_PlayNewFileTime");
+ CalcTimeDiffUsPrint(startPlayStartTime_, startPlayEndTime_, startPlay, KPI_PRINT);
+ recordFirstFrameCost_ = true;
+ }
+#endif
+}
+
+PlayerControl::PlayerControl()
+ : isInited_(false),
+ isPlayEnd_(false),
+ isAudPlayEos_(false),
+ cachedPacket_(false),
+ lastRendPos_(0),
+ lastNotifyTime_(0),
+ lastReadPktStrmIdx_(-1),
+ lastReadPktPts_(0),
+ lastSendPktPts_(0),
+ isVideoStarted_(false),
+ isAudioStarted_(false),
+ strmReadEnd_(false),
+ isPlayErr_(false),
+ lastSendAdecPts_(AV_INVALID_PTS),
+ currentPosition_(0),
+ paused_(false),
+ schThreadExit_(false),
+ loop_(false),
+ hasRenderAudioEos_(false),
+ hasRenderVideoEos_(false),
+ renderSleepTime_(0),
+ leftVolume_(-1.0f),
+ rightVolume_(-1.0f),
+ schMutex_(nullptr),
+ schCond_(nullptr),
+ schProcess_(nullptr),
+ seekToTimeMs_(-1),
+ sourceType_(SOURCE_TYPE_BUT),
+ firstAudioFrameAfterSeek_(false),
+ firstPosAfterSeek_(0),
+ fd_(-1),
+ offset_(0),
+ playerSource_(nullptr),
+ sinkManager_(nullptr),
+ surface_(nullptr),
+ surfaceBuf_(nullptr),
+ curState_(PLAY_STATUS_IDLE),
+ offloadAudio_(false),
+ audioSession_(0),
+ streamType_(AUDIO_STREAM_MUSIC),
+ recordFirstFrameCost_(false),
+ renderEsTotalTime_(0),
+ readPktTotalTime_(0),
+ renderEsFrameCnt_(0),
+ readPacketCnt_(0),
+ outDeviceId_(OUT_BUILTIN_SPEAKER),
+ headInSendSuccessInterval_(-1),
+ tailInSendSuccessInterval_(-1),
+ hasAudio_(false),
+ hasVideo_(false),
+ isAudio_(false),
+ isVideo_(false)
+{
+ eventCallback_.player = nullptr;
+ eventCallback_.callbackFun = nullptr;
+ if (memset_s(&fmtFileInfo_, sizeof(fmtFileInfo_), 0, sizeof(FormatFileInfo)) != EOK) {
+ MEDIA_ERR_LOG("memset_s failed");
+ }
+ fmtFileInfo_.s32UsedAudioStreamIndex = HI_DEMUXER_NO_MEDIA_STREAM;
+ fmtFileInfo_.s32UsedVideoStreamIndex = HI_DEMUXER_NO_MEDIA_STREAM;
+ playerParam_.u32PlayPosNotifyIntervalMs = DEFAULT_POS_NOFITY_INTERVAL;
+ playerParam_.u32VideoEsBufSize = DEFAULT_POS_NOFITY_INTERVAL;
+ playerParam_.u32AudioEsBufSize = DEFAULT_POS_NOFITY_INTERVAL;
+ playerParam_.u32VdecFrameBufCnt = DEFAULT_POS_NOFITY_INTERVAL;
+ if (memset_s(&formatPacket_, sizeof(formatPacket_), 0, sizeof(FormatFrame)) != EOK) {
+ MEDIA_ERR_LOG("memset_s failed");
+ }
+ streamAttr_.videoBufSize = 0;
+ streamAttr_.audioBufSize = 0;
+ adecAttr_.type = 0;
+ adecAttr_.sampleRate = 0;
+ adecAttr_.channel = 0;
+ adecAttr_.bitWidth = 0;
+ streamSource_.param.sampleRate = 0;
+ streamSource_.param.sampleFormat = 0;
+ streamSource_.param.channelCount = 0;
+ streamSource_.param.channelLayout = 0;
+ streamSource_.stream.ReadData = nullptr;
+ streamSource_.stream.GetReadableSize = nullptr;
+ streamSource_.stream.handle = nullptr;
+ eventQueue_.clear();
+ startPlayStartTime_.tv_sec = 0;
+ startPlayStartTime_.tv_usec = 0;
+ startPlayEndTime_.tv_sec = 0;
+ startPlayEndTime_.tv_usec = 0;
+ streamEndTime_.tv_sec = 0;
+ streamEndTime_.tv_usec = 0;
+ metaData_.key = 0;
+ metaData_.size = 0;
+#if !defined(UNSUPPORT_AUDIO_DECODER)
+ audioDecoder_ = nullptr;
+#endif
+#if !defined(UNSUPPORT_VIDEO_DECODER)
+ videoDecoder_ = nullptr;
+#endif
+}
+
+PlayerControl::~PlayerControl()
+{
+ (void)Deinit();
+ eventQueue_.clear();
+}
+
+int32_t PlayerControl::InitAttr(const PlayerControlParam &createParam)
+{
+ if (memset_s(&fmtFileInfo_, sizeof(fmtFileInfo_), 0x00, sizeof(FormatFileInfo)) != EOK) {
+ MEDIA_ERR_LOG("memset_s failed");
+ return HI_ERR_PLAYERCONTROL_MEM_SET;
+ }
+ fmtFileInfo_.s32UsedAudioStreamIndex = HI_DEMUXER_NO_MEDIA_STREAM;
+ fmtFileInfo_.s32UsedVideoStreamIndex = HI_DEMUXER_NO_MEDIA_STREAM;
+ streamAttr_.playMode = RENDER_MODE_NORMAL;
+ streamAttr_.videoBufSize = DEFAULT_VID_BUFSIZE;
+ streamAttr_.audioBufSize = DEFAULT_AUD_BUFSIZE;
+
+ lastReadPktPts_ = 0;
+ lastSendPktPts_ = 0;
+ CHECK_FAILED_PRINT(memcpy_s(&playerParam_, sizeof(playerParam_), &createParam, sizeof(PlayerControlParam)), EOK,
+ "copy playerParam_ fail");
+ playerParam_.u32PlayPosNotifyIntervalMs = (createParam.u32PlayPosNotifyIntervalMs == 0) ?
+ DEFAULT_POS_NOFITY_INTERVAL :
+ createParam.u32PlayPosNotifyIntervalMs;
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::Init(const PlayerControlParam &createParam)
+{
+ MEDIA_INFO_LOG("Init in");
+ CHECK_TRUE_CONDITION_RETURN(isInited_, HI_SUCCESS, "already be inited");
+ CHECK_FAILED_RETURN(InitAttr(createParam), HI_SUCCESS, HI_FAILURE, "InitAttr failed");
+ schMutex_ = MediaMutexCreate(nullptr);
+ if (schMutex_ == nullptr) {
+ MEDIA_ERR_LOG("create mutex failed");
+ return HI_FAILURE;
+ }
+ schCond_ = MediaThreadCondCreate();
+ if (schCond_ == nullptr) {
+ MEDIA_ERR_LOG("create cond failed");
+ MediaMutexDestroy(&schMutex_);
+ return HI_FAILURE;
+ }
+ isInited_ = true;
+#ifdef PLAYER_KPI_ON
+ RecordTime(startPlayStartTime_);
+#endif
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::Deinit()
+{
+ if (!isInited_) {
+ return HI_SUCCESS;
+ }
+ DestroyDecoder();
+ MediaMutexDestroy(&schMutex_);
+ MediaThreadCondDestroy(&schCond_);
+ isInited_ = false;
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::RegCallback(PlayerCtrlCallbackParam &eventCallback)
+{
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_REGCALLBACK;
+ msg.msgData = static_cast<void *>(&eventCallback);
+ msg.msgDataLen = 0;
+ return OnMessageReceived(msg);
+}
+
+int32_t PlayerControl::SetDataSource(const std::string filepath)
+{
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_SET_DATASOURCE_URI;
+ msg.msgData = const_cast<void *>(static_cast<const void *>(filepath.c_str()));
+ msg.msgDataLen = 0;
+ return OnMessageReceived(msg);
+}
+
+int32_t PlayerControl::SetDataSource(SourceFdParam &fdSrc)
+{
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_SET_DATASOURCE_FD;
+ msg.msgData = static_cast<void *>(&fdSrc);
+ msg.msgDataLen = 0;
+ return OnMessageReceived(msg);
+}
+
+int32_t PlayerControl::SetDataSource(StreamSourceParam &streamSource)
+{
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_SET_DATASOURCE_STREAM;
+ msg.msgData = static_cast<void *>(&streamSource);
+ msg.msgDataLen = 0;
+ return OnMessageReceived(msg);
+}
+
+int32_t PlayerControl::Prepare()
+{
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_PREPARE;
+ return OnMessageReceived(msg);
+}
+
+int32_t PlayerControl::Play()
+{
+ int32_t ret;
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_PLAY;
+ ret = OnMessageReceived(msg);
+ CHECK_FAILED_PRINT(ret, HI_SUCCESS, "play failed");
+ return ret;
+}
+
+int32_t PlayerControl::SetVolume(const VolumeAttr &volumeAttr)
+{
+ VolumeAttr attr = volumeAttr;
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_SET_VOLUME;
+ msg.msgData = static_cast<void *>(&attr);
+ msg.msgDataLen = 0;
+ return OnMessageReceived(msg);
+}
+
+int32_t PlayerControl::Stop()
+{
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_STOP;
+ return OnMessageReceived(msg);
+}
+
+int32_t PlayerControl::Pause()
+{
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_PAUSE;
+ return OnMessageReceived(msg);
+}
+
+int32_t PlayerControl::Seek(int64_t timeInMs)
+{
+ if (fmtFileInfo_.enVideoType == CODEC_JPEG) {
+ MEDIA_ERR_LOG("seek action not support for play picture");
+ return HI_ERR_PLAYERCONTROL_NOT_SUPPORT;
+ }
+ if ((fmtFileInfo_.s64Duration > 0) && (fmtFileInfo_.s64Duration < timeInMs)) {
+ return HI_ERR_PLAYERCONTROL_ILLEGAL_PARAM;
+ }
+ seekToTimeMs_ = timeInMs;
+ MediaThreadCondSignal(schCond_);
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::GetFileInfo(FormatFileInfo &formatInfo)
+{
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_GETFILEINFO;
+ msg.msgData = &formatInfo;
+ msg.msgDataLen = sizeof(FormatFileInfo);
+ return OnMessageReceived(msg);
+}
+
+int32_t PlayerControl::SetMedia(PlayerControlStreamAttr &mediaAttr)
+{
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_SETATTR;
+ msg.msgData = &mediaAttr;
+ msg.msgDataLen = sizeof(PlayerControlStreamAttr);
+ return OnMessageReceived(msg);
+}
+
+#if defined(ENABLE_UIKIT)
+int32_t PlayerControl::SetSurface(Surface *surface)
+#elif defined(ENABLE_LVGL)
+int32_t PlayerControl::SetSurface(LvSurfaceView *surface)
+#endif
+{
+ surface_ = surface;
+ return 0;
+}
+
+int32_t PlayerControl::SetPlaybackSpeed(float speed)
+{
+ float setSpeed = speed;
+ MsgInfo msg = {};
+ msg.what = PLAYERCONTROL_MSG_SETSPEED;
+ msg.msgData = static_cast<void *>(&setSpeed);
+ msg.msgDataLen = 0;
+ return OnMessageReceived(msg);
+}
+
+void PlayerControl::ClearCachePacket()
+{
+ if (cachedPacket_) {
+ if (formatPacket_.data != nullptr) {
+ if (playerSource_ != nullptr && playerSource_->FreeFrame(formatPacket_) != 0) {
+ MEDIA_ERR_LOG("FreeFrame failed \n");
+ }
+ formatPacket_.data = nullptr;
+ formatPacket_.len = 0;
+ formatPacket_.trackId = -1;
+ }
+ /* end packet is null do not need to demux free */
+ cachedPacket_ = false;
+ }
+}
+
+void PlayerControl::OnVideoEndOfStream()
+{
+ if (!hasAudio_ && (lastSendVdecPts_ > AV_INVALID_PTS)) {
+ EventCallback(PLAYERCONTROL_EVENT_PROGRESS, &lastSendVdecPts_);
+ }
+ isVidPlayEos_ = true;
+ isPlayEnd_ = IsPlayEos() ? true : isPlayEnd_;
+}
+
+void PlayerControl::EventProcess(EventCbType event)
+{
+ PlayerControlError playerError;
+ MEDIA_DEBUG_LOG("handleEvent %d", event);
+ switch (event) {
+ case EVNET_VIDEO_PLAY_EOS:
+ OnVideoEndOfStream();
+ break;
+ case EVNET_VIDEO_PLAY_SOS:
+ MEDIA_INFO_LOG("video sos recv");
+ break;
+ case EVNET_AUDIO_PLAY_EOS:
+ isAudPlayEos_ = true;
+ isPlayEnd_ = IsPlayEos() ? true : isPlayEnd_;
+ if (lastSendAdecPts_ > AV_INVALID_PTS) {
+ EventCallback(PLAYERCONTROL_EVENT_PROGRESS, &lastSendAdecPts_);
+ }
+ break;
+ case EVNET_VIDEO_RUNNING_ERR:
+ case EVNET_AUDIO_RUNNING_ERR:
+ playerError = PLAYERCONTROL_ERROR_AUD_PLAY_FAIL;
+ isPlayErr_ = true;
+ EventCallback(PLAYERCONTROL_EVENT_ERROR, &playerError);
+ break;
+ default:
+ break;
+ }
+}
+
+void PlayerControl::EventQueueProcess(void)
+{
+ size_t queSize;
+ PalayControlEventItem *item = nullptr;
+
+ queSize = eventQueue_.size();
+ if (queSize > MAX_EVENT_MESSAGE_NUM) {
+ MEDIA_WARNING_LOG("mesaage except, num:%u", queSize);
+ }
+ for (size_t i = 0; i < queSize && i < MAX_EVENT_MESSAGE_NUM; i++) {
+ item = &eventQueue_[i];
+ EventProcess(item->event);
+ }
+ eventQueue_.clear();
+}
+
+int32_t PlayerControl::OnPlayControlEvent(void *priv, const EventCbType event) const
+{
+ // audio play eos event needs to be handled immediately
+ if (event == EVNET_AUDIO_PLAY_EOS) {
+ MEDIA_INFO_LOG("Received audio play eos event");
+ EventCallback(PLAYERCONTROL_EVENT_EOF, nullptr);
+ return HI_SUCCESS;
+ } else if (event == EVNET_AUDIO_BUFFER_EMPTY) {
+ EventCallback(PLAYERCONTROL_BUFFER_EMPTY, nullptr);
+ return HI_SUCCESS;
+ } else if (event == EVNET_OUTPUT_DEVICE_CHANGED) {
+ PlayerControl *player = static_cast<PlayerControl *>(priv);
+ player->RecordLastPosition();
+ return HI_SUCCESS;
+ } else if (event == EVNET_AUDIO_RUNNING_ERR ||
+ event == EVNET_VIDEO_RUNNING_ERR) {
+ PlayerControlError playerError = PLAYERCONTROL_ERROR_AUD_PLAY_FAIL;
+ EventCallback(PLAYERCONTROL_EVENT_ERROR, &playerError);
+ return HI_SUCCESS;
+ }
+
+ PalayControlEventItem item;
+ PlayerControl *player = static_cast<PlayerControl *>(priv);
+
+ item.event = event;
+ player->eventQueue_.push_back(item);
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::PauseResume(void)
+{
+ CHECK_NULL_RETURN(sinkManager_, HI_ERR_PLAYERCONTROL_NULL_PTR, "sinkManager_ nullptr");
+ MediaMutexLock(schMutex_);
+ int32_t ret = sinkManager_->Resume();
+ if (ret != HI_SUCCESS) {
+ if (ret != NOT_FOUND_ACTIVE_STREAME) {
+ MEDIA_ERR_LOG("resume failed");
+ hasVideo_ ? NotifyError(PLAYERCONTROL_ERROR_VID_PLAY_FAIL) : NotifyError(PLAYERCONTROL_ERROR_AUD_PLAY_FAIL);
+ }
+ MediaMutexUnLock(schMutex_);
+ return ret;
+ }
+ paused_ = false;
+ // played to the end no need to signal
+ if (!IsPlayEos()) {
+ MediaThreadCondSignal(schCond_);
+ }
+ MediaMutexUnLock(schMutex_);
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::CheckMediaInfo(void) const
+{
+ if (fmtFileInfo_.s32UsedAudioStreamIndex >= HI_DEMUXER_RESOLUTION_CNT ||
+ fmtFileInfo_.s32UsedVideoStreamIndex >= HI_DEMUXER_RESOLUTION_CNT) {
+ MEDIA_ERR_LOG("input file error video track: %d audio %d", fmtFileInfo_.s32UsedVideoStreamIndex,
+ fmtFileInfo_.s32UsedAudioStreamIndex);
+ return HI_ERR_PLAYERCONTROL_DEMUX_ERROR;
+ }
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::GetVideoResolution(int32_t streamIdx, StreamResolution &resolution)
+{
+ if (streamIdx == HI_DEMUXER_NO_MEDIA_STREAM) {
+ MEDIA_ERR_LOG("stream id [%d] in invalid", streamIdx);
+ return HI_FAILURE;
+ }
+
+ for (uint32_t i = 0; i < HI_DEMUXER_RESOLUTION_CNT; i++) {
+ if (fmtFileInfo_.stSteamResolution[i].s32VideoStreamIndex == streamIdx) {
+ resolution.enVideoType = fmtFileInfo_.stSteamResolution[i].enVideoType;
+ resolution.s32VideoStreamIndex = fmtFileInfo_.stSteamResolution[i].s32VideoStreamIndex;
+ resolution.u32Width = fmtFileInfo_.stSteamResolution[i].u32Width;
+ resolution.u32Height = fmtFileInfo_.stSteamResolution[i].u32Height;
+ return HI_SUCCESS;
+ }
+ }
+
+ MEDIA_ERR_LOG("not found stream[%d] in file", streamIdx);
+ return HI_FAILURE;
+}
+
+int32_t PlayerControl::SetVDecAttr(void)
+{
+ StreamResolution resolution = {};
+ if (GetVideoResolution(fmtFileInfo_.s32UsedVideoStreamIndex, resolution) != HI_SUCCESS) {
+ MEDIA_ERR_LOG("GetVideoResolution failed");
+ return HI_FAILURE;
+ }
+ vdecAttr_.maxWidth = resolution.u32Width;
+ vdecAttr_.maxHeight = resolution.u32Height;
+ vdecAttr_.type = resolution.enVideoType;
+ vdecAttr_.frameBufCnt = playerParam_.u32VdecFrameBufCnt;
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::SetADecAttr(void)
+{
+ adecAttr_.bitWidth = AUDIO_BITWIDTH;
+ adecAttr_.channel = fmtFileInfo_.u32AudioChannelCnt;
+ adecAttr_.sampleRate = fmtFileInfo_.u32SampleRate;
+ adecAttr_.type = fmtFileInfo_.enAudioType;
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::SetStreamAttr()
+{
+ if (hasVideo_) {
+ StreamResolution resolution = {};
+ if (GetVideoResolution(fmtFileInfo_.s32UsedVideoStreamIndex, resolution) != HI_SUCCESS) {
+ MEDIA_ERR_LOG("GetVideoResolution failed");
+ return HI_ERR_PLAYERCONTROL_ILLEGAL_PARAM;
+ }
+ streamAttr_.videoBufSize = playerParam_.u32VideoEsBufSize;
+ }
+
+ if (hasAudio_) {
+ streamAttr_.audioBufSize =
+ (playerParam_.u32AudioEsBufSize) ? (playerParam_.u32AudioEsBufSize) : streamAttr_.audioBufSize;
+ }
+
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::SetDecoderAndStreamAttr(void)
+{
+ int ret;
+
+ if (hasAudio_) {
+ ret = SetADecAttr();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SetADecAttr failed");
+ }
+
+ if (hasVideo_) {
+ ret = SetVDecAttr();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SetVDecAttr failed");
+ }
+
+ ret = SetStreamAttr();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SetStreamAttr failed");
+ return HI_SUCCESS;
+}
+
+#if !defined(UNSUPPORT_VIDEO_DECODER) || !defined(UNSUPPORT_AUDIO_DECODER)
+static AvCodecMime TransformCodecFormatToAvCodecMime(CodecFormat format)
+{
+ AvCodecMime mime = MEDIA_MIMETYPE_INVALID;
+ uint32_t size = sizeof(g_avCodecFormatInfo) / sizeof(CodecFormatAndMimePair);
+
+ for (uint32_t i = 0; i < size; i++) {
+ if (g_avCodecFormatInfo[i].format == format) {
+ mime = g_avCodecFormatInfo[i].mime;
+ break;
+ }
+ }
+
+ return mime;
+}
+#endif
+
+#ifndef UNSUPPORT_VIDEO_DECODER
+static void GetCurVideoSolution(const FormatFileInfo &info, uint32_t &width, uint32_t &height)
+{
+ for (int i = 0; i < HI_DEMUXER_RESOLUTION_CNT; i++) {
+ if (info.stSteamResolution[i].s32VideoStreamIndex == info.s32UsedVideoStreamIndex) {
+ width = info.stSteamResolution[i].u32Width;
+ height = info.stSteamResolution[i].u32Height;
+ break;
+ }
+ }
+}
+#endif
+
+#ifndef UNSUPPORT_AUDIO_DECODER
+static std::string GetAudioNameByAvCodecMime(AvCodecMime mime)
+{
+ std::string audioName = "codec.unknow.soft.decoder";
+ switch (mime) {
+ case MEDIA_MIMETYPE_AUDIO_AAC:
+ audioName = "codec.aac.soft.decoder";
+ break;
+ case MEDIA_MIMETYPE_AUDIO_MP3:
+ audioName = "codec.mp3.soft.decoder";
+ break;
+ default:
+ MEDIA_ERR_LOG("not support codec type:%d", mime);
+ break;
+ }
+ return audioName;
+}
+
+int32_t PlayerControl::AudioDecoderStart(void)
+{
+ AvCodecMime mime = TransformCodecFormatToAvCodecMime(fmtFileInfo_.enAudioType);
+ if (mime == MEDIA_MIMETYPE_INVALID) {
+ MEDIA_ERR_LOG("DecoderStart not support codec:%d", fmtFileInfo_.enAudioType);
+ return -1;
+ }
+ audioDecoder_ = std::make_shared<Decoder>();
+ CHECK_NULL_RETURN(audioDecoder_, -1, "new decoder failed");
+ AvAttribute attr;
+ attr.type = AUDIO_DECODER;
+ attr.adecAttr.mime = mime;
+ attr.adecAttr.priv = nullptr;
+ attr.adecAttr.bufSize = 0x400; /* 1024 */
+ attr.adecAttr.channelCnt = (mime == MEDIA_MIMETYPE_AUDIO_PCM) ? fmtFileInfo_.u32AudioChannelCnt : 0;
+ const std::string audioName = GetAudioNameByAvCodecMime(mime);
+ int32_t ret = audioDecoder_->CreateHandle(audioName, attr);
+ CHECK_FAILED_RETURN(ret, 0, -1, "create audio decoder failed");
+ ret = audioDecoder_->StartDec();
+ CHECK_FAILED_RETURN(ret, 0, -1, "start audio decoder failed");
+ MEDIA_INFO_LOG("audio decoder started");
+
+ return 0;
+}
+#endif
+
+#if !defined(UNSUPPORT_VIDEO_DECODER)
+int32_t PlayerControl::VideoDecoderStart(void)
+{
+ AvAttribute attr;
+ uint32_t width = DECODER_DEFAULT_WIDTH;
+ uint32_t height = DECODER_DEFAULT_HEIGHT;
+
+ AvCodecMime mime = TransformCodecFormatToAvCodecMime(fmtFileInfo_.enVideoType);
+ if (mime == MEDIA_MIMETYPE_INVALID) {
+ MEDIA_ERR_LOG("DecoderStart not support codec:%d", fmtFileInfo_.enVideoType);
+ return -1;
+ }
+ GetCurVideoSolution(fmtFileInfo_, width, height);
+
+ videoDecoder_ = std::make_shared<Decoder>();
+ CHECK_NULL_RETURN(videoDecoder_, -1, "new decoder failed");
+ attr.type = VIDEO_DECODER;
+ attr.vdecAttr.mime = mime;
+ attr.vdecAttr.priv = nullptr;
+ attr.vdecAttr.bufSize = 0;
+ attr.vdecAttr.maxWidth = width;
+ attr.vdecAttr.maxHeight = height;
+ const std::string videoName = "codec.avc.soft.decoder";
+ int32_t ret = videoDecoder_->CreateHandle(videoName, attr);
+ CHECK_FAILED_RETURN(ret, 0, -1, "create video decoder failed");
+ ret = videoDecoder_->StartDec();
+ CHECK_FAILED_RETURN(ret, 0, -1, "start video decoder failed");
+ MEDIA_INFO_LOG("video decoder started");
+
+ return 0;
+}
+#endif
+
+int32_t PlayerControl::DecoderStart(void)
+{
+ if (!hasAudio_ && !hasVideo_) {
+ MEDIA_ERR_LOG("not decoder need start");
+ return -1;
+ }
+
+ MEDIA_INFO_LOG("audio stream id: %d, video stream id: %d", fmtFileInfo_.s32UsedAudioStreamIndex,
+ fmtFileInfo_.s32UsedVideoStreamIndex);
+
+ /* if offload audio is false, need audio decoder, not support */
+ if (hasAudio_) {
+ if (!offloadAudio_) {
+ MEDIA_ERR_LOG("not support offload, need audio decoder, return failed");
+ return -1;
+ }
+ }
+
+ if (hasVideo_) {
+#if !defined(UNSUPPORT_VIDEO_DECODER)
+ if (VideoDecoderStart() != 0) {
+ return -1;
+ }
+#endif
+ }
+ return 0;
+}
+
+void PlayerControl::DestroyDecoder() const
+{
+#ifndef UNSUPPORT_AUDIO_DECODER
+ if (audioDecoder_ != nullptr) {
+ audioDecoder_->DestroyHandle();
+ }
+#endif
+#if !defined(UNSUPPORT_VIDEO_DECODER)
+ if (videoDecoder_ != nullptr) {
+ videoDecoder_->DestroyHandle();
+ }
+#endif
+}
+
+void PlayerControl::StopSinkAndDecoder()
+{
+ OutputInfo outInfo = {};
+ EsFrameInfo frameInfo = {};
+ if (sinkManager_ != nullptr) {
+ sinkManager_->Stop();
+#ifdef UNSUPPORT_AUDIO_DECODER
+ while (sinkManager_->DequeReleaseEsFrame(true, frameInfo) == HI_SUCCESS) {
+ }
+#else
+ if (audioDecoder_ != nullptr) {
+ while (sinkManager_->DequeReleaseFrame(true, outInfo) == 0) {
+ audioDecoder_->QueueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);
+ }
+ audioDecoder_->StopDec();
+ }
+#endif
+#if !defined(UNSUPPORT_VIDEO_DECODER)
+ if (videoDecoder_ != nullptr) {
+ while (sinkManager_->DequeReleaseFrame(false, outInfo) == 0) {
+ videoDecoder_->QueueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);
+ }
+ videoDecoder_->StopDec();
+ }
+#endif
+ }
+
+ isVideoStarted_ = false;
+ isAudioStarted_ = false;
+}
+
+int32_t PlayerControl::AddAudioSink(void)
+{
+ CHECK_TRUE_CONDITION_RETURN(isAudioStarted_, HI_SUCCESS, "already started");
+ SinkAttr attr;
+ attr.sinkType = SINK_TYPE_AUDIO;
+ attr.trackId = fmtFileInfo_.s32UsedAudioStreamIndex;
+ attr.audAttr.format = g_fromCodecFormatToAudioManager[fmtFileInfo_.enAudioType];
+ attr.audAttr.sampleRate = adecAttr_.sampleRate;
+ attr.audAttr.channel = fmtFileInfo_.u32AudioChannelCnt;
+ attr.audAttr.sessionID = audioSession_;
+ attr.audAttr.streamType = streamType_;
+ attr.audAttr.bitWidth = adecAttr_.bitWidth;
+ attr.audAttr.sampleFmt = fmtFileInfo_.sampleFmt;
+ MEDIA_INFO_LOG("AddAudioSink, format:%d, sampleRate:%d, channel:%d, session:%d, streamType:%d, bitWidth:%d",
+ attr.audAttr.format, attr.audAttr.sampleRate, attr.audAttr.channel, attr.audAttr.sessionID,
+ attr.audAttr.streamType, attr.audAttr.bitWidth);
+ if (sinkManager_->AddNewSink(attr) != 0) {
+ MEDIA_ERR_LOG("AddNewSink failed");
+ return -1;
+ }
+ isAudioStarted_ = true;
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::GetOffloadSupport(void)
+{
+ if (sinkManager_ == nullptr) {
+ MEDIA_ERR_LOG("sinkManager_ is invalid");
+ return -1;
+ }
+ AudioOffloadParam curOffloadInfo;
+ curOffloadInfo.streamType = streamType_;
+ curOffloadInfo.format = g_fromCodecFormatToAudioManager[fmtFileInfo_.enAudioType];
+ curOffloadInfo.sampleRate = adecAttr_.sampleRate;
+ curOffloadInfo.channel = fmtFileInfo_.u32AudioChannelCnt;
+ curOffloadInfo.bitWidth = 0;
+ MEDIA_INFO_LOG("GetOffloadSupport format:%d, audio:%d", curOffloadInfo.format, fmtFileInfo_.enAudioType);
+ offloadAudio_ = sinkManager_->IsOffloadSupported(curOffloadInfo);
+ MEDIA_INFO_LOG("%s audio offload", offloadAudio_ ? "supported" : "unsupported");
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::AddVideoSink()
+{
+ CHECK_TRUE_CONDITION_RETURN(isVideoStarted_, HI_SUCCESS, "already started");
+ SinkAttr attr;
+ attr.sinkType = SINK_TYPE_VIDEO;
+ attr.trackId = fmtFileInfo_.s32UsedVideoStreamIndex;
+ attr.vidAttr.width = fmtFileInfo_.u32Width;
+ attr.vidAttr.height = fmtFileInfo_.u32Height;
+ attr.vidAttr.frameRate = fmtFileInfo_.fFrameRate;
+ attr.vidAttr.format = fmtFileInfo_.enVideoType;
+ attr.vidAttr.surface = surface_;
+ if (sinkManager_->AddNewSink(attr) != 0) {
+ MEDIA_ERR_LOG("AddNewSink failed");
+ return -1;
+ }
+ isVideoStarted_ = true;
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::SinkStart(void)
+{
+ int32_t ret;
+ sinkManager_ = std::make_shared<SinkManager>();
+ CHECK_NULL_RETURN(sinkManager_, HI_FAILURE, "new sinkManager_ nullptr");
+ if (hasVideo_ && !isVideoStarted_) {
+ ret = AddVideoSink();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "AddVideoSink failed");
+ isVideoStarted_ = true;
+ }
+ if (hasAudio_ && !isAudioStarted_) {
+ ret = AddAudioSink();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "AddAudioSink failed");
+ isAudioStarted_ = true;
+ }
+
+ PlayEventCallback callback;
+ GetPlayElementEventCallBack(callback);
+ ret = sinkManager_->RegisterCallBack(callback);
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "RegisterCallBack failed");
+ /* get offload flag */
+ GetOffloadSupport();
+
+ if (metaData_.key == KEY_TYPE_EXTRADATA && hasAudio_) {
+ std::string key("extradata");
+ ret = sinkManager_->SetParam(key, DATA_TYPE_PTR, metaData_.value.pValue, metaData_.size);
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "sinkManager_ SetParam failed");
+ }
+
+ ret = sinkManager_->Start();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "sinkManager_ Start failed");
+
+ if (leftVolume_ >= 0.0f || rightVolume_ >= 0.0f) {
+ sinkManager_->SetVolume(leftVolume_, rightVolume_);
+ }
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::ReadFrameFromSource(FormatFrame &fmtFrame)
+{
+ CHECK_NULL_RETURN(playerSource_, HI_ERR_PLAYERCONTROL_NULL_PTR, "playerSource_ nullptr");
+ int ret = playerSource_->ReadFrame(fmtFrame);
+ // Check consistency of fmtFrame
+ if ((ret == HI_SUCCESS) && (fmtFrame.data != nullptr) && (fmtFrame.len == 0)) {
+ MEDIA_ERR_LOG("ReadFrame ERROR : u32Size is invalid");
+ ret = HI_FAILURE;
+ }
+ return ret;
+}
+
+// message begin
+int32_t PlayerControl::DoRegCallback(const PlayerCtrlCallbackParam &eventCallback)
+{
+ if (eventCallback_.callbackFun != nullptr) {
+ MEDIA_WARNING_LOG("you have reg callback,now the before callback fun pointer will be overwrite");
+ }
+ eventCallback_ = eventCallback;
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::DoSetDataSource(const char *filepath)
+{
+ filePath_ = std::string(filepath);
+ sourceType_ = SOURCE_TYPE_URI;
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::DoSetDataSource(const SourceFdParam &fdSrc)
+{
+ fd_ = fdSrc.fd;
+ offset_ = fdSrc.offset;
+ sourceType_ = SOURCE_TYPE_FD;
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::DoSetDataSource(const StreamSourceParam &streamSource)
+{
+ streamSource_ = streamSource;
+ sourceType_ = SOURCE_TYPE_STREAM;
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::DoPrepare(void)
+{
+ MEDIA_DEBUG_LOG("Process in");
+ CHECK_NULL_RETURN(eventCallback_.callbackFun, HI_ERR_PLAYERCONTROL_CALLBACK_ERROR, "callbackFun nullptr");
+ isPlayEnd_ = false;
+ int32_t ret = SyncPrepare();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, HI_ERR_PLAYERCONTROL_OTHER, "SyncPrepare failed");
+ if (playerParam_.u32PlayPosNotifyIntervalMs >= fmtFileInfo_.s64Duration) {
+ MEDIA_WARNING_LOG("play postion notify interval %d ms oversize file duration, user will never receive notify",
+ playerParam_.u32PlayPosNotifyIntervalMs);
+ }
+ MEDIA_DEBUG_LOG("Process out");
+ return HI_SUCCESS;
+}
+
+#if !defined(UNSUPPORT_VIDEO_DECODER) || !defined(UNSUPPORT_AUDIO_DECODER)
+static void InitOutputBuffer(OutputInfo &outInfo, CodecType type)
+{
+ if (outInfo.buffers != nullptr) {
+ free(outInfo.buffers);
+ outInfo.buffers = nullptr;
+ }
+
+ outInfo.bufferCnt = 0;
+ outInfo.buffers = nullptr;
+ outInfo.timeStamp = -1;
+ outInfo.sequence = 0;
+ outInfo.flag = 0;
+ outInfo.type = type;
+ outInfo.vendorPrivate = nullptr;
+}
+#endif
+
+#ifndef UNSUPPORT_AUDIO_DECODER
+void PlayerControl::ReleaseADecoderOutputFrame(void)
+{
+ if (audioDecoder_ == nullptr || sinkManager_ == nullptr) {
+ return;
+ }
+ while (true) {
+ OutputInfo outInfo;
+ if (sinkManager_->DequeReleaseFrame(true, outInfo) != 0) {
+ break;
+ }
+ audioDecoder_->QueueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);
+ }
+}
+#endif
+
+void PlayerControl::ReleaseAudioSinkESFrame(void)
+{
+ CHECK_NULL_RETURN_NONE(sinkManager_, "sink manager is null");
+
+ EsFrameInfo outInfo = {};
+ while (sinkManager_->DequeReleaseEsFrame(true, outInfo) == HI_SUCCESS) {
+ }
+}
+
+#if !defined(UNSUPPORT_VIDEO_DECODER)
+void PlayerControl::ReleaseVDecoderOutputFrame(void) const
+{
+ if (videoDecoder_ == nullptr || sinkManager_ == nullptr) {
+ return;
+ }
+ while (true) {
+ OutputInfo outInfo;
+ if (sinkManager_->DequeReleaseFrame(false, outInfo) != 0) {
+ break;
+ }
+ }
+}
+#endif
+
+void PlayerControl::ReportRenderPosition(void)
+{
+ int64_t position = -1;
+ CHECK_NULL_RETURN_NONE(sinkManager_, "sinkManager_ nullptr");
+ sinkManager_->GetRenderPosition(position);
+ if (position >= 0 && currentPosition_ != position) {
+ if (lastRendPos_ >= 0) {
+ currentPosition_ = position - lastRendPos_ + firstPosAfterSeek_;
+ } else {
+ currentPosition_ = position;
+ }
+ EventCallback(PLAYERCONTROL_EVENT_PROGRESS, ¤tPosition_);
+ }
+}
+
+void PlayerControl::GetRenderFullSleepThresholdTime(AudioCodecFormat codecFormat)
+{
+#ifdef DEBUG_LOW_POWER
+ if (codecFormat == PCM) {
+ renderFullSleepThresholdMs_ = RENDER_FULL_SLEEP_THRESHOLD_MS_PCM;
+ } else if (codecFormat == MP3 || codecFormat == AAC_LC || codecFormat == OPUS) {
+ renderFullSleepThresholdMs_ = RENDER_FULL_SLEEP_THRESHOLD_MS_MP3_AACLC_OPUS;
+ } else if (codecFormat == FLAC) {
+ renderFullSleepThresholdMs_ = RENDER_FULL_SLEEP_THRESHOLD_MS_FLAC;
+ }
+#else
+ MEDIA_UNUSED(codecFormat);
+#endif
+}
+
+void PlayerControl::DataSchPreProcess(PlayerControl *play, bool *isContinue)
+{
+ if (play->hasRenderAudioEos_) {
+ int32_t info = PLAYERCONTROL_ERROR_AUD_PLAY_FAIL;
+ play->EventCallback(PLAYERCONTROL_EVENT_ERROR, &info);
+ MEDIA_ERR_LOG("player waiting for the EOS callback timed out.");
+ }
+ play->DoSeekIfNeed();
+
+ play->renderSleepTime_ = 0;
+
+ if (play->paused_) {
+ // blocking wait ensures that the system goes into deep sleep for reducing power consumption
+ MediaThreadCondWait(play->schCond_, play->schMutex_);
+ *isContinue = true;
+ }
+}
+
+void PlayerControl::DataSchPostProcess(PlayerControl *play)
+{
+ play->EventQueueProcess();
+
+ play->ReportRenderPosition();
+
+ play->PrintKpiTime();
+
+ // process pure video eos
+ if (play->hasVideo_ && !play->hasAudio_ && play->hasRenderVideoEos_) {
+ MEDIA_INFO_LOG("Received video play eos flag");
+ play->EventCallback(PLAYERCONTROL_EVENT_EOF, nullptr);
+ }
+
+ if (play->IsPlayEos()) {
+ play->renderSleepTime_ = RENDER_EOS_SLEEP_TIME_US;
+ }
+}
+
+#if !defined(UNSUPPORT_VIDEO_DECODER) || !defined(UNSUPPORT_AUDIO_DECODER)
+inline static bool IsValidPacket(FormatFrame &packet)
+{
+ return (packet.data != nullptr && packet.len != 0) ? true : false;
+}
+#endif
+
+int32_t PlayerControl::DequeueInputDataFromDemuxer(void)
+{
+ if (GetCurState() != PLAY_STATUS_PLAY) {
+ renderSleepTime_ = WAIT_MAIN_THREAD_SWITCH_TO_PLAY_STATUS_TIME_US;
+ return HI_FAILURE;
+ }
+
+ CHECK_TRUE_CONDITION_RETURN(strmReadEnd_, HI_SUCCESS, "read stream end");
+
+#ifdef PLAYER_KPI_ON
+ struct timeval readPacketStartTime;
+ RecordTime(readPacketStartTime);
+#endif
+
+ int32_t ret = ReadPacket();
+ if (ret == HI_RET_NODATA) {
+ renderSleepTime_ = NO_DATA_READ_SLEEP_TIME_US;
+ goto RE_SEND;
+ } else if (ret != HI_SUCCESS) {
+ goto RE_SEND;
+ }
+
+#ifdef PLAYER_KPI_ON
+ ReadPacketAvgCostTime(readPacketStartTime);
+#endif
+
+ if (formatPacket_.data == nullptr && formatPacket_.len == 0) {
+ strmReadEnd_ = true;
+ formatPacket_.timestampUs = -1;
+ gettimeofday(&streamEndTime_, nullptr);
+ if (loop_) {
+ seekToTimeMs_ = 0;
+ return HI_FAILURE;
+ }
+ }
+
+ isAudio_ = (formatPacket_.frameType == FRAME_TYPE_AUDIO) ? true : false;
+ isVideo_ = (formatPacket_.frameType == FRAME_TYPE_VIDEO) ? true : false;
+
+ return HI_SUCCESS;
+
+RE_SEND:
+ ClearCachePacket();
+ return ret;
+}
+
+int32_t PlayerControl::QueueInputDataToAudioSink(void)
+{
+ CHECK_NULL_RETURN(sinkManager_, HI_FAILURE, "sink manager is null");
+ CHECK_TRUE_CONDITION_RETURN(hasRenderAudioEos_, HI_FAILURE, "has render audio eos");
+
+ if (strmReadEnd_) {
+ sinkManager_->RenderEos(true);
+ } else {
+ CHECK_FALSE_CONDITION_RETURN(cachedPacket_, HI_FAILURE, "no cache packet");
+ }
+
+ EsFrameInfo outInfo = {};
+ FillAudioFrameInfo(outInfo);
+ int32_t ret = sinkManager_->RenderEsFrame(outInfo);
+ if (ret == SINK_RENDER_FULL || ret == SINK_RENDER_DELAY) {
+#ifdef DEBUG_LOW_POWER
+ static uint32_t renderSuccessCount = 0;
+ LowPowerProcess(outInfo.pts, renderSuccessCount, false);
+#else
+ if (ret == SINK_RENDER_FULL && fmtFileInfo_.s32UsedVideoStreamIndex < 0) {
+ renderSleepTime_ = WAIT_BUFFER_EMPTY_SLEEP_TIME_US;
+ } else {
+ renderSleepTime_ = RENDER_FULL_SLEEP_TIME_US;
+ }
+#endif
+ return ret;
+ } else {
+#ifdef DEBUG_LOW_POWER
+ LowPowerProcess(outInfo.pts, renderSuccessCount, true);
+#endif
+ renderSleepTime_ = 0;
+ }
+ ReleaseAudioSinkESFrame();
+ if (ret == SINK_RENDER_EOS) {
+ hasRenderAudioEos_ = true;
+ MEDIA_INFO_LOG("have render audio eos");
+ if (IsPlayEos()) {
+ isPlayEnd_ = true;
+ }
+ }
+ if (firstAudioFrameAfterSeek_) {
+ firstAudioFrameAfterSeek_ = false;
+ sinkManager_->GetRenderPosition(lastRendPos_);
+ firstPosAfterSeek_ = formatPacket_.timestampUs;
+ MEDIA_INFO_LOG("push firstAudioFrameAfterSeek_ success, pts:%lld", formatPacket_.timestampUs);
+ }
+ if (formatPacket_.data != nullptr || formatPacket_.len != 0) {
+ lastSendAdecPts_ = formatPacket_.timestampUs;
+ }
+ ClearCachePacket();
+ return ret;
+}
+
+#ifndef UNSUPPORT_AUDIO_DECODER
+void PlayerControl::QueueInputDataToAudioDecoder(void)
+{
+ CHECK_NULL_RETURN_NONE(audioDecoder_, "audio decoder is null");
+ CHECK_TRUE_CONDITION_RETURN_NONE(cachedPacket_, "no cache packet");
+
+ InputInfo inputData = { 0, nullptr, 0, 0 };
+ CodecBufferInfo inBufInfo = {};
+
+ int32_t ret = audioDecoder_->DequeInputBuffer(inputData, GET_BUFFER_TIMEOUT_MS);
+ CHECK_FAILED_RETURN_NONE(ret, HI_SUCCESS, "deque input buffer failed");
+
+ inBufInfo.addr = formatPacket_.data;
+ inBufInfo.length = formatPacket_.len;
+ inputData.bufferCnt = 1;
+ inputData.buffers = &inBufInfo;
+ inputData.pts = formatPacket_.timestampUs;
+ inputData.flag = 0;
+ ret = audioDecoder_->QueueInputBuffer(inputData, GET_BUFFER_TIMEOUT_MS);
+ if (ret == CODEC_ERR_STREAM_BUF_FULL) {
+ renderSleepTime_ = QUEUE_BUFFER_FULL_SLEEP_TIME_US;
+ return;
+ }
+ if (firstAudioFrameAfterSeek_ && IsValidPacket(formatPacket_)) {
+ firstAudioFrameAfterSeek_ = false;
+ MEDIA_INFO_LOG("push firstAudioFrameAfterSeek_ success, pts:%lld", inputData.pts);
+ }
+ if (formatPacket_.data != nullptr || formatPacket_.len != 0) {
+ lastSendAdecPts_ = formatPacket_.timestampUs;
+ }
+ ClearCachePacket();
+}
+
+void PlayerControl::DequeueOutputBufferAndRenderAudioFrame(void)
+{
+ CHECK_NULL_RETURN_NONE(audioDecoder_, "audio decoder is null");
+ CHECK_NULL_RETURN_NONE(sinkManager_, "sink manager is null");
+ CHECK_FAILED_RETURN_NONE(hasRenderAudioEos_, false, "has render audio eos");
+
+ OutputInfo outInfo = {};
+ int32_t ret = audioDecoder_->DequeueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);
+ if (ret != HI_SUCCESS) {
+ InitOutputBuffer(outInfo, AUDIO_DECODER);
+ if (ret == CODEC_RECEIVE_EOS && strmReadEnd_) {
+ // all frame have been send to audio sink
+ sinkManager_->RenderEos(true);
+ }
+ }
+
+ ret = sinkManager_->RenderFrame(outInfo);
+ if (ret == SINK_RENDER_FULL || ret == SINK_RENDER_DELAY) {
+ renderSleepTime_ = RENDER_FULL_SLEEP_TIME_US;
+ } else if (ret == SINK_QUE_EMPTY) {
+ renderSleepTime_ = 0;
+ }
+ ReleaseADecoderOutputFrame();
+ // all frame in frameCacheQue_ is processed
+ if (ret == SINK_RENDER_EOS) {
+ hasRenderAudioEos_ = true;
+ MEDIA_INFO_LOG("have render audio eos");
+ if (IsPlayEos()) {
+ isPlayEnd_ = true;
+ }
+ }
+}
+#endif
+
+#if !defined(UNSUPPORT_VIDEO_DECODER)
+int32_t PlayerControl::QueueOutputBufferToVideoDecoder(void)
+{
+ CHECK_NULL_RETURN(surface_, HI_FAILURE, "surface is null");
+ CHECK_NULL_RETURN(sinkManager_, HI_FAILURE, "sink manager is null");
+ CHECK_NULL_RETURN(videoDecoder_, HI_FAILURE, "video decoder is null");
+
+ // 1. if video sink have cache, means have remain buffer not send to surface, don't need request buffer from surface
+ bool haveCache = sinkManager_->HaveCacheFrame(false);
+ if (haveCache) {
+ MEDIA_DEBUG_LOG("have cache frame skip this");
+ return HI_SUCCESS;
+ }
+
+ // 2. request video output buffer from surface
+#if defined(ENABLE_UIKIT)
+ surfaceBuf_ = surface_->RequestBuffer();
+#elif defined(ENABLE_LVGL)
+ surfaceBuf_ = LvRequestBuffer(reinterpret_cast<lv_obj_t *>(surface_), 0);
+#endif
+ if (surfaceBuf_ == nullptr) {
+ if (continousRequestSurfaceBufferFailCount_ == MAX_CONTINOUS_REQUEST_SURFACE_BUFFER_FAIL_COUNT) {
+ PalayControlEventItem item = { EVNET_VIDEO_RUNNING_ERR };
+ eventQueue_.push_back(item);
+ MEDIA_FATAL_LOG("continous request buffer fail count exceed upper limit");
+ return REQUEST_SURFACE_BUFFER_FATAL;
+ }
+ MEDIA_DEBUG_LOG("no free surface buffer retry");
+ renderSleepTime_ = REQUEST_BUFFER_RETRY_WAIT_TIME_US;
+ continousRequestSurfaceBufferFailCount_++;
+ return HI_FAILURE;
+ }
+ continousRequestSurfaceBufferFailCount_ = 0;
+
+ // 3. queue output buffer to video decoder
+ OutputInfo outInfo = {};
+ outInfo.type = VIDEO_DECODER;
+ outInfo.bufferCnt = 1;
+ outInfo.buffers = (CodecBufferInfo *)malloc(sizeof(CodecBufferInfo));
+ if (outInfo.buffers == nullptr) {
+ MEDIA_ERR_LOG("malloc failed");
+ return HI_FAILURE;
+ }
+ outInfo.buffers[0].type = BUFFER_TYPE_VIRTUAL;
+ outInfo.buffers[0].addr = reinterpret_cast<uint8_t *>(surfaceBuf_->addr);
+ outInfo.buffers[0].length = surfaceBuf_->width * surfaceBuf_->height * YCBCR420SP_BUFFER_SIZE_COEFFICIENT;
+ outInfo.vendorPrivate = surfaceBuf_;
+
+ int32_t ret = videoDecoder_->QueueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);
+ if (ret != HI_SUCCESS) {
+ free(outInfo.buffers);
+ MEDIA_ERR_LOG("queue output buffer to video decoder failed: 0x%x", ret);
+ return HI_FAILURE;
+ }
+
+ free(outInfo.buffers);
+ return HI_SUCCESS;
+}
+
+void PlayerControl::QueueInputDataToVideoDecoder(void)
+{
+ CHECK_NULL_RETURN_NONE(videoDecoder_, "video decoder is null");
+ CHECK_NULL_RETURN_NONE(sinkManager_, "sink manager is null");
+
+ bool haveCache = sinkManager_->HaveCacheFrame(false);
+ if (haveCache) {
+ MEDIA_DEBUG_LOG("have cache frame skip this");
+ return;
+ }
+
+ if (!strmReadEnd_) {
+ CHECK_FALSE_CONDITION_RETURN_NONE(cachedPacket_, "no cache packet");
+ }
+
+ InputInfo inputData = { 0, nullptr, 0, 0 };
+ CodecBufferInfo inBufInfo = {};
+
+ int32_t ret = videoDecoder_->DequeInputBuffer(inputData, GET_BUFFER_TIMEOUT_MS);
+ CHECK_FAILED_RETURN_NONE(ret, HI_SUCCESS, "deque input buffer failed");
+
+ MEDIA_DEBUG_LOG("queue input buffer len: %u, pts: %lld", formatPacket_.len, formatPacket_.timestampUs);
+
+ inBufInfo.addr = formatPacket_.data;
+ inBufInfo.length = formatPacket_.len;
+ inputData.bufferCnt = 1;
+ inputData.buffers = &inBufInfo;
+ inputData.pts = formatPacket_.timestampUs;
+ inputData.flag = (formatPacket_.data == nullptr && formatPacket_.len == 0) ? STREAM_FLAG_EOS : 0;
+ ret = videoDecoder_->QueueInputBuffer(inputData, GET_BUFFER_TIMEOUT_MS);
+ if (ret == CODEC_ERR_STREAM_BUF_FULL) {
+ renderSleepTime_ = QUEUE_BUFFER_FULL_SLEEP_TIME_US;
+ return;
+ }
+ if (firstVideoFrameAfterSeek_ && IsValidPacket(formatPacket_)) {
+ firstVideoFrameAfterSeek_ = false;
+ // MEDIA_INFO_LOG("push firstVideoFrameAfterSeek_ success, pts:%lld", inputData.pts);
+ }
+ if (formatPacket_.data != nullptr && formatPacket_.len != 0) {
+ lastSendVdecPts_ = formatPacket_.timestampUs;
+ }
+ ClearCachePacket();
+}
+
+void PlayerControl::DequeueOutputBufferAndRenderVideoFrame(void)
+{
+ CHECK_NULL_RETURN_NONE(videoDecoder_, "video decoder is null");
+ CHECK_NULL_RETURN_NONE(sinkManager_, "sink manager is null");
+ CHECK_TRUE_CONDITION_RETURN_NONE(hasRenderVideoEos_, "has render video eos");
+
+ OutputInfo outInfo = {};
+ outInfo.buffers = (CodecBufferInfo *)malloc(sizeof(CodecBufferInfo));
+ if (outInfo.buffers == nullptr) {
+ MEDIA_ERR_LOG("malloc failed");
+ return;
+ }
+ int ret = videoDecoder_->DequeueOutputBuffer(outInfo, GET_BUFFER_TIMEOUT_MS);
+ if (ret != 0) {
+ InitOutputBuffer(outInfo, VIDEO_DECODER);
+ if (surface_ != nullptr) {
+#if defined(ENABLE_UIKIT)
+ surface_->CancelBuffer(surfaceBuf_);
+#elif defined(ENABLE_LVGL)
+ LvCancelBuffer(reinterpret_cast<lv_obj_t *>(surface_), surfaceBuf_);
+#endif
+ }
+ if (ret == CODEC_RECEIVE_EOS) {
+ sinkManager_->RenderEos(false); /* all frame have been send to video sink */
+ } else {
+ goto EXIT;
+ }
+ }
+
+ ret = sinkManager_->RenderFrame(outInfo);
+ if (ret == SINK_RENDER_FULL || ret == SINK_RENDER_DELAY) {
+ renderSleepTime_ = RENDER_FULL_SLEEP_TIME_US;
+ } else if (ret == SINK_QUE_EMPTY) {
+ renderSleepTime_ = 0;
+ }
+EXIT:
+ ReleaseVDecoderOutputFrame();
+ /* fuction RenderFrame will return SINK_RENDER_EOS when all frame in queue that have been processed */
+ if (ret == SINK_RENDER_EOS) {
+ hasRenderVideoEos_ = true;
+ MEDIA_INFO_LOG("have render video eos");
+ if (IsPlayEos()) {
+ isPlayEnd_ = true;
+ }
+ }
+
+ if (outInfo.buffers != nullptr) {
+ free(outInfo.buffers);
+ }
+ return;
+}
+#endif
+
+int32_t PlayerControl::DealWithInputEos(bool hasAudio, bool hasVideo)
+{
+ if (hasAudio) {
+#ifdef UNSUPPORT_AUDIO_DECODER
+ QueueInputDataToAudioSink();
+#else
+ QueueInputDataToAudioDecoder();
+ DequeueOutputBufferAndRenderAudioFrame();
+#endif
+ }
+
+ if (hasVideo) {
+#if !defined(UNSUPPORT_VIDEO_DECODER)
+ int32_t ret = QueueOutputBufferToVideoDecoder();
+ if (ret != HI_SUCCESS) {
+ return ret;
+ }
+ QueueInputDataToVideoDecoder();
+ DequeueOutputBufferAndRenderVideoFrame();
+#endif
+ }
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::ProcessInputData(bool isAudio, bool isVideo)
+{
+ if (isAudio) {
+#ifdef UNSUPPORT_AUDIO_DECODER
+ return QueueInputDataToAudioSink();
+#else
+ QueueInputDataToAudioDecoder();
+ DequeueOutputBufferAndRenderAudioFrame();
+#endif
+ } else if (isVideo) {
+#if !defined(UNSUPPORT_VIDEO_DECODER)
+ int32_t retValue = QueueOutputBufferToVideoDecoder();
+ if (retValue != HI_SUCCESS) {
+ return retValue;
+ }
+ QueueInputDataToVideoDecoder();
+ DequeueOutputBufferAndRenderVideoFrame();
+#endif
+ }
+ return HI_SUCCESS;
+}
+
+void *PlayerControl::DataSchProcess(void *priv)
+{
+ CHECK_NULL_RETURN(priv, nullptr, "priv is null");
+
+ PlayerControl *play = (PlayerControl *)priv;
+
+#ifdef SUPPORT_SYS_PRCTL
+ prctl(PR_SET_NAME, "PlaySch", 0, 0, 0);
+#endif
+
+ MEDIA_INFO_LOG("start work");
+
+ // for low power
+ play->GetRenderFullSleepThresholdTime(g_fromCodecFormatToAudioManager[play->fmtFileInfo_.enAudioType]);
+
+ int32_t ret = HI_FAILURE;
+ while (true) {
+ MediaMutexLock(play->schMutex_);
+ if (play->schThreadExit_) {
+ MediaMutexUnLock(play->schMutex_);
+ break;
+ }
+
+ bool isContinue = false;
+ DataSchPreProcess(play, &isContinue);
+ if (isContinue) {
+ goto CONTINUE;
+ }
+
+ if (play->DequeueInputDataFromDemuxer() != HI_SUCCESS) {
+ goto CONTINUE;
+ }
+
+ if (play->strmReadEnd_) {
+ ret = play->DealWithInputEos(play->hasAudio_, play->hasVideo_);
+ } else {
+ ret = play->ProcessInputData(play->isAudio_, play->isVideo_);
+ }
+
+ if (ret == SINK_RENDER_FATEL || ret == REQUEST_SURFACE_BUFFER_FATAL) {
+ play->EventQueueProcess();
+ MediaMutexUnLock(play->schMutex_);
+ break;
+ } else if (ret != HI_SUCCESS) {
+ goto CONTINUE;
+ }
+
+ DataSchPostProcess(play);
+
+ CONTINUE:
+ if (play->renderSleepTime_ > 0) {
+ MediaThreadCondTimeWait(play->schCond_, play->schMutex_, play->renderSleepTime_);
+ }
+ MediaMutexUnLock(play->schMutex_);
+ }
+
+ MediaMutexLock(play->schMutex_);
+ play->schThreadExit_ = true;
+ MediaMutexUnLock(play->schMutex_);
+
+ MEDIA_INFO_LOG("end work");
+ return nullptr;
+}
+
+int32_t PlayerControl::DoPlay()
+{
+ MEDIA_DEBUG_LOG("Process in");
+ CHECK_NULL_RETURN(playerSource_, HI_ERR_PLAYERCONTROL_NULL_PTR, "playerSource_ nullptr");
+
+ int32_t ret = HI_SUCCESS;
+ PlayerStatus playerState = GetCurState();
+ CHECK_STATE_SAME_RETURN(playerState, PLAY_STATUS_PLAY, "state same");
+ if (playerState == PLAY_STATUS_PREPARED) {
+ ret = CheckMediaInfo();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "CheckMediaInfo failed");
+ ret = SetDecoderAndStreamAttr();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SetDecoderAndStreamAttr failed");
+ ret = SinkStart();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SinkStart failed");
+ ret = DecoderStart();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "DecoderStart failed");
+ ret = playerSource_->Start();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "playerSource_ Start failed");
+ MediaMutexLock(schMutex_);
+ paused_ = true;
+ MediaThreadattr attr = { "PlaySch", MAX_THREAD_STACK_SIZE, THREAD_SCHED_INVALID, 80, false };
+ schProcess_ = MediaThreadCreate(DataSchProcess, this, &attr);
+ if (schProcess_ == nullptr) {
+ MEDIA_ERR_LOG("thread create failed %d", ret);
+ schThreadExit_ = false;
+ MediaMutexUnLock(schMutex_);
+ return -1;
+ }
+ paused_ = false;
+ MediaMutexUnLock(schMutex_);
+ } else if (playerState == PLAY_STATUS_PAUSE) {
+ ret = PauseResume();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "PauseResume failed");
+ } else {
+ return HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION;
+ }
+ return ret;
+}
+
+int32_t PlayerControl::DoSetVolume(const VolumeAttr &volumeAttr)
+{
+ leftVolume_ = volumeAttr.leftVolume;
+ rightVolume_ = volumeAttr.rightVolume;
+ CHECK_NULL_RETURN(sinkManager_, HI_SUCCESS, "sinkManager_ nullptr, it will be setted after play");
+ return sinkManager_->SetVolume(volumeAttr.leftVolume, volumeAttr.rightVolume);
+}
+
+int32_t PlayerControl::ReadPacket()
+{
+ int32_t ret = HI_SUCCESS;
+ if (cachedPacket_) {
+ return ret;
+ }
+ ret = ReadFrameFromSource(formatPacket_);
+ if (ret != HI_RET_FILE_EOF && formatPacket_.data == nullptr && formatPacket_.len == 0) {
+ return HI_RET_NODATA;
+ }
+ if (ret == HI_RET_FILE_EOF) {
+ CHECK_FAILED_RETURN(memset_s(&formatPacket_, sizeof(formatPacket_), 0, sizeof(FormatFrame)), EOK, -1,
+ "memset_s failed");
+ ret = HI_SUCCESS;
+ } else if (ret == HI_RET_NODATA) {
+ CHECK_FAILED_RETURN(memset_s(&formatPacket_, sizeof(formatPacket_), 0, sizeof(FormatFrame)), EOK, -1,
+ "memset_s failed");
+ strmReadEnd_ = false;
+ return ret;
+ } else if (ret != HI_SUCCESS) {
+ MEDIA_ERR_LOG("ReadFrameFromSource failed , ret:%d", ret);
+ NotifyError(PLAYERCONTROL_ERROR_DEMUX_FAIL);
+ return HI_FAILURE;
+ }
+ strmReadEnd_ = false;
+ cachedPacket_ = true;
+ return ret;
+}
+
+#ifdef PLAYER_KPI_ON
+void PlayerControl::PrintRenderEsTime(const struct timeval &esFrameStartTime)
+{
+ std::string renderEsFrame("KPI_PlayerRenderEsFrame");
+ struct timeval esFrameEndTime = {};
+ uint64_t renderEsOnceTime = CalcTimeDiffUsPrint(esFrameStartTime, esFrameEndTime, renderEsFrame, false);
+ if (renderEsOnceTime != INVALID_TIME) {
+ renderEsTotalTime_ += renderEsOnceTime;
+ renderEsFrameCnt_++;
+ }
+ if (renderEsFrameCnt_ == 500) { /* 500:Print Interval */
+ MEDIA_INFO_LOG("KPI_PlayerRenderEsFrame avg time: %lld us", renderEsTotalTime_ /= renderEsFrameCnt_);
+ renderEsTotalTime_ = 0;
+ renderEsFrameCnt_ = 0;
+ }
+}
+#endif
+
+void PlayerControl::FillAudioFrameInfo(EsFrameInfo &outInfo)
+{
+ if (memset_s(&outInfo, sizeof(outInfo), 0, sizeof(EsFrameInfo)) != EOK) {
+ return;
+ }
+
+ outInfo.addr = formatPacket_.data;
+ outInfo.size = formatPacket_.len;
+ outInfo.pts = formatPacket_.timestampUs;
+ outInfo.flag = 0;
+ EsFrameType frameType = g_fromDemuxTypeToSinkType[formatPacket_.frameType];
+ outInfo.type = (frameType == ESFRAME_TYPE_NONE) ? ESFRAME_TYPE_AUDIO : frameType;
+}
+
+#ifdef DEBUG_LOW_POWER
+void PlayerControl::LowPowerProcess(int64_t pts, uint32_t &renderSuccessCount, bool renderFrameSuccess)
+{
+ if (renderFrameSuccess) {
+ if (headInSendSuccessInterval_ == -1) {
+ headInSendSuccessInterval_ = pts;
+ tailInSendSuccessInterval_ = -1;
+ }
+ renderSuccessCount++;
+ } else {
+ if (tailInSendSuccessInterval_ == -1) {
+ tailInSendSuccessInterval_ = pts;
+ int64_t diffMs = tailInSendSuccessInterval_ - headInSendSuccessInterval_ - renderFullSleepThresholdMs_;
+ renderSleepTime_ = (diffMs > 0) ? (diffMs * US_2_MS) : RENDER_FULL_SLEEP_TIME_US;
+ }
+
+ /* MEAIA_XXX_LOG have performance problem, use printf instead */
+ printf("render %d audio frames, from %lldms to %lldms, thread wait %ums\n", renderSuccessCount,
+ tailInSendSuccessInterval_, headInSendSuccessInterval_, renderSleepTime_ / US_2_MS);
+
+ headInSendSuccessInterval_ = -1;
+ renderSuccessCount = 0;
+ }
+}
+#endif
+
+#ifdef PLAYER_KPI_ON
+void PlayerControl::ReadPacketAvgCostTime(const struct timeval &readPacketStartTime)
+{
+ struct timeval readPacketEndTime;
+ std::string readPacketCost("KPI_Player_demux_cost_time");
+ uint64_t readPktOnceTime = CalcTimeDiffUsPrint(readPacketStartTime, readPacketEndTime, readPacketCost, false);
+ if (readPktOnceTime != INVALID_TIME) {
+ readPktTotalTime_ += readPktOnceTime;
+ readPacketCnt_++;
+ }
+ if (readPacketCnt_ == 500) { /* 500:Print Interval */
+ MEDIA_INFO_LOG("KPI_Player_demux_cost_time avg time: %lld us", readPktTotalTime_ /= readPacketCnt_);
+ readPktTotalTime_ = 0;
+ readPacketCnt_ = 0;
+ }
+}
+#endif
+
+int32_t PlayerControl::DoStop()
+{
+ int32_t ret = HI_SUCCESS;
+ PlayerStatus playerState = GetCurState();
+ CHECK_STATE_SAME_RETURN(playerState, PLAY_STATUS_IDLE, "state same");
+
+ if (schProcess_ != nullptr) {
+ MediaMutexLock(schMutex_);
+ schThreadExit_ = true;
+ MediaThreadCondSignal(schCond_);
+ MediaMutexUnLock(schMutex_);
+ MediaThreadJoin(&schProcess_);
+ }
+ StopSinkAndDecoder();
+ ClearCachePacket();
+ if (playerSource_ != nullptr) {
+ ret = playerSource_->Stop();
+ CHECK_FAILED_PRINT(ret, HI_SUCCESS, "playerSource_ stop failed");
+ }
+ isPlayEnd_ = false;
+ strmReadEnd_ = false;
+ isPlayErr_ = false;
+ lastRendPos_ = 0;
+ lastReadPktPts_ = 0;
+ lastSendPktPts_ = 0;
+ isAudPlayEos_ = false;
+ hasRenderAudioEos_ = false;
+ hasRenderAudioEos_ = false;
+ lastNotifyTime_ = 0;
+ seekToTimeMs_ = -1;
+ if (memset_s(&(fmtFileInfo_), sizeof(fmtFileInfo_), 0, sizeof(FormatFileInfo)) != EOK) {
+ MEDIA_ERR_LOG("memset_s failed");
+ return HI_ERR_PLAYERCONTROL_MEM_SET;
+ }
+ return ret;
+}
+
+int32_t PlayerControl::DoPause(void)
+{
+ PlayerStatus playerState = GetCurState();
+ CHECK_STATE_SAME_RETURN(playerState, PLAY_STATUS_PAUSE, "state same");
+ CHECK_NULL_RETURN(sinkManager_, HI_FAILURE, "sinkManager_ nullptr");
+
+ if (playerState == PLAY_STATUS_PLAY) {
+ MediaMutexLock(schMutex_);
+ int32_t ret = sinkManager_->Pause();
+ CHECK_FAILED_PRINT(ret, 0, "sinkManager_ pause failed:%d");
+ paused_ = true;
+ MediaMutexUnLock(schMutex_);
+ } else {
+ return HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION;
+ }
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::DoSeekIfNeed(void)
+{
+ if (seekToTimeMs_ == -1) {
+ return HI_SUCCESS;
+ }
+ MEDIA_INFO_LOG("seek start");
+
+ // 在 seek 前重置解码器和渲染器,确保状态一致,避免 DPU 超时
+ // 清空解码器中的旧帧,重置渲染器状态,让 DPU 重新同步
+ int32_t ret = DecoderAndSinkReset();
+ if (ret != HI_SUCCESS) {
+ MEDIA_ERR_LOG("DecoderAndSinkReset failed, ret:%d", ret);
+ // 即使 reset 失败,也继续执行 seek,避免阻塞
+ }
+
+ ret = AyncSeek(seekToTimeMs_);
+ if (ret != HI_SUCCESS) {
+ MEDIA_ERR_LOG(" AyncSeek failed , ret:%d", ret);
+ NotifyError(PLAYERCONTROL_ERROR_AUD_PLAY_FAIL);
+ return ret;
+ }
+ strmReadEnd_ = false;
+ isAudPlayEos_ = false;
+ isVidPlayEos_ = false;
+ hasRenderVideoEos_ = false;
+ hasRenderAudioEos_ = false;
+ isPlayEnd_ = false;
+ seekToTimeMs_ = -1;
+ firstAudioFrameAfterSeek_ = true;
+ firstVideoFrameAfterSeek_ = true;
+ MEDIA_INFO_LOG("seek end");
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::DoSeek(int64_t timeInMs)
+{
+ seekToTimeMs_ = timeInMs;
+ return DoSeekIfNeed();
+}
+
+int32_t PlayerControl::DoGetFileInfo(FormatFileInfo &fileInfo) const
+{
+ return memcpy_s(&fileInfo, sizeof(FormatFileInfo), &fmtFileInfo_, sizeof(fmtFileInfo_));
+}
+
+int32_t PlayerControl::DoSetMedia(const PlayerControlStreamAttr &mediaAttr)
+{
+ CHECK_NULL_RETURN(playerSource_, HI_ERR_PLAYERCONTROL_NULL_PTR, "playerSource_ nullptr");
+
+ int32_t ret = HI_SUCCESS;
+ if (hasVideo_) {
+ ret = playerSource_->SelectTrack(0, mediaAttr.s32VidStreamId);
+ CHECK_FAILED_RETURN(ret, 0, HI_ERR_PLAYERCONTROL_DEMUX_ERROR, "select video track failed");
+ }
+ if (hasAudio_) {
+ ret = playerSource_->SelectTrack(0, mediaAttr.s32AudStreamId);
+ CHECK_FAILED_RETURN(ret, 0, HI_ERR_PLAYERCONTROL_DEMUX_ERROR, "select audio track failed");
+ }
+
+ fmtFileInfo_.s32UsedVideoStreamIndex = mediaAttr.s32VidStreamId;
+ fmtFileInfo_.s32UsedAudioStreamIndex = mediaAttr.s32AudStreamId;
+
+ hasAudio_ = (fmtFileInfo_.s32UsedAudioStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) ? true : false;
+ hasVideo_ = (fmtFileInfo_.s32UsedVideoStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) ? true : false;
+
+ return ret;
+}
+
+int32_t PlayerControl::DoSetPlaybackSpeed(float speed) const
+{
+ MediaMutexLock(schMutex_);
+ int ret = sinkManager_->SetSpeed(speed);
+ if (ret != HI_SUCCESS) {
+ MEDIA_ERR_LOG("DoSetPlaybackSpeed failed:%d", ret);
+ }
+ MediaMutexUnLock(schMutex_);
+ return HI_SUCCESS;
+}
+
+void PlayerControl::RecordLastPosition()
+{
+ sinkManager_->RecordLastPosition();
+}
+
+// util bigein
+void PlayerControl::EventCallback(PlayerControlEvent event, const void *data) const
+{
+ CHECK_NULL_RETURN_NONE(eventCallback_.callbackFun, "callbackFun nullptr");
+ eventCallback_.callbackFun(eventCallback_.player, event, data);
+}
+
+void PlayerControl::PlayerControlCondSignal(void)
+{
+ if (fmtFileInfo_.s32UsedVideoStreamIndex < 0) {
+ MediaThreadCondSignal(schCond_);
+ }
+}
+
+void PlayerControl::EnableSingleLooping(bool loop)
+{
+ MediaMutexLock(schMutex_);
+ loop_ = loop;
+ MediaMutexUnLock(schMutex_);
+}
+
+int32_t PlayerControl::SetParam(const std::string &key, const void *value, uint32_t len)
+{
+ CHECK_NULL_RETURN(sinkManager_, HI_ERR_PLAYERCONTROL_NULL_PTR, "sinkManager_ nullptr");
+ MediaMutexLock(schMutex_);
+ int32_t ret = sinkManager_->SetParam(key, DATA_TYPE_STRING, value, len);
+ if (ret != HI_SUCCESS) {
+ MediaMutexUnLock(schMutex_);
+ return ret;
+ }
+ MediaMutexUnLock(schMutex_);
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::GetParam(const std::string &key, void *value, uint32_t size)
+{
+ CHECK_NULL_RETURN(sinkManager_, HI_ERR_PLAYERCONTROL_NULL_PTR, "sinkManager_ nullptr");
+ MediaMutexLock(schMutex_);
+ int32_t ret = sinkManager_->GetParam(key, DATA_TYPE_PTR, value, size);
+ if (ret != HI_SUCCESS) {
+ MediaMutexUnLock(schMutex_);
+ return ret;
+ }
+ MediaMutexUnLock(schMutex_);
+ return HI_SUCCESS;
+}
+
+void PlayerControl::NotifyError(PlayerControlError playerError) const
+{
+ EventCallback(PLAYERCONTROL_EVENT_ERROR, static_cast<void *>(&playerError));
+}
+
+void PlayerControl::StateChangeCallback(PlayerStatus state) const
+{
+ EventCallback(PLAYERCONTROL_EVENT_STATE_CHANGED, static_cast<void *>(&state));
+}
+
+void PlayerControl::FlushDecoder(void)
+{
+#ifndef UNSUPPORT_AUDIO_DECODER
+ ReleaseADecoderOutputFrame();
+ if (audioDecoder_ != nullptr) {
+ audioDecoder_->FlushDec();
+ }
+#endif
+
+#if !defined(UNSUPPORT_VIDEO_DECODER)
+ // 取消当前正在使用的 Surface buffer,确保 buffer 可以被重新请求
+ if (surface_ != nullptr && surfaceBuf_ != nullptr) {
+#if defined(ENABLE_UIKIT)
+ surface_->CancelBuffer(surfaceBuf_);
+#elif defined(ENABLE_LVGL)
+ LvCancelBuffer(reinterpret_cast<lv_obj_t *>(surface_), surfaceBuf_);
+#endif
+ surfaceBuf_ = nullptr;
+ }
+ ReleaseVDecoderOutputFrame();
+ if (videoDecoder_ != nullptr) {
+ videoDecoder_->FlushDec();
+ }
+#endif
+}
+
+int32_t PlayerControl::DecoderAndSinkReset(void)
+{
+ if (strmReadEnd_ && loop_) {
+ return HI_SUCCESS;
+ }
+ int32_t ret;
+ bool isNeedResume = false;
+ ret = sinkManager_->Pause();
+ if ((ret == HI_SUCCESS) && (!paused_)) {
+ isNeedResume = true;
+ }
+ ret = sinkManager_->Reset();
+ if (ret != HI_SUCCESS) {
+ MEDIA_ERR_LOG("m_render reset failed");
+ (void)sinkManager_->Resume();
+ return ret;
+ }
+ FlushDecoder();
+ if (isNeedResume) {
+ ret = sinkManager_->Resume();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, HI_FAILURE, "sinkManager_ Resume failed");
+ }
+ return HI_SUCCESS;
+}
+
+int32_t PlayerControl::AyncSeek(int64_t seekTime)
+{
+ CHECK_NULL_RETURN(playerSource_, HI_FAILURE, "playerSource_ nullptr");
+ int64_t seekTimeInMs = seekTime;
+ int32_t ret = 0;
+ ClearCachePacket();
+ if (fmtFileInfo_.s32UsedVideoStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) {
+ ret = playerSource_->Seek(fmtFileInfo_.s32UsedVideoStreamIndex, seekTimeInMs, FORMAT_SEEK_MODE_BACKWARD_KEY);
+ if (ret != HI_SUCCESS) {
+ MEDIA_INFO_LOG("exec fmt_seek video stream failed, ret:%d", ret);
+ seekTimeInMs = currentPosition_;
+ }
+ }
+ if (fmtFileInfo_.s32UsedAudioStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) {
+ ret = playerSource_->Seek(fmtFileInfo_.s32UsedAudioStreamIndex, seekTimeInMs, FORMAT_SEEK_MODE_BACKWARD_KEY);
+ if (ret != HI_SUCCESS) {
+ MEDIA_INFO_LOG("exec fmt_seek audio stream failed, ret:%d", ret);
+ seekTimeInMs = currentPosition_;
+ }
+ }
+ currentPosition_ = seekTimeInMs;
+ EventCallback(PLAYERCONTROL_EVENT_PROGRESS, ¤tPosition_);
+ EventCallback(PLAYERCONTROL_EVENT_SEEK_END, static_cast<void *>(&seekTimeInMs));
+ return HI_SUCCESS;
+}
+
+void PlayerControl::GetPlayElementEventCallBack(PlayEventCallback &callback)
+{
+ callback.onEventCallback = PlayerControlOnEvent;
+ callback.priv = static_cast<void *>(this);
+}
+int32_t PlayerControl::SyncPrepare()
+{
+ int ret;
+ playerSource_ = std::make_shared<PlayerSource>();
+ CHECK_NULL_RETURN(playerSource_, HI_FAILURE, "new playerSource_ nullptr");
+ playerSource_->Init();
+
+ if (sourceType_ == SOURCE_TYPE_FD) {
+ playerSource_->SetSource(fd_, offset_);
+ } else if (sourceType_ == SOURCE_TYPE_STREAM) {
+ playerSource_->SetSource(streamSource_);
+ } else {
+ playerSource_->SetSource(filePath_.c_str());
+ }
+
+ PlayEventCallback callback;
+ GetPlayElementEventCallBack(callback);
+ ret = playerSource_->SetCallBack(callback);
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "SetCallBack failed");
+
+ ret = playerSource_->Prepare();
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "Prepare failed");
+ ret = playerSource_->GetFileInfo(fmtFileInfo_);
+ CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "GetFileInfo failed");
+ metaData_.key = KEY_TYPE_EXTRADATA;
+ ret = playerSource_->GetParam(0, metaData_);
+ if (ret != HI_SUCCESS) {
+ MEDIA_INFO_LOG("no extradata metadata");
+ metaData_.key = 0;
+ }
+
+ hasAudio_ = (fmtFileInfo_.s32UsedAudioStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) ? true : false;
+ hasVideo_ = (fmtFileInfo_.s32UsedVideoStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) ? true : false;
+
+ MEDIA_INFO_LOG("used audiostream index %d", fmtFileInfo_.s32UsedAudioStreamIndex);
+ MEDIA_INFO_LOG("used videostream index %d", fmtFileInfo_.s32UsedVideoStreamIndex);
+
+ return HI_SUCCESS;
+}
+
+bool PlayerControl::IsPlayEos() const
+{
+ bool isEos = false;
+ if (hasAudio_) {
+ if (hasVideo_) {
+ return (!isAudioStarted_ || hasRenderAudioEos_) && (!isVideoStarted_ || hasRenderVideoEos_);
+ } else {
+ return (!isAudioStarted_ || hasRenderAudioEos_);
+ }
+ } else {
+ if (hasVideo_) {
+ return (!isVideoStarted_ || hasRenderVideoEos_);
+ } else {
+ MEDIA_ERR_LOG("neither audio nor video");
+ isEos = false;
+ }
+ }
+
+ return isEos;
+}
+
+int32_t PlayerControl::Invoke(PlayerInvoke invokeId, const void *param)
+{
+ MsgInfo msg = {};
+ InvokeParameter invokeParam;
+ invokeParam.id = invokeId;
+ invokeParam.param = param;
+
+ msg.what = PLAYERCONTROL_MSG_INVOKE;
+ msg.msgData = &invokeParam;
+ msg.msgDataLen = sizeof(InvokeParameter);
+ return OnMessageReceived(msg);
+}
+
+int32_t PlayerControl::DoInvoke(const InvokeParameter &invokeParam)
+{
+ switch (invokeParam.id) {
+ case INVOKE_ENABLE_PAUSE_AFTER_PLAYER:
+ if (invokeParam.param == nullptr) {
+ return -1;
+ }
+ break;
+
+ case INVOKE_SET_AUDIO_SESSION:
+ if (invokeParam.param == nullptr) {
+ return -1;
+ }
+ audioSession_ = *(static_cast<const uint32_t *>(invokeParam.param));
+ MEDIA_INFO_LOG("audio sessionId: %d", audioSession_);
+ break;
+
+ case INVOKE_SET_OUTPUT_DEVICE:
+ if (invokeParam.param == nullptr) {
+ return -1;
+ }
+ outDeviceId_ = *(static_cast<const uint32_t *>(invokeParam.param));
+ MEDIA_INFO_LOG("outputDevice: 0x%x", outDeviceId_);
+ if (sinkManager_ != nullptr) {
+ return sinkManager_->SetOutputDevice(outDeviceId_);
+ }
+ break;
+
+ case INVOKE_SET_AUDIOSTREAM_TYPE:
+ if (invokeParam.param == nullptr) {
+ return -1;
+ }
+ streamType_ = *(static_cast<const uint32_t *>(invokeParam.param));
+ MEDIA_INFO_LOG("streamType: 0x%x", streamType_);
+ break;
+ default:
+ MEDIA_ERR_LOG("unsupport invoke: 0x%x", invokeParam.id);
+ return -1;
+ }
+ return 0;
+}
+
+int PlayerControl::HandleMsgWithParam(const MsgInfo &msgInfo)
+{
+ int32_t ret;
+ if (msgInfo.msgData == nullptr) {
+ MEDIA_ERR_LOG("data is null, msg:%d", msgInfo.what);
+ return HI_ERR_PLAYERCONTROL_NULL_PTR;
+ }
+ switch (msgInfo.what) {
+ case PLAYERCONTROL_MSG_REGCALLBACK:
+ ret = DoRegCallback(*static_cast<PlayerCtrlCallbackParam *>(msgInfo.msgData));
+ break;
+ case PLAYERCONTROL_MSG_SET_DATASOURCE_URI:
+ ret = DoSetDataSource(static_cast<const char *>(msgInfo.msgData));
+ break;
+ case PLAYERCONTROL_MSG_SET_DATASOURCE_FD:
+ ret = DoSetDataSource(*static_cast<SourceFdParam *>(msgInfo.msgData));
+ break;
+ case PLAYERCONTROL_MSG_SET_DATASOURCE_STREAM:
+ ret = DoSetDataSource(*static_cast<StreamSourceParam *>(msgInfo.msgData));
+ break;
+ case PLAYERCONTROL_MSG_SETATTR:
+ ret = DoSetMedia(*static_cast<PlayerControlStreamAttr *>(msgInfo.msgData));
+ break;
+ case PLAYERCONTROL_MSG_SETSPEED:
+ ret = DoSetPlaybackSpeed(*static_cast<const float *>(msgInfo.msgData));
+ break;
+ case PLAYERCONTROL_MSG_SET_VOLUME:
+ ret = DoSetVolume(*static_cast<VolumeAttr *>(msgInfo.msgData));
+ break;
+ case PLAYERCONTROL_MSG_SEEK:
+ ret = DoSeek(*static_cast<int64_t *>(msgInfo.msgData));
+ break;
+ case PLAYERCONTROL_MSG_GETFILEINFO:
+ ret = DoGetFileInfo(*static_cast<FormatFileInfo *>(msgInfo.msgData));
+ break;
+ case PLAYERCONTROL_MSG_INVOKE:
+ ret = DoInvoke(*static_cast<InvokeParameter *>(msgInfo.msgData));
+ break;
+ default:
+ ret = HI_ERR_PLAYERCONTROL_ILLEGAL_PARAM;
+ break;
+ }
+
+ return ret;
+}
+
+int PlayerControl::HandleMsgWithNoParam(const MsgInfo &msgInfo)
+{
+ int32_t ret;
+ switch (msgInfo.what) {
+ case PLAYERCONTROL_MSG_PREPARE:
+ ret = DoPrepare();
+ break;
+ case PLAYERCONTROL_MSG_PLAY:
+ ret = DoPlay();
+ break;
+ case PLAYERCONTROL_MSG_PAUSE:
+ ret = DoPause();
+ break;
+ case PLAYERCONTROL_MSG_STOP:
+ ret = DoStop();
+ break;
+ case PLAYERCONTROL_MSG_HANDLEDATA:
+ ret = HI_SUCCESS;
+ break;
+ default:
+ ret = HI_ERR_PLAYERCONTROL_ILLEGAL_PARAM;
+ break;
+ }
+
+ return ret;
+}
+
+int PlayerControl::HandleMessage(const MsgInfo &msgInfo)
+{
+ int32_t ret = HI_FAILURE;
+ if (!EventValidAtCurState(static_cast<PlayerControlMsgType>(msgInfo.what))) {
+ MEDIA_ERR_LOG("invalid event :%d at current state: %d", msgInfo.what, GetCurState());
+ return HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION;
+ }
+
+ switch (msgInfo.what) {
+ case PLAYERCONTROL_MSG_REGCALLBACK:
+ case PLAYERCONTROL_MSG_SET_DATASOURCE_URI:
+ case PLAYERCONTROL_MSG_SET_DATASOURCE_FD:
+ case PLAYERCONTROL_MSG_SET_DATASOURCE_STREAM:
+ case PLAYERCONTROL_MSG_SETATTR:
+ case PLAYERCONTROL_MSG_SETSPEED:
+ case PLAYERCONTROL_MSG_SET_VOLUME:
+ case PLAYERCONTROL_MSG_SEEK:
+ case PLAYERCONTROL_MSG_GETFILEINFO:
+ case PLAYERCONTROL_MSG_INVOKE:
+ ret = HandleMsgWithParam(msgInfo);
+ break;
+ case PLAYERCONTROL_MSG_PAUSE:
+ case PLAYERCONTROL_MSG_PREPARE:
+ case PLAYERCONTROL_MSG_PLAY:
+ case PLAYERCONTROL_MSG_HANDLEDATA:
+ case PLAYERCONTROL_MSG_STOP:
+ ret = HandleMsgWithNoParam(msgInfo);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+void PlayerControl::OnEventHandled(int event, int result) const
+{
+ if ((result == HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION) && (event == PLAYERCONTROL_MSG_SEEK)) {
+ NotifyError(PLAYERCONTROL_ERROR_ILLEGAL_STATEACTION);
+ }
+}
+
+int32_t PlayerControl::OnMessageReceived(const MsgInfo &msg)
+{
+ int32_t ret = HandleMessage(msg);
+ if (ret == HI_SUCCESS) {
+ PlayerStatus nextState = FindTransition(GetCurState(), msg.what);
+ curState_ = nextState;
+ StateChangeCallback(curState_);
+ }
+ OnEventHandled(msg.what, ret);
+ return ret;
+}
+
+PlayerStatus PlayerControl::GetCurState(void)
+{
+ return curState_;
+}
+
+PlayerStatus PlayerControl::FindTransition(PlayerStatus state, int32_t event) const
+{
+ for (uint32_t i = 0; i < STATE_TRANS_STATE_SIZE; i++) {
+ if (event == STATE_MACHINE[state][i].msgType) {
+ return STATE_MACHINE[state][i].newState;
+ }
+ }
+ return state;
+}
+
+bool PlayerControl::EventValidAtCurState(PlayerControlMsgType type)
+{
+ if (type < PLAYERCONTROL_MSG_SETATTR || type >= PLAYERCONTROL_MSG_BUTT) {
+ MEDIA_ERR_LOG("EventValidAtCurState MSG type not support %d", type);
+ return false;
+ }
+ if (GetCurState() < 0 || GetCurState() >= PLAY_STATUS_BUTT) {
+ MEDIA_ERR_LOG("EventValidAtCurState cur state not support %d", GetCurState());
+ return false;
+ }
+ return LITEPLAY_STATE[type][GetCurState()];
+}
+bool PlayerControl::UIntMulIsOverflow64(uint64_t a, uint64_t b, uint64_t *value) const
+{
+ if (a == 0 || b == 0) {
+ return false;
+ }
+ if (UINT64_MAX / a < b) {
+ return true;
+ }
+
+ uint64_t result = static_cast<uint64_t>((a) * (b));
+ if (value != nullptr) {
+ *value = result;
+ }
+ return false;
+}
+bool PlayerControl::UIntMulIsOverflow32(uint32_t a, uint32_t b, uint32_t *value) const
+{
+ if (a == 0 || b == 0) {
+ return false;
+ }
+ if (UINT32_MAX / a < b) {
+ return true;
+ }
+
+ long long result = static_cast<long long>((a) * (b));
+ if (value != nullptr) {
+ *value = static_cast<uint32_t>(result);
+ }
+ return false;
+}
+}
+}