2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
26 /* for stats file handling */
28 #include <glib/gstdio.h>
31 #include <libavcodec/avcodec.h>
32 #include <libavutil/stereo3d.h>
35 #include "gstavcodecmap.h"
36 #include "gstavutils.h"
37 #include "gstavvidenc.h"
40 #define DEFAULT_VIDEO_BITRATE 300000 /* in bps */
41 #define DEFAULT_VIDEO_GOP_SIZE 15
43 #define DEFAULT_WIDTH 352
44 #define DEFAULT_HEIGHT 288
47 #define VIDEO_BUFFER_SIZE (1024*1024)
62 PROP_RTP_PAYLOAD_SIZE,
68 #define GST_TYPE_ME_METHOD (gst_ffmpegvidenc_me_method_get_type())
70 gst_ffmpegvidenc_me_method_get_type (void)
72 static GType ffmpegenc_me_method_type = 0;
73 static GEnumValue ffmpegenc_me_methods[] = {
74 {ME_ZERO, "None (Very low quality)", "zero"},
75 {ME_FULL, "Full (Slow, unmaintained)", "full"},
76 {ME_LOG, "Logarithmic (Low quality, unmaintained)", "logarithmic"},
77 {ME_PHODS, "phods (Low quality, unmaintained)", "phods"},
78 {ME_EPZS, "EPZS (Best quality, Fast)", "epzs"},
79 {ME_X1, "X1 (Experimental)", "x1"},
82 if (!ffmpegenc_me_method_type) {
83 ffmpegenc_me_method_type =
84 g_enum_register_static ("GstLibAVVidEncMeMethod", ffmpegenc_me_methods);
86 return ffmpegenc_me_method_type;
89 /* A number of function prototypes are given so we can refer to them later. */
90 static void gst_ffmpegvidenc_class_init (GstFFMpegVidEncClass * klass);
91 static void gst_ffmpegvidenc_base_init (GstFFMpegVidEncClass * klass);
92 static void gst_ffmpegvidenc_init (GstFFMpegVidEnc * ffmpegenc);
93 static void gst_ffmpegvidenc_finalize (GObject * object);
95 static gboolean gst_ffmpegvidenc_start (GstVideoEncoder * encoder);
96 static gboolean gst_ffmpegvidenc_stop (GstVideoEncoder * encoder);
97 static GstFlowReturn gst_ffmpegvidenc_finish (GstVideoEncoder * encoder);
98 static gboolean gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
99 GstVideoCodecState * state);
100 static gboolean gst_ffmpegvidenc_propose_allocation (GstVideoEncoder * encoder,
102 static gboolean gst_ffmpegvidenc_flush (GstVideoEncoder * encoder);
104 static GstFlowReturn gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
105 GstVideoCodecFrame * frame);
107 static void gst_ffmpegvidenc_set_property (GObject * object,
108 guint prop_id, const GValue * value, GParamSpec * pspec);
109 static void gst_ffmpegvidenc_get_property (GObject * object,
110 guint prop_id, GValue * value, GParamSpec * pspec);
112 #define GST_FFENC_PARAMS_QDATA g_quark_from_static_string("avenc-params")
114 static GstElementClass *parent_class = NULL;
116 /*static guint gst_ffmpegvidenc_signals[LAST_SIGNAL] = { 0 }; */
119 gst_ffmpegvidenc_base_init (GstFFMpegVidEncClass * klass)
121 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
123 GstPadTemplate *srctempl = NULL, *sinktempl = NULL;
124 GstCaps *srccaps = NULL, *sinkcaps = NULL;
125 gchar *longname, *description;
126 const gchar *classification;
129 (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
130 GST_FFENC_PARAMS_QDATA);
131 g_assert (in_plugin != NULL);
133 /* construct the element details struct */
134 longname = g_strdup_printf ("libav %s encoder", in_plugin->long_name);
135 description = g_strdup_printf ("libav %s encoder", in_plugin->name);
137 gst_ffmpeg_codecid_is_image (in_plugin->id) ? "Codec/Encoder/Image" :
138 "Codec/Encoder/Video";
139 gst_element_class_set_metadata (element_class, longname,
140 classification, description,
141 "Wim Taymans <wim.taymans@gmail.com>, "
142 "Ronald Bultje <rbultje@ronald.bitfreak.net>");
144 g_free (description);
146 if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) {
147 GST_DEBUG ("Couldn't get source caps for encoder '%s'", in_plugin->name);
148 srccaps = gst_caps_new_empty_simple ("unknown/unknown");
151 sinkcaps = gst_ffmpeg_codectype_to_video_caps (NULL,
152 in_plugin->id, TRUE, in_plugin);
154 GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name);
155 sinkcaps = gst_caps_new_empty_simple ("unknown/unknown");
159 sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
160 GST_PAD_ALWAYS, sinkcaps);
161 srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);
163 gst_element_class_add_pad_template (element_class, srctempl);
164 gst_element_class_add_pad_template (element_class, sinktempl);
166 gst_caps_unref (sinkcaps);
167 gst_caps_unref (srccaps);
169 klass->in_plugin = in_plugin;
170 klass->srctempl = srctempl;
171 klass->sinktempl = sinktempl;
177 gst_ffmpegvidenc_class_init (GstFFMpegVidEncClass * klass)
179 GObjectClass *gobject_class;
180 GstVideoEncoderClass *venc_class;
183 gobject_class = (GObjectClass *) klass;
184 venc_class = (GstVideoEncoderClass *) klass;
186 parent_class = g_type_class_peek_parent (klass);
188 gobject_class->set_property = gst_ffmpegvidenc_set_property;
189 gobject_class->get_property = gst_ffmpegvidenc_get_property;
191 /* FIXME: could use -1 for a sensible per-codec default based on
192 * e.g. input resolution and framerate */
193 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BIT_RATE,
194 g_param_spec_int ("bitrate", "Bit Rate",
195 "Target Video Bitrate", 0, G_MAXINT, DEFAULT_VIDEO_BITRATE,
196 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
197 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GOP_SIZE,
198 g_param_spec_int ("gop-size", "GOP Size",
199 "Number of frames within one GOP", 0, G_MAXINT,
200 DEFAULT_VIDEO_GOP_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
201 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ME_METHOD,
202 g_param_spec_enum ("me-method", "ME Method", "Motion Estimation Method",
203 GST_TYPE_ME_METHOD, ME_EPZS,
204 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
206 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BUFSIZE,
207 g_param_spec_int ("buffer-size", "Buffer Size",
208 "Size of the video buffers", 0, G_MAXINT, 0,
209 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
210 g_object_class_install_property (G_OBJECT_CLASS (klass),
211 PROP_RTP_PAYLOAD_SIZE, g_param_spec_int ("rtp-payload-size",
212 "RTP Payload Size", "Target GOB length", 0, G_MAXINT, 0,
213 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
215 caps = klass->in_plugin->capabilities;
216 if (caps & (AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS)) {
217 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_THREADS,
218 g_param_spec_int ("max-threads", "Maximum encode threads",
219 "Maximum number of worker threads to spawn. (0 = auto)",
220 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
223 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLIANCE,
224 g_param_spec_enum ("compliance", "Compliance",
225 "Adherence of the encoder to the specifications",
226 GST_TYPE_FFMPEG_COMPLIANCE, FFMPEG_DEFAULT_COMPLIANCE,
227 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
229 /* register additional properties, possibly dependent on the exact CODEC */
230 gst_ffmpeg_cfg_install_property (klass, PROP_CFG_BASE);
232 venc_class->start = gst_ffmpegvidenc_start;
233 venc_class->stop = gst_ffmpegvidenc_stop;
234 venc_class->finish = gst_ffmpegvidenc_finish;
235 venc_class->handle_frame = gst_ffmpegvidenc_handle_frame;
236 venc_class->set_format = gst_ffmpegvidenc_set_format;
237 venc_class->propose_allocation = gst_ffmpegvidenc_propose_allocation;
238 venc_class->flush = gst_ffmpegvidenc_flush;
240 gobject_class->finalize = gst_ffmpegvidenc_finalize;
244 gst_ffmpegvidenc_init (GstFFMpegVidEnc * ffmpegenc)
246 GstFFMpegVidEncClass *klass =
247 (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
249 GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (ffmpegenc));
252 ffmpegenc->context = avcodec_alloc_context3 (klass->in_plugin);
253 ffmpegenc->picture = av_frame_alloc ();
254 ffmpegenc->opened = FALSE;
256 ffmpegenc->file = NULL;
258 ffmpegenc->bitrate = DEFAULT_VIDEO_BITRATE;
259 ffmpegenc->me_method = ME_EPZS;
260 ffmpegenc->buffer_size = 512 * 1024;
261 ffmpegenc->gop_size = DEFAULT_VIDEO_GOP_SIZE;
262 ffmpegenc->rtp_payload_size = 0;
263 ffmpegenc->compliance = FFMPEG_DEFAULT_COMPLIANCE;
264 ffmpegenc->max_threads = 0;
267 ffmpegenc->lmax = 31;
268 ffmpegenc->max_key_interval = 0;
270 gst_ffmpeg_cfg_set_defaults (ffmpegenc);
274 gst_ffmpegvidenc_finalize (GObject * object)
276 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) object;
278 gst_ffmpeg_cfg_finalize (ffmpegenc);
280 /* clean up remaining allocated data */
281 av_frame_free (&ffmpegenc->picture);
282 gst_ffmpeg_avcodec_close (ffmpegenc->context);
283 av_free (ffmpegenc->context);
285 g_free (ffmpegenc->filename);
287 G_OBJECT_CLASS (parent_class)->finalize (object);
291 gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
292 GstVideoCodecState * state)
295 GstCaps *allowed_caps;
297 GstVideoCodecState *output_format;
298 enum AVPixelFormat pix_fmt;
299 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
300 GstFFMpegVidEncClass *oclass =
301 (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
303 /* close old session */
304 if (ffmpegenc->opened) {
305 gst_ffmpeg_avcodec_close (ffmpegenc->context);
306 ffmpegenc->opened = FALSE;
307 if (avcodec_get_context_defaults3 (ffmpegenc->context,
308 oclass->in_plugin) < 0) {
309 GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
314 /* if we set it in _getcaps we should set it also in _link */
315 ffmpegenc->context->strict_std_compliance = ffmpegenc->compliance;
317 /* user defined properties */
318 ffmpegenc->context->bit_rate = ffmpegenc->bitrate;
319 ffmpegenc->context->bit_rate_tolerance = ffmpegenc->bitrate;
320 ffmpegenc->context->gop_size = ffmpegenc->gop_size;
321 ffmpegenc->context->me_method = ffmpegenc->me_method;
322 GST_DEBUG_OBJECT (ffmpegenc, "Setting avcontext to bitrate %d, gop_size %d",
323 ffmpegenc->bitrate, ffmpegenc->gop_size);
325 if (ffmpegenc->max_threads == 0) {
326 if (!(oclass->in_plugin->capabilities & AV_CODEC_CAP_AUTO_THREADS))
327 ffmpegenc->context->thread_count = gst_ffmpeg_auto_max_threads ();
329 ffmpegenc->context->thread_count = 0;
331 ffmpegenc->context->thread_count = ffmpegenc->max_threads;
333 /* RTP payload used for GOB production (for Asterisk) */
334 if (ffmpegenc->rtp_payload_size) {
335 ffmpegenc->context->rtp_payload_size = ffmpegenc->rtp_payload_size;
338 /* additional avcodec settings */
339 /* first fill in the majority by copying over */
340 gst_ffmpeg_cfg_fill_context (ffmpegenc, ffmpegenc->context);
342 /* then handle some special cases */
343 ffmpegenc->context->lmin = (ffmpegenc->lmin * FF_QP2LAMBDA + 0.5);
344 ffmpegenc->context->lmax = (ffmpegenc->lmax * FF_QP2LAMBDA + 0.5);
346 if (ffmpegenc->interlaced) {
347 ffmpegenc->context->flags |=
348 AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME;
351 /* some other defaults */
352 ffmpegenc->context->rc_strategy = 2;
353 ffmpegenc->context->b_frame_strategy = 0;
354 ffmpegenc->context->coder_type = 0;
355 ffmpegenc->context->context_model = 0;
356 ffmpegenc->context->scenechange_threshold = 0;
358 /* and last but not least the pass; CBR, 2-pass, etc */
359 ffmpegenc->context->flags |= ffmpegenc->pass;
360 switch (ffmpegenc->pass) {
361 /* some additional action depends on type of pass */
362 case AV_CODEC_FLAG_QSCALE:
363 ffmpegenc->context->global_quality
364 = ffmpegenc->picture->quality = FF_QP2LAMBDA * ffmpegenc->quantizer;
366 case AV_CODEC_FLAG_PASS1: /* need to prepare a stats file */
367 /* we don't close when changing caps, fingers crossed */
368 if (!ffmpegenc->file)
369 ffmpegenc->file = g_fopen (ffmpegenc->filename, "w");
370 if (!ffmpegenc->file)
373 case AV_CODEC_FLAG_PASS2:
374 { /* need to read the whole stats file ! */
377 if (!g_file_get_contents (ffmpegenc->filename,
378 &ffmpegenc->context->stats_in, &size, NULL))
387 GST_DEBUG_OBJECT (ffmpegenc, "Extracting common video information");
388 /* fetch pix_fmt, fps, par, width, height... */
389 gst_ffmpeg_videoinfo_to_context (&state->info, ffmpegenc->context);
391 /* sanitize time base */
392 if (ffmpegenc->context->time_base.num <= 0
393 || ffmpegenc->context->time_base.den <= 0)
394 goto insane_timebase;
396 if ((oclass->in_plugin->id == AV_CODEC_ID_MPEG4)
397 && (ffmpegenc->context->time_base.den > 65535)) {
398 /* MPEG4 Standards do not support time_base denominator greater than
399 * (1<<16) - 1 . We therefore scale them down.
400 * Agreed, it will not be the exact framerate... but the difference
401 * shouldn't be that noticeable */
402 ffmpegenc->context->time_base.num =
403 (gint) gst_util_uint64_scale_int (ffmpegenc->context->time_base.num,
404 65535, ffmpegenc->context->time_base.den);
405 ffmpegenc->context->time_base.den = 65535;
406 GST_LOG_OBJECT (ffmpegenc, "MPEG4 : scaled down framerate to %d / %d",
407 ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num);
410 pix_fmt = ffmpegenc->context->pix_fmt;
412 /* max-key-interval may need the framerate set above */
413 if (ffmpegenc->max_key_interval) {
416 /* override gop-size */
417 ctx = ffmpegenc->context;
418 ctx->gop_size = (ffmpegenc->max_key_interval < 0) ?
419 (-ffmpegenc->max_key_interval
420 * (ctx->time_base.den * ctx->ticks_per_frame / ctx->time_base.num))
421 : ffmpegenc->max_key_interval;
424 /* some codecs support more than one format, first auto-choose one */
425 GST_DEBUG_OBJECT (ffmpegenc, "picking an output format ...");
426 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
428 GST_DEBUG_OBJECT (ffmpegenc, "... but no peer, using template caps");
429 /* we need to copy because get_allowed_caps returns a ref, and
430 * get_pad_template_caps doesn't */
432 gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
434 GST_DEBUG_OBJECT (ffmpegenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
435 gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
436 oclass->in_plugin->type, allowed_caps, ffmpegenc->context);
439 if (gst_ffmpeg_avcodec_open (ffmpegenc->context, oclass->in_plugin) < 0) {
440 gst_caps_unref (allowed_caps);
441 goto open_codec_fail;
444 /* is the colourspace correct? */
445 if (pix_fmt != ffmpegenc->context->pix_fmt) {
446 gst_caps_unref (allowed_caps);
450 /* we may have failed mapping caps to a pixfmt,
451 * and quite some codecs do not make up their own mind about that
452 * in any case, _NONE can never work out later on */
453 if (pix_fmt == AV_PIX_FMT_NONE) {
454 gst_caps_unref (allowed_caps);
458 /* second pass stats buffer no longer needed */
459 g_free (ffmpegenc->context->stats_in);
461 /* try to set this caps on the other side */
462 other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
463 ffmpegenc->context, TRUE);
466 gst_caps_unref (allowed_caps);
467 goto unsupported_codec;
470 icaps = gst_caps_intersect (allowed_caps, other_caps);
471 gst_caps_unref (allowed_caps);
472 gst_caps_unref (other_caps);
473 if (gst_caps_is_empty (icaps)) {
474 gst_caps_unref (icaps);
475 goto unsupported_codec;
477 icaps = gst_caps_fixate (icaps);
479 GST_DEBUG_OBJECT (ffmpegenc, "codec flags 0x%08x", ffmpegenc->context->flags);
481 /* Store input state and set output state */
482 if (ffmpegenc->input_state)
483 gst_video_codec_state_unref (ffmpegenc->input_state);
484 ffmpegenc->input_state = gst_video_codec_state_ref (state);
486 output_format = gst_video_encoder_set_output_state (encoder, icaps, state);
487 gst_video_codec_state_unref (output_format);
489 /* Store some tags */
491 GstTagList *tags = gst_tag_list_new_empty ();
494 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
495 (guint) ffmpegenc->context->bit_rate, NULL);
498 gst_ffmpeg_get_codecid_longname (ffmpegenc->context->codec_id)))
499 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_VIDEO_CODEC, codec,
502 gst_video_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE);
503 gst_tag_list_unref (tags);
507 ffmpegenc->opened = TRUE;
514 GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE,
515 (("Could not open file \"%s\" for writing."), ffmpegenc->filename),
521 GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ,
522 (("Could not get contents of file \"%s\"."), ffmpegenc->filename),
529 GST_ERROR_OBJECT (ffmpegenc, "Rejecting time base %d/%d",
530 ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num);
531 goto cleanup_stats_in;
535 GST_DEBUG ("Unsupported codec - no caps found");
536 goto cleanup_stats_in;
540 GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to open libav codec",
541 oclass->in_plugin->name);
547 GST_DEBUG_OBJECT (ffmpegenc,
548 "avenc_%s: AV wants different colourspace (%d given, %d wanted)",
549 oclass->in_plugin->name, pix_fmt, ffmpegenc->context->pix_fmt);
555 GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to determine input format",
556 oclass->in_plugin->name);
561 gst_ffmpeg_avcodec_close (ffmpegenc->context);
562 if (avcodec_get_context_defaults3 (ffmpegenc->context,
563 oclass->in_plugin) < 0)
564 GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
565 goto cleanup_stats_in;
569 g_free (ffmpegenc->context->stats_in);
576 gst_ffmpegvidenc_propose_allocation (GstVideoEncoder * encoder,
579 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
581 return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
586 gst_ffmpegvidenc_free_avpacket (gpointer pkt)
588 av_packet_unref ((AVPacket *) pkt);
589 g_slice_free (AVPacket, pkt);
595 GstVideoFrame vframe;
599 buffer_info_free (void *opaque, guint8 * data)
601 BufferInfo *info = opaque;
603 gst_video_frame_unmap (&info->vframe);
604 gst_buffer_unref (info->buffer);
605 g_slice_free (BufferInfo, info);
608 static enum AVStereo3DType
609 stereo_gst_to_av (GstVideoMultiviewMode mview_mode)
611 switch (mview_mode) {
612 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
613 return AV_STEREO3D_SIDEBYSIDE;
614 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
615 return AV_STEREO3D_TOPBOTTOM;
616 case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
617 return AV_STEREO3D_FRAMESEQUENCE;
618 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
619 return AV_STEREO3D_CHECKERBOARD;
620 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX:
621 return AV_STEREO3D_SIDEBYSIDE_QUINCUNX;
622 case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED:
623 return AV_STEREO3D_LINES;
624 case GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED:
625 return AV_STEREO3D_COLUMNS;
629 GST_WARNING ("Unsupported multiview mode - no mapping in libav");
630 return AV_STEREO3D_2D;
634 gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
635 GstVideoCodecFrame * frame)
637 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
640 GstVideoInfo *info = &ffmpegenc->input_state->info;
643 BufferInfo *buffer_info;
645 if (ffmpegenc->interlaced) {
646 ffmpegenc->picture->interlaced_frame = TRUE;
647 /* if this is not the case, a filter element should be used to swap fields */
648 ffmpegenc->picture->top_field_first =
649 GST_BUFFER_FLAG_IS_SET (frame->input_buffer, GST_VIDEO_BUFFER_FLAG_TFF);
652 if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) != GST_VIDEO_MULTIVIEW_MODE_NONE) {
653 AVStereo3D *stereo = av_stereo3d_create_side_data (ffmpegenc->picture);
654 stereo->type = stereo_gst_to_av (GST_VIDEO_INFO_MULTIVIEW_MODE (info));
656 if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) &
657 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST) {
658 stereo->flags = AV_STEREO3D_FLAG_INVERT;
662 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame))
663 ffmpegenc->picture->pict_type = AV_PICTURE_TYPE_I;
665 buffer_info = g_slice_new0 (BufferInfo);
666 buffer_info->buffer = gst_buffer_ref (frame->input_buffer);
668 if (!gst_video_frame_map (&buffer_info->vframe, info, frame->input_buffer,
670 GST_ERROR_OBJECT (encoder, "Failed to map input buffer");
671 gst_buffer_unref (buffer_info->buffer);
672 g_slice_free (BufferInfo, buffer_info);
673 gst_video_codec_frame_unref (frame);
674 return GST_FLOW_ERROR;
678 ffmpegenc->picture->buf[0] =
679 av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);
680 for (c = 0; c < AV_NUM_DATA_POINTERS; c++) {
681 if (c < GST_VIDEO_INFO_N_COMPONENTS (info)) {
682 ffmpegenc->picture->data[c] =
683 GST_VIDEO_FRAME_PLANE_DATA (&buffer_info->vframe, c);
684 ffmpegenc->picture->linesize[c] =
685 GST_VIDEO_FRAME_COMP_STRIDE (&buffer_info->vframe, c);
687 ffmpegenc->picture->data[c] = NULL;
688 ffmpegenc->picture->linesize[c] = 0;
692 ffmpegenc->picture->format = ffmpegenc->context->pix_fmt;
693 ffmpegenc->picture->width = GST_VIDEO_FRAME_WIDTH (&buffer_info->vframe);
694 ffmpegenc->picture->height = GST_VIDEO_FRAME_HEIGHT (&buffer_info->vframe);
696 ffmpegenc->picture->pts =
697 gst_ffmpeg_time_gst_to_ff (frame->pts /
698 ffmpegenc->context->ticks_per_frame, ffmpegenc->context->time_base);
701 pkt = g_slice_new0 (AVPacket);
704 avcodec_encode_video2 (ffmpegenc->context, pkt, ffmpegenc->picture,
707 av_frame_unref (ffmpegenc->picture);
709 if (ret < 0 || !have_data)
710 g_slice_free (AVPacket, pkt);
715 /* Encoder needs more data */
717 gst_video_codec_frame_unref (frame);
721 /* save stats info if there is some as well as a stats file */
722 if (ffmpegenc->file && ffmpegenc->context->stats_out)
723 if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0)
724 GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE,
725 (("Could not write to file \"%s\"."), ffmpegenc->filename),
728 gst_video_codec_frame_unref (frame);
730 /* Get oldest frame */
731 frame = gst_video_encoder_get_oldest_frame (encoder);
734 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data,
735 pkt->size, 0, pkt->size, pkt, gst_ffmpegvidenc_free_avpacket);
736 frame->output_buffer = outbuf;
738 if (pkt->flags & AV_PKT_FLAG_KEY)
739 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
741 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
743 return gst_video_encoder_finish_frame (encoder, frame);
748 #ifndef GST_DISABLE_GST_DEBUG
749 GstFFMpegVidEncClass *oclass =
750 (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
751 GST_ERROR_OBJECT (ffmpegenc,
752 "avenc_%s: failed to encode buffer", oclass->in_plugin->name);
753 #endif /* GST_DISABLE_GST_DEBUG */
754 /* avoid frame (and ts etc) piling up */
755 return gst_video_encoder_finish_frame (encoder, frame);
760 gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send)
762 GstVideoCodecFrame *frame;
763 GstFlowReturn flow_ret = GST_FLOW_OK;
769 GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send);
771 /* no need to empty codec if there is none */
772 if (!ffmpegenc->opened)
776 gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (ffmpegenc)))) {
777 pkt = g_slice_new0 (AVPacket);
780 ret = avcodec_encode_video2 (ffmpegenc->context, pkt, NULL, &have_data);
782 if (ret < 0) { /* there should be something, notify and give up */
783 #ifndef GST_DISABLE_GST_DEBUG
784 GstFFMpegVidEncClass *oclass =
785 (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
786 GST_WARNING_OBJECT (ffmpegenc,
787 "avenc_%s: failed to flush buffer", oclass->in_plugin->name);
788 #endif /* GST_DISABLE_GST_DEBUG */
789 g_slice_free (AVPacket, pkt);
790 gst_video_codec_frame_unref (frame);
794 /* save stats info if there is some as well as a stats file */
795 if (ffmpegenc->file && ffmpegenc->context->stats_out)
796 if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0)
797 GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE,
798 (("Could not write to file \"%s\"."), ffmpegenc->filename),
801 if (send && have_data) {
803 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data,
804 pkt->size, 0, pkt->size, pkt, gst_ffmpegvidenc_free_avpacket);
805 frame->output_buffer = outbuf;
807 if (pkt->flags & AV_PKT_FLAG_KEY)
808 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
810 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
813 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame);
815 /* no frame attached, so will be skipped and removed from frame list */
816 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame);
827 gst_ffmpegvidenc_set_property (GObject * object,
828 guint prop_id, const GValue * value, GParamSpec * pspec)
830 GstFFMpegVidEnc *ffmpegenc;
832 /* Get a pointer of the right type. */
833 ffmpegenc = (GstFFMpegVidEnc *) (object);
835 if (ffmpegenc->opened) {
836 GST_WARNING_OBJECT (ffmpegenc,
837 "Can't change properties once decoder is setup !");
841 /* Check the argument id to see which argument we're setting. */
844 ffmpegenc->bitrate = g_value_get_int (value);
847 ffmpegenc->gop_size = g_value_get_int (value);
850 ffmpegenc->me_method = g_value_get_enum (value);
854 case PROP_RTP_PAYLOAD_SIZE:
855 ffmpegenc->rtp_payload_size = g_value_get_int (value);
857 case PROP_COMPLIANCE:
858 ffmpegenc->compliance = g_value_get_enum (value);
860 case PROP_MAX_THREADS:
861 ffmpegenc->max_threads = g_value_get_int (value);
864 if (!gst_ffmpeg_cfg_set_property (object, value, pspec))
865 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
870 /* The set function is simply the inverse of the get fuction. */
872 gst_ffmpegvidenc_get_property (GObject * object,
873 guint prop_id, GValue * value, GParamSpec * pspec)
875 GstFFMpegVidEnc *ffmpegenc;
877 /* It's not null if we got it, but it might not be ours */
878 ffmpegenc = (GstFFMpegVidEnc *) (object);
882 g_value_set_int (value, ffmpegenc->bitrate);
885 g_value_set_int (value, ffmpegenc->gop_size);
888 g_value_set_enum (value, ffmpegenc->me_method);
891 g_value_set_int (value, ffmpegenc->buffer_size);
893 case PROP_RTP_PAYLOAD_SIZE:
894 g_value_set_int (value, ffmpegenc->rtp_payload_size);
896 case PROP_COMPLIANCE:
897 g_value_set_enum (value, ffmpegenc->compliance);
899 case PROP_MAX_THREADS:
900 g_value_set_int (value, ffmpegenc->max_threads);
903 if (!gst_ffmpeg_cfg_get_property (object, value, pspec))
904 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
910 gst_ffmpegvidenc_flush (GstVideoEncoder * encoder)
912 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
914 if (ffmpegenc->opened)
915 avcodec_flush_buffers (ffmpegenc->context);
921 gst_ffmpegvidenc_start (GstVideoEncoder * encoder)
923 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
924 GstFFMpegVidEncClass *oclass =
925 (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
927 /* close old session */
928 gst_ffmpeg_avcodec_close (ffmpegenc->context);
929 if (avcodec_get_context_defaults3 (ffmpegenc->context, oclass->in_plugin) < 0) {
930 GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
938 gst_ffmpegvidenc_stop (GstVideoEncoder * encoder)
940 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
942 gst_ffmpegvidenc_flush_buffers (ffmpegenc, FALSE);
943 gst_ffmpeg_avcodec_close (ffmpegenc->context);
944 ffmpegenc->opened = FALSE;
946 if (ffmpegenc->file) {
947 fclose (ffmpegenc->file);
948 ffmpegenc->file = NULL;
950 if (ffmpegenc->input_state) {
951 gst_video_codec_state_unref (ffmpegenc->input_state);
952 ffmpegenc->input_state = NULL;
959 gst_ffmpegvidenc_finish (GstVideoEncoder * encoder)
961 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
963 return gst_ffmpegvidenc_flush_buffers (ffmpegenc, TRUE);
967 gst_ffmpegvidenc_register (GstPlugin * plugin)
969 GTypeInfo typeinfo = {
970 sizeof (GstFFMpegVidEncClass),
971 (GBaseInitFunc) gst_ffmpegvidenc_base_init,
973 (GClassInitFunc) gst_ffmpegvidenc_class_init,
976 sizeof (GstFFMpegVidEnc),
978 (GInstanceInitFunc) gst_ffmpegvidenc_init,
984 GST_LOG ("Registering encoders");
986 /* build global ffmpeg param/property info */
987 gst_ffmpeg_cfg_init ();
989 in_plugin = av_codec_next (NULL);
993 /* Skip non-AV codecs */
994 if (in_plugin->type != AVMEDIA_TYPE_VIDEO)
997 /* no quasi codecs, please */
998 if (in_plugin->id == AV_CODEC_ID_RAWVIDEO ||
999 in_plugin->id == AV_CODEC_ID_V210 ||
1000 in_plugin->id == AV_CODEC_ID_V210X ||
1001 in_plugin->id == AV_CODEC_ID_V308 ||
1002 in_plugin->id == AV_CODEC_ID_V408 ||
1003 in_plugin->id == AV_CODEC_ID_V410 ||
1004 in_plugin->id == AV_CODEC_ID_R210
1005 || in_plugin->id == AV_CODEC_ID_AYUV
1006 || in_plugin->id == AV_CODEC_ID_Y41P
1007 || in_plugin->id == AV_CODEC_ID_012V
1008 || in_plugin->id == AV_CODEC_ID_YUV4
1009 #if AV_VERSION_INT (LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO) >= \
1010 AV_VERSION_INT (57,4,0)
1011 || in_plugin->id == AV_CODEC_ID_WRAPPED_AVFRAME
1013 || in_plugin->id == AV_CODEC_ID_ZLIB) {
1017 /* No encoders depending on external libraries (we don't build them, but
1018 * people who build against an external ffmpeg might have them.
1019 * We have native gstreamer plugins for all of those libraries anyway. */
1020 if (!strncmp (in_plugin->name, "lib", 3)) {
1022 ("Not using external library encoder %s. Use the gstreamer-native ones instead.",
1027 if (strstr (in_plugin->name, "vaapi")) {
1029 ("Ignoring VAAPI encoder %s. We can't handle this outside of ffmpeg",
1034 if (strstr (in_plugin->name, "nvenc")) {
1036 ("Ignoring nvenc encoder %s. We can't handle this outside of ffmpeg",
1041 if (g_str_has_suffix (in_plugin->name, "_qsv")) {
1043 ("Ignoring qsv encoder %s. We can't handle this outside of ffmpeg",
1048 if (g_str_has_suffix (in_plugin->name, "_v4l2m2m")) {
1050 ("Ignoring V4L2 mem-to-mem encoder %s. We can't handle this outside of ffmpeg",
1055 /* only video encoders */
1056 if (!av_codec_is_encoder (in_plugin)
1057 || in_plugin->type != AVMEDIA_TYPE_VIDEO)
1060 /* FIXME : We should have a method to know cheaply whether we have a mapping
1061 * for the given plugin or not */
1063 GST_DEBUG ("Trying plugin %s [%s]", in_plugin->name, in_plugin->long_name);
1065 /* no codecs for which we're GUARANTEED to have better alternatives */
1066 if (!strcmp (in_plugin->name, "gif")) {
1067 GST_LOG ("Ignoring encoder %s", in_plugin->name);
1071 /* construct the type */
1072 type_name = g_strdup_printf ("avenc_%s", in_plugin->name);
1074 type = g_type_from_name (type_name);
1078 /* create the glib type now */
1080 g_type_register_static (GST_TYPE_VIDEO_ENCODER, type_name, &typeinfo,
1082 g_type_set_qdata (type, GST_FFENC_PARAMS_QDATA, (gpointer) in_plugin);
1085 static const GInterfaceInfo preset_info = {
1090 g_type_add_interface_static (type, GST_TYPE_PRESET, &preset_info);
1094 if (!gst_element_register (plugin, type_name, GST_RANK_SECONDARY, type)) {
1102 in_plugin = av_codec_next (in_plugin);
1105 GST_LOG ("Finished registering encoders");