static GstFlowReturn gst_vaapidecode_step(GstVaapiDecode *decode) { GstVaapiSurfaceProxy *proxy; GstVaapiDecoderStatus status; GstBuffer *buffer; GstFlowReturn ret; GstClockTime timestamp; gint64 end_time; 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); 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( decode->decoder_ready, decode->decoder_mutex, end_time ); g_mutex_unlock(decode->decoder_mutex); if (was_signalled) continue; goto error_decode_timeout; } if (status != GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA) goto error_decode; /* More data is needed */ break; } g_object_weak_ref( G_OBJECT(proxy), (GWeakNotify)gst_vaapidecode_release, decode ); buffer = gst_vaapi_video_buffer_new(decode->display); if (!buffer) goto error_create_buffer; timestamp = GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy); if (!decode->render_time_base) decode->render_time_base = g_get_monotonic_time(); decode->last_buffer_time = timestamp; GST_BUFFER_TIMESTAMP(buffer) = timestamp; GST_BUFFER_DURATION(buffer) = GST_VAAPI_SURFACE_PROXY_DURATION(proxy); gst_buffer_set_caps(buffer, GST_PAD_CAPS(decode->srcpad)); if (GST_VAAPI_SURFACE_PROXY_TFF(proxy)) GST_BUFFER_FLAG_SET(buffer, GST_VIDEO_BUFFER_TFF); gst_vaapi_video_buffer_set_surface_proxy( GST_VAAPI_VIDEO_BUFFER(buffer), proxy ); ret = gst_pad_push(decode->srcpad, buffer); if (ret != GST_FLOW_OK) goto error_commit_buffer; g_object_unref(proxy); } return GST_FLOW_OK; /* ERRORS */ error_decode_timeout: { GST_DEBUG("decode timeout. Decoder required a VA surface but none " "got available within one second"); return GST_FLOW_UNEXPECTED; } error_decode: { GST_DEBUG("decode error %d", status); switch (status) { case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC: case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE: case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT: ret = GST_FLOW_NOT_SUPPORTED; break; default: ret = GST_FLOW_UNEXPECTED; break; } return ret; } error_create_buffer: { const GstVaapiID surface_id = gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy)); GST_DEBUG("video sink failed to create video buffer for proxy'ed " "surface %" GST_VAAPI_ID_FORMAT " (error %d)", GST_VAAPI_ID_ARGS(surface_id), ret); g_object_unref(proxy); return GST_FLOW_UNEXPECTED; } error_commit_buffer: { GST_DEBUG("video sink rejected the video buffer (error %d)", ret); g_object_unref(proxy); return GST_FLOW_UNEXPECTED; } }
static GstFlowReturn gst_vaapi_video_buffer_pool_alloc_buffer (GstBufferPool * pool, GstBuffer ** out_buffer_ptr, GstBufferPoolAcquireParams * params) { GstVaapiVideoBufferPoolPrivate *const priv = GST_VAAPI_VIDEO_BUFFER_POOL (pool)->priv; GstVaapiVideoBufferPoolAcquireParams *const priv_params = (GstVaapiVideoBufferPoolAcquireParams *) params; GstVaapiVideoMeta *meta; GstMemory *mem; GstBuffer *buffer; const gboolean alloc_vaapi_video_meta = !params || !(params->flags & GST_VAAPI_VIDEO_BUFFER_POOL_ACQUIRE_FLAG_NO_ALLOC); if (!priv->allocator) goto error_no_allocator; if (alloc_vaapi_video_meta) { meta = gst_vaapi_video_meta_new (priv->display); if (!meta) goto error_create_meta; buffer = gst_vaapi_video_buffer_new (meta); } else { meta = NULL; buffer = gst_vaapi_video_buffer_new_empty (); } if (!buffer) goto error_create_buffer; if (priv_params && priv_params->proxy) gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy); if (priv->use_dmabuf_memory) mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta); else mem = gst_vaapi_video_memory_new (priv->allocator, meta); if (!mem) goto error_create_memory; gst_vaapi_video_meta_replace (&meta, NULL); gst_buffer_append_memory (buffer, mem); if (priv->options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META) { GstVideoInfo *const vip = &priv->vmeta_vinfo; GstVideoMeta *vmeta; vmeta = gst_buffer_add_video_meta_full (buffer, 0, GST_VIDEO_INFO_FORMAT (vip), GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip), GST_VIDEO_INFO_N_PLANES (vip), &GST_VIDEO_INFO_PLANE_OFFSET (vip, 0), &GST_VIDEO_INFO_PLANE_STRIDE (vip, 0)); if (GST_VAAPI_IS_VIDEO_MEMORY (mem)) { vmeta->map = gst_video_meta_map_vaapi_memory; vmeta->unmap = gst_video_meta_unmap_vaapi_memory; } } #if (USE_GLX || USE_EGL) if (priv->options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD) gst_buffer_add_texture_upload_meta (buffer); #endif *out_buffer_ptr = buffer; return GST_FLOW_OK; /* ERRORS */ error_no_allocator: { GST_ERROR_OBJECT (pool, "no GstAllocator in buffer pool"); return GST_FLOW_ERROR; } error_create_meta: { GST_ERROR_OBJECT (pool, "failed to allocate vaapi video meta"); return GST_FLOW_ERROR; } error_create_buffer: { GST_ERROR_OBJECT (pool, "failed to create video buffer"); gst_vaapi_video_meta_unref (meta); return GST_FLOW_ERROR; } error_create_memory: { GST_ERROR_OBJECT (pool, "failed to create video memory"); gst_buffer_unref (buffer); gst_vaapi_video_meta_unref (meta); return GST_FLOW_ERROR; } }