From 81aa5edf4887e4029dfceca8e6bb5b27cc85a5c7 Mon Sep 17 00:00:00 2001 From: ireader Date: Sun, 20 Oct 2024 12:55:24 +0800 Subject: [PATCH] fix: h266 rtsp demuxer --- .gitignore | 2 + libmpeg/include/mpeg-util.h | 7 +++ librtp/payload/rtp-h266-unpack.c | 4 +- librtp/payload/rtp-mp4a-latm-pack.c | 4 +- librtsp/include/sdp-a-fmtp.h | 20 +++++++ librtsp/source/sdp-a-fmtp.c | 81 +++++++++++++++++++++++++ librtsp/source/sdp/sdp-h266.c | 92 +++++++++++++++++++++++++++++ librtsp/source/utils/rtsp-demuxer.c | 10 ++++ test/test.cpp | 4 ++ test/test.vcxproj | 1 + 10 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 librtsp/source/sdp/sdp-h266.c diff --git a/.gitignore b/.gitignore index eab232f1..b890150a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ Release *.user *.d *.o +debug.* +release.* diff --git a/libmpeg/include/mpeg-util.h b/libmpeg/include/mpeg-util.h index 45e0482b..4aeaa453 100644 --- a/libmpeg/include/mpeg-util.h +++ b/libmpeg/include/mpeg-util.h @@ -1,6 +1,10 @@ #ifndef _mpeg_util_h_ #define _mpeg_util_h_ +#ifdef __cplusplus +extern "C" { +#endif + #include "mpeg-types.h" #include @@ -169,4 +173,7 @@ int mpeg_h266_start_with_access_unit_delimiter(const uint8_t* p, size_t bytes); uint32_t mpeg_crc32(uint32_t crc, const uint8_t *buffer, uint32_t size); +#ifdef __cplusplus +} +#endif #endif /* !_mpeg_util_h_ */ diff --git a/librtp/payload/rtp-h266-unpack.c b/librtp/payload/rtp-h266-unpack.c index 0d3ffd59..c717c3c3 100644 --- a/librtp/payload/rtp-h266-unpack.c +++ b/librtp/payload/rtp-h266-unpack.c @@ -1,4 +1,4 @@ -// https://www.ietf.org/archive/id/draft-ietf-avtcore-rtp-vvc-18.htm +// https://www.rfc-editor.org/rfc/rfc9328.html #include "rtp-packet.h" #include "rtp-payload-internal.h" @@ -259,7 +259,7 @@ static int rtp_h266_unpack_input(void* p, const void* packet, int bytes) assert(pkt.payloadlen > 2); ptr = (const uint8_t*)pkt.payload; - nal = H266_TYPE(ptr[0]); + nal = H266_TYPE(ptr[1]); if (nal > 31) return 0; // packet discard, Unsupported (VVC) NAL type diff --git a/librtp/payload/rtp-mp4a-latm-pack.c b/librtp/payload/rtp-mp4a-latm-pack.c index 74e572d3..c9f90644 100644 --- a/librtp/payload/rtp-mp4a-latm-pack.c +++ b/librtp/payload/rtp-mp4a-latm-pack.c @@ -61,7 +61,7 @@ static int rtp_mp4a_latm_pack_input(void* pack, const void* data, int bytes, uin int r; int n, len; uint8_t *rtp; - uint8_t hd[400]; // 100KB + uint8_t hd[40]; // 10KB const uint8_t *ptr; struct rtp_encode_mp4a_latm_t *packer; packer = (struct rtp_encode_mp4a_latm_t *)pack; @@ -117,7 +117,7 @@ static int rtp_mp4a_latm_pack_input(void* pack, const void* data, int bytes, uin memcpy(rtp + n + len, packer->pkt.payload, packer->pkt.payloadlen); r = packer->handler.packet(packer->cbparam, rtp, n + len + packer->pkt.payloadlen, packer->pkt.rtp.timestamp, 0); packer->handler.free(packer->cbparam, rtp); - len = 0; + len = 0; // write PayloadLengthInfo once only } return r; diff --git a/librtsp/include/sdp-a-fmtp.h b/librtsp/include/sdp-a-fmtp.h index fc602488..0c707083 100644 --- a/librtsp/include/sdp-a-fmtp.h +++ b/librtsp/include/sdp-a-fmtp.h @@ -80,6 +80,26 @@ struct sdp_a_fmtp_h265_t int sdp_a_fmtp_h265(const char* fmtp, int *format, struct sdp_a_fmtp_h265_t *h265); +// H.266 +enum { + SDP_A_FMTP_H266_SPROP_VPS = 0x00000100, + SDP_A_FMTP_H266_SPROP_SPS = 0x00000200, + SDP_A_FMTP_H266_SPROP_PPS = 0x00000400, + SDP_A_FMTP_H266_SPROP_SEI = 0x00000800, + SDP_A_FMTP_H266_SPROP_DCI = 0x00001000, +}; +struct sdp_a_fmtp_h266_t +{ + int flags; // test with (1< +int sdp_a_fmtp_h266(const char* fmtp, int* format, struct sdp_a_fmtp_h266_t* h266) +{ + size_t nc; + const char* p1, * p2; + const char* p = fmtp; + + // payload type + *format = atoi(p); + p1 = strchr(p, ' '); + if (!p1 || ' ' != *p1) + return -1; + + h266->flags = 0; + assert(' ' == *p1); + p = p1 + 1; + while (*p) + { + p1 = strchr(p, '='); + if (!p1 || '=' != *p1) + return -1; + + p2 = strchr(p1 + 1, ';'); + if (!p2) + p2 = p1 + strlen(p1); + + while (' ' == *p) p++; // skip space + + nc = (size_t)(p1 - p); // ptrdiff_t to size_t + //vc = (size_t)(p2 - p1 - 1); // ptrdiff_t to size_t + switch (*p) + { + case 'i': + // interop-constraints + break; + case 'l': + // level-id + break; + case 'p': + // profile-space + // profile-id + // profile-compatibility-indicator + break; + + case 's': + // sprop-dci + // sprop-vps + // sprop-sps + // sprop-pps + // sprop-sei + if (0 == strncasecmp("sprop-vps", p, nc)) + { + } + else if (0 == strncasecmp("sprop-sps", p, nc)) + { + } + else if (0 == strncasecmp("sprop-pps", p, nc)) + { + } + else if (0 == strncasecmp("sprop-sei", p, nc)) + { + } + else if (0 == strncasecmp("sprop-dci", p, nc)) + { + } + break; + + case 't': + // tier-flag + break; + } + + p = *p2 ? p2 + 1 : p2; + } + + return 0; +} + // RFC3640 RTP Payload Format for Transport of MPEG-4 Elementary Streams // m=audio 49230 RTP/AVP 96 // a=rtpmap:96 mpeg4-generic/16000/1 diff --git a/librtsp/source/sdp/sdp-h266.c b/librtsp/source/sdp/sdp-h266.c new file mode 100644 index 00000000..d9887ca0 --- /dev/null +++ b/librtsp/source/sdp/sdp-h266.c @@ -0,0 +1,92 @@ +// RFC 9328 RTP Payload Format for Versatile Video Coding(VVC) + +#include "mpeg4-vvc.h" +#include "sdp-payload.h" +#include "base64.h" +#include +#include +#include +#include +#include +#include + +int sdp_h266(uint8_t *data, int bytes, const char* proto, unsigned short port, int payload, int frequence, const void* extra, int extra_size) +{ + static const char* pattern = + "m=video %hu %s %d\n" + "a=rtpmap:%d H266/90000\n" + "a=fmtp:%d"; + + const uint8_t nalu[] = { 13/*dci*/, 14/*vps*/, 15/*sps*/, 16/*pps*/ }; + const char* sprop[] = { "sprop-dci", "sprop-vps", "sprop-sps", "sprop-pps" }; + + int r, n; + int i, j, k; + struct mpeg4_vvc_t vvc; + + assert(90000 == frequence); + r = mpeg4_vvc_decoder_configuration_record_load((const uint8_t*)extra, extra_size, &vvc); + if (r < 0) + return r; + + n = snprintf((char*)data, bytes, pattern, port, proto && *proto ? proto : "RTP/AVP", payload, payload, payload); + + for (i = 0; i < sizeof(nalu) / sizeof(nalu[0]) && n < bytes; i++) + { + if (i > 0 && n < bytes) data[n++] = ';'; + n += snprintf((char*)data + n, bytes - n, " %s=", sprop[i]); + + for (k = j = 0; j < vvc.numOfArrays; j++) + { + assert(vvc.nalu[j].bytes > 2 && vvc.nalu[j].type == ((vvc.nalu[j].data[1] >> 3) & 0x1F)); + if (nalu[i] != vvc.nalu[j].type) + continue; + + if (n + 1 + vvc.nalu[j].bytes * 2 > bytes) + return -ENOMEM; // don't have enough memory + + if (k++ > 0 && n < bytes) data[n++] = ','; + n += (int)base64_encode((char*)data + n, vvc.nalu[j].data, vvc.nalu[j].bytes); + } + } + + if(n < bytes) + data[n++] = '\n'; + return n; +} + +int sdp_h266_load(uint8_t* data, int bytes, const char* vps, const char* sps, const char* pps, const char* sei, const char* dci) +{ + int i, n, len, off; + const char* p, * next; + const char* sprops[5]; + const uint8_t startcode[] = { 0x00, 0x00, 0x00, 0x01 }; + + off = 0; + sprops[0] = vps; + sprops[1] = sps; + sprops[2] = pps; + sprops[3] = sei; + sprops[4] = dci; + for (i = 0; i < sizeof(sprops) / sizeof(sprops[0]); i++) + { + p = sprops[i]; + while (p) + { + next = strchr(p, ','); + len = next ? (int)(next - p) : (int)strlen(p); + if (off + (len + 3) / 4 * 3 + (int)sizeof(startcode) > bytes) + return -ENOMEM; // don't have enough space + + memcpy(data + off, startcode, sizeof(startcode)); + n = (int)base64_decode(data + off + sizeof(startcode), p, len); + assert(n <= (len + 3) / 4 * 3); + off += n + sizeof(startcode); + off += n; + + p = next ? next + 1 : NULL; + } + } + + return 0; +} diff --git a/librtsp/source/utils/rtsp-demuxer.c b/librtsp/source/utils/rtsp-demuxer.c index df461fec..9d89b8b5 100644 --- a/librtsp/source/utils/rtsp-demuxer.c +++ b/librtsp/source/utils/rtsp-demuxer.c @@ -51,6 +51,7 @@ struct rtp_payload_info_t { struct sdp_a_fmtp_h264_t h264; struct sdp_a_fmtp_h265_t h265; + struct sdp_a_fmtp_h266_t h266; struct sdp_a_fmtp_mpeg4_t mpeg4; struct mpeg4_aac_t aac; @@ -98,6 +99,7 @@ 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); +int sdp_h266_load(uint8_t* data, int bytes, const char* vps, const char* sps, const char* pps, const char* sei, const char* dci); static int rtsp_demuxer_avpbs_onpacket(void* param, struct avpacket_t* pkt) { @@ -457,6 +459,14 @@ int rtsp_demuxer_add_payload(struct rtsp_demuxer_t* demuxer, int frequency, int onpacket = rtsp_demuxer_onh2645nalu; break; + case AVCODEC_VIDEO_H266: + if (fmtp && *fmtp && 0 == sdp_a_fmtp_h266(fmtp, &payload, &pt->fmtp.h266)) + pt->extra_bytes = sdp_h266_load(pt->extra, len, pt->fmtp.h266.sprop_vps, pt->fmtp.h266.sprop_sps, pt->fmtp.h266.sprop_pps, pt->fmtp.h266.sprop_sei, pt->fmtp.h266.sprop_dci); + pt->avbsf = avbsf_find(AVCODEC_VIDEO_H266); + 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")) { diff --git a/test/test.cpp b/test/test.cpp index 166a980a..aa5a4bc8 100755 --- a/test/test.cpp +++ b/test/test.cpp @@ -135,6 +135,8 @@ extern "C" DEF_FUN_VOID(mpeg4_hevc_test); extern "C" DEF_FUN_VOID(mpeg4_vvc_test); extern "C" DEF_FUN_VOID(avswg_avs3_test); extern "C" DEF_FUN_VOID(mp3_header_test); +extern "C" DEF_FUN_VOID(opus_head_test); +extern "C" DEF_FUN_VOID(flac_streaminfo_test); extern "C" DEF_FUN_VOID(h264_mp4toannexb_test); extern "C" DEF_FUN_VOID(sdp_a_fmtp_test); extern "C" DEF_FUN_VOID(sdp_a_rtpmap_test); @@ -250,6 +252,8 @@ int main(int argc, const char* argv[]) RE_RUN_REG("mpeg4_vvc_test", argc, argv); RE_RUN_REG("avswg_avs3_test", argc, argv); RE_RUN_REG("mp3_header_test", argc, argv); + RE_RUN_REG("opus_head_test", argc, argv); + RE_RUN_REG("flac_streaminfo_test", argc, argv); RE_RUN_REG("h264_mp4toannexb_test", argc, argv); RE_RUN_REG("sdp_a_fmtp_test", argc, argv); RE_RUN_REG("sdp_a_rtpmap_test", argc, argv); diff --git a/test/test.vcxproj b/test/test.vcxproj index b0f290d8..efad67c1 100644 --- a/test/test.vcxproj +++ b/test/test.vcxproj @@ -262,6 +262,7 @@ +