History

avformat/matroskaenc: Don't fail if reserved Cues space doesn't suffice

When the user opted to write the Cues at the beginning, the Cues were simply written without checking in advance whether enough space has been reserved for them. If it wasn't enough, the data following the space reserved for the Cues was simply overwritten, corrupting the file. This commit changes this by checking whether enough space has been reserved for the Cues before outputting anything. If it isn't enough, no Cues will be output at all and the file will be finalized normally, yet writing the trailer will nevertheless return an error to notify the user that his wish of having Cues at the front of the file hasn't been fulfilled. This change opens new usecases for this option: It is now safe to use this option to e.g. record live streams or to use it when muxing the output of an expensive encoding, because when the reserved space turns out to be insufficient, one ends up with a file that just lacks Cues but is otherwise fine.

Andreas Rheinhardt committed 6 years ago

Commit 06f10891 parent 8e1354c2 files · +50 −41Browse files

Unified · Split

2 files
  1. doc/muxers.texi +3 −2
  2. libavformat/matroskaenc.c +47 −39
doc/muxers.texi+3−2
@@ -1352,8 +1352,9 @@ index at the beginning of the file. · 1351 unmodified lines
1352 1352
1353If this option is set to a non-zero value, the muxer will reserve a given amount1353If this option is set to a non-zero value, the muxer will reserve a given amount
1354of space in the file header and then try to write the cues there when the muxing1354of space in the file header and then try to write the cues there when the muxing
1355finishes. If the available space does not suffice, muxing will fail. A safe size1355finishes. If the reserved space does not suffice, no Cues will be written, the
1356for most use cases should be about 50kB per hour of video.1356file will be finalized and writing the trailer will return an error.
1357A safe size for most use cases should be about 50kB per hour of video.
1357 1358
1358Note that cues are only written if the output is seekable and this option will1359Note that cues are only written if the output is seekable and this option will
1359have no effect if it is not.1360have no effect if it is not.
libavformat/matroskaenc.c+47−39
@@ -500,23 +500,15 @@ static int mkv_add_cuepoint(MatroskaMuxContext *mkv, int stream, int tracknum, i · 499 unmodified lines
500 return 0;500 return 0;
501}501}
502 502
503static int64_t mkv_write_cues(AVFormatContext *s, mkv_cues *cues, mkv_track *tracks, int num_tracks)503static int mkv_assemble_cues(AVStream **streams, AVIOContext *dyn_cp,
504 mkv_cues *cues, mkv_track *tracks, int num_tracks)
504{505{
505 MatroskaMuxContext *mkv = s->priv_data;506 AVIOContext *cuepoint;
506 AVIOContext *dyn_cp, *pb = s->pb, *cuepoint;
507 int64_t currentpos;
508 int ret;507 int ret;
509 508
510 currentpos = avio_tell(pb);
511 ret = start_ebml_master_crc32(&dyn_cp, mkv);
512 if (ret < 0)
513 return ret;
514
515 ret = avio_open_dyn_buf(&cuepoint);509 ret = avio_open_dyn_buf(&cuepoint);
516 if (ret < 0) {510 if (ret < 0)
517 ffio_free_dyn_buf(&dyn_cp);
518 return ret;511 return ret;
519 }
520 512
521 for (mkv_cuepoint *entry = cues->entries, *end = entry + cues->num_entries;513 for (mkv_cuepoint *entry = cues->entries, *end = entry + cues->num_entries;
522 entry < end;) {514 entry < end;) {
@@ -535,7 +527,7 @@ static int64_t mkv_write_cues(AVFormatContext *s, mkv_cues *cues, mkv_track *tra · 12 unmodified lines
535 int idx = entry->stream_idx;527 int idx = entry->stream_idx;
536 528
537 av_assert0(idx >= 0 && idx < num_tracks);529 av_assert0(idx >= 0 && idx < num_tracks);
538 if (tracks[idx].has_cue && s->streams[idx]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)530 if (tracks[idx].has_cue && streams[idx]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
539 continue;531 continue;
540 tracks[idx].has_cue = 1;532 tracks[idx].has_cue = 1;
541 track_positions = start_ebml_master(cuepoint, MATROSKA_ID_CUETRACKPOSITION, MAX_CUETRACKPOS_SIZE);533 track_positions = start_ebml_master(cuepoint, MATROSKA_ID_CUETRACKPOSITION, MAX_CUETRACKPOS_SIZE);
@@ -551,9 +543,8 @@ static int64_t mkv_write_cues(AVFormatContext *s, mkv_cues *cues, mkv_track *tra · 9 unmodified lines
551 ffio_reset_dyn_buf(cuepoint);543 ffio_reset_dyn_buf(cuepoint);
552 }544 }
553 ffio_free_dyn_buf(&cuepoint);545 ffio_free_dyn_buf(&cuepoint);
554 end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CUES);
555 546
556 return currentpos;547 return 0;
557}548}
558 549
559static int put_xiph_codecpriv(AVFormatContext *s, AVIOContext *pb, AVCodecParameters *par)550static int put_xiph_codecpriv(AVFormatContext *s, AVIOContext *pb, AVCodecParameters *par)
@@ -2464,7 +2455,7 @@ static int mkv_write_trailer(AVFormatContext *s) · 1904 unmodified lines
2464{2455{
2465 MatroskaMuxContext *mkv = s->priv_data;2456 MatroskaMuxContext *mkv = s->priv_data;
2466 AVIOContext *pb = s->pb;2457 AVIOContext *pb = s->pb;
2467 int64_t currentpos, cuespos;2458 int64_t currentpos;
2468 int ret;2459 int ret;
2469 2460
2470 // check if we have an audio packet cached2461 // check if we have an audio packet cached
@@ -2487,35 +2478,52 @@ static int mkv_write_trailer(AVFormatContext *s) · 16 unmodified lines
2487 2478
2488 2479
2489 if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) {2480 if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) {
2481 int64_t ret64;
2482
2490 if (mkv->cues.num_entries) {2483 if (mkv->cues.num_entries) {
2491 if (mkv->reserve_cues_space) {2484 AVIOContext *cues;
2492 int64_t cues_end;2485 uint64_t size;
2493
2494 currentpos = avio_tell(pb);
2495 avio_seek(pb, mkv->cues_pos, SEEK_SET);
2496
2497 cuespos = mkv_write_cues(s, &mkv->cues, mkv->tracks, s->nb_streams);
2498 cues_end = avio_tell(pb);
2499 if (cues_end > cuespos + mkv->reserve_cues_space) {
2500 av_log(s, AV_LOG_ERROR,
2501 "Insufficient space reserved for cues: %d "
2502 "(needed: %" PRId64 ").\n",
2503 mkv->reserve_cues_space, cues_end - cuespos);
2504 return AVERROR(EINVAL);
2505 }
2506 2486
2507 if (cues_end < cuespos + mkv->reserve_cues_space)2487 ret = start_ebml_master_crc32(&cues, mkv);
2508 put_ebml_void(pb, mkv->reserve_cues_space -2488 if (ret < 0)
2509 (cues_end - cuespos));2489 return ret;
2510 2490
2511 avio_seek(pb, currentpos, SEEK_SET);2491 ret = mkv_assemble_cues(s->streams, cues, &mkv->cues,
2512 } else {2492 mkv->tracks, s->nb_streams);
2513 cuespos = mkv_write_cues(s, &mkv->cues, mkv->tracks, s->nb_streams);2493 if (ret < 0) {
2494 ffio_free_dyn_buf(&cues);
2495 return ret;
2514 }2496 }
2515 2497
2516 mkv_add_seekhead_entry(mkv, MATROSKA_ID_CUES, cuespos);2498 if (mkv->reserve_cues_space) {
2499 size = avio_tell(cues);
2500 size += 4 + ebml_num_size(size);
2501 if (mkv->reserve_cues_space < size) {
2502 av_log(s, AV_LOG_WARNING,
2503 "Insufficient space reserved for Cues: "
2504 "%d < %"PRIu64". No Cues will be output.\n",
2505 mkv->reserve_cues_space, size);
2506 mkv->reserve_cues_space = -1;
2507 ffio_free_dyn_buf(&cues);
2508 goto after_cues;
2509 } else {
2510 currentpos = avio_tell(pb);
2511 if ((ret64 = avio_seek(pb, mkv->cues_pos, SEEK_SET)) < 0) {
2512 ffio_free_dyn_buf(&cues);
2513 return ret64;
2514 }
2515 }
2516 }
2517 mkv_add_seekhead_entry(mkv, MATROSKA_ID_CUES, avio_tell(pb));
2518 end_ebml_master_crc32(pb, &cues, mkv, MATROSKA_ID_CUES);
2519 if (mkv->reserve_cues_space) {
2520 if (size < mkv->reserve_cues_space)
2521 put_ebml_void(pb, mkv->reserve_cues_space - size);
2522 avio_seek(pb, currentpos, SEEK_SET);
2523 }
2517 }2524 }
2518 2525
2526 after_cues:
2519 currentpos = avio_tell(pb);2527 currentpos = avio_tell(pb);
2520 2528
2521 ret = mkv_write_seekhead(pb, mkv, 1, mkv->info_pos);2529 ret = mkv_write_seekhead(pb, mkv, 1, mkv->info_pos);
@@ -2570,7 +2578,7 @@ static int mkv_write_trailer(AVFormatContext *s) · 48 unmodified lines
2570 end_ebml_master(pb, mkv->segment);2578 end_ebml_master(pb, mkv->segment);
2571 }2579 }
2572 2580
2573 return 0;2581 return mkv->reserve_cues_space < 0 ? AVERROR(EINVAL) : 0;
2574}2582}
2575 2583
2576static int mkv_query_codec(enum AVCodecID codec_id, int std_compliance)2584static int mkv_query_codec(enum AVCodecID codec_id, int std_compliance)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t