• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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