You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 lines
4.8KB

  1. /*
  2. * VorbisComment writer
  3. * Copyright (c) 2009 James Darnley
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "avio.h"
  22. #include "avformat.h"
  23. #include "metadata.h"
  24. #include "vorbiscomment.h"
  25. #include "libavutil/dict.h"
  26. /**
  27. * VorbisComment metadata conversion mapping.
  28. * from Ogg Vorbis I format specification: comment field and header specification
  29. * http://xiph.org/vorbis/doc/v-comment.html
  30. */
  31. const AVMetadataConv ff_vorbiscomment_metadata_conv[] = {
  32. { "ALBUMARTIST", "album_artist"},
  33. { "TRACKNUMBER", "track" },
  34. { "DISCNUMBER", "disc" },
  35. { "DESCRIPTION", "comment" },
  36. { 0 }
  37. };
  38. int64_t ff_vorbiscomment_length(const AVDictionary *m, const char *vendor_string,
  39. AVChapter **chapters, unsigned int nb_chapters)
  40. {
  41. int64_t len = 8;
  42. len += strlen(vendor_string);
  43. if (chapters && nb_chapters) {
  44. for (int i = 0; i < nb_chapters; i++) {
  45. AVDictionaryEntry *tag = NULL;
  46. len += 4 + 12 + 1 + 10;
  47. while ((tag = av_dict_get(chapters[i]->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
  48. int64_t len1 = !strcmp(tag->key, "title") ? 4 : strlen(tag->key);
  49. len += 4 + 10 + len1 + 1 + strlen(tag->value);
  50. }
  51. }
  52. }
  53. if (m) {
  54. AVDictionaryEntry *tag = NULL;
  55. while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
  56. len += 4 +strlen(tag->key) + 1 + strlen(tag->value);
  57. }
  58. }
  59. return len;
  60. }
  61. int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m,
  62. const char *vendor_string,
  63. AVChapter **chapters, unsigned int nb_chapters)
  64. {
  65. int cm_count = 0;
  66. avio_wl32(pb, strlen(vendor_string));
  67. avio_write(pb, vendor_string, strlen(vendor_string));
  68. if (chapters && nb_chapters) {
  69. for (int i = 0; i < nb_chapters; i++) {
  70. cm_count += av_dict_count(chapters[i]->metadata) + 1;
  71. }
  72. }
  73. if (m) {
  74. int count = av_dict_count(m) + cm_count;
  75. AVDictionaryEntry *tag = NULL;
  76. avio_wl32(pb, count);
  77. while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
  78. int64_t len1 = strlen(tag->key);
  79. int64_t len2 = strlen(tag->value);
  80. if (len1+1+len2 > UINT32_MAX)
  81. return AVERROR(EINVAL);
  82. avio_wl32(pb, len1 + 1 + len2);
  83. avio_write(pb, tag->key, len1);
  84. avio_w8(pb, '=');
  85. avio_write(pb, tag->value, len2);
  86. }
  87. for (int i = 0; i < nb_chapters; i++) {
  88. AVChapter *chp = chapters[i];
  89. char chapter_time[13];
  90. char chapter_number[4];
  91. int h, m, s, ms;
  92. s = av_rescale(chp->start, chp->time_base.num, chp->time_base.den);
  93. h = s / 3600;
  94. m = (s / 60) % 60;
  95. ms = av_rescale_q(chp->start, chp->time_base, av_make_q( 1, 1000)) % 1000;
  96. s = s % 60;
  97. snprintf(chapter_number, sizeof(chapter_number), "%03d", i);
  98. snprintf(chapter_time, sizeof(chapter_time), "%02d:%02d:%02d.%03d", h, m, s, ms);
  99. avio_wl32(pb, 10 + 1 + 12);
  100. avio_write(pb, "CHAPTER", 7);
  101. avio_write(pb, chapter_number, 3);
  102. avio_w8(pb, '=');
  103. avio_write(pb, chapter_time, 12);
  104. tag = NULL;
  105. while ((tag = av_dict_get(chapters[i]->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
  106. int64_t len1 = !strcmp(tag->key, "title") ? 4 : strlen(tag->key);
  107. int64_t len2 = strlen(tag->value);
  108. if (len1+1+len2+10 > UINT32_MAX)
  109. return AVERROR(EINVAL);
  110. avio_wl32(pb, 10 + len1 + 1 + len2);
  111. avio_write(pb, "CHAPTER", 7);
  112. avio_write(pb, chapter_number, 3);
  113. if (!strcmp(tag->key, "title"))
  114. avio_write(pb, "NAME", 4);
  115. else
  116. avio_write(pb, tag->key, len1);
  117. avio_w8(pb, '=');
  118. avio_write(pb, tag->value, len2);
  119. }
  120. }
  121. } else
  122. avio_wl32(pb, 0);
  123. return 0;
  124. }