static void gst_vaapidecode_purge (GstVaapiDecode * decode) { GstVaapiDecoderStatus status; if (!decode->decoder) return; status = gst_vaapi_decoder_flush (decode->decoder); if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) GST_INFO_OBJECT (decode, "failed to flush decoder (status %d)", status); /* Purge all decoded frames as we don't need them (e.g. flush and close) * Releasing the frames is important, otherwise the frames are not * freed. */ do { GstVideoCodecFrame *frame = NULL; status = gst_vaapi_decoder_get_frame_with_timeout (decode->decoder, &frame, 0); if (frame) { gst_video_decoder_release_frame (GST_VIDEO_DECODER (decode), frame); gst_video_codec_frame_unref (frame); } } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS); }
static GstFlowReturn gst_vaapidecode_finish (GstVideoDecoder * vdec) { GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); GstVaapiDecoderStatus status; GstFlowReturn ret; if (!decode->decoder) return GST_FLOW_OK; gst_vaapidecode_flush_output_adapter (decode); status = gst_vaapi_decoder_flush (decode->decoder); ret = gst_vaapidecode_push_all_decoded_frames (decode); if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) goto error_decoder_flush; return ret; /* ERRORS: */ error_decoder_flush: { GST_WARNING_OBJECT (decode, "failed to flush decoder (status %d)", status); return GST_FLOW_ERROR; } }
static gboolean gst_vaapidecode_internal_flush (GstVideoDecoder * vdec) { GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); GstVaapiDecoderStatus status; if (!decode->decoder) return TRUE; /* If there is something in GstVideoDecoder's output adapter, then submit the frame for decoding */ if (decode->current_frame_size) { gst_video_decoder_have_frame (vdec); decode->current_frame_size = 0; } status = gst_vaapi_decoder_flush (decode->decoder); if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { GST_WARNING_OBJECT (decode, "failed to flush decoder (status %d)", status); return FALSE; } return TRUE; }
static gpointer decoder_thread (gpointer data) { App *const app = data; GError *error = NULL; GstVaapiDecoderStatus status; GstVaapiSurfaceProxy *proxy; RenderFrame *rfp; GstBuffer *buffer; GstClockTime pts; gboolean got_surface, got_eos = FALSE; gint64 end_time; guint ofs; g_print ("Decoder thread started\n"); #define SEND_ERROR(...) \ do { \ error = g_error_new(APP_ERROR, APP_ERROR_DECODER, __VA_ARGS__); \ goto send_error; \ } while (0) pts = g_get_monotonic_time (); ofs = 0; while (!app->decoder_thread_cancel) { if (G_UNLIKELY (ofs == app->file_size)) buffer = NULL; else { const gsize size = MIN (4096, app->file_size - ofs); buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, app->file_data, app->file_size, ofs, size, NULL, NULL); if (!buffer) SEND_ERROR ("failed to allocate new buffer"); ofs += size; } if (!gst_vaapi_decoder_put_buffer (app->decoder, buffer)) SEND_ERROR ("failed to push buffer to decoder"); gst_buffer_replace (&buffer, NULL); get_surface: status = gst_vaapi_decoder_get_surface (app->decoder, &proxy); switch (status) { case GST_VAAPI_DECODER_STATUS_SUCCESS: gst_vaapi_surface_proxy_set_destroy_notify (proxy, (GDestroyNotify) decoder_release, app); rfp = render_frame_new (); if (!rfp) SEND_ERROR ("failed to allocate render frame"); rfp->proxy = proxy; rfp->pts = pts; rfp->duration = app->frame_duration; pts += app->frame_duration; g_async_queue_push (app->decoder_queue, rfp); break; case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA: /* nothing to do, just continue to the next iteration */ break; case GST_VAAPI_DECODER_STATUS_END_OF_STREAM: gst_vaapi_decoder_flush (app->decoder); if (got_eos) goto send_eos; got_eos = TRUE; break; case GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE: end_time = g_get_monotonic_time () + G_TIME_SPAN_SECOND; g_mutex_lock (&app->mutex); got_surface = g_cond_wait_until (&app->decoder_ready, &app->mutex, end_time); g_mutex_unlock (&app->mutex); if (got_surface) goto get_surface; SEND_ERROR ("failed to acquire a surface within one second"); break; default: SEND_ERROR ("%s", get_decoder_status_string (status)); break; } } return NULL; #undef SEND_ERROR send_eos: app_send_eos (app); return NULL; send_error: app_send_error (app, error); return NULL; }