static GstFlowReturn gst_glimage_sink_prepare (GstBaseSink * bsink, GstBuffer * buf) { GstGLImageSink *glimage_sink; glimage_sink = GST_GLIMAGE_SINK (bsink); GST_TRACE ("preparing buffer:%p", buf); if (GST_VIDEO_SINK_WIDTH (glimage_sink) < 1 || GST_VIDEO_SINK_HEIGHT (glimage_sink) < 1) { return GST_FLOW_NOT_NEGOTIATED; } if (!_ensure_gl_setup (glimage_sink)) return GST_FLOW_NOT_NEGOTIATED; if (!gst_gl_upload_perform_with_buffer (glimage_sink->upload, buf, &glimage_sink->next_tex)) goto upload_failed; if (glimage_sink->window_id != glimage_sink->new_window_id) { GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context); glimage_sink->window_id = glimage_sink->new_window_id; gst_gl_window_set_window_handle (window, glimage_sink->window_id); gst_object_unref (window); } return GST_FLOW_OK; upload_failed: { GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s", "Failed to upload buffer"), (NULL)); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstGLImageSink *glimage_sink; guint tex_id; GST_TRACE ("rendering buffer:%p", buf); glimage_sink = GST_GLIMAGE_SINK (bsink); if (GST_VIDEO_SINK_WIDTH (glimage_sink) < 1 || GST_VIDEO_SINK_HEIGHT (glimage_sink) < 1) { return GST_FLOW_NOT_NEGOTIATED; } if (!_ensure_gl_setup (glimage_sink)) return GST_FLOW_NOT_NEGOTIATED; if (!gst_gl_upload_perform_with_buffer (glimage_sink->upload, buf, &tex_id)) goto upload_failed; if (glimage_sink->window_id != glimage_sink->new_window_id) { GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context); glimage_sink->window_id = glimage_sink->new_window_id; gst_gl_window_set_window_handle (window, glimage_sink->window_id); gst_object_unref (window); } GST_TRACE ("redisplay texture:%u of size:%ux%u, window size:%ux%u", tex_id, GST_VIDEO_INFO_WIDTH (&glimage_sink->info), GST_VIDEO_INFO_HEIGHT (&glimage_sink->info), GST_VIDEO_SINK_WIDTH (glimage_sink), GST_VIDEO_SINK_HEIGHT (glimage_sink)); /* Avoid to release the texture while drawing */ GST_GLIMAGE_SINK_LOCK (glimage_sink); glimage_sink->redisplay_texture = tex_id; GST_GLIMAGE_SINK_UNLOCK (glimage_sink); /* Ask the underlying window to redraw its content */ if (!gst_glimage_sink_redisplay (glimage_sink)) goto redisplay_failed; GST_TRACE ("post redisplay"); if (g_atomic_int_get (&glimage_sink->to_quit) != 0) { GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); gst_gl_upload_release_buffer (glimage_sink->upload); return GST_FLOW_ERROR; } gst_gl_upload_release_buffer (glimage_sink->upload); return GST_FLOW_OK; /* ERRORS */ redisplay_failed: { gst_gl_upload_release_buffer (glimage_sink->upload); GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); return GST_FLOW_ERROR; } upload_failed: { GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s", "Failed to upload format"), (NULL)); return FALSE; } }
gboolean gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf) { guint i; GList *walk; guint out_tex; gboolean res = TRUE; guint array_index = 0; GstVideoFrame out_frame; gboolean out_gl_wrapped = FALSE; GstElement *element = GST_ELEMENT (mix); GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix); GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); GstGLMixerPrivate *priv = mix->priv; GST_TRACE ("Processing buffers"); if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf, GST_MAP_WRITE | GST_MAP_GL)) { return FALSE; } if (gst_is_gl_memory (out_frame.map[0].memory)) { out_tex = *(guint *) out_frame.data[0]; } else { GST_INFO ("Output Buffer does not contain correct memory, " "attempting to wrap for download"); out_tex = mix->out_tex_id;; if (!mix->download) mix->download = gst_gl_download_new (mix->context); gst_gl_download_set_format (mix->download, &out_frame.info); out_gl_wrapped = TRUE; } GST_OBJECT_LOCK (mix); walk = element->sinkpads; i = mix->frames->len; g_ptr_array_set_size (mix->frames, element->numsinkpads); for (; i < element->numsinkpads; i++) mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData); while (walk) { GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data); GstVideoAggregatorPad *vaggpad = walk->data; GstGLMixerFrameData *frame; frame = g_ptr_array_index (mix->frames, array_index); frame->pad = pad; frame->texture = 0; walk = g_list_next (walk); if (vaggpad->buffer != NULL) { guint in_tex; if (!pad->upload) { pad->upload = gst_gl_upload_new (mix->context); gst_gl_upload_set_format (pad->upload, &vaggpad->info); } if (!gst_gl_upload_perform_with_buffer (pad->upload, vaggpad->buffer, &in_tex)) { ++array_index; pad->mapped = FALSE; continue; } pad->mapped = TRUE; frame->texture = in_tex; } ++array_index; } g_mutex_lock (&priv->gl_resource_lock); if (!priv->gl_resource_ready) g_cond_wait (&priv->gl_resource_cond, &priv->gl_resource_lock); if (!priv->gl_resource_ready) { g_mutex_unlock (&priv->gl_resource_lock); GST_ERROR_OBJECT (mix, "fbo used to render can't be created, do not run process_textures"); res = FALSE; goto out; } mix_class->process_textures (mix, mix->frames, out_tex); g_mutex_unlock (&priv->gl_resource_lock); if (out_gl_wrapped) { if (!gst_gl_download_perform_with_data (mix->download, out_tex, out_frame.data)) { GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", "Failed to download video frame"), (NULL)); res = FALSE; goto out; } } out: i = 0; walk = GST_ELEMENT (mix)->sinkpads; while (walk) { GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data); if (pad->mapped) gst_gl_upload_release_buffer (pad->upload); pad->mapped = FALSE; walk = g_list_next (walk); i++; } GST_OBJECT_UNLOCK (mix); gst_video_frame_unmap (&out_frame); return res; }
static GstFlowReturn stereosplit_chain (GstPad * pad, GstGLStereoSplit * split, GstBuffer * buf) { GstBuffer *uploaded_buffer, *converted_buffer, *left, *right; GstBuffer *split_buffer = NULL; GstFlowReturn ret; gint i, n_planes; if (!split->upload) _init_upload (split); n_planes = GST_VIDEO_INFO_N_PLANES (&split->viewconvert->out_info); GST_LOG_OBJECT (split, "chaining buffer %" GST_PTR_FORMAT, buf); if (GST_GL_UPLOAD_DONE != gst_gl_upload_perform_with_buffer (split->upload, buf, &uploaded_buffer)) { gst_buffer_unref (buf); GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s", "Failed to upload buffer"), (NULL)); return GST_FLOW_ERROR; } gst_buffer_unref (buf); if (!(converted_buffer = gst_gl_color_convert_perform (split->convert, uploaded_buffer))) { GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s", "Failed to convert buffer"), (NULL)); gst_buffer_unref (uploaded_buffer); return GST_FLOW_ERROR; } gst_buffer_unref (uploaded_buffer); if (gst_gl_view_convert_submit_input_buffer (split->viewconvert, GST_BUFFER_IS_DISCONT (converted_buffer), converted_buffer) != GST_FLOW_OK) { GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s", "Failed to 3d convert buffer"), ("Could not get submit input buffer")); return GST_FLOW_ERROR; } ret = gst_gl_view_convert_get_output (split->viewconvert, &split_buffer); if (ret != GST_FLOW_OK) { GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s", "Failed to 3d convert buffer"), ("Could not get output buffer")); return GST_FLOW_ERROR; } if (split_buffer == NULL) return GST_FLOW_OK; /* Need another input buffer */ left = gst_buffer_new (); gst_buffer_copy_into (left, buf, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); GST_BUFFER_FLAG_UNSET (left, GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE); gst_buffer_add_parent_buffer_meta (left, split_buffer); for (i = 0; i < n_planes; i++) { GstMemory *mem = gst_buffer_get_memory (split_buffer, i); gst_buffer_append_memory (left, mem); } ret = gst_pad_push (split->left_pad, gst_buffer_ref (left)); /* Allow unlinked on the first pad - as long as the 2nd isn't unlinked */ gst_buffer_unref (left); if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)) { gst_buffer_unref (split_buffer); return ret; } right = gst_buffer_new (); gst_buffer_copy_into (right, buf, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); GST_BUFFER_FLAG_UNSET (left, GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE); gst_buffer_add_parent_buffer_meta (right, split_buffer); for (i = n_planes; i < n_planes * 2; i++) { GstMemory *mem = gst_buffer_get_memory (split_buffer, i); gst_buffer_append_memory (right, mem); } ret = gst_pad_push (split->right_pad, gst_buffer_ref (right)); gst_buffer_unref (right); gst_buffer_unref (split_buffer); return ret; }
/** * gst_gl_filter_filter_texture: * @filter: a #GstGLFilter * @inbuf: an input buffer * @outbuf: an output buffer * * Perform automatic upload if needed, call filter_texture vfunc and then an * automatic download if needed. * * Returns: whether the transformation succeeded */ gboolean gst_gl_filter_filter_texture (GstGLFilter * filter, GstBuffer * inbuf, GstBuffer * outbuf) { GstGLFilterClass *filter_class; guint in_tex, out_tex; GstVideoFrame out_frame; gboolean ret, out_gl_mem; GstVideoGLTextureUploadMeta *out_tex_upload_meta; filter_class = GST_GL_FILTER_GET_CLASS (filter); if (!gst_gl_upload_perform_with_buffer (filter->upload, inbuf, &in_tex)) return FALSE; if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf, GST_MAP_WRITE | GST_MAP_GL)) { ret = FALSE; goto inbuf_error; } out_gl_mem = gst_is_gl_memory (out_frame.map[0].memory); out_tex_upload_meta = gst_buffer_get_video_gl_texture_upload_meta (outbuf); if (out_gl_mem) { out_tex = *(guint *) out_frame.data[0]; } else { GST_LOG ("Output Buffer does not contain correct memory, " "attempting to wrap for download"); if (!filter->download) { filter->download = gst_gl_download_new (filter->context); if (!gst_gl_download_init_format (filter->download, GST_VIDEO_FRAME_FORMAT (&out_frame), GST_VIDEO_FRAME_WIDTH (&out_frame), GST_VIDEO_FRAME_HEIGHT (&out_frame))) { GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND, ("%s", "Failed to init download format"), (NULL)); ret = FALSE; goto error; } } out_tex = filter->out_tex_id; } GST_DEBUG ("calling filter_texture with textures in:%i out:%i", in_tex, out_tex); g_assert (filter_class->filter_texture); ret = filter_class->filter_texture (filter, in_tex, out_tex); if (!out_gl_mem && !out_tex_upload_meta) { if (!gst_gl_download_perform_with_data (filter->download, out_tex, out_frame.data)) { GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND, ("%s", "Failed to download video frame"), (NULL)); ret = FALSE; goto error; } } error: gst_video_frame_unmap (&out_frame); inbuf_error: gst_gl_upload_release_buffer (filter->upload); return ret; }
static GstBuffer * _default_pad_upload_buffer (GstGLMixer * mix, GstGLMixerFrameData * frame, GstBuffer * buffer) { GstVideoAggregatorPad *vaggpad = GST_VIDEO_AGGREGATOR_PAD (frame->pad); GstGLMixerPad *pad = frame->pad; GstBuffer *uploaded_buf, *gl_buffer; GstCaps *gl_caps; GstCapsFeatures *gl_features; GstVideoInfo gl_info; GstVideoFrame gl_frame; GstGLSyncMeta *sync_meta; gst_video_info_set_format (&gl_info, GST_VIDEO_FORMAT_RGBA, GST_VIDEO_INFO_WIDTH (&vaggpad->info), GST_VIDEO_INFO_HEIGHT (&vaggpad->info)); gl_features = gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY); gl_caps = gst_video_info_to_caps (&gl_info); gst_caps_set_features (gl_caps, 0, gst_caps_features_copy (gl_features)); if (!pad->upload) { GstCaps *in_caps = gst_pad_get_current_caps (GST_PAD (pad)); GstCaps *upload_caps = gst_caps_copy (in_caps); pad->upload = gst_gl_upload_new (mix->context); gst_caps_set_features (upload_caps, 0, gst_caps_features_copy (gl_features)); gst_gl_upload_set_caps (pad->upload, in_caps, upload_caps); if (!pad->convert) { pad->convert = gst_gl_color_convert_new (mix->context); gst_gl_color_convert_set_caps (pad->convert, upload_caps, gl_caps); } gst_caps_unref (upload_caps); gst_caps_unref (in_caps); } gst_caps_features_free (gl_features); gst_caps_unref (gl_caps); sync_meta = gst_buffer_get_gl_sync_meta (vaggpad->buffer); if (sync_meta) gst_gl_sync_meta_wait (sync_meta); if (gst_gl_upload_perform_with_buffer (pad->upload, vaggpad->buffer, &uploaded_buf) != GST_GL_UPLOAD_DONE) { return NULL; } if (!(gl_buffer = gst_gl_color_convert_perform (pad->convert, uploaded_buf))) { gst_buffer_unref (uploaded_buf); return NULL; } if (!gst_video_frame_map (&gl_frame, &gl_info, gl_buffer, GST_MAP_READ | GST_MAP_GL)) { gst_buffer_unref (uploaded_buf); gst_buffer_unref (gl_buffer); return NULL; } frame->texture = *(guint *) gl_frame.data[0]; gst_buffer_unref (uploaded_buf); gst_video_frame_unmap (&gl_frame); return gl_buffer; }