热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

利用GLSL在iOS上实现YV12到RGB的转换,并附带展示结果图像

本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。

referred to this question

提到这个问题

i convert the yv12 frame data to rgb data using glsl shader,the raw image below: enter image description here

我使用glsl着色器将yv12帧数据转换为rgb数据,原始图像如下:

but the result image is not same with the former,attached below: enter image description here

但结果图像与前者不相同,如下图所示:

following is my code for uploading the three planar data to textures:

以下是我上传三个平面数据到纹理的代码:

- (GLuint) textureY: (Byte*)imageData        
      widthType: (int) width       
     heightType: (int) height       
{          
    GLuint texName;    
    glGenTextures( 1, &texName );     
    glBindTexture(GL_TEXTURE_2D, texName);

    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);    

    glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData );  
    //free(imageData);

    return texName;    
}    

- (GLuint) textureU: (Byte*)imageData        
          widthType: (int) width       
         heightType: (int) height       
{          
    GLuint texName;    

    glGenTextures( 1, &texName );     
    glBindTexture(GL_TEXTURE_2D, texName);


    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);    

    glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData );    

    //free(imageData);
    return texName;    
}    

- (GLuint) textureV: (Byte*)imageData        
          widthType: (int) width       
         heightType: (int) height       
{          
    GLuint texName;    
    glGenTextures( 1, &texName );     
    glBindTexture(GL_TEXTURE_2D, texName);


    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);    

    glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData );    

    //free(imageData);
    return texName;    
}    


- (void) readYUVFile     
{    
    NSString *file = [[NSBundle mainBundle] pathForResource:@"video" ofType:@"yv12"];
    NSLog(@"%@",file);
    NSData* fileData = [NSData dataWithContentsOfFile:file]; 
    //NSLog(@"%@",[fileData description]);
    NSInteger width  = 352;    
    NSInteger height = 288;
    NSInteger uv_width  = width  / 2;    
    NSInteger uv_height = height / 2;
    NSInteger dataSize = [fileData length];
    NSLog(@"%i\n",dataSize);

    GLint nYsize  = width * height;     
    GLint nUVsize = uv_width * uv_height;      
    GLint nCbOffSet = nYsize;    
    GLint nCrOffSet = nCbOffSet + nUVsize;    

    Byte *spriteData = (Byte *)malloc(dataSize);
    [fileData getBytes:spriteData length:dataSize];


    Byte* uData = spriteData + nCbOffSet;
    //NSLog(@"%@\n",[[NSData dataWithBytes:uData length:nUVsize] description]);
    Byte* vData = spriteData + nCrOffSet;  
    //NSLog(@"%@\n",[[NSData dataWithBytes:vData length:nUVsize] description]);
    /**
    Byte *YPlanarData = (Byte *)malloc(nYsize);
    for (int i=0; i

and my fragment shaders code:

我的片段着色器代码:

   precision highp float;
uniform sampler2D SamplerY;
uniform sampler2D SamplerU;
uniform sampler2D SamplerV;

varying highp vec2 coordinate;

void main()
{
    highp vec3 yuv,yuv1;
    highp vec3 rgb;

    yuv.x = texture2D(SamplerY, coordinate).r;

    yuv.y = texture2D(SamplerU, coordinate).r-0.5;

    yuv.z = texture2D(SamplerV, coordinate).r-0.5 ;

   rgb = mat3(      1,       1,      1,
                     0, -.34414, 1.772,
               1.402, -.71414,      0) * yuv;

    gl_FragColor = vec4(rgb, 1);
}

my confusion is the conversion formula while i using this formula directly converting the yv12 data to rgb24,and draw a image with the

我的混淆是转换公式,我使用这个公式直接将yv12数据转换为rgb24,并绘制一个图像。

CGImageCreate(iwidth, 
                                       iheight, 
                                       8, 
                                       24, 
                                       iwidth*3, 
                                       colorSpace, 
                                       bitmapInfo, 
                                       provider, 
                                       NULL, 
                                       NO, 
                                       kCGRenderingIntentDefault);

the result image is correct. but using the shader (for the direct transform approach running on iOS device is dump) turns to this problem ,i've tried some tricks(expand the UV planers to (2*uv_width)*2(uv_height) rectangle and then upload the texture),but failed in the same more red image.

结果图像是正确的。但是使用shader(在iOS设备上运行的直接转换方法是dump)转向这个问题,我尝试了一些技巧(将UV planers扩展到(2*uv_width)*2(uv_height)矩形,然后上传纹理),但是在相同的红色图像中失败了。

How to resolve this issue?

如何解决这个问题?

attached with my whole glView.m code:

连同我的整个glView。m代码:

#import "OpenGLView.h"

typedef struct {
    float Position[3];
    float TexCoord[2];
} Vertex;

const Vertex Vertices[] = {
    {{1, -1, 0},{1,1}},
    {{1, 1, 0},{1,0}},
    {{-1, 1, 0},{0,0}},
    {{-1, -1, 0},{0,1}}
};

const GLubyte Indices[] = {
    0, 1, 2,
    2, 3, 0
};



@interface OpenGLView ()
- (void)setupLayer;
- (void)setupContext;
- (void)setupRenderBuffer;
- (void)setupFrameBuffer;
- (void)render;

- (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType;
- (void)setupVBOs;
- (void)compileShaders;

- (void) readYUVFile;
@end

@implementation OpenGLView

- (void)setupVBOs {

    GLuint vertexBuffer;
    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);

    GLuint indexBuffer;
    glGenBuffers(1, &indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);

}



- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code[]
        self.backgroundColor = [UIColor redColor];
        [self setupLayer];
        [self setupContext];
        [self setupRenderBuffer];
        [self setupFrameBuffer];

        [self setupVBOs];
        [self compileShaders];
        [self readYUVFile];

        [self render];

    }
    return self;
}

+ (Class)layerClass{
    return [CAEAGLLayer class];
}

-(void)setupLayer{
    _eaglLayer = (CAEAGLLayer *)self.layer;
    _eaglLayer.opaque = YES;
}

- (void)setupContext{
    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
    _cOntext= [[[EAGLContext alloc] initWithAPI:api] autorelease];

    if (!_context) {
        NSLog(@"Failed to initialize OpenGLES 2.0 context");
        exit(1);
    }

    if (![EAGLContext setCurrentContext:_context]) {
        NSLog(@"Failed to set current OpenGL context");
        exit(1);
    }
}

- (void)setupRenderBuffer {
    glGenRenderbuffers(1, &_colorRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);        
    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];    
}

- (void)setupFrameBuffer {    
    GLuint framebuffer;
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
                              GL_RENDERBUFFER, _colorRenderBuffer);
}

- (GLuint) textureY: (Byte*)imageData        
          widthType: (int) width       
         heightType: (int) height       
{          
    GLuint texName;    
    glGenTextures( 1, &texName );     
    glBindTexture(GL_TEXTURE_2D, texName);

    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);    

    glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData );  
    //free(imageData);

    return texName;    
}    

- (GLuint) textureU: (Byte*)imageData        
          widthType: (int) width       
         heightType: (int) height       
{          
    GLuint texName;    

    glGenTextures( 1, &texName );     
    glBindTexture(GL_TEXTURE_2D, texName);


    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);    

    glTexImage2D( GL_TEXTURE_2D, 0, GL_RED_EXT, width, height, 0, GL_RED_EXT, GL_UNSIGNED_BYTE, imageData );    

    //free(imageData);
    return texName;    
}    

- (GLuint) textureV: (Byte*)imageData        
          widthType: (int) width       
         heightType: (int) height       
{          
    GLuint texName;    
    glGenTextures( 1, &texName );     
    glBindTexture(GL_TEXTURE_2D, texName);


    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);    

    glTexImage2D( GL_TEXTURE_2D, 0, GL_RED_EXT, width, height, 0, GL_RED_EXT, GL_UNSIGNED_BYTE, imageData );    

    //free(imageData);
    return texName;    
}    


- (void) readYUVFile     
{    
    NSString *file = [[NSBundle mainBundle] pathForResource:@"video" ofType:@"yv12"];
    NSLog(@"%@",file);
    NSData* fileData = [NSData dataWithContentsOfFile:file]; 
    //NSLog(@"%@",[fileData description]);
    NSInteger width  = 352;    
    NSInteger height = 288;
    NSInteger uv_width  = width  / 2;    
    NSInteger uv_height = height / 2;
    NSInteger dataSize = [fileData length];
    NSLog(@"%i\n",dataSize);

    GLint nYsize  = width * height;     
    GLint nUVsize = uv_width * uv_height;      
    GLint nCbOffSet = nYsize;    
    GLint nCrOffSet = nCbOffSet + nUVsize;    

    Byte *spriteData = (Byte *)malloc(dataSize);
    [fileData getBytes:spriteData length:dataSize];


    Byte* uData = spriteData + nCbOffSet;
    //NSLog(@"%@\n",[[NSData dataWithBytes:uData length:nUVsize] description]);
    Byte* vData = spriteData + nCrOffSet;  
    //NSLog(@"%@\n",[[NSData dataWithBytes:vData length:nUVsize] description]);

    Byte *YPlanarData = (Byte *)malloc(nYsize);
    for (int i=0; i

1 个解决方案

#1


2  

my foolish mistake,the three uploading-texture process and fragment shader are correct ,but the following code are not compatible:

我的愚蠢错误,三个上传纹理的过程和片段着色器是正确的,但是下面的代码是不兼容的:

glActiveTexture(GL_TEXTURE0); 
glBindTexture(GL_TEXTURE_2D, _YPlanarTexture);
glUniform1i(_textureUniformY, 0);

glActiveTexture(GL_TEXTURE1); 
glBindTexture(GL_TEXTURE_2D, _UPlanarTexture);
glUniform1i(_textureUniformU, 1);

glActiveTexture(GL_TEXTURE2); 
glBindTexture(GL_TEXTURE_2D, _VPlanarTexture);
glUniform1i(_textureUniformV, 2);

and below:

和下面的:

_YPlanarTexture = glGetUniformLocation(programHandle, "SamplerY");
_UPlanarTexture = glGetUniformLocation(programHandle, "SamplerU");
_VPlanarTexture = glGetUniformLocation(programHandle, "SamplerV");

so replace with this:

所以替换为:

_textureUniformY = glGetUniformLocation(programHandle, "SamplerY");
_textureUniformU = glGetUniformLocation(programHandle, "SamplerU");
_textureUniformV = glGetUniformLocation(programHandle, "SamplerV");

then it will do right thing .

这样做是对的。


推荐阅读
  • 深入理解Redis的数据结构与对象系统
    本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • 本文介绍了如何在C#中启动一个应用程序,并通过枚举窗口来获取其主窗口句柄。当使用Process类启动程序时,我们通常只能获得进程的句柄,而主窗口句柄可能为0。因此,我们需要使用API函数和回调机制来准确获取主窗口句柄。 ... [详细]
  • 本文详细解析了Python中的os和sys模块,介绍了它们的功能、常用方法及其在实际编程中的应用。 ... [详细]
  • Scala 实现 UTF-8 编码属性文件读取与克隆
    本文介绍如何使用 Scala 以 UTF-8 编码方式读取属性文件,并实现属性文件的克隆功能。通过这种方式,可以确保配置文件在多线程环境下的一致性和高效性。 ... [详细]
  • 选择适合生产环境的Docker存储驱动
    本文旨在探讨如何在生产环境中选择合适的Docker存储驱动,并详细介绍不同Linux发行版下的配置方法。通过参考官方文档和兼容性矩阵,提供实用的操作指南。 ... [详细]
author-avatar
仰望天空说再见
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有