DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  4737 随笔 :: 2 文章 :: 542 评论 :: 1615万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

改demo程序,调用ffmpeg API,获取rtsp的音视频流,打印每一包的ts,验证是否同步。

运行环境是linux


//FFDecoder.h
#pragma once  
 
//#define __STDC_CONSTANT_MACROS
 
extern "C" {  
#include "libavcodec/avcodec.h"  
#include "libavformat/avformat.h"  
#include "libavutil/avutil.h"   
#include "libavutil/opt.h"  
#include "libswscale/swscale.h"  
}  
 
#pragma comment(lib,"avutil.lib")  
#pragma comment(lib,"avformat.lib")  
#pragma comment(lib,"swresample.lib")  
#pragma comment(lib,"avcodec.lib")  
#pragma comment(lib,"swscale.lib")  
 
 
class CFFDecoder  
{  
public:  
    CFFDecoder();  
    virtual ~CFFDecoder();  
 
    int                 OpenFile(const char *pFilePath);  
    int                 GetMediaInfo(int &nFrameW,int &nFrameH);  
    int                 GetOneFrame(AVFrame *pFrame);  
 
private:  
    AVFormatContext     *m_pFormatCxt; 
 
    AVCodecContext      *m_pCodecCtx;  
    AVCodec             *m_pCodec;  
 
    AVCodecContext      *m_pACodecCtx;  
    AVCodec             *m_pACodec;  
 
    AVPacket            m_Packet;  
    int                 m_nVideoIndex;  
    int                 m_nAudioIndex;  
 
    double                m_nLastAudioPTS;
    double                m_nLastVideoPTS;
    double                m_nStartAudioTS;
    double                m_nStartVideoTS;
};  

//FFDecoder.cpp
#include "FFDecoder.h"  
 
CFFDecoder::CFFDecoder()  
{  
    m_pFormatCxt = avformat_alloc_context();  
    m_pCodecCtx = NULL;  
    m_pCodec = NULL;  
    m_nVideoIndex = -1;  
    m_nAudioIndex = -1;  
    m_nLastAudioPTS = -1;
    m_nLastVideoPTS = -1;
    m_nStartAudioTS = -1;
    m_nStartVideoTS = -1;
}  
 
CFFDecoder::~CFFDecoder()  
{  
 
}  
 
int CFFDecoder::OpenFile(const char *pFilePath)  
{  
    av_register_all();  
 
    if(avformat_open_input(&m_pFormatCxt,pFilePath,NULL,NULL)<0)  
    {  
        return -1;  
    }  
 
    if (avformat_find_stream_info(m_pFormatCxt,NULL)<0)  
    {  
        return -2;  
    }  
 
    //找到音视频对应的流通道  
 
    for (int i=0;i<m_pFormatCxt->nb_streams;i++)  
    {  
        if (m_pFormatCxt->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)  
        {  
            m_nVideoIndex = i;  
        }  
        else if (m_pFormatCxt->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)  
        {  
            m_nAudioIndex = i;  
        }  
    }  
 
    if (m_nVideoIndex == -1)  
    {  
        return -3;  
    }  
 
    //打开相应的解码器  
    m_pCodecCtx = m_pFormatCxt->streams[m_nVideoIndex]->codec;  
    m_pCodec = avcodec_find_decoder(m_pCodecCtx->codec_id);;  
    if(m_pCodec==NULL){    
        return -4;    
    }  
 
    if(avcodec_open2(m_pCodecCtx, m_pCodec,NULL)<0){  
        return -5;  
    }  
 
    //打开相应的解码器  
    m_pACodecCtx = m_pFormatCxt->streams[m_nAudioIndex]->codec;  
    m_pACodec = avcodec_find_decoder(m_pACodecCtx->codec_id);;  
    if(m_pACodec==NULL){    
        return -4;    
    }  
 
    if(avcodec_open2(m_pACodecCtx, m_pACodec,NULL)<0){  
        return -5;  
    }  
    
    m_nStartVideoTS = m_pFormatCxt->streams[m_nVideoIndex]->start_time;
    m_nStartAudioTS = m_pFormatCxt->streams[m_nAudioIndex]->start_time;
 
    return 0;  
}  
 
int CFFDecoder::GetMediaInfo(int &nFrameW,int &nFrameH)  
{  
    if(m_pCodecCtx==NULL)  
        return -1;  
 
    nFrameW = m_pCodecCtx->width;  
    nFrameH = m_pCodecCtx->height;  
    return 0;  
}  
 
int CFFDecoder::GetOneFrame(AVFrame *pFrame)  
{  
    if(m_pFormatCxt==NULL)  
        return 0;  
 
    int nGotPicture=-1;  
 
    if(av_read_frame(m_pFormatCxt,&m_Packet)>=0)  
    {  
        //判断是否为当前视频流中的包  
        if (m_Packet.stream_index == m_nVideoIndex)  
        {  
            //printf("video pts = %ld  dts=%ld  ---  pts=%ld  dur=%ld\n",
            //    m_Packet.pts,m_Packet.dts,
            //    m_Packet.pts*av_q2d(m_pFormatCxt->streams[m_nVideoIndex]->time_base),
            //    m_Packet.pts-m_nLastVideoPTS);
            double pts = m_Packet.pts/90;
            double dts = m_Packet.dts/90;
            double nDur = pts-m_nLastVideoPTS;
            //m_nStartVideoTS = m_pFormatCxt->streams[m_nVideoIndex]->start_time;
 
            //long pts2 = m_Packet.pts*av_q2d(m_pFormatCxt->streams[m_nVideoIndex]->time_base);
            printf("video pts = %.02f  dts=%.02f   ---  dur=%.02f\n",
                pts,
                dts,
                nDur);
            
            m_nLastVideoPTS = pts;
 
            int nLen = avcodec_decode_video2(m_pCodecCtx,pFrame,&nGotPicture,&m_Packet);  
            if (nLen<0)  
            {  
                return 0;  
            }  
 
            if (nGotPicture)  
            {  
                //成功得到一帧数据  
                //long pts = av_frame_get_best_effort_timestamp(pFrame);
                //printf("after decoder video pts=%ld\n",(pts)/90);
                //m_nLastVideoPTS = (pts)/90;
                return nLen;  
            }  
        }
        else if (m_nAudioIndex == m_Packet.stream_index)
        {
            AVRational tb;
            tb.den = 8000;
            tb.num = 1;
 
            double pts = (m_Packet.pts)/8;
            double dts = m_Packet.dts/8;
            double nDur = pts-m_nLastAudioPTS;
            //long lpts3 = av_rescale_q(pts,m_pFormatCxt->streams[m_nAudioIndex]->time_base,tb);
            //long pts2 = pts*av_q2d(m_pFormatCxt->streams[m_nAudioIndex]->time_base);
            printf("audio pts = %.02f  dts=%.02f   ---  dur=%.02f\n",
                pts,
                dts,
                nDur);
 
            m_nLastAudioPTS = pts;
            //av_rescale_q_rnd(m_Packet.pts,  m_pFormatCxt->streams[m_nAudioIndex]->time_base,  m_pFormatCxt->streams[m_nAudioIndex]->time_base, AV_ROUND_NEAR_INF));
            
            int ret = avcodec_decode_audio4(m_pACodecCtx, pFrame, &nGotPicture, &m_Packet);
            if (nGotPicture) {
                //AVRational tb;
                //tb.den = pFrame->sample_rate;
                //tb.num = 1;
 
                //if (m_nLastAudioPTS != AV_NOPTS_VALUE)
                //    m_nLastAudioPTS = av_rescale_q(pFrame->pts, m_pCodecCtx->time_base, tb);
                //else if (pFrame->pkt_pts != AV_NOPTS_VALUE)
                //    m_nLastAudioPTS = av_rescale_q(pFrame->pkt_pts, av_codec_get_pkt_timebase(m_pCodecCtx), tb);
 
                //printf("after decoder audio pts=%ld\n",m_nLastAudioPTS);
            }
        }
 
        printf("v.ts(%.02f) - a.ts(%.02f) = %.02f\n",m_nLastVideoPTS,m_nLastAudioPTS,m_nLastVideoPTS - m_nLastAudioPTS);
        
        /*time_t now;
        struct tm *timenow;
        time(&now);
        timenow = localtime(&now);
        printf(">>>>  now time is %s <<<<\n",asctime(timenow));*/
        
        time_t timer;
        struct tm *t_tm;
        time(&timer);
        t_tm = localtime(&timer);
        printf("now time is %4d-%02d-%02d %02d:%02d:%02d\n",
        t_tm->tm_year+1900,
        t_tm->tm_mon,
        t_tm->tm_mday,
        t_tm->tm_hour,
        t_tm->tm_min,
        t_tm->tm_sec);
        
        //printf("a.ts - v.ts = %d\n",m_nLastAudioPTS - m_nLastVideoPTS);
    }  
 
        av_free_packet(&m_Packet);
    return 0;  
}  

主函数
// FFmpegTest.cpp : 定义控制台应用程序的入口点。
//
#include "FFDecoder.h"
 
 
int main(int argc, char **argv)
{
    if(argc!=2)
    {
        printf("err arg.  exe rtsp://...\n");
        return 0;
    }
 
    char szRTSPUrl[256]={0};
    strcpy(szRTSPUrl,argv[1]);
    printf("rtsp url = %s\n",szRTSPUrl);
    
    CFFDecoder dec;
    dec.OpenFile(szRTSPUrl); 
 
    AVFrame *pFrame=av_frame_alloc();  
    while(1)  
    {  
        if(dec.GetOneFrame(pFrame)>0)  
        {  
             //printf("pts=%lld\n",pFrame->pkt_dts);
        }  
    }  
 
    system("pause");
    return 0;
}

编译脚本:
g++ -o ffts *.cpp -I/usr/local/include/ -I./ -D__STDC_CONSTANT_MACROS -L/usr/local/lib/ -lavcodec -lavdevice -lavformat -lavfilter -lswscale

posted on   DoubleLi  阅读(567)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
历史上的今天:
2021-01-21 inux top命令的用法详细详解
2021-01-21 mysql占用CPU超过100%解决过程
2019-01-21 vld for memory leak detector (release version)
2019-01-21 在Release版本下使用VLD
2015-01-21 CURL 和LIBCURL C++代码 上传本地文件,好不容易碰到了这种折腾我几天的代码
2014-01-21 VS2008调试技巧收集备用
2013-01-21 c++读写文件和测试程序运行时间的例子
点击右上角即可分享
微信分享提示