| /* GStreamer Intel MSDK plugin |
| * Copyright (c) 2018, Intel Corporation |
| * Copyright (c) 2018, Igalia S.L. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * 3. Neither the name of the copyright holder nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGDECE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
| * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "gstmsdkcontextutil.h" |
| |
| GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT); |
| |
| static void |
| _init_context_debug (void) |
| { |
| #ifndef GST_DISABLE_GST_DEBUG |
| static volatile gsize _init = 0; |
| |
| if (g_once_init_enter (&_init)) { |
| GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT"); |
| g_once_init_leave (&_init, 1); |
| } |
| #endif |
| } |
| |
| static gboolean |
| context_pad_query (const GValue * item, GValue * value, gpointer user_data) |
| { |
| GstPad *const pad = g_value_get_object (item); |
| GstQuery *const query = user_data; |
| |
| if (gst_pad_peer_query (pad, query)) { |
| g_value_set_boolean (value, TRUE); |
| return FALSE; |
| } |
| |
| GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "context pad peer query failed"); |
| return TRUE; |
| } |
| |
| static gboolean |
| _gst_context_run_query (GstElement * element, GstQuery * query, |
| GstPadDirection direction) |
| { |
| GstIteratorFoldFunction const func = context_pad_query; |
| GstIterator *it; |
| GValue res = { 0 }; |
| |
| g_value_init (&res, G_TYPE_BOOLEAN); |
| g_value_set_boolean (&res, FALSE); |
| |
| /* Ask neighbour */ |
| if (direction == GST_PAD_SRC) |
| it = gst_element_iterate_src_pads (element); |
| else |
| it = gst_element_iterate_sink_pads (element); |
| |
| while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC) |
| gst_iterator_resync (it); |
| gst_iterator_free (it); |
| |
| return g_value_get_boolean (&res); |
| } |
| |
| static gboolean |
| _gst_context_get_from_query (GstElement * element, GstQuery * query, |
| GstPadDirection direction) |
| { |
| GstContext *ctxt; |
| |
| if (!_gst_context_run_query (element, query, direction)) |
| return FALSE; |
| |
| gst_query_parse_context (query, &ctxt); |
| if (!ctxt) |
| return FALSE; |
| |
| GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, |
| "found context (%" GST_PTR_FORMAT ") in %s query", ctxt, |
| direction == GST_PAD_SRC ? "downstream" : "upstream"); |
| |
| gst_element_set_context (element, ctxt); |
| return TRUE; |
| } |
| |
| static void |
| _gst_context_query (GstElement * element, const gchar * context_type) |
| { |
| GstQuery *query; |
| GstMessage *msg; |
| |
| /* 2) Query downstream with GST_QUERY_CONTEXT for the context and |
| check if downstream already has a context of the specific |
| type */ |
| |
| /* 3) Query upstream with GST_QUERY_CONTEXT for the context and |
| check if upstream already has a context of the specific |
| type */ |
| query = gst_query_new_context (context_type); |
| if (_gst_context_get_from_query (element, query, GST_PAD_SRC)) |
| goto found; |
| if (_gst_context_get_from_query (element, query, GST_PAD_SINK)) |
| goto found; |
| |
| /* 4) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with |
| the required context types and afterwards check if an |
| usable context was set now as in 1). The message could |
| be handled by the parent bins of the element and the |
| application. */ |
| GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, |
| "posting `need-context' message"); |
| |
| msg = gst_message_new_need_context (GST_OBJECT_CAST (element), context_type); |
| if (!gst_element_post_message (element, msg)) |
| GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, "No bus attached"); |
| |
| /* Whomever responds to the need-context message performs a |
| GstElement::set_context() with the required context in which the |
| element is required to update the display_ptr */ |
| |
| found: |
| gst_query_unref (query); |
| } |
| |
| gboolean |
| gst_msdk_context_prepare (GstElement * element, GstMsdkContext ** context_ptr) |
| { |
| g_return_val_if_fail (element != NULL, FALSE); |
| g_return_val_if_fail (context_ptr != NULL, FALSE); |
| |
| _init_context_debug (); |
| |
| /* 1) Check if the element already has a context of the specific type. */ |
| if (*context_ptr) { |
| GST_LOG_OBJECT (element, "already have a context %" GST_PTR_FORMAT, |
| *context_ptr); |
| return TRUE; |
| } |
| |
| _gst_context_query (element, GST_MSDK_CONTEXT_TYPE_NAME); |
| |
| if (*context_ptr) |
| GST_LOG_OBJECT (element, "found a context %" GST_PTR_FORMAT, *context_ptr); |
| |
| return *context_ptr != NULL; |
| } |
| |
| gboolean |
| gst_msdk_context_get_context (GstContext * context, |
| GstMsdkContext ** msdk_context) |
| { |
| const GstStructure *structure; |
| const gchar *type; |
| |
| g_return_val_if_fail (GST_IS_CONTEXT (context), FALSE); |
| |
| type = gst_context_get_context_type (context); |
| |
| if (!g_strcmp0 (type, GST_MSDK_CONTEXT_TYPE_NAME)) { |
| structure = gst_context_get_structure (context); |
| return gst_structure_get (structure, GST_MSDK_CONTEXT_TYPE_NAME, |
| GST_TYPE_MSDK_CONTEXT, msdk_context, NULL); |
| } |
| |
| return FALSE; |
| } |
| |
| static void |
| gst_msdk_context_propagate (GstElement * element, GstMsdkContext * msdk_context) |
| { |
| GstContext *context; |
| GstStructure *structure; |
| GstMessage *msg; |
| |
| context = gst_context_new (GST_MSDK_CONTEXT_TYPE_NAME, FALSE); |
| |
| structure = gst_context_writable_structure (context); |
| gst_structure_set (structure, GST_MSDK_CONTEXT_TYPE_NAME, |
| GST_TYPE_MSDK_CONTEXT, msdk_context, NULL); |
| |
| gst_element_set_context (element, context); |
| |
| GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, |
| "posting `have-context' message with MSDK context %" GST_PTR_FORMAT, |
| msdk_context); |
| |
| msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context); |
| if (!gst_element_post_message (element, msg)) { |
| GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, "No bus attached"); |
| } |
| } |
| |
| gboolean |
| gst_msdk_context_ensure_context (GstElement * element, gboolean hardware, |
| GstMsdkContextJobType job) |
| { |
| GstMsdkContext *msdk_context; |
| |
| msdk_context = gst_msdk_context_new (hardware, job); |
| if (!msdk_context) { |
| GST_ERROR_OBJECT (element, "Context creation failed"); |
| return FALSE; |
| } |
| |
| GST_INFO_OBJECT (element, "New MSDK Context %p", msdk_context); |
| |
| gst_msdk_context_propagate (element, msdk_context); |
| gst_object_unref (msdk_context); |
| |
| return TRUE; |
| } |