首页 > 其他分享 >解决tiktok切换前后置虚拟摄像头卡住问题

解决tiktok切换前后置虚拟摄像头卡住问题

时间:2024-05-24 19:01:08浏览次数:12  
标签:status 调用 函数 缩放 tiktok 卡住 相机 切换 摄像头

背景介绍:本人原先是android逆向工程师,后来因为工作变动,离开了协议分析这类的岗位,目前在做直播机与第三方应用兼容性分析相关分析。所以就有了这篇兼容性分析文章。本文篇幅较长,需要跟着思路一直往下看,否则肯定云里雾里,第一次发表长文,有很多不足的地方,请各位大佬指正,小弟在此谢过!!!
问题:tiktok在我们推流设备直播时,经过几个特定步骤后切换前后置摄像头会出现卡住的问题
重现步骤:直播界面打开更多菜单 -> 然后退到后台 -> 回到前台 ->切换前后置菜单
现象:直播画面卡住不动了

解决思路:找到点击切换按钮后的点击事件回调,找到切换摄像头的核心逻辑,来找到卡住原因
1、如果了解ART虚拟机的同学会知道,jni函数和java函数都会调用到art虚拟机ArtMethod的Invoke函数

图片描述


输出日志:
find target method: android.view.View.performClick
ArtMethod Invoke【22955】: ; lr:0x4af78c; libart.so: android.view.View.performClick
ArtMethod Invoke【22955】: ; lr:0x2e2800; libart.so: java.lang.Enum.toString
ArtMethod Invoke【22955】: ; lr:0x2e2800; libart.so: X.Ggh.LIZ
ArtMethod Invoke【22955】: ; lr:0x2e2800; libart.so: java.util.LinkedHashMap.<init>
ArtMethod Invoke【22955】: ; lr:0x2e2800; libart.so: java.util.HashMap.putAll
ArtMethod Invoke【22955】: ; lr:0x2e2800; libart.so: java.util.HashMap.put
ArtMethod Invoke【22955】: ; lr:0x2e2800; libart.so: X.DED.LIZ
ArtMethod Invoke【22955】: ; lr:0x2e2800; libart.so: X.D5k.onClick

通过frida hook libart.so的ArtMethod的Invoke函数,我们找到了点击事件的回调类X.D5k

找到这个类对应的onClick函数后,我对整个流程做个简单的研读,感觉发现了核心代码在注释直播流处理 跟着核心代码一路往下找到LiveCore这应该就是直播的核心代码,其实现类为LiveCoreImpl,ILiveStream的实现类为LiveStream

 发现此处只是做了日志信息的合成和应用镜像之类的代码,但是又找到一个核心的类LiveStreamVideoCapture

追踪到这里发现链路断了,又凑巧通过frida打开tiktok卡死在启动页上,那么接下来使用Xposed继续理流程;

上面的代码虽然没有追中到切换摄像头的核心逻辑,但是我们找到了两个核心逻辑的类LiveStreamVideoCapture和LiveCoreImpl,分别和直播视频流控制直播核心流程控制相关,所以Xposed继续走的时候以这两个类为重点,那么此处就开始放大招了,hook这两个类的所有函数,贴上代码。注意这里使用的classloader是application的classloader。

 日志太多了,这里通过shell命令setprop做了个日志控制

然后找到CameraVideoCapturer类的tryDeliverFrame,这里是处理相机的视频帧,感觉越来越接近真相了,继续hook这个方法,然后发现相机切换卡住以后,这个方法也停止调用了,那么没办法,继续往上找堆栈中run方法的调用调用处; 

 至此,熟悉相机开发的同学应该知道,这就是SurfaceTexture.setOnFrameAvailableListener后,相机的可用帧会回调到这个函数,切换相机后卡顿,可用帧也同时不回调。
接下来hook原生相机

 调用的是android.hardware.Camera,也就是camera1相关的api,切换卡顿的时候并没有调用Camera.open函数

图片描述


首次开直播的时候调用了这两个函数,点击切换相机的时候并没有调用,在X.HCF这个类里找到switchCamera函数,那么猜测首次开相机,和切换前后相机走的并不是同一个流程,因为这个bug只有在切换相机时才会出现,所以我们就不关注首次开相机的流程。 

 

果然,切换相机的时候走了这个流程,这是又发现了LiveStreamVideoCapture这个核心类,那么简单进去看看SwitchCaptureRunnable这个有没有被创建 经过测试,发现这个类只会被创建一次,而run方法每次切换都会被调用,而且卡住的情况下也会被调用,那么结合上面Camera.open卡住时没有调用,可以大胆的猜测中间过程某个条件不满足被return了。根据堆栈信息继续往下找几个关键点

图片描述

 发现CameraVideoCapture里也有切换相机的流程,切一步步往下走,能调用到上面我们hook
过的X.HCF的switchCamera,那么我们就看看这里的switchCamera有没有调用吧
•情况一:先滑动直播界面,再按home键,然后回到tiktok,再切换相机,此时status()函数返回1,走了后续Camera.open流程

•情况二:先滑动界面,再切换相机,然后按home键,接着回到tiktok,最后切换相机,此时status()函数返回2,没走后续Camera.open流程 从日志看switchCamera两种情况都走了,再结合switchCamera的源码看,源码里的status()函数的返回值决定了是否继续往下调用切换相机的流程,很遗憾的是,两种情况都出现了,而且都会卡住(为什么两个status值会不一样呢,这里先留个坑,最后来填)。这可把我难住了…心理mmp!!!就在这时脑子突然开窍,既然画面卡住,那么必然有错误信息回调,果然一搜索CameraVideoCapture这个核心类有onError函数,毫不犹豫hook它,发现每次出错时,这个函数的错误码都会报-421错误(截图省略-421错误码的测试过程

错误信息非常明确的告诉我们是因为相机不支持缩放,导致的打开相机失败,那么至此相机卡住的直接原因找到了,但是还没找到为什么特殊的操作流程后会卡住,而正常的操作不会。于是乎继续跟着堆栈信息往上找。 发现走进了这里的流程,导致的相机进缩放流程,为了验证猜想,我决定在这个函数调用前,把message里的what字段改成2,让它不走这个流程,来看看是不是就不会导致界面卡住,于是就有了下面这段代码。

经过这一番篡改,果真随便怎么折腾,直播界面都不会卡住了。那么我只要找到那里给handler发送的这个message就应该离真想很近了 然后找这个handler的sendMessage相关切message的what字段赋值为1的函数

然后我找到了它,这个函数还和缩放相关,那就八九不离十了 按之前的堆栈继续hook,发现卡住的时候这些方法确实都走了,而正常的时候是不走的,那么在X.Dvc的LIZ继续用抛堆栈大法。
得到如下两种堆栈:
•X.DCM接收到了touch事件,然后交由X.DCc这个类进行手势判断,发现是需要执行缩放的手势,于是执行了相机的缩放功能(由于我们业务原因需要隐藏底部NavigationBar,在Window底部上划会显示NavigationBar,上划的手势同时触发了控件的以为需要执行相机缩放),但是我们的虚拟摄像头又不支持缩放,导致打开相机失败,画面就卡在了之前相机拿到的最后一帧

•点击tiktok的切换相机Button,触发进入相机的缩放,这里就和我们之前的点击事件联系上了,红框部分就是补上了之前没关注但是最重要的相机缩放功能判断部分 

至此,我们已经把相机卡住的直接原因和根本原因都找到了,先手势再点击切换相机触发了进入相机缩放功能判断流程,由于我们的虚拟相机不支持缩放,导致打开相机失败,卡在相机的最后一帧(也可能是黑屏)。所以只要交付给framework组开发人员,让他们支持相机缩放相关功能就可以了。

接下来来填前面留下的坑,为什么退到后台会导致status函数的返回值不一样?
我们回到CameraVideoCapturer类,看看这个status()函数到底是个什么鬼!

 通过AndroidStudio自带的字段读写索引功能,很容易找到父类里的start、stop和release函数,以及自身的onErrorOnHandler函数里(也就是我们之前抛-421错误堆栈的函数)。如果熟悉相机开发的同学应该知道,一般我们界面退到后台会释放相机,然后回到前台重新打开。那么接下来我们把这几个函数都hook一下,来验证猜想。

 这里我多hook了一个onCaptureStarted函数,这个函数会调用父类的onStart函数,想看看是否会有调了onCaptureStarted但是没调父类的onStart的情况。然后还hook了CameraVideoCapturer自身重写的onStart和父类ExternalVideoCapturer的onStart函数。
下面是刚打开直播时的日志,此时status=1

•情况一:先滑动直播界面,再按home键,然后回到tiktok,再切换相机,此时status()函数返回1,走了后续Camera.open流程
这是直播退到后台时的调用,说明确实释放掉了,但是又调用了父类的onStart函数,那么此时的应该为2的status又变回了1 接下来回到前台,此时一切正常status还是为1,而且重走了自身的onStart函数,相当于相机整个流程完全重开

再接着切换相机第一次,这时的status还是为1,相机正常,紧接着我们发现了-421错误,发现又重走了父类的onStart函数,那么此时status还是1 

以上就是第一种情况,由于每次切换相机都会抛完-421错误后,再调用父类ExternalVideoCapturer的start函数来重置status,也就造成了能调用Camera.open但是画面卡住的情况;

•情况二:先滑动界面,再切换相机,然后按home键,接着回到tiktok,最后切换相机,此时status()函数返回2,没走后续Camera.open流程
前面流程就不贴了,直接开后面的流程记录
退到后台 status=1

以上就是第二钟情况
这个坑填完,本篇经验记录就到此结束。 

标签:status,调用,函数,缩放,tiktok,卡住,相机,切换,摄像头
From: https://blog.csdn.net/jmm18363027827/article/details/139182233

相关文章

  • 百问网,T113 usb摄像头使用cpu解码显示
    1资料下载https://download.100ask.net/boards/Allwinner/T113/index.html2软件安装资料下载完毕后,根据说明,安装vmware,安装win驱动3配置开发环境为了方便,建议将sdk文件上传到目录/home/book/安装必要的工具包,如果出现问题Couldnotgetlock/var/lib/dpkg/lock-......
  • python实现ONVIF协议抓取华为摄像头图像
    参考文档:配置摄像机ONVIF协议参数-SDC10.0C系列产品文档-华为机器视觉(huawei.com) 配置摄像机ONVIF协议参数1)登录摄像机Web界面,选择“配置>视音频>视频”,将“编码协议”设置为“H.264”2)进入“网络平台对接”配置,选择“第二协议参数>ONVIF”,进入ONVIF协议参数......
  • c# 摄像头及保存视频记录
     usingSystem.IO;usingICameraDll.DirectX.Capture;Capturecapture;//摄像头录像操作Filtersfilters=newFilters();//Filter集合//函数intGetffshowIndex(){FilterCollectionvideoC......
  • C#调用电脑摄像头拍照
    1.打开VS,新建一个Form窗体,工具->NuGet包管理工具->管理解决方案的NuGet包,在浏览里搜索AForge.Controls、AForge.Video.DirectShow,安装AForge.Controls和AForge.Video.DirectShow2.安装AForge组件完成后,VS工具箱会新增AForge控件,把AForge.NET中的VideoSourcePlayer拖到Form窗体上......
  • 摄像头 --- OV5640
    帧率(frameratetiming)  图像窗口有效像素是2592*1944,总像素是2624*1956(非有效像素用来黑电平校准和插值)physicalpixelsize是 2624*19560x3800~0x3807设置ISPinput范围0x3810~0x3813进一步设置pre-scaling范围dataoutputsize由0x3808~0x380B设置,datao......
  • openGauss TPCC运行时-注入磁盘满故障-TPCC卡住的问题
    TPCC运行时,注入磁盘满故障,TPCC卡住的问题问题现象TPCC运行时,注入磁盘满故障,TPCC卡住,故障消除后,TPCC自动续跑。原因分析数据库本身机制,在性能日志(gs_profile)所在磁盘满时,导致无法写入而陷入无限等待,表现为TPCC卡住。磁盘满故障消除后,性能日志能正常写入,TPCC恢复正常。处理分析......
  • 基于Luckfox Pico的opencv使用UDP协议与ubuntu传输摄像头数据-小白进阶
    使用UDP传输opencv的mat数据并显示本教程适用于进阶的小白尝试先说一下背景吧,正在工作的我,突然间看到淘宝上有个很漂亮的价格还不错的linux小板子,遂买下。没错,工作太无聊以至于开始摸鱼学习~但奈何每天工作完回家就像躺着,所以板子到手都快半年了才开始研究实现了简陋的摄像头......
  • 关于在CentOS7的docker容器下启动MySQL5.7.44卡住的问题的解决办法
    最近想在docker中跑一个MySQL5.7版本的服务,而且要基于CentOS,所以着手自己构建镜像。容器的构建参照下面这篇文章基于CentOS7镜像容器的MySQL环境构筑-sxb_sunday-博客园(cnblogs.com)构建完成后,用下面命令启动MySQL服务的时候,启动进程一直卡住没有反应,只能CTRL+C强制停止。......
  • OV5640 摄像头图像显示
    概述OV5640是一款1/4英寸单芯片图像传感器,其感光阵列达到25921944(即500W像素),能实现最快15fpsQSXVGA(25921944)或者90fpsVGA(640*480)分辨率的图像采集。传感器采用OmniVision推出的OmniBSI(背面照度)技术,使传感器达到更高的性能,如高灵敏度、低串扰和低噪声。传感器内......
  • Qt/C++音视频开发71-指定mjpeg/h264格式采集本地摄像头/存储文件到mp4/设备推流/采集
    一、前言用ffmpeg采集本地摄像头,如果不指定格式的话,默认小分辨率比如640x480使用rawvideo格式,大分辨率比如1280x720使用mjpeg格式,当然前提是这个摄像头设备要支持这些格式。目前市面上有一些厂家做的本地设备支持264格式,这个压缩率极高,由于采集到的就是264格式的裸流,所以不用编码......