使用qt实现一个rtsp服务程序

一 简介

本文章主要是实现一个rtsp服务程序.该rtsp服务程序参考EsayRtspServer开源库,该rtsp服务程序使用到的库有: EasyRTSPServer,SimpleStreamClient,FFmpeg.本服务支持rtsp客户端从本服务拉取rtsp媒体流。拉流地址示例:rtsp://192.168.22.53:8554/rtsp地址.

二 依赖库

1.EasyRTSPServer库 --------- 开源库;

基于live555实现的可并发多路的rtsp服务组件;

2.SimpleStreamClient库 ------ 自定义库,参考链接 :拉流库

基于ffmpeg实现的拉取媒体流数据包动态库;

3. FFmpeg库 ------------ 开源库;

开源媒体流框架

三 相关文件

QRtspServer.pro

复制代码
QT +=core widgets

CONFIG += c++11 console
CONFIG -= app_bundle

QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        main.cpp \
        mainwindow.cpp \
        rtspserver.cpp

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    mainwindow.h \
    rtspserver.h

INCLUDEPATH += $$PWD/ffmpeg/include

LIBS += -L$$PWD/ffmpeg/lib \
        -lavcodec \
        -lavdevice \
        -lavformat \
        -lavutil \
        -lswscale \
        -lswresample


unix:!macx: LIBS += -L$$PWD/EasyRtspServer/ -lEasyRTSPServer

INCLUDEPATH += $$PWD/EasyRtspServer
DEPENDPATH += $$PWD/EasyRtspServer

unix:!macx: LIBS += -L$$PWD/SimpleStreamClient/lib/ -lSimpleStreamClient

INCLUDEPATH += $$PWD/SimpleStreamClient/include
DEPENDPATH += $$PWD/SimpleStreamClient/include

rtspserver.h

cpp 复制代码
#ifndef RTSPSERVER_H
#define RTSPSERVER_H

#include <QThread>
#include <QDebug>

#include "EasyRtspServerAPI.h"
#include "SimpleStreamClientAPI.h"


typedef struct __AV_FRAME_PTS_T
{
    long long	pts;

    long long dts;
    float		dtsDecimal;
}AV_FRAME_PTS_T;

typedef struct __RTSP_CHANNEL_T
{
    char		url[256];
    char		resourcename[256];
    char		username[36];
    char		password[36];

    EASY_RTSPSERVER_MEDIA_INFO_T		mediaInfo;		//源媒体信息
    SIMPLE_MEDIA_INFO_T s_mediaInfo;

    Simple_Handle   rtspClientHandle;//rtsp客户端句柄
    EASY_CHANNEL_HANDLE channelHandle;

    int status;
}RTSP_CHANNEL_T;

class RtspServer:public QObject
{
    Q_OBJECT
public:
    explicit RtspServer(QObject *parent = nullptr);
    ~RtspServer();

    bool startSrv(int port = 8554);
    void stopSrv();

private:

private:

};

#endif // RTSPSERVER_H

rtspserver.cpp

cpp 复制代码
#include "rtspserver.h"
#include <QDateTime>
#include "SimpleStreamClientAPI.h"
//#define EASYSTREALCLIENT

//输入的pbuf必须包含start code(00 00 00 01)
int GetH265VPSandSPSandPPS(char *pbuf, int bufsize, char *_vps, int *_vpslen, char *_sps, int *_spslen, char *_pps, int *_ppslen)
{
    char vps[512]={0}, sps[512] = {0}, pps[128] = {0};
    int vpslen=0, spslen=0, ppslen=0, i=0, iStartPos=0, ret=-1;
    int iFoundVPS=0, iFoundSPS=0, iFoundPPS=0, iFoundSEI=0;
    if (NULL == pbuf || bufsize<4)	return -1;

    for (i=0; i<bufsize; i++)
    {
        if ( (unsigned char)pbuf[i] == 0x00 && (unsigned char)pbuf[i+1] == 0x00 &&
             (unsigned char)pbuf[i+2] == 0x00 && (unsigned char)pbuf[i+3] == 0x01 )
        {
            //printf("0x%X\n", (unsigned char)pbuf[i+4]);
            switch ((unsigned char)pbuf[i+4])
            {
            case 0x40:		//VPS
                {
                    iFoundVPS = 1;
                    iStartPos = i+4;
                }
                break;
            case 0x42:		//SPS
                {
                    if (iFoundVPS == 0x01 && i>4)
                    {
                        vpslen = i-4-iStartPos+4;
                        if (vpslen>256)	return -1;          //vps长度超出范围
                        memset(vps, 0x00, sizeof(vps));
                        memcpy(vps, pbuf+iStartPos, vpslen);
                    }

                    iStartPos = i+4;
                    iFoundSPS = 1;
                }
                break;
            case 0x44:		//PPS
                {
                    if (iFoundSPS == 0x01 && i>4)
                    {
                        spslen = i-4-iStartPos+4;
                        if (spslen>256)	return -1;
                        memset(sps, 0x0, sizeof(sps));
                        memcpy(sps, pbuf+iStartPos,  spslen);
                    }

                    iStartPos = i+4;
                    iFoundPPS = 1;
                }
                break;
            case 0x4E:		//SEI
            case 0x50:
                {
                    if (iFoundPPS == 0x01 && i>4)
                    {
                        ppslen = i-4-iStartPos+4;
                        if (ppslen>256)	return -1;
                        memset(pps, 0x0, sizeof(pps));
                        memcpy(pps, pbuf+iStartPos,  ppslen);
                    }
                    iStartPos = i+4;
                    iFoundSEI = 1;
                }
                break;
            default:
                {
                    iStartPos = i+4;
                }
                break;
            }
        }

        if (iFoundSEI == 0x01)		break;
    }


    if (iFoundVPS == 0x01)
    {
        if (vpslen < 1)
        {
            if (bufsize < sizeof(vps))
            {
                vpslen = bufsize-4;
                memset(vps, 0x00, sizeof(vps));
                memcpy(vps, pbuf+4, vpslen);
            }
        }

        if (vpslen > 0)
        {
            if (NULL != _vps)   memcpy(_vps, vps, vpslen);
            if (NULL != _vpslen)    *_vpslen = vpslen;
        }

        ret = 0;
    }


    if (iFoundSPS == 0x01)
    {
        if (spslen < 1)
        {
            if (bufsize < sizeof(sps))
            {
                spslen = bufsize-4;
                memset(sps, 0x00, sizeof(sps));
                memcpy(sps, pbuf+4, spslen);
            }
        }

        if (spslen > 0)
        {
            if (NULL != _sps)   memcpy(_sps, sps, spslen);
            if (NULL != _spslen)    *_spslen = spslen;
        }

        ret = 0;
    }

    if (iFoundPPS == 0x01)
    {
        if (ppslen < 1)
        {
            if (bufsize < sizeof(pps))
            {
                ppslen = bufsize-4;
                memset(pps, 0x00, sizeof(pps));
                memcpy(pps, pbuf+4, ppslen);	//pps
            }
        }
        if (ppslen > 0)
        {
            if (NULL != _pps)   memcpy(_pps, pps, ppslen);
            if (NULL != _ppslen)    *_ppslen = ppslen;
        }
        ret = 0;
    }

    return ret;
}
int GetH264SPSandPPS(char* pbuf, int bufsize, char* _sps, int* _spslen, char* _pps, int* _ppslen, char* _sei, int* _seilen)
{
    char sps[512] = { 0 }, pps[128] = { 0 }, sei[128] = { 0 };
    int spslen = 0, ppslen = 0, seilen = 0, i = 0, iStartPos = 0, ret = -1;
    int iFoundSPS = 0, iFoundPPS = 0, iFoundSEI = 0, iFoundIDR = 0;
    if (NULL == pbuf || bufsize < 4)	return -1;


    int startCodeOffset = -1;
    int offsetLen = 0;
    for (i = 0; i < bufsize; i++)
    {

        if ((unsigned char)pbuf[i] == 0x00 && (unsigned char)pbuf[i + 1] == 0x00 &&
            (unsigned char)pbuf[i + 2] == 0x00 && (unsigned char)pbuf[i + 3] == 0x01)
        {
            startCodeOffset = 4;
        }
        else if ((unsigned char)pbuf[i] == 0x00 && (unsigned char)pbuf[i + 1] == 0x00 &&
            (unsigned char)pbuf[i + 2] == 0x01)
        {
            startCodeOffset = 3;
        }

        if (startCodeOffset >= 0)
        {
            unsigned char naltype = ((unsigned char)pbuf[i + startCodeOffset] & 0x1F);
            if (naltype == 7)       //sps
            {
                iFoundSPS = 1;
                iStartPos = i + startCodeOffset;

                offsetLen += startCodeOffset;
                i += 1;
            }
            else if (naltype == 8)	//pps
            {
                //copy sps
                if (iFoundSPS == 0x01 && i > 4)
                {
                    spslen = i - startCodeOffset;
                    if (spslen > 256)	return -1;          //sps3¤?è3?3?·??§
                    memset(sps, 0x00, sizeof(sps));
                    memcpy(sps, pbuf + startCodeOffset, spslen);
                }

                iFoundPPS = 1;
                offsetLen += startCodeOffset;
                i += 1;
            }
            else if (naltype == 6)		//sei
            {
                if (iFoundPPS == 0x01 && i > 4)
                {
                    ppslen = i - spslen - offsetLen;
                    if (ppslen > 0 && ppslen < sizeof(pps))
                    {
                        memset(pps, 0x00, sizeof(pps));
                        memcpy(pps, pbuf + spslen + offsetLen, ppslen);	//pps
                    }
                }
                iFoundSEI = 1;
                offsetLen += startCodeOffset;
                i += 1;
            }
            else if (naltype == 5)	//idr
            {
                iFoundIDR = 1;

                if (iFoundPPS == 1 && iFoundSEI == 0)
                {
                    ppslen = i - spslen - offsetLen;
                    if (ppslen > 0 && ppslen < sizeof(pps))
                    {
                        memset(pps, 0x00, sizeof(pps));
                        memcpy(pps, pbuf + spslen + offsetLen, ppslen);	//pps
                    }
                }
                else if (iFoundSEI==1)
                {
                    seilen = i - spslen - offsetLen - ppslen;
                    if (seilen > 0 && seilen < sizeof(sei))
                    {
                        memset(sei, 0x00, sizeof(sei));
                        memcpy(sei, pbuf + spslen + offsetLen + ppslen, seilen);	//sei
                    }
                    else
                    {
                        seilen = 0;
                    }
                }
                break;
            }



            startCodeOffset = -1;

        }
        else
        {

        }
    }


    if (iFoundSPS == 0x01)
    {
        if (spslen < 1)
        {
            if (bufsize < sizeof(sps))
            {
                spslen = bufsize - 4;
                memset(sps, 0x00, sizeof(sps));
                memcpy(sps, pbuf + 4, spslen);
            }
        }

        if (spslen > 0)
        {
            if (NULL != _sps)   memcpy(_sps, sps, spslen);
            if (NULL != _spslen)    *_spslen = spslen;
        }

        ret = 0;
    }

    if (iFoundPPS == 0x01)
    {
        if (ppslen < 1)
        {
            if (bufsize < sizeof(pps))
            {
                ppslen = bufsize - 4;
                memset(pps, 0x00, sizeof(pps));
                memcpy(pps, pbuf + 4, ppslen);	//pps
            }
        }
        if (ppslen > 0)
        {
            if (NULL != _pps)   memcpy(_pps, pps, ppslen);
            if (NULL != _ppslen)    *_ppslen = ppslen;
        }
        ret = 0;
    }

    if (iFoundSEI == 0x01)
    {
        if (seilen > 0)
        {
            if (NULL != _sei)   memcpy(_sei, sei, seilen);
            if (NULL != _seilen)    *_seilen = seilen;
        }
        ret = 0;
    }
    return ret;
}

int CALLBACK __SimpleStreamClientCallBack(void *_channelPtr, int _frameType, void *pBuf, SIMPLE_FRAME_INFO* frameInfo)
{
    RTSP_CHANNEL_T* pChannel = (RTSP_CHANNEL_T*)_channelPtr;

    if (_frameType == EASY_SDK_VIDEO_FRAME_FLAG){
        if (pChannel->mediaInfo.spsLength < 1 && frameInfo->type == 1)
        {
#if 1
            if (frameInfo->codec == EASY_SDK_VIDEO_CODEC_H264)
            {
                GetH264SPSandPPS((char*)pBuf, frameInfo->length,
                                 (char*)pChannel->mediaInfo.sps, (int*)&pChannel->mediaInfo.spsLength,
                                 (char*)pChannel->mediaInfo.pps, (int*)&pChannel->mediaInfo.ppsLength,
                                 (char*)pChannel->mediaInfo.sei, (int*)&pChannel->mediaInfo.seiLength);
                qDebug() << "I帧 H264 spslen:" << pChannel->mediaInfo.spsLength << " ppslen:" << pChannel->mediaInfo.ppsLength;
                pChannel->mediaInfo.videoCodec = EASY_SDK_VIDEO_CODEC_H264;
            }
            else if (frameInfo->codec == EASY_SDK_VIDEO_CODEC_H265)
            {
                GetH265VPSandSPSandPPS((char*)pBuf, frameInfo->length, (char*)pChannel->mediaInfo.vps, (int*)&pChannel->mediaInfo.vpsLength, (char*)pChannel->mediaInfo.sps, (int*)&pChannel->mediaInfo.spsLength, (char*)pChannel->mediaInfo.pps, (int*)&pChannel->mediaInfo.ppsLength);
                pChannel->mediaInfo.videoCodec = EASY_SDK_VIDEO_CODEC_H265;
            }

            qDebug("__EasyStreamClientCallBack Get Media Info: video:%u fps:%u audio:%u channel:%u sampleRate:%u spslen: %d ppslen:%d\n",
                   pChannel->mediaInfo.videoCodec, pChannel->mediaInfo.videoFps,
                   pChannel->mediaInfo.audioCodec, pChannel->mediaInfo.audioChannel, pChannel->mediaInfo.audioSampleRate,
                   pChannel->mediaInfo.spsLength, pChannel->mediaInfo.ppsLength);
#if 0
            if (pChannel->mediaInfo.spsLength > 0)
            {
                pChannel->mediaInfo.videoCodec = frameInfo->codec;
                pChannel->mediaInfo.audioCodec = EASY_SDK_AUDIO_CODEC_G711U;

                pChannel->mediaInfo.audioSampleRate = 8000;
                pChannel->mediaInfo.audioChannel = 1;
                pChannel->mediaInfo.audioBitsPerSample = 16;
            }
#endif
#endif
        }
        EASY_AV_Frame		avFrameInfo;
        bool bSendSpsAndPps = false;

#if 1
        if (frameInfo->type == 0x01 && pChannel->mediaInfo.spsLength > 0 && pChannel->mediaInfo.ppsLength > 0)
        {
            bSendSpsAndPps = true;
            if (pChannel->mediaInfo.vpsLength > 0)
            {
                //VPS
                memset(&avFrameInfo, 0x00, sizeof(EASY_AV_Frame));
                avFrameInfo.u32AVFrameFlag = _frameType;
                avFrameInfo.u32AVFrameLen = pChannel->mediaInfo.vpsLength;
                avFrameInfo.u32VFrameType = frameInfo->type;
                avFrameInfo.pBuffer = (unsigned char*)(pChannel->mediaInfo.vps);
                EasyRtspServer_PushFrame(pChannel->channelHandle, &avFrameInfo);
            }
#if 1
            //SPS
            memset(&avFrameInfo, 0x00, sizeof(EASY_AV_Frame));
            avFrameInfo.u32AVFrameFlag = _frameType;
            avFrameInfo.u32AVFrameLen = pChannel->mediaInfo.spsLength;
            avFrameInfo.u32VFrameType = frameInfo->type;
            avFrameInfo.pBuffer = (unsigned char*)(pChannel->mediaInfo.sps);
            EasyRtspServer_PushFrame(pChannel->channelHandle, &avFrameInfo);

            //PPS
            memset(&avFrameInfo, 0x00, sizeof(EASY_AV_Frame));
            avFrameInfo.u32AVFrameFlag = _frameType;
            avFrameInfo.u32AVFrameLen = pChannel->mediaInfo.ppsLength;
            avFrameInfo.u32VFrameType = frameInfo->type;
            avFrameInfo.pBuffer = (unsigned char*)(pChannel->mediaInfo.pps);
            EasyRtspServer_PushFrame(pChannel->channelHandle, &avFrameInfo);
#endif
        }
#endif
        memset(&avFrameInfo, 0x00, sizeof(EASY_AV_Frame));
        avFrameInfo.u32AVFrameFlag = _frameType;
        //rtsp流
        avFrameInfo.u32AVFrameLen = frameInfo->length - 4;
        avFrameInfo.u32VFrameType = frameInfo->type;
        avFrameInfo.pBuffer = (unsigned char*)(pChannel->mediaInfo.sps);

        if (bSendSpsAndPps)
        {
            if (pChannel->mediaInfo.videoCodec == EASY_SDK_VIDEO_CODEC_H264)
            {
#if 1
                unsigned char* frameData = (unsigned char*)pBuf;
                for (unsigned int idx = 0; idx < frameInfo->length - 1; idx++)
                {
                    if (((unsigned char)(frameData)[idx] == 0x00) &&
                            ((unsigned char)frameData[idx + 1] == 0x01) &&
                            (((unsigned char)frameData[idx + 2] & 0x1f) == 0x5)) //I帧
                    {
                        avFrameInfo.u32AVFrameLen = frameInfo->length - idx - 2;
                        avFrameInfo.pBuffer = (unsigned char*)(frameData + idx + 2);

                        break;
                    }
                }
#else
                int trim_length = 4 + pChannel->mediaInfo.spsLength;
                trim_length += 4 + pChannel->mediaInfo.ppsLength;
                if (pChannel->mediaInfo.seiLength > 0)			trim_length += 4 + pChannel->mediaInfo.seiLength;
                trim_length += 4;

                avFrameInfo.u32AVFrameLen = frameInfo->length ;
                avFrameInfo.pBuffer = (unsigned char*)((char*)pBuf);
#endif
#if 0
                qDebug("h264 I frame:%d\n",avFrameInfo.u32AVFrameLen);
                QByteArray arr((char*)avFrameInfo.pBuffer,50);
                QString hex = arr.toHex(' ');
                qDebug().noquote() <<"前五十个字节:"<< hex;
#endif
            }
            else if (pChannel->mediaInfo.videoCodec == EASY_SDK_VIDEO_CODEC_H265)
            {
#if 0
                unsigned char* frameData = (unsigned char*)pBuf;
                for (unsigned int idx = 0; idx < frameInfo->length - 1; idx++)
                {
                    if (((unsigned char)(frameData)[idx] == 0x00) &&
                            ((unsigned char)frameData[idx + 1] == 0x01) &&
                            ((((unsigned char)frameData[idx + 2] & 0x7f) == 19||
                             ((unsigned char)frameData[idx + 2] & 0x7f) == 20))) //I帧
                    {
                        avFrameInfo.u32AVFrameLen = frameInfo->length - idx - 2;
                        avFrameInfo.pBuffer = (unsigned char*)(frameData + idx + 2);

                        break;
                    }
                }
#else
                int trim_length = 4 + pChannel->mediaInfo.vpsLength;
                trim_length += 4 + pChannel->mediaInfo.spsLength;
                trim_length += 4 + pChannel->mediaInfo.ppsLength;
                if (pChannel->mediaInfo.seiLength > 0)
                    trim_length += 4 + pChannel->mediaInfo.seiLength;

                avFrameInfo.u32AVFrameLen = frameInfo->length-trim_length;
                avFrameInfo.pBuffer = (unsigned char*)((char*)pBuf+trim_length);
#endif
                qDebug("h265 I frame:%d\n",avFrameInfo.u32AVFrameLen);
                QByteArray arr((char*)avFrameInfo.pBuffer,50);
                QString hex = arr.toHex(' ');
                qDebug().noquote() <<"前十个字节:"<< hex;
                qDebug("\n");
            }
        }
        else
        {
             avFrameInfo.pBuffer = (unsigned char*)((char*)pBuf + 4);
#if 0
             qDebug("h264 P frame:%d\n",avFrameInfo.u32AVFrameLen);
             QByteArray arr((char*)avFrameInfo.pBuffer,50);
             QString hex = arr.toHex(' ');
             qDebug().noquote() <<"前五十个字节:"<< hex;
#endif
        }

        EasyRtspServer_PushFrame(pChannel->channelHandle, &avFrameInfo);
    }else if(_frameType == EASY_SDK_AUDIO_FRAME_FLAG){
        EASY_AV_Frame		avFrameInfo;
        memset(&avFrameInfo, 0x00, sizeof(EASY_AV_Frame));
        avFrameInfo.u32AVFrameFlag = _frameType;
        avFrameInfo.u32AVFrameLen = frameInfo->length;
        avFrameInfo.u32VFrameType = frameInfo->type;
        avFrameInfo.pBuffer = (unsigned char*)pBuf;
        EasyRtspServer_PushFrame(pChannel->channelHandle, &avFrameInfo);
    }else if(_frameType == EASY_SDK_EVENT_FRAME_FLAG){

    }else if(_frameType == EASY_SDK_MEDIA_INFO_FLAG){
        EASY_MEDIA_INFO_T* mediainfo = (EASY_MEDIA_INFO_T*)pBuf;
        if (pBuf != NULL)
        {
            memcpy(mediainfo, pBuf, sizeof(EASY_MEDIA_INFO_T));
#if 0
            printf("Source;[%s] Get MediaInfo: video:%u fps:%u audio:%u channel:%u sampleRate:%u spslen: %d ppslen:%d\n",
                   pChannel->url,
                   mediainfo->u32VideoCodec, mediainfo->u32VideoFps,
                   mediainfo->u32AudioCodec, mediainfo->u32AudioChannel, mediainfo->u32AudioSamplerate,
                   mediainfo->u32SpsLength, mediainfo->u32PpsLength);
#endif
        }
        if (NULL != mediainfo && NULL != pChannel)
        {
            pChannel->mediaInfo.audioChannel = mediainfo->u32AudioChannel;
            pChannel->mediaInfo.audioSampleRate = mediainfo->u32AudioSamplerate;
            pChannel->mediaInfo.audioBitsPerSample = mediainfo->u32AudioBitsPerSample;

            pChannel->mediaInfo.vpsLength = mediainfo->u32VpsLength;
            if (pChannel->mediaInfo.vpsLength > 0)		memcpy(pChannel->mediaInfo.vps, mediainfo->u8Vps, mediainfo->u32VpsLength);

            pChannel->mediaInfo.spsLength = mediainfo->u32SpsLength;
            if (pChannel->mediaInfo.spsLength > 0)		memcpy(pChannel->mediaInfo.sps, mediainfo->u8Sps, mediainfo->u32SpsLength);

            pChannel->mediaInfo.ppsLength = mediainfo->u32PpsLength;
            if (pChannel->mediaInfo.ppsLength > 0)		memcpy(pChannel->mediaInfo.pps, mediainfo->u8Pps, mediainfo->u32PpsLength);

            //最后再设置编码类型
            pChannel->mediaInfo.audioCodec = mediainfo->u32AudioCodec;
            pChannel->mediaInfo.videoCodec = mediainfo->u32VideoCodec;
        }
    }
    return 0;
}

int CALLBACK __EasyRtspServer_Callback(EASY_RTSPSERVER_STATE_T serverStatus, const char *resourceName,
                                            EASY_CHANNEL_HANDLE *channelHandle,
                                            EASY_RTSPSERVER_MEDIA_INFO_T *mediaInfo,
                                            EASY_PLAY_CONTROL_INFO_T *playCtrlInfo,
                                            void *userPtr, void *channelPtr)
{
    int ret = -1;
    qDebug("EasyStreamingServer New Request: %s   status[%d]\n", resourceName, serverStatus );
    if (EASY_CHANNEL_OPEN_STREAM == serverStatus)
    {
        EASY_CHANNEL_HANDLE pChannelHandle = NULL;

        qDebug("EasyStreamingServer New Request: %s\n", resourceName);


        char szURL[260] = { 0 };
#if 0
        char filename[MAX_PATH] = { 0 };
        sprintf(filename, "%s.txt", resourceName);
        FILE* f = fopen(filename, "rb");
        if (NULL == f)
        {
            return 0;
        }

        fgets(szURL, sizeof(szURL), f);
        fclose(f);
#else
        strcpy(szURL, resourceName);
#endif

        int len = (int)strlen(szURL);
        for (int i = len - 1; i > 0; i--)
        {
            if (((unsigned char)szURL[i] == '\r') ||
                    ((unsigned char)szURL[i] == '\n'))
            {
                szURL[i] = '\0';
            }
        }
#if 0
        if ((int)strlen(szURL) < 3)		return 0;
#endif

        RTSP_CHANNEL_T	*pRtspChannel = new RTSP_CHANNEL_T;
        if (NULL == pRtspChannel)		return -1;

        memset(pRtspChannel, 0x00, sizeof(RTSP_CHANNEL_T));

        strcpy(pRtspChannel->url, szURL);// resourceName);

#ifdef EASYSTREALCLIENT
        EasyStreamClient_Init(&pRtspChannel->rtspClientHandle, 2);

        if (!pRtspChannel->rtspClientHandle)
        {
            printf("EasyStreamClient_Init Initial fail.\n");
            return 0;
        }

        EasyStreamClient_SetAudioEnable(pRtspChannel->rtspClientHandle, 1);

        EasyStreamClient_SetCallback(pRtspChannel->rtspClientHandle, __EasyStreamClientCallBack);

        unsigned int mediaType = EASY_SDK_VIDEO_FRAME_FLAG | EASY_SDK_AUDIO_FRAME_FLAG;

        EasyStreamClient_OpenStream(pRtspChannel->rtspClientHandle, pRtspChannel->url, EASY_RTP_OVER_TCP, (void*)pRtspChannel, 1000, 1, 1);
#else
        SimpleStreamClient_Init(&pRtspChannel->rtspClientHandle, 0);
        if (!pRtspChannel->rtspClientHandle)
        {
            printf("EasyStreamClient_Init Initial fail.\n");
            return 0;
        }
        SimpleStreamClient_SetCallback(pRtspChannel->rtspClientHandle,__SimpleStreamClientCallBack);

        SimpleStreamClient_OpenStream(pRtspChannel->rtspClientHandle,pRtspChannel->url,Simple_RTP_OVER_TCP,(void*)pRtspChannel,1000,1,1);
#endif

        for (int i=0; i<10*2; i++)		//等待5秒
        {
            if (pRtspChannel->s_mediaInfo.u32VideoCodec>0)	break;// && pRtspChannel->mediaInfo.audioCodec)		break;

            QThread::msleep(100);
        }

        //设置媒体信息
        mediaInfo->videoCodec = pRtspChannel->s_mediaInfo.u32VideoCodec;
        mediaInfo->audioCodec = pRtspChannel->s_mediaInfo.u32AudioCodec;
        mediaInfo->audioSampleRate = pRtspChannel->s_mediaInfo.u32AudioSamplerate;
        mediaInfo->audioChannel = pRtspChannel->s_mediaInfo.u32AudioChannel;
        mediaInfo->audioBitsPerSample = pRtspChannel->s_mediaInfo.u32AudioBitsPerSample == 0 ? 16 : pRtspChannel->s_mediaInfo.u32AudioBitsPerSample;

        qDebug("Get Source:[%s] videoCodec:%d,audioCodec:%d,audioSampleRate=%d,pRtspChannel=%x\n",
               pRtspChannel->url,
               pRtspChannel->s_mediaInfo.u32VideoCodec,
               pRtspChannel->s_mediaInfo.u32AudioCodec,
               pRtspChannel->s_mediaInfo.u32AudioSamplerate,
               pRtspChannel);
#if 1
        //此处可指定sps & pps, 也可以不指定
        mediaInfo->vpsLength = pRtspChannel->s_mediaInfo.u32VpsLength;
        memcpy(mediaInfo->vps, pRtspChannel->s_mediaInfo.u8Vps, mediaInfo->vpsLength);
        mediaInfo->spsLength = pRtspChannel->s_mediaInfo.u32SpsLength;
        memcpy(mediaInfo->sps, pRtspChannel->s_mediaInfo.u8Sps, mediaInfo->spsLength);
        mediaInfo->ppsLength = pRtspChannel->s_mediaInfo.u32PpsLength;
        memcpy(mediaInfo->pps, pRtspChannel->s_mediaInfo.u8Pps, mediaInfo->ppsLength);
#endif
        mediaInfo->videoFps = 25;
        if (pRtspChannel->s_mediaInfo.u32VideoCodec > 0)
        {
            qDebug("create channel: %s\n", resourceName);

            //创建通道
            EasyRtspServer_CreateChannel(resourceName, &pChannelHandle, (void *)pRtspChannel);
            *channelHandle = pChannelHandle;
            pRtspChannel->channelHandle = pChannelHandle;

            ret = 0;
        }
        else		//关闭源
        {

            qDebug("Get Source[%s][%s] sdp fail.\n", resourceName, pRtspChannel->url);
#ifdef EASYSTREALCLIENT
            EasyStreamClient_Deinit(pRtspChannel->rtspClientHandle);
#else
            SimpleStreamClient_Deinit(pRtspChannel->rtspClientHandle);
#endif
            delete pRtspChannel;
            pRtspChannel = NULL;
        }
    }
    if (EASY_CHANNEL_START_STREAM == serverStatus)
    {
        RTSP_CHANNEL_T	*pRtspChannel = (RTSP_CHANNEL_T *)channelPtr;
        pRtspChannel->status = 0x01;		//开始发送流
    }
    if (EASY_CHANNEL_STOP_STREAM == serverStatus)
    {
        RTSP_CHANNEL_T	*pRtspChannel = (RTSP_CHANNEL_T *)channelPtr;
        pRtspChannel->status = 0x00;		//停止发送流
    }
    else if (EASY_CHANNEL_CLOSE_STREAM == serverStatus)
    {
        qDebug("#######################Close Stream: %s\n", resourceName);

        RTSP_CHANNEL_T	*pRtspChannel = (RTSP_CHANNEL_T *)channelPtr;
        if (NULL != pRtspChannel)
        {
            if (NULL != pRtspChannel->rtspClientHandle)
            {
#ifdef EASYSTREALCLIENT
                EasyStreamClient_Deinit(pRtspChannel->rtspClientHandle);
#else
                SimpleStreamClient_Deinit(pRtspChannel->rtspClientHandle);
#endif
            }
            qDebug("Close Source OK: %s    %s\n", resourceName, pRtspChannel->url);

            EasyRtspServer_DeleteChannel(&pRtspChannel->channelHandle);
            delete pRtspChannel;
            pRtspChannel = NULL;
        }
        ret = 0;
    }
    else if (EASY_CHANNEL_PLAY_CONTROL == serverStatus)
    {
        //以下为播放控制, 用于录像回放时使用
#if 0
        printf("RTSP_CHANNEL_PLAY_CONTROL: %s\n", resourceName);

        RTSP_CHANNEL_T	*pRtspChannel = (RTSP_CHANNEL_T *)channelPtr;
        if (NULL != pRtspChannel)
        {
            char szMediaType[16] = {0};
            if (EASY_SDK_VIDEO_FRAME_FLAG == playCtrlInfo->mediaType)		strcpy(szMediaType, "Video");
            else if (EASY_SDK_AUDIO_FRAME_FLAG == playCtrlInfo->mediaType)	strcpy(szMediaType, "Audio");
            else if (EASY_SDK_EVENT_FRAME_FLAG == playCtrlInfo->mediaType)	strcpy(szMediaType, "Metadata");

            if (EASY_PLAY_CTRL_CMD_GET_DURATION == playCtrlInfo->ctrlCommand)
                printf("GetDuration... %s\n", szMediaType);
            else if (EASY_PLAY_CTRL_CMD_PAUSE == playCtrlInfo->ctrlCommand)
                printf("Pause...%s\n", szMediaType);
            else if (EASY_PLAY_CTRL_CMD_RESUME == playCtrlInfo->ctrlCommand)
                printf("Resume...%s\n", szMediaType);
            else if (EASY_PLAY_CTRL_CMD_SCALE == playCtrlInfo->ctrlCommand)
                printf("Scale[%s]: %.2f\n", szMediaType, playCtrlInfo->scale);
            else if (EASY_PLAY_CTRL_CMD_SEEK_STREAM == playCtrlInfo->ctrlCommand)
                printf("Seek[%s]: %s - %s \n", szMediaType, playCtrlInfo->startTime, playCtrlInfo->endTime);
        }
#endif
    }

    return ret;
}
RtspServer::RtspServer(QObject *parent)
{

}

RtspServer::~RtspServer()
{
    stopSrv();
}

bool RtspServer::startSrv(int port)
{
    // 启动RTSP服务
    if (EasyRtspServer_Startup(port,nullptr,EASY_AUTHENTICATION_TYPE_NONE
                               ,"admin","12345",__EasyRtspServer_Callback,this) < 0) {
        qDebug() << "RTSP服务启动失败";
        printf("startup fail.\n");
        EasyRtspServer_Shutdown();
        return false;
    }
    qDebug() << "RTSP服务启动成功...";
    qDebug() << "rtsp://127.0.0.1:" << port << "/ch[1-7]";
    qDebug() << "rtsp://127.0.0.1:" <<port << "/[rtsp地址]";
    return true;
}

void RtspServer::stopSrv()
{
    EasyRtspServer_Shutdown();
}

main.cpp

cpp 复制代码
#include <QApplication>
#include "rtspserver.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    RtspServer *_rtspServer = new RtspServer;
    _rtspServer->startSrv();
    return a.exec();
}

四 关键代码

SimpleStreamClient库回调函数

主要实现的功能包括:

处理视频流,并通过接口发送数据包给rtsp服务;

处理音频流,并通过接口发送数据包给rtsp服务;

处理事件帧信息;(未使用)

处理媒体信息.(未使用)

int CALLBACK __SimpleStreamClientCallBack(void *_channelPtr, int _frameType, void *pBuf, SIMPLE_FRAME_INFO* frameInfo)

{

RTSP_CHANNEL_T* pChannel = (RTSP_CHANNEL_T*)_channelPtr;

if (_frameType == EASY_SDK_VIDEO_FRAME_FLAG){

if (pChannel->mediaInfo.spsLength < 1 && frameInfo->type == 1)

{

#if 1

if (frameInfo->codec == EASY_SDK_VIDEO_CODEC_H264)

{

GetH264SPSandPPS((char*)pBuf, frameInfo->length,

(char*)pChannel->mediaInfo.sps, (int*)&pChannel->mediaInfo.spsLength,

(char*)pChannel->mediaInfo.pps, (int*)&pChannel->mediaInfo.ppsLength,

(char*)pChannel->mediaInfo.sei, (int*)&pChannel->mediaInfo.seiLength);

qDebug() << "I帧 H264 spslen:" << pChannel->mediaInfo.spsLength << " ppslen:" << pChannel->mediaInfo.ppsLength;

pChannel->mediaInfo.videoCodec = EASY_SDK_VIDEO_CODEC_H264;

}

else if (frameInfo->codec == EASY_SDK_VIDEO_CODEC_H265)

{

GetH265VPSandSPSandPPS((char*)pBuf, frameInfo->length, (char*)pChannel->mediaInfo.vps, (int*)&pChannel->mediaInfo.vpsLength, (char*)pChannel->mediaInfo.sps, (int*)&pChannel->mediaInfo.spsLength, (char*)pChannel->mediaInfo.pps, (int*)&pChannel->mediaInfo.ppsLength);

pChannel->mediaInfo.videoCodec = EASY_SDK_VIDEO_CODEC_H265;

}

qDebug("__EasyStreamClientCallBack Get Media Info: video:%u fps:%u audio:%u channel:%u sampleRate:%u spslen: %d ppslen:%d\n",

pChannel->mediaInfo.videoCodec, pChannel->mediaInfo.videoFps,

pChannel->mediaInfo.audioCodec, pChannel->mediaInfo.audioChannel, pChannel->mediaInfo.audioSampleRate,

pChannel->mediaInfo.spsLength, pChannel->mediaInfo.ppsLength);

#if 0

if (pChannel->mediaInfo.spsLength > 0)

{

pChannel->mediaInfo.videoCodec = frameInfo->codec;

pChannel->mediaInfo.audioCodec = EASY_SDK_AUDIO_CODEC_G711U;

pChannel->mediaInfo.audioSampleRate = 8000;

pChannel->mediaInfo.audioChannel = 1;

pChannel->mediaInfo.audioBitsPerSample = 16;

}

#endif

#endif

}

EASY_AV_Frame avFrameInfo;

bool bSendSpsAndPps = false;

#if 1

if (frameInfo->type == 0x01 && pChannel->mediaInfo.spsLength > 0 && pChannel->mediaInfo.ppsLength > 0)

{

bSendSpsAndPps = true;

if (pChannel->mediaInfo.vpsLength > 0)

{

//VPS

memset(&avFrameInfo, 0x00, sizeof(EASY_AV_Frame));

avFrameInfo.u32AVFrameFlag = _frameType;

avFrameInfo.u32AVFrameLen = pChannel->mediaInfo.vpsLength;

avFrameInfo.u32VFrameType = frameInfo->type;

avFrameInfo.pBuffer = (unsigned char*)(pChannel->mediaInfo.vps);

EasyRtspServer_PushFrame(pChannel->channelHandle, &avFrameInfo);

}

#if 1

//SPS

memset(&avFrameInfo, 0x00, sizeof(EASY_AV_Frame));

avFrameInfo.u32AVFrameFlag = _frameType;

avFrameInfo.u32AVFrameLen = pChannel->mediaInfo.spsLength;

avFrameInfo.u32VFrameType = frameInfo->type;

avFrameInfo.pBuffer = (unsigned char*)(pChannel->mediaInfo.sps);

EasyRtspServer_PushFrame(pChannel->channelHandle, &avFrameInfo);

//PPS

memset(&avFrameInfo, 0x00, sizeof(EASY_AV_Frame));

avFrameInfo.u32AVFrameFlag = _frameType;

avFrameInfo.u32AVFrameLen = pChannel->mediaInfo.ppsLength;

avFrameInfo.u32VFrameType = frameInfo->type;

avFrameInfo.pBuffer = (unsigned char*)(pChannel->mediaInfo.pps);

EasyRtspServer_PushFrame(pChannel->channelHandle, &avFrameInfo);

#endif

}

#endif

memset(&avFrameInfo, 0x00, sizeof(EASY_AV_Frame));

avFrameInfo.u32AVFrameFlag = _frameType;

//rtsp流

avFrameInfo.u32AVFrameLen = frameInfo->length - 4;

avFrameInfo.u32VFrameType = frameInfo->type;

avFrameInfo.pBuffer = (unsigned char*)(pChannel->mediaInfo.sps);

if (bSendSpsAndPps)

{

if (pChannel->mediaInfo.videoCodec == EASY_SDK_VIDEO_CODEC_H264)

{

#if 1

unsigned char* frameData = (unsigned char*)pBuf;

for (unsigned int idx = 0; idx < frameInfo->length - 1; idx++)

{

if (((unsigned char)(frameData)idx == 0x00) &&

((unsigned char)frameDataidx + 1 == 0x01) &&

(((unsigned char)frameDataidx + 2 & 0x1f) == 0x5)) //I帧

{

avFrameInfo.u32AVFrameLen = frameInfo->length - idx - 2;

avFrameInfo.pBuffer = (unsigned char*)(frameData + idx + 2);

break;

}

}

#else

int trim_length = 4 + pChannel->mediaInfo.spsLength;

trim_length += 4 + pChannel->mediaInfo.ppsLength;

if (pChannel->mediaInfo.seiLength > 0) trim_length += 4 + pChannel->mediaInfo.seiLength;

trim_length += 4;

avFrameInfo.u32AVFrameLen = frameInfo->length ;

avFrameInfo.pBuffer = (unsigned char*)((char*)pBuf);

#endif

#if 0

qDebug("h264 I frame:%d\n",avFrameInfo.u32AVFrameLen);

QByteArray arr((char*)avFrameInfo.pBuffer,50);

QString hex = arr.toHex(' ');

qDebug().noquote() <<"前五十个字节:"<< hex;

#endif

}

else if (pChannel->mediaInfo.videoCodec == EASY_SDK_VIDEO_CODEC_H265)

{

#if 0

unsigned char* frameData = (unsigned char*)pBuf;

for (unsigned int idx = 0; idx < frameInfo->length - 1; idx++)

{

if (((unsigned char)(frameData)idx == 0x00) &&

((unsigned char)frameDataidx + 1 == 0x01) &&

((((unsigned char)frameDataidx + 2 & 0x7f) == 19||

((unsigned char)frameDataidx + 2 & 0x7f) == 20))) //I帧

{

avFrameInfo.u32AVFrameLen = frameInfo->length - idx - 2;

avFrameInfo.pBuffer = (unsigned char*)(frameData + idx + 2);

break;

}

}

#else

int trim_length = 4 + pChannel->mediaInfo.vpsLength;

trim_length += 4 + pChannel->mediaInfo.spsLength;

trim_length += 4 + pChannel->mediaInfo.ppsLength;

if (pChannel->mediaInfo.seiLength > 0)

trim_length += 4 + pChannel->mediaInfo.seiLength;

avFrameInfo.u32AVFrameLen = frameInfo->length-trim_length;

avFrameInfo.pBuffer = (unsigned char*)((char*)pBuf+trim_length);

#endif

qDebug("h265 I frame:%d\n",avFrameInfo.u32AVFrameLen);

QByteArray arr((char*)avFrameInfo.pBuffer,50);

QString hex = arr.toHex(' ');

qDebug().noquote() <<"前十个字节:"<< hex;

qDebug("\n");

}

}

else

{

avFrameInfo.pBuffer = (unsigned char*)((char*)pBuf + 4);

#if 0

qDebug("h264 P frame:%d\n",avFrameInfo.u32AVFrameLen);

QByteArray arr((char*)avFrameInfo.pBuffer,50);

QString hex = arr.toHex(' ');

qDebug().noquote() <<"前五十个字节:"<< hex;

#endif

}

EasyRtspServer_PushFrame(pChannel->channelHandle, &avFrameInfo);

}else if(_frameType == EASY_SDK_AUDIO_FRAME_FLAG){

EASY_AV_Frame avFrameInfo;

memset(&avFrameInfo, 0x00, sizeof(EASY_AV_Frame));

avFrameInfo.u32AVFrameFlag = _frameType;

avFrameInfo.u32AVFrameLen = frameInfo->length;

avFrameInfo.u32VFrameType = frameInfo->type;

avFrameInfo.pBuffer = (unsigned char*)pBuf;

EasyRtspServer_PushFrame(pChannel->channelHandle, &avFrameInfo);

}else if(_frameType == EASY_SDK_EVENT_FRAME_FLAG){

}else if(_frameType == EASY_SDK_MEDIA_INFO_FLAG){

EASY_MEDIA_INFO_T* mediainfo = (EASY_MEDIA_INFO_T*)pBuf;

if (pBuf != NULL)

{

memcpy(mediainfo, pBuf, sizeof(EASY_MEDIA_INFO_T));

#if 0

printf("Source;%s Get MediaInfo: video:%u fps:%u audio:%u channel:%u sampleRate:%u spslen: %d ppslen:%d\n",

pChannel->url,

mediainfo->u32VideoCodec, mediainfo->u32VideoFps,

mediainfo->u32AudioCodec, mediainfo->u32AudioChannel, mediainfo->u32AudioSamplerate,

mediainfo->u32SpsLength, mediainfo->u32PpsLength);

#endif

}

if (NULL != mediainfo && NULL != pChannel)

{

pChannel->mediaInfo.audioChannel = mediainfo->u32AudioChannel;

pChannel->mediaInfo.audioSampleRate = mediainfo->u32AudioSamplerate;

pChannel->mediaInfo.audioBitsPerSample = mediainfo->u32AudioBitsPerSample;

pChannel->mediaInfo.vpsLength = mediainfo->u32VpsLength;

if (pChannel->mediaInfo.vpsLength > 0) memcpy(pChannel->mediaInfo.vps, mediainfo->u8Vps, mediainfo->u32VpsLength);

pChannel->mediaInfo.spsLength = mediainfo->u32SpsLength;

if (pChannel->mediaInfo.spsLength > 0) memcpy(pChannel->mediaInfo.sps, mediainfo->u8Sps, mediainfo->u32SpsLength);

pChannel->mediaInfo.ppsLength = mediainfo->u32PpsLength;

if (pChannel->mediaInfo.ppsLength > 0) memcpy(pChannel->mediaInfo.pps, mediainfo->u8Pps, mediainfo->u32PpsLength);

//最后再设置编码类型

pChannel->mediaInfo.audioCodec = mediainfo->u32AudioCodec;

pChannel->mediaInfo.videoCodec = mediainfo->u32VideoCodec;

}

}

return 0;

}

EasyRtspServer库回调函数

主要实现的功能包括:

处理打开媒体流;

处理开始发送流;

处理停止发送流;

处理关闭流;

处理流控制.

int CALLBACK __EasyRtspServer_Callback(EASY_RTSPSERVER_STATE_T serverStatus, const char *resourceName,

EASY_CHANNEL_HANDLE *channelHandle,

EASY_RTSPSERVER_MEDIA_INFO_T *mediaInfo,

EASY_PLAY_CONTROL_INFO_T *playCtrlInfo,

void *userPtr, void *channelPtr)

{

int ret = -1;

qDebug("EasyStreamingServer New Request: %s status%d\n", resourceName, serverStatus );

if (EASY_CHANNEL_OPEN_STREAM == serverStatus)

{

EASY_CHANNEL_HANDLE pChannelHandle = NULL;

qDebug("EasyStreamingServer New Request: %s\n", resourceName);

char szURL260 = { 0 };

#if 0

char filenameMAX_PATH = { 0 };

sprintf(filename, "%s.txt", resourceName);

FILE* f = fopen(filename, "rb");

if (NULL == f)

{

return 0;

}

fgets(szURL, sizeof(szURL), f);

fclose(f);

#else

strcpy(szURL, resourceName);

#endif

int len = (int)strlen(szURL);

for (int i = len - 1; i > 0; i--)

{

if (((unsigned char)szURLi == '\r') ||

((unsigned char)szURLi == '\n'))

{

szURLi = '\0';

}

}

#if 0

if ((int)strlen(szURL) < 3) return 0;

#endif

RTSP_CHANNEL_T *pRtspChannel = new RTSP_CHANNEL_T;

if (NULL == pRtspChannel) return -1;

memset(pRtspChannel, 0x00, sizeof(RTSP_CHANNEL_T));

strcpy(pRtspChannel->url, szURL);// resourceName);

#ifdef EASYSTREALCLIENT

EasyStreamClient_Init(&pRtspChannel->rtspClientHandle, 2);

if (!pRtspChannel->rtspClientHandle)

{

printf("EasyStreamClient_Init Initial fail.\n");

return 0;

}

EasyStreamClient_SetAudioEnable(pRtspChannel->rtspClientHandle, 1);

EasyStreamClient_SetCallback(pRtspChannel->rtspClientHandle, __EasyStreamClientCallBack);

unsigned int mediaType = EASY_SDK_VIDEO_FRAME_FLAG | EASY_SDK_AUDIO_FRAME_FLAG;

EasyStreamClient_OpenStream(pRtspChannel->rtspClientHandle, pRtspChannel->url, EASY_RTP_OVER_TCP, (void*)pRtspChannel, 1000, 1, 1);

#else

SimpleStreamClient_Init(&pRtspChannel->rtspClientHandle, 0);

if (!pRtspChannel->rtspClientHandle)

{

printf("EasyStreamClient_Init Initial fail.\n");

return 0;

}

SimpleStreamClient_SetCallback(pRtspChannel->rtspClientHandle,__SimpleStreamClientCallBack);

SimpleStreamClient_OpenStream(pRtspChannel->rtspClientHandle,pRtspChannel->url,Simple_RTP_OVER_TCP,(void*)pRtspChannel,1000,1,1);

#endif

for (int i=0; i<10*2; i++) //等待5秒

{

if (pRtspChannel->s_mediaInfo.u32VideoCodec>0) break;// && pRtspChannel->mediaInfo.audioCodec) break;

QThread::msleep(100);

}

//设置媒体信息

mediaInfo->videoCodec = pRtspChannel->s_mediaInfo.u32VideoCodec;

mediaInfo->audioCodec = pRtspChannel->s_mediaInfo.u32AudioCodec;

mediaInfo->audioSampleRate = pRtspChannel->s_mediaInfo.u32AudioSamplerate;

mediaInfo->audioChannel = pRtspChannel->s_mediaInfo.u32AudioChannel;

mediaInfo->audioBitsPerSample = pRtspChannel->s_mediaInfo.u32AudioBitsPerSample == 0 ? 16 : pRtspChannel->s_mediaInfo.u32AudioBitsPerSample;

qDebug("Get Source:%s videoCodec:%d,audioCodec:%d,audioSampleRate=%d,pRtspChannel=%x\n",

pRtspChannel->url,

pRtspChannel->s_mediaInfo.u32VideoCodec,

pRtspChannel->s_mediaInfo.u32AudioCodec,

pRtspChannel->s_mediaInfo.u32AudioSamplerate,

pRtspChannel);

#if 1

//此处可指定sps & pps, 也可以不指定

mediaInfo->vpsLength = pRtspChannel->s_mediaInfo.u32VpsLength;

memcpy(mediaInfo->vps, pRtspChannel->s_mediaInfo.u8Vps, mediaInfo->vpsLength);

mediaInfo->spsLength = pRtspChannel->s_mediaInfo.u32SpsLength;

memcpy(mediaInfo->sps, pRtspChannel->s_mediaInfo.u8Sps, mediaInfo->spsLength);

mediaInfo->ppsLength = pRtspChannel->s_mediaInfo.u32PpsLength;

memcpy(mediaInfo->pps, pRtspChannel->s_mediaInfo.u8Pps, mediaInfo->ppsLength);

#endif

mediaInfo->videoFps = 25;

if (pRtspChannel->s_mediaInfo.u32VideoCodec > 0)

{

qDebug("create channel: %s\n", resourceName);

//创建通道

EasyRtspServer_CreateChannel(resourceName, &pChannelHandle, (void *)pRtspChannel);

*channelHandle = pChannelHandle;

pRtspChannel->channelHandle = pChannelHandle;

ret = 0;

}

else //关闭源

{

qDebug("Get Source%s%s sdp fail.\n", resourceName, pRtspChannel->url);

#ifdef EASYSTREALCLIENT

EasyStreamClient_Deinit(pRtspChannel->rtspClientHandle);

#else

SimpleStreamClient_Deinit(pRtspChannel->rtspClientHandle);

#endif

delete pRtspChannel;

pRtspChannel = NULL;

}

}

if (EASY_CHANNEL_START_STREAM == serverStatus)

{

RTSP_CHANNEL_T *pRtspChannel = (RTSP_CHANNEL_T *)channelPtr;

pRtspChannel->status = 0x01; //开始发送流

}

if (EASY_CHANNEL_STOP_STREAM == serverStatus)

{

RTSP_CHANNEL_T *pRtspChannel = (RTSP_CHANNEL_T *)channelPtr;

pRtspChannel->status = 0x00; //停止发送流

}

else if (EASY_CHANNEL_CLOSE_STREAM == serverStatus)

{

qDebug("#######################Close Stream: %s\n", resourceName);

RTSP_CHANNEL_T *pRtspChannel = (RTSP_CHANNEL_T *)channelPtr;

if (NULL != pRtspChannel)

{

if (NULL != pRtspChannel->rtspClientHandle)

{

#ifdef EASYSTREALCLIENT

EasyStreamClient_Deinit(pRtspChannel->rtspClientHandle);

#else

SimpleStreamClient_Deinit(pRtspChannel->rtspClientHandle);

#endif

}

qDebug("Close Source OK: %s %s\n", resourceName, pRtspChannel->url);

EasyRtspServer_DeleteChannel(&pRtspChannel->channelHandle);

delete pRtspChannel;

pRtspChannel = NULL;

}

ret = 0;

}

else if (EASY_CHANNEL_PLAY_CONTROL == serverStatus)

{

//以下为播放控制, 用于录像回放时使用

#if 0

printf("RTSP_CHANNEL_PLAY_CONTROL: %s\n", resourceName);

RTSP_CHANNEL_T *pRtspChannel = (RTSP_CHANNEL_T *)channelPtr;

if (NULL != pRtspChannel)

{

char szMediaType16 = {0};

if (EASY_SDK_VIDEO_FRAME_FLAG == playCtrlInfo->mediaType) strcpy(szMediaType, "Video");

else if (EASY_SDK_AUDIO_FRAME_FLAG == playCtrlInfo->mediaType) strcpy(szMediaType, "Audio");

else if (EASY_SDK_EVENT_FRAME_FLAG == playCtrlInfo->mediaType) strcpy(szMediaType, "Metadata");

if (EASY_PLAY_CTRL_CMD_GET_DURATION == playCtrlInfo->ctrlCommand)

printf("GetDuration... %s\n", szMediaType);

else if (EASY_PLAY_CTRL_CMD_PAUSE == playCtrlInfo->ctrlCommand)

printf("Pause...%s\n", szMediaType);

else if (EASY_PLAY_CTRL_CMD_RESUME == playCtrlInfo->ctrlCommand)

printf("Resume...%s\n", szMediaType);

else if (EASY_PLAY_CTRL_CMD_SCALE == playCtrlInfo->ctrlCommand)

printf("Scale%s: %.2f\n", szMediaType, playCtrlInfo->scale);

else if (EASY_PLAY_CTRL_CMD_SEEK_STREAM == playCtrlInfo->ctrlCommand)

printf("Seek%s: %s - %s \n", szMediaType, playCtrlInfo->startTime, playCtrlInfo->endTime);

}

#endif

}

return ret;

}

五 运行日志

RTSP服务启动成功...

rtsp://127.0.0.1: 8554 /ch1-7

rtsp://127.0.0.1: 8554 /rtsp地址

EasyStreamingServer New Request: ch1 status1

EasyStreamingServer New Request: ch1

Get Source:ch1 videoCodec:28,audioCodec:0,audioSampleRate=0,pRtspChannel=9c000d20

create channel: ch1

EasyStreamingServer New Request: ch1 status6

EasyStreamingServer New Request: ch1 status6

EasyStreamingServer New Request: ch1 status2

EasyStreamingServer New Request: ch1 status6

EasyStreamingServer New Request: ch1 status6

EasyStreamingServer New Request: ch1 status4

EasyStreamingServer New Request: ch1 status5

#######################Close Stream: ch1

Close Source OK: ch1 ch1