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.
This commit is contained in:
Sebastian Dröge 2015-05-27 23:34:14 +02:00
parent 360f0be2a8
commit a6fb482247
10 changed files with 623 additions and 316 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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;
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)

View file

@ -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;

View file

@ -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;
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)

View file

@ -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;

View file

@ -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;
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)

View file

@ -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;

View file

@ -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)
{
@ -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;
}

View file

@ -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);