ffmetadec.c 4.6 KB

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