ffmpeg extrai stream rtmp e salva flv

O código é implementado da seguinte forma:
#include <thread>
#include <iostream>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}

int main()
{  
    AVOutputFormat *ofmt = NULL;
    AVFormatContext *ifmt_ctx = NULL;
    AVFormatContext *ofmt_ctx = NULL;
    AVPacket *pkt = NULL;
    const char *in_filename = "rtmp://vlive2018.people.com.cn/2010/cctv132019/live_2000";
    const char *out_filename = "out.flv";
    int ret = -1;
    bool stop = false;
    // 初始化网络
    avformat_network_init(); 

    // 初始化输入格式上下文  
    if ((ifmt_ctx = avformat_alloc_context()) == NULL) {
        std:: cout << "avformat_alloc_context failed." << std::endl;
        exit(1);
    }

    // 打开输入格式上下文
    if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
        std:: cout << "Could not open input file." << std::endl;
        exit(1);
    }
    
    // 获取输入信息
    if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
        std:: cout << "Failed to retrieve input stream information" << std::endl;
        return -1;
    }
    
    // 申请pkt
    if (!(pkt = av_packet_alloc())) {
        std:: cout << "Could not allocate packet"<< std::endl;
        return -1;
    }
    
    // 打开输出格式上下文
    if ((ret = avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename)) < 0 || !ofmt_ctx) {
        std:: cout << "Could not create output context" << std::endl; 
        return -1;
    }
    ofmt = ofmt_ctx->oformat;    

    // 关联输入输出
    for (int i = 0; i < ifmt_ctx->nb_streams; i++) {
        AVStream *in_stream = ifmt_ctx->streams[i];
        AVStream *out_stream = avformat_new_stream(ofmt_ctx, NULL);
        if (!out_stream) {
            std:: cout << "Failed allocating output stream" << std::endl;
        } else
        {
            if ((ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar)) < 0) {
                std:: cout << "Failed to copy codec context to out_stream codecpar context" << std::endl;           
            }
        }
    }
 
    av_dump_format(ifmt_ctx, 0, in_filename, 0);
    av_dump_format(ofmt_ctx, 0, out_filename, 1);
    
    if (!(ofmt->flags & AVFMT_NOFILE)) {
        if ((ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE)) < 0) {
            std:: cout << "Could not open output URL" << std::string(out_filename) << std::endl;
            return -1;
        }
    }
    // 写入头
    if ((ret = avformat_write_header(ofmt_ctx, NULL)) < 0) {
        std:: cout << "Error occurred when opening output URL" << std::endl;
        return -1;
    }
    
    std::thread th([&]{
        while (av_read_frame(ifmt_ctx, pkt) >= 0 && !stop) {           
            // 写入数据
            if (av_interleaved_write_frame(ofmt_ctx, pkt) < 0) {
                std:: cout << "Error muxing packet" << std::endl;
                break;
            }
            av_packet_unref(pkt);
        }
        // 写入尾数据
        av_write_trailer(ofmt_ctx);    
    });
    
    std::cout << "input char to stop" << std::endl;
    while(getchar() != 'q');

    stop = true;
    if (th.joinable())
    {
	    th.join();
    }
    
    // 释放
    avformat_close_input(&ifmt_ctx);
    av_packet_free(&pkt);
    /* close output */
    if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE)) {
        avio_close(ofmt_ctx->pb);
    } 
    avformat_free_context(ofmt_ctx);

    return 0;
}

おすすめ

転載: blog.csdn.net/xiehuanbin/article/details/133177014