Несмотря на то, что видеокассеты уже давно вышли из повседневной жизни, услуги по их оцифровке продолжают пользоваться спросом. Кассеты с любительскими записями есть почти в каждой семье, и рано или поздно их нужно перевести в цифру, ведь срок жизни магнитной ленты ограничен.

Зимой 2025 года в мои руки попало 35 кассет формата VHS и VHS-C из семейного архива, и встала задача по их оцифровке. С учетом того, что на каждой кассете было записано приблизительно по 60 минут видео, а средний ценник услуг по захвату сейчас составляет 400 рублей в час, общая стоимость конвертации составила бы около 14 тысяч рублей. Эта сумма показалась мне слишком большой, и было решено сделать все самостоятельно. В данной статье я хочу рассказать об относительно новом методе оцифровки видеокассет, на котором я остановился, и сравнить его с классическими подходами.

Оцифровка видео — это сложно

Оцифровка данных с аналоговых носителей — непростая задача. В случае с видео она осложняется тем, что приходится работать с очень большим потоком информации. Если на аудиокассете ширина полосы пропускания составляет 12-16кГц, то на кассете стандарта VHS — около 5МГц, то есть в 300 раз больше. Это накладывает жесткие требования на качество оборудования и точность его работы. Кроме того, видеосигнал имеет сложную структуру и рассчитан на телевизор с кинескопом, который рисует кадр строчку за строчкой. А значит, нужно как-то интерпретировать для конвертации в цифровой файл.

Из-за этих и многих других сложностей для качественной оцифровки видео обычно требуется дорогое оборудование, настроенное правильным образом. Споры о том, какой магнитофон, карта захвата и программа дают лучший результат, не утихают по сей день.

Айсберг оцифровки видео (не полный)
Айсберг оцифровки видео (не полный)

Популярные способы оцифровки видео

Методы оцифровки видео можно условно поделить на две категории:

  • Любительский — используется дешевая внешняя USB карта захвата, например AVerMedia DVD EZMaker 7, и бытовой VHS магнитофон. Стоимость такого комплекта составляет приблизительно 9 тысяч рублей при покупке с рук;

  • Профессиональный — используется дорогая внешняя или внутренняя карта захвата, например Canopus ADVC-300, и S-VHS магнитофон с функцией Time Based Correction (TBC), ведь серьезные карты захвата очень требовательны к стабильности сигнала, и при работе в паре с бытовым магнитофоном гарантировано будут потери кадров. Стоимость такого комплекта начинается с 35 тысяч рублей при покупке с рук.

Конечно, это упрощенная классификация, в которой не учтены экзотические походы. Например, в качестве карты захвата можно использовать старую камеру стандарта Digital8, подключив ее к компьютеру по FireWire.

Что такое VHS-Decode?

VHS-Decode — это программа, создатели которой обещают результат профессионального качества при минимальных затратах на оборудование. Предлагается использовать бытовой магнитофон, но брать сигнал не с видеовыхода, а с предусилителя магнитных головок, после чего оцифровывать его с высокой частотой простым АЦП. Последующая работа по интерпретации данных выполняется на компьютере. Таким образом, программа заменяет собой схемотехнику магнитофона и карты захвата.

Не смотря на название, VHS-Decode позволяет оцифровывать следующие форматы аналогового видео:

  • VHS (NTSC, NTSC-J, PAL, PAL-M);

  • SVHS (NTSC, NTSC-J, PAL, PAL-M);

  • U-Matic Low Band (PAL, NTSC);

  • U-Matic High Band (PAL);

  • Betamax (PAL, NTSC);

  • SuperBeta (NTSC);

  • Video8 и Hi8 (PAL, NTSC);

  • 1" Type C (SMPTE Type C) (PAL, NTSC);

  • 1" Type B (SMPTE Type B) (PAL, NTSC);

  • EIAJ (PAL);

  • Philips VCR и Philips VCR "LP" (PAL).

Проект активно развивается, и возможно этот список будет расширен в будущем. Также, важно заметить, что VHS-Decode является форком проекта LD-Decode, который нацелен на работу с LaserDisk.

Подготовка к оцифровке с помощью VHS-Decode

Для оцифровки кассет с помощью VHS-Decode вам потребуется следующее оборудование:

  • Видеомагнитофон формата VHS. Подойдет любой исправный аппарат, но, если есть выбор, лучше взять машину от Panasonic или JVC с поддержкой Hi-Fi. Стоимость такого магнитофона на Авито от 2 до 5 тысяч рублей;

  • Аудиокарта для записи звука. Подойдет любой приличный вариант с поддержкой захвата 24bit 48kHz. Стоимость такой карты на Авито начинается от 4 тысяч рублей;

  • Кассета формата VHS с записанным на нее фильмом длиной не менее получаса и цифровая версия этого фильма. Они пригодятся нам при калибровке скрипта для синхронизации аудио и видео. Кассету можно найти на дальней полке шкафа или на Авито за несколько сотен рублей;

  • Высокочастотный кабель длиной не более метра с импедансом 50Ом и высокочастотными разъемами мама-папа на концах. Авторы проекта рекомендуют разъемы BNC, однако ниже я объясню, почему лучше остановиться на разъемах SMA. Такой кабель можно найти на Ozon за 600 рублей;

  • Тюбик нейтрального эпоксидного клея-пластилина или силиконового герметика. Можно найти где угодно приблизительно за 300 рублей;

  • Керамический конденсатор номиналом от 3.3 до 10мкФ. Можно найти где угодно за несколько рублей;

  • Карта видеозахвата формата PCIe 1x на основе чипа Conexant CX2388x, как на картинке ниже. Такую карточку можно найти по запросу «карта видеозахвата 640x480» на Ozon или Aliexpress. Стоить она будет около 1700 рублей.

Как говорилось выше, мы будем подключаться к предусилителю магнитных головок. Для этого нужно вскрыть корпус магнитофона и найти на плате контакт, предусмотренный для проверки сигнала при ремонте устройства. В зависимости от производителя он может быть подписан по-разному. Например, в моем LG L494 используется обозначение “RF”. Более подробно о том, как найти площадку и подключиться к ней, написано в вики VHS-Decode.

Можно использовать и электролитический конденсатор. Главное учесть полярность
Можно использовать и электролитический конденсатор. Главное учесть полярность

Необходимо отрезать кусок высокочастотного кабеля и припаять его к найденному контакту через конденсатор. Для удобства в корпусе магнитофона можно проделать дополнительное отверстие и вывести кабель через него, нанеся на место стыка силиконовый герметик или эпоксидную смолу для фиксации.

Я использовал разъем BNC и пожалел об этом
Я использовал разъем BNC и пожалел об этом

Описанные операции могут показаться сложными, однако занимают не более получаса и безопасны для магнитофона.

Карту видеозахвата также необходимо доработать. Во-первых, требуется удалить разъем RCA и припаять к освободившимся контактным площадкам ответную часть кабеля. При этом суммарная длина этого куска и того, что был установлен в магнитофон, не должна превышать 50 сантиметров. Во-вторых, для снижения уровня шума при оцифровке рекомендуется удалить конденсатор C31. Более подробно модификации карты описаны здесь. Эти манипуляции тоже занимают не более получаса.

Я также на всякий случай установил мелкие радиаторы на чипы
Я также на всякий случай установил мелкие радиаторы на чипы

Теперь, можно установить карту в компьютер. Однако, в случае использования разъема BNC вы не сможете это сделать, так как он шире прорези в корпусе. Именно поэтому лучше использовать более мелкий разъем SMA.

Разъем BNC был ошибкой, но я справился
Разъем BNC был ошибкой, но я справился

Осталось установить необходимые программы:

  • Драйвер АЦП под Ubuntu 22.04 или Windows. Второй имеет статус экспериментального, однако работает без нареканий;

  • Набор утилит из проекта VHS-Decode для Windows, MacOS или Linux. На момент написания статьи актуальна версия 0.3.5;

  • Консольная программа SoX для захвата звука.

Я работаю под Windows, однако большая часть того, что будет сказано далее, справедливо и для Linux версий программ.

Процесс оцифровки

Процесс оцифровки состоит из семи шагов:

  1. Настройка BIOS и перевод Windows в тестовый режим;

  2. Настройка АЦП;

  3. Захват сигнала с магнитофона и сохранение его в файл (capture);

  4. Выделение из сырых данных полезной информации (decode);

  5. Экспорт видео (export);

  6. Синхронизация аудио и видео (align);

  7. Постобработка.

В этом и двух следующих разделах будет дано подробное описание каждого из них. Если вам это не интересно, вы можете перейти к разделу “Сравнение с классическими методами”.

Для корректной работы драйвера АЦП необходимо отключить опцию Secure Boot в BIOS. Под Windows требуется также перевести ОС в тестовый режим, выполнив команду

bcdedit -set testsigning on

и перезагрузив компьютер. После того, как вы захватили все кассеты, можно вернуть ОС в обычный режим с помощью команды

bcdedit -set testsigning off

и повторной перезагрузки.

Настройка АЦП выполняется через специальные команды драйвера. При этом необходимо указать следующие параметры:

  • Разъем, с которого будет захватываться сигнал (vmux);

  • Применять ли ко входному сигналу дополнительное усиление на 6дБ (sixdb);

  • Уровень цифрового усиления входного сигнала (level);

  • Центрирование значений при оцифровке (center_offset).

Мы используем ту площадку АЦП, где изначально стоял разъем RCA, поэтому в качестве первого значения необходимо указать единицу. Дополнительное усиление я рекомендую выключить, так как оно вносит шумы в сигнал. Оставшиеся значения зависят от модели магнитофона и драйвер может подобрать их автоматически. Для этого нужно запустить на магнитофоне воспроизведение и выполнить команду драйвера leveladj. При перезагрузке настройки сбрасываются, поэтому чтобы не восстанавливать их вручную, можно подготовить bat файл. Мой скрипт выглядит следующим образом

prepare.bat

:: вывести список доступных АЦП (в системе их может быть до 255)
"C:\Program Files\cxadc\tools\cxadc-win-tool.exe" scan

:: настроить первый АЦП
"C:\Program Files\cxadc\tools\cxadc-win-tool.exe" set \\.\cxadc0 vmux 1
"C:\Program Files\cxadc\tools\cxadc-win-tool.exe" set \\.\cxadc0 sixdb 0
:: эти два параметра у вас могут отличаться
"C:\Program Files\cxadc\tools\cxadc-win-tool.exe" set \\.\cxadc0 level 31
"C:\Program Files\cxadc\tools\cxadc-win-tool.exe" set \\.\cxadc0 center_offset 8

:: проверить, что настройки сохранились
"C:\Program Files\cxadc\tools\cxadc-win-tool.exe" get \\.\cxadc0

pause

Подробнее о настройке драйвера под Windows можно прочитать здесь, а описание Linux версии приведено здесь.

Теперь мы готовы к оцифровке сигнала. Подключим самодельный кабель, идущий из магнитофона, к АЦП, а красный и белый RCA разъемы к аудио карте. Наконец, запустим такой скрипт

capture.bat

:: запустить запись аудио и видео одновременно на X секунд
start /high "" cmd /c ""C:\Program Files (x86)\sox-14-4-2\sox.exe" -t waveaudio 0 -e signed-integer -b 24 -c 2 -r 48000 "audio.wav" trim 0 X"
start /high "" cmd /c ""C:\Program Files\cxadc\tools\cxadc-win-tool.exe" capture \\.\cxadc0 capture.u8" & timeout /t X /nobreak > nul & taskkill /im cxadc-win-tool.exe /f

и нажмем клавишу Play на магнитофоне. В директории, в которой находится скрипт, появятся файлы audio.wav и capture.u8, в которые будет сохраняться поток аудио и видео соответственно. Запись будет продолжаться в течение X секунд, если вы не прервете ее досрочно. При этом магнитофон можно подключить к телевизору, чтобы контролировать процесс.

По завершении захвата требуется запустить следующий скрипт, сохраняющий время, когда началась запись аудио и видео в файл time.txt. Эта информация пригодится далее для сведения дорожек.

time.bat

echo "Начало захвата видео" >> time.txt
powershell -command "(Get-Item "capture.u8").CreationTime.ToString(\"HH:mm:ss.fff\")" >> time.txt

echo "Начало захвата аудио" >> time.txt
powershell -command "(Get-Item "audio.wav").CreationTime.ToString(\"HH:mm:ss.fff\")" >> time.txt

echo "Смещение начала аудио относительно начала видео (миллисекунд). Если больше 0, то нужно добавить тишину, а если меньше 0 — отрезать начало" >> time.txt
powershell -command "((Get-Item "audio.wav").CreationTime - (Get-Item "capture.u8").CreationTime).TotalMilliseconds" >> time.txt

Теперь мы можем расшифровать сигнал и экспортировать его в видео. Для этого запустим команды

decode pal.bat

:: декодировать сигнал формата PAL с кассеты формата SP
"C:\Program Files\vhs-decode\decode.exe" vhs -p -t 3 --tf vhs --cxadc --recheck_phase --ire0_adjust capture.u8 decoded

:: экспортировать в видео формата FFV1 с чересстрочной разверткой
:: "C:\Program Files\vhs-decode\tbc-video-export.exe" decoded.tbc

pause

Первая запустит длительный процесс расшифровки видео. При этом будет создан ряд файлов с названием decoded и разными расширениями. Далее, будет сформирован файл decoded.mkv с результатом. У утилиты decode есть великое множество аргументов, описанных здесь. Приведенный выше набор параметров кажется мне оптимальным на данный момент (к сожалению, аргумент --chroma_trap сейчас сломан). Программа tbc-video-export тоже предоставляет широкий набор возможностей. Например, можно экспортировать видео в более привычный формат со сжатием h.265 и прогрессивной разверткой. При этом для устранения чересстрочности будет применяться относительно простой алгоритм bwdif.

Наконец, нужно синхронизировать видео с аудиодорожкой с помощью

sync audio.bat

:: добавить X секунд тишины в начало аудио (X отличается от раза к разу)
"C:\Program Files (x86)\sox-14-4-2\sox.exe" audio.wav padded_audio.wav pad X

:: отрезать первые Y секунд аудио (Y отличается от раза к разу)
"C:\Program Files (x86)\sox-14-4-2\sox.exe" audio.wav padded_audio.wav trim Y

:: выровнять аудио, приняв частоту дискретизации аудиодорожки за Z (Z нужно найти один раз)
"C:\Program Files\vhs-decode\ffmpeg.exe" -i padded_audio.wav -filter_complex "channelmap=map=FL-FL|FR-FR" -f s24le -ac 2 - | "C:\Program Files\vhs-decode\AutoAudioAlign.exe" stream-align --sample-size-bytes 6 --stream-sample-rate-hz Z --json decoded.tbc.json --rf-video-sample-rate-hz 40000000 | "C:\Program Files\vhs-decode\ffmpeg.exe" -f s24le -ar Z -ac 2 -i - -af aresample=48000 -sample_fmt s32 sync_audio.wav

pause

Таким образом, мы получим файл sync_audio.wav со звуком для нашего видео. Про параметры X, Y и Z из этого скрипта будет рассказано в следующем разделе.

После оцифровки первой кассеты рекомендую открыть файлы decoded.tbc и decoded.tbc.json в программе ld-analyze, входящей в состав VHS-Decode и проверить отношение сигнала к шуму (SNR). Эта величина должна быть не менее 30дБ.

Подробнее о сведении аудио и видео

Сведение аудио и видео дорожек не так очевидно, как может показаться на первый взгляд. На это есть три причины:

  1. Захват аудио и видео начинается не одновременно. Эта разница может достигать десятых долей секунды в ту или иную сторону;

  2. При работе с сырым сигналом утилита decode выравнивает поля кадра так, чтобы их частота составляла ровно 50Гц (речь идет о стандарте PAL). Требуется передвинуть фрагменты аудио вслед за ними;

  3. Мы считаем, что частота тактового генератора в карте захвата видео равняется 28636363Гц, а в карте захвата аудио — 48000Гц. Однако, на практике всегда существует погрешность на сотые доли процента из-за которой оцифрованное аудио будет воспроизводится чуть быстрее или чуть медленнее оцифрованного видео. Таким образом, за час может набегать до 5 секунд расхождения.

Первая проблема решается проще всего. Один из скриптов, приведенных выше, сформировал файл time.txt, в котором указано, на сколько миллисекунд раньше или позже был создан файл audio.wav относительно capture.u8. Эта величина может служить первым приближением, чтобы решить, сколько миллисекунд добавить к аудио или отрезать от него, чтобы выровнять дорожки. Большей точности можно добиться, оценив эту величину самостоятельно в видеоредакторе. При этом важно смотреть только на самое начало записи. Смещение — это случайная величина, поэтому так придется делать каждый раз при оцифровке очередной кассеты.

Очевидно, что тут нужно отрезать 12/60 секунды в начале аудио
Очевидно, что тут нужно отрезать 12/60 секунды в начале аудио

Вторую проблему за нас решит утилита AutoAudioAlign, входящая в состав VHS-Decode. Она подгонит звук под видео. Однако, для правильной работы этой программы нужно решить третью проблему. Тут то и пригодится кассета с фильмом, для которого у нас цифровая версия с идеально синхронизированными дорожками. Выполним следующие действия:

  1. Оцифруем не менее получаса фильма с кассеты. Получим файлы decoded.mkv и audio.wav;

  2. Выровняем начало audio.wav, методом, описанным выше. Назовем этот файл padded_audio.wav (смотрите скрипт sync audio.bat);

  3. В видеоредакторе разместим параллельно видеодорожку с кассеты и цифровую версию фильма, совместим их с точностью до кадра;

  4. Для начала будем считать, что аудиокарта работает с частотой Z=48000Гц;

  5. Запустим утилиту AutoAudioAlign с текущим значением Z. Назовем получившийся файл sync_audio.wav (смотрите скрипт sync audio.bat);

  6. Добавим на временную шкалу видеоредактора аудиодорожку sync_audio.wav, совместив ее начало с началом decoded.mkv;

  7. Оценим, торопится ли sync_audio.wav относительно дорожки с цифровой версии фильма или отстает от нее;

  8. Если sync_audio.wav торопится, нужно уменьшить величину Z на несколько Гц и вернуться к шагу 5;

  9. Если sync_audio.wav отстает, нужно увеличить величину Z на несколько Гц и вернуться к шагу 5;

  10. Будем уточнять Z до тех пор, пока не добьемся приемлемой точности.

Я использовал для калибровки кассету с клипами Майкла Джексона
Я использовал для калибровки кассету с клипами Майкла Джексона

Таким образом, с помощью эталона мы подбираем такую частоту Z, при которой утилита AutoAudioAlign будет выдывать правильный результат. Величину Z нужно найти один раз, после чего ее можно жестко прописать в скрипте sync audio.bat. Например, в моем случае она равна 47989Гц и погрешность не превышает 0.03 секунды на 30 минут видео.

Постобработка

Теперь, когда у нас есть видеодорожка decoded.mkv и аудиодорожка sync_audio.wav, мы можем объединить их в любом видеоредакторе. Дальнейшая постобработка — дело вкуса, однако я рекомендую выполнить следующие шаги:

  • Устранение чересстрочности — на данный момент мы имеем видео с чересстрочной разверткой, однако для корректного отображения на современных мониторах необходимо перейти к прогрессивной. Есть много методов устранения чересстрочности, но самым продвинутым считается QTGMC. Я пользуюсь реализацией этого алгоритма, входящей в состав StaxRip;

Мой пресет в StaxRip
Мой пресет в StaxRip
  • Временное шумоподавление — VHS-Decode экспортирует именно то, что записано на кассете. В результате получается шумное во времени видео. Если применить к нему фильтр, который удалит помехи с учетом соседних кадров, это значительно улучшит результат;

  • Коррекция кривой яркости — VHS-Decode экспортирует видео с диапазоном яркости 16-235. Это телевизионный стандарт, который может неправильно отображаться в некоторых видеоплеерах. Поэтому зачастую требуется исправить контраст, растянув яркость на полный диапазон 0-255.

Обратите внимание на кривую в нижней центральной части скриншота. Также можно видеть мои настройки шумоподавления
Обратите внимание на кривую в нижней центральной части скриншота. Также можно видеть мои настройки шумоподавления

Вывод о процессе оцифровки

Процесс оцифровки, описанный выше, может показаться сложным, однако после того, как вы откалибруете скрипт для синхронизации аудио, все будет сводиться к простым шагам:

  1. Перевести Windows в тестовый режим;

  2. Подключить магнитофон к компьютеру;

  3. Последовательно запустить скрипты prepare.bat и capture.bat;

  4. Запустить воспроизведение на магнитофоне и дождаться конца кассеты;

  5. Остановить скрипт capture.bat;

  6. Последовательно запустить скрипты time.bat и decode pal.bat;

  7. Оценить, сколько миллисекунд нужно убрать или добавить в начало аудиодорожки, основываясь на подсказке из файла time.txt и том, что вы видите в видеоредакторе. Прописать эту величину в скрипт sync audio.bat

  8. Запустить скрипт sync audio.bat;

  9. Объединить дорожки в видеоредакторе;

  10. Выполнить устранение чересстрочности, шумоподавление и коррекцию кривой в видеоредакторе (опционально).

Сравнение с классическими методами

Наконец, посмотрим, на что способен VHS‑Decode. В сравнении будут участвовать следующие подходы:

  • Любительский — магнитофон LG L494 → дешевый конвертер AV2HDMI → дешевая карта захвата для компьютера → запись через OBS. Стоимость такого комплекта без учета кабелей около 4 тысяч рублей;

  • Профессиональный — магнитофон Panasonic NV-HS 860 (TBC включено, а 3D DNR - нет) → передача по S-Video → карта захвата Canopus ADVC-300 → запись через Pinnacle Studio → устранение чересстрочности с помощью QTGMC → экспорт в FFV1. Стоимость такого комплекта без учета кабелей около 40 тысяч рублей;

  • Новый — магнитофон LG L494 → карта захвата видео на чипе Conexant CX23883-39 и карта захвата аудио Roland Rubix 22 → драйвер для Windows → обработка с помощью VHS-Decode 0.3.5 → устранение чересстрочности с помощью QTGMC → экспорт в FFV1 → временное шумоподавление и коррекция кривой в DaVinci Resolve → экспорт в FFV1. Стоимость такого комплекта без учета аудиокарты около 6 тысяч рублей. С минимально приемлемой аудиокартой комплект стоил бы около 10 тысяч рублей.

Сначала сравним качество изображения. На свежую кассету TDK был записан фильм Звонок 2002 года. Запись выполнена с цифрового исходника с разрешением 720x480 на магнитофоне Panasonic NV-HS830. Оцифруем первые 5 минут фильма разными методами и будем оценивать, насколько результат близок к оригиналу.

Для удобства я также подготовил стоп-кадры.

Кадр 1
Кадр 2
Кадр 3
Кадр 4

AV2HDMI, очевидно, занимает третье место. Причем проблема не в магнитофоне, так как даже в паре с продвинутым Panasonic NV-HS 820 качество не сильно лучше.

Разница между Canopus ADVC-300 и VHS-Decode не так очевидна, но она есть. Обратите внимание на цвет лица героини на втором кадре. Там, где классический метод увел все в зелень, VHS-Decode смог восстановить оттенки красного. Глядя на остальные кадры, мы также можем заметить это различие. Таким образом, VHS-Decode обеспечивает лучшую цветопередачу и уровень детализации.

Теперь сравним стабильность изображения. Возьмем кассету Fujifilm формата VHS-C, выпущенную в 1994 году, с записью 1998 года. Лента сохранилась плохо, и на ней есть проблемные места. Посмотрим, на сколько стабильна картинка при оцифровке разными способами.

Можно видеть, что при использовании VHS-Decode искажения минимальны. Однако, удивляет то, на сколько отличаются цвета при оцифровке разными методами.

Возможные аппаратные доработки

Я описал базовый набор оборудования для VHS-Decode. Как показано выше, этого достаточно для получения хорошего результата при работе с кассетами формата VHS. Однако существует ряд модификаций, которые могут улучшить качество оцифровки:

  • Установка усилителя между магнитофоном и картой захвата видео — сигнал, идущий от предусилителя магнитных головок, очень слаб, и его приходится усиливать перед оцифровкой. В карте АЦП есть встроенный усилитель, однако он вносит помехи. Предварительное усиление сигнала перед подачей в карту может улучшить отношение сигнала к шуму. Кроме того, это позволит увеличить длину кабеля, идущего от магнитофона к компьютеру;

  • Увеличение частоты АЦП — изначально карта захвата видео работает на частоте 28.6МГц, однако, если заменить кварцевый резонатор, можно разогнать ее до 40МГц и выше. При этом микросхемы будут выделять больше тепла, а значит на них желательно установить радиатор. Данная модификация может повысить отношение сигнала к шуму, а также улучшить качество оцифровки форматов, более сложных чем VHS, например S-VHS;

  • Установка второй карты захвата для оцифровки Hi-Fi аудио — зачастую кассеты формата VHS содержат Hi-Fi звук. Такое аудио кодируется схожим образом, что и видео и считывается отдельной головкой. Тогда можно припаять к магнитофону еще один провод и установить в компьютер еще одну карту захвата, чтобы оцифровывать в высоком качестве не только видео, но и звук. В VHS-Decode есть ряд утилит для декодирования аудио;

  • Тактирование карт захвата одним генератором — развитие предыдущей модификации. Как говорилось в одном из прошлых разделов, частота любого тактового генератора всегда немного отличается от теоретического значения. Из-за этого оцифрованная аудиодорожка будет воспроизводиться чуть быстрее или чуть медленнее оцифрованного видео, и за час может набегать до 5 секунд расхождения. Мы научились компенсировать этот эффект с помощью скрипта sync audio.bat, но, если хочется решить проблему окончательно, можно установить общий тактовый генератор для двух карт захвата.

Недостатки VHS-Decode

Помимо преимуществ у VHS-Decode есть два недостатка, с которыми вы неизбежно столкнетесь, если решите попробовать этот метод.

Во-первых, сырые данные, полученные с кассеты, занимают много места на диске. Так, для часа видео файл capture.u8 будет весить около 96ГБ, decoded.tbc и decoded_chroma.tbc — по 117ГБ, а decoded.mkv - еще 43ГБ . Итого около 373ГБ без учета аудио. Проблему можно немного сгладить, сжав сырые данные без потерь

"C:\Program Files\flac\flac.exe" -f capture.u8 --threads 64 --best --sample-rate=28636 --sign=unsigned --channels=1 --endian=little --bps=8 capture.flac

и удалив исходник. Это уменьшит суммарный размер до 333ГБ, что все равно прилично.

Во-вторых, на момент написания статьи декодирование сырых данных утилитой decode занимает очень много времени. Так, расшифровка часовой записи занимает около 12 часов на процессоре Ryzen 7 7700. При этом по ходу обработки процесс замедляется с 8 кадров в секунду до 1. Кроме того, увеличение количества потоков может не ускорить, а замедлить процесс. Авторы программы знают о проблеме и признают, что код написан неоптимальным образом, однако пока что не нашлось желающих переписать его. Хочется верить, что однажды это будет сделано.

Замедление при обработке четырехчасовой кассеты (картинка из сети)
Замедление при обработке четырехчасовой кассеты (картинка из сети)
Зависимость производительности от количества потоков (картинка из сети)
Зависимость производительности от количества потоков (картинка из сети)

Вывод

При оцифровке кассет формата VHS проект VHS-Decode позволяет получить превосходный результат при минимальных финансовых затратах. Кроме того, с годами по мере выхода из строя продвинутых магнитофонов с функцией TBC он может стать единственным профессиональным методом оцифровки аналогового видео. Не стоит забывать и о том, что помимо VHS проект поддерживает множество других носителей.

Однако, на данный момент первичная подготовка для оцифровки этим методом может представлять трудности для неподготовленного человека. Также в нынешнем виде VHS-Decode непригоден для быстрой обработки большого количества кассет. В том числе в коммерческих целях.

Таким образом, по моему мнению сейчас VHS-Decode может представлять интерес для энтузиастов, стремящихся получить видео максимального качества без оглядки на временные затраты. Но проект развивается, а значит можно ждать изменений к лучшему в будущем.

Айсберг оцифровки видео (более полный)
Айсберг оцифровки видео (более полный)

P.S.

Хочу выразить благодарность Алексею за помощь в модификации магнитофона и Павлу за запись тестовой кассеты и оцифровку на профессиональном оборудовании.

Если у вас возникли вопросы по VHS-Decode, вы можете задать их в комментариях или написать мне в Telegram @kuprin2000.

Комментарии (128)


  1. Vivado_man
    06.07.2025 20:31

    “оцифровывать его с высокой частотой простым ЦАП” - дальше читать не стал.


    1. YegorP
      06.07.2025 20:31

      Стоило дочитать хотя бы до того места, где упоминается вполне доступный ЦАП:

      Карта видеозахвата формата PCIe 1x на основе чипа Conexant CX2388x, как на картинке ниже. Такую карточку можно найти по запросу «карта видеозахвата 640x480» на Ozon или Aliexpress. Стоить она будет около 1700 рублей.


      1. Vivado_man
        06.07.2025 20:31

        ЦАП не оцифровывает. Оцифровывает АЦП.


        1. AndrewKuprin Автор
          06.07.2025 20:31

          Исправил это опечатку, спасибо


      1. gena_k
        06.07.2025 20:31

        Кто-то уже нашёл за 1700 руб - поделитесь пожалуйста? За 1700 удалось встретить только на чипе Conexant fusion 878a с мостом PCIe-PCI, а она плохо подходит для оцифровки из-за неотключаемого смещения уровня под уровень чёрного и выключения АЦП во время обратного хода развёртки.


        1. r3dfx
          06.07.2025 20:31

          Я покупал около полугода назад за 2200 с али, она ехала ко мне через всю Росиию... За 1700р нигде не видел)


  1. r3dfx
    06.07.2025 20:31

    А у вас всё хорошо с цветом без использования amplifyer? Кстати, кварц 40МГц даёт лучшую картину по искажениям (если не изменяет память)
    UPD: а зачем вы используете флаги nld и ire0_adjust?


    1. AndrewKuprin Автор
      06.07.2025 20:31

      Без промежуточного усилителя отношение сигнала к шуму на кассете со звонком около 36дБ, а это вроде бы неплохо. Но это отношение может зависеть от магнитофона, поэтому что у разных магнитофонов разная амплитуда сигнала на тестовом контакте. Возможно, вам не повезло.

      Вы пробовали 40МГц? Я попробовал заменить кварц, но у меня почему-то не завелось, и я вернул все, как было. Как я понимаю, 40МГц нужно скорее для S-VHS, а для обычного VHS хватит и стандартной частоты.

      Я не использую флаг nld, потому что он пока что экспериментальный. А флаг ire0_adjust использую, потому что его настоятельно советуют разработчики. И действительно цвета становятся более приятными. В вики VHS-Decode пишут

      Automatically adjust the black level on a per-field basis, using the back porch level. Unlike --clamp this is done after time base correction. Therefore it can fix the per-field variations caused by the slight carrier shift of VHS-HQ and S-VHS. (more info)

      сначала меня смутили слова про VHS-HQ и S-VHS, но потом мне обьяснили, что этот аргумент полезен для всех форматов. Обещали исправить формулировку в вики


      1. r3dfx
        06.07.2025 20:31

        Спасибо за ответ. У меня заработал буквально первый попавшийся китайский кварц :) Если хотите, могу скинуть ссылку на лот.

        Суть предварительного усилителя не в том, чтобы увеличить отношение С/Ш (это вторично), а согласовать импедансы. Не знаю как у вас, но в моём случае видаку не очень приятно работать в нагрузку 75Ом, которую внезапно прицепили на выход, поэтому на выходе присутствуют ромбовидные артефакты... Я сперва думал что это проникновение цвета в канал яркости (но откуда ему взяться при декодировании?), потом оказалось что это типовая проблема, которая решается только установкой полноценного преда и подбором нагрузки на его стороне

        В вики чётко не прописано, но с этими картами категорически не стоит использовать любые частоты дискретизации кроме частоты тактирования. Это связано с появлением отражений (aliasing)...

        Для ускорения можно было сделать даунсэмплинг через SOX к 18MSps и "убрать" один бит, т.к. отношение С/Ш позволяет.

        С 0ire у меня были опасения что будут видны мгновенные изменения в цветах поля. Надо будет попробовать самому... nld у вас был на скрине с графиком скорости, поэтому я про него и написал)


        1. AndrewKuprin Автор
          06.07.2025 20:31

          Наверное пока что мне не нужен другой кварц. Для целей оцифровки семейных кассет стандартной частоты хватает.

          Я не сталкивался с артефактами, поэтому не могу ничего сказать о вашей ситуации. Возможно, в вашем случае действительно не обойтись без усилителя. Видел на алиэкспресс варианты, которые могут подойти.

          Для ускорения можно было сделать даунсэмплинг....

          Это предложение, как можно ускорить работу Decode? Уменьшить частоту дискретизации до 18МГц, а затем запустить decode с аргументом --no_resample ? Вы пробовали так делать? Это дает прирост скорости? И есть ли при этом заметная потеря качества?

          ... nld у вас был на скрине...

          Это не мой скрин :) Под ним написано, что картинка взята из сети. Если конкретно, то это замеры одного из участников чата VHS-Decode в Discord


          1. r3dfx
            06.07.2025 20:31

            Вы немного не поняли части про ускорение: вы всегда захватываете с частотой дискретизации Х1 от тактирующей, а потом делаете даунсэмплинг. 40 МГц лучше не потому что полоса выше, а потому что АЦП имеет меньшие искажения (по сравнению со стоковыми 28 МГц)...

            Уменьшить частоту дискретизации до 18МГц, а затем запустить decode с аргументом --no_resample ? Вы пробовали так делать? Это дает прирост скорости? И есть ли при этом заметная потеря качества?

            Я думал вы читали вики 0_0. Можно даже отбросить 1 бит, т.к. 7 бит дают ДД в 42дБ, что покрывает почти все записи с VHS... Если вы цифровали архив, можно было даже использовать use_saved_levels т.к. источник записи одинаковый. Я догонял скорость на R7 3700X почти до 8fps на малом отрезке

            Видел на алиэкспресс варианты, которые могут подойти.

            Я на днях закажу у Гарри платы clockgen и собранный amplifyer, а то что на али, не позволит настроить сопротивление на входе...

            Это не мой скрин :) Под ним написано, что картинка взята из сети

            Лисичка не читатель

            Вообще странно что в статье не показана работа с ld-analyse, а ведь в него необходимо залезать для правильной настройки вывода


            1. AndrewKuprin Автор
              06.07.2025 20:31

              После того, как у меня не завелся кварц на 40МГц, я не особо копал в сторону нестандартных частот. Также я не храню сырые данные, поэтому пропустил разделы про сжатие файлов. Не подумал, это может быть полезно для ускорения декодирования.

              Я понимаю, что вы имеете в виду. Семплирование с частотой X1, ресемплинг из файла в файл с понижением частоты дискретизации, отбрасывание одного бита, деродирова6ние с no_resample. При этом процесс декодирования укоряется где-то в 1.5-2 раза? И видимой потери качества нет, верно?

              Я на днях закажу у Гарри платы clockgen и собранный amplifyer, а то что на али, не позволит настроить сопротивление на входе...

              Ох, вы находитесь в России? Если да, то можно скооперироваться с вами и заказать два усилителя?


        1. Javian
          06.07.2025 20:31

          Кстати недавно видел описание как работают РЭБ для Дронов - они сигнал модулируют частотой 32768 и это сводит с ума электронику.


  1. SpbDev58
    06.07.2025 20:31

    Если рандомно соединять проводом два устройства 220 вольт, то кого-нибудь может убить током и оцифровка будет идти уже без вас...


    1. Oangai
      06.07.2025 20:31

      не знаю за что минусуют, замечание вполне уместное, думать нужно про такие вещи. Но с конкретно видеомагнитофонами это не опасно, у них обычно корпус не заземлён и гальваническая развязка качественная.


    1. alcotel
      06.07.2025 20:31

      Вас долбануло, когда вы USB-принтер к компу подключали?

      Магнитофон штатно подключается к аудио-системе, которая тоже ест 220 В от соседней розетки. И к телевизору той эпохи, в котором на кинескоп вообще 25000 В подаётся. И если это всё нечаянно не заливать смузи пивом, оно нормально работает и током не шарахает.


      1. SpbDev58
        06.07.2025 20:31

        Я 43 года занимаюсь электроникой и сжег уже достаточно техники (компьютеры, принтеры, телевизоры и пр.). Вы путаете внешние интерфейсы, которые конечно имеют гальваническую развязку и пр. защитные механизмы и припаиные сопли (даже через конденсатор за 3 рубля) ВНУТРЬ устройства, на который у вас нет достоверной информации об особенностях работы или питания. 85% что оно сгорит, может быть даже не сегодня. Надеяться что вы сделаете лучше чем это сделали в Panasonice как бы совсем наивно. Кстати магнитных головок в видеомагнитофоне как минимум 4. К какой там автор хотел подпаяться?


        1. alcotel
          06.07.2025 20:31

          Я, конечно, извиняюсь за резкость. Но защиту интерфейсов бытовых устройств не стоит переоценивать. Чаще всего на штатных входах/выходах защиты нет никакой, кроме встроенных в любой усилитель паразитных диодов. Гальвано-развязка трансформатором от сети есть, и на том спасибо)))

          Наверное, стоило бы добавить последовательный резистор 75 Ом, чтобы согласовать с кабелем и АЦП, и заодно помочь этим самым диодам в борьбе за выживание. Но для разового мероприятия это лишнее.

          Кстати магнитных головок в видеомагнитофоне как минимум 4. К какой там автор хотел подпаяться?

          Тут пишут, что к двум видео-головам после преампа и коммутатора. Сигнал со звуковой головы пишут на звуковую карту. А синхро-голова, оказывается, только самому магнитофону нужна, а при обработке - нет.


  1. Sap_ru
    06.07.2025 20:31

    Извините, но ЧТО ВЫ НЕСЁТЕ?!!
    "RF" это же ни разу не с "видео головки"! Это же "Radio Frequency"! Это самые что ни на есть "обычный" видеосигнал! Вы его спокойно можете найти на разъёме ЛЮБОГО (совершенного любого) видеомагнитофона! Это уже сигнал с головки, сто раз обработанный и преобразованный к какому-то стандарту! Иногда через двойное преобразование (смотря, что у вас за магнитофон и кто и как писал). С потерей информации, между прочим. Его же (этот бедный видео-сигнал, который вы мучаете) сначала сняли с головки, потом декодировали, преобразовали во что-то, потом промодулировали, а вы его теперь демодулируете и декодируете. Причём однозначно криво (что у вас с шумами?!) и с недостаточной полосой пропускания (т.е. мыло у вас сразу с первых шагов заложено). Куча сил угрохана с совершенно сомнительным результатом.
    Есть хочется по-настоящему декодировать VHS с целью сохранить архив, то сигнал нужно брать RGB+Sync (ну, или хотя бы RGB) с разъёма SCART - и вот тогда будет картинка с минимумом искажений, которую ещё и проще всего обработать. Причём самая кривая китайская карта, которая может его оцифровывать, при записи в MPEG2 даст результат принципиально лучше того, что вы получили или можете получить.

    И вы, главное, не задумайтесь, во что это всё кодировать для своего архива, и что именно происходит с interlaced видео в подавляющем большинстве кодеков, а то с таким энтузиазмом...

    P.S. Ах, да. Вас там (у вас на экране) не смущает надпись про 576 строк при 25 (!!!) кадрах. Вы же, наверное, слышали, что когда очень давно, во времена VHS, телевидение работало с частотой кадров 50 или 60 герц? Всё ещё ничего не смущает?
    Архивы, говорите, сохраняете? За качество боретесь? Разные варианты по качеству (!!!!) сравниваете?! Ну-ну :)))))


    1. r3dfx
      06.07.2025 20:31

      Вы не разобрались совсем, а наезжаете на автора... Речь не про антенный разъём, а сигнал с голов. И он RF, т.к. частоты соответствующие


      1. Sap_ru
        06.07.2025 20:31

        Зачем?! Чтобы что? А частотная компенсация, которая у каждой головки и даже у каждого магнитофона своя? Он же её просто "от балды" пытается угадать. А обратная связь от вращения головки? Без неё можно работать, но зачем? А то, что он своим подключением ещё и поломал всю эту компенсацию и теперь восстановить нормальную картинку ( на уровне того, что магнитофон через SCART выдаёт) из этого будет практически невозможно?
        А то, что он рассказывает про качество, а у него полоса недостаточная и про чередование строк он "забыл"?


        1. r3dfx
          06.07.2025 20:31

          Почему это полоса недостаточная?) Для VHS нужно порядка 5.5МГц, мы даже не учитываем потери при перезаписях
          Чередование строк тоже на месте, в статье же 50i... Каждый кадр - это 2 поля
          Вы хоть раз видели захват со свистка в MPEG2? Я видел и внезапно(!), разница с vhs decode, мягко говоря, приличная


          1. ldmi
            06.07.2025 20:31

            Меня и Beholder TV H8 + iuVCS устраивает. А всякие пост-обработки на современном железе - это уже вжух! и готово.

            а раньше да - дернул мышкой и рассинхрон )))


            1. r3dfx
              06.07.2025 20:31

              Так статья не про вас :)

              Decode позволяет вытянуть "мёртвые" ленты и крайне нестабильные источники. Автор правильно написал, это не метод для сгона сотен лент (к тому же полноценной поддержки SECAM пока нет), это инструмент для оцифровки единичных архивов, обладающий максимальной гибкостью (вплоть до настройки фильтров вручную)


              1. SADKO
                06.07.2025 20:31

                Для вытягивания мертвых лен нужна избыточность, а тут ей и не пахнет. Хотя софтина, наверное, позволяет, иначе просто нет смысла огород городить, тк он не лучше TBS.

                ...я когда-то использовал подобный подход, но у меня была более глубокая модификация видеомагнитофона, который, по сути, превращался в сканер.


        1. sim2q
          06.07.2025 20:31

          Спокойствие, только спокойствие!)
          Кто увидел земляную петлю с оплётки из МГТФ и так всё понял :)


          1. alcotel
            06.07.2025 20:31

            А что тут такого? В полосе 5-6 МГц этот кусок провода - слону дробинка. В самом магнитофоне от головы к схеме идёт провод ещё длиннее. А тут скорее всего не с головы сигнал снят, а скорее, с предусилителя.

            Гораздо важнее, что нет настоящей петли по заземлению - через провод питания. У магнитофонов, слава богу, заземление в шнуре питания не предусмотрено.


    1. Fagear
      06.07.2025 20:31

      Действительно, что ВЫ несёте? Полное непонимание происходящего как минимум :)


      1. zatim
        06.07.2025 20:31

        Ну, скажем так, если бы я чуть менее глубоко разбирался в электронике и аналоговой видеозаписи, из текста статьи я бы тоже ничего не понял. Что откуда берется, почему и зачем. К сожалению, автор не потрудился осветить этот момент подробнее.


    1. iliasam
      06.07.2025 20:31

      Судя по вот этой картинке, там действительно берут усиленный сигнал прямо с головки: https://raw.githubusercontent.com/wiki/oyvindln/vhs-decode/assets/images/graphics/Laymans-Diagrams-FM-RF-Archival-%26-Decoding-Light-Current.png


  1. inkelyad
    06.07.2025 20:31

    Вопрос дилетанта. А если взять все эти разнообразные SDR приёмники, втыкаемые в USB качестве средства оцифровки этого самого сигнала вместо карты видеозахвата - результат каким будет? Они, вообще, справятся или по характеристикам не подойдут?


    1. r3dfx
      06.07.2025 20:31

      Их полосы хватает на захват Hi-Fi сигнала (декодирование Hi-Fi вроде смогли сделать быстрее realtime). Можете почитать в вики vhs decode про разные варианты АЦП


      1. inkelyad
        06.07.2025 20:31

        Ага. Понятно.

        Но странно, что они другие варианты не пробовали. RTL-SDR -- это самый дешевый и самый паршивый вариант. Уже давно есть лишь немногим дороже но с лучшими параметрами.


        1. r3dfx
          06.07.2025 20:31

          Там вариантов немного, т.к. без доп. преда, 50 Ом на входе большинства АЦП сделают их по сути одинаково бесполезными)
          Под эти CX чипы написан драйвер под Linux (недавно был порт на Win, но в тестовом режиме) плюс они стоят буквально копейки по сравнению с "полноценными" устройствами...
          В целом никто не запрещает юзать что-то другое, просто здесь "каноничный" вариант, который обкатан и работает


        1. NutsUnderline
          06.07.2025 20:31

          так там цена такая что canopus выйдет проще и без заморочек. Плюс еще понять надо что делать с iq потоком или как получить сырой поток с АЦП

          они и со звуком то мудрят нехило так https://github.com/oyvindln/vhs-decode/wiki/RTLSDR


    1. alcotel
      06.07.2025 20:31

      Как уже сказали, полосы сигнала не хватает. У DVB, под которую USB-свистки заточены, полоса сигнала меньше, чем у аналогового видео с кассеты.

      Второй момент - многие из этих свистков оцифровывают сигнал на промежуточной частоте, типа 10 МГц, а не от 0 Гц. Соответственно, если оцифровывать без суровых танцев с аппаратным бубном, придётся из видео-магнитофона брать сигнал с антенного выхода. А он уже точно по качеству не лучше штатного видео-выхода.


  1. avasiukevich
    06.07.2025 20:31

    Я как-то лет 10 назад, когда учился в универе, занялся оцифровкой домашнего архива VHS

    Денег у студентов конечно же нет, поэтому был выбран бюджетный вариант: куплена самая стандартная карта захвата (вроде бы от beholder), использовался её же софт для захвата видео (без компрессии), VHS магнитофон взят из дома (panasonic из 90х)

    Самой большой проблемой была десинхронизация аудио и видео при захвате, получилось её побороть захватом в ASF контейнер, который сохраняет синхронизацию за счет поддержки variable frame rate VFR (метод был прочитан на каком-то форуме). Потом VFR ASF перегонялся в CFR AVI (25 кадров в секунду) через mencoder.

    Минимальная обработка (убрать шумы, обрезать мусор по краям и т д) делалась через avisynth. Цель: убрать неразличимые глазом шумы, чтобы снизить размер сжатого файла, минимально улучшить картинку.

    Деинтерлейсинг я в итоге не стал делать, так как ни один доступный мне тогда деинтерлейсер не показал достойное качество, все мазали картинку. Решено было сохранить оригинальную чересстрочную картинку. Её было комфортно и так смотреть, а при необходимости деинтерлейсинг всегда можно включить непосредственно в плеере

    Конечный результат кодировался в x264 и сохранялся в MKV. Аудио тривиально кодировалось из несжатого CFR AVI в m4a используя ffmpeg и тоже добавлялось в MKV

    Весь пайплайн был автоматизирован скриптом и выглядел как-то так: VFR ASF -> mencoder -> CFR AVI -> avisynth -> x264 -> MKV.

    Запись одной кассеты занимала часа 3, последующая конвертация еще часов 10. Можно было параллелить это и одновременно записывать на одном компе и конвертировать на другом. Исходный несжатый ASF файл для трехчасовой кассеты занимал 90GB, финальный MKV 4-7 GB. Качество получалось идентично тому, что видно на экране в лайве, артефакты компрессии глазу не видны совсем.

    Получился в итоге довольно интересный студенческий проект на лето, было интересно поэкспериментировать с технологиями видеозаписи и видеокомпрессии.


    1. kvk-2019
      06.07.2025 20:31

      Тоже как-то оцифровывал подобным образом. С шестиголовочного магнитофона захватывал YPbPr сигнал бехолдером 8 (PCI-e 1x). Насколько помню, пришел также в конце концов к захвату в lossless ASF, при записи вручную подстраивал фильтры (нужно было для лучшего качества смотреть на изменение картинки), деинтерлейс делал "на лету" (из всех вариантов, доступных на сайте, был один более или менее подходящий по качеству, как мне показалось), критичной при этом была нагрузка на процессор, настройки фильтров подбирались в том числе исходя из этого. Потом конвертировал ffmpeg в x264 -crf 18. Сейчас, правда при необходимости перекодирую видео видеокартой Nvidia - это намного быстрее, качество вполне устраивает. А в начале захватывал в AVI. Видео со звуком всегда расходилось при этом, причём, насколько помню каждый раз по-разному. Даже скрипт для корректировки расхождения на пайтоне написал исходя из предположения о линейной зависимости, пока не пришёл к описанному выше варианту.

      Скрипт: VirtualDub.py
      #! python3.5
      
      import bisect
      import os
      import re
      import subprocess
      import sys
      import threading
      import tkinter
      from tkinter import ttk
      import win32api
      import win32com.client
      import win32con
      import win32console
      import win32gui
      
      import mylib
      
      
      class Application(ttk.Frame):
          def __init__(self, master=None):
              global padx, pady
              super().__init__(master)
              master.title(os.path.split(sys.argv[0])[1])
              master.resizable(False, False)
              
              # Определим размер шрифта для расчета горизонтальных и вертикальных отступов
              ttk.Style().configure("TLabel", font=font)
              self.label = ttk.Label(self, text="0" * 2)
              self.label.pack()
              padx = self.label.winfo_reqwidth()
              pady = self.label.winfo_reqheight()
              self.label["text"] = self.label["text"][0]
              padx -= self.label.winfo_reqwidth()
              self.label.destroy()
              del self.label
              
              self.correction_value = tkinter.IntVar()
              self.correction_value.set(1100)
              self.correction_focused = None
              self.sign_factor = -1
              self.correction0_value = tkinter.IntVar()
              self.correction0_value.set(0)
              self.sign0_factor = -1
              self.correction0_focused = None
              self.saved_value = None
              self.grid()
              self.createWidgets()
          
          def update_application_window(self):
              if root.wm_state() == "withdrawn":
                  x = (root.winfo_screenwidth() - root.winfo_reqwidth()) // 2
                  y = (root.winfo_screenheight() - root.winfo_reqheight()) // 2
                  root.wm_geometry("+{0:d}+{1:d}".format(x, y))
                  root.deiconify()  # Делаем видимым основное окно
              
              for suffix in ("", "0"):
                  correction = getattr(self, "correction{0}".format(suffix))
                  correction_focused = "focus" in correction.state()
                  if correction_focused and not getattr(self, "correction{0}_focused".format(suffix)):
                      correction.select_range(0, "end")
                  setattr(self, "correction{0}_focused".format(suffix), correction_focused)
              
              state = "disabled" if self.correction_value.get() == self.correction0_value.get() else "normal"
              self.hour["state"] = self.minute["state"] = (state, )
              
              self.update_idletasks()
              self.update()
              self.after(100, self.update_application_window)
          
          def change_sign(self, widget):
              def factor():
                  return "sign{0}_factor".format("0" if correction0 else "")
              correction0 = self.nametowidget(widget) in (self.correction0, self.sign0_button)
              setattr(self, factor(), -getattr(self, factor()))
              button = getattr(self, "sign{0}_button".format("0" if correction0 else ""))
              button["text"] = "-" if getattr(self, factor()) < 0 else "+"
          
          def key_return(self, event):
              if event.widget == self.run_button:
                  self.run()
              else:
                  event.widget.tk_focusNext().focus()
                  next_widget = root.focus_get()
                  if next_widget == self.sign0_button:
                      next_widget.tk_focusNext().focus()
                      next_widget = root.focus_get()
                  if next_widget in (self.correction, self.correction0, self.hour, self.minute):
                      next_widget.select_range(0, "end")
          
          def validate_correction(self, widget, data, action):
              correction0 = self.nametowidget(widget) == self.correction0
              value = getattr(self, "correction{0}_value".format("0" if correction0 else ""))
              other_value = getattr(self, "correction{0}_value".format("" if correction0 else "0"))
              entry = getattr(self, "correction{0}".format("0" if correction0 else ""))
              valid = re.match(r'^\d+$', data) is not None
              if action == '0':
                  self.saved_value = value.get()
              elif action == '1':
                  if not valid:
                      try:
                          value.get()
                      except Exception:
                          value.set(self.saved_value)
                          entry.select_range(0, "end")
                      if data in "-+":
                          self.change_sign(widget)
                      elif data == " ":
                          other_value.set(value.get())
                          entry.select_range(0, "end")
              else:
                  return False
              return valid
          
          def validate_time(self, widget, new_value, data, action):
              def process_widget(name, max_value):
                  widget = getattr(self, name)
                  if widget.get() == '':
                      widget.set(self.saved_value)
                      widget.select_range(0, "end")
                  if data == "-":
                      widget.set(str(max(0, int(widget.get()) - 1)))
                  elif data == "+":
                      widget.set(str(min(max_value, int(widget.get()) + 1)))
              
              if action == '0':
                  self.saved_value = self.nametowidget(widget).get()
                  return True
              elif action == '1':
                  if widget == str(self.hour):
                      valid = re.match(r'^\d$', new_value) is not None
                      if not valid:
                          process_widget('hour', 9)
                  elif widget == str(self.minute):
                      valid = re.match(r'^[0-5]?\d$', new_value) is not None
                      if not valid:
                          process_widget('minute', 59)
              else:
                  return False
              return valid
          
          def run(self, event=None):
              config = """VirtualDub.audio.SetSource(1);
      VirtualDub.audio.SetMode(1);
      VirtualDub.audio.SetInterleave(1,500,1,0,{2});
      VirtualDub.audio.SetClipMode(1,1);
      VirtualDub.audio.SetConversion(0,0,0,0,1);
      VirtualDub.audio.SetVolume();
      VirtualDub.audio.SetCompressionWithHint(8192,48000,2,0,32000,1024,"AC3ACM");
      VirtualDub.audio.EnableFilterGraph({0});
      VirtualDub.video.SetInputFormat(0);
      VirtualDub.video.SetOutputFormat(7);
      VirtualDub.video.SetMode(0);
      VirtualDub.video.SetSmartRendering(0);
      VirtualDub.video.SetPreserveEmptyFrames(0);
      VirtualDub.video.SetFrameRate2(0,0,1);
      VirtualDub.video.SetIVTC(0, 0, 0, 0);
      VirtualDub.video.SetCompression();
      VirtualDub.video.filters.Clear();
      VirtualDub.audio.filters.Clear();
      VirtualDub.audio.filters.Add("input");
      VirtualDub.audio.filters.Add("time stretch");
      VirtualDub.audio.filters.Connect(0, 0, 1, 0);
      VirtualDub.audio.filters.instance[1].SetDouble(0, {1:.8});
      VirtualDub.audio.filters.Add("output");
      VirtualDub.audio.filters.Connect(1, 0, 2, 0);
      """
              try:
                  correction = self.sign_factor * int(self.correction.get())
              except ValueError:
                  threading.Thread(target=mylib.MessageBox, args=('Не задана коррекция!',
                      win32con.MB_ICONEXCLAMATION, 5)).start()
                  return
              try:
                  correction0 = self.sign0_factor * int(self.correction0.get())
              except ValueError:
                  threading.Thread(target=mylib.MessageBox, args=('Не задана коррекция нуля!',
                      win32con.MB_ICONEXCLAMATION, 5)).start()
                  return
              try:
                  time_span = (int(self.hour.get()) * 60 + int(self.minute.get())) * 60
              except ValueError:
                  time_span = 0
              if not time_span:
                  threading.Thread(target=mylib.MessageBox, args=('Не задано время!',
                      win32con.MB_ICONEXCLAMATION, 5)).start()
                  return
              if not os.path.exists(PROGRAM):
                  threading.Thread(target=mylib.MessageBox, args=('Не обнаружен "{0}"!'.format(PROGRAM),
                      win32con.MB_ICONEXCLAMATION, 5)).start()
                  return
              correction -= correction0
              if not correction:
                  config = re.sub(r'^.*\.audio\.filters\.(?!Clear).*$', '', config, flags=re.MULTILINE).rstrip()
              factor = 1.0 + correction / 1000 / time_span
              with open(CONFIG_NAME, "w") as config_file:
                  config_file.write(config.format(1 if correction else 0, factor, correction0))
              subprocess.Popen('"' + PROGRAM + '" /s "{0}"'.format(CONFIG_NAME))
              self.quit()
          
          def createWidgets(self):
              self.config(padding=(padx, int(pady/4)))
          
              style = ttk.Style()
              style.configure("TLabel", font=font)
              style.configure("TButton", font=font)
              style.configure("C.TButton", font=font, foreground="red")
              style.configure("TCombobox", font=font)
              style.configure("TRadiobutton", font=font)
              
              root.bind('<Key-Return>', self.key_return)
              root.bind('<Control-Key-Return>', self.run)
              
              row = 0
              self.header = ttk.Label(self, text="Задай коррекцию и время")
              self.header.grid(row=row, column=0, columnspan=4)
              row += 1
              self.correction_label = ttk.Label(self, text="Коррекция(ms)*:")
              self.correction_label.grid(row=row, column=0, sticky="e")
              self.clear_button = ttk.Button(self, text="C", width=1, style="C.TButton")
              self.clear_button["command"] = lambda:self.correction_value.set(0)
              self.clear_button.grid(row=row, column=1)
              self.sign_button = ttk.Button(self, text="-", width=1)
              self.sign_button["command"] = (self.register(self.change_sign), self.sign_button)
              self.sign_button.grid(row=row, column=2)
              self.correction = ttk.Entry(self, width=5, textvariable=self.correction_value, validate="key",
                  validatecommand=(self.register(self.validate_correction), '%W', '%S', '%d'))
              self.correction.grid(row=row, column=3)
              self.correction.focus()
              row += 1
              self.correction0_label = ttk.Label(self, text="Коррекция нуля(ms)*:")
              self.correction0_label.grid(row=row, column=0, columnspan=2, sticky="e")
              self.sign0_button = ttk.Button(self, text="-", width=1)
              self.sign0_button["command"] = (self.register(self.change_sign), self.sign0_button)
              self.sign0_button.grid(row=row, column=2)
              self.correction0 = ttk.Entry(self, width=5, textvariable=self.correction0_value, validate="key",
                  validatecommand=(self.register(self.validate_correction), '%W', '%S', '%d'))
              self.correction0.grid(row=row, column=3)
              row += 1
              self.time_label = ttk.Label(self, text="Время(h:mm):")
              self.time_label.grid(row=row, column=0, sticky="e")
              self.hour = ttk.Combobox(self, width=1, validate="key",
                  validatecommand=(self.register(self.validate_time), '%W', '%P', '%S', '%d'))
              self.hour["values"] = list(map(lambda x:"{0}".format(x), range(10)))
              self.hour.current(0)
              self.hour.grid(row=row, column=1)
              self.sc1 = ttk.Label(self, text=":")
              self.sc1.grid(row=row, column=2)
              self.minute = ttk.Combobox(self, width=2, validate="key",
                  validatecommand=(self.register(self.validate_time), '%W', '%P', '%S', '%d'))
              self.minute["values"] = list(map(lambda x:"{0:>02}".format(x*5), range(12)))
              self.minute.current(10)
              self.minute.grid(row=row, column=3)
              row += 1
              self.space_label = ttk.Label(self, text="*Space-копировать")
              self.space_label.grid(row=row, column=0, sticky="w")
              self.run_button = ttk.Button(self, text="Запуск", width=8, command=self.run)
              self.run_button.grid(row=row, column=1, columnspan=3, pady=int(pady/4))
              
              self.after(100, self.update_application_window)
      
      
      if __name__ == "__main__":
          FOLDER = os.path.split(sys.argv[0])[0]
          PROGRAM = os.path.join(FOLDER, "VirtualDub.exe")
          CONFIG_NAME = os.path.join(FOLDER, "config.vcf")
          MONIKER = r"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2"
          SCRIPT_TITLE = os.path.split(sys.argv[0])[1]
          keep_output = False
          COMSPEC = os.getenv("comspec")
          if COMSPEC:  # Проверим на запуск в режиме сохраниеия вывода после завершения
              parent_process_moniker = (MONIKER + ":Win32_Process.Handle=" + str(os.getppid()))
              try:
                  for i in range(2):
                      parent_process = win32com.client.GetObject(parent_process_moniker)
                      keep_output += re.match('("?)' + COMSPEC.replace("\\", "\\\\").replace(".", "\\.") + '\\1\s+/[ck]\s+',
                          parent_process.CommandLine, re.IGNORECASE) is not None
                      parent_process_moniker = (MONIKER + ":Win32_Process.Handle=" + str(parent_process.ParentProcessId))
              except Exception:
                  pass
              finally:
                  parent_process = None
          
          main_hwnd = win32console.GetConsoleWindow()
          if main_hwnd:
              if win32api.GetConsoleTitle() != SCRIPT_TITLE:
                  win32api.SetConsoleTitle(SCRIPT_TITLE)
              if not keep_output:
                  win32gui.ShowWindow(main_hwnd, win32con.SW_HIDE)
          
          root = tkinter.Tk()
          root.withdraw()  # Скроем основное окно до прорисовки точно в центре экрана (делаем видимым методом update_application_window)
          
          # Важно! Шрифт моноширинный
          font_sizes = [(0, 8), (480, 10), (864, 12)]
          font = ("Lucida Console", font_sizes[bisect.bisect(font_sizes, 
              (root.winfo_screenheight(), float("inf"))) - 1][1], "normal")
          
          app = Application(master=root)
          app.mainloop()
          
          try:
              root.destroy()
          except tkinter.TclError:
              pass


      1. avasiukevich
        06.07.2025 20:31

        А в начале захватывал в AVI. Видео со звуком всегда расходилось при этом, причём, насколько помню каждый раз по-разному. Даже скрипт для корректировки расхождения на пайтоне написал исходя из предположения о линейной зависимости, пока не пришёл к описанному выше варианту.

        Да, я тоже пробовал аналогично корректировать рассинхрон, но такой линейный подход работал не всегда. В конце концов выяснил, что рассинхрон вызывали две независимые причины: (1) разные частоты аудио и видео; (2) дропы кадров, когда видеопоток прерывался

        И если с (1) линейная подгонка работала хорошо, то с (2) вообще никак не помогала.


  1. andrewilife
    06.07.2025 20:31

    Еще остались неразмагниченные кассеты?


    1. AndrewKuprin Автор
      06.07.2025 20:31

      Я работал с кассетами, которые содержат записи 1997-2006 года. Все кроме одной живы и здоровы


    1. alcotel
      06.07.2025 20:31

      Зависит от качества носителя и условий хранения. Тут вот товарищ, например, пишет, что не запись, а сам носитель может разваливаться в прах.

      Сейчас для долговременного хранения данных в ЦОД и архивах, на сколько я знаю, пользуются стриммерами, как и 50 лет назад - той же магнитной записью на плёнке. И на HDD в общем та же магнитная запись, и, если производитель не косячит, данные десятками лет хранятся без проблем.


  1. zatim
    06.07.2025 20:31

    Прикольная идея! Эх, ее бы мне увидеть лет 6 назад. Была у меня Электроника 590, развандаленная аффинажниками. Механика вся была на месте, а плат не было. И хотелось прочитать видеозапись с катушки. Для этого попытался подкинуть туда кишки от vhs, там форматы записи почти похожи. Но подружить их так и не вышло. А с этой программой могло бы и получиться.

    Кстати, интересный вопрос: как она разбирает сигнал на кадры? Если начало/конец строки можно вытащить из сигнала с БВГ, то кадровые синхроимпульсы идут с отдельной головки (объединенной со звуковой).


    1. HardWrMan
      06.07.2025 20:31

      Там не кадровая а синхронизирующая т.н. "трекинг". Причем 25 Гц. Смещение фазы этой частоты приводит к смешению траектории описываемой видеоголовками на ленте. А на саму голову пишется полноценный видеосигнал в FM кодировании со всеми служебными интервалами, поэтому он и называется RF. Разве что цветность может транскодироваться в другой формат (часто видеомагнитофон пишет всегда только в PAL или NTSC, но принимает любой, даже SECAM). Причем, так как головы 2 а обхват чуть более 180 градусов, то они работают по очереди, коммутатор находится непосредственно рядом с трансформатором БВГ вместе с усилителем. Технически, в статье снимают сигнал не с самой головы а после коммутатора-усилителя.


      1. zatim
        06.07.2025 20:31

        Там не кадровая а синхронизирующая 

        Не нужно придираться к терминологии без причины. Везде, в т.ч. и в википедии, пишут - кадровая.

        Вдоль нижнего края ленты записывается управляющая дорожка[6], содержащая кадровые синхроимпульсы[8]

        Тем более если знать, что то, что передается с частотой 50 Гц - это поле, при чересстрочной развертке кадр состоит из двух полей, четного и нечетного. Соответственно, кадры идут с частотой 25 Гц.


        1. HardWrMan
          06.07.2025 20:31

          Ещё раз: это не кадровая. Но она вынуждена быть таковой, потому что 1 проход 1 головы это одно поле. 2 прохода 2 голов это как раз 2 поля или 1 оборот барабана - 1 кадр черезстрочной развёртки. И эта синхронизация лишь частично-косвенно используется для восстановления настоящей кадровой синхронизации. Вот RPM БВГ как раз настоящая кадровая частота. И она держится стабильной даже при стоп-кадре, когда синхрочастота равна 0. Если бы бвло как пишут на этой вашей википедии то стопкадр был бы в принципе невозможен.

          А что там пишут и не дай Б-г модерируют на википедии давно уже всем известно.


          1. zatim
            06.07.2025 20:31

            А что там пишут и не дай Б-г модерируют на википедии давно уже всем известно.

            Там вообще то ссылка на журнал "Радио" за 1987 год. То есть, вы хотите сказать, что в журнале в 1987 году писали и модерировали неправильно?


            1. HardWrMan
              06.07.2025 20:31

              При всём авторитете журнала Радио (и моём личном уважении к нему) даже в нём бывают факапы. Если бы вы его читали как я, то знали бы про постоянную рубрику "По следам публикаций". Вон, ниже уточнили, что в ангельском разделе вики написано правильно.


              1. zatim
                06.07.2025 20:31

                Не вижу тут никаких факапов. Скорее тут у вас факап. Вы решили доколупаться до слов, но не вывезли. В английском варианте написано ровно то же самое, воспользуйтесь переводчиком.


                1. HardWrMan
                  06.07.2025 20:31

                  А давайте.

                  Another linear control track at the tape's lower edge holds pulses that mark the beginning of every frame of video; these are used to fine-tune the tape speed during playback, so that the high speed rotating heads remained exactly on their helical tracks rather than somewhere between two adjacent tracks (known as "tracking"). Since good tracking depends on precise distances between the rotating drum and the fixed control/audio head reading the linear tracks, which usually varies by a couple of micrometers between machines due to manufacturing tolerances, most VCRs offer tracking adjustment, either manual or automatic, to correct such mismatches.

                  Ну и? Где кадровая? Есть только "метка начала кадра". И при этом указано, для чего она там. Ещё раз: как возможен стопкадр или поиск вперёд/назад? Ну, как, если кадровая записана только в синхродороге?


                  1. zatim
                    06.07.2025 20:31

                    pulses that mark the beginning of every frame of video

                    Это что, по вашему? Смотрю в книгу, вижу фигу?


                    1. HardWrMan
                      06.07.2025 20:31

                      Метка != синхроимпульс. Ниже вам написал. Смиритесь уже вы, не вывозите вы в техчасть да что с того то? А про стопкадр и поиск вы так и не ответили.

                      A control track is a track that runs along an outside edge of a standard analog videotape (including VHS). The control track encodes a series of pulses, each pulse corresponding to the beginning of each frame. This allows the video tape player to synchronize its scan speed and tape speed to the speed of the recording. Thus, the recorded control track defines the speed of playback (e.g. SP, LP, EP, etc.), and it is also what drives the relative counter clock that most VCRs have.

                      Вот вам ещё про истинное назначение синхродороги. Заметьте - ни слова про видеосигнал!


                      1. zatim
                        06.07.2025 20:31

                        Что за бред вы несете. Синхроимпульс - он везде синхроимпульс. Если он начал выполнять другую функцию, он не перестал от этого быть синхроимпульсом.


                      1. HardWrMan
                        06.07.2025 20:31

                        Верно, но есть нюанс что именно он синхронизирует. Позицию головы на дорожке или луч кинескопа в телевизоре. Подумайте над этим на досуге.

                        The control track is used to fine-tune the tape speed during playback, so that the high speed rotating heads remained exactly on their helical tracks rather than somewhere between two adjacent tracks (known as "tracking"). Since good tracking depends on precise distances between the rotating drum and the fixed control/audio head reading the linear tracks, which usually varies by a couple of micrometers between machines due to manufacturing tolerances, most VCRs offer tracking adjustment, either manual or automatic, to correct such mismatches.


          1. ahabreader
            06.07.2025 20:31

            enwiki говорит про это поточнее:

            Tracking adjustment and index marking

            Another linear control track at the tape's lower edge holds pulses that mark the beginning of every frame of video; these are used to fine-tune the tape speed during playback...


            1. zatim
              06.07.2025 20:31

              pulses that mark the beginning of every frame of video

              Да нет, все то же самое. Воспользуйтесь переводчиком. Импульс, который обозначает начало каждого кадра - это (внезапно!) кадровый синхроимпульс.


              1. HardWrMan
                06.07.2025 20:31

                Ещё раз, чисто для вас:

                Each of the diagonal-angled tracks is a complete TV picture field, lasting 1⁄60 of a second (1⁄50 on PAL) on the display. One tape head records an entire picture field. The adjacent track, recorded by the second tape head, is another 1⁄60 or 1⁄50 of a second TV picture field, and so on. Thus one complete head rotation records an entire NTSC or PAL frame of two fields.

                Видеоголова пишем весь кадр целиком, со всеми синхроимпульсами. Точка. Синхродорога пишет сигнал, внезапно, синхронизации БВГ к этим дорожкам. Смиритесь уже с этим.


              1. ahabreader
                06.07.2025 20:31

                Ну, суть в том, что он не один такой. Для телевизора есть синхронизация в самом видеосигнале на наклонных дорожках - как строчный HBLANK остаётся на месте, так и кадровый VBLANK.

                Оффтоп: сейчас странновато смотреть, как в аналоге хранили невидимые части кадра, но тогда это была хорошая идея и в них потом дополнительную информацию пихали. Субтитры, телетекст, мини-настроечная таблица (ITU-T J.63), метаданные на LD...

                Про метаданные из IEC 60856-1986
                Про метаданные из IEC 60856-1986


                1. zatim
                  06.07.2025 20:31

                  строчный HBLANK остаётся на месте, так и кадровый VBLANK.

                  Это гасящие импульсы. Не путайте их с синхронизирующими.


                  1. ahabreader
                    06.07.2025 20:31

                    В радиоэфире других нет, так что телевизор обречён синхронизироваться по ним. По импульсам внутри импульсов, точнее. По синхронизирующим (vertical sync pulses) внутри гасящих (vertical blanking period).

                    https://www.ntsc-tv.com/ntsc-index-02.htm


            1. HardWrMan
              06.07.2025 20:31

              Вот это точнее. По синхродороге весь ЛПМ подстраивается под записанный контент, прямо как дисковод под отформатированный диск: скорость протягивания для правильного звука и фаза поворота БВГ для правильного трекинга (это фаза переключения между головами и продольное, по отношению к ленте, смещение "сканирования" головами нанесённых дорожек). При записи видеомагнитофон всё делает по внутренним опорным генераторам, подпёртыми кварцевыми резонаторами, а при воспроизведении полностью опирается на сигнал с ленты, сравнивая с эталоном только частоту синхросигнала для получения правильной высоты звука. Физически же при этом отклонение движения ленты может быть даже заметным на глаз - полоса ФАПЧ мотора капстана (тонвала) достаточно широкая. Я в бытность ремонта помню модифицировал свой ВМ12 так, что 3 часовая кассета вмещала 4 часа. При этом он без проблем воспроизводил и записи с других магнитофонов.


    1. ahabreader
      06.07.2025 20:31

      как она разбирает сигнал на кадры?

      На наклонных дорожках остаётся информация для этого (VBLANK, кадровый гасящий импульс). Теоретически её могли бы выкинуть для экономии места, но субтитры, защита Macrovision и стоп-кадр сообщают, что (все?) невидимые строки на месте.


      1. HardWrMan
        06.07.2025 20:31

        Ничего там не выкинуто, всё в наличии. Немного модифицировано, чтобы влезать в модуляцию, только и всего.


        1. ahabreader
          06.07.2025 20:31

          Такая экономия места (8-9%) ещё бы Hi-Fi Stereo сломала, если подумать.

          Но какие-то из невидимых строк должны быть сильно зашумлены в момент смены головок (head switching noise). Вот в книжке пишут, что пришлось постараться, чтобы дорожка Hi-Fi Stereo не щёлкала 50-60 раз в секунду.


          1. HardWrMan
            06.07.2025 20:31

            Ну да, угол HiFi при этом меняется, но о каком HiFi идёт речь в рамках ВМ12? Кассеты предназначались только для воспроизведения на нём же. HiFi и не требовалось, а вот Арвид радовался дополнительной ёмкости.


            1. ahabreader
              06.07.2025 20:31

              Я про саму теоретическую возможность с её теоретическими последствиями.

              И приправляю коммент тем, что не знаю, сколько там в норме шума в момент переключения и что там ещё теряется кроме фазы этого антисоветского FM-звука (допустим, сколько частей строки, если бы на ней хранилось что-то полезное).


              1. HardWrMan
                06.07.2025 20:31

                Вы не поняли. Я по сути сделал LP для ВМ12. Это влияло только на скорость протягивания ленты и, как итог, только на стандартную линейную аудиодорожку, как и в другом видеомагнитофоне со штатной функцией LP. А HiFi пишется головками на БВГ, с углом смещения 60 или 42 градуса. Смещение позволяет сдвинуть аудиодорожку относительно видеодорожки потому что плёнка движется непрерывно. Причём, HiFi магнитофоны с функцией LP в большинстве своём умеют писать HiFi даже на скорости LP. Ну а в тракте HiFi там сигнал/шум и частотный диапазон не зависят от скорости протягивания ленты потому что HiFi головки находятся на БВГ и их скорость перемещения стабильная и высокая.


  1. VBDUnit
    06.07.2025 20:31

    Эээ...

    Компонентный выход у магнитофона. Y - яркость, Cb - разница между ней и синим, Cr - между ней и красным. Гораздо качественнее композита, где всё по одному проводу
    Компонентный выход у магнитофона. Y - яркость, Cb - разница между ней и синим, Cr - между ней и красным. Гораздо качественнее композита, где всё по одному проводу
    1. Берём хороший бу живой магнитон типа JVC HM‑DH40 000U, который имеет выход Component (то есть три провода для трех каналов цвета — яркость и две цветоразностные)

    2. Берём карту захвата с компонентом типа Intensity

    3. Пихаем компонент сигнал в комп

    4. На стороне компа захватываем видеопоток в RAW без сжатия и без субдискретизации, можно в RGB

    5. Полученное сырьё реставрируем, цветокорим по вектороскопам/осциллоскопам чтобы вправить моск цветам как было. Доп обработка по вкусу, можно нейросетями и/или апскейлом

    6. Жмём в что‑нибудь с большим битрейтом или вообще в Loseless типа ProRes

    Если всё правильно сделать, качество будет максимальное, в прямом смысле: мы здесь на каждом этапе теряем минимум информации.

    Опционально можно всё или часть делать за один присест, если не гнать этот пайплайн через софт для монтажа, а сразу пропускать и синхронизировать RAW картинку через софт для видеомикширования (не буду показывать пальцем на Tesseract :) )

    Тогда сразу будет захватываться готовый результат.

    Аналоговый шум надо убирать

    Аналоговый шум алгоритмы сжатия видно часто воспринимают как детали картинки и пытаются их сохранить, выкидывая настоящие детали. В итоге к аналоговому шуму добавляется мыло и/или файл получается больше. Потому что оно искренне пытается сохранить каждую мурашку.

    Поэтому шумы лучше убирать (если не писать в RAW конечно). По этой же причине стоит 10 раз подумать, прежде чем добавлять художественный шум в видео, которое заливается в соц сети и телеграмы, где царит низкий битрейт.

    Упоротый вариант — подцепить АЦП к головке магнитофона. Но это, кхм, сопряжено некоторыми небольшими сложностями :)


    1. AndrewKuprin Автор
      06.07.2025 20:31

      Прочитайте вывод статьи. Я и не настаиваю на том, что это лучший метод. Ваш вариант вполне рабочий. Единственное, в чем VHS-Decode явно лучше других методов - это качество TBC (смотрите второе видео в статье). Ну и цена конечно.

      Наверное с точки зрения эффективности разумно было использовать хороший магнитофон и хорошую карту захвата как основной инструмент для оцифровки, а VHS-Decode как вариант для плохо сохранившихся кассет, которые встречаются не так часто.


      1. SADKO
        06.07.2025 20:31

        Да не будет у него лучше качество TBS, а на тянутых лентах даже хуже. Тк и то, и другое происходит в реальном времени, но интегрированный TBS работает в плотной связке с другими системами видеомагнитофона.

        Я не отрицаю такой подход более того сам в свое время подобное проворачивал, правда не для VHS, и не в реальном времени, и не только из-за проблем с производительностью. Смысл был в том, чтобы по сути сканировать плёнку, с большой избыточностью. Частота вращения барабана была постоянная и синхронизированная АЦП. А подача плёнки управлялась программно, по мере необходимости.


    1. HardWrMan
      06.07.2025 20:31

      Упоротый вариант — подцепить АЦП к головке магнитофона. Но это, кхм, сопряжено некоторыми небольшими сложностями :)

      Однако, это единственный правильный метод вытащить то, что по факту на носителе, исключая все артефакты постобработки конкретного аппарата. Точно так же работает декодирование RF с фотоприёмника LD проигрывателя. Вопрос лишь в целесообразности: насколько важен записанный контент. Есть очень много быстродействующих АЦП на 8-12 разрядов (до сотни МГц сэмплирования), есть хорошие и быстрые FPGA. Можно всё сделать даже ещё лучше, чем описано в статье, вопрос лишь в том, какая конечная цель преследуется.


      1. VBDUnit
        06.07.2025 20:31

        Более чем согласен. Но имхо это как из орбитального ядерного лазера по воробьям. Если воробей какой‑то особенный то норм, но в общем случае не надо :)

        много быстродействующих АЦП на 8–12 разрядов (до сотни МГц сэмплирования)

        Есть подозрение, что для качества этого мало, и надо не менее 1 ГГц. А так да.

        Для годноты можно ещё в FPGA параллельно завести питание через отдельный АЦП, чтобы если вдруг (ну вдруг) по нему наводятся помехи, то алгоритмы обработки были в курсе и могли через пару обработок вычесть из полезного сигнала.


        1. nafikovr
          06.07.2025 20:31

          так вроде в статье как раз и говорится что метод хорошо подходит для проблемных кассет, в отличии от записи с "бытовых" проигрывателей.


          1. HardWrMan
            06.07.2025 20:31

            Более того, если снять то, что по факту на ленте, причём если ещё и стабилизацию протягивания сделать внешнюю, то можно избавиться и от артефактов инертности ФАПЧ капстана и трекинга в целом, при потере сигнала в синхродорожке. А там время реагирования измеряется в секундах.

            Точка RF, кстати, используется при ремонте и настройке видеомагнитофона с помощью осциллографа, до получения стабильного равномерного сигнала от обеих голов. Например, вот так:

            Настраивается как механика (направляющие ролики и азимут самих кристаллов) так и электроника (средняя фаза автоматического трекинга). Поэтому, тестовая точка RF есть у каждого видеомагнитофона.


    1. LAutour
      06.07.2025 20:31

      Берём карту захвата с компонентом типа Intensity

      В обычных(начиная с гибридных, я так цеплялся к Beholder-T8) тв-тюнерах компонентные входы тоже встречались, включая поддержку RGB захвата.


    1. ahabreader
      06.07.2025 20:31

      Компонентный выход у магнитофона.
      Гораздо качественнее композита, где всё по одному проводу

      Если принимать это безусловно, можно оцифровку лазердиска испортить. Для него композит - родной формат и наилучший демодулятор вряд ли окажется в старом проигрывателе (а не на стороне приёмника сигнала - т.е. в карте захвата или софте ld-decode).

      В случае VHS родной формат на кассете похож на S-Video (цветность отделена от яркости и впихнута в полосу частот под яркостью - т.н. color-under) и компонентный выход (S-Video или YPbPr) позволит избежать лишнего объединения-разделения цветности и яркости, но ЕМНИП, люди не видели однозначного улучшения - полосы частот так порезаны при записи, что заметные артефакты от разделения не возникают.

      В S-VHS расширили полосу яркости, в композите она стала явно пересекаться с цветностью (=> артефакты разделения) и поэтому в видаки с поддержкой S-VHS добавили S-Video.

      YPbPr в этот видак поставили ради цифрового D-VHS*, HD-сигналу которого есть что терять и который не имел преступных связей с композитом. Ну и ради цифровой обработки (TBC, DNR), то есть ему бы вообще цифровой выход иметь, раз он всё через цифру прогоняет.

      Аналоговый шум надо убирать

      Сохранять плёночное зерно в 4K сейчас считается нормальным, а тут разрешение в 30 раз меньше и хранить шум слишком дорого? Нет, если шум маскирует нехватку деталей (улучшает субъективное качество), то пусть остаётся. Для видеохостингов SD-видео апскейлят, чтобы заставить их поднять битрейт (потому что это единственный переключатель качества со стороны пользователя, кнопки "576p/480p High Bitrate" у него нет).

      Упоротый вариант — подцепить АЦП к головке магнитофона. Но это, кхм, сопряжено некоторыми небольшими сложностями :)

      Вся статья про это - в видеомагнитофон залезли настолько глубоко, насколько есть смысл (предусилителю и штуке, которая сигналы с чередующихся головок объединяет, можно и довериться). Залезли в эту точку, получается:

      Figure 8.4.5 Block diagram of a color-under system из этой книжки
      Figure 8.4.5 Block diagram of a color-under system из этой книжки

      * Это видак 3-в-1 (VHS, S-VHS, D-VHS) и он до сих пор тыщу долларов стоит.


      1. HardWrMan
        06.07.2025 20:31

        Сохранять плёночное зерно в 4K сейчас считается нормальным

        Аналоговый шум работает как дизеринг. Он визуально (в случаях звука - аудиально) улучшает качество оцифровки на малых уровнях, когда битовая глубина исчерпывается.


        1. ahabreader
          06.07.2025 20:31

          Ну, я про другой, психологический, эффект говорил. Когда высокочастотное мельтешение не даёт чётко всмотреться и закричать при виде настоящего адского мыло-пластилина. Возможность совершенно ясно увидеть отсутствие деталей бывает неприятной и проявит остальные артефакты.


      1. VBDUnit
        06.07.2025 20:31

        Для видеохостингов SD-видео апскейлят, чтобы заставить их поднять битрейт (потому что это единственный переключатель качества со стороны пользователя, кнопки "576p/480p High Bitrate" у него нет).

        Абсолютно точно, именно для этого я в своё время доработал возможность апскейла в фильтры захвата и стрима. Жалко, что многие люди этот приём не используют.

        Сохранять плёночное зерно в 4K сейчас считается нормальным, а тут разрешение в 30 раз меньше и хранить шум слишком дорого?

        Дело не в дорого, можно, в конце концов, хранить/стримить в loseless или вообще в RAW. PNG/EXR сиквенсы + WAV рулят :)

        Дело в том, что этот шум будет отжирать на себя часть битрейта. Ну то есть, грубо говоря, из 100% битрейта 50% уходит на шум. Если битрейт большой вследствие апскейла, 10/16/100500-битности или просто что его большим поставили — да, это допустимо, потому что полезная информация поместится в оставшуюся часть битрейта.

        Но часто битрейта не хватает — и я про этот случай. Поголовно люди такие: «О, 576 строк, значит достаточно 480p/720p». И из этого шума вырастает ушатанное пережатое мыло.

        если шум маскирует нехватку деталей (улучшает субъективное качество), то пусть остаётся.

        Согласен. Но тогда нужно, чтобы этот шум сохранился.

        Плёнка есть прогрессивная развёртка. А VHS — это чересстрочка. Которой на стримминговых сервисах и прочих воблачках нет. Поэтому изначальный труъ‑ламповый шум улетает как минимум в деинтерлейсер, который уже превратит его в непойми что. Особенно это касается деинтерлейсеров по оптическому потоку.

        Поэтому, если уж заморачиваться, то:

        1. Оцифровываем RAW

        2. Измеряем и сохраняем спектр шума по яркости и цветоразностным (причём в каждом кадре отдельно)

        3. Удаляем шум максимально качественно алгоритмом, способным жрать чересстрочку

        4. Деинтерлейсим качественно

        5. Апскейлим какой‑нибудь хорошей штукой до 4K/8K/16K

        6. На основе ранее запечатлённого спектра генерируем шум яркости и цветоразностных заново. Можно крупный (чтобы пропорционально соотноситься с «пикселями» исходной картинки), можно помельче

        YPbPr в этот видак поставили ради цифрового D-VHS*, HD-сигналу которого есть что терять и который не имел преступных связей с композитом. Ну и ради цифровой обработки (TBC, DNR), то есть ему бы вообще цифровой выход иметь, раз он всё через цифру прогоняет.

        С одной стороны да, с другой — у нас на том конце провода висит карта захвата, которая тоже может вносить свои косяки. И с компонентом их огрести менее вероятно.

        Можно вообще попробовать три карты захвата SVideo для каждого компонента — будет три отдельных АЦП и, по идее, будет вкусно. Но надо тестить, потому что не всё так просто.

        но ЕМНИП, люди не видели однозначного улучшения - полосы частот так порезаны при записи, что заметные артефакты от разделения не возникают.

        Ну моя идея не в том, что это однозначно улучшит качество, а в том, что при этом мы с меньшей вероятностью потеряем информацию, и даже если она не видна для глаза, она может стать важна для каких‑нибудь алгоритмов обработки, которые мы применим дальше в конвейере.


        1. ahabreader
          06.07.2025 20:31

          в конце концов, хранить/стримить в loseless или вообще в RAW. PNG/EXR сиквенсы + WAV рулят :)

          Если оставить в YCbCr, то цветность проредить можно будет (хотя бы по горизонтали для чересстрочного). 4:2:2 уменьшит битрейт в полтора раза, 4:1:1 - в два раза, передовым lossless-сжатием для видео вроде остаётся FFV1 в 2 прохода (уменьшит битрейт ещё чуть больше двух раз).

          Ну моя идея не в том, что это однозначно улучшит качество, а в том, что при этом мы с меньшей вероятностью потеряем информацию, и даже если она не видна для глаза, она может стать важна для каких‑нибудь алгоритмов обработки, которые мы применим дальше в конвейере.

          На кашу из топора похоже - выбрали аппарат по наличию компонентного выхода (польза для VHS туманна), получили в целом качественный аппарат с TBC (польза очевидна), использовали компонентный выход (раз уж есть, то тупо не использовать*), а проверять гипотезы насчёт композита в конце этого длинного пути уже никому не захочется.

          * принцип не работает с лазердисками