diff options
Diffstat (limited to 'src/plugins/mkv_extractor.c')
-rw-r--r-- | src/plugins/mkv_extractor.c | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/src/plugins/mkv_extractor.c b/src/plugins/mkv_extractor.c new file mode 100644 index 0000000..14d8383 --- /dev/null +++ b/src/plugins/mkv_extractor.c | |||
@@ -0,0 +1,389 @@ | |||
1 | /* | ||
2 | This file is part of libextractor. | ||
3 | (C) 2004, 2005, 2006, 2009 Vidyut Samanta and Christian Grothoff | ||
4 | |||
5 | libextractor is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | libextractor is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with libextractor; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * Made by Gabriel Peixoto | ||
23 | * Using AVInfo 1.x code. Copyright (c) 2004 George Shuklin. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "extractor.h" | ||
29 | |||
30 | |||
31 | #define ADD(s,t) do { if (0 != (ret = proc (proc_cls, "mkv", t, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen(s)+1))) goto EXIT; } while (0) | ||
32 | |||
33 | #define BUFFER_SIZE 0x4000 | ||
34 | #define MAX_STRING_SIZE 1024 | ||
35 | #define MAX_STREAMS 9 | ||
36 | typedef long long int64; | ||
37 | enum | ||
38 | { | ||
39 | MKV_Track_video = 1, | ||
40 | MKV_Track_audio = 2, | ||
41 | MKV_Track_subtitle = 3, | ||
42 | MKV_Track_subtitle_orig = 0x11 | ||
43 | }; | ||
44 | enum | ||
45 | { | ||
46 | MKVID_OutputSamplingFrequency = 0x78B5, | ||
47 | MKVID_FILE_BEGIN = 0x1A, | ||
48 | MKVID_EBML = 0x1A45DFA3, | ||
49 | MKVID_Segment = 0x18538067, | ||
50 | MKVID_Info = 0x1549A966, | ||
51 | MKVID_Tracks = 0x1654AE6B, | ||
52 | MKVID_TrackEntry = 0xAE, | ||
53 | MKVID_TrackType = 0x83, | ||
54 | MKVID_DefaultDuration = 0x23E383, | ||
55 | MKVID_Language = 0x22B59C, | ||
56 | MKVID_CodecID = 0x86, | ||
57 | MKVID_CodecPrivate = 0x63A2, | ||
58 | MKVID_PixelWidth = 0xB0, | ||
59 | MKVID_PixelHeight = 0xBA, | ||
60 | MKVID_TimeCodeScale = 0x2AD7B1, | ||
61 | MKVID_Duration = 0x4489, | ||
62 | MKVID_Channels = 0x9F, | ||
63 | MKVID_BitDepth = 0x6264, | ||
64 | MKVID_SamplingFrequency = 0xB5, | ||
65 | MKVID_Title = 0x7BA9, | ||
66 | MKVID_Tags = 0x1254C367, | ||
67 | MKVID_SeekHead = 0x114D9B74, | ||
68 | MKVID_Video = 0xE0, | ||
69 | MKVID_Audio = 0xE1, | ||
70 | MKVID_CodecName = 0x258688, | ||
71 | MKVID_DisplayHeight = 0x54BA, | ||
72 | MKVID_DisplayWidth = 0x54B0 | ||
73 | }; | ||
74 | |||
75 | |||
76 | static int | ||
77 | VINTparse (const unsigned char *buffer, const int start, const int end, | ||
78 | int64 * result, const int flag) | ||
79 | { | ||
80 | unsigned const char mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; | ||
81 | unsigned const char imask[8] = { 0x7F, 0x3F, 0x1F, 0xF, 0x7, 0x3, 0x1, 00 }; | ||
82 | int VINT_WIDTH; | ||
83 | int c; | ||
84 | |||
85 | VINT_WIDTH = 0; | ||
86 | int64 temp; | ||
87 | unsigned char tempc; | ||
88 | *result = 0; | ||
89 | |||
90 | if (end - start < 2) | ||
91 | { | ||
92 | return 0; /*ops */ | ||
93 | } | ||
94 | |||
95 | for (c = 0; c < 8; c++) | ||
96 | if (!(buffer[start] & mask[c])) | ||
97 | VINT_WIDTH++; | ||
98 | else | ||
99 | break; | ||
100 | if (VINT_WIDTH >= 8 || VINT_WIDTH + start + 1 >= end) | ||
101 | { | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | for (c = 0; c < VINT_WIDTH; c++) | ||
106 | { | ||
107 | tempc = buffer[start + VINT_WIDTH - c]; | ||
108 | temp = tempc << (c * 8); | ||
109 | *result += temp; | ||
110 | } | ||
111 | |||
112 | if (flag) | ||
113 | *result += (buffer[start] & imask[VINT_WIDTH]) << (VINT_WIDTH * 8); | ||
114 | else | ||
115 | *result += (buffer[start]) << (VINT_WIDTH * 8); | ||
116 | |||
117 | return VINT_WIDTH + 1; | ||
118 | } | ||
119 | |||
120 | static int | ||
121 | elementRead (const char *buffer, const int start, const int end, | ||
122 | unsigned int *ID, int64 * size) | ||
123 | { | ||
124 | int64 tempID; | ||
125 | int64 tempsize; | ||
126 | int ID_offset, size_offset; | ||
127 | |||
128 | tempID = 0; | ||
129 | |||
130 | ID_offset = VINTparse (buffer, start, end, &tempID, 0); | ||
131 | if (!ID_offset) | ||
132 | return 0; | ||
133 | size_offset = VINTparse (buffer, start + ID_offset, end, &tempsize, 1); | ||
134 | if (!size_offset) | ||
135 | return 0; | ||
136 | *ID = (int) tempID; /*id must be <4 and must to feet in uint */ | ||
137 | *size = tempsize; | ||
138 | return ID_offset + size_offset; | ||
139 | } | ||
140 | |||
141 | static int64 | ||
142 | getInt (const char *buffer, const int start, const int size) | ||
143 | { | ||
144 | /*return a int [8-64], from buffer, Big Endian*/ | ||
145 | int64 result = 0; | ||
146 | int c; | ||
147 | |||
148 | for (c = 1; c <= size; c++) | ||
149 | { | ||
150 | result += buffer[start + c - 1] << (8 * (size - c)); | ||
151 | } | ||
152 | return result; | ||
153 | } | ||
154 | |||
155 | static float | ||
156 | getFloat (const char *buffer, const int start, const int size) | ||
157 | { | ||
158 | float result = 0; | ||
159 | char tmp[4]; | ||
160 | |||
161 | if (size == sizeof (float)) | ||
162 | { | ||
163 | tmp[0] = buffer[start + 3]; | ||
164 | tmp[1] = buffer[start + 2]; | ||
165 | tmp[2] = buffer[start + 1]; | ||
166 | tmp[3] = buffer[start]; | ||
167 | result = *((float *) (tmp)); | ||
168 | } | ||
169 | return result; | ||
170 | } | ||
171 | |||
172 | const unsigned int MKV_Parse_list[] = { /*Elements, containing requed information (sub-elements), see enum in mkv.h for values */ | ||
173 | MKVID_Segment, | ||
174 | MKVID_Info, | ||
175 | MKVID_Video, | ||
176 | MKVID_Audio, | ||
177 | MKVID_TrackEntry, | ||
178 | MKVID_Tracks | ||
179 | }; | ||
180 | |||
181 | const char stream_type_letters[] = "?vat"; /*[0]-no, [1]-video,[2]-audio,[3]-text */ | ||
182 | |||
183 | |||
184 | /* video/mkv */ | ||
185 | int | ||
186 | EXTRACTOR_mkv_extract (const unsigned char *data, size_t size1, | ||
187 | EXTRACTOR_MetaDataProcessor proc, void *proc_cls, | ||
188 | const char *options) | ||
189 | { | ||
190 | int ret; | ||
191 | char buffer[128],temp[128]; | ||
192 | int p; /*pointer in buffer */ | ||
193 | int c, c2; /*counter in some loops */ | ||
194 | |||
195 | unsigned int eID; /*element ID */ | ||
196 | int64 eSize; /*Size of element content */ | ||
197 | int offs; | ||
198 | int64 timescale = 1000000; | ||
199 | float Duration = 0; | ||
200 | int64 DefaultDuration = 0; | ||
201 | int TrackType = 0; | ||
202 | int pvt_look_flag = 0; | ||
203 | int curr_c = -1; | ||
204 | int a_c = -1; | ||
205 | int v_c = -1; | ||
206 | int t_c = -1; | ||
207 | int value_width = 0; | ||
208 | int value_height = 0; | ||
209 | int value = 0; | ||
210 | int size; | ||
211 | |||
212 | ret = 0; | ||
213 | p = 0; | ||
214 | |||
215 | if (size1 > 16777216) | ||
216 | { | ||
217 | size = 16777216; | ||
218 | }else{ | ||
219 | size = size1; | ||
220 | } | ||
221 | |||
222 | if (!size) | ||
223 | { | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | |||
228 | while (data[p] != MKVID_FILE_BEGIN) | ||
229 | { | ||
230 | p++; | ||
231 | if (p >= size) | ||
232 | { | ||
233 | return 0; | ||
234 | } | ||
235 | }; /*skip text while EBML begin */ | ||
236 | |||
237 | /*main loop*/ | ||
238 | do | ||
239 | { | ||
240 | offs = elementRead (data, p, size, &eID, &eSize); | ||
241 | p += offs; | ||
242 | if (!offs || p >= size) | ||
243 | break; | ||
244 | for (c = 0; c < sizeof (MKV_Parse_list) / sizeof (*MKV_Parse_list); c++) | ||
245 | if (MKV_Parse_list[c] == eID) | ||
246 | { | ||
247 | break; | ||
248 | } | ||
249 | if (c < sizeof (MKV_Parse_list) / sizeof (*MKV_Parse_list)) | ||
250 | continue; | ||
251 | if (p + eSize > size) | ||
252 | break; /*TODO - add (if requied) suckup from file to data */ | ||
253 | if (eSize == 4 || eSize == 8 || eSize == 1 || eSize == 2) | ||
254 | value = (int) getInt (data, p, eSize); | ||
255 | |||
256 | switch (eID) | ||
257 | { | ||
258 | case MKVID_TrackType: /*detect a stream type (video/audio/text) */ | ||
259 | TrackType = value; | ||
260 | pvt_look_flag = 0; | ||
261 | switch (TrackType) | ||
262 | { | ||
263 | case MKV_Track_video: | ||
264 | v_c++; | ||
265 | if (v_c > MAX_STREAMS) | ||
266 | v_c = MAX_STREAMS; | ||
267 | sprintf (buffer, "%u(video)", | ||
268 | (int) (Duration / 1e+9 * (float) timescale)); | ||
269 | ADD (buffer, EXTRACTOR_METATYPE_DURATION); | ||
270 | curr_c = v_c; | ||
271 | break; | ||
272 | case MKV_Track_audio: | ||
273 | a_c++; | ||
274 | if (a_c > MAX_STREAMS) | ||
275 | a_c = MAX_STREAMS; | ||
276 | sprintf (buffer, "%u(audio)", | ||
277 | (int) (Duration / 1e+9 * (float) timescale)); | ||
278 | ADD (buffer, EXTRACTOR_METATYPE_DURATION); | ||
279 | curr_c = a_c; | ||
280 | break; | ||
281 | case MKV_Track_subtitle_orig: | ||
282 | t_c++; | ||
283 | TrackType = MKV_Track_subtitle; /*for normal use in lang array */ | ||
284 | if (t_c > MAX_STREAMS) | ||
285 | t_c = MAX_STREAMS; | ||
286 | curr_c = t_c; | ||
287 | break; | ||
288 | } | ||
289 | break; | ||
290 | case MKVID_DefaultDuration: /*fps detection */ | ||
291 | if (TrackType == MKV_Track_video && v_c >= 0) | ||
292 | { | ||
293 | DefaultDuration = value; | ||
294 | if (DefaultDuration > 100) | ||
295 | { | ||
296 | sprintf (buffer, "fps: %u", 1000000000 / DefaultDuration); | ||
297 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
298 | } | ||
299 | } | ||
300 | break; | ||
301 | case MKVID_Language: /*stream language */ | ||
302 | if (curr_c >= 0 && TrackType < 4 && eSize < MAX_STRING_SIZE) | ||
303 | { | ||
304 | strncpy(temp,data+p,eSize); | ||
305 | temp[eSize] = '\0'; | ||
306 | sprintf (buffer, "%s", temp); | ||
307 | ADD (buffer, EXTRACTOR_METATYPE_LANGUAGE); | ||
308 | } | ||
309 | break; | ||
310 | case MKVID_CodecName: /*passtrough */ | ||
311 | case MKVID_CodecID: /*codec detection (if V_MS/VFW/FOURCC - set a fourcc code, else fill a vcodecs value) */ | ||
312 | if (curr_c >= 0 && TrackType < 4 && eSize < MAX_STRING_SIZE) | ||
313 | { | ||
314 | strncpy(temp,data+p,eSize); | ||
315 | temp[eSize] = '\0'; | ||
316 | if (!strcmp (temp, "V_MS/VFW/FOURCC")) | ||
317 | pvt_look_flag = 1; | ||
318 | sprintf (buffer, "codec: %s", temp); | ||
319 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
320 | } | ||
321 | break; | ||
322 | case MKVID_CodecPrivate: | ||
323 | if (pvt_look_flag && v_c >= 0 && eSize >= 24) | ||
324 | { /*CodecPrivate contains a BITMAPINFOHEADER structure due CodecID==V_MS/VFW/FOURCC */ | ||
325 | pvt_look_flag = 0; | ||
326 | //TODO | ||
327 | /* | ||
328 | video[v_c][V_cc]=(buffer[p+16]<<24)+(buffer[p+17]<<16)+(buffer[p+18]<<8)+buffer[p+19]; | ||
329 | if (codec[v_c][MKV_Track_video]) | ||
330 | { | ||
331 | free (codec[v_c][MKV_Track_video]); | ||
332 | codec[v_c][MKV_Track_video] = NULL; | ||
333 | } | ||
334 | */ | ||
335 | } | ||
336 | break; | ||
337 | case MKVID_PixelWidth: /*pasthough *//*bug with aspect differ from 1:1 */ | ||
338 | case MKVID_DisplayWidth: | ||
339 | value_width = value; | ||
340 | break; | ||
341 | case MKVID_PixelHeight: /*pasthough */ | ||
342 | case MKVID_DisplayHeight: | ||
343 | value_height = value; | ||
344 | break; | ||
345 | case MKVID_TimeCodeScale: | ||
346 | timescale = getInt (data, p, eSize); | ||
347 | sprintf (buffer, "TimeScale: %u", timescale); | ||
348 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
349 | break; | ||
350 | case MKVID_Duration: | ||
351 | Duration = getFloat (data, p, eSize); | ||
352 | sprintf (buffer, "duration: %u s", Duration); | ||
353 | ADD (buffer, EXTRACTOR_METATYPE_DURATION); | ||
354 | break; | ||
355 | case MKVID_Channels: | ||
356 | sprintf (buffer, "channels: %u", value); | ||
357 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
358 | break; | ||
359 | case MKVID_BitDepth: | ||
360 | sprintf (buffer, "BitDepth: %u", value); | ||
361 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
362 | break; | ||
363 | case MKVID_OutputSamplingFrequency: /*pasthough */ | ||
364 | case MKVID_SamplingFrequency: | ||
365 | sprintf (buffer, "Sampling Frequency: %u", value); | ||
366 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
367 | break; | ||
368 | break; | ||
369 | case MKVID_Title: | ||
370 | if (eSize > MAX_STRING_SIZE) | ||
371 | break; | ||
372 | strncpy(temp,data+p,eSize); | ||
373 | temp[eSize] = '\0'; | ||
374 | ADD (temp, EXTRACTOR_METATYPE_TITLE); | ||
375 | break; | ||
376 | /*TODO case MKVID_Tags:*/ | ||
377 | } | ||
378 | p += eSize; /*skip unknown or uninteresting */ | ||
379 | } | ||
380 | while (1); | ||
381 | |||
382 | sprintf (buffer, "Image dimensions: %u X %u", value_width, value_height); | ||
383 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
384 | |||
385 | EXIT: | ||
386 | |||
387 | return ret; | ||
388 | |||
389 | } | ||