C++实现视频格式转换PC客户端工具(支持多任务,暂停,断点续转,删除等基本功能)

2023-05-16

在接到这个任务时,当时有些懵,网上找了很多资料,开源项目没有发现与之类似,大多都是像迅雷这样子支持多任务下载,断点续传。所以现在对于这个个人做个总结方便后期回顾,同时对正在完成类似的同学有些许帮助最好。

此项目借鉴了NPVideoTranscode的UI设计以及任务的处理方式,开发工具使用的是vs2008,界面使用的是Duilib。编译的release版本的Unicode字符集。建议将NPVideoTranscode下载下来运行其中的NPVideoTranscode.exe看是否满足你目前项目的设计要求,链接: https://pan.baidu.com/s/1Fx2kbFs8KujaqjCS5KUVQQ 提取码: hgzw  网盘下载太慢我有办法,需要的留言吧!现在看下我们在此基本上重新设计的界面以及功能间逻辑及数据结构吧。

一、首先看下数据结构的设计:

typedef struct Node
{
	Node()
	{
		Status =_T(""); 
		strFileNameOut =_T("");
		outType = _T("");
		strFileNameIn= _T("");

		pVideoTrans = NULL;
		m_StreamVR = NULL;
		m_StreamAR = NULL;
		m_StreamVW = NULL;
		m_StreamAW = NULL;
		m_Writer = NULL;
		m_Reader = NULL;
		strShowFileName  =_T("");
	}

	DllManager *pVideoTrans; //转码类指针
	CString Status;  //状态	
	CString strFileNameOut ;
	float uiReadLen;  //暂停时已处理的字节长度
	float uiFileLen ; //文件总字节长度
	int sampleA; //当前音频帧的数量
	int sampleV; //当前视频帧的数量
	
	CString strShowFileName;   //界面中用来显示的源文件名
	CString strFileNameIn;   //需要转码的文件路径名
	int Progress;  //当前转码完成的进度
	int timeShow; //当前转码的时间
	CString outType;  //输出的文件类型

	CAVIREADER_STREAMHANDLE m_StreamVR;   //源文件视频流句柄
	CAVIREADER_STREAMHANDLE m_StreamAR;   //....音频流句柄

	CAVIWRITER_STREAMHANDLE m_StreamVW;	  //写入视频流句柄
	CAVIWRITER_STREAMHANDLE m_StreamAW;	  //...音频流句柄

	CAVIREADER_HANDLE m_Writer;  
	CAVIREADER_HANDLE m_Reader;

	//float m_fileLen;


}StreamHandleInfo;

各个参数的说明在注释里都比较清晰,其中的DllManager 是真正的转码类,在源码中有解释,其原理是打开要操作的文件,读取文件的流信息头定义,视频流格式定义,音频流格式定义,需要转码的流信息头定义,视频流格式定义,音频流格式定义,转码的流创建好,开始数据的接收可以使用多线程,大家也可以网上参考转码过程。后面我们对文件的打开。暂停如何保存断点信息,以及删除任务进行说明。

二、文件添加支持文件的拖入以及导入按钮进行导入,拖拽时

HDROP m_hdrop = hDropInfo;
	//std::queue<TCHAR *> ll;
	//查询拖入文件个数
	int number = 0;
	number = DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0);

	//查询每个文件的名称
	TCHAR szpathName[MAX_PATH];
	CString  pathName;
	CString  fileName;

	DWORD    dwSize;
	std::vector<CString> szInFileName;

	for (int i = 0; i < number; i++)
	{
		dwSize = DragQueryFile(hDropInfo, i, NULL, 0);
		DragQueryFile(hDropInfo, i, szpathName, dwSize + 1);
		pathName = szpathName;
		szInFileName.push_back((pathName));
	}
	int nNumber = 0;
	int nCnt = szInFileName.size();
	while (nCnt > nNumber)
	{
		CString ll = szInFileName[nNumber].Right(4);
		CString ll2 = _T(".avi") ,ll3=_T(".mp4");
		//if (strcmp((const char *)(LPCTSTR)ll, (const char  *)(LPCTSTR)ll2)==0)
		if (ll.CompareNoCase(ll2) == 0)	
		{
			m_szInFileName.push_back(szInFileName[nNumber]);
		}
		nNumber++;
	}
	//完成拖入文件操作,让系统释放缓冲区
	DragFinish(hDropInfo);

    //进入新建转码的界面
	CNewTranscodeWnd *newTranscode = new CNewTranscodeWnd(_T("NewTranscodeWnd.xml"));
	newTranscode ->Create(m_hWnd,_T("NewTranscodeWnd"),UI_WNDSTYLE_DIALOG,WS_EX_WINDOWEDGE);
	m_NewTranscodeHwnd = newTranscode->GetCurrentwndHwnd();
	newTranscode->SetParentHwnd(this->m_hWnd);
	::SendMessage(m_NewTranscodeHwnd,CM_MAINTONEWTRANCFILENAME,(WPARAM)(LPCTSTR)m_szOutPath,(LPARAM)&m_szInFileName);
	m_szInFileName.clear();
	m_szInFileName.resize(0);
	newTranscode->CenterWindow();
	newTranscode->ShowModal();

	//CView::OnDropFiles(hDropInfo);
	return 0;

文件拖入时可以看到支持的是.avi格式,在拖入后我们会创建新建转码的窗口,此窗口下会有一个List表格显示对应拖入的文件名,同时支持继续添加文件以及删除部分文件。如何将文件名显示在List表格中并在我添加文件时能继续显示,这里使用了回调函数GetItemText,在类CNewTranscodeWnd中实现,其中GetItemText的使用在duilib的demo中有具体实现,可自行参考使用。其中CNewTranscodeWnd类主要实现文件的添加、删除,文件输出存储位置,输出视频的格式以及保存位置的可用空间大小,打开文件的实现方法如下。

        size_t index;
		CString cstrsucstring;
		CFileDialog filedlg(TRUE, NULL ,NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT,_T("Source Files(*.avi)|*.avi||"));
		TCHAR *pBuffer = new TCHAR[MAX_PATH*20];
		filedlg.m_ofn.lpstrFile = pBuffer;
		filedlg.m_ofn.nMaxFile = MAX_PATH * 20;
		filedlg.m_ofn.lpstrFile[0] = '\0';
		if (filedlg.DoModal() == IDOK)
		{
			CString cstrfilpath = _T("");
			POSITION pos = filedlg.GetStartPosition();
			while (pos != NULL)
			{
				cstrfilpath = filedlg.GetNextPathName(pos);
				m_szNewFileName.push_back((cstrfilpath));
			}
		}
		AddFileNameToList();

     其中AddFileNameToList()函数就是将打开的视频保存在vector中之后在回调函数GetItemText中显示,当前会显示视频输入的路径,可否转码以及高级设置,高级设置理论是可以设置其码率,这里没有处理,之后发送消息给主界面,其中包括输入视频的路径,转码后视频的路径,转码格式。

三、接受消息获得视频信息,实现任务开始、暂停

对于主界面在接收到返回的信息时,将其保存设置在上面定义的结构体中,在该主界面类使用回调函数GetItemText进行显示。默认实现同时执行两个任务转码,此时可以通过点击正在进行的任务来暂停任务,另一个等待的任务开始执行,这里我们用vector来保存正在执行的任务,设置当前的vector中只存在两个,使用线程对该vector进行检测,当其中数目少于两个时,说明可以添加进来执行新任务,当然也要保证有等待的任务,否则不可自动添加进来。对于暂停的任务点击开始即可添加进执行任务的vector中。而对于当前已经有两个任务执行的,在我们点击已经暂停的任务让其重新开启任务时,我们需要暂停正在执行任务中最后添加进来的任务,从运行的vector中删除先前正在运行的最后一个,添加进来当前暂停的任务,以此来开启新任务,以下是开启暂停任务的过程

if (m_szCurrentTaskNumVct.size() >= 2)
		{
			std::vector<StreamHandleInfo>::iterator it = std::find_if(m_szTranscodeFileInfoVct.begin(),m_szTranscodeFileInfoVct.end(),std::bind2nd(NodeInfo(),m_szCurrentTaskNumVct[1]));
			int index;
			if (m_szTranscodeFileInfoVct.end() != it)
			{
				index = it-m_szTranscodeFileInfoVct.begin();
				m_szTranscodeFileInfoVct[index].pVideoTrans->isStartRun(FALSE);
				m_szTranscodeFileInfoVct[index].Status =_T("等待");
				m_szTranscodeFileInfoVct[index].uiFileLen=m_szTranscodeFileInfoVct[index].pVideoTrans->m_uiFileLen;
				m_szTranscodeFileInfoVct[index].uiReadLen=m_szTranscodeFileInfoVct[index].pVideoTrans->m_uiReadLen;
				m_szTranscodeFileInfoVct[index].sampleA=m_szTranscodeFileInfoVct[index].pVideoTrans->m_SampleNOA;
				m_szTranscodeFileInfoVct[index].sampleV=m_szTranscodeFileInfoVct[index].pVideoTrans->m_SampleNOV;
				m_szCurrentTaskNumVct.erase(m_szCurrentTaskNumVct.begin() + 1);
			}
		}

		m_szCurrentTaskNumVct.push_back(m_szTranscodeFileInfoVct[nCulSel]);
		m_szTranscodeFileInfoVct[nCulSel].Status = _T("正在进行");
		m_szTranscodeFileInfoVct[nCulSel].pVideoTrans->m_uiReadLen = m_szTranscodeFileInfoVct[nCulSel].uiReadLen;
		m_szTranscodeFileInfoVct[nCulSel].pVideoTrans->m_uiFileLen = m_szTranscodeFileInfoVct[nCulSel].uiFileLen;
		m_szTranscodeFileInfoVct[nCulSel].pVideoTrans->m_SampleNOA = m_szTranscodeFileInfoVct[nCulSel].sampleA;
		m_szTranscodeFileInfoVct[nCulSel].pVideoTrans->m_SampleNOV = m_szTranscodeFileInfoVct[nCulSel].sampleV;
		m_szTranscodeFileInfoVct[nCulSel].pVideoTrans->isStartRun(TRUE);
	}

以上就是重新开启暂停任务的过程,需要注意的就是>=2这个就死判断当前正在任务数量是否为2,为2的话我们需要保存最后一个任务的信息,然后从vector中删除掉。

四、删除等待的任务或者暂停的任务(不允许删除正在运行的任务,若要删除可以先暂停再删除它)

删除主要注意两个部分:

1.如何从List表格中删除,这个我们可以用list中的方法

int nCulSel = pList->GetCurSel();
		if (nCulSel < 0) return;
		pList->RemoveAt(nCulSel);

2.我们需要删除它的数据这可用rease函数进行删除,可以了解下如何删除。

以上两项在duilib的listdemo中均有使用方法,自行学习。

还有一个重点就是在执行任务时如何进度的显示,这里我们开了线程,时间为间隔为1s,我们利用转码类DllManager中已经转码的字节和文件的总字节进行处理,从而获得当前已转码进度,再利用线程即可达到效果。

 

以上就是大体的思想,我将源码分享出来,里面有实现的详细过程以及部分注释,根据里面的定义变量名也更能方便理解,希望对视频转码的同学有些许帮助,部分代码被我注释了,只提供学习参考,你可能无法简单的成功编译的,转码的视频需用我提供的,在release版本里,有疑问的请留言。

源码链接:https://download.csdn.net/download/hfuu1504011020/11816506

release版本链接:https://pan.baidu.com/s/1zPks2Mfzz4lgYNzDKjEEag 提取码: pvjh  (包括可转码的视频)

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

C++实现视频格式转换PC客户端工具(支持多任务,暂停,断点续转,删除等基本功能) 的相关文章

  • 关于串口的初始化Uart_Init(0, 115200)

    void Uart Init int pclk int baud int i if pclk 61 61 0 因为Main c 中定义了 GLOBAL CLK 61 1 所以 PCLK 在 option h 中定义 在Main c 中的设置
  • 【学习笔记】Ubuntu双系统+搭建个人服务器

    Ubuntu双系统 43 搭建个人服务器 前言1 Ubuntu 43 Win双系统1 1 制作U盘启动盘1 2 系统分盘1 3 安装Ubuntu系统 2 搭建个人服务器2 1 设置root2 2 配置ssh2 3 向日葵连接 3 内网穿透3
  • IMU 测量模型和运动学模型

    一 概念 高斯白噪声 测量噪声是AD转换器件引起的外部噪声 xff0c 波动激烈的测量白噪声 随机游走 这里指零偏Bias 随机游走噪声 xff0c 是传感器内部机械 温度等各种物理因素产生的传感器内部误差的综合参数 xff0c 是变化缓慢
  • java参数校验注解

    java参数校验注解 java中前后台参数传递时如何对参数进行校验 校验主要使用到 javax validation类 一 引入依赖 SpringBoot的web组件中已引入validation的jar包 xff0c 但也可自行引入 spa
  • SpringBoot集成阿里easyexcel(三)CellWriteHandler图片转换

    继承单元格处理器 xff0c 通过重写不同方法 xff0c 对单元格进行处理 span class token keyword public span span class token keyword class span span cla
  • 使用Mybatis-plus拦截加密数据

    使用Mybatis plus拦截加密数据 使用自定义注解来标识需要加密的po和字段 xff0c 并通过mybaitsplus的插件工具类Interceptor类来实现对数据的拦截与加密转换操作 一 自定义加密注解 作用在类上的注解 pack
  • SpringBoot集成阿里easyexcel(四)Converter导入导出数据转换器

    SpringBoot集成阿里easyexcel xff08 四 xff09 Converter导入导出数据转换器 通过com alibaba excel converters Converter转换器实现Excel导入导出时Java数据与E
  • SpringBoot集成Ehcache缓存

    SpringBoot集成Ehcache缓存 Ehcache有两种缓存方式 xff0c 分别是堆内存 磁盘 xff08 非堆内存 xff09 一 堆内存缓存 也就是MemoryStore xff0c 速度最快 xff0c 不适合存放大量数据
  • Spring的切面编程(AOP)概念与使用AOP实现日志记录

    Spring的切面编程 xff08 AOP xff09 概念与使用 一 面向切面编程 定义 面向切面编程 xff08 AOP xff09 是通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术 作用 xff1a 利用AOP对业务
  • 关于intrins.h头文件的介绍

    在单片机中应用最多的当然就是移位函数 xff0c 利用移位函数可以更简便的实现流水灯等效果 移位函数 移位函数名 左移 span class token function crol span span class token punctua
  • 大批量数据分批批量插入或更新(Mybatis+MySQL)

    大批量数据分批批量插入或更新 在MySQL数据库的前提下 xff0c 插入或更新大批量数据 首先批量插入需要考虑到以下几个因素 xff1a 数据库一次可以承受多大或者多少条数据的插入批量插入是否会占用Mysql资源太久 xff0c 影响系统
  • VSCode配置C++开发环境

    更新细节 2020 7 3 更新细节及排版 2022 6 9 昨天从下午一直研究到晚上十一点 xff0c 查阅了很多博客资料 xff0c 还是没配置好VSCode的C 43 43 开发环境 xff0c 今天早上又弄了一下 xff0c 现在O
  • stm32模拟输出PPM信号

    PPM信号周期为20ms xff0c 分成10分代表10个通道信号 xff0c 也就是2ms代表一个信号 0 5ms代表一个通道信号的开始 xff0c 所以0 5ms 2ms为通道范围控制 LED p1 39 A 39 8 IO口初始化 x
  • 使用JSON.parse,解决ie6-7上JSON未定义问题

    使用JSON parse时出现JSON未定义问题 xff0c JSON不是标准的javascript类型 xff0c 一些高级的浏览器支持 xff0c 但一些老一点的浏览器不支持JSON 如ie6 7 若需要 ie6 7 支持JSON只需要
  • C语言中的大小端转换与高低位颠倒

    在说大小端高低位之前 xff0c 肯定要说明数据在计算机内是如何存储的 在计算机中 xff0c 我们将数据分割成了一个一个的字节 xff08 byte xff09 xff0c 而每个字节又有8位 xff08 bit xff09 一个字节 x
  • C语言库函数中的Strcat函数

    一 Strcat函数的参数 Strcat函数所引用的头文件是 lt string h gt char strcat char strDestination const char strSource 参数说明 xff1a strDestina
  • SLAM中的marginalization 和 Schur complement

    在视觉SLAM的很多论文中 xff0c 会大量或者偶尔出现marginalization这个词 翻译为边缘化 xff0c 有的论文是特地要用它 xff0c 比如sliding window slam 2 okvis 3 dso 4 而有的论
  • 数据结构之单链表循环

    单链表循环代码如下 xff1a include lt stdio h gt include lt stdlib h gt typedef struct node int data struct node next sqlist sqlist
  • 数据结构之双链表循环

    定义是 xff1a 每个数据结点都有两个指针 xff0c 分别指向直接后继和直接前驱 因此双向链表中单任意一个结点开始 xff0c 都可以很方便的访问它的前驱结点和后继结点 循环链表指 xff1a 最后一个结点next指向头结点 xff0c
  • linux学习之进程

    进程概念 xff1a 活跃度程序 xff0c 占用系统资源 xff0c 在内存中执行产生一个进程 孤儿进程 xff1a 父进程先于子进程结束 xff0c 则子进程称为孤儿进程 xff0c 并且这个子进程被init进程回收 include l

随机推荐