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 ())
73 gst_omx_video_enc_qp_mode_get_type (void)
75 static GType qtype = 0;
78 static const GEnumValue values[] = {
79 {OMX_ALG_UNIFORM_QP, "Use the same QP for all coding units of the frame",
82 "Let the VCU encoder change the QP for each coding unit according to its content",
85 "Adjust QP according to the regions of interest defined on each frame. Must be set to handle ROI metadata.",
87 {0xffffffff, "Component Default", "default"},
91 qtype = g_enum_register_static ("GstOMXVideoEncQpMode", values);
96 #define GST_TYPE_OMX_VIDEO_ENC_GOP_MODE (gst_omx_video_enc_gop_mode_get_type ())
98 gst_omx_video_enc_gop_mode_get_type (void)
100 static GType qtype = 0;
103 static const GEnumValue values[] = {
104 {OMX_ALG_GOP_MODE_DEFAULT, "Basic GOP settings", "basic"},
105 {OMX_ALG_GOP_MODE_PYRAMIDAL,
106 "Advanced GOP pattern with hierarchical B-frames", "pyramidal"},
107 {OMX_ALG_GOP_MODE_LOW_DELAY_P, "Single I-frame followed by P-frames only",
109 {OMX_ALG_GOP_MODE_LOW_DELAY_B, "Single I-frame followed by B-frames only",
111 {OMX_ALG_GOP_MODE_ADAPTIVE, "Advanced GOP pattern with adaptive B-frames",
116 qtype = g_enum_register_static ("GstOMXVideoEncGopMode", values);
121 #define GST_TYPE_OMX_VIDEO_ENC_GDR_MODE (gst_omx_video_enc_gdr_mode_get_type ())
123 gst_omx_video_enc_gdr_mode_get_type (void)
125 static GType qtype = 0;
128 static const GEnumValue values[] = {
129 {OMX_ALG_GDR_OFF, "No GDR", "disabled"},
130 {OMX_ALG_GDR_VERTICAL,
131 "Gradual refresh using a vertical bar moving from left to right",
133 {OMX_ALG_GDR_HORIZONTAL,
134 "Gradual refresh using a horizontal bar moving from top to bottom",
139 qtype = g_enum_register_static ("GstOMXVideoEncGdrMode", values);
144 #define GST_TYPE_OMX_VIDEO_ENC_SCALING_LIST (gst_omx_video_enc_scaling_list_get_type ())
146 gst_omx_video_enc_scaling_list_get_type (void)
148 static GType qtype = 0;
151 static const GEnumValue values[] = {
152 {OMX_ALG_SCL_DEFAULT, "Default scaling list mode", "default"},
153 {OMX_ALG_SCL_FLAT, "Flat scaling list mode", "flat"},
157 qtype = g_enum_register_static ("GstOMXVideoEncScalingList", values);
162 #define GST_TYPE_OMX_VIDEO_ENC_ASPECT_RATIO (gst_omx_video_enc_aspect_ratio_get_type ())
164 gst_omx_video_enc_aspect_ratio_get_type (void)
166 static GType qtype = 0;
169 static const GEnumValue values[] = {
170 {OMX_ALG_ASPECT_RATIO_AUTO,
171 "4:3 for SD video,16:9 for HD video,unspecified for unknown format",
173 {OMX_ALG_ASPECT_RATIO_4_3, "4:3 aspect ratio", "4-3"},
174 {OMX_ALG_ASPECT_RATIO_16_9, "16:9 aspect ratio", "16-9"},
175 {OMX_ALG_ASPECT_RATIO_NONE,
176 "Aspect ratio information is not present in the stream", "none"},
180 qtype = g_enum_register_static ("GstOMXVideoEncAspectRatio", values);
185 #define GST_TYPE_OMX_VIDEO_ENC_ROI_QUALITY (gst_omx_video_enc_roi_quality_type ())
187 gst_omx_video_enc_roi_quality_type (void)
189 static GType qtype = 0;
192 static const GEnumValue values[] = {
193 {OMX_ALG_ROI_QUALITY_HIGH, "Delta QP of -5", "high"},
194 {OMX_ALG_ROI_QUALITY_MEDIUM, "Delta QP of 0", "medium"},
195 {OMX_ALG_ROI_QUALITY_LOW, "Delta QP of +5", "low"},
196 {OMX_ALG_ROI_QUALITY_DONT_CARE, "Maximum delta QP value", "dont-care"},
200 qtype = g_enum_register_static ("GstOMXVideoEncRoiQuality", values);
207 static void gst_omx_video_enc_finalize (GObject * object);
208 static void gst_omx_video_enc_set_property (GObject * object, guint prop_id,
209 const GValue * value, GParamSpec * pspec);
210 static void gst_omx_video_enc_get_property (GObject * object, guint prop_id,
211 GValue * value, GParamSpec * pspec);
214 static GstStateChangeReturn
215 gst_omx_video_enc_change_state (GstElement * element,
216 GstStateChange transition);
218 static gboolean gst_omx_video_enc_open (GstVideoEncoder * encoder);
219 static gboolean gst_omx_video_enc_close (GstVideoEncoder * encoder);
220 static gboolean gst_omx_video_enc_start (GstVideoEncoder * encoder);
221 static gboolean gst_omx_video_enc_stop (GstVideoEncoder * encoder);
222 static gboolean gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
223 GstVideoCodecState * state);
224 static gboolean gst_omx_video_enc_flush (GstVideoEncoder * encoder);
225 static GstFlowReturn gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
226 GstVideoCodecFrame * frame);
227 static gboolean gst_omx_video_enc_finish (GstVideoEncoder * encoder);
228 static gboolean gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
230 static GstCaps *gst_omx_video_enc_getcaps (GstVideoEncoder * encoder,
232 static gboolean gst_omx_video_enc_decide_allocation (GstVideoEncoder * encoder,
234 static gboolean gst_omx_video_enc_sink_query (GstVideoEncoder * encoder,
237 static GstFlowReturn gst_omx_video_enc_drain (GstOMXVideoEnc * self);
239 static GstFlowReturn gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc *
240 self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame);
264 PROP_DEPENDENT_SLICE,
265 PROP_DEFAULT_ROI_QUALITY,
268 /* FIXME: Better defaults */
269 #define GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT (0xffffffff)
270 #define GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT (0xffffffff)
271 #define GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT (0xffffffff)
272 #define GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT (0xffffffff)
273 #define GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT (0xffffffff)
274 #define GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT (0xffffffff)
275 #define GST_OMX_VIDEO_ENC_MIN_QP_DEFAULT (10)
276 #define GST_OMX_VIDEO_ENC_MAX_QP_DEFAULT (51)
277 #define GST_OMX_VIDEO_ENC_GOP_MODE_DEFAULT (OMX_ALG_GOP_MODE_DEFAULT)
278 #define GST_OMX_VIDEO_ENC_GDR_MODE_DEFAULT (OMX_ALG_GDR_OFF)
279 #define GST_OMX_VIDEO_ENC_INITIAL_DELAY_DEFAULT (1500)
280 #define GST_OMX_VIDEO_ENC_CPB_SIZE_DEFAULT (3000)
281 #define GST_OMX_VIDEO_ENC_SCALING_LIST_DEFAULT (OMX_ALG_SCL_DEFAULT)
282 #define GST_OMX_VIDEO_ENC_LOW_BANDWIDTH_DEFAULT (FALSE)
283 #define GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT (0xffffffff)
284 #define GST_OMX_VIDEO_ENC_ASPECT_RATIO_DEFAULT (OMX_ALG_ASPECT_RATIO_AUTO)
285 #define GST_OMX_VIDEO_ENC_FILLER_DATA_DEFAULT (TRUE)
286 #define GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT (0xffffffff)
287 #define GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT (0)
288 #define GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT (FALSE)
289 #define GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY OMX_ALG_ROI_QUALITY_HIGH
291 /* class initialization */
294 GST_DEBUG_CATEGORY_INIT (gst_omx_video_enc_debug_category, "omxvideoenc", 0, \
295 "debug category for gst-omx video encoder base class"); \
296 G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL); \
299 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoEnc, gst_omx_video_enc,
300 GST_TYPE_VIDEO_ENCODER, do_init);
303 gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass)
305 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
306 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
307 GstVideoEncoderClass *video_encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
310 gobject_class->finalize = gst_omx_video_enc_finalize;
311 gobject_class->set_property = gst_omx_video_enc_set_property;
312 gobject_class->get_property = gst_omx_video_enc_get_property;
314 g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
315 g_param_spec_enum ("control-rate", "Control Rate",
316 "Bitrate control method",
317 GST_TYPE_OMX_VIDEO_ENC_CONTROL_RATE,
318 GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT,
319 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
320 GST_PARAM_MUTABLE_READY));
322 g_object_class_install_property (gobject_class, PROP_TARGET_BITRATE,
323 g_param_spec_uint ("target-bitrate", "Target Bitrate",
324 "Target bitrate in bits per second (0xffffffff=component default)",
325 0, G_MAXUINT, GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT,
326 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
327 GST_PARAM_MUTABLE_PLAYING));
329 g_object_class_install_property (gobject_class, PROP_QUANT_I_FRAMES,
330 g_param_spec_uint ("quant-i-frames", "I-Frame Quantization",
331 "Quantization parameter for I-frames (0xffffffff=component default)",
332 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT,
333 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
334 GST_PARAM_MUTABLE_READY));
336 g_object_class_install_property (gobject_class, PROP_QUANT_P_FRAMES,
337 g_param_spec_uint ("quant-p-frames", "P-Frame Quantization",
338 "Quantization parameter for P-frames (0xffffffff=component default)",
339 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT,
340 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
341 GST_PARAM_MUTABLE_READY));
343 g_object_class_install_property (gobject_class, PROP_QUANT_B_FRAMES,
344 g_param_spec_uint ("quant-b-frames", "B-Frame Quantization",
345 "Quantization parameter for B-frames (0xffffffff=component default)",
346 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT,
347 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
348 GST_PARAM_MUTABLE_READY));
350 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
351 g_object_class_install_property (gobject_class, PROP_QP_MODE,
352 g_param_spec_enum ("qp-mode", "QP mode",
353 "QP control mode used by the VCU encoder",
354 GST_TYPE_OMX_VIDEO_ENC_QP_MODE,
355 GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT,
356 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
357 GST_PARAM_MUTABLE_READY));
359 g_object_class_install_property (gobject_class, PROP_MIN_QP,
360 g_param_spec_uint ("min-qp", "min Quantization value",
361 "Minimum QP value allowed for the rate control",
362 0, 51, GST_OMX_VIDEO_ENC_MIN_QP_DEFAULT,
363 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
364 GST_PARAM_MUTABLE_READY));
366 g_object_class_install_property (gobject_class, PROP_MAX_QP,
367 g_param_spec_uint ("max-qp", "max Quantization value",
368 "Maximum QP value allowed for the rate control",
369 0, 51, GST_OMX_VIDEO_ENC_MAX_QP_DEFAULT,
370 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
371 GST_PARAM_MUTABLE_READY));
373 g_object_class_install_property (gobject_class, PROP_GOP_MODE,
374 g_param_spec_enum ("gop-mode", "GOP mode",
375 "Group Of Pictures mode",
376 GST_TYPE_OMX_VIDEO_ENC_GOP_MODE,
377 GST_OMX_VIDEO_ENC_GOP_MODE_DEFAULT,
378 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
379 GST_PARAM_MUTABLE_READY));
381 g_object_class_install_property (gobject_class, PROP_GDR_MODE,
382 g_param_spec_enum ("gdr-mode", "GDR mode",
383 "Gradual Decoder Refresh scheme mode. Only used if gop-mode=low-delay-p",
384 GST_TYPE_OMX_VIDEO_ENC_GDR_MODE,
385 GST_OMX_VIDEO_ENC_GDR_MODE_DEFAULT,
386 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
387 GST_PARAM_MUTABLE_READY));
389 g_object_class_install_property (gobject_class, PROP_INITIAL_DELAY,
390 g_param_spec_uint ("initial-delay", "Initial Delay",
391 "The initial removal delay as specified in the HRD model in msec. "
392 "Not used when control-rate=disable",
393 0, G_MAXUINT, GST_OMX_VIDEO_ENC_INITIAL_DELAY_DEFAULT,
394 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
395 GST_PARAM_MUTABLE_READY));
397 g_object_class_install_property (gobject_class, PROP_CPB_SIZE,
398 g_param_spec_uint ("cpb-size", "CPB size",
399 "Coded Picture Buffer as specified in the HRD model in msec. "
400 "Not used when control-rate=disable",
401 0, G_MAXUINT, GST_OMX_VIDEO_ENC_CPB_SIZE_DEFAULT,
402 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
403 GST_PARAM_MUTABLE_READY));
405 g_object_class_install_property (gobject_class, PROP_SCALING_LIST,
406 g_param_spec_enum ("scaling-list", "Scaling List",
408 GST_TYPE_OMX_VIDEO_ENC_SCALING_LIST,
409 GST_OMX_VIDEO_ENC_SCALING_LIST_DEFAULT,
410 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
411 GST_PARAM_MUTABLE_READY));
413 g_object_class_install_property (gobject_class, PROP_LOW_BANDWIDTH,
414 g_param_spec_boolean ("low-bandwidth", "Low bandwidth mode",
415 "If enabled, decrease the vertical search range "
416 "used for P-frame motion estimation to reduce the bandwidth",
417 GST_OMX_VIDEO_ENC_LOW_BANDWIDTH_DEFAULT,
418 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
419 GST_PARAM_MUTABLE_READY));
421 g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
422 g_param_spec_uint ("max-bitrate", "Max Bitrate",
423 "Max bitrate in bits per second, only used if control-rate=variable (0xffffffff=component default)",
424 0, G_MAXUINT, GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT,
425 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
426 GST_PARAM_MUTABLE_READY));
428 g_object_class_install_property (gobject_class, PROP_ASPECT_RATIO,
429 g_param_spec_enum ("aspect-ratio", "Aspect ratio",
430 "Display aspect ratio of the video sequence to be written in SPS/VUI",
431 GST_TYPE_OMX_VIDEO_ENC_ASPECT_RATIO,
432 GST_OMX_VIDEO_ENC_ASPECT_RATIO_DEFAULT,
433 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
434 GST_PARAM_MUTABLE_READY));
436 g_object_class_install_property (gobject_class, PROP_FILLER_DATA,
437 g_param_spec_boolean ("filler-data", "Filler Data",
438 "Enable/Disable Filler Data NAL units for CBR rate control",
439 GST_OMX_VIDEO_ENC_FILLER_DATA_DEFAULT,
440 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
441 GST_PARAM_MUTABLE_READY));
443 g_object_class_install_property (gobject_class, PROP_NUM_SLICES,
444 g_param_spec_uint ("num-slices", "Number of slices",
445 "Number of slices produced for each frame. Each slice contains one or more complete macroblock/CTU row(s). "
446 "Slices are distributed over the frame as regularly as possible. If slice-size is defined as well more slices "
447 "may be produced to fit the slice-size requirement (0xffffffff=component default)",
448 1, G_MAXUINT, GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT,
449 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
450 GST_PARAM_MUTABLE_READY));
452 g_object_class_install_property (gobject_class, PROP_SLICE_SIZE,
453 g_param_spec_uint ("slice-size", "Target slice size",
454 "Target slice size (in bytes) that the encoder uses to "
455 "automatically split the bitstream into approximately equally-sized slices",
456 0, 65535, GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT,
457 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
458 GST_PARAM_MUTABLE_READY));
460 g_object_class_install_property (gobject_class, PROP_DEPENDENT_SLICE,
461 g_param_spec_boolean ("dependent-slice", "Dependent slice",
462 "If encoding with multiple slices, specify whether the additional slices are "
463 "dependent slice segments or regular slices",
464 GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT,
465 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
467 g_object_class_install_property (gobject_class, PROP_DEFAULT_ROI_QUALITY,
468 g_param_spec_enum ("default-roi-quality", "Default ROI Qualtiy",
469 "The default quality level to apply to each Region of Interest",
470 GST_TYPE_OMX_VIDEO_ENC_ROI_QUALITY,
471 GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY,
472 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
475 element_class->change_state =
476 GST_DEBUG_FUNCPTR (gst_omx_video_enc_change_state);
478 video_encoder_class->open = GST_DEBUG_FUNCPTR (gst_omx_video_enc_open);
479 video_encoder_class->close = GST_DEBUG_FUNCPTR (gst_omx_video_enc_close);
480 video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_enc_start);
481 video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_enc_stop);
482 video_encoder_class->flush = GST_DEBUG_FUNCPTR (gst_omx_video_enc_flush);
483 video_encoder_class->set_format =
484 GST_DEBUG_FUNCPTR (gst_omx_video_enc_set_format);
485 video_encoder_class->handle_frame =
486 GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_frame);
487 video_encoder_class->finish = GST_DEBUG_FUNCPTR (gst_omx_video_enc_finish);
488 video_encoder_class->propose_allocation =
489 GST_DEBUG_FUNCPTR (gst_omx_video_enc_propose_allocation);
490 video_encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_omx_video_enc_getcaps);
491 video_encoder_class->decide_allocation =
492 GST_DEBUG_FUNCPTR (gst_omx_video_enc_decide_allocation);
493 video_encoder_class->sink_query =
494 GST_DEBUG_FUNCPTR (gst_omx_video_enc_sink_query);
496 klass->cdata.type = GST_OMX_COMPONENT_TYPE_FILTER;
497 klass->cdata.default_sink_template_caps =
498 GST_VIDEO_CAPS_MAKE (GST_OMX_VIDEO_SUPPORTED_FORMATS);
500 klass->handle_output_frame =
501 GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_output_frame);
505 gst_omx_video_enc_init (GstOMXVideoEnc * self)
507 self->control_rate = GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT;
508 self->target_bitrate = GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT;
509 self->quant_i_frames = GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT;
510 self->quant_p_frames = GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT;
511 self->quant_b_frames = GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT;
512 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
513 self->qp_mode = GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT;
514 self->min_qp = GST_OMX_VIDEO_ENC_MIN_QP_DEFAULT;
515 self->max_qp = GST_OMX_VIDEO_ENC_MAX_QP_DEFAULT;
516 self->gop_mode = GST_OMX_VIDEO_ENC_GOP_MODE_DEFAULT;
517 self->gdr_mode = GST_OMX_VIDEO_ENC_GDR_MODE_DEFAULT;
518 self->initial_delay = GST_OMX_VIDEO_ENC_INITIAL_DELAY_DEFAULT;
519 self->cpb_size = GST_OMX_VIDEO_ENC_CPB_SIZE_DEFAULT;
520 self->scaling_list = GST_OMX_VIDEO_ENC_SCALING_LIST_DEFAULT;
521 self->low_bandwidth = GST_OMX_VIDEO_ENC_LOW_BANDWIDTH_DEFAULT;
522 self->max_bitrate = GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT;
523 self->aspect_ratio = GST_OMX_VIDEO_ENC_ASPECT_RATIO_DEFAULT;
524 self->filler_data = GST_OMX_VIDEO_ENC_FILLER_DATA_DEFAULT;
525 self->num_slices = GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT;
526 self->slice_size = GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT;
527 self->dependent_slice = GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT;
528 self->default_roi_quality = GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY;
531 self->default_target_bitrate = GST_OMX_PROP_OMX_DEFAULT;
533 g_mutex_init (&self->drain_lock);
534 g_cond_init (&self->drain_cond);
536 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
537 self->alg_roi_quality_enum_class =
538 g_type_class_ref (GST_TYPE_OMX_VIDEO_ENC_ROI_QUALITY);
542 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
544 #define CHECK_ERR(setting) \
545 if (err == OMX_ErrorUnsupportedIndex || err == OMX_ErrorUnsupportedSetting) { \
546 GST_WARNING_OBJECT (self, \
547 "Setting " setting " parameters not supported by the component"); \
548 } else if (err != OMX_ErrorNone) { \
549 GST_ERROR_OBJECT (self, \
550 "Failed to set " setting " parameters: %s (0x%08x)", \
551 gst_omx_error_to_string (err), err); \
556 set_zynqultrascaleplus_props (GstOMXVideoEnc * self)
560 if (self->qp_mode != GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT) {
561 OMX_ALG_VIDEO_PARAM_QUANTIZATION_CONTROL quant;
563 GST_OMX_INIT_STRUCT (&quant);
564 quant.nPortIndex = self->enc_out_port->index;
565 quant.eQpControlMode = self->qp_mode;
567 GST_DEBUG_OBJECT (self, "setting QP mode to %d", self->qp_mode);
570 gst_omx_component_set_parameter (self->enc,
571 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoQuantizationControl, &quant);
572 CHECK_ERR ("quantization");
576 OMX_ALG_VIDEO_PARAM_QUANTIZATION_EXTENSION qp_values;
578 GST_OMX_INIT_STRUCT (&qp_values);
579 qp_values.nPortIndex = self->enc_out_port->index;
580 qp_values.nQpMin = self->min_qp;
581 qp_values.nQpMax = self->max_qp;
583 GST_DEBUG_OBJECT (self, "setting min QP as %d and max QP as %d",
584 self->min_qp, self->max_qp);
587 gst_omx_component_set_parameter (self->enc,
588 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoQuantizationExtension,
590 CHECK_ERR ("min-qp and max-qp");
594 OMX_ALG_VIDEO_PARAM_GOP_CONTROL gop_mode;
596 if (self->gdr_mode != OMX_ALG_GDR_OFF &&
597 self->gop_mode != OMX_ALG_GOP_MODE_LOW_DELAY_P) {
598 GST_ERROR_OBJECT (self,
599 "gdr-mode mode only can be set if gop-mode=low-delay-p");
603 GST_OMX_INIT_STRUCT (&gop_mode);
604 gop_mode.nPortIndex = self->enc_out_port->index;
605 gop_mode.eGopControlMode = self->gop_mode;
606 gop_mode.eGdrMode = self->gdr_mode;
608 GST_DEBUG_OBJECT (self, "setting GOP mode to %d and GDR mode to %d",
609 self->gop_mode, self->gdr_mode);
612 gst_omx_component_set_parameter (self->enc,
613 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoGopControl, &gop_mode);
614 CHECK_ERR ("GOP & GDR");
617 if (self->control_rate != OMX_Video_ControlRateDisable) {
618 if (self->cpb_size < self->initial_delay) {
619 GST_ERROR_OBJECT (self,
620 "cpb-size (%d) cannot be smaller than initial-delay (%d)",
621 self->cpb_size, self->initial_delay);
622 g_critical ("cpb-size (%d) cannot be smaller than initial-delay (%d)",
623 self->cpb_size, self->initial_delay);
625 OMX_ALG_VIDEO_PARAM_CODED_PICTURE_BUFFER cpb;
627 GST_OMX_INIT_STRUCT (&cpb);
628 cpb.nPortIndex = self->enc_out_port->index;
629 cpb.nCodedPictureBufferSize = self->cpb_size;
630 cpb.nInitialRemovalDelay = self->initial_delay;
632 GST_DEBUG_OBJECT (self, "setting cpb size to %d and initial delay to %d",
633 self->cpb_size, self->initial_delay);
636 gst_omx_component_set_parameter (self->enc,
637 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoCodedPictureBuffer, &cpb);
638 CHECK_ERR ("cpb size & initial delay");
643 OMX_ALG_VIDEO_PARAM_SCALING_LIST scaling_list;
645 GST_OMX_INIT_STRUCT (&scaling_list);
646 scaling_list.nPortIndex = self->enc_out_port->index;
647 scaling_list.eScalingListMode = self->scaling_list;
649 GST_DEBUG_OBJECT (self, "setting scaling list mode as %d",
653 gst_omx_component_set_parameter (self->enc,
654 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoScalingList, &scaling_list);
655 CHECK_ERR ("scaling-list");
659 OMX_ALG_VIDEO_PARAM_LOW_BANDWIDTH low_bw;
661 GST_OMX_INIT_STRUCT (&low_bw);
662 low_bw.nPortIndex = self->enc_out_port->index;
663 low_bw.bEnableLowBandwidth = self->low_bandwidth;
665 GST_DEBUG_OBJECT (self, "%s low bandwith moded",
666 self->low_bandwidth ? "Enable" : "Disable");
669 gst_omx_component_set_parameter (self->enc,
670 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoLowBandwidth, &low_bw);
671 CHECK_ERR ("low-bandwidth");
674 if (self->max_bitrate != GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT) {
675 OMX_ALG_VIDEO_PARAM_MAX_BITRATE max_bitrate;
677 GST_OMX_INIT_STRUCT (&max_bitrate);
678 max_bitrate.nPortIndex = self->enc_out_port->index;
679 /* nMaxBitrate is in kbps while max-bitrate is in bps */
680 max_bitrate.nMaxBitrate = self->max_bitrate / 1000;
682 GST_DEBUG_OBJECT (self, "setting max bitrate to %d", self->max_bitrate);
685 gst_omx_component_set_parameter (self->enc,
686 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoMaxBitrate, &max_bitrate);
687 CHECK_ERR ("max-bitrate");
691 OMX_ALG_VIDEO_PARAM_ASPECT_RATIO aspect_ratio;
693 GST_OMX_INIT_STRUCT (&aspect_ratio);
694 aspect_ratio.nPortIndex = self->enc_out_port->index;
695 aspect_ratio.eAspectRatio = self->aspect_ratio;
697 GST_DEBUG_OBJECT (self, "setting aspect ratio to %d", self->aspect_ratio);
700 gst_omx_component_set_parameter (self->enc,
701 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoAspectRatio, &aspect_ratio);
702 CHECK_ERR ("aspect-ratio");
706 OMX_ALG_VIDEO_PARAM_FILLER_DATA filler_data;
708 GST_OMX_INIT_STRUCT (&filler_data);
709 filler_data.nPortIndex = self->enc_out_port->index;
710 filler_data.bDisableFillerData = !(self->filler_data);
712 GST_DEBUG_OBJECT (self, "%s filler data",
713 self->filler_data ? "Enable" : "Disable");
716 gst_omx_component_set_parameter (self->enc,
717 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoFillerData, &filler_data);
718 CHECK_ERR ("filler-data");
721 if (self->num_slices != GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT ||
722 self->slice_size != GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT) {
723 OMX_ALG_VIDEO_PARAM_SLICES slices;
725 GST_OMX_INIT_STRUCT (&slices);
726 slices.nPortIndex = self->enc_out_port->index;
728 err = gst_omx_component_get_parameter (self->enc,
729 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoSlices, &slices);
730 if (err != OMX_ErrorNone) {
731 GST_WARNING_OBJECT (self, "Error getting slice parameters: %s (0x%08x)",
732 gst_omx_error_to_string (err), err);
736 if (self->num_slices != GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT) {
737 slices.nNumSlices = self->num_slices;
738 GST_DEBUG_OBJECT (self,
739 "setting number of slices to %d (dependent slices: %d)",
740 self->num_slices, self->dependent_slice);
743 if (self->slice_size != GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT) {
744 slices.nSlicesSize = self->slice_size;
745 GST_DEBUG_OBJECT (self, "setting slice size to %d (dependent slices: %d)",
746 self->slice_size, self->dependent_slice);
749 slices.bDependentSlices = self->dependent_slice;
752 gst_omx_component_set_parameter (self->enc,
753 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoSlices, &slices);
754 CHECK_ERR ("slices");
762 gst_omx_video_enc_set_bitrate (GstOMXVideoEnc * self)
765 OMX_VIDEO_PARAM_BITRATETYPE bitrate_param;
766 gboolean result = TRUE;
768 GST_OBJECT_LOCK (self);
770 GST_OMX_INIT_STRUCT (&bitrate_param);
771 bitrate_param.nPortIndex = self->enc_out_port->index;
773 err = gst_omx_component_get_parameter (self->enc,
774 OMX_IndexParamVideoBitrate, &bitrate_param);
776 if (err == OMX_ErrorNone) {
777 #ifdef USE_OMX_TARGET_RPI
778 /* FIXME: Workaround for RPi returning garbage for this parameter */
779 if (bitrate_param.nVersion.nVersion == 0) {
780 GST_OMX_INIT_STRUCT (&bitrate_param);
781 bitrate_param.nPortIndex = self->enc_out_port->index;
784 if (self->default_target_bitrate == GST_OMX_PROP_OMX_DEFAULT)
785 /* Save the actual OMX default so we can restore it if needed */
786 self->default_target_bitrate = bitrate_param.nTargetBitrate;
788 if (self->control_rate != 0xffffffff)
789 bitrate_param.eControlRate = self->control_rate;
790 if (self->target_bitrate != 0xffffffff)
791 bitrate_param.nTargetBitrate = self->target_bitrate;
793 bitrate_param.nTargetBitrate = self->default_target_bitrate;
796 gst_omx_component_set_parameter (self->enc,
797 OMX_IndexParamVideoBitrate, &bitrate_param);
798 if (err == OMX_ErrorUnsupportedIndex) {
799 GST_WARNING_OBJECT (self,
800 "Setting a bitrate not supported by the component");
801 } else if (err == OMX_ErrorUnsupportedSetting) {
802 GST_WARNING_OBJECT (self,
803 "Setting bitrate settings %u %u not supported by the component",
804 self->control_rate, self->target_bitrate);
805 } else if (err != OMX_ErrorNone) {
806 GST_ERROR_OBJECT (self,
807 "Failed to set bitrate parameters: %s (0x%08x)",
808 gst_omx_error_to_string (err), err);
812 GST_ERROR_OBJECT (self, "Failed to get bitrate parameters: %s (0x%08x)",
813 gst_omx_error_to_string (err), err);
816 GST_OBJECT_UNLOCK (self);
821 gst_omx_video_enc_open (GstVideoEncoder * encoder)
823 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
824 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
825 gint in_port_index, out_port_index;
828 gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
829 klass->cdata.component_name, klass->cdata.component_role,
831 self->started = FALSE;
836 if (gst_omx_component_get_state (self->enc,
837 GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
840 in_port_index = klass->cdata.in_port_index;
841 out_port_index = klass->cdata.out_port_index;
843 if (in_port_index == -1 || out_port_index == -1) {
844 OMX_PORT_PARAM_TYPE param;
847 GST_OMX_INIT_STRUCT (¶m);
850 gst_omx_component_get_parameter (self->enc, OMX_IndexParamVideoInit,
852 if (err != OMX_ErrorNone) {
853 GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
854 gst_omx_error_to_string (err), err);
859 GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
860 (guint) param.nPorts, (guint) param.nStartPortNumber);
861 in_port_index = param.nStartPortNumber + 0;
862 out_port_index = param.nStartPortNumber + 1;
866 self->enc_in_port = gst_omx_component_add_port (self->enc, in_port_index);
867 self->enc_out_port = gst_omx_component_add_port (self->enc, out_port_index);
869 if (!self->enc_in_port || !self->enc_out_port)
876 if (!gst_omx_video_enc_set_bitrate (self))
879 if (self->quant_i_frames != 0xffffffff ||
880 self->quant_p_frames != 0xffffffff ||
881 self->quant_b_frames != 0xffffffff) {
882 OMX_VIDEO_PARAM_QUANTIZATIONTYPE quant_param;
884 GST_OMX_INIT_STRUCT (&quant_param);
885 quant_param.nPortIndex = self->enc_out_port->index;
887 err = gst_omx_component_get_parameter (self->enc,
888 OMX_IndexParamVideoQuantization, &quant_param);
890 if (err == OMX_ErrorNone) {
892 if (self->quant_i_frames != 0xffffffff)
893 quant_param.nQpI = self->quant_i_frames;
894 if (self->quant_p_frames != 0xffffffff)
895 quant_param.nQpP = self->quant_p_frames;
896 if (self->quant_b_frames != 0xffffffff)
897 quant_param.nQpB = self->quant_b_frames;
900 gst_omx_component_set_parameter (self->enc,
901 OMX_IndexParamVideoQuantization, &quant_param);
902 if (err == OMX_ErrorUnsupportedIndex) {
903 GST_WARNING_OBJECT (self,
904 "Setting quantization parameters not supported by the component");
905 } else if (err == OMX_ErrorUnsupportedSetting) {
906 GST_WARNING_OBJECT (self,
907 "Setting quantization parameters %u %u %u not supported by the component",
908 self->quant_i_frames, self->quant_p_frames, self->quant_b_frames);
909 } else if (err != OMX_ErrorNone) {
910 GST_ERROR_OBJECT (self,
911 "Failed to set quantization parameters: %s (0x%08x)",
912 gst_omx_error_to_string (err), err);
916 GST_ERROR_OBJECT (self,
917 "Failed to get quantization parameters: %s (0x%08x)",
918 gst_omx_error_to_string (err), err);
923 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
924 if (!set_zynqultrascaleplus_props (self))
932 gst_omx_video_enc_deallocate_in_buffers (GstOMXVideoEnc * self)
934 /* Pool will take care of deallocating buffers when deactivated upstream */
935 if (!self->in_pool_used
936 && gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone)
943 gst_omx_video_enc_shutdown (GstOMXVideoEnc * self)
947 GST_DEBUG_OBJECT (self, "Shutting down encoder");
949 state = gst_omx_component_get_state (self->enc, 0);
950 if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
951 if (state > OMX_StateIdle) {
952 gst_omx_component_set_state (self->enc, OMX_StateIdle);
953 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
955 gst_omx_component_set_state (self->enc, OMX_StateLoaded);
956 gst_omx_video_enc_deallocate_in_buffers (self);
957 gst_omx_port_deallocate_buffers (self->enc_out_port);
958 if (state > OMX_StateLoaded)
959 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
966 gst_omx_video_enc_close (GstVideoEncoder * encoder)
968 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
970 GST_DEBUG_OBJECT (self, "Closing encoder");
972 if (!gst_omx_video_enc_shutdown (self))
975 self->enc_in_port = NULL;
976 self->enc_out_port = NULL;
978 gst_omx_component_unref (self->enc);
981 self->started = FALSE;
987 gst_omx_video_enc_finalize (GObject * object)
989 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
991 g_mutex_clear (&self->drain_lock);
992 g_cond_clear (&self->drain_cond);
994 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
995 g_clear_pointer (&self->alg_roi_quality_enum_class, g_type_class_unref);
998 G_OBJECT_CLASS (gst_omx_video_enc_parent_class)->finalize (object);
1002 gst_omx_video_enc_set_property (GObject * object, guint prop_id,
1003 const GValue * value, GParamSpec * pspec)
1005 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
1008 case PROP_CONTROL_RATE:
1009 self->control_rate = g_value_get_enum (value);
1011 case PROP_TARGET_BITRATE:
1012 GST_OBJECT_LOCK (self);
1013 self->target_bitrate = g_value_get_uint (value);
1015 OMX_VIDEO_CONFIG_BITRATETYPE config;
1018 GST_OMX_INIT_STRUCT (&config);
1019 config.nPortIndex = self->enc_out_port->index;
1020 config.nEncodeBitrate = self->target_bitrate;
1022 gst_omx_component_set_config (self->enc,
1023 OMX_IndexConfigVideoBitrate, &config);
1024 if (err != OMX_ErrorNone)
1025 GST_ERROR_OBJECT (self,
1026 "Failed to set bitrate parameter: %s (0x%08x)",
1027 gst_omx_error_to_string (err), err);
1029 GST_OBJECT_UNLOCK (self);
1031 case PROP_QUANT_I_FRAMES:
1032 self->quant_i_frames = g_value_get_uint (value);
1034 case PROP_QUANT_P_FRAMES:
1035 self->quant_p_frames = g_value_get_uint (value);
1037 case PROP_QUANT_B_FRAMES:
1038 self->quant_b_frames = g_value_get_uint (value);
1040 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1042 self->qp_mode = g_value_get_enum (value);
1045 self->min_qp = g_value_get_uint (value);
1048 self->max_qp = g_value_get_uint (value);
1051 self->gop_mode = g_value_get_enum (value);
1054 self->gdr_mode = g_value_get_enum (value);
1056 case PROP_INITIAL_DELAY:
1057 self->initial_delay = g_value_get_uint (value);
1060 self->cpb_size = g_value_get_uint (value);
1062 case PROP_SCALING_LIST:
1063 self->scaling_list = g_value_get_enum (value);
1065 case PROP_LOW_BANDWIDTH:
1066 self->low_bandwidth = g_value_get_boolean (value);
1068 case PROP_MAX_BITRATE:
1069 self->max_bitrate = g_value_get_uint (value);
1071 case PROP_ASPECT_RATIO:
1072 self->aspect_ratio = g_value_get_enum (value);
1074 case PROP_FILLER_DATA:
1075 self->filler_data = g_value_get_boolean (value);
1077 case PROP_NUM_SLICES:
1078 self->num_slices = g_value_get_uint (value);
1080 case PROP_SLICE_SIZE:
1081 self->slice_size = g_value_get_uint (value);
1083 case PROP_DEPENDENT_SLICE:
1084 self->dependent_slice = g_value_get_boolean (value);
1086 case PROP_DEFAULT_ROI_QUALITY:
1087 self->default_roi_quality = g_value_get_enum (value);
1091 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1097 gst_omx_video_enc_get_property (GObject * object, guint prop_id, GValue * value,
1100 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
1103 case PROP_CONTROL_RATE:
1104 g_value_set_enum (value, self->control_rate);
1106 case PROP_TARGET_BITRATE:
1107 GST_OBJECT_LOCK (self);
1108 g_value_set_uint (value, self->target_bitrate);
1109 GST_OBJECT_UNLOCK (self);
1111 case PROP_QUANT_I_FRAMES:
1112 g_value_set_uint (value, self->quant_i_frames);
1114 case PROP_QUANT_P_FRAMES:
1115 g_value_set_uint (value, self->quant_p_frames);
1117 case PROP_QUANT_B_FRAMES:
1118 g_value_set_uint (value, self->quant_b_frames);
1120 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1122 g_value_set_enum (value, self->qp_mode);
1125 g_value_set_uint (value, self->min_qp);
1128 g_value_set_uint (value, self->max_qp);
1131 g_value_set_enum (value, self->gop_mode);
1134 g_value_set_enum (value, self->gdr_mode);
1136 case PROP_INITIAL_DELAY:
1137 g_value_set_uint (value, self->initial_delay);
1140 g_value_set_uint (value, self->cpb_size);
1142 case PROP_SCALING_LIST:
1143 g_value_set_enum (value, self->scaling_list);
1145 case PROP_LOW_BANDWIDTH:
1146 g_value_set_boolean (value, self->low_bandwidth);
1148 case PROP_MAX_BITRATE:
1149 g_value_set_uint (value, self->max_bitrate);
1151 case PROP_ASPECT_RATIO:
1152 g_value_set_enum (value, self->aspect_ratio);
1154 case PROP_FILLER_DATA:
1155 g_value_set_boolean (value, self->filler_data);
1157 case PROP_NUM_SLICES:
1158 g_value_set_uint (value, self->num_slices);
1160 case PROP_SLICE_SIZE:
1161 g_value_set_uint (value, self->slice_size);
1163 case PROP_DEPENDENT_SLICE:
1164 g_value_set_boolean (value, self->dependent_slice);
1166 case PROP_DEFAULT_ROI_QUALITY:
1167 g_value_set_enum (value, self->default_roi_quality);
1171 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1176 static GstStateChangeReturn
1177 gst_omx_video_enc_change_state (GstElement * element, GstStateChange transition)
1179 GstOMXVideoEnc *self;
1180 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1182 g_return_val_if_fail (GST_IS_OMX_VIDEO_ENC (element),
1183 GST_STATE_CHANGE_FAILURE);
1184 self = GST_OMX_VIDEO_ENC (element);
1186 switch (transition) {
1187 case GST_STATE_CHANGE_NULL_TO_READY:
1189 case GST_STATE_CHANGE_READY_TO_PAUSED:
1190 self->downstream_flow_ret = GST_FLOW_OK;
1192 self->draining = FALSE;
1193 self->started = FALSE;
1195 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1197 case GST_STATE_CHANGE_PAUSED_TO_READY:
1198 if (self->enc_in_port)
1199 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
1200 if (self->enc_out_port)
1201 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1203 g_mutex_lock (&self->drain_lock);
1204 self->draining = FALSE;
1205 g_cond_broadcast (&self->drain_cond);
1206 g_mutex_unlock (&self->drain_lock);
1212 if (ret == GST_STATE_CHANGE_FAILURE)
1216 GST_ELEMENT_CLASS (gst_omx_video_enc_parent_class)->change_state (element,
1219 if (ret == GST_STATE_CHANGE_FAILURE)
1222 switch (transition) {
1223 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1225 case GST_STATE_CHANGE_PAUSED_TO_READY:
1226 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1227 self->started = FALSE;
1229 case GST_STATE_CHANGE_READY_TO_NULL:
1239 get_chroma_info_from_input (GstOMXVideoEnc * self, const gchar ** chroma_format,
1240 guint * bit_depth_luma, guint * bit_depth_chroma)
1242 switch (self->input_state->info.finfo->format) {
1243 case GST_VIDEO_FORMAT_GRAY8:
1244 *chroma_format = "4:0:0";
1245 *bit_depth_luma = 8;
1246 *bit_depth_chroma = 0;
1248 case GST_VIDEO_FORMAT_I420:
1249 case GST_VIDEO_FORMAT_NV12:
1250 *chroma_format = "4:2:0";
1251 *bit_depth_luma = *bit_depth_chroma = 8;
1253 case GST_VIDEO_FORMAT_NV16:
1254 case GST_VIDEO_FORMAT_YUY2:
1255 case GST_VIDEO_FORMAT_YVYU:
1256 case GST_VIDEO_FORMAT_UYVY:
1257 *chroma_format = "4:2:2";
1258 *bit_depth_luma = *bit_depth_chroma = 8;
1260 case GST_VIDEO_FORMAT_GRAY10_LE32:
1261 *chroma_format = "4:0:0";
1262 *bit_depth_luma = 10;
1263 *bit_depth_chroma = 0;
1265 case GST_VIDEO_FORMAT_NV12_10LE32:
1266 *chroma_format = "4:2:0";
1267 *bit_depth_luma = *bit_depth_chroma = 10;
1269 case GST_VIDEO_FORMAT_NV16_10LE32:
1270 *chroma_format = "4:2:2";
1271 *bit_depth_luma = *bit_depth_chroma = 10;
1281 get_output_caps (GstOMXVideoEnc * self)
1283 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1285 const gchar *chroma_format;
1286 guint bit_depth_luma, bit_depth_chroma;
1288 caps = klass->get_caps (self, self->enc_out_port, self->input_state);
1290 /* Add chroma info about the encoded stream inferred from the format of the input */
1291 if (get_chroma_info_from_input (self, &chroma_format, &bit_depth_luma,
1292 &bit_depth_chroma)) {
1293 GST_DEBUG_OBJECT (self,
1294 "adding chroma info to output caps: %s (luma %d bits) (chroma %d bits)",
1295 chroma_format, bit_depth_luma, bit_depth_chroma);
1297 gst_caps_set_simple (caps, "chroma-format", G_TYPE_STRING, chroma_format,
1298 "bit-depth-luma", G_TYPE_UINT, bit_depth_luma,
1299 "bit-depth-chroma", G_TYPE_UINT, bit_depth_chroma, NULL);
1305 static GstFlowReturn
1306 gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port,
1307 GstOMXBuffer * buf, GstVideoCodecFrame * frame)
1309 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1310 GstFlowReturn flow_ret = GST_FLOW_OK;
1312 if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG)
1313 && buf->omx_buf->nFilledLen > 0) {
1314 GstVideoCodecState *state;
1315 GstBuffer *codec_data;
1316 GstMapInfo map = GST_MAP_INFO_INIT;
1319 GST_DEBUG_OBJECT (self, "Handling codec data");
1321 caps = get_output_caps (self);
1322 codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
1324 gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
1326 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
1327 buf->omx_buf->nFilledLen);
1328 gst_buffer_unmap (codec_data, &map);
1330 gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
1332 state->codec_data = codec_data;
1333 gst_video_codec_state_unref (state);
1334 if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) {
1335 gst_video_codec_frame_unref (frame);
1336 GST_ERROR_OBJECT (self,
1337 "Downstream element refused to negotiate codec_data in the caps");
1338 return GST_FLOW_NOT_NEGOTIATED;
1340 gst_video_codec_frame_unref (frame);
1341 flow_ret = GST_FLOW_OK;
1342 } else if (buf->omx_buf->nFilledLen > 0) {
1344 GstMapInfo map = GST_MAP_INFO_INIT;
1346 GST_DEBUG_OBJECT (self, "Handling output data");
1348 outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
1350 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
1352 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
1353 buf->omx_buf->nFilledLen);
1354 gst_buffer_unmap (outbuf, &map);
1356 GST_BUFFER_TIMESTAMP (outbuf) =
1357 gst_util_uint64_scale (GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp),
1358 GST_SECOND, OMX_TICKS_PER_SECOND);
1359 if (buf->omx_buf->nTickCount != 0)
1360 GST_BUFFER_DURATION (outbuf) =
1361 gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND,
1362 OMX_TICKS_PER_SECOND);
1364 if ((klass->cdata.hacks & GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED)
1365 || (buf->omx_buf->nFlags & OMX_BUFFERFLAG_SYNCFRAME)) {
1367 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1369 GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1372 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
1374 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1378 frame->output_buffer = outbuf;
1380 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
1382 GST_ERROR_OBJECT (self, "No corresponding frame found");
1383 flow_ret = gst_pad_push (GST_VIDEO_ENCODER_SRC_PAD (self), outbuf);
1385 } else if (frame != NULL) {
1386 /* Just ignore empty buffers, don't drop a frame for that */
1387 flow_ret = GST_FLOW_OK;
1388 gst_video_codec_frame_unref (frame);
1395 gst_omx_video_enc_ensure_nb_out_buffers (GstOMXVideoEnc * self)
1397 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1400 if (!(klass->cdata.hacks & GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL))
1403 /* If dowstream tell us how many buffers it needs allocate as many extra buffers so we won't starve
1404 * if it keeps them downstream (like when using dynamic mode). */
1405 if (self->nb_downstream_buffers)
1406 extra = self->nb_downstream_buffers;
1408 if (!gst_omx_port_ensure_buffer_count_actual (self->enc_out_port, extra))
1415 gst_omx_video_enc_pause_loop (GstOMXVideoEnc * self, GstFlowReturn flow_ret)
1417 g_mutex_lock (&self->drain_lock);
1418 if (self->draining) {
1419 self->draining = FALSE;
1420 g_cond_broadcast (&self->drain_cond);
1422 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1423 self->downstream_flow_ret = flow_ret;
1424 self->started = FALSE;
1425 g_mutex_unlock (&self->drain_lock);
1429 gst_omx_video_enc_loop (GstOMXVideoEnc * self)
1431 GstOMXVideoEncClass *klass;
1432 GstOMXPort *port = self->enc_out_port;
1433 GstOMXBuffer *buf = NULL;
1434 GstVideoCodecFrame *frame;
1435 GstFlowReturn flow_ret = GST_FLOW_OK;
1436 GstOMXAcquireBufferReturn acq_return;
1439 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1441 acq_return = gst_omx_port_acquire_buffer (port, &buf, GST_OMX_WAIT);
1442 if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
1443 goto component_error;
1444 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
1446 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) {
1450 if (!gst_pad_has_current_caps (GST_VIDEO_ENCODER_SRC_PAD (self))
1451 || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1453 GstVideoCodecState *state;
1455 GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");
1457 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE
1458 && gst_omx_port_is_enabled (port)) {
1459 /* Reallocate all buffers */
1460 err = gst_omx_port_set_enabled (port, FALSE);
1461 if (err != OMX_ErrorNone)
1462 goto reconfigure_error;
1464 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
1465 if (err != OMX_ErrorNone)
1466 goto reconfigure_error;
1468 err = gst_omx_port_deallocate_buffers (port);
1469 if (err != OMX_ErrorNone)
1470 goto reconfigure_error;
1472 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
1473 if (err != OMX_ErrorNone)
1474 goto reconfigure_error;
1477 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1479 caps = get_output_caps (self);
1482 gst_omx_port_release_buffer (self->enc_out_port, buf);
1483 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1487 GST_DEBUG_OBJECT (self, "Setting output state: %" GST_PTR_FORMAT, caps);
1490 gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
1492 gst_video_codec_state_unref (state);
1494 if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) {
1496 gst_omx_port_release_buffer (self->enc_out_port, buf);
1497 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1501 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1503 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1504 if (!gst_omx_video_enc_ensure_nb_out_buffers (self))
1505 goto reconfigure_error;
1507 err = gst_omx_port_set_enabled (port, TRUE);
1508 if (err != OMX_ErrorNone)
1509 goto reconfigure_error;
1511 err = gst_omx_port_allocate_buffers (port);
1512 if (err != OMX_ErrorNone)
1513 goto reconfigure_error;
1515 err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
1516 if (err != OMX_ErrorNone)
1517 goto reconfigure_error;
1519 err = gst_omx_port_populate (port);
1520 if (err != OMX_ErrorNone)
1521 goto reconfigure_error;
1523 err = gst_omx_port_mark_reconfigured (port);
1524 if (err != OMX_ErrorNone)
1525 goto reconfigure_error;
1528 /* Now get a buffer */
1529 if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) {
1534 g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
1536 /* This prevents a deadlock between the srcpad stream
1537 * lock and the videocodec stream lock, if ::flush()
1538 * is called at the wrong time
1540 if (gst_omx_port_is_flushing (self->enc_out_port)) {
1541 GST_DEBUG_OBJECT (self, "Flushing");
1542 gst_omx_port_release_buffer (self->enc_out_port, buf);
1546 GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x (%s) %" G_GUINT64_FORMAT,
1547 (guint) buf->omx_buf->nFlags,
1548 gst_omx_buffer_flags_to_string (buf->omx_buf->nFlags),
1549 (guint64) GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp));
1551 frame = gst_omx_video_find_nearest_frame (GST_ELEMENT_CAST (self), buf,
1552 gst_video_encoder_get_frames (GST_VIDEO_ENCODER (self)));
1554 g_assert (klass->handle_output_frame);
1555 flow_ret = klass->handle_output_frame (self, self->enc_out_port, buf, frame);
1557 GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
1559 err = gst_omx_port_release_buffer (port, buf);
1560 if (err != OMX_ErrorNone)
1563 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1564 self->downstream_flow_ret = flow_ret;
1565 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1567 GST_DEBUG_OBJECT (self, "Read frame from component");
1569 if (flow_ret != GST_FLOW_OK)
1576 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1577 ("OpenMAX component in error state %s (0x%08x)",
1578 gst_omx_component_get_last_error_string (self->enc),
1579 gst_omx_component_get_last_error (self->enc)));
1580 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1581 gst_omx_video_enc_pause_loop (self, GST_FLOW_ERROR);
1586 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1587 gst_omx_video_enc_pause_loop (self, GST_FLOW_FLUSHING);
1593 g_mutex_lock (&self->drain_lock);
1594 if (self->draining) {
1595 GST_DEBUG_OBJECT (self, "Drained");
1596 self->draining = FALSE;
1597 g_cond_broadcast (&self->drain_cond);
1598 flow_ret = GST_FLOW_OK;
1599 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1601 GST_DEBUG_OBJECT (self, "Component signalled EOS");
1602 flow_ret = GST_FLOW_EOS;
1604 g_mutex_unlock (&self->drain_lock);
1606 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1607 self->downstream_flow_ret = flow_ret;
1608 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1610 /* Here we fallback and pause the task for the EOS case */
1611 if (flow_ret != GST_FLOW_OK)
1618 if (flow_ret == GST_FLOW_EOS) {
1619 GST_DEBUG_OBJECT (self, "EOS");
1621 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
1622 gst_event_new_eos ());
1623 } else if (flow_ret < GST_FLOW_EOS) {
1624 GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."),
1625 ("stream stopped, reason %s", gst_flow_get_name (flow_ret)));
1627 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
1628 gst_event_new_eos ());
1629 } else if (flow_ret == GST_FLOW_FLUSHING) {
1630 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1632 gst_omx_video_enc_pause_loop (self, flow_ret);
1637 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1638 ("Unable to reconfigure output port"));
1639 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1640 gst_omx_video_enc_pause_loop (self, GST_FLOW_NOT_NEGOTIATED);
1645 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps"));
1646 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1647 gst_omx_video_enc_pause_loop (self, GST_FLOW_NOT_NEGOTIATED);
1652 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1653 ("Failed to relase output buffer to component: %s (0x%08x)",
1654 gst_omx_error_to_string (err), err));
1655 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1656 gst_omx_video_enc_pause_loop (self, GST_FLOW_ERROR);
1662 gst_omx_video_enc_start (GstVideoEncoder * encoder)
1664 GstOMXVideoEnc *self;
1666 self = GST_OMX_VIDEO_ENC (encoder);
1668 self->last_upstream_ts = 0;
1669 self->downstream_flow_ret = GST_FLOW_OK;
1670 self->nb_downstream_buffers = 0;
1671 self->in_pool_used = FALSE;
1677 gst_omx_video_enc_stop (GstVideoEncoder * encoder)
1679 GstOMXVideoEnc *self;
1681 self = GST_OMX_VIDEO_ENC (encoder);
1683 GST_DEBUG_OBJECT (self, "Stopping encoder");
1685 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
1686 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1688 gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1690 if (gst_omx_component_get_state (self->enc, 0) > OMX_StateIdle)
1691 gst_omx_component_set_state (self->enc, OMX_StateIdle);
1693 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1694 self->started = FALSE;
1696 if (self->input_state)
1697 gst_video_codec_state_unref (self->input_state);
1698 self->input_state = NULL;
1700 g_mutex_lock (&self->drain_lock);
1701 self->draining = FALSE;
1702 g_cond_broadcast (&self->drain_cond);
1703 g_mutex_unlock (&self->drain_lock);
1705 self->default_target_bitrate = GST_OMX_PROP_OMX_DEFAULT;
1707 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
1712 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1714 gst_omx_video_enc_set_latency (GstOMXVideoEnc * self)
1716 GstClockTime latency;
1717 OMX_ALG_PARAM_REPORTED_LATENCY param;
1720 GST_OMX_INIT_STRUCT (¶m);
1722 gst_omx_component_get_parameter (self->enc,
1723 (OMX_INDEXTYPE) OMX_ALG_IndexParamReportedLatency, ¶m);
1725 if (err != OMX_ErrorNone) {
1726 GST_WARNING_OBJECT (self, "Couldn't retrieve latency: %s (0x%08x)",
1727 gst_omx_error_to_string (err), err);
1731 GST_DEBUG_OBJECT (self, "retrieved latency of %d ms",
1732 (guint32) param.nLatency);
1735 latency = param.nLatency * GST_MSECOND;
1737 gst_video_encoder_set_latency (GST_VIDEO_ENCODER (self), latency, latency);
1742 gst_omx_video_enc_disable (GstOMXVideoEnc * self)
1744 GstOMXVideoEncClass *klass;
1746 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1748 GST_DEBUG_OBJECT (self, "Need to disable and drain encoder");
1749 gst_omx_video_enc_drain (self);
1750 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1752 /* Wait until the srcpad loop is finished,
1753 * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
1754 * caused by using this lock from inside the loop function */
1755 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1756 gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1757 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1759 if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) {
1760 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1761 gst_omx_video_enc_stop (GST_VIDEO_ENCODER (self));
1762 gst_omx_video_enc_close (GST_VIDEO_ENCODER (self));
1763 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1765 if (!gst_omx_video_enc_open (GST_VIDEO_ENCODER (self)))
1768 /* The decoder is returned to initial state */
1769 self->disabled = FALSE;
1771 /* Disabling at the same time input port and output port is only
1772 * required when a buffer is shared between the ports. This cannot
1773 * be the case for a encoder because its input and output buffers
1774 * are of different nature. So let's disable ports sequencially.
1775 * Starting from IL 1.2.0, this point has been clarified.
1776 * OMX_SendCommand will return an error if the IL client attempts to
1777 * call it when there is already an on-going command being processed.
1778 * The exception is for buffer sharing above and the event
1779 * OMX_EventPortNeedsDisable will be sent to request disabling the
1780 * other port at the same time. */
1781 if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone)
1783 if (gst_omx_port_wait_buffers_released (self->enc_in_port,
1784 5 * GST_SECOND) != OMX_ErrorNone)
1786 if (!gst_omx_video_enc_deallocate_in_buffers (self))
1788 if (gst_omx_port_wait_enabled (self->enc_in_port,
1789 1 * GST_SECOND) != OMX_ErrorNone)
1792 if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
1794 if (gst_omx_port_wait_buffers_released (self->enc_out_port,
1795 1 * GST_SECOND) != OMX_ErrorNone)
1797 if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1799 if (gst_omx_port_wait_enabled (self->enc_out_port,
1800 1 * GST_SECOND) != OMX_ErrorNone)
1803 self->disabled = TRUE;
1806 GST_DEBUG_OBJECT (self, "Encoder drained and disabled");
1811 gst_omx_video_enc_configure_input_buffer (GstOMXVideoEnc * self,
1814 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1815 GstVideoInfo *info = &self->input_state->info;
1816 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1818 guint stride, slice_height;
1820 gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
1822 meta = gst_buffer_get_video_meta (input);
1824 /* Use the stride and slice height of the first plane */
1825 stride = meta->stride[0];
1826 g_assert (stride != 0);
1827 slice_height = (meta->offset[1] - meta->offset[0]) / stride;
1829 GST_DEBUG_OBJECT (self,
1830 "adjusting stride (%d) and slice-height (%d) using input buffer meta",
1831 stride, slice_height);
1833 GST_WARNING_OBJECT (self,
1834 "input buffer doesn't provide video meta, can't adjust stride and slice height");
1836 stride = info->stride[0];
1837 slice_height = info->height;
1840 if (port_def.nBufferAlignment)
1841 port_def.format.video.nStride =
1842 GST_ROUND_UP_N (stride, port_def.nBufferAlignment);
1844 port_def.format.video.nStride = GST_ROUND_UP_4 (stride); /* safe (?) default */
1846 if (klass->cdata.hacks & GST_OMX_HACK_HEIGHT_MULTIPLE_16)
1847 port_def.format.video.nSliceHeight = GST_ROUND_UP_16 (slice_height);
1849 port_def.format.video.nSliceHeight = slice_height;
1851 switch (port_def.format.video.eColorFormat) {
1852 case OMX_COLOR_FormatYUV420Planar:
1853 case OMX_COLOR_FormatYUV420PackedPlanar:
1854 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1855 /* Formats defined in extensions have their own enum so disable to -Wswitch warning */
1856 #pragma GCC diagnostic push
1857 #pragma GCC diagnostic ignored "-Wswitch"
1858 case OMX_ALG_COLOR_FormatYUV420SemiPlanar10bitPacked:
1859 #pragma GCC diagnostic pop
1861 port_def.nBufferSize =
1862 (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
1863 2 * ((port_def.format.video.nStride / 2) *
1864 ((port_def.format.video.nFrameHeight + 1) / 2));
1867 case OMX_COLOR_FormatYUV420PackedSemiPlanar:
1868 case OMX_COLOR_FormatYUV420SemiPlanar:
1869 port_def.nBufferSize =
1870 (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
1871 (port_def.format.video.nStride *
1872 ((port_def.format.video.nFrameHeight + 1) / 2));
1875 case OMX_COLOR_FormatYUV422SemiPlanar:
1876 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1877 /* Formats defined in extensions have their own enum so disable to -Wswitch warning */
1878 #pragma GCC diagnostic push
1879 #pragma GCC diagnostic ignored "-Wswitch"
1880 case OMX_ALG_COLOR_FormatYUV422SemiPlanar10bitPacked:
1881 #pragma GCC diagnostic pop
1883 port_def.nBufferSize =
1884 (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
1885 2 * (port_def.format.video.nStride *
1886 ((port_def.format.video.nFrameHeight + 1) / 2));
1890 GST_ERROR_OBJECT (self, "Unsupported port format %x",
1891 port_def.format.video.eColorFormat);
1892 g_assert_not_reached ();
1895 GST_DEBUG_OBJECT (self,
1896 "setting input nStride=%d nSliceHeight=%d nBufferSize=%d (nBufferAlignment=%d)",
1897 (guint) port_def.format.video.nStride,
1898 (guint) port_def.format.video.nSliceHeight,
1899 (guint) port_def.nBufferSize, (guint) port_def.nBufferAlignment);
1901 if (gst_omx_port_update_port_definition (self->enc_in_port,
1902 &port_def) != OMX_ErrorNone)
1909 gst_omx_video_enc_ensure_nb_in_buffers (GstOMXVideoEnc * self)
1911 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1913 if ((klass->cdata.hacks & GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL)) {
1914 if (!gst_omx_port_ensure_buffer_count_actual (self->enc_in_port, 0))
1922 gst_omx_video_enc_allocate_in_buffers (GstOMXVideoEnc * self)
1924 switch (self->input_allocation) {
1925 case GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER:
1926 if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1929 case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC:
1930 if (gst_omx_port_use_dynamic_buffers (self->enc_in_port) != OMX_ErrorNone)
1933 case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER:
1936 g_return_val_if_reached (FALSE);
1943 check_input_alignment (GstOMXVideoEnc * self, GstMapInfo * map)
1945 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
1947 if (map->size != port_def->nBufferSize) {
1948 GST_DEBUG_OBJECT (self,
1949 "input buffer has wrong size/stride (%" G_GSIZE_FORMAT
1950 " expected: %u), can't use dynamic allocation",
1951 map->size, (guint32) port_def->nBufferSize);
1955 if (port_def->nBufferAlignment &&
1956 (GPOINTER_TO_UINT (map->data) & (port_def->nBufferAlignment - 1)) != 0) {
1957 GST_DEBUG_OBJECT (self,
1958 "input buffer is not properly aligned (address: %p alignment: %u bytes), can't use dynamic allocation",
1959 map->data, (guint32) port_def->nBufferAlignment);
1966 /* Check if @inbuf's alignment and stride matches the requirements to use the
1967 * dynamic buffer mode. */
1969 can_use_dynamic_buffer_mode (GstOMXVideoEnc * self, GstBuffer * inbuf)
1972 gboolean result = FALSE;
1974 if (gst_buffer_n_memory (inbuf) > 1) {
1975 GST_DEBUG_OBJECT (self,
1976 "input buffer contains more than one memory, can't use dynamic allocation");
1980 if (!gst_buffer_map (inbuf, &map, GST_MAP_READ)) {
1981 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
1982 ("failed to map input buffer"));
1986 result = check_input_alignment (self, &map);
1988 gst_buffer_unmap (inbuf, &map);
1992 /* Choose the allocation mode for input buffers depending of what's supported by
1993 * the component and the size/alignment of the input buffer. */
1994 static GstOMXBufferAllocation
1995 gst_omx_video_enc_pick_input_allocation_mode (GstOMXVideoEnc * self,
1998 if (!gst_omx_is_dynamic_allocation_supported ())
1999 return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
2001 if (can_use_dynamic_buffer_mode (self, inbuf)) {
2002 GST_DEBUG_OBJECT (self,
2003 "input buffer is properly aligned, use dynamic allocation");
2004 return GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC;
2007 GST_DEBUG_OBJECT (self, "let input buffer allocate its buffers");
2008 return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
2012 gst_omx_video_enc_set_to_idle (GstOMXVideoEnc * self)
2014 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
2015 gboolean no_disable_outport;
2017 no_disable_outport = klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT;
2019 if (!no_disable_outport) {
2020 /* Disable output port */
2021 if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
2024 if (gst_omx_port_wait_enabled (self->enc_out_port,
2025 1 * GST_SECOND) != OMX_ErrorNone)
2029 if (gst_omx_component_set_state (self->enc, OMX_StateIdle) != OMX_ErrorNone)
2032 /* Need to allocate buffers to reach Idle state */
2033 if (!gst_omx_video_enc_allocate_in_buffers (self))
2036 if (no_disable_outport) {
2037 if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
2041 if (gst_omx_component_get_state (self->enc,
2042 GST_CLOCK_TIME_NONE) != OMX_StateIdle)
2048 static GstOMXBuffer *
2049 get_omx_buf (GstBuffer * buffer)
2053 mem = gst_buffer_peek_memory (buffer, 0);
2054 return gst_omx_memory_get_omx_buf (mem);
2058 buffer_is_from_input_pool (GstOMXVideoEnc * self, GstBuffer * buffer)
2060 /* Buffer from our input pool will already have a GstOMXBuffer associated
2061 * with our input port. */
2064 buf = get_omx_buf (buffer);
2068 return buf->port == self->enc_in_port;
2072 gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input)
2074 GstOMXVideoEncClass *klass;
2076 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
2078 /* Is downstream using our buffer pool? */
2079 if (buffer_is_from_input_pool (self, input)) {
2080 self->in_pool_used = TRUE;
2083 if (!self->in_pool_used) {
2084 if (!gst_omx_video_enc_configure_input_buffer (self, input))
2087 self->input_allocation = gst_omx_video_enc_pick_input_allocation_mode (self,
2089 self->input_dmabuf = FALSE;
2091 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2092 if (gst_is_dmabuf_memory (gst_buffer_peek_memory (input, 0))) {
2093 if (self->input_allocation ==
2094 GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
2095 GST_DEBUG_OBJECT (self, "Configure encoder input to import dmabuf");
2096 gst_omx_port_set_dmabuf (self->enc_in_port, TRUE);
2098 GST_DEBUG_OBJECT (self,
2099 "Wrong input allocation mode (%d); dynamic buffers are required to use dmabuf import",
2100 self->input_allocation);
2103 self->input_dmabuf = TRUE;
2108 GST_DEBUG_OBJECT (self, "Enabling component");
2110 if (!self->in_pool_used) {
2111 if (!gst_omx_video_enc_ensure_nb_in_buffers (self))
2113 if (!gst_omx_video_enc_ensure_nb_out_buffers (self))
2117 if (self->disabled) {
2118 if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone)
2120 if (!gst_omx_video_enc_allocate_in_buffers (self))
2123 if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
2124 if (gst_omx_port_set_enabled (self->enc_out_port, TRUE) != OMX_ErrorNone)
2126 if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
2129 if (gst_omx_port_wait_enabled (self->enc_out_port,
2130 5 * GST_SECOND) != OMX_ErrorNone)
2134 if (gst_omx_port_wait_enabled (self->enc_in_port,
2135 5 * GST_SECOND) != OMX_ErrorNone)
2137 if (gst_omx_port_mark_reconfigured (self->enc_in_port) != OMX_ErrorNone)
2140 /* If the input pool is active we already allocated buffers and set the component to Idle. */
2141 if (!self->in_pool_used) {
2142 if (!gst_omx_video_enc_set_to_idle (self))
2146 if (gst_omx_component_set_state (self->enc,
2147 OMX_StateExecuting) != OMX_ErrorNone)
2150 if (gst_omx_component_get_state (self->enc,
2151 GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
2155 /* Unset flushing to allow ports to accept data again */
2156 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
2157 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);
2159 if (gst_omx_component_get_last_error (self->enc) != OMX_ErrorNone) {
2160 GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)",
2161 gst_omx_component_get_last_error_string (self->enc),
2162 gst_omx_component_get_last_error (self->enc));
2166 self->disabled = FALSE;
2171 /* returns TRUE if only the framerate changed and that framerate could be
2172 * updated using OMX_IndexConfigVideoFramerate */
2174 gst_omx_video_enc_framerate_changed (GstOMXVideoEnc * self,
2175 GstVideoCodecState * state)
2177 GstVideoInfo prev_info = self->input_state->info;
2178 GstVideoInfo *info = &state->info;
2179 GstOMXVideoEncClass *klass;
2181 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
2183 prev_info.fps_n = info->fps_n;
2184 prev_info.fps_d = info->fps_d;
2186 /* if only the framerate changed, try and set the framerate parameter */
2187 if (gst_video_info_is_equal (info, &prev_info)) {
2188 OMX_CONFIG_FRAMERATETYPE config;
2191 GST_DEBUG_OBJECT (self, "Framerate change detected: %d/%d -> %d/%d",
2192 self->input_state->info.fps_n, self->input_state->info.fps_d,
2193 info->fps_n, info->fps_d);
2195 GST_OMX_INIT_STRUCT (&config);
2196 config.nPortIndex = self->enc_in_port->index;
2197 if (klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER)
2198 config.xEncodeFramerate = info->fps_n ? (info->fps_n) / (info->fps_d) : 0;
2200 config.xEncodeFramerate = gst_omx_video_calculate_framerate_q16 (info);
2202 err = gst_omx_component_set_config (self->enc,
2203 OMX_IndexConfigVideoFramerate, &config);
2204 if (err == OMX_ErrorNone) {
2205 gst_video_codec_state_unref (self->input_state);
2206 self->input_state = gst_video_codec_state_ref (state);
2209 GST_WARNING_OBJECT (self,
2210 "Failed to set framerate configuration: %s (0x%08x)",
2211 gst_omx_error_to_string (err), err);
2212 /* if changing the rate dynamically didn't work, keep going with a full
2221 gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
2222 GstVideoCodecState * state)
2224 GstOMXVideoEnc *self;
2225 GstOMXVideoEncClass *klass;
2226 gboolean needs_disable = FALSE;
2227 OMX_PARAM_PORTDEFINITIONTYPE port_def;
2228 GstVideoInfo *info = &state->info;
2229 GList *negotiation_map = NULL, *l;
2232 self = GST_OMX_VIDEO_ENC (encoder);
2233 klass = GST_OMX_VIDEO_ENC_GET_CLASS (encoder);
2235 caps = gst_video_info_to_caps (info);
2236 GST_DEBUG_OBJECT (self, "Setting new input format: %" GST_PTR_FORMAT, caps);
2237 gst_caps_unref (caps);
2239 gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
2242 gst_omx_component_get_state (self->enc,
2243 GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
2244 /* If the component is not in Loaded state and a real format change happens
2245 * we have to disable the port and re-allocate all buffers. If no real
2246 * format change happened we can just exit here.
2248 if (needs_disable) {
2249 if (gst_omx_video_enc_framerate_changed (self, state))
2252 if (!gst_omx_video_enc_disable (self))
2255 if (!self->disabled) {
2256 /* The local port_def is now obsolete so get it again. */
2257 gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
2262 gst_omx_video_get_supported_colorformats (self->enc_in_port,
2264 if (!negotiation_map) {
2266 switch (info->finfo->format) {
2267 case GST_VIDEO_FORMAT_I420:
2268 port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
2270 case GST_VIDEO_FORMAT_NV12:
2271 port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
2273 case GST_VIDEO_FORMAT_NV16:
2274 port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV422SemiPlanar;
2276 case GST_VIDEO_FORMAT_ABGR:
2277 port_def.format.video.eColorFormat = OMX_COLOR_Format32bitARGB8888;
2279 case GST_VIDEO_FORMAT_ARGB:
2280 port_def.format.video.eColorFormat = OMX_COLOR_Format32bitBGRA8888;
2283 GST_ERROR_OBJECT (self, "Unsupported format %s",
2284 gst_video_format_to_string (info->finfo->format));
2289 for (l = negotiation_map; l; l = l->next) {
2290 GstOMXVideoNegotiationMap *m = l->data;
2292 if (m->format == info->finfo->format) {
2293 port_def.format.video.eColorFormat = m->type;
2297 g_list_free_full (negotiation_map,
2298 (GDestroyNotify) gst_omx_video_negotiation_map_free);
2301 port_def.format.video.nFrameWidth = info->width;
2302 port_def.format.video.nFrameHeight = info->height;
2304 if (G_UNLIKELY (klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER))
2305 port_def.format.video.xFramerate =
2306 info->fps_n ? (info->fps_n) / (info->fps_d) : 0;
2308 port_def.format.video.xFramerate =
2309 gst_omx_video_calculate_framerate_q16 (info);
2311 GST_DEBUG_OBJECT (self, "Setting inport port definition");
2312 if (gst_omx_port_update_port_definition (self->enc_in_port,
2313 &port_def) != OMX_ErrorNone)
2316 #ifdef USE_OMX_TARGET_RPI
2320 OMX_CONFIG_POINTTYPE aspect_ratio_param;
2322 GST_OMX_INIT_STRUCT (&aspect_ratio_param);
2323 aspect_ratio_param.nPortIndex = self->enc_out_port->index;
2325 err = gst_omx_component_get_parameter (self->enc,
2326 OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
2328 if (err == OMX_ErrorNone) {
2330 aspect_ratio_param.nX = info->par_n;
2331 aspect_ratio_param.nY = info->par_d;
2334 gst_omx_component_set_parameter (self->enc,
2335 OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
2337 if (err == OMX_ErrorUnsupportedIndex) {
2338 GST_WARNING_OBJECT (self,
2339 "Setting aspect ratio parameters not supported by the component");
2340 } else if (err == OMX_ErrorUnsupportedSetting) {
2341 GST_WARNING_OBJECT (self,
2342 "Setting aspect ratio %u %u not supported by the component",
2343 aspect_ratio_param.nX, aspect_ratio_param.nY);
2344 } else if (err != OMX_ErrorNone) {
2345 GST_ERROR_OBJECT (self,
2346 "Failed to set aspect ratio: %s (0x%08x)",
2347 gst_omx_error_to_string (err), err);
2352 #endif // USE_OMX_TARGET_RPI
2354 if (klass->set_format) {
2355 if (!klass->set_format (self, self->enc_in_port, state)) {
2356 GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
2361 GST_DEBUG_OBJECT (self, "Updating ports definition");
2362 if (gst_omx_port_update_port_definition (self->enc_out_port,
2363 NULL) != OMX_ErrorNone)
2365 if (gst_omx_port_update_port_definition (self->enc_in_port,
2366 NULL) != OMX_ErrorNone)
2369 /* Some OMX implementations reset the bitrate after setting the compression
2370 * format, see bgo#698049, so re-set it */
2371 gst_omx_video_enc_set_bitrate (self);
2373 if (self->input_state)
2374 gst_video_codec_state_unref (self->input_state);
2375 self->input_state = gst_video_codec_state_ref (state);
2377 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2378 gst_omx_video_enc_set_latency (self);
2381 self->downstream_flow_ret = GST_FLOW_OK;
2386 gst_omx_video_enc_flush (GstVideoEncoder * encoder)
2388 GstOMXVideoEnc *self;
2390 self = GST_OMX_VIDEO_ENC (encoder);
2392 GST_DEBUG_OBJECT (self, "Flushing encoder");
2394 if (gst_omx_component_get_state (self->enc, 0) == OMX_StateLoaded)
2397 /* 0) Pause the components */
2398 if (gst_omx_component_get_state (self->enc, 0) == OMX_StateExecuting) {
2399 gst_omx_component_set_state (self->enc, OMX_StatePause);
2400 gst_omx_component_get_state (self->enc, GST_CLOCK_TIME_NONE);
2403 /* 1) Flush the ports */
2404 GST_DEBUG_OBJECT (self, "flushing ports");
2405 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
2406 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
2408 /* Wait until the srcpad loop is finished,
2409 * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
2410 * caused by using this lock from inside the loop function */
2411 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
2412 GST_PAD_STREAM_LOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
2413 GST_PAD_STREAM_UNLOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
2414 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2416 /* 3) Resume components */
2417 gst_omx_component_set_state (self->enc, OMX_StateExecuting);
2418 gst_omx_component_get_state (self->enc, GST_CLOCK_TIME_NONE);
2420 /* 4) Unset flushing to allow ports to accept data again */
2421 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
2422 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);
2423 gst_omx_port_populate (self->enc_out_port);
2425 /* Start the srcpad loop again */
2426 self->last_upstream_ts = 0;
2427 self->downstream_flow_ret = GST_FLOW_OK;
2428 self->started = FALSE;
2429 GST_DEBUG_OBJECT (self, "Flush finished");
2435 gst_omx_video_enc_semi_planar_manual_copy (GstOMXVideoEnc * self,
2436 GstBuffer * inbuf, GstOMXBuffer * outbuf, const GstVideoFormatInfo * finfo)
2438 GstVideoInfo *info = &self->input_state->info;
2439 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
2440 GstVideoFrame frame;
2441 gint i, j, height, width;
2443 gint src_stride, dest_stride;
2445 outbuf->omx_buf->nFilledLen = 0;
2447 if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
2448 GST_ERROR_OBJECT (self, "Invalid input buffer size");
2451 dest_stride = port_def->format.video.nStride;
2453 for (i = 0; i < 2; i++) {
2454 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i);
2455 /* XXX: Try this if no stride was set */
2456 if (dest_stride == 0)
2457 dest_stride = src_stride;
2459 dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
2462 port_def->format.video.nSliceHeight * port_def->format.video.nStride;
2464 src = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
2465 height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
2466 width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i) * (i == 0 ? 1 : 2);
2468 if (GST_VIDEO_FORMAT_INFO_BITS (finfo) == 10)
2469 /* Need ((width + 2) / 3) 32-bits words */
2470 width = (width + 2) / 3 * 4;
2472 if (dest + dest_stride * height >
2473 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nAllocLen) {
2474 GST_ERROR_OBJECT (self, "Invalid output buffer size");
2475 gst_video_frame_unmap (&frame);
2479 for (j = 0; j < height; j++) {
2480 memcpy (dest, src, width);
2482 dest += dest_stride;
2485 /* nFilledLen should include the vertical padding in each slice (spec 3.1.3.7.1) */
2486 outbuf->omx_buf->nFilledLen +=
2487 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i,
2488 port_def->format.video.nSliceHeight) * port_def->format.video.nStride;
2491 gst_video_frame_unmap (&frame);
2496 gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf,
2497 GstOMXBuffer * outbuf)
2499 GstVideoCodecState *state = gst_video_codec_state_ref (self->input_state);
2500 GstVideoInfo *info = &state->info;
2501 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
2502 gboolean ret = FALSE;
2503 GstVideoFrame frame;
2505 if (info->width != port_def->format.video.nFrameWidth ||
2506 info->height != port_def->format.video.nFrameHeight) {
2507 GST_ERROR_OBJECT (self, "Width or height do not match");
2511 if (self->enc_in_port->allocation ==
2512 GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
2513 if (gst_buffer_n_memory (inbuf) > 1) {
2514 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2515 ("input buffer now has more than one memory, can't use dynamic allocation any more"));
2519 if (!self->input_dmabuf) {
2520 /* Map and keep a ref on the buffer while it's being processed
2521 * by the OMX component. */
2522 if (!gst_omx_buffer_map_frame (outbuf, inbuf, info)) {
2523 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2524 ("failed to map input buffer"));
2528 if (!check_input_alignment (self, &outbuf->input_frame.map[0])) {
2529 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2530 ("input buffer now has wrong alignment/stride, can't use dynamic allocation any more"));
2534 GST_LOG_OBJECT (self, "Transfer buffer of %" G_GSIZE_FORMAT " bytes",
2535 gst_buffer_get_size (inbuf));
2538 if (!gst_omx_buffer_import_fd (outbuf, inbuf)) {
2539 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2540 ("failed to import dmabuf"));
2544 GST_LOG_OBJECT (self, "Import dmabuf of %" G_GSIZE_FORMAT " bytes",
2545 gst_buffer_get_size (inbuf));
2552 /* Same strides and everything */
2553 if (gst_buffer_get_size (inbuf) ==
2554 outbuf->omx_buf->nAllocLen - outbuf->omx_buf->nOffset) {
2555 outbuf->omx_buf->nFilledLen = gst_buffer_get_size (inbuf);
2557 GST_LOG_OBJECT (self, "Matched strides - direct copy %u bytes",
2558 (guint) outbuf->omx_buf->nFilledLen);
2560 gst_buffer_extract (inbuf, 0,
2561 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset,
2562 outbuf->omx_buf->nFilledLen);
2567 /* Different strides */
2568 GST_LOG_OBJECT (self, "Mismatched strides - copying line-by-line");
2570 switch (info->finfo->format) {
2571 case GST_VIDEO_FORMAT_I420:{
2572 gint i, j, height, width;
2574 gint src_stride, dest_stride;
2576 outbuf->omx_buf->nFilledLen = 0;
2578 if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
2579 GST_ERROR_OBJECT (self, "Invalid input buffer size");
2584 for (i = 0; i < 3; i++) {
2586 dest_stride = port_def->format.video.nStride;
2588 dest_stride = port_def->format.video.nStride / 2;
2591 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i);
2592 /* XXX: Try this if no stride was set */
2593 if (dest_stride == 0)
2594 dest_stride = src_stride;
2596 dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
2599 port_def->format.video.nSliceHeight *
2600 port_def->format.video.nStride;
2603 (port_def->format.video.nSliceHeight / 2) *
2604 (port_def->format.video.nStride / 2);
2606 src = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
2607 height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
2608 width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i);
2610 if (dest + dest_stride * height >
2611 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nAllocLen) {
2612 gst_video_frame_unmap (&frame);
2613 GST_ERROR_OBJECT (self, "Invalid output buffer size");
2618 for (j = 0; j < height; j++) {
2619 memcpy (dest, src, width);
2621 dest += dest_stride;
2624 /* nFilledLen should include the vertical padding in each slice (spec 3.1.3.7.1) */
2626 outbuf->omx_buf->nFilledLen +=
2627 port_def->format.video.nSliceHeight *
2628 port_def->format.video.nStride;
2630 outbuf->omx_buf->nFilledLen +=
2631 (port_def->format.video.nSliceHeight / 2) *
2632 (port_def->format.video.nStride / 2);
2634 gst_video_frame_unmap (&frame);
2638 case GST_VIDEO_FORMAT_NV12:
2639 case GST_VIDEO_FORMAT_NV16:
2640 case GST_VIDEO_FORMAT_NV12_10LE32:
2641 case GST_VIDEO_FORMAT_NV16_10LE32:
2643 gst_omx_video_enc_semi_planar_manual_copy (self, inbuf, outbuf,
2647 GST_ERROR_OBJECT (self, "Unsupported format");
2654 gst_video_codec_state_unref (state);
2659 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2661 handle_roi_metadata (GstOMXVideoEnc * self, GstBuffer * input)
2664 gpointer state = NULL;
2667 gst_buffer_iterate_meta_filtered (input, &state,
2668 GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE))) {
2669 GstVideoRegionOfInterestMeta *roi = (GstVideoRegionOfInterestMeta *) meta;
2670 OMX_ALG_VIDEO_CONFIG_REGION_OF_INTEREST roi_param;
2673 GST_LOG_OBJECT (self, "Input buffer ROI: type=%s id=%d (%d, %d) %dx%d",
2674 g_quark_to_string (roi->roi_type), roi->id, roi->x, roi->y, roi->w,
2677 if (self->qp_mode != OMX_ALG_ROI_QP) {
2678 GST_WARNING_OBJECT (self,
2679 "Need qp-mode=roi to handle ROI metadata (current: %d); ignoring",
2684 GST_OMX_INIT_STRUCT (&roi_param);
2685 roi_param.nPortIndex = self->enc_in_port->index;
2686 roi_param.nLeft = roi->x;
2687 roi_param.nTop = roi->y;
2688 roi_param.nWidth = roi->w;
2689 roi_param.nHeight = roi->h;
2691 s = gst_video_region_of_interest_meta_get_param (roi, "roi/omx-alg");
2693 const gchar *quality;
2696 quality = gst_structure_get_string (s, "quality");
2699 g_enum_get_value_by_nick (self->alg_roi_quality_enum_class, quality);
2701 roi_param.eQuality = self->default_roi_quality;
2703 GST_WARNING_OBJECT (self,
2704 "Unknown ROI encoding quality '%s', use default (%d)",
2705 quality, self->default_roi_quality);
2707 roi_param.eQuality = evalue->value;
2709 GST_LOG_OBJECT (self, "Use encoding quality '%s' from upstream",
2713 roi_param.eQuality = self->default_roi_quality;
2715 GST_LOG_OBJECT (self, "No quality specified upstream, use default (%d)",
2716 self->default_roi_quality);
2719 gst_omx_component_set_config (self->enc,
2720 (OMX_INDEXTYPE) OMX_ALG_IndexConfigVideoRegionOfInterest, &roi_param);
2725 static GstFlowReturn
2726 gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
2727 GstVideoCodecFrame * frame)
2729 GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
2730 GstOMXVideoEnc *self;
2734 GstClockTimeDiff deadline;
2736 self = GST_OMX_VIDEO_ENC (encoder);
2738 GST_DEBUG_OBJECT (self, "Handling frame");
2740 if (self->downstream_flow_ret != GST_FLOW_OK) {
2741 gst_video_codec_frame_unref (frame);
2742 return self->downstream_flow_ret;
2745 deadline = gst_video_encoder_get_max_encode_time (encoder, frame);
2747 GST_WARNING_OBJECT (self,
2748 "Input frame is too late, dropping (deadline %" GST_TIME_FORMAT ")",
2749 GST_TIME_ARGS (-deadline));
2751 /* Calling finish_frame with frame->output_buffer == NULL will drop it */
2752 return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
2755 if (!self->started) {
2756 if (gst_omx_port_is_flushing (self->enc_out_port)) {
2757 if (!gst_omx_video_enc_enable (self, frame->input_buffer))
2761 GST_DEBUG_OBJECT (self, "Starting task");
2762 gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
2763 (GstTaskFunction) gst_omx_video_enc_loop, self, NULL);
2766 port = self->enc_in_port;
2768 while (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
2769 GstClockTime timestamp, duration;
2770 gboolean fill_buffer = TRUE;
2772 /* Make sure to release the base class stream lock, otherwise
2773 * _loop() can't call _finish_frame() and we might block forever
2774 * because no input buffers are released */
2775 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
2777 if (buffer_is_from_input_pool (self, frame->input_buffer)) {
2778 /* Receiving a buffer from our input pool */
2779 buf = get_omx_buf (frame->input_buffer);
2781 GST_LOG_OBJECT (self,
2782 "Input buffer %p already has a OMX buffer associated: %p",
2783 frame->input_buffer, buf);
2785 g_assert (!buf->input_buffer);
2786 /* Prevent the buffer to be released to the pool while it's being
2787 * processed by OMX. The reference will be dropped in EmptyBufferDone() */
2788 buf->input_buffer = gst_buffer_ref (frame->input_buffer);
2790 acq_ret = GST_OMX_ACQUIRE_BUFFER_OK;
2791 fill_buffer = FALSE;
2792 buf->omx_buf->nFilledLen = gst_buffer_get_size (frame->input_buffer);
2794 acq_ret = gst_omx_port_acquire_buffer (port, &buf, GST_OMX_WAIT);
2797 if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) {
2798 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2799 goto component_error;
2800 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
2801 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2803 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
2804 /* Reallocate all buffers */
2805 err = gst_omx_port_set_enabled (port, FALSE);
2806 if (err != OMX_ErrorNone) {
2807 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2808 goto reconfigure_error;
2811 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
2812 if (err != OMX_ErrorNone) {
2813 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2814 goto reconfigure_error;
2817 err = gst_omx_port_deallocate_buffers (port);
2818 if (err != OMX_ErrorNone) {
2819 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2820 goto reconfigure_error;
2823 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
2824 if (err != OMX_ErrorNone) {
2825 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2826 goto reconfigure_error;
2829 if (!gst_omx_video_enc_ensure_nb_in_buffers (self)) {
2830 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2831 goto reconfigure_error;
2834 err = gst_omx_port_set_enabled (port, TRUE);
2835 if (err != OMX_ErrorNone) {
2836 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2837 goto reconfigure_error;
2840 if (!gst_omx_video_enc_allocate_in_buffers (self)) {
2841 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2842 goto reconfigure_error;
2845 err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
2846 if (err != OMX_ErrorNone) {
2847 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2848 goto reconfigure_error;
2851 err = gst_omx_port_mark_reconfigured (port);
2852 if (err != OMX_ErrorNone) {
2853 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2854 goto reconfigure_error;
2857 /* Now get a new buffer and fill it */
2858 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2861 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2863 g_assert (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
2865 if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <= 0) {
2866 gst_omx_port_release_buffer (port, buf);
2870 if (self->downstream_flow_ret != GST_FLOW_OK) {
2871 gst_omx_port_release_buffer (port, buf);
2875 /* Now handle the frame */
2877 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
2878 #ifdef USE_OMX_TARGET_RPI
2879 OMX_CONFIG_BOOLEANTYPE config;
2881 GST_OMX_INIT_STRUCT (&config);
2882 config.bEnabled = OMX_TRUE;
2884 GST_DEBUG_OBJECT (self, "Forcing a keyframe (iframe on the RPi)");
2887 gst_omx_component_set_config (self->enc,
2888 OMX_IndexConfigBrcmVideoRequestIFrame, &config);
2889 #elif defined(USE_OMX_TARGET_ZYNQ_USCALE_PLUS)
2890 OMX_ALG_VIDEO_CONFIG_INSERT config;
2892 GST_OMX_INIT_STRUCT (&config);
2893 config.nPortIndex = self->enc_out_port->index;
2895 GST_DEBUG_OBJECT (self, "Forcing a keyframe");
2896 err = gst_omx_component_set_config (self->enc, (OMX_INDEXTYPE)
2897 OMX_ALG_IndexConfigVideoInsertInstantaneousDecodingRefresh, &config);
2899 OMX_CONFIG_INTRAREFRESHVOPTYPE config;
2901 GST_OMX_INIT_STRUCT (&config);
2902 config.nPortIndex = port->index;
2903 config.IntraRefreshVOP = OMX_TRUE;
2905 GST_DEBUG_OBJECT (self, "Forcing a keyframe");
2907 gst_omx_component_set_config (self->enc,
2908 OMX_IndexConfigVideoIntraVOPRefresh, &config);
2910 if (err != OMX_ErrorNone)
2911 GST_ERROR_OBJECT (self, "Failed to force a keyframe: %s (0x%08x)",
2912 gst_omx_error_to_string (err), err);
2914 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2915 handle_roi_metadata (self, frame->input_buffer);
2918 /* Copy the buffer content in chunks of size as requested
2921 && !gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) {
2922 gst_omx_port_release_buffer (port, buf);
2923 goto buffer_fill_error;
2926 timestamp = frame->pts;
2927 if (timestamp != GST_CLOCK_TIME_NONE) {
2928 GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp,
2929 gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND));
2930 self->last_upstream_ts = timestamp;
2933 duration = frame->duration;
2934 if (duration != GST_CLOCK_TIME_NONE) {
2935 buf->omx_buf->nTickCount =
2936 gst_util_uint64_scale (duration, OMX_TICKS_PER_SECOND, GST_SECOND);
2937 self->last_upstream_ts += duration;
2939 buf->omx_buf->nTickCount = 0;
2942 self->started = TRUE;
2943 err = gst_omx_port_release_buffer (port, buf);
2944 if (err != OMX_ErrorNone)
2947 GST_DEBUG_OBJECT (self, "Passed frame to component");
2950 gst_video_codec_frame_unref (frame);
2952 return self->downstream_flow_ret;
2956 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2957 ("Got OpenMAX buffer with no free space (%p, %u/%u)", buf,
2958 (guint) buf->omx_buf->nOffset, (guint) buf->omx_buf->nAllocLen));
2959 gst_video_codec_frame_unref (frame);
2960 return GST_FLOW_ERROR;
2965 gst_video_codec_frame_unref (frame);
2966 return self->downstream_flow_ret;
2971 /* Report the OMX error, if any */
2972 if (gst_omx_component_get_last_error (self->enc) != OMX_ErrorNone)
2973 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2974 ("Failed to enable OMX encoder: %s (0x%08x)",
2975 gst_omx_component_get_last_error_string (self->enc),
2976 gst_omx_component_get_last_error (self->enc)));
2978 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2979 ("Failed to enable OMX encoder"));
2980 gst_video_codec_frame_unref (frame);
2981 return GST_FLOW_ERROR;
2986 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2987 ("OpenMAX component in error state %s (0x%08x)",
2988 gst_omx_component_get_last_error_string (self->enc),
2989 gst_omx_component_get_last_error (self->enc)));
2990 gst_video_codec_frame_unref (frame);
2991 return GST_FLOW_ERROR;
2996 GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
2997 gst_video_codec_frame_unref (frame);
2998 return GST_FLOW_FLUSHING;
3002 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
3003 ("Unable to reconfigure input port"));
3004 gst_video_codec_frame_unref (frame);
3005 return GST_FLOW_ERROR;
3009 GST_ELEMENT_ERROR (self, RESOURCE, WRITE, (NULL),
3010 ("Failed to write input into the OpenMAX buffer"));
3011 gst_video_codec_frame_unref (frame);
3012 return GST_FLOW_ERROR;
3016 gst_video_codec_frame_unref (frame);
3017 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
3018 ("Failed to relase input buffer to component: %s (0x%08x)",
3019 gst_omx_error_to_string (err), err));
3020 return GST_FLOW_ERROR;
3024 static GstFlowReturn
3025 gst_omx_video_enc_finish (GstVideoEncoder * encoder)
3027 GstOMXVideoEnc *self;
3029 self = GST_OMX_VIDEO_ENC (encoder);
3031 return gst_omx_video_enc_drain (self);
3034 static GstFlowReturn
3035 gst_omx_video_enc_drain (GstOMXVideoEnc * self)
3037 GstOMXVideoEncClass *klass;
3039 GstOMXAcquireBufferReturn acq_ret;
3042 GST_DEBUG_OBJECT (self, "Draining component");
3044 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
3046 if (!self->started) {
3047 GST_DEBUG_OBJECT (self, "Component not started yet");
3050 self->started = FALSE;
3052 if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
3053 GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
3057 /* Make sure to release the base class stream lock, otherwise
3058 * _loop() can't call _finish_frame() and we might block forever
3059 * because no input buffers are released */
3060 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
3062 /* Send an EOS buffer to the component and let the base
3063 * class drop the EOS event. We will send it later when
3064 * the EOS buffer arrives on the output port. */
3065 acq_ret = gst_omx_port_acquire_buffer (self->enc_in_port, &buf, GST_OMX_WAIT);
3066 if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
3067 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3068 GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d",
3070 return GST_FLOW_ERROR;
3073 g_mutex_lock (&self->drain_lock);
3074 self->draining = TRUE;
3075 buf->omx_buf->nFilledLen = 0;
3076 GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp,
3077 gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND,
3079 buf->omx_buf->nTickCount = 0;
3080 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS;
3081 err = gst_omx_port_release_buffer (self->enc_in_port, buf);
3082 if (err != OMX_ErrorNone) {
3083 GST_ERROR_OBJECT (self, "Failed to drain component: %s (0x%08x)",
3084 gst_omx_error_to_string (err), err);
3085 g_mutex_unlock (&self->drain_lock);
3086 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3087 return GST_FLOW_ERROR;
3089 GST_DEBUG_OBJECT (self, "Waiting until component is drained");
3090 g_cond_wait (&self->drain_cond, &self->drain_lock);
3091 GST_DEBUG_OBJECT (self, "Drained component");
3092 g_mutex_unlock (&self->drain_lock);
3093 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3095 self->started = FALSE;
3100 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3102 pool_request_allocate_cb (GstBufferPool * pool, GstOMXVideoEnc * self)
3104 GstStructure *config;
3107 gst_omx_port_set_dmabuf (self->enc_in_port, TRUE);
3109 config = gst_buffer_pool_get_config (pool);
3111 if (!gst_buffer_pool_config_get_params (config, NULL, NULL, &min, NULL)) {
3112 gst_structure_free (config);
3115 gst_structure_free (config);
3117 GST_DEBUG_OBJECT (self,
3118 "input pool configured for %d buffers, adjust nBufferCountActual", min);
3120 if (!gst_omx_port_update_buffer_count_actual (self->enc_in_port, min))
3123 if (!gst_omx_video_enc_set_to_idle (self))
3126 self->input_allocation = GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
3127 self->input_dmabuf = TRUE;
3129 /* gst_omx_port_acquire_buffer() will fail if the input port is stil flushing
3130 * which will prevent upstream from acquiring buffers. */
3131 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
3136 static GstBufferPool *
3137 create_input_pool (GstOMXVideoEnc * self, GstCaps * caps, guint num_buffers)
3139 GstBufferPool *pool;
3140 GstStructure *config;
3143 gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->enc,
3144 self->enc_in_port, GST_OMX_BUFFER_MODE_DMABUF);
3146 g_signal_connect_object (pool, "allocate",
3147 G_CALLBACK (pool_request_allocate_cb), self, 0);
3149 config = gst_buffer_pool_get_config (pool);
3151 gst_buffer_pool_config_set_params (config, caps,
3152 self->enc_in_port->port_def.nBufferSize, num_buffers, 0);
3154 if (!gst_buffer_pool_set_config (pool, config)) {
3155 GST_INFO_OBJECT (self, "Failed to set config on input pool");
3156 gst_object_unref (pool);
3165 gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
3168 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
3172 GstBufferPool *pool = NULL;
3174 gst_query_parse_allocation (query, &caps, NULL);
3177 GST_WARNING_OBJECT (self, "allocation query does not contain caps");
3181 if (!gst_video_info_from_caps (&info, caps)) {
3182 GST_WARNING_OBJECT (self, "Failed to parse caps %" GST_PTR_FORMAT, caps);
3186 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
3188 num_buffers = self->enc_in_port->port_def.nBufferCountMin + 1;
3190 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3191 /* dmabuf export is currently only supported on Zynqultrascaleplus */
3192 pool = create_input_pool (self, caps, num_buffers);
3194 GST_WARNING_OBJECT (self, "Failed to create and configure pool");
3199 GST_DEBUG_OBJECT (self,
3200 "request at least %d buffers of size %" G_GSIZE_FORMAT, num_buffers,
3202 gst_query_add_allocation_pool (query, pool,
3203 self->enc_in_port->port_def.nBufferSize, num_buffers, 0);
3205 self->in_pool_used = FALSE;
3207 g_clear_object (&pool);
3210 GST_VIDEO_ENCODER_CLASS
3211 (gst_omx_video_enc_parent_class)->propose_allocation (encoder, query);
3215 filter_supported_formats (GList * negotiation_map)
3219 for (cur = negotiation_map; cur != NULL;) {
3220 GstOMXVideoNegotiationMap *nmap = (GstOMXVideoNegotiationMap *) (cur->data);
3223 switch (nmap->format) {
3224 case GST_VIDEO_FORMAT_I420:
3225 case GST_VIDEO_FORMAT_NV12:
3226 case GST_VIDEO_FORMAT_NV12_10LE32:
3227 case GST_VIDEO_FORMAT_NV16:
3228 case GST_VIDEO_FORMAT_NV16_10LE32:
3229 //case GST_VIDEO_FORMAT_ABGR:
3230 //case GST_VIDEO_FORMAT_ARGB:
3231 cur = g_list_next (cur);
3234 gst_omx_video_negotiation_map_free (nmap);
3235 next = g_list_next (cur);
3236 negotiation_map = g_list_delete_link (negotiation_map, cur);
3241 return negotiation_map;
3245 gst_omx_video_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
3247 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
3248 GList *negotiation_map = NULL;
3249 GstCaps *comp_supported_caps;
3253 return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
3256 gst_omx_video_get_supported_colorformats (self->enc_in_port,
3258 negotiation_map = filter_supported_formats (negotiation_map);
3260 comp_supported_caps = gst_omx_video_get_caps_for_map (negotiation_map);
3261 g_list_free_full (negotiation_map,
3262 (GDestroyNotify) gst_omx_video_negotiation_map_free);
3264 if (!gst_caps_is_empty (comp_supported_caps)) {
3266 gst_video_encoder_proxy_getcaps (encoder, comp_supported_caps, filter);
3267 gst_caps_unref (comp_supported_caps);
3269 gst_caps_unref (comp_supported_caps);
3270 ret = gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
3273 GST_LOG_OBJECT (encoder, "Supported caps %" GST_PTR_FORMAT, ret);
3279 gst_omx_video_enc_decide_allocation (GstVideoEncoder * encoder,
3282 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
3285 if (!GST_VIDEO_ENCODER_CLASS
3286 (gst_omx_video_enc_parent_class)->decide_allocation (encoder, query))
3289 if (gst_query_get_n_allocation_pools (query)) {
3290 gst_query_parse_nth_allocation_pool (query, 0, NULL, NULL, &min, NULL);
3291 GST_DEBUG_OBJECT (self,
3292 "Downstream requested %d buffers, adjust number of output buffers accordingly",
3295 GST_DEBUG_OBJECT (self, "Downstream didn't set any allocation pool info");
3298 self->nb_downstream_buffers = min;
3304 gst_omx_video_enc_sink_query (GstVideoEncoder * encoder, GstQuery * query)
3306 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
3308 switch (GST_QUERY_TYPE (query)) {
3309 case GST_QUERY_ALLOCATION:
3310 case GST_QUERY_DRAIN:
3312 GST_DEBUG_OBJECT (encoder, "%s query: drain encoder",
3313 GST_QUERY_TYPE_NAME (query));
3315 gst_omx_video_enc_drain (self);
3323 GST_VIDEO_ENCODER_CLASS (gst_omx_video_enc_parent_class)->sink_query