{"record":{"id":"8c57abbb2ced819c","repo":"TeamNewPipe/NewPipe","slug":"mdat-found-without-moof","errorCode":null,"errorMessage":"mdat found without moof","messagePattern":"mdat found without moof","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/org/schabi/newpipe/streams/Mp4DashReader.java","lineNumber":228,"sourceCode":"                            if (hasFlag(moof.traf.tfhd.bFlags, 0x10)) {\n                                moof.traf.trun.chunkSize = moof.traf.tfhd.defaultSampleSize\n                                        * moof.traf.trun.entryCount;\n                            } else {\n                                moof.traf.trun.chunkSize = (int) (box.size - 8);\n                            }\n                        }\n                        if (!hasFlag(moof.traf.trun.bFlags, 0x900)\n                                && moof.traf.trun.chunkDuration == 0) {\n                            if (hasFlag(moof.traf.tfhd.bFlags, 0x20)) {\n                                moof.traf.trun.chunkDuration = moof.traf.tfhd.defaultSampleDuration\n                                        * moof.traf.trun.entryCount;\n                            }\n                        }\n                    }\n                    break;\n                case ATOM_MDAT:\n                    if (moof == null) {\n                        throw new IOException(\"mdat found without moof\");\n                    }\n\n                    if (moof.traf == null) {\n                        moof = null;\n                        continue; // find another chunk\n                    }\n\n                    final Mp4DashChunk chunk = new Mp4DashChunk();\n                    chunk.moof = moof;\n                    if (!infoOnly) {\n                        chunk.data = stream.getView(moof.traf.trun.chunkSize);\n                    }\n\n                    moof = null;\n\n                    stream.skipBytes(chunk.moof.traf.trun.dataOffset);\n                    return chunk;\n                default:","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/TeamNewPipe/NewPipe/blob/9e8be091560a69f35d44bd252eb00bc7911c977b/app/src/main/java/org/schabi/newpipe/streams/Mp4DashReader.java#L210-L246","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Confirm the input is a fragmented MP4 with correct moof→mdat ordering (re-download if suspect).","Pre-validate the ftyp brand (error 21) since a progressive MP4 will hit this after the brand check.","Re-mux the source with a conformant fragmenter.","Ensure range requests include the moof that precedes each mdat."],"exampleFix":"// before — feeding a progressive MP4 to the DASH reader\nnew Mp4DashReader(progressiveStream).parse(); // mdat before moof → IOException\n\n// after — use the fragmented/DASH source for this reader\nnew Mp4DashReader(fragmentedStream).parse();","handlingStrategy":"validation","validationCode":"// Confirm the input is fragmented (moof precedes mdat) via a shallow scan.\npublic static boolean isFragmented(SharpStream s, long scanLimit) throws IOException {\n    long pos = s.position();\n    try {\n        boolean sawMoof = false;\n        while (s.position() < scanLimit) {\n            int size = readInt(s); int type = readInt(s);\n            if (type == 0x6D6F6F66 /*moof*/) sawMoof = true;\n            if (type == 0x6D646174 /*mdat*/) return sawMoof; // valid only if moof seen first\n            s.skip(size - 8);\n        }\n        return false;\n    } finally { s.seek(pos); }\n}","typeGuard":"public static boolean isDashFragmentedMp4(byte[] ftypHead) {\n    if (ftypHead.length < 8) return false;\n    int brand = ((ftypHead[4]&0xFF)<<24)|((ftypHead[5]&0xFF)<<16)|((ftypHead[6]&0xFF)<<8)|(ftypHead[7]&0xFF);\n    return brand == 0x64617368 || brand == 0x69736F35;\n}","tryCatchPattern":"try {\n    reader.parse();\n} catch (IOException e) {\n    if (e.getMessage().contains(\"mdat found without moof\")) {\n        // progressive MP4 or corrupt segment — switch source\n        selectFragmentedDashSource();\n    } else throw e;\n}","preventionTips":["Feed only fragmented DASH MP4 to Mp4DashReader.","Sniff the ftyp brand and scan for moof-before-mdat before parsing.","Re-download segments that arrive out of order or truncated.","Keep progressive MP4 paths separate from DASH paths."],"tags":["mp4","dash","container","corrupt-data","java"],"backgroundTag":null,"analyzedSha":"9e8be091560a69f35d44bd252eb00bc7911c977b","analyzedAt":"2026-08-14T00:11:33.519Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}