#include "rtsp-muxer.h" #include "rtp-profile.h" #include "rtp-payload.h" #include "rtcp-header.h" #include "rtp.h" #include "sdp-a-fmtp.h" #include "mpeg-ps.h" #include "mpeg-ts.h" #include "avbsf.h" // https://github.com/ireader/avcodec #include "mpeg4-aac.h" #include "rtp-sender.h" #include "rtsp-payloads.h" #include #include #include #include #include #include #include #if defined(OS_WINDOWS) #if !defined(strcasecmp) #define strcasecmp _stricmp #endif #endif uint64_t rtpclock(void); struct rtp_muxer_media_t; struct rtp_muxer_payload_t; typedef int (*media_input)(struct rtp_muxer_media_t* m, int flags, int64_t pts, int64_t dts, const void* data, size_t bytes); struct rtp_muxer_payload_t { struct rtsp_muxer_t* muxer; struct rtp_sender_t rtp; int pid; int port; uint64_t clock; // rtcp clock struct ps_muxer_t* ps; void* ts; // ts muxer int64_t timestamp; // ps/ts only const char* sdp; int len; // sdp size }; struct rtp_muxer_media_t { int codec; int stream; // ps/ts only struct rtp_muxer_payload_t* pt; media_input input; struct avbsf_t* bsf; void* filter; }; struct rtsp_muxer_t { struct rtp_muxer_payload_t payloads[3]; int payload_capacity; int payload_count; struct rtp_muxer_media_t medias[4]; int media_capacity; int media_count; rtsp_muxer_onpacket onpacket; void* param; uint8_t ptr[1024 * 1024]; int off; }; static void* rtsp_muxer_ts_alloc(void* param, size_t bytes) { struct rtp_muxer_payload_t* pt; pt = (struct rtp_muxer_payload_t*)param; if (bytes > sizeof(pt->muxer->ptr) - pt->muxer->off) { assert(0); return NULL; } return pt->muxer->ptr + pt->muxer->off; } static void rtsp_muxer_ts_free(void* param, void* packet) { (void)param, (void)packet; } static int rtsp_muxer_ts_write(void* param, const void* packet, size_t bytes) { struct rtp_muxer_payload_t* pt; pt = (struct rtp_muxer_payload_t*)param; return rtp_payload_encode_input(pt->rtp.encoder, packet, (int)bytes, (uint32_t)pt->timestamp); } static int rtsp_muxer_ps_write(void* param, int stream, void* packet, size_t bytes) { struct rtp_muxer_payload_t* pt; (void)stream; pt = (struct rtp_muxer_payload_t*)param; return rtp_payload_encode_input(pt->rtp.encoder, packet, (int)bytes, (uint32_t)pt->timestamp); } static int rtsp_muxer_rtp_encode_packet(void* param, const void* packet, int bytes, uint32_t timestamp, int flags) { struct rtp_muxer_payload_t* pt; pt = (struct rtp_muxer_payload_t*)param; return pt->muxer->onpacket(pt->muxer->param, pt->pid, packet, bytes, timestamp, flags); } static int rtsp_muxer_ts_input(struct rtp_muxer_media_t* m, int flags, int64_t pts, int64_t dts, const void* data, size_t bytes) { m->pt->timestamp = pts * 90; // last dts return mpeg_ts_write(m->pt->ts, m->stream, flags ? 0x01 : 0, pts * 90, dts * 90, data, bytes); } static int rtsp_muxer_ps_input(struct rtp_muxer_media_t* m, int flags, int64_t pts, int64_t dts, const void* data, size_t bytes) { m->pt->timestamp = pts * 90; // last dts return ps_muxer_input(m->pt->ps, m->stream, flags ? 0x01 : 0, pts * 90, dts * 90, data, bytes); } static int rtsp_muxer_av_input(struct rtp_muxer_media_t* m, int flags, int64_t pts, int64_t dts, const void* data, size_t bytes) { (void)flags, (void)dts; // TODO: rtp timestamp map PTS return rtp_payload_encode_input(m->pt->rtp.encoder, data, (int)bytes, (uint32_t)(pts * m->pt->rtp.frequency / 1000)); } static int rtsp_muxer_bsf_onpacket(void* param, int64_t pts, int64_t dts, const uint8_t* data, int bytes, int flags) { struct rtp_muxer_media_t* m; m = (struct rtp_muxer_media_t*)param; return m->input(m, flags, pts, dts, data, bytes); } static int rtsp_muxer_payload_close(struct rtp_muxer_payload_t* pt) { if (pt->ps) { ps_muxer_destroy(pt->ps); pt->ps = NULL; } if (pt->ts) { mpeg_ts_destroy(pt->ts); pt->ts = NULL; } rtp_sender_destroy(&pt->rtp); return 0; } struct rtsp_muxer_t* rtsp_muxer_create(rtsp_muxer_onpacket onpacket, void* param) { struct rtsp_muxer_t* muxer; muxer = calloc(1, sizeof(*muxer)); if (!muxer) return NULL; muxer->payload_capacity = sizeof(muxer->payloads) / sizeof(muxer->payloads[0]); muxer->media_capacity = sizeof(muxer->medias) / sizeof(muxer->medias[0]); muxer->onpacket = onpacket; muxer->param = param; return muxer; } int rtsp_muxer_destroy(struct rtsp_muxer_t* muxer) { int i; struct rtp_muxer_media_t* m; struct rtp_muxer_payload_t* pt; if (muxer) { for (i = 0; i < muxer->media_count; i++) { m = &muxer->medias[i]; if (m->bsf && m->filter) m->bsf->destroy(&m->filter); } for (i = 0; i < muxer->payload_count; i++) { pt = &muxer->payloads[i]; rtsp_muxer_payload_close(pt); } free(muxer); } return 0; } int rtsp_muxer_add_payload(struct rtsp_muxer_t* muxer, const char* proto, int frequence, int payload, const char* encoding, uint16_t seq, uint32_t ssrc, uint16_t port, const void* extra, int size) { int r = 0; struct rtp_muxer_payload_t* pt; if (muxer->payload_count >= muxer->payload_capacity) return -E2BIG; pt = &muxer->payloads[muxer->payload_count]; memset(pt, 0, sizeof(*pt)); pt->port = port; pt->pid = muxer->payload_count; pt->muxer = muxer; pt->rtp.seq = seq; pt->rtp.ssrc = ssrc; pt->rtp.onpacket = rtsp_muxer_rtp_encode_packet; pt->rtp.param = pt; if (RTP_PAYLOAD_MP2T == payload) { struct mpeg_ts_func_t h; h.alloc = rtsp_muxer_ts_alloc; h.write = rtsp_muxer_ts_write; h.free = rtsp_muxer_ts_free; for (r = 0; r < muxer->payload_count; r++) { if (muxer->payloads[r].ts) return muxer->payloads[r].pid; // exist } pt->ts = mpeg_ts_create(&h, pt); r = rtp_sender_init_video(&pt->rtp, proto, port, payload, encoding, 90000, extra, size); } else if (0 == strcasecmp(encoding, "MP2P") || 0 == strcasecmp(encoding, "PS")) { struct ps_muxer_func_t h; h.alloc = rtsp_muxer_ts_alloc; h.write = rtsp_muxer_ps_write; h.free = rtsp_muxer_ts_free; for (r = 0; r < muxer->payload_count; r++) { if (muxer->payloads[r].ps) return muxer->payloads[r].pid; // exist } pt->ps = ps_muxer_create(&h, pt); r = rtp_sender_init_video(&pt->rtp, proto, port, payload, encoding, 90000, extra, size); } else { if (0 == strcasecmp(encoding, "H264") || 0 == strcasecmp(encoding, "H265") || 0 == strcasecmp(encoding, "HEVC") || 0 == strcasecmp(encoding, "VP8") || 0 == strcasecmp(encoding, "VP9") || 0 == strcasecmp(encoding, "AV1") || 0 == strcasecmp(encoding, "MP4V-ES")) { r = rtp_sender_init_video(&pt->rtp, proto, port, payload, encoding, frequence ? frequence : 90000, extra, size); } else if (RTP_PAYLOAD_PCMU == payload || RTP_PAYLOAD_PCMA == payload || 0 == strcasecmp(encoding, "MP4A-LATM") || 0 == strcasecmp(encoding, "MPEG4-GENERIC") || 0 == strcasecmp(encoding, "opus")) { r = rtp_sender_init_audio(&pt->rtp, proto, port, payload, encoding, frequence, 0 /*from extra*/, extra, size); } else { assert(0); return -EPROTONOSUPPORT; } } if (r < 0 || r > (int)sizeof(muxer->ptr) - muxer->off) { rtsp_muxer_payload_close(pt); return -1; } // copy sdp pt->len = r; pt->sdp = (const char*)muxer->ptr + muxer->off; memcpy(muxer->ptr + muxer->off, pt->rtp.buffer, r); muxer->payload_count++; muxer->off += r; return pt->pid; } int rtsp_muxer_add_media(struct rtsp_muxer_t* muxer, int pid, int codec, const void* extra, int size) { int mpeg2; struct rtp_muxer_media_t* m; if (muxer->media_count >= muxer->media_capacity) return -E2BIG; if (pid < 0 || pid >= muxer->payload_count) return -ENOENT; mpeg2 = avpayload_find_by_payload((uint8_t)codec); if (mpeg2 < 0) return -EPROTONOSUPPORT; m = &muxer->medias[muxer->media_count]; memset(m, 0, sizeof(*m)); m->pt = &muxer->payloads[pid]; m->codec = codec; switch (codec) { case RTP_PAYLOAD_H264: //m->bsf = avbsf_h264(); break; case RTP_PAYLOAD_H265: //m->bsf = avbsf_h265(); break; case RTP_PAYLOAD_MP4A: //m->bsf = avbsf_aac(); break; default: // TODO: opus/g711 ; } if (m->bsf) m->filter = m->bsf->create(extra, size, rtsp_muxer_bsf_onpacket, m); if (m->bsf && !m->filter) { assert(0); return -1; } if (RTP_PAYLOAD_MP2T == m->pt->rtp.payload) { m->stream = mpeg_ts_add_stream(m->pt->ts, s_payloads[mpeg2].mpeg2, NULL, 0); m->input = rtsp_muxer_ts_input; } else if (0 == strcasecmp(m->pt->rtp.encoding, "MP2P") || 0 == strcasecmp(m->pt->rtp.encoding, "PS")) { m->stream = ps_muxer_add_stream(m->pt->ps, s_payloads[mpeg2].mpeg2, NULL, 0); m->input = rtsp_muxer_ps_input; } else { m->stream = 0; // unuse m->input = rtsp_muxer_av_input; } if (m->stream < 0) { assert(0); return -1; } return muxer->media_count++; } int rtsp_muxer_getinfo(struct rtsp_muxer_t* muxer, int pid, uint16_t* seq, uint32_t* timestamp, const char** sdp, int* size) { struct rtp_muxer_payload_t* pt; if (pid < 0 || pid >= muxer->payload_count) return -ENOENT; pt = &muxer->payloads[pid]; *sdp = pt->sdp; *size = pt->len; rtp_payload_encode_getinfo(pt->rtp.rtp, seq, timestamp); return 0; } int rtsp_muxer_input(struct rtsp_muxer_t* muxer, int mid, int64_t pts, int64_t dts, const void* data, int bytes, int flags) { int r; struct rtp_muxer_media_t* m; if (mid < 0 || mid >= muxer->media_count) return -ENOENT; m = &muxer->medias[mid]; if (m->bsf && m->filter) r = m->bsf->input(m->filter, pts, dts, (const uint8_t*)data, bytes); else r = m->input(m, flags, pts, dts, data, bytes); return r; } int rtsp_muxer_rtcp(struct rtsp_muxer_t* muxer, int pid, void* buf, int len) { int r; int interval; uint64_t clock; struct rtp_muxer_payload_t* pt; if (pid < 0 || pid >= muxer->payload_count) return -ENOENT; pt = &muxer->payloads[pid]; r = 0; clock = rtpclock(); interval = rtp_rtcp_interval(pt->rtp.rtp); if (pt->clock + (uint64_t)interval * 1000 < clock) { // RTCP report r = rtp_rtcp_report(pt->rtp.rtp, buf, len); pt->clock = clock; } return r; } int rtsp_muxer_onrtcp(struct rtsp_muxer_t* muxer, int pid, const void* buf, int len) { struct rtp_muxer_payload_t* pt; if (pid < 0 || pid >= muxer->payload_count) return -ENOENT; pt = &muxer->payloads[pid]; return rtp_onreceived_rtcp(pt->rtp.rtp, buf, len); }