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.

138 lines
4.1KB

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