Introduction to librtmp library API and its structure overview

Introduction to librtmp library API and its structure overview

rtmp is a common streaming media protocol. It is an application layer protocol proposed by Adobe. rtmp transmits encapsulated data in flv format, which generally stores H.264 video stream and AAC audio stream.

librtmp library realizes the client function of rtmp protocol and a few server functions. It is a good tool for learning rtmp.

This paper introduces the main API s of librtmp and arranges the general implementation framework of librtmp, but it does not go deep into the specific details. This article is not an introductory article, but a general summary. I hope it will be helpful to those who want to use librtmp and those with librtmp education.

Before you want to deeply understand how librtmp works, please understand the FLV encapsulation format and rtmp protocol.

1. Use of librtmp API

1.1 usage process of librtmp API

The usage process of librtmp API can be summarized as follows:

  1. Allocate and initialize an RTMP instance

  2. Set parameters of RTMP instance

  3. Call RTMP_ The connect function connects to the server

  4. Call rtmp_ The connectstream function creates an rtmp stream

  5. Use RTMP_Read or RTMP_Write to read and write, or control the rtmp flow (such as pause, stop, etc.)

  6. After reading and writing, turn off and release RTMP

‚Äč

In librtmp, the structure RTMP is used to represent an RTMP connection.

In step 2, set the rtmp connection according to your needs, and librtmp will do the corresponding operation according to our settings. Note that only parameters are set here, which have not been used yet. Consider the following two interfaces:

//Set the duration of buffering in milliseconds
void RTMP_SetBufferMS(RTMP *r, int size);
//Send the control packet of "set buffer duration"
void RTMP_UpdateBufferMS(RTMP *r);

The former only saves the parameter size to instance r, while the latter uses the parameter in instance r and plays a practical role.

Therefore, it should be noted: generally, we only set parameters in step 2, and it is not recommended to set parameters in other places, because setting parameters and the actual role of this parameter are two concepts. Of course, if you know how librtmp works, you can set it elsewhere.

After connecting to the rtmp server and establishing a rtmp stream, we can perform relevant operations on this stream. For example, you can pause, stop and other operations, or read or write to the rtmp stream.

After the related operations are completed, the RTMP instance must be closed and released.

1.2 example of librtmp

Let's first look at two examples of using librtmp API to understand its API and usage process.

First, an example of saving a read rtmp stream as a flv file is given:

https://blog.csdn.net/leixiaohua1020/article/details/42104893

Then there is an example of uploading local files to the rtmp server:

https://blog.csdn.net/leixiaohua1020/article/details/42104945

After knowing the above two examples in detail, you can learn the API of librtmp in detail and systematically.

1.3 librtmp API details

Through the above examples, we know that RTMP type is a very important type in librtmp. Now let's take a look at its related API s.

We don't need to check the specific composition of RTMP first. We just need to know that it represents an RTMP stream. The following is the most basic API related to RTMP.

These basic API s include: allocate, initialize, close rtmp stream, and release.

1.3.1 chunk and message in librtmp

First, let's learn about the structures related to chunk and Message in librtmp and their related operations.

The following structures correspond to chunk and Mesage respectively:

/*
    Represents a raw chunk, the original chunk

    c_header,c_headerSize: Save the data and size of chunk header
    c_chunk,c_chunkSize:Save the data and size of chunk data
*/
typedef struct RTMPChunk
{
    int c_headerSize;
    int c_chunkSize;
    char *c_chunk;
    char c_header[RTMP_MAX_HEADER_SIZE];
} RTMPChunk;

/*
    Represents a Message

    m_headerType        : Represents M_ The type of chunk, that is, fmt in basic header in chunk header
    m_packetType        : Indicates the Message Type ID
    m_hasAbsTimestamp   : Indicates whether the timestamp is absolute or relative, that is, when chunk type is 0, it is the absolute timestamp, and when other types are the increment of timestamp
    m_nChannel          : Indicates the chunk Stream ID
    m_nTimeStamp        : time stamp
    m_nInfoField2       : chunk fmt When it is 0, the last four bytes of the header, that is, the Message Stream ID
    m_nBodySize         : Message Size of the body
    m_nBytesRead        : The number of bytes of the body that have been read
    m_chunk             : If it is not NULL, it means that the user wants to get chunk, and this field will be filled in when reading Message
    m_body              : Message My body
*/
typedef struct RTMPPacket
{
    uint8_t m_headerType;
    uint8_t m_packetType;
    uint8_t m_hasAbsTimestamp;	/* timestamp absolute or relative? */
    int m_nChannel;
    uint32_t m_nTimeStamp;	/* timestamp */
    int32_t m_nInfoField2;	/* last 4 bytes in a long header */
    uint32_t m_nBodySize;
    uint32_t m_nBytesRead;
    RTMPChunk *m_chunk;
    char *m_body;
} RTMPPacket;

//Empty all fields (buffer is still in)
void RTMPPacket_Reset(RTMPPacket *p);
//Print packet
void RTMPPacket_Dump(RTMPPacket *p);
//Allocate buffer for p, including fixed size header and nSize size body
int RTMPPacket_Alloc(RTMPPacket *p, int nSize);
//Free buffer
void RTMPPacket_Free(RTMPPacket *p);

//Whether the packet is complete
#define RTMPPacket_IsReady(a)	((a)->m_nBytesRead == (a)->m_nBodySize)

Note the following:

  • chunk has only one structure to save its original content, but no structure with detailed related fields;
  • The field name in message is somewhat specious, and the content contained seems to be confused with the content of chunk. This is because librtmp is the product of reverse engineering. The author guesses the content of rtmp protocol according to the actual rtmp packet and reversely parses rtmp protocol. At that time, Adobe had not published the content of rtmp protocol;

1.3.2 RTMP basic API

//Assign an RTMP
//Its operation is only to allocate a memory of RTMP size, and RTMP can also be allocated on the stack
RTMP *RTMP_Alloc(void);

//Initialize RTMP and set each field of RTMP as the default value
void RTMP_Init(RTMP *r);

//Close this RTMP. If it is currently connected, the connection will be closed; Then release RTMP related content
void RTMP_Close(RTMP *r);

//Freeing memory for RTMP
void RTMP_Free(RTMP *r);

1.3.3 setting RTMP properties

After allocating and initializing an RTMP instance, you need to set the properties of the RTMP instance. The following is the API related to setting the properties.

//Resolve RTMP address
//The format of the url is: protocol://host:port/app/playpath , return the parsed fields through parameters
int RTMP_ParseURL(const char *url, int *protocol, AVal *host,
                  unsigned int *port, AVal *playpath, AVal *app);

//Resolve playpath from RTMP URL
void RTMP_ParsePlaypath(AVal *in, AVal *out);

//Set the duration of buffering in milliseconds
void RTMP_SetBufferMS(RTMP *r, int size);

//Set relevant properties of RTMP
//If the property specified by opt does not exist, RTMP is called_ Optusage() prints out all properties of RTMP.
int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg);

//Print rtmp all attributes
static void RTMP_OptUsage();

//Set url
int RTMP_SetupURL(RTMP *r, char *url);

//Set flow
void RTMP_SetupStream(RTMP *r, int protocol,  
                      AVal *hostname,                 
                      unsigned int port,
                      AVal *sockshost,
                      AVal *playpath,
                      AVal *tcUrl,
                      AVal *swfUrl,
                      AVal *pageUrl,
                      AVal *app,
                      AVal *auth,
                      AVal *swfSHA256Hash,
                      uint32_t swfSize,
                      AVal *flashVer,
                      AVal *subscribepath,
                      int dStart,
                      int dStop, int bLiveStream, long int timeout);

//Set RTMP Link add write attribute
//That is, you need to pulish a stream instead of play a stream
void RTMP_EnableWrite(RTMP *r);

First, RTMP_ParseURL() and RTMP_ParsePlaypath() is two helper functions that are used to protocol://host:port/app/playpath String, which is parsed into the corresponding fields, and then set to the RTMP example.

The last five functions are the functions that set properties. Where, RTMP_SetBufferMS() and RTMP_EnableWrite() can only set a single related attribute: the former sets the "buffer duration", and the latter tells librtmp that we should use polish instead of play, that is, we should push the stream to the server rather than pull the stream from the server.

The remaining three functions are essentially the same without any difference, but provide different forms of interfaces for setting properties. RTMP_SetOpt() will set different properties according to opt; RTMP_SetupURL() will call RTMP at the bottom_ Parseurl() function, and then set the parsed fields to different attributes of RTMP instances; RTMP_SetupStream() provides a convenient interface that allows us to set all properties at one time.

So, what properties can RTMP set? We won't repeat it here. Please check the introduction of rtmpdump, which introduces the related properties of RTMP in detail.

1.3.4 connecting to the server

/*
    The client initiates a TCP connection with the server and executes Connect

    RTMP was called internally_ Connect0 to complete the TCP connection
    Call RTMP_Connect1 completed connect
*/
int RTMP_Connect(RTMP *r, RTMPPacket *cp);
struct sockaddr;
//Write host and port information to sockaddr_in
static int add_addr_info(struct sockaddr_in *service, AVal *host, int port);
//Connect to the specified address (server address or proxy address), only at the TCP layer
int RTMP_Connect0(RTMP *r, struct sockaddr *svc);
//It is assumed that the connection at the TCP level has been completed
//handshake and send Connect Message
int RTMP_Connect1(RTMP *r, RTMPPacket *cp);

//The server handles handshake successfully, and the return value is greater than 0
int RTMP_Serve(RTMP *r);

From the perspective of users, there is nothing in this part, just know RTMP_Connect() function can connect to rtmp server.

1.3.5 create rtmp stream

//Connect to the stream specified by the url and return TRUE and flare
int RTMP_ConnectStream(RTMP *r, int seekTime);

This step is also relatively simple. You only need to set enough properties before calling it. Especially the following two points:

  • Set the correct url information
  • If it is a push stream, that is, polish, RTMP is called_ Enablewrite(), if a stream, play, is played, no additional settings are required. The default is play.

1.3.6 operation of RTMP stream

After the rtmp stream is created, you can perform relevant operations on this stream. rtmp stream operations can be divided into three categories: one is control operations, such as pause, stop, resume, reconnect, interrupt and so on; The second type is the query class interface, which returns the current state of rtmp stream; The last type is read-write operation, which is used to read or write rtmp stream data.

1.3.6.1 control API
//Send "set buffer time" control packet
void RTMP_UpdateBufferMS(RTMP *r);
//Pause or resume flow
int RTMP_ToggleStream(RTMP *r);
//Reconnect the stream, that is, connect the stream again after deleting the stream, and wait for synchronization until the stream starts
int RTMP_ReconnectStream(RTMP *r, int seekTime);
//Stop the flow, or delete the flow
void RTMP_DeleteStream(RTMP *r);
//RTMP process interrupted
//The essence is to set the global variable RTMP_ CTRL C is true
void RTMP_UserInterrupt(void);	/* user typed Ctrl-C */

The so-called API of control class is the API that will change the current rtmp flow. From the user's point of view, it is generally to pause, resume, stop and other operations on the rtmp stream, while there are other operations on the rtmp protocol level. Here, we only focus on the former. No matter what kind of API, they are implemented by sending an RTMP Msg.

1.3.6.2 query API
//Is RTMP connected
int RTMP_IsConnected(RTMP *r);
//Returns the socket associated with RTMP
int RTMP_Socket(RTMP *r);
//Is RTMP interrupted
int RTMP_IsTimedout(RTMP *r);
//Gets the length of the current RTMP stream
double RTMP_GetDuration(RTMP *r);

View the relevant status or information of the current rtmp stream.

1.3.6.3 read write API
//RTMP reads a packet, which is not guaranteed to read a complete packet
int RTMP_ReadPacket(RTMP *r, RTMPPacket *packet);
//RTMP is used to send packet s, and queue indicates whether to send according to the queue
int RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue);
//RTMP sends a chunk
int RTMP_SendChunk(RTMP *r, RTMPChunk *chunk);

//Reading data using RTMP
int RTMP_Read(RTMP *r, char *buf, int size);
//Write data using RTMP
int RTMP_Write(RTMP *r, const char *buf, int size);

There are many read-write interfaces in librtmp. If you don't know, you don't know which functions should be called to complete our functions.

The above are the five most commonly used read-write API s. Just remember for a moment and be able to use them. We will introduce the reading and writing process of librtmp in detail below.

2. Reading and writing process of librtmp data stream

Only when we have a comprehensive understanding of the data parsing process of librtmp library can we have an overall grasp of this library and make more rational use of this library. And through this process to confirm the learning of RTMP protocol, which is the most important.

According to my own understanding, the data analysis process is divided into multiple levels. Let's understand the analysis process one by one from bottom to top.

2.1 transport layer

The standard rtmp protocol uses TCP protocol to transmit data at the bottom, while some variants of rtmp protocol may use HTTP protocol to transmit data. No matter which protocol is used, this part has and only has the function of data transmission, so we call it the transport layer.

The transport layer pair provides a set of unified interfaces to encapsulate different transmission protocols. The interfaces are as follows:

//Read N bytes and return the number of bytes actually read
static int ReadN(RTMP *r, char *buffer, int n);

//Write N bytes and return the number of bytes actually written
static int WriteN(RTMP *r, const char *buffer, int n);

The transport layer relies on the lower TCP interface and HTTP interface.

2.1.1 TCP interface

The definitions related to TCP layer are as follows, which are relatively simple:

/*
	RTMPSockBuf: RTMP Socket cache for
    Represents a TCP socket connection and its read cache

    sb_socket   : Socket socket
    sb_size     : buffer The number of unprocessed bytes in, that is, the size of the buffered data
    sb_start    : Point to the bytes to be processed in the buffer, that is, point to the buffered data
    sb_buf      : Data read buffer
    sb_timedout : Whether the socket is interrupted
    sb_ssl      : SSL related data 
*/
typedef struct RTMPSockBuf
{
    int sb_socket;
    int sb_size;		/* number of unprocessed bytes in buffer */
    char *sb_start;		/* pointer into sb_pBuffer of next byte to process */
    char sb_buf[RTMP_BUFFER_CACHE_SIZE];	/* data read from socket */
    int sb_timedout;
    void *sb_ssl;
} RTMPSockBuf;

//TCP level operations: read, write, close
int RTMPSockBuf_Fill(RTMPSockBuf *sb);
int RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len);
int RTMPSockBuf_Close(RTMPSockBuf *sb);

2.1.2 HTTP layer interface

The interface of HTTP layer is also relatively simple, as shown below:

//HTTP level operations: read, write
static int HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len);
static int HTTP_read(RTMP *r, int fill);

2.2 Message read / write layer

This layer is above the transport layer. Its function is to read and write messages and chunks.

This layer is a very simple read-write layer. It directly parses the data read from the transport layer without processing the parsed Message and Chunk. It also directly calls the transport layer interface to write relevant data regardless of the content of the data to be written.

Features: analyze the data, but do not process the content of the data, but hand it over to a higher level for processing.

/*
    Function: read a chunk, and then check whether the chunk can synthesize a complete Message
    Default condition: before and after the function call, the first byte of the current stream is the start byte of the new Chunk

    If the packet is read, relevant data can be obtained through the packet
    If the packet has not been read, the relevant data cannot be obtained through the packet, but the relevant information can be obtained
*/
int RTMP_ReadPacket(RTMP *r, RTMPPacket *packet);

/*
	After splitting msg into chunk, write chunk
	  1 Analyze the type of chunk used by msg
	  2 Split msg into chunk	
	  3 When msg is command msg, relevant fields are processed
	The underlying layer calls the write () function instead of RTMP_SendPacket() function
*/
int RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue);

/*
	Write to chunk directly, but this function is not used in rtmp library. It is recommended not to use it
	Content: just write chunk
	The underlying layer calls the write() function
*/
int RTMP_SendChunk(RTMP *r, RTMPChunk *chunk)

2.3 business layer

Above the Message read-write layer, the business layer performs relevant and necessary business processing, including:

  • Processing of non media messages sent by the server
  • Filter non media messages
  • Process seek operation
  • Handle resume operation
  • Filter video and audio RTMP messages with too small size

In this way, after passing through the business layer, the media data and meta object data that the user wants to obtain are returned. The so-called "user wants to get" here includes the seek and resume operations specified by the user.

/* Read from the stream until we get a media packet.
 * Returns -3 if Play.Close/Stop, -2 if fatal error, -1 if no more media
 * packets, 0 if ignorable error, >0 if there is a media packet
 *
 * Read data from the stream until a media packet is obtained
 * What is a media packet? Please check RTMP_GetNextMediaPacket() function
 * Return value: indicates the status of the current RTMP stream, that is, RTMP_READ.status, as follows:
 *          If there is a negligible error, it returns 0. If the media packet is read, it returns a positive value
 *
 * Function: process the set RTMP connection and return the media RTMPPacket
 *
 * 1 Process seek
 * 2 Processing resume
 * 3 Filter non media RTMP packets (by calling RTMP_GetNextMediaPacket())
 * 4 Filter video audio rtmppacket with too small size
 */
static int Read_1_Packet(RTMP *r, char *buf, unsigned int buflen);

/*
    Get a Media message

    Ignore messages that are not media messages until media messages are obtained. This function calls RTMP_ The readpacket function reads a Message and then calls RTMP_ClientPacket processes the read Message.

    What is media Message? See RTMP for details_ ClientPacket
*/
int RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet)

/*
    Client processing Message
    Return value:
        1 Indicates that the packet is audio, video, metadata message (one of object msg) and aggregate message
        2 Indicates that the packet is command message and play Complete or play Stop and so on indicate that the flow is suspended or ended
        0 Indicates other message s

    This function calls various types of messages by calling the following handle message block
    
    When the return value is greater than 0, it indicates that the packet is a media packet, that is, the packet really contains media data, or some media have ended or paused, and it is temporarily impossible to obtain real media data. Therefore, it is returned to prevent the logic from getting stuck here.
*/
int RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)

2.4 FLV read / write layer

After the rtmp stream is processed by the business layer, there are only media data and meta object data left, but these data still exist in the form of Message. Sometimes, we need to save media data in the form of byte stream, that is, byte stream in FLV format. Therefore, there is flv read-write layer, which functions as follows:

  • When Read, convert the media data in Message format into FLV TAG format; When writing, the opposite is true
  • When reading, complete the FLV Header part; When writing, skip the FLV Header section

This is why the first rtmp example above saves the rtmp stream as a flv file and uses the flv read / write layer interface; Moreover, in the second example, there are different examples of using flv read-write layer and Message read-write layer API s respectively. The biggest difference lies in the byte stream form of FLV TAG and the Message form of RTMPPacket structure.

/*
    Read data, FLV level

    The returned value is an FLV data stream, just like RTMP_Write writes an FLV data stream
    1 Complete flv tag = = > rtmppacket, RTMP_Write is the opposite
    2 Complete the FLV data stream, such as adding FLV Header

    Return value:
        0   Indicates that reading the RTMP stream has been completed
        -1  Indicates that an error has occurred
        >0  Indicates the number of bytes actually read
*/
int RTMP_Read(RTMP *r, char *buf, int size)

/*
    Write part of the flv file in turn. Note: generally, any part of FLV file cannot be omitted. Of course, if you want to ignore some data, then
    [FLVHeader + first preTagSize] or any [FLVTAG+preTagSize] can be ignored

    The part actually written is FLV TAG, and other parts will be ignored. TAGHeader will be parsed to Msg Header, and TAGBody is Msg Body.

    RTMP_Write Encapsulate the incoming data as RTMPPacket, and then call RTMP_ The sendpacket() function sends.

    Return value: successfully returns the number of bytes actually written. Failure returns - 1.
*/
int RTMP_Write(RTMP *r, const char *buf, int size)

2.5 others: processing and sending messages

In the above business layer, RTMP will be called after reading a Message_ Clientpacket() to process the read Message. In this function, different processing functions will be called according to the type of Message, that is, the following function with the form of "Handle * * * ()".

Please note that the naming of these processing functions here indicates that these functions are internal functions of the framework rather than external interfaces.

If you are interested in rtmp protocol, you can check the contents of these functions in detail to confirm the relevant protocol contents.

static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize);
static int HandleMetadata(RTMP *r, char *body, unsigned int len);
static void HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet);
static void HandleAudio(RTMP *r, const RTMPPacket *packet);
static void HandleVideo(RTMP *r, const RTMPPacket *packet);
static void HandleCtrl(RTMP *r, const RTMPPacket *packet);
static void HandleServerBW(RTMP *r, const RTMPPacket *packet);
static void HandleClientBW(RTMP *r, const RTMPPacket *packet);

Corresponding to the above, when we want to make certain modifications to the RTMP stream, we need to Send a Message packet to the other party. The specific interfaces for sending packets are as follows. They are functions in the form of "Send * * * ()" or "RTMP_Send * * * ()". Of course, in librtmp, there are other interfaces built on these interfaces for sending Message packets. When we encounter them, we should be able to easily distinguish them.

The same as above. If you are interested in the specific content of rtmp protocol, you can check the details of these functions.

static int SendConnectPacket(RTMP *r, RTMPPacket *cp);
static int SendCheckBW(RTMP *r);
static int SendCheckBWResult(RTMP *r, double txn);
static int SendDeleteStream(RTMP *r, double dStreamId);
static int SendReleaseStream(RTMP *r);
static int SendFCPublish(RTMP *r);
static int SendPublish(RTMP *r);
static int SendFCUnpublish(RTMP *r);
static int SendFCSubscribe(RTMP *r, AVal *subscribepath);
static int SendPlay(RTMP *r);
static int SendBytesReceived(RTMP *r);
int RTMP_SendCreateStream(RTMP *r);
int RTMP_SendPause(RTMP *r, int DoPause, int iTime)
int RTMP_SendSeek(RTMP *r, int iTime);
int RTMP_SendServerBW(RTMP *r);
int RTMP_SendClientBW(RTMP *r);
int RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime);

3.rtmpdump example

This example comprehensively shows how to use librtmp as a client. If you don't know how to use librtmp, you can refer to this example.

4. Reference articles

This article is only an outline document, far from clearing the details of librtmp. Readers can refer to other people's relevant articles. Among them, Raytheon's librtmp series articles are very detailed and are rare good materials. The address is as follows: https://blog.csdn.net/leixiaohua1020/article/details/15814587 .

5. Comment code

The following is my RTMP H documents:

#ifndef __RTMP_H__
#define __RTMP_H__
/*
 *      Copyright (C) 2005-2008 Team XBMC
 *      http://www.xbmc.org
 *      Copyright (C) 2008-2009 Andrej Stepanchuk
 *      Copyright (C) 2009-2010 Howard Chu
 *
 *  This file is part of librtmp.
 *
 *  librtmp is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2.1,
 *  or (at your option) any later version.
 *
 *  librtmp is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with librtmp see the file COPYING.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA  02110-1301, USA.
 *  http://www.gnu.org/copyleft/lgpl.html
 */

#if !defined(NO_CRYPTO) && !defined(CRYPTO)
#define CRYPTO
#endif

#include <errno.h>
#include <stdint.h>
#include <stddef.h>

#include "amf.h"

#ifdef __cplusplus
extern "C"
{
#endif

//Version number of this library
#define RTMP_LIB_VERSION	0x020300	/* 2.3 */

//FEATURE of rtmp
#define RTMP_FEATURE_HTTP	0x01
#define RTMP_FEATURE_ENC	0x02
#define RTMP_FEATURE_SSL	0x04
#define RTMP_FEATURE_MFP	0x08	/* not yet supported */
#define RTMP_FEATURE_WRITE 	 0x10 	/*  publish, not play * / / / stream instead of play
#define RTMP_FEATURE_HTTP2 	 0x20 	/*  Server side rtmpt * / / / rtmpt on server side

//The protocol types of rtmp and its variants are essentially a combination of the above features
#define RTMP_PROTOCOL_UNDEFINED	-1
#define RTMP_PROTOCOL_RTMP      0
#define RTMP_PROTOCOL_RTMPE     RTMP_FEATURE_ENC
#define RTMP_PROTOCOL_RTMPT     RTMP_FEATURE_HTTP
#define RTMP_PROTOCOL_RTMPS     RTMP_FEATURE_SSL
#define RTMP_PROTOCOL_RTMPTE    (RTMP_FEATURE_HTTP|RTMP_FEATURE_ENC)
#define RTMP_PROTOCOL_RTMPTS    (RTMP_FEATURE_HTTP|RTMP_FEATURE_SSL)
#define RTMP_PROTOCOL_RTMFP     RTMP_FEATURE_MFP

//Default max chunk size
#define RTMP_DEFAULT_CHUNKSIZE	128

//The size of the receiving buffer at the SocketBuffer level
/* needs to fit largest number of bytes recv() may return */
#define RTMP_BUFFER_CACHE_SIZE (16*1024)

//The maximum value that chunk Stream id can express
#define	RTMP_CHANNELS	65600

//The string name of the protocol type of rtmp and its variants, in lowercase
//There is also a corresponding uppercase version in RTMP C, which is not open to users
extern const char RTMPProtocolStringsLower[][7];
//Default Flash version number string description
extern const AVal RTMP_DefaultFlashVer;
//Indicates the ctrl-c interrupt mechanism
extern int RTMP_ctrlC;

//Get current time
uint32_t RTMP_GetTime(void);

//Message Type ID
#define RTMP_PACKET_TYPE_AUDIO 0x08 //audio message
#define RTMP_PACKET_TYPE_VIDEO 0x09 //video message
#define RTMP_PACKET_TYPE_INFO  0x12 //command message

//The chunk header consists of three parts, and the size of each part can be changed
//The bytes of each part at its maximum size are: 3 + 11 + 4
#define RTMP_MAX_HEADER_SIZE 18

//The first part of chunk header is fmt value in basic header
#define RTMP_PACKET_SIZE_LARGE    0
#define RTMP_PACKET_SIZE_MEDIUM   1
#define RTMP_PACKET_SIZE_SMALL    2
#define RTMP_PACKET_SIZE_MINIMUM  3

/*
    Represents a raw chunk, the original chunk

    c_header,c_headerSize: Save the data and size of chunk header
    c_chunk,c_chunkSize:Save the data and size of chunk data
*/
typedef struct RTMPChunk
{
    int c_headerSize;
    int c_chunkSize;
    char *c_chunk;
    char c_header[RTMP_MAX_HEADER_SIZE];
} RTMPChunk;

/*
    Represents a Message

    m_headerType        : Represents M_ The type of chunk, that is, fmt in basic header in chunk header
    m_packetType        : Indicates the Message Type ID
    m_hasAbsTimestamp   : Indicates whether the timestamp is absolute or relative, that is, when chunk type is 0, it is the absolute timestamp, and when other types are the increment of timestamp
    m_nChannel          : Indicates the chunk Stream ID
    m_nTimeStamp        : time stamp
    m_nInfoField2       : chunk fmt When it is 0, the last four bytes of the header, that is, the Message Stream ID
    m_nBodySize         : Message Size of the body
    m_nBytesRead        : The number of bytes of the body that have been read
    m_chunk             : If it is not NULL, it means that the user wants to get chunk, and this field will be filled in when reading Message
    m_body              : Message My body
*/
typedef struct RTMPPacket
{
    uint8_t m_headerType;
    uint8_t m_packetType;
    uint8_t m_hasAbsTimestamp;	/* timestamp absolute or relative? */
    int m_nChannel;
    uint32_t m_nTimeStamp;	/* timestamp */
    int32_t m_nInfoField2;	/* last 4 bytes in a long header */
    uint32_t m_nBodySize;
    uint32_t m_nBytesRead;
    RTMPChunk *m_chunk;
    char *m_body;
} RTMPPacket;

/*
    RTMPSockBuf: RTMP Transport layer socket and its cache
    Represents a TCP socket connection and its read cache

    sb_socket   : Socket socket
    sb_size     : buffer The number of unprocessed bytes in, that is, the size of the buffered data
    sb_start    : Point to the bytes to be processed in the buffer, that is, point to the buffered data
    sb_buf      : Data read buffer
    sb_timedout : Whether the socket is interrupted
    sb_ssl      : SSL related data 
*/
typedef struct RTMPSockBuf
{
    int sb_socket;
    int sb_size;		/* number of unprocessed bytes in buffer */
    char *sb_start;		/* pointer into sb_pBuffer of next byte to process */
    char sb_buf[RTMP_BUFFER_CACHE_SIZE];	/* data read from socket */
    int sb_timedout;
    void *sb_ssl;
} RTMPSockBuf;

//Empty all fields (buffer is still in)
void RTMPPacket_Reset(RTMPPacket *p);
//Print packet
void RTMPPacket_Dump(RTMPPacket *p);
//Allocate buffer for p, including fixed size header and nSize size body
int RTMPPacket_Alloc(RTMPPacket *p, int nSize);
//Free buffer
void RTMPPacket_Free(RTMPPacket *p);

//Whether the packet is complete
#define RTMPPacket_IsReady(a)	((a)->m_nBytesRead == (a)->m_nBodySize)

/*
    RTMP Connection parameters, that is, the parameter set required to establish RTMP connection
    Note: This is provided by the user of the client

    The meaning of the fields in this structure is closely related to the options in rtmpdump. You can see the meaning of the options in rtmpdump to help us understand them.
*/
typedef struct RTMP_LNK
{
    AVal hostname;      //Host name of the server to connect to
    AVal sockshost;     //Proxy host name

    /* parsed from URL */
    AVal playpath0;     //playpath parsed from URL
    /* passed in explicitly */
    AVal playpath;      //Explicitly specified playpath
    AVal tcUrl;         //The URL of the target stream to connect to. The default value is: rtmp[e]://host[:port]/app/playpath, which is formed by splicing the parsed field values.
    AVal swfUrl;        //The URL of the SWF player of the media. No value is set by default
    AVal pageUrl;       //The URL of the media embedded in the web page. No value is set by default
    AVal app;           //The application on the server to which you want to connect
    AVal auth;          //Validation string, which is appended to the end of the Connect Message. Using this option,
                        //A Boolean value of TRUE will actually be appended, followed by the validation string. Only some special servers are needed and have been abandoned.
    AVal flashVer;      //The version of the Flash Plug-in used to run the SWF player. The default is "LUX 10,0,32,18"“
    AVal subscribepath; //The name of the stream to access
    AVal token;         //The key to be used in the SecureToken Response. Used when the server needs a SecureToken authentication
    AMFObject extras;
    int edepth;

    int seekTime;       //Offset time when accessing media
    int stopTime;       //Stop time to access media

#define RTMP_LF_AUTH 	 0x0001 	/*  using auth param * / / / whether to use validation parameters
#define RTMP_LF_LIVE 	 0x0002 	/*  stream is live * / / / whether the requested stream is a real-time stream
#define RTMP_LF_SWFV 	 0x0004 	/*  do SWF verification * / / / do you want to perform SWF verification
#define RTMP_LF_PLST 	 0x0008 	/*  send playlist before play * / / / whether to send playlist between sending plays
#define RTMP_LF_BUFX 	 0x0010 	/*  Toggle stream on BufferEmpty msg * / / / is toggle stream on BufferEmpty msg
#define RTMP_LF_FTCU 	 0x0020 	/*  Free tcUrl on close * / / / whether to release tcUrl when close
    int lFlags;         //Composite identification

    int swfAge;         //Specify the valid days of the cached SWF information. After this number of days, it will be rechecked

    int protocol;       //rtmp protocol type of server
    /* connection timeout in seconds */
    int timeout;		//Time value of connection timeout

    unsigned short socksport;       //Port of proxy host
    unsigned short port;            //Port of the server

    //Encryption related fields
#ifdef CRYPTO
#define RTMP_SWF_HASHLEN	32
    void *dh;			/* for encryption */
    void *rc4keyIn;
    void *rc4keyOut;

    uint32_t SWFSize;
    uint8_t SWFHash[RTMP_SWF_HASHLEN];
    char SWFVerificationResponse[RTMP_SWF_HASHLEN+10];
#endif
} RTMP_LNK;

//RTMP business layer, that is, the parameters required to perform necessary operations on the RTMP stream after the RTMP stream is established
//Necessary operations, such as seek and resume
/* state for read() wrapper */
typedef struct RTMP_READ
{
    char *buf;                      //Point to read buffer
    char *bufpos;                   //Pointer to unprocessed data
    unsigned int buflen;            //Size of unprocessed data
    uint32_t timestamp;             //Current timestamp of RTMP stream
    uint8_t dataType;               //The data type of RTMP stream, that is, whether it contains audio data and video data. 0x04 is audio and 0x01 is video. The representation of flv is used
    uint8_t flags;                  //Parse the flag, including the following values
#define RTMP_READ_HEADER 	 0x01 / / indicates whether to insert flv header in the beginning of the current rtmp stream. This state will not be set by default. When actually reading, insert the corresponding flv header, and then set it, indicating that flv header has been added
#define RTMP_READ_RESUME 	 / / 0x02 indicates whether to resume
#define RTMP_READ_NO_IGNORE	0x04        //
#define RTMP_READ_GOTKF 		 0x08 / / indicates whether resume has been completed
#define RTMP_READ_GOTFLVK	0x10        //
#define RTMP_READ_SEEKING 	 0x20 / / indicates whether to perform seek operation
    int8_t status;                  //The current status read indicates the analysis result of the current flow. It has the following four values, and 0 indicates normal
#define RTMP_READ_COMPLETE 	- 3 / / close or Stop status, indicating that the reading is completed
#define RTMP_READ_ERROR 	- 2 / / fatal error
#define RTMP_READ_EOF	-1              //EOF
#define RTMP_READ_IGNORE 	 0 / / negligible error

    /* if bResume == TRUE */        //The fields that need to be specified during resume are used to help the flow define the location of resume
    uint8_t initialFrameType;           //The type of frame to locate, i.e. video frame or audio frame
    uint32_t nResumeTS;                 //Timestamp of the located frame
    char *metaHeader;                   //metedata of the stream to resume
    char *initialFrame;                 //data of the positioned frame
    uint32_t nMetaHeaderSize;           //The size of the metadata data of the stream to resume
    uint32_t nInitialFrameSize;         //data length of the positioned frame
    uint32_t nIgnoredFrameCounter;
    uint32_t nIgnoredFlvFrameCounter;
} RTMP_READ;

//Method: method
//Represents a method or function of RTMP
typedef struct RTMP_METHOD
{
    AVal name;
    int num;
} RTMP_METHOD;

//Represents an RTMP stream, which is used to save the relevant parameters of the RTMP stream
typedef struct RTMP
{
    int m_inChunkSize;          //max chunk size in receiving direction
    int m_outChunkSize;
    int m_nBWCheckCounter;
    int m_nBytesIn;             //The total number of bytes received
    int m_nBytesInSent;         //Total number of bytes sent
    int m_nBufferMS;
    int m_stream_id;		/* returned in _result from createStream */ //Message Stream ID
    int m_mediaChannel;         //chunk Stream id currently used by media
    uint32_t m_mediaStamp;      //Timestamp of the current media
    uint32_t m_pauseStamp;
    int m_pausing;
    int m_nServerBW;            //window size
    int m_nClientBW;            //window size in Set Peer Bandwidth Message
    uint8_t m_nClientBW2;       //limit type in Set Peer Bandwidth Message
    uint8_t m_bPlaying;         //Whether to play currently
    uint8_t m_bSendEncoding;
    uint8_t m_bSendCounter;

    int m_numInvokes;           //Record the number of RTMP initiated invoke s
    int m_numCalls;             //m_ Number in methodcalls
    /* remote method calls queue */
    RTMP_METHOD *m_methodCalls;	//request list

    RTMPPacket *m_vecChannelsIn[RTMP_CHANNELS];     //The last packet corresponding to the entered chunk Stream
    RTMPPacket *m_vecChannelsOut[RTMP_CHANNELS];    //The last packet corresponding to the output chunk stream
    /* abs timestamp of last packet */
    int m_channelTimestamp[RTMP_CHANNELS];          //Absolute timestamp corresponding to the last packet

    /* audioCodecs for the connect packet */
    double m_fAudioCodecs;                      //Audio codec in Connect msg
    /* videoCodecs for the connect packet */
    double m_fVideoCodecs;                      //Video codec in Connect msg
    /* AMF0 or AMF3 */
    double m_fEncoding;                         //Use AMF0 or AMF3

    /* duration of stream in seconds */
    double m_fDuration;                         //The length of the current stream, in seconds

    /* RTMPT stuff */       //The following are RTMPT related member variables:
    int m_msgCounter;		//
    int m_polling;          //
    int m_resplen;          //The body length of the HTTP Response, indicating whether the HTTP Response has been read, but the data is saved in the SB
    int m_unackd;           //Indicates the number of unresponsive HTTP request s (generally, no request must have a response)
    AVal m_clientID;        //When the bottom layer is HTTP, it is used to represent the client ID

    RTMP_READ m_read;       //RTMP level reading
    RTMPPacket m_write;     //Temporary msg object during RTMP level write
    RTMPSockBuf m_sb;       //Socket level read and write
    RTMP_LNK Link;          //Parameters of RTMP connection
} RTMP;

//Resolve RTMP address
int RTMP_ParseURL(const char *url, int *protocol, AVal *host,
                  unsigned int *port, AVal *playpath, AVal *app);
//Resolve playpath from RTMP URL
void RTMP_ParsePlaypath(AVal *in, AVal *out);
//Set the duration of buffering in milliseconds
void RTMP_SetBufferMS(RTMP *r, int size);
//Send the control packet of "set buffer duration"
void RTMP_UpdateBufferMS(RTMP *r);

//Set relevant properties of RTMP
int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg);

//Set url
int RTMP_SetupURL(RTMP *r, char *url);

//Set flow
void RTMP_SetupStream(RTMP *r, int protocol,  //agreement
                      AVal *hostname,                     //hostname
                      unsigned int port,                  //port
                      AVal *sockshost,
                      AVal *playpath,
                      AVal *tcUrl,
                      AVal *swfUrl,
                      AVal *pageUrl,
                      AVal *app,
                      AVal *auth,
                      AVal *swfSHA256Hash,
                      uint32_t swfSize,
                      AVal *flashVer,
                      AVal *subscribepath,
                      int dStart,
                      int dStop, int bLiveStream, long int timeout);

//The client establishes a connection with the server and connects
int RTMP_Connect(RTMP *r, RTMPPacket *cp);
struct sockaddr;
int RTMP_Connect0(RTMP *r, struct sockaddr *svc);
int RTMP_Connect1(RTMP *r, RTMPPacket *cp);

//The server handles handshake successfully, and the return value is greater than 0
int RTMP_Serve(RTMP *r);

//RTMP reads a packet, which is not guaranteed to read a complete packet
int RTMP_ReadPacket(RTMP *r, RTMPPacket *packet);
//RTMP is used to send packet s, and queue indicates whether to send according to the queue
int RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue);
//RTMP sends a chunk
int RTMP_SendChunk(RTMP *r, RTMPChunk *chunk);
//Is RTMP connected
int RTMP_IsConnected(RTMP *r);
//Returns the socket associated with RTMP
int RTMP_Socket(RTMP *r);
//Is RTMP interrupted
int RTMP_IsTimedout(RTMP *r);
//Gets the length of the current RTMP stream
double RTMP_GetDuration(RTMP *r);

//Pause or resume flow
int RTMP_ToggleStream(RTMP *r);

//Connect to the stream specified by the url and return TRUE and flare
int RTMP_ConnectStream(RTMP *r, int seekTime);
//Reconnect the stream, that is, connect the stream again after deleting the stream, and wait for synchronization until the stream starts
int RTMP_ReconnectStream(RTMP *r, int seekTime);
//Stop the flow, or delete the flow
void RTMP_DeleteStream(RTMP *r);

//Get a media packet, that is, audio frame or video frame (implemented on the RTMP_ReadPacket function)
int RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet);

//Client processing packet
int RTMP_ClientPacket(RTMP *r, RTMPPacket *packet);

//Initialize RTMP and set each field of RTMP as the default value
void RTMP_Init(RTMP *r);
//Close this RTMP. If it is currently connected, the connection will be closed; Then release RTMP related content
void RTMP_Close(RTMP *r);
//Assign an RTMP
//Its operation is only to allocate a memory of RTMP size, and RTMP can also be allocated on the stack
RTMP *RTMP_Alloc(void);
//Free this RTMP sized memory
void RTMP_Free(RTMP *r);


//Add write attribute for RTMP Link
void RTMP_EnableWrite(RTMP *r);
//Returns the version number of the RTMP library
int RTMP_LibVersion(void);
//RTMP process interrupted
//The essence is to set the global variable RTMP_ CTRL C is true
void RTMP_UserInterrupt(void);	/* user typed Ctrl-C */


int RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject,
                  unsigned int nTime);

/* caller probably doesn't know current timestamp, should
   * just use RTMP_Pause instead
   */
int RTMP_SendPause(RTMP *r, int DoPause, int dTime);
int RTMP_Pause(RTMP *r, int DoPause);

int RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name,
                                   AMFObjectProperty * p);

//TCP level operations: read, write, close
//Read at the TCP level and return the number of bytes read
int RTMPSockBuf_Fill(RTMPSockBuf *sb);
//Write at the TCP level and return the written return value
int RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len);
//Close the socket and return the closed return value
int RTMPSockBuf_Close(RTMPSockBuf *sb);

//
int RTMP_SendCreateStream(RTMP *r);
int RTMP_SendSeek(RTMP *r, int dTime);
int RTMP_SendServerBW(RTMP *r);
int RTMP_SendClientBW(RTMP *r);
//Discard the ith request
//freeit indicates whether to release the request
void RTMP_DropRequest(RTMP *r, int i, int freeit);

//FLV level
int RTMP_Read(RTMP *r, char *buf, int size);
int RTMP_Write(RTMP *r, const char *buf, int size);

/* hashswf.c */
int RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash,
                 int age);

#ifdef __cplusplus
};
#endif

#endif

Tags: RTMP

Posted by MacGod on Mon, 09 May 2022 17:21:23 +0300