您当前的位置:首页 > 电脑百科 > 程序开发 > 移动端 > Android

把Android手机变成电脑摄像头,开发者倒苦水:40行代码搞定,但需要40个项目文件支持!

时间:2023-08-21 14:59:01  来源:CSDN  作者:

编译 | 苏宓

出品 | CSDN(ID:CSDNnews)

开发一款 App,难不难?

软件工程师 Thomas SIMON 闲暇之余用实践回答道:其实说难也不难。

当他拿起一个 Android 手机,想要将其作为电脑摄像头和麦克风使用时,他只写了 40 行代码就实现了这一功能。

只不过,令他苦恼的是,写 40 行代码背后需要安装超过 20GB 的工具、也需要创建数十个项目文件才能以运行。

当他把自己的这段经历分享到网上时,没想到,引起了多位开发者的共鸣,纷纷表示,这种感觉太熟悉了。

在分享的文章中,Thomas SIMON 引用马斯克曾经说过的一句话,「聪明工程师会犯的最常见错误,就是优化本不该存在的东西」。开发本身或许并不难,只是被平白增加了很多的复杂性。

接下来,我们将从 Thomas SIMON 的经历中了解开发者那些本该避开的坑。

需要一个 App,把 Android 手机变成电脑摄像头和麦克风

之所以想要开发一款 App,是因为作为一名软件工程师,Thomas SIMON 平时保持着视频录制分享技术的习惯。

此前,他主要使用 Android 手机来录制视频。与台式机上的 linux 系统相比,Android 系统的兼容性很好,而且它很少出错,即使出错,也是以众人可接受的方式,譬如电池电量不足、系统更新等等。

后来,Thomas SIMON 决定和一位朋友一起录制他们技术分享,并将其作为播客片段上传到网络上,期间需要对录制的文件进行剪辑、制作等等,还是电脑好操作一些。

不过,Thomas SIMON 的 Linux 系统电脑并没有摄像头,所以在他的计划中,原来是想要将 Linux 电脑作为主设备进行录制,然后使用手机上的摄像头和麦克风加入通话。

然而,在录制期间需要管理两台设备非常麻烦,况且搭载 Linux 系统的电脑设备本身就有一个不错的麦克风,所以,此时只要有一个 Linux 兼容的网络摄像头存在就可以解决难题。

在研究市场上现有的网络摄像头之后,Thomas SIMON 认为那些设备不仅价格昂贵,而且质量还不如几年前的中档手机后置摄像头。

恰巧他手头正好有一部三星 S20,手机的后置镜头是长焦镜头,非常适合拍摄人像,平行光线让人脸看起来清晰、漂亮。

在这样的背景下,Thomas SIMON 萌生了自己开发一个 Android App 的想法,只需要通过 Wi-Fi 或其他方式将手机摄像头的数据流重定向到他的电脑上,让他的 Linux 电脑相信 Android 手机是一个摄像头,或者让 Linux 的应用程序(如 google Meet 和 Zoom)相信它是一个摄像头即可。

也许有人会说,其实市场中也早已有了这样的软件,譬如 DroidCam。DroidCam 软件分为两部分,一部分是手机上安装的软件,称为服务器;另一部分是 PC 上安装的软件,称为客户端。只需要 PC 和手机连接到同一个 Wi-Fi,就可以把手机作为电脑摄像头。

不过,Thomas SIMON 在使用后发现,DroidCam 是一款被广告限制且需要付费的应用程序,而且并非所有摄像头都能显示。同时,经过测试,它的质量令人无法接受,即使是 720p 的低分辨率也被官方推荐。

无法忍受之下,Thomas SIMON 决定自己开发一款 Android App,把 Android 手机相机变成电脑的摄像头。

这有什么难的?

通过多年的积累,Thomas SIMON 已经掌握了全栈、Linux、视频流等方面的所有专业知识。其表示,”虽然我一直对手机应用程序敬而远之,但我的整个职业生涯都是朝着网络、服务器应用程序和桌面原生应用程序方向发展的。“

所以,对于 Thomas SIMON 而言,开发一款 Android App 难度其实并不大。而且在他的规划中,他只想要一个包含选择相机、分辨率和退出键这几个菜单栏的 App, 并不需要有太多的设计感。

于是,Thomas SIMON 开始寻找制作 Android 应用程序的最简单方法。他发现,几乎每个专家都在积极推动 Android Studio 作为 IDE 开发环境。

不难想象,他下载了一个 Android Studio,结果发现,这是一个 1.1GB 的 .tar.gz 压缩包,一旦安装了所需的工具,最终会占用 20GB(分布在多个文件夹中)的空间

安装好工具之后,Thomas SIMON 开始寻找可以处理摄像头的官方 APIs。

简而言之,Thomas SIMON 试过 cameraX,这是一个 Jetpack 库,旨在帮助简化相机应用程序的开发,但它太高级了。所以 Thomas SIMON 最终使用了 camera2。

Thomas SIMON 下载了一个 camera2 的官方示例项目,其实他只想拼接一个 http 服务器并用来传输帧,在他的设想中,整个过程应该只需要几分钟就可以完成的。没想到,厄运从这里才真正开始......

Thomas SIMON 表示,这个官方示例项目(Github.com/android/camera-samples/tree/mAIn/Camera2Basic)的作用只有「显示摄像头、并拍摄一张照片」,但是没想到它包含了很多文件。

仅以 gradle 为关键词搜索,就有一大堆文件:

$:/tmp/Camera2Basic$ find . -type f -name "_gradle_" ./gradlew.bat ./gradle.properties ./gradlew ./settings.gradle ./utils/build.gradle ./gradle/wrapper/gradle-wrapper.jar ./gradle/wrapper/gradle-wrapper.properties ./build.gradle ./app/build.gradle

Thomas SIMON 表示,自己不可能花时间去慢慢理解这些东西,他只是要修改一些代码,来实现自己想要的功能。

不过,还没等他开始寻找代码片段,Android Studio 就开始跳出了一个提示:

"不支持 JAVA,点击此处更新 gradle thingy"。

于是,事情似乎进入了循环:

Thomas SIMON 点击。

事情发生了变化,左侧窗格中的文件改变了结构,标签页反复打开和关闭。

"建议更新项目,点击启动 AGP 升级助手”

Thomas SIMON 继续点击:

显示许多选项,其中一些已预选,一个按钮上写着 "运行选定步骤"。

Thomas SIMON 再次点击:

事情发生了变化,左侧窗格中的文件改变了结构,选项卡反复打开和关闭。

"建议更新项目,单击启动 AGP 升级助手

Thomas SIMON 点击:

显示大量选项,其中一些已预选,一个按钮显示 "运行选定步骤"。

Thomas SIMON 继续点击:

事情发生了变化,左侧窗格中的文件改变了结构,标签反复打开和关闭。

Thomas SIMON 无语道,“这是一款很棒的点击冒险游戏。”

折腾了一会,Thomas SIMON 的 AGP 和 gradle 终于不再跳出更新提示。

接下来,正式进入代码部分。

写过不少 Java 和 Scala 代码的 Thomas SIMON 发现这部分的代码是用 Kotlin 写的。

“从这里开始,我喜欢我所看到的,代码很清晰。它在 xml 中定义一个视图,在代码中用标识符与之关联,非常标准且可预测。清晰的代码让我不需要学习任何东西就能提高工作效率”,Thomas SIMON 说道。

紧接着,Thomas SIMON 调用一个 Android API 来制作一个简单的 http 服务器,然后把它插入、测试,它就能工作了!

现在,Thomas SIMON 的电脑浏览器标签页上有一个 mjpeg 流。对于实时调用来说,质量和延迟都还可以。这样,他就可以在终端输入一行命令将其转换为 Linux 网络摄像头设备:


ffmpeg -f mjpeg -i "http://192.168.1.2:8080" -vf "format=yuv420p" -f v4l2 /dev/video0

整体而言,Thomas SIMON 表示,网络世界虽然有一些不必要的步骤和配置,但这个 Android 世界简直是疯了。

他下载了官方示例之后,删除了未使用的视图,添加了选择相机、分辨率和质量的下拉菜单,将所有功能移至前台服务,以便在锁定手机的情况下保持激活状态,并将其发布在 GitHub 上(https://github.com/Ruddle/RemoteCam),整个项目花了他两个下午的时间(其中大部分时间都在了解 Android 希望你怎么做)。

实际工作量应该如何?

Thomas SIMON 认为,在理想的情况下,在手机端,只需一行代码就足够了,根本不需要上面那样复杂的操作。倘若我们想编写一个应用程序,只是为了准确地指定数据流,而不是依赖天才们已经开发出来的高级工具(如桌面上的 ffmpeg 和 v4l2)。

在理想的世界里,具有这种规格的 App 应具备:

  • 允许配置相机、分辨率和质量/比特率
  • 没有设计,只有原始功能
  • 在本地网络上传输帧流

Thomas SIMON 表示,只需一个 40 行伪代码(pseudo code,又称虚拟代码,是一种高层次描述算法的方法,它可能综合使用多种编程语言的语法、保留字,甚至会用到自然语言)的文件就能实现以上功能:

1CAMERA.getPermission orquit

.NETWORK.getPermission orquit

3

4queue=Producer(size= 1)

5

6server = NETWORK.createHttpServer(port = 8080)

7server.onRequest = req ->

8queue.dropConsumers //only allows 1client, drop old ones

9req.sendHeader( "Content-Type", "multipart/x-mixed-replace;boundary=FRAME")

10queue.consumeUntilDrop( frame, consumer ->

11data = "--FRAME=rnContent-Type=image/jpegrn".bytes+frame.bytes

12req.sendBytes(data) orqueue.drop(consumer)

13frame. close// Free camera memory of this frame

14)

15req. close

16

17options = STORAGE.get( "config") or{sensor: 0, format: "jpeg", fps: 30, resolution:[ 1280, 720]}

18

19session = CAMERA. open(options)

20session.onFrame= frame -> queue.pushTry(frame) orframe. close

21

22UI. insert(UI.text).text= "Choose a sensor:"

23dropdownSensors = UI. insert(UI.dropdown)

24dropdownSensors.selection= session.sensor

25dropdownSensors.values = CAMERA.sensors.map(_.name)

26dropdownSensors.onSelect = index ->

27STORAGE.set( "config", options + {sensor: index})

28restart

29

30UI. insert(UI.text).text= "Choose a resolution:"

31dropdownResolution = UI. insert(UI.dropdown)

32dropdownResolution.selection= session.resolutions.indexOf(session.resolution)

33dropdownResolution.values = session.resolutions.map(_ .0+ "x"+_ .1)

34dropdownResolution.onSelect = index ->

35STORAGE.set( "config", options + {resolution: session.resolutions[index]})

36restart

37

38quitBtn = UI. insert(UI.button)

39quitBtn.onClick = quit

40quitBtn.text = "quit"

这段伪代码虽然简单,但明确指出了所需的内容。 其中,对 API 的访问如CAMERA(摄像头)、NETWORK(网络)、UI(用户界面)和 STORAGE(存储)等都非常明显易懂。

无需导入、无需 gradle、无需指定无用的用户界面文件、无需多个事实来源。该文件非常简短,Thomas SIMON 甚至懒得将存储密钥命名为 "config"。

Thomas SIMON 解释道,“伪代码假定是托管执行,就像 Kotlin 或 Java 一样,允许非常容易地使用高阶函数。支持这种单文本文件应用程序并不需要什么新东西。我们只需选择一种语言,如 Python/ target=_blank class=infotextkey>Python、Java 或 Kotlin,然后编写一个库来公开 API。我们甚至可以开发一个标准的 Android 应用程序,作为操作系统来执行这些单文本文件应用程序。但 Google 并不允许这样做。从技术上讲,你可以进行动态代码加载,但一旦 Google 发现你可以让人们绕过 Play 商店来加载小于 1kB 的应用程序,你就完了。此外,Google 和 Apple 已经在极力阻止 PWA(一种让网页拥有原生应用程序功能的技术)运行得太好。”

对于 Thomas SIMON 而言,他大概只用了 10 分钟就写出了这段伪代码。其中有 5 分钟是在网上查找如何在多部分 http 流中分离帧(获取信息的难度出乎意料)。

就目前而言,其实通过一个 LLM(比如 ChatGPT,甚至是本地运行的 LLM)可以在 10 秒内写完这段代码,而且至少有一半的时间不会出错。

经过 Gzip 压缩后,一个文本文件应用程序的大小为 688 字节。

1$> gzip -k text_app; ls -lh

21, 5K text_app

3688text_app.gz

相比之下,Thomas SIMON 用 Android Studio 生成的 APK 只有 14.9MB。

至于用户可能存疑的所有的 gradle 配置文件都在哪里?Thomas SIMON 表示,这些文件中 99% 的内容都是用来处理糟糕的抽象。

最后的 1% 可能只是文件顶部的一些注释,如

// name:RemoteCam // author:Thomas SIMON // version:1.0 // icon: image/png;base64,ABC...

对于安全性、兼容性和更新等问题,Thomas SIMO 解释道,这些问题都已经解决了。

  • 安全性:只需根据你信任的文件进行签名检查。
  • 兼容性:只需在文件顶部注释 minAndroidVersion。
  • 更新:替换应用程序文件即可。

这些问题都不能成为你在 Android 系统上制作应用程序的复杂性的借口。

这些问题都不能由应用程序商店自行解决(应用程序本身只有 40 行)。

结论

最后,Thomas SIMO 仅用了 40 行代码就开发了一个网络摄像头 App,并将代码开源在了 GitHub 上(https://github.com/Ruddle/RemoteCam)。

Thomas SIMO 表示,他用这款应用程序进行了两次视频通话,每次持续时间都在 1 小时 30 分钟以上,它的表现非常出色。

经过自己开发了一款 App,他也终于明白为什么 DroidCam 试图推销付费模式,主要是因为开发一款 App 必须忍受的非必要工作和挫折实在太多,代码没写多少,但其中的工具安装、项目支持文件实在过于臃肿,最终导致你想向别人收费来寻求心理平衡罢了。

来源:https://thomassimon.dev/ps/2



Tags:Android   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Android Emulator黑屏怎么办 Android模拟器黑屏解决方法
Android Emulator黑屏问题困扰了非常多的玩家,Android Emulator作为一款安卓模拟器,可以让你在电脑上运行和浏览安卓应用程序,但是程序本身不是很稳定,很容易会出现黑屏,启动不了...【详细内容】
2024-03-04  Search: Android  点击:(37)  评论:(0)  加入收藏
Android 谷歌三件套:解锁谷歌生态!
大家是不是遇到这个情况?当我们需要下载一些国外的游戏或者软件的时候,需要在手机里面安装Google Play商店,然后通过Google Play商店下载国外软件!为了帮助大家使用上各种好用的...【详细内容】
2024-01-02  Search: Android  点击:(110)  评论:(0)  加入收藏
Android开发中常见的Hook技术有哪些?
Hook技术介绍Hook技术是一种在软件开发中常见的技术,它允许开发者在特定的事件发生时插入自定义的代码逻辑。常见的应用场景包括在函数调用前后执行特定的操作,或者在特定的事...【详细内容】
2023-12-25  Search: Android  点击:(83)  评论:(0)  加入收藏
在Android应用开发中使用NFC功能
NFC介绍NFC是指“近场通讯”(Near Field Communication),它是一种短距离无线通信技术,允许设备在非接触或极短距离内进行通信。NFC通常用于移动支付、门禁系统、智能标签和其他...【详细内容】
2023-12-22  Search: Android  点击:(102)  评论:(0)  加入收藏
关于Android图像Bitmap类,你要知道的一切
Bitmap介绍Bitmap是一种图像文件格式,它由像素阵列组成,每个像素都有自己的颜色信息。在计算机图形学中,Bitmap图像可以被描述为一个二维的矩阵,其中每个元素代表一个像素的颜色...【详细内容】
2023-12-19  Search: Android  点击:(97)  评论:(0)  加入收藏
Android开发中如何进行单元测试?
单元测试介绍单元测试是软件开发中的一种测试方法,用于验证代码中的最小可测试单元(通常是函数或方法)是否按预期工作。单元测试通常由开发人员编写,旨在隔离和测试代码的特定部...【详细内容】
2023-12-11  Search: Android  点击:(167)  评论:(0)  加入收藏
我的手机我做主,如何为Android手机应用换图标?
作为一名Android用户,你是否曾经为自己的手机桌面感到单调而乏味?虽然Android系统的桌面定制性已经非常强大,但有时候我们还是希望能够在细节上做出一些改变,尤其是对于那些每天...【详细内容】
2023-12-10  Search: Android  点击:(61)  评论:(0)  加入收藏
了解Android系统架构中的HAL硬件抽象层
在Android系统中,HAL的存在使得不同厂商的硬件可以统一被上层的应用程序调用,从而提高了系统的兼容性和可移植性。HAL还可以帮助开发者更方便地开发应用程序,因为他们不需要为...【详细内容】
2023-12-06  Search: Android  点击:(200)  评论:(0)  加入收藏
谷歌 CEO 皮查伊建议 Android 用户不要侧载应用,称非常危险
iOS和Android的一个显著差异是,Android支持用户从第三方渠道安装应用程序(即“侧载”)。然而,谷歌似乎并不希望用户这样做。最近,在与Epic Store的法律诉讼中,谷歌首席执行官桑达...【详细内容】
2023-11-20  Search: Android  点击:(166)  评论:(0)  加入收藏
Android数据对象序列化原理与应用
序列化与反序列化「序列化」是将对象转换为可以存储或传输的格式的过程。在计算机科学中,对象通常是指内存中的数据结构,如数组、列表、字典等。通过序列化,可以将这些对象转换...【详细内容】
2023-11-14  Search: Android  点击:(272)  评论:(0)  加入收藏
▌简易百科推荐
Android Emulator黑屏怎么办 Android模拟器黑屏解决方法
Android Emulator黑屏问题困扰了非常多的玩家,Android Emulator作为一款安卓模拟器,可以让你在电脑上运行和浏览安卓应用程序,但是程序本身不是很稳定,很容易会出现黑屏,启动不了...【详细内容】
2024-03-04  18183游戏网    Tags:Android Emulator   点击:(37)  评论:(0)  加入收藏
Android开发中常见的Hook技术有哪些?
Hook技术介绍Hook技术是一种在软件开发中常见的技术,它允许开发者在特定的事件发生时插入自定义的代码逻辑。常见的应用场景包括在函数调用前后执行特定的操作,或者在特定的事...【详细内容】
2023-12-25  沐雨花飞蝶  微信公众号  Tags:Android   点击:(83)  评论:(0)  加入收藏
在Android应用开发中使用NFC功能
NFC介绍NFC是指“近场通讯”(Near Field Communication),它是一种短距离无线通信技术,允许设备在非接触或极短距离内进行通信。NFC通常用于移动支付、门禁系统、智能标签和其他...【详细内容】
2023-12-22  沐雨花飞蝶  微信公众号  Tags:Android   点击:(102)  评论:(0)  加入收藏
关于Android图像Bitmap类,你要知道的一切
Bitmap介绍Bitmap是一种图像文件格式,它由像素阵列组成,每个像素都有自己的颜色信息。在计算机图形学中,Bitmap图像可以被描述为一个二维的矩阵,其中每个元素代表一个像素的颜色...【详细内容】
2023-12-19  沐雨花飞蝶  微信公众号  Tags:Android   点击:(97)  评论:(0)  加入收藏
Android开发中如何进行单元测试?
单元测试介绍单元测试是软件开发中的一种测试方法,用于验证代码中的最小可测试单元(通常是函数或方法)是否按预期工作。单元测试通常由开发人员编写,旨在隔离和测试代码的特定部...【详细内容】
2023-12-11  沐雨花飞蝶  微信公众号  Tags:Android   点击:(167)  评论:(0)  加入收藏
一篇聊聊Jetpack Room实现数据存储持久性
Room介绍Room 是 Android Jetpack 组件库中的一部分,它是用于在 Android 应用中进行本地数据库访问和管理的库。Room 提供了一个抽象层,使开发者能够更轻松地访问 SQLite 数据...【详细内容】
2023-12-08  沐雨花飞蝶  微信公众号  Tags:Jetpack   点击:(142)  评论:(0)  加入收藏
了解Android系统架构中的HAL硬件抽象层
在Android系统中,HAL的存在使得不同厂商的硬件可以统一被上层的应用程序调用,从而提高了系统的兼容性和可移植性。HAL还可以帮助开发者更方便地开发应用程序,因为他们不需要为...【详细内容】
2023-12-06  沐雨花飞蝶  微信公众号  Tags:Android   点击:(200)  评论:(0)  加入收藏
我们一起聊聊 IntentService 与 Service 的区别?
Service介绍Service组件是Android应用开发中的四大组件之一,用于在后台执行长时间运行的操作或处理远程请求。它可以在没有用户界面的情况下执行任务,并且可以与其他应用组件...【详细内容】
2023-12-06  沐雨花飞蝶  微信公众号  Tags:IntentService   点击:(167)  评论:(0)  加入收藏
Android数据对象序列化原理与应用
序列化与反序列化「序列化」是将对象转换为可以存储或传输的格式的过程。在计算机科学中,对象通常是指内存中的数据结构,如数组、列表、字典等。通过序列化,可以将这些对象转换...【详细内容】
2023-11-14  沐雨花飞蝶  微信公众号  Tags:Android   点击:(272)  评论:(0)  加入收藏
你了解Android中的SELinux吗?
SELinux介绍SELinux(Security-Enhanced Linux)是一种安全增强的Linux操作系统,它通过强制访问控制(MAC)机制来提供更高级别的系统安全保护。相比于传统的Linux访问控制机制(DAC),SEL...【详细内容】
2023-11-09  沐雨花飞蝶  微信公众号  Tags:Android   点击:(263)  评论:(0)  加入收藏
站内最新
站内热门
站内头条