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>
33 #include <libavutil/opt.h>
36 #include "gstavcodecmap.h"
37 #include "gstavutils.h"
38 #include "gstavvidenc.h"
51 static void gst_ffmpegvidenc_class_init (GstFFMpegVidEncClass * klass);
52 static void gst_ffmpegvidenc_base_init (GstFFMpegVidEncClass * klass);
53 static void gst_ffmpegvidenc_init (GstFFMpegVidEnc * ffmpegenc);
54 static void gst_ffmpegvidenc_finalize (GObject * object);
56 static gboolean gst_ffmpegvidenc_start (GstVideoEncoder * encoder);
57 static gboolean gst_ffmpegvidenc_stop (GstVideoEncoder * encoder);
58 static GstFlowReturn gst_ffmpegvidenc_finish (GstVideoEncoder * encoder);
59 static gboolean gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
60 GstVideoCodecState * state);
61 static gboolean gst_ffmpegvidenc_propose_allocation (GstVideoEncoder * encoder,
63 static gboolean gst_ffmpegvidenc_flush (GstVideoEncoder * encoder);
65 static GstFlowReturn gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
66 GstVideoCodecFrame * frame);
68 static void gst_ffmpegvidenc_set_property (GObject * object,
69 guint prop_id, const GValue * value, GParamSpec * pspec);
70 static void gst_ffmpegvidenc_get_property (GObject * object,
71 guint prop_id, GValue * value, GParamSpec * pspec);
73 #define GST_FFENC_PARAMS_QDATA g_quark_from_static_string("avenc-params")
75 static GstElementClass *parent_class = NULL;
77 #define GST_TYPE_FFMPEG_PASS (gst_ffmpeg_pass_get_type ())
79 gst_ffmpeg_pass_get_type (void)
81 static GType ffmpeg_pass_type = 0;
83 if (!ffmpeg_pass_type) {
84 static const GEnumValue ffmpeg_passes[] = {
85 {0, "Constant Bitrate Encoding", "cbr"},
86 {AV_CODEC_FLAG_QSCALE, "Constant Quantizer", "quant"},
87 {AV_CODEC_FLAG_PASS1, "VBR Encoding - Pass 1", "pass1"},
88 {AV_CODEC_FLAG_PASS2, "VBR Encoding - Pass 2", "pass2"},
93 g_enum_register_static ("GstLibAVEncPass", ffmpeg_passes);
96 return ffmpeg_pass_type;
100 gst_ffmpegvidenc_base_init (GstFFMpegVidEncClass * klass)
102 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
104 GstPadTemplate *srctempl = NULL, *sinktempl = NULL;
105 GstCaps *srccaps = NULL, *sinkcaps = NULL;
106 gchar *longname, *description;
107 const gchar *classification;
110 (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
111 GST_FFENC_PARAMS_QDATA);
112 g_assert (in_plugin != NULL);
114 /* construct the element details struct */
115 longname = g_strdup_printf ("libav %s encoder", in_plugin->long_name);
116 description = g_strdup_printf ("libav %s encoder", in_plugin->name);
118 gst_ffmpeg_codecid_is_image (in_plugin->id) ? "Codec/Encoder/Image" :
119 "Codec/Encoder/Video";
120 gst_element_class_set_metadata (element_class, longname,
121 classification, description,
122 "Wim Taymans <wim.taymans@gmail.com>, "
123 "Ronald Bultje <rbultje@ronald.bitfreak.net>");
125 g_free (description);
127 if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) {
128 GST_DEBUG ("Couldn't get source caps for encoder '%s'", in_plugin->name);
129 srccaps = gst_caps_new_empty_simple ("unknown/unknown");
132 sinkcaps = gst_ffmpeg_codectype_to_video_caps (NULL,
133 in_plugin->id, TRUE, in_plugin);
135 GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name);
136 sinkcaps = gst_caps_new_empty_simple ("unknown/unknown");
140 sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
141 GST_PAD_ALWAYS, sinkcaps);
142 srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);
144 gst_element_class_add_pad_template (element_class, srctempl);
145 gst_element_class_add_pad_template (element_class, sinktempl);
147 gst_caps_unref (sinkcaps);
148 gst_caps_unref (srccaps);
150 klass->in_plugin = in_plugin;
151 klass->srctempl = srctempl;
152 klass->sinktempl = sinktempl;
158 gst_ffmpegvidenc_class_init (GstFFMpegVidEncClass * klass)
160 GObjectClass *gobject_class;
161 GstVideoEncoderClass *venc_class;
163 gobject_class = (GObjectClass *) klass;
164 venc_class = (GstVideoEncoderClass *) klass;
166 parent_class = g_type_class_peek_parent (klass);
168 gobject_class->set_property = gst_ffmpegvidenc_set_property;
169 gobject_class->get_property = gst_ffmpegvidenc_get_property;
171 g_object_class_install_property (gobject_class, PROP_QUANTIZER,
172 g_param_spec_float ("quantizer", "Constant Quantizer",
173 "Constant Quantizer", 0, 30, 0.01f,
174 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
176 g_object_class_install_property (gobject_class, PROP_PASS,
177 g_param_spec_enum ("pass", "Encoding pass/type",
178 "Encoding pass/type", GST_TYPE_FFMPEG_PASS, 0,
179 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
181 g_object_class_install_property (gobject_class, PROP_FILENAME,
182 g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
183 "Filename for multipass cache file", "stats.log",
184 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
186 /* register additional properties, possibly dependent on the exact CODEC */
187 gst_ffmpeg_cfg_install_properties (gobject_class, klass->in_plugin,
188 PROP_CFG_BASE, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM);
190 venc_class->start = gst_ffmpegvidenc_start;
191 venc_class->stop = gst_ffmpegvidenc_stop;
192 venc_class->finish = gst_ffmpegvidenc_finish;
193 venc_class->handle_frame = gst_ffmpegvidenc_handle_frame;
194 venc_class->set_format = gst_ffmpegvidenc_set_format;
195 venc_class->propose_allocation = gst_ffmpegvidenc_propose_allocation;
196 venc_class->flush = gst_ffmpegvidenc_flush;
198 gobject_class->finalize = gst_ffmpegvidenc_finalize;
202 gst_ffmpegvidenc_init (GstFFMpegVidEnc * ffmpegenc)
204 GstFFMpegVidEncClass *klass =
205 (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
207 GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (ffmpegenc));
209 ffmpegenc->context = avcodec_alloc_context3 (klass->in_plugin);
210 ffmpegenc->refcontext = avcodec_alloc_context3 (klass->in_plugin);
211 ffmpegenc->picture = av_frame_alloc ();
212 ffmpegenc->opened = FALSE;
213 ffmpegenc->file = NULL;
217 gst_ffmpegvidenc_finalize (GObject * object)
219 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) object;
221 /* clean up remaining allocated data */
222 av_frame_free (&ffmpegenc->picture);
223 gst_ffmpeg_avcodec_close (ffmpegenc->context);
224 av_free (ffmpegenc->context);
225 av_free (ffmpegenc->refcontext);
227 G_OBJECT_CLASS (parent_class)->finalize (object);
231 gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
232 GstVideoCodecState * state)
235 GstCaps *allowed_caps;
237 GstVideoCodecState *output_format;
238 enum AVPixelFormat pix_fmt;
239 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
240 GstFFMpegVidEncClass *oclass =
241 (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
243 /* close old session */
244 if (ffmpegenc->opened) {
245 gst_ffmpeg_avcodec_close (ffmpegenc->context);
246 ffmpegenc->opened = FALSE;
247 if (avcodec_get_context_defaults3 (ffmpegenc->context,
248 oclass->in_plugin) < 0) {
249 GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
254 /* additional avcodec settings */
255 gst_ffmpeg_cfg_fill_context (G_OBJECT (ffmpegenc), ffmpegenc->context);
257 if (GST_VIDEO_INFO_IS_INTERLACED (&state->info))
258 ffmpegenc->context->flags |=
259 AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME;
261 /* and last but not least the pass; CBR, 2-pass, etc */
262 ffmpegenc->context->flags |= ffmpegenc->pass;
263 switch (ffmpegenc->pass) {
264 /* some additional action depends on type of pass */
265 case AV_CODEC_FLAG_QSCALE:
266 ffmpegenc->context->global_quality
267 = ffmpegenc->picture->quality = FF_QP2LAMBDA * ffmpegenc->quantizer;
269 case AV_CODEC_FLAG_PASS1: /* need to prepare a stats file */
270 /* we don't close when changing caps, fingers crossed */
271 if (!ffmpegenc->file)
272 ffmpegenc->file = g_fopen (ffmpegenc->filename, "w");
273 if (!ffmpegenc->file)
276 case AV_CODEC_FLAG_PASS2:
277 { /* need to read the whole stats file ! */
280 if (!g_file_get_contents (ffmpegenc->filename,
281 &ffmpegenc->context->stats_in, &size, NULL))
290 GST_DEBUG_OBJECT (ffmpegenc, "Extracting common video information");
291 /* fetch pix_fmt, fps, par, width, height... */
292 gst_ffmpeg_videoinfo_to_context (&state->info, ffmpegenc->context);
294 /* sanitize time base */
295 if (ffmpegenc->context->time_base.num <= 0
296 || ffmpegenc->context->time_base.den <= 0)
297 goto insane_timebase;
299 if ((oclass->in_plugin->id == AV_CODEC_ID_MPEG4)
300 && (ffmpegenc->context->time_base.den > 65535)) {
301 /* MPEG4 Standards do not support time_base denominator greater than
302 * (1<<16) - 1 . We therefore scale them down.
303 * Agreed, it will not be the exact framerate... but the difference
304 * shouldn't be that noticeable */
305 ffmpegenc->context->time_base.num =
306 (gint) gst_util_uint64_scale_int (ffmpegenc->context->time_base.num,
307 65535, ffmpegenc->context->time_base.den);
308 ffmpegenc->context->time_base.den = 65535;
309 GST_LOG_OBJECT (ffmpegenc, "MPEG4 : scaled down framerate to %d / %d",
310 ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num);
313 pix_fmt = ffmpegenc->context->pix_fmt;
315 /* some codecs support more than one format, first auto-choose one */
316 GST_DEBUG_OBJECT (ffmpegenc, "picking an output format ...");
317 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
319 GST_DEBUG_OBJECT (ffmpegenc, "... but no peer, using template caps");
320 /* we need to copy because get_allowed_caps returns a ref, and
321 * get_pad_template_caps doesn't */
323 gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
325 GST_DEBUG_OBJECT (ffmpegenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
326 gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
327 oclass->in_plugin->type, allowed_caps, ffmpegenc->context);
330 if (gst_ffmpeg_avcodec_open (ffmpegenc->context, oclass->in_plugin) < 0) {
331 gst_caps_unref (allowed_caps);
332 goto open_codec_fail;
335 /* is the colourspace correct? */
336 if (pix_fmt != ffmpegenc->context->pix_fmt) {
337 gst_caps_unref (allowed_caps);
341 /* we may have failed mapping caps to a pixfmt,
342 * and quite some codecs do not make up their own mind about that
343 * in any case, _NONE can never work out later on */
344 if (pix_fmt == AV_PIX_FMT_NONE) {
345 gst_caps_unref (allowed_caps);
349 /* second pass stats buffer no longer needed */
350 g_free (ffmpegenc->context->stats_in);
352 /* try to set this caps on the other side */
353 other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
354 ffmpegenc->context, TRUE);
357 gst_caps_unref (allowed_caps);
358 goto unsupported_codec;
361 icaps = gst_caps_intersect (allowed_caps, other_caps);
362 gst_caps_unref (allowed_caps);
363 gst_caps_unref (other_caps);
364 if (gst_caps_is_empty (icaps)) {
365 gst_caps_unref (icaps);
366 goto unsupported_codec;
368 icaps = gst_caps_fixate (icaps);
370 GST_DEBUG_OBJECT (ffmpegenc, "codec flags 0x%08x", ffmpegenc->context->flags);
372 /* Store input state and set output state */
373 if (ffmpegenc->input_state)
374 gst_video_codec_state_unref (ffmpegenc->input_state);
375 ffmpegenc->input_state = gst_video_codec_state_ref (state);
377 output_format = gst_video_encoder_set_output_state (encoder, icaps, state);
378 gst_video_codec_state_unref (output_format);
380 /* Store some tags */
382 GstTagList *tags = gst_tag_list_new_empty ();
385 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
386 (guint) ffmpegenc->context->bit_rate, NULL);
389 gst_ffmpeg_get_codecid_longname (ffmpegenc->context->codec_id)))
390 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_VIDEO_CODEC, codec,
393 gst_video_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE);
394 gst_tag_list_unref (tags);
398 ffmpegenc->opened = TRUE;
405 GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE,
406 (("Could not open file \"%s\" for writing."), ffmpegenc->filename),
412 GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ,
413 (("Could not get contents of file \"%s\"."), ffmpegenc->filename),
420 GST_ERROR_OBJECT (ffmpegenc, "Rejecting time base %d/%d",
421 ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num);
422 goto cleanup_stats_in;
426 GST_DEBUG ("Unsupported codec - no caps found");
427 goto cleanup_stats_in;
431 GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to open libav codec",
432 oclass->in_plugin->name);
438 GST_DEBUG_OBJECT (ffmpegenc,
439 "avenc_%s: AV wants different colourspace (%d given, %d wanted)",
440 oclass->in_plugin->name, pix_fmt, ffmpegenc->context->pix_fmt);
446 GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to determine input format",
447 oclass->in_plugin->name);
452 gst_ffmpeg_avcodec_close (ffmpegenc->context);
453 if (avcodec_get_context_defaults3 (ffmpegenc->context,
454 oclass->in_plugin) < 0)
455 GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
456 goto cleanup_stats_in;
460 g_free (ffmpegenc->context->stats_in);
467 gst_ffmpegvidenc_propose_allocation (GstVideoEncoder * encoder,
470 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
472 return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
477 gst_ffmpegvidenc_free_avpacket (gpointer pkt)
479 av_packet_unref ((AVPacket *) pkt);
480 g_slice_free (AVPacket, pkt);
486 GstVideoFrame vframe;
490 buffer_info_free (void *opaque, guint8 * data)
492 BufferInfo *info = opaque;
494 gst_video_frame_unmap (&info->vframe);
495 gst_buffer_unref (info->buffer);
496 g_slice_free (BufferInfo, info);
499 static enum AVStereo3DType
500 stereo_gst_to_av (GstVideoMultiviewMode mview_mode)
502 switch (mview_mode) {
503 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
504 return AV_STEREO3D_SIDEBYSIDE;
505 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
506 return AV_STEREO3D_TOPBOTTOM;
507 case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
508 return AV_STEREO3D_FRAMESEQUENCE;
509 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
510 return AV_STEREO3D_CHECKERBOARD;
511 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX:
512 return AV_STEREO3D_SIDEBYSIDE_QUINCUNX;
513 case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED:
514 return AV_STEREO3D_LINES;
515 case GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED:
516 return AV_STEREO3D_COLUMNS;
520 GST_WARNING ("Unsupported multiview mode - no mapping in libav");
521 return AV_STEREO3D_2D;
525 gst_ffmpegvidenc_add_cc (GstBuffer * buffer, AVFrame * picture)
527 GstVideoCaptionMeta *cc_meta;
528 gpointer iter = NULL;
531 (GstVideoCaptionMeta *) gst_buffer_iterate_meta_filtered (buffer,
532 &iter, GST_VIDEO_CAPTION_META_API_TYPE))) {
535 if (cc_meta->caption_type != GST_VIDEO_CAPTION_TYPE_CEA708_RAW)
538 sd = av_frame_new_side_data (picture, AV_FRAME_DATA_A53_CC, cc_meta->size);
539 memcpy (sd->data, cc_meta->data, cc_meta->size);
544 gst_ffmpegvidenc_send_frame (GstFFMpegVidEnc * ffmpegenc,
545 GstVideoCodecFrame * frame)
547 GstVideoInfo *info = &ffmpegenc->input_state->info;
548 BufferInfo *buffer_info;
551 GstFlowReturn ret = GST_FLOW_ERROR;
552 AVFrame *picture = NULL;
557 picture = ffmpegenc->picture;
559 gst_ffmpegvidenc_add_cc (frame->input_buffer, picture);
561 if (GST_VIDEO_INFO_IS_INTERLACED (&ffmpegenc->input_state->info)) {
562 picture->interlaced_frame = TRUE;
563 picture->top_field_first =
564 GST_BUFFER_FLAG_IS_SET (frame->input_buffer, GST_VIDEO_BUFFER_FLAG_TFF)
565 || GST_VIDEO_INFO_FIELD_ORDER (&ffmpegenc->input_state->info) ==
566 GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST;
567 picture->repeat_pict =
568 GST_BUFFER_FLAG_IS_SET (frame->input_buffer, GST_VIDEO_BUFFER_FLAG_RFF);
571 if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) != GST_VIDEO_MULTIVIEW_MODE_NONE) {
572 AVStereo3D *stereo = av_stereo3d_create_side_data (picture);
573 stereo->type = stereo_gst_to_av (GST_VIDEO_INFO_MULTIVIEW_MODE (info));
575 if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) &
576 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST) {
577 stereo->flags = AV_STEREO3D_FLAG_INVERT;
581 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame))
582 picture->pict_type = AV_PICTURE_TYPE_I;
584 buffer_info = g_slice_new0 (BufferInfo);
585 buffer_info->buffer = gst_buffer_ref (frame->input_buffer);
587 if (!gst_video_frame_map (&buffer_info->vframe, info, frame->input_buffer,
589 GST_ERROR_OBJECT (ffmpegenc, "Failed to map input buffer");
590 gst_buffer_unref (buffer_info->buffer);
591 g_slice_free (BufferInfo, buffer_info);
592 gst_video_codec_frame_unref (frame);
598 av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);
599 for (c = 0; c < AV_NUM_DATA_POINTERS; c++) {
600 if (c < GST_VIDEO_INFO_N_COMPONENTS (info)) {
601 picture->data[c] = GST_VIDEO_FRAME_PLANE_DATA (&buffer_info->vframe, c);
602 picture->linesize[c] =
603 GST_VIDEO_FRAME_COMP_STRIDE (&buffer_info->vframe, c);
605 picture->data[c] = NULL;
606 picture->linesize[c] = 0;
610 picture->format = ffmpegenc->context->pix_fmt;
611 picture->width = GST_VIDEO_FRAME_WIDTH (&buffer_info->vframe);
612 picture->height = GST_VIDEO_FRAME_HEIGHT (&buffer_info->vframe);
615 gst_ffmpeg_time_gst_to_ff (frame->pts /
616 ffmpegenc->context->ticks_per_frame, ffmpegenc->context->time_base);
619 res = avcodec_send_frame (ffmpegenc->context, picture);
622 av_frame_unref (picture);
626 else if (res == AVERROR_EOF)
634 gst_ffmpegvidenc_receive_packet (GstFFMpegVidEnc * ffmpegenc,
635 gboolean * got_packet, gboolean send)
639 GstVideoCodecFrame *frame;
641 GstFlowReturn ret = GST_FLOW_OK;
645 pkt = g_slice_new0 (AVPacket);
647 res = avcodec_receive_packet (ffmpegenc->context, pkt);
649 if (res == AVERROR (EAGAIN)) {
650 g_slice_free (AVPacket, pkt);
652 } else if (res == AVERROR_EOF) {
655 } else if (res < 0) {
656 ret = GST_FLOW_ERROR;
662 /* save stats info if there is some as well as a stats file */
663 if (ffmpegenc->file && ffmpegenc->context->stats_out)
664 if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0)
665 GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE,
666 (("Could not write to file \"%s\"."), ffmpegenc->filename),
669 /* Get oldest frame */
670 frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (ffmpegenc));
674 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data,
675 pkt->size, 0, pkt->size, pkt, gst_ffmpegvidenc_free_avpacket);
676 frame->output_buffer = outbuf;
678 if (pkt->flags & AV_PKT_FLAG_KEY)
679 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
681 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
684 ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame);
691 gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
692 GstVideoCodecFrame * frame)
694 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
698 ret = gst_ffmpegvidenc_send_frame (ffmpegenc, frame);
700 if (ret != GST_FLOW_OK)
703 gst_video_codec_frame_unref (frame);
706 ret = gst_ffmpegvidenc_receive_packet (ffmpegenc, &got_packet, TRUE);
707 if (ret != GST_FLOW_OK)
709 } while (got_packet);
714 /* We choose to be error-resilient */
717 #ifndef GST_DISABLE_GST_DEBUG
718 GstFFMpegVidEncClass *oclass =
719 (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
720 GST_ERROR_OBJECT (ffmpegenc,
721 "avenc_%s: failed to encode buffer", oclass->in_plugin->name);
722 #endif /* GST_DISABLE_GST_DEBUG */
723 /* avoid frame (and ts etc) piling up */
724 ret = gst_video_encoder_finish_frame (encoder, frame);
730 gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send)
732 GstFlowReturn ret = GST_FLOW_OK;
735 GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send);
737 /* no need to empty codec if there is none */
738 if (!ffmpegenc->opened)
741 ret = gst_ffmpegvidenc_send_frame (ffmpegenc, NULL);
743 if (ret != GST_FLOW_OK)
747 ret = gst_ffmpegvidenc_receive_packet (ffmpegenc, &got_packet, send);
748 if (ret != GST_FLOW_OK)
750 } while (got_packet);
757 gst_ffmpegvidenc_set_property (GObject * object,
758 guint prop_id, const GValue * value, GParamSpec * pspec)
760 GstFFMpegVidEnc *ffmpegenc;
762 ffmpegenc = (GstFFMpegVidEnc *) (object);
764 if (ffmpegenc->opened) {
765 GST_WARNING_OBJECT (ffmpegenc,
766 "Can't change properties once decoder is setup !");
772 ffmpegenc->quantizer = g_value_get_float (value);
775 ffmpegenc->pass = g_value_get_enum (value);
778 g_free (ffmpegenc->filename);
779 ffmpegenc->filename = g_value_dup_string (value);
782 if (!gst_ffmpeg_cfg_set_property (ffmpegenc->refcontext, value, pspec))
783 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
789 gst_ffmpegvidenc_get_property (GObject * object,
790 guint prop_id, GValue * value, GParamSpec * pspec)
792 GstFFMpegVidEnc *ffmpegenc;
794 ffmpegenc = (GstFFMpegVidEnc *) (object);
798 g_value_set_float (value, ffmpegenc->quantizer);
801 g_value_set_enum (value, ffmpegenc->pass);
804 g_value_take_string (value, g_strdup (ffmpegenc->filename));
807 if (!gst_ffmpeg_cfg_get_property (ffmpegenc->refcontext, value, pspec))
808 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
814 gst_ffmpegvidenc_flush (GstVideoEncoder * encoder)
816 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
818 if (ffmpegenc->opened)
819 avcodec_flush_buffers (ffmpegenc->context);
825 gst_ffmpegvidenc_start (GstVideoEncoder * encoder)
827 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
828 GstFFMpegVidEncClass *oclass =
829 (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
831 /* close old session */
832 gst_ffmpeg_avcodec_close (ffmpegenc->context);
833 if (avcodec_get_context_defaults3 (ffmpegenc->context, oclass->in_plugin) < 0) {
834 GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
842 gst_ffmpegvidenc_stop (GstVideoEncoder * encoder)
844 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
846 gst_ffmpegvidenc_flush_buffers (ffmpegenc, FALSE);
847 gst_ffmpeg_avcodec_close (ffmpegenc->context);
848 ffmpegenc->opened = FALSE;
850 if (ffmpegenc->input_state) {
851 gst_video_codec_state_unref (ffmpegenc->input_state);
852 ffmpegenc->input_state = NULL;
859 gst_ffmpegvidenc_finish (GstVideoEncoder * encoder)
861 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
863 return gst_ffmpegvidenc_flush_buffers (ffmpegenc, TRUE);
867 gst_ffmpegvidenc_register (GstPlugin * plugin)
869 GTypeInfo typeinfo = {
870 sizeof (GstFFMpegVidEncClass),
871 (GBaseInitFunc) gst_ffmpegvidenc_base_init,
873 (GClassInitFunc) gst_ffmpegvidenc_class_init,
876 sizeof (GstFFMpegVidEnc),
878 (GInstanceInitFunc) gst_ffmpegvidenc_init,
884 GST_LOG ("Registering encoders");
886 while ((in_plugin = (AVCodec *) av_codec_iterate (&i))) {
889 /* Skip non-AV codecs */
890 if (in_plugin->type != AVMEDIA_TYPE_VIDEO)
893 /* no quasi codecs, please */
894 if (in_plugin->id == AV_CODEC_ID_RAWVIDEO ||
895 in_plugin->id == AV_CODEC_ID_V210 ||
896 in_plugin->id == AV_CODEC_ID_V210X ||
897 in_plugin->id == AV_CODEC_ID_V308 ||
898 in_plugin->id == AV_CODEC_ID_V408 ||
899 in_plugin->id == AV_CODEC_ID_V410 ||
900 in_plugin->id == AV_CODEC_ID_R210
901 || in_plugin->id == AV_CODEC_ID_AYUV
902 || in_plugin->id == AV_CODEC_ID_Y41P
903 || in_plugin->id == AV_CODEC_ID_012V
904 || in_plugin->id == AV_CODEC_ID_YUV4
905 #if AV_VERSION_INT (LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO) >= \
906 AV_VERSION_INT (57,4,0)
907 || in_plugin->id == AV_CODEC_ID_WRAPPED_AVFRAME
909 || in_plugin->id == AV_CODEC_ID_ZLIB) {
913 /* No encoders depending on external libraries (we don't build them, but
914 * people who build against an external ffmpeg might have them.
915 * We have native gstreamer plugins for all of those libraries anyway. */
916 if (!strncmp (in_plugin->name, "lib", 3)) {
918 ("Not using external library encoder %s. Use the gstreamer-native ones instead.",
923 if (strstr (in_plugin->name, "vaapi")) {
925 ("Ignoring VAAPI encoder %s. We can't handle this outside of ffmpeg",
930 if (strstr (in_plugin->name, "nvenc")) {
932 ("Ignoring nvenc encoder %s. We can't handle this outside of ffmpeg",
937 if (g_str_has_suffix (in_plugin->name, "_qsv")) {
939 ("Ignoring qsv encoder %s. We can't handle this outside of ffmpeg",
944 if (g_str_has_suffix (in_plugin->name, "_v4l2m2m")) {
946 ("Ignoring V4L2 mem-to-mem encoder %s. We can't handle this outside of ffmpeg",
951 /* only video encoders */
952 if (!av_codec_is_encoder (in_plugin)
953 || in_plugin->type != AVMEDIA_TYPE_VIDEO)
956 /* FIXME : We should have a method to know cheaply whether we have a mapping
957 * for the given plugin or not */
959 GST_DEBUG ("Trying plugin %s [%s]", in_plugin->name, in_plugin->long_name);
961 /* no codecs for which we're GUARANTEED to have better alternatives */
962 if (!strcmp (in_plugin->name, "gif")) {
963 GST_LOG ("Ignoring encoder %s", in_plugin->name);
967 /* construct the type */
968 type_name = g_strdup_printf ("avenc_%s", in_plugin->name);
970 type = g_type_from_name (type_name);
974 /* create the glib type now */
976 g_type_register_static (GST_TYPE_VIDEO_ENCODER, type_name, &typeinfo,
978 g_type_set_qdata (type, GST_FFENC_PARAMS_QDATA, (gpointer) in_plugin);
981 static const GInterfaceInfo preset_info = {
986 g_type_add_interface_static (type, GST_TYPE_PRESET, &preset_info);
990 if (!gst_element_register (plugin, type_name, GST_RANK_SECONDARY, type)) {
998 GST_LOG ("Finished registering encoders");