diff options
Diffstat (limited to 'src/plugins/gstreamer_extractor.c')
-rw-r--r-- | src/plugins/gstreamer_extractor.c | 483 |
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 | */ | ||
55 | static struct KnownTag __known_tags[] = | 57 | static 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 | */ | ||
722 | struct NamedTag named_tags[] = | 728 | struct 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 | |||
751 | struct PrivStruct | 758 | struct 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 | |||
766 | struct InitData | 774 | struct 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 | |||
773 | static GQuark *audio_quarks; | 782 | static GQuark *audio_quarks; |
774 | 783 | ||
775 | static GQuark *video_quarks; | 784 | static GQuark *video_quarks; |
@@ -778,107 +787,6 @@ static GQuark *subtitle_quarks; | |||
778 | 787 | ||
779 | static GQuark duration_quark; | 788 | static GQuark duration_quark; |
780 | 789 | ||
781 | static void send_streams (GstDiscovererStreamInfo *info, struct PrivStruct *ps); | ||
782 | |||
783 | static void send_tag_foreach (const GstTagList * tags, const gchar * tag, | ||
784 | gpointer user_data); | ||
785 | |||
786 | static void send_discovered_info (GstDiscovererInfo * info, struct PrivStruct * ps); | ||
787 | |||
788 | static void _source_setup (GstDiscoverer * dc, GstElement * source, struct PrivStruct * ps); | ||
789 | |||
790 | static void feed_data (GstElement * appsrc, guint size, struct PrivStruct * ps); | ||
791 | static gboolean seek_data (GstElement * appsrc, guint64 position, struct PrivStruct * ps); | ||
792 | |||
793 | |||
794 | static void | ||
795 | _new_discovered_uri (GstDiscoverer * dc, GstDiscovererInfo * info, GError * err, struct PrivStruct * ps) | ||
796 | { | ||
797 | send_discovered_info (info, ps); | ||
798 | } | ||
799 | |||
800 | static void | ||
801 | _discoverer_finished (GstDiscoverer * dc, struct InitData * id) | ||
802 | { | ||
803 | g_main_loop_quit (id->loop); | ||
804 | } | ||
805 | |||
806 | static int | ||
807 | initialize (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. */ | ||
858 | static 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 | ||
883 | static void | 791 | static void |
884 | feed_data (GstElement * appsrc, guint size, struct PrivStruct * ps) | 792 | feed_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 | |||
948 | static gboolean | 857 | static gboolean |
949 | seek_data (GstElement * appsrc, guint64 position, struct PrivStruct * ps) | 858 | seek_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 | |||
957 | static gboolean | 867 | static 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 | ||
965 | static gboolean | 875 | static gboolean |
966 | send_structure_foreach (GQuark field_id, const GValue *value, | 876 | send_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 | |||
1055 | static int | 967 | static int |
1056 | send_audio_info (GstDiscovererAudioInfo *info, struct PrivStruct *ps) | 968 | send_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 | |||
1132 | static int | 1048 | static int |
1133 | send_video_info (GstDiscovererVideoInfo *info, struct PrivStruct *ps) | 1049 | send_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 | |||
1218 | static int | 1135 | static int |
1219 | send_subtitle_info (GstDiscovererSubtitleInfo *info, struct PrivStruct *ps) | 1136 | send_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 | ||
1233 | static void | ||
1234 | send_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 | ||
1320 | static void | 1151 | static void |
1321 | send_tag_foreach (const GstTagList * tags, const gchar * tag, | 1152 | send_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 | |||
1412 | static void | ||
1413 | send_streams (GstDiscovererStreamInfo *info, | ||
1414 | struct PrivStruct *ps); | ||
1415 | |||
1416 | |||
1417 | static void | ||
1418 | send_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 | |||
1582 | static void | 1505 | static void |
1583 | send_toc_tags_foreach (const GstTagList * tags, const gchar * tag, | 1506 | send_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 | |||
1520 | static void | ||
1521 | send_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 | ||
1697 | static void | ||
1698 | send_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 | |||
1712 | static void | 1639 | static void |
1713 | send_info (GstDiscovererInfo * info, struct PrivStruct *ps) | 1640 | send_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 | |||
1777 | static void | 1705 | static void |
1778 | send_discovered_info (GstDiscovererInfo * info, struct PrivStruct * ps) | 1706 | send_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 | ||
1734 | static void | ||
1735 | _new_discovered_uri (GstDiscoverer * dc, GstDiscovererInfo * info, GError * err, struct PrivStruct * ps) | ||
1736 | { | ||
1737 | send_discovered_info (info, ps); | ||
1738 | } | ||
1739 | |||
1740 | |||
1741 | static 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. */ | ||
1753 | static 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 | |||
1779 | static int | ||
1780 | initialize (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. |