diff --git a/sys/androidmedia/gstamc.c b/sys/androidmedia/gstamc.c index 8080de401b..88f81a7ab3 100644 --- a/sys/androidmedia/gstamc.c +++ b/sys/androidmedia/gstamc.c @@ -72,7 +72,9 @@ static struct jmethodID dequeue_output_buffer; jmethodID flush; jmethodID get_input_buffers; + jmethodID get_input_buffer; jmethodID get_output_buffers; + jmethodID get_output_buffer; jmethodID get_output_format; jmethodID queue_input_buffer; jmethodID release; @@ -106,6 +108,11 @@ static struct jmethodID set_byte_buffer; } media_format; +static GstAmcBuffer *gst_amc_codec_get_input_buffers (GstAmcCodec * codec, + gsize * n_buffers, GError ** err); +static GstAmcBuffer *gst_amc_codec_get_output_buffers (GstAmcCodec * codec, + gsize * n_buffers, GError ** err); + GstAmcCodec * gst_amc_codec_new (const gchar * name, GError ** err) { @@ -160,6 +167,19 @@ gst_amc_codec_free (GstAmcCodec * codec) g_return_if_fail (codec != NULL); env = gst_amc_jni_get_env (); + + if (codec->input_buffers) + gst_amc_jni_free_buffer_array (env, codec->input_buffers, + codec->n_input_buffers); + codec->input_buffers = NULL; + codec->n_input_buffers = 0; + + if (codec->output_buffers) + gst_amc_jni_free_buffer_array (env, codec->output_buffers, + codec->n_output_buffers); + codec->output_buffers = NULL; + codec->n_output_buffers = 0; + gst_amc_jni_object_unref (env, codec->object); g_slice_free (GstAmcCodec, codec); } @@ -212,12 +232,29 @@ gboolean gst_amc_codec_start (GstAmcCodec * codec, GError ** err) { JNIEnv *env; + gboolean ret; g_return_val_if_fail (codec != NULL, FALSE); env = gst_amc_jni_get_env (); - return gst_amc_jni_call_void_method (env, err, codec->object, + ret = gst_amc_jni_call_void_method (env, err, codec->object, media_codec.start); + if (!ret) + return ret; + + if (!media_codec.get_input_buffer) { + if (codec->input_buffers) + gst_amc_jni_free_buffer_array (env, codec->input_buffers, + codec->n_input_buffers); + codec->input_buffers = + gst_amc_codec_get_input_buffers (codec, &codec->n_input_buffers, err); + if (!codec->input_buffers) { + gst_amc_codec_stop (codec, NULL); + return FALSE; + } + } + + return ret; } gboolean @@ -228,6 +265,19 @@ gst_amc_codec_stop (GstAmcCodec * codec, GError ** err) g_return_val_if_fail (codec != NULL, FALSE); env = gst_amc_jni_get_env (); + + if (codec->input_buffers) + gst_amc_jni_free_buffer_array (env, codec->input_buffers, + codec->n_input_buffers); + codec->input_buffers = NULL; + codec->n_input_buffers = 0; + + if (codec->output_buffers) + gst_amc_jni_free_buffer_array (env, codec->output_buffers, + codec->n_output_buffers); + codec->output_buffers = NULL; + codec->n_output_buffers = 0; + return gst_amc_jni_call_void_method (env, err, codec->object, media_codec.stop); } @@ -252,11 +302,24 @@ gst_amc_codec_release (GstAmcCodec * codec, GError ** err) g_return_val_if_fail (codec != NULL, FALSE); env = gst_amc_jni_get_env (); + + if (codec->input_buffers) + gst_amc_jni_free_buffer_array (env, codec->input_buffers, + codec->n_input_buffers); + codec->input_buffers = NULL; + codec->n_input_buffers = 0; + + if (codec->output_buffers) + gst_amc_jni_free_buffer_array (env, codec->output_buffers, + codec->n_output_buffers); + codec->output_buffers = NULL; + codec->n_output_buffers = 0; + return gst_amc_jni_call_void_method (env, err, codec->object, media_codec.release); } -GstAmcBuffer * +static GstAmcBuffer * gst_amc_codec_get_output_buffers (GstAmcCodec * codec, gsize * n_buffers, GError ** err) { @@ -284,6 +347,55 @@ done: } GstAmcBuffer * +gst_amc_codec_get_output_buffer (GstAmcCodec * codec, gint index, GError ** err) +{ + JNIEnv *env; + jobject buffer = NULL; + GstAmcBuffer *ret = NULL; + + g_return_val_if_fail (codec != NULL, NULL); + g_return_val_if_fail (index >= 0, NULL); + + env = gst_amc_jni_get_env (); + + if (!media_codec.get_output_buffer) { + g_return_val_if_fail (index < codec->n_output_buffers && index >= 0, NULL); + return gst_amc_buffer_copy (&codec->output_buffers[index]); + } + + if (!gst_amc_jni_call_object_method (env, err, codec->object, + media_codec.get_output_buffer, &buffer, index)) + goto done; + + ret = g_new0 (GstAmcBuffer, 1); + ret->object = gst_amc_jni_object_make_global (env, buffer); + if (!ret->object) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference"); + goto error; + } + + ret->data = (*env)->GetDirectBufferAddress (env, ret->object); + if (!ret->data) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address"); + goto error; + } + ret->size = (*env)->GetDirectBufferCapacity (env, ret->object); + +done: + + return ret; + +error: + if (ret->object) + gst_amc_jni_object_unref (env, ret->object); + g_free (ret); + + return NULL; +} + +static GstAmcBuffer * gst_amc_codec_get_input_buffers (GstAmcCodec * codec, gsize * n_buffers, GError ** err) { @@ -310,13 +422,53 @@ done: return ret; } -void -gst_amc_codec_free_buffers (GstAmcBuffer * buffers, gsize n_buffers) +GstAmcBuffer * +gst_amc_codec_get_input_buffer (GstAmcCodec * codec, gint index, GError ** err) { JNIEnv *env; + jobject buffer = NULL; + GstAmcBuffer *ret = NULL; + + g_return_val_if_fail (codec != NULL, NULL); + g_return_val_if_fail (index >= 0, NULL); env = gst_amc_jni_get_env (); - gst_amc_jni_free_buffer_array (env, buffers, n_buffers); + + if (!media_codec.get_input_buffer) { + g_return_val_if_fail (index < codec->n_input_buffers && index >= 0, NULL); + return gst_amc_buffer_copy (&codec->input_buffers[index]); + } + + if (!gst_amc_jni_call_object_method (env, err, codec->object, + media_codec.get_input_buffer, &buffer, index)) + goto done; + + ret = g_new0 (GstAmcBuffer, 1); + ret->object = gst_amc_jni_object_make_global (env, buffer); + if (!ret->object) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference"); + goto error; + } + + ret->data = (*env)->GetDirectBufferAddress (env, ret->object); + if (!ret->data) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address"); + goto error; + } + ret->size = (*env)->GetDirectBufferCapacity (env, ret->object); + +done: + + return ret; + +error: + if (ret->object) + gst_amc_jni_object_unref (env, ret->object); + g_free (ret); + + return NULL; } gint @@ -386,7 +538,30 @@ gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec, goto done; } - if (!gst_amc_codec_fill_buffer_info (env, info_o, info, err)) { + if (ret == INFO_OUTPUT_BUFFERS_CHANGED || ret == INFO_OUTPUT_FORMAT_CHANGED + || (ret >= 0 && !codec->output_buffers + && !media_codec.get_output_buffer)) { + if (!media_codec.get_output_buffer) { + if (codec->output_buffers) + gst_amc_jni_free_buffer_array (env, codec->output_buffers, + codec->n_output_buffers); + codec->output_buffers = + gst_amc_codec_get_output_buffers (codec, + &codec->n_output_buffers, err); + if (!codec->output_buffers) { + ret = G_MININT; + goto done; + } + } + if (ret == INFO_OUTPUT_BUFFERS_CHANGED) { + gst_amc_jni_object_local_unref (env, info_o); + return gst_amc_codec_dequeue_output_buffer (codec, info, timeoutUs, err); + } + } else if (ret < 0) { + goto done; + } + + if (ret >= 0 && !gst_amc_codec_fill_buffer_info (env, info_o, info, err)) { ret = G_MININT; goto done; } @@ -766,6 +941,8 @@ gst_amc_format_get_buffer (GstAmcFormat * format, const gchar * key, gboolean ret = FALSE; jstring key_str = NULL; jobject v = NULL; + GstAmcBuffer buf = { 0, }; + gint position = 0, limit = 0; g_return_val_if_fail (format != NULL, FALSE); g_return_val_if_fail (key != NULL, FALSE); @@ -791,7 +968,14 @@ gst_amc_format_get_buffer (GstAmcFormat * format, const gchar * key, goto done; } *size = (*env)->GetDirectBufferCapacity (env, v); - *data = g_memdup (*data, *size); + + buf.object = v; + buf.data = *data; + buf.size = *size; + gst_amc_buffer_get_position_and_limit (&buf, NULL, &position, &limit); + *size = limit; + + *data = g_memdup (*data + position, limit); ret = TRUE; @@ -812,6 +996,7 @@ gst_amc_format_set_buffer (GstAmcFormat * format, const gchar * key, jstring key_str = NULL; jobject v = NULL; gboolean ret = FALSE; + GstAmcBuffer buf = { 0, }; g_return_val_if_fail (format != NULL, FALSE); g_return_val_if_fail (key != NULL, FALSE); @@ -831,6 +1016,12 @@ gst_amc_format_set_buffer (GstAmcFormat * format, const gchar * key, goto done; } + buf.object = v; + buf.data = data; + buf.size = size; + + gst_amc_buffer_set_position_and_limit (&buf, NULL, 0, size); + if (!gst_amc_jni_call_void_method (env, err, format->object, media_format.set_byte_buffer, key_str, v)) goto done; @@ -972,6 +1163,20 @@ get_java_classes (void) goto done; } + /* Android >= 21 */ + media_codec.get_output_buffer = + (*env)->GetMethodID (env, media_codec.klass, "getOutputBuffer", + "(I)Ljava/nio/ByteBuffer;"); + if ((*env)->ExceptionCheck (env)) + (*env)->ExceptionClear (env); + + /* Android >= 21 */ + media_codec.get_input_buffer = + (*env)->GetMethodID (env, media_codec.klass, "getInputBuffer", + "(I)Ljava/nio/ByteBuffer;"); + if ((*env)->ExceptionCheck (env)) + (*env)->ExceptionClear (env); + tmp = (*env)->FindClass (env, "android/media/MediaCodec$BufferInfo"); if (!tmp) { ret = FALSE; diff --git a/sys/androidmedia/gstamc.h b/sys/androidmedia/gstamc.h index e216039bd3..88d49fbaee 100644 --- a/sys/androidmedia/gstamc.h +++ b/sys/androidmedia/gstamc.h @@ -65,6 +65,9 @@ struct _GstAmcFormat { struct _GstAmcCodec { /* < private > */ jobject object; /* global reference */ + + GstAmcBuffer *input_buffers, *output_buffers; + gsize n_input_buffers, n_output_buffers; }; struct _GstAmcBufferInfo { @@ -87,9 +90,8 @@ gboolean gst_amc_codec_stop (GstAmcCodec * codec, GError **err); gboolean gst_amc_codec_flush (GstAmcCodec * codec, GError **err); gboolean gst_amc_codec_release (GstAmcCodec * codec, GError **err); -GstAmcBuffer * gst_amc_codec_get_output_buffers (GstAmcCodec * codec, gsize * n_buffers, GError **err); -GstAmcBuffer * gst_amc_codec_get_input_buffers (GstAmcCodec * codec, gsize * n_buffers, GError **err); -void gst_amc_codec_free_buffers (GstAmcBuffer * buffers, gsize n_buffers); +GstAmcBuffer * gst_amc_codec_get_output_buffer (GstAmcCodec * codec, gint index, GError **err); +GstAmcBuffer * gst_amc_codec_get_input_buffer (GstAmcCodec * codec, gint index, GError **err); gint gst_amc_codec_dequeue_input_buffer (GstAmcCodec * codec, gint64 timeoutUs, GError **err); gint gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec, GstAmcBufferInfo *info, gint64 timeoutUs, GError **err); diff --git a/sys/androidmedia/gstamcaudiodec.c b/sys/androidmedia/gstamcaudiodec.c index ca090c3c9e..bc8190740f 100644 --- a/sys/androidmedia/gstamcaudiodec.c +++ b/sys/androidmedia/gstamcaudiodec.c @@ -7,6 +7,8 @@ * Copyright (C) 2012, Collabora Ltd. * Author: Sebastian Dröge * + * Copyright (C) 2015, Sebastian Dröge + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation @@ -408,6 +410,7 @@ gst_amc_audio_dec_loop (GstAmcAudioDec * self) { GstFlowReturn flow_ret = GST_FLOW_OK; gboolean is_eos; + GstAmcBuffer *buf; GstAmcBufferInfo buffer_info; gint idx; GError *err = NULL; @@ -435,18 +438,10 @@ retry: } switch (idx) { - case INFO_OUTPUT_BUFFERS_CHANGED:{ - GST_DEBUG_OBJECT (self, "Output buffers have changed"); - if (self->output_buffers) - gst_amc_codec_free_buffers (self->output_buffers, - self->n_output_buffers); - self->output_buffers = - gst_amc_codec_get_output_buffers (self->codec, - &self->n_output_buffers, &err); - if (!self->output_buffers) - goto get_output_buffers_error; + case INFO_OUTPUT_BUFFERS_CHANGED: + /* Handled internally */ + g_assert_not_reached (); break; - } case INFO_OUTPUT_FORMAT_CHANGED:{ GstAmcFormat *format; gchar *format_string; @@ -471,15 +466,6 @@ retry: } gst_amc_format_free (format); - if (self->output_buffers) - gst_amc_codec_free_buffers (self->output_buffers, - self->n_output_buffers); - self->output_buffers = - gst_amc_codec_get_output_buffers (self->codec, - &self->n_output_buffers, &err); - if (!self->output_buffers) - goto get_output_buffers_error; - goto retry; } @@ -500,23 +486,24 @@ retry: } GST_DEBUG_OBJECT (self, - "Got output buffer at index %d: size %d time %" G_GINT64_FORMAT - " flags 0x%08x", idx, buffer_info.size, buffer_info.presentation_time_us, - buffer_info.flags); + "Got output buffer at index %d: offset %d size %d time %" G_GINT64_FORMAT + " flags 0x%08x", idx, buffer_info.offset, buffer_info.size, + buffer_info.presentation_time_us, buffer_info.flags); is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM); + buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err); + if (!buf) + goto failed_to_get_output_buffer; + if (buffer_info.size > 0) { GstBuffer *outbuf; - GstAmcBuffer *buf; GstMapInfo minfo; /* This sometimes happens at EOS or if the input is not properly framed, * let's handle it gracefully by allocating a new buffer for the current * caps and filling it */ - if (idx >= self->n_output_buffers) - goto invalid_buffer_index; if (buffer_info.size % self->info.bpf != 0) goto invalid_buffer_size; @@ -528,7 +515,6 @@ retry: goto failed_allocate; gst_buffer_map (outbuf, &minfo, GST_MAP_WRITE); - buf = &self->output_buffers[idx]; if (self->needs_reorder) { gint i, n_samples, c, n_channels; gint *reorder_map = self->reorder_map; @@ -557,6 +543,9 @@ retry: } } + gst_amc_buffer_free (buf); + buf = NULL; + if (self->spf != -1) { GstBuffer *outbuf; guint avail = gst_adapter_available (self->output_adapter); @@ -632,20 +621,6 @@ dequeue_error: return; } -get_output_buffers_error: - { - GST_ELEMENT_ERROR_FROM_ERROR (self, err); - gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); - gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); - self->downstream_flow_ret = GST_FLOW_ERROR; - GST_AUDIO_DECODER_STREAM_UNLOCK (self); - g_mutex_lock (&self->drain_lock); - self->draining = FALSE; - g_cond_broadcast (&self->drain_cond); - g_mutex_unlock (&self->drain_lock); - return; - } - format_error: { if (err) @@ -711,10 +686,9 @@ flow_error: return; } -invalid_buffer_index: +failed_to_get_output_buffer: { - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), - ("Invalid input buffer index %d of %d", idx, self->n_input_buffers)); + GST_AUDIO_DECODER_ERROR_FROM_ERROR (self, err); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; @@ -796,12 +770,6 @@ gst_amc_audio_dec_stop (GstAudioDecoder * decoder) if (err) GST_ELEMENT_WARNING_FROM_ERROR (self, err); self->started = FALSE; - if (self->input_buffers) - gst_amc_codec_free_buffers (self->input_buffers, self->n_input_buffers); - self->input_buffers = NULL; - if (self->output_buffers) - gst_amc_codec_free_buffers (self->output_buffers, self->n_output_buffers); - self->output_buffers = NULL; } gst_pad_stop_task (GST_AUDIO_DECODER_SRC_PAD (decoder)); @@ -973,17 +941,6 @@ gst_amc_audio_dec_set_format (GstAudioDecoder * decoder, GstCaps * caps) return FALSE; } - if (self->input_buffers) - gst_amc_codec_free_buffers (self->input_buffers, self->n_input_buffers); - self->input_buffers = - gst_amc_codec_get_input_buffers (self->codec, &self->n_input_buffers, - &err); - if (!self->input_buffers) { - GST_ERROR_OBJECT (self, "Failed to get input buffers"); - GST_ELEMENT_ERROR_FROM_ERROR (self, err); - return FALSE; - } - self->spf = -1; /* TODO: Implement for other codecs too */ if (gst_structure_has_name (s, "audio/mpeg")) { @@ -1133,9 +1090,6 @@ gst_amc_audio_dec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf) continue; } - if (idx >= self->n_input_buffers) - goto invalid_buffer_index; - if (self->flushing) { memset (&buffer_info, 0, sizeof (buffer_info)); gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, NULL); @@ -1155,14 +1109,21 @@ gst_amc_audio_dec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf) /* Copy the buffer content in chunks of size as requested * by the port */ - buf = &self->input_buffers[idx]; + buf = gst_amc_codec_get_input_buffer (self->codec, idx, &err); + if (!buf) + goto failed_to_get_input_buffer; memset (&buffer_info, 0, sizeof (buffer_info)); buffer_info.offset = 0; buffer_info.size = MIN (minfo.size - offset, buf->size); + gst_amc_buffer_set_position_and_limit (buf, NULL, buffer_info.offset, + buffer_info.size); orc_memcpy (buf->data, minfo.data + offset, buffer_info.size); + gst_amc_buffer_free (buf); + buf = NULL; + /* Interpolate timestamps if we're passing the buffer * in multiple chunks */ if (offset != 0 && duration != GST_CLOCK_TIME_NONE) { @@ -1212,10 +1173,9 @@ downstream_error: gst_buffer_unref (inbuf); return self->downstream_flow_ret; } -invalid_buffer_index: +failed_to_get_input_buffer: { - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), - ("Invalid input buffer index %d of %d", idx, self->n_input_buffers)); + GST_ELEMENT_ERROR_FROM_ERROR (self, err); if (minfo.data) gst_buffer_unmap (inbuf, &minfo); if (inbuf) @@ -1281,43 +1241,53 @@ gst_amc_audio_dec_drain (GstAmcAudioDec * self) idx = gst_amc_codec_dequeue_input_buffer (self->codec, 500000, &err); GST_AUDIO_DECODER_STREAM_LOCK (self); - if (idx >= 0 && idx < self->n_input_buffers) { + if (idx >= 0) { + GstAmcBuffer *buf; GstAmcBufferInfo buffer_info; - GST_AUDIO_DECODER_STREAM_UNLOCK (self); - g_mutex_lock (&self->drain_lock); - self->draining = TRUE; + buf = gst_amc_codec_get_input_buffer (self->codec, idx, &err); + if (buf) { + GST_AUDIO_DECODER_STREAM_UNLOCK (self); + g_mutex_lock (&self->drain_lock); + self->draining = TRUE; - memset (&buffer_info, 0, sizeof (buffer_info)); - buffer_info.size = 0; - buffer_info.presentation_time_us = - gst_util_uint64_scale (self->last_upstream_ts, 1, GST_USECOND); - buffer_info.flags |= BUFFER_FLAG_END_OF_STREAM; + memset (&buffer_info, 0, sizeof (buffer_info)); + buffer_info.size = 0; + buffer_info.presentation_time_us = + gst_util_uint64_scale (self->last_upstream_ts, 1, GST_USECOND); + buffer_info.flags |= BUFFER_FLAG_END_OF_STREAM; - if (gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err)) { - GST_DEBUG_OBJECT (self, "Waiting until codec is drained"); - g_cond_wait (&self->drain_cond, &self->drain_lock); - GST_DEBUG_OBJECT (self, "Drained codec"); - ret = GST_FLOW_OK; - } else { - GST_ERROR_OBJECT (self, "Failed to queue input buffer"); - if (self->flushing) { - g_clear_error (&err); - ret = GST_FLOW_FLUSHING; + gst_amc_buffer_set_position_and_limit (buf, NULL, 0, 0); + gst_amc_buffer_free (buf); + buf = NULL; + + if (gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, + &err)) { + GST_DEBUG_OBJECT (self, "Waiting until codec is drained"); + g_cond_wait (&self->drain_cond, &self->drain_lock); + GST_DEBUG_OBJECT (self, "Drained codec"); + ret = GST_FLOW_OK; } else { - GST_ELEMENT_WARNING_FROM_ERROR (self, err); - ret = GST_FLOW_ERROR; + GST_ERROR_OBJECT (self, "Failed to queue input buffer"); + if (self->flushing) { + g_clear_error (&err); + ret = GST_FLOW_FLUSHING; + } else { + GST_ELEMENT_WARNING_FROM_ERROR (self, err); + ret = GST_FLOW_ERROR; + } } - } - self->drained = TRUE; - self->draining = FALSE; - g_mutex_unlock (&self->drain_lock); - GST_AUDIO_DECODER_STREAM_LOCK (self); - } else if (idx >= self->n_input_buffers) { - GST_ERROR_OBJECT (self, "Invalid input buffer index %d of %d", - idx, self->n_input_buffers); - ret = GST_FLOW_ERROR; + self->drained = TRUE; + self->draining = FALSE; + g_mutex_unlock (&self->drain_lock); + GST_AUDIO_DECODER_STREAM_LOCK (self); + } else { + GST_ERROR_OBJECT (self, "Failed to get buffer for EOS: %d", idx); + if (err) + GST_ELEMENT_WARNING_FROM_ERROR (self, err); + ret = GST_FLOW_ERROR; + } } else { GST_ERROR_OBJECT (self, "Failed to acquire buffer for EOS: %d", idx); if (err) diff --git a/sys/androidmedia/gstamcaudiodec.h b/sys/androidmedia/gstamcaudiodec.h index 9fff22105f..04e973426b 100644 --- a/sys/androidmedia/gstamcaudiodec.h +++ b/sys/androidmedia/gstamcaudiodec.h @@ -51,8 +51,6 @@ struct _GstAmcAudioDec /* < private > */ GstAmcCodec *codec; - GstAmcBuffer *input_buffers, *output_buffers; - gsize n_input_buffers, n_output_buffers; GstCaps *input_caps; GList *codec_datas; diff --git a/sys/androidmedia/gstamcvideodec.c b/sys/androidmedia/gstamcvideodec.c index a2ac65e1c4..33bed1c3c2 100644 --- a/sys/androidmedia/gstamcvideodec.c +++ b/sys/androidmedia/gstamcvideodec.c @@ -9,6 +9,8 @@ * * Copyright (C) 2012, Rafaël Carré * + * Copyright (C) 2015, Sebastian Dröge + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation @@ -557,27 +559,18 @@ gst_amc_video_dec_set_src_caps (GstAmcVideoDec * self, GstAmcFormat * format) } static gboolean -gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, +gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, GstAmcBuffer * buf, const GstAmcBufferInfo * buffer_info, GstBuffer * outbuf) { - GstAmcBuffer *buf; GstVideoCodecState *state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self)); GstVideoInfo *info = &state->info; gboolean ret = FALSE; - if (idx >= self->n_output_buffers) { - GST_ERROR_OBJECT (self, "Invalid output buffer index %d of %d", - idx, self->n_output_buffers); - goto done; - } - buf = &self->output_buffers[idx]; - ret = gst_amc_color_format_copy (&self->color_format_info, buf, buffer_info, info, outbuf, COLOR_FORMAT_COPY_OUT); -done: gst_video_codec_state_unref (state); return ret; } @@ -589,6 +582,7 @@ gst_amc_video_dec_loop (GstAmcVideoDec * self) GstFlowReturn flow_ret = GST_FLOW_OK; GstClockTimeDiff deadline; gboolean is_eos; + GstAmcBuffer *buf; GstAmcBufferInfo buffer_info; gint idx; GError *err = NULL; @@ -616,18 +610,10 @@ retry: } switch (idx) { - case INFO_OUTPUT_BUFFERS_CHANGED:{ - GST_DEBUG_OBJECT (self, "Output buffers have changed"); - if (self->output_buffers) - gst_amc_codec_free_buffers (self->output_buffers, - self->n_output_buffers); - self->output_buffers = - gst_amc_codec_get_output_buffers (self->codec, - &self->n_output_buffers, &err); - if (!self->output_buffers) - goto get_output_buffers_error; + case INFO_OUTPUT_BUFFERS_CHANGED: + /* Handled internally */ + g_assert_not_reached (); break; - } case INFO_OUTPUT_FORMAT_CHANGED:{ GstAmcFormat *format; gchar *format_string; @@ -652,15 +638,6 @@ retry: } gst_amc_format_free (format); - if (self->output_buffers) - gst_amc_codec_free_buffers (self->output_buffers, - self->n_output_buffers); - self->output_buffers = - gst_amc_codec_get_output_buffers (self->codec, - &self->n_output_buffers, &err); - if (!self->output_buffers) - goto get_output_buffers_error; - goto retry; } case INFO_TRY_AGAIN_LATER: @@ -678,9 +655,9 @@ retry: } GST_DEBUG_OBJECT (self, - "Got output buffer at index %d: size %d time %" G_GINT64_FORMAT - " flags 0x%08x", idx, buffer_info.size, buffer_info.presentation_time_us, - buffer_info.flags); + "Got output buffer at index %d: offset %d size %d time %" G_GINT64_FORMAT + " flags 0x%08x", idx, buffer_info.offset, buffer_info.size, + buffer_info.presentation_time_us, buffer_info.flags); frame = _find_nearest_frame (self, @@ -688,6 +665,10 @@ retry: is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM); + buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err); + if (!buf) + goto failed_to_get_output_buffer; + if (frame && (deadline = gst_video_decoder_get_max_decode_time (GST_VIDEO_DECODER (self), @@ -708,7 +689,7 @@ retry: outbuf = gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self)); - if (!gst_amc_video_dec_fill_buffer (self, idx, &buffer_info, outbuf)) { + if (!gst_amc_video_dec_fill_buffer (self, buf, &buffer_info, outbuf)) { gst_buffer_unref (outbuf); if (!gst_amc_codec_release_output_buffer (self->codec, idx, &err)) GST_ERROR_OBJECT (self, "Failed to release output buffer index %d", @@ -716,6 +697,8 @@ retry: if (err && !self->flushing) GST_ELEMENT_WARNING_FROM_ERROR (self, err); g_clear_error (&err); + gst_amc_buffer_free (buf); + buf = NULL; goto invalid_buffer; } @@ -733,10 +716,12 @@ retry: if (err && !self->flushing) GST_ELEMENT_WARNING_FROM_ERROR (self, err); g_clear_error (&err); + gst_amc_buffer_free (buf); + buf = NULL; goto flow_error; } - if (!gst_amc_video_dec_fill_buffer (self, idx, &buffer_info, + if (!gst_amc_video_dec_fill_buffer (self, buf, &buffer_info, frame->output_buffer)) { gst_buffer_replace (&frame->output_buffer, NULL); gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); @@ -746,6 +731,8 @@ retry: if (err && !self->flushing) GST_ELEMENT_WARNING_FROM_ERROR (self, err); g_clear_error (&err); + gst_amc_buffer_free (buf); + buf = NULL; goto invalid_buffer; } @@ -754,6 +741,9 @@ retry: flow_ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); } + gst_amc_buffer_free (buf); + buf = NULL; + if (!gst_amc_codec_release_output_buffer (self->codec, idx, &err)) { if (self->flushing) { g_clear_error (&err); @@ -802,20 +792,6 @@ dequeue_error: return; } -get_output_buffers_error: - { - GST_ELEMENT_ERROR_FROM_ERROR (self, err); - gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ()); - gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self)); - self->downstream_flow_ret = GST_FLOW_ERROR; - GST_VIDEO_DECODER_STREAM_UNLOCK (self); - g_mutex_lock (&self->drain_lock); - self->draining = FALSE; - g_cond_broadcast (&self->drain_cond); - g_mutex_unlock (&self->drain_lock); - return; - } - format_error: { if (err) @@ -881,6 +857,20 @@ flow_error: return; } +failed_to_get_output_buffer: + { + GST_VIDEO_DECODER_ERROR_FROM_ERROR (self, err); + gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ()); + gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self)); + self->downstream_flow_ret = GST_FLOW_ERROR; + GST_VIDEO_DECODER_STREAM_UNLOCK (self); + g_mutex_lock (&self->drain_lock); + self->draining = FALSE; + g_cond_broadcast (&self->drain_cond); + g_mutex_unlock (&self->drain_lock); + return; + } + invalid_buffer: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), @@ -929,12 +919,6 @@ gst_amc_video_dec_stop (GstVideoDecoder * decoder) if (err) GST_ELEMENT_WARNING_FROM_ERROR (self, err); self->started = FALSE; - if (self->input_buffers) - gst_amc_codec_free_buffers (self->input_buffers, self->n_input_buffers); - self->input_buffers = NULL; - if (self->output_buffers) - gst_amc_codec_free_buffers (self->output_buffers, self->n_output_buffers); - self->output_buffers = NULL; } gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder)); @@ -1080,17 +1064,6 @@ gst_amc_video_dec_set_format (GstVideoDecoder * decoder, return FALSE; } - if (self->input_buffers) - gst_amc_codec_free_buffers (self->input_buffers, self->n_input_buffers); - self->input_buffers = - gst_amc_codec_get_input_buffers (self->codec, &self->n_input_buffers, - &err); - if (!self->input_buffers) { - GST_ERROR_OBJECT (self, "Failed to get input buffers"); - GST_ELEMENT_ERROR_FROM_ERROR (self, err); - return FALSE; - } - self->started = TRUE; self->input_state = gst_video_codec_state_ref (state); self->input_state_changed = TRUE; @@ -1212,9 +1185,6 @@ gst_amc_video_dec_handle_frame (GstVideoDecoder * decoder, continue; } - if (idx >= self->n_input_buffers) - goto invalid_buffer_index; - if (self->flushing) { memset (&buffer_info, 0, sizeof (buffer_info)); gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, NULL); @@ -1234,14 +1204,21 @@ gst_amc_video_dec_handle_frame (GstVideoDecoder * decoder, /* Copy the buffer content in chunks of size as requested * by the port */ - buf = &self->input_buffers[idx]; + buf = gst_amc_codec_get_input_buffer (self->codec, idx, &err); + if (!buf) + goto failed_to_get_input_buffer; memset (&buffer_info, 0, sizeof (buffer_info)); buffer_info.offset = 0; buffer_info.size = MIN (minfo.size - offset, buf->size); + gst_amc_buffer_set_position_and_limit (buf, NULL, buffer_info.offset, + buffer_info.size); orc_memcpy (buf->data, minfo.data + offset, buffer_info.size); + gst_amc_buffer_free (buf); + buf = NULL; + /* Interpolate timestamps if we're passing the buffer * in multiple chunks */ if (offset != 0 && duration != GST_CLOCK_TIME_NONE) { @@ -1295,10 +1272,9 @@ downstream_error: gst_video_codec_frame_unref (frame); return self->downstream_flow_ret; } -invalid_buffer_index: +failed_to_get_input_buffer: { - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), - ("Invalid input buffer index %d of %d", idx, self->n_input_buffers)); + GST_ELEMENT_ERROR_FROM_ERROR (self, err); if (minfo.data) gst_buffer_unmap (frame->input_buffer, &minfo); gst_video_codec_frame_unref (frame); @@ -1370,43 +1346,53 @@ gst_amc_video_dec_drain (GstAmcVideoDec * self) idx = gst_amc_codec_dequeue_input_buffer (self->codec, 500000, &err); GST_VIDEO_DECODER_STREAM_LOCK (self); - if (idx >= 0 && idx < self->n_input_buffers) { + if (idx >= 0) { + GstAmcBuffer *buf; GstAmcBufferInfo buffer_info; - GST_VIDEO_DECODER_STREAM_UNLOCK (self); - g_mutex_lock (&self->drain_lock); - self->draining = TRUE; + buf = gst_amc_codec_get_input_buffer (self->codec, idx, &err); + if (buf) { + GST_VIDEO_DECODER_STREAM_UNLOCK (self); + g_mutex_lock (&self->drain_lock); + self->draining = TRUE; - memset (&buffer_info, 0, sizeof (buffer_info)); - buffer_info.size = 0; - buffer_info.presentation_time_us = - gst_util_uint64_scale (self->last_upstream_ts, 1, GST_USECOND); - buffer_info.flags |= BUFFER_FLAG_END_OF_STREAM; + memset (&buffer_info, 0, sizeof (buffer_info)); + buffer_info.size = 0; + buffer_info.presentation_time_us = + gst_util_uint64_scale (self->last_upstream_ts, 1, GST_USECOND); + buffer_info.flags |= BUFFER_FLAG_END_OF_STREAM; - if (gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err)) { - GST_DEBUG_OBJECT (self, "Waiting until codec is drained"); - g_cond_wait (&self->drain_cond, &self->drain_lock); - GST_DEBUG_OBJECT (self, "Drained codec"); - ret = GST_FLOW_OK; - } else { - GST_ERROR_OBJECT (self, "Failed to queue input buffer"); - if (self->flushing) { - g_clear_error (&err); - ret = GST_FLOW_FLUSHING; + gst_amc_buffer_set_position_and_limit (buf, NULL, 0, 0); + gst_amc_buffer_free (buf); + buf = NULL; + + if (gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, + &err)) { + GST_DEBUG_OBJECT (self, "Waiting until codec is drained"); + g_cond_wait (&self->drain_cond, &self->drain_lock); + GST_DEBUG_OBJECT (self, "Drained codec"); + ret = GST_FLOW_OK; } else { - GST_ELEMENT_WARNING_FROM_ERROR (self, err); - ret = GST_FLOW_ERROR; + GST_ERROR_OBJECT (self, "Failed to queue input buffer"); + if (self->flushing) { + g_clear_error (&err); + ret = GST_FLOW_FLUSHING; + } else { + GST_ELEMENT_WARNING_FROM_ERROR (self, err); + ret = GST_FLOW_ERROR; + } } - } - self->drained = TRUE; - self->draining = FALSE; - g_mutex_unlock (&self->drain_lock); - GST_VIDEO_DECODER_STREAM_LOCK (self); - } else if (idx >= self->n_input_buffers) { - GST_ERROR_OBJECT (self, "Invalid input buffer index %d of %d", - idx, self->n_input_buffers); - ret = GST_FLOW_ERROR; + self->drained = TRUE; + self->draining = FALSE; + g_mutex_unlock (&self->drain_lock); + GST_VIDEO_DECODER_STREAM_LOCK (self); + } else { + GST_ERROR_OBJECT (self, "Failed to get buffer for EOS: %d", idx); + if (err) + GST_ELEMENT_WARNING_FROM_ERROR (self, err); + ret = GST_FLOW_ERROR; + } } else { GST_ERROR_OBJECT (self, "Failed to acquire buffer for EOS: %d", idx); if (err) diff --git a/sys/androidmedia/gstamcvideodec.h b/sys/androidmedia/gstamcvideodec.h index a4ef11cff0..c6c2b4f49a 100644 --- a/sys/androidmedia/gstamcvideodec.h +++ b/sys/androidmedia/gstamcvideodec.h @@ -51,8 +51,6 @@ struct _GstAmcVideoDec /* < private > */ GstAmcCodec *codec; - GstAmcBuffer *input_buffers, *output_buffers; - gsize n_input_buffers, n_output_buffers; GstVideoCodecState *input_state; gboolean input_state_changed; diff --git a/sys/androidmedia/gstamcvideoenc.c b/sys/androidmedia/gstamcvideoenc.c index 4384c7624d..8a6dd44b85 100644 --- a/sys/androidmedia/gstamcvideoenc.c +++ b/sys/androidmedia/gstamcvideoenc.c @@ -10,6 +10,8 @@ * Copyright (C) 2013, Lemote Ltd. * Author: Chen Jie * + * Copyright (C) 2015, Sebastian Dröge + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation @@ -982,15 +984,6 @@ retry: gst_amc_format_free (format); - if (self->output_buffers) - gst_amc_codec_free_buffers (self->output_buffers, - self->n_output_buffers); - self->output_buffers = - gst_amc_codec_get_output_buffers (self->codec, - &self->n_output_buffers, &err); - if (!self->output_buffers) - goto get_output_buffers_error; - if (idx >= 0) goto process_buffer; @@ -998,18 +991,10 @@ retry: } switch (idx) { - case INFO_OUTPUT_BUFFERS_CHANGED:{ - GST_DEBUG_OBJECT (self, "Output buffers have changed"); - if (self->output_buffers) - gst_amc_codec_free_buffers (self->output_buffers, - self->n_output_buffers); - self->output_buffers = - gst_amc_codec_get_output_buffers (self->codec, - &self->n_output_buffers, &err); - if (!self->output_buffers) - goto get_output_buffers_error; + case INFO_OUTPUT_BUFFERS_CHANGED: + /* Handled internally */ + g_assert_not_reached (); break; - } case INFO_TRY_AGAIN_LATER: GST_DEBUG_OBJECT (self, "Dequeueing output buffer timed out"); goto retry; @@ -1038,17 +1023,16 @@ process_buffer: is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM); - if (idx >= self->n_output_buffers) { - GST_ERROR_OBJECT (self, "Invalid output buffer index %d of %d", - idx, self->n_output_buffers); - - goto invalid_buffer; - } - buf = &self->output_buffers[idx]; + buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err); + if (!buf) + goto failed_to_get_output_buffer; flow_ret = gst_amc_video_enc_handle_output_frame (self, buf, &buffer_info, frame); + gst_amc_buffer_free (buf); + buf = NULL; + if (!gst_amc_codec_release_output_buffer (self->codec, idx, &err)) { if (self->flushing) { g_clear_error (&err); @@ -1097,20 +1081,6 @@ dequeue_error: return; } -get_output_buffers_error: - { - GST_ELEMENT_ERROR_FROM_ERROR (self, err); - gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); - gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self)); - self->downstream_flow_ret = GST_FLOW_ERROR; - GST_VIDEO_ENCODER_STREAM_UNLOCK (self); - g_mutex_lock (&self->drain_lock); - self->draining = FALSE; - g_cond_broadcast (&self->drain_cond); - g_mutex_unlock (&self->drain_lock); - return; - } - format_error: { if (err) @@ -1173,10 +1143,9 @@ flow_error: return; } -invalid_buffer: +failed_to_get_output_buffer: { - GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), - ("Invalid sized input buffer")); + GST_ELEMENT_ERROR_FROM_ERROR (self, err); gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED; @@ -1221,12 +1190,6 @@ gst_amc_video_enc_stop (GstVideoEncoder * encoder) if (err) GST_ELEMENT_WARNING_FROM_ERROR (self, err); self->started = FALSE; - if (self->input_buffers) - gst_amc_codec_free_buffers (self->input_buffers, self->n_input_buffers); - self->input_buffers = NULL; - if (self->output_buffers) - gst_amc_codec_free_buffers (self->output_buffers, self->n_output_buffers); - self->output_buffers = NULL; } gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder)); @@ -1341,17 +1304,6 @@ gst_amc_video_enc_set_format (GstVideoEncoder * encoder, goto quit; } - if (self->input_buffers) - gst_amc_codec_free_buffers (self->input_buffers, self->n_input_buffers); - self->input_buffers = - gst_amc_codec_get_input_buffers (self->codec, &self->n_input_buffers, - &err); - if (!self->input_buffers) { - GST_ERROR_OBJECT (self, "Failed to get input buffers"); - GST_ELEMENT_ERROR_FROM_ERROR (self, err); - goto quit; - } - self->amc_format = format; format = NULL; @@ -1481,9 +1433,6 @@ again: goto again; } - if (idx >= self->n_input_buffers) - goto invalid_buffer_index; - if (self->flushing) { memset (&buffer_info, 0, sizeof (buffer_info)); gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, NULL); @@ -1503,11 +1452,15 @@ again: /* Copy the buffer content in chunks of size as requested * by the port */ - buf = &self->input_buffers[idx]; + buf = gst_amc_codec_get_input_buffer (self->codec, idx, &err); + if (!buf) + goto failed_to_get_input_buffer; memset (&buffer_info, 0, sizeof (buffer_info)); buffer_info.offset = 0; buffer_info.size = MIN (self->color_format_info.frame_size, buf->size); + gst_amc_buffer_set_position_and_limit (buf, NULL, buffer_info.offset, + buffer_info.size); if (!gst_amc_video_enc_fill_buffer (self, frame->input_buffer, buf, &buffer_info)) { @@ -1516,9 +1469,14 @@ again: if (err && !self->flushing) GST_ELEMENT_WARNING_FROM_ERROR (self, err); g_clear_error (&err); + gst_amc_buffer_free (buf); + buf = NULL; goto buffer_fill_error; } + gst_amc_buffer_free (buf); + buf = NULL; + if (timestamp != GST_CLOCK_TIME_NONE) { buffer_info.presentation_time_us = gst_util_uint64_scale (timestamp + timestamp_offset, 1, GST_USECOND); @@ -1559,10 +1517,9 @@ downstream_error: gst_video_codec_frame_unref (frame); return self->downstream_flow_ret; } -invalid_buffer_index: +failed_to_get_input_buffer: { - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), - ("Invalid input buffer index %d of %d", idx, self->n_input_buffers)); + GST_ELEMENT_ERROR_FROM_ERROR (self, err); gst_video_codec_frame_unref (frame); return GST_FLOW_ERROR; } @@ -1634,43 +1591,53 @@ gst_amc_video_enc_drain (GstAmcVideoEnc * self) idx = gst_amc_codec_dequeue_input_buffer (self->codec, 500000, &err); GST_VIDEO_ENCODER_STREAM_LOCK (self); - if (idx >= 0 && idx < self->n_input_buffers) { + if (idx >= 0) { + GstAmcBuffer *buf; GstAmcBufferInfo buffer_info; - GST_VIDEO_ENCODER_STREAM_UNLOCK (self); - g_mutex_lock (&self->drain_lock); - self->draining = TRUE; + buf = gst_amc_codec_get_input_buffer (self->codec, idx, &err); + if (buf) { + GST_VIDEO_ENCODER_STREAM_UNLOCK (self); + g_mutex_lock (&self->drain_lock); + self->draining = TRUE; - memset (&buffer_info, 0, sizeof (buffer_info)); - buffer_info.size = 0; - buffer_info.presentation_time_us = - gst_util_uint64_scale (self->last_upstream_ts, 1, GST_USECOND); - buffer_info.flags |= BUFFER_FLAG_END_OF_STREAM; + memset (&buffer_info, 0, sizeof (buffer_info)); + buffer_info.size = 0; + buffer_info.presentation_time_us = + gst_util_uint64_scale (self->last_upstream_ts, 1, GST_USECOND); + buffer_info.flags |= BUFFER_FLAG_END_OF_STREAM; - if (gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err)) { - GST_DEBUG_OBJECT (self, "Waiting until codec is drained"); - g_cond_wait (&self->drain_cond, &self->drain_lock); - GST_DEBUG_OBJECT (self, "Drained codec"); - ret = GST_FLOW_OK; - } else { - GST_ERROR_OBJECT (self, "Failed to queue input buffer"); - if (self->flushing) { - g_clear_error (&err); - ret = GST_FLOW_FLUSHING; + gst_amc_buffer_set_position_and_limit (buf, NULL, 0, 0); + gst_amc_buffer_free (buf); + buf = NULL; + + if (gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, + &err)) { + GST_DEBUG_OBJECT (self, "Waiting until codec is drained"); + g_cond_wait (&self->drain_cond, &self->drain_lock); + GST_DEBUG_OBJECT (self, "Drained codec"); + ret = GST_FLOW_OK; } else { - GST_ELEMENT_WARNING_FROM_ERROR (self, err); - ret = GST_FLOW_ERROR; + GST_ERROR_OBJECT (self, "Failed to queue input buffer"); + if (self->flushing) { + g_clear_error (&err); + ret = GST_FLOW_FLUSHING; + } else { + GST_ELEMENT_WARNING_FROM_ERROR (self, err); + ret = GST_FLOW_ERROR; + } } - } - self->drained = TRUE; - self->draining = FALSE; - g_mutex_unlock (&self->drain_lock); - GST_VIDEO_ENCODER_STREAM_LOCK (self); - } else if (idx >= self->n_input_buffers) { - GST_ERROR_OBJECT (self, "Invalid input buffer index %d of %d", - idx, self->n_input_buffers); - ret = GST_FLOW_ERROR; + self->drained = TRUE; + self->draining = FALSE; + g_mutex_unlock (&self->drain_lock); + GST_VIDEO_ENCODER_STREAM_LOCK (self); + } else { + GST_ERROR_OBJECT (self, "Failed to get buffer for EOS: %d", idx); + if (err) + GST_ELEMENT_WARNING_FROM_ERROR (self, err); + ret = GST_FLOW_ERROR; + } } else { GST_ERROR_OBJECT (self, "Failed to acquire buffer for EOS: %d", idx); if (err) diff --git a/sys/androidmedia/gstamcvideoenc.h b/sys/androidmedia/gstamcvideoenc.h index 60a3687038..f16924897e 100644 --- a/sys/androidmedia/gstamcvideoenc.h +++ b/sys/androidmedia/gstamcvideoenc.h @@ -53,8 +53,6 @@ struct _GstAmcVideoEnc /* < private > */ GstAmcCodec *codec; - GstAmcBuffer *input_buffers, *output_buffers; - gsize n_input_buffers, n_output_buffers; GstAmcFormat *amc_format; GstVideoCodecState *input_state; diff --git a/sys/androidmedia/gstjniutils.c b/sys/androidmedia/gstjniutils.c index 02bc3a8216..b2be366556 100644 --- a/sys/androidmedia/gstjniutils.c +++ b/sys/androidmedia/gstjniutils.c @@ -6,6 +6,7 @@ * Copyright (C) 2014, Sebastian Dröge * Copyright (C) 2014, Collabora Ltd. * Author: Matthieu Bouron + * Copyright (C) 2015, Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -41,6 +42,14 @@ static JavaVM *java_vm; static gboolean started_java_vm = FALSE; static pthread_key_t current_jni_env; +static struct +{ + jclass klass; + jmethodID get_limit, get_position; + jmethodID set_limit, set_position; + jmethodID clear; +} java_nio_buffer; + jclass gst_amc_jni_get_class (JNIEnv * env, GError ** err, const gchar * name) { @@ -547,6 +556,69 @@ symbol_error: } } +static gboolean +initialize_classes (void) +{ + JNIEnv *env; + GError *err = NULL; + + env = gst_amc_jni_get_env (); + + java_nio_buffer.klass = gst_amc_jni_get_class (env, &err, "java/nio/Buffer"); + if (!java_nio_buffer.klass) { + GST_ERROR ("Failed to get java.nio.Buffer class: %s", err->message); + g_clear_error (&err); + return FALSE; + } + + java_nio_buffer.get_limit = + gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "limit", + "()I"); + if (!java_nio_buffer.get_limit) { + GST_ERROR ("Failed to get java.nio.Buffer limit(): %s", err->message); + g_clear_error (&err); + return FALSE; + } + + java_nio_buffer.get_position = + gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "position", + "()I"); + if (!java_nio_buffer.get_position) { + GST_ERROR ("Failed to get java.nio.Buffer position(): %s", err->message); + g_clear_error (&err); + return FALSE; + } + + java_nio_buffer.set_limit = + gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "limit", + "(I)Ljava/nio/Buffer;"); + if (!java_nio_buffer.set_limit) { + GST_ERROR ("Failed to get java.nio.Buffer limit(): %s", err->message); + g_clear_error (&err); + return FALSE; + } + + java_nio_buffer.set_position = + gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "position", + "(I)Ljava/nio/Buffer;"); + if (!java_nio_buffer.set_position) { + GST_ERROR ("Failed to get java.nio.Buffer position(): %s", err->message); + g_clear_error (&err); + return FALSE; + } + + java_nio_buffer.clear = + gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "clear", + "()Ljava/nio/Buffer;"); + if (!java_nio_buffer.clear) { + GST_ERROR ("Failed to get java.nio.Buffer clear(): %s", err->message); + g_clear_error (&err); + return FALSE; + } + + return TRUE; +} + static gboolean gst_amc_jni_initialize_java_vm (void) { @@ -599,7 +671,10 @@ gst_amc_jni_initialize_java_vm (void) started_java_vm = TRUE; } - return java_vm != NULL; + if (java_vm == NULL) + return FALSE; + + return initialize_classes (); get_created_failed: { @@ -902,3 +977,105 @@ gst_amc_jni_free_buffer_array (JNIEnv * env, GstAmcBuffer * buffers, } g_free (buffers); } + +void +gst_amc_buffer_free (GstAmcBuffer * buffer) +{ + JNIEnv *env; + + g_return_if_fail (buffer != NULL); + + env = gst_amc_jni_get_env (); + + if (buffer->object) + gst_amc_jni_object_unref (env, buffer->object); + g_free (buffer); +} + +GstAmcBuffer * +gst_amc_buffer_copy (GstAmcBuffer * buffer) +{ + JNIEnv *env; + GstAmcBuffer *ret; + + g_return_val_if_fail (buffer != NULL, NULL); + + env = gst_amc_jni_get_env (); + + ret = g_new0 (GstAmcBuffer, 1); + + ret->object = gst_amc_jni_object_ref (env, buffer->object); + ret->data = buffer->data; + ret->size = buffer->size; + + return ret; +} + +gboolean +gst_amc_buffer_get_position_and_limit (GstAmcBuffer * buffer, GError ** err, + gint * position, gint * limit) +{ + JNIEnv *env; + + g_return_val_if_fail (buffer != NULL, FALSE); + g_return_val_if_fail (buffer->object != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_int_method (env, err, buffer->object, + java_nio_buffer.get_position, position)) + return FALSE; + + if (!gst_amc_jni_call_int_method (env, err, buffer->object, + java_nio_buffer.get_limit, limit)) + return FALSE; + + return TRUE; +} + +gboolean +gst_amc_buffer_set_position_and_limit (GstAmcBuffer * buffer, GError ** err, + gint position, gint limit) +{ + JNIEnv *env; + jobject tmp; + + g_return_val_if_fail (buffer != NULL, FALSE); + g_return_val_if_fail (buffer->object != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_object_method (env, err, buffer->object, + java_nio_buffer.set_limit, &tmp, limit)) + return FALSE; + + gst_amc_jni_object_local_unref (env, tmp); + + if (!gst_amc_jni_call_object_method (env, err, buffer->object, + java_nio_buffer.set_position, &tmp, position)) + return FALSE; + + gst_amc_jni_object_local_unref (env, tmp); + + return TRUE; +} + +gboolean +gst_amc_buffer_clear (GstAmcBuffer * buffer, GError ** err) +{ + JNIEnv *env; + jobject tmp; + + g_return_val_if_fail (buffer != NULL, FALSE); + g_return_val_if_fail (buffer->object != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_object_method (env, err, buffer->object, + java_nio_buffer.clear, &tmp)) + return FALSE; + + gst_amc_jni_object_local_unref (env, tmp); + + return TRUE; +} diff --git a/sys/androidmedia/gstjniutils.h b/sys/androidmedia/gstjniutils.h index 0b25daa7fa..ef0f14b0b5 100644 --- a/sys/androidmedia/gstjniutils.h +++ b/sys/androidmedia/gstjniutils.h @@ -175,6 +175,12 @@ struct _GstAmcBuffer { gsize size; }; +gboolean gst_amc_buffer_get_position_and_limit (GstAmcBuffer * buffer, GError ** err, gint * position, gint * limit); +gboolean gst_amc_buffer_set_position_and_limit (GstAmcBuffer * buffer, GError ** err, gint position, gint limit); +gboolean gst_amc_buffer_clear (GstAmcBuffer * buffer, GError ** err); +GstAmcBuffer * gst_amc_buffer_copy (GstAmcBuffer * buffer); +void gst_amc_buffer_free (GstAmcBuffer * buffer); + gboolean gst_amc_jni_get_buffer_array (JNIEnv * env, GError ** err, jobject array, GstAmcBuffer ** buffers, gsize * n_buffers); void gst_amc_jni_free_buffer_array (JNIEnv * env, GstAmcBuffer * buffers, gsize n_buffers);