Cleaning up the support list

This commit is contained in:
Zoe Roux 2020-10-22 23:58:36 +02:00
parent a988d2b75b
commit 199e541997
7 changed files with 232 additions and 400 deletions

View File

@ -22,7 +22,7 @@ import { PeopleListComponent } from './components/people-list/people-list.compon
import {
BufferToWidthPipe,
FormatTimePipe,
PlayerComponent,
PlayerComponent, SupportedButtonPipe,
VolumeToButtonPipe
} from "./pages/player/player.component";
import { SearchComponent } from './pages/search/search.component';
@ -67,7 +67,8 @@ import { MatBadgeModule } from "@angular/material/badge";
ShowGridComponent,
FormatTimePipe,
BufferToWidthPipe,
VolumeToButtonPipe
VolumeToButtonPipe,
SupportedButtonPipe
],
imports: [
BrowserModule,

View File

@ -0,0 +1,155 @@
import { detect } from "detect-browser";
import { Track, WatchItem } from "../../models/watch-item";
export enum method
{
direct = "Direct Play",
transmux = "Transmux",
transcode = "Transcode"
}
export class SupportList
{
container: boolean;
videoCodec: boolean;
audioCodec: boolean[];
getPlaybackMethod(): method
{
if (this.container)
{
if (this.videoCodec && this.audioCodec)
return method.direct;
return method.transcode;
}
if (this.videoCodec && this.audioCodec)
return method.transmux;
return method.transcode;
}
}
export function getWhatIsSupported(player: HTMLVideoElement, item: WatchItem): SupportList
{
let supportList: SupportList = new SupportList();
let browser = detect();
if (!browser)
{
supportList.container = false;
supportList.videoCodec = false;
supportList.audioCodec = item.audios.map(() => false);
}
else
{
supportList.container = containerIsSupported(player, item.container, browser.name) && item.audios.length <= 1;
supportList.videoCodec = videoCodecIsSupported(player, item.video.codec, browser.name);
supportList.audioCodec = item.audios.map((x: Track) => audioCodecIsSupported(player, x.codec, browser.name));
}
return (supportList);
}
function containerIsSupported(player: HTMLVideoElement, container: string, browser: string): boolean
{
switch (container)
{
case "asf":
return browser == "tizen" || browser == "orsay" || browser == "edge";
case "avi":
return browser == "tizen" || browser == "orsay" || browser == "edge";
case "mpg":
case "mpeg":
return browser == "tizen" || browser == "orsay" || browser == "edge";
case "flv":
return browser == "tizen" || browser == "orsay";
case "3gp":
case "mts":
case "trp":
case "vob":
case "vro":
return browser == "tizen" || browser == "orsay";
case "mov":
return browser == "tizen" || browser == "orsay" || browser == "edge" || browser == "chrome";
case "m2ts":
return browser == "tizen" || browser == "orsay" || browser == "edge";
case "wmv":
return browser == "tizen" || browser == "orsay" || browser == "edge";
case "ts":
return browser == "tizen" || browser == "orsay" || browser == "edge";
case "mp4":
case "m4v":
return true;
case "mkv":
if (browser == "tizen" || browser == "orsay" || browser == "chrome" || browser == "edge")
return true;
return !!(player.canPlayType("video/x-matroska") || player.canPlayType("video/mkv"));
default:
return false;
}
}
//SHOULD CHECK FOR DEPTH (8bits ok but 10bits unsupported for almost every browsers)
function videoCodecIsSupported(player: HTMLVideoElement, codec: string, browser: string): boolean
{
switch (codec)
{
case "h264":
return !!player.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
case "h265":
case "hevc":
if (browser == "tizen" || browser == "orsay" || browser == "xboxOne" || browser == "ios")
return true;
//SHOULD SUPPORT CHROMECAST ULTRA
// if (browser.chromecast)
// {
// var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
// if (isChromecastUltra)
// {
// return true;
// }
// }
return !!player.canPlayType('video/hevc; codecs="hevc, aac"');
case "mpeg2video":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "vc1":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "msmpeg4v2":
return browser == "orsay" || browser == "tizen";
case "vp8":
return !!player.canPlayType('video/webm; codecs="vp8');
case "vp9":
return !!player.canPlayType('video/webm; codecs="vp9"');
case "vorbis":
return browser == "orsay" || browser == "tizen" || !!player.canPlayType('video/webm; codecs="vp8');
default:
return false;
}
}
//SHOULD CHECK FOR NUMBER OF AUDIO CHANNEL (2 ok but 5 not in some browsers)
function audioCodecIsSupported(player: HTMLVideoElement, codec: string, browser: string): boolean
{
switch (codec)
{
case "mp3":
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"') ||
!!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"');
case "aac":
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"');
case "mp2":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "pcm_s16le":
case "pcm_s24le":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "aac_latm":
return browser == "orsay" || browser == "tizen";
case "opus":
return !!player.canPlayType('audio/ogg; codecs="opus"');
case "flac":
return browser == "orsay" || browser == "tizen" || browser == "edge";
default:
return false;
}
}

View File

@ -37,25 +37,25 @@
Video Container:
<span>
{{this.item.container}}
<i class="material-icons">{{getSupportedFeature("container")}}</i>
<i class="material-icons">{{this.supportList | supportedButton: "container"}}</i>
</span>
<br />
Video Codec:
<span>
{{this.item.video.codec}}
<i class="material-icons">{{getSupportedFeature("video")}}</i>
<i class="material-icons">{{this.supportList | supportedButton: "video"}}</i>
</span>
<br />
Audio Codec:
<span>
{{this.item.audios[0].codec}}
<i class="material-icons">{{getSupportedFeature("audio")}}</i>
{{this.item.audios[this.selectedAudio].codec}}
<i class="material-icons">{{this.supportList | supportedButton: "audio":this.selectedAudio}}</i>
</span>
<br />
Subtitle Codec:
<span>
{{this.selectedSubtitle ? this.selectedSubtitle.codec : "none"}}
<i class="material-icons">{{getSupportedFeature("subtitle")}}</i>
{{this.selectedSubtitle != -1 ? this.item.subtitles[this.selectedSubtitle].codec : "none"}}
<i class="material-icons">{{this.supportList | supportedButton: "subtitle"}}</i>
</span>
<br />
</mat-card-content>
@ -130,7 +130,8 @@
<p>{{player.currentTime | formatTime: player.duration}} / {{player.duration | formatTime}}</p>
</div>
<div class="right">
<button id="volume" *ngIf="this.item.audios.length > 1" mat-icon-button matTooltipPosition="above" matTooltip="Select audio track">
<button *ngIf="this.item.audios.length > 1" mat-icon-button
matTooltipPosition="above" matTooltip="Select audio track">
<mat-icon>music_note</mat-icon>
</button>
<button *ngIf="this.item.subtitles.length > 0" mat-icon-button [matMenuTriggerFor]="subtitles"
@ -158,12 +159,13 @@
<mat-menu #subtitles="matMenu" (closed)="this.isMenuOpen = false">
<ng-template matMenuContent>
<button [ngClass]="{'selected': this.selectedSubtitle == null}" mat-menu-item (click)="selectSubtitle(null)">
<button [ngClass]="{'selected': this.selectedSubtitle === -1}" mat-menu-item
(click)="selectSubtitle(null)">
<span>None</span>
</button>
<div *ngFor="let subtitle of this.item.subtitles">
<button [ngClass]="{'selected': this.selectedSubtitle == subtitle}"
<div *ngFor="let subtitle of this.item.subtitles; index as i">
<button [ngClass]="{'selected': this.selectedSubtitle === i}"
mat-menu-item *ngIf="subtitle.codec === 'ass' || subtitle.codec === 'subrip';
else elseBlock"
(click)="selectSubtitle(subtitle)">

View File

@ -16,11 +16,10 @@ import { ActivatedRoute, Event, NavigationCancel, NavigationEnd, NavigationStart
import { OidcSecurityService } from "angular-auth-oidc-client";
import * as Hls from "hls.js";
import {
getPlaybackMethod,
getWhatIsSupported,
method,
SupportList
} from "../../../videoSupport/playbackMethodDetector";
} from "./playbackMethodDetector";
import { AppComponent } from "../../app.component";
import { Track, WatchItem } from "../../models/watch-item";
@ -76,6 +75,30 @@ export class VolumeToButtonPipe implements PipeTransform
}
}
@Pipe({
name: "supportedButton",
pure: true
})
export class SupportedButtonPipe implements PipeTransform
{
transform(supports: SupportList, selector: string, audioIndex: number = 0): string
{
if (!supports)
return "help";
switch (selector)
{
case "container":
return supports.container ? "check_circle" : "cancel";
case "video":
return supports.videoCodec ? "check_circle" : "cancel";
case "audio":
return supports.audioCodec[audioIndex] ? "check_circle" : "cancel";
default:
return "help";
}
}
}
@Component({
selector: "app-player",
templateUrl: "./player.component.html",
@ -85,7 +108,8 @@ export class VolumeToButtonPipe implements PipeTransform
export class PlayerComponent implements OnInit, OnDestroy, AfterViewInit
{
item: WatchItem;
selectedSubtitle: Track;
selectedAudio: number = 0;
selectedSubtitle: number = -1;
playMethod: method = method.direct;
supportList: SupportList;
playing: boolean = true;
@ -182,11 +206,11 @@ export class PlayerComponent implements OnInit, OnDestroy, AfterViewInit
switch (true)
{
case event instanceof NavigationStart:
this.loading = false;
this.loading = true;
break;
case event instanceof NavigationEnd:
case event instanceof NavigationCancel:
this.loading = true;
this.loading = false;
break;
default:
break;
@ -207,11 +231,25 @@ export class PlayerComponent implements OnInit, OnDestroy, AfterViewInit
ngAfterViewInit()
{
if (this.oidcSecurity === undefined)
this.oidcSecurity = this.injector.get(OidcSecurityService);
this.hlsPlayer.config.xhrSetup = xhr =>
{
const token = this.oidcSecurity.getToken();
if (token)
xhr.setRequestHeader("Authorization", "Bearer " + token);
};
this.showControls = true;
setTimeout(() => this.route.data.subscribe(() =>
{
// TODO remove the query param for the method (should be a session setting).
let queryMethod: string = this.route.snapshot.queryParams["method"];
this.selectPlayMethod(queryMethod ? method[queryMethod] : getPlaybackMethod(this.player, this.item));
this.supportList = getWhatIsSupported(this.player, this.item);
this.selectPlayMethod(queryMethod ? method[queryMethod] : this.supportList.getPlaybackMethod());
// TODO remove this, it should be a user's setting.
const subSlug: string = this.route.snapshot.queryParams["sub"];
if (subSlug != null)
{
@ -220,10 +258,7 @@ export class PlayerComponent implements OnInit, OnDestroy, AfterViewInit
const sub: Track = this.item.subtitles.find(x => x.language == languageCode && x.isForced == forced);
this.selectSubtitle(sub, false);
}
this.supportList = getWhatIsSupported(this.player, this.item);
}));
this.showControls = true;
}
get isFullScreen(): boolean
@ -304,16 +339,6 @@ export class PlayerComponent implements OnInit, OnDestroy, AfterViewInit
selectPlayMethod(playMethod: method)
{
this.playMethod = playMethod;
if (this.oidcSecurity === undefined)
this.oidcSecurity = this.injector.get(OidcSecurityService);
this.hlsPlayer.config.xhrSetup = xhr =>
{
const token = this.oidcSecurity.getToken();
if (token)
xhr.setRequestHeader("Authorization", "Bearer " + token);
};
if (this.playMethod == method.direct)
this.player.src = `/video/${this.item.slug}`;
else
@ -377,8 +402,16 @@ export class PlayerComponent implements OnInit, OnDestroy, AfterViewInit
document.body.requestFullscreen();
}
selectSubtitle(subtitle: Track, changeUrl: boolean = true)
selectSubtitle(subtitle: Track | number, changeUrl: boolean = true)
{
if (typeof(subtitle) === "number")
{
this.selectedSubtitle = subtitle;
subtitle = this.item.subtitles[subtitle];
}
else
this.selectedSubtitle = this.item.subtitles.indexOf(subtitle);
if (changeUrl)
{
let subSlug: string;
@ -393,11 +426,10 @@ export class PlayerComponent implements OnInit, OnDestroy, AfterViewInit
relativeTo: this.route,
queryParams: {sub: subSlug},
replaceUrl: true,
queryParamsHandling: "merge"
queryParamsHandling: "merge",
});
}
this.selectedSubtitle = subtitle;
if (subtitle == null)
{
@ -442,23 +474,6 @@ export class PlayerComponent implements OnInit, OnDestroy, AfterViewInit
}
}
getSupportedFeature(feature: string) : string
{
if (!this.supportList)
return "help";
switch (feature)
{
case "container":
return this.supportList.container ? "check_circle" : "cancel";
case "video":
return this.supportList.videoCodec ? "check_circle" : "cancel";
case "audio":
return this.supportList.audioCodec ? "check_circle" : "cancel";
default:
return "help";
}
}
removeHtmlTrack()
{
let elements = this.player.getElementsByTagName("track");
@ -466,17 +481,14 @@ export class PlayerComponent implements OnInit, OnDestroy, AfterViewInit
elements.item(0).remove();
}
getThumb(url: string)
{
return this.sanitizer.bypassSecurityTrustStyle("url(" + url + ")");
}
@HostListener("document:keyup", ["$event"])
keypress(event: KeyboardEvent): void
{
switch (event.key)
{
case " ":
case "k":
case "K":
this.togglePlayback();
break;
@ -499,18 +511,17 @@ export class PlayerComponent implements OnInit, OnDestroy, AfterViewInit
});
break;
case "v":
case "V":
const subtitleIndex: number = this.item.subtitles.indexOf(this.selectedSubtitle);
const nextSub: Track = subtitleIndex + 1 <= this.item.subtitles.length
? this.item.subtitles[subtitleIndex + 1]
: this.item.subtitles[0];
this.selectSubtitle(nextSub);
this.selectSubtitle((this.selectedSubtitle + 2) % (this.item.subtitles.length + 1) - 1);
break;
case "f":
case "F":
this.fullscreen();
break;
case "m":
case "M":
this.muted = !this.muted;
this.snackBar.open(this.player.muted ? "Sound muted." : "Sound unmuted", null, {
@ -521,10 +532,12 @@ export class PlayerComponent implements OnInit, OnDestroy, AfterViewInit
});
break;
case "n":
case "N":
this.next();
break;
case "p":
case "P":
this.previous();
break;

View File

@ -1,159 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var detect_browser_1 = require("detect-browser");
var method;
(function (method) {
method["direct"] = "Direct Play";
method["transmux"] = "Transmux";
method["transcode"] = "Transcode";
})(method = exports.method || (exports.method = {}));
;
var SupportList = /** @class */ (function () {
function SupportList() {
}
return SupportList;
}());
exports.SupportList = SupportList;
function getPlaybackMethod(player, item) {
var supportList = getWhatIsSupported(player, item);
if (supportList.container) {
if (supportList.videoCodec && supportList.audioCodec)
return method.direct;
return method.transcode;
}
if (supportList.videoCodec && supportList.audioCodec)
return method.transmux;
return method.transcode;
}
exports.getPlaybackMethod = getPlaybackMethod;
function getWhatIsSupported(player, item) {
var supportList = new SupportList();
var browser = detect_browser_1.detect();
if (!browser) {
supportList.container = false;
supportList.videoCodec = false;
supportList.audioCodec = false;
}
else {
supportList.container = containerIsSupported(player, item.container, browser.name) && item.audios.length <= 1;
supportList.videoCodec = videoCodecIsSupported(player, item.video.codec, browser.name);
supportList.audioCodec = audioCodecIsSupported(player, item.audios.map(function (value) { return value.codec; }), browser.name);
}
return (supportList);
}
exports.getWhatIsSupported = getWhatIsSupported;
function containerIsSupported(player, container, browser) {
var supported = false;
switch (container) {
case "asf":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
//videoAudioCodecs = [];
break;
case "avi":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
break;
case "mpg":
case "mpeg":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
break;
case "flv":
supported = browser == "tizen" || browser == "orsay";
break;
case "3gp":
case "mts":
case "trp":
case "vob":
case "vro":
supported = browser == "tizen" || browser == "orsay";
break;
case "mov":
supported = browser == "tizen" || browser == "orsay" || browser == "edge" || browser == "chrome";
break;
case "m2ts":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
break;
case "wmv":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
//videoAudioCodecs = [];
break;
case "ts":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
break;
case "mp4":
case "m4v":
supported = true;
break;
case "mkv":
supported = browser == "tizen" || browser == "orsay" || browser == "chrome" || browser == "edge";
if (supported)
break;
if (player.canPlayType("video/x-matroska") || player.canPlayType("video/mkv"))
supported = true;
break;
default:
break;
}
return supported;
}
//SHOULD CHECK FOR DEPTH (8bits ok but 10bits unsuported for almost every browsers)
function videoCodecIsSupported(player, codec, browser) {
switch (codec) {
case "h264":
return !!player.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'); //The !! is used to parse the string as a bool
case "h265":
case "hevc":
if (browser == "tizen" || browser == "orsay" || browser == "xboxOne" || browser == "ios")
return true;
//SHOULD SUPPORT CHROMECAST ULTRA
// if (browser.chromecast)
// {
// var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
// if (isChromecastUltra)
// {
// return true;
// }
// }
return !!player.canPlayType('video/hevc; codecs="hevc, aac"');
case "mpeg2video":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "vc1":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "msmpeg4v2":
return browser == "orsay" || browser == "tizen";
case "vp8":
return !!player.canPlayType('video/webm; codecs="vp8');
case "vp9":
return !!player.canPlayType('video/webm; codecs="vp9"');
case "vorbis":
return browser == "orsay" || browser == "tizen" || !!player.canPlayType('video/webm; codecs="vp8');
default:
return false;
}
}
//SHOULD CHECK FOR NUMBER OF AUDIO CHANNEL (2 ok but 5 not in some browsers)
function audioCodecIsSupported(player, codecs, browser) {
for (var _i = 0, codecs_1 = codecs; _i < codecs_1.length; _i++) {
var codec = codecs_1[_i];
switch (codec) {
case "mp3":
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"') ||
!!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"');
case "aac":
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"');
case "mp2":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "pcm_s16le":
case "pcm_s24le":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "aac_latm":
return browser == "orsay" || browser == "tizen";
case "opus":
return !!player.canPlayType('audio/ogg; codecs="opus"');
case "flac":
return browser == "orsay" || browser == "tizen" || browser == "edge";
default:
return false;
}
}
}
//# sourceMappingURL=playbackMethodDetector.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"playbackMethodDetector.js","sourceRoot":"","sources":["playbackMethodDetector.ts"],"names":[],"mappings":"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"}

View File

@ -1,179 +0,0 @@
import { detect } from "detect-browser";
import { Track, WatchItem } from "../app/models/watch-item";
export enum method
{
direct = "Direct Play",
transmux = "Transmux",
transcode = "Transcode"
}
export class SupportList
{
container: boolean;
videoCodec: boolean;
audioCodec: boolean;
}
export function getPlaybackMethod(player: HTMLVideoElement, item: WatchItem): method
{
let supportList: SupportList = getWhatIsSupported(player, item);
if (supportList.container)
{
if (supportList.videoCodec && supportList.audioCodec)
return method.direct;
return method.transcode;
}
if (supportList.videoCodec && supportList.audioCodec)
return method.transmux;
return method.transcode;
}
export function getWhatIsSupported(player: HTMLVideoElement, item: WatchItem): SupportList
{
let supportList: SupportList = new SupportList();
let browser = detect();
if (!browser)
{
supportList.container = false;
supportList.videoCodec = false;
supportList.audioCodec = false;
}
else
{
supportList.container = containerIsSupported(player, item.container, browser.name) && item.audios.length <= 1;
supportList.videoCodec = videoCodecIsSupported(player, item.video.codec, browser.name);
supportList.audioCodec = audioCodecIsSupported(player, item.audios.map((value: Track) => value.codec), browser.name);
}
return (supportList);
}
function containerIsSupported(player: HTMLVideoElement, container: string, browser: string): boolean
{
let supported: boolean = false;
switch (container)
{
case "asf":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
//videoAudioCodecs = [];
break;
case "avi":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
break;
case "mpg":
case "mpeg":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
break;
case "flv":
supported = browser == "tizen" || browser == "orsay";
break;
case "3gp":
case "mts":
case "trp":
case "vob":
case "vro":
supported = browser == "tizen" || browser == "orsay";
break;
case "mov":
supported = browser == "tizen" || browser == "orsay" || browser == "edge" || browser == "chrome";
break;
case "m2ts":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
break;
case "wmv":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
//videoAudioCodecs = [];
break;
case "ts":
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
break;
case "mp4":
case "m4v":
supported = true;
break;
case "mkv":
supported = browser == "tizen" || browser == "orsay" || browser == "chrome" || browser == "edge";
if (supported)
break;
if (player.canPlayType("video/x-matroska") || player.canPlayType("video/mkv"))
supported = true;
break;
default:
break;
}
return supported;
}
//SHOULD CHECK FOR DEPTH (8bits ok but 10bits unsuported for almost every browsers)
function videoCodecIsSupported(player: HTMLVideoElement, codec: string, browser: string): boolean
{
switch (codec)
{
case "h264":
return !!player.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'); //The !! is used to parse the string as a bool
case "h265":
case "hevc":
if (browser == "tizen" || browser == "orsay" || browser == "xboxOne" || browser == "ios")
return true;
//SHOULD SUPPORT CHROMECAST ULTRA
// if (browser.chromecast)
// {
// var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
// if (isChromecastUltra)
// {
// return true;
// }
// }
return !!player.canPlayType('video/hevc; codecs="hevc, aac"');
case "mpeg2video":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "vc1":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "msmpeg4v2":
return browser == "orsay" || browser == "tizen";
case "vp8":
return !!player.canPlayType('video/webm; codecs="vp8');
case "vp9":
return !!player.canPlayType('video/webm; codecs="vp9"');
case "vorbis":
return browser == "orsay" || browser == "tizen" || !!player.canPlayType('video/webm; codecs="vp8');
default:
return false;
}
}
//SHOULD CHECK FOR NUMBER OF AUDIO CHANNEL (2 ok but 5 not in some browsers)
function audioCodecIsSupported(player: HTMLVideoElement, codecs: string[], browser: string): boolean
{
for (let codec of codecs)
{
switch (codec)
{
case "mp3":
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"') ||
!!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"');
case "aac":
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"');
case "mp2":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "pcm_s16le":
case "pcm_s24le":
return browser == "orsay" || browser == "tizen" || browser == "edge";
case "aac_latm":
return browser == "orsay" || browser == "tizen";
case "opus":
return !!player.canPlayType('audio/ogg; codecs="opus"');
case "flac":
return browser == "orsay" || browser == "tizen" || browser == "edge";
default:
return false;
}
}
}