linux下利用MP4v2封裝H264 aac爲mp4

mp4文件格式:https://wenku.baidu.com/view/673482284b73f242336c5f4c.html

MP4v2開源庫:https://download.csdn.net/download/lq496387202/10515621

mp4v2簡介記錄:https://blog.csdn.net/yuan1125/article/details/51051683

方法都是在網上查找的通用方法,目前實現了將h264文件封裝成了mp4文件,可以播放成功。但是buf設置有點問題,導致轉碼有點錯誤,會有花屏的現象,如果直接取流,一幀一幀的取就會沒問題,以下代碼只是最簡單的讀h264文件的進行封裝mp4,sps_pps可以將h264文件通過ue打開查看,(例如:00 00 00 01 67,,,,,這些就是sps,00 00 00 01 68。。這就是pps)爲了圖方便直接使用最簡單的操作數組寫死sps_pps(ps:這個是我的h264文件的sps和pps)。目前將aac文件和h264文件封裝成mp4文件,但是音視頻不同步,還需好好調試。aac的MP4SetTrackESConfiguration(mp4File,audio,audioconfig, 2);中的audioconfig配置請看https://www.cnblogs.com/zhangxuan/p/8809245.html 

主要是5個bit的profile4個bit的採樣率4個bit的通道,以及三個字節的0,這些配置可以從adts頭中找到,adts分析可以看上述鏈接

源代碼:

#include <stdio.h>
#include "mp4v2/mp4v2.h"
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define BUF_SIZE 1024*1024*2
uint16_t width=1920;
uint16_t height=1080;
unsigned char sps_pps[] = {0x67,0x4D,0x40,0x28,0x8D,0x8D,0x40,0x3C,0x01,0x13, 0xF2,0xE0,0x2D,0xC0,0x40,0x40,0x50,0X00,0X00,0X3E,0X90,0X00,0X0E,0XA6,0X0E,
0X86,0X00,0X3D,0X08,0X00,0X01,0X7D,0X78,0X2E,0XF2,0XE3,0X43,0X00,0X1E,0X84,0X00,0X00,0XBE,0XBC,0X17,0X79,0X70,0XA0,0X68,0XEE,0X38,0X80}; //48(sps)+4(pps)
                            
//unsigned char sps_pps[] = {0x67, 0x42, 0xC0, 0x2A, 0xD9 ,0x00, 0x78, 0x02, 0x27, 0xE5, 0xC0, 0x44, 0x00, 0x00, 0x03, 0x00, 0x04,0X00,0X00,0X03,0X01,0XE2,0X3C,0X60,0XC9,
                            //0X20,0X68,0XCB,0X8C,0XB2};//26(sps)+4(pps)
uint8_t audioconfig[2] = {0x11,0x90};    //0x11 0x90/*low 48000 2*/ 0x11 0x10/*low 64000 2*/ 0x12 0x08/*low 44100 1*/ 0x11 0x88/*low 48000 1*/ 0x12 0x10/*low 44100 2*/                
#define    FRAME_HD_00_1    0
#define    FRAME_HD_00_2    1
#define    FRAME_HD_00_3    2
#define    FRAME_HD_01    3
#define    FRAME_END_00_1    4
#define    FRAME_END_00_2    5
#define    FRAME_END_00_3    6
#define    FRAME_END_01    7
#define AUDIO 1
int Vframe_state=FRAME_HD_00_1;
int Aframe_state=FRAME_HD_00_1;

typedef struct _FRAME_PARA{
    long first_byte;
    long last_byte;
    long data_total;


}FRAME_PARA;

int buff_len=1;
int buff_len1=1;
int Aflag=0;
int Vflag=0;
long Vdat_cnt=-1;
long Adat_cnt=-1;
FRAME_PARA gPara_video;
FRAME_PARA gPara_audio;
char *frame_buff;
char *frame_buff1;
int Get_VFrame_Data(char *src_buff,long len,char *dst_buff,long offset, FRAME_PARA *ptr)
{
    int i;
    //long dat_cnt=-1;
    Vflag=0;
    for(i=offset;i<len;i++)
    {
        switch(Vframe_state)
        {
            //============find head 00 00 00 01 ====================
            case FRAME_HD_00_1:
                if(src_buff[i]==0x00)
                {
                    ptr->first_byte=i;
                    Vdat_cnt++;
                    //dst_buff[offset+dat_cnt]=src_buff[i];
                    dst_buff[Vdat_cnt]=src_buff[i];
                    Vframe_state=FRAME_HD_00_2;
                    //printf("-HEAD-find1-\n");
                }
                break;
            case FRAME_HD_00_2:
                if(src_buff[i]==0x00)
                {
                    Vdat_cnt++;
                    //dst_buff[offset+dat_cnt]=src_buff[i];
                    dst_buff[Vdat_cnt]=src_buff[i];
                    Vframe_state=FRAME_HD_00_3;
                    //printf("-HEAD-find2-\n");
                }
                else
                {
                    Vdat_cnt--;
                    Vframe_state=FRAME_HD_00_1;
                }
                break;
            case FRAME_HD_00_3:
                if(src_buff[i]==0x00)
                {
                    Vdat_cnt++;
                    //dst_buff[offset+dat_cnt]=src_buff[i];
                    dst_buff[Vdat_cnt]=src_buff[i];
                    Vframe_state=FRAME_HD_01;
                    //printf("-HEAD-find3-\n");
                }
                else
                {
                    Vdat_cnt--;
                    Vdat_cnt--;
                    Vframe_state=FRAME_HD_00_1;
                }
                break;
            case FRAME_HD_01:
                if(src_buff[i]==0x01)
                {
                    Vdat_cnt++;
                    //dst_buff[offset+dat_cnt]=src_buff[i];
                    dst_buff[Vdat_cnt]=src_buff[i];
                    Vframe_state=FRAME_END_00_1;
                    printf("-HEAD-find4-dat_cnt=%d\n",Vdat_cnt);
                }
                else
                {
                    Vdat_cnt--;
                    Vdat_cnt--;
                    Vdat_cnt--;
                    Vframe_state=FRAME_HD_00_1;
                }
                break;
                
                
            //============find tail 00 00 00 01 ====================
            case FRAME_END_00_1:
                Vdat_cnt++;
                //dst_buff[offset+dat_cnt]=src_buff[i];
                dst_buff[Vdat_cnt]=src_buff[i];
                if(src_buff[i]==0x00)
                    Vframe_state=FRAME_END_00_2;
                //printf("-END-find1-\n");
                break;
            case FRAME_END_00_2:
                Vdat_cnt++;
                //dst_buff[offset+dat_cnt]=src_buff[i];
                dst_buff[Vdat_cnt]=src_buff[i];
                if(src_buff[i]==0x00)
                {
                    Vframe_state=FRAME_END_00_3;
                    //printf("-END-find2-\n");
                }
                else
                    Vframe_state=FRAME_END_00_1;
                break;
            case FRAME_END_00_3:
                Vdat_cnt++;
                //dst_buff[offset+dat_cnt]=src_buff[i];
                dst_buff[Vdat_cnt]=src_buff[i];
                if(src_buff[i]==0x00)
                {
                    Vframe_state=FRAME_END_01;
                    //printf("-END-find3-\n");
                }
                else
                    Vframe_state=FRAME_END_00_1;
                break;
            case FRAME_END_01:
                Vdat_cnt++;
                //dst_buff[offset+dat_cnt]=src_buff[i];
                dst_buff[Vdat_cnt]=src_buff[i];
                if(src_buff[i]==0x01)
                {
                    Vframe_state=FRAME_HD_00_1;
                    ptr->last_byte=i-3;
                    //ptr->data_total=ptr->data_total+dat_cnt-4;
                    ptr->data_total=Vdat_cnt-3;
                    printf("-END-find4-dat_cnt=%d\n",Vdat_cnt-3);
                    Vdat_cnt=-1;
                    Vflag=1;
                    return 1;
                }
                else
                    Vframe_state=FRAME_END_00_1;
                break;
        }
    }
    return 0;
}    
int count=0;
int Get_One_VFrame(int fp)
{
    char buff[101];
    int ret=-1;
    for(;;)
    {    
        if(Vflag==0)
            buff_len=read(fp,buff,100);
        if(buff_len<=0)
        {
            printf("read data over\n");
            return 0;
        }
        ret=Get_VFrame_Data(buff,buff_len,frame_buff,gPara_video.last_byte,(FRAME_PARA *)&gPara_video);
        if(ret==1)    // 讀到完整的幀尾,frame_buff前四個字節放幀長度
        {
            frame_buff[0]=((gPara_video.data_total-4)&0xff000000)>>24;
            frame_buff[1]=((gPara_video.data_total-4)&0x00ff0000)>>16;
            frame_buff[2]=((gPara_video.data_total-4)&0x0000ff00)>>8;
            frame_buff[3]=((gPara_video.data_total-4)&0x000000ff);
            count++;
            break;
        }
        else
        {
            gPara_video.first_byte=0;
            gPara_video.last_byte=0;    
        }        
    }
    return 1;
}
int Get_AFrame_Data(char *src_buff,long len,char *dst_buff,long offset, FRAME_PARA *ptr)
{
    int i;
    //long dat_cnt=-1;
    Aflag=0;
    for(i=offset;i<len;i++)
    {
        switch(Aframe_state)
        {
            //============find head FF F9 4C 80 ====================
            case FRAME_HD_00_1:
                if(src_buff[i]==0xFF)
                {
                    ptr->first_byte=i;
                    Adat_cnt++;
                    //dst_buff[offset+dat_cnt]=src_buff[i];
                    dst_buff[Adat_cnt]=src_buff[i];
                    Aframe_state=FRAME_HD_00_2;
                    //printf("-HEAD-find1-\n");
                }
                break;
            case FRAME_HD_00_2:
                if(src_buff[i]==0xF9)
                {
                    Adat_cnt++;
                    //dst_buff[offset+dat_cnt]=src_buff[i];
                    dst_buff[Adat_cnt]=src_buff[i];
                    Aframe_state=FRAME_HD_00_3;
                    //printf("-HEAD-find2-\n");
                }
                else
                {
                    Adat_cnt--;
                    Aframe_state=FRAME_HD_00_1;
                }
                break;
            case FRAME_HD_00_3:
                if(src_buff[i]==0x4C)
                {
                    Adat_cnt++;
                    //dst_buff[offset+dat_cnt]=src_buff[i];
                    dst_buff[Adat_cnt]=src_buff[i];
                    Aframe_state=FRAME_HD_01;
                    //printf("-HEAD-find3-\n");
                }
                else
                {
                    Adat_cnt--;
                    Adat_cnt--;
                    Aframe_state=FRAME_HD_00_1;
                }
                break;
            case FRAME_HD_01:
                if(src_buff[i]==0x80)
                {
                    Adat_cnt++;
                    //dst_buff[offset+dat_cnt]=src_buff[i];
                    dst_buff[Adat_cnt]=src_buff[i];
                    Aframe_state=FRAME_END_00_1;
                    printf("-HEAD-find4-dat_cnt=%d\n",Adat_cnt);
                }
                else
                {
                    Adat_cnt--;
                    Adat_cnt--;
                    Adat_cnt--;
                    Aframe_state=FRAME_HD_00_1;
                }
                break;
                
                
            //============find tail FF F9 4C 80 ====================
            case FRAME_END_00_1:
                Adat_cnt++;
                //dst_buff[offset+dat_cnt]=src_buff[i];
                dst_buff[Adat_cnt]=src_buff[i];
                if(src_buff[i]==0xFF)
                    Aframe_state=FRAME_END_00_2;
                //printf("-END-find1-\n");
                break;
            case FRAME_END_00_2:
                Adat_cnt++;
                //dst_buff[offset+dat_cnt]=src_buff[i];
                dst_buff[Adat_cnt]=src_buff[i];
                if(src_buff[i]==0xF9)
                {
                    Aframe_state=FRAME_END_00_3;
                    //printf("-END-find2-\n");
                }
                else
                    Aframe_state=FRAME_END_00_1;
                break;
            case FRAME_END_00_3:
                Adat_cnt++;
                //dst_buff[offset+dat_cnt]=src_buff[i];
                dst_buff[Adat_cnt]=src_buff[i];
                if(src_buff[i]==0x4C)
                {
                    Aframe_state=FRAME_END_01;
                    //printf("-END-find3-\n");
                }
                else
                    Aframe_state=FRAME_END_00_1;
                break;
            case FRAME_END_01:
                Adat_cnt++;
                //dst_buff[offset+dat_cnt]=src_buff[i];
                dst_buff[Adat_cnt]=src_buff[i];
                if(src_buff[i]==0x80)
                {
                    Aframe_state=FRAME_HD_00_1;
                    ptr->last_byte=i-3;
                    //ptr->data_total=ptr->data_total+dat_cnt-4;
                    ptr->data_total=Adat_cnt-3;
                    printf("-END-find4-dat_cnt=%d\n",Adat_cnt-3);
                    Adat_cnt=-1;
                    Aflag=1;
                    return 1;
                }
                else
                    Aframe_state=FRAME_END_00_1;
                break;
        }
    }
    return 0;
}
int number=0;
int Get_One_AFrame(int fp)
{
    char buff[101];
    int ret=-1;
    for(;;)
    {    
        if(Aflag==0)
            buff_len1=read(fp,buff,100);
        if(buff_len1<=0)
        {
            printf("read data over\n");
            return 0;
        }
        ret=Get_AFrame_Data(buff,buff_len1,frame_buff1,gPara_audio.last_byte,(FRAME_PARA *)&gPara_audio);
        if(ret==1)    // 讀到完整的幀尾,frame_buff前四個字節放幀長度
            break;
        else
        {
            gPara_audio.first_byte=0;
            gPara_audio.last_byte=0;    
        }        
    }
    return 1;
}
int main(int argc,char *argv[])
{    
    int fd_audio,fd_video;
    frame_buff=(char *)malloc(BUF_SIZE);
    memset(frame_buff,0,BUF_SIZE);
    if(frame_buff==NULL)
    {
        fprintf(stderr,"malloc fail!\n");
            exit(1);
    }
    frame_buff1=(char *)malloc(BUF_SIZE);
    memset(frame_buff1,0,BUF_SIZE);
    if(frame_buff1==NULL)
    {
        fprintf(stderr,"malloc fail!\n");
            exit(1);
    }
    if (argc < 4)
        {
            fprintf(stderr,"usage fail!\n");
            exit(1);
        }
    
    u_int32_t verbosity = 0 /* MP4_DETAILS_ALL */;

    fd_video=open(argv[1],O_RDWR);
    if(fd_video<0)
        {    
            fprintf(stderr,"open fail!\n");
            exit(1);
        }
    fd_audio=open(argv[2],O_RDWR);
    if(fd_audio<0)
        {    
            fprintf(stderr,"open fail!\n");
            exit(1);
        }
    MP4FileHandle mp4File = MP4Create(argv[3],verbosity);
    #if 1
    //MP4FileHandle mp4File = MP4CreateEx(argv[2],MP4_DETAILS_ALL, 0, 1, 1, 0, 0, 0, 0);//創建mp4文件
    if (mp4File==MP4_INVALID_FILE_HANDLE)
            exit(1);
    
    MP4SetTimeScale(mp4File,90000);
    MP4TrackId video = MP4AddH264VideoTrack(mp4File,90000,90000/29.97, width, height,
                                        0x4D, //sps[1] AVCProfileIndication
                                        0x40, //sps[2] profile_compat
                                        0x28, //sps[3] AVCLevelIndication
                                        3); // 4 bytes length before each NAL unit
     //MP4TrackId audio = MP4AddAudioTrack(mp4File,16000, 1024,MP4_MPEG2_AAC_LC_AUDIO_TYPE);
    if (video == MP4_INVALID_TRACK_ID)    
        {
            perror("add video track fialed.\n");
            return 1;
        }
    MP4AddH264SequenceParameterSet(mp4File,video,sps_pps,48);
    MP4AddH264PictureParameterSet(mp4File,video,sps_pps+48,4);
    MP4SetVideoProfileLevel(mp4File, 0x7F);
    //MP4SetVideoProfileLevel(mp4File, 0x1);
    #if AUDIO
    //MP4TrackId audio = MP4AddAudioTrack(mp4File,44100,1024,MP4_MPEG4_AAC_LC_AUDIO_TYPE);
     MP4TrackId audio = MP4AddAudioTrack(mp4File,48000,1024,MP4_MPEG2_AAC_LC_AUDIO_TYPE);
    //MP4TrackId audio = MP4AddAudioTrack(mp4File,48000,1024,MP4_MPEG4_AUDIO_TYPE);
    if (audio == MP4_INVALID_TRACK_ID)    
        {
            perror("add audio track fialed.\n");
            return 1;
        }
        MP4SetAudioProfileLevel(mp4File, 0x2 );
        // 設置編碼信息
        MP4SetTrackESConfiguration(mp4File,audio,audioconfig, 2);
        #endif
    #endif
    int ret,ret1;
    int i=0;
    while(1)
    {    
        
        ret=Get_One_VFrame(fd_video);
        if(ret==1)
            MP4WriteSample(mp4File,video,frame_buff,gPara_video.data_total,90000/29.97, 0, 1);
        
    #if AUDIO
        ret1=Get_One_AFrame(fd_audio);
            if(ret1==1)
                MP4WriteSample(mp4File,audio,&frame_buff1[7],gPara_audio.data_total-7,MP4_INVALID_DURATION, 0, 1);    // MP4_INVALID_DURATION
    #endif
        if(ret==0)
        #if AUDIO
            if(ret1==0)
        #endif
            break;
        
        memset(frame_buff,0,gPara_video.data_total);
        memset(frame_buff1,0,gPara_audio.data_total);
    }
        printf("-----------------encode sucess!-------------\n");
        printf("count=%d\n",count);
    free(frame_buff);
    free(frame_buff1);
    close(fd_video);
    close(fd_audio);
    MP4Close(mp4File,0);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章