Qt截屏 X265lib編碼 rtsp請(qǐng)求 rtp流發(fā)送 (rtsp)實(shí)現(xiàn)

\color{rgb(125,125,125)}{什么是rtsp協(xié)議,作用是什么?}
rtsp跟http一樣都是七層應(yīng)用層協(xié)議.在rtsp協(xié)議組中的主要作用是:
\color{rgb(255,125,0)}{返回支持的方法}
\color{rgb(255,125,0)}{客戶(hù)端->發(fā)送客戶(hù)端監(jiān)聽(tīng)的rtp rtcp端口號(hào)}
\color{rgb(255,125,0)}{服務(wù)端->發(fā)送服務(wù)端監(jiān)聽(tīng)的rtp rtcp端口號(hào)}
\color{rgb(255,125,125)}{下面是支持vlc,ffplay的rtsp的請(qǐng)求響應(yīng)過(guò)程:}
1.客戶(hù)端發(fā)送OPTIONS請(qǐng)求:

客戶(hù)端(ffplay)請(qǐng)求報(bào)文:
OPTIONS rtsp://127.0.0.1:1133 RTSP/1.0\r\nCSeq: 1\r\nUser-Agent: Lavf57.83.100\r\n\r\n}$
服務(wù)端響應(yīng)報(bào)文:
RTSP/1.0 200 OK\r\nCSeq:"+QString::number(cseq)+"\r\nPublic:DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE\r\n\r\n
//服務(wù)器返回了服務(wù)器支持的方法;
//注意請(qǐng)求和返回都是\r\n\r\n結(jié)尾。

2.客戶(hù)端發(fā)送DESCRIBE請(qǐng)求

客戶(hù)端發(fā)送DESCRIBE請(qǐng)求
DESCRIBE rtsp://127.0.0.1:1133 RTSP/1.0\r\nAccept: application/sdp\r\nCSeq: 2\r\nUser-Agent: Lavf57.83.100\r\n\r\n"
服務(wù)端響應(yīng)客戶(hù)端請(qǐng)求.
"c=IN IP4 127.0.0.1\r\nm=video 0 RTP/AVP 96\r\na=rtpmap:96 H265/90000\r\na=fmtp:96 profile-space=0;profile-id=0;tier-flag=0;level-id=0\r\n\r\n"
//注釋?zhuān)篴=rtpmap:96 H265/90000  96表示媒體類(lèi)型是視頻预吆,H265/90000表示h265編碼波特率是90000

3.客戶(hù)端SETUP請(qǐng)求:

客戶(hù)端setup請(qǐng)求報(bào)文
"SETUP rtsp://127.0.0.1:1133 RTSP/1.0\r\nTransport: RTP/AVP/UDP;unicast;client_port=\color{rgb(255,0,0)}{20260-20261}\r\nCSeq: 3\r\nUser-Agent: Lavf57.83.100\r\n\r\n"
//紅色為客戶(hù)端監(jiān)聽(tīng)的端口號(hào).
服務(wù)端響應(yīng)報(bào)文
"RTSP/1.0 200 OK\r\nCSeq:0\r\nTransport: RTP/AVP;unicast;client_port=18174-0;server_port=\color{rgb(255,0,0)}{1130-1131};ssrc=\color{rgb(0,0,255)}{Wang_qin_feng18174_0}\r\nSession:\color{rgb(0,255,0)}{Wang_qin_feng18174_0}\r\n\r\n"
//紅色部分為server rtp-rtcp端口號(hào)乏梁,藍(lán)色部分和綠色部分為會(huì)話(huà)唯一標(biāo)識(shí),類(lèi)似于http的會(huì)話(huà)保持.

4.客戶(hù)端發(fā)送PLAY請(qǐng)求

客戶(hù)端PLAY請(qǐng)求報(bào)文
"PLAY rtsp://127.0.0.1:1133 RTSP/1.0\r\nRange: npt=0.000-\r\nCSeq: 4\r\nUser-Agent: Lavf57.83.100\r\nSession: Wang_qin_feng18174_0\r\n\r\n"
服務(wù)端返回報(bào)文
"RTSP/1.0 200 OK\r\nCSeq: 0\r\nSession:Wang_qin_feng10540_0\r\nRTP-Info: url=rtsp://127.0.0.1:1133;seq=9810092;rtptime=0\r\n\r\n"

5.此時(shí)ffplay等待server rtp端口號(hào)(1130)發(fā)送來(lái)的數(shù)據(jù).
rtsp的實(shí)現(xiàn):
cache.h全局緩存

#ifndef CACHE_H
#define CACHE_H
#include <QList>
#include <QHostAddress>
#include "rtp.h"
struct rtp_rtcp_struct{
  int rtp; //客戶(hù)端端口
  int rtcp; //客戶(hù)端端口
  QHostAddress ip; //客戶(hù)端地址
};
extern rtp_rtcp_struct s_s_p;
extern QList<rtp_rtcp_struct> client_rtp_rtcp_list;
extern rtp rtp_server;
class cache
{
public:
    cache();
};

#endif // CACHE_H

cache.cpp

#include "cache.h"
#include <QList>

rtp_rtcp_struct s_s_p;
QList<rtp_rtcp_struct> client_rtp_rtcp_list;
rtp rtp_server;
cache::cache()
{

}

rtsp.h

#define RTSP_H
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
class rtsp : public QTcpServer
{
    Q_OBJECT
public:
    explicit rtsp(int rtp,int rtcp,QTcpServer *parent = nullptr);
    void incomingConnection(qintptr socket_number);
signals:
public slots:
private:
    int server_rtp;
    int server_rtcp;
};
//客戶(hù)端連接
class connect_socket :public QTcpSocket{
    Q_OBJECT
public:
    explicit connect_socket(int rtp,int rtcp,qintptr   socket_number,QTcpSocket *parent=nullptr);
    enum return_error{
        no_error=0,
        no_vision= -1,
        no_rtp_rtcp_port=-2,
    };
signals:
private:
    int router(QStringList head); //請(qǐng)求方法路由
    void send_methon();    //返回支持的方法
    void send_rtp_rtcp_session(); //返回會(huì)話(huà)端口號(hào)等信息
    void send_sdp();    //發(fā)送sdp文件
    int verison;
    int client_rtp_port; //client 監(jiān)聽(tīng)rtp的端口號(hào)
    int client_rtcp_port; //client 監(jiān)聽(tīng)的rtcp的端口號(hào)
    int server_rtp_port; 
    int server_rtcp_port;
    int cseq=0;
    QByteArray SSRC="Wang_qin_feng";
public slots:
    void read_data();
};
#endif // RTSP_H

rtsp.cpp

#include "rtsp.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QThread>
#include <QDebug>
#include <QDateTime>
#include <QByteArray>
#include "cache.h"
rtsp::rtsp(int rtp,int rtcp,QTcpServer *parent) : QTcpServer(parent)
{
    server_rtp=rtp; 
    server_rtcp=rtcp;
}
//新的tcp socket連接時(shí)創(chuàng)建一個(gè)新的連接.
void rtsp::incomingConnection(qintptr socket_number){
 //new一個(gè)新的socket連接
    connect_socket *client_socket=new connect_socket(server_rtp,server_rtcp,socket_number);
 //創(chuàng)建一個(gè)線(xiàn)程.
    QThread *client_socket_thread=new QThread();
    client_socket->moveToThread(client_socket_thread);
    client_socket_thread->start();
}
connect_socket::connect_socket(int rtp,int rtcp,qintptr socket_number,QTcpSocket *parent):QTcpSocket (parent){
    this->setSocketDescriptor(socket_number);
    server_rtp_port=rtp; //server rtp_port
    server_rtcp_port=rtcp; //server rtcp_port
//有數(shù)據(jù)傳入是調(diào)用槽
    connect(this,SIGNAL(readyRead()),this,SLOT(read_data()));
};
void connect_socket::read_data(){ 
    QString tmp_data;
    tmp_data=this->readAll();
    if(tmp_data.size()>50){ //因?yàn)関lc有傳空請(qǐng)求來(lái)!所有判定下長(zhǎng)度
        QStringList request_body=tmp_data.split(" ");
//        qDebug()<<tmp_data;
      //按不同的請(qǐng)求路由到不同的處理方法.
        router(request_body);
    }
}
int connect_socket::router(QStringList head){
    return_error error_return;
    error_return=no_error; //正常返回0;
    QString methon=head[0];

    cseq=head[3].split("\r\n")[0].toInt();
    if(methon=="OPTIONS"){ //本版獲取
        error_return=no_vision;
            if(head[2].contains("\r\n")){
                QStringList verison_list=head[2].split("\r\n");
                //rtsp獲取版本號(hào)
                if(verison_list[0].contains("/")){verison=verison_list[0].split("/")[0].toInt();}else {
                    return  error_return;
                    };
                send_methon(); //發(fā)送支持的方法給客戶(hù)端;
            }else {
                //無(wú)版本號(hào)返回-1;
                error_return=no_vision;
                return error_return;
            }
    }else if (methon=="SETUP") { //setup請(qǐng)求
        error_return=no_rtp_rtcp_port;
        //從請(qǐng)求中取出rtp rtcp端口號(hào)
        if(head[head.length()-1].contains("\r\n\r\n")){
            int client_port_index=0;
            for(int i=0;i<head.length();i++){
                if(head[i].contains("=") and head[i].contains("-")){
                    client_port_index=i;
                }
            }
            QStringList port_list=head[client_port_index].split("\r\n\r\n")[0].split("=")[1].split("-");
            client_rtp_port=port_list[0].toInt();
            client_rtcp_port=port_list[1].toInt();
                        //添加客戶(hù)端端口號(hào)到列表
            s_s_p.rtp=client_rtp_port;
            s_s_p.rtcp=client_rtcp_port;
            s_s_p.ip= this->peerAddress();
            client_rtp_rtcp_list.append(s_s_p);
                        //返回會(huì)話(huà)數(shù)據(jù)
            send_rtp_rtcp_session();
            }else {
                        return error_return;
                    }
    }else if (methon=="PLAY") {
        QString url;
        if(head.size()>=1){
            url=head[1];
        }
        QByteArray data;
        data.append("RTSP/1.0 200 OK\r\nCSeq: "+QString::number(cseq)+"\r\nSession: "+SSRC+"\r\n"+"RTP-Info: url="+url
                    +";seq=9810092;rtptime=0\r\n\r\n");
        this->write(data);
//        qDebug()<<data;
        this->waitForBytesWritten(3000);
    }else if (methon=="DESCRIBE") {
            send_sdp();
    }else{
    }
    return  error_return;
};
void connect_socket::send_methon(){ //發(fā)送支持的方法
    QByteArray data;
    data.append("RTSP/1.0 200 OK\r\n CSeq:"+QString::number(cseq)+"\r\nPublic:DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE\r\n\r\n");
    this->write(data);
    this->waitForBytesWritten(3000);
}
void connect_socket::send_rtp_rtcp_session(){ //發(fā)送會(huì)話(huà)數(shù)據(jù)
    SSRC+=QString::number(client_rtp_port)+"_"+QString::number(client_rtcp_port);
    QByteArray data;
    data.append("RTSP/1.0 200 OK\r\nCSeq:"+QString::number(cseq)+"\r\nTransport: RTP/AVP;unicast;client_port="+
            QString::number(client_rtp_port)+"-"+QString::number(client_rtcp_port)+";"
            +"server_port="+QString::number(server_rtp_port)+"-"+QString::number(server_rtcp_port)+";"
            +"ssrc="+SSRC+"\r\nSession:"+SSRC+"\r\n\r\n");
//    qDebug()<<data;
    this->write(data);
    this->waitForBytesWritten(3000);
}
void connect_socket::send_sdp(){
    QByteArray tmp_data;
    QByteArray data;
    tmp_data.append("c=IN IP4 "+this->peerAddress().toString().split(":")[3]+"\r\nm=video 0 RTP/AVP 96\r\na=rtpmap:96 H265/90000\r\na=fmtp:96 profile-space=0;profile-id=0;tier-flag=0;level-id=0\r\n\r\n");
    data.append( "RTSP/1.0 200 OK\r\nCSeq:"+QString::number(cseq)+"\r\nContent-Type: application/sdp\r\nContent-Length:"
                 +QString::number(tmp_data.size())+"\r\n\r\n");
    data.append(tmp_data);
//    qDebug()<<tmp_data;
    this->write(data);
    this->waitForBytesWritten(3000);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末杜漠,一起剝皮案震驚了整個(gè)濱河市腰湾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌处坪,老刑警劉巖根资,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異同窘,居然都是意外死亡玄帕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)想邦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)裤纹,“玉大人,你說(shuō)我怎么就攤上這事丧没∮ソ罚” “怎么了锡移?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)吹零。 經(jīng)常有香客問(wèn)我罩抗,道長(zhǎng),這世上最難降的妖魔是什么灿椅? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任套蒂,我火速辦了婚禮,結(jié)果婚禮上茫蛹,老公的妹妹穿的比我還像新娘操刀。我一直安慰自己,他們只是感情好婴洼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布骨坑。 她就那樣靜靜地躺著,像睡著了一般柬采。 火紅的嫁衣襯著肌膚如雪欢唾。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天粉捻,我揣著相機(jī)與錄音礁遣,去河邊找鬼。 笑死肩刃,一個(gè)胖子當(dāng)著我的面吹牛祟霍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盈包,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼沸呐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了呢燥?” 一聲冷哼從身側(cè)響起崭添,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叛氨,沒(méi)想到半個(gè)月后滥朱,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡力试,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年徙邻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畸裳。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缰犁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情帅容,我是刑警寧澤颇象,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站并徘,受9級(jí)特大地震影響遣钳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜麦乞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一蕴茴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧姐直,春花似錦倦淀、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至插龄,卻和暖如春愿棋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背均牢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工糠雨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人膨处。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像砂竖,于是被迫代替她去往敵國(guó)和親真椿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子安聘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容