ffmpeg编码参数初始化

本文介绍使用FFmpeg进行视频编码的具体参数设置过程,包括视频流的添加、视频编码器的选择及参数调整等关键技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自: http://topic.youkuaiyun.com/u/20081218/09/96dc2d1c-2f27-48a4-8cc2-c00333392b9b.html?91495

 

m_fmt->video_codec = CODEC_ID_H264;

/* 添加视频流 */
m_video_st = av_new_stream(m_oc, 0);
if (!m_video_st) {
return 0;
}
m_videoc=avcodec_alloc_context();
m_videoc = m_video_st->codec;

/* 视频相关参数 */
m_videoc->codec_id = m_fmt->video_codec;
m_videoc->codec_type = CODEC_TYPE_VIDEO;
m_videoc->bit_rate = video_bitrate*1000;
m_videoc->width = video_width;
m_videoc->height = video_height;
m_videoc->time_base.den = 25;
m_videoc->time_base.num = 1;
m_videoc->dct_algo = 0;
m_videoc->gop_size = 12; 
m_videoc->me_pre_cmp=2;
m_videoc->cqp = 26;
m_videoc->me_method =7;
m_videoc->qmin = 3;
m_videoc->qmax = 31;
m_videoc->max_qdiff = 3;
m_videoc->qcompress = 0.5;
m_videoc->qblur = 0.5;
m_videoc->nsse_weight = 8;
m_videoc->i_quant_factor = (float)0.8;
m_videoc->b_quant_factor = 1.25;
m_videoc->b_quant_offset = 1.25;

m_videoc->pix_fmt = PIX_FMT_YUV420P;//当前YUV420

if (m_videoc->codec_id == CODEC_ID_MPEG2VIDEO) {
m_videoc->max_b_frames = 2;
}
if (m_videoc->codec_id == CODEC_ID_MPEG1VIDEO){
m_videoc->mb_decision=2;
}

if(!strcmp(m_oc->oformat->name, "mp4") 
|| !strcmp(m_oc->oformat->name, "mov") 
|| !strcmp(m_oc->oformat->name, "3gp"))
m_videoc->flags |= CODEC_FLAG_GLOBAL_HEADER;

  /* 检查参数是否设置完毕*/
  if (av_set_parameters(m_oc, NULL) < 0) {
return 0;
  }
  dump_format(m_oc, 0, filename, 1);

/* 所有视频设置完毕,打开视频解码器,并打开必要的编码缓冲器 */ 
  if (m_video_st){

AVCodec *video_codec;

/* 查找视频解码器 */
video_codec = avcodec_find_encoder(m_videoc->codec_id);
if (!video_codec) {
return 0;
}

/* 打开视频解码器 */
if (avcodec_open(m_videoc, video_codec) < 0) {
return 0;
}

video_outbuf = NULL;
if (!(m_oc->oformat->flags & AVFMT_RAWPICTURE)) {
/* allocate output buffer */
/* XXX: API change will be done */
/* buffers passed into lav* can be allocated any way you prefer,
as long as they're aligned enough for the architecture, and
they're freed appropriately (such as using av_free for buffers
allocated with av_malloc) */
video_outbuf_size = 200000;
video_outbuf = (uint8_t *)av_malloc(video_outbuf_size);

}

/* allocate the encoded raw picture */
picture = alloc_picture(m_videoc->pix_fmt, m_videoc->width, m_videoc->height);
if (!picture) {
return 0;
}

/* if the output format is not YUV420P, then a temporary YUV420P
picture is needed too. It is then converted to the required
output format */
tmp_picture = NULL;
if (m_videoc->pix_fmt != PIX_FMT_YUV420P) {
tmp_picture = alloc_picture(PIX_FMT_YUV420P, m_videoc->width, m_videoc->height);
if (!tmp_picture) {
return 0;
}
}

 

 

if(!strcmp(m_oc->oformat->name, "mp4") 
|| !strcmp(m_oc->oformat->name, "mov") 
|| !strcmp(m_oc->oformat->name, "3gp")) 
m_videoc->flags |= CODEC_FLAG_GLOBAL_HEADER;

这段改成这样就可以了

if(!strcmp(m_oc->oformat->name, "mp4") 
|| !strcmp(m_oc->oformat->name, "mov") 
|| !strcmp(m_oc->oformat->name, "3gp"))
m_videoc->flags |=CODEC_FLAG_QSCALE;
以下是使用FFmpeg库进行推流的初始化代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <signal.h> #include <sys/time.h> #include <sys/select.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/avutil.h> #include <libavutil/pixdesc.h> #include <libavutil/time.h> #include <libswscale/swscale.h> int main(int argc, char *argv[]) { AVFormatContext *fmt_ctx = NULL; AVOutputFormat *out_fmt = NULL; AVStream *video_st = NULL; AVCodecContext *codec_ctx = NULL; AVCodec *codec = NULL; int ret; // 初始化FFmpeg库 av_register_all(); avformat_network_init(); // 打开输出文件 ret = avformat_alloc_output_context2(&fmt_ctx, NULL, "flv", "rtmp://127.0.0.1/live/stream"); if (ret < 0) { printf("Could not allocate output format context\n"); return -1; } out_fmt = fmt_ctx->oformat; // 添加音视频流 video_st = avformat_new_stream(fmt_ctx, NULL); if (!video_st) { printf("Could not create video stream\n"); return -1; } codec_ctx = video_st->codec; // 设置编码参数 codec_ctx->codec_id = out_fmt->video_codec; codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO; codec_ctx->width = 640; codec_ctx->height = 480; codec_ctx->time_base.num = 1; codec_ctx->time_base.den = 25; codec = avcodec_find_encoder(codec_ctx->codec_id); if (!codec) { printf("Could not find encoder\n"); return -1; } // 打开编码器 ret = avcodec_open2(codec_ctx, codec, NULL); if (ret < 0) { printf("Could not open encoder\n"); return -1; } // 打开输出流 ret = avio_open(&fmt_ctx->pb, fmt_ctx->filename, AVIO_FLAG_WRITE); if (ret < 0) { printf("Could not open output file\n"); return -1; } // 写文件头 ret = avformat_write_header(fmt_ctx, NULL); if (ret < 0) { printf("Error occurred when writing file header\n"); return -1; } // 推流 AVFrame *frame = av_frame_alloc(); AVPacket pkt; int i; for (i = 0; i < 100; i++) { av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; // 生成测试图像 uint8_t *data[1]; int linesize[1]; int height = codec_ctx->height; int width = codec_ctx->width; data[0] = (uint8_t*)malloc(width * height * 3); int y; for (y = 0; y < height; y++) { memset(data[0] + y * width * 3, y + i * 3, width * 3); } linesize[0] = width * 3; // 填充AVFrame frame->format = codec_ctx->pix_fmt; frame->width = codec_ctx->width; frame->height = codec_ctx->height; av_image_fill_arrays(frame->data, frame->linesize, data[0], codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, 1); // 编码并发送数据 int got_picture = 0; ret = avcodec_encode_video2(codec_ctx, &pkt, frame, &got_picture); if (ret < 0) { printf("Error encoding video frame\n"); return -1; } if (got_picture) { pkt.stream_index = video_st->index; ret = av_write_frame(fmt_ctx, &pkt); if (ret < 0) { printf("Error writing video frame\n"); return -1; } } av_free_packet(&pkt); av_freep(&data[0]); } // 写文件尾 av_write_trailer(fmt_ctx); // 释放资源 avio_close(fmt_ctx->pb); avcodec_close(codec_ctx); avformat_free_context(fmt_ctx); av_frame_free(&frame); return 0; } ``` 这段代码将以FLV格式将一组测试图像推流到`rtmp://127.0.0.1/live/stream`位置。你可以根据需要修改推流地址等参数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值