glActiveTexture 和 glBindTexture 之间的差异和关系,以及内部实现C++模拟代码,OpenGL程序员讨论集合

关于 OpenGL 对象

OpenGL 对象的标准模型如下所示。

对象具有状态。将它们视为 .因此,您可能有一个像这样定义的对象:struct

struct Object
{
    int count;
    float opacity;
    char *name;
};

对象中存储了某些值,并且具有状态。OpenGL 对象也有状态。

更改状态

在 C/C++ 中,如果您有一个类型 为 的实例,则可以按如下方式更改其状态:您将直接引用对象的实例,获取要更改的特定状态,然后将值推入其中。Objectobj.count = 5;

在OpenGL中,你这样做。

由于遗留原因,最好不要解释,要更改OpenGL对象的状态,必须首先将其绑定到上下文。这是通过一些来自调用来完成的。glBind*

与此等效的 C/C++如下所示:

Object *g_objs[MAX_LOCATIONS] = {NULL};    
void BindObject(int loc, Object *obj)
{
  g_objs[loc] = obj;
}

纹理很有趣;它们代表了绑定的特殊情况。许多调用都有一个"target"参数。这表示 OpenGL 上下文中可以绑定该类型对象的不同位置。例如,可以绑定帧缓冲器对象以读取 () 或写入 ()。这会影响 OpenGL 使用缓冲区的方式。这就是上面的参数所代表的内容。glBind*GL_READ_FRAMEBUFFERGL_DRAW_FRAMEBUFFERloc

纹理是特殊的,因为当您第一次将它们绑定到目标时,它们会获得特殊信息。首次将纹理绑定为 时,实际上是在纹理中设置特殊状态。你是说这个纹理是一个2D纹理。它将永远是2D纹理;此状态永远无法更改。如果你有一个纹理,它首先被绑定为 ,你必须始终将其绑定为 ;尝试绑定它将导致错误(在运行时)。GL_TEXTURE_2DGL_TEXTURE_2DGL_TEXTURE_2DGL_TEXTURE_1D

绑定对象后,可以更改其状态。这是通过特定于该对象的泛型函数完成的。它们也采用表示要修改的对象的位置。

在 C/C++ 中,如下所示:

void ObjectParameteri(int loc, ObjectParameters eParam, int value)
{
  if(g_objs[loc] == NULL)
    return;

  switch(eParam)
  {
    case OBJECT_COUNT:
      g_objs[loc]->count = value;
      break;
    case OBJECT_OPACITY:
      g_objs[loc]->opacity = (float)value;
      break;
    default:
      //INVALID_ENUM error
      break;
  }
}

请注意此函数如何设置当前绑定值中碰巧出现的任何内容。loc

对于纹理对象,主要的纹理状态更改函数是glTexParameter。唯一改变纹理状态的其他函数是glTexImage函数及其变体(glCompressedTexImage,glCopyTexImage,最近的glTexStorage)。 各种版本会更改纹理的内容,但从技术上讲,它们不会更改其状态。这些函数分配纹理存储并设置纹理的格式;这些函数只是复制像素。这不被视为纹理的状态。SubImageImageSubImage

请允许我重复一遍:这些是修改纹理状态的唯一函数。 修改环境状态;它不会影响存储在纹理对象中的任何内容。glTexEnv

活性纹理

纹理的情况更为复杂,同样出于传统原因,最好不要透露。这就是glActiveTexture的用武之地。

对于纹理,不仅有目标 (, 等)。还有 纹理单元。就我们的C/C++示例而言,我们有这样的:GL_TEXTURE_1DGL_TEXTURE_CUBE_MAP

Object *g_objs[MAX_OBJECTS][MAX_LOCATIONS] = {NULL};
int g_currObject = 0;

void BindObject(int loc, Object *obj)
{
  g_objs[g_currObject][loc] = obj;
}

void ActiveObject(int currObject)
{
  g_currObject = currObject;
}

请注意,现在,我们不仅有一个s的2D列表,而且我们还有一个当前对象的概念。我们有一个设置当前对象的函数,我们有一个最大数量的当前对象的概念,并且我们所有的对象操作函数都经过调整以从当前对象中进行选择。Object

更改当前活动对象时,将更改整个目标位置集。因此,您可以绑定进入当前对象 0 的内容,切换到当前对象 4,然后修改一个完全不同的对象。

这种与纹理对象的类比是完美的...几乎。

看,不取整数;它需要一个枚举器。从理论上讲,这意味着它可以从 到 .但有一件事你必须明白:glActiveTextureGL_TEXTURE0GL_TEXTURE31

这是错误的!

可以采用的实际范围由 控制。这是实现允许的最大并发多纹理数。它们分别被划分为不同的分组,用于不同的着色器阶段。例如,在 GL 3.x 类硬件上,您将获得 16 个顶点着色器纹理、16 个片段着色器纹理和 16 个几何着色器纹理。因此,将是48。glActiveTextureGL_MAX_COMBINED_TEXTURE_IMAGE_UNITSGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS

但是没有48个枚举器。这就是为什么不真正采用枚举器的原因。正确的调用方式如下:glActiveTextureglActiveTexture

glActiveTexture(GL_TEXTURE0 + i);

其中 是介于 0 和 之间的数字。iGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS

渲染

那么,所有这些与渲染有什么关系呢?

使用着色器时,将采样器制服设置为纹理图像单元(图像单元位于何处)。这表示您与 一起使用的数字。采样器将根据采样器类型选择目标。因此,将从目标中挑选。这是采样器具有不同类型的原因之一。glUniform1i(samplerLoc, i)iglActiveTexturesampler2DGL_TEXTURE_2D

现在,这听起来很可疑,就像您可以拥有两个GLSL采样器一样,它们具有使用相同纹理图像单元的不同类型。但你不能;OpenGL禁止这样做,并且在您尝试渲染时会给您一个错误。

您可以创建大约与系统中可用内存一样多的纹理对象。这些对象保存纹理的实际数据(纹素)以及glTexParameter提供的参数(请参阅常见问题解答)。

创建时,必须将一个纹理目标分配给一个纹理对象,该对象表示纹理的类型 (, , , ...)。GL_TEXTURE_2DGL_TEXTURE_3DGL_TEXTURE_CUBE

这两个项目,纹理对象纹理目标表示纹理数据。我们稍后再来讨论他们。

纹理单元

现在,OpenGL提供了一个纹理单元数组,可以在绘图时同时使用。阵列的大小取决于OpenGL系统,你的有8个。

可以将纹理对象绑定到纹理单元,以便在绘图时使用给定的纹理。

在一个简单易用的世界中,要使用给定的纹理进行绘制,您需要将纹理对象绑定到纹理单元,然后您就可以做到(伪代码):

glTextureUnit[0] = textureObject

由于GL是一个状态机,因此它不能以这种方式工作。假设我们有纹理目标的数据,我们将前面的赋值表示为:textureObjectGL_TEXTURE_2D

glActiveTexture(GL_TEXTURE0);                   // select slot 0 of the texture units array
glBindTexture(GL_TEXTURE_2D, textureObject);    // do the binding

请注意,这实际上取决于要绑定的纹理的类型。GL_TEXTURE_2D

纹理对象

在伪代码中,要设置纹理数据或纹理参数,例如:

setTexData(textureObject, ...)
setTexParameter(textureObject, TEXTURE_MIN_FILTER, LINEAR)

OpenGL不能直接操作纹理对象,要更新/设置它们的内容,或更改它们的参数,你必须首先将它们绑定到活动的纹理单元(以它为准)。等效代码变为:

glBindTexture(GL_TEXTURE_2D, textureObject)       // this 'installs' textureObject in texture unit
glTexImage2D(GL_TEXTURE_2D, ...)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

着色

着色器可以访问所有纹理单元,它们不关心活动纹理。

采样器制服是表示要用于采样器的纹理单元(而不是要使用的纹理对象)的索引的值。int

因此,您必须将纹理对象绑定到要使用的单位。

采样器的类型将与纹理单元中使用的纹理目标进行匹配:for ,依此类推...Sampler2DGL_TEXTURE_2D

想象一下,GPU就像一些油漆加工厂。

有许多罐子,它们将染料输送到一些涂装机。在涂漆机中,然后将染料应用于物体。这些坦克是纹理单位

这些罐可以配备不同种类的染料。每种染料都需要某种其他类型的溶剂。"溶剂"是质地目标。为方便起见,每个罐子都连接到一些溶剂供应,但每个罐中一次只能使用一种溶剂。所以有一个阀门/开关, , , .您可以同时将所有染料类型填充到罐中,但由于只有一种溶剂进入,因此只会"稀释"匹配的染料。因此,您可以绑定每种质地,但是与"最重要的"溶剂的结合实际上会进入罐中并与它所属的染料混合。TEXTURE_CUBE_MAPTEXTURE_3DTEXTURE_2DTEXTURE_1D

然后是染料本身,它来自仓库,并通过"绑定"将其填充到罐中。这就是你的质地。

何时使用 glActiveTexture?

在 OpenGL 编程指南一书中,示例 9-7 使用两个纹理对象,它在调用 glBindTexture 之前不调用 glActiveTexture,而在示例 9-10 中,它在 glBindTexture 之前调用 glActiveTexture。有什么区别?

glActiveTexture 和 glBindTexture 有什么区别?似乎它们都可以激活纹理。

想象一下,OpenGL 内部看起来像这样:


struct TextureUnit
{
    GLuint targetTexture1D;
    GLuint targetTexture2D;
    GLuint targetTexture3D;
    GLuint targetTextureCube;
    ...
};

TextureUnit textureUnits[GL_MAX_TEXTURE_IMAGE_UNITS]
GLuint currentTextureUnit = 0;

glActiveTexture的意思是:


void glActiveTexture(GLenum textureUnit)
{
    currentTextureUnit = GL_TEXTURE0 - textureUnit;
}

glBindTexture就是这样做的:


void glBindTexture(GLenum textureTarget, GLuint textureObject)
{
    TextureUnit *texUnit = &textureUnits[currentTextureUnit];
    switch(textureTarget)
    {
    case GL_TEXTURE_1D: texUnit->targetTexture1D = textureObject; break;
    case GL_TEXTURE_2D: texUnit->targetTexture2D = textureObject; break;
    case GL_TEXTURE_3D: texUnit->targetTexture3D = textureObject; break;
    case GL_TEXTURE_CUBEMAP: texUnit->targetTextureCube = textureObject; break;
    }
}

显然会有错误测试,但这就是想法。修改纹理的所有函数都使用 glActiveTexture 设置的"currentTextureUnit"。它们采用的目标参数告诉要使用的纹理单元中的绑定纹理位置。

因此,如果您有:


glActiveTexture(GL_TEXTURE0 + 5);
glBindTexture(GL_TEXTURE_2D, object);
glTexImage2D(GL_TEXTURE_2D, ...);

要上传到的纹理是存储在 textureUnits[5]->targetTexture2D 中的纹理。绑定的每个纹理都有一个纹理目标和一个纹理单元。这将指定其在上下文中的唯一位置。

我没有那本特定的书,但人们经常将纹理绑定到上下文中,只是为了上传一些数据或修改它。此时,将其绑定到哪个纹理单元并不重要,因此无需设置当前纹理单元。glTexImage2D不关心当前活动纹理是0,1,40还是其他什么。

但是,纹理单元对对象的渲染具有特殊意义。绑定纹理以便与纹理一起渲染时,需要将它们绑定到特定的纹理单元。因此,您需要在执行绑定之前设置当前纹理单元。

示例9-10不完整;也许这就是为什么你感到困惑。以这种方式思考:如果需要同时使用多个纹理,则必须应用 glActiveTexture() 来设置每个纹理单元(请参阅 Alfonse 之前的帖子)。如果一次只需要一个纹理,则只使用一个单位(通常为 0)。

请注意,纹理单元的数量是有限的。在移动设备上,通常只有两个。在台式机系统上,它应至少为 8。

你已经得到了一些很好的答案。我只想补充一点。glActiveTexture 选择活动纹理单元,glBindTexture 将纹理绑定到活动纹理单元。所以你看到他们携手合作。

GL 不是使用幕后的"活动纹理单元"选择器来帮助定义 BindTexture 的功能,而是可以在一个独立的 GL 调用中将参数提供给两个 API。事实上,这就是在EXT_direct_state_access 12函数 glBindMultiTextureEXT:


void BindMultiTextureEXT(enum texunit, enum target, uint texture);

这完全符合我们刚才讨论的内容。你告诉它你想要绑定哪个"纹理",它的纹理类型是什么(目标),以及你想要绑定它的"纹理单元"。一切都在那里,没有任何幕后选择器。

此扩展为许多其他纹理调用定义了类似的 API,此外还有许多其他调用。

如果不调用 glActiveTexture,则它使用默认值,即 0(GL_TEXTURE0)。

如果需要将纹理绑定到另一个 tex 单元,则需要 glActiveTexture。

尽管有这个名字,glActiveTexture不会激活纹理单元。我真的不知道为什么他们不只是在GL 1.2.1中创建glBindMultiTexture函数。

当时有一种"让我们不要修改旧的GL函数,而只是引入另一个"的态度。现在必须忍受它。

GLES2标准至少需要8个纹理单元,但不太确定GLES1需要什么。顺便说一句,使用PowerVR SGX的N900仅支持:8个纹理单元。按照今天的标准,N900中的SGX在图腾柱上相当低,并且较新的设备通常比N900中的SGX更快(也足够频繁地使用SGX,但更高的时钟和更高的"型号")。

红皮书在固定功能方面非常出色,但几乎没有提供关于可编程管道中正在发生的事情的线索。另一方面,Wiki过于简单化了。

您有六个不同的常量,用于定义可以使用多少个采样器对象:

  • GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
  • GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,
  • GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,
  • GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS,
  • GL_MAX_TEXTURE_IMAGE_UNITS和
  • GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS。

前5个中的每一个都定义了特定可编程流水线级中纹理图像单元的最大数量。最后一个定义了可在所有阶段中同时使用的纹理图像单元的总数。从理论上讲,MAX_COMBINED可以是所有其他值的总和,但在实践中,由于纹理单元可能是共享的,因此该数字可能会更小。

纹理参数存储在纹理对象中,而不是纹理单元中。因此,当您调用后跟 时,调用会修改您刚刚绑定到该纹理单元的纹理的状态。如果随后将不同的纹理绑定到该纹理单元并调用 ,它将修改第二个纹理的状态;第一个纹理将保留其未绑定时的状态。glBindTextureglTexParameterglTexParameterglTexParameter

纹理单元只不过是对实际纹理的引用集合。其状态完全由绑定到每个目标的纹理以及(自 3.3 起)绑定到纹理单元的任何采样器(采样器对象允许将采样状态与纹理分开存储)组成。使用 OpenGL 4.5 或扩展,可以创建和修改纹理,而无需将它们绑定到纹理单元(通过 、 、 )。使用扩展(不在任何核心版本中),可以使用纹理,而无需将它们绑定到纹理单元。ARB_direct_state_accessglTextureStorage*glTextureSubImage*glTextureParameter*ARB_bindless_texture

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。
以下是一个简单的例子,展示了如何使用OpenGL ES和MediaCodec将YUV格式编码成MP4视频。在此之前,需要确保您已经了解了OpenGL ES和MediaCodec的基本使用方法。 首先,需要创建OpenGL ES环境,并将YUV数据绘制到纹理上。以下是示例代码: ```c++ // 创建OpenGL ES环境 EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); EGLint major, minor; eglInitialize(eglDisplay, &major, &minor); EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 0, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLint numConfigs; EGLConfig eglConfig; eglChooseConfig(eglDisplay, configAttribs, &eglConfig, 1, &numConfigs); EGLint pbufferAttribs[] = { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE, }; EGLSurface eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, pbufferAttribs); eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); // 创建OpenGL ES纹理 GLuint textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // 绘制YUV数据到纹理上 glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, YUVData); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width / 2, height / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, YUVData + width * height); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width / 2, height / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, YUVData + width * height * 5 / 4); ``` 然后,需要创建MediaCodec编码器,并将OpenGL ES纹理作为输入数据。以下是示例代码: ```c++ // 创建MediaCodec编码器 AMediaFormat* format = AMediaFormat_new(); AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "video/avc"); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, width); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, height); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, bitRate); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, frameRate); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, OMX_COLOR_FormatYUV420SemiPlanar); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, iFrameInterval); AMediaCodec* codec = AMediaCodec_createEncoderByType("video/avc"); AMediaCodec_configure(codec, format, NULL, NULL, AMEDIACODEC_CONFIGURE_FLAG_ENCODE); AMediaCodec_start(codec); // 将OpenGL ES纹理作为输入数据 AMediaCodecBufferInfo bufferInfo; memset(&bufferInfo, 0, sizeof(bufferInfo)); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); for (int i = 0; i < frameCount; i++) { GLuint textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // 绘制YUV数据到纹理上 glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, YUVData); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width / 2, height / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, YUVData + width * height); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width / 2, height / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, YUVData + width * height * 5 / 4); // 将纹理作为输入数据 glUseProgram(program); glUniform1i(texSamplerHandle, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // 从MediaCodec编码器获取输出数据 int outputBufferIndex = AMediaCodec_dequeueOutputBuffer(codec, &bufferInfo, 0); if (outputBufferIndex >= 0) { AMediaCodecBufferInfo* outputBufferInfo = AMediaCodec_getOutputBufferInfo(codec, outputBufferIndex); uint8_t* outputBuffer = AMediaCodec_getOutputBuffer(codec, outputBufferIndex); // 将输出数据写入MP4文件 fwrite(outputBuffer, 1, outputBufferInfo->size, outputFile); AMediaCodec_releaseOutputBuffer(codec, outputBufferIndex, false); } } ``` 最后,需要释放资源并停止编码器。以下是示例代码: ```c++ // 释放资源 AMediaCodec_stop(codec); AMediaCodec_delete(codec); AMediaFormat_delete(format); glDeleteTextures(1, &textureID); eglDestroySurface(eglDisplay, eglSurface); eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(eglDisplay, eglContext); eglTerminate(eglDisplay); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AppNinja

你的鼓励是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值