ffmpeg进行h264编码

首先需要穿件编码的上下文以及指定编码器代码如下

//视频编码上下文
- (AVCodecContext *)get_avcodecContext_fv{
    AVCodecContext *c_ctx = NULL;
    AVCodec *codec = NULL;
    codec = avcodec_find_encoder_by_name("libx264");
//    AV_CODEC_ID_H264  avcodec_find_encoder(AV_CODEC_ID_H264);
    c_ctx = avcodec_alloc_context3(codec);
//    c_ctx->flags = AV_CODEC_FLAG_GLOBAL_HEADER;
    c_ctx->profile = FF_PROFILE_H264_HIGH_444;
    c_ctx->level    = 50;
    c_ctx->bit_rate = self.config.bit_rate;
    c_ctx->width    = self.config.width;
    c_ctx->height    = self.config.height;
    c_ctx->time_base = (AVRational){1,self.config.time_base_m};
    c_ctx->framerate = (AVRational){25,1};
    c_ctx->gop_size = 10;
    c_ctx->max_b_frames = 1;
    c_ctx->thread_count = 8;
    c_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
        if (codec->id == AV_CODEC_ID_H264)
    av_opt_set(c_ctx->priv_data, "preset", "slow", 0);
    output_en_codec_v = codec;
    output_en_ctx_v = c_ctx;
    c_ctx->thread_count = 8;
    int is_open = avcodec_open2(c_ctx, codec, NULL);
    if (is_open < 0) {
        fprintf(stderr, "encode_ctx open faild");
        return NULL;
    }
    if (!c_ctx) {
        fprintf(stderr, "Failed to open c_ctx");
        return NULL;
    }
    return c_ctx;
}

ffmpeg可以进行软编码也可以进行硬编码 硬编码在编译ffmpeg库的时候需要进行特殊的配置在以后的博客中我会单独在写一个ffmpeg 实现硬编码的方式 本文只讲述 ffmpeg如何进行软编码 

配置编码使用AVFrame 


AVFrame* get_avframe_video(AVCodecContext *output_en_ctx_v){
    AVFrame *av_frame = NULL;
    av_frame = av_frame_alloc();
    if (!av_frame) {
        fprintf(stderr,"av_frame_alloc failed");
        goto __ERROR;
    }
    av_frame->width     = output_en_ctx_v->width;
    av_frame->height    = output_en_ctx_v->height;
    av_frame->format = output_en_ctx_v->pix_fmt;//AV_PIX_FMT_YUV420P;
    av_frame_get_buffer(av_frame, 32);
    if (!av_frame->data[0]) {
        printf("Error, Failed to alloc buf in frame!\n");
        return NULL;
    }
    return av_frame;
__ERROR:
    if (!av_frame) {
        av_frame_free(&av_frame);
    }
    return NULL;
}

进行编码ffmpeg在16年还是17年以后推荐使用的api为

int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);

int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);

- (BOOL)encode_video:(AVCodecContext *)output_ctx and_packet:(AVPacket *)output_avpacket and_frame:(AVFrame *)output_avframe with_h264file:(FILE*)h264_file{
    BOOL is_encode_success = NO;
    int ret = -1;
    ret = avcodec_send_frame(output_ctx, output_avframe);
    while (ret >= 0) {
        ret = avcodec_receive_packet(output_ctx, output_avpacket);
        if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
            return is_encode_success;
        }else if( ret < 0){
            printf("Error, encoding audio frame\n");
            exit(-1);
        }
        
        if (h264_file) {
            fwrite(output_avpacket->data, 1, output_avpacket->size, h264_file);
        }else{
            [self separation_avpacket_with_avpacket:output_avpacket];
        }
        is_encode_success = YES;
        av_packet_unref(output_avpacket);
    }
    return is_encode_success;
}

由ffmpeg 编码后的avpacket 可以使用ffmpeg 进行推流 也可以使用rtmp 进行推流 如果使用rtmp进行推流 则需要自己构建rtmppacket 

avpacket如何rtmppacket的构建在下个博客中进行讲解

这里编码出的avpacket 可以直接写入文件生成.h264 文件 需要注意的是 在编码时需要指定时间基 时间基的指定可以有多种方式

1.每次自增1

2.采取当前时间戳同步来进行赋值

这两种方式都可以 正常的播放 

如果不指定时间戳,写入的h264文件在播放时会特别快 再有就是 如果写入flv文件 需要注意的问题是 在停止采集时需要向编码器发送空数据,将编码器缓冲区的数据取出

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值