【音视频】保存同步的音视频文件-ffmpeg(九)

本文介绍了使用ffmpeg将采集的音频和视频数据合成为视音同步的可播放文件的流程。通过初始化输出文件上下文、创建音视频流、写入数据并确保线程安全,最后写入文件尾部,完成音视频合成。整个过程涉及视频编码、音频编码、重采样、混音等技术。
摘要由CSDN通过智能技术生成

这是从采集桌面音视频=>转码=>编码之后的最后一个步骤了,即产生一个视音同步的可播放的文件。那如何将两股同时采集编码的音频和视频合成一个视音同步的可播放的文件呢?本文中用到了ffmpeg的写文件技术。

技术简介

使用ffmpeg的相关技术

使用模块(库)

使用ffmpeg的avformat-58.dll

主要流程和代码

1、初始化视音频融合器(自己取的名称)

int FfmpegMuxer::init(const char* outputFilename, const FILE_MUX_SETTING& setting,
			CAPTOR::VideoCaptor* videoCaptor, CAPTOR::AudioCaptor** audioCaptors, const int audioCaptorNumbers)
{
   
	int err = ERROR_CODE_OK;

	if ((outputFilename == nullptr || strlen(outputFilename) == 0)
		|| (videoCaptor == nullptr && (audioCaptors == nullptr || audioCaptorNumbers <= 0))) {
   
		err = ERROR_CODE_PARAMS_ERROR;
		return err;
	}

	do {
   
		std::string dstOutputFilename;
		if (!HELPER::SystemPath::canonicalizePath(outputFilename, dstOutputFilename)) {
   
			err = ERROR_CODE_CANONICALIZE_PATH_ERROR;
			break;
		}
		m_outputFilename = dstOutputFilename;

		err = initOutputContext();
		HCMDR_ERROR_CODE_BREAK(err);

		if (m_outputfmt->video_codec != AV_CODEC_ID_NONE && videoCaptor != nullptr) {
   
			err = createVideoStreamLink(setting, videoCaptor);
			HCMDR_ERROR_CODE_BREAK(err);
		}

		if (m_outputfmt->audio_codec != AV_CODEC_ID_NONE && audioCaptors != nullptr && audioCaptorNumbers > 0) {
   
			err = createAudioStreamLink(setting, audioCaptors, audioCaptorNumbers);
			HCMDR_ERROR_CODE_BREAK(err);
		}

		err = openOutputFile();
		HCMDR_ERROR_CODE_BREAK(err);

		av_dump_format(m_formatCtx, 0, nullptr, 1);

		m_inited = true;
	} while (0);

	if (err != ERROR_CODE_OK) {
   
		cleanup();
		LOGGER::Logger::log(LOGGER::LOG_TYPE_ERROR, "[%s] init ffmpeg muxer failed!", __FUNCTION__);
	}

	return err;
}

初始化输出文件上下文

int FfmpegMuxer::initOutputContext()
{
   
	int err = ERROR_CODE_OK;

	do {
   
		int ret = avformat_alloc_output_context2(&m_formatCtx, nullptr, nullptr, m_outputFilename.c_str());
		if (ret < 0 || m_formatCtx == nullptr) {
   
			err = ERROR_CODE_FFMPEG_ALLOC_CONTEXT_FAILED;
			break;
		}

		m_outputfmt = m_formatCtx->oformat;
	} while (0);

	return err;
}

创建视频流连接,从采集到转码再到编码,其中createVideoTranscoder/createVideoEncoder是多态实现,用来产生对应的子类类型的视频转码器/编码器;参数setting是视频相关配置信息,参数captor是桌面采集器

int FfmpegMuxer::createVideoStreamLink(const FILE_MUX_SETTING& setting, CAPTOR::VideoCaptor* captor)
{
   
	int err = ERROR_CODE_OK;

	m_videoStream = new FILE_MUX_STREAM();
	SecureZeroMemory(m_videoStream, sizeof(FILE_MUX_STREAM));
	m_videoStream->firstPacketPts = (uint64_t)-1;
	m_videoStream->vCaptor = captor;
	captor->registerCallback(std::bind(&FfmpegMuxer::onVideoCaptureData, this, std::placeholders::_1),
		std::bind(&FfmpegMuxer::onVideoCaptureError, this, std::placeholders::_1));

	do {
   
		err = TRANSCODER::createVideoTranscoder(setting.vTranscodeType, &m_videoStream->vTranscoder);
		HCMDR_ERROR_CODE_BREAK(err);

		TRANSCODER::VideoTranscoder* transcoder = m_videoStream->vTranscoder;
		CAPTOR::DesktopCaptureRect rect = captor->getRect();
		err = transcoder->init(captor->getPixelFormat(), rect.right - rect.left, rect.bottom - rect.top,
			setting.pixelFmt, setting.width, setting.height);
		HCMDR_ERROR_CODE_BREAK(err);

		err = ENCODER::createVideoEncoder(setting.vEncodeType, &m_videoStream->vEncoder);
		HCMDR_ERROR_CODE_BREAK(err);

		ENCODER::VideoEncoder* encoder = m_videoStream->vEncoder;
		err = encoder->init(setting.width, setting.height, setting.framerate, setting.vBitrate, setting.qb, setting.gopTime);
		HCMDR_ERROR_CODE_BREAK(err);

		encoder->registerCallback(std::bind(&FfmpegMuxer::onVideoEncodeData, this, std::placeholders::_1),
			std::bind(&FfmpegMuxer::onVideoEncodeError, this, std::placeholders::_1));

		AVCodec* codec = avcodec_find_encoder(encoder->getCodecId());
		if (codec == nullptr) {
   
			err = ERROR_CODE_FFMPEG_FIND_ENCODER_FAILED;
			break;
		}

		AVStream* stream = avformat_new_stream(m_formatCtx, codec);
		if (stream == nullptr) {
   
			err = ERROR_CODE_FFMPEG_NEW_STREAM_FAILED;
			break;
		}

		AVCodecContext* codecCtx = avcodec_alloc_context3(codec);
		if (codecCtx == nullptr) {
   
			err = ERROR_CODE_FFMPEG_ALLOC_CONTEXT_FAILED
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值