import { Input, ALL_FORMATS, BlobSource } from 'mediabunny'; const selectMediaButton = document.querySelector('button') as HTMLButtonElement; const fileNameElement = document.querySelector('#file-name') as HTMLParagraphElement; const horizontalRule = document.querySelector('hr') as HTMLHRElement; const bytesReadElement = document.querySelector('#bytes-read') as HTMLParagraphElement; const metadataContainer = document.querySelector('#metadata-container') as HTMLDivElement; 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.name), '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); }; // 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