使用ffmpeg将实时流保存为AVI

使用ffmpeg将实时流保存为AVI

项目中需要将编码器编码出的H264数据保存为avi格式文件。使用ffmpeg接口进行实现。

ffmpeg一般是直接打开本地视频文件(如avi、mp4等)或者网络视频流(如:rtmp流媒体等),只需要直接将本地视频文件名或者流媒体的URL作为avformat_open_input的参数即可。但是这次的项目中,则需要直接将编码器编码出的H264流保存为avi文件。原本准备参考雷神的《ffmpeg 从内存中读取数据(或将数据输出到内存)》,但是这样对现有的程序结构改动比较大,因此考虑更为直接的方式,跳过avformat_open_input过程:

#include "libavformat/avformat.h"

int main(int argc, char **argv)
{
    int ret;
    char buf[] = ""; 
    AVOutputFormat *ofmt_ctx = NULL;
    AVStream *out_stream = NULL;
    AVPacket pkt = { 0 }; 

    av_register_all();
    av_log_set_level(AV_LOG_DEBUG);


    /* allocate the output media context */
    avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename);  
    if (!ofmt_ctx) {  
        printf("Could not deduce output format from file extension: using AVI.\n");
        avformat_alloc_output_context2(&ofmt_ctx, NULL, "avi", filename);
    }
    if(!ofmt_ctx) {
        goto exit;
    }

    out_stream = avformat_new_stream(ofmt_ctx, NULL);   
    if (!out_stream) {  
        printf( "Failed allocating output stream\n");  
        ret = AVERROR_UNKNOWN;  
        goto exit;  
    } 

    AVCodecContext *avctx = out_stream->codec;
    avctx->codec_type = AVMEDIA_TYPE_VIDEO;
    /*此处,需指定编码后的H264数据的分辨率、帧率及码率*/
    avctx->codec_id = AV_CODEC_ID_H264;
    avctx->bit_rate = 2000000;
    avctx->width = 640;
    avctx->height = 480;
    avctx->time_base.num = 1;
    avctx->time_base.den = 30;

    /* print output stream information*/
    av_dump_format(ofmt_ctx, 0, filename, 1);

    if (!(ofmt->flags & AVFMT_NOFILE)) 
    {  
        ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);  
        if (ret < 0) {  
            printf( "Could not open output file '%s'\n", filename);  
            goto exit;  
        }
        printf("Open output file success!\n");
    }

    //写文件头(Write file header)  
    ret = avformat_write_header(ofmt_ctx, NULL);  
    if (ret < 0) {  
        printf( "write avi file header failed\n");  
        goto exit;  
    }  
    printf("Write avi header success!\n");

    while(...) {
        av_init_packet(&pkt); 

        // get a video frame(从编码器获取一帧编码后的H264数据)
        ...

        // determine whether the I frame
        if(/* I frame */) { // 判断该H264帧是否为I帧
            pkt.flags |= AV_PKT_FLAG_KEY;
        } else { /* p frame*/
            pkt.flags = 0;
        }

        pkt.dts = pkt.pts = AV_NOPTS_VALUE;
        pkt.size = size; /*帧大小*/

        pkt.data = data; /*帧数据*/
        if(!pkt.data) {
            printf("no data\n");
        }   

        //写入(Write)   
        ret = av_interleaved_write_frame(ofmt_ctx, &pkt);  
        if (ret < 0) {  
            av_strerror(ret, buf, 1024);    
        }
        av_packet_unref(&pkt);  
    }

    av_write_trailer(ofmt_ctx);  
exit:
        /* close output */  
    if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) 
        avio_close(ofmt_ctx->pb); 

    avformat_free_context(ofmt_ctx);

    return 0
}

上面的代码只贴出了创建ffmpeg输入流、创建并保存数据到AVI文件的部分程序,方式已验证,能正常录制avi并使用VLC等进行播放。若是想保存为MP4文件,则还需另外写入extradata,否则会出现VLC能播放,但其它播放器无法播放,或播放帧率不对的问题。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值