123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- import window from 'global/window';
- var regexs = {
- // to determine mime types
- mp4: /^(av0?1|avc0?[1234]|vp0?9|flac|opus|mp3|mp4a|mp4v|stpp.ttml.im1t)/,
- webm: /^(vp0?[89]|av0?1|opus|vorbis)/,
- ogg: /^(vp0?[89]|theora|flac|opus|vorbis)/,
- // to determine if a codec is audio or video
- video: /^(av0?1|avc0?[1234]|vp0?[89]|hvc1|hev1|theora|mp4v)/,
- audio: /^(mp4a|flac|vorbis|opus|ac-[34]|ec-3|alac|mp3|speex|aac)/,
- text: /^(stpp.ttml.im1t)/,
- // mux.js support regex
- muxerVideo: /^(avc0?1)/,
- muxerAudio: /^(mp4a)/,
- // match nothing as muxer does not support text right now.
- // there cannot never be a character before the start of a string
- // so this matches nothing.
- muxerText: /a^/
- };
- var mediaTypes = ['video', 'audio', 'text'];
- var upperMediaTypes = ['Video', 'Audio', 'Text'];
- /**
- * Replace the old apple-style `avc1.<dd>.<dd>` codec string with the standard
- * `avc1.<hhhhhh>`
- *
- * @param {string} codec
- * Codec string to translate
- * @return {string}
- * The translated codec string
- */
- export var translateLegacyCodec = function translateLegacyCodec(codec) {
- if (!codec) {
- return codec;
- }
- return codec.replace(/avc1\.(\d+)\.(\d+)/i, function (orig, profile, avcLevel) {
- var profileHex = ('00' + Number(profile).toString(16)).slice(-2);
- var avcLevelHex = ('00' + Number(avcLevel).toString(16)).slice(-2);
- return 'avc1.' + profileHex + '00' + avcLevelHex;
- });
- };
- /**
- * Replace the old apple-style `avc1.<dd>.<dd>` codec strings with the standard
- * `avc1.<hhhhhh>`
- *
- * @param {string[]} codecs
- * An array of codec strings to translate
- * @return {string[]}
- * The translated array of codec strings
- */
- export var translateLegacyCodecs = function translateLegacyCodecs(codecs) {
- return codecs.map(translateLegacyCodec);
- };
- /**
- * Replace codecs in the codec string with the old apple-style `avc1.<dd>.<dd>` to the
- * standard `avc1.<hhhhhh>`.
- *
- * @param {string} codecString
- * The codec string
- * @return {string}
- * The codec string with old apple-style codecs replaced
- *
- * @private
- */
- export var mapLegacyAvcCodecs = function mapLegacyAvcCodecs(codecString) {
- return codecString.replace(/avc1\.(\d+)\.(\d+)/i, function (match) {
- return translateLegacyCodecs([match])[0];
- });
- };
- /**
- * @typedef {Object} ParsedCodecInfo
- * @property {number} codecCount
- * Number of codecs parsed
- * @property {string} [videoCodec]
- * Parsed video codec (if found)
- * @property {string} [videoObjectTypeIndicator]
- * Video object type indicator (if found)
- * @property {string|null} audioProfile
- * Audio profile
- */
- /**
- * Parses a codec string to retrieve the number of codecs specified, the video codec and
- * object type indicator, and the audio profile.
- *
- * @param {string} [codecString]
- * The codec string to parse
- * @return {ParsedCodecInfo}
- * Parsed codec info
- */
- export var parseCodecs = function parseCodecs(codecString) {
- if (codecString === void 0) {
- codecString = '';
- }
- var codecs = codecString.split(',');
- var result = [];
- codecs.forEach(function (codec) {
- codec = codec.trim();
- var codecType;
- mediaTypes.forEach(function (name) {
- var match = regexs[name].exec(codec.toLowerCase());
- if (!match || match.length <= 1) {
- return;
- }
- codecType = name; // maintain codec case
- var type = codec.substring(0, match[1].length);
- var details = codec.replace(type, '');
- result.push({
- type: type,
- details: details,
- mediaType: name
- });
- });
- if (!codecType) {
- result.push({
- type: codec,
- details: '',
- mediaType: 'unknown'
- });
- }
- });
- return result;
- };
- /**
- * Returns a ParsedCodecInfo object for the default alternate audio playlist if there is
- * a default alternate audio playlist for the provided audio group.
- *
- * @param {Object} master
- * The master playlist
- * @param {string} audioGroupId
- * ID of the audio group for which to find the default codec info
- * @return {ParsedCodecInfo}
- * Parsed codec info
- */
- export var codecsFromDefault = function codecsFromDefault(master, audioGroupId) {
- if (!master.mediaGroups.AUDIO || !audioGroupId) {
- return null;
- }
- var audioGroup = master.mediaGroups.AUDIO[audioGroupId];
- if (!audioGroup) {
- return null;
- }
- for (var name in audioGroup) {
- var audioType = audioGroup[name];
- if (audioType.default && audioType.playlists) {
- // codec should be the same for all playlists within the audio type
- return parseCodecs(audioType.playlists[0].attributes.CODECS);
- }
- }
- return null;
- };
- export var isVideoCodec = function isVideoCodec(codec) {
- if (codec === void 0) {
- codec = '';
- }
- return regexs.video.test(codec.trim().toLowerCase());
- };
- export var isAudioCodec = function isAudioCodec(codec) {
- if (codec === void 0) {
- codec = '';
- }
- return regexs.audio.test(codec.trim().toLowerCase());
- };
- export var isTextCodec = function isTextCodec(codec) {
- if (codec === void 0) {
- codec = '';
- }
- return regexs.text.test(codec.trim().toLowerCase());
- };
- export var getMimeForCodec = function getMimeForCodec(codecString) {
- if (!codecString || typeof codecString !== 'string') {
- return;
- }
- var codecs = codecString.toLowerCase().split(',').map(function (c) {
- return translateLegacyCodec(c.trim());
- }); // default to video type
- var type = 'video'; // only change to audio type if the only codec we have is
- // audio
- if (codecs.length === 1 && isAudioCodec(codecs[0])) {
- type = 'audio';
- } else if (codecs.length === 1 && isTextCodec(codecs[0])) {
- // text uses application/<container> for now
- type = 'application';
- } // default the container to mp4
- var container = 'mp4'; // every codec must be able to go into the container
- // for that container to be the correct one
- if (codecs.every(function (c) {
- return regexs.mp4.test(c);
- })) {
- container = 'mp4';
- } else if (codecs.every(function (c) {
- return regexs.webm.test(c);
- })) {
- container = 'webm';
- } else if (codecs.every(function (c) {
- return regexs.ogg.test(c);
- })) {
- container = 'ogg';
- }
- return type + "/" + container + ";codecs=\"" + codecString + "\"";
- };
- export var browserSupportsCodec = function browserSupportsCodec(codecString) {
- if (codecString === void 0) {
- codecString = '';
- }
- return window.MediaSource && window.MediaSource.isTypeSupported && window.MediaSource.isTypeSupported(getMimeForCodec(codecString)) || false;
- };
- export var muxerSupportsCodec = function muxerSupportsCodec(codecString) {
- if (codecString === void 0) {
- codecString = '';
- }
- return codecString.toLowerCase().split(',').every(function (codec) {
- codec = codec.trim(); // any match is supported.
- for (var i = 0; i < upperMediaTypes.length; i++) {
- var type = upperMediaTypes[i];
- if (regexs["muxer" + type].test(codec)) {
- return true;
- }
- }
- return false;
- });
- };
- export var DEFAULT_AUDIO_CODEC = 'mp4a.40.2';
- export var DEFAULT_VIDEO_CODEC = 'avc1.4d400d';
|