ffmpeg拉流rtmp保存h264和aac

代码实现
#include <thread>
#include <iostream>
#include <fstream>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}


int mp4toannexb(AVBSFContext* bsf_ctx, AVPacket *pkt, std::ofstream& out)
{
    int ret;

    ret = av_bsf_send_packet(bsf_ctx, pkt);
    if (ret < 0) {
        std::cout << "bsf send packet failed, errno:" << ret << std::endl;
        return -1;
    }

    for(;;) {
        ret = av_bsf_receive_packet(bsf_ctx, pkt);
        if (AVERROR_EOF == ret || AVERROR(EAGAIN) == ret) {
            return 0;
        }
        if (ret < 0) {
            std::cout << "Could not receive packet, errno:" << ret << std::endl;
            return -1;
        }
        out.write((const char*)pkt->data, pkt->size); 
    }
    return 0;
}


int find_sample_index(int samplerate)
{
    const int adts_sample_rates[16] = {
	    96000,
	    88200,
	    64000,
	    48000,
	    44100,
	    32000,
	    24000,
	    22050,
	    16000,
	    12000,
	    11025,
	    8000,
	    7350,
	    -1,
	    -1,
	    -1,
    };
    for(int i=0; i < 16;i++)
    {
        if(samplerate == adts_sample_rates[i])
            return i;
    }
    return 15;
}

int main()
{  
    AVOutputFormat  *ofmt     = NULL;
    AVFormatContext *ifmt_ctx = NULL;
    AVBSFContext    *bsf_ctx  = NULL;
    AVPacket        *pkt      = NULL;
    const char *in_filename   = "rtmp://vlive2018.people.com.cn/2010/cctv132019/live_2000";
    int ret                   = -1;
    int audio_index           = -1;
    int video_index           = -1;
    bool stop                 = false;
    std::ofstream outh264("out.h264", std::ios::binary | std::ios::trunc);
    std::ofstream outaac("out.aac", std::ios::binary | std::ios::trunc);
    // 初始化网络
    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;
    }
    
    audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    if (audio_index < 0) {
        std:: cout << "Could not find stream " << std::string(av_get_media_type_string(AVMEDIA_TYPE_AUDIO)) << std::endl;
        return -1;
    }

    video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if (video_index < 0) {
        std:: cout <<  "Could not find stream " << std::string(av_get_media_type_string(AVMEDIA_TYPE_VIDEO)) << std::endl;
        return -1;
    }
 
    av_dump_format(ifmt_ctx, 0, in_filename, 0);
    
    const AVBitStreamFilter *filter = av_bsf_get_by_name("h264_mp4toannexb");
    if (NULL == filter) {
        std:: cout << "Could not create filter" << std::endl;
        return -1;
    }

    ret = av_bsf_alloc(filter, &bsf_ctx);
    if (ret < 0) {
        printf("Could not alloc bitstream filter \n");
        return -1;
    }

    // avcodec_parameters_from_context
    ret = avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[video_index]->codecpar);
    if (ret < 0) {
        printf("Parameter copy filed, errno: %d \n", ret);
        return -1;
    }

    ret = av_bsf_init(bsf_ctx);
    if (ret < 0) {
        printf("BSF init failed, errno: %d \n", ret);
        return -1;
    }
    
    std::thread th([&]{
        AVCodecParameters *params = ifmt_ctx->streams[audio_index]->codecpar;
        while (av_read_frame(ifmt_ctx, pkt) >= 0 && !stop) {
            if (pkt->stream_index == video_index)
            {
                mp4toannexb(bsf_ctx, pkt, outh264);
            }
            if (pkt->stream_index == audio_index) 
            {        
                char bits[7] = {0};
                int aac_frame_length = 7 + pkt->size;
                int sample_index = find_sample_index(params->sample_rate);
                int channels = params->channels;
                if (channels == 8) {
                    channels = 7;
                }
            
                bits[0] = 0xff;
                bits[1] = 0xf1;
                bits[2] = (params->profile << 6);
                bits[2] |= (sample_index << 2);
                bits[2] |= (channels >> 2);
                bits[3] |= ((channels << 6) & 0xC0);
                bits[3] |= (aac_frame_length >> 11);
                bits[4] = ((aac_frame_length >> 3) & 0xFF);
                bits[5] = ((aac_frame_length << 5) & 0xE0);
                bits[5] |= (0x7FF >> 6);
                bits[6] = 0xfc;
            
                outaac.write((const char*)bits, 7);
                outaac.write((const char*)pkt->data, pkt->size);
            }           
            av_packet_unref(pkt);
        }         
    });
    
    std::cout << "input char to stop" << std::endl;
    while(getchar() != 'q');

    stop = true;
    if (th.joinable())
    {
	    th.join();
    }
    
    // 释放
    outh264.close();
    outaac.close();
    avformat_close_input(&ifmt_ctx);
    av_packet_free(&pkt);
    av_bsf_free(&bsf_ctx);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值