对于视频使用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:下的代码执行以下操作:
这里,主视频表面由基本体绘制,色度表面通过着色器与其混合。这就是为什么通过采样器将色度表面的纹理传递到着色器的原因。