Browse code

Merge commit '95e177eeb21f3e968aa9353bc69d1946966cc835'

* commit '95e177eeb21f3e968aa9353bc69d1946966cc835':
rtpdec: HEVC/H.265 support

Conflicts:
Changelog
libavformat/rtpdec_hevc.c
libavformat/version.h

See: 96b2ba68c4aef4e92b3e9de87d1fb94f2fb659f0
Merged-by: Michael Niedermayer <michaelni@gmx.at>

Michael Niedermayer authored on 2014/09/03 21:56:12
Showing 3 changed files
... ...
@@ -9,7 +9,7 @@ version <next>:
9 9
 - support for using metadata in stream specifiers in fftools
10 10
 - LZMA compression support in TIFF decoder
11 11
 - support for H.261 RTP payload format (RFC 4587)
12
-- support for HEVC/H.265 RTP payload format (draft v6) - depacketizing
12
+- HEVC/H.265 RTP payload format (draft v6) depacketizer
13 13
 - added codecview filter to visualize information exported by some codecs
14 14
 - matroska 3d support thorugh side data
15 15
 
... ...
@@ -17,61 +17,41 @@
17 17
  * You should have received a copy of the GNU Lesser General Public
18 18
  * License along with FFmpeg; if not, write to the Free Software
19 19
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
20 21
  */
21 22
 
22 23
 #include "libavutil/avstring.h"
24
+
23 25
 #include "avformat.h"
24 26
 #include "rtpdec.h"
25 27
 
26
-#define RTP_HEVC_PAYLOAD_HEADER_SIZE                    2
27
-#define RTP_HEVC_FU_HEADER_SIZE                         1
28
-#define RTP_HEVC_DONL_FIELDS_SIZE                       2
29
-#define HEVC_SPECIFIED_NAL_UNIT_TYPES                   48
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
30 32
 
33
+/* SDP out-of-band signaling data */
31 34
 struct PayloadContext {
32
-    /* SDP out-of-band signaling data */
33 35
     int using_donl_field;
34 36
     int profile_id;
35
-    /* debugging */
36
-#ifdef DEBUG
37
-    int packets_received[HEVC_SPECIFIED_NAL_UNIT_TYPES];
38
-#endif
39 37
 };
40 38
 
41
-#ifdef DEBUG
42
-#define COUNT_HEVC_NAL_TYPE(data, nal_type) if (nal_type < HEVC_SPECIFIED_NAL_UNIT_TYPES) data->packets_received[(nal_type)]++
43
-#else
44
-#define COUNT_HEVC_NAL_TYPE(data, nal_type) do { } while (0)
45
-#endif
46
-
47 39
 static const uint8_t start_sequence[] = { 0x00, 0x00, 0x00, 0x01 };
48 40
 
49
-static PayloadContext *hevc_new_context(void)
41
+static av_cold PayloadContext *hevc_new_context(void)
50 42
 {
51 43
     return av_mallocz(sizeof(PayloadContext));
52 44
 }
53 45
 
54 46
 static av_cold void hevc_free_context(PayloadContext *data)
55 47
 {
56
-#ifdef DEBUG
57
-    int i;
58
-
59
-    for (i = 0; i < HEVC_SPECIFIED_NAL_UNIT_TYPES; i++) {
60
-        if (data->packets_received[i])
61
-            av_log(NULL, AV_LOG_DEBUG, "Received %d packets of NAL unit type %d\n",
62
-                data->packets_received[i], i);
63
-    }
64
-#endif
65
-
66 48
     av_free(data);
67 49
 }
68 50
 
69 51
 static av_cold int hevc_init(AVFormatContext *ctx, int st_index,
70 52
                              PayloadContext *data)
71 53
 {
72
-#ifdef DEBUG
73
-    av_log(ctx, AV_LOG_DEBUG, "hevc_init() for stream %d\n", st_index);
74
-#endif
54
+    av_dlog(ctx, "hevc_init() for stream %d\n", st_index);
75 55
 
76 56
     if (st_index < 0)
77 57
         return 0;
... ...
@@ -82,23 +62,15 @@ static av_cold int hevc_init(AVFormatContext *ctx, int st_index,
82 82
 }
83 83
 
84 84
 static av_cold int hevc_sdp_parse_fmtp_config(AVFormatContext *s,
85
-                                      AVStream *stream,
86
-                                      PayloadContext *hevc_data,
87
-                                      char *attr, char *value)
85
+                                              AVStream *stream,
86
+                                              PayloadContext *hevc_data,
87
+                                              char *attr, char *value)
88 88
 {
89
-
90
-#ifdef DEBUG
91
-    av_log(s, AV_LOG_DEBUG, "SDP: fmtp value %s is %s\n", attr, value);
92
-#endif
93
-
94 89
     /* profile-space: 0-3 */
95 90
     /* profile-id: 0-31 */
96 91
     if (!strcmp(attr, "profile-id")) {
97 92
         hevc_data->profile_id = atoi(value);
98
-
99
-#ifdef DEBUG
100
-        av_log(s, AV_LOG_DEBUG, "SDP: found profile-id: %d\n", hevc_data->profile_id);
101
-#endif
93
+        av_dlog(s, "SDP: found profile-id: %d\n", hevc_data->profile_id);
102 94
     }
103 95
 
104 96
     /* tier-flag: 0-1 */
... ...
@@ -124,22 +96,18 @@ static av_cold int hevc_sdp_parse_fmtp_config(AVFormatContext *s,
124 124
          value MUST be greater than 0.
125 125
     */
126 126
     if (!strcmp(attr, "sprop-max-don-diff")) {
127
-        if(atoi(value) > 0)
127
+        if (atoi(value) > 0)
128 128
             hevc_data->using_donl_field = 1;
129
-
130
-#ifdef DEBUG
131
-        av_log(s, AV_LOG_DEBUG, "SDP: found sprop-max-don-diff in SDP, DON field usage is: %d\n", hevc_data->using_donl_field);
132
-#endif
129
+        av_dlog(s, "Found sprop-max-don-diff in SDP, DON field usage is: %d\n",
130
+                hevc_data->using_donl_field);
133 131
     }
134 132
 
135 133
     /* sprop-depack-buf-nalus: 0-32767 */
136 134
     if (!strcmp(attr, "sprop-depack-buf-nalus")) {
137
-        if(atoi(value) > 0)
135
+        if (atoi(value) > 0)
138 136
             hevc_data->using_donl_field = 1;
139
-
140
-#ifdef DEBUG
141
-        av_log(s, AV_LOG_DEBUG, "SDP: found sprop-depack-buf-nalus in SDP, DON field usage is: %d\n", hevc_data->using_donl_field);
142
-#endif
137
+        av_dlog(s, "Found sprop-depack-buf-nalus in SDP, DON field usage is: %d\n",
138
+                hevc_data->using_donl_field);
143 139
     }
144 140
 
145 141
     /* sprop-depack-buf-bytes: 0-4294967295 */
... ...
@@ -153,16 +121,12 @@ static av_cold int hevc_sdp_parse_fmtp_config(AVFormatContext *s,
153 153
 }
154 154
 
155 155
 static av_cold int hevc_parse_sdp_line(AVFormatContext *ctx, int st_index,
156
-                               PayloadContext *hevc_data, const char *line)
156
+                                       PayloadContext *hevc_data, const char *line)
157 157
 {
158 158
     AVStream *current_stream;
159 159
     AVCodecContext *codec;
160 160
     const char *sdp_line_ptr = line;
161 161
 
162
-#ifdef DEBUG
163
-    av_log(ctx, AV_LOG_DEBUG, "parse_hevc_sdp_line() got SDP line %s\n", line);
164
-#endif
165
-
166 162
     if (st_index < 0)
167 163
         return 0;
168 164
 
... ...
@@ -173,9 +137,10 @@ static av_cold int hevc_parse_sdp_line(AVFormatContext *ctx, int st_index,
173 173
         char str_video_width[50];
174 174
         char *str_video_width_ptr = str_video_width;
175 175
 
176
-        /**
176
+        /*
177 177
          * parse "a=framesize:96 320-240"
178 178
          */
179
+
179 180
         /* ignore spaces */
180 181
         while (*sdp_line_ptr && *sdp_line_ptr == ' ')
181 182
             sdp_line_ptr++;
... ...
@@ -186,19 +151,19 @@ static av_cold int hevc_parse_sdp_line(AVFormatContext *ctx, int st_index,
186 186
         while (*sdp_line_ptr && *sdp_line_ptr == ' ')
187 187
             sdp_line_ptr++;
188 188
         /* extract the actual video resolution description */
189
-        while (*sdp_line_ptr && *sdp_line_ptr != '-' && (str_video_width_ptr - str_video_width) < sizeof(str_video_width) - 1)
189
+        while (*sdp_line_ptr && *sdp_line_ptr != '-' &&
190
+               (str_video_width_ptr - str_video_width) < sizeof(str_video_width) - 1)
190 191
             *str_video_width_ptr++ = *sdp_line_ptr++;
191 192
         /* add trailing zero byte */
192 193
         *str_video_width_ptr = '\0';
193 194
 
194 195
         /* determine the width value */
195 196
         codec->width   = atoi(str_video_width);
196
-        // jump beyond the "-" and determine the height value
197
+        /* jump beyond the "-" and determine the height value */
197 198
         codec->height  = atoi(sdp_line_ptr + 1);
198 199
     } else if (av_strstart(sdp_line_ptr, "fmtp:", &sdp_line_ptr)) {
199
-        return ff_parse_fmtp(ctx, current_stream, hevc_data, sdp_line_ptr, hevc_sdp_parse_fmtp_config);
200
-    } else if (av_strstart(sdp_line_ptr, "cliprect:", &sdp_line_ptr)) {
201
-        // could use this if we wanted.
200
+        return ff_parse_fmtp(ctx, current_stream, hevc_data, sdp_line_ptr,
201
+                             hevc_sdp_parse_fmtp_config);
202 202
     }
203 203
 
204 204
     return 0;
... ...
@@ -213,10 +178,10 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
213 213
     int tid, lid, nal_type;
214 214
     int first_fragment, last_fragment, fu_type;
215 215
     uint8_t new_nal_header[2];
216
-    int res=0;
216
+    int res = 0;
217 217
 
218
-    /* sanity check for size of input packet */
219
-    if (len < 3 /* 2 bytes header and 1 byte payload at least */) {
218
+    /* sanity check for size of input packet: 1 byte payload at least */
219
+    if (len < RTP_HEVC_PAYLOAD_HEADER_SIZE + 1) {
220 220
         av_log(ctx, AV_LOG_ERROR, "Too short RTP/HEVC packet, got %d bytes\n", len);
221 221
         return AVERROR_INVALIDDATA;
222 222
     }
... ...
@@ -240,40 +205,35 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
240 240
     tid  =   buf[1] & 0x07;
241 241
 
242 242
     /* sanity check for correct layer ID */
243
-    if(lid){
243
+    if (lid) {
244 244
         /* future scalable or 3D video coding extensions */
245
-        av_log(ctx, AV_LOG_ERROR, "Multi-layer HEVC coding is not supported yet, a patch is welcome\n");
245
+        avpriv_report_missing_feature(ctx, "Multi-layer HEVC coding\n");
246 246
         return AVERROR_PATCHWELCOME;
247 247
     }
248 248
 
249 249
     /* sanity check for correct temporal ID */
250
-    if(!tid){
250
+    if (!tid) {
251 251
         av_log(ctx, AV_LOG_ERROR, "Illegal temporal ID in RTP/HEVC packet\n");
252 252
         return AVERROR_INVALIDDATA;
253 253
     }
254 254
 
255 255
     /* sanity check for correct NAL unit type */
256
-    if (nal_type > 50){
256
+    if (nal_type > 50) {
257 257
         av_log(ctx, AV_LOG_ERROR, "Unsupported (HEVC) NAL type (%d)\n", nal_type);
258 258
         return AVERROR_INVALIDDATA;
259 259
     }
260 260
 
261
-#ifdef DEBUG
262
-    av_log(ctx, AV_LOG_DEBUG, "hevc_handle_packet() got NAL type %d with %d bytes\n", nal_type, len);
263
-#endif
264
-
265
-    switch(nal_type)
266
-    {
261
+    switch (nal_type) {
267 262
     /* aggregated packets (AP) */
268 263
     case 48:
269 264
         /* pass the HEVC payload header */
270 265
         buf += RTP_HEVC_PAYLOAD_HEADER_SIZE;
271 266
         len -= RTP_HEVC_PAYLOAD_HEADER_SIZE;
272 267
 
273
-        /* pass the HEVC DONL fields */
274
-        if(rtp_hevc_ctx->using_donl_field){
275
-            buf += RTP_HEVC_DONL_FIELDS_SIZE;
276
-            len -= RTP_HEVC_DONL_FIELDS_SIZE;
268
+        /* pass the HEVC DONL field */
269
+        if (rtp_hevc_ctx->using_donl_field) {
270
+            buf += RTP_HEVC_DONL_FIELD_SIZE;
271
+            len -= RTP_HEVC_DONL_FIELD_SIZE;
277 272
         }
278 273
 
279 274
         /* fall-through */
... ...
@@ -287,6 +247,14 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
287 287
     case 39:
288 288
     /* single NAL unit packet */
289 289
     default:
290
+        /* sanity check for size of input packet: 1 byte payload at least */
291
+        if (len < 1) {
292
+            av_log(ctx, AV_LOG_ERROR,
293
+                   "Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n",
294
+                   len, nal_type);
295
+            return AVERROR_INVALIDDATA;
296
+        }
297
+
290 298
         /* create A/V packet */
291 299
         if ((res = av_new_packet(pkt, sizeof(start_sequence) + len)) < 0)
292 300
             return res;
... ...
@@ -295,8 +263,6 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
295 295
         /* A/V packet: copy NAL unit data */
296 296
         memcpy(pkt->data + sizeof(start_sequence), buf, len);
297 297
 
298
-        COUNT_HEVC_NAL_TYPE(rtp_hevc_ctx, nal_type);
299
-
300 298
         break;
301 299
     /* fragmentation unit (FU) */
302 300
     case 49:
... ...
@@ -304,7 +270,9 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
304 304
         buf += RTP_HEVC_PAYLOAD_HEADER_SIZE;
305 305
         len -= RTP_HEVC_PAYLOAD_HEADER_SIZE;
306 306
 
307
-        /**
307
+        if (len < 1)
308
+            return AVERROR_INVALIDDATA;
309
+        /*
308 310
              decode the FU header
309 311
 
310 312
               0 1 2 3 4 5 6 7
... ...
@@ -317,22 +285,20 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
317 317
                 FuType: 6 bits
318 318
         */
319 319
         first_fragment = buf[0] & 0x80;
320
-        last_fragment = buf[0] & 0x40;
321
-        fu_type = buf[0] & 0x3f;
320
+        last_fragment  = buf[0] & 0x40;
321
+        fu_type        = buf[0] & 0x3f;
322 322
 
323 323
         /* pass the HEVC FU header */
324 324
         buf += RTP_HEVC_FU_HEADER_SIZE;
325 325
         len -= RTP_HEVC_FU_HEADER_SIZE;
326 326
 
327
-        /* pass the HEVC DONL fields */
328
-        if(rtp_hevc_ctx->using_donl_field){
329
-            buf += RTP_HEVC_DONL_FIELDS_SIZE;
330
-            len -= RTP_HEVC_DONL_FIELDS_SIZE;
327
+        /* pass the HEVC DONL field */
328
+        if (rtp_hevc_ctx->using_donl_field) {
329
+            buf += RTP_HEVC_DONL_FIELD_SIZE;
330
+            len -= RTP_HEVC_DONL_FIELD_SIZE;
331 331
         }
332 332
 
333
-#ifdef DEBUG
334
-        av_log(ctx, AV_LOG_DEBUG, " FU type %d with %d bytes\n", fu_type, len);
335
-#endif
333
+        av_dlog(ctx, " FU type %d with %d bytes\n", fu_type, len);
336 334
 
337 335
         if (len > 0) {
338 336
             new_nal_header[0] = (rtp_pl[0] & 0x81) | (fu_type << 1);
... ...
@@ -340,7 +306,7 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
340 340
 
341 341
             /* start fragment vs. subsequent fragments */
342 342
             if (first_fragment) {
343
-                if(!last_fragment){
343
+                if (!last_fragment) {
344 344
                     /* create A/V packet which is big enough */
345 345
                     if ((res = av_new_packet(pkt, sizeof(start_sequence) + sizeof(new_nal_header) + len)) < 0)
346 346
                         return res;
... ...
@@ -350,7 +316,7 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
350 350
                     memcpy(pkt->data + sizeof(start_sequence), new_nal_header, sizeof(new_nal_header));
351 351
                     /* A/V packet: copy NAL unit data */
352 352
                     memcpy(pkt->data + sizeof(start_sequence) + sizeof(new_nal_header), buf, len);
353
-                }else{
353
+                } else {
354 354
                     av_log(ctx, AV_LOG_ERROR, "Illegal combination of S and E bit in RTP/HEVC packet\n");
355 355
                     res = AVERROR_INVALIDDATA;
356 356
                 }
... ...
@@ -362,19 +328,18 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
362 362
                 memcpy(pkt->data, buf, len);
363 363
             }
364 364
         } else {
365
-            av_log(ctx, AV_LOG_ERROR, "Too short data for (HEVC) NAL unit, got %d bytes\n", len);
365
+            /* sanity check for size of input packet: 1 byte payload at least */
366
+            av_log(ctx, AV_LOG_ERROR,
367
+                   "Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n",
368
+                   len, nal_type);
366 369
             res = AVERROR_INVALIDDATA;
367 370
         }
368 371
 
369
-        if(!res){
370
-            COUNT_HEVC_NAL_TYPE(rtp_hevc_ctx, fu_type);
371
-        }
372
-
373 372
         break;
374 373
     /* PACI packet */
375 374
     case 50:
376 375
         /* Temporal scalability control information (TSCI) */
377
-        av_log(ctx, AV_LOG_ERROR, "PACI packets for RTP/HEVC are not supported yet, a patch is welcome\n");
376
+        avpriv_report_missing_feature(ctx, "PACI packets for RTP/HEVC\n");
378 377
         res = AVERROR_PATCHWELCOME;
379 378
         break;
380 379
     }
... ...
@@ -398,7 +363,7 @@ RTPDynamicProtocolHandler ff_hevc_dynamic_handler = {
398 398
 RTPDynamicProtocolHandler ff_h265_dynamic_handler = {
399 399
     .enc_name         = "H265",
400 400
     .codec_type       = AVMEDIA_TYPE_VIDEO,
401
-    .codec_id         = AV_CODEC_ID_H265,
401
+    .codec_id         = AV_CODEC_ID_HEVC,
402 402
     .init             = hevc_init,
403 403
     .parse_sdp_a_line = hevc_parse_sdp_line,
404 404
     .alloc            = hevc_new_context,
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR 56
33
-#define LIBAVFORMAT_VERSION_MINOR  3
33
+#define LIBAVFORMAT_VERSION_MINOR  4
34 34
 #define LIBAVFORMAT_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \