ffmpeg 單線程本地mp4 rtmp推流

//dbt_rtmp.h
#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <windows.h>
#include <queue.h>
#include <string>
using namespace std;
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include <libavutil/time.h>
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/audio_fifo.h"
#include "libavfilter/avfiltergraph.h"
#include "libavfilter/avcodec.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavutil/avutil.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
};



#define STREAM_FRAME_RATE  25
#define INPUTURL   "yekong.mp4"
//#define OUTPUTURL  "zhizuxia.flv"
#define OUTPUTURL    "rtmp://localhost:1935/live/stream"
int width, height;
AVFormatContext *ifmt_ctx = NULL;
AVStream* ist_v = NULL, *ist_a = NULL;
AVFormatContext* ofmt_ctx = NULL;
AVCodecContext *audio_codec_context = NULL, *video_codec_context = NULL;
AVCodec* video_codec = NULL, *audio_codec = NULL;
AVStream *video_st = NULL, *audio_st = NULL;

int videoframecnt = 1;
int audioframecnt;



//video param
AVCodecID video_codecID = AV_CODEC_ID_H264;


//audio param
int dst_channels = 2;      //聲道

AVCodecID audio_codecID = AV_CODEC_ID_AAC;
int audio_frame_size = 1024;

AVBitStreamFilterContext * m_aac_adtstoasc;     //aac->adts to asc過濾器  
int out_framesize; //音頻輸出流的每幀採樣數(aac爲1024)

//輸入流中音視頻的索引
int iv_index = -1, ia_index = -1;

double lastptstime;

void init_packet(AVPacket *packet);
void add_stream(AVFormatContext *out_format_context, AVStream** st, AVCodecContext **out_codec_context, AVCodec** codec, AVCodecID codec_id);
void open_video(AVCodecContext* codec_context, AVCodec* codec);
void open_audio(AVCodecContext* audio_codec_context, AVCodec * codec);
int encode_video_frame(AVFrame *frame,AVFormatContext *out_format_context,AVStream *video_st);
int encode_audio_frame(AVFrame *frame, int nbsamples,AVFormatContext *output_format_context, AVStream* st);
void decode_video_frame(AVPacket *pkt);
void decode_audio_frame(AVPacket *pkt);


typedef struct FilteringContext {
    AVFilterContext *buffersink_ctx;
    AVFilterContext *buffersrc_ctx;
    AVFilterGraph *filter_graph;
} FilteringContext;
FilteringContext *filter_ctx;
//dbt_rtmp.cpp
#include <dbt_rtmp.h>

void init_packet(AVPacket *packet){
    av_init_packet(packet);
    packet->data = NULL;
    packet->size = 0;
}

int initVideoFilters(FilteringContext *filter_ctx,AVCodecContext * icodecContext, AVCodecContext *ocodecContext)
{
    char args[512];
    int ret = 0;
    AVFilterContext *buffersrc_ctx = NULL;
    AVFilterContext *buffersink_ctx = NULL;
    //爲FilterGraph分配內存
    AVFilterGraph *filter_graph = avfilter_graph_alloc();

    AVFilter *buffersrc = avfilter_get_by_name("buffer");
    AVFilter *buffersink = avfilter_get_by_name("buffersink");
    AVFilterInOut *outputs = avfilter_inout_alloc();
    AVFilterInOut *inputs = avfilter_inout_alloc();
    string  filters_descr = "null";
    enum AVPixelFormat pix_fmts[] = { ocodecContext->pix_fmt, AV_PIX_FMT_NONE };


    if (!outputs || !inputs || !filter_graph) {
        ret = AVERROR(ENOMEM);
        goto end;
    }

    /**
    * 要填入正確的參數
    */
    sprintf_s(args, sizeof(args),
        "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
        icodecContext->width, icodecContext->height, icodecContext->pix_fmt,
        icodecContext->time_base.num, icodecContext->time_base.den,
        icodecContext->sample_aspect_ratio.num, icodecContext->sample_aspect_ratio.den);


    //創建並向FilterGraph中添加一個Filter
    ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
        args, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
        goto end;
    }

    //創建並向FilterGraph中添加一個Filter
    ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
        NULL, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
        goto end;
    }

    ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,
        AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");
        goto end;
    }

    /* Endpoints for the filter graph. */
    outputs->name = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;
    outputs->pad_idx = 0;
    outputs->next = NULL;

    inputs->name = av_strdup("out");
    inputs->filter_ctx = buffersink_ctx;
    inputs->pad_idx = 0;
    inputs->next = NULL;
    //將一串通過字符串描述的Graph添加到FilterGraph中
    if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr.c_str(),
        &inputs, &outputs, NULL)) < 0)
        goto end;
    //檢查FilterGraph的配置
    if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
        goto end;
    /* Fill FilteringContext */
    filter_ctx->buffersrc_ctx = buffersrc_ctx;
    filter_ctx->buffersink_ctx = buffersink_ctx;
    filter_ctx->filter_graph = filter_graph;
end:
    avfilter_inout_free(&inputs);
    avfilter_inout_free(&outputs);
    return ret;
}


int initAudioFilters(FilteringContext *filter_ctx, AVCodecContext * icodecContext, AVCodecContext *ocodecContext)
{
    char args[512];
    int ret;
    AVFilter *abuffersrc = avfilter_get_by_name("abuffer");
    AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
    AVFilterInOut *outputs = avfilter_inout_alloc();
    AVFilterInOut *inputs = avfilter_inout_alloc();
    AVFilterContext *buffersrc_ctx = NULL;
    AVFilterContext *buffersink_ctx = NULL;

    if (!icodecContext->channel_layout)
        icodecContext->channel_layout = av_get_default_channel_layout(icodecContext->channels);
    //AV_SAMPLE_FMT_FLTP
    static const enum AVSampleFormat out_sample_fmts[] = { ocodecContext->sample_fmt, AV_SAMPLE_FMT_NONE };
    static const int64_t out_channel_layouts[] = { ocodecContext->channel_layout, -1 };
    static const int out_sample_rates[] = { ocodecContext->sample_rate, -1 };


    AVFilterGraph* filter_graph = avfilter_graph_alloc();
    filter_graph->nb_threads = 1;

    sprintf_s(args, sizeof(args),
        "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
        icodecContext->time_base.num, icodecContext->time_base.den, icodecContext->sample_rate,
        av_get_sample_fmt_name(icodecContext->sample_fmt), icodecContext->channel_layout);

    ret = avfilter_graph_create_filter(&buffersrc_ctx, abuffersrc, "in",
        args, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
        return ret;
    }

    /* buffer audio sink: to terminate the filter chain. */
    ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out",
        NULL, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
        return ret;
    }

    ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1,
        AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n");
        return ret;
    }

    ret = av_opt_set_int_list(buffersink_ctx, "channel_layouts", out_channel_layouts, -1,
        AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n");
        return ret;
    }

    ret = av_opt_set_int_list(buffersink_ctx, "sample_rates", out_sample_rates, -1,
        AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n");
        return ret;
    }

    /* Endpoints for the filter graph. */
    outputs->name = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;;
    outputs->pad_idx = 0;
    outputs->next = NULL;

    inputs->name = av_strdup("out");
    inputs->filter_ctx =buffersink_ctx;
    inputs->pad_idx = 0;
    inputs->next = NULL;

    if ((ret = avfilter_graph_parse_ptr(filter_graph, "anull",
        &inputs, &outputs, nullptr)) < 0)
        return ret;

    if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
        return ret;

    av_buffersink_set_frame_size(buffersink_ctx, 1024);
    /* Fill FilteringContext */
    filter_ctx->buffersrc_ctx = buffersrc_ctx;
    filter_ctx->buffersink_ctx = buffersink_ctx;
    filter_ctx->filter_graph = filter_graph;
    return 0;
}


void add_stream(AVFormatContext *out_format_context, AVStream** st, AVCodecContext **out_codec_context, AVCodec** codec, AVCodecID codec_id)
{
    *codec = avcodec_find_encoder(codec_id);
    if (!codec) {
        fprintf(stderr, "Could not find encoder for '%s'\n",
            avcodec_get_name(codec_id));
        getchar();exit(1);
    }

    *st = avformat_new_stream(out_format_context, *codec);

    if (!*st) {
        fprintf(stderr, "Could not alloc stream");
        getchar();exit(1);
    }

    *out_codec_context = (*st)->codec;
    (*st)->id = out_format_context->nb_streams - 1;
    (*out_codec_context)->codec_id = codec_id;
    AVRational time_base;
    switch ((*codec)->type) {
    case AVMEDIA_TYPE_AUDIO:

        (*out_codec_context)->codec_type = AVMEDIA_TYPE_AUDIO;

        (*out_codec_context)->channels = dst_channels;
        (*out_codec_context)->channel_layout = av_get_default_channel_layout(dst_channels);

        (*out_codec_context)->sample_rate = ist_a->codec->sample_rate;
        (*out_codec_context)->frame_size = audio_frame_size;
        (*out_codec_context)->sample_fmt = (*codec)->sample_fmts[0];

        time_base = { 1, (*out_codec_context)->sample_rate };
        (*out_codec_context)->time_base = time_base;

        break;
    case AVMEDIA_TYPE_VIDEO:
        (*out_codec_context)->codec_type = AVMEDIA_TYPE_VIDEO;

        (*out_codec_context)->time_base = ist_v->codec->time_base;

        (*out_codec_context)->pix_fmt = (*codec)->pix_fmts[0];
        (*out_codec_context)->width = width;
        (*out_codec_context)->height = height;
        (*st)->avg_frame_rate = ist_a->avg_frame_rate;
        (*out_codec_context)->has_b_frames = ist_v->codec->has_b_frames;
        (*out_codec_context)->max_b_frames = ist_v->codec->max_b_frames;
        //(*out_codec_context)->me_range = 0;
        //(*out_codec_context)->max_qdiff = 4;
        //(*out_codec_context)->qmin = ist_v->codec->qmin;
        //(*out_codec_context)->qmax = ist_v->codec->qmax;
        //(*out_codec_context)->qcompress = 0.6;

        //(*out_codec_context)->profile = FF_PROFILE_H264_BASELINE;
        break;
    default:
        break;
    }
    (*out_codec_context)->codec_tag = 0;

    // some formats want stream headers to be separate
    if (out_format_context->oformat->flags & AVFMT_GLOBALHEADER)
        (*out_codec_context)->flags |= CODEC_FLAG_GLOBAL_HEADER;


}


void open_video(AVCodecContext* codec_context, AVCodec* codec){


    AVDictionary *param = NULL;

    av_dict_set(&param, "preset", "veryfast", 0);
    av_dict_set(&param, "tune", "zerolatency", 0);
    //av_dict_set(&param, "profile", "baseline", 0);
    if (avcodec_open2(video_st->codec, codec, &param) < 0) {
        fprintf(stderr, "could not open codec\n");
        getchar(); exit(1);
    }

}

void open_audio(AVCodecContext* audio_codec_context, AVCodec * codec){

    if (avcodec_open2(audio_codec_context, codec, NULL) < 0) {
        printf("Could not open audio codec \n");
        getchar();exit(1);
    }
}



int encode_video_frame(AVFrame *frame,
    AVFormatContext *out_format_context,
    AVStream *video_st){

    AVCodecContext* out_codec_context = video_st->codec;
    int got_packet;
    AVPacket enc_pkt;
    init_packet(&enc_pkt);

    if (frame){
        //decodec層時間基到codec的時間基轉換
        frame->pts = av_rescale_q(frame->pts, ist_v->codec->time_base, video_st->codec->time_base);
        frame->pict_type = AV_PICTURE_TYPE_NONE;
    }
    int ret = avcodec_encode_video2(out_codec_context, &enc_pkt,
        frame, &got_packet);

    if (ret < 0 || !got_packet){ //在flush的時候,如果失敗 ,說明丟失幀(緩存幀)已經空了
        av_free_packet(&enc_pkt);

        return 1;
    }

    //codec層時間基轉mux層
    enc_pkt.pts = av_rescale_q(enc_pkt.pts, video_st->codec->time_base, video_st->time_base);
    enc_pkt.dts = av_rescale_q(enc_pkt.dts, video_st->codec->time_base, video_st->time_base);
    enc_pkt.duration = av_rescale_q(enc_pkt.duration, video_st->codec->time_base, video_st->time_base);

    enc_pkt.stream_index = video_st->index;
    printf("video info--- enc_pkt:pts:%lld\t dts:%lld\t duration:%d\n", enc_pkt.pts, enc_pkt.dts, enc_pkt.duration);
    lastptstime = enc_pkt.pts*av_q2d(video_st->time_base);
    ret = av_interleaved_write_frame(out_format_context, &enc_pkt);

    av_free_packet(&enc_pkt);

    if (ret < 0){
        printf("write video frame failed!\n");
        return 1;
    }
    else{

        printf("write video frame success\t%d\n", videoframecnt);

        videoframecnt++;
    }

    return 0;
}


int encode_audio_frame(AVFrame *frame, int nbsamples,
    AVFormatContext *output_format_context, AVStream* st){
    int got_packet;
    AVPacket enc_pkt;
    init_packet(&enc_pkt);
    if (frame){
        //decodec層時間基到codec的時間基轉換
        frame->pts = av_rescale_q(frame->pts, ist_a->codec->time_base, audio_st->codec->time_base);

    }

    int ret = avcodec_encode_audio2(st->codec, &enc_pkt,
        frame, &got_packet);

    if (ret < 0 || !got_packet){
        av_free_packet(&enc_pkt);

        return 1;
    }


    enc_pkt.pts = av_rescale_q_rnd(enc_pkt.pts, audio_st->codec->time_base, audio_st->time_base, AV_ROUND_NEAR_INF);
    enc_pkt.dts = av_rescale_q_rnd(enc_pkt.dts, audio_st->codec->time_base, audio_st->time_base, AV_ROUND_NEAR_INF);
    enc_pkt.duration = av_rescale_q(enc_pkt.duration, audio_st->codec->time_base, audio_st->time_base);

    enc_pkt.stream_index = audio_st->index;

    lastptstime = enc_pkt.pts*av_q2d(audio_st->time_base);
    printf("audio info--- enc_pkt:pts:%lld\t dts:%lld\t duration:%d\n",enc_pkt.pts, enc_pkt.dts, enc_pkt.duration);

    av_bitstream_filter_filter(m_aac_adtstoasc, audio_st->codec, NULL, &enc_pkt.data, &enc_pkt.size, enc_pkt.data, enc_pkt.size, 0);


    ret = av_interleaved_write_frame(output_format_context, &enc_pkt);


    av_free_packet(&enc_pkt);

    if (ret < 0){
        printf("write audio frame failed!\n");
        return 1;
    }
    else{
        audioframecnt++;
        printf("write audio frame success!\t%d\n", audioframecnt);

    }

    return 0;
}



void decode_video_frame(AVPacket *pkt){
    AVFrame* srcFrame = av_frame_alloc();
    pkt->dts = av_rescale_q_rnd(pkt->dts,
        ist_v->time_base,
        ist_v->codec->time_base,
        (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    pkt->pts = av_rescale_q_rnd(pkt->pts,
        ist_v->time_base,
        ist_v->codec->time_base,
        (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    int got_picture;
    avcodec_decode_video2(ist_v->codec, srcFrame, &got_picture, pkt);
    if (got_picture){

        srcFrame->pts = av_frame_get_best_effort_timestamp(srcFrame);


        if (av_buffersrc_add_frame_flags(filter_ctx[iv_index].buffersrc_ctx,
            srcFrame, 0) >=0){
            AVFrame *filt_frame = av_frame_alloc();
            if (av_buffersink_get_frame(filter_ctx[iv_index].buffersink_ctx,
                filt_frame) >= 0){
                encode_video_frame(filt_frame, ofmt_ctx, video_st);
            }
            av_frame_free(&filt_frame);

        }

    }

    av_frame_free(&srcFrame);


}


void decode_audio_frame(AVPacket *pkt){
    AVFrame* srcFrame = av_frame_alloc();
    //demux層轉decode層時間基
    pkt->dts = av_rescale_q_rnd(pkt->dts,
        ist_a->time_base,
        ist_a->codec->time_base,
        AV_ROUND_NEAR_INF);
    pkt->pts = av_rescale_q_rnd(pkt->pts,
        ist_a->time_base,
        ist_a->codec->time_base,
        AV_ROUND_NEAR_INF);
    int got_frame;
    AVFrame *filt_frame;
    avcodec_decode_audio4(ist_a->codec, srcFrame, &got_frame, pkt);
    if (got_frame){
        srcFrame->pts = av_frame_get_best_effort_timestamp(srcFrame);

        if (av_buffersrc_add_frame_flags(filter_ctx[ia_index].buffersrc_ctx,
            srcFrame, 0) >= 0){

            while (1) {
                filt_frame = av_frame_alloc();
                if (av_buffersink_get_frame(filter_ctx[ia_index].buffersink_ctx,
                    filt_frame) >= 0){
                    int ret=encode_audio_frame(filt_frame, out_framesize, ofmt_ctx, audio_st);
                    if (ret){
                        break;
                    }
                }
                else{
                    break;
                }

            }

            av_frame_free(&filt_frame);

        }

    }
    av_frame_free(&srcFrame);
}



int main(int argc, char **argv){

    av_register_all();
    avformat_network_init();
    avfilter_register_all();
    int ret;
    AVDictionary* in_options = NULL;
    av_dict_set(&in_options, "re", "1", 0);
    if ((ret = avformat_open_input(&ifmt_ctx, INPUTURL, 0, &in_options)) < 0) {
        printf("Could not open input file.");
    }
    ifmt_ctx->max_analyze_duration2 = 60 * 1000000;
    avformat_find_stream_info(ifmt_ctx, 0);


    for (int i = 0; i < ifmt_ctx->nb_streams; i++) {

        if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
            iv_index = i;

            ist_v = ifmt_ctx->streams[i];
            width = ist_v->codec->width;
            height = ist_v->codec->height;

            AVCodec *codec = avcodec_find_decoder(ist_v->codec->codec_id);

            /* open the codec */
            if (avcodec_open2(ist_v->codec, codec,NULL) < 0) {
                fprintf(stderr, "could not open input video decoder codec\n");
                getchar();exit(1);
            }

        }
        else if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){
            ia_index = i;
            ist_a = ifmt_ctx->streams[i];

            AVCodec *codec = avcodec_find_decoder(ist_a->codec->codec_id);

            /* open the codec */
            if (avcodec_open2(ist_a->codec, codec, NULL) < 0) {
                fprintf(stderr, "could not open input audio decoder codec\n");
                getchar(); exit(1);
            }
        }

    }
    av_dump_format(ifmt_ctx, 0, INPUTURL, 0);


    ofmt_ctx = avformat_alloc_context();
    if (strstr(OUTPUTURL, "rtmp")){
        avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", OUTPUTURL); //RTMP
    }
    else{
        avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, OUTPUTURL);
    }

    AVOutputFormat* fmt = ofmt_ctx->oformat;
    if (!fmt) {
        fprintf(stderr, "Could not find suitable output format");
        getchar();exit(1);
    }


    add_stream(ofmt_ctx, &video_st, &video_codec_context, &video_codec, video_codecID);
    add_stream(ofmt_ctx, &audio_st, &audio_codec_context, &audio_codec, audio_codecID);

    open_video(video_codec_context, video_codec);
    open_audio(audio_codec_context, audio_codec);

    av_dump_format(ofmt_ctx, 0, OUTPUTURL, 1);

    filter_ctx = (FilteringContext *)av_malloc_array(ifmt_ctx->nb_streams, sizeof(*filter_ctx));


    initVideoFilters(&filter_ctx[iv_index],ist_v->codec,video_st->codec);
    initAudioFilters(&filter_ctx[ia_index], ist_a->codec, audio_st->codec);

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


    m_aac_adtstoasc = av_bitstream_filter_init("aac_adtstoasc");
    /*AVDictionary *out_options = NULL;
    av_dict_set(&out_options, "rtmp_buffer", "1024000", 0);
    av_dict_set(&out_options, "max_delay", "500000", 0);
    av_dict_set(&out_options, "timeout", "6", 0);*/
    ret = avformat_write_header(ofmt_ctx, NULL);
    if (ret < 0) {
        fprintf(stderr, "Error occurred when opening output file: %s\n", "");
        return 1;
    }

    out_framesize = audio_codec_context->frame_size;
    double starttime = av_gettime();
    for (;;){
        double diff = lastptstime - ((double)(av_gettime() - starttime) / 1000000);
        printf("diff:%f\n", diff);
        if (diff>0){
            Sleep(diff*1000);
        }
        AVPacket pkt;
        init_packet(&pkt);
        ret = av_read_frame(ifmt_ctx, &pkt);
        if (ret < 0){
            printf("到文件尾了\n");
            break;
        }

        if (pkt.stream_index == iv_index){

            decode_video_frame(&pkt);
        }
        else if (pkt.stream_index == ia_index){

            decode_audio_frame(&pkt);
        }
        av_free_packet(&pkt);

    }



    if (video_codec_context->codec->capabilities &CODEC_CAP_DELAY){
        while (!encode_video_frame(NULL, ofmt_ctx, video_st)){ 
            printf("encode_video_frame while");
            ;
        }
    }
    if (audio_codec_context->codec->capabilities &CODEC_CAP_DELAY){
        while (!encode_audio_frame(NULL, out_framesize, ofmt_ctx,audio_st)){ 
            printf("encode_audio_frame while");
            ;
        }
    }

    av_write_trailer(ofmt_ctx);

    av_bitstream_filter_close(m_aac_adtstoasc);
    avformat_close_input(&ifmt_ctx);

    if (ofmt_ctx) {
        avio_closep(&ofmt_ctx->pb);
        avformat_free_context(ofmt_ctx);
    }

    printf("程序運行end");
    return getchar();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章