2 * Initially based on gst-plugins-bad/sys/androidmedia/gstamcvideodec.c
4 * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
5 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
7 * Copyright (C) 2012, Collabora Ltd.
8 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
10 * Copyright (C) 2013, Lemote Ltd.
11 * Author: Chen Jie <chenj@lemote.com>
13 * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
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.
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.
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
41 #define orc_memcpy memcpy
45 #include "gstjniutils.h"
48 #include "gstamcvideoenc.h"
49 #include "gstamc-constants.h"
51 GST_DEBUG_CATEGORY_STATIC (gst_amc_video_enc_debug_category);
52 #define GST_CAT_DEFAULT gst_amc_video_enc_debug_category
54 typedef struct _BufferIdentification BufferIdentification;
55 struct _BufferIdentification
60 static BufferIdentification *
61 buffer_identification_new (GstClockTime timestamp)
63 BufferIdentification *id = g_slice_new (BufferIdentification);
65 id->timestamp = timestamp;
71 buffer_identification_free (BufferIdentification * id)
73 g_slice_free (BufferIdentification, id);
77 static void gst_amc_video_enc_finalize (GObject * object);
79 static GstStateChangeReturn
80 gst_amc_video_enc_change_state (GstElement * element,
81 GstStateChange transition);
83 static gboolean gst_amc_video_enc_open (GstVideoEncoder * encoder);
84 static gboolean gst_amc_video_enc_close (GstVideoEncoder * encoder);
85 static gboolean gst_amc_video_enc_start (GstVideoEncoder * encoder);
86 static gboolean gst_amc_video_enc_stop (GstVideoEncoder * encoder);
87 static gboolean gst_amc_video_enc_set_format (GstVideoEncoder * encoder,
88 GstVideoCodecState * state);
89 static gboolean gst_amc_video_enc_flush (GstVideoEncoder * encoder);
90 static GstFlowReturn gst_amc_video_enc_handle_frame (GstVideoEncoder * encoder,
91 GstVideoCodecFrame * frame);
92 static GstFlowReturn gst_amc_video_enc_finish (GstVideoEncoder * encoder);
94 static GstFlowReturn gst_amc_video_enc_drain (GstAmcVideoEnc * self);
96 #define BIT_RATE_DEFAULT (2 * 1024 * 1024)
97 #define I_FRAME_INTERVAL_DEFAULT 0
102 PROP_I_FRAME_INTERVAL,
103 PROP_I_FRAME_INTERVAL_FLOAT
106 /* class initialization */
108 static void gst_amc_video_enc_class_init (GstAmcVideoEncClass * klass);
109 static void gst_amc_video_enc_init (GstAmcVideoEnc * self);
110 static void gst_amc_video_enc_base_init (gpointer g_class);
112 static GstVideoEncoderClass *parent_class = NULL;
115 gst_amc_video_enc_get_type (void)
117 static gsize type = 0;
119 if (g_once_init_enter (&type)) {
121 static const GTypeInfo info = {
122 sizeof (GstAmcVideoEncClass),
123 gst_amc_video_enc_base_init,
125 (GClassInitFunc) gst_amc_video_enc_class_init,
128 sizeof (GstAmcVideoEnc),
130 (GInstanceInitFunc) gst_amc_video_enc_init,
134 _type = g_type_register_static (GST_TYPE_VIDEO_ENCODER, "GstAmcVideoEnc",
137 GST_DEBUG_CATEGORY_INIT (gst_amc_video_enc_debug_category, "amcvideoenc", 0,
138 "Android MediaCodec video encoder");
140 g_once_init_leave (&type, _type);
145 static GstAmcFormat *
146 create_amc_format (GstAmcVideoEnc * encoder, GstVideoCodecState * input_state,
149 GstAmcVideoEncClass *klass;
152 const gchar *mime = NULL;
153 const gchar *profile_string = NULL;
154 const gchar *level_string = NULL;
168 gint stride, slice_height;
169 GstAmcFormat *format = NULL;
170 GstVideoInfo *info = &input_state->info;
173 klass = GST_AMC_VIDEO_ENC_GET_CLASS (encoder);
174 s = gst_caps_get_structure (src_caps, 0);
178 name = gst_structure_get_name (s);
179 profile_string = gst_structure_get_string (s, "profile");
180 level_string = gst_structure_get_string (s, "level");
182 if (strcmp (name, "video/mpeg") == 0) {
185 if (!gst_structure_get_int (s, "mpegversion", &mpegversion))
188 if (mpegversion == 4) {
189 mime = "video/mp4v-es";
191 if (profile_string) {
192 amc_profile.key = "profile"; /* named profile ? */
193 amc_profile.id = gst_amc_mpeg4_profile_from_string (profile_string);
197 amc_level.key = "level"; /* named level ? */
198 amc_level.id = gst_amc_mpeg4_level_from_string (level_string);
200 } else if ( /* mpegversion == 1 || */ mpegversion == 2)
201 mime = "video/mpeg2";
202 } else if (strcmp (name, "video/x-h263") == 0) {
204 } else if (strcmp (name, "video/x-h264") == 0) {
207 if (profile_string) {
208 amc_profile.key = "profile"; /* named profile ? */
209 amc_profile.id = gst_amc_avc_profile_from_string (profile_string);
213 amc_level.key = "level"; /* named level ? */
214 amc_level.id = gst_amc_avc_level_from_string (level_string);
216 } else if (strcmp (name, "video/x-vp8") == 0) {
217 mime = "video/x-vnd.on2.vp8";
218 } else if (strcmp (name, "video/x-vp9") == 0) {
219 mime = "video/x-vnd.on2.vp9";
221 GST_ERROR_OBJECT (encoder, "Failed to convert caps(%s/...) to any mime",
226 format = gst_amc_format_new_video (mime, info->width, info->height, &err);
228 GST_ERROR_OBJECT (encoder, "Failed to create a \"%s,%dx%d\" MediaFormat",
229 mime, info->width, info->height);
230 GST_ELEMENT_ERROR_FROM_ERROR (encoder, err);
235 gst_amc_video_format_to_color_format (klass->codec_info,
236 mime, info->finfo->format);
237 if (color_format == -1)
238 goto video_format_failed_to_convert;
240 gst_amc_format_set_int (format, "bitrate", encoder->bitrate, &err);
242 GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
243 gst_amc_format_set_int (format, "color-format", color_format, &err);
245 GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
246 stride = GST_ROUND_UP_4 (info->width); /* safe (?) */
247 gst_amc_format_set_int (format, "stride", stride, &err);
249 GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
250 slice_height = info->height;
251 gst_amc_format_set_int (format, "slice-height", slice_height, &err);
253 GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
255 if (profile_string) {
256 if (amc_profile.id == -1)
257 goto unsupported_profile;
259 /* FIXME: Set to any value in AVCProfile* leads to
260 * codec configuration fail */
261 /* gst_amc_format_set_int (format, amc_profile.key, 0x40); */
265 if (amc_level.id == -1)
266 goto unsupported_level;
268 /* gst_amc_format_set_int (format, amc_level.key, amc_level.id); */
271 /* On Android N_MR1 and higher, i-frame-interval can be a float value */
273 if (gst_amc_jni_get_android_level () >= 25) {
274 GST_LOG_OBJECT (encoder, "Setting i-frame-interval to %f",
275 encoder->i_frame_int);
276 gst_amc_format_set_float (format, "i-frame-interval", encoder->i_frame_int,
281 int i_frame_int = encoder->i_frame_int;
282 /* Round a fractional interval to 1 per sec on older Android */
283 if (encoder->i_frame_int > 0 && encoder->i_frame_int < 1.0)
285 gst_amc_format_set_int (format, "i-frame-interval", i_frame_int, &err);
288 GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
291 gst_amc_format_set_float (format, "frame-rate",
292 ((gfloat) info->fps_n) / info->fps_d, &err);
294 GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
296 encoder->format = info->finfo->format;
297 if (!gst_amc_color_format_info_set (&encoder->color_format_info,
298 klass->codec_info, mime, color_format, info->width, info->height,
299 stride, slice_height, 0, 0, 0, 0))
300 goto color_format_info_failed_to_set;
302 GST_DEBUG_OBJECT (encoder,
303 "Color format info: {color_format=%d, width=%d, height=%d, "
304 "stride=%d, slice-height=%d, crop-left=%d, crop-top=%d, "
305 "crop-right=%d, crop-bottom=%d, frame-size=%d}",
306 encoder->color_format_info.color_format, encoder->color_format_info.width,
307 encoder->color_format_info.height, encoder->color_format_info.stride,
308 encoder->color_format_info.slice_height,
309 encoder->color_format_info.crop_left, encoder->color_format_info.crop_top,
310 encoder->color_format_info.crop_right,
311 encoder->color_format_info.crop_bottom,
312 encoder->color_format_info.frame_size);
316 video_format_failed_to_convert:
317 GST_ERROR_OBJECT (encoder, "Failed to convert video format");
318 gst_amc_format_free (format);
321 color_format_info_failed_to_set:
322 GST_ERROR_OBJECT (encoder, "Failed to set up GstAmcColorFormatInfo");
323 gst_amc_format_free (format);
327 GST_ERROR_OBJECT (encoder, "Unsupported profile '%s'", profile_string);
328 gst_amc_format_free (format);
332 GST_ERROR_OBJECT (encoder, "Unsupported level '%s'", level_string);
333 gst_amc_format_free (format);
338 caps_from_amc_format (GstAmcFormat * amc_format)
340 GstCaps *caps = NULL;
343 gint amc_profile, amc_level;
344 gfloat frame_rate = 0.0;
345 gint fraction_n, fraction_d;
348 if (!gst_amc_format_get_string (amc_format, "mime", &mime, &err)) {
349 GST_ERROR ("Failed to get 'mime': %s", err->message);
350 g_clear_error (&err);
354 if (!gst_amc_format_get_int (amc_format, "width", &width, &err) ||
355 !gst_amc_format_get_int (amc_format, "height", &height, &err)) {
356 GST_ERROR ("Failed to get size: %s", err->message);
357 g_clear_error (&err);
363 gst_amc_format_get_float (amc_format, "frame-rate", &frame_rate, NULL);
364 gst_util_double_to_fraction (frame_rate, &fraction_n, &fraction_d);
366 if (strcmp (mime, "video/mp4v-es") == 0) {
367 const gchar *profile_string, *level_string;
370 gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
371 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
373 if (gst_amc_format_get_int (amc_format, "profile", &amc_profile, NULL)) {
374 profile_string = gst_amc_mpeg4_profile_to_string (amc_profile);
376 goto unsupported_profile;
378 gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile_string,
382 if (gst_amc_format_get_int (amc_format, "level", &amc_level, NULL)) {
383 level_string = gst_amc_mpeg4_level_to_string (amc_profile);
385 goto unsupported_level;
387 gst_caps_set_simple (caps, "level", G_TYPE_STRING, level_string, NULL);
390 } else if (strcmp (mime, "video/mpeg2") == 0) {
391 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", 2, NULL);
392 } else if (strcmp (mime, "video/3gpp") == 0) {
393 caps = gst_caps_new_empty_simple ("video/x-h263");
394 } else if (strcmp (mime, "video/avc") == 0) {
395 const gchar *profile_string, *level_string;
398 gst_caps_new_simple ("video/x-h264",
399 "stream-format", G_TYPE_STRING, "byte-stream", NULL);
401 if (gst_amc_format_get_int (amc_format, "profile", &amc_profile, NULL)) {
402 profile_string = gst_amc_avc_profile_to_string (amc_profile, NULL);
404 goto unsupported_profile;
406 gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile_string,
410 if (gst_amc_format_get_int (amc_format, "level", &amc_level, NULL)) {
411 level_string = gst_amc_avc_level_to_string (amc_profile);
413 goto unsupported_level;
415 gst_caps_set_simple (caps, "level", G_TYPE_STRING, level_string, NULL);
417 } else if (strcmp (mime, "video/x-vnd.on2.vp8") == 0) {
418 caps = gst_caps_new_empty_simple ("video/x-vp8");
419 } else if (strcmp (mime, "video/x-vnd.on2.vp9") == 0) {
420 caps = gst_caps_new_empty_simple ("video/x-vp9");
423 gst_caps_set_simple (caps, "width", G_TYPE_INT, width,
424 "height", G_TYPE_INT, height,
425 "framerate", GST_TYPE_FRACTION, fraction_n, fraction_d, NULL);
431 GST_ERROR ("Unsupported amc profile id %d", amc_profile);
433 gst_caps_unref (caps);
438 GST_ERROR ("Unsupported amc level id %d", amc_level);
440 gst_caps_unref (caps);
446 gst_amc_video_enc_base_init (gpointer g_class)
448 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
449 GstAmcVideoEncClass *videoenc_class = GST_AMC_VIDEO_ENC_CLASS (g_class);
450 const GstAmcCodecInfo *codec_info;
451 GstPadTemplate *templ;
452 GstCaps *sink_caps, *src_caps;
456 g_type_get_qdata (G_TYPE_FROM_CLASS (g_class), gst_amc_codec_info_quark);
457 /* This happens for the base class and abstract subclasses */
461 videoenc_class->codec_info = codec_info;
463 gst_amc_codec_info_to_caps (codec_info, &sink_caps, &src_caps);
464 /* Add pad templates */
466 gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
467 gst_element_class_add_pad_template (element_class, templ);
468 gst_caps_unref (sink_caps);
470 templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps);
471 gst_element_class_add_pad_template (element_class, templ);
472 gst_caps_unref (src_caps);
474 longname = g_strdup_printf ("Android MediaCodec %s", codec_info->name);
475 gst_element_class_set_metadata (element_class,
477 "Codec/Encoder/Video/Hardware",
478 longname, "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
483 gst_amc_video_enc_set_property (GObject * object, guint prop_id,
484 const GValue * value, GParamSpec * pspec)
486 GstAmcVideoEnc *encoder;
488 gboolean codec_active;
491 encoder = GST_AMC_VIDEO_ENC (object);
493 GST_OBJECT_LOCK (encoder);
495 state = GST_STATE (encoder);
496 codec_active = (encoder->codec && state != GST_STATE_READY
497 && state != GST_STATE_NULL);
501 encoder->bitrate = g_value_get_uint (value);
503 g_mutex_lock (&encoder->codec_lock);
504 if (encoder->codec) {
505 if (!gst_amc_codec_set_dynamic_bitrate (encoder->codec, &err,
507 g_mutex_unlock (&encoder->codec_lock);
511 g_mutex_unlock (&encoder->codec_lock);
513 GST_ELEMENT_WARNING_FROM_ERROR (encoder, err);
514 g_clear_error (&err);
518 case PROP_I_FRAME_INTERVAL:
519 encoder->i_frame_int = g_value_get_uint (value);
523 case PROP_I_FRAME_INTERVAL_FLOAT:
524 encoder->i_frame_int = g_value_get_float (value);
529 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
532 GST_OBJECT_UNLOCK (encoder);
538 GST_WARNING_OBJECT (encoder, "setting property in wrong state");
539 GST_OBJECT_UNLOCK (encoder);
544 gst_amc_video_enc_get_property (GObject * object, guint prop_id,
545 GValue * value, GParamSpec * pspec)
547 GstAmcVideoEnc *encoder;
549 encoder = GST_AMC_VIDEO_ENC (object);
551 GST_OBJECT_LOCK (encoder);
554 g_value_set_uint (value, encoder->bitrate);
556 case PROP_I_FRAME_INTERVAL:
557 g_value_set_uint (value, encoder->i_frame_int);
559 case PROP_I_FRAME_INTERVAL_FLOAT:
560 g_value_set_float (value, encoder->i_frame_int);
563 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
566 GST_OBJECT_UNLOCK (encoder);
571 gst_amc_video_enc_class_init (GstAmcVideoEncClass * klass)
573 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
574 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
575 GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
576 GParamFlags dynamic_flag = 0;
578 parent_class = g_type_class_peek_parent (klass);
580 gobject_class->set_property = gst_amc_video_enc_set_property;
581 gobject_class->get_property = gst_amc_video_enc_get_property;
582 gobject_class->finalize = gst_amc_video_enc_finalize;
584 element_class->change_state =
585 GST_DEBUG_FUNCPTR (gst_amc_video_enc_change_state);
587 videoenc_class->start = GST_DEBUG_FUNCPTR (gst_amc_video_enc_start);
588 videoenc_class->stop = GST_DEBUG_FUNCPTR (gst_amc_video_enc_stop);
589 videoenc_class->open = GST_DEBUG_FUNCPTR (gst_amc_video_enc_open);
590 videoenc_class->close = GST_DEBUG_FUNCPTR (gst_amc_video_enc_close);
591 videoenc_class->flush = GST_DEBUG_FUNCPTR (gst_amc_video_enc_flush);
592 videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_amc_video_enc_set_format);
593 videoenc_class->handle_frame =
594 GST_DEBUG_FUNCPTR (gst_amc_video_enc_handle_frame);
595 videoenc_class->finish = GST_DEBUG_FUNCPTR (gst_amc_video_enc_finish);
597 // On Android >= 19, we can set bitrate dynamically
598 // so add the flag so apps can detect it.
599 if (gst_amc_codec_have_dynamic_bitrate ())
600 dynamic_flag = GST_PARAM_MUTABLE_PLAYING;
602 g_object_class_install_property (gobject_class, PROP_BIT_RATE,
603 g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in bit/sec", 1,
604 G_MAXINT, BIT_RATE_DEFAULT,
605 dynamic_flag | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
607 g_object_class_install_property (gobject_class, PROP_I_FRAME_INTERVAL,
608 g_param_spec_uint ("i-frame-interval", "I-frame interval",
609 "The frequency of I frames expressed in seconds between I frames (0 for automatic)",
610 0, G_MAXINT, I_FRAME_INTERVAL_DEFAULT,
611 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
613 g_object_class_install_property (gobject_class, PROP_I_FRAME_INTERVAL_FLOAT,
614 g_param_spec_float ("i-frame-interval-float", "I-frame interval",
615 "The frequency of I frames expressed in seconds between I frames (0 for automatic). "
616 "Fractional intervals work on Android >= 25",
617 0, G_MAXFLOAT, I_FRAME_INTERVAL_DEFAULT,
618 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
622 gst_amc_video_enc_init (GstAmcVideoEnc * self)
624 g_mutex_init (&self->codec_lock);
625 g_mutex_init (&self->drain_lock);
626 g_cond_init (&self->drain_cond);
628 self->bitrate = BIT_RATE_DEFAULT;
629 self->i_frame_int = I_FRAME_INTERVAL_DEFAULT;
633 gst_amc_video_enc_open (GstVideoEncoder * encoder)
635 GstAmcVideoEnc *self = GST_AMC_VIDEO_ENC (encoder);
636 GstAmcVideoEncClass *klass = GST_AMC_VIDEO_ENC_GET_CLASS (self);
639 GST_DEBUG_OBJECT (self, "Opening encoder");
641 g_mutex_lock (&self->codec_lock);
642 self->codec = gst_amc_codec_new (klass->codec_info->name, TRUE, &err);
644 g_mutex_unlock (&self->codec_lock);
645 GST_ELEMENT_ERROR_FROM_ERROR (self, err);
648 g_mutex_unlock (&self->codec_lock);
649 self->started = FALSE;
650 self->flushing = TRUE;
652 GST_DEBUG_OBJECT (self, "Opened encoder");
658 gst_amc_video_enc_close (GstVideoEncoder * encoder)
660 GstAmcVideoEnc *self = GST_AMC_VIDEO_ENC (encoder);
662 GST_DEBUG_OBJECT (self, "Closing encoder");
664 g_mutex_lock (&self->codec_lock);
668 gst_amc_codec_release (self->codec, &err);
670 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
672 gst_amc_codec_free (self->codec);
675 g_mutex_unlock (&self->codec_lock);
677 self->started = FALSE;
678 self->flushing = TRUE;
680 GST_DEBUG_OBJECT (self, "Closed encoder");
686 gst_amc_video_enc_finalize (GObject * object)
688 GstAmcVideoEnc *self = GST_AMC_VIDEO_ENC (object);
690 g_mutex_clear (&self->codec_lock);
691 g_mutex_clear (&self->drain_lock);
692 g_cond_clear (&self->drain_cond);
694 G_OBJECT_CLASS (parent_class)->finalize (object);
697 static GstStateChangeReturn
698 gst_amc_video_enc_change_state (GstElement * element, GstStateChange transition)
700 GstAmcVideoEnc *self;
701 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
704 g_return_val_if_fail (GST_IS_AMC_VIDEO_ENC (element),
705 GST_STATE_CHANGE_FAILURE);
706 self = GST_AMC_VIDEO_ENC (element);
708 switch (transition) {
709 case GST_STATE_CHANGE_NULL_TO_READY:
711 case GST_STATE_CHANGE_READY_TO_PAUSED:
712 self->downstream_flow_ret = GST_FLOW_OK;
713 self->draining = FALSE;
714 self->started = FALSE;
716 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
718 case GST_STATE_CHANGE_PAUSED_TO_READY:
719 self->flushing = TRUE;
720 gst_amc_codec_flush (self->codec, &err);
722 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
723 g_mutex_lock (&self->drain_lock);
724 self->draining = FALSE;
725 g_cond_broadcast (&self->drain_cond);
726 g_mutex_unlock (&self->drain_lock);
732 if (ret == GST_STATE_CHANGE_FAILURE)
735 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
737 if (ret == GST_STATE_CHANGE_FAILURE)
740 switch (transition) {
741 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
743 case GST_STATE_CHANGE_PAUSED_TO_READY:
744 self->downstream_flow_ret = GST_FLOW_FLUSHING;
745 self->started = FALSE;
747 case GST_STATE_CHANGE_READY_TO_NULL:
756 #define MAX_FRAME_DIST_TIME (5 * GST_SECOND)
757 #define MAX_FRAME_DIST_FRAMES (100)
759 static GstVideoCodecFrame *
760 _find_nearest_frame (GstAmcVideoEnc * self, GstClockTime reference_timestamp)
762 GList *l, *best_l = NULL;
763 GList *finish_frames = NULL;
764 GstVideoCodecFrame *best = NULL;
765 guint64 best_timestamp = 0;
766 guint64 best_diff = G_MAXUINT64;
767 BufferIdentification *best_id = NULL;
770 frames = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (self));
772 for (l = frames; l; l = l->next) {
773 GstVideoCodecFrame *tmp = l->data;
774 BufferIdentification *id = gst_video_codec_frame_get_user_data (tmp);
775 guint64 timestamp, diff;
777 /* This happens for frames that were just added but
778 * which were not passed to the component yet. Ignore
784 timestamp = id->timestamp;
786 if (timestamp > reference_timestamp)
787 diff = timestamp - reference_timestamp;
789 diff = reference_timestamp - timestamp;
791 if (best == NULL || diff < best_diff) {
793 best_timestamp = timestamp;
798 /* For frames without timestamp we simply take the first frame */
799 if ((reference_timestamp == 0 && !GST_CLOCK_TIME_IS_VALID (timestamp))
806 for (l = frames; l && l != best_l; l = l->next) {
807 GstVideoCodecFrame *tmp = l->data;
808 BufferIdentification *id = gst_video_codec_frame_get_user_data (tmp);
809 guint64 diff_time, diff_frames;
811 if (id->timestamp > best_timestamp)
814 if (id->timestamp == 0 || best_timestamp == 0)
817 diff_time = best_timestamp - id->timestamp;
818 diff_frames = best->system_frame_number - tmp->system_frame_number;
820 if (diff_time > MAX_FRAME_DIST_TIME
821 || diff_frames > MAX_FRAME_DIST_FRAMES) {
823 g_list_prepend (finish_frames, gst_video_codec_frame_ref (tmp));
829 g_warning ("%s: Too old frames, bug in encoder -- please file a bug",
830 GST_ELEMENT_NAME (self));
831 for (l = finish_frames; l; l = l->next) {
832 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), l->data);
837 gst_video_codec_frame_ref (best);
839 g_list_foreach (frames, (GFunc) gst_video_codec_frame_unref, NULL);
840 g_list_free (frames);
846 gst_amc_video_enc_set_src_caps (GstAmcVideoEnc * self, GstAmcFormat * format)
849 GstVideoCodecState *output_state;
851 caps = caps_from_amc_format (format);
853 GST_ERROR_OBJECT (self, "Failed to create output caps");
857 /* It may not be proper to reference self->input_state here,
858 * because MediaCodec is an async model -- input_state may change multiple times,
859 * the passed-in MediaFormat may not be the one matched to the current input_state.
861 * Though, currently, the final src caps only calculate
862 * width/height/pixel-aspect-ratio/framerate/codec_data from self->input_state.
864 * If input width/height/codec_data change(is_format_change), it will restart
865 * MediaCodec, which means in these cases, self->input_state is matched.
867 output_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
868 caps, self->input_state);
869 gst_video_codec_state_unref (output_state);
871 if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self)))
877 /* The weird handling of cropping, alignment and everything is taken from
878 * platform/frameworks/media/libstagefright/colorconversion/ColorConversion.cpp
881 gst_amc_video_enc_fill_buffer (GstAmcVideoEnc * self, GstBuffer * inbuf,
882 GstAmcBuffer * outbuf, const GstAmcBufferInfo * buffer_info)
884 GstVideoCodecState *input_state = self->input_state;
885 /* The fill_buffer runs in the same thread as set_format?
886 * then we can use state->info safely */
887 GstVideoInfo *info = &input_state->info;
889 if (buffer_info->size < self->color_format_info.frame_size)
892 return gst_amc_color_format_copy (&self->color_format_info, outbuf,
893 buffer_info, info, inbuf, COLOR_FORMAT_COPY_IN);
897 gst_amc_video_enc_handle_output_frame (GstAmcVideoEnc * self,
898 GstAmcBuffer * buf, const GstAmcBufferInfo * buffer_info,
899 GstVideoCodecFrame * frame)
901 GstFlowReturn flow_ret = GST_FLOW_OK;
902 GstVideoEncoder *encoder = GST_VIDEO_ENCODER_CAST (self);
904 /* The BUFFER_FLAG_CODEC_CONFIG logic is borrowed from
905 * gst-omx. see *_handle_output_frame in
906 * gstomxvideoenc.c and gstomxh264enc.c */
907 if ((buffer_info->flags & BUFFER_FLAG_CODEC_CONFIG)
908 && buffer_info->size > 0) {
910 GstVideoCodecState *state;
912 state = gst_video_encoder_get_output_state (encoder);
913 s = gst_caps_get_structure (state->caps, 0);
914 if (!strcmp (gst_structure_get_name (s), "video/x-h264")) {
915 gst_video_codec_state_unref (state);
917 if (buffer_info->size > 4 &&
918 GST_READ_UINT32_BE (buf->data + buffer_info->offset) == 0x00000001) {
922 GST_DEBUG_OBJECT (self, "got codecconfig in byte-stream format");
924 hdrs = gst_buffer_new_and_alloc (buffer_info->size);
925 gst_buffer_fill (hdrs, 0, buf->data + buffer_info->offset,
927 GST_BUFFER_PTS (hdrs) =
928 gst_util_uint64_scale (buffer_info->presentation_time_us,
931 l = g_list_append (l, hdrs);
932 gst_video_encoder_set_headers (encoder, l);
935 GstBuffer *codec_data;
937 GST_DEBUG_OBJECT (self, "Handling codec data");
939 codec_data = gst_buffer_new_and_alloc (buffer_info->size);
940 gst_buffer_fill (codec_data, 0, buf->data + buffer_info->offset,
942 state->codec_data = codec_data;
943 gst_video_codec_state_unref (state);
945 if (!gst_video_encoder_negotiate (encoder)) {
946 gst_video_codec_frame_unref (frame);
947 return GST_FLOW_NOT_NEGOTIATED;
954 if (buffer_info->size > 0) {
958 srcpad = GST_VIDEO_ENCODER_SRC_PAD (encoder);
960 gst_video_encoder_allocate_output_buffer (encoder, buffer_info->size);
961 gst_buffer_fill (out_buf, 0, buf->data + buffer_info->offset,
964 GST_BUFFER_PTS (out_buf) =
965 gst_util_uint64_scale (buffer_info->presentation_time_us, GST_USECOND,
969 frame->output_buffer = out_buf;
970 flow_ret = gst_video_encoder_finish_frame (encoder, frame);
972 /* This sometimes happens at EOS or if the input is not properly framed,
973 * let's handle it gracefully by allocating a new buffer for the current
974 * caps and filling it
977 GST_ERROR_OBJECT (self, "No corresponding frame found");
978 flow_ret = gst_pad_push (srcpad, out_buf);
981 flow_ret = gst_video_encoder_finish_frame (encoder, frame);
988 gst_amc_video_enc_loop (GstAmcVideoEnc * self)
990 GstVideoCodecFrame *frame;
991 GstFlowReturn flow_ret = GST_FLOW_OK;
993 GstAmcBufferInfo buffer_info;
998 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1001 GST_DEBUG_OBJECT (self, "Waiting for available output buffer");
1002 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1003 /* Wait at most 100ms here, some codecs don't fail dequeueing if
1004 * the codec is flushing, causing deadlocks during shutdown */
1006 gst_amc_codec_dequeue_output_buffer (self->codec, &buffer_info, 100000,
1008 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1011 if (idx < 0 || self->amc_format) {
1012 if (self->flushing) {
1013 g_clear_error (&err);
1017 /* The comments from https://android.googlesource.com/platform/cts/+/android-4.3_r3.1/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
1018 * line 539 says INFO_OUTPUT_FORMAT_CHANGED is not expected for an encoder
1020 if (self->amc_format || idx == INFO_OUTPUT_FORMAT_CHANGED) {
1021 GstAmcFormat *format;
1022 gchar *format_string;
1024 GST_DEBUG_OBJECT (self, "Output format has changed");
1026 format = (idx == INFO_OUTPUT_FORMAT_CHANGED) ?
1027 gst_amc_codec_get_output_format (self->codec,
1028 &err) : self->amc_format;
1030 format = self->amc_format;
1031 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1034 if (self->amc_format) {
1035 if (format != self->amc_format)
1036 gst_amc_format_free (self->amc_format);
1037 self->amc_format = NULL;
1043 format_string = gst_amc_format_to_string (format, &err);
1045 gst_amc_format_free (format);
1048 GST_DEBUG_OBJECT (self, "Got new output format: %s", format_string);
1049 g_free (format_string);
1051 if (!gst_amc_video_enc_set_src_caps (self, format)) {
1052 gst_amc_format_free (format);
1056 gst_amc_format_free (format);
1059 goto process_buffer;
1065 case INFO_OUTPUT_BUFFERS_CHANGED:
1066 /* Handled internally */
1067 g_assert_not_reached ();
1069 case INFO_TRY_AGAIN_LATER:
1070 GST_DEBUG_OBJECT (self, "Dequeueing output buffer timed out");
1074 GST_ERROR_OBJECT (self, "Failure dequeueing input buffer");
1078 g_assert_not_reached ();
1086 GST_DEBUG_OBJECT (self,
1087 "Got output buffer at index %d: size %d time %" G_GINT64_FORMAT
1088 " flags 0x%08x", idx, buffer_info.size, buffer_info.presentation_time_us,
1091 buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err);
1093 if (self->flushing) {
1094 g_clear_error (&err);
1097 goto failed_to_get_output_buffer;
1099 goto got_null_output_buffer;
1103 _find_nearest_frame (self,
1104 gst_util_uint64_scale (buffer_info.presentation_time_us, GST_USECOND, 1));
1106 is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM);
1109 gst_amc_video_enc_handle_output_frame (self, buf, &buffer_info, frame);
1111 gst_amc_buffer_free (buf);
1114 if (!gst_amc_codec_release_output_buffer (self->codec, idx, FALSE, &err)) {
1115 if (self->flushing) {
1116 g_clear_error (&err);
1119 goto failed_release;
1122 if (is_eos || flow_ret == GST_FLOW_EOS) {
1123 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1124 g_mutex_lock (&self->drain_lock);
1125 if (self->draining) {
1126 GST_DEBUG_OBJECT (self, "Drained");
1127 self->draining = FALSE;
1128 g_cond_broadcast (&self->drain_cond);
1129 } else if (flow_ret == GST_FLOW_OK) {
1130 GST_DEBUG_OBJECT (self, "Component signalled EOS");
1131 flow_ret = GST_FLOW_EOS;
1133 g_mutex_unlock (&self->drain_lock);
1134 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1136 GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
1139 self->downstream_flow_ret = flow_ret;
1141 if (flow_ret != GST_FLOW_OK)
1144 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1150 GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1151 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1152 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1153 self->downstream_flow_ret = GST_FLOW_ERROR;
1154 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1155 g_mutex_lock (&self->drain_lock);
1156 self->draining = FALSE;
1157 g_cond_broadcast (&self->drain_cond);
1158 g_mutex_unlock (&self->drain_lock);
1165 GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1167 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1168 ("Failed to handle format"));
1169 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1170 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1171 self->downstream_flow_ret = GST_FLOW_ERROR;
1172 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1173 g_mutex_lock (&self->drain_lock);
1174 self->draining = FALSE;
1175 g_cond_broadcast (&self->drain_cond);
1176 g_mutex_unlock (&self->drain_lock);
1181 GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1182 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1183 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1184 self->downstream_flow_ret = GST_FLOW_ERROR;
1185 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1186 g_mutex_lock (&self->drain_lock);
1187 self->draining = FALSE;
1188 g_cond_broadcast (&self->drain_cond);
1189 g_mutex_unlock (&self->drain_lock);
1194 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1195 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1196 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1197 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1203 if (flow_ret == GST_FLOW_EOS) {
1204 GST_DEBUG_OBJECT (self, "EOS");
1205 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
1206 gst_event_new_eos ());
1207 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1208 } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) {
1209 GST_ELEMENT_FLOW_ERROR (self, flow_ret);
1210 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
1211 gst_event_new_eos ());
1212 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1214 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1215 g_mutex_lock (&self->drain_lock);
1216 self->draining = FALSE;
1217 g_cond_broadcast (&self->drain_cond);
1218 g_mutex_unlock (&self->drain_lock);
1222 failed_to_get_output_buffer:
1224 GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1225 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1226 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1227 self->downstream_flow_ret = GST_FLOW_ERROR;
1228 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1229 g_mutex_lock (&self->drain_lock);
1230 self->draining = FALSE;
1231 g_cond_broadcast (&self->drain_cond);
1232 g_mutex_unlock (&self->drain_lock);
1236 got_null_output_buffer:
1238 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1239 ("Got no output buffer"));
1240 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
1241 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
1242 self->downstream_flow_ret = GST_FLOW_ERROR;
1243 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1244 g_mutex_lock (&self->drain_lock);
1245 self->draining = FALSE;
1246 g_cond_broadcast (&self->drain_cond);
1247 g_mutex_unlock (&self->drain_lock);
1253 gst_amc_video_enc_start (GstVideoEncoder * encoder)
1255 GstAmcVideoEnc *self;
1257 self = GST_AMC_VIDEO_ENC (encoder);
1258 self->last_upstream_ts = 0;
1259 self->drained = TRUE;
1260 self->downstream_flow_ret = GST_FLOW_OK;
1261 self->started = FALSE;
1262 self->flushing = TRUE;
1268 gst_amc_video_enc_stop (GstVideoEncoder * encoder)
1270 GstAmcVideoEnc *self;
1273 self = GST_AMC_VIDEO_ENC (encoder);
1274 GST_DEBUG_OBJECT (self, "Stopping encoder");
1275 self->flushing = TRUE;
1276 if (self->started) {
1277 gst_amc_codec_flush (self->codec, &err);
1279 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1280 gst_amc_codec_stop (self->codec, &err);
1282 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1283 self->started = FALSE;
1285 gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1287 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1288 self->drained = TRUE;
1289 g_mutex_lock (&self->drain_lock);
1290 self->draining = FALSE;
1291 g_cond_broadcast (&self->drain_cond);
1292 g_mutex_unlock (&self->drain_lock);
1293 if (self->input_state)
1294 gst_video_codec_state_unref (self->input_state);
1295 self->input_state = NULL;
1297 if (self->amc_format) {
1298 gst_amc_format_free (self->amc_format);
1299 self->amc_format = NULL;
1302 GST_DEBUG_OBJECT (self, "Stopped encoder");
1307 gst_amc_video_enc_set_format (GstVideoEncoder * encoder,
1308 GstVideoCodecState * state)
1310 GstAmcVideoEnc *self;
1311 GstAmcFormat *format = NULL;
1312 GstCaps *allowed_caps = NULL;
1313 gboolean is_format_change = FALSE;
1314 gboolean needs_disable = FALSE;
1315 gchar *format_string;
1319 self = GST_AMC_VIDEO_ENC (encoder);
1321 GST_DEBUG_OBJECT (self, "Setting new caps %" GST_PTR_FORMAT, state->caps);
1323 /* Check if the caps change is a real format change or if only irrelevant
1324 * parts of the caps have changed or nothing at all.
1326 is_format_change |= self->color_format_info.width != state->info.width;
1327 is_format_change |= self->color_format_info.height != state->info.height;
1328 needs_disable = self->started;
1330 /* If the component is not started and a real format change happens
1331 * we have to restart the component. If no real format change
1332 * happened we can just exit here.
1334 if (needs_disable && !is_format_change) {
1336 /* Framerate or something minor changed */
1337 if (self->input_state)
1338 gst_video_codec_state_unref (self->input_state);
1339 self->input_state = gst_video_codec_state_ref (state);
1340 GST_DEBUG_OBJECT (self,
1341 "Already running and caps did not change the format");
1345 if (needs_disable && is_format_change) {
1346 gst_amc_video_enc_drain (self);
1347 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1348 gst_amc_video_enc_stop (GST_VIDEO_ENCODER (self));
1349 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1350 gst_amc_video_enc_close (GST_VIDEO_ENCODER (self));
1351 if (!gst_amc_video_enc_open (GST_VIDEO_ENCODER (self))) {
1352 GST_ERROR_OBJECT (self, "Failed to open codec again");
1356 if (!gst_amc_video_enc_start (GST_VIDEO_ENCODER (self))) {
1357 GST_ERROR_OBJECT (self, "Failed to start codec again");
1360 /* srcpad task is not running at this point */
1361 if (self->input_state)
1362 gst_video_codec_state_unref (self->input_state);
1363 self->input_state = NULL;
1365 GST_DEBUG_OBJECT (self, "picking an output format ...");
1366 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1367 if (!allowed_caps) {
1368 GST_DEBUG_OBJECT (self, "... but no peer, using template caps");
1370 gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1372 GST_DEBUG_OBJECT (self, "chose caps %" GST_PTR_FORMAT, allowed_caps);
1373 allowed_caps = gst_caps_truncate (allowed_caps);
1375 format = create_amc_format (self, state, allowed_caps);
1379 format_string = gst_amc_format_to_string (format, &err);
1381 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1382 GST_DEBUG_OBJECT (self, "Configuring codec with format: %s",
1383 GST_STR_NULL (format_string));
1384 g_free (format_string);
1386 if (!gst_amc_codec_configure (self->codec, format, NULL, &err)) {
1387 GST_ERROR_OBJECT (self, "Failed to configure codec");
1388 GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1392 if (!gst_amc_codec_start (self->codec, &err)) {
1393 GST_ERROR_OBJECT (self, "Failed to start codec");
1394 GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1398 self->amc_format = format;
1401 self->input_state = gst_video_codec_state_ref (state);
1403 self->started = TRUE;
1405 /* Start the srcpad loop again */
1406 self->flushing = FALSE;
1407 self->downstream_flow_ret = GST_FLOW_OK;
1408 gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
1409 (GstTaskFunction) gst_amc_video_enc_loop, encoder, NULL);
1415 gst_caps_unref (allowed_caps);
1418 gst_amc_format_free (format);
1424 gst_amc_video_enc_flush (GstVideoEncoder * encoder)
1426 GstAmcVideoEnc *self;
1429 self = GST_AMC_VIDEO_ENC (encoder);
1431 GST_DEBUG_OBJECT (self, "Flushing encoder");
1433 if (!self->started) {
1434 GST_DEBUG_OBJECT (self, "Codec not started yet");
1438 self->flushing = TRUE;
1439 gst_amc_codec_flush (self->codec, &err);
1441 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1443 /* Wait until the srcpad loop is finished,
1444 * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
1445 * caused by using this lock from inside the loop function */
1446 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1447 GST_PAD_STREAM_LOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
1448 GST_PAD_STREAM_UNLOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
1449 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1450 self->flushing = FALSE;
1452 /* Start the srcpad loop again */
1453 self->last_upstream_ts = 0;
1454 self->drained = TRUE;
1455 self->downstream_flow_ret = GST_FLOW_OK;
1456 gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
1457 (GstTaskFunction) gst_amc_video_enc_loop, encoder, NULL);
1459 GST_DEBUG_OBJECT (self, "Flush encoder");
1464 static GstFlowReturn
1465 gst_amc_video_enc_handle_frame (GstVideoEncoder * encoder,
1466 GstVideoCodecFrame * frame)
1468 GstAmcVideoEnc *self;
1471 GstAmcBufferInfo buffer_info;
1472 GstClockTime timestamp, duration, timestamp_offset = 0;
1473 BufferIdentification *id;
1476 self = GST_AMC_VIDEO_ENC (encoder);
1478 GST_DEBUG_OBJECT (self, "Handling frame");
1480 if (!self->started) {
1481 GST_ERROR_OBJECT (self, "Codec not started yet");
1482 gst_video_codec_frame_unref (frame);
1483 return GST_FLOW_NOT_NEGOTIATED;
1489 if (self->downstream_flow_ret != GST_FLOW_OK)
1490 goto downstream_error;
1492 timestamp = frame->pts;
1493 duration = frame->duration;
1495 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
1496 if (gst_amc_codec_request_key_frame (self->codec, &err)) {
1497 GST_DEBUG_OBJECT (self, "Passed keyframe request to MediaCodec");
1500 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1501 g_clear_error (&err);
1506 /* Make sure to release the base class stream lock, otherwise
1507 * _loop() can't call _finish_frame() and we might block forever
1508 * because no input buffers are released */
1509 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1510 /* Wait at most 100ms here, some codecs don't fail dequeueing if
1511 * the codec is flushing, causing deadlocks during shutdown */
1512 idx = gst_amc_codec_dequeue_input_buffer (self->codec, 100000, &err);
1513 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1516 if (self->flushing || self->downstream_flow_ret == GST_FLOW_FLUSHING) {
1517 g_clear_error (&err);
1522 case INFO_TRY_AGAIN_LATER:
1523 GST_DEBUG_OBJECT (self, "Dequeueing input buffer timed out");
1524 goto again; /* next try */
1527 GST_ERROR_OBJECT (self, "Failed to dequeue input buffer");
1530 g_assert_not_reached ();
1537 if (self->flushing) {
1538 memset (&buffer_info, 0, sizeof (buffer_info));
1539 gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, NULL);
1543 if (self->downstream_flow_ret != GST_FLOW_OK) {
1544 memset (&buffer_info, 0, sizeof (buffer_info));
1545 gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err);
1546 if (err && !self->flushing)
1547 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1548 g_clear_error (&err);
1549 goto downstream_error;
1552 /* Now handle the frame */
1554 /* Copy the buffer content in chunks of size as requested
1556 buf = gst_amc_codec_get_input_buffer (self->codec, idx, &err);
1558 goto failed_to_get_input_buffer;
1560 goto got_null_input_buffer;
1562 memset (&buffer_info, 0, sizeof (buffer_info));
1563 buffer_info.offset = 0;
1564 buffer_info.size = MIN (self->color_format_info.frame_size, buf->size);
1565 gst_amc_buffer_set_position_and_limit (buf, NULL, buffer_info.offset,
1568 if (!gst_amc_video_enc_fill_buffer (self, frame->input_buffer, buf,
1570 memset (&buffer_info, 0, sizeof (buffer_info));
1571 gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err);
1572 if (err && !self->flushing)
1573 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1574 g_clear_error (&err);
1575 gst_amc_buffer_free (buf);
1577 goto buffer_fill_error;
1580 gst_amc_buffer_free (buf);
1583 if (timestamp != GST_CLOCK_TIME_NONE) {
1584 buffer_info.presentation_time_us =
1585 gst_util_uint64_scale (timestamp + timestamp_offset, 1, GST_USECOND);
1586 self->last_upstream_ts = timestamp + timestamp_offset;
1588 if (duration != GST_CLOCK_TIME_NONE)
1589 self->last_upstream_ts += duration;
1591 id = buffer_identification_new (timestamp + timestamp_offset);
1592 if (GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame))
1593 buffer_info.flags |= BUFFER_FLAG_SYNC_FRAME;
1594 gst_video_codec_frame_set_user_data (frame, id,
1595 (GDestroyNotify) buffer_identification_free);
1597 GST_DEBUG_OBJECT (self,
1598 "Queueing buffer %d: size %d time %" G_GINT64_FORMAT " flags 0x%08x",
1599 idx, buffer_info.size, buffer_info.presentation_time_us,
1601 if (!gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err)) {
1602 if (self->flushing) {
1603 g_clear_error (&err);
1609 self->drained = FALSE;
1611 gst_video_codec_frame_unref (frame);
1613 return self->downstream_flow_ret;
1617 GST_ERROR_OBJECT (self, "Downstream returned %s",
1618 gst_flow_get_name (self->downstream_flow_ret));
1620 gst_video_codec_frame_unref (frame);
1621 return self->downstream_flow_ret;
1623 failed_to_get_input_buffer:
1625 GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1626 gst_video_codec_frame_unref (frame);
1627 return GST_FLOW_ERROR;
1629 got_null_input_buffer:
1631 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1632 ("Got no input buffer"));
1633 gst_video_codec_frame_unref (frame);
1634 return GST_FLOW_ERROR;
1638 GST_ELEMENT_ERROR (self, RESOURCE, WRITE, (NULL),
1639 ("Failed to write input into the amc buffer(write %dB to a %"
1640 G_GSIZE_FORMAT "B buffer)", self->color_format_info.frame_size,
1642 gst_video_codec_frame_unref (frame);
1643 return GST_FLOW_ERROR;
1647 GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1648 gst_video_codec_frame_unref (frame);
1649 return GST_FLOW_ERROR;
1653 GST_ELEMENT_ERROR_FROM_ERROR (self, err);
1654 gst_video_codec_frame_unref (frame);
1655 return GST_FLOW_ERROR;
1659 GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
1660 gst_video_codec_frame_unref (frame);
1661 return GST_FLOW_FLUSHING;
1665 static GstFlowReturn
1666 gst_amc_video_enc_finish (GstVideoEncoder * encoder)
1668 GstAmcVideoEnc *self;
1670 self = GST_AMC_VIDEO_ENC (encoder);
1672 return gst_amc_video_enc_drain (self);
1675 static GstFlowReturn
1676 gst_amc_video_enc_drain (GstAmcVideoEnc * self)
1682 GST_DEBUG_OBJECT (self, "Draining codec");
1683 if (!self->started) {
1684 GST_DEBUG_OBJECT (self, "Codec not started yet");
1688 /* Don't send drain buffer twice, this doesn't work */
1689 if (self->drained) {
1690 GST_DEBUG_OBJECT (self, "Codec is drained already");
1694 /* Make sure to release the base class stream lock, otherwise
1695 * _loop() can't call _finish_frame() and we might block forever
1696 * because no input buffers are released */
1697 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1698 /* Send an EOS buffer to the component and let the base
1699 * class drop the EOS event. We will send it later when
1700 * the EOS buffer arrives on the output port.
1701 * Wait at most 0.5s here. */
1702 idx = gst_amc_codec_dequeue_input_buffer (self->codec, 500000, &err);
1703 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1707 GstAmcBufferInfo buffer_info;
1709 buf = gst_amc_codec_get_input_buffer (self->codec, idx, &err);
1711 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1712 g_mutex_lock (&self->drain_lock);
1713 self->draining = TRUE;
1715 memset (&buffer_info, 0, sizeof (buffer_info));
1716 buffer_info.size = 0;
1717 buffer_info.presentation_time_us =
1718 gst_util_uint64_scale (self->last_upstream_ts, 1, GST_USECOND);
1719 buffer_info.flags |= BUFFER_FLAG_END_OF_STREAM;
1721 gst_amc_buffer_set_position_and_limit (buf, NULL, 0, 0);
1722 gst_amc_buffer_free (buf);
1725 if (gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info,
1727 GST_DEBUG_OBJECT (self, "Waiting until codec is drained");
1728 g_cond_wait (&self->drain_cond, &self->drain_lock);
1729 GST_DEBUG_OBJECT (self, "Drained codec");
1732 GST_ERROR_OBJECT (self, "Failed to queue input buffer");
1733 if (self->flushing) {
1734 g_clear_error (&err);
1735 ret = GST_FLOW_FLUSHING;
1737 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1738 ret = GST_FLOW_ERROR;
1742 self->drained = TRUE;
1743 self->draining = FALSE;
1744 g_mutex_unlock (&self->drain_lock);
1745 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1747 GST_ERROR_OBJECT (self, "Failed to get buffer for EOS: %d", idx);
1749 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1750 ret = GST_FLOW_ERROR;
1753 GST_ERROR_OBJECT (self, "Failed to acquire buffer for EOS: %d", idx);
1755 GST_ELEMENT_WARNING_FROM_ERROR (self, err);
1756 ret = GST_FLOW_ERROR;