зеркало из https://github.com/xamarin/ios-samples.git
[avcustomedit] Some timing and simplification fixes (#349)
Running this sample on device with the interpreter has spotted a few issues in the sample. * Timing issue: Use `DispatchGroup.Notify` (like sample) instead of `Waiting` (it's not the same) and remove the `InvokeOnMainThread` since we're already running on that thread. Also uncomment some code that, likely, did not work because `Notify` was not used; * Timing issue: `composition` can be `null` but it triggers an `ArgumentNullException` (because the API does not _officially_ accept `nil`). * Enhancement: Set initial capacity of `List<T>` - just like it's done in the original sample; * Simplification: There's no point in checking for `null` values inside `List<T>` since that would have triggered an `ArgumentNullException`; * Simplification" There's no point in converting `CMTimeRange` into `NSValue` (and back into `CMTimeRange`). In contrast to `NSArray` we can add non-`NSObject` (including value type like struct) inside `List<T>`; * Cleanup: remove ugly `goto` and use `_` for unused `out NSError` This will fix https://github.com/xamarin/xamarin-macios/issues/5364
This commit is contained in:
Родитель
beb972af1f
Коммит
df1b3e3a62
|
@ -13,13 +13,19 @@ namespace AVCustomEdit
|
|||
|
||||
public List<AVAsset> Clips { get; set; } // array of AVURLAssets
|
||||
|
||||
public List<NSValue> ClipTimeRanges { get; set; } // array of CMTimeRanges stored in NSValues.
|
||||
public List<CMTimeRange> ClipTimeRanges { get; set; }
|
||||
|
||||
public TransitionType TransitionType { get; set; }
|
||||
|
||||
public CMTime TransitionDuration { get; set; }
|
||||
|
||||
public AVPlayerItem PlayerItem => new AVPlayerItem(this.composition) { VideoComposition = this.videoComposition };
|
||||
public AVPlayerItem PlayerItem {
|
||||
get {
|
||||
if (composition == null)
|
||||
return null;
|
||||
return new AVPlayerItem(this.composition) { VideoComposition = this.videoComposition };
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildTransitionComposition(AVMutableComposition mutableComposition, AVMutableVideoComposition mutableVideoComposition)
|
||||
{
|
||||
|
@ -30,12 +36,9 @@ namespace AVCustomEdit
|
|||
var transitionDuration = this.TransitionDuration;
|
||||
foreach (var clipTimeRange in this.ClipTimeRanges)
|
||||
{
|
||||
if (clipTimeRange != null)
|
||||
{
|
||||
var halfClipDuration = clipTimeRange.CMTimeRangeValue.Duration;
|
||||
halfClipDuration.TimeScale *= 2; // You can halve a rational by doubling its denominator.
|
||||
transitionDuration = CMTime.GetMinimum(transitionDuration, halfClipDuration);
|
||||
}
|
||||
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.
|
||||
|
@ -55,16 +58,13 @@ namespace AVCustomEdit
|
|||
{
|
||||
int alternatingIndex = i % 2; // alternating targets: 0, 1, 0, 1, ...
|
||||
var asset = this.Clips[i];
|
||||
var clipTimeRange = this.ClipTimeRanges[i];
|
||||
|
||||
var timeRangeInAsset = clipTimeRange != null ? clipTimeRange.CMTimeRangeValue
|
||||
: new CMTimeRange { Start = CMTime.Zero, Duration = asset.Duration };
|
||||
var timeRangeInAsset = this.ClipTimeRanges[i];
|
||||
|
||||
var clipVideoTrack = asset.TracksWithMediaType(AVMediaType.Video)[0];
|
||||
compositionVideoTracks[alternatingIndex].InsertTimeRange(timeRangeInAsset, clipVideoTrack, nextClipStartTime, out NSError error);
|
||||
compositionVideoTracks[alternatingIndex].InsertTimeRange(timeRangeInAsset, clipVideoTrack, nextClipStartTime, out _);
|
||||
|
||||
var clipAudioTrack = asset.TracksWithMediaType(AVMediaType.Audio)[0];
|
||||
compositionAudioTracks[alternatingIndex].InsertTimeRange(timeRangeInAsset, clipAudioTrack, nextClipStartTime, out error);
|
||||
compositionAudioTracks[alternatingIndex].InsertTimeRange(timeRangeInAsset, clipAudioTrack, nextClipStartTime, out _);
|
||||
|
||||
// Remember the time range in which this clip should pass through.
|
||||
// First clip ends with a transition.
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace AVCustomEdit
|
|||
private SimpleEditor editor;
|
||||
|
||||
private List<AVAsset> clips;
|
||||
private List<NSValue> clipTimeRanges;
|
||||
private List<CMTimeRange> clipTimeRanges;
|
||||
|
||||
private AVPlayer player;
|
||||
private AVPlayerItem playerItem;
|
||||
|
@ -44,8 +44,8 @@ namespace AVCustomEdit
|
|||
base.ViewDidLoad();
|
||||
|
||||
this.editor = new SimpleEditor();
|
||||
this.clips = new List<AVAsset>();
|
||||
this.clipTimeRanges = new List<NSValue>();
|
||||
this.clips = new List<AVAsset>(2);
|
||||
this.clipTimeRanges = new List<CMTimeRange>(2);
|
||||
|
||||
// Defaults for the transition settings.
|
||||
this.transitionType = TransitionType.DiagonalWipeTransition;
|
||||
|
@ -115,8 +115,9 @@ namespace AVCustomEdit
|
|||
this.LoadAsset(asset2, assetKeysToLoadAndTest, dispatchGroup);
|
||||
|
||||
// Wait until both assets are loaded
|
||||
dispatchGroup.Wait(DispatchTime.Forever);
|
||||
base.InvokeOnMainThread(() => this.SynchronizeWithEditor());
|
||||
dispatchGroup.Notify(DispatchQueue.MainQueue, () => {
|
||||
SynchronizeWithEditor();
|
||||
});
|
||||
}
|
||||
|
||||
private void LoadAsset(AVAsset asset, string[] assetKeysToLoad, DispatchGroup dispatchGroup)
|
||||
|
@ -124,28 +125,32 @@ namespace AVCustomEdit
|
|||
dispatchGroup.Enter();
|
||||
asset.LoadValuesAsynchronously(assetKeysToLoad, () =>
|
||||
{
|
||||
bool add_asset = true;
|
||||
// First test whether the values of each of the keys we need have been successfully loaded.
|
||||
foreach (var key in assetKeysToLoad)
|
||||
{
|
||||
if (asset.StatusOfValue(key, out NSError error) == AVKeyValueStatus.Failed)
|
||||
{
|
||||
Console.WriteLine($"Key value loading failed for key:{key} with error: {error?.LocalizedDescription ?? ""}");
|
||||
goto bail;
|
||||
add_asset = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!asset.Composable)
|
||||
{
|
||||
Console.WriteLine("Asset is not composable");
|
||||
goto bail;
|
||||
add_asset = false;
|
||||
}
|
||||
|
||||
this.clips.Add(asset);
|
||||
// This code assumes that both assets are atleast 5 seconds long.
|
||||
var value = NSValue.FromCMTimeRange(new CMTimeRange { Start = CMTime.FromSeconds(0, 1), Duration = CMTime.FromSeconds(5, 1) });
|
||||
this.clipTimeRanges.Add(value);
|
||||
if (add_asset)
|
||||
{
|
||||
this.clips.Add(asset);
|
||||
// This code assumes that both assets are atleast 5 seconds long.
|
||||
var value = new CMTimeRange { Start = CMTime.FromSeconds(0, 1), Duration = CMTime.FromSeconds(5, 1) };
|
||||
this.clipTimeRanges.Add(value);
|
||||
}
|
||||
|
||||
bail:
|
||||
dispatchGroup.Leave();
|
||||
});
|
||||
}
|
||||
|
@ -185,8 +190,8 @@ namespace AVCustomEdit
|
|||
private void SynchronizeWithEditor()
|
||||
{
|
||||
// Clips
|
||||
this.SynchronizeEditorClipsWithOurClips();
|
||||
this.SynchronizeEditorClipTimeRangesWithOurClipTimeRanges();
|
||||
this.editor.Clips = new List<AVAsset> (clips);
|
||||
this.editor.ClipTimeRanges = new List<CMTimeRange> (clipTimeRanges);
|
||||
|
||||
// Transitions
|
||||
if (this.isTransitionsEnabled)
|
||||
|
@ -200,36 +205,8 @@ namespace AVCustomEdit
|
|||
}
|
||||
|
||||
// Build AVComposition and AVVideoComposition objects for playback
|
||||
//this.editor.BuildCompositionObjectsForPlayback(true);
|
||||
//this.SynchronizePlayerWithEditor();
|
||||
}
|
||||
|
||||
private void SynchronizeEditorClipsWithOurClips()
|
||||
{
|
||||
var validClips = new List<AVAsset>();
|
||||
foreach (var asset in this.clips)
|
||||
{
|
||||
if (asset != null)
|
||||
{
|
||||
validClips.Add(asset);
|
||||
}
|
||||
}
|
||||
|
||||
this.editor.Clips = validClips;
|
||||
}
|
||||
|
||||
private void SynchronizeEditorClipTimeRangesWithOurClipTimeRanges()
|
||||
{
|
||||
var validClipTimeRanges = new List<NSValue>();
|
||||
foreach (var timeRange in this.clipTimeRanges)
|
||||
{
|
||||
if (timeRange != null)
|
||||
{
|
||||
validClipTimeRanges.Add(timeRange);
|
||||
}
|
||||
}
|
||||
|
||||
this.editor.ClipTimeRanges = validClipTimeRanges;
|
||||
this.editor.BuildCompositionObjectsForPlayback(true);
|
||||
this.SynchronizePlayerWithEditor();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
Загрузка…
Ссылка в новой задаче