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;
200 gst_type_mark_as_plugin_api (GST_TYPE_FFMPEG_PASS, 0);
204 gst_ffmpegvidenc_init (GstFFMpegVidEnc * ffmpegenc)
206 GstFFMpegVidEncClass *klass =
207 (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
209 GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (ffmpegenc));
211 ffmpegenc->context = avcodec_alloc_context3 (klass->in_plugin);
212 ffmpegenc->refcontext = avcodec_alloc_context3 (klass->in_plugin);
213 ffmpegenc->picture = av_frame_alloc ();
214 ffmpegenc->opened = FALSE;
215 ffmpegenc->file = NULL;
219 gst_ffmpegvidenc_finalize (GObject * object)
221 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) object;
223 /* clean up remaining allocated data */
224 av_frame_free (&ffmpegenc->picture);
225 gst_ffmpeg_avcodec_close (ffmpegenc->context);
226 gst_ffmpeg_avcodec_close (ffmpegenc->refcontext);
227 av_freep (&ffmpegenc->context);
228 av_freep (&ffmpegenc->refcontext);
229 g_free (ffmpegenc->filename);
231 G_OBJECT_CLASS (parent_class)->finalize (object);
235 gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
236 GstVideoCodecState * state)
239 GstCaps *allowed_caps;
241 GstVideoCodecState *output_format;
242 enum AVPixelFormat pix_fmt;
243 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
244 GstFFMpegVidEncClass *oclass =
245 (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
247 ffmpegenc->need_reopen = FALSE;
249 /* close old session */
250 if (ffmpegenc->opened) {
251 avcodec_free_context (&ffmpegenc->context);
252 ffmpegenc->opened = FALSE;
253 ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin);
254 if (ffmpegenc->context == NULL) {
255 GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
260 /* additional avcodec settings */
261 gst_ffmpeg_cfg_fill_context (G_OBJECT (ffmpegenc), ffmpegenc->context);
263 if (GST_VIDEO_INFO_IS_INTERLACED (&state->info))
264 ffmpegenc->context->flags |=
265 AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME;
267 /* and last but not least the pass; CBR, 2-pass, etc */
268 ffmpegenc->context->flags |= ffmpegenc->pass;
269 switch (ffmpegenc->pass) {
270 /* some additional action depends on type of pass */
271 case AV_CODEC_FLAG_QSCALE:
272 ffmpegenc->context->global_quality
273 = ffmpegenc->picture->quality = FF_QP2LAMBDA * ffmpegenc->quantizer;
275 case AV_CODEC_FLAG_PASS1: /* need to prepare a stats file */
276 /* we don't close when changing caps, fingers crossed */
277 if (!ffmpegenc->file)
278 ffmpegenc->file = g_fopen (ffmpegenc->filename, "w");
279 if (!ffmpegenc->file)
282 case AV_CODEC_FLAG_PASS2:
283 { /* need to read the whole stats file ! */
286 if (!g_file_get_contents (ffmpegenc->filename,
287 &ffmpegenc->context->stats_in, &size, NULL))
296 GST_DEBUG_OBJECT (ffmpegenc, "Extracting common video information");
297 /* fetch pix_fmt, fps, par, width, height... */
298 gst_ffmpeg_videoinfo_to_context (&state->info, ffmpegenc->context);
300 /* sanitize time base */
301 if (ffmpegenc->context->time_base.num <= 0
302 || ffmpegenc->context->time_base.den <= 0)
303 goto insane_timebase;
305 if ((oclass->in_plugin->id == AV_CODEC_ID_MPEG4)
306 && (ffmpegenc->context->time_base.den > 65535)) {
307 /* MPEG4 Standards do not support time_base denominator greater than
308 * (1<<16) - 1 . We therefore scale them down.
309 * Agreed, it will not be the exact framerate... but the difference
310 * shouldn't be that noticeable */
311 ffmpegenc->context->time_base.num =
312 (gint) gst_util_uint64_scale_int (ffmpegenc->context->time_base.num,
313 65535, ffmpegenc->context->time_base.den);
314 ffmpegenc->context->time_base.den = 65535;
315 GST_LOG_OBJECT (ffmpegenc, "MPEG4 : scaled down framerate to %d / %d",
316 ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num);
319 pix_fmt = ffmpegenc->context->pix_fmt;
321 /* some codecs support more than one format, first auto-choose one */
322 GST_DEBUG_OBJECT (ffmpegenc, "picking an output format ...");
323 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
325 GST_DEBUG_OBJECT (ffmpegenc, "... but no peer, using template caps");
326 /* we need to copy because get_allowed_caps returns a ref, and
327 * get_pad_template_caps doesn't */
329 gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
331 GST_DEBUG_OBJECT (ffmpegenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
332 gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
333 oclass->in_plugin->type, allowed_caps, ffmpegenc->context);
336 if (gst_ffmpeg_avcodec_open (ffmpegenc->context, oclass->in_plugin) < 0) {
337 gst_caps_unref (allowed_caps);
338 goto open_codec_fail;
341 /* is the colourspace correct? */
342 if (pix_fmt != ffmpegenc->context->pix_fmt) {
343 gst_caps_unref (allowed_caps);
347 /* we may have failed mapping caps to a pixfmt,
348 * and quite some codecs do not make up their own mind about that
349 * in any case, _NONE can never work out later on */
350 if (pix_fmt == AV_PIX_FMT_NONE) {
351 gst_caps_unref (allowed_caps);
355 /* second pass stats buffer no longer needed */
356 g_free (ffmpegenc->context->stats_in);
358 /* try to set this caps on the other side */
359 other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
360 ffmpegenc->context, TRUE);
363 gst_caps_unref (allowed_caps);
364 goto unsupported_codec;
367 icaps = gst_caps_intersect (allowed_caps, other_caps);
368 gst_caps_unref (allowed_caps);
369 gst_caps_unref (other_caps);
370 if (gst_caps_is_empty (icaps)) {
371 gst_caps_unref (icaps);
372 goto unsupported_codec;
374 icaps = gst_caps_fixate (icaps);
376 GST_DEBUG_OBJECT (ffmpegenc, "codec flags 0x%08x", ffmpegenc->context->flags);
378 /* Store input state and set output state */
379 if (ffmpegenc->input_state)
380 gst_video_codec_state_unref (ffmpegenc->input_state);
381 ffmpegenc->input_state = gst_video_codec_state_ref (state);
383 output_format = gst_video_encoder_set_output_state (encoder, icaps, state);
384 gst_video_codec_state_unref (output_format);
386 /* Store some tags */
388 GstTagList *tags = gst_tag_list_new_empty ();
391 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
392 (guint) ffmpegenc->context->bit_rate, NULL);
395 gst_ffmpeg_get_codecid_longname (ffmpegenc->context->codec_id)))
396 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_VIDEO_CODEC, codec,
399 gst_video_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE);
400 gst_tag_list_unref (tags);
404 ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
405 ffmpegenc->opened = TRUE;
412 GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE,
413 (("Could not open file \"%s\" for writing."), ffmpegenc->filename),
419 GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ,
420 (("Could not get contents of file \"%s\"."), ffmpegenc->filename),
427 GST_ERROR_OBJECT (ffmpegenc, "Rejecting time base %d/%d",
428 ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num);
429 goto cleanup_stats_in;
433 GST_DEBUG ("Unsupported codec - no caps found");
434 goto cleanup_stats_in;
438 GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to open libav codec",
439 oclass->in_plugin->name);
445 GST_DEBUG_OBJECT (ffmpegenc,
446 "avenc_%s: AV wants different colourspace (%d given, %d wanted)",
447 oclass->in_plugin->name, pix_fmt, ffmpegenc->context->pix_fmt);
453 GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to determine input format",
454 oclass->in_plugin->name);
459 avcodec_free_context (&ffmpegenc->context);
460 ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin);
461 if (ffmpegenc->context == NULL)
462 GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
463 goto cleanup_stats_in;
467 g_free (ffmpegenc->context->stats_in);
474 gst_ffmpegvidenc_propose_allocation (GstVideoEncoder * encoder,
477 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
479 return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
484 gst_ffmpegvidenc_free_avpacket (gpointer pkt)
486 av_packet_unref ((AVPacket *) pkt);
487 g_slice_free (AVPacket, pkt);
493 GstVideoFrame vframe;
497 buffer_info_free (void *opaque, guint8 * data)
499 BufferInfo *info = opaque;
501 gst_video_frame_unmap (&info->vframe);
502 gst_buffer_unref (info->buffer);
503 g_slice_free (BufferInfo, info);
506 static enum AVStereo3DType
507 stereo_gst_to_av (GstVideoMultiviewMode mview_mode)
509 switch (mview_mode) {
510 case GST_VIDEO_MULTIVIEW_MODE_MONO:
511 /* Video is not stereoscopic (and metadata has to be there). */
512 return AV_STEREO3D_2D;
513 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
514 return AV_STEREO3D_SIDEBYSIDE;
515 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
516 return AV_STEREO3D_TOPBOTTOM;
517 case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
518 return AV_STEREO3D_FRAMESEQUENCE;
519 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
520 return AV_STEREO3D_CHECKERBOARD;
521 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX:
522 return AV_STEREO3D_SIDEBYSIDE_QUINCUNX;
523 case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED:
524 return AV_STEREO3D_LINES;
525 case GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED:
526 return AV_STEREO3D_COLUMNS;
530 GST_WARNING ("Unsupported multiview mode - no mapping in libav");
531 return AV_STEREO3D_2D;
535 gst_ffmpegvidenc_add_cc (GstBuffer * buffer, AVFrame * picture)
537 GstVideoCaptionMeta *cc_meta;
538 gpointer iter = NULL;
541 (GstVideoCaptionMeta *) gst_buffer_iterate_meta_filtered (buffer,
542 &iter, GST_VIDEO_CAPTION_META_API_TYPE))) {
545 if (cc_meta->caption_type != GST_VIDEO_CAPTION_TYPE_CEA708_RAW)
548 sd = av_frame_new_side_data (picture, AV_FRAME_DATA_A53_CC, cc_meta->size);
549 memcpy (sd->data, cc_meta->data, cc_meta->size);
554 gst_ffmpegvidenc_send_frame (GstFFMpegVidEnc * ffmpegenc,
555 GstVideoCodecFrame * frame)
557 GstVideoInfo *info = &ffmpegenc->input_state->info;
558 BufferInfo *buffer_info;
561 GstFlowReturn ret = GST_FLOW_ERROR;
562 AVFrame *picture = NULL;
567 picture = ffmpegenc->picture;
569 gst_ffmpegvidenc_add_cc (frame->input_buffer, picture);
571 if (GST_VIDEO_INFO_IS_INTERLACED (&ffmpegenc->input_state->info)) {
572 picture->interlaced_frame = TRUE;
573 picture->top_field_first =
574 GST_BUFFER_FLAG_IS_SET (frame->input_buffer, GST_VIDEO_BUFFER_FLAG_TFF)
575 || GST_VIDEO_INFO_FIELD_ORDER (&ffmpegenc->input_state->info) ==
576 GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST;
577 picture->repeat_pict =
578 GST_BUFFER_FLAG_IS_SET (frame->input_buffer, GST_VIDEO_BUFFER_FLAG_RFF);
581 if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) != GST_VIDEO_MULTIVIEW_MODE_NONE) {
582 AVStereo3D *stereo = av_stereo3d_create_side_data (picture);
583 stereo->type = stereo_gst_to_av (GST_VIDEO_INFO_MULTIVIEW_MODE (info));
585 if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) &
586 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST) {
587 stereo->flags = AV_STEREO3D_FLAG_INVERT;
591 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame))
592 picture->pict_type = AV_PICTURE_TYPE_I;
594 buffer_info = g_slice_new0 (BufferInfo);
595 buffer_info->buffer = gst_buffer_ref (frame->input_buffer);
597 if (!gst_video_frame_map (&buffer_info->vframe, info, frame->input_buffer,
599 GST_ERROR_OBJECT (ffmpegenc, "Failed to map input buffer");
600 gst_buffer_unref (buffer_info->buffer);
601 g_slice_free (BufferInfo, buffer_info);
602 gst_video_codec_frame_unref (frame);
608 av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);
609 for (c = 0; c < AV_NUM_DATA_POINTERS; c++) {
610 if (c < GST_VIDEO_INFO_N_COMPONENTS (info)) {
611 picture->data[c] = GST_VIDEO_FRAME_PLANE_DATA (&buffer_info->vframe, c);
612 picture->linesize[c] =
613 GST_VIDEO_FRAME_COMP_STRIDE (&buffer_info->vframe, c);
615 picture->data[c] = NULL;
616 picture->linesize[c] = 0;
620 picture->format = ffmpegenc->context->pix_fmt;
621 picture->width = GST_VIDEO_FRAME_WIDTH (&buffer_info->vframe);
622 picture->height = GST_VIDEO_FRAME_HEIGHT (&buffer_info->vframe);
624 if (ffmpegenc->pts_offset == GST_CLOCK_TIME_NONE) {
625 ffmpegenc->pts_offset = frame->pts;
628 if (frame->pts == GST_CLOCK_TIME_NONE) {
629 picture->pts = AV_NOPTS_VALUE;
630 } else if (frame->pts < ffmpegenc->pts_offset) {
631 GST_ERROR_OBJECT (ffmpegenc, "PTS is going backwards");
632 picture->pts = AV_NOPTS_VALUE;
635 gst_ffmpeg_time_gst_to_ff ((frame->pts - ffmpegenc->pts_offset) /
636 ffmpegenc->context->ticks_per_frame, ffmpegenc->context->time_base);
641 GstFFMpegVidEncClass *oclass =
642 (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
644 /* If AV_CODEC_CAP_ENCODER_FLUSH wasn't set, we need to re-open
646 if (!(oclass->in_plugin->capabilities & AV_CODEC_CAP_ENCODER_FLUSH)) {
647 GST_DEBUG_OBJECT (ffmpegenc, "Encoder needs reopen later");
649 /* we will reopen later handle_frame() */
650 ffmpegenc->need_reopen = TRUE;
654 res = avcodec_send_frame (ffmpegenc->context, picture);
657 av_frame_unref (picture);
661 else if (res == AVERROR_EOF)
669 gst_ffmpegvidenc_receive_packet (GstFFMpegVidEnc * ffmpegenc,
670 gboolean * got_packet, gboolean send)
674 GstVideoCodecFrame *frame;
676 GstFlowReturn ret = GST_FLOW_OK;
680 pkt = g_slice_new0 (AVPacket);
682 res = avcodec_receive_packet (ffmpegenc->context, pkt);
684 if (res == AVERROR (EAGAIN)) {
685 g_slice_free (AVPacket, pkt);
687 } else if (res == AVERROR_EOF) {
688 g_slice_free (AVPacket, pkt);
691 } else if (res < 0) {
692 ret = GST_FLOW_ERROR;
698 /* save stats info if there is some as well as a stats file */
699 if (ffmpegenc->file && ffmpegenc->context->stats_out)
700 if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0)
701 GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE,
702 (("Could not write to file \"%s\"."), ffmpegenc->filename),
705 /* Get oldest frame */
706 frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (ffmpegenc));
710 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data,
711 pkt->size, 0, pkt->size, pkt, gst_ffmpegvidenc_free_avpacket);
712 frame->output_buffer = outbuf;
714 if (pkt->flags & AV_PKT_FLAG_KEY)
715 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
717 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
720 if (pkt->dts != AV_NOPTS_VALUE) {
722 gst_ffmpeg_time_ff_to_gst (pkt->dts + ffmpegenc->pts_offset,
723 ffmpegenc->context->time_base);
725 /* This will lose some precision compared to setting the PTS from the input
726 * buffer directly, but that way we're sure PTS and DTS are consistent, in
727 * particular DTS should always be <= PTS
729 if (pkt->pts != AV_NOPTS_VALUE) {
731 gst_ffmpeg_time_ff_to_gst (pkt->pts + ffmpegenc->pts_offset,
732 ffmpegenc->context->time_base);
735 ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame);
742 gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
743 GstVideoCodecFrame * frame)
745 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
749 /* endoder was drained or flushed, and ffmpeg encoder doesn't support
750 * flushing. We need to re-open encoder then */
751 if (ffmpegenc->need_reopen) {
753 GstVideoCodecState *input_state;
755 GST_DEBUG_OBJECT (ffmpegenc, "Open encoder again");
757 if (!ffmpegenc->input_state) {
758 GST_ERROR_OBJECT (ffmpegenc,
759 "Cannot re-open encoder without input state");
760 return GST_FLOW_NOT_NEGOTIATED;
763 input_state = gst_video_codec_state_ref (ffmpegenc->input_state);
764 reopen_ret = gst_ffmpegvidenc_set_format (encoder, input_state);
765 gst_video_codec_state_unref (input_state);
768 GST_ERROR_OBJECT (ffmpegenc, "Couldn't re-open encoder");
769 return GST_FLOW_NOT_NEGOTIATED;
773 ret = gst_ffmpegvidenc_send_frame (ffmpegenc, frame);
775 if (ret != GST_FLOW_OK)
778 gst_video_codec_frame_unref (frame);
781 ret = gst_ffmpegvidenc_receive_packet (ffmpegenc, &got_packet, TRUE);
782 if (ret != GST_FLOW_OK)
784 } while (got_packet);
789 /* We choose to be error-resilient */
792 #ifndef GST_DISABLE_GST_DEBUG
793 GstFFMpegVidEncClass *oclass =
794 (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
795 GST_ERROR_OBJECT (ffmpegenc,
796 "avenc_%s: failed to encode buffer", oclass->in_plugin->name);
797 #endif /* GST_DISABLE_GST_DEBUG */
798 /* avoid frame (and ts etc) piling up */
799 ret = gst_video_encoder_finish_frame (encoder, frame);
805 gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send)
807 GstFlowReturn ret = GST_FLOW_OK;
810 GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send);
812 /* no need to empty codec if there is none */
813 if (!ffmpegenc->opened)
816 ret = gst_ffmpegvidenc_send_frame (ffmpegenc, NULL);
818 if (ret != GST_FLOW_OK)
822 ret = gst_ffmpegvidenc_receive_packet (ffmpegenc, &got_packet, send);
823 if (ret != GST_FLOW_OK)
825 } while (got_packet);
826 avcodec_flush_buffers (ffmpegenc->context);
827 ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
830 /* FFMpeg will return AVERROR_EOF if it's internal was fully drained
831 * then we are translating it to GST_FLOW_EOS. However, because this behavior
832 * is fully internal stuff of this implementation and gstvideoencoder
833 * baseclass doesn't convert this GST_FLOW_EOS to GST_FLOW_OK,
834 * convert this flow returned here */
835 if (ret == GST_FLOW_EOS)
842 gst_ffmpegvidenc_set_property (GObject * object,
843 guint prop_id, const GValue * value, GParamSpec * pspec)
845 GstFFMpegVidEnc *ffmpegenc;
847 ffmpegenc = (GstFFMpegVidEnc *) (object);
849 if (ffmpegenc->opened) {
850 GST_WARNING_OBJECT (ffmpegenc,
851 "Can't change properties once decoder is setup !");
857 ffmpegenc->quantizer = g_value_get_float (value);
860 ffmpegenc->pass = g_value_get_enum (value);
863 g_free (ffmpegenc->filename);
864 ffmpegenc->filename = g_value_dup_string (value);
867 if (!gst_ffmpeg_cfg_set_property (ffmpegenc->refcontext, value, pspec))
868 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
874 gst_ffmpegvidenc_get_property (GObject * object,
875 guint prop_id, GValue * value, GParamSpec * pspec)
877 GstFFMpegVidEnc *ffmpegenc;
879 ffmpegenc = (GstFFMpegVidEnc *) (object);
883 g_value_set_float (value, ffmpegenc->quantizer);
886 g_value_set_enum (value, ffmpegenc->pass);
889 g_value_take_string (value, g_strdup (ffmpegenc->filename));
892 if (!gst_ffmpeg_cfg_get_property (ffmpegenc->refcontext, value, pspec))
893 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
899 gst_ffmpegvidenc_flush (GstVideoEncoder * encoder)
901 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
903 if (ffmpegenc->opened) {
904 avcodec_flush_buffers (ffmpegenc->context);
905 ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
912 gst_ffmpegvidenc_start (GstVideoEncoder * encoder)
914 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
915 GstFFMpegVidEncClass *oclass =
916 (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
918 ffmpegenc->opened = FALSE;
919 ffmpegenc->need_reopen = FALSE;
921 /* close old session */
922 avcodec_free_context (&ffmpegenc->context);
923 ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin);
924 if (ffmpegenc->context == NULL) {
925 GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
929 gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000);
935 gst_ffmpegvidenc_stop (GstVideoEncoder * encoder)
937 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
939 gst_ffmpegvidenc_flush_buffers (ffmpegenc, FALSE);
940 gst_ffmpeg_avcodec_close (ffmpegenc->context);
941 ffmpegenc->opened = FALSE;
942 ffmpegenc->need_reopen = FALSE;
944 if (ffmpegenc->input_state) {
945 gst_video_codec_state_unref (ffmpegenc->input_state);
946 ffmpegenc->input_state = NULL;
953 gst_ffmpegvidenc_finish (GstVideoEncoder * encoder)
955 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
957 return gst_ffmpegvidenc_flush_buffers (ffmpegenc, TRUE);
961 gst_ffmpegvidenc_register (GstPlugin * plugin)
963 GTypeInfo typeinfo = {
964 sizeof (GstFFMpegVidEncClass),
965 (GBaseInitFunc) gst_ffmpegvidenc_base_init,
967 (GClassInitFunc) gst_ffmpegvidenc_class_init,
970 sizeof (GstFFMpegVidEnc),
972 (GInstanceInitFunc) gst_ffmpegvidenc_init,
978 GST_LOG ("Registering encoders");
980 while ((in_plugin = (AVCodec *) av_codec_iterate (&i))) {
983 /* Skip non-AV codecs */
984 if (in_plugin->type != AVMEDIA_TYPE_VIDEO)
987 /* no quasi codecs, please */
988 if (in_plugin->id == AV_CODEC_ID_RAWVIDEO ||
989 in_plugin->id == AV_CODEC_ID_V210 ||
990 in_plugin->id == AV_CODEC_ID_V210X ||
991 in_plugin->id == AV_CODEC_ID_V308 ||
992 in_plugin->id == AV_CODEC_ID_V408 ||
993 in_plugin->id == AV_CODEC_ID_V410 ||
994 in_plugin->id == AV_CODEC_ID_R210
995 || in_plugin->id == AV_CODEC_ID_AYUV
996 || in_plugin->id == AV_CODEC_ID_Y41P
997 || in_plugin->id == AV_CODEC_ID_012V
998 || in_plugin->id == AV_CODEC_ID_YUV4
999 #if AV_VERSION_INT (LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO) >= \
1000 AV_VERSION_INT (57,4,0)
1001 || in_plugin->id == AV_CODEC_ID_WRAPPED_AVFRAME
1003 || in_plugin->id == AV_CODEC_ID_ZLIB) {
1007 /* No encoders depending on external libraries (we don't build them, but
1008 * people who build against an external ffmpeg might have them.
1009 * We have native gstreamer plugins for all of those libraries anyway. */
1010 if (!strncmp (in_plugin->name, "lib", 3)) {
1012 ("Not using external library encoder %s. Use the gstreamer-native ones instead.",
1017 /* Skip hardware or hybrid (hardware with software fallback) */
1018 if ((in_plugin->capabilities & AV_CODEC_CAP_HARDWARE) ==
1019 AV_CODEC_CAP_HARDWARE) {
1021 ("Ignoring hardware encoder %s. We can't handle this outside of ffmpeg",
1026 if ((in_plugin->capabilities & AV_CODEC_CAP_HYBRID) == AV_CODEC_CAP_HYBRID) {
1028 ("Ignoring hybrid encoder %s. We can't handle this outside of ffmpeg",
1033 /* only video encoders */
1034 if (!av_codec_is_encoder (in_plugin)
1035 || in_plugin->type != AVMEDIA_TYPE_VIDEO)
1038 /* FIXME : We should have a method to know cheaply whether we have a mapping
1039 * for the given plugin or not */
1041 GST_DEBUG ("Trying plugin %s [%s]", in_plugin->name, in_plugin->long_name);
1043 /* no codecs for which we're GUARANTEED to have better alternatives */
1044 if (!strcmp (in_plugin->name, "gif")) {
1045 GST_LOG ("Ignoring encoder %s", in_plugin->name);
1049 /* construct the type */
1050 type_name = g_strdup_printf ("avenc_%s", in_plugin->name);
1052 type = g_type_from_name (type_name);
1056 /* create the glib type now */
1058 g_type_register_static (GST_TYPE_VIDEO_ENCODER, type_name, &typeinfo,
1060 g_type_set_qdata (type, GST_FFENC_PARAMS_QDATA, (gpointer) in_plugin);
1063 static const GInterfaceInfo preset_info = {
1068 g_type_add_interface_static (type, GST_TYPE_PRESET, &preset_info);
1072 if (!gst_element_register (plugin, type_name, GST_RANK_SECONDARY, type)) {
1080 GST_LOG ("Finished registering encoders");