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 "gst_venc_base.h"
17 #include <vector>
18 #include "buffer_type_meta.h"
19 #include "scope_guard.h"
20 #include "securec.h"
21 #include "gst_codec_video_common.h"
22
23 using namespace OHOS;
24 using namespace OHOS::Media;
25 GST_DEBUG_CATEGORY_STATIC(gst_venc_base_debug_category);
26 #define GST_CAT_DEFAULT gst_venc_base_debug_category
27 #define gst_venc_base_parent_class parent_class
28 #define GST_VENC_BASE_SUPPORTED_FORMATS "{ NV21 }"
29 #define GST_VENC_BITRATE_DEFAULT (0xffffffff)
30 #define GST_VENC_ALIGN_DEFAULT 16
31
32 static void gst_venc_base_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
33 static void gst_venc_base_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
34 static gboolean gst_venc_base_open(GstVideoEncoder *encoder);
35 static gboolean gst_venc_base_close(GstVideoEncoder *encoder);
36 static gboolean gst_venc_base_start(GstVideoEncoder *encoder);
37 static gboolean gst_venc_base_stop(GstVideoEncoder *encoder);
38 static gboolean gst_venc_base_set_format(GstVideoEncoder *encoder, GstVideoCodecState *state);
39 static gboolean gst_venc_base_flush(GstVideoEncoder *encoder);
40 static GstFlowReturn gst_venc_base_handle_frame(GstVideoEncoder *encoder, GstVideoCodecFrame *frame);
41 static void gst_venc_base_finalize(GObject *object);
42 static GstFlowReturn gst_venc_base_finish(GstVideoEncoder *encoder);
43 static void gst_venc_base_loop(GstVencBase *self);
44 static void gst_venc_base_pause_loop(GstVencBase *self);
45 static gboolean gst_venc_base_event(GstVideoEncoder *encoder, GstEvent *event);
46 static gboolean gst_venc_base_decide_allocation(GstVideoEncoder *encoder, GstQuery *query);
47 static gboolean gst_venc_base_propose_allocation(GstVideoEncoder *encoder, GstQuery *query);
48 static gboolean gst_codec_return_is_ok(const GstVencBase *encoder, gint ret,
49 const char *error_name, gboolean need_report);
50 static GstStateChangeReturn gst_venc_base_change_state(GstElement *element, GstStateChange transition);
51 static void gst_venc_base_init_config(GObjectClass *gobject_class);
52
53 enum {
54 PROP_0,
55 PROP_BITRATE,
56 PROP_REQUEST_I_FRAME,
57 PROP_VENDOR,
58 PROP_SURFACE_ENABLE,
59 PROP_I_FRAME_INTERVAL,
60 PROP_BITRATE_MODE,
61 PROP_CODEC_QUALITY,
62 PROP_I_FRAME_INTERVAL_NEW,
63 PROP_CODEC_PROFILE,
64 };
65
66 G_DEFINE_ABSTRACT_TYPE(GstVencBase, gst_venc_base, GST_TYPE_VIDEO_ENCODER);
67
gst_venc_base_class_init(GstVencBaseClass * klass)68 static void gst_venc_base_class_init(GstVencBaseClass *klass)
69 {
70 GST_DEBUG_OBJECT(klass, "Class init");
71 g_return_if_fail(klass != nullptr);
72 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
73 GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
74 GstVideoEncoderClass *video_encoder_class = GST_VIDEO_ENCODER_CLASS(klass);
75 GST_DEBUG_CATEGORY_INIT(gst_venc_base_debug_category, "vencbase", 0, "video encoder base class");
76 gobject_class->set_property = gst_venc_base_set_property;
77 gobject_class->get_property = gst_venc_base_get_property;
78 gobject_class->finalize = gst_venc_base_finalize;
79 video_encoder_class->open = gst_venc_base_open;
80 video_encoder_class->close = gst_venc_base_close;
81 video_encoder_class->start = gst_venc_base_start;
82 video_encoder_class->stop = gst_venc_base_stop;
83 video_encoder_class->flush = gst_venc_base_flush;
84 video_encoder_class->set_format = gst_venc_base_set_format;
85 video_encoder_class->handle_frame = gst_venc_base_handle_frame;
86 video_encoder_class->finish = gst_venc_base_finish;
87 video_encoder_class->sink_event = gst_venc_base_event;
88 video_encoder_class->decide_allocation = gst_venc_base_decide_allocation;
89 video_encoder_class->propose_allocation = gst_venc_base_propose_allocation;
90 element_class->change_state = gst_venc_base_change_state;
91
92 g_object_class_install_property(gobject_class, PROP_BITRATE,
93 g_param_spec_uint("bitrate", "Bitrate", "Bitrate in bits per second",
94 0, G_MAXUINT, GST_VENC_BITRATE_DEFAULT,
95 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING)));
96
97 g_object_class_install_property(gobject_class, PROP_REQUEST_I_FRAME,
98 g_param_spec_uint("req-i-frame", "Request I frame", "Request I frame for video encoder",
99 0, G_MAXUINT32, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
100
101 g_object_class_install_property(gobject_class, PROP_I_FRAME_INTERVAL,
102 g_param_spec_uint("i-frame-interval", "I frame interval", "Set i frame interval for video encoder",
103 0, G_MAXUINT32, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
104
105 g_object_class_install_property(gobject_class, PROP_VENDOR,
106 g_param_spec_pointer("vendor", "Vendor property", "Vendor property",
107 (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
108
109 gst_venc_base_init_config(gobject_class);
110 const gchar *sink_caps_string = GST_VIDEO_CAPS_MAKE(GST_VENC_BASE_SUPPORTED_FORMATS);
111 GstCaps *sink_caps = gst_caps_from_string(sink_caps_string);
112 if (sink_caps != nullptr) {
113 GstPadTemplate *sink_templ = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
114 gst_element_class_add_pad_template(element_class, sink_templ);
115 gst_caps_unref(sink_caps);
116 }
117 }
118
gst_venc_base_init_config(GObjectClass * gobject_class)119 static void gst_venc_base_init_config(GObjectClass *gobject_class)
120 {
121 g_object_class_install_property(gobject_class, PROP_SURFACE_ENABLE,
122 g_param_spec_boolean("enable-surface", "Enable Surface", "The input mem is surface buffer",
123 FALSE, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
124
125 g_object_class_install_property(gobject_class, PROP_BITRATE_MODE,
126 g_param_spec_int("bitrate-mode", "Bitrate mode", "bitrate mode for video encoder",
127 0, G_MAXINT32, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
128
129 g_object_class_install_property(gobject_class, PROP_CODEC_QUALITY,
130 g_param_spec_int("codec-quality", "Codec quality", "Codec quality for video encoder",
131 0, G_MAXINT32, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
132
133 // this interval is operate by codec
134 g_object_class_install_property(gobject_class, PROP_I_FRAME_INTERVAL_NEW,
135 g_param_spec_int("i-frame-interval-new", "I frame interval new", "I frame interval for video encoder",
136 0, G_MAXINT32, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
137
138 g_object_class_install_property(gobject_class, PROP_CODEC_PROFILE,
139 g_param_spec_int("codec-profile", "Codec profile", "Codec profile for video encoder",
140 0, G_MAXINT32, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
141 }
142
gst_venc_base_set_property_next(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)143 static void gst_venc_base_set_property_next(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
144 {
145 (void)pspec;
146 GstVencBase *self = GST_VENC_BASE(object);
147 g_return_if_fail(value != nullptr);
148 g_return_if_fail(self != nullptr);
149 switch (property_id) {
150 case PROP_BITRATE_MODE:
151 self->bitrate_mode = g_value_get_int(value);
152 break;
153 case PROP_CODEC_QUALITY:
154 self->codec_quality = g_value_get_int(value);
155 break;
156 case PROP_I_FRAME_INTERVAL_NEW:
157 self->i_frame_interval_new = g_value_get_int(value);
158 break;
159 case PROP_CODEC_PROFILE:
160 self->codec_profile = g_value_get_int(value);
161 break;
162 default:
163 break;
164 }
165 }
166
gst_venc_base_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)167 static void gst_venc_base_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
168 {
169 GST_DEBUG_OBJECT(object, "Set Property");
170 GstVencBase *self = GST_VENC_BASE(object);
171 g_return_if_fail(value != nullptr);
172 g_return_if_fail(self != nullptr);
173 gint ret = GST_CODEC_OK;
174 switch (property_id) {
175 case PROP_BITRATE: {
176 GST_INFO_OBJECT(object, "Set dynamic bitrate");
177 GST_OBJECT_LOCK(self);
178 self->bitrate = g_value_get_uint(value);
179 if (self->encoder != nullptr) {
180 ret = self->encoder->SetParameter(GST_DYNAMIC_BITRATE, GST_ELEMENT(self));
181 }
182 GST_OBJECT_UNLOCK(self);
183 g_return_if_fail(ret == GST_CODEC_OK);
184 break;
185 }
186 case PROP_REQUEST_I_FRAME: {
187 GST_INFO_OBJECT(object, "Request I frame");
188 if (self->encoder != nullptr) {
189 g_return_if_fail(self->encoder->SetParameter(GST_REQUEST_I_FRAME, GST_ELEMENT(self)) == GST_CODEC_OK);
190 }
191 break;
192 }
193 case PROP_I_FRAME_INTERVAL: {
194 self->i_frame_interval = g_value_get_uint(value);
195 GST_INFO_OBJECT(object, "Set i frame interval %u for video encoder", self->i_frame_interval);
196 break;
197 }
198 case PROP_VENDOR: {
199 GST_INFO_OBJECT(object, "Set vendor property");
200 if (self->encoder != nullptr) {
201 g_return_if_fail(self->encoder->SetParameter(GST_VENDOR, GST_ELEMENT(self)) == GST_CODEC_OK);
202 }
203 break;
204 }
205 case PROP_SURFACE_ENABLE: {
206 GST_OBJECT_LOCK(self);
207 gboolean enable = g_value_get_boolean(value);
208 self->memtype = enable ? GST_MEMTYPE_SURFACE : self->memtype;
209 GST_OBJECT_UNLOCK(self);
210 break;
211 }
212 default:
213 break;
214 }
215 gst_venc_base_set_property_next(object, property_id, value, pspec);
216 }
217
gst_venc_base_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)218 static void gst_venc_base_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
219 {
220 (void)pspec;
221 GST_DEBUG_OBJECT(object, "Get Property");
222 g_return_if_fail(object != nullptr);
223 GstVencBase *self = GST_VENC_BASE(object);
224 switch (property_id) {
225 case PROP_BITRATE:
226 GST_OBJECT_LOCK(self);
227 g_value_set_uint(value, self->bitrate);
228 GST_OBJECT_UNLOCK(self);
229 break;
230 default: {
231 break;
232 }
233 }
234 }
235
gst_venc_base_init(GstVencBase * self)236 static void gst_venc_base_init(GstVencBase *self)
237 {
238 GST_DEBUG_OBJECT(self, "Init");
239 g_return_if_fail(self != nullptr);
240 g_return_if_fail(GST_VIDEO_ENCODER_SINK_PAD(self) != nullptr);
241 GST_PAD_SET_ACCEPT_TEMPLATE(GST_VIDEO_ENCODER_SINK_PAD(self));
242
243 g_mutex_init(&self->lock);
244 g_mutex_init(&self->drain_lock);
245 g_cond_init(&self->drain_cond);
246 self->draining = FALSE;
247 self->flushing = FALSE;
248 self->prepared = FALSE;
249 self->width = 0;
250 self->height = 0;
251 self->frame_rate = 0;
252 (void)memset_s(&self->input, sizeof(GstVencBasePort), 0, sizeof(GstVencBasePort));
253 (void)memset_s(&self->output, sizeof(GstVencBasePort), 0, sizeof(GstVencBasePort));
254 self->memtype = GST_MEMTYPE_INVALID;
255 self->bitrate = 0;
256 self->input.frame_cnt = 0;
257 self->input.first_frame_time = 0;
258 self->input.last_frame_time = 0;
259 self->output.frame_cnt = 0;
260 self->output.first_frame_time = 0;
261 self->output.last_frame_time = 0;
262 self->coding_outbuf_cnt = 0;
263 self->first_in_frame = TRUE;
264 self->first_out_frame = TRUE;
265 self->last_pts = GST_CLOCK_TIME_NONE;
266 self->first_frame_pts = GST_CLOCK_TIME_NONE;
267 self->i_frame_interval = 0;
268 self->flushing_stopping = FALSE;
269 self->encoder_start = FALSE;
270 self->bitrate_mode = -1;
271 self->codec_quality = -1;
272 self->i_frame_interval_new = 1000; // 1000ms I frame once
273 self->codec_profile = -1;
274 self->codec_level = -1;
275 }
276
gst_venc_base_finalize(GObject * object)277 static void gst_venc_base_finalize(GObject *object)
278 {
279 GST_DEBUG_OBJECT(object, "Finalize");
280 g_return_if_fail(object != nullptr);
281 GstVencBase *self = GST_VENC_BASE(object);
282 gst_object_unref(self->inpool);
283 self->inpool = nullptr;
284 gst_object_unref(self->outpool);
285 self->outpool = nullptr;
286 gst_object_unref(self->input.allocator);
287 self->input.allocator = nullptr;
288 gst_object_unref(self->output.allocator);
289 self->output.allocator = nullptr;
290 gst_video_codec_state_unref(self->input_state);
291 self->input_state = nullptr;
292 gst_object_unref(self->output_state);
293 self->output_state = nullptr;
294 g_mutex_clear(&self->drain_lock);
295 g_cond_clear(&self->drain_cond);
296 g_mutex_clear(&self->lock);
297 self->input.av_shmem_pool = nullptr;
298 self->output.av_shmem_pool = nullptr;
299 std::vector<GstVideoFormat> tempVec;
300 tempVec.swap(self->formats);
301 self->encoder = nullptr;
302 G_OBJECT_CLASS(parent_class)->finalize(object);
303 }
304
gst_venc_base_open(GstVideoEncoder * encoder)305 static gboolean gst_venc_base_open(GstVideoEncoder *encoder)
306 {
307 GST_DEBUG_OBJECT(encoder, "Open");
308 g_return_val_if_fail(encoder != nullptr, FALSE);
309 GstVencBase *self = GST_VENC_BASE(encoder);
310 GstVencBaseClass *base_class = GST_VENC_BASE_GET_CLASS(self);
311 g_return_val_if_fail(base_class != nullptr && base_class->create_codec != nullptr, FALSE);
312 self->encoder = base_class->create_codec(reinterpret_cast<GstElementClass*>(base_class));
313 g_return_val_if_fail(self->encoder != nullptr, FALSE);
314 return TRUE;
315 }
316
gst_venc_base_is_flushing(GstVencBase * self)317 static gboolean gst_venc_base_is_flushing(GstVencBase *self)
318 {
319 g_return_val_if_fail(self != nullptr, FALSE);
320 GST_OBJECT_LOCK(self);
321 gboolean flushing = self->flushing;
322 GST_OBJECT_UNLOCK(self);
323 GST_DEBUG_OBJECT(self, "Flushing %d", flushing);
324 return flushing;
325 }
326
gst_venc_base_set_flushing(GstVencBase * self,const gboolean flushing)327 static void gst_venc_base_set_flushing(GstVencBase *self, const gboolean flushing)
328 {
329 GST_DEBUG_OBJECT(self, "Set flushing %d", flushing);
330 g_return_if_fail(self != nullptr);
331 GST_OBJECT_LOCK(self);
332 self->flushing = flushing;
333 GST_OBJECT_UNLOCK(self);
334 }
335
gst_venc_base_close(GstVideoEncoder * encoder)336 static gboolean gst_venc_base_close(GstVideoEncoder *encoder)
337 {
338 GST_DEBUG_OBJECT(encoder, "Close");
339 g_return_val_if_fail(encoder != nullptr, FALSE);
340 GstVencBase *self = GST_VENC_BASE(encoder);
341 g_return_val_if_fail(self->encoder != nullptr, FALSE);
342 self->encoder->Deinit();
343 self->encoder = nullptr;
344
345 return TRUE;
346 }
347
gst_venc_base_start(GstVideoEncoder * encoder)348 static gboolean gst_venc_base_start(GstVideoEncoder *encoder)
349 {
350 GST_DEBUG_OBJECT(encoder, "Start");
351 GstVencBase *self = GST_VENC_BASE(encoder);
352 self->input.frame_cnt = 0;
353 self->input.first_frame_time = 0;
354 self->input.last_frame_time = 0;
355 self->output.frame_cnt = 0;
356 self->output.first_frame_time = 0;
357 self->output.last_frame_time = 0;
358 self->first_out_frame = TRUE;
359 return TRUE;
360 }
361
gst_venc_base_pool_ref(GstBufferPool * pool)362 static GstBufferPool *gst_venc_base_pool_ref(GstBufferPool *pool)
363 {
364 g_return_val_if_fail(pool != nullptr, nullptr);
365 return reinterpret_cast<GstBufferPool*>(gst_object_ref(reinterpret_cast<gpointer>(pool)));
366 }
367
gst_venc_base_pool_unref(GstBufferPool * pool)368 static void gst_venc_base_pool_unref(GstBufferPool *pool)
369 {
370 g_return_if_fail(pool != nullptr);
371 gst_object_unref(reinterpret_cast<gpointer>(pool));
372 }
373
gst_venc_base_stop(GstVideoEncoder * encoder)374 static gboolean gst_venc_base_stop(GstVideoEncoder *encoder)
375 {
376 g_return_val_if_fail(encoder != nullptr, FALSE);
377 GstVencBase *self = GST_VENC_BASE(encoder);
378 g_return_val_if_fail(self->encoder != nullptr, FALSE);
379 GST_DEBUG_OBJECT(self, "Stop encoder start");
380
381 g_mutex_lock(&self->drain_lock);
382 self->draining = FALSE;
383 g_cond_broadcast(&self->drain_cond);
384 g_mutex_unlock(&self->drain_lock);
385
386 gint ret = self->encoder->Stop();
387 (void)gst_codec_return_is_ok(self, ret, "Stop", TRUE);
388 if (self->input_state) {
389 gst_video_codec_state_unref(self->input_state);
390 }
391 if (self->output_state) {
392 gst_video_codec_state_unref(self->output_state);
393 }
394 self->input_state = nullptr;
395 self->output_state = nullptr;
396 gst_pad_stop_task(GST_VIDEO_ENCODER_SRC_PAD(encoder));
397 ret = self->encoder->FreeInputBuffers();
398 (void)gst_codec_return_is_ok(self, ret, "FreeInput", TRUE);
399 ret = self->encoder->FreeOutputBuffers();
400 (void)gst_codec_return_is_ok(self, ret, "FreeOutput", TRUE);
401 if (self->inpool) {
402 GST_DEBUG_OBJECT(self, "Input buffer ref count %u", (reinterpret_cast<GObject*>(self->inpool)->ref_count));
403 gst_venc_base_pool_unref(self->inpool);
404 self->inpool = nullptr;
405 }
406 if (self->outpool) {
407 GST_DEBUG_OBJECT(self, "Output buffer ref count %u", (reinterpret_cast<GObject*>(self->outpool)->ref_count));
408 gst_venc_base_pool_unref(self->outpool);
409 self->outpool = nullptr;
410 }
411 self->prepared = FALSE;
412 self->encoder_start = FALSE;
413 GST_DEBUG_OBJECT(self, "Stop encoder end");
414
415 return TRUE;
416 }
417
gst_codec_return_is_ok(const GstVencBase * encoder,gint ret,const char * error_name,gboolean need_report)418 static gboolean gst_codec_return_is_ok(const GstVencBase *encoder, gint ret,
419 const char *error_name, gboolean need_report)
420 {
421 if (ret == GST_CODEC_OK) {
422 return TRUE;
423 }
424 if (need_report) {
425 GST_ELEMENT_ERROR(encoder, STREAM, ENCODE, ("hardware encoder error!"), ("%s", error_name));
426 } else {
427 GST_ERROR_OBJECT(encoder, "Hardware encoder error %s", error_name);
428 }
429 return FALSE;
430 }
431
gst_venc_base_flush(GstVideoEncoder * encoder)432 static gboolean gst_venc_base_flush(GstVideoEncoder *encoder)
433 {
434 GstVencBase *self = GST_VENC_BASE(encoder);
435 g_return_val_if_fail(self != nullptr, FALSE);
436 g_return_val_if_fail(self->encoder != nullptr, FALSE);
437 GST_DEBUG_OBJECT(self, "Flush start");
438
439 if (!self->flushing_stopping) {
440 gst_venc_base_set_flushing(self, TRUE);
441 gint ret = self->encoder->Flush(GST_CODEC_ALL);
442 (void)gst_codec_return_is_ok(self, ret, "flush", FALSE);
443 gst_venc_base_set_flushing(self, FALSE);
444 }
445
446 GST_DEBUG_OBJECT(self, "Flush end");
447
448 return TRUE;
449 }
450
gst_venc_base_allocate_surface_in_buffers(GstVencBase * self)451 static gboolean gst_venc_base_allocate_surface_in_buffers(GstVencBase *self)
452 {
453 GST_DEBUG_OBJECT(self, "Allocate input buffers start");
454 g_return_val_if_fail(self != nullptr, FALSE);
455 g_return_val_if_fail(self->encoder != nullptr, FALSE);
456 std::vector<GstBuffer*> buffers;
457 for (guint i = 0; i < self->input.buffer_cnt; ++i) {
458 buffers.push_back(nullptr);
459 }
460 gint ret = self->encoder->UseInputBuffers(buffers);
461 buffers.clear();
462 return gst_codec_return_is_ok(self, ret, "Usebuffer", TRUE);
463 }
464
gst_venc_base_init_surface_mem(GstVencBase * self,GstQuery * query,gboolean update_pool)465 static gboolean gst_venc_base_init_surface_mem(GstVencBase *self, GstQuery *query, gboolean update_pool)
466 {
467 g_return_val_if_fail(self != nullptr, FALSE);
468 g_return_val_if_fail(self->encoder != nullptr, FALSE);
469 gint ret = self->encoder->SetParameter(GST_VIDEO_SURFACE_INIT, GST_ELEMENT(self));
470 g_return_val_if_fail(gst_codec_return_is_ok(self, ret, "GST_VIDEO_SURFACE_INIT", TRUE), FALSE);
471 if (update_pool) {
472 gst_query_set_nth_allocation_pool(query, 0, nullptr, 0, self->input.buffer_cnt, self->input.buffer_cnt);
473 } else {
474 gst_query_add_allocation_pool(query, nullptr, 0, self->input.buffer_cnt, self->input.buffer_cnt);
475 }
476 return gst_venc_base_allocate_surface_in_buffers(self);
477 }
478
gst_venc_base_set_outstate(GstVencBase * self)479 static gboolean gst_venc_base_set_outstate(GstVencBase *self)
480 {
481 g_return_val_if_fail(self != nullptr, FALSE);
482 g_return_val_if_fail(GST_VIDEO_ENCODER_SRC_PAD(self) != nullptr, FALSE);
483 GstVideoEncoder *encoder = GST_VIDEO_ENCODER(self);
484 GstVencBaseClass *klass = GST_VENC_BASE_GET_CLASS(self);
485
486 GST_DEBUG_OBJECT(self, "Setting output state: format %s, width %d, height %d",
487 gst_video_format_to_string(self->format), self->width, self->height);
488 GstCaps *caps = klass->get_caps(self, self->input_state);
489 GstVideoCodecState *out_state = gst_video_encoder_set_output_state(encoder, caps, self->input_state);
490 GST_DEBUG_OBJECT(self, "Out_state ref %d", out_state->ref_count);
491 out_state->info.interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
492 out_state->info.chroma_site = GST_VIDEO_CHROMA_SITE_NONE;
493 gst_video_codec_state_unref(out_state);
494 return TRUE;
495 }
496
gst_venc_base_negotiate(GstVencBase * self)497 static gboolean gst_venc_base_negotiate(GstVencBase *self)
498 {
499 GST_DEBUG_OBJECT(self, "Negotiate");
500 g_return_val_if_fail(self != nullptr, FALSE);
501 g_return_val_if_fail(GST_VIDEO_ENCODER_SRC_PAD(self) != nullptr, FALSE);
502 g_return_val_if_fail(gst_venc_base_set_outstate(self), FALSE);
503 g_return_val_if_fail(gst_video_encoder_negotiate(GST_VIDEO_ENCODER(self)), FALSE);
504 GST_WARNING_OBJECT(self, "KPI-TRACE-VENC: negotiate end");
505 return TRUE;
506 }
507
gst_venc_base_allocate_in_buffers(GstVencBase * self)508 static gboolean gst_venc_base_allocate_in_buffers(GstVencBase *self)
509 {
510 GST_DEBUG_OBJECT(self, "Allocate input buffers start");
511 g_return_val_if_fail(self != nullptr, FALSE);
512 g_return_val_if_fail(self->encoder != nullptr, FALSE);
513 g_return_val_if_fail(self->inpool != nullptr, FALSE);
514 std::vector<GstBuffer*> buffers;
515 GstBufferPool *pool = reinterpret_cast<GstBufferPool*>(gst_object_ref(self->inpool));
516 ON_SCOPE_EXIT(0) { gst_object_unref(pool); };
517 for (guint i = 0; i < self->input.buffer_cnt; ++i) {
518 GST_DEBUG_OBJECT(self, "Input buffer index %u", i);
519 GstBuffer *buffer = nullptr;
520 GstFlowReturn flow_ret = gst_buffer_pool_acquire_buffer(pool, &buffer, nullptr);
521 if (flow_ret != GST_FLOW_OK || buffer == nullptr) {
522 GST_WARNING_OBJECT(self, "Input buffer is nullptr");
523 gst_buffer_unref(buffer);
524 continue;
525 }
526 buffers.push_back(buffer);
527 }
528 gint ret = self->encoder->UseInputBuffers(buffers);
529 for (auto buffer : buffers) {
530 gst_buffer_unref(buffer);
531 }
532 buffers.clear();
533 return gst_codec_return_is_ok(self, ret, "Usebuffer", TRUE);
534 }
535
gst_venc_base_update_out_port_def(GstVencBase * self)536 static gboolean gst_venc_base_update_out_port_def(GstVencBase *self)
537 {
538 g_return_val_if_fail(self != nullptr, FALSE);
539 g_return_val_if_fail(self->encoder != nullptr, FALSE);
540 gint ret = self->encoder->GetParameter(GST_VIDEO_OUTPUT_COMMON, GST_ELEMENT(self));
541 GST_INFO_OBJECT(self, "output params is min buffer count %u, buffer count %u, buffer size is %u",
542 self->output.min_buffer_cnt, self->output.buffer_cnt, self->output.buffer_size);
543 g_return_val_if_fail(ret == GST_CODEC_OK, FALSE);
544 self->output.buffer_size = self->input.buffer_size;
545 ret = self->encoder->SetParameter(GST_VIDEO_OUTPUT_COMMON, GST_ELEMENT(self));
546 g_return_val_if_fail(ret == GST_CODEC_OK, FALSE);
547 return TRUE;
548 }
549
gst_venc_base_allocate_out_buffers(GstVencBase * self)550 static gboolean gst_venc_base_allocate_out_buffers(GstVencBase *self)
551 {
552 GST_DEBUG_OBJECT(self, "Allocate output buffers start");
553 g_return_val_if_fail(self != nullptr, FALSE);
554 g_return_val_if_fail(self->encoder != nullptr, FALSE);
555 g_return_val_if_fail(self->outpool != nullptr, FALSE);
556 std::vector<GstBuffer*> buffers;
557 self->coding_outbuf_cnt = self->output.buffer_cnt;
558 GstBufferPool *pool = reinterpret_cast<GstBufferPool*>(gst_object_ref(self->outpool));
559 ON_SCOPE_EXIT(0) { gst_object_unref(pool); };
560 for (guint i = 0; i < self->output.buffer_cnt; ++i) {
561 GST_DEBUG_OBJECT(self, "Output buffer index %u", i);
562 GstBuffer *buffer = nullptr;
563 GstFlowReturn flow_ret = gst_buffer_pool_acquire_buffer(pool, &buffer, nullptr);
564 if (flow_ret != GST_FLOW_OK || buffer == nullptr) {
565 GST_WARNING_OBJECT(self, "Output buffer is nullptr");
566 gst_buffer_unref(buffer);
567 continue;
568 }
569 buffers.push_back(buffer);
570 }
571 gint ret = self->encoder->UseOutputBuffers(buffers);
572 for (auto buffer : buffers) {
573 gst_buffer_unref(buffer);
574 }
575 g_return_val_if_fail(gst_codec_return_is_ok(self, ret, "usebuffer", TRUE), FALSE);
576 return TRUE;
577 }
578
gst_venc_base_prepare(GstVencBase * self)579 static gboolean gst_venc_base_prepare(GstVencBase *self)
580 {
581 GST_DEBUG_OBJECT(self, "Prepare");
582 g_return_val_if_fail(self != nullptr, FALSE);
583 // Negotiate with downstream and get format
584 g_return_val_if_fail(gst_venc_base_negotiate(self), FALSE);
585 // To allocate output memory, we need to give the size
586 g_return_val_if_fail(gst_venc_base_allocate_out_buffers(self), FALSE);
587
588 return TRUE;
589 }
590
gst_venc_debug_input_time(GstVencBase * self)591 static void gst_venc_debug_input_time(GstVencBase *self)
592 {
593 if (self->input.first_frame_time == 0) {
594 self->input.first_frame_time = g_get_monotonic_time();
595 } else {
596 self->input.last_frame_time = g_get_monotonic_time();
597 }
598 self->input.frame_cnt++;
599 gint64 time_interval = self->input.last_frame_time - self->input.first_frame_time;
600 gint64 frame_cnt = self->input.frame_cnt - 1;
601 if (frame_cnt > 0) {
602 gint64 time_every_frame = time_interval / frame_cnt;
603 GST_DEBUG_OBJECT(self, "Encoder Input Time interval %" G_GINT64_FORMAT " us, frame count %" G_GINT64_FORMAT
604 " ,every frame time %" G_GINT64_FORMAT " us, frame rate %.9f", time_interval, self->input.frame_cnt,
605 time_every_frame, static_cast<double>(G_TIME_SPAN_SECOND) / static_cast<double>(time_every_frame));
606 }
607 }
608
gst_venc_debug_output_time(GstVencBase * self)609 static void gst_venc_debug_output_time(GstVencBase *self)
610 {
611 if (self->output.first_frame_time == 0) {
612 self->output.first_frame_time = g_get_monotonic_time();
613 } else {
614 self->output.last_frame_time = g_get_monotonic_time();
615 }
616 self->output.frame_cnt++;
617 gint64 time_interval = self->output.last_frame_time - self->output.first_frame_time;
618 gint64 frame_cnt = self->output.frame_cnt - 1;
619 if (frame_cnt > 0) {
620 gint64 time_every_frame = time_interval / frame_cnt;
621 GST_DEBUG_OBJECT(self, "Encoder Output Time interval %" G_GINT64_FORMAT " us, frame count %" G_GINT64_FORMAT
622 " ,every frame time %" G_GINT64_FORMAT " us, frame rate %.9f", time_interval, self->output.frame_cnt,
623 time_every_frame, static_cast<double>(G_TIME_SPAN_SECOND) / static_cast<double>(time_every_frame));
624 }
625 }
626
gst_venc_base_change_state(GstElement * element,GstStateChange transition)627 static GstStateChangeReturn gst_venc_base_change_state(GstElement *element, GstStateChange transition)
628 {
629 g_return_val_if_fail(element != nullptr, GST_STATE_CHANGE_FAILURE);
630 GstVencBase *self = GST_VENC_BASE(element);
631
632 GST_DEBUG_OBJECT(element, "change state %d", transition);
633 switch (transition) {
634 case GST_STATE_CHANGE_PAUSED_TO_READY:
635 GST_WARNING_OBJECT(self, "KPI-TRACE-VENC: stop start");
636
637 GST_VIDEO_ENCODER_STREAM_LOCK(self);
638 if (self->encoder != nullptr) {
639 (void)self->encoder->Flush(GST_CODEC_ALL);
640 }
641 gst_venc_base_set_flushing(self, TRUE);
642 GST_VIDEO_ENCODER_STREAM_UNLOCK(self);
643 break;
644 case GST_STATE_CHANGE_READY_TO_NULL:
645 GST_WARNING_OBJECT(self, "KPI-TRACE-VENC: close start");
646 break;
647 default:
648 break;
649 }
650
651 GstStateChangeReturn ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
652
653 switch (transition) {
654 case GST_STATE_CHANGE_PAUSED_TO_READY:
655 GST_WARNING_OBJECT(self, "KPI-TRACE-VENC: stop end");
656 break;
657 case GST_STATE_CHANGE_READY_TO_NULL:
658 GST_WARNING_OBJECT(self, "KPI-TRACE-VENC: close end");
659 break;
660 default:
661 break;
662 }
663 return ret;
664 }
665
gst_venc_base_handle_frame_after(GstVencBase * self,GstVideoCodecFrame * frame)666 static void gst_venc_base_handle_frame_after(GstVencBase *self, GstVideoCodecFrame *frame)
667 {
668 g_return_if_fail(frame != nullptr);
669 g_return_if_fail(self != nullptr);
670 gst_buffer_unref(frame->input_buffer);
671 frame->input_buffer = nullptr;
672 self->last_pts = frame->pts;
673 if (self->first_in_frame) {
674 self->first_in_frame = FALSE;
675 self->first_frame_pts = frame->pts;
676 }
677 }
678
gst_venc_base_handle_frame(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)679 static GstFlowReturn gst_venc_base_handle_frame(GstVideoEncoder *encoder, GstVideoCodecFrame *frame)
680 {
681 GST_DEBUG_OBJECT(encoder, "Handle frame");
682 ON_SCOPE_EXIT(0) { gst_video_codec_frame_unref(frame); };
683 g_return_val_if_fail(frame != nullptr, GST_FLOW_ERROR);
684 GstVencBase *self = GST_VENC_BASE(encoder);
685 g_return_val_if_fail(self != nullptr && self->encoder != nullptr, GST_FLOW_ERROR);
686 if (self->first_in_frame) {
687 GST_WARNING_OBJECT(self, "KPI-TRACE-VENC: first in frame");
688 }
689 if (gst_venc_base_is_flushing(self)) {
690 return GST_FLOW_FLUSHING;
691 }
692 if (!self->prepared) {
693 if (!gst_venc_base_prepare(self)) {
694 GST_WARNING_OBJECT(self, "hdi video dec enable failed");
695 return GST_FLOW_ERROR;
696 }
697 self->prepared = TRUE;
698 }
699 GstPad *pad = GST_VIDEO_ENCODER_SRC_PAD(self);
700 if (!self->encoder_start) {
701 gint ret = self->encoder->Start();
702 g_return_val_if_fail(gst_codec_return_is_ok(self, ret, "start", TRUE), GST_FLOW_ERROR);
703 self->encoder_start = TRUE;
704 GST_WARNING_OBJECT(self, "KPI-TRACE-VENC: start end");
705 }
706 if (gst_pad_get_task_state(pad) != GST_TASK_STARTED &&
707 gst_pad_start_task(pad, (GstTaskFunction)gst_venc_base_loop, encoder, nullptr) != TRUE) {
708 return GST_FLOW_ERROR;
709 }
710 GST_VIDEO_ENCODER_STREAM_UNLOCK(self);
711 gst_venc_debug_input_time(self);
712 if (self->i_frame_interval != 0 && self->input.frame_cnt % (gint64)self->i_frame_interval == 0) {
713 (void)self->encoder->SetParameter(GST_REQUEST_I_FRAME, GST_ELEMENT(self));
714 }
715 // buffer ref no give to encoder
716 gint codec_ret = self->encoder->PushInputBuffer(frame->input_buffer);
717 GST_VIDEO_ENCODER_STREAM_LOCK(self);
718 GstFlowReturn ret = GST_FLOW_OK;
719 switch (codec_ret) {
720 case GST_CODEC_OK:
721 break;
722 case GST_CODEC_FLUSH:
723 GST_DEBUG_OBJECT(self, "Codec flushing");
724 ret = GST_FLOW_FLUSHING;
725 break;
726 default:
727 GST_ELEMENT_WARNING(self, STREAM, ENCODE, ("Hardware encoder error!"), ("pull"));
728 ret = GST_FLOW_ERROR;
729 }
730 gst_venc_base_handle_frame_after(self, frame);
731 return ret;
732 }
733
gst_venc_base_finish_output_buffer(GstVencBase * self,GstBuffer * buffer)734 static GstFlowReturn gst_venc_base_finish_output_buffer(GstVencBase *self, GstBuffer *buffer)
735 {
736 GST_DEBUG_OBJECT(self, "Finish output buffer start");
737 g_return_val_if_fail(self != nullptr, GST_FLOW_ERROR);
738 g_return_val_if_fail(buffer != nullptr, GST_FLOW_ERROR);
739 GstFlowReturn flow_ret = GST_FLOW_OK;
740 gst_venc_debug_output_time(self);
741
742 GstVideoCodecFrame *frame = gst_video_encoder_get_oldest_frame(GST_VIDEO_ENCODER(self));
743 if (frame != nullptr) {
744 frame->output_buffer = buffer;
745 flow_ret = gst_video_encoder_finish_frame(GST_VIDEO_ENCODER(self), frame);
746 } else {
747 GST_DEBUG_OBJECT(self, "No frame available");
748 GST_BUFFER_PTS(buffer) = self->last_pts;
749 flow_ret = gst_pad_push(GST_VIDEO_ENCODER_SRC_PAD(self), buffer);
750 }
751 GST_DEBUG_OBJECT(self, "Finish output buffer end");
752 return flow_ret;
753 }
754
gst_venc_base_codec_eos(GstVencBase * self)755 static GstFlowReturn gst_venc_base_codec_eos(GstVencBase *self)
756 {
757 GST_DEBUG_OBJECT(self, "Eos");
758 g_return_val_if_fail(self != nullptr, GST_FLOW_ERROR);
759 g_return_val_if_fail(GST_VIDEO_ENCODER_SRC_PAD(self) != nullptr, GST_FLOW_ERROR);
760 g_mutex_lock(&self->drain_lock);
761 if (self->draining) {
762 GST_DEBUG_OBJECT(self, "Drained");
763 self->draining = FALSE;
764 g_cond_broadcast(&self->drain_cond);
765 }
766 g_mutex_unlock(&self->drain_lock);
767 gst_venc_base_pause_loop(self);
768 return GST_FLOW_OK;
769 }
770
gst_venc_base_pause_loop(GstVencBase * self)771 static void gst_venc_base_pause_loop(GstVencBase *self)
772 {
773 GST_DEBUG_OBJECT(self, "Pause loop start");
774 g_return_if_fail(self != nullptr);
775 g_mutex_lock(&self->drain_lock);
776 if (self->draining) {
777 self->draining = FALSE;
778 g_cond_broadcast(&self->drain_cond);
779 }
780 g_mutex_unlock(&self->drain_lock);
781 gst_pad_pause_task(GST_VIDEO_ENCODER_SRC_PAD(self));
782 GST_DEBUG_OBJECT(self, "pause loop end");
783 }
784
gst_venc_base_push_out_buffers(GstVencBase * self)785 static gboolean gst_venc_base_push_out_buffers(GstVencBase *self)
786 {
787 GstBuffer *buffer = nullptr;
788 g_return_val_if_fail(self != nullptr, FALSE);
789 g_return_val_if_fail(self->encoder != nullptr, FALSE);
790 GstBufferPool *pool = gst_venc_base_pool_ref(self->outpool);
791 ON_SCOPE_EXIT(0) { gst_venc_base_pool_unref(pool); };
792 GstFlowReturn flow = GST_FLOW_OK;
793 gint codec_ret = GST_CODEC_OK;
794 GstBufferPoolAcquireParams params;
795 g_return_val_if_fail(memset_s(¶ms, sizeof(params), 0, sizeof(params)) == EOK, FALSE);
796 if (self->coding_outbuf_cnt != 0) {
797 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
798 }
799 while (flow == GST_FLOW_OK) {
800 flow = gst_buffer_pool_acquire_buffer(pool, &buffer, ¶ms);
801 if (flow == GST_FLOW_OK) {
802 g_return_val_if_fail(buffer != nullptr, FALSE);
803 ON_SCOPE_EXIT(1) {
804 gst_buffer_unref(buffer);
805 };
806 codec_ret = self->encoder->PushOutputBuffer(buffer);
807 g_return_val_if_fail(gst_codec_return_is_ok(self, codec_ret, "push buffer", TRUE), FALSE);
808 self->coding_outbuf_cnt++;
809 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
810 }
811 }
812 g_return_val_if_fail(flow == GST_FLOW_EOS, FALSE);
813 return TRUE;
814 }
815
gst_venc_base_loop(GstVencBase * self)816 static void gst_venc_base_loop(GstVencBase *self)
817 {
818 g_return_if_fail(self != nullptr);
819 g_return_if_fail(self->encoder != nullptr);
820 GstBuffer *gst_buffer = nullptr;
821 if (gst_venc_base_push_out_buffers(self) != TRUE) {
822 gst_venc_base_pause_loop(self);
823 return;
824 }
825 GST_DEBUG_OBJECT(self, "coding buffers %u", self->coding_outbuf_cnt);
826 gint codec_ret = self->encoder->PullOutputBuffer(&gst_buffer);
827 gint flow_ret = GST_FLOW_OK;
828 switch (codec_ret) {
829 case GST_CODEC_OK:
830 self->coding_outbuf_cnt--;
831 flow_ret = gst_venc_base_finish_output_buffer(self, gst_buffer);
832 break;
833 case GST_CODEC_EOS:
834 self->coding_outbuf_cnt--;
835 flow_ret = gst_venc_base_codec_eos(self);
836 break;
837 case GST_CODEC_FLUSH:
838 flow_ret = GST_FLOW_FLUSHING;
839 break;
840 case GST_CODEC_ERROR:
841 GST_ELEMENT_WARNING(self, STREAM, ENCODE, ("Hardware encoder error!"), ("pull"));
842 flow_ret = GST_FLOW_ERROR;
843 break;
844 default:
845 GST_ERROR_OBJECT(self, "Unknown error");
846 flow_ret = GST_FLOW_ERROR;
847 }
848 GST_DEBUG_OBJECT(self, "Flow_ret %d", flow_ret);
849 switch (flow_ret) {
850 case GST_FLOW_OK:
851 return;
852 case GST_FLOW_FLUSHING:
853 GST_DEBUG_OBJECT(self, "Flushing");
854 break;
855 case GST_FLOW_EOS:
856 GST_DEBUG_OBJECT(self, "Eos");
857 gst_pad_push_event(GST_VIDEO_ENCODER_SRC_PAD(self), gst_event_new_eos());
858 break;
859 default:
860 gst_pad_push_event(GST_VIDEO_ENCODER_SRC_PAD(self), gst_event_new_eos());
861 }
862 gst_venc_base_pause_loop(self);
863 }
864
gst_venc_base_set_format(GstVideoEncoder * encoder,GstVideoCodecState * state)865 static gboolean gst_venc_base_set_format(GstVideoEncoder *encoder, GstVideoCodecState *state)
866 {
867 GstVencBase *self = GST_VENC_BASE(encoder);
868 g_return_val_if_fail(self != nullptr, FALSE);
869 g_return_val_if_fail(state != nullptr, FALSE);
870 g_return_val_if_fail(self->encoder != nullptr, FALSE);
871 GstVideoInfo *info = &state->info;
872 GstCaps *caps = state->caps;
873 g_return_val_if_fail(info != nullptr, FALSE);
874 gboolean is_format_change = FALSE;
875 gint ret = self->encoder->GetParameter(GST_VIDEO_INPUT_COMMON, GST_ELEMENT(self));
876 g_return_val_if_fail(ret == GST_CODEC_OK, FALSE);
877 GST_INFO_OBJECT(self, "input params is min buffer count %u, buffer count %u, buffer size is %u",
878 self->input.min_buffer_cnt, self->input.buffer_cnt, self->input.buffer_size);
879
880 GST_DEBUG_OBJECT(self, "Setting new caps");
881
882 GstStructure *structure = gst_caps_get_structure(caps, 0);
883 const gchar *format_str = gst_structure_get_string(structure, "format");
884 GST_DEBUG_OBJECT(self, "gst_venc_base_set_format format=%s", format_str);
885 self->format = gst_video_format_from_string(format_str);
886
887 is_format_change = is_format_change || self->width != info->width;
888 is_format_change = is_format_change || self->height != GST_VIDEO_INFO_FIELD_HEIGHT(info);
889 is_format_change = is_format_change || (self->frame_rate != info->fps_n && info->fps_n != 0);
890
891 if (is_format_change) {
892 self->width = info->width;
893 self->height = GST_VIDEO_INFO_FIELD_HEIGHT(info);
894 self->frame_rate = info->fps_n;
895 self->nslice_height = self->height;
896 self->nstride = info->stride[0];
897 self->input.buffer_size = info->size;
898 GST_DEBUG_OBJECT(self, "width %d height %d frame_rate %d nslice_height %d nstride %d buffer_size %u",
899 self->width, self->height, self->frame_rate, self->nslice_height, self->nstride, self->input.buffer_size);
900 }
901
902 GST_DEBUG_OBJECT(self, "Setting inport definition");
903 ret = self->encoder->SetParameter(GST_VIDEO_INPUT_COMMON, GST_ELEMENT(self));
904 g_return_val_if_fail(ret == GST_CODEC_OK, FALSE);
905 ret = self->encoder->SetParameter(GST_VIDEO_FORMAT, GST_ELEMENT(self));
906 g_return_val_if_fail(ret == GST_CODEC_OK, FALSE);
907 ret = self->encoder->SetParameter(GST_VIDEO_ENCODER_CONFIG, GST_ELEMENT(self));
908 g_return_val_if_fail(ret == GST_CODEC_OK, FALSE);
909 if (self->input_state != nullptr) {
910 gst_video_codec_state_unref(self->input_state);
911 }
912 self->input_state = gst_video_codec_state_ref(state);
913 return gst_codec_return_is_ok(self, ret, "setparam", TRUE);
914 }
915
gst_venc_base_finish(GstVideoEncoder * encoder)916 static GstFlowReturn gst_venc_base_finish(GstVideoEncoder *encoder)
917 {
918 GstVencBase *self = GST_VENC_BASE(encoder);
919 g_return_val_if_fail(self != nullptr, GST_FLOW_ERROR);
920 g_return_val_if_fail(self->encoder != nullptr, GST_FLOW_ERROR);
921 GST_DEBUG_OBJECT(self, "Finish codec start");
922 GstPad *pad = GST_VIDEO_ENCODER_SRC_PAD(self);
923 if (gst_pad_get_task_state(pad) != GST_TASK_STARTED) {
924 GST_DEBUG_OBJECT(self, "venc not start yet");
925 return GST_FLOW_OK;
926 }
927 GST_VIDEO_ENCODER_STREAM_UNLOCK(self);
928 g_mutex_lock(&self->drain_lock);
929 self->draining = TRUE;
930 gint ret = self->encoder->PushInputBuffer(nullptr);
931 if (ret != GST_CODEC_OK) {
932 GST_ERROR_OBJECT(self, "Failed to push input buffer for draining: %d", ret);
933 g_mutex_unlock(&self->drain_lock);
934 GST_VIDEO_ENCODER_STREAM_LOCK(self);
935 return GST_FLOW_ERROR;
936 }
937 GST_DEBUG_OBJECT(self, "Waiting until codec is drained");
938 gint64 wait_until = g_get_monotonic_time() + G_TIME_SPAN_SECOND;
939 if (!g_cond_wait_until(&self->drain_cond, &self->drain_lock, wait_until)) {
940 GST_ERROR_OBJECT(self, "Drain timed out");
941 } else {
942 GST_DEBUG_OBJECT(self, "Finish hdi end");
943 }
944 g_mutex_unlock(&self->drain_lock);
945 GST_VIDEO_ENCODER_STREAM_LOCK(self);
946
947 return GST_FLOW_OK;
948 }
949
gst_venc_base_event(GstVideoEncoder * encoder,GstEvent * event)950 static gboolean gst_venc_base_event(GstVideoEncoder *encoder, GstEvent *event)
951 {
952 g_return_val_if_fail(encoder != nullptr, FALSE);
953 g_return_val_if_fail(event != nullptr, FALSE);
954 g_return_val_if_fail(GST_VIDEO_ENCODER_CLASS(parent_class) != nullptr, FALSE);
955 GstVencBase *self = GST_VENC_BASE(encoder);
956 GST_DEBUG_OBJECT(self, "gst_venc_base_sink_event, type=%s", GST_EVENT_TYPE_NAME(event));
957
958 gboolean ret = TRUE;
959 switch (GST_EVENT_TYPE(event)) {
960 case GST_EVENT_FLUSH_START:
961 GST_WARNING_OBJECT(self, "KPI-TRACE-VENC: flush start");
962 if (self->encoder != nullptr) {
963 (void)self->encoder->Flush(GST_CODEC_ALL);
964 }
965 gst_venc_base_set_flushing(self, TRUE);
966 self->encoder_start = FALSE;
967 break;
968 case GST_EVENT_FLUSH_STOP:
969 self->flushing_stopping = TRUE;
970 self->encoder_start = FALSE;
971 ret = GST_VIDEO_ENCODER_CLASS(parent_class)->sink_event(encoder, event);
972 gst_venc_base_set_flushing(self, FALSE);
973 self->flushing_stopping = FALSE;
974 GST_WARNING_OBJECT(self, "KPI-TRACE-VENC: flush stop");
975 return ret;
976 default:
977 break;
978 }
979
980 ret = GST_VIDEO_ENCODER_CLASS(parent_class)->sink_event(encoder, event);
981 return ret;
982 }
983
gst_venc_base_new_shmem_pool(GstVencBase * self,GstCaps * caps,guint size,guint buffer_cnt,gboolean is_input)984 static GstBufferPool *gst_venc_base_new_shmem_pool(GstVencBase *self, GstCaps *caps, guint size,
985 guint buffer_cnt, gboolean is_input)
986 {
987 GST_DEBUG_OBJECT(self, "New pool");
988 g_return_val_if_fail(self != nullptr, nullptr);
989 g_return_val_if_fail(caps != nullptr, nullptr);
990
991 GstShMemPool *pool = gst_shmem_pool_new();
992 GstAllocationParams allocParams;
993 gst_allocation_params_init(&allocParams);
994 g_return_val_if_fail(pool != nullptr, nullptr);
995 ON_SCOPE_EXIT(0) { gst_object_unref(pool); };
996 std::shared_ptr<OHOS::Media::AVSharedMemoryPool> av_shmem_pool =
997 std::make_shared<OHOS::Media::AVSharedMemoryPool>("venc");
998 GstShMemAllocator *allocator = gst_shmem_allocator_new();
999 g_return_val_if_fail(allocator != nullptr, nullptr);
1000 ON_SCOPE_EXIT(1) { gst_object_unref(allocator); };
1001 (void)gst_shmem_pool_set_avshmempool(pool, av_shmem_pool);
1002 (void)gst_shmem_allocator_set_pool(allocator, av_shmem_pool);
1003 GstStructure *config = gst_buffer_pool_get_config(GST_BUFFER_POOL_CAST(pool));
1004 g_return_val_if_fail(config != nullptr, nullptr);
1005 gst_buffer_pool_config_set_allocator(config, GST_ALLOCATOR_CAST(allocator), &allocParams);
1006 gst_buffer_pool_config_set_params(config, caps, size, buffer_cnt, buffer_cnt);
1007 g_return_val_if_fail(gst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(pool), config), nullptr);
1008 CANCEL_SCOPE_EXIT_GUARD(0);
1009 CANCEL_SCOPE_EXIT_GUARD(1);
1010 if (is_input) {
1011 self->input.av_shmem_pool = av_shmem_pool;
1012 if (self->input.allocator != nullptr) {
1013 gst_object_unref(self->input.allocator);
1014 }
1015 self->input.allocator = allocator;
1016 } else {
1017 self->output.av_shmem_pool = av_shmem_pool;
1018 if (self->output.allocator != nullptr) {
1019 gst_object_unref(self->output.allocator);
1020 }
1021 self->output.allocator = allocator;
1022 }
1023 return GST_BUFFER_POOL(pool);
1024 }
1025
gst_venc_base_update_pool(GstVencBase * self,GstBufferPool ** pool,GstCaps * caps,gint size,guint buf_cnt)1026 static void gst_venc_base_update_pool(GstVencBase *self, GstBufferPool **pool, GstCaps *caps, gint size, guint buf_cnt)
1027 {
1028 GST_DEBUG_OBJECT(self, "Update pool");
1029 g_return_if_fail(*pool != nullptr);
1030 ON_SCOPE_EXIT(0) { gst_object_unref(*pool); *pool = nullptr; };
1031 GstStructure *config = gst_buffer_pool_get_config(*pool);
1032 g_return_if_fail(config != nullptr);
1033 gst_buffer_pool_config_set_params(config, caps, size, buf_cnt, buf_cnt);
1034 if (self->memtype == GST_MEMTYPE_SURFACE) {
1035 gst_structure_set(config, "usage", G_TYPE_UINT64, self->usage, nullptr);
1036 }
1037 g_return_if_fail(gst_buffer_pool_set_config(*pool, config));
1038 CANCEL_SCOPE_EXIT_GUARD(0);
1039 }
1040
gst_venc_base_decide_allocation(GstVideoEncoder * encoder,GstQuery * query)1041 static gboolean gst_venc_base_decide_allocation(GstVideoEncoder *encoder, GstQuery *query)
1042 {
1043 GST_DEBUG_OBJECT(encoder, "Decide allocation");
1044 g_return_val_if_fail(encoder != nullptr, FALSE);
1045 GstCaps *outcaps = nullptr;
1046 GstBufferPool *pool = nullptr;
1047 guint size = 0;
1048 guint min_buf = 0;
1049 guint max_buf = 0;
1050 GstVencBase *self = GST_VENC_BASE(encoder);
1051 gst_query_parse_allocation(query, &outcaps, nullptr);
1052
1053 GstAllocationParams params;
1054 guint index = 0;
1055 gst_allocation_params_init(¶ms);
1056 guint pool_num = gst_query_get_n_allocation_pools(query);
1057 if (pool_num > 0) {
1058 gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min_buf, &max_buf);
1059 GST_DEBUG_OBJECT(encoder, "Get bufferpool num %u", pool_num);
1060 if (!gst_query_find_allocation_meta(query, GST_BUFFER_TYPE_META_API_TYPE, &index)) {
1061 GST_INFO_OBJECT(encoder, "no meta api");
1062 gst_object_unref(pool);
1063 pool = nullptr;
1064 }
1065 } else {
1066 pool = nullptr;
1067 }
1068
1069 g_return_val_if_fail(gst_venc_base_update_out_port_def(self), FALSE);
1070 if (pool == nullptr) {
1071 pool = gst_venc_base_new_shmem_pool(self, outcaps, self->output.buffer_size, self->output.buffer_cnt, FALSE);
1072 } else {
1073 gst_venc_base_update_pool(self, &pool, outcaps, self->output.buffer_size, self->output.buffer_cnt);
1074 }
1075 g_return_val_if_fail(pool != nullptr, FALSE);
1076 GST_DEBUG_OBJECT(encoder, "Pool ref %d", (reinterpret_cast<GObject*>(pool)->ref_count));
1077 if (self->outpool) {
1078 GST_DEBUG_OBJECT(encoder, "change buffer pool");
1079 gst_object_unref(self->outpool);
1080 }
1081 self->outpool = pool;
1082 gst_buffer_pool_set_active(pool, TRUE);
1083 return TRUE;
1084 }
1085
gst_venc_base_propose_allocation(GstVideoEncoder * encoder,GstQuery * query)1086 static gboolean gst_venc_base_propose_allocation(GstVideoEncoder *encoder, GstQuery *query)
1087 {
1088 GST_DEBUG_OBJECT(encoder, "Propose allocation");
1089 g_return_val_if_fail(encoder != nullptr, FALSE);
1090 g_return_val_if_fail(query != nullptr, FALSE);
1091 GstVencBase *self = GST_VENC_BASE(encoder);
1092 GstCaps *incaps = nullptr;
1093 GstVideoInfo vinfo;
1094 GstBufferPool *pool = nullptr;
1095 guint size = 0;
1096 gboolean update_pool = FALSE;
1097 guint pool_num = gst_query_get_n_allocation_pools(query);
1098 if (pool_num > 0) {
1099 update_pool = TRUE;
1100 }
1101 gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, nullptr);
1102 gst_query_add_allocation_meta(query, GST_BUFFER_TYPE_META_API_TYPE, nullptr);
1103 if (self->memtype == GST_MEMTYPE_SURFACE) {
1104 GST_INFO_OBJECT(encoder, "It is surface mem");
1105 return gst_venc_base_init_surface_mem(self, query, update_pool);
1106 }
1107 gst_video_info_init(&vinfo);
1108 gst_query_parse_allocation(query, &incaps, nullptr);
1109 if (incaps != nullptr) {
1110 gst_video_info_from_caps(&vinfo, incaps);
1111 }
1112 size = vinfo.size;
1113 pool = gst_venc_base_new_shmem_pool(self, incaps, size, self->input.buffer_cnt, TRUE);
1114 g_return_val_if_fail(pool != nullptr, FALSE);
1115 if (update_pool) {
1116 gst_query_set_nth_allocation_pool(query, 0, pool, size, self->input.buffer_cnt, self->input.buffer_cnt);
1117 } else {
1118 gst_query_add_allocation_pool(query, pool, size, self->input.buffer_cnt, self->input.buffer_cnt);
1119 }
1120 GST_DEBUG_OBJECT(encoder, "Pool ref %d", (reinterpret_cast<GObject*>(pool)->ref_count));
1121 if (self->inpool) {
1122 GST_INFO_OBJECT(encoder, "Change buffer pool");
1123 gst_object_unref(self->inpool);
1124 }
1125 self->inpool = pool;
1126 gst_buffer_pool_set_active(pool, TRUE);
1127 g_return_val_if_fail(gst_venc_base_allocate_in_buffers(self), FALSE);
1128 return TRUE;
1129 }