aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/gstreamer_extractor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/gstreamer_extractor.c')
-rw-r--r--src/plugins/gstreamer_extractor.c483
1 files changed, 253 insertions, 230 deletions
diff --git a/src/plugins/gstreamer_extractor.c b/src/plugins/gstreamer_extractor.c
index 8370f36..867fdfe 100644
--- a/src/plugins/gstreamer_extractor.c
+++ b/src/plugins/gstreamer_extractor.c
@@ -24,7 +24,6 @@
24 */ 24 */
25#include "platform.h" 25#include "platform.h"
26#include "extractor.h" 26#include "extractor.h"
27
28#include <glib.h> 27#include <glib.h>
29#include <glib-object.h> 28#include <glib-object.h>
30#include <gst/pbutils/pbutils.h> 29#include <gst/pbutils/pbutils.h>
@@ -52,6 +51,9 @@ struct KnownTag
52}; 51};
53 52
54 53
54/**
55 * Struct mapping known tags (that do occur in GST API) to LE tags.
56 */
55static struct KnownTag __known_tags[] = 57static struct KnownTag __known_tags[] =
56{ 58{
57 /** 59 /**
@@ -719,22 +721,26 @@ struct NamedTag
719}; 721};
720 722
721 723
724/**
725 * Mapping from GST tag names to LE types for tags that are not in
726 * the public GST API.
727 */
722struct NamedTag named_tags[] = 728struct NamedTag named_tags[] =
723 { 729 {
724 "FPS", EXTRACTOR_METATYPE_FRAME_RATE, 730 { "FPS", EXTRACTOR_METATYPE_FRAME_RATE },
725 "PLAY_COUNTER", EXTRACTOR_METATYPE_PLAY_COUNTER, 731 { "PLAY_COUNTER", EXTRACTOR_METATYPE_PLAY_COUNTER },
726 "RATING", EXTRACTOR_METATYPE_RATING, 732 { "RATING", EXTRACTOR_METATYPE_RATING },
727 "SUMMARY", EXTRACTOR_METATYPE_SUMMARY, 733 { "SUMMARY", EXTRACTOR_METATYPE_SUMMARY },
728 "SUBJECT", EXTRACTOR_METATYPE_SUBJECT, 734 { "SUBJECT", EXTRACTOR_METATYPE_SUBJECT },
729 "MOOD", EXTRACTOR_METATYPE_MOOD, 735 { "MOOD", EXTRACTOR_METATYPE_MOOD },
730 "LEAD_PERFORMER", EXTRACTOR_METATYPE_PERFORMER, 736 { "LEAD_PERFORMER", EXTRACTOR_METATYPE_PERFORMER },
731 "DIRECTOR", EXTRACTOR_METATYPE_MOVIE_DIRECTOR, 737 { "DIRECTOR", EXTRACTOR_METATYPE_MOVIE_DIRECTOR },
732 "WRITTEN_BY", EXTRACTOR_METATYPE_WRITER, 738 { "WRITTEN_BY", EXTRACTOR_METATYPE_WRITER },
733 "PRODUCER", EXTRACTOR_METATYPE_PRODUCER, 739 { "PRODUCER", EXTRACTOR_METATYPE_PRODUCER },
734 "PUBLISHER", EXTRACTOR_METATYPE_PUBLISHER, 740 { "PUBLISHER", EXTRACTOR_METATYPE_PUBLISHER },
735 "ORIGINAL/ARTIST", EXTRACTOR_METATYPE_ORIGINAL_ARTIST, 741 { "ORIGINAL/ARTIST", EXTRACTOR_METATYPE_ORIGINAL_ARTIST },
736 "ORIGINAL/TITLE", EXTRACTOR_METATYPE_ORIGINAL_TITLE, 742 { "ORIGINAL/TITLE", EXTRACTOR_METATYPE_ORIGINAL_TITLE },
737 NULL, EXTRACTOR_METATYPE_UNKNOWN 743 { NULL, EXTRACTOR_METATYPE_UNKNOWN }
738 }; 744 };
739 745
740 746
@@ -748,6 +754,7 @@ enum CurrentStreamType
748 STREAM_TYPE_IMAGE = 5 754 STREAM_TYPE_IMAGE = 5
749}; 755};
750 756
757
751struct PrivStruct 758struct PrivStruct
752{ 759{
753 GstElement *source; 760 GstElement *source;
@@ -763,6 +770,7 @@ struct PrivStruct
763 enum CurrentStreamType st; 770 enum CurrentStreamType st;
764}; 771};
765 772
773
766struct InitData 774struct InitData
767{ 775{
768 GMainLoop *loop; 776 GMainLoop *loop;
@@ -770,6 +778,7 @@ struct InitData
770 struct PrivStruct *ps; 778 struct PrivStruct *ps;
771}; 779};
772 780
781
773static GQuark *audio_quarks; 782static GQuark *audio_quarks;
774 783
775static GQuark *video_quarks; 784static GQuark *video_quarks;
@@ -778,107 +787,6 @@ static GQuark *subtitle_quarks;
778 787
779static GQuark duration_quark; 788static GQuark duration_quark;
780 789
781static void send_streams (GstDiscovererStreamInfo *info, struct PrivStruct *ps);
782
783static void send_tag_foreach (const GstTagList * tags, const gchar * tag,
784 gpointer user_data);
785
786static void send_discovered_info (GstDiscovererInfo * info, struct PrivStruct * ps);
787
788static void _source_setup (GstDiscoverer * dc, GstElement * source, struct PrivStruct * ps);
789
790static void feed_data (GstElement * appsrc, guint size, struct PrivStruct * ps);
791static gboolean seek_data (GstElement * appsrc, guint64 position, struct PrivStruct * ps);
792
793
794static void
795_new_discovered_uri (GstDiscoverer * dc, GstDiscovererInfo * info, GError * err, struct PrivStruct * ps)
796{
797 send_discovered_info (info, ps);
798}
799
800static void
801_discoverer_finished (GstDiscoverer * dc, struct InitData * id)
802{
803 g_main_loop_quit (id->loop);
804}
805
806static int
807initialize (struct InitData *id, struct PrivStruct *ps)
808{
809 GError *err = NULL;
810 gint timeout = 10;
811
812 gst_init (NULL, NULL);
813 GST_DEBUG_CATEGORY_INIT (gstreamer_extractor, "GstExtractor",
814 0, "GStreamer-based libextractor plugin");
815 audio_quarks = g_new0 (GQuark, 4);
816 audio_quarks[0] = g_quark_from_string ("rate");
817 audio_quarks[1] = g_quark_from_string ("channels");
818 audio_quarks[2] = g_quark_from_string ("depth");
819 audio_quarks[3] = g_quark_from_string (NULL);
820
821 video_quarks = g_new0 (GQuark, 6);
822 video_quarks[0] = g_quark_from_string ("width");
823 video_quarks[1] = g_quark_from_string ("height");
824 video_quarks[2] = g_quark_from_string ("framerate");
825 video_quarks[3] = g_quark_from_string ("max-framerate");
826 video_quarks[4] = g_quark_from_string ("pixel-aspect-ratio");
827 video_quarks[5] = g_quark_from_string (NULL);
828
829 subtitle_quarks = g_new0 (GQuark, 2);
830 subtitle_quarks[0] = g_quark_from_string ("language-code");
831 subtitle_quarks[1] = g_quark_from_string (NULL);
832
833 duration_quark = g_quark_from_string ("duration");
834
835 id->dc = gst_discoverer_new (timeout * GST_SECOND, &err);
836 if (G_UNLIKELY (id->dc == NULL)) {
837 g_print ("Error initializing: %s\n", err->message);
838 return FALSE;
839 }
840 if (err)
841 g_error_free (err);
842 /* connect signals */
843 g_signal_connect (id->dc, "discovered", G_CALLBACK (_new_discovered_uri), ps);
844 g_signal_connect (id->dc, "finished", G_CALLBACK (_discoverer_finished), id);
845 g_signal_connect (id->dc, "source-setup", G_CALLBACK (_source_setup), ps);
846
847 id->loop = g_main_loop_new (NULL, TRUE);
848
849 id->ps = ps;
850
851 return TRUE;
852}
853
854/* this callback is called when discoverer has constructed a source object to
855 * read from. Since we provided the appsrc:// uri to discoverer, this will be
856 * the appsrc that we must handle. We set up some signals - one to push data
857 * into appsrc and one to perform a seek. */
858static void
859_source_setup (GstDiscoverer * dc, GstElement * source, struct PrivStruct * ps)
860{
861 if (ps->source)
862 gst_object_unref (GST_OBJECT (ps->source));
863 ps->source = source;
864 gst_object_ref (source);
865
866 /* we can set the length in appsrc. This allows some elements to estimate the
867 * total duration of the stream. It's a good idea to set the property when you
868 * can but it's not required. */
869 if (ps->length > 0)
870 {
871 g_object_set (ps->source, "size", (gint64) ps->length, NULL);
872 gst_util_set_object_arg (G_OBJECT (ps->source), "stream-type", "random-access");
873 }
874 else
875 gst_util_set_object_arg (G_OBJECT (ps->source), "stream-type", "seekable");
876
877 /* configure the appsrc, we will push a buffer to appsrc when it needs more
878 * data */
879 g_signal_connect (ps->source, "need-data", G_CALLBACK (feed_data), ps);
880 g_signal_connect (ps->source, "seek-data", G_CALLBACK (seek_data), ps);
881}
882 790
883static void 791static void
884feed_data (GstElement * appsrc, guint size, struct PrivStruct * ps) 792feed_data (GstElement * appsrc, guint size, struct PrivStruct * ps)
@@ -945,6 +853,7 @@ feed_data (GstElement * appsrc, guint size, struct PrivStruct * ps)
945 return; 853 return;
946} 854}
947 855
856
948static gboolean 857static gboolean
949seek_data (GstElement * appsrc, guint64 position, struct PrivStruct * ps) 858seek_data (GstElement * appsrc, guint64 position, struct PrivStruct * ps)
950{ 859{
@@ -954,6 +863,7 @@ seek_data (GstElement * appsrc, guint64 position, struct PrivStruct * ps)
954 return ps->offset >= 0; 863 return ps->offset >= 0;
955} 864}
956 865
866
957static gboolean 867static gboolean
958_run_async (struct InitData * id) 868_run_async (struct InitData * id)
959{ 869{
@@ -963,8 +873,9 @@ _run_async (struct InitData * id)
963 873
964 874
965static gboolean 875static gboolean
966send_structure_foreach (GQuark field_id, const GValue *value, 876send_structure_foreach (GQuark field_id,
967 gpointer user_data) 877 const GValue *value,
878 gpointer user_data)
968{ 879{
969 struct PrivStruct *ps = user_data; 880 struct PrivStruct *ps = user_data;
970 gchar *str; 881 gchar *str;
@@ -1052,8 +963,10 @@ send_structure_foreach (GQuark field_id, const GValue *value,
1052 return !ps->time_to_leave; 963 return !ps->time_to_leave;
1053} 964}
1054 965
966
1055static int 967static int
1056send_audio_info (GstDiscovererAudioInfo *info, struct PrivStruct *ps) 968send_audio_info (GstDiscovererAudioInfo *info,
969 struct PrivStruct *ps)
1057{ 970{
1058 gchar *tmp; 971 gchar *tmp;
1059 const gchar *ctmp; 972 const gchar *ctmp;
@@ -1062,8 +975,10 @@ send_audio_info (GstDiscovererAudioInfo *info, struct PrivStruct *ps)
1062 ctmp = gst_discoverer_audio_info_get_language (info); 975 ctmp = gst_discoverer_audio_info_get_language (info);
1063 if (ctmp) 976 if (ctmp)
1064 if ((ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", 977 if ((ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
1065 EXTRACTOR_METATYPE_AUDIO_LANGUAGE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", 978 EXTRACTOR_METATYPE_AUDIO_LANGUAGE,
1066 (const char *) ctmp, strlen (ctmp) + 1))) 979 EXTRACTOR_METAFORMAT_UTF8,
980 "text/plain",
981 (const char *) ctmp, strlen (ctmp) + 1)))
1067 return TRUE; 982 return TRUE;
1068 983
1069 u = gst_discoverer_audio_info_get_channels (info); 984 u = gst_discoverer_audio_info_get_channels (info);
@@ -1129,6 +1044,7 @@ send_audio_info (GstDiscovererAudioInfo *info, struct PrivStruct *ps)
1129 return FALSE; 1044 return FALSE;
1130} 1045}
1131 1046
1047
1132static int 1048static int
1133send_video_info (GstDiscovererVideoInfo *info, struct PrivStruct *ps) 1049send_video_info (GstDiscovererVideoInfo *info, struct PrivStruct *ps)
1134{ 1050{
@@ -1215,6 +1131,7 @@ send_video_info (GstDiscovererVideoInfo *info, struct PrivStruct *ps)
1215 return FALSE; 1131 return FALSE;
1216} 1132}
1217 1133
1134
1218static int 1135static int
1219send_subtitle_info (GstDiscovererSubtitleInfo *info, struct PrivStruct *ps) 1136send_subtitle_info (GstDiscovererSubtitleInfo *info, struct PrivStruct *ps)
1220{ 1137{
@@ -1230,107 +1147,19 @@ send_subtitle_info (GstDiscovererSubtitleInfo *info, struct PrivStruct *ps)
1230 return FALSE; 1147 return FALSE;
1231} 1148}
1232 1149
1233static void
1234send_stream_info (GstDiscovererStreamInfo * info, struct PrivStruct *ps)
1235{
1236 const GstStructure *misc;
1237 GstCaps *caps;
1238 const GstTagList *tags;
1239
1240 caps = gst_discoverer_stream_info_get_caps (info);
1241
1242 if (GST_IS_DISCOVERER_AUDIO_INFO (info))
1243 ps->st = STREAM_TYPE_AUDIO;
1244 else if (GST_IS_DISCOVERER_VIDEO_INFO (info))
1245 ps->st = STREAM_TYPE_VIDEO;
1246 else if (GST_IS_DISCOVERER_SUBTITLE_INFO (info))
1247 ps->st = STREAM_TYPE_SUBTITLE;
1248 else if (GST_IS_DISCOVERER_CONTAINER_INFO (info))
1249 ps->st = STREAM_TYPE_CONTAINER;
1250
1251 if (caps)
1252 {
1253 GstStructure *structure = gst_caps_get_structure (caps, 0);
1254 const gchar *structname = gst_structure_get_name (structure);
1255 if (g_str_has_prefix (structname, "image/"))
1256 ps->st = STREAM_TYPE_IMAGE;
1257 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
1258 EXTRACTOR_METATYPE_MIMETYPE, EXTRACTOR_METAFORMAT_UTF8, "text/plain",
1259 (const char *) structname, strlen (structname) + 1);
1260 if (!ps->time_to_leave)
1261 {
1262 gst_structure_foreach (structure, send_structure_foreach, ps);
1263 }
1264 gst_caps_unref (caps);
1265 }
1266
1267 if (ps->time_to_leave)
1268 {
1269 ps->st = STREAM_TYPE_NONE;
1270 return;
1271 }
1272
1273 misc = gst_discoverer_stream_info_get_misc (info);
1274 if (misc)
1275 {
1276 gst_structure_foreach (misc, send_structure_foreach, ps);
1277 }
1278
1279 if (ps->time_to_leave)
1280 {
1281 ps->st = STREAM_TYPE_NONE;
1282 return;
1283 }
1284
1285 tags = gst_discoverer_stream_info_get_tags (info);
1286 if (tags)
1287 {
1288 gst_tag_list_foreach (tags, send_tag_foreach, ps);
1289 }
1290 ps->st = STREAM_TYPE_NONE;
1291
1292 if (ps->time_to_leave)
1293 return;
1294
1295 if (GST_IS_DISCOVERER_AUDIO_INFO (info))
1296 send_audio_info (GST_DISCOVERER_AUDIO_INFO (info), ps);
1297 else if (GST_IS_DISCOVERER_VIDEO_INFO (info))
1298 send_video_info (GST_DISCOVERER_VIDEO_INFO (info), ps);
1299 else if (GST_IS_DISCOVERER_SUBTITLE_INFO (info))
1300 send_subtitle_info (GST_DISCOVERER_SUBTITLE_INFO (info), ps);
1301 else if (GST_IS_DISCOVERER_CONTAINER_INFO (info))
1302 {
1303 GList *child;
1304 GstDiscovererContainerInfo *c = GST_DISCOVERER_CONTAINER_INFO (info);
1305 GList *children = gst_discoverer_container_info_get_streams (c);
1306 for (child = children; (NULL != child) && (!ps->time_to_leave);
1307 child = child->next)
1308 {
1309 GstDiscovererStreamInfo *sinfo = child->data;
1310 /* send_streams () will unref it */
1311 sinfo = gst_discoverer_stream_info_ref (sinfo);
1312 send_streams (sinfo, ps);
1313 }
1314 if (children)
1315 gst_discoverer_stream_info_list_free (children);
1316 }
1317}
1318
1319 1150
1320static void 1151static void
1321send_tag_foreach (const GstTagList * tags, const gchar * tag, 1152send_tag_foreach (const GstTagList * tags,
1322 gpointer user_data) 1153 const gchar * tag,
1154 gpointer user_data)
1323{ 1155{
1324 struct PrivStruct *ps = user_data; 1156 struct PrivStruct *ps = user_data;
1325 size_t i; 1157 size_t i;
1326 size_t tagl = sizeof (__known_tags) / sizeof (struct KnownTag); 1158 size_t tagl = sizeof (__known_tags) / sizeof (struct KnownTag);
1327 struct KnownTag *kt = NULL; 1159 struct KnownTag *kt = NULL;
1328 struct KnownTag unknown_tag = {NULL, EXTRACTOR_METATYPE_UNKNOWN}; 1160 struct KnownTag unknown_tag = {NULL, EXTRACTOR_METATYPE_UNKNOWN};
1329
1330
1331 GQuark tag_quark; 1161 GQuark tag_quark;
1332 guint vallen; 1162 guint vallen;
1333
1334 GstSample *sample; 1163 GstSample *sample;
1335 1164
1336 if (ps->time_to_leave) 1165 if (ps->time_to_leave)
@@ -1455,7 +1284,7 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag,
1455 str = gst_value_serialize (&val); 1284 str = gst_value_serialize (&val);
1456 break; 1285 break;
1457 } 1286 }
1458 if (str != NULL) 1287 if (NULL != str)
1459 { 1288 {
1460 /* Discoverer internally uses some tags to provide streaminfo; 1289 /* Discoverer internally uses some tags to provide streaminfo;
1461 * ignore these tags to avoid duplicates. 1290 * ignore these tags to avoid duplicates.
@@ -1579,20 +1408,128 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag,
1579 } 1408 }
1580} 1409}
1581 1410
1411
1412static void
1413send_streams (GstDiscovererStreamInfo *info,
1414 struct PrivStruct *ps);
1415
1416
1417static void
1418send_stream_info (GstDiscovererStreamInfo * info,
1419 struct PrivStruct *ps)
1420{
1421 const GstStructure *misc;
1422 GstCaps *caps;
1423 const GstTagList *tags;
1424
1425 caps = gst_discoverer_stream_info_get_caps (info);
1426
1427 if (GST_IS_DISCOVERER_AUDIO_INFO (info))
1428 ps->st = STREAM_TYPE_AUDIO;
1429 else if (GST_IS_DISCOVERER_VIDEO_INFO (info))
1430 ps->st = STREAM_TYPE_VIDEO;
1431 else if (GST_IS_DISCOVERER_SUBTITLE_INFO (info))
1432 ps->st = STREAM_TYPE_SUBTITLE;
1433 else if (GST_IS_DISCOVERER_CONTAINER_INFO (info))
1434 ps->st = STREAM_TYPE_CONTAINER;
1435
1436 if (caps)
1437 {
1438 GstStructure *structure = gst_caps_get_structure (caps, 0);
1439 const gchar *structname = gst_structure_get_name (structure);
1440 if (g_str_has_prefix (structname, "image/"))
1441 ps->st = STREAM_TYPE_IMAGE;
1442 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
1443 EXTRACTOR_METATYPE_MIMETYPE, EXTRACTOR_METAFORMAT_UTF8, "text/plain",
1444 (const char *) structname, strlen (structname) + 1);
1445 if (!ps->time_to_leave)
1446 {
1447 gst_structure_foreach (structure, send_structure_foreach, ps);
1448 }
1449 gst_caps_unref (caps);
1450 }
1451
1452 if (ps->time_to_leave)
1453 {
1454 ps->st = STREAM_TYPE_NONE;
1455 return;
1456 }
1457
1458 misc = gst_discoverer_stream_info_get_misc (info);
1459 if (misc)
1460 {
1461 gst_structure_foreach (misc, send_structure_foreach, ps);
1462 }
1463
1464 if (ps->time_to_leave)
1465 {
1466 ps->st = STREAM_TYPE_NONE;
1467 return;
1468 }
1469
1470 tags = gst_discoverer_stream_info_get_tags (info);
1471 if (tags)
1472 {
1473 gst_tag_list_foreach (tags, send_tag_foreach, ps);
1474 }
1475 ps->st = STREAM_TYPE_NONE;
1476
1477 if (ps->time_to_leave)
1478 return;
1479
1480 if (GST_IS_DISCOVERER_AUDIO_INFO (info))
1481 send_audio_info (GST_DISCOVERER_AUDIO_INFO (info), ps);
1482 else if (GST_IS_DISCOVERER_VIDEO_INFO (info))
1483 send_video_info (GST_DISCOVERER_VIDEO_INFO (info), ps);
1484 else if (GST_IS_DISCOVERER_SUBTITLE_INFO (info))
1485 send_subtitle_info (GST_DISCOVERER_SUBTITLE_INFO (info), ps);
1486 else if (GST_IS_DISCOVERER_CONTAINER_INFO (info))
1487 {
1488 GList *child;
1489 GstDiscovererContainerInfo *c = GST_DISCOVERER_CONTAINER_INFO (info);
1490 GList *children = gst_discoverer_container_info_get_streams (c);
1491 for (child = children; (NULL != child) && (!ps->time_to_leave);
1492 child = child->next)
1493 {
1494 GstDiscovererStreamInfo *sinfo = child->data;
1495 /* send_streams () will unref it */
1496 sinfo = gst_discoverer_stream_info_ref (sinfo);
1497 send_streams (sinfo, ps);
1498 }
1499 if (children)
1500 gst_discoverer_stream_info_list_free (children);
1501 }
1502}
1503
1504
1582static void 1505static void
1583send_toc_tags_foreach (const GstTagList * tags, const gchar * tag, 1506send_streams (GstDiscovererStreamInfo *info, struct PrivStruct *ps)
1584 gpointer user_data) 1507{
1508 while ( (NULL != info) && (! ps->time_to_leave) )
1509 {
1510 GstDiscovererStreamInfo *next;
1511
1512 send_stream_info (info, ps);
1513 next = gst_discoverer_stream_info_get_next (info);
1514 gst_discoverer_stream_info_unref (info);
1515 info = next;
1516 }
1517}
1518
1519
1520static void
1521send_toc_tags_foreach (const GstTagList * tags,
1522 const gchar * tag,
1523 gpointer user_data)
1585{ 1524{
1586 struct PrivStruct *ps = user_data; 1525 struct PrivStruct *ps = user_data;
1587 GValue val = { 0, }; 1526 GValue val = { 0 };
1588 gchar *topen, *str, *tclose; 1527 gchar *topen, *str, *tclose;
1589 const gchar *type_name; 1528 const gchar *type_name;
1590 GType gst_fraction = GST_TYPE_FRACTION; 1529 GType gst_fraction = GST_TYPE_FRACTION;
1591 1530
1592 gst_tag_list_copy_value (&val, tags, tag); 1531 gst_tag_list_copy_value (&val, tags, tag);
1593
1594 type_name = g_type_name (G_VALUE_TYPE (&val)); 1532 type_name = g_type_name (G_VALUE_TYPE (&val));
1595
1596 switch (G_VALUE_TYPE (&val)) 1533 switch (G_VALUE_TYPE (&val))
1597 { 1534 {
1598 case G_TYPE_STRING: 1535 case G_TYPE_STRING:
@@ -1651,6 +1588,7 @@ send_toc_foreach (gpointer data, gpointer user_data)
1651 if (GST_TOC_ENTRY_TYPE_INVALID != entype) 1588 if (GST_TOC_ENTRY_TYPE_INVALID != entype)
1652 { 1589 {
1653 char *s; 1590 char *s;
1591
1654 gst_toc_entry_get_start_stop_times (entry, &start, &stop); 1592 gst_toc_entry_get_start_stop_times (entry, &start, &stop);
1655 s = g_strdup_printf ("%*.*s<%s start=\"%" GST_TIME_FORMAT "\" stop=\"%" 1593 s = g_strdup_printf ("%*.*s<%s start=\"%" GST_TIME_FORMAT "\" stop=\"%"
1656 GST_TIME_FORMAT"\">\n", ps->toc_depth * 2, ps->toc_depth * 2, " ", 1594 GST_TIME_FORMAT"\">\n", ps->toc_depth * 2, ps->toc_depth * 2, " ",
@@ -1694,21 +1632,10 @@ send_toc_foreach (gpointer data, gpointer user_data)
1694 } 1632 }
1695} 1633}
1696 1634
1697static void
1698send_streams (GstDiscovererStreamInfo *info, struct PrivStruct *ps)
1699{
1700 while (NULL != info && !ps->time_to_leave)
1701 {
1702 GstDiscovererStreamInfo *next;
1703 send_stream_info (info, ps);
1704 next = gst_discoverer_stream_info_get_next (info);
1705 gst_discoverer_stream_info_unref (info);
1706 info = next;
1707 }
1708}
1709 1635
1710#define TOC_XML_HEADER "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" 1636#define TOC_XML_HEADER "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
1711 1637
1638
1712static void 1639static void
1713send_info (GstDiscovererInfo * info, struct PrivStruct *ps) 1640send_info (GstDiscovererInfo * info, struct PrivStruct *ps)
1714{ 1641{
@@ -1774,6 +1701,7 @@ send_info (GstDiscovererInfo * info, struct PrivStruct *ps)
1774 send_streams (sinfo, ps); 1701 send_streams (sinfo, ps);
1775} 1702}
1776 1703
1704
1777static void 1705static void
1778send_discovered_info (GstDiscovererInfo * info, struct PrivStruct * ps) 1706send_discovered_info (GstDiscovererInfo * info, struct PrivStruct * ps)
1779{ 1707{
@@ -1803,6 +1731,101 @@ send_discovered_info (GstDiscovererInfo * info, struct PrivStruct * ps)
1803} 1731}
1804 1732
1805 1733
1734static void
1735_new_discovered_uri (GstDiscoverer * dc, GstDiscovererInfo * info, GError * err, struct PrivStruct * ps)
1736{
1737 send_discovered_info (info, ps);
1738}
1739
1740
1741static void
1742_discoverer_finished (GstDiscoverer * dc, struct InitData * id)
1743{
1744 g_main_loop_quit (id->loop);
1745}
1746
1747
1748/**
1749 * This callback is called when discoverer has constructed a source object to
1750 * read from. Since we provided the appsrc:// uri to discoverer, this will be
1751 * the appsrc that we must handle. We set up some signals - one to push data
1752 * into appsrc and one to perform a seek. */
1753static void
1754_source_setup (GstDiscoverer * dc, GstElement * source, struct PrivStruct * ps)
1755{
1756 if (ps->source)
1757 gst_object_unref (GST_OBJECT (ps->source));
1758 ps->source = source;
1759 gst_object_ref (source);
1760
1761 /* we can set the length in appsrc. This allows some elements to estimate the
1762 * total duration of the stream. It's a good idea to set the property when you
1763 * can but it's not required. */
1764 if (ps->length > 0)
1765 {
1766 g_object_set (ps->source, "size", (gint64) ps->length, NULL);
1767 gst_util_set_object_arg (G_OBJECT (ps->source), "stream-type", "random-access");
1768 }
1769 else
1770 gst_util_set_object_arg (G_OBJECT (ps->source), "stream-type", "seekable");
1771
1772 /* configure the appsrc, we will push a buffer to appsrc when it needs more
1773 * data */
1774 g_signal_connect (ps->source, "need-data", G_CALLBACK (feed_data), ps);
1775 g_signal_connect (ps->source, "seek-data", G_CALLBACK (seek_data), ps);
1776}
1777
1778
1779static int
1780initialize (struct InitData *id, struct PrivStruct *ps)
1781{
1782 GError *err = NULL;
1783 gint timeout = 10;
1784
1785 gst_init (NULL, NULL);
1786 GST_DEBUG_CATEGORY_INIT (gstreamer_extractor, "GstExtractor",
1787 0, "GStreamer-based libextractor plugin");
1788 audio_quarks = g_new0 (GQuark, 4);
1789 audio_quarks[0] = g_quark_from_string ("rate");
1790 audio_quarks[1] = g_quark_from_string ("channels");
1791 audio_quarks[2] = g_quark_from_string ("depth");
1792 audio_quarks[3] = g_quark_from_string (NULL);
1793
1794 video_quarks = g_new0 (GQuark, 6);
1795 video_quarks[0] = g_quark_from_string ("width");
1796 video_quarks[1] = g_quark_from_string ("height");
1797 video_quarks[2] = g_quark_from_string ("framerate");
1798 video_quarks[3] = g_quark_from_string ("max-framerate");
1799 video_quarks[4] = g_quark_from_string ("pixel-aspect-ratio");
1800 video_quarks[5] = g_quark_from_string (NULL);
1801
1802 subtitle_quarks = g_new0 (GQuark, 2);
1803 subtitle_quarks[0] = g_quark_from_string ("language-code");
1804 subtitle_quarks[1] = g_quark_from_string (NULL);
1805
1806 duration_quark = g_quark_from_string ("duration");
1807
1808 id->dc = gst_discoverer_new (timeout * GST_SECOND, &err);
1809 if (NULL == id->dc)
1810 {
1811 g_print ("Error initializing: %s\n", err->message);
1812 return FALSE;
1813 }
1814 if (err)
1815 g_error_free (err);
1816 /* connect signals */
1817 g_signal_connect (id->dc, "discovered", G_CALLBACK (_new_discovered_uri), ps);
1818 g_signal_connect (id->dc, "finished", G_CALLBACK (_discoverer_finished), id);
1819 g_signal_connect (id->dc, "source-setup", G_CALLBACK (_source_setup), ps);
1820
1821 id->loop = g_main_loop_new (NULL, TRUE);
1822
1823 id->ps = ps;
1824
1825 return TRUE;
1826}
1827
1828
1806/** 1829/**
1807 * This will be the main method of your plugin. 1830 * This will be the main method of your plugin.
1808 * Describe a bit what it does here. 1831 * Describe a bit what it does here.