⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp4file.cpp

📁 AAC编解码源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 *
 * The Original Code is MPEG4IP.
 *
 * The Initial Developer of the Original Code is Cisco Systems Inc.
 * Portions created by Cisco Systems Inc. are
 * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
 *
 * Contributor(s):
 *      Dave Mackie       dmackie@cisco.com
 *              Alix Marchandise-Franquet alix@cisco.com
 */

#include "mp4common.h"

MP4File::MP4File(u_int32_t verbosity)
{
    m_fileName = NULL;
    m_pFile = NULL;
    m_orgFileSize = 0;
    m_fileSize = 0;
    m_pRootAtom = NULL;
    m_odTrackId = MP4_INVALID_TRACK_ID;

    m_verbosity = verbosity;
    m_mode = 0;
    m_use64bits = false;
    m_useIsma = false;

    m_pModificationProperty = NULL;
    m_pTimeScaleProperty = NULL;
    m_pDurationProperty = NULL;

    m_memoryBuffer = NULL;
    m_memoryBufferSize = 0;
    m_memoryBufferPosition = 0;

    m_numReadBits = 0;
    m_bufReadBits = 0;
    m_numWriteBits = 0;
    m_bufWriteBits = 0;

#ifdef USE_FILE_CALLBACKS
    // These are the default for when no callbacks are specified
    m_userData = (void*)this;
    m_MP4fopen = MP4fopen_cb;
    m_MP4fclose = MP4fclose_cb;
    m_MP4fread = MP4fread_cb;
    m_MP4fwrite = MP4fwrite_cb;
    m_MP4fgetpos = MP4fgetpos_cb;
    m_MP4fsetpos = MP4fsetpos_cb;
    m_MP4filesize = MP4filesize_cb;
#endif
}

MP4File::~MP4File()
{
    MP4Free(m_fileName);
    delete m_pRootAtom;
    for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
        delete m_pTracks[i];
    }
    MP4Free(m_memoryBuffer);    // just in case
}

void MP4File::Read(const char* fileName)
{
    m_fileName = MP4Stralloc(fileName);
    m_mode = 'r';

    Open("rb");

    ReadFromFile();

    CacheProperties();
}

void MP4File::Create(const char* fileName, bool use64bits)
{
    m_fileName = MP4Stralloc(fileName);
    m_mode = 'w';
    m_use64bits = use64bits;

    Open("wb+");

    // generate a skeletal atom tree
    m_pRootAtom = MP4Atom::CreateAtom(NULL);
    m_pRootAtom->SetFile(this);
    m_pRootAtom->Generate();

    CacheProperties();

    // create mdat, and insert it after ftyp, and before moov
    InsertChildAtom(m_pRootAtom, "mdat", 1);

    // start writing
    m_pRootAtom->BeginWrite();
}

void MP4File::Modify(const char* fileName)
{
    m_fileName = MP4Stralloc(fileName);
    m_mode = 'r';

    Open("rb+");
    ReadFromFile();

    m_mode = 'w';

    // find the moov atom
    MP4Atom* pMoovAtom = m_pRootAtom->FindAtom("moov");
    u_int32_t numAtoms;

    if (pMoovAtom == NULL) {
        // there isn't one, odd but we can still proceed
        pMoovAtom = AddChildAtom(m_pRootAtom, "moov");
    } else {
        numAtoms = m_pRootAtom->GetNumberOfChildAtoms();

        // work backwards thru the top level atoms
        int32_t i;
        bool lastAtomIsMoov = true;
        MP4Atom* pLastAtom = NULL;

        for (i = numAtoms - 1; i >= 0; i--) {
            MP4Atom* pAtom = m_pRootAtom->GetChildAtom(i);
            const char* type = pAtom->GetType();

            // get rid of any trailing free or skips
            if (!strcmp(type, "free") || !strcmp(type, "skip")) {
                m_pRootAtom->DeleteChildAtom(pAtom);
                continue;
            }

            if (strcmp(type, "moov")) {
                if (pLastAtom == NULL) {
                    pLastAtom = pAtom;
                    lastAtomIsMoov = false;
                }
                continue;
            }

            // now at moov atom

            // multiple moov atoms?!?
            if (pAtom != pMoovAtom) {
                throw new MP4Error(
                    "Badly formed mp4 file, multiple moov atoms",
                    "MP4Modify");
            }

            if (lastAtomIsMoov) {
                // position to start of moov atom,
                // effectively truncating file
                // prior to adding new mdat
                SetPosition(pMoovAtom->GetStart());

            } else { // last atom isn't moov
                // need to place a free atom
                MP4Atom* pFreeAtom = MP4Atom::CreateAtom("free");

                // in existing position of the moov atom
                m_pRootAtom->InsertChildAtom(pFreeAtom, i);
                m_pRootAtom->DeleteChildAtom(pMoovAtom);
                m_pRootAtom->AddChildAtom(pMoovAtom);

                // write free atom to disk
                SetPosition(pMoovAtom->GetStart());
                pFreeAtom->SetSize(pMoovAtom->GetSize());
                pFreeAtom->Write();

                // finally set our file position to the end of the last atom
                SetPosition(pLastAtom->GetEnd());
            }

            break;
        }
        ASSERT(i != -1);
    }

    CacheProperties();  // of moov atom

    numAtoms = m_pRootAtom->GetNumberOfChildAtoms();

    // insert another mdat prior to moov atom (the last atom)
    MP4Atom* pMdatAtom = InsertChildAtom(m_pRootAtom, "mdat", numAtoms - 1);

    // start writing new mdat
    pMdatAtom->BeginWrite();
}

void MP4File::Optimize(const char* orgFileName, const char* newFileName)
{
#if 1//ndef USE_FILE_CALLBACKS
    m_fileName = MP4Stralloc(orgFileName);
    m_mode = 'r';

    // first load meta-info into memory
    Open("rb");
    ReadFromFile();

    CacheProperties();  // of moov atom

    // now switch over to writing the new file
    MP4Free(m_fileName);

    // create a temporary file if necessary
    if (newFileName == NULL) {
        m_fileName = MP4Stralloc(TempFileName());
    } else {
        m_fileName = MP4Stralloc(newFileName);
    }

    FILE* pReadFile = m_pFile;
    m_pFile = NULL;
    m_mode = 'w';

    Open("wb");

    SetIntegerProperty("moov.mvhd.modificationTime",
        MP4GetAbsTimestamp());

    // writing meta info in the optimal order
    ((MP4RootAtom*)m_pRootAtom)->BeginOptimalWrite();

    // write data in optimal order
    RewriteMdat(pReadFile, m_pFile);

    // finish writing
    ((MP4RootAtom*)m_pRootAtom)->FinishOptimalWrite();

    // cleanup
    fclose(m_pFile);
    m_pFile = NULL;
    fclose(pReadFile);

    // move temporary file into place
    if (newFileName == NULL) {
        Rename(m_fileName, orgFileName);
    }
#else
    throw new MP4Error(errno, "Function not supported when using callbacks", "MP4Optimize");
#endif
}

void MP4File::RewriteMdat(FILE* pReadFile, FILE* pWriteFile)
{
    u_int32_t numTracks = m_pTracks.Size();

    MP4ChunkId* chunkIds = new MP4ChunkId[numTracks];
    MP4ChunkId* maxChunkIds = new MP4ChunkId[numTracks];
    MP4Timestamp* nextChunkTimes = new MP4Timestamp[numTracks];

    for (u_int32_t i = 0; i < numTracks; i++) {
        chunkIds[i] = 1;
        maxChunkIds[i] = m_pTracks[i]->GetNumberOfChunks();
        nextChunkTimes[i] = MP4_INVALID_TIMESTAMP;
    }

    while (true) {
        u_int32_t nextTrackIndex = (u_int32_t)-1;
        MP4Timestamp nextTime = MP4_INVALID_TIMESTAMP;

        for (u_int32_t i = 0; i < numTracks; i++) {
            if (chunkIds[i] > maxChunkIds[i]) {
                continue;
            }

            if (nextChunkTimes[i] == MP4_INVALID_TIMESTAMP) {
                MP4Timestamp chunkTime =
                    m_pTracks[i]->GetChunkTime(chunkIds[i]);

                nextChunkTimes[i] = MP4ConvertTime(chunkTime,
                    m_pTracks[i]->GetTimeScale(), GetTimeScale());
            }

            // time is not earliest so far
            if (nextChunkTimes[i] > nextTime) {
                continue;
            }

            // prefer hint tracks to media tracks if times are equal
            if (nextChunkTimes[i] == nextTime
              && strcmp(m_pTracks[i]->GetType(), MP4_HINT_TRACK_TYPE)) {
                continue;
            }

            // this is our current choice of tracks
            nextTime = nextChunkTimes[i];
            nextTrackIndex = i;
        }

        if (nextTrackIndex == (u_int32_t)-1) {
            break;
        }

        // point into original mp4 file for read chunk call
        m_pFile = pReadFile;
        m_mode = 'r';

        u_int8_t* pChunk;
        u_int32_t chunkSize;

        m_pTracks[nextTrackIndex]->
            ReadChunk(chunkIds[nextTrackIndex], &pChunk, &chunkSize);

        // point back at the new mp4 file for write chunk
        m_pFile = pWriteFile;
        m_mode = 'w';

        m_pTracks[nextTrackIndex]->
            RewriteChunk(chunkIds[nextTrackIndex], pChunk, chunkSize);

        MP4Free(pChunk);

        chunkIds[nextTrackIndex]++;
        nextChunkTimes[nextTrackIndex] = MP4_INVALID_TIMESTAMP;
    }

    delete [] chunkIds;
    delete [] maxChunkIds;
    delete [] nextChunkTimes;
}

void MP4File::Open(const char* fmode)
{
    ASSERT(m_pFile == NULL);

#ifndef USE_FILE_CALLBACKS
#ifdef O_LARGEFILE
    // UGH! fopen doesn't open a file in 64-bit mode, period.
    // So we need to use open() and then fdopen()
    int fd;
    int flags = O_LARGEFILE;

    if (strchr(fmode, '+')) {
        flags |= O_CREAT | O_RDWR;
        if (fmode[0] == 'w') {
            flags |= O_TRUNC;
        }
    } else {
        if (fmode[0] == 'w') {
            flags |= O_CREAT | O_TRUNC | O_WRONLY;
        } else {
            flags |= O_RDONLY;
        }
    }
    fd = open(m_fileName, flags, 0666);

    if (fd >= 0) {
        m_pFile = fdopen(fd, fmode);
    }
#else
    m_pFile = fopen(m_fileName, fmode);
#endif
    if (m_pFile == NULL) {
        throw new MP4Error(errno, "failed", "MP4Open");
    }
#else
    u_int32_t rc = m_MP4fopen(m_fileName, fmode, m_userData);
    if (rc == 0) {
        throw new MP4Error(errno, "failed", "MP4Open");
    }
#endif

    if (m_mode == 'r') {
#ifndef USE_FILE_CALLBACKS
        struct stat s;
        if (fstat(fileno(m_pFile), &s) < 0) {
            throw new MP4Error(errno, "stat failed", "MP4Open");
        }
        m_orgFileSize = m_fileSize = s.st_size;
#else
        int64_t s = m_MP4filesize(m_userData);
        if (s < 0) {
            throw new MP4Error(errno, "retreiving filesize failed", "MP4Open");
        }
        m_orgFileSize = m_fileSize = (u_int64_t)s;
#endif
    } else {
        m_orgFileSize = m_fileSize = 0;
    }
}

void MP4File::ReadFromFile()
{
    // ensure we start at beginning of file
    SetPosition(0);

    // create a new root atom
    ASSERT(m_pRootAtom == NULL);
    m_pRootAtom = MP4Atom::CreateAtom(NULL);

    u_int64_t fileSize = GetSize();

    m_pRootAtom->SetFile(this);
    m_pRootAtom->SetStart(0);
    m_pRootAtom->SetSize(fileSize);
    m_pRootAtom->SetEnd(fileSize);

    m_pRootAtom->Read();

    // create MP4Track's for any tracks in the file
    GenerateTracks();
}

void MP4File::GenerateTracks()
{
    u_int32_t trackIndex = 0;

    while (true) {
        char trackName[32];
        snprintf(trackName, sizeof(trackName), "moov.trak[%u]", trackIndex);

        // find next trak atom
        MP4Atom* pTrakAtom = m_pRootAtom->FindAtom(trackName);

        // done, no more trak atoms
        if (pTrakAtom == NULL) {
            break;
        }

        // find track id property
        MP4Integer32Property* pTrackIdProperty = NULL;
        pTrakAtom->FindProperty(
            "trak.tkhd.trackId",
            (MP4Property**)&pTrackIdProperty);

        // find track type property
        MP4StringProperty* pTypeProperty = NULL;
        pTrakAtom->FindProperty(
            "trak.mdia.hdlr.handlerType",
            (MP4Property**)&pTypeProperty);

        // ensure we have the basics properties
        if (pTrackIdProperty && pTypeProperty) {

            m_trakIds.Add(pTrackIdProperty->GetValue());

            MP4Track* pTrack = NULL;
            try {
                if (!strcmp(pTypeProperty->GetValue(), MP4_HINT_TRACK_TYPE)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -