惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Darknet – Hacking Tools, Hacker News & Cyber Security
AI
AI
S
Security Affairs
S
Secure Thoughts
Attack and Defense Labs
Attack and Defense Labs
Application and Cybersecurity Blog
Application and Cybersecurity Blog
H
Heimdal Security Blog
Forbes - Security
Forbes - Security
Security Archives - TechRepublic
Security Archives - TechRepublic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Spread Privacy
Spread Privacy
C
Cybersecurity and Infrastructure Security Agency CISA
Latest news
Latest news
T
Tor Project blog
I
Intezer
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Project Zero
Project Zero
V2EX - 技术
V2EX - 技术
V
Vulnerabilities – Threatpost
L
Lohrmann on Cybersecurity
C
CXSECURITY Database RSS Feed - CXSecurity.com
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Hacker News: Ask HN
Hacker News: Ask HN
S
Schneier on Security
T
Threat Research - Cisco Blogs
Webroot Blog
Webroot Blog
T
Threatpost
Help Net Security
Help Net Security
W
WeLiveSecurity
Know Your Adversary
Know Your Adversary
WordPress大学
WordPress大学
L
LINUX DO - 最新话题
月光博客
月光博客
PCI Perspectives
PCI Perspectives
小众软件
小众软件
爱范儿
爱范儿
博客园 - Franky
Security Latest
Security Latest
Microsoft Azure Blog
Microsoft Azure Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Stack Overflow Blog
Stack Overflow Blog
Google DeepMind News
Google DeepMind News
Scott Helme
Scott Helme
P
Privacy International News Feed
Y
Y Combinator Blog
P
Palo Alto Networks Blog
M
MIT News - Artificial intelligence
N
Netflix TechBlog - Medium

Yesterday17's Blog

2026 新年解密红包 / Melody Flag | Yesterday17's Blog 谈谈 Iori 的设计思路(二):如何实现一个 Showroom 录制工具? | Yesterday17's Blog 谈谈 Iori 的设计思路(一):从 Nico Timeshift 说起 | Yesterday17's Blog Iori Minyami 0.1.0 发布 | Yesterday17's Blog 2025 新年解密红包 / Melody Flag | Yesterday17's Blog 使用 Cloudflare Warp 解决罗森票务的海外登录问题 | Yesterday17's Blog How To Blog 04: The Astro v5 Era | Yesterday17's Blog 谈谈 tokio::select! 的公平性 | Yesterday17's Blog Learning Pingora 05 - Connect with TLS | Yesterday17's Blog Leaving Bytedance | Yesterday17's Blog 大橋彩香 AsiaTour「Reflection」上海公演 个人向记录 & Repo | Yesterday17's Blog Recoving from burnout - What happened? | Yesterday17 Yubikey 重建手册 | Yesterday17's Blog How To Blog 03: Heimus | Yesterday17's Blog 🪧 Blog Migration Accouncement | Yesterday17's Blog Learn Your IDE - VSCode 是如何仅重启插件的? | Yesterday17's Blog How To Blog 02: Astro❤️Password | Yesterday17's Blog How To Blog 01: Why, How, and the Future | Yesterday17's Blog Learning Pingora 04 - Establish L4 Connection | Yesterday17's Blog Learning Pingora 03 - Upstreams and Peers | Yesterday17's Blog Learning Pingora 02 - A Simple HTTP Server | Yesterday17's Blog Learning Pingora 01 - Getting Started | Yesterday17's Blog 2024 新年解密红包 / Melody Flag | Yesterday17's Blog 向新的一年飞驰——记录 2023 | Yesterday17's Blog 「サクラノ刻」对话选摘(2) | Yesterday17's Blog PGP Key Revocation 注销声明 | Yesterday17's Blog 「サクラノ刻」对话选摘(1) | Yesterday17's Blog 2023 新年解密红包 / Melody Flag | Yesterday17's Blog 『蒼の彼方のフォーリズム』通关感想 | Yesterday17's Blog 单显卡直通教程 | Yesterday17's Blog 对博客与笔记的思考 | Yesterday17's Blog Project Anni 之旅(3)自动化 Flutter 应用 CI/CD 上架流程 | Yesterday17's Blog AsobiStage 直接播放链接 | Yesterday17 如何在后分P时代进行投稿——sswa使用详解 | Yesterday17's Blog JSON RPC 与 LSP 协议基础 | Yesterday17's Blog Grajapa Shueisha / BookEnd 加密方式调查 | Yesterday17's Blog 【2022篇+WriteUp】如何再收一个新年红包? | Yesterday17's Blog 如何将良心云的良心功能清理干净 | Yesterday17's Blog 【油猴脚本】bilibili 投稿页面返回旧版+旧版页面强制允许分P上传 | Yesterday17's Blog Cloudr1v1 授权方式分析 | Yesterday17 Typora 1.0.2 逆向实录 | Yesterday17's Blog Project Anni 之旅(2)ValueAfterTable——toml-rs的实现与限制 | Yesterday17's Blog IPv4透明代理+IPv6 Passthrough——树莓派单臂软路由折腾记 | Yesterday17's Blog Chaos; Child 汉化补丁 神秘编码探索 | Yesterday17's Blog 镣铐与舞蹈——个性与共性之迷思 | Yesterday17's Blog Go 学习笔记 02 - 找准 io 之道 | Yesterday17's Blog NAT Slipstreaming v1 原理浅析 | Yesterday17's Blog 绕过「9-nine-」的 CDKEY 验证——KrkrPlugin 正(?)向实录 | Yesterday17's Blog 静流的青春纪念册——「サクラノ刻 -櫻の森の下を歩む-」体验版感言 | Yesterday17's Blog Project Anni 之旅 01 - 从 clap-builder 到 derive | Yesterday17's Blog [Google CTF 2021] CPP WriteUp | Yesterday17's Blog 获取 アソビステージ 的实际播放链接 | Yesterday17's Blog 90 行 Rust 代码实现 AsyncTeeReader | Yesterday17's Blog 或许还算有价值一读的文章列表 | Yesterday17's Blog 从零开始的 Seedbox 之旅 | Yesterday17's Blog [随笔]技术型博客行文迷思(1) | Yesterday17's Blog 浅谈 git fetch 的工作方式 | Yesterday17's Blog 『ソーサレス*アライヴ! ~the World's End Fallen Star~』通关感想" | Yesterday17's Blog Rust std::fmt 格式语法简述 | Yesterday17's Blog 日亚修改居住国的解决方案 | Yesterday17's Blog 【翻译】Subtyping and Variance / 子类型与变型 | Yesterday17's Blog Berd's Red Envelope 2021 WriteUp | Yesterday17's Blog 【中英对照】ALSA 音频 API 使用教程/A Tutorial on Using the ALSA Audio API | Yesterday17's Blog 从 cue_scanner.l 看 CUE Sheet 的词法单元 | Yesterday17's Blog Postman 历史记录导出的解决方案 | Yesterday17's Blog 《恋爱绮谭 不存在的夏天》通关感想 | Yesterday17's Blog [微机实验/TD-PITE] 微机接口综合实验 | Yesterday17's Blog [微机实验/TD-PITE] 键盘扫描及数码管显示实验 | Yesterday17's Blog [微机实验/TD-PITE] 数码管显示实验 | Yesterday17's Blog Airsonic Advanced+Google Drive+Caddy 部署纪实 | Yesterday17's Blog X-NUCA 2020 - hellowasm 题解 | Yesterday17's Blog [微机实验/TD-PITE] 8251 串行接口实验 | Yesterday17's Blog Node.js child_process.fork 与 env 污染 RCE | Yesterday17's Blog EP.01 「夜の向日葵」 | Yesterday17's Blog [微机实验/TD-PITE] 8254 定时/计数器实验+选做实验 | Yesterday17's Blog [JLU CTF/2020] babywasm WriteUp | Yesterday17's Blog PHP 反序列化与经典利用 | Yesterday17's Blog WebAssembly 逆向简述 | Yesterday17's Blog 『彼女、お借りします』一期完结点评 | Yesterday17's Blog [微机实验/TD-PITE] D/A 转换实验+选做实验 | Yesterday17's Blog [微机实验/TD-PITE] A/D 转换实验+选做实验 | Yesterday17's Blog 开源项目申请 JetBrains Open Source License 简单流程 | Yesterday17's Blog 微软拼音与 JetBrains 搜索快捷键冲突的解决方案 | Yesterday17's Blog [微机实验/TD-PITE] 8259 中断优先级实验+选做实验 | Yesterday17's Blog IFTTT 测试(续) | Yesterday17 IFTTT 测试 | Yesterday17's Blog [微机实验/TD-PITE] 存储器扩展实验+选做实验 | Yesterday17's Blog 新版 GCC 针对 -fdump-translation-unit 的替代方案 | Yesterday17's Blog 一次 HSTS 策略配置的排错之旅 | Yesterday17's Blog YukiNative 踩坑记——Windows 的消息队列 | Yesterday17's Blog 我是我自己——论获取 HTTPS 证书时的验证步骤 | Yesterday17's Blog 【设计文档】对 PUG 的大规模设计修订(1.1) | Yesterday17's Blog GS65 折腾记(2)加装固态,分区,Grub2 引导 Manjaro LiveCD | Yesterday17's Blog 「さくら、もゆ。」的空白字体列表——一次逆向问题定位过程实录 | Yesterday17's Blog GSuite 探索篇(1)使用 Service Account 向 Google Drive 传输文件 | Yesterday17's Blog 『サクラノ詩 -櫻の森の上を舞う-』通关感想 | Yesterday17's Blog 《ATRI -My Dear Moments-》通关感想 | Yesterday17's Blog [工具][VSCode 扩展] AegiKit——方便 Aegisub 使用的工具箱 | Yesterday17's Blog 贝塞尔曲线、字体矢量化与曲线运算 | Yesterday17's Blog NAT 类型初探 | Yesterday17's Blog
[Windows/Linux] GC553 的 Switch 完美采集之路 | Yesterday17's Blog
Yesterday17 · 2021-01-27 · via Yesterday17's Blog

ToC

  • 前言
  • Windows
  • Linux
    • 视频
      • 尝试:VLC
      • 尝试:OBS-Studio
      • 尝试:mpv
    • 那么,音频……
      • 音频在哪里?
      • mpv 播放视频+音频
      • mpv 播放音频
      • OBS 播放音频
      • PulseAudio 音频 loopback
    • Bash Script
  • 参考

前言

趁着假期摸了一块采集卡,准备在笔记本上愉快地莱莎2。本来基本已经放弃在 Linux 上玩耍了[1],但 Reddit 上的一篇帖子[2]重新勾起了我的兴趣。

正面照
正面照

帖子中的描述非常简单,好像楼主也并没有做太多的操作。但正是由于过于简单,导致后续的研究过程耗费了比较多的时间。

虽说是勾起的 Linux 下的兴趣,这篇文章中同样包含 Windows 下的部分配置内容。虽然 Windows 用得少,但不代表完全不用。Windows 下的采集非常简单,基本上可以说是完全无坑;Linux 下则是完全靠着摸索得到的方案,也算是收获颇丰吧(笑)

什么?你说 mac?你给我买一台我就写(逃

Windows

Windows 下有着官方的技术支持,过程非常简单,但我使用的并不是官方方案。一来官方方案需要额外下载软件,二是官方方案主要是为直播而生,对于直接在笔记本上使用并没有特别优化过。因此我最终选择了 PotPlayer

虽然它被钉在了耻辱柱上,但谁让它是真的香呢(悲)

PotPlayer 的主菜单中,选择「打开设备」,然后选中设备就可以了。视频输入一般是开箱即用,音频输入可能需要在下面的设置里调整一下,或者直接在 Windows 设置里把采集卡的音频输入设置成默认(?

总之就是这种不需要怎么说就能简单实现的平台 有空把这部分补补齐吧(懒

Linux

Linux 下的问题就相对复杂些了。由于官方没有提供任何 Linux 相关的技术支持,我们只能自己摸索。为了方便观察,下面的截图里使用了很多 grep 来产生高亮。

视频

首先需要解决的问题是视频源。我们插入 USB,看看 lsusb

设备成功显示。然后使用 v4l2-ctl 查看设备列表:

可以看到有两个 /dev/video,我暂且蒙在鼓里(

尝试:VLC

尝试使用 VLC 打开:

第一次打开发现提示了神秘的错误:

第二次出现了神秘的影像:

看起来要手动调整一下分辨率:

然而修改之后再尝试连接什么反应都没有了,非常神秘。重新开启 VLC,连之前的神秘影像都显示不出来了。拔掉 USB 重来,看来是不能指望 VLC 了。

尝试:OBS-Studio

OBSWindows 上的表现还是值得称道的,但在 Linux 下好像就不大行了……

不知道发生了什么事情,总之就是绿了。不大行(

尝试:mpv

mpv 在它的 Wiki 中有专门的一篇文章叙述 v4l2[3]。我们直接使用 Wiki 上提供的第一行命令:

mpv av://v4l2:/dev/video0 --profile=low-latency

然后就没有然后了,hmm……并且延迟非常可以,个人感觉比 Windows 下还低。完全没有问题了。

顺带一提,在 mpv 成功播放之后,OBS 它也可以了(

这合理吗
这合理吗

嘛,不管专门说,视频问题都解决了(

那么,音频……

解决完视频问题,问题就解决了一大半了。毕竟你可以直接把耳机接 NS 上(逃

音频在哪里?

我们先通过 pactl 来观察一下情况:

可以发现,音频源是作为一个输入设备接入的。通过 arecord 也可以看到:

同样是通过 arecord,获得设备的 ID

现在我们来尝试录制一下:

耳机里出现了熟悉的 BGM

mpv 播放视频+音频

同样是在那篇 Wiki 中,mpv 提供了和 v4l2 一起播放音频的方案:通过 --audio-file 指定音频文件为 pulseaudio 设备。

但这个方案在测试中发现并不能让 mpv 发出声音。文章最后的 untested suggestion 倒是可以播放音频,但发出声音的代价是视频的延迟激增到了 2 秒以上,并且伴随着极低的 FPS。这条路可以算是彻底不可行了。

mpv 播放音频

和上面一条路有点像,但又有所区别。既然 mpv 一起放不行,那分开放呢?

事实证明,分开播放确实可行。由于视频采集和音频采集各自的延时都很低,因此分开播放并不会产生太大的 desync 问题。但是在播放过程中,时常会有扰人的 Audio device underrun 出现,伴随着由此产生的爆音:

日志输出
日志输出

于是,这条路也只好放弃了。

OBS 播放音频

既然是 PulseAudio 源,那么使用 OBS 的音频输入捕获怎么样呢?我们来尝试一下。首先是音频源,直接选中我们的设备:

可以看到,底部已经有声音的标识了:

但这时候我们还不能听到声音,需要在高级音频属性里打开音频设备的监听:

此时桌面音频就和音频输入捕获保持同步了,我们也可以听到音乐了:

经过测试,OBS 的音频输入捕获工作得非常完美,不存在 mpv 的爆音问题。但为了播放音频而多打开一个软件实在是太不优雅,于是这条路作为备用方案,暂时搁置。

PulseAudio 音频 loopback

到了这里,我们不妨想一想,绕了这么多圈,用了这么多软件,我们这个需求的本质是什么?

在我之前翻译的 ALSA 音频 API 使用教程 中较为详细地描述了 ALSA 工作的一些基本概念,而 PulseAudio 则是在 ALSA 和应用程序之间充当着代理的角色。

回到正题,我们希望能够将采集卡采集到的音频在计算机上播放,此时采集卡相当于一个输入设备。对于我们而言,平时最常用的音频输入设备麦克风,此时的采集卡也充当着这样的角色。

回过头来,在很多情况下,我们都能听到麦克风录制的自己的声音,这通常用在麦克风测试的过程中,通过播放麦克风录制的音频,确保麦克风配置正确。这样的行为就是 loopback

PulseAudio 中,通过 module-loopback 模块开启音频源的 loopback,我们可以通过 pactl 来启用它:

启用过程中要指定 source 的 id
启用过程中要指定 source 的 id

随着 BGM 的响起,这场和采集卡斗智斗勇的旅程也就这样告下帷幕了。

Bash Script

最后就是一键脚本时间了。保存脚本为 ccp.sh,你就可以通过 ccp 直接开始摸鱼了。

幸福往往是摸得透彻,而敬业的心却常常隐藏

简单来说,功能有:

  • 双击全屏
  • ESC 退出全屏
  • Ctrl+C 退出
  • F10 截屏到 pwd 或指定目录

具体实现看源码就是了(笑

实际使用中有一个问题,就是在 USB 刚刚接入的时候就运行脚本,有大概率音频回放没有声音。我个人的猜测是采集卡还没有进入工作状态,所以建议等待一段时间(也不用太长)再运行就没有问题了。

#!/bin/bash

PROGNAME="$(basename $0)"

# mpv settings

MPV_FULLSCREEN=no

MPV_VIDEO_SIZE=1920x1080

MPV_TITLE="Live Gamer Ultra-Video"

MPV_SCREENSHOT_DIR="$(pwd)"

GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","fullscreen","fs" -n "$PROGNAME" -- "$@")

[[ $? -ne 0 ]] && exit 1

eval set -- "$GETOPT_ARGS"

while :; do

case "$1" in

-h|--help)

usage

exit 0

;;

--video-size)

shift

VIDEO_SIZE="$1"

shift

;;

--video-device)

shift

MPV_VIDEO_SIZE="$1"

shift

;;

--fullscreen|--fs)

shift

MPV_FULLSCREEN=yes

;;

--screenshot-directory)

shift

MPV_SCREENSHOT_DIR="$1"

shift

;;

--title)

shift

MPV_TITLE="$1"

SHIFT

;;

--)

shift

break

;;

esac

done

function requirement_check() {

which lsusb > /dev/null 2>&1 &&

which pactl > /dev/null 2>&1 &&

which v4l2-ctl > /dev/null 2>&1 &&

which mpv > /dev/null 2>&1 ||

(echo "Please make sure lsusb, pactl, v4l2-ctl and mpv exist in your system!"; exit 1)

}

function device_check() {

lsusb | grep -q AVerMedia

[[ $? -ne 0 ]] && echo "No capture card found!" && exit 1

}

function get_source() {

PACTL_SOURCE=$(LC_ALL=C pactl list sources | grep AVerMedia -B 3 | grep Source | cut -d '#' -f 2)

}

function audio_on() {

# get audio source id

get_source

# retry once

# may fail if audio source has not been initialized

[[ -z "$PACTL_SOURCE" ]] && sleep 1 && get_source

[[ -z "$PACTL_SOURCE" ]] && echo "Failed to get audio source!" && exit 1

# enable audio loopback

PACTL_MODULE_ID=$(pactl load-module module-loopback source="$PACTL_SOURCE")

[[ $? -ne 0 ]] && echo "Failed to initialize audio playback!" && exit 1

}

function audio_off() {

if [ ! -z "$PACTL_MODULE_ID" ]; then

pactl unload-module $PACTL_MODULE_ID

fi

}

function video_config() {

# create tmp config dir

CONFIG_DIR=$(mktemp -d -t ccplay-XXXXXXXX)

# create tmp config file

CONFIG_FILE=$(cat << EOF

osc=no

input-default-bindings=no

osd-font-size=24

profile=low-latency

untimed=yes

# screenshot

screenshot-format=png

screenshot-template=screenshot-%tY-%tm-%td-%tH:%tM:%tS

screenshot-directory=$MPV_SCREENSHOT_DIR

title=$MPV_TITLE

fullscreen=$MPV_FULLSCREEN

demuxer-lavf-o=video_size=$MPV_VIDEO_SIZE

EOF

)

echo "$CONFIG_FILE" > "$CONFIG_DIR/mpv.conf"

# create tmp input config

CONFIG_FILE=$(cat << EOF

MBTN_LEFT_DBL cycle fullscreen

ESC set fullscreen no

ctrl+c quit 0

F10 screenshot

EOF

)

echo "$CONFIG_FILE" > "$CONFIG_DIR/input.conf"

}

function video_on() {

# default video device

if [ -z "$VIDEO_DEVICE" ]; then

VIDEO_DEVICE=$(v4l2-ctl --list-devices | grep 'Live Gamer Ultra-Video' -A 5 | grep '/dev' | head -n 1 | xargs)

fi

# launch mpv

mpv "av://v4l2:$VIDEO_DEVICE" --config-dir="$CONFIG_DIR" &>/dev/null &

}

function start() {

requirement_check

device_check

audio_on

video_config

video_on

wait $!

# https://github.com/mpv-player/mpv/blob/master/DOCS/man/mpv.rst#exit-codes

# file could not be played, retry once

if [ $? -eq 2 ]; then

video_on

wait

fi

}

function clean() {

audio_off

yes | rm "$CONFIG_DIR"/*.conf &>/dev/null

yes | rmdir "$CONFIG_DIR" &>/dev/null

}

trap clean EXIT

start

参考

  1. https://forum.manjaro.org/t/trying-to-connect-avermedia-capture-card/38613
  2. https://www.reddit.com/r/linux/comments/c0vy1c/recording_4k_linux_including_gaming_footage_using/
  3. https://github.com/mpv-player/mpv/wiki/Video4Linux2-Input