FFmpeg合并视频流与音频流

2023-05-16

mux.h

 

#ifndef MUX_H
#define MUX_H

#ifdef __cplusplus
extern "C"
{
#endif

#include"common.h"
#include"encode.h"

	typedef struct AVMuxing {
		videoParm *vp;
		AVFormatContext *i_fmt_ctx_v;
		AVFormatContext *i_fmt_ctx_a;
		AVFormatContext *o_fmt_ctx;
		AVCodecContext *enc_ctx_v;
		AVCodecContext *enc_ctx_a;
		const char *in_audio;

		int audio_len;
		int videoindex_v;
		int videoindex_out;
		int audioindex_a;
		int audioindex_out;
	}AVMuxing;

	/*
	*identifier,status, percent
	*/
	typedef void(*AVMuxCallbackFunction)(void*, int, int);

	/*
	* 输入编码时返回的结构体指针,一个音频
	*/
	extern int MuxAudioVideo(videoParm *vp, const char *inAudio);

#ifdef __cplusplus
};
#endif
#endif


mux.cpp

 

 

#include "stdafx.h"

#ifdef __cplusplus
extern "C"
{
#endif

#include<tchar.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include"common.h"

#include"mux.h"
#include"logger.h"

#define CLEAN_AND_EXIT {MuxCallbackFunction((AVMuxCallbackFunction)avm->vp->notification, avm->vp, -1, /*avm->vp->progress*/0);\
						CtxAllFree(avm);\
						return -1;}

#ifdef __cplusplus
};
#endif

/*
* status, -1 for failed, 0 for encode succeed, 1 for setting stop, 2 for calback progress, 3 for mux succeed
*/

/*
* 释放结构体内存
*/
static void CtxAllFree(AVMuxing *avm);

/*
* 计算进度
*/
static int CurrentPercent(int cnt, int total);

static void MuxCallbackFunction(AVMuxCallbackFunction fcn, void *identifier, int status, int percent)
{
	if (fcn != NULL) {
		fcn(identifier, status, percent);
	}
	else {
		//LogPrint();
	}
}


OpenInputFile:

 

 

 

 

/*
* 判断输入音频是否有效
*/
static int OpenInputFile(const char *filename)
{
	FILE *fp;
	fp = fopen(filename, "rb");
	if (fp == NULL) {
		LOG_PRINT("%s....Audio fopen failed", __FUNCTION__);
		return -1;
	}
	/* fp如果为空,feek会出错,根本走不到判断audio_len那里 */
	fseek(fp, 0L, SEEK_END);
	int len = ftell(fp);
	/* 即时是局部变量,也调用fclose */
	fclose(fp);
	return len;
}


copy_file_thread:

 

 

 

 

/* 将临时文件拷贝到目的路径,用在没有音频的时候 */
void* copy_file_thread(void *arg)
{
	__try {
		int ret;
		LOG_PRINT("%s...1", __FUNCTION__);
		AVMuxing *avm = (AVMuxing*)arg;
		LOG_PRINT("%s....tmp_path: %s, path: %s", __FUNCTION__, avm->vp->tmp_path, avm->vp->path);
		bool flag = CopyFileA(avm->vp->tmp_path, avm->vp->path, FALSE);
		if (!flag) {
			TCHAR szBuf[128];
			LPVOID lpMsgBuf;
			DWORD dw = GetLastError();
			FormatMessage(
				FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
				NULL,
				dw,
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
				(LPTSTR)&lpMsgBuf,
				0, NULL);
			wsprintf(szBuf,
				_T("%s error message (error code = %d): %s"),
				_T("CopyFileA"), dw, lpMsgBuf);
			LocalFree(lpMsgBuf);
			LOG_PRINT("%s...%s", __FUNCTION__, szBuf);
			MuxCallbackFunction((AVMuxCallbackFunction)avm->vp->notification, avm->vp, -1, avm->vp->progress);
			CtxAllFree(avm);
			return NULL;
		}

		LOG_PRINT("%s....======copy_file_thread end ======!", __FUNCTION__);
		MuxCallbackFunction((AVMuxCallbackFunction)avm->vp->notification, avm->vp, 3, 100);
		CtxAllFree(avm);
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		LOG_PRINT("%s error\n", __FUNCTION__);
	}
	return NULL;
}


mux_thread:

 

 

 

 

/*
* 将音频和视频复用,判断音频包和视频包的pts,pts在前的先写入输出文件
* 当音频包没了,继续写入视频包
*/
void* mux_thread(void* avmuxing)
{
	__try {
		LOG_PRINT("%s...1", __FUNCTION__);
		AVMuxing *avm = (AVMuxing*)avmuxing;
		AVPacket pkt;
		int frame_index = 0;
		int64_t cur_pts_v = 0, cur_pts_a = 0;
		bool flag = FALSE;
		int compare_tag = -1;
		bool audio_pkt_done = FALSE;	//音频包写完标志,即使音频包写完了还要继续写视频包
		int pkt_cnt = 1;
		int i_v_nb_frames = avm->vp->fmt_ctx->streams[0]->nb_frames;

		while (1) {
			pthread_mutex_lock(&(avm->vp->pp->mutex_t));
			if (avm->vp->is_stop) {
				flag = TRUE;
			}
			pthread_mutex_unlock(&(avm->vp->pp->mutex_t));
			if (flag) {
				break;
			}
			int stream_index = 0;
			AVFormatContext *i_fmt_ctx;
			AVStream *in_stream, *out_stream;

			/* 比较音频包和视频包的pts */
			if (!audio_pkt_done) {
				if (avm->audio_len > 0) {
					compare_tag = av_compare_ts(cur_pts_v, avm->i_fmt_ctx_v->streams[avm->videoindex_v]->time_base,
						cur_pts_a, avm->i_fmt_ctx_a->streams[avm->audioindex_a]->time_base);
				}
			}
			if (compare_tag <= 0) {		/* 视频包在前,写入视频包 */
				i_fmt_ctx = avm->i_fmt_ctx_v;
				stream_index = avm->videoindex_out;

				if (av_read_frame(i_fmt_ctx, &pkt) >= 0) {
					do {
						in_stream = i_fmt_ctx->streams[pkt.stream_index];
						out_stream = avm->o_fmt_ctx->streams[stream_index];
						//out_stream->time_base = { 1, vp->fps };		//force out_stream to AVCodecContext->fps
						if (pkt.stream_index == avm->videoindex_v) {
							if (pkt.pts == AV_NOPTS_VALUE) {
								AVRational time_base1 = in_stream->time_base;
								int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
								pkt.pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
								pkt.dts = pkt.pts;
								pkt.duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
								frame_index++;
							}
							cur_pts_v = pkt.pts;

							/* 在此回调进度 */
							avm->vp->progress = CurrentPercent(++pkt_cnt, i_v_nb_frames);
							MuxCallbackFunction((AVMuxCallbackFunction)avm->vp->notification, avm->vp, 2, avm->vp->progress);
							break;
						}

					} while (av_read_frame(i_fmt_ctx, &pkt) >= 0);
				}
				else {
					LOG_PRINT("%s....av_read_frame < 0", __FUNCTION__);
					break;
				}
			}
			else {		/* 音频包在前,写入音频包 */
				i_fmt_ctx = avm->i_fmt_ctx_a;
				stream_index = avm->audioindex_out;
				if (av_read_frame(i_fmt_ctx, &pkt) >= 0) {
					do {
						in_stream = i_fmt_ctx->streams[pkt.stream_index];
						out_stream = avm->o_fmt_ctx->streams[stream_index];
						if (pkt.stream_index == avm->audioindex_a) {
							//TODO:add audio filter here to format pkt!
							if (pkt.pts == AV_NOPTS_VALUE) {
								AVRational time_base1 = in_stream->time_base;
								int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
								pkt.pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
								pkt.dts = pkt.pts;
								pkt.duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
								frame_index++;
							}
							cur_pts_a = pkt.pts;
							break;
						}
					} while (av_read_frame(i_fmt_ctx, &pkt) >= 0);
				}
				else {
					//break;	/* 如果音频比视频短,不break,以视频为标准 */
					/* 音频包写完后,继续写完视频包 */
					audio_pkt_done = TRUE;
					compare_tag = -1;
					continue;
				}
			}

			//Convert PTS/DTS
			pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
			pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
			pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
			pkt.pos = -1;
			pkt.stream_index = stream_index;
#ifdef DEBUG
			printf("Write 1 Packet. Size:%5d\tpts:%5lld\tdts:%5lld\n", pkt.size, pkt.pts, pkt.dts);
#endif
			//Write packet to file
			if (av_interleaved_write_frame(avm->o_fmt_ctx, &pkt) < 0) {
				LOG_PRINT("%s....av_interleaved_write_frame failed", __FUNCTION__);
				MuxCallbackFunction((AVMuxCallbackFunction)avm->vp->notification, avm->vp, -1, avm->vp->progress);
				CtxAllFree(avm);
				return NULL;
				//break;
			}
			av_free_packet(&pkt);
		}

		pthread_mutex_lock(&(avm->vp->pp->mutex_t));
		if (avm->vp->is_stop) {
			flag = TRUE;
		}
		pthread_mutex_unlock(&(avm->vp->pp->mutex_t));
		if (flag) {
			MuxCallbackFunction((AVMuxCallbackFunction)avm->vp->notification, avm->vp, 1, avm->vp->progress);
			CtxAllFree(avm);
			return NULL;
		}
		//Write file trailer
		av_write_trailer(avm->o_fmt_ctx);

#ifdef DEBUG
		printf("======muxer success ======!\n");
#endif
		LOG_PRINT("%s....======mux_thread end ======!", __FUNCTION__);
		MuxCallbackFunction((AVMuxCallbackFunction)avm->vp->notification, avm->vp, 3, 100);
		CtxAllFree(avm);
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		LOG_PRINT("%s error\n", __FUNCTION__);
	}
	return NULL;
}


MuxAudioVideo:

 

 

 

 

int MuxAudioVideo(videoParm *vp, const char *inAudio)
{
	LOG_PRINT("%s....width = %d, height = %d, fps = %d, format = %s, outpath = %s", __FUNCTION__,
		vp->width, vp->height, vp->fps, vp->format, vp->path);
	LOG_PRINT("%s....1", __FUNCTION__);

	AVMuxing *avm = (AVMuxing*)malloc(sizeof(AVMuxing));
	memset(avm, 0, sizeof(AVMuxing));

	avm->vp = vp;
	avm->i_fmt_ctx_a = NULL;
	avm->i_fmt_ctx_v = NULL;
	avm->o_fmt_ctx = NULL;
	avm->enc_ctx_v = NULL;
	avm->enc_ctx_a = NULL;
	avm->in_audio = inAudio;

	/*
	* 当外部没有音频(或生成音频失败)则创建拷贝文件线程,将临时文件拷贝到目的路径
	*/
	if (!strcmp("", inAudio)) {
		pthread_create(&avm->vp->pp->tid, NULL, copy_file_thread, avm);
		/* 线程退出时自动释放资源 */
		pthread_detach(avm->vp->pp->tid);
		LOG_PRINT("%s....Create copy file thread", __FUNCTION__);
		return 0;
	}

	AVOutputFormat *o_fmt;

	int ret = -1, i = -1;
	avm->videoindex_v = -1;
	avm->videoindex_out = -1;
	avm->audioindex_a = -1;
	avm->audioindex_out = -1;
	bool flag = FALSE;
	const char *in_video = avm->vp->tmp_path;
	const char *in_audio = avm->in_audio;
	const char *out_file = avm->vp->path;

#ifdef DEBUG
	printf("=========input video: %s\n", in_video);
	printf("=========input audio: %s\n", in_audio);
#endif
	if ((avm->audio_len = OpenInputFile(in_audio)) == -1) {
		LOG_PRINT("%s....OpenInputFile failed", __FUNCTION__, ret);
		CLEAN_AND_EXIT
	}
	/* 注册所有编解码器和协议 */
	av_register_all();
	/* 打开输入音频文件, 返回AVFormatContext */
	if ((ret = avformat_open_input(&avm->i_fmt_ctx_a, in_audio, NULL, NULL)) < 0) {
		LOG_PRINT("%s....audio avformat_open_input failed,error code is: %d", __FUNCTION__, ret);
		CLEAN_AND_EXIT
	}
	/* 查找音频流信息 */
	if ((ret = avformat_find_stream_info(avm->i_fmt_ctx_a, NULL)) < 0) {
		LOG_PRINT("%s....audio avformat_find_stream_info failed,error code is: %d", __FUNCTION__, ret);
		if (avm->audio_len > 0) {
			LOG_PRINT("%s....Audio is Null", __FUNCTION__);
			CLEAN_AND_EXIT
		}
	}
	if ((ret = avformat_open_input(&avm->i_fmt_ctx_v, in_video, NULL, NULL)) < 0) {
		LOG_PRINT("%s....video avformat_open_input failed,error code is: %d", __FUNCTION__, ret);
		CLEAN_AND_EXIT
	}
	if ((ret = avformat_find_stream_info(avm->i_fmt_ctx_v, NULL)) < 0) {
		LOG_PRINT("%s....video avformat_find_stream_info failed,error code is: %d", __FUNCTION__, ret);
		CLEAN_AND_EXIT
	}
#ifdef DEBUG
	printf("========================Input Infomation==================================\n");
	av_dump_format(avm->i_fmt_ctx_v, 0, in_video, 0);
	av_dump_format(avm->i_fmt_ctx_a, 0, in_audio, 0);
	printf("==========================================================================\n");
#endif
	LOG_PRINT("%s....width = %d, height = %d, fps = %d, format = %s, outpath = %s", __FUNCTION__,
		avm->vp->width, avm->vp->height, avm->vp->fps, avm->vp->format, avm->vp->path);
	ret = avformat_alloc_output_context2(&avm->o_fmt_ctx, NULL, NULL, out_file);
	if (ret < 0) {
		LOG_PRINT("%s....avformat_alloc_output_context2 failed, error code: %d, out file is: %s", __FUNCTION__, ret, out_file);
		CLEAN_AND_EXIT
	}
	o_fmt = avm->o_fmt_ctx->oformat;

	for (i = 0; i < avm->i_fmt_ctx_v->nb_streams; i++) {
		pthread_mutex_lock(&(avm->vp->pp->mutex_t));
		if (avm->vp->is_stop) {
			flag = TRUE;
		}
		pthread_mutex_unlock(&(avm->vp->pp->mutex_t));
		if (flag) {
			break;
		}
		if (avm->i_fmt_ctx_v->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
			AVStream *in_stream = avm->i_fmt_ctx_v->streams[i];
			avm->enc_ctx_v = avcodec_alloc_context3(NULL);
			if ((ret = avcodec_parameters_to_context(avm->enc_ctx_v, in_stream->codecpar)) < 0) {
				LOG_PRINT("%s....Video avcodec_parameters_to_context failed,error code is: %d", __FUNCTION__, ret);
				CLEAN_AND_EXIT
			}
			AVStream *out_stream = avformat_new_stream(avm->o_fmt_ctx, avm->enc_ctx_v->codec);
			if (!out_stream) {
				LOG_PRINT("%s....Video avformat_new_stream failed", __FUNCTION__);
				CLEAN_AND_EXIT
			}
			//out_stream->time_base = { 1, avm->vp->fps };		//force out_stream to AVCodecContext->fps
			out_stream->time_base.num = 1;
			out_stream->time_base.den = avm->vp->fps;
			avm->videoindex_v = i;
			avm->videoindex_out = out_stream->index;

			avm->enc_ctx_v->codec_tag = 0;
			if (o_fmt->flags & AVFMT_GLOBALHEADER) {
				avm->enc_ctx_v->flags |= CODEC_FLAG_GLOBAL_HEADER;
			}
			if ((ret = avcodec_parameters_from_context(out_stream->codecpar, avm->enc_ctx_v)) < 0) {
				LOG_PRINT("%s....Video avcodec_parameters_from_context,error code is: %d", __FUNCTION__, ret);
				//CLEAN_AND_EXIT
			}
			break;
		}
	}

	if (avm->audio_len > 0) {
		for (i = 0; i < avm->i_fmt_ctx_a->nb_streams; i++) {
			pthread_mutex_lock(&(avm->vp->pp->mutex_t));
			if (avm->vp->is_stop) {
				flag = TRUE;
			}
			pthread_mutex_unlock(&(avm->vp->pp->mutex_t));
			if (flag) {
				break;
			}
#ifdef DEBUG
			printf("===========streams number:%3d===========\n", avm->i_fmt_ctx_a->nb_streams);
#endif
			if (avm->i_fmt_ctx_a->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
				AVStream *in_stream = avm->i_fmt_ctx_a->streams[i];
				avm->enc_ctx_a = avcodec_alloc_context3(NULL);
				if ((ret = avcodec_parameters_to_context(avm->enc_ctx_a, in_stream->codecpar)) < 0) {
					LOG_PRINT("%s....Audio avcodec_parameters_to_context failed,error code is: %d", __FUNCTION__, ret);
					CLEAN_AND_EXIT
				}
				AVStream *out_stream = avformat_new_stream(avm->o_fmt_ctx, avm->enc_ctx_a->codec);
				if (!out_stream) {
					LOG_PRINT("%s....Audio avformat_new_stream failed", __FUNCTION__);
					CLEAN_AND_EXIT
				}
				avm->audioindex_a = i;
				avm->audioindex_out = out_stream->index;

				out_stream->codecpar->codec_tag = 0;
				if (o_fmt->flags & AVFMT_GLOBALHEADER) {
					avm->enc_ctx_a->flags |= CODEC_FLAG_GLOBAL_HEADER;
				}
				if ((ret = avcodec_parameters_from_context(out_stream->codecpar, avm->enc_ctx_a)) < 0) {
					LOG_PRINT("%s....Audio avcodec_parameters_from_context,error code is: %d", __FUNCTION__, ret);
					CLEAN_AND_EXIT
				}
				break;
			}
		}
	}
#ifdef DEBUG
	printf("========Output Infomation=======\n");
	av_dump_format(avm->o_fmt_ctx, 0, out_file, 1);
	printf("================================\n");
#endif

	//Open output file
	if (!(o_fmt->flags & AVFMT_NOFILE)) {
		if ((ret = avio_open(&avm->o_fmt_ctx->pb, out_file, AVIO_FLAG_WRITE)) < 0) {
			LOG_PRINT("%s....avio_open failed,error code is: %d", __FUNCTION__, ret);
			CLEAN_AND_EXIT
		}
	}

	if (avm->o_fmt_ctx->pb == NULL)
		LOG_PRINT("%s....avm->o_fmt_ctx->pb == NULL", __FUNCTION__);
	if (avm->o_fmt_ctx->oformat == NULL)
		LOG_PRINT("%s....avm->o_fmt_ctx->oformat == NULL", __FUNCTION__);

	//Write file header
	int header_ret = avformat_write_header(avm->o_fmt_ctx, NULL);
	if (header_ret < 0) {
		if (avm->o_fmt_ctx == NULL) {
			LOG_PRINT("%s....avm->o_fmt_ctx is NULL", __FUNCTION__);
		}
		LOG_PRINT("%s....avformat_write_header failed,error code is: %d", __FUNCTION__, header_ret);
		CLEAN_AND_EXIT
	}

	/*
	* 创建复用线程
	*/
	pthread_create(&avm->vp->pp->tid, NULL, mux_thread, avm);
	/* 线程退出时自动释放资源 */
	pthread_detach(avm->vp->pp->tid);
	LOG_PRINT("%s....Create mux thread", __FUNCTION__);
	return 0;
}


CtxAllFree:

 

 

 

 

static void CtxAllFree(AVMuxing *avm)
{
	__try {
		if (avm->enc_ctx_a) {
			avcodec_close(avm->enc_ctx_a);
		}
		if (avm->enc_ctx_v) {
			avcodec_close(avm->enc_ctx_v);
		}
		if (avm->i_fmt_ctx_a) {
			avformat_close_input(&avm->i_fmt_ctx_a);
		}
		if (avm->i_fmt_ctx_v) {
			avformat_close_input(&avm->i_fmt_ctx_v);
		}
		if (avm->o_fmt_ctx) {
			avio_close(avm->o_fmt_ctx->pb);
			avformat_free_context(avm->o_fmt_ctx);
		}
		if (avm) {
			free(avm);
		}
		/* 设为NULL,避免使用野指针 */
		avm = NULL;
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		LOG_PRINT("%s error\n", __FUNCTION__);
	}
}


CurrentPercent:

 

 

 

 

int CurrentPercent(int cnt, int total)
{
	int ret = -1;
	ret = (int)((float)cnt / (float)total * 100.0);
	printf("Progress is %d\n", ret);

	return ret;
}

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FFmpeg合并视频流与音频流 的相关文章

  • 编程领域中的事务概念解析

    在编程领域 xff0c 事务 xff08 Transaction xff09 是一个非常重要的概念 它可以帮助我们处理分布式系统中的并发问题 保证数据的一致性和完整性 本文将详细解释事务的概念及其在编程中的应用 一 什么是事务 xff1f
  • C++流概述

    C 43 43 流概述 在程序设计中 xff0c 数据输入 输出 xff08 I O xff09 操作是必不可少的 xff0c C 43 43 语言的数据输入 输出操作是通过I O流库来实现的 C 43 43 中把数据之间的传输操作称为流
  • kNN(K-Nearest Neighbor)最邻近规则分类

    K最近邻分类算法 方法的思路 xff1a 如果一个样本在特征空间中的k个最相似 xff08 即特征空间中最邻近 xff09 的样本中的大多数属于这一类别 xff0c 则该样本也属于这个类别 KNN算法中 xff0c 所选择的邻居都是已经正确
  • SPOOLING技术

    SPOOLING技术 xff08 Simultaneous Peripheral Operating On Line 同时联机外围操作技术 xff0c 它是关于慢速字符设备 如何与计算机主机进行数据交换 的一种技术 xff0c 通常又称 假
  • Belady现象

    Belady现象 采用FIFO算法时 xff0c 如果对 个进程未分配它所要求的全部页面 xff0c 有时就会出现分配的页面数增多但缺页率反而提高的异常现象 Belady现象的描述 xff1a 一个进程P要访问M个页 OS分配N N lt
  • 计算结构体的字节数

    结构体中的成员可以是不同的数据类型 xff0c 成员按照定义时的顺序依次存储在连续的内存空间 和数组不一样的是 xff0c 结构体的大小不是所有成员大小简单的相加 xff0c 需要考虑到系统在存储结构体变量时的地址对齐问题 看下面这样的一个
  • 轻松搞定面试中的二叉树题目

    版权所有 xff0c 转载请注明出处 xff0c 谢谢 xff01 http blog csdn net walkinginthewind article details 7518888 树是一种比较重要的数据结构 xff0c 尤其是二叉树
  • 使用Anaconda Navigator无法成功创建虚拟环境问题的解决方案

    1 问题描述 使用anaconda Navigator创建虚拟环境时 xff0c 配置初始名称以及python版本 xff0c Fetching各种包成功后 xff0c 开始loading各种包的过程中闪过cmd黑色窗口 xff0c 然后左
  • QT 后台处理时间过长 主界面卡死解决办法

    之前用WPF开发 xff0c 处理逻辑就是1 xff0c 处理前显示等待窗口 xff0c 2 同步处理改未异步 xff0c 3 处理完毕后关闭等待窗口 Qt应该也是类似的处理逻辑 xff1a 一 创建等待处理窗口 xff08 采用了QMoi
  • 一圈n个人,1-3循环报数,报道3的退出,最后剩下的是几号

    import java util ArrayList import java util List import java util Scanner public class CirCle public static void main St
  • GCD【洛谷P2568】(小左的GCD)

    题目描述 给定整数N xff0c 求1 lt 61 x y lt 61 N且Gcd x y 为素数的数对 x y 有多少对 输入格式 一个整数N 输出格式 答案 输入输出样例 输入 1 复制 4 输出 1 复制 4 说明 提示 对于样例 2
  • C++中的weak_ptr深入解析

    引言 在C 43 43 的智能指针家族中 xff0c weak ptr是一种非常实用且独特的成员 它主要用于解决循环引用问题 xff0c 从而避免内存泄漏 在本文中 xff0c 我们将详细讨论weak ptr的基本概念 功能和应用场景 xf
  • 【Redis】解决WARNING overcommit_memory is set to 0 Background save may fail under low memory condition.

    问题说明 不管是linux直装 xff0c 还是在docker环境中 xff0c 启动redis时 xff0c 报如下错误 WARNING overcommit memory is set to 0 Background save may
  • 运动跟踪算法CMT(续)之层次凝聚聚类算法(HAC)

    熟悉CMT的都知道 xff0c 作者在聚类部分使用了层次凝聚聚类算法 xff08 Hierarchical Agglomerative Clustering xff09 并且使用的是单链 xff08 Single link xff09 xf
  • 使用mysql8.x版本设置远程连接

    主要步骤 xff0c 注意 xff1a 自mysql8 x版本 xff0c 密码的加密方式改为caching sha2 password 登录mysql账号修改root用户登录地址修改root用户密码加密方式 usr local mysql
  • jenkins基础配置之四:读取本地文件

    需要安装的插件 Extended Choice Parameter Plug span class token operator span In span class token operator span External Monitor
  • 初识Btrfs文件系统

    Btrfs 也有一个重要的缺点 xff0c 当 BTree 中某个节点出现错误时 xff0c 文件系统将失去该节点之下的所有的文件信息 而 ext2 3 却避免了这种被称为 错误扩散 的问题 Btrfs相关介绍 xff1a Btrfs 是一
  • 服务器使用笔记本网络连接外网

    由于服务器经常部署在机房 xff0c 并没有外网 xff0c 连不上外网 需要使用自己笔记本的网络供服务器使用 笔记本连接手机热点 xff0c 再分享给服务器 一 首先 xff0c 需要把服务器和笔记本连接到同一网络内 xff0c 可以选择
  • grafana接入openldap认证

    首先两个文件开启ldap的支持 文件1 xff1a etc grafana grafana ini auth ldap enabled 61 true config file 61 etc grafana ldap toml allow s
  • Wireshark的常见提示

    概述 本文主要介绍Wireshark中出现的一些常见提示 详细信息 Wireshark简介 Gerald Combs是堪萨斯城密苏里大学计算机科学专业的毕业生 1998年发布了第一版Ethereal工具 xff0c Ethereal工具使用

随机推荐

  • shell报错bad substitution 解决办法

    bin bash a 61 34 hello 34 b 61 34 hi is a 34 echo b echo a echo a echo a 1 2 执行脚本方式不同出现的结果不同 xff1a 方式1 xff1a sh shell sh
  • centos8软件安装dnf命令

    DNF是新一代的rpm软件包管理器 它首先出现在 Fedora 18 这个发行版中 而目前 xff0c 它取代了yum xff0c 正式成为从 Fedora 22 起 Fedora 版本的包管理器 DNF包管理器克服了YUM包管理器的一些瓶
  • 多目标规则在 Makefile 中的应用与示例

    在 Makefile 中 xff0c 如果一个规则有多个目标 xff0c 而且它们之间用空格分隔 xff0c 我们称之为 34 多目标规则 34 这意味着这个规则适用于列出的所有目标 在目标下面的命令是 C 64 xff0c 它通常与 ma
  • 计算机中内存、cache和寄存器之间的关系及区别

    1 寄存器是中央处理器内的组成部份 寄存器是有限存贮容量的高速存贮部件 xff0c 它们可用来暂存指令 数据和位址 在中央处理器的控制部件中 xff0c 包含的寄存器有指令寄存器 IR 和程序计数器 PC 在中央处理器的算术及逻辑部件中 x
  • dell 台式电脑设置每天定时开机和关机

    每天定时开机设置 xff1a 戴尔电脑通过CMOS设置实现自动开机的设置过程如下 xff1a 1 首先进入 CMOS SETUP 程序 大多数主板是在计算机启动时按DEL或F2键进入 xff1b 2 然后将光条移到 Power Manage
  • windows批处理自动获取电脑配置信息

    39 2 gt nul 3 gt nul amp cls amp 64 echo off 39 amp rem 获取本机系统及硬件配置信息 39 amp set 61 Any question amp set 64 61 WX amp se
  • Centos7搭建cisco ocserv

    一 安装的部分直接yum安装即可 yum y install ocserv 二 配置文件根据实际情况调整 auth方式有两种 1 系统账号认证 配置的话就是 xff1a auth 61 34 pam 34 2 本地文件认证 配置的话就是 x
  • 私有harbor部署(docker方式)

    环境准备 docker compose v Docker Compose version v2 14 2 wget https github com docker compose releases download v2 14 2 dock
  • ORACLE扩展表空间

    一 查询表空间使用情况 SELECT UPPER F TABLESPACE NAME 34 表空间名 34 D TOT GROOTTE MB 34 表空间大小 M 34 D TOT GROOTTE MB F TOTAL BYTES 34 已
  • Oracle 常用性能监控SQL语句

    1 查看表锁 SELECT FROM SYS V SQLAREA WHERE DISK READS gt 100 2 监控事例的等待 SELECT EVENT SUM DECODE WAIT TIME 0 0 1 34 Prev 34 SU
  • Nginx出现“ 413 (499 502 404) Request Entity Too Large”错误解决方法

    1 Nginx413错误的排查 修改上传文件大小限制 在使用上传POST一段数据时 xff0c 被提示413 Request Entity Too Large xff0c 应该是nginx限制了上传数据的大小 解决方法就是 打开nginx主
  • 查看弹出广告来自哪个软件

    打开VS的Spy 43 43 将指针移到广告处 xff0c 然后点OK xff0c 在Process标签页可以看到进程id和线程id将获得的16进制进程id xff08 例如 xff1a 000025F8 xff09 通过计算器转成10进制
  • C++多态虚函数实现原理,对象和虚函数表的内存布局

    基本概念 我们知道C 43 43 动态多态是用虚函数实现的 xff0c 而虚函数的实现方式虽说C 43 43 标准没有要求 xff0c 但是基本都是用虚函数表实现的 xff08 编译器决定 xff09 所以我们有必要了解一下虚函数表的实现原
  • C++ STL中递归锁与普通锁的区别

    在多线程编程中 xff0c 保护共享资源的访问很重要 xff0c 为了实现这个目标 xff0c C 43 43 标准库 xff08 STL xff09 中提供了多种锁 xff0c 如std mutex和std recursive mutex
  • VS+Qt开发环境

    VS Qt下载 VS下载 xff1a https visualstudio microsoft com zh hans vs Qt下载安装 xff1a https www bilibili com video BV1gx4y1M7cM VS
  • windows下使用ShiftMediaProject编译调试FFmpeg

    为什么要编译FFmpeg xff1f 定制模块调试源码 windows下编译 推荐项目ShiftMediaProject FFmpeg 平时总是看到一些人说windows下编译FFmpeg很麻烦 xff0c 这时候我就都是微微一笑 xff0
  • RTSP分析

    RTSP使用TCP来发送控制命令 xff08 OPTIONS DESCRIBE SETUP PLAY xff09 xff0c 因为TCP提供可靠有序的数据传输 xff0c 而且TCP还提供错误检测和纠正 RTSP的报文格式可以参考HTTP的
  • RTP分析

    参考 RTP xff08 A Transport Protocol for Real Time Applications 实时传输协议 xff0c rfc3550 xff09 RTP Payload Format for H 264 Vid
  • VS链接器工具错误 LNK2019:无法解析的外部符号

    常见的问题 以下是一些导致 LNK2019 的常见问题 xff1a 未链接的对象文件或包含符号定义的库 在 Visual Studio 中 xff0c 验证包含定义源代码文件是生成 xff0c 分别链接为项目的一部分 在命令行中 xff0c
  • FFmpeg合并视频流与音频流

    mux h ifndef MUX H define MUX H ifdef cplusplus extern 34 C 34 endif include 34 common h 34 include 34 encode h 34 typed