[DEMO] ES格式文件读取

performance.h

#ifndef PERFORMANCE_TOOL
#define PERFORMANCE_TOOL

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <thread>
#include <memory>
#include <time.h>
#include <signal.h>
#include <mutex>
#include <condition_variable>
#include <list>
#include <utility>


#ifndef DEBUG_PERFTOOL
#define DEBUG_PERFTOOL
#endif

#define THREAD_WORK



//------------ MyTimer start -----------
#ifndef MYTIMER
#define MYTIMER
template <typename T>
class MyTimer
{
public:
    typedef void (*TimerHandler)(union sigval);
public:
    MyTimer();
    ~MyTimer();
    void Init(bool triggeronstart,long long interval,TimerHandler routine,T* routineArgs,std::string desc);
    void Delete();

public:
    std::string m_desc;

private:
    TimerHandler m_routine;
    bool m_triggerOnStart = false;
    long long m_interval;	 //ms
    timer_t m_timerid;
    T* m_routineArgs;
};

template <typename T>
MyTimer<T>::MyTimer()
{

}

template <typename T>
MyTimer<T>::~MyTimer()
{

}

template <typename T>
void MyTimer<T>::Init(bool triggeronstart,long long interval,TimerHandler routine,T* routineArgs,std::string desc)
{
    m_triggerOnStart = triggeronstart;
    m_interval = interval;
    m_routine = routine;
    m_routineArgs = routineArgs;
    m_desc = desc;

    int ret = 0;
    struct sigevent sev;
    memset(&sev, 0, sizeof(struct sigevent));
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = m_routine;
    sev.sigev_value.sival_ptr = m_routineArgs;
    ret = timer_create(CLOCK_REALTIME,&sev,&m_timerid);
    if(0!=ret){
        return;
    }

    struct itimerspec its;
    its.it_interval.tv_sec = m_interval/1000;
    its.it_interval.tv_nsec = (m_interval%1000)*1000000;
    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = 1;

    ret = timer_settime(m_timerid, 0, &its, NULL);
    if(0!=ret){
        return;
    }
}

template <typename T>
void MyTimer<T>::Delete()
{
    timer_delete(m_timerid);
}
#endif
//------------ MyTimer end -----------


//EsFile Dump Usage (not in use)
class EsDump{
public:
    EsDump(const std::string filepath);
    ~EsDump();
    int64_t dumpVideo(uint8_t * data,int64_t len,int pts);
private:
    FILE* m_fp = NULL;
    int64_t m_cnt=0;
};


//EsFile Parse Usage
class EsFileRead{
public:
    EsFileRead()=default;
    ~EsFileRead();
    bool openFile(const std::string filepath);
    void closeFile();
    bool readOneFrame(int64_t* offset1,int64_t* offset2);
    void getData(int64_t offset1,int64_t offset2,unsigned char *dest,int64_t* size);
    unsigned char* peekData(int64_t offset)const;
    bool isEnd(){
        return m_end;
    }

private:
    int64_t findTag();

private:
    int m_fd=-1; //esfile fd
    unsigned char* m_data; //esfile data start addr
    struct stat m_fileinfo; //esfile info, eg. file size
    int64_t m_offset=0; //current offset
    int64_t m_idroffset=-1; //idr offset
    bool m_findingEndTag=false; //if is finding frame end
    bool m_end=false;//if reach file end
};


class EsFilePlayer
{
public:
    enum CODEC_TYPE{
        H264,
        CNT
    };

public:
    EsFilePlayer();
    ~EsFilePlayer();

    void Open(const std::string filepath,const CODEC_TYPE type,
                const int width,const int height,const int fps,void *wnd);		//open and set up espp
    void Close();		//close espp
    void Start();		//start render
    void Stop();		//stop render

private:
    static void workloop(void* param);
    static void timeout(union sigval param);

private:
    CODEC_TYPE m_codec;		//which codec to use
    int m_fps;				//fps of input file
    std::thread m_workloop; //prepare timer && supply thread for timeout callback func
    EsFileRead m_efr;
    bool m_needstop=false;
    MyTimer<EsFilePlayer> m_timer;
    std::mutex m_mut;
    std::condition_variable m_cond;
    std::list<std::pair<int64_t,int64_t> > m_frameaddr;
};

#endif

performance.cpp

#include "performance.h"
#include "log.hpp"

//------------ EsDump start ------------
EsDump::EsDump(const std::string filepath)
{
    m_fp = fopen(filepath.c_str(),"w+");
    if(NULL!=m_fp){
        setvbuf(m_fp,NULL,_IONBF,0);
    }
}

EsDump::~EsDump()
{
    if(NULL!=m_fp){
        fclose(m_fp);
        m_fp=NULL;
    }
}

int64_t EsDump::dumpVideo(uint8_t * data,int64_t len,int pts)
{
    if(NULL!=m_fp){
        int64_t nbytes = fwrite(data,1,len,m_fp);
        m_cnt+=nbytes;
        return nbytes;
    }else{
        return -1;
    }
}
//------------ EsDump end ------------



//------------ EsFileRead start ------------
EsFileRead::~EsFileRead()
{
    closeFile();
}

bool EsFileRead::openFile(const std::string filepath)
{
    if(-1 != m_fd){
        return true;
    }else{
        m_fd = open(filepath.c_str(),O_RDONLY);
        if(-1==m_fd){
            LOG(ERROR) << "file open error";
            return false;
        }
        if(-1==fstat(m_fd,&m_fileinfo)){
            LOG(ERROR) << "get file size error";
            return false;
        }
        m_data = (unsigned char*)mmap(NULL,m_fileinfo.st_size,PROT_READ,MAP_PRIVATE,m_fd,0);
        if(MAP_FAILED == m_data){
            LOG(ERROR) << "map file error";
            return false;
        }
        LOG(INFO) << "file size : "<<m_fileinfo.st_size;
        return true;
    }
}

void EsFileRead::closeFile()
{
    if(NULL!=m_data){
        munmap(m_data,m_fileinfo.st_size);
    }

    if(-1!=m_fd){
        close(m_fd);
    }

    m_fd=-1;
    m_data=NULL;
    memset(&m_fileinfo,0,sizeof(m_fileinfo));
    m_offset=0;
    m_idroffset=-1;
    m_findingEndTag=false;
    m_end=true;
}

int64_t EsFileRead::findTag()
{
    if(m_offset <= 0){
        m_offset=0;
    }

    if(m_offset >= m_fileinfo.st_size-1){
		m_end = true;
        m_offset = m_fileinfo.st_size;
        return m_offset;
    }

	//startcg_debug_log("-----> %02x,%02x,%02x,%02x,%02x",m_data[m_offset],m_data[m_offset+1],m_data[m_offset+2],m_data[m_offset+3],m_data[m_offset+4]);


	if(m_data[m_offset] != 0x00 || m_data[m_offset+1]!=0x00 || m_data[m_offset+2] != 0x00 || m_data[m_offset+3] != 0x01){	//not found,steop 1 byte
		m_offset++;
		findTag();
	}else{	//if 00 00 00 01, found nalu
        //start of frame
        if(!m_findingEndTag && (m_data[m_offset+4] == 0x67 || m_data[m_offset+4] == 0x68 || m_data[m_offset+4] == 0x65)){	//found , idr frame
            //only find start can enter , found 65 67 or 68
            if(m_idroffset==-1){
            	//record first position of idr frame
                m_idroffset = m_offset;
            }
            m_offset++;
            findTag();;
        }
    }

	return m_offset;
}

void EsFileRead::getData(int64_t offset1,int64_t offset2,unsigned char *dest,int64_t* size)
{
    int64_t _size = offset2 - offset1;
    *size = _size;
    memcpy(dest,&m_data[offset1],_size);
}

unsigned char* EsFileRead::peekData(int64_t offset)const
{
    return &m_data[offset];
}

bool EsFileRead::readOneFrame(int64_t* offset1,int64_t* offset2)
{
    long offset_1 = 0;
    long offset_2 = 0;

    //find start tag
    m_findingEndTag=false;
	offset_1 = findTag();
	
	//find end tag
    if(-1!=m_idroffset){	//if idr frame , use m_offset as end tag
        *offset1 = m_idroffset;
        *offset2 = offset_1 - 1; //position of findTag() return is the first 00 of 00 00 00 01, so minus 1 is the end of frame
    }else{					//if not idr frame , find next 
        m_findingEndTag=true;
        m_offset++;
        offset_2 = findTag();
        *offset1 = offset_1;
        *offset2 = offset_2 - 1;
    }

    m_idroffset=-1;
	
	return true;
}

//------------ EsFileRead end ------------


//------------ EsFilePlayer start ------------

EsFilePlayer::EsFilePlayer(){

}

EsFilePlayer::~EsFilePlayer(){

}

void EsFilePlayer::Open(const std::string filepath,const CODEC_TYPE type,
    const int width,const int height,const int fps,void *wnd)
{
    bool bret=false;
    //1.set up esfilereader
    bret = m_efr.openFile(filepath);
    if(!bret){
        return;
    }
    LOG(INFO) << "file opened";
    m_fps = fps;
}

void EsFilePlayer::Close()
{

}

void EsFilePlayer::Start()
{

#ifdef THREAD_WORK
    //create thread
    std::thread tmp(workloop,this);
    m_workloop = std::move(tmp);
    m_workloop.detach();

#else
    //parse file
    int64_t offset1,offset2;
    while(!m_efr.isEnd()){
        offset1=0;
        offset2=0;
        pins->m_efr.readOneFrame(&offset1,&offset2);
        //LOG(INFO) << "start :"<<offset1<<" end:"<<offset2;
        std::pair<int64_t,int64_t> tmp(offset1,offset2);
        pins->m_frameaddr.push_back(tmp);
    }

    //dump file (for test)
    #ifdef DEBUG_PERFTOOL
    std::list<std::pair<int64_t,int64_t> >::iterator it;
    for(it=m_frameaddr.begin();it!=m_frameaddr.end();it++){
        int64_t off1,off2;
        std::pair<int64_t,int64_t> p = *it;
        off1=p.first;
        off2=p.second;
    }
    #endif
    */


    //start timer
    int interval = (int)(1000/m_fps);
    m_timer.Init(true,interval,timeout,this," 1000/fps ms send one frame");
#endif

    return;
}

void EsFilePlayer::Stop()
{
    //stop timer
    m_timer.Delete();

    //stop thread
    std::unique_lock<std::mutex> lg(m_mut);
    m_needstop=true;
    m_cond.notify_all();

    return;
}

void EsFilePlayer::workloop(void* param)
{
    EsFilePlayer* pins = (EsFilePlayer*)param;
    if(!pins){
        return;
    }

    //wait for end thread condition (not in use)
    //std::unique_lock<std::mutex> lg(pins->m_mut);
    //pins->m_cond.wait(lg,[&]{return pins->m_needstop;});

    //start parse esfile (parse in workloop thread cause readoneFrame work slowly,why?)
    LOG(INFO) << "parse file start";
    int64_t offset1,offset2;
    while(!pins->m_efr.isEnd()){
        offset1=0;
        offset2=0;
        pins->m_efr.readOneFrame(&offset1,&offset2);
        std::pair<int64_t,int64_t> tmp(offset1,offset2);
        pins->m_frameaddr.push_back(tmp);
    }
    LOG(INFO) << "parse file end";

    #ifdef DEBUG_PERFTOOL
    std::list<std::pair<int64_t,int64_t> >::iterator it;
    for(it=pins->m_frameaddr.begin();it!=pins->m_frameaddr.end();it++){
        int64_t off1,off2;
        std::pair<int64_t,int64_t> p = *it;
        off1=p.first;
        off2=p.second;
        LOG(INFO) << "start :"<<off1<<" end:"<<off2;
    }
    #endif

    //start timer
    int interval = (int)(1000/pins->m_fps);
    pins->m_timer.Init(true,interval,timeout,pins," 1000/fps ms send one frame");

    return;
}

void EsFilePlayer::timeout(union sigval param)
{
    EsFilePlayer* pins = (EsFilePlayer*)param.sival_ptr;

    return;
}


//------------ EsFilePlayer end ------------




log.hpp

#ifndef LOGER_H
#define LOGER_H

#ifndef GLOG_NO_ABBREVIATED_SEVERITIES
#define GLOG_NO_ABBREVIATED_SEVERITIES
#endif

#include "glog/logging.h"
#include "glog/raw_logging.h"
#include "glog/log_severity.h"
#include <iostream>
#include <fstream>
#ifdef WIN32
#include <direct.h>
#else
#include <sys/stat.h>
#include <sys/types.h>
#endif

#ifdef WIN32
#define GLOG_FOLDER ".//LOG"
#define GLOG_INFO_PATH ".//LOG//info" //directory of INFO level log
#define GLOG_WARN_PATH ".//LOG//warn" //directory of WARNING level log
#define GLOG_ERROR_PATH ".//LOG//error"  //directory of ERROR level log
#define GLOG_FATAL_PATH ".//LOG//fatal" //directory of FATAL level log
#else
#define GLOG_FOLDER "./LOG"
#define GLOG_INFO_PATH "./LOG/info" //directory of INFO level log
#define GLOG_WARN_PATH "./LOG/warn" //directory of WARNING level log
#define GLOG_ERROR_PATH "./LOG/error"  //directory of ERROR level log
#define GLOG_FATAL_PATH "./LOG/fatal" //directory of FATAL level log
#endif


class Gloger
{
public:
    Gloger();
    Gloger(const char* program){
        google::InitGoogleLogging(program);
        createDirect(GLOG_FOLDER);

        google::SetLogDestination(google::GLOG_INFO,    GLOG_INFO_PATH);
        google::SetLogDestination(google::GLOG_WARNING, GLOG_WARN_PATH);
        google::SetLogDestination(google::GLOG_ERROR,   GLOG_ERROR_PATH);
        google::SetLogDestination(google::GLOG_FATAL,   GLOG_FATAL_PATH);

        FLAGS_logbufsecs = 0;
        FLAGS_max_log_size = 100;
        FLAGS_stop_logging_if_full_disk = true;
    }
    ~Gloger(void){
        google::ShutdownGoogleLogging();
    }


    int createDirect(const char * dirName)
    {
        std::fstream _file;
        _file.open(dirName,std::ios::in);

        if(!_file){
    #ifdef WIN32
            return _mkdir(dirName);
    #else
            return mkdir(dirName,S_IRWXU);
    #endif
        }
        else{
            return 0;
        }
    }
};

//usage
//Gloger* logger = new Gloger("appname");

#endif // LOGER_H

main.cpp

#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <thread>
#include "performance.h"
#include "log.hpp"

int main(int argc, char ** argv)
{
    Gloger loger(argv[0]);
    EsFilePlayer m_efp;

    m_efp.Open("/home/ubuntu/DumpVideo.es",EsFilePlayer::H264,1920,1080,60,NULL);
    m_efp.Start();

    while(1);
}

pro.pro

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt

HEADERS += performance.h \
    log.hpp

SOURCES += main.cpp \
    performance.cpp

LIBS += -lpthread -lglog -lrt

HEADERS += \
    performance.h

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值