您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
13. 完成音视频解码和并重构解码器加入观察者模式~1
发布时间:2021-06-09 20:51:20编辑:雪饮阅读()
上篇咱們實現了幀數據類型的獲取,那麽接下來我們要實現觀察者的加入。
然後我們要在cpp/IDecode.h中聲明update方法,用於被觀察對象的數據更新:
那麽cpp/IDecode.cpp中就主要來實現這個被觀察者的數據更新方法update:
然後我們被觀察的對象需要有添加觀察者和通知所有觀察者的方法的實現:cpp/IObserver.cpp:
另外需要説明的是,在上篇實現了幀數據的音視頻區分,則這裏在cpp/FFDecode.cpp中打開方法open中也可以進行針對性的處理了:
雷電4開起來吧:
#include <string>
#include "FFDemux.h"
#include "XLog.h"
#include "FFDecode.h"
class TestObs:public IObserver
{
public:
void Update(XData d)
{
//XLOGI("TestObs Update data size is %d",d.size);
}
};
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_example_xplay_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
//XLOGI("S begin!");
//XSleep(3000);
//XLOGI("S end!");
//return env->NewStringUTF(hello.c_str());
///////////////////////////////////
///测试用代码
TestObs *tobs = new TestObs();
IDemux *de = new FFDemux();
//de->AddObs(tobs);
de->Open("/sdcard/1080.mp4");
IDecode *vdecode = new FFDecode();
vdecode->Open(de->GetVPara());
IDecode *adecode = new FFDecode();
adecode->Open(de->GetAPara());
de->AddObs(vdecode);
de->AddObs(adecode);
//vdecode->Open();
de->Start();
vdecode->Start();
adecode->Start();
//XSleep(3000);
//de->Stop();
/*for(;;)
{
XData d = de->Read();
XLOGI("Read data size is %d",d.size);
}*/
return env->NewStringUTF(hello.c_str());
}
#define XPLAY_IDECODE_H
#include "XParameter.h"
#include "IObserver.h"
#include <list>
//解码接口,支持硬解码
class IDecode:public IObserver
{
public:
//打开解码器
virtual bool Open(XParameter para) = 0;
//future模型 发送数据到线程解码
virtual bool SendPacket(XData pkt) = 0;
//从线程中获取解码结果 再次调用会复用上次空间,线程不安全
virtual XData RecvFrame() = 0;
//由主体notify的数据 阻塞
virtual void Update(XData pkt);
bool isAudio = false;
//最大的队列缓冲
int maxList = 100;
protected:
virtual void Main();
//读取缓冲
std::list<XData> packs;
std::mutex packsMutex;
};
#endif //XPLAY_IDECODE_H
#include "XLog.h"
//由主体notify的数据
void IDecode::Update(XData pkt)
{
if(pkt.isAudio != isAudio)
{
return;
}
while (!isExit)
{
packsMutex.lock();
//阻塞
if(packs.size() < maxList)
{
//生产者
packs.push_back(pkt);
packsMutex.unlock();
break;
}
packsMutex.unlock();
XSleep(1);
}
}
void IDecode::Main()
{
while(!isExit)
{
packsMutex.lock();
if(packs.empty())
{
packsMutex.unlock();
XSleep(1);
continue;
}
//取出packet 消费者
XData pack = packs.front();
packs.pop_front();
//发送数据到解码线程,一个数据包,可能解码多个结果
if(this->SendPacket(pack))
{
while(!isExit)
{
//获取解码数据
XData frame = RecvFrame();
if(!frame.data) break;
//XLOGE("RecvFrame %d",frame.size);
//发送数据给观察者
this->Notify(frame);
}
}
pack.Drop();
packsMutex.unlock();
}
}
//主体函数 添加观察者
void IObserver::AddObs(IObserver *obs)
{
if(!obs)return;
mux.lock();
obss.push_back(obs);
mux.unlock();
}
//通知所有观察者
void IObserver::Notify(XData data)
{
mux.lock();
for(int i =0; i < obss.size(); i++)
{
obss[i]->Update(data);
}
mux.unlock();
}
{
#include <libavcodec/avcodec.h>
}
#include "FFDecode.h"
#include "XLog.h"
bool FFDecode::Open(XParameter para)
{
if(!para.para) return false;
AVCodecParameters *p = para.para;
//1 查找解码器
AVCodec *cd = avcodec_find_decoder(p->codec_id);
if(!cd)
{
XLOGE("avcodec_find_decoder %d failed!",p->codec_id);
return false;
}
XLOGI("avcodec_find_decoder success!");
//2 创建解码上下文,并复制参数
codec = avcodec_alloc_context3(cd);
avcodec_parameters_to_context(codec,p);
codec->thread_count = 8;
//3 打开解码器
int re = avcodec_open2(codec,0,0);
if(re != 0)
{
char buf[1024] = {0};
av_strerror(re,buf,sizeof(buf)-1);
XLOGE("%s",buf);
return false;
}
if(codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
this->isAudio = false;
}
else
{
this->isAudio = true;
}
XLOGI("avcodec_open2 success!");
return true;
}
bool FFDecode::SendPacket(XData pkt)
{
if(pkt.size<=0 || !pkt.data)return false;
if(!codec)
{
return false;
}
int re = avcodec_send_packet(codec,(AVPacket*)pkt.data);
if(re != 0)
{
return false;
}
return true;
}
//从线程中获取解码结果
XData FFDecode::RecvFrame()
{
if(!codec)
{
return XData();
}
if(!frame)
{
frame = av_frame_alloc();
}
int re = avcodec_receive_frame(codec,frame);
if(re != 0)
{
return XData();
}
XData d;
d.data = (unsigned char *)frame;
if(codec->codec_type == AVMEDIA_TYPE_VIDEO)
d.size = (frame->linesize[0] + frame->linesize[1] + frame->linesize[2])*frame->height;
else
//样本字节数 * 单通道样本数 * 通道数
d.size = av_get_bytes_per_sample((AVSampleFormat)frame->format)*frame->nb_samples*2;
return d;
}
关键字词:重構
相关文章
-
无相关信息