|
|
|
|
Quelle interop_cvpx.m Sprache: unbekannt
|
|
Spracherkennung für: .m vermutete Sprache: Masm {Masm[50] Cobol[44] Fortran[42]} [Methode: maximale Elemente, drei Dimensionen]
/*****************************************************************************
* converter_cvpx.c: OpenGL Apple CVPX opaque converter
*****************************************************************************
* Copyright (C) 2017 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include "gl_util.h"
#include "interop.h"
#include "../../codec/vt_utils.h"
#if TARGET_OS_IPHONE
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#include <CoreVideo/CVOpenGLESTextureCache.h>
#include <OpenGLES/EAGL.h>
#else
#include <IOSurface/IOSurface.h>
#endif
struct priv
{
#if TARGET_OS_IPHONE
CVOpenGLESTextureCacheRef cache;
CVOpenGLESTextureRef last_cvtexs[PICTURE_PLANE_MAX];
#else
CGLContextObj gl_ctx;
#endif
picture_t *last_pic;
struct {
PFNGLACTIVETEXTUREPROC ActiveTexture;
PFNGLBINDTEXTUREPROC BindTexture;
PFNGLTEXPARAMETERIPROC TexParameteri;
} gl;
};
#if TARGET_OS_IPHONE
/* CVOpenGLESTextureCache version (ios) */
static int
tc_cvpx_update(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[],
picture_t *pic, const size_t *plane_offset)
{
(void) plane_offset;
struct priv *priv = interop->priv;
/* Sanity check, don't change format behind interop's back. */
assert(pic->format.i_chroma == interop->fmt_in.i_chroma);
CVPixelBufferRef pixelBuffer = cvpxpic_get_ref(pic);
for (unsigned i = 0; i < interop->tex_count; ++i)
{
if (likely(priv->last_cvtexs[i]))
{
CFRelease(priv->last_cvtexs[i]);
priv->last_cvtexs[i] = NULL;
}
}
if (priv->last_pic != NULL)
picture_Release(priv->last_pic);
priv->last_pic = picture_Hold(pic);
CVOpenGLESTextureCacheFlush(priv->cache, 0);
for (unsigned i = 0; i < interop->tex_count; ++i)
{
CVOpenGLESTextureRef cvtex;
CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(
kCFAllocatorDefault, priv->cache, pixelBuffer, NULL,
interop->tex_target, interop->texs[i].internal, tex_width[i], tex_height[i],
interop->texs[i].format, interop->texs[i].type, i, &cvtex);
if (err != noErr)
{
msg_Err(interop->gl,
"CVOpenGLESTextureCacheCreateTextureFromImage failed: %d",
err);
return VLC_EGENERIC;
}
textures[i] = CVOpenGLESTextureGetName(cvtex);
priv->gl.BindTexture(interop->tex_target, textures[i]);
priv->gl.TexParameteri(interop->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
priv->gl.TexParameteri(interop->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
priv->gl.TexParameteri(interop->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
priv->gl.TexParameteri(interop->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
priv->gl.BindTexture(interop->tex_target, 0);
priv->last_cvtexs[i] = cvtex;
}
return VLC_SUCCESS;
}
#else
/* IOSurface version (macos) */
static int
tc_cvpx_update(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[],
picture_t *pic, const size_t *plane_offset)
{
(void) plane_offset;
struct priv *priv = interop->priv;
CVPixelBufferRef pixelBuffer = cvpxpic_get_ref(pic);
IOSurfaceRef surface = CVPixelBufferGetIOSurface(pixelBuffer);
for (unsigned i = 0; i < interop->tex_count; ++i)
{
assert(IOSurfaceGetWidthOfPlane(surface, i) >= tex_width[i]);
assert(IOSurfaceGetHeightOfPlane(surface, i) >= tex_height[i]);
priv->gl.ActiveTexture(GL_TEXTURE0 + i);
priv->gl.BindTexture(interop->tex_target, textures[i]);
CGLError err =
CGLTexImageIOSurface2D(priv->gl_ctx, interop->tex_target,
interop->texs[i].internal,
tex_width[i], tex_height[i],
interop->texs[i].format,
interop->texs[i].type,
surface, i);
if (err != kCGLNoError)
{
msg_Err(interop->gl, "CGLTexImageIOSurface2D error: %u: %s", i,
CGLErrorString(err));
return VLC_EGENERIC;
}
}
if (priv->last_pic != NULL)
picture_Release(priv->last_pic);
priv->last_pic = picture_Hold(pic);
return VLC_SUCCESS;
}
#endif
static void
Close(struct vlc_gl_interop *interop)
{
struct priv *priv = interop->priv;
#if TARGET_OS_IPHONE
for (unsigned i = 0; i < interop->tex_count; ++i)
{
if (likely(priv->last_cvtexs[i]))
CFRelease(priv->last_cvtexs[i]);
}
CFRelease(priv->cache);
#endif
if (priv->last_pic != NULL)
picture_Release(priv->last_pic);
free(priv);
}
static int
Open(struct vlc_gl_interop *interop)
{
if (interop->fmt_in.i_chroma != VLC_CODEC_CVPX_UYVY
&& interop->fmt_in.i_chroma != VLC_CODEC_CVPX_NV12
&& interop->fmt_in.i_chroma != VLC_CODEC_CVPX_I420
&& interop->fmt_in.i_chroma != VLC_CODEC_CVPX_BGRA
&& interop->fmt_in.i_chroma != VLC_CODEC_CVPX_P010)
return VLC_EGENERIC;
/* The pictures are uploaded upside-down */
video_format_TransformBy(&interop->fmt_out, TRANSFORM_VFLIP);
struct priv *priv = calloc(1, sizeof(struct priv));
if (unlikely(priv == NULL))
return VLC_ENOMEM;
#define LOAD_FUNCTION(name) \
priv->gl.name = vlc_gl_GetProcAddress(interop->gl, "gl" # name); \
assert(priv->gl.name != NULL)
LOAD_FUNCTION(ActiveTexture);
LOAD_FUNCTION(BindTexture);
LOAD_FUNCTION(TexParameteri);
#if TARGET_OS_IPHONE
const GLenum tex_target = GL_TEXTURE_2D;
{
CVEAGLContext eagl_ctx = [EAGLContext currentContext];
if (!eagl_ctx)
{
msg_Warn(&interop->obj, "OpenGL provider is not using CAEAGL, cannot use interop_cvpx");
free(priv);
return VLC_EGENERIC;
}
CVReturn err =
CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL,
eagl_ctx, NULL, &priv->cache);
if (err != noErr)
{
msg_Err(interop->gl, "CVOpenGLESTextureCacheCreate failed: %d", err);
free(priv);
return VLC_EGENERIC;
}
}
#else
const GLenum tex_target = GL_TEXTURE_RECTANGLE;
{
priv->gl_ctx = CGLGetCurrentContext();
if (!priv->gl_ctx)
{
msg_Warn(&interop->obj, "OpenGL provider is not using CGL, cannot use interop_cvpx");
free(priv);
return VLC_EGENERIC;
}
}
#endif
struct vlc_gl_extension_vt extension_vt;
vlc_gl_LoadExtensionFunctions(interop->gl, &extension_vt);
/* RG textures are available natively since OpenGL 3.0 and OpenGL ES 3.0 */
bool has_texture_rg = vlc_gl_GetVersionMajor(&extension_vt) >= 3
|| (interop->gl->api_type == VLC_OPENGL
&& vlc_gl_HasExtension(&extension_vt, "GL_ARB_texture_rg"))
|| (interop->gl->api_type == VLC_OPENGL_ES2
&& vlc_gl_HasExtension(&extension_vt, "GL_EXT_texture_rg"));
interop->tex_target = tex_target;
switch (interop->fmt_in.i_chroma)
{
case VLC_CODEC_CVPX_UYVY:
/* Generate a VLC_CODEC_VYUY shader in order to use the "gbr"
* swizzling. Indeed, the Y, Cb and Cr color channels within the
* GL_RGB_422_APPLE format are mapped into the existing green, blue
* and red color channels, respectively. cf. APPLE_rgb_422 khronos
* extension. */
interop->fmt_out.i_chroma = VLC_CODEC_VYUY;
interop->fmt_out.space = interop->fmt_in.space;
interop->tex_count = 1;
interop->texs[0] = (struct vlc_gl_tex_cfg) {
.w = {1, 1},
.h = {1, 1},
.internal = GL_RGB,
.format = GL_RGB_422_APPLE,
.type = GL_UNSIGNED_SHORT_8_8_APPLE,
};
break;
case VLC_CODEC_CVPX_NV12:
{
interop->fmt_out.i_chroma = VLC_CODEC_NV12;
interop->fmt_out.space = interop->fmt_in.space;
interop->tex_count = 2;
interop->texs[0] = (struct vlc_gl_tex_cfg) {
.w = {1, 1},
.h = {1, 1},
.internal = has_texture_rg ? GL_RED : GL_LUMINANCE,
.format = has_texture_rg ? GL_RED : GL_LUMINANCE,
.type = GL_UNSIGNED_BYTE,
};
interop->texs[1] = (struct vlc_gl_tex_cfg) {
.w = {1, 2},
.h = {1, 2},
.internal = has_texture_rg ? GL_RG : GL_LUMINANCE_ALPHA,
.format = has_texture_rg ? GL_RG : GL_LUMINANCE_ALPHA,
.type = GL_UNSIGNED_BYTE,
};
break;
}
case VLC_CODEC_CVPX_P010:
{
if (!has_texture_rg
|| vlc_gl_interop_GetTexFormatSize(interop, tex_target, GL_RG,
GL_RG16, GL_UNSIGNED_SHORT) != 16)
goto error;
interop->fmt_out.i_chroma = VLC_CODEC_P010;
interop->fmt_out.space = interop->fmt_in.space;
interop->tex_count = 2;
interop->texs[0] = (struct vlc_gl_tex_cfg) {
.w = {1, 1},
.h = {1, 1},
.internal = GL_R16,
.format = GL_RED,
.type = GL_UNSIGNED_SHORT,
};
interop->texs[1] = (struct vlc_gl_tex_cfg) {
.w = {1, 2},
.h = {1, 2},
.internal = GL_RG16,
.format = GL_RG,
.type = GL_UNSIGNED_SHORT,
};
break;
}
case VLC_CODEC_CVPX_I420:
interop->fmt_out.i_chroma = VLC_CODEC_I420;
interop->fmt_out.space = interop->fmt_in.space;
interop->tex_count = 3;
interop->texs[0] = (struct vlc_gl_tex_cfg) {
.w = {1, 1},
.h = {1, 1},
.internal = has_texture_rg ? GL_RED : GL_LUMINANCE,
.format = has_texture_rg ? GL_RED : GL_LUMINANCE,
.type = GL_UNSIGNED_BYTE,
};
interop->texs[1] = interop->texs[2] = (struct vlc_gl_tex_cfg) {
.w = {1, 2},
.h = {1, 2},
.internal = has_texture_rg ? GL_RED : GL_LUMINANCE,
.format = has_texture_rg ? GL_RED : GL_LUMINANCE,
.type = GL_UNSIGNED_BYTE,
};
break;
case VLC_CODEC_CVPX_BGRA:
interop->fmt_out.i_chroma = VLC_CODEC_BGRA;
interop->fmt_out.space = COLOR_SPACE_UNDEF;
interop->tex_count = 1;
interop->texs[0] = (struct vlc_gl_tex_cfg) {
.w = {1, 1},
.h = {1, 1},
.internal = GL_RGBA,
.format = GL_BGRA,
#if TARGET_OS_IPHONE
.type = GL_UNSIGNED_BYTE,
#else
.type = GL_UNSIGNED_INT_8_8_8_8_REV,
#endif
};
break;
default:
vlc_assert_unreachable();
}
#if TARGET_OS_IPHONE
interop->handle_texs_gen = true;
for (unsigned i = 0; i < interop->tex_count; ++i)
priv->last_cvtexs[i] = NULL;
#endif
priv->last_pic = NULL;
interop->priv = priv;
static const struct vlc_gl_interop_ops ops = {
.update_textures = tc_cvpx_update,
.close = Close,
};
interop->ops = &ops;
return VLC_SUCCESS;
error:
free(priv);
return VLC_EGENERIC;
}
vlc_module_begin ()
set_description("Apple OpenGL CVPX converter")
set_capability("glinterop", 1)
set_callback(Open)
set_subcategory(SUBCAT_VIDEO_VOUT)
vlc_module_end ()
[Dauer der Verarbeitung: 0.3 Sekunden, vorverarbeitet 2026-10-24]
|
2026-11-01
|
|
|
|
|
Neuigkeiten |
| Aktuelles |
| Motto des Tages |
|
Open Source Software |
|
|
|
Jenseits des Üblichen ....
|
|
Besucherstatistik |
|
|
| Statistik |
| #Sources=1104856 |
| #Domains=417809 |
|
|