• 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 "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(&params, 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, &params);
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(&params);
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 }