Пример #1
0
static GstFlowReturn
gst_glimage_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
{
  GstGLImageSink *glimage_sink;
  GstBuffer *stored_buffer;

  GST_TRACE ("rendering buffer:%p", buf);

  glimage_sink = GST_GLIMAGE_SINK (vsink);

  GST_TRACE ("redisplay texture:%u of size:%ux%u, window size:%ux%u",
      glimage_sink->next_tex, 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 = glimage_sink->next_tex;
  stored_buffer = glimage_sink->stored_buffer;
  glimage_sink->stored_buffer = gst_buffer_ref (buf);
  GST_GLIMAGE_SINK_UNLOCK (glimage_sink);
  if (stored_buffer)
    gst_buffer_unref (stored_buffer);

  /* 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;
  }

  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;
  }
}
static void
gst_gl_upload_reset (GstGLUpload * upload)
{
    guint i;

    if (upload->priv->tex_id) {
        gst_gl_context_del_texture (upload->context, &upload->priv->tex_id);
        upload->priv->tex_id = 0;
    }

    if (upload->convert) {
        gst_object_unref (upload->convert);
        upload->convert = NULL;
    }

    if (upload->out_tex) {
        gst_memory_unref ((GstMemory *) upload->out_tex);
        upload->out_tex = NULL;
    }

    for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
        if (upload->in_tex[i]) {
            gst_memory_unref ((GstMemory *) upload->in_tex[i]);
            upload->in_tex[i] = NULL;
        }
    }

    gst_gl_upload_release_buffer (upload);
}
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;
  }
}
Пример #4
0
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;
}
Пример #5
0
gboolean
gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf)
{
    guint i;
    GList *walk;
    guint out_tex, out_tex_target;
    gboolean res = TRUE;
    guint array_index = 0;
    GstVideoFrame out_frame;
    GstElement *element = GST_ELEMENT (mix);
    GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
    GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
    GstGLMixerPrivate *priv = mix->priv;
    gboolean to_download =
        gst_caps_features_is_equal (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY,
                                    gst_caps_get_features (mix->out_caps, 0));
    GstMapFlags out_map_flags = GST_MAP_WRITE;

    GST_TRACE ("Processing buffers");

    to_download |= !gst_is_gl_memory (gst_buffer_peek_memory (outbuf, 0));

    if (!to_download)
        out_map_flags |= GST_MAP_GL;

    if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf, out_map_flags)) {
        return FALSE;
    }

    if (!to_download) {
        out_tex = *(guint *) out_frame.data[0];
        out_tex_target =
            ((GstGLMemory *) gst_buffer_peek_memory (outbuf, 0))->tex_target;
    } else {
        GST_INFO ("Output Buffer does not contain correct memory, "
                  "attempting to wrap for download");

        if (!mix->download)
            mix->download = gst_gl_download_new (mix->context);

        gst_gl_download_set_format (mix->download, &out_frame.info);
        out_tex = mix->out_tex_id;
        out_tex_target = GL_TEXTURE_2D;
    }

    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);
        GstGLMixerPadClass *pad_class = GST_GL_MIXER_PAD_GET_CLASS (pad);
        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) {
            g_assert (pad_class->upload_buffer);

            if (pad->gl_buffer)
                gst_buffer_unref (pad->gl_buffer);
            pad->gl_buffer = pad_class->upload_buffer (mix, frame, vaggpad->buffer);

            GST_DEBUG_OBJECT (pad,
                              "uploaded buffer %" GST_PTR_FORMAT " from buffer %" GST_PTR_FORMAT,
                              pad->gl_buffer, vaggpad->buffer);
        }

        ++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 (to_download) {
        if (!gst_gl_download_perform_with_data (mix->download,
                                                out_tex, out_tex_target, 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->upload)
            gst_gl_upload_release_buffer (pad->upload);

        walk = g_list_next (walk);
        i++;
    }
    GST_OBJECT_UNLOCK (mix);

    gst_video_frame_unmap (&out_frame);

    return res;
}
Пример #6
0
/**
 * 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;
}
/**
 * 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;
}