From 6e84f26f469a05d6c5bd7777f580bf0f84de3350 Mon Sep 17 00:00:00 2001 From: Zhao Halley Date: Sat, 20 Apr 2013 13:12:41 +0800 Subject: [PATCH] Fix seek issue https://bugs.tizen.org/jira/browse/TIVI-708 [Reason] When decoder runs faster than downlink elements (postprocessing and sink), many video surface are cached in pools (queue element for example). Then decoding will fail because of no video surface available. During seek, data flows much fater to position to dedicted frame. It is easier to run into to above failure. [Resolution] 1. A condition wait is added to decode func, it waits up until a surface is available. It usually happens when a surface is recycled after use (renders to Window/Pixmap). 2. The start of seek event (GST_EVENT_FLUSH_START) will also wake up the above wait, even if there is still no surface available. The end of seek event (GST_EVENT_FLUSH_STOP) will disable such special case. to assist the above mechanism 3. The resumed decode func trigger retry on the previous video data. by the way, 1. The previous solution bases on a timeout wait, it isn't reliable during quick seek. 2. Gst event and status change is added in GST_INFO to ease debug. If you still meet seek issue, please send us the log wiht "export GST_DEBUG=vaapidecode:3" --- gst-libs/gst/vaapi/gstvaapidecoder.c | 18 +++++++--- gst-libs/gst/vaapi/gstvaapidecoder.h | 3 +- gst/vaapi/gstvaapidecode.c | 66 +++++++++++++++++++++++++----------- gst/vaapi/gstvaapidecode.h | 2 ++ tests/test-decode.c | 2 +- tests/test-subpicture.c | 2 +- 6 files changed, 67 insertions(+), 26 deletions(-) mode change 100644 => 100755 gst-libs/gst/vaapi/gstvaapidecoder.c mode change 100644 => 100755 gst-libs/gst/vaapi/gstvaapidecoder.h mode change 100644 => 100755 gst/vaapi/gstvaapidecode.c mode change 100644 => 100755 gst/vaapi/gstvaapidecode.h mode change 100644 => 100755 tests/test-decode.c mode change 100644 => 100755 tests/test-subpicture.c diff --git a/gst-libs/gst/vaapi/gstvaapidecoder.c b/gst-libs/gst/vaapi/gstvaapidecoder.c old mode 100644 new mode 100755 index 0df566d..489ae2f --- a/gst-libs/gst/vaapi/gstvaapidecoder.c +++ b/gst-libs/gst/vaapi/gstvaapidecoder.c @@ -90,7 +90,7 @@ pop_buffer(GstVaapiDecoder *decoder) } static GstVaapiDecoderStatus -decode_step(GstVaapiDecoder *decoder) +decode_step(GstVaapiDecoder *decoder, gboolean *try_again) { GstVaapiDecoderStatus status; GstBuffer *buffer; @@ -101,7 +101,15 @@ decode_step(GstVaapiDecoder *decoder) return status; do { - buffer = pop_buffer(decoder); + if (*try_again){ + buffer = gst_buffer_new(); + if (buffer){ + gst_buffer_set_data(buffer, NULL, 0); + } + *try_again = FALSE; + }else{ + buffer = pop_buffer(decoder); + } if (!buffer) return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; @@ -413,6 +421,7 @@ gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf) * gst_vaapi_decoder_get_surface: * @decoder: a #GstVaapiDecoder * @pstatus: return location for the decoder status, or %NULL + * @try_again: a #gboolean * * Flushes encoded buffers to the decoder and returns a decoded * surface, if any. @@ -424,7 +433,8 @@ gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf) GstVaapiSurfaceProxy * gst_vaapi_decoder_get_surface( GstVaapiDecoder *decoder, - GstVaapiDecoderStatus *pstatus + GstVaapiDecoderStatus *pstatus, + gboolean try_again ) { GstVaapiSurfaceProxy *proxy; @@ -438,7 +448,7 @@ gst_vaapi_decoder_get_surface( proxy = pop_surface(decoder); if (!proxy) { do { - status = decode_step(decoder); + status = decode_step(decoder, &try_again); } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS); proxy = pop_surface(decoder); } diff --git a/gst-libs/gst/vaapi/gstvaapidecoder.h b/gst-libs/gst/vaapi/gstvaapidecoder.h old mode 100644 new mode 100755 index ebcead9..0ebb92b --- a/gst-libs/gst/vaapi/gstvaapidecoder.h +++ b/gst-libs/gst/vaapi/gstvaapidecoder.h @@ -129,7 +129,8 @@ gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf); GstVaapiSurfaceProxy * gst_vaapi_decoder_get_surface( GstVaapiDecoder *decoder, - GstVaapiDecoderStatus *pstatus + GstVaapiDecoderStatus *pstatus, + gboolean try_again ); void diff --git a/gst/vaapi/gstvaapidecode.c b/gst/vaapi/gstvaapidecode.c old mode 100644 new mode 100755 index 309348e..0f00a53 --- a/gst/vaapi/gstvaapidecode.c +++ b/gst/vaapi/gstvaapidecode.c @@ -203,29 +203,27 @@ gst_vaapidecode_step(GstVaapiDecode *decode) GstBuffer *buffer; GstFlowReturn ret; GstClockTime timestamp; - gint64 end_time; + gboolean try_again = FALSE; for (;;) { - end_time = decode->render_time_base; - if (!end_time) - end_time = g_get_monotonic_time(); - end_time += GST_TIME_AS_USECONDS(decode->last_buffer_time); - end_time += G_TIME_SPAN_SECOND; - - proxy = gst_vaapi_decoder_get_surface(decode->decoder, &status); + proxy = gst_vaapi_decoder_get_surface(decode->decoder, &status, try_again); + try_again = FALSE; if (!proxy) { if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) { - gboolean was_signalled; g_mutex_lock(&decode->decoder_mutex); - was_signalled = g_cond_wait_until( + if (decode->escape_decoding){ + goto handle_escape_decoding; + } + g_cond_wait( &decode->decoder_ready, - &decode->decoder_mutex, - end_time + &decode->decoder_mutex ); + if (decode->escape_decoding){ + goto handle_escape_decoding; + } g_mutex_unlock(&decode->decoder_mutex); - if (was_signalled) - continue; - goto error_decode_timeout; + try_again = TRUE; + continue; } if (status != GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA) goto error_decode; @@ -275,10 +273,10 @@ gst_vaapidecode_step(GstVaapiDecode *decode) return GST_FLOW_OK; /* ERRORS */ -error_decode_timeout: +handle_escape_decoding: { - GST_DEBUG("decode timeout. Decoder required a VA surface but none " - "got available within one second"); + g_mutex_unlock(&decode->decoder_mutex); + GST_INFO("Escape decoding wait: flush event comes for seek etc."); return GST_FLOW_UNEXPECTED; } error_decode: @@ -518,12 +516,32 @@ gst_vaapidecode_finalize(GObject *object) G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object); } +typedef struct { + int trans; + char *trans_name; +} _GstStateChangeMap; +_GstStateChangeMap gst_state_change_string_map[] = { + {GST_STATE_CHANGE_NULL_TO_READY, "GST_STATE_CHANGE_NULL_TO_READY"}, + {GST_STATE_CHANGE_READY_TO_PAUSED, "GST_STATE_CHANGE_READY_TO_PAUSED",}, + {GST_STATE_CHANGE_PAUSED_TO_PLAYING,"GST_STATE_CHANGE_PAUSED_TO_PLAYING"}, + {GST_STATE_CHANGE_PLAYING_TO_PAUSED,"GST_STATE_CHANGE_PLAYING_TO_PAUSED"}, + {GST_STATE_CHANGE_PAUSED_TO_READY, "GST_STATE_CHANGE_PAUSED_TO_READY"}, + {GST_STATE_CHANGE_READY_TO_NULL, "GST_STATE_CHANGE_READY_TO_NULL"}, + {-1, "UNDEFINED_STATE_CHANGE"} +}; + static GstStateChangeReturn gst_vaapidecode_change_state(GstElement *element, GstStateChange transition) { GstVaapiDecode * const decode = GST_VAAPIDECODE(element); GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + int i; + for (i=0; iis_ready = TRUE; @@ -712,11 +730,20 @@ gst_vaapidecode_sink_event(GstPad *pad, GstEvent *event) { GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad)); - GST_DEBUG("handle sink event '%s'", GST_EVENT_TYPE_NAME(event)); + GST_INFO("handle sink event '%s'", GST_EVENT_TYPE_NAME(event)); /* Propagate event downstream */ switch (GST_EVENT_TYPE(event)) { + case GST_EVENT_FLUSH_START: + g_mutex_lock(&decode->decoder_mutex); + decode->escape_decoding = TRUE; + g_cond_signal(&decode->decoder_ready); + g_mutex_unlock(&decode->decoder_mutex); + break; case GST_EVENT_FLUSH_STOP: + g_mutex_lock(&decode->decoder_mutex); + decode->escape_decoding = FALSE; + g_mutex_unlock(&decode->decoder_mutex); gst_segment_init(&decode->segment, GST_FORMAT_UNDEFINED); if (decode->decoder) gst_vaapi_decoder_clear_buffer(decode->decoder); @@ -784,6 +811,7 @@ gst_vaapidecode_init(GstVaapiDecode *decode) decode->render_time_base = 0; decode->last_buffer_time = 0; decode->is_ready = FALSE; + decode->escape_decoding = FALSE; g_mutex_init(&decode->decoder_mutex); g_cond_init(&decode->decoder_ready); diff --git a/gst/vaapi/gstvaapidecode.h b/gst/vaapi/gstvaapidecode.h old mode 100644 new mode 100755 index c8b2583..ff27780 --- a/gst/vaapi/gstvaapidecode.h +++ b/gst/vaapi/gstvaapidecode.h @@ -76,6 +76,8 @@ struct _GstVaapiDecode { gint64 render_time_base; GstClockTime last_buffer_time; unsigned int is_ready : 1; + // escape decoding (blocked by hw resource) when there is _flush event, usually happens during seek. + unsigned int escape_decoding : 1; }; struct _GstVaapiDecodeClass { diff --git a/tests/test-decode.c b/tests/test-decode.c old mode 100644 new mode 100755 index f02e612..e173aaa --- a/tests/test-decode.c +++ b/tests/test-decode.c @@ -181,7 +181,7 @@ main(int argc, char *argv[]) if (!gst_vaapi_decoder_put_buffer(decoder, NULL)) g_error("could not send EOS to the decoder"); - proxy = gst_vaapi_decoder_get_surface(decoder, &status); + proxy = gst_vaapi_decoder_get_surface(decoder, &status, FALSE); if (!proxy) g_error("could not get decoded surface (decoder status %d)", status); diff --git a/tests/test-subpicture.c b/tests/test-subpicture.c old mode 100644 new mode 100755 index 7a65fe3..b9eae9a --- a/tests/test-subpicture.c +++ b/tests/test-subpicture.c @@ -157,7 +157,7 @@ main(int argc, char *argv[]) if (!gst_vaapi_decoder_put_buffer(decoder, NULL)) g_error("could not send EOS to the decoder"); - proxy = gst_vaapi_decoder_get_surface(decoder, &status); + proxy = gst_vaapi_decoder_get_surface(decoder, &status, FALSE); if (!proxy) g_error("could not get decoded surface (decoder status %d)", status); -- 2.7.4