您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
6. IDemux&FFdemux线程安全和Close清理函数编写~1
发布时间:2021-06-13 13:48:33编辑:雪饮阅读()
爲了綫程安全,這裏要在cpp/FFDemux.cpp中加上同步鎖:
#include "FFDemux.h"
#include "XLog.h"
extern "C"{
#include <libavformat/avformat.h>
}
//分数转为浮点数
static double r2d(AVRational r)
{
return r.num == 0 || r.den == 0 ?0.:(double) r.num/(double)r.den;
}
void FFDemux::Close()
{
mux.lock();
if(ic)
avformat_close_input(&ic);
mux.unlock();
}
//打开文件,或者流媒体 rmtp http rtsp
bool FFDemux::Open(const char *url)
{
XLOGI("Open file %s begin",url);
Close();
mux.lock();
int re = avformat_open_input(&ic,url,0,0);
if(re != 0 )
{
mux.unlock();
char buf[1024] = {0};
av_strerror(re,buf,sizeof(buf));
XLOGE("FFDemux open %s failed!",url);
return false;
}
XLOGI("FFDemux open %s success!",url);
//读取文件信息
re = avformat_find_stream_info(ic,0);
if(re != 0 )
{
mux.unlock();
char buf[1024] = {0};
av_strerror(re,buf,sizeof(buf));
XLOGE("avformat_find_stream_info %s failed!",url);
return false;
}
this->totalMs = ic->duration/(AV_TIME_BASE/1000);
mux.unlock();
XLOGI("total ms = %d!",totalMs);
GetVPara();
GetAPara();
return true;
}
//获取视频参数
XParameter FFDemux::GetVPara()
{
mux.lock();
if (!ic) {
mux.unlock();
XLOGE("GetVPara failed! ic is NULL!");
return XParameter();
}
//获取了视频流索引
int re = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);
if (re < 0) {
mux.unlock();
XLOGE("av_find_best_stream failed!");
return XParameter();
}
videoStream = re;
XParameter para;
para.para = ic->streams[re]->codecpar;
mux.unlock();
return para;
}
//获取音频参数
XParameter FFDemux::GetAPara()
{
mux.lock();
if (!ic) {
mux.unlock();
XLOGE("GetVPara failed! ic is NULL!");
return XParameter();
}
//获取了音频流索引
int re = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0);
if (re < 0) {
mux.unlock();
XLOGE("av_find_best_stream failed!");
return XParameter();
}
audioStream = re;
XParameter para;
para.para = ic->streams[re]->codecpar;
para.channels = ic->streams[re]->codecpar->channels;
para.sample_rate = ic->streams[re]->codecpar->sample_rate;
mux.unlock();
return para;
}
//读取一帧数据,数据由调用者清理
XData FFDemux::Read()
{
mux.lock();
if(!ic)
{
mux.unlock();
return XData();
}
XData d;
AVPacket *pkt = av_packet_alloc();
int re = av_read_frame(ic,pkt);
if(re != 0)
{
av_packet_free(&pkt);
return XData();
}
//XLOGI("pack size is %d ptss %lld",pkt->size,pkt->pts);
d.data = (unsigned char*)pkt;
d.size = pkt->size;
if(pkt->stream_index == audioStream)
{
d.isAudio = true;
}
else if(pkt->stream_index == videoStream)
{
d.isAudio = false;
}
else
{
av_packet_free(&pkt);
mux.unlock();
return XData();
}
//转换pts
pkt->pts = pkt->pts * (1000*r2d(ic->streams[pkt->stream_index]->time_base));
pkt->dts = pkt->dts * (1000*r2d(ic->streams[pkt->stream_index]->time_base));
d.pts = (int)pkt->pts;
//XLOGE("demux pts %d",d.pts);
mux.unlock();
return d;
}
FFDemux::FFDemux()
{
static bool isFirst = true;
if(isFirst)
{
isFirst = false;
//注册所有封装器
av_register_all();
//注册所有的解码器
avcodec_register_all();
//初始化网络
avformat_network_init();
XLOGI("register ffmpeg!");
}
}
#include "XLog.h"
extern "C"{
#include <libavformat/avformat.h>
}
//分数转为浮点数
static double r2d(AVRational r)
{
return r.num == 0 || r.den == 0 ?0.:(double) r.num/(double)r.den;
}
void FFDemux::Close()
{
mux.lock();
if(ic)
avformat_close_input(&ic);
mux.unlock();
}
//打开文件,或者流媒体 rmtp http rtsp
bool FFDemux::Open(const char *url)
{
XLOGI("Open file %s begin",url);
Close();
mux.lock();
int re = avformat_open_input(&ic,url,0,0);
if(re != 0 )
{
mux.unlock();
char buf[1024] = {0};
av_strerror(re,buf,sizeof(buf));
XLOGE("FFDemux open %s failed!",url);
return false;
}
XLOGI("FFDemux open %s success!",url);
//读取文件信息
re = avformat_find_stream_info(ic,0);
if(re != 0 )
{
mux.unlock();
char buf[1024] = {0};
av_strerror(re,buf,sizeof(buf));
XLOGE("avformat_find_stream_info %s failed!",url);
return false;
}
this->totalMs = ic->duration/(AV_TIME_BASE/1000);
mux.unlock();
XLOGI("total ms = %d!",totalMs);
GetVPara();
GetAPara();
return true;
}
//获取视频参数
XParameter FFDemux::GetVPara()
{
mux.lock();
if (!ic) {
mux.unlock();
XLOGE("GetVPara failed! ic is NULL!");
return XParameter();
}
//获取了视频流索引
int re = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);
if (re < 0) {
mux.unlock();
XLOGE("av_find_best_stream failed!");
return XParameter();
}
videoStream = re;
XParameter para;
para.para = ic->streams[re]->codecpar;
mux.unlock();
return para;
}
//获取音频参数
XParameter FFDemux::GetAPara()
{
mux.lock();
if (!ic) {
mux.unlock();
XLOGE("GetVPara failed! ic is NULL!");
return XParameter();
}
//获取了音频流索引
int re = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0);
if (re < 0) {
mux.unlock();
XLOGE("av_find_best_stream failed!");
return XParameter();
}
audioStream = re;
XParameter para;
para.para = ic->streams[re]->codecpar;
para.channels = ic->streams[re]->codecpar->channels;
para.sample_rate = ic->streams[re]->codecpar->sample_rate;
mux.unlock();
return para;
}
//读取一帧数据,数据由调用者清理
XData FFDemux::Read()
{
mux.lock();
if(!ic)
{
mux.unlock();
return XData();
}
XData d;
AVPacket *pkt = av_packet_alloc();
int re = av_read_frame(ic,pkt);
if(re != 0)
{
av_packet_free(&pkt);
return XData();
}
//XLOGI("pack size is %d ptss %lld",pkt->size,pkt->pts);
d.data = (unsigned char*)pkt;
d.size = pkt->size;
if(pkt->stream_index == audioStream)
{
d.isAudio = true;
}
else if(pkt->stream_index == videoStream)
{
d.isAudio = false;
}
else
{
av_packet_free(&pkt);
mux.unlock();
return XData();
}
//转换pts
pkt->pts = pkt->pts * (1000*r2d(ic->streams[pkt->stream_index]->time_base));
pkt->dts = pkt->dts * (1000*r2d(ic->streams[pkt->stream_index]->time_base));
d.pts = (int)pkt->pts;
//XLOGE("demux pts %d",d.pts);
mux.unlock();
return d;
}
FFDemux::FFDemux()
{
static bool isFirst = true;
if(isFirst)
{
isFirst = false;
//注册所有封装器
av_register_all();
//注册所有的解码器
avcodec_register_all();
//初始化网络
avformat_network_init();
XLOGI("register ffmpeg!");
}
}
然後同樣的需要在cpp/FFDemux.h中進行對應聲明:
這根本就是在送錢嘛,一切都是這麽美好。
#define XPLAY_FFDEMUX_H
#include "IDemux.h"
#include <mutex>
struct AVFormatContext;
class FFDemux: public IDemux {
public:
//打开文件,或者流媒体 rmtp http rtsp
virtual bool Open(const char *url);
virtual void Close();
//获取视频参数
virtual XParameter GetVPara();
//获取音频参数
virtual XParameter GetAPara();
//读取一帧数据,数据由调用者清理
virtual XData Read();
FFDemux();
private:
AVFormatContext *ic = 0;
std::mutex mux;
int audioStream = 1;
int videoStream = 0;
};
#endif //XPLAY_FFDEMUX_H
关键字词:FFdemux