X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmatroskaenc.c;h=c3d895f931886c765457755aba01da7e66aad230;hb=e83717e63eab1f1b78dc0990e5b8e927097fca29;hp=e5efba54084272702a3cd1689f55739261254873;hpb=f9ceb18f3b26d792522536d32838c6795b8df20d;p=ffmpeg diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index e5efba54084..c3d895f9318 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -137,7 +137,7 @@ typedef struct MatroskaMuxContext { mkv_cues cues; int64_t cues_pos; - AVPacket cur_audio_pkt; + AVPacket *cur_audio_pkt; unsigned nb_attachments; int have_video; @@ -195,6 +195,8 @@ static void put_ebml_size_unknown(AVIOContext *pb, int bytes) { av_assert0(bytes <= 8); avio_w8(pb, 0x1ff >> bytes); + if (av_builtin_constant_p(bytes) && bytes == 1) + return; ffio_fill(pb, 0xff, bytes - 1); } @@ -451,7 +453,7 @@ static void mkv_deinit(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; - av_packet_unref(&mkv->cur_audio_pkt); + av_packet_free(&mkv->cur_audio_pkt); ffio_free_dyn_buf(&mkv->cluster_bc); ffio_free_dyn_buf(&mkv->info.bc); @@ -585,7 +587,7 @@ static int mkv_assemble_cues(AVStream **streams, AVIOContext *dyn_cp, 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); @@ -1197,6 +1199,11 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGHEARINGIMPAIRED, 1); if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED) put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGVISUALIMPAIRED, 1); + if (st->disposition & (AV_DISPOSITION_ORIGINAL | AV_DISPOSITION_DUB) && + (st->disposition & (AV_DISPOSITION_ORIGINAL | AV_DISPOSITION_DUB)) + != (AV_DISPOSITION_ORIGINAL | AV_DISPOSITION_DUB)) + put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGORIGINAL, + !!(st->disposition & AV_DISPOSITION_ORIGINAL)); // look for a codec ID string specific to mkv to use, // if none are found, use AVI codes @@ -1359,6 +1366,8 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, av_log(s, AV_LOG_ERROR, "Subtitle codec %d is not supported.\n", par->codec_id); return AVERROR(ENOSYS); } + if (mkv->mode != MODE_WEBM && st->disposition & AV_DISPOSITION_DESCRIPTIONS) + put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGTEXTDESCRIPTIONS, 1); if (mkv->mode != MODE_WEBM || par->codec_id != AV_CODEC_ID_WEBVTT) native_id = MATROSKA_TRACK_TYPE_SUBTITLE; @@ -1618,24 +1627,29 @@ static int mkv_write_tags(AVFormatContext *s) 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; @@ -1649,12 +1663,15 @@ static int mkv_write_chapters(AVFormatContext *s) } 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; + uint64_t uid = create_new_ids ? i + 1ULL : c->id; if (chapterstart < 0 || chapterstart > chapterend || chapterend < 0) { av_log(s, AV_LOG_ERROR, "Invalid chapter start (%"PRId64") or end (%"PRId64").\n", @@ -1664,8 +1681,7 @@ static int mkv_write_chapters(AVFormatContext *s) } 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))) { @@ -1678,8 +1694,7 @@ static int mkv_write_chapters(AVFormatContext *s) 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; } @@ -1751,6 +1766,7 @@ static int mkv_write_attachments(AVFormatContext *s) 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); @@ -1926,8 +1942,6 @@ static int mkv_write_header(AVFormatContext *s) mkv->reserve_cues_space = -1; } - av_init_packet(&mkv->cur_audio_pkt); - mkv->cur_audio_pkt.size = 0; mkv->cluster_pos = -1; // start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or @@ -2016,7 +2030,8 @@ static int mkv_write_block(AVFormatContext *s, AVIOContext *pb, AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; mkv_track *track = &mkv->tracks[pkt->stream_index]; uint8_t *data = NULL, *side_data = NULL; - int err = 0, offset = 0, size = pkt->size, side_data_size; + buffer_size_t side_data_size; + int err = 0, offset = 0, size = pkt->size; int64_t ts = track->write_dts ? pkt->dts : pkt->pts; uint64_t additional_id; int64_t discard_padding = 0; @@ -2126,7 +2141,8 @@ static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, const AVPac MatroskaMuxContext *mkv = s->priv_data; mkv_track *track = &mkv->tracks[pkt->stream_index]; ebml_master blockgroup; - int id_size, settings_size, size; + buffer_size_t id_size, settings_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; @@ -2139,6 +2155,10 @@ static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, const AVPac &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 @@ -2158,12 +2178,15 @@ static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, const AVPac 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) @@ -2191,7 +2214,8 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) mkv_track *track = &mkv->tracks[pkt->stream_index]; AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; uint8_t *side_data; - int side_data_size, ret; + buffer_size_t side_data_size; + int ret; side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_data_size); @@ -2282,7 +2306,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt) 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; @@ -2319,34 +2343,31 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt) 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, track->track_num_size)); -#if FF_API_CONVERGENCE_DURATION -FF_DISABLE_DEPRECATION_WARNINGS - /* For backward compatibility, prefer convergence_duration. */ - if (pkt->convergence_duration > 0) { - duration = pkt->convergence_duration; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* All subtitle blocks are considered to be keyframes. */ mkv_write_block(s, pb, MATROSKA_ID_BLOCK, pkt, 1); put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, duration); @@ -2421,9 +2442,9 @@ static int mkv_write_packet(AVFormatContext *s, const AVPacket *pkt) keyframe && (mkv->have_video ? codec_type == AVMEDIA_TYPE_VIDEO : 1) ? AVIO_DATA_MARKER_SYNC_POINT : AVIO_DATA_MARKER_BOUNDARY_POINT); // check if we have an audio packet cached - if (mkv->cur_audio_pkt.size > 0) { - ret = mkv_write_packet_internal(s, &mkv->cur_audio_pkt); - av_packet_unref(&mkv->cur_audio_pkt); + if (mkv->cur_audio_pkt->size > 0) { + ret = mkv_write_packet_internal(s, mkv->cur_audio_pkt); + av_packet_unref(mkv->cur_audio_pkt); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Could not write cached audio packet ret:%d\n", ret); @@ -2435,7 +2456,7 @@ static int mkv_write_packet(AVFormatContext *s, const AVPacket *pkt) // keyframe's timecode is contained in the same cluster for WebM if (codec_type == AVMEDIA_TYPE_AUDIO) { if (pkt->size > 0) - ret = av_packet_ref(&mkv->cur_audio_pkt, pkt); + ret = av_packet_ref(mkv->cur_audio_pkt, pkt); } else ret = mkv_write_packet_internal(s, pkt); return ret; @@ -2467,8 +2488,8 @@ static int mkv_write_trailer(AVFormatContext *s) int ret, ret2 = 0; // check if we have an audio packet cached - if (mkv->cur_audio_pkt.size > 0) { - ret = mkv_write_packet_internal(s, &mkv->cur_audio_pkt); + if (mkv->cur_audio_pkt->size > 0) { + ret = mkv_write_packet_internal(s, mkv->cur_audio_pkt); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Could not write cached audio packet ret:%d\n", ret); @@ -2692,6 +2713,9 @@ static int mkv_init(struct AVFormatContext *s) } else mkv->mode = MODE_MATROSKAv2; + mkv->cur_audio_pkt = av_packet_alloc(); + if (!mkv->cur_audio_pkt) + return AVERROR(ENOMEM); mkv->tracks = av_mallocz_array(s->nb_streams, sizeof(*mkv->tracks)); if (!mkv->tracks) return AVERROR(ENOMEM);