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.

143 lines
4.2KB

  1. /*
  2. * On2 VP8 parser for Ogg
  3. * Copyright (C) 2013 James Almer
  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 "libavutil/intreadwrite.h"
  22. #include "avformat.h"
  23. #include "internal.h"
  24. #include "oggdec.h"
  25. #define VP8_HEADER_SIZE 26
  26. static int vp8_header(AVFormatContext *s, int idx)
  27. {
  28. struct ogg *ogg = s->priv_data;
  29. struct ogg_stream *os = ogg->streams + idx;
  30. uint8_t *p = os->buf + os->pstart;
  31. AVStream *st = s->streams[idx];
  32. AVRational framerate;
  33. if (os->psize < 7 || p[0] != 0x4f)
  34. return 0;
  35. switch (p[5]){
  36. case 0x01:
  37. if (os->psize < VP8_HEADER_SIZE) {
  38. av_log(s, AV_LOG_ERROR, "Invalid OggVP8 header packet");
  39. return AVERROR_INVALIDDATA;
  40. }
  41. if (p[6] != 1) {
  42. av_log(s, AV_LOG_WARNING,
  43. "Unknown OggVP8 version %d.%d\n", p[6], p[7]);
  44. return AVERROR_INVALIDDATA;
  45. }
  46. st->codecpar->width = AV_RB16(p + 8);
  47. st->codecpar->height = AV_RB16(p + 10);
  48. st->sample_aspect_ratio.num = AV_RB24(p + 12);
  49. st->sample_aspect_ratio.den = AV_RB24(p + 15);
  50. framerate.num = AV_RB32(p + 18);
  51. framerate.den = AV_RB32(p + 22);
  52. avpriv_set_pts_info(st, 64, framerate.den, framerate.num);
  53. st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
  54. st->codecpar->codec_id = AV_CODEC_ID_VP8;
  55. st->need_parsing = AVSTREAM_PARSE_HEADERS;
  56. break;
  57. case 0x02:
  58. if (p[6] != 0x20)
  59. return AVERROR_INVALIDDATA;
  60. ff_vorbis_stream_comment(s, st, p + 7, os->psize - 7);
  61. break;
  62. default:
  63. av_log(s, AV_LOG_ERROR, "Unknown VP8 header type 0x%02X\n", p[5]);
  64. return AVERROR_INVALIDDATA;
  65. }
  66. return 1;
  67. }
  68. static uint64_t vp8_gptopts(AVFormatContext *s, int idx,
  69. uint64_t granule, int64_t *dts)
  70. {
  71. struct ogg *ogg = s->priv_data;
  72. struct ogg_stream *os = ogg->streams + idx;
  73. uint64_t pts = (granule >> 32);
  74. uint32_t dist = (granule >> 3) & 0x07ffffff;
  75. if (!dist)
  76. os->pflags |= AV_PKT_FLAG_KEY;
  77. if (dts)
  78. *dts = pts;
  79. return pts;
  80. }
  81. static int vp8_packet(AVFormatContext *s, int idx)
  82. {
  83. struct ogg *ogg = s->priv_data;
  84. struct ogg_stream *os = ogg->streams + idx;
  85. uint8_t *p = os->buf + os->pstart;
  86. if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) &&
  87. !(os->flags & OGG_FLAG_EOS)) {
  88. int seg;
  89. int duration;
  90. uint8_t *last_pkt = p;
  91. uint8_t *next_pkt;
  92. seg = os->segp;
  93. duration = (last_pkt[0] >> 4) & 1;
  94. next_pkt = last_pkt += os->psize;
  95. for (; seg < os->nsegs; seg++) {
  96. if (os->segments[seg] < 255) {
  97. duration += (last_pkt[0] >> 4) & 1;
  98. last_pkt = next_pkt + os->segments[seg];
  99. }
  100. next_pkt += os->segments[seg];
  101. }
  102. os->lastpts =
  103. os->lastdts = vp8_gptopts(s, idx, os->granule, NULL) - duration;
  104. if(s->streams[idx]->start_time == AV_NOPTS_VALUE) {
  105. s->streams[idx]->start_time = os->lastpts;
  106. if (s->streams[idx]->duration)
  107. s->streams[idx]->duration -= s->streams[idx]->start_time;
  108. }
  109. }
  110. if (os->psize > 0)
  111. os->pduration = (p[0] >> 4) & 1;
  112. return 0;
  113. }
  114. const struct ogg_codec ff_vp8_codec = {
  115. .magic = "OVP80",
  116. .magicsize = 5,
  117. .header = vp8_header,
  118. .packet = vp8_packet,
  119. .gptopts = vp8_gptopts,
  120. .nb_header = 1,
  121. };