zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    【网易官方】极客战记(codecombat)攻略-地牢-健忘的宝石匠
    【网易官方】极客战记(codecombat)攻略-地牢-深藏的宝石
    【网易官方】极客战记(codecombat)攻略-地牢-Kithgard 地牢
    【网易官方】极客战记(codecombat)攻略[地牢]:祸之火焰-通关代码及讲解
    spring可以接收的正则的方式
    Calls to static methods in Java interfaces are prohibited in JVM target 1.6. Recompile with '-jvm-target 1.8'
    EnableRetry
    https://www.youtube.com/watch?v=kwuu1efzkf4 38分
    https://gitee.com/createmaker/reactor-examples reactor编程代码
    webflux 20201011
  • 原文地址:https://www.cnblogs.com/dong1/p/11739379.html
Copyright © 2011-2022 走看看