123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712 |
- #include "MpegDashDemuxer.h"
- using namespace bell::mpeg;
- MpegDashDemuxer::MpegDashDemuxer(std::shared_ptr<bell::ByteStream> stream)
- {
- this->reader = std::make_shared<bell::BinaryReader>(stream);
- }
- int readIntFromVector(std::vector<uint8_t> c, size_t offset)
- {
- return ((c[0] << 24) | (c[1] << 16) | (c[2] << 8) | (c[3])) & 0xffffffffL;
- }
- void MpegDashDemuxer::close() {
- reader->close();
- }
- void MpegDashDemuxer::parse()
- {
- // Skip FTYP box
- lastBox = readBox();
- ensureBox(lastBox);
- auto moov = std::make_unique<Moov>();
- while (lastBox->type != ATOM_MOOF)
- {
- ensureBox(lastBox);
- lastBox = readBox();
- if (lastBox->type == ATOM_MOOV)
- {
- // parse moov
- moov = parseMoov(lastBox);
- }
- }
- tracks = std::vector<Mp4Track>(moov->trak.size());
- for (int i = 0; i < tracks.size(); i++)
- {
- tracks[i] = Mp4Track();
- tracks[i].trak = std::move(moov->trak[i]);
- }
- }
- int MpegDashDemuxer::parseMfhd()
- {
- reader->skip(4);
- return reader->readInt();
- }
- long MpegDashDemuxer::parseTfdt()
- {
- uint8_t version = reader->readByte();
- reader->skip(3);
- return version == 0 ? reader->readUInt() : reader->readLong();
- }
- std::unique_ptr<Mp4DashSample> MpegDashDemuxer::getNextSample(std::unique_ptr<Chunk> &chunk)
- {
- auto sample = std::make_unique<Mp4DashSample>();
- if (chunk->size == 0)
- {
- return nullptr;
- }
- if (chunk->i >= chunk->moof->traf->trun->entryCount)
- {
- return nullptr;
- }
- sample->info = getAbsoluteTrunEntry(chunk->moof->traf->trun, chunk->i++, chunk->moof->traf->tfhd);
- sample->data = reader->readBytes(sample->info->sampleSize);
- chunk->sampleRead += sample->info->sampleSize;
- return sample;
- }
- std::unique_ptr<Chunk> MpegDashDemuxer::getNextChunk(bool infoOnly)
- {
- while (reader->position() < reader->size())
- {
- if (chunkZero)
- {
- ensureBox(lastBox);
- lastBox = readBox();
- }
- else
- {
- chunkZero = true;
- }
- if (lastBox->type == ATOM_MOOF)
- {
- lastMoof = parseMoof(lastBox, tracks[0].trak->tkhd->trackId);
- if (lastMoof->traf != nullptr)
- {
- if (hasFlag(lastMoof->traf->trun->bFlags, 0x0001))
- {
- lastMoof->traf->trun->dataOffset -= lastBox->size + 8;
- }
- }
- if (lastMoof->traf->trun->chunkSize < 1)
- {
- if (hasFlag(lastMoof->traf->tfhd->bFlags, 0x10))
- {
- lastMoof->traf->trun->chunkSize = lastMoof->traf->tfhd->defaultSampleSize * lastMoof->traf->trun->entryCount;
- }
- else
- {
- lastMoof->traf->trun->chunkSize = lastBox->size = 8;
- }
- }
- if (!hasFlag(lastMoof->traf->trun->bFlags, 0x900) && lastMoof->traf->trun->chunkDuration == 0)
- {
- if (hasFlag(lastMoof->traf->tfhd->bFlags, 0x20))
- {
- lastMoof->traf->trun->chunkDuration = lastMoof->traf->tfhd->defaultSampleDuration * lastMoof->traf->trun->entryCount;
- }
- }
- }
- if (lastBox->type == ATOM_MDAT)
- {
- if (lastMoof->traf == nullptr)
- {
- lastMoof = nullptr;
- continue;
- }
- auto chunk = std::make_unique<Chunk>();
- chunk->moof = std::move(lastMoof);
- if (!infoOnly)
- {
- chunk->size = chunk->moof->traf->trun->chunkSize;
- }
- lastMoof = nullptr;
- reader->skip(chunk->moof->traf->trun->dataOffset);
- return chunk;
- }
- }
- return std::unique_ptr<Chunk>(nullptr);
- }
- size_t MpegDashDemuxer::position() {
- return reader->position();
- }
- std::unique_ptr<Moof> MpegDashDemuxer::parseMoof(std::unique_ptr<MpegBox> &ref, int trackId)
- {
- auto moof = std::make_unique<Moof>();
- auto box = readBox();
- moof->mfgdSequenceNumber = parseMfhd();
- ensureBox(box);
- box = untilBox(ref, ATOM_TRAF);
- while (box)
- {
- moof->traf = parseTraf(box, trackId);
- ensureBox(box);
- if (moof->traf->tfdt != -1)
- {
- return moof;
- }
- box = untilBox(ref, ATOM_TRAF);
- }
- return moof;
- }
- std::unique_ptr<Traf> MpegDashDemuxer::parseTraf(std::unique_ptr<MpegBox> &ref, int trackId)
- {
- auto traf = std::make_unique<Traf>();
- auto box = readBox();
- traf->tfhd = parseTfhd(trackId);
- ensureBox(box);
- box = untilBox(ref, ATOM_TRUN, ATOM_TFDT);
- if (box->type == ATOM_TFDT)
- {
- traf->tfdt = parseTfdt();
- ensureBox(box);
- box = readBox();
- }
- traf->trun = parseTrun();
- ensureBox(box);
- return traf;
- }
- std::unique_ptr<Trun> MpegDashDemuxer::parseTrun()
- {
- auto trun = std::make_unique<Trun>();
- trun->bFlags = reader->readInt();
- trun->entryCount = reader->readInt();
- trun->entriesRowSize = 0;
- if (hasFlag(trun->bFlags, 0x0100))
- {
- trun->entriesRowSize += 4;
- }
- if (hasFlag(trun->bFlags, 0x0200))
- {
- trun->entriesRowSize += 4;
- }
- if (hasFlag(trun->bFlags, 0x0400))
- {
- trun->entriesRowSize += 4;
- }
- if (hasFlag(trun->bFlags, 0x0800))
- {
- trun->entriesRowSize += 4;
- }
- if (hasFlag(trun->bFlags, 0x0001))
- {
- trun->dataOffset = reader->readInt();
- }
- if (hasFlag(trun->bFlags, 0x0004))
- {
- trun->bFirstSampleFlags = reader->readInt();
- }
- trun->bEntries = reader->readBytes(trun->entriesRowSize * trun->entryCount);
- trun->chunkSize = 0;
- for (int i = 0; i < trun->entryCount; i++)
- {
- auto entry = getTrunEntry(trun, i);
- if (hasFlag(trun->bFlags, 0x0100))
- {
- trun->chunkDuration += entry->sampleDuration;
- }
- if (hasFlag(trun->bFlags, 0x200))
- {
- trun->chunkSize += entry->sampleSize;
- }
- if (hasFlag(trun->bFlags, 0x0800))
- {
- if (!hasFlag(trun->bFlags, 0x0100))
- {
- trun->chunkDuration += entry->sampleCompositionTimeOffset;
- }
- }
- }
- return trun;
- }
- std::unique_ptr<TrunEntry> MpegDashDemuxer::getTrunEntry(std::unique_ptr<Trun> &trun, int i)
- {
- std::vector<uint8_t> subBuffer(
- trun->bEntries.begin() + (i * trun->entriesRowSize),
- trun->bEntries.begin() + ((i + 1) * trun->entriesRowSize));
- auto entry = std::make_unique<TrunEntry>();
- if (hasFlag(trun->bFlags, 0x0100))
- {
- entry->sampleDuration = readIntFromVector(subBuffer, 0);
- }
- if (hasFlag(trun->bFlags, 0x0200))
- {
- entry->sampleSize = readIntFromVector(subBuffer, 0);
- }
- if (hasFlag(trun->bFlags, 0x0400))
- {
- entry->sampleFlags = readIntFromVector(subBuffer, 0);
- }
- if (hasFlag(trun->bFlags, 0x800))
- {
- entry->sampleCompositionTimeOffset = readIntFromVector(subBuffer, 0);
- }
- entry->hasCompositionTimeOffset = hasFlag(trun->bFlags, 0x0800);
- entry->isKeyframe = !hasFlag(entry->sampleFlags, 0x10000);
- return entry;
- }
- std::unique_ptr<TrunEntry> MpegDashDemuxer::getAbsoluteTrunEntry(std::unique_ptr<Trun> &trun, int i, std::unique_ptr<Tfhd> &header)
- {
- std::unique_ptr<TrunEntry> entry = getTrunEntry(trun, i);
- if (!hasFlag(trun->bFlags, 0x0100) && hasFlag(header->bFlags, 0x20))
- {
- entry->sampleFlags = header->defaultSampleFlags;
- }
- if (!hasFlag(trun->bFlags, 0x0200) && hasFlag(header->bFlags, 0x10))
- {
- entry->sampleSize = header->defaultSampleSize;
- }
- if (!hasFlag(trun->bFlags, 0x0100) && hasFlag(header->bFlags, 0x08))
- {
- entry->sampleDuration = header->defaultSampleDuration;
- }
- if (i == 0 && hasFlag(trun->bFlags, 0x0004))
- {
- entry->sampleFlags = trun->bFirstSampleFlags;
- }
- return entry;
- }
- std::unique_ptr<Tfhd> MpegDashDemuxer::parseTfhd(int trackId)
- {
- auto tfhd = std::make_unique<Tfhd>();
- tfhd->bFlags = reader->readInt();
- tfhd->trackId = reader->readInt();
- if (trackId != -1 && tfhd->trackId != trackId)
- {
- return tfhd;
- }
- if (hasFlag(tfhd->bFlags, 0x01))
- {
- reader->skip(8);
- }
- if (hasFlag(tfhd->bFlags, 0x02))
- {
- reader->skip(4);
- }
- if (hasFlag(tfhd->bFlags, 0x08))
- {
- tfhd->defaultSampleDuration = reader->readInt();
- }
- if (hasFlag(tfhd->bFlags, 0x10))
- {
- tfhd->defaultSampleSize = reader->readInt();
- }
- if (hasFlag(tfhd->bFlags, 0x20))
- {
- tfhd->defaultSampleFlags = reader->readInt();
- }
- return tfhd;
- }
- bool MpegDashDemuxer::hasFlag(int flags, int mask)
- {
- return (flags & mask) == mask;
- }
- std::unique_ptr<Moov> MpegDashDemuxer::parseMoov(std::unique_ptr<MpegBox> &ref)
- {
- auto moov = std::make_unique<Moov>();
- auto box = readBox();
- moov->mvhd = parseMvhd();
- moov->mvexTrex = std::vector<Trex>();
- ensureBox(box);
- moov->trak = std::vector<std::unique_ptr<Trak>>();
- box = untilBox(ref, ATOM_TRAK, ATOM_MVEX);
- while (box)
- {
- if (box->type == ATOM_TRAK)
- {
- moov->trak.push_back(parseTrak(box));
- }
- if (box->type == ATOM_MVEX)
- {
- moov->mvexTrex = parseMvex(box, moov->mvhd->nextTrackId);
- }
- ensureBox(box);
- box = untilBox(ref, ATOM_TRAK, ATOM_MVEX);
- }
- return moov;
- }
- Trex MpegDashDemuxer::parseTrex()
- {
- reader->skip(4);
- Trex trex;
- trex.trackId = reader->readInt();
- trex.defaultSampleDescriptionIndex = reader->readInt();
- trex.defaultSampleDuration = reader->readInt();
- trex.defaultSampleSize = reader->readInt();
- trex.defaultSampleFlags = reader->readInt();
- return trex;
- }
- std::vector<Trex> MpegDashDemuxer::parseMvex(std::unique_ptr<MpegBox> &ref, int possibleTrackCount)
- {
- auto trexs = std::vector<Trex>();
- auto box = untilBox(ref, ATOM_TREX);
- while (box)
- {
- trexs.push_back(parseTrex());
- ensureBox(box);
- box = untilBox(ref, ATOM_TREX);
- }
- return trexs;
- }
- std::vector<uint8_t> MpegDashDemuxer::readFullBox(std::unique_ptr<MpegBox> &ref)
- {
- auto size = ref->size;
- std::vector<uint8_t> header(8);
- header.at(0) = *((uint8_t *)&ref->size + 0);
- header.at(1) = *((uint8_t *)&ref->size + 1);
- header.at(2) = *((uint8_t *)&ref->size + 2);
- header.at(3) = *((uint8_t *)&ref->size + 3);
- header.at(4) = *((uint8_t *)&ref->type + 0);
- header.at(5) = *((uint8_t *)&ref->type + 1);
- header.at(6) = *((uint8_t *)&ref->type + 2);
- header.at(7) = *((uint8_t *)&ref->type + 3);
- std::vector<uint8_t> data = reader->readBytes(size - 8);
- header.insert(header.end(), data.begin(), data.end());
- return header;
- }
- std::unique_ptr<Tkhd> MpegDashDemuxer::parseTkhd()
- {
- auto tkhd = std::make_unique<Tkhd>();
- uint8_t version = reader->readByte();
- // flags
- // creation entries_time
- // modification entries_time
- reader->skip(3 + (2 * (version == 0 ? 4 : 8)));
- tkhd->trackId = reader->readInt();
- reader->skip(4);
- tkhd->duration = version == 0 ? reader->readUInt() : reader->readLong();
- reader->skip(2 * 4);
- tkhd->bLayer = reader->readShort();
- tkhd->bAlternateGroup = reader->readShort();
- tkhd->bVolume = reader->readShort();
- reader->skip(2);
- tkhd->matrix = reader->readBytes(9 * 4);
- tkhd->bWidth = reader->readInt();
- tkhd->bHeight = reader->readInt();
- return tkhd;
- }
- std::unique_ptr<Trak> MpegDashDemuxer::parseTrak(std::unique_ptr<MpegBox> &ref)
- {
- auto trak = std::make_unique<Trak>();
- auto box = readBox();
- trak->tkhd = parseTkhd();
- ensureBox(box);
- box = untilBox(ref, ATOM_MDIA, ATOM_EDTS);
- while (box)
- {
- if (box->type == ATOM_MDIA)
- {
- trak->mdia = parseMdia(box);
- }
- if (box->type == ATOM_EDTS)
- {
- trak->edstElst = parseEdts(box);
- }
- ensureBox(box);
- box = untilBox(ref, ATOM_MDIA, ATOM_EDTS);
- }
- return trak;
- }
- std::unique_ptr<Minf> MpegDashDemuxer::parseMinf(std::unique_ptr<MpegBox> &ref)
- {
- auto minf = std::make_unique<Minf>();
- auto box = untilAnyBox(ref);
- while (box)
- {
- if (box->type == ATOM_DINF)
- {
- minf->dinf = readFullBox(box);
- }
- if (box->type == ATOM_STBL)
- {
- minf->stblStsd = parseStbl(box);
- }
- if (box->type == ATOM_VMHD || box->type == ATOM_SMHD)
- {
- minf->mhd = readFullBox(box);
- }
- ensureBox(box);
- box = untilAnyBox(ref);
- }
- return minf;
- }
- std::vector<uint8_t> MpegDashDemuxer::parseStbl(std::unique_ptr<MpegBox> &ref)
- {
- auto box = untilBox(ref, ATOM_STSD);
- return readFullBox(box);
- }
- std::unique_ptr<Elst> MpegDashDemuxer::parseEdts(std::unique_ptr<MpegBox> &ref)
- {
- auto elst = std::make_unique<Elst>();
- auto box = untilBox(ref, ATOM_ELST);
- bool v1 = reader->readByte() == 1;
- reader->skip(3); // flags
- int entryCount = reader->readInt();
- if (entryCount < 1)
- {
- elst->bMediaRate = 0x00010000;
- return elst;
- }
- if (v1)
- {
- reader->skip(8); // duration
- elst->mediaTime = reader->readLong();
- // ignore all entries
- reader->skip((entryCount - 1) * 16);
- }
- else
- {
- reader->skip(4); // segment duration
- elst->mediaTime = reader->readInt();
- }
- elst->bMediaRate = reader->readInt();
- return elst;
- }
- std::unique_ptr<Hdlr> MpegDashDemuxer::parseHdlr(std::unique_ptr<MpegBox> &box)
- {
- auto hdlr = std::make_unique<Hdlr>();
- reader->skip(4);
- hdlr->type = reader->readInt();
- hdlr->subType = reader->readInt();
- hdlr->bReserved = reader->readBytes(12);
- reader->skip((box->offset + box->size) - reader->position());
- return hdlr;
- }
- std::unique_ptr<Mdia> MpegDashDemuxer::parseMdia(std::unique_ptr<MpegBox> &ref)
- {
- auto mdia = std::make_unique<Mdia>();
- auto box = untilBox(ref, ATOM_MDHD, ATOM_HDLR, ATOM_MINF);
- while (box)
- {
- if (box->type == ATOM_MDHD)
- {
- mdia->mdhd = readFullBox(box);
- }
- if (box->type == ATOM_HDLR)
- {
- mdia->hdlr = parseHdlr(box);
- }
- if (box->type == ATOM_MINF)
- {
- mdia->minf = parseMinf(box);
- }
- ensureBox(box);
- box = untilBox(ref, ATOM_MDHD, ATOM_HDLR, ATOM_MINF);
- }
- return mdia;
- }
- std::unique_ptr<Mvhd> MpegDashDemuxer::parseMvhd()
- {
- auto mvhd = std::make_unique<Mvhd>();
- uint8_t version = reader->readByte();
- reader->skip(3); // flags
- // creation entries_time
- // modification entries_time
- reader->skip(2 * (version == 0 ? 4 : 8));
- mvhd->timeScale = reader->readUInt();
- // chunkDuration
- reader->skip(version == 0 ? 4 : 8);
- // rate
- // volume
- // reserved
- // matrix array
- // predefined
- reader->skip(76);
- mvhd->nextTrackId = reader->readUInt();
- return mvhd;
- }
- void MpegDashDemuxer::ensureBox(std::unique_ptr<MpegBox> &box)
- {
- reader->skip(box->offset + box->size - reader->position());
- }
- std::unique_ptr<MpegBox> MpegDashDemuxer::readBox()
- {
- auto box = std::make_unique<MpegBox>();
- box->offset = reader->position();
- box->size = reader->readUInt();
- box->type = reader->readInt();
- if (box->size == 1)
- {
- box->size = reader->readLong();
- }
- return box;
- }
- std::unique_ptr<MpegBox> MpegDashDemuxer::untilBox(std::unique_ptr<MpegBox> &ref, int boxType1, int boxType2, int boxType3)
- {
- auto box = std::make_unique<MpegBox>();
- while (reader->position() < (ref->offset + ref->size))
- {
- box = readBox();
- if (box->type == boxType1 || box->type == boxType2 || box->type == boxType3)
- {
- return box;
- }
- ensureBox(box);
- }
- return std::unique_ptr<MpegBox>(nullptr);
- }
- std::unique_ptr<MpegBox> MpegDashDemuxer::untilBox(std::unique_ptr<MpegBox> &ref, int boxType1, int boxType2)
- {
- auto box = std::make_unique<MpegBox>();
- while (reader->position() < (ref->offset + ref->size))
- {
- box = readBox();
- if (box->type == boxType1 || box->type == boxType2)
- {
- return box;
- }
- ensureBox(box);
- }
- return std::unique_ptr<MpegBox>(nullptr);
- }
- std::unique_ptr<MpegBox> MpegDashDemuxer::untilBox(std::unique_ptr<MpegBox> &ref, int boxType1)
- {
- auto box = std::make_unique<MpegBox>();
- while (reader->position() < (ref->offset + ref->size))
- {
- box = readBox();
- if (box->type == boxType1)
- {
- return box;
- }
- ensureBox(box);
- }
- return std::unique_ptr<MpegBox>(nullptr);
- }
- std::unique_ptr<MpegBox> MpegDashDemuxer::untilAnyBox(std::unique_ptr<MpegBox> &ref)
- {
- if (reader->position() >= (ref->offset + ref->size))
- {
- return std::unique_ptr<MpegBox>(nullptr);
- }
- return readBox();
- }
|