源码地图
按“我要解决什么问题”定位入口。所有链接固定到 scrcpy v4.1。
一、总入口与组合根
| 问题 | 入口 | 接下来读 |
|---|---|---|
| CLI 如何进入主流程 | app/src/main.c | cli.c, options.c |
| 客户端组件如何装配 | scrcpy() | 同文件 532–1035 |
| Android 端如何装配 | Server.scrcpy() | AsyncProcessor 实现 |
| 退出码从哪里来 | event_loop() | callbacks + events.h |
二、ADB、进程与连接
| 目标 | 主要文件 | 关键符号 |
|---|---|---|
| 选择设备 | app/src/server.c, adb/adb_parser.c | run_server, sc_adb_select_device |
| push/启动 server | app/src/server.c | push_server, execute_server |
| reverse/forward | adb/adb_tunnel.c | sc_adb_tunnel_open |
| Android socket | DesktopConnection.java | open, shutdown, close |
| 可中断网络 | util/intr.c, util/net_intr.c | sc_intr_interrupt |
| 子进程观察 | util/process.c | sc_process_observer_* |
三、视频设备端
| 目标 | 文件 | 关键位置 |
|---|---|---|
| 编码循环/降级 | SurfaceEncoder.java | streamCapture, prepareRetry, encode |
| capture 抽象 | SurfaceCapture.java | init/prepare/start/stop/release |
| 真实屏幕 | ScreenCapture.java | display properties + projection |
| 相机 | CameraCapture.java | selectCamera, selectSize, Camera2 callbacks |
| 虚拟显示 | NewDisplayCapture.java | create/resize/display id publish |
| reset 原因 | CaptureControl.java | reset, consumeReset |
| 视频约束 | VideoConstraints.java | max size/alignment/capabilities |
| 封帧 | device/Streamer.java | codec/session/packet headers |
四、音频设备端
| 目标 | 文件 | 关键职责 |
|---|---|---|
| source 枚举 | audio/AudioSource.java | direct 与 playback 分类 |
| playback capture | AudioPlaybackCapture.java | AudioRecord 构造与启动 |
| direct capture | AudioDirectCapture.java | 麦克风/voice source |
| 稳定读 PCM | AudioRecordReader.java | timestamp 与读循环 |
| 压缩编码 | AudioEncoder.java | MediaCodec |
| raw 直传 | AudioRawRecorder.java | PCM packet |
五、客户端媒体
| 目标 | 文件 | 关键职责 |
|---|---|---|
| 解 scrcpy framing | demuxer.c | codec/session/packet |
| 合并 H.26x config | packet_merger.c | config 前置 |
| FFmpeg 解码 | decoder.c | packet → frame |
| packet 多播 | trait/packet_source.c | sinks open/push/close |
| frame 多播 | trait/frame_source.c | sinks open/push/session |
| 最新帧缓冲 | frame_buffer.c | AVFrame ref/consume |
| 视频调度 | video_regulator.c | PTS deadline |
| 音频调节 | audio_regulator.c | ring buffer + compensation |
六、控制与输入
| 目标 | 文件 | 关键职责 |
|---|---|---|
| SDL 语义翻译 | input_manager.c | shortcuts/coords/clipboard |
| 客户端发送队列 | controller.c | queue/serialize/send |
| 控制序列化 | control_msg.c | desktop → device |
| 反向反序列化 | device_msg.c, receiver.c | device → desktop |
| Java 控制分发 | control/Controller.java | 23 种 action |
| Java 消息解析 | ControlMessageReader.java | binary reader |
| 设备注入 | device/Device.java | InputEvent、power、clipboard、app |
| SDK 键鼠 | keyboard_sdk.c, mouse_sdk.c | Android action messages |
| UHID | app/src/uhid/*, UhidManager.java | virtual HID |
| AOA | app/src/usb/* | libusb accessory HID |
| HID 状态 | app/src/hid/* | descriptors/reports |
七、UI 与输出
| 目标 | 文件 | 关键职责 |
|---|---|---|
| SDL window/render/input | screen.c | content rect + render |
| YUV texture | texture.c | AVFrame → SDL_Texture |
| 坐标反算 | screen.c | convert_window_to_frame_coords |
| 录制 | recorder.c | packet queue + FFmpeg mux |
| V4L2 | v4l2_sink.c | raw frame → virtual camera |
| 文件拖放 | file_pusher.c | adb install/push + media scan |
八、Android 兼容与构建
| 目标 | 文件 | 关键职责 |
|---|---|---|
| 虚构 app 环境 | Workarounds.java, FakeContext.java | ActivityThread/Context |
| 系统 Binder | wrappers/ServiceManager.java | service lookup/cache |
| 隐藏 API 漂移 | wrappers/*.java | reflection/version branches |
| 状态恢复 | CleanUp.java | settings/display/jar cleanup |
| C 构建 | app/meson.build | deps/platform/features/tests |
| Java 构建 | server/build.gradle | SDK/AIDL/JUnit |
| 总构建 | meson.build, server/meson.build | app/server/prebuilt |
| 发布矩阵 | .github/workflows/release.yml | tests + multi-platform artifacts |
九、按改动类型的最短阅读链
text
新增 control message:
control_msg.h/c → ControlMessage.java → ControlMessageReader.java
→ Controller.handleEvent → 双端 tests
新增 frame consumer:
frame_sink.h → 参考 screen/v4l2 → scrcpy.c 装配 → stop/join/destroy
新增 capture source:
SurfaceCapture → 参考 Screen/Camera/NewDisplay
→ Options → Server.scrcpy → control capabilities
排查启动失败:
run_server → adb parser/select → adb_tunnel → execute_server
→ DesktopConnection → Server.internalMain