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 #ifdef SUPPORT_AVPLAYER_DRM
25 #include "i_keysession_service.h"
26 #endif
27
28 namespace {
29 const std::string REFERENCE_LIB_PATH = std::string(DRAGGING_PLAYER_PATH);
30 const std::string FILESEPARATOR = "/";
31 const std::string REFERENCE_LIB_NAME = "libvideo_dragging_player.z.so";
32 const std::string REFENCE_LIB_ABSOLUTE_PATH = REFERENCE_LIB_PATH + FILESEPARATOR + REFERENCE_LIB_NAME;
33 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_PLAYER, "DraggingPlayerAgent"};
34 }
35
36 namespace OHOS {
37 namespace Media {
38 using namespace Pipeline;
39
40 void *DraggingPlayerAgent::handler_ = nullptr;
41 DraggingPlayerAgent::CreateFunc DraggingPlayerAgent::createFunc_ = nullptr;
42 DraggingPlayerAgent::DestroyFunc DraggingPlayerAgent::destroyFunc_ = nullptr;
43 DraggingPlayerAgent::CheckSupportedFunc DraggingPlayerAgent::checkSupportedFunc_ = nullptr;
44 bool DraggingPlayerAgent::loaded_ = false;
45 std::mutex DraggingPlayerAgent::mtx_;
46
47 class VideoStreamReadyCallbackImpl : public VideoStreamReadyCallback {
48 public:
VideoStreamReadyCallbackImpl(const std::shared_ptr<DraggingDelegator> draggingDelegator)49 explicit VideoStreamReadyCallbackImpl(const std::shared_ptr<DraggingDelegator> draggingDelegator)
50 : draggingDelegator_(draggingDelegator) {}
IsVideoStreamDiscardable(const std::shared_ptr<AVBuffer> buffer)51 bool IsVideoStreamDiscardable(const std::shared_ptr<AVBuffer> buffer) override
52 {
53 auto draggingDelegator = draggingDelegator_.lock();
54 FALSE_RETURN_V_MSG(draggingDelegator != nullptr && buffer != nullptr, false, "invalid parameter");
55 return draggingDelegator->IsVideoStreamDiscardable(buffer);
56 }
57 private:
58 std::weak_ptr<DraggingDelegator> draggingDelegator_;
59 };
60
61 class VideoFrameReadyCallbackImpl : public VideoFrameReadyCallback {
62 public:
VideoFrameReadyCallbackImpl(const std::shared_ptr<DraggingDelegator> draggingDelegator)63 explicit VideoFrameReadyCallbackImpl(const std::shared_ptr<DraggingDelegator> draggingDelegator)
64 : draggingDelegator_(draggingDelegator) {}
ConsumeVideoFrame(const std::shared_ptr<AVBuffer> buffer,uint32_t bufferIndex)65 void ConsumeVideoFrame(const std::shared_ptr<AVBuffer> buffer, uint32_t bufferIndex) override
66 {
67 auto draggingDelegator = draggingDelegator_.lock();
68 FALSE_RETURN_MSG(draggingDelegator != nullptr && buffer != nullptr, "invalid parameter");
69 draggingDelegator->ConsumeVideoFrame(buffer, bufferIndex);
70 }
71 private:
72 std::weak_ptr<DraggingDelegator> draggingDelegator_;
73 };
74
Create(const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,const shared_ptr<DemuxerFilter> demuxer,const shared_ptr<DecoderSurfaceFilter> decoder,const string & playerId)75 shared_ptr<DraggingPlayerAgent> DraggingPlayerAgent::Create(
76 const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,
77 const shared_ptr<DemuxerFilter> demuxer,
78 const shared_ptr<DecoderSurfaceFilter> decoder,
79 const string &playerId)
80 {
81 FALSE_RETURN_V_MSG_E(demuxer != nullptr && decoder != nullptr, nullptr, "Invalid demuxer filter instance.");
82 shared_ptr<DraggingPlayerAgent> agent = make_shared<DraggingPlayerAgent>(pipeline, demuxer, decoder, playerId);
83 FALSE_RETURN_V(DraggingPlayerAgent::LoadSymbol(), agent);
84 FALSE_RETURN_V(DraggingPlayerAgent::IsDraggingSupported(demuxer, decoder), agent);
85 agent->draggingMode_ = DraggingMode::DRAGGING_CONTINUOUS;
86 return agent;
87 }
88
IsDraggingSupported(const shared_ptr<DemuxerFilter> demuxer,const shared_ptr<DecoderSurfaceFilter> decoder)89 bool DraggingPlayerAgent::IsDraggingSupported(const shared_ptr<DemuxerFilter> demuxer,
90 const shared_ptr<DecoderSurfaceFilter> decoder)
91 {
92 FALSE_RETURN_V_MSG_E(demuxer != nullptr && decoder != nullptr, false, "demuxer or decoder is null");
93 FALSE_RETURN_V_MSG_E(demuxer->IsLocalFd(), false, "source is not local fd");
94 FALSE_RETURN_V_MSG_E(LoadSymbol() && checkSupportedFunc_ != nullptr, false, "no so");
95 return checkSupportedFunc_(demuxer.get(), decoder.get());
96 }
97
DraggingPlayerAgent(const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,const shared_ptr<DemuxerFilter> demuxer,const shared_ptr<DecoderSurfaceFilter> decoder,const string & playerId)98 DraggingPlayerAgent::DraggingPlayerAgent(
99 const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,
100 const shared_ptr<DemuxerFilter> demuxer,
101 const shared_ptr<DecoderSurfaceFilter> decoder,
102 const string &playerId)
103 : pipeline_(pipeline), demuxer_(demuxer), decoder_(decoder), playerId_(playerId)
104 {
105 }
106
~DraggingPlayerAgent()107 DraggingPlayerAgent::~DraggingPlayerAgent()
108 {
109 if (!isReleased_) {
110 Release();
111 }
112 if (delegator_ != nullptr) {
113 delegator_ = nullptr;
114 }
115 }
116
Init()117 Status DraggingPlayerAgent::Init()
118 {
119 FALSE_RETURN_V_MSG_E(demuxer_ != nullptr && decoder_ != nullptr,
120 Status::ERROR_INVALID_PARAMETER, "Invalid demuxer filter instance.");
121 delegator_ = DraggingDelegatorFactory::CreateDelegator(pipeline_, demuxer_, decoder_, playerId_, draggingMode_);
122 FALSE_RETURN_V_MSG_E(delegator_ != nullptr, Status::ERROR_INVALID_DATA, "delegator_ is null");
123 return Status::OK;
124 }
125
UpdateSeekPos(int64_t seekMs)126 void DraggingPlayerAgent::UpdateSeekPos(int64_t seekMs)
127 {
128 FALSE_RETURN_MSG(delegator_ != nullptr, "delegator_ is null");
129 delegator_->UpdateSeekPos(seekMs);
130 }
131
Release()132 void DraggingPlayerAgent::Release()
133 {
134 std::unique_lock<std::mutex> lock(draggingMutex_);
135 delegator_->Release();
136 isReleased_ = true;
137 }
138
GetDraggingMode()139 DraggingMode DraggingPlayerAgent::GetDraggingMode()
140 {
141 return draggingMode_;
142 }
143
LoadLibrary()144 void *DraggingPlayerAgent::LoadLibrary()
145 {
146 char path[PATH_MAX] = {0x00};
147 const char *inputPath = REFENCE_LIB_ABSOLUTE_PATH.c_str();
148 if (strlen(inputPath) > PATH_MAX || realpath(inputPath, path) == nullptr) {
149 MEDIA_LOG_E("dlopen failed due to Invalid path");
150 return nullptr;
151 }
152 auto ptr = ::dlopen(path, RTLD_NOW | RTLD_LOCAL);
153 FALSE_RETURN_V_MSG_E(ptr != nullptr, nullptr, "dlopen failed due to %{public}s", ::dlerror());
154 handler_ = ptr;
155 return ptr;
156 }
157
CheckSymbol(void * handler)158 bool DraggingPlayerAgent::CheckSymbol(void *handler)
159 {
160 FALSE_RETURN_V_MSG_E(handler != nullptr, false, "handler is nullptr");
161 std::string createFuncName = "CreateDraggingPlayer";
162 std::string destroyFuncName = "DestroyDraggingPlayer";
163 std::string checkSupportedFuncName = "IsDraggingSupported";
164 CreateFunc createFunc = nullptr;
165 DestroyFunc destroyFunc = nullptr;
166 CheckSupportedFunc checkSupportedFunc = nullptr;
167 createFunc = (CreateFunc)(::dlsym(handler, createFuncName.c_str()));
168 destroyFunc = (DestroyFunc)(::dlsym(handler, destroyFuncName.c_str()));
169 checkSupportedFunc = (CheckSupportedFunc)(::dlsym(handler, checkSupportedFuncName.c_str()));
170 FALSE_RETURN_V_MSG_E(checkSupportedFunc != nullptr, false, "check supported func is nullptr");
171 checkSupportedFunc_ = checkSupportedFunc;
172 FALSE_RETURN_V_MSG_E(createFunc != nullptr && destroyFunc != nullptr, false, "create or destroy func is nullptr");
173 MEDIA_LOG_I("CheckSymbol: createFuncName %{public}s, destroyFuncName %{public}s", createFuncName.c_str(),
174 destroyFuncName.c_str());
175 createFunc_ = createFunc;
176 destroyFunc_ = destroyFunc;
177 return true;
178 }
179
LoadSymbol()180 bool DraggingPlayerAgent::LoadSymbol()
181 {
182 lock_guard<mutex> lock(mtx_);
183 FALSE_RETURN_V_MSG_E(!loaded_ || handler_ != nullptr, false, "loaded but no handler");
184 FALSE_RETURN_V_NOLOG(handler_ == nullptr, true);
185 loaded_ = true;
186 FALSE_RETURN_V_MSG_E(CheckSymbol(LoadLibrary()), false, "Load Reference parser so fail");
187 return true;
188 }
189
CreateDelegator(const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,const shared_ptr<DemuxerFilter> demuxer,const shared_ptr<DecoderSurfaceFilter> decoder,const string & playerId,DraggingMode & draggingMode)190 shared_ptr<DraggingDelegator> DraggingDelegatorFactory::CreateDelegator(
191 const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,
192 const shared_ptr<DemuxerFilter> demuxer,
193 const shared_ptr<DecoderSurfaceFilter> decoder,
194 const string &playerId,
195 DraggingMode &draggingMode)
196 {
197 FALSE_RETURN_V_MSG_E(draggingMode != DraggingMode::DRAGGING_NONE, nullptr, "Invalid draggingMode.");
198 shared_ptr<DraggingDelegator> delegator = nullptr;
199 if (draggingMode == DraggingMode::DRAGGING_CONTINUOUS) {
200 shared_ptr<DraggingDelegator> delegator
201 = SeekContinuousDelegator::Create(pipeline, demuxer, decoder, playerId);
202 FALSE_RETURN_V_NOLOG(delegator == nullptr, delegator);
203 }
204 draggingMode = DraggingMode::DRAGGING_CLOSEST;
205 return SeekClosestDelegator::Create(pipeline, demuxer, decoder, playerId);
206 }
207
Create(const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,const shared_ptr<DemuxerFilter> demuxer,const shared_ptr<DecoderSurfaceFilter> decoder,const string & playerId)208 shared_ptr<SeekContinuousDelegator> SeekContinuousDelegator::Create(
209 const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,
210 const shared_ptr<DemuxerFilter> demuxer,
211 const shared_ptr<DecoderSurfaceFilter> decoder,
212 const string &playerId)
213 {
214 shared_ptr<SeekContinuousDelegator> delegator
215 = make_shared<SeekContinuousDelegator>(pipeline, demuxer, decoder, playerId);
216 FALSE_RETURN_V_MSG_E(delegator != nullptr && delegator->draggingPlayer_ != nullptr,
217 nullptr, "delegator is nullptr");
218 Status ret = delegator->Init();
219 if (ret != Status::OK) {
220 delegator = nullptr;
221 }
222 return delegator;
223 }
224
SeekContinuousDelegator(const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,const shared_ptr<DemuxerFilter> demuxer,const shared_ptr<DecoderSurfaceFilter> decoder,const string & playerId)225 SeekContinuousDelegator::SeekContinuousDelegator(
226 const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,
227 const shared_ptr<DemuxerFilter> demuxer,
228 const shared_ptr<DecoderSurfaceFilter> decoder,
229 const string &playerId)
230 : DraggingDelegator(pipeline, demuxer, decoder, playerId)
231 {
232 if (DraggingPlayerAgent::createFunc_ != nullptr) {
233 draggingPlayer_ = DraggingPlayerAgent::createFunc_();
234 }
235 }
236
~SeekContinuousDelegator()237 SeekContinuousDelegator::~SeekContinuousDelegator()
238 {
239 if (!isReleased_) {
240 Release();
241 }
242 PipeLineThreadPool::GetInstance().DestroyThread(threadName_);
243 if (draggingPlayer_ != nullptr) {
244 DraggingPlayerAgent::destroyFunc_(draggingPlayer_);
245 draggingPlayer_ = nullptr;
246 }
247 }
248
Init()249 Status SeekContinuousDelegator::Init()
250 {
251 MEDIA_LOG_I("SeekContinuousDelegator::Init");
252 FALSE_RETURN_V_MSG_E(demuxer_ != nullptr && decoder_ != nullptr,
253 Status::ERROR_INVALID_PARAMETER, "Invalid demuxer filter instance.");
254 Status ret = draggingPlayer_->Init(demuxer_, decoder_);
255 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "SeekContinuousDelegator::Init failed");
256 videoStreamReadyCb_ = std::make_shared<VideoStreamReadyCallbackImpl>(shared_from_this());
257 demuxer_->RegisterVideoStreamReadyCallback(videoStreamReadyCb_);
258 videoFrameReadyCb_ = std::make_shared<VideoFrameReadyCallbackImpl>(shared_from_this());
259 decoder_->RegisterVideoFrameReadyCallback(videoFrameReadyCb_);
260 threadName_ = "DraggingTask_" + playerId_;
261 monitorTask_ = std::make_unique<Task>("draggingThread", threadName_, TaskType::GLOBAL, TaskPriority::NORMAL, false);
262 monitorTask_->Start();
263 return Status::OK;
264 }
265
UpdateSeekPos(int64_t seekMs)266 void SeekContinuousDelegator::UpdateSeekPos(int64_t seekMs)
267 {
268 std::unique_lock<std::mutex> lock(draggingMutex_);
269 FALSE_RETURN(draggingPlayer_ != nullptr);
270 seekCnt_.fetch_add(1);
271 draggingPlayer_->UpdateSeekPos(seekMs);
272 if (monitorTask_ != nullptr) {
273 int64_t seekCnt = seekCnt_.load();
274 lock.unlock();
275 monitorTask_->SubmitJob([this, seekCnt]() { StopDragging(seekCnt); }, 33333); // 33333 means 33333us, 33ms
276 }
277 }
278
Release()279 void SeekContinuousDelegator::Release()
280 {
281 MEDIA_LOG_I("SeekContinuousDelegator::Release");
282 if (monitorTask_) {
283 monitorTask_->Stop();
284 }
285 std::unique_lock<std::mutex> lock(draggingMutex_);
286 if (draggingPlayer_ != nullptr) {
287 draggingPlayer_->Release();
288 }
289 if (draggingPlayer_ != nullptr) {
290 auto res = demuxer_->PauseDragging();
291 FALSE_LOG_MSG(res == Status::OK, "PauseDragging failed");
292 }
293 if (demuxer_ != nullptr) {
294 demuxer_->DeregisterVideoStreamReadyCallback();
295 }
296 if (decoder_ != nullptr) {
297 decoder_->DeregisterVideoFrameReadyCallback();
298 }
299 isReleased_ = true;
300 }
301
ConsumeVideoFrame(const std::shared_ptr<AVBuffer> avBuffer,uint32_t bufferIndex)302 void SeekContinuousDelegator::ConsumeVideoFrame(const std::shared_ptr<AVBuffer> avBuffer, uint32_t bufferIndex)
303 {
304 FALSE_RETURN(draggingPlayer_ != nullptr);
305 draggingPlayer_->ConsumeVideoFrame(avBuffer, bufferIndex);
306 }
307
IsVideoStreamDiscardable(const std::shared_ptr<AVBuffer> avBuffer)308 bool SeekContinuousDelegator::IsVideoStreamDiscardable(const std::shared_ptr<AVBuffer> avBuffer)
309 {
310 FALSE_RETURN_V_MSG_E(draggingPlayer_ != nullptr, false, "Invalid draggingPlayer_ instance.");
311 return draggingPlayer_->IsVideoStreamDiscardable(avBuffer);
312 }
313
StopDragging(int64_t seekCnt)314 void SeekContinuousDelegator::StopDragging(int64_t seekCnt)
315 {
316 std::unique_lock<std::mutex> lock(draggingMutex_);
317 FALSE_RETURN(!isReleased_);
318 FALSE_RETURN(draggingPlayer_ != nullptr);
319 FALSE_RETURN_NOLOG(seekCnt_.load() == seekCnt);
320 draggingPlayer_->StopDragging();
321 }
322
Create(const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,const shared_ptr<DemuxerFilter> demuxer,const shared_ptr<DecoderSurfaceFilter> decoder,const string & playerId)323 shared_ptr<SeekClosestDelegator> SeekClosestDelegator::Create(
324 const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,
325 const shared_ptr<DemuxerFilter> demuxer,
326 const shared_ptr<DecoderSurfaceFilter> decoder,
327 const string &playerId)
328 {
329 shared_ptr<SeekClosestDelegator> delegator
330 = make_shared<SeekClosestDelegator>(pipeline, demuxer, decoder, playerId);
331 FALSE_RETURN_V_MSG_E(delegator != nullptr, delegator, "delegator is nullptr");
332 Status ret = delegator->Init();
333 if (ret != Status::OK) {
334 delegator = nullptr;
335 }
336 return delegator;
337 }
338
SeekClosestDelegator(const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,const shared_ptr<DemuxerFilter> demuxer,const shared_ptr<DecoderSurfaceFilter> decoder,const std::string & playerId)339 SeekClosestDelegator::SeekClosestDelegator(
340 const shared_ptr<OHOS::Media::Pipeline::Pipeline> pipeline,
341 const shared_ptr<DemuxerFilter> demuxer,
342 const shared_ptr<DecoderSurfaceFilter> decoder,
343 const std::string &playerId)
344 : DraggingDelegator(pipeline, demuxer, decoder, playerId)
345 {
346 }
347
~SeekClosestDelegator()348 SeekClosestDelegator::~SeekClosestDelegator()
349 {
350 if (!isReleased_) {
351 Release();
352 }
353 PipeLineThreadPool::GetInstance().DestroyThread(threadName_);
354 }
355
Init()356 Status SeekClosestDelegator::Init()
357 {
358 MEDIA_LOG_I("SeekClosestDelegator::Init");
359 threadName_ = "SeekTask_" + playerId_;
360 seekTask_ = std::make_unique<Task>("seekThread", threadName_, TaskType::GLOBAL, TaskPriority::NORMAL, false);
361 seekTask_->Start();
362 return Status::OK;
363 }
364
UpdateSeekPos(int64_t seekMs)365 void SeekClosestDelegator::UpdateSeekPos(int64_t seekMs)
366 {
367 lock_guard<mutex> lock(queueMutex_);
368 seekTimeMsQue_.push_back(seekMs);
369 if (seekTimeMsQue_.size() == 1) {
370 seekTask_->SubmitJob([this]() { SeekJob(); });
371 }
372 }
373
Release()374 void SeekClosestDelegator::Release()
375 {
376 MEDIA_LOG_I("SeekClosestDelegator::Release");
377 if (seekTask_) {
378 seekTask_->Stop();
379 }
380 int64_t lastSeekTimeMs = -1;
381 {
382 lock_guard<mutex> lock(queueMutex_);
383 if (seekTimeMsQue_.size() > 0) {
384 lastSeekTimeMs = seekTimeMsQue_.back();
385 seekTimeMsQue_.clear();
386 }
387 }
388 DoSeek(lastSeekTimeMs);
389 isReleased_ = true;
390 }
391
SeekJob()392 void SeekClosestDelegator::SeekJob()
393 {
394 int64_t seekTimeMs = -1;
395 {
396 lock_guard<mutex> lock(queueMutex_);
397 if (seekTimeMsQue_.size() <= 0) {
398 return;
399 }
400 seekTimeMs = seekTimeMsQue_.back();
401 seekTimeMsQue_.clear();
402 }
403 DoSeek(seekTimeMs);
404 }
405
DoSeek(int64_t seekTimeMs)406 void SeekClosestDelegator::DoSeek(int64_t seekTimeMs)
407 {
408 FALSE_RETURN_MSG(seekTimeMs >= 0, "invalid seekTimeMs");
409 FALSE_RETURN_MSG(pipeline_ != nullptr && demuxer_ != nullptr && decoder_ != nullptr, "key objects is null");
410 lock_guard<mutex> lock(seekClosestMutex_);
411 FALSE_RETURN_MSG(seekTimeMs != curSeekTimeMs_, "the same seek time with last seek;");
412 curSeekTimeMs_ = seekTimeMs;
413 int64_t seekTimeUs = 0;
414 FALSE_RETURN_MSG(Plugins::Us2HstTime(seekTimeMs, seekTimeUs), "cast seekTime ms to us failed");
415 pipeline_->Flush();
416 decoder_->SetSeekTime(seekTimeUs);
417 int64_t realSeekTimeMs = seekTimeMs;
418 Status res = demuxer_->SeekTo(seekTimeMs, Plugins::SeekMode::SEEK_CLOSEST_INNER, realSeekTimeMs);
419 FALSE_RETURN_MSG(res == Status::OK, "demuxer seekto error.");
420 pipeline_->Preroll(true);
421 }
422 } // namespace Media
423 } // namespace OHOS