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