2 * RTP parser for HEVC/H.265 payload format (draft version 6)
3 * Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.com>
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "libavutil/avstring.h"
28 #define RTP_HEVC_PAYLOAD_HEADER_SIZE 2
29 #define RTP_HEVC_FU_HEADER_SIZE 1
30 #define RTP_HEVC_DONL_FIELD_SIZE 2
31 #define HEVC_SPECIFIED_NAL_UNIT_TYPES 48
33 /* SDP out-of-band signaling data */
34 struct PayloadContext
{
39 static const uint8_t start_sequence
[] = { 0x00, 0x00, 0x00, 0x01 };
41 static av_cold PayloadContext
*hevc_new_context(void)
43 return av_mallocz(sizeof(PayloadContext
));
46 static av_cold
void hevc_free_context(PayloadContext
*data
)
51 static av_cold
int hevc_init(AVFormatContext
*ctx
, int st_index
,
54 av_dlog(ctx
, "hevc_init() for stream %d\n", st_index
);
59 ctx
->streams
[st_index
]->need_parsing
= AVSTREAM_PARSE_FULL
;
64 static av_cold
int hevc_sdp_parse_fmtp_config(AVFormatContext
*s
,
66 PayloadContext
*hevc_data
,
67 char *attr
, char *value
)
69 /* profile-space: 0-3 */
70 /* profile-id: 0-31 */
71 if (!strcmp(attr
, "profile-id")) {
72 hevc_data
->profile_id
= atoi(value
);
73 av_dlog(s
, "SDP: found profile-id: %d\n", hevc_data
->profile_id
);
78 /* interop-constraints: [base16] */
79 /* profile-compatibility-indicator: [base16] */
80 /* sprop-sub-layer-id: 0-6, defines highest possible value for TID, default: 6 */
81 /* recv-sub-layer-id: 0-6 */
82 /* max-recv-level-id: 0-255 */
83 /* tx-mode: MSM,SSM */
84 /* sprop-vps: [base64] */
85 /* sprop-sps: [base64] */
86 /* sprop-pps: [base64] */
87 /* sprop-sei: [base64] */
88 /* max-lsr, max-lps, max-cpb, max-dpb, max-br, max-tr, max-tc */
91 /* sprop-max-don-diff: 0-32767
93 When the RTP stream depends on one or more other RTP
94 streams (in this case tx-mode MUST be equal to "MSM" and
95 MSM is in use), this parameter MUST be present and the
96 value MUST be greater than 0.
98 if (!strcmp(attr
, "sprop-max-don-diff")) {
100 hevc_data
->using_donl_field
= 1;
101 av_dlog(s
, "Found sprop-max-don-diff in SDP, DON field usage is: %d\n",
102 hevc_data
->using_donl_field
);
105 /* sprop-depack-buf-nalus: 0-32767 */
106 if (!strcmp(attr
, "sprop-depack-buf-nalus")) {
108 hevc_data
->using_donl_field
= 1;
109 av_dlog(s
, "Found sprop-depack-buf-nalus in SDP, DON field usage is: %d\n",
110 hevc_data
->using_donl_field
);
113 /* sprop-depack-buf-bytes: 0-4294967295 */
115 /* sprop-segmentation-id: 0-3 */
116 /* sprop-spatial-segmentation-idc: [base16] */
117 /* dec-parallel-ca: */
123 static av_cold
int hevc_parse_sdp_line(AVFormatContext
*ctx
, int st_index
,
124 PayloadContext
*hevc_data
, const char *line
)
126 AVStream
*current_stream
;
127 AVCodecContext
*codec
;
128 const char *sdp_line_ptr
= line
;
133 current_stream
= ctx
->streams
[st_index
];
134 codec
= current_stream
->codec
;
136 if (av_strstart(sdp_line_ptr
, "framesize:", &sdp_line_ptr
)) {
137 char str_video_width
[50];
138 char *str_video_width_ptr
= str_video_width
;
141 * parse "a=framesize:96 320-240"
145 while (*sdp_line_ptr
&& *sdp_line_ptr
== ' ')
147 /* ignore RTP payload ID */
148 while (*sdp_line_ptr
&& *sdp_line_ptr
!= ' ')
151 while (*sdp_line_ptr
&& *sdp_line_ptr
== ' ')
153 /* extract the actual video resolution description */
154 while (*sdp_line_ptr
&& *sdp_line_ptr
!= '-' &&
155 (str_video_width_ptr
- str_video_width
) < sizeof(str_video_width
) - 1)
156 *str_video_width_ptr
++ = *sdp_line_ptr
++;
157 /* add trailing zero byte */
158 *str_video_width_ptr
= '\0';
160 /* determine the width value */
161 codec
->width
= atoi(str_video_width
);
162 /* jump beyond the "-" and determine the height value */
163 codec
->height
= atoi(sdp_line_ptr
+ 1);
164 } else if (av_strstart(sdp_line_ptr
, "fmtp:", &sdp_line_ptr
)) {
165 return ff_parse_fmtp(ctx
, current_stream
, hevc_data
, sdp_line_ptr
,
166 hevc_sdp_parse_fmtp_config
);
172 static int hevc_handle_packet(AVFormatContext
*ctx
, PayloadContext
*rtp_hevc_ctx
,
173 AVStream
*st
, AVPacket
*pkt
, uint32_t *timestamp
,
174 const uint8_t *buf
, int len
, uint16_t seq
,
177 const uint8_t *rtp_pl
= buf
;
178 int tid
, lid
, nal_type
;
179 int first_fragment
, last_fragment
, fu_type
;
180 uint8_t new_nal_header
[2];
183 /* sanity check for size of input packet: 1 byte payload at least */
184 if (len
< RTP_HEVC_PAYLOAD_HEADER_SIZE
+ 1) {
185 av_log(ctx
, AV_LOG_ERROR
, "Too short RTP/HEVC packet, got %d bytes\n", len
);
186 return AVERROR_INVALIDDATA
;
190 decode the HEVC payload header according to section 4 of draft version 6:
193 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
194 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
195 |F| Type | LayerId | TID |
196 +-------------+-----------------+
198 Forbidden zero (F): 1 bit
199 NAL unit type (Type): 6 bits
200 NUH layer ID (LayerId): 6 bits
201 NUH temporal ID plus 1 (TID): 3 bits
203 nal_type
= (buf
[0] >> 1) & 0x3f;
204 lid
= ((buf
[0] << 5) & 0x20) | ((buf
[1] >> 3) & 0x1f);
207 /* sanity check for correct layer ID */
209 /* future scalable or 3D video coding extensions */
210 avpriv_report_missing_feature(ctx
, "Multi-layer HEVC coding\n");
211 return AVERROR_PATCHWELCOME
;
214 /* sanity check for correct temporal ID */
216 av_log(ctx
, AV_LOG_ERROR
, "Illegal temporal ID in RTP/HEVC packet\n");
217 return AVERROR_INVALIDDATA
;
220 /* sanity check for correct NAL unit type */
222 av_log(ctx
, AV_LOG_ERROR
, "Unsupported (HEVC) NAL type (%d)\n", nal_type
);
223 return AVERROR_INVALIDDATA
;
227 /* aggregated packets (AP) */
229 /* pass the HEVC payload header */
230 buf
+= RTP_HEVC_PAYLOAD_HEADER_SIZE
;
231 len
-= RTP_HEVC_PAYLOAD_HEADER_SIZE
;
233 /* pass the HEVC DONL field */
234 if (rtp_hevc_ctx
->using_donl_field
) {
235 buf
+= RTP_HEVC_DONL_FIELD_SIZE
;
236 len
-= RTP_HEVC_DONL_FIELD_SIZE
;
240 /* video parameter set (VPS) */
242 /* sequence parameter set (SPS) */
244 /* picture parameter set (PPS) */
246 /* supplemental enhancement information (SEI) */
248 /* single NAL unit packet */
250 /* sanity check for size of input packet: 1 byte payload at least */
252 av_log(ctx
, AV_LOG_ERROR
,
253 "Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n",
255 return AVERROR_INVALIDDATA
;
258 /* create A/V packet */
259 if ((res
= av_new_packet(pkt
, sizeof(start_sequence
) + len
)) < 0)
261 /* A/V packet: copy start sequence */
262 memcpy(pkt
->data
, start_sequence
, sizeof(start_sequence
));
263 /* A/V packet: copy NAL unit data */
264 memcpy(pkt
->data
+ sizeof(start_sequence
), buf
, len
);
267 /* fragmentation unit (FU) */
269 /* pass the HEVC payload header */
270 buf
+= RTP_HEVC_PAYLOAD_HEADER_SIZE
;
271 len
-= RTP_HEVC_PAYLOAD_HEADER_SIZE
;
274 return AVERROR_INVALIDDATA
;
283 Start fragment (S): 1 bit
284 End fragment (E): 1 bit
287 first_fragment
= buf
[0] & 0x80;
288 last_fragment
= buf
[0] & 0x40;
289 fu_type
= buf
[0] & 0x3f;
291 /* pass the HEVC FU header */
292 buf
+= RTP_HEVC_FU_HEADER_SIZE
;
293 len
-= RTP_HEVC_FU_HEADER_SIZE
;
295 /* pass the HEVC DONL field */
296 if (rtp_hevc_ctx
->using_donl_field
) {
297 buf
+= RTP_HEVC_DONL_FIELD_SIZE
;
298 len
-= RTP_HEVC_DONL_FIELD_SIZE
;
301 av_dlog(ctx
, " FU type %d with %d bytes\n", fu_type
, len
);
304 new_nal_header
[0] = (rtp_pl
[0] & 0x81) | (fu_type
<< 1);
305 new_nal_header
[1] = rtp_pl
[1];
307 /* start fragment vs. subsequent fragments */
308 if (first_fragment
) {
309 if (!last_fragment
) {
310 /* create A/V packet which is big enough */
311 if ((res
= av_new_packet(pkt
, sizeof(start_sequence
) + sizeof(new_nal_header
) + len
)) < 0)
313 /* A/V packet: copy start sequence */
314 memcpy(pkt
->data
, start_sequence
, sizeof(start_sequence
));
315 /* A/V packet: copy new NAL header */
316 memcpy(pkt
->data
+ sizeof(start_sequence
), new_nal_header
, sizeof(new_nal_header
));
317 /* A/V packet: copy NAL unit data */
318 memcpy(pkt
->data
+ sizeof(start_sequence
) + sizeof(new_nal_header
), buf
, len
);
320 av_log(ctx
, AV_LOG_ERROR
, "Illegal combination of S and E bit in RTP/HEVC packet\n");
321 res
= AVERROR_INVALIDDATA
;
324 /* create A/V packet */
325 if ((res
= av_new_packet(pkt
, len
)) < 0)
327 /* A/V packet: copy NAL unit data */
328 memcpy(pkt
->data
, buf
, len
);
331 /* sanity check for size of input packet: 1 byte payload at least */
332 av_log(ctx
, AV_LOG_ERROR
,
333 "Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n",
335 res
= AVERROR_INVALIDDATA
;
341 /* Temporal scalability control information (TSCI) */
342 avpriv_report_missing_feature(ctx
, "PACI packets for RTP/HEVC\n");
343 res
= AVERROR_PATCHWELCOME
;
347 pkt
->stream_index
= st
->index
;
352 RTPDynamicProtocolHandler ff_hevc_dynamic_handler
= {
354 .codec_type
= AVMEDIA_TYPE_VIDEO
,
355 .codec_id
= AV_CODEC_ID_HEVC
,
357 .parse_sdp_a_line
= hevc_parse_sdp_line
,
358 .alloc
= hevc_new_context
,
359 .free
= hevc_free_context
,
360 .parse_packet
= hevc_handle_packet
363 RTPDynamicProtocolHandler ff_h265_dynamic_handler
= {
365 .codec_type
= AVMEDIA_TYPE_VIDEO
,
366 .codec_id
= AV_CODEC_ID_HEVC
,
368 .parse_sdp_a_line
= hevc_parse_sdp_line
,
369 .alloc
= hevc_new_context
,
370 .free
= hevc_free_context
,
371 .parse_packet
= hevc_handle_packet