summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2015-05-27 23:34:14 +0200
committerSebastian Dröge <sebastian@centricular.com>2015-05-31 21:27:27 +0200
commita6fb4822477dffb8bcf0e4183a212e559e3bd5b6 (patch)
treea63c12e4a9341fdcf91e4a9d3cb03b93ab01d606 /sys
parent360f0be2a80ca11e1b3b0c087367c48cb18c4c3e (diff)
downloadgstreamer-plugins-bad-a6fb4822477dffb8bcf0e4183a212e559e3bd5b6.tar.gz
androidmedia: Conditionally use get_{input,output}_buffer() Android 21 APIs
Also properly set limit/position on byte buffer, some codecs prefer to have correct values there.
Diffstat (limited to 'sys')
-rw-r--r--sys/androidmedia/gstamc.c219
-rw-r--r--sys/androidmedia/gstamc.h8
-rw-r--r--sys/androidmedia/gstamcaudiodec.c168
-rw-r--r--sys/androidmedia/gstamcaudiodec.h2
-rw-r--r--sys/androidmedia/gstamcvideodec.c194
-rw-r--r--sys/androidmedia/gstamcvideodec.h2
-rw-r--r--sys/androidmedia/gstamcvideoenc.c165
-rw-r--r--sys/androidmedia/gstamcvideoenc.h2
-rw-r--r--sys/androidmedia/gstjniutils.c179
-rw-r--r--sys/androidmedia/gstjniutils.h6
10 files changed, 626 insertions, 319 deletions
diff --git a/sys/androidmedia/gstamc.c b/sys/androidmedia/gstamc.c
index 8080de401..88f81a7ab 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 e216039bd..88d49fbae 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 ca090c3c9..bc8190740 100644
--- a/sys/androidmedia/gstamcaudiodec.c
+++ b/sys/androidmedia/gstamcaudiodec.c
@@ -7,6 +7,8 @@
* Copyright (C) 2012, Collabora Ltd.
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
+ * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
+ *
* 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;
-
- 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;
+ 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;
+
+ 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 9fff22105..04e973426 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 a2ac65e1c..33bed1c3c 100644
--- a/sys/androidmedia/gstamcvideodec.c
+++ b/sys/androidmedia/gstamcvideodec.c
@@ -9,6 +9,8 @@
*
* Copyright (C) 2012, Rafaël Carré <funman@videolanorg>
*
+ * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
+ *
* 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;
-
- 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;
+ 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;
+
+ 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 a4ef11cff..c6c2b4f49 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 4384c7624..8a6dd44b8 100644
--- a/sys/androidmedia/gstamcvideoenc.c
+++ b/sys/androidmedia/gstamcvideoenc.c
@@ -10,6 +10,8 @@
* Copyright (C) 2013, Lemote Ltd.
* Author: Chen Jie <chenj@lemote.com>
*
+ * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
+ *
* 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;
+
+ 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_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;
+ }
+ }
- 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;
+ 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 queue input buffer");
- if (self->flushing) {
- g_clear_error (&err);
- ret = GST_FLOW_FLUSHING;
- } 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;
- }
+ 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;
} 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 60a368703..f16924897 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 02bc3a821..b2be36655 100644
--- a/sys/androidmedia/gstjniutils.c
+++ b/sys/androidmedia/gstjniutils.c
@@ -6,6 +6,7 @@
* Copyright (C) 2014, Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2014, Collabora Ltd.
* Author: Matthieu Bouron <matthieu.bouron@collabora.com>
+ * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
*
* 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)
{
@@ -548,6 +557,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)
{
jsize n_vms;
@@ -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 0b25daa7f..ef0f14b0b 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);