aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/mkv_extractor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/mkv_extractor.c')
-rw-r--r--src/plugins/mkv_extractor.c267
1 files changed, 159 insertions, 108 deletions
diff --git a/src/plugins/mkv_extractor.c b/src/plugins/mkv_extractor.c
index 14d8383..fc7489f 100644
--- a/src/plugins/mkv_extractor.c
+++ b/src/plugins/mkv_extractor.c
@@ -26,14 +26,28 @@
26 26
27#include "platform.h" 27#include "platform.h"
28#include "extractor.h" 28#include "extractor.h"
29 29#include <stdint.h>
30 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) 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 32
33/**
34 * FIXME: document
35 */
33#define BUFFER_SIZE 0x4000 36#define BUFFER_SIZE 0x4000
37
38/**
39 * FIXME: document
40 */
34#define MAX_STRING_SIZE 1024 41#define MAX_STRING_SIZE 1024
42
43/**
44 * FIXME: document
45 */
35#define MAX_STREAMS 9 46#define MAX_STREAMS 9
36typedef long long int64; 47
48/**
49 * FIXME: document
50 */
37enum 51enum
38{ 52{
39 MKV_Track_video = 1, 53 MKV_Track_video = 1,
@@ -41,6 +55,10 @@ enum
41 MKV_Track_subtitle = 3, 55 MKV_Track_subtitle = 3,
42 MKV_Track_subtitle_orig = 0x11 56 MKV_Track_subtitle_orig = 0x11
43}; 57};
58
59/**
60 * FIXME: document
61 */
44enum 62enum
45{ 63{
46 MKVID_OutputSamplingFrequency = 0x78B5, 64 MKVID_OutputSamplingFrequency = 0x78B5,
@@ -73,103 +91,113 @@ enum
73}; 91};
74 92
75 93
76static int 94/**
77VINTparse (const unsigned char *buffer, const int start, const int end, 95 * FIXME: document 'flag', should 'temp'/'result' really be signed?
78 int64 * result, const int flag) 96 *
97 * @return 0 on error, otherwise number of bytes read from buffer
98 */
99static size_t
100VINTparse (const unsigned char *buffer, size_t start, size_t end,
101 int64_t * result, int flag)
79{ 102{
80 unsigned const char mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; 103 static const unsigned 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 }; 104 static const unsigned char imask[8] = { 0x7F, 0x3F, 0x1F, 0xF, 0x7, 0x3, 0x1, 00 };
82 int VINT_WIDTH; 105 int vint_width;
83 int c; 106 unsigned int c;
84 107 int64_t temp;
85 VINT_WIDTH = 0;
86 int64 temp;
87 unsigned char tempc; 108 unsigned char tempc;
88 *result = 0;
89 109
90 if (end - start < 2) 110 if (end - start < 2)
91 { 111 return 0; /*ops */
92 return 0; /*ops */
93 }
94 112
113 vint_width = 0;
95 for (c = 0; c < 8; c++) 114 for (c = 0; c < 8; c++)
96 if (!(buffer[start] & mask[c])) 115 if (!(buffer[start] & mask[c]))
97 VINT_WIDTH++; 116 vint_width++;
98 else 117 else
99 break; 118 break;
100 if (VINT_WIDTH >= 8 || VINT_WIDTH + start + 1 >= end) 119 if ( (vint_width >= 8) || (vint_width + start + 1 >= end) )
101 {
102 return 0; 120 return 0;
103 }
104 121
105 for (c = 0; c < VINT_WIDTH; c++) 122 *result = 0;
123 for (c = 0; c < vint_width; c++)
106 { 124 {
107 tempc = buffer[start + VINT_WIDTH - c]; 125 tempc = buffer[start + vint_width - c];
108 temp = tempc << (c * 8); 126 temp = tempc << (c * 8);
109 *result += temp; 127 *result += temp;
110 } 128 }
111
112 if (flag) 129 if (flag)
113 *result += (buffer[start] & imask[VINT_WIDTH]) << (VINT_WIDTH * 8); 130 *result += (buffer[start] & imask[vint_width]) << (vint_width * 8);
114 else 131 else
115 *result += (buffer[start]) << (VINT_WIDTH * 8); 132 *result += (buffer[start]) << (vint_width * 8);
116 133 return vint_width + 1;
117 return VINT_WIDTH + 1;
118} 134}
119 135
136
137/**
138 * FIXME: 'unsigned int' or 'uint32_t' for ID?
139 * FIXME: document arguments, return value...
140 */
120static int 141static int
121elementRead (const char *buffer, const int start, const int end, 142elementRead (const unsigned char *buffer, size_t start, size_t end,
122 unsigned int *ID, int64 * size) 143 unsigned int *id, int64_t * size)
123{ 144{
124 int64 tempID; 145 int64_t tempID;
125 int64 tempsize; 146 int64_t tempsize;
126 int ID_offset, size_offset; 147 size_t id_offset;
148 size_t size_offset;
127 149
128 tempID = 0; 150 tempID = 0;
129 151
130 ID_offset = VINTparse (buffer, start, end, &tempID, 0); 152 id_offset = VINTparse (buffer, start, end, &tempID, 0);
131 if (!ID_offset) 153 if (!id_offset)
132 return 0; 154 return 0;
133 size_offset = VINTparse (buffer, start + ID_offset, end, &tempsize, 1); 155 size_offset = VINTparse (buffer, start + id_offset, end, &tempsize, 1);
134 if (!size_offset) 156 if (!size_offset)
135 return 0; 157 return 0;
136 *ID = (int) tempID; /*id must be <4 and must to feet in uint */ 158 *id = (unsigned int) tempID; /*id must be <4 and must fit in uint */
137 *size = tempsize; 159 *size = tempsize;
138 return ID_offset + size_offset; 160 return id_offset + size_offset;
139} 161}
140 162
141static int64 163
142getInt (const char *buffer, const int start, const int size) 164/**
165 * FIXME: signed or unsigned return value?
166 */
167static int64_t
168getInt (const unsigned char *buffer, size_t start, size_t size)
143{ 169{
144/*return a int [8-64], from buffer, Big Endian*/ 170 /*return a int [8-64], from buffer, Big Endian*/
145 int64 result = 0; 171 int64_t result;
146 int c; 172 size_t c;
147 173
174 result = 0;
148 for (c = 1; c <= size; c++) 175 for (c = 1; c <= size; c++)
149 { 176 result += buffer[start + c - 1] << (8 * (size - c));
150 result += buffer[start + c - 1] << (8 * (size - c));
151 }
152 return result; 177 return result;
153} 178}
154 179
155static float 180static float
156getFloat (const char *buffer, const int start, const int size) 181getFloat (const char *buffer, size_t start, size_t size)
157{ 182{
158 float result = 0; 183 float result;
159 char tmp[4]; 184 char tmp[4];
160 185
186 if (size != sizeof (float))
187 return 0.0;
161 if (size == sizeof (float)) 188 if (size == sizeof (float))
162 { 189 {
163 tmp[0] = buffer[start + 3]; 190 tmp[0] = buffer[start + 3];
164 tmp[1] = buffer[start + 2]; 191 tmp[1] = buffer[start + 2];
165 tmp[2] = buffer[start + 1]; 192 tmp[2] = buffer[start + 1];
166 tmp[3] = buffer[start]; 193 tmp[3] = buffer[start];
167 result = *((float *) (tmp)); 194 return *((float *) (tmp));
168 } 195 }
169 return result; 196 return result;
170} 197}
171 198
172const unsigned int MKV_Parse_list[] = { /*Elements, containing requed information (sub-elements), see enum in mkv.h for values */ 199static const unsigned int MKV_Parse_list[] = {
200 /*Elements, containing requed information (sub-elements), see enum in mkv.h for values */
173 MKVID_Segment, 201 MKVID_Segment,
174 MKVID_Info, 202 MKVID_Info,
175 MKVID_Video, 203 MKVID_Video,
@@ -178,26 +206,26 @@ const unsigned int MKV_Parse_list[] = { /*Elements, containing requed informatio
178 MKVID_Tracks 206 MKVID_Tracks
179}; 207};
180 208
181const char stream_type_letters[] = "?vat"; /*[0]-no, [1]-video,[2]-audio,[3]-text */ 209static const char stream_type_letters[] = "?vat"; /*[0]-no, [1]-video,[2]-audio,[3]-text */
182 210
183 211
184/* video/mkv */ 212/* video/mkv */
185int 213int
186EXTRACTOR_mkv_extract (const unsigned char *data, size_t size1, 214EXTRACTOR_mkv_extract (const unsigned char *data, size_t size,
187 EXTRACTOR_MetaDataProcessor proc, void *proc_cls, 215 EXTRACTOR_MetaDataProcessor proc, void *proc_cls,
188 const char *options) 216 const char *options)
189{ 217{
190 int ret; 218 int ret;
191 char buffer[128],temp[128]; 219 char buffer[128];
192 int p; /*pointer in buffer */ 220 char temp[128];
221 size_t p; /*pointer in buffer */
193 int c, c2; /*counter in some loops */ 222 int c, c2; /*counter in some loops */
194
195 unsigned int eID; /*element ID */ 223 unsigned int eID; /*element ID */
196 int64 eSize; /*Size of element content */ 224 int64_t eSize; /*Size of element content */
197 int offs; 225 int offs;
198 int64 timescale = 1000000; 226 int64_t timescale = 1000000;
199 float Duration = 0; 227 float duration = -1.0;
200 int64 DefaultDuration = 0; 228 int64_t DefaultDuration = 0;
201 int TrackType = 0; 229 int TrackType = 0;
202 int pvt_look_flag = 0; 230 int pvt_look_flag = 0;
203 int curr_c = -1; 231 int curr_c = -1;
@@ -207,34 +235,20 @@ EXTRACTOR_mkv_extract (const unsigned char *data, size_t size1,
207 int value_width = 0; 235 int value_width = 0;
208 int value_height = 0; 236 int value_height = 0;
209 int value = 0; 237 int value = 0;
210 int size; 238 size_t size1;
239 const unsigned char *start;
211 240
212 ret = 0; 241 if (size > 32 * 1024)
213 p = 0; 242 size1 = 32 * 1024;
214 243 else
215 if (size1 > 16777216) 244 size1 = size;
216 { 245 start = memchr (data, MKVID_FILE_BEGIN, size1);
217 size = 16777216; 246 if (NULL == start)
218 }else{
219 size = size1;
220 }
221
222 if (!size)
223 {
224 return 0; 247 return 0;
225 } 248 p = start - data;
226 249
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*/ 250/*main loop*/
251 ret = 0;
238 do 252 do
239 { 253 {
240 offs = elementRead (data, p, size, &eID, &eSize); 254 offs = elementRead (data, p, size, &eID, &eSize);
@@ -264,18 +278,32 @@ EXTRACTOR_mkv_extract (const unsigned char *data, size_t size1,
264 v_c++; 278 v_c++;
265 if (v_c > MAX_STREAMS) 279 if (v_c > MAX_STREAMS)
266 v_c = MAX_STREAMS; 280 v_c = MAX_STREAMS;
267 sprintf (buffer, "%u(video)", 281 if (duration != -1.0)
268 (int) (Duration / 1e+9 * (float) timescale)); 282 {
269 ADD (buffer, EXTRACTOR_METATYPE_DURATION); 283 /* FIXME: duration might still be -1 here, defer until
284 end of function & check if duration is != -1 */
285 snprintf (buffer,
286 sizeof(buffer),
287 "%u s (video)",
288 (int) (duration / 1e+9 * (float) timescale));
289 ADD (buffer, EXTRACTOR_METATYPE_DURATION);
290 }
270 curr_c = v_c; 291 curr_c = v_c;
271 break; 292 break;
272 case MKV_Track_audio: 293 case MKV_Track_audio:
273 a_c++; 294 a_c++;
274 if (a_c > MAX_STREAMS) 295 if (a_c > MAX_STREAMS)
275 a_c = MAX_STREAMS; 296 a_c = MAX_STREAMS;
276 sprintf (buffer, "%u(audio)", 297 if (duration != -1.0)
277 (int) (Duration / 1e+9 * (float) timescale)); 298 {
278 ADD (buffer, EXTRACTOR_METATYPE_DURATION); 299 /* FIXME: duration might still be -1 here, defer until
300 end of function & check if duration is != -1 */
301 snprintf (buffer,
302 sizeof (buffer),
303 "%u s (audio)",
304 (unsigned int) (duration / 1e+9 * (float) timescale));
305 ADD (buffer, EXTRACTOR_METATYPE_DURATION);
306 }
279 curr_c = a_c; 307 curr_c = a_c;
280 break; 308 break;
281 case MKV_Track_subtitle_orig: 309 case MKV_Track_subtitle_orig:
@@ -293,7 +321,10 @@ EXTRACTOR_mkv_extract (const unsigned char *data, size_t size1,
293 DefaultDuration = value; 321 DefaultDuration = value;
294 if (DefaultDuration > 100) 322 if (DefaultDuration > 100)
295 { 323 {
296 sprintf (buffer, "fps: %u", 1000000000 / DefaultDuration); 324 /* FIXME: integrate with codec name/id into 'METATYPE_FORMAT' */
325 snprintf (buffer,
326 sizeof (buffer),
327 "fps: %u", 1000000000 / DefaultDuration);
297 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); 328 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN);
298 } 329 }
299 } 330 }
@@ -301,9 +332,12 @@ EXTRACTOR_mkv_extract (const unsigned char *data, size_t size1,
301 case MKVID_Language: /*stream language */ 332 case MKVID_Language: /*stream language */
302 if (curr_c >= 0 && TrackType < 4 && eSize < MAX_STRING_SIZE) 333 if (curr_c >= 0 && TrackType < 4 && eSize < MAX_STRING_SIZE)
303 { 334 {
304 strncpy(temp,data+p,eSize); 335 /* FIXME: why first temp, then buffer? */
305 temp[eSize] = '\0'; 336 snprintf (buffer,
306 sprintf (buffer, "%s", temp); 337 sizeof (buffer),
338 "%.*s",
339 (int) eSize,
340 data + p);
307 ADD (buffer, EXTRACTOR_METATYPE_LANGUAGE); 341 ADD (buffer, EXTRACTOR_METATYPE_LANGUAGE);
308 } 342 }
309 break; 343 break;
@@ -311,12 +345,15 @@ EXTRACTOR_mkv_extract (const unsigned char *data, size_t size1,
311 case MKVID_CodecID: /*codec detection (if V_MS/VFW/FOURCC - set a fourcc code, else fill a vcodecs value) */ 345 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) 346 if (curr_c >= 0 && TrackType < 4 && eSize < MAX_STRING_SIZE)
313 { 347 {
314 strncpy(temp,data+p,eSize); 348 if (!strncmp (data + p, "V_MS/VFW/FOURCC", eSize))
315 temp[eSize] = '\0';
316 if (!strcmp (temp, "V_MS/VFW/FOURCC"))
317 pvt_look_flag = 1; 349 pvt_look_flag = 1;
318 sprintf (buffer, "codec: %s", temp); 350 snprintf (buffer,
319 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); 351 sizeof (buffer),
352 "codec: %.*s",
353 (int) eSize,
354 data + p);
355 ADD (buffer,
356 EXTRACTOR_METATYPE_FORMAT);
320 } 357 }
321 break; 358 break;
322 case MKVID_CodecPrivate: 359 case MKVID_CodecPrivate:
@@ -344,25 +381,36 @@ EXTRACTOR_mkv_extract (const unsigned char *data, size_t size1,
344 break; 381 break;
345 case MKVID_TimeCodeScale: 382 case MKVID_TimeCodeScale:
346 timescale = getInt (data, p, eSize); 383 timescale = getInt (data, p, eSize);
347 sprintf (buffer, "TimeScale: %u", timescale); 384 snprintf (buffer,
385 sizeof (buffer),
386 "TimeScale: %u", timescale);
348 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); 387 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN);
349 break; 388 break;
350 case MKVID_Duration: 389 case MKVID_Duration:
351 Duration = getFloat (data, p, eSize); 390 duration = getFloat (data, p, eSize);
352 sprintf (buffer, "duration: %u s", Duration); 391 snprintf (buffer,
392 sizeof (buffer),
393 "%f ms", duration);
353 ADD (buffer, EXTRACTOR_METATYPE_DURATION); 394 ADD (buffer, EXTRACTOR_METATYPE_DURATION);
354 break; 395 break;
355 case MKVID_Channels: 396 case MKVID_Channels:
356 sprintf (buffer, "channels: %u", value); 397 snprintf (buffer,
398 sizeof (buffer),
399 "channels: %u", value);
357 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); 400 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN);
358 break; 401 break;
359 case MKVID_BitDepth: 402 case MKVID_BitDepth:
360 sprintf (buffer, "BitDepth: %u", value); 403 snprintf (buffer,
404 sizeof (buffer),
405 "BitDepth: %u", value);
361 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); 406 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN);
362 break; 407 break;
363 case MKVID_OutputSamplingFrequency: /*pasthough */ 408 case MKVID_OutputSamplingFrequency: /*pasthough */
364 case MKVID_SamplingFrequency: 409 case MKVID_SamplingFrequency:
365 sprintf (buffer, "Sampling Frequency: %u", value); 410 /* FIXME: the resulting value seems wrong... Unit? */
411 snprintf (buffer,
412 sizeof (buffer),
413 "Sampling Frequency: %u", value);
366 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); 414 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN);
367 break; 415 break;
368 break; 416 break;
@@ -378,9 +426,12 @@ EXTRACTOR_mkv_extract (const unsigned char *data, size_t size1,
378 p += eSize; /*skip unknown or uninteresting */ 426 p += eSize; /*skip unknown or uninteresting */
379 } 427 }
380 while (1); 428 while (1);
381 429 if ( (value_width != 0) && (value_height != 0) )
382 sprintf (buffer, "Image dimensions: %u X %u", value_width, value_height); 430 snprintf (buffer,
383 ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); 431 sizeof(buffer),
432 "%ux%u",
433 value_width, value_height);
434 ADD (buffer, EXTRACTOR_METATYPE_IMAGE_DIMENSIONS);
384 435
385EXIT: 436EXIT:
386 437