MiniDV → Apple Silicon

Рабочий стек, методика архивной оцифровки и живой режим: камера и звук в реальном времени.
Sony DCR-PC115E · MacBook Air M1 · macOS 26.5.2 Tahoe · ASFireWire · обновлено 4 октября 2026

Проект и патч к ASFireWire: github.com/PaperPit/minidv-macos · English README: README.md

Статус на 4 октября 2026. Mac, в котором Apple полностью удалила стек FireWire, работает и как станция оцифровки, и как живой источник: пользовательский DriverKit-драйвер, камкордер опознан по шине, с ленты снята побитовая копия (1895 кадров, 1 потерянный, 0 переполнений кольца, размер делится на 144 000 без остатка), а живой DV идёт в OBS и браузер — видео через Syphon, звук прямо из DV-потока в BlackHole, оба канала сверены с FFmpeg побитово. Ярлык поднимает всё это одним кликом. Документ фиксирует, что для этого понадобилось, — чтобы через полгода не собирать заново по памяти.
Содержание
  1. Стек: железо, софт, идентификаторы
  2. Что именно было сделано — воспроизводимая последовательность
  3. Найденные баги и наблюдения (для upstream и для себя)
  4. Методика оцифровки: как делать правильно
  5. Живой режим: камера и звук в реальном времени
  6. Состояние системы, обслуживание и откат
  7. Шпаргалка команд

1. Стек

Физическая цепочка

Sony DCR-PC115E
i.LINK 4-pin, S100
→ кабель FW400 4-pin ↔ FW800 9-pin→ Apple TB→FireWire
A1463, FW 5.6
→ Apple TB3→TB2
A1790
→ MacBook Air M1
Thunderbolt 3 / USB4

Порядок сборки жёсткий: A1790 в Mac, в него A1463, в него FireWire-кабель. A1790 однонаправленный (TB2-устройство → TB3-хост), наоборот не работает. Внутри A1463 — PCIe-контроллер OHCI 1394, который пробрасывается в систему через Thunderbolt-туннель.

Точные идентификаторы

КомпонентЗначениеГде увидеть
MacMacBookAir10,1 / J313AP / T8103 (M1)ioreg -p IOService
macOS26.5.2 (25F84), Darwin 25.5.0, arm64sw_vers
Xcode26.6 (17F113)xcodebuild -version
OHCI-контроллерLSI/Agere FW643 «TrueFire»
PCI 11c1:5901 → IOPCIMatch 0x590111c1
ioreg | grep 11c1
Thunderbolt-линкBus 0, Route String 1, 10 Гбит/с, прошивка адаптера 5.6system_profiler SPThunderboltDataType
Локальный узелnode 0 / 0xFFC0, S800отчёт диагностики ASFW
Камера на шинеnode 1 / 0xFFC1, S100, root + IRM, contenderотчёт диагностики ASFW
GUID камеры0x0800460101DBB1F0вкладка Device Discovery
Vendor OUI0x080046 = SonyConfig ROM
Unit Spec ID0x00A02D (1394 TA / AV/C)Config ROM
Класс устройстваTA 61883 (AMDTP)Discovery
ДрайверASFireWire, commit 9055449, VERSION 0.2.0-audio
bundle net.mrmidi.ASFW.ASFWDriver (0.2.0/2)
systemextensionsctl list

Состояние системы, необходимое для работы

SIP
Отключён (csrutil disable из Recovery). Сборка ad-hoc-подписанная, без нотаризации — иначе AMFI её не запустит.
Developer mode
Включён (sudo systemextensionsctl developer on).
Подпись
Ad-hoc (codesign --sign -), entitlements встроены скриптом sign.sh. Team ID отсутствует, поэтому удаление — systemextensionsctl uninstall - <bundle> с дефисом вместо ID.
Entitlements dext
driverkit, driverkit.transport.pci, driverkit.transport.pci.bridge, driverkit.family.audio
Entitlements app
system-extension.install, driverkit.userclient-access
SCSI HBA
Не собирать. Флаг --scsi при отсутствии SBP-2-устройства на шине приводит к панике ядра в бут-луп. В нашей сборке персоналии нет.

Параметры сигнала

ПараметрЗначениеСледствие
ФорматDV25, PAL 625/50кадр 720×576, 25 к/с, чересстрочный
Цветyuv420p, SAR 16:15, DAR 4:3в квадратных пикселях — 768×576
Порядок полейbottom field firstsetfield=bff, bwdif=parity=bff
Кадр на диске144 000 байт (300 DIF-пакетов × 480 Б)размер файла обязан делиться нацело
Поток≈3,6 МБ/с → 12,96 ГБ/часчас ленты ≈ 13 ГБ
Изохронный канал63 (широковещательный)камкордеры Sony вещают на нём по умолчанию
Пакетов в секунду8000 циклов, из них 7500 с данными300 × 25 = 7500 — контрольная арифметика
Звук12 бит / 32 кГц, 2 стереопарыST1 — микрофон (−25 дБ), ST2 пуста (−91 дБ)
Метаданныетаймкод ленты сохраняетсяв примере 00:04:22:08

2. Что было сделано

Последовательность воспроизводима с нуля на любом Apple Silicon Mac с macOS 26 и таким же адаптером.

Шаг 1. Диагностика: понять, что именно сломано

На Tahoe бандлы IOFireWireFamily.kext, IOFireWireAVC.kext, AppleFWOHCI.kext физически лежат в /System/Library/Extensions/ — и это сбивает с толку. Решающая проверка:

kmutil inspect --bundle-path /System/Library/Extensions/IOFireWireFamily.kext | grep -i fire
kmutil showloaded | grep -i IOFire
ioreg -p IOService -w0 | grep -i "11c1"

В boot kernel collection нет ни одного FireWire-расширения — на Apple Silicon код системных kext-ов живёт там, а не в бандле. Бандлы остались пустыми скорлупками с Info.plist и userspace-плагинами. При этом контроллер pci11c1,5901 исправно виден как IOPCIDevice — то есть железо работает, не хватает только драйвера.

Ложный след: AppleFireStormErrorHandler в выводе kextstat | grep fire — это обработчик ошибок производительных ядер M1, к FireWire отношения не имеет.

Шаг 2. Сборка ASFireWire

mkdir -p ~/Developer && cd ~/Developer
git clone https://github.com/mrmidi/ASFireWire.git
cd ASFireWire

sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -license accept

./build.sh --config Release     # БЕЗ --scsi
./sign.sh

build.sh собирает намеренно без подписи; sign.sh затем ad-hoc-подписывает и .app, и вложенный .dext нужными entitlements и сам проверяет, что они встроились. Готовых релизов у проекта нет — только исходники.

Шаг 3. Подготовка системы

Recovery (зажать кнопку питания → Параметры → Утилиты → Терминал):

csrutil disable

После перезагрузки:

csrutil status                          # System Integrity Protection status: disabled.
sudo systemextensionsctl developer on

Шаг 4. Установка

cp -R build/DerivedData/Build/Products/Release/ASFW.app /Applications/
open /Applications/ASFW.app

Кнопка Install живёт в тулбаре окна справа сверху, горячая клавиша ⌘I. Расширение уйдёт в состояние activated waiting for user — его нужно вручную одобрить: Системные настройки → Основные → Объекты входа и расширения → Расширения драйверов.

Проверка:

systemextensionsctl list        # ждём [activated enabled]
ioreg -p IOService -w0 -l -r -n "pci11c1,5901" -d 2 | grep -Ei "ASFWDriver|IOUserServerCDHash"

Под PCI-нодой должен появиться дочерний ASFWDriver. IOUserServerCDHash — надёжный способ убедиться, что загружена именно свежая сборка, а не закешированная старая: версия бандла при пересборке не меняется, а хеш меняется всегда.

Грабли. При переустановке старое расширение зависает в состоянии terminating for uninstall but still running и держит слот — новое активируется, но контроллер может остаться за старым процессом. Лечится перезагрузкой; после неё в списке должна остаться ровно одна запись.

Шаг 5. Патч скорости ответов

Без него AV/C не работает вообще, а Config ROM читается через раз. Подробности — в разделе 3.

sed -i '' 's/constexpr uint8_t kSpeedS400 = 0x02;/constexpr uint8_t kSpeedS400 = 0x00;  \/\/ S100 responses/' \
  ASFWDriver/Async/Tx/ResponseSender.cpp
./build.sh --config Release && ./sign.sh

Дальше — снять старое расширение, заменить app, поставить заново, перезагрузиться:

systemextensionsctl uninstall - net.mrmidi.ASFW.ASFWDriver
rm -rf /Applications/ASFW.app
cp -R build/DerivedData/Build/Products/Release/ASFW.app /Applications/
open /Applications/ASFW.app        # ⌘I, одобрить, перезагрузиться

Шаг 6. Захват

Камера: питание от сети, кассета внутри, POWER → VCR, в меню VCR SET → A/V→DV OUT = OFF. Кабель подключать только при выключенной камере.

В ASFW: Controller Status → Connect, затем вкладка DV Capture, канал 63, выбрать выходной файл, Start Capture, и нажать Play — в приложении или пальцем на камере. AV/C для захвата не требуется: поток идёт по изохронному каналу независимо от команд управления.

3. Найденные баги и наблюдения

Баг 1 — жёстко зашитая скорость S400 в исходящих ответах исправлен

ASFWDriver/Async/Tx/ResponseSender.cpp, строки 34 и 42:

constexpr uint8_t kSpeedS400 = 0x02;
...
uint32_t BuildQ0(uint8_t tLabel, uint8_t tCode) {
    return (static_cast<uint32_t>(kSrcBusID & 0x01) << 23) |
           (static_cast<uint32_t>(kSpeedS400 & 0x07) << 16) |   // ← всегда S400
           ...

Исходящие async-запросы используют скорость из speed map (драйвер корректно опускает узел до S100 после двух таймаутов), а ответы — нет. Камкордер i.LINK работает только на S100 и физически не принимает пакеты на S400. Результат — шторм AT-resp DROPPED ... event=0x03 (evt_missing_ack) и полный развал AV/C.

Почему баг не всплывал раньше: всё тестовое железо автора (Apogee Duet, Focusrite Saffire, PreSonus StudioLive, Midas Venice) — устройства S400. Камкордер S100 попал на этот драйвер впервые.

Временное исправление: отвечать всегда на S100. Ответы — мелкие пакеты, потеря скорости на них не значима, а S100 принимают все устройства без исключения.

Правильное исправление для upstream: отзеркаливать скорость принятого запроса, как это делает Linux (fw_fill_response). Мешает баг 3.

Баг 2 — AT-completion не сопоставляется для блочных записей открыт

После исправления бага 1 транзакции на проводе проходят полностью — это видно в трассе диагностики:

TX ATReq 34 WrBlock S100 0xFFC0→0xFFC1 0xFFFFF0000B00  complete   ← AV/C-команда в FCP_COMMAND
RX ARReq 34 WrBlock      0xFFC1→0xFFC0 0xFFFFF0000D00  Ack 0x12   ← ответ камеры через 2.9 мс
TX ATRsp 34 WrResp S100  0xFFC0→0xFFC1                 complete   ← наш write-response

Но драйвер этого не видит и через 750 мс помечает транзакцию как TimedOut:

OnTimeout: tLabel=34 state=ATPosted ackCode=0x0
❌ FAILED: AT completion never arrived after 2 attempts
[AVC] AVCUnit: UNIT_INFO failed: result=8

Квадлетные чтения (Config ROM) сопоставляются нормально — ломаются именно блочные записи с payload. Подозреваемое место: ATContextBase::ExtractCompletionTLabel, где индекс дескриптора-заголовка вычисляется как (headIndex + capacity - 2) % capacity — для пакетов с payload геометрия дескрипторов другая.

Практическое следствие: AV/C-команды до камеры доходят и выполняются, интерфейс просто рапортует «no FCP response». Кнопки Play/Stop/Rewind, скорее всего, работают, несмотря на сообщение. Для захвата потока это вообще не критично.

Баг 3 — скорость принятого пакета теряется при разборе блокирует правильный фикс бага 1

В OHCI скорость приёма лежит в битах 21–23 трейлерного xferStatus (Linux: p.speed = (status >> 21) & 0x7). В ASFireWire структура ARPacketView (ASFWDriver/Async/Rx/PacketRouter.hpp) хранит uint16_t xferStatus — младшие 16 бит. Биты скорости отрезаются, отзеркалить скорость запроса в ответе невозможно. В PacketRouter.cpp:223 при этом стоит заглушка event.speed = 0; // S100.

Правильный фикс: расширить поле до 32 бит либо добавить uint8_t speed в ARPacketView и использовать его в ResponseSender::BuildQ0.

Наблюдение — gap count 44 при оптимальном 5

Gap Count: 44        Expected Gap: 5
Decision: SuppressedByRoleMode
Configured Role Mode: Client Only (no BM/IRM)
BM Node: none

Драйвер сознательно не претендует на роль Bus Manager, поэтому никто не оптимизирует gap count. Для шины из двух узлов 44 — это заметно раздутые арбитражные паузы. На нашем захвате это не помешало (0 переполнений кольца), но при длинных лентах или более загруженной шине сюда стоит вернуться первым делом. Цикл-мастером выступает камера — она root и CMC-capable, Remote Cycle Continuity: Yes.

Что имеет смысл отправить в upstream

4. Методика оцифровки

4.1 Подготовка лент

4.2 Настройка камеры

Питание
Только сетевой адаптер. Просадка на батарее в середине кассеты = обрыв захвата.
Режим
POWER → VCR
Меню
VCR SET → A/V→DV OUT = OFF — это сквозной аналог→DV, при воспроизведении ленты он должен быть выключен
Автовыключение
OTHERS → A.SHUT OFF → NEVER, иначе камера уснёт на паузе и уронит шину
Подключение
Кабель втыкать только при выключенной камере. Горячее подключение FireWire — классический способ сжечь порт i.LINK
LP-режим
Читается хуже SP. Если лента писалась в LP — ожидайте больше выпадений, это свойство формата

4.3 Процесс

  1. Запустите caffeinate -d -i в отдельном окне терминала — ноутбук не должен уснуть посреди кассеты.
  2. Убедитесь, что свободного места хватает: 13 ГБ на час ленты. 60-минутная кассета SP ≈ 13 ГБ.
  3. ASFW → Controller Status → Connect → вкладка DV Capture.
  4. Канал 63. Выберите выходной файл с осмысленным именем (см. 4.5).
  5. Start Capture, затем Play. Захват идёт в реальном времени: час ленты = час ожидания, ускорить нельзя.
  6. Следите за счётчиками (см. 4.4). Не сворачивайте окно надолго — приложение вычитывает кольцо на 30 Гц.
  7. По окончании — Stop Capture. Только после этого файл закрыт и валиден.

4.4 Контроль качества во время захвата

СчётчикНормаЕсли не так
SystemPAL (625/50)NTSC на европейской ленте — разбирайтесь до продолжения
Isoch packets seen≈8000/с0 → камера не вещает: проверьте, идёт ли лента, и не занят ли IR-контекст аудио
DV source packets7500/с (300 на кадр)сильно меньше — потери на шине
Non-DV packets0>0 → фильтр CIP не узнаёт поток, пришлите Last rejected в issue
Frames+25/сотставание = потери
Dropped frames0, допустимо единицырастёт постоянно → изохронный приём не справляется
Ring overruns0>0 → приложение не успевает вычитывать кольцо (буфер всего 1,1 с)
Written≈3,6 МБ/сарифметика: кадры × 144000 = байты

Эталон нашего захвата: 1895 кадров, 1 dropped, 621 186 isoch, 568 554 DV source, 0 non-DV, 0 overruns, 272 880 000 байт. 568554 / 1896 = ровно 300 пакетов на кадр.

4.5 Проверка результата

F=~/Documents/tape01.dv
python3 -c "import os,sys;s=os.path.getsize(sys.argv[1]);print(s,'bytes |',s/144000,'frames | remainder',s%144000)" "$F"
ffprobe -hide_banner "$F"

Остаток от деления обязан быть 0. Это главный признак того, что кадры выровнены и файл не бит. ffprobe должен показать dvvideo, yuv420p, 720x576 [SAR 16:15 DAR 4:3], 25 tbr и звуковые дорожки.

Проверить, есть ли что-то на второй звуковой паре (12-битный режим пишет две, вторая обычно пуста):

ffmpeg -hide_banner -i "$F" -map 0:a:0 -af volumedetect -f null - 2>&1 | grep mean_volume
ffmpeg -hide_banner -i "$F" -map 0:a:1 -af volumedetect -f null - 2>&1 | grep mean_volume

Уровень около -91 dB = дорожка пустая.

4.6 Именование и хранение

Мастер .dv — это точная копия ленты. Его не редактируют, не пережимают и не удаляют никогда; всё остальное пересоздаётся из него одной командой.

2003-08_семейный-отпуск_кассета-04.dv
2003-08_семейный-отпуск_кассета-04.dv.md      ← заметки: что на ленте, состояние, число dropped

Правило 3-2-1: три копии, на двух разных носителях, одна вне дома. 13 ГБ на час — это дорого в облаке, но дешевле, чем потерять всё. Таймкод ленты сохраняется в метаданных файла, так что порядок и позиции восстановимы.

4.7 Производные файлы

Мастер для монтажа — ProRes HQ, обе звуковые дорожки, поля сохранены

ffmpeg -i "$F" -map 0 -c:v prores_ks -profile:v 3 -vf "setfield=bff" \
  -c:a pcm_s16le tape01_prores.mov

Для просмотра — деинтерлейс в 50p, квадратный пиксель 768×576

ffmpeg -i "$F" -filter_complex \
  "[0:v]bwdif=mode=send_field:parity=bff,scale=768:576:flags=lanczos,setsar=1[v]" \
  -map "[v]" -map 0:a:0 -c:v libx264 -crf 18 -preset slow -pix_fmt yuv420p \
  -c:a aac -b:a 192k tape01_view.mp4
Почему 768, а не 1024. PAL DV имеет неквадратный пиксель. При SAR 16:15 и кадре 4:3 правильный размер в квадратных пикселях — 720 × 16/15 = 768×576. Ширина 1024 применяется только к анаморфному 16:9 материалу. Если ошибиться, ffmpeg компенсирует через SAR 3:4 и картинка всё равно покажется верно, но вы зря потратите битрейт на растянутый кадр.

bwdif=mode=send_field даёт 50 кадров в секунду — движение остаётся таким же плавным, как на ленте. Деинтерлейс применяется только к копии для просмотра; мастер и монтажный ProRes остаются чересстрочными.

5. Живой режим: камера и звук в реальном времени

Работает целиком. Камкордер в режиме CAMERA (или на воспроизведении ленты) отдаёт живой DV по i.LINK; видео уходит в OBS через Syphon, звук — прямо из DV-потока в BlackHole, оттуда его берут OBS, Chrome и любые приложения. Оба канала сверены с FFmpeg побитово. Одним кликом по ярлыку поднимается всё: камера, звук, источники в OBS и виртуальная камера для браузера.

5.1 Цепочка целиком

Sony DCR-PC115E
CAMERA или VCR
→ ASFWDriver
изохронный канал 63
→ кольцо DIF
480 Б × 8192
→ декодер + звук
144 000 Б на кадр
видео → Syphon
1024×576 или 768×576
→ OBS
источники сцены
→ OBS Virtual Camera
1920×1080@60
→ Chrome / Zoom / Meet
звук → BlackHole 2ch
микрофон для приложений
→ OBS / Chrome

5.2 Что реализовано

КомпонентФайлыСостояние
Захват DV в драйвереASFWDriver/Isoch/Receive/DVCaptureSinkработает, кольцо в разделяемой памяти
Сборка кадра из DIF-чанковDVLive/DVFrameAssembler.swiftтолько кадры точного размера
Декод видеоDVLive/DVDecoder.swiftVideoToolbox, PAL и NTSC
ДеинтерлейсDVLive/DVDeinterlacer.swiftbob по нижнему полю → 50p
Публикация видеоDVLive/SyphonOutput.swiftSyphon, кадр растянут до квадратного пикселя
Геометрия кадраDVLive/DVFrameGeometry.swift4:3 и 16:9WIDE, vImage
Звук из DVDVLive/DVAudioExtractor.swift16 бит и 12 бит, сверено с FFmpeg
Вывод звукаDVLive/DVAudioExtractor.swift (DVAudioPlayer)приёмник по имени, по умолчанию BlackHole
Публикация камеры системеASFWCamera/не активируется из-за подписи, см. 5.8
Ярлык «всё сразу»scripts/minidv-live/работает, см. 5.5

5.3 Звук: он уже лежит внутри DV-потока

Отдельного аудиопути не нужно: в каждом кадре DV 12 DIF-последовательностей, в каждой 9 аудиоблоков, и звук жёстко привязан к кадру. Отсюда важное следствие — звук и видео синхронны по построению, и синхронность не надо восстанавливать: 48 кГц — 1920 сэмплов на канал на кадр, 32 кГц — 1280, 44,1 кГц — 1764.

16 бит линейный
режим AUDIO MODE → 16BIT (48 кГц, одна стереопара)
12 бит нелинейный
режим AUDIO MODE → 12BIT (32 кГц, две стереопары; разбирается первая, ST1)
Приёмник по умолчанию
BlackHole 2ch — тогда любое приложение видит звук с камкордера как микрофон, а системный вывод остаётся свободным
Стоимость разбора
3,5 мкс на кадр при -O (0,009 % бюджета 40 мс)

Проверено. 16 бит/48 кГц — 250 кадров, побитовое совпадение с FFmpeg (480 000 сэмплов, max|d| = 0); 12 бит/32 кГц — тоже побитово (1280 сэмплов на канал, сверка с первым аудиопотоком FFmpeg); офлайн-рендер графа AVAudioEngine — побитово. Живой прогон в устройство: 50 буферов из 50, потерь 0.

# что вообще есть в системе
/Applications/ASFW.app/Contents/MacOS/ASFW --list-audio-devices

# тон 1 кГц слева / 3 кГц справа прямо в приёмник
/Applications/ASFW.app/Contents/MacOS/ASFW --audio-selftest 3

# прогон .dv через боевой путь в темпе 25 к/с + дамп PCM для сверки
/Applications/ASFW.app/Contents/MacOS/ASFW --dv-audio-selftest test48.dv --pcm-out out.pcm

# тот же граф офлайн-рендером (сверка с FFmpeg)
/Applications/ASFW.app/Contents/MacOS/ASFW --audio-render-selftest test48.dv --pcm-out render.pcm

Установка приёмника: brew install --cask blackhole-2ch (нужен пароль администратора). Другой приёмник задаётся флагом --audio-device <имя или UID>, выключить звук — --no-audio.

5.4 Геометрия: почему картинка была сжата

В DV пиксель неквадратный, а 16:9WIDE у Sony — анаморфная запись: мануал DCR-PC115E (стр. 59) прямо говорит «the picture … is compressed in the widthwise direction». Показывать кадр надо так:

Режим камерыPARКвадратный пиксельПризнак в кадре
4:316:15768×576код аспекта 0
16:9WIDE64:451024×576код аспекта 2

Признак лежит в VAUX Video Control пакете (тег 0x61, позиции чередуются между DIF-последовательностями), условие то же, что в FFmpeg: (vsc[2] & 7) == 2 || (!apt && (vsc[2] & 7) == 7).

Что было не так. Живой путь отдавал кадр 720×576 как квадратный пиксель, то есть 5:4. Замер по записи OBS: содержимое занимало 1344×1075 = 5:4 вместо 16:9 — картинка была сжата по ширине примерно на 42 %. Syphon pixel aspect ratio не передаёт вовсе, поэтому растягивать приходится нам: кадр уходит в Syphon уже с квадратным пикселем, и OBS не надо ничего настраивать.
# проверка без камеры: режим, растяжка и PNG на выходе
/Applications/ASFW.app/Contents/MacOS/ASFW --dv-frame-selftest wide.dv --png wide.png
# → режим кадра: 16:9 (анаморфно); извлечено 720×576 → 1024×576

Тестовые потоки генерируются FFmpeg: -f dv с -aspect 16:9 даёт анаморфный 16:9 (SAR 64:45), без него — обычный 4:3 (SAR 16:15).

5.5 Ярлык MiniDV Live: один клик

Двойной клик — и поднимается всё. Ярлык лежит в /Applications/MiniDV Live.app, исходники — scripts/minidv-live/ (обычный bash + помощник на node), переустановка — ./install.sh.

  1. проверяет, что драйвер ASFW загружен и BlackHole установлен;
  2. останавливает прошлый живой захват (иначе два процесса дерутся за одно кольцо драйвера) и поднимает новый;
  3. открывает OBS и через obs-websocket приводит сцену к рабочему виду: источник Sony DCR-PC115E (тип syphon-input), звуковой вход BlackHole 2ch, видео вписано в канву;
  4. включает виртуальную камеру (StartVirtualCam) — без этого браузер видит устройство, но кадров не получает.

Лог: ~/Library/Logs/MiniDVLive.log. Отладка без окон: MINIDV_NO_DIALOG=1 "/Applications/MiniDV Live.app/Contents/MacOS/MiniDVLive".

5.6 OBS: сцена, виртуальная камера и одна ловушка

Ловушка. OBS Virtual Camera — системное расширение, и оно всегда перечисляется в списке камер приложений, даже когда OBS закрыт. Кадры при этом не идут, пока не активен выход виртуальной камеры. Отсюда классическая жалоба «камера в списке есть, но картинки нет» — сначала Start Virtual Camera, и только потом выбирать её в браузере. Второе: расширение объявляет единственный формат 1920×1080@60, поэтому если приложение требует ровно 30 к/с — будет отказ (см. тестовую страницу в 5.7).

5.7 Браузер: Chrome и другие

Разрешения нужны на двух уровнях: macOS (Настройки → Конфиденциальность → Камера/Микрофон) и сам сайт (иконка камеры в адресной строке). В нашем случае у Chrome оба разрешения выданы, а проблема была в выключенной виртуальной камере.

Для быстрой диагностики есть страница camera-test.html (запускается через локальный сервер скриптом camera-test.command — на file:// Chrome иногда не даёт доступ к камере). Она показывает список устройств, превью, negotiated-формат и точную ошибку (NotAllowedError, NotReadableError, OverconstrainedError), плюс отдельные кнопки с frameRate ideal/ровно 30/ровно 60. Полезное рядом: chrome://media-internals — покажет, какой формат запрошен и на чём споткнулся.

5.8 Что осталось

Не сделаноПочему и что нужно
Камера как системное устройство (CMIO)Расширение ASFWCamera написано и публикует «Sony DCR-PC115E», но не активируется: OSSystemExtensionError.validationFailed (9). Сборка ad-hoc, Team ID нет, а камера-расширение требует нормальной подписи (Developer ID/Development + совпадающий Mach-service). Живой режим поэтому идёт через Syphon → OBS → OBS Virtual Camera.
Вторая звуковая пара (ST2) в 12-битном режимеРазбирается только ST1 (микрофон). ST2 обычно пуста, но для полноты можно публиковать вторым потоком.
Общий таймлайн и метрика дрейфаСинхронность держится на покадровом приходе (DV кадрово-синхронный), отдельного общего времени и счётчика расхождения пока нет.
Восстановление после bus resetWatchdog есть у Syphon-раннера (перезапуск при остановке потока), обработки выдёргивания кабеля и переключения CAMERA↔VCR нет.
Gap count 44 при оптимальном 5Драйвер не претендует на роль Bus Manager. На нашем захвате не мешало, но на длинных сессиях стоит вернуться.
NTSC и DVCPRO50Извлекатель звука рассчитан на PAL 625/50 (144 000 Б), для NTSC нужны 120 000 Б и таблица dv_audio_shuffle525.
Только macOSЯрлык и диагностика — macOS-специфичные; сам драйвер тоже (DriverKit).
Чего мы не измеряли. Сквозную задержку «камера → браузер» и потери на длинных сессиях. По частям: разбор звука 3,5 мкс/кадр, буферы по 20 мс, BlackHole добавляет буфер устройства, OBS Virtual Camera объявляет 1080p60. Если будете мерить — интересны кадры на длинной дистанции и поведение после bus reset.

6. Состояние системы, обслуживание и откат

Каким должно быть рабочее состояние

SIP
Отключён (csrutil disable из Recovery). Сборка ad-hoc-подписанная, без нотаризации — иначе AMFI её не запустит.
Developer mode
Включён (sudo systemextensionsctl developer on).
Драйвер
net.mrmidi.ASFW.ASFWDriver (0.2.0/2) в состоянии [activated enabled].
Камера-расширение
Обычно не активировано — это нормально, живой режим идёт мимо него (см. 5.8).
obs-websocket
Включён ярлыком (server_enabled: true), слушает только 127.0.0.1:4455 с вашим паролем.
Диск
Оцифровка требует ~13 ГБ на час ленты; живой режим места не требует.

Как остановить живой режим

pkill -f -- "--syphon"          # выключить камеру и звук
# в OBS: Stop Virtual Camera; в браузере устройства исчезнут сами

Откат ярлыка и obs-websocket

rm -rf "/Applications/MiniDV Live.app"
# WebSocket: OBS → Tools → WebSocket Server Settings → снять Enable
#   либо вернуть конфиг из бэкапа, который ярлык сделал сам:
#   ~/Library/Application Support/obs-studio/plugin_config/obs-websocket/config.json.bak-minidv

Полный откат драйвера

Порядок обратный установке и его нельзя нарушать:

pkill -f -- "--syphon"
systemextensionsctl uninstall - net.mrmidi.ASFW.ASFWDriver
systemextensionsctl list                 # убедиться, что записи нет
sudo systemextensionsctl developer off

И только потом Recovery → csrutil enable → перезагрузка.

Почему порядок важен. С включённым SIP система откажется запускать ad-hoc-подписанный dext. Если расширение осталось установленным, при каждом старте остаётся осиротевший kernel-stub. В сборках со SCSI HBA это приводит к панике в бут-луп. Аварийный выход: Recovery → csrutil disable → загрузиться → снять расширение → Recovery → csrutil enable.

Что сохранить на будущее

7. Шпаргалка

Живой режим — одной командой

open -a "MiniDV Live"                                   # ярлык: камера + звук + OBS + виртуалка
MINIDV_NO_DIALOG=1 "/Applications/MiniDV Live.app/Contents/MacOS/MiniDVLive"   # без окон, для отладки
tail -f ~/Library/Logs/MiniDVLive.log                   # что происходит

Состояние системы

csrutil status
systemextensionsctl list
ioreg -p IOService -w0 | grep -i "11c1"
ioreg -p IOService -w0 -l -r -n "pci11c1,5901" -d 2 | grep -Ei "ASFWDriver|IOUserServerCDHash"

Звук

/Applications/ASFW.app/Contents/MacOS/ASFW --list-audio-devices
/Applications/ASFW.app/Contents/MacOS/ASFW --audio-selftest 3
/Applications/ASFW.app/Contents/MacOS/ASFW --dv-audio-selftest test48.dv --pcm-out out.pcm
/Applications/ASFW.app/Contents/MacOS/ASFW --audio-render-selftest test48.dv --pcm-out render.pcm

Геометрия кадра

/Applications/ASFW.app/Contents/MacOS/ASFW --dv-frame-selftest wide.dv --png wide.png

# тестовые потоки: 4:3 и анаморфный 16:9
ffmpeg -y -f lavfi -i "testsrc2=size=720x576:rate=25" -c:v dvvideo -pix_fmt yuv420p -r 25 -t 2 -f dv four3.dv
ffmpeg -y -f lavfi -i "testsrc2=size=720x576:rate=25" -c:v dvvideo -pix_fmt yuv420p -r 25 -aspect 16:9 -t 2 -f dv wide.dv

OBS: что видит сам OBS

# статус виртуальной камеры и источника (нужен node и включённый obs-websocket)
node scripts/minidv-live/obs-sources.js        # привести сцену к рабочему виду
# в логе скрипта: outputActive, videoActive, videoShowing, список источников

Логи драйвера и приложения

log stream --style compact --predicate 'processImagePath CONTAINS[c] "ASFWDriver"
 OR eventMessage CONTAINS[c] "[Discovery]" OR eventMessage CONTAINS[c] "[Async]"
 OR eventMessage CONTAINS[c] "[AVC]" OR eventMessage CONTAINS[c] "[Isoch]"'

log show --last 10m --style compact --predicate 'subsystem CONTAINS "DVLive"' | tail -40
sudo log collect --last 10m --output ~/Desktop/asfw.logarchive

Пересборка после правки

cd ~/Developer/ASFireWire
./build.sh --config Release --no-bump && ./sign.sh
systemextensionsctl uninstall - net.mrmidi.ASFW.ASFWDriver
rm -rf /Applications/ASFW.app
cp -R build/DerivedData/Build/Products/Release/ASFW.app /Applications/
open /Applications/ASFW.app      # ⌘I → одобрить → перезагрузиться

Оцифровка ленты и проверка файла

python3 -c "import os,sys;s=os.path.getsize(sys.argv[1]);print(s,'bytes |',s/144000,'frames | remainder',s%144000)" tape.dv
ffprobe -hide_banner tape.dv
ffmpeg -hide_banner -i tape.dv -map 0:a:1 -af volumedetect -f null - 2>&1 | grep mean_volume

Транскод

# монтажный мастер
ffmpeg -i tape.dv -map 0 -c:v prores_ks -profile:v 3 -vf "setfield=bff" -c:a pcm_s16le tape_prores.mov

# просмотр
ffmpeg -i tape.dv -filter_complex "[0:v]bwdif=mode=send_field:parity=bff,scale=768:576:flags=lanczos,setsar=1[v]" \
  -map "[v]" -map 0:a:0 -c:v libx264 -crf 18 -preset slow -pix_fmt yuv420p -c:a aac -b:a 192k tape_view.mp4

Полезное во время сессии

caffeinate -d -i        # не давать Mac уснуть
df -h ~                 # 13 ГБ на час ленты
Источники и ссылки. ASFireWire · Тред разработки на MacRumors · TidBITS: FireWire удалён из macOS 26 · Der Flounder: что исчезло · DVRescue · tapecap (macOS 11–15) · Apple: Core Media I/O · Apple: отладка system extensions · Syphon · BlackHole · obs-websocket · OBS: virtual camera troubleshooting · PCI 11C1:5901 — LSI FW643

Обновлено 4 октября 2026 года: добавлены живой звук через DV, геометрия 4:3/16:9WIDE, ярлык запуска и работа с виртуальной камерой в браузере. ASFireWire активно развивается — перед возвратом к проекту сверьтесь с актуальным состоянием репозитория: часть описанных багов может быть уже исправлена в upstream.