1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-13 03:41:55 +00:00

for #133, decode the h264 NALU from rtp.

This commit is contained in:
winlin 2015-02-18 11:49:42 +08:00
parent 6a64164985
commit 0cc693a3b8
5 changed files with 349 additions and 4 deletions

View file

@ -33,19 +33,24 @@ using namespace std;
#include <srs_kernel_log.hpp> #include <srs_kernel_log.hpp>
#include <srs_app_utility.hpp> #include <srs_app_utility.hpp>
#include <srs_core_autofree.hpp> #include <srs_core_autofree.hpp>
#include <srs_kernel_stream.hpp>
#include <srs_kernel_buffer.hpp>
#ifdef SRS_AUTO_STREAM_CASTER #ifdef SRS_AUTO_STREAM_CASTER
SrsRtpConn::SrsRtpConn(SrsRtspConn* r, int p) SrsRtpConn::SrsRtpConn(SrsRtspConn* r, int p, int sid)
{ {
rtsp = r; rtsp = r;
_port = p; _port = p;
stream_id = sid;
listener = new SrsUdpListener(this, p); listener = new SrsUdpListener(this, p);
cache = new SrsRtpPacket();
} }
SrsRtpConn::~SrsRtpConn() SrsRtpConn::~SrsRtpConn()
{ {
srs_freep(listener); srs_freep(listener);
srs_freep(cache);
} }
int SrsRtpConn::port() int SrsRtpConn::port()
@ -61,6 +66,53 @@ int SrsRtpConn::listen()
int SrsRtpConn::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf) int SrsRtpConn::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf)
{ {
int ret = ERROR_SUCCESS; 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; return ret;
} }
@ -162,10 +214,10 @@ int SrsRtspConn::do_cycle()
SrsRtpConn* rtp = NULL; SrsRtpConn* rtp = NULL;
if (req->stream_id == video_id) { if (req->stream_id == video_id) {
srs_freep(video_rtp); srs_freep(video_rtp);
rtp = video_rtp = new SrsRtpConn(this, lpm); rtp = video_rtp = new SrsRtpConn(this, lpm, video_id);
} else { } else {
srs_freep(audio_rtp); 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) { if ((ret = rtp->listen()) != ERROR_SUCCESS) {
srs_error("rtsp: rtp listen at port=%d failed. ret=%d", lpm, ret); srs_error("rtsp: rtp listen at port=%d failed. ret=%d", lpm, ret);
@ -210,6 +262,12 @@ int SrsRtspConn::do_cycle()
return ret; return ret;
} }
int SrsRtspConn::on_rtp_packet(SrsRtpPacket* pkt)
{
int ret = ERROR_SUCCESS;
return ret;
}
int SrsRtspConn::cycle() int SrsRtspConn::cycle()
{ {
// serve the rtsp client. // serve the rtsp client.

View file

@ -45,6 +45,7 @@ class SrsRtspConn;
class SrsRtspStack; class SrsRtspStack;
class SrsRtspCaster; class SrsRtspCaster;
class SrsConfDirective; class SrsConfDirective;
class SrsRtpPacket;
/** /**
* a rtp connection which transport a stream. * a rtp connection which transport a stream.
@ -54,9 +55,11 @@ class SrsRtpConn: public ISrsUdpHandler
private: private:
SrsUdpListener* listener; SrsUdpListener* listener;
SrsRtspConn* rtsp; SrsRtspConn* rtsp;
SrsRtpPacket* cache;
int stream_id;
int _port; int _port;
public: public:
SrsRtpConn(SrsRtspConn* r, int p); SrsRtpConn(SrsRtspConn* r, int p, int sid);
virtual ~SrsRtpConn(); virtual ~SrsRtpConn();
public: public:
virtual int port(); virtual int port();
@ -103,6 +106,9 @@ public:
virtual int serve(); virtual int serve();
private: private:
virtual int do_cycle(); virtual int do_cycle();
// internal methods
public:
virtual int on_rtp_packet(SrsRtpPacket* pkt);
// interface ISrsThreadHandler // interface ISrsThreadHandler
public: public:
virtual int cycle(); virtual int cycle();

View file

@ -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_RTMP_MIC_CACHE_OVERFLOW 2041
#define ERROR_RTSP_TOKEN_NOT_NORMAL 2042 #define ERROR_RTSP_TOKEN_NOT_NORMAL 2042
#define ERROR_RTSP_REQUEST_HEADER_EOF 2043 #define ERROR_RTSP_REQUEST_HEADER_EOF 2043
#define ERROR_RTP_HEADER_CORRUPT 2044
// //
// system control message, // system control message,
// not an error, but special control logic. // not an error, but special control logic.

View file

@ -34,6 +34,7 @@ using namespace std;
#include <srs_kernel_consts.hpp> #include <srs_kernel_consts.hpp>
#include <srs_core_autofree.hpp> #include <srs_core_autofree.hpp>
#include <srs_kernel_utility.hpp> #include <srs_kernel_utility.hpp>
#include <srs_kernel_stream.hpp>
#ifdef SRS_AUTO_STREAM_CASTER #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() SrsRtspSdp::SrsRtspSdp()
{ {
state = SrsRtspSdpStateOthers; state = SrsRtspSdpStateOthers;

View file

@ -37,6 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifdef SRS_AUTO_STREAM_CASTER #ifdef SRS_AUTO_STREAM_CASTER
class SrsStream;
class SrsSimpleBuffer; class SrsSimpleBuffer;
class ISrsProtocolReaderWriter; class ISrsProtocolReaderWriter;
@ -146,6 +147,169 @@ enum SrsRtspTokenState
SrsRtspTokenStateEOF = 102, 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 identi es the version of RTP. The version de ned by this speci cation 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 de ned in Section 5.3.1.
*/
int8_t extension; //1bit
/**
* CSRC count (CC): 4 bits
* The CSRC count contains the number of CSRC identi ers that follow the xed header.
*/
int8_t csrc_count; //4bits
/**
* marker (M): 1 bit
* The interpretation of the marker is de ned by a pro le. It is intended to allow signi cant
* events such as frame boundaries to be marked in the packet stream. A pro le may de ne
* 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 identi es the format of the RTP payload and determines its interpretation by the
* application. A pro le may specify a default static mapping of payload type codes to payload
* formats. Additional payload type codes may be de ned dynamically through non-RTP means
* (see Section 3). A set of default mappings for audio and video is speci ed 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 speci ed statically in the pro le
* or payload format speci cation that de nes the format, or may be speci ed dynamically for
* payload formats de ned 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 di erent media streams may advance at di erent rates and usually
* have independent, random o sets. Therefore, although these timestamps are sucient to
* reconstruct the timing of a single stream, directly comparing RTP timestamps from di erent
* media is not e ective 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 de nition 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 signi cance
* 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 di erent 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 identi es the synchronization source. This identi er should be chosen
* randomly, with the intent that no two synchronization sources within the same RTP session
* will have the same SSRC identi er. An example algorithm for generating a random identi er
* is presented in Appendix A.6. Although the probability of multiple sources choosing the same
* identi er 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 identi er. If
* a source changes its source transport address, it must also choose a new SSRC identi er 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 * the sdp in announce, @see rtsp-rfc2326-1998.pdf, page 159
* Appendix C: Use of SDP for RTSP Session Descriptions * Appendix C: Use of SDP for RTSP Session Descriptions