27 #include <sbIGStreamerService.h>
29 #include <sbFileUtils.h>
38 #include <nsServiceManagerUtils.h>
39 #include <nsThreadUtils.h>
40 #include <nsStringAPI.h>
41 #include <nsUnicharUtils.h>
42 #include <nsArrayUtils.h>
43 #include <nsNetUtil.h>
47 #include <nsIFileURL.h>
48 #include <nsIBinaryInputStream.h>
49 #include <sbIMediaItem.h>
50 #include <nsIProperty.h>
52 #include <gst/tag/tag.h>
56 #define PROGRESS_INTERVAL 200
63 static PRLogModuleInfo* gGStreamerVideoTranscode =
64 PR_NewLogModule(
"sbGStreamerVideoTranscode");
65 #define LOG(args) PR_LOG(gGStreamerVideoTranscode, PR_LOG_WARNING, args)
66 #define TRACE(args) PR_LOG(gGStreamerVideoTranscode, PR_LOG_DEBUG, args)
93 sbGStreamerVideoTranscoder::sbGStreamerVideoTranscoder() :
96 mPipelineBuilt(PR_FALSE),
97 mWaitingForCaps(PR_FALSE),
100 mAudioQueueSrc(NULL),
101 mVideoQueueSrc(NULL),
106 TRACE((
"%s[%p]", __FUNCTION__,
this));
108 mBuildLock = nsAutoLock::NewLock(
"VideoTranscoder lock");
109 NS_ENSURE_TRUE (mBuildLock, );
112 sbGStreamerVideoTranscoder::~sbGStreamerVideoTranscoder()
114 TRACE((
"%s[%p]", __FUNCTION__,
this));
116 nsresult rv = CleanupPipeline();
117 NS_ENSURE_SUCCESS (rv, );
120 nsAutoLock::DestroyLock(mBuildLock);
127 sbGStreamerVideoTranscoder::Notify(nsITimer *aTimer)
129 TRACE((
"%s[%p]", __FUNCTION__,
this));
131 NS_ENSURE_ARG_POINTER(aTimer);
141 sbGStreamerVideoTranscoder::SetConfigurator(
144 TRACE((
"%s[%p]", __FUNCTION__,
this));
146 mConfigurator = aConfigurator;
151 sbGStreamerVideoTranscoder::GetConfigurator(
154 TRACE((
"%s[%p]", __FUNCTION__,
this));
155 NS_ENSURE_ARG_POINTER(aConfigurator);
157 NS_IF_ADDREF (*aConfigurator = mConfigurator);
163 sbGStreamerVideoTranscoder::SetSourceURI(
const nsAString& aSourceURI)
165 TRACE((
"%s[%p]", __FUNCTION__,
this));
168 NS_ENSURE_STATE (!mPipelineBuilt);
170 mSourceURI = aSourceURI;
178 sbGStreamerVideoTranscoder::GetSourceURI(nsAString& aSourceURI)
180 TRACE((
"%s[%p]", __FUNCTION__,
this));
182 aSourceURI = mSourceURI;
187 sbGStreamerVideoTranscoder::SetDestURI(
const nsAString& aDestURI)
189 TRACE((
"%s[%p]", __FUNCTION__,
this));
192 NS_ENSURE_STATE (!mPipelineBuilt);
199 sbGStreamerVideoTranscoder::GetDestURI(nsAString& aDestURI)
201 TRACE((
"%s[%p]", __FUNCTION__,
this));
208 sbGStreamerVideoTranscoder::GetDestStream(nsIOutputStream **aStream)
210 TRACE((
"%s[%p]", __FUNCTION__,
this));
212 NS_ENSURE_ARG_POINTER(aStream);
214 NS_IF_ADDREF(*aStream = mDestStream);
219 sbGStreamerVideoTranscoder::SetDestStream(nsIOutputStream *aStream)
221 TRACE((
"%s[%p]", __FUNCTION__,
this));
224 NS_ENSURE_STATE (!mPipelineBuilt);
226 mDestStream = aStream;
234 TRACE((
"%s[%p]", __FUNCTION__,
this));
236 NS_ENSURE_ARG_POINTER(aMetadata);
238 NS_IF_ADDREF(*aMetadata = mMetadata);
245 TRACE((
"%s[%p]", __FUNCTION__,
this));
248 NS_ENSURE_STATE (!mPipelineBuilt);
250 mMetadata = aMetadata;
255 sbGStreamerVideoTranscoder::GetMetadataImage(nsIInputStream **aImageStream)
257 TRACE((
"%s[%p]", __FUNCTION__,
this));
259 NS_ENSURE_ARG_POINTER(aImageStream);
262 NS_ENSURE_STATE (!mPipelineBuilt);
264 NS_IF_ADDREF(*aImageStream = mImageStream);
269 sbGStreamerVideoTranscoder::SetMetadataImage(nsIInputStream *aImageStream)
271 TRACE((
"%s[%p]", __FUNCTION__,
this));
274 NS_ENSURE_STATE (!mPipelineBuilt);
276 mImageStream = aImageStream;
281 sbGStreamerVideoTranscoder::Vote(
sbIMediaItem *aMediaItem, PRInt32 *aVote)
283 TRACE((
"%s[%p]", __FUNCTION__,
this));
285 NS_ENSURE_ARG_POINTER(aVote);
287 nsString contentType;
288 nsresult rv = aMediaItem->GetContentType(contentType);
289 NS_ENSURE_SUCCESS(rv, rv);
292 if (contentType.EqualsLiteral(
"video") ||
293 contentType.EqualsLiteral(
"audio"))
307 TRACE((
"%s[%p]", __FUNCTION__,
this));
309 NS_ENSURE_STATE (!mPipelineBuilt);
311 nsresult rv = BuildTranscodePipeline (
"transcode-pipeline");
312 NS_ENSURE_SUCCESS (rv, rv);
320 sbGStreamerVideoTranscoder::Transcode()
322 TRACE((
"%s[%p]", __FUNCTION__,
this));
324 nsresult rv = ClearStatus();
325 NS_ENSURE_SUCCESS (rv, rv);
329 NS_ENSURE_STATE (!mPipelineBuilt);
338 TRACE((
"%s[%p]", __FUNCTION__,
this));
342 rv = sbGStreamerPipeline::PlayPipeline();
343 NS_ENSURE_SUCCESS (rv, rv);
345 rv = StartProgressReporting();
346 NS_ENSURE_SUCCESS (rv, rv);
355 TRACE((
"%s[%p]", __FUNCTION__,
this));
359 rv = sbGStreamerPipeline::StopPipeline();
360 NS_ENSURE_SUCCESS (rv, rv);
362 rv = StopProgressReporting();
363 NS_ENSURE_SUCCESS (rv, rv);
367 rv = CleanupPipeline();
370 rv = OnJobProgress();
371 NS_ENSURE_SUCCESS (rv, rv);
379 sbGStreamerVideoTranscoder::GetCanCancel(PRBool *aCanCancel)
381 TRACE((
"%s[%p]", __FUNCTION__,
this));
383 NS_ENSURE_ARG_POINTER(aCanCancel);
385 *aCanCancel = PR_TRUE;
390 sbGStreamerVideoTranscoder::Cancel()
392 TRACE((
"%s[%p]", __FUNCTION__,
this));
397 NS_ENSURE_SUCCESS (rv, rv);
405 sbGStreamerVideoTranscoder::GetElapsedTime(PRUint32 *aElapsedTime)
407 TRACE((
"%s[%p]", __FUNCTION__,
this));
409 NS_ENSURE_ARG_POINTER(aElapsedTime);
412 *aElapsedTime =
static_cast<PRUint32
>(
GetRunningTime() / GST_MSECOND);
418 sbGStreamerVideoTranscoder::GetRemainingTime(PRUint32 *aRemainingTime)
420 TRACE((
"%s[%p]", __FUNCTION__,
this));
422 GstClockTime
duration = QueryDuration();
423 GstClockTime
position = QueryPosition();
426 if (duration == GST_CLOCK_TIME_NONE || position == GST_CLOCK_TIME_NONE ||
427 elapsed == GST_CLOCK_TIME_NONE)
430 *aRemainingTime = (PRUint32)-1;
433 GstClockTime totalTime = gst_util_uint64_scale (elapsed, duration,
437 static_cast<PRUint32
>((totalTime - elapsed) / GST_MSECOND);
444 sbGStreamerVideoTranscoder::GetStatus(PRUint16 *aStatus)
446 NS_ENSURE_ARG_POINTER(aStatus);
454 sbGStreamerVideoTranscoder::GetBlocked(PRBool *aBlocked)
456 NS_ENSURE_ARG_POINTER(aBlocked);
458 *aBlocked = PR_FALSE;
464 sbGStreamerVideoTranscoder::GetStatusText(nsAString& aText)
466 TRACE((
"%s[%p]", __FUNCTION__,
this));
468 nsresult rv = NS_ERROR_FAILURE;
473 NS_LITERAL_STRING(
"mediacore.gstreamer.transcode.failed"));
477 NS_LITERAL_STRING(
"mediacore.gstreamer.transcode.succeeded"));
481 NS_LITERAL_STRING(
"mediacore.gstreamer.transcode.running"));
484 NS_NOTREACHED(
"Status is invalid");
491 sbGStreamerVideoTranscoder::GetTitleText(nsAString& aText)
493 TRACE((
"%s[%p]", __FUNCTION__,
this));
496 NS_LITERAL_STRING(
"mediacore.gstreamer.transcode.title"));
500 sbGStreamerVideoTranscoder::GetProgress(PRUint32* aProgress)
502 TRACE((
"%s[%p]", __FUNCTION__,
this));
504 NS_ENSURE_ARG_POINTER(aProgress);
506 GstClockTime duration = QueryDuration();
507 GstClockTime position = QueryPosition();
509 if (duration != GST_CLOCK_TIME_NONE && position != GST_CLOCK_TIME_NONE &&
513 *aProgress = (PRUint32)gst_util_uint64_scale (position, 1000, duration);
523 sbGStreamerVideoTranscoder::GetTotal(PRUint32* aTotal)
525 TRACE((
"%s[%p]", __FUNCTION__,
this));
527 NS_ENSURE_ARG_POINTER(aTotal);
529 GstClockTime duration = QueryDuration();
534 if (duration != GST_CLOCK_TIME_NONE) {
547 sbGStreamerVideoTranscoder::GetErrorCount(PRUint32* aErrorCount)
549 TRACE((
"%s[%p]", __FUNCTION__,
this));
551 NS_ENSURE_ARG_POINTER(aErrorCount);
552 NS_ASSERTION(NS_IsMainThread(),
553 "sbIJobProgress::GetErrorCount is main thread only!");
555 *aErrorCount = mErrors.Length();
563 TRACE((
"%s[%p]", __FUNCTION__,
this));
565 NS_ENSURE_ARG_POINTER(aMessages);
566 NS_ASSERTION(NS_IsMainThread(),
567 "sbIJobProgress::GetProgress is main thread only!");
573 nsRefPtr<sbJobErrorEnumerator<sbITranscodeError> > enumerator =
574 new sbJobErrorEnumerator<sbITranscodeError>(mErrors);
575 rv = CallQueryInterface(enumerator.get(), aMessages);
576 NS_ENSURE_SUCCESS(rv, rv);
584 TRACE((
"%s[%p]", __FUNCTION__,
this));
586 NS_ENSURE_ARG_POINTER(aListener);
587 NS_ASSERTION(NS_IsMainThread(), \
588 "sbGStreamerVideoTranscoder::AddJobProgressListener is main thread only!");
590 PRInt32 index = mProgressListeners.IndexOf(aListener);
593 return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
595 PRBool
succeeded = mProgressListeners.AppendObject(aListener);
596 NS_ENSURE_TRUE(succeeded, NS_ERROR_FAILURE);
602 sbGStreamerVideoTranscoder::RemoveJobProgressListener(
605 TRACE((
"%s[%p]", __FUNCTION__,
this));
607 NS_ENSURE_ARG_POINTER(aListener);
608 NS_ASSERTION(NS_IsMainThread(), \
609 "sbGStreamerVideoTranscoder::RemoveJobProgressListener is main thread only!");
611 PRInt32 indexToRemove = mProgressListeners.IndexOf(aListener);
612 if (indexToRemove < 0) {
618 PRBool succeeded = mProgressListeners.RemoveObjectAt(indexToRemove);
619 NS_ENSURE_TRUE(succeeded, NS_ERROR_FAILURE);
626 sbGStreamerVideoTranscoder::OnJobProgress()
628 TRACE((
"%s[%p]", __FUNCTION__,
this));
630 NS_ASSERTION(NS_IsMainThread(), \
631 "sbGStreamerVideoTranscoder::OnJobProgress is main thread only!");
634 for (PRInt32
i = mProgressListeners.Count() - 1;
i >= 0; --
i) {
636 mProgressListeners[
i]->OnJobProgress(
this);
641 void sbGStreamerVideoTranscoder::HandleErrorMessage(GstMessage *
message)
643 TRACE((
"%s[%p]", __FUNCTION__,
this));
645 GError *gerror = NULL;
651 gst_message_parse_error(message, &gerror, &debug);
653 nsCOMPtr<sbITranscodeError> errorObj;
655 NS_ConvertUTF8toUTF16(gerror->message),
659 getter_AddRefs(errorObj));
660 if (NS_SUCCEEDED(rv)) {
661 mErrors.AppendElement(errorObj);
664 g_error_free (gerror);
671 void sbGStreamerVideoTranscoder::HandleEOSMessage(GstMessage *message)
673 TRACE((
"%s[%p]", __FUNCTION__,
this));
681 GstClockTime sbGStreamerVideoTranscoder::QueryPosition()
683 TRACE((
"%s[%p]", __FUNCTION__,
this));
686 gint64 position = GST_CLOCK_TIME_NONE;
691 query = gst_query_new_position(GST_FORMAT_TIME);
694 gst_query_parse_position(query, NULL, &position);
696 gst_query_unref (query);
701 GstClockTime sbGStreamerVideoTranscoder::QueryDuration()
703 TRACE((
"%s[%p]", __FUNCTION__,
this));
706 gint64 duration = GST_CLOCK_TIME_NONE;
711 query = gst_query_new_duration(GST_FORMAT_TIME);
714 gst_query_parse_duration(query, NULL, &duration);
716 gst_query_unref (query);
722 sbGStreamerVideoTranscoder::StartProgressReporting()
724 TRACE((
"%s[%p]", __FUNCTION__,
this));
726 NS_ENSURE_STATE(!mProgressTimer);
730 do_CreateInstance(
"@mozilla.org/timer;1", &rv);
731 NS_ENSURE_SUCCESS(rv, rv);
733 mProgressTimer->InitWithCallback(
this,
740 sbGStreamerVideoTranscoder::StopProgressReporting()
742 TRACE((
"%s[%p]", __FUNCTION__,
this));
744 if (mProgressTimer) {
745 mProgressTimer->Cancel();
746 mProgressTimer = nsnull;
753 sbGStreamerVideoTranscoder::AsyncStopPipeline()
756 NS_ENSURE_SUCCESS (rv, );
760 sbGStreamerVideoTranscoder::TranscodingFatalError (
const char *errorName)
762 TRACE((
"%s[%p]", __FUNCTION__,
this));
766 nsString message = bundle.
Get(errorName);
769 nsCOMPtr<sbITranscodeError> errorObj;
773 getter_AddRefs(errorObj));
774 if (NS_SUCCEEDED(rv)) {
775 mErrors.AppendElement(errorObj);
778 nsRefPtr<sbMediacoreError> error;
781 NS_ENSURE_TRUE (error, );
790 nsCOMPtr<nsIRunnable>
event = NS_NEW_RUNNABLE_METHOD (
793 rv = NS_DispatchToMainThread(
event, NS_DISPATCH_NORMAL);
794 NS_ENSURE_SUCCESS (rv, );
798 sbGStreamerVideoTranscoder::AddImageToTagList(GstTagList *aTags,
799 nsIInputStream *aStream)
801 TRACE((
"%s[%p]", __FUNCTION__,
this));
803 PRUint32 imageDataLen;
807 nsCOMPtr<nsIBinaryInputStream> stream =
808 do_CreateInstance(
"@mozilla.org/binaryinputstream;1", &rv);
809 NS_ENSURE_SUCCESS(rv, rv);
811 rv = stream->SetInputStream(aStream);
812 NS_ENSURE_SUCCESS(rv, rv);
814 rv = aStream->Available(&imageDataLen);
815 NS_ENSURE_SUCCESS(rv, rv);
817 rv = stream->ReadByteArray(imageDataLen, &imageData);
818 NS_ENSURE_SUCCESS(rv, rv);
822 GstBuffer *imagebuf = gst_tag_image_data_to_image_buffer (
823 imageData, imageDataLen, GST_TAG_IMAGE_TYPE_FRONT_COVER);
825 return NS_ERROR_FAILURE;
827 gst_tag_list_add (aTags, GST_TAG_MERGE_REPLACE, GST_TAG_IMAGE,
829 gst_buffer_unref (imagebuf);
836 sbGStreamerVideoTranscoder::SetMetadataOnTagSetters()
838 TRACE((
"%s[%p]", __FUNCTION__,
this));
844 tags = gst_tag_list_new();
848 AddImageToTagList (tags, mImageStream);
853 GstIterator *it = gst_bin_iterate_all_by_interface (
854 (GstBin *)
mPipeline, GST_TYPE_TAG_SETTER);
857 while (gst_iterator_next (it, (
void **)&element) == GST_ITERATOR_OK) {
858 GstTagSetter *setter = GST_TAG_SETTER (element);
862 gst_tag_setter_merge_tags (setter, tags, GST_TAG_MERGE_REPLACE);
863 g_object_unref (element);
865 gst_iterator_free (it);
866 gst_tag_list_free (tags);
873 sbGStreamerVideoTranscoder::ClearStatus()
883 sbGStreamerVideoTranscoder::CleanupPads()
886 g_object_unref (mAudioSrc);
891 g_object_unref (mVideoSrc);
895 if (mAudioQueueSrc) {
896 g_object_unref (mAudioQueueSrc);
897 mAudioQueueSrc = NULL;
900 if (mVideoQueueSrc) {
901 g_object_unref (mVideoQueueSrc);
902 mVideoQueueSrc = NULL;
907 sbGStreamerVideoTranscoder::CleanupPipeline()
913 mPipelineBuilt = PR_FALSE;
914 mWaitingForCaps = PR_FALSE;
920 sbGStreamerVideoTranscoder::decodebin_pad_added_cb (GstElement * uridecodebin,
923 nsresult rv = transcoder->DecoderPadAdded(uridecodebin, pad);
924 NS_ENSURE_SUCCESS (rv, );
928 sbGStreamerVideoTranscoder::decodebin_no_more_pads_cb (
931 nsresult rv = transcoder->DecoderNoMorePads(uridecodebin);
932 NS_ENSURE_SUCCESS (rv, );
936 sbGStreamerVideoTranscoder::pad_blocked_cb (GstPad * pad, gboolean blocked,
939 nsresult rv = transcoder->PadBlocked(pad, blocked);
940 NS_ENSURE_SUCCESS (rv, );
944 sbGStreamerVideoTranscoder::pad_notify_caps_cb (GObject *obj, GParamSpec *pspec,
947 nsresult rv = transcoder->PadNotifyCaps (GST_PAD (obj));
948 NS_ENSURE_SUCCESS (rv, );
952 sbGStreamerVideoTranscoder::DecoderPadAdded (GstElement *uridecodebin,
955 TRACE((
"%s[%p]", __FUNCTION__,
this));
965 if (mPipelineBuilt) {
966 LOG((
"pad-added after pipeline fully constructed; cannot use"));
967 return NS_ERROR_FAILURE;
970 GstCaps *caps = gst_pad_get_caps (pad);
971 GstStructure *structure = gst_caps_get_structure (caps, 0);
972 const gchar *
name = gst_structure_get_name (structure);
973 bool isVideo = g_str_has_prefix (name,
"video/");
974 bool isAudio = g_str_has_prefix (name,
"audio/");
976 gst_caps_unref (caps);
980 LOG((
"Multiple audio streams: ignoring subsequent ones"));
987 if (!mTranscoderConfigurator->SupportsAudio()) {
988 LOG((
"Transcoder not configured to support audio, ignoring stream"));
993 LOG((
"Using audio pad %s:%s for audio stream", GST_DEBUG_PAD_NAME (pad)));
994 gst_object_ref (pad);
999 LOG((
"Multiple video streams: ignoring subsequent ones"));
1005 if (!mTranscoderConfigurator->SupportsVideo()) {
1006 LOG((
"Transcoder not configured to support video, ignoring stream"));
1011 LOG((
"Using video pad %s:%s for video stream", GST_DEBUG_PAD_NAME (pad)));
1012 gst_object_ref (pad);
1016 LOG((
"Ignoring non-audio, non-video stream"));
1024 sbGStreamerVideoTranscoder::ConfigureVideoBox (GstElement *videobox,
1025 GstCaps *aInputVideoCaps, gint outputWidth, gint outputHeight,
1026 gint outputParN, gint outputParD)
1028 TRACE((
"%s[%p]", __FUNCTION__,
this));
1030 gint imageWidth, imageHeight, imageParN, imageParD;
1032 GstStructure *structure = gst_caps_get_structure (aInputVideoCaps, 0);
1036 ret = gst_structure_get_int (structure,
"width", &imageWidth);
1037 NS_ASSERTION (ret,
"Invalid image caps, no width");
1038 ret = gst_structure_get_int (structure,
"height", &imageHeight);
1039 NS_ASSERTION (ret,
"Invalid image caps, no height");
1041 const GValue* par = gst_structure_get_value (structure,
1042 "pixel-aspect-ratio");
1044 imageParN = gst_value_get_fraction_numerator(par);
1045 imageParD = gst_value_get_fraction_denominator(par);
1049 imageParN = imageParD = 1;
1052 gint imageDarN = imageWidth * imageParN;
1053 gint imageDarD = imageHeight * imageParD;
1055 gint outputDarN = outputWidth * outputParN;
1056 gint outputDarD = outputHeight * outputParD;
1058 LOG((
"Determining output geometry. Output image is %dx%d (PAR %d:%d). "
1059 "Input image is %dx%d (PAR %d:%d)", outputWidth, outputHeight,
1060 outputParN, outputParD, imageWidth, imageHeight, imageParN, imageParD));
1066 if (imageDarN * outputDarD > outputDarN * imageDarD) {
1070 gint outputImageHeight = outputWidth *
1071 (imageDarD * outputParN) / (imageDarN * outputParD);
1072 gint padding = outputHeight - outputImageHeight;
1077 gint paddingBottom, paddingTop;
1078 if (padding % 4 == 0) {
1079 paddingBottom = padding / 2;
1082 paddingBottom = padding / 2 + 1;
1084 paddingTop = padding - paddingBottom;
1086 LOG((
"Padding %d pixels at top, %d pixels at bottom", paddingTop,
1090 g_object_set (videobox,
"top", -paddingTop,
"bottom", -paddingBottom, NULL);
1092 else if (imageDarN * outputDarD < outputDarN * imageDarD) {
1096 gint outputImageWidth = outputHeight *
1097 (imageDarN * outputParD) / (imageDarD * outputParN);
1098 gint padding = outputWidth - outputImageWidth;
1103 gint paddingRight, paddingLeft;
1104 if (padding % 4 == 0) {
1105 paddingRight = padding / 2;
1108 paddingRight = padding / 2 + 1;
1110 paddingLeft = padding - paddingRight;
1112 LOG((
"Padding %d pixels at left, %d pixels at right", paddingLeft,
1116 g_object_set (videobox,
"left", -paddingLeft,
"right", -paddingRight, NULL);
1119 LOG((
"No padding required"));
1124 sbGStreamerVideoTranscoder::BuildVideoBin(GstCaps *aInputVideoCaps,
1125 GstElement **aVideoBin)
1127 TRACE((
"%s[%p]", __FUNCTION__,
this));
1133 GstElement *videorate = NULL;
1134 GstElement *colorspace = NULL;
1135 GstElement *videoscale = NULL;
1136 GstElement *videobox = NULL;
1137 GstElement *capsfilter = NULL;
1138 GstElement *encoder = NULL;
1139 nsCOMPtr<nsIPropertyBag> encoderProperties;
1141 PRInt32 outputWidth, outputHeight;
1142 PRUint32 outputParN, outputParD;
1143 PRUint32 outputFramerateN, outputFramerateD;
1146 nsCOMPtr<sbIMediaFormatVideo> videoFormat;
1147 rv = mConfigurator->GetVideoFormat (getter_AddRefs(videoFormat));
1148 NS_ENSURE_SUCCESS (rv, rv);
1150 rv = videoFormat->GetVideoWidth(&outputWidth);
1151 NS_ENSURE_SUCCESS (rv, rv);
1152 rv = videoFormat->GetVideoHeight(&outputHeight);
1153 NS_ENSURE_SUCCESS (rv, rv);
1154 rv = videoFormat->GetVideoPAR(&outputParN, &outputParD);
1155 NS_ENSURE_SUCCESS (rv, rv);
1156 rv = videoFormat->GetVideoFrameRate(&outputFramerateN, &outputFramerateD);
1157 NS_ENSURE_SUCCESS (rv, rv);
1161 NS_ENSURE_TRUE(outputWidth > 0, NS_ERROR_FAILURE);
1162 NS_ENSURE_TRUE(outputHeight > 0, NS_ERROR_FAILURE);
1163 NS_ENSURE_TRUE(outputParN > 0, NS_ERROR_FAILURE);
1164 NS_ENSURE_TRUE(outputParD > 0, NS_ERROR_FAILURE);
1165 NS_ENSURE_TRUE(outputFramerateN > 0, NS_ERROR_FAILURE);
1166 NS_ENSURE_TRUE(outputFramerateD > 0, NS_ERROR_FAILURE);
1169 nsString encoderName;
1170 rv = mConfigurator->GetVideoEncoder(encoderName);
1171 NS_ENSURE_SUCCESS (rv, rv);
1173 GstPad *srcpad, *sinkpad, *ghostpad;
1177 bin = GST_BIN (gst_bin_new(
"video-encode-bin"));
1178 videorate = gst_element_factory_make (
"videorate", NULL);
1179 colorspace = gst_element_factory_make (
"ffmpegcolorspace", NULL);
1180 videoscale = gst_element_factory_make (
"videoscale", NULL);
1181 videobox = gst_element_factory_make (
"videobox", NULL);
1182 capsfilter = gst_element_factory_make (
"capsfilter", NULL);
1185 if (!videorate || !colorspace || !videoscale || !videobox || !capsfilter)
1189 rv = NS_ERROR_FAILURE;
1193 if (encoderName.IsEmpty()) {
1194 LOG((
"Video enabled but no video encoder specified"));
1195 rv = NS_ERROR_FAILURE;
1199 encoder = gst_element_factory_make (
1200 NS_ConvertUTF16toUTF8(encoderName).BeginReading(), NULL);
1203 LOG((
"No encoder %s available",
1204 NS_ConvertUTF16toUTF8(encoderName).BeginReading()));
1205 TranscodingFatalError(
1206 "songbird.transcode.error.video_encoder_unavailable");
1207 rv = NS_ERROR_FAILURE;
1211 rv = mConfigurator->GetVideoEncoderProperties(
1212 getter_AddRefs(encoderProperties));
1213 if (NS_FAILED (rv)) {
1218 if (NS_FAILED (rv)) {
1223 g_object_set (videoscale,
"method", 2, NULL);
1228 caps = gst_caps_new_simple (
"video/x-raw-yuv",
1229 "width", G_TYPE_INT, outputWidth,
1230 "height", G_TYPE_INT, outputHeight,
1231 "pixel-aspect-ratio", GST_TYPE_FRACTION, outputParN, outputParD,
1232 "framerate", GST_TYPE_FRACTION, outputFramerateN, outputFramerateD,
1234 g_object_set (capsfilter,
"caps", caps, NULL);
1235 gst_caps_unref (caps);
1240 ConfigureVideoBox (videobox, aInputVideoCaps, outputWidth, outputHeight,
1241 outputParN, outputParD);
1244 gst_bin_add_many (bin, videorate, colorspace, videoscale, videobox,
1246 gst_element_link_many (videorate, colorspace, videoscale, videobox,
1251 gst_bin_add (bin, encoder);
1252 gst_element_link (capsfilter, encoder);
1256 sinkpad = gst_element_get_static_pad (videorate,
"sink");
1257 ghostpad = gst_ghost_pad_new (
"sink", sinkpad);
1258 g_object_unref (sinkpad);
1259 gst_element_add_pad (GST_ELEMENT (bin), ghostpad);
1261 srcpad = gst_element_get_static_pad (last,
"src");
1262 ghostpad = gst_ghost_pad_new (
"src", srcpad);
1263 g_object_unref (srcpad);
1264 gst_element_add_pad (GST_ELEMENT (bin), ghostpad);
1267 *aVideoBin = GST_ELEMENT (bin);
1273 g_object_unref (videorate);
1275 g_object_unref (colorspace);
1277 g_object_unref (videoscale);
1279 g_object_unref (videobox);
1281 g_object_unref (capsfilter);
1283 g_object_unref (encoder);
1285 g_object_unref (bin);
1291 sbGStreamerVideoTranscoder::GetRawAudioCaps(GstCaps **aResultCaps)
1295 nsCOMPtr<nsIPropertyBag> encoderProperties;
1296 rv = mConfigurator->GetAudioEncoderProperties(
1297 getter_AddRefs(encoderProperties));
1298 NS_ENSURE_SUCCESS(rv, rv);
1300 nsCOMPtr<nsIVariant> isFloatVar;
1301 rv = encoderProperties->GetProperty(NS_LITERAL_STRING (
"IsFloat"),
1302 getter_AddRefs(isFloatVar));
1303 NS_ENSURE_SUCCESS(rv, rv);
1305 rv = isFloatVar->GetAsBool(&isFloat);
1306 NS_ENSURE_SUCCESS(rv, rv);
1308 nsCOMPtr<nsIVariant> isLittleEndianVar;
1309 rv = encoderProperties->GetProperty(NS_LITERAL_STRING (
"LittleEndian"),
1310 getter_AddRefs(isLittleEndianVar));
1311 NS_ENSURE_SUCCESS(rv, rv);
1312 PRBool isLittleEndian;
1313 rv = isLittleEndianVar->GetAsBool(&isLittleEndian);
1314 NS_ENSURE_SUCCESS(rv, rv);
1316 nsCOMPtr<nsIVariant> sampleDepthVar;
1317 rv = encoderProperties->GetProperty(NS_LITERAL_STRING (
"Depth"),
1318 getter_AddRefs(sampleDepthVar));
1319 NS_ENSURE_SUCCESS(rv, rv);
1320 PRInt32 sampleDepth;
1321 rv = sampleDepthVar->GetAsInt32(&sampleDepth);
1322 NS_ENSURE_SUCCESS(rv, rv);
1324 PRInt32 outputRate, outputChannels;
1327 nsCOMPtr<sbIMediaFormatAudio> audioFormat;
1328 rv = mConfigurator->GetAudioFormat (getter_AddRefs(audioFormat));
1329 NS_ENSURE_SUCCESS (rv, rv);
1331 rv = audioFormat->GetSampleRate (&outputRate);
1332 NS_ENSURE_SUCCESS (rv, rv);
1333 rv = audioFormat->GetChannels (&outputChannels);
1334 NS_ENSURE_SUCCESS (rv, rv);
1336 gint32 endianness = isLittleEndian ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
1339 caps = gst_caps_new_simple (
"audio/x-raw-float",
1340 "endianness", G_TYPE_INT, endianness,
1341 "width", G_TYPE_INT, sampleDepth,
1342 "rate", G_TYPE_INT, outputRate,
1343 "channels", G_TYPE_INT, outputChannels);
1346 caps = gst_caps_new_simple (
"audio/x-raw-int",
1347 "endianness", G_TYPE_INT, endianness,
1348 "width", G_TYPE_INT, sampleDepth,
1349 "depth", G_TYPE_INT, sampleDepth,
1350 "rate", G_TYPE_INT, outputRate,
1351 "channels", G_TYPE_INT, outputChannels,
1352 "signed", G_TYPE_BOOLEAN, sampleDepth != 8);
1355 *aResultCaps = caps;
1361 sbGStreamerVideoTranscoder::BuildAudioBin(GstCaps *aInputAudioCaps,
1362 GstElement **aAudioBin)
1364 TRACE((
"%s[%p]", __FUNCTION__,
this));
1370 GstElement *audiorate = NULL;
1371 GstElement *audioconvert = NULL;
1372 GstElement *audioresample = NULL;
1373 GstElement *capsfilter = NULL;
1374 GstElement *audioresample2 = NULL;
1375 GstElement *encoder = NULL;
1377 PRInt32 outputRate, outputChannels;
1380 nsCOMPtr<sbIMediaFormatAudio> audioFormat;
1381 rv = mConfigurator->GetAudioFormat (getter_AddRefs(audioFormat));
1382 NS_ENSURE_SUCCESS (rv, rv);
1384 rv = audioFormat->GetSampleRate (&outputRate);
1385 NS_ENSURE_SUCCESS (rv, rv);
1386 rv = audioFormat->GetChannels (&outputChannels);
1387 NS_ENSURE_SUCCESS (rv, rv);
1391 NS_ENSURE_TRUE (outputRate > 0, NS_ERROR_FAILURE);
1392 NS_ENSURE_TRUE (outputChannels > 0, NS_ERROR_FAILURE);
1395 nsString encoderName;
1396 rv = mConfigurator->GetAudioEncoder(encoderName);
1397 NS_ENSURE_SUCCESS (rv, rv);
1399 GstPad *srcpad, *sinkpad, *ghostpad;
1402 GstStructure *structure;
1404 bin = GST_BIN (gst_bin_new(
"audio-encode-bin"));
1405 audiorate = gst_element_factory_make (
"audiorate", NULL);
1406 audioconvert = gst_element_factory_make (
"audioconvert", NULL);
1407 audioresample = gst_element_factory_make (
"audioresample", NULL);
1408 capsfilter = gst_element_factory_make (
"capsfilter", NULL);
1409 audioresample2 = gst_element_factory_make (
"audioresample", NULL);
1411 if (!audiorate || !audioconvert || !audioresample || !capsfilter ||
1416 rv = NS_ERROR_FAILURE;
1422 if (!encoderName.IsEmpty()) {
1423 encoder = gst_element_factory_make (
1424 NS_ConvertUTF16toUTF8 (encoderName).BeginReading(), NULL);
1426 LOG((
"No encoder %s available",
1427 NS_ConvertUTF16toUTF8(encoderName).BeginReading()));
1428 TranscodingFatalError(
1429 "songbird.transcode.error.audio_encoder_unavailable");
1430 rv = NS_ERROR_FAILURE;
1434 nsCOMPtr<nsIPropertyBag> encoderProperties;
1435 rv = mConfigurator->GetAudioEncoderProperties(
1436 getter_AddRefs(encoderProperties));
1437 if (NS_FAILED (rv)) {
1442 if (NS_FAILED (rv)) {
1455 caps = gst_caps_new_empty ();
1456 structure = gst_structure_new (
"audio/x-raw-int",
1457 "rate", G_TYPE_INT, outputRate,
1458 "channels", G_TYPE_INT, outputChannels,
1460 gst_caps_append_structure (caps, structure);
1461 structure = gst_structure_new (
"audio/x-raw-float",
1462 "rate", G_TYPE_INT, outputRate,
1463 "channels", G_TYPE_INT, outputChannels,
1465 gst_caps_append_structure (caps, structure);
1468 rv = GetRawAudioCaps(&caps);
1473 g_object_set (capsfilter,
"caps", caps, NULL);
1474 gst_caps_unref (caps);
1477 gst_bin_add_many (bin, audiorate, audioconvert, audioresample,
1478 capsfilter, audioresample2, NULL);
1479 gst_element_link_many (audiorate, audioconvert, audioresample,
1480 capsfilter, audioresample2, NULL);
1482 last = audioresample2;
1485 gst_bin_add (bin, encoder);
1486 gst_element_link (last, encoder);
1491 sinkpad = gst_element_get_static_pad (audiorate,
"sink");
1492 ghostpad = gst_ghost_pad_new (
"sink", sinkpad);
1493 g_object_unref (sinkpad);
1494 gst_element_add_pad (GST_ELEMENT (bin), ghostpad);
1496 srcpad = gst_element_get_static_pad (last,
"src");
1497 ghostpad = gst_ghost_pad_new (
"src", srcpad);
1498 g_object_unref (srcpad);
1499 gst_element_add_pad (GST_ELEMENT (bin), ghostpad);
1502 *aAudioBin = GST_ELEMENT (bin);
1508 g_object_unref (audiorate);
1510 g_object_unref (audioconvert);
1512 g_object_unref (audioresample);
1514 g_object_unref (capsfilter);
1516 g_object_unref (audioresample2);
1518 g_object_unref (encoder);
1520 g_object_unref (bin);
1526 sbGStreamerVideoTranscoder::AddAudioBin(GstPad *inputAudioSrcPad,
1527 GstPad **outputAudioSrcPad)
1529 TRACE((
"%s[%p]", __FUNCTION__,
this));
1530 NS_ENSURE_ARG_POINTER (inputAudioSrcPad);
1531 NS_ENSURE_ARG_POINTER (outputAudioSrcPad);
1536 GstElement *audioBin = NULL;
1537 GstCaps *caps = GetCapsFromPad (mAudioSrc);
1538 rv = BuildAudioBin(caps, &audioBin);
1539 gst_caps_unref (caps);
1540 NS_ENSURE_SUCCESS (rv, rv);
1542 GstPad *audioBinSinkPad = gst_element_get_pad (audioBin,
"sink");
1543 GstPad *audioBinSrcPad = gst_element_get_pad (audioBin,
"src");
1545 gst_bin_add (GST_BIN (
mPipeline), audioBin);
1546 gst_element_sync_state_with_parent (audioBin);
1548 GstPadLinkReturn linkret = gst_pad_link (inputAudioSrcPad, audioBinSinkPad);
1549 if (linkret != GST_PAD_LINK_OK) {
1550 TranscodingFatalError(
"songbird.transcode.error.audio_incompatible");
1551 rv = NS_ERROR_FAILURE;
1555 g_object_unref (audioBinSinkPad);
1558 *outputAudioSrcPad = audioBinSrcPad;
1563 g_object_unref (audioBinSinkPad);
1564 g_object_unref (audioBinSrcPad);
1574 sbGStreamerVideoTranscoder::AddVideoBin(GstPad *inputVideoSrcPad,
1575 GstPad **outputVideoSrcPad)
1577 TRACE((
"%s[%p]", __FUNCTION__,
this));
1578 NS_ENSURE_ARG_POINTER (inputVideoSrcPad);
1579 NS_ENSURE_ARG_POINTER (outputVideoSrcPad);
1585 GstElement *videoBin = NULL;
1586 GstCaps *caps = GetCapsFromPad (mVideoSrc);
1587 rv = BuildVideoBin(caps, &videoBin);
1588 gst_caps_unref (caps);
1589 NS_ENSURE_SUCCESS (rv, rv);
1591 GstPad *videoBinSinkPad = gst_element_get_pad (videoBin,
"sink");
1592 GstPad *videoBinSrcPad = gst_element_get_pad (videoBin,
"src");
1594 gst_bin_add (GST_BIN (
mPipeline), videoBin);
1595 gst_element_sync_state_with_parent (videoBin);
1597 GstPadLinkReturn linkret = gst_pad_link (inputVideoSrcPad, videoBinSinkPad);
1598 if (linkret != GST_PAD_LINK_OK) {
1599 TranscodingFatalError(
"songbird.transcode.error.video_incompatible");
1600 rv = NS_ERROR_FAILURE;
1604 g_object_unref (videoBinSinkPad);
1607 *outputVideoSrcPad = videoBinSrcPad;
1612 g_object_unref (videoBinSinkPad);
1613 g_object_unref (videoBinSrcPad);
1619 sbGStreamerVideoTranscoder::GetPadFromTemplate (GstElement *element,
1620 GstPadTemplate *templ)
1622 TRACE((
"%s[%p]", __FUNCTION__,
this));
1624 GstPadPresence presence = GST_PAD_TEMPLATE_PRESENCE (templ);
1626 if (presence == GST_PAD_ALWAYS || presence == GST_PAD_SOMETIMES)
1628 return gst_element_get_static_pad (element, templ->name_template);
1632 return gst_element_get_request_pad (element, templ->name_template);
1641 sbGStreamerVideoTranscoder::GetCompatiblePad (GstElement *element,
1644 TRACE((
"%s[%p]", __FUNCTION__,
this));
1646 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
1647 GList *padlist = gst_element_class_get_pad_template_list (klass);
1648 GstPadTemplate *compatibleTemplate = NULL;
1651 GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data;
1655 if (GST_PAD_DIRECTION (pad) != padtempl->direction) {
1656 GstCaps *caps = gst_pad_get_caps (pad);
1658 gboolean compatible = gst_caps_can_intersect (
1659 caps, GST_PAD_TEMPLATE_CAPS (padtempl));
1660 gst_caps_unref (caps);
1663 compatibleTemplate = padtempl;
1668 padlist = g_list_next (padlist);
1671 if (compatibleTemplate) {
1673 return GetPadFromTemplate (element, compatibleTemplate);
1686 sbGStreamerVideoTranscoder::AddMuxer (GstPad **muxerSrcPad,
1690 TRACE((
"%s[%p]", __FUNCTION__,
this));
1691 NS_ENSURE_ARG_POINTER (muxerSrcPad);
1692 NS_ASSERTION (audioPad || videoPad,
"Must have at least one pad");
1696 nsresult rv = mConfigurator->GetMuxer(muxerName);
1697 NS_ENSURE_SUCCESS (rv, rv);
1699 GstElement *muxer = NULL;
1701 if (muxerName.IsEmpty()) {
1702 LOG((
"Muxer enabled but no muxer specified"));
1703 return NS_ERROR_FAILURE;
1706 muxer = gst_element_factory_make (
1707 NS_ConvertUTF16toUTF8 (muxerName).BeginReading(), NULL);
1710 LOG((
"No muxer %s available",
1711 NS_ConvertUTF16toUTF8 (muxerName).BeginReading()));
1712 TranscodingFatalError(
"songbird.transcode.error.muxer_unavailable");
1713 return NS_ERROR_FAILURE;
1719 gst_bin_add (GST_BIN (
mPipeline), muxer);
1722 sinkpad = GetCompatiblePad (muxer, audioPad);
1724 TranscodingFatalError(
"songbird.transcode.error.audio_not_muxable");
1725 return NS_ERROR_FAILURE;
1728 GstPadLinkReturn linkret = gst_pad_link (audioPad, sinkpad);
1729 if (linkret != GST_PAD_LINK_OK) {
1730 g_object_unref (sinkpad);
1731 TranscodingFatalError(
"songbird.transcode.error.audio_not_muxable");
1732 return NS_ERROR_FAILURE;
1735 g_object_unref (sinkpad);
1739 sinkpad = GetCompatiblePad (muxer, videoPad);
1741 TranscodingFatalError(
"songbird.transcode.error.video_not_muxable");
1742 return NS_ERROR_FAILURE;
1745 GstPadLinkReturn linkret = gst_pad_link (videoPad, sinkpad);
1746 if (linkret != GST_PAD_LINK_OK) {
1747 g_object_unref (sinkpad);
1748 TranscodingFatalError(
"songbird.transcode.error.video_not_muxable");
1749 return NS_ERROR_FAILURE;
1752 g_object_unref (sinkpad);
1755 gst_element_sync_state_with_parent (muxer);
1758 *muxerSrcPad = gst_element_get_static_pad (muxer,
"src");
1764 sbGStreamerVideoTranscoder::CreateSink (GstElement **aSink)
1766 TRACE((
"%s[%p]", __FUNCTION__,
this));
1768 GstElement *sink = NULL;
1771 sink = gst_element_factory_make (
"mozillasink",
"sink");
1774 g_object_set (sink,
"stream", mDestStream.get(), NULL);
1777 else if (!mDestURI.IsEmpty()) {
1778 nsCString
uri = NS_ConvertUTF16toUTF8 (mDestURI);
1779 sink = gst_element_make_from_uri (GST_URI_SINK,
1785 TranscodingFatalError(
"songbird.transcode.error.no_sink");
1786 return NS_ERROR_FAILURE;
1794 sbGStreamerVideoTranscoder::AddSink (GstPad *muxerSrcPad)
1796 TRACE((
"%s[%p]", __FUNCTION__,
this));
1798 GstElement *sink = NULL;
1799 nsresult rv = CreateSink(&sink);
1800 NS_ENSURE_SUCCESS (rv, rv);
1802 gst_bin_add (GST_BIN (
mPipeline), sink);
1803 gst_element_sync_state_with_parent (sink);
1805 GstPad *sinkpad = gst_element_get_static_pad (sink,
"sink");
1807 GstPadLinkReturn linkret = gst_pad_link (muxerSrcPad, sinkpad);
1808 if (linkret != GST_PAD_LINK_OK) {
1809 TranscodingFatalError(
"songbird.transcode.error.sink_incompatible");
1810 return NS_ERROR_FAILURE;
1813 g_object_unref (sinkpad);
1819 sbGStreamerVideoTranscoder::SetVideoFormatFromCaps (
1824 GstStructure *structure = gst_caps_get_structure (caps, 0);
1829 success = gst_structure_get_int (structure,
"width", &width);
1830 NS_ENSURE_TRUE (success, NS_ERROR_FAILURE);
1831 success = gst_structure_get_int (structure,
"height", &height);
1832 NS_ENSURE_TRUE (success, NS_ERROR_FAILURE);
1834 const GValue* par = gst_structure_get_value(structure,
1835 "pixel-aspect-ratio");
1838 parN = gst_value_get_fraction_numerator(par);
1839 parD = gst_value_get_fraction_denominator(par);
1847 const GValue* fr = gst_structure_get_value(structure,
"framerate");
1850 frN = gst_value_get_fraction_numerator(fr);
1851 frD = gst_value_get_fraction_denominator(fr);
1861 rv = format->SetVideoType (NS_LITERAL_STRING (
"video/x-raw"));
1862 NS_ENSURE_SUCCESS (rv, rv);
1863 rv = format->SetVideoWidth (width);
1864 NS_ENSURE_SUCCESS (rv, rv);
1865 rv = format->SetVideoHeight (height);
1866 NS_ENSURE_SUCCESS (rv, rv);
1867 rv = format->SetVideoPAR(parN, parD);
1868 NS_ENSURE_SUCCESS (rv, rv);
1869 rv = format->SetVideoFrameRate(frN, frD);
1870 NS_ENSURE_SUCCESS (rv, rv);
1876 sbGStreamerVideoTranscoder::SetAudioFormatFromCaps (
1880 GstStructure *structure = gst_caps_get_structure (caps, 0);
1886 success = gst_structure_get_int (structure,
"rate", &rate);
1887 NS_ENSURE_TRUE (success, NS_ERROR_FAILURE);
1888 success = gst_structure_get_int (structure,
"channels", &channels);
1889 NS_ENSURE_TRUE (success, NS_ERROR_FAILURE);
1893 rv = format->SetAudioType(NS_LITERAL_STRING (
"audio/x-raw"));
1894 NS_ENSURE_SUCCESS (rv, rv);
1895 rv = format->SetSampleRate (rate);
1896 NS_ENSURE_SUCCESS (rv, rv);
1897 rv = format->SetChannels (channels);
1898 NS_ENSURE_SUCCESS (rv, rv);
1904 sbGStreamerVideoTranscoder::InitializeConfigurator()
1906 TRACE((
"%s[%p]", __FUNCTION__,
this));
1911 nsCOMPtr<sbIMediaFormatMutable> mediaFormat =
1913 NS_ENSURE_SUCCESS (rv, rv);
1916 nsCOMPtr<sbIMediaFormatVideoMutable> videoFormat =
1918 NS_ENSURE_SUCCESS (rv, rv);
1920 GstCaps *videoCaps = GetCapsFromPad (mVideoSrc);
1921 NS_ENSURE_TRUE (videoCaps, NS_ERROR_FAILURE);
1923 rv = SetVideoFormatFromCaps(videoFormat, videoCaps);
1924 gst_caps_unref (videoCaps);
1925 NS_ENSURE_SUCCESS (rv, rv);
1927 rv = mediaFormat->SetVideoStream(videoFormat);
1928 NS_ENSURE_SUCCESS (rv, rv);
1933 nsCOMPtr<sbIMediaFormatAudioMutable> audioFormat =
1935 NS_ENSURE_SUCCESS (rv, rv);
1937 GstCaps *audioCaps = GetCapsFromPad (mAudioSrc);
1938 NS_ENSURE_TRUE (audioCaps, NS_ERROR_FAILURE);
1940 rv = SetAudioFormatFromCaps(audioFormat, audioCaps);
1941 gst_caps_unref (audioCaps);
1942 NS_ENSURE_SUCCESS (rv, rv);
1944 rv = mediaFormat->SetAudioStream(audioFormat);
1945 NS_ENSURE_SUCCESS (rv, rv);
1948 rv = mConfigurator->SetInputFormat(mediaFormat);
1949 NS_ENSURE_SUCCESS (rv, rv);
1951 rv = mConfigurator->Configurate();
1952 if (NS_FAILED (rv)) {
1953 TranscodingFatalError(
"songbird.transcode.error.failed_configuration");
1954 NS_ENSURE_SUCCESS (rv, rv);
1959 if (!mDestURI.IsEmpty()) {
1960 nsCOMPtr<nsIURI> fixedDestURI;
1961 rv = NS_NewURI(getter_AddRefs(fixedDestURI),
1962 NS_ConvertUTF16toUTF8(mDestURI));
1963 NS_ENSURE_SUCCESS(rv, rv);
1965 nsCOMPtr<nsIFileURL> fixedDestFileURI = do_QueryInterface(
1967 if (NS_SUCCEEDED(rv) && fixedDestFileURI) {
1968 nsCString curFileExt;
1969 rv = fixedDestFileURI->GetFileExtension(curFileExt);
1970 NS_ENSURE_SUCCESS(rv, rv);
1972 nsCString configFileExt;
1973 rv = mConfigurator->GetFileExtension(configFileExt);
1974 NS_ENSURE_SUCCESS(rv, rv);
1976 if (!curFileExt.Equals(configFileExt, CaseInsensitiveCompare)) {
1977 rv = fixedDestFileURI->SetFileExtension(configFileExt);
1978 NS_ENSURE_SUCCESS(rv, rv);
1982 rv = fixedDestFileURI->GetFile(getter_AddRefs(destFile));
1985 rv = destFile->Exists(&exists);
1986 NS_ENSURE_SUCCESS(rv, rv);
1990 rv = destFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE,
1992 NS_ENSURE_SUCCESS(rv, rv);
1993 rv = NS_NewFileURI(getter_AddRefs(fixedDestURI), destFile);
1994 NS_ENSURE_SUCCESS(rv, rv);
1995 fixedDestFileURI = do_QueryInterface(fixedDestURI, &rv);
1996 NS_ENSURE_SUCCESS(rv, rv);
1999 nsCString fixedSpec;
2000 rv = fixedDestFileURI->GetSpec(fixedSpec);
2001 NS_ENSURE_SUCCESS(rv, rv);
2003 CopyUTF8toUTF16(fixedSpec, mDestURI);
2011 nsString audioEncoder;
2012 rv = mConfigurator->GetAudioEncoder(audioEncoder);
2013 NS_ENSURE_SUCCESS(rv, rv);
2014 rv = mConfigurator->GetUseAudioEncoder(&mUseAudio);
2015 NS_ENSURE_SUCCESS(rv, rv);
2017 nsString videoEncoder;
2018 rv = mConfigurator->GetVideoEncoder(videoEncoder);
2019 NS_ENSURE_SUCCESS(rv, rv);
2020 rv = mConfigurator->GetUseVideoEncoder(&mUseVideo);
2021 NS_ENSURE_SUCCESS(rv, rv);
2024 rv = mConfigurator->GetMuxer(muxer);
2025 NS_ENSURE_SUCCESS(rv, rv);
2026 rv = mConfigurator->GetUseMuxer(&mUseMuxer);
2027 NS_ENSURE_SUCCESS(rv, rv);
2030 if (!mUseMuxer && (mUseAudio && mUseVideo))
2031 return NS_ERROR_UNEXPECTED;
2037 sbGStreamerVideoTranscoder::DecoderNoMorePads(GstElement *uridecodebin)
2039 TRACE((
"%s[%p]", __FUNCTION__,
this));
2041 if (!mAudioSrc && !mVideoSrc) {
2043 TranscodingFatalError(
"songbird.transcode.error.no_streams");
2044 return NS_ERROR_FAILURE;
2053 g_signal_connect (mAudioSrc,
"notify::caps",
2054 G_CALLBACK (pad_notify_caps_cb),
this);
2056 GstElement *queue = gst_element_factory_make (
"queue",
"audio-queue");
2057 GstPad *queueSink = gst_element_get_pad (queue,
"sink");
2059 gst_bin_add (GST_BIN (
mPipeline), queue);
2060 gst_element_sync_state_with_parent (queue);
2062 gst_pad_link (mAudioSrc, queueSink);
2063 g_object_unref (queueSink);
2065 GstPad *queueSrc = gst_element_get_pad (queue,
"src");
2066 mAudioQueueSrc = queueSrc;
2068 gst_pad_set_blocked_async (queueSrc, TRUE,
2069 (GstPadBlockCallback)pad_blocked_cb,
this);
2073 g_signal_connect (mVideoSrc,
"notify::caps",
2074 G_CALLBACK (pad_notify_caps_cb),
this);
2076 GstElement *queue = gst_element_factory_make (
"queue",
"video-queue");
2077 GstPad *queueSink = gst_element_get_pad (queue,
"sink");
2079 gst_bin_add (GST_BIN (
mPipeline), queue);
2080 gst_element_sync_state_with_parent (queue);
2082 gst_pad_link (mVideoSrc, queueSink);
2083 g_object_unref (queueSink);
2085 GstPad *queueSrc = gst_element_get_pad (queue,
"src");
2086 mVideoQueueSrc = queueSrc;
2088 gst_pad_set_blocked_async (queueSrc, TRUE,
2089 (GstPadBlockCallback)pad_blocked_cb,
this);
2092 mWaitingForCaps = PR_TRUE;
2098 sbGStreamerVideoTranscoder::PadNotifyCaps (GstPad *pad)
2100 return CheckForAllCaps();
2105 sbGStreamerVideoTranscoder::GetCapsFromPad (GstPad *pad)
2118 GstCaps *caps = gst_pad_get_negotiated_caps (realPad);
2120 if (gst_caps_is_fixed (caps)) {
2121 g_object_unref(realPad);
2124 gst_caps_unref (caps);
2127 caps = GST_PAD_CAPS (realPad);
2129 gst_caps_ref (caps);
2130 g_object_unref(realPad);
2133 g_object_unref(realPad);
2138 sbGStreamerVideoTranscoder::CheckForAllCaps ()
2141 nsAutoLock lock(mBuildLock);
2142 nsresult rv =
NS_OK;
2144 if (mWaitingForCaps) {
2145 TRACE((
"CheckForAllCaps: checking if we have fixed caps on all pads"));
2147 GstCaps *audioCaps = GetCapsFromPad (mAudioSrc);
2152 gst_caps_unref (audioCaps);
2156 GstCaps *videoCaps = GetCapsFromPad (mVideoSrc);
2161 gst_caps_unref (videoCaps);
2164 LOG((
"Have fixed caps on all pads: proceeding to build pipeline"));
2168 rv = BuildRemainderOfPipeline();
2171 mWaitingForCaps = PR_FALSE;
2173 if (NS_SUCCEEDED (rv)) {
2174 if (mAudioQueueSrc) {
2175 gst_pad_set_blocked_async (mAudioQueueSrc, FALSE,
2176 (GstPadBlockCallback)pad_blocked_cb,
this);
2178 if (mVideoQueueSrc) {
2179 gst_pad_set_blocked_async (mVideoQueueSrc, FALSE,
2180 (GstPadBlockCallback)pad_blocked_cb,
this);
2189 TranscodingFatalError(
"songbird.transcode.error.failed_configuration");
2201 sbGStreamerVideoTranscoder::PadBlocked (GstPad *pad, gboolean blocked)
2204 LOG((
"Pad blocked, checking if we have full caps yet"));
2205 return CheckForAllCaps();
2208 LOG((
"PadBlocked: returning NS_OK after unblocking."));
2214 sbGStreamerVideoTranscoder::BuildRemainderOfPipeline ()
2216 TRACE((
"%s[%p]", __FUNCTION__,
this));
2221 rv = InitializeConfigurator();
2222 NS_ENSURE_SUCCESS (rv, rv);
2224 GstPad *newAudioSrc = NULL;
2225 GstPad *newVideoSrc = NULL;
2227 if (mAudioQueueSrc && mUseAudio) {
2228 rv = AddAudioBin (mAudioQueueSrc, &newAudioSrc);
2229 NS_ENSURE_SUCCESS (rv, rv);
2232 if (mVideoQueueSrc && mUseVideo) {
2233 rv = AddVideoBin (mVideoQueueSrc, &newVideoSrc);
2234 NS_ENSURE_SUCCESS (rv, rv);
2237 GstPad *srcpad = NULL;
2240 rv = AddMuxer (&srcpad, newAudioSrc, newVideoSrc);
2241 NS_ENSURE_SUCCESS (rv, rv);
2245 srcpad = (GstPad *)gst_object_ref (newAudioSrc);
2246 else if (newVideoSrc)
2247 srcpad = (GstPad *)gst_object_ref (newVideoSrc);
2249 NS_NOTREACHED (
"No audio or video, not allowed");
2250 return NS_ERROR_FAILURE;
2254 rv = AddSink (srcpad);
2255 if (NS_FAILED (rv)) {
2256 NS_ENSURE_SUCCESS (rv, rv);
2259 g_object_unref (srcpad);
2261 g_object_unref (newVideoSrc);
2263 g_object_unref (newAudioSrc);
2266 rv = SetMetadataOnTagSetters();
2268 LOG((
"Finished building pipeline"));
2273 sbGStreamerVideoTranscoder::BuildTranscodePipeline(
const gchar *aPipelineName)
2275 TRACE((
"%s[%p]", __FUNCTION__,
this));
2341 mPipeline = gst_pipeline_new (aPipelineName);
2342 NS_ENSURE_TRUE (
mPipeline, NS_ERROR_FAILURE);
2344 GstElement *uridecodebin = gst_element_factory_make(
"uridecodebin",
2345 "transcode-decoder");
2346 if (!uridecodebin) {
2350 return NS_ERROR_FAILURE;
2354 nsCString uri = NS_ConvertUTF16toUTF8 (mSourceURI);
2355 g_object_set (uridecodebin,
"uri", uri.BeginReading(), NULL);
2360 g_signal_connect (uridecodebin,
"pad-added",
2361 G_CALLBACK (decodebin_pad_added_cb),
this);
2362 g_signal_connect (uridecodebin,
"no-more-pads",
2363 G_CALLBACK (decodebin_no_more_pads_cb),
this);
2365 gst_bin_add (GST_BIN (
mPipeline), uridecodebin);
function succeeded(ch, cx, status, data)
nsresult SB_NewTranscodeError(const nsAString &aMessageWithItem, const nsAString &aMessageWithoutItem, const nsAString &aDetails, const nsAString &aUri, sbIMediaItem *aMediaItem, sbITranscodeError **_retval)
#define SB_DEFAULT_FILE_PERMISSIONS
Generic interface for exposing long running jobs to the UI.
nsString Get(const nsAString &aKey, const nsAString &aDefault=SBVoidString())
An object capable of transcoding a source URI to a destination file.
NS_INTERFACE_MAP_END NS_IMPL_CI_INTERFACE_GETTER6(sbDeviceLibrary, nsIClassInfo, sbIDeviceLibrary, sbILibrary, sbIMediaList, sbIMediaItem, sbILibraryResource) sbDeviceLibrary
const unsigned short STATUS_SUCCEEDED
Constant indicating that the job has completed.
Generic interface extending sbIJobProgress that can track expected time, etc in addition to abstract ...
sbIJobCancelable NS_DECL_CLASSINFO(sbGStreamerVideoTranscoder)
GstClockTime GetRunningTime()
virtual void HandleErrorMessage(GstMessage *message)
const unsigned short STATUS_RUNNING
Constant indicating that the job is active.
Base interface for all Transcoding Configurators. This interface should be implemented by any Configu...
void DispatchMediacoreEvent(unsigned long type, nsIVariant *aData=NULL, sbIMediacoreError *aError=NULL)
virtual void HandleEOSMessage(GstMessage *message)
virtual nsresult BuildPipeline()
#define PROGRESS_INTERVAL
NS_IMETHOD PlayPipeline()
Songbird String Bundle Definitions.
nsresult SBGetLocalizedString(nsAString &aString, const nsAString &aKey, const nsAString &aDefault, class nsIStringBundle *aStringBundle)
nsString mResourceDisplayName
NS_IMPL_THREADSAFE_CI(sbGStreamerVideoTranscoder)
void SetPipelineOp(GStreamer::pipelineOp_t aPipelineOp)
Implemented to receive notifications from sbIJobProgress interfaces.
NS_IMETHOD StopPipeline()
const unsigned short STATUS_FAILED
Constant indicating that the job has completed with errors.
An interface to carry around arrays of nsIProperty instances. Users of this interface should only QI ...
_getSelectedPageStyle s i
NS_IMPL_THREADSAFE_ISUPPORTS8(sbGStreamerVideoTranscoder, nsIClassInfo, sbIGStreamerPipeline, sbITranscodeVideoJob, sbIMediacoreEventTarget, sbIJobProgress, sbIJobProgressTime, sbIJobCancelable, nsITimerCallback) NS_IMPL_CI_INTERFACE_GETTER6(sbGStreamerVideoTranscoder