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
5.0KB

  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 "avformat.h"
  22. #include "metadata.h"
  23. #include "vorbiscomment.h"
  24. #include "libavcodec/bytestream.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(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(uint8_t **p, AVDictionary **m,
  62. const char *vendor_string,
  63. AVChapter **chapters, unsigned int nb_chapters)
  64. {
  65. int cm_count = 0;
  66. bytestream_put_le32(p, strlen(vendor_string));
  67. bytestream_put_buffer(p, 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. bytestream_put_le32(p, 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. bytestream_put_le32(p, len1+1+len2);
  83. bytestream_put_buffer(p, tag->key, len1);
  84. bytestream_put_byte(p, '=');
  85. bytestream_put_buffer(p, 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. bytestream_put_le32(p, 10+1+12);
  100. bytestream_put_buffer(p, "CHAPTER", 7);
  101. bytestream_put_buffer(p, chapter_number, 3);
  102. bytestream_put_byte(p, '=');
  103. bytestream_put_buffer(p, 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. bytestream_put_le32(p, 10+len1+1+len2);
  111. bytestream_put_buffer(p, "CHAPTER", 7);
  112. bytestream_put_buffer(p, chapter_number, 3);
  113. if (!strcmp(tag->key, "title"))
  114. bytestream_put_buffer(p, "NAME", 4);
  115. else
  116. bytestream_put_buffer(p, tag->key, len1);
  117. bytestream_put_byte(p, '=');
  118. bytestream_put_buffer(p, tag->value, len2);
  119. }
  120. }
  121. } else
  122. bytestream_put_le32(p, 0);
  123. return 0;
  124. }