您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
12. 读取媒体帧数据获取类型信息(音频、视频)存入XData~1
发布时间:2021-06-09 18:16:42编辑:雪饮阅读()
#include "XLog.h"
extern "C"{
#include <libavformat/avformat.h>
}
//打开文件,或者流媒体 rmtp http rtsp
bool FFDemux::Open(const char *url)
{
XLOGI("Open file %s begin",url);
int re = avformat_open_input(&ic,url,0,0);
if(re != 0 )
{
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 )
{
char buf[1024] = {0};
av_strerror(re,buf,sizeof(buf));
XLOGE("avformat_find_stream_info %s failed!",url);
return false;
}
//ffmpeg内部的時間單位是微秒,AVFormatContext =》duration的單位是AV_TIME_BASE
this->totalMs = ic->duration/(AV_TIME_BASE/1000);
XLOGI("total ms = %d!",totalMs);
GetVPara();
GetAPara();
return true;
}
//获取视频参数
XParameter FFDemux::GetVPara()
{
if (!ic) {
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) {
XLOGE("av_find_best_stream failed!");
return XParameter();
}
videoStream=re;
XParameter para;
para.para = ic->streams[re]->codecpar;
return para;
}
//获取音频参数
XParameter FFDemux::GetAPara()
{
if (!ic) {
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) {
XLOGE("av_find_best_stream failed!");
return XParameter();
}
audioStream=re;
XParameter para;
para.para = ic->streams[re]->codecpar;
return para;
}
//读取一帧数据,数据由调用者清理
XData FFDemux::Read()
{
if(!ic)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);
return XData();
}
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:
派生类FFDemux中对GetVPara和GetAPara的声明尤其需要注意,不能像是基类那样直接纯虚函数,这里可以是虚函数,但绝对不能是纯虚函数,否则会在入口native-lib.cpp入口中new这个派生类的时候由于纯虚函数会引发如下错误:
#define XPLAY_IDEMUX_H
#include "XData.h"
#include "XThread.h"
#include "IObserver.h"
#include "XParameter.h"
//解封装接口
class IDemux: public IObserver {
public:
//打开文件,或者流媒体 rmtp http rtsp
virtual bool Open(const char *url) = 0;
//获取视频参数没加的话。。virtual声明的是虚函数。。然后加个0声明的是纯虚函数。。。两个不一样的。。
virtual XParameter GetVPara() = 0;
//获取音频参数
virtual XParameter GetAPara()=0;
//读取一帧数据,数据由调用者清理
virtual XData Read() = 0;
//总时长(毫秒)
int totalMs = 0;
protected:
virtual void Main();
};
#endif //XPLAY_IDEMUX_H
#define XPLAY_FFDEMUX_H
#include "IDemux.h"
struct AVFormatContext;
class FFDemux: public IDemux {
public:
//打开文件,或者流媒体 rmtp http rtsp
virtual bool Open(const char *url);
/*
*注意:
* 这里FFDemux继承自IDemux,而IDemux中GetVPara和GetAPara都是纯虚函数,那么在派生类中这两个函数就不能为纯虚函数,否则例如在入口native-lib.cpp中若要new这个FFDemux就会new失败
* 会抛出错误如:allocating an object of abstract class type 'FFDemux'
* */
//获取视频参数
virtual XParameter GetVPara();
//获取音频参数
virtual XParameter GetAPara();
//读取一帧数据,数据由调用者清理
virtual XData Read();
FFDemux();
private:
AVFormatContext *ic = 0;
int audioStream=1;
int videoStream=0;
};
#endif //XPLAY_FFDEMUX_H
#define XPLAY_XDATA_H
struct XData {
unsigned char *data = 0;
int size = 0;
bool isAudio=false;
void Drop();
};
#endif //XPLAY_XDATA_H
关键字词:XData
相关文章
-
无相关信息