1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define HST_LOG_TAG "DraggingPlayerAgent"
17 
18 #include <dlfcn.h>
19 
20 #include "common/log.h"
21 #include "dragging_player_agent.h"
22 #include "osal/task/pipeline_threadpool.h"
23 
24 namespace {
25 const std::string REFERENCE_LIB_PATH = std::string(DRAGGING_PLAYER_PATH);
26 const std::string FILESEPARATOR = "/";
27 const std::string REFERENCE_LIB_NAME = "libvideo_dragging_player.z.so";
28 const std::string REFENCE_LIB_ABSOLUTE_PATH = REFERENCE_LIB_PATH + FILESEPARATOR + REFERENCE_LIB_NAME;
29 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_PLAYER, "DraggingPlayerAgent"};
30 }
31 
32 namespace OHOS {
33 namespace Media {
34 
35 void *DraggingPlayerAgent::handler_ = nullptr;
36 DraggingPlayerAgent::CreateFunc DraggingPlayerAgent::createFunc_ = nullptr;
37 DraggingPlayerAgent::DestroyFunc DraggingPlayerAgent::destroyFunc_ = nullptr;
38 DraggingPlayerAgent::CheckSupportedFunc DraggingPlayerAgent::checkSupportedFunc_ = nullptr;
39 bool DraggingPlayerAgent::loaded_ = false;
40 std::mutex DraggingPlayerAgent::mtx_;
41 
42 class VideoStreamReadyCallbackImpl : public VideoStreamReadyCallback {
43 public:
VideoStreamReadyCallbackImpl(const std::shared_ptr<DraggingPlayerAgent> draggingPlayerAgent)44     explicit VideoStreamReadyCallbackImpl(const std::shared_ptr<DraggingPlayerAgent> draggingPlayerAgent)
45         : draggingPlayerAgent_(draggingPlayerAgent) {}
IsVideoStreamDiscardable(const std::shared_ptr<AVBuffer> buffer)46     bool IsVideoStreamDiscardable(const std::shared_ptr<AVBuffer> buffer) override
47     {
48         auto draggingPlayerAgent = draggingPlayerAgent_.lock();
49         if (draggingPlayerAgent != nullptr && buffer != nullptr) {
50             return draggingPlayerAgent->IsVideoStreamDiscardable(buffer);
51         }
52         return false;
53     }
54 private:
55     std::weak_ptr<DraggingPlayerAgent> draggingPlayerAgent_;
56 };
57 
58 class VideoFrameReadyCallbackImpl : public VideoFrameReadyCallback {
59 public:
VideoFrameReadyCallbackImpl(const std::shared_ptr<DraggingPlayerAgent> draggingPlayerAgent)60     explicit VideoFrameReadyCallbackImpl(const std::shared_ptr<DraggingPlayerAgent> draggingPlayerAgent)
61         : draggingPlayerAgent_(draggingPlayerAgent) {}
ConsumeVideoFrame(const std::shared_ptr<AVBuffer> buffer,uint32_t bufferIndex)62     void ConsumeVideoFrame(const std::shared_ptr<AVBuffer> buffer, uint32_t bufferIndex) override
63     {
64         auto draggingPlayerAgent = draggingPlayerAgent_.lock();
65         if (draggingPlayerAgent != nullptr && buffer != nullptr) {
66             return draggingPlayerAgent->ConsumeVideoFrame(buffer, bufferIndex);
67         }
68     }
69 private:
70     std::weak_ptr<DraggingPlayerAgent> draggingPlayerAgent_;
71 };
72 
Create()73 shared_ptr<DraggingPlayerAgent> DraggingPlayerAgent::Create()
74 {
75     shared_ptr<DraggingPlayerAgent> agent = make_shared<DraggingPlayerAgent>();
76     if (!agent->LoadSymbol()) {
77         return nullptr;
78     }
79     agent->draggingPlayer_ = agent->createFunc_();
80     if (agent->draggingPlayer_ == nullptr) {
81         MEDIA_LOG_E("createFunc_ fail");
82         return nullptr;
83     }
84 
85     return agent;
86 }
87 
IsDraggingSupported(const shared_ptr<DemuxerFilter> & demuxer,const shared_ptr<DecoderSurfaceFilter> & decoder)88 bool DraggingPlayerAgent::IsDraggingSupported(const shared_ptr<DemuxerFilter> &demuxer,
89     const shared_ptr<DecoderSurfaceFilter> &decoder)
90 {
91     if (!LoadSymbol() || checkSupportedFunc_ == nullptr) {
92         return false;
93     }
94     return checkSupportedFunc_(demuxer.get(), decoder.get());
95 }
96 
~DraggingPlayerAgent()97 DraggingPlayerAgent::~DraggingPlayerAgent()
98 {
99     if (!isReleased_) {
100         Release();
101     }
102     PipeLineThreadPool::GetInstance().DestroyThread(threadName_);
103     if (draggingPlayer_ != nullptr) {
104         destroyFunc_(draggingPlayer_);
105         draggingPlayer_ = nullptr;
106     }
107 }
108 
Init(const shared_ptr<DemuxerFilter> & demuxer,const shared_ptr<DecoderSurfaceFilter> & decoder,std::string playerId)109 Status DraggingPlayerAgent::Init(const shared_ptr<DemuxerFilter> &demuxer,
110     const shared_ptr<DecoderSurfaceFilter> &decoder, std::string playerId)
111 {
112     FALSE_RETURN_V_MSG_E(demuxer != nullptr && decoder != nullptr,
113         Status::ERROR_INVALID_PARAMETER, "Invalid demuxer filter instance.");
114     demuxer_ = demuxer;
115     decoder_ = decoder;
116     Status ret = draggingPlayer_->Init(demuxer, decoder);
117     if (ret != Status::OK) {
118         MEDIA_LOG_E("liyudebug DraggingPlayerAgent::Init failed");
119         return ret;
120     }
121     MEDIA_LOG_I("DraggingPlayerAgent::Init register");
122     videoStreamReadyCb_ = std::make_shared<VideoStreamReadyCallbackImpl>(shared_from_this());
123     demuxer->RegisterVideoStreamReadyCallback(videoStreamReadyCb_);
124     videoFrameReadyCb_ = std::make_shared<VideoFrameReadyCallbackImpl>(shared_from_this());
125     decoder->RegisterVideoFrameReadyCallback(videoFrameReadyCb_);
126     threadName_ = "DraggingTask_" + playerId;
127     task_ = std::make_unique<Task>("draggingThread", threadName_, TaskType::GLOBAL, TaskPriority::NORMAL, false);
128     task_->Start();
129     return Status::OK;
130 }
131 
IsVideoStreamDiscardable(const std::shared_ptr<AVBuffer> avBuffer)132 bool DraggingPlayerAgent::IsVideoStreamDiscardable(const std::shared_ptr<AVBuffer> avBuffer)
133 {
134     FALSE_RETURN_V_MSG_E(draggingPlayer_ != nullptr, false, "Invalid draggingPlayer_ instance.");
135     return draggingPlayer_->IsVideoStreamDiscardable(avBuffer);
136 }
137 
ConsumeVideoFrame(const std::shared_ptr<AVBuffer> avBuffer,uint32_t bufferIndex)138 void DraggingPlayerAgent::ConsumeVideoFrame(const std::shared_ptr<AVBuffer> avBuffer, uint32_t bufferIndex)
139 {
140     FALSE_RETURN(draggingPlayer_ != nullptr);
141     draggingPlayer_->ConsumeVideoFrame(avBuffer, bufferIndex);
142 }
143 
UpdateSeekPos(int64_t seekMs)144 void DraggingPlayerAgent::UpdateSeekPos(int64_t seekMs)
145 {
146     std::unique_lock<std::mutex> lock(draggingMutex_);
147     FALSE_RETURN(draggingPlayer_ != nullptr);
148     seekCnt_.fetch_add(1);
149     draggingPlayer_->UpdateSeekPos(seekMs);
150     if (task_) {
151         int64_t seekCnt = seekCnt_.load();
152         lock.unlock();
153         task_->SubmitJob([this, seekCnt]() { StopDragging(seekCnt); }, 33333); // 33333 means 33333us, 33ms
154     }
155 }
156 
StopDragging(int64_t seekCnt)157 void DraggingPlayerAgent::StopDragging(int64_t seekCnt)
158 {
159     std::unique_lock<std::mutex> lock(draggingMutex_);
160     FALSE_RETURN(!isReleased_);
161     FALSE_RETURN(draggingPlayer_ != nullptr);
162     if (seekCnt_.load() != seekCnt) {
163         return;
164     }
165     draggingPlayer_->StopDragging();
166 }
167 
Release()168 void DraggingPlayerAgent::Release()
169 {
170     if (task_) {
171         task_->Stop();
172     }
173     std::unique_lock<std::mutex> lock(draggingMutex_);
174     if (draggingPlayer_ != nullptr) {
175         draggingPlayer_->Release();
176     }
177     if (draggingPlayer_ != nullptr) {
178         auto res = demuxer_->PauseDragging();
179         FALSE_LOG_MSG(res == Status::OK, "PauseDragging failed");
180     }
181     if (demuxer_ != nullptr) {
182         demuxer_->DeregisterVideoStreamReadyCallback();
183     }
184     if (decoder_ != nullptr) {
185         decoder_->DeregisterVideoFrameReadyCallback();
186     }
187     isReleased_ = true;
188 }
189 
LoadLibrary()190 void *DraggingPlayerAgent::LoadLibrary()
191 {
192     char path[PATH_MAX] = {0x00};
193     const char *inputPath = REFENCE_LIB_ABSOLUTE_PATH.c_str();
194     if (strlen(inputPath) > PATH_MAX || realpath(inputPath, path) == nullptr) {
195         MEDIA_LOG_E("dlopen failed due to Invalid path");
196         return nullptr;
197     }
198     auto ptr = ::dlopen(path, RTLD_NOW | RTLD_LOCAL);
199     if (ptr == nullptr) {
200         MEDIA_LOG_E("dlopen failed due to %{public}s", ::dlerror());
201     }
202     handler_ = ptr;
203     return ptr;
204 }
205 
CheckSymbol(void * handler)206 bool DraggingPlayerAgent::CheckSymbol(void *handler)
207 {
208     if (handler) {
209         std::string createFuncName = "CreateDraggingPlayer";
210         std::string destroyFuncName = "DestroyDraggingPlayer";
211         std::string checkSupportedFuncName = "IsDraggingSupported";
212         CreateFunc createFunc = nullptr;
213         DestroyFunc destroyFunc = nullptr;
214         CheckSupportedFunc checkSupportedFunc = nullptr;
215         createFunc = (CreateFunc)(::dlsym(handler, createFuncName.c_str()));
216         destroyFunc = (DestroyFunc)(::dlsym(handler, destroyFuncName.c_str()));
217         checkSupportedFunc = (CheckSupportedFunc)(::dlsym(handler, checkSupportedFuncName.c_str()));
218         if (checkSupportedFunc != nullptr) {
219             checkSupportedFunc_ = checkSupportedFunc;
220         }
221         if (createFunc && destroyFunc) {
222             MEDIA_LOG_D("CheckSymbol:  createFuncName %{public}s", createFuncName.c_str());
223             MEDIA_LOG_D("CheckSymbol:  destroyFuncName %{public}s", destroyFuncName.c_str());
224             createFunc_ = createFunc;
225             destroyFunc_ = destroyFunc;
226             return true;
227         }
228     }
229     return false;
230 }
231 
LoadSymbol()232 bool DraggingPlayerAgent::LoadSymbol()
233 {
234     lock_guard<mutex> lock(mtx_);
235     if (loaded_ && handler_ == nullptr) {
236         return false;
237     }
238     if (handler_ == nullptr) {
239         loaded_ = true;
240         if (!CheckSymbol(LoadLibrary())) {
241             MEDIA_LOG_E("Load Reference parser so fail");
242             return false;
243         }
244     }
245     return true;
246 }
247 }  // namespace Media
248 }  // namespace OHOS