Skip to content

Seeking fragmented file broken #520

@big-nacho

Description

@big-nacho

I'm trying to seek a timestamp in an mp4 file. The procedure is as follows:

  1. createFile and set onReady / onSamples callbacks
  2. Start appending chunks from the start of the file
  3. As soon as onReady runs, stop appending chunks
  4. setExtractionOptions and file.start()
  5. Call file.seek(time, true) and store the offset
  6. Start appending chunks starting from offset and wait for onSamples callback

I'm still pretty new to the library so if any of the above doesn't make sense, I'd appreciate the feedback.

The result

  • If the file is not fragmented, everything works fine ✅
  • If the file is fragmented:
    • If I feed tiny chunks to the file, it works, but I haven't delved too deep into why that is ✅
    • If I feed reasonably sized chunks (64kb), it doesn't work. I get no calls to onSamples

I think I've managed to track it down to the seekTrack function. In there, there's some arithmetic done with alreadyRead values that are undefined. I don't fully understand why alreadyRead is optional and what it means for it to not be defined, but number + undefined doesn't feel right.

The following change to seekTrack fixed the issue for me, but it feels more like a patch to that particular function than a real fix

MP4Box.ISOFile.prototype.seekTrack = function (time, useRap, trak) {
    let rap_seek_sample_num = 0;
    let seek_sample_num = 0;
    let timescale;
    if (trak.samples.length === 0) {
      return { offset: 0, time: 0 };
    }
    for (let j = 0; j < trak.samples.length; j++) {
      const sample = trak.samples[j];
      if (j === 0) {
        seek_sample_num = 0;
        timescale = sample.timescale;
      } else if (sample.cts > time * sample.timescale) {
        seek_sample_num = j - 1;
        break;
      }
      if (useRap && sample.is_sync) {
        rap_seek_sample_num = j;
      }
    }
    if (useRap) {
      seek_sample_num = rap_seek_sample_num;
    }
    time = trak.samples[seek_sample_num].cts;
    trak.nextSample = seek_sample_num;

    // ========================================= Original =========================================
    while (trak.samples[seek_sample_num].alreadyRead === trak.samples[seek_sample_num].size) {
      if (!trak.samples[seek_sample_num + 1]) {
        break;
      }
      seek_sample_num++;
    }
    const seek_offset = trak.samples[seek_sample_num].offset + trak.samples[seek_sample_num].alreadyRead;
    return { offset: seek_offset, time: time / timescale };
    // ========================================= Original =========================================

    // ========================================= My version =========================================
    let alreadyRead = trak.samples[seek_sample_num].alreadyRead ?? 0;
    while (alreadyRead === trak.samples[seek_sample_num].size) {
      if (!trak.samples[seek_sample_num + 1]) {
        break;
      }
      seek_sample_num++;
      alreadyRead = trak.samples[seek_sample_num].alreadyRead ?? 0;
    }

    const seek_offset = trak.samples[seek_sample_num].offset + alreadyRead;
    return { offset: seek_offset, time: time / timescale };
    // ========================================= My version =========================================
}

It would be great to get some clarity on whether this is an actual bug, and whether the library supports seeking fragmented files altogether.
Thank you 😃

P.S this happens to me with pretty much every fragmented file, but here's one that fails for reference https://drive.google.com/file/d/1OgxDcNcQPJ4MlmW9tN08RjJzVQ0l2CQG/view?usp=sharing

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions