Metal(六) 案例之视频文件的渲染

本案例实现使用Metal读取视频文件,并渲染到屏幕上。(此时显示是没有声音的)
思路:

  1. 使用AVFundation中的AVAssetReaderTrackOutput方法,并将原始数据传入到CMSempleBuffer中。CMSempleBuffer存储的是每一帧的数据。
  2. Metal渲染回调将 CMSempleBuffer中的数据转成CVPixelBufferRef。
  3. 使用CoreVideo获取Y纹理和UV纹理。
  4. 自定义片元函数将YUV转成RGBA,显示出来。

1. 顶点函数和片元函数

  • 定点函数

在顶点函数中需要传入顶点坐标和纹理坐标。

//结构体(用于顶点函数输出/片元函数输入)
typedef struct
{
   
    float4 clipSpacePosition [[position]]; // position的修饰符表示这个是顶点
    
    float2 textureCoordinate; // 纹理坐标
    
} RasterizerData;

//RasterizerData 返回数据类型->片元函数
// vertex_id是顶点shader每次处理的index,用于定位当前的顶点
// buffer表明是缓存数据,0是索引
vertex RasterizerData
vertexShader(uint vertexID [[ vertex_id ]],
             constant CCVertex *vertexArray [[ buffer(CCVertexInputIndexVertices) ]])
{
   
    RasterizerData out;
    //顶点坐标
    out.clipSpacePosition = vertexArray[vertexID].position;
    //纹理坐标
    out.textureCoordinate = vertexArray[vertexID].textureCoordinate;
    return out;
}
  • 片元函数
    YUV转RGB使用转换矩阵:
float3 rgb = convertMatrix->matrix * (yuv + convertMatrix->offset);

在片元函数中需要传入Y、UV纹理和转换矩阵。

fragment float4
samplingShader(RasterizerData input [[stage_in]],
               texture2d<float> textureY [[ texture(CCFragmentTextureIndexTextureY) ]],
               texture2d<float> textureUV [[ texture(CCFragmentTextureIndexTextureUV) ]],
               constant CCConvertMatrix *convertMatrix [[ buffer(CCFragmentInputIndexMatrix) ]])
{
   
    //1.获取纹理采样器
    constexpr sampler textureSampler (mag_filter::linear,
                                      min_filter::linear);
    /*
     2. 读取YUV 颜色值
        textureY.sample(textureSampler, input.textureCoordinate).r
        从textureY中的纹理采集器中读取,纹理坐标对应上的R值.(Y)
        textureUV.sample(textureSampler, input.textureCoordinate).rg
        从textureUV中的纹理采集器中读取,纹理坐标对应上的RG值.(UV)
     */
    float3 yuv = float3(textureY.sample(textureSampler, input.textureCoordinate).r,
                        textureUV.sample(textureSampler, input.textureCoordinate).rg);
    
    //3.将YUV 转化为 RGB值.convertMatrix->matrix * (YUV + convertMatrix->offset)
    float3 rgb = convertMatrix->matrix * (yuv + convertMatrix->offset);
    
    //4.返回颜色值(RGBA)
    return float4(rgb, 1.0);
}

2. 设置纹理

在这里插入图片描述

  • 从现有图像缓冲区创建核心视频Metal纹理缓冲区。 将每一帧的数据从缓存中复制到Metal的纹理缓冲区。
参数1: allocator 内存分配器,默认kCFAllocatorDefault
     参数2: textureCache 纹理缓存区对象
     参数3: sourceImage 视频图像缓冲区
     参数4: textureAttributes 纹理参数字典.默认为NULL
     参数5: pixelFormat 图像缓存区数据的Metal 像素格式常量.注意如果MTLPixelFormatBGRA8Unorm和摄像头采集时设置的颜色格式不一致,则会出现图像异常的情况;
     参数6: width,纹理图像的宽度(像素)
     参数7: height,纹理图像的高度(像素)
     参数8: planeIndex.如果图像缓冲区是平面的,则为映射纹理数据的平面索引。对于非平面图像缓冲区忽略。
     参数9: textureOut,返回时,返回创建的Metal纹理缓冲区。
     
     // Mapping a BGRA buffer:
     CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textureCache, pixelBuffer, NULL, MTLPixelFormatBGRA8Unorm, width, height, 0, &outTexture);
     
     // Mapping the luma plane of a 420v buffer:
     CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textureCache, pixelBuffer, NULL, MTLPixelFormatR8Unorm, width, height, 0, &outTexture);
     
     // Mapping the chroma plane of a 420v buffer as a source texture:
     CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textureCache, pixelBuffer, NULL, MTLPixelFormatRG8Unorm width/2, height/2, 1, &outTexture);
     
     // Mapping a yuvs buffer as a source texture (note: yuvs/f and 2vuy are unpacked and resampled -- not colorspace converted)
     CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textureCache, pixelBuffer, NULL, MTLPixelFormatGBGR422, width, height, 1, &outTexture);
  • 从CMSampleBuffer读取CVPixelBuffer
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
  • 返回纹理缓冲区的Metal纹理对象。 将临时的纹理对象赋值到全局的纹理对象。
CVMetalTextureGetTexture(</
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值