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

相关推荐
sell-cloud2 小时前
Prompt Engineering要凉了?Fable 5.5能“猜“意图,但银行正在封杀AI Agent——企业AI的真正护城河是什么
人工智能·prompt
Navicat中国4 小时前
Navicat 18 内置 AI 助手让数据库开发从繁琐操作迈向智能协作
大数据·人工智能·数据库开发
4SAPI4 小时前
多模型请求路由怎么设计?成本、速度和能力如何平衡
人工智能·python·gateway·php
魔乐社区5 小时前
翼芯・智算测试与适配优化专区,让国产算力“选得准、跑得通、用得好“
人工智能·开源·大模型
XCDoris6 小时前
郴州logo设计机构
大数据·人工智能·python
Goboy7 小时前
一个人带三个Agent,我用全新TRAE从0到1搭了个资讯周刊站
人工智能·trae
俊哥V7 小时前
每日 AI 研究简报 · 2026-10-19
人工智能·ai
AI_AGENT_DEV_AI7 小时前
AI英语教培智能体的开发
人工智能
物联网软硬件开发-轨物科技7 小时前
【技术白皮书】光伏清检一体化机器人系统解决方案技术白皮书
大数据·运维·网络·人工智能·机器人
海宇数据7 小时前
零信任架构实战:基于海宇网上踪迹欺诈行为识别构建自动化信贷资信评估网关
运维·人工智能·架构·自动化