实例代码
int video_capture()
{
AVFormatContext* m_fmt_ctx = NULL;
AVInputFormat* m_input_fmt = NULL;
int video_stream = -1;
avdevice_register_all();
//注册所有的编解码器
avcodec_register_all();
//const char* deviceName = "video=screen-capture-recorder";
//const char* inputformat = "dshow";
const char* deviceName = "desktop";
const char* inputformat = "gdigrab";
int FPS = 15;
m_fmt_ctx = avformat_alloc_context();
m_input_fmt = av_find_input_format(inputformat);
AVDictionary* deoptions = NULL;
av_dict_set_int(&deoptions, "framerate", FPS, AV_DICT_MATCH_CASE);
av_dict_set_int(&deoptions, "rtbufsize", 3041280 * 100 *5, 0);//默认大小3041280
//av_dict_set(&deoptions, "video_size", "640x480", AV_DICT_MATCH_CASE);
int ret = avformat_open_input(&m_fmt_ctx, deviceName, m_input_fmt, &deoptions);
if (ret != 0) {
return XError(ret);
}
av_dict_free(&deoptions);
ret = avformat_find_stream_info(m_fmt_ctx, NULL);
if (ret < 0) {
return XError(ret);
}
av_dump_format(m_fmt_ctx, 0, deviceName, 0);
video_stream = av_find_best_stream(m_fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (video_stream < 0) {
return -1;
}
AVCodecContext * _codec_ctx = m_fmt_ctx->streams[video_stream]->codec;
AVCodec* _codec = avcodec_find_decoder(_codec_ctx->codec_id);
//_codec = avcodec_find_decoder_by_name("h264_qsv");
if (_codec == NULL) {
return -1;
}
ret = avcodec_open2(_codec_ctx, _codec, NULL);
if (ret != 0) {
return -1;
}
int width = m_fmt_ctx->streams[video_stream]->codec->width;
int height = m_fmt_ctx->streams[video_stream]->codec->height;
int fps = m_fmt_ctx->streams[video_stream]->codec->framerate.num > 0 ? m_fmt_ctx->streams[video_stream]->codec->framerate.num : 25;
AVPixelFormat videoType = m_fmt_ctx->streams[video_stream]->codec->pix_fmt;
std::cout << "avstream timebase : " << m_fmt_ctx->streams[video_stream]->time_base.num << " / " << m_fmt_ctx->streams[video_stream]->time_base.den << endl;
//////////////////////////////////////////////////////////////////////////////////////////////////////////
AVDictionary* enoptions = 0;
av_dict_set(&enoptions, "preset", "superfast", 0);
//av_dict_set(&enoptions, "preset", "slow", 0);
av_dict_set(&enoptions, "tune", "zerolatency", 0);
///4 初始化编码器 AV_CODEC_ID_H264
AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
{
std::cout << "avcodec_find_encoder failed!" << endl;
return NULL;
}
//视频编码器上下文
AVCodecContext* vc = avcodec_alloc_context3(codec);
if (!vc)
{
std::cout << "avcodec_alloc_context3 failed!" << endl;
return NULL;
}
std::cout << "avcodec_alloc_context3 success!" << endl;
vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
vc->codec_id = AV_CODEC_ID_H264;
vc->codec_type = AVMEDIA_TYPE_VIDEO;
vc->pix_fmt = AV_PIX_FMT_YUV420P;
vc->width = width;
vc->height = height;
vc->time_base.num = 1;
vc->time_base.den = FPS;
vc->framerate = { FPS,1 };
vc->bit_rate = 1024*1000;
vc->gop_size = 120;
vc->qmin = 10;
vc->qmax = 51;
vc->max_b_frames = 0;//NO B Frame
//vc->me_range = 16;
//vc->max_qdiff = 4;
//vc->qcompress = 0.6;
vc->profile = FF_PROFILE_H264_MAIN;
/*unsigned char sps_pps[23] = { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x0a, 0xf8, 0x0f, 0x00, 0x44, 0xbe, 0x8,
0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x38, 0x80 };
vc->extradata_size = 23;
vc->extradata = (uint8_t*)av_malloc(23 + AV_INPUT_BUFFER_PADDING_SIZE);
if (vc->extradata == NULL) {
printf("could not av_malloc the video params extradata!\n");
return -1;
}
memcpy(vc->extradata, sps_pps, 23);*/
//打开视频编码器
ret = avcodec_open2(vc, codec, &enoptions);
if (ret != 0)
{
return XError(ret);
}
std::cout << "avcodec_open2 success!" << endl;
av_dict_free(&enoptions);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///2 初始化格式转换上下文
SwsContext* vsc = NULL;
vsc = sws_getCachedContext(vsc,
width, height, (AVPixelFormat)videoType, //源宽、高、像素格式
width, height, AV_PIX_FMT_YUV420P,//目标宽、高、像素格式
SWS_BICUBIC, // 尺寸变化使用算法
0, 0, 0
);
if (!vsc)
{
cout << "sws_getCachedContext failed!";
return false;
}
///3 初始化输出的数据结构
AVFrame* yuv = av_frame_alloc();
yuv->format = AV_PIX_FMT_YUV420P;
yuv->width = width;
yuv->height = height;
yuv->pts = 0;
//分配yuv空间
ret = av_frame_get_buffer(yuv, 32);
if (ret != 0)
{
return XError(ret);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//打开输出 rtmp 地址 rtmp://你的流媒体服务器IP地址:端口/live/随意取啥
const char* rtmpurl = "rtmp://你的流媒体服务器IP地址:端口/live/随意取啥";
AVFormatContext* ic = NULL;
ret = avformat_alloc_output_context2(&ic, 0, "flv", rtmpurl);
if (ret < 0)
{
return XError(ret);
}
//b 添加视频流
AVStream* st = avformat_new_stream(ic, NULL);
if (!st)
{
cout << "avformat_new_stream failed" << endl;
return -1;
}
st->codecpar->codec_tag = 0;
//从编码器复制参数
avcodec_parameters_from_context(st->codecpar, vc);
av_dump_format(ic, 0, rtmpurl, 1);
///打开rtmp 的网络输出IO
ret = avio_open(&ic->pb, rtmpurl, AVIO_FLAG_WRITE);
if (ret != 0)
{
return XError(ret);
}
//写入封装头
ret = avformat_write_header(ic, NULL);
if (ret != 0)
{
return XError(ret);
}
///////////////////////////////////////////////////////////////////////////////////////////
std::cout << "进入视频录制" << endl;
AVPacket* packet = av_packet_alloc();
AVPacket* Encodepacket = av_packet_alloc();
//FILE* video_record = fopen("video_1920x1080_yuv420p.h264", "wb");
//FILE* video_record_yuv = fopen("video_1920x1080_yuv420p.yuv", "wb");
int frameIndex = 0;
int EncodeIndex = 0;
AVFrame* rgb = av_frame_alloc();
AVBitStreamFilterContext* h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
long long startpts = m_fmt_ctx->start_time;
long long lastpts = 0;
long long duration = av_rescale_q(1, { 1,FPS }, { 1,AV_TIME_BASE });
int got_picture = 0;
while (frameIndex < 200)
{
ret = av_read_frame(m_fmt_ctx, packet);
if (ret < 0) {
break;
}
if (packet->stream_index == video_stream)
{
//std::cout << "index: " << frameIndex << " pts:" << packet->pts<< " dts: " << packet->dts << " size: " << packet->size << endl;
ret = avcodec_decode_video2(_codec_ctx, rgb, &got_picture, packet);
if (ret < 0) {
printf("Decode Error.\n");
return ret;
}
if (got_picture) {
int h = sws_scale(vsc, rgb->data, rgb->linesize, 0, height, //源数据
yuv->data, yuv->linesize);
/* fwrite(yuv->data[0], 1, width* height, video_record_yuv);
fwrite(yuv->data[1], 1, width* height / 4, video_record_yuv);
fwrite(yuv->data[2], 1, width* height / 4, video_record_yuv);*/
//当前 pts
//yuv->pts = packet->pts - startpts;
//按照帧间隔 猜测 pts
int guesspts = frameIndex * duration;
yuv->pts = guesspts;
frameIndex++;
//Encode
ret = avcodec_encode_video2(vc, Encodepacket, yuv, &got_picture);
if (ret < 0) {
printf("Failed to encode! \n");
break;
}
if (got_picture == 1) {
Encodepacket->pts = av_rescale_q(EncodeIndex, vc->time_base, st->time_base);
Encodepacket->dts = Encodepacket->pts;
std::cout << "frameindex : " << EncodeIndex << " pts:" << Encodepacket->pts << " dts: " << Encodepacket->dts << " encodeSize:" << Encodepacket->size << " curtime - lasttime " << Encodepacket->pts - lastpts << endl;
lastpts = Encodepacket->pts;
//av_free(Encodepacket->data);
ret = av_interleaved_write_frame(ic, Encodepacket);
//av_free(Encodepacket->data);
EncodeIndex++;
av_packet_unref(Encodepacket);
}
}
}
av_packet_unref(packet);
}
ret = avcodec_send_frame(vc, NULL);
while (ret >= 0) {
ret = avcodec_receive_packet(vc, Encodepacket);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}
if (ret < 0) {
break;
}
//Encodepacket->pts = av_rescale_q(av_gettime() - starttime, ac->time_base, st->time_base);
//Encodepacket->dts = Encodepacket->pts;
//Encodepacket->pts = av_rescale_q(packet->pts - startpts, m_fmt_ctx->streams[video_stream]->time_base, vc->time_base);
//Encodepacket->dts = Encodepacket->pts;
//ret = av_bitstream_filter_filter(h264bsfc, m_fmt_ctx->streams[video_stream]->codec, NULL, &Encodepacket->data, &Encodepacket->size, Encodepacket->data, Encodepacket->size, 0);
//std::fwrite(Encodepacket->data, 1, Encodepacket->size, video_record);
std::cout << "frameindex : " << EncodeIndex << " pts:" << Encodepacket->pts - startpts << " dts: " << Encodepacket->dts - startpts << " encodeSize:" << Encodepacket->size << endl;
ret = av_interleaved_write_frame(ic, Encodepacket);
//av_free(Encodepacket->data);
EncodeIndex++;
}
///////////////////////////////////////////////////////////////////////////////////////////////
av_write_trailer(ic);
//std::fclose(video_record);
//fclose(video_record_yuv);
av_packet_free(&packet);
av_packet_free(&Encodepacket);
av_frame_free(&rgb);
av_frame_free(&yuv);
av_bitstream_filter_close(h264bsfc);
h264bsfc = NULL;
if (vsc)
{
sws_freeContext(vsc);
vsc = NULL;
}
if (_codec_ctx)
avcodec_close(_codec_ctx);
_codec_ctx = NULL;
_codec = NULL;
if (vc)
avcodec_free_context(&vc);
if (m_fmt_ctx)
avformat_close_input(&m_fmt_ctx);
if (ic && !(ic->flags & AVFMT_NOFILE))
avio_closep(&ic->pb);
if (ic) {
avformat_free_context(ic);
ic = NULL;
}
m_input_fmt = NULL;
std::cout << "退出视频录制" << endl;
return 0;
}
实例运行效果
注:用拉流工具观看 vlc