diff options
-rw-r--r-- | src/include/extractor.h | 7 | ||||
-rw-r--r-- | src/main/extractor_metatypes.c | 7 | ||||
-rw-r--r-- | src/plugins/gstreamer_extractor.c | 70 | ||||
-rw-r--r-- | src/plugins/test_gstreamer.c | 197 |
4 files changed, 272 insertions, 9 deletions
diff --git a/src/include/extractor.h b/src/include/extractor.h index 1102247..b5f3d87 100644 --- a/src/include/extractor.h +++ b/src/include/extractor.h | |||
@@ -377,7 +377,12 @@ enum EXTRACTOR_MetaType | |||
377 | EXTRACTOR_METATYPE_VIDEO_LANGUAGE = 223, | 377 | EXTRACTOR_METATYPE_VIDEO_LANGUAGE = 223, |
378 | 378 | ||
379 | EXTRACTOR_METATYPE_TOC = 224, | 379 | EXTRACTOR_METATYPE_TOC = 224, |
380 | EXTRACTOR_METATYPE_LAST = 225 | 380 | |
381 | EXTRACTOR_METATYPE_VIDEO_DURATION = 225, | ||
382 | EXTRACTOR_METATYPE_AUDIO_DURATION = 226, | ||
383 | EXTRACTOR_METATYPE_SUBTITLE_DURATION = 227, | ||
384 | |||
385 | EXTRACTOR_METATYPE_LAST = 228 | ||
381 | }; | 386 | }; |
382 | 387 | ||
383 | 388 | ||
diff --git a/src/main/extractor_metatypes.c b/src/main/extractor_metatypes.c index 979e210..571ab06 100644 --- a/src/main/extractor_metatypes.c +++ b/src/main/extractor_metatypes.c | |||
@@ -541,6 +541,13 @@ static const struct MetaTypeDescription meta_type_descriptions[] = { | |||
541 | { gettext_noop ("table of contents"), | 541 | { gettext_noop ("table of contents"), |
542 | gettext_noop ("chapters, contents or bookmarks (in xml format)") }, | 542 | gettext_noop ("chapters, contents or bookmarks (in xml format)") }, |
543 | /* 225 */ | 543 | /* 225 */ |
544 | { gettext_noop ("video duration"), | ||
545 | gettext_noop ("duration of a video stream") }, | ||
546 | { gettext_noop ("audio duration"), | ||
547 | gettext_noop ("duration of an audio stream") }, | ||
548 | { gettext_noop ("subtitle duration"), | ||
549 | gettext_noop ("duration of a subtitle stream") }, | ||
550 | |||
544 | { gettext_noop ("last"), | 551 | { gettext_noop ("last"), |
545 | gettext_noop ("last") } | 552 | gettext_noop ("last") } |
546 | }; | 553 | }; |
diff --git a/src/plugins/gstreamer_extractor.c b/src/plugins/gstreamer_extractor.c index cb314cf..162ae09 100644 --- a/src/plugins/gstreamer_extractor.c +++ b/src/plugins/gstreamer_extractor.c | |||
@@ -647,6 +647,7 @@ static GQuark *video_quarks; | |||
647 | 647 | ||
648 | static GQuark *subtitle_quarks; | 648 | static GQuark *subtitle_quarks; |
649 | 649 | ||
650 | static GQuark duration_quark; | ||
650 | 651 | ||
651 | static void send_streams (GstDiscovererStreamInfo *info, struct PrivStruct *ps); | 652 | static void send_streams (GstDiscovererStreamInfo *info, struct PrivStruct *ps); |
652 | 653 | ||
@@ -700,6 +701,8 @@ initialize (struct InitData *id, struct PrivStruct *ps) | |||
700 | subtitle_quarks[0] = g_quark_from_string ("language-code"); | 701 | subtitle_quarks[0] = g_quark_from_string ("language-code"); |
701 | subtitle_quarks[1] = g_quark_from_string (NULL); | 702 | subtitle_quarks[1] = g_quark_from_string (NULL); |
702 | 703 | ||
704 | duration_quark = g_quark_from_string ("duration"); | ||
705 | |||
703 | id->dc = gst_discoverer_new (timeout * GST_SECOND, &err); | 706 | id->dc = gst_discoverer_new (timeout * GST_SECOND, &err); |
704 | if (G_UNLIKELY (id->dc == NULL)) { | 707 | if (G_UNLIKELY (id->dc == NULL)) { |
705 | g_print ("Error initializing: %s\n", err->message); | 708 | g_print ("Error initializing: %s\n", err->message); |
@@ -1155,16 +1158,19 @@ send_stream_info (GstDiscovererStreamInfo * info, struct PrivStruct *ps) | |||
1155 | send_subtitle_info (GST_DISCOVERER_SUBTITLE_INFO (info), ps); | 1158 | send_subtitle_info (GST_DISCOVERER_SUBTITLE_INFO (info), ps); |
1156 | else if (GST_IS_DISCOVERER_CONTAINER_INFO (info)) | 1159 | else if (GST_IS_DISCOVERER_CONTAINER_INFO (info)) |
1157 | { | 1160 | { |
1161 | GList *child; | ||
1158 | GstDiscovererContainerInfo *c = GST_DISCOVERER_CONTAINER_INFO (info); | 1162 | GstDiscovererContainerInfo *c = GST_DISCOVERER_CONTAINER_INFO (info); |
1159 | GList *children = gst_discoverer_container_info_get_streams (c); | 1163 | GList *children = gst_discoverer_container_info_get_streams (c); |
1160 | if (children) | 1164 | for (child = children; (NULL != child) && (!ps->time_to_leave); |
1165 | child = child->next) | ||
1161 | { | 1166 | { |
1162 | GstDiscovererStreamInfo *sinfo = children->data; | 1167 | GstDiscovererStreamInfo *sinfo = child->data; |
1163 | /* send_streams () will unref it */ | 1168 | /* send_streams () will unref it */ |
1164 | gst_discoverer_stream_info_ref (sinfo); | 1169 | gst_discoverer_stream_info_ref (sinfo); |
1165 | send_streams (sinfo, ps); | 1170 | send_streams (sinfo, ps); |
1166 | gst_discoverer_stream_info_list_free (children); | ||
1167 | } | 1171 | } |
1172 | if (children) | ||
1173 | gst_discoverer_stream_info_list_free (children); | ||
1168 | } | 1174 | } |
1169 | } | 1175 | } |
1170 | 1176 | ||
@@ -1177,9 +1183,12 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, | |||
1177 | size_t i; | 1183 | size_t i; |
1178 | size_t tagl = sizeof (__known_tags) / sizeof (struct KnownTag); | 1184 | size_t tagl = sizeof (__known_tags) / sizeof (struct KnownTag); |
1179 | struct KnownTag *kt = NULL; | 1185 | struct KnownTag *kt = NULL; |
1186 | struct KnownTag unknown_tag = {NULL, EXTRACTOR_METATYPE_UNKNOWN}; | ||
1187 | |||
1180 | 1188 | ||
1181 | GValue val = { 0, }; | 1189 | GValue val = { 0, }; |
1182 | gchar *str; | 1190 | gchar *str = NULL; |
1191 | GQuark tag_quark; | ||
1183 | 1192 | ||
1184 | GstSample *sample; | 1193 | GstSample *sample; |
1185 | 1194 | ||
@@ -1194,10 +1203,12 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, | |||
1194 | break; | 1203 | break; |
1195 | } | 1204 | } |
1196 | if (kt == NULL) | 1205 | if (kt == NULL) |
1197 | return; | 1206 | kt = &unknown_tag; |
1198 | 1207 | ||
1199 | gst_tag_list_copy_value (&val, tags, tag); | 1208 | gst_tag_list_copy_value (&val, tags, tag); |
1200 | 1209 | ||
1210 | tag_quark = g_quark_from_string (tag); | ||
1211 | |||
1201 | switch (G_VALUE_TYPE (&val)) | 1212 | switch (G_VALUE_TYPE (&val)) |
1202 | { | 1213 | { |
1203 | case G_TYPE_STRING: | 1214 | case G_TYPE_STRING: |
@@ -1276,6 +1287,13 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, | |||
1276 | gst_buffer_unmap (buf, &mi); | 1287 | gst_buffer_unmap (buf, &mi); |
1277 | } | 1288 | } |
1278 | } | 1289 | } |
1290 | else if ((G_VALUE_TYPE (&val) == G_TYPE_UINT64) && | ||
1291 | (tag_quark == duration_quark)) | ||
1292 | { | ||
1293 | GstClockTime duration = (GstClockTime) g_value_get_uint64 (&val); | ||
1294 | if ((GST_CLOCK_TIME_IS_VALID (duration)) && (duration > 0)) | ||
1295 | str = g_strdup_printf ("%" GST_TIME_FORMAT, GST_TIME_ARGS (duration)); | ||
1296 | } | ||
1279 | else | 1297 | else |
1280 | str = gst_value_serialize (&val); | 1298 | str = gst_value_serialize (&val); |
1281 | break; | 1299 | break; |
@@ -1338,6 +1356,19 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, | |||
1338 | break; | 1356 | break; |
1339 | } | 1357 | } |
1340 | break; | 1358 | break; |
1359 | case EXTRACTOR_METATYPE_NOMINAL_BITRATE: | ||
1360 | switch (ps->st) | ||
1361 | { | ||
1362 | case STREAM_TYPE_AUDIO: | ||
1363 | skip = TRUE; | ||
1364 | break; | ||
1365 | case STREAM_TYPE_VIDEO: | ||
1366 | skip = TRUE; | ||
1367 | break; | ||
1368 | default: | ||
1369 | break; | ||
1370 | } | ||
1371 | break; | ||
1341 | case EXTRACTOR_METATYPE_IMAGE_DIMENSIONS: | 1372 | case EXTRACTOR_METATYPE_IMAGE_DIMENSIONS: |
1342 | switch (ps->st) | 1373 | switch (ps->st) |
1343 | { | 1374 | { |
@@ -1348,6 +1379,30 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, | |||
1348 | break; | 1379 | break; |
1349 | } | 1380 | } |
1350 | break; | 1381 | break; |
1382 | case EXTRACTOR_METATYPE_DURATION: | ||
1383 | switch (ps->st) | ||
1384 | { | ||
1385 | case STREAM_TYPE_VIDEO: | ||
1386 | le_type = EXTRACTOR_METATYPE_VIDEO_DURATION; | ||
1387 | break; | ||
1388 | case STREAM_TYPE_AUDIO: | ||
1389 | le_type = EXTRACTOR_METATYPE_AUDIO_DURATION; | ||
1390 | break; | ||
1391 | case STREAM_TYPE_SUBTITLE: | ||
1392 | le_type = EXTRACTOR_METATYPE_SUBTITLE_DURATION; | ||
1393 | break; | ||
1394 | default: | ||
1395 | break; | ||
1396 | } | ||
1397 | break; | ||
1398 | case EXTRACTOR_METATYPE_UNKNOWN: | ||
1399 | /* Convert to "key=value" form */ | ||
1400 | { | ||
1401 | gchar *new_str = g_strdup_printf ("%s=%s", tag, str); | ||
1402 | g_free (str); | ||
1403 | str = new_str; | ||
1404 | } | ||
1405 | break; | ||
1351 | default: | 1406 | default: |
1352 | break; | 1407 | break; |
1353 | } | 1408 | } |
@@ -1501,10 +1556,9 @@ send_info (GstDiscovererInfo * info, struct PrivStruct *ps) | |||
1501 | GstClockTime duration; | 1556 | GstClockTime duration; |
1502 | 1557 | ||
1503 | duration = gst_discoverer_info_get_duration (info); | 1558 | duration = gst_discoverer_info_get_duration (info); |
1504 | if (duration > 0) | 1559 | if ((GST_CLOCK_TIME_IS_VALID (duration)) && (duration > 0)) |
1505 | { | 1560 | { |
1506 | s = g_strdup_printf ("%" GST_TIME_FORMAT, | 1561 | s = g_strdup_printf ("%" GST_TIME_FORMAT, GST_TIME_ARGS (duration)); |
1507 | GST_TIME_ARGS (gst_discoverer_info_get_duration (info))); | ||
1508 | if (s) | 1562 | if (s) |
1509 | ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", | 1563 | ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", |
1510 | EXTRACTOR_METATYPE_DURATION, EXTRACTOR_METAFORMAT_UTF8, "text/plain", | 1564 | EXTRACTOR_METATYPE_DURATION, EXTRACTOR_METAFORMAT_UTF8, "text/plain", |
diff --git a/src/plugins/test_gstreamer.c b/src/plugins/test_gstreamer.c index 4f9fdd4..c6d9611 100644 --- a/src/plugins/test_gstreamer.c +++ b/src/plugins/test_gstreamer.c | |||
@@ -302,6 +302,203 @@ main (int argc, char *argv[]) | |||
302 | }; | 302 | }; |
303 | result += (0 == ET_main ("gstreamer", ps) ? 0 : 1); | 303 | result += (0 == ET_main ("gstreamer", ps) ? 0 : 1); |
304 | } | 304 | } |
305 | |||
306 | pre_test = discoverer_main (dc, "testdata/barsandtone.flv"); | ||
307 | if (pre_test != GST_DISCOVERER_MISSING_PLUGINS) | ||
308 | { | ||
309 | struct SolutionData barsandtone_sol[] = | ||
310 | { | ||
311 | { | ||
312 | EXTRACTOR_METATYPE_DURATION, | ||
313 | EXTRACTOR_METAFORMAT_UTF8, | ||
314 | "text/plain", | ||
315 | "0:00:06.060000000", | ||
316 | strlen ("0:00:06.060000000") + 1, | ||
317 | 0 | ||
318 | }, | ||
319 | { | ||
320 | EXTRACTOR_METATYPE_MIMETYPE, | ||
321 | EXTRACTOR_METAFORMAT_UTF8, | ||
322 | "text/plain", | ||
323 | "video/x-flv", | ||
324 | strlen ("video/x-flv") + 1, | ||
325 | 0 | ||
326 | }, | ||
327 | { | ||
328 | EXTRACTOR_METATYPE_MIMETYPE, | ||
329 | EXTRACTOR_METAFORMAT_UTF8, | ||
330 | "text/plain", | ||
331 | "video/x-vp6-flash", | ||
332 | strlen ("video/x-vp6-flash") + 1, | ||
333 | 0 | ||
334 | }, | ||
335 | { | ||
336 | EXTRACTOR_METATYPE_VIDEO_DURATION, | ||
337 | EXTRACTOR_METAFORMAT_UTF8, | ||
338 | "text/plain", | ||
339 | "0:00:06.000000000", | ||
340 | strlen ("0:00:06.000000000") + 1, | ||
341 | 0 | ||
342 | }, | ||
343 | { | ||
344 | EXTRACTOR_METATYPE_AUDIO_CODEC, | ||
345 | EXTRACTOR_METAFORMAT_UTF8, | ||
346 | "text/plain", | ||
347 | "MPEG-1 Layer 3 (MP3)", | ||
348 | strlen ("MPEG-1 Layer 3 (MP3)") + 1, | ||
349 | 0 | ||
350 | }, | ||
351 | { | ||
352 | EXTRACTOR_METATYPE_VIDEO_CODEC, | ||
353 | EXTRACTOR_METAFORMAT_UTF8, | ||
354 | "text/plain", | ||
355 | "On2 VP6/Flash", | ||
356 | strlen ("On2 VP6/Flash") + 1, | ||
357 | 0 | ||
358 | }, | ||
359 | { | ||
360 | EXTRACTOR_METATYPE_VIDEO_DIMENSIONS, | ||
361 | EXTRACTOR_METAFORMAT_UTF8, | ||
362 | "text/plain", | ||
363 | "368x288", | ||
364 | strlen ("368x288") + 1, | ||
365 | 0 | ||
366 | }, | ||
367 | { | ||
368 | EXTRACTOR_METATYPE_FRAME_RATE, | ||
369 | EXTRACTOR_METAFORMAT_UTF8, | ||
370 | "text/plain", | ||
371 | "10/1", | ||
372 | strlen ("10/1") + 1, | ||
373 | 0 | ||
374 | }, | ||
375 | { | ||
376 | EXTRACTOR_METATYPE_PIXEL_ASPECT_RATIO, | ||
377 | EXTRACTOR_METAFORMAT_UTF8, | ||
378 | "text/plain", | ||
379 | "1/1", | ||
380 | strlen ("1/1") + 1, | ||
381 | 0 | ||
382 | }, | ||
383 | { | ||
384 | EXTRACTOR_METATYPE_MIMETYPE, | ||
385 | EXTRACTOR_METAFORMAT_UTF8, | ||
386 | "text/plain", | ||
387 | "audio/mpeg", | ||
388 | strlen ("audio/mpeg") + 1, | ||
389 | 0 | ||
390 | }, | ||
391 | { | ||
392 | EXTRACTOR_METATYPE_UNKNOWN, | ||
393 | EXTRACTOR_METAFORMAT_UTF8, | ||
394 | "text/plain", | ||
395 | "mpegversion=1", | ||
396 | strlen ("mpegversion=1") + 1, | ||
397 | 0 | ||
398 | }, | ||
399 | { | ||
400 | EXTRACTOR_METATYPE_UNKNOWN, | ||
401 | EXTRACTOR_METAFORMAT_UTF8, | ||
402 | "text/plain", | ||
403 | "mpegaudioversion=1", | ||
404 | strlen ("mpegaudioversion=1") + 1, | ||
405 | 0 | ||
406 | }, | ||
407 | { | ||
408 | EXTRACTOR_METATYPE_UNKNOWN, | ||
409 | EXTRACTOR_METAFORMAT_UTF8, | ||
410 | "text/plain", | ||
411 | "layer=3", | ||
412 | strlen ("layer=3") + 1, | ||
413 | 0 | ||
414 | }, | ||
415 | { | ||
416 | EXTRACTOR_METATYPE_UNKNOWN, | ||
417 | EXTRACTOR_METAFORMAT_UTF8, | ||
418 | "text/plain", | ||
419 | "parsed=true", | ||
420 | strlen ("parsed=true") + 1, | ||
421 | 0 | ||
422 | }, | ||
423 | { | ||
424 | EXTRACTOR_METATYPE_AUDIO_DURATION, | ||
425 | EXTRACTOR_METAFORMAT_UTF8, | ||
426 | "text/plain", | ||
427 | "0:00:06.000000000", | ||
428 | strlen ("0:00:06.000000000") + 1, | ||
429 | 0 | ||
430 | }, | ||
431 | /* Yes, again. This seems to be a bug/feature of the element that | ||
432 | * gives us these streams; this doesn't happen when discovering | ||
433 | * Matroska files, for example. Or maybe file itself is made that way. | ||
434 | */ | ||
435 | { | ||
436 | EXTRACTOR_METATYPE_AUDIO_CODEC, | ||
437 | EXTRACTOR_METAFORMAT_UTF8, | ||
438 | "text/plain", | ||
439 | "MPEG-1 Layer 3 (MP3)", | ||
440 | strlen ("MPEG-1 Layer 3 (MP3)") + 1, | ||
441 | 0 | ||
442 | }, | ||
443 | { | ||
444 | EXTRACTOR_METATYPE_VIDEO_CODEC, | ||
445 | EXTRACTOR_METAFORMAT_UTF8, | ||
446 | "text/plain", | ||
447 | "On2 VP6/Flash", | ||
448 | strlen ("On2 VP6/Flash") + 1, | ||
449 | 0 | ||
450 | }, | ||
451 | { | ||
452 | EXTRACTOR_METATYPE_UNKNOWN, | ||
453 | EXTRACTOR_METAFORMAT_UTF8, | ||
454 | "text/plain", | ||
455 | "has-crc=false", | ||
456 | strlen ("has-crc=false") + 1, | ||
457 | 0 | ||
458 | }, | ||
459 | { | ||
460 | EXTRACTOR_METATYPE_UNKNOWN, | ||
461 | EXTRACTOR_METAFORMAT_UTF8, | ||
462 | "text/plain", | ||
463 | "channel-mode=joint-stereo", | ||
464 | strlen ("channel-mode=joint-stereo") + 1, | ||
465 | 0 | ||
466 | }, | ||
467 | { | ||
468 | EXTRACTOR_METATYPE_CHANNELS, | ||
469 | EXTRACTOR_METAFORMAT_UTF8, | ||
470 | "text/plain", | ||
471 | "2", | ||
472 | strlen ("2") + 1, | ||
473 | 0 | ||
474 | }, | ||
475 | { | ||
476 | EXTRACTOR_METATYPE_SAMPLE_RATE, | ||
477 | EXTRACTOR_METAFORMAT_UTF8, | ||
478 | "text/plain", | ||
479 | "44100", | ||
480 | strlen ("44100") + 1, | ||
481 | 0 | ||
482 | }, | ||
483 | { | ||
484 | EXTRACTOR_METATYPE_AUDIO_BITRATE, | ||
485 | EXTRACTOR_METAFORMAT_UTF8, | ||
486 | "text/plain", | ||
487 | "96000", | ||
488 | strlen ("96000") + 1, | ||
489 | 0 | ||
490 | }, | ||
491 | { 0, 0, NULL, NULL, 0, -1 } | ||
492 | }; | ||
493 | struct ProblemSet ps[] = | ||
494 | { | ||
495 | { "testdata/barsandtone.flv", | ||
496 | barsandtone_sol }, | ||
497 | { NULL, NULL } | ||
498 | }; | ||
499 | result += (0 == ET_main ("gstreamer", ps) ? 0 : 1); | ||
500 | } | ||
501 | |||
305 | g_object_unref (dc); | 502 | g_object_unref (dc); |
306 | return result; | 503 | return result; |
307 | } | 504 | } |