mirror of
https://github.com/hexahigh/080609.git
synced 2025-12-11 19:55:06 +01:00
feat: Added browser codec support checker
This commit is contained in:
parent
e71323f02f
commit
8308e02d1f
@ -36,6 +36,7 @@
|
|||||||
"flowbite": "^3.1.2",
|
"flowbite": "^3.1.2",
|
||||||
"flowbite-svelte": "^0.47.4",
|
"flowbite-svelte": "^0.47.4",
|
||||||
"fuse.js": "^7.1.0",
|
"fuse.js": "^7.1.0",
|
||||||
|
"iconify-icon": "^2.3.0",
|
||||||
"mode-watcher": "^0.5.0",
|
"mode-watcher": "^0.5.0",
|
||||||
"msgpackr": "^1.11.2",
|
"msgpackr": "^1.11.2",
|
||||||
"pako": "^2.1.0",
|
"pako": "^2.1.0",
|
||||||
|
|||||||
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@ -26,6 +26,9 @@ importers:
|
|||||||
fuse.js:
|
fuse.js:
|
||||||
specifier: ^7.1.0
|
specifier: ^7.1.0
|
||||||
version: 7.1.0
|
version: 7.1.0
|
||||||
|
iconify-icon:
|
||||||
|
specifier: ^2.3.0
|
||||||
|
version: 2.3.0
|
||||||
mode-watcher:
|
mode-watcher:
|
||||||
specifier: ^0.5.0
|
specifier: ^0.5.0
|
||||||
version: 0.5.0(svelte@5.2.11)
|
version: 0.5.0(svelte@5.2.11)
|
||||||
@ -273,6 +276,9 @@ packages:
|
|||||||
'@floating-ui/utils@0.2.9':
|
'@floating-ui/utils@0.2.9':
|
||||||
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
|
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
|
||||||
|
|
||||||
|
'@iconify/types@2.0.0':
|
||||||
|
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||||
|
|
||||||
'@isaacs/cliui@8.0.2':
|
'@isaacs/cliui@8.0.2':
|
||||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@ -852,6 +858,9 @@ packages:
|
|||||||
html-void-elements@3.0.0:
|
html-void-elements@3.0.0:
|
||||||
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
||||||
|
|
||||||
|
iconify-icon@2.3.0:
|
||||||
|
resolution: {integrity: sha512-C0beI9oTDxQz6voI5CKl7MiJf0Lw4UU8K4G4t6pcUDClLmCvuMOpcvd8MAztQ2SfoH0iv7WHdxBFjekKPFKH2Q==}
|
||||||
|
|
||||||
import-meta-resolve@4.1.0:
|
import-meta-resolve@4.1.0:
|
||||||
resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==}
|
resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==}
|
||||||
|
|
||||||
@ -1724,6 +1733,8 @@ snapshots:
|
|||||||
|
|
||||||
'@floating-ui/utils@0.2.9': {}
|
'@floating-ui/utils@0.2.9': {}
|
||||||
|
|
||||||
|
'@iconify/types@2.0.0': {}
|
||||||
|
|
||||||
'@isaacs/cliui@8.0.2':
|
'@isaacs/cliui@8.0.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
string-width: 5.1.2
|
string-width: 5.1.2
|
||||||
@ -2290,6 +2301,10 @@ snapshots:
|
|||||||
|
|
||||||
html-void-elements@3.0.0: {}
|
html-void-elements@3.0.0: {}
|
||||||
|
|
||||||
|
iconify-icon@2.3.0:
|
||||||
|
dependencies:
|
||||||
|
'@iconify/types': 2.0.0
|
||||||
|
|
||||||
import-meta-resolve@4.1.0: {}
|
import-meta-resolve@4.1.0: {}
|
||||||
|
|
||||||
is-binary-path@2.1.0:
|
is-binary-path@2.1.0:
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import 'iconify-icon';
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{@render children()}
|
{@render children()}
|
||||||
|
|||||||
@ -17,7 +17,21 @@
|
|||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
import { unified } from 'unified';
|
import { unified } from 'unified';
|
||||||
|
|
||||||
let alerts = [];
|
let alerts: {
|
||||||
|
text: string;
|
||||||
|
color:
|
||||||
|
| 'dark'
|
||||||
|
| 'red'
|
||||||
|
| 'yellow'
|
||||||
|
| 'green'
|
||||||
|
| 'indigo'
|
||||||
|
| 'purple'
|
||||||
|
| 'pink'
|
||||||
|
| 'blue'
|
||||||
|
| 'primary'
|
||||||
|
| 'none';
|
||||||
|
icon: string;
|
||||||
|
}[] = $state([]);
|
||||||
|
|
||||||
let conversionOptions = $state({
|
let conversionOptions = $state({
|
||||||
gfm: true,
|
gfm: true,
|
||||||
@ -39,14 +53,15 @@
|
|||||||
|
|
||||||
outputValue = u.processSync(inputValue).toString();
|
outputValue = u.processSync(inputValue).toString();
|
||||||
|
|
||||||
|
alerts.push({ text: 'Conversion successful', color: 'green', icon: 'nrk:check' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
outputValue = e
|
outputValue = e;
|
||||||
alerts.push({ text: e, color: 'red' });
|
alerts.push({ text: e, color: 'red', icon: 'nrk:close' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-screen items-center justify-between gap-4 px-4">
|
<div class="flex min-h-screen flex-col items-center justify-between gap-4 px-4 md:flex-row">
|
||||||
<!-- Left Section -->
|
<!-- Left Section -->
|
||||||
<div class="flex flex-1 flex-col items-center justify-center space-y-2">
|
<div class="flex flex-1 flex-col items-center justify-center space-y-2">
|
||||||
<Label for="markdown-input">Markdown</Label>
|
<Label for="markdown-input">Markdown</Label>
|
||||||
@ -85,9 +100,21 @@
|
|||||||
bind:value={outputValue}
|
bind:value={outputValue}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="toast-container">
|
||||||
{#each alerts as alert}
|
{#each alerts as alert}
|
||||||
<Toast transition={fly} params={{ x: 200 }} color={alert.color} class="mb-4">
|
<Toast transition={fly} params={{ x: 200 }} color={alert.color} class="mb-4">
|
||||||
|
<iconify-icon icon={alert.icon} slot="icon"></iconify-icon>
|
||||||
{alert.text}
|
{alert.text}
|
||||||
</Toast>
|
</Toast>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.toast-container {
|
||||||
|
position: fixed;
|
||||||
|
right: 1rem;
|
||||||
|
bottom: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
211
src/routes/(normal)/supports/+page.svelte
Normal file
211
src/routes/(normal)/supports/+page.svelte
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { getAllAV1Codecs, getAllAVCCodecs, getAllHEVCCodecs, getAllVP9Codecs } from './codecs';
|
||||||
|
|
||||||
|
type ResultType = {
|
||||||
|
name: string;
|
||||||
|
// The result type. If it is a boolean it will be rendered as a tick or cross. If it is a number it will be a percentage of the 'total' value.
|
||||||
|
type?: 'boolean' | 'string' | 'number';
|
||||||
|
supported: boolean | string | number;
|
||||||
|
// Has no effect if the result type is not a number
|
||||||
|
total?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SectionType = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
note: string;
|
||||||
|
results?: ResultType[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Results {
|
||||||
|
sections: SectionType[] = [];
|
||||||
|
addSection(id: string, name: string, description: string, note?: string) {
|
||||||
|
this.sections.push({
|
||||||
|
id: id,
|
||||||
|
name: name,
|
||||||
|
description: description,
|
||||||
|
note: note,
|
||||||
|
results: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
addFormat(sectionId: string, resultData: ResultType) {
|
||||||
|
// Find the section
|
||||||
|
const section = this.sections.find((section) => section.id === sectionId);
|
||||||
|
if (section) {
|
||||||
|
// Add the result
|
||||||
|
section.results.push(resultData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let results = new Results();
|
||||||
|
let isChecking = true;
|
||||||
|
|
||||||
|
const imageFormats: { name: string; mime: string }[] = [
|
||||||
|
{ name: 'AVIF', mime: 'avif' },
|
||||||
|
{ name: 'WEBP', mime: 'webp' },
|
||||||
|
{ name: 'JPEG', mime: 'jpeg' },
|
||||||
|
{ name: 'PNG', mime: 'png' },
|
||||||
|
{ name: 'GIF', mime: 'gif' },
|
||||||
|
{ name: 'BMP', mime: 'bmp' },
|
||||||
|
{ name: 'ICO', mime: 'vnd.microsoft.icon' },
|
||||||
|
{ name: 'SVG', mime: 'svg+xml' },
|
||||||
|
{ name: 'HEIC', mime: 'heic' },
|
||||||
|
{ name: 'HEIF', mime: 'heif' },
|
||||||
|
{ name: 'TIFF', mime: 'tiff' },
|
||||||
|
{ name: 'JPEG XL', mime: 'jxl' }
|
||||||
|
];
|
||||||
|
|
||||||
|
async function checkImageFormat(format: string): Promise<boolean> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = `data:image/${format};base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=`;
|
||||||
|
img.onload = () => resolve(true);
|
||||||
|
img.onerror = () => resolve(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
// Check image formats
|
||||||
|
const imageResults = await Promise.all(
|
||||||
|
imageFormats.map(async (format) => checkImageFormat(format.mime))
|
||||||
|
);
|
||||||
|
results.addSection(
|
||||||
|
'image',
|
||||||
|
'Image Formats',
|
||||||
|
'Image formats detected using data URIs',
|
||||||
|
'This tends to be pretty inaccurate'
|
||||||
|
);
|
||||||
|
imageFormats.forEach((format, i) => {
|
||||||
|
results.addFormat('image', {
|
||||||
|
name: format.name,
|
||||||
|
type: 'boolean',
|
||||||
|
supported: imageResults[i]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
results.addSection('video.codecs', 'Video Codecs', 'Video codecs detected using MediaSource.isTypeSupported(). The larger the number displayed the more variations of the codec are supported.');
|
||||||
|
const av1Codecs = getAllAV1Codecs();
|
||||||
|
const avcCodecs = getAllAVCCodecs();
|
||||||
|
const hevcCodecs = getAllHEVCCodecs();
|
||||||
|
const vp9Codecs = getAllVP9Codecs();
|
||||||
|
let av1CodecsSupported = 0;
|
||||||
|
let avcCodecsSupported = 0;
|
||||||
|
let hevcCodecsSupported = 0;
|
||||||
|
let vp9CodecsSupported = 0;
|
||||||
|
|
||||||
|
av1Codecs.forEach((codec) => {
|
||||||
|
const supported = MediaSource.isTypeSupported(`video/mp4; codecs="${codec.codec}"`);
|
||||||
|
if (supported) {
|
||||||
|
av1CodecsSupported++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
avcCodecs.forEach((codec) => {
|
||||||
|
const supported = MediaSource.isTypeSupported(`video/mp4; codecs="${codec.codec}"`);
|
||||||
|
if (supported) {
|
||||||
|
avcCodecsSupported++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
hevcCodecs.forEach((codec) => {
|
||||||
|
const supported = MediaSource.isTypeSupported(`video/mp4; codecs="${codec.codec}"`);
|
||||||
|
if (supported) {
|
||||||
|
hevcCodecsSupported++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
vp9Codecs.forEach((codec) => {
|
||||||
|
const supported = MediaSource.isTypeSupported(`video/mp4; codecs="${codec.codec}"`);
|
||||||
|
if (supported) {
|
||||||
|
vp9CodecsSupported++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
results.addFormat('video.codecs', {
|
||||||
|
name: 'AV1',
|
||||||
|
type: 'number',
|
||||||
|
supported: av1CodecsSupported,
|
||||||
|
total: av1Codecs.length
|
||||||
|
});
|
||||||
|
results.addFormat('video.codecs', {
|
||||||
|
name: 'AVC',
|
||||||
|
type: 'number',
|
||||||
|
supported: avcCodecsSupported,
|
||||||
|
total: avcCodecs.length
|
||||||
|
});
|
||||||
|
results.addFormat('video.codecs', {
|
||||||
|
name: 'HEVC',
|
||||||
|
type: 'number',
|
||||||
|
supported: hevcCodecsSupported,
|
||||||
|
total: hevcCodecs.length
|
||||||
|
});
|
||||||
|
results.addFormat('video.codecs', {
|
||||||
|
name: 'VP9',
|
||||||
|
type: 'number',
|
||||||
|
supported: vp9CodecsSupported,
|
||||||
|
total: vp9Codecs.length
|
||||||
|
});
|
||||||
|
|
||||||
|
isChecking = false;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="min-h-screen bg-gray-100 px-4 py-8">
|
||||||
|
<div class="mx-auto max-w-2xl space-y-6">
|
||||||
|
<h1 class="text-center text-3xl font-bold text-gray-900">Browser Format Support Checker</h1>
|
||||||
|
|
||||||
|
{#if isChecking}
|
||||||
|
<div class="text-center text-gray-600">Checking supported formats...</div>
|
||||||
|
{:else}
|
||||||
|
{#each results.sections as section}
|
||||||
|
<div class="rounded-lg bg-white p-6 shadow">
|
||||||
|
<h2 class="mb-4 text-xl font-semibold">{section.name}</h2>
|
||||||
|
<p class="mb-2 text-center text-gray-600">{section.description}</p>
|
||||||
|
{#if section.note}
|
||||||
|
<p class="mb-2 text-center text-yellow-600">{section.note}</p>
|
||||||
|
{/if}
|
||||||
|
<ul class="space-y-2">
|
||||||
|
{#each section.results as format}
|
||||||
|
{#if format.type === 'boolean'}
|
||||||
|
<li
|
||||||
|
class="flex items-center justify-between rounded-lg p-3 {format.supported
|
||||||
|
? 'bg-green-50'
|
||||||
|
: 'bg-red-50'}"
|
||||||
|
>
|
||||||
|
<span class="font-medium">{format.name}</span>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<div
|
||||||
|
class={`h-2 w-2 rounded-full ${format.supported ? 'bg-green-500' : 'bg-red-500'}`}
|
||||||
|
/>
|
||||||
|
<span class={format.supported ? 'text-green-700' : 'text-red-700'}>
|
||||||
|
{format.supported ? 'Supported' : 'Not Supported'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{:else if format.type === 'number' && typeof format.supported === 'number'}
|
||||||
|
<li
|
||||||
|
class="flex items-center justify-between rounded-lg p-3"
|
||||||
|
style="background-color: hsl({(format.supported / format.total) * 120}, 100%, 90%)"
|
||||||
|
>
|
||||||
|
<span class="font-medium">{format.name}</span>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<div
|
||||||
|
style="background-color: hsl({(format.supported / format.total) * 120}, 100%, 50%)"
|
||||||
|
class="h-2 w-2 rounded-full"
|
||||||
|
/>
|
||||||
|
<span class="text-gray-700">
|
||||||
|
{format.supported}/{format.total}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
283
src/routes/(normal)/supports/codecs.js
Normal file
283
src/routes/(normal)/supports/codecs.js
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
export function getAllAVCCodecs()
|
||||||
|
{
|
||||||
|
var AVC_PROFILES_DESC = [
|
||||||
|
//{ constrained_set0_flag: true },
|
||||||
|
//{ constrained_set1_flag: true },
|
||||||
|
//{ constrained_set2_flag: true },
|
||||||
|
{ profile_idc: 66, description: "Baseline" },
|
||||||
|
{ profile_idc: 66, description: "Constrained Baseline", constrained_set1_flag: true},
|
||||||
|
{ profile_idc: 77, description: "Main" },
|
||||||
|
{ profile_idc: 77, description: "Constrained Main", constrained_set1_flag: true},
|
||||||
|
{ profile_idc: 88, description: "Extended" },
|
||||||
|
{ profile_idc: 100, description: "High", constrained_set4_flag: false },
|
||||||
|
{ profile_idc: 100, description: "High Progressive", constrained_set4_flag: true },
|
||||||
|
{ profile_idc: 100, description: "Constrained High", constrained_set4_flag: true, constrained_set5_flag: true },
|
||||||
|
{ profile_idc: 110, description: "High 10" },
|
||||||
|
{ profile_idc: 110, description: "High 10 Intra", constrained_set3_flag: true },
|
||||||
|
{ profile_idc: 122, description: "High 4:2:2" },
|
||||||
|
{ profile_idc: 122, description: "High 4:2:2 Intra", constrained_set3_flag: true },
|
||||||
|
{ profile_idc: 244, description: "High 4:4:4 Predictive" },
|
||||||
|
{ profile_idc: 244, description: "High 4:4:4 Intra", constrained_set3_flag: true },
|
||||||
|
{ profile_idc: 44, description: "CAVLC 4:4:4 Intra" }
|
||||||
|
];
|
||||||
|
|
||||||
|
var AVC_PROFILES_IDC = [ 66, 77, 88, 100, 110, 122, 244, 44];
|
||||||
|
var AVC_CONSTRAINTS = [ 0, 4, 8, 16, 32, 64, 128 ];
|
||||||
|
var AVC_LEVELS = [ 10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51, 52];
|
||||||
|
|
||||||
|
var sj, sk, sl;
|
||||||
|
var mimes = [];
|
||||||
|
for (var j in AVC_PROFILES_IDC) {
|
||||||
|
sj = AVC_PROFILES_IDC[j].toString(16);
|
||||||
|
if (sj.length == 1) sj = "0"+sj;
|
||||||
|
for (var k in AVC_CONSTRAINTS) {
|
||||||
|
sk = AVC_CONSTRAINTS[k].toString(16);
|
||||||
|
if (sk.length == 1) sk = "0"+sk;
|
||||||
|
|
||||||
|
var desc = "";
|
||||||
|
for (let i in AVC_PROFILES_DESC) {
|
||||||
|
if (AVC_PROFILES_IDC[j] == AVC_PROFILES_DESC[i].profile_idc) {
|
||||||
|
var c = ((AVC_PROFILES_DESC[i].constrained_set0_flag ? 1 : 0) << 7) |
|
||||||
|
((AVC_PROFILES_DESC[i].constrained_set1_flag ? 1 : 0) << 6) |
|
||||||
|
((AVC_PROFILES_DESC[i].constrained_set2_flag ? 1 : 0) << 5) |
|
||||||
|
((AVC_PROFILES_DESC[i].constrained_set3_flag ? 1 : 0) << 4) |
|
||||||
|
((AVC_PROFILES_DESC[i].constrained_set4_flag ? 1 : 0) << 3) |
|
||||||
|
((AVC_PROFILES_DESC[i].constrained_set5_flag ? 1 : 0) << 2);
|
||||||
|
if (c === AVC_CONSTRAINTS[k]) {
|
||||||
|
desc = AVC_PROFILES_DESC[i].description;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (desc.length > 0) {
|
||||||
|
for (var l in AVC_LEVELS) {
|
||||||
|
sl = AVC_LEVELS[l].toString(16);
|
||||||
|
if (sl.length == 1) sl = "0"+sl;
|
||||||
|
mimes.push({
|
||||||
|
codec: 'avc1.'+sj+sk+sl,
|
||||||
|
description: "AVC "+desc+" Level "+ AVC_LEVELS[l]/10
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mimes;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAllAV1Codecs()
|
||||||
|
{
|
||||||
|
var PROFILES_VALUES = [ 0, 1, 2 ];
|
||||||
|
var PROFILES_NAMES = [ 'Main', 'High', 'Professional' ];
|
||||||
|
var LEVEL_VALUES = [ 0, 1, 2, 3,
|
||||||
|
4, 5, 6, 7,
|
||||||
|
8, 9, 10, 11,
|
||||||
|
12, 13, 14, 15,
|
||||||
|
16, 17, 18, 19,
|
||||||
|
20, 21, 22, 23,
|
||||||
|
31];
|
||||||
|
var LEVEL_NAMES = [ '2.0', '2.1', '2.2', '2.3',
|
||||||
|
'3.0', '3.1', '3.2', '3.3',
|
||||||
|
'4.0', '4.1', '4.2', '4.3',
|
||||||
|
'5.0', '5.1', '5.2', '5.3',
|
||||||
|
'6.0', '6.1', '6.2', '6.3',
|
||||||
|
'7.0', '6.1', '7.2', '7.3',
|
||||||
|
'Max' ];
|
||||||
|
var TIER_VALUES = [ 'M', 'H' ];
|
||||||
|
var TIER_NAMES = [ 'Main', 'High' ];
|
||||||
|
var DEPTH_VALUES = [ 8, 10, 12];
|
||||||
|
var MONOCHROME_VALUES = [ null ];//, 0, 1 ];
|
||||||
|
var CHROMA_SUBSAMPLING_VALUES = [ '000', '001', '010', '011', '100', '101', '110', '111' ];
|
||||||
|
var COLOR_PRIMARIES_VALUES = [ 0, 1, 2];//, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ];
|
||||||
|
var TRANSER_CHARACTERISTICS_VALUES = [ 0, 1, 2];//, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ];
|
||||||
|
var MATRIX_COEFFICIENT_VALUES = [ 0, 1, 2];//, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ];
|
||||||
|
var VIDEO_FULL_RANGE_FLAG_VALUES = [ 0, 1 ];
|
||||||
|
|
||||||
|
var allValues = [];
|
||||||
|
for (var profile in PROFILES_VALUES) {
|
||||||
|
for (var level in LEVEL_VALUES) {
|
||||||
|
var levelString = ''+LEVEL_VALUES[level];
|
||||||
|
if (levelString.length == 1) levelString = "0"+levelString;
|
||||||
|
|
||||||
|
for (var tier in TIER_VALUES) {
|
||||||
|
for (var depth in DEPTH_VALUES) {
|
||||||
|
var depthString = ''+DEPTH_VALUES[depth];
|
||||||
|
if (depthString.length == 1) depthString = "0"+depthString;
|
||||||
|
for (var mono in MONOCHROME_VALUES) {
|
||||||
|
if (MONOCHROME_VALUES[mono]!= null) {
|
||||||
|
for (var chroma in CHROMA_SUBSAMPLING_VALUES) {
|
||||||
|
for (var colorPrimary in COLOR_PRIMARIES_VALUES) {
|
||||||
|
for (var transfer in TRANSER_CHARACTERISTICS_VALUES) {
|
||||||
|
for (var matrix in MATRIX_COEFFICIENT_VALUES) {
|
||||||
|
for (var range in VIDEO_FULL_RANGE_FLAG_VALUES) {
|
||||||
|
allValues.push({
|
||||||
|
codec: 'av01.'+PROFILES_VALUES[profile]+
|
||||||
|
'.'+levelString+
|
||||||
|
''+TIER_VALUES[tier]+
|
||||||
|
'.'+depthString+
|
||||||
|
'.'+MONOCHROME_VALUES[mono]+
|
||||||
|
'.'+CHROMA_SUBSAMPLING_VALUES[chroma]+
|
||||||
|
'.'+COLOR_PRIMARIES_VALUES[colorPrimary]+
|
||||||
|
'.'+TRANSER_CHARACTERISTICS_VALUES[transfer]+
|
||||||
|
'.'+MATRIX_COEFFICIENT_VALUES[matrix]+
|
||||||
|
'.'+VIDEO_FULL_RANGE_FLAG_VALUES[range],
|
||||||
|
description: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
allValues.push({
|
||||||
|
codec: 'av01.'+PROFILES_VALUES[profile]+
|
||||||
|
'.'+levelString+
|
||||||
|
''+TIER_VALUES[tier]+
|
||||||
|
'.'+depthString,
|
||||||
|
description: 'AV1 '+PROFILES_NAMES[profile]+' Profile, level '+LEVEL_NAMES[level]+', '+TIER_NAMES[tier]+ ' tier, '+DEPTH_VALUES[depth]+' bits'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAllHEVCCodecs() {
|
||||||
|
const HEVC_PROFILES_DESC = [
|
||||||
|
{ profile_idc: 1, description: "Main" },
|
||||||
|
{ profile_idc: 2, description: "Main 10" },
|
||||||
|
{ profile_idc: 3, description: "Main Still Picture" },
|
||||||
|
{ profile_idc: 4, description: "Range Extensions" },
|
||||||
|
{ profile_idc: 5, description: "High Throughput" },
|
||||||
|
{ profile_idc: 6, description: "Multiview Main" },
|
||||||
|
{ profile_idc: 7, description: "Scalable Main" },
|
||||||
|
{ profile_idc: 8, description: "3D Main" },
|
||||||
|
{ profile_idc: 9, description: "Screen Content Coding Extensions" },
|
||||||
|
{ profile_idc: 10, description: "Scalable Format Range Extensions" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const HEVC_TIERS = [
|
||||||
|
{ tier: 0, tier_name: 'Main' },
|
||||||
|
{ tier: 1, tier_name: 'High' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const HEVC_LEVELS = [30, 60, 63, 90, 93, 120, 123, 150, 153, 156, 180, 183, 186];
|
||||||
|
const HEVC_CONSTRAINTS = ['B0']; // Placeholder for constraints
|
||||||
|
|
||||||
|
const mimes = [];
|
||||||
|
for (const profile of HEVC_PROFILES_DESC) {
|
||||||
|
for (const tier of HEVC_TIERS) {
|
||||||
|
for (const level of HEVC_LEVELS) {
|
||||||
|
for (const constraint of HEVC_CONSTRAINTS) {
|
||||||
|
const tierCompatibility = tier.tier === 0 ? 6 : 4; // Example-based
|
||||||
|
const levelHex = level.toString(16).toUpperCase().padStart(2, '0');
|
||||||
|
const codec = `hev1.${profile.profile_idc}.${tierCompatibility}.L${levelHex}.${constraint}`;
|
||||||
|
const levelName = (level / 30).toFixed(1);
|
||||||
|
const description = `HEVC ${profile.description}, ${tier.tier_name} Tier, Level ${levelName}`;
|
||||||
|
mimes.push({ codec, description });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mimes;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAllVP9Codecs() {
|
||||||
|
const VP9_PROFILES = [0, 1, 2, 3];
|
||||||
|
const VP9_PROFILE_NAMES = ['Profile 0', 'Profile 1', 'Profile 2', 'Profile 3'];
|
||||||
|
const VP9_LEVELS = [10, 11, 20, 21, 30, 31, 40, 41, 50, 51];
|
||||||
|
const VP9_LEVEL_NAMES = {
|
||||||
|
10: '1.0', 11: '1.1', 20: '2.0', 21: '2.1',
|
||||||
|
30: '3.0', 31: '3.1', 40: '4.0', 41: '4.1',
|
||||||
|
50: '5.0', 51: '5.1'
|
||||||
|
};
|
||||||
|
const VP9_BIT_DEPTHS = [8, 10, 12];
|
||||||
|
const VP9_CHROMA_SUBSAMPLING = [0, 1, 2];
|
||||||
|
const VP9_COLOR_PRIMARIES = [1, 9]; // 1=BT.709, 9=BT.2020
|
||||||
|
const VP9_TRANSFER_CHARACTERISTICS = [1, 15]; // 1=BT.709, 15=HLG
|
||||||
|
const VP9_MATRIX_COEFFICIENTS = [1, 9]; // 1=BT.709, 9=BT.2020
|
||||||
|
const VP9_VIDEO_FULL_RANGE_FLAG = [0, 1];
|
||||||
|
|
||||||
|
const mimes = [];
|
||||||
|
|
||||||
|
const pad = (n) => n.toString().padStart(2, '0');
|
||||||
|
|
||||||
|
const getChromaName = (cs) => {
|
||||||
|
switch (cs) {
|
||||||
|
case 0: return '4:2:0';
|
||||||
|
case 1: return '4:2:2';
|
||||||
|
case 2: return '4:4:4';
|
||||||
|
default: return 'Unknown';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getColorPrimaryName = (cp) => {
|
||||||
|
switch (cp) {
|
||||||
|
case 1: return 'BT.709';
|
||||||
|
case 9: return 'BT.2020';
|
||||||
|
default: return 'Unknown';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTransferName = (tc) => {
|
||||||
|
switch (tc) {
|
||||||
|
case 1: return 'BT.709';
|
||||||
|
case 15: return 'HLG';
|
||||||
|
default: return 'Unknown';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMatrixName = (mc) => {
|
||||||
|
switch (mc) {
|
||||||
|
case 1: return 'BT.709';
|
||||||
|
case 9: return 'BT.2020';
|
||||||
|
default: return 'Unknown';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const profile of VP9_PROFILES) {
|
||||||
|
for (const level of VP9_LEVELS) {
|
||||||
|
const levelName = VP9_LEVEL_NAMES[level] || 'Unknown';
|
||||||
|
for (const bitDepth of VP9_BIT_DEPTHS) {
|
||||||
|
// Minimal codec string
|
||||||
|
const minimalCodec = `vp09.${pad(profile)}.${pad(level)}.${pad(bitDepth)}`;
|
||||||
|
const minimalDesc = `VP9 ${VP9_PROFILE_NAMES[profile]}, Level ${levelName}, ${bitDepth}-bit`;
|
||||||
|
mimes.push({ codec: minimalCodec, description: minimalDesc });
|
||||||
|
|
||||||
|
// Full codec strings with all parameters
|
||||||
|
for (const chroma of VP9_CHROMA_SUBSAMPLING) {
|
||||||
|
for (const colorPrimary of VP9_COLOR_PRIMARIES) {
|
||||||
|
for (const transfer of VP9_TRANSFER_CHARACTERISTICS) {
|
||||||
|
for (const matrix of VP9_MATRIX_COEFFICIENTS) {
|
||||||
|
for (const range of VP9_VIDEO_FULL_RANGE_FLAG) {
|
||||||
|
const codec = [
|
||||||
|
`vp09.${pad(profile)}`,
|
||||||
|
pad(level),
|
||||||
|
pad(bitDepth),
|
||||||
|
pad(chroma),
|
||||||
|
pad(colorPrimary),
|
||||||
|
pad(transfer),
|
||||||
|
pad(matrix),
|
||||||
|
pad(range)
|
||||||
|
].join('.');
|
||||||
|
const desc = [
|
||||||
|
minimalDesc,
|
||||||
|
`Chroma ${getChromaName(chroma)}`,
|
||||||
|
`Color ${getColorPrimaryName(colorPrimary)}`,
|
||||||
|
`Transfer ${getTransferName(transfer)}`,
|
||||||
|
`Matrix ${getMatrixName(matrix)}`,
|
||||||
|
`${range ? 'Full' : 'Limited'} Range`
|
||||||
|
].join(', ');
|
||||||
|
mimes.push({ codec, description: desc });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mimes;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user