aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-09-25 13:57:45 +0000
committerChristian Grothoff <christian@grothoff.org>2012-09-25 13:57:45 +0000
commit3a10e7b630e4c5e6f7c534e7f762fbb733a03ab3 (patch)
tree95b9bfc7b5a7178bf56d7533ff5198ad9aa0b1c8
parentac15ab4bc2928e9cfbbcd53dce67d3aa80034dda (diff)
downloadlibextractor-3a10e7b630e4c5e6f7c534e7f762fbb733a03ab3.tar.gz
libextractor-3a10e7b630e4c5e6f7c534e7f762fbb733a03ab3.zip
documenting the code a bit
-rw-r--r--src/plugins/gstreamer_extractor.c396
1 files changed, 297 insertions, 99 deletions
diff --git a/src/plugins/gstreamer_extractor.c b/src/plugins/gstreamer_extractor.c
index 34c10e3..8e4a2ee 100644
--- a/src/plugins/gstreamer_extractor.c
+++ b/src/plugins/gstreamer_extractor.c
@@ -757,61 +757,181 @@ struct NamedTag named_tags[] =
757 }; 757 };
758 758
759 759
760/**
761 *
762 */
760enum CurrentStreamType 763enum CurrentStreamType
761{ 764{
765 /**
766 *
767 */
762 STREAM_TYPE_NONE = 0, 768 STREAM_TYPE_NONE = 0,
769
770 /**
771 *
772 */
763 STREAM_TYPE_AUDIO = 1, 773 STREAM_TYPE_AUDIO = 1,
774
775 /**
776 *
777 */
764 STREAM_TYPE_VIDEO = 2, 778 STREAM_TYPE_VIDEO = 2,
779
780 /**
781 *
782 */
765 STREAM_TYPE_SUBTITLE = 3, 783 STREAM_TYPE_SUBTITLE = 3,
784
785 /**
786 *
787 */
766 STREAM_TYPE_CONTAINER = 4, 788 STREAM_TYPE_CONTAINER = 4,
789
790 /**
791 *
792 */
767 STREAM_TYPE_IMAGE = 5 793 STREAM_TYPE_IMAGE = 5
768}; 794};
769 795
770 796
797/**
798 * Closure we pass when processing a request.
799 */
771struct PrivStruct 800struct PrivStruct
772{ 801{
802 /**
803 * Tracks the time from the last IO request so that we can decide
804 * to terminate processing if GStreamer just takes far too long.
805 * Values are based on 'g_get_monotonic_time()', in milliseconds.
806 */
807 gint64 last_data_request_time;
808
809 /**
810 * Current read-offset in the 'ec' context (based on our read/seek calls).
811 */
812 guint64 offset;
813
814 /**
815 * Overall size of the file we're processing, UINT64_MAX if unknown.
816 */
817 uint64_t length;
818
819 /**
820 *
821 */
773 GstElement *source; 822 GstElement *source;
823
824 /**
825 * Extraction context for IO on the underlying data.
826 */
774 struct EXTRACTOR_ExtractContext *ec; 827 struct EXTRACTOR_ExtractContext *ec;
775 long length; 828
776 guint64 offset; 829 /**
777 int toc_depth; 830 * Glib main loop.
778 size_t toc_length; 831 */
779 size_t toc_pos;
780 gchar *toc;
781 gboolean toc_print_phase;
782 unsigned char time_to_leave;
783 enum CurrentStreamType st;
784 GMainLoop *loop; 832 GMainLoop *loop;
833
834 /**
835 * Discoverer object we are using.
836 */
785 GstDiscoverer *dc; 837 GstDiscoverer *dc;
838
839 /**
840 * Location for building the XML 'table of contents' (EXTRACTOR_METATYPE_TOC) for
841 * the input. Used only during 'send_info'.
842 */
843 gchar *toc;
844
845 /**
846 * Length of the 'toc' string.
847 */
848 size_t toc_length;
849
850 /**
851 * Current position (used when creating the 'toc' string).
852 */
853 size_t toc_pos;
854
855 /**
856 *
857 */
786 guint timeout_id; 858 guint timeout_id;
787 gint64 last_data_request_time; 859
860 /**
861 * Counter used to determine our current depth in the TOC hierarchy.
862 */
863 int toc_depth;
864
865 /**
866 *
867 */
868 enum CurrentStreamType st;
869
870 /**
871 * Last return value from the meta data processor. Set to
872 * 1 to abort, 0 to continue extracting.
873 */
874 int time_to_leave;
875
876 /**
877 * TOC generation is executed in two phases. First phase determines
878 * the size of the string and the second phase actually does the
879 * 'printing' (string construction). This bit is TRUE if we are
880 * in the 'printing' phase.
881 */
882 gboolean toc_print_phase;
883
788}; 884};
789 885
790 886
887/**
888 *
889 */
791static GQuark *audio_quarks; 890static GQuark *audio_quarks;
792 891
892/**
893 *
894 */
793static GQuark *video_quarks; 895static GQuark *video_quarks;
794 896
897/**
898 *
899 */
795static GQuark *subtitle_quarks; 900static GQuark *subtitle_quarks;
796 901
902/**
903 *
904 */
797static GQuark duration_quark; 905static GQuark duration_quark;
798 906
799 907
908/**
909 * Implementation of GstElement's "need-data" callback. Reads data from
910 * the extraction context and passes it to GStreamer.
911 *
912 * @param appsrc the GstElement for which we are implementing "need-data"
913 * @param size number of bytes requested
914 * @param ps our execution context
915 */
800static void 916static void
801feed_data (GstElement * appsrc, guint size, struct PrivStruct * ps) 917feed_data (GstElement * appsrc,
918 guint size,
919 struct PrivStruct * ps)
802{ 920{
803 long data_len; 921 ssize_t data_len;
804 uint8_t *le_data; 922 uint8_t *le_data;
805 guint accumulated; 923 guint accumulated;
806 GstMemory *mem; 924 GstMemory *mem;
807 GstMapInfo mi; 925 GstMapInfo mi;
926 GstBuffer *buffer;
808 927
809 GST_DEBUG ("Request %u bytes", size); 928 GST_DEBUG ("Request %u bytes", size);
810 929
811 /* Update it now, in case we bail out due to error */ 930 /* Update it now, in case we bail out due to error */
812 ps->last_data_request_time = g_get_monotonic_time (); 931 ps->last_data_request_time = g_get_monotonic_time ();
813 932
814 if (ps->length > 0 && ps->offset >= ps->length) { 933 if ( (ps->length > 0) && (ps->offset >= ps->length) )
934 {
815 /* we are at the EOS, send end-of-stream */ 935 /* we are at the EOS, send end-of-stream */
816 gst_app_src_end_of_stream (GST_APP_SRC (ps->source)); 936 gst_app_src_end_of_stream (GST_APP_SRC (ps->source));
817 return; 937 return;
@@ -831,7 +951,7 @@ feed_data (GstElement * appsrc, guint size, struct PrivStruct * ps)
831 951
832 accumulated = 0; 952 accumulated = 0;
833 data_len = 1; 953 data_len = 1;
834 while (accumulated < size && data_len > 0) 954 while ( (accumulated < size) && (data_len > 0) )
835 { 955 {
836 data_len = ps->ec->read (ps->ec->cls, (void **) &le_data, size - accumulated); 956 data_len = ps->ec->read (ps->ec->cls, (void **) &le_data, size - accumulated);
837 if (data_len > 0) 957 if (data_len > 0)
@@ -841,9 +961,8 @@ feed_data (GstElement * appsrc, guint size, struct PrivStruct * ps)
841 } 961 }
842 } 962 }
843 gst_memory_unmap (mem, &mi); 963 gst_memory_unmap (mem, &mi);
844 if (data_len > 0) 964 if (size == accumulated)
845 { 965 {
846 GstBuffer *buffer;
847 buffer = gst_buffer_new (); 966 buffer = gst_buffer_new ();
848 gst_buffer_append_memory (buffer, mem); 967 gst_buffer_append_memory (buffer, mem);
849 968
@@ -851,8 +970,8 @@ feed_data (GstElement * appsrc, guint size, struct PrivStruct * ps)
851 GST_BUFFER_OFFSET (buffer) = ps->offset; 970 GST_BUFFER_OFFSET (buffer) = ps->offset;
852 GST_BUFFER_OFFSET_END (buffer) = ps->offset + size; 971 GST_BUFFER_OFFSET_END (buffer) = ps->offset + size;
853 972
854 GST_DEBUG ("feed buffer %p, offset %" G_GUINT64_FORMAT "-%u", buffer, 973 GST_DEBUG ("feed buffer %p, offset %" G_GUINT64_FORMAT "-%u",
855 ps->offset, size); 974 buffer, ps->offset, size);
856 gst_app_src_push_buffer (GST_APP_SRC (ps->source), buffer); 975 gst_app_src_push_buffer (GST_APP_SRC (ps->source), buffer);
857 ps->offset += size; 976 ps->offset += size;
858 } 977 }
@@ -860,33 +979,43 @@ feed_data (GstElement * appsrc, guint size, struct PrivStruct * ps)
860 { 979 {
861 gst_memory_unref (mem); 980 gst_memory_unref (mem);
862 gst_app_src_end_of_stream (GST_APP_SRC (ps->source)); 981 gst_app_src_end_of_stream (GST_APP_SRC (ps->source));
982 ps->offset = UINT64_MAX; /* set to invalid value */
863 } 983 }
864 984
865 /* Update it again to account for time we spent fulfilling the request */ 985 /* Update it again to account for time we spent fulfilling the request */
866 ps->last_data_request_time = g_get_monotonic_time (); 986 ps->last_data_request_time = g_get_monotonic_time ();
867 return;
868} 987}
869 988
870 989
990/**
991 * Implementation of GstElement's "seek-data" callback. Seeks to a new
992 * position in the extraction context.
993 *
994 * @param appsrc the GstElement for which we are implementing "need-data"
995 * @param position new desired absolute position in the file
996 * @param ps our execution context
997 * @return TRUE if seeking succeeded, FALSE if not
998 */
871static gboolean 999static gboolean
872seek_data (GstElement * appsrc, guint64 position, struct PrivStruct * ps) 1000seek_data (GstElement * appsrc,
1001 guint64 position,
1002 struct PrivStruct * ps)
873{ 1003{
874 GST_DEBUG ("seek to offset %" G_GUINT64_FORMAT, position); 1004 GST_DEBUG ("seek to offset %" G_GUINT64_FORMAT, position);
875 ps->offset = ps->ec->seek (ps->ec->cls, position, SEEK_SET); 1005 ps->offset = ps->ec->seek (ps->ec->cls, position, SEEK_SET);
876
877 ps->last_data_request_time = g_get_monotonic_time (); 1006 ps->last_data_request_time = g_get_monotonic_time ();
878 return ps->offset >= 0; 1007 return ps->offset == position;
879}
880
881
882static gboolean
883_run_async (struct PrivStruct * ps)
884{
885 gst_discoverer_discover_uri_async (ps->dc, "appsrc://");
886 return FALSE;
887} 1008}
888 1009
889 1010
1011/**
1012 * FIXME
1013 *
1014 * @param field_id FIXME
1015 * @param value FIXME
1016 * @param user_data our 'struct PrivStruct'
1017 * @return TRUE to continue processing, FALSE to abort
1018 */
890static gboolean 1019static gboolean
891send_structure_foreach (GQuark field_id, 1020send_structure_foreach (GQuark field_id,
892 const GValue *value, 1021 const GValue *value,
@@ -922,7 +1051,6 @@ send_structure_foreach (GQuark field_id,
922 break; 1051 break;
923 } 1052 }
924 1053
925
926 switch (G_VALUE_TYPE (value)) 1054 switch (G_VALUE_TYPE (value))
927 { 1055 {
928 case G_TYPE_STRING: 1056 case G_TYPE_STRING:
@@ -948,7 +1076,7 @@ send_structure_foreach (GQuark field_id,
948 str = NULL; 1076 str = NULL;
949 break; 1077 break;
950 } 1078 }
951 if (NULL != str) 1079 if (NULL != str)
952 { 1080 {
953 unsigned int i; 1081 unsigned int i;
954 1082
@@ -969,16 +1097,24 @@ send_structure_foreach (GQuark field_id,
969 gchar *senddata = g_strdup_printf ("%s=%s", field_name, str); 1097 gchar *senddata = g_strdup_printf ("%s=%s", field_name, str);
970 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", 1098 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
971 EXTRACTOR_METATYPE_UNKNOWN, EXTRACTOR_METAFORMAT_UTF8, "text/plain", 1099 EXTRACTOR_METATYPE_UNKNOWN, EXTRACTOR_METAFORMAT_UTF8, "text/plain",
972 (const char *) senddata, strlen (senddata) + 1); 1100 (const char *) senddata,
1101 strlen (senddata) + 1);
973 g_free (senddata); 1102 g_free (senddata);
974 } 1103 }
975 g_free (str); 1104 g_free (str);
976 1105
977 return !ps->time_to_leave; 1106 return ! ps->time_to_leave;
978} 1107}
979 1108
980 1109
981static int 1110/**
1111 * FIXME
1112 *
1113 * @param info FIXME
1114 * @param ps processing context
1115 * @return FALSE to continue processing, TRUE to abort
1116 */
1117static gboolean
982send_audio_info (GstDiscovererAudioInfo *info, 1118send_audio_info (GstDiscovererAudioInfo *info,
983 struct PrivStruct *ps) 1119 struct PrivStruct *ps)
984{ 1120{
@@ -1059,15 +1195,24 @@ send_audio_info (GstDiscovererAudioInfo *info,
1059} 1195}
1060 1196
1061 1197
1198/**
1199 * FIXME
1200 *
1201 * @param info FIXME
1202 * @param ps processing context
1203 * @return FALSE to continue processing, TRUE to abort
1204 */
1062static int 1205static int
1063send_video_info (GstDiscovererVideoInfo *info, struct PrivStruct *ps) 1206send_video_info (GstDiscovererVideoInfo *info,
1207 struct PrivStruct *ps)
1064{ 1208{
1065 gchar *tmp; 1209 gchar *tmp;
1066 guint u, u2; 1210 guint u;
1211 guint u2;
1067 1212
1068 u = gst_discoverer_video_info_get_width (info); 1213 u = gst_discoverer_video_info_get_width (info);
1069 u2 = gst_discoverer_video_info_get_height (info); 1214 u2 = gst_discoverer_video_info_get_height (info);
1070 if (u > 0 && u2 > 0) 1215 if ( (u > 0) && (u2 > 0) )
1071 { 1216 {
1072 tmp = g_strdup_printf ("%ux%u", u, u2); 1217 tmp = g_strdup_printf ("%ux%u", u, u2);
1073 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", 1218 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
@@ -1092,7 +1237,7 @@ send_video_info (GstDiscovererVideoInfo *info, struct PrivStruct *ps)
1092 1237
1093 u = gst_discoverer_video_info_get_framerate_num (info); 1238 u = gst_discoverer_video_info_get_framerate_num (info);
1094 u2 = gst_discoverer_video_info_get_framerate_denom (info); 1239 u2 = gst_discoverer_video_info_get_framerate_denom (info);
1095 if (u > 0 && u2 > 0) 1240 if ( (u > 0) && (u2 > 0) )
1096 { 1241 {
1097 tmp = g_strdup_printf ("%u/%u", u, u2); 1242 tmp = g_strdup_printf ("%u/%u", u, u2);
1098 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", 1243 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
@@ -1105,7 +1250,7 @@ send_video_info (GstDiscovererVideoInfo *info, struct PrivStruct *ps)
1105 1250
1106 u = gst_discoverer_video_info_get_par_num (info); 1251 u = gst_discoverer_video_info_get_par_num (info);
1107 u2 = gst_discoverer_video_info_get_par_denom (info); 1252 u2 = gst_discoverer_video_info_get_par_denom (info);
1108 if (u > 0 && u2 > 0) 1253 if ( (u > 0) && (u2 > 0) )
1109 { 1254 {
1110 tmp = g_strdup_printf ("%u/%u", u, u2); 1255 tmp = g_strdup_printf ("%u/%u", u, u2);
1111 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", 1256 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
@@ -1119,7 +1264,7 @@ send_video_info (GstDiscovererVideoInfo *info, struct PrivStruct *ps)
1119 /* gst_discoverer_video_info_is_interlaced (info) I don't trust it... */ 1264 /* gst_discoverer_video_info_is_interlaced (info) I don't trust it... */
1120 1265
1121 u = gst_discoverer_video_info_get_bitrate (info); 1266 u = gst_discoverer_video_info_get_bitrate (info);
1122 if (u > 0 && u2 > 0) 1267 if (u > 0)
1123 { 1268 {
1124 tmp = g_strdup_printf ("%u", u); 1269 tmp = g_strdup_printf ("%u", u);
1125 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", 1270 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
@@ -1131,7 +1276,7 @@ send_video_info (GstDiscovererVideoInfo *info, struct PrivStruct *ps)
1131 } 1276 }
1132 1277
1133 u = gst_discoverer_video_info_get_max_bitrate (info); 1278 u = gst_discoverer_video_info_get_max_bitrate (info);
1134 if (u > 0 && u2 > 0) 1279 if (u > 0)
1135 { 1280 {
1136 tmp = g_strdup_printf ("%u", u); 1281 tmp = g_strdup_printf ("%u", u);
1137 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", 1282 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
@@ -1146,18 +1291,27 @@ send_video_info (GstDiscovererVideoInfo *info, struct PrivStruct *ps)
1146} 1291}
1147 1292
1148 1293
1294/**
1295 * FIXME
1296 *
1297 * @param info FIXME
1298 * @param ps processing context
1299 * @return FALSE to continue processing, TRUE to abort
1300 */
1149static int 1301static int
1150send_subtitle_info (GstDiscovererSubtitleInfo *info, struct PrivStruct *ps) 1302send_subtitle_info (GstDiscovererSubtitleInfo *info,
1303 struct PrivStruct *ps)
1151{ 1304{
1152 const gchar *ctmp; 1305 const gchar *ctmp;
1153 1306
1154 ctmp = gst_discoverer_subtitle_info_get_language (info); 1307 ctmp = gst_discoverer_subtitle_info_get_language (info);
1155 if (ctmp) 1308 if ( (NULL != ctmp) &&
1156 if ((ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", 1309 (0 != (ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
1157 EXTRACTOR_METATYPE_SUBTITLE_LANGUAGE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", 1310 EXTRACTOR_METATYPE_SUBTITLE_LANGUAGE,
1158 (const char *) ctmp, strlen (ctmp) + 1))) 1311 EXTRACTOR_METAFORMAT_UTF8,
1159 return TRUE; 1312 "text/plain",
1160 1313 (const char *) ctmp, strlen (ctmp) + 1))) )
1314 return TRUE;
1161 return FALSE; 1315 return FALSE;
1162} 1316}
1163 1317
@@ -1167,11 +1321,11 @@ send_tag_foreach (const GstTagList * tags,
1167 const gchar * tag, 1321 const gchar * tag,
1168 gpointer user_data) 1322 gpointer user_data)
1169{ 1323{
1324 static struct KnownTag unknown_tag = {NULL, EXTRACTOR_METATYPE_UNKNOWN};
1170 struct PrivStruct *ps = user_data; 1325 struct PrivStruct *ps = user_data;
1171 size_t i; 1326 size_t i;
1172 size_t tagl = sizeof (__known_tags) / sizeof (struct KnownTag); 1327 size_t tagl = sizeof (__known_tags) / sizeof (struct KnownTag);
1173 struct KnownTag *kt = NULL; 1328 const struct KnownTag *kt = NULL;
1174 struct KnownTag unknown_tag = {NULL, EXTRACTOR_METATYPE_UNKNOWN};
1175 GQuark tag_quark; 1329 GQuark tag_quark;
1176 guint vallen; 1330 guint vallen;
1177 GstSample *sample; 1331 GstSample *sample;
@@ -1517,12 +1671,13 @@ send_stream_info (GstDiscovererStreamInfo * info,
1517 1671
1518 1672
1519static void 1673static void
1520send_streams (GstDiscovererStreamInfo *info, struct PrivStruct *ps) 1674send_streams (GstDiscovererStreamInfo *info,
1675 struct PrivStruct *ps)
1521{ 1676{
1677 GstDiscovererStreamInfo *next;
1678
1522 while ( (NULL != info) && (! ps->time_to_leave) ) 1679 while ( (NULL != info) && (! ps->time_to_leave) )
1523 { 1680 {
1524 GstDiscovererStreamInfo *next;
1525
1526 send_stream_info (info, ps); 1681 send_stream_info (info, ps);
1527 next = gst_discoverer_stream_info_get_next (info); 1682 next = gst_discoverer_stream_info_get_next (info);
1528 gst_discoverer_stream_info_unref (info); 1683 gst_discoverer_stream_info_unref (info);
@@ -1531,6 +1686,13 @@ send_streams (GstDiscovererStreamInfo *info, struct PrivStruct *ps)
1531} 1686}
1532 1687
1533 1688
1689/**
1690 * Callback used to construct the XML 'toc'.
1691 *
1692 * @param tags FIXME
1693 * @param tag FIXME
1694 * @param user_data the 'struct PrivStruct' with the 'toc' string we are assembling
1695 */
1534static void 1696static void
1535send_toc_tags_foreach (const GstTagList * tags, 1697send_toc_tags_foreach (const GstTagList * tags,
1536 const gchar * tag, 1698 const gchar * tag,
@@ -1588,6 +1750,12 @@ send_toc_tags_foreach (const GstTagList * tags,
1588} 1750}
1589 1751
1590 1752
1753/**
1754 * Top-level callback used to construct the XML 'toc'.
1755 *
1756 * @param data the GstTocEntry we're processing
1757 * @param user_data the 'struct PrivStruct' with the 'toc' string we are assembling
1758 */
1591static void 1759static void
1592send_toc_foreach (gpointer data, gpointer user_data) 1760send_toc_foreach (gpointer data, gpointer user_data)
1593{ 1761{
@@ -1595,68 +1763,72 @@ send_toc_foreach (gpointer data, gpointer user_data)
1595 struct PrivStruct *ps = user_data; 1763 struct PrivStruct *ps = user_data;
1596 GstTagList *tags; 1764 GstTagList *tags;
1597 GList *subentries; 1765 GList *subentries;
1598 gint64 start, stop; 1766 gint64 start;
1767 gint64 stop;
1599 GstTocEntryType entype; 1768 GstTocEntryType entype;
1769 gchar *s;
1600 1770
1601 entype = gst_toc_entry_get_entry_type (entry); 1771 entype = gst_toc_entry_get_entry_type (entry);
1602 if (GST_TOC_ENTRY_TYPE_INVALID != entype) 1772 if (GST_TOC_ENTRY_TYPE_INVALID == entype)
1603 { 1773 return;
1604 char *s; 1774 gst_toc_entry_get_start_stop_times (entry, &start, &stop);
1605 1775 s = g_strdup_printf ("%*.*s<%s start=\"%" GST_TIME_FORMAT "\" stop=\"%"
1606 gst_toc_entry_get_start_stop_times (entry, &start, &stop); 1776 GST_TIME_FORMAT"\">\n", ps->toc_depth * 2, ps->toc_depth * 2, " ",
1607 s = g_strdup_printf ("%*.*s<%s start=\"%" GST_TIME_FORMAT "\" stop=\"%" 1777 gst_toc_entry_type_get_nick (entype), GST_TIME_ARGS (start),
1608 GST_TIME_FORMAT"\">\n", ps->toc_depth * 2, ps->toc_depth * 2, " ", 1778 GST_TIME_ARGS (stop));
1609 gst_toc_entry_type_get_nick (entype), GST_TIME_ARGS (start), 1779 if (ps->toc_print_phase)
1610 GST_TIME_ARGS (stop)); 1780 ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length - ps->toc_pos, "%s", s);
1611 if (ps->toc_print_phase) 1781 else
1612 ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length - ps->toc_pos, "%s", s); 1782 ps->toc_length += strlen (s);
1613 else 1783 g_free (s);
1614 ps->toc_length += strlen (s); 1784 ps->toc_depth++;
1615 g_free (s); 1785 tags = gst_toc_entry_get_tags (entry);
1616 ps->toc_depth++; 1786 if (tags)
1617 tags = gst_toc_entry_get_tags (entry);
1618 if (tags)
1619 { 1787 {
1620 if (ps->toc_print_phase) 1788 if (ps->toc_print_phase)
1621 ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length - ps->toc_pos, 1789 ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length - ps->toc_pos,
1622 "%*.*s<tags>\n", ps->toc_depth * 2, ps->toc_depth * 2, " "); 1790 "%*.*s<tags>\n", ps->toc_depth * 2, ps->toc_depth * 2, " ");
1623 else 1791 else
1624 ps->toc_length += strlen ("<tags>\n") + ps->toc_depth * 2; 1792 ps->toc_length += strlen ("<tags>\n") + ps->toc_depth * 2;
1625 ps->toc_depth++; 1793 ps->toc_depth++;
1626 gst_tag_list_foreach (tags, send_toc_tags_foreach, ps); 1794 gst_tag_list_foreach (tags, &send_toc_tags_foreach, ps);
1627 ps->toc_depth--; 1795 ps->toc_depth--;
1628 if (ps->toc_print_phase) 1796 if (ps->toc_print_phase)
1629 ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length - ps->toc_pos, 1797 ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length - ps->toc_pos,
1630 "%*.*s</tags>\n", ps->toc_depth * 2, ps->toc_depth * 2, " "); 1798 "%*.*s</tags>\n", ps->toc_depth * 2, ps->toc_depth * 2, " ");
1631 else 1799 else
1632 ps->toc_length += strlen ("</tags>\n") + ps->toc_depth * 2; 1800 ps->toc_length += strlen ("</tags>\n") + ps->toc_depth * 2;
1633 } 1801 }
1634 1802
1635 subentries = gst_toc_entry_get_sub_entries (entry); 1803 subentries = gst_toc_entry_get_sub_entries (entry);
1636 g_list_foreach (subentries, send_toc_foreach, ps); 1804 g_list_foreach (subentries, send_toc_foreach, ps);
1637 ps->toc_depth--; 1805 ps->toc_depth--;
1638 1806
1639 s = g_strdup_printf ("%*.*s</%s>\n", ps->toc_depth * 2, ps->toc_depth * 2, " ", 1807 s = g_strdup_printf ("%*.*s</%s>\n", ps->toc_depth * 2, ps->toc_depth * 2, " ",
1640 gst_toc_entry_type_get_nick (entype)); 1808 gst_toc_entry_type_get_nick (entype));
1641 if (ps->toc_print_phase) 1809 if (ps->toc_print_phase)
1642 ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length - ps->toc_pos, "%s", s); 1810 ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length - ps->toc_pos, "%s", s);
1643 else 1811 else
1644 ps->toc_length += strlen (s); 1812 ps->toc_length += strlen (s);
1645 g_free (s); 1813 g_free (s);
1646 }
1647} 1814}
1648 1815
1649 1816
1817/**
1818 * XML header for the table-of-contents meta data.
1819 */
1650#define TOC_XML_HEADER "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" 1820#define TOC_XML_HEADER "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
1651 1821
1652 1822
1653static void 1823static void
1654send_info (GstDiscovererInfo * info, struct PrivStruct *ps) 1824send_info (GstDiscovererInfo * info,
1825 struct PrivStruct *ps)
1655{ 1826{
1656 const GstToc *toc; 1827 const GstToc *toc;
1657 gchar *s; 1828 gchar *s;
1658 GstDiscovererStreamInfo *sinfo; 1829 GstDiscovererStreamInfo *sinfo;
1659 GstClockTime duration; 1830 GstClockTime duration;
1831 GList *entries;
1660 1832
1661 duration = gst_discoverer_info_get_duration (info); 1833 duration = gst_discoverer_info_get_duration (info);
1662 if ((GST_CLOCK_TIME_IS_VALID (duration)) && (duration > 0)) 1834 if ((GST_CLOCK_TIME_IS_VALID (duration)) && (duration > 0))
@@ -1684,12 +1856,10 @@ send_info (GstDiscovererInfo * info, struct PrivStruct *ps)
1684 1856
1685 if ((toc = gst_discoverer_info_get_toc (info))) 1857 if ((toc = gst_discoverer_info_get_toc (info)))
1686 { 1858 {
1687 GList *entries;
1688
1689 entries = gst_toc_get_entries (toc); 1859 entries = gst_toc_get_entries (toc);
1690 ps->toc_print_phase = FALSE; 1860 ps->toc_print_phase = FALSE;
1691 ps->toc_length = 0; 1861 ps->toc_length = 0;
1692 g_list_foreach (entries, send_toc_foreach, ps); 1862 g_list_foreach (entries, &send_toc_foreach, ps);
1693 1863
1694 if (ps->toc_length > 0) 1864 if (ps->toc_length > 0)
1695 { 1865 {
@@ -1697,18 +1867,24 @@ send_info (GstDiscovererInfo * info, struct PrivStruct *ps)
1697 ps->toc_length += 1 + strlen (TOC_XML_HEADER); 1867 ps->toc_length += 1 + strlen (TOC_XML_HEADER);
1698 ps->toc = g_malloc (ps->toc_length); 1868 ps->toc = g_malloc (ps->toc_length);
1699 ps->toc_pos = 0; 1869 ps->toc_pos = 0;
1700 ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length - ps->toc_pos, "%s", TOC_XML_HEADER); 1870 ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos],
1701 g_list_foreach (entries, send_toc_foreach, ps); 1871 ps->toc_length - ps->toc_pos,
1872 "%s",
1873 TOC_XML_HEADER);
1874 g_list_foreach (entries, &send_toc_foreach, ps);
1702 ps->toc[ps->toc_length - 1] = '\0'; 1875 ps->toc[ps->toc_length - 1] = '\0';
1703 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", 1876 ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
1704 EXTRACTOR_METATYPE_TOC, EXTRACTOR_METAFORMAT_C_STRING, "application/xml", 1877 EXTRACTOR_METATYPE_TOC,
1705 (const char *) ps->toc, ps->toc_length); 1878 EXTRACTOR_METAFORMAT_C_STRING,
1879 "application/xml",
1880 (const char *) ps->toc,
1881 ps->toc_length);
1706 g_free (ps->toc); 1882 g_free (ps->toc);
1707 ps->toc = NULL; 1883 ps->toc = NULL;
1708 } 1884 }
1709 } 1885 }
1710 1886
1711 if (ps->time_to_leave) 1887 if (0 != ps->time_to_leave)
1712 return; 1888 return;
1713 1889
1714 sinfo = gst_discoverer_info_get_stream_info (info); 1890 sinfo = gst_discoverer_info_get_stream_info (info);
@@ -1717,7 +1893,8 @@ send_info (GstDiscovererInfo * info, struct PrivStruct *ps)
1717 1893
1718 1894
1719static void 1895static void
1720send_discovered_info (GstDiscovererInfo * info, struct PrivStruct * ps) 1896send_discovered_info (GstDiscovererInfo * info,
1897 struct PrivStruct * ps)
1721{ 1898{
1722 GstDiscovererResult result; 1899 GstDiscovererResult result;
1723 1900
@@ -1765,6 +1942,7 @@ _discoverer_finished (GstDiscoverer * dc, struct PrivStruct *ps)
1765 g_main_loop_quit (ps->loop); 1942 g_main_loop_quit (ps->loop);
1766} 1943}
1767 1944
1945
1768static gboolean 1946static gboolean
1769_data_timeout (struct PrivStruct *ps) 1947_data_timeout (struct PrivStruct *ps)
1770{ 1948{
@@ -1780,11 +1958,17 @@ _data_timeout (struct PrivStruct *ps)
1780 return TRUE; 1958 return TRUE;
1781} 1959}
1782 1960
1961
1783/** 1962/**
1784 * This callback is called when discoverer has constructed a source object to 1963 * This callback is called when discoverer has constructed a source object to
1785 * read from. Since we provided the appsrc:// uri to discoverer, this will be 1964 * read from. Since we provided the appsrc:// uri to discoverer, this will be
1786 * the appsrc that we must handle. We set up some signals - one to push data 1965 * the appsrc that we must handle. We set up some signals - one to push data
1787 * into appsrc and one to perform a seek. */ 1966 * into appsrc and one to perform a seek.
1967 *
1968 * @param dc
1969 * @param source
1970 * @param ps
1971 */
1788static void 1972static void
1789_source_setup (GstDiscoverer * dc, 1973_source_setup (GstDiscoverer * dc,
1790 GstElement * source, 1974 GstElement * source,
@@ -1816,6 +2000,20 @@ _source_setup (GstDiscoverer * dc,
1816 2000
1817 2001
1818/** 2002/**
2003 * Task run from the main loop to call 'gst_discoverer_uri_async'.
2004 *
2005 * @param ps our execution context
2006 * @return FALSE (always)
2007 */
2008static gboolean
2009_run_async (struct PrivStruct * ps)
2010{
2011 gst_discoverer_discover_uri_async (ps->dc, "appsrc://");
2012 return FALSE;
2013}
2014
2015
2016/**
1819 * This will be the main method of your plugin. 2017 * This will be the main method of your plugin.
1820 * Describe a bit what it does here. 2018 * Describe a bit what it does here.
1821 * 2019 *