# VCD 转录报告 — 光盘卷标 `TOX_VCD`（两盘一套：VCD1 / VCD2）

- 转录时间：2026-09-28
- 来源：光驱 `/dev/sr0`（hp DVD-RAM UJ8E1）中的两张 CD
- 光盘类型：**VCD（Video CD）**，CD-Bridge / CD-ROM XA 格式
- 产出：**6 个 MP4**（每盘 2 段分卷 + 1 个合并完整版，共约 114 分钟）+ 2 张内容总览图
- 下载页：http://192.168.31.76:8899/66-VCD转录/

---

## 一、总览

| | VCD1 | VCD2 |
|---|---|---|
| 卷标 | `TOX_VCD` | `TOX_VCD` |
| 制作 | Easy CD Creator 4.0，2000-02-21 | 同上（同批） |
| 容量 | 534.9 MiB / 273,858 扇区 | 496.2 MiB / 242,305 扇区 |
| 视频段落 | `MUSIC01.DAT` + `MUSIC02.DAT` | `MUSIC01.DAT` + `MUSIC02.DAT` |
| 总时长 | **1:00:35**（26:11 + 34:24） | **53:34**（31:44 + 21:50） |
| 可读性 | **0 个坏扇区** | **0 个坏扇区** |
| 画面 | MPEG-1 352×288 PAL、25 fps、逐行 | 同左 |
| 声音 | MPEG-1 Layer II 224 kbps 立体声 44.1 kHz | 同左 |
| 内容 | 学校艺术节演出实况（鼓乐群舞/独唱/合唱/铜管/群舞/重唱/颁奖/谢幕） | 同类演出实况（主持串场/群舞/钢琴/对唱/独唱/谢幕） |
| 结尾背景板 | 金字「**飞翔 青春**」＋学生举 "**SEIZE THE DAY**" 字牌 | 红底横幅「**华南师大附中第23届青春旋律艺术节**」 |

两盘均为同一家店（TERAOPTIX）同一时期制作的 `TOX_VCD`，盘面**没有任何曲目/标题元数据**（`VCD/INFO.VCD`、`ENTRIES.VCD` 内只有版本号，无文本字段），活动名是从画面上读出来的。

> **关于两盘关系**：经用户确认，两盘属于**同一届**（华南师大附中第23届青春旋律艺术节），是**同一届艺术节的两次录像**（不是同一场简单分卷）。因此两盘文件名统一采用该活动名。
>
> 盘面上能看到的差别：两盘**结尾谢幕场景不同**——VCD1 是蓝色运动服学生举 "SEIZE THE DAY" 红字牌、背景板为金色主题字「飞翔 青春」；VCD2 是各色演出服全体谢幕、背景板为红底白字校名届次横幅。VCD1 画面上**没有**出现校名届次横幅，其届次**无法从盘面自行读出**（曾放大颁奖展板等文字，VCD 分辨率下不可辨）——文件名中的届次依据用户确认，本报告如实记录这一来源。

---

## 二、产出文件

| 文件 | 时长 | 大小 |
|---|---|---|
| `VCD1-Part1-华南师大附中第23届青春旋律艺术节-26分11秒.mp4` | 26:10.9 | 224 MB |
| `VCD1-Part2-华南师大附中第23届青春旋律艺术节-34分24秒.mp4` | 34:23.7 | 279 MB |
| `VCD1-完整版-华南师大附中第23届青春旋律艺术节-60分35秒.mp4` | 60:34.6 | 503 MB |
| `VCD2-Part1-华南师大附中第23届青春旋律艺术节-31分44秒.mp4` | 31:44.2 | 227 MB |
| `VCD2-Part2-华南师大附中第23届青春旋律艺术节-21分50秒.mp4` | 21:49.6 | 158 MB |
| `VCD2-完整版-华南师大附中第23届青春旋律艺术节-53分34秒.mp4` | 53:33.9 | 384 MB |
| `VCD1-华南师大附中第23届青春旋律艺术节-内容总览.png` | — | VCD1 内容总览图（12 格带时间码） |
| `VCD2-华南师大附中第23届青春旋律艺术节-内容总览.png` | — | VCD2 内容总览图（12 格带时间码） |
| `VCD2-华南师大附中第23届青春旋律艺术节-背景板横幅.png` | — | 活动名证据（背景板放大 4 倍） |

命名规则统一为 **`VCD<碟号>-<PartN|完整版>-华南师大附中第23届青春旋律艺术节-<时长>.mp4`**。

「完整版」是把该盘两段用 `-c copy` 无损拼接（不重新编码），拼接点前后解码 0 错误。

---

## 三、内容说明

### VCD1（1:00:35，`MUSIC01.DAT` + `MUSIC02.DAT`）

| 时间 | 内容 |
|---|---|
| 00:00 | 彩条测试图（录像母带常规开头） |
| 00:00–05:00 | 儿童鼓乐＋扇舞群舞（红鼓、粉装） |
| ~05:00 | 女声独唱（绿色花饰演出服） |
| ~10:00 | 合唱（男生白衬衫领结） |
| ~15:00 | 少年铜管独奏 |
| ~20:00 | 群舞 |
| ~25:00 | 女声独唱（白色长裙）＋伴舞 |
| ~30:00 | 男女重唱（折扇） |
| ~40:00 | 蓝色布光下的双人演出 |
| ~45:00 | 童声合唱（黑白制服） |
| ~50:00 | 颁奖环节（学生举奖杯展板） |
| 结尾 | 全体谢幕：学生举红牌拼出 "**SEIZE THE DAY**"，背景板金字「**飞翔 青春**」 |

### VCD2（53:34，`MUSIC01.DAT` + `MUSIC02.DAT`）

| 时间 | 内容 |
|---|---|
| 00:00 | 女声独唱（红装） |
| ~04:28 | 舞蹈 |
| ~08:56 | 主持人串场 |
| ~13:24 | 群舞（粉色伞/扇） |
| ~17:52 | 钢琴独奏 |
| ~26:48 | 校服男女对唱/朗诵 |
| ~31:16 | 双人舞 |
| ~35:44 | 男女对唱（黄裙） |
| ~40:12 | 男声独唱 |
| ~44:40 | 蓝色布光下的群像节目 |
| 结尾 | 全体谢幕，背景板红底横幅「**华南师大附中第23届青春旋律艺术节**」 |

（时间点为每 4 分半抽一帧的粗定位，用于快速跳转；两张「内容总览.png」即这些帧的拼图。）

---

## 四、技术难点与解决过程（关键部分）

这两张光盘**不能直接用 `mount` + `cp`/`ffmpeg` 转录**，遇到三层问题，逐层解决如下。两盘情况完全相同。

### 问题 1：内核无法读取数据，报 `Illegal mode for this track`

**现象**：`mount -t iso9660 /dev/sr0` 能挂载、能列目录，但一读 `MPEGAV` 里的大文件就立刻失败：

```
$ dd if=/mnt/vcd/... bs=2048 count=200 conv=noerror,sync
dd: 读取时出错: 输入/输出错误        # 每个块都失败，出来的全是 0 字节
```

`dmesg` 关键信息：

```
sr 6:0:0:0: [sr0] tag#0 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_OK
Sense Key : Illegal Request [current]
Add. Sense: Illegal mode for this track          ← ASC 0x64
CDB: Read(10) 28 00 00 00 04 00 00 00 02 00 00 00
```

注意 `Add. Sense: Illegal mode for this track`（ASC/ASCQ = `0x64/0x00`）**不是坏道**（坏道会报 `Medium error` / `Unrecoverable read error`，ASC 0x11）。它表示*驱动器拒绝了这个读取命令的模式*，且 100% 复现。

**原因**：VCD 的视频/音频数据存放在 **CD-ROM XA Mode 2 Form 2** 扇区里——每个 2352 字节扇区中用户数据是 **2324 字节**（12 字节同步头 + 4 字节地址头 + 8 字节 subheader + 2324 字节数据 + 4 字节 EDC）。
而 Linux 的 `sr` 驱动只会用 `READ(10)` 按 **2048 字节（Mode 1 / Mode 2 Form 1）** 读，驱动器发现扇区实际是 Form 2，直接回 `Illegal mode for this track`。于是：

- ISO9660 **元数据**（PVD、目录）是 Form 1 → 挂载、`ls` 正常；
- MPEG **数据**是 Form 2 → 一读就全错。

### 验证：用 SG_IO 绕过内核，对比两种 SCSI 命令

写 `sgio.py` 用 `ioctl(SG_IO)` 直接下发 SCSI 命令，在同一个 LBA 上对比（两盘结果一致）：

| LBA | `READ(10)`（2048 B，内核用的） | `READ CD`（0xBE，原始 2352 B） |
|---|---|---|
| 0 / 16 | OK（16 是 PVD） | OK |
| 1000、8850、53850、123450、200000、270000… | ✗ CHECK CONDITION | **OK 2352 B** |

结论明确：**`READ(10)` 全盘失败，`READ CD` 原始读取全盘成功。**

### 解决：raw 抓取 + 按扇区取 2324 字节负载

1. 用 `READ CD (0xBE)` 带 `SYNC|HEADER|USERDATA|EDC/ECC` 标志（CDB byte9 = `0xF8`），把全盘按 2352 字节/扇区镜像成 `*-disc.img`（VCD1 644 MB、VCD2 570 MB）；
2. 按 ISO9660 解析出各 `.DAT` 的起始 LBA 与扇区数；
3. 对每个扇区跳过 24 字节（同步头+地址头+subheader），取 **2324 字节**数据拼接，得到标准 MPEG-1 Program Stream。

**口径自校验**：提取出的流以 `00 00 01 BA`（MPEG pack start code）开头；码率反算 VCD1 为 273,960,092 B ÷ 1570.8 s = 174.3 KB/s = 1.394 Mbps，与 VCD 标准（1.15 Mbps 视频 + 224 kbps 音频 ≈ 1.374 Mbps）吻合 → 证明按 2324 取字节是对的。

### 问题 2：单次 SG_IO 传输有 120 KB 上限

一开始按 64 扇区/次（150 KB）读取，结果**每个块都失败**并退化成逐扇区读，速度只有 0.18 MB/s（预计要 53 分钟）。查明原因：

```
$ cat /sys/block/sr0/queue/max_sectors_kb
120
```

实测阈值正好卡在这里：**52 扇区（122,304 B）成功，53 扇区（124,656 B）报 EIO**。改成每次 52 扇区后，速度升到 **2.6–2.9 MB/s（24x）**，每盘约 3.7 分钟读完。

### 问题 3：TOC 报的 lead-out 是错的，不能作为抓取边界

两盘的 TOC 都不可信：

| | TOC 报告的 lead-out | 实际最后一个文件末端 | 设备容量 |
|---|---|---|---|
| VCD1 | LBA 240,825 | LBA 273,737 | LBA 273,858 |
| VCD2 | LBA 237,975 | LBA 242,184 | LBA 242,305 |

若按 VCD1 的 lead-out 截断，会丢掉 `MUSIC02.DAT` 结尾 **21 分钟**内容。所以抓取范围取 **`max(所有文件末端, 设备容量)`**，两盘都 100% 读取成功。

### 附带发现：挂载看到的目录树是错的

`mount` 后 `ls` 得到的是「`mpegav/` 空、`vcd/music01.dat`、`segment/entries.vcd`」，而直接从原始镜像解析 ISO9660 得到的正确结构是「`MPEGAV/MUSIC01.DAT`、`VCD/INFO.VCD`、`SEGMENT/` 空」——**挂载视图的目录内容整体错位**（与 `READ(10)` 的异常同源），且该盘无 Joliet / Rock Ridge，本不该出现小写文件名。所以本次**一切结论都以自行解析 raw 镜像为准**，不采信挂载结果。

---

## 五、转码参数与质量校验

**源**：MPEG-1 video 352×288、SAR 178:163（= 4:3）、25 fps、逐行、1130.8 kbps + MPEG-1 Layer II audio 224 kbps 立体声 44.1 kHz

**命令**：
```bash
ffmpeg -i musicNN.mpg \
  -vf "scale=384:288:flags=lanczos,setsar=1" \
  -c:v libx264 -preset slow -crf 18 -pix_fmt yuv420p \
  -c:a aac -b:a 192k -ac 2 \
  -movflags +faststart out.mp4
```

参数理由：

- **不做反交错**：`ffmpeg -vf idet` 抽样（VCD1 403 帧 / VCD2 303 帧）结果均为 `Progressive` 100%、`TFF/BFF = 0`，源是纯逐行，强行反交错只会损失清晰度。
- **缩放到 384×288 方形像素**：源像素是非方形的（352 × 178/163 = 384.4），即正确显示宽度是 384。缩成 384×288 并标记 SAR 1:1，可保证**任何播放器/手机/电视都按 4:3 正确显示**，不依赖播放器是否尊重 SAR；放大只有 1.09 倍，不引入可见损失。
- **CRF 18 + preset slow**：源仅 1.13 Mbps 且带模拟噪声，CRF 18 下成品码率约 1.13–1.19 Mbps，肉眼与源无差别。
- **`+faststart`**：moov 原子前置，下载页可秒开、可拖动进度条。

**校验结果**：

| 检查项 | VCD1 | VCD2 |
|---|---|---|
| 提取出的 MPEG 全流解码（`-err_detect explode -f null -`） | **0 错误** | **0 错误** |
| 成品时长 vs 源时长 | 分卷 1570.92 / 2063.68 s，合并 3634.62 s | 分卷 1904.20 / 1309.64 s，合并 3213.86 s |
| 合并版拼接点解码 | **0 错误** | **0 错误** |
| 成品规格 | H.264 High / yuv420p / 384×288 DAR 4:3 / AAC-LC 44.1 kHz 立体声 | 同左 |

---

## 六、原始素材与脚本（DSH 机 `~/Downloads/vcd-rip/`）

无损母版全部保留，便于日后重做（更高码率、加字幕、刻盘回 VCD 等）：

| 路径 | 内容 |
|---|---|
| `disc.img` (644 MB) / `VCD2-disc.img` (570 MB) | **整盘 raw 镜像**，2352 B/扇区 |
| `mpeg/music01.mpg` (274 MB)、`mpeg/music02.mpg` (360 MB) | VCD1 无损 MPEG-PS 母版 |
| `mpeg-VCD2/music01.mpg` (332 MB)、`music02.mpg` (228 MB) | VCD2 无损 MPEG-PS 母版 |
| `sgio.py` | SG_IO 底层工具（TOC 读取 / `READ CD` 原始读扇区 / 分块与重试） |
| `disc_scan.py` | **直接从光盘**读 ISO9660 元数据，推算抓取范围 |
| `rip_raw.py` | 整盘 raw 抓取（分块、重试、错误扇区记录） |
| `iso_parse.py` | 从 raw 镜像解析 ISO9660（Form 1 负载在偏移 24） |
| `extract_vcd.py` | 按扇区取 2324 字节负载，拼出 MPEG |
| `run_disc.sh` | 阶段一：扫描 → 抓取 → 提取 → 打印流信息（`bash run_disc.sh VCD2`） |
| `encode_disc.sh` | 阶段二：转 MP4 + 合并完整版（`bash encode_disc.sh VCD2`） |
| `convert_mp4.sh` | VCD1 最早的手工转码脚本（保留备查） |
| `disc.err.json` / `VCD2-disc.err.json` | 坏扇区清单（两盘内容均为 `"errors": []`） |

---

## 七、复现步骤（以后遇到同类 VCD 一条龙）

```bash
cd ~/Downloads/vcd-rip

# 阶段一：扫描光盘 → 整盘 raw 抓取 → 提取 MPEG-PS → 打印流信息
bash run_disc.sh VCD3          # 换成你要的前缀

# （可选）抽帧确认内容、确认是否隔行
ffmpeg -ss 600 -i mpeg-VCD3/music01.mpg -frames:v 1 -q:v 2 -y /tmp/f.jpg
ffmpeg -ss 600 -i mpeg-VCD3/music01.mpg -vf idet -frames:v 300 -f null -

# 阶段二：转 MP4（384x288 / H.264 CRF18 / AAC 192k）+ 合并完整版
bash encode_disc.sh VCD3
```

### 通用经验（下次遇到同类盘可直接套用）

1. **`Add. Sense: Illegal mode for this track`（ASC 0x64）≠ 坏盘**，是扇区模式不匹配；VCD/SVCD/CD-i 的 MPEG 数据是 Mode 2 Form 2，普通 `mount` + `cp` 一定读不出来。
2. **不要依赖 `mount` 的目录树**，这类盘必须从 raw 镜像自己解析 ISO9660（本次挂载结果整体错位）。
3. **不要依赖 TOC 的 lead-out** 作为抓取终点（本次两盘都错，VCD1 差 33,000 扇区）；用「设备容量」与「ISO 声明的文件末端」取大者。
4. **`READ CD (0xBE)` 原始 2352 字节读取是这类盘的万能钥匙**；系统没有 `readcd`/`cdrdao` 时，用 Python + `SG_IO` 几十行就能实现。
5. **单次 SG_IO 传输受 `max_sectors_kb` 限制**（本机 120 KB）；超限直接报 EIO 而不自动截断，极易被误判成坏道。
6. **VCD 的 `.DAT` 在 ISO 里声明的大小是「扇区数 × 2048」，但每个扇区实际携带 2324 字节**——拼接时必须按 2324 取，否则流会错乱。
7. VCD 画面像素是**非方形**的（352×288 实际显示为 384×288），转录时要么保留 SAR，要么缩成 384×288 方形像素，否则画面会被压扁。

---

## 八、下载地址

- 目录页：http://192.168.31.76:8899/66-VCD转录/
- 本报告：http://192.168.31.76:8899/66-VCD转录/VCD转录报告.md?preview=1
- 在线播放（支持拖动进度条）：`VCD1-完整版-华南师大附中第23届青春旋律艺术节-60分35秒.mp4`、`VCD2-完整版-华南师大附中第23届青春旋律艺术节-53分34秒.mp4`
