diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index a65a5373b0..d1edc6756e 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); @@ -465,7 +466,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); @@ -1382,7 +1383,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; } @@ -1438,7 +1439,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; @@ -1637,7 +1638,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; } @@ -1733,7 +1734,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; } @@ -1874,7 +1875,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); @@ -2162,7 +2163,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_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT); } @@ -2469,7 +2470,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); @@ -2483,6 +2484,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) @@ -2497,7 +2499,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: " @@ -2512,10 +2515,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); @@ -2534,11 +2546,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) { @@ -2568,7 +2580,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);