• 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 "securec.h"
18 #include "display_type.h"
19 #include "param_wrapper.h"
20 #include "gst/video/gstvideometa.h"
21 #include "media_log.h"
22 #include "media_errors.h"
23 #include "media_dfx.h"
24 
25 namespace {
26     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PlayerSinkProvider"};
27     constexpr uint32_t DEFAULT_BUFFER_NUM = 8;
28 }
29 
30 namespace OHOS {
31 namespace Media {
PlayerSinkProvider(const sptr<Surface> & surface)32 PlayerSinkProvider::PlayerSinkProvider(const sptr<Surface> &surface)
33     : producerSurface_(surface)
34 {
35     MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
36 }
37 
~PlayerSinkProvider()38 PlayerSinkProvider::~PlayerSinkProvider()
39 {
40     MEDIA_LOGD("enter dtor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
41 
42     producerSurface_ = nullptr;
43     if (audioSink_ != nullptr) {
44         gst_object_unref(audioSink_);
45         audioSink_ = nullptr;
46     }
47     if (videoSink_ != nullptr) {
48         gst_object_unref(videoSink_);
49         videoSink_ = nullptr;
50     }
51     if (subtitleSink_ != nullptr) {
52         gst_object_unref(subtitleSink_);
53         subtitleSink_ = nullptr;
54     }
55     if (audioCaps_ != nullptr) {
56         gst_caps_unref(audioCaps_);
57         audioCaps_ = nullptr;
58     }
59     if (videoCaps_ != nullptr) {
60         gst_caps_unref(videoCaps_);
61         videoCaps_ = nullptr;
62     }
63 }
64 
CreateAudioSink()65 PlayBinSinkProvider::SinkPtr PlayerSinkProvider::CreateAudioSink()
66 {
67     constexpr gint rate = 44100;
68     constexpr gint channels = 2;
69 
70     if (audioSink_ != nullptr) {
71         gst_object_unref(audioSink_);
72         audioSink_ = nullptr;
73     }
74     if (audioCaps_ == nullptr) {
75         audioCaps_ = gst_caps_new_simple("audio/x-raw",
76                                          "format", G_TYPE_STRING, "S16LE",
77                                          "rate", G_TYPE_INT, rate,
78                                          "channels", G_TYPE_INT, channels, nullptr);
79         CHECK_AND_RETURN_RET_LOG(audioCaps_ != nullptr, nullptr, "gst_caps_new_simple failed..");
80 
81         audioSink_ = DoCreateAudioSink(audioCaps_, reinterpret_cast<gpointer>(this));
82         CHECK_AND_RETURN_RET_LOG(audioSink_ != nullptr, nullptr, "CreateAudioSink failed..");
83     }
84 
85     return audioSink_;
86 }
87 
EnableOptRenderDelay() const88 bool PlayerSinkProvider::EnableOptRenderDelay() const
89 {
90     std::string enable;
91     int32_t res = OHOS::system::GetStringParameter("sys.media.kpi.opt.renderdelay.enable", enable, "");
92     if (res != 0 || enable.empty()) {
93         MEDIA_LOGW("KPI-TRACE: get value fail, default enable");
94         return true;
95     }
96 
97     MEDIA_LOGI("KPI-TRACE: sys.media.kpi.opt.renderdelay.enable=%{public}s", enable.c_str());
98     if (enable != "true") {
99         return false;
100     }
101     return true;
102 }
103 
DoCreateAudioSink(const GstCaps * caps,const gpointer userData)104 GstElement *PlayerSinkProvider::DoCreateAudioSink(const GstCaps *caps, const gpointer userData)
105 {
106     (void)caps;
107     MEDIA_LOGI("CreateAudioSink in.");
108     CHECK_AND_RETURN_RET_LOG(userData != nullptr, nullptr, "input userData is nullptr..");
109 
110     auto sink = GST_ELEMENT_CAST(gst_object_ref_sink(gst_element_factory_make("audioserversink", nullptr)));
111     CHECK_AND_RETURN_RET_LOG(sink != nullptr, nullptr, "gst_element_factory_make failed..");
112 
113     g_object_set(G_OBJECT(sink), "app-uid", uid_, nullptr);
114     g_object_set(G_OBJECT(sink), "app-pid", pid_, nullptr);
115     g_object_set(G_OBJECT(sink), "app-token-id", tokenId_, nullptr);
116 
117     gboolean enable = static_cast<gboolean>(EnableOptRenderDelay());
118     g_object_set(G_OBJECT(sink), "enable-opt-render-delay", enable, nullptr);
119 
120     GstPad *pad = gst_element_get_static_pad(sink, "sink");
121     if (pad == nullptr) {
122         gst_object_unref(sink);
123         MEDIA_LOGE("gst_element_get_static_pad failed..");
124         return nullptr;
125     }
126 
127     (void)gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM,
128         PlayerSinkProvider::SinkPadProbeCb, userData, nullptr);
129     gst_object_unref(pad);
130     return sink;
131 }
132 
EnableKpiAVSyncLog() const133 bool PlayerSinkProvider::EnableKpiAVSyncLog() const
134 {
135     std::string enable;
136     int32_t res = OHOS::system::GetStringParameter("sys.media.kpi.avsync.log.enable", enable, "");
137     if (res != 0 || enable.empty()) {
138         return false;
139     }
140 
141     MEDIA_LOGI("KPI-TRACE: sys.media.kpi.avsync.log.enable=%{public}s", enable.c_str());
142     if (enable != "true") {
143         return false;
144     }
145     return true;
146 }
147 
CreateVideoSink()148 PlayBinSinkProvider::SinkPtr PlayerSinkProvider::CreateVideoSink()
149 {
150     CHECK_AND_RETURN_RET_LOG(producerSurface_ != nullptr, nullptr,
151         "producerSurface_ is nullptr, cannot create video sink!");
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     CHECK_AND_RETURN(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 
CreateSubtitleSink()220 PlayBinSinkProvider::SinkPtr PlayerSinkProvider::CreateSubtitleSink()
221 {
222     if (subtitleSink_ != nullptr) {
223         gst_object_unref(subtitleSink_);
224         subtitleSink_ = nullptr;
225     }
226     subtitleSink_ = DoCreateSubtitleSink(reinterpret_cast<gpointer>(this));
227     CHECK_AND_RETURN_RET_LOG(subtitleSink_ != nullptr, nullptr, "CreateSubtitleSink failed..");
228     g_object_set(G_OBJECT(subtitleSink_), "audio-sink", audioSink_, nullptr);
229     return subtitleSink_;
230 }
231 
DoCreateSubtitleSink(const gpointer userData)232 GstElement *PlayerSinkProvider::DoCreateSubtitleSink(const gpointer userData)
233 {
234     MEDIA_LOGI("CreateSubtitleSink in.");
235     CHECK_AND_RETURN_RET_LOG(userData != nullptr, nullptr, "input userData is nullptr..");
236 
237     auto sink = GST_ELEMENT_CAST(gst_object_ref_sink(gst_element_factory_make("subtitledisplaysink", nullptr)));
238     CHECK_AND_RETURN_RET_LOG(sink != nullptr, nullptr, "gst_element_factory_make failed..");
239 
240     GstSubtitleSinkCallbacks sinkCallbacks = { PlayerSinkProvider::SubtitleUpdated };
241     gst_subtitle_sink_set_callback(GST_SUBTITLE_SINK(sink), &sinkCallbacks, userData, nullptr);
242     MEDIA_LOGI("CreateSubtitleSink out.");
243     return sink;
244 }
245 
HandleSubtitleBuffer(GstBuffer * sample,Format & subtitle)246 void PlayerSinkProvider::HandleSubtitleBuffer(GstBuffer *sample, Format &subtitle)
247 {
248     if (sample == nullptr) {
249         (void)subtitle.PutStringValue(PlayerKeys::SUBTITLE_TEXT, "");
250         return;
251     }
252     GstMapInfo mapInfo;
253     CHECK_AND_RETURN(gst_buffer_map(sample, &mapInfo, GST_MAP_READ));
254     uint32_t gstBufferSize = static_cast<uint32_t>(gst_buffer_get_size(sample));
255     char *textFrame = new (std::nothrow) char[gstBufferSize + 1];
256     (void)memcpy_s(textFrame, gstBufferSize + 1, mapInfo.data, gstBufferSize);
257     textFrame[gstBufferSize] = static_cast<char>(0);
258     (void)subtitle.PutStringValue(PlayerKeys::SUBTITLE_TEXT, std::string_view(textFrame));
259     MEDIA_LOGD("text = %{public}s", textFrame);
260     delete[] textFrame;
261     gst_buffer_unmap(sample, &mapInfo);
262 }
263 
SubtitleUpdated(GstBuffer * sample,gpointer userData)264 GstFlowReturn PlayerSinkProvider::SubtitleUpdated(GstBuffer *sample, gpointer userData)
265 {
266     MediaTrace trace("PlayerSinkProvider::SubtitleUpdated");
267     CHECK_AND_RETURN_RET(userData != nullptr, GST_FLOW_ERROR);
268     PlayerSinkProvider *sinkProvider = reinterpret_cast<PlayerSinkProvider *>(userData);
269     Format subtitle;
270     sinkProvider->HandleSubtitleBuffer(sample, subtitle);
271     sinkProvider->OnSubtitleUpdated(subtitle);
272     return GST_FLOW_OK;
273 }
274 
OnSubtitleUpdated(const Format & subtitle)275 void PlayerSinkProvider::OnSubtitleUpdated(const Format &subtitle)
276 {
277     std::unique_lock<std::mutex> lock(mutex_);
278     MEDIA_LOGD("OnSubtitleUpdated enter");
279     auto temp_notifier = notifier_;
280     lock.unlock();
281     CHECK_AND_RETURN(temp_notifier != nullptr);
282     PlayBinMessage msg = {PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_SUBTITLE_UPDATED, 0, subtitle};
283     temp_notifier(msg);
284     MEDIA_LOGD("OnSubtitleUpdated exit");
285 }
286 
EosCb(GstMemSink * memSink,gpointer userData)287 void PlayerSinkProvider::EosCb(GstMemSink *memSink, gpointer userData)
288 {
289     (void)memSink;
290     (void)userData;
291     MEDIA_LOGI("EOS in");
292 }
293 
NewPrerollCb(GstMemSink * memSink,GstBuffer * sample,gpointer userData)294 GstFlowReturn PlayerSinkProvider::NewPrerollCb(GstMemSink *memSink, GstBuffer *sample, gpointer userData)
295 {
296     (void)userData;
297     MEDIA_LOGI("NewPrerollCb in");
298     MediaTrace trace("PlayerSinkProvider::NewPrerollCb");
299     CHECK_AND_RETURN_RET(gst_mem_sink_app_preroll_render(memSink, sample) == GST_FLOW_OK, GST_FLOW_ERROR);
300     return GST_FLOW_OK;
301 }
302 
NewSampleCb(GstMemSink * memSink,GstBuffer * sample,gpointer userData)303 GstFlowReturn PlayerSinkProvider::NewSampleCb(GstMemSink *memSink, GstBuffer *sample, gpointer userData)
304 {
305     MEDIA_LOGI("NewSampleCb in");
306     MediaTrace trace("PlayerSinkProvider::NewSampleCb");
307     CHECK_AND_RETURN_RET(gst_mem_sink_app_render(memSink, sample) == GST_FLOW_OK, GST_FLOW_ERROR);
308 
309     FirstRenderFrame(userData);
310     return GST_FLOW_OK;
311 }
312 
SinkPadProbeCb(GstPad * pad,GstPadProbeInfo * info,gpointer userData)313 GstPadProbeReturn PlayerSinkProvider::SinkPadProbeCb(GstPad *pad, GstPadProbeInfo *info, gpointer userData)
314 {
315     (void)pad;
316     (void)userData;
317     GstQuery *query = GST_PAD_PROBE_INFO_QUERY(info);
318     if (GST_QUERY_TYPE(query) == GST_QUERY_ALLOCATION) {
319         GstCaps *caps = nullptr;
320         gboolean needPool;
321         gst_query_parse_allocation(query, &caps, &needPool);
322 
323         auto s = gst_caps_get_structure(caps, 0);
324         auto mediaType = gst_structure_get_name(s);
325         gboolean isVideo = g_str_has_prefix(mediaType, "video/");
326         if (isVideo) {
327             gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, nullptr);
328         }
329     }
330     return GST_PAD_PROBE_OK;
331 }
332 
SetMsgNotifier(PlayBinMsgNotifier notifier)333 void PlayerSinkProvider::SetMsgNotifier(PlayBinMsgNotifier notifier)
334 {
335     std::unique_lock<std::mutex> lock(mutex_);
336     notifier_ = notifier;
337 }
338 
SetFirstRenderFrameFlag(bool firstRenderFrame)339 void PlayerSinkProvider::SetFirstRenderFrameFlag(bool firstRenderFrame)
340 {
341     firstRenderFrame_ = firstRenderFrame;
342 }
343 
GetFirstRenderFrameFlag() const344 bool PlayerSinkProvider::GetFirstRenderFrameFlag() const
345 {
346     return firstRenderFrame_;
347 }
348 
GetProducerSurface() const349 const sptr<Surface> PlayerSinkProvider::GetProducerSurface() const
350 {
351     return producerSurface_;
352 }
353 
SetVideoScaleType(const uint32_t videoScaleType)354 void PlayerSinkProvider::SetVideoScaleType(const uint32_t videoScaleType)
355 {
356     if (videoSink_ != nullptr) {
357         g_object_set(videoSink_, "video-scale-type", videoScaleType, nullptr);
358     } else {
359         videoScaleType_ = videoScaleType;
360     }
361 }
362 
SetAppInfo(int32_t uid,int32_t pid,uint32_t tokenId)363 void PlayerSinkProvider::SetAppInfo(int32_t uid, int32_t pid, uint32_t tokenId)
364 {
365     uid_ = uid;
366     pid_ = pid;
367     tokenId_ = tokenId;
368 }
369 }
370 }
371