| @@ -224,12 +224,33 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type, int track_idx · 223 unmodified lines |
| 224 | 224 | return st; |
| 225 | 225 | } |
| 226 | 226 | |
| 227 | | −static int flv_same_audio_codec(AVCodecParameters *apar, int flags) |
| 227 | +static int flv_same_audio_codec(AVCodecParameters *apar, int flags, uint32_t codec_fourcc) |
| 228 | 228 | { |
| 229 | 229 | int bits_per_coded_sample = (flags & FLV_AUDIO_SAMPLESIZE_MASK) ? 16 : 8; |
| 230 | 230 | int flv_codecid = flags & FLV_AUDIO_CODECID_MASK; |
| 231 | 231 | int codec_id; |
| 232 | 232 | |
| 233 | + switch (codec_fourcc) { |
| 234 | + case MKBETAG('m', 'p', '4', 'a'): |
| 235 | + return apar->codec_id == AV_CODEC_ID_AAC; |
| 236 | + case MKBETAG('O', 'p', 'u', 's'): |
| 237 | + return apar->codec_id == AV_CODEC_ID_OPUS; |
| 238 | + case MKBETAG('.', 'm', 'p', '3'): |
| 239 | + return apar->codec_id == AV_CODEC_ID_MP3; |
| 240 | + case MKBETAG('f', 'L', 'a', 'C'): |
| 241 | + return apar->codec_id == AV_CODEC_ID_FLAC; |
| 242 | + case MKBETAG('a', 'c', '-', '3'): |
| 243 | + return apar->codec_id == AV_CODEC_ID_AC3; |
| 244 | + case MKBETAG('e', 'c', '-', '3'): |
| 245 | + return apar->codec_id == AV_CODEC_ID_EAC3; |
| 246 | + case 0: |
| 247 | + // Not enhanced flv, continue as normal. |
| 248 | + break; |
| 249 | + default: |
| 250 | + // Unknown FOURCC |
| 251 | + return 0; |
| 252 | + } |
| 253 | + |
| 233 | 254 | if (!apar->codec_id && !apar->codec_tag) |
| 234 | 255 | return 1; |
| 235 | 256 | |
| @@ -328,6 +349,24 @@ static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream, · 92 unmodified lines |
| 328 | 349 | apar->sample_rate = 8000; |
| 329 | 350 | apar->codec_id = AV_CODEC_ID_PCM_ALAW; |
| 330 | 351 | break; |
| 352 | + case MKBETAG('m', 'p', '4', 'a'): |
| 353 | + apar->codec_id = AV_CODEC_ID_AAC; |
| 354 | + return; |
| 355 | + case MKBETAG('O', 'p', 'u', 's'): |
| 356 | + apar->codec_id = AV_CODEC_ID_OPUS; |
| 357 | + return; |
| 358 | + case MKBETAG('.', 'm', 'p', '3'): |
| 359 | + apar->codec_id = AV_CODEC_ID_MP3; |
| 360 | + return; |
| 361 | + case MKBETAG('f', 'L', 'a', 'C'): |
| 362 | + apar->codec_id = AV_CODEC_ID_FLAC; |
| 363 | + return; |
| 364 | + case MKBETAG('a', 'c', '-', '3'): |
| 365 | + apar->codec_id = AV_CODEC_ID_AC3; |
| 366 | + return; |
| 367 | + case MKBETAG('e', 'c', '-', '3'): |
| 368 | + apar->codec_id = AV_CODEC_ID_EAC3; |
| 369 | + return; |
| 331 | 370 | default: |
| 332 | 371 | avpriv_request_sample(s, "Audio codec (%x)", |
| 333 | 372 | flv_codecid >> FLV_AUDIO_CODECID_OFFSET); |
| @@ -1249,7 +1288,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) · 915 unmodified lines |
| 1249 | 1288 | int multitrack = 0; |
| 1250 | 1289 | int pkt_type = 0; |
| 1251 | 1290 | uint8_t track_idx = 0; |
| 1252 | | − uint32_t video_codec_id = 0; |
| 1291 | + uint32_t codec_id = 0; |
| 1253 | 1292 | |
| 1254 | 1293 | retry: |
| 1255 | 1294 | /* pkt size is repeated at end. skip it */ |
| @@ -1293,16 +1332,31 @@ retry: · 37 unmodified lines |
| 1293 | 1332 | stream_type = FLV_STREAM_TYPE_AUDIO; |
| 1294 | 1333 | flags = avio_r8(s->pb); |
| 1295 | 1334 | size--; |
| 1335 | + |
| 1336 | + if ((flags & FLV_AUDIO_CODECID_MASK) == FLV_CODECID_EX_HEADER) { |
| 1337 | + enhanced_flv = 1; |
| 1338 | + pkt_type = flags & ~FLV_AUDIO_CODECID_MASK; |
| 1339 | + |
| 1340 | + channels = 0; |
| 1341 | + |
| 1342 | + if (pkt_type == AudioPacketTypeMultitrack) { |
| 1343 | + av_log(s, AV_LOG_ERROR, "Multitrack audio is unsupported!\n"); |
| 1344 | + return AVERROR_PATCHWELCOME; |
| 1345 | + } |
| 1346 | + |
| 1347 | + codec_id = avio_rb32(s->pb); |
| 1348 | + size -= 4; |
| 1349 | + } |
| 1296 | 1350 | } else if (type == FLV_TAG_TYPE_VIDEO) { |
| 1297 | 1351 | stream_type = FLV_STREAM_TYPE_VIDEO; |
| 1298 | 1352 | flags = avio_r8(s->pb); |
| 1299 | | − video_codec_id = flags & FLV_VIDEO_CODECID_MASK; |
| 1353 | + codec_id = flags & FLV_VIDEO_CODECID_MASK; |
| 1300 | 1354 | /* |
| 1301 | 1355 | * Reference Enhancing FLV 2023-03-v1.0.0-B.8 |
| 1302 | 1356 | * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp-v1.pdf |
| 1303 | 1357 | * */ |
| 1304 | 1358 | enhanced_flv = (flags >> 7) & 1; |
| 1305 | | − pkt_type = enhanced_flv ? video_codec_id : 0; |
| 1359 | + pkt_type = enhanced_flv ? codec_id : 0; |
| 1306 | 1360 | size--; |
| 1307 | 1361 | |
| 1308 | 1362 | if (pkt_type == PacketTypeMultitrack) { |
| @@ -1320,7 +1374,7 @@ retry: · 11 unmodified lines |
| 1320 | 1374 | } |
| 1321 | 1375 | |
| 1322 | 1376 | if (enhanced_flv) { |
| 1323 | | − video_codec_id = avio_rb32(s->pb); |
| 1377 | + codec_id = avio_rb32(s->pb); |
| 1324 | 1378 | size -= 4; |
| 1325 | 1379 | } |
| 1326 | 1380 | if (multitrack) { |
| @@ -1388,11 +1442,11 @@ skip: · 61 unmodified lines |
| 1388 | 1442 | st = s->streams[i]; |
| 1389 | 1443 | if (stream_type == FLV_STREAM_TYPE_AUDIO) { |
| 1390 | 1444 | if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && |
| 1391 | | − (s->audio_codec_id || flv_same_audio_codec(st->codecpar, flags))) |
| 1445 | + (s->audio_codec_id || flv_same_audio_codec(st->codecpar, flags, codec_id))) |
| 1392 | 1446 | break; |
| 1393 | 1447 | } else if (stream_type == FLV_STREAM_TYPE_VIDEO) { |
| 1394 | 1448 | if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && |
| 1395 | | − (s->video_codec_id || flv_same_video_codec(st->codecpar, video_codec_id)) && |
| 1449 | + (s->video_codec_id || flv_same_video_codec(st->codecpar, codec_id)) && |
| 1396 | 1450 | st->id == track_idx) |
| 1397 | 1451 | break; |
| 1398 | 1452 | } else if (stream_type == FLV_STREAM_TYPE_SUBTITLE) { |
| @@ -1461,7 +1515,7 @@ retry_duration: · 62 unmodified lines |
| 1461 | 1515 | flv->searched_for_end = 1; |
| 1462 | 1516 | } |
| 1463 | 1517 | |
| 1464 | | − if (stream_type == FLV_STREAM_TYPE_AUDIO) { |
| 1518 | + if (stream_type == FLV_STREAM_TYPE_AUDIO && !enhanced_flv) { |
| 1465 | 1519 | int bits_per_coded_sample; |
| 1466 | 1520 | channels = (flags & FLV_AUDIO_CHANNEL_MASK) == FLV_STEREO ? 2 : 1; |
| 1467 | 1521 | sample_rate = 44100 << ((flags & FLV_AUDIO_SAMPLERATE_MASK) >> |
| @@ -1493,8 +1547,48 @@ retry_duration: · 25 unmodified lines |
| 1493 | 1547 | sample_rate = par->sample_rate; |
| 1494 | 1548 | avcodec_parameters_free(&par); |
| 1495 | 1549 | } |
| 1550 | + } else if (stream_type == FLV_STREAM_TYPE_AUDIO) { |
| 1551 | + if (!st->codecpar->codec_id) { |
| 1552 | + flv_set_audio_codec(s, st, st->codecpar, |
| 1553 | + codec_id ? codec_id : (flags & FLV_AUDIO_CODECID_MASK)); |
| 1554 | + flv->last_sample_rate = 0; |
| 1555 | + flv->last_channels = 0; |
| 1556 | + } |
| 1557 | + |
| 1558 | + // These are not signalled in the flags anymore |
| 1559 | + channels = 0; |
| 1560 | + sample_rate = 0; |
| 1561 | + |
| 1562 | + if (pkt_type == AudioPacketTypeMultichannelConfig) { |
| 1563 | + int channel_order = avio_r8(s->pb); |
| 1564 | + channels = avio_r8(s->pb); |
| 1565 | + size -= 2; |
| 1566 | + |
| 1567 | + if (channel_order == AudioChannelOrderCustom) { |
| 1568 | + for (i = 0; i < channels; i++) { |
| 1569 | + avio_r8(s->pb); // audio channel mapping |
| 1570 | + size--; |
| 1571 | + } |
| 1572 | + } else if (channel_order == AudioChannelOrderNative) { |
| 1573 | + avio_rb32(s->pb); // audio channel flags |
| 1574 | + size -= 4; |
| 1575 | + } |
| 1576 | + |
| 1577 | + if (!av_channel_layout_check(&st->codecpar->ch_layout)) { |
| 1578 | + ///TODO: This can be much more sophisticated with above info. |
| 1579 | + av_channel_layout_default(&st->codecpar->ch_layout, channels); |
| 1580 | + flv->last_channels = channels; |
| 1581 | + } |
| 1582 | + |
| 1583 | + if (channels != flv->last_channels) { |
| 1584 | + flv->last_channels = channels; |
| 1585 | + ff_add_param_change(pkt, channels, 0, 0, 0, 0); |
| 1586 | + } |
| 1587 | + |
| 1588 | + goto leave; |
| 1589 | + } |
| 1496 | 1590 | } else if (stream_type == FLV_STREAM_TYPE_VIDEO) { |
| 1497 | | − int ret = flv_set_video_codec(s, st, video_codec_id, 1); |
| 1591 | + int ret = flv_set_video_codec(s, st, codec_id, 1); |
| 1498 | 1592 | if (ret < 0) |
| 1499 | 1593 | return ret; |
| 1500 | 1594 | size -= ret; |
| @@ -1505,13 +1599,15 @@ retry_duration: · 4 unmodified lines |
| 1505 | 1599 | } |
| 1506 | 1600 | |
| 1507 | 1601 | if (st->codecpar->codec_id == AV_CODEC_ID_AAC || |
| 1602 | + st->codecpar->codec_id == AV_CODEC_ID_OPUS || |
| 1603 | + st->codecpar->codec_id == AV_CODEC_ID_FLAC || |
| 1508 | 1604 | st->codecpar->codec_id == AV_CODEC_ID_H264 || |
| 1509 | 1605 | st->codecpar->codec_id == AV_CODEC_ID_MPEG4 || |
| 1510 | 1606 | st->codecpar->codec_id == AV_CODEC_ID_HEVC || |
| 1511 | 1607 | st->codecpar->codec_id == AV_CODEC_ID_AV1 || |
| 1512 | 1608 | st->codecpar->codec_id == AV_CODEC_ID_VP9) { |
| 1513 | 1609 | int type = 0; |
| 1514 | | − if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO) { |
| 1610 | + if (enhanced_flv) { |
| 1515 | 1611 | type = pkt_type; |
| 1516 | 1612 | } else { |
| 1517 | 1613 | type = avio_r8(s->pb); |
| @@ -1547,6 +1643,7 @@ retry_duration: · 29 unmodified lines |
| 1547 | 1643 | size -= 3; |
| 1548 | 1644 | } |
| 1549 | 1645 | if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC || |
| 1646 | + st->codecpar->codec_id == AV_CODEC_ID_OPUS || st->codecpar->codec_id == AV_CODEC_ID_FLAC || |
| 1550 | 1647 | st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_HEVC || |
| 1551 | 1648 | st->codecpar->codec_id == AV_CODEC_ID_AV1 || st->codecpar->codec_id == AV_CODEC_ID_VP9)) { |
| 1552 | 1649 | AVDictionaryEntry *t; |
| @@ -1602,7 +1699,7 @@ retry_duration: · 49 unmodified lines |
| 1602 | 1699 | flv->mt_extradata_sz[track_idx] = 0; |
| 1603 | 1700 | } |
| 1604 | 1701 | } |
| 1605 | | − if (stream_type == FLV_STREAM_TYPE_AUDIO && |
| 1702 | + if (stream_type == FLV_STREAM_TYPE_AUDIO && !enhanced_flv && |
| 1606 | 1703 | (sample_rate != flv->last_sample_rate || |
| 1607 | 1704 | channels != flv->last_channels)) { |
| 1608 | 1705 | flv->last_sample_rate = sample_rate; |