metadec.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * Metadata demuxer
  3. * Copyright (c) 2010 Anton Khirnov
  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 "meta.h"
  23. static int probe(AVProbeData *p)
  24. {
  25. if(!memcmp(p->buf, ID_STRING, strlen(ID_STRING)))
  26. return AVPROBE_SCORE_MAX;
  27. return 0;
  28. }
  29. static void get_line(ByteIOContext *s, uint8_t *buf, int size)
  30. {
  31. do {
  32. uint8_t c;
  33. int i = 0;
  34. while ((c = get_byte(s))) {
  35. if (c == '\\') {
  36. if (i < size - 1)
  37. buf[i++] = c;
  38. c = get_byte(s);
  39. } else if (c == '\n')
  40. break;
  41. if (i < size - 1)
  42. buf[i++] = c;
  43. }
  44. buf[i] = 0;
  45. } while (!url_feof(s) && (buf[0] == ';' || buf[0] == '#' || buf[0] == 0));
  46. }
  47. static AVChapter *read_chapter(AVFormatContext *s)
  48. {
  49. uint8_t line[256];
  50. int64_t start, end;
  51. AVRational tb = {1, 1e9};
  52. get_line(s->pb, line, sizeof(line));
  53. if (sscanf(line, "TIMEBASE=%d/%d", &tb.num, &tb.den))
  54. get_line(s->pb, line, sizeof(line));
  55. if (!sscanf(line, "START=%lld", &start)) {
  56. av_log(s, AV_LOG_ERROR, "Expected chapter start timestamp, found %s.\n", line);
  57. start = (s->nb_chapters && s->chapters[s->nb_chapters - 1]->end != AV_NOPTS_VALUE) ?
  58. s->chapters[s->nb_chapters - 1]->end : 0;
  59. } else
  60. get_line(s->pb, line, sizeof(line));
  61. if (!sscanf(line, "END=%lld", &end)) {
  62. av_log(s, AV_LOG_ERROR, "Expected chapter end timestamp, found %s.\n", line);
  63. end = AV_NOPTS_VALUE;
  64. }
  65. return ff_new_chapter(s, s->nb_chapters, tb, start, end, NULL);
  66. }
  67. static uint8_t *unescape(uint8_t *buf, int size)
  68. {
  69. uint8_t *ret = av_malloc(size + 1);
  70. uint8_t *p1 = ret, *p2 = buf;
  71. if (!ret)
  72. return NULL;
  73. while (p2 < buf + size) {
  74. if (*p2 == '\\')
  75. p2++;
  76. *p1++ = *p2++;
  77. }
  78. *p1 = 0;
  79. return ret;
  80. }
  81. static int read_tag(uint8_t *line, AVMetadata **m)
  82. {
  83. uint8_t *key, *value, *p = line;
  84. /* find first not escaped '=' */
  85. while (1) {
  86. if (*p == '=')
  87. break;
  88. else if (*p == '\\')
  89. p++;
  90. if (*p++)
  91. continue;
  92. return 0;
  93. }
  94. if (!(key = unescape(line, p - line)))
  95. return AVERROR(ENOMEM);
  96. if (!(value = unescape(p + 1, strlen(p + 1)))) {
  97. av_free(key);
  98. return AVERROR(ENOMEM);
  99. }
  100. av_metadata_set2(m, key, value, AV_METADATA_DONT_STRDUP_KEY | AV_METADATA_DONT_STRDUP_VAL);
  101. return 0;
  102. }
  103. static int read_header(AVFormatContext *s, AVFormatParameters *ap)
  104. {
  105. AVMetadata **m = &s->metadata;
  106. uint8_t line[1024];
  107. while(!url_feof(s->pb)) {
  108. get_line(s->pb, line, sizeof(line));
  109. if (!memcmp(line, ID_STREAM, strlen(ID_STREAM))) {
  110. AVStream *st = av_new_stream(s, 0);
  111. if (!st)
  112. return -1;
  113. st->codec->codec_type = AVMEDIA_TYPE_DATA;
  114. st->codec->codec_id = CODEC_ID_FFMETADATA;
  115. m = &st->metadata;
  116. } else if (!memcmp(line, ID_CHAPTER, strlen(ID_CHAPTER))) {
  117. AVChapter *ch = read_chapter(s);
  118. if (!ch)
  119. return -1;
  120. m = &ch->metadata;
  121. } else
  122. read_tag(line, m);
  123. }
  124. s->start_time = 0;
  125. if (s->nb_chapters)
  126. s->duration = av_rescale_q(s->chapters[s->nb_chapters - 1]->end,
  127. s->chapters[s->nb_chapters - 1]->time_base,
  128. AV_TIME_BASE_Q);
  129. return 0;
  130. }
  131. static int read_packet(AVFormatContext *s, AVPacket *pkt)
  132. {
  133. return AVERROR_EOF;
  134. }
  135. AVInputFormat ffmetadata_demuxer = {
  136. .name = "ffmetadata",
  137. .long_name = NULL_IF_CONFIG_SMALL("FFmpeg metadata in text format"),
  138. .read_probe = probe,
  139. .read_header = read_header,
  140. .read_packet = read_packet,
  141. };