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