Browse code

mpegtsenc: Add support for muxing Opus in MPEG-TS

Signed-off-by: Sebastian Dröge <sebastian@centricular.com>
Previous version reviewed-by: Kieran Kunhya <kierank@obe.tv>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>

Sebastian Dröge authored on 2015/11/06 07:35:42
Showing 1 changed files
... ...
@@ -227,6 +227,9 @@ typedef struct MpegTSWriteStream {
227 227
     uint8_t *payload;
228 228
     AVFormatContext *amux;
229 229
     AVRational user_tb;
230
+
231
+    /* For Opus */
232
+    int opus_queued_samples;
230 233
 } MpegTSWriteStream;
231 234
 
232 235
 static void mpegts_write_pat(AVFormatContext *s)
... ...
@@ -314,6 +317,9 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
314 314
         case AV_CODEC_ID_TRUEHD:
315 315
             stream_type = STREAM_TYPE_AUDIO_TRUEHD;
316 316
             break;
317
+        case AV_CODEC_ID_OPUS:
318
+            stream_type = STREAM_TYPE_PRIVATE_DATA;
319
+            break;
317 320
         default:
318 321
             stream_type = STREAM_TYPE_PRIVATE_DATA;
319 322
             break;
... ...
@@ -340,6 +346,82 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
340 340
                 *q++ = 'S';
341 341
                 *q++ = 'D';
342 342
             }
343
+            if (st->codec->codec_id==AV_CODEC_ID_OPUS) {
344
+                /* 6 bytes registration descriptor, 4 bytes Opus audio descriptor */
345
+                if (q - data > SECTION_LENGTH - 6 - 4) {
346
+                    err = 1;
347
+                    break;
348
+                }
349
+
350
+                *q++ = 0x05; /* MPEG-2 registration descriptor*/
351
+                *q++ = 4;
352
+                *q++ = 'O';
353
+                *q++ = 'p';
354
+                *q++ = 'u';
355
+                *q++ = 's';
356
+
357
+                *q++ = 0x7f; /* DVB extension descriptor */
358
+                *q++ = 2;
359
+                *q++ = 0x80;
360
+
361
+                if (st->codec->extradata && st->codec->extradata_size >= 19) {
362
+                    if (st->codec->extradata[18] == 0 && st->codec->channels <= 2) {
363
+                        /* RTP mapping family */
364
+                        *q++ = st->codec->channels;
365
+                    } else if (st->codec->extradata[18] == 1 && st->codec->channels <= 8 &&
366
+                               st->codec->extradata_size >= 21 + st->codec->channels) {
367
+                        static const uint8_t coupled_stream_counts[9] = {
368
+                            1, 0, 1, 1, 2, 2, 2, 3, 3
369
+                        };
370
+                        static const uint8_t channel_map_a[8][8] = {
371
+                            {0},
372
+                            {0, 1},
373
+                            {0, 2, 1},
374
+                            {0, 1, 2, 3},
375
+                            {0, 4, 1, 2, 3},
376
+                            {0, 4, 1, 2, 3, 5},
377
+                            {0, 4, 1, 2, 3, 5, 6},
378
+                            {0, 6, 1, 2, 3, 4, 5, 7},
379
+                        };
380
+                        static const uint8_t channel_map_b[8][8] = {
381
+                            {0},
382
+                            {0, 1},
383
+                            {0, 1, 2},
384
+                            {0, 1, 2, 3},
385
+                            {0, 1, 2, 3, 4},
386
+                            {0, 1, 2, 3, 4, 5},
387
+                            {0, 1, 2, 3, 4, 5, 6},
388
+                            {0, 1, 2, 3, 4, 5, 6, 7},
389
+                        };
390
+                        /* Vorbis mapping family */
391
+
392
+                        if (st->codec->extradata[19] == st->codec->channels - coupled_stream_counts[st->codec->channels] &&
393
+                            st->codec->extradata[20] == coupled_stream_counts[st->codec->channels] &&
394
+                            memcmp(&st->codec->extradata[21], channel_map_a[st->codec->channels], st->codec->channels) == 0) {
395
+                            *q++ = st->codec->channels;
396
+                        } else if (st->codec->channels >= 2 && st->codec->extradata[19] == st->codec->channels &&
397
+                                   st->codec->extradata[20] == 0 &&
398
+                                   memcmp(&st->codec->extradata[21], channel_map_b[st->codec->channels], st->codec->channels) == 0) {
399
+                            *q++ = st->codec->channels | 0x80;
400
+                        } else {
401
+                            /* Unsupported, could write an extended descriptor here */
402
+                            av_log(s, AV_LOG_ERROR, "Unsupported Opus Vorbis-style channel mapping");
403
+                            *q++ = 0xff;
404
+                        }
405
+                    } else {
406
+                        /* Unsupported */
407
+                        av_log(s, AV_LOG_ERROR, "Unsupported Opus channel mapping for family %d", st->codec->extradata[18]);
408
+                        *q++ = 0xff;
409
+                    }
410
+                } else if (st->codec->channels <= 2) {
411
+                    /* Assume RTP mapping family */
412
+                    *q++ = st->codec->channels;
413
+                } else {
414
+                    /* Unsupported */
415
+                    av_log(s, AV_LOG_ERROR, "Unsupported Opus channel mapping");
416
+                    *q++ = 0xff;
417
+                }
418
+            }
343 419
 
344 420
             if (lang) {
345 421
                 char *p;
... ...
@@ -1261,6 +1343,58 @@ static int check_hevc_startcode(AVFormatContext *s, const AVStream *st, const AV
1261 1261
     return 0;
1262 1262
 }
1263 1263
 
1264
+/* Based on GStreamer's gst-plugins-base/ext/ogg/gstoggstream.c
1265
+ * Released under the LGPL v2.1+, written by
1266
+ * Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
1267
+ */
1268
+static int opus_get_packet_samples(AVFormatContext *s, AVPacket *pkt)
1269
+{
1270
+    static const int durations[32] = {
1271
+      480, 960, 1920, 2880,       /* Silk NB */
1272
+      480, 960, 1920, 2880,       /* Silk MB */
1273
+      480, 960, 1920, 2880,       /* Silk WB */
1274
+      480, 960,                   /* Hybrid SWB */
1275
+      480, 960,                   /* Hybrid FB */
1276
+      120, 240, 480, 960,         /* CELT NB */
1277
+      120, 240, 480, 960,         /* CELT NB */
1278
+      120, 240, 480, 960,         /* CELT NB */
1279
+      120, 240, 480, 960,         /* CELT NB */
1280
+    };
1281
+    int toc, frame_duration, nframes, duration;
1282
+
1283
+    if (pkt->size < 1)
1284
+        return 0;
1285
+
1286
+    toc = pkt->data[0];
1287
+
1288
+    frame_duration = durations[toc >> 3];
1289
+    switch (toc & 3) {
1290
+    case 0:
1291
+        nframes = 1;
1292
+        break;
1293
+    case 1:
1294
+        nframes = 2;
1295
+        break;
1296
+    case 2:
1297
+        nframes = 2;
1298
+        break;
1299
+    case 3:
1300
+        if (pkt->size < 2)
1301
+            return 0;
1302
+        nframes = pkt->data[1] & 63;
1303
+        break;
1304
+    }
1305
+
1306
+    duration = nframes * frame_duration;
1307
+    if (duration > 5760) {
1308
+        av_log(s, AV_LOG_WARNING,
1309
+               "Opus packet duration > 120 ms, invalid");
1310
+        return 0;
1311
+    }
1312
+
1313
+    return duration;
1314
+}
1315
+
1264 1316
 static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
1265 1317
 {
1266 1318
     AVStream *st = s->streams[pkt->stream_index];
... ...
@@ -1271,6 +1405,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
1271 1271
     MpegTSWriteStream *ts_st = st->priv_data;
1272 1272
     const int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE) * 2;
1273 1273
     int64_t dts = pkt->dts, pts = pkt->pts;
1274
+    int opus_samples = 0;
1274 1275
 
1275 1276
     if (ts->reemit_pat_pmt) {
1276 1277
         av_log(s, AV_LOG_WARNING,
... ...
@@ -1370,6 +1505,44 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
1370 1370
         int ret = check_hevc_startcode(s, st, pkt);
1371 1371
         if (ret < 0)
1372 1372
             return ret;
1373
+    } else if (st->codec->codec_id == AV_CODEC_ID_OPUS) {
1374
+        if (pkt->size < 2) {
1375
+            av_log(s, AV_LOG_ERROR, "Opus packet too short\n");
1376
+            return AVERROR_INVALIDDATA;
1377
+        }
1378
+
1379
+        /* Add Opus control header */
1380
+        if ((AV_RB16(pkt->data) >> 5) != 0x3ff) {
1381
+            int i, n;
1382
+
1383
+            opus_samples = opus_get_packet_samples(s, pkt);
1384
+
1385
+            data = av_malloc(pkt->size + 2 + pkt->size / 255 + 1);
1386
+            if (!data)
1387
+                return AVERROR(ENOMEM);
1388
+
1389
+            /* TODO: Write trim if needed */
1390
+            data[0] = 0x7f;
1391
+            data[1] = 0xe0;
1392
+
1393
+            n = pkt->size;
1394
+            i = 2;
1395
+            do {
1396
+                data[i] = FFMIN(n, 255);
1397
+                n -= 255;
1398
+                i++;
1399
+            } while (n >= 0);
1400
+
1401
+            av_assert0(2 + pkt->size / 255 + 1 == i);
1402
+
1403
+            memcpy(data + i, pkt->data, pkt->size);
1404
+            buf     = data;
1405
+            size    = pkt->size + 2 + pkt->size / 255 + 1;
1406
+        } else {
1407
+            /* TODO: Can we get TS formatted data here? If so we will
1408
+             * need to count the samples of that too! */
1409
+            av_log(s, AV_LOG_WARNING, "Got MPEG-TS formatted Opus data, unhandled");
1410
+        }
1373 1411
     }
1374 1412
 
1375 1413
     if (pkt->dts != AV_NOPTS_VALUE) {
... ...
@@ -1390,11 +1563,13 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
1390 1390
     if (ts_st->payload_size && (ts_st->payload_size + size > ts->pes_payload_size ||
1391 1391
         (dts != AV_NOPTS_VALUE && ts_st->payload_dts != AV_NOPTS_VALUE &&
1392 1392
          av_compare_ts(dts - ts_st->payload_dts, st->time_base,
1393
-                       s->max_delay, AV_TIME_BASE_Q) >= 0))) {
1393
+                       s->max_delay, AV_TIME_BASE_Q) >= 0) ||
1394
+        ts_st->opus_queued_samples + opus_samples >= 5760 /* 120ms */)) {
1394 1395
         mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_size,
1395 1396
                          ts_st->payload_pts, ts_st->payload_dts,
1396 1397
                          ts_st->payload_flags & AV_PKT_FLAG_KEY);
1397 1398
         ts_st->payload_size = 0;
1399
+        ts_st->opus_queued_samples = 0;
1398 1400
     }
1399 1401
 
1400 1402
     if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO || size > ts->pes_payload_size) {
... ...
@@ -1402,6 +1577,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
1402 1402
         // for video and subtitle, write a single pes packet
1403 1403
         mpegts_write_pes(s, st, buf, size, pts, dts,
1404 1404
                          pkt->flags & AV_PKT_FLAG_KEY);
1405
+        ts_st->opus_queued_samples = 0;
1405 1406
         av_free(data);
1406 1407
         return 0;
1407 1408
     }
... ...
@@ -1414,6 +1590,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
1414 1414
 
1415 1415
     memcpy(ts_st->payload + ts_st->payload_size, buf, size);
1416 1416
     ts_st->payload_size += size;
1417
+    ts_st->opus_queued_samples += opus_samples;
1417 1418
 
1418 1419
     av_free(data);
1419 1420
 
... ...
@@ -1433,6 +1610,7 @@ static void mpegts_write_flush(AVFormatContext *s)
1433 1433
                              ts_st->payload_pts, ts_st->payload_dts,
1434 1434
                              ts_st->payload_flags & AV_PKT_FLAG_KEY);
1435 1435
             ts_st->payload_size = 0;
1436
+            ts_st->opus_queued_samples = 0;
1436 1437
         }
1437 1438
     }
1438 1439
 }