ffmetadec.c 4.6 KB

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