ffmpeg解码RTSP/TCP视频流H.264(QT界面显示视频画面)

我用的ffmpeg版本为 ffmpeg-2.1.8.tar.bz2

版本低了恐怕有些头文件和API找不到。

在Linux下解压后编译,Linux下编译很简单,我这里生成的动态库:

./configure –enable-shared

make

就能找到各个so动态库文件。

移动位置后,记得手动链接 一下:

ln -s libavcodec.so.55 libavcodec.so
ln -s libavdevice.so.55 libavdevice.so
ln -s libavfilter.so.3 libavfilter.so
ln -s libavformat.so.55 libavformat.so
ln -s libavutil.so.52 libavutil.so
ln -s libswscale.so.2 libswscale.so

QT pro文件中记得加入:

INCLUDEPATH += ffmpeg/include

// windows下用这几个

win32: LIBS += ffmpeg/lib/libavcodec.dll.a ffmpeg/lib/libavfilter.dll.a ffmpeg/lib/libavformat.dll.a ffmpeg/lib/libswscale.dll.a ffmpeg/lib/libavutil.dll.a

// Linux下用这几个

LIBS += -lavcodec -lavdevice -lavfilter -lavformat -lavutil -lswscale -L./ffmpeg/so

我这里对外提供三个接口:

void VideoStream::setUrl(QString url)
{
    m_str_url = url;
}

void VideoStream::startStream()
{
    videoStreamIndex=-1;
    av_register_all();//注册库中所有可用的文件格式和解码器
    avformat_network_init();//初始化网络流格式,使用RTSP网络流时必须先执行
    pAVFormatContext = avformat_alloc_context();//申请一个AVFormatContext结构的内存,并进行简单初始化
    pAVFrame=av_frame_alloc();
    if (this->Init())
    {
        m_timerPlay->start();
    }
}
void VideoStream::stopStream()
{
    m_timerPlay->stop();

    avformat_free_context(pAVFormatContext);
    av_frame_free(&pAVFrame);
    sws_freeContext(pSwsContext);
}

里面与ffmpeg解码相关的私有变量:

    QMutex mutex;
    AVPicture  pAVPicture;
    AVFormatContext *pAVFormatContext;
    AVCodecContext *pAVCodecContext;
    AVFrame *pAVFrame;
    SwsContext * pSwsContext;
    AVPacket pAVPacket;

在QT里,用一个QLabel的对象来显示解码后的视频画面:

connect(this,SIGNAL(GetImage(QImage)),this,SLOT(SetImageSlots(QImage)));

...
void VideoStream::SetImageSlots(const QImage &image)
{
    if (image.height()>0){
        QPixmap pix = QPixmap::fromImage(image.scaled(m_i_w,m_i_h));
        m_label->setPixmap(pix);
    }
}

这里用的QTimer来进行一帧帧数据的解码,也可以用一个线程比如QThread来进行解码:

    m_timerPlay = new QTimer;
    m_timerPlay->setInterval(10);
    connect(m_timerPlay,SIGNAL(timeout()),this,SLOT(playSlots()));

    m_i_frameFinished = 0;

...
bool VideoStream::Init()
{
    if(m_str_url.isEmpty())
        return false;
    //打开视频流
    int result=avformat_open_input(&pAVFormatContext, m_str_url.toStdString().c_str(),NULL,NULL);
    if (result<0){
        qDebug()<<"打开视频流失败";
        return false;
    }

    //获取视频流信息
    result=avformat_find_stream_info(pAVFormatContext,NULL);
    if (result<0){
        qDebug()<<"获取视频流信息失败";
        return false;
    }

    //获取视频流索引
    videoStreamIndex = -1;
    for (uint i = 0; i < pAVFormatContext->nb_streams; i++) {
        if (pAVFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            break;
        }
    }

    if (videoStreamIndex==-1){
        qDebug()<<"获取视频流索引失败";
        return false;
    }

    //获取视频流的分辨率大小
    pAVCodecContext = pAVFormatContext->streams[videoStreamIndex]->codec;
    videoWidth=pAVCodecContext->width;
    videoHeight=pAVCodecContext->height;

    avpicture_alloc(&pAVPicture,PIX_FMT_RGB24,videoWidth,videoHeight);

    AVCodec *pAVCodec;

    //获取视频流解码器
    pAVCodec = avcodec_find_decoder(pAVCodecContext->codec_id);
    pSwsContext = sws_getContext(videoWidth,videoHeight,PIX_FMT_YUV420P,videoWidth,videoHeight,PIX_FMT_RGB24,SWS_BICUBIC,0,0,0);

    //打开对应解码器
    result=avcodec_open2(pAVCodecContext,pAVCodec,NULL);
    if (result<0){
        qDebug()<<"打开解码器失败";
        return false;
    }

    qDebug()<<"初始化视频流成功";
    return true;
}

void VideoStream::playSlots()
{
    //一帧一帧读取视频
    if (av_read_frame(pAVFormatContext, &pAVPacket) >= 0){
        if(pAVPacket.stream_index==videoStreamIndex){
            qDebug()<<"开始解码"<<QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
            avcodec_decode_video2(pAVCodecContext, pAVFrame, &m_i_frameFinished, &pAVPacket);
            if (m_i_frameFinished){
                mutex.lock();
                sws_scale(pSwsContext,(const uint8_t* const *)pAVFrame->data,pAVFrame->linesize,0,videoHeight,pAVPicture.data,pAVPicture.linesize);
                //发送获取一帧图像信号
                QImage image(pAVPicture.data[0],videoWidth,videoHeight,QImage::Format_RGB888);
                emit GetImage(image);
                mutex.unlock();
            }
        }
    }
    av_free_packet(&pAVPacket);//释放资源,否则内存会一直上升
}

备注:

头文件包含及注意事项

//必须加以下内容,否则编译不能通过,为了兼容C和C99标准

#ifndef INT64_C
#define INT64_C
#define UINT64_C
#endif

//引入ffmpeg头文件
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libswscale/swscale.h>
#include <libavutil/frame.h>
}

启发:

setUrl(QString url);

这里的url 一般情况下是一个RTSP流的播放地址,如rtsp://192.168.1.123:554/stream1

但也可以是一个TCP流。

我这边测试的是一个本地的socket流,设url地址为 http://127.0.0.1:5858

可直接解码播放。

时间: 2024-08-06 10:57:42

ffmpeg解码RTSP/TCP视频流H.264(QT界面显示视频画面)的相关文章

H.264/ACC音视频编码流的RTP/RTSP传输实现(1)

目标: 实现一个用于H.264/ACC音视频编码流的RTP/RTSP传输的简单服务器,主要通过此过程学习基于RTP的NAL.ADTS码流封装技术和基于RTSP的视频交互控制技术.完整系统应该包括服务器和客户端两个部分,其中服务器负责接收客户端请求.封包以及发送音视频数据,客户端负责发送请求和接收视频数据.分别在Windows平台上和Android平台上进行网络传输实体测试,通过客户端网络流抓包和播放器播放对系统进行进一步验证. 简介: 随着互联网和移动通信的飞速发展,H.264凭借其突出的编码效

基于H.264协议的视频传输系统中遇到的问题以及解决办法

问题1.视频压缩解码模块在运用的时候出现错误:解码器再解码第二帧视频图片的时候出现异常 client: ../../decoder/T264dec.c:594:T264dec_decode_nal: Assertion `0' failed. Aborted 对于该问题的分析及解决过程为: 1.  修改数据类型,所有缓存区改为unsigned char类型(原来统一为char 类型),但是还是遇到一样的异常错误,问题没有解决. 2.  查看缓存区具体内容是否与服务器端压缩的数据是一致的的,对照数

H.264/ACC音视频编码流的RTP/RTSP传输实现(4)

实时流协议RTSP RTSP[[[] Schulzrinne,H., Rao.Real time streaming protocol (RTSP) RFC 2326[J]. IETF .1998]]由RealNetworks.Netscape Communications和哥伦比亚大学共同开发而成.1998年5月,IETF作为建议标准发布.RTSP是从HTTP协议框架上继承而来,拥有着HTTP的大部分特性.RTSP(Real Time Stream Protocol,实时流协议)是应用级协议,

视频编解码技术详解(H.264、MPEG-4)

一.视频编解码概述 1. 应用场景 视频编码的目的就是压缩视频的占用空间,提高存储和传输的效率,在获得有效的压缩效果的同时,使得压缩过程引起的失真最小.视频压缩算法是通过去除时间.空间的冗余来实现的.通过去除不同类型的冗余,可以明显的压缩数据,代价就是一部分信息失真,可以通过熵编码器(如哈夫曼编码等)进行编码可以获得更高的压缩比.目前主流的图像/视频压缩标准为:JPEG,MPEG,H26X等标准. 2. 主流视频编码标准简介 MPEG-4和H.264(也叫AVC)是目前较为主流的编码标准.每个标

H.264/ACC音视频编码流的RTP/RTSP传输实现(2)

H.264编码基本原理 为达到良好的编码效率及性能,H.264编码器采用的仍是变换和预测的混合编码法,[[[] 毕厚杰. 新一代视频压缩编码标准: H. 264/AVC[M]. 人民邮电出版社, 2005]]其完整的编码过程如图2-1所示. 在H.264编码标准中,输入的帧或场Fn是以宏块为单位进行处理的,采样后的视频图像都被分成16*16的宏块每个宏块包括1个亮度子块和2个8*8的色度子块.在分割宏块后,宏块按照相应次序进行编码器进行压缩编码.在H.264编码过程中,首先按照根据编码速率.编码

FMS发布视频流H.264如何设置

FMS这个话题由来已久,H.264这个编码格式也由来已久.FMS不叫FMS了,改叫AMS了.因为是Adobe. 今天就说说flash发布流媒体视频,以H.264编码出现的问题.在网上找,大把的关于as3的H.264视频编码的代码.API就那么几个.可是,当你真正去做,用到流媒体发布和播放的时候,就会发现结果并不是想象的那么美.也许会遇到以下几个问题.1.发布端的视频都不清晰.2.发布端的视频清晰,客户端接受到的视频不清晰.冥冥H.264视频编码备受推崇,高清的帽子早戴上了.为什么会这样呢.这里就

干货:如何实现RTSP推送H.264、RTSP推送H.265(hevc)

rtsp推送相关的资料和测试软件比较少,本文介绍rtsp推送相关信令和测试效果: 1. rtsp推送流程. 主要分两部分:第一部分先发送信令:第二部分发送rtp包. ?信令流程: ?1.1?先发送OPTIONS, OPTIONS比较常用,就不做详细说明了. 1.2 发送ANNOUNCE, 发送ANNOUNCE主要是把要推送的音视频信息通过sdp格式传给服务器.关于sdp信息如何构造,对于h264请参考rfc6184. h265请参考rfc7798. 下面举两个例子. h264+aac ANNOU

h.264并行熵解码

在前面讨论并行解码的章节中,我们专注于讨论解码的宏块重建部分,甚至把宏块重建描述成宏块解码,这是因为在解码工作中,宏块重建确实占了相当大的比重,不过解码还包含其它的部分,按照解码流程可粗略分为: 读取并初步解析码流(front-end) 熵解码(本文章只讨论CABAC) 帧间预测.帧内预测 (主要讨论部分为运动向量预测) 宏块重建 在以前的并行解码文章,我们主要讨论了宏块重建的并行算法,得知采用不同的算法,会产生不同的并行度.在不考虑硬件负担的情况下,并行度可以达到几十,甚至上千,如此一来,除开

H.264解码过程剖析-4

x264开源工程实现H.264的视频编码,但没有提供对应的解码器.ffmpeg开源多媒体编解码集合汇集了市面上几乎所有媒体格式的编解码的源代码.其中的H264.c就是一个能正常解码x264编码码流的独立的源文件,其使用步骤也与上述的编码或解码CODEC应用案例基本相同.这一节通过自顶向下的方式,讲述H264.c如何实现H.264视频解码过程. H264.c源文件有几千行,代码量庞大,很不便于浏览.分析和移植.同时该文件还依赖其他源文件,组织结构较复杂,实现平台由于不是基于Windows的VC++