From patchwork Wed Jan 1 00:58:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Rheinhardt X-Patchwork-Id: 17095 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a05:6214:1865:0:0:0:0 with SMTP id eh5csp220312qvb; Tue, 31 Dec 2019 17:01:57 -0800 (PST) X-Google-Smtp-Source: APXvYqzPu2LYtrvHhRWmIklCik3wHOoAhLHQpbkspy3DTUWQxkrjTU4z/Cg9au6bwC6NeTNrn75J X-Received: by 2002:a17:906:bd2:: with SMTP id y18mr62204722ejg.161.1577840517236; Tue, 31 Dec 2019 17:01:57 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1577840517; cv=none; d=google.com; s=arc-20160816; b=FpoTlPDhQQEnoPj0LaBIlcTfp3mnSyaO11LRhfi3X1D1AW33y/7gNNYKZCZ+QzE68p rAp71WTCcqYF3Jymdzt/UNfTuSz29LFYbUaNbtvCdt15s6TOa0fIageWq4NwU4CjhEVQ WbyNFknAMPqsRf5vyNemZk0wVeJ2m7UcWfU2YMHEC4Z+I6dMQbblZFn+DR1JlBa4GRJY VAsX65VdmsWM4KTWkxVCL4hs4kHU6Gs66rZktmyrX/XSI+EwnN1zxURz+r3ZcKZfMJuH jVxpF9KJlNL5zZ5/1OAbDDSSYsUKsj9DK56sbeC2hFUIeLpfG28bMnp5B7/GY9vdO1F2 3bLA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=s2ZYXyvOv/39Bm/HzfSHQ6s95Ox1kFvoXjVcid19YoU=; b=WW7tdqb0xihfKhZoORrL/HbNjsaJgJ+hYYNteN6Rgrv3MxU/okYQdFyGnC2qmmIkoa FfKPiyEINWe+FdKe9x8vtlPKOO8Z0y+WjPxlngSQymJjoBwA1u2MhSQygOtqXXSyCcUu DSmFF9WnTlZTGrRrNSRTRfNIiXSFN1MJ9+SC38MDJX8vMjGHKmRpJ0cfzIdVHVKOH0jG jmpeE9UsPxMTHSSg9vD9h4T7GfZKrMnQkLXstHOywqJk62/XUBpO9PbIlgXPBR8aEa5Z j3zQNk8e2FihGwtDQfMoNKCFvGhiZArpM35YsfHFhK5V92e/H5WI0c75u1LtxBOShcnR cDOQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=qlxtYbzs; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id bc28si9281366edb.68.2019.12.31.17.01.56; Tue, 31 Dec 2019 17:01:57 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=qlxtYbzs; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id E742D68AE5E; Wed, 1 Jan 2020 02:59:27 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f66.google.com (mail-wr1-f66.google.com [209.85.221.66]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2CAAF68ADBD for ; Wed, 1 Jan 2020 02:59:17 +0200 (EET) Received: by mail-wr1-f66.google.com with SMTP id z3so36239292wru.3 for ; Tue, 31 Dec 2019 16:59:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HTTPAU2u9fG7sTtn4uh5ppdp7o8pvQg3oy4F19Ne7yU=; b=qlxtYbzsjus1OOVj+svL3BCH6oSdTcicecpjNkOtvJk9SK6qHig9vuU+so1AxbM7Ua KswFf/oV0jE5iSKOjPCqDjPteq22r9wdKsqvqb14ieFEfd/aQOdsa/lvSzVHnKQXhAZO 3tf8x6Ihh2Vl9xKx5mSH7ijhG+7751jiAtKjpRFukQzMriai31d3Qx+L12QkKsFr2zh9 5bg51iufhdubX45iMh0IVMfk1K3HEqhqetsyNcVM4iTXzwNQicVov5L84jOIE4RtKYvO qkMIBKhV0k4ZHmS9EPzzb0XOt6v9JFQGbJmIiw+iC4Lhrv88fXRdYa9dCuv7c+8k72Z+ tFmA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=HTTPAU2u9fG7sTtn4uh5ppdp7o8pvQg3oy4F19Ne7yU=; b=HYXwB9Nl8Vr91WfmDStlR9rxiwGkEkstLIY2UwA55iCVqJCvrHrVbcYEjtskQbe3lf fCF/Y/NEEfKAAOc7kRR8jffqbRdqCyoRWgNpaiEMhSLA561G5+4kJ4gGBnvT4soX75aY 1w1KmPmlDpeK/c/lyYMsmT5vOkE6bF8s/Xt5BwMyOa0G3MhlVBC5L53zv2EtTwBaOALm hT5BBAA2bhzcW+T0ug3IFZ72DrBJIe7InvSL42idcFe7HJ4/C1aEWKv38W0YrADvCW4n zj8dJXwlRARRjIj3ArP8nfLMtB4NkOSWbkUtuCsQjxTW6GPXbD/wbzjSnuURRkstcnoS lk8Q== X-Gm-Message-State: APjAAAVTNjCOOYjtxyWwwfO8+jcYpDFh+vgGPM5RiOEMaFfAWg8K2dPs 7bKoEx3ni7uvLANLJPl8yUJjsClt X-Received: by 2002:adf:a109:: with SMTP id o9mr79620373wro.189.1577840356302; Tue, 31 Dec 2019 16:59:16 -0800 (PST) Received: from sblaptop.fritz.box (ipbcc08bbf.dynamic.kabel-deutschland.de. [188.192.139.191]) by smtp.gmail.com with ESMTPSA id w17sm52431655wrt.89.2019.12.31.16.59.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Dec 2019 16:59:15 -0800 (PST) From: Andreas Rheinhardt To: ffmpeg-devel@ffmpeg.org Date: Wed, 1 Jan 2020 01:58:36 +0100 Message-Id: <20200101005837.11356-20-andreas.rheinhardt@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200101005837.11356-1-andreas.rheinhardt@gmail.com> References: <20200101005837.11356-1-andreas.rheinhardt@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 19/20] avformat/matroskaenc: Fix edge case of writing Cues at the beginning X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Andreas Rheinhardt Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: y2NfNb8BtbeK Content-Length: 11696 The Matroska muxer has the ability to write the Cues (the index) at the beginning of the file (in front of the Cluster): The user inputs the amount of space that should be reserved at the beginning of the file and if this is sufficient, the Cues will be written there and the part of the reserved space not used up by the Cues will be filled with a "Void" element. There is just one problem with this: One can not fill a single byte this way, because said Void element is minimally two bytes long (one byte ID, one byte length field). Up until now, if one reserved one byte more than needed, one would run into an assert when writing the Void element. There are two solutions for this: Error out if it happens. Or adjust the length field of the Cues in order to ensure that the above situation can't happen (i.e. write the length on one byte more than necessary). The first solution is very unsatisfactory, as enough space has been reserved. Therefore this commit implements the second solution. Signed-off-by: Andreas Rheinhardt --- libavformat/matroskaenc.c | 42 +++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 4e739d245b..24317d3819 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -339,14 +339,15 @@ 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) + MatroskaMuxContext *mkv, uint32_t id, + int length_size) { uint8_t *buf, crc[4]; int size, skip = 0; put_ebml_id(pb, id); size = avio_close_dyn_buf(*dyn_cp, &buf); - put_ebml_num(pb, size, 0); + put_ebml_num(pb, size, length_size); if (mkv->write_crc) { skip = 6; /* Skip reserved 6-byte long void element from the dynamic buffer. */ AV_WL32(crc, av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), UINT32_MAX, buf + skip, size - skip) ^ UINT32_MAX); @@ -467,7 +468,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); + end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_SEEKHEAD, 0); remaining = seekhead->filepos + seekhead->reserved_size - avio_tell(pb); put_ebml_void(pb, remaining); @@ -1383,7 +1384,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); + end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS, 0); return 0; } @@ -1439,7 +1440,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); + end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CHAPTERS, 0); mkv->wrote_chapters = 1; return 0; @@ -1638,7 +1639,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); + end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS, 0); } return 0; } @@ -1734,7 +1735,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); + end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_ATTACHMENTS, 0); return 0; } @@ -1875,7 +1876,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); + end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO, 0); pb = s->pb; ret = mkv_write_tracks(s); @@ -2157,7 +2158,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); + end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv, MATROSKA_ID_CLUSTER, 0); mkv->cluster_pos = -1; avio_flush(s->pb); } @@ -2462,7 +2463,7 @@ static int mkv_write_trailer(AVFormatContext *s) } if (mkv->cluster_bc) { - end_ebml_master_crc32(pb, &mkv->cluster_bc, mkv, MATROSKA_ID_CLUSTER); + end_ebml_master_crc32(pb, &mkv->cluster_bc, mkv, MATROSKA_ID_CLUSTER, 0); } ret = mkv_write_chapters(s); @@ -2476,6 +2477,7 @@ static int mkv_write_trailer(AVFormatContext *s) if (mkv->cues.num_entries) { AVIOContext *cues; uint64_t size; + int length_size = 0; ret = start_ebml_master_crc32(&cues, mkv); if (ret < 0) @@ -2488,7 +2490,8 @@ static int mkv_write_trailer(AVFormatContext *s) if (mkv->reserve_cues_space) { size = avio_tell(cues); - size += 4 + ebml_num_size(size); + length_size = ebml_num_size(size); + size += 4 + length_size; if (mkv->reserve_cues_space < size) { av_log(s, AV_LOG_WARNING, "Insufficient space reserved for Cues: %d < " @@ -2501,10 +2504,19 @@ static int mkv_write_trailer(AVFormatContext *s) ffio_free_dyn_buf(&cues); return ret64; } + if (mkv->reserve_cues_space == size + 1) { + /* There is no way to reserve a single byte because + * the minimal size of an EBML Void element is 2 + * (1 byte ID, 1 byte length field). This problem + * is solved by writing the Cues' length field on + * one byte more than necessary. */ + length_size++; + size++; + } } } mkv_add_seekhead_entry(mkv, MATROSKA_ID_CUES, avio_tell(pb)); - end_ebml_master_crc32(pb, &cues, mkv, MATROSKA_ID_CUES); + end_ebml_master_crc32(pb, &cues, mkv, MATROSKA_ID_CUES, length_size); if (mkv->reserve_cues_space) { if (size < mkv->reserve_cues_space) put_ebml_void(pb, mkv->reserve_cues_space - size); @@ -2522,11 +2534,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); + end_ebml_master_crc32(pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO, 0); // write tracks master avio_seek(pb, mkv->tracks_pos, SEEK_SET); - end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS); + end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS, 0); // update stream durations if (!mkv->is_live) { @@ -2556,7 +2568,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); + end_ebml_master_crc32(pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS, 0); } avio_seek(pb, currentpos, SEEK_SET);