/src/ffmpeg/libavformat/oggparsevp8.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
22 | | #include "libavutil/intreadwrite.h" |
23 | | |
24 | | #include "avformat.h" |
25 | | #include "internal.h" |
26 | | #include "oggdec.h" |
27 | | |
28 | 1.34k | #define VP8_HEADER_SIZE 26 |
29 | | |
30 | | static int vp8_header(AVFormatContext *s, int idx) |
31 | 1.58k | { |
32 | 1.58k | struct ogg *ogg = s->priv_data; |
33 | 1.58k | struct ogg_stream *os = ogg->streams + idx; |
34 | 1.58k | uint8_t *p = os->buf + os->pstart; |
35 | 1.58k | AVStream *st = s->streams[idx]; |
36 | 1.58k | AVRational framerate; |
37 | | |
38 | 1.58k | if (os->psize < 7 || p[0] != 0x4f) |
39 | 234 | return 0; |
40 | | |
41 | 1.34k | switch (p[5]){ |
42 | 1.34k | case 0x01: |
43 | 1.34k | if (os->psize < VP8_HEADER_SIZE) { |
44 | 0 | av_log(s, AV_LOG_ERROR, "Invalid OggVP8 header packet"); |
45 | 0 | return AVERROR_INVALIDDATA; |
46 | 0 | } |
47 | | |
48 | 1.34k | if (p[6] != 1) { |
49 | 13 | av_log(s, AV_LOG_WARNING, |
50 | 13 | "Unknown OggVP8 version %d.%d\n", p[6], p[7]); |
51 | 13 | return AVERROR_INVALIDDATA; |
52 | 13 | } |
53 | | |
54 | 1.32k | st->codecpar->width = AV_RB16(p + 8); |
55 | 1.32k | st->codecpar->height = AV_RB16(p + 10); |
56 | 1.32k | st->sample_aspect_ratio.num = AV_RB24(p + 12); |
57 | 1.32k | st->sample_aspect_ratio.den = AV_RB24(p + 15); |
58 | 1.32k | framerate.num = AV_RB32(p + 18); |
59 | 1.32k | framerate.den = AV_RB32(p + 22); |
60 | | |
61 | 1.32k | avpriv_set_pts_info(st, 64, framerate.den, framerate.num); |
62 | 1.32k | st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; |
63 | 1.32k | st->codecpar->codec_id = AV_CODEC_ID_VP8; |
64 | 1.32k | ffstream(st)->need_parsing = AVSTREAM_PARSE_HEADERS; |
65 | 1.32k | break; |
66 | 0 | case 0x02: |
67 | 0 | if (p[6] != 0x20) |
68 | 0 | return AVERROR_INVALIDDATA; |
69 | 0 | ff_vorbis_stream_comment(s, st, p + 7, os->psize - 7); |
70 | 0 | break; |
71 | 7 | default: |
72 | 7 | av_log(s, AV_LOG_ERROR, "Unknown VP8 header type 0x%02X\n", p[5]); |
73 | 7 | return AVERROR_INVALIDDATA; |
74 | 1.34k | } |
75 | | |
76 | 1.32k | return 1; |
77 | 1.34k | } |
78 | | |
79 | | static uint64_t vp8_gptopts(AVFormatContext *s, int idx, |
80 | | uint64_t granule, int64_t *dts) |
81 | 11.7k | { |
82 | 11.7k | struct ogg *ogg = s->priv_data; |
83 | 11.7k | struct ogg_stream *os = ogg->streams + idx; |
84 | | |
85 | 11.7k | int invcnt = !((granule >> 30) & 3); |
86 | | // If page granule is that of an invisible vp8 frame, its pts will be |
87 | | // that of the end of the next visible frame. We subtract 1 for those |
88 | | // to prevent messing up pts calculations. |
89 | 11.7k | uint64_t pts = (granule >> 32) - invcnt; |
90 | 11.7k | uint32_t dist = (granule >> 3) & 0x07ffffff; |
91 | | |
92 | 11.7k | if (!dist) |
93 | 6.88k | os->pflags |= AV_PKT_FLAG_KEY; |
94 | | |
95 | 11.7k | if (dts) |
96 | 3.08k | *dts = pts; |
97 | | |
98 | 11.7k | return pts; |
99 | 11.7k | } |
100 | | |
101 | | static int vp8_packet(AVFormatContext *s, int idx) |
102 | 11.4k | { |
103 | 11.4k | struct ogg *ogg = s->priv_data; |
104 | 11.4k | struct ogg_stream *os = ogg->streams + idx; |
105 | 11.4k | uint8_t *p = os->buf + os->pstart; |
106 | | |
107 | 11.4k | if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && |
108 | 11.4k | !(os->flags & OGG_FLAG_EOS)) { |
109 | 7.70k | int seg; |
110 | 7.70k | int duration; |
111 | 7.70k | uint8_t *last_pkt = p; |
112 | 7.70k | uint8_t *next_pkt; |
113 | | |
114 | 7.70k | seg = os->segp; |
115 | 7.70k | duration = (last_pkt[0] >> 4) & 1; |
116 | 7.70k | next_pkt = last_pkt += os->psize; |
117 | 44.5k | for (; seg < os->nsegs; seg++) { |
118 | 36.7k | if (os->segments[seg] < 255) { |
119 | 16.6k | duration += (last_pkt[0] >> 4) & 1; |
120 | 16.6k | last_pkt = next_pkt + os->segments[seg]; |
121 | 16.6k | } |
122 | 36.7k | next_pkt += os->segments[seg]; |
123 | 36.7k | } |
124 | 7.70k | os->lastpts = |
125 | 7.70k | os->lastdts = vp8_gptopts(s, idx, os->granule, NULL) - duration; |
126 | 7.70k | if(s->streams[idx]->start_time == AV_NOPTS_VALUE) { |
127 | 198 | s->streams[idx]->start_time = os->lastpts; |
128 | 198 | if (s->streams[idx]->duration && s->streams[idx]->duration != AV_NOPTS_VALUE) |
129 | 41 | s->streams[idx]->duration -= s->streams[idx]->start_time; |
130 | 198 | } |
131 | 7.70k | } |
132 | | |
133 | 11.4k | if (os->psize > 0) |
134 | 4.13k | os->pduration = (p[0] >> 4) & 1; |
135 | | |
136 | 11.4k | return 0; |
137 | 11.4k | } |
138 | | |
139 | | const struct ogg_codec ff_vp8_codec = { |
140 | | .magic = "OVP80", |
141 | | .magicsize = 5, |
142 | | .header = vp8_header, |
143 | | .packet = vp8_packet, |
144 | | .gptopts = vp8_gptopts, |
145 | | .nb_header = 1, |
146 | | }; |