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; }
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; }
/** * gst_gl_upload_perform_with_buffer: * @upload: a #GstGLUpload * @buffer: a #GstBuffer * @tex_id: resulting texture * * Uploads @buffer to the texture given by @tex_id. @tex_id is valid * until gst_gl_upload_release_buffer() is called. * * Returns: whether the upload was successful */ gboolean gst_gl_upload_perform_with_buffer (GstGLUpload * upload, GstBuffer * buffer, guint * tex_id) { GstMemory *mem; GstVideoGLTextureUploadMeta *gl_tex_upload_meta; guint texture_ids[] = { 0, 0, 0, 0 }; gint i; gboolean ret; g_return_val_if_fail (upload != NULL, FALSE); g_return_val_if_fail (buffer != NULL, FALSE); g_return_val_if_fail (tex_id != NULL, FALSE); g_return_val_if_fail (gst_buffer_n_memory (buffer) > 0, FALSE); gst_gl_upload_release_buffer (upload); /* GstGLMemory */ mem = gst_buffer_peek_memory (buffer, 0); if (gst_is_gl_memory (mem)) { if (GST_VIDEO_INFO_FORMAT (&upload->in_info) == GST_VIDEO_FORMAT_RGBA) { GstMapInfo map_info; gst_memory_map (mem, &map_info, GST_MAP_READ | GST_MAP_GL); gst_memory_unmap (mem, &map_info); *tex_id = ((GstGLMemory *) mem)->tex_id; return TRUE; } GST_LOG_OBJECT (upload, "Attempting upload with GstGLMemory"); for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->in_info); i++) { upload->in_tex[i] = (GstGLMemory *) gst_buffer_peek_memory (buffer, i); } ret = _upload_memory (upload); *tex_id = upload->out_tex->tex_id; for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->in_info); i++) { upload->in_tex[i] = NULL; } return ret; } #if GST_GL_HAVE_PLATFORM_EGL if (!upload->priv->tex_id && gst_is_egl_image_memory (mem)) gst_gl_context_gen_texture (upload->context, &upload->priv->tex_id, GST_VIDEO_FORMAT_RGBA, 0, 0); #endif if (!upload->priv->tex_id) gst_gl_context_gen_texture (upload->context, &upload->priv->tex_id, GST_VIDEO_FORMAT_RGBA, GST_VIDEO_INFO_WIDTH (&upload->in_info), GST_VIDEO_INFO_HEIGHT (&upload->in_info)); /* GstVideoGLTextureUploadMeta */ gl_tex_upload_meta = gst_buffer_get_video_gl_texture_upload_meta (buffer); if (gl_tex_upload_meta) { GST_LOG_OBJECT (upload, "Attempting upload with " "GstVideoGLTextureUploadMeta"); texture_ids[0] = upload->priv->tex_id; if (!gst_gl_upload_perform_with_gl_texture_upload_meta (upload, gl_tex_upload_meta, texture_ids)) { GST_DEBUG_OBJECT (upload, "Upload with GstVideoGLTextureUploadMeta " "failed"); } else { upload->priv->mapped = FALSE; *tex_id = upload->priv->tex_id; return TRUE; } } GST_LOG_OBJECT (upload, "Attempting upload with raw data"); /* GstVideoMeta map */ if (!gst_video_frame_map (&upload->priv->frame, &upload->in_info, buffer, GST_MAP_READ)) { GST_ERROR_OBJECT (upload, "Failed to map memory"); return FALSE; } upload->priv->mapped = TRUE; /* update the video info from the one updated by frame_map using video meta */ gst_gl_upload_set_format (upload, &upload->priv->frame.info); if (!gst_gl_upload_perform_with_data (upload, tex_id, upload->priv->frame.data)) { return FALSE; } return TRUE; }