Назад в Центр знаний
Отпечатки

MIME и кодеки: сигналы поддержки медиа в браузере

Как canPlayType, isTypeSupported и MediaCapabilities сообщают о поддержке медиа, почему ответы зависят от хоста и как сверить их с одним профилем.

BotBrowser Team

Документация

Нужна поддерживаемая продуктовая документация?

У этой статьи есть соответствующая страница в центре документации. Используйте docs для каноничного сценария настройки, актуальных флагов и долгосрочной справки.

Запросы MIME-типов показывают, какие контейнеры и кодеки принимает браузер, а ответы зависят от сборки, операционной системы и графического оборудования хоста. BotBrowser может отдавать canPlayType(), isTypeSupported() и decodingInfo() медиатипы загруженного профиля, но сообщённый тип не доказывает, что хост действительно его декодирует.

Смотреть видео

Это видео на английском разбирает один симптом: одна и та же строка MIME получает разные ответы на двух машинах. В нём по порядку проверяются четыре подозреваемых: три API, которые отвечают (canPlayType(), MediaSource.isTypeSupported() и MediaCapabilities.decodingInfo()), сама строка MIME, хост под браузером и контекст, который задаёт вопрос. Локальная лабораторная страница объявляет фиксированный список медиатипов и опрашивает каждый API в основной странице, выделенном Worker и iframe того же источника; ответы читаются в консоли DevTools браузера на раннере Ubuntu и на раннере Windows. Затем цитируются статья и документация BotBrowser о флаге --bot-media-types и его трёх режимах (expand, profile, real). В записях профиль BotBrowser не загружен, поэтому режимы цитируются, а не запускаются. Звук на английском.

Краткое резюме

Сравнивайте три интерфейса на одном списке строк кодеков на главной странице, в Worker и в iframe: ответы должны совпадать по направлению. Режим --bot-media-types выбирайте по вопросу: profile для проверки согласованности, expand по умолчанию, real для проверки возможностей хоста.

Содержание руководства

Три медиа-API сравнивают поддержку кодеков в профиле, странице, Worker и iframe.

Что сообщают три медиа-API

HTMLMediaElement.canPlayType(type) принимает строку с MIME-типом, при необходимости с параметром codecs, и возвращает пустую строку, maybe или probably (MDN canPlayType). Пустая строка означает, что браузер не может воспроизвести такой тип. probably говорит об уверенности, а maybe о том, что без попытки воспроизведения определить это нельзя. Трёхзначный ответ намеренно грубый, поэтому о качестве и производительности он почти ничего не говорит.

MediaSource.isTypeSupported(type) это статический метод, который возвращает булево значение для MIME-типа с необязательным списком кодеков (MDN isTypeSupported). Он сообщает плееру, примет ли браузер этот тип для потоковой передачи через Media Source Extensions. Результат true это прогноз поддержки, а не доказательство того, что конкретный поток воспроизведётся.

MediaCapabilities.decodingInfo(configuration) самый подробный из трёх (MDN decodingInfo). Конфигурация описывает поток: тип содержимого, а для видео ещё размеры, битрейт и частоту кадров. Возвращаемый promise разрешается с флагами supported, smooth и powerEfficient. Последние два описывают ожидаемое качество декодирования, поэтому они сильнее зависят от оборудования и от собственной истории браузера, чем простые ответы о поддержке.

Все три интерфейса начинают со строки с MIME-типом. Один лишь тип контейнера, например video/mp4, говорит мало, потому что в одном контейнере может лежать много кодеков. Необязательный параметр codecs называет реальные кодеки, например avc1.42E01E для видео H.264, mp4a.40.2 для звука AAC, vp09.00.10.08 для видео VP9 или opus для звука Opus. Строки кодеков намеренно компактны и кодируют профиль и уровень, поэтому две строки одного семейства кодеков могут получить разные ответы.

Поле type в конфигурации decodingInfo() тоже важно. Значение file описывает обычное воспроизведение ресурса, а media-source описывает потоковую передачу через Media Source Extensions, и эти два пути не обязаны совпадать. Если спрашивать с тем типом, который соответствует реальной работе вашего плеера, ответ остаётся относящимся к делу, а сам вопрос каждый раз одинаков.

Вызовы ниже показывают все три формы рядом.

const type = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
document.createElement('video').canPlayType(type);
MediaSource.isTypeSupported(type);
await navigator.mediaCapabilities.decodingInfo({
  type: 'media-source',
  video: { contentType: 'video/mp4; codecs="avc1.42E01E"', width: 1280, height: 720, bitrate: 2500000, framerate: 30 },
});

Один и тот же код может выдать разные ответы на двух компьютерах, а также на одном компьютере после обновления браузера. MIME-строка это только вопрос. Ответ определяют декодеры и правила, доступные получившему её браузеру.

Зашифрованные медиа добавляют ещё один слой. decodingInfo() можно спросить и о ключевой системе, а это уже область DRM, а не простой поддержки кодеков. Эту границу разбирает статья о фингерпринтинге DRM, а возможности WebCodecs описывают более низкоуровневый интерфейс кодеков, у которого есть собственные запросы поддержки.

Почему ответы различаются между машинами

Сравнивайте canPlayType() и MediaSource.isTypeSupported() с одной MIME-строкой: браузер, ОС, GPU и управляемая политика могут менять каждый ответ.

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

  • Версия браузера: со временем появляются новые кодеки и возможности контейнеров, а ветка кода может потерять поддержку старого формата.
  • Операционная система: декодер, установленный в одной системе, может отсутствовать в другой даже при той же версии браузера.
  • Оборудование: более новое графическое оборудование декодирует кодеки, которые старое устройство обрабатывает программно или не обрабатывает совсем.
  • Конфигурация: корпоративные политики, пользовательские параметры и флаги командной строки могут менять то, о чём сообщает браузер.

Примеры делают закономерность наглядной. Видео H.264 и звук AAC широко доступны в основных настольных браузерах, VP9 и Opus тоже распространены. HEVC часто зависит от декодера, который предоставляет операционная система или графическое оборудование, а AV1 зависит либо от программного декодера в браузере, либо от более нового оборудования. Это тенденции, а не правила.

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

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

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

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

Как читать ответы рядом

Три интерфейса связаны, но не взаимозаменяемы, и полезная проверка сравнивает их на одних и тех же строках кодеков. У каждого своя задача.

  • canPlayType() отвечает про обычное воспроизведение в медиаэлементе и возвращает строку с тремя состояниями.
  • isTypeSupported() отвечает про потоковую передачу через Media Source Extensions и возвращает булево значение.
  • decodingInfo() отвечает про описанный поток и добавляет smooth и powerEfficient.

Отсюда два ожидания согласованности. Во-первых, ответы должны совпадать по направлению: если decodingInfo() сообщает supported равным false для кодека при скромном разрешении, то true от isTypeSupported() для того же типа требует объяснения. Во-вторых, семейство кодеков должно выглядеть цельным для платформы. Отчёт, в котором перечислены самые новые кодеки, доступные только в оборудовании, но отсутствует базовый кодек вроде H.264, необычен для основного настольного браузера, а необычное само по себе информативно.

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

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

На практике важен порядок действий. canPlayType() и isTypeSupported() отвечают сразу, а decodingInfo() возвращает promise, поэтому скрипт должен дождаться каждого результата, прежде чем что-то записывать. Выполняйте все вызовы из одной ветки кода, собирайте ответы в фиксированном порядке и сравнивайте с базой, которую вы сами получили на том же хосте. Список, скопированный с веб-страницы или с другой машины, описывает другую среду и вводит проверку в заблуждение чаще, чем помогает.

Вот типичное прочтение. Допустим, canPlayType() возвращает probably для H.264 и AAC в MP4, isTypeSupported() возвращает true для того же типа, а decodingInfo() сообщает supported и smooth для потока 720p. Эти три ответа согласуются, и хост явно справляется с базовым веб-видео. Если же decodingInfo() для потока AV1 высокого разрешения сообщает supported, но не powerEfficient, это может указывать на программное декодирование, а не на противоречие.

Проверка одного профиля в разных контекстах

Медиа-API доступны не только на главной странице. К navigator.mediaCapabilities можно обратиться из Workers, а медиаэлементы и MediaSource можно использовать внутри iframe. Поэтому страница может задать один и тот же вопрос из нескольких контекстов, и конфигурация браузера, которая на главной странице отвечает одно, а в Worker или во фрейме другое, выглядит непоследовательной, даже если каждый ответ по отдельности правдоподобен.

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

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

  1. Зафиксируйте список строк типов, соответствующий медиа, которые реально использует ваш рабочий процесс, с явными параметрами codecs.
  2. Запустите три API для этого списка на главной странице и запишите каждый ответ.
  3. Повторите в выделенном Worker и в iframe того же источника, где API там доступен.
  4. Сравните строка за строкой, затем сопоставьте результат с тем, что должен описывать загруженный профиль.
  5. Воспроизведите короткий образец каждого важного типа, чтобы увидеть, что хост действительно декодирует.

Расхождение это находка, которую нужно объяснить, а не шум, который можно игнорировать. Частые причины: конфигурация была изменена только в одном контексте, в списке смешаны строки с разными кодами профиля и уровня, а ответ отражает реальные декодеры хоста, а не профиль. Устраните причину и снова прогоните весь список целиком, потому что частичный повтор может скрыть новое различие. Более общий метод сравнения браузера на разных платформах описан в статье об оценке согласованности браузера между платформами.

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

Когда ответы действительно противоречат

Пара ответовВердиктПочему
canPlayType probably + isTypeSupported trueСовместимыДва разных пути оба дают положительный ответ
canPlayType "" + isTypeSupported trueОбъяснитьПоддержка только через MSE возможна, но необычна
decodingInfo supported: false + isTypeSupported trueПротиворечиеТот же кодек, один путь утверждает, что декодирование недоступно
supported: true + smooth: falseМягкий признакОжидание качества, а не утверждение о поддержке
powerEfficient: true на одном хосте и false на другомНесопоставимоПоле следует за оборудованием и историей воспроизведения

Дефектом является только третья строка, и только когда decodingInfo запрашивается с типом media-source; при типе file те же два ответа относятся ко второй строке, потому что тогда API описывают разные пути доставки, а не противоречат друг другу. Первая строка является обычным случаем, а две последние относятся к более мягким сигналам, описанным выше.

Записывайте вердикт рядом с парой, а не сырые строки, потому что записанные true и false не говорят, к какой из пяти строк они относятся. Таблица вердиктов также делает два хоста сопоставимыми: те же пять строк, тот же вердикт и diff, показывающий, какая строка сменила категорию.

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

Границы приватности медиазапросов

Запрашивайте только нужные форматы и сохраняйте тип MIME ошибки рядом с версией браузера; MediaCapabilities не требует полного перечня возможностей.

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

Выбор режима медиатипов

Когда профиль загружен, флаг --bot-media-types определяет, как медиатипы профиля соотносятся с собственными декодерами хоста. Он принимает три значения, описанных в документации (документация по MIME и кодекам).

  • expand используется по умолчанию. Он отдаёт приоритет локальным декодерам и расширяет список типами, которые определяет профиль, поэтому результат сочетает реальные возможности хоста и возможности профиля.
  • profile использует только медиатипы, определённые профилем. Он не добавляет декодеры хоста, поэтому подходит для проверки согласованности, где ответы сравниваются с загруженным профилем.
  • real использует фактические медиатипы системы. Он подходит, чтобы проверить, что хост действительно умеет декодировать, но может не совпасть с профилем, описывающим другое оборудование.

Выбирайте режим по вопросу, на который отвечаете. Для проверки согласованности начните с profile и сравните три API в разных контекстах. Переходите на expand, когда воспроизведение на хосте важнее строгого совпадения, а real используйте, чтобы узнать, о чём сообщает сам хост. Меняйте один параметр за раз и держите список типов неизменным между запусками.

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

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

BotBrowser сообщает о поддержке MIME-типов и кодеков через загруженный профиль и предоставляет флаг --bot-media-types с режимами expand (по умолчанию), profile и real, поэтому результаты canPlayType(), isTypeSupported() и MediaCapabilities можно проверять на согласованность на главной странице, в Workers, в Service Workers и в iframe. Это даёт документированный способ убедиться, что медиаответы соответствуют одному профилю. BotBrowser не может добавить декодеры, которых нет у хоста, не гарантирует, что конкретный сайт сочтёт сообщаемые медиавозможности приемлемыми, и не заменяет проверку реального воспроизведения в вашем целевом рабочем процессе.

Для более подробного разбора см. Widevine в автоматизированных браузерах: почему EME не работает.

Что добавлено по сравнению со справочной страницей

Справочная страница перечисляет медиарежимы. Добавленная матрица вызывает canPlayType, isTypeSupported и decodingInfo с одинаковыми MIME строками, затем сравнивает страницу, Worker и media element. Расхождение означает, что нужно изучить контекст или декодер хоста.

Практический итог

Для проверки согласованности начните с --bot-media-types=profile и фиксированного списка типов в нескольких контекстах. Расхождение между контекстами или интерфейсами считайте находкой и объясняйте сборкой, системой, оборудованием или конфигурацией, а не усредняйте.

Источники

#Mime#Codec#Media#fingerprinting#приватность#Mediacapabilities

Эта статья входит в руководство: Что такое отпечаток браузера?

Переведите BotBrowser из исследований в продакшн

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