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 "avcodec_engine_ctrl.h"
17 #include <vector>
18 #include "media_errors.h"
19 #include "media_log.h"
20 #include "scope_guard.h"
21
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecEngineCtrl"};
24 }
25
26 namespace OHOS {
27 namespace Media {
AVCodecEngineCtrl()28 AVCodecEngineCtrl::AVCodecEngineCtrl()
29 {
30 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
31 }
32
~AVCodecEngineCtrl()33 AVCodecEngineCtrl::~AVCodecEngineCtrl()
34 {
35 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
36 (void)Release();
37 }
38
Init(AVCodecType type,bool useSoftware,const std::string & name)39 int32_t AVCodecEngineCtrl::Init(AVCodecType type, bool useSoftware, const std::string &name)
40 {
41 MEDIA_LOGD("Enter Init");
42 codecType_ = type;
43 gstPipeline_ = GST_PIPELINE_CAST(gst_pipeline_new("codec-pipeline"));
44 CHECK_AND_RETURN_RET(gstPipeline_ != nullptr, MSERR_NO_MEMORY);
45
46 bus_ = gst_pipeline_get_bus(gstPipeline_);
47 CHECK_AND_RETURN_RET(bus_ != nullptr, MSERR_UNKNOWN);
48 gst_bus_set_sync_handler(bus_, BusSyncHandler, this, nullptr);
49
50 codecBin_ = GST_ELEMENT_CAST(gst_object_ref(gst_element_factory_make("codecbin", "the_codec_bin")));
51 CHECK_AND_RETURN_RET(codecBin_ != nullptr, MSERR_NO_MEMORY);
52
53 gboolean ret = gst_bin_add(GST_BIN_CAST(gstPipeline_), codecBin_);
54 CHECK_AND_RETURN_RET(ret == TRUE, MSERR_NO_MEMORY);
55
56 g_object_set(codecBin_, "use-software", static_cast<gboolean>(useSoftware), nullptr);
57 g_object_set(codecBin_, "type", static_cast<int32_t>(type), nullptr);
58 g_object_set(codecBin_, "coder-name", name.c_str(), nullptr);
59
60 isEncoder_ = (type == AVCODEC_TYPE_VIDEO_ENCODER) || (type == AVCODEC_TYPE_AUDIO_ENCODER);
61 if (isEncoder_) {
62 g_object_set(codecBin_, "src-convert", static_cast<gboolean>(true), nullptr);
63 } else {
64 g_object_set(codecBin_, "sink-convert", static_cast<gboolean>(true), nullptr);
65 }
66
67 return MSERR_OK;
68 }
69
Prepare(std::shared_ptr<ProcessorConfig> inputConfig,std::shared_ptr<ProcessorConfig> outputConfig)70 int32_t AVCodecEngineCtrl::Prepare(std::shared_ptr<ProcessorConfig> inputConfig,
71 std::shared_ptr<ProcessorConfig> outputConfig)
72 {
73 if (src_ == nullptr) {
74 MEDIA_LOGD("Use buffer src");
75 src_ = AVCodecEngineFactory::CreateSrc(SrcType::SRC_TYPE_BYTEBUFFER);
76 CHECK_AND_RETURN_RET_LOG(src_ != nullptr, MSERR_NO_MEMORY, "No memory");
77 CHECK_AND_RETURN_RET(src_->Init() == MSERR_OK, MSERR_UNKNOWN);
78 CHECK_AND_RETURN_RET(src_->SetCallback(obs_) == MSERR_OK, MSERR_UNKNOWN);
79 }
80
81 if (sink_ == nullptr) {
82 MEDIA_LOGD("Use buffer sink");
83 sink_ = AVCodecEngineFactory::CreateSink(SinkType::SINK_TYPE_BYTEBUFFER);
84 CHECK_AND_RETURN_RET_LOG(sink_ != nullptr, MSERR_NO_MEMORY, "No memory");
85 CHECK_AND_RETURN_RET(sink_->Init() == MSERR_OK, MSERR_UNKNOWN);
86 CHECK_AND_RETURN_RET(sink_->SetCallback(obs_) == MSERR_OK, MSERR_UNKNOWN);
87 }
88
89 CHECK_AND_RETURN_RET(codecBin_ != nullptr, MSERR_UNKNOWN);
90 if (inputConfig->needParser_) {
91 g_object_set(codecBin_, "parser", static_cast<gboolean>(true), nullptr);
92 }
93 g_object_set(codecBin_, "src", static_cast<gpointer>(const_cast<GstElement *>(src_->GetElement())), nullptr);
94 CHECK_AND_RETURN_RET(src_->Configure(inputConfig) == MSERR_OK, MSERR_UNKNOWN);
95
96 g_object_set(codecBin_, "sink", static_cast<gpointer>(const_cast<GstElement *>(sink_->GetElement())), nullptr);
97 CHECK_AND_RETURN_RET(sink_->Configure(outputConfig) == MSERR_OK, MSERR_UNKNOWN);
98
99 CHECK_AND_RETURN_RET(gstPipeline_ != nullptr, MSERR_UNKNOWN);
100 GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(gstPipeline_), GST_STATE_PAUSED);
101 CHECK_AND_RETURN_RET(ret != GST_STATE_CHANGE_FAILURE, MSERR_UNKNOWN);
102 if (ret == GST_STATE_CHANGE_ASYNC) {
103 MEDIA_LOGD("Wait state change");
104 std::unique_lock<std::mutex> lock(gstPipeMutex_);
105 gstPipeCond_.wait(lock);
106 }
107
108 MEDIA_LOGD("Prepare success");
109 return MSERR_OK;
110 }
111
Start()112 int32_t AVCodecEngineCtrl::Start()
113 {
114 CHECK_AND_RETURN_RET(gstPipeline_ != nullptr, MSERR_UNKNOWN);
115
116 CHECK_AND_RETURN_RET(sink_ != nullptr, MSERR_UNKNOWN);
117 if (flushAtStart_ || sink_->IsEos()) {
118 CHECK_AND_RETURN_RET(Flush() == MSERR_OK, MSERR_INVALID_OPERATION);
119 flushAtStart_ = false;
120 }
121
122 CHECK_AND_RETURN_RET(src_->Start() == MSERR_OK, MSERR_INVALID_OPERATION);
123 GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(gstPipeline_), GST_STATE_PLAYING);
124 CHECK_AND_RETURN_RET(ret != GST_STATE_CHANGE_FAILURE, MSERR_UNKNOWN);
125 if (ret == GST_STATE_CHANGE_ASYNC) {
126 MEDIA_LOGD("Wait state change");
127 std::unique_lock<std::mutex> lock(gstPipeMutex_);
128 gstPipeCond_.wait(lock);
129 }
130
131 isStart_ = true;
132 MEDIA_LOGD("Start success");
133 return MSERR_OK;
134 }
135
Stop()136 int32_t AVCodecEngineCtrl::Stop()
137 {
138 if (!isStart_) {
139 return MSERR_OK;
140 }
141
142 CHECK_AND_RETURN_RET(src_->Stop() == MSERR_OK, MSERR_INVALID_OPERATION);
143 GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(gstPipeline_), GST_STATE_PAUSED);
144 CHECK_AND_RETURN_RET(ret != GST_STATE_CHANGE_FAILURE, MSERR_UNKNOWN);
145 if (ret == GST_STATE_CHANGE_ASYNC) {
146 std::unique_lock<std::mutex> lock(gstPipeMutex_);
147 gstPipeCond_.wait(lock);
148 }
149
150 CHECK_AND_RETURN_RET(Flush() == MSERR_OK, MSERR_UNKNOWN);
151
152 MEDIA_LOGD("Stop success");
153 isStart_ = false;
154 return MSERR_OK;
155 }
156
Flush()157 int32_t AVCodecEngineCtrl::Flush()
158 {
159 CHECK_AND_RETURN_RET(gstPipeline_ != nullptr, MSERR_UNKNOWN);
160
161 CHECK_AND_RETURN_RET(src_ != nullptr, MSERR_UNKNOWN);
162 if (!src_->Needflush()) {
163 MEDIA_LOGD("Flush success, src is empty.");
164 return MSERR_OK;
165 }
166 CHECK_AND_RETURN_RET(src_->Flush() == MSERR_OK, MSERR_UNKNOWN);
167
168 CHECK_AND_RETURN_RET(sink_ != nullptr, MSERR_UNKNOWN);
169 CHECK_AND_RETURN_RET(sink_->Flush() == MSERR_OK, MSERR_UNKNOWN);
170
171 CHECK_AND_RETURN_RET(codecBin_ != nullptr, MSERR_UNKNOWN);
172 GstEvent *event = gst_event_new_flush_start();
173 CHECK_AND_RETURN_RET(event != nullptr, MSERR_NO_MEMORY);
174 (void)gst_element_send_event(codecBin_, event);
175
176 event = gst_event_new_flush_stop(FALSE);
177 CHECK_AND_RETURN_RET(event != nullptr, MSERR_NO_MEMORY);
178 (void)gst_element_send_event(codecBin_, event);
179
180 MEDIA_LOGD("Flush success");
181 return MSERR_OK;
182 }
183
Release()184 int32_t AVCodecEngineCtrl::Release()
185 {
186 if (gstPipeline_ != nullptr) {
187 CHECK_AND_RETURN_RET(Stop() == MSERR_OK, MSERR_UNKNOWN);
188 (void)gst_element_set_state(GST_ELEMENT_CAST(gstPipeline_), GST_STATE_NULL);
189 }
190
191 src_ = nullptr;
192 sink_ = nullptr;
193 if (codecBin_ != nullptr) {
194 gst_object_unref(codecBin_);
195 codecBin_ = nullptr;
196 }
197 if (gstPipeline_ != nullptr) {
198 gst_object_unref(gstPipeline_);
199 gstPipeline_ = nullptr;
200 }
201 if (bus_ != nullptr) {
202 g_clear_object(&bus_);
203 bus_ = nullptr;
204 }
205
206 MEDIA_LOGD("Release success");
207 return MSERR_OK;
208 }
209
SetObs(const std::weak_ptr<IAVCodecEngineObs> & obs)210 void AVCodecEngineCtrl::SetObs(const std::weak_ptr<IAVCodecEngineObs> &obs)
211 {
212 obs_ = obs;
213 }
214
CreateInputSurface(std::shared_ptr<ProcessorConfig> inputConfig)215 sptr<Surface> AVCodecEngineCtrl::CreateInputSurface(std::shared_ptr<ProcessorConfig> inputConfig)
216 {
217 CHECK_AND_RETURN_RET(codecType_ == AVCODEC_TYPE_VIDEO_ENCODER, nullptr);
218 if (src_ == nullptr) {
219 MEDIA_LOGD("Use surface src");
220 src_ = AVCodecEngineFactory::CreateSrc(SrcType::SRC_TYPE_SURFACE);
221 CHECK_AND_RETURN_RET_LOG(src_ != nullptr, nullptr, "No memory");
222 CHECK_AND_RETURN_RET_LOG(src_->Init() == MSERR_OK, nullptr, "Failed to create input surface");
223 }
224
225 auto surface = src_->CreateInputSurface(inputConfig);
226 CHECK_AND_RETURN_RET(surface != nullptr, nullptr);
227 useSurfaceInput_ = true;
228 CHECK_AND_RETURN_RET(codecBin_ != nullptr, nullptr);
229 g_object_set(codecBin_, "use-surface-input", TRUE, nullptr);
230 MEDIA_LOGD("CreateInputSurface success");
231 return surface;
232 }
233
SetOutputSurface(sptr<Surface> surface)234 int32_t AVCodecEngineCtrl::SetOutputSurface(sptr<Surface> surface)
235 {
236 CHECK_AND_RETURN_RET(codecType_ == AVCODEC_TYPE_VIDEO_DECODER, MSERR_INVALID_OPERATION);
237 if (sink_ == nullptr) {
238 MEDIA_LOGD("Use surface sink");
239 sink_ = AVCodecEngineFactory::CreateSink(SinkType::SINK_TYPE_SURFACE);
240 CHECK_AND_RETURN_RET_LOG(sink_ != nullptr, MSERR_NO_MEMORY, "No memory");
241 CHECK_AND_RETURN_RET(sink_->Init() == MSERR_OK, MSERR_UNKNOWN);
242 CHECK_AND_RETURN_RET(sink_->SetCallback(obs_) == MSERR_OK, MSERR_UNKNOWN);
243 }
244 if (sink_->SetOutputSurface(surface) == MSERR_OK) {
245 useSurfaceRender_ = true;
246 } else {
247 return MSERR_UNKNOWN;
248 }
249
250 MEDIA_LOGD("SetOutputSurface success");
251 return MSERR_OK;
252 }
253
GetInputBuffer(uint32_t index)254 std::shared_ptr<AVSharedMemory> AVCodecEngineCtrl::GetInputBuffer(uint32_t index)
255 {
256 CHECK_AND_RETURN_RET(src_ != nullptr, nullptr);
257 return src_->GetInputBuffer(index);
258 }
259
QueueInputBuffer(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag)260 int32_t AVCodecEngineCtrl::QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag)
261 {
262 CHECK_AND_RETURN_RET(src_ != nullptr, MSERR_UNKNOWN);
263 int32_t ret = src_->QueueInputBuffer(index, info, flag);
264 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
265 if (flag & AVCODEC_BUFFER_FLAG_EOS) {
266 GstEvent *event = gst_event_new_eos();
267 CHECK_AND_RETURN_RET(event != nullptr, MSERR_NO_MEMORY);
268 (void)gst_element_send_event(codecBin_, event);
269 flushAtStart_ = true;
270 }
271 return MSERR_OK;
272 }
273
GetOutputBuffer(uint32_t index)274 std::shared_ptr<AVSharedMemory> AVCodecEngineCtrl::GetOutputBuffer(uint32_t index)
275 {
276 CHECK_AND_RETURN_RET(sink_ != nullptr, nullptr);
277 return sink_->GetOutputBuffer(index);
278 }
279
ReleaseOutputBuffer(uint32_t index,bool render)280 int32_t AVCodecEngineCtrl::ReleaseOutputBuffer(uint32_t index, bool render)
281 {
282 CHECK_AND_RETURN_RET(sink_ != nullptr, MSERR_UNKNOWN);
283 return sink_->ReleaseOutputBuffer(index, render);
284 }
285
SetParameter(const Format & format)286 int32_t AVCodecEngineCtrl::SetParameter(const Format &format)
287 {
288 CHECK_AND_RETURN_RET(src_ != nullptr, MSERR_UNKNOWN);
289 CHECK_AND_RETURN_RET(src_->SetParameter(format) == MSERR_OK, MSERR_UNKNOWN);
290
291 CHECK_AND_RETURN_RET(sink_ != nullptr, MSERR_UNKNOWN);
292 CHECK_AND_RETURN_RET(sink_->SetParameter(format) == MSERR_OK, MSERR_UNKNOWN);
293
294 CHECK_AND_RETURN_RET(codecBin_ != nullptr, MSERR_UNKNOWN);
295
296 int32_t value = 0;
297 if (format.GetValueType(std::string_view("req_i_frame")) == FORMAT_TYPE_INT32) {
298 if (format.GetIntValue("req_i_frame", value) && value >= 0) {
299 g_object_set(codecBin_, "req-i-frame", static_cast<uint32_t>(value), nullptr);
300 }
301 }
302
303 if (format.GetValueType(std::string_view("bitrate")) == FORMAT_TYPE_INT32) {
304 if (format.GetIntValue("bitrate", value) && value > 0) {
305 g_object_set(codecBin_, "bitrate", static_cast<uint32_t>(value), nullptr);
306 }
307 }
308
309 if (format.GetValueType(std::string_view("vendor.custom")) == FORMAT_TYPE_ADDR) {
310 uint8_t *addr = nullptr;
311 size_t size = 0;
312 if (format.GetBuffer("vendor.custom", &addr, size) && addr != nullptr) {
313 GstBuffer *buffer = gst_buffer_new_allocate(nullptr, size, nullptr);
314 CHECK_AND_RETURN_RET(buffer != nullptr, MSERR_NO_MEMORY);
315
316 ON_SCOPE_EXIT(0) { gst_buffer_unref(buffer); };
317
318 gsize ret = gst_buffer_fill(buffer, 0, (char *)addr, size);
319 CHECK_AND_RETURN_RET(ret == static_cast<gsize>(size), MSERR_UNKNOWN);
320 g_object_set(codecBin_, "vendor", static_cast<gpointer>(buffer), nullptr);
321 }
322 }
323
324 MEDIA_LOGD("SetParameter success");
325 return MSERR_OK;
326 }
327
BusSyncHandler(GstBus * bus,GstMessage * message,gpointer userData)328 GstBusSyncReply AVCodecEngineCtrl::BusSyncHandler(GstBus *bus, GstMessage *message, gpointer userData)
329 {
330 CHECK_AND_RETURN_RET(message != nullptr, GST_BUS_DROP);
331
332 auto self = reinterpret_cast<AVCodecEngineCtrl *>(userData);
333 switch (GST_MESSAGE_TYPE(message)) {
334 case GST_MESSAGE_STATE_CHANGED: {
335 CHECK_AND_RETURN_RET(message->src != nullptr, GST_BUS_DROP);
336 if (GST_IS_BIN(message->src) && !GST_IS_PIPELINE(message->src)) {
337 MEDIA_LOGD("Finish state change");
338 std::unique_lock<std::mutex> lock(self->gstPipeMutex_);
339 self->gstPipeCond_.notify_all();
340 }
341 break;
342 }
343 case GST_MESSAGE_ERROR: {
344 int32_t errCode = MSERR_UNKNOWN;
345 GError *err = nullptr;
346 gst_message_parse_error(message, &err, nullptr);
347 if (err->domain == GST_CORE_ERROR) {
348 errCode = MSERR_UNKNOWN;
349 } else if (err->domain == GST_LIBRARY_ERROR) {
350 errCode = MSERR_UNSUPPORT;
351 } else
352 if (err->domain == GST_RESOURCE_ERROR) {
353 errCode = MSERR_INVALID_VAL;
354 } else if (err->domain == GST_STREAM_ERROR) {
355 errCode = MSERR_DATA_SOURCE_ERROR_UNKNOWN;
356 }
357
358 auto obs = self->obs_.lock();
359 CHECK_AND_RETURN_RET(obs != nullptr, GST_BUS_DROP);
360 obs->OnError(AVCODEC_ERROR_INTERNAL, errCode);
361 break;
362 }
363 default: {
364 break;
365 }
366 }
367 return GST_BUS_PASS;
368 }
369 } // namespace Media
370 } // namespace OHOS
371