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更新了啥,感觉启动都很卡,干啥都卡

相关推荐
SUPER52662 小时前
本地开发环境_spring-ai项目启动异常
java·人工智能·spring
上进小菜猪7 小时前
基于 YOLOv8 的智能车牌定位检测系统设计与实现—从模型训练到 PyQt 可视化落地的完整实战方案
人工智能
AI浩7 小时前
UNIV:红外与可见光模态的统一基础模型
人工智能·深度学习
GitCode官方7 小时前
SGLang AI 金融 π 对(杭州站)回顾:大模型推理的工程实践全景
人工智能·金融·sglang
木头左8 小时前
LSTM模型入参有效性验证基于量化交易策略回测的方法学实践
人工智能·rnn·lstm
找方案8 小时前
我的 all-in-rag 学习笔记:文本分块 ——RAG 系统的 “信息切菜术“
人工智能·笔记·all-in-rag
亚马逊云开发者8 小时前
让 AI 工作空间更智能:Amazon Quick Suite 集成博查搜索实践
人工智能
腾讯WeTest8 小时前
「低成本、高质高效」WeTest AI翻译限时免费
人工智能
Lucas555555558 小时前
现代C++四十不惑:AI时代系统软件的基石与新征程
开发语言·c++·人工智能
言之。8 小时前
Claude Code 专业教学文档
人工智能