The Matroska muxer uses a dynamic buffer to buffer the content of Clusters before eventually writing them. Up until now, each time a Cluster was written, the dynamic buffer was closed, i.e. freed; now it is only reset, saving allocations of the AVIOContext itself, its opaque as well as most of the reallocations of the buffer.
This is advantageous performance-wise, in particular on systems where reallocations are slow (namely Windows). The following table shows the decicyles for writing a frame on Linux (Ubuntu 19.10) and Windows (7) on an x64 Haswell (to /dev/null on Linux, to stdout which is discarded on Windows (the default values of the size and duration of clusters for seekable output have been explicitly set in this case); in all tests, writing CRC-32 values has been disabled in all tests; calls to the muxer's write_packet function in write_packet() in libavformat/mux.c have been timed; each of the following tests has been repeated 50 times): | Windows before | Windows after | Linux before | Linux after _________________________________________________________________ A | 979437 | 192304 | 259500 | 183320 B | 715936 | 155648 | 152786 | 130879 C | 265115 | 56034 | 78496 | 53243 D | 386224 | 80307 | 128894 | 75354 E | 21732 | 10695 | 11320 | 9801 (A is a 10.2 mb/s file with a GOP length of 2s, amounting to an average Cluster size of about 2.5 MiB; the average Cluster size of B is 1.1 MiB; for C it is 2.35 MiB, for D it is 0.46 MiB; for E - a file with just a single audio track of 158kb/s resulting in a Cluster size of about 100 kB, the relative gains were the smallest, probably because of the small Cluster size.) Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@gmail.com> --- libavformat/matroskaenc.c | 47 ++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 5065b2adbd..8bbacf5cd3 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -337,7 +337,7 @@ static int start_ebml_master_crc32(AVIOContext **dyn_cp, MatroskaMuxContext *mkv { int ret; - if ((ret = avio_open_dyn_buf(dyn_cp)) < 0) + if (!*dyn_cp && (ret = avio_open_dyn_buf(dyn_cp)) < 0) return ret; if (mkv->write_crc) @@ -348,13 +348,13 @@ static int start_ebml_master_crc32(AVIOContext **dyn_cp, MatroskaMuxContext *mkv static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv, uint32_t id, - int length_size) + int length_size, int keep_buffer) { uint8_t *buf, crc[4]; int size, skip = 0; put_ebml_id(pb, id); - size = avio_close_dyn_buf(*dyn_cp, &buf); + size = avio_get_dyn_buf(*dyn_cp, &buf); put_ebml_num(pb, size, length_size); if (mkv->write_crc) { skip = 6; /* Skip reserved 6-byte long void element from the dynamic buffer. */ @@ -363,8 +363,11 @@ static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, } avio_write(pb, buf + skip, size - skip); - av_free(buf); - *dyn_cp = NULL; + if (keep_buffer) { + ffio_reset_dyn_buf(*dyn_cp); + } else { + ffio_free_dyn_buf(dyn_cp); + } } /** @@ -449,7 +452,7 @@ static void mkv_add_seekhead_entry(MatroskaMuxContext *mkv, uint32_t elementid, static int mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv, int error_on_seek_failure, int64_t destpos) { - AVIOContext *dyn_cp; + AVIOContext *dyn_cp = NULL; mkv_seekhead *seekhead = &mkv->seekhead; int64_t remaining, ret64; int i, ret; @@ -476,7 +479,7 @@ static int mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv, put_ebml_uint(dyn_cp, MATROSKA_ID_SEEKPOSITION, entry->segmentpos); end_ebml_master(dyn_cp, seekentry); } - end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_SEEKHEAD, 0); + end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_SEEKHEAD, 0, 0); remaining = seekhead->filepos + seekhead->reserved_size - avio_tell(pb); put_ebml_void(pb, remaining); @@ -1416,7 +1419,7 @@ static int mkv_write_tracks(AVFormatContext *s) end_ebml_master_crc32_preliminary(pb, mkv->tracks_bc, MATROSKA_ID_TRACKS, &mkv->tracks_pos); else - end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS, 0); + end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS, 0, 0); return 0; } @@ -1424,7 +1427,7 @@ static int mkv_write_tracks(AVFormatContext *s) static int mkv_write_chapters(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; - AVIOContext *dyn_cp, *pb = s->pb; + AVIOContext *dyn_cp = NULL, *pb = s->pb; ebml_master editionentry; AVRational scale = {1, 1E9}; int i, ret; @@ -1472,7 +1475,7 @@ static int mkv_write_chapters(AVFormatContext *s) end_ebml_master(dyn_cp, chapteratom); } end_ebml_master(dyn_cp, editionentry); - end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CHAPTERS, 0); + end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CHAPTERS, 0, 0); mkv->wrote_chapters = 1; return 0; @@ -1671,7 +1674,7 @@ static int mkv_write_tags(AVFormatContext *s) end_ebml_master_crc32_preliminary(s->pb, mkv->tags_bc, MATROSKA_ID_TAGS, &mkv->tags_pos); else - end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS, 0); + end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS, 0, 0); } return 0; } @@ -1679,7 +1682,7 @@ static int mkv_write_tags(AVFormatContext *s) static int mkv_write_attachments(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; - AVIOContext *dyn_cp, *pb = s->pb; + AVIOContext *dyn_cp = NULL, *pb = s->pb; AVLFG c; int i, ret; @@ -1767,7 +1770,7 @@ static int mkv_write_attachments(AVFormatContext *s) mkv->attachments->entries[mkv->attachments->num_entries].stream_idx = i; mkv->attachments->entries[mkv->attachments->num_entries++].fileuid = fileuid; } - end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_ATTACHMENTS, 0); + end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_ATTACHMENTS, 0, 0); return 0; } @@ -1908,7 +1911,7 @@ static int mkv_write_header(AVFormatContext *s) end_ebml_master_crc32_preliminary(s->pb, mkv->info_bc, MATROSKA_ID_INFO, &mkv->info_pos); else - end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO, 0); + end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO, 0, 0); pb = s->pb; ret = mkv_write_tracks(s); @@ -2188,7 +2191,7 @@ static void mkv_end_cluster(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; - end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv, MATROSKA_ID_CLUSTER, 0); + end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv, MATROSKA_ID_CLUSTER, 0, 1); mkv->cluster_pos = -1; avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT); } @@ -2492,7 +2495,8 @@ static int mkv_write_trailer(AVFormatContext *s) } if (mkv->cluster_bc) { - end_ebml_master_crc32(pb, &mkv->cluster_bc, mkv, MATROSKA_ID_CLUSTER, 0); + end_ebml_master_crc32(pb, &mkv->cluster_bc, mkv, + MATROSKA_ID_CLUSTER, 0, 0); } ret = mkv_write_chapters(s); @@ -2506,7 +2510,7 @@ static int mkv_write_trailer(AVFormatContext *s) endpos = avio_tell(pb); if (mkv->cues.num_entries) { - AVIOContext *cues; + AVIOContext *cues = NULL; uint64_t size; int64_t cuespos = endpos; int length_size = 0; @@ -2548,7 +2552,8 @@ static int mkv_write_trailer(AVFormatContext *s) } } mkv_add_seekhead_entry(mkv, MATROSKA_ID_CUES, cuespos); - end_ebml_master_crc32(pb, &cues, mkv, MATROSKA_ID_CUES, length_size); + end_ebml_master_crc32(pb, &cues, mkv, MATROSKA_ID_CUES, + length_size, 0); if (mkv->reserve_cues_space) { if (size < mkv->reserve_cues_space) put_ebml_void(pb, mkv->reserve_cues_space - size); @@ -2564,11 +2569,11 @@ static int mkv_write_trailer(AVFormatContext *s) av_log(s, AV_LOG_DEBUG, "end duration = %" PRIu64 "\n", mkv->duration); avio_seek(mkv->info_bc, mkv->duration_offset, SEEK_SET); put_ebml_float(mkv->info_bc, MATROSKA_ID_DURATION, mkv->duration); - end_ebml_master_crc32(pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO, 0); + end_ebml_master_crc32(pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO, 0, 0); // write tracks master avio_seek(pb, mkv->tracks_pos, SEEK_SET); - end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS, 0); + end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS, 0, 0); // update stream durations if (!mkv->is_live) { @@ -2598,7 +2603,7 @@ static int mkv_write_trailer(AVFormatContext *s) } if (mkv->tags_bc && !mkv->is_live) { avio_seek(pb, mkv->tags_pos, SEEK_SET); - end_ebml_master_crc32(pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS, 0); + end_ebml_master_crc32(pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS, 0, 0); } avio_seek(pb, endpos, SEEK_SET); -- 2.20.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".