Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * Copyright (C) 2005 Matthieu CASTET, Alex Beregszaszi | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person | ||
5 | * obtaining a copy of this software and associated documentation | ||
6 | * files (the "Software"), to deal in the Software without | ||
7 | * restriction, including without limitation the rights to use, copy, | ||
8 | * modify, merge, publish, distribute, sublicense, and/or sell copies | ||
9 | * of the Software, and to permit persons to whom the Software is | ||
10 | * furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice shall be | ||
13 | * included in all copies or substantial portions of the Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
19 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
20 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
22 | * DEALINGS IN THE SOFTWARE. | ||
23 | **/ | ||
24 | |||
25 | #include <stdlib.h> | ||
26 | #include "libavutil/mem.h" | ||
27 | #include "libavcodec/get_bits.h" | ||
28 | #include "avformat.h" | ||
29 | #include "internal.h" | ||
30 | #include "oggdec.h" | ||
31 | |||
32 | typedef struct TheoraParams { | ||
33 | int gpshift; | ||
34 | int gpmask; | ||
35 | unsigned version; | ||
36 | } TheoraParams; | ||
37 | |||
38 | 12 | static int theora_header(AVFormatContext *s, int idx) | |
39 | { | ||
40 | 12 | struct ogg *ogg = s->priv_data; | |
41 | 12 | struct ogg_stream *os = ogg->streams + idx; | |
42 | 12 | AVStream *st = s->streams[idx]; | |
43 | 12 | TheoraParams *thp = os->private; | |
44 | 12 | int cds = st->codecpar->extradata_size + os->psize + 2; | |
45 | int err; | ||
46 | uint8_t *cdp; | ||
47 | |||
48 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
|
12 | if (!(os->buf[os->pstart] & 0x80)) |
49 | 3 | return 0; | |
50 | |||
51 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
|
9 | if (!thp) { |
52 | 3 | thp = av_mallocz(sizeof(*thp)); | |
53 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (!thp) |
54 | ✗ | return AVERROR(ENOMEM); | |
55 | 3 | os->private = thp; | |
56 | } | ||
57 | |||
58 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
9 | switch (os->buf[os->pstart]) { |
59 | 3 | case 0x80: { | |
60 | GetBitContext gb; | ||
61 | AVRational timebase; | ||
62 | |||
63 | 3 | init_get_bits(&gb, os->buf + os->pstart, os->psize * 8); | |
64 | |||
65 | /* 0x80"theora" */ | ||
66 | 3 | skip_bits_long(&gb, 7 * 8); | |
67 | |||
68 | 3 | thp->version = get_bits(&gb, 24); | |
69 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (thp->version < 0x030100) { |
70 | ✗ | av_log(s, AV_LOG_ERROR, | |
71 | "Too old or unsupported Theora (%x)\n", thp->version); | ||
72 | ✗ | return AVERROR(ENOSYS); | |
73 | } | ||
74 | |||
75 | 3 | st->codecpar->width = get_bits(&gb, 16) << 4; | |
76 | 3 | st->codecpar->height = get_bits(&gb, 16) << 4; | |
77 | |||
78 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (thp->version >= 0x030400) |
79 | ✗ | skip_bits(&gb, 100); | |
80 | |||
81 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (thp->version >= 0x030200) { |
82 | 3 | int width = get_bits(&gb, 24); | |
83 | 3 | int height = get_bits(&gb, 24); | |
84 |
3/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
|
3 | if (width <= st->codecpar->width && width > st->codecpar->width - 16 && |
85 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | height <= st->codecpar->height && height > st->codecpar->height - 16) { |
86 | 1 | st->codecpar->width = width; | |
87 | 1 | st->codecpar->height = height; | |
88 | } | ||
89 | |||
90 | 3 | skip_bits(&gb, 16); | |
91 | } | ||
92 | |||
93 | 3 | timebase.den = get_bits_long(&gb, 32); | |
94 | 3 | timebase.num = get_bits_long(&gb, 32); | |
95 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
3 | if (!(timebase.num > 0 && timebase.den > 0)) { |
96 | ✗ | av_log(s, AV_LOG_WARNING, "Invalid time base in theora stream, assuming 25 FPS\n"); | |
97 | ✗ | timebase.num = 1; | |
98 | ✗ | timebase.den = 25; | |
99 | } | ||
100 | 3 | avpriv_set_pts_info(st, 64, timebase.num, timebase.den); | |
101 | |||
102 | 3 | st->sample_aspect_ratio.num = get_bits(&gb, 24); | |
103 | 3 | st->sample_aspect_ratio.den = get_bits(&gb, 24); | |
104 | |||
105 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (thp->version >= 0x030200) |
106 | 3 | skip_bits_long(&gb, 38); | |
107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (thp->version >= 0x304000) |
108 | ✗ | skip_bits(&gb, 2); | |
109 | |||
110 | 3 | thp->gpshift = get_bits(&gb, 5); | |
111 | 3 | thp->gpmask = (1U << thp->gpshift) - 1; | |
112 | |||
113 | 3 | st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; | |
114 | 3 | st->codecpar->codec_id = AV_CODEC_ID_THEORA; | |
115 | 3 | ffstream(st)->need_parsing = AVSTREAM_PARSE_HEADERS; | |
116 | } | ||
117 | 3 | break; | |
118 | 3 | case 0x81: | |
119 | 3 | ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 7, os->psize - 7); | |
120 | 6 | case 0x82: | |
121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (!thp->version) |
122 | ✗ | return AVERROR_INVALIDDATA; | |
123 | 6 | break; | |
124 | ✗ | default: | |
125 | ✗ | av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]); | |
126 | ✗ | return AVERROR_INVALIDDATA; | |
127 | } | ||
128 | |||
129 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if ((err = av_reallocp(&st->codecpar->extradata, |
130 | 9 | cds + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) { | |
131 | ✗ | st->codecpar->extradata_size = 0; | |
132 | ✗ | return err; | |
133 | } | ||
134 | 9 | memset(st->codecpar->extradata + cds, 0, AV_INPUT_BUFFER_PADDING_SIZE); | |
135 | |||
136 | 9 | cdp = st->codecpar->extradata + st->codecpar->extradata_size; | |
137 | 9 | *cdp++ = os->psize >> 8; | |
138 | 9 | *cdp++ = os->psize & 0xff; | |
139 | 9 | memcpy(cdp, os->buf + os->pstart, os->psize); | |
140 | 9 | st->codecpar->extradata_size = cds; | |
141 | |||
142 | 9 | return 1; | |
143 | } | ||
144 | |||
145 | 10 | static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, | |
146 | int64_t *dts) | ||
147 | { | ||
148 | 10 | struct ogg *ogg = ctx->priv_data; | |
149 | 10 | struct ogg_stream *os = ogg->streams + idx; | |
150 | 10 | TheoraParams *thp = os->private; | |
151 | uint64_t iframe, pframe; | ||
152 | |||
153 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!thp) |
154 | ✗ | return AV_NOPTS_VALUE; | |
155 | |||
156 | 10 | iframe = gp >> thp->gpshift; | |
157 | 10 | pframe = gp & thp->gpmask; | |
158 | |||
159 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (thp->version < 0x030201) |
160 | ✗ | iframe++; | |
161 | |||
162 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
|
10 | if (!pframe) |
163 | 4 | os->pflags |= AV_PKT_FLAG_KEY; | |
164 | |||
165 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | if (dts) |
166 | 5 | *dts = iframe + pframe; | |
167 | |||
168 | 10 | return iframe + pframe; | |
169 | } | ||
170 | |||
171 | 31 | static int theora_packet(AVFormatContext *s, int idx) | |
172 | { | ||
173 | 31 | struct ogg *ogg = s->priv_data; | |
174 | 31 | struct ogg_stream *os = ogg->streams + idx; | |
175 | int duration; | ||
176 | |||
177 | /* first packet handling | ||
178 | here we parse the duration of each packet in the first page and compare | ||
179 | the total duration to the page granule to find the encoder delay and | ||
180 | set the first timestamp */ | ||
181 | |||
182 |
6/6✓ Branch 0 taken 25 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 28 times.
|
31 | if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) { |
183 | int seg; | ||
184 | int64_t pts; | ||
185 | |||
186 | 2 | duration = 1; | |
187 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | for (seg = os->segp; seg < os->nsegs; seg++) { |
188 | ✗ | if (os->segments[seg] < 255) | |
189 | ✗ | duration ++; | |
190 | } | ||
191 | |||
192 | 2 | pts = theora_gptopts(s, idx, os->granule, NULL); | |
193 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (pts != AV_NOPTS_VALUE) |
194 | 2 | pts = av_sat_sub64(pts, duration); | |
195 | 2 | os->lastpts = os->lastdts = pts; | |
196 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | if(s->streams[idx]->start_time == AV_NOPTS_VALUE && os->lastpts != AV_NOPTS_VALUE) { |
197 | 1 | s->streams[idx]->start_time = os->lastpts; | |
198 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (s->streams[idx]->duration > 0) |
199 | 1 | s->streams[idx]->duration = av_sat_sub64(s->streams[idx]->duration, s->streams[idx]->start_time); | |
200 | } | ||
201 | } | ||
202 | |||
203 | /* parse packet duration */ | ||
204 |
1/2✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
|
31 | if (os->psize > 0) { |
205 | 31 | os->pduration = 1; | |
206 | } | ||
207 | |||
208 | 31 | return 0; | |
209 | } | ||
210 | |||
211 | const struct ogg_codec ff_theora_codec = { | ||
212 | .magic = "\200theora", | ||
213 | .magicsize = 7, | ||
214 | .header = theora_header, | ||
215 | .packet = theora_packet, | ||
216 | .gptopts = theora_gptopts, | ||
217 | .nb_header = 3, | ||
218 | }; | ||
219 |