1 /*
2 * Copyright (C) 2022 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 "player_codec_ctrl.h"
17 #include "surface.h"
18 #include "media_log.h"
19 #include "media_errors.h"
20 #include "param_wrapper.h"
21
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PlayerCodecCtrl"};
24 }
25
26 namespace OHOS {
27 namespace Media {
28 constexpr uint32_t MAX_SOFT_BUFFERS = 10;
29 constexpr uint32_t DEFAULT_CACHE_BUFFERS = 1;
30
PlayerCodecCtrl()31 PlayerCodecCtrl::PlayerCodecCtrl()
32 {
33 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
34 DisablePerformanceBySysParam();
35 }
36
~PlayerCodecCtrl()37 PlayerCodecCtrl::~PlayerCodecCtrl()
38 {
39 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
40 notifier_ = nullptr;
41 elementMap_.clear();
42 }
43
SetupCodecCb(const std::string & metaStr,GstElement * src,GstElement * videoSink,CapsFixErrorNotifier notifier)44 void PlayerCodecCtrl::SetupCodecCb(const std::string &metaStr, GstElement *src, GstElement *videoSink,
45 CapsFixErrorNotifier notifier)
46 {
47 if (metaStr.find("Codec/Decoder/Video/Hardware") != std::string::npos) {
48 // hardware dec
49 isHardwareDec_ = true;
50 notifier_ = notifier;
51 DecoderElement element;
52 element.isHardware = true;
53 element.signalId = g_signal_connect(src, "caps-fix-error", G_CALLBACK(&PlayerCodecCtrl::CapsFixErrorCb), this);
54 elementMap_[src] = element;
55 MEDIA_LOGD("add decoder element size = %{public}zu", elementMap_.size());
56 g_object_set(G_OBJECT(src), "player-mode", TRUE, nullptr);
57 if (!codecTypeList_.empty()) {
58 // For hls scene when change codec, the second codec should not go performance mode process.
59 codecTypeList_.push_back(true);
60 return;
61 }
62 // For performance mode.
63 codecTypeList_.push_back(true);
64
65 g_object_set(G_OBJECT(src), "player-scene", TRUE, nullptr);
66 if (isEnablePerformanceMode_) {
67 g_object_set(G_OBJECT(src), "performance-mode", TRUE, nullptr);
68 g_object_set(G_OBJECT(videoSink), "performance-mode", TRUE, nullptr);
69 }
70
71 GstCaps *caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "NV12", nullptr);
72 g_object_set(G_OBJECT(videoSink), "caps", caps, nullptr);
73 g_object_set(G_OBJECT(src), "sink-caps", caps, nullptr);
74 gst_caps_unref(caps);
75
76 GstBufferPool *pool;
77 g_object_get(videoSink, "surface-pool", &pool, nullptr);
78 g_object_set(G_OBJECT(src), "surface-pool", pool, nullptr);
79 } else if (metaStr.find("Codec/Decoder/Video") != std::string::npos) {
80 // software dec
81 codecTypeList_.push_back(false);
82 isHardwareDec_ = false;
83 }
84 }
85
DetectCodecSetup(const std::string & metaStr,GstElement * src,GstElement * videoSink,CapsFixErrorNotifier notifier)86 void PlayerCodecCtrl::DetectCodecSetup(const std::string &metaStr, GstElement *src, GstElement *videoSink,
87 CapsFixErrorNotifier notifier)
88 {
89 std::lock_guard<std::mutex> lock(mutex_);
90 MEDIA_LOGD("Codec Setup");
91 SetupCodecCb(metaStr, src, videoSink, notifier);
92 if (IsFirstCodecSetup()) {
93 SetupCodecBufferNum(metaStr, videoSink);
94 MEDIA_LOGI("0x%{public}06" PRIXPTR " Set isHardwareDec_ %{public}d", FAKE_POINTER(this), isHardwareDec_);
95 g_object_set(videoSink, "is-hardware-decoder", isHardwareDec_, nullptr);
96 isHEBCMode_ = isHardwareDec_;
97 }
98 }
99
SetupCodecBufferNum(const std::string & metaStr,GstElement * src) const100 void PlayerCodecCtrl::SetupCodecBufferNum(const std::string &metaStr, GstElement *src) const
101 {
102 if (metaStr.find("Sink/Video") != std::string::npos && !isHardwareDec_) {
103 g_object_set(G_OBJECT(src), "max-pool-capacity", MAX_SOFT_BUFFERS, nullptr);
104 g_object_set(G_OBJECT(src), "cache-buffers-num", DEFAULT_CACHE_BUFFERS, nullptr);
105 }
106 }
107
CapsFixErrorCb(const GstElement * decoder,gpointer userData)108 void PlayerCodecCtrl::CapsFixErrorCb(const GstElement *decoder, gpointer userData)
109 {
110 CHECK_AND_RETURN_LOG(decoder != nullptr, "decoder is nullptr");
111 CHECK_AND_RETURN_LOG(userData != nullptr, "userData is nullptr");
112 MEDIA_LOGD("CapsFixErrorCb in");
113
114 auto playerCodecCtrl = static_cast<PlayerCodecCtrl *>(userData);
115 if (playerCodecCtrl->notifier_ != nullptr) {
116 playerCodecCtrl->notifier_();
117 }
118 }
119
DetectCodecUnSetup(GstElement * src,GstElement * videoSink)120 void PlayerCodecCtrl::DetectCodecUnSetup(GstElement *src, GstElement *videoSink)
121 {
122 std::lock_guard<std::mutex> lock(mutex_);
123 MEDIA_LOGD("Codec UnSetup");
124 auto it = elementMap_.find(src);
125 if (it != elementMap_.end()) {
126 if (elementMap_[src].signalId != 0) {
127 g_signal_handler_disconnect(src, elementMap_[src].signalId);
128 elementMap_[src].signalId = 0;
129 }
130 elementMap_.erase(it);
131 }
132 MEDIA_LOGD("del decoder element size = %{public}zu", elementMap_.size());
133 HlsSwichSoftAndHardCodec(videoSink);
134 }
135
HlsSwichSoftAndHardCodec(GstElement * videoSink)136 void PlayerCodecCtrl::HlsSwichSoftAndHardCodec(GstElement *videoSink)
137 {
138 CHECK_AND_RETURN_LOG(!codecTypeList_.empty(), "codec type list is empty");
139
140 bool codecType = codecTypeList_.front();
141 codecTypeList_.pop_front();
142 if ((codecTypeList_.empty()) || (codecType == codecTypeList_.front())) {
143 MEDIA_LOGD("codec type is empty or the next is same");
144 return;
145 }
146
147 GstCaps *caps = nullptr;
148 if (codecTypeList_.front()) {
149 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "NV12", nullptr);
150 g_object_set(G_OBJECT(videoSink), "max-pool-capacity", SURFACE_MAX_QUEUE_SIZE, nullptr);
151 g_object_set(G_OBJECT(videoSink), "cache-buffers-num", 0, nullptr);
152 } else {
153 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "RGBA", nullptr);
154 g_object_set(G_OBJECT(videoSink), "max-pool-capacity", MAX_SOFT_BUFFERS, nullptr);
155 g_object_set(G_OBJECT(videoSink), "cache-buffers-num", DEFAULT_CACHE_BUFFERS, nullptr);
156 }
157 MEDIA_LOGI("Set isHardwareDec_ %{public}d", codecTypeList_.front());
158 g_object_set(videoSink, "is-hardware-decoder", codecTypeList_.front(), nullptr);
159 isHEBCMode_ = codecTypeList_.front();
160 g_object_set(G_OBJECT(videoSink), "caps", caps, nullptr);
161 gst_caps_unref(caps);
162 }
163
EnhanceSeekPerformance(bool enable)164 void PlayerCodecCtrl::EnhanceSeekPerformance(bool enable)
165 {
166 std::lock_guard<std::mutex> lock(mutex_);
167 MEDIA_LOGD("EnhanceSeekPerformance %{public}d", enable);
168 for (auto &it : elementMap_) {
169 if (it.second.isHardware) {
170 g_object_set(it.first, "seeking", enable, nullptr);
171 }
172 }
173 }
174
GetHEBCMode() const175 int32_t PlayerCodecCtrl::GetHEBCMode() const
176 {
177 return isHEBCMode_;
178 }
179
IsFirstCodecSetup() const180 bool PlayerCodecCtrl::IsFirstCodecSetup() const
181 {
182 return codecTypeList_.size() == 1;
183 }
184
HandleCodecBuffers(bool enable)185 int32_t PlayerCodecCtrl::HandleCodecBuffers(bool enable)
186 {
187 std::lock_guard<std::mutex> lock(mutex_);
188 MEDIA_LOGD("HandleCodecBuffers %{public}d", enable);
189 for (auto &it : elementMap_) {
190 if (it.second.isHardware) {
191 if (enable) {
192 g_object_set(it.first, "free_codec_buffers", enable, nullptr);
193 } else {
194 g_object_set(it.first, "recover_codec_buffers", enable, nullptr);
195 }
196 return MSERR_OK;
197 }
198 }
199 return MSERR_INVALID_OPERATION;
200 }
201
StopFormatChange()202 void PlayerCodecCtrl::StopFormatChange()
203 {
204 std::lock_guard<std::mutex> lock(mutex_);
205 MEDIA_LOGD("StopFormatChange");
206 for (auto &it : elementMap_) {
207 if (it.second.isHardware) {
208 g_object_set(it.first, "stop-format-change", TRUE, nullptr);
209 }
210 }
211 }
DisablePerformanceBySysParam()212 void PlayerCodecCtrl::DisablePerformanceBySysParam()
213 {
214 std::string cmd;
215 int32_t ret = OHOS::system::GetStringParameter("sys.media.player.performance.enable", cmd, "");
216 if (ret == 0 && !cmd.empty()) {
217 isEnablePerformanceMode_ = cmd == "FALSE" ? false : true;
218 }
219 }
220 } // Media
221 } // OHOS