You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-15 14:13:16 +02:00
avformat/matroskaenc: fix targets for attachment tags
Attachment tags were being written targeting non-existent streams in the output file. Also filter filename and mimetype entries, as they are standard elements in the Attachment master. Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
@@ -96,6 +96,16 @@ typedef struct mkv_track {
|
|||||||
int64_t ts_offset;
|
int64_t ts_offset;
|
||||||
} mkv_track;
|
} mkv_track;
|
||||||
|
|
||||||
|
typedef struct mkv_attachment {
|
||||||
|
int stream_idx;
|
||||||
|
uint32_t fileuid;
|
||||||
|
} mkv_attachment;
|
||||||
|
|
||||||
|
typedef struct mkv_attachments {
|
||||||
|
mkv_attachment *entries;
|
||||||
|
int num_entries;
|
||||||
|
} mkv_attachments;
|
||||||
|
|
||||||
#define MODE_MATROSKAv2 0x01
|
#define MODE_MATROSKAv2 0x01
|
||||||
#define MODE_WEBM 0x02
|
#define MODE_WEBM 0x02
|
||||||
|
|
||||||
@@ -121,6 +131,7 @@ typedef struct MatroskaMuxContext {
|
|||||||
mkv_seekhead *main_seekhead;
|
mkv_seekhead *main_seekhead;
|
||||||
mkv_cues *cues;
|
mkv_cues *cues;
|
||||||
mkv_track *tracks;
|
mkv_track *tracks;
|
||||||
|
mkv_attachments *attachments;
|
||||||
|
|
||||||
AVPacket cur_audio_pkt;
|
AVPacket cur_audio_pkt;
|
||||||
|
|
||||||
@@ -368,6 +379,10 @@ static void mkv_free(MatroskaMuxContext *mkv) {
|
|||||||
av_freep(&mkv->cues->entries);
|
av_freep(&mkv->cues->entries);
|
||||||
av_freep(&mkv->cues);
|
av_freep(&mkv->cues);
|
||||||
}
|
}
|
||||||
|
if (mkv->attachments) {
|
||||||
|
av_freep(&mkv->attachments->entries);
|
||||||
|
av_freep(&mkv->attachments);
|
||||||
|
}
|
||||||
av_freep(&mkv->tracks);
|
av_freep(&mkv->tracks);
|
||||||
av_freep(&mkv->stream_durations);
|
av_freep(&mkv->stream_durations);
|
||||||
av_freep(&mkv->stream_duration_offsets);
|
av_freep(&mkv->stream_duration_offsets);
|
||||||
@@ -1393,7 +1408,10 @@ static int mkv_check_tag_name(const char *name, unsigned int elementid)
|
|||||||
av_strcasecmp(name, "encoding_tool") &&
|
av_strcasecmp(name, "encoding_tool") &&
|
||||||
av_strcasecmp(name, "duration") &&
|
av_strcasecmp(name, "duration") &&
|
||||||
(elementid != MATROSKA_ID_TAGTARGETS_TRACKUID ||
|
(elementid != MATROSKA_ID_TAGTARGETS_TRACKUID ||
|
||||||
av_strcasecmp(name, "language"));
|
av_strcasecmp(name, "language")) &&
|
||||||
|
(elementid != MATROSKA_ID_TAGTARGETS_ATTACHUID ||
|
||||||
|
(av_strcasecmp(name, "filename") &&
|
||||||
|
av_strcasecmp(name, "mimetype")));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int elementid,
|
static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int elementid,
|
||||||
@@ -1446,6 +1464,9 @@ static int mkv_write_tags(AVFormatContext *s)
|
|||||||
for (i = 0; i < s->nb_streams; i++) {
|
for (i = 0; i < s->nb_streams; i++) {
|
||||||
AVStream *st = s->streams[i];
|
AVStream *st = s->streams[i];
|
||||||
|
|
||||||
|
if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID))
|
if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1456,9 +1477,13 @@ static int mkv_write_tags(AVFormatContext *s)
|
|||||||
if (s->pb->seekable && !mkv->is_live) {
|
if (s->pb->seekable && !mkv->is_live) {
|
||||||
for (i = 0; i < s->nb_streams; i++) {
|
for (i = 0; i < s->nb_streams; i++) {
|
||||||
AVIOContext *pb;
|
AVIOContext *pb;
|
||||||
|
AVStream *st = s->streams[i];
|
||||||
ebml_master tag_target;
|
ebml_master tag_target;
|
||||||
ebml_master tag;
|
ebml_master tag;
|
||||||
|
|
||||||
|
if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT)
|
||||||
|
continue;
|
||||||
|
|
||||||
mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &mkv->tags, &tag_target);
|
mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &mkv->tags, &tag_target);
|
||||||
pb = mkv->tags_bc;
|
pb = mkv->tags_bc;
|
||||||
|
|
||||||
@@ -1484,6 +1509,20 @@ static int mkv_write_tags(AVFormatContext *s)
|
|||||||
if (ret < 0) return ret;
|
if (ret < 0) return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mkv->have_attachments) {
|
||||||
|
for (i = 0; i < mkv->attachments->num_entries; i++) {
|
||||||
|
mkv_attachment *attachment = &mkv->attachments->entries[i];
|
||||||
|
AVStream *st = s->streams[attachment->stream_idx];
|
||||||
|
|
||||||
|
if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID, attachment->fileuid, &mkv->tags);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mkv->tags.pos) {
|
if (mkv->tags.pos) {
|
||||||
if (s->pb->seekable && !mkv->is_live)
|
if (s->pb->seekable && !mkv->is_live)
|
||||||
put_ebml_void(s->pb, avio_tell(mkv->tags_bc) + ((mkv->write_crc && mkv->mode != MODE_WEBM) ? 2 /* ebml id + data size */ + 4 /* CRC32 */ : 0));
|
put_ebml_void(s->pb, avio_tell(mkv->tags_bc) + ((mkv->write_crc && mkv->mode != MODE_WEBM) ? 2 /* ebml id + data size */ + 4 /* CRC32 */ : 0));
|
||||||
@@ -1504,6 +1543,10 @@ static int mkv_write_attachments(AVFormatContext *s)
|
|||||||
if (!mkv->have_attachments)
|
if (!mkv->have_attachments)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
mkv->attachments = av_mallocz(sizeof(*mkv->attachments));
|
||||||
|
if (!mkv->attachments)
|
||||||
|
return ret;
|
||||||
|
|
||||||
av_lfg_init(&c, av_get_random_seed());
|
av_lfg_init(&c, av_get_random_seed());
|
||||||
|
|
||||||
ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_ATTACHMENTS, avio_tell(pb));
|
ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_ATTACHMENTS, avio_tell(pb));
|
||||||
@@ -1515,13 +1558,19 @@ static int mkv_write_attachments(AVFormatContext *s)
|
|||||||
for (i = 0; i < s->nb_streams; i++) {
|
for (i = 0; i < s->nb_streams; i++) {
|
||||||
AVStream *st = s->streams[i];
|
AVStream *st = s->streams[i];
|
||||||
ebml_master attached_file;
|
ebml_master attached_file;
|
||||||
|
mkv_attachment *attachment = mkv->attachments->entries;
|
||||||
AVDictionaryEntry *t;
|
AVDictionaryEntry *t;
|
||||||
const char *mimetype = NULL;
|
const char *mimetype = NULL;
|
||||||
uint64_t fileuid;
|
uint32_t fileuid;
|
||||||
|
|
||||||
if (st->codecpar->codec_type != AVMEDIA_TYPE_ATTACHMENT)
|
if (st->codecpar->codec_type != AVMEDIA_TYPE_ATTACHMENT)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
attachment = av_realloc_array(attachment, mkv->attachments->num_entries + 1, sizeof(mkv_attachment));
|
||||||
|
if (!attachment)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
mkv->attachments->entries = attachment;
|
||||||
|
|
||||||
attached_file = start_ebml_master(dyn_cp, MATROSKA_ID_ATTACHEDFILE, 0);
|
attached_file = start_ebml_master(dyn_cp, MATROSKA_ID_ATTACHEDFILE, 0);
|
||||||
|
|
||||||
if (t = av_dict_get(st->metadata, "title", NULL, 0))
|
if (t = av_dict_get(st->metadata, "title", NULL, 0))
|
||||||
@@ -1561,17 +1610,20 @@ static int mkv_write_attachments(AVFormatContext *s)
|
|||||||
av_sha_update(sha, st->codecpar->extradata, st->codecpar->extradata_size);
|
av_sha_update(sha, st->codecpar->extradata, st->codecpar->extradata_size);
|
||||||
av_sha_final(sha, digest);
|
av_sha_final(sha, digest);
|
||||||
av_free(sha);
|
av_free(sha);
|
||||||
fileuid = AV_RL64(digest);
|
fileuid = AV_RL32(digest);
|
||||||
} else {
|
} else {
|
||||||
fileuid = av_lfg_get(&c);
|
fileuid = av_lfg_get(&c);
|
||||||
}
|
}
|
||||||
av_log(s, AV_LOG_VERBOSE, "Using %.16"PRIx64" for attachment %d\n",
|
av_log(s, AV_LOG_VERBOSE, "Using %.8"PRIx32" for attachment %d\n",
|
||||||
fileuid, i);
|
fileuid, mkv->attachments->num_entries);
|
||||||
|
|
||||||
put_ebml_string(dyn_cp, MATROSKA_ID_FILEMIMETYPE, mimetype);
|
put_ebml_string(dyn_cp, MATROSKA_ID_FILEMIMETYPE, mimetype);
|
||||||
put_ebml_binary(dyn_cp, MATROSKA_ID_FILEDATA, st->codecpar->extradata, st->codecpar->extradata_size);
|
put_ebml_binary(dyn_cp, MATROSKA_ID_FILEDATA, st->codecpar->extradata, st->codecpar->extradata_size);
|
||||||
put_ebml_uint(dyn_cp, MATROSKA_ID_FILEUID, fileuid);
|
put_ebml_uint(dyn_cp, MATROSKA_ID_FILEUID, fileuid);
|
||||||
end_ebml_master(dyn_cp, attached_file);
|
end_ebml_master(dyn_cp, attached_file);
|
||||||
|
|
||||||
|
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, attachments);
|
end_ebml_master_crc32(pb, &dyn_cp, mkv, attachments);
|
||||||
|
|
||||||
@@ -1751,11 +1803,11 @@ static int mkv_write_header(AVFormatContext *s)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
ret = mkv_write_tags(s);
|
ret = mkv_write_attachments(s);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
ret = mkv_write_attachments(s);
|
ret = mkv_write_tags(s);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
591d55099c938bd7560585da13874a4c *./tests/data/lavf/lavf.mkv
|
a06683a6eb4af6fe8ffe5603c1942a97 *./tests/data/lavf/lavf.mkv
|
||||||
472929 ./tests/data/lavf/lavf.mkv
|
472755 ./tests/data/lavf/lavf.mkv
|
||||||
./tests/data/lavf/lavf.mkv CRC=0xec6c3c68
|
./tests/data/lavf/lavf.mkv CRC=0xec6c3c68
|
||||||
c1009a6b9b4ef7e0eb0775d227131415 *./tests/data/lavf/lavf.mkv
|
c1009a6b9b4ef7e0eb0775d227131415 *./tests/data/lavf/lavf.mkv
|
||||||
320599 ./tests/data/lavf/lavf.mkv
|
320599 ./tests/data/lavf/lavf.mkv
|
||||||
|
Reference in New Issue
Block a user