put_ebml_uint(cuepoint, MATROSKA_ID_CUETRACK , tracks[idx].track_num);
put_ebml_uint(cuepoint, MATROSKA_ID_CUECLUSTERPOSITION , entry->cluster_pos);
put_ebml_uint(cuepoint, MATROSKA_ID_CUERELATIVEPOSITION, entry->relative_pos);
- if (entry->duration != -1)
+ if (entry->duration > 0)
put_ebml_uint(cuepoint, MATROSKA_ID_CUEDURATION , entry->duration);
end_ebml_master(cuepoint, track_positions);
} while (++entry < end && entry->pts == pts);
return 0;
}
+static int mkv_new_chapter_ids_needed(const AVFormatContext *s)
+{
+ for (unsigned i = 0; i < s->nb_chapters; i++) {
+ if (!s->chapters[i]->id)
+ return 1;
+ for (unsigned j = 0; j < i; j++)
+ if (s->chapters[j]->id == s->chapters[i]->id)
+ return 1;
+ }
+ return 0;
+}
+
static int mkv_write_chapters(AVFormatContext *s)
{
MatroskaMuxContext *mkv = s->priv_data;
AVIOContext *dyn_cp = NULL, *dyn_tags = NULL, **tags, *pb = s->pb;
ebml_master editionentry;
- uint64_t chapter_id_offset = 0;
AVRational scale = {1, 1E9};
- int i, ret;
+ int ret, create_new_ids;
if (!s->nb_chapters || mkv->wrote_chapters)
return 0;
- for (i = 0; i < s->nb_chapters; i++)
- if (!s->chapters[i]->id) {
- chapter_id_offset = 1;
- break;
- }
-
ret = start_ebml_master_crc32(&dyn_cp, mkv);
if (ret < 0)
return ret;
} else
tags = NULL;
- for (i = 0; i < s->nb_chapters; i++) {
+ create_new_ids = mkv_new_chapter_ids_needed(s);
+
+ for (unsigned i = 0; i < s->nb_chapters; i++) {
ebml_master chapteratom, chapterdisplay;
const AVChapter *c = s->chapters[i];
int64_t chapterstart = av_rescale_q(c->start, c->time_base, scale);
int64_t chapterend = av_rescale_q(c->end, c->time_base, scale);
const AVDictionaryEntry *t;
+#if FF_API_CHAPTER_ID_INT
+ uint64_t uid = create_new_ids ? i + 1ULL : (uint32_t)c->id;
+#else
+ uint64_t uid = create_new_ids ? i + 1ULL : c->id;
+#endif
if (chapterstart < 0 || chapterstart > chapterend || chapterend < 0) {
av_log(s, AV_LOG_ERROR,
"Invalid chapter start (%"PRId64") or end (%"PRId64").\n",
}
chapteratom = start_ebml_master(dyn_cp, MATROSKA_ID_CHAPTERATOM, 0);
- put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERUID,
- (uint32_t)c->id + chapter_id_offset);
+ put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERUID, uid);
put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERTIMESTART, chapterstart);
put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERTIMEEND, chapterend);
if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
if (tags && mkv_check_tag(c->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID)) {
ret = mkv_write_tag(mkv, c->metadata, tags, NULL,
- MATROSKA_ID_TAGTARGETS_CHAPTERUID,
- (uint32_t)c->id + chapter_id_offset);
+ MATROSKA_ID_TAGTARGETS_CHAPTERUID, uid);
if (ret < 0)
goto fail;
}
put_ebml_string(dyn_cp, MATROSKA_ID_FILEDESC, t->value);
if (!(t = av_dict_get(st->metadata, "filename", NULL, 0))) {
av_log(s, AV_LOG_ERROR, "Attachment stream %d has no filename tag.\n", i);
+ ffio_free_dyn_buf(&dyn_cp);
return AVERROR(EINVAL);
}
put_ebml_string(dyn_cp, MATROSKA_ID_FILENAME, t->value);
mkv_track *track = &mkv->tracks[pkt->stream_index];
ebml_master blockgroup;
buffer_size_t id_size, settings_size;
- int size;
+ int size, id_size_int, settings_size_int;
const char *id, *settings;
int64_t ts = track->write_dts ? pkt->dts : pkt->pts;
const int flags = 0;
&settings_size);
settings = settings ? settings : "";
+ if (id_size > INT_MAX - 2 || settings_size > INT_MAX - id_size - 2 ||
+ pkt->size > INT_MAX - settings_size - id_size - 2)
+ return AVERROR(EINVAL);
+
size = id_size + 1 + settings_size + 1 + pkt->size;
/* The following string is identical to the one in mkv_write_block so that
put_ebml_num(pb, track->track_num, track->track_num_size);
avio_wb16(pb, ts - mkv->cluster_pts);
avio_w8(pb, flags);
- avio_printf(pb, "%.*s\n%.*s\n%.*s", id_size, id, settings_size, settings, pkt->size, pkt->data);
+
+ id_size_int = id_size;
+ settings_size_int = settings_size;
+ avio_printf(pb, "%.*s\n%.*s\n%.*s", id_size_int, id, settings_size_int, settings, pkt->size, pkt->data);
put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, pkt->duration);
end_ebml_master(pb, blockgroup);
- return pkt->duration;
+ return 0;
}
static int mkv_end_cluster(AVFormatContext *s)
AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar;
mkv_track *track = &mkv->tracks[pkt->stream_index];
int keyframe = !!(pkt->flags & AV_PKT_FLAG_KEY);
- int duration = pkt->duration;
+ int64_t duration = pkt->duration;
int ret;
int64_t ts = track->write_dts ? pkt->dts : pkt->pts;
int64_t relative_packet_pos;
relative_packet_pos = avio_tell(pb);
- if (par->codec_type != AVMEDIA_TYPE_SUBTITLE) {
+ if (par->codec_type != AVMEDIA_TYPE_SUBTITLE ||
+ (par->codec_id != AV_CODEC_ID_WEBVTT && duration <= 0)) {
ret = mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe);
if (ret < 0)
return ret;
if (keyframe && IS_SEEKABLE(s->pb, mkv) &&
- (par->codec_type == AVMEDIA_TYPE_VIDEO || !mkv->have_video && !track->has_cue)) {
+ (par->codec_type == AVMEDIA_TYPE_VIDEO ||
+ par->codec_type == AVMEDIA_TYPE_SUBTITLE ||
+ !mkv->have_video && !track->has_cue)) {
ret = mkv_add_cuepoint(mkv, pkt->stream_index, ts,
- mkv->cluster_pos, relative_packet_pos, -1);
+ mkv->cluster_pos, relative_packet_pos, 0);
if (ret < 0)
return ret;
track->has_cue = 1;
}
} else {
if (par->codec_id == AV_CODEC_ID_WEBVTT) {
- duration = mkv_write_vtt_blocks(s, pb, pkt);
+ ret = mkv_write_vtt_blocks(s, pb, pkt);
+ if (ret < 0)
+ return ret;
} else {
ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP,
mkv_blockgroup_size(pkt->size,