示例#1
0
文件: testegl.c 项目: ryumiel/gst-omx
static void
update_image (APP_STATE_T * state, GstBuffer * buffer)
{
    GstVideoGLTextureUploadMeta *meta = NULL;

    if (state->current_buffer) {
        gst_buffer_unref (state->current_buffer);
    } else {
        /* Setup the model world */
        init_model_proj (state);
        TRACE_VC_MEMORY ("after init_model_proj");

        /* initialize the OGLES texture(s) */
        init_textures (state, buffer);
        TRACE_VC_MEMORY ("after init_textures");
    }
    state->current_buffer = gst_buffer_ref (buffer);

    TRACE_VC_MEMORY_ONCE_FOR_ID ("before GstVideoGLTextureUploadMeta", gid0);

    if (state->can_avoid_upload) {
        GstMemory *mem = gst_buffer_peek_memory (state->current_buffer, 0);
        g_assert (gst_is_gl_memory (mem));
        state->tex = ((GstGLMemory *) mem)->tex_id;
    } else if ((meta = gst_buffer_get_video_gl_texture_upload_meta (buffer))) {
        if (meta->n_textures == 1) {
            guint ids[4] = { state->tex, 0, 0, 0 };
            if (!gst_video_gl_texture_upload_meta_upload (meta, ids)) {
                GST_WARNING ("failed to upload to texture");
            }
        }
    }

    TRACE_VC_MEMORY_ONCE_FOR_ID ("after GstVideoGLTextureUploadMeta", gid1);
}
示例#2
0
/**
 * gst_gl_memory_pbo_download_transfer:
 * @gl_mem: a #GstGLMemoryPBO
 *
 * Transfer the texture data from the texture into the PBO if necessary.
 *
 * Since: 1.8
 */
void
gst_gl_memory_pbo_download_transfer (GstGLMemoryPBO * gl_mem)
{
  g_return_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem));

  gst_gl_context_thread_add (gl_mem->mem.mem.context,
      (GstGLContextThreadFunc) _download_transfer, gl_mem);
}
示例#3
0
/**
 * gst_gl_memory_pbo_download_transfer:
 * @gl_mem: a #GstGLMemoryPBO
 *
 * Transfer the texture data from the PBO into the texture if necessary.
 *
 * Since: 1.8
 */
void
gst_gl_memory_pbo_upload_transfer (GstGLMemoryPBO * gl_mem)
{
  g_return_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem));

  if (gl_mem->pbo && CONTEXT_SUPPORTS_PBO_UPLOAD (gl_mem->mem.mem.context))
    gst_gl_context_thread_add (gl_mem->mem.mem.context,
        (GstGLContextThreadFunc) _upload_transfer, gl_mem);
}
示例#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
GstFlowReturn ofGstVideoUtils::process_sample(shared_ptr<GstSample> sample){
	GstBuffer * _buffer = gst_sample_get_buffer(sample.get());

#ifdef OF_USE_GST_GL
	if (gst_buffer_map (_buffer, &mapinfo, (GstMapFlags)(GST_MAP_READ | GST_MAP_GL))){
		if (gst_is_gl_memory (mapinfo.memory)) {
			bufferQueue.push(sample);
			gst_buffer_unmap(_buffer, &mapinfo);
			bool newTexture=false;
			std::unique_lock<std::mutex> lock(mutex);
			while(bufferQueue.size()>2){
				backBuffer = bufferQueue.front();
				bufferQueue.pop();
				newTexture = true;
			}
			if(newTexture){
				GstBuffer * _buffer = gst_sample_get_buffer(backBuffer.get());
				gst_buffer_map (_buffer, &mapinfo, (GstMapFlags)(GST_MAP_READ | GST_MAP_GL));
				auto texId = *(guint*)mapinfo.data;
				backTexture.setUseExternalTextureID(texId);
				ofTextureData & texData = backTexture.getTextureData();
				texData.bAllocated = true;
				texData.bFlipTexture = false;
				texData.glTypeInternal = GL_RGBA;
				texData.height = getHeight();
				texData.width = getWidth();
				texData.magFilter = GL_LINEAR;
				texData.minFilter = GL_LINEAR;
				texData.tex_h = getHeight();
				texData.tex_w = getWidth();
				texData.tex_u = 1;
				texData.tex_t = 1;
				texData.textureID = texId;
				texData.textureTarget = GL_TEXTURE_2D;
				texData.wrapModeHorizontal = GL_CLAMP_TO_EDGE;
				texData.wrapModeVertical = GL_CLAMP_TO_EDGE;
				bBackPixelsChanged=true;
				gst_buffer_unmap(_buffer,&mapinfo);
			}
			return GST_FLOW_OK;
		}
	}
#endif

	// video frame has normal texture
	gst_buffer_map (_buffer, &mapinfo, GST_MAP_READ);
	guint size = mapinfo.size;

	int stride = 0;
	if(pixels.isAllocated() && pixels.getTotalBytes()!=(int)size){
		GstVideoInfo v_info = getVideoInfo(sample.get());
		stride = v_info.stride[0];

		if(stride == (pixels.getWidth() * pixels.getBytesPerPixel())) {
			ofLogError("ofGstVideoUtils") << "buffer_cb(): error on new buffer, buffer size: " << size << "!= init size: " << pixels.getTotalBytes();
			return GST_FLOW_ERROR;
		}
	}
	mutex.lock();
	if(!copyPixels){
		backBuffer = sample;
	}

	if(pixels.isAllocated()){
		if(stride > 0) {
			backPixels.setFromAlignedPixels(mapinfo.data,pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat(),stride);
		} else if(!copyPixels){
			backPixels.setFromExternalPixels(mapinfo.data,pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat());
			eventPixels.setFromExternalPixels(mapinfo.data,pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat());
		}else{
			backPixels.setFromPixels(mapinfo.data,pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat());
		}

		bBackPixelsChanged=true;
		mutex.unlock();
		if(stride == 0) {
			ofNotifyEvent(prerollEvent,eventPixels);
		}
	}else{
		mutex.unlock();
		if(appsink){
			appsink->on_stream_prepared();
		}else{
			GstVideoInfo v_info = getVideoInfo(sample.get());
			allocate(v_info.width,v_info.height,getOFFormat(v_info.finfo->format));
		}
	}
	gst_buffer_unmap(_buffer, &mapinfo);
	return GST_FLOW_OK;
}
示例#7
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;
}
/* Called by the idle function in the gl thread */
void
_do_convert (GstGLContext * context, GstGLColorConvert * convert)
{
  guint in_width, in_height, out_width, out_height;
  struct ConvertInfo *c_info = &convert->priv->convert_info;
  GstMapInfo out_info[GST_VIDEO_MAX_PLANES], in_info[GST_VIDEO_MAX_PLANES];
  gboolean res = TRUE;
  gint i, j = 0;

  out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
  out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
  in_width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
  in_height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);

  convert->outbuf = NULL;

  if (!_init_convert (convert)) {
    convert->priv->result = FALSE;
    return;
  }

  convert->outbuf = gst_buffer_new ();
  if (!gst_gl_memory_setup_buffer (convert->context, &convert->out_info,
          convert->outbuf)) {
    convert->priv->result = FALSE;
    return;
  }

  gst_buffer_add_video_meta_full (convert->outbuf, 0,
      GST_VIDEO_INFO_FORMAT (&convert->out_info),
      GST_VIDEO_INFO_WIDTH (&convert->out_info),
      GST_VIDEO_INFO_HEIGHT (&convert->out_info),
      GST_VIDEO_INFO_N_PLANES (&convert->out_info),
      convert->out_info.offset, convert->out_info.stride);

  for (i = 0; i < c_info->in_n_textures; i++) {
    convert->priv->in_tex[i] =
        (GstGLMemory *) gst_buffer_peek_memory (convert->inbuf, i);
    if (!gst_is_gl_memory ((GstMemory *) convert->priv->in_tex[i])) {
      GST_ERROR_OBJECT (convert, "input must be GstGLMemory");
      res = FALSE;
      goto out;
    }
    if (!gst_memory_map ((GstMemory *) convert->priv->in_tex[i], &in_info[i],
            GST_MAP_READ | GST_MAP_GL)) {
      GST_ERROR_OBJECT (convert, "failed to map input memory %p",
          convert->priv->in_tex[i]);
      res = FALSE;
      goto out;
    }
  }

  for (j = 0; j < c_info->out_n_textures; j++) {
    GstGLMemory *out_tex =
        (GstGLMemory *) gst_buffer_peek_memory (convert->outbuf, j);
    gint mem_width, mem_height;

    if (!gst_is_gl_memory ((GstMemory *) out_tex)) {
      GST_ERROR_OBJECT (convert, "output must be GstGLMemory");
      res = FALSE;
      goto out;
    }

    mem_width = gst_gl_memory_get_texture_width (out_tex);
    mem_height = gst_gl_memory_get_texture_height (out_tex);

    if (out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
        || out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA
        || out_width != mem_width || out_height != mem_height) {
      /* Luminance formats are not color renderable */
      /* renderering to a framebuffer only renders the intersection of all
       * the attachments i.e. the smallest attachment size */
      GstVideoInfo temp_info;

      gst_video_info_set_format (&temp_info, GST_VIDEO_FORMAT_RGBA, out_width,
          out_height);

      if (!convert->priv->out_tex[j])
        convert->priv->out_tex[j] =
            (GstGLMemory *) gst_gl_memory_alloc (context, &temp_info, 0);
    } else {
      convert->priv->out_tex[j] = out_tex;
    }

    if (!gst_memory_map ((GstMemory *) convert->priv->out_tex[j], &out_info[j],
            GST_MAP_WRITE | GST_MAP_GL)) {
      GST_ERROR_OBJECT (convert, "failed to map output memory %p",
          convert->priv->out_tex[i]);
      res = FALSE;
      goto out;
    }
  }

  GST_LOG_OBJECT (convert, "converting to textures:%p,%p,%p,%p "
      "dimensions:%ux%u, from textures:%p,%p,%p,%p dimensions:%ux%u",
      convert->priv->out_tex[0], convert->priv->out_tex[1],
      convert->priv->out_tex[2], convert->priv->out_tex[3], out_width,
      out_height, convert->priv->in_tex[0], convert->priv->in_tex[1],
      convert->priv->in_tex[2], convert->priv->in_tex[3], in_width, in_height);

  if (!_do_convert_draw (context, convert))
    res = FALSE;

out:
  for (j--; j >= 0; j--) {
    GstGLMemory *out_tex =
        (GstGLMemory *) gst_buffer_peek_memory (convert->outbuf, j);
    gint mem_width, mem_height;

    gst_memory_unmap ((GstMemory *) convert->priv->out_tex[j], &out_info[j]);

    mem_width = gst_gl_memory_get_texture_width (out_tex);
    mem_height = gst_gl_memory_get_texture_height (out_tex);

    if (out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
        || out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA
        || out_width != mem_width || out_height != mem_height) {
      GstMapInfo to_info, from_info;

      if (!gst_memory_map ((GstMemory *) convert->priv->out_tex[j], &from_info,
              GST_MAP_READ | GST_MAP_GL)) {
        gst_gl_context_set_error (convert->context, "Failed to map "
            "intermediate memory");
        res = FALSE;
        continue;
      }
      if (!gst_memory_map ((GstMemory *) out_tex, &to_info,
              GST_MAP_WRITE | GST_MAP_GL)) {
        gst_gl_context_set_error (convert->context, "Failed to map "
            "intermediate memory");
        res = FALSE;
        continue;
      }
      gst_gl_memory_copy_into_texture (convert->priv->out_tex[j],
          out_tex->tex_id, out_tex->tex_type, mem_width, mem_height,
          GST_VIDEO_INFO_PLANE_STRIDE (&out_tex->info, out_tex->plane), FALSE);
      gst_memory_unmap ((GstMemory *) convert->priv->out_tex[j], &from_info);
      gst_memory_unmap ((GstMemory *) out_tex, &to_info);
    } else {
      convert->priv->out_tex[j] = NULL;
    }
  }

  /* YV12 the same as I420 except planes 1+2 swapped */
  if (GST_VIDEO_INFO_FORMAT (&convert->out_info) == GST_VIDEO_FORMAT_YV12) {
    GstMemory *mem1 = gst_buffer_get_memory (convert->outbuf, 1);
    GstMemory *mem2 = gst_buffer_get_memory (convert->outbuf, 2);

    gst_buffer_replace_memory (convert->outbuf, 1, mem2);
    gst_buffer_replace_memory (convert->outbuf, 2, mem1);
  }

  for (i--; i >= 0; i--) {
    gst_memory_unmap ((GstMemory *) convert->priv->in_tex[i], &in_info[i]);
  }

  if (!res) {
    gst_buffer_unref (convert->outbuf);
    convert->outbuf = NULL;
  }

  convert->priv->result = res;
  return;
}
/**
 * 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;
}