アンドロイドMediaPlayerのRTSP(2):FFmpegの分析コードフローのRTSP

免責事項:この記事はブロガーオリジナル記事ですが、許可ブロガーなく再生してはなりません。https://blog.csdn.net/myvest/article/details/80884516

背景:

RTSPはFFmpegの異なるバージョンでは若干異なる場合があり、FFmpegのRTSPの章では、関連するコードの主な流れを紹介し、いくつかの構造を含み、詳細FFmpegは、レイシャオ華グレート神のブログを参照することができます興味を持っているFFmpegの詳細な分析で説明されることはありませんhttps://my.csdn.net/leixiaohua1020。

1、キー構造のff_rtsp_demuxer:

この構造モジュール、カプセル開放装置のオーディオおよびビデオファイルを逆多重化AVInputFormat呼ばれ、RTSPプロトコルにこのような媒体は、FFmpegのがパックフォーマットとして扱われ、主インタラクションプロセスRTSPプロトコル処理段階もDEMUX 。

AVInputFormat ff_rtsp_demuxer = {
    "rtsp",
    NULL_IF_CONFIG_SMALL("RTSP input format"),
    sizeof(RTSPState),
    rtsp_probe,
    rtsp_read_header,
    rtsp_read_packet,
    rtsp_read_close,
    rtsp_read_seek,
    .flags = AVFMT_NOFILE,
    .read_play = rtsp_read_play,
    .read_pause = rtsp_read_pause,
    .priv_class = &rtsp_demuxer_class,
};

我々はav_register_allインターフェースを呼び出すと、あなたはAVFMT_NOFILE設定されたフラグを参照することができ、登録ff_rtsp_demuxerに来ます。
FFmpegのにミュクサーは、設定されたフラグとメンバ変数に設ける必要がないデミュクサーAVFMT_NOFILE、AVIOContext(プレゼンテーションコンテキストバイトストリーム入力/出力)を有し、そして場合ミュクサーのデミュクサーは独自のプロセス入力/出力を使用するため。
簡単に言えば、入力は、このタイプのファイルI / Oが実行されるのURLProtocol RTSP分析が、処理のデマルチプレクサを使用していません。
そこで、我々は、ハンドラを、対応するff_rtsp_demuxerが最もあるに焦点を当てる必要があります。

av_register_all:

    REGISTER_MUXDEMUX(RTSP, rtsp);

2、ファイルrtsp_read_headerを開きます

次のようにユーバープレーヤーのRTSPアドレスを開くためにavformat_open_input機能、read_headerする呼び出すと、コードは次のとおりです。

avformat_open_input:
    if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
        if ((ret = s->iformat->read_header(s)) < 0)
            goto fail;

呼プロトコルread_headerデマルチプレクサ機能に対応する、リードヘッドの再生フォーマットを初期化します。
次のようにff_rtsp_demuxerにおいて、rtsp_read_header主機能コードは次のとおり

rtsp_read_header:

	{
	    RTSPState *rt = s->priv_data;
	    int ret;
	    
	redirect:
	    av_log(NULL, AV_LOG_INFO, "[%s:%d]\n", __FUNCTION__, __LINE__);
	    rt->send_keepalive=0;
	    ret = ff_rtsp_connect(s);
	    if (ret)
	        return ret;
	......
	    if (rt->initial_pause) {
	         /* do not start immediately */
	    } else {
	         ret = rtsp_read_play(s);
	         if (ret < 0) {
	            ff_rtsp_close_streams(s);
	            ff_rtsp_close_connections(s);
	            if(ret <=-300&& ret > -400)//add by wusc for redirect
	                goto redirect;
	            return AVERROR_INVALIDDATA;
	        }
	    } 
	......
	}

rtsp_read_header主に以下の2つのワーク:
1、オプションを含む接続プロセス- > DESCRIBE - >セットアップ手順。
PLAYを入力するかどうかの設定に応じて2、。

2.1プロセスの段階を接続

> DESCRIBE - - >セットアップ手順ff_rtsp_connect機能は、OPTIONSを完了します。
各コマンド応答の前端は、FFmpegのが解析されます。

 if ((ret = ff_rtsp_read_reply(s, reply, content_ptr, 0, method) ) < 0){
av_log(s, AV_LOG_INFO, "ff_rtsp_read_reply  %s error  status_code: %d\n", method,
            reply->status_code);
     return ret;
 	}
 	
ff_rtsp_read_reply:

     ff_rtsp_parse_line(reply, p, rt, method);
     av_strlcat(rt->last_reply, p,    sizeof(rt->last_reply));
     av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply));

次のようにRTSP相互作用メインコードのプロセスである:
1、実施再生パラメータアドレスURLを解析し、含まれる「UDP」/「TCP」/によると 、「HTTP」、 lower_transport_maskフラグ、セットアップステージのlower_transport_mask表す、基礎となるRTPデータ支援の伝送を提供しますどのようなプロトコルの種類(UDP / TCPまたはサポート)

ff_rtsp_connect:

            if (!strcmp(option, "udp")) {
                lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_UDP);
            } else if (!strcmp(option, "multicast")) {
                lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
            } else if (!strcmp(option, "tcp")) {
                lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_TCP);
            } else if(!strcmp(option, "http")) {
                lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_TCP);
                rt->control_transport = RTSP_MODE_TUNNEL;
            } else if (!strcmp(option, "filter_src")) {
                rt->filter_source = 1;

2は、関係なく、RTPデータストリームのオープンRTSPインタラクティブなTCP接続は、部分的にTCPやUDPに基づいており、RTSPプロトコルの相互作用は、TCPに基づいているので、最初のURLは、TCPリンクを開く、「TCP」タブをマーク。あなたは、ポート番号を指定しない場合、デフォルトのRTSPポート番号は554です。

ff_rtsp_connect:

        /* open the tcp connection */
        ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL);
        if(rt->use_protocol_mode){
		av_strlcat(tcpname, "?rcvbuf_size=1024", sizeof(tcpname));
        }
   	 int ret=ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE);

図3は、OPTIONS要求を送信します

ff_rtsp_connect:

        ff_rtsp_send_cmd(s, "OPTIONS", rt->control_uri, cmd, reply, NULL);

図4に示すように、送信要求を記述し、記事を参照することができるSDPメッセージを解析し、フィードバックの前端にSDPメッセージを解析します。

请求
ff_rtsp_connect:

    if (s->iformat && CONFIG_RTSP_DEMUXER)
        err = ff_rtsp_setup_input_streams(s, reply);
        
ff_rtsp_setup_input_streams:

    ff_rtsp_send_cmd(s, "DESCRIBE", rt->control_uri, cmd, reply, &content);

解析SDP
ff_rtsp_setup_input_streams:

    /* now we got the SDP description, we parse it */
    ret = ff_sdp_parse(s, (const char *)content);

図5は、SETUP要求を送信する
:SETUP要求ff_rtsp_make_setup_requestは、コアコード、主コードロジックの以下の分析である
。1)、伝送プロトコルRTPを指定lower_transport_maskは、上記設定に従って決定lower_transport担体です。

ff_rtsp_connect:

        int lower_transport = ff_log2_tab[lower_transport_mask &
                                  ~(lower_transport_mask - 1)];
        float value = 0.0;
        int ret = -1;        
        av_log(NULL, AV_LOG_INFO, "[%s:%d]lowtrans=%d,lowtransm=%d,value=%d\n", __FUNCTION__,__LINE__, lower_transport,lower_transport_mask,value);
        err = ff_rtsp_make_setup_request(s, host, port, lower_transport,
                                 rt->server_type == RTSP_SERVER_REAL ?
                                     real_challenge : NULL);

2)指定された転送プロトコルSDPメッセージに従ってRT->輸送、キャリアが提供される接頭SETUP要求プロトコル

ff_rtsp_make_setup_request:

    if (rt->transport == RTSP_TRANSPORT_RDT)
        trans_pref = "x-pn-tng";
    else if (rt->transport == RTSP_TRANSPORT_RAW)
        trans_pref = "RAW/RAW";    
    else if (NULL != strstr(rt->server, "ZXUS") || NULL != strstr(rt->server, "ZMSS"))//wusc add for ZXUS/ZMSS  server
        trans_pref = "MP2T/RTP";
    else
        trans_pref = "RTP/AVP";

3)契約のキャリアによっては、その後の処理の流れも多少異なりますが、我々は、最も一般的なTCPおよびUDPプロトコル解析を持っています。
TCPモードの輸送MP2T / RTP / TCP、
ユニキャスト、インターリーブ= 0-1 TCP送信モードであれば、
変速機が設けられている、すなわち、接頭辞プラス/ TCP(MP2T / RTP / TCP )、 ユニキャスト集合つつ。ユニキャスト
B.は、= 0-1インターリーブとして設定されたパラメータを、インターリーブ。送信されたRTP、RTCPパケットが同じリンク上にあるため、0 RTP、RTCPチャネルは1によって表されるチャネルを表すインターリーブ有するので、それは、区別する必要がある、インタリーブは、2つの値:0、0 RTPを示しパケットは、RTCPパケットがインターリーブされたパケットであるデータの種類を区別するために受信側の値に応じて、1を表します。

ff_rtsp_make_setup_request:
        else if (lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
        ......
            snprintf(transport, sizeof(transport) - 1,
                     "%s/TCP;", trans_pref);
            if (rt->transport != RTSP_TRANSPORT_RDT)
                av_strlcat(transport, "unicast;", sizeof(transport));
            av_strlcatf(transport, sizeof(transport),
                        "interleaved=%d-%d",
                        interleave, interleave + 1);
            interleave += 2;
        }

UDPモードトランスポート:MP2T / RTP / UDP;
ユニキャスト; CLIENT_PORT = 5000から5001 UDP伝送を使用する場合は、
最初のポートもff_url_joinがオープンRTPをffurl_open、「RTP」タブをマークし、チャネルとしてRTSPのペアとRTCP RTPチャネルが必要です。伝送チャネル。
B。伝送モードを設定し、すなわち、接頭辞プラス/ UDP(MP2T / RTP / UDP )。ユニキャストユニキャストを設定します。
c.UDPは、フロントエンドは、RTPにデータを送信するためにどのポートを知っている必要があるように、フロントエンドに彼らが使用するRTPとRTCPポート番号を送信します、CLIENT_PORTパラメータを実行する必要があります。

ff_rtsp_make_setup_request:

                while (j <= RTSP_RTP_PORT_MAX) {
                    ff_url_join(buf, sizeof(buf), "rtp", NULL, host, -1,
                                "?localport=%d", j);
                    /* we will use two ports per rtp stream (rtp and rtcp) */
                    j += 2;
                    if (ffurl_open(&rtsp_st->rtp_handle, buf, AVIO_FLAG_READ_WRITE) == 0){
			av_log(NULL, AV_LOG_INFO, "[%s]ffurl_open,handle=%d\n", __FUNCTION__, rtsp_st->rtp_handle);
                        goto rtp_opened;
                    }

......
        rtp_opened:
            port = rtp_get_local_rtp_port(rtsp_st->rtp_handle);
        have_port:
            snprintf(transport, sizeof(transport) - 1,
                     "%s/UDP;", trans_pref);
            if (rt->server_type != RTSP_SERVER_REAL)
                av_strlcat(transport, "unicast;", sizeof(transport));
            av_strlcatf(transport, sizeof(transport),
                     "client_port=%d", port);
            if (rt->transport == RTSP_TRANSPORT_RTP &&
                !(rt->server_type == RTSP_SERVER_WMS && i > 0))
                av_strlcatf(transport, sizeof(transport), "-%d", port + 1);
        

6.SETUP応答メッセージ解析
キャリアがプロトコルをサポートしていない、提供されている場合、フロントエンド461が応答します

RTSP / 1.0 461サポートされていない輸送

サーバー:ZXUSS100 1.0

CSeq:3

461の場合は、FFmpegのキャリアは、この合意がlower_transport_mask == 0(すなわち、いくつかのプロトコルは裁判が終わっクライアントによって設定されている)まで、新しいlower_transport_maskを設定できませんでしキャンセルさせていただきます。

ff_rtsp_connect:

        err = ff_rtsp_make_setup_request(s, host, port, lower_transport,
                                 rt->server_type == RTSP_SERVER_REAL ?
                                     real_challenge : NULL);
        if (err < 0)
            goto fail;
        lower_transport_mask &= ~(1 << lower_transport);
        if (lower_transport_mask == 0 && err == 1) {
            err = AVERROR(EPROTONOSUPPORT);
            goto fail;
        }
    } while (err);

成功した場合に送信されたSETUPメッセージは、
1)、TCPモードのためのキャリアは、フロントエンドサーバは、RTP / RTCPチャネル番号としてFFmpegのインターリーブされた仮パラメータを返信します。

ff_rtsp_make_setup_request:

        case RTSP_LOWER_TRANSPORT_TCP:
            rtsp_st->interleaved_min = reply->transports[0].interleaved_min;
            rtsp_st->interleaved_max = reply->transports[0].interleaved_max;
            break;

RTSP / 1.0 200 OK

CSeq:4

サーバー:Wowzaストリーミングエンジン4.7.5.01 build21752

Cache-Control:キャッシュなし

有効期限:木、2018年7月5日3時56分01秒UTC

トランスポート:RTP / AVP / TCP;ユニキャスト、インターリーブされた= 0-1

日付:木、2018年7月5日午前3時56分01秒UTC

セッション:1531975305;タイムアウト= 60

2)、UDPモード用キャリアは、フロントエンドサーバがパラメータを返信するサーバポートSERVER_PORTで、RTP送信元サーバアドレスを示します。RTPは、このIPとポートへのリンクが必要になります。

ff_rtsp_make_setup_request:

            if (reply->transports[0].source[0]) {
                ff_url_join(url, sizeof(url), "rtp", NULL,
                            reply->transports[0].source,
                            reply->transports[0].server_port_min, "%s", options);
            } else {
                ff_url_join(url, sizeof(url), "rtp", NULL, host,
                            reply->transports[0].server_port_min, "%s", options);
            }

            if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) &&
                rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
                err = AVERROR_INVALIDDATA;
                goto fail;
            }

RTSP / 1.0 200 OK

サーバー:ZMSS_ChinaTelcom2.2 / ZXMSSV3.00.23.13U10P01P07T01

CSeq:4

セッション:791434909882685964

日付:木、2018年午前12時41分40秒GMT 5月10日

有効期限:木、2018年5月10日12時41分40秒GMT

トランスポート:
RTP / AVP / UDP、ユニキャスト、ソース= 210.13.2.51; CLIENT_PORT = 5000から5001; SERVER_PORT = 30146から30147

一方、UDPモードのために、我々は、サーバーが正常にクライアントの流れをプッシュすることができるように、SERVER_PORT、短いRTPパケット送信サーバへ、すなわちソースとクライアントのニーズをNATホールパンチングパケットを送信するために最善を尽くします。そうでない場合は、ネットワーク内のネットワークの数のために、PLAY後に再生することはできません。

ff_rtsp_make_setup_request:

            if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && s->iformat &&
                CONFIG_RTPDEC){
                    if(NULL != strstr(rt->server, "ZXUS") || NULL != strstr(rt->server, "ZMSS")){
                        av_log(s, AV_LOG_ERROR, "ZXUS/ZMSS  server send NAT after PLAY\n");
                    }else{
                        rtp_send_zte_punch_packets(rtsp_st->rtp_handle,rt->rtsp_hd);//ZTE NAT
                        rtp_send_punch_packets(rtsp_st->rtp_handle);
                    }
                }
            break;

フロントエンドの一部は、先のパラメータを返し、そして一緒にCLIENT_PORT、プッシュRTPデータのフロントエンドという、クライアントは先= 192.168.1.16、以下の実施例からIPアドレスとポートを受け取ります。ネットワークは、ネットワークを見ることができるで、このような状況をNATは、そうでない場合は、データを受信することもできません。

輸送:
MP2T / RTP / UDP;宛先= 192.168.1.16; CLIENT_PORT = 5000から5001; SERVER_PORT = 8000から8001、ソース= 239.2.1.242

図7に示すように、後続のRTPデータ解析のためのRTP相担体の実施例では、IPアドレス、ポートオープンRTPインタラクションコンテキストを設定SETUPに係ります。

ff_rtsp_make_setup_request: 

        if ((err = rtsp_open_transport_ctx(s, rtsp_st)))

これまでのところff_rtsp_connectプロセスはほぼ完了です。次の段階は、その後、rtsp_read_playに入りました。

2.2 PLAYステージ

ff_rtsp_connect完全なクライアントとサーバがrtsp_read_playを入力して、良好な接続を確立しています。
1、PLAYパラメータ、主に範囲を設定し、これらの2つのパラメータをスケール。
1)レンジが設定値に応じて、上側スプライシングを要求されたデータの再生位置を示し、いくつかがあります
期間;.要求する必要が絶対時間の説明、クロック= XXX-ビデオデータを表すために使用される
Bはによれば、位置を説明します。それは0-から放送されている場合= NTP;再生がNPT = XXX-0提供した場合、シークダウン上部の相対位置を設定し、前方の遊びの場合は、NPT = XXX-設けられている
Cの位置の説明を、説明文字列を、= NOW- NPT; =開始NPT -xxx; NPT = 0、END; これらは可能であり、
事実とB、BとCの実現には、次の2種類、位置は説明と同様。

2)スケール上層操作に応じてダウンセットされ、再生の速度を示しています。

rtsp_read_play:

设置Range
	      // time scale function
            // seek, fast-forward/fast-rewind triggered seek 
            if (rt->playback_rate_permille != rt->playback_rate_permille_next)
                    rt->playback_rate_permille = rt->playback_rate_permille_next;
            if(rt->playseekFlag == 1){
                    snprintf(cmd, sizeof(cmd),"Range: clock=%s.00Z-\r\n",rt->playseekTime);
            }else{
                    if (rt->playback_rate_permille >= 0) {
                         // forward
                         snprintf(cmd, sizeof(cmd),
		   "Range: npt=%"PRId64".%03"PRId64"-\r\n",
		   rt->seek_timestamp / AV_TIME_BASE,
		   rt->seek_timestamp / (AV_TIME_BASE / 1000) % 1000);
                    } else {
                          // backward
                         snprintf(cmd, sizeof(cmd),
		   "Range: npt=%"PRId64".%03"PRId64"-0\r\n",
		   rt->seek_timestamp / AV_TIME_BASE,
		   rt->seek_timestamp / (AV_TIME_BASE / 1000) % 1000);
                    }
     }


设置Scale   
            length = strlen (cmd);
            snprintf(&cmd [length], sizeof(cmd) - length,
                            "Scale: %d.%d\r\n",
                            rt->playback_rate_permille / 1000,
                            rt->playback_rate_permille % 1000);
            // length = strlen (cmd); 


2、PLAY要求を送信します

PLAY RTSP://61.149.64.212:554 /ライブ/ ch11091521361097960208.sdp /
RTSP / 1.0

範囲:クロック= 20180628T065101.00Z-

スケール:1.0

CSeq:4

セッション:65538918

RTSP / 1.0 200 OK

サーバー:ZXUSS100 1.0

CSeq:4

範囲:クロック= 20180628T065101.00Z-20180628T065158.98Z

スケール:1.0

セッション:65538918

RTP-情報:
URL = RTSP://61.149.64.132:11842 /ライブ/ ch11091521361097960208.sdp / trackID = 2; SEQ = 0; rtptime = 453338458

コードは以下の通りであります:

rtsp_read_play:

    ff_rtsp_send_cmd(s, "PLAY", rt->control_uri, cmd, reply, NULL);

RTPは、関連する情報が、それは、分析関数はrtsp_parse_rtp_info、比較的簡単に解決され、詳細に展開しないことを示している:PLAYを送信した後、あなたは、RTP-INFOメッセージに返信することを決議する必要があります。しかし、懸念はRTP-infoです:ときRTP-Infoで勝訴することができ、戻りのフロントエンド運ばurlは異なるソースSETUPかもしれません。

これまでのところ、PLAYも完了しています。
ブロードキャストプロトコルの相互作用のプロセスが完了するから、全体rtsp_read_headerは、終了しました。解決策は、私たちがrtsp_read_packet機能を見て、プレーの流れをプルダウンすることです。

3、プレイrtsp_read_packet

プロセスは、実質的にデータ・ストリームを再生得ることで、注射は、我々は唯一のストリーム部分を引っ張る、関連部分、すなわち、に焦点を当てRTSPをデカプセル化復号されます。
播種が今必要とされているrtsp_read_header RTSPプロトコルの相互作用の一部、上に完了しているので、データを再生するために取得することです。
上位層データストリーム取得プルff_read_packet使用される場合、RTSPに対応read_packetデマルチプレクサの機能は、対応するrtsp_read_packetに呼び出します。

.read_packet    = rtsp_read_packet,

rtsp_read_packet、ff_rtsp_fetch_packetのコア部分

rtsp_read_packet:
	ret = ff_rtsp_fetch_packet(s, pkt);

キャリアはデータが読み出され、クライアントは、TCPのキャリアモードをサポートしている場合、それはTCPのキャリアに切り替わります、UDPモードです。これは、プロトコルの相互作用のプロセス上で再取るTEARDOWNのと同じです。

rtsp_read_packet:
        if (ret == AVERROR(ETIMEDOUT) && !rt->packets) {
            if (rt->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
                rt->lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_TCP)) {
                RTSPMessageHeader reply1, *reply = &reply1;
                av_log(s, AV_LOG_WARNING, "UDP timeout, retrying with TCP\n");
                if (rtsp_read_pause(s) != 0)
                    return -1;
                // TEARDOWN is required on Real-RTSP, but might make
                // other servers close the connection.
                if (rt->server_type == RTSP_SERVER_REAL)
                    ff_rtsp_send_cmd(s, "TEARDOWN", rt->control_uri, NULL,
                                     reply, NULL);
                rt->session_id[0] = '\0';
                if (resetup_tcp(s) == 0) {
                    rt->state = RTSP_STATE_IDLE;
                    rt->need_subscription = 1;
                    if (rtsp_read_play(s) != 0)
                        return -1;
                    goto retry;
                }
            }
        }

3.1カーネルff_rtsp_fetch_packet

次に、ff_rtsp_fetch_packetダウンロードセクションコア機能の分析は、機能は、ダウンロードしてメディアデータを解析を完了します。

最後のRTPパケットがまだ完全には完全に解決されていない場合1は、この最後のRTPパケットを解決するために続けています。
RTPのカプセル化によるデータ伝送、それぞれ3つの分析関数を取る:
1)RDTコールff_rdt_parse_packet解析、独自の転送プロトコル実RM形式のファイルであり、
2)データは、呼ff_rtp_parse_packet解析し、RTPパケットである場合
3)データである場合裸のトランスポートストリームフォーマット、解析コールavpriv_mpegts_parse_packetは、
本明細書RTPカプセル化は、一般的なプロセスの詳細な分析をすることなく、説明します。次のように関数のパラメータは次のとおりです。

/ **

  • 直接バッファとして送信RTPまたはRTCPパケットを解析します。
  • @param sのRTPの解析コンテキスト。
  • @paramのPKTは、パケットを返さ
  • 次のパケットを読み取るための入力バッファまたはNULLを指すポインタBUFPTR @param
  • @param緩衝液のみのみ
  • パケットが返された場合、パケットが返された場合、1を0に@return、より従うことができます
  • (次を読み取るためにNULLとしてBUFを使用)。-1無しパケット(エラーまたはこれ以上のパケット)の場合。
    * /
    int型ff_rtp_parse_packet(RTPDemuxContext * S、AVPacket * PKT、
    uint8_t ** BUFPTR、int型のLEN)
ff_rtsp_fetch_packet:

    /* get next frames from the same RTP packet */
    if (rt->cur_transport_priv) {
        if (rt->transport == RTSP_TRANSPORT_RDT) {
            ret = ff_rdt_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
        } else if (rt->transport == RTSP_TRANSPORT_RTP) {
            ret = ff_rtp_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
        } else if (CONFIG_RTPDEC && rt->ts) {
            ret = avpriv_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf + rt->recvbuf_pos, rt->recvbuf_len - rt->recvbuf_pos);
            if (ret >= 0) {
                rt->recvbuf_pos += ret;
                ret = rt->recvbuf_pos < rt->recvbuf_len;
            }

2最後のRTPパケットが決意を完了している場合、それは新しいRTPパケットを受信し、解析します。
コード受信データ:
1)はTCPキャリアff_rtsp_tcp_read_packet呼び出し
2)UDPキャリアコールudp_read_packetと、のUDP、データを受信した後の各時間の後、フィードバックパケット遠位端を送信する必要がある、現在受信したデータの数、機能ff_rtp_check_and_send_back_rrを呼び出します。

機能とフィードバック機能を受信し、基礎となる実装ffurl_readへの各呼び出しは、/他のカプセル化されたインターフェイスをffurl_write。適切なプロトコルインターフェイスに呼び出します。

ff_rtsp_fetch_packet:

	    default:
	#if CONFIG_RTSP_DEMUXER
	    case RTSP_LOWER_TRANSPORT_TCP:
	        len = ff_rtsp_tcp_read_packet(s, &rtsp_st, rt->recvbuf, RECVBUF_SIZE);
	        break;
	#endif
	    case RTSP_LOWER_TRANSPORT_UDP:
	    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
	        len = udp_read_packet(s, &rtsp_st, rt->recvbuf, RECVBUF_SIZE, wait_end);
	        if (len > 0 && rtsp_st->transport_priv && rt->transport == RTSP_TRANSPORT_RTP)
	            ff_rtp_check_and_send_back_rr(rtsp_st->transport_priv, rtsp_st->rtp_handle, NULL, len);
	        break;

上記RTPデータ解析処理を受けた後の解析処理の後、本質的に同じです。

3.2、ハートビートを報告

報告されたハートビートパケットの送信などGET_PARAMETER

rtsp_read_packet:

    if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN)) {
        /* send dummy request to keep TCP connection alive */
        if ((av_gettime_relative() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2 ||
            rt->auth_state.stale) {
            if (rt->server_type == RTSP_SERVER_WMS ||
                (rt->server_type != RTSP_SERVER_REAL &&
                 rt->get_parameter_supported)) {
                ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL);
            }

このように、プルを演奏解析部RTSPストリーミングメディアストリームが終了し
、メインプロセスが3つあります。データを受信- > RTPを解析- >ハートビート送信
上部リード関数呼び出しを常に再生が実現し、データを受信し、それをデコーダに書き込みます。

概要

前節に基づいて、RTSP FFmpegのコード解析に主に関連するコードフロー部分とデータのダウンロードプロトコル相互作用部でした。合意、私たちはより明確にRTSPプロトコルを理解することを可能にするコードの解析部の特にインタラクティブ一部。
FFmpegのは私たちに非常に優れたフレームワークの青写真を与えたが、フロントケースの実際の状況は異なっている、我々はいくつかの適応作業を行う必要があります。特にUDPの場合には、後の記事で、実際のプロジェクトでは、コードの一部に変更を含むであろう。

おすすめ

転載: blog.csdn.net/myvest/article/details/80884516