static void setup (void) { GError *error = NULL; display = gst_gl_display_new (); context = gst_gl_context_new (display); gst_gl_context_create (context, 0, &error); window = gst_gl_context_get_window (context); fail_if (error != NULL, "Error creating context: %s\n", error ? error->message : "Unknown Error"); upload = gst_gl_upload_new (context); }
static void _init_upload (GstGLStereoSplit * split) { GstGLContext *context = split->context; if (!split->upload) { GstCaps *in_caps = gst_pad_get_current_caps (GST_PAD (split->sink_pad)); GstCaps *split_caps = gst_pad_get_current_caps (split->left_pad); GstCaps *upload_caps = gst_caps_copy (in_caps); GstCapsFeatures *gl_features = gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY); GstCaps *gl_caps; split->upload = gst_gl_upload_new (context); gst_caps_set_features (upload_caps, 0, gst_caps_features_copy (gl_features)); gst_gl_upload_set_caps (split->upload, in_caps, upload_caps); gst_caps_unref (in_caps); gl_caps = gst_caps_copy (upload_caps); gst_caps_set_simple (gl_caps, "format", G_TYPE_STRING, "RGBA", NULL); gst_caps_set_features (gl_caps, 0, gst_caps_features_copy (gl_features)); if (!split->convert) { split->convert = gst_gl_color_convert_new (context); gst_gl_color_convert_set_caps (split->convert, upload_caps, gl_caps); } gst_caps_unref (upload_caps); gst_caps_features_free (gl_features); gst_gl_view_convert_set_context (split->viewconvert, split->context); split_caps = gst_caps_make_writable (split_caps); gst_caps_set_simple (split_caps, "multiview-mode", G_TYPE_STRING, "separated", "views", G_TYPE_INT, 2, NULL); gst_gl_view_convert_set_caps (split->viewconvert, gl_caps, split_caps); gst_caps_unref (split_caps); gst_caps_unref (gl_caps); } }
static gboolean _ensure_gl_setup (GstGLImageSink * gl_sink) { GError *error = NULL; if (!gst_gl_ensure_display (gl_sink, &gl_sink->display)) return FALSE; if (!gl_sink->context) { gl_sink->context = gst_gl_context_new (gl_sink->display); if (!gst_gl_context_create (gl_sink->context, gl_sink->other_context, &error)) goto context_error; } if (!gl_sink->upload) { gl_sink->upload = gst_gl_upload_new (gl_sink->context); if (!gst_gl_upload_init_format (gl_sink->upload, gl_sink->info, gl_sink->info)) goto upload_error; } return TRUE; upload_error: { GST_ELEMENT_ERROR (gl_sink, RESOURCE, NOT_FOUND, ("Failed to init upload"), (NULL)); return FALSE; } context_error: { GST_ELEMENT_ERROR (gl_sink, RESOURCE, NOT_FOUND, ("%s", error->message), (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 gboolean gst_gl_filter_decide_allocation (GstBaseTransform * trans, GstQuery * query) { GstGLFilter *filter = GST_GL_FILTER (trans); GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); GstBufferPool *pool = NULL; GstStructure *config; GstCaps *caps; guint min, max, size; gboolean update_pool; guint idx; GError *error = NULL; guint in_width, in_height, out_width, out_height; gst_query_parse_allocation (query, &caps, NULL); if (gst_query_get_n_allocation_pools (query) > 0) { gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); update_pool = TRUE; } else { GstVideoInfo vinfo; gst_video_info_init (&vinfo); gst_video_info_from_caps (&vinfo, caps); size = vinfo.size; min = max = 0; update_pool = FALSE; } if (!gst_gl_ensure_display (filter, &filter->display)) return FALSE; if (gst_query_find_allocation_meta (query, GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx)) { GstGLContext *context; const GstStructure *upload_meta_params; gst_query_parse_nth_allocation_meta (query, idx, &upload_meta_params); if (gst_structure_get (upload_meta_params, "gst.gl.GstGLContext", GST_GL_TYPE_CONTEXT, &context, NULL) && context) { GstGLContext *old = filter->context; filter->context = context; if (old) gst_object_unref (old); } } if (!filter->context) { filter->context = gst_gl_context_new (filter->display); if (!gst_gl_context_create (filter->context, filter->other_context, &error)) goto context_error; } in_width = GST_VIDEO_INFO_WIDTH (&filter->in_info); in_height = GST_VIDEO_INFO_HEIGHT (&filter->in_info); out_width = GST_VIDEO_INFO_WIDTH (&filter->out_info); out_height = GST_VIDEO_INFO_HEIGHT (&filter->out_info); if (!filter->upload) { filter->upload = gst_gl_upload_new (filter->context); gst_gl_upload_init_format (filter->upload, filter->in_info, filter->out_info); } //blocking call, generate a FBO if (!gst_gl_context_gen_fbo (filter->context, out_width, out_height, &filter->fbo, &filter->depthbuffer)) goto context_error; gst_gl_context_gen_texture (filter->context, &filter->in_tex_id, GST_VIDEO_FORMAT_RGBA, in_width, in_height); gst_gl_context_gen_texture (filter->context, &filter->out_tex_id, GST_VIDEO_FORMAT_RGBA, out_width, out_height); if (filter_class->display_init_cb != NULL) { gst_gl_context_thread_add (filter->context, gst_gl_filter_start_gl, filter); } if (filter_class->onInitFBO) { if (!filter_class->onInitFBO (filter)) goto error; } if (!pool) pool = gst_gl_buffer_pool_new (filter->context); config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, caps, size, min, max); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); gst_buffer_pool_set_config (pool, config); if (update_pool) gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); else gst_query_add_allocation_pool (query, pool, size, min, max); gst_object_unref (pool); return TRUE; context_error: { GST_ELEMENT_ERROR (trans, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); return FALSE; } error: { GST_ELEMENT_ERROR (trans, LIBRARY, INIT, ("Subclass failed to initialize."), (NULL)); return FALSE; } }
static gboolean gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) { GstGLImageSink *glimage_sink; gint width; gint height; gboolean ok; gint par_n, par_d; gint display_par_n, display_par_d; guint display_ratio_num, display_ratio_den; GstVideoInfo vinfo; GstStructure *structure; GstBufferPool *newpool, *oldpool; GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); glimage_sink = GST_GLIMAGE_SINK (bsink); ok = gst_video_info_from_caps (&vinfo, caps); if (!ok) return FALSE; width = GST_VIDEO_INFO_WIDTH (&vinfo); height = GST_VIDEO_INFO_HEIGHT (&vinfo); par_n = GST_VIDEO_INFO_PAR_N (&vinfo); par_d = GST_VIDEO_INFO_PAR_D (&vinfo); if (!par_n) par_n = 1; /* get display's PAR */ if (glimage_sink->par_n != 0 && glimage_sink->par_d != 0) { display_par_n = glimage_sink->par_n; display_par_d = glimage_sink->par_d; } else { display_par_n = 1; display_par_d = 1; } ok = gst_video_calculate_display_ratio (&display_ratio_num, &display_ratio_den, width, height, par_n, par_d, display_par_n, display_par_d); if (!ok) return FALSE; GST_TRACE ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, display_par_d); if (height % display_ratio_den == 0) { GST_DEBUG ("keeping video height"); GST_VIDEO_SINK_WIDTH (glimage_sink) = (guint) gst_util_uint64_scale_int (height, display_ratio_num, display_ratio_den); GST_VIDEO_SINK_HEIGHT (glimage_sink) = height; } else if (width % display_ratio_num == 0) { GST_DEBUG ("keeping video width"); GST_VIDEO_SINK_WIDTH (glimage_sink) = width; GST_VIDEO_SINK_HEIGHT (glimage_sink) = (guint) gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num); } else { GST_DEBUG ("approximating while keeping video height"); GST_VIDEO_SINK_WIDTH (glimage_sink) = (guint) gst_util_uint64_scale_int (height, display_ratio_num, display_ratio_den); GST_VIDEO_SINK_HEIGHT (glimage_sink) = height; } GST_DEBUG ("scaling to %dx%d", GST_VIDEO_SINK_WIDTH (glimage_sink), GST_VIDEO_SINK_HEIGHT (glimage_sink)); glimage_sink->info = vinfo; if (!_ensure_gl_setup (glimage_sink)) return FALSE; newpool = gst_gl_buffer_pool_new (glimage_sink->context); structure = gst_buffer_pool_get_config (newpool); gst_buffer_pool_config_set_params (structure, caps, vinfo.size, 2, 0); gst_buffer_pool_set_config (newpool, structure); oldpool = glimage_sink->pool; /* we don't activate the pool yet, this will be done by downstream after it * has configured the pool. If downstream does not want our pool we will * activate it when we render into it */ glimage_sink->pool = newpool; /* unref the old sink */ if (oldpool) { /* we don't deactivate, some elements might still be using it, it will * be deactivated when the last ref is gone */ gst_object_unref (oldpool); } if (glimage_sink->upload) gst_object_unref (glimage_sink->upload); glimage_sink->upload = gst_gl_upload_new (glimage_sink->context); gst_gl_upload_set_format (glimage_sink->upload, &vinfo); return TRUE; }
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; }