gstreamer/sys/androidmedia/jni/gstamc-codec-jni.c
Jan Schmidt cfe318ea03 androidmedia: Permit Codec surface to be NULL
The AMC encoder wrapper doesn't support input surfaces yet,
and passes NULL when configuring the underlying codec.

This was broken in commit 7fcf3e
Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/1102
2020-02-09 02:19:12 +11:00

966 lines
26 KiB
C

/*
* Copyright (C) 2012,2018 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
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstjniutils.h"
#include "../gstamc-codec.h"
#include "../gstamc-constants.h"
#include "gstamc-internal-jni.h"
#include "gstamcsurfacetexture-jni.h"
#include "gstamcsurface.h"
struct _GstAmcCodec
{
jobject object; /* global reference */
RealBuffer *input_buffers, *output_buffers;
gsize n_input_buffers, n_output_buffers;
GstAmcSurface *surface;
gboolean is_encoder;
};
static struct
{
jclass klass;
jmethodID configure;
jmethodID create_by_codec_name;
jmethodID dequeue_input_buffer;
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;
jmethodID release_output_buffer;
jmethodID start;
jmethodID stop;
} media_codec;
static struct
{
jclass klass;
jmethodID constructor;
jfieldID flags;
jfieldID offset;
jfieldID presentation_time_us;
jfieldID size;
} media_codec_buffer_info;
static struct
{
jclass klass;
jmethodID get_limit, get_position;
jmethodID set_limit, set_position;
jmethodID clear;
} java_nio_buffer;
gboolean
gst_amc_codec_static_init (void)
{
gboolean ret = TRUE;
JNIEnv *env;
jclass tmp;
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;
}
tmp = (*env)->FindClass (env, "android/media/MediaCodec$BufferInfo");
if (!tmp) {
ret = FALSE;
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get codec buffer info class");
goto done;
}
media_codec_buffer_info.klass = (*env)->NewGlobalRef (env, tmp);
if (!media_codec_buffer_info.klass) {
ret = FALSE;
GST_ERROR ("Failed to get codec buffer info class global reference");
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionDescribe (env);
(*env)->ExceptionClear (env);
}
goto done;
}
(*env)->DeleteLocalRef (env, tmp);
tmp = NULL;
media_codec_buffer_info.constructor =
(*env)->GetMethodID (env, media_codec_buffer_info.klass, "<init>", "()V");
media_codec_buffer_info.flags =
(*env)->GetFieldID (env, media_codec_buffer_info.klass, "flags", "I");
media_codec_buffer_info.offset =
(*env)->GetFieldID (env, media_codec_buffer_info.klass, "offset", "I");
media_codec_buffer_info.presentation_time_us =
(*env)->GetFieldID (env, media_codec_buffer_info.klass,
"presentationTimeUs", "J");
media_codec_buffer_info.size =
(*env)->GetFieldID (env, media_codec_buffer_info.klass, "size", "I");
if (!media_codec_buffer_info.constructor || !media_codec_buffer_info.flags
|| !media_codec_buffer_info.offset
|| !media_codec_buffer_info.presentation_time_us
|| !media_codec_buffer_info.size) {
ret = FALSE;
GST_ERROR ("Failed to get buffer info methods and fields");
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionDescribe (env);
(*env)->ExceptionClear (env);
}
goto done;
}
tmp = (*env)->FindClass (env, "android/media/MediaCodec");
if (!tmp) {
ret = FALSE;
GST_ERROR ("Failed to get codec class");
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionDescribe (env);
(*env)->ExceptionClear (env);
}
goto done;
}
media_codec.klass = (*env)->NewGlobalRef (env, tmp);
if (!media_codec.klass) {
ret = FALSE;
GST_ERROR ("Failed to get codec class global reference");
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionDescribe (env);
(*env)->ExceptionClear (env);
}
goto done;
}
(*env)->DeleteLocalRef (env, tmp);
tmp = NULL;
media_codec.create_by_codec_name =
(*env)->GetStaticMethodID (env, media_codec.klass, "createByCodecName",
"(Ljava/lang/String;)Landroid/media/MediaCodec;");
media_codec.configure =
(*env)->GetMethodID (env, media_codec.klass, "configure",
"(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V");
media_codec.dequeue_input_buffer =
(*env)->GetMethodID (env, media_codec.klass, "dequeueInputBuffer",
"(J)I");
media_codec.dequeue_output_buffer =
(*env)->GetMethodID (env, media_codec.klass, "dequeueOutputBuffer",
"(Landroid/media/MediaCodec$BufferInfo;J)I");
media_codec.flush =
(*env)->GetMethodID (env, media_codec.klass, "flush", "()V");
media_codec.get_input_buffers =
(*env)->GetMethodID (env, media_codec.klass, "getInputBuffers",
"()[Ljava/nio/ByteBuffer;");
media_codec.get_output_buffers =
(*env)->GetMethodID (env, media_codec.klass, "getOutputBuffers",
"()[Ljava/nio/ByteBuffer;");
media_codec.get_output_format =
(*env)->GetMethodID (env, media_codec.klass, "getOutputFormat",
"()Landroid/media/MediaFormat;");
media_codec.queue_input_buffer =
(*env)->GetMethodID (env, media_codec.klass, "queueInputBuffer",
"(IIIJI)V");
media_codec.release =
(*env)->GetMethodID (env, media_codec.klass, "release", "()V");
media_codec.release_output_buffer =
(*env)->GetMethodID (env, media_codec.klass, "releaseOutputBuffer",
"(IZ)V");
media_codec.start =
(*env)->GetMethodID (env, media_codec.klass, "start", "()V");
media_codec.stop =
(*env)->GetMethodID (env, media_codec.klass, "stop", "()V");
if (!media_codec.configure ||
!media_codec.create_by_codec_name ||
!media_codec.dequeue_input_buffer ||
!media_codec.dequeue_output_buffer ||
!media_codec.flush ||
!media_codec.get_input_buffers ||
!media_codec.get_output_buffers ||
!media_codec.get_output_format ||
!media_codec.queue_input_buffer ||
!media_codec.release ||
!media_codec.release_output_buffer ||
!media_codec.start || !media_codec.stop) {
ret = FALSE;
GST_ERROR ("Failed to get codec methods");
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionDescribe (env);
(*env)->ExceptionClear (env);
}
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);
done:
if (tmp)
(*env)->DeleteLocalRef (env, tmp);
tmp = NULL;
return ret;
}
static void
gst_amc_jni_free_buffer_array (JNIEnv * env, RealBuffer * buffers,
gsize n_buffers)
{
jsize i;
g_return_if_fail (buffers != NULL);
for (i = 0; i < n_buffers; i++) {
if (buffers[i].object)
gst_amc_jni_object_unref (env, buffers[i].object);
}
g_free (buffers);
}
static gboolean
gst_amc_jni_get_buffer_array (JNIEnv * env, GError ** err, jobject array,
RealBuffer ** buffers_, gsize * n_buffers)
{
RealBuffer **buffers = (RealBuffer **) buffers_;
jsize i;
*n_buffers = (*env)->GetArrayLength (env, array);
*buffers = g_new0 (RealBuffer, *n_buffers);
for (i = 0; i < *n_buffers; i++) {
jobject buffer = NULL;
buffer = (*env)->GetObjectArrayElement (env, array, i);
if ((*env)->ExceptionCheck (env)) {
gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
GST_LIBRARY_ERROR_FAILED, "Failed to get buffer %d", i);
goto error;
}
/* NULL buffers are not a problem and are happening when we configured
* a surface as input/output */
if (!buffer)
continue;
(*buffers)[i].object = gst_amc_jni_object_make_global (env, buffer);
if (!(*buffers)[i].object) {
gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
GST_LIBRARY_ERROR_FAILED,
"Failed to create global buffer reference %d", i);
goto error;
}
(*buffers)[i].data =
(*env)->GetDirectBufferAddress (env, (*buffers)[i].object);
if (!(*buffers)[i].data) {
gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address %d", i);
goto error;
}
(*buffers)[i].size =
(*env)->GetDirectBufferCapacity (env, (*buffers)[i].object);
}
return TRUE;
error:
if (*buffers)
gst_amc_jni_free_buffer_array (env, *buffers, *n_buffers);
*buffers = NULL;
*n_buffers = 0;
return FALSE;
}
void
gst_amc_buffer_free (GstAmcBuffer * buffer_)
{
RealBuffer *buffer = (RealBuffer *) 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);
}
static GstAmcBuffer *
gst_amc_buffer_copy (RealBuffer * buffer)
{
JNIEnv *env;
RealBuffer *ret;
g_return_val_if_fail (buffer != NULL, NULL);
env = gst_amc_jni_get_env ();
ret = g_new0 (RealBuffer, 1);
ret->object = gst_amc_jni_object_ref (env, buffer->object);
ret->data = buffer->data;
ret->size = buffer->size;
return (GstAmcBuffer *) ret;
}
gboolean
gst_amc_buffer_get_position_and_limit (RealBuffer * buffer_, GError ** err,
gint * position, gint * limit)
{
RealBuffer *buffer = (RealBuffer *) buffer_;
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)
{
RealBuffer *buffer = (RealBuffer *) buffer_;
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;
}
GstAmcCodec *
gst_amc_codec_new (const gchar * name, gboolean is_encoder, GError ** err)
{
JNIEnv *env;
GstAmcCodec *codec = NULL;
jstring name_str;
jobject object = NULL;
g_return_val_if_fail (name != NULL, NULL);
env = gst_amc_jni_get_env ();
name_str = gst_amc_jni_string_from_gchar (env, err, FALSE, name);
if (!name_str) {
goto error;
}
codec = g_slice_new0 (GstAmcCodec);
codec->is_encoder = is_encoder;
if (!gst_amc_jni_call_static_object_method (env, err, media_codec.klass,
media_codec.create_by_codec_name, &object, name_str))
goto error;
codec->object = gst_amc_jni_object_make_global (env, object);
object = NULL;
if (!codec->object) {
gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
GST_LIBRARY_ERROR_SETTINGS, "Failed to create global codec reference");
goto error;
}
done:
if (name_str)
gst_amc_jni_object_local_unref (env, name_str);
name_str = NULL;
return codec;
error:
if (codec)
g_slice_free (GstAmcCodec, codec);
codec = NULL;
goto done;
}
void
gst_amc_codec_free (GstAmcCodec * codec)
{
JNIEnv *env;
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;
g_clear_object (&codec->surface);
gst_amc_jni_object_unref (env, codec->object);
g_slice_free (GstAmcCodec, codec);
}
gboolean
gst_amc_codec_configure (GstAmcCodec * codec, GstAmcFormat * format,
GstAmcSurfaceTexture * surface, GError ** err)
{
JNIEnv *env;
gint flags = 0;
g_return_val_if_fail (codec != NULL, FALSE);
g_return_val_if_fail (format != NULL, FALSE);
g_return_val_if_fail (surface == NULL
|| GST_IS_AMC_SURFACE_TEXTURE_JNI (surface), FALSE);
env = gst_amc_jni_get_env ();
if (surface) {
g_object_unref (codec->surface);
codec->surface =
gst_amc_surface_new ((GstAmcSurfaceTextureJNI *) surface, err);
if (!codec->surface)
return FALSE;
}
if (codec->is_encoder)
flags = 1;
return gst_amc_jni_call_void_method (env, err, codec->object,
media_codec.configure, format->object,
codec->surface ? codec->surface->jobject : NULL, NULL, flags);
}
GstAmcFormat *
gst_amc_codec_get_output_format (GstAmcCodec * codec, GError ** err)
{
JNIEnv *env;
GstAmcFormat *ret = NULL;
jobject object = NULL;
g_return_val_if_fail (codec != NULL, NULL);
env = gst_amc_jni_get_env ();
if (!gst_amc_jni_call_object_method (env, err, codec->object,
media_codec.get_output_format, &object))
goto done;
ret = g_slice_new0 (GstAmcFormat);
ret->object = gst_amc_jni_object_make_global (env, object);
if (!ret->object) {
gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
GST_LIBRARY_ERROR_SETTINGS, "Failed to create global format reference");
g_slice_free (GstAmcFormat, ret);
ret = NULL;
}
done:
return ret;
}
static RealBuffer *
gst_amc_codec_get_input_buffers (GstAmcCodec * codec, gsize * n_buffers,
GError ** err)
{
JNIEnv *env;
jobject input_buffers = NULL;
RealBuffer *ret = NULL;
g_return_val_if_fail (codec != NULL, NULL);
g_return_val_if_fail (n_buffers != NULL, NULL);
*n_buffers = 0;
env = gst_amc_jni_get_env ();
if (!gst_amc_jni_call_object_method (env, err, codec->object,
media_codec.get_input_buffers, &input_buffers))
goto done;
gst_amc_jni_get_buffer_array (env, err, input_buffers, &ret, n_buffers);
done:
if (input_buffers)
gst_amc_jni_object_local_unref (env, input_buffers);
return ret;
}
static RealBuffer *
gst_amc_codec_get_output_buffers (GstAmcCodec * codec, gsize * n_buffers,
GError ** err)
{
JNIEnv *env;
jobject output_buffers = NULL;
RealBuffer *ret = NULL;
g_return_val_if_fail (codec != NULL, NULL);
g_return_val_if_fail (n_buffers != NULL, NULL);
*n_buffers = 0;
env = gst_amc_jni_get_env ();
if (!gst_amc_jni_call_object_method (env, err, codec->object,
media_codec.get_output_buffers, &output_buffers))
goto done;
gst_amc_jni_get_buffer_array (env, err, output_buffers, &ret, n_buffers);
done:
if (output_buffers)
gst_amc_jni_object_local_unref (env, output_buffers);
return ret;
}
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 ();
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
gst_amc_codec_stop (GstAmcCodec * codec, GError ** err)
{
JNIEnv *env;
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);
}
gboolean
gst_amc_codec_flush (GstAmcCodec * codec, GError ** err)
{
JNIEnv *env;
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,
media_codec.flush);
}
gboolean
gst_amc_codec_release (GstAmcCodec * codec, GError ** err)
{
JNIEnv *env;
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 *
gst_amc_codec_get_output_buffer (GstAmcCodec * codec, gint index, GError ** err)
{
JNIEnv *env;
jobject buffer = NULL;
RealBuffer *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);
if (codec->output_buffers[index].object)
return gst_amc_buffer_copy (&codec->output_buffers[index]);
else
return NULL;
}
if (!gst_amc_jni_call_object_method (env, err, codec->object,
media_codec.get_output_buffer, &buffer, index))
goto done;
if (buffer != NULL) {
ret = g_new0 (RealBuffer, 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 (GstAmcBuffer *) ret;
error:
if (ret->object)
gst_amc_jni_object_unref (env, ret->object);
g_free (ret);
return NULL;
}
GstAmcBuffer *
gst_amc_codec_get_input_buffer (GstAmcCodec * codec, gint index, GError ** err)
{
JNIEnv *env;
jobject buffer = NULL;
RealBuffer *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_input_buffer) {
g_return_val_if_fail (index < codec->n_input_buffers && index >= 0, NULL);
if (codec->input_buffers[index].object)
return gst_amc_buffer_copy (&codec->input_buffers[index]);
else
return NULL;
}
if (!gst_amc_jni_call_object_method (env, err, codec->object,
media_codec.get_input_buffer, &buffer, index))
goto done;
if (buffer != NULL) {
ret = g_new0 (RealBuffer, 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 (GstAmcBuffer *) ret;
error:
if (ret->object)
gst_amc_jni_object_unref (env, ret->object);
g_free (ret);
return NULL;
}
gint
gst_amc_codec_dequeue_input_buffer (GstAmcCodec * codec, gint64 timeoutUs,
GError ** err)
{
JNIEnv *env;
gint ret = G_MININT;
g_return_val_if_fail (codec != NULL, G_MININT);
env = gst_amc_jni_get_env ();
if (!gst_amc_jni_call_int_method (env, err, codec->object,
media_codec.dequeue_input_buffer, &ret, timeoutUs))
return G_MININT;
return ret;
}
static gboolean
gst_amc_codec_fill_buffer_info (JNIEnv * env, jobject buffer_info,
GstAmcBufferInfo * info, GError ** err)
{
g_return_val_if_fail (buffer_info != NULL, FALSE);
if (!gst_amc_jni_get_int_field (env, err, buffer_info,
media_codec_buffer_info.flags, &info->flags))
return FALSE;
if (!gst_amc_jni_get_int_field (env, err, buffer_info,
media_codec_buffer_info.offset, &info->offset))
return FALSE;
if (!gst_amc_jni_get_long_field (env, err, buffer_info,
media_codec_buffer_info.presentation_time_us,
&info->presentation_time_us))
return FALSE;
if (!gst_amc_jni_get_int_field (env, err, buffer_info,
media_codec_buffer_info.size, &info->size))
return FALSE;
return TRUE;
}
gint
gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec,
GstAmcBufferInfo * info, gint64 timeoutUs, GError ** err)
{
JNIEnv *env;
gint ret = G_MININT;
jobject info_o = NULL;
g_return_val_if_fail (codec != NULL, G_MININT);
env = gst_amc_jni_get_env ();
info_o =
gst_amc_jni_new_object (env, err, FALSE, media_codec_buffer_info.klass,
media_codec_buffer_info.constructor);
if (!info_o)
goto done;
if (!gst_amc_jni_call_int_method (env, err, codec->object,
media_codec.dequeue_output_buffer, &ret, info_o, timeoutUs)) {
ret = G_MININT;
goto done;
}
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;
}
done:
if (info_o)
gst_amc_jni_object_local_unref (env, info_o);
info_o = NULL;
return ret;
}
gboolean
gst_amc_codec_queue_input_buffer (GstAmcCodec * codec, gint index,
const GstAmcBufferInfo * info, GError ** err)
{
JNIEnv *env;
g_return_val_if_fail (codec != NULL, FALSE);
g_return_val_if_fail (info != NULL, FALSE);
env = gst_amc_jni_get_env ();
return gst_amc_jni_call_void_method (env, err, codec->object,
media_codec.queue_input_buffer, index, info->offset, info->size,
info->presentation_time_us, info->flags);
}
gboolean
gst_amc_codec_release_output_buffer (GstAmcCodec * codec, gint index,
gboolean render, GError ** err)
{
JNIEnv *env;
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,
media_codec.release_output_buffer, index, render);
}
GstAmcSurfaceTexture *
gst_amc_codec_new_surface_texture (GError ** err)
{
return (GstAmcSurfaceTexture *) gst_amc_surface_texture_jni_new (err);
}