Record h264 + g711a/aac into mp4

一、mp4的几种封装方案

1、ffmpeg

2、mp4v2

3、gpac

https://blog.csdn.net/LLL347/article/details/85886975

https://blog.csdn.net/weixin_43549602/article/details/84571906

二、mp4v2

通过EasyAACEncoder + mp4v2, 根据两位老哥的代码,整合了个demo.

main.cpp

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "EasyAACEncoderAPI.h"
#include "mp4v2.h"
#include "util.h"

/*test file*/
static off_t file_size;

static char* get_h264_frame(char* raw_file)
{
    int raw_fd = open(raw_file, O_RDONLY);
    if (raw_fd < 0) {
        printf("open h264 raw file %s failed.
", raw_file);
        return nullptr;
    }
    
    file_size = lseek(raw_fd, 0, SEEK_END);
    if (file_size <= 0) {
        printf("h264 raw file %s empty.
", raw_file);
        return nullptr;
    }
    
    char*h264_raw = (char*)malloc(file_size);
    if (!h264_raw) {
        printf("alloc raw buffer failed for file %s.
", raw_file);
        return nullptr;
    }
    
    lseek(raw_fd, 0, SEEK_SET);
    ssize_t nb_read = 0;
    if ((nb_read = read(raw_fd, h264_raw, file_size)) != file_size) {
        printf("buffer %s failed, expect=%dKB, actual=%dKB.
", 
            raw_file, (int)(file_size / 1024), (int)(nb_read / 1024));
        return nullptr;
    }

    close(raw_fd);

    return h264_raw; 
}

/*example*/
int main(int argc, char** argv)
{
    int fps = 25;

    /*g711 data source*/
    int n = 0;
    char g711a[320];
    FILE *infile=fopen("./doc/stream-file/8k_1_16.g711a","rb");
    
    /*g711_to_aac*/
    InitParam initParam;
    initParam.u32AudioSamplerate=8000;
    initParam.ucAudioChannel=1;
    initParam.u32PCMBitSize=16;
    initParam.ucAudioCodec = Law_ALaw;
    Easy_Handle handle = Easy_AACEncoder_Init(initParam);
    int bAACBufferSize = 4*1024;
    unsigned char *pbAACBuffer = (unsigned char*)malloc(bAACBufferSize * sizeof(unsigned char));  
    unsigned int aac_len = 0;

    /*Create */
    //MP4FileHandle mp4 = MP4CreateEx("test.mp4", MP4_DETAILS_ALL, 0, 1, 1, 0, 0, 0, 0);
    MP4FileHandle mp4 = MP4Create("test.mp4", 0);
    MP4SetTimeScale(mp4, 90000);

    /*Set video*/
    MP4TrackId video = MP4AddH264VideoTrack(mp4, 90000, 90000 / fps, 640, 480,
                                            0x64, //sps[1] AVCProfileIndication
                                            0x00, //sps[2] profile_compat
                                            0x1f, //sps[3] AVCLevelIndication
                                            3);
    MP4SetVideoProfileLevel(mp4, 0x7F);

    /*Set audio*/
    MP4TrackId audio = MP4AddAudioTrack(mp4, 8000, 1024, MP4_MPEG4_AUDIO_TYPE);
    MP4SetAudioProfileLevel(mp4, 0x2);

    while(1){

        if(fread(g711a,1,320,infile) > 0)
        {

            if(Easy_AACEncoder_Encode(handle, (unsigned char*)g711a, 320, pbAACBuffer, &aac_len) > 0)
            {
                dump_bin("ttt.aac",(char*)pbAACBuffer, aac_len);
                MP4WriteSample(mp4, audio, pbAACBuffer, aac_len, MP4_INVALID_DURATION, 0, 1);
            }

        }else{
            fseek(infile, 0, SEEK_SET);
            continue;
        }

        char str[32];
        sprintf(str,"./doc/stream-file/h264_3/%d",n); 
        char* h264_raw = get_h264_frame(str);   
        if(h264_raw != nullptr){
            MP4WriteSample(mp4,video , (uint8_t*)h264_raw, file_size, MP4_INVALID_DURATION, 0, 1);
        }
                                
        free(h264_raw);
        if(++n > 311) break;

    }

    Easy_AACEncoder_Release(handle);
    free(pbAACBuffer);
    MP4Close(mp4);

    return 0;
}

 Makefile

APP = main

INCLUDE = 
-I ./lib/EasyAACEncoder/include 
-I ./lib/mp4v2/include 
-I ./lib/mp4v2/include/mp4v2 
-I ./lib/util

LIB = 
./lib/EasyAACEncoder/lib/libEasyAACEncoder.a 
./lib/mp4v2/lib/libmp4v2.a


SRC  = main.cpp 
./lib/util/util.c

CFLAGS = -g -O0 -std=c++11 -lstdc++

LDFLAGS = -lpthread -lz

out: 
    g++ $(SRC) -o $(APP) $(LIB) $(INCLUDE) $(CFLAGS) $(LDFLAGS)

clean:
    rm -rf *o *.out $(APP)

封装一下

  while( ((i=fread(buffer,1,160,infile))>0) && (runcond) )
    {
        rtp_session_send_with_ts(session,buffer,i,user_ts);
        user_ts+=160;
    }

    while(!feof(ts_file)){  
        int read_len = fread(buf+count, 1, TS_PACKET_SIZE, ts_file);   
        count += read_len;   
    }

参考

1. 先是随手一搜,看起来应该很简单

https://blog.csdn.net/lipku/article/details/78138645

https://github.com/EasyDarwin/EasyAACEncoder

2. 以上很快搞定了,发现vlc , ffmpeg播放正常,Windows Media Player播不了,然后找到据说需要在视频nalu头部添加长度信息

https://blog.csdn.net/firehood_/article/details/8813587#

https://blog.csdn.net/machh/article/details/40623387

3. 视频nalu头部添加长度信息也不管用,aac单独导出来也能播,写到mp4就不行,已经怀疑mp4v2到底是不是靠谱!

https://www.zhihu.com/question/25396952

4. 2015年就有人遇到同样的问题,留到今天还没解决,咱用ffmpeg也行, 只是mp4v2看起来小巧,为了更轻量折腾了2天半.

三、ffmpeg

ffmpeg 音视频同步需要注意,调了一圈,发现一样Windows Media Player播不了

ffmpeg muxer (h264 +g711a)

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <fcntl.h>

#include <libavutil/opt.h>
#include <libavformat/avformat.h>

#define STREAM_FRAME_RATE 25 /* 25 images/s */

/*test file*/
static off_t file_size;

static char* get_file_frame(char* raw_file)
{
    int raw_fd = open(raw_file, O_RDONLY);
    if (raw_fd < 0) {
        printf("open h264 raw file %s failed.
", raw_file);
        return NULL;
    }
    
    file_size = lseek(raw_fd, 0, SEEK_END);
    if (file_size <= 0) {
        printf("h264 raw file %s empty.
", raw_file);
        return NULL;
    }
    
    char* raw = (char*)malloc(file_size);
    if (!raw) {
        printf("alloc raw buffer failed for file %s.
", raw_file);
        return NULL;
    }
    
    lseek(raw_fd, 0, SEEK_SET);
    ssize_t nb_read = 0;
    if ((nb_read = read(raw_fd, raw, file_size)) != file_size) {
        printf("buffer %s failed, expect=%dKB, actual=%dKB.
", 
            raw_file, (int)(file_size / 1024), (int)(nb_read / 1024));
        return NULL;
    }

    close(raw_fd);

    return raw; 
}

/* Add an output stream. */
static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec,
                            enum AVCodecID codec_id)
{
    AVCodecContext *c;
    AVStream *st;

    /* find the encoder */
    *codec = avcodec_find_encoder(codec_id);
    if (!(*codec)) {
        fprintf(stderr, "Could not find encoder for '%s'
",
                avcodec_get_name(codec_id));
        exit(1);
    }

    st = avformat_new_stream(oc, *codec);
    if (!st) {
        fprintf(stderr, "Could not allocate stream
");
        exit(1);
    }
    st->id = oc->nb_streams-1;
    c = st->codec;

    switch ((*codec)->type) {
    case AVMEDIA_TYPE_AUDIO:
        c->sample_fmt  = AV_SAMPLE_FMT_FLTP;
        c->bit_rate    = 64000;
        c->sample_rate = 44100;
        c->channels    = 2;
        break;

    case AVMEDIA_TYPE_VIDEO:
        c->codec_id = codec_id;

        c->bit_rate = 400000;
        /* Resolution must be a multiple of two. */
        c->width    = 1920;
        c->height   = 1080;
        /* timebase: This is the fundamental unit of time (in seconds) in terms
         * of which frame timestamps are represented. For fixed-fps content,
         * timebase should be 1/framerate and timestamp increments should be
         * identical to 1. */
        c->time_base.den = STREAM_FRAME_RATE;
        c->time_base.num = 1;
        c->gop_size      = STREAM_FRAME_RATE; /* emit one intra frame every twelve frames at most */
        c->pix_fmt       = AV_PIX_FMT_YUV420P;
        if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
            /* just for testing, we also add B frames */
            c->max_b_frames = 2;
        }
        if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
            /* Needed to avoid using macroblocks in which some coeffs overflow.
             * This does not happen with normal video, it just happens here as
             * the motion of the chroma plane does not match the luma plane. */
            c->mb_decision = 2;
        }
    break;

    default:
        break;
    }

    /* Some formats want stream headers to be separate. */
    if (oc->oformat->flags & AVFMT_GLOBALHEADER)
        c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    return st;
}


/**************************************************************/
/* media file output */

int main(int argc, char **argv)
{
    AVOutputFormat *fmt;
    AVFormatContext *oc;
    AVStream *audio_st,*video_st;
    AVCodec *audio_codec,*video_codec;

    int ret;

    char filename[32];
    sprintf(filename,"rm.mp4");

    /* Initialize libavcodec, and register all codecs and formats. */
    av_register_all();

    /* allocate the output media context */
    avformat_alloc_output_context2(&oc, NULL, NULL, filename);
    if (!oc) {
        printf("
Could not deduce output format from file extension.
");
        return 0;
    }
    if (!oc) {
        return 1;
    }
    fmt = oc->oformat;

    /* Add the audio and video streams using the default format codecs
     * and initialize the codecs. */
    video_st = NULL;
    audio_st = NULL;

    if (fmt->video_codec != AV_CODEC_ID_NONE) {
        fmt->video_codec = AV_CODEC_ID_H264;
        video_st = add_stream(oc, &video_codec, fmt->video_codec);
    }
    if (fmt->audio_codec != AV_CODEC_ID_NONE) {
        fmt->audio_codec = AV_CODEC_ID_AAC;
        audio_st = add_stream(oc, &audio_codec, fmt->audio_codec);
    }

    /* open the output file, if needed */
    if (!(fmt->flags & AVFMT_NOFILE)) {
        ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
        if (ret < 0) {
            fprintf(stderr, "Could not open '%s': %s
", filename,
                    av_err2str(ret));
            return 0;
        }
    }

    /* Write the stream header, if any. */
    ret = avformat_write_header(oc, NULL);
    if (ret < 0) {
        fprintf(stderr, "Error occurred when opening output file: %s
",
                av_err2str(ret));
        return 0;
    }

    video_st->time_base.den = 90000;
    video_st->time_base.num = 1;

    long pts_vtime = 0;
    long pts_atime = 0;

    printf("ffmpeg mux start : 
");

    /*g711 data source*/
    int m = 0;
    int n = 0;
    FILE *infile=fopen("./doc/stream-file/8k_1_16.g711a","rb");
    
    int video_tag;

    while(1){
        AVPacket pkt = { 0 };
        av_init_packet(&pkt);
            
        pkt.size = 0;

        if(video_tag == 1)
        {
            pts_vtime += 90000/25;
            pkt.dts = pts_vtime;
            pkt.pts = pts_vtime;
            pkt.stream_index = video_st->index;

            /*h264 mux*/
            char str[32];
            sprintf(str,"./avc_raw/avc_raw_%03d.h264",m); 
            char* h264_raw = get_file_frame(str);   
            if(h264_raw != NULL){
                pkt.size = file_size;
                pkt.data = (unsigned char*)h264_raw;
                ret = av_interleaved_write_frame(oc, &pkt);
            }
            free(h264_raw);
            if(++m > 248) m=0;
            
            video_tag = 0;

        }else{
            pts_atime += 90000/25/2;
            pkt.dts = pts_atime;
            pkt.pts = pts_atime;
            pkt.stream_index = audio_st->index;     
            /*aac mux*/
            char str[32];
            sprintf(str,"./aac_raw/aac_raw_%03d.aac",n); 
            char* aac_raw = get_file_frame(str);   
            if(aac_raw != NULL){
                pkt.size = file_size;
                pkt.data = (unsigned char*)aac_raw;
                ret = av_interleaved_write_frame(oc, &pkt);
            }
            free(aac_raw);
            if(++n > 431) break;
            
            video_tag = 1;
        }
    }
     
    av_write_trailer(oc);
    avio_close(oc->pb);
    avformat_free_context(oc);

    printf("
---FILE:%s-line %d ---
",__FILE__,__LINE__);
    printf("ffmpeg save file done !!!
");
    
    return 0;
}

ffmpeg muxer (h264 + aac/g711a)

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <fcntl.h>
#include "EasyAACEncoderAPI.h"

#include <libavutil/opt.h>
#include <libavformat/avformat.h>

#define STREAM_FRAME_RATE 25 /* 25 images/s */

/*test file*/
static off_t file_size;

static char* get_file_frame(char* raw_file)
{
    int raw_fd = open(raw_file, O_RDONLY);
    if (raw_fd < 0) {
        printf("open h264 raw file %s failed.
", raw_file);
        return NULL;
    }
    
    file_size = lseek(raw_fd, 0, SEEK_END);
    if (file_size <= 0) {
        printf("h264 raw file %s empty.
", raw_file);
        return NULL;
    }
    
    char* raw = (char*)malloc(file_size);
    if (!raw) {
        printf("alloc raw buffer failed for file %s.
", raw_file);
        return NULL;
    }
    
    lseek(raw_fd, 0, SEEK_SET);
    ssize_t nb_read = 0;
    if ((nb_read = read(raw_fd, raw, file_size)) != file_size) {
        printf("buffer %s failed, expect=%dKB, actual=%dKB.
", 
            raw_file, (int)(file_size / 1024), (int)(nb_read / 1024));
        return NULL;
    }

    close(raw_fd);

    return raw; 
}

int dump(const char * file, char *buf, int len)
{
    FILE *fp = fopen(file, "a+b");
    if(fp)
    {
     fwrite(buf, len, 1, fp);
     fclose(fp);
     fp = NULL;
     return -1;
    }
    return 0;
}

void make_dsi( unsigned int sampling_frequency_index, unsigned int channel_configuration, unsigned char* dsi )
{
  unsigned int object_type = 2; // AAC LC by default
  dsi[0] = (object_type<<3) | (sampling_frequency_index>>1);
  dsi[1] = ((sampling_frequency_index&1)<<7) | (channel_configuration<<3);
}

int get_sr_index(unsigned int sampling_frequency)
{
  switch (sampling_frequency) {
   case 96000: return 0;
   case 88200: return 1;
   case 64000: return 2;
   case 48000: return 3;
   case 44100: return 4;
   case 32000: return 5;
   case 24000: return 6;
   case 22050: return 7;
   case 16000: return 8;
   case 12000: return 9;
   case 11025: return 10;
   case 8000:  return 11;
   case 7350:  return 12;
   default:    return 0;
  }
}

/**
*  Add ADTS header at the beginning of each and every AAC packet.
*  This is needed as MediaCodec encoder generates a packet of raw
*  AAC data.
*
*  Note the packetLen must count in the ADTS header itself !!! .
*注意,这里的packetLen参数为raw aac Packet Len + 7; 7 bytes adts header
**/
void addADTStoPacket(char* packet, int packetLen) {
    int profile = 2;  //AAC LC,MediaCodecInfo.CodecProfileLevel.AACObjectLC;
    int freqIdx = 4;  //44.1K, 见后面注释avpriv_mpeg4audio_sample_rates中32000对应的数组下标,来自ffmpeg源码
    int chanCfg = 2;  //见后面注释channel_configuration,Stero双声道立体声

    /*int avpriv_mpeg4audio_sample_rates[] = {
        96000, 88200, 64000, 48000, 44100, 32000,
                24000, 22050, 16000, 12000, 11025, 8000, 7350
    };
    channel_configuration: 表示声道数chanCfg
    0: Defined in AOT Specifc Config
    1: 1 channel: front-center
    2: 2 channels: front-left, front-right
    3: 3 channels: front-center, front-left, front-right
    4: 4 channels: front-center, front-left, front-right, back-center
    5: 5 channels: front-center, front-left, front-right, back-left, back-right
    6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
    7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
    8-15: Reserved
    */

    // fill in ADTS data
    packet[0] = (char)0xFF;
    packet[1] = (char)0xF9;
    packet[2] = (char)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
    packet[3] = (char)(((chanCfg&3)<<6) + (packetLen>>11));
    packet[4] = (char)((packetLen&0x7FF) >> 3);
    packet[5] = (char)(((packetLen&7)<<5) + 0x1F);
    packet[6] = (char)0xFC;
}


/* Add an output stream. */
static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec,
                            enum AVCodecID codec_id)
{
    AVCodecContext *c;
    AVStream *st;

    /* find the encoder */
    *codec = avcodec_find_encoder(codec_id);
    if (!(*codec)) {
        fprintf(stderr, "Could not find encoder for '%s'
",
                avcodec_get_name(codec_id));
        exit(1);
    }

    st = avformat_new_stream(oc, *codec);
    if (!st) {
        fprintf(stderr, "Could not allocate stream
");
        exit(1);
    }
    st->id = oc->nb_streams-1;
    c = st->codec;

    switch ((*codec)->type) {
    case AVMEDIA_TYPE_AUDIO:
        c->sample_fmt  = AV_SAMPLE_FMT_FLTP;
        c->bit_rate    = 64000;
        c->sample_rate = 44100;
        c->channels    = 2;

        char dsi[2];
        make_dsi( get_sr_index(44100), 2, dsi );
        c->extradata = (uint8_t*)av_malloc(sizeof(uint8_t)*2);
        memcpy(c->extradata, &dsi[0], 2);
        c->extradata_size = 2;


        break;

    case AVMEDIA_TYPE_VIDEO:
        c->codec_id = codec_id;

        c->bit_rate = 400000;
        /* Resolution must be a multiple of two. */
        c->width    = 1920;
        c->height   = 1080;
        /* timebase: This is the fundamental unit of time (in seconds) in terms
         * of which frame timestamps are represented. For fixed-fps content,
         * timebase should be 1/framerate and timestamp increments should be
         * identical to 1. */
        c->time_base.den = STREAM_FRAME_RATE;
        c->time_base.num = 1;
        c->gop_size      = STREAM_FRAME_RATE; /* emit one intra frame every twelve frames at most */
        c->pix_fmt       = AV_PIX_FMT_YUV420P;
        if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
            /* just for testing, we also add B frames */
            c->max_b_frames = 2;
        }
        if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
            /* Needed to avoid using macroblocks in which some coeffs overflow.
             * This does not happen with normal video, it just happens here as
             * the motion of the chroma plane does not match the luma plane. */
            c->mb_decision = 2;
        }
        break;

    default:
        break;
    }

    /* Some formats want stream headers to be separate. */
    if (oc->oformat->flags & AVFMT_GLOBALHEADER)
        c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    return st;
}


/**************************************************************/
/* media file output */

int main(int argc, char **argv)
{
    AVOutputFormat *fmt;
    AVFormatContext *oc;
    AVStream *audio_st,*video_st;
    AVCodec *audio_codec,*video_codec;

    int ret;

    char filename[32];
    sprintf(filename,"rm.mp4");

    /* Initialize libavcodec, and register all codecs and formats. */
    av_register_all();

    /* allocate the output media context */
    avformat_alloc_output_context2(&oc, NULL, NULL, filename);
    if (!oc) {
        printf("
Could not deduce output format from file extension.
");
        return 0;
    }
    if (!oc) {
        return 1;
    }
    fmt = oc->oformat;

    /* Add the audio and video streams using the default format codecs
     * and initialize the codecs. */
    video_st = NULL;
    audio_st = NULL;

    if (fmt->video_codec != AV_CODEC_ID_NONE) {
        fmt->video_codec = AV_CODEC_ID_H264;
        video_st = add_stream(oc, &video_codec, fmt->video_codec);
    }
    if (fmt->audio_codec != AV_CODEC_ID_NONE) {
        fmt->audio_codec = AV_CODEC_ID_AAC;
        audio_st = add_stream(oc, &audio_codec, fmt->audio_codec);
    }

    /* open the output file, if needed */
    if (!(fmt->flags & AVFMT_NOFILE)) {
        ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
        if (ret < 0) {
            fprintf(stderr, "Could not open '%s': %s
", filename,
                    av_err2str(ret));
            return 0;
        }
    }

    /* Write the stream header, if any. */
    ret = avformat_write_header(oc, NULL);
    if (ret < 0) {
        fprintf(stderr, "Error occurred when opening output file: %s
",
                av_err2str(ret));
        return 0;
    }

    video_st->time_base.den = 90000;
    video_st->time_base.num = 1;

    long pts_time = 0;
    long pts_atime = 0;
    long pts_vtime = 0;

    printf("ffmpeg mux start : 
");

    /*g711 data source*/
    int m = 0;
    int n = 0;
    char g711a[320];
    FILE *infile=fopen("./doc/stream-file/8k_1_16.g711a","rb");

    /*g711_to_aac*/
    InitParam initParam;
    initParam.u32AudioSamplerate=8000;
    initParam.ucAudioChannel=1;
    initParam.u32PCMBitSize=16;
    initParam.ucAudioCodec = Law_ALaw;
    Easy_Handle handle = Easy_AACEncoder_Init(initParam);
    int bAACBufferSize = 4*1024;
    unsigned char *pbAACBuffer = (unsigned char*)malloc(bAACBufferSize * sizeof(unsigned char));  
    unsigned int aac_len = 0;
    
    int video_tag=0;

    while(1){
        AVPacket pkt = { 0 };
        av_init_packet(&pkt);
        
        
        pkt.dts = pts_time;
        pkt.pts = pts_time;
        pkt.size = 0;

        if(video_tag == 1)
        {
            pts_vtime += 90000/25; //(video_st->time_base.num*1000/video_st->time_base.den)//
            pkt.dts = pts_vtime;
            pkt.pts = pts_vtime;
            pkt.stream_index = video_st->index;

            /*h264 mux*/
            char str[32];
            sprintf(str,"./avc_raw/avc_raw_%03d.h264",m); 
            char* h264_raw = get_file_frame(str);   
            if(h264_raw != NULL){
                pkt.size = file_size;
                pkt.data = (unsigned char*)h264_raw;
                ret = av_interleaved_write_frame(oc, &pkt);
            }
            free(h264_raw);
            if(++m > 248) break;
            
            video_tag = 0;

        }
        else
        {        
            pts_atime += 90000/25/2;
            pkt.dts = pts_atime;
            pkt.pts = pts_atime;
            pkt.stream_index = audio_st->index;
   
            #if 1
            /*aac mux*/
            char str[32];
            sprintf(str,"./aac_raw/aac_raw_%03d.aac",n); 
            char* aac_raw = get_file_frame(str);   
            if(aac_raw != NULL){
                pkt.size = file_size;
                pkt.data = (unsigned char*)aac_raw;
                ret = av_interleaved_write_frame(oc, &pkt);
            }
            free(aac_raw);
            if(++n > 431) break;
            #else

            /*g711a mux*/
            if(fread(g711a,1,320,infile) > 0)
            {
                if(Easy_AACEncoder_Encode(handle, (unsigned char*)g711a, 320, pbAACBuffer, &aac_len) > 0)
                {
                    pkt.size = aac_len-7;
                    pkt.data = (unsigned char*)(&pbAACBuffer[7]);
                    ret = av_interleaved_write_frame(oc, &pkt);
                }

            }else{
                fseek(infile, 0, SEEK_SET);
                continue;
            }
            #endif

            video_tag = 1;
        }

    }
     
    av_write_trailer(oc);
    avio_close(oc->pb);
    avformat_free_context(oc);

    printf("
---FILE:%s-line %d ---
",__FILE__,__LINE__);
    printf("ffmpeg save file done !!!
");
    
    return 0;
}

ffmpeg muxer pts/dts:

https://blog.csdn.net/leixiaohua1020/article/details/39802913#t2 

end

原文地址:https://www.cnblogs.com/dong1/p/11739379.html