音视频开发系列(17):封装控制类使用音视频类

本文档介绍了一个音视频处理项目,通过封装一个名为XController的控制类,实现了图像美颜、音视频录制、编码、推流等功能。该类在线程中运行,用户只需调用Start和Stop方法即可开始和结束推流。在Start方法中,包含了初始化相机、设置美颜参数、音频录制、音视频编码和推流等步骤,确保了整个流程的顺畅执行。
摘要由CSDN通过智能技术生成

上次分享了如何对图像进行进行处理以达到图像磨皮的效果,由于后面要把这个音视频项目做成一个带有界面的项目,所以需要对其中例如编码器初始化这些操作封装成一个控制类,这样的话界面只需要调用该类即可,就不需要再写重复的代码。

这个项目主要的核心类如下图所示。

 这次主要要封装一个控制类,该类主要包括以下方法和属性:

#pragma once
#include <QThread>
#include <string>
#include "XDataThread.h"
class XController:public XDataThread
{
public:
	std::string outUrl;
	int camIndex = -1;
	std::string inUrl = "";
	std::string error = "";
	static XController *Get()
	{
		static XController xc;
		return &xc;
	}
	//设定美颜参数
	virtual bool Set(std::string key,double value);
	virtual bool Start();
	virtual void Stop();
	void run();
	virtual ~XController();
protected:
	int vindex = 0;//视频流索引
	int aindex = 0;//音频流索引
	XController();
};

该类为一个线程类,主要在用户调用该类进行Start后就会开启一个线程,然后在线程里面就会开启音视频录制类线程并进行读取录制好的数据,这样在主函数中只需要调用Start和Stop来开启和暂停线程即可,接下来是源码的分享。该类也是一个线程类,继承于之前编写过的XDataThread类

XController.cpp

#include "XController.h"
#include <iostream>
#include "XVideoCapture.h"
#include "XAudioRecord.h"
#include "XMediaEncode.h"
#include "XRtmp.h"
using namespace std;

void XController::run()
{
	long long beginTime = GetCurTime();
	while (!isExit)
	{
		//一次读取一帧音频
		XData ad = XAudioRecord::Get()->Pop();
		XData vd = XVideoCapture::Get()->Pop();
		if (ad.size <= 0 && vd.size <= 0)
		{
			msleep(1);
			continue;
		}
		if (ad.size > 0)
		{
			ad.pts = ad.pts - beginTime;
			//已经读取一帧源数据
			//重采样数据
			XData pcm = XMediaEncode::Get()->Resample(ad);
			ad.Drop();
			XData pkt = XMediaEncode::Get()->EncodeAudio(pcm);
			if (pkt.size>0)
			{
				//推流
				if (XRtmp::Get()->SendFrame(pkt, aindex))
				{
					cout << "#" << flush;
				}
			}
		}
		if (vd.size > 0)
		{
			vd.pts = vd.pts - beginTime;
			XData yuv = XMediaEncode::Get()->RGBToYUV(vd);
			vd.Drop();
			XData pkt = XMediaEncode::Get()->EncodeVideo(yuv);
			if (pkt.size>0)
			{
				//推流		
				if (XRtmp::Get()->SendFrame(pkt, vindex))
				{
					cout << "@" << flush;
				}
			}
		}
	}
}
bool XController::Set(std::string key, double value)
{
	XFilter::Get()->Set(key, value);
	return true;
}
bool XController::Start()
{
	///1.设置磨皮过滤器
	XVideoCapture::Get()->AddFilter(XFilter::Get());
	cout << "1设置磨皮过滤器成功" << endl;
	///2.打开相机
	if (camIndex >= 0)
	{
		if (!XVideoCapture::Get()->Init(camIndex))
		{
			error = "打开相机失败";
			cout << error << endl;
			return false;
		}

	}else if(inUrl.empty())
	{
		if (!XVideoCapture::Get()->Init(inUrl.c_str()))
		{
			error = "打开";
			error += inUrl;
			error += "相机失败";
			cout << error << endl;
			return false;
		}
	}
	else
	{
		error = "请输入相机参数";
		cout << "请输入相机参数" << endl;
		return false;
	}
	cout << "2相机打开成功" << endl;

	///3.qt音频开始录制
	if (!XAudioRecord::Get()->Init())
	{
		error = "录音设备打开失败";
		cout << error << endl;
		return false;
	}
	cout << "3录音设备打开成功" << endl;

	///11.启动音视频录制线程
	XAudioRecord::Get()->Start();
	XVideoCapture::Get()->Start();
	///音视频编码类
	///4.初始化格式转换上下文
	///初始化输出的数据结构
	XMediaEncode::Get()->inWidth=XVideoCapture::Get()->width;
	XMediaEncode::Get()->inHeight = XVideoCapture::Get()->height;
	
	XMediaEncode::Get()->outWidth = XVideoCapture::Get()->width;
	XMediaEncode::Get()->outHeight = XVideoCapture::Get()->height;
	if (!XMediaEncode::Get()->InitScale())
	{
		error = "视频像素格式转换打开失败";
		cout << error << endl;
		return false;
	}
	cout << "4视频像素格式转换打开成功" << endl;
	///5.音频重采样 上下文初始化
	XMediaEncode::Get()->channels = XAudioRecord::Get()->channels;
	XMediaEncode::Get()->nbSample = XAudioRecord::Get()->nbSample;
	XMediaEncode::Get()->sampleRate = XAudioRecord::Get()->sampleRate;
	if (!XMediaEncode::Get()->InitResample())
	{
		error = "音频重采样上下文初始化失败";
		cout << error << endl;
		return false;
	}
	cout << "5音频重采样上下文初始化成功" << endl;

	///6.初始化音频编码器
	if (!XMediaEncode::Get()->InitAudioCodec())
	{
		error = "初始化音频编码器失败";
		cout << error << endl;
		return false;
	}
	cout << "6初始化音频编码器成功" << endl;
	///7.初始化视频编码器
	if (!XMediaEncode::Get()->InitVideoCodec())
	{
		error = "初始化视频编码器失败";
		cout << error << endl;
		return false;
	}
	cout << "7初始化视频编码器成功" << endl;

	///8.创建输出封装器上下文
	if (!XRtmp::Get()->Init(outUrl.c_str()))
	{
		error = "创建输出封装器上下文失败";
		cout << error << endl;
		return false;
	}
	cout << "8创建输出封装器上下文成功" << endl;

	///9.添加音视频流
	vindex = XRtmp::Get()->AddStream(XMediaEncode::Get()->vc);
	
	aindex = XRtmp::Get()->AddStream(XMediaEncode::Get()->ac);
	if (vindex < 0 || aindex < 0)
	{
		error = "添加音视频流失败";
		cout << error << endl;
		return false;
	}
	cout << "9添加音视频流成功" << endl;

	///10.写入封装头
	if (!XRtmp::Get()->SendHead())
	{
		error = "发送封装头失败";
		cout << error << endl;
		return false;
	}
	cout << "10发送封装头成功" << endl;


	XAudioRecord::Get()->Clear();
	XVideoCapture::Get()->Clear();
	XDataThread::Start();
	return true;
}
void XController::Stop()
{
	XDataThread::Stop();
	XAudioRecord::Get()->Stop();
	XVideoCapture::Get()->Stop();

	XMediaEncode::Get()->Close();
	XRtmp::Get()->Close();

	camIndex = -1;
	inUrl = "";
	return;
}
XController::XController()
{
}


XController::~XController()
{
}

main.cpp

主函数主要用于测试停止后是否存在问题。

#include <QtCore/QCoreApplication>
#include <QThread>
#include <iostream>
#include "XMediaEncode.h"
#include "XRtmp.h"
#include "XAudioRecord.h"
#include "XVideoCapture.h"
#include "XFilter.h"
#include "XController.h"
using namespace std;
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	const char *outUrl = "rtmp://192.168.198.128/live";
	XController::Get()->camIndex = 0;
	XController::Get()->outUrl = outUrl;
	XController::Get()->Start();
	QThread::msleep(10000);

	XController::Get()->Stop();
	XController::Get()->camIndex = 0;
	XController::Get()->outUrl = outUrl;
	XController::Get()->Start();
	XController::Get()->wait();
	return a.exec();
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值