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,
235 static GstFlowReturn gst_omx_video_enc_drain (GstOMXVideoEnc * self);
237 static GstFlowReturn gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc *
238 self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame);
262 PROP_DEPENDENT_SLICE,
263 PROP_DEFAULT_ROI_QUALITY,
266 /* FIXME: Better defaults */
267 #define GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT (0xffffffff)
268 #define GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT (0xffffffff)
269 #define GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT (0xffffffff)
270 #define GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT (0xffffffff)
271 #define GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT (0xffffffff)
272 #define GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT (0xffffffff)
273 #define GST_OMX_VIDEO_ENC_MIN_QP_DEFAULT (10)
274 #define GST_OMX_VIDEO_ENC_MAX_QP_DEFAULT (51)
275 #define GST_OMX_VIDEO_ENC_GOP_MODE_DEFAULT (OMX_ALG_GOP_MODE_DEFAULT)
276 #define GST_OMX_VIDEO_ENC_GDR_MODE_DEFAULT (OMX_ALG_GDR_OFF)
277 #define GST_OMX_VIDEO_ENC_INITIAL_DELAY_DEFAULT (1500)
278 #define GST_OMX_VIDEO_ENC_CPB_SIZE_DEFAULT (3000)
279 #define GST_OMX_VIDEO_ENC_SCALING_LIST_DEFAULT (OMX_ALG_SCL_DEFAULT)
280 #define GST_OMX_VIDEO_ENC_LOW_BANDWIDTH_DEFAULT (FALSE)
281 #define GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT (0xffffffff)
282 #define GST_OMX_VIDEO_ENC_ASPECT_RATIO_DEFAULT (OMX_ALG_ASPECT_RATIO_AUTO)
283 #define GST_OMX_VIDEO_ENC_FILLER_DATA_DEFAULT (TRUE)
284 #define GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT (0xffffffff)
285 #define GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT (0)
286 #define GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT (FALSE)
287 #define GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY OMX_ALG_ROI_QUALITY_HIGH
289 /* class initialization */
292 GST_DEBUG_CATEGORY_INIT (gst_omx_video_enc_debug_category, "omxvideoenc", 0, \
293 "debug category for gst-omx video encoder base class"); \
294 G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL); \
297 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoEnc, gst_omx_video_enc,
298 GST_TYPE_VIDEO_ENCODER, do_init);
301 gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass)
303 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
304 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
305 GstVideoEncoderClass *video_encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
308 gobject_class->finalize = gst_omx_video_enc_finalize;
309 gobject_class->set_property = gst_omx_video_enc_set_property;
310 gobject_class->get_property = gst_omx_video_enc_get_property;
312 g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
313 g_param_spec_enum ("control-rate", "Control Rate",
314 "Bitrate control method",
315 GST_TYPE_OMX_VIDEO_ENC_CONTROL_RATE,
316 GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT,
317 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
318 GST_PARAM_MUTABLE_READY));
320 g_object_class_install_property (gobject_class, PROP_TARGET_BITRATE,
321 g_param_spec_uint ("target-bitrate", "Target Bitrate",
322 "Target bitrate in bits per second (0xffffffff=component default)",
323 0, G_MAXUINT, GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT,
324 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
325 GST_PARAM_MUTABLE_PLAYING));
327 g_object_class_install_property (gobject_class, PROP_QUANT_I_FRAMES,
328 g_param_spec_uint ("quant-i-frames", "I-Frame Quantization",
329 "Quantization parameter for I-frames (0xffffffff=component default)",
330 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT,
331 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
332 GST_PARAM_MUTABLE_READY));
334 g_object_class_install_property (gobject_class, PROP_QUANT_P_FRAMES,
335 g_param_spec_uint ("quant-p-frames", "P-Frame Quantization",
336 "Quantization parameter for P-frames (0xffffffff=component default)",
337 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT,
338 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
339 GST_PARAM_MUTABLE_READY));
341 g_object_class_install_property (gobject_class, PROP_QUANT_B_FRAMES,
342 g_param_spec_uint ("quant-b-frames", "B-Frame Quantization",
343 "Quantization parameter for B-frames (0xffffffff=component default)",
344 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT,
345 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
346 GST_PARAM_MUTABLE_READY));
348 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
349 g_object_class_install_property (gobject_class, PROP_QP_MODE,
350 g_param_spec_enum ("qp-mode", "QP mode",
351 "QP control mode used by the VCU encoder",
352 GST_TYPE_OMX_VIDEO_ENC_QP_MODE,
353 GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT,
354 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
355 GST_PARAM_MUTABLE_READY));
357 g_object_class_install_property (gobject_class, PROP_MIN_QP,
358 g_param_spec_uint ("min-qp", "min Quantization value",
359 "Minimum QP value allowed for the rate control",
360 0, 51, GST_OMX_VIDEO_ENC_MIN_QP_DEFAULT,
361 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
362 GST_PARAM_MUTABLE_READY));
364 g_object_class_install_property (gobject_class, PROP_MAX_QP,
365 g_param_spec_uint ("max-qp", "max Quantization value",
366 "Maximum QP value allowed for the rate control",
367 0, 51, GST_OMX_VIDEO_ENC_MAX_QP_DEFAULT,
368 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
369 GST_PARAM_MUTABLE_READY));
371 g_object_class_install_property (gobject_class, PROP_GOP_MODE,
372 g_param_spec_enum ("gop-mode", "GOP mode",
373 "Group Of Pictures mode",
374 GST_TYPE_OMX_VIDEO_ENC_GOP_MODE,
375 GST_OMX_VIDEO_ENC_GOP_MODE_DEFAULT,
376 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
377 GST_PARAM_MUTABLE_READY));
379 g_object_class_install_property (gobject_class, PROP_GDR_MODE,
380 g_param_spec_enum ("gdr-mode", "GDR mode",
381 "Gradual Decoder Refresh scheme mode. Only used if gop-mode=low-delay-p",
382 GST_TYPE_OMX_VIDEO_ENC_GDR_MODE,
383 GST_OMX_VIDEO_ENC_GDR_MODE_DEFAULT,
384 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
385 GST_PARAM_MUTABLE_READY));
387 g_object_class_install_property (gobject_class, PROP_INITIAL_DELAY,
388 g_param_spec_uint ("initial-delay", "Initial Delay",
389 "The initial removal delay as specified in the HRD model in msec. "
390 "Not used when control-rate=disable",
391 0, G_MAXUINT, GST_OMX_VIDEO_ENC_INITIAL_DELAY_DEFAULT,
392 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
393 GST_PARAM_MUTABLE_READY));
395 g_object_class_install_property (gobject_class, PROP_CPB_SIZE,
396 g_param_spec_uint ("cpb-size", "CPB size",
397 "Coded Picture Buffer as specified in the HRD model in msec. "
398 "Not used when control-rate=disable",
399 0, G_MAXUINT, GST_OMX_VIDEO_ENC_CPB_SIZE_DEFAULT,
400 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
401 GST_PARAM_MUTABLE_READY));
403 g_object_class_install_property (gobject_class, PROP_SCALING_LIST,
404 g_param_spec_enum ("scaling-list", "Scaling List",
406 GST_TYPE_OMX_VIDEO_ENC_SCALING_LIST,
407 GST_OMX_VIDEO_ENC_SCALING_LIST_DEFAULT,
408 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
409 GST_PARAM_MUTABLE_READY));
411 g_object_class_install_property (gobject_class, PROP_LOW_BANDWIDTH,
412 g_param_spec_boolean ("low-bandwidth", "Low bandwidth mode",
413 "If enabled, decrease the vertical search range "
414 "used for P-frame motion estimation to reduce the bandwidth",
415 GST_OMX_VIDEO_ENC_LOW_BANDWIDTH_DEFAULT,
416 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
417 GST_PARAM_MUTABLE_READY));
419 g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
420 g_param_spec_uint ("max-bitrate", "Max Bitrate",
421 "Max bitrate in bits per second, only used if control-rate=variable (0xffffffff=component default)",
422 0, G_MAXUINT, GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT,
423 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
424 GST_PARAM_MUTABLE_READY));
426 g_object_class_install_property (gobject_class, PROP_ASPECT_RATIO,
427 g_param_spec_enum ("aspect-ratio", "Aspect ratio",
428 "Display aspect ratio of the video sequence to be written in SPS/VUI",
429 GST_TYPE_OMX_VIDEO_ENC_ASPECT_RATIO,
430 GST_OMX_VIDEO_ENC_ASPECT_RATIO_DEFAULT,
431 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
432 GST_PARAM_MUTABLE_READY));
434 g_object_class_install_property (gobject_class, PROP_FILLER_DATA,
435 g_param_spec_boolean ("filler-data", "Filler Data",
436 "Enable/Disable Filler Data NAL units for CBR rate control",
437 GST_OMX_VIDEO_ENC_FILLER_DATA_DEFAULT,
438 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
439 GST_PARAM_MUTABLE_READY));
441 g_object_class_install_property (gobject_class, PROP_NUM_SLICES,
442 g_param_spec_uint ("num-slices", "Number of slices",
443 "Number of slices produced for each frame. Each slice contains one or more complete macroblock/CTU row(s). "
444 "Slices are distributed over the frame as regularly as possible. If slice-size is defined as well more slices "
445 "may be produced to fit the slice-size requirement (0xffffffff=component default)",
446 1, G_MAXUINT, GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT,
447 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
448 GST_PARAM_MUTABLE_READY));
450 g_object_class_install_property (gobject_class, PROP_SLICE_SIZE,
451 g_param_spec_uint ("slice-size", "Target slice size",
452 "Target slice size (in bytes) that the encoder uses to "
453 "automatically split the bitstream into approximately equally-sized slices",
454 0, 65535, GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT,
455 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
456 GST_PARAM_MUTABLE_READY));
458 g_object_class_install_property (gobject_class, PROP_DEPENDENT_SLICE,
459 g_param_spec_boolean ("dependent-slice", "Dependent slice",
460 "If encoding with multiple slices, specify whether the additional slices are "
461 "dependent slice segments or regular slices",
462 GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT,
463 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
465 g_object_class_install_property (gobject_class, PROP_DEFAULT_ROI_QUALITY,
466 g_param_spec_enum ("default-roi-quality", "Default ROI Qualtiy",
467 "The default quality level to apply to each Region of Interest",
468 GST_TYPE_OMX_VIDEO_ENC_ROI_QUALITY,
469 GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY,
470 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
473 element_class->change_state =
474 GST_DEBUG_FUNCPTR (gst_omx_video_enc_change_state);
476 video_encoder_class->open = GST_DEBUG_FUNCPTR (gst_omx_video_enc_open);
477 video_encoder_class->close = GST_DEBUG_FUNCPTR (gst_omx_video_enc_close);
478 video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_enc_start);
479 video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_enc_stop);
480 video_encoder_class->flush = GST_DEBUG_FUNCPTR (gst_omx_video_enc_flush);
481 video_encoder_class->set_format =
482 GST_DEBUG_FUNCPTR (gst_omx_video_enc_set_format);
483 video_encoder_class->handle_frame =
484 GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_frame);
485 video_encoder_class->finish = GST_DEBUG_FUNCPTR (gst_omx_video_enc_finish);
486 video_encoder_class->propose_allocation =
487 GST_DEBUG_FUNCPTR (gst_omx_video_enc_propose_allocation);
488 video_encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_omx_video_enc_getcaps);
489 video_encoder_class->decide_allocation =
490 GST_DEBUG_FUNCPTR (gst_omx_video_enc_decide_allocation);
492 klass->cdata.type = GST_OMX_COMPONENT_TYPE_FILTER;
493 klass->cdata.default_sink_template_caps =
494 GST_VIDEO_CAPS_MAKE (GST_OMX_VIDEO_SUPPORTED_FORMATS);
496 klass->handle_output_frame =
497 GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_output_frame);
501 gst_omx_video_enc_init (GstOMXVideoEnc * self)
503 self->control_rate = GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT;
504 self->target_bitrate = GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT;
505 self->quant_i_frames = GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT;
506 self->quant_p_frames = GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT;
507 self->quant_b_frames = GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT;
508 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
509 self->qp_mode = GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT;
510 self->min_qp = GST_OMX_VIDEO_ENC_MIN_QP_DEFAULT;
511 self->max_qp = GST_OMX_VIDEO_ENC_MAX_QP_DEFAULT;
512 self->gop_mode = GST_OMX_VIDEO_ENC_GOP_MODE_DEFAULT;
513 self->gdr_mode = GST_OMX_VIDEO_ENC_GDR_MODE_DEFAULT;
514 self->initial_delay = GST_OMX_VIDEO_ENC_INITIAL_DELAY_DEFAULT;
515 self->cpb_size = GST_OMX_VIDEO_ENC_CPB_SIZE_DEFAULT;
516 self->scaling_list = GST_OMX_VIDEO_ENC_SCALING_LIST_DEFAULT;
517 self->low_bandwidth = GST_OMX_VIDEO_ENC_LOW_BANDWIDTH_DEFAULT;
518 self->max_bitrate = GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT;
519 self->aspect_ratio = GST_OMX_VIDEO_ENC_ASPECT_RATIO_DEFAULT;
520 self->filler_data = GST_OMX_VIDEO_ENC_FILLER_DATA_DEFAULT;
521 self->num_slices = GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT;
522 self->slice_size = GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT;
523 self->dependent_slice = GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT;
524 self->default_roi_quality = GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY;
527 self->default_target_bitrate = GST_OMX_PROP_OMX_DEFAULT;
529 g_mutex_init (&self->drain_lock);
530 g_cond_init (&self->drain_cond);
532 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
533 self->alg_roi_quality_enum_class =
534 g_type_class_ref (GST_TYPE_OMX_VIDEO_ENC_ROI_QUALITY);
538 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
540 #define CHECK_ERR(setting) \
541 if (err == OMX_ErrorUnsupportedIndex || err == OMX_ErrorUnsupportedSetting) { \
542 GST_WARNING_OBJECT (self, \
543 "Setting " setting " parameters not supported by the component"); \
544 } else if (err != OMX_ErrorNone) { \
545 GST_ERROR_OBJECT (self, \
546 "Failed to set " setting " parameters: %s (0x%08x)", \
547 gst_omx_error_to_string (err), err); \
552 set_zynqultrascaleplus_props (GstOMXVideoEnc * self)
556 if (self->qp_mode != GST_OMX_VIDEO_ENC_QP_MODE_DEFAULT) {
557 OMX_ALG_VIDEO_PARAM_QUANTIZATION_CONTROL quant;
559 GST_OMX_INIT_STRUCT (&quant);
560 quant.nPortIndex = self->enc_out_port->index;
561 quant.eQpControlMode = self->qp_mode;
563 GST_DEBUG_OBJECT (self, "setting QP mode to %d", self->qp_mode);
566 gst_omx_component_set_parameter (self->enc,
567 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoQuantizationControl, &quant);
568 CHECK_ERR ("quantization");
572 OMX_ALG_VIDEO_PARAM_QUANTIZATION_EXTENSION qp_values;
574 GST_OMX_INIT_STRUCT (&qp_values);
575 qp_values.nPortIndex = self->enc_out_port->index;
576 qp_values.nQpMin = self->min_qp;
577 qp_values.nQpMax = self->max_qp;
579 GST_DEBUG_OBJECT (self, "setting min QP as %d and max QP as %d",
580 self->min_qp, self->max_qp);
583 gst_omx_component_set_parameter (self->enc,
584 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoQuantizationExtension,
586 CHECK_ERR ("min-qp and max-qp");
590 OMX_ALG_VIDEO_PARAM_GOP_CONTROL gop_mode;
592 if (self->gdr_mode != OMX_ALG_GDR_OFF &&
593 self->gop_mode != OMX_ALG_GOP_MODE_LOW_DELAY_P) {
594 GST_ERROR_OBJECT (self,
595 "gdr-mode mode only can be set if gop-mode=low-delay-p");
599 GST_OMX_INIT_STRUCT (&gop_mode);
600 gop_mode.nPortIndex = self->enc_out_port->index;
601 gop_mode.eGopControlMode = self->gop_mode;
602 gop_mode.eGdrMode = self->gdr_mode;
604 GST_DEBUG_OBJECT (self, "setting GOP mode to %d and GDR mode to %d",
605 self->gop_mode, self->gdr_mode);
608 gst_omx_component_set_parameter (self->enc,
609 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoGopControl, &gop_mode);
610 CHECK_ERR ("GOP & GDR");
613 if (self->control_rate != OMX_Video_ControlRateDisable) {
614 if (self->cpb_size < self->initial_delay) {
615 GST_ERROR_OBJECT (self,
616 "cpb-size (%d) cannot be smaller than initial-delay (%d)",
617 self->cpb_size, self->initial_delay);
618 g_critical ("cpb-size (%d) cannot be smaller than initial-delay (%d)",
619 self->cpb_size, self->initial_delay);
621 OMX_ALG_VIDEO_PARAM_CODED_PICTURE_BUFFER cpb;
623 GST_OMX_INIT_STRUCT (&cpb);
624 cpb.nPortIndex = self->enc_out_port->index;
625 cpb.nCodedPictureBufferSize = self->cpb_size;
626 cpb.nInitialRemovalDelay = self->initial_delay;
628 GST_DEBUG_OBJECT (self, "setting cpb size to %d and initial delay to %d",
629 self->cpb_size, self->initial_delay);
632 gst_omx_component_set_parameter (self->enc,
633 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoCodedPictureBuffer, &cpb);
634 CHECK_ERR ("cpb size & initial delay");
639 OMX_ALG_VIDEO_PARAM_SCALING_LIST scaling_list;
641 GST_OMX_INIT_STRUCT (&scaling_list);
642 scaling_list.nPortIndex = self->enc_out_port->index;
643 scaling_list.eScalingListMode = self->scaling_list;
645 GST_DEBUG_OBJECT (self, "setting scaling list mode as %d",
649 gst_omx_component_set_parameter (self->enc,
650 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoScalingList, &scaling_list);
651 CHECK_ERR ("scaling-list");
655 OMX_ALG_VIDEO_PARAM_LOW_BANDWIDTH low_bw;
657 GST_OMX_INIT_STRUCT (&low_bw);
658 low_bw.nPortIndex = self->enc_out_port->index;
659 low_bw.bEnableLowBandwidth = self->low_bandwidth;
661 GST_DEBUG_OBJECT (self, "%s low bandwith moded",
662 self->low_bandwidth ? "Enable" : "Disable");
665 gst_omx_component_set_parameter (self->enc,
666 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoLowBandwidth, &low_bw);
667 CHECK_ERR ("low-bandwidth");
670 if (self->max_bitrate != GST_OMX_VIDEO_ENC_MAX_BITRATE_DEFAULT) {
671 OMX_ALG_VIDEO_PARAM_MAX_BITRATE max_bitrate;
673 GST_OMX_INIT_STRUCT (&max_bitrate);
674 max_bitrate.nPortIndex = self->enc_out_port->index;
675 /* nMaxBitrate is in kbps while max-bitrate is in bps */
676 max_bitrate.nMaxBitrate = self->max_bitrate / 1000;
678 GST_DEBUG_OBJECT (self, "setting max bitrate to %d", self->max_bitrate);
681 gst_omx_component_set_parameter (self->enc,
682 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoMaxBitrate, &max_bitrate);
683 CHECK_ERR ("max-bitrate");
687 OMX_ALG_VIDEO_PARAM_ASPECT_RATIO aspect_ratio;
689 GST_OMX_INIT_STRUCT (&aspect_ratio);
690 aspect_ratio.nPortIndex = self->enc_out_port->index;
691 aspect_ratio.eAspectRatio = self->aspect_ratio;
693 GST_DEBUG_OBJECT (self, "setting aspect ratio to %d", self->aspect_ratio);
696 gst_omx_component_set_parameter (self->enc,
697 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoAspectRatio, &aspect_ratio);
698 CHECK_ERR ("aspect-ratio");
702 OMX_ALG_VIDEO_PARAM_FILLER_DATA filler_data;
704 GST_OMX_INIT_STRUCT (&filler_data);
705 filler_data.nPortIndex = self->enc_out_port->index;
706 filler_data.bDisableFillerData = !(self->filler_data);
708 GST_DEBUG_OBJECT (self, "%s filler data",
709 self->filler_data ? "Enable" : "Disable");
712 gst_omx_component_set_parameter (self->enc,
713 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoFillerData, &filler_data);
714 CHECK_ERR ("filler-data");
717 if (self->num_slices != GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT ||
718 self->slice_size != GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT) {
719 OMX_ALG_VIDEO_PARAM_SLICES slices;
721 GST_OMX_INIT_STRUCT (&slices);
722 slices.nPortIndex = self->enc_out_port->index;
724 err = gst_omx_component_get_parameter (self->enc,
725 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoSlices, &slices);
726 if (err != OMX_ErrorNone) {
727 GST_WARNING_OBJECT (self, "Error getting slice parameters: %s (0x%08x)",
728 gst_omx_error_to_string (err), err);
732 if (self->num_slices != GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT) {
733 slices.nNumSlices = self->num_slices;
734 GST_DEBUG_OBJECT (self,
735 "setting number of slices to %d (dependent slices: %d)",
736 self->num_slices, self->dependent_slice);
739 if (self->slice_size != GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT) {
740 slices.nSlicesSize = self->slice_size;
741 GST_DEBUG_OBJECT (self, "setting slice size to %d (dependent slices: %d)",
742 self->slice_size, self->dependent_slice);
745 slices.bDependentSlices = self->dependent_slice;
748 gst_omx_component_set_parameter (self->enc,
749 (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoSlices, &slices);
750 CHECK_ERR ("slices");
758 gst_omx_video_enc_set_bitrate (GstOMXVideoEnc * self)
761 OMX_VIDEO_PARAM_BITRATETYPE bitrate_param;
762 gboolean result = TRUE;
764 GST_OBJECT_LOCK (self);
766 GST_OMX_INIT_STRUCT (&bitrate_param);
767 bitrate_param.nPortIndex = self->enc_out_port->index;
769 err = gst_omx_component_get_parameter (self->enc,
770 OMX_IndexParamVideoBitrate, &bitrate_param);
772 if (err == OMX_ErrorNone) {
773 #ifdef USE_OMX_TARGET_RPI
774 /* FIXME: Workaround for RPi returning garbage for this parameter */
775 if (bitrate_param.nVersion.nVersion == 0) {
776 GST_OMX_INIT_STRUCT (&bitrate_param);
777 bitrate_param.nPortIndex = self->enc_out_port->index;
780 if (self->default_target_bitrate == GST_OMX_PROP_OMX_DEFAULT)
781 /* Save the actual OMX default so we can restore it if needed */
782 self->default_target_bitrate = bitrate_param.nTargetBitrate;
784 if (self->control_rate != 0xffffffff)
785 bitrate_param.eControlRate = self->control_rate;
786 if (self->target_bitrate != 0xffffffff)
787 bitrate_param.nTargetBitrate = self->target_bitrate;
789 bitrate_param.nTargetBitrate = self->default_target_bitrate;
792 gst_omx_component_set_parameter (self->enc,
793 OMX_IndexParamVideoBitrate, &bitrate_param);
794 if (err == OMX_ErrorUnsupportedIndex) {
795 GST_WARNING_OBJECT (self,
796 "Setting a bitrate not supported by the component");
797 } else if (err == OMX_ErrorUnsupportedSetting) {
798 GST_WARNING_OBJECT (self,
799 "Setting bitrate settings %u %u not supported by the component",
800 self->control_rate, self->target_bitrate);
801 } else if (err != OMX_ErrorNone) {
802 GST_ERROR_OBJECT (self,
803 "Failed to set bitrate parameters: %s (0x%08x)",
804 gst_omx_error_to_string (err), err);
808 GST_ERROR_OBJECT (self, "Failed to get bitrate parameters: %s (0x%08x)",
809 gst_omx_error_to_string (err), err);
812 GST_OBJECT_UNLOCK (self);
817 gst_omx_video_enc_open (GstVideoEncoder * encoder)
819 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
820 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
821 gint in_port_index, out_port_index;
824 gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
825 klass->cdata.component_name, klass->cdata.component_role,
827 self->started = FALSE;
832 if (gst_omx_component_get_state (self->enc,
833 GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
836 in_port_index = klass->cdata.in_port_index;
837 out_port_index = klass->cdata.out_port_index;
839 if (in_port_index == -1 || out_port_index == -1) {
840 OMX_PORT_PARAM_TYPE param;
843 GST_OMX_INIT_STRUCT (¶m);
846 gst_omx_component_get_parameter (self->enc, OMX_IndexParamVideoInit,
848 if (err != OMX_ErrorNone) {
849 GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
850 gst_omx_error_to_string (err), err);
855 GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
856 (guint) param.nPorts, (guint) param.nStartPortNumber);
857 in_port_index = param.nStartPortNumber + 0;
858 out_port_index = param.nStartPortNumber + 1;
862 self->enc_in_port = gst_omx_component_add_port (self->enc, in_port_index);
863 self->enc_out_port = gst_omx_component_add_port (self->enc, out_port_index);
865 if (!self->enc_in_port || !self->enc_out_port)
872 if (!gst_omx_video_enc_set_bitrate (self))
875 if (self->quant_i_frames != 0xffffffff ||
876 self->quant_p_frames != 0xffffffff ||
877 self->quant_b_frames != 0xffffffff) {
878 OMX_VIDEO_PARAM_QUANTIZATIONTYPE quant_param;
880 GST_OMX_INIT_STRUCT (&quant_param);
881 quant_param.nPortIndex = self->enc_out_port->index;
883 err = gst_omx_component_get_parameter (self->enc,
884 OMX_IndexParamVideoQuantization, &quant_param);
886 if (err == OMX_ErrorNone) {
888 if (self->quant_i_frames != 0xffffffff)
889 quant_param.nQpI = self->quant_i_frames;
890 if (self->quant_p_frames != 0xffffffff)
891 quant_param.nQpP = self->quant_p_frames;
892 if (self->quant_b_frames != 0xffffffff)
893 quant_param.nQpB = self->quant_b_frames;
896 gst_omx_component_set_parameter (self->enc,
897 OMX_IndexParamVideoQuantization, &quant_param);
898 if (err == OMX_ErrorUnsupportedIndex) {
899 GST_WARNING_OBJECT (self,
900 "Setting quantization parameters not supported by the component");
901 } else if (err == OMX_ErrorUnsupportedSetting) {
902 GST_WARNING_OBJECT (self,
903 "Setting quantization parameters %u %u %u not supported by the component",
904 self->quant_i_frames, self->quant_p_frames, self->quant_b_frames);
905 } else if (err != OMX_ErrorNone) {
906 GST_ERROR_OBJECT (self,
907 "Failed to set quantization parameters: %s (0x%08x)",
908 gst_omx_error_to_string (err), err);
912 GST_ERROR_OBJECT (self,
913 "Failed to get quantization parameters: %s (0x%08x)",
914 gst_omx_error_to_string (err), err);
919 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
920 if (!set_zynqultrascaleplus_props (self))
928 gst_omx_video_enc_deallocate_in_buffers (GstOMXVideoEnc * self)
930 /* Pool will take care of deallocating buffers when deactivated upstream */
931 if (!self->in_pool_used
932 && gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone)
939 gst_omx_video_enc_shutdown (GstOMXVideoEnc * self)
943 GST_DEBUG_OBJECT (self, "Shutting down encoder");
945 state = gst_omx_component_get_state (self->enc, 0);
946 if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
947 if (state > OMX_StateIdle) {
948 gst_omx_component_set_state (self->enc, OMX_StateIdle);
949 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
951 gst_omx_component_set_state (self->enc, OMX_StateLoaded);
952 gst_omx_video_enc_deallocate_in_buffers (self);
953 gst_omx_port_deallocate_buffers (self->enc_out_port);
954 if (state > OMX_StateLoaded)
955 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
962 gst_omx_video_enc_close (GstVideoEncoder * encoder)
964 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
966 GST_DEBUG_OBJECT (self, "Closing encoder");
968 if (!gst_omx_video_enc_shutdown (self))
971 self->enc_in_port = NULL;
972 self->enc_out_port = NULL;
974 gst_omx_component_unref (self->enc);
977 self->started = FALSE;
983 gst_omx_video_enc_finalize (GObject * object)
985 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
987 g_mutex_clear (&self->drain_lock);
988 g_cond_clear (&self->drain_cond);
990 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
991 g_clear_pointer (&self->alg_roi_quality_enum_class, g_type_class_unref);
994 G_OBJECT_CLASS (gst_omx_video_enc_parent_class)->finalize (object);
998 gst_omx_video_enc_set_property (GObject * object, guint prop_id,
999 const GValue * value, GParamSpec * pspec)
1001 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
1004 case PROP_CONTROL_RATE:
1005 self->control_rate = g_value_get_enum (value);
1007 case PROP_TARGET_BITRATE:
1008 GST_OBJECT_LOCK (self);
1009 self->target_bitrate = g_value_get_uint (value);
1011 OMX_VIDEO_CONFIG_BITRATETYPE config;
1014 GST_OMX_INIT_STRUCT (&config);
1015 config.nPortIndex = self->enc_out_port->index;
1016 config.nEncodeBitrate = self->target_bitrate;
1018 gst_omx_component_set_config (self->enc,
1019 OMX_IndexConfigVideoBitrate, &config);
1020 if (err != OMX_ErrorNone)
1021 GST_ERROR_OBJECT (self,
1022 "Failed to set bitrate parameter: %s (0x%08x)",
1023 gst_omx_error_to_string (err), err);
1025 GST_OBJECT_UNLOCK (self);
1027 case PROP_QUANT_I_FRAMES:
1028 self->quant_i_frames = g_value_get_uint (value);
1030 case PROP_QUANT_P_FRAMES:
1031 self->quant_p_frames = g_value_get_uint (value);
1033 case PROP_QUANT_B_FRAMES:
1034 self->quant_b_frames = g_value_get_uint (value);
1036 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1038 self->qp_mode = g_value_get_enum (value);
1041 self->min_qp = g_value_get_uint (value);
1044 self->max_qp = g_value_get_uint (value);
1047 self->gop_mode = g_value_get_enum (value);
1050 self->gdr_mode = g_value_get_enum (value);
1052 case PROP_INITIAL_DELAY:
1053 self->initial_delay = g_value_get_uint (value);
1056 self->cpb_size = g_value_get_uint (value);
1058 case PROP_SCALING_LIST:
1059 self->scaling_list = g_value_get_enum (value);
1061 case PROP_LOW_BANDWIDTH:
1062 self->low_bandwidth = g_value_get_boolean (value);
1064 case PROP_MAX_BITRATE:
1065 self->max_bitrate = g_value_get_uint (value);
1067 case PROP_ASPECT_RATIO:
1068 self->aspect_ratio = g_value_get_enum (value);
1070 case PROP_FILLER_DATA:
1071 self->filler_data = g_value_get_boolean (value);
1073 case PROP_NUM_SLICES:
1074 self->num_slices = g_value_get_uint (value);
1076 case PROP_SLICE_SIZE:
1077 self->slice_size = g_value_get_uint (value);
1079 case PROP_DEPENDENT_SLICE:
1080 self->dependent_slice = g_value_get_boolean (value);
1082 case PROP_DEFAULT_ROI_QUALITY:
1083 self->default_roi_quality = g_value_get_enum (value);
1087 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1093 gst_omx_video_enc_get_property (GObject * object, guint prop_id, GValue * value,
1096 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
1099 case PROP_CONTROL_RATE:
1100 g_value_set_enum (value, self->control_rate);
1102 case PROP_TARGET_BITRATE:
1103 GST_OBJECT_LOCK (self);
1104 g_value_set_uint (value, self->target_bitrate);
1105 GST_OBJECT_UNLOCK (self);
1107 case PROP_QUANT_I_FRAMES:
1108 g_value_set_uint (value, self->quant_i_frames);
1110 case PROP_QUANT_P_FRAMES:
1111 g_value_set_uint (value, self->quant_p_frames);
1113 case PROP_QUANT_B_FRAMES:
1114 g_value_set_uint (value, self->quant_b_frames);
1116 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1118 g_value_set_enum (value, self->qp_mode);
1121 g_value_set_uint (value, self->min_qp);
1124 g_value_set_uint (value, self->max_qp);
1127 g_value_set_enum (value, self->gop_mode);
1130 g_value_set_enum (value, self->gdr_mode);
1132 case PROP_INITIAL_DELAY:
1133 g_value_set_uint (value, self->initial_delay);
1136 g_value_set_uint (value, self->cpb_size);
1138 case PROP_SCALING_LIST:
1139 g_value_set_enum (value, self->scaling_list);
1141 case PROP_LOW_BANDWIDTH:
1142 g_value_set_boolean (value, self->low_bandwidth);
1144 case PROP_MAX_BITRATE:
1145 g_value_set_uint (value, self->max_bitrate);
1147 case PROP_ASPECT_RATIO:
1148 g_value_set_enum (value, self->aspect_ratio);
1150 case PROP_FILLER_DATA:
1151 g_value_set_boolean (value, self->filler_data);
1153 case PROP_NUM_SLICES:
1154 g_value_set_uint (value, self->num_slices);
1156 case PROP_SLICE_SIZE:
1157 g_value_set_uint (value, self->slice_size);
1159 case PROP_DEPENDENT_SLICE:
1160 g_value_set_boolean (value, self->dependent_slice);
1162 case PROP_DEFAULT_ROI_QUALITY:
1163 g_value_set_enum (value, self->default_roi_quality);
1167 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1172 static GstStateChangeReturn
1173 gst_omx_video_enc_change_state (GstElement * element, GstStateChange transition)
1175 GstOMXVideoEnc *self;
1176 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1178 g_return_val_if_fail (GST_IS_OMX_VIDEO_ENC (element),
1179 GST_STATE_CHANGE_FAILURE);
1180 self = GST_OMX_VIDEO_ENC (element);
1182 switch (transition) {
1183 case GST_STATE_CHANGE_NULL_TO_READY:
1185 case GST_STATE_CHANGE_READY_TO_PAUSED:
1186 self->downstream_flow_ret = GST_FLOW_OK;
1188 self->draining = FALSE;
1189 self->started = FALSE;
1191 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1193 case GST_STATE_CHANGE_PAUSED_TO_READY:
1194 if (self->enc_in_port)
1195 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
1196 if (self->enc_out_port)
1197 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1199 g_mutex_lock (&self->drain_lock);
1200 self->draining = FALSE;
1201 g_cond_broadcast (&self->drain_cond);
1202 g_mutex_unlock (&self->drain_lock);
1208 if (ret == GST_STATE_CHANGE_FAILURE)
1212 GST_ELEMENT_CLASS (gst_omx_video_enc_parent_class)->change_state (element,
1215 if (ret == GST_STATE_CHANGE_FAILURE)
1218 switch (transition) {
1219 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1221 case GST_STATE_CHANGE_PAUSED_TO_READY:
1222 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1223 self->started = FALSE;
1225 case GST_STATE_CHANGE_READY_TO_NULL:
1235 get_chroma_info_from_input (GstOMXVideoEnc * self, const gchar ** chroma_format,
1236 guint * bit_depth_luma, guint * bit_depth_chroma)
1238 switch (self->input_state->info.finfo->format) {
1239 case GST_VIDEO_FORMAT_GRAY8:
1240 *chroma_format = "4:0:0";
1241 *bit_depth_luma = 8;
1242 *bit_depth_chroma = 0;
1244 case GST_VIDEO_FORMAT_I420:
1245 case GST_VIDEO_FORMAT_NV12:
1246 *chroma_format = "4:2:0";
1247 *bit_depth_luma = *bit_depth_chroma = 8;
1249 case GST_VIDEO_FORMAT_NV16:
1250 case GST_VIDEO_FORMAT_YUY2:
1251 case GST_VIDEO_FORMAT_YVYU:
1252 case GST_VIDEO_FORMAT_UYVY:
1253 *chroma_format = "4:2:2";
1254 *bit_depth_luma = *bit_depth_chroma = 8;
1256 case GST_VIDEO_FORMAT_GRAY10_LE32:
1257 *chroma_format = "4:0:0";
1258 *bit_depth_luma = 10;
1259 *bit_depth_chroma = 0;
1261 case GST_VIDEO_FORMAT_NV12_10LE32:
1262 *chroma_format = "4:2:0";
1263 *bit_depth_luma = *bit_depth_chroma = 10;
1265 case GST_VIDEO_FORMAT_NV16_10LE32:
1266 *chroma_format = "4:2:2";
1267 *bit_depth_luma = *bit_depth_chroma = 10;
1277 get_output_caps (GstOMXVideoEnc * self)
1279 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1281 const gchar *chroma_format;
1282 guint bit_depth_luma, bit_depth_chroma;
1284 caps = klass->get_caps (self, self->enc_out_port, self->input_state);
1286 /* Add chroma info about the encoded stream inferred from the format of the input */
1287 if (get_chroma_info_from_input (self, &chroma_format, &bit_depth_luma,
1288 &bit_depth_chroma)) {
1289 GST_DEBUG_OBJECT (self,
1290 "adding chroma info to output caps: %s (luma %d bits) (chroma %d bits)",
1291 chroma_format, bit_depth_luma, bit_depth_chroma);
1293 gst_caps_set_simple (caps, "chroma-format", G_TYPE_STRING, chroma_format,
1294 "bit-depth-luma", G_TYPE_UINT, bit_depth_luma,
1295 "bit-depth-chroma", G_TYPE_UINT, bit_depth_chroma, NULL);
1301 static GstFlowReturn
1302 gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port,
1303 GstOMXBuffer * buf, GstVideoCodecFrame * frame)
1305 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1306 GstFlowReturn flow_ret = GST_FLOW_OK;
1308 if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG)
1309 && buf->omx_buf->nFilledLen > 0) {
1310 GstVideoCodecState *state;
1311 GstBuffer *codec_data;
1312 GstMapInfo map = GST_MAP_INFO_INIT;
1315 GST_DEBUG_OBJECT (self, "Handling codec data");
1317 caps = get_output_caps (self);
1318 codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
1320 gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
1322 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
1323 buf->omx_buf->nFilledLen);
1324 gst_buffer_unmap (codec_data, &map);
1326 gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
1328 state->codec_data = codec_data;
1329 gst_video_codec_state_unref (state);
1330 if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) {
1331 gst_video_codec_frame_unref (frame);
1332 GST_ERROR_OBJECT (self,
1333 "Downstream element refused to negotiate codec_data in the caps");
1334 return GST_FLOW_NOT_NEGOTIATED;
1336 gst_video_codec_frame_unref (frame);
1337 flow_ret = GST_FLOW_OK;
1338 } else if (buf->omx_buf->nFilledLen > 0) {
1340 GstMapInfo map = GST_MAP_INFO_INIT;
1342 GST_DEBUG_OBJECT (self, "Handling output data");
1344 outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
1346 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
1348 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
1349 buf->omx_buf->nFilledLen);
1350 gst_buffer_unmap (outbuf, &map);
1352 GST_BUFFER_TIMESTAMP (outbuf) =
1353 gst_util_uint64_scale (GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp),
1354 GST_SECOND, OMX_TICKS_PER_SECOND);
1355 if (buf->omx_buf->nTickCount != 0)
1356 GST_BUFFER_DURATION (outbuf) =
1357 gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND,
1358 OMX_TICKS_PER_SECOND);
1360 if ((klass->cdata.hacks & GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED)
1361 || (buf->omx_buf->nFlags & OMX_BUFFERFLAG_SYNCFRAME)) {
1363 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1365 GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1368 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
1370 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1374 frame->output_buffer = outbuf;
1376 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
1378 GST_ERROR_OBJECT (self, "No corresponding frame found");
1379 flow_ret = gst_pad_push (GST_VIDEO_ENCODER_SRC_PAD (self), outbuf);
1381 } else if (frame != NULL) {
1382 /* Just ignore empty buffers, don't drop a frame for that */
1383 flow_ret = GST_FLOW_OK;
1384 gst_video_codec_frame_unref (frame);
1391 gst_omx_video_enc_ensure_nb_out_buffers (GstOMXVideoEnc * self)
1393 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1396 if (!(klass->cdata.hacks & GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL))
1399 /* If dowstream tell us how many buffers it needs allocate as many extra buffers so we won't starve
1400 * if it keeps them downstream (like when using dynamic mode). */
1401 if (self->nb_downstream_buffers)
1402 extra = self->nb_downstream_buffers;
1404 if (!gst_omx_port_ensure_buffer_count_actual (self->enc_out_port, extra))
1411 gst_omx_video_enc_pause_loop (GstOMXVideoEnc * self, GstFlowReturn flow_ret)
1413 g_mutex_lock (&self->drain_lock);
1414 if (self->draining) {
1415 self->draining = FALSE;
1416 g_cond_broadcast (&self->drain_cond);
1418 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1419 self->downstream_flow_ret = flow_ret;
1420 self->started = FALSE;
1421 g_mutex_unlock (&self->drain_lock);
1425 gst_omx_video_enc_loop (GstOMXVideoEnc * self)
1427 GstOMXVideoEncClass *klass;
1428 GstOMXPort *port = self->enc_out_port;
1429 GstOMXBuffer *buf = NULL;
1430 GstVideoCodecFrame *frame;
1431 GstFlowReturn flow_ret = GST_FLOW_OK;
1432 GstOMXAcquireBufferReturn acq_return;
1435 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1437 acq_return = gst_omx_port_acquire_buffer (port, &buf, GST_OMX_WAIT);
1438 if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
1439 goto component_error;
1440 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
1442 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) {
1446 if (!gst_pad_has_current_caps (GST_VIDEO_ENCODER_SRC_PAD (self))
1447 || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1449 GstVideoCodecState *state;
1451 GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");
1453 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE
1454 && gst_omx_port_is_enabled (port)) {
1455 /* Reallocate all buffers */
1456 err = gst_omx_port_set_enabled (port, FALSE);
1457 if (err != OMX_ErrorNone)
1458 goto reconfigure_error;
1460 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
1461 if (err != OMX_ErrorNone)
1462 goto reconfigure_error;
1464 err = gst_omx_port_deallocate_buffers (port);
1465 if (err != OMX_ErrorNone)
1466 goto reconfigure_error;
1468 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
1469 if (err != OMX_ErrorNone)
1470 goto reconfigure_error;
1473 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1475 caps = get_output_caps (self);
1478 gst_omx_port_release_buffer (self->enc_out_port, buf);
1479 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1483 GST_DEBUG_OBJECT (self, "Setting output state: %" GST_PTR_FORMAT, caps);
1486 gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
1488 gst_video_codec_state_unref (state);
1490 if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) {
1492 gst_omx_port_release_buffer (self->enc_out_port, buf);
1493 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1497 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1499 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1500 if (!gst_omx_video_enc_ensure_nb_out_buffers (self))
1501 goto reconfigure_error;
1503 err = gst_omx_port_set_enabled (port, TRUE);
1504 if (err != OMX_ErrorNone)
1505 goto reconfigure_error;
1507 err = gst_omx_port_allocate_buffers (port);
1508 if (err != OMX_ErrorNone)
1509 goto reconfigure_error;
1511 err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
1512 if (err != OMX_ErrorNone)
1513 goto reconfigure_error;
1515 err = gst_omx_port_populate (port);
1516 if (err != OMX_ErrorNone)
1517 goto reconfigure_error;
1519 err = gst_omx_port_mark_reconfigured (port);
1520 if (err != OMX_ErrorNone)
1521 goto reconfigure_error;
1524 /* Now get a buffer */
1525 if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) {
1530 g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
1532 /* This prevents a deadlock between the srcpad stream
1533 * lock and the videocodec stream lock, if ::flush()
1534 * is called at the wrong time
1536 if (gst_omx_port_is_flushing (self->enc_out_port)) {
1537 GST_DEBUG_OBJECT (self, "Flushing");
1538 gst_omx_port_release_buffer (self->enc_out_port, buf);
1542 GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x (%s) %" G_GUINT64_FORMAT,
1543 (guint) buf->omx_buf->nFlags,
1544 gst_omx_buffer_flags_to_string (buf->omx_buf->nFlags),
1545 (guint64) GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp));
1547 frame = gst_omx_video_find_nearest_frame (GST_ELEMENT_CAST (self), buf,
1548 gst_video_encoder_get_frames (GST_VIDEO_ENCODER (self)));
1550 g_assert (klass->handle_output_frame);
1551 flow_ret = klass->handle_output_frame (self, self->enc_out_port, buf, frame);
1553 GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
1555 err = gst_omx_port_release_buffer (port, buf);
1556 if (err != OMX_ErrorNone)
1559 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1560 self->downstream_flow_ret = flow_ret;
1561 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1563 GST_DEBUG_OBJECT (self, "Read frame from component");
1565 if (flow_ret != GST_FLOW_OK)
1572 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1573 ("OpenMAX component in error state %s (0x%08x)",
1574 gst_omx_component_get_last_error_string (self->enc),
1575 gst_omx_component_get_last_error (self->enc)));
1576 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1577 gst_omx_video_enc_pause_loop (self, GST_FLOW_ERROR);
1582 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1583 gst_omx_video_enc_pause_loop (self, GST_FLOW_FLUSHING);
1589 g_mutex_lock (&self->drain_lock);
1590 if (self->draining) {
1591 GST_DEBUG_OBJECT (self, "Drained");
1592 self->draining = FALSE;
1593 g_cond_broadcast (&self->drain_cond);
1594 flow_ret = GST_FLOW_OK;
1595 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1597 GST_DEBUG_OBJECT (self, "Component signalled EOS");
1598 flow_ret = GST_FLOW_EOS;
1600 g_mutex_unlock (&self->drain_lock);
1602 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1603 self->downstream_flow_ret = flow_ret;
1604 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1606 /* Here we fallback and pause the task for the EOS case */
1607 if (flow_ret != GST_FLOW_OK)
1614 if (flow_ret == GST_FLOW_EOS) {
1615 GST_DEBUG_OBJECT (self, "EOS");
1617 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
1618 gst_event_new_eos ());
1619 } else if (flow_ret < GST_FLOW_EOS) {
1620 GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."),
1621 ("stream stopped, reason %s", gst_flow_get_name (flow_ret)));
1623 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
1624 gst_event_new_eos ());
1625 } else if (flow_ret == GST_FLOW_FLUSHING) {
1626 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1628 gst_omx_video_enc_pause_loop (self, flow_ret);
1633 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1634 ("Unable to reconfigure output port"));
1635 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1636 gst_omx_video_enc_pause_loop (self, GST_FLOW_NOT_NEGOTIATED);
1641 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps"));
1642 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1643 gst_omx_video_enc_pause_loop (self, GST_FLOW_NOT_NEGOTIATED);
1648 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1649 ("Failed to relase output buffer to component: %s (0x%08x)",
1650 gst_omx_error_to_string (err), err));
1651 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1652 gst_omx_video_enc_pause_loop (self, GST_FLOW_ERROR);
1658 gst_omx_video_enc_start (GstVideoEncoder * encoder)
1660 GstOMXVideoEnc *self;
1662 self = GST_OMX_VIDEO_ENC (encoder);
1664 self->last_upstream_ts = 0;
1665 self->downstream_flow_ret = GST_FLOW_OK;
1666 self->nb_downstream_buffers = 0;
1667 self->in_pool_used = FALSE;
1673 gst_omx_video_enc_stop (GstVideoEncoder * encoder)
1675 GstOMXVideoEnc *self;
1677 self = GST_OMX_VIDEO_ENC (encoder);
1679 GST_DEBUG_OBJECT (self, "Stopping encoder");
1681 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
1682 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1684 gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1686 if (gst_omx_component_get_state (self->enc, 0) > OMX_StateIdle)
1687 gst_omx_component_set_state (self->enc, OMX_StateIdle);
1689 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1690 self->started = FALSE;
1692 if (self->input_state)
1693 gst_video_codec_state_unref (self->input_state);
1694 self->input_state = NULL;
1696 g_mutex_lock (&self->drain_lock);
1697 self->draining = FALSE;
1698 g_cond_broadcast (&self->drain_cond);
1699 g_mutex_unlock (&self->drain_lock);
1701 self->default_target_bitrate = GST_OMX_PROP_OMX_DEFAULT;
1703 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
1708 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1710 gst_omx_video_enc_set_latency (GstOMXVideoEnc * self)
1712 GstClockTime latency;
1713 OMX_ALG_PARAM_REPORTED_LATENCY param;
1716 GST_OMX_INIT_STRUCT (¶m);
1718 gst_omx_component_get_parameter (self->enc,
1719 (OMX_INDEXTYPE) OMX_ALG_IndexParamReportedLatency, ¶m);
1721 if (err != OMX_ErrorNone) {
1722 GST_WARNING_OBJECT (self, "Couldn't retrieve latency: %s (0x%08x)",
1723 gst_omx_error_to_string (err), err);
1727 GST_DEBUG_OBJECT (self, "retrieved latency of %d ms",
1728 (guint32) param.nLatency);
1731 latency = param.nLatency * GST_MSECOND;
1733 gst_video_encoder_set_latency (GST_VIDEO_ENCODER (self), latency, latency);
1738 gst_omx_video_enc_disable (GstOMXVideoEnc * self)
1740 GstOMXVideoEncClass *klass;
1742 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1744 GST_DEBUG_OBJECT (self, "Need to disable and drain encoder");
1745 gst_omx_video_enc_drain (self);
1746 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1748 /* Wait until the srcpad loop is finished,
1749 * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
1750 * caused by using this lock from inside the loop function */
1751 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1752 gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1753 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1755 if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) {
1756 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1757 gst_omx_video_enc_stop (GST_VIDEO_ENCODER (self));
1758 gst_omx_video_enc_close (GST_VIDEO_ENCODER (self));
1759 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1761 if (!gst_omx_video_enc_open (GST_VIDEO_ENCODER (self)))
1764 /* The decoder is returned to initial state */
1765 self->disabled = FALSE;
1767 /* Disabling at the same time input port and output port is only
1768 * required when a buffer is shared between the ports. This cannot
1769 * be the case for a encoder because its input and output buffers
1770 * are of different nature. So let's disable ports sequencially.
1771 * Starting from IL 1.2.0, this point has been clarified.
1772 * OMX_SendCommand will return an error if the IL client attempts to
1773 * call it when there is already an on-going command being processed.
1774 * The exception is for buffer sharing above and the event
1775 * OMX_EventPortNeedsDisable will be sent to request disabling the
1776 * other port at the same time. */
1777 if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone)
1779 if (gst_omx_port_wait_buffers_released (self->enc_in_port,
1780 5 * GST_SECOND) != OMX_ErrorNone)
1782 if (!gst_omx_video_enc_deallocate_in_buffers (self))
1784 if (gst_omx_port_wait_enabled (self->enc_in_port,
1785 1 * GST_SECOND) != OMX_ErrorNone)
1788 if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
1790 if (gst_omx_port_wait_buffers_released (self->enc_out_port,
1791 1 * GST_SECOND) != OMX_ErrorNone)
1793 if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1795 if (gst_omx_port_wait_enabled (self->enc_out_port,
1796 1 * GST_SECOND) != OMX_ErrorNone)
1799 self->disabled = TRUE;
1802 GST_DEBUG_OBJECT (self, "Encoder drained and disabled");
1807 gst_omx_video_enc_configure_input_buffer (GstOMXVideoEnc * self,
1810 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1811 GstVideoInfo *info = &self->input_state->info;
1812 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1814 guint stride, slice_height;
1816 gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
1818 meta = gst_buffer_get_video_meta (input);
1820 /* Use the stride and slice height of the first plane */
1821 stride = meta->stride[0];
1822 g_assert (stride != 0);
1823 slice_height = (meta->offset[1] - meta->offset[0]) / stride;
1825 GST_DEBUG_OBJECT (self,
1826 "adjusting stride (%d) and slice-height (%d) using input buffer meta",
1827 stride, slice_height);
1829 GST_WARNING_OBJECT (self,
1830 "input buffer doesn't provide video meta, can't adjust stride and slice height");
1832 stride = info->stride[0];
1833 slice_height = info->height;
1836 if (port_def.nBufferAlignment)
1837 port_def.format.video.nStride =
1838 GST_ROUND_UP_N (stride, port_def.nBufferAlignment);
1840 port_def.format.video.nStride = GST_ROUND_UP_4 (stride); /* safe (?) default */
1842 if (klass->cdata.hacks & GST_OMX_HACK_HEIGHT_MULTIPLE_16)
1843 port_def.format.video.nSliceHeight = GST_ROUND_UP_16 (slice_height);
1845 port_def.format.video.nSliceHeight = slice_height;
1847 switch (port_def.format.video.eColorFormat) {
1848 case OMX_COLOR_FormatYUV420Planar:
1849 case OMX_COLOR_FormatYUV420PackedPlanar:
1850 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1851 /* Formats defined in extensions have their own enum so disable to -Wswitch warning */
1852 #pragma GCC diagnostic push
1853 #pragma GCC diagnostic ignored "-Wswitch"
1854 case OMX_ALG_COLOR_FormatYUV420SemiPlanar10bitPacked:
1855 #pragma GCC diagnostic pop
1857 port_def.nBufferSize =
1858 (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
1859 2 * ((port_def.format.video.nStride / 2) *
1860 ((port_def.format.video.nFrameHeight + 1) / 2));
1863 case OMX_COLOR_FormatYUV420PackedSemiPlanar:
1864 case OMX_COLOR_FormatYUV420SemiPlanar:
1865 port_def.nBufferSize =
1866 (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
1867 (port_def.format.video.nStride *
1868 ((port_def.format.video.nFrameHeight + 1) / 2));
1871 case OMX_COLOR_FormatYUV422SemiPlanar:
1872 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1873 /* Formats defined in extensions have their own enum so disable to -Wswitch warning */
1874 #pragma GCC diagnostic push
1875 #pragma GCC diagnostic ignored "-Wswitch"
1876 case OMX_ALG_COLOR_FormatYUV422SemiPlanar10bitPacked:
1877 #pragma GCC diagnostic pop
1879 port_def.nBufferSize =
1880 (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
1881 2 * (port_def.format.video.nStride *
1882 ((port_def.format.video.nFrameHeight + 1) / 2));
1886 GST_ERROR_OBJECT (self, "Unsupported port format %x",
1887 port_def.format.video.eColorFormat);
1888 g_assert_not_reached ();
1891 GST_DEBUG_OBJECT (self,
1892 "setting input nStride=%d nSliceHeight=%d nBufferSize=%d (nBufferAlignment=%d)",
1893 (guint) port_def.format.video.nStride,
1894 (guint) port_def.format.video.nSliceHeight,
1895 (guint) port_def.nBufferSize, (guint) port_def.nBufferAlignment);
1897 if (gst_omx_port_update_port_definition (self->enc_in_port,
1898 &port_def) != OMX_ErrorNone)
1905 gst_omx_video_enc_ensure_nb_in_buffers (GstOMXVideoEnc * self)
1907 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1909 if ((klass->cdata.hacks & GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL)) {
1910 if (!gst_omx_port_ensure_buffer_count_actual (self->enc_in_port, 0))
1918 gst_omx_video_enc_allocate_in_buffers (GstOMXVideoEnc * self)
1920 switch (self->input_allocation) {
1921 case GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER:
1922 if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1925 case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC:
1926 if (gst_omx_port_use_dynamic_buffers (self->enc_in_port) != OMX_ErrorNone)
1929 case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER:
1932 g_return_val_if_reached (FALSE);
1939 check_input_alignment (GstOMXVideoEnc * self, GstMapInfo * map)
1941 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
1943 if (map->size != port_def->nBufferSize) {
1944 GST_DEBUG_OBJECT (self,
1945 "input buffer has wrong size/stride (%" G_GSIZE_FORMAT
1946 " expected: %u), can't use dynamic allocation",
1947 map->size, (guint32) port_def->nBufferSize);
1951 if (port_def->nBufferAlignment &&
1952 (GPOINTER_TO_UINT (map->data) & (port_def->nBufferAlignment - 1)) != 0) {
1953 GST_DEBUG_OBJECT (self,
1954 "input buffer is not properly aligned (address: %p alignment: %u bytes), can't use dynamic allocation",
1955 map->data, (guint32) port_def->nBufferAlignment);
1962 /* Check if @inbuf's alignment and stride matches the requirements to use the
1963 * dynamic buffer mode. */
1965 can_use_dynamic_buffer_mode (GstOMXVideoEnc * self, GstBuffer * inbuf)
1968 gboolean result = FALSE;
1970 if (gst_buffer_n_memory (inbuf) > 1) {
1971 GST_DEBUG_OBJECT (self,
1972 "input buffer contains more than one memory, can't use dynamic allocation");
1976 if (!gst_buffer_map (inbuf, &map, GST_MAP_READ)) {
1977 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
1978 ("failed to map input buffer"));
1982 result = check_input_alignment (self, &map);
1984 gst_buffer_unmap (inbuf, &map);
1988 /* Choose the allocation mode for input buffers depending of what's supported by
1989 * the component and the size/alignment of the input buffer. */
1990 static GstOMXBufferAllocation
1991 gst_omx_video_enc_pick_input_allocation_mode (GstOMXVideoEnc * self,
1994 if (!gst_omx_is_dynamic_allocation_supported ())
1995 return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
1997 if (can_use_dynamic_buffer_mode (self, inbuf)) {
1998 GST_DEBUG_OBJECT (self,
1999 "input buffer is properly aligned, use dynamic allocation");
2000 return GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC;
2003 GST_DEBUG_OBJECT (self, "let input buffer allocate its buffers");
2004 return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
2008 gst_omx_video_enc_set_to_idle (GstOMXVideoEnc * self)
2010 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
2011 gboolean no_disable_outport;
2013 no_disable_outport = klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT;
2015 if (!no_disable_outport) {
2016 /* Disable output port */
2017 if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
2020 if (gst_omx_port_wait_enabled (self->enc_out_port,
2021 1 * GST_SECOND) != OMX_ErrorNone)
2025 if (gst_omx_component_set_state (self->enc, OMX_StateIdle) != OMX_ErrorNone)
2028 /* Need to allocate buffers to reach Idle state */
2029 if (!gst_omx_video_enc_allocate_in_buffers (self))
2032 if (no_disable_outport) {
2033 if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
2037 if (gst_omx_component_get_state (self->enc,
2038 GST_CLOCK_TIME_NONE) != OMX_StateIdle)
2044 static GstOMXBuffer *
2045 get_omx_buf (GstBuffer * buffer)
2049 mem = gst_buffer_peek_memory (buffer, 0);
2050 return gst_omx_memory_get_omx_buf (mem);
2054 buffer_is_from_input_pool (GstOMXVideoEnc * self, GstBuffer * buffer)
2056 /* Buffer from our input pool will already have a GstOMXBuffer associated
2057 * with our input port. */
2060 buf = get_omx_buf (buffer);
2064 return buf->port == self->enc_in_port;
2068 gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input)
2070 GstOMXVideoEncClass *klass;
2072 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
2074 /* Is downstream using our buffer pool? */
2075 if (buffer_is_from_input_pool (self, input)) {
2076 self->in_pool_used = TRUE;
2079 if (!self->in_pool_used) {
2080 if (!gst_omx_video_enc_configure_input_buffer (self, input))
2083 self->input_allocation = gst_omx_video_enc_pick_input_allocation_mode (self,
2085 self->input_dmabuf = FALSE;
2087 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2088 if (gst_is_dmabuf_memory (gst_buffer_peek_memory (input, 0))) {
2089 if (self->input_allocation ==
2090 GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
2091 GST_DEBUG_OBJECT (self, "Configure encoder input to import dmabuf");
2092 gst_omx_port_set_dmabuf (self->enc_in_port, TRUE);
2094 GST_DEBUG_OBJECT (self,
2095 "Wrong input allocation mode (%d); dynamic buffers are required to use dmabuf import",
2096 self->input_allocation);
2099 self->input_dmabuf = TRUE;
2104 GST_DEBUG_OBJECT (self, "Enabling component");
2106 if (!self->in_pool_used) {
2107 if (!gst_omx_video_enc_ensure_nb_in_buffers (self))
2109 if (!gst_omx_video_enc_ensure_nb_out_buffers (self))
2113 if (self->disabled) {
2114 if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone)
2116 if (!gst_omx_video_enc_allocate_in_buffers (self))
2119 if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
2120 if (gst_omx_port_set_enabled (self->enc_out_port, TRUE) != OMX_ErrorNone)
2122 if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
2125 if (gst_omx_port_wait_enabled (self->enc_out_port,
2126 5 * GST_SECOND) != OMX_ErrorNone)
2130 if (gst_omx_port_wait_enabled (self->enc_in_port,
2131 5 * GST_SECOND) != OMX_ErrorNone)
2133 if (gst_omx_port_mark_reconfigured (self->enc_in_port) != OMX_ErrorNone)
2136 /* If the input pool is active we already allocated buffers and set the component to Idle. */
2137 if (!self->in_pool_used) {
2138 if (!gst_omx_video_enc_set_to_idle (self))
2142 if (gst_omx_component_set_state (self->enc,
2143 OMX_StateExecuting) != OMX_ErrorNone)
2146 if (gst_omx_component_get_state (self->enc,
2147 GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
2151 /* Unset flushing to allow ports to accept data again */
2152 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
2153 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);
2155 if (gst_omx_component_get_last_error (self->enc) != OMX_ErrorNone) {
2156 GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)",
2157 gst_omx_component_get_last_error_string (self->enc),
2158 gst_omx_component_get_last_error (self->enc));
2162 self->disabled = FALSE;
2167 /* returns TRUE if only the framerate changed and that framerate could be
2168 * updated using OMX_IndexConfigVideoFramerate */
2170 gst_omx_video_enc_framerate_changed (GstOMXVideoEnc * self,
2171 GstVideoCodecState * state)
2173 GstVideoInfo prev_info = self->input_state->info;
2174 GstVideoInfo *info = &state->info;
2175 GstOMXVideoEncClass *klass;
2177 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
2179 prev_info.fps_n = info->fps_n;
2180 prev_info.fps_d = info->fps_d;
2182 /* if only the framerate changed, try and set the framerate parameter */
2183 if (gst_video_info_is_equal (info, &prev_info)) {
2184 OMX_CONFIG_FRAMERATETYPE config;
2187 GST_DEBUG_OBJECT (self, "Framerate change detected: %d/%d -> %d/%d",
2188 self->input_state->info.fps_n, self->input_state->info.fps_d,
2189 info->fps_n, info->fps_d);
2191 GST_OMX_INIT_STRUCT (&config);
2192 config.nPortIndex = self->enc_in_port->index;
2193 if (klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER)
2194 config.xEncodeFramerate = info->fps_n ? (info->fps_n) / (info->fps_d) : 0;
2196 config.xEncodeFramerate = gst_omx_video_calculate_framerate_q16 (info);
2198 err = gst_omx_component_set_config (self->enc,
2199 OMX_IndexConfigVideoFramerate, &config);
2200 if (err == OMX_ErrorNone) {
2201 gst_video_codec_state_unref (self->input_state);
2202 self->input_state = gst_video_codec_state_ref (state);
2205 GST_WARNING_OBJECT (self,
2206 "Failed to set framerate configuration: %s (0x%08x)",
2207 gst_omx_error_to_string (err), err);
2208 /* if changing the rate dynamically didn't work, keep going with a full
2217 gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
2218 GstVideoCodecState * state)
2220 GstOMXVideoEnc *self;
2221 GstOMXVideoEncClass *klass;
2222 gboolean needs_disable = FALSE;
2223 OMX_PARAM_PORTDEFINITIONTYPE port_def;
2224 GstVideoInfo *info = &state->info;
2225 GList *negotiation_map = NULL, *l;
2228 self = GST_OMX_VIDEO_ENC (encoder);
2229 klass = GST_OMX_VIDEO_ENC_GET_CLASS (encoder);
2231 caps = gst_video_info_to_caps (info);
2232 GST_DEBUG_OBJECT (self, "Setting new input format: %" GST_PTR_FORMAT, caps);
2233 gst_caps_unref (caps);
2235 gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
2238 gst_omx_component_get_state (self->enc,
2239 GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
2240 /* If the component is not in Loaded state and a real format change happens
2241 * we have to disable the port and re-allocate all buffers. If no real
2242 * format change happened we can just exit here.
2244 if (needs_disable) {
2245 if (gst_omx_video_enc_framerate_changed (self, state))
2248 if (!gst_omx_video_enc_disable (self))
2251 if (!self->disabled) {
2252 /* The local port_def is now obsolete so get it again. */
2253 gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
2258 gst_omx_video_get_supported_colorformats (self->enc_in_port,
2260 if (!negotiation_map) {
2262 switch (info->finfo->format) {
2263 case GST_VIDEO_FORMAT_I420:
2264 port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
2266 case GST_VIDEO_FORMAT_NV12:
2267 port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
2269 case GST_VIDEO_FORMAT_NV16:
2270 port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV422SemiPlanar;
2272 case GST_VIDEO_FORMAT_ABGR:
2273 port_def.format.video.eColorFormat = OMX_COLOR_Format32bitARGB8888;
2275 case GST_VIDEO_FORMAT_ARGB:
2276 port_def.format.video.eColorFormat = OMX_COLOR_Format32bitBGRA8888;
2279 GST_ERROR_OBJECT (self, "Unsupported format %s",
2280 gst_video_format_to_string (info->finfo->format));
2285 for (l = negotiation_map; l; l = l->next) {
2286 GstOMXVideoNegotiationMap *m = l->data;
2288 if (m->format == info->finfo->format) {
2289 port_def.format.video.eColorFormat = m->type;
2293 g_list_free_full (negotiation_map,
2294 (GDestroyNotify) gst_omx_video_negotiation_map_free);
2297 port_def.format.video.nFrameWidth = info->width;
2298 port_def.format.video.nFrameHeight = info->height;
2300 if (G_UNLIKELY (klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER))
2301 port_def.format.video.xFramerate =
2302 info->fps_n ? (info->fps_n) / (info->fps_d) : 0;
2304 port_def.format.video.xFramerate =
2305 gst_omx_video_calculate_framerate_q16 (info);
2307 GST_DEBUG_OBJECT (self, "Setting inport port definition");
2308 if (gst_omx_port_update_port_definition (self->enc_in_port,
2309 &port_def) != OMX_ErrorNone)
2312 #ifdef USE_OMX_TARGET_RPI
2316 OMX_CONFIG_POINTTYPE aspect_ratio_param;
2318 GST_OMX_INIT_STRUCT (&aspect_ratio_param);
2319 aspect_ratio_param.nPortIndex = self->enc_out_port->index;
2321 err = gst_omx_component_get_parameter (self->enc,
2322 OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
2324 if (err == OMX_ErrorNone) {
2326 aspect_ratio_param.nX = info->par_n;
2327 aspect_ratio_param.nY = info->par_d;
2330 gst_omx_component_set_parameter (self->enc,
2331 OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
2333 if (err == OMX_ErrorUnsupportedIndex) {
2334 GST_WARNING_OBJECT (self,
2335 "Setting aspect ratio parameters not supported by the component");
2336 } else if (err == OMX_ErrorUnsupportedSetting) {
2337 GST_WARNING_OBJECT (self,
2338 "Setting aspect ratio %u %u not supported by the component",
2339 aspect_ratio_param.nX, aspect_ratio_param.nY);
2340 } else if (err != OMX_ErrorNone) {
2341 GST_ERROR_OBJECT (self,
2342 "Failed to set aspect ratio: %s (0x%08x)",
2343 gst_omx_error_to_string (err), err);
2348 #endif // USE_OMX_TARGET_RPI
2350 if (klass->set_format) {
2351 if (!klass->set_format (self, self->enc_in_port, state)) {
2352 GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
2357 GST_DEBUG_OBJECT (self, "Updating ports definition");
2358 if (gst_omx_port_update_port_definition (self->enc_out_port,
2359 NULL) != OMX_ErrorNone)
2361 if (gst_omx_port_update_port_definition (self->enc_in_port,
2362 NULL) != OMX_ErrorNone)
2365 /* Some OMX implementations reset the bitrate after setting the compression
2366 * format, see bgo#698049, so re-set it */
2367 gst_omx_video_enc_set_bitrate (self);
2369 if (self->input_state)
2370 gst_video_codec_state_unref (self->input_state);
2371 self->input_state = gst_video_codec_state_ref (state);
2373 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2374 gst_omx_video_enc_set_latency (self);
2377 self->downstream_flow_ret = GST_FLOW_OK;
2382 gst_omx_video_enc_flush (GstVideoEncoder * encoder)
2384 GstOMXVideoEnc *self;
2386 self = GST_OMX_VIDEO_ENC (encoder);
2388 GST_DEBUG_OBJECT (self, "Flushing encoder");
2390 if (gst_omx_component_get_state (self->enc, 0) == OMX_StateLoaded)
2393 /* 0) Pause the components */
2394 if (gst_omx_component_get_state (self->enc, 0) == OMX_StateExecuting) {
2395 gst_omx_component_set_state (self->enc, OMX_StatePause);
2396 gst_omx_component_get_state (self->enc, GST_CLOCK_TIME_NONE);
2399 /* 1) Flush the ports */
2400 GST_DEBUG_OBJECT (self, "flushing ports");
2401 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
2402 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
2404 /* Wait until the srcpad loop is finished,
2405 * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
2406 * caused by using this lock from inside the loop function */
2407 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
2408 GST_PAD_STREAM_LOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
2409 GST_PAD_STREAM_UNLOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
2410 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2412 /* 3) Resume components */
2413 gst_omx_component_set_state (self->enc, OMX_StateExecuting);
2414 gst_omx_component_get_state (self->enc, GST_CLOCK_TIME_NONE);
2416 /* 4) Unset flushing to allow ports to accept data again */
2417 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
2418 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);
2419 gst_omx_port_populate (self->enc_out_port);
2421 /* Start the srcpad loop again */
2422 self->last_upstream_ts = 0;
2423 self->downstream_flow_ret = GST_FLOW_OK;
2424 self->started = FALSE;
2425 GST_DEBUG_OBJECT (self, "Flush finished");
2431 gst_omx_video_enc_semi_planar_manual_copy (GstOMXVideoEnc * self,
2432 GstBuffer * inbuf, GstOMXBuffer * outbuf, const GstVideoFormatInfo * finfo)
2434 GstVideoInfo *info = &self->input_state->info;
2435 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
2436 GstVideoFrame frame;
2437 gint i, j, height, width;
2439 gint src_stride, dest_stride;
2441 outbuf->omx_buf->nFilledLen = 0;
2443 if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
2444 GST_ERROR_OBJECT (self, "Invalid input buffer size");
2447 dest_stride = port_def->format.video.nStride;
2449 for (i = 0; i < 2; i++) {
2450 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i);
2451 /* XXX: Try this if no stride was set */
2452 if (dest_stride == 0)
2453 dest_stride = src_stride;
2455 dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
2458 port_def->format.video.nSliceHeight * port_def->format.video.nStride;
2460 src = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
2461 height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
2462 width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i) * (i == 0 ? 1 : 2);
2464 if (GST_VIDEO_FORMAT_INFO_BITS (finfo) == 10)
2465 /* Need ((width + 2) / 3) 32-bits words */
2466 width = (width + 2) / 3 * 4;
2468 if (dest + dest_stride * height >
2469 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nAllocLen) {
2470 GST_ERROR_OBJECT (self, "Invalid output buffer size");
2471 gst_video_frame_unmap (&frame);
2475 for (j = 0; j < height; j++) {
2476 memcpy (dest, src, width);
2478 dest += dest_stride;
2481 /* nFilledLen should include the vertical padding in each slice (spec 3.1.3.7.1) */
2482 outbuf->omx_buf->nFilledLen +=
2483 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i,
2484 port_def->format.video.nSliceHeight) * port_def->format.video.nStride;
2487 gst_video_frame_unmap (&frame);
2492 gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf,
2493 GstOMXBuffer * outbuf)
2495 GstVideoCodecState *state = gst_video_codec_state_ref (self->input_state);
2496 GstVideoInfo *info = &state->info;
2497 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
2498 gboolean ret = FALSE;
2499 GstVideoFrame frame;
2501 if (info->width != port_def->format.video.nFrameWidth ||
2502 info->height != port_def->format.video.nFrameHeight) {
2503 GST_ERROR_OBJECT (self, "Width or height do not match");
2507 if (self->enc_in_port->allocation ==
2508 GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
2509 if (gst_buffer_n_memory (inbuf) > 1) {
2510 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2511 ("input buffer now has more than one memory, can't use dynamic allocation any more"));
2515 if (!self->input_dmabuf) {
2516 /* Map and keep a ref on the buffer while it's being processed
2517 * by the OMX component. */
2518 if (!gst_omx_buffer_map_frame (outbuf, inbuf, info)) {
2519 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2520 ("failed to map input buffer"));
2524 if (!check_input_alignment (self, &outbuf->input_frame.map[0])) {
2525 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2526 ("input buffer now has wrong alignment/stride, can't use dynamic allocation any more"));
2530 GST_LOG_OBJECT (self, "Transfer buffer of %" G_GSIZE_FORMAT " bytes",
2531 gst_buffer_get_size (inbuf));
2534 if (!gst_omx_buffer_import_fd (outbuf, inbuf)) {
2535 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2536 ("failed to import dmabuf"));
2540 GST_LOG_OBJECT (self, "Import dmabuf of %" G_GSIZE_FORMAT " bytes",
2541 gst_buffer_get_size (inbuf));
2548 /* Same strides and everything */
2549 if (gst_buffer_get_size (inbuf) ==
2550 outbuf->omx_buf->nAllocLen - outbuf->omx_buf->nOffset) {
2551 outbuf->omx_buf->nFilledLen = gst_buffer_get_size (inbuf);
2553 GST_LOG_OBJECT (self, "Matched strides - direct copy %u bytes",
2554 (guint) outbuf->omx_buf->nFilledLen);
2556 gst_buffer_extract (inbuf, 0,
2557 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset,
2558 outbuf->omx_buf->nFilledLen);
2563 /* Different strides */
2564 GST_LOG_OBJECT (self, "Mismatched strides - copying line-by-line");
2566 switch (info->finfo->format) {
2567 case GST_VIDEO_FORMAT_I420:{
2568 gint i, j, height, width;
2570 gint src_stride, dest_stride;
2572 outbuf->omx_buf->nFilledLen = 0;
2574 if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
2575 GST_ERROR_OBJECT (self, "Invalid input buffer size");
2580 for (i = 0; i < 3; i++) {
2582 dest_stride = port_def->format.video.nStride;
2584 dest_stride = port_def->format.video.nStride / 2;
2587 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i);
2588 /* XXX: Try this if no stride was set */
2589 if (dest_stride == 0)
2590 dest_stride = src_stride;
2592 dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
2595 port_def->format.video.nSliceHeight *
2596 port_def->format.video.nStride;
2599 (port_def->format.video.nSliceHeight / 2) *
2600 (port_def->format.video.nStride / 2);
2602 src = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
2603 height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
2604 width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i);
2606 if (dest + dest_stride * height >
2607 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nAllocLen) {
2608 gst_video_frame_unmap (&frame);
2609 GST_ERROR_OBJECT (self, "Invalid output buffer size");
2614 for (j = 0; j < height; j++) {
2615 memcpy (dest, src, width);
2617 dest += dest_stride;
2620 /* nFilledLen should include the vertical padding in each slice (spec 3.1.3.7.1) */
2622 outbuf->omx_buf->nFilledLen +=
2623 port_def->format.video.nSliceHeight *
2624 port_def->format.video.nStride;
2626 outbuf->omx_buf->nFilledLen +=
2627 (port_def->format.video.nSliceHeight / 2) *
2628 (port_def->format.video.nStride / 2);
2630 gst_video_frame_unmap (&frame);
2634 case GST_VIDEO_FORMAT_NV12:
2635 case GST_VIDEO_FORMAT_NV16:
2636 case GST_VIDEO_FORMAT_NV12_10LE32:
2637 case GST_VIDEO_FORMAT_NV16_10LE32:
2639 gst_omx_video_enc_semi_planar_manual_copy (self, inbuf, outbuf,
2643 GST_ERROR_OBJECT (self, "Unsupported format");
2650 gst_video_codec_state_unref (state);
2655 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2657 handle_roi_metadata (GstOMXVideoEnc * self, GstBuffer * input)
2660 gpointer state = NULL;
2663 gst_buffer_iterate_meta_filtered (input, &state,
2664 GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE))) {
2665 GstVideoRegionOfInterestMeta *roi = (GstVideoRegionOfInterestMeta *) meta;
2666 OMX_ALG_VIDEO_CONFIG_REGION_OF_INTEREST roi_param;
2669 GST_LOG_OBJECT (self, "Input buffer ROI: type=%s id=%d (%d, %d) %dx%d",
2670 g_quark_to_string (roi->roi_type), roi->id, roi->x, roi->y, roi->w,
2673 if (self->qp_mode != OMX_ALG_ROI_QP) {
2674 GST_WARNING_OBJECT (self,
2675 "Need qp-mode=roi to handle ROI metadata (current: %d); ignoring",
2680 GST_OMX_INIT_STRUCT (&roi_param);
2681 roi_param.nPortIndex = self->enc_in_port->index;
2682 roi_param.nLeft = roi->x;
2683 roi_param.nTop = roi->y;
2684 roi_param.nWidth = roi->w;
2685 roi_param.nHeight = roi->h;
2687 s = gst_video_region_of_interest_meta_get_param (roi, "roi/omx-alg");
2689 const gchar *quality;
2692 quality = gst_structure_get_string (s, "quality");
2695 g_enum_get_value_by_nick (self->alg_roi_quality_enum_class, quality);
2697 roi_param.eQuality = self->default_roi_quality;
2699 GST_WARNING_OBJECT (self,
2700 "Unknown ROI encoding quality '%s', use default (%d)",
2701 quality, self->default_roi_quality);
2703 roi_param.eQuality = evalue->value;
2705 GST_LOG_OBJECT (self, "Use encoding quality '%s' from upstream",
2709 roi_param.eQuality = self->default_roi_quality;
2711 GST_LOG_OBJECT (self, "No quality specified upstream, use default (%d)",
2712 self->default_roi_quality);
2715 gst_omx_component_set_config (self->enc,
2716 (OMX_INDEXTYPE) OMX_ALG_IndexConfigVideoRegionOfInterest, &roi_param);
2721 static GstFlowReturn
2722 gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
2723 GstVideoCodecFrame * frame)
2725 GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
2726 GstOMXVideoEnc *self;
2730 GstClockTimeDiff deadline;
2732 self = GST_OMX_VIDEO_ENC (encoder);
2734 GST_DEBUG_OBJECT (self, "Handling frame");
2736 if (self->downstream_flow_ret != GST_FLOW_OK) {
2737 gst_video_codec_frame_unref (frame);
2738 return self->downstream_flow_ret;
2741 deadline = gst_video_encoder_get_max_encode_time (encoder, frame);
2743 GST_WARNING_OBJECT (self,
2744 "Input frame is too late, dropping (deadline %" GST_TIME_FORMAT ")",
2745 GST_TIME_ARGS (-deadline));
2747 /* Calling finish_frame with frame->output_buffer == NULL will drop it */
2748 return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
2751 if (!self->started) {
2752 if (gst_omx_port_is_flushing (self->enc_out_port)) {
2753 if (!gst_omx_video_enc_enable (self, frame->input_buffer))
2757 GST_DEBUG_OBJECT (self, "Starting task");
2758 gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
2759 (GstTaskFunction) gst_omx_video_enc_loop, self, NULL);
2762 port = self->enc_in_port;
2764 while (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
2765 GstClockTime timestamp, duration;
2766 gboolean fill_buffer = TRUE;
2768 /* Make sure to release the base class stream lock, otherwise
2769 * _loop() can't call _finish_frame() and we might block forever
2770 * because no input buffers are released */
2771 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
2773 if (buffer_is_from_input_pool (self, frame->input_buffer)) {
2774 /* Receiving a buffer from our input pool */
2775 buf = get_omx_buf (frame->input_buffer);
2777 GST_LOG_OBJECT (self,
2778 "Input buffer %p already has a OMX buffer associated: %p",
2779 frame->input_buffer, buf);
2781 g_assert (!buf->input_buffer);
2782 /* Prevent the buffer to be released to the pool while it's being
2783 * processed by OMX. The reference will be dropped in EmptyBufferDone() */
2784 buf->input_buffer = gst_buffer_ref (frame->input_buffer);
2786 acq_ret = GST_OMX_ACQUIRE_BUFFER_OK;
2787 fill_buffer = FALSE;
2788 buf->omx_buf->nFilledLen = gst_buffer_get_size (frame->input_buffer);
2790 acq_ret = gst_omx_port_acquire_buffer (port, &buf, GST_OMX_WAIT);
2793 if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) {
2794 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2795 goto component_error;
2796 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
2797 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2799 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
2800 /* Reallocate all buffers */
2801 err = gst_omx_port_set_enabled (port, FALSE);
2802 if (err != OMX_ErrorNone) {
2803 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2804 goto reconfigure_error;
2807 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
2808 if (err != OMX_ErrorNone) {
2809 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2810 goto reconfigure_error;
2813 err = gst_omx_port_deallocate_buffers (port);
2814 if (err != OMX_ErrorNone) {
2815 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2816 goto reconfigure_error;
2819 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
2820 if (err != OMX_ErrorNone) {
2821 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2822 goto reconfigure_error;
2825 if (!gst_omx_video_enc_ensure_nb_in_buffers (self)) {
2826 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2827 goto reconfigure_error;
2830 err = gst_omx_port_set_enabled (port, TRUE);
2831 if (err != OMX_ErrorNone) {
2832 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2833 goto reconfigure_error;
2836 if (!gst_omx_video_enc_allocate_in_buffers (self)) {
2837 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2838 goto reconfigure_error;
2841 err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
2842 if (err != OMX_ErrorNone) {
2843 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2844 goto reconfigure_error;
2847 err = gst_omx_port_mark_reconfigured (port);
2848 if (err != OMX_ErrorNone) {
2849 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2850 goto reconfigure_error;
2853 /* Now get a new buffer and fill it */
2854 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2857 GST_VIDEO_ENCODER_STREAM_LOCK (self);
2859 g_assert (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
2861 if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <= 0) {
2862 gst_omx_port_release_buffer (port, buf);
2866 if (self->downstream_flow_ret != GST_FLOW_OK) {
2867 gst_omx_port_release_buffer (port, buf);
2871 /* Now handle the frame */
2873 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
2874 #ifdef USE_OMX_TARGET_RPI
2875 OMX_CONFIG_BOOLEANTYPE config;
2877 GST_OMX_INIT_STRUCT (&config);
2878 config.bEnabled = OMX_TRUE;
2880 GST_DEBUG_OBJECT (self, "Forcing a keyframe (iframe on the RPi)");
2883 gst_omx_component_set_config (self->enc,
2884 OMX_IndexConfigBrcmVideoRequestIFrame, &config);
2885 #elif defined(USE_OMX_TARGET_ZYNQ_USCALE_PLUS)
2886 OMX_ALG_VIDEO_CONFIG_INSERT config;
2888 GST_OMX_INIT_STRUCT (&config);
2889 config.nPortIndex = self->enc_out_port->index;
2891 GST_DEBUG_OBJECT (self, "Forcing a keyframe");
2892 err = gst_omx_component_set_config (self->enc, (OMX_INDEXTYPE)
2893 OMX_ALG_IndexConfigVideoInsertInstantaneousDecodingRefresh, &config);
2895 OMX_CONFIG_INTRAREFRESHVOPTYPE config;
2897 GST_OMX_INIT_STRUCT (&config);
2898 config.nPortIndex = port->index;
2899 config.IntraRefreshVOP = OMX_TRUE;
2901 GST_DEBUG_OBJECT (self, "Forcing a keyframe");
2903 gst_omx_component_set_config (self->enc,
2904 OMX_IndexConfigVideoIntraVOPRefresh, &config);
2906 if (err != OMX_ErrorNone)
2907 GST_ERROR_OBJECT (self, "Failed to force a keyframe: %s (0x%08x)",
2908 gst_omx_error_to_string (err), err);
2910 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2911 handle_roi_metadata (self, frame->input_buffer);
2914 /* Copy the buffer content in chunks of size as requested
2917 && !gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) {
2918 gst_omx_port_release_buffer (port, buf);
2919 goto buffer_fill_error;
2922 timestamp = frame->pts;
2923 if (timestamp != GST_CLOCK_TIME_NONE) {
2924 GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp,
2925 gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND));
2926 self->last_upstream_ts = timestamp;
2929 duration = frame->duration;
2930 if (duration != GST_CLOCK_TIME_NONE) {
2931 buf->omx_buf->nTickCount =
2932 gst_util_uint64_scale (duration, OMX_TICKS_PER_SECOND, GST_SECOND);
2933 self->last_upstream_ts += duration;
2935 buf->omx_buf->nTickCount = 0;
2938 self->started = TRUE;
2939 err = gst_omx_port_release_buffer (port, buf);
2940 if (err != OMX_ErrorNone)
2943 GST_DEBUG_OBJECT (self, "Passed frame to component");
2946 gst_video_codec_frame_unref (frame);
2948 return self->downstream_flow_ret;
2952 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2953 ("Got OpenMAX buffer with no free space (%p, %u/%u)", buf,
2954 (guint) buf->omx_buf->nOffset, (guint) buf->omx_buf->nAllocLen));
2955 gst_video_codec_frame_unref (frame);
2956 return GST_FLOW_ERROR;
2961 gst_video_codec_frame_unref (frame);
2962 return self->downstream_flow_ret;
2967 /* Report the OMX error, if any */
2968 if (gst_omx_component_get_last_error (self->enc) != OMX_ErrorNone)
2969 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2970 ("Failed to enable OMX encoder: %s (0x%08x)",
2971 gst_omx_component_get_last_error_string (self->enc),
2972 gst_omx_component_get_last_error (self->enc)));
2974 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2975 ("Failed to enable OMX encoder"));
2976 gst_video_codec_frame_unref (frame);
2977 return GST_FLOW_ERROR;
2982 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2983 ("OpenMAX component in error state %s (0x%08x)",
2984 gst_omx_component_get_last_error_string (self->enc),
2985 gst_omx_component_get_last_error (self->enc)));
2986 gst_video_codec_frame_unref (frame);
2987 return GST_FLOW_ERROR;
2992 GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
2993 gst_video_codec_frame_unref (frame);
2994 return GST_FLOW_FLUSHING;
2998 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
2999 ("Unable to reconfigure input port"));
3000 gst_video_codec_frame_unref (frame);
3001 return GST_FLOW_ERROR;
3005 GST_ELEMENT_ERROR (self, RESOURCE, WRITE, (NULL),
3006 ("Failed to write input into the OpenMAX buffer"));
3007 gst_video_codec_frame_unref (frame);
3008 return GST_FLOW_ERROR;
3012 gst_video_codec_frame_unref (frame);
3013 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
3014 ("Failed to relase input buffer to component: %s (0x%08x)",
3015 gst_omx_error_to_string (err), err));
3016 return GST_FLOW_ERROR;
3020 static GstFlowReturn
3021 gst_omx_video_enc_finish (GstVideoEncoder * encoder)
3023 GstOMXVideoEnc *self;
3025 self = GST_OMX_VIDEO_ENC (encoder);
3027 return gst_omx_video_enc_drain (self);
3030 static GstFlowReturn
3031 gst_omx_video_enc_drain (GstOMXVideoEnc * self)
3033 GstOMXVideoEncClass *klass;
3035 GstOMXAcquireBufferReturn acq_ret;
3038 GST_DEBUG_OBJECT (self, "Draining component");
3040 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
3042 if (!self->started) {
3043 GST_DEBUG_OBJECT (self, "Component not started yet");
3046 self->started = FALSE;
3048 if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
3049 GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
3053 /* Make sure to release the base class stream lock, otherwise
3054 * _loop() can't call _finish_frame() and we might block forever
3055 * because no input buffers are released */
3056 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
3058 /* Send an EOS buffer to the component and let the base
3059 * class drop the EOS event. We will send it later when
3060 * the EOS buffer arrives on the output port. */
3061 acq_ret = gst_omx_port_acquire_buffer (self->enc_in_port, &buf, GST_OMX_WAIT);
3062 if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
3063 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3064 GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d",
3066 return GST_FLOW_ERROR;
3069 g_mutex_lock (&self->drain_lock);
3070 self->draining = TRUE;
3071 buf->omx_buf->nFilledLen = 0;
3072 GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp,
3073 gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND,
3075 buf->omx_buf->nTickCount = 0;
3076 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS;
3077 err = gst_omx_port_release_buffer (self->enc_in_port, buf);
3078 if (err != OMX_ErrorNone) {
3079 GST_ERROR_OBJECT (self, "Failed to drain component: %s (0x%08x)",
3080 gst_omx_error_to_string (err), err);
3081 g_mutex_unlock (&self->drain_lock);
3082 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3083 return GST_FLOW_ERROR;
3085 GST_DEBUG_OBJECT (self, "Waiting until component is drained");
3086 g_cond_wait (&self->drain_cond, &self->drain_lock);
3087 GST_DEBUG_OBJECT (self, "Drained component");
3088 g_mutex_unlock (&self->drain_lock);
3089 GST_VIDEO_ENCODER_STREAM_LOCK (self);
3091 self->started = FALSE;
3096 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3098 pool_request_allocate_cb (GstBufferPool * pool, GstOMXVideoEnc * self)
3100 GstStructure *config;
3103 gst_omx_port_set_dmabuf (self->enc_in_port, TRUE);
3105 config = gst_buffer_pool_get_config (pool);
3107 if (!gst_buffer_pool_config_get_params (config, NULL, NULL, &min, NULL)) {
3108 gst_structure_free (config);
3111 gst_structure_free (config);
3113 GST_DEBUG_OBJECT (self,
3114 "input pool configured for %d buffers, adjust nBufferCountActual", min);
3116 if (!gst_omx_port_update_buffer_count_actual (self->enc_in_port, min))
3119 if (!gst_omx_video_enc_set_to_idle (self))
3122 self->input_allocation = GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
3123 self->input_dmabuf = TRUE;
3125 /* gst_omx_port_acquire_buffer() will fail if the input port is stil flushing
3126 * which will prevent upstream from acquiring buffers. */
3127 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
3132 static GstBufferPool *
3133 create_input_pool (GstOMXVideoEnc * self, GstCaps * caps, guint num_buffers)
3135 GstBufferPool *pool;
3136 GstStructure *config;
3139 gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->enc,
3140 self->enc_in_port, GST_OMX_BUFFER_MODE_DMABUF);
3142 g_signal_connect_object (pool, "allocate",
3143 G_CALLBACK (pool_request_allocate_cb), self, 0);
3145 config = gst_buffer_pool_get_config (pool);
3147 gst_buffer_pool_config_set_params (config, caps,
3148 self->enc_in_port->port_def.nBufferSize, num_buffers, 0);
3150 if (!gst_buffer_pool_set_config (pool, config)) {
3151 GST_INFO_OBJECT (self, "Failed to set config on input pool");
3152 gst_object_unref (pool);
3161 gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
3164 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
3168 GstBufferPool *pool = NULL;
3170 gst_query_parse_allocation (query, &caps, NULL);
3173 GST_WARNING_OBJECT (self, "allocation query does not contain caps");
3177 if (!gst_video_info_from_caps (&info, caps)) {
3178 GST_WARNING_OBJECT (self, "Failed to parse caps %" GST_PTR_FORMAT, caps);
3182 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
3184 num_buffers = self->enc_in_port->port_def.nBufferCountMin + 1;
3186 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3187 /* dmabuf export is currently only supported on Zynqultrascaleplus */
3188 pool = create_input_pool (self, caps, num_buffers);
3190 GST_WARNING_OBJECT (self, "Failed to create and configure pool");
3195 GST_DEBUG_OBJECT (self,
3196 "request at least %d buffers of size %" G_GSIZE_FORMAT, num_buffers,
3198 gst_query_add_allocation_pool (query, pool,
3199 self->enc_in_port->port_def.nBufferSize, num_buffers, 0);
3201 self->in_pool_used = FALSE;
3203 g_clear_object (&pool);
3206 GST_VIDEO_ENCODER_CLASS
3207 (gst_omx_video_enc_parent_class)->propose_allocation (encoder, query);
3211 filter_supported_formats (GList * negotiation_map)
3215 for (cur = negotiation_map; cur != NULL;) {
3216 GstOMXVideoNegotiationMap *nmap = (GstOMXVideoNegotiationMap *) (cur->data);
3219 switch (nmap->format) {
3220 case GST_VIDEO_FORMAT_I420:
3221 case GST_VIDEO_FORMAT_NV12:
3222 case GST_VIDEO_FORMAT_NV12_10LE32:
3223 case GST_VIDEO_FORMAT_NV16:
3224 case GST_VIDEO_FORMAT_NV16_10LE32:
3225 //case GST_VIDEO_FORMAT_ABGR:
3226 //case GST_VIDEO_FORMAT_ARGB:
3227 cur = g_list_next (cur);
3230 gst_omx_video_negotiation_map_free (nmap);
3231 next = g_list_next (cur);
3232 negotiation_map = g_list_delete_link (negotiation_map, cur);
3237 return negotiation_map;
3241 gst_omx_video_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
3243 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
3244 GList *negotiation_map = NULL;
3245 GstCaps *comp_supported_caps;
3249 return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
3252 gst_omx_video_get_supported_colorformats (self->enc_in_port,
3254 negotiation_map = filter_supported_formats (negotiation_map);
3256 comp_supported_caps = gst_omx_video_get_caps_for_map (negotiation_map);
3257 g_list_free_full (negotiation_map,
3258 (GDestroyNotify) gst_omx_video_negotiation_map_free);
3260 if (!gst_caps_is_empty (comp_supported_caps)) {
3262 gst_video_encoder_proxy_getcaps (encoder, comp_supported_caps, filter);
3263 gst_caps_unref (comp_supported_caps);
3265 gst_caps_unref (comp_supported_caps);
3266 ret = gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
3269 GST_LOG_OBJECT (encoder, "Supported caps %" GST_PTR_FORMAT, ret);
3275 gst_omx_video_enc_decide_allocation (GstVideoEncoder * encoder,
3278 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
3281 if (!GST_VIDEO_ENCODER_CLASS
3282 (gst_omx_video_enc_parent_class)->decide_allocation (encoder, query))
3285 if (gst_query_get_n_allocation_pools (query)) {
3286 gst_query_parse_nth_allocation_pool (query, 0, NULL, NULL, &min, NULL);
3287 GST_DEBUG_OBJECT (self,
3288 "Downstream requested %d buffers, adjust number of output buffers accordingly",
3291 GST_DEBUG_OBJECT (self, "Downstream didn't set any allocation pool info");
3294 self->nb_downstream_buffers = min;