Вы когда-нибудь смотрели видео на Netflix и думали: "Вот бы просто скачать это?". Я бы никогда не стал этого делать, потому что мне претит мысль о нарушении законов об интеллектуальной собственности ;3. Однако если кто-то задастся такой целью, то первое, что ему придется обойти, - это печально известное программное обеспечение DRM компании Google - widevine.
В сотрудничестве с замечательным компьютерным инженером Alex Wilson нам удалось разобрать большую часть возможностей Widevine и использовать его реализацию в самом лучшем веб-браузере... Firefox! Firefox не только имеет наиболее открытую платформу для кодирования, но и предоставляет легкий доступ ко всем инструментам, которые он использует для взаимодействия с библиотеками Widevine. В Firefox также есть замечательный инструмент сторонних разработчиков Searchfox, который делает поиск в исходном коде очень простым!
Прежде чем приступать к изучению самого формата, необходимо выяснить, как Firefox реализует Widevine. Знание этого поможет в дальнейшем при попытке его использования. Судя по тому ограниченному анализу, который мы провели в отношении реализации Widevine в Firefox, похоже, что после расшифровки видео оно становится таким же доступным, как и обычная вставка видео. Это означает, что теоретически для получения исходных видеоданных достаточно перехватить кадры, которые декодируются Widevine.
Хотя перехват расшифрованных видеокадров и позволяет обойти значительную часть процесса декодирования, он имеет свои недостатки. Во-первых, необходимо позаботиться об адаптивном битрейте, а во-вторых, нужно придумать, как запросить у видеосервера больше кадров, чем обычно при воспроизведении обычного видео.
Конечно, идея - это только половина дела, ее реализация - совсем другое дело. Очевидно, что mozilla поставит какие-нибудь барьеры, чтобы помешать пользователю просто перехватывать данные кадра, верно?... верно? НЕТ! С помощью пары строк кода вы можете обойти почти все ограничения, созданные Mozilla для предотвращения захвата пользователем кадров.
Первое препятствие, которое необходимо преодолеть, - это ограничение Firefox на запись видео с ограничением DRM. Хотя вы можете подумать, что сделать это будет сложно, на самом деле все просто - достаточно убрать один оператор if. Серьезно, единственное, что мешает вам поделиться потоком Netflix с друзьями в Discord, - это единственный оператор if.
// /dom/html/htmlmediaelement.cpp#3796
// предотвращение захвата видео с ограниченным доступом
if (acapturetype == streamcapturetype::capture_all_tracks &&
containsrestrictedcontent()) {
return false;
}
return true;
Это, конечно, здорово, но все равно вы будете записывать сильно закодированное видео с сильными артефактами. Если бы только существовал простой способ захвата кадров сразу после их декодирования. Если бы в Firefox был встроенный метод захвата кадров контента, защищенного DRM... О, подождите, есть! В файле dom/media/gmp/ChromiumCDMChild.cpp есть все необходимые инструменты для захвата информации о кадрах, кодеках и сохранения каждого кадра, декодированного Widevine.
Ниже приведен фрагмент кода, который может захватывать, записывать и форматировать захваченные видеоданные непосредственно из Widevine и добавлять их в файл в виде необработанного видео в формате yuv420. Хотя я понимаю, что это не идеальный подход, это большой скачок к захвату видео с высоким разрешением Widevine, поскольку он не делает различий между шифрованием L1, L2 или L3.
WidevineVideoFrame frame;
cdm::Status rv = mCDM->DecryptAndDecodeFrame(input, &frame);
//====[Извлечение рамок Widevine]=====|
// Убедитесь, что сборка/запуск с отключенной файловой песочницейbr
printf("Расшифрованный кадр! w:%i h:%i f:%i\n", frame.Size().width, frame.Size().height, frame.Format());
printf("\tOffsets - Y:%i U:%i V:%i\n",
frame.PlaneOffset(cdm::kYPlane), frame.PlaneOffset(cdm::kUPlane),
frame.PlaneOffset(cdm::kVPlane));
printf("\tStride - Y:%i U:%i V:%i\n",
frame.Stride(cdm::kYPlane), frame.Stride(cdm::kUPlane),
frame.Stride(cdm::kVPlane));
if (frame.Size().width > 0) {
FILE *fptr;
fptr = fopen("/tmp/widevine_frame.yuv", "ab");
fwrite(frame.FrameBuffer()->Data(), frame.FrameBuffer()->Size(), 1, fptr);
fclose(fptr);
}
//====[Конец извлечения]=============|
Несмотря на то, что эта реализация отнюдь не идеальна, существует множество способов дальнейшего совершенствования реализации Widevine в Firefox, следующими в списке которых являются извлечение звука и быстрый запрос кадров. Если эти два препятствия удастся преодолеть, мы станем еще на один шаг ближе к мечте о загрузке DRM-защищенного контента по щёлчку правой кнопкой мыши.