From 8b9edb10cac98c618f5d491861dbe6cb7e90caaa Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
Date: Mon, 23 Mar 2020 02:38:11 +0100
Subject: [PATCH] avformat/matroskaenc: Write level 1 elements in one go
Up until now, writing level 1 elements proceeded as follows: First, the
element id was written to the ordinary output AVIOContext and a dynamic
buffer was opened for the content of the level 1 element in
start_ebml_master_crc32(). Then this buffer was actually used and after it
was closed (in end_ebml_master_crc32()), the size field corresponding to
the buffer's size was written, after which the actual data was written.
This commit changes this: Nothing is written to the main AVIOContext any
more in start_ebml_master_crc32(). end_ebml_master_crc32() now writes
both the id, the length field as well as the data. This is benefical for
streaming, because a client that receives just a Cluster ID and nothing
more might infer that this is EOF; in certain usecases there is also the
danger of a client receiving the Cluster without the actual Cluster ID
at the beginning.
Addresses #8578.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
---
libavformat/matroskaenc.c | 65 ++++++++++++++++++++++-----------------
1 file changed, 36 insertions(+), 29 deletions(-)
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index cef504fa05..2014d73845 100644
|
a
|
b
|
static void end_ebml_master(AVIOContext *pb, ebml_master master)
|
| 331 | 331 | avio_seek(pb, pos, SEEK_SET); |
| 332 | 332 | } |
| 333 | 333 | |
| 334 | | static int start_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv, |
| 335 | | uint32_t elementid) |
| | 334 | static int start_ebml_master_crc32(AVIOContext **dyn_cp, MatroskaMuxContext *mkv) |
| 336 | 335 | { |
| 337 | 336 | int ret; |
| 338 | 337 | |
| 339 | 338 | if ((ret = avio_open_dyn_buf(dyn_cp)) < 0) |
| 340 | 339 | return ret; |
| 341 | 340 | |
| 342 | | put_ebml_id(pb, elementid); |
| 343 | 341 | if (mkv->write_crc) |
| 344 | 342 | put_ebml_void(*dyn_cp, 6); /* Reserve space for CRC32 so position/size calculations using avio_tell() take it into account */ |
| 345 | 343 | |
| 346 | 344 | return 0; |
| 347 | 345 | } |
| 348 | 346 | |
| 349 | | static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv) |
| | 347 | static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, |
| | 348 | MatroskaMuxContext *mkv, uint32_t id) |
| 350 | 349 | { |
| 351 | 350 | uint8_t *buf, crc[4]; |
| 352 | 351 | int size, skip = 0; |
| 353 | 352 | |
| | 353 | put_ebml_id(pb, id); |
| 354 | 354 | size = avio_close_dyn_buf(*dyn_cp, &buf); |
| 355 | 355 | put_ebml_num(pb, size, 0); |
| 356 | 356 | if (mkv->write_crc) { |
| … |
… |
static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, Matrosk
|
| 368 | 368 | * Complete ebml master without destroying the buffer, allowing for later updates |
| 369 | 369 | */ |
| 370 | 370 | static void end_ebml_master_crc32_preliminary(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv, |
| 371 | | int64_t *pos) |
| | 371 | uint32_t id, int64_t *pos) |
| 372 | 372 | { |
| 373 | 373 | uint8_t *buf; |
| 374 | 374 | int size = avio_get_dyn_buf(*dyn_cp, &buf); |
| 375 | 375 | |
| 376 | 376 | *pos = avio_tell(pb); |
| 377 | 377 | |
| | 378 | put_ebml_id(pb, id); |
| 378 | 379 | put_ebml_num(pb, size, 0); |
| 379 | 380 | avio_write(pb, buf, size); |
| 380 | 381 | } |
| … |
… |
static int64_t mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv)
|
| 500 | 501 | } |
| 501 | 502 | } |
| 502 | 503 | |
| 503 | | if (start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_SEEKHEAD) < 0) { |
| | 504 | if (start_ebml_master_crc32(&dyn_cp, mkv) < 0) { |
| 504 | 505 | currentpos = -1; |
| 505 | 506 | goto fail; |
| 506 | 507 | } |
| … |
… |
static int64_t mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv)
|
| 517 | 518 | put_ebml_uint(dyn_cp, MATROSKA_ID_SEEKPOSITION, entry->segmentpos); |
| 518 | 519 | end_ebml_master(dyn_cp, seekentry); |
| 519 | 520 | } |
| 520 | | end_ebml_master_crc32(pb, &dyn_cp, mkv); |
| | 521 | end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_SEEKHEAD); |
| 521 | 522 | |
| 522 | 523 | if (seekhead->reserved_size > 0) { |
| 523 | 524 | uint64_t remaining = seekhead->filepos + seekhead->reserved_size - avio_tell(pb); |
| … |
… |
static int64_t mkv_write_cues(AVFormatContext *s, mkv_cues *cues, mkv_track *tra
|
| 574 | 575 | int i, j, ret; |
| 575 | 576 | |
| 576 | 577 | currentpos = avio_tell(pb); |
| 577 | | ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CUES); |
| | 578 | ret = start_ebml_master_crc32(&dyn_cp, mkv); |
| 578 | 579 | if (ret < 0) |
| 579 | 580 | return ret; |
| 580 | 581 | |
| … |
… |
static int64_t mkv_write_cues(AVFormatContext *s, mkv_cues *cues, mkv_track *tra
|
| 620 | 621 | i += j - 1; |
| 621 | 622 | end_ebml_master(dyn_cp, cuepoint); |
| 622 | 623 | } |
| 623 | | end_ebml_master_crc32(pb, &dyn_cp, mkv); |
| | 624 | end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CUES); |
| 624 | 625 | |
| 625 | 626 | return currentpos; |
| 626 | 627 | } |
| … |
… |
static int mkv_write_tracks(AVFormatContext *s)
|
| 1450 | 1451 | if (ret < 0) |
| 1451 | 1452 | return ret; |
| 1452 | 1453 | |
| 1453 | | ret = start_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS); |
| | 1454 | ret = start_ebml_master_crc32(&mkv->tracks_bc, mkv); |
| 1454 | 1455 | if (ret < 0) |
| 1455 | 1456 | return ret; |
| 1456 | 1457 | |
| … |
… |
static int mkv_write_tracks(AVFormatContext *s)
|
| 1465 | 1466 | } |
| 1466 | 1467 | |
| 1467 | 1468 | if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) |
| 1468 | | end_ebml_master_crc32_preliminary(pb, &mkv->tracks_bc, mkv, &mkv->tracks_pos); |
| | 1469 | end_ebml_master_crc32_preliminary(pb, &mkv->tracks_bc, mkv, |
| | 1470 | MATROSKA_ID_TRACKS, &mkv->tracks_pos); |
| 1469 | 1471 | else |
| 1470 | | end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv); |
| | 1472 | end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS); |
| 1471 | 1473 | |
| 1472 | 1474 | return 0; |
| 1473 | 1475 | } |
| … |
… |
static int mkv_write_chapters(AVFormatContext *s)
|
| 1486 | 1488 | ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_CHAPTERS, avio_tell(pb)); |
| 1487 | 1489 | if (ret < 0) return ret; |
| 1488 | 1490 | |
| 1489 | | ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CHAPTERS); |
| | 1491 | ret = start_ebml_master_crc32(&dyn_cp, mkv); |
| 1490 | 1492 | if (ret < 0) return ret; |
| 1491 | 1493 | |
| 1492 | 1494 | editionentry = start_ebml_master(dyn_cp, MATROSKA_ID_EDITIONENTRY, 0); |
| … |
… |
static int mkv_write_chapters(AVFormatContext *s)
|
| 1524 | 1526 | end_ebml_master(dyn_cp, chapteratom); |
| 1525 | 1527 | } |
| 1526 | 1528 | end_ebml_master(dyn_cp, editionentry); |
| 1527 | | end_ebml_master_crc32(pb, &dyn_cp, mkv); |
| | 1529 | end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CHAPTERS); |
| 1528 | 1530 | |
| 1529 | 1531 | mkv->wrote_chapters = 1; |
| 1530 | 1532 | return 0; |
| … |
… |
static int mkv_write_tag_targets(AVFormatContext *s, uint32_t elementid,
|
| 1576 | 1578 | ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_TAGS, avio_tell(s->pb)); |
| 1577 | 1579 | if (ret < 0) return ret; |
| 1578 | 1580 | |
| 1579 | | start_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS); |
| | 1581 | start_ebml_master_crc32(&mkv->tags_bc, mkv); |
| | 1582 | if (ret < 0) |
| | 1583 | return ret; |
| 1580 | 1584 | } |
| 1581 | 1585 | pb = mkv->tags_bc; |
| 1582 | 1586 | |
| … |
… |
static int mkv_write_tags(AVFormatContext *s)
|
| 1716 | 1720 | |
| 1717 | 1721 | if (mkv->tags_bc) { |
| 1718 | 1722 | if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) |
| 1719 | | end_ebml_master_crc32_preliminary(s->pb, &mkv->tags_bc, mkv, &mkv->tags_pos); |
| | 1723 | end_ebml_master_crc32_preliminary(s->pb, &mkv->tags_bc, mkv, |
| | 1724 | MATROSKA_ID_TAGS, &mkv->tags_pos); |
| 1720 | 1725 | else |
| 1721 | | end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv); |
| | 1726 | end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS); |
| 1722 | 1727 | } |
| 1723 | 1728 | return 0; |
| 1724 | 1729 | } |
| … |
… |
static int mkv_write_attachments(AVFormatContext *s)
|
| 1742 | 1747 | ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_ATTACHMENTS, avio_tell(pb)); |
| 1743 | 1748 | if (ret < 0) return ret; |
| 1744 | 1749 | |
| 1745 | | ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_ATTACHMENTS); |
| | 1750 | ret = start_ebml_master_crc32(&dyn_cp, mkv); |
| 1746 | 1751 | if (ret < 0) return ret; |
| 1747 | 1752 | |
| 1748 | 1753 | for (i = 0; i < s->nb_streams; i++) { |
| … |
… |
static int mkv_write_attachments(AVFormatContext *s)
|
| 1815 | 1820 | mkv->attachments->entries[mkv->attachments->num_entries].stream_idx = i; |
| 1816 | 1821 | mkv->attachments->entries[mkv->attachments->num_entries++].fileuid = fileuid; |
| 1817 | 1822 | } |
| 1818 | | end_ebml_master_crc32(pb, &dyn_cp, mkv); |
| | 1823 | end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_ATTACHMENTS); |
| 1819 | 1824 | |
| 1820 | 1825 | return 0; |
| 1821 | 1826 | } |
| … |
… |
static int mkv_write_header(AVFormatContext *s)
|
| 1901 | 1906 | ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_INFO, avio_tell(pb)); |
| 1902 | 1907 | if (ret < 0) goto fail; |
| 1903 | 1908 | |
| 1904 | | ret = start_ebml_master_crc32(pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO); |
| | 1909 | ret = start_ebml_master_crc32(&mkv->info_bc, mkv); |
| 1905 | 1910 | if (ret < 0) |
| 1906 | 1911 | return ret; |
| 1907 | 1912 | pb = mkv->info_bc; |
| … |
… |
static int mkv_write_header(AVFormatContext *s)
|
| 1960 | 1965 | } |
| 1961 | 1966 | } |
| 1962 | 1967 | if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) |
| 1963 | | end_ebml_master_crc32_preliminary(s->pb, &mkv->info_bc, mkv, &mkv->info_pos); |
| | 1968 | end_ebml_master_crc32_preliminary(s->pb, &mkv->info_bc, mkv, |
| | 1969 | MATROSKA_ID_INFO, &mkv->info_pos); |
| 1964 | 1970 | else |
| 1965 | | end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv); |
| | 1971 | end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO); |
| 1966 | 1972 | pb = s->pb; |
| 1967 | 1973 | |
| 1968 | 1974 | // initialize stream_duration fields |
| … |
… |
static void mkv_start_new_cluster(AVFormatContext *s, AVPacket *pkt)
|
| 2258 | 2264 | { |
| 2259 | 2265 | MatroskaMuxContext *mkv = s->priv_data; |
| 2260 | 2266 | |
| 2261 | | end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv); |
| | 2267 | end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv, MATROSKA_ID_CLUSTER); |
| 2262 | 2268 | mkv->cluster_pos = -1; |
| 2263 | 2269 | av_log(s, AV_LOG_DEBUG, |
| 2264 | 2270 | "Starting new cluster at offset %" PRIu64 " bytes, " |
| … |
… |
static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_
|
| 2403 | 2409 | |
| 2404 | 2410 | if (mkv->cluster_pos == -1) { |
| 2405 | 2411 | mkv->cluster_pos = avio_tell(s->pb); |
| 2406 | | ret = start_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv, MATROSKA_ID_CLUSTER); |
| | 2412 | ret = start_ebml_master_crc32(&mkv->cluster_bc, mkv); |
| 2407 | 2413 | if (ret < 0) |
| 2408 | 2414 | return ret; |
| 2409 | 2415 | put_ebml_uint(mkv->cluster_bc, MATROSKA_ID_CLUSTERTIMECODE, FFMAX(0, ts)); |
| … |
… |
static int mkv_write_flush_packet(AVFormatContext *s, AVPacket *pkt)
|
| 2539 | 2545 | |
| 2540 | 2546 | if (!pkt) { |
| 2541 | 2547 | if (mkv->cluster_pos != -1) { |
| 2542 | | end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv); |
| | 2548 | end_ebml_master_crc32(s->pb, &mkv->cluster_bc, |
| | 2549 | mkv, MATROSKA_ID_CLUSTER); |
| 2543 | 2550 | mkv->cluster_pos = -1; |
| 2544 | 2551 | av_log(s, AV_LOG_DEBUG, |
| 2545 | 2552 | "Flushing cluster at offset %" PRIu64 " bytes\n", |
| … |
… |
static int mkv_write_trailer(AVFormatContext *s)
|
| 2570 | 2577 | } |
| 2571 | 2578 | |
| 2572 | 2579 | if (mkv->cluster_bc) { |
| 2573 | | end_ebml_master_crc32(pb, &mkv->cluster_bc, mkv); |
| | 2580 | end_ebml_master_crc32(pb, &mkv->cluster_bc, mkv, MATROSKA_ID_CLUSTER); |
| 2574 | 2581 | } |
| 2575 | 2582 | |
| 2576 | 2583 | ret = mkv_write_chapters(s); |
| … |
… |
static int mkv_write_trailer(AVFormatContext *s)
|
| 2619 | 2626 | avio_seek(mkv->info_bc, mkv->duration_offset, SEEK_SET); |
| 2620 | 2627 | put_ebml_float(mkv->info_bc, MATROSKA_ID_DURATION, mkv->duration); |
| 2621 | 2628 | avio_seek(pb, mkv->info_pos, SEEK_SET); |
| 2622 | | end_ebml_master_crc32(pb, &mkv->info_bc, mkv); |
| | 2629 | end_ebml_master_crc32(pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO); |
| 2623 | 2630 | |
| 2624 | 2631 | // write tracks master |
| 2625 | 2632 | avio_seek(pb, mkv->tracks_pos, SEEK_SET); |
| 2626 | | end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv); |
| | 2633 | end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS); |
| 2627 | 2634 | |
| 2628 | 2635 | // update stream durations |
| 2629 | 2636 | if (!mkv->is_live && mkv->stream_durations) { |
| … |
… |
static int mkv_write_trailer(AVFormatContext *s)
|
| 2652 | 2659 | } |
| 2653 | 2660 | if (mkv->tags_bc && !mkv->is_live) { |
| 2654 | 2661 | avio_seek(pb, mkv->tags_pos, SEEK_SET); |
| 2655 | | end_ebml_master_crc32(pb, &mkv->tags_bc, mkv); |
| | 2662 | end_ebml_master_crc32(pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS); |
| 2656 | 2663 | } |
| 2657 | 2664 | |
| 2658 | 2665 | avio_seek(pb, currentpos, SEEK_SET); |