对于视频使用YUV颜色格式的平台,需要额外的步骤来绘制这些视频。这涉及到使用着色器在基本体四边形上绘制两个表面。
首先阅读video_draw()参考页,了解有关函数为 YUV 视频返回的数据的信息,然后继续阅读下面的内容,了解有关使用该数据绘制视频的说明。
在项目中创建着色器资源,并将其碎片着色器 (.fsh) 代码替换为:
//
// CUSTOM fragment shader for handling YUV content
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform sampler2D v_chroma;
const float x = 1.164383;
const float y = 1.138393;
const float z = 1.138393;
const vec3 src_bias = vec3(16.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0);
const mat3 src_xform = mat3(1.00000000 * x, 0.00000000 * y, 1.57480000 * z,
1.00000000 * x, -0.18732427 * y, -0.46812427 * z,
1.00000000 * x, 1.85560000 * y, 0.00000000 * z);
void main()
{
float yy = texture2D(gm_BaseTexture, vec2(v_vTexcoord.x, v_vTexcoord.y)).r;
vec2 cbcr = texture2D(v_chroma, vec2(v_vTexcoord.x, v_vTexcoord.y)).rg;
vec3 yuv = vec3(yy, cbcr);
yuv -= src_bias;
yuv *= src_xform;
gl_FragColor = vec4(yuv, 1.0);
}
在创建对象事件中,获取v_chroma着色器制服的采样器ID(仅当视频为 YUV 时):
var _format = video_get_format();
if (_format == video_format_yuv)
{
videochromasampler = shader_get_sampler_index(shader_YUV, "v_chroma");
}
在对象的"绘制"事件中,调用video_draw(),如果其第一个数组位置为0(表示正在播放视频),请绘制视频。
在下面的代码中,我们在 video_get_format() 函数上使用 switch 语句。如果视频使用的是 RGBA 格式,则它只是在阵列的 [1] 位置绘制表面。
如果视频使用 YUV 格式,则使用着色器将两个表面 (位置 [1] 和 [2]) 绘制到基本体四边形上。
var _data = video_draw();
if(_data[0] == 0)
{
switch(video_get_format())
{
case video_format_rgba:
var _surf = _data[1];
draw_surface(_surf,0,0);
break;
// #### YUV PART HERE ####
case video_format_yuv:
var _surf = _data[1];
var _chromasurf = _data[2];
if(surface_exists(_surf) and surface_exists(_chromasurf))
{
shader_set(shader_YUV);
var _tex_id = surface_get_texture(_surf);
var _chroma_tex_id = surface_get_texture(_chromasurf);
texture_set_stage(videochromasampler, _chroma_tex_id);
gpu_set_texfilter(false);
draw_primitive_begin_texture(pr_trianglestrip, _tex_id);
draw_vertex_texture(0, 0, 0, 0);
draw_vertex_texture(surface_get_width(_chromasurf), 0, 1, 0);
draw_vertex_texture(0, surface_get_height(_chromasurf), 0, 1);
draw_vertex_texture(surface_get_width(_chromasurf), surface_get_height(_chromasurf), 1, 1);
draw_primitive_end();
gpu_set_texfilter(true);
shader_reset();
}
break;
}
}
case video_format_yuv:下的代码执行以下操作:
这里,主视频表面由基本体绘制,色度表面通过着色器与其混合。这就是为什么通过采样器将色度表面的纹理传递到着色器的原因。