懒人李冰

记录我的生活、学习

RTMP协议学习(中):源码分析

了解了 RTMP 协议规范后,本文主要记录下 RTMPDump 源码的学习过程。

大致流程

使用RTMP下载流媒体的主要流程包括以下几个步骤:

  • InitSocket()
  • RTMP_Init(Struct RTMP)
  • RTMP_ParseURL
  • RTMP_SetupStream
  • fopen
  • RTMP_Connect()
  • RTMP_ConnectStream
  • Download
  • CleanUp:RTMP_Close(&rtmp); fclose(file); CleanupSockets();

下面逐个记录各个步骤的功能。 在了解具体步骤之前,先了解结构重要的Structure:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
typedef struct RTMP
{
    int m_inChunkSize;
    int m_outChunkSize;
    int m_nBWCheckCounter;
    int m_nBytesIn;
    int m_nBytesInSent;
    int m_nBufferMS;
    int m_stream_id;
    int m_mediaChannel;
    uint32_t m_mediaStamp;
    uint32_t m_pauseStamp;
    int m_pausing;
    int m_nServerBW;
    int m_nClientBW;
    uint8_t m_nClientBW2;
    uint8_t m_bPlaying;
    uint8_t m_bSendEncoding;
    uint8_t m_bSendCounter;

    int m_numInvokes;
    int m_numCalls;
    RTMP_METHOD *m_methodCalls;
}

InitSocket()

初始化 Socket ,代码非常简单。

1
2
3
4
5
6
7
8
9
10
11
12
int InitSockets()
{
#ifdef WIN32
    WORD version;
    WSADATA wsaData;

    version MAKEWORD(1, 1);       
    return (WSASTartup(version, &wsaData) == 1);
#else
    return TRUE;
#endif
}

RTMP_Init(Struct RTMP)

初始化 RTMP 结构体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void RTMP_Init(RTMP *r)
{
#ifdef CRYPTO
    if(!RTMP_TLS_cts)
        RTMP_TLS_Init();
#endif

    memset(r, 0, sizeof(RTMP));
    r->m_sb.sb_socket = -1;
    r->m_inChunkSize  = RTMP_DEFAULT_CHUNKSIZE;
    r->m_outChunkSize = RTMP_DEFAULT_CHUNKSIZE;
    r->m_nBufferMS    = 30000;
    r->m_nClientBW    = 2500000;
    r->m_nClientBW2   = 2;
    r->m_nServerBW    = 2500000;
    r->m_fAudioCodecs = 3191.0;
    r->m_fVideoCodecs = 252.0;
    r->Link.timeout   = 20;
    r->Link.swfAge    = 30;
}

RTMP_ParseURL

URL 一般由三部分组成: 资源类型、存放资源的主机域名、资源文件名。 语法格式为([]为可选项):protocol://hostname[:port]/path/[:parameters][?query]#fragment protocol(协议名称)、hostname(主机名)、port(端口号)、path(路径)、parameters(参数)。

RTMP_ParseURL函数定义:

1
int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, AVal *playpath, AVal *app);

从函数定义的几个参数可以看出,url 被定位为 const 型,即该参数在函数内部不可改变,而protocol、host、port、palypath、app 则是在函数内部根据url来进行解析,之后进行赋值的。

RTMP_SetupStream

fopen

RTMP_Connect()

RTMP_ConnectStream

Download

CleanUp:RTMP_Close(&rtmp); fclose(file); CleanupSockets();