#include "rtsp-demuxer.h" #include "rtp-demuxer.h" #include "rtp-profile.h" #include "rtcp-header.h" #include "sdp-a-fmtp.h" #include "mpeg-ps.h" #include "mpeg-ts.h" #include "avbsf.h" #include "avpbs.h" // https://github.com/ireader/avcodec #avbsf/include #include "mpeg4-aac.h" #include "rtsp-payloads.h" #include #include #include #include #include #define RTSP_STREAM_MAX 4 #define RTSP_PAYLOAD_MAX 8 #define RTSP_PAYLOAD_MAX_SIZE (10 * 1024 * 1024) #if defined(OS_WINDOWS) #if !defined(strcasecmp) #define strcasecmp _stricmp #endif #endif struct rtsp_demuxer_t; struct rtp_payload_info_t { struct rtsp_demuxer_t* ctx; int frequency; int payload; char encoding[64]; uint8_t* extra; int extra_bytes; uint16_t seq; // RTP-Info seq uint32_t base; // RTP-Info timestamp uint32_t last; // last rtp packet timestamp int64_t timestamp; // rtp timestamp extend to 64bit int64_t pts; // last mapped rtp packet timestamp struct rtp_demuxer_t* rtp; void* ts, * ps; // only one union { struct sdp_a_fmtp_h264_t h264; struct sdp_a_fmtp_h265_t h265; struct sdp_a_fmtp_mpeg4_t mpeg4; struct mpeg4_aac_t aac; } fmtp; struct avpbs_t* bs; void* filter; // 264/265 only struct avbsf_t* avbsf; void* h2645; // ps/ts only struct { AVPACKET_CODEC_ID codec; struct avpbs_t* bs; void* filter; int pid; // ts/ps only } tracks[RTSP_STREAM_MAX]; // ps only struct { uint8_t* ptr; int len, cap; } ptr; }; struct rtsp_demuxer_t { void* param; rtsp_demuxer_onpacket onpacket; int stream; int jitter; struct rtp_payload_info_t pt[RTSP_PAYLOAD_MAX]; int count; // payload type count int idx; // last payload index uint8_t ptr[8 * 1024]; int off; }; int sdp_aac_latm_load(uint8_t* data, int bytes, const char* config); int sdp_aac_mpeg4_load(uint8_t* data, int bytes, const char* config); int sdp_h264_load(uint8_t* data, int bytes, const char* config); int sdp_h265_load(uint8_t* data, int bytes, const char* vps, const char* sps, const char* pps, const char* sei); static int rtsp_demuxer_avpbs_onpacket(void* param, struct avpacket_t* pkt) { struct rtp_payload_info_t* pt; pt = (struct rtp_payload_info_t*)param; return pt->ctx->onpacket(pt->ctx->param, pkt); } static int rtsp_demuxer_mpeg2_fetch_stream(struct rtp_payload_info_t* pt, int pid, int codecid) { int i, mpeg2; mpeg2 = avpayload_find_by_mpeg2((uint8_t)codecid); if (mpeg2 < 0) return -EPROTONOSUPPORT; for (i = 0; i < sizeof(pt->tracks) / sizeof(pt->tracks[0]); i++) { if (0 == pt->tracks[i].pid || pt->tracks[i].pid == pid) break; } if (i >= sizeof(pt->tracks) / sizeof(pt->tracks[0])) return -E2BIG; if(pt->tracks[i].codec != s_payloads[mpeg2].codecid && pt->tracks[i].bs && pt->tracks[i].filter) pt->tracks[i].bs->destroy(&pt->tracks[i].filter); if (!pt->tracks[i].bs || !pt->tracks[i].filter) { pt->tracks[i].codec = s_payloads[mpeg2].codecid; pt->tracks[i].bs = avpbs_find(s_payloads[mpeg2].codecid); if(pt->tracks[i].bs) pt->tracks[i].filter = pt->tracks[i].bs->create(i, s_payloads[mpeg2].codecid, NULL, 0, rtsp_demuxer_avpbs_onpacket, pt); } pt->tracks[i].pid = pid; return pt->tracks[i].filter ? i : -1; } static inline int rtsp_demuxer_mpegts_onpacket(void* param, int program, int track, int codecid, int flags, int64_t pts, int64_t dts, const void* data, size_t bytes) { int i; struct rtp_payload_info_t* pt; #if defined(FIX_DAHUA_AAC_FROM_G711) if ((codecid == PSI_STREAM_AUDIO_G711A || codecid == PSI_STREAM_AUDIO_G711U) && bytes > 7 && 0xFF == ((uint8_t*)data)[0] && 0xF0 == (((uint8_t*)data)[1] & 0xF0)) { int n = 7; // fix n = 0 for (i = 0; i + 7 < bytes && n >= 7; i += n) n = mpeg4_aac_adts_frame_length((const uint8_t*)data + i, bytes - i); codecid = i == bytes ? PSI_STREAM_AAC : codecid; // fix it } #endif pt = (struct rtp_payload_info_t*)param; i = rtsp_demuxer_mpeg2_fetch_stream(pt, track, codecid); if (i >= 0) { flags = flags ? AVPACKET_FLAG_KEY : 0; return pt->tracks[i].bs->input(pt->tracks[i].filter, pts / 90, dts / 90, (const uint8_t*)data, (int)bytes, flags); } if (0xbd == codecid || 0 == codecid) return 0; // ignore HIK private stream (void)program; //ignore assert(0); return -1; // discard } static inline int rtsp_demuxer_mpegps_onpacket(void* param, int track, int codecid, int flags, int64_t pts, int64_t dts, const void* data, size_t bytes) { //struct rtp_payload_info_t* pt; //pt = (struct rtp_payload_info_t*)param; (void)param; return rtsp_demuxer_mpegts_onpacket(param, 0, track, codecid, flags, pts, dts, data, bytes); } static inline int rtsp_demuxer_ontspacket(void* param, const void* packet, int bytes, uint32_t timestamp, int flags) { int r; struct rtp_payload_info_t* pt; pt = (struct rtp_payload_info_t*)param; r = 0; while (0 == r && bytes >= 188) { r = (int)ts_demuxer_input(pt->ts, packet, 188); assert(0 == r); bytes -= 188; packet = (const uint8_t*)packet + 188; } (void)timestamp, (void)flags; //ignore return r; } static inline int rtsp_demuxer_merge_ps_buffer(struct rtp_payload_info_t* pt, const uint8_t* packet, int bytes) { int n; uint8_t* ptr; if (bytes < 0) return -EINVAL; if (pt->ptr.len + bytes > pt->ptr.cap) { if (pt->ptr.len + bytes > RTSP_PAYLOAD_MAX_SIZE) { pt->ptr.len = 0; // clear return -E2BIG; } n = pt->ptr.len + bytes + 64 * 1024; ptr = (uint8_t*)realloc(pt->ptr.ptr, n); if (!ptr) { pt->ptr.len = 0; // clear return -ENOMEM; } pt->ptr.ptr = ptr; pt->ptr.cap = n; } if (bytes > 0) { memmove(pt->ptr.ptr + pt->ptr.len, packet, bytes); pt->ptr.len += bytes; } return 0; } static inline int rtsp_demuxer_onpspacket(void* param, const void* packet, int bytes, uint32_t timestamp, int flags) { int r, n; struct rtp_payload_info_t* pt; pt = (struct rtp_payload_info_t*)param; #if 1 if (pt->ptr.len > 0) { r = rtsp_demuxer_merge_ps_buffer(pt, packet, bytes); if (0 != r) return r; packet = pt->ptr.ptr; bytes = pt->ptr.len; pt->ptr.len = 0; } n = (int)ps_demuxer_input(pt->ps, packet, bytes); assert(n <= bytes); if (n >= 0 && n < bytes) r = rtsp_demuxer_merge_ps_buffer(pt, (const uint8_t*)packet + n, bytes - n); else r = n < 0 ? n : 0; (void)timestamp, (void)flags; //ignore return r; #else if (!pt->tracks[0].bs || !pt->tracks[0].filter) { pt->tracks[0].codec = AVCODEC_DATA_MP2P; pt->tracks[0].bs = avpbs_find(AVCODEC_DATA_MP2P); if (pt->tracks[0].bs) pt->tracks[0].filter = pt->tracks[0].bs->create(0, AVCODEC_DATA_MP2P, NULL, 0, rtsp_demuxer_avpbs_onpacket, pt); } // RTP timestamp => PTS/DTS if (0 == pt->last && INT64_MIN == pt->pts) pt->timestamp = timestamp; else pt->timestamp += (int32_t)(timestamp - pt->last); pt->last = timestamp; pt->pts = pt->timestamp * 1000 / pt->frequency; flags = flags ? AVPACKET_FLAG_KEY : 0; return pt->tracks[0].bs->input(pt->tracks[0].filter, pt->pts, pt->pts, (const uint8_t*)packet, (int)bytes, flags); #endif } static inline int rtsp_demuxer_onrtppacket(void* param, const void* data, int bytes, uint32_t timestamp, int flags) { int r; struct rtp_payload_info_t* pt; pt = (struct rtp_payload_info_t*)param; // RTP timestamp => PTS/DTS if (0 == pt->last && INT64_MIN == pt->pts) pt->timestamp = timestamp; else pt->timestamp += (int32_t)(timestamp - pt->last); pt->last = timestamp; pt->pts = pt->timestamp * 1000 / pt->frequency; r = -1; if (pt->bs && pt->filter) { //flags = 0; r = pt->bs->input(pt->filter, pt->pts, pt->pts, (const uint8_t*)data, bytes, flags); } //else // r = pt->ctx->onpacket(pt->ctx->param, 0, pt->payload, pt->encoding, pt->pts, pt->pts, data, bytes, flags); return r; } static inline int rtsp_demuxer_onh2645nalu(void* param, const void* data, int bytes, uint32_t timestamp, int flags) { struct rtp_payload_info_t* pt; pt = (struct rtp_payload_info_t*)param; // RTP timestamp => PTS/DTS if (0 == pt->last && INT64_MIN == pt->pts) pt->timestamp = timestamp; else pt->timestamp += (int32_t)(timestamp - pt->last); pt->last = timestamp; pt->pts = pt->timestamp * 1000 / pt->frequency; assert(pt->avbsf && pt->h2645); if (pt->avbsf && pt->h2645) { //flags = 0; return pt->avbsf->input(pt->h2645, pt->pts, pt->pts, (const uint8_t*)data, bytes); } (void)flags; // ignore return -1; } static int rtsp_demuxer_onh2645packet(void* param, int64_t pts, int64_t dts, const uint8_t* data, int bytes, int flags) { struct rtp_payload_info_t* pt; pt = (struct rtp_payload_info_t*)param; if (pt->bs && pt->filter) { //flags = 0; return pt->bs->input(pt->filter, pts, dts, (const uint8_t*)data, bytes, flags); } return -1; } static int rtsp_demuxer_payload_close(struct rtp_payload_info_t* pt) { if (pt->ptr.ptr) { assert(pt->ptr.cap > 0); free(pt->ptr.ptr); pt->ptr.ptr = NULL; } if (pt->bs && pt->filter) { pt->bs->destroy(&pt->filter); pt->bs = NULL; } if (pt->avbsf && pt->h2645) { pt->avbsf->destroy(&pt->h2645); pt->avbsf = NULL; } if (pt->ts) { ts_demuxer_destroy(pt->ts); pt->ts = NULL; } if (pt->ps) { ps_demuxer_destroy(pt->ps); pt->ps = NULL; } if (pt->rtp) { rtp_demuxer_destroy(&pt->rtp); pt->rtp = NULL; } return 0; } int rtsp_demuxer_add_payload(struct rtsp_demuxer_t* demuxer, int frequency, int payload, const char* encoding, const char* fmtp) { int avp, len; AVPACKET_CODEC_ID codec; struct rtp_payload_info_t* pt; int (*onpacket)(void* param, const void* data, int bytes, uint32_t timestamp, int flags); if (demuxer->count >= sizeof(demuxer->pt) / sizeof(demuxer->pt[0])) return -E2BIG; // too many payload type avp = avpayload_find_by_rtp((uint8_t)payload, encoding); // fixme: ffmpeg g711u sample rate 0 frequency = frequency ? frequency : (-1!=avp?s_payloads[avp].frequency:90000); pt = &demuxer->pt[demuxer->count]; memset(pt, 0, sizeof(*pt)); snprintf(pt->encoding, sizeof(pt->encoding) - 1, "%s", encoding); pt->frequency = frequency; pt->payload = payload; pt->extra = demuxer->ptr + demuxer->off; pt->extra_bytes = 0; pt->ctx = demuxer; pt->pts = INT64_MIN; if (RTP_PAYLOAD_MP2T == payload) { onpacket = rtsp_demuxer_ontspacket; pt->ts = ts_demuxer_create(rtsp_demuxer_mpegts_onpacket, pt); } else if (0 == strcasecmp(encoding, "MP2P") || 0 == strcasecmp(encoding, "PS")) { onpacket = rtsp_demuxer_onpspacket; pt->ps = ps_demuxer_create(rtsp_demuxer_mpegps_onpacket, pt); } else { onpacket = rtsp_demuxer_onrtppacket; assert(demuxer->off <= sizeof(demuxer->ptr)); len = sizeof(demuxer->ptr) - demuxer->off; codec = -1 != avp ? s_payloads[avp].codecid : AVCODEC_NONE; switch (codec) { case AVCODEC_VIDEO_H264: if (fmtp && *fmtp && 0 == sdp_a_fmtp_h264(fmtp, &payload, &pt->fmtp.h264)) pt->extra_bytes = sdp_h264_load(pt->extra, len, pt->fmtp.h264.sprop_parameter_sets); pt->avbsf = avbsf_h264(); pt->h2645 = pt->avbsf->create(pt->extra, pt->extra_bytes, rtsp_demuxer_onh2645packet, pt); onpacket = rtsp_demuxer_onh2645nalu; break; case AVCODEC_VIDEO_H265: if (fmtp && *fmtp && 0 == sdp_a_fmtp_h265(fmtp, &payload, &pt->fmtp.h265)) pt->extra_bytes = sdp_h265_load(pt->extra, len, pt->fmtp.h265.sprop_vps, pt->fmtp.h265.sprop_sps, pt->fmtp.h265.sprop_pps, pt->fmtp.h265.sprop_sei); pt->avbsf = avbsf_h265(); pt->h2645 = pt->avbsf->create(pt->extra, pt->extra_bytes, rtsp_demuxer_onh2645packet, pt); onpacket = rtsp_demuxer_onh2645nalu; break; case AVCODEC_AUDIO_AAC: if (0 == strcasecmp(encoding, "MPEG4-GENERIC")) { if (fmtp && *fmtp && 0 == sdp_a_fmtp_mpeg4(fmtp, &payload, &pt->fmtp.mpeg4)) pt->extra_bytes = sdp_aac_mpeg4_load(pt->extra, len, pt->fmtp.mpeg4.config); } else if (0 == strcasecmp(encoding, "MP4A-LATM")) { if (fmtp && *fmtp && 0 == sdp_a_fmtp_mpeg4(fmtp, &payload, &pt->fmtp.mpeg4)) pt->extra_bytes = sdp_aac_latm_load(pt->extra, len, pt->fmtp.mpeg4.config); } else { } break; // TODO: case AVCODEC_VIDEO_AV1: case AVCODEC_VIDEO_VP8: case AVCODEC_VIDEO_VP9: case AVCODEC_AUDIO_MP3: case AVCODEC_AUDIO_OPUS: default:// common break; } pt->bs = avpbs_find(codec); if (pt->bs) pt->filter = pt->bs->create(demuxer->stream+demuxer->count, codec, pt->extra, pt->extra_bytes > 0 ? pt->extra_bytes : 0, rtsp_demuxer_avpbs_onpacket, pt); } pt->rtp = rtp_demuxer_create(demuxer->jitter, frequency, pt->payload, encoding, onpacket, pt); if (!pt->rtp || (pt->bs && !pt->filter)) { rtsp_demuxer_payload_close(pt); return -ENOMEM; } demuxer->count++; demuxer->off += pt->extra_bytes; assert(demuxer->off <= sizeof(demuxer->ptr)); return 0; } struct rtsp_demuxer_t* rtsp_demuxer_create(int stream, int jitter, rtsp_demuxer_onpacket onpkt, void* param) { struct rtsp_demuxer_t* demuxer; demuxer = calloc(1, sizeof(*demuxer)); if (!demuxer) return NULL; demuxer->stream = stream; demuxer->jitter = jitter; demuxer->param = param; demuxer->onpacket = onpkt; return demuxer; } int rtsp_demuxer_destroy(struct rtsp_demuxer_t* demuxer) { int i; if (demuxer) { for (i = 0; i < demuxer->count; i++) rtsp_demuxer_payload_close(&demuxer->pt[i]); free(demuxer); } return 0; } int rtsp_demuxer_rtpinfo(struct rtsp_demuxer_t* demuxer, uint16_t seq, uint32_t timestamp) { struct rtp_payload_info_t* pt; if (demuxer->idx >= demuxer->count || demuxer->idx < 0) { assert(0); return -ENOENT; } pt = &demuxer->pt[demuxer->idx]; pt->seq = seq; pt->base = timestamp; // fixme //if (0 == pt->last) // pt->last = timestamp; //pt->pts = ((int64_t)(int32_t)(pt->last - timestamp)) * 1000 / pt->frequency; return 0; } int rtsp_demuxer_input(struct rtsp_demuxer_t* demuxer, const void* data, int bytes) { int i; uint8_t id; struct rtp_payload_info_t* pt; id = bytes > 1 ? ((const uint8_t*)data)[1] : 255; for (i = demuxer->idx; i < demuxer->count + demuxer->idx; i++) { pt = &demuxer->pt[i % demuxer->count]; // RFC7983 SRTP: https://tools.ietf.org/html/draft-ietf-avtcore-rfc5764-mux-fixes assert(((const uint8_t*)data)[0] > 127 && ((const uint8_t*)data)[0] < 192); // http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-4 // RFC 5761 (RTCP-mux) states this range for secure RTCP/RTP detection. // RTCP packet types in the ranges 1-191 and 224-254 SHOULD only be used when other values have been exhausted. if ( (id & 0x7F) == pt->payload || (192 <= id && id <= 223) ) { demuxer->idx = i % demuxer->count; return rtp_demuxer_input(pt->rtp, data, bytes); } } //assert(0); //return -1; return 0; } int rtsp_demuxer_rtcp(struct rtsp_demuxer_t* demuxer, void* buf, int len) { if (demuxer->idx >= demuxer->count || demuxer->idx < 0) { assert(0); return -ENOENT; } return rtp_demuxer_rtcp(demuxer->pt[demuxer->idx].rtp, buf, len); }