Skip to content

Instantly share code, notes, and snippets.

@theodrosyimer
Last active February 28, 2025 08:15
Show Gist options
  • Save theodrosyimer/12dc67ceb37d2f0924f3b869edb53410 to your computer and use it in GitHub Desktop.
Save theodrosyimer/12dc67ceb37d2f0924f3b869edb53410 to your computer and use it in GitHub Desktop.
Get the duration of a video using Node.js and TypeScript
/////////
// Inspired by: https://gist.github.com/Elements-/cf063254730cd754599e
/////////
import type { PathLike } from 'fs'
import { createReadStream } from 'fs'
import { pipeline } from 'stream/promises'
const BUFFER_SIZE = 100
// Define MVHD_HEADER as a Uint8Array directly with the correct bytes
// for proper type compatibility
const MVHD_HEADER = new Uint8Array([0x6d, 0x76, 0x68, 0x64]) // 'mvhd' in hex
async function* videoDurationGenerator(source: AsyncIterable<Buffer>) {
let headerFound = false
let timeScale: number | null = null
let duration: number | null = null
for await (const chunk of source) {
if (headerFound) continue
const mvhdIndex = chunk.indexOf(MVHD_HEADER)
if (mvhdIndex !== -1) {
headerFound = true
const start = mvhdIndex + 16
// Ensure we have enough data to read timeScale and duration
if (chunk.length >= start + 8) {
timeScale = chunk.readUInt32BE(start)
duration = chunk.readUInt32BE(start + 4)
const videoDuration = Math.floor((duration / timeScale) * 1000) / 1000
yield { timeScale, duration, videoDuration }
return // Exit the generator once we have the duration
}
}
}
throw new Error('Could not find MVHD header in video file')
}
export type VideoDuration = {
timeScale: number
duration: number
videoDuration: number
}
export async function getVideoDuration(resource: PathLike) {
try {
const results: VideoDuration[] = []
await pipeline(
createReadStream(resource, { highWaterMark: BUFFER_SIZE }),
async function* (source) {
for await (const result of videoDurationGenerator(source)) {
results.push(result)
yield result
}
},
async function* (source) {
for await (const chunk of source) {
console.log('[chunk]', chunk)
}
},
)
return results[0]
} catch (error) {
console.error('[getVideoDuration] Error processing video:', error)
throw error
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment