ffmetadec.c 4.5 KB

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