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 "securec.h"
18 #include "gst_shmem_memory.h"
19 #include "media_log.h"
20 #include "scope_guard.h"
21
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "SinkBytebufferImpl"};
24 constexpr uint32_t ADTS_HEAD_SIZE = 7;
25 }
26
27 namespace OHOS {
28 namespace Media {
SinkBytebufferImpl()29 SinkBytebufferImpl::SinkBytebufferImpl()
30 {
31 }
32
~SinkBytebufferImpl()33 SinkBytebufferImpl::~SinkBytebufferImpl()
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 SinkBytebufferImpl::Init()
44 {
45 sink_ = GST_ELEMENT_CAST(gst_object_ref_sink(gst_element_factory_make("sharedmemsink", "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 SinkBytebufferImpl::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_), "mem-size", static_cast<guint>(config->bufferSize_), nullptr);
56 g_object_set(G_OBJECT(sink_), "caps", config->caps_, nullptr);
57 (void)CapsToFormat(config->caps_, bufferFormat_);
58
59 GstMemSinkCallbacks sinkCallbacks = { EosCb, nullptr, NewSampleCb };
60 gst_mem_sink_set_callback(GST_MEM_SINK(sink_), &sinkCallbacks, this, nullptr);
61
62 needAdtsTransform_ = config->needFilter_ && config->filterMode_ == BUFFER_FILTER_MODE_ADD_ADTS;
63 adtsHead_ = config->adtsHead_;
64
65 return MSERR_OK;
66 }
67
Flush()68 int32_t SinkBytebufferImpl::Flush()
69 {
70 std::unique_lock<std::mutex> lock(mutex_);
71 bufferList_.clear();
72 isFirstFrame_ = true;
73 isEos_ = false;
74 return MSERR_OK;
75 }
76
GetOutputBuffer(uint32_t index)77 std::shared_ptr<AVSharedMemory> SinkBytebufferImpl::GetOutputBuffer(uint32_t index)
78 {
79 std::unique_lock<std::mutex> lock(mutex_);
80 CHECK_AND_RETURN_RET(index <= bufferList_.size(), nullptr);
81 CHECK_AND_RETURN_RET(bufferList_[index] != nullptr, nullptr);
82 CHECK_AND_RETURN_RET(bufferList_[index]->owner_ == BufferWrapper::SERVER, nullptr);
83
84 GstMemory *memory = gst_buffer_peek_memory(bufferList_[index]->gstBuffer_, 0);
85 CHECK_AND_RETURN_RET(memory != nullptr, nullptr);
86 CHECK_AND_RETURN_RET(gst_is_shmem_memory(memory), nullptr);
87
88 GstShMemMemory *shmem = reinterpret_cast<GstShMemMemory *>(memory);
89 bufferList_[index]->owner_ = BufferWrapper::APP;
90 return shmem->mem;
91 }
92
ReleaseOutputBuffer(uint32_t index,bool render)93 int32_t SinkBytebufferImpl::ReleaseOutputBuffer(uint32_t index, bool render)
94 {
95 (void)render;
96 std::unique_lock<std::mutex> lock(mutex_);
97 CHECK_AND_RETURN_RET(index < bufferList_.size(), MSERR_INVALID_OPERATION);
98 CHECK_AND_RETURN_RET(bufferList_[index] != nullptr, MSERR_INVALID_VAL);
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 if (impl == nullptr) {
126 MEDIA_LOGE("impl is nullptr");
127 gst_buffer_unref(sample);
128 return GST_FLOW_ERROR;
129 }
130 std::unique_lock<std::mutex> lock(impl->mutex_);
131 CHECK_AND_RETURN_RET(impl->HandleNewSampleCb(sample) == MSERR_OK, GST_FLOW_ERROR);
132 return GST_FLOW_OK;
133 }
134
EosCb(GstMemSink * memSink,gpointer userData)135 void SinkBytebufferImpl::EosCb(GstMemSink *memSink, gpointer userData)
136 {
137 (void)memSink;
138 MEDIA_LOGI("EOS reached");
139 auto impl = static_cast<SinkBytebufferImpl *>(userData);
140 CHECK_AND_RETURN(impl != nullptr);
141 std::unique_lock<std::mutex> lock(impl->mutex_);
142 impl->isEos_ = true;
143
144 auto obs = impl->obs_.lock();
145 CHECK_AND_RETURN(obs != nullptr);
146
147 AVCodecBufferInfo info;
148 constexpr uint32_t invalidIndex = 1000;
149 obs->OnOutputBufferAvailable(invalidIndex, info, AVCODEC_BUFFER_FLAG_EOS);
150 }
151
HandleNewSampleCb(GstBuffer * buffer)152 int32_t SinkBytebufferImpl::HandleNewSampleCb(GstBuffer *buffer)
153 {
154 CHECK_AND_RETURN_RET(buffer != nullptr, MSERR_UNKNOWN);
155 ON_SCOPE_EXIT(0) { gst_buffer_unref(buffer); };
156
157 GstMemory *memory = gst_buffer_peek_memory(buffer, 0);
158 CHECK_AND_RETURN_RET(memory != nullptr, MSERR_UNKNOWN);
159 CHECK_AND_RETURN_RET(gst_is_shmem_memory(memory), MSERR_UNKNOWN);
160 GstShMemMemory *shmem = reinterpret_cast<GstShMemMemory *>(memory);
161 CHECK_AND_RETURN_RET(shmem->mem != nullptr, MSERR_UNKNOWN);
162
163 uint32_t index = 0;
164 CHECK_AND_RETURN_RET(FindBufferIndex(index, shmem->mem) == MSERR_OK, MSERR_UNKNOWN);
165
166 auto obs = obs_.lock();
167 CHECK_AND_RETURN_RET_LOG(obs != nullptr, MSERR_UNKNOWN, "obs is nullptr");
168
169 if (isFirstFrame_) {
170 isFirstFrame_ = false;
171 obs->OnOutputFormatChanged(bufferFormat_);
172 }
173
174 isEos_ = false;
175
176 GstMapInfo map = GST_MAP_INFO_INIT;
177 CHECK_AND_RETURN_RET(gst_buffer_map(buffer, &map, GST_MAP_READ) == TRUE, MSERR_UNKNOWN);
178
179 AVCodecBufferInfo info;
180 info.offset = 0;
181 if (map.size >= INT32_MAX) {
182 MEDIA_LOGE("Invalid size");
183 gst_buffer_unmap(buffer, &map);
184 return MSERR_UNKNOWN;
185 }
186 if (needAdtsTransform_) {
187 if (AddAdtsHead(shmem->mem, map.size) != MSERR_OK) {
188 gst_buffer_unmap(buffer, &map);
189 return MSERR_UNKNOWN;
190 }
191 info.size = static_cast<int32_t>(map.size) + static_cast<int32_t>(ADTS_HEAD_SIZE);
192 } else {
193 info.size = static_cast<int32_t>(map.size);
194 }
195 constexpr uint64_t nsToUs = 1000;
196 info.presentationTimeUs = static_cast<int64_t>(GST_BUFFER_PTS(buffer) / nsToUs);
197 AVCodecBufferFlag flag = AVCODEC_BUFFER_FLAG_NONE;
198 GetFlagFromBuffer(buffer, flag);
199 obs->OnOutputBufferAvailable(index, info, flag);
200
201 MEDIA_LOGD("OutputBufferAvailable, index:%{public}d, pts:%{public}" PRId64 "", index, info.presentationTimeUs);
202 gst_buffer_unmap(buffer, &map);
203 bufferList_[index]->owner_ = BufferWrapper::SERVER;
204 bufferList_[index]->gstBuffer_ = gst_buffer_ref(buffer);
205
206 return MSERR_OK;
207 }
208
FindBufferIndex(uint32_t & index,std::shared_ptr<AVSharedMemory> mem)209 int32_t SinkBytebufferImpl::FindBufferIndex(uint32_t &index, std::shared_ptr<AVSharedMemory> mem)
210 {
211 CHECK_AND_RETURN_RET(mem != nullptr, MSERR_UNKNOWN);
212
213 index = 0;
214 for (auto it = bufferList_.begin(); it != bufferList_.end(); it++) {
215 if ((*it) != nullptr && (*it)->mem_ == mem.get()) {
216 break;
217 }
218 index++;
219 }
220
221 if (index == bufferList_.size()) {
222 auto bufWrap = std::make_shared<BufferWrapper>(BufferWrapper::SERVER);
223 CHECK_AND_RETURN_RET(bufWrap != nullptr, MSERR_NO_MEMORY);
224 bufWrap->mem_ = mem.get();
225 bufferList_.push_back(bufWrap);
226 }
227
228 return MSERR_OK;
229 }
230
AddAdtsHead(std::shared_ptr<AVSharedMemory> mem,uint32_t rawFrameSize)231 int32_t SinkBytebufferImpl::AddAdtsHead(std::shared_ptr<AVSharedMemory> mem, uint32_t rawFrameSize)
232 {
233 CHECK_AND_RETURN_RET(mem != nullptr && mem->GetBase() != nullptr && rawFrameSize > 0, MSERR_UNKNOWN);
234
235 uint32_t adtsFrameSize = rawFrameSize + ADTS_HEAD_SIZE;
236 CHECK_AND_RETURN_RET(static_cast<uint32_t>(mem->GetSize()) >= adtsFrameSize, MSERR_UNKNOWN);
237
238 uint8_t *base = mem->GetBase();
239 CHECK_AND_RETURN_RET(memmove_s(base + ADTS_HEAD_SIZE, mem->GetSize() - ADTS_HEAD_SIZE, base, rawFrameSize) == EOK,
240 MSERR_UNKNOWN);
241 CHECK_AND_RETURN_RET(memset_s(base, mem->GetSize(), 0, ADTS_HEAD_SIZE) == EOK, MSERR_UNKNOWN);
242
243 base[0] = 0xFF; // syncword 8 bits
244 base[1] = 0xF1; // syncword 4 bits + MPEG version + layer + protection absent
245 uint32_t proflie = adtsHead_.objectType - 1;
246 // profile + sampling frequency index + private bit + channel configuration 1 bits
247 base[2] = static_cast<uint8_t>((proflie << 6) + (adtsHead_.samplingIndex << 2) + (adtsHead_.channelConfig >> 2));
248 // channel configuration 2 bits + original + home + copyright id bit + copyright id start + frame length 2 bits
249 base[3] = static_cast<uint8_t>(((adtsHead_.channelConfig & 0x03) << 6) + (adtsFrameSize >> 11)) ;
250 base[4] = static_cast<uint8_t>((adtsFrameSize & 0x7FF) >> 3); // frame length 8 bits
251 base[5] = static_cast<uint8_t>(((adtsFrameSize & 0x07) << 5) + 0x1F); // frame length 5 bits + buffer fullness
252 base[6] = 0xFC;
253
254 return MSERR_OK;
255 }
256 } // namespace Media
257 } // namespace OHOS
258