Commit d2279d9d authored by François Cartegnie's avatar François Cartegnie 🤞
Browse files

stream_out: rtp: add support for HEVC

parent c245cdbc
......@@ -50,6 +50,7 @@ static int rtp_packetize_mp4a (sout_stream_id_sys_t *, block_t *);
static int rtp_packetize_mp4a_latm (sout_stream_id_sys_t *, block_t *);
static int rtp_packetize_h263 (sout_stream_id_sys_t *, block_t *);
static int rtp_packetize_h264 (sout_stream_id_sys_t *, block_t *);
static int rtp_packetize_h265 (sout_stream_id_sys_t *, block_t *);
static int rtp_packetize_amr (sout_stream_id_sys_t *, block_t *);
static int rtp_packetize_spx (sout_stream_id_sys_t *, block_t *);
static int rtp_packetize_t140 (sout_stream_id_sys_t *, block_t *);
......@@ -335,6 +336,136 @@ int rtp_get_fmt( vlc_object_t *obj, const es_format_t *p_fmt, const char *mux,
rtp_fmt->fmtp = strdup( "packetization-mode=1" );
break;
case VLC_CODEC_HEVC:
{
rtp_fmt->ptname = "H265";
rtp_fmt->pf_packetize = rtp_packetize_h265;
rtp_fmt->fmtp = NULL;
int i_profile = p_fmt->i_profile;
int i_level = p_fmt->i_level;
int i_tiers = -1;
int i_space = -1;
struct nalset_e
{
const uint8_t i_nal;
const uint8_t i_extend;
const char *psz_name;
char *psz_64;
} nalsets[4] = {
{ 32, 0, "vps", NULL },
{ 33, 0, "sps", NULL },
{ 34, 0, "pps", NULL },
{ 39, 1, "sei", NULL },
};
if( p_fmt->i_extra > 0 )
{
hxxx_iterator_ctx_t it;
for(int i=0; i<4; i++)
{
struct nalset_e *set = &nalsets[i];
hxxx_iterator_init( &it, p_fmt->p_extra, p_fmt->i_extra, 0 );
const uint8_t *p_nal;
size_t i_nal;
while( hxxx_annexb_iterate_next( &it, &p_nal, &i_nal ) )
{
const uint8_t i_nal_type = (p_nal[0] & 0x7E) >> 1;
if( i_nal_type < set->i_nal ||
i_nal_type > set->i_nal + set->i_extend )
continue;
msg_Dbg( obj, "we found a startcode for NAL with TYPE:%" PRIu8, i_nal_type );
char *psz_temp = vlc_b64_encode_binary( p_nal, i_nal );
if( psz_temp )
{
if( set->psz_64 == NULL )
{
set->psz_64 = psz_temp;
}
else
{
char *psz_merged;
if( asprintf( &psz_merged, "%s,%s", set->psz_64, psz_temp ) != -1 )
{
free( set->psz_64 );
set->psz_64 = psz_merged;
}
free( psz_temp );
}
}
if( i_nal_type == 33 && i_nal > 12 )
{
if( i_profile < 0 )
i_profile = p_nal[1] & 0x1F;
if( i_space < 0 )
i_space = p_nal[1] >> 6;
if( i_tiers < 0 )
i_tiers = !!(p_nal[1] & 0x20);
if( i_level < 0 )
i_level = p_nal[12];
}
}
}
}
rtp_fmt->fmtp = strdup( "tx-mode=SRST;" );
if( rtp_fmt->fmtp )
{
char *psz_fmtp;
if( i_profile >= 0 &&
asprintf( &psz_fmtp, "%sprofile-id=%d;",
rtp_fmt->fmtp, i_profile ) != -1 )
{
free( rtp_fmt->fmtp );
rtp_fmt->fmtp = psz_fmtp;
}
if( i_level >= 0 &&
asprintf( &psz_fmtp, "%slevel-id=%d;",
rtp_fmt->fmtp, i_level ) != -1 )
{
free( rtp_fmt->fmtp );
rtp_fmt->fmtp = psz_fmtp;
}
if( i_tiers >= 0 &&
asprintf( &psz_fmtp, "%stier-flag=%d;",
rtp_fmt->fmtp, i_tiers ) != -1 )
{
free( rtp_fmt->fmtp );
rtp_fmt->fmtp = psz_fmtp;
}
if( i_space >= 0 &&
asprintf( &psz_fmtp, "%sprofile-space=%d;",
rtp_fmt->fmtp, i_space ) != -1 )
{
free( rtp_fmt->fmtp );
rtp_fmt->fmtp = psz_fmtp;
}
for(int i=0; i<4; i++)
{
struct nalset_e *set = &nalsets[i];
if( set->psz_64 &&
asprintf( &psz_fmtp, "%ssprop-%s=%s;",
rtp_fmt->fmtp,
set->psz_name,
set->psz_64 ) != -1 )
{
free( rtp_fmt->fmtp );
rtp_fmt->fmtp = psz_fmtp;
}
}
}
for(int i=0; i<4; i++)
free( nalsets[i].psz_64 );
break;
}
case VLC_CODEC_MP4V:
{
rtp_fmt->ptname = "MP4V-ES";
......@@ -1189,6 +1320,87 @@ static int rtp_packetize_h264( sout_stream_id_sys_t *id, block_t *in )
return VLC_SUCCESS;
}
/* rfc7798 */
static int
rtp_packetize_h265_nal( sout_stream_id_sys_t *id,
const uint8_t *p_data, size_t i_data, int64_t i_pts,
int64_t i_dts, bool b_last, int64_t i_length )
{
const size_t i_max = rtp_mtu (id); /* payload max in one packet */
if( i_data < 3 )
return VLC_SUCCESS;
/* */
if( i_data <= i_max )
{
/* Single NAL unit packet */
block_t *out = block_Alloc( 12 + i_data );
out->i_dts = i_dts;
out->i_length = i_length;
/* */
rtp_packetize_common( id, out, b_last, i_pts );
memcpy( &out->p_buffer[12], p_data, i_data );
rtp_packetize_send( id, out );
}
else
{
const uint16_t i_nal_hdr = (GetWBE(p_data) & 0x81FF) | 0x6200 /* 49 */;
const uint8_t i_nal_type = (p_data[0] & 0x7E) >> 1;
/* FU-A Fragmentation Unit without interleaving */
const size_t i_count = ( i_data-2 + i_max-3 - 2 ) / (i_max-3);
p_data += 2;
i_data -= 2;
for( size_t i = 0; i < i_count; i++ )
{
const size_t i_payload = __MIN( i_data, i_max-3 );
block_t *out = block_Alloc( 12 + 3 + i_payload );
out->i_dts = i_dts + i * i_length / i_count;
out->i_length = i_length / i_count;
/* */
rtp_packetize_common( id, out, (b_last && i_payload == i_data),
i_pts );
/* FU indicator */
out->p_buffer[12] = i_nal_hdr >> 8;
out->p_buffer[13] = i_nal_hdr & 0x00FF;
/* FU header */
out->p_buffer[14] = ( i == 0 ? 0x80 : 0x00 ) | ( (i == i_count-1) ? 0x40 : 0x00 ) | i_nal_type;
memcpy( &out->p_buffer[15], p_data, i_payload );
rtp_packetize_send( id, out );
i_data -= i_payload;
p_data += i_payload;
}
}
return VLC_SUCCESS;
}
static int rtp_packetize_h265( sout_stream_id_sys_t *id, block_t *in )
{
hxxx_iterator_ctx_t it;
hxxx_iterator_init( &it, in->p_buffer, in->i_buffer, 0 );
const uint8_t *p_nal;
size_t i_nal;
while( hxxx_annexb_iterate_next( &it, &p_nal, &i_nal ) )
{
rtp_packetize_h265_nal( id, p_nal, i_nal,
(in->i_pts > VLC_TS_INVALID ? in->i_pts : in->i_dts), in->i_dts,
it.p_head + 3 >= it.p_tail, in->i_length * i_nal / in->i_buffer );
}
block_Release(in);
return VLC_SUCCESS;
}
static int rtp_packetize_amr( sout_stream_id_sys_t *id, block_t *in )
{
int i_max = rtp_mtu (id) - 2; /* payload max in one packet */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment