documentation: fixed a heap o' typos
[platform/upstream/gstreamer.git] / sys / androidmedia / gstamcvideoenc.c
1 /*
2  * Initially based on gst-plugins-bad/sys/androidmedia/gstamcvideodec.c
3  *
4  * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
5  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
6  *
7  * Copyright (C) 2012, Collabora Ltd.
8  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
9  *
10  * Copyright (C) 2013, Lemote Ltd.
11  *   Author: Chen Jie <chenj@lemote.com>
12  *
13  * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
14  *
15  * This library is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Lesser General Public
17  * License as published by the Free Software Foundation
18  * version 2.1 of the License.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23  * Lesser General Public License for more details.
24  *
25  * You should have received a copy of the GNU Lesser General Public
26  * License along with this library; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
28  *
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <gst/gst.h>
36 #include <string.h>
37
38 #ifdef HAVE_ORC
39 #include <orc/orc.h>
40 #else
41 #define orc_memcpy memcpy
42 #endif
43
44 #include "gstamcvideoenc.h"
45 #include "gstamc-constants.h"
46
47 GST_DEBUG_CATEGORY_STATIC (gst_amc_video_enc_debug_category);
48 #define GST_CAT_DEFAULT gst_amc_video_enc_debug_category
49
50 typedef struct _BufferIdentification BufferIdentification;
51 struct _BufferIdentification
52 {
53   guint64 timestamp;
54 };
55
56 static BufferIdentification *
57 buffer_identification_new (GstClockTime timestamp)
58 {
59   BufferIdentification *id = g_slice_new (BufferIdentification);
60
61   id->timestamp = timestamp;
62
63   return id;
64 }
65
66 static void
67 buffer_identification_free (BufferIdentification * id)
68 {
69   g_slice_free (BufferIdentification, id);
70 }
71
72 /* prototypes */
73 static void gst_amc_video_enc_finalize (GObject * object);
74
75 static GstStateChangeReturn
76 gst_amc_video_enc_change_state (GstElement * element,
77     GstStateChange transition);
78
79 static gboolean gst_amc_video_enc_open (GstVideoEncoder * encoder);
80 static gboolean gst_amc_video_enc_close (GstVideoEncoder * encoder);
81 static gboolean gst_amc_video_enc_start (GstVideoEncoder * encoder);
82 static gboolean gst_amc_video_enc_stop (GstVideoEncoder * encoder);
83 static gboolean gst_amc_video_enc_set_format (GstVideoEncoder * encoder,
84     GstVideoCodecState * state);
85 static gboolean gst_amc_video_enc_flush (GstVideoEncoder * encoder);
86 static GstFlowReturn gst_amc_video_enc_handle_frame (GstVideoEncoder * encoder,
87     GstVideoCodecFrame * frame);
88 static GstFlowReturn gst_amc_video_enc_finish (GstVideoEncoder * encoder);
89
90 static GstFlowReturn gst_amc_video_enc_drain (GstAmcVideoEnc * self);
91
92 #define BIT_RATE_DEFAULT (2 * 1024 * 1024)
93 #define I_FRAME_INTERVAL_DEFAULT 0
94 enum
95 {
96   PROP_0,
97   PROP_BIT_RATE,
98   PROP_I_FRAME_INTERVAL
99 };
100
101 /* class initialization */
102
103 static void gst_amc_video_enc_class_init (GstAmcVideoEncClass * klass);
104 static void gst_amc_video_enc_init (GstAmcVideoEnc * self);
105 static void gst_amc_video_enc_base_init (gpointer g_class);
106
107 static GstVideoEncoderClass *parent_class = NULL;
108
109 GType
110 gst_amc_video_enc_get_type (void)
111 {
112   static volatile gsize type = 0;
113
114   if (g_once_init_enter (&type)) {
115     GType _type;
116     static const GTypeInfo info = {
117       sizeof (GstAmcVideoEncClass),
118       gst_amc_video_enc_base_init,
119       NULL,
120       (GClassInitFunc) gst_amc_video_enc_class_init,
121       NULL,
122       NULL,
123       sizeof (GstAmcVideoEnc),
124       0,
125       (GInstanceInitFunc) gst_amc_video_enc_init,
126       NULL
127     };
128
129     _type = g_type_register_static (GST_TYPE_VIDEO_ENCODER, "GstAmcVideoEnc",
130         &info, 0);
131
132     GST_DEBUG_CATEGORY_INIT (gst_amc_video_enc_debug_category, "amcvideoenc", 0,
133         "Android MediaCodec video encoder");
134
135     g_once_init_leave (&type, _type);
136   }
137   return type;
138 }
139
140 static GstAmcFormat *
141 create_amc_format (GstAmcVideoEnc * encoder, GstVideoCodecState * input_state,
142     GstCaps * src_caps)
143 {
144   GstAmcVideoEncClass *klass;
145   GstStructure *s;
146   const gchar *name;
147   const gchar *mime = NULL;
148   const gchar *profile_string = NULL;
149   const gchar *level_string = NULL;
150   struct
151   {
152     const gchar *key;
153     gint id;
154   } amc_profile = {
155   NULL, -1};
156   struct
157   {
158     const gchar *key;
159     gint id;
160   } amc_level = {
161   NULL, -1};
162   gint color_format;
163   gint stride, slice_height;
164   GstAmcFormat *format = NULL;
165   GstVideoInfo *info = &input_state->info;
166   GError *err = NULL;
167
168   klass = GST_AMC_VIDEO_ENC_GET_CLASS (encoder);
169   s = gst_caps_get_structure (src_caps, 0);
170   if (!s)
171     return NULL;
172
173   name = gst_structure_get_name (s);
174   profile_string = gst_structure_get_string (s, "profile");
175   level_string = gst_structure_get_string (s, "level");
176
177   if (strcmp (name, "video/mpeg") == 0) {
178     gint mpegversion;
179
180     if (!gst_structure_get_int (s, "mpegversion", &mpegversion))
181       return NULL;
182
183     if (mpegversion == 4) {
184       mime = "video/mp4v-es";
185
186       if (profile_string) {
187         amc_profile.key = "profile";    /* named profile ? */
188         amc_profile.id = gst_amc_mpeg4_profile_from_string (profile_string);
189       }
190
191       if (level_string) {
192         amc_level.key = "level";        /* named level ? */
193         amc_level.id = gst_amc_mpeg4_level_from_string (level_string);
194       }
195     } else if ( /* mpegversion == 1 || */ mpegversion == 2)
196       mime = "video/mpeg2";
197   } else if (strcmp (name, "video/x-h263") == 0) {
198     mime = "video/3gpp";
199   } else if (strcmp (name, "video/x-h264") == 0) {
200     mime = "video/avc";
201
202     if (profile_string) {
203       amc_profile.key = "profile";      /* named profile ? */
204       amc_profile.id = gst_amc_avc_profile_from_string (profile_string);
205     }
206
207     if (level_string) {
208       amc_level.key = "level";  /* named level ? */
209       amc_level.id = gst_amc_avc_level_from_string (level_string);
210     }
211   } else if (strcmp (name, "video/x-vp8") == 0) {
212     mime = "video/x-vnd.on2.vp8";
213   } else if (strcmp (name, "video/x-vp9") == 0) {
214     mime = "video/x-vnd.on2.vp9";
215   } else {
216     GST_ERROR_OBJECT (encoder, "Failed to convert caps(%s/...) to any mime",
217         name);
218     return NULL;
219   }
220
221   format = gst_amc_format_new_video (mime, info->width, info->height, &err);
222   if (!format) {
223     GST_ERROR_OBJECT (encoder, "Failed to create a \"%s,%dx%d\" MediaFormat",
224         mime, info->width, info->height);
225     GST_ELEMENT_ERROR_FROM_ERROR (encoder, err);
226     return NULL;
227   }
228
229   color_format =
230       gst_amc_video_format_to_color_format (klass->codec_info,
231       mime, info->finfo->format);
232   if (color_format == -1)
233     goto video_format_failed_to_convert;
234
235   gst_amc_format_set_int (format, "bitrate", encoder->bitrate, &err);
236   if (err)
237     GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
238   gst_amc_format_set_int (format, "color-format", color_format, &err);
239   if (err)
240     GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
241   stride = GST_ROUND_UP_4 (info->width);        /* safe (?) */
242   gst_amc_format_set_int (format, "stride", stride, &err);
243   if (err)
244     GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
245   slice_height = info->height;
246   gst_amc_format_set_int (format, "slice-height", slice_height, &err);
247   if (err)
248     GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
249
250   if (profile_string) {
251     if (amc_profile.id == -1)
252       goto unsupported_profile;
253
254     /* FIXME: Set to any value in AVCProfile* leads to
255      * codec configuration fail */
256     /* gst_amc_format_set_int (format, amc_profile.key, 0x40); */
257   }
258
259   if (level_string) {
260     if (amc_level.id == -1)
261       goto unsupported_level;
262
263     /* gst_amc_format_set_int (format, amc_level.key, amc_level.id); */
264   }
265
266   gst_amc_format_set_int (format, "i-frame-interval", encoder->i_frame_int,
267       &err);
268   if (err)
269     GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
270
271   if (info->fps_d)
272     gst_amc_format_set_float (format, "frame-rate",
273         ((gfloat) info->fps_n) / info->fps_d, &err);
274   if (err)
275     GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
276
277   encoder->format = info->finfo->format;
278   if (!gst_amc_color_format_info_set (&encoder->color_format_info,
279           klass->codec_info, mime, color_format, info->width, info->height,
280           stride, slice_height, 0, 0, 0, 0))
281     goto color_format_info_failed_to_set;
282
283   GST_DEBUG_OBJECT (encoder,
284       "Color format info: {color_format=%d, width=%d, height=%d, "
285       "stride=%d, slice-height=%d, crop-left=%d, crop-top=%d, "
286       "crop-right=%d, crop-bottom=%d, frame-size=%d}",
287       encoder->color_format_info.color_format, encoder->color_format_info.width,
288       encoder->color_format_info.height, encoder->color_format_info.stride,
289       encoder->color_format_info.slice_height,
290       encoder->color_format_info.crop_left, encoder->color_format_info.crop_top,
291       encoder->color_format_info.crop_right,
292       encoder->color_format_info.crop_bottom,
293       encoder->color_format_info.frame_size);
294
295   return format;
296
297 video_format_failed_to_convert:
298   GST_ERROR_OBJECT (encoder, "Failed to convert video format");
299   gst_amc_format_free (format);
300   return NULL;
301
302 color_format_info_failed_to_set:
303   GST_ERROR_OBJECT (encoder, "Failed to set up GstAmcColorFormatInfo");
304   gst_amc_format_free (format);
305   return NULL;
306
307 unsupported_profile:
308   GST_ERROR_OBJECT (encoder, "Unsupported profile '%s'", profile_string);
309   gst_amc_format_free (format);
310   return NULL;
311
312 unsupported_level:
313   GST_ERROR_OBJECT (encoder, "Unsupported level '%s'", level_string);
314   gst_amc_format_free (format);
315   return NULL;
316 }
317
318 static GstCaps *
319 caps_from_amc_format (GstAmcFormat * amc_format)
320 {
321   GstCaps *caps = NULL;
322   gchar *mime = NULL;
323   gint width, height;
324   gint amc_profile, amc_level;
325   gfloat frame_rate = 0.0;
326   gint fraction_n, fraction_d;
327   GError *err = NULL;
328
329   if (!gst_amc_format_get_string (amc_format, "mime", &mime, &err)) {
330     GST_ERROR ("Failed to get 'mime': %s", err->message);
331     g_clear_error (&err);
332     return NULL;
333   }
334
335   if (!gst_amc_format_get_int (amc_format, "width", &width, &err) ||
336       !gst_amc_format_get_int (amc_format, "height", &height, &err)) {
337     GST_ERROR ("Failed to get size: %s", err->message);
338     g_clear_error (&err);
339
340     g_free (mime);
341     return NULL;
342   }
343
344   gst_amc_format_get_float (amc_format, "frame-rate", &frame_rate, NULL);
345   gst_util_double_to_fraction (frame_rate, &fraction_n, &fraction_d);
346
347   if (strcmp (mime, "video/mp4v-es") == 0) {
348     const gchar *profile_string, *level_string;
349
350     caps =
351         gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
352         "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
353
354     if (gst_amc_format_get_int (amc_format, "profile", &amc_profile, NULL)) {
355       profile_string = gst_amc_mpeg4_profile_to_string (amc_profile);
356       if (!profile_string)
357         goto unsupported_profile;
358
359       gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile_string,
360           NULL);
361     }
362
363     if (gst_amc_format_get_int (amc_format, "level", &amc_level, NULL)) {
364       level_string = gst_amc_mpeg4_level_to_string (amc_profile);
365       if (!level_string)
366         goto unsupported_level;
367
368       gst_caps_set_simple (caps, "level", G_TYPE_STRING, level_string, NULL);
369     }
370
371   } else if (strcmp (mime, "video/mpeg2") == 0) {
372     caps = gst_caps_new_simple ("video/mpeg", "mpegversion", 2, NULL);
373   } else if (strcmp (mime, "video/3gpp") == 0) {
374     caps = gst_caps_new_empty_simple ("video/x-h263");
375   } else if (strcmp (mime, "video/avc") == 0) {
376     const gchar *profile_string, *level_string;
377
378     caps =
379         gst_caps_new_simple ("video/x-h264",
380         "stream-format", G_TYPE_STRING, "byte-stream", NULL);
381
382     if (gst_amc_format_get_int (amc_format, "profile", &amc_profile, NULL)) {
383       profile_string = gst_amc_avc_profile_to_string (amc_profile, NULL);
384       if (!profile_string)
385         goto unsupported_profile;
386
387       gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile_string,
388           NULL);
389     }
390
391     if (gst_amc_format_get_int (amc_format, "level", &amc_level, NULL)) {
392       level_string = gst_amc_avc_level_to_string (amc_profile);
393       if (!level_string)
394         goto unsupported_level;
395
396       gst_caps_set_simple (caps, "level", G_TYPE_STRING, level_string, NULL);
397     }
398   } else if (strcmp (mime, "video/x-vnd.on2.vp8") == 0) {
399     caps = gst_caps_new_empty_simple ("video/x-vp8");
400   } else if (strcmp (mime, "video/x-vnd.on2.vp9") == 0) {
401     caps = gst_caps_new_empty_simple ("video/x-vp9");
402   }
403
404   gst_caps_set_simple (caps, "width", G_TYPE_INT, width,
405       "height", G_TYPE_INT, height,
406       "framerate", GST_TYPE_FRACTION, fraction_n, fraction_d, NULL);
407
408   g_free (mime);
409   return caps;
410
411 unsupported_profile:
412   GST_ERROR ("Unsupported amc profile id %d", amc_profile);
413   g_free (mime);
414   gst_caps_unref (caps);
415
416   return NULL;
417
418 unsupported_level:
419   GST_ERROR ("Unsupported amc level id %d", amc_level);
420   g_free (mime);
421   gst_caps_unref (caps);
422
423   return NULL;
424 }
425
426 static void
427 gst_amc_video_enc_base_init (gpointer g_class)
428 {
429   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
430   GstAmcVideoEncClass *videoenc_class = GST_AMC_VIDEO_ENC_CLASS (g_class);
431   const GstAmcCodecInfo *codec_info;
432   GstPadTemplate *templ;
433   GstCaps *sink_caps, *src_caps;
434   gchar *longname;
435
436   codec_info =
437       g_type_get_qdata (G_TYPE_FROM_CLASS (g_class), gst_amc_codec_info_quark);
438   /* This happens for the base class and abstract subclasses */
439   if (!codec_info)
440     return;
441
442   videoenc_class->codec_info = codec_info;
443
444   gst_amc_codec_info_to_caps (codec_info, &sink_caps, &src_caps);
445   /* Add pad templates */
446   templ =
447       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
448   gst_element_class_add_pad_template (element_class, templ);
449   gst_caps_unref (sink_caps);
450
451   templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps);
452   gst_element_class_add_pad_template (element_class, templ);
453   gst_caps_unref (src_caps);
454
455   longname = g_strdup_printf ("Android MediaCodec %s", codec_info->name);
456   gst_element_class_set_metadata (element_class,
457       codec_info->name,
458       "Codec/Encoder/Video/Hardware",
459       longname, "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
460   g_free (longname);
461 }
462
463 static void
464 gst_amc_video_enc_set_property (GObject * object, guint prop_id,
465     const GValue * value, GParamSpec * pspec)
466 {
467   GstAmcVideoEnc *encoder;
468   GstState state;
469
470   encoder = GST_AMC_VIDEO_ENC (object);
471
472   GST_OBJECT_LOCK (encoder);
473
474   state = GST_STATE (encoder);
475   if (state != GST_STATE_READY && state != GST_STATE_NULL)
476     goto wrong_state;
477
478   switch (prop_id) {
479     case PROP_BIT_RATE:
480       encoder->bitrate = g_value_get_uint (value);
481       break;
482     case PROP_I_FRAME_INTERVAL:
483       encoder->i_frame_int = g_value_get_uint (value);
484       break;
485     default:
486       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
487       break;
488   }
489   GST_OBJECT_UNLOCK (encoder);
490   return;
491
492   /* ERROR */
493 wrong_state:
494   {
495     GST_WARNING_OBJECT (encoder, "setting property in wrong state");
496     GST_OBJECT_UNLOCK (encoder);
497   }
498 }
499
500 static void
501 gst_amc_video_enc_get_property (GObject * object, guint prop_id,
502     GValue * value, GParamSpec * pspec)
503 {
504   GstAmcVideoEnc *encoder;
505
506   encoder = GST_AMC_VIDEO_ENC (object);
507
508   GST_OBJECT_LOCK (encoder);
509   switch (prop_id) {
510     case PROP_BIT_RATE:
511       g_value_set_uint (value, encoder->bitrate);
512       break;
513     case PROP_I_FRAME_INTERVAL:
514       g_value_set_uint (value, encoder->i_frame_int);
515       break;
516     default:
517       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
518       break;
519   }
520   GST_OBJECT_UNLOCK (encoder);
521 }
522
523
524 static void
525 gst_amc_video_enc_class_init (GstAmcVideoEncClass * klass)
526 {
527   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
528   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
529   GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
530
531   parent_class = g_type_class_peek_parent (klass);
532
533   gobject_class->set_property = gst_amc_video_enc_set_property;
534   gobject_class->get_property = gst_amc_video_enc_get_property;
535   gobject_class->finalize = gst_amc_video_enc_finalize;
536
537   element_class->change_state =
538       GST_DEBUG_FUNCPTR (gst_amc_video_enc_change_state);
539
540   videoenc_class->start = GST_DEBUG_FUNCPTR (gst_amc_video_enc_start);
541   videoenc_class->stop = GST_DEBUG_FUNCPTR (gst_amc_video_enc_stop);
542   videoenc_class->open = GST_DEBUG_FUNCPTR (gst_amc_video_enc_open);
543   videoenc_class->close = GST_DEBUG_FUNCPTR (gst_amc_video_enc_close);
544   videoenc_class->flush = GST_DEBUG_FUNCPTR (gst_amc_video_enc_flush);
545   videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_amc_video_enc_set_format);
546   videoenc_class->handle_frame =
547       GST_DEBUG_FUNCPTR (gst_amc_video_enc_handle_frame);
548   videoenc_class->finish = GST_DEBUG_FUNCPTR (gst_amc_video_enc_finish);
549
550   g_object_class_install_property (gobject_class, PROP_BIT_RATE,
551       g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in bit/sec", 1,
552           G_MAXINT, BIT_RATE_DEFAULT,
553           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
554
555   g_object_class_install_property (gobject_class, PROP_I_FRAME_INTERVAL,
556       g_param_spec_uint ("i-frame-interval", "I-frame interval",
557           "The frequency of I frames expressed in seconds between I frames (0 for automatic)",
558           0, G_MAXINT, I_FRAME_INTERVAL_DEFAULT,
559           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
560 }
561
562 static void
563 gst_amc_video_enc_init (GstAmcVideoEnc * self)
564 {
565   g_mutex_init (&self->drain_lock);
566   g_cond_init (&self->drain_cond);
567
568   self->bitrate = BIT_RATE_DEFAULT;
569   self->i_frame_int = I_FRAME_INTERVAL_DEFAULT;
570 }
571
572 static gboolean
573 gst_amc_video_enc_open (GstVideoEncoder * encoder)
574 {
575   GstAmcVideoEnc *self = GST_AMC_VIDEO_ENC (encoder);
576   GstAmcVideoEncClass *klass = GST_AMC_VIDEO_ENC_GET_CLASS (self);
577   GError *err = NULL;
578
579   GST_DEBUG_OBJECT (self, "Opening encoder");
580
581   self->codec = gst_amc_codec_new (klass->codec_info->name, TRUE, &err);
582   if (!self->codec) {
583     GST_ELEMENT_ERROR_FROM_ERROR (self, err);
584     return FALSE;
585   }
586   self->started = FALSE;
587   self->flushing = TRUE;
588
589   GST_DEBUG_OBJECT (self, "Opened encoder");
590
591   return TRUE;
592 }
593
594 static gboolean
595 gst_amc_video_enc_close (GstVideoEncoder * encoder)
596 {
597   GstAmcVideoEnc *self = GST_AMC_VIDEO_ENC (encoder);
598
599   GST_DEBUG_OBJECT (self, "Closing encoder");
600
601   if (self->codec) {
602     GError *err = NULL;
603
604     gst_amc_codec_release (self->codec, &err);
605     if (err)
606       GST_ELEMENT_WARNING_FROM_ERROR (self, err);
607
608     gst_amc_codec_free (self->codec);
609   }
610   self->codec = NULL;
611
612   self->started = FALSE;
613   self->flushing = TRUE;
614
615   GST_DEBUG_OBJECT (self, "Closed encoder");
616
617   return TRUE;
618 }
619
620 static void
621 gst_amc_video_enc_finalize (GObject * object)
622 {
623   GstAmcVideoEnc *self = GST_AMC_VIDEO_ENC (object);
624
625   g_mutex_clear (&self->drain_lock);
626   g_cond_clear (&self->drain_cond);
627
628   G_OBJECT_CLASS (parent_class)->finalize (object);
629 }
630
631 static GstStateChangeReturn
632 gst_amc_video_enc_change_state (GstElement * element, GstStateChange transition)
633 {
634   GstAmcVideoEnc *self;
635   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
636   GError *err = NULL;
637
638   g_return_val_if_fail (GST_IS_AMC_VIDEO_ENC (element),
639       GST_STATE_CHANGE_FAILURE);
640   self = GST_AMC_VIDEO_ENC (element);
641
642   switch (transition) {
643     case GST_STATE_CHANGE_NULL_TO_READY:
644       break;
645     case GST_STATE_CHANGE_READY_TO_PAUSED:
646       self->downstream_flow_ret = GST_FLOW_OK;
647       self->draining = FALSE;
648       self->started = FALSE;
649       break;
650     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
651       break;
652     case GST_STATE_CHANGE_PAUSED_TO_READY:
653       self->flushing = TRUE;
654       gst_amc_codec_flush (self->codec, &err);
655       if (err)
656         GST_ELEMENT_WARNING_FROM_ERROR (self, err);
657       g_mutex_lock (&self->drain_lock);
658       self->draining = FALSE;
659       g_cond_broadcast (&self->drain_cond);
660       g_mutex_unlock (&self->drain_lock);
661       break;
662     default:
663       break;
664   }
665
666   if (ret == GST_STATE_CHANGE_FAILURE)
667     return ret;
668
669   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
670
671   if (ret == GST_STATE_CHANGE_FAILURE)
672     return ret;
673
674   switch (transition) {
675     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
676       break;
677     case GST_STATE_CHANGE_PAUSED_TO_READY:
678       self->downstream_flow_ret = GST_FLOW_FLUSHING;
679       self->started = FALSE;
680       break;
681     case GST_STATE_CHANGE_READY_TO_NULL:
682       break;
683     default:
684       break;
685   }
686
687   return ret;
688 }
689
690 #define MAX_FRAME_DIST_TIME  (5 * GST_SECOND)
691 #define MAX_FRAME_DIST_FRAMES (100)
692
693 static GstVideoCodecFrame *
694 _find_nearest_frame (GstAmcVideoEnc * self, GstClockTime reference_timestamp)
695 {
696   GList *l, *best_l = NULL;
697   GList *finish_frames = NULL;
698   GstVideoCodecFrame *best = NULL;
699   guint64 best_timestamp = 0;
700   guint64 best_diff = G_MAXUINT64;
701   BufferIdentification *best_id = NULL;
702   GList *frames;
703
704   frames = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (self));
705
706   for (l = frames; l; l = l->next) {
707     GstVideoCodecFrame *tmp = l->data;
708     BufferIdentification *id = gst_video_codec_frame_get_user_data (tmp);
709     guint64 timestamp, diff;
710
711     /* This happens for frames that were just added but
712      * which were not passed to the component yet. Ignore
713      * them here!
714      */
715     if (!id)
716       continue;
717
718     timestamp = id->timestamp;
719
720     if (timestamp > reference_timestamp)
721       diff = timestamp - reference_timestamp;
722     else
723       diff = reference_timestamp - timestamp;
724
725     if (best == NULL || diff < best_diff) {
726       best = tmp;
727       best_timestamp = timestamp;
728       best_diff = diff;
729       best_l = l;
730       best_id = id;
731
732       /* For frames without timestamp we simply take the first frame */
733       if ((reference_timestamp == 0 && !GST_CLOCK_TIME_IS_VALID (timestamp))
734           || diff == 0)
735         break;
736     }
737   }
738
739   if (best_id) {
740     for (l = frames; l && l != best_l; l = l->next) {
741       GstVideoCodecFrame *tmp = l->data;
742       BufferIdentification *id = gst_video_codec_frame_get_user_data (tmp);
743       guint64 diff_time, diff_frames;
744
745       if (id->timestamp > best_timestamp)
746         break;
747
748       if (id->timestamp == 0 || best_timestamp == 0)
749         diff_time = 0;
750       else
751         diff_time = best_timestamp - id->timestamp;
752       diff_frames = best->system_frame_number - tmp->system_frame_number;
753
754       if (diff_time > MAX_FRAME_DIST_TIME
755           || diff_frames > MAX_FRAME_DIST_FRAMES) {
756         finish_frames =
757             g_list_prepend (finish_frames, gst_video_codec_frame_ref (tmp));
758       }
759     }
760   }
761
762   if (finish_frames) {
763     g_warning ("%s: Too old frames, bug in encoder -- please file a bug",
764         GST_ELEMENT_NAME (self));
765     for (l = finish_frames; l; l = l->next) {
766       gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), l->data);
767     }
768   }
769
770   if (best)
771     gst_video_codec_frame_ref (best);
772
773   g_list_foreach (frames, (GFunc) gst_video_codec_frame_unref, NULL);
774   g_list_free (frames);
775
776   return best;
777 }
778
779 static gboolean
780 gst_amc_video_enc_set_src_caps (GstAmcVideoEnc * self, GstAmcFormat * format)
781 {
782   GstCaps *caps;
783   GstVideoCodecState *output_state;
784
785   caps = caps_from_amc_format (format);
786   if (!caps) {
787     GST_ERROR_OBJECT (self, "Failed to create output caps");
788     return FALSE;
789   }
790
791   /* It may not be proper to reference self->input_state here,
792    * because MediaCodec is an async model -- input_state may change multiple times,
793    * the passed-in MediaFormat may not be the one matched to the current input_state.
794    *
795    * Though, currently, the final src caps only calculate
796    * width/height/pixel-aspect-ratio/framerate/codec_data from self->input_state.
797    *
798    * If input width/height/codec_data change(is_format_change), it will restart
799    * MediaCodec, which means in these cases, self->input_state is matched.
800    */
801   output_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
802       caps, self->input_state);
803   gst_video_codec_state_unref (output_state);
804
805   if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self)))
806     return FALSE;
807
808   return TRUE;
809 }
810
811 /* The weird handling of cropping, alignment and everything is taken from
812  * platform/frameworks/media/libstagefright/colorconversion/ColorConversion.cpp
813  */
814 static gboolean
815 gst_amc_video_enc_fill_buffer (GstAmcVideoEnc * self, GstBuffer * inbuf,
816     GstAmcBuffer * outbuf, const GstAmcBufferInfo * buffer_info)
817 {
818   GstVideoCodecState *input_state = self->input_state;
819   /* The fill_buffer runs in the same thread as set_format?
820    * then we can use state->info safely */
821   GstVideoInfo *info = &input_state->info;
822
823   if (buffer_info->size < self->color_format_info.frame_size)
824     return FALSE;
825
826   return gst_amc_color_format_copy (&self->color_format_info, outbuf,
827       buffer_info, info, inbuf, COLOR_FORMAT_COPY_IN);
828 }
829
830 static GstFlowReturn
831 gst_amc_video_enc_handle_output_frame (GstAmcVideoEnc * self,
832     GstAmcBuffer * buf, const GstAmcBufferInfo * buffer_info,
833     GstVideoCodecFrame * frame)
834 {
835   GstFlowReturn flow_ret = GST_FLOW_OK;
836   GstVideoEncoder *encoder = GST_VIDEO_ENCODER_CAST (self);
837
838   /* The BUFFER_FLAG_CODEC_CONFIG logic is borrowed from
839    * gst-omx. see *_handle_output_frame in
840    * gstomxvideoenc.c and gstomxh264enc.c */
841   if ((buffer_info->flags & BUFFER_FLAG_CODEC_CONFIG)
842       && buffer_info->size > 0) {
843     GstStructure *s;
844     GstVideoCodecState *state;
845
846     state = gst_video_encoder_get_output_state (encoder);
847     s = gst_caps_get_structure (state->caps, 0);
848     if (!strcmp (gst_structure_get_name (s), "video/x-h264")) {
849       gst_video_codec_state_unref (state);
850
851       if (buffer_info->size > 4 &&
852           GST_READ_UINT32_BE (buf->data + buffer_info->offset) == 0x00000001) {
853         GList *l = NULL;
854         GstBuffer *hdrs;
855
856         GST_DEBUG_OBJECT (self, "got codecconfig in byte-stream format");
857
858         hdrs = gst_buffer_new_and_alloc (buffer_info->size);
859         gst_buffer_fill (hdrs, 0, buf->data + buffer_info->offset,
860             buffer_info->size);
861         GST_BUFFER_PTS (hdrs) =
862             gst_util_uint64_scale (buffer_info->presentation_time_us,
863             GST_USECOND, 1);
864
865         l = g_list_append (l, hdrs);
866         gst_video_encoder_set_headers (encoder, l);
867       }
868     } else {
869       GstBuffer *codec_data;
870
871       GST_DEBUG_OBJECT (self, "Handling codec data");
872
873       codec_data = gst_buffer_new_and_alloc (buffer_info->size);
874       gst_buffer_fill (codec_data, 0, buf->data + buffer_info->offset,
875           buffer_info->size);
876       state->codec_data = codec_data;
877       gst_video_codec_state_unref (state);
878
879       if (!gst_video_encoder_negotiate (encoder)) {
880         gst_video_codec_frame_unref (frame);
881         return GST_FLOW_NOT_NEGOTIATED;
882       }
883
884       return GST_FLOW_OK;
885     }
886   }
887
888   if (buffer_info->size > 0) {
889     GstBuffer *out_buf;
890     GstPad *srcpad;
891
892     srcpad = GST_VIDEO_ENCODER_SRC_PAD (encoder);
893     out_buf =
894         gst_video_encoder_allocate_output_buffer (encoder, buffer_info->size);
895     gst_buffer_fill (out_buf, 0, buf->data + buffer_info->offset,
896         buffer_info->size);
897
898     GST_BUFFER_PTS (out_buf) =
899         gst_util_uint64_scale (buffer_info->presentation_time_us, GST_USECOND,
900         1);
901
902     if (frame) {
903       frame->output_buffer = out_buf;
904       flow_ret = gst_video_encoder_finish_frame (encoder, frame);
905     } else {
906       /* This sometimes happens at EOS or if the input is not properly framed,
907        * let's handle it gracefully by allocating a new buffer for the current
908        * caps and filling it
909        */
910
911       GST_ERROR_OBJECT (self, "No corresponding frame found");
912       flow_ret = gst_pad_push (srcpad, out_buf);
913     }
914   } else if (frame) {
915     flow_ret = gst_video_encoder_finish_frame (encoder, frame);
916   }
917
918   return flow_ret;
919 }
920
921 static void
922 gst_amc_video_enc_loop (GstAmcVideoEnc * self)
923 {
924   GstVideoCodecFrame *frame;
925   GstFlowReturn flow_ret = GST_FLOW_OK;
926   gboolean is_eos;
927   GstAmcBufferInfo buffer_info;
928   GstAmcBuffer *buf;
929   gint idx;
930   GError *err = NULL;
931
932   GST_VIDEO_ENCODER_STREAM_LOCK (self);
933
934 retry:
935   GST_DEBUG_OBJECT (self, "Waiting for available output buffer");
936   GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
937   /* Wait at most 100ms here, some codecs don't fail dequeueing if
938    * the codec is flushing, causing deadlocks during shutdown */
939   idx =
940       gst_amc_codec_dequeue_output_buffer (self->codec, &buffer_info, 100000,
941       &err);
942   GST_VIDEO_ENCODER_STREAM_LOCK (self);
943   /*} */
944
945   if (idx < 0 || self->amc_format) {
946     if (self->flushing) {
947       g_clear_error (&err);
948       goto flushing;
949     }
950
951     /* The comments from https://android.googlesource.com/platform/cts/+/android-4.3_r3.1/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
952      * line 539 says INFO_OUTPUT_FORMAT_CHANGED is not expected for an encoder
953      */
954     if (self->amc_format || idx == INFO_OUTPUT_FORMAT_CHANGED) {
955       GstAmcFormat *format;
956       gchar *format_string;
957
958       GST_DEBUG_OBJECT (self, "Output format has changed");
959
960       format = (idx == INFO_OUTPUT_FORMAT_CHANGED) ?
961           gst_amc_codec_get_output_format (self->codec,
962           &err) : self->amc_format;
963       if (err) {
964         format = self->amc_format;
965         GST_ELEMENT_WARNING_FROM_ERROR (self, err);
966       }
967
968       if (self->amc_format) {
969         if (format != self->amc_format)
970           gst_amc_format_free (self->amc_format);
971         self->amc_format = NULL;
972       }
973
974       if (!format)
975         goto format_error;
976
977       format_string = gst_amc_format_to_string (format, &err);
978       if (err) {
979         gst_amc_format_free (format);
980         goto format_error;
981       }
982       GST_DEBUG_OBJECT (self, "Got new output format: %s", format_string);
983       g_free (format_string);
984
985       if (!gst_amc_video_enc_set_src_caps (self, format)) {
986         gst_amc_format_free (format);
987         goto format_error;
988       }
989
990       gst_amc_format_free (format);
991
992       if (idx >= 0)
993         goto process_buffer;
994
995       goto retry;
996     }
997
998     switch (idx) {
999       case INFO_OUTPUT_BUFFERS_CHANGED:
1000         /* Handled internally */
1001         g_assert_not_reached ();
1002         break;
1003       case INFO_TRY_AGAIN_LATER:
1004         GST_DEBUG_OBJECT (self, "Dequeueing output buffer timed out");
1005         goto retry;
1006         break;
1007       case G_MININT:
1008         GST_ERROR_OBJECT (self, "Failure dequeueing input buffer");
1009         goto dequeue_error;
1010         break;
1011       default:
1012         g_assert_not_reached ();
1013         break;
1014     }
1015
1016     goto retry;
1017   }
1018
1019 process_buffer:
1020   GST_DEBUG_OBJECT (self,
1021       "Got output buffer at index %d: size %d time %" G_GINT64_FORMAT
1022       " flags 0x%08x", idx, buffer_info.size, buffer_info.presentation_time_us,
1023       buffer_info.flags);
1024
1025   buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err);
1026   if (err) {
1027     if (self->flushing) {
1028       g_clear_error (&err);
1029       goto flushing;
1030     }
1031     goto failed_to_get_output_buffer;
1032   } else if (!buf) {
1033     goto got_null_output_buffer;
1034   }
1035
1036   frame =
1037       _find_nearest_frame (self,
1038       gst_util_uint64_scale (buffer_info.presentation_time_us, GST_USECOND, 1));
1039
1040   is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM);
1041
1042   flow_ret =
1043       gst_amc_video_enc_handle_output_frame (self, buf, &buffer_info, frame);
1044
1045   gst_amc_buffer_free (buf);
1046   buf = NULL;
1047
1048   if (!gst_amc_codec_release_output_buffer (self->codec, idx, FALSE, &err)) {
1049     if (self->flushing) {
1050       g_clear_error (&err);
1051       goto flushing;
1052     }
1053     goto failed_release;
1054   }
1055
1056   if (is_eos || flow_ret == GST_FLOW_EOS) {
1057     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1058     g_mutex_lock (&self->drain_lock);
1059     if (self->draining) {
1060       GST_DEBUG_OBJECT (self, "Drained");
1061       self->draining = FALSE;
1062       g_cond_broadcast (&self->drain_cond);
1063     } else if (flow_ret == GST_FLOW_OK) {
1064       GST_DEBUG_OBJECT (self, "Component signalled EOS");
1065       flow_ret = GST_FLOW_EOS;
1066     }
1067     g_mutex_unlock (&self->drain_lock);
1068     GST_VIDEO_ENCODER_STREAM_LOCK (self);
1069   } else {
1070     GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
1071   }
1072
1073   self->downstream_flow_ret = flow_ret;
1074
1075   if (flow_ret != GST_FLOW_OK)
1076     goto flow_error;
1077
1078   GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1079
1080   return;
1081
1082 dequeue_error:
1083   {
1084     GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1085     gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1086     gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1087     self->downstream_flow_ret = GST_FLOW_ERROR;
1088     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1089     g_mutex_lock (&self->drain_lock);
1090     self->draining = FALSE;
1091     g_cond_broadcast (&self->drain_cond);
1092     g_mutex_unlock (&self->drain_lock);
1093     return;
1094   }
1095
1096 format_error:
1097   {
1098     if (err)
1099       GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1100     else
1101       GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1102           ("Failed to handle format"));
1103     gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1104     gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1105     self->downstream_flow_ret = GST_FLOW_ERROR;
1106     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1107     g_mutex_lock (&self->drain_lock);
1108     self->draining = FALSE;
1109     g_cond_broadcast (&self->drain_cond);
1110     g_mutex_unlock (&self->drain_lock);
1111     return;
1112   }
1113 failed_release:
1114   {
1115     GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1116     gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1117     gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1118     self->downstream_flow_ret = GST_FLOW_ERROR;
1119     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1120     g_mutex_lock (&self->drain_lock);
1121     self->draining = FALSE;
1122     g_cond_broadcast (&self->drain_cond);
1123     g_mutex_unlock (&self->drain_lock);
1124     return;
1125   }
1126 flushing:
1127   {
1128     GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1129     gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1130     self->downstream_flow_ret = GST_FLOW_FLUSHING;
1131     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1132     return;
1133   }
1134
1135 flow_error:
1136   {
1137     if (flow_ret == GST_FLOW_EOS) {
1138       GST_DEBUG_OBJECT (self, "EOS");
1139       gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
1140           gst_event_new_eos ());
1141       gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1142     } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) {
1143       GST_ELEMENT_FLOW_ERROR (self, flow_ret);
1144       gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
1145           gst_event_new_eos ());
1146       gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1147     }
1148     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1149     g_mutex_lock (&self->drain_lock);
1150     self->draining = FALSE;
1151     g_cond_broadcast (&self->drain_cond);
1152     g_mutex_unlock (&self->drain_lock);
1153     return;
1154   }
1155
1156 failed_to_get_output_buffer:
1157   {
1158     GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1159     gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1160     gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1161     self->downstream_flow_ret = GST_FLOW_ERROR;
1162     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1163     g_mutex_lock (&self->drain_lock);
1164     self->draining = FALSE;
1165     g_cond_broadcast (&self->drain_cond);
1166     g_mutex_unlock (&self->drain_lock);
1167     return;
1168   }
1169
1170 got_null_output_buffer:
1171   {
1172     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1173         ("Got no output buffer"));
1174     gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1175     gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1176     self->downstream_flow_ret = GST_FLOW_ERROR;
1177     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1178     g_mutex_lock (&self->drain_lock);
1179     self->draining = FALSE;
1180     g_cond_broadcast (&self->drain_cond);
1181     g_mutex_unlock (&self->drain_lock);
1182     return;
1183   }
1184 }
1185
1186 static gboolean
1187 gst_amc_video_enc_start (GstVideoEncoder * encoder)
1188 {
1189   GstAmcVideoEnc *self;
1190
1191   self = GST_AMC_VIDEO_ENC (encoder);
1192   self->last_upstream_ts = 0;
1193   self->drained = TRUE;
1194   self->downstream_flow_ret = GST_FLOW_OK;
1195   self->started = FALSE;
1196   self->flushing = TRUE;
1197
1198   return TRUE;
1199 }
1200
1201 static gboolean
1202 gst_amc_video_enc_stop (GstVideoEncoder * encoder)
1203 {
1204   GstAmcVideoEnc *self;
1205   GError *err = NULL;
1206
1207   self = GST_AMC_VIDEO_ENC (encoder);
1208   GST_DEBUG_OBJECT (self, "Stopping encoder");
1209   self->flushing = TRUE;
1210   if (self->started) {
1211     gst_amc_codec_flush (self->codec, &err);
1212     if (err)
1213       GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1214     gst_amc_codec_stop (self->codec, &err);
1215     if (err)
1216       GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1217     self->started = FALSE;
1218   }
1219   gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1220
1221   self->downstream_flow_ret = GST_FLOW_FLUSHING;
1222   self->drained = TRUE;
1223   g_mutex_lock (&self->drain_lock);
1224   self->draining = FALSE;
1225   g_cond_broadcast (&self->drain_cond);
1226   g_mutex_unlock (&self->drain_lock);
1227   if (self->input_state)
1228     gst_video_codec_state_unref (self->input_state);
1229   self->input_state = NULL;
1230
1231   if (self->amc_format) {
1232     gst_amc_format_free (self->amc_format);
1233     self->amc_format = NULL;
1234   }
1235
1236   GST_DEBUG_OBJECT (self, "Stopped encoder");
1237   return TRUE;
1238 }
1239
1240 static gboolean
1241 gst_amc_video_enc_set_format (GstVideoEncoder * encoder,
1242     GstVideoCodecState * state)
1243 {
1244   GstAmcVideoEnc *self;
1245   GstAmcFormat *format = NULL;
1246   GstCaps *allowed_caps = NULL;
1247   gboolean is_format_change = FALSE;
1248   gboolean needs_disable = FALSE;
1249   gchar *format_string;
1250   gboolean r = FALSE;
1251   GError *err = NULL;
1252
1253   self = GST_AMC_VIDEO_ENC (encoder);
1254
1255   GST_DEBUG_OBJECT (self, "Setting new caps %" GST_PTR_FORMAT, state->caps);
1256
1257   /* Check if the caps change is a real format change or if only irrelevant
1258    * parts of the caps have changed or nothing at all.
1259    */
1260   is_format_change |= self->color_format_info.width != state->info.width;
1261   is_format_change |= self->color_format_info.height != state->info.height;
1262   needs_disable = self->started;
1263
1264   /* If the component is not started and a real format change happens
1265    * we have to restart the component. If no real format change
1266    * happened we can just exit here.
1267    */
1268   if (needs_disable && !is_format_change) {
1269
1270     /* Framerate or something minor changed */
1271     if (self->input_state)
1272       gst_video_codec_state_unref (self->input_state);
1273     self->input_state = gst_video_codec_state_ref (state);
1274     GST_DEBUG_OBJECT (self,
1275         "Already running and caps did not change the format");
1276     return TRUE;
1277   }
1278
1279   if (needs_disable && is_format_change) {
1280     gst_amc_video_enc_drain (self);
1281     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1282     gst_amc_video_enc_stop (GST_VIDEO_ENCODER (self));
1283     GST_VIDEO_ENCODER_STREAM_LOCK (self);
1284     gst_amc_video_enc_close (GST_VIDEO_ENCODER (self));
1285     if (!gst_amc_video_enc_open (GST_VIDEO_ENCODER (self))) {
1286       GST_ERROR_OBJECT (self, "Failed to open codec again");
1287       return FALSE;
1288     }
1289
1290     if (!gst_amc_video_enc_start (GST_VIDEO_ENCODER (self))) {
1291       GST_ERROR_OBJECT (self, "Failed to start codec again");
1292     }
1293   }
1294   /* srcpad task is not running at this point */
1295   if (self->input_state)
1296     gst_video_codec_state_unref (self->input_state);
1297   self->input_state = NULL;
1298
1299   GST_DEBUG_OBJECT (self, "picking an output format ...");
1300   allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1301   if (!allowed_caps) {
1302     GST_DEBUG_OBJECT (self, "... but no peer, using template caps");
1303     allowed_caps =
1304         gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1305   }
1306   GST_DEBUG_OBJECT (self, "chose caps %" GST_PTR_FORMAT, allowed_caps);
1307   allowed_caps = gst_caps_truncate (allowed_caps);
1308
1309   format = create_amc_format (self, state, allowed_caps);
1310   if (!format)
1311     goto quit;
1312
1313   format_string = gst_amc_format_to_string (format, &err);
1314   if (err)
1315     GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1316   GST_DEBUG_OBJECT (self, "Configuring codec with format: %s",
1317       GST_STR_NULL (format_string));
1318   g_free (format_string);
1319
1320   if (!gst_amc_codec_configure (self->codec, format, NULL, &err)) {
1321     GST_ERROR_OBJECT (self, "Failed to configure codec");
1322     GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1323     goto quit;
1324   }
1325
1326   if (!gst_amc_codec_start (self->codec, &err)) {
1327     GST_ERROR_OBJECT (self, "Failed to start codec");
1328     GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1329     goto quit;
1330   }
1331
1332   self->amc_format = format;
1333   format = NULL;
1334
1335   self->input_state = gst_video_codec_state_ref (state);
1336
1337   self->started = TRUE;
1338
1339   /* Start the srcpad loop again */
1340   self->flushing = FALSE;
1341   self->downstream_flow_ret = GST_FLOW_OK;
1342   gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
1343       (GstTaskFunction) gst_amc_video_enc_loop, encoder, NULL);
1344
1345   r = TRUE;
1346
1347 quit:
1348   if (allowed_caps)
1349     gst_caps_unref (allowed_caps);
1350
1351   if (format)
1352     gst_amc_format_free (format);
1353
1354   return r;
1355 }
1356
1357 static gboolean
1358 gst_amc_video_enc_flush (GstVideoEncoder * encoder)
1359 {
1360   GstAmcVideoEnc *self;
1361   GError *err = NULL;
1362
1363   self = GST_AMC_VIDEO_ENC (encoder);
1364
1365   GST_DEBUG_OBJECT (self, "Flushing encoder");
1366
1367   if (!self->started) {
1368     GST_DEBUG_OBJECT (self, "Codec not started yet");
1369     return TRUE;
1370   }
1371
1372   self->flushing = TRUE;
1373   gst_amc_codec_flush (self->codec, &err);
1374   if (err)
1375     GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1376
1377   /* Wait until the srcpad loop is finished,
1378    * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
1379    * caused by using this lock from inside the loop function */
1380   GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1381   GST_PAD_STREAM_LOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
1382   GST_PAD_STREAM_UNLOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
1383   GST_VIDEO_ENCODER_STREAM_LOCK (self);
1384   self->flushing = FALSE;
1385
1386   /* Start the srcpad loop again */
1387   self->last_upstream_ts = 0;
1388   self->drained = TRUE;
1389   self->downstream_flow_ret = GST_FLOW_OK;
1390   gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
1391       (GstTaskFunction) gst_amc_video_enc_loop, encoder, NULL);
1392
1393   GST_DEBUG_OBJECT (self, "Flush encoder");
1394
1395   return TRUE;
1396 }
1397
1398 static GstFlowReturn
1399 gst_amc_video_enc_handle_frame (GstVideoEncoder * encoder,
1400     GstVideoCodecFrame * frame)
1401 {
1402   GstAmcVideoEnc *self;
1403   gint idx;
1404   GstAmcBuffer *buf;
1405   GstAmcBufferInfo buffer_info;
1406   GstClockTime timestamp, duration, timestamp_offset = 0;
1407   BufferIdentification *id;
1408   GError *err = NULL;
1409
1410   self = GST_AMC_VIDEO_ENC (encoder);
1411
1412   GST_DEBUG_OBJECT (self, "Handling frame");
1413
1414   if (!self->started) {
1415     GST_ERROR_OBJECT (self, "Codec not started yet");
1416     gst_video_codec_frame_unref (frame);
1417     return GST_FLOW_NOT_NEGOTIATED;
1418   }
1419
1420   if (self->flushing)
1421     goto flushing;
1422
1423   if (self->downstream_flow_ret != GST_FLOW_OK)
1424     goto downstream_error;
1425
1426   timestamp = frame->pts;
1427   duration = frame->duration;
1428
1429 again:
1430   /* Make sure to release the base class stream lock, otherwise
1431    * _loop() can't call _finish_frame() and we might block forever
1432    * because no input buffers are released */
1433   GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1434   /* Wait at most 100ms here, some codecs don't fail dequeueing if
1435    * the codec is flushing, causing deadlocks during shutdown */
1436   idx = gst_amc_codec_dequeue_input_buffer (self->codec, 100000, &err);
1437   GST_VIDEO_ENCODER_STREAM_LOCK (self);
1438
1439   if (idx < 0) {
1440     if (self->flushing || self->downstream_flow_ret == GST_FLOW_FLUSHING) {
1441       g_clear_error (&err);
1442       goto flushing;
1443     }
1444
1445     switch (idx) {
1446       case INFO_TRY_AGAIN_LATER:
1447         GST_DEBUG_OBJECT (self, "Dequeueing input buffer timed out");
1448         goto again;             /* next try */
1449         break;
1450       case G_MININT:
1451         GST_ERROR_OBJECT (self, "Failed to dequeue input buffer");
1452         goto dequeue_error;
1453       default:
1454         g_assert_not_reached ();
1455         break;
1456     }
1457
1458     goto again;
1459   }
1460
1461   if (self->flushing) {
1462     memset (&buffer_info, 0, sizeof (buffer_info));
1463     gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, NULL);
1464     goto flushing;
1465   }
1466
1467   if (self->downstream_flow_ret != GST_FLOW_OK) {
1468     memset (&buffer_info, 0, sizeof (buffer_info));
1469     gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err);
1470     if (err && !self->flushing)
1471       GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1472     g_clear_error (&err);
1473     goto downstream_error;
1474   }
1475
1476   /* Now handle the frame */
1477
1478   /* Copy the buffer content in chunks of size as requested
1479    * by the port */
1480   buf = gst_amc_codec_get_input_buffer (self->codec, idx, &err);
1481   if (err)
1482     goto failed_to_get_input_buffer;
1483   else if (!buf)
1484     goto got_null_input_buffer;
1485
1486   memset (&buffer_info, 0, sizeof (buffer_info));
1487   buffer_info.offset = 0;
1488   buffer_info.size = MIN (self->color_format_info.frame_size, buf->size);
1489   gst_amc_buffer_set_position_and_limit (buf, NULL, buffer_info.offset,
1490       buffer_info.size);
1491
1492   if (!gst_amc_video_enc_fill_buffer (self, frame->input_buffer, buf,
1493           &buffer_info)) {
1494     memset (&buffer_info, 0, sizeof (buffer_info));
1495     gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err);
1496     if (err && !self->flushing)
1497       GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1498     g_clear_error (&err);
1499     gst_amc_buffer_free (buf);
1500     buf = NULL;
1501     goto buffer_fill_error;
1502   }
1503
1504   gst_amc_buffer_free (buf);
1505   buf = NULL;
1506
1507   if (timestamp != GST_CLOCK_TIME_NONE) {
1508     buffer_info.presentation_time_us =
1509         gst_util_uint64_scale (timestamp + timestamp_offset, 1, GST_USECOND);
1510     self->last_upstream_ts = timestamp + timestamp_offset;
1511   }
1512   if (duration != GST_CLOCK_TIME_NONE)
1513     self->last_upstream_ts += duration;
1514
1515   id = buffer_identification_new (timestamp + timestamp_offset);
1516   if (GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame))
1517     buffer_info.flags |= BUFFER_FLAG_SYNC_FRAME;
1518   gst_video_codec_frame_set_user_data (frame, id,
1519       (GDestroyNotify) buffer_identification_free);
1520
1521   GST_DEBUG_OBJECT (self,
1522       "Queueing buffer %d: size %d time %" G_GINT64_FORMAT " flags 0x%08x",
1523       idx, buffer_info.size, buffer_info.presentation_time_us,
1524       buffer_info.flags);
1525   if (!gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err)) {
1526     if (self->flushing) {
1527       g_clear_error (&err);
1528       goto flushing;
1529     }
1530     goto queue_error;
1531   }
1532
1533   self->drained = FALSE;
1534
1535   gst_video_codec_frame_unref (frame);
1536
1537   return self->downstream_flow_ret;
1538
1539 downstream_error:
1540   {
1541     GST_ERROR_OBJECT (self, "Downstream returned %s",
1542         gst_flow_get_name (self->downstream_flow_ret));
1543
1544     gst_video_codec_frame_unref (frame);
1545     return self->downstream_flow_ret;
1546   }
1547 failed_to_get_input_buffer:
1548   {
1549     GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1550     gst_video_codec_frame_unref (frame);
1551     return GST_FLOW_ERROR;
1552   }
1553 got_null_input_buffer:
1554   {
1555     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1556         ("Got no input buffer"));
1557     gst_video_codec_frame_unref (frame);
1558     return GST_FLOW_ERROR;
1559   }
1560 buffer_fill_error:
1561   {
1562     GST_ELEMENT_ERROR (self, RESOURCE, WRITE, (NULL),
1563         ("Failed to write input into the amc buffer(write %dB to a %"
1564             G_GSIZE_FORMAT "B buffer)", self->color_format_info.frame_size,
1565             buf->size));
1566     gst_video_codec_frame_unref (frame);
1567     return GST_FLOW_ERROR;
1568   }
1569 dequeue_error:
1570   {
1571     GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1572     gst_video_codec_frame_unref (frame);
1573     return GST_FLOW_ERROR;
1574   }
1575 queue_error:
1576   {
1577     GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1578     gst_video_codec_frame_unref (frame);
1579     return GST_FLOW_ERROR;
1580   }
1581 flushing:
1582   {
1583     GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
1584     gst_video_codec_frame_unref (frame);
1585     return GST_FLOW_FLUSHING;
1586   }
1587 }
1588
1589 static GstFlowReturn
1590 gst_amc_video_enc_finish (GstVideoEncoder * encoder)
1591 {
1592   GstAmcVideoEnc *self;
1593
1594   self = GST_AMC_VIDEO_ENC (encoder);
1595
1596   return gst_amc_video_enc_drain (self);
1597 }
1598
1599 static GstFlowReturn
1600 gst_amc_video_enc_drain (GstAmcVideoEnc * self)
1601 {
1602   GstFlowReturn ret;
1603   gint idx;
1604   GError *err = NULL;
1605
1606   GST_DEBUG_OBJECT (self, "Draining codec");
1607   if (!self->started) {
1608     GST_DEBUG_OBJECT (self, "Codec not started yet");
1609     return GST_FLOW_OK;
1610   }
1611
1612   /* Don't send drain buffer twice, this doesn't work */
1613   if (self->drained) {
1614     GST_DEBUG_OBJECT (self, "Codec is drained already");
1615     return GST_FLOW_OK;
1616   }
1617
1618   /* Make sure to release the base class stream lock, otherwise
1619    * _loop() can't call _finish_frame() and we might block forever
1620    * because no input buffers are released */
1621   GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1622   /* Send an EOS buffer to the component and let the base
1623    * class drop the EOS event. We will send it later when
1624    * the EOS buffer arrives on the output port.
1625    * Wait at most 0.5s here. */
1626   idx = gst_amc_codec_dequeue_input_buffer (self->codec, 500000, &err);
1627   GST_VIDEO_ENCODER_STREAM_LOCK (self);
1628
1629   if (idx >= 0) {
1630     GstAmcBuffer *buf;
1631     GstAmcBufferInfo buffer_info;
1632
1633     buf = gst_amc_codec_get_input_buffer (self->codec, idx, &err);
1634     if (buf) {
1635       GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1636       g_mutex_lock (&self->drain_lock);
1637       self->draining = TRUE;
1638
1639       memset (&buffer_info, 0, sizeof (buffer_info));
1640       buffer_info.size = 0;
1641       buffer_info.presentation_time_us =
1642           gst_util_uint64_scale (self->last_upstream_ts, 1, GST_USECOND);
1643       buffer_info.flags |= BUFFER_FLAG_END_OF_STREAM;
1644
1645       gst_amc_buffer_set_position_and_limit (buf, NULL, 0, 0);
1646       gst_amc_buffer_free (buf);
1647       buf = NULL;
1648
1649       if (gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info,
1650               &err)) {
1651         GST_DEBUG_OBJECT (self, "Waiting until codec is drained");
1652         g_cond_wait (&self->drain_cond, &self->drain_lock);
1653         GST_DEBUG_OBJECT (self, "Drained codec");
1654         ret = GST_FLOW_OK;
1655       } else {
1656         GST_ERROR_OBJECT (self, "Failed to queue input buffer");
1657         if (self->flushing) {
1658           g_clear_error (&err);
1659           ret = GST_FLOW_FLUSHING;
1660         } else {
1661           GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1662           ret = GST_FLOW_ERROR;
1663         }
1664       }
1665
1666       self->drained = TRUE;
1667       self->draining = FALSE;
1668       g_mutex_unlock (&self->drain_lock);
1669       GST_VIDEO_ENCODER_STREAM_LOCK (self);
1670     } else {
1671       GST_ERROR_OBJECT (self, "Failed to get buffer for EOS: %d", idx);
1672       if (err)
1673         GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1674       ret = GST_FLOW_ERROR;
1675     }
1676   } else {
1677     GST_ERROR_OBJECT (self, "Failed to acquire buffer for EOS: %d", idx);
1678     if (err)
1679       GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1680     ret = GST_FLOW_ERROR;
1681   }
1682
1683   return ret;
1684 }