mirror of
https://github.com/ossrs/srs.git
synced 2025-02-13 11:51:57 +00:00
for #133, decode the h264 NALU from rtp.
This commit is contained in:
parent
6a64164985
commit
0cc693a3b8
5 changed files with 349 additions and 4 deletions
|
@ -33,19 +33,24 @@ using namespace std;
|
|||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_app_utility.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_kernel_stream.hpp>
|
||||
#include <srs_kernel_buffer.hpp>
|
||||
|
||||
#ifdef SRS_AUTO_STREAM_CASTER
|
||||
|
||||
SrsRtpConn::SrsRtpConn(SrsRtspConn* r, int p)
|
||||
SrsRtpConn::SrsRtpConn(SrsRtspConn* r, int p, int sid)
|
||||
{
|
||||
rtsp = r;
|
||||
_port = p;
|
||||
stream_id = sid;
|
||||
listener = new SrsUdpListener(this, p);
|
||||
cache = new SrsRtpPacket();
|
||||
}
|
||||
|
||||
SrsRtpConn::~SrsRtpConn()
|
||||
{
|
||||
srs_freep(listener);
|
||||
srs_freep(cache);
|
||||
}
|
||||
|
||||
int SrsRtpConn::port()
|
||||
|
@ -61,6 +66,53 @@ int SrsRtpConn::listen()
|
|||
int SrsRtpConn::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (true) {
|
||||
SrsStream stream;
|
||||
|
||||
if ((ret = stream.initialize(buf, nb_buf)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsRtpPacket pkt;
|
||||
if ((ret = pkt.decode(&stream)) != ERROR_SUCCESS) {
|
||||
srs_error("rtsp: decode rtp packet failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pkt.chunked) {
|
||||
if (!cache) {
|
||||
cache = new SrsRtpPacket();
|
||||
}
|
||||
cache->copy(&pkt);
|
||||
cache->payload->append(pkt.payload->bytes(), pkt.payload->length());
|
||||
if (!cache->completed) {
|
||||
srs_trace("rtsp: rtp chunked %dB, vt=%d/%u, sts=%u/%#x/%#x, paylod=%dB",
|
||||
nb_buf, cache->version, cache->payload_type, cache->sequence_number, cache->timestamp, cache->ssrc,
|
||||
cache->payload->length()
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
srs_freep(cache);
|
||||
cache = new SrsRtpPacket();
|
||||
cache->reap(&pkt);
|
||||
}
|
||||
}
|
||||
|
||||
srs_trace("rtsp: rtp %dB, vt=%d/%u, sts=%u/%#x/%#x, paylod=%dB, chunked=%d",
|
||||
nb_buf, cache->version, cache->payload_type, cache->sequence_number, cache->timestamp, cache->ssrc,
|
||||
cache->payload->length(), cache->chunked
|
||||
);
|
||||
|
||||
// always free it.
|
||||
SrsAutoFree(SrsRtpPacket, cache);
|
||||
|
||||
if ((ret = rtsp->on_rtp_packet(cache)) != ERROR_SUCCESS) {
|
||||
srs_error("rtsp: process rtp packet failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -162,10 +214,10 @@ int SrsRtspConn::do_cycle()
|
|||
SrsRtpConn* rtp = NULL;
|
||||
if (req->stream_id == video_id) {
|
||||
srs_freep(video_rtp);
|
||||
rtp = video_rtp = new SrsRtpConn(this, lpm);
|
||||
rtp = video_rtp = new SrsRtpConn(this, lpm, video_id);
|
||||
} else {
|
||||
srs_freep(audio_rtp);
|
||||
rtp = audio_rtp = new SrsRtpConn(this, lpm);
|
||||
rtp = audio_rtp = new SrsRtpConn(this, lpm, audio_id);
|
||||
}
|
||||
if ((ret = rtp->listen()) != ERROR_SUCCESS) {
|
||||
srs_error("rtsp: rtp listen at port=%d failed. ret=%d", lpm, ret);
|
||||
|
@ -210,6 +262,12 @@ int SrsRtspConn::do_cycle()
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsRtspConn::on_rtp_packet(SrsRtpPacket* pkt)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsRtspConn::cycle()
|
||||
{
|
||||
// serve the rtsp client.
|
||||
|
|
|
@ -45,6 +45,7 @@ class SrsRtspConn;
|
|||
class SrsRtspStack;
|
||||
class SrsRtspCaster;
|
||||
class SrsConfDirective;
|
||||
class SrsRtpPacket;
|
||||
|
||||
/**
|
||||
* a rtp connection which transport a stream.
|
||||
|
@ -54,9 +55,11 @@ class SrsRtpConn: public ISrsUdpHandler
|
|||
private:
|
||||
SrsUdpListener* listener;
|
||||
SrsRtspConn* rtsp;
|
||||
SrsRtpPacket* cache;
|
||||
int stream_id;
|
||||
int _port;
|
||||
public:
|
||||
SrsRtpConn(SrsRtspConn* r, int p);
|
||||
SrsRtpConn(SrsRtspConn* r, int p, int sid);
|
||||
virtual ~SrsRtpConn();
|
||||
public:
|
||||
virtual int port();
|
||||
|
@ -103,6 +106,9 @@ public:
|
|||
virtual int serve();
|
||||
private:
|
||||
virtual int do_cycle();
|
||||
// internal methods
|
||||
public:
|
||||
virtual int on_rtp_packet(SrsRtpPacket* pkt);
|
||||
// interface ISrsThreadHandler
|
||||
public:
|
||||
virtual int cycle();
|
||||
|
|
|
@ -144,6 +144,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#define ERROR_RTMP_MIC_CACHE_OVERFLOW 2041
|
||||
#define ERROR_RTSP_TOKEN_NOT_NORMAL 2042
|
||||
#define ERROR_RTSP_REQUEST_HEADER_EOF 2043
|
||||
#define ERROR_RTP_HEADER_CORRUPT 2044
|
||||
//
|
||||
// system control message,
|
||||
// not an error, but special control logic.
|
||||
|
|
|
@ -34,6 +34,7 @@ using namespace std;
|
|||
#include <srs_kernel_consts.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_kernel_utility.hpp>
|
||||
#include <srs_kernel_stream.hpp>
|
||||
|
||||
#ifdef SRS_AUTO_STREAM_CASTER
|
||||
|
||||
|
@ -118,6 +119,121 @@ std::string srs_generate_rtsp_method_str(SrsRtspMethod method)
|
|||
}
|
||||
}
|
||||
|
||||
SrsRtpPacket::SrsRtpPacket()
|
||||
{
|
||||
version = 2;
|
||||
padding = 0;
|
||||
extension = 0;
|
||||
csrc_count = 0;
|
||||
marker = 1;
|
||||
|
||||
payload_type = 0;
|
||||
sequence_number = 0;
|
||||
timestamp = 0;
|
||||
ssrc = 0;
|
||||
|
||||
payload = new SrsSimpleBuffer();
|
||||
chunked = false;
|
||||
completed = false;
|
||||
}
|
||||
|
||||
SrsRtpPacket::~SrsRtpPacket()
|
||||
{
|
||||
srs_freep(payload);
|
||||
}
|
||||
|
||||
void SrsRtpPacket::copy(SrsRtpPacket* src)
|
||||
{
|
||||
version = src->version;
|
||||
padding = src->padding;
|
||||
extension = src->extension;
|
||||
csrc_count = src->csrc_count;
|
||||
marker = src->marker;
|
||||
payload_type = src->payload_type;
|
||||
sequence_number = src->sequence_number;
|
||||
timestamp = src->timestamp;
|
||||
ssrc = src->ssrc;
|
||||
|
||||
chunked = src->chunked;
|
||||
completed = src->completed;
|
||||
}
|
||||
|
||||
void SrsRtpPacket::reap(SrsRtpPacket* src)
|
||||
{
|
||||
copy(src);
|
||||
|
||||
payload = src->payload;
|
||||
src->payload = NULL;
|
||||
}
|
||||
|
||||
int SrsRtpPacket::decode(SrsStream* stream)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// 12bytes header, atleast 2bytes content.
|
||||
if (!stream->require(14)) {
|
||||
ret = ERROR_RTP_HEADER_CORRUPT;
|
||||
srs_error("rtsp: rtp header corrupt. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int8_t vv = stream->read_1bytes();
|
||||
version = (vv >> 6) & 0x03;
|
||||
padding = (vv >> 5) & 0x01;
|
||||
extension = (vv >> 4) & 0x01;
|
||||
csrc_count = vv & 0x0f;
|
||||
|
||||
int8_t mv = stream->read_1bytes();
|
||||
marker = (mv >> 7) & 0x01;
|
||||
payload_type = mv & 0x7f;
|
||||
|
||||
sequence_number = stream->read_2bytes();
|
||||
timestamp = stream->read_4bytes();
|
||||
ssrc = stream->read_4bytes();
|
||||
|
||||
// frame type
|
||||
// 0... .... reserverd
|
||||
// .11. .... NALU[0]&0x60
|
||||
// ...1 11.. FU indicator
|
||||
// .... ..00 reserverd
|
||||
int8_t ftv = stream->read_1bytes();
|
||||
int8_t nalu_0x60 = ftv & 0x60;
|
||||
int8_t fu_indicator = ftv & 0x1c;
|
||||
|
||||
// nri, whatever
|
||||
// 10.. .... first chunk.
|
||||
// 00.. .... continous chunk.
|
||||
// 01.. .... last chunk.
|
||||
// ...1 1111 NALU[0]&0x1f
|
||||
int8_t nriv = stream->read_1bytes();
|
||||
bool first_chunk = (nriv & 0xC0) == 0x80;
|
||||
bool last_chunk = (nriv & 0xC0) == 0x40;
|
||||
bool contious_chunk = (nriv & 0xC0) == 0x00;
|
||||
int8_t nalu_0x1f = nriv & 0x1f;
|
||||
|
||||
// chunked, generate the first byte NALU.
|
||||
if (fu_indicator == 0x1c && (first_chunk || last_chunk || contious_chunk)) {
|
||||
chunked = true;
|
||||
completed = last_chunk;
|
||||
|
||||
// generate and append the first byte NALU.
|
||||
if (first_chunk) {
|
||||
int8_t nalu_byte0 = nalu_0x60 | nalu_0x1f;
|
||||
payload->append((char*)&nalu_byte0, 1);
|
||||
}
|
||||
|
||||
payload->append(stream->data() + stream->pos(), stream->size() - stream->pos());
|
||||
return ret;
|
||||
}
|
||||
|
||||
// no chunked, append to payload.
|
||||
stream->skip(-2);
|
||||
payload->append(stream->data() + stream->pos(), stream->size() - stream->pos());
|
||||
completed = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsRtspSdp::SrsRtspSdp()
|
||||
{
|
||||
state = SrsRtspSdpStateOthers;
|
||||
|
|
|
@ -37,6 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
#ifdef SRS_AUTO_STREAM_CASTER
|
||||
|
||||
class SrsStream;
|
||||
class SrsSimpleBuffer;
|
||||
class ISrsProtocolReaderWriter;
|
||||
|
||||
|
@ -146,6 +147,169 @@ enum SrsRtspTokenState
|
|||
SrsRtspTokenStateEOF = 102,
|
||||
};
|
||||
|
||||
/**
|
||||
* the rtp packet.
|
||||
* 5. RTP Data Transfer Protocol, @see rtp-rfc3550-2003.pdf, page 12
|
||||
*/
|
||||
class SrsRtpPacket
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* version (V): 2 bits
|
||||
* This eld identies the version of RTP. The version dened by this specication is two (2).
|
||||
* (The value 1 is used by the rst draft version of RTP and the value 0 is used by the protocol
|
||||
* initially implemented in the \vat" audio tool.)
|
||||
*/
|
||||
int8_t version; //2bits
|
||||
/**
|
||||
* padding (P): 1 bit
|
||||
* If the padding bit is set, the packet contains one or more additional padding octets at the
|
||||
* end which are not part of the payload. The last octet of the padding contains a count of
|
||||
* how many padding octets should be ignored, including itself. Padding may be needed by
|
||||
* some encryption algorithms with xed block sizes or for carrying several RTP packets in a
|
||||
* lower-layer protocol data unit.
|
||||
*/
|
||||
int8_t padding; //1bit
|
||||
/**
|
||||
* extension (X): 1 bit
|
||||
* If the extension bit is set, the xed header must be followed by exactly one header extension,
|
||||
* with a format dened in Section 5.3.1.
|
||||
*/
|
||||
int8_t extension; //1bit
|
||||
/**
|
||||
* CSRC count (CC): 4 bits
|
||||
* The CSRC count contains the number of CSRC identiers that follow the xed header.
|
||||
*/
|
||||
int8_t csrc_count; //4bits
|
||||
/**
|
||||
* marker (M): 1 bit
|
||||
* The interpretation of the marker is dened by a prole. It is intended to allow signicant
|
||||
* events such as frame boundaries to be marked in the packet stream. A prole may dene
|
||||
* additional marker bits or specify that there is no marker bit by changing the number of bits
|
||||
* in the payload type eld (see Section 5.3).
|
||||
*/
|
||||
int8_t marker; //1bit
|
||||
/**
|
||||
* payload type (PT): 7 bits
|
||||
* This eld identies the format of the RTP payload and determines its interpretation by the
|
||||
* application. A prole may specify a default static mapping of payload type codes to payload
|
||||
* formats. Additional payload type codes may be dened dynamically through non-RTP means
|
||||
* (see Section 3). A set of default mappings for audio and video is specied in the companion
|
||||
* RFC 3551 [1]. An RTP source may change the payload type during a session, but this eld
|
||||
* should not be used for multiplexing separate media streams (see Section 5.2).
|
||||
* A receiver must ignore packets with payload types that it does not understand.
|
||||
*/
|
||||
int8_t payload_type; //7bits
|
||||
/**
|
||||
* sequence number: 16 bits
|
||||
* The sequence number increments by one for each RTP data packet sent, and may be used
|
||||
* by the receiver to detect packet loss and to restore packet sequence. The initial value of the
|
||||
* sequence number should be random (unpredictable) to make known-plaintext attacks on
|
||||
* encryption more dicult, even if the source itself does not encrypt according to the method
|
||||
* in Section 9.1, because the packets may flow through a translator that does. Techniques for
|
||||
* choosing unpredictable numbers are discussed in [17].
|
||||
*/
|
||||
u_int16_t sequence_number; //16bits
|
||||
/**
|
||||
* timestamp: 32 bits
|
||||
* The timestamp reflects the sampling instant of the rst octet in the RTP data packet. The
|
||||
* sampling instant must be derived from a clock that increments monotonically and linearly
|
||||
* in time to allow synchronization and jitter calculations (see Section 6.4.1). The resolution
|
||||
* of the clock must be sucient for the desired synchronization accuracy and for measuring
|
||||
* packet arrival jitter (one tick per video frame is typically not sucient). The clock frequency
|
||||
* is dependent on the format of data carried as payload and is specied statically in the prole
|
||||
* or payload format specication that denes the format, or may be specied dynamically for
|
||||
* payload formats dened through non-RTP means. If RTP packets are generated periodically,
|
||||
* the nominal sampling instant as determined from the sampling clock is to be used, not a
|
||||
* reading of the system clock. As an example, for xed-rate audio the timestamp clock would
|
||||
* likely increment by one for each sampling period. If an audio application reads blocks covering
|
||||
* 160 sampling periods from the input device, the timestamp would be increased by 160 for
|
||||
* each such block, regardless of whether the block is transmitted in a packet or dropped as
|
||||
* silent.
|
||||
*
|
||||
* The initial value of the timestamp should be random, as for the sequence number. Several
|
||||
* consecutive RTP packets will have equal timestamps if they are (logically) generated at once,
|
||||
* e.g., belong to the same video frame. Consecutive RTP packets may contain timestamps that
|
||||
* are not monotonic if the data is not transmitted in the order it was sampled, as in the case
|
||||
* of MPEG interpolated video frames. (The sequence numbers of the packets as transmitted
|
||||
* will still be monotonic.)
|
||||
*
|
||||
* RTP timestamps from dierent media streams may advance at dierent rates and usually
|
||||
* have independent, random osets. Therefore, although these timestamps are sucient to
|
||||
* reconstruct the timing of a single stream, directly comparing RTP timestamps from dierent
|
||||
* media is not eective for synchronization. Instead, for each medium the RTP timestamp
|
||||
* is related to the sampling instant by pairing it with a timestamp from a reference clock
|
||||
* (wallclock) that represents the time when the data corresponding to the RTP timestamp was
|
||||
* sampled. The reference clock is shared by all media to be synchronized. The timestamp
|
||||
* pairs are not transmitted in every data packet, but at a lower rate in RTCP SR packets as
|
||||
* described in Section 6.4.
|
||||
*
|
||||
* The sampling instant is chosen as the point of reference for the RTP timestamp because it is
|
||||
* known to the transmitting endpoint and has a common denition for all media, independent
|
||||
* of encoding delays or other processing. The purpose is to allow synchronized presentation of
|
||||
* all media sampled at the same time.
|
||||
*
|
||||
* Applications transmitting stored data rather than data sampled in real time typically use a
|
||||
* virtual presentation timeline derived from wallclock time to determine when the next frame
|
||||
* or other unit of each medium in the stored data should be presented. In this case, the RTP
|
||||
* timestamp would reflect the presentation time for each unit. That is, the RTP timestamp for
|
||||
* each unit would be related to the wallclock time at which the unit becomes current on the
|
||||
* virtual presentation timeline. Actual presentation occurs some time later as determined by
|
||||
* the receiver.
|
||||
*
|
||||
* An example describing live audio narration of prerecorded video illustrates the signicance
|
||||
* of choosing the sampling instant as the reference point. In this scenario, the video would
|
||||
* be presented locally for the narrator to view and would be simultaneously transmitted using
|
||||
* RTP. The \sampling instant" of a video frame transmitted in RTP would be established by
|
||||
* referencing its timestamp to the wallclock time when that video frame was presented to the
|
||||
* narrator. The sampling instant for the audio RTP packets containing the narrator's speech
|
||||
* would be established by referencing the same wallclock time when the audio was sampled.
|
||||
* The audio and video may even be transmitted by dierent hosts if the reference clocks on
|
||||
* the two hosts are synchronized by some means such as NTP. A receiver can then synchronize
|
||||
* presentation of the audio and video packets by relating their RTP timestamps using the
|
||||
* timestamp pairs in RTCP SR packets.
|
||||
*/
|
||||
u_int32_t timestamp; //32bits
|
||||
/**
|
||||
* SSRC: 32 bits
|
||||
* The SSRC eld identies the synchronization source. This identier should be chosen
|
||||
* randomly, with the intent that no two synchronization sources within the same RTP session
|
||||
* will have the same SSRC identier. An example algorithm for generating a random identier
|
||||
* is presented in Appendix A.6. Although the probability of multiple sources choosing the same
|
||||
* identier is low, all RTP implementations must be prepared to detect and resolve collisions.
|
||||
* Section 8 describes the probability of collision along with a mechanism for resolving collisions
|
||||
* and detecting RTP-level forwarding loops based on the uniqueness of the SSRC identier. If
|
||||
* a source changes its source transport address, it must also choose a new SSRC identier to
|
||||
* avoid being interpreted as a looped source (see Section 8.2).
|
||||
*/
|
||||
u_int32_t ssrc; //32bits
|
||||
|
||||
// the payload.
|
||||
SrsSimpleBuffer* payload;
|
||||
// whether transport in chunked payload.
|
||||
bool chunked;
|
||||
// whether message is completed.
|
||||
// normal message always completed.
|
||||
// while chunked completed when the last chunk arriaved.
|
||||
bool completed;
|
||||
public:
|
||||
SrsRtpPacket();
|
||||
virtual ~SrsRtpPacket();
|
||||
public:
|
||||
/**
|
||||
* copy the header from src.
|
||||
*/
|
||||
virtual void copy(SrsRtpPacket* src);
|
||||
/**
|
||||
* reap the src to this packet, reap the payload.
|
||||
*/
|
||||
virtual void reap(SrsRtpPacket* src);
|
||||
/**
|
||||
* decode rtp packet from stream.
|
||||
*/
|
||||
virtual int decode(SrsStream* stream);
|
||||
};
|
||||
|
||||
/**
|
||||
* the sdp in announce, @see rtsp-rfc2326-1998.pdf, page 159
|
||||
* Appendix C: Use of SDP for RTSP Session Descriptions
|
||||
|
|
Loading…
Reference in a new issue