コード例 #1
0
        public void BuildCompositionObjects(Boolean playBack)
        {
            if (Clips == null || Clips.Count == 0)
            {
                Composition      = null;
                VideoComposition = null;
                AudioMix         = null;
                return;
            }

            SizeF videoSize         = Clips [0].NaturalSize;
            var   composition1      = AVMutableComposition.Create();
            var   videoComposition1 = AVMutableVideoComposition.Create();
            var   audioMix          = AVMutableAudioMix.Create();

            composition1.NaturalSize = videoSize;

            BuildTransitionComposition(composition1, videoComposition1, audioMix);
            if (videoComposition1 != null)
            {
                videoComposition1.FrameDuration = new CMTime(1, 30);
                videoComposition1.RenderSize    = videoSize;
            }

            Composition      = composition1;
            VideoComposition = videoComposition1;
            AudioMix         = audioMix;
        }
コード例 #2
0
		private void ProcessComposition (AVMutableComposition composition)
		{
			var tracks = new List<List<APLCompositionTrackSegmentInfo>> ();
			foreach (AVCompositionTrack track in composition.Tracks) {
				var segmentInfos = new List<APLCompositionTrackSegmentInfo> ();
				foreach (AVCompositionTrackSegment segment in track.Segments) {
					var segmentInfo = new APLCompositionTrackSegmentInfo (segment, track.MediaType);
					segmentInfos.Add (segmentInfo);
				}

				tracks.Add (segmentInfos);
			}

			compositionTracks = tracks;
			duration = CMTime.GetMaximum (duration, composition.Duration);
		}
コード例 #3
0
		public void SynchronizeToCompositoin (AVMutableComposition composition, AVMutableVideoComposition videoComposition, AVMutableAudioMix audioMix)
		{
			compositionTracks = null;
			audioMixTracks = null;
			videoCompositionStages = null;

			duration = new CMTime (1, 1);

			if (composition != null)
				ProcessComposition (composition);

			if (videoComposition != null)
				ProcessVideoComposition (videoComposition);

			if (audioMix != null)
				ProcessAudioMix (audioMix);
		}
コード例 #4
0
        public void BuildCompositionObjects(bool playBack)
        {
            if (Clips == null || Clips.Count == 0)
            {
                Composition      = null;
                VideoComposition = null;
                return;
            }

            var videoSize   = Clips [0].NaturalSize;
            var composition = AVMutableComposition.Create();
            AVMutableVideoComposition videoComposition = null;

            composition.NaturalSize = videoSize;

            // With transitions:
            // Place clips into alternating video & audio tracks in composition, overlapped by transitionDuration.
            // Set up the video composition to cycle between "pass through A", "transition from A to B",
            // "pass through B".

            videoComposition = AVMutableVideoComposition.Create();


            //Set CustomVideoCompositorClass based on the Compositor user selected.

            if (TransitionType == TransitionTypeController.DiagonalWipeTransition)
            {
                videoComposition.CustomVideoCompositorClass = new MonoTouch.ObjCRuntime.Class(typeof(DiagonalWipeCompositor));
            }
            else
            {
                videoComposition.CustomVideoCompositorClass = new MonoTouch.ObjCRuntime.Class(typeof(CrossDissolveCompositor));
            }

            buildTransitionComposition(composition, videoComposition);
            if (videoComposition != null)
            {
                // Every videoComposition needs these properties to be set:
                videoComposition.FrameDuration = new CMTime(1, 30);
                videoComposition.RenderSize    = videoSize;
            }
            Composition      = composition;
            VideoComposition = videoComposition;
        }
コード例 #5
0
        private void ProcessComposition(AVMutableComposition composition)
        {
            var tracks = new List <List <APLCompositionTrackSegmentInfo> > ();

            foreach (AVCompositionTrack track in composition.Tracks)
            {
                var segmentInfos = new List <APLCompositionTrackSegmentInfo> ();
                foreach (AVCompositionTrackSegment segment in track.Segments)
                {
                    var segmentInfo = new APLCompositionTrackSegmentInfo(segment, track.MediaType);
                    segmentInfos.Add(segmentInfo);
                }

                tracks.Add(segmentInfos);
            }

            compositionTracks = tracks;
            duration          = CMTime.GetMaximum(duration, composition.Duration);
        }
コード例 #6
0
        public void BuildCompositionObjectsForPlayback(bool playback)
        {
            if (Clips == null || Clips.Count == 0)
            {
                this.composition      = null;
                this.videoComposition = null;
            }
            else
            {
                var videoSize          = Clips[0].NaturalSize;
                var mutableComposition = AVMutableComposition.Create();
                AVMutableVideoComposition mutableVideoComposition = null;

                mutableComposition.NaturalSize = videoSize;

                // With transitions:
                // Place clips into alternating video & audio tracks in composition, overlapped by transitionDuration.
                // Set up the video composition to cycle between "pass through A", "transition from A to B",
                // "pass through B".

                mutableVideoComposition = AVMutableVideoComposition.Create();
                if (TransitionType == TransitionType.DiagonalWipeTransition)
                {
                    mutableVideoComposition.CustomVideoCompositorClass = new ObjCRuntime.Class(typeof(DiagonalWipeCompositor));
                }
                else
                {
                    mutableVideoComposition.CustomVideoCompositorClass = new ObjCRuntime.Class(typeof(CrossDissolveCompositor));
                }

                BuildTransitionComposition(mutableComposition, mutableVideoComposition);
                if (mutableVideoComposition != null)
                {
                    // Every videoComposition needs these properties to be set:
                    mutableVideoComposition.FrameDuration = new CMTime(1, 30);
                    mutableVideoComposition.RenderSize    = videoSize;
                }

                this.composition      = mutableComposition;
                this.videoComposition = mutableVideoComposition;
            }
        }
コード例 #7
0
        public void SynchronizeToCompositoin(AVMutableComposition composition, AVMutableVideoComposition videoComposition, AVMutableAudioMix audioMix)
        {
            compositionTracks      = null;
            audioMixTracks         = null;
            videoCompositionStages = null;

            duration = new CMTime(1, 1);

            if (composition != null)
            {
                ProcessComposition(composition);
            }

            if (videoComposition != null)
            {
                ProcessVideoComposition(videoComposition);
            }

            if (audioMix != null)
            {
                ProcessAudioMix(audioMix);
            }
        }
コード例 #8
0
        private void BuildTransitionComposition(AVMutableComposition composition, AVMutableVideoComposition videoComposition, AVMutableAudioMix audioMix)
        {
            CMTime nextClipStartTime = CMTime.Zero;
            int    clipsCount        = Clips.Count;

            // Make transitionDuration no greater than half the shortest clip duration.
            CMTime transitionDuration = TransitionDuration;

            Console.WriteLine("Clips Count:" + clipsCount);
            Console.WriteLine("Clips Range Count:" + ClipTimeRanges.Count);

            for (int i = 0; i < clipsCount; i++)
            {
                NSValue clipTimeRange = ClipTimeRanges [i];
                if (clipTimeRange != null)
                {
                    CMTime halfClipDuration = clipTimeRange.CMTimeRangeValue.Duration;
                    halfClipDuration.TimeScale *= 2;
                    transitionDuration          = CMTime.GetMinimum(transitionDuration, halfClipDuration);
                }
            }

            // Add two video tracks and two audio tracks.
            var compositionVideoTracks = new AVMutableCompositionTrack [] {
                composition.AddMutableTrack(AVMediaType.Video, 0),
                composition.AddMutableTrack(AVMediaType.Video, 0)
            };
            var compositionAudioTracks = new AVMutableCompositionTrack [] {
                composition.AddMutableTrack(AVMediaType.Audio, 0),
                composition.AddMutableTrack(AVMediaType.Audio, 0)
            };

            var passThroughTimeRanges = new CMTimeRange[clipsCount];
            var transitionTimeRanges  = new CMTimeRange[clipsCount];

            // Place clips into alternating video & audio tracks in composition, overlapped by transitionDuration.
            for (int i = 0; i < clipsCount; i++)
            {
                int         alternatingIndex = i % 2;
                AVAsset     asset            = Clips [i];
                NSValue     clipTimeRange    = ClipTimeRanges [i];
                CMTimeRange timeRangeInAsset;
                if (clipTimeRange != null)
                {
                    timeRangeInAsset = clipTimeRange.CMTimeRangeValue;
                }
                else
                {
                    timeRangeInAsset          = new CMTimeRange();
                    timeRangeInAsset.Start    = CMTime.Zero;
                    timeRangeInAsset.Duration = asset.Duration;
                }
                NSError      error;
                AVAssetTrack clipVideoTrack = asset.TracksWithMediaType(AVMediaType.Video) [0];
                compositionVideoTracks [alternatingIndex].InsertTimeRange(timeRangeInAsset, clipVideoTrack, nextClipStartTime, out error);

                AVAssetTrack clipAudioTrack = asset.TracksWithMediaType(AVMediaType.Audio) [0];
                compositionAudioTracks [alternatingIndex].InsertTimeRange(timeRangeInAsset, clipAudioTrack, nextClipStartTime, out error);

                // Remember the time range in which this clip should pass through.
                // First clip ends with a transition.
                // Second clip begins with a transition.
                // Exclude that transition from the pass through time ranges
                CMTimeRange timeRange = new CMTimeRange();
                timeRange.Start           = nextClipStartTime;
                timeRange.Duration        = timeRangeInAsset.Duration;
                passThroughTimeRanges [i] = timeRange;

                if (i > 0)
                {
                    passThroughTimeRanges[i].Start    = CMTime.Add(passThroughTimeRanges[i].Start, transitionDuration);
                    passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration, transitionDuration);
                }

                if (i + 1 < clipsCount)
                {
                    passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration, transitionDuration);
                }

                // The end of this clip will overlap the start of the next by transitionDuration.
                // (Note: this arithmetic falls apart if timeRangeInAsset.duration < 2 * transitionDuration.)
                nextClipStartTime = CMTime.Add(nextClipStartTime, timeRangeInAsset.Duration);
                nextClipStartTime = CMTime.Subtract(nextClipStartTime, transitionDuration);

                // Remember the time range for the transition to the next item
                if (i + 1 < clipsCount)
                {
                    transitionTimeRanges [i] = new CMTimeRange()
                    {
                        Start    = nextClipStartTime,
                        Duration = transitionDuration
                    };
                }
            }

            List <AVVideoCompositionInstruction>    instructions  = new List <AVVideoCompositionInstruction> ();
            List <AVMutableAudioMixInputParameters> trackMixArray = new List <AVMutableAudioMixInputParameters> ();

            // Set up the video composition if we are to perform crossfade transitions between clips.
            for (int i = 0; i < clipsCount; i++)
            {
                int alternatingIndex = i % 2;
                AVMutableVideoCompositionInstruction passThroughInstructions = AVMutableVideoCompositionInstruction.Create() as AVMutableVideoCompositionInstruction;
                passThroughInstructions.TimeRange = passThroughTimeRanges [i];

                AVMutableVideoCompositionLayerInstruction passThroughLayerInstructions = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks [alternatingIndex]);

                passThroughInstructions.LayerInstructions = new AVVideoCompositionLayerInstruction[] { passThroughLayerInstructions };
                instructions.Add(passThroughInstructions);

                if (i + 1 < clipsCount)
                {
                    var transitionInstruction = AVMutableVideoCompositionInstruction.Create() as AVMutableVideoCompositionInstruction;
                    transitionInstruction.TimeRange = transitionTimeRanges [i];
                    var fromLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks [alternatingIndex]);
                    var toLayer   = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks [1 - alternatingIndex]);


                    // Fade in the toLayer by setting a ramp from 0.0 to 1.0.
                    toLayer.SetOpacityRamp(0.0f, 1.0f, transitionTimeRanges [i]);
                    transitionInstruction.LayerInstructions = new AVVideoCompositionLayerInstruction[]
                    {
                        toLayer,
                        fromLayer,
                    };
                    instructions.Add(transitionInstruction);

                    // Add AudioMix to fade in the volume ramps
                    var trackMix = AVMutableAudioMixInputParameters.FromTrack(compositionAudioTracks[0]);
                    trackMix.SetVolumeRamp(1f, 0f, transitionTimeRanges[0]);
                    trackMixArray.Add(trackMix);

                    trackMix = AVMutableAudioMixInputParameters.FromTrack(compositionAudioTracks[1]);
                    trackMix.SetVolumeRamp(0f, 1f, transitionTimeRanges[0]);
                    trackMix.SetVolumeRamp(1f, 1f, passThroughTimeRanges[1]);
                    trackMixArray.Add(trackMix);
                }
            }

            videoComposition.Instructions = instructions.ToArray();
            audioMix.InputParameters      = trackMixArray.ToArray();
        }
コード例 #9
0
        void buildTransitionComposition(AVMutableComposition composition, AVMutableVideoComposition videoComposition)
        {
            CMTime nextClipStartTime = CMTime.Zero;
            int    clipsCount        = Clips.Count;

            // Make transitionDuration no greater than half the shortest clip duration.
            CMTime transitionDuration = TransitionDuration;

            foreach (var clipTimeRange in ClipTimeRanges)
            {
                if (clipTimeRange == null)
                {
                    continue;
                }

                CMTime halfClipDuration = clipTimeRange.CMTimeRangeValue.Duration;
                halfClipDuration.TimeScale *= 2;
                transitionDuration          = CMTime.GetMinimum(transitionDuration, halfClipDuration);
            }

            // Add two video tracks and two audio tracks.
            var compositionVideoTracks = new AVMutableCompositionTrack [2];
            var compositionAudioTracks = new AVMutableCompositionTrack [2];

            compositionVideoTracks [0] = composition.AddMutableTrack(AVMediaType.Video, 0);
            compositionVideoTracks [1] = composition.AddMutableTrack(AVMediaType.Video, 0);
            compositionAudioTracks [0] = composition.AddMutableTrack(AVMediaType.Audio, 0);
            compositionAudioTracks [1] = composition.AddMutableTrack(AVMediaType.Audio, 0);

            var passThroughTimeRanges = new CMTimeRange[clipsCount];
            var transitionTimeRanges  = new CMTimeRange[clipsCount];

            // Place clips into alternating video & audio tracks in composition, overlapped by transitionDuration.
            for (int i = 0; i < clipsCount; i++)
            {
                int         alternatingIndex = i % 2;
                AVAsset     asset            = Clips [i];
                NSValue     clipTimeRange    = ClipTimeRanges [i];
                CMTimeRange timeRangeInAsset;
                if (clipTimeRange != null)
                {
                    timeRangeInAsset = clipTimeRange.CMTimeRangeValue;
                }
                else
                {
                    timeRangeInAsset = new CMTimeRange {
                        Start    = CMTime.Zero,
                        Duration = asset.Duration
                    };
                }
                NSError      error          = new NSError();
                AVAssetTrack clipVideoTrack = asset.TracksWithMediaType(AVMediaType.Video) [0];
                compositionVideoTracks [alternatingIndex].InsertTimeRange(timeRangeInAsset, clipVideoTrack, nextClipStartTime, out error);

                AVAssetTrack clipAudioTrack = asset.TracksWithMediaType(AVMediaType.Audio) [0];
                compositionAudioTracks [alternatingIndex].InsertTimeRange(timeRangeInAsset, clipAudioTrack, nextClipStartTime, out error);

                // Remember the time range in which this clip should pass through.
                // First clip ends with a transition.
                // Second clip begins with a transition.
                // Exclude that transition from the pass through time ranges
                passThroughTimeRanges [i] = new CMTimeRange {
                    Start    = nextClipStartTime,
                    Duration = timeRangeInAsset.Duration
                };

                if (i > 0)
                {
                    passThroughTimeRanges[i].Start    = CMTime.Add(passThroughTimeRanges[i].Start, transitionDuration);
                    passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration, transitionDuration);
                }
                if (i + 1 < clipsCount)
                {
                    passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration, transitionDuration);
                }

                // The end of this clip will overlap the start of the next by transitionDuration.
                // (Note: this arithmetic falls apart if timeRangeInAsset.duration < 2 * transitionDuration.)
                nextClipStartTime = CMTime.Add(nextClipStartTime, timeRangeInAsset.Duration);
                nextClipStartTime = CMTime.Subtract(nextClipStartTime, transitionDuration);

                // Remember the time range for the transition to the next item.

                if (i + 1 < clipsCount)
                {
                    transitionTimeRanges [i] = new CMTimeRange()
                    {
                        Start    = nextClipStartTime,
                        Duration = transitionDuration
                    };
                }
            }

            // Set up the video composition to perform cross dissolve or diagonal wipe transitions between clips.
            var instructions = new List <AVVideoCompositionInstruction> ();

            // Cycle between "pass through A", "transition from A to B", "pass through B"
            for (int i = 0; i < clipsCount; i++)
            {
                int alternatingIndex = i % 2;

//				if (videoComposition.CustomVideoCompositorClass != null) {
//					var videoInstruction = new CustomVideoCompositionInstruction (compositionVideoTracks [alternatingIndex].TrackID, passThroughTimeRanges [i]);
//					instructions.Add (videoInstruction);
//				} else {
//					// Pass through clip i.
//					var passThroughInstruction = AVMutableVideoCompositionInstruction.Create () as AVMutableVideoCompositionInstruction;
//					passThroughInstruction.TimeRange = passThroughTimeRanges [i];
//					var passThroughLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [alternatingIndex]);
//					passThroughInstruction.LayerInstructions = new [] { passThroughLayer };
//					instructions.Add (passThroughInstruction);
//
//				}
                //TODO: Remove following call if previous works
                if (videoComposition.CustomVideoCompositorClass.Name != "nil")
                {
                    var videoInstruction = new CustomVideoCompositionInstruction(compositionVideoTracks [alternatingIndex].TrackID, passThroughTimeRanges [i]);
                    instructions.Add(videoInstruction);
                }
                else
                {
                    // Pass through clip i.
                    var passThroughInstruction = AVMutableVideoCompositionInstruction.Create() as AVMutableVideoCompositionInstruction;
                    passThroughInstruction.TimeRange = passThroughTimeRanges [i];
                    var passThroughLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks [alternatingIndex]);
                    passThroughInstruction.LayerInstructions = new [] { passThroughLayer };
                    instructions.Add(passThroughInstruction);
                }

                if (i + 1 < clipsCount)
                {
                    // Add transition from clip i to clip i+1.
//					if (videoComposition.CustomVideoCompositorClass != null) {
//						var videoInstruction = new CustomVideoCompositionInstruction (new NSNumber [] {
//							compositionVideoTracks [0].TrackID,
//							compositionVideoTracks [1].TrackID
//						}, transitionTimeRanges [1]);
//
//						if (alternatingIndex == 0) {
//							videoInstruction.ForegroundTrackID = compositionVideoTracks [alternatingIndex].TrackID;
//							videoInstruction.BackgroundTrackID = compositionVideoTracks [1 - alternatingIndex].TrackID;
//						}
//
//						instructions.Add (videoInstruction);
//					} else {
//						var transitionInstruction = AVMutableVideoCompositionInstruction.Create () as AVMutableVideoCompositionInstruction;
//						transitionInstruction.TimeRange = transitionTimeRanges [i];
//						var fromLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [alternatingIndex]);
//						var toLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [1 - alternatingIndex]);
//						transitionInstruction.LayerInstructions = new [] { toLayer, fromLayer };
//						instructions.Add (transitionInstruction);
//					}
                    // TODO: remove following call if previous works
                    if (videoComposition.CustomVideoCompositorClass.Name != "nil")
                    {
                        NSNumber[] sources = new NSNumber[] {
                            new NSNumber(compositionVideoTracks [0].TrackID),
                            new NSNumber(compositionVideoTracks [1].TrackID)
                        };
                        var videoInstructions = new CustomVideoCompositionInstruction(sources, transitionTimeRanges [i]);
                        if (alternatingIndex == 0)
                        {
                            videoInstructions.ForegroundTrackID = compositionVideoTracks [alternatingIndex].TrackID;
                            videoInstructions.BackgroundTrackID = compositionVideoTracks [1 - alternatingIndex].TrackID;
                        }

                        instructions.Add(videoInstructions);
                        Console.WriteLine("Add transition from clip i to clip i+1");
                    }
                    else
                    {
                        AVMutableVideoCompositionInstruction transitionInstruction = AVMutableVideoCompositionInstruction.Create() as AVMutableVideoCompositionInstruction;
                        transitionInstruction.TimeRange = transitionTimeRanges [i];
                        AVMutableVideoCompositionLayerInstruction fromLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks [alternatingIndex]);
                        AVMutableVideoCompositionLayerInstruction toLayer   = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks [1 - alternatingIndex]);
                        transitionInstruction.LayerInstructions = new AVVideoCompositionLayerInstruction[] {
                            fromLayer,
                            toLayer,
                        };
                        instructions.Add(transitionInstruction);
                    }
                }
            }

            videoComposition.Instructions = instructions.ToArray();
        }
コード例 #10
0
		private void BuildTransitionComposition(AVMutableComposition composition, AVMutableVideoComposition videoComposition, AVMutableAudioMix audioMix)
		{
			CMTime nextClipStartTime = CMTime.Zero;
			int clipsCount = Clips.Count;

			// Make transitionDuration no greater than half the shortest clip duration.
			CMTime transitionDuration = TransitionDuration;
			Console.WriteLine ("Clips Count:" + clipsCount);
			Console.WriteLine ("Clips Range Count:" + ClipTimeRanges.Count);

			for (int i = 0; i < clipsCount; i++) {
				NSValue clipTimeRange = ClipTimeRanges [i];
				if(clipTimeRange != null) {
					CMTime halfClipDuration = clipTimeRange.CMTimeRangeValue.Duration;
					halfClipDuration.TimeScale *= 2;
					transitionDuration = CMTime.GetMinimum(transitionDuration,halfClipDuration);
				}
			}

			// Add two video tracks and two audio tracks.
			var compositionVideoTracks = new AVMutableCompositionTrack [] {
				composition.AddMutableTrack (AVMediaType.Video, 0),
				composition.AddMutableTrack (AVMediaType.Video, 0)
			};
			var compositionAudioTracks = new AVMutableCompositionTrack [] {
				composition.AddMutableTrack (AVMediaType.Audio, 0),
				composition.AddMutableTrack (AVMediaType.Audio, 0)
			};

			var passThroughTimeRanges = new CMTimeRange[clipsCount];
			var transitionTimeRanges = new CMTimeRange[clipsCount];

			// Place clips into alternating video & audio tracks in composition, overlapped by transitionDuration.
			for(int i = 0; i < clipsCount; i++) {
				int alternatingIndex = i % 2;
				AVAsset asset = Clips [i];
				NSValue clipTimeRange = ClipTimeRanges [i];
				CMTimeRange timeRangeInAsset;
				if (clipTimeRange != null)
					timeRangeInAsset = clipTimeRange.CMTimeRangeValue;
				else {
					timeRangeInAsset = new CMTimeRange ();
					timeRangeInAsset.Start = CMTime.Zero;
					timeRangeInAsset.Duration = asset.Duration;
				}
				NSError error;
				AVAssetTrack clipVideoTrack = asset.TracksWithMediaType (AVMediaType.Video) [0];
				compositionVideoTracks [alternatingIndex].InsertTimeRange (timeRangeInAsset, clipVideoTrack, nextClipStartTime,out error);

				AVAssetTrack clipAudioTrack = asset.TracksWithMediaType (AVMediaType.Audio) [0];
				compositionAudioTracks [alternatingIndex].InsertTimeRange (timeRangeInAsset, clipAudioTrack, nextClipStartTime,out error);

				// Remember the time range in which this clip should pass through.
				// First clip ends with a transition.
				// Second clip begins with a transition.
				// Exclude that transition from the pass through time ranges
				CMTimeRange timeRange = new CMTimeRange();
				timeRange.Start = nextClipStartTime;
				timeRange.Duration = timeRangeInAsset.Duration;
				passThroughTimeRanges [i] = timeRange;

				if (i > 0)
				{
					passThroughTimeRanges[i].Start = CMTime.Add(passThroughTimeRanges[i].Start,transitionDuration);
					passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration,transitionDuration);
				}

				if(i + 1 < clipsCount)
				{
					passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration,transitionDuration);
				}

				// The end of this clip will overlap the start of the next by transitionDuration.
				// (Note: this arithmetic falls apart if timeRangeInAsset.duration < 2 * transitionDuration.)
				nextClipStartTime = CMTime.Add (nextClipStartTime, timeRangeInAsset.Duration);
				nextClipStartTime = CMTime.Subtract (nextClipStartTime, transitionDuration);

				// Remember the time range for the transition to the next item
				if(i + 1 < clipsCount)
				{
					transitionTimeRanges [i] = new CMTimeRange ()
					{
						Start  = nextClipStartTime,
						Duration = transitionDuration
					};

				}
			}

			List<AVVideoCompositionInstruction> instructions = new List<AVVideoCompositionInstruction> ();
			List<AVMutableAudioMixInputParameters> trackMixArray = new List<AVMutableAudioMixInputParameters> ();

			// Set up the video composition if we are to perform crossfade transitions between clips.
			for (int i = 0; i < clipsCount; i++)
			{
				int alternatingIndex = i % 2;
				AVMutableVideoCompositionInstruction passThroughInstructions = AVMutableVideoCompositionInstruction.Create () as AVMutableVideoCompositionInstruction;
				passThroughInstructions.TimeRange = passThroughTimeRanges [i];

				AVMutableVideoCompositionLayerInstruction passThroughLayerInstructions = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [alternatingIndex]);

				passThroughInstructions.LayerInstructions = new AVVideoCompositionLayerInstruction[] { passThroughLayerInstructions };
				instructions.Add (passThroughInstructions);

				if (i + 1 < clipsCount)
				{
					var transitionInstruction = AVMutableVideoCompositionInstruction.Create () as AVMutableVideoCompositionInstruction;
					transitionInstruction.TimeRange = transitionTimeRanges [i];
					var fromLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [alternatingIndex]);
					var toLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [1 - alternatingIndex]);

					// Fade in the toLayer by setting a ramp from 0.0 to 1.0.
					toLayer.SetOpacityRamp (0.0f, 1.0f, transitionTimeRanges [i]);
					transitionInstruction.LayerInstructions = new AVVideoCompositionLayerInstruction[]
					{
						toLayer,
						fromLayer,
					};
					instructions.Add(transitionInstruction);

					// Add AudioMix to fade in the volume ramps
					var trackMix = AVMutableAudioMixInputParameters.FromTrack(compositionAudioTracks[0]);
					trackMix.SetVolumeRamp (1f, 0f, transitionTimeRanges[0]);
					trackMixArray.Add (trackMix);

					trackMix = AVMutableAudioMixInputParameters.FromTrack (compositionAudioTracks[1]);
					trackMix.SetVolumeRamp (0f, 1f, transitionTimeRanges[0]);
					trackMix.SetVolumeRamp (1f, 1f, passThroughTimeRanges[1]);
					trackMixArray.Add (trackMix);
				}
			}

			videoComposition.Instructions = instructions.ToArray ();
			audioMix.InputParameters = trackMixArray.ToArray();
		}
コード例 #11
0
        private void BuildTransitionComposition(AVMutableComposition mutableComposition, AVMutableVideoComposition mutableVideoComposition)
        {
            var nextClipStartTime = CMTime.Zero;
            var clipsCount        = this.Clips.Count;

            // Make transitionDuration no greater than half the shortest clip duration.
            var transitionDuration = this.TransitionDuration;

            foreach (var clipTimeRange in this.ClipTimeRanges)
            {
                var halfClipDuration = clipTimeRange.Duration;
                halfClipDuration.TimeScale *= 2; // You can halve a rational by doubling its denominator.
                transitionDuration          = CMTime.GetMinimum(transitionDuration, halfClipDuration);
            }

            // Add two video tracks and two audio tracks.
            var compositionVideoTracks = new AVMutableCompositionTrack[2];
            var compositionAudioTracks = new AVMutableCompositionTrack[2];

            compositionVideoTracks[0] = mutableComposition.AddMutableTrack(AVMediaType.Video, 0);
            compositionVideoTracks[1] = mutableComposition.AddMutableTrack(AVMediaType.Video, 0);
            compositionAudioTracks[0] = mutableComposition.AddMutableTrack(AVMediaType.Audio, 0);
            compositionAudioTracks[1] = mutableComposition.AddMutableTrack(AVMediaType.Audio, 0);

            var passThroughTimeRanges = new CMTimeRange[clipsCount];
            var transitionTimeRanges  = new CMTimeRange[clipsCount];

            // Place clips into alternating video & audio tracks in composition, overlapped by transitionDuration.
            for (int i = 0; i < clipsCount; i++)
            {
                int alternatingIndex = i % 2; // alternating targets: 0, 1, 0, 1, ...
                var asset            = this.Clips[i];
                var timeRangeInAsset = this.ClipTimeRanges[i];

                var clipVideoTrack = asset.TracksWithMediaType(AVMediaType.Video)[0];
                compositionVideoTracks[alternatingIndex].InsertTimeRange(timeRangeInAsset, clipVideoTrack, nextClipStartTime, out _);

                var clipAudioTrack = asset.TracksWithMediaType(AVMediaType.Audio)[0];
                compositionAudioTracks[alternatingIndex].InsertTimeRange(timeRangeInAsset, clipAudioTrack, nextClipStartTime, out _);

                // Remember the time range in which this clip should pass through.
                // First clip ends with a transition.
                // Second clip begins with a transition.
                // Exclude that transition from the pass through time ranges
                passThroughTimeRanges[i] = new CMTimeRange {
                    Start = nextClipStartTime, Duration = timeRangeInAsset.Duration
                };

                if (i > 0)
                {
                    passThroughTimeRanges[i].Start    = CMTime.Add(passThroughTimeRanges[i].Start, transitionDuration);
                    passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration, transitionDuration);
                }

                if (i + 1 < clipsCount)
                {
                    passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration, transitionDuration);
                }

                // The end of this clip will overlap the start of the next by transitionDuration.
                // (Note: this arithmetic falls apart if timeRangeInAsset.duration < 2 * transitionDuration.)
                nextClipStartTime = CMTime.Add(nextClipStartTime, timeRangeInAsset.Duration);
                nextClipStartTime = CMTime.Subtract(nextClipStartTime, transitionDuration);

                // Remember the time range for the transition to the next item.
                if (i + 1 < clipsCount)
                {
                    transitionTimeRanges[i] = new CMTimeRange {
                        Start = nextClipStartTime, Duration = transitionDuration
                    };
                }
            }

            // Set up the video composition to perform cross dissolve or diagonal wipe transitions between clips.
            var instructions = new List <AVVideoCompositionInstruction>();

            // Cycle between "pass through A", "transition from A to B", "pass through B"
            for (int i = 0; i < clipsCount; i++)
            {
                int alternatingIndex = i % 2; // alternating targets

                if (mutableVideoComposition.CustomVideoCompositorClass != null)
                {
                    var videoInstruction = new CustomVideoCompositionInstruction(compositionVideoTracks[alternatingIndex].TrackID, passThroughTimeRanges[i]);
                    instructions.Add(videoInstruction);
                }
                else
                {
                    // Pass through clip i.
                    var passThroughInstruction = AVMutableVideoCompositionInstruction.Create() as AVMutableVideoCompositionInstruction;
                    passThroughInstruction.TimeRange = passThroughTimeRanges[i];

                    var passThroughLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks[alternatingIndex]);
                    passThroughInstruction.LayerInstructions = new[] { passThroughLayer };

                    instructions.Add(passThroughInstruction);
                }

                if (i + 1 < clipsCount)
                {
                    // Add transition from clip i to clip i+1.
                    if (mutableVideoComposition.CustomVideoCompositorClass != null)
                    {
                        var videoInstruction = new CustomVideoCompositionInstruction(new NSNumber[]
                        {
                            compositionVideoTracks[0].TrackID,
                            compositionVideoTracks[1].TrackID
                        }, transitionTimeRanges[i]);

                        if (alternatingIndex == 0)
                        {
                            // First track -> Foreground track while compositing
                            videoInstruction.ForegroundTrackId = compositionVideoTracks[alternatingIndex].TrackID;
                            // Second track -> Background track while compositing
                            videoInstruction.BackgroundTrackId = compositionVideoTracks[1 - alternatingIndex].TrackID;
                        }

                        instructions.Add(videoInstruction);
                    }
                    else
                    {
                        var transitionInstruction = AVMutableVideoCompositionInstruction.Create() as AVMutableVideoCompositionInstruction;
                        transitionInstruction.TimeRange = transitionTimeRanges[i];

                        var fromLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks[alternatingIndex]);
                        var toLayer   = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks[1 - alternatingIndex]);

                        transitionInstruction.LayerInstructions = new[] { toLayer, fromLayer };
                        instructions.Add(transitionInstruction);
                    }
                }
            }

            mutableVideoComposition.Instructions = instructions.ToArray();
        }
コード例 #12
0
		public void BuildCompositionObjects(bool playBack)
		{
			if (Clips == null || Clips.Count == 0) {
				Composition = null;
				VideoComposition = null;
				return;
			}

			var videoSize = Clips [0].NaturalSize;
			var composition = AVMutableComposition.Create ();
			AVMutableVideoComposition videoComposition;

			composition.NaturalSize = videoSize;

			// With transitions:
			// Place clips into alternating video & audio tracks in composition, overlapped by transitionDuration.
			// Set up the video composition to cycle between "pass through A", "transition from A to B",
			// "pass through B".

			videoComposition = AVMutableVideoComposition.Create ();

			//Set CustomVideoCompositorClass based on the Compositor user selected.

			if (TransitionType == TransitionTypeController.DiagonalWipeTransition) {
				videoComposition.CustomVideoCompositorClass = new ObjCRuntime.Class (typeof(DiagonalWipeCompositor));
			} else {
				videoComposition.CustomVideoCompositorClass = new ObjCRuntime.Class (typeof(CrossDissolveCompositor));
			}

			buildTransitionComposition (composition, videoComposition);
			if (videoComposition != null) {
				// Every videoComposition needs these properties to be set:
				videoComposition.FrameDuration = new CMTime (1, 30);
				videoComposition.RenderSize = videoSize;

			}
			Composition = composition;
			VideoComposition = videoComposition;
		}
コード例 #13
0
		void buildTransitionComposition(AVMutableComposition composition, AVMutableVideoComposition videoComposition)
		{
			CMTime nextClipStartTime = CMTime.Zero;
			int clipsCount = Clips.Count;

			// Make transitionDuration no greater than half the shortest clip duration.
			CMTime transitionDuration = TransitionDuration;

			foreach (var clipTimeRange in ClipTimeRanges) {
				if (clipTimeRange == null)
					continue;

				CMTime halfClipDuration = clipTimeRange.CMTimeRangeValue.Duration;
				halfClipDuration.TimeScale *= 2;
				transitionDuration = CMTime.GetMinimum(transitionDuration,halfClipDuration);
			}

			// Add two video tracks and two audio tracks.
			var compositionVideoTracks = new AVMutableCompositionTrack [2];
			var compositionAudioTracks = new AVMutableCompositionTrack [2];

			compositionVideoTracks [0] = composition.AddMutableTrack (AVMediaType.Video, 0);
			compositionVideoTracks [1] = composition.AddMutableTrack (AVMediaType.Video, 0);
			compositionAudioTracks [0] = composition.AddMutableTrack (AVMediaType.Audio, 0);
			compositionAudioTracks [1] = composition.AddMutableTrack (AVMediaType.Audio, 0);

			var passThroughTimeRanges = new CMTimeRange[clipsCount];
			var transitionTimeRanges = new CMTimeRange[clipsCount];

			// Place clips into alternating video & audio tracks in composition, overlapped by transitionDuration.
			for(int i = 0; i < clipsCount; i++)
			{
				int alternatingIndex = i % 2;
				AVAsset asset = Clips [i];
				NSValue clipTimeRange = ClipTimeRanges [i];
				CMTimeRange timeRangeInAsset;
				if (clipTimeRange != null)
					timeRangeInAsset = clipTimeRange.CMTimeRangeValue;
				else
				{
					timeRangeInAsset = new CMTimeRange {
						Start = CMTime.Zero,
						Duration = asset.Duration
					};
				}
				NSError error;
				AVAssetTrack clipVideoTrack = asset.TracksWithMediaType (AVMediaType.Video) [0];
				compositionVideoTracks [alternatingIndex].InsertTimeRange (timeRangeInAsset, clipVideoTrack, nextClipStartTime, out error);

				AVAssetTrack clipAudioTrack = asset.TracksWithMediaType (AVMediaType.Audio) [0];
				compositionAudioTracks [alternatingIndex].InsertTimeRange (timeRangeInAsset, clipAudioTrack, nextClipStartTime, out error);

				// Remember the time range in which this clip should pass through.
				// First clip ends with a transition.
				// Second clip begins with a transition.
				// Exclude that transition from the pass through time ranges
				passThroughTimeRanges [i] = new CMTimeRange {
					Start = nextClipStartTime,
					Duration = timeRangeInAsset.Duration
				};

				if (i > 0) {
					passThroughTimeRanges[i].Start = CMTime.Add(passThroughTimeRanges[i].Start, transitionDuration);
					passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration, transitionDuration);
				}
				if( i + 1 < clipsCount)
					passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration,transitionDuration);

				// The end of this clip will overlap the start of the next by transitionDuration.
				// (Note: this arithmetic falls apart if timeRangeInAsset.duration < 2 * transitionDuration.)
				nextClipStartTime = CMTime.Add (nextClipStartTime, timeRangeInAsset.Duration);
				nextClipStartTime = CMTime.Subtract (nextClipStartTime, transitionDuration);

				// Remember the time range for the transition to the next item.

				if(i + 1 < clipsCount)
				{
					transitionTimeRanges [i] = new CMTimeRange {
						Start  = nextClipStartTime,
						Duration = transitionDuration
					};

				}
			}

			// Set up the video composition to perform cross dissolve or diagonal wipe transitions between clips.
			var instructions = new List<AVVideoCompositionInstruction> ();

			// Cycle between "pass through A", "transition from A to B", "pass through B"
			for(int i = 0;  i < clipsCount; i++)
			{
				int alternatingIndex = i % 2;

//				if (videoComposition.CustomVideoCompositorClass != null) {
//					var videoInstruction = new CustomVideoCompositionInstruction (compositionVideoTracks [alternatingIndex].TrackID, passThroughTimeRanges [i]);
//					instructions.Add (videoInstruction);
//				} else {
//					// Pass through clip i.
//					var passThroughInstruction = AVMutableVideoCompositionInstruction.Create () as AVMutableVideoCompositionInstruction;
//					passThroughInstruction.TimeRange = passThroughTimeRanges [i];
//					var passThroughLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [alternatingIndex]);
//					passThroughInstruction.LayerInstructions = new [] { passThroughLayer };
//					instructions.Add (passThroughInstruction);
//
//				}
				//TODO: Remove following call if previous works
 				if (videoComposition.CustomVideoCompositorClass.Name != "nil") {
					var videoInstruction = new CustomVideoCompositionInstruction (compositionVideoTracks [alternatingIndex].TrackID, passThroughTimeRanges [i]);
					instructions.Add (videoInstruction);

				}
				else {
					// Pass through clip i.
					var passThroughInstruction = AVMutableVideoCompositionInstruction.Create () as AVMutableVideoCompositionInstruction;
					passThroughInstruction.TimeRange = passThroughTimeRanges [i];
					var passThroughLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [alternatingIndex]);
					passThroughInstruction.LayerInstructions = new [] { passThroughLayer };
					instructions.Add (passThroughInstruction);

				}

				if (i + 1 < clipsCount) {
					// Add transition from clip i to clip i+1.
//					if (videoComposition.CustomVideoCompositorClass != null) {
//						var videoInstruction = new CustomVideoCompositionInstruction (new NSNumber [] {
//							compositionVideoTracks [0].TrackID,
//							compositionVideoTracks [1].TrackID
//						}, transitionTimeRanges [1]);
//
//						if (alternatingIndex == 0) {
//							videoInstruction.ForegroundTrackID = compositionVideoTracks [alternatingIndex].TrackID;
//							videoInstruction.BackgroundTrackID = compositionVideoTracks [1 - alternatingIndex].TrackID;
//						}
//
//						instructions.Add (videoInstruction);
//					} else {
//						var transitionInstruction = AVMutableVideoCompositionInstruction.Create () as AVMutableVideoCompositionInstruction;
//						transitionInstruction.TimeRange = transitionTimeRanges [i];
//						var fromLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [alternatingIndex]);
//						var toLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [1 - alternatingIndex]);
//						transitionInstruction.LayerInstructions = new [] { toLayer, fromLayer };
//						instructions.Add (transitionInstruction);
//					}
					// TODO: remove following call if previous works
					if (videoComposition.CustomVideoCompositorClass.Name != "nil") {
						NSNumber[] sources = {
							new NSNumber (compositionVideoTracks [0].TrackID),
							new NSNumber (compositionVideoTracks [1].TrackID)
						};
						var videoInstructions = new CustomVideoCompositionInstruction (sources, transitionTimeRanges [i]);
						if (alternatingIndex == 0) {
							videoInstructions.ForegroundTrackID = compositionVideoTracks [alternatingIndex].TrackID;
							videoInstructions.BackgroundTrackID = compositionVideoTracks [1 - alternatingIndex].TrackID;
						}

						instructions.Add (videoInstructions);
						Console.WriteLine ("Add transition from clip i to clip i+1");
					} else {
						var transitionInstruction = AVMutableVideoCompositionInstruction.Create () as AVMutableVideoCompositionInstruction;
						transitionInstruction.TimeRange = transitionTimeRanges [i];
						AVMutableVideoCompositionLayerInstruction fromLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [alternatingIndex]);
						AVMutableVideoCompositionLayerInstruction toLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack (compositionVideoTracks [1 - alternatingIndex]);
						transitionInstruction.LayerInstructions = new AVVideoCompositionLayerInstruction[] {
							fromLayer,
							toLayer,
						};
						instructions.Add (transitionInstruction);
					}
				}
			}

			videoComposition.Instructions = instructions.ToArray ();
		}
コード例 #14
0
        public Task <OperationResult> AddAudioToVideoTrack(string videoFilePath, string audioFilePath, string outputFilePath,
                                                           float volume = 1, float fadeOutDuration = 0)
        {
            var tcs = new TaskCompletionSource <OperationResult>();

            var composition           = AVMutableComposition.Create();
            var videoCompositionTrack = composition.AddMutableTrack(AVMediaType.Video, 0);
            var audioCompositionTrack = composition.AddMutableTrack(AVMediaType.Audio, 0);

            var videoUrl        = NSUrl.FromFilename(videoFilePath);
            var videoAsset      = AVAsset.FromUrl(videoUrl);
            var videoAssetTrack = videoAsset.TracksWithMediaType(AVMediaType.Video).First();

            var audioUrl        = NSUrl.FromFilename(audioFilePath);
            var audioAsset      = AVAsset.FromUrl(audioUrl);
            var audioAssetTrack = audioAsset.TracksWithMediaType(AVMediaType.Audio).First();

            CGSize size = videoAssetTrack.NaturalSize;
            CMTime time = CMTime.Zero;

            var range = new CMTimeRange
            {
                Start    = CMTime.Zero,
                Duration = videoAssetTrack.TimeRange.Duration
            };

            NSError error = null;

            videoCompositionTrack.InsertTimeRange(range, videoAssetTrack, time, out error);
            if (error != null)
            {
                Console.WriteLine("Error adding video composition track: " + error.LocalizedDescription);
            }

            error = null;
            audioCompositionTrack.InsertTimeRange(range, audioAssetTrack, time, out error);
            if (error != null)
            {
                Console.WriteLine("Error adding audio composition track: " + error.LocalizedDescription);
            }


            var audioMix         = AVMutableAudioMix.Create();
            var audioInputParams = AVMutableAudioMixInputParameters.FromTrack(audioCompositionTrack);

            audioInputParams.SetVolume(volume, CMTime.Zero);

            if (fadeOutDuration > 0)
            {
                var fadeOutStartTime = CMTime.Subtract(videoAssetTrack.TimeRange.Duration, CMTime.FromSeconds(fadeOutDuration, audioAssetTrack.NaturalTimeScale));
                var fadeOutRange     = new CMTimeRange
                {
                    Start    = fadeOutStartTime,
                    Duration = CMTime.FromSeconds(fadeOutDuration, audioAssetTrack.NaturalTimeScale)
                };

                audioInputParams.SetVolumeRamp(volume, 0.0f, fadeOutRange);
            }

            audioMix.InputParameters = new[] { audioInputParams };

            var session = new AVAssetExportSession(composition, AVAssetExportSession.PresetHighestQuality);

            session.OutputUrl      = NSUrl.FromFilename(outputFilePath);
            session.OutputFileType = AVFileType.Mpeg4;
            session.AudioMix       = audioMix;

            session.ExportAsynchronously(() =>
            {
                if (session.Status == AVAssetExportSessionStatus.Failed)
                {
                    tcs.SetResult(OperationResult.AsFailure(session.Error.LocalizedDescription));
                }
                else
                {
                    tcs.SetResult(OperationResult.AsSuccess());
                }
            });

            return(tcs.Task);
        }