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 "src_bytebuffer_impl.h"
17 #include <mutex>
18 #include "gst_shmem_memory.h"
19 #include "buffer_type_meta.h"
20 #include "media_log.h"
21 #include "scope_guard.h"
22 #include "media_dfx.h"
23
24 namespace {
25 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "SrcBytebufferImpl"};
26 constexpr uint32_t DEFAULT_BUFFER_NUM = 10;
27 }
28
29 namespace OHOS {
30 namespace Media {
SrcBytebufferImpl()31 SrcBytebufferImpl::SrcBytebufferImpl()
32 {
33 }
34
~SrcBytebufferImpl()35 SrcBytebufferImpl::~SrcBytebufferImpl()
36 {
37 bufferList_.clear();
38 if (src_ != nullptr) {
39 gst_object_unref(src_);
40 src_ = nullptr;
41 }
42 if (caps_ != nullptr) {
43 gst_caps_unref(caps_);
44 caps_ = nullptr;
45 }
46 }
47
Init()48 int32_t SrcBytebufferImpl::Init()
49 {
50 src_ = GST_ELEMENT_CAST(gst_object_ref_sink(gst_element_factory_make("shmemsrc", "src")));
51 CHECK_AND_RETURN_RET_LOG(src_ != nullptr, MSERR_UNKNOWN, "Failed to gst_element_factory_make");
52 return MSERR_OK;
53 }
54
Configure(const std::shared_ptr<ProcessorConfig> & config)55 int32_t SrcBytebufferImpl::Configure(const std::shared_ptr<ProcessorConfig> &config)
56 {
57 CHECK_AND_RETURN_RET(config != nullptr, MSERR_UNKNOWN);
58 CHECK_AND_RETURN_RET(src_ != nullptr, MSERR_UNKNOWN);
59
60 g_object_set(G_OBJECT(src_), "buffer-num", DEFAULT_BUFFER_NUM, nullptr);
61 g_object_set(G_OBJECT(src_), "buffer-size", config->bufferSize_, nullptr);
62 g_object_set(G_OBJECT(src_), "caps", config->caps_, nullptr);
63 gst_mem_src_set_callback(GST_MEM_SRC(src_), BufferAvailable, this, nullptr);
64
65 needCodecData_ = config->needCodecData_;
66 if (needCodecData_) {
67 caps_ = config->caps_;
68 gst_caps_ref(caps_);
69 }
70 return MSERR_OK;
71 }
72
Start()73 int32_t SrcBytebufferImpl::Start()
74 {
75 std::unique_lock<std::mutex> lock(mutex_);
76 start_ = true;
77 return MSERR_OK;
78 }
79
Stop()80 int32_t SrcBytebufferImpl::Stop()
81 {
82 std::unique_lock<std::mutex> lock(mutex_);
83 start_ = false;
84 return MSERR_OK;
85 }
86
Flush()87 int32_t SrcBytebufferImpl::Flush()
88 {
89 std::unique_lock<std::mutex> lock(mutex_);
90 bufferList_.clear();
91 return MSERR_OK;
92 }
93
Needflush()94 bool SrcBytebufferImpl::Needflush()
95 {
96 std::unique_lock<std::mutex> lock(mutex_);
97 return !bufferList_.empty();
98 }
99
GetInputBuffer(uint32_t index)100 std::shared_ptr<AVSharedMemory> SrcBytebufferImpl::GetInputBuffer(uint32_t index)
101 {
102 std::unique_lock<std::mutex> lock(mutex_);
103 CHECK_AND_RETURN_RET(index <= bufferList_.size(), nullptr);
104 CHECK_AND_RETURN_RET(bufferList_[index] != nullptr, nullptr);
105 CHECK_AND_RETURN_RET(bufferList_[index]->owner_ == BufferWrapper::SERVER, nullptr);
106
107 GstMemory *memory = gst_buffer_peek_memory(bufferList_[index]->gstBuffer_, 0);
108 CHECK_AND_RETURN_RET(memory != nullptr, nullptr);
109 CHECK_AND_RETURN_RET(gst_is_shmem_memory(memory), nullptr);
110
111 GstShMemMemory *shmem = reinterpret_cast<GstShMemMemory *>(memory);
112 bufferList_[index]->owner_ = BufferWrapper::APP;
113
114 return shmem->mem;
115 }
116
QueueInputBuffer(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag)117 int32_t SrcBytebufferImpl::QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag)
118 {
119 std::unique_lock<std::mutex> lock(mutex_);
120 CHECK_AND_RETURN_RET(index <= bufferList_.size(), MSERR_INVALID_VAL);
121 CHECK_AND_RETURN_RET(bufferList_[index] != nullptr, MSERR_INVALID_VAL);
122
123 auto &bufWrapper = bufferList_[index];
124 CHECK_AND_RETURN_RET(bufWrapper->owner_ == BufferWrapper::APP, MSERR_INVALID_OPERATION);
125 CHECK_AND_RETURN_RET(bufWrapper->gstBuffer_ != nullptr, MSERR_INVALID_OPERATION);
126 CHECK_AND_RETURN_RET(info.offset >= 0 && info.size >= 0, MSERR_INVALID_VAL);
127 gst_buffer_resize(bufWrapper->gstBuffer_, info.offset, info.size);
128 GstBufferTypeMeta *meta = gst_buffer_get_buffer_type_meta(bufWrapper->gstBuffer_);
129 CHECK_AND_RETURN_RET(meta != nullptr, MSERR_INVALID_OPERATION);
130 meta->offset = static_cast<uint32_t>(info.offset);
131 meta->length = static_cast<uint32_t>(info.size);
132 MEDIA_LOGD("meta->offset change to: %{public}u, meta->length change to: %{public}u",
133 meta->offset, meta->length);
134
135 if (needCodecData_) {
136 if (HandleCodecBuffer(index, info, flag) == MSERR_OK) {
137 needCodecData_ = false;
138 bufWrapper->owner_ = BufferWrapper::DOWNSTREAM;
139 gst_buffer_unref(bufWrapper->gstBuffer_);
140 bufWrapper->gstBuffer_ = nullptr;
141 return MSERR_OK;
142 }
143 return MSERR_UNKNOWN;
144 }
145
146 uint8_t *address = bufWrapper->mem_->GetBase();
147 CHECK_AND_RETURN_RET(address != nullptr, MSERR_UNKNOWN);
148 CHECK_AND_RETURN_RET((info.offset + info.size) <= bufWrapper->mem_->GetSize(), MSERR_INVALID_VAL);
149
150 constexpr int32_t usToNs = 1000;
151 if (info.presentationTimeUs < 0) {
152 MEDIA_LOGE("Invalid pts: < 0, use 0 as default");
153 GST_BUFFER_PTS(bufWrapper->gstBuffer_) = 0;
154 } else if (info.presentationTimeUs >= (INT64_MAX / usToNs)) {
155 MEDIA_LOGE("Invalid pts: too big, use 0 as default");
156 GST_BUFFER_PTS(bufWrapper->gstBuffer_) = 0;
157 } else {
158 GST_BUFFER_PTS(bufWrapper->gstBuffer_) = static_cast<uint64_t>(info.presentationTimeUs * usToNs);
159 }
160
161 CHECK_AND_RETURN_RET(src_ != nullptr, MSERR_UNKNOWN);
162 (void)gst_mem_src_push_buffer(GST_MEM_SRC(src_), bufWrapper->gstBuffer_);
163 bufWrapper->owner_ = BufferWrapper::DOWNSTREAM;
164 bufWrapper->gstBuffer_ = nullptr; // src elem take ownership of this buffer.
165
166 MEDIA_LOGD("QueueInputBuffer, index = %{public}u", index);
167 return MSERR_OK;
168 }
169
SetCallback(const std::weak_ptr<IAVCodecEngineObs> & obs)170 int32_t SrcBytebufferImpl::SetCallback(const std::weak_ptr<IAVCodecEngineObs> &obs)
171 {
172 std::unique_lock<std::mutex> lock(mutex_);
173 obs_ = obs;
174 return MSERR_OK;
175 }
176
HandleCodecBuffer(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag)177 int32_t SrcBytebufferImpl::HandleCodecBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag)
178 {
179 CHECK_AND_RETURN_RET(caps_ != nullptr, MSERR_UNKNOWN);
180 CHECK_AND_RETURN_RET(src_ != nullptr, MSERR_UNKNOWN);
181 bool hasCodecFlag = static_cast<uint32_t>(flag) & static_cast<uint32_t>(AVCODEC_BUFFER_FLAG_CODEC_DATA);
182 CHECK_AND_RETURN_RET(bufferList_[index] != nullptr, MSERR_INVALID_VAL);
183 CHECK_AND_RETURN_RET_LOG(hasCodecFlag == true, MSERR_INVALID_VAL, "First buffer must be codec buffer");
184
185 uint8_t *address = bufferList_[index]->mem_->GetBase();
186 CHECK_AND_RETURN_RET(address != nullptr, MSERR_UNKNOWN);
187 CHECK_AND_RETURN_RET((info.offset + info.size) <= bufferList_[index]->mem_->GetSize(), MSERR_INVALID_VAL);
188
189 GstBuffer *codecBuffer = gst_buffer_new_allocate(nullptr, info.size, nullptr);
190 CHECK_AND_RETURN_RET_LOG(codecBuffer != nullptr, MSERR_NO_MEMORY, "no memory");
191
192 ON_SCOPE_EXIT(0) { gst_buffer_unref(codecBuffer); };
193
194 gsize size = gst_buffer_fill(codecBuffer, 0, (char*)address + info.offset, info.size);
195 CHECK_AND_RETURN_RET(size == static_cast<gsize>(info.size), MSERR_UNKNOWN);
196
197 gst_caps_set_simple(caps_, "codec_data", GST_TYPE_BUFFER, codecBuffer, nullptr);
198 g_object_set(G_OBJECT(src_), "caps", caps_, nullptr);
199
200 CHECK_AND_RETURN_RET(gst_base_src_set_caps(GST_BASE_SRC(src_), caps_) == TRUE, MSERR_UNKNOWN);
201 return MSERR_OK;
202 }
203
BufferAvailable(GstMemSrc * memsrc,gpointer userData)204 GstFlowReturn SrcBytebufferImpl::BufferAvailable(GstMemSrc *memsrc, gpointer userData)
205 {
206 CHECK_AND_RETURN_RET(memsrc != nullptr, GST_FLOW_ERROR);
207 CHECK_AND_RETURN_RET(userData != nullptr, GST_FLOW_ERROR);
208
209 GstBuffer *buffer = gst_mem_src_pull_buffer(memsrc);
210 CHECK_AND_RETURN_RET(buffer != nullptr, GST_FLOW_ERROR);
211
212 SrcBytebufferImpl *thiz = reinterpret_cast<SrcBytebufferImpl *>(userData);
213 int32_t ret = thiz->HandleBufferAvailable(buffer);
214 CHECK_AND_RETURN_RET(ret == MSERR_OK, GST_FLOW_ERROR);
215
216 return GST_FLOW_OK;
217 }
218
HandleBufferAvailable(GstBuffer * buffer)219 int32_t SrcBytebufferImpl::HandleBufferAvailable(GstBuffer *buffer)
220 {
221 std::unique_lock<std::mutex> lock(mutex_);
222 ON_SCOPE_EXIT(0) { gst_buffer_unref(buffer); };
223 if (!start_) {
224 MEDIA_LOGD("Codec source is stop, unref available buffer");
225 return MSERR_OK;
226 }
227
228 GstMemory *memory = gst_buffer_peek_memory(buffer, 0);
229 CHECK_AND_RETURN_RET(memory != nullptr, MSERR_UNKNOWN);
230 CHECK_AND_RETURN_RET(gst_is_shmem_memory(memory), MSERR_UNKNOWN);
231 GstShMemMemory *shmem = reinterpret_cast<GstShMemMemory *>(memory);
232 CHECK_AND_RETURN_RET(shmem->mem != nullptr, MSERR_UNKNOWN);
233
234 uint32_t index = 0;
235 int32_t ret = FindBufferIndex(index, shmem->mem);
236 CHECK_AND_RETURN_RET(ret == MSERR_OK, MSERR_UNKNOWN);
237
238 auto obs = obs_.lock();
239 CHECK_AND_RETURN_RET_LOG(obs != nullptr, MSERR_UNKNOWN, "obs is nullptr");
240 MediaTrace::TraceBegin("Codec::OnInputBufferAvailable", FAKE_POINTER(this));
241 obs->OnInputBufferAvailable(index);
242 MediaTrace::TraceEnd("Codec::OnInputBufferAvailable", FAKE_POINTER(this));
243
244 MEDIA_LOGD("OnInputBufferAvailable, index:%{public}u", index);
245 bufferList_[index]->owner_ = BufferWrapper::SERVER;
246 bufferList_[index]->gstBuffer_ = gst_buffer_ref(buffer);
247
248 return MSERR_OK;
249 }
250
FindBufferIndex(uint32_t & index,const std::shared_ptr<AVSharedMemory> & mem)251 int32_t SrcBytebufferImpl::FindBufferIndex(uint32_t &index, const std::shared_ptr<AVSharedMemory> &mem)
252 {
253 CHECK_AND_RETURN_RET(mem != nullptr, MSERR_UNKNOWN);
254
255 index = 0;
256 for (auto it = bufferList_.begin(); it != bufferList_.end(); it++) {
257 if ((*it) != nullptr && (*it)->mem_ == mem.get()) {
258 break;
259 }
260 index++;
261 }
262
263 if (index == bufferList_.size()) {
264 auto bufWrap = std::make_shared<BufferWrapper>(BufferWrapper::SERVER);
265 CHECK_AND_RETURN_RET(bufWrap != nullptr, MSERR_NO_MEMORY);
266 bufWrap->mem_ = mem.get();
267 bufferList_.push_back(bufWrap);
268 }
269
270 return MSERR_OK;
271 }
272 } // namespace Media
273 } // namespace OHOS
274