1.Apple Vision Pros使用的源码MV-HEVC编码格式
2.UE4:Niagara扩展CameraQuery支持CPU获取ViewSize
3.surfaceviewåviewçåºå«
Apple Vision Pros使用的MV-HEVC编码格式
MV-HEVC,全称Multiview High Efficiency Video Coding,解析是源码HEVC(High Efficiency Video Coding)编码标准的扩展部分,记为HEVC version 2。解析这一视频编码标准自年7月发布以来,源码相关标准于年月发布。解析死亡细胞源码然而,源码尽管这一标准已发布近十年,解析但在具体业务中的源码应用却并不多。
年6月,解析在WWDC开发者大会上,源码苹果公司宣布,解析通过iOS .2 Beta版本,源码iPhone Pro能够拍摄出Apple Vision Pro的解析空间视频,而Apple Vision Pro所采用的源码xnat 源码视频编码格式,正是MV-HEVC。
为何苹果选择使用MV-HEVC格式来实现3D视频编码?在开发者大会上,苹果介绍了3D视频的视频,链接地址如下:developer.apple.com/vid...
苹果表示,MV-HEVC实际上是HEVC,而目前对HEVC视频编码格式支持最好的或许就是苹果。无论是基于HEVC的HEIF静态格式、HEVC的动图live photo,还是苹果的HEVC视频hvc1,苹果都提供了良好的支持。
苹果在开发者大会上所提到的“空间视频”,其原理与我们在**院看的3D**类似,都是利用人眼的左右眼视差来制造和表现“立体”效果。
从视频编解码的403源码角度来看,使用MV-HEVC方案的好处是,它可以在不改变slice层以下的HEVC原有语法和解码过程下,通过layer间预测技术实现对3D和多视角视频的支持。这也意味着MV-HEVC可后向兼容和使用现有的HEVC编码器和解码器,不需要有较大的修改,仅修改high level语法即可。
如果对MV-HEVC格式做了Block Level语法的修改,此时对应的便是JCT-3V制定的3D-HEVC格式,它的压缩性能要比MV-HEVC更高,会有额外的压缩性能的工具。
目前MV-HEVC和3D-HEVC的参考软件都是同一套代码,叫做HTM。hevc.hhi.fraunhofer.de/...
HTM的代码是使用SVN进行版本管理的,如果想下载源码,halcon源码在macOS上可以在终端直接使用下面的命令检出代码:
在HTM源码的TypeDef.h头文件中,可以看到有一个HEVC_EXT宏,如果这个宏的值是1,此时编译的就是MV-HEVC,而如果是2,此时就是3D-HEVC。
在MV-HEVC标准中语法元素LayerId,表示该NALU所归属的view。在空间视频中,通常用LayerId 0表示该帧属于左视点(通常也是主视点),LayerId 1则表示属于右视点(辅视点)。
属于主视点的图像编码参考帧规则保持和沿用标准HEVC,它得到的码流就是标准HEVC码流,而辅视点每一帧图像编码多了视点间的svprogresshud 源码参考帧,如果显示设备还不支持解码和播放MV-HEVC格式,那就可以只解码和显示主视点的标准HEVC码流,就像把3D**用2D来看一样。
实际上3D-HEVC,MV-HEVC以及Scalable HEVC有一样的层间预测技术,都可以抽取出base view码流,且能用支持Main profile的HEVC解码器来解码。而3D-HEVC里还可以抽取出MV-HEVC的码流,因为MV-HEVC加上Depth信息就是3D-HEVC,而HEVC加上delta信息就是MV-HEVC。
最后,再来看一下MV-HEVC名字里的view具体是什么?view表示All layers belonging to the same camera perspective,包括像苹果的MV-HEVC格式,通常是有2个view,分别是left view和right view,对应人眼的左眼和右眼。
当然也可以有多个view,下图是4个layer和2个view的编码结构和参考依赖图。
以上是对MV-HEVC的简单介绍,由于目前能够支持对其进行正常解析和解码的硬件和软件几乎没有,所以暂时不能对实际拍摄的空间视频做更多分析和介绍。更多MV-HEVC对高层语法的修改内容请参考文章后面的参考资料4。
虽然今天来看MV-HEVC不是什么新技术,但苹果能在自家手机和消费终端Apple Version Pro上首次推广和使用这个技术,让这个技术更接近用户,此举是值得点赞的。而对我们这些视频编解码算法工程师来说,一项编码技术能有更多的业务应用,也是好事。
参考资料
1. ieeexplore.ieee.org/sta...
2. developer.apple.com/av-...
3.Standardized Extensions of High Efficiency Video Coding (HEVC)
4.Overview of the Multiview and 3D Extensions of High Efficiency Video Coding
5. pastebin.com/qZ1xSmuc#...
UE4:Niagara扩展CameraQuery支持CPU获取ViewSize
在使用UE4中的Niagara系统进行粒子系统开发时,遇到过一个需求:需要在CPU粒子系统中获取ViewSize参数,而该参数在CameraQuery组件中仅提供了一个支持GPU的方法。为了解决这个问题,我们探究了如何在Niagara系统中实现CPU获取ViewSize的方法。
首先,创建一个NiagaraScript并添加CameraQuery节点,目的是获取ViewSize参数。在MapGet节点中拉出一个Get方法,可以看到该方法支持CPU还是GPU。然而,由于添加了一个不支持的方法,编译时会报错。因此,我们需要实现一个在CPU粒子系统中获取ViewSize的解决方案。
通过查看CameraQuery的源码,发现GetViewPropertiesGPU函数在注释中被标记为CPU模拟实现,实际并未获取任何数据。进一步研究其他CPU函数的实现,我们了解到数据实际上是从Context的FCameraDataInterface_InstanceData中获取的。通过VectorVM::FExternalFuncRegisterHandler的方式,将获取到的值传递到输出pin,完成了数据从实例数据到输出的传递。
接着,关注到UNiagaraDataInterfaceCamera::GetCameraProperties函数中的完整流程,它更详细地展示了如何添加输出、获取值和赋值的操作。通过分析FCameraDataInterface_InstanceData的初始化和PerInstanceTick函数,我们了解到摄像机参数是通过从World和PlayerController获取的,而这些操作在Tick函数中进行。确认了摄像机参数的获取过程合理,并支持编辑器模式下的正常获取。
在GetFunctions函数中,添加输出和方法的定义时,需要注意函数名、支持CPU/GPU的标志以及是否为成员函数等细节。在GetFunctionHLSL中,只关注CPU方法的实现,通过函数的DefinitionName获取HLSL代码。
为了在CameraQuery中增加获取ViewSize的方法,我们需要在FCameraDataInterface_InstanceData结构体中增加相应的参数,并在PerInstanceTick函数中进行赋值。同时,修改GetFunctions和GetFunctionHLSL以支持CPU粒子系统。最后,通过绑定GetVMExternalFunction完成方法的实现。
实现后,可以通过任意的Material进行调试,并在编辑器中查看结果,验证方法的正确性。这样,我们不仅解决了获取ViewSize的需求,还为Niagara系统的CPU粒子系统增加了更多灵活性。
surfaceviewåviewçåºå«
ããSurfaceViewæ¯ä»Viewåºç±»ä¸æ´¾çåºæ¥çæ¾ç¤ºç±»ï¼ç´æ¥åç±»æGLSurfaceViewåVideoViewï¼å¯ä»¥çåºGLåè§é¢ææ¾ä»¥åCameraæå头ä¸è¬å使ç¨SurfaceViewï¼å°åºæåªäºä¼å¿å¢? SurfaceViewå¯ä»¥æ§å¶è¡¨é¢çæ ¼å¼ï¼æ¯å¦å¤§å°ï¼æ¾ç¤ºå¨å±å¹ä¸çä½ç½®ï¼æå ³é®æ¯çæä¾äºSurfaceHolderç±»ï¼ä½¿ç¨getHolderæ¹æ³è·åï¼ç¸å ³çæCanvas lockCanvas()
ããCanvas lockCanvas(Rect dirty) ãvoid removeCallback(SurfaceHolder.Callback callback)ãvoid unlockCanvasAndPost(Canvas canvas) æ§å¶å¾å½¢ä»¥åç»å¶ï¼èå¨SurfaceHolder.Callback æ¥å£åè°ä¸å¯ä»¥éè¿éåä¸é¢æ¹æ³å®ç°ã
ãã使ç¨çSurfaceViewçæ¶åï¼ä¸è¬æ åµä¸è¦å¯¹å ¶è¿è¡å建ï¼éæ¯ï¼æ¹åæ¶çæ åµè¿è¡çè§ï¼è¿å°±è¦ç¨å° SurfaceHolder.Callback.
ããclass XxxView extends SurfaceView implements SurfaceHolder.Callback {
ããpublic void surfaceChanged(SurfaceHolder holder,int format,int width,int height){ }
ãã//çå ¶åç¥å ¶ä¹ï¼å¨surfaceç大å°åçæ¹åæ¶æ¿å
ããpublic void surfaceCreated(SurfaceHolder holder){ }
ãã//åä¸ï¼å¨å建æ¶æ¿åï¼ä¸è¬å¨è¿éè°ç¨ç»å¾ç线ç¨ã
ããpublic void surfaceDestroyed(SurfaceHolder holder) { }
ãã//åä¸ï¼éæ¯æ¶æ¿åï¼ä¸è¬å¨è¿éå°ç»å¾ç线ç¨åæ¢ãéæ¾ã
ãã}
ãã对äºSurfaceç¸å ³çï¼Androidåºå±è¿æä¾äºGPUå éåè½ï¼æ以ä¸è¬å®æ¶æ§å¾å¼ºçåºç¨ä¸ä¸»è¦ä½¿ç¨SurfaceViewèä¸æ¯ç´æ¥ä»Viewæ建ï¼åæ¶åæ¥åandroid 3d OpenGLä¸çGLSurfaceViewä¹æ¯ä»è¯¥ç±»å®ç°ã
ããSurfaceViewåViewææ¬è´¨çåºå«å¨äºï¼surfaceViewæ¯å¨ä¸ä¸ªæ°èµ·çåç¬çº¿ç¨ä¸å¯ä»¥éæ°ç»å¶ç»é¢èViewå¿ é¡»å¨UIç主线ç¨ä¸æ´æ°ç»é¢ã
ããé£ä¹å¨UIç主线ç¨ä¸æ´æ°ç»é¢ å¯è½ä¼å¼åé®é¢ï¼æ¯å¦ä½ æ´æ°ç»é¢çæ¶é´è¿é¿ï¼é£ä¹ä½ ç主UI线ç¨ä¼è¢«ä½ æ£å¨ç»çå½æ°é»å¡ãé£ä¹å°æ æ³ååºæé®ï¼è§¦å±çæ¶æ¯ã
ããå½ä½¿ç¨surfaceView ç±äºæ¯å¨æ°ç线ç¨ä¸æ´æ°ç»é¢æ以ä¸ä¼é»å¡ä½ çUI主线ç¨ãä½è¿ä¹å¸¦æ¥äºå¦å¤ä¸ä¸ªé®é¢ï¼å°±æ¯äºä»¶åæ¥ãæ¯å¦ä½ 触å±äºä¸ä¸ï¼ä½ éè¦surfaceViewä¸threadå¤çï¼ä¸è¬å°±éè¦æä¸ä¸ªevent queueç设计æ¥ä¿åtouch eventï¼è¿ä¼ç¨ç¨å¤æä¸ç¹ï¼å 为æ¶åå°çº¿ç¨åæ¥ã
ããæ以åºäºä»¥ä¸ï¼æ ¹æ®æ¸¸æç¹ç¹ï¼ä¸è¬åæ两类ã
ãã1 被å¨æ´æ°ç»é¢çãæ¯å¦æ£ç±»ï¼è¿ç§ç¨view就好äºãå 为ç»é¢çæ´æ°æ¯ä¾èµäº onTouch æ¥æ´æ°ï¼å¯ä»¥ç´æ¥ä½¿ç¨ invalidateã å 为è¿ç§æ åµä¸ï¼è¿ä¸æ¬¡Touchåä¸ä¸æ¬¡çTouchéè¦çæ¶é´æ¯è¾é¿äºï¼ä¸ä¼äº§çå½±åã
ãã2 主å¨æ´æ°ãæ¯å¦ä¸ä¸ªäººå¨ä¸ç´è·å¨ãè¿å°±éè¦ä¸ä¸ªåç¬çthreadä¸åçéç»äººçç¶æï¼é¿å é»å¡main UI threadãæ以æ¾ç¶viewä¸åéï¼éè¦surfaceViewæ¥æ§å¶ã
ãã
ãã3.Androidä¸çSurfaceView类就æ¯åç¼å²æºå¶ãå æ¤ï¼å¼å游ææ¶å°½é使ç¨SurfaceViewèä¸è¦ä½¿ç¨Viewï¼è¿æ ·çè¯æçè¾é«ï¼èä¸SurfaceViewçåè½ä¹æ´å å®åã
ãã
ããèè以ä¸å ç¹ï¼æ以æä¸ç´é½éç¨ SurfaceView æ¥è¿è¡æ¸¸æå¼åã
ããé£ä¹å¨ä»¥åæºç å®ä¾ä¸ï¼æé½ä¼ä»¥ç»§æ¿sarfaceViewæ¡æ¶æ¥è¿è¡æ¼ç¤ºãä¸ä¸ç« å°è¯¦ç»åæsarfaceview ï¼ä»¥åéä¸æ¬äººåç游æå¼åæ¶æ