基于安卓的裸眼立体播放器

来自CGTWiki
跳转至:导航搜索

基础:在Android平台下使用MediaPlayer和GLSurfaceView进行视频播放

1. 视频

百度网盘链接:https://pan.baidu.com/s/19M1LojKwa6tJJim1sM3L8g 提取码:xf34

2. 源码

链接①:https://pan.baidu.com/s/1xy7PB6oBM3MK_wyVoB7S1Q 提取码:9c36

链接②:文件:VideoPlayer-20210203.rar

3.前言文字版

生成缩略图出错:尺寸超过12.5 MP的文件










①由于系统不支持上传wmv格式的视频文件,所以上传到了百度网盘

②由于视频时长3个多小时,并且其中大部分时间都是在手撕代码,而源码中包含有大量注释,观看视频效率不高,因此建议只需查看“视频0.0节”、“前言文字版”和“源码”就可以了。

源码

链接:https://pan.baidu.com/s/1Q-eczMhrNmnkMUiYopn_gA 提取码:jcj8

实验与验证步骤

文件:实验与验证步骤.docx

软件框图

流程图

人眼跟踪与视点排布

片段着色器代码(软件2.0版应该更新为此代码)

Shader "Hidden/EyeTrackingShader"
{
    Properties
    {
        _MainTex ("Texture", 2D)     =      "white" {}
		_Width("Width", float)       =      3840.0
		_Height("Height", float)     =      2160.0
		_isRGB("isRGB",float)        =      1.0
		_isTest("isTest",float)      =      1.0
		_scale("Scale",float)        =      1.0
		_IncAngle("IncAngle", float) =      0.6667
		_LineNum ("LineNum", float)  =      1.66667

		_eyePosX("eyePosX", float)   =      0.0
		_eyePosY("eyePosY", float)   =      0.0
		_deltaX("deltaX", float)     =      0.0
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D        _MainTex;
			uniform float    _LineNum;
			uniform float    _IncAngle;

			uniform float    _isRGB ;
			uniform float    _isTest;

			uniform float    _Width;
			uniform float    _Height;
			uniform float    _scale;
			uniform float    _deltaX;
			uniform float    _eyePosX;
			uniform float    _eyePosY;



			int getViewNUM(float i, float j, float k)
			{
				float step_value = 0.5f * _LineNum;
				float value_pixel = j * 3 + 3 * i * _IncAngle + k;

				float eyeTrackingShift =  (_eyePosX + _IncAngle * _eyePosY)/ _scale;
				
				value_pixel += -eyeTrackingShift + _deltaX;

				float judge_value = value_pixel - int(value_pixel / _LineNum) * _LineNum ;

				while (0 > judge_value)           
				{
					judge_value += _LineNum;
				}

				int view_point_number = floor(judge_value / step_value);

				return view_point_number;
			}


            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);

				float x = i.uv[0];
				float y = 1 - i.uv[1];

				int m = y * _Height;
				int n = x * _Width;


				float2 leftCoord  = float2(x*0.5 ,      i.uv[1]);
				float2 rightCoord = float2(x*0.5 + 0.5, i.uv[1]);

				if (_isTest ==1.0)
				{
					if (_isRGB != 1.0)
					{
						if (getViewNUM((float)m, (float)n, 0.0) > 0.5)
						{
							col.x = tex2D(_MainTex, leftCoord).x;
						}
						else
						{
							col.x = tex2D(_MainTex, rightCoord).x;
						}
						if (getViewNUM((float)m, (float)n, 1.0) > 0.5)
						{
							col.y = tex2D(_MainTex, leftCoord).y;
						}
						else
						{
							col.y = tex2D(_MainTex, rightCoord).y;
						}
						if (getViewNUM((float)m, (float)n, 2.0) > 0.5)
						{
							col.z = tex2D(_MainTex, leftCoord).z;
						}
						else
						{
							col.z = tex2D(_MainTex, rightCoord).z;
						}

					}
					else
					{
						if (getViewNUM((float)m, (float)n, 2.0) > 0.5)
						{
							col.x = tex2D(_MainTex, leftCoord).x;
						}
						else
						{
							col.x = tex2D(_MainTex, rightCoord).x;
						}
						if (getViewNUM((float)m, (float)n, 1.0) > 0.5)
						{
							col.y = tex2D(_MainTex, leftCoord).y;
						}
						else
						{
							col.y = tex2D(_MainTex, rightCoord).y;
						}
						if (getViewNUM((float)m, (float)n, 0.0) > 0.5)
						{
							col.z = tex2D(_MainTex, leftCoord).z;
						}
						else
						{
							col.z = tex2D(_MainTex, rightCoord).z;
						}
					}
				}
				else
				{
					if (_isRGB == 1.0)
					{
						if (getViewNUM((float)m, (float)n, 0.0) > 0.5)
						{
							col.x = 1.0;
						}
						else
						{
							col.x = 0.0;
						}
						if (getViewNUM((float)m, (float)n, 1.0) > 0.5)
						{
							col.y = 1.0;
						}
						else
						{
							col.y = 0.0;
						}
						if (getViewNUM((float)m, (float)n, 2.0) > 0.5)
						{
							col.z = 1.0;
						}
						else
						{
							col.z = 0.0;
						}

					}
					else
					{
						if (getViewNUM((float)m, (float)n, 2.0) > 0.5)
						{
							col.x = 1.0;
						}
						else
						{
							col.x = 0.0;
						}
						if (getViewNUM((float)m, (float)n, 1.0) > 0.5)
						{
							col.y = 1.0;
						}
						else
						{
							col.y = 0.0;
						}
						if (getViewNUM((float)m, (float)n, 0.0) > 0.5)
						{
							col.z = 1.0;
						}
						else
						{
							col.z = 0.0;
						}
					}

				}
                return col;
            }
            ENDCG
        }
    }
}

最低硬件配置

Android开发板,自由立体显示器

开发日志

(只有猜测的大概时间,准确的记不清了) 2019/10/24-2019/10/28:安装Android开发环境(JDK+Android Studio+SDK),编写Android程序播放本地视频。

2019/10/28-2019/11/04:改写Android程序,使用OpenGL ES进行视频的播放。

2019/11/04-2019/11/09:在OpenGL ES的片段着色器中,使用glsl编写程序,使屏幕中只显示“左右格式3D视频”的左半面的视频。

2019/11/12-2019/11/28:修改X-Player源代码,使其在进行人眼检测的同时,使用OpenGL ES播放视频。

2019/11/28-2019/12/16:在glsl中编写程序,将九幅视差图像合成立体图像,实现九宫格视频的播放。

2019/12/17-2019/12/18:调整Android开发板性能。

2019/12/18-2019/12/23:测量“显示屏幕上的画面”到“显示屏幕”的距离l。根据眼睛的屏幕坐标,计算眼睛的三维坐标。

2019/12/23-2019/12/24:将计算得到的眼睛坐标传递给glsl,并在glsl中编写代码,参考定向子像素渲染算法,根据眼睛坐标和显示器显示参数计算视点排布,合成并显示立体图像。出现问题:左(右)眼看到50%的右(左)眼图像。

现存BUG

主要参考文献

参考文献

现阶段需要的实验室支持

方案一:使用3399开发板进行“视频播放+计算视点排布”,使用3280开发板进行人眼跟踪

问题:3280开发板不支持基于Camera2 API的人眼跟踪(可能 更新成支持人眼跟踪的Android系统能够解决)。如图:设置-->关于设备-->人脸识别、人脸类型 都显示不支持

关于设备-人脸识别和人脸类型都显示不支持

















方案二:使用3280开发板进行“视频播放+计算视点排布”,使用3399开发板进行人眼跟踪

问题:3280开发板(4K分辨率),计算视点排布时,视频播放卡顿

参与人员

张恒 戴任翔