ffmpeg 编码示例

ffmpeg 自身有h264的解码模块。编码却需要打包入其他编码库。具体效率分析参看: 主流开源编解码器Xvid,x264,ffmpeg 性能对比(转)


实现编码定义了四个函数。


一:帧添加结束后flush,将未输出的avpacket写入

int vflush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index) {
    int ret = 0;
    int got_frame;
    AVPacket enc_pkt;
    if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities
            & CODEC_CAP_DELAY))
        return 0;
    av_init_packet(&enc_pkt);
    while (1) {
        enc_pkt.data = NULL;
        enc_pkt.size = 0;
        ret = avcodec_encode_video2(fmt_ctx->streams[stream_index]->codec,
                &enc_pkt, NULL, &got_frame);
        if (ret < 0)
            break;
        if (!got_frame) {
            ret = 0;
            break;
        }
        ret = av_write_frame(fmt_ctx, &enc_pkt);
        av_free_packet(&enc_pkt);
        if (ret < 0)
            break;
    }

    return ret;
}



二 编码前初始化

ENCODE_KEY* encode_init(char* h264file)
{
    ENCODE_KEY* temp = (ENCODE_KEY*) malloc(sizeof(ENCODE_KEY));
    AVFormatContext* pFormatCtx;
    AVOutputFormat* fmt;
    AVStream* video_st;
    AVCodecContext* pCodecCtx;
    AVCodec* pCodec;
    AVFrame* pFrame;
    char* out_file = h264file;
    av_register_all();
    pFormatCtx = avformat_alloc_context();
    fmt = av_guess_format(NULL, param->h264file, NULL);
    pFormatCtx->oformat = fmt;

    if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) {
        dmprint_string("Failed to open output file! ");
        return NULL;
    }

    video_st = avformat_new_stream(pFormatCtx, 0);
    video_st->time_base.num = 1;
    video_st->time_base.den = 30;

    if (video_st == NULL) {
        return NULL;
    }
    //Param that must set
    pCodecCtx = video_st->codec;
    pCodecCtx->codec_id =AV_CODEC_ID_H264;
    pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
    pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
    pCodecCtx->width =640;
    pCodecCtx->height =640;
    pCodecCtx->time_base.num = 1;
    pCodecCtx->time_base.den = 30;
    //pCodecCtx->bit_rate = 1600000;
    pCodecCtx->gop_size = 150;
    pCodecCtx->keyint_min =30;
    pCodecCtx->thread_count =15;
    pCodecCtx->me_range = 16;
    pCodecCtx->max_qdiff = 4;
    pCodecCtx->qcompress = 0.6;

    pCodecCtx->max_b_frames = 0;
    pCodecCtx->b_frame_strategy = true;
    //量化因子
    pCodecCtx->qmin = 16;
    pCodecCtx->qmax =24;

    av_opt_set(pCodecCtx->priv_data, "preset", "ultrafast", 0);
    av_opt_set(pCodecCtx->priv_data, "tune", "zerolatency", 0);

  
    int ret;
    pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
    if (!pCodec) {
        puts("Can not find encoder!");
        return NULL;
    }
    if ((ret = avcodec_open2(pCodecCtx, pCodec, &p)) < 0) {
           printf("Failed to open encoder! ret = %d\n",ret);
        return NULL;
    }


    pFrame = av_frame_alloc();
    pFrame->width = param->width;
    pFrame->height = param->height;
    pFrame->format = param->pic_fmt;
   
    avformat_write_header(pFormatCtx, NULL);

    temp->pFormatCtx = pFormatCtx;
    temp->video_st = video_st;
    temp->pCodecCtx=pCodecCtx;
    temp->pFrame=pFrame;
    return temp;
}


ENCODE_KEY是封装的一个结构体,里面有编码所用到的结构体集合和部分参数。
内容如下;
typedef struct encode_key{
    AVFormatContext* pFormatCtx;
    AVCodecContext* pCodecCtx;
    AVStream* video_st;
    AVFrame* pFrame;
}ENCODE_KEY;    


为了实现同时支持编码多个视频,所以将这些封装为结构体传送指针。


三 编码一帧

int encode_frame(AVFrame* frame,ENCODE_KEY* temp)
{
    AVPacket encode_pkt;
    int got_picture  = 0;
    int encode_ret = 0;
    av_new_packet(&encode_pkt, avpicture_get_size(temp->pCodecCtx->pix_fmt, temp->pCodecCtx->width,
            temp->pCodecCtx->height));
    int ret = 0;

    ret = avcodec_encode_video2(temp->pCodecCtx, &encode_pkt, frame, &got_picture);

    if (ret < 0) {
        encode_ret = -1;
        goto encode_end;
    }
    if (got_picture == 1) {
        encode_pkt.stream_index = temp->video_st->index;
        ret = av_write_frame(temp->pFormatCtx, &encode_pkt);
    }
    else
    {
       //
    }
encode_end:
    av_free_packet(&encode_pkt);
    return encode_ret;

}




四  停止编码,释放资源

int encode_release(ENCODE_KEY* temp)
{
    int ret = vflush_encoder(temp->pFormatCtx, 0);
    if (ret < 0) {
        
        return -1;
    }


    //Write file trailer
    av_write_trailer(temp->pFormatCtx);

    //Clean
    if (temp->video_st) {
        avcodec_close(temp->video_st->codec);
        av_free(temp->pFrame);
    }
    avio_close(temp->pFormatCtx->pb);
    avformat_free_context(temp->pFormatCtx);
  
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值