Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /** |
2 | Copyright (C) 2005 Michael Ahlberg, Måns Rullgård | |
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/avassert.h" | |
27 | #include "libavutil/intreadwrite.h" | |
28 | #include "libavcodec/get_bits.h" | |
29 | #include "libavcodec/bytestream.h" | |
30 | #include "avformat.h" | |
31 | #include "internal.h" | |
32 | #include "oggdec.h" | |
33 | #include "riff.h" | |
34 | ||
35 | static int | |
36 | ogm_header(AVFormatContext *s, int idx) | |
37 | { | |
38 | struct ogg *ogg = s->priv_data; | |
39 | struct ogg_stream *os = ogg->streams + idx; | |
40 | AVStream *st = s->streams[idx]; | |
41 | GetByteContext p; | |
42 | uint64_t time_unit; | |
43 | uint64_t spu; | |
44 | uint32_t size; | |
45 | ||
46 | bytestream2_init(&p, os->buf + os->pstart, os->psize); | |
47 | if (!(bytestream2_peek_byte(&p) & 1)) | |
48 | return 0; | |
49 | ||
50 | if (bytestream2_peek_byte(&p) == 1) { | |
51 | bytestream2_skip(&p, 1); | |
52 | ||
53 | if (bytestream2_peek_byte(&p) == 'v'){ | |
54 | int tag; | |
55 | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; | |
56 | bytestream2_skip(&p, 8); | |
57 | tag = bytestream2_get_le32(&p); | |
58 | st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag); | |
59 | st->codec->codec_tag = tag; | |
60 | } else if (bytestream2_peek_byte(&p) == 't') { | |
61 | st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; | |
62 | st->codec->codec_id = AV_CODEC_ID_TEXT; | |
63 | bytestream2_skip(&p, 12); | |
64 | } else { | |
65 | uint8_t acid[5] = { 0 }; | |
66 | int cid; | |
67 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; | |
68 | bytestream2_skip(&p, 8); | |
69 | bytestream2_get_buffer(&p, acid, 4); | |
70 | acid[4] = 0; | |
71 | cid = strtol(acid, NULL, 16); | |
72 | st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, cid); | |
73 | // our parser completely breaks AAC in Ogg | |
74 | if (st->codec->codec_id != AV_CODEC_ID_AAC) | |
75 | st->need_parsing = AVSTREAM_PARSE_FULL; | |
76 | } | |
77 | ||
78 | size = bytestream2_get_le32(&p); | |
79 | size = FFMIN(size, os->psize); | |
80 | time_unit = bytestream2_get_le64(&p); | |
81 | spu = bytestream2_get_le64(&p); | |
82 | if (!time_unit || !spu) { | |
83 | av_log(s, AV_LOG_ERROR, "Invalid timing values.\n"); | |
84 | return AVERROR_INVALIDDATA; | |
85 | } | |
86 | ||
87 | bytestream2_skip(&p, 4); /* default_len */ | |
88 | bytestream2_skip(&p, 8); /* buffersize + bits_per_sample */ | |
89 | ||
90 | if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){ | |
91 | st->codec->width = bytestream2_get_le32(&p); | |
92 | st->codec->height = bytestream2_get_le32(&p); | |
93 | avpriv_set_pts_info(st, 64, time_unit, spu * 10000000); | |
94 | } else { | |
95 | st->codec->channels = bytestream2_get_le16(&p); | |
96 | bytestream2_skip(&p, 2); /* block_align */ | |
97 | st->codec->bit_rate = bytestream2_get_le32(&p) * 8; | |
98 | st->codec->sample_rate = spu * 10000000 / time_unit; | |
99 | avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); | |
100 | if (size >= 56 && st->codec->codec_id == AV_CODEC_ID_AAC) { | |
101 | bytestream2_skip(&p, 4); | |
102 | size -= 4; | |
103 | } | |
104 | if (size > 52) { | |
105 | av_assert0(FF_INPUT_BUFFER_PADDING_SIZE <= 52); | |
106 | size -= 52; | |
107 | ff_alloc_extradata(st->codec, size); | |
108 | bytestream2_get_buffer(&p, st->codec->extradata, st->codec->extradata_size); | |
109 | } | |
110 | } | |
111 | } else if (bytestream2_peek_byte(&p) == 3) { | |
112 | bytestream2_skip(&p, 7); | |
113 | if (bytestream2_get_bytes_left(&p) > 1) | |
114 | ff_vorbis_stream_comment(s, st, p.buffer, bytestream2_get_bytes_left(&p) - 1); | |
115 | } | |
116 | ||
117 | return 1; | |
118 | } | |
119 | ||
120 | static int | |
121 | ogm_dshow_header(AVFormatContext *s, int idx) | |
122 | { | |
123 | struct ogg *ogg = s->priv_data; | |
124 | struct ogg_stream *os = ogg->streams + idx; | |
125 | AVStream *st = s->streams[idx]; | |
126 | uint8_t *p = os->buf + os->pstart; | |
127 | uint32_t t; | |
128 | ||
129 | if(!(*p & 1)) | |
130 | return 0; | |
131 | if(*p != 1) | |
132 | return 1; | |
133 | ||
134 | if (os->psize < 100) | |
135 | return AVERROR_INVALIDDATA; | |
136 | t = AV_RL32(p + 96); | |
137 | ||
138 | if(t == 0x05589f80){ | |
139 | if (os->psize < 184) | |
140 | return AVERROR_INVALIDDATA; | |
141 | ||
142 | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; | |
143 | st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(p + 68)); | |
144 | avpriv_set_pts_info(st, 64, AV_RL64(p + 164), 10000000); | |
145 | st->codec->width = AV_RL32(p + 176); | |
146 | st->codec->height = AV_RL32(p + 180); | |
147 | } else if(t == 0x05589f81){ | |
148 | if (os->psize < 136) | |
149 | return AVERROR_INVALIDDATA; | |
150 | ||
151 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; | |
152 | st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, AV_RL16(p + 124)); | |
153 | st->codec->channels = AV_RL16(p + 126); | |
154 | st->codec->sample_rate = AV_RL32(p + 128); | |
155 | st->codec->bit_rate = AV_RL32(p + 132) * 8; | |
156 | } | |
157 | ||
158 | return 1; | |
159 | } | |
160 | ||
161 | static int | |
162 | ogm_packet(AVFormatContext *s, int idx) | |
163 | { | |
164 | struct ogg *ogg = s->priv_data; | |
165 | struct ogg_stream *os = ogg->streams + idx; | |
166 | uint8_t *p = os->buf + os->pstart; | |
167 | int lb; | |
168 | ||
169 | if(*p & 8) | |
170 | os->pflags |= AV_PKT_FLAG_KEY; | |
171 | ||
172 | lb = ((*p & 2) << 1) | ((*p >> 6) & 3); | |
173 | os->pstart += lb + 1; | |
174 | os->psize -= lb + 1; | |
175 | ||
176 | while (lb--) | |
177 | os->pduration += p[lb+1] << (lb*8); | |
178 | ||
179 | return 0; | |
180 | } | |
181 | ||
182 | const struct ogg_codec ff_ogm_video_codec = { | |
183 | .magic = "\001video", | |
184 | .magicsize = 6, | |
185 | .header = ogm_header, | |
186 | .packet = ogm_packet, | |
187 | .granule_is_start = 1, | |
188 | .nb_header = 2, | |
189 | }; | |
190 | ||
191 | const struct ogg_codec ff_ogm_audio_codec = { | |
192 | .magic = "\001audio", | |
193 | .magicsize = 6, | |
194 | .header = ogm_header, | |
195 | .packet = ogm_packet, | |
196 | .granule_is_start = 1, | |
197 | .nb_header = 2, | |
198 | }; | |
199 | ||
200 | const struct ogg_codec ff_ogm_text_codec = { | |
201 | .magic = "\001text", | |
202 | .magicsize = 5, | |
203 | .header = ogm_header, | |
204 | .packet = ogm_packet, | |
205 | .granule_is_start = 1, | |
206 | .nb_header = 2, | |
207 | }; | |
208 | ||
209 | const struct ogg_codec ff_ogm_old_codec = { | |
210 | .magic = "\001Direct Show Samples embedded in Ogg", | |
211 | .magicsize = 35, | |
212 | .header = ogm_dshow_header, | |
213 | .packet = ogm_packet, | |
214 | .granule_is_start = 1, | |
215 | .nb_header = 1, | |
216 | }; |