diff options
Diffstat (limited to 'src/plugins/gstreamer_extractor.c')
-rw-r--r-- | src/plugins/gstreamer_extractor.c | 393 |
1 files changed, 205 insertions, 188 deletions
diff --git a/src/plugins/gstreamer_extractor.c b/src/plugins/gstreamer_extractor.c index 5fe2126..fa3eaf8 100644 --- a/src/plugins/gstreamer_extractor.c +++ b/src/plugins/gstreamer_extractor.c | |||
@@ -1186,9 +1186,8 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, | |||
1186 | struct KnownTag unknown_tag = {NULL, EXTRACTOR_METATYPE_UNKNOWN}; | 1186 | struct KnownTag unknown_tag = {NULL, EXTRACTOR_METATYPE_UNKNOWN}; |
1187 | 1187 | ||
1188 | 1188 | ||
1189 | GValue val = { 0, }; | ||
1190 | gchar *str = NULL; | ||
1191 | GQuark tag_quark; | 1189 | GQuark tag_quark; |
1190 | guint vallen; | ||
1192 | 1191 | ||
1193 | GstSample *sample; | 1192 | GstSample *sample; |
1194 | 1193 | ||
@@ -1205,220 +1204,238 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, | |||
1205 | if (kt == NULL) | 1204 | if (kt == NULL) |
1206 | kt = &unknown_tag; | 1205 | kt = &unknown_tag; |
1207 | 1206 | ||
1208 | gst_tag_list_copy_value (&val, tags, tag); | 1207 | vallen = gst_tag_list_get_tag_size (tags, tag); |
1208 | if (vallen == 0) | ||
1209 | return; | ||
1209 | 1210 | ||
1210 | tag_quark = g_quark_from_string (tag); | 1211 | tag_quark = g_quark_from_string (tag); |
1211 | 1212 | ||
1212 | switch (G_VALUE_TYPE (&val)) | 1213 | for (i = 0; i < vallen; i++) |
1213 | { | 1214 | { |
1214 | case G_TYPE_STRING: | 1215 | GValue val = { 0, }; |
1215 | str = g_value_dup_string (&val); | 1216 | const GValue *val_ref; |
1216 | break; | 1217 | gchar *str = NULL; |
1217 | case G_TYPE_UINT: | 1218 | |
1218 | case G_TYPE_INT: | 1219 | val_ref = gst_tag_list_get_value_index (tags, tag, i); |
1219 | case G_TYPE_DOUBLE: | 1220 | if (val_ref == NULL) |
1220 | case G_TYPE_BOOLEAN: | ||
1221 | str = gst_value_serialize (&val); | ||
1222 | break; | ||
1223 | default: | ||
1224 | if (G_VALUE_TYPE (&val) == GST_TYPE_SAMPLE && (sample = gst_value_get_sample (&val))) | ||
1225 | { | 1221 | { |
1226 | GstMapInfo mi; | 1222 | g_value_unset (&val); |
1227 | const gchar *structname; | 1223 | continue; |
1228 | GstCaps *caps; | 1224 | } |
1225 | g_value_init (&val, G_VALUE_TYPE (val_ref)); | ||
1226 | g_value_copy (val_ref, &val); | ||
1229 | 1227 | ||
1230 | caps = gst_sample_get_caps (sample); | 1228 | switch (G_VALUE_TYPE (&val)) |
1231 | if (caps) | 1229 | { |
1230 | case G_TYPE_STRING: | ||
1231 | str = g_value_dup_string (&val); | ||
1232 | break; | ||
1233 | case G_TYPE_UINT: | ||
1234 | case G_TYPE_INT: | ||
1235 | case G_TYPE_DOUBLE: | ||
1236 | case G_TYPE_BOOLEAN: | ||
1237 | str = gst_value_serialize (&val); | ||
1238 | break; | ||
1239 | default: | ||
1240 | if (G_VALUE_TYPE (&val) == GST_TYPE_SAMPLE && (sample = gst_value_get_sample (&val))) | ||
1232 | { | 1241 | { |
1233 | GstTagImageType imagetype; | 1242 | GstMapInfo mi; |
1234 | const GstStructure *info; | 1243 | const gchar *structname; |
1235 | GstBuffer *buf; | 1244 | GstCaps *caps; |
1236 | const gchar *mime_type; | 1245 | |
1237 | enum EXTRACTOR_MetaType le_type; | 1246 | caps = gst_sample_get_caps (sample); |
1238 | 1247 | if (caps) | |
1239 | mime_type = gst_structure_get_name (gst_caps_get_structure (caps, 0)); | ||
1240 | info = gst_sample_get_info (sample); | ||
1241 | |||
1242 | if (!gst_structure_get (info, "image-type", GST_TYPE_TAG_IMAGE_TYPE, &imagetype, NULL)) | ||
1243 | le_type = EXTRACTOR_METATYPE_PICTURE; | ||
1244 | else | ||
1245 | { | 1248 | { |
1246 | switch (imagetype) | 1249 | GstTagImageType imagetype; |
1247 | { | 1250 | const GstStructure *info; |
1248 | case GST_TAG_IMAGE_TYPE_NONE: | 1251 | GstBuffer *buf; |
1249 | case GST_TAG_IMAGE_TYPE_UNDEFINED: | 1252 | const gchar *mime_type; |
1250 | case GST_TAG_IMAGE_TYPE_FISH: | 1253 | enum EXTRACTOR_MetaType le_type; |
1251 | case GST_TAG_IMAGE_TYPE_ILLUSTRATION: | 1254 | |
1252 | default: | 1255 | mime_type = gst_structure_get_name (gst_caps_get_structure (caps, 0)); |
1256 | info = gst_sample_get_info (sample); | ||
1257 | |||
1258 | if (!gst_structure_get (info, "image-type", GST_TYPE_TAG_IMAGE_TYPE, &imagetype, NULL)) | ||
1253 | le_type = EXTRACTOR_METATYPE_PICTURE; | 1259 | le_type = EXTRACTOR_METATYPE_PICTURE; |
1254 | break; | 1260 | else |
1255 | case GST_TAG_IMAGE_TYPE_FRONT_COVER: | 1261 | { |
1256 | case GST_TAG_IMAGE_TYPE_BACK_COVER: | 1262 | switch (imagetype) |
1257 | case GST_TAG_IMAGE_TYPE_LEAFLET_PAGE: | 1263 | { |
1258 | case GST_TAG_IMAGE_TYPE_MEDIUM: | 1264 | case GST_TAG_IMAGE_TYPE_NONE: |
1259 | le_type = EXTRACTOR_METATYPE_COVER_PICTURE; | 1265 | case GST_TAG_IMAGE_TYPE_UNDEFINED: |
1260 | break; | 1266 | case GST_TAG_IMAGE_TYPE_FISH: |
1261 | case GST_TAG_IMAGE_TYPE_LEAD_ARTIST: | 1267 | case GST_TAG_IMAGE_TYPE_ILLUSTRATION: |
1262 | case GST_TAG_IMAGE_TYPE_ARTIST: | 1268 | default: |
1263 | case GST_TAG_IMAGE_TYPE_CONDUCTOR: | 1269 | le_type = EXTRACTOR_METATYPE_PICTURE; |
1264 | case GST_TAG_IMAGE_TYPE_BAND_ORCHESTRA: | 1270 | break; |
1265 | case GST_TAG_IMAGE_TYPE_COMPOSER: | 1271 | case GST_TAG_IMAGE_TYPE_FRONT_COVER: |
1266 | case GST_TAG_IMAGE_TYPE_LYRICIST: | 1272 | case GST_TAG_IMAGE_TYPE_BACK_COVER: |
1267 | le_type = EXTRACTOR_METATYPE_CONTRIBUTOR_PICTURE; | 1273 | case GST_TAG_IMAGE_TYPE_LEAFLET_PAGE: |
1268 | break; | 1274 | case GST_TAG_IMAGE_TYPE_MEDIUM: |
1269 | case GST_TAG_IMAGE_TYPE_RECORDING_LOCATION: | 1275 | le_type = EXTRACTOR_METATYPE_COVER_PICTURE; |
1270 | case GST_TAG_IMAGE_TYPE_DURING_RECORDING: | 1276 | break; |
1271 | case GST_TAG_IMAGE_TYPE_DURING_PERFORMANCE: | 1277 | case GST_TAG_IMAGE_TYPE_LEAD_ARTIST: |
1272 | case GST_TAG_IMAGE_TYPE_VIDEO_CAPTURE: | 1278 | case GST_TAG_IMAGE_TYPE_ARTIST: |
1273 | le_type = EXTRACTOR_METATYPE_EVENT_PICTURE; | 1279 | case GST_TAG_IMAGE_TYPE_CONDUCTOR: |
1274 | break; | 1280 | case GST_TAG_IMAGE_TYPE_BAND_ORCHESTRA: |
1275 | case GST_TAG_IMAGE_TYPE_BAND_ARTIST_LOGO: | 1281 | case GST_TAG_IMAGE_TYPE_COMPOSER: |
1276 | case GST_TAG_IMAGE_TYPE_PUBLISHER_STUDIO_LOGO: | 1282 | case GST_TAG_IMAGE_TYPE_LYRICIST: |
1277 | le_type = EXTRACTOR_METATYPE_LOGO; | 1283 | le_type = EXTRACTOR_METATYPE_CONTRIBUTOR_PICTURE; |
1278 | break; | 1284 | break; |
1285 | case GST_TAG_IMAGE_TYPE_RECORDING_LOCATION: | ||
1286 | case GST_TAG_IMAGE_TYPE_DURING_RECORDING: | ||
1287 | case GST_TAG_IMAGE_TYPE_DURING_PERFORMANCE: | ||
1288 | case GST_TAG_IMAGE_TYPE_VIDEO_CAPTURE: | ||
1289 | le_type = EXTRACTOR_METATYPE_EVENT_PICTURE; | ||
1290 | break; | ||
1291 | case GST_TAG_IMAGE_TYPE_BAND_ARTIST_LOGO: | ||
1292 | case GST_TAG_IMAGE_TYPE_PUBLISHER_STUDIO_LOGO: | ||
1293 | le_type = EXTRACTOR_METATYPE_LOGO; | ||
1294 | break; | ||
1295 | } | ||
1279 | } | 1296 | } |
1280 | } | ||
1281 | 1297 | ||
1282 | buf = gst_sample_get_buffer (sample); | 1298 | buf = gst_sample_get_buffer (sample); |
1283 | gst_buffer_map (buf, &mi, GST_MAP_READ); | 1299 | gst_buffer_map (buf, &mi, GST_MAP_READ); |
1284 | ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", le_type, | 1300 | ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", le_type, |
1285 | EXTRACTOR_METAFORMAT_BINARY, mime_type, | 1301 | EXTRACTOR_METAFORMAT_BINARY, mime_type, |
1286 | (const char *) mi.data, mi.size); | 1302 | (const char *) mi.data, mi.size); |
1287 | gst_buffer_unmap (buf, &mi); | 1303 | gst_buffer_unmap (buf, &mi); |
1288 | } | 1304 | } |
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 | } | ||
1297 | else | ||
1298 | str = gst_value_serialize (&val); | ||
1299 | break; | ||
1300 | } | ||
1301 | if (str != NULL) | ||
1302 | { | ||
1303 | /* Discoverer internally uses some tags to provide streaminfo; | ||
1304 | * ignore these tags to avoid duplicates. | ||
1305 | * This MIGHT be fixed in new GStreamer versions, but won't affect | ||
1306 | * this code (we simply won't get the tags that we think we should skip). | ||
1307 | */ | ||
1308 | gboolean skip = FALSE; | ||
1309 | /* We have one tag-processing routine and use it for different | ||
1310 | * stream types. However, tags themselves don't know the type of the | ||
1311 | * stream they are attached to. We remember that before listing the | ||
1312 | * tags, and adjust LE type accordingly. | ||
1313 | */ | ||
1314 | enum EXTRACTOR_MetaType le_type = kt->le_type; | ||
1315 | switch (kt->le_type) | ||
1316 | { | ||
1317 | case EXTRACTOR_METATYPE_LANGUAGE: | ||
1318 | switch (ps->st) | ||
1319 | { | ||
1320 | case STREAM_TYPE_AUDIO: | ||
1321 | skip = TRUE; | ||
1322 | break; | ||
1323 | case STREAM_TYPE_SUBTITLE: | ||
1324 | skip = TRUE; | ||
1325 | break; | ||
1326 | case STREAM_TYPE_VIDEO: | ||
1327 | le_type = EXTRACTOR_METATYPE_VIDEO_LANGUAGE; | ||
1328 | break; | ||
1329 | default: | ||
1330 | break; | ||
1331 | } | ||
1332 | break; | ||
1333 | case EXTRACTOR_METATYPE_BITRATE: | ||
1334 | switch (ps->st) | ||
1335 | { | ||
1336 | case STREAM_TYPE_AUDIO: | ||
1337 | skip = TRUE; | ||
1338 | break; | ||
1339 | case STREAM_TYPE_VIDEO: | ||
1340 | skip = TRUE; | ||
1341 | break; | ||
1342 | default: | ||
1343 | break; | ||
1344 | } | 1305 | } |
1345 | break; | 1306 | else if ((G_VALUE_TYPE (&val) == G_TYPE_UINT64) && |
1346 | case EXTRACTOR_METATYPE_MAXIMUM_BITRATE: | 1307 | (tag_quark == duration_quark)) |
1347 | switch (ps->st) | ||
1348 | { | 1308 | { |
1349 | case STREAM_TYPE_AUDIO: | 1309 | GstClockTime duration = (GstClockTime) g_value_get_uint64 (&val); |
1350 | skip = TRUE; | 1310 | if ((GST_CLOCK_TIME_IS_VALID (duration)) && (duration > 0)) |
1351 | break; | 1311 | str = g_strdup_printf ("%" GST_TIME_FORMAT, GST_TIME_ARGS (duration)); |
1352 | case STREAM_TYPE_VIDEO: | ||
1353 | skip = TRUE; | ||
1354 | break; | ||
1355 | default: | ||
1356 | break; | ||
1357 | } | 1312 | } |
1313 | else | ||
1314 | str = gst_value_serialize (&val); | ||
1358 | break; | 1315 | break; |
1359 | case EXTRACTOR_METATYPE_NOMINAL_BITRATE: | 1316 | } |
1360 | switch (ps->st) | 1317 | if (str != NULL) |
1318 | { | ||
1319 | /* Discoverer internally uses some tags to provide streaminfo; | ||
1320 | * ignore these tags to avoid duplicates. | ||
1321 | * This MIGHT be fixed in new GStreamer versions, but won't affect | ||
1322 | * this code (we simply won't get the tags that we think we should skip). | ||
1323 | */ | ||
1324 | gboolean skip = FALSE; | ||
1325 | /* We have one tag-processing routine and use it for different | ||
1326 | * stream types. However, tags themselves don't know the type of the | ||
1327 | * stream they are attached to. We remember that before listing the | ||
1328 | * tags, and adjust LE type accordingly. | ||
1329 | */ | ||
1330 | enum EXTRACTOR_MetaType le_type = kt->le_type; | ||
1331 | switch (kt->le_type) | ||
1361 | { | 1332 | { |
1362 | case STREAM_TYPE_AUDIO: | 1333 | case EXTRACTOR_METATYPE_LANGUAGE: |
1363 | skip = TRUE; | 1334 | switch (ps->st) |
1364 | break; | 1335 | { |
1365 | case STREAM_TYPE_VIDEO: | 1336 | case STREAM_TYPE_AUDIO: |
1366 | skip = TRUE; | 1337 | skip = TRUE; |
1338 | break; | ||
1339 | case STREAM_TYPE_SUBTITLE: | ||
1340 | skip = TRUE; | ||
1341 | break; | ||
1342 | case STREAM_TYPE_VIDEO: | ||
1343 | le_type = EXTRACTOR_METATYPE_VIDEO_LANGUAGE; | ||
1344 | break; | ||
1345 | default: | ||
1346 | break; | ||
1347 | } | ||
1367 | break; | 1348 | break; |
1368 | default: | 1349 | case EXTRACTOR_METATYPE_BITRATE: |
1350 | switch (ps->st) | ||
1351 | { | ||
1352 | case STREAM_TYPE_AUDIO: | ||
1353 | skip = TRUE; | ||
1354 | break; | ||
1355 | case STREAM_TYPE_VIDEO: | ||
1356 | skip = TRUE; | ||
1357 | break; | ||
1358 | default: | ||
1359 | break; | ||
1360 | } | ||
1369 | break; | 1361 | break; |
1370 | } | 1362 | case EXTRACTOR_METATYPE_MAXIMUM_BITRATE: |
1371 | break; | 1363 | switch (ps->st) |
1372 | case EXTRACTOR_METATYPE_IMAGE_DIMENSIONS: | 1364 | { |
1373 | switch (ps->st) | 1365 | case STREAM_TYPE_AUDIO: |
1374 | { | 1366 | skip = TRUE; |
1375 | case STREAM_TYPE_VIDEO: | 1367 | break; |
1376 | le_type = EXTRACTOR_METATYPE_VIDEO_DIMENSIONS; | 1368 | case STREAM_TYPE_VIDEO: |
1369 | skip = TRUE; | ||
1370 | break; | ||
1371 | default: | ||
1372 | break; | ||
1373 | } | ||
1377 | break; | 1374 | break; |
1378 | default: | 1375 | case EXTRACTOR_METATYPE_NOMINAL_BITRATE: |
1376 | switch (ps->st) | ||
1377 | { | ||
1378 | case STREAM_TYPE_AUDIO: | ||
1379 | skip = TRUE; | ||
1380 | break; | ||
1381 | case STREAM_TYPE_VIDEO: | ||
1382 | skip = TRUE; | ||
1383 | break; | ||
1384 | default: | ||
1385 | break; | ||
1386 | } | ||
1379 | break; | 1387 | break; |
1380 | } | 1388 | case EXTRACTOR_METATYPE_IMAGE_DIMENSIONS: |
1381 | break; | 1389 | switch (ps->st) |
1382 | case EXTRACTOR_METATYPE_DURATION: | 1390 | { |
1383 | switch (ps->st) | 1391 | case STREAM_TYPE_VIDEO: |
1384 | { | 1392 | le_type = EXTRACTOR_METATYPE_VIDEO_DIMENSIONS; |
1385 | case STREAM_TYPE_VIDEO: | 1393 | break; |
1386 | le_type = EXTRACTOR_METATYPE_VIDEO_DURATION; | 1394 | default: |
1395 | break; | ||
1396 | } | ||
1387 | break; | 1397 | break; |
1388 | case STREAM_TYPE_AUDIO: | 1398 | case EXTRACTOR_METATYPE_DURATION: |
1389 | le_type = EXTRACTOR_METATYPE_AUDIO_DURATION; | 1399 | switch (ps->st) |
1400 | { | ||
1401 | case STREAM_TYPE_VIDEO: | ||
1402 | le_type = EXTRACTOR_METATYPE_VIDEO_DURATION; | ||
1403 | break; | ||
1404 | case STREAM_TYPE_AUDIO: | ||
1405 | le_type = EXTRACTOR_METATYPE_AUDIO_DURATION; | ||
1406 | break; | ||
1407 | case STREAM_TYPE_SUBTITLE: | ||
1408 | le_type = EXTRACTOR_METATYPE_SUBTITLE_DURATION; | ||
1409 | break; | ||
1410 | default: | ||
1411 | break; | ||
1412 | } | ||
1390 | break; | 1413 | break; |
1391 | case STREAM_TYPE_SUBTITLE: | 1414 | case EXTRACTOR_METATYPE_UNKNOWN: |
1392 | le_type = EXTRACTOR_METATYPE_SUBTITLE_DURATION; | 1415 | /* Convert to "key=value" form */ |
1416 | { | ||
1417 | gchar *new_str; | ||
1418 | /* GST_TAG_EXTENDED_COMMENT is already in key=value form */ | ||
1419 | if ((0 != strcmp (tag, "extended-comment")) || !strchr (str, '=')) | ||
1420 | { | ||
1421 | new_str = g_strdup_printf ("%s=%s", tag, str); | ||
1422 | g_free (str); | ||
1423 | str = new_str; | ||
1424 | } | ||
1425 | } | ||
1393 | break; | 1426 | break; |
1394 | default: | 1427 | default: |
1395 | break; | 1428 | break; |
1396 | } | 1429 | } |
1397 | break; | 1430 | if (!skip) |
1398 | case EXTRACTOR_METATYPE_UNKNOWN: | 1431 | ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", le_type, |
1399 | /* Convert to "key=value" form */ | 1432 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", |
1400 | { | 1433 | (const char *) str, strlen (str) + 1); |
1401 | gchar *new_str; | ||
1402 | /* GST_TAG_EXTENDED_COMMENT is already in key=value form */ | ||
1403 | if ((0 != strcmp (tag, "extended-comment")) || !strchr (str, '=')) | ||
1404 | { | ||
1405 | new_str = g_strdup_printf ("%s=%s", tag, str); | ||
1406 | g_free (str); | ||
1407 | str = new_str; | ||
1408 | } | ||
1409 | } | ||
1410 | break; | ||
1411 | default: | ||
1412 | break; | ||
1413 | } | 1434 | } |
1414 | if (!skip) | ||
1415 | ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", le_type, | ||
1416 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
1417 | (const char *) str, strlen (str) + 1); | ||
1418 | } | ||
1419 | 1435 | ||
1420 | g_free (str); | 1436 | g_free (str); |
1421 | g_value_unset (&val); | 1437 | g_value_unset (&val); |
1438 | } | ||
1422 | } | 1439 | } |
1423 | 1440 | ||
1424 | static void | 1441 | static void |