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