diff options
Diffstat (limited to 'src/plugins/mkv_extractor.c')
-rw-r--r-- | src/plugins/mkv_extractor.c | 267 |
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 |
36 | typedef long long int64; | 47 | |
48 | /** | ||
49 | * FIXME: document | ||
50 | */ | ||
37 | enum | 51 | enum |
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 | */ | ||
44 | enum | 62 | enum |
45 | { | 63 | { |
46 | MKVID_OutputSamplingFrequency = 0x78B5, | 64 | MKVID_OutputSamplingFrequency = 0x78B5, |
@@ -73,103 +91,113 @@ enum | |||
73 | }; | 91 | }; |
74 | 92 | ||
75 | 93 | ||
76 | static int | 94 | /** |
77 | VINTparse (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 | */ | ||
99 | static size_t | ||
100 | VINTparse (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 | */ | ||
120 | static int | 141 | static int |
121 | elementRead (const char *buffer, const int start, const int end, | 142 | elementRead (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 | ||
141 | static int64 | 163 | |
142 | getInt (const char *buffer, const int start, const int size) | 164 | /** |
165 | * FIXME: signed or unsigned return value? | ||
166 | */ | ||
167 | static int64_t | ||
168 | getInt (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 | ||
155 | static float | 180 | static float |
156 | getFloat (const char *buffer, const int start, const int size) | 181 | getFloat (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 | ||
172 | const unsigned int MKV_Parse_list[] = { /*Elements, containing requed information (sub-elements), see enum in mkv.h for values */ | 199 | static 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 | ||
181 | const char stream_type_letters[] = "?vat"; /*[0]-no, [1]-video,[2]-audio,[3]-text */ | 209 | static const char stream_type_letters[] = "?vat"; /*[0]-no, [1]-video,[2]-audio,[3]-text */ |
182 | 210 | ||
183 | 211 | ||
184 | /* video/mkv */ | 212 | /* video/mkv */ |
185 | int | 213 | int |
186 | EXTRACTOR_mkv_extract (const unsigned char *data, size_t size1, | 214 | EXTRACTOR_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 | ||
385 | EXIT: | 436 | EXIT: |
386 | 437 | ||