1 /*
2 * Copyright (C) 2021 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 #include "playbin_ctrler_base.h"
17 #include <gst/playback/gstplay-enum.h>
18 #include "nocopyable.h"
19 #include "string_ex.h"
20 #include "media_errors.h"
21 #include "media_log.h"
22 #include "player.h"
23 #include "format.h"
24 #include "uri_helper.h"
25 #include "scope_guard.h"
26 #include "playbin_state.h"
27 #include "gst_utils.h"
28 #include "media_dfx.h"
29 #include "player_xcollie.h"
30 #include "param_wrapper.h"
31
32 namespace {
33 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PlayBinCtrlerBase"};
34 constexpr uint64_t RING_BUFFER_MAX_SIZE = 5242880; // 5 * 1024 * 1024
35 constexpr int32_t PLAYBIN_QUEUE_MAX_SIZE = 100 * 1024 * 1024; // 100 * 1024 * 1024 Bytes
36 constexpr uint64_t BUFFER_DURATION = 15000000000; // 15s
37 constexpr int32_t BUFFER_LOW_PERCENT_DEFAULT = 1;
38 constexpr int32_t BUFFER_HIGH_PERCENT_DEFAULT = 4;
39 constexpr int32_t BUFFER_PERCENT_THRESHOLD = 100;
40 constexpr int32_t NANO_SEC_PER_USEC = 1000;
41 constexpr int32_t USEC_PER_MSEC = 1000;
42 constexpr double DEFAULT_RATE = 1.0;
43 constexpr uint32_t INTERRUPT_EVENT_SHIFT = 8;
44 constexpr uint64_t CONNECT_SPEED_DEFAULT = 4 * 8 * 1024 * 1024; // 4Mbps
45 constexpr uint32_t MAX_SUBTITLE_TRACK_NUN = 8;
46 }
47
48 namespace OHOS {
49 namespace Media {
50 static const std::unordered_map<int32_t, int32_t> SEEK_OPTION_TO_GST_SEEK_FLAGS = {
51 {
52 IPlayBinCtrler::PlayBinSeekMode::PREV_SYNC,
53 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_BEFORE,
54 },
55 {
56 IPlayBinCtrler::PlayBinSeekMode::NEXT_SYNC,
57 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_AFTER,
58 },
59 {
60 IPlayBinCtrler::PlayBinSeekMode::CLOSET_SYNC,
61 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_NEAREST,
62 },
63 {
64 IPlayBinCtrler::PlayBinSeekMode::CLOSET,
65 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
66 }
67 };
68
ElementSetup(const GstElement * playbin,GstElement * elem,gpointer userData)69 void PlayBinCtrlerBase::ElementSetup(const GstElement *playbin, GstElement *elem, gpointer userData)
70 {
71 (void)playbin;
72 CHECK_AND_RETURN_LOG(elem != nullptr, "elem is nullptr");
73 CHECK_AND_RETURN_LOG(userData != nullptr, "userData is nullptr");
74
75 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
76 if (thizStrong != nullptr) {
77 return thizStrong->OnElementSetup(*elem);
78 }
79 }
80
ElementUnSetup(const GstElement * playbin,GstElement * subbin,GstElement * child,gpointer userData)81 void PlayBinCtrlerBase::ElementUnSetup(const GstElement *playbin, GstElement *subbin,
82 GstElement *child, gpointer userData)
83 {
84 (void)playbin;
85 (void)subbin;
86 CHECK_AND_RETURN_LOG(child != nullptr, "elem is nullptr");
87 CHECK_AND_RETURN_LOG(userData != nullptr, "userData is nullptr");
88
89 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
90 if (thizStrong != nullptr) {
91 return thizStrong->OnElementUnSetup(*child);
92 }
93 }
94
SourceSetup(const GstElement * playbin,GstElement * elem,gpointer userData)95 void PlayBinCtrlerBase::SourceSetup(const GstElement *playbin, GstElement *elem, gpointer userData)
96 {
97 CHECK_AND_RETURN_LOG(elem != nullptr, "elem is nullptr");
98 CHECK_AND_RETURN_LOG(userData != nullptr, "userData is nullptr");
99
100 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
101 if (thizStrong != nullptr) {
102 return thizStrong->OnSourceSetup(playbin, elem, thizStrong);
103 }
104 }
105
PlayBinCtrlerBase(const PlayBinCreateParam & createParam)106 PlayBinCtrlerBase::PlayBinCtrlerBase(const PlayBinCreateParam &createParam)
107 : renderMode_(createParam.renderMode),
108 notifier_(createParam.notifier),
109 sinkProvider_(createParam.sinkProvider)
110 {
111 MEDIA_LOGD("enter ctor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
112 }
113
~PlayBinCtrlerBase()114 PlayBinCtrlerBase::~PlayBinCtrlerBase()
115 {
116 MEDIA_LOGD("enter dtor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
117 if (Reset() == MSERR_OK) {
118 sinkProvider_ = nullptr;
119 notifier_ = nullptr;
120 }
121 }
122
Init()123 int32_t PlayBinCtrlerBase::Init()
124 {
125 CHECK_AND_RETURN_RET_LOG(sinkProvider_ != nullptr, MSERR_INVALID_VAL, "sinkprovider is nullptr");
126
127 idleState_ = std::make_shared<IdleState>(*this);
128 initializedState_ = std::make_shared<InitializedState>(*this);
129 preparingState_ = std::make_shared<PreparingState>(*this);
130 preparedState_ = std::make_shared<PreparedState>(*this);
131 playingState_ = std::make_shared<PlayingState>(*this);
132 pausedState_ = std::make_shared<PausedState>(*this);
133 stoppingState_ = std::make_shared<StoppingState>(*this);
134 stoppedState_ = std::make_shared<StoppedState>(*this);
135 playbackCompletedState_ = std::make_shared<PlaybackCompletedState>(*this);
136
137 rate_ = DEFAULT_RATE;
138
139 ChangeState(idleState_);
140
141 msgQueue_ = std::make_unique<TaskQueue>("PlaybinCtrl");
142 int32_t ret = msgQueue_->Start();
143 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "msgqueue start failed");
144
145 return ret;
146 }
147
IsLiveSource() const148 bool PlayBinCtrlerBase::IsLiveSource() const
149 {
150 if (appsrcWrap_ != nullptr && appsrcWrap_->IsLiveMode()) {
151 return true;
152 }
153 return false;
154 }
155
EnableBufferingBySysParam() const156 bool PlayBinCtrlerBase::EnableBufferingBySysParam() const
157 {
158 std::string cmd;
159 int32_t ret = OHOS::system::GetStringParameter("sys.media.player.buffering.enable", cmd, "");
160 if (ret == 0 && !cmd.empty()) {
161 return cmd == "TRUE" ? TRUE : FALSE;
162 }
163 return FALSE;
164 }
165
SetSource(const std::string & url)166 int32_t PlayBinCtrlerBase::SetSource(const std::string &url)
167 {
168 std::unique_lock<std::mutex> lock(mutex_);
169 uri_ = url;
170 if (url.find("http") == 0 || url.find("https") == 0 || EnableBufferingBySysParam()) {
171 isNetWorkPlay_ = true;
172 }
173
174 MEDIA_LOGI("Set source: %{public}s", url.c_str());
175 return MSERR_OK;
176 }
177
SetSource(const std::shared_ptr<GstAppsrcEngine> & appsrcWrap)178 int32_t PlayBinCtrlerBase::SetSource(const std::shared_ptr<GstAppsrcEngine> &appsrcWrap)
179 {
180 std::unique_lock<std::mutex> lock(mutex_);
181 appsrcWrap_ = appsrcWrap;
182 return MSERR_OK;
183 }
184
AddSubSource(const std::string & url)185 int32_t PlayBinCtrlerBase::AddSubSource(const std::string &url)
186 {
187 MEDIA_LOGD("enter");
188
189 std::unique_lock<std::mutex> lock(mutex_);
190 ON_SCOPE_EXIT(0) {
191 OnAddSubDone();
192 };
193
194 CHECK_AND_RETURN_RET(sinkProvider_ != nullptr, MSERR_INVALID_VAL);
195 CHECK_AND_RETURN_RET(subtitleTrackNum_ < MAX_SUBTITLE_TRACK_NUN,
196 (OnError(MSERR_INVALID_OPERATION, "subtitle tracks exceed the max num limit!"), MSERR_INVALID_OPERATION));
197
198 if (subtitleSink_ == nullptr) {
199 subtitleSink_ = sinkProvider_->CreateSubtitleSink();
200 g_object_set(playbin_, "text-sink", subtitleSink_, nullptr);
201 }
202
203 isAddingSubtitle_ = true;
204 g_object_set(playbin_, "add-suburi", url.c_str(), nullptr);
205 CANCEL_SCOPE_EXIT_GUARD(0);
206
207 return MSERR_OK;
208 }
209
PrepareAsync()210 int32_t PlayBinCtrlerBase::PrepareAsync()
211 {
212 MEDIA_LOGD("enter");
213
214 std::unique_lock<std::mutex> lock(mutex_);
215 return PrepareAsyncInternal();
216 }
217
Play()218 int32_t PlayBinCtrlerBase::Play()
219 {
220 MEDIA_LOGD("enter");
221
222 std::unique_lock<std::mutex> lock(mutex_);
223 CHECK_AND_RETURN_RET_LOG(GetCurrState() != playingState_, MSERR_OK, "already at playing state");
224
225 if (isBuffering_) {
226 ChangeState(playingState_);
227 return MSERR_OK;
228 }
229
230 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
231 int32_t ret = currState->Play();
232 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Play failed");
233
234 return MSERR_OK;
235 }
236
Pause()237 int32_t PlayBinCtrlerBase::Pause()
238 {
239 MEDIA_LOGD("enter");
240
241 std::unique_lock<std::mutex> lock(mutex_);
242 CHECK_AND_RETURN_RET_LOG(GetCurrState() != pausedState_, MSERR_OK, "already at paused state");
243 CHECK_AND_RETURN_RET_LOG(GetCurrState() != preparedState_, MSERR_OK, "already at prepared state");
244
245 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
246 int32_t ret = currState->Pause();
247 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Pause failed");
248
249 return MSERR_OK;
250 }
251
Seek(int64_t timeUs,int32_t seekOption)252 int32_t PlayBinCtrlerBase::Seek(int64_t timeUs, int32_t seekOption)
253 {
254 MEDIA_LOGD("enter");
255 CHECK_AND_RETURN_RET_LOG(SEEK_OPTION_TO_GST_SEEK_FLAGS.find(seekOption) !=
256 SEEK_OPTION_TO_GST_SEEK_FLAGS.end(), MSERR_INVALID_VAL,
257 "unsupported seek option: %{public}d", seekOption);
258 std::unique_lock<std::mutex> lock(mutex_);
259 std::unique_lock<std::mutex> cacheLock(cacheCtrlMutex_);
260
261 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
262 int32_t ret = currState->Seek(timeUs, seekOption);
263 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Seek failed");
264
265 return MSERR_OK;
266 }
267
Stop(bool needWait)268 int32_t PlayBinCtrlerBase::Stop(bool needWait)
269 {
270 MEDIA_LOGD("enter");
271 std::unique_lock<std::mutex> lock(mutex_);
272 if (trackParse_ != nullptr) {
273 trackParse_->Stop();
274 }
275 audioIndex_ = -1;
276
277 if (GetCurrState() == preparingState_ && needWait) {
278 MEDIA_LOGD("begin wait stop for current status is preparing");
279 static constexpr int32_t timeout = 2;
280 preparedCond_.wait_for(lock, std::chrono::seconds(timeout));
281 MEDIA_LOGD("end wait stop for current status is preparing");
282 }
283
284 if (appsrcWrap_ != nullptr) {
285 appsrcWrap_->Stop();
286 }
287
288 std::unique_lock<std::mutex> stateChangeLock(stateChangePropertyMutex_);
289 stopBuffering_ = true;
290 if (videoSink_ == nullptr) {
291 g_object_set(playbin_, "state-change", GST_PLAYER_STATUS_READY, nullptr);
292 }
293 if (seekFuture_.valid()) {
294 (void)seekFuture_.get();
295 }
296 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
297 (void)currState->Stop();
298
299 {
300 MEDIA_LOGD("Stop Start");
301 if (GetCurrState() != stoppedState_) {
302 LISTENER(stoppingCond_.wait(lock), "stoppingCond_.wait", PlayerXCollie::timerTimeout)
303 }
304 MEDIA_LOGD("Stop End");
305 }
306 trackParse_ = nullptr;
307 CHECK_AND_RETURN_RET_LOG(GetCurrState() == stoppedState_, MSERR_INVALID_STATE, "Stop failed");
308 return MSERR_OK;
309 }
310
ChooseSetRateFlags(double rate)311 GstSeekFlags PlayBinCtrlerBase::ChooseSetRateFlags(double rate)
312 {
313 (void)rate;
314 GstSeekFlags seekFlags = static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH |
315 GST_SEEK_FLAG_TRICKMODE | GST_SEEK_FLAG_SNAP_AFTER);
316 return seekFlags;
317 }
318
SetRateInternal(double rate)319 int32_t PlayBinCtrlerBase::SetRateInternal(double rate)
320 {
321 MEDIA_LOGD("execute set rate, rate: %{public}lf", rate);
322
323 gint64 position;
324 gboolean ret;
325
326 isRating_ = true;
327 if (isDuration_.load()) {
328 position = duration_ * NANO_SEC_PER_USEC;
329 } else {
330 ret = gst_element_query_position(GST_ELEMENT_CAST(playbin_), GST_FORMAT_TIME, &position);
331 if (!ret) {
332 MEDIA_LOGW("query position failed, use lastTime");
333 position = lastTime_;
334 }
335 }
336
337 GstSeekFlags flags = ChooseSetRateFlags(rate);
338 int64_t start = rate > 0 ? position : 0;
339 int64_t stop = rate > 0 ? static_cast<int64_t>(GST_CLOCK_TIME_NONE) : position;
340
341 GstEvent *event = gst_event_new_seek(rate, GST_FORMAT_TIME, flags,
342 GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop);
343 CHECK_AND_RETURN_RET_LOG(event != nullptr, MSERR_NO_MEMORY, "set rate failed");
344
345 ret = gst_element_send_event(GST_ELEMENT_CAST(playbin_), event);
346 CHECK_AND_RETURN_RET_LOG(ret, MSERR_SEEK_FAILED, "set rate failed");
347
348 rate_ = rate;
349
350 return MSERR_OK;
351 }
352
SetRate(double rate)353 int32_t PlayBinCtrlerBase::SetRate(double rate)
354 {
355 MEDIA_LOGD("enter");
356 std::unique_lock<std::mutex> lock(mutex_);
357 std::unique_lock<std::mutex> cacheLock(cacheCtrlMutex_);
358
359 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
360 int32_t ret = currState->SetRate(rate);
361 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "SetRate failed");
362
363 return MSERR_OK;
364 }
365
SetLoop(bool loop)366 int32_t PlayBinCtrlerBase::SetLoop(bool loop)
367 {
368 enableLooping_ = loop;
369 return MSERR_OK;
370 }
371
SetVolume(const float & leftVolume,const float & rightVolume)372 void PlayBinCtrlerBase::SetVolume(const float &leftVolume, const float &rightVolume)
373 {
374 (void)rightVolume;
375 std::unique_lock<std::mutex> lock(mutex_);
376 float volume = leftVolume;
377 if (audioSink_ != nullptr) {
378 MEDIA_LOGI("SetVolume(%{public}f) to audio sink", volume);
379 g_object_set(audioSink_, "volume", volume, nullptr);
380 }
381 }
382
SetAudioRendererInfo(const uint32_t rendererInfo,const int32_t rendererFlag)383 int32_t PlayBinCtrlerBase::SetAudioRendererInfo(const uint32_t rendererInfo, const int32_t rendererFlag)
384 {
385 std::unique_lock<std::mutex> lock(mutex_, std::try_to_lock);
386 rendererInfo_ = rendererInfo;
387 rendererFlag_ = rendererFlag;
388 if (audioSink_ != nullptr) {
389 MEDIA_LOGI("SetAudioRendererInfo to audio sink");
390 g_object_set(audioSink_, "audio-renderer-desc", rendererInfo, nullptr);
391 g_object_set(audioSink_, "audio-renderer-flag", rendererFlag, nullptr);
392 }
393 return MSERR_OK;
394 }
395
SetAudioInterruptMode(const int32_t interruptMode)396 void PlayBinCtrlerBase::SetAudioInterruptMode(const int32_t interruptMode)
397 {
398 std::unique_lock<std::mutex> lock(mutex_);
399 if (audioSink_ != nullptr) {
400 g_object_set(audioSink_, "audio-interrupt-mode", interruptMode, nullptr);
401 }
402 }
403
SetAudioEffectMode(const int32_t effectMode)404 int32_t PlayBinCtrlerBase::SetAudioEffectMode(const int32_t effectMode)
405 {
406 std::unique_lock<std::mutex> lock(mutex_);
407 if (audioSink_ != nullptr) {
408 g_object_set(audioSink_, "audio-effect-mode", effectMode, nullptr);
409 int32_t effectModeNow = -1;
410 g_object_get(audioSink_, "audio-effect-mode", &effectModeNow, nullptr);
411 CHECK_AND_RETURN_RET_LOG(effectModeNow == effectMode, MSERR_INVALID_VAL, "failed to set audio-effect-mode");
412 }
413 return MSERR_OK;
414 }
415
SelectBitRate(uint32_t bitRate)416 int32_t PlayBinCtrlerBase::SelectBitRate(uint32_t bitRate)
417 {
418 std::unique_lock<std::mutex> lock(mutex_);
419 MEDIA_LOGD("enter SelectBitRate, bandwidth: %{public}u", bitRate);
420 if (bitRateVec_.empty()) {
421 MEDIA_LOGE("BitRate is empty");
422 return MSERR_INVALID_OPERATION;
423 }
424 if (connectSpeed_ == bitRate && !isSelectBitRate_) {
425 PlayBinMessage msg = { PLAYBIN_MSG_BITRATEDONE, 0, static_cast<int32_t>(bitRate), {} };
426 ReportMessage(msg);
427 } else {
428 MEDIA_LOGD("set bandwidth to: %{public}u", bitRate);
429 isSelectBitRate_ = true;
430 g_object_set(playbin_, "connection-speed", static_cast<uint64_t>(bitRate), nullptr);
431 }
432 return MSERR_OK;
433 }
434
Reset()435 int32_t PlayBinCtrlerBase::Reset() noexcept
436 {
437 MEDIA_LOGD("enter");
438
439 std::unique_lock<std::mutex> lock(mutex_);
440 {
441 std::unique_lock<std::mutex> lk(listenerMutex_);
442 elemSetupListener_ = nullptr;
443 elemUnSetupListener_ = nullptr;
444 autoPlugSortListener_ = nullptr;
445 }
446 // Do it here before the ChangeState to IdleState, for avoding the deadlock when msg handler
447 // try to call the ChangeState.
448 ExitInitializedState();
449 ChangeState(idleState_);
450
451 if (msgQueue_ != nullptr) {
452 (void)msgQueue_->Stop();
453 }
454
455 uri_.clear();
456 isErrorHappened_ = false;
457 enableLooping_ = false;
458 {
459 std::unique_lock<std::mutex> appsrcLock(appsrcMutex_);
460 appsrcWrap_ = nullptr;
461 }
462
463 rate_ = DEFAULT_RATE;
464 seekPos_ = 0;
465 lastTime_ = 0;
466 isSeeking_ = false;
467 isRating_ = false;
468 isAddingSubtitle_ = false;
469 isBuffering_ = false;
470 isSelectBitRate_ = false;
471 cachePercent_ = BUFFER_PERCENT_THRESHOLD;
472 isDuration_ = false;
473 isUserSetPause_ = false;
474 subtitleTrackNum_ = 0;
475
476 MEDIA_LOGD("exit");
477 return MSERR_OK;
478 }
479
SetElemSetupListener(ElemSetupListener listener)480 void PlayBinCtrlerBase::SetElemSetupListener(ElemSetupListener listener)
481 {
482 std::unique_lock<std::mutex> lock(mutex_);
483 std::unique_lock<std::mutex> lk(listenerMutex_);
484 elemSetupListener_ = listener;
485 }
486
SetElemUnSetupListener(ElemSetupListener listener)487 void PlayBinCtrlerBase::SetElemUnSetupListener(ElemSetupListener listener)
488 {
489 std::unique_lock<std::mutex> lock(mutex_);
490 std::unique_lock<std::mutex> lk(listenerMutex_);
491 elemUnSetupListener_ = listener;
492 }
493
SetAutoPlugSortListener(AutoPlugSortListener listener)494 void PlayBinCtrlerBase::SetAutoPlugSortListener(AutoPlugSortListener listener)
495 {
496 std::unique_lock<std::mutex> lock(mutex_);
497 std::unique_lock<std::mutex> lk(listenerMutex_);
498 autoPlugSortListener_ = listener;
499 }
500
DoInitializeForHttp()501 void PlayBinCtrlerBase::DoInitializeForHttp()
502 {
503 if (isNetWorkPlay_) {
504 g_object_set(playbin_, "ring-buffer-max-size", RING_BUFFER_MAX_SIZE, nullptr);
505 g_object_set(playbin_, "buffering-flags", true, "buffer-size", PLAYBIN_QUEUE_MAX_SIZE,
506 "buffer-duration", BUFFER_DURATION, "low-percent", BUFFER_LOW_PERCENT_DEFAULT,
507 "high-percent", BUFFER_HIGH_PERCENT_DEFAULT, nullptr);
508
509 std::string autoSelectBitrate;
510 int32_t res = OHOS::system::GetStringParameter(
511 "sys.media.hls.set.autoSelectBitrate", autoSelectBitrate, "");
512 if (res == 0 && !autoSelectBitrate.empty() && autoSelectBitrate == "TRUE") {
513 SetAutoSelectBitrate(true);
514 MEDIA_LOGD("set autoSelectBitrate to true");
515 } else {
516 SetAutoSelectBitrate(false);
517 MEDIA_LOGD("set autoSelectBitrate to false");
518 }
519
520 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
521 CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
522
523 gulong id = g_signal_connect_data(playbin_, "bitrate-parse-complete",
524 G_CALLBACK(&PlayBinCtrlerBase::OnBitRateParseCompleteCb), wrapper,
525 (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
526 CheckAndAddSignalIds(id, wrapper, GST_ELEMENT_CAST(playbin_));
527
528 PlayBinCtrlerWrapper *wrap = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
529 CHECK_AND_RETURN_LOG(wrap != nullptr, "can not create this wrap");
530
531 id = g_signal_connect_data(videoSink_, "bandwidth-change",
532 G_CALLBACK(&PlayBinCtrlerBase::OnSelectBitrateDoneCb), wrap,
533 (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
534 CheckAndAddSignalIds(id, wrap, videoSink_);
535 }
536 }
537
EnterInitializedState()538 int32_t PlayBinCtrlerBase::EnterInitializedState()
539 {
540 if (isInitialized_) {
541 (void)DoInitializeForDataSource();
542 return MSERR_OK;
543 }
544 MediaTrace("PlayBinCtrlerBase::InitializedState");
545 MEDIA_LOGD("EnterInitializedState enter");
546
547 ON_SCOPE_EXIT(0) {
548 ExitInitializedState();
549 PlayBinMessage msg { PlayBinMsgType::PLAYBIN_MSG_ERROR,
550 PlayBinMsgErrorSubType::PLAYBIN_SUB_MSG_ERROR_WITH_MESSAGE,
551 MSERR_CREATE_PLAYER_ENGINE_FAILED, std::string("failed to EnterInitializedState") };
552 ReportMessage(msg);
553 MEDIA_LOGE("enter initialized state failed");
554 };
555
556 int32_t ret = OnInit();
557 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
558 CHECK_AND_RETURN_RET(playbin_ != nullptr, static_cast<int32_t>(MSERR_CREATE_PLAYER_ENGINE_FAILED));
559
560 ret = DoInitializeForDataSource();
561 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "DoInitializeForDataSource failed!");
562
563 SetupCustomElement();
564 SetupSourceSetupSignal();
565 ret = SetupSignalMessage();
566 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
567 ret = SetupElementUnSetupSignal();
568 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
569 SetAudioRendererInfo(rendererInfo_, rendererFlag_);
570
571 uint32_t flags = 0;
572 g_object_get(playbin_, "flags", &flags, nullptr);
573 if ((renderMode_ & PlayBinRenderMode::DEFAULT_RENDER) != 0) {
574 flags &= ~GST_PLAY_FLAG_VIS;
575 }
576 if ((renderMode_ & PlayBinRenderMode::NATIVE_STREAM) != 0) {
577 flags |= GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_NATIVE_AUDIO;
578 flags &= ~(GST_PLAY_FLAG_SOFT_COLORBALANCE | GST_PLAY_FLAG_SOFT_VOLUME);
579 }
580 if ((renderMode_ & PlayBinRenderMode::DISABLE_TEXT) != 0) {
581 flags &= ~GST_PLAY_FLAG_TEXT;
582 }
583 g_object_set(playbin_, "flags", flags, nullptr);
584
585 // There may be a risk of data competition, but the uri is unlikely to be reconfigured.
586 if (!uri_.empty()) {
587 g_object_set(playbin_, "uri", uri_.c_str(), nullptr);
588 }
589
590 DoInitializeForHttp();
591
592 isInitialized_ = true;
593 ChangeState(initializedState_);
594
595 CANCEL_SCOPE_EXIT_GUARD(0);
596 MEDIA_LOGD("EnterInitializedState exit");
597
598 return MSERR_OK;
599 }
600
ExitInitializedState()601 void PlayBinCtrlerBase::ExitInitializedState()
602 {
603 MEDIA_LOGD("ExitInitializedState enter");
604
605 if (!isInitialized_) {
606 return;
607 }
608 isInitialized_ = false;
609
610 mutex_.unlock();
611 if (msgProcessor_ != nullptr) {
612 msgProcessor_->Reset();
613 msgProcessor_ = nullptr;
614 }
615 mutex_.lock();
616
617 if (sinkProvider_ != nullptr) {
618 sinkProvider_->SetMsgNotifier(nullptr);
619 }
620 for (auto &item : signalIds_) {
621 for (auto id : item.second) {
622 g_signal_handler_disconnect(item.first, id);
623 }
624 }
625 signalIds_.clear();
626
627 MEDIA_LOGD("unref playbin start");
628 if (playbin_ != nullptr) {
629 (void)gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_NULL);
630 gst_object_unref(playbin_);
631 playbin_ = nullptr;
632 }
633 MEDIA_LOGD("unref playbin stop");
634
635 MEDIA_LOGD("ExitInitializedState exit");
636 }
637
PrepareAsyncInternal()638 int32_t PlayBinCtrlerBase::PrepareAsyncInternal()
639 {
640 if ((GetCurrState() == preparingState_) || (GetCurrState() == preparedState_)) {
641 MEDIA_LOGI("already at preparing state, skip");
642 return MSERR_OK;
643 }
644
645 CHECK_AND_RETURN_RET_LOG((!uri_.empty() || appsrcWrap_), MSERR_INVALID_OPERATION, "Set uri firsty!");
646 trackParse_ = PlayerTrackParse::Create();
647 int32_t ret = EnterInitializedState();
648 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
649
650 stopBuffering_ = false;
651 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
652 ret = currState->Prepare();
653 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "PrepareAsyncInternal failed");
654
655 return MSERR_OK;
656 }
657
SeekInternal(int64_t timeUs,int32_t seekOption)658 int32_t PlayBinCtrlerBase::SeekInternal(int64_t timeUs, int32_t seekOption)
659 {
660 MEDIA_LOGI("execute seek, time: %{public}" PRIi64 ", option: %{public}d", timeUs, seekOption);
661
662 int32_t seekFlags = SEEK_OPTION_TO_GST_SEEK_FLAGS.at(seekOption);
663 timeUs = timeUs > duration_ ? duration_ : timeUs;
664 timeUs = timeUs < 0 ? 0 : timeUs;
665
666 constexpr int32_t usecToNanoSec = 1000;
667 int64_t timeNs = timeUs * usecToNanoSec;
668 seekPos_ = timeUs;
669 isSeeking_ = true;
670 if (videoSink_ == nullptr || seekOption == IPlayBinCtrler::PlayBinSeekMode::CLOSET) {
671 isClosetSeeking_ = true;
672 }
673 GstEvent *event = gst_event_new_seek(rate_, GST_FORMAT_TIME, static_cast<GstSeekFlags>(seekFlags),
674 GST_SEEK_TYPE_SET, timeNs, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE);
675 CHECK_AND_RETURN_RET_LOG(event != nullptr, MSERR_NO_MEMORY, "seek failed");
676
677 if (videoSink_ != nullptr) {
678 gboolean ret = gst_element_send_event(GST_ELEMENT_CAST(playbin_), event);
679 CHECK_AND_RETURN_RET_LOG(ret, MSERR_SEEK_FAILED, "seek failed");
680 } else {
681 seekFuture_ = std::async(std::launch::async, [this, event]() -> gboolean {
682 gboolean ret = FALSE;
683 CHECK_AND_RETURN_RET_LOG(playbin_ != nullptr, FALSE, "playbin is nullptr");
684 pthread_setname_np(pthread_self(), "AudioAsyncSeek");
685 MEDIA_LOGI("audio seek start");
686 ret = gst_element_send_event(GST_ELEMENT_CAST(playbin_), event);
687 MEDIA_LOGI("audio seek end");
688 return ret;
689 });
690 }
691 return MSERR_OK;
692 }
693
SetupInterruptEventCb()694 void PlayBinCtrlerBase::SetupInterruptEventCb()
695 {
696 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
697 CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
698
699 gulong id = g_signal_connect_data(audioSink_, "interrupt-event",
700 G_CALLBACK(&PlayBinCtrlerBase::OnInterruptEventCb), wrapper,
701 (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
702 CheckAndAddSignalIds(id, wrapper, audioSink_);
703 }
704
SetupAudioSegmentEventCb()705 void PlayBinCtrlerBase::SetupAudioSegmentEventCb()
706 {
707 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
708 CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
709
710 gulong id = g_signal_connect_data(audioSink_, "segment-updated",
711 G_CALLBACK(&PlayBinCtrlerBase::OnAudioSegmentEventCb), wrapper,
712 (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
713 CheckAndAddSignalIds(id, wrapper, audioSink_);
714 }
715
SetupAudioDiedEventCb()716 void PlayBinCtrlerBase::SetupAudioDiedEventCb()
717 {
718 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
719 CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
720
721 gulong id = g_signal_connect_data(audioSink_, "audio-service-died",
722 G_CALLBACK(&PlayBinCtrlerBase::OnAudioDiedEventCb), wrapper,
723 (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
724 CheckAndAddSignalIds(id, wrapper, audioSink_);
725 }
726
SetupCustomElement()727 void PlayBinCtrlerBase::SetupCustomElement()
728 {
729 // There may be a risk of data competition, but the sinkProvider is unlikely to be reconfigured.
730 if (sinkProvider_ != nullptr) {
731 audioSink_ = sinkProvider_->CreateAudioSink();
732 if (audioSink_ != nullptr) {
733 g_object_set(playbin_, "audio-sink", audioSink_, nullptr);
734 SetupInterruptEventCb();
735 SetupAudioSegmentEventCb();
736 SetupAudioDiedEventCb();
737 }
738 videoSink_ = sinkProvider_->CreateVideoSink();
739 if (videoSink_ != nullptr) {
740 g_object_set(playbin_, "video-sink", videoSink_, nullptr);
741 } else if (audioSink_ != nullptr) {
742 g_object_set(playbin_, "video-sink", audioSink_, nullptr);
743 }
744 auto msgNotifier = std::bind(&PlayBinCtrlerBase::OnSinkMessageReceived, this, std::placeholders::_1);
745 sinkProvider_->SetMsgNotifier(msgNotifier);
746 } else {
747 MEDIA_LOGD("no sinkprovider, delay the sink selection until the playbin enters pause state.");
748 }
749
750 if ((renderMode_ & PlayBinRenderMode::NATIVE_STREAM) == 0) {
751 GstElement *audioFilter = gst_element_factory_make("scaletempo", "scaletempo");
752 if (audioFilter != nullptr) {
753 g_object_set(playbin_, "audio-filter", audioFilter, nullptr);
754 } else {
755 MEDIA_LOGD("can not create scaletempo, the audio playback speed can not be adjusted");
756 }
757 }
758 }
759
SetupSourceSetupSignal()760 void PlayBinCtrlerBase::SetupSourceSetupSignal()
761 {
762 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
763 CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
764
765 gulong id = g_signal_connect_data(playbin_, "source-setup",
766 G_CALLBACK(&PlayBinCtrlerBase::SourceSetup), wrapper, (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory,
767 static_cast<GConnectFlags>(0));
768 CheckAndAddSignalIds(id, wrapper, GST_ELEMENT_CAST(playbin_));
769 }
770
SetupSignalMessage()771 int32_t PlayBinCtrlerBase::SetupSignalMessage()
772 {
773 MEDIA_LOGD("SetupSignalMessage enter");
774
775 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
776 CHECK_AND_RETURN_RET_LOG(wrapper != nullptr, MSERR_NO_MEMORY, "can not create this wrapper");
777
778 gulong id = g_signal_connect_data(playbin_, "element-setup",
779 G_CALLBACK(&PlayBinCtrlerBase::ElementSetup), wrapper, (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory,
780 static_cast<GConnectFlags>(0));
781 CheckAndAddSignalIds(id, wrapper, GST_ELEMENT_CAST(playbin_));
782
783 PlayBinCtrlerWrapper *wrap = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
784 CHECK_AND_RETURN_RET_LOG(wrap != nullptr, MSERR_NO_MEMORY, "can not create this wrapper");
785 id = g_signal_connect_data(playbin_, "audio-changed", G_CALLBACK(&PlayBinCtrlerBase::AudioChanged),
786 wrap, (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
787 CheckAndAddSignalIds(id, wrap, GST_ELEMENT_CAST(playbin_));
788
789 GstBus *bus = gst_pipeline_get_bus(playbin_);
790 CHECK_AND_RETURN_RET_LOG(bus != nullptr, MSERR_UNKNOWN, "can not get bus");
791
792 auto msgNotifier = std::bind(&PlayBinCtrlerBase::OnMessageReceived, this, std::placeholders::_1);
793 msgProcessor_ = std::make_unique<GstMsgProcessor>(*bus, msgNotifier);
794
795 gst_object_unref(bus);
796 bus = nullptr;
797
798 int32_t ret = msgProcessor_->Init();
799 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
800
801 // only concern the msg from playbin
802 msgProcessor_->AddMsgFilter(ELEM_NAME(GST_ELEMENT_CAST(playbin_)));
803
804 MEDIA_LOGD("SetupSignalMessage exit");
805 return MSERR_OK;
806 }
807
SetupElementUnSetupSignal()808 int32_t PlayBinCtrlerBase::SetupElementUnSetupSignal()
809 {
810 MEDIA_LOGD("SetupElementUnSetupSignal enter");
811
812 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
813 CHECK_AND_RETURN_RET_LOG(wrapper != nullptr, MSERR_NO_MEMORY, "can not create this wrapper");
814
815 gulong id = g_signal_connect_data(playbin_, "deep-element-removed",
816 G_CALLBACK(&PlayBinCtrlerBase::ElementUnSetup), wrapper, (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory,
817 static_cast<GConnectFlags>(0));
818 CheckAndAddSignalIds(id, wrapper, GST_ELEMENT_CAST(playbin_));
819
820 return MSERR_OK;
821 }
822
QueryDuration()823 void PlayBinCtrlerBase::QueryDuration()
824 {
825 auto state = GetCurrState();
826 if (state != preparedState_ && state != playingState_ && state != pausedState_ &&
827 state != playbackCompletedState_) {
828 MEDIA_LOGE("reuse the last query result: %{public}" PRIi64 " microsecond", duration_);
829 return;
830 }
831
832 gint64 duration = -1;
833 gboolean ret = gst_element_query_duration(GST_ELEMENT_CAST(playbin_), GST_FORMAT_TIME, &duration);
834 CHECK_AND_RETURN_LOG(ret, "query duration failed");
835
836 if (duration >= 0) {
837 duration_ = duration / NANO_SEC_PER_USEC;
838 }
839 MEDIA_LOGI("update the duration: %{public}" PRIi64 " microsecond", duration_);
840 }
841
QueryPosition()842 int64_t PlayBinCtrlerBase::QueryPosition()
843 {
844 gint64 position = 0;
845 gboolean ret = gst_element_query_position(GST_ELEMENT_CAST(playbin_), GST_FORMAT_TIME, &position);
846 if (!ret) {
847 MEDIA_LOGW("query position failed");
848 return lastTime_ / USEC_PER_MSEC;
849 }
850
851 int64_t curTime = position / NANO_SEC_PER_USEC;
852 if (duration_ >= 0) {
853 curTime = std::min(curTime, duration_);
854 }
855 lastTime_ = curTime;
856 MEDIA_LOGI("update the position: %{public}" PRIi64 " microsecond", curTime);
857 return curTime / USEC_PER_MSEC;
858 }
859
ProcessEndOfStream()860 void PlayBinCtrlerBase::ProcessEndOfStream()
861 {
862 MEDIA_LOGD("End of stream");
863 isDuration_ = true;
864
865 if (!enableLooping_.load() && !isSeeking_) { // seek duration done->seeking->eos
866 ChangeState(playbackCompletedState_);
867 }
868 }
869
DoInitializeForDataSource()870 int32_t PlayBinCtrlerBase::DoInitializeForDataSource()
871 {
872 if (appsrcWrap_ != nullptr) {
873 (void)appsrcWrap_->Prepare();
874 if (isInitialized_) {
875 return MSERR_OK;
876 }
877 auto msgNotifier = std::bind(&PlayBinCtrlerBase::OnAppsrcMessageReceived, this, std::placeholders::_1);
878 CHECK_AND_RETURN_RET_LOG(appsrcWrap_->SetCallback(msgNotifier) == MSERR_OK,
879 MSERR_INVALID_OPERATION, "set appsrc error callback failed");
880
881 g_object_set(playbin_, "uri", "appsrc://", nullptr);
882 }
883 return MSERR_OK;
884 }
885
GetVideoTrackInfo(std::vector<Format> & videoTrack)886 int32_t PlayBinCtrlerBase::GetVideoTrackInfo(std::vector<Format> &videoTrack)
887 {
888 std::unique_lock<std::mutex> lock(mutex_);
889 CHECK_AND_RETURN_RET_LOG(trackParse_ != nullptr, MSERR_INVALID_OPERATION, "trackParse_ is nullptr");
890 return trackParse_->GetVideoTrackInfo(videoTrack);
891 }
892
GetAudioTrackInfo(std::vector<Format> & audioTrack)893 int32_t PlayBinCtrlerBase::GetAudioTrackInfo(std::vector<Format> &audioTrack)
894 {
895 std::unique_lock<std::mutex> lock(mutex_);
896 CHECK_AND_RETURN_RET_LOG(trackParse_ != nullptr, MSERR_INVALID_OPERATION, "trackParse_ is nullptr");
897 return trackParse_->GetAudioTrackInfo(audioTrack);
898 }
899
GetSubtitleTrackInfo(std::vector<Format> & subtitleTrack)900 int32_t PlayBinCtrlerBase::GetSubtitleTrackInfo(std::vector<Format> &subtitleTrack)
901 {
902 std::unique_lock<std::mutex> lock(mutex_);
903 CHECK_AND_RETURN_RET_LOG(trackParse_ != nullptr, MSERR_INVALID_OPERATION, "trackParse_ is nullptr");
904 return trackParse_->GetSubtitleTrackInfo(subtitleTrack);
905 }
906
SelectTrack(int32_t index)907 int32_t PlayBinCtrlerBase::SelectTrack(int32_t index)
908 {
909 std::unique_lock<std::mutex> lock(mutex_);
910 ON_SCOPE_EXIT(0) {
911 OnTrackDone();
912 };
913
914 CHECK_AND_RETURN_RET_LOG(trackParse_ != nullptr, MSERR_INVALID_OPERATION, "trackParse_ is nullptr");
915 int32_t trackType = -1;
916 int32_t innerIndex = -1;
917 int32_t ret = trackParse_->GetTrackInfo(index, innerIndex, trackType);
918 CHECK_AND_RETURN_RET(ret == MSERR_OK, (OnError(ret, "Invalid track index!"), ret));
919 CHECK_AND_RETURN_RET(innerIndex >= 0,
920 (OnError(MSERR_INVALID_OPERATION, "This track is currently not supported!"), MSERR_INVALID_OPERATION));
921
922 if (trackType == MediaType::MEDIA_TYPE_AUD) {
923 ret = MSERR_INVALID_OPERATION;
924 CHECK_AND_RETURN_RET(GetCurrState() == preparedState_,
925 (OnError(ret, "Audio tracks can only be selected in the prepared state!"), ret));
926
927 int32_t currentIndex = -1;
928 g_object_get(playbin_, "current-audio", ¤tIndex, nullptr);
929 CHECK_AND_RETURN_RET(innerIndex != currentIndex,
930 (OnError(MSERR_OK, "This track has already been selected!"), MSERR_OK));
931
932 lastStartTime_ = gst_element_get_start_time(GST_ELEMENT_CAST(playbin_));
933 g_object_set(playbin_, "current-audio", innerIndex, nullptr);
934 // The seek operation clears the original audio data and re parses the new track data.
935 isTrackChanging_ = true;
936 trackChangeType_ = MediaType::MEDIA_TYPE_AUD;
937 SeekInternal(seekPos_, IPlayBinCtrler::PlayBinSeekMode::CLOSET_SYNC);
938 CANCEL_SCOPE_EXIT_GUARD(0);
939 } else if (trackType == MediaType::MEDIA_TYPE_SUBTITLE) {
940 int32_t currentIndex = -1;
941 g_object_get(playbin_, "current-text", ¤tIndex, nullptr);
942 CHECK_AND_RETURN_RET((!hasSubtitleTrackSelected_ || innerIndex != currentIndex),
943 (OnError(MSERR_OK, "This track has already been selected!"), MSERR_OK));
944
945 MEDIA_LOGI("start select subtitle track %{public}d", index);
946 isTrackChanging_ = true;
947 trackChangeType_ = MediaType::MEDIA_TYPE_SUBTITLE;
948 g_object_set(subtitleSink_, "change-track", true, nullptr);
949 lastStartTime_ = gst_element_get_start_time(GST_ELEMENT_CAST(playbin_));
950 gst_element_set_start_time(GST_ELEMENT_CAST(playbin_), GST_CLOCK_TIME_NONE);
951 g_object_set(playbin_, "current-text", innerIndex, nullptr);
952 hasSubtitleTrackSelected_ = true;
953 g_object_set(subtitleSink_, "enable-display", hasSubtitleTrackSelected_, nullptr);
954 CANCEL_SCOPE_EXIT_GUARD(0);
955 } else {
956 OnError(MSERR_INVALID_VAL, "The track type does not support this operation!");
957 return MSERR_INVALID_OPERATION;
958 }
959 return MSERR_OK;
960 }
961
DeselectTrack(int32_t index)962 int32_t PlayBinCtrlerBase::DeselectTrack(int32_t index)
963 {
964 std::unique_lock<std::mutex> lock(mutex_);
965 ON_SCOPE_EXIT(0) {
966 OnTrackDone();
967 };
968
969 CHECK_AND_RETURN_RET_LOG(trackParse_ != nullptr, MSERR_INVALID_OPERATION, "trackParse_ is nullptr");
970 int32_t trackType = -1;
971 int32_t innerIndex = -1;
972 int32_t ret = trackParse_->GetTrackInfo(index, innerIndex, trackType);
973 CHECK_AND_RETURN_RET(ret == MSERR_OK, (OnError(ret, "Invalid track index!"), ret));
974 CHECK_AND_RETURN_RET(innerIndex >= 0,
975 (OnError(MSERR_INVALID_OPERATION, "This track has not been selected yet!"), MSERR_INVALID_OPERATION));
976
977 if (trackType == MediaType::MEDIA_TYPE_AUD) {
978 ret = MSERR_INVALID_OPERATION;
979 CHECK_AND_RETURN_RET(GetCurrState() == preparedState_,
980 (OnError(ret, "Audio tracks can only be deselected in the prepared state!"), ret));
981
982 int32_t currentIndex = -1;
983 g_object_get(playbin_, "current-audio", ¤tIndex, nullptr);
984 CHECK_AND_RETURN_RET(innerIndex == currentIndex,
985 (OnError(ret, "This track has not been selected yet!"), ret));
986
987 CHECK_AND_RETURN_RET(currentIndex != 0,
988 (OnError(MSERR_OK, "The current audio track is already the default track!"), MSERR_OK));
989
990 g_object_set(playbin_, "current-audio", 0, nullptr); // 0 is the default track
991 // The seek operation clears the original audio data and re parses the new track data.
992 isTrackChanging_ = true;
993 trackChangeType_ = MediaType::MEDIA_TYPE_AUD;
994 SeekInternal(seekPos_, IPlayBinCtrler::PlayBinSeekMode::CLOSET_SYNC);
995 CANCEL_SCOPE_EXIT_GUARD(0);
996 } else if (trackType == MediaType::MEDIA_TYPE_SUBTITLE) {
997 ret = MSERR_INVALID_OPERATION;
998 int32_t currentIndex = -1;
999 g_object_get(playbin_, "current-text", ¤tIndex, nullptr);
1000 CHECK_AND_RETURN_RET((hasSubtitleTrackSelected_ && innerIndex == currentIndex),
1001 (OnError(ret, "This track has not been selected yet!"), ret));
1002
1003 hasSubtitleTrackSelected_ = false;
1004 g_object_set(subtitleSink_, "enable-display", hasSubtitleTrackSelected_, nullptr);
1005 trackChangeType_ = MediaType::MEDIA_TYPE_SUBTITLE;
1006 ReportTrackChange();
1007 CANCEL_SCOPE_EXIT_GUARD(0);
1008 } else {
1009 OnError(MSERR_INVALID_VAL, "The track type does not support this operation!");
1010 return MSERR_INVALID_VAL;
1011 }
1012 return MSERR_OK;
1013 }
1014
GetCurrentTrack(int32_t trackType,int32_t & index)1015 int32_t PlayBinCtrlerBase::GetCurrentTrack(int32_t trackType, int32_t &index)
1016 {
1017 std::unique_lock<std::mutex> lock(mutex_);
1018 MEDIA_LOGI("GetCurrentTrack in");
1019 CHECK_AND_RETURN_RET(trackParse_ != nullptr, MSERR_INVALID_OPERATION);
1020 int32_t innerIndex = -1;
1021 if (trackType == MediaType::MEDIA_TYPE_AUD) {
1022 if (isTrackChanging_) {
1023 // During the change track process, return the original value.
1024 innerIndex = audioIndex_;
1025 } else {
1026 g_object_get(playbin_, "current-audio", &innerIndex, nullptr);
1027 }
1028 } else if (trackType == MediaType::MEDIA_TYPE_VID) {
1029 g_object_get(playbin_, "current-video", &innerIndex, nullptr);
1030 } else {
1031 if (hasSubtitleTrackSelected_) {
1032 g_object_get(playbin_, "current-text", &innerIndex, nullptr);
1033 } else {
1034 innerIndex = -1;
1035 }
1036 }
1037
1038 if (innerIndex >= 0) {
1039 return trackParse_->GetTrackIndex(innerIndex, trackType, index);
1040 } else {
1041 // There are no tracks currently playing, return to -1.
1042 index = innerIndex;
1043 return MSERR_OK;
1044 }
1045 }
1046
HandleCacheCtrl(int32_t percent)1047 void PlayBinCtrlerBase::HandleCacheCtrl(int32_t percent)
1048 {
1049 MEDIA_LOGI("HandleCacheCtrl percent is %{public}d", percent);
1050 if (!isBuffering_) {
1051 HandleCacheCtrlWhenNoBuffering(percent);
1052 } else {
1053 HandleCacheCtrlWhenBuffering(percent);
1054 }
1055 }
1056
HandleCacheCtrlCb(const InnerMessage & msg)1057 void PlayBinCtrlerBase::HandleCacheCtrlCb(const InnerMessage &msg)
1058 {
1059 if (isNetWorkPlay_) {
1060 cachePercent_ = msg.detail1;
1061 HandleCacheCtrl(cachePercent_);
1062 }
1063 }
1064
HandleCacheCtrlWhenNoBuffering(int32_t percent)1065 void PlayBinCtrlerBase::HandleCacheCtrlWhenNoBuffering(int32_t percent)
1066 {
1067 if (isSelectBitRate_) {
1068 MEDIA_LOGD("switch bitrate, just return");
1069 return;
1070 }
1071 if (percent < static_cast<float>(BUFFER_LOW_PERCENT_DEFAULT) / BUFFER_HIGH_PERCENT_DEFAULT *
1072 BUFFER_PERCENT_THRESHOLD) {
1073 // percent<25% buffering start
1074 PlayBinMessage msg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_START, 0, {} };
1075 ReportMessage(msg);
1076
1077 // percent<25% buffering percent
1078 PlayBinMessage percentMsg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_PERCENT, percent, {} };
1079 ReportMessage(percentMsg);
1080
1081 isBuffering_ = true;
1082 if (!SetPlayerState(GST_PLAYER_STATUS_BUFFERING)) {
1083 MEDIA_LOGD("Stopping, just return");
1084 return;
1085 }
1086
1087 if (GetCurrState() == playingState_ && !isSeeking_ && !isRating_ &&
1088 !isAddingSubtitle_ && !isUserSetPause_) {
1089 std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
1090 MEDIA_LOGI("HandleCacheCtrl percent is %{public}d, begin set to paused", percent);
1091 GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_PAUSED);
1092 if (ret == GST_STATE_CHANGE_FAILURE) {
1093 MEDIA_LOGE("Failed to change playbin's state to GST_STATE_PAUSED");
1094 return;
1095 }
1096 }
1097 }
1098 }
1099
HandleCacheCtrlWhenBuffering(int32_t percent)1100 void PlayBinCtrlerBase::HandleCacheCtrlWhenBuffering(int32_t percent)
1101 {
1102 // 0% < percent < 100% buffering percent
1103 PlayBinMessage percentMsg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_PERCENT, percent, {} };
1104 ReportMessage(percentMsg);
1105
1106 // percent > 100% buffering end
1107 if (percent >= BUFFER_PERCENT_THRESHOLD) {
1108 isBuffering_ = false;
1109 if (GetCurrState() == playingState_ && !isUserSetPause_) {
1110 if (!SetPlayerState(GST_PLAYER_STATUS_PLAYING)) {
1111 MEDIA_LOGD("Stopping, just return");
1112 return;
1113 }
1114 std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
1115 MEDIA_LOGI("percent is %{public}d, begin set to playing", percent);
1116 GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_PLAYING);
1117 if (ret == GST_STATE_CHANGE_FAILURE) {
1118 MEDIA_LOGE("Failed to change playbin's state to GST_STATE_PLAYING");
1119 return;
1120 }
1121 } else {
1122 if (!SetPlayerState(GST_PLAYER_STATUS_PAUSED)) {
1123 MEDIA_LOGD("Stopping, just return");
1124 return;
1125 }
1126 }
1127
1128 PlayBinMessage msg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_END, 0, {} };
1129 ReportMessage(msg);
1130 }
1131 }
1132
RemoveGstPlaySinkVideoConvertPlugin()1133 void PlayBinCtrlerBase::RemoveGstPlaySinkVideoConvertPlugin()
1134 {
1135 uint32_t flags = 0;
1136
1137 CHECK_AND_RETURN_LOG(playbin_ != nullptr, "playbin_ is nullptr");
1138 g_object_get(playbin_, "flags", &flags, nullptr);
1139 flags |= (GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_HARDWARE_VIDEO);
1140 flags &= ~GST_PLAY_FLAG_SOFT_COLORBALANCE;
1141 MEDIA_LOGD("set gstplaysink flags %{public}d", flags);
1142 // set playsink remove GstPlaySinkVideoConvert, for first-frame performance optimization
1143 g_object_set(playbin_, "flags", flags, nullptr);
1144 }
1145
AutoPlugSort(const GstElement * uriDecoder,GstPad * pad,GstCaps * caps,GValueArray * factories,gpointer userData)1146 GValueArray *PlayBinCtrlerBase::AutoPlugSort(const GstElement *uriDecoder, GstPad *pad, GstCaps *caps,
1147 GValueArray *factories, gpointer userData)
1148 {
1149 CHECK_AND_RETURN_RET_LOG(uriDecoder != nullptr, nullptr, "uriDecoder is null");
1150 CHECK_AND_RETURN_RET_LOG(pad != nullptr, nullptr, "pad is null");
1151 CHECK_AND_RETURN_RET_LOG(caps != nullptr, nullptr, "caps is null");
1152 CHECK_AND_RETURN_RET_LOG(factories != nullptr, nullptr, "factories is null");
1153
1154 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1155 CHECK_AND_RETURN_RET_LOG(thizStrong != nullptr, nullptr, "thizStrong is null");
1156 return thizStrong->OnAutoPlugSort(*factories);
1157 }
OnAutoPlugSort(GValueArray & factories)1158 GValueArray *PlayBinCtrlerBase::OnAutoPlugSort(GValueArray &factories)
1159 {
1160 MEDIA_LOGD("OnAutoPlugSort");
1161
1162 decltype(autoPlugSortListener_) listener = nullptr;
1163 {
1164 std::unique_lock<std::mutex> lock(listenerMutex_);
1165 listener = autoPlugSortListener_;
1166 }
1167
1168 if (listener != nullptr) {
1169 return listener(factories);
1170 }
1171 return nullptr;
1172 }
1173
OnSourceSetup(const GstElement * playbin,GstElement * src,const std::shared_ptr<PlayBinCtrlerBase> & playbinCtrl)1174 void PlayBinCtrlerBase::OnSourceSetup(const GstElement *playbin, GstElement *src,
1175 const std::shared_ptr<PlayBinCtrlerBase> &playbinCtrl)
1176 {
1177 (void)playbin;
1178 CHECK_AND_RETURN_LOG(playbinCtrl != nullptr, "playbinCtrl is null");
1179 CHECK_AND_RETURN_LOG(src != nullptr, "src is null");
1180
1181 GstElementFactory *elementFac = gst_element_get_factory(src);
1182 const gchar *eleTypeName = g_type_name(gst_element_factory_get_element_type(elementFac));
1183 CHECK_AND_RETURN_LOG(eleTypeName != nullptr, "eleTypeName is nullptr");
1184
1185 std::unique_lock<std::mutex> appsrcLock(appsrcMutex_);
1186 if ((strstr(eleTypeName, "GstAppSrc") != nullptr) && (playbinCtrl->appsrcWrap_ != nullptr)) {
1187 g_object_set(src, "datasrc-mode", true, nullptr);
1188 (void)playbinCtrl->appsrcWrap_->SetAppsrc(src);
1189 } else if (strstr(eleTypeName, "GstCurlHttpSrc") != nullptr) {
1190 g_object_set(src, "ssl-ca-file", "/etc/ssl/certs/cacert.pem", nullptr);
1191 MEDIA_LOGI("setup curl_http ca_file done");
1192 }
1193 }
1194
OnVideoDecoderSetup(GstElement & elem)1195 bool PlayBinCtrlerBase::OnVideoDecoderSetup(GstElement &elem)
1196 {
1197 const gchar *metadata = gst_element_get_metadata(&elem, GST_ELEMENT_METADATA_KLASS);
1198 if (metadata == nullptr) {
1199 MEDIA_LOGE("gst_element_get_metadata return nullptr");
1200 return false;
1201 }
1202
1203 std::string metaStr(metadata);
1204 if (metaStr.find("Decoder/Video") != std::string::npos) {
1205 return true;
1206 }
1207
1208 return false;
1209 }
1210
OnIsLiveStream(const GstElement * demux,gboolean isLiveStream,gpointer userData)1211 void PlayBinCtrlerBase::OnIsLiveStream(const GstElement *demux, gboolean isLiveStream, gpointer userData)
1212 {
1213 (void)demux;
1214 MEDIA_LOGI("is live stream: %{public}d", isLiveStream);
1215 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1216 if (isLiveStream) {
1217 PlayBinMessage msg { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_IS_LIVE_STREAM, 0, {} };
1218 thizStrong->ReportMessage(msg);
1219 }
1220 }
1221
OnAdaptiveElementSetup(GstElement & elem)1222 void PlayBinCtrlerBase::OnAdaptiveElementSetup(GstElement &elem)
1223 {
1224 const gchar *metadata = gst_element_get_metadata(&elem, GST_ELEMENT_METADATA_KLASS);
1225 if (metadata == nullptr) {
1226 return;
1227 }
1228
1229 std::string metaStr(metadata);
1230 if (metaStr.find("Demuxer/Adaptive") == std::string::npos) {
1231 return;
1232 }
1233 MEDIA_LOGI("get element_name %{public}s, get metadata %{public}s", GST_ELEMENT_NAME(&elem), metadata);
1234 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
1235 CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
1236 gulong id = g_signal_connect_data(&elem, "is-live-scene", G_CALLBACK(&PlayBinCtrlerBase::OnIsLiveStream), wrapper,
1237 (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
1238 CheckAndAddSignalIds(id, wrapper, &elem);
1239 }
1240
OnElementSetup(GstElement & elem)1241 void PlayBinCtrlerBase::OnElementSetup(GstElement &elem)
1242 {
1243 MEDIA_LOGI("element setup: %{public}s", ELEM_NAME(&elem));
1244 // limit to the g-signal, send this notification at this thread, do not change the work thread.
1245 // otherwise ,the avmetaengine will work improperly.
1246
1247 if (OnVideoDecoderSetup(elem) || strncmp(ELEM_NAME(&elem), "multiqueue", strlen("multiqueue")) == 0 ||
1248 strncmp(ELEM_NAME(&elem), "qtdemux", strlen("qtdemux")) == 0) {
1249 MEDIA_LOGI("add msgfilter element: %{public}s", ELEM_NAME(&elem));
1250 msgProcessor_->AddMsgFilter(ELEM_NAME(&elem));
1251 }
1252
1253 OnAdaptiveElementSetup(elem);
1254 std::string elementName(GST_ELEMENT_NAME(&elem));
1255 if (isNetWorkPlay_ == false && elementName.find("uridecodebin") != std::string::npos) {
1256 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
1257 CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
1258 gulong id = g_signal_connect_data(&elem, "autoplug-sort",
1259 G_CALLBACK(&PlayBinCtrlerBase::AutoPlugSort), wrapper,
1260 (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
1261 CheckAndAddSignalIds(id, wrapper, &elem);
1262 }
1263
1264 if (trackParse_ != nullptr) {
1265 trackParse_->OnElementSetup(elem);
1266 }
1267
1268 decltype(elemSetupListener_) listener = nullptr;
1269 {
1270 std::unique_lock<std::mutex> lock(listenerMutex_);
1271 listener = elemSetupListener_;
1272 }
1273
1274 if (listener != nullptr) {
1275 listener(elem);
1276 }
1277 }
1278
OnElementUnSetup(GstElement & elem)1279 void PlayBinCtrlerBase::OnElementUnSetup(GstElement &elem)
1280 {
1281 MEDIA_LOGI("element unsetup: %{public}s", ELEM_NAME(&elem));
1282 if (trackParse_ != nullptr) {
1283 trackParse_->OnElementUnSetup(elem);
1284 }
1285
1286 decltype(elemUnSetupListener_) listener = nullptr;
1287 {
1288 std::unique_lock<std::mutex> lock(listenerMutex_);
1289 listener = elemUnSetupListener_;
1290 }
1291
1292 if (listener != nullptr) {
1293 listener(elem);
1294 }
1295 RemoveSignalIds(&elem);
1296 }
1297
OnInterruptEventCb(const GstElement * audioSink,const uint32_t eventType,const uint32_t forceType,const uint32_t hintType,gpointer userData)1298 void PlayBinCtrlerBase::OnInterruptEventCb(const GstElement *audioSink, const uint32_t eventType,
1299 const uint32_t forceType, const uint32_t hintType, gpointer userData)
1300 {
1301 (void)audioSink;
1302 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1303 CHECK_AND_RETURN(thizStrong != nullptr);
1304 uint32_t value = 0;
1305 value = (((eventType << INTERRUPT_EVENT_SHIFT) | forceType) << INTERRUPT_EVENT_SHIFT) | hintType;
1306 PlayBinMessage msg { PLAYBIN_MSG_AUDIO_SINK, PLAYBIN_MSG_INTERRUPT_EVENT, 0, value };
1307 thizStrong->ReportMessage(msg);
1308 }
1309
OnAudioSegmentEventCb(const GstElement * audioSink,gpointer userData)1310 void PlayBinCtrlerBase::OnAudioSegmentEventCb(const GstElement *audioSink, gpointer userData)
1311 {
1312 (void)audioSink;
1313 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1314 CHECK_AND_RETURN(thizStrong != nullptr);
1315 if (thizStrong->subtitleSink_ != nullptr) {
1316 g_object_set(G_OBJECT(thizStrong->subtitleSink_), "segment-updated", TRUE, nullptr);
1317 }
1318 }
1319
OnAudioDiedEventCb(const GstElement * audioSink,gpointer userData)1320 void PlayBinCtrlerBase::OnAudioDiedEventCb(const GstElement *audioSink, gpointer userData)
1321 {
1322 (void)audioSink;
1323 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1324 CHECK_AND_RETURN(thizStrong != nullptr);
1325 MEDIA_LOGE("audio service died callback");
1326 PlayBinMessage msg {
1327 PLAYBIN_MSG_ERROR,
1328 PlayBinMsgErrorSubType::PLAYBIN_SUB_MSG_ERROR_WITH_MESSAGE,
1329 MSERR_AUD_RENDER_FAILED,
1330 std::string("audio service died!")
1331 };
1332 thizStrong->ReportMessage(msg);
1333 }
1334
OnBitRateParseCompleteCb(const GstElement * playbin,uint32_t * bitrateInfo,uint32_t bitrateNum,gpointer userData)1335 void PlayBinCtrlerBase::OnBitRateParseCompleteCb(const GstElement *playbin, uint32_t *bitrateInfo,
1336 uint32_t bitrateNum, gpointer userData)
1337 {
1338 (void)playbin;
1339 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1340 CHECK_AND_RETURN(thizStrong != nullptr);
1341 MEDIA_LOGD("bitrateNum = %{public}u", bitrateNum);
1342 for (uint32_t i = 0; i < bitrateNum; i++) {
1343 MEDIA_LOGD("bitrate = %{public}u", bitrateInfo[i]);
1344 thizStrong->bitRateVec_.push_back(bitrateInfo[i]);
1345 }
1346 Format format;
1347 (void)format.PutBuffer(std::string(PlayerKeys::PLAYER_BITRATE),
1348 static_cast<uint8_t *>(static_cast<void *>(bitrateInfo)), bitrateNum * sizeof(uint32_t));
1349 PlayBinMessage msg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BITRATE_COLLECT, 0, format };
1350 thizStrong->ReportMessage(msg);
1351 }
1352
AudioChanged(const GstElement * playbin,gpointer userData)1353 void PlayBinCtrlerBase::AudioChanged(const GstElement *playbin, gpointer userData)
1354 {
1355 (void)playbin;
1356 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1357 CHECK_AND_RETURN(thizStrong != nullptr);
1358 thizStrong->OnAudioChanged();
1359 }
1360
OnAudioChanged()1361 void PlayBinCtrlerBase::OnAudioChanged()
1362 {
1363 CHECK_AND_RETURN(playbin_ != nullptr && trackParse_ != nullptr);
1364 if (!trackParse_->FindTrackInfo()) {
1365 MEDIA_LOGI("The plugin has been cleared, no need to report it");
1366 return;
1367 }
1368
1369 int32_t audioIndex = -1;
1370 g_object_get(playbin_, "current-audio", &audioIndex, nullptr);
1371 MEDIA_LOGI("AudioChanged, current-audio %{public}d", audioIndex);
1372 if (audioIndex == audioIndex_) {
1373 MEDIA_LOGI("Audio Not Changed");
1374 return;
1375 }
1376
1377 if (isTrackChanging_) {
1378 MEDIA_LOGI("Waiting for the seek event to complete, not reporting at this time!");
1379 return;
1380 }
1381
1382 audioIndex_ = audioIndex;
1383 int32_t index;
1384 CHECK_AND_RETURN(trackParse_->GetTrackIndex(audioIndex, MediaType::MEDIA_TYPE_AUD, index) == MSERR_OK);
1385
1386 if (GetCurrState() == preparingState_) {
1387 MEDIA_LOGI("defaule audio index %{public}d, inner index %{public}d", index, audioIndex);
1388 Format format;
1389 (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), index);
1390 (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_TYPE), MediaType::MEDIA_TYPE_AUD);
1391 PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE,
1392 PlayBinMsgSubType::PLAYBIN_SUB_MSG_DEFAULE_TRACK, 0, format };
1393 ReportMessage(msg);
1394 return;
1395 }
1396
1397 Format format;
1398 (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), index);
1399 (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_IS_SELECT), true);
1400 PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE,
1401 PlayBinMsgSubType::PLAYBIN_SUB_MSG_AUDIO_CHANGED, 0, format };
1402 ReportMessage(msg);
1403 }
1404
OnSubtitleChanged()1405 void PlayBinCtrlerBase::OnSubtitleChanged()
1406 {
1407 CHECK_AND_RETURN(playbin_ != nullptr && trackParse_ != nullptr);
1408 if (!trackParse_->FindTrackInfo()) {
1409 MEDIA_LOGI("The plugin has been cleared, no need to report it");
1410 return;
1411 }
1412
1413 int32_t index;
1414 if (!hasSubtitleTrackSelected_) {
1415 index = -1;
1416 MEDIA_LOGI("SubtitleChanged, current text: -1");
1417 } else {
1418 int32_t subtitleIndex = -1;
1419 g_object_get(playbin_, "current-text", &subtitleIndex, nullptr);
1420 MEDIA_LOGI("SubtitleChanged, current text: %{public}d", subtitleIndex);
1421 CHECK_AND_RETURN(trackParse_->GetTrackIndex(subtitleIndex, MediaType::MEDIA_TYPE_SUBTITLE, index) == MSERR_OK);
1422 }
1423
1424 Format format;
1425 (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), index);
1426 (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_IS_SELECT), true);
1427 PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE,
1428 PlayBinMsgSubType::PLAYBIN_SUB_MSG_SUBTITLE_CHANGED, 0, format };
1429 ReportMessage(msg);
1430 }
1431
ReportTrackChange()1432 void PlayBinCtrlerBase::ReportTrackChange()
1433 {
1434 MEDIA_LOGI("Seek event completed, report track change!");
1435 if (trackChangeType_ == MediaType::MEDIA_TYPE_AUD) {
1436 OnAudioChanged();
1437 } else if (trackChangeType_ == MediaType::MEDIA_TYPE_SUBTITLE) {
1438 OnSubtitleChanged();
1439 }
1440 OnTrackDone();
1441 }
1442
OnTrackDone()1443 void PlayBinCtrlerBase::OnTrackDone()
1444 {
1445 PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE, PlayBinMsgSubType::PLAYBIN_SUB_MSG_TRACK_DONE, 0, {} };
1446 ReportMessage(msg);
1447 }
1448
OnAddSubDone()1449 void PlayBinCtrlerBase::OnAddSubDone()
1450 {
1451 PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE,
1452 PlayBinMsgSubType::PLAYBIN_SUB_MSG_ADD_SUBTITLE_DONE, 0, {} };
1453 ReportMessage(msg);
1454 }
1455
OnError(int32_t errorCode,std::string message)1456 void PlayBinCtrlerBase::OnError(int32_t errorCode, std::string message)
1457 {
1458 // There is no limit on the number of reports and the state machine is not changed.
1459 PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE,
1460 PlayBinMsgSubType::PLAYBIN_SUB_MSG_ONERROR, errorCode, message };
1461 ReportMessage(msg);
1462 }
1463
OnSelectBitrateDoneCb(const GstElement * playbin,uint32_t bandwidth,gpointer userData)1464 void PlayBinCtrlerBase::OnSelectBitrateDoneCb(const GstElement *playbin, uint32_t bandwidth, gpointer userData)
1465 {
1466 (void)playbin;
1467 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1468 MEDIA_LOGD("OnSelectBitrateDoneCb, Get bandwidth is: %{public}u", bandwidth);
1469 if (thizStrong != nullptr && bandwidth != 0) {
1470 thizStrong->isSelectBitRate_ = false;
1471 thizStrong->connectSpeed_ = bandwidth;
1472 PlayBinMessage msg = { PLAYBIN_MSG_BITRATEDONE, 0, bandwidth, {} };
1473 thizStrong->ReportMessage(msg);
1474 }
1475 }
1476
OnAppsrcMessageReceived(const InnerMessage & msg)1477 bool PlayBinCtrlerBase::OnAppsrcMessageReceived(const InnerMessage &msg)
1478 {
1479 MEDIA_LOGI("in OnAppsrcMessageReceived");
1480 if (msg.type == INNER_MSG_ERROR) {
1481 PlayBinMessage message { PlayBinMsgType::PLAYBIN_MSG_ERROR,
1482 PlayBinMsgErrorSubType::PLAYBIN_SUB_MSG_ERROR_WITH_MESSAGE,
1483 msg.detail1, msg.extend };
1484 ReportMessage(message);
1485 } else if (msg.type == INNER_MSG_BUFFERING) {
1486 if (msg.detail1 < static_cast<float>(BUFFER_LOW_PERCENT_DEFAULT) / BUFFER_HIGH_PERCENT_DEFAULT *
1487 BUFFER_PERCENT_THRESHOLD) {
1488 CHECK_AND_RETURN_RET_LOG(GetCurrState() == playingState_ && !isSeeking_ && !isRating_ && !isUserSetPause_,
1489 false, "ignore change to pause");
1490 std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
1491 MEDIA_LOGI("begin set to pause");
1492 GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_PAUSED);
1493 if (ret == GST_STATE_CHANGE_FAILURE) {
1494 MEDIA_LOGE("Failed to change playbin's state to GST_STATE_PAUSED");
1495 return false;
1496 }
1497 } else if (msg.detail1 >= BUFFER_PERCENT_THRESHOLD) {
1498 CHECK_AND_RETURN_RET_LOG(GetCurrState() == playingState_ && !isUserSetPause_,
1499 false, "ignore change to playing");
1500 std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
1501 MEDIA_LOGI("begin set to play");
1502 GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_PLAYING);
1503 if (ret == GST_STATE_CHANGE_FAILURE) {
1504 MEDIA_LOGE("Failed to change playbin's state to GST_STATE_PLAYING");
1505 return false;
1506 }
1507 }
1508 }
1509 return true;
1510 }
1511
OnMessageReceived(const InnerMessage & msg)1512 void PlayBinCtrlerBase::OnMessageReceived(const InnerMessage &msg)
1513 {
1514 HandleMessage(msg);
1515 }
1516
OnSinkMessageReceived(const PlayBinMessage & msg)1517 void PlayBinCtrlerBase::OnSinkMessageReceived(const PlayBinMessage &msg)
1518 {
1519 ReportMessage(msg);
1520 }
1521
SetNotifier(PlayBinMsgNotifier notifier)1522 void PlayBinCtrlerBase::SetNotifier(PlayBinMsgNotifier notifier)
1523 {
1524 std::unique_lock<std::mutex> lock(mutex_);
1525 notifier_ = notifier;
1526 }
1527
SetAutoSelectBitrate(bool enable)1528 void PlayBinCtrlerBase::SetAutoSelectBitrate(bool enable)
1529 {
1530 if (enable) {
1531 g_object_set(playbin_, "connection-speed", 0, nullptr);
1532 } else if (connectSpeed_ == 0) {
1533 g_object_set(playbin_, "connection-speed", CONNECT_SPEED_DEFAULT, nullptr);
1534 }
1535 }
1536
ReportMessage(const PlayBinMessage & msg)1537 void PlayBinCtrlerBase::ReportMessage(const PlayBinMessage &msg)
1538 {
1539 if (msg.type == PlayBinMsgType::PLAYBIN_MSG_ERROR) {
1540 MEDIA_LOGE("error happend, error code: %{public}d", msg.code);
1541
1542 {
1543 std::unique_lock<std::mutex> lock(mutex_);
1544 isErrorHappened_ = true;
1545 preparingCond_.notify_all();
1546 stoppingCond_.notify_all();
1547 }
1548 }
1549
1550 MEDIA_LOGD("report msg, type: %{public}d", msg.type);
1551
1552 PlayBinMsgNotifier notifier = notifier_;
1553 if (notifier != nullptr) {
1554 auto msgReportHandler = std::make_shared<TaskHandler<void>>([msg, notifier]() {
1555 LISTENER(notifier(msg), "PlayBinCtrlerBase::ReportMessage", PlayerXCollie::timerTimeout)
1556 });
1557 (void)msgQueue_->EnqueueTask(msgReportHandler);
1558 }
1559
1560 if (msg.type == PlayBinMsgType::PLAYBIN_MSG_EOS) {
1561 ProcessEndOfStream();
1562 }
1563 }
1564
CheckAndAddSignalIds(gulong id,PlayBinCtrlerWrapper * wrapper,GstElement * elem)1565 void PlayBinCtrlerBase::CheckAndAddSignalIds(gulong id, PlayBinCtrlerWrapper *wrapper, GstElement *elem)
1566 {
1567 if (id == 0) {
1568 delete wrapper;
1569 MEDIA_LOGW("add signal failed");
1570 } else {
1571 AddSignalIds(elem, id);
1572 }
1573 }
1574
SetPlayerState(GstPlayerStatus status)1575 bool PlayBinCtrlerBase::SetPlayerState(GstPlayerStatus status)
1576 {
1577 std::unique_lock<std::mutex> stateChangeLock(stateChangePropertyMutex_);
1578 if (stopBuffering_) {
1579 MEDIA_LOGD("Do not set player state when stopping");
1580 return false;
1581 }
1582 std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
1583 g_object_set(playbin_, "state-change", status, nullptr);
1584 return true;
1585 }
1586 } // namespace Media
1587 } // namespace OHOS
1588
1589