33 #include <sbIGStreamerService.h>
34 #include <sbIMediacoreCapabilities.h>
40 #include <nsComponentManagerUtils.h>
41 #include <nsProxyRelease.h>
42 #include <nsServiceManagerUtils.h>
43 #include <nsThreadUtils.h>
44 #include <nsIStringEnumerator.h>
46 #include <nsUnicharUtils.h>
51 #include <gst/pbutils/missing-plugins.h>
53 #define METADATA_TIMEOUT (30 * PR_MSEC_PER_SEC)
56 static PRLogModuleInfo* gGSTMetadataLog = nsnull;
59 if (!gGSTMetadataLog) \
60 gGSTMetadataLog = PR_NewLogModule("gstmetadata"); \
61 PR_LOG(gGSTMetadataLog, PR_LOG_DEBUG, args); \
65 if (!gGSTMetadataLog) \
66 gGSTMetadataLog = PR_NewLogModule("gstmetadata"); \
67 PR_LOG(gGSTMetadataLog, PR_LOG_WARN, args); \
77 gst_object_unref(mValue),
82 gst_object_unref(mValue),
87 gst_object_unref(mValue),
105 sbGStreamerMetadataHandler::~sbGStreamerMetadataHandler()
109 nsAutoLock::DestroyLock(
mLock);
117 TRACE((__FUNCTION__));
118 mLock = nsAutoLock::NewLock(
"sbGStreamerMetadataHandler::mLock");
119 NS_ENSURE_TRUE(
mLock, NS_ERROR_OUT_OF_MEMORY);
123 nsCOMPtr<nsISupports> gstService =
125 NS_ENSURE_SUCCESS(rv, rv);
132 sbGStreamerMetadataHandler::GetContractID(nsACString &aContractID)
142 TRACE((__FUNCTION__));
143 NS_ENSURE_ARG_POINTER(aProps);
145 NS_ENSURE_STATE(*aProps);
153 TRACE((__FUNCTION__));
155 return NS_ERROR_NOT_IMPLEMENTED;
160 sbGStreamerMetadataHandler::GetCompleted(PRBool *aCompleted)
162 TRACE((__FUNCTION__));
163 NS_ENSURE_ARG_POINTER(aCompleted);
165 TRACE((
"%s: completed? %s", __FUNCTION__, *aCompleted ?
"true" :
"false"));
171 sbGStreamerMetadataHandler::GetRequiresMainThread(PRBool *aRequiresMainThread)
173 TRACE((__FUNCTION__));
174 NS_ENSURE_ARG_POINTER(aRequiresMainThread);
177 *aRequiresMainThread = PR_TRUE;
183 sbGStreamerMetadataHandler::GetChannel(
nsIChannel * *aChannel)
185 TRACE((__FUNCTION__));
186 NS_ENSURE_ARG_POINTER(aChannel);
192 sbGStreamerMetadataHandler::SetChannel(
nsIChannel * aChannel)
194 TRACE((__FUNCTION__));
197 NS_ENSURE_SUCCESS(rv, rv);
199 nsAutoLock lock(
mLock);
202 nsCOMPtr<nsIURI>
uri;
203 rv =
mChannel->GetURI(getter_AddRefs(uri));
204 NS_ENSURE_SUCCESS(rv, rv);
206 rv = uri->GetSpec(
mSpec);
207 NS_ENSURE_SUCCESS(rv, rv);
209 mSpec.SetIsVoid(PR_TRUE);
217 TRACE((__FUNCTION__));
222 rv = aEnum->HasMore(&hasMore);
223 NS_ENSURE_SUCCESS(rv, PR_FALSE);
229 rv = aEnum->GetNext(
string);
230 NS_ENSURE_SUCCESS(rv, PR_FALSE);
232 string.Insert(
'.', 0);
233 if (aHaystack.Find(
string, CaseInsensitiveCompare) >= 0) {
243 sbGStreamerMetadataHandler::Vote(
const nsAString & aUrl, PRInt32 *_retval)
245 TRACE((__FUNCTION__));
246 NS_ENSURE_ARG_POINTER(_retval);
249 nsCString
url = NS_ConvertUTF16toUTF8(aUrl);
252 PRInt32 colonPos = url.Find(
":");
253 NS_ENSURE_TRUE(colonPos >= 0,
NS_OK);
254 nsCString proto = PromiseFlatCString(StringHead(url, colonPos));
255 gboolean protoSupported =
256 gst_uri_protocol_is_supported(GST_URI_SRC, proto.get());
257 if (!protoSupported) {
258 TRACE((
"%s: protocol %s not supported", __FUNCTION__, proto.get()));
268 nsAutoLock lock(
mLock);
271 NS_ENSURE_SUCCESS(rv, rv);
275 nsCOMPtr<sbIMediacoreCapabilities> caps;
276 rv =
mFactory->GetCapabilities(getter_AddRefs(caps));
277 NS_ENSURE_SUCCESS(rv, rv);
279 nsCOMPtr<nsIStringEnumerator>
strings;
280 PRBool found = PR_FALSE;
281 rv = caps->GetAudioExtensions(getter_AddRefs(strings));
282 if (NS_SUCCEEDED(rv) && strings) {
285 rv = caps->GetVideoExtensions(getter_AddRefs(strings));
286 if (NS_SUCCEEDED(rv) && strings) {
289 rv = caps->GetImageExtensions(getter_AddRefs(strings));
290 if (NS_SUCCEEDED(rv) && strings) {
294 TRACE((
"%s: failed to match any supported extensions", __FUNCTION__));
306 sbGStreamerMetadataHandler::Read(PRInt32 *_retval)
308 TRACE((__FUNCTION__));
309 NS_ENSURE_ARG_POINTER(_retval);
314 NS_ENSURE_SUCCESS(rv, rv);
316 sbGstElement decodeBin, pipeline;
318 GstStateChangeReturn stateReturn;
321 nsAutoLock lock(
mLock);
324 mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
325 NS_ENSURE_SUCCESS(rv, rv);
327 nsCOMPtr<nsITimerCallback> timerCallback =
329 rv =
mTimer->InitWithCallback(timerCallback,
331 nsITimer::TYPE_ONE_SHOT);
332 NS_ENSURE_SUCCESS(rv, rv);
335 rv = NS_ERROR_OUT_OF_MEMORY;
336 NS_ASSERTION(!
mPipeline,
"pipeline already exists!");
342 pipeline = gst_pipeline_new(
"metadata-pipeline");
345 NS_ENSURE_TRUE(pipeline, NS_ERROR_OUT_OF_MEMORY);
347 decodeBin = gst_element_factory_make(
"uridecodebin",
"metadata-decodebin");
348 NS_ENSURE_TRUE(decodeBin, NS_ERROR_OUT_OF_MEMORY);
349 gst_bin_add(GST_BIN_CAST(pipeline.get()), decodeBin.get());
350 gst_object_ref(decodeBin.get());
352 bus = gst_pipeline_get_bus(GST_PIPELINE_CAST(pipeline.get()));
353 NS_ENSURE_TRUE(bus, NS_ERROR_FAILURE);
355 g_signal_connect(decodeBin.get(),
"pad-added", G_CALLBACK(
on_pad_added),
this);
359 g_object_set(pipeline.get(),
"auto-flush-bus", FALSE, NULL);
366 TRACE((
"%s: Setting URI to [%s]", __FUNCTION__,
mSpec.get()));
367 g_object_set(G_OBJECT(decodeBin.get()),
"uri",
mSpec.get(), NULL);
369 stateReturn = gst_element_set_state(pipeline.get(), GST_STATE_PAUSED);
370 NS_ENSURE_TRUE(stateReturn == GST_STATE_CHANGE_SUCCESS ||
371 stateReturn == GST_STATE_CHANGE_ASYNC,
376 nsAutoLock lock(
mLock);
385 sbGStreamerMetadataHandler::Write(PRInt32 *_retval)
387 TRACE((__FUNCTION__));
388 return NS_ERROR_NOT_IMPLEMENTED;
395 sbGStreamerMetadataHandler::GetImageData(PRInt32 aType, nsACString & aMimeType,
396 PRUint32 *aDataLen, PRUint8 **
aData)
398 TRACE((__FUNCTION__));
399 return NS_ERROR_NOT_IMPLEMENTED;
404 sbGStreamerMetadataHandler::SetImageData(PRInt32 aType,
const nsAString & aUrl)
406 TRACE((__FUNCTION__));
407 return NS_ERROR_NOT_IMPLEMENTED;
412 sbGStreamerMetadataHandler::OnChannelData(
nsISupports *aChannel)
414 TRACE((__FUNCTION__));
416 return NS_ERROR_NOT_IMPLEMENTED;
421 sbGStreamerMetadataHandler::Close()
423 TRACE((__FUNCTION__));
424 GstElement *pipeline = NULL;
427 nsAutoLock lock(
mLock);
431 gst_object_ref(pipeline);
434 nsresult rv =
mTimer->Cancel();
436 NS_WARNING(
"Failed to cancel metadata timeout timer");
443 gst_element_set_state (pipeline, GST_STATE_NULL);
444 gst_object_unref (pipeline);
447 nsAutoLock lock(
mLock);
454 NS_ASSERTION(GST_IS_TAG_LIST(
mTags),
"tags is not a tag list!?");
455 gst_tag_list_free (
mTags);
461 nsCOMPtr<nsIThread> mainThread;
462 rv = NS_GetMainThread(getter_AddRefs(mainThread));
463 NS_ENSURE_SUCCESS(rv, rv);
465 nsCOMPtr<nsIEventTarget> mainTarget = do_QueryInterface(mainThread, &rv);
466 NS_ENSURE_SUCCESS(rv, rv);
471 nsAutoLock lock(
mLock);
475 rv = NS_ProxyRelease(mainTarget, channel);
476 NS_ENSURE_SUCCESS(rv, rv);
479 TRACE((
"%s: successfully closed", __FUNCTION__));
488 TRACE((
"%s: received message %s", __FUNCTION__,
489 message ? GST_MESSAGE_TYPE_NAME(message) :
"(null)"));
491 NS_ENSURE_TRUE(message, );
492 switch (GST_MESSAGE_TYPE(message)) {
493 case GST_MESSAGE_TAG:
496 case GST_MESSAGE_STATE_CHANGED: {
497 nsAutoLock lock(
mLock);
502 GstObject *src = GST_MESSAGE_SRC(message);
504 GstState oldState, newState, pendingState;
505 gst_message_parse_state_changed(message, &oldState, &newState,
507 TRACE((
"%s: state %s -> %s (-> %s)", __FUNCTION__,
508 gst_element_state_get_name(oldState),
509 gst_element_state_get_name(newState),
510 gst_element_state_get_name(pendingState)));
511 if (newState == GST_STATE_PAUSED) {
512 TRACE((
"%s: Successfully paused", __FUNCTION__));
517 nsAutoUnlock unlock(
mLock);
521 NS_ENSURE_SUCCESS(rv, );
522 NS_ENSURE_SUCCESS(rv2, );
527 case GST_MESSAGE_ELEMENT: {
528 if (gst_is_missing_plugin_message(message)) {
531 const gchar *type = gst_structure_get_string(message->structure,
"type");
532 if (type && !strcmp(type,
"decoder")) {
534 const GValue *
val = gst_structure_get_value (message->structure,
"detail");
535 const GstCaps *caps = gst_value_get_caps (val);
536 GstStructure *structure = gst_caps_get_structure (caps, 0);
537 const gchar *capsname = gst_structure_get_name (structure);
539 if (g_str_has_prefix(capsname,
"video/")) {
546 case GST_MESSAGE_ERROR: {
547 GError *gerror = NULL;
548 gchar *debugMessage = NULL;
549 gst_message_parse_error(message, &gerror, &debugMessage);
550 LOG((
"%s: GStreamer error: %s / %s", __FUNCTION__, gerror->message, debugMessage));
551 g_error_free (gerror);
552 g_free (debugMessage);
556 if (GST_IS_ELEMENT (message->src)) {
557 GstElementClass *elementclass = GST_ELEMENT_CLASS (
558 G_OBJECT_GET_CLASS (message->src));
559 GstElementFactory *factory = elementclass->elementfactory;
561 if (strstr (factory->details.klass,
"Video") &&
562 strstr (factory->details.klass,
"Decoder"))
568 nsAutoLock lock(
mLock);
574 nsAutoUnlock unlock(
mLock);
578 NS_ENSURE_SUCCESS(rv, );
579 NS_ENSURE_SUCCESS(rv2, );
600 TRACE((__FUNCTION__));
602 sbGstElement queue, sink, pipeline;
603 sbGstPad queueSink, oldPad, pad;
605 NS_ENSURE_TRUE(
self, );
607 nsAutoLock lock(
self->mLock);
608 if (
self->mCompleted) {
609 NS_WARNING(
"pad added after completion (or abort)");
612 NS_ENSURE_TRUE(
self->mPipeline, );
613 pipeline = GST_ELEMENT(gst_object_ref(
self->mPipeline));
615 NS_ENSURE_TRUE(pipeline, );
618 queue = gst_element_factory_make(
"queue", NULL);
619 NS_ENSURE_TRUE(queue, );
621 sink = gst_element_factory_make(
"fakesink", NULL);
622 NS_ENSURE_TRUE(sink, );
625 gst_object_ref(queue.get());
626 gst_object_ref(sink.get());
627 gst_bin_add_many(GST_BIN_CAST(pipeline.get()), queue.get(), sink.get(), NULL);
629 gst_element_set_state(queue.get(), GST_STATE_PAUSED);
630 gst_element_set_state(sink.get(), GST_STATE_PAUSED);
632 queueSink = gst_element_get_static_pad(queue.get(),
"sink");
633 NS_ENSURE_TRUE(queueSink, );
635 GstPadLinkReturn linkResult;
636 linkResult = gst_pad_link(newPad, queueSink.get());
637 NS_ENSURE_TRUE(GST_PAD_LINK_OK == linkResult, );
640 succeeded = gst_element_link_pads(queue.get(),
"src", sink.get(),
"sink");
641 NS_ENSURE_TRUE(succeeded, );
647 pad = (GstPad*)gst_object_ref(newPad);
648 while (GST_IS_GHOST_PAD(pad.get())) {
649 oldPad = pad.forget();
650 pad = gst_ghost_pad_get_target(GST_GHOST_PAD(oldPad.get()));
665 gboolean success = gst_structure_get_int(aStruct, aFieldName, &value);
667 nsString stringValue;
668 stringValue.AppendInt(value);
669 nsresult rv = aProps->AppendProperty(NS_ConvertASCIItoUTF16(aPropName),
671 NS_ENSURE_SUCCESS(rv, );
672 TRACE((
"%s: %s = %s", __FUNCTION__, aPropName,
673 NS_LossyConvertUTF16toASCII(stringValue).
get()));
682 TRACE((__FUNCTION__));
683 nsAutoLock lock(
self->mLock);
684 if (
self->mCompleted) {
685 NS_WARNING(
"caps changed after completion (or abort)");
688 GstStructure* capStruct = NULL;
689 sbGstCaps caps = gst_pad_get_negotiated_caps(pad);
692 TRACE((
"%s: no caps yet", __FUNCTION__));
696 char *capsString = gst_caps_to_string(caps.get());
697 const gchar *capName;
698 TRACE((
"%s: caps are %s", __FUNCTION__, capsString));
703 NS_ENSURE_TRUE(gst_caps_get_size(caps.get()) > 0, );
704 capStruct = gst_caps_get_structure(caps.get(), 0);
705 NS_ENSURE_TRUE(capStruct, );
706 if (!
self->mProperties) {
710 NS_ENSURE_SUCCESS(rv, );
712 NS_ENSURE_TRUE(
self->mProperties, );
714 capName = gst_structure_get_name(capStruct);
715 if (g_str_has_prefix(capName,
"audio/")) {
720 self->mHasAudio = PR_TRUE;
721 }
else if (g_str_has_prefix(capName,
"video/")) {
722 self->mHasVideo = PR_TRUE;
729 TRACE((__FUNCTION__));
730 GstTagList *tag_list = NULL;
732 nsAutoLock lock(
mLock);
734 NS_WARNING(
"tag message after completion (or abort)");
738 gst_message_parse_tag(message, &tag_list);
741 GstTagList *newTags = gst_tag_list_merge (
mTags, tag_list,
742 GST_TAG_MERGE_REPLACE);
743 gst_tag_list_free (
mTags);
747 mTags = gst_tag_list_copy (tag_list);
749 gst_tag_list_free(tag_list);
755 TRACE((
"%s[%p]", __FUNCTION__,
this));
762 NS_ENSURE_SUCCESS(rv, rv);
765 if (aSucceeded &&
mTags) {
766 nsCOMPtr<sbIPropertyArray> propArray;
768 NS_ENSURE_SUCCESS(rv, rv );
772 rv = propArray->GetLength(&newLength);
773 NS_ENSURE_SUCCESS(rv, rv);
775 for (PRUint32
i = 0 ;
i < newLength; ++
i) {
776 nsCOMPtr<sbIProperty> prop;
777 rv = propArray->GetPropertyAt(
i, getter_AddRefs(prop));
778 NS_ENSURE_SUCCESS(rv, rv);
781 rv = prop->GetId(
id);
782 NS_ENSURE_SUCCESS(rv, rv);
783 rv = prop->GetValue(value);
784 NS_ENSURE_SUCCESS(rv, rv);
787 NS_ENSURE_SUCCESS(rv, rv);
791 nsString contentType;
793 TRACE((
"%s[%p]: file %s is video",
794 __FUNCTION__,
this,
mSpec.get()));
795 contentType = NS_LITERAL_STRING(
"video");
798 TRACE((
"%s[%p]: file %s is audio",
799 __FUNCTION__,
this,
mSpec.get()));
800 contentType = NS_LITERAL_STRING(
"audio");
806 nsCOMPtr<sbIMediacoreCapabilities> caps;
807 rv =
mFactory->GetCapabilities(getter_AddRefs(caps));
808 NS_ENSURE_SUCCESS(rv, rv);
810 nsCOMPtr<nsIStringEnumerator>
strings;
811 PRBool found = PR_FALSE;
812 rv = caps->GetVideoExtensions(getter_AddRefs(strings));
813 if (NS_SUCCEEDED(rv) && strings) {
817 TRACE((
"%s[%p]: file %s found via fallback to be video",
818 __FUNCTION__,
this,
mSpec.get()));
820 contentType = NS_LITERAL_STRING(
"video");
823 TRACE((
"%s[%p]: file %s found via fallback to be not video",
824 __FUNCTION__,
this,
mSpec.get()));
828 if (!contentType.IsEmpty()) {
831 NS_ENSURE_SUCCESS(rv, rv);
838 sbGStreamerMetadataHandler::Notify(nsITimer* aTimer)
840 TRACE((__FUNCTION__));
845 nsCOMPtr<sbIMetadataHandler> kungFuDeathGrip(
this);
848 nsAutoLock lock(
mLock);
853 NS_ENSURE_SUCCESS(rv, rv);
#define SB_PROPERTY_SAMPLERATE
#define SB_PROPERTY_CHANNELS
function succeeded(ch, cx, status, data)
#define SBGSTREAMERSERVICE_CONTRACTID
An interface to carry around arrays of nsIProperty instances Note that implementations of the interfa...
#define SB_PROPERTY_CONTENTTYPE
this _dialogInput val(dateText)
StringArrayEnumerator prototype hasMore
_getSelectedPageStyle s i
_updateTextAndScrollDataForFrame aData