Skip to content

Commit 81aa5ed

Browse files
committed
fix: h266 rtsp demuxer
1 parent 601a372 commit 81aa5ed

File tree

10 files changed

+221
-4
lines changed

10 files changed

+221
-4
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ Release
77
*.user
88
*.d
99
*.o
10+
debug.*
11+
release.*

libmpeg/include/mpeg-util.h

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#ifndef _mpeg_util_h_
22
#define _mpeg_util_h_
33

4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
48
#include "mpeg-types.h"
59
#include <assert.h>
610

@@ -169,4 +173,7 @@ int mpeg_h266_start_with_access_unit_delimiter(const uint8_t* p, size_t bytes);
169173

170174
uint32_t mpeg_crc32(uint32_t crc, const uint8_t *buffer, uint32_t size);
171175

176+
#ifdef __cplusplus
177+
}
178+
#endif
172179
#endif /* !_mpeg_util_h_ */

librtp/payload/rtp-h266-unpack.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// https://www.ietf.org/archive/id/draft-ietf-avtcore-rtp-vvc-18.htm
1+
// https://www.rfc-editor.org/rfc/rfc9328.html
22

33
#include "rtp-packet.h"
44
#include "rtp-payload-internal.h"
@@ -259,7 +259,7 @@ static int rtp_h266_unpack_input(void* p, const void* packet, int bytes)
259259

260260
assert(pkt.payloadlen > 2);
261261
ptr = (const uint8_t*)pkt.payload;
262-
nal = H266_TYPE(ptr[0]);
262+
nal = H266_TYPE(ptr[1]);
263263

264264
if (nal > 31)
265265
return 0; // packet discard, Unsupported (VVC) NAL type

librtp/payload/rtp-mp4a-latm-pack.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static int rtp_mp4a_latm_pack_input(void* pack, const void* data, int bytes, uin
6161
int r;
6262
int n, len;
6363
uint8_t *rtp;
64-
uint8_t hd[400]; // 100KB
64+
uint8_t hd[40]; // 10KB
6565
const uint8_t *ptr;
6666
struct rtp_encode_mp4a_latm_t *packer;
6767
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
117117
memcpy(rtp + n + len, packer->pkt.payload, packer->pkt.payloadlen);
118118
r = packer->handler.packet(packer->cbparam, rtp, n + len + packer->pkt.payloadlen, packer->pkt.rtp.timestamp, 0);
119119
packer->handler.free(packer->cbparam, rtp);
120-
len = 0;
120+
len = 0; // write PayloadLengthInfo once only
121121
}
122122

123123
return r;

librtsp/include/sdp-a-fmtp.h

+20
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,26 @@ struct sdp_a_fmtp_h265_t
8080

8181
int sdp_a_fmtp_h265(const char* fmtp, int *format, struct sdp_a_fmtp_h265_t *h265);
8282

83+
// H.266
84+
enum {
85+
SDP_A_FMTP_H266_SPROP_VPS = 0x00000100,
86+
SDP_A_FMTP_H266_SPROP_SPS = 0x00000200,
87+
SDP_A_FMTP_H266_SPROP_PPS = 0x00000400,
88+
SDP_A_FMTP_H266_SPROP_SEI = 0x00000800,
89+
SDP_A_FMTP_H266_SPROP_DCI = 0x00001000,
90+
};
91+
struct sdp_a_fmtp_h266_t
92+
{
93+
int flags; // test with (1<<SDP_A_FMTP_H266_xxx)
94+
char sprop_vps[1];
95+
char sprop_sps[1];
96+
char sprop_pps[1];
97+
char sprop_sei[1];
98+
char sprop_dci[1];
99+
};
100+
101+
int sdp_a_fmtp_h266(const char* fmtp, int* format, struct sdp_a_fmtp_h266_t* h266);
102+
83103
// mpeg4-generic
84104
enum {
85105
SDP_A_FMTP_MPEG4_OBJECTTYPE = 0x0001,

librtsp/source/sdp-a-fmtp.c

+81
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,87 @@ int sdp_a_fmtp_h265(const char* fmtp, int *format, struct sdp_a_fmtp_h265_t *h26
302302
return 0;
303303
}
304304

305+
// RFC9328 RTP Payload Format for Versatile Video Coding(VVC)
306+
// m=video 49170 RTP/AVP 98
307+
// a=rtpmap:98 H266/90000
308+
// a=fmtp:98 profile-id=1; sprop-vps=<video parameter sets data>
309+
int sdp_a_fmtp_h266(const char* fmtp, int* format, struct sdp_a_fmtp_h266_t* h266)
310+
{
311+
size_t nc;
312+
const char* p1, * p2;
313+
const char* p = fmtp;
314+
315+
// payload type
316+
*format = atoi(p);
317+
p1 = strchr(p, ' ');
318+
if (!p1 || ' ' != *p1)
319+
return -1;
320+
321+
h266->flags = 0;
322+
assert(' ' == *p1);
323+
p = p1 + 1;
324+
while (*p)
325+
{
326+
p1 = strchr(p, '=');
327+
if (!p1 || '=' != *p1)
328+
return -1;
329+
330+
p2 = strchr(p1 + 1, ';');
331+
if (!p2)
332+
p2 = p1 + strlen(p1);
333+
334+
while (' ' == *p) p++; // skip space
335+
336+
nc = (size_t)(p1 - p); // ptrdiff_t to size_t
337+
//vc = (size_t)(p2 - p1 - 1); // ptrdiff_t to size_t
338+
switch (*p)
339+
{
340+
case 'i':
341+
// interop-constraints
342+
break;
343+
case 'l':
344+
// level-id
345+
break;
346+
case 'p':
347+
// profile-space
348+
// profile-id
349+
// profile-compatibility-indicator
350+
break;
351+
352+
case 's':
353+
// sprop-dci
354+
// sprop-vps
355+
// sprop-sps
356+
// sprop-pps
357+
// sprop-sei
358+
if (0 == strncasecmp("sprop-vps", p, nc))
359+
{
360+
}
361+
else if (0 == strncasecmp("sprop-sps", p, nc))
362+
{
363+
}
364+
else if (0 == strncasecmp("sprop-pps", p, nc))
365+
{
366+
}
367+
else if (0 == strncasecmp("sprop-sei", p, nc))
368+
{
369+
}
370+
else if (0 == strncasecmp("sprop-dci", p, nc))
371+
{
372+
}
373+
break;
374+
375+
case 't':
376+
// tier-flag
377+
break;
378+
}
379+
380+
p = *p2 ? p2 + 1 : p2;
381+
}
382+
383+
return 0;
384+
}
385+
305386
// RFC3640 RTP Payload Format for Transport of MPEG-4 Elementary Streams
306387
// m=audio 49230 RTP/AVP 96
307388
// a=rtpmap:96 mpeg4-generic/16000/1

librtsp/source/sdp/sdp-h266.c

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// RFC 9328 RTP Payload Format for Versatile Video Coding(VVC)
2+
3+
#include "mpeg4-vvc.h"
4+
#include "sdp-payload.h"
5+
#include "base64.h"
6+
#include <stdio.h>
7+
#include <stdint.h>
8+
#include <stdlib.h>
9+
#include <string.h>
10+
#include <assert.h>
11+
#include <errno.h>
12+
13+
int sdp_h266(uint8_t *data, int bytes, const char* proto, unsigned short port, int payload, int frequence, const void* extra, int extra_size)
14+
{
15+
static const char* pattern =
16+
"m=video %hu %s %d\n"
17+
"a=rtpmap:%d H266/90000\n"
18+
"a=fmtp:%d";
19+
20+
const uint8_t nalu[] = { 13/*dci*/, 14/*vps*/, 15/*sps*/, 16/*pps*/ };
21+
const char* sprop[] = { "sprop-dci", "sprop-vps", "sprop-sps", "sprop-pps" };
22+
23+
int r, n;
24+
int i, j, k;
25+
struct mpeg4_vvc_t vvc;
26+
27+
assert(90000 == frequence);
28+
r = mpeg4_vvc_decoder_configuration_record_load((const uint8_t*)extra, extra_size, &vvc);
29+
if (r < 0)
30+
return r;
31+
32+
n = snprintf((char*)data, bytes, pattern, port, proto && *proto ? proto : "RTP/AVP", payload, payload, payload);
33+
34+
for (i = 0; i < sizeof(nalu) / sizeof(nalu[0]) && n < bytes; i++)
35+
{
36+
if (i > 0 && n < bytes) data[n++] = ';';
37+
n += snprintf((char*)data + n, bytes - n, " %s=", sprop[i]);
38+
39+
for (k = j = 0; j < vvc.numOfArrays; j++)
40+
{
41+
assert(vvc.nalu[j].bytes > 2 && vvc.nalu[j].type == ((vvc.nalu[j].data[1] >> 3) & 0x1F));
42+
if (nalu[i] != vvc.nalu[j].type)
43+
continue;
44+
45+
if (n + 1 + vvc.nalu[j].bytes * 2 > bytes)
46+
return -ENOMEM; // don't have enough memory
47+
48+
if (k++ > 0 && n < bytes) data[n++] = ',';
49+
n += (int)base64_encode((char*)data + n, vvc.nalu[j].data, vvc.nalu[j].bytes);
50+
}
51+
}
52+
53+
if(n < bytes)
54+
data[n++] = '\n';
55+
return n;
56+
}
57+
58+
int sdp_h266_load(uint8_t* data, int bytes, const char* vps, const char* sps, const char* pps, const char* sei, const char* dci)
59+
{
60+
int i, n, len, off;
61+
const char* p, * next;
62+
const char* sprops[5];
63+
const uint8_t startcode[] = { 0x00, 0x00, 0x00, 0x01 };
64+
65+
off = 0;
66+
sprops[0] = vps;
67+
sprops[1] = sps;
68+
sprops[2] = pps;
69+
sprops[3] = sei;
70+
sprops[4] = dci;
71+
for (i = 0; i < sizeof(sprops) / sizeof(sprops[0]); i++)
72+
{
73+
p = sprops[i];
74+
while (p)
75+
{
76+
next = strchr(p, ',');
77+
len = next ? (int)(next - p) : (int)strlen(p);
78+
if (off + (len + 3) / 4 * 3 + (int)sizeof(startcode) > bytes)
79+
return -ENOMEM; // don't have enough space
80+
81+
memcpy(data + off, startcode, sizeof(startcode));
82+
n = (int)base64_decode(data + off + sizeof(startcode), p, len);
83+
assert(n <= (len + 3) / 4 * 3);
84+
off += n + sizeof(startcode);
85+
off += n;
86+
87+
p = next ? next + 1 : NULL;
88+
}
89+
}
90+
91+
return 0;
92+
}

librtsp/source/utils/rtsp-demuxer.c

+10
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct rtp_payload_info_t
5151
{
5252
struct sdp_a_fmtp_h264_t h264;
5353
struct sdp_a_fmtp_h265_t h265;
54+
struct sdp_a_fmtp_h266_t h266;
5455
struct sdp_a_fmtp_mpeg4_t mpeg4;
5556

5657
struct mpeg4_aac_t aac;
@@ -98,6 +99,7 @@ int sdp_aac_latm_load(uint8_t* data, int bytes, const char* config);
9899
int sdp_aac_mpeg4_load(uint8_t* data, int bytes, const char* config);
99100
int sdp_h264_load(uint8_t* data, int bytes, const char* config);
100101
int sdp_h265_load(uint8_t* data, int bytes, const char* vps, const char* sps, const char* pps, const char* sei);
102+
int sdp_h266_load(uint8_t* data, int bytes, const char* vps, const char* sps, const char* pps, const char* sei, const char* dci);
101103

102104
static int rtsp_demuxer_avpbs_onpacket(void* param, struct avpacket_t* pkt)
103105
{
@@ -457,6 +459,14 @@ int rtsp_demuxer_add_payload(struct rtsp_demuxer_t* demuxer, int frequency, int
457459
onpacket = rtsp_demuxer_onh2645nalu;
458460
break;
459461

462+
case AVCODEC_VIDEO_H266:
463+
if (fmtp && *fmtp && 0 == sdp_a_fmtp_h266(fmtp, &payload, &pt->fmtp.h266))
464+
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);
465+
pt->avbsf = avbsf_find(AVCODEC_VIDEO_H266);
466+
pt->h2645 = pt->avbsf->create(pt->extra, pt->extra_bytes, rtsp_demuxer_onh2645packet, pt);
467+
onpacket = rtsp_demuxer_onh2645nalu;
468+
break;
469+
460470
case AVCODEC_AUDIO_AAC:
461471
if (0 == strcasecmp(encoding, "MPEG4-GENERIC"))
462472
{

test/test.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ extern "C" DEF_FUN_VOID(mpeg4_hevc_test);
135135
extern "C" DEF_FUN_VOID(mpeg4_vvc_test);
136136
extern "C" DEF_FUN_VOID(avswg_avs3_test);
137137
extern "C" DEF_FUN_VOID(mp3_header_test);
138+
extern "C" DEF_FUN_VOID(opus_head_test);
139+
extern "C" DEF_FUN_VOID(flac_streaminfo_test);
138140
extern "C" DEF_FUN_VOID(h264_mp4toannexb_test);
139141
extern "C" DEF_FUN_VOID(sdp_a_fmtp_test);
140142
extern "C" DEF_FUN_VOID(sdp_a_rtpmap_test);
@@ -250,6 +252,8 @@ int main(int argc, const char* argv[])
250252
RE_RUN_REG("mpeg4_vvc_test", argc, argv);
251253
RE_RUN_REG("avswg_avs3_test", argc, argv);
252254
RE_RUN_REG("mp3_header_test", argc, argv);
255+
RE_RUN_REG("opus_head_test", argc, argv);
256+
RE_RUN_REG("flac_streaminfo_test", argc, argv);
253257
RE_RUN_REG("h264_mp4toannexb_test", argc, argv);
254258
RE_RUN_REG("sdp_a_fmtp_test", argc, argv);
255259
RE_RUN_REG("sdp_a_rtpmap_test", argc, argv);

test/test.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@
262262
<ClCompile Include="..\librtsp\source\sdp\sdp-g7xx.c" />
263263
<ClCompile Include="..\librtsp\source\sdp\sdp-h264.c" />
264264
<ClCompile Include="..\librtsp\source\sdp\sdp-h265.c" />
265+
<ClCompile Include="..\librtsp\source\sdp\sdp-h266.c" />
265266
<ClCompile Include="..\librtsp\source\sdp\sdp-mpeg2.c" />
266267
<ClCompile Include="..\librtsp\source\sdp\sdp-mpeg4.c" />
267268
<ClCompile Include="..\librtsp\source\sdp\sdp-opus.c" />

0 commit comments

Comments
 (0)