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 "player_sinkprovider.h"
17 #include <sync_fence.h>
18 #include "securec.h"
19 #include "display_type.h"
20 #include "param_wrapper.h"
21 #include "surface_buffer_impl.h"
22 #include "gst/video/gstvideometa.h"
23 #include "media_log.h"
24 #include "media_errors.h"
25 #include "media_dfx.h"
26
27 namespace {
28 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PlayerSinkProvider"};
29 constexpr uint32_t DEFAULT_BUFFER_NUM = 8;
30 }
31
32 namespace OHOS {
33 namespace Media {
PlayerSinkProvider(const sptr<Surface> & surface)34 PlayerSinkProvider::PlayerSinkProvider(const sptr<Surface> &surface)
35 : producerSurface_(surface)
36 {
37 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
38 }
39
~PlayerSinkProvider()40 PlayerSinkProvider::~PlayerSinkProvider()
41 {
42 MEDIA_LOGD("enter dtor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
43
44 producerSurface_ = nullptr;
45 if (audioSink_ != nullptr) {
46 gst_object_unref(audioSink_);
47 audioSink_ = nullptr;
48 }
49 if (videoSink_ != nullptr) {
50 gst_object_unref(videoSink_);
51 videoSink_ = nullptr;
52 }
53 if (audioCaps_ != nullptr) {
54 gst_caps_unref(audioCaps_);
55 audioCaps_ = nullptr;
56 }
57 if (videoCaps_ != nullptr) {
58 gst_caps_unref(videoCaps_);
59 videoCaps_ = nullptr;
60 }
61 }
62
CreateAudioSink()63 PlayBinSinkProvider::SinkPtr PlayerSinkProvider::CreateAudioSink()
64 {
65 constexpr gint rate = 44100;
66 constexpr gint channels = 2;
67
68 if (audioSink_ != nullptr) {
69 gst_object_unref(audioSink_);
70 audioSink_ = nullptr;
71 }
72 if (audioCaps_ == nullptr) {
73 audioCaps_ = gst_caps_new_simple("audio/x-raw",
74 "format", G_TYPE_STRING, "S16LE",
75 "rate", G_TYPE_INT, rate,
76 "channels", G_TYPE_INT, channels, nullptr);
77 CHECK_AND_RETURN_RET_LOG(audioCaps_ != nullptr, nullptr, "gst_caps_new_simple failed..");
78
79 audioSink_ = DoCreateAudioSink(audioCaps_, reinterpret_cast<gpointer>(this));
80 CHECK_AND_RETURN_RET_LOG(audioSink_ != nullptr, nullptr, "CreateAudioSink failed..");
81 }
82
83 return audioSink_;
84 }
85
EnableOptRenderDelay() const86 bool PlayerSinkProvider::EnableOptRenderDelay() const
87 {
88 std::string enable;
89 int32_t res = OHOS::system::GetStringParameter("sys.media.kpi.opt.renderdelay.enable", enable, "");
90 if (res != 0 || enable.empty()) {
91 MEDIA_LOGW("KPI-TRACE: get value fail, default enable");
92 return true;
93 }
94
95 MEDIA_LOGI("KPI-TRACE: sys.media.kpi.opt.renderdelay.enable=%{public}s", enable.c_str());
96 if (enable != "true") {
97 return false;
98 }
99 return true;
100 }
101
DoCreateAudioSink(const GstCaps * caps,const gpointer userData)102 GstElement *PlayerSinkProvider::DoCreateAudioSink(const GstCaps *caps, const gpointer userData)
103 {
104 (void)caps;
105 MEDIA_LOGI("CreateAudioSink in.");
106 CHECK_AND_RETURN_RET_LOG(userData != nullptr, nullptr, "input userData is nullptr..");
107
108 auto sink = GST_ELEMENT_CAST(gst_object_ref_sink(gst_element_factory_make("audioserversink", nullptr)));
109 CHECK_AND_RETURN_RET_LOG(sink != nullptr, nullptr, "gst_element_factory_make failed..");
110
111 g_object_set(G_OBJECT(sink), "app-uid", uid_, nullptr);
112 g_object_set(G_OBJECT(sink), "app-pid", pid_, nullptr);
113
114 gboolean enable = static_cast<gboolean>(EnableOptRenderDelay());
115 g_object_set(G_OBJECT(sink), "enable-opt-render-delay", enable, nullptr);
116
117 GstPad *pad = gst_element_get_static_pad(sink, "sink");
118 if (pad == nullptr) {
119 gst_object_unref(sink);
120 MEDIA_LOGE("gst_element_get_static_pad failed..");
121 return nullptr;
122 }
123
124 (void)gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM,
125 PlayerSinkProvider::SinkPadProbeCb, userData, nullptr);
126 gst_object_unref(pad);
127 return sink;
128 }
129
EnableKpiAVSyncLog() const130 bool PlayerSinkProvider::EnableKpiAVSyncLog() const
131 {
132 std::string enable;
133 int32_t res = OHOS::system::GetStringParameter("sys.media.kpi.avsync.log.enable", enable, "");
134 if (res != 0 || enable.empty()) {
135 return false;
136 }
137
138 MEDIA_LOGI("KPI-TRACE: sys.media.kpi.avsync.log.enable=%{public}s", enable.c_str());
139 if (enable != "true") {
140 return false;
141 }
142 return true;
143 }
144
CreateVideoSink()145 PlayBinSinkProvider::SinkPtr PlayerSinkProvider::CreateVideoSink()
146 {
147 if (producerSurface_ == nullptr) {
148 MEDIA_LOGI("producerSurface_ is nullptr, cannot create video sink!");
149 return nullptr;
150 }
151
152 if (videoCaps_ == nullptr) {
153 videoCaps_ = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "RGBA", nullptr);
154 CHECK_AND_RETURN_RET_LOG(videoCaps_ != nullptr, nullptr, "gst_caps_new_simple failed..");
155
156 videoSink_ = DoCreateVideoSink(videoCaps_, reinterpret_cast<gpointer>(this));
157 CHECK_AND_RETURN_RET_LOG(videoSink_ != nullptr, nullptr, "CreateVideoSink failed..");
158 }
159
160 if (audioSink_ != nullptr) {
161 MEDIA_LOGI("KPI-TRACE: set audio sink to video sink");
162 gboolean enable = static_cast<gboolean>(EnableKpiAVSyncLog());
163 g_object_set(G_OBJECT(videoSink_), "audio-sink", audioSink_, "enable-kpi-avsync-log", enable, nullptr);
164 }
165
166 (void)producerSurface_->SetQueueSize(DEFAULT_BUFFER_NUM);
167 queueSize_ = DEFAULT_BUFFER_NUM;
168
169 return videoSink_;
170 }
171
DoCreateVideoSink(const GstCaps * caps,const gpointer userData)172 GstElement *PlayerSinkProvider::DoCreateVideoSink(const GstCaps *caps, const gpointer userData)
173 {
174 MEDIA_LOGI("CreateVideoSink in.");
175 CHECK_AND_RETURN_RET_LOG(caps != nullptr, nullptr, "input caps is nullptr..");
176 CHECK_AND_RETURN_RET_LOG(userData != nullptr, nullptr, "input userData is nullptr..");
177 PlayerSinkProvider *sinkProvider = reinterpret_cast<PlayerSinkProvider *>(userData);
178
179 auto sink = GST_ELEMENT_CAST(gst_object_ref_sink(gst_element_factory_make("videodisplaysink", "sink")));
180 CHECK_AND_RETURN_RET_LOG(sink != nullptr, nullptr, "gst_element_factory_make failed..");
181 gst_base_sink_set_async_enabled(GST_BASE_SINK(sink), FALSE);
182
183 g_object_set(G_OBJECT(sink), "caps", caps, nullptr);
184 g_object_set(G_OBJECT(sink), "surface", static_cast<gpointer>(sinkProvider->GetProducerSurface()), nullptr);
185 g_object_set(G_OBJECT(sink), "video-scale-type", videoScaleType_, nullptr);
186
187 GstMemSinkCallbacks sinkCallbacks = { PlayerSinkProvider::EosCb, PlayerSinkProvider::NewPrerollCb,
188 PlayerSinkProvider::NewSampleCb };
189 gst_mem_sink_set_callback(GST_MEM_SINK(sink), &sinkCallbacks, userData, nullptr);
190
191 return sink;
192 }
193
GetVideoSink()194 PlayBinSinkProvider::SinkPtr PlayerSinkProvider::GetVideoSink()
195 {
196 CHECK_AND_RETURN_RET_LOG(videoSink_ != nullptr, nullptr, "videoSink is nullptr");
197 return GST_ELEMENT_CAST(videoSink_);
198 }
199
FirstRenderFrame(gpointer userData)200 void PlayerSinkProvider::FirstRenderFrame(gpointer userData)
201 {
202 CHECK_AND_RETURN_LOG(userData != nullptr, "input userData is nullptr..");
203 PlayerSinkProvider *sinkProvider = reinterpret_cast<PlayerSinkProvider *>(userData);
204
205 sinkProvider->OnFirstRenderFrame();
206 }
207
OnFirstRenderFrame()208 void PlayerSinkProvider::OnFirstRenderFrame()
209 {
210 std::unique_lock<std::mutex> lock(mutex_);
211 if (notifier_ != nullptr) {
212 if (GetFirstRenderFrameFlag()) {
213 PlayBinMessage msg { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_VIDEO_RENDERING_START, 0, {} };
214 notifier_(msg);
215 SetFirstRenderFrameFlag(false);
216 MEDIA_LOGW("KPI-TRACE: FIRST-VIDEO-FRAME rendered");
217 }
218 }
219 }
220
EosCb(GstMemSink * memSink,gpointer userData)221 void PlayerSinkProvider::EosCb(GstMemSink *memSink, gpointer userData)
222 {
223 (void)memSink;
224 (void)userData;
225 MEDIA_LOGI("EOS in");
226 }
227
NewPrerollCb(GstMemSink * memSink,GstBuffer * sample,gpointer userData)228 GstFlowReturn PlayerSinkProvider::NewPrerollCb(GstMemSink *memSink, GstBuffer *sample, gpointer userData)
229 {
230 (void)userData;
231 MEDIA_LOGI("NewPrerollCb in");
232 MediaTrace trace("PlayerSinkProvider::NewPrerollCb");
233 CHECK_AND_RETURN_RET(gst_mem_sink_app_preroll_render(memSink, sample) == GST_FLOW_OK, GST_FLOW_ERROR);
234 return GST_FLOW_OK;
235 }
236
NewSampleCb(GstMemSink * memSink,GstBuffer * sample,gpointer userData)237 GstFlowReturn PlayerSinkProvider::NewSampleCb(GstMemSink *memSink, GstBuffer *sample, gpointer userData)
238 {
239 MEDIA_LOGI("NewSampleCb in");
240 MediaTrace trace("PlayerSinkProvider::NewSampleCb");
241 CHECK_AND_RETURN_RET(gst_mem_sink_app_render(memSink, sample) == GST_FLOW_OK, GST_FLOW_ERROR);
242
243 FirstRenderFrame(userData);
244 return GST_FLOW_OK;
245 }
246
SinkPadProbeCb(GstPad * pad,GstPadProbeInfo * info,gpointer userData)247 GstPadProbeReturn PlayerSinkProvider::SinkPadProbeCb(GstPad *pad, GstPadProbeInfo *info, gpointer userData)
248 {
249 (void)pad;
250 (void)userData;
251 GstQuery *query = GST_PAD_PROBE_INFO_QUERY(info);
252 if (GST_QUERY_TYPE(query) == GST_QUERY_ALLOCATION) {
253 GstCaps *caps = nullptr;
254 gboolean needPool;
255 gst_query_parse_allocation(query, &caps, &needPool);
256
257 auto s = gst_caps_get_structure(caps, 0);
258 auto mediaType = gst_structure_get_name(s);
259 gboolean isVideo = g_str_has_prefix(mediaType, "video/");
260 if (isVideo) {
261 gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, nullptr);
262 }
263 }
264 return GST_PAD_PROBE_OK;
265 }
266
SetMsgNotifier(PlayBinMsgNotifier notifier)267 void PlayerSinkProvider::SetMsgNotifier(PlayBinMsgNotifier notifier)
268 {
269 std::unique_lock<std::mutex> lock(mutex_);
270 notifier_ = notifier;
271 }
272
SetFirstRenderFrameFlag(bool firstRenderFrame)273 void PlayerSinkProvider::SetFirstRenderFrameFlag(bool firstRenderFrame)
274 {
275 firstRenderFrame_ = firstRenderFrame;
276 }
277
GetFirstRenderFrameFlag() const278 bool PlayerSinkProvider::GetFirstRenderFrameFlag() const
279 {
280 return firstRenderFrame_;
281 }
282
GetProducerSurface() const283 const sptr<Surface> PlayerSinkProvider::GetProducerSurface() const
284 {
285 return producerSurface_;
286 }
287
SetVideoScaleType(const uint32_t videoScaleType)288 void PlayerSinkProvider::SetVideoScaleType(const uint32_t videoScaleType)
289 {
290 if (videoSink_ != nullptr) {
291 g_object_set(videoSink_, "video-scale-type", videoScaleType, nullptr);
292 } else {
293 videoScaleType_ = videoScaleType;
294 }
295 }
296
SetAppInfo(int32_t uid,int32_t pid)297 void PlayerSinkProvider::SetAppInfo(int32_t uid, int32_t pid)
298 {
299 uid_ = uid;
300 pid_ = pid;
301 }
302 }
303 }
304