TeamNewPipe/NewPipe · error · IOException

mdat found without moof

Error message

mdat found without moof

What it means

In nextChunk(), an mdat (Media Data) box is found while moof is null. Fragmented MP4 requires every mdat to be preceded by its describing moof; an mdat with no preceding fragment header has no sample table and cannot be decoded. The IOException stops the parse rather than reading uninterpretable bytes.

Source

Thrown at app/src/main/java/org/schabi/newpipe/streams/Mp4DashReader.java:228

                            if (hasFlag(moof.traf.tfhd.bFlags, 0x10)) {
                                moof.traf.trun.chunkSize = moof.traf.tfhd.defaultSampleSize
                                        * moof.traf.trun.entryCount;
                            } else {
                                moof.traf.trun.chunkSize = (int) (box.size - 8);
                            }
                        }
                        if (!hasFlag(moof.traf.trun.bFlags, 0x900)
                                && moof.traf.trun.chunkDuration == 0) {
                            if (hasFlag(moof.traf.tfhd.bFlags, 0x20)) {
                                moof.traf.trun.chunkDuration = moof.traf.tfhd.defaultSampleDuration
                                        * moof.traf.trun.entryCount;
                            }
                        }
                    }
                    break;
                case ATOM_MDAT:
                    if (moof == null) {
                        throw new IOException("mdat found without moof");
                    }

                    if (moof.traf == null) {
                        moof = null;
                        continue; // find another chunk
                    }

                    final Mp4DashChunk chunk = new Mp4DashChunk();
                    chunk.moof = moof;
                    if (!infoOnly) {
                        chunk.data = stream.getView(moof.traf.trun.chunkSize);
                    }

                    moof = null;

                    stream.skipBytes(chunk.moof.traf.trun.dataOffset);
                    return chunk;
                default:

View on GitHub (pinned to 9e8be09156)

Solutions

  1. Confirm the input is a fragmented MP4 with correct moof→mdat ordering (re-download if suspect).
  2. Pre-validate the ftyp brand (error 21) since a progressive MP4 will hit this after the brand check.
  3. Re-mux the source with a conformant fragmenter.
  4. Ensure range requests include the moof that precedes each mdat.

Example fix

// before — feeding a progressive MP4 to the DASH reader
new Mp4DashReader(progressiveStream).parse(); // mdat before moof → IOException

// after — use the fragmented/DASH source for this reader
new Mp4DashReader(fragmentedStream).parse();
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the input is fragmented (moof precedes mdat) via a shallow scan.
public static boolean isFragmented(SharpStream s, long scanLimit) throws IOException {
    long pos = s.position();
    try {
        boolean sawMoof = false;
        while (s.position() < scanLimit) {
            int size = readInt(s); int type = readInt(s);
            if (type == 0x6D6F6F66 /*moof*/) sawMoof = true;
            if (type == 0x6D646174 /*mdat*/) return sawMoof; // valid only if moof seen first
            s.skip(size - 8);
        }
        return false;
    } finally { s.seek(pos); }
}

Type guard

public static boolean isDashFragmentedMp4(byte[] ftypHead) {
    if (ftypHead.length < 8) return false;
    int brand = ((ftypHead[4]&0xFF)<<24)|((ftypHead[5]&0xFF)<<16)|((ftypHead[6]&0xFF)<<8)|(ftypHead[7]&0xFF);
    return brand == 0x64617368 || brand == 0x69736F35;
}

Try / catch

try {
    reader.parse();
} catch (IOException e) {
    if (e.getMessage().contains("mdat found without moof")) {
        // progressive MP4 or corrupt segment — switch source
        selectFragmentedDashSource();
    } else throw e;
}

Prevention

When it happens

Trigger: A fragmented MP4 whose box order places mdat before moof, or a file with an orphan mdat (e.g. a progressive MP4's mdat leaking into DASH parsing). Also a partially over-written segment where moof was lost but mdat survived.

Common situations: Wrong file type fed to the DASH reader (a progressive MP4 has mdat early, no moof); a corrupted segment missing its moof; a download that started mid-file skipping the moof header.

Related errors


AI-assisted analysis of TeamNewPipe/NewPipe@9e8be09156 (2026-08-14). Data as JSON: /api/errors/8c57abbb2ced819c. Report an issue: GitHub.