2 * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
3 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation
8 * version 2.1 of the License.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <gst/video/gstvideometa.h>
27 #include <gst/allocators/gstdmabuf.h>
31 #include "gstomxbufferpool.h"
32 #include "gstomxvideo.h"
33 #include "gstomxvideoenc.h"
35 #ifdef USE_OMX_TARGET_RPI
36 #include <OMX_Broadcom.h>
37 #include <OMX_Index.h>
40 GST_DEBUG_CATEGORY_STATIC (gst_omx_video_enc_debug_category);
41 #define GST_CAT_DEFAULT gst_omx_video_enc_debug_category
43 #define GST_TYPE_OMX_VIDEO_ENC_CONTROL_RATE (gst_omx_video_enc_control_rate_get_type ())
45 gst_omx_video_enc_control_rate_get_type (void)
47 static GType qtype = 0;
50 static const GEnumValue values[] = {
51 {OMX_Video_ControlRateDisable, "Disable", "disable"},
52 {OMX_Video_ControlRateVariable, "Variable", "variable"},
53 {OMX_Video_ControlRateConstant, "Constant", "constant"},
54 {OMX_Video_ControlRateVariableSkipFrames, "Variable Skip Frames",
55 "variable-skip-frames"},
56 {OMX_Video_ControlRateConstantSkipFrames, "Constant Skip Frames",
57 "constant-skip-frames"},
58 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
59 {OMX_ALG_Video_ControlRateLowLatency, "Low Latency", "low-latency"},
61 {0xffffffff, "Component Default", "default"},
65 qtype = g_enum_register_static ("GstOMXVideoEncControlRate", values);
70 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
71 #define GST_TYPE_OMX_VIDEO_ENC_QP_MODE (gst_omx_video_enc_qp_mode_get_type ())
79 } GstOMXVideoEncQpMode;
83 gst_omx_video_enc_qp_mode_get_type (void)
85 static GType qtype = 0;
88 static const GEnumValue values[] = {
89 {UNIFORM_QP, "Use the same QP for all coding units of the frame",
92 "Adjust QP according to the regions of interest defined on each frame. Must be set to handle ROI metadata.",
95 "Let the VCU encoder change the QP for each coding unit according to its content",
98 "Uses absolute QP values set by user. Must be set to use External QP buffer",
101 "Uses Relative/Delta QP values set by user. Must be set to use External QP buffer",
103 {0xffffffff, "Component Default", "default"},
107 qtype = g_enum_register_static ("GstOMXVideoEncQpMode", values);
112 #define GST_TYPE_OMX_VIDEO_ENC_GOP_MODE (gst_omx_video_enc_gop_mode_get_type ())
114 gst_omx_video_enc_gop_mode_get_type (void)
116 static GType qtype = 0;
119 static const GEnumValue values[] = {
120 {OMX_ALG_GOP_MODE_DEFAULT, "Basic GOP settings", "basic"},
121 {OMX_ALG_GOP_MODE_PYRAMIDAL,
122 "Advanced GOP pattern with hierarchical B-frames", "pyramidal"},
123 {OMX_ALG_GOP_MODE_LOW_DELAY_P, "Single I-frame followed by P-frames only",
125 {OMX_ALG_GOP_MODE_LOW_DELAY_B, "Single I-frame followed by B-frames only",
127 {OMX_ALG_GOP_MODE_ADAPTIVE, "Advanced GOP pattern with adaptive B-frames",
132 qtype = g_enum_register_static ("GstOMXVideoEncGopMode", values);
137 #define GST_TYPE_OMX_VIDEO_ENC_GDR_MODE (gst_omx_video_enc_gdr_mode_get_type ())
139 gst_omx_video_enc_gdr_mode_get_type (void)
141 static GType qtype = 0;
144 static const GEnumValue values[] = {
145 {OMX_ALG_GDR_OFF, "No GDR", "disabled"},
146 {OMX_ALG_GDR_VERTICAL,
147 "Gradual refresh using a vertical bar moving from left to right",
149 {OMX_ALG_GDR_HORIZONTAL,
150 "Gradual refresh using a horizontal bar moving from top to bottom",
155 qtype = g_enum_register_static ("GstOMXVideoEncGdrMode", values);
160 #define GST_TYPE_OMX_VIDEO_ENC_SCALING_LIST (gst_omx_video_enc_scaling_list_get_type ())
162 gst_omx_video_enc_scaling_list_get_type (void)
164 static GType qtype = 0;
167 static const GEnumValue values[] = {
168 {OMX_ALG_SCL_DEFAULT, "Default scaling list mode", "default"},
169 {OMX_ALG_SCL_FLAT, "Flat scaling list mode", "flat"},
173 qtype = g_enum_register_static ("GstOMXVideoEncScalingList", values);
178 #define GST_TYPE_OMX_VIDEO_ENC_ASPECT_RATIO (gst_omx_video_enc_aspect_ratio_get_type ())
180 gst_omx_video_enc_aspect_ratio_get_type (void)
182 static GType qtype = 0;
185 static const GEnumValue values[] = {
186 {OMX_ALG_ASPECT_RATIO_AUTO,
187 "4:3 for SD video,16:9 for HD video,unspecified for unknown format",
189 {OMX_ALG_ASPECT_RATIO_4_3, "4:3 aspect ratio", "4-3"},
190 {OMX_ALG_ASPECT_RATIO_16_9, "16:9 aspect ratio", "16-9"},
191 {OMX_ALG_ASPECT_RATIO_NONE,
192 "Aspect ratio information is not present in the stream", "none"},
196 qtype = g_enum_register_static ("GstOMXVideoEncAspectRatio", values);
201 #define GST_TYPE_OMX_VIDEO_ENC_ROI_QUALITY (gst_omx_video_enc_roi_quality_type ())
203 gst_omx_video_enc_roi_quality_type (void)
205 static GType qtype = 0;
208 static const GEnumValue values[] = {
209 {OMX_ALG_ROI_QUALITY_HIGH, "Delta QP of -5", "high"},
210 {OMX_ALG_ROI_QUALITY_MEDIUM, "Delta QP of 0", "medium"},
211 {OMX_ALG_ROI_QUALITY_LOW, "Delta QP of +5", "low"},
212 {OMX_ALG_ROI_QUALITY_DONT_CARE, "Maximum delta QP value", "dont-care"},
216 qtype = g_enum_register_static ("GstOMXVideoEncRoiQuality", values);
223 static void gst_omx_video_enc_finalize (GObject * object);
224 static void gst_omx_video_enc_set_property (GObject * object, guint prop_id,
225 const GValue * value, GParamSpec * pspec);
226 static void gst_omx_video_enc_get_property (GObject * object, guint prop_id,
227 GValue * value, GParamSpec * pspec);
230 static GstStateChangeReturn
231 gst_omx_video_enc_change_state (GstElement * element,
232 GstStateChange transition);
234 static gboolean gst_omx_video_enc_open (GstVideoEncoder * encoder);
235 static gboolean gst_omx_video_enc_close (GstVideoEncoder * encoder);
236 static gboolean gst_omx_video_enc_start (GstVideoEncoder * encoder);
237 static gboolean gst_omx_video_enc_stop (GstVideoEncoder * encoder);
238 static gboolean gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
239 GstVideoCodecState * state);
240 static gboolean gst_omx_video_enc_flush (GstVideoEncoder * encoder);
241 static GstFlowReturn gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
242 GstVideoCodecFrame * frame);
243 static gboolean gst_omx_video_enc_finish (GstVideoEncoder * encoder);
244 static gboolean gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
246 static GstCaps *gst_omx_video_enc_getcaps (GstVideoEncoder * encoder,
248 static gboolean gst_omx_video_enc_decide_allocation (GstVideoEncoder * encoder,
251 static GstFlowReturn gst_omx_video_enc_drain (GstOMXVideoEnc * self);
253 static GstFlowReturn gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc *
254 self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame);
256 static gboolean gst_omx_video_enc_sink_event (GstVideoEncoder * encoder,
281 PROP_DEPENDENT_SLICE,
282 PROP_DEFAULT_ROI_QUALITY,
284 PROP_LONGTERM_FREQUENCY,
288 /* FIXME: Better defaults */
289 #define GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT (0xffffffff)
290 #define GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT (0xffffffff)
291 #define GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT (0xffffffff)
292 #define GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT (0xffffffff)
293 #define GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT (0xffffffff)
294 #define GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT (0xffffffff)
295 #define GST_OMX_VIDEO_ENC_MIN_QP_DEFAULT (10)
296 #define GST_OMX_VIDEO_ENC_MAX_QP_DEFAULT (51)
297 #define GST_OMX_VIDEO_ENC_GOP_MODE_DEFAULT (OMX_ALG_GOP_MODE_DEFAULT)
298 #define GST_OMX_VIDEO_ENC_GDR_MODE_DEFAULT (OMX_ALG_GDR_OFF)
299 #define GST_OMX_VIDEO_ENC_INITIAL_DELAY_DEFAULT (1500)
300 #define GST_OMX_VIDEO_ENC_CPB_SIZE_DEFAULT (3000)
301 #define GST_OMX_VIDEO_ENC_SCALING_LIST_DEFAULT (OMX_ALG_SCL_DEFAULT)
302 #define GST_OMX_VIDEO_ENC_LOW_BANDWIDTH_DEFAULT (FALSE)
303 #define GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT (0xffffffff)
304 #define GST_OMX_VIDEO_ENC_ASPECT_RATIO_DEFAULT (OMX_ALG_ASPECT_RATIO_AUTO)
305 #define GST_OMX_VIDEO_ENC_FILLER_DATA_DEFAULT (TRUE)
306 #define GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT (0xffffffff)
307 #define GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT (0)
308 #define GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT (FALSE)
309 #define GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY OMX_ALG_ROI_QUALITY_HIGH
310 #define GST_OMX_VIDEO_ENC_LONGTERM_REF_DEFAULT (FALSE)
311 #define GST_OMX_VIDEO_ENC_LONGTERM_FREQUENCY_DEFAULT (0)
312 #define GST_OMX_VIDEO_ENC_LOOK_AHEAD_DEFAULT (0)
314 /* ZYNQ_USCALE_PLUS encoder custom events */
315 #define OMX_ALG_GST_EVENT_INSERT_LONGTERM "omx-alg/insert-longterm"
316 #define OMX_ALG_GST_EVENT_USE_LONGTERM "omx-alg/use-longterm"
318 /* class initialization */
321 GST_DEBUG_CATEGORY_INIT (gst_omx_video_enc_debug_category, "omxvideoenc", 0, \
322 "debug category for gst-omx video encoder base class"); \
323 G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL); \
326 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoEnc, gst_omx_video_enc,
327 GST_TYPE_VIDEO_ENCODER, do_init);
330 gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass)
332 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
333 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
334 GstVideoEncoderClass *video_encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
337 gobject_class->finalize = gst_omx_video_enc_finalize;
338 gobject_class->set_property = gst_omx_video_enc_set_property;
339 gobject_class->get_property = gst_omx_video_enc_get_property;
341 g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
342 g_param_spec_enum ("control-rate", "Control Rate",
343 "Bitrate control method",
344 GST_TYPE_OMX_VIDEO_ENC_CONTROL_RATE,
345 GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT,
346 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
347 GST_PARAM_MUTABLE_READY));
349 g_object_class_install_property (gobject_class, PROP_TARGET_BITRATE,
350 g_param_spec_uint ("target-bitrate", "Target Bitrate",
351 "Target bitrate in bits per second (0xffffffff=component default)",
352 0, G_MAXUINT, GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT,
353 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
354 GST_PARAM_MUTABLE_PLAYING));
356 g_object_class_install_property (gobject_class, PROP_QUANT_I_FRAMES,
357 g_param_spec_uint ("quant-i-frames", "I-Frame Quantization",
358 "Quantization parameter for I-frames (0xffffffff=component default)",
359 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT,
360 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
361 GST_PARAM_MUTABLE_READY));
363 g_object_class_install_property (gobject_class, PROP_QUANT_P_FRAMES,
364 g_param_spec_uint ("quant-p-frames", "P-Frame Quantization",
365 "Quantization parameter for P-frames (0xffffffff=component default)",
366 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT,
367 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
368 GST_PARAM_MUTABLE_READY));
370 g_object_class_install_property (gobject_class, PROP_QUANT_B_FRAMES,
371 g_param_spec_uint ("quant-b-frames", "B-Frame Quantization",
372 "Quantization parameter for B-frames (0xffffffff=component default)",
373 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT,
374 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
375 GST_PARAM_MUTABLE_READY));
377 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
378 g_object_class_install_property (gobject_class, PROP_QP_MODE,
379 g_param_spec_enum ("qp-mode", "QP mode",
380 "QP control mode used by the VCU encoder",
381 GST_TYPE_OMX_VIDEO_ENC_QP_MODE,
382 GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT,
383 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
384 GST_PARAM_MUTABLE_READY));
386 g_object_class_install_property (gobject_class, PROP_MIN_QP,
387 g_param_spec_uint ("min-qp", "min Quantization value",
388 "Minimum QP value allowed for the rate control",
389 0, 51, GST_OMX_VIDEO_ENC_MIN_QP_DEFAULT,
390 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
391 GST_PARAM_MUTABLE_READY));
393 g_object_class_install_property (gobject_class, PROP_MAX_QP,
394 g_param_spec_uint ("max-qp", "max Quantization value",
395 "Maximum QP value allowed for the rate control",
396 0, 51, GST_OMX_VIDEO_ENC_MAX_QP_DEFAULT,
397 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
398 GST_PARAM_MUTABLE_READY));
400 g_object_class_install_property (gobject_class, PROP_GOP_MODE,
401 g_param_spec_enum ("gop-mode", "GOP mode",
402 "Group Of Pictures mode",
403 GST_TYPE_OMX_VIDEO_ENC_GOP_MODE,
404 GST_OMX_VIDEO_ENC_GOP_MODE_DEFAULT,
405 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
406 GST_PARAM_MUTABLE_READY));
408 g_object_class_install_property (gobject_class, PROP_GDR_MODE,
409 g_param_spec_enum ("gdr-mode", "GDR mode",
410 "Gradual Decoder Refresh scheme mode. Only used if gop-mode=low-delay-p",
411 GST_TYPE_OMX_VIDEO_ENC_GDR_MODE,
412 GST_OMX_VIDEO_ENC_GDR_MODE_DEFAULT,
413 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
414 GST_PARAM_MUTABLE_READY));
416 g_object_class_install_property (gobject_class, PROP_INITIAL_DELAY,
417 g_param_spec_uint ("initial-delay", "Initial Delay",
418 "The initial removal delay as specified in the HRD model in msec. "
419 "Not used when control-rate=disable",
420 0, G_MAXUINT, GST_OMX_VIDEO_ENC_INITIAL_DELAY_DEFAULT,
421 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
422 GST_PARAM_MUTABLE_READY));
424 g_object_class_install_property (gobject_class, PROP_CPB_SIZE,
425 g_param_spec_uint ("cpb-size", "CPB size",
426 "Coded Picture Buffer as specified in the HRD model in msec. "
427 "Not used when control-rate=disable",
428 0, G_MAXUINT, GST_OMX_VIDEO_ENC_CPB_SIZE_DEFAULT,
429 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
430 GST_PARAM_MUTABLE_READY));
432 g_object_class_install_property (gobject_class, PROP_SCALING_LIST,
433 g_param_spec_enum ("scaling-list", "Scaling List",
435 GST_TYPE_OMX_VIDEO_ENC_SCALING_LIST,
436 GST_OMX_VIDEO_ENC_SCALING_LIST_DEFAULT,
437 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
438 GST_PARAM_MUTABLE_READY));
440 g_object_class_install_property (gobject_class, PROP_LOW_BANDWIDTH,
441 g_param_spec_boolean ("low-bandwidth", "Low bandwidth mode",
442 "If enabled, decrease the vertical search range "
443 "used for P-frame motion estimation to reduce the bandwidth",
444 GST_OMX_VIDEO_ENC_LOW_BANDWIDTH_DEFAULT,
445 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
446 GST_PARAM_MUTABLE_READY));
448 g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
449 g_param_spec_uint ("max-bitrate", "Max Bitrate",
450 "Max bitrate in bits per second, only used if control-rate=variable (0xffffffff=component default)",
451 0, G_MAXUINT, GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT,
452 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
453 GST_PARAM_MUTABLE_READY));
455 g_object_class_install_property (gobject_class, PROP_ASPECT_RATIO,
456 g_param_spec_enum ("aspect-ratio", "Aspect ratio",
457 "Display aspect ratio of the video sequence to be written in SPS/VUI",
458 GST_TYPE_OMX_VIDEO_ENC_ASPECT_RATIO,
459 GST_OMX_VIDEO_ENC_ASPECT_RATIO_DEFAULT,
460 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
461 GST_PARAM_MUTABLE_READY));
463 g_object_class_install_property (gobject_class, PROP_FILLER_DATA,
464 g_param_spec_boolean ("filler-data", "Filler Data",
465 "Enable/Disable Filler Data NAL units for CBR rate control",
466 GST_OMX_VIDEO_ENC_FILLER_DATA_DEFAULT,
467 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
468 GST_PARAM_MUTABLE_READY));
470 g_object_class_install_property (gobject_class, PROP_NUM_SLICES,
471 g_param_spec_uint ("num-slices", "Number of slices",
472 "Number of slices produced for each frame. Each slice contains one or more complete macroblock/CTU row(s). "
473 "Slices are distributed over the frame as regularly as possible. If slice-size is defined as well more slices "
474 "may be produced to fit the slice-size requirement (0xffffffff=component default)",
475 1, G_MAXUINT, GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT,
476 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
477 GST_PARAM_MUTABLE_READY));
479 g_object_class_install_property (gobject_class, PROP_SLICE_SIZE,
480 g_param_spec_uint ("slice-size", "Target slice size",
481 "Target slice size (in bytes) that the encoder uses to "
482 "automatically split the bitstream into approximately equally-sized slices",
483 0, 65535, GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT,
484 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
485 GST_PARAM_MUTABLE_READY));
487 g_object_class_install_property (gobject_class, PROP_DEPENDENT_SLICE,
488 g_param_spec_boolean ("dependent-slice", "Dependent slice",
489 "If encoding with multiple slices, specify whether the additional slices are "
490 "dependent slice segments or regular slices",
491 GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT,
492 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
494 g_object_class_install_property (gobject_class, PROP_DEFAULT_ROI_QUALITY,
495 g_param_spec_enum ("default-roi-quality", "Default ROI Qualtiy",
496 "The default quality level to apply to each Region of Interest",
497 GST_TYPE_OMX_VIDEO_ENC_ROI_QUALITY,
498 GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY,
499 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
501 g_object_class_install_property (gobject_class, PROP_LONGTERM_REF,
502 g_param_spec_boolean ("long-term-ref", "LongTerm Reference Pictures",
503 "If enabled, encoder accepts dynamically inserting and using long-term reference "
504 "picture events from upstream elements",
505 GST_OMX_VIDEO_ENC_LONGTERM_REF_DEFAULT,
506 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
507 GST_PARAM_MUTABLE_READY));
509 g_object_class_install_property (gobject_class, PROP_LONGTERM_FREQUENCY,
510 g_param_spec_uint ("long-term-freq", "LongTerm reference frequency",
511 "Periodicity of LongTerm reference picture marking in encoding process "
512 "Units in frames, distance between two consequtive long-term reference pictures",
513 0, G_MAXUINT, GST_OMX_VIDEO_ENC_LONGTERM_REF_DEFAULT,
514 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
515 GST_PARAM_MUTABLE_READY));
517 g_object_class_install_property (gobject_class, PROP_LOOK_AHEAD,
518 g_param_spec_uint ("look-ahead", "look ahead size",
519 "The number of frames processed ahead of second pass encoding. If smaller than 2, dual pass encoding is disabled",
520 0, G_MAXUINT, GST_OMX_VIDEO_ENC_LOOK_AHEAD_DEFAULT,
521 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
522 GST_PARAM_MUTABLE_READY));
525 element_class->change_state =
526 GST_DEBUG_FUNCPTR (gst_omx_video_enc_change_state);
528 video_encoder_class->open = GST_DEBUG_FUNCPTR (gst_omx_video_enc_open);
529 video_encoder_class->close = GST_DEBUG_FUNCPTR (gst_omx_video_enc_close);
530 video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_enc_start);
531 video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_enc_stop);
532 video_encoder_class->flush = GST_DEBUG_FUNCPTR (gst_omx_video_enc_flush);
533 video_encoder_class->set_format =
534 GST_DEBUG_FUNCPTR (gst_omx_video_enc_set_format);
535 video_encoder_class->handle_frame =
536 GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_frame);
537 video_encoder_class->finish = GST_DEBUG_FUNCPTR (gst_omx_video_enc_finish);
538 video_encoder_class->propose_allocation =
539 GST_DEBUG_FUNCPTR (gst_omx_video_enc_propose_allocation);
540 video_encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_omx_video_enc_getcaps);
541 video_encoder_class->sink_event =
542 GST_DEBUG_FUNCPTR (gst_omx_video_enc_sink_event);
543 video_encoder_class->decide_allocation =
544 GST_DEBUG_FUNCPTR (gst_omx_video_enc_decide_allocation);
546 klass->cdata.type = GST_OMX_COMPONENT_TYPE_FILTER;
547 klass->cdata.default_sink_template_caps =
548 GST_VIDEO_CAPS_MAKE (GST_OMX_VIDEO_ENC_SUPPORTED_FORMATS);
550 klass->handle_output_frame =
551 GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_output_frame);
555 gst_omx_video_enc_init (GstOMXVideoEnc * self)
557 self->control_rate = GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT;
558 self->target_bitrate = GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT;
559 self->quant_i_frames = GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT;
560 self->quant_p_frames = GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT;
561 self->quant_b_frames = GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT;
562 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
563 self->qp_mode = GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT;
564 self->min_qp = GST_OMX_VIDEO_ENC_MIN_QP_DEFAULT;
565 self->max_qp = GST_OMX_VIDEO_ENC_MAX_QP_DEFAULT;
566 self->gop_mode = GST_OMX_VIDEO_ENC_GOP_MODE_DEFAULT;
567 self->gdr_mode = GST_OMX_VIDEO_ENC_GDR_MODE_DEFAULT;
568 self->initial_delay = GST_OMX_VIDEO_ENC_INITIAL_DELAY_DEFAULT;
569 self->cpb_size = GST_OMX_VIDEO_ENC_CPB_SIZE_DEFAULT;
570 self->scaling_list = GST_OMX_VIDEO_ENC_SCALING_LIST_DEFAULT;
571 self->low_bandwidth = GST_OMX_VIDEO_ENC_LOW_BANDWIDTH_DEFAULT;
572 self->max_bitrate = GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT;
573 self->aspect_ratio = GST_OMX_VIDEO_ENC_ASPECT_RATIO_DEFAULT;
574 self->filler_data = GST_OMX_VIDEO_ENC_FILLER_DATA_DEFAULT;
575 self->num_slices = GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT;
576 self->slice_size = GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT;
577 self->dependent_slice = GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT;
578 self->default_roi_quality = GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY;
579 self->long_term_ref = GST_OMX_VIDEO_ENC_LONGTERM_REF_DEFAULT;
580 self->long_term_freq = GST_OMX_VIDEO_ENC_LONGTERM_FREQUENCY_DEFAULT;
581 self->look_ahead = GST_OMX_VIDEO_ENC_LOOK_AHEAD_DEFAULT;
584 self->default_target_bitrate = GST_OMX_PROP_OMX_DEFAULT;
586 g_mutex_init (&self->drain_lock);
587 g_cond_init (&self->drain_cond);
589 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
590 self->alg_roi_quality_enum_class =
591 g_type_class_ref (GST_TYPE_OMX_VIDEO_ENC_ROI_QUALITY);
595 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
597 #define CHECK_ERR(setting) \
598 if (err == OMX_ErrorUnsupportedIndex || err == OMX_ErrorUnsupportedSetting) { \
599 GST_WARNING_OBJECT (self, \
600 "Setting " setting " parameters not supported by the component"); \
601 } else if (err != OMX_ErrorNone) { \
602 GST_ERROR_OBJECT (self, \
603 "Failed to set " setting " parameters: %s (0x%08x)", \
604 gst_omx_error_to_string (err), err); \
609 set_zynqultrascaleplus_props (GstOMXVideoEnc * self)
612 OMX_ALG_VIDEO_PARAM_QUANTIZATION_CONTROL quant;
613 OMX_ALG_VIDEO_PARAM_QUANTIZATION_TABLE quant_table;
615 if (self->qp_mode != GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT) {
616 guint32 qp_mode = OMX_ALG_QP_CTRL_NONE;
617 guint32 qp_table = OMX_ALG_QP_TABLE_NONE;
619 /* qp_mode should be mapped to combination QUANTIZATION_CONTROL & QUANTIZATION_TABLE Params */
620 switch (self->qp_mode) {
622 qp_mode = OMX_ALG_QP_CTRL_NONE;
623 qp_table = OMX_ALG_QP_TABLE_NONE;
626 qp_mode = OMX_ALG_QP_CTRL_AUTO;
627 qp_table = OMX_ALG_QP_TABLE_NONE;
630 qp_mode = OMX_ALG_QP_CTRL_NONE;
631 qp_table = OMX_ALG_QP_TABLE_RELATIVE;
633 case LOAD_QP_ABSOLUTE:
634 qp_mode = OMX_ALG_QP_CTRL_NONE;
635 qp_table = OMX_ALG_QP_TABLE_ABSOLUTE;
637 case LOAD_QP_RELATIVE:
638 qp_mode = OMX_ALG_QP_CTRL_NONE;
639 qp_table = OMX_ALG_QP_TABLE_RELATIVE;
642 GST_WARNING_OBJECT (self,
643 "Invalid option. Falling back to Uniform mode");
647 GST_OMX_INIT_STRUCT (&quant);
648 quant.nPortIndex = self->enc_out_port->index;
649 quant.eQpControlMode = qp_mode;
651 GST_DEBUG_OBJECT (self, "setting QP mode to %d", qp_mode);
654 gst_omx_component_set_parameter (self->enc,
655 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoQuantizationControl, &quant);
656 CHECK_ERR ("quantization");
658 GST_OMX_INIT_STRUCT (&quant_table);
659 quant_table.nPortIndex = self->enc_out_port->index;
660 quant_table.eQpTableMode = qp_table;
662 GST_DEBUG_OBJECT (self, "setting QP Table Mode to %d", qp_table);
665 gst_omx_component_set_parameter (self->enc,
666 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoQuantizationTable, &quant_table);
667 CHECK_ERR ("quantization table");
671 OMX_ALG_VIDEO_PARAM_QUANTIZATION_EXTENSION qp_values;
673 GST_OMX_INIT_STRUCT (&qp_values);
674 qp_values.nPortIndex = self->enc_out_port->index;
675 qp_values.nQpMin = self->min_qp;
676 qp_values.nQpMax = self->max_qp;
678 GST_DEBUG_OBJECT (self, "setting min QP as %d and max QP as %d",
679 self->min_qp, self->max_qp);
682 gst_omx_component_set_parameter (self->enc,
683 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoQuantizationExtension,
685 CHECK_ERR ("min-qp and max-qp");
689 OMX_ALG_VIDEO_PARAM_GOP_CONTROL gop_mode;
691 if (self->gdr_mode != OMX_ALG_GDR_OFF &&
692 self->gop_mode != OMX_ALG_GOP_MODE_LOW_DELAY_P) {
693 GST_ERROR_OBJECT (self,
694 "gdr-mode mode only can be set if gop-mode=low-delay-p");
698 GST_OMX_INIT_STRUCT (&gop_mode);
699 gop_mode.nPortIndex = self->enc_out_port->index;
700 gop_mode.eGopControlMode = self->gop_mode;
701 gop_mode.eGdrMode = self->gdr_mode;
703 GST_DEBUG_OBJECT (self, "setting GOP mode to %d and GDR mode to %d",
704 self->gop_mode, self->gdr_mode);
707 gst_omx_component_set_parameter (self->enc,
708 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoGopControl, &gop_mode);
709 CHECK_ERR ("GOP & GDR");
712 if (self->control_rate != OMX_Video_ControlRateDisable) {
713 if (self->cpb_size < self->initial_delay) {
714 GST_ERROR_OBJECT (self,
715 "cpb-size (%d) cannot be smaller than initial-delay (%d)",
716 self->cpb_size, self->initial_delay);
717 g_critical ("cpb-size (%d) cannot be smaller than initial-delay (%d)",
718 self->cpb_size, self->initial_delay);
720 OMX_ALG_VIDEO_PARAM_CODED_PICTURE_BUFFER cpb;
722 GST_OMX_INIT_STRUCT (&cpb);
723 cpb.nPortIndex = self->enc_out_port->index;
724 cpb.nCodedPictureBufferSize = self->cpb_size;
725 cpb.nInitialRemovalDelay = self->initial_delay;
727 GST_DEBUG_OBJECT (self, "setting cpb size to %d and initial delay to %d",
728 self->cpb_size, self->initial_delay);
731 gst_omx_component_set_parameter (self->enc,
732 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoCodedPictureBuffer, &cpb);
733 CHECK_ERR ("cpb size & initial delay");
738 OMX_ALG_VIDEO_PARAM_SCALING_LIST scaling_list;
740 GST_OMX_INIT_STRUCT (&scaling_list);
741 scaling_list.nPortIndex = self->enc_out_port->index;
742 scaling_list.eScalingListMode = self->scaling_list;
744 GST_DEBUG_OBJECT (self, "setting scaling list mode as %d",
748 gst_omx_component_set_parameter (self->enc,
749 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoScalingList, &scaling_list);
750 CHECK_ERR ("scaling-list");
754 OMX_ALG_VIDEO_PARAM_LOW_BANDWIDTH low_bw;
756 GST_OMX_INIT_STRUCT (&low_bw);
757 low_bw.nPortIndex = self->enc_out_port->index;
758 low_bw.bEnableLowBandwidth = self->low_bandwidth;
760 GST_DEBUG_OBJECT (self, "%s low bandwith moded",
761 self->low_bandwidth ? "Enable" : "Disable");
764 gst_omx_component_set_parameter (self->enc,
765 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoLowBandwidth, &low_bw);
766 CHECK_ERR ("low-bandwidth");
769 if (self->max_bitrate != GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT) {
770 OMX_ALG_VIDEO_PARAM_MAX_BITRATE max_bitrate;
772 GST_OMX_INIT_STRUCT (&max_bitrate);
773 max_bitrate.nPortIndex = self->enc_out_port->index;
774 /* nMaxBitrate is in kbps while max-bitrate is in bps */
775 max_bitrate.nMaxBitrate = self->max_bitrate / 1000;
777 GST_DEBUG_OBJECT (self, "setting max bitrate to %d", self->max_bitrate);
780 gst_omx_component_set_parameter (self->enc,
781 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoMaxBitrate, &max_bitrate);
782 CHECK_ERR ("max-bitrate");
786 OMX_ALG_VIDEO_PARAM_ASPECT_RATIO aspect_ratio;
788 GST_OMX_INIT_STRUCT (&aspect_ratio);
789 aspect_ratio.nPortIndex = self->enc_out_port->index;
790 aspect_ratio.eAspectRatio = self->aspect_ratio;
792 GST_DEBUG_OBJECT (self, "setting aspect ratio to %d", self->aspect_ratio);
795 gst_omx_component_set_parameter (self->enc,
796 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoAspectRatio, &aspect_ratio);
797 CHECK_ERR ("aspect-ratio");
801 OMX_ALG_VIDEO_PARAM_FILLER_DATA filler_data;
803 GST_OMX_INIT_STRUCT (&filler_data);
804 filler_data.nPortIndex = self->enc_out_port->index;
805 filler_data.bDisableFillerData = !(self->filler_data);
807 GST_DEBUG_OBJECT (self, "%s filler data",
808 self->filler_data ? "Enable" : "Disable");
811 gst_omx_component_set_parameter (self->enc,
812 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoFillerData, &filler_data);
813 CHECK_ERR ("filler-data");
816 if (self->num_slices != GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT ||
817 self->slice_size != GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT) {
818 OMX_ALG_VIDEO_PARAM_SLICES slices;
820 GST_OMX_INIT_STRUCT (&slices);
821 slices.nPortIndex = self->enc_out_port->index;
823 err = gst_omx_component_get_parameter (self->enc,
824 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoSlices, &slices);
825 if (err != OMX_ErrorNone) {
826 GST_WARNING_OBJECT (self, "Error getting slice parameters: %s (0x%08x)",
827 gst_omx_error_to_string (err), err);
831 if (self->num_slices != GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT) {
832 slices.nNumSlices = self->num_slices;
833 GST_DEBUG_OBJECT (self,
834 "setting number of slices to %d (dependent slices: %d)",
835 self->num_slices, self->dependent_slice);
838 if (self->slice_size != GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT) {
839 slices.nSlicesSize = self->slice_size;
840 GST_DEBUG_OBJECT (self, "setting slice size to %d (dependent slices: %d)",
841 self->slice_size, self->dependent_slice);
844 slices.bDependentSlices = self->dependent_slice;
847 gst_omx_component_set_parameter (self->enc,
848 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoSlices, &slices);
849 CHECK_ERR ("slices");
853 OMX_ALG_VIDEO_PARAM_LONG_TERM longterm;
854 GST_OMX_INIT_STRUCT (&longterm);
855 longterm.nPortIndex = self->enc_out_port->index;
856 longterm.bEnableLongTerm = self->long_term_ref;
857 longterm.nLongTermFrequency = self->long_term_freq;
859 GST_DEBUG_OBJECT (self, "setting long-term ref to %d, long-term-freq to %d",
860 self->long_term_ref, self->long_term_freq);
863 gst_omx_component_set_parameter (self->enc,
864 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoLongTerm, &longterm);
865 CHECK_ERR ("longterm");
869 OMX_ALG_VIDEO_PARAM_LOOKAHEAD look_ahead;
871 GST_OMX_INIT_STRUCT (&look_ahead);
872 look_ahead.nPortIndex = self->enc_in_port->index;
873 look_ahead.nLookAhead = self->look_ahead;
875 GST_DEBUG_OBJECT (self, "setting look_ahead to %d", self->look_ahead);
878 gst_omx_component_set_parameter (self->enc,
879 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoLookAhead, &look_ahead);
880 CHECK_ERR ("look-ahead");
888 gst_omx_video_enc_set_bitrate (GstOMXVideoEnc * self)
891 OMX_VIDEO_PARAM_BITRATETYPE bitrate_param;
892 gboolean result = TRUE;
894 GST_OBJECT_LOCK (self);
896 GST_OMX_INIT_STRUCT (&bitrate_param);
897 bitrate_param.nPortIndex = self->enc_out_port->index;
899 err = gst_omx_component_get_parameter (self->enc,
900 OMX_IndexParamVideoBitrate, &bitrate_param);
902 if (err == OMX_ErrorNone) {
903 #ifdef USE_OMX_TARGET_RPI
904 /* FIXME: Workaround for RPi returning garbage for this parameter */
905 if (bitrate_param.nVersion.nVersion == 0) {
906 GST_OMX_INIT_STRUCT (&bitrate_param);
907 bitrate_param.nPortIndex = self->enc_out_port->index;
910 if (self->default_target_bitrate == GST_OMX_PROP_OMX_DEFAULT)
911 /* Save the actual OMX default so we can restore it if needed */
912 self->default_target_bitrate = bitrate_param.nTargetBitrate;
914 if (self->control_rate != 0xffffffff)
915 bitrate_param.eControlRate = self->control_rate;
916 if (self->target_bitrate != 0xffffffff)
917 bitrate_param.nTargetBitrate = self->target_bitrate;
919 bitrate_param.nTargetBitrate = self->default_target_bitrate;
922 gst_omx_component_set_parameter (self->enc,
923 OMX_IndexParamVideoBitrate, &bitrate_param);
924 if (err == OMX_ErrorUnsupportedIndex) {
925 GST_WARNING_OBJECT (self,
926 "Setting a bitrate not supported by the component");
927 } else if (err == OMX_ErrorUnsupportedSetting) {
928 GST_WARNING_OBJECT (self,
929 "Setting bitrate settings %u %u not supported by the component",
930 self->control_rate, self->target_bitrate);
931 } else if (err != OMX_ErrorNone) {
932 GST_ERROR_OBJECT (self,
933 "Failed to set bitrate parameters: %s (0x%08x)",
934 gst_omx_error_to_string (err), err);
938 GST_ERROR_OBJECT (self, "Failed to get bitrate parameters: %s (0x%08x)",
939 gst_omx_error_to_string (err), err);
942 GST_OBJECT_UNLOCK (self);
947 gst_omx_video_enc_open (GstVideoEncoder * encoder)
949 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
950 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
951 gint in_port_index, out_port_index;
954 gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
955 klass->cdata.component_name, klass->cdata.component_role,
957 self->started = FALSE;
962 if (gst_omx_component_get_state (self->enc,
963 GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
966 in_port_index = klass->cdata.in_port_index;
967 out_port_index = klass->cdata.out_port_index;
969 if (in_port_index == -1 || out_port_index == -1) {
970 OMX_PORT_PARAM_TYPE param;
973 GST_OMX_INIT_STRUCT (¶m);
976 gst_omx_component_get_parameter (self->enc, OMX_IndexParamVideoInit,
978 if (err != OMX_ErrorNone) {
979 GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
980 gst_omx_error_to_string (err), err);
985 GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
986 (guint) param.nPorts, (guint) param.nStartPortNumber);
987 in_port_index = param.nStartPortNumber + 0;
988 out_port_index = param.nStartPortNumber + 1;
992 self->enc_in_port = gst_omx_component_add_port (self->enc, in_port_index);
993 self->enc_out_port = gst_omx_component_add_port (self->enc, out_port_index);
995 if (!self->enc_in_port || !self->enc_out_port)
1002 if (!gst_omx_video_enc_set_bitrate (self))
1005 if (self->quant_i_frames != 0xffffffff ||
1006 self->quant_p_frames != 0xffffffff ||
1007 self->quant_b_frames != 0xffffffff) {
1008 OMX_VIDEO_PARAM_QUANTIZATIONTYPE quant_param;
1010 GST_OMX_INIT_STRUCT (&quant_param);
1011 quant_param.nPortIndex = self->enc_out_port->index;
1013 err = gst_omx_component_get_parameter (self->enc,
1014 OMX_IndexParamVideoQuantization, &quant_param);
1016 if (err == OMX_ErrorNone) {
1018 if (self->quant_i_frames != 0xffffffff)
1019 quant_param.nQpI = self->quant_i_frames;
1020 if (self->quant_p_frames != 0xffffffff)
1021 quant_param.nQpP = self->quant_p_frames;
1022 if (self->quant_b_frames != 0xffffffff)
1023 quant_param.nQpB = self->quant_b_frames;
1026 gst_omx_component_set_parameter (self->enc,
1027 OMX_IndexParamVideoQuantization, &quant_param);
1028 if (err == OMX_ErrorUnsupportedIndex) {
1029 GST_WARNING_OBJECT (self,
1030 "Setting quantization parameters not supported by the component");
1031 } else if (err == OMX_ErrorUnsupportedSetting) {
1032 GST_WARNING_OBJECT (self,
1033 "Setting quantization parameters %u %u %u not supported by the component",
1034 self->quant_i_frames, self->quant_p_frames, self->quant_b_frames);
1035 } else if (err != OMX_ErrorNone) {
1036 GST_ERROR_OBJECT (self,
1037 "Failed to set quantization parameters: %s (0x%08x)",
1038 gst_omx_error_to_string (err), err);
1042 GST_ERROR_OBJECT (self,
1043 "Failed to get quantization parameters: %s (0x%08x)",
1044 gst_omx_error_to_string (err), err);
1049 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1050 if (!set_zynqultrascaleplus_props (self))
1058 gst_omx_video_enc_deallocate_in_buffers (GstOMXVideoEnc * self)
1060 /* Pool will take care of deallocating buffers when deactivated upstream */
1061 if (!self->in_pool_used
1062 && gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1069 gst_omx_video_enc_shutdown (GstOMXVideoEnc * self)
1071 OMX_STATETYPE state;
1073 GST_DEBUG_OBJECT (self, "Shutting down encoder");
1075 state = gst_omx_component_get_state (self->enc, 0);
1076 if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
1077 if (state > OMX_StateIdle) {
1078 gst_omx_component_set_state (self->enc, OMX_StateIdle);
1079 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
1081 gst_omx_component_set_state (self->enc, OMX_StateLoaded);
1082 gst_omx_video_enc_deallocate_in_buffers (self);
1083 gst_omx_port_deallocate_buffers (self->enc_out_port);
1084 if (state > OMX_StateLoaded)
1085 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
1092 gst_omx_video_enc_close (GstVideoEncoder * encoder)
1094 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
1096 GST_DEBUG_OBJECT (self, "Closing encoder");
1098 if (!gst_omx_video_enc_shutdown (self))
1101 self->enc_in_port = NULL;
1102 self->enc_out_port = NULL;
1104 gst_omx_component_unref (self->enc);
1107 self->started = FALSE;
1113 gst_omx_video_enc_finalize (GObject * object)
1115 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
1117 g_mutex_clear (&self->drain_lock);
1118 g_cond_clear (&self->drain_cond);
1120 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1121 g_clear_pointer (&self->alg_roi_quality_enum_class, g_type_class_unref);
1124 G_OBJECT_CLASS (gst_omx_video_enc_parent_class)->finalize (object);
1128 gst_omx_video_enc_set_property (GObject * object, guint prop_id,
1129 const GValue * value, GParamSpec * pspec)
1131 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
1134 case PROP_CONTROL_RATE:
1135 self->control_rate = g_value_get_enum (value);
1137 case PROP_TARGET_BITRATE:
1138 GST_OBJECT_LOCK (self);
1139 self->target_bitrate = g_value_get_uint (value);
1141 OMX_VIDEO_CONFIG_BITRATETYPE config;
1144 GST_OMX_INIT_STRUCT (&config);
1145 config.nPortIndex = self->enc_out_port->index;
1146 config.nEncodeBitrate = self->target_bitrate;
1148 gst_omx_component_set_config (self->enc,
1149 OMX_IndexConfigVideoBitrate, &config);
1150 if (err != OMX_ErrorNone)
1151 GST_ERROR_OBJECT (self,
1152 "Failed to set bitrate parameter: %s (0x%08x)",
1153 gst_omx_error_to_string (err), err);
1155 GST_OBJECT_UNLOCK (self);
1157 case PROP_QUANT_I_FRAMES:
1158 self->quant_i_frames = g_value_get_uint (value);
1160 case PROP_QUANT_P_FRAMES:
1161 self->quant_p_frames = g_value_get_uint (value);
1163 case PROP_QUANT_B_FRAMES:
1164 self->quant_b_frames = g_value_get_uint (value);
1166 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1168 self->qp_mode = g_value_get_enum (value);
1171 self->min_qp = g_value_get_uint (value);
1174 self->max_qp = g_value_get_uint (value);
1177 self->gop_mode = g_value_get_enum (value);
1180 self->gdr_mode = g_value_get_enum (value);
1182 case PROP_INITIAL_DELAY:
1183 self->initial_delay = g_value_get_uint (value);
1186 self->cpb_size = g_value_get_uint (value);
1188 case PROP_SCALING_LIST:
1189 self->scaling_list = g_value_get_enum (value);
1191 case PROP_LOW_BANDWIDTH:
1192 self->low_bandwidth = g_value_get_boolean (value);
1194 case PROP_MAX_BITRATE:
1195 self->max_bitrate = g_value_get_uint (value);
1197 case PROP_ASPECT_RATIO:
1198 self->aspect_ratio = g_value_get_enum (value);
1200 case PROP_FILLER_DATA:
1201 self->filler_data = g_value_get_boolean (value);
1203 case PROP_NUM_SLICES:
1204 self->num_slices = g_value_get_uint (value);
1206 case PROP_SLICE_SIZE:
1207 self->slice_size = g_value_get_uint (value);
1209 case PROP_DEPENDENT_SLICE:
1210 self->dependent_slice = g_value_get_boolean (value);
1212 case PROP_DEFAULT_ROI_QUALITY:
1213 self->default_roi_quality = g_value_get_enum (value);
1215 case PROP_LONGTERM_REF:
1216 self->long_term_ref = g_value_get_boolean (value);
1218 case PROP_LONGTERM_FREQUENCY:
1219 self->long_term_freq = g_value_get_uint (value);
1221 case PROP_LOOK_AHEAD:
1222 self->look_ahead = g_value_get_uint (value);
1226 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1232 gst_omx_video_enc_get_property (GObject * object, guint prop_id, GValue * value,
1235 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
1238 case PROP_CONTROL_RATE:
1239 g_value_set_enum (value, self->control_rate);
1241 case PROP_TARGET_BITRATE:
1242 GST_OBJECT_LOCK (self);
1243 g_value_set_uint (value, self->target_bitrate);
1244 GST_OBJECT_UNLOCK (self);
1246 case PROP_QUANT_I_FRAMES:
1247 g_value_set_uint (value, self->quant_i_frames);
1249 case PROP_QUANT_P_FRAMES:
1250 g_value_set_uint (value, self->quant_p_frames);
1252 case PROP_QUANT_B_FRAMES:
1253 g_value_set_uint (value, self->quant_b_frames);
1255 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1257 g_value_set_enum (value, self->qp_mode);
1260 g_value_set_uint (value, self->min_qp);
1263 g_value_set_uint (value, self->max_qp);
1266 g_value_set_enum (value, self->gop_mode);
1269 g_value_set_enum (value, self->gdr_mode);
1271 case PROP_INITIAL_DELAY:
1272 g_value_set_uint (value, self->initial_delay);
1275 g_value_set_uint (value, self->cpb_size);
1277 case PROP_SCALING_LIST:
1278 g_value_set_enum (value, self->scaling_list);
1280 case PROP_LOW_BANDWIDTH:
1281 g_value_set_boolean (value, self->low_bandwidth);
1283 case PROP_MAX_BITRATE:
1284 g_value_set_uint (value, self->max_bitrate);
1286 case PROP_ASPECT_RATIO:
1287 g_value_set_enum (value, self->aspect_ratio);
1289 case PROP_FILLER_DATA:
1290 g_value_set_boolean (value, self->filler_data);
1292 case PROP_NUM_SLICES:
1293 g_value_set_uint (value, self->num_slices);
1295 case PROP_SLICE_SIZE:
1296 g_value_set_uint (value, self->slice_size);
1298 case PROP_DEPENDENT_SLICE:
1299 g_value_set_boolean (value, self->dependent_slice);
1301 case PROP_DEFAULT_ROI_QUALITY:
1302 g_value_set_enum (value, self->default_roi_quality);
1304 case PROP_LONGTERM_REF:
1305 g_value_set_boolean (value, self->long_term_ref);
1307 case PROP_LONGTERM_FREQUENCY:
1308 g_value_set_uint (value, self->long_term_freq);
1310 case PROP_LOOK_AHEAD:
1311 g_value_set_uint (value, self->look_ahead);
1315 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1320 static GstStateChangeReturn
1321 gst_omx_video_enc_change_state (GstElement * element, GstStateChange transition)
1323 GstOMXVideoEnc *self;
1324 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1326 g_return_val_if_fail (GST_IS_OMX_VIDEO_ENC (element),
1327 GST_STATE_CHANGE_FAILURE);
1328 self = GST_OMX_VIDEO_ENC (element);
1330 switch (transition) {
1331 case GST_STATE_CHANGE_NULL_TO_READY:
1333 case GST_STATE_CHANGE_READY_TO_PAUSED:
1334 self->downstream_flow_ret = GST_FLOW_OK;
1336 self->draining = FALSE;
1337 self->started = FALSE;
1339 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1341 case GST_STATE_CHANGE_PAUSED_TO_READY:
1342 if (self->enc_in_port)
1343 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
1344 if (self->enc_out_port)
1345 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1347 g_mutex_lock (&self->drain_lock);
1348 self->draining = FALSE;
1349 g_cond_broadcast (&self->drain_cond);
1350 g_mutex_unlock (&self->drain_lock);
1356 if (ret == GST_STATE_CHANGE_FAILURE)
1360 GST_ELEMENT_CLASS (gst_omx_video_enc_parent_class)->change_state (element,
1363 if (ret == GST_STATE_CHANGE_FAILURE)
1366 switch (transition) {
1367 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1369 case GST_STATE_CHANGE_PAUSED_TO_READY:
1370 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1371 self->started = FALSE;
1373 case GST_STATE_CHANGE_READY_TO_NULL:
1383 get_chroma_info_from_input (GstOMXVideoEnc * self, const gchar ** chroma_format,
1384 guint * bit_depth_luma, guint * bit_depth_chroma)
1386 switch (self->input_state->info.finfo->format) {
1387 case GST_VIDEO_FORMAT_GRAY8:
1388 *chroma_format = "4:0:0";
1389 *bit_depth_luma = 8;
1390 *bit_depth_chroma = 0;
1392 case GST_VIDEO_FORMAT_I420:
1393 case GST_VIDEO_FORMAT_NV12:
1394 *chroma_format = "4:2:0";
1395 *bit_depth_luma = *bit_depth_chroma = 8;
1397 case GST_VIDEO_FORMAT_NV16:
1398 case GST_VIDEO_FORMAT_YUY2:
1399 case GST_VIDEO_FORMAT_YVYU:
1400 case GST_VIDEO_FORMAT_UYVY:
1401 *chroma_format = "4:2:2";
1402 *bit_depth_luma = *bit_depth_chroma = 8;
1404 case GST_VIDEO_FORMAT_GRAY10_LE32:
1405 *chroma_format = "4:0:0";
1406 *bit_depth_luma = 10;
1407 *bit_depth_chroma = 0;
1409 case GST_VIDEO_FORMAT_NV12_10LE32:
1410 *chroma_format = "4:2:0";
1411 *bit_depth_luma = *bit_depth_chroma = 10;
1413 case GST_VIDEO_FORMAT_NV16_10LE32:
1414 *chroma_format = "4:2:2";
1415 *bit_depth_luma = *bit_depth_chroma = 10;
1425 get_output_caps (GstOMXVideoEnc * self)
1427 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1429 const gchar *chroma_format;
1430 guint bit_depth_luma, bit_depth_chroma;
1432 caps = klass->get_caps (self, self->enc_out_port, self->input_state);
1434 /* Add chroma info about the encoded stream inferred from the format of the input */
1435 if (get_chroma_info_from_input (self, &chroma_format, &bit_depth_luma,
1436 &bit_depth_chroma)) {
1437 GST_DEBUG_OBJECT (self,
1438 "adding chroma info to output caps: %s (luma %d bits) (chroma %d bits)",
1439 chroma_format, bit_depth_luma, bit_depth_chroma);
1441 gst_caps_set_simple (caps, "chroma-format", G_TYPE_STRING, chroma_format,
1442 "bit-depth-luma", G_TYPE_UINT, bit_depth_luma,
1443 "bit-depth-chroma", G_TYPE_UINT, bit_depth_chroma, NULL);
1449 static GstFlowReturn
1450 gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port,
1451 GstOMXBuffer * buf, GstVideoCodecFrame * frame)
1453 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1454 GstFlowReturn flow_ret = GST_FLOW_OK;
1456 if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG)
1457 && buf->omx_buf->nFilledLen > 0) {
1458 GstVideoCodecState *state;
1459 GstBuffer *codec_data;
1460 GstMapInfo map = GST_MAP_INFO_INIT;
1463 GST_DEBUG_OBJECT (self, "Handling codec data");
1465 caps = get_output_caps (self);
1466 codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
1468 gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
1470 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
1471 buf->omx_buf->nFilledLen);
1472 gst_buffer_unmap (codec_data, &map);
1474 gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
1476 state->codec_data = codec_data;
1477 gst_video_codec_state_unref (state);
1478 if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) {
1479 gst_video_codec_frame_unref (frame);
1480 GST_ERROR_OBJECT (self,
1481 "Downstream element refused to negotiate codec_data in the caps");
1482 return GST_FLOW_NOT_NEGOTIATED;
1484 gst_video_codec_frame_unref (frame);
1485 flow_ret = GST_FLOW_OK;
1486 } else if (buf->omx_buf->nFilledLen > 0) {
1488 GstMapInfo map = GST_MAP_INFO_INIT;
1490 GST_DEBUG_OBJECT (self, "Handling output data");
1492 outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
1494 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
1496 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
1497 buf->omx_buf->nFilledLen);
1498 gst_buffer_unmap (outbuf, &map);
1500 GST_BUFFER_TIMESTAMP (outbuf) =
1501 gst_util_uint64_scale (GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp),
1502 GST_SECOND, OMX_TICKS_PER_SECOND);
1503 if (buf->omx_buf->nTickCount != 0)
1504 GST_BUFFER_DURATION (outbuf) =
1505 gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND,
1506 OMX_TICKS_PER_SECOND);
1508 if ((klass->cdata.hacks & GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED)
1509 || (buf->omx_buf->nFlags & OMX_BUFFERFLAG_SYNCFRAME)) {
1511 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1513 GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1516 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
1518 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1522 frame->output_buffer = outbuf;
1523 if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_ENDOFFRAME)
1524 || !gst_omx_port_get_subframe (self->enc_out_port)) {
1526 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
1527 if (!(buf->omx_buf->nFlags & OMX_BUFFERFLAG_ENDOFFRAME))
1528 GST_WARNING_OBJECT (self,
1529 "OMX_BUFFERFLAG_ENDOFFRAME is missing in flags 0x%x",
1530 (guint) buf->omx_buf->nFlags);
1533 gst_video_encoder_finish_subframe (GST_VIDEO_ENCODER (self), frame);
1534 gst_video_codec_frame_unref (frame);
1537 GST_ERROR_OBJECT (self, "No corresponding frame found");
1538 flow_ret = gst_pad_push (GST_VIDEO_ENCODER_SRC_PAD (self), outbuf);
1540 } else if (frame != NULL) {
1541 /* Just ignore empty buffers, don't drop a frame for that */
1542 flow_ret = GST_FLOW_OK;
1543 gst_video_codec_frame_unref (frame);
1550 gst_omx_video_enc_ensure_nb_out_buffers (GstOMXVideoEnc * self)
1552 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1555 if (!(klass->cdata.hacks & GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL))
1558 /* If dowstream tell us how many buffers it needs allocate as many extra buffers so we won't starve
1559 * if it keeps them downstream (like when using dynamic mode). */
1560 if (self->nb_downstream_buffers)
1561 extra = self->nb_downstream_buffers;
1563 if (!gst_omx_port_ensure_buffer_count_actual (self->enc_out_port, extra))
1570 gst_omx_video_enc_allocate_out_buffers (GstOMXVideoEnc * self)
1572 if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1579 gst_omx_video_enc_pause_loop (GstOMXVideoEnc * self, GstFlowReturn flow_ret)
1581 g_mutex_lock (&self->drain_lock);
1582 if (self->draining) {
1583 self->draining = FALSE;
1584 g_cond_broadcast (&self->drain_cond);
1586 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1587 self->downstream_flow_ret = flow_ret;
1588 self->started = FALSE;
1589 g_mutex_unlock (&self->drain_lock);
1593 gst_omx_video_enc_loop (GstOMXVideoEnc * self)
1595 GstOMXVideoEncClass *klass;
1596 GstOMXPort *port = self->enc_out_port;
1597 GstOMXBuffer *buf = NULL;
1598 GstVideoCodecFrame *frame;
1599 GstFlowReturn flow_ret = GST_FLOW_OK;
1600 GstOMXAcquireBufferReturn acq_return;
1603 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1605 acq_return = gst_omx_port_acquire_buffer (port, &buf, GST_OMX_WAIT);
1606 if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
1607 goto component_error;
1608 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
1610 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) {
1614 if (!gst_pad_has_current_caps (GST_VIDEO_ENCODER_SRC_PAD (self))
1615 || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1617 GstVideoCodecState *state;
1619 GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");
1621 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE
1622 && gst_omx_port_is_enabled (port)) {
1623 /* Reallocate all buffers */
1624 err = gst_omx_port_set_enabled (port, FALSE);
1625 if (err != OMX_ErrorNone)
1626 goto reconfigure_error;
1628 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
1629 if (err != OMX_ErrorNone)
1630 goto reconfigure_error;
1632 err = gst_omx_port_deallocate_buffers (port);
1633 if (err != OMX_ErrorNone)
1634 goto reconfigure_error;
1636 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
1637 if (err != OMX_ErrorNone)
1638 goto reconfigure_error;
1641 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1643 caps = get_output_caps (self);
1646 gst_omx_port_release_buffer (self->enc_out_port, buf);
1647 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1651 GST_DEBUG_OBJECT (self, "Setting output state: %" GST_PTR_FORMAT, caps);
1654 gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
1656 gst_video_codec_state_unref (state);
1658 if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) {
1660 gst_omx_port_release_buffer (self->enc_out_port, buf);
1661 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1665 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1667 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1668 if (!gst_omx_video_enc_ensure_nb_out_buffers (self))
1669 goto reconfigure_error;
1671 err = gst_omx_port_set_enabled (port, TRUE);
1672 if (err != OMX_ErrorNone)
1673 goto reconfigure_error;
1675 if (!gst_omx_video_enc_allocate_out_buffers (self))
1676 goto reconfigure_error;
1678 err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
1679 if (err != OMX_ErrorNone)
1680 goto reconfigure_error;
1682 err = gst_omx_port_populate (port);
1683 if (err != OMX_ErrorNone)
1684 goto reconfigure_error;
1686 err = gst_omx_port_mark_reconfigured (port);
1687 if (err != OMX_ErrorNone)
1688 goto reconfigure_error;
1691 /* Now get a buffer */
1692 if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) {
1697 g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
1699 /* This prevents a deadlock between the srcpad stream
1700 * lock and the videocodec stream lock, if ::flush()
1701 * is called at the wrong time
1703 if (gst_omx_port_is_flushing (self->enc_out_port)) {
1704 GST_DEBUG_OBJECT (self, "Flushing");
1705 gst_omx_port_release_buffer (self->enc_out_port, buf);
1709 GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x (%s) %" G_GUINT64_FORMAT,
1710 (guint) buf->omx_buf->nFlags,
1711 gst_omx_buffer_flags_to_string (buf->omx_buf->nFlags),
1712 (guint64) GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp));
1714 frame = gst_omx_video_find_nearest_frame (GST_ELEMENT_CAST (self), buf,
1715 gst_video_encoder_get_frames (GST_VIDEO_ENCODER (self)));
1717 g_assert (klass->handle_output_frame);
1721 klass->handle_output_frame (self, self->enc_out_port, buf, frame);
1723 gst_omx_port_release_buffer (self->enc_out_port, buf);
1728 GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
1730 err = gst_omx_port_release_buffer (port, buf);
1731 if (err != OMX_ErrorNone)
1734 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1735 self->downstream_flow_ret = flow_ret;
1736 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1738 GST_DEBUG_OBJECT (self, "Read frame from component");
1740 if (flow_ret != GST_FLOW_OK)
1747 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1748 ("OpenMAX component in error state %s (0x%08x)",
1749 gst_omx_component_get_last_error_string (self->enc),
1750 gst_omx_component_get_last_error (self->enc)));
1751 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1752 gst_omx_video_enc_pause_loop (self, GST_FLOW_ERROR);
1757 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1758 gst_omx_video_enc_pause_loop (self, GST_FLOW_FLUSHING);
1764 g_mutex_lock (&self->drain_lock);
1765 if (self->draining) {
1766 GST_DEBUG_OBJECT (self, "Drained");
1767 self->draining = FALSE;
1768 g_cond_broadcast (&self->drain_cond);
1769 flow_ret = GST_FLOW_OK;
1770 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1772 GST_DEBUG_OBJECT (self, "Component signalled EOS");
1773 flow_ret = GST_FLOW_EOS;
1775 g_mutex_unlock (&self->drain_lock);
1777 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1778 self->downstream_flow_ret = flow_ret;
1779 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1781 /* Here we fallback and pause the task for the EOS case */
1782 if (flow_ret != GST_FLOW_OK)
1789 if (flow_ret == GST_FLOW_EOS) {
1790 GST_DEBUG_OBJECT (self, "EOS");
1792 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
1793 gst_event_new_eos ());
1794 } else if (flow_ret < GST_FLOW_EOS) {
1795 GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."),
1796 ("stream stopped, reason %s", gst_flow_get_name (flow_ret)));
1798 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
1799 gst_event_new_eos ());
1800 } else if (flow_ret == GST_FLOW_FLUSHING) {
1801 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1803 gst_omx_video_enc_pause_loop (self, flow_ret);
1808 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1809 ("Unable to reconfigure output port"));
1810 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1811 gst_omx_video_enc_pause_loop (self, GST_FLOW_NOT_NEGOTIATED);
1816 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps"));
1817 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1818 gst_omx_video_enc_pause_loop (self, GST_FLOW_NOT_NEGOTIATED);
1823 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1824 ("Failed to relase output buffer to component: %s (0x%08x)",
1825 gst_omx_error_to_string (err), err));
1826 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1827 gst_omx_video_enc_pause_loop (self, GST_FLOW_ERROR);
1833 gst_omx_video_enc_start (GstVideoEncoder * encoder)
1835 GstOMXVideoEnc *self;
1837 self = GST_OMX_VIDEO_ENC (encoder);
1839 self->last_upstream_ts = 0;
1840 self->downstream_flow_ret = GST_FLOW_OK;
1841 self->nb_downstream_buffers = 0;
1842 self->in_pool_used = FALSE;
1848 gst_omx_video_enc_stop (GstVideoEncoder * encoder)
1850 GstOMXVideoEnc *self;
1852 self = GST_OMX_VIDEO_ENC (encoder);
1854 GST_DEBUG_OBJECT (self, "Stopping encoder");
1856 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
1857 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1859 gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1861 if (gst_omx_component_get_state (self->enc, 0) > OMX_StateIdle)
1862 gst_omx_component_set_state (self->enc, OMX_StateIdle);
1864 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1865 self->started = FALSE;
1867 if (self->input_state)
1868 gst_video_codec_state_unref (self->input_state);
1869 self->input_state = NULL;
1871 g_mutex_lock (&self->drain_lock);
1872 self->draining = FALSE;
1873 g_cond_broadcast (&self->drain_cond);
1874 g_mutex_unlock (&self->drain_lock);
1876 self->default_target_bitrate = GST_OMX_PROP_OMX_DEFAULT;
1878 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
1883 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1885 gst_omx_video_enc_set_latency (GstOMXVideoEnc * self)
1887 GstClockTime latency;
1888 OMX_ALG_PARAM_REPORTED_LATENCY param;
1891 GST_OMX_INIT_STRUCT (¶m);
1893 gst_omx_component_get_parameter (self->enc,
1894 (OMX_INDEXTYPE) OMX_ALG_IndexParamReportedLatency, ¶m);
1896 if (err != OMX_ErrorNone) {
1897 GST_WARNING_OBJECT (self, "Couldn't retrieve latency: %s (0x%08x)",
1898 gst_omx_error_to_string (err), err);
1902 GST_DEBUG_OBJECT (self, "retrieved latency of %d ms",
1903 (guint32) param.nLatency);
1906 latency = param.nLatency * GST_MSECOND;
1908 gst_video_encoder_set_latency (GST_VIDEO_ENCODER (self), latency, latency);
1913 gst_omx_video_enc_disable (GstOMXVideoEnc * self)
1915 GstOMXVideoEncClass *klass;
1917 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1919 GST_DEBUG_OBJECT (self, "Need to disable and drain encoder");
1920 gst_omx_video_enc_drain (self);
1921 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1923 /* Wait until the srcpad loop is finished,
1924 * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
1925 * caused by using this lock from inside the loop function */
1926 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1927 gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1928 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1930 if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) {
1931 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1932 gst_omx_video_enc_stop (GST_VIDEO_ENCODER (self));
1933 gst_omx_video_enc_close (GST_VIDEO_ENCODER (self));
1934 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1936 if (!gst_omx_video_enc_open (GST_VIDEO_ENCODER (self)))
1939 /* The decoder is returned to initial state */
1940 self->disabled = FALSE;
1942 /* Disabling at the same time input port and output port is only
1943 * required when a buffer is shared between the ports. This cannot
1944 * be the case for a encoder because its input and output buffers
1945 * are of different nature. So let's disable ports sequencially.
1946 * Starting from IL 1.2.0, this point has been clarified.
1947 * OMX_SendCommand will return an error if the IL client attempts to
1948 * call it when there is already an on-going command being processed.
1949 * The exception is for buffer sharing above and the event
1950 * OMX_EventPortNeedsDisable will be sent to request disabling the
1951 * other port at the same time. */
1952 if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone)
1954 if (gst_omx_port_wait_buffers_released (self->enc_in_port,
1955 5 * GST_SECOND) != OMX_ErrorNone)
1957 if (!gst_omx_video_enc_deallocate_in_buffers (self))
1959 if (gst_omx_port_wait_enabled (self->enc_in_port,
1960 1 * GST_SECOND) != OMX_ErrorNone)
1963 if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
1965 if (gst_omx_port_wait_buffers_released (self->enc_out_port,
1966 1 * GST_SECOND) != OMX_ErrorNone)
1968 if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1970 if (gst_omx_port_wait_enabled (self->enc_out_port,
1971 1 * GST_SECOND) != OMX_ErrorNone)
1974 self->disabled = TRUE;
1977 GST_DEBUG_OBJECT (self, "Encoder drained and disabled");
1982 gst_omx_video_enc_configure_input_buffer (GstOMXVideoEnc * self,
1985 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1986 GstVideoInfo *info = &self->input_state->info;
1987 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1989 guint stride, slice_height;
1991 gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
1993 meta = gst_buffer_get_video_meta (input);
1995 guint plane_height[GST_VIDEO_MAX_PLANES];
1997 /* Use the stride and slice height of the first plane */
1998 if (!gst_video_meta_get_plane_height (meta, plane_height)) {
1999 GST_WARNING_OBJECT (self, "Failed to retrieve plane height from meta");
2000 slice_height = GST_VIDEO_INFO_FIELD_HEIGHT (info);
2002 slice_height = plane_height[0];
2005 stride = meta->stride[0];
2006 g_assert (stride != 0);
2008 GST_DEBUG_OBJECT (self,
2009 "adjusting stride (%d) and slice-height (%d) using input buffer meta",
2010 stride, slice_height);
2012 GST_WARNING_OBJECT (self,
2013 "input buffer doesn't provide video meta, can't adjust stride and slice height");
2015 stride = info->stride[0];
2016 slice_height = GST_VIDEO_INFO_FIELD_HEIGHT (info);
2019 if (port_def.nBufferAlignment)
2020 port_def.format.video.nStride =
2021 GST_ROUND_UP_N (stride, port_def.nBufferAlignment);
2023 port_def.format.video.nStride = GST_ROUND_UP_4 (stride); /* safe (?) default */
2025 if (klass->cdata.hacks & GST_OMX_HACK_HEIGHT_MULTIPLE_16)
2026 port_def.format.video.nSliceHeight = GST_ROUND_UP_16 (slice_height);
2028 port_def.format.video.nSliceHeight = slice_height;
2030 switch (port_def.format.video.eColorFormat) {
2031 case OMX_COLOR_FormatYUV420Planar:
2032 case OMX_COLOR_FormatYUV420PackedPlanar:
2033 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2034 /* Formats defined in extensions have their own enum so disable to -Wswitch warning */
2035 #pragma GCC diagnostic push
2036 #pragma GCC diagnostic ignored "-Wswitch"
2037 case OMX_ALG_COLOR_FormatYUV420SemiPlanar10bitPacked:
2038 #pragma GCC diagnostic pop
2040 port_def.nBufferSize =
2041 (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
2042 2 * ((port_def.format.video.nStride / 2) *
2043 ((port_def.format.video.nFrameHeight + 1) / 2));
2046 case OMX_COLOR_FormatYUV420PackedSemiPlanar:
2047 case OMX_COLOR_FormatYUV420SemiPlanar:
2048 port_def.nBufferSize =
2049 (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
2050 (port_def.format.video.nStride *
2051 ((port_def.format.video.nFrameHeight + 1) / 2));
2054 case OMX_COLOR_FormatL8:
2055 port_def.nBufferSize =
2056 port_def.format.video.nStride * port_def.format.video.nFrameHeight;
2059 case OMX_COLOR_FormatYUV422SemiPlanar:
2060 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2061 /* Formats defined in extensions have their own enum so disable to -Wswitch warning */
2062 #pragma GCC diagnostic push
2063 #pragma GCC diagnostic ignored "-Wswitch"
2064 case OMX_ALG_COLOR_FormatYUV422SemiPlanar10bitPacked:
2065 #pragma GCC diagnostic pop
2067 port_def.nBufferSize =
2068 (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
2069 2 * (port_def.format.video.nStride *
2070 ((port_def.format.video.nFrameHeight + 1) / 2));
2074 GST_ERROR_OBJECT (self, "Unsupported port format %x",
2075 port_def.format.video.eColorFormat);
2076 g_assert_not_reached ();
2079 GST_DEBUG_OBJECT (self,
2080 "setting input nStride=%d nSliceHeight=%d nBufferSize=%d (nBufferAlignment=%d)",
2081 (guint) port_def.format.video.nStride,
2082 (guint) port_def.format.video.nSliceHeight,
2083 (guint) port_def.nBufferSize, (guint) port_def.nBufferAlignment);
2085 if (gst_omx_port_update_port_definition (self->enc_in_port,
2086 &port_def) != OMX_ErrorNone)
2093 gst_omx_video_enc_ensure_nb_in_buffers (GstOMXVideoEnc * self)
2095 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
2097 if ((klass->cdata.hacks & GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL)) {
2098 if (!gst_omx_port_ensure_buffer_count_actual (self->enc_in_port, 0))
2106 gst_omx_video_enc_allocate_in_buffers (GstOMXVideoEnc * self)
2108 switch (self->input_allocation) {
2109 case GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER:
2110 if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
2113 case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC:
2114 if (gst_omx_port_use_dynamic_buffers (self->enc_in_port) != OMX_ErrorNone)
2117 case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER:
2120 g_return_val_if_reached (FALSE);
2127 check_input_alignment (GstOMXVideoEnc * self, GstMapInfo * map)
2129 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
2131 if (map->size != port_def->nBufferSize) {
2132 GST_DEBUG_OBJECT (self,
2133 "input buffer has wrong size/stride (%" G_GSIZE_FORMAT
2134 " expected: %u), can't use dynamic allocation",
2135 map->size, (guint32) port_def->nBufferSize);
2139 if (port_def->nBufferAlignment &&
2140 (GPOINTER_TO_UINT (map->data) & (port_def->nBufferAlignment - 1)) != 0) {
2141 GST_DEBUG_OBJECT (self,
2142 "input buffer is not properly aligned (address: %p alignment: %u bytes), can't use dynamic allocation",
2143 map->data, (guint32) port_def->nBufferAlignment);
2150 /* Check if @inbuf's alignment and stride matches the requirements to use the
2151 * dynamic buffer mode. */
2153 can_use_dynamic_buffer_mode (GstOMXVideoEnc * self, GstBuffer * inbuf)
2156 gboolean result = FALSE;
2158 if (gst_buffer_n_memory (inbuf) > 1) {
2159 GST_DEBUG_OBJECT (self,
2160 "input buffer contains more than one memory, can't use dynamic allocation");
2164 if (!gst_buffer_map (inbuf, &map, GST_MAP_READ)) {
2165 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2166 ("failed to map input buffer"));
2170 result = check_input_alignment (self, &map);
2172 gst_buffer_unmap (inbuf, &map);
2176 /* Choose the allocation mode for input buffers depending of what's supported by
2177 * the component and the size/alignment of the input buffer. */
2178 static GstOMXBufferAllocation
2179 gst_omx_video_enc_pick_input_allocation_mode (GstOMXVideoEnc * self,
2182 if (!gst_omx_is_dynamic_allocation_supported ())
2183 return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
2185 if (can_use_dynamic_buffer_mode (self, inbuf)) {
2186 GST_DEBUG_OBJECT (self,
2187 "input buffer is properly aligned, use dynamic allocation");
2188 return GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC;
2191 GST_DEBUG_OBJECT (self, "let input buffer allocate its buffers");
2192 return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
2196 gst_omx_video_enc_set_to_idle (GstOMXVideoEnc * self)
2198 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
2199 gboolean no_disable_outport;
2201 no_disable_outport = klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT;
2203 if (!no_disable_outport) {
2204 /* Disable output port */
2205 if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
2208 if (gst_omx_port_wait_enabled (self->enc_out_port,
2209 1 * GST_SECOND) != OMX_ErrorNone)
2213 if (gst_omx_component_set_state (self->enc, OMX_StateIdle) != OMX_ErrorNone)
2216 /* Need to allocate buffers to reach Idle state */
2217 if (!gst_omx_video_enc_allocate_in_buffers (self))
2220 if (no_disable_outport) {
2221 if (!gst_omx_video_enc_allocate_out_buffers (self))
2225 if (gst_omx_component_get_state (self->enc,
2226 GST_CLOCK_TIME_NONE) != OMX_StateIdle)
2232 static GstOMXBuffer *
2233 get_omx_buf (GstBuffer * buffer)
2237 mem = gst_buffer_peek_memory (buffer, 0);
2238 return gst_omx_memory_get_omx_buf (mem);
2242 buffer_is_from_input_pool (GstOMXVideoEnc * self, GstBuffer * buffer)
2244 /* Buffer from our input pool will already have a GstOMXBuffer associated
2245 * with our input port. */
2248 buf = get_omx_buf (buffer);
2252 return buf->port == self->enc_in_port;
2256 gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input)
2258 GstOMXVideoEncClass *klass;
2260 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
2262 /* Is downstream using our buffer pool? */
2263 if (buffer_is_from_input_pool (self, input)) {
2264 self->in_pool_used = TRUE;
2267 if (!self->in_pool_used) {
2268 if (!gst_omx_video_enc_configure_input_buffer (self, input))
2271 self->input_allocation = gst_omx_video_enc_pick_input_allocation_mode (self,
2273 self->input_dmabuf = FALSE;
2275 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2276 if (gst_is_dmabuf_memory (gst_buffer_peek_memory (input, 0))) {
2277 if (self->input_allocation ==
2278 GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
2279 GST_DEBUG_OBJECT (self, "Configure encoder input to import dmabuf");
2280 gst_omx_port_set_dmabuf (self->enc_in_port, TRUE);
2282 GST_DEBUG_OBJECT (self,
2283 "Wrong input allocation mode (%d); dynamic buffers are required to use dmabuf import",
2284 self->input_allocation);
2287 self->input_dmabuf = TRUE;
2292 GST_DEBUG_OBJECT (self, "Enabling component");
2294 if (!self->in_pool_used) {
2295 if (!gst_omx_video_enc_ensure_nb_in_buffers (self))
2297 if (!gst_omx_video_enc_ensure_nb_out_buffers (self))
2301 if (self->disabled) {
2302 if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone)
2304 if (!gst_omx_video_enc_allocate_in_buffers (self))
2307 if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
2308 if (gst_omx_port_set_enabled (self->enc_out_port, TRUE) != OMX_ErrorNone)
2310 if (!gst_omx_video_enc_allocate_out_buffers (self))
2313 if (gst_omx_port_wait_enabled (self->enc_out_port,
2314 5 * GST_SECOND) != OMX_ErrorNone)
2318 if (gst_omx_port_wait_enabled (self->enc_in_port,
2319 5 * GST_SECOND) != OMX_ErrorNone)
2321 if (gst_omx_port_mark_reconfigured (self->enc_in_port) != OMX_ErrorNone)
2324 /* If the input pool is active we already allocated buffers and set the component to Idle. */
2325 if (!self->in_pool_used) {
2326 if (!gst_omx_video_enc_set_to_idle (self))
2330 if (gst_omx_component_set_state (self->enc,
2331 OMX_StateExecuting) != OMX_ErrorNone)
2334 if (gst_omx_component_get_state (self->enc,
2335 GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
2339 /* Unset flushing to allow ports to accept data again */
2340 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
2341 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);
2343 if (gst_omx_component_get_last_error (self->enc) != OMX_ErrorNone) {
2344 GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)",
2345 gst_omx_component_get_last_error_string (self->enc),
2346 gst_omx_component_get_last_error (self->enc));
2350 self->disabled = FALSE;
2355 /* returns TRUE if only the framerate changed and that framerate could be
2356 * updated using OMX_IndexConfigVideoFramerate */
2358 gst_omx_video_enc_framerate_changed (GstOMXVideoEnc * self,
2359 GstVideoCodecState * state)
2361 GstVideoInfo prev_info = self->input_state->info;
2362 GstVideoInfo *info = &state->info;
2363 GstOMXVideoEncClass *klass;
2365 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
2367 prev_info.fps_n = info->fps_n;
2368 prev_info.fps_d = info->fps_d;
2370 /* if only the framerate changed, try and set the framerate parameter */
2371 if (gst_video_info_is_equal (info, &prev_info)) {
2372 OMX_CONFIG_FRAMERATETYPE config;
2375 GST_DEBUG_OBJECT (self, "Framerate change detected: %d/%d -> %d/%d",
2376 self->input_state->info.fps_n, self->input_state->info.fps_d,
2377 info->fps_n, info->fps_d);
2379 GST_OMX_INIT_STRUCT (&config);
2380 config.nPortIndex = self->enc_in_port->index;
2381 if (klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER) {
2382 config.xEncodeFramerate =
2383 info->fps_d ? GST_VIDEO_INFO_FIELD_RATE_N (info) / (info->fps_d) : 0;
2385 config.xEncodeFramerate = gst_omx_video_calculate_framerate_q16 (info);
2388 err = gst_omx_component_set_config (self->enc,
2389 OMX_IndexConfigVideoFramerate, &config);
2390 if (err == OMX_ErrorNone) {
2391 gst_video_codec_state_unref (self->input_state);
2392 self->input_state = gst_video_codec_state_ref (state);
2395 GST_WARNING_OBJECT (self,
2396 "Failed to set framerate configuration: %s (0x%08x)",
2397 gst_omx_error_to_string (err), err);
2398 /* if changing the rate dynamically didn't work, keep going with a full
2406 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2408 gst_omx_video_enc_set_interlacing_parameters (GstOMXVideoEnc * self,
2409 GstVideoInfo * info)
2412 OMX_INTERLACEFORMATTYPE interlace_format_param;
2414 GST_OMX_INIT_STRUCT (&interlace_format_param);
2415 interlace_format_param.nPortIndex = self->enc_in_port->index;
2417 err = gst_omx_component_get_parameter (self->enc,
2418 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoInterlaceFormatCurrent,
2419 &interlace_format_param);
2421 if (err != OMX_ErrorNone) {
2422 GST_ERROR_OBJECT (self,
2423 "Failed to get interlace format: %s (0x%08x)",
2424 gst_omx_error_to_string (err), err);
2428 if (info->interlace_mode == GST_VIDEO_INTERLACE_MODE_PROGRESSIVE)
2429 interlace_format_param.nFormat = OMX_InterlaceFrameProgressive;
2430 else if (info->interlace_mode == GST_VIDEO_INTERLACE_MODE_ALTERNATE) {
2431 if (GST_VIDEO_INFO_FIELD_ORDER (info) ==
2432 GST_VIDEO_FIELD_ORDER_BOTTOM_FIELD_FIRST)
2433 interlace_format_param.nFormat =
2434 OMX_ALG_InterlaceAlternateBottomFieldFirst;
2435 else if (GST_VIDEO_INFO_FIELD_ORDER (info) ==
2436 GST_VIDEO_FIELD_ORDER_BOTTOM_FIELD_FIRST)
2437 interlace_format_param.nFormat = OMX_ALG_InterlaceAlternateTopFieldFirst;
2439 GST_INFO_OBJECT (self,
2440 "input field-order unspecified, assume top-field-first");
2441 interlace_format_param.nFormat = OMX_ALG_InterlaceAlternateTopFieldFirst;
2444 /* Caps templates should ensure this doesn't happen but just to be safe.. */
2445 GST_ERROR_OBJECT (self, "Video interlacing mode %s not supported",
2446 gst_video_interlace_mode_to_string (info->interlace_mode));
2450 err = gst_omx_component_set_parameter (self->enc,
2451 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoInterlaceFormatCurrent,
2452 &interlace_format_param);
2454 if (err != OMX_ErrorNone) {
2455 GST_ERROR_OBJECT (self,
2456 "Failed to set interlacing mode %s (%s) format: %s (0x%08x)",
2457 gst_video_interlace_mode_to_string (info->interlace_mode),
2458 interlace_format_param.nFormat ==
2459 OMX_ALG_InterlaceAlternateTopFieldFirst ? "top-field-first" :
2460 "bottom-field-first", gst_omx_error_to_string (err), err);
2463 GST_DEBUG_OBJECT (self,
2464 "Video interlacing mode %s (%s) set on component",
2465 gst_video_interlace_mode_to_string (info->interlace_mode),
2466 interlace_format_param.nFormat ==
2467 OMX_ALG_InterlaceAlternateTopFieldFirst ? "top-field-first" :
2468 "bottom-field-first");
2473 #endif // USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2476 gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
2477 GstVideoCodecState * state)
2479 GstOMXVideoEnc *self;
2480 GstOMXVideoEncClass *klass;
2481 gboolean needs_disable = FALSE;
2482 OMX_PARAM_PORTDEFINITIONTYPE port_def;
2483 GstVideoInfo *info = &state->info;
2484 GList *negotiation_map = NULL, *l;
2487 self = GST_OMX_VIDEO_ENC (encoder);
2488 klass = GST_OMX_VIDEO_ENC_GET_CLASS (encoder);
2490 caps = gst_video_info_to_caps (info);
2491 GST_DEBUG_OBJECT (self, "Setting new input format: %" GST_PTR_FORMAT, caps);
2492 gst_caps_unref (caps);
2494 gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
2497 gst_omx_component_get_state (self->enc,
2498 GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
2499 /* If the component is not in Loaded state and a real format change happens
2500 * we have to disable the port and re-allocate all buffers. If no real
2501 * format change happened we can just exit here.
2503 if (needs_disable) {
2504 if (gst_omx_video_enc_framerate_changed (self, state))
2507 if (!gst_omx_video_enc_disable (self))
2510 if (!self->disabled) {
2511 /* The local port_def is now obsolete so get it again. */
2512 gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
2517 gst_omx_video_get_supported_colorformats (self->enc_in_port,
2519 if (!negotiation_map) {
2521 switch (info->finfo->format) {
2522 case GST_VIDEO_FORMAT_I420:
2523 port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
2525 case GST_VIDEO_FORMAT_NV12:
2526 port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
2528 case GST_VIDEO_FORMAT_NV16:
2529 port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV422SemiPlanar;
2531 case GST_VIDEO_FORMAT_ABGR:
2532 port_def.format.video.eColorFormat = OMX_COLOR_Format32bitARGB8888;
2534 case GST_VIDEO_FORMAT_ARGB:
2535 port_def.format.video.eColorFormat = OMX_COLOR_Format32bitBGRA8888;
2538 GST_ERROR_OBJECT (self, "Unsupported format %s",
2539 gst_video_format_to_string (info->finfo->format));
2544 for (l = negotiation_map; l; l = l->next) {
2545 GstOMXVideoNegotiationMap *m = l->data;
2547 if (m->format == info->finfo->format) {
2548 port_def.format.video.eColorFormat = m->type;
2552 g_list_free_full (negotiation_map,
2553 (GDestroyNotify) gst_omx_video_negotiation_map_free);
2556 port_def.format.video.nFrameWidth = info->width;
2557 port_def.format.video.nFrameHeight = GST_VIDEO_INFO_FIELD_HEIGHT (info);
2559 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2560 if (!gst_omx_video_enc_set_interlacing_parameters (self, info))
2564 if (G_UNLIKELY (klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER)) {
2565 port_def.format.video.xFramerate =
2566 info->fps_d ? GST_VIDEO_INFO_FIELD_RATE_N (info) / (info->fps_d) : 0;
2568 port_def.format.video.xFramerate =
2569 gst_omx_video_calculate_framerate_q16 (info);
2572 GST_DEBUG_OBJECT (self, "Setting inport port definition");
2573 if (gst_omx_port_update_port_definition (self->enc_in_port,
2574 &port_def) != OMX_ErrorNone)
2577 #ifdef USE_OMX_TARGET_RPI
2581 OMX_CONFIG_POINTTYPE aspect_ratio_param;
2583 GST_OMX_INIT_STRUCT (&aspect_ratio_param);
2584 aspect_ratio_param.nPortIndex = self->enc_out_port->index;
2586 err = gst_omx_component_get_parameter (self->enc,
2587 OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
2589 if (err == OMX_ErrorNone) {
2591 aspect_ratio_param.nX = info->par_n;
2592 aspect_ratio_param.nY = info->par_d;
2595 gst_omx_component_set_parameter (self->enc,
2596 OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
2598 if (err == OMX_ErrorUnsupportedIndex) {
2599 GST_WARNING_OBJECT (self,
2600 "Setting aspect ratio parameters not supported by the component");
2601 } else if (err == OMX_ErrorUnsupportedSetting) {
2602 GST_WARNING_OBJECT (self,
2603 "Setting aspect ratio %u %u not supported by the component",
2604 aspect_ratio_param.nX, aspect_ratio_param.nY);
2605 } else if (err != OMX_ErrorNone) {
2606 GST_ERROR_OBJECT (self,
2607 "Failed to set aspect ratio: %s (0x%08x)",
2608 gst_omx_error_to_string (err), err);
2613 #endif // USE_OMX_TARGET_RPI
2615 if (klass->set_format) {
2616 if (!klass->set_format (self, self->enc_in_port, state)) {
2617 GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
2622 GST_DEBUG_OBJECT (self, "Updating ports definition");
2623 if (gst_omx_port_update_port_definition (self->enc_out_port,
2624 NULL) != OMX_ErrorNone)
2626 if (gst_omx_port_update_port_definition (self->enc_in_port,
2627 NULL) != OMX_ErrorNone)
2630 /* Some OMX implementations reset the bitrate after setting the compression
2631 * format, see bgo#698049, so re-set it */
2632 gst_omx_video_enc_set_bitrate (self);
2634 if (self->input_state)
2635 gst_video_codec_state_unref (self->input_state);
2636 self->input_state = gst_video_codec_state_ref (state);
2638 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2639 gst_omx_video_enc_set_latency (self);
2642 self->downstream_flow_ret = GST_FLOW_OK;
2647 gst_omx_video_enc_flush (GstVideoEncoder * encoder)
2649 GstOMXVideoEnc *self;
2651 self = GST_OMX_VIDEO_ENC (encoder);
2653 GST_DEBUG_OBJECT (self, "Flushing encoder");
2655 if (gst_omx_component_get_state (self->enc, 0) == OMX_StateLoaded)
2658 /* 0) Pause the components */
2659 if (gst_omx_component_get_state (self->enc, 0) == OMX_StateExecuting) {
2660 gst_omx_component_set_state (self->enc, OMX_StatePause);
2661 gst_omx_component_get_state (self->enc, GST_CLOCK_TIME_NONE);
2664 /* 1) Flush the ports */
2665 GST_DEBUG_OBJECT (self, "flushing ports");
2666 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
2667 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
2669 /* Wait until the srcpad loop is finished,
2670 * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
2671 * caused by using this lock from inside the loop function */
2672 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
2673 GST_PAD_STREAM_LOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
2674 GST_PAD_STREAM_UNLOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
2675 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2677 /* 3) Resume components */
2678 gst_omx_component_set_state (self->enc, OMX_StateExecuting);
2679 gst_omx_component_get_state (self->enc, GST_CLOCK_TIME_NONE);
2681 /* 4) Unset flushing to allow ports to accept data again */
2682 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
2683 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);
2684 gst_omx_port_populate (self->enc_out_port);
2686 /* Start the srcpad loop again */
2687 self->last_upstream_ts = 0;
2688 self->downstream_flow_ret = GST_FLOW_OK;
2689 self->started = FALSE;
2690 GST_DEBUG_OBJECT (self, "Flush finished");
2696 gst_omx_video_enc_copy_plane (GstOMXVideoEnc * self, guint i,
2697 GstVideoFrame * frame, GstOMXBuffer * outbuf,
2698 const GstVideoFormatInfo * finfo)
2700 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
2702 gint src_stride, dest_stride;
2703 gint j, height, width;
2705 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
2706 dest_stride = port_def->format.video.nStride;
2707 /* XXX: Try this if no stride was set */
2708 if (dest_stride == 0)
2709 dest_stride = src_stride;
2711 dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
2714 port_def->format.video.nSliceHeight * port_def->format.video.nStride;
2716 src = GST_VIDEO_FRAME_COMP_DATA (frame, i);
2717 height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, i);
2718 width = GST_VIDEO_FRAME_COMP_WIDTH (frame, i) * (i == 0 ? 1 : 2);
2720 if (GST_VIDEO_FORMAT_INFO_BITS (finfo) == 10)
2721 /* Need ((width + 2) / 3) 32-bits words */
2722 width = (width + 2) / 3 * 4;
2724 if (dest + dest_stride * height >
2725 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nAllocLen) {
2726 GST_ERROR_OBJECT (self, "Invalid output buffer size");
2730 for (j = 0; j < height; j++) {
2731 memcpy (dest, src, width);
2733 dest += dest_stride;
2736 /* nFilledLen should include the vertical padding in each slice (spec 3.1.3.7.1) */
2737 outbuf->omx_buf->nFilledLen +=
2738 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i,
2739 port_def->format.video.nSliceHeight) * port_def->format.video.nStride;
2744 gst_omx_video_enc_semi_planar_manual_copy (GstOMXVideoEnc * self,
2745 GstBuffer * inbuf, GstOMXBuffer * outbuf, const GstVideoFormatInfo * finfo)
2747 GstVideoInfo *info = &self->input_state->info;
2748 GstVideoFrame frame;
2751 outbuf->omx_buf->nFilledLen = 0;
2753 if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
2754 GST_ERROR_OBJECT (self, "Invalid input buffer size");
2758 for (i = 0; i < 2; i++) {
2759 if (!gst_omx_video_enc_copy_plane (self, i, &frame, outbuf, finfo)) {
2760 gst_video_frame_unmap (&frame);
2765 gst_video_frame_unmap (&frame);
2770 gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf,
2771 GstOMXBuffer * outbuf)
2773 GstVideoCodecState *state = gst_video_codec_state_ref (self->input_state);
2774 GstVideoInfo *info = &state->info;
2775 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
2776 gboolean ret = FALSE;
2777 GstVideoFrame frame;
2778 GstVideoMeta *meta = gst_buffer_get_video_meta (inbuf);
2779 gint stride = meta ? meta->stride[0] : info->stride[0];
2781 if (info->width != port_def->format.video.nFrameWidth ||
2782 GST_VIDEO_INFO_FIELD_HEIGHT (info) !=
2783 port_def->format.video.nFrameHeight) {
2784 GST_ERROR_OBJECT (self, "Width or height do not match");
2788 if (self->enc_in_port->allocation ==
2789 GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
2790 if (gst_buffer_n_memory (inbuf) > 1) {
2791 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2792 ("input buffer now has more than one memory, can't use dynamic allocation any more"));
2796 if (!self->input_dmabuf) {
2797 /* Map and keep a ref on the buffer while it's being processed
2798 * by the OMX component. */
2799 if (!gst_omx_buffer_map_frame (outbuf, inbuf, info)) {
2800 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2801 ("failed to map input buffer"));
2805 if (!check_input_alignment (self, &outbuf->input_frame.map[0])) {
2806 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2807 ("input buffer now has wrong alignment/stride, can't use dynamic allocation any more"));
2811 GST_LOG_OBJECT (self, "Transfer buffer of %" G_GSIZE_FORMAT " bytes",
2812 gst_buffer_get_size (inbuf));
2815 if (!gst_omx_buffer_import_fd (outbuf, inbuf)) {
2816 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2817 ("failed to import dmabuf"));
2821 GST_LOG_OBJECT (self, "Import dmabuf of %" G_GSIZE_FORMAT " bytes",
2822 gst_buffer_get_size (inbuf));
2829 /* Same strides and everything */
2830 if ((gst_buffer_get_size (inbuf) ==
2831 outbuf->omx_buf->nAllocLen - outbuf->omx_buf->nOffset) &&
2832 (stride == port_def->format.video.nStride)) {
2833 outbuf->omx_buf->nFilledLen = gst_buffer_get_size (inbuf);
2835 GST_LOG_OBJECT (self, "Matched strides - direct copy %u bytes",
2836 (guint) outbuf->omx_buf->nFilledLen);
2838 gst_buffer_extract (inbuf, 0,
2839 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset,
2840 outbuf->omx_buf->nFilledLen);
2845 /* Different strides */
2846 GST_LOG_OBJECT (self, "Mismatched strides - copying line-by-line");
2848 switch (info->finfo->format) {
2849 case GST_VIDEO_FORMAT_I420:{
2850 gint i, j, height, width;
2852 gint src_stride, dest_stride;
2854 outbuf->omx_buf->nFilledLen = 0;
2856 if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
2857 GST_ERROR_OBJECT (self, "Invalid input buffer size");
2862 for (i = 0; i < 3; i++) {
2864 dest_stride = port_def->format.video.nStride;
2866 dest_stride = port_def->format.video.nStride / 2;
2869 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i);
2870 /* XXX: Try this if no stride was set */
2871 if (dest_stride == 0)
2872 dest_stride = src_stride;
2874 dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
2877 port_def->format.video.nSliceHeight *
2878 port_def->format.video.nStride;
2881 (port_def->format.video.nSliceHeight / 2) *
2882 (port_def->format.video.nStride / 2);
2884 src = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
2885 height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
2886 width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i);
2888 if (dest + dest_stride * height >
2889 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nAllocLen) {
2890 gst_video_frame_unmap (&frame);
2891 GST_ERROR_OBJECT (self, "Invalid output buffer size");
2896 for (j = 0; j < height; j++) {
2897 memcpy (dest, src, width);
2899 dest += dest_stride;
2902 /* nFilledLen should include the vertical padding in each slice (spec 3.1.3.7.1) */
2904 outbuf->omx_buf->nFilledLen +=
2905 port_def->format.video.nSliceHeight *
2906 port_def->format.video.nStride;
2908 outbuf->omx_buf->nFilledLen +=
2909 (port_def->format.video.nSliceHeight / 2) *
2910 (port_def->format.video.nStride / 2);
2912 gst_video_frame_unmap (&frame);
2916 case GST_VIDEO_FORMAT_NV12:
2917 case GST_VIDEO_FORMAT_NV16:
2918 case GST_VIDEO_FORMAT_NV12_10LE32:
2919 case GST_VIDEO_FORMAT_NV16_10LE32:
2921 gst_omx_video_enc_semi_planar_manual_copy (self, inbuf, outbuf,
2924 case GST_VIDEO_FORMAT_GRAY8:
2926 if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
2927 GST_ERROR_OBJECT (self, "Failed to map input buffer");
2932 ret = gst_omx_video_enc_copy_plane (self, 0, &frame, outbuf, info->finfo);
2933 gst_video_frame_unmap (&frame);
2937 GST_ERROR_OBJECT (self, "Unsupported format");
2944 gst_video_codec_state_unref (state);
2949 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2951 handle_roi_metadata (GstOMXVideoEnc * self, GstBuffer * input)
2954 gpointer state = NULL;
2957 gst_buffer_iterate_meta_filtered (input, &state,
2958 GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE))) {
2959 GstVideoRegionOfInterestMeta *roi = (GstVideoRegionOfInterestMeta *) meta;
2960 OMX_ALG_VIDEO_CONFIG_REGION_OF_INTEREST roi_param;
2963 GST_LOG_OBJECT (self, "Input buffer ROI: type=%s id=%d (%d, %d) %dx%d",
2964 g_quark_to_string (roi->roi_type), roi->id, roi->x, roi->y, roi->w,
2967 if (self->qp_mode != ROI_QP) {
2968 GST_WARNING_OBJECT (self,
2969 "Need qp-mode=roi to handle ROI metadata (current: %d); ignoring",
2974 GST_OMX_INIT_STRUCT (&roi_param);
2975 roi_param.nPortIndex = self->enc_in_port->index;
2976 roi_param.nLeft = roi->x;
2977 roi_param.nTop = roi->y;
2978 roi_param.nWidth = roi->w;
2979 roi_param.nHeight = roi->h;
2981 s = gst_video_region_of_interest_meta_get_param (roi, "roi/omx-alg");
2983 const gchar *quality;
2986 quality = gst_structure_get_string (s, "quality");
2989 g_enum_get_value_by_nick (self->alg_roi_quality_enum_class, quality);
2991 roi_param.eQuality = self->default_roi_quality;
2993 GST_WARNING_OBJECT (self,
2994 "Unknown ROI encoding quality '%s', use default (%d)",
2995 quality, self->default_roi_quality);
2997 roi_param.eQuality = evalue->value;
2999 GST_LOG_OBJECT (self, "Use encoding quality '%s' from upstream",
3003 roi_param.eQuality = self->default_roi_quality;
3005 GST_LOG_OBJECT (self, "No quality specified upstream, use default (%d)",
3006 self->default_roi_quality);
3009 gst_omx_component_set_config (self->enc,
3010 (OMX_INDEXTYPE) OMX_ALG_IndexConfigVideoRegionOfInterest, &roi_param);
3015 static GstFlowReturn
3016 gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
3017 GstVideoCodecFrame * frame)
3019 GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
3020 GstOMXVideoEnc *self;
3024 GstClockTimeDiff deadline;
3026 self = GST_OMX_VIDEO_ENC (encoder);
3028 GST_DEBUG_OBJECT (self, "Handling frame");
3030 if (self->downstream_flow_ret != GST_FLOW_OK) {
3031 gst_video_codec_frame_unref (frame);
3032 return self->downstream_flow_ret;
3035 deadline = gst_video_encoder_get_max_encode_time (encoder, frame);
3037 GST_WARNING_OBJECT (self,
3038 "Input frame is too late, dropping (deadline %" GST_TIME_FORMAT ")",
3039 GST_TIME_ARGS (-deadline));
3041 /* Calling finish_frame with frame->output_buffer == NULL will drop it */
3042 return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
3045 if (!self->started) {
3046 if (gst_omx_port_is_flushing (self->enc_out_port)) {
3047 if (!gst_omx_video_enc_enable (self, frame->input_buffer))
3051 GST_DEBUG_OBJECT (self, "Starting task");
3052 gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
3053 (GstTaskFunction) gst_omx_video_enc_loop, self, NULL);
3056 port = self->enc_in_port;
3058 while (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
3059 GstClockTime timestamp, duration;
3060 gboolean fill_buffer = TRUE;
3062 /* Make sure to release the base class stream lock, otherwise
3063 * _loop() can't call _finish_frame() and we might block forever
3064 * because no input buffers are released */
3065 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
3067 if (buffer_is_from_input_pool (self, frame->input_buffer)) {
3068 /* Receiving a buffer from our input pool */
3069 buf = get_omx_buf (frame->input_buffer);
3071 GST_LOG_OBJECT (self,
3072 "Input buffer %p already has a OMX buffer associated: %p",
3073 frame->input_buffer, buf);
3075 g_assert (!buf->input_buffer);
3076 /* Prevent the buffer to be released to the pool while it's being
3077 * processed by OMX. The reference will be dropped in EmptyBufferDone() */
3078 buf->input_buffer = gst_buffer_ref (frame->input_buffer);
3080 acq_ret = GST_OMX_ACQUIRE_BUFFER_OK;
3081 fill_buffer = FALSE;
3082 buf->omx_buf->nFilledLen = gst_buffer_get_size (frame->input_buffer);
3084 acq_ret = gst_omx_port_acquire_buffer (port, &buf, GST_OMX_WAIT);
3087 if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) {
3088 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3089 goto component_error;
3090 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
3091 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3093 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
3094 /* Reallocate all buffers */
3095 err = gst_omx_port_set_enabled (port, FALSE);
3096 if (err != OMX_ErrorNone) {
3097 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3098 goto reconfigure_error;
3101 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
3102 if (err != OMX_ErrorNone) {
3103 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3104 goto reconfigure_error;
3107 err = gst_omx_port_deallocate_buffers (port);
3108 if (err != OMX_ErrorNone) {
3109 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3110 goto reconfigure_error;
3113 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
3114 if (err != OMX_ErrorNone) {
3115 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3116 goto reconfigure_error;
3119 if (!gst_omx_video_enc_ensure_nb_in_buffers (self)) {
3120 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3121 goto reconfigure_error;
3124 err = gst_omx_port_set_enabled (port, TRUE);
3125 if (err != OMX_ErrorNone) {
3126 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3127 goto reconfigure_error;
3130 if (!gst_omx_video_enc_allocate_in_buffers (self)) {
3131 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3132 goto reconfigure_error;
3135 err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
3136 if (err != OMX_ErrorNone) {
3137 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3138 goto reconfigure_error;
3141 err = gst_omx_port_mark_reconfigured (port);
3142 if (err != OMX_ErrorNone) {
3143 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3144 goto reconfigure_error;
3147 /* Now get a new buffer and fill it */
3148 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3151 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3153 g_assert (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
3155 if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <= 0) {
3156 gst_omx_port_release_buffer (port, buf);
3160 if (self->downstream_flow_ret != GST_FLOW_OK) {
3161 gst_omx_port_release_buffer (port, buf);
3165 /* Now handle the frame */
3167 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
3168 #ifdef USE_OMX_TARGET_RPI
3169 OMX_CONFIG_BOOLEANTYPE config;
3171 GST_OMX_INIT_STRUCT (&config);
3172 config.bEnabled = OMX_TRUE;
3174 GST_DEBUG_OBJECT (self, "Forcing a keyframe (iframe on the RPi)");
3177 gst_omx_component_set_config (self->enc,
3178 OMX_IndexConfigBrcmVideoRequestIFrame, &config);
3179 #elif defined(USE_OMX_TARGET_ZYNQ_USCALE_PLUS)
3180 OMX_ALG_VIDEO_CONFIG_INSERT config;
3182 GST_OMX_INIT_STRUCT (&config);
3183 config.nPortIndex = self->enc_out_port->index;
3185 GST_DEBUG_OBJECT (self, "Forcing a keyframe");
3186 err = gst_omx_component_set_config (self->enc, (OMX_INDEXTYPE)
3187 OMX_ALG_IndexConfigVideoInsertInstantaneousDecodingRefresh, &config);
3189 OMX_CONFIG_INTRAREFRESHVOPTYPE config;
3191 GST_OMX_INIT_STRUCT (&config);
3192 config.nPortIndex = port->index;
3193 config.IntraRefreshVOP = OMX_TRUE;
3195 GST_DEBUG_OBJECT (self, "Forcing a keyframe");
3197 gst_omx_component_set_config (self->enc,
3198 OMX_IndexConfigVideoIntraVOPRefresh, &config);
3200 if (err != OMX_ErrorNone)
3201 GST_ERROR_OBJECT (self, "Failed to force a keyframe: %s (0x%08x)",
3202 gst_omx_error_to_string (err), err);
3204 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3205 handle_roi_metadata (self, frame->input_buffer);
3208 /* Copy the buffer content in chunks of size as requested
3211 && !gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) {
3212 gst_omx_port_release_buffer (port, buf);
3213 goto buffer_fill_error;
3216 timestamp = frame->pts;
3217 if (timestamp != GST_CLOCK_TIME_NONE) {
3218 GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp,
3219 gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND));
3220 self->last_upstream_ts = timestamp;
3223 duration = frame->duration;
3224 if (duration != GST_CLOCK_TIME_NONE) {
3225 buf->omx_buf->nTickCount =
3226 gst_util_uint64_scale (duration, OMX_TICKS_PER_SECOND, GST_SECOND);
3227 self->last_upstream_ts += duration;
3229 buf->omx_buf->nTickCount = 0;
3232 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3233 if (GST_VIDEO_BUFFER_IS_TOP_FIELD (frame->input_buffer))
3234 buf->omx_buf->nFlags |= OMX_ALG_BUFFERFLAG_TOP_FIELD;
3235 else if (GST_VIDEO_BUFFER_IS_BOTTOM_FIELD (frame->input_buffer))
3236 buf->omx_buf->nFlags |= OMX_ALG_BUFFERFLAG_BOT_FIELD;
3239 self->started = TRUE;
3240 err = gst_omx_port_release_buffer (port, buf);
3241 if (err != OMX_ErrorNone)
3244 GST_DEBUG_OBJECT (self, "Passed frame to component");
3247 gst_video_codec_frame_unref (frame);
3249 return self->downstream_flow_ret;
3253 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
3254 ("Got OpenMAX buffer with no free space (%p, %u/%u)", buf,
3255 (guint) buf->omx_buf->nOffset, (guint) buf->omx_buf->nAllocLen));
3256 gst_video_codec_frame_unref (frame);
3257 return GST_FLOW_ERROR;
3262 gst_video_codec_frame_unref (frame);
3263 return self->downstream_flow_ret;
3268 /* Report the OMX error, if any */
3269 if (gst_omx_component_get_last_error (self->enc) != OMX_ErrorNone)
3270 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
3271 ("Failed to enable OMX encoder: %s (0x%08x)",
3272 gst_omx_component_get_last_error_string (self->enc),
3273 gst_omx_component_get_last_error (self->enc)));
3275 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
3276 ("Failed to enable OMX encoder"));
3277 gst_video_codec_frame_unref (frame);
3278 return GST_FLOW_ERROR;
3283 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
3284 ("OpenMAX component in error state %s (0x%08x)",
3285 gst_omx_component_get_last_error_string (self->enc),
3286 gst_omx_component_get_last_error (self->enc)));
3287 gst_video_codec_frame_unref (frame);
3288 return GST_FLOW_ERROR;
3293 GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
3294 gst_video_codec_frame_unref (frame);
3295 return GST_FLOW_FLUSHING;
3299 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
3300 ("Unable to reconfigure input port"));
3301 gst_video_codec_frame_unref (frame);
3302 return GST_FLOW_ERROR;
3306 GST_ELEMENT_ERROR (self, RESOURCE, WRITE, (NULL),
3307 ("Failed to write input into the OpenMAX buffer"));
3308 gst_video_codec_frame_unref (frame);
3309 return GST_FLOW_ERROR;
3313 gst_video_codec_frame_unref (frame);
3314 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
3315 ("Failed to relase input buffer to component: %s (0x%08x)",
3316 gst_omx_error_to_string (err), err));
3317 return GST_FLOW_ERROR;
3321 static GstFlowReturn
3322 gst_omx_video_enc_finish (GstVideoEncoder * encoder)
3324 GstOMXVideoEnc *self;
3326 self = GST_OMX_VIDEO_ENC (encoder);
3328 return gst_omx_video_enc_drain (self);
3331 static GstFlowReturn
3332 gst_omx_video_enc_drain (GstOMXVideoEnc * self)
3334 GstOMXVideoEncClass *klass;
3336 GstOMXAcquireBufferReturn acq_ret;
3339 GST_DEBUG_OBJECT (self, "Draining component");
3341 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
3343 if (!self->started) {
3344 GST_DEBUG_OBJECT (self, "Component not started yet");
3347 self->started = FALSE;
3349 if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
3350 GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
3354 /* Make sure to release the base class stream lock, otherwise
3355 * _loop() can't call _finish_frame() and we might block forever
3356 * because no input buffers are released */
3357 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
3359 /* Send an EOS buffer to the component and let the base
3360 * class drop the EOS event. We will send it later when
3361 * the EOS buffer arrives on the output port. */
3362 acq_ret = gst_omx_port_acquire_buffer (self->enc_in_port, &buf, GST_OMX_WAIT);
3363 if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
3364 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3365 GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d",
3367 return GST_FLOW_ERROR;
3370 g_mutex_lock (&self->drain_lock);
3371 self->draining = TRUE;
3372 buf->omx_buf->nFilledLen = 0;
3373 GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp,
3374 gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND,
3376 buf->omx_buf->nTickCount = 0;
3377 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS;
3378 err = gst_omx_port_release_buffer (self->enc_in_port, buf);
3379 if (err != OMX_ErrorNone) {
3380 GST_ERROR_OBJECT (self, "Failed to drain component: %s (0x%08x)",
3381 gst_omx_error_to_string (err), err);
3382 g_mutex_unlock (&self->drain_lock);
3383 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3384 return GST_FLOW_ERROR;
3386 GST_DEBUG_OBJECT (self, "Waiting until component is drained");
3387 g_cond_wait (&self->drain_cond, &self->drain_lock);
3388 GST_DEBUG_OBJECT (self, "Drained component");
3389 g_mutex_unlock (&self->drain_lock);
3390 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3392 self->started = FALSE;
3397 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3399 pool_request_allocate_cb (GstBufferPool * pool, GstOMXVideoEnc * self)
3401 GstStructure *config;
3404 gst_omx_port_set_dmabuf (self->enc_in_port, TRUE);
3406 config = gst_buffer_pool_get_config (pool);
3408 if (!gst_buffer_pool_config_get_params (config, NULL, NULL, &min, NULL)) {
3409 gst_structure_free (config);
3412 gst_structure_free (config);
3414 GST_DEBUG_OBJECT (self,
3415 "input pool configured for %d buffers, adjust nBufferCountActual", min);
3417 if (!gst_omx_port_update_buffer_count_actual (self->enc_in_port, min))
3420 if (!gst_omx_video_enc_set_to_idle (self))
3423 self->input_allocation = GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
3424 self->input_dmabuf = TRUE;
3426 /* gst_omx_port_acquire_buffer() will fail if the input port is stil flushing
3427 * which will prevent upstream from acquiring buffers. */
3428 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
3433 static GstBufferPool *
3434 create_input_pool (GstOMXVideoEnc * self, GstCaps * caps, guint num_buffers)
3436 GstBufferPool *pool;
3437 GstStructure *config;
3440 gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->enc,
3441 self->enc_in_port, GST_OMX_BUFFER_MODE_DMABUF);
3443 g_signal_connect_object (pool, "allocate",
3444 G_CALLBACK (pool_request_allocate_cb), self, 0);
3446 config = gst_buffer_pool_get_config (pool);
3448 gst_buffer_pool_config_set_params (config, caps,
3449 self->enc_in_port->port_def.nBufferSize, num_buffers, 0);
3451 if (!gst_buffer_pool_set_config (pool, config)) {
3452 GST_INFO_OBJECT (self, "Failed to set config on input pool");
3453 gst_object_unref (pool);
3461 static GstStructure *
3462 get_allocation_video_meta (GstOMXVideoEnc * self, GstVideoInfo * info)
3464 GstStructure *result;
3465 GstVideoAlignment align;
3467 gst_omx_video_get_port_padding (self->enc_in_port, info, &align);
3469 result = gst_structure_new_empty ("video-meta");
3471 gst_structure_set (result, "padding-top", G_TYPE_UINT, align.padding_top,
3472 "padding-bottom", G_TYPE_UINT, align.padding_bottom,
3473 "padding-left", G_TYPE_UINT, align.padding_left,
3474 "padding-right", G_TYPE_UINT, align.padding_right, NULL);
3476 GST_LOG_OBJECT (self, "Request buffer layout to producer: %" GST_PTR_FORMAT,
3483 gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
3486 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
3490 GstBufferPool *pool = NULL;
3491 GstStructure *params;
3493 gst_query_parse_allocation (query, &caps, NULL);
3496 GST_WARNING_OBJECT (self, "allocation query does not contain caps");
3500 if (!gst_video_info_from_caps (&info, caps)) {
3501 GST_WARNING_OBJECT (self, "Failed to parse caps %" GST_PTR_FORMAT, caps);
3505 params = get_allocation_video_meta (self, &info);
3506 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, params);
3507 gst_structure_free (params);
3509 num_buffers = self->enc_in_port->port_def.nBufferCountMin + 1;
3511 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3512 /* dmabuf export is currently only supported on Zynqultrascaleplus */
3513 pool = create_input_pool (self, caps, num_buffers);
3515 GST_WARNING_OBJECT (self, "Failed to create and configure pool");
3520 GST_DEBUG_OBJECT (self,
3521 "request at least %d buffers of size %d", num_buffers,
3522 (guint) self->enc_in_port->port_def.nBufferSize);
3523 gst_query_add_allocation_pool (query, pool,
3524 self->enc_in_port->port_def.nBufferSize, num_buffers, 0);
3526 self->in_pool_used = FALSE;
3528 g_clear_object (&pool);
3531 GST_VIDEO_ENCODER_CLASS
3532 (gst_omx_video_enc_parent_class)->propose_allocation (encoder, query);
3536 filter_supported_formats (GList * negotiation_map)
3540 for (cur = negotiation_map; cur != NULL;) {
3541 GstOMXVideoNegotiationMap *nmap = (GstOMXVideoNegotiationMap *) (cur->data);
3544 switch (nmap->format) {
3545 case GST_VIDEO_FORMAT_I420:
3546 case GST_VIDEO_FORMAT_NV12:
3547 case GST_VIDEO_FORMAT_NV12_10LE32:
3548 case GST_VIDEO_FORMAT_NV16:
3549 case GST_VIDEO_FORMAT_NV16_10LE32:
3550 case GST_VIDEO_FORMAT_GRAY8:
3551 cur = g_list_next (cur);
3554 gst_omx_video_negotiation_map_free (nmap);
3555 next = g_list_next (cur);
3556 negotiation_map = g_list_delete_link (negotiation_map, cur);
3561 return negotiation_map;
3565 add_interlace_to_caps (GstOMXVideoEnc * self, GstCaps * caps)
3567 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3569 OMX_INTERLACEFORMATTYPE interlace_format_param;
3570 GstCaps *caps_alternate;
3572 if (gst_caps_is_empty (caps))
3573 /* No caps to add to */
3576 GST_OMX_INIT_STRUCT (&interlace_format_param);
3577 interlace_format_param.nPortIndex = self->enc_in_port->index;
3579 err = gst_omx_component_get_parameter (self->enc,
3580 OMX_ALG_IndexParamVideoInterlaceFormatSupported, &interlace_format_param);
3582 if (err != OMX_ErrorNone) {
3583 GST_WARNING_OBJECT (self,
3584 "Failed to get OMX_ALG_IndexParamVideoInterlaceFormatSupported %s (0x%08x)",
3585 gst_omx_error_to_string (err), err);
3589 if (!(interlace_format_param.nFormat &
3590 OMX_ALG_InterlaceAlternateTopFieldFirst)
3591 && !(interlace_format_param.nFormat &
3592 OMX_ALG_InterlaceAlternateBottomFieldFirst))
3595 /* Alternate mode is supported, create an 'alternate' variant of the caps
3596 * with the caps feature. */
3597 caps_alternate = gst_caps_copy (caps);
3599 gst_caps_set_features_simple (caps_alternate,
3600 gst_caps_features_new (GST_CAPS_FEATURE_FORMAT_INTERLACED, NULL));
3602 caps = gst_caps_merge (caps, caps_alternate);
3603 #endif // USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3609 gst_omx_video_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
3611 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
3612 GList *negotiation_map = NULL;
3613 GstCaps *comp_supported_caps;
3617 return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
3620 gst_omx_video_get_supported_colorformats (self->enc_in_port,
3622 negotiation_map = filter_supported_formats (negotiation_map);
3624 comp_supported_caps = gst_omx_video_get_caps_for_map (negotiation_map);
3625 g_list_free_full (negotiation_map,
3626 (GDestroyNotify) gst_omx_video_negotiation_map_free);
3628 comp_supported_caps = add_interlace_to_caps (self, comp_supported_caps);
3630 if (!gst_caps_is_empty (comp_supported_caps)) {
3632 gst_video_encoder_proxy_getcaps (encoder, comp_supported_caps, filter);
3633 gst_caps_unref (comp_supported_caps);
3635 gst_caps_unref (comp_supported_caps);
3636 ret = gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
3639 GST_LOG_OBJECT (encoder, "Supported caps %" GST_PTR_FORMAT, ret);
3644 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3646 handle_longterm_event (GstOMXVideoEnc * self, GstEvent * event)
3648 OMX_ALG_VIDEO_CONFIG_INSERT longterm;
3650 OMX_INDEXTYPE omx_index_long_term;
3652 GST_OMX_INIT_STRUCT (&longterm);
3653 longterm.nPortIndex = self->enc_in_port->index;
3655 /* If long-term-ref is enabled then "omx-alg/insert-longterm" event
3656 * marks the encoding picture as long term reference picture and
3657 * "omx-alg/use-longterm" event informs the encoder that encoding picture
3658 * should use existing long term picture in the dpb as reference for encoding process */
3660 if (self->long_term_ref) {
3661 if (gst_event_has_name (event, OMX_ALG_GST_EVENT_INSERT_LONGTERM)) {
3662 GST_LOG_OBJECT (self, "received omx-alg/insert-longterm event");
3663 omx_index_long_term =
3664 (OMX_INDEXTYPE) OMX_ALG_IndexConfigVideoInsertLongTerm;
3666 GST_LOG_OBJECT (self, "received omx-alg/use-longterm event");
3667 omx_index_long_term = (OMX_INDEXTYPE) OMX_ALG_IndexConfigVideoUseLongTerm;
3671 gst_omx_component_set_config (self->enc, omx_index_long_term,
3674 if (err != OMX_ErrorNone)
3675 GST_ERROR_OBJECT (self,
3676 "Failed to longterm events: %s (0x%08x)",
3677 gst_omx_error_to_string (err), err);
3679 GST_WARNING_OBJECT (self,
3680 "LongTerm events are not handled because long_term_ref is disabled");
3688 gst_omx_video_enc_sink_event (GstVideoEncoder * encoder, GstEvent * event)
3690 switch (GST_EVENT_TYPE (event)) {
3691 case GST_EVENT_CUSTOM_DOWNSTREAM:
3693 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3694 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
3695 if (gst_event_has_name (event, OMX_ALG_GST_EVENT_INSERT_LONGTERM)
3696 || gst_event_has_name (event, OMX_ALG_GST_EVENT_USE_LONGTERM))
3697 return handle_longterm_event (self, event);
3705 GST_VIDEO_ENCODER_CLASS (gst_omx_video_enc_parent_class)->sink_event
3710 gst_omx_video_enc_decide_allocation (GstVideoEncoder * encoder,
3713 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
3716 if (!GST_VIDEO_ENCODER_CLASS
3717 (gst_omx_video_enc_parent_class)->decide_allocation (encoder, query))
3720 if (gst_query_get_n_allocation_pools (query)) {
3721 gst_query_parse_nth_allocation_pool (query, 0, NULL, NULL, &min, NULL);
3722 GST_DEBUG_OBJECT (self,
3723 "Downstream requested %d buffers, adjust number of output buffers accordingly",
3726 GST_DEBUG_OBJECT (self, "Downstream didn't set any allocation pool info");
3729 self->nb_downstream_buffers = min;