• 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 "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