admin 管理员组

文章数量: 1184232

1.xaudio.h

#pragma onceclassxaudioplay{public:static xaudioplay*get();xaudioplay();//一定得是虚析构函数,delete时才可以通过父类指针完成继承类的析构virtual~xaudioplay();virtualboolopen()=0;//第二次打开如果是其他媒体文件的话下面这些参数就要变,因此需要有closevirtualboolclose()=0;//将参数传递与ffmpeg隔离,故通过成员传递,QT的音频格式对象需要这些参数//channels和采样率通过demux传递,采样大小固定int samplerate =0;int samplesize =16;int channels =0;//音频virtualboolwrite(constunsignedchar* data,int datasize)=0;virtualintGetfree()=0;};

1.纯虚函数(open(),close())

在基类中仅仅给出声明,不对虚函数实现定义,而是在派生类中实现。这个虚函数称为纯虚函数。普通函数如果仅仅给出它的声明而没有实现它的函数体,这是编译不过的。纯虚函数没有函数体。

纯虚函数需要在声明之后加个=0;

class <基类名>

{

virtual <类型><函数名>(<参数表>)=0; …

};

2.抽象类 (xaudioplay)

含有纯虚函数的类被称为抽象类。抽象类只能作为派生类的基类,不能定义对象,但可以定义指针。在派生类实现该纯虚函数后,定义抽象类对象的指针,并指向或引用子类对象。

1)在定义纯虚函数时,不能定义虚函数的实现部分;

2)在没有重新定义这种纯虚函数之前,是不能调用这种函数的。

抽象类的唯一用途是为派生类提供基类,纯虚函数的作用是作为派生类中的成员函数的基础,并实现 动态多态性 。继承于抽象类的派生类如果不能实现基类中所有的纯虚函数,那么这个派生类也就成了抽象类。因为它继承了基类的抽象函数,只要含有纯虚函数的类就是抽象类。纯虚函数已经在抽象类中定义了这个方法的声明,其它类中只能按照这个接口去实现。

3.该类(xaudioplay)做为工厂来创建对象(在头文件中定义),对象具体(xaudio)创建过程在其继承类中(在cpp中定义)
可能会几种播放器:基于QT,基于DIRECXT,根据不同的需要然后返回不同的继承类对象

4.C++提供static这个关键词对静态成员进行声明,静态成员函数和类的实例化无关,对于同一类来说,静态成员函数是共享的。而普通成员函数需要实例化才能调用,对于每一个实例来说,普通成员函数是自己独有的
:static xaudioplay* get();
在使用使通过类名来调用,而不是通过实例化后的类名来调用:
xaudioplay::get()->samplerate

2.xaudio.cpp

classaudioplay:public xaudioplay
{//还有个好处是可以将细节隐藏起来//与qt相关的成员放在audioplay中public:
	QAudioOutput* output;
	QIODevice* io;//因为打开与关闭可能不在一个线程,所以要加锁
	std::mutex mux;virtualboolopen(){close();
		QAudioFormat fmt;
		
		fmt.setSampleRate(samplerate);
		fmt.setSampleSize(samplesize);//采样位数
		fmt.setChannelCount(channels);
		fmt.setCodec("audio/pcm");
		fmt.setByteOrder(QAudioFormat::LittleEndian);
		fmt.setSampleType(QAudioFormat::UnSignedInt);
		mux.lock();
		output =newQAudioOutput(fmt);
		io = output->start();//开始播放
		mux.unlock();if(io)returntrue;returnfalse;}virtualboolclose(){
		mux.lock();if(io){
			io->close();//io空间是由output产生的,所以不需要delete,当deleteoutput时会自动删除这块空间//“由谁产生就谁释放”
			io =0;}if(output){
			output->stop();delete output;
			output =0;}
		mux.unlock();returntrue;}virtualboolwrite(constunsignedchar* data,int datasize){if(!data || datasize <=0)returnfalse;
		mux.lock();if(!output||!io){
			mux.unlock();return0;}int size=io->write((char*)data, datasize);if(size != datasize){
			mux.unlock();returnfalse;}
		mux.unlock();returntrue;}virtualintGetfree(){
		mux.lock();if(!output){
			mux.unlock();return0;}int free = output->bytesFree();
		mux.unlock();return free;}};
xaudioplay* xaudioplay::get(){static audioplay play;return&play;}
xaudioplay::xaudioplay(){}
xaudioplay::~xaudioplay(){}

本例中父类中只有get()没有定义为虚函数,get函数做为父类与子类的桥梁,工厂中的传送带

通过父类xxaudioplay的get()方法定义一个其子类,将其设为static,调用期间该不会销毁,保证多次调用都是同一个对象,用法:xaudioplay::get()->open()

3.main

在线程类中修改

classtesttread:public QThread
{public:voidinit(){constchar* path ="E:\\ffmpeg\\test222.mp4";
        cout <<"demux.Open = "<< demux.Open(path)<< endl;
        cout <<"vdecode.open()"<< vdecode.open(demux.CopyVPara())<< endl;
        cout <<"adecode.open()"<< adecode.open(demux.CopyAPara())<< endl;
        cout <<"reasmple.open()"<< resample.Open(demux.CopyAPara())<< endl;
        xaudioplay::get()->channels = demux.channels;
        xaudioplay::get()->samplerate = demux.sampletrate;
        cout <<"xaudioplay::get()->open()"<< xaudioplay::get()->open()<<endl;}unsignedchar*pcm =newunsignedchar[1024*1024*1024];voidrun(){for(;;){
            AVPacket* pkt = demux.readfz();if(demux.isvideo(pkt)==true){
                vdecode.send(pkt);
                AVFrame* frame = vdecode.receive();
                video->Repaint(frame);}else{
                adecode.send(pkt);
                AVFrame* frame = adecode.receive();int len = resample.Resample(frame, pcm);
                cout<<"resample大小:"<<len<<endl;while(len >0){if(xaudioplay::get()->Getfree()>= len){
                        xaudioplay::get()->write(pcm, len);break;}msleep(5);}}if(!pkt)break;}}
    xdemux demux;
    xvideowidget* video;
    xresample resample;protected:
    
    xdecode vdecode;
    xdecode adecode;};

resample.open()的参数是解码获得的,整个媒体文件只有一份,
resample.resample()的参数是AVFrame,是在循环里依次对解码得到的frame进行处理,每从解码队列里获得一个音频packet,就对这个packet进行重采样,并获得重采样后每个音频通道每次采样的比特数,当用QAudioOutput类的方法成员Getfree()判断空余空间中比特数,当前者小于后者时便将pcm(重采样后的结果放在pcm中)进行write并播放

6声道媒体文件播放全是杂音,使用ffmpeg转成2声道就可以正常播放(暂时不知道为什么)

本文标签: 通过父类 编程 声明