diff options
Diffstat (limited to 'src/plugins/mkv_extractor.c')
-rw-r--r-- | src/plugins/mkv_extractor.c | 274 |
1 files changed, 120 insertions, 154 deletions
diff --git a/src/plugins/mkv_extractor.c b/src/plugins/mkv_extractor.c index fc7489f..678b4de 100644 --- a/src/plugins/mkv_extractor.c +++ b/src/plugins/mkv_extractor.c | |||
@@ -48,7 +48,7 @@ | |||
48 | /** | 48 | /** |
49 | * FIXME: document | 49 | * FIXME: document |
50 | */ | 50 | */ |
51 | enum | 51 | enum MKV_TrackType |
52 | { | 52 | { |
53 | MKV_Track_video = 1, | 53 | MKV_Track_video = 1, |
54 | MKV_Track_audio = 2, | 54 | MKV_Track_audio = 2, |
@@ -135,12 +135,11 @@ VINTparse (const unsigned char *buffer, size_t start, size_t end, | |||
135 | 135 | ||
136 | 136 | ||
137 | /** | 137 | /** |
138 | * FIXME: 'unsigned int' or 'uint32_t' for ID? | ||
139 | * FIXME: document arguments, return value... | 138 | * FIXME: document arguments, return value... |
140 | */ | 139 | */ |
141 | static int | 140 | static unsigned int |
142 | elementRead (const unsigned char *buffer, size_t start, size_t end, | 141 | elementRead (const unsigned char *buffer, size_t start, size_t end, |
143 | unsigned int *id, int64_t * size) | 142 | uint32_t *id, int64_t * size) |
144 | { | 143 | { |
145 | int64_t tempID; | 144 | int64_t tempID; |
146 | int64_t tempsize; | 145 | int64_t tempsize; |
@@ -155,7 +154,7 @@ elementRead (const unsigned char *buffer, size_t start, size_t end, | |||
155 | size_offset = VINTparse (buffer, start + id_offset, end, &tempsize, 1); | 154 | size_offset = VINTparse (buffer, start + id_offset, end, &tempsize, 1); |
156 | if (!size_offset) | 155 | if (!size_offset) |
157 | return 0; | 156 | return 0; |
158 | *id = (unsigned int) tempID; /*id must be <4 and must fit in uint */ | 157 | *id = (uint32_t) tempID; |
159 | *size = tempsize; | 158 | *size = tempsize; |
160 | return id_offset + size_offset; | 159 | return id_offset + size_offset; |
161 | } | 160 | } |
@@ -173,15 +172,14 @@ getInt (const unsigned char *buffer, size_t start, size_t size) | |||
173 | 172 | ||
174 | result = 0; | 173 | result = 0; |
175 | for (c = 1; c <= size; c++) | 174 | for (c = 1; c <= size; c++) |
176 | result += buffer[start + c - 1] << (8 * (size - c)); | 175 | result += ((uint64_t)buffer[start + c - 1]) << (8 * (size - c)); |
177 | return result; | 176 | return result; |
178 | } | 177 | } |
179 | 178 | ||
180 | static float | 179 | static float |
181 | getFloat (const char *buffer, size_t start, size_t size) | 180 | getFloat (const unsigned char *buffer, size_t start, size_t size) |
182 | { | 181 | { |
183 | float result; | 182 | unsigned char tmp[4]; |
184 | char tmp[4]; | ||
185 | 183 | ||
186 | if (size != sizeof (float)) | 184 | if (size != sizeof (float)) |
187 | return 0.0; | 185 | return 0.0; |
@@ -193,7 +191,7 @@ getFloat (const char *buffer, size_t start, size_t size) | |||
193 | tmp[3] = buffer[start]; | 191 | tmp[3] = buffer[start]; |
194 | return *((float *) (tmp)); | 192 | return *((float *) (tmp)); |
195 | } | 193 | } |
196 | return result; | 194 | return 0.0; |
197 | } | 195 | } |
198 | 196 | ||
199 | static const unsigned int MKV_Parse_list[] = { | 197 | static const unsigned int MKV_Parse_list[] = { |
@@ -216,27 +214,27 @@ EXTRACTOR_mkv_extract (const unsigned char *data, size_t size, | |||
216 | const char *options) | 214 | const char *options) |
217 | { | 215 | { |
218 | int ret; | 216 | int ret; |
219 | char buffer[128]; | 217 | char buffer[256]; |
220 | char temp[128]; | 218 | size_t p; |
221 | size_t p; /*pointer in buffer */ | 219 | int c; |
222 | int c, c2; /*counter in some loops */ | 220 | uint32_t eID; |
223 | unsigned int eID; /*element ID */ | 221 | int64_t eSize; /* signed? */ |
224 | int64_t eSize; /*Size of element content */ | 222 | unsigned int offs; |
225 | int offs; | ||
226 | int64_t timescale = 1000000; | 223 | int64_t timescale = 1000000; |
227 | float duration = -1.0; | 224 | float duration = -1.0; |
228 | int64_t DefaultDuration = 0; | 225 | enum MKV_TrackType trackType; |
229 | int TrackType = 0; | 226 | int have_audio = 0; |
230 | int pvt_look_flag = 0; | 227 | int have_video = 0; |
231 | int curr_c = -1; | 228 | unsigned int value_width = 0; |
232 | int a_c = -1; | 229 | unsigned int value_height = 0; |
233 | int v_c = -1; | 230 | int64_t value; |
234 | int t_c = -1; | ||
235 | int value_width = 0; | ||
236 | int value_height = 0; | ||
237 | int value = 0; | ||
238 | size_t size1; | 231 | size_t size1; |
239 | const unsigned char *start; | 232 | const unsigned char *start; |
233 | int is_mkv = 0; | ||
234 | unsigned int fps = 0; | ||
235 | unsigned int bit_depth = 0; | ||
236 | const unsigned char *codec = NULL; | ||
237 | int codec_strlen = 0; | ||
240 | 238 | ||
241 | if (size > 32 * 1024) | 239 | if (size > 32 * 1024) |
242 | size1 = 32 * 1024; | 240 | size1 = 32 * 1024; |
@@ -255,125 +253,65 @@ EXTRACTOR_mkv_extract (const unsigned char *data, size_t size, | |||
255 | p += offs; | 253 | p += offs; |
256 | if (!offs || p >= size) | 254 | if (!offs || p >= size) |
257 | break; | 255 | break; |
256 | if (MKVID_EBML == eID) | ||
257 | { | ||
258 | ADD ("video/mkv", EXTRACTOR_METATYPE_MIMETYPE); | ||
259 | is_mkv = 1; | ||
260 | continue; | ||
261 | } | ||
262 | if (! is_mkv) | ||
263 | return 0; | ||
258 | for (c = 0; c < sizeof (MKV_Parse_list) / sizeof (*MKV_Parse_list); c++) | 264 | for (c = 0; c < sizeof (MKV_Parse_list) / sizeof (*MKV_Parse_list); c++) |
259 | if (MKV_Parse_list[c] == eID) | 265 | if (MKV_Parse_list[c] == eID) |
260 | { | 266 | break; |
261 | break; | ||
262 | } | ||
263 | if (c < sizeof (MKV_Parse_list) / sizeof (*MKV_Parse_list)) | 267 | if (c < sizeof (MKV_Parse_list) / sizeof (*MKV_Parse_list)) |
264 | continue; | 268 | continue; |
269 | |||
265 | if (p + eSize > size) | 270 | if (p + eSize > size) |
266 | break; /*TODO - add (if requied) suckup from file to data */ | 271 | break; |
267 | if (eSize == 4 || eSize == 8 || eSize == 1 || eSize == 2) | ||
268 | value = (int) getInt (data, p, eSize); | ||
269 | 272 | ||
273 | if ( (eSize == 4) || (eSize == 8) || (eSize == 1) || (eSize == 2)) | ||
274 | value = getInt (data, p, eSize); | ||
275 | |||
270 | switch (eID) | 276 | switch (eID) |
271 | { | 277 | { |
272 | case MKVID_TrackType: /*detect a stream type (video/audio/text) */ | 278 | case MKVID_TrackType: /*detect a stream type (video/audio/text) */ |
273 | TrackType = value; | 279 | trackType = (enum MKV_TrackType) value; |
274 | pvt_look_flag = 0; | 280 | switch (trackType) |
275 | switch (TrackType) | ||
276 | { | 281 | { |
277 | case MKV_Track_video: | 282 | case MKV_Track_video: |
278 | v_c++; | 283 | have_video = 1; |
279 | if (v_c > MAX_STREAMS) | ||
280 | v_c = MAX_STREAMS; | ||
281 | if (duration != -1.0) | ||
282 | { | ||
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 | } | ||
291 | curr_c = v_c; | ||
292 | break; | 284 | break; |
293 | case MKV_Track_audio: | 285 | case MKV_Track_audio: |
294 | a_c++; | 286 | have_audio = 1; |
295 | if (a_c > MAX_STREAMS) | ||
296 | a_c = MAX_STREAMS; | ||
297 | if (duration != -1.0) | ||
298 | { | ||
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 | } | ||
307 | curr_c = a_c; | ||
308 | break; | 287 | break; |
288 | case MKV_Track_subtitle: | ||
289 | break; | ||
309 | case MKV_Track_subtitle_orig: | 290 | case MKV_Track_subtitle_orig: |
310 | t_c++; | 291 | break; |
311 | TrackType = MKV_Track_subtitle; /*for normal use in lang array */ | ||
312 | if (t_c > MAX_STREAMS) | ||
313 | t_c = MAX_STREAMS; | ||
314 | curr_c = t_c; | ||
315 | break; | ||
316 | } | 292 | } |
317 | break; | 293 | break; |
318 | case MKVID_DefaultDuration: /*fps detection */ | 294 | case MKVID_DefaultDuration: |
319 | if (TrackType == MKV_Track_video && v_c >= 0) | 295 | fps = (unsigned int) (1000000000 / value); |
320 | { | ||
321 | DefaultDuration = value; | ||
322 | if (DefaultDuration > 100) | ||
323 | { | ||
324 | /* FIXME: integrate with codec name/id into 'METATYPE_FORMAT' */ | ||
325 | snprintf (buffer, | ||
326 | sizeof (buffer), | ||
327 | "fps: %u", 1000000000 / DefaultDuration); | ||
328 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
329 | } | ||
330 | } | ||
331 | break; | 296 | break; |
332 | case MKVID_Language: /*stream language */ | 297 | case MKVID_Language: |
333 | if (curr_c >= 0 && TrackType < 4 && eSize < MAX_STRING_SIZE) | 298 | snprintf (buffer, |
334 | { | 299 | sizeof (buffer), |
335 | /* FIXME: why first temp, then buffer? */ | 300 | "%.*s", |
336 | snprintf (buffer, | 301 | (int) eSize, |
337 | sizeof (buffer), | 302 | data + p); |
338 | "%.*s", | 303 | ADD (buffer, EXTRACTOR_METATYPE_LANGUAGE); |
339 | (int) eSize, | ||
340 | data + p); | ||
341 | ADD (buffer, EXTRACTOR_METATYPE_LANGUAGE); | ||
342 | } | ||
343 | break; | 304 | break; |
344 | case MKVID_CodecName: /*passtrough */ | 305 | case MKVID_CodecName: |
345 | case MKVID_CodecID: /*codec detection (if V_MS/VFW/FOURCC - set a fourcc code, else fill a vcodecs value) */ | 306 | case MKVID_CodecID: |
346 | if (curr_c >= 0 && TrackType < 4 && eSize < MAX_STRING_SIZE) | 307 | codec = data + p; |
347 | { | 308 | codec_strlen = eSize; |
348 | if (!strncmp (data + p, "V_MS/VFW/FOURCC", eSize)) | ||
349 | pvt_look_flag = 1; | ||
350 | snprintf (buffer, | ||
351 | sizeof (buffer), | ||
352 | "codec: %.*s", | ||
353 | (int) eSize, | ||
354 | data + p); | ||
355 | ADD (buffer, | ||
356 | EXTRACTOR_METATYPE_FORMAT); | ||
357 | } | ||
358 | break; | 309 | break; |
359 | case MKVID_CodecPrivate: | 310 | case MKVID_CodecPrivate: |
360 | if (pvt_look_flag && v_c >= 0 && eSize >= 24) | ||
361 | { /*CodecPrivate contains a BITMAPINFOHEADER structure due CodecID==V_MS/VFW/FOURCC */ | ||
362 | pvt_look_flag = 0; | ||
363 | //TODO | ||
364 | /* | ||
365 | video[v_c][V_cc]=(buffer[p+16]<<24)+(buffer[p+17]<<16)+(buffer[p+18]<<8)+buffer[p+19]; | ||
366 | if (codec[v_c][MKV_Track_video]) | ||
367 | { | ||
368 | free (codec[v_c][MKV_Track_video]); | ||
369 | codec[v_c][MKV_Track_video] = NULL; | ||
370 | } | ||
371 | */ | ||
372 | } | ||
373 | break; | 311 | break; |
374 | case MKVID_PixelWidth: /*pasthough *//*bug with aspect differ from 1:1 */ | 312 | case MKVID_PixelWidth: /*pasthough *//*bug with aspect differ from 1:1 */ |
375 | case MKVID_DisplayWidth: | 313 | case MKVID_DisplayWidth: |
376 | value_width = value; | 314 | value_width = value; |
377 | break; | 315 | break; |
378 | case MKVID_PixelHeight: /*pasthough */ | 316 | case MKVID_PixelHeight: /*pasthough */ |
379 | case MKVID_DisplayHeight: | 317 | case MKVID_DisplayHeight: |
@@ -381,60 +319,88 @@ EXTRACTOR_mkv_extract (const unsigned char *data, size_t size, | |||
381 | break; | 319 | break; |
382 | case MKVID_TimeCodeScale: | 320 | case MKVID_TimeCodeScale: |
383 | timescale = getInt (data, p, eSize); | 321 | timescale = getInt (data, p, eSize); |
384 | snprintf (buffer, | ||
385 | sizeof (buffer), | ||
386 | "TimeScale: %u", timescale); | ||
387 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
388 | break; | 322 | break; |
389 | case MKVID_Duration: | 323 | case MKVID_Duration: |
390 | duration = getFloat (data, p, eSize); | 324 | duration = getFloat (data, p, eSize); |
391 | snprintf (buffer, | ||
392 | sizeof (buffer), | ||
393 | "%f ms", duration); | ||
394 | ADD (buffer, EXTRACTOR_METATYPE_DURATION); | ||
395 | break; | 325 | break; |
396 | case MKVID_Channels: | 326 | case MKVID_Channels: |
397 | snprintf (buffer, | 327 | /* num_channels = (unsigned int) value; */ |
398 | sizeof (buffer), | ||
399 | "channels: %u", value); | ||
400 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
401 | break; | 328 | break; |
402 | case MKVID_BitDepth: | 329 | case MKVID_BitDepth: |
403 | snprintf (buffer, | 330 | bit_depth = (unsigned int) value; |
404 | sizeof (buffer), | ||
405 | "BitDepth: %u", value); | ||
406 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
407 | break; | 331 | break; |
408 | case MKVID_OutputSamplingFrequency: /*pasthough */ | 332 | case MKVID_OutputSamplingFrequency: |
409 | case MKVID_SamplingFrequency: | 333 | case MKVID_SamplingFrequency: |
410 | /* FIXME: the resulting value seems wrong... Unit? */ | 334 | /* FIXME: what unit has 'value'? */ |
411 | snprintf (buffer, | ||
412 | sizeof (buffer), | ||
413 | "Sampling Frequency: %u", value); | ||
414 | ADD (buffer, EXTRACTOR_METATYPE_UNKNOWN); | ||
415 | break; | ||
416 | break; | 335 | break; |
417 | case MKVID_Title: | 336 | case MKVID_Title: |
418 | if (eSize > MAX_STRING_SIZE) | 337 | if (eSize > MAX_STRING_SIZE) |
419 | break; | 338 | break; |
420 | strncpy(temp,data+p,eSize); | 339 | snprintf (buffer, |
421 | temp[eSize] = '\0'; | 340 | sizeof (buffer), |
422 | ADD (temp, EXTRACTOR_METATYPE_TITLE); | 341 | "%.*s", |
342 | (int) eSize, | ||
343 | (const char*) data + p); | ||
344 | ADD (buffer, EXTRACTOR_METATYPE_TITLE); | ||
345 | break; | ||
346 | default: | ||
423 | break; | 347 | break; |
424 | /*TODO case MKVID_Tags:*/ | ||
425 | } | 348 | } |
426 | p += eSize; /*skip unknown or uninteresting */ | 349 | p += eSize; /*skip unknown or uninteresting */ |
427 | } | 350 | } |
428 | while (1); | 351 | while (1); |
352 | |||
353 | snprintf (buffer, | ||
354 | sizeof (buffer), | ||
355 | "%u s (%s%s%s)", | ||
356 | (unsigned int) (duration / 1e+9 * (float) timescale), | ||
357 | (have_audio ? "audio" : ""), | ||
358 | ((have_audio && have_video) ? "/" : ""), | ||
359 | (have_video ? "video" : "")); | ||
360 | if ( (have_audio || have_video) && (duration >= 0.0) ) | ||
361 | ADD (buffer, EXTRACTOR_METATYPE_DURATION); | ||
429 | if ( (value_width != 0) && (value_height != 0) ) | 362 | if ( (value_width != 0) && (value_height != 0) ) |
363 | { | ||
430 | snprintf (buffer, | 364 | snprintf (buffer, |
431 | sizeof(buffer), | 365 | sizeof(buffer), |
432 | "%ux%u", | 366 | "%ux%u", |
433 | value_width, value_height); | 367 | value_width, value_height); |
434 | ADD (buffer, EXTRACTOR_METATYPE_IMAGE_DIMENSIONS); | 368 | ADD (buffer, EXTRACTOR_METATYPE_IMAGE_DIMENSIONS); |
435 | 369 | } | |
436 | EXIT: | ||
437 | 370 | ||
371 | if (NULL != codec) | ||
372 | { | ||
373 | if ( (fps != 0) && (bit_depth != 0) ) | ||
374 | snprintf (buffer, | ||
375 | sizeof (buffer), | ||
376 | "%.*s (%u fps, %u bit)", | ||
377 | codec_strlen, | ||
378 | codec, | ||
379 | fps, | ||
380 | bit_depth); | ||
381 | else if (fps != 0) | ||
382 | snprintf (buffer, | ||
383 | sizeof (buffer), | ||
384 | "%.*s (%u fps)", | ||
385 | codec_strlen, | ||
386 | codec, | ||
387 | fps); | ||
388 | else if (bit_depth != 0) | ||
389 | snprintf (buffer, | ||
390 | sizeof (buffer), | ||
391 | "%.*s (%u bit)", | ||
392 | codec_strlen, | ||
393 | codec, | ||
394 | bit_depth); | ||
395 | else | ||
396 | snprintf (buffer, | ||
397 | sizeof (buffer), | ||
398 | "%.*s", | ||
399 | codec_strlen, | ||
400 | codec); | ||
401 | ADD (buffer, | ||
402 | EXTRACTOR_METATYPE_FORMAT); | ||
403 | } | ||
404 | EXIT: | ||
438 | return ret; | 405 | return ret; |
439 | |||
440 | } | 406 | } |