7b1607c2f60214c929c515c69b003de0e30e9010
[platform/upstream/gstreamer.git] / ext / libav / gstavvidenc.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <assert.h>
25 #include <string.h>
26 /* for stats file handling */
27 #include <stdio.h>
28 #include <glib/gstdio.h>
29 #include <errno.h>
30
31 #include <libavcodec/avcodec.h>
32 #include <libavutil/stereo3d.h>
33
34 #include "gstav.h"
35 #include "gstavcodecmap.h"
36 #include "gstavutils.h"
37 #include "gstavvidenc.h"
38 #include "gstavcfg.h"
39
40 #define DEFAULT_VIDEO_BITRATE 300000    /* in bps */
41 #define DEFAULT_VIDEO_GOP_SIZE 15
42
43 #define DEFAULT_WIDTH 352
44 #define DEFAULT_HEIGHT 288
45
46
47 #define VIDEO_BUFFER_SIZE (1024*1024)
48
49 enum
50 {
51   /* FILL ME */
52   LAST_SIGNAL
53 };
54
55 enum
56 {
57   PROP_0,
58   PROP_BIT_RATE,
59   PROP_GOP_SIZE,
60   PROP_ME_METHOD,
61   PROP_BUFSIZE,
62   PROP_RTP_PAYLOAD_SIZE,
63   PROP_MAX_THREADS,
64   PROP_COMPLIANCE,
65   PROP_CFG_BASE,
66 };
67
68 #define GST_TYPE_ME_METHOD (gst_ffmpegvidenc_me_method_get_type())
69 static GType
70 gst_ffmpegvidenc_me_method_get_type (void)
71 {
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"},
80     {0, NULL, NULL},
81   };
82   if (!ffmpegenc_me_method_type) {
83     ffmpegenc_me_method_type =
84         g_enum_register_static ("GstLibAVVidEncMeMethod", ffmpegenc_me_methods);
85   }
86   return ffmpegenc_me_method_type;
87 }
88
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);
94
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,
101     GstQuery * query);
102 static gboolean gst_ffmpegvidenc_flush (GstVideoEncoder * encoder);
103
104 static GstFlowReturn gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
105     GstVideoCodecFrame * frame);
106
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);
111
112 #define GST_FFENC_PARAMS_QDATA g_quark_from_static_string("avenc-params")
113
114 static GstElementClass *parent_class = NULL;
115
116 /*static guint gst_ffmpegvidenc_signals[LAST_SIGNAL] = { 0 }; */
117
118 static void
119 gst_ffmpegvidenc_base_init (GstFFMpegVidEncClass * klass)
120 {
121   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
122   AVCodec *in_plugin;
123   GstPadTemplate *srctempl = NULL, *sinktempl = NULL;
124   GstCaps *srccaps = NULL, *sinkcaps = NULL;
125   gchar *longname, *description;
126   const gchar *classification;
127
128   in_plugin =
129       (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
130       GST_FFENC_PARAMS_QDATA);
131   g_assert (in_plugin != NULL);
132
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);
136   classification =
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>");
143   g_free (longname);
144   g_free (description);
145
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");
149   }
150
151   sinkcaps = gst_ffmpeg_codectype_to_video_caps (NULL,
152       in_plugin->id, TRUE, in_plugin);
153   if (!sinkcaps) {
154     GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name);
155     sinkcaps = gst_caps_new_empty_simple ("unknown/unknown");
156   }
157
158   /* pad templates */
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);
162
163   gst_element_class_add_pad_template (element_class, srctempl);
164   gst_element_class_add_pad_template (element_class, sinktempl);
165
166   gst_caps_unref (sinkcaps);
167   gst_caps_unref (srccaps);
168
169   klass->in_plugin = in_plugin;
170   klass->srctempl = srctempl;
171   klass->sinktempl = sinktempl;
172
173   return;
174 }
175
176 static void
177 gst_ffmpegvidenc_class_init (GstFFMpegVidEncClass * klass)
178 {
179   GObjectClass *gobject_class;
180   GstVideoEncoderClass *venc_class;
181   int caps;
182
183   gobject_class = (GObjectClass *) klass;
184   venc_class = (GstVideoEncoderClass *) klass;
185
186   parent_class = g_type_class_peek_parent (klass);
187
188   gobject_class->set_property = gst_ffmpegvidenc_set_property;
189   gobject_class->get_property = gst_ffmpegvidenc_get_property;
190
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));
205
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));
214
215   caps = klass->in_plugin->capabilities;
216   if (caps & (CODEC_CAP_FRAME_THREADS | 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));
221   }
222
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));
228
229   /* register additional properties, possibly dependent on the exact CODEC */
230   gst_ffmpeg_cfg_install_property (klass, PROP_CFG_BASE);
231
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;
239
240   gobject_class->finalize = gst_ffmpegvidenc_finalize;
241 }
242
243 static void
244 gst_ffmpegvidenc_init (GstFFMpegVidEnc * ffmpegenc)
245 {
246   GstFFMpegVidEncClass *klass =
247       (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
248
249   GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (ffmpegenc));
250
251   /* ffmpeg objects */
252   ffmpegenc->context = avcodec_alloc_context3 (klass->in_plugin);
253   ffmpegenc->picture = av_frame_alloc ();
254   ffmpegenc->opened = FALSE;
255
256   ffmpegenc->file = NULL;
257
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;
265
266   ffmpegenc->lmin = 2;
267   ffmpegenc->lmax = 31;
268   ffmpegenc->max_key_interval = 0;
269
270   gst_ffmpeg_cfg_set_defaults (ffmpegenc);
271 }
272
273 static void
274 gst_ffmpegvidenc_finalize (GObject * object)
275 {
276   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) object;
277
278   gst_ffmpeg_cfg_finalize (ffmpegenc);
279
280   /* clean up remaining allocated data */
281   av_frame_free (&ffmpegenc->picture);
282   gst_ffmpeg_avcodec_close (ffmpegenc->context);
283   av_free (ffmpegenc->context);
284
285   g_free (ffmpegenc->filename);
286
287   G_OBJECT_CLASS (parent_class)->finalize (object);
288 }
289
290 static gboolean
291 gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
292     GstVideoCodecState * state)
293 {
294   GstCaps *other_caps;
295   GstCaps *allowed_caps;
296   GstCaps *icaps;
297   GstVideoCodecState *output_format;
298   enum AVPixelFormat pix_fmt;
299   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
300   GstFFMpegVidEncClass *oclass =
301       (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
302
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");
310       return FALSE;
311     }
312   }
313
314   /* if we set it in _getcaps we should set it also in _link */
315   ffmpegenc->context->strict_std_compliance = ffmpegenc->compliance;
316
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);
324
325   if (ffmpegenc->max_threads == 0) {
326     if (!(oclass->in_plugin->capabilities & CODEC_CAP_AUTO_THREADS))
327       ffmpegenc->context->thread_count = gst_ffmpeg_auto_max_threads ();
328     else
329       ffmpegenc->context->thread_count = 0;
330   } else
331     ffmpegenc->context->thread_count = ffmpegenc->max_threads;
332
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;
336   }
337
338   /* additional avcodec settings */
339   /* first fill in the majority by copying over */
340   gst_ffmpeg_cfg_fill_context (ffmpegenc, ffmpegenc->context);
341
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);
345
346   if (ffmpegenc->interlaced) {
347     ffmpegenc->context->flags |=
348         CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME;
349   }
350
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;
357
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 CODEC_FLAG_QSCALE:
363       ffmpegenc->context->global_quality
364           = ffmpegenc->picture->quality = FF_QP2LAMBDA * ffmpegenc->quantizer;
365       break;
366     case 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)
371         goto open_file_err;
372       break;
373     case CODEC_FLAG_PASS2:
374     {                           /* need to read the whole stats file ! */
375       gsize size;
376
377       if (!g_file_get_contents (ffmpegenc->filename,
378               &ffmpegenc->context->stats_in, &size, NULL))
379         goto file_read_err;
380
381       break;
382     }
383     default:
384       break;
385   }
386
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);
390
391   /* sanitize time base */
392   if (ffmpegenc->context->time_base.num <= 0
393       || ffmpegenc->context->time_base.den <= 0)
394     goto insane_timebase;
395
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);
408   }
409
410   pix_fmt = ffmpegenc->context->pix_fmt;
411
412   /* max-key-interval may need the framerate set above */
413   if (ffmpegenc->max_key_interval) {
414     AVCodecContext *ctx;
415
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;
422   }
423
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));
427   if (!allowed_caps) {
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 */
431     allowed_caps =
432         gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
433   }
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);
437
438   /* open codec */
439   if (gst_ffmpeg_avcodec_open (ffmpegenc->context, oclass->in_plugin) < 0) {
440     gst_caps_unref (allowed_caps);
441     goto open_codec_fail;
442   }
443
444   /* is the colourspace correct? */
445   if (pix_fmt != ffmpegenc->context->pix_fmt) {
446     gst_caps_unref (allowed_caps);
447     goto pix_fmt_err;
448   }
449
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);
455     goto bad_input_fmt;
456   }
457
458   /* second pass stats buffer no longer needed */
459   g_free (ffmpegenc->context->stats_in);
460
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);
464
465   if (!other_caps) {
466     gst_caps_unref (allowed_caps);
467     goto unsupported_codec;
468   }
469
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;
476   }
477   icaps = gst_caps_fixate (icaps);
478
479   GST_DEBUG_OBJECT (ffmpegenc, "codec flags 0x%08x", ffmpegenc->context->flags);
480
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);
485
486   output_format = gst_video_encoder_set_output_state (encoder, icaps, state);
487   gst_video_codec_state_unref (output_format);
488
489   /* Store some tags */
490   {
491     GstTagList *tags = gst_tag_list_new_empty ();
492     const gchar *codec;
493
494     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
495         (guint) ffmpegenc->context->bit_rate, NULL);
496
497     if ((codec =
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,
500           NULL);
501
502     gst_video_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE);
503     gst_tag_list_unref (tags);
504   }
505
506   /* success! */
507   ffmpegenc->opened = TRUE;
508
509   return TRUE;
510
511   /* ERRORS */
512 open_file_err:
513   {
514     GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE,
515         (("Could not open file \"%s\" for writing."), ffmpegenc->filename),
516         GST_ERROR_SYSTEM);
517     return FALSE;
518   }
519 file_read_err:
520   {
521     GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ,
522         (("Could not get contents of file \"%s\"."), ffmpegenc->filename),
523         GST_ERROR_SYSTEM);
524     return FALSE;
525   }
526
527 insane_timebase:
528   {
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;
532   }
533 unsupported_codec:
534   {
535     GST_DEBUG ("Unsupported codec - no caps found");
536     goto cleanup_stats_in;
537   }
538 open_codec_fail:
539   {
540     GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to open libav codec",
541         oclass->in_plugin->name);
542     goto close_codec;
543   }
544
545 pix_fmt_err:
546   {
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);
550     goto close_codec;
551   }
552
553 bad_input_fmt:
554   {
555     GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to determine input format",
556         oclass->in_plugin->name);
557     goto close_codec;
558   }
559 close_codec:
560   {
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;
566   }
567 cleanup_stats_in:
568   {
569     g_free (ffmpegenc->context->stats_in);
570     return FALSE;
571   }
572 }
573
574
575 static gboolean
576 gst_ffmpegvidenc_propose_allocation (GstVideoEncoder * encoder,
577     GstQuery * query)
578 {
579   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
580
581   return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
582       query);
583 }
584
585 static void
586 gst_ffmpegvidenc_free_avpacket (gpointer pkt)
587 {
588   av_packet_unref ((AVPacket *) pkt);
589   g_slice_free (AVPacket, pkt);
590 }
591
592 typedef struct
593 {
594   GstBuffer *buffer;
595   GstVideoFrame vframe;
596 } BufferInfo;
597
598 static void
599 buffer_info_free (void *opaque, guint8 * data)
600 {
601   BufferInfo *info = opaque;
602
603   gst_video_frame_unmap (&info->vframe);
604   gst_buffer_unref (info->buffer);
605   g_slice_free (BufferInfo, info);
606 }
607
608 static enum AVStereo3DType
609 stereo_gst_to_av (GstVideoMultiviewMode mview_mode)
610 {
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;
626     default:
627       break;
628   }
629   GST_WARNING ("Unsupported multiview mode - no mapping in libav");
630   return AV_STEREO3D_2D;
631 }
632
633 static GstFlowReturn
634 gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
635     GstVideoCodecFrame * frame)
636 {
637   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
638   GstBuffer *outbuf;
639   gint ret = 0, c;
640   GstVideoInfo *info = &ffmpegenc->input_state->info;
641   AVPacket *pkt;
642   int have_data = 0;
643   BufferInfo *buffer_info;
644
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);
650   }
651
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));
655
656     if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) &
657         GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST) {
658       stereo->flags = AV_STEREO3D_FLAG_INVERT;
659     }
660   }
661
662   if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame))
663     ffmpegenc->picture->pict_type = AV_PICTURE_TYPE_I;
664
665   buffer_info = g_slice_new0 (BufferInfo);
666   buffer_info->buffer = gst_buffer_ref (frame->input_buffer);
667
668   if (!gst_video_frame_map (&buffer_info->vframe, info, frame->input_buffer,
669           GST_MAP_READ)) {
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;
675   }
676
677   /* Fill avpicture */
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);
686     } else {
687       ffmpegenc->picture->data[c] = NULL;
688       ffmpegenc->picture->linesize[c] = 0;
689     }
690   }
691
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);
695
696   ffmpegenc->picture->pts =
697       gst_ffmpeg_time_gst_to_ff (frame->pts /
698       ffmpegenc->context->ticks_per_frame, ffmpegenc->context->time_base);
699
700   have_data = 0;
701   pkt = g_slice_new0 (AVPacket);
702
703   ret =
704       avcodec_encode_video2 (ffmpegenc->context, pkt, ffmpegenc->picture,
705       &have_data);
706
707   av_frame_unref (ffmpegenc->picture);
708
709   if (ret < 0 || !have_data)
710     g_slice_free (AVPacket, pkt);
711
712   if (ret < 0)
713     goto encode_fail;
714
715   /* Encoder needs more data */
716   if (!have_data) {
717     gst_video_codec_frame_unref (frame);
718     return GST_FLOW_OK;
719   }
720
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),
726           GST_ERROR_SYSTEM);
727
728   gst_video_codec_frame_unref (frame);
729
730   /* Get oldest frame */
731   frame = gst_video_encoder_get_oldest_frame (encoder);
732
733   outbuf =
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;
737
738   if (pkt->flags & AV_PKT_FLAG_KEY)
739     GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
740   else
741     GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
742
743   return gst_video_encoder_finish_frame (encoder, frame);
744
745   /* ERRORS */
746 encode_fail:
747   {
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);
756   }
757 }
758
759 static GstFlowReturn
760 gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send)
761 {
762   GstVideoCodecFrame *frame;
763   GstFlowReturn flow_ret = GST_FLOW_OK;
764   GstBuffer *outbuf;
765   gint ret;
766   AVPacket *pkt;
767   int have_data = 0;
768
769   GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send);
770
771   /* no need to empty codec if there is none */
772   if (!ffmpegenc->opened)
773     goto done;
774
775   while ((frame =
776           gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (ffmpegenc)))) {
777     pkt = g_slice_new0 (AVPacket);
778     have_data = 0;
779
780     ret = avcodec_encode_video2 (ffmpegenc->context, pkt, NULL, &have_data);
781
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);
791       break;
792     }
793
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),
799             GST_ERROR_SYSTEM);
800
801     if (send && have_data) {
802       outbuf =
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;
806
807       if (pkt->flags & AV_PKT_FLAG_KEY)
808         GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
809       else
810         GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
811
812       flow_ret =
813           gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame);
814     } else {
815       /* no frame attached, so will be skipped and removed from frame list */
816       gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame);
817     }
818   }
819
820 done:
821
822   return flow_ret;
823 }
824
825
826 static void
827 gst_ffmpegvidenc_set_property (GObject * object,
828     guint prop_id, const GValue * value, GParamSpec * pspec)
829 {
830   GstFFMpegVidEnc *ffmpegenc;
831
832   /* Get a pointer of the right type. */
833   ffmpegenc = (GstFFMpegVidEnc *) (object);
834
835   if (ffmpegenc->opened) {
836     GST_WARNING_OBJECT (ffmpegenc,
837         "Can't change properties once decoder is setup !");
838     return;
839   }
840
841   /* Check the argument id to see which argument we're setting. */
842   switch (prop_id) {
843     case PROP_BIT_RATE:
844       ffmpegenc->bitrate = g_value_get_int (value);
845       break;
846     case PROP_GOP_SIZE:
847       ffmpegenc->gop_size = g_value_get_int (value);
848       break;
849     case PROP_ME_METHOD:
850       ffmpegenc->me_method = g_value_get_enum (value);
851       break;
852     case PROP_BUFSIZE:
853       break;
854     case PROP_RTP_PAYLOAD_SIZE:
855       ffmpegenc->rtp_payload_size = g_value_get_int (value);
856       break;
857     case PROP_COMPLIANCE:
858       ffmpegenc->compliance = g_value_get_enum (value);
859       break;
860     case PROP_MAX_THREADS:
861       ffmpegenc->max_threads = g_value_get_int (value);
862       break;
863     default:
864       if (!gst_ffmpeg_cfg_set_property (object, value, pspec))
865         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
866       break;
867   }
868 }
869
870 /* The set function is simply the inverse of the get fuction. */
871 static void
872 gst_ffmpegvidenc_get_property (GObject * object,
873     guint prop_id, GValue * value, GParamSpec * pspec)
874 {
875   GstFFMpegVidEnc *ffmpegenc;
876
877   /* It's not null if we got it, but it might not be ours */
878   ffmpegenc = (GstFFMpegVidEnc *) (object);
879
880   switch (prop_id) {
881     case PROP_BIT_RATE:
882       g_value_set_int (value, ffmpegenc->bitrate);
883       break;
884     case PROP_GOP_SIZE:
885       g_value_set_int (value, ffmpegenc->gop_size);
886       break;
887     case PROP_ME_METHOD:
888       g_value_set_enum (value, ffmpegenc->me_method);
889       break;
890     case PROP_BUFSIZE:
891       g_value_set_int (value, ffmpegenc->buffer_size);
892       break;
893     case PROP_RTP_PAYLOAD_SIZE:
894       g_value_set_int (value, ffmpegenc->rtp_payload_size);
895       break;
896     case PROP_COMPLIANCE:
897       g_value_set_enum (value, ffmpegenc->compliance);
898       break;
899     case PROP_MAX_THREADS:
900       g_value_set_int (value, ffmpegenc->max_threads);
901       break;
902     default:
903       if (!gst_ffmpeg_cfg_get_property (object, value, pspec))
904         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
905       break;
906   }
907 }
908
909 static gboolean
910 gst_ffmpegvidenc_flush (GstVideoEncoder * encoder)
911 {
912   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
913
914   if (ffmpegenc->opened)
915     avcodec_flush_buffers (ffmpegenc->context);
916
917   return TRUE;
918 }
919
920 static gboolean
921 gst_ffmpegvidenc_start (GstVideoEncoder * encoder)
922 {
923   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
924   GstFFMpegVidEncClass *oclass =
925       (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
926
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");
931     return FALSE;
932   }
933
934   return TRUE;
935 }
936
937 static gboolean
938 gst_ffmpegvidenc_stop (GstVideoEncoder * encoder)
939 {
940   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
941
942   gst_ffmpegvidenc_flush_buffers (ffmpegenc, FALSE);
943   gst_ffmpeg_avcodec_close (ffmpegenc->context);
944   ffmpegenc->opened = FALSE;
945
946   if (ffmpegenc->file) {
947     fclose (ffmpegenc->file);
948     ffmpegenc->file = NULL;
949   }
950   if (ffmpegenc->input_state) {
951     gst_video_codec_state_unref (ffmpegenc->input_state);
952     ffmpegenc->input_state = NULL;
953   }
954
955   return TRUE;
956 }
957
958 static GstFlowReturn
959 gst_ffmpegvidenc_finish (GstVideoEncoder * encoder)
960 {
961   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
962
963   return gst_ffmpegvidenc_flush_buffers (ffmpegenc, TRUE);
964 }
965
966 gboolean
967 gst_ffmpegvidenc_register (GstPlugin * plugin)
968 {
969   GTypeInfo typeinfo = {
970     sizeof (GstFFMpegVidEncClass),
971     (GBaseInitFunc) gst_ffmpegvidenc_base_init,
972     NULL,
973     (GClassInitFunc) gst_ffmpegvidenc_class_init,
974     NULL,
975     NULL,
976     sizeof (GstFFMpegVidEnc),
977     0,
978     (GInstanceInitFunc) gst_ffmpegvidenc_init,
979   };
980   GType type;
981   AVCodec *in_plugin;
982
983
984   GST_LOG ("Registering encoders");
985
986   /* build global ffmpeg param/property info */
987   gst_ffmpeg_cfg_init ();
988
989   in_plugin = av_codec_next (NULL);
990   while (in_plugin) {
991     gchar *type_name;
992
993     /* Skip non-AV codecs */
994     if (in_plugin->type != AVMEDIA_TYPE_VIDEO)
995       goto next;
996
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
1012 #endif
1013         || in_plugin->id == AV_CODEC_ID_ZLIB) {
1014       goto next;
1015     }
1016
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)) {
1021       GST_DEBUG
1022           ("Not using external library encoder %s. Use the gstreamer-native ones instead.",
1023           in_plugin->name);
1024       goto next;
1025     }
1026
1027     if (strstr (in_plugin->name, "vaapi")) {
1028       GST_DEBUG
1029           ("Ignoring VAAPI encoder %s. We can't handle this outside of ffmpeg",
1030           in_plugin->name);
1031       goto next;
1032     }
1033
1034     if (strstr (in_plugin->name, "nvenc")) {
1035       GST_DEBUG
1036           ("Ignoring nvenc encoder %s. We can't handle this outside of ffmpeg",
1037           in_plugin->name);
1038       goto next;
1039     }
1040
1041     if (g_str_has_suffix (in_plugin->name, "_qsv")) {
1042       GST_DEBUG
1043           ("Ignoring qsv encoder %s. We can't handle this outside of ffmpeg",
1044           in_plugin->name);
1045       goto next;
1046     }
1047
1048     if (g_str_has_suffix (in_plugin->name, "_v4l2m2m")) {
1049       GST_DEBUG
1050           ("Ignoring V4L2 mem-to-mem encoder %s. We can't handle this outside of ffmpeg",
1051           in_plugin->name);
1052       goto next;
1053     }
1054
1055     /* only video encoders */
1056     if (!av_codec_is_encoder (in_plugin)
1057         || in_plugin->type != AVMEDIA_TYPE_VIDEO)
1058       goto next;
1059
1060     /* FIXME : We should have a method to know cheaply whether we have a mapping
1061      * for the given plugin or not */
1062
1063     GST_DEBUG ("Trying plugin %s [%s]", in_plugin->name, in_plugin->long_name);
1064
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);
1068       goto next;
1069     }
1070
1071     /* construct the type */
1072     type_name = g_strdup_printf ("avenc_%s", in_plugin->name);
1073
1074     type = g_type_from_name (type_name);
1075
1076     if (!type) {
1077
1078       /* create the glib type now */
1079       type =
1080           g_type_register_static (GST_TYPE_VIDEO_ENCODER, type_name, &typeinfo,
1081           0);
1082       g_type_set_qdata (type, GST_FFENC_PARAMS_QDATA, (gpointer) in_plugin);
1083
1084       {
1085         static const GInterfaceInfo preset_info = {
1086           NULL,
1087           NULL,
1088           NULL
1089         };
1090         g_type_add_interface_static (type, GST_TYPE_PRESET, &preset_info);
1091       }
1092     }
1093
1094     if (!gst_element_register (plugin, type_name, GST_RANK_SECONDARY, type)) {
1095       g_free (type_name);
1096       return FALSE;
1097     }
1098
1099     g_free (type_name);
1100
1101   next:
1102     in_plugin = av_codec_next (in_plugin);
1103   }
1104
1105   GST_LOG ("Finished registering encoders");
1106
1107   return TRUE;
1108 }