cv::Mat编码H264

音视频应用开发系列文章目录

本文基于ffmpeg and opencv封装H264编码器类AvH264,编码opencv的Mat数据类型图像为ffmpeg的AVPacket数据类型的H264数据。

编码流程

打开编码器 // 初始化一些H264编码器的参数

编码

关闭编码器

编码器参数

typedef struct AvH264EncConfig_T {

	int width = 320;
	int height = 240;
	int frame_rate = 25;
	int64_t bit_rate = 320000;
	int gop_size = 250;
	int max_b_frames = 0;
}AvH264EncConfig;

width:输出流的宽度

height:输出流的高度

frame_rate:帧率

bit_rate:比特率

gop_size:可以理解I帧间隔,间隔多少帧取一个I帧,值越大,输出流空间少,质量较差;值越大,输出空间大,质量较好

max_b_frames:最大B帧数

打开编码器

int open(AvH264EncConfig h264_config);

h264_config:编码器参数

编码

AVPacket *encode(cv::Mat mat);

mat:opencv Mat 图像

返回值:ffmpeg AVPacket流

关闭编码器

void close();

AvH264编码器类

AvH264.h

#ifndef _AV_H264_H_
#define _AV_H264_H_

/***********************************************************
**	Author:kaychan
**	Data:2019-11-29
**  Mail:1203375695@qq.com
**	Explain:a h264 codec
***********************************************************/

#include <opencv2/opencv.hpp>

#define __STDC_CONSTANT_MACROS 
#ifdef __cplusplus
extern "C" {
#endif
#include <libavutil/time.h>
#include <libavutil/mathematics.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavdevice/avdevice.h>
#include <libswresample/swresample.h>
#ifdef __cplusplus
};
#endif

typedef struct AvH264EncConfig_T {

	int width = 320;
	int height = 240;
	int frame_rate = 25;
	int64_t bit_rate = 320000;
	int gop_size = 250;
	int max_b_frames = 0;
}AvH264EncConfig;

class AvH264 {

public:
	AvH264();
	int open(AvH264EncConfig h264_config);
	AVPacket *encode(cv::Mat mat);
	void close();
private:
	AVCodec *cdc_;
	AVCodecContext *cdc_ctx_;
	AVFrame *avf_;
	AVPacket *avp_;
	int frame_size_;
	int pts_;
};

#endif

AvH264.cpp

#include "AvH264.h"

AvH264::AvH264() {

	cdc_ = NULL;
	cdc_ctx_ = NULL;
	avf_ = NULL;
	avp_ = NULL;
}

int AvH264::open(AvH264EncConfig h264_config) {

	pts_ = 0;
	cdc_ = avcodec_find_encoder(AV_CODEC_ID_H264);
	if (!cdc_) {

		return -1;
	}
	cdc_ctx_ = avcodec_alloc_context3(cdc_);
	if (!cdc_ctx_) {

		return -1;
	}
	cdc_ctx_->bit_rate = h264_config.bit_rate;
	cdc_ctx_->width = h264_config.width;
	cdc_ctx_->height = h264_config.height;
	cdc_ctx_->time_base = { 1, h264_config.frame_rate };
	cdc_ctx_->framerate = { h264_config.frame_rate, 1 };
	cdc_ctx_->gop_size = h264_config.gop_size;
	cdc_ctx_->max_b_frames = h264_config.max_b_frames;
	cdc_ctx_->pix_fmt = AV_PIX_FMT_YUV420P;
	cdc_ctx_->codec_id = AV_CODEC_ID_H264;
	cdc_ctx_->codec_type = AVMEDIA_TYPE_VIDEO;
	//cdc_ctx_->qmin = 10;
	//cdc_ctx_->qmax = 51;
	//cdc_ctx_->qcompress = 0.6;
	AVDictionary *dict = 0;
	av_dict_set(&dict, "preset", "slow", 0);
	av_dict_set(&dict, "tune", "zerolatency", 0);
	av_dict_set(&dict, "profile", "main", 0);
	avf_ = av_frame_alloc();
	avp_ = av_packet_alloc();
	if (!avf_ || !avp_) {

		return -1;
	}
	frame_size_ = cdc_ctx_->width * cdc_ctx_->height;
	avf_->format = cdc_ctx_->pix_fmt;
	avf_->width = cdc_ctx_->width;
	avf_->height = cdc_ctx_->height;
	// alloc memory
	int r = av_frame_get_buffer(avf_, 0);
	if (r < 0) {

		return -1;
	}
	r = av_frame_make_writable(avf_);
	if (r < 0) {

		return -1;
	}
	return avcodec_open2(cdc_ctx_, cdc_, &dict);
}

void AvH264::close() {

	if(cdc_ctx_) avcodec_free_context(&cdc_ctx_);
	if (avf_) av_frame_free(&avf_);
	if (avp_) av_packet_free(&avp_);
}

AVPacket *AvH264::encode(cv::Mat mat) {

	if (mat.empty()) return NULL;
	cv::resize(mat, mat, cv::Size(cdc_ctx_->width, cdc_ctx_->height));
	cv::Mat yuv;
	cv::cvtColor(mat, yuv, cv::COLOR_BGR2YUV_I420);
	unsigned char *pdata = yuv.data;
	// fill yuv420
	// yyy yyy yyy yyy
	// uuu
	// vvv
	avf_->data[0] = pdata;
	avf_->data[1] = pdata + frame_size_;
	avf_->data[2] = pdata + frame_size_ * 5 / 4;
	avf_->pts = pts_++;
	int r = avcodec_send_frame(cdc_ctx_, avf_);
	if (r >= 0) {
		
		r = avcodec_receive_packet(cdc_ctx_, avp_);
		if (r == 0) {

			//avp_->stream_index = 0;
			return avp_;
		}
		if (r == AVERROR(EAGAIN) || r == AVERROR_EOF) {

			return NULL;
		}	
	}
	return NULL;
}

调用实例

AvH264 h264;
AvH264EncConfig conf;
conf.bit_rate = 320000;
conf.width = 320;
conf.height = 240;
conf.gop_size = 250;
conf.max_b_frames = 0;
conf.frame_rate = 25;
h264.open(conf);
while{

	// get mat
	cv::Mat f = GetMat();
	// do encode
	AVPacket *pkt = h264_.encode(f);
	// do pkt
}
h264.close();

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值