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 /* calculate the DTS by taking the PTS/DTS difference from the ffmpeg side
721 * and applying it to our PTS. We don't use the ffmpeg timestamps verbatim
722 * because they're too inaccurate and in the framerate time_base
724 if (pkt->dts != AV_NOPTS_VALUE) {
725 gint64 pts_dts_diff = pkt->dts - pkt->pts;
726 if (pts_dts_diff < 0) {
727 GstClockTime gst_pts_dts_diff = gst_ffmpeg_time_ff_to_gst (-pts_dts_diff,
728 ffmpegenc->context->time_base);
730 if (gst_pts_dts_diff > frame->pts)
733 frame->dts = frame->pts - gst_pts_dts_diff;
735 frame->dts = frame->pts +
736 gst_ffmpeg_time_ff_to_gst (pts_dts_diff,
737 ffmpegenc->context->time_base);
741 ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame);
748 gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
749 GstVideoCodecFrame * frame)
751 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
755 /* endoder was drained or flushed, and ffmpeg encoder doesn't support
756 * flushing. We need to re-open encoder then */
757 if (ffmpegenc->need_reopen) {
759 GstVideoCodecState *input_state;
761 GST_DEBUG_OBJECT (ffmpegenc, "Open encoder again");
763 if (!ffmpegenc->input_state) {
764 GST_ERROR_OBJECT (ffmpegenc,
765 "Cannot re-open encoder without input state");
766 return GST_FLOW_NOT_NEGOTIATED;
769 input_state = gst_video_codec_state_ref (ffmpegenc->input_state);
770 reopen_ret = gst_ffmpegvidenc_set_format (encoder, input_state);
771 gst_video_codec_state_unref (input_state);
774 GST_ERROR_OBJECT (ffmpegenc, "Couldn't re-open encoder");
775 return GST_FLOW_NOT_NEGOTIATED;
779 ret = gst_ffmpegvidenc_send_frame (ffmpegenc, frame);
781 if (ret != GST_FLOW_OK)
784 gst_video_codec_frame_unref (frame);
787 ret = gst_ffmpegvidenc_receive_packet (ffmpegenc, &got_packet, TRUE);
788 if (ret != GST_FLOW_OK)
790 } while (got_packet);
795 /* We choose to be error-resilient */
798 #ifndef GST_DISABLE_GST_DEBUG
799 GstFFMpegVidEncClass *oclass =
800 (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
801 GST_ERROR_OBJECT (ffmpegenc,
802 "avenc_%s: failed to encode buffer", oclass->in_plugin->name);
803 #endif /* GST_DISABLE_GST_DEBUG */
804 /* avoid frame (and ts etc) piling up */
805 ret = gst_video_encoder_finish_frame (encoder, frame);
811 gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send)
813 GstFlowReturn ret = GST_FLOW_OK;
816 GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send);
818 /* no need to empty codec if there is none */
819 if (!ffmpegenc->opened)
822 ret = gst_ffmpegvidenc_send_frame (ffmpegenc, NULL);
824 if (ret != GST_FLOW_OK)
828 ret = gst_ffmpegvidenc_receive_packet (ffmpegenc, &got_packet, send);
829 if (ret != GST_FLOW_OK)
831 } while (got_packet);
832 avcodec_flush_buffers (ffmpegenc->context);
833 ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
836 /* FFMpeg will return AVERROR_EOF if it's internal was fully drained
837 * then we are translating it to GST_FLOW_EOS. However, because this behavior
838 * is fully internal stuff of this implementation and gstvideoencoder
839 * baseclass doesn't convert this GST_FLOW_EOS to GST_FLOW_OK,
840 * convert this flow returned here */
841 if (ret == GST_FLOW_EOS)
848 gst_ffmpegvidenc_set_property (GObject * object,
849 guint prop_id, const GValue * value, GParamSpec * pspec)
851 GstFFMpegVidEnc *ffmpegenc;
853 ffmpegenc = (GstFFMpegVidEnc *) (object);
855 if (ffmpegenc->opened) {
856 GST_WARNING_OBJECT (ffmpegenc,
857 "Can't change properties once decoder is setup !");
863 ffmpegenc->quantizer = g_value_get_float (value);
866 ffmpegenc->pass = g_value_get_enum (value);
869 g_free (ffmpegenc->filename);
870 ffmpegenc->filename = g_value_dup_string (value);
873 if (!gst_ffmpeg_cfg_set_property (ffmpegenc->refcontext, value, pspec))
874 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
880 gst_ffmpegvidenc_get_property (GObject * object,
881 guint prop_id, GValue * value, GParamSpec * pspec)
883 GstFFMpegVidEnc *ffmpegenc;
885 ffmpegenc = (GstFFMpegVidEnc *) (object);
889 g_value_set_float (value, ffmpegenc->quantizer);
892 g_value_set_enum (value, ffmpegenc->pass);
895 g_value_take_string (value, g_strdup (ffmpegenc->filename));
898 if (!gst_ffmpeg_cfg_get_property (ffmpegenc->refcontext, value, pspec))
899 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
905 gst_ffmpegvidenc_flush (GstVideoEncoder * encoder)
907 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
909 if (ffmpegenc->opened) {
910 avcodec_flush_buffers (ffmpegenc->context);
911 ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
918 gst_ffmpegvidenc_start (GstVideoEncoder * encoder)
920 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
921 GstFFMpegVidEncClass *oclass =
922 (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
924 ffmpegenc->opened = FALSE;
925 ffmpegenc->need_reopen = FALSE;
927 /* close old session */
928 avcodec_free_context (&ffmpegenc->context);
929 ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin);
930 if (ffmpegenc->context == NULL) {
931 GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
935 gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000);
941 gst_ffmpegvidenc_stop (GstVideoEncoder * encoder)
943 GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
945 gst_ffmpegvidenc_flush_buffers (ffmpegenc, FALSE);
946 gst_ffmpeg_avcodec_close (ffmpegenc->context);
947 ffmpegenc->opened = FALSE;
948 ffmpegenc->need_reopen = FALSE;
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 while ((in_plugin = (AVCodec *) av_codec_iterate (&i))) {
989 /* Skip non-AV codecs */
990 if (in_plugin->type != AVMEDIA_TYPE_VIDEO)
993 /* no quasi codecs, please */
994 if (in_plugin->id == AV_CODEC_ID_RAWVIDEO ||
995 in_plugin->id == AV_CODEC_ID_V210 ||
996 in_plugin->id == AV_CODEC_ID_V210X ||
997 in_plugin->id == AV_CODEC_ID_V308 ||
998 in_plugin->id == AV_CODEC_ID_V408 ||
999 in_plugin->id == AV_CODEC_ID_V410 ||
1000 in_plugin->id == AV_CODEC_ID_R210
1001 || in_plugin->id == AV_CODEC_ID_AYUV
1002 || in_plugin->id == AV_CODEC_ID_Y41P
1003 || in_plugin->id == AV_CODEC_ID_012V
1004 || in_plugin->id == AV_CODEC_ID_YUV4
1005 #if AV_VERSION_INT (LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO) >= \
1006 AV_VERSION_INT (57,4,0)
1007 || in_plugin->id == AV_CODEC_ID_WRAPPED_AVFRAME
1009 || in_plugin->id == AV_CODEC_ID_ZLIB) {
1013 /* No encoders depending on external libraries (we don't build them, but
1014 * people who build against an external ffmpeg might have them.
1015 * We have native gstreamer plugins for all of those libraries anyway. */
1016 if (!strncmp (in_plugin->name, "lib", 3)) {
1018 ("Not using external library encoder %s. Use the gstreamer-native ones instead.",
1023 /* Skip hardware or hybrid (hardware with software fallback) */
1024 if ((in_plugin->capabilities & AV_CODEC_CAP_HARDWARE) ==
1025 AV_CODEC_CAP_HARDWARE) {
1027 ("Ignoring hardware encoder %s. We can't handle this outside of ffmpeg",
1032 if ((in_plugin->capabilities & AV_CODEC_CAP_HYBRID) == AV_CODEC_CAP_HYBRID) {
1034 ("Ignoring hybrid encoder %s. We can't handle this outside of ffmpeg",
1039 /* only video encoders */
1040 if (!av_codec_is_encoder (in_plugin)
1041 || in_plugin->type != AVMEDIA_TYPE_VIDEO)
1044 /* FIXME : We should have a method to know cheaply whether we have a mapping
1045 * for the given plugin or not */
1047 GST_DEBUG ("Trying plugin %s [%s]", in_plugin->name, in_plugin->long_name);
1049 /* no codecs for which we're GUARANTEED to have better alternatives */
1050 if (!strcmp (in_plugin->name, "gif")) {
1051 GST_LOG ("Ignoring encoder %s", in_plugin->name);
1055 /* construct the type */
1056 type_name = g_strdup_printf ("avenc_%s", in_plugin->name);
1058 type = g_type_from_name (type_name);
1062 /* create the glib type now */
1064 g_type_register_static (GST_TYPE_VIDEO_ENCODER, type_name, &typeinfo,
1066 g_type_set_qdata (type, GST_FFENC_PARAMS_QDATA, (gpointer) in_plugin);
1069 static const GInterfaceInfo preset_info = {
1074 g_type_add_interface_static (type, GST_TYPE_PRESET, &preset_info);
1078 if (!gst_element_register (plugin, type_name, GST_RANK_SECONDARY, type)) {
1086 GST_LOG ("Finished registering encoders");