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 "sink_surface_impl.h"
17 #include "display_type.h"
18 #include "media_log.h"
19 #include "scope_guard.h"
20 #include "gst_surface_memory.h"
21 #include "media_dfx.h"
22
23 namespace {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "SinkSurfaceImpl"};
25 }
26
27 namespace OHOS {
28 namespace Media {
SinkSurfaceImpl()29 SinkSurfaceImpl::SinkSurfaceImpl()
30 {
31 }
32
~SinkSurfaceImpl()33 SinkSurfaceImpl::~SinkSurfaceImpl()
34 {
35 std::unique_lock<std::mutex> lock(mutex_);
36 bufferList_.clear();
37 if (sink_ != nullptr) {
38 gst_object_unref(sink_);
39 sink_ = nullptr;
40 }
41 }
42
Init()43 int32_t SinkSurfaceImpl::Init()
44 {
45 sink_ = GST_ELEMENT_CAST(gst_object_ref_sink(gst_element_factory_make("surfacememsink", "sink")));
46 CHECK_AND_RETURN_RET(sink_ != nullptr, MSERR_UNKNOWN);
47 gst_base_sink_set_async_enabled(GST_BASE_SINK(sink_), FALSE);
48 return MSERR_OK;
49 }
50
Configure(std::shared_ptr<ProcessorConfig> config)51 int32_t SinkSurfaceImpl::Configure(std::shared_ptr<ProcessorConfig> config)
52 {
53 CHECK_AND_RETURN_RET(sink_ != nullptr && config->caps_ != nullptr, MSERR_UNKNOWN);
54
55 g_object_set(G_OBJECT(sink_), "caps", config->caps_, nullptr);
56 (void)CapsToFormat(config->caps_, bufferFormat_);
57 g_object_set(G_OBJECT(sink_), "video-rotation", config->videoRotation_, nullptr);
58 GstMemSinkCallbacks sinkCallbacks = { EosCb, nullptr, NewSampleCb };
59 gst_mem_sink_set_callback(GST_MEM_SINK(sink_), &sinkCallbacks, this, nullptr);
60
61 return MSERR_OK;
62 }
63
Flush()64 int32_t SinkSurfaceImpl::Flush()
65 {
66 std::unique_lock<std::mutex> lock(mutex_);
67 bufferList_.clear();
68 isFirstFrame_ = true;
69 return MSERR_OK;
70 }
71
SetOutputSurface(sptr<Surface> surface)72 int32_t SinkSurfaceImpl::SetOutputSurface(sptr<Surface> surface)
73 {
74 std::unique_lock<std::mutex> lock(mutex_);
75 CHECK_AND_RETURN_RET(sink_ != nullptr, MSERR_UNKNOWN);
76 CHECK_AND_RETURN_RET(surface != nullptr, MSERR_INVALID_VAL);
77 g_object_set(G_OBJECT(sink_), "surface", static_cast<gpointer>(surface), nullptr);
78 return MSERR_OK;
79 }
80
SetOutputBuffersCount(uint32_t maxBuffers)81 int32_t SinkSurfaceImpl::SetOutputBuffersCount(uint32_t maxBuffers)
82 {
83 g_object_set(G_OBJECT(sink_), "max-pool-capacity", maxBuffers, nullptr);
84 return MSERR_OK;
85 }
86
SetCacheBuffersCount(uint32_t cacheBuffers)87 int32_t SinkSurfaceImpl::SetCacheBuffersCount(uint32_t cacheBuffers)
88 {
89 g_object_set(G_OBJECT(sink_), "cache-buffers-num", cacheBuffers, nullptr);
90 return MSERR_OK;
91 }
92
SetParameter(const Format & format)93 int32_t SinkSurfaceImpl::SetParameter(const Format &format)
94 {
95 (void)format;
96 return MSERR_OK;
97 }
98
ReleaseOutputBuffer(uint32_t index,bool render)99 int32_t SinkSurfaceImpl::ReleaseOutputBuffer(uint32_t index, bool render)
100 {
101 std::unique_lock<std::mutex> lock(mutex_);
102 CHECK_AND_RETURN_RET(index < bufferList_.size(), MSERR_INVALID_OPERATION);
103 CHECK_AND_RETURN_RET(bufferList_[index]->owner_ == BufferWrapper::SERVER, MSERR_INVALID_OPERATION);
104 CHECK_AND_RETURN_RET(bufferList_[index]->gstBuffer_ != nullptr, MSERR_UNKNOWN);
105
106 if (render) {
107 (void)gst_mem_sink_app_render(GST_MEM_SINK(sink_), bufferList_[index]->gstBuffer_);
108 }
109
110 bufferList_[index]->owner_ = BufferWrapper::DOWNSTREAM;
111 gst_buffer_unref(bufferList_[index]->gstBuffer_);
112 bufferList_[index]->gstBuffer_ = nullptr;
113 return MSERR_OK;
114 }
115
SetCallback(const std::weak_ptr<IAVCodecEngineObs> & obs)116 int32_t SinkSurfaceImpl::SetCallback(const std::weak_ptr<IAVCodecEngineObs> &obs)
117 {
118 std::unique_lock<std::mutex> lock(mutex_);
119 obs_ = obs;
120 return MSERR_OK;
121 }
122
NewSampleCb(GstMemSink * memSink,GstBuffer * sample,gpointer userData)123 GstFlowReturn SinkSurfaceImpl::NewSampleCb(GstMemSink *memSink, GstBuffer *sample, gpointer userData)
124 {
125 (void)memSink;
126 auto impl = static_cast<SinkSurfaceImpl *>(userData);
127 CHECK_AND_RETURN_RET(impl != nullptr, GST_FLOW_ERROR);
128 std::unique_lock<std::mutex> lock(impl->mutex_);
129 CHECK_AND_RETURN_RET(impl->HandleNewSampleCb(sample) == MSERR_OK, GST_FLOW_ERROR);
130 return GST_FLOW_OK;
131 }
132
EosCb(GstMemSink * memSink,gpointer userData)133 void SinkSurfaceImpl::EosCb(GstMemSink *memSink, gpointer userData)
134 {
135 (void)memSink;
136 MEDIA_LOGI("EOS reached");
137 auto impl = static_cast<SinkSurfaceImpl *>(userData);
138 CHECK_AND_RETURN(impl != nullptr);
139 std::unique_lock<std::mutex> lock(impl->mutex_);
140
141 auto obs = impl->obs_.lock();
142 CHECK_AND_RETURN(obs != nullptr);
143
144 AVCodecBufferInfo info;
145 constexpr uint32_t invalidIndex = 1000;
146 obs->OnOutputBufferAvailable(invalidIndex, info, AVCODEC_BUFFER_FLAG_EOS);
147 }
148
HandleNewSampleCb(GstBuffer * buffer)149 int32_t SinkSurfaceImpl::HandleNewSampleCb(GstBuffer *buffer)
150 {
151 CHECK_AND_RETURN_RET(buffer != nullptr, MSERR_UNKNOWN);
152
153 GstMemory *memory = gst_buffer_peek_memory(buffer, 0);
154 CHECK_AND_RETURN_RET(memory != nullptr, MSERR_UNKNOWN);
155 CHECK_AND_RETURN_RET(gst_is_surface_memory(memory), MSERR_UNKNOWN);
156 GstSurfaceMemory *surfaceMem = reinterpret_cast<GstSurfaceMemory *>(memory);
157 CHECK_AND_RETURN_RET(surfaceMem->buf != nullptr, MSERR_UNKNOWN);
158
159 uint32_t index = 0;
160 CHECK_AND_RETURN_RET(FindBufferIndex(index, surfaceMem->buf) == MSERR_OK, MSERR_UNKNOWN);
161 CHECK_AND_RETURN_RET(index < bufferList_.size(), MSERR_UNKNOWN);
162 bufferList_[index]->gstBuffer_ = gst_buffer_ref(buffer);
163
164 auto obs = obs_.lock();
165 CHECK_AND_RETURN_RET_LOG(obs != nullptr, MSERR_UNKNOWN, "obs is nullptr");
166
167 if (isFirstFrame_) {
168 isFirstFrame_ = false;
169 obs->OnOutputFormatChanged(bufferFormat_);
170 }
171
172 AVCodecBufferInfo info;
173 info.offset = 0;
174 info.size = 0;
175 constexpr uint64_t nsToUs = 1000;
176 info.presentationTimeUs = static_cast<int64_t>(GST_BUFFER_PTS(buffer) / nsToUs);
177 AVCodecBufferFlag flag = AVCODEC_BUFFER_FLAG_NONE;
178 GetFlagFromBuffer(buffer, flag);
179 MediaTrace::TraceBegin("Codec::OnOutputBufferAvailable", FAKE_POINTER(this));
180 obs->OnOutputBufferAvailable(index, info, flag);
181 MediaTrace::TraceEnd("Codec::OnOutputBufferAvailable", FAKE_POINTER(this));
182
183 MEDIA_LOGD("OutputBufferAvailable, index:%{public}d", index);
184 bufferList_[index]->owner_ = BufferWrapper::SERVER;
185
186 return MSERR_OK;
187 }
188
FindBufferIndex(uint32_t & index,sptr<SurfaceBuffer> buffer)189 int32_t SinkSurfaceImpl::FindBufferIndex(uint32_t &index, sptr<SurfaceBuffer> buffer)
190 {
191 CHECK_AND_RETURN_RET(buffer != nullptr, MSERR_UNKNOWN);
192
193 index = 0;
194 for (auto it = bufferList_.begin(); it != bufferList_.end(); it++) {
195 if ((*it) != nullptr && (*it)->surfaceBuffer_ != nullptr &&
196 (*it)->surfaceBuffer_->GetVirAddr() == buffer->GetVirAddr()) {
197 break;
198 }
199 index++;
200 }
201
202 if (index == bufferList_.size()) {
203 auto bufWrap = std::make_shared<BufferWrapper>(BufferWrapper::SERVER);
204 CHECK_AND_RETURN_RET(bufWrap != nullptr, MSERR_NO_MEMORY);
205 bufWrap->surfaceBuffer_ = buffer;
206 bufferList_.push_back(bufWrap);
207 }
208
209 CHECK_AND_RETURN_RET(index < bufferList_.size(), MSERR_UNKNOWN);
210 return MSERR_OK;
211 }
212 } // namespace Media
213 } // namespace OHOS
214