ffmpeg4教程6:采集桌面图像(desktop)和声音压缩为mp4或推流rtmp

基于vs2017 vc++  ffmpeg4.0.2下测试

ffmpeg 环境配置请百度(vs2017 ffmpeg )图像和声音请安装screencapturer便于查找 

部分方法在https://blog.csdn.net/Java_lilin/article/details/85118365中查找

 需要pthread

#include "pch.h"
#include <iostream>

extern "C" {
#include "libavcodec/avcodec.h" 
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/audio_fifo.h"
#include <libavutil/time.h>
#include <libavutil/mathematics.h>
#define HAVE_STRUCT_TIMESPEC
#include "pthread.h"

/*采集声音和桌面到文件或者rmtp*/
typedef struct _Packet {
    int64_t pts;//时间
    AVPacket pkt;//meiyizhen
    struct _Packet *next;
}Packet;
typedef struct _PacketList {
    struct _Packet *packet;
    struct _Packet *end;
    int pkgSize;
    int max;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    pthread_cond_t wait;
    int exit;
}PacketList;

typedef struct GobleData{
    int64_t audiotime;
}GobleData;
typedef struct MyOutPutStream { 
    GobleData *gobledata;

    PacketList *packetList;
    pthread_t pthread;
    int64_t nextshowpts;

    AVFormatContext *formatCtx;

    AVCodecContext *ctx;//yuanlai de

    AVCodecContext *enctx;//目标压缩器

    AVStream *st;//

    int runing;int64_t nexttps; 
    AVFrame *frame;//

    AVFrame *outframe;//转目标 
    //video  
    SwsContext *img_convert_ctx; 
    //声音  
    AVFrame *newframe;
    AVFrame *newframe2;
    AVAudioFifo *fifo;
    SwrContext *swr;
}MyOutPutStream;

static int initPakcetList(PacketList **ppacketList,int max) {
    int ret = 0;
    PacketList* p = NULL;
    *ppacketList = (PacketList*)av_mallocz(sizeof(PacketList));
    p = *ppacketList;
    if (p == NULL)return -1;
    ret = pthread_mutex_init(&p->mutex,NULL);
    if (ret != 0) {
        av_freep(p);
        return -1;
    } 
    ret= pthread_cond_init(&p->cond, NULL);
    if (ret != 0) {
        av_freep(&p);
        return -1;
    }
    ret = pthread_cond_init(&p->wait, NULL);
    if (ret != 0) {
        av_freep(&p);
        return -1;
    }
    p->max = max;
    return 0;
}

static void destoryPakcetList(PacketList *packetList) {
    if (packetList == NULL)return;
    {
        Packet *pkt=NULL;
        PacketList *p = packetList;
        pthread_mutex_lock(&p->mutex);
        p->exit = 1;

        pkt = p->packet;
        while (pkt) {
            Packet *temp = pkt->next;
            if (temp != NULL) {
                av_packet_unref(&temp->pkt);
            }
            pkt = temp;
        }
        pthread_mutex_unlock(&p->mutex);
    }
}
static int pushPakcet(PacketList *p,AVPacket *pkt,int64_t pts) {
    int ret = 0;
    Packet *packet = NULL;
    if (p == NULL || p->exit)return 0;
    pthread_mutex_lock(&p->mutex);
    while (!p->exit && p->pkgSize > p->max) {
        pthread_cond_wait(&p->wait, &p->mutex);
    }
    if (p->exit) {
        pthread_mutex_unlock(&p->mutex);
        return 0;
    }
    packet = (Packet*)av_mallocz(sizeof(Packet));
    if (packet) {
        packet->pts = pts;
        av_packet_ref(&packet->pkt,pkt);
        if (p->end == NULL) {
            p->packet = packet;
        }
        else {
            p->end->next = packet;
        }
        p->end = packet;
        p->pkgSize++;
        ret = 1; 
        pthread_cond_signal(&p->cond);
    }
    pthread_mutex_unlock(&p->mutex);
    return ret;
}
static int64_t popPacket(PacketList *p, AVPacket *pkt) {
    int64_t ret = 0;
    if (p == NULL || p->exit )return 0;
    pthread_mutex_lock(&p->mutex); 
    while (!p->exit &&   p->pkgSize < 1) { 
        pthread_cond_wait(&p->cond,&p->mutex); 
    }
    if (p->exit) {
        pthread_mutex_unlock(&p->mutex); 
        return -1;
    }
    
    if (p->packet == p->end) {
        ret = p->packet->pts;
        av_packet_ref(pkt,&p->packet->pkt);
        av_packet_unref(&p->packet->pkt);
        av_freep(&p->packet);
        p->packet = NULL;
        p->end = NULL; 
    } 
    else { 
        Packet *temp = p->packet; 
        p->packet = temp->next;
        ret = temp->pts;
        av_packet_ref(pkt, &temp->pkt);
        av_packet_unref(&temp->pkt);
        av_freep(&temp); 
    }
    p->pkgSize--;
    pthread_cond_signal(&p->wait);
    pthread_mutex_unlock(&p->mutex);
    return ret;
}

static int add_video(AVFormatContext *oc, MyOutPutStream *ost) {
    AVCodec *encodec = avcodec_find_encoder(AV_CODEC_ID_H264);
    if (!encodec) {
        printf("not found encoder for H264");
        avcodec_get_name(AV_CODEC_ID_H264);
        return -1;
    }

    ost->st = avformat_new_stream(oc, encodec);
    ost->st->id = oc->nb_streams - 1;

    ost->enctx = avcodec_alloc_context3(encodec);
    ost->enctx->codec_id = AV_CODEC_ID_H264;
    ost->enctx->bit_rate = 8000000;//码率
    ost->enctx->width = 640;
    ost->enctx->height = 480;

    AVRational  base; base.num = 1; base.den = 15;//帧率
    ost->enctx->time_base = base;
    ost->enctx->gop_size = 12;
    ost->enctx->max_b_frames = 0;
    ost->enctx->pix_fmt = AV_PIX_FMT_YUV420P;//h264必须
    ost->enctx->gop_size = 12;
    ost->enctx->max_b_frames = 0;
    //减少延迟
    av_opt_set(ost->enctx->priv_data, "preset", "superfast", 0);
    av_opt_set(ost->enctx->priv_data, "tune", "zerolatency", 0);

    //播放器播放不出来
    if (oc->oformat->flags&AVFMT_GLOBALHEADER) {
        ost->enctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    }
    AVDictionary* opt = NULL;
    int ret = avcodec_open2(ost->enctx, encodec, &opt);
    av_dict_free(&opt);
    if (ret < 0) {
        printf("not open video codec");
        return -1;
    }


    //add关联 把编辑器参数传递给输出流
    avcodec_parameters_from_context(ost->st->codecpar, ost->enctx);

    return 0;
}
static int add_audio(AVFormatContext *oc, MyOutPutStream *ost) {
    AVOutputFormat *fmt = oc->oformat;
    fmt->audio_codec = AV_CODEC_ID_AAC;//AV_CODEC_ID_MP3 mp3格式 改下面4个

    AVCodec *encodec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!encodec) {
        printf("not found encoder for aac");
        avcodec_get_name(AV_CODEC_ID_AAC);
        return -1;
    }

    ost->st = avformat_new_stream(oc, encodec);
    ost->st->id = oc->nb_streams - 1;
    /*******************************/
    //test4 代码
    ost->enctx = avcodec_alloc_context3(encodec);
    ost->enctx->codec_id = AV_CODEC_ID_AAC;
    ost->enctx->sample_fmt = encodec->sample_fmts ? encodec->sample_fmts[0] : AV_SAMPLE_FMT_FLT;
    ost->enctx->bit_rate = 128000;
    ost->enctx->sample_rate = 44100;
    if (encodec->supported_samplerates) {//查找是否支持
        ost->enctx->sample_rate = encodec->supported_samplerates[0];
        for (int i = 0; encodec->supported_samplerates[i]; i++)
        {
            if (encodec->supported_samplerates[i] == 44100) { ost->enctx->sample_rate = 44100; }
        }
    }
    ost->enctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;

    ost->enctx->channel_layout = AV_CH_LAYOUT_STEREO;
    if (encodec->channel_layouts) {//查找是否支持
        ost->enctx->channel_layout = encodec->channel_layouts[0];
        for (int i = 0; encodec->channel_layouts[i]; i++)
        {
            if (encodec->channel_layouts[i] == AV_CH_LAYOUT_STEREO) { ost->enctx->channel_layout = AV_CH_LAYOUT_STEREO; }
        }
    }
    ost->enctx->channels = av_get_channel_layout_nb_channels(ost->enctx->channel_layout);
    //播放器播放不出来
    if (oc->oformat->flags&AVFMT_GLOBALHEADER) {
        ost->enctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    }
    AVDictionary* opt = NULL;
    int ret = avcodec_open2(ost->enctx, encodec, &opt);
    av_dict_free(&opt);
    if (ret < 0) {
        printf("not open audio codec");
        return -1;
    }

    //add关联 把编辑器参数传递给输出流
    avcodec_parameters_from_context(ost->st->codecpar, ost->enctx);

    return 0;
}

static int open_video(MyOutPutStream *ost) {
    
    //添加test1的代码 begin 
    ost->formatCtx = avformat_alloc_context();
    AVInputFormat *ifmt = av_find_input_format("gdigrab");//设备类型
    //AVInputFormat *ifmt = av_find_input_format("dshow");//设备类型
    AVDictionary* options = NULL;
    //av_dict_set(&options, "video_size","1920*1080",0);//大小  默认全部
    av_dict_set(&options, "framerate", "15", 0);//帧lu
    if (avformat_open_input(&ost->formatCtx, "desktop", ifmt, &options) != 0) {
        //if (avformat_open_input(&formatCtx, "video=Integrated Camera", ifmt, &options) != 0) {
        printf("open input device fail\n");
        return -1;
    }
    av_dict_free(&options);

    if (avformat_find_stream_info(ost->formatCtx, NULL) < 0) {
        printf("avformat_find_stream_info faill\n");
        return -1;
    }
    if (ost->formatCtx->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
        printf("no find stream info\n");
        return -1;
    }
    //查找解密器
    AVCodec *codec = avcodec_find_decoder(ost->formatCtx->streams[0]->codecpar->codec_id);
    if (codec == NULL) {
        printf("codec not found\n");
        return -1;
    }
    ost->ctx = avcodec_alloc_context3(codec);
    avcodec_parameters_to_context(ost->ctx, ost->formatCtx->streams[0]->codecpar);
    if (avcodec_open2(ost->ctx, codec, NULL) < 0) {
        printf("codec not open\n");
        return -1;
    }
    printf("pix format is %d\n", ost->formatCtx->streams[0]->codecpar->format);//==AVPixelFormat->AV_PIX_FMT_BGRA 
    
    ost->frame = alloc_picture((AVPixelFormat)ost->formatCtx->streams[0]->codecpar->format, ost->formatCtx->streams[0]->codecpar->width, ost->formatCtx->streams[0]->codecpar->height);
    //图像缩放
    ost->img_convert_ctx = sws_getContext(ost->formatCtx->streams[0]->codecpar->width, ost->formatCtx->streams[0]->codecpar->height, (AVPixelFormat)ost->formatCtx->streams[0]->codecpar->format,
        ost->enctx->width, ost->enctx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
    //目标
    ost->outframe = alloc_picture(AV_PIX_FMT_YUV420P, ost->enctx->width, ost->enctx->height);

    return 0;
}
static int open_audio(MyOutPutStream *ost) {

    ost->formatCtx = avformat_alloc_context();
    AVInputFormat *ifmt = av_find_input_format("dshow");//设备类型
    AVDictionary* options = NULL;
    //av_dict_set(&options, "video_size","1920*1080",0);//大小  默认全部
    av_dict_set(&options, "framerate", "15", 0);//帧lu
    if (avformat_open_input(&ost->formatCtx, "audio=virtual-audio-capturer", ifmt, &options) != 0) {
        printf("open input device fail\n");
        return -1;
    }
    av_dict_free(&options);

    if (avformat_find_stream_info(ost->formatCtx, NULL) < 0) {
        printf("avformat_find_stream_info faill\n");
        return -1;
    }
    if (ost->formatCtx->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) {
        printf("no find stream info\n");
        return -1;
    }
    //查找解密器
    AVCodec *codec = avcodec_find_decoder(ost->formatCtx->streams[0]->codecpar->codec_id);
    if (codec == NULL) {
        printf("codec not found\n");
        return -1;
    }
    ost->ctx = avcodec_alloc_context3(codec);
    avcodec_parameters_to_context(ost->ctx, ost->formatCtx->streams[0]->codecpar);
    if (avcodec_open2(ost->ctx, codec, NULL) < 0) {
        printf("codec not open\n");
        return -1;
    }

    ost->frame = alloc_audio_frame((AVSampleFormat)ost->formatCtx->streams[0]->codecpar->format, ost->formatCtx->streams[0]->codecpar->channel_layout, ost->formatCtx->streams[0]->codecpar->channels, ost->formatCtx->streams[0]->codecpar->sample_rate, ost->formatCtx->streams[0]->codecpar->frame_size);
    //目标
    ost->ctx->channel_layout = av_get_default_channel_layout(ost->ctx->channels);
    ost->swr = swr_alloc();
    av_opt_set_int(ost->swr, "in_channel_count", ost->ctx->channels, 0);
    av_opt_set_int(ost->swr, "in_channel_layout", ost->ctx->channel_layout, 0);
    av_opt_set_int(ost->swr, "in_sample_rate", ost->ctx->sample_rate, 0);
    av_opt_set_sample_fmt(ost->swr, "in_sample_fmt", ost->ctx->sample_fmt, 0);
    //gai
    int64_t desc_channel_layout = ost->enctx->channel_layout;
    int64_t desc_channel_count = ost->enctx->channels;
    int64_t desc_sample_rate = ost->enctx->sample_rate;
    AVSampleFormat desc_fmt = ost->enctx->sample_fmt;

    av_opt_set_int(ost->swr, "out_channel_count", desc_channel_count, 0);
    av_opt_set_int(ost->swr, "out_channel_layout", desc_channel_layout, 0);
    av_opt_set_int(ost->swr, "out_sample_rate", desc_sample_rate, 0);
    av_opt_set_sample_fmt(ost->swr, "out_sample_fmt", desc_fmt, 0);

    printf("\n声道%d,采样率%d格式%d----》声道%d,采样率%d格式%d\n", ost->ctx->channels, ost->ctx->sample_rate,
        ost->ctx->sample_fmt, desc_channel_count, desc_sample_rate, desc_fmt);

    int DES_NB_SAMPLES = ost->enctx->frame_size;//每次需要1024个 不够有噪音

    ost->outframe = alloc_audio_frame(desc_fmt, desc_channel_layout, desc_channel_count, desc_sample_rate, DES_NB_SAMPLES);
    ost->newframe = alloc_audio_frame(desc_fmt, desc_channel_layout, desc_channel_count, desc_sample_rate, 0);
    ost->newframe2 = alloc_audio_frame(desc_fmt, desc_channel_layout, desc_channel_count, desc_sample_rate, 0);

    ost->fifo = av_audio_fifo_alloc(desc_fmt, desc_channel_count, 10240);

    return 0;
}
static AVFrame* getVideoFrame(MyOutPutStream *ost) {
    int ret;
    while (ost->runing) {
        if (ost->gobledata->audiotime == 0) { 
            av_usleep(20);
            continue;
        }
        if (ost->outframe->pts>0&&ost->nexttps  < ost->gobledata->audiotime - 1000000LL * ost->enctx->time_base.num / ost->enctx->time_base.den) {
            ost->outframe->pts = ost->nexttps;
            ost->nexttps = ost->outframe->pts + 1000000LL * ost->enctx->time_base.num / ost->enctx->time_base.den;
            return ost->outframe;
        }
        if (ost->gobledata->audiotime>0 && ost->nexttps > ost->gobledata->audiotime + 1000000LL * ost->enctx->time_base.num / ost->enctx->time_base.den) {
            
            av_usleep(1000000LL * ost->enctx->time_base.num / ost->enctx->time_base.den); 
        }
        AVPacket packet = { 0 };
        av_init_packet(&packet);
        if (av_read_frame(ost->formatCtx, &packet) >= 0) {
            avcodec_send_packet(ost->ctx, &packet);
            if (avcodec_receive_frame(ost->ctx, ost->frame) < 0) {
                printf("decode error\n");
            }
            else {
                //printf("采集到图片");
                //转换 AV_PIX_FMT_BGRA to AV_PIX_FMT_YUV420P
                sws_scale(ost->img_convert_ctx, (const unsigned char* const*)ost->frame->data, ost->frame->linesize, 0, ost->frame->height, ost->outframe->data, ost->outframe->linesize);
                if (ost->nexttps == 0) { 
                    ost->outframe->pts = 0; //av_gettime();
                }
                else { ost->outframe->pts = ost->nexttps; }
                ost->nexttps = ost->outframe->pts + 1000000LL * ost->enctx->time_base.num / ost->enctx->time_base.den;
                //提取yizhen

            } 
        }
        av_packet_unref(&packet);
        break;
    }
    return ost->outframe;
}
static AVFrame* getAudioFrame(MyOutPutStream *ost) {
     
    while (true) {
        int size = av_audio_fifo_size(ost->fifo);
        if (size >= ost->enctx->frame_size) {//超过
            printf("\n第一次超过\n");
            size = ost->enctx->frame_size;
            av_audio_fifo_read(ost->fifo, (void**)ost->outframe->data, size);
            //完整

            //写文件 替换  
            ost->outframe->pts = ost->nexttps; 
            ost->nexttps = ost->outframe->pts + 1000000LL * ost->outframe->linesize[0] / (ost->enctx->sample_rate*av_get_bytes_per_sample(ost->enctx->sample_fmt));
            ost->gobledata->audiotime = ost->outframe->pts;

            return ost->outframe;
        }

        AVPacket packet = { 0 };
        av_init_packet(&packet);
        if (av_read_frame(ost->formatCtx, &packet) >= 0) {
            avcodec_send_packet(ost->ctx, &packet);
            if (avcodec_receive_frame(ost->ctx, ost->frame) < 0) {
                printf("audio decode error\n");
                return NULL;
            }
            else {
                //printf("采集到音频"); // 
                swr_convert_frame(ost->swr, ost->newframe, ost->frame);
                av_audio_fifo_write(ost->fifo, (void**)ost->newframe->data, ost->newframe->nb_samples);

                int64_t dealy = swr_get_delay(ost->swr, ost->enctx->sample_rate);
                if (dealy > 0) {
                    swr_convert_frame(ost->swr, ost->newframe2, NULL);
                    av_audio_fifo_write(ost->fifo, (void**)ost->newframe2->data, ost->newframe2->nb_samples);
                }
                //这里可以判断下fifo里的数量是否够1024
                int size = av_audio_fifo_size(ost->fifo);
                if (size < ost->enctx->frame_size) {
                    //数据不够 
                    av_packet_unref(&packet);
                    continue;
                }
                size = ost->enctx->frame_size;//够了
                av_audio_fifo_read(ost->fifo, (void**)ost->outframe->data, size);//固定大小的
            
                //写文件 gai
                //fwrite(outframe->data[0], size, desc_channel_count*av_get_bytes_per_sample(desc_fmt), file);
                
                if (ost->nexttps == 0) { 
                    ost->outframe->pts = 0;//av_gettime();  
                }
                else { ost->outframe->pts = ost->nexttps; }

                ost->nexttps = ost->outframe->pts + 1000000LL * ost->outframe->linesize[0] / (ost->enctx->sample_rate*av_get_bytes_per_sample(ost->enctx->sample_fmt));
                ost->gobledata->audiotime = ost->outframe->pts; 
                 
            }
        }
        
        av_packet_unref(&packet);
        break;
    }
    return ost->outframe;
}

static void* read_thread(void* p) { 
    MyOutPutStream *ost = (MyOutPutStream*)p;
    int ret;
    ost->runing = 1;
    AVFrame* frame = NULL;
    while (ost->runing) { 
        if (ost->enctx->codec_type == AVMEDIA_TYPE_VIDEO) {
            frame = getVideoFrame(ost);
        }
        else {
            frame = getAudioFrame(ost);
        }
        if (frame == NULL) {//error
            
        }    else {
            int64_t  ttt= frame->pts;
            {
                AVRational  base; base.num = 1; base.den = 1000000LL;//帧率
                //转换回去去压缩器的时基
                frame->pts = av_rescale_q(frame->pts, base, ost->enctx->time_base);
            }
            //开始压缩
            avcodec_send_frame(ost->enctx, frame);
            AVPacket pkt = { 0 };
            av_init_packet(&pkt);
            ret = avcodec_receive_packet(ost->enctx, &pkt);
            if (ret == 0) {//需去掉前面4个才是标准h264流
                //压缩成功 
                //printf("压缩%s成功", ost->enctx->codec_type == AVMEDIA_TYPE_VIDEO ? "视频" : "音频");
                
                pushPakcet(ost->packetList,&pkt, ttt);
            } 
            av_packet_unref(&pkt);
        }
    }

    return NULL;
}


static int writefile(AVFormatContext *oc,MyOutPutStream *ost) {
 
    AVPacket pkt;
    av_init_packet(&pkt);
    int64_t pts = popPacket(ost->packetList, &pkt);
    if (pts < 0) {  return -1; }
    
    write_frame(oc, &ost->enctx->time_base, ost->st, &pkt);
    ost->nextshowpts = pts + 1000000LL * ost->enctx->time_base.num / ost->enctx->time_base.den;
    return 0;
}
static int myclose(MyOutPutStream *ost) {

    av_frame_free(&ost->frame);
    av_frame_free(&ost->newframe);
    av_frame_free(&ost->newframe2);
    av_frame_free(&ost->outframe);
    av_audio_fifo_free(ost->fifo);
    avcodec_free_context(&ost->ctx);
    avformat_close_input(&ost->formatCtx);
    avcodec_free_context(&ost->enctx);

    return 0;
}
int main()
{
    //采集音视频写入文件或rmtp
    int ret=0;
    avdevice_register_all();
    
    MyOutPutStream video_st = { 0 };
    MyOutPutStream audio_st = { 0 };
    GobleData gobledata = { 0 };
    video_st.gobledata = &gobledata;
    audio_st.gobledata = &gobledata;

    const char* filename = "C:\\Users\\lilin\\Desktop\\1.mp4";//"C:\\Users\\lilin\\Desktop\\1.mp4";
    AVFormatContext *oc = NULL;
    avformat_alloc_output_context2(&oc, NULL, NULL, filename);
    if (oc == NULL) {
        printf("AVFormatContext init fail");
        return -1;
    }
    AVOutputFormat *fmt = oc->oformat;

    ret=add_video(oc,&video_st);
    if (ret < 0) { 
        return - 1;
    }
    ret=add_audio(oc,&audio_st);
    if (ret < 0) {
        return -1;
    }
    av_dump_format(oc, 0, filename, 1);//打印输出流

    //打开写头信息
    if (!(fmt->flags&AVFMT_NOFILE)) {
        ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
        if (ret < 0) {
            printf("无法输出到指定位置");
            return -1;
        }
    }
    /*write  stram header if any*/
    AVDictionary* opt = NULL;
    ret = avformat_write_header(oc, &opt);
    av_dict_free(&opt);
    if (ret < 0) {
        printf("open output file error");
        return -1;
    }

    ret=open_video(&video_st);
    if (ret < 0) {
        return -1;
    }
    ret=open_audio(&audio_st);
    if (ret < 0) {
        return -1;
    }
    //30帧
    initPakcetList(&video_st.packetList,300);
    initPakcetList(&audio_st.packetList, 1100);

    pthread_create(&video_st.pthread,NULL, read_thread,&video_st);
    pthread_create(&audio_st.pthread, NULL, read_thread, &audio_st);

    ret = 0;
    int xunhuan = 15*60;//10s
    
    while (ret==0&&xunhuan>0) { 
        if (video_st.nextshowpts <= audio_st.nextshowpts &&video_st.packetList->pkgSize>0) {//写入获取下一个视频包并写入文件
            printf("写入视频%d", xunhuan);
            ret = writefile(oc, &video_st);  
            xunhuan--;
            
        }
        else if (audio_st.packetList->pkgSize > 0) {//写入获取下一个yinping包并写入文件
        //    printf("写入音频%d", xunhuan);
            printf("写入音频%d", xunhuan); 
            ret = writefile(oc, &audio_st);  
        }
        else {
            av_usleep(300);
        }
    }

    video_st.runing = 0;
    audio_st.runing = 0;
    
    destoryPakcetList(video_st.packetList);
    destoryPakcetList(audio_st.packetList);

    pthread_join(video_st.pthread,NULL);
    pthread_join(audio_st.pthread, NULL);
    //
    av_write_trailer(oc);

    
    avformat_close_input(&oc);

    myclose(&video_st);
    myclose(&audio_st);
    //

    av_free(video_st.packetList); video_st.packetList = NULL;

    av_free(audio_st.packetList); audio_st.packetList = NULL;
    getchar();
    printf("ok");

    return 0;
}
 

rtmp只需要将地址改为rtmp

avformat_alloc_output_context2(&oc, NULL, “flv”, filename); 这句改成flv

讨论群261074724

猜你喜欢

转载自blog.csdn.net/Java_lilin/article/details/85123233