|
|
@@ -375,19 +375,22 @@ static int start_ebml_master_crc32(AVIOContext **dyn_cp, MatroskaMuxContext *mkv |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, |
|
|
|
static int end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, |
|
|
|
MatroskaMuxContext *mkv, uint32_t id, |
|
|
|
int length_size, int keep_buffer, |
|
|
|
int add_seekentry) |
|
|
|
{ |
|
|
|
uint8_t *buf, crc[4]; |
|
|
|
int size, skip = 0; |
|
|
|
int ret, size, skip = 0; |
|
|
|
|
|
|
|
size = avio_get_dyn_buf(*dyn_cp, &buf); |
|
|
|
if ((ret = (*dyn_cp)->error) < 0) |
|
|
|
goto fail; |
|
|
|
|
|
|
|
if (add_seekentry) |
|
|
|
mkv_add_seekhead_entry(mkv, id, avio_tell(pb)); |
|
|
|
|
|
|
|
put_ebml_id(pb, id); |
|
|
|
size = avio_get_dyn_buf(*dyn_cp, &buf); |
|
|
|
put_ebml_length(pb, size, length_size); |
|
|
|
if (mkv->write_crc) { |
|
|
|
skip = 6; /* Skip reserved 6-byte long void element from the dynamic buffer. */ |
|
|
@@ -396,18 +399,20 @@ static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, |
|
|
|
} |
|
|
|
avio_write(pb, buf + skip, size - skip); |
|
|
|
|
|
|
|
fail: |
|
|
|
if (keep_buffer) { |
|
|
|
ffio_reset_dyn_buf(*dyn_cp); |
|
|
|
} else { |
|
|
|
ffio_free_dyn_buf(dyn_cp); |
|
|
|
} |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Output EBML master. Keep the buffer if seekable, allowing for later updates. |
|
|
|
* Furthermore always add a SeekHead Entry for this element. |
|
|
|
*/ |
|
|
|
static void end_ebml_master_crc32_tentatively(AVIOContext *pb, |
|
|
|
static int end_ebml_master_crc32_tentatively(AVIOContext *pb, |
|
|
|
ebml_stored_master *elem, |
|
|
|
MatroskaMuxContext *mkv, uint32_t id) |
|
|
|
{ |
|
|
@@ -415,14 +420,19 @@ static void end_ebml_master_crc32_tentatively(AVIOContext *pb, |
|
|
|
uint8_t *buf; |
|
|
|
int size = avio_get_dyn_buf(elem->bc, &buf); |
|
|
|
|
|
|
|
if (elem->bc->error < 0) |
|
|
|
return elem->bc->error; |
|
|
|
|
|
|
|
elem->pos = avio_tell(pb); |
|
|
|
mkv_add_seekhead_entry(mkv, id, elem->pos); |
|
|
|
|
|
|
|
put_ebml_id(pb, id); |
|
|
|
put_ebml_length(pb, size, 0); |
|
|
|
avio_write(pb, buf, size); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} else |
|
|
|
end_ebml_master_crc32(pb, &elem->bc, mkv, id, 0, 0, 1); |
|
|
|
return end_ebml_master_crc32(pb, &elem->bc, mkv, id, 0, 0, 1); |
|
|
|
} |
|
|
|
|
|
|
|
static void put_xiph_size(AVIOContext *pb, int size) |
|
|
@@ -501,7 +511,10 @@ 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, 0, 0, 0); |
|
|
|
ret = end_ebml_master_crc32(pb, &dyn_cp, mkv, |
|
|
|
MATROSKA_ID_SEEKHEAD, 0, 0, 0); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
|
|
|
|
remaining = seekhead->filepos + seekhead->reserved_size - avio_tell(pb); |
|
|
|
put_ebml_void(pb, remaining); |
|
|
@@ -574,12 +587,14 @@ static int mkv_assemble_cues(AVStream **streams, AVIOContext *dyn_cp, |
|
|
|
end_ebml_master(cuepoint, track_positions); |
|
|
|
} while (++entry < end && entry->pts == pts); |
|
|
|
size = avio_get_dyn_buf(cuepoint, &buf); |
|
|
|
if ((ret = cuepoint->error) < 0) |
|
|
|
break; |
|
|
|
put_ebml_binary(dyn_cp, MATROSKA_ID_POINTENTRY, buf, size); |
|
|
|
ffio_reset_dyn_buf(cuepoint); |
|
|
|
} |
|
|
|
ffio_free_dyn_buf(&cuepoint); |
|
|
|
|
|
|
|
return 0; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static int put_xiph_codecpriv(AVFormatContext *s, AVIOContext *pb, |
|
|
@@ -800,10 +815,12 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, |
|
|
|
ff_put_wav_header(s, dyn_cp, par, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX); |
|
|
|
} |
|
|
|
|
|
|
|
if (ret >= 0) { |
|
|
|
codecpriv_size = avio_get_dyn_buf(dyn_cp, &codecpriv); |
|
|
|
if (codecpriv_size) |
|
|
|
if ((ret = dyn_cp->error) >= 0 && codecpriv_size) |
|
|
|
put_ebml_binary(pb, MATROSKA_ID_CODECPRIVATE, codecpriv, |
|
|
|
codecpriv_size); |
|
|
|
} |
|
|
|
ffio_free_dyn_buf(&dyn_cp); |
|
|
|
return ret; |
|
|
|
} |
|
|
@@ -1423,10 +1440,8 @@ static int mkv_write_tracks(AVFormatContext *s) |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
end_ebml_master_crc32_tentatively(pb, &mkv->track, mkv, |
|
|
|
return end_ebml_master_crc32_tentatively(pb, &mkv->track, mkv, |
|
|
|
MATROSKA_ID_TRACKS); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int mkv_write_chapters(AVFormatContext *s) |
|
|
@@ -1482,10 +1497,10 @@ 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, 0, 0, 1); |
|
|
|
|
|
|
|
mkv->wrote_chapters = 1; |
|
|
|
return 0; |
|
|
|
|
|
|
|
return end_ebml_master_crc32(pb, &dyn_cp, mkv, |
|
|
|
MATROSKA_ID_CHAPTERS, 0, 0, 1); |
|
|
|
} |
|
|
|
|
|
|
|
static int mkv_write_simpletag(AVIOContext *pb, const AVDictionaryEntry *t) |
|
|
@@ -1677,7 +1692,7 @@ static int mkv_write_tags(AVFormatContext *s) |
|
|
|
} |
|
|
|
|
|
|
|
if (mkv->tags.bc) { |
|
|
|
end_ebml_master_crc32_tentatively(s->pb, &mkv->tags, mkv, |
|
|
|
return end_ebml_master_crc32_tentatively(s->pb, &mkv->tags, mkv, |
|
|
|
MATROSKA_ID_TAGS); |
|
|
|
} |
|
|
|
return 0; |
|
|
@@ -1740,9 +1755,8 @@ static int mkv_write_attachments(AVFormatContext *s) |
|
|
|
put_ebml_uid(dyn_cp, MATROSKA_ID_FILEUID, track->uid); |
|
|
|
end_ebml_master(dyn_cp, attached_file); |
|
|
|
} |
|
|
|
end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_ATTACHMENTS, 0, 0, 1); |
|
|
|
|
|
|
|
return 0; |
|
|
|
return end_ebml_master_crc32(pb, &dyn_cp, mkv, |
|
|
|
MATROSKA_ID_ATTACHMENTS, 0, 0, 1); |
|
|
|
} |
|
|
|
|
|
|
|
static int64_t get_metadata_duration(AVFormatContext *s) |
|
|
@@ -1856,7 +1870,10 @@ static int mkv_write_header(AVFormatContext *s) |
|
|
|
put_ebml_void(pb, 11); // assumes double-precision float to be written |
|
|
|
} |
|
|
|
} |
|
|
|
end_ebml_master_crc32_tentatively(s->pb, &mkv->info, mkv, MATROSKA_ID_INFO); |
|
|
|
ret = end_ebml_master_crc32_tentatively(s->pb, &mkv->info, |
|
|
|
mkv, MATROSKA_ID_INFO); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
pb = s->pb; |
|
|
|
|
|
|
|
ret = mkv_write_tracks(s); |
|
|
@@ -2137,18 +2154,23 @@ static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, const AVPac |
|
|
|
return pkt->duration; |
|
|
|
} |
|
|
|
|
|
|
|
static void mkv_end_cluster(AVFormatContext *s) |
|
|
|
static int mkv_end_cluster(AVFormatContext *s) |
|
|
|
{ |
|
|
|
MatroskaMuxContext *mkv = s->priv_data; |
|
|
|
int ret; |
|
|
|
|
|
|
|
end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv, |
|
|
|
MATROSKA_ID_CLUSTER, 0, 1, 0); |
|
|
|
if (!mkv->have_video) { |
|
|
|
for (unsigned i = 0; i < s->nb_streams; i++) |
|
|
|
mkv->tracks[i].has_cue = 0; |
|
|
|
} |
|
|
|
mkv->cluster_pos = -1; |
|
|
|
ret = end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv, |
|
|
|
MATROSKA_ID_CLUSTER, 0, 1, 0); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
|
|
|
|
avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) |
|
|
@@ -2216,15 +2238,16 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
ff_isom_write_av1c(dyn_cp, side_data, side_data_size); |
|
|
|
codecpriv_size = avio_close_dyn_buf(dyn_cp, &codecpriv); |
|
|
|
if (!codecpriv_size) { |
|
|
|
av_free(codecpriv); |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
codecpriv_size = avio_get_dyn_buf(dyn_cp, &codecpriv); |
|
|
|
if ((ret = dyn_cp->error) < 0 || |
|
|
|
!codecpriv_size && (ret = AVERROR_INVALIDDATA)) { |
|
|
|
ffio_free_dyn_buf(&dyn_cp); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
avio_seek(mkv->track.bc, track->codecpriv_offset, SEEK_SET); |
|
|
|
// Do not write the OBUs as we don't have space saved for them |
|
|
|
put_ebml_binary(mkv->track.bc, MATROSKA_ID_CODECPRIVATE, codecpriv, 4); |
|
|
|
av_free(codecpriv); |
|
|
|
ffio_free_dyn_buf(&dyn_cp); |
|
|
|
ret = ff_alloc_extradata(par, side_data_size); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
@@ -2262,7 +2285,9 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt) |
|
|
|
if (mkv->cluster_pos != -1) { |
|
|
|
int64_t cluster_time = ts - mkv->cluster_pts; |
|
|
|
if ((int16_t)cluster_time != cluster_time) { |
|
|
|
mkv_end_cluster(s); |
|
|
|
ret = mkv_end_cluster(s); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
av_log(s, AV_LOG_WARNING, "Starting new cluster due to timestamp\n"); |
|
|
|
} |
|
|
|
} |
|
|
@@ -2372,8 +2397,11 @@ static int mkv_write_packet(AVFormatContext *s, const AVPacket *pkt) |
|
|
|
} else |
|
|
|
start_new_cluster = 0; |
|
|
|
|
|
|
|
if (start_new_cluster) |
|
|
|
mkv_end_cluster(s); |
|
|
|
if (start_new_cluster) { |
|
|
|
ret = mkv_end_cluster(s); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!mkv->cluster_pos) |
|
|
@@ -2408,7 +2436,9 @@ static int mkv_write_flush_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
|
|
|
|
if (!pkt) { |
|
|
|
if (mkv->cluster_pos != -1) { |
|
|
|
mkv_end_cluster(s); |
|
|
|
int ret = mkv_end_cluster(s); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
av_log(s, AV_LOG_DEBUG, |
|
|
|
"Flushing cluster at offset %" PRIu64 " bytes\n", |
|
|
|
avio_tell(s->pb)); |
|
|
@@ -2435,8 +2465,10 @@ static int mkv_write_trailer(AVFormatContext *s) |
|
|
|
} |
|
|
|
|
|
|
|
if (mkv->cluster_pos != -1) { |
|
|
|
end_ebml_master_crc32(pb, &mkv->cluster_bc, mkv, |
|
|
|
ret = end_ebml_master_crc32(pb, &mkv->cluster_bc, mkv, |
|
|
|
MATROSKA_ID_CLUSTER, 0, 0, 0); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
ret = mkv_write_chapters(s); |
|
|
@@ -2493,8 +2525,10 @@ static int mkv_write_trailer(AVFormatContext *s) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
end_ebml_master_crc32(pb, &cues, mkv, MATROSKA_ID_CUES, |
|
|
|
ret = end_ebml_master_crc32(pb, &cues, mkv, MATROSKA_ID_CUES, |
|
|
|
length_size, 0, 1); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
if (mkv->reserve_cues_space) { |
|
|
|
if (size < mkv->reserve_cues_space) |
|
|
|
put_ebml_void(pb, mkv->reserve_cues_space - size); |
|
|
@@ -2511,13 +2545,18 @@ 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, 0, 0, 0); |
|
|
|
ret = end_ebml_master_crc32(pb, &mkv->info.bc, mkv, |
|
|
|
MATROSKA_ID_INFO, 0, 0, 0); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
|
|
|
|
if (mkv->track.bc) { |
|
|
|
// write Tracks master |
|
|
|
avio_seek(pb, mkv->track.pos, SEEK_SET); |
|
|
|
end_ebml_master_crc32(pb, &mkv->track.bc, mkv, |
|
|
|
ret = end_ebml_master_crc32(pb, &mkv->track.bc, mkv, |
|
|
|
MATROSKA_ID_TRACKS, 0, 0, 0); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
// update stream durations |
|
|
@@ -2545,8 +2584,10 @@ static int mkv_write_trailer(AVFormatContext *s) |
|
|
|
} |
|
|
|
|
|
|
|
avio_seek(pb, mkv->tags.pos, SEEK_SET); |
|
|
|
end_ebml_master_crc32(pb, &mkv->tags.bc, mkv, |
|
|
|
ret = end_ebml_master_crc32(pb, &mkv->tags.bc, mkv, |
|
|
|
MATROSKA_ID_TAGS, 0, 0, 0); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
avio_seek(pb, endpos, SEEK_SET); |
|
|
|