YUV 视频

对于视频使用YUV颜色格式的平台,需要额外的步骤来绘制这些视频。这涉及到使用着色器在基本体四边形上绘制两个表面。

首先阅读video_draw()参考页,了解有关函数为 YUV 视频返回的数据的信息,然后继续阅读下面的内容,了解有关使用该数据绘制视频的说明。

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:下的代码执行以下操作:

这里,主视频表面由基本体绘制,色度表面通过着色器与其混合。这就是为什么通过采样器将色度表面的纹理传递到着色器的原因。