diff --git a/assets/big-buck-bunny-trimmed.mp4 b/assets/big-buck-bunny-trimmed.mp4 new file mode 100644 index 0000000..dd8de4f Binary files /dev/null and b/assets/big-buck-bunny-trimmed.mp4 differ diff --git a/assets/download-icon.svg b/assets/download-icon.svg new file mode 100644 index 0000000..4158264 --- /dev/null +++ b/assets/download-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/github-mark.svg b/assets/github-mark.svg new file mode 100644 index 0000000..37fa923 --- /dev/null +++ b/assets/github-mark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/mediakit-logo.svg b/assets/mediakit-logo.svg new file mode 100644 index 0000000..458fbad --- /dev/null +++ b/assets/mediakit-logo.svg @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/dev/convert.html b/dev/convert.html index 459e554..7f9fde7 100644 --- a/dev/convert.html +++ b/dev/convert.html @@ -66,6 +66,7 @@ }, */ video: { + width: 640 //forceReencode: true, //rotate: 90 //width: 720 ?? 2160, @@ -77,10 +78,10 @@ //width: 200, //height: 100, }, - //trim: { - // start: 0, - // end: 30 - //}, + trim: { + start: 0, + end: 40 + }, computeProgress: true }); console.log(conversion); diff --git a/examples/example-a/index.html b/examples/example-a/index.html deleted file mode 100644 index a9ff60f..0000000 --- a/examples/example-a/index.html +++ /dev/null @@ -1,3 +0,0 @@ -

hello!

- - \ No newline at end of file diff --git a/examples/example-a/script.ts b/examples/example-a/script.ts deleted file mode 100644 index bf9b28a..0000000 --- a/examples/example-a/script.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as Mediakit from 'mediakit'; - -console.log(Mediakit); diff --git a/examples/example-b/index.html b/examples/example-b/index.html deleted file mode 100644 index 6862400..0000000 --- a/examples/example-b/index.html +++ /dev/null @@ -1,3 +0,0 @@ -

goodbye!

- - \ No newline at end of file diff --git a/examples/example-b/script.ts b/examples/example-b/script.ts deleted file mode 100644 index 9216262..0000000 --- a/examples/example-b/script.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as Mediakit from 'mediakit'; - -console.log('kekw', Mediakit); diff --git a/examples/index.css b/examples/index.css new file mode 100644 index 0000000..ead0cb3 --- /dev/null +++ b/examples/index.css @@ -0,0 +1,8 @@ +@import "tailwindcss"; + +@layer base { + button:not(:disabled), + [role="button"]:not(:disabled) { + cursor: pointer; + } +} diff --git a/examples/metadata-extraction/index.html b/examples/metadata-extraction/index.html new file mode 100644 index 0000000..5ba19b2 --- /dev/null +++ b/examples/metadata-extraction/index.html @@ -0,0 +1,58 @@ + + + + + + + Metadata extraction example | Mediakit + + + + + +

Metadata extraction example

+

Select or drop a media file, and Mediakit will start extracting various metadata about that file.

+ +
+ + + + + +
+

+ + + +

+
+ +
+ +

Mediakit

+
+ + + +

View source code

+
+ + + + diff --git a/examples/metadata-extraction/metadata-extraction.ts b/examples/metadata-extraction/metadata-extraction.ts new file mode 100644 index 0000000..b83bd24 --- /dev/null +++ b/examples/metadata-extraction/metadata-extraction.ts @@ -0,0 +1,177 @@ +import { Input, ALL_FORMATS, BlobSource } from 'mediakit'; + +const selectMediaButton = document.querySelector('button')!; +const fileNameElement = document.querySelector('#file-name')!; +const horizontalRule = document.querySelector('hr')!; +const bytesReadElement = document.querySelector('#bytes-read')!; +const metadataContainer = document.querySelector('#metadata-container')!; + +const extractMetadata = (file: File) => { + // Create a new input from the file + const input = new Input({ + source: new BlobSource(file), + formats: ALL_FORMATS, // Accept all formats + }); + + let bytesRead = 0; + let fileSize: number | null = null; + + const updateBytesRead = () => { + bytesReadElement.textContent = `Bytes read: ${bytesRead} / ${fileSize === null ? '?' : fileSize}`; + + if (fileSize !== null) { + bytesReadElement.textContent += ` (${(100 * bytesRead / fileSize).toPrecision(3)}% of entire file)`; + } + }; + + input.source.onread = (start, end) => { + bytesRead += end - start; + updateBytesRead(); + }; + + // Get the input's size + void input.source.getSize().then(size => fileSize = size); + + // This object contains all the data that gets displayed: + const object = { + 'Format': input.getFormat().then(format => format.getName()), + 'Full MIME type': input.getMimeType(), + 'Duration': input.computeDuration().then(duration => `${duration} seconds`), + 'Tracks': input.getTracks().then(tracks => tracks.map(track => ({ + 'Type': track.type, + 'Codec': track.codec, + 'Full codec string': track.getCodecParameterString(), + 'Duration': track.computeDuration().then(duration => `${duration} seconds`), + 'Language code': track.languageCode, + ...(track.isVideoTrack() + ? { + 'Coded width': `${track.codedWidth} pixels`, + 'Coded height': `${track.codedHeight} pixels`, + 'Rotation': `${track.rotation}° clockwise`, + } + : track.isAudioTrack() + ? { + 'Number of channels': track.numberOfChannels, + 'Sample rate': `${track.sampleRate} Hz`, + } + : {}), + 'Packet statistics': shortDelay().then(() => track.computePacketStats()).then(stats => ({ + 'Packet count': stats.packetCount, + 'Average packet rate': `${stats.averagePacketRate} Hz${track.isVideoTrack() ? ' (FPS)' : ''}`, + 'Average bitrate': `${stats.averageBitrate} bps`, + })), + ...(track.isVideoTrack() + ? { + 'Color space': track.getColorSpace().then(colorSpace => ({ + 'Color primaries': colorSpace.primaries ?? 'Unknown', + 'Transfer characteristics': colorSpace.transfer ?? 'Unknown', + 'Matrix coefficients': colorSpace.matrix ?? 'Unknown', + 'Full range': colorSpace.fullRange ?? 'Unknown', + 'HDR': track.hasHighDynamicRange(), + })), + } + : {} + ), + }))), + }; + + fileNameElement.textContent = file.name; + horizontalRule.style.display = ''; + bytesReadElement.innerHTML = ''; + metadataContainer.innerHTML = ''; + + const htmlElement = renderValue(object); + metadataContainer.append(bytesReadElement, htmlElement); +}; + +selectMediaButton.addEventListener('click', () => { + const fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.addEventListener('change', () => { + const file = fileInput.files?.[0]; + if (!file) { + return; + } + + extractMetadata(file); + }); + + fileInput.click(); +}); + +document.addEventListener('dragover', (event) => { + event.preventDefault(); + event.dataTransfer!.dropEffect = 'copy'; +}); + +document.addEventListener('drop', (event) => { + event.preventDefault(); + const files = event.dataTransfer?.files; + const file = files && files.length > 0 ? files[0] : undefined; + if (file) { + extractMetadata(file); + } +}); + +// Creates an HTML element to display any given value +const renderValue = (value: unknown) => { + if (Array.isArray(value)) { + const arrayAsObject: Record = Object.fromEntries( + value.map((item, index) => [(index + 1).toString(), item]), + ); + return renderObject(arrayAsObject); + } else if (typeof value === 'object' && value !== null) { + return renderObject(value as Record); + } else { + const spanElement = document.createElement('span'); + spanElement.textContent = String(value); + return spanElement; + } +}; + +// Returns a