天天看點

mp4解包成h264資料進行分析。

1 把h264打包成mp4,請看此文章。包括安裝環境,以及把264打包mp4。

   https://blog.csdn.net/jenie/article/details/105975306

2 今天講解一下反向操作。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <time.h>
#include <sys/time.h>
#include <mp4v2/mp4v2.h>

unsigned char sps[64],pps[64];
int spslen = 0,ppslen = 0;

int get264stream(MP4FileHandle oMp4File,int VTrackId,int totalFrame)
{
    if(!oMp4File) return -1;
    char NAL[5] = {0x00,0x00,0x00,0x01};
    unsigned char *pData = NULL;
    unsigned int nSize = 0;
    MP4Timestamp pStartTime;
    MP4Duration pDuration;
    MP4Duration pRenderingOffset;
    bool pIsSyncSample = 0;

    int nReadIndex = 0;
    FILE *pFile = NULL;
    pFile = fopen("out.h264","wb");

    while(nReadIndex < totalFrame)
    {
        nReadIndex ++;
        //printf("nReadIndex:%d\n",nReadIndex);
        MP4ReadSample(oMp4File,VTrackId,nReadIndex,&pData,&nSize,&pStartTime,&pDuration,&pRenderingOffset,&pIsSyncSample);

        //IDR֡ 幀,寫入sps pps先
        if(pIsSyncSample)
        {
            fwrite(NAL,4,1,pFile);
            fwrite(sps,spslen,1,pFile);

            fwrite(NAL,4,1,pFile);
            fwrite(pps,ppslen,1,pFile);

        }
        //264frame
        if(pData && nSize > 4)
        {
            //标準的264幀,前面幾個位元組就是frame的長度.
            //需要替換為标準的264 nal 頭.
            pData[0] = 0x00;
            pData[1] = 0x00;
            pData[2] = 0x00;
            pData[3] = 0x01;
            fwrite(pData,nSize,1,pFile);
        }

        //如果傳入MP4ReadSample的視訊pData是null
        // 它内部就會new 一個記憶體
        //如果傳入的是已知的記憶體區域,
        //則需要保證空間bigger then max frames size.
        free(pData);
        pData = NULL;
    }
    fflush(pFile);
    fclose(pFile);

    return 0;
}
int openmp4file(char *sMp4file)
{
    MP4FileHandle oMp4File;
    int i;

    //unsigned int oStreamDuration;
    unsigned int oFrameCount;

    oMp4File = MP4Read(sMp4file);
    int videoindex = -1,audioindex = -1;
    uint32_t numSamples;
    //uint32_t timescale;
    //uint64_t duration;        

    if (!oMp4File)
    {
        printf("Read error....%s\r\n",sMp4file);
        return -1;
    }

    MP4TrackId trackId = MP4_INVALID_TRACK_ID;
    uint32_t numTracks = MP4GetNumberOfTracks(oMp4File,NULL,0);
    printf("numTracks:%d\n",numTracks);

    for (i = 0; i < numTracks; i++)
    {
        trackId = MP4FindTrackId(oMp4File, i,NULL,0);
        const char* trackType = MP4GetTrackType(oMp4File, trackId);
        if (MP4_IS_VIDEO_TRACK_TYPE(trackType))
        {
            //printf("[%s %d] trackId:%d\r\n",__FUNCTION__,__LINE__,trackId);
            videoindex= trackId;

            //duration = MP4GetTrackDuration(oMp4File, trackId );
            numSamples = MP4GetTrackNumberOfSamples(oMp4File, trackId);
            //timescale = MP4GetTrackTimeScale(oMp4File, trackId);          
            //oStreamDuration = duration/(timescale/1000);          
            oFrameCount = numSamples;

            // read sps/pps 
            uint8_t **seqheader;
            uint8_t **pictheader;
            uint32_t *pictheadersize;
            uint32_t *seqheadersize;
            uint32_t ix;
            MP4GetTrackH264SeqPictHeaders(oMp4File, trackId, &seqheader, &seqheadersize, &pictheader, &pictheadersize);

            for (ix = 0; seqheadersize[ix] != 0; ix++)
            {
                memcpy(sps, seqheader[ix], seqheadersize[ix]);
                spslen = seqheadersize[ix];
                free(seqheader[ix]);
            }
            free(seqheader);
            free(seqheadersize);

            for (ix = 0; pictheadersize[ix] != 0; ix++)
            {
                memcpy(pps, pictheader[ix], pictheadersize[ix]);
                ppslen = pictheadersize[ix];
                free(pictheader[ix]);
            }
           free(pictheader);
            free(pictheadersize);
        }
        else if (MP4_IS_AUDIO_TRACK_TYPE(trackType))
        {
            audioindex = trackId;
            printf("audioindex:%d\n",audioindex);
        }
    }

    //解析完了mp4,主要是為了擷取sps pps 還有video的trackID
    if(videoindex >= 0)
        get264stream(oMp4File,videoindex,oFrameCount);

    //需要mp4close 否則在嵌入式裝置打開mp4上多了會記憶體洩露挂掉.
    MP4Close(oMp4File,0);
    return 0;
}

int main(void)
{
    openmp4file("sender.mp4");
    return 0;
}

           

直接解包成功,通過vlc或是eseye工具檢視一下資料流。實測成功!

繼續閱讀