aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-11-19 14:20:42 +0000
committerChristian Grothoff <christian@grothoff.org>2011-11-19 14:20:42 +0000
commitba90dc573961d9daa855bd423a47b61d958b47c6 (patch)
tree80394b43c93d2198f46fdc267e44184a5e3c6391
parent53a0ab31905a3a096543ee9540b00e6f80c259d2 (diff)
downloadlibextractor-ba90dc573961d9daa855bd423a47b61d958b47c6.tar.gz
libextractor-ba90dc573961d9daa855bd423a47b61d958b47c6.zip
first draft of MKV plugin
-rw-r--r--AUTHORS1
-rw-r--r--doc/version.texi2
-rw-r--r--src/plugins/Makefile.am6
-rw-r--r--src/plugins/mkv_extractor.c389
4 files changed, 397 insertions, 1 deletions
diff --git a/AUTHORS b/AUTHORS
index 3bcf7e1..3e4f3c2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -43,6 +43,7 @@ applefile - Heikki Lindholm
43it - Toni Ruottu <toni.ruottu@iki.fi> 43it - Toni Ruottu <toni.ruottu@iki.fi>
44xm - Toni Ruottu <toni.ruottu@iki.fi> 44xm - Toni Ruottu <toni.ruottu@iki.fi>
45s3m - Toni Ruottu <toni.ruottu@iki.fi> 45s3m - Toni Ruottu <toni.ruottu@iki.fi>
46mkv - Gabriel Peixoto <peixotogm@gmail.com>
46 47
47General contributors: 48General contributors:
48Yuri N. Sedunov <aris@altlinux.ru> 49Yuri N. Sedunov <aris@altlinux.ru>
diff --git a/doc/version.texi b/doc/version.texi
index 76de64a..fafc586 100644
--- a/doc/version.texi
+++ b/doc/version.texi
@@ -1,4 +1,4 @@
1@set UPDATED 29 March 2010 1@set UPDATED 31 March 2010
2@set UPDATED-MONTH March 2010 2@set UPDATED-MONTH March 2010
3@set EDITION 0.6.2 3@set EDITION 0.6.2
4@set VERSION 0.6.2 4@set VERSION 0.6.2
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index b3dd1de..5a29df3 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -94,6 +94,7 @@ plugin_LTLIBRARIES = \
94 libextractor_jpeg.la \ 94 libextractor_jpeg.la \
95 libextractor_man.la \ 95 libextractor_man.la \
96 libextractor_mime.la \ 96 libextractor_mime.la \
97 libextractor_mkv.la \
97 libextractor_mp3.la \ 98 libextractor_mp3.la \
98 $(mpeg) \ 99 $(mpeg) \
99 libextractor_nsf.la \ 100 libextractor_nsf.la \
@@ -240,6 +241,11 @@ libextractor_mime_la_SOURCES = \
240libextractor_mime_la_LDFLAGS = \ 241libextractor_mime_la_LDFLAGS = \
241 $(PLUGINFLAGS) 242 $(PLUGINFLAGS)
242 243
244libextractor_mkv_la_SOURCES = \
245 mkv_extractor.c
246libextractor_mkv_la_LDFLAGS = \
247 $(PLUGINFLAGS)
248
243libextractor_mp3_la_SOURCES = \ 249libextractor_mp3_la_SOURCES = \
244 mp3_extractor.c 250 mp3_extractor.c
245libextractor_mp3_la_LDFLAGS = \ 251libextractor_mp3_la_LDFLAGS = \
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
36typedef long long int64;
37enum
38{
39 MKV_Track_video = 1,
40 MKV_Track_audio = 2,
41 MKV_Track_subtitle = 3,
42 MKV_Track_subtitle_orig = 0x11
43};
44enum
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
76static int
77VINTparse (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
120static int
121elementRead (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
141static int64
142getInt (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
155static float
156getFloat (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
172const 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
181const char stream_type_letters[] = "?vat"; /*[0]-no, [1]-video,[2]-audio,[3]-text */
182
183
184/* video/mkv */
185int
186EXTRACTOR_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
385EXIT:
386
387 return ret;
388
389}