Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
ffmpeg
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
ffmpeg
Commits
96b2ba68
Commit
96b2ba68
authored
Aug 25, 2014
by
ThomasVolkert
Committed by
Michael Niedermayer
Aug 26, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
avformat/rtpdec: support for HEVC/H.265 RTP payload format (draft v6) depacketizing
parent
1f7e6c07
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
413 additions
and
0 deletions
+413
-0
MAINTAINERS
MAINTAINERS
+1
-0
Makefile
libavformat/Makefile
+1
-0
rtpdec.c
libavformat/rtpdec.c
+2
-0
rtpdec_formats.h
libavformat/rtpdec_formats.h
+2
-0
rtpdec_hevc.c
libavformat/rtpdec_hevc.c
+407
-0
No files found.
MAINTAINERS
View file @
96b2ba68
...
...
@@ -460,6 +460,7 @@ Muxers/Demuxers:
rtmp* Kostya Shishkov
rtp.c, rtpenc.c Martin Storsjo
rtpdec_h261.*, rtpenc_h261.* Thomas Volkert
rtpdec_hevc.* Thomas Volkert
rtpdec_asf.* Ronald S. Bultje
rtpenc_mpv.*, rtpenc_aac.* Martin Storsjo
rtsp.c Luca Barbato
...
...
libavformat/Makefile
View file @
96b2ba68
...
...
@@ -37,6 +37,7 @@ OBJS-$(CONFIG_RTPDEC) += rdt.o \
rtpdec_h263.o
\
rtpdec_h263_rfc2190.o
\
rtpdec_h264.o
\
rtpdec_hevc.o
\
rtpdec_ilbc.o
\
rtpdec_jpeg.o
\
rtpdec_latm.o
\
...
...
libavformat/rtpdec.c
View file @
96b2ba68
...
...
@@ -77,6 +77,8 @@ void ff_register_rtp_dynamic_payload_handlers(void)
ff_register_dynamic_payload_handler
(
&
ff_h263_2000_dynamic_handler
);
ff_register_dynamic_payload_handler
(
&
ff_h263_rfc2190_dynamic_handler
);
ff_register_dynamic_payload_handler
(
&
ff_h264_dynamic_handler
);
ff_register_dynamic_payload_handler
(
&
ff_h265_dynamic_handler
);
ff_register_dynamic_payload_handler
(
&
ff_hevc_dynamic_handler
);
ff_register_dynamic_payload_handler
(
&
ff_ilbc_dynamic_handler
);
ff_register_dynamic_payload_handler
(
&
ff_jpeg_dynamic_handler
);
ff_register_dynamic_payload_handler
(
&
ff_mp4a_latm_dynamic_handler
);
...
...
libavformat/rtpdec_formats.h
View file @
96b2ba68
...
...
@@ -50,6 +50,8 @@ extern RTPDynamicProtocolHandler ff_h263_1998_dynamic_handler;
extern
RTPDynamicProtocolHandler
ff_h263_2000_dynamic_handler
;
extern
RTPDynamicProtocolHandler
ff_h263_rfc2190_dynamic_handler
;
extern
RTPDynamicProtocolHandler
ff_h264_dynamic_handler
;
extern
RTPDynamicProtocolHandler
ff_h265_dynamic_handler
;
extern
RTPDynamicProtocolHandler
ff_hevc_dynamic_handler
;
extern
RTPDynamicProtocolHandler
ff_ilbc_dynamic_handler
;
extern
RTPDynamicProtocolHandler
ff_jpeg_dynamic_handler
;
extern
RTPDynamicProtocolHandler
ff_mp4a_latm_dynamic_handler
;
...
...
libavformat/rtpdec_hevc.c
0 → 100644
View file @
96b2ba68
/*
* RTP parser for HEVC/H.265 payload format (draft version 6)
* Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/avstring.h"
#include "avformat.h"
#include "rtpdec.h"
#define RTP_HEVC_PAYLOAD_HEADER_SIZE 2
#define RTP_HEVC_FU_HEADER_SIZE 1
#define RTP_HEVC_DONL_FIELDS_SIZE 2
#define HEVC_SPECIFIED_NAL_UNIT_TYPES 48
struct
PayloadContext
{
/* SDP out-of-band signaling data */
int
using_donl_field
;
int
profile_id
;
/* debugging */
#ifdef DEBUG
int
packets_received
[
HEVC_SPECIFIED_NAL_UNIT_TYPES
];
#endif
};
#ifdef DEBUG
#define COUNT_HEVC_NAL_TYPE(data, nal_type) if (nal_type < HEVC_SPECIFIED_NAL_UNIT_TYPES) data->packets_received[(nal_type)]++
#else
#define COUNT_HEVC_NAL_TYPE(data, nal_type) do { } while (0)
#endif
static
const
uint8_t
start_sequence
[]
=
{
0x00
,
0x00
,
0x00
,
0x01
};
static
PayloadContext
*
hevc_new_context
(
void
)
{
return
av_mallocz
(
sizeof
(
PayloadContext
));
}
static
av_cold
void
hevc_free_context
(
PayloadContext
*
data
)
{
#ifdef DEBUG
int
i
;
for
(
i
=
0
;
i
<
HEVC_SPECIFIED_NAL_UNIT_TYPES
;
i
++
)
{
if
(
data
->
packets_received
[
i
])
av_log
(
NULL
,
AV_LOG_DEBUG
,
"Received %d packets of NAL unit type %d
\n
"
,
data
->
packets_received
[
i
],
i
);
}
#endif
av_free
(
data
);
}
static
av_cold
int
hevc_init
(
AVFormatContext
*
ctx
,
int
st_index
,
PayloadContext
*
data
)
{
#ifdef DEBUG
av_log
(
ctx
,
AV_LOG_DEBUG
,
"hevc_init() for stream %d
\n
"
,
st_index
);
#endif
if
(
st_index
<
0
)
return
0
;
ctx
->
streams
[
st_index
]
->
need_parsing
=
AVSTREAM_PARSE_FULL
;
return
0
;
}
static
av_cold
int
hevc_sdp_parse_fmtp_config
(
AVFormatContext
*
s
,
AVStream
*
stream
,
PayloadContext
*
hevc_data
,
char
*
attr
,
char
*
value
)
{
#ifdef DEBUG
av_log
(
s
,
AV_LOG_DEBUG
,
"SDP: fmtp value %s is %s
\n
"
,
attr
,
value
);
#endif
/* profile-space: 0-3 */
/* profile-id: 0-31 */
if
(
!
strcmp
(
attr
,
"profile-id"
))
{
hevc_data
->
profile_id
=
atoi
(
value
);
#ifdef DEBUG
av_log
(
s
,
AV_LOG_DEBUG
,
"SDP: found profile-id: %d
\n
"
,
hevc_data
->
profile_id
);
#endif
}
/* tier-flag: 0-1 */
/* level-id: 0-255 */
/* interop-constraints: [base16] */
/* profile-compatibility-indicator: [base16] */
/* sprop-sub-layer-id: 0-6, defines highest possible value for TID, default: 6 */
/* recv-sub-layer-id: 0-6 */
/* max-recv-level-id: 0-255 */
/* tx-mode: MSM,SSM */
/* sprop-vps: [base64] */
/* sprop-sps: [base64] */
/* sprop-pps: [base64] */
/* sprop-sei: [base64] */
/* max-lsr, max-lps, max-cpb, max-dpb, max-br, max-tr, max-tc */
/* max-fps */
/* sprop-max-don-diff: 0-32767
When the RTP stream depends on one or more other RTP
streams (in this case tx-mode MUST be equal to "MSM" and
MSM is in use), this parameter MUST be present and the
value MUST be greater than 0.
*/
if
(
!
strcmp
(
attr
,
"sprop-max-don-diff"
))
{
if
(
atoi
(
value
)
>
0
)
hevc_data
->
using_donl_field
=
1
;
#ifdef DEBUG
av_log
(
s
,
AV_LOG_DEBUG
,
"SDP: found sprop-max-don-diff in SDP, DON field usage is: %d
\n
"
,
hevc_data
->
using_dons
);
#endif
}
/* sprop-depack-buf-nalus: 0-32767 */
if
(
!
strcmp
(
attr
,
"sprop-depack-buf-nalus"
))
{
if
(
atoi
(
value
)
>
0
)
hevc_data
->
using_donl_field
=
1
;
#ifdef DEBUG
av_log
(
s
,
AV_LOG_DEBUG
,
"SDP: found sprop-depack-buf-nalus in SDP, DON field usage is: %d
\n
"
,
hevc_data
->
using_dons
);
#endif
}
/* sprop-depack-buf-bytes: 0-4294967295 */
/* depack-buf-cap */
/* sprop-segmentation-id: 0-3 */
/* sprop-spatial-segmentation-idc: [base16] */
/* dec-parallel-ca: */
/* include-dph */
return
0
;
}
static
av_cold
int
hevc_parse_sdp_line
(
AVFormatContext
*
ctx
,
int
st_index
,
PayloadContext
*
hevc_data
,
const
char
*
line
)
{
AVStream
*
current_stream
;
AVCodecContext
*
codec
;
const
char
*
sdp_line_ptr
=
line
;
#ifdef DEBUG
av_log
(
ctx
,
AV_LOG_DEBUG
,
"parse_hevc_sdp_line() got SDP line %s
\n
"
,
line
);
#endif
if
(
st_index
<
0
)
return
0
;
current_stream
=
ctx
->
streams
[
st_index
];
codec
=
current_stream
->
codec
;
if
(
av_strstart
(
sdp_line_ptr
,
"framesize:"
,
&
sdp_line_ptr
))
{
char
str_video_width
[
50
];
char
*
str_video_width_ptr
=
str_video_width
;
/**
* parse "a=framesize:96 320-240"
*/
/* ignore spaces */
while
(
*
sdp_line_ptr
&&
*
sdp_line_ptr
==
' '
)
sdp_line_ptr
++
;
/* ignore RTP payload ID */
while
(
*
sdp_line_ptr
&&
*
sdp_line_ptr
!=
' '
)
sdp_line_ptr
++
;
/* ignore spaces */
while
(
*
sdp_line_ptr
&&
*
sdp_line_ptr
==
' '
)
sdp_line_ptr
++
;
/* extract the actual video resolution description */
while
(
*
sdp_line_ptr
&&
*
sdp_line_ptr
!=
'-'
&&
(
str_video_width_ptr
-
str_video_width
)
<
sizeof
(
str_video_width
)
-
1
)
*
str_video_width_ptr
++
=
*
sdp_line_ptr
++
;
/* add trailing zero byte */
*
str_video_width_ptr
=
'\0'
;
/* determine the width value */
codec
->
width
=
atoi
(
str_video_width
);
// jump beyond the "-" and determine the height value
codec
->
height
=
atoi
(
sdp_line_ptr
+
1
);
}
else
if
(
av_strstart
(
sdp_line_ptr
,
"fmtp:"
,
&
sdp_line_ptr
))
{
return
ff_parse_fmtp
(
ctx
,
current_stream
,
hevc_data
,
sdp_line_ptr
,
hevc_sdp_parse_fmtp_config
);
}
else
if
(
av_strstart
(
sdp_line_ptr
,
"cliprect:"
,
&
sdp_line_ptr
))
{
// could use this if we wanted.
}
return
0
;
}
static
int
hevc_handle_packet
(
AVFormatContext
*
ctx
,
PayloadContext
*
rtp_hevc_ctx
,
AVStream
*
st
,
AVPacket
*
pkt
,
uint32_t
*
timestamp
,
const
uint8_t
*
buf
,
int
len
,
uint16_t
seq
,
int
flags
)
{
const
uint8_t
*
rtp_pl
=
buf
;
int
tid
,
lid
,
nal_type
;
int
first_fragment
,
last_fragment
,
fu_type
;
uint8_t
new_nal_header
[
2
];
int
res
=
0
;
/* sanity check for size of input packet */
if
(
len
<
3
/* 2 bytes header and 1 byte payload at least */
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Too short RTP/HEVC packet, got %d bytes
\n
"
,
len
);
return
AVERROR_INVALIDDATA
;
}
/*
decode the HEVC payload header according to section 4 of draft version 6:
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F| Type | LayerId | TID |
+-------------+-----------------+
Forbidden zero (F): 1 bit
NAL unit type (Type): 6 bits
NUH layer ID (LayerId): 6 bits
NUH temporal ID plus 1 (TID): 3 bits
*/
nal_type
=
(
buf
[
0
]
>>
1
)
&
0x3f
;
lid
=
((
buf
[
0
]
<<
5
)
&
0x20
)
|
((
buf
[
1
]
>>
3
)
&
0x1f
);
tid
=
buf
[
1
]
&
0x07
;
/* sanity check for correct layer ID */
if
(
lid
){
/* future scalable or 3D video coding extensions */
av_log
(
ctx
,
AV_LOG_ERROR
,
"Multi-layer HEVC coding is not supported yet, a patch is welcome
\n
"
);
return
AVERROR_PATCHWELCOME
;
}
/* sanity check for correct temporal ID */
if
(
!
tid
){
av_log
(
ctx
,
AV_LOG_ERROR
,
"Illegal temporal ID in RTP/HEVC packet
\n
"
);
return
AVERROR_INVALIDDATA
;
}
/* sanity check for correct NAL unit type */
if
(
nal_type
>
50
){
av_log
(
ctx
,
AV_LOG_ERROR
,
"Unsupported (HEVC) NAL type (%d)
\n
"
,
nal_type
);
return
AVERROR_INVALIDDATA
;
}
#ifdef DEBUG
av_log
(
ctx
,
AV_LOG_DEBUG
,
"hevc_handle_packet() got NAL type %d with %d bytes
\n
"
,
nal_type
,
len
);
#endif
switch
(
nal_type
)
{
/* aggregated packets (AP) */
case
48
:
/* pass the HEVC payload header */
buf
+=
RTP_HEVC_PAYLOAD_HEADER_SIZE
;
len
-=
RTP_HEVC_PAYLOAD_HEADER_SIZE
;
/* pass the HEVC DONL fields */
if
(
rtp_hevc_ctx
->
using_donl_field
){
buf
+=
RTP_HEVC_DONL_FIELDS_SIZE
;
len
-=
RTP_HEVC_DONL_FIELDS_SIZE
;
}
/* fall-through */
/* video parameter set (VPS) */
case
32
:
/* sequence parameter set (SPS) */
case
33
:
/* picture parameter set (PPS) */
case
34
:
/* supplemental enhancement information (SEI) */
case
39
:
/* single NAL unit packet */
default:
/* create A/V packet */
if
((
res
=
av_new_packet
(
pkt
,
sizeof
(
start_sequence
)
+
len
))
<
0
)
return
res
;
/* A/V packet: copy start sequence */
memcpy
(
pkt
->
data
,
start_sequence
,
sizeof
(
start_sequence
));
/* A/V packet: copy NAL unit data */
memcpy
(
pkt
->
data
+
sizeof
(
start_sequence
),
buf
,
len
);
COUNT_HEVC_NAL_TYPE
(
data
,
nal_type
);
break
;
/* fragmentation unit (FU) */
case
49
:
/* pass the HEVC payload header */
buf
+=
RTP_HEVC_PAYLOAD_HEADER_SIZE
;
len
-=
RTP_HEVC_PAYLOAD_HEADER_SIZE
;
/**
decode the FU header
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|S|E| FuType |
+---------------+
Start fragment (S): 1 bit
End fragment (E): 1 bit
FuType: 6 bits
*/
first_fragment
=
buf
[
0
]
&
0x80
;
last_fragment
=
buf
[
0
]
&
0x40
;
fu_type
=
buf
[
0
]
&
0x3f
;
/* pass the HEVC FU header */
buf
+=
RTP_HEVC_FU_HEADER_SIZE
;
len
-=
RTP_HEVC_FU_HEADER_SIZE
;
/* pass the HEVC DONL fields */
if
(
rtp_hevc_ctx
->
using_donl_field
){
buf
+=
RTP_HEVC_DONL_FIELDS_SIZE
;
len
-=
RTP_HEVC_DONL_FIELDS_SIZE
;
}
#ifdef DEBUG
av_log
(
ctx
,
AV_LOG_DEBUG
,
" FU type %d with %d bytes
\n
"
,
fu_type
,
len
);
#endif
if
(
len
>
0
)
{
new_nal_header
[
0
]
=
(
rtp_pl
[
0
]
&
0x81
)
|
(
fu_type
<<
1
);
new_nal_header
[
1
]
=
rtp_pl
[
1
];
/* start fragment vs. subsequent fragments */
if
(
first_fragment
)
{
if
(
!
last_fragment
){
/* create A/V packet which is big enough */
if
((
res
=
av_new_packet
(
pkt
,
sizeof
(
start_sequence
)
+
sizeof
(
new_nal_header
)
+
len
))
<
0
)
return
res
;
/* A/V packet: copy start sequence */
memcpy
(
pkt
->
data
,
start_sequence
,
sizeof
(
start_sequence
));
/* A/V packet: copy new NAL header */
memcpy
(
pkt
->
data
+
sizeof
(
start_sequence
),
new_nal_header
,
sizeof
(
new_nal_header
));
/* A/V packet: copy NAL unit data */
memcpy
(
pkt
->
data
+
sizeof
(
start_sequence
)
+
sizeof
(
new_nal_header
),
buf
,
len
);
}
else
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Illegal combination of S and E bit in RTP/HEVC packet
\n
"
);
res
=
AVERROR_INVALIDDATA
;
}
}
else
{
/* create A/V packet */
if
((
res
=
av_new_packet
(
pkt
,
len
))
<
0
)
return
res
;
/* A/V packet: copy NAL unit data */
memcpy
(
pkt
->
data
,
buf
,
len
);
}
}
else
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Too short data for (HEVC) NAL unit, got %d bytes
\n
"
,
len
);
res
=
AVERROR_INVALIDDATA
;
}
if
(
!
res
){
COUNT_HEVC_NAL_TYPE
(
data
,
fu_type
);
}
break
;
/* PACI packet */
case
50
:
/* Temporal scalability control information (TSCI) */
av_log
(
ctx
,
AV_LOG_ERROR
,
"PACI packets for RTP/HEVC are not supported yet, a patch is welcome
\n
"
);
res
=
AVERROR_PATCHWELCOME
;
break
;
}
pkt
->
stream_index
=
st
->
index
;
return
res
;
}
RTPDynamicProtocolHandler
ff_hevc_dynamic_handler
=
{
.
enc_name
=
"HEVC"
,
.
codec_type
=
AVMEDIA_TYPE_VIDEO
,
.
codec_id
=
AV_CODEC_ID_HEVC
,
.
init
=
hevc_init
,
.
parse_sdp_a_line
=
hevc_parse_sdp_line
,
.
alloc
=
hevc_new_context
,
.
free
=
hevc_free_context
,
.
parse_packet
=
hevc_handle_packet
};
RTPDynamicProtocolHandler
ff_h265_dynamic_handler
=
{
.
enc_name
=
"H265"
,
.
codec_type
=
AVMEDIA_TYPE_VIDEO
,
.
codec_id
=
AV_CODEC_ID_H265
,
.
init
=
hevc_init
,
.
parse_sdp_a_line
=
hevc_parse_sdp_line
,
.
alloc
=
hevc_new_context
,
.
free
=
hevc_free_context
,
.
parse_packet
=
hevc_handle_packet
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment