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>
... | ... |
@@ -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 |
} |