Browse code

sdp: Provide out of bound parameter sets for HEVC if extradata is set

Signed-off-by: Martin Storsjö <martin@martin.st>

Martin Storsjö authored on 2014/10/04 05:25:37
Showing 1 changed files
... ...
@@ -29,6 +29,7 @@
29 29
 #include "avformat.h"
30 30
 #include "internal.h"
31 31
 #include "avc.h"
32
+#include "hevc.h"
32 33
 #include "rtp.h"
33 34
 #if CONFIG_NETWORK
34 35
 #include "network.h"
... ...
@@ -222,6 +223,107 @@ static char *extradata2psets(AVCodecContext *c)
222 222
     return psets;
223 223
 }
224 224
 
225
+static char *extradata2psets_hevc(AVCodecContext *c)
226
+{
227
+    char *psets;
228
+    uint8_t *extradata = c->extradata;
229
+    int extradata_size = c->extradata_size;
230
+    uint8_t *tmpbuf = NULL;
231
+    int ps_pos[3] = { 0 };
232
+    static const char * const ps_names[3] = { "vps", "sps", "pps" };
233
+    int num_arrays, num_nalus;
234
+    int pos, i, j;
235
+
236
+    // Convert to hvcc format. Since we need to group multiple NALUs of
237
+    // the same type, and we might need to convert from one format to the
238
+    // other anyway, we get away with a little less work by using the hvcc
239
+    // format.
240
+    if (c->extradata[0] != 1) {
241
+        AVIOContext *pb;
242
+        if (avio_open_dyn_buf(&pb) < 0)
243
+            return NULL;
244
+        if (ff_isom_write_hvcc(pb, c->extradata, c->extradata_size, 0) < 0) {
245
+            avio_close_dyn_buf(pb, &tmpbuf);
246
+            goto err;
247
+        }
248
+        extradata_size = avio_close_dyn_buf(pb, &extradata);
249
+        tmpbuf = extradata;
250
+    }
251
+
252
+    if (extradata_size < 23)
253
+        goto err;
254
+
255
+    num_arrays = extradata[22];
256
+    pos = 23;
257
+    for (i = 0; i < num_arrays; i++) {
258
+        int num_nalus, nalu_type;
259
+        if (pos + 3 > extradata_size)
260
+            goto err;
261
+        nalu_type = extradata[pos] & 0x3f;
262
+        // Not including libavcodec/hevc.h to avoid confusion between
263
+        // NAL_* with the same name for both H264 and HEVC.
264
+        if (nalu_type == 32) // VPS
265
+            ps_pos[0] = pos;
266
+        else if (nalu_type == 33) // SPS
267
+            ps_pos[1] = pos;
268
+        else if (nalu_type == 34) // PPS
269
+            ps_pos[2] = pos;
270
+        num_nalus = AV_RB16(&extradata[pos + 1]);
271
+        pos += 3;
272
+        for (j = 0; j < num_nalus; j++) {
273
+            int len;
274
+            if (pos + 2 > extradata_size)
275
+                goto err;
276
+            len = AV_RB16(&extradata[pos]);
277
+            pos += 2;
278
+            if (pos + len > extradata_size)
279
+                goto err;
280
+            pos += len;
281
+        }
282
+    }
283
+    if (!ps_pos[0] || !ps_pos[1] || !ps_pos[2])
284
+        goto err;
285
+
286
+    psets = av_mallocz(MAX_PSET_SIZE);
287
+    if (!psets)
288
+        goto err;
289
+    psets[0] = '\0';
290
+
291
+    for (i = 0; i < 3; i++) {
292
+        pos = ps_pos[i];
293
+
294
+        if (i > 0)
295
+            av_strlcat(psets, "; ", MAX_PSET_SIZE);
296
+        av_strlcatf(psets, MAX_PSET_SIZE, "sprop-%s=", ps_names[i]);
297
+
298
+        // Skipping boundary checks in the input here; we've already traversed
299
+        // the whole hvcc structure above without issues
300
+        num_nalus = AV_RB16(&extradata[pos + 1]);
301
+        pos += 3;
302
+        for (j = 0; j < num_nalus; j++) {
303
+            int len = AV_RB16(&extradata[pos]);
304
+            int strpos;
305
+            pos += 2;
306
+            if (j > 0)
307
+                av_strlcat(psets, ",", MAX_PSET_SIZE);
308
+            strpos = strlen(psets);
309
+            if (!av_base64_encode(psets + strpos, MAX_PSET_SIZE - strpos,
310
+                                  &extradata[pos], len)) {
311
+                av_free(psets);
312
+                goto err;
313
+            }
314
+            pos += len;
315
+        }
316
+    }
317
+    av_free(tmpbuf);
318
+
319
+    return psets;
320
+
321
+err:
322
+    av_free(tmpbuf);
323
+    return NULL;
324
+}
325
+
225 326
 static char *extradata2config(AVCodecContext *c)
226 327
 {
227 328
     char *config;
... ...
@@ -412,9 +514,11 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c,
412 412
             break;
413 413
         case AV_CODEC_ID_HEVC:
414 414
             if (c->extradata_size)
415
-                av_log(NULL, AV_LOG_WARNING, "HEVC extradata not currently "
416
-                                             "passed properly through SDP\n");
415
+                config = extradata2psets_hevc(c);
417 416
             av_strlcatf(buff, size, "a=rtpmap:%d H265/90000\r\n", payload_type);
417
+            if (config)
418
+                av_strlcatf(buff, size, "a=fmtp:%d %s\r\n",
419
+                                         payload_type, config);
418 420
             break;
419 421
         case AV_CODEC_ID_MPEG4:
420 422
             if (c->extradata_size) {