C++ 使用ffmpeg5.0.1实现rtsp取流

环境
Ubuntu 18.04
Qt 5.14.2
FFmpeg-n5.0.1

下载
https://git.ffmpeg.org/ffmpeg.git
https://github.com/FFmpeg/FFmpeg

这里选择n5.0.1版本

安装编译依赖
sudo apt-get install nasm
配置
生成包括静态和动态库
头文件和库都在当前的install文件夹中

FFmpeg-n5.0.1$  ./configure --prefix="./install"  --enable-shared
再执行

make
make install

在install文件夹中的include

在install文件夹中的lib


ffmepg采用rtsp取流流程图


CMakeLists.txt编写方法
cmake_minimum_required(VERSION 3.5)

project(rtsp LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt5Core)

set(FFMPEG_PREFIX_PATH /path/to/FFmpeg-n5.0.1/install)

include_directories(
    ${FFMPEG_PREFIX_PATH}/include/
)

link_directories(
    ${FFMPEG_PREFIX_PATH}/lib/ )

add_executable(rtsp
  main.cpp
)
target_link_libraries(rtsp avcodec avformat avfilter avutil swresample swscale swscale )

实现代码
#include <iostream>

extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
}

int main(int argc, char *argv[])
{

    int status_error_=-1;
    std::string videourl= "rtsp://admin:Admin12345@192.168.3.64:554/Streaming/Channels/1";
    AVFormatContext *pFormatCtx = NULL;
    AVDictionary *options = NULL;
    AVPacket *av_packet = NULL; // AVPacket暂存解码之前的媒体数据


    avformat_network_init();
    //执行网络库的全局初始化。
    //此函数仅用于解决旧版GNUTLS或OpenSSL库的线程安全问题。
    //一旦删除对较旧的GNUTLS和OpenSSL库的支持,此函数将被弃用,并且此函数将不再有任何用途。
    av_dict_set(&options, "buffer_size", "4096000", 0); //设置缓存大小
    av_dict_set(&options, "rtsp_transport", "tcp", 0);  //以tcp的方式打开,
    av_dict_set(&options, "stimeout", "5000000", 0);    //设置超时断开链接时间,单位us,   5s
    av_dict_set(&options, "max_delay", "500000", 0);    //设置最大时延

    pFormatCtx = avformat_alloc_context(); //用来申请AVFormatContext类型变量并初始化默认参数,申请的空间

    //打开网络流或文件流
    if (avformat_open_input(&pFormatCtx, videourl.c_str(), NULL, &options) != 0)
    {

        std::cout << "Couldn't open input stream.\n"
                  << std::endl;

        return status_error_;
    }

    //获取视频文件信息
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
    {

        std::cout << "Couldn't find stream information."<< std::endl;
        return status_error_;
    }

    std::cout << "av_dict_get:" << std::endl;
    AVDictionaryEntry *tag = NULL;
    //av_dict_set(&pFormatCtx->metadata, "rotate", "0", 0);这里可以设置一些属性
    while ((tag = av_dict_get(pFormatCtx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
    {
        std::string key = tag->key;
        std::string value = tag->value;
        std::cout << "av_dict_get:" << key << ":" << value << std::endl;
    }


    //查找码流中是否有视频流
    int videoindex = -1;
    unsigned i = 0;
    for (i = 0; i < pFormatCtx->nb_streams; i++)
    {
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoindex = i;
            break;
        }
    }
    if (videoindex == -1)
    {

        std::cout << "Didn't find a video stream.\n"
                  << std::endl;

        return status_error_;
    }

    av_packet = (AVPacket *)av_malloc(sizeof(AVPacket));

    while (true)
    {
        if (av_read_frame(pFormatCtx, av_packet) >= 0)
        {

            if (av_packet->stream_index == videoindex)
            {
                std::cout << "\ndata size is:" << av_packet->size;
                //这里就是接收到的未解码之前的数据

            }
            if (av_packet != NULL)
                av_packet_unref(av_packet);
        }


    }

    av_free(av_packet);
    avformat_close_input(&pFormatCtx);

    return 0;
}

运行可执行文件前,可设置从当前文件夹查找so动态库

export LD_LIBRARY_PATH=./
结果

posted @ 2023-05-18 15:58  阿风小子  阅读(669)  评论(0编辑  收藏  举报