ffmpeg + opencv 把摄像头画面保存为mp4文件(Ubuntu24.04)

参考链接

ffmpeg + opencv 把摄像头画面保存为mp4文件_ffmpeg转化摄像头mp4-CSDN博客

调试环境

Ubuntu24.04

ffmpeg 6.1.1

opencv 4.6

g++ 13.2.0

C++源码

cpp 复制代码
#include <iostream>
#include <sys/time.h>
#include <string>

#ifdef __cplusplus
extern "C"
{
#endif

#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libavcodec/avcodec.h>

#ifdef __cplusplus
} // endof extern "C"
#endif

#include <opencv2/opencv.hpp>
using namespace cv;

AVFrame *videoFrame = nullptr;
AVCodecContext *cctx = nullptr;
SwsContext *swsCtx = nullptr;
int frameCounter = 0;
AVFormatContext *ofctx = nullptr;
int fps = 30;
int width = 640;
int height = 480;
int bitrate = 2000;
long start_time = 0;
const std::string output_filename = "out.mp4";
// const std::string output_filename = "out.ts";

long getCurrentTime()
{
	struct timeval tv;
	gettimeofday(&tv, NULL);
	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

static void pushFrame(uint8_t *data, long currentTime)
{
	int err;
	AVPacket pkt = {0};

	int inLinesize[1] = {3 * cctx->width};
	// From RGB to YUV
	sws_scale(swsCtx, (const uint8_t *const *)&data, inLinesize, 0, cctx->height, videoFrame->data, videoFrame->linesize);
	videoFrame->pts = ((currentTime - start_time) / 1000.0) * 90000;
	std::cout << videoFrame->pts << " " << cctx->time_base.num << " " << cctx->time_base.den << " " << frameCounter << std::endl;
	if ((err = avcodec_send_frame(cctx, videoFrame)) < 0)
	{
		std::cout << "Failed to send frame" << err << std::endl;
		return;
	}

	pkt.buf = NULL;
	pkt.side_data = NULL;
	pkt.data = NULL;
	pkt.size = 0;
	pkt.flags |= AV_PKT_FLAG_KEY;
	if (avcodec_receive_packet(cctx, &pkt) == 0)
	{
		static int counter = 0;
		if (counter == 0)
		{
			FILE *fp = fopen("dump_first_frame1.dat", "wb");
			fwrite(pkt.data, pkt.size, 1, fp);
			fclose(fp);
		}
		std::cout << "pkt key: " << (pkt.flags & AV_PKT_FLAG_KEY) << " " << pkt.size << " " << (counter++) << std::endl;
		uint8_t *size = ((uint8_t *)pkt.data);
		std::cout << "first: " << (int)size[0] << " " << (int)size[1] << " " << (int)size[2] << " " << (int)size[3] << " " << (int)size[4] << " " << (int)size[5] << " " << (int)size[6] << " " << (int)size[7] << std::endl;
		av_interleaved_write_frame(ofctx, &pkt);
		av_packet_unref(&pkt);
	}
}

static void finish()
{
	// DELAYED FRAMES
	AVPacket pkt = {0};
	pkt.data = NULL;
	pkt.size = 0;

	while (true)
	{
		avcodec_send_frame(cctx, NULL);
		if (avcodec_receive_packet(cctx, &pkt) == 0)
		{
			av_interleaved_write_frame(ofctx, &pkt);
			av_packet_unref(&pkt);
		}
		else
		{
			break;
		}
	}

	av_write_trailer(ofctx);
	avformat_close_input(&ofctx);
}

static void free()
{
	if (videoFrame)
	{
		av_frame_free(&videoFrame);
	}
	if (cctx)
	{
		avcodec_free_context(&cctx);
	}
	if (ofctx)
	{
		avformat_free_context(ofctx);
	}
	if (swsCtx)
	{
		sws_freeContext(swsCtx);
	}
}

int main()
{
	// VideoCapture capture("road_test.mp4");
	VideoCapture capture(0);
	Mat frame;
	capture >> frame;

	width = frame.cols;
	height = frame.rows;

	avdevice_register_all();

	int err = avformat_alloc_output_context2(&ofctx, nullptr, nullptr, output_filename.c_str());
	if (err)
	{
		std::cout << "can't create output context" << std::endl;
		return -1;
	}

	const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
	if (!codec)
	{
		std::cout << "can't create codec" << std::endl;
		return -1;
	}

	AVStream *stream = avformat_new_stream(ofctx, codec);
	if (!stream)
	{
		std::cout << "can't find format" << std::endl;
		return -1;
	}

	cctx = avcodec_alloc_context3(codec);

	if (!cctx)
	{
		std::cout << "can't create codec context" << std::endl;
		return -1;
	}

	stream->codecpar->codec_id = AV_CODEC_ID_H264;
	stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
	stream->codecpar->width = width;
	stream->codecpar->height = height;
	stream->codecpar->format = AV_PIX_FMT_YUV420P;
	stream->codecpar->bit_rate = bitrate * 1000;
	avcodec_parameters_to_context(cctx, stream->codecpar);
	cctx->time_base = (AVRational){1, 1};
	cctx->max_b_frames = 2;
	cctx->gop_size = 12;
	cctx->framerate = (AVRational){fps, 1};

	if (stream->codecpar->codec_id == AV_CODEC_ID_H265)
	{
		av_opt_set(cctx, "preset", "ultrafast", 0);
	}

	avcodec_parameters_from_context(stream->codecpar, cctx);

	if ((err = avcodec_open2(cctx, codec, NULL)) < 0)
	{
		std::cout << "Failed to open codec" << err << std::endl;
		return -1;
	}

	if ((err = avio_open(&ofctx->pb, output_filename.c_str(), AVIO_FLAG_WRITE)) < 0)
	{
		std::cout << "Failed to open file" << err << std::endl;
		return -1;
	}

	if ((err = avformat_write_header(ofctx, NULL)) < 0)
	{
		std::cout << "Failed to write header" << err << std::endl;
		return -1;
	}

	av_dump_format(ofctx, 0, output_filename.c_str(), 1);

	videoFrame = av_frame_alloc();
	videoFrame->format = AV_PIX_FMT_YUV420P;
	videoFrame->width = cctx->width;
	videoFrame->height = cctx->height;
	if ((err = av_frame_get_buffer(videoFrame, 32)) < 0)
	{
		std::cout << "Failed to allocate picture" << err << std::endl;
		return -1;
	}

	swsCtx = sws_getContext(cctx->width, cctx->height, AV_PIX_FMT_BGR24, cctx->width, cctx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, 0, 0, 0);

	start_time = getCurrentTime();
	for (int i = 0; i < 100; ++i)
	{
		capture >> frame;
		pushFrame(frame.data, getCurrentTime());
	}

	finish();
	free();
	return 0;
}

CMakeLists.txt

cpp 复制代码
cmake_minimum_required(VERSION 3.16)
 
project(recordStudy)
 
find_package(OpenCV REQUIRED)
 
include_directories(. ${OpenCV_INCLUDE_DIRS})
 
link_libraries(avformat)
link_libraries(avcodec)
link_libraries(avutil)
link_libraries(swscale)
link_libraries(avdevice)
 
add_executable(recordStudy main.cpp)
target_link_libraries(recordStudy ${OpenCV_LIBS})

牢骚

不知道Ubuntu24.04更新了啥,感觉启动都很卡,干啥都卡

相关推荐
热爱跑步的恒川34 分钟前
【论文复现】基于图卷积网络的轻量化推荐模型
网络·人工智能·开源·aigc·ai编程
阡之尘埃3 小时前
Python数据分析案例61——信贷风控评分卡模型(A卡)(scorecardpy 全面解析)
人工智能·python·机器学习·数据分析·智能风控·信贷风控
孙同学要努力5 小时前
全连接神经网络案例——手写数字识别
人工智能·深度学习·神经网络
Eric.Lee20215 小时前
yolo v5 开源项目
人工智能·yolo·目标检测·计算机视觉
岁月小龙5 小时前
如何让ffmpeg运行时从当前目录加载库,而不是从/lib64
ffmpeg·origin·ffprobe·rpath
其实吧36 小时前
基于Matlab的图像融合研究设计
人工智能·计算机视觉·matlab
丕羽6 小时前
【Pytorch】基本语法
人工智能·pytorch·python
ctrey_6 小时前
2024-11-1 学习人工智能的Day20 openCV(2)
人工智能·opencv·学习
SongYuLong的博客6 小时前
Air780E基于LuatOS编程开发
人工智能
Jina AI6 小时前
RAG 系统的分块难题:小型语言模型如何找到最佳断点?
人工智能·语言模型·自然语言处理