History

avformat/matroskaenc: Check chapter ids for duplicates

Up until now, there has been no check that each chapter has a unique id; there was only a check for whether a chapter id is zero (this happens often when the chapters originated from a format that lacks the concept of chapter id and simply counts from zero) which is invalid in Matroska. In this case the chapter ids are offset by 1 to make them nonnegative. Yet offsetting won't fix duplicate ids, therefore this is changed to simply create new chapter uids when the input chapter uids don't conform to the requirements of Matroska (in which case it can be presumed that they did not originate from Matroska, so that we don't need to bother to preserve them).

Andreas Rheinhardt committed 5 years ago

Commit e1e6a5c1 parent 57853951 file · +19 −13Browse files

Unified · Split

libavformat/matroskaenc.c+19−13
@@ -1625,24 +1625,29 @@ static int mkv_write_tags(AVFormatContext *s) · 1624 unmodified lines
1625 return 0;1625 return 0;
1626}1626}
1627 1627
1628static int mkv_new_chapter_ids_needed(const AVFormatContext *s)
1629{
1630 for (unsigned i = 0; i < s->nb_chapters; i++) {
1631 if (!s->chapters[i]->id)
1632 return 1;
1633 for (unsigned j = 0; j < i; j++)
1634 if (s->chapters[j]->id == s->chapters[i]->id)
1635 return 1;
1636 }
1637 return 0;
1638}
1639
1628static int mkv_write_chapters(AVFormatContext *s)1640static int mkv_write_chapters(AVFormatContext *s)
1629{1641{
1630 MatroskaMuxContext *mkv = s->priv_data;1642 MatroskaMuxContext *mkv = s->priv_data;
1631 AVIOContext *dyn_cp = NULL, *dyn_tags = NULL, **tags, *pb = s->pb;1643 AVIOContext *dyn_cp = NULL, *dyn_tags = NULL, **tags, *pb = s->pb;
1632 ebml_master editionentry;1644 ebml_master editionentry;
1633 uint64_t chapter_id_offset = 0;
1634 AVRational scale = {1, 1E9};1645 AVRational scale = {1, 1E9};
1635 int i, ret;1646 int ret, create_new_ids;
1636 1647
1637 if (!s->nb_chapters || mkv->wrote_chapters)1648 if (!s->nb_chapters || mkv->wrote_chapters)
1638 return 0;1649 return 0;
1639 1650
1640 for (i = 0; i < s->nb_chapters; i++)
1641 if (!s->chapters[i]->id) {
1642 chapter_id_offset = 1;
1643 break;
1644 }
1645
1646 ret = start_ebml_master_crc32(&dyn_cp, mkv);1651 ret = start_ebml_master_crc32(&dyn_cp, mkv);
1647 if (ret < 0)1652 if (ret < 0)
1648 return ret;1653 return ret;
@@ -1656,12 +1661,15 @@ static int mkv_write_chapters(AVFormatContext *s) · 7 unmodified lines
1656 } else1661 } else
1657 tags = NULL;1662 tags = NULL;
1658 1663
1659 for (i = 0; i < s->nb_chapters; i++) {1664 create_new_ids = mkv_new_chapter_ids_needed(s);
1665
1666 for (unsigned i = 0; i < s->nb_chapters; i++) {
1660 ebml_master chapteratom, chapterdisplay;1667 ebml_master chapteratom, chapterdisplay;
1661 const AVChapter *c = s->chapters[i];1668 const AVChapter *c = s->chapters[i];
1662 int64_t chapterstart = av_rescale_q(c->start, c->time_base, scale);1669 int64_t chapterstart = av_rescale_q(c->start, c->time_base, scale);
1663 int64_t chapterend = av_rescale_q(c->end, c->time_base, scale);1670 int64_t chapterend = av_rescale_q(c->end, c->time_base, scale);
1664 const AVDictionaryEntry *t;1671 const AVDictionaryEntry *t;
1672 uint64_t uid = create_new_ids ? i + 1ULL : (uint32_t)c->id;
1665 if (chapterstart < 0 || chapterstart > chapterend || chapterend < 0) {1673 if (chapterstart < 0 || chapterstart > chapterend || chapterend < 0) {
1666 av_log(s, AV_LOG_ERROR,1674 av_log(s, AV_LOG_ERROR,
1667 "Invalid chapter start (%"PRId64") or end (%"PRId64").\n",1675 "Invalid chapter start (%"PRId64") or end (%"PRId64").\n",
@@ -1671,8 +1679,7 @@ static int mkv_write_chapters(AVFormatContext *s) · 3 unmodified lines
1671 }1679 }
1672 1680
1673 chapteratom = start_ebml_master(dyn_cp, MATROSKA_ID_CHAPTERATOM, 0);1681 chapteratom = start_ebml_master(dyn_cp, MATROSKA_ID_CHAPTERATOM, 0);
1674 put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERUID,1682 put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERUID, uid);
1675 (uint32_t)c->id + chapter_id_offset);
1676 put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERTIMESTART, chapterstart);1683 put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERTIMESTART, chapterstart);
1677 put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERTIMEEND, chapterend);1684 put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERTIMEEND, chapterend);
1678 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {1685 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
@@ -1685,8 +1692,7 @@ static int mkv_write_chapters(AVFormatContext *s) · 6 unmodified lines
1685 1692
1686 if (tags && mkv_check_tag(c->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID)) {1693 if (tags && mkv_check_tag(c->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID)) {
1687 ret = mkv_write_tag(mkv, c->metadata, tags, NULL,1694 ret = mkv_write_tag(mkv, c->metadata, tags, NULL,
1688 MATROSKA_ID_TAGTARGETS_CHAPTERUID,1695 MATROSKA_ID_TAGTARGETS_CHAPTERUID, uid);
1689 (uint32_t)c->id + chapter_id_offset);
1690 if (ret < 0)1696 if (ret < 0)
1691 goto fail;1697 goto fail;
1692 }1698 }

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