stream-deploy/ZLM/3rdpart/media-server/librtsp/source/utils/rtsp-muxer.c

448 lines
12 KiB
C++

#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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <inttypes.h>
#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;
struct {
uint32_t rtp; // rtp timestamp
int64_t pts;
} timeline; // map a/v pts -> rtp timestamp
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 inline uint32_t rtsp_muxer_timeline_update(struct rtp_muxer_payload_t* pt, int64_t pts)
{
if (0 == pt->timeline.pts)
pt->timeline.rtp = pt->rtp.timestamp;
else
pt->timeline.rtp += (int32_t)(pts - pt->timeline.pts);
pt->timeline.pts = pts;
return pt->timeline.rtp;
}
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, rtsp_muxer_timeline_update(pt, 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, rtsp_muxer_timeline_update(pt, 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 & (MPEG_FLAG_IDR_FRAME | MPEG_FLAG_H264_H265_WITH_AUD) /* ? 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 & (MPEG_FLAG_IDR_FRAME | MPEG_FLAG_H264_H265_WITH_AUD) /* ? 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, rtsp_muxer_timeline_update(m->pt, 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;
}
// init timeline
pt->timeline.rtp = pt->rtp.timestamp;
pt->timeline.pts = 0;
// 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_find(AVCODEC_VIDEO_H264);
break;
case RTP_PAYLOAD_H265:
//m->bsf = avbsf_find(AVCODEC_VIDEO_H265);
break;
case RTP_PAYLOAD_H266:
//m->bsf = avbsf_find(AVCODEC_VIDEO_H266);
break;
case RTP_PAYLOAD_MP4A:
//m->bsf = avbsf_find(AVCODEC_AUDIO_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.encoder, 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);
}