How to properly decode a partial mp4 video data on js frontend

55 Views Asked by At

I have a server that can http video-stream (send the parts of a video to the http get request with "Range" header). This streaming works properly on Chrome if just putting the link to a video tag. However, I need to take some specific config;s raw data from these mp4 chunks before playing them on the page (specifically moov -> trak -> mdia -> esds). How do I find those configs?

The following code is what I have

For parsing numbers and changing from Little-Endian to Big-Endian:

function parseNumber(data: Uint8Array, offset: number, size: number) {
  let result: number = 0
  for(let i = offset; i < size; i++) {
    result += data[i] * 256 ^ (i - offset)
  }
  return result
}

For parsing strings:

function parseString(data: Uint8Array, offset: number, size: number) {
  return String.fromCharCode(...data.slice(offset, offset + size));
}

For searching for an atom inside of body of another atom:

function lookForChildAtom(data: Uint8Array, offset: number, size: number, lookFor: string | string[]) {
  while(offset < size) {
    let [childAtomSize, childAtomName] = parseAtomSizeAndName(data, offset)

    if(childAtomSize === 1 && childAtomName === 'mdat') {
      childAtomSize = parseNumber(data, offset + 8, 16)
    }

    if(childAtomSize < (MIN_SIZES[childAtomName] ?? 8)) {
      throw Error('The file is invalid: ' + childAtomName + ' atom < ' + MIN_SIZES[childAtomName] ?? '8')
    }

    if(lookFor instanceof Array && lookFor.includes(childAtomName) || childAtomName === lookFor) {
      return [offset, childAtomSize]
    }

    offset += childAtomSize
  }
  return [offset, 0]
}

And, eventually for searching the config I need:

export default function parseMp4ForESDSData(data: Uint8Array) : string {
  let offset = 0;
  let size: number = data.length;

  [offset, size] = lookForChildAtom(data, offset, size, ['moov', 'moof']);
  while(true) {
    const [trakOffset, trakSize] = lookForChildAtom(data, offset, size, 'trak');
    const [mdiaOffset, mdiaSize] = lookForChildAtom(data, trakOffset, trakSize, 'mdia');
    const [hdlrOffset, hdlrSize] = lookForChildAtom(data, mdiaOffset, mdiaSize, 'hdlr');
    const hdlrSubtype = parseString(data, hdlrOffset + HDLRSubtypeStart, HDLRSubtypeSize)

    if(hdlrSubtype === 'soun') {
      [offset, size] = [mdiaOffset, mdiaSize]
      break
    }
    const trackEnd = trakOffset + trakSize
    offset += trackEnd
    size -= trackEnd

    if(size <= 0) {
      throw Error('No sound track in the file')
    }
  }
  [offset, size] = lookForChildAtom(data, offset, size, 'minf');
  [offset, size] = lookForChildAtom(data, offset, size, 'mp4a');
  [offset, size] = lookForChildAtom(data, offset, size, 'esds');


  offset += ESDSElementaryStreamDescriptorStart
  size -= ESDSElementaryStreamDescriptorStart


  return parseString(data, offset, offset + size)
}
0

There are 0 best solutions below