amc: MediaCodec::getOutputBuffer() can return NULL without exception

Happens when doing zerocopy rendering, or when passing a wrong index to it.
Handle this properly for zerocopy rendering, fail properly for the other
cases.

https://bugzilla.gnome.org/show_bug.cgi?id=760961
This commit is contained in:
Sebastian Dröge 2016-01-22 16:13:45 +02:00
parent c87a7e2667
commit 5a3744e86c
4 changed files with 72 additions and 17 deletions

View file

@ -369,21 +369,23 @@ gst_amc_codec_get_output_buffer (GstAmcCodec * codec, gint index, GError ** err)
media_codec.get_output_buffer, &buffer, index)) media_codec.get_output_buffer, &buffer, index))
goto done; goto done;
ret = g_new0 (GstAmcBuffer, 1); if (buffer != NULL) {
ret->object = gst_amc_jni_object_make_global (env, buffer); ret = g_new0 (GstAmcBuffer, 1);
if (!ret->object) { ret->object = gst_amc_jni_object_make_global (env, buffer);
gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, if (!ret->object) {
GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference"); gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
goto error; GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference");
} goto error;
}
ret->data = (*env)->GetDirectBufferAddress (env, ret->object); ret->data = (*env)->GetDirectBufferAddress (env, ret->object);
if (!ret->data) { if (!ret->data) {
gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address"); GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address");
goto error; goto error;
}
ret->size = (*env)->GetDirectBufferCapacity (env, ret->object);
} }
ret->size = (*env)->GetDirectBufferCapacity (env, ret->object);
done: done:

View file

@ -493,8 +493,10 @@ retry:
is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM); is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM);
buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err); buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err);
if (!buf) if (err)
goto failed_to_get_output_buffer; goto failed_to_get_output_buffer;
else if (!buf)
goto got_null_output_buffer;
if (buffer_info.size > 0) { if (buffer_info.size > 0) {
GstBuffer *outbuf; GstBuffer *outbuf;
@ -699,6 +701,22 @@ failed_to_get_output_buffer:
g_mutex_unlock (&self->drain_lock); g_mutex_unlock (&self->drain_lock);
return; return;
} }
got_null_output_buffer:
{
GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
("Got no output buffer"));
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;
}
invalid_buffer_size: invalid_buffer_size:
{ {
GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),

View file

@ -1271,9 +1271,12 @@ retry:
is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM); is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM);
buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err); buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err);
if (!buf) if (err)
goto failed_to_get_output_buffer; goto failed_to_get_output_buffer;
if (self->codec_config != AMC_CODEC_CONFIG_WITH_SURFACE && !buf)
goto got_null_output_buffer;
if (frame if (frame
&& (deadline = && (deadline =
gst_video_decoder_get_max_decode_time (GST_VIDEO_DECODER (self), gst_video_decoder_get_max_decode_time (GST_VIDEO_DECODER (self),
@ -1574,6 +1577,21 @@ failed_to_get_output_buffer:
return; return;
} }
got_null_output_buffer:
{
GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
("Got no output buffer"));
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: invalid_buffer:
{ {
GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),

View file

@ -1023,8 +1023,10 @@ process_buffer:
is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM); is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM);
buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err); buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err);
if (!buf) if (err)
goto failed_to_get_output_buffer; goto failed_to_get_output_buffer;
else if (!buf)
goto got_null_output_buffer;
flow_ret = flow_ret =
gst_amc_video_enc_handle_output_frame (self, buf, &buffer_info, frame); gst_amc_video_enc_handle_output_frame (self, buf, &buffer_info, frame);
@ -1147,7 +1149,22 @@ failed_to_get_output_buffer:
GST_ELEMENT_ERROR_FROM_ERROR (self, err); GST_ELEMENT_ERROR_FROM_ERROR (self, err);
gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self)); gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED; 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;
}
got_null_output_buffer:
{
GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
("Got no output buffer"));
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); GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
g_mutex_lock (&self->drain_lock); g_mutex_lock (&self->drain_lock);
self->draining = FALSE; self->draining = FALSE;