* added new project

* fixed playing status

* updated formatting

* added several optimization steps

* added cooperation with transition conrtoller

* updated photo library saving

* fixed export

* fxied launch screen and transitions

* fixed transitions

* deleted old project

* added assets

* small optimization

* added data

* Update README.md

* fixed iPhone X UI

* Updated storyboard
This commit is contained in:
Mykyta Bondarenko 2018-12-07 06:34:22 +02:00 коммит произвёл Craig Dunn
Родитель 4f10108c0a
Коммит d4c8fdeb47
52 изменённых файлов: 2581 добавлений и 2232 удалений

Просмотреть файл

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AVCustomEdit", "AVCustomEdit\AVCustomEdit.csproj", "{B086E3A5-1D26-4F87-B908-2521E3091A2D}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AVCustomEdit", "AVCustomEdit\AVCustomEdit.csproj", "{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -13,30 +13,27 @@ Global
AppStore|iPhone = AppStore|iPhone
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.AppStore|iPhone.Build.0 = AppStore|iPhone
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.Debug|iPhone.ActiveCfg = Debug|iPhone
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.Debug|iPhone.Build.0 = Debug|iPhone
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.Release|iPhone.ActiveCfg = Release|iPhone
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.Release|iPhone.Build.0 = Release|iPhone
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{B086E3A5-1D26-4F87-B908-2521E3091A2D}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.Debug|iPhone.ActiveCfg = Debug|iPhone
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.Debug|iPhone.Build.0 = Debug|iPhone
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.Release|iPhone.ActiveCfg = Release|iPhone
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.Release|iPhone.Build.0 = Release|iPhone
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.Ad-Hoc|iPhone.ActiveCfg = Release|iPhone
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.Ad-Hoc|iPhone.Build.0 = Release|iPhone
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.AppStore|iPhone.ActiveCfg = Release|iPhone
{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}.AppStore|iPhone.Build.0 = Release|iPhone
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = AVCustomEdit\AVCustomEdit.csproj
Policies = $0
$0.TextStylePolicy = $1
$1.TabsToSpaces = False
$1.inheritsSet = VisualStudio
$1.inheritsScope = text/plain
$1.scope = text/x-csharp
$1.FileWidth = 80
$1.inheritsSet = null
$0.CSharpFormattingPolicy = $2
$2.inheritsSet = Mono
$2.inheritsScope = text/x-csharp
$2.scope = text/x-csharp
EndGlobalSection
EndGlobal

Просмотреть файл

@ -1,149 +1,144 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{B086E3A5-1D26-4F87-B908-2521E3091A2D}</ProjectGuid>
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Exe</OutputType>
<RootNamespace>AVCustomEdit</RootNamespace>
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
<AssemblyName>AVCustomEdit</AssemblyName>
<TargetFrameworkIdentifier>Xamarin.iOS</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v1.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
<DebugSymbols>false</DebugSymbols>
<DebugType></DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<MtouchLink>None</MtouchLink>
<ConsolePause>false</ConsolePause>
<MtouchDebug>true</MtouchDebug>
<MtouchArch>x86_64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
<DebugType></DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhoneSimulator\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<MtouchLink>None</MtouchLink>
<ConsolePause>false</ConsolePause>
<MtouchArch>x86_64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
<DebugSymbols>false</DebugSymbols>
<DebugType></DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhone\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<MtouchDebug>true</MtouchDebug>
<ConsolePause>false</ConsolePause>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchArch>ARM64</MtouchArch>
<MtouchUseRefCounting>true</MtouchUseRefCounting>
<MtouchI18n></MtouchI18n>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
<DebugType></DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhone\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignKey>iPhone Developer</CodesignKey>
<ConsolePause>false</ConsolePause>
<MtouchArch>ARM64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Ad-Hoc|iPhone' ">
<DebugType></DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhone\Ad-Hoc</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignKey>iPhone Distribution</CodesignKey>
<BuildIpa>true</BuildIpa>
<ConsolePause>false</ConsolePause>
<CodesignProvision>Automatic:AdHoc</CodesignProvision>
<MtouchArch>ARM64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|iPhone' ">
<DebugType></DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhone\AppStore</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignKey>iPhone Distribution</CodesignKey>
<ConsolePause>false</ConsolePause>
<CodesignProvision>Automatic:AppStore</CodesignProvision>
<MtouchArch>ARM64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
<Reference Include="OpenTK-1.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
<Folder Include="OpenGL Renderers\" />
<Folder Include="Custom Compositors\" />
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
</ItemGroup>
<ItemGroup>
<Compile Include="Main.cs" />
<Compile Include="AppDelegate.cs" />
<Compile Include="PlayerViewController.cs" />
<Compile Include="PlayerViewController.designer.cs">
<DependentUpon>PlayerViewController.cs</DependentUpon>
</Compile>
<Compile Include="PlayerView.cs" />
<Compile Include="PlayerView.designer.cs">
<DependentUpon>PlayerView.cs</DependentUpon>
</Compile>
<Compile Include="TransitionTypeController.cs" />
<Compile Include="TransitionTypeController.designer.cs">
<DependentUpon>TransitionTypeController.cs</DependentUpon>
</Compile>
<Compile Include="SimpleEditor.cs" />
<Compile Include="OpenGL Renderers\DiagonalWipeRenderer.cs" />
<Compile Include="OpenGL Renderers\CrossDissolveRenderer.cs" />
<Compile Include="OpenGL Renderers\OpenGLRenderer.cs" />
<Compile Include="Custom Compositors\CustomVideoCompositionInstruction.cs" />
<Compile Include="Custom Compositors\CustomVideoCompositor.cs" />
</ItemGroup>
<ItemGroup>
<InterfaceDefinition Include="MainStoryboard.storyboard" />
</ItemGroup>
<ItemGroup>
<BundleResource Include="sample_clip1.m4v" />
<BundleResource Include="sample_clip2.mov" />
<BundleResource Include="Resources\Icon.png" />
<BundleResource Include="Resources\Icon%402x.png" />
<BundleResource Include="Resources\Icon-72.png" />
<BundleResource Include="Resources\Icon-72%402x.png" />
<BundleResource Include="Resources\Icon-Small.png" />
<BundleResource Include="Resources\Icon-Small%402x.png" />
<BundleResource Include="Resources\Icon-Small-50.png" />
<BundleResource Include="Resources\Default.png" />
<BundleResource Include="Resources\Default%402x.png" />
<BundleResource Include="Resources\Default-568h%402x.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{E35D29CE-B9F3-41D9-A22A-C00FD94D392C}</ProjectGuid>
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Exe</OutputType>
<RootNamespace>AVCustomEdit</RootNamespace>
<AssemblyName>AVCustomEdit</AssemblyName>
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
<DefineConstants>DEBUG;ENABLE_TEST_CLOUD;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchDebug>true</MtouchDebug>
<MtouchNoSymbolStrip>true</MtouchNoSymbolStrip>
<MtouchFastDev>true</MtouchFastDev>
<IOSDebuggerPort>13612</IOSDebuggerPort>
<MtouchLink>None</MtouchLink>
<MtouchArch>x86_64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
<DeviceSpecificBuild>false</DeviceSpecificBuild>
<MtouchVerbosity></MtouchVerbosity>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhone\Release</OutputPath>
<DefineConstants></DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchUseLlvm>true</MtouchUseLlvm>
<MtouchFloat32>true</MtouchFloat32>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<MtouchLink>SdkOnly</MtouchLink>
<MtouchArch>ARM64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
<MtouchVerbosity></MtouchVerbosity>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhoneSimulator\Release</OutputPath>
<DefineConstants></DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchNoSymbolStrip>true</MtouchNoSymbolStrip>
<MtouchLink>None</MtouchLink>
<MtouchArch>x86_64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
<MtouchVerbosity></MtouchVerbosity>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhone\Debug</OutputPath>
<DefineConstants>DEBUG;ENABLE_TEST_CLOUD;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignKey>iPhone Developer</CodesignKey>
<DeviceSpecificBuild>true</DeviceSpecificBuild>
<MtouchDebug>true</MtouchDebug>
<MtouchNoSymbolStrip>true</MtouchNoSymbolStrip>
<MtouchFastDev>true</MtouchFastDev>
<MtouchFloat32>true</MtouchFloat32>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<IOSDebuggerPort>11505</IOSDebuggerPort>
<MtouchLink>SdkOnly</MtouchLink>
<MtouchArch>ARM64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
<MtouchVerbosity></MtouchVerbosity>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
<Reference Include="OpenTK-1.0" />
</ItemGroup>
<ItemGroup>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Contents.json" />
<ImageAsset Include="Assets.xcassets\Contents.json" />
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\app-store-logo.png" />
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-app-83.5%402x.png" />
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\icon-app-76%402x.png" />
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\icon-app-76.png" />
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\icon-spotlight-29.png" />
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\icon-spotlight-29%402x.png" />
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\icon-spotlight-29%403x.png" />
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\icon-app-60%402x.png" />
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-app-60%403x.png" />
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\icon-spotlight-40%402x.png" />
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\icon-spotlight-40%403x.png" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
<Folder Include="OpenGL Renderers\" />
<Folder Include="Custom Compositors\" />
</ItemGroup>
<ItemGroup>
<InterfaceDefinition Include="LaunchScreen.storyboard" />
<InterfaceDefinition Include="Main.storyboard" />
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
<None Include="Entitlements.plist" />
</ItemGroup>
<ItemGroup>
<Compile Include="Main.cs" />
<Compile Include="AppDelegate.cs" />
<Compile Include="ViewController.cs" />
<Compile Include="ViewController.designer.cs">
<DependentUpon>ViewController.cs</DependentUpon>
</Compile>
<Compile Include="PlayerView.cs" />
<Compile Include="SimpleEditor.cs" />
<Compile Include="TransitionTypeController.cs" />
<Compile Include="TransitionTypeController.designer.cs">
<DependentUpon>TransitionTypeController.cs</DependentUpon>
</Compile>
<Compile Include="OpenGL Renderers\CrossDissolveRenderer.cs" />
<Compile Include="OpenGL Renderers\DiagonalWipeRenderer.cs" />
<Compile Include="OpenGL Renderers\OpenGLRenderer.cs" />
<Compile Include="Custom Compositors\CustomVideoCompositionInstruction.cs" />
<Compile Include="Custom Compositors\CustomVideoCompositor.cs" />
</ItemGroup>
<ItemGroup>
<BundleResource Include="Resources\sample_clip1.m4v" />
<BundleResource Include="Resources\sample_clip2.mov" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
</Project>

Просмотреть файл

@ -1,21 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using Foundation;
using UIKit;
namespace AVCustomEdit
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
// User Interface of the application, as well as listening (and optionally responding) to application events from iOS.
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
public class AppDelegate : UIApplicationDelegate
{
// class-level declarations
public override UIWindow Window {
get;
set;
public override UIWindow Window { get; set; }
public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
// Override point for customization after application launch.
// If not required for your application you can safely delete this method
return true;
}
}
}
}

Просмотреть файл

@ -0,0 +1,244 @@
{
"images": [
{
"size": "20x20",
"scale": "2x",
"idiom": "iphone"
},
{
"size": "20x20",
"scale": "3x",
"idiom": "iphone"
},
{
"filename": "icon-spotlight-29@2x.png",
"size": "29x29",
"scale": "2x",
"idiom": "iphone"
},
{
"filename": "icon-spotlight-29@3x.png",
"size": "29x29",
"scale": "3x",
"idiom": "iphone"
},
{
"filename": "icon-spotlight-40@2x.png",
"size": "40x40",
"scale": "2x",
"idiom": "iphone"
},
{
"filename": "icon-spotlight-40@3x.png",
"size": "40x40",
"scale": "3x",
"idiom": "iphone"
},
{
"filename": "icon-app-60@2x.png",
"size": "60x60",
"scale": "2x",
"idiom": "iphone"
},
{
"filename": "Icon-app-60@3x.png",
"size": "60x60",
"scale": "3x",
"idiom": "iphone"
},
{
"size": "20x20",
"scale": "1x",
"idiom": "ipad"
},
{
"size": "20x20",
"scale": "2x",
"idiom": "ipad"
},
{
"filename": "icon-spotlight-29.png",
"size": "29x29",
"scale": "1x",
"idiom": "ipad"
},
{
"filename": "icon-spotlight-29@2x.png",
"size": "29x29",
"scale": "2x",
"idiom": "ipad"
},
{
"size": "40x40",
"scale": "1x",
"idiom": "ipad"
},
{
"filename": "icon-spotlight-40@2x.png",
"size": "40x40",
"scale": "2x",
"idiom": "ipad"
},
{
"filename": "Icon-app-83.5@2x.png",
"size": "83.5x83.5",
"scale": "2x",
"idiom": "ipad"
},
{
"filename": "icon-app-76.png",
"size": "76x76",
"scale": "1x",
"idiom": "ipad"
},
{
"filename": "icon-app-76@2x.png",
"size": "76x76",
"scale": "2x",
"idiom": "ipad"
},
{
"filename": "app-store-logo.png",
"size": "1024x1024",
"scale": "1x",
"idiom": "ios-marketing"
},
{
"size": "60x60",
"scale": "2x",
"idiom": "car"
},
{
"size": "60x60",
"scale": "3x",
"idiom": "car"
},
{
"role": "notificationCenter",
"size": "24x24",
"subtype": "38mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "notificationCenter",
"size": "27.5x27.5",
"subtype": "42mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "companionSettings",
"size": "29x29",
"scale": "2x",
"idiom": "watch"
},
{
"role": "companionSettings",
"size": "29x29",
"scale": "3x",
"idiom": "watch"
},
{
"role": "appLauncher",
"size": "40x40",
"subtype": "38mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "appLauncher",
"size": "44x44",
"subtype": "40mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "appLauncher",
"size": "50x50",
"subtype": "44mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "quickLook",
"size": "86x86",
"subtype": "38mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "quickLook",
"size": "98x98",
"subtype": "42mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "quickLook",
"size": "108x108",
"subtype": "44mm",
"scale": "2x",
"idiom": "watch"
},
{
"size": "1024x1024",
"scale": "1x",
"idiom": "watch-marketing"
},
{
"size": "16x16",
"scale": "1x",
"idiom": "mac"
},
{
"size": "16x16",
"scale": "2x",
"idiom": "mac"
},
{
"size": "32x32",
"scale": "1x",
"idiom": "mac"
},
{
"size": "32x32",
"scale": "2x",
"idiom": "mac"
},
{
"size": "128x128",
"scale": "1x",
"idiom": "mac"
},
{
"size": "128x128",
"scale": "2x",
"idiom": "mac"
},
{
"size": "256x256",
"scale": "1x",
"idiom": "mac"
},
{
"size": "256x256",
"scale": "2x",
"idiom": "mac"
},
{
"size": "512x512",
"scale": "1x",
"idiom": "mac"
},
{
"size": "512x512",
"scale": "2x",
"idiom": "mac"
}
],
"info": {
"version": 1,
"author": "xcode"
}
}

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 8.6 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 22 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.3 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.3 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 900 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.8 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.5 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.2 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.3 KiB

Просмотреть файл

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Просмотреть файл

@ -1,68 +1,80 @@
using AVFoundation;
using CoreMedia;
using Foundation;
using ObjCRuntime;
namespace AVCustomEdit
{
public class CustomVideoCompositionInstruction : AVVideoCompositionInstruction
{
public int ForegroundTrackID;
public int BackgroundTrackID;
public class CustomVideoCompositionInstruction : AVVideoCompositionInstruction
{
private readonly NSNumber[] requiredSourceTrackIds;
private readonly bool enablePostProcessing;
private readonly int passthroughTrackId;
private readonly bool containsTweening;
private readonly CMTimeRange timeRange;
CMTimeRange timeRange;
readonly int passthroughTrackID;
readonly NSNumber [] requiredSourceTrackIDs;
readonly bool enablePostProcessing;
readonly bool containsTweening;
public CustomVideoCompositionInstruction() : base() { }
public override int PassthroughTrackID {
get {
return passthroughTrackID;
}
}
public CustomVideoCompositionInstruction(int passthroughTrackId, CMTimeRange timeRange) : base()
{
this.passthroughTrackId = passthroughTrackId;
this.requiredSourceTrackIds = null;
this.timeRange = timeRange;
this.containsTweening = false;
this.enablePostProcessing = false;
}
public override NSNumber [] RequiredSourceTrackIDs {
get {
return requiredSourceTrackIDs;
}
}
public CustomVideoCompositionInstruction(NSNumber[] sourceTracksIds, CMTimeRange timeRange) : base()
{
this.requiredSourceTrackIds = sourceTracksIds;
this.passthroughTrackId = 0;
this.timeRange = timeRange;
this.containsTweening = true;
this.enablePostProcessing = false;
}
public override CMTimeRange TimeRange {
get {
return timeRange;
}
}
public override bool EnablePostProcessing {
get {
return enablePostProcessing;
}
}
public override bool ContainsTweening {
get {
return containsTweening;
}
}
public int ForegroundTrackId { get; set; }
public CustomVideoCompositionInstruction ()
{
}
public int BackgroundTrackId { get; set; }
public CustomVideoCompositionInstruction (int passthroughTrackID, CMTimeRange timeRange)
{
this.passthroughTrackID = passthroughTrackID;
requiredSourceTrackIDs = null;
this.timeRange = timeRange;
containsTweening = false;
enablePostProcessing = false;
}
public override int PassthroughTrackID => this.passthroughTrackId;
public CustomVideoCompositionInstruction(NSNumber [] sourceTracksIDS, CMTimeRange timeRange)
{
requiredSourceTrackIDs = sourceTracksIDS;
passthroughTrackID = 0;
this.timeRange = timeRange;
containsTweening = true;
enablePostProcessing = false;
}
}
public override NSNumber[] RequiredSourceTrackIDs => this.requiredSourceTrackIds;
public override CMTimeRange TimeRange => this.timeRange;
public override bool EnablePostProcessing => this.enablePostProcessing;
public override bool ContainsTweening => this.containsTweening;
[return: Release]
public override NSObject Copy()
{
return CustomVideoCompositionInstruction.Copy(this);
}
[return: Release]
public override NSObject MutableCopy()
{
return CustomVideoCompositionInstruction.Copy(this);
}
public static CustomVideoCompositionInstruction Copy(CustomVideoCompositionInstruction current)
{
CustomVideoCompositionInstruction result = null;
if (current.RequiredSourceTrackIDs != null && current.RequiredSourceTrackIDs.Length > 0)
{
result = new CustomVideoCompositionInstruction(current.RequiredSourceTrackIDs, current.TimeRange);
}
else
{
result = new CustomVideoCompositionInstruction(current.PassthroughTrackID, current.TimeRange);
}
result.ForegroundTrackId = current.ForegroundTrackId;
result.BackgroundTrackId = current.BackgroundTrackId;
return result;
}
}
}

Просмотреть файл

@ -1,149 +1,174 @@
using System;
using CoreGraphics;
using Foundation;
using AVFoundation;
using CoreFoundation;
using CoreVideo;
using CoreGraphics;
using CoreMedia;
using CoreVideo;
using Foundation;
using System;
namespace AVCustomEdit
{
public class CrossDissolveCompositor : CustomVideoCompositor
{
public CrossDissolveCompositor (IntPtr handle) : base (handle)
{
oglRender = new CrossDissolveRenderer ();
}
public class CrossDissolveCompositor : CustomVideoCompositor
{
public CrossDissolveCompositor(IntPtr handle) : base(handle)
{
Render = new CrossDissolveRenderer();
}
public CrossDissolveCompositor(AVVideoComposition videoComposition) : base(videoComposition)
{
oglRender = new CrossDissolveRenderer ();
}
}
public CrossDissolveCompositor(AVVideoComposition videoComposition) : base(videoComposition)
{
Render = new CrossDissolveRenderer();
}
}
public class DiagonalWipeCompositor : CustomVideoCompositor
{
public DiagonalWipeCompositor (IntPtr handle) : base (handle)
{
oglRender = new DiagonalWipeRenderer ();
}
public class DiagonalWipeCompositor : CustomVideoCompositor
{
public DiagonalWipeCompositor(IntPtr handle) : base(handle)
{
Render = new DiagonalWipeRenderer();
}
public DiagonalWipeCompositor(AVVideoComposition videoComposition) : base(videoComposition)
{
oglRender = new DiagonalWipeRenderer ();
}
}
public DiagonalWipeCompositor(AVVideoComposition videoComposition) : base(videoComposition)
{
Render = new DiagonalWipeRenderer();
}
}
public class CustomVideoCompositor : AVVideoCompositing
{
bool shouldCancelAllRequests;
bool renderContextDidChange;
DispatchQueue renderingQueue;
DispatchQueue renderContextQueue;
AVVideoCompositionRenderContext renderContext;
//CVPixelBuffer previousBuffer;
public OpenGLRenderer oglRender;
public class CustomVideoCompositor : AVVideoCompositing
{
private bool shouldCancelAllRequests;
private bool renderContextDidChange;
private DispatchQueue renderingQueue;
private DispatchQueue renderContextQueue;
private AVVideoCompositionRenderContext renderContext;
//private CVPixelBuffer previousBuffer;
public CustomVideoCompositor (IntPtr handle) : base (handle)
{
renderingQueue = new DispatchQueue ("com.apple.aplcustomvideocompositor.renderingqueue");
renderContextQueue = new DispatchQueue ("com.apple.aplcustomvideocompositor.rendercontextqueue");
renderContextDidChange = false;
}
public CustomVideoCompositor(IntPtr handle) : base(handle)
{
renderingQueue = new DispatchQueue("com.apple.aplcustomvideocompositor.renderingqueue");
renderContextQueue = new DispatchQueue("com.apple.aplcustomvideocompositor.rendercontextqueue");
//previousBuffer = null;
renderContextDidChange = false;
}
public CustomVideoCompositor (AVVideoComposition videoComposition)
{
renderingQueue = new DispatchQueue ("com.apple.aplcustomvideocompositor.renderingqueue");
renderContextQueue = new DispatchQueue ("com.apple.aplcustomvideocompositor.rendercontextqueue");
renderContextDidChange = false;
}
public CustomVideoCompositor(AVVideoComposition videoComposition)
{
renderingQueue = new DispatchQueue("com.apple.aplcustomvideocompositor.renderingqueue");
renderContextQueue = new DispatchQueue("com.apple.aplcustomvideocompositor.rendercontextqueue");
//previousBuffer = null;
renderContextDidChange = false;
}
public override NSDictionary SourcePixelBufferAttributes ()
{
return new NSDictionary (CVPixelBuffer.PixelFormatTypeKey, CVPixelFormatType.CV420YpCbCr8BiPlanarVideoRange,
CVPixelBuffer.OpenGLESCompatibilityKey, true);
}
public OpenGLRenderer Render { get; set; }
public override NSDictionary RequiredPixelBufferAttributesForRenderContext ()
{
return new NSDictionary (CVPixelBuffer.PixelFormatTypeKey, CVPixelFormatType.CV420YpCbCr8BiPlanarVideoRange,
CVPixelBuffer.OpenGLESCompatibilityKey, true);
}
public override NSDictionary SourcePixelBufferAttributes()
{
return new NSDictionary(CVPixelBuffer.PixelFormatTypeKey, CVPixelFormatType.CV420YpCbCr8BiPlanarVideoRange,
CVPixelBuffer.OpenGLESCompatibilityKey, true);
}
public override void RenderContextChanged (AVVideoCompositionRenderContext newRenderContext)
{
renderContextQueue.DispatchSync (() => {
renderContext = newRenderContext;
renderContextDidChange = true;
});
}
public override NSDictionary RequiredPixelBufferAttributesForRenderContext()
{
return new NSDictionary(CVPixelBuffer.PixelFormatTypeKey, CVPixelFormatType.CV420YpCbCr8BiPlanarVideoRange,
CVPixelBuffer.OpenGLESCompatibilityKey, true);
}
public override void StartVideoCompositionRequest (AVAsynchronousVideoCompositionRequest asyncVideoCompositionRequest)
{
renderingQueue.DispatchAsync (() => {
if(shouldCancelAllRequests)
asyncVideoCompositionRequest.FinishCancelledRequest();
else
{
NSError error;
CVPixelBuffer resultPixels = newRenderedPixelBufferForRequest( asyncVideoCompositionRequest, out error);
if(resultPixels != null){
asyncVideoCompositionRequest.FinishWithComposedVideoFrame(resultPixels);
resultPixels.Dispose();
}
else{
asyncVideoCompositionRequest.FinishWithError(error);
}
public override void RenderContextChanged(AVVideoCompositionRenderContext newRenderContext)
{
renderContextQueue.DispatchSync(() =>
{
renderContext = newRenderContext;
renderContextDidChange = true;
});
}
}
});
}
public override void StartVideoCompositionRequest(AVAsynchronousVideoCompositionRequest request)
{
renderingQueue.DispatchAsync(() =>
{
// Check if all pending requests have been cancelled
if (shouldCancelAllRequests)
{
request.FinishCancelledRequest();
}
else
{
// Get the next rendererd pixel buffer
var resultPixels = NewRenderedPixelBufferForRequest(request, out NSError error);
if (resultPixels != null)
{
// The resulting pixelbuffer from OpenGL renderer is passed along to the request
request.FinishWithComposedVideoFrame(resultPixels);
resultPixels.Dispose();
resultPixels = null;
}
else
{
request.FinishWithError(error);
}
}
});
}
public override void CancelAllPendingVideoCompositionRequests ()
{
shouldCancelAllRequests = true;
renderingQueue.DispatchAsync (() => {
shouldCancelAllRequests = false;
});
}
public override void CancelAllPendingVideoCompositionRequests()
{
// pending requests will call finishCancelledRequest, those already rendering will call finishWithComposedVideoFrame
shouldCancelAllRequests = true;
//Utilities methods
renderingQueue.DispatchAsync(() =>
{
// start accepting requests again
shouldCancelAllRequests = false;
});
}
static double FactorForTimeInRange( CMTime time, CMTimeRange range)
{
CMTime elapsed = CMTime.Subtract (time, range.Start);
return elapsed.Seconds / range.Duration.Seconds;
}
#region Utilities methods
CVPixelBuffer newRenderedPixelBufferForRequest (AVAsynchronousVideoCompositionRequest request, out NSError error )
{
CVPixelBuffer dstPixels;
float tweenFactor =(float) FactorForTimeInRange (request.CompositionTime, request.VideoCompositionInstruction.TimeRange);
private static double FactorForTimeInRange(CMTime time, CMTimeRange range)
{
var elapsed = CMTime.Subtract(time, range.Start);
return elapsed.Seconds / range.Duration.Seconds;
}
var currentInstruction = (CustomVideoCompositionInstruction)request.VideoCompositionInstruction;
private CVPixelBuffer NewRenderedPixelBufferForRequest(AVAsynchronousVideoCompositionRequest request, out NSError error)
{
CVPixelBuffer dstPixels;
CVPixelBuffer foregroundSourceBuffer = request.SourceFrameByTrackID (currentInstruction.ForegroundTrackID);
CVPixelBuffer backgroundSourceBuffer = request.SourceFrameByTrackID (currentInstruction.BackgroundTrackID);
// tweenFactor indicates how far within that timeRange are we rendering this frame. This is normalized to vary between 0.0 and 1.0.
// 0.0 indicates the time at first frame in that videoComposition timeRange
// 1.0 indicates the time at last frame in that videoComposition timeRange
var tweenFactor = (float)FactorForTimeInRange(request.CompositionTime, request.VideoCompositionInstruction.TimeRange);
dstPixels = renderContext.CreatePixelBuffer ();
var currentInstruction = request.VideoCompositionInstruction as CustomVideoCompositionInstruction;
if (renderContextDidChange) {
var renderSize = renderContext.Size;
var destinationSize = new CGSize (dstPixels.Width, dstPixels.Height);
var renderContextTransform = new CGAffineTransform (renderSize.Width / 2, 0, 0, renderSize.Height / 2, renderSize.Width / 2, renderSize.Height / 2);
var destinationTransform = new CGAffineTransform (2 / destinationSize.Width, 0, 0, 2 / destinationSize.Height, -1, -1);
var normalizedRenderTransform = CGAffineTransform.Multiply( CGAffineTransform.Multiply(renderContextTransform, renderContext.RenderTransform), destinationTransform);
oglRender.RenderTransform = normalizedRenderTransform;
// Source pixel buffers are used as inputs while rendering the transition
var foregroundSourceBuffer = request.SourceFrameByTrackID(currentInstruction.ForegroundTrackId);
var backgroundSourceBuffer = request.SourceFrameByTrackID(currentInstruction.BackgroundTrackId);
renderContextDidChange = false;
}
// Destination pixel buffer into which we render the output
dstPixels = renderContext.CreatePixelBuffer();
oglRender.RenderPixelBuffer (dstPixels, foregroundSourceBuffer, backgroundSourceBuffer, tweenFactor);
// Recompute normalized render transform everytime the render context changes
if (renderContextDidChange)
{
// The renderTransform returned by the renderContext is in X: [0, w] and Y: [0, h] coordinate system
// But since in this sample we render using OpenGLES which has its coordinate system between [-1, 1] we compute a normalized transform
var renderSize = renderContext.Size;
var destinationSize = new CGSize(dstPixels.Width, dstPixels.Height);
var renderContextTransform = new CGAffineTransform(renderSize.Width / 2, 0, 0, renderSize.Height / 2, renderSize.Width / 2, renderSize.Height / 2);
var destinationTransform = new CGAffineTransform(2 / destinationSize.Width, 0, 0, 2 / destinationSize.Height, -1, -1);
var normalizedRenderTransform = CGAffineTransform.Multiply(CGAffineTransform.Multiply(renderContextTransform, renderContext.RenderTransform), destinationTransform);
Render.RenderTransform = normalizedRenderTransform;
error = null;
return dstPixels;
}
}
}
renderContextDidChange = false;
}
Render.RenderPixelBuffer(dstPixels, foregroundSourceBuffer, backgroundSourceBuffer, tweenFactor);
error = null;
return dstPixels;
}
}
#endregion
}

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>

Просмотреть файл

@ -1,42 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIMainStoryboardFile</key>
<string>MainStoryboard</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIStatusBarTintParameters</key>
<dict>
<key>UINavigationBar</key>
<dict>
<key>Style</key>
<string>UIBarStyleDefault</string>
<key>Translucent</key>
<false />
</dict>
</dict>
<key>CFBundleIconFiles</key>
<array>
<string>Icon</string>
<string>Icon@2x</string>
<string>Icon-72</string>
<string>Icon-72@2x</string>
<string>Icon-Small</string>
<string>Icon-Small@2x</string>
<string>Icon-Small-50</string>
</array>
<key>CFBundleDisplayName</key>
<key>CFBundleName</key>
<string>AVCustomEdit</string>
<key>CFBundleIdentifier</key>
<string>com.xamarin.AVCustomEdit</string>
@ -44,11 +10,30 @@
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>UISupportedInterfaceOrientations~ipad</key>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>9.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/AppIcon.appiconset</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Access to PhotoLibrary for export feature</string>
</dict>

Просмотреть файл

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Xamarin" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0EM-Jt-5LB">
<rect key="frame" x="116.5" y="319.5" width="142" height="48"/>
<fontDescription key="fontDescription" type="system" pointSize="40"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="0EM-Jt-5LB" firstAttribute="centerY" secondItem="LzO-nd-BUG" secondAttribute="centerY" id="TYB-Rs-GJa"/>
<constraint firstItem="0EM-Jt-5LB" firstAttribute="centerX" secondItem="LzO-nd-BUG" secondAttribute="centerX" id="qAU-C5-ays"/>
</constraints>
<viewLayoutGuide key="safeArea" id="LzO-nd-BUG"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

Просмотреть файл

@ -1,19 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using UIKit;
using UIKit;
namespace AVCustomEdit
{
public class Application
{
// This is the main entry point of the application.
static void Main (string[] args)
static void Main (string [] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main (args, null, "AppDelegate");
}
}
}
}

Просмотреть файл

@ -0,0 +1,202 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="landscape">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LD4-Le-jcl" customClass="PlayerView">
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outletCollection property="gestureRecognizers" destination="sLC-Cu-nWY" appends="YES" id="HWH-G8-9PM"/>
</connections>
</view>
<progressView hidden="YES" opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kEb-nT-KfT">
<rect key="frame" x="258.5" y="323" width="150" height="2"/>
<constraints>
<constraint firstAttribute="width" constant="150" id="boE-uP-EQB"/>
</constraints>
</progressView>
<toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" barStyle="black" translatesAutoresizingMaskIntoConstraints="NO" id="4sS-5v-XkA">
<rect key="frame" x="0.0" y="341" width="667" height="34"/>
<items>
<barButtonItem style="plain" systemItem="play" id="EYI-u1-A8G">
<connections>
<action selector="TogglePlayPause:" destination="BYZ-38-t0r" id="N3Z-8b-dQc"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" id="A6v-IJ-sMa">
<slider key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" id="fHe-9A-hM0">
<rect key="frame" x="37" y="0.0" width="204" height="34"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<connections>
<action selector="BeginScrubbing:" destination="BYZ-38-t0r" eventType="touchDown" id="eHY-jB-UQ4"/>
<action selector="EndScrubbing:" destination="BYZ-38-t0r" eventType="touchUpInside" id="AyU-3Z-Leu"/>
<action selector="EndScrubbing:" destination="BYZ-38-t0r" eventType="touchUpOutside" id="HVd-Gp-Qpg"/>
<action selector="EndScrubbing:" destination="BYZ-38-t0r" eventType="touchCancel" id="jEC-H0-ztW"/>
<action selector="Scrub:" destination="BYZ-38-t0r" eventType="valueChanged" id="RXh-oW-bvG"/>
</connections>
</slider>
</barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="Qbw-sK-BJN"/>
<barButtonItem title="Set Transition" id="6uz-rN-HPP">
<connections>
<segue destination="R9e-Pk-PpT" kind="presentation" identifier="Transition" id="1354"/>
</connections>
</barButtonItem>
<barButtonItem title="Export" id="xIp-Oh-YCB">
<connections>
<action selector="ExportToMovie:" destination="BYZ-38-t0r" id="ebu-5Y-QnB"/>
</connections>
</barButtonItem>
</items>
</toolbar>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ddd" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iyX-Gk-aIe">
<rect key="frame" x="256" y="342" width="48" height="21"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="49U-gc-cgh"/>
<constraint firstAttribute="width" constant="48" id="Xsh-ZO-Iie"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="LD4-Le-jcl" secondAttribute="trailing" id="JcL-ai-hsJ"/>
<constraint firstItem="iyX-Gk-aIe" firstAttribute="leading" secondItem="lKW-hZ-kwj" secondAttribute="leading" constant="256" id="KvA-GL-IGT"/>
<constraint firstItem="LD4-Le-jcl" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="LGn-eA-lFf"/>
<constraint firstItem="4sS-5v-XkA" firstAttribute="trailing" secondItem="8bC-Xf-vdC" secondAttribute="trailing" id="MJG-q2-xEK"/>
<constraint firstItem="4sS-5v-XkA" firstAttribute="centerX" secondItem="kEb-nT-KfT" secondAttribute="centerX" id="cRw-Hw-r9y"/>
<constraint firstItem="iyX-Gk-aIe" firstAttribute="bottom" secondItem="4sS-5v-XkA" secondAttribute="bottom" constant="-12" id="dbf-pq-r04"/>
<constraint firstAttribute="bottom" secondItem="LD4-Le-jcl" secondAttribute="bottom" id="hfk-51-is5"/>
<constraint firstAttribute="leading" secondItem="4sS-5v-XkA" secondAttribute="leading" symbolic="YES" id="iWh-sU-oDY"/>
<constraint firstItem="LD4-Le-jcl" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="isS-W9-DiJ"/>
<constraint firstItem="4sS-5v-XkA" firstAttribute="top" secondItem="kEb-nT-KfT" secondAttribute="bottom" constant="16" id="m2G-PQ-rNK"/>
<constraint firstAttribute="bottom" secondItem="4sS-5v-XkA" secondAttribute="bottom" id="pN1-vs-Azc"/>
</constraints>
<viewLayoutGuide key="safeArea" id="lKW-hZ-kwj"/>
</view>
<connections>
<outlet property="currentTimeLabel" destination="iyX-Gk-aIe" id="name-outlet-iyX-Gk-aIe"/>
<outlet property="exportButton" destination="xIp-Oh-YCB" id="name-outlet-xIp-Oh-YCB"/>
<outlet property="exportProgressView" destination="kEb-nT-KfT" id="name-outlet-kEb-nT-KfT"/>
<outlet property="playPauseButton" destination="EYI-u1-A8G" id="name-outlet-EYI-u1-A8G"/>
<outlet property="playerView" destination="LD4-Le-jcl" id="name-outlet-LD4-Le-jcl"/>
<outlet property="scrubber" destination="fHe-9A-hM0" id="name-outlet-fHe-9A-hM0"/>
<outlet property="toolbar" destination="4sS-5v-XkA" id="name-outlet-4sS-5v-XkA"/>
<outlet property="transitionButton" destination="6uz-rN-HPP" id="name-outlet-6uz-rN-HPP"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
<tapGestureRecognizer id="sLC-Cu-nWY">
<connections>
<action selector="HandleTapGesture:" destination="BYZ-38-t0r" id="407"/>
<outlet property="delegate" destination="BYZ-38-t0r" id="e8g-ul-YGd"/>
</connections>
</tapGestureRecognizer>
</objects>
<point key="canvasLocation" x="0.0" y="0.0"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="oF8-X1-4jb">
<objects>
<navigationController definesPresentationContext="YES" id="R9e-Pk-PpT" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="BNi-gR-eHR">
<rect key="frame" x="0.0" y="0.0" width="667" height="32"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="1IP-es-DBQ" kind="relationship" relationship="rootViewController" id="hMp-g1-JcV"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="kbS-mz-Eti" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="702" y="-574"/>
</scene>
<!--Set Transition-->
<scene sceneID="X1A-oB-eDW">
<objects>
<tableViewController id="1IP-es-DBQ" customClass="TransitionTypeController" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" estimatedRowHeight="-1" sectionHeaderHeight="10" sectionFooterHeight="10" id="FbG-9a-Ewx">
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<sections>
<tableViewSection headerTitle="Transition Type" id="1042">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" indentationLevel="1" indentationWidth="0.0" textLabel="nno-KP-PYO" style="IBUITableViewCellStyleDefault" id="1043">
<rect key="frame" x="0.0" y="55.5" width="667" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="1043" id="1044">
<rect key="frame" x="0.0" y="0.0" width="667" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Diagonal Wipe" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="nno-KP-PYO">
<rect key="frame" x="20" y="0.0" width="627" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" indentationLevel="1" indentationWidth="0.0" textLabel="7iK-G1-2ez" style="IBUITableViewCellStyleDefault" id="1045">
<rect key="frame" x="0.0" y="99.5" width="667" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="1045" id="1046">
<rect key="frame" x="0.0" y="0.0" width="667" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Cross Dissolve" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="7iK-G1-2ez">
<rect key="frame" x="20" y="0.0" width="627" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
<connections>
<outlet property="dataSource" destination="1IP-es-DBQ" id="5Zm-ji-Kq2"/>
<outlet property="delegate" destination="1IP-es-DBQ" id="Yt3-gX-f2e"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Set Transition" id="H2T-Lk-SG8">
<barButtonItem key="rightBarButtonItem" title="Done" style="done" id="2f7-fq-iCZ">
<connections>
<action selector="TransitionSelected:" destination="1IP-es-DBQ" id="772"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="crossDissolveCell" destination="1045" id="name-outlet-1045"/>
<outlet property="diagonalWipeCell" destination="1043" id="name-outlet-1043"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="aMV-Ds-sup" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="701" y="289"/>
</scene>
</scenes>
</document>

Просмотреть файл

@ -1,186 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="5053" systemVersion="13C64" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="64">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3733"/>
</dependencies>
<scenes>
<!--Player View Controller-->
<scene sceneID="63">
<objects>
<viewController id="64" customClass="PlayerViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="65">
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" barStyle="blackTranslucent" id="dMF-K1-Sws">
<rect key="frame" x="-3" y="276" width="570" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<items>
<barButtonItem systemItem="play" id="HOB-PP-3UB">
<connections>
<action selector="togglePlayPause:" destination="64" id="370"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" id="9Zj-cl-VbD">
<slider key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" id="oEO-gT-r2P">
<rect key="frame" x="42" y="5" width="168" height="34"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<connections>
<action selector="beginScrubbing:" destination="64" eventType="touchDown" id="365"/>
<action selector="endScrubbing:" destination="64" eventType="touchCancel" id="366"/>
<action selector="endScrubbing:" destination="64" eventType="touchUpInside" id="367"/>
<action selector="endScrubbing:" destination="64" eventType="touchUpOutside" id="368"/>
<action selector="scrub:" destination="64" eventType="valueChanged" id="369"/>
</connections>
</slider>
</barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="68"/>
<barButtonItem title="Transition" id="70">
<connections>
<segue destination="90" kind="modal" identifier="Transition" id="FXO-CA-qDp"/>
</connections>
</barButtonItem>
<barButtonItem title="Export" id="75">
<connections>
<action selector="exportToMovie:" destination="64" id="374"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" id="240"/>
</items>
</toolbar>
<view contentMode="scaleToFill" id="83" customClass="PlayerView">
<rect key="frame" x="-1" y="20" width="569" height="255"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<progressView hidden="YES" opaque="NO" contentMode="scaleToFill" progress="0.5" id="361">
<rect key="frame" x="166" y="247" width="150" height="2"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</progressView>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
</view>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="U69-c1-S53">
<rect key="frame" x="221" y="287" width="62" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
</view>
<extendedEdge key="edgesForExtendedLayout"/>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<connections>
<outlet property="currentTimeLabel" destination="U69-c1-S53" id="name-outlet-U69-c1-S53"/>
<outlet property="exportButton" destination="75" id="name-outlet-75"/>
<outlet property="exportProgressView" destination="361" id="name-outlet-361"/>
<outlet property="gestureRecognizer" destination="373" id="name-outlet-373"/>
<outlet property="playPauseButton" destination="HOB-PP-3UB" id="name-outlet-HOB-PP-3UB"/>
<outlet property="playerView" destination="83" id="s8j-Pv-pQ1"/>
<outlet property="scrubber" destination="oEO-gT-r2P" id="name-outlet-oEO-gT-r2P"/>
<outlet property="toolBar" destination="dMF-K1-Sws" id="i53-z0-8ml"/>
<outlet property="transitionButton" destination="70" id="name-outlet-70"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="66" userLabel="First Responder" sceneMemberID="firstResponder"/>
<tapGestureRecognizer id="373"/>
</objects>
<point key="canvasLocation" x="-914" y="-408"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="89">
<objects>
<navigationController definesPresentationContext="YES" id="90" sceneMemberID="viewController">
<extendedEdge key="edgesForExtendedLayout"/>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="93">
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="294" kind="relationship" relationship="rootViewController" id="310"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="94" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-560" y="160"/>
</scene>
<!--Transition Type Controller - Transition Type-->
<scene sceneID="293">
<objects>
<tableViewController id="294" customClass="TransitionTypeController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="295">
<rect key="frame" x="0.0" y="64" width="568" height="256"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<sections>
<tableViewSection headerTitle="Section-1" id="321">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" indentationWidth="10" textLabel="340" style="IBUITableViewCellStyleDefault" id="322">
<rect key="frame" x="0.0" y="22" width="568" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="322" id="Pnh-ey-78t">
<rect key="frame" x="0.0" y="0.0" width="568" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Diagonal Wipe" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="340">
<rect key="frame" x="15" y="0.0" width="538" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell tag="1" contentMode="scaleToFill" selectionStyle="blue" indentationWidth="10" textLabel="356" style="IBUITableViewCellStyleDefault" id="323">
<rect key="frame" x="0.0" y="66" width="568" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="323" id="A5s-Uj-1yJ">
<rect key="frame" x="0.0" y="0.0" width="568" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" tag="1" contentMode="left" text="Cross Dissolve" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="356">
<rect key="frame" x="15" y="0.0" width="538" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
<connections>
<outlet property="dataSource" destination="294" id="296"/>
<outlet property="delegate" destination="294" id="297"/>
</connections>
</tableView>
<extendedEdge key="edgesForExtendedLayout"/>
<navigationItem key="navigationItem" title="Transition Type" id="309">
<barButtonItem key="rightBarButtonItem" title="Done" style="done" id="378">
<connections>
<action selector="TransitionSelected:" destination="294" id="gBS-xF-lRK"/>
</connections>
</barButtonItem>
</navigationItem>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<connections>
<outlet property="crossDissolveCell" destination="323" id="name-outlet-323"/>
<outlet property="diagonalWipeCell" destination="322" id="name-outlet-322"/>
<outlet property="tableView" destination="295" id="name-outlet-295"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="299" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-87" y="-321"/>
</scene>
</scenes>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer>
</document>

Просмотреть файл

@ -1,204 +1,190 @@
using System;
using Foundation;
using OpenGLES;
using CoreGraphics;
using CoreVideo;
using OpenGLES;
using OpenTK.Graphics.ES20;
using System;
namespace AVCustomEdit
{
public class CrossDissolveRenderer : OpenGLRenderer
{
public CrossDissolveRenderer () : base()
{
}
public class CrossDissolveRenderer : OpenGLRenderer
{
public override void RenderPixelBuffer(CoreVideo.CVPixelBuffer destinationPixelBuffer, CoreVideo.CVPixelBuffer foregroundPixelBuffer, CoreVideo.CVPixelBuffer backgroundPixelBuffer, float tween)
{
EAGLContext.SetCurrentContext(CurrentContext);
if (foregroundPixelBuffer != null || backgroundPixelBuffer != null)
{
var foregroundLumaTexture = LumaTextureForPixelBuffer(foregroundPixelBuffer);
var foregroundChromaTexture = ChromaTextureForPixelBuffer(foregroundPixelBuffer);
public override void RenderPixelBuffer (CoreVideo.CVPixelBuffer destinationPixelBuffer, CoreVideo.CVPixelBuffer foregroundPixelBuffer, CoreVideo.CVPixelBuffer backgroundPixelBuffer, float tween)
{
EAGLContext.SetCurrentContext (CurrentContext);
if (foregroundPixelBuffer != null || backgroundPixelBuffer != null) {
CVOpenGLESTexture foregroundLumaTexture = LumaTextureForPixelBuffer (foregroundPixelBuffer);
CVOpenGLESTexture foregroundChromaTexture = ChromaTextureForPixelBuffer (foregroundPixelBuffer);
var backgroundLumaTexture = LumaTextureForPixelBuffer(backgroundPixelBuffer);
var backgroundChromaTexture = ChromaTextureForPixelBuffer(backgroundPixelBuffer);
CVOpenGLESTexture backgroundLumaTexture = LumaTextureForPixelBuffer (backgroundPixelBuffer);
CVOpenGLESTexture backgroundChromaTexture = ChromaTextureForPixelBuffer (backgroundPixelBuffer);
var destLumaTexture = LumaTextureForPixelBuffer(destinationPixelBuffer);
var destChromaTexture = ChromaTextureForPixelBuffer(destinationPixelBuffer);
CVOpenGLESTexture destLumaTexture = LumaTextureForPixelBuffer (destinationPixelBuffer);
CVOpenGLESTexture destChromaTexture = ChromaTextureForPixelBuffer (destinationPixelBuffer);
GL.UseProgram(ProgramY);
GL.UseProgram (ProgramY);
// Set the render transform
float[] preferredRenderTransform =
{
(float)RenderTransform.xx, (float)RenderTransform.xy, (float)RenderTransform.x0, 0.0f,
(float)RenderTransform.yx, (float)RenderTransform.yy, (float)RenderTransform.y0, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
// Set the render transform
float[] preferredRenderTransform = {
(float)RenderTransform.xx, (float)RenderTransform.xy, (float)RenderTransform.x0, 0.0f,
(float)RenderTransform.yx, (float)RenderTransform.yy,(float)RenderTransform.y0, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
GL.UniformMatrix4(Uniforms[(int)Uniform.Render_Transform_Y], 1, false, preferredRenderTransform);
GL.UniformMatrix4 (Uniforms [(int)Uniform.Render_Transform_Y], 1, false, preferredRenderTransform);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, OffscreenBufferHandle);
GL.Viewport(0, 0, (int)destinationPixelBuffer.GetWidthOfPlane(0), (int)destinationPixelBuffer.GetHeightOfPlane(0));
GL.BindFramebuffer (FramebufferTarget.Framebuffer, OffscreenBufferHandle);
GL.Viewport (0, 0, (int)destinationPixelBuffer.Width, (int)destinationPixelBuffer.Height);
// Y planes of foreground and background frame are used to render the Y plane of the destination frame
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(foregroundLumaTexture.Target, foregroundLumaTexture.Name);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
GL.ActiveTexture (TextureUnit.Texture0);
GL.BindTexture (foregroundLumaTexture.Target, foregroundLumaTexture.Name);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
GL.ActiveTexture(TextureUnit.Texture1);
GL.BindTexture(backgroundLumaTexture.Target, backgroundLumaTexture.Name);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
GL.ActiveTexture (TextureUnit.Texture1);
GL.BindTexture (backgroundLumaTexture.Target, backgroundLumaTexture.Name);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
// Attach the destination texture as a color attachment to the off screen frame buffer
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, destLumaTexture.Target, destLumaTexture.Name, 0);
// Attach the destination texture as a color attachment to the off screen frame buffer
GL.FramebufferTexture2D (FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, destLumaTexture.Target, destLumaTexture.Name, 0);
if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete)
{
Console.Error.WriteLine($"Failed to make complete framebuffer object {GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer)}");
goto bail;
}
if (GL.CheckFramebufferStatus (FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete) {
Console.Error.WriteLine ("Failed to make complete framebuffer object " + GL.CheckFramebufferStatus (FramebufferTarget.Framebuffer));
foregroundLumaTexture.Dispose ();
foregroundChromaTexture.Dispose ();
backgroundLumaTexture.Dispose ();
backgroundChromaTexture.Dispose ();
destLumaTexture.Dispose ();
destChromaTexture.Dispose ();
VideoTextureCache.Flush (0);
EAGLContext.SetCurrentContext (null);
return;
}
GL.ClearColor(0f, 0f, 0f, 1f);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.ClearColor (0.0f, 0.0f, 0.0f, 1.0f);
GL.Clear (ClearBufferMask.ColorBufferBit);
float[] quadVertexData1 =
{
-1.0f, 1.0f,
1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, -1.0f,
};
float[] quadVertexData1 = {
-1.0f, 1.0f,
1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, -1.0f,
};
// texture data varies from 0 -> 1, whereas vertex data varies from -1 -> 1
float[] quadTextureData1 = {
0.5f + quadVertexData1 [0] / 2, 0.5f + quadVertexData1 [1] / 2,
0.5f + quadVertexData1 [2] / 2, 0.5f + quadVertexData1 [3] / 2,
0.5f + quadVertexData1 [4] / 2, 0.5f + quadVertexData1 [5] / 2,
0.5f + quadVertexData1 [6] / 2, 0.5f + quadVertexData1 [7] / 2,
};
// texture data varies from 0 -> 1, whereas vertex data varies from -1 -> 1
float[] quadTextureData1 =
{
0.5f + quadVertexData1[0] / 2, 0.5f + quadVertexData1[1] / 2,
0.5f + quadVertexData1[2] / 2, 0.5f + quadVertexData1[3] / 2,
0.5f + quadVertexData1[4] / 2, 0.5f + quadVertexData1[5] / 2,
0.5f + quadVertexData1[6] / 2, 0.5f + quadVertexData1[7] / 2,
};
GL.Uniform1 (Uniforms [(int)Uniform.Y], 0);
GL.Uniform1(Uniforms[(int)Uniform.Y], 0);
GL.VertexAttribPointer ((int)Attrib.Vertex_Y, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray ((int)Attrib.Vertex_Y);
GL.VertexAttribPointer((int)Attrib.Vertex_Y, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray((int)Attrib.Vertex_Y);
GL.VertexAttribPointer ((int)Attrib.TexCoord_Y, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray ((int)Attrib.TexCoord_Y);
GL.VertexAttribPointer((int)Attrib.TexCoord_Y, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray((int)Attrib.TexCoord_Y);
// Blend function to draw the foreground frame
GL.Enable (EnableCap.Blend);
GL.BlendFunc (BlendingFactorSrc.One, BlendingFactorDest.Zero);
// Blend function to draw the foreground frame
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.Zero);
// Draw the foreground frame
GL.DrawArrays (BeginMode.TriangleStrip, 0, 4);
// Draw the foreground frame
GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);
GL.Uniform1 (Uniforms [(int)Uniform.Y], 1);
GL.Uniform1(Uniforms[(int)Uniform.Y], 1);
GL.VertexAttribPointer ((int)Attrib.Vertex_Y, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray ((int)Attrib.Vertex_Y);
GL.VertexAttribPointer((int)Attrib.Vertex_Y, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray((int)Attrib.Vertex_Y);
GL.VertexAttribPointer ((int)Attrib.TexCoord_Y, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray ((int)Attrib.TexCoord_Y);
GL.VertexAttribPointer((int)Attrib.TexCoord_Y, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray((int)Attrib.TexCoord_Y);
// Blend function to draw the background frame
GL.BlendColor (0, 0, 0, tween);
GL.BlendFunc (BlendingFactorSrc.ConstantAlpha, BlendingFactorDest.OneMinusConstantAlpha);
// Blend function to draw the background frame
GL.BlendColor(0, 0, 0, tween);
GL.BlendFunc(BlendingFactorSrc.ConstantAlpha, BlendingFactorDest.OneMinusConstantAlpha);
// Draw the background frame
GL.DrawArrays (BeginMode.TriangleStrip, 0, 4);
// Draw the background frame
GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);
// Perform similar operations as above for the UV plane
GL.UseProgram (ProgramUV);
// Perform similar operations as above for the UV plane
GL.UseProgram(ProgramUV);
GL.UniformMatrix4 (Uniforms [(int)Uniform.Render_Transform_UV], 1, false, preferredRenderTransform);
GL.UniformMatrix4(Uniforms[(int)Uniform.Render_Transform_UV], 1, false, preferredRenderTransform);
GL.ActiveTexture (TextureUnit.Texture2);
GL.BindTexture (foregroundChromaTexture.Target, foregroundChromaTexture.Name);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
// UV planes of foreground and background frame are used to render the UV plane of the destination frame
GL.ActiveTexture(TextureUnit.Texture2);
GL.BindTexture(foregroundChromaTexture.Target, foregroundChromaTexture.Name);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
GL.ActiveTexture (TextureUnit.Texture3);
GL.BindTexture (backgroundChromaTexture.Target, backgroundChromaTexture.Name);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
GL.ActiveTexture(TextureUnit.Texture3);
GL.BindTexture(backgroundChromaTexture.Target, backgroundChromaTexture.Name);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
GL.Viewport (0, 0, (int)destinationPixelBuffer.Width, (int)destinationPixelBuffer.Height);
GL.Viewport(0, 0, (int)destinationPixelBuffer.GetWidthOfPlane(1), (int)destinationPixelBuffer.GetHeightOfPlane(1));
// Attach the destination texture as a color attachment to the off screen frame buffer
GL.FramebufferTexture2D (FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, destChromaTexture.Target, destChromaTexture.Name, 0);
// Attach the destination texture as a color attachment to the off screen frame buffer
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, destChromaTexture.Target, destChromaTexture.Name, 0);
if (GL.CheckFramebufferStatus (FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete) {
Console.Error.WriteLine ("Failed to make complete framebuffer object " + GL.CheckFramebufferStatus (FramebufferTarget.Framebuffer));
foregroundLumaTexture.Dispose ();
foregroundChromaTexture.Dispose ();
backgroundLumaTexture.Dispose ();
backgroundChromaTexture.Dispose ();
destLumaTexture.Dispose ();
destChromaTexture.Dispose ();
this.VideoTextureCache.Flush (0);
EAGLContext.SetCurrentContext (null);
return;
}
if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete)
{
Console.Error.WriteLine($"Failed to make complete framebuffer object {GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer)}");
goto bail;
}
GL.ClearColor (0.0f, 0.0f, 0.0f, 1.0f);
GL.Clear (ClearBufferMask.ColorBufferBit);
GL.ClearColor(0f, 0f, 0f, 1f);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.Uniform1 (Uniforms [(int)Uniform.UV], 2);
GL.Uniform1(Uniforms[(int)Uniform.UV], 2);
GL.VertexAttribPointer ((int)Attrib.Vertex_UV, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray ((int)Attrib.Vertex_UV);
GL.VertexAttribPointer((int)Attrib.Vertex_UV, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray((int)Attrib.Vertex_UV);
GL.VertexAttribPointer ((int)Attrib.TexCoord_UV, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray ((int)Attrib.TexCoord_UV);
GL.VertexAttribPointer((int)Attrib.TexCoord_UV, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray((int)Attrib.TexCoord_UV);
// Blend function to draw the foreground frame
GL.BlendFunc (BlendingFactorSrc.One, BlendingFactorDest.Zero);
GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.Zero);
// Draw the foreground frame
GL.DrawArrays (BeginMode.TriangleStrip, 0, 4);
// Draw the foreground frame
GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);
GL.Uniform1 (Uniforms [(int)Uniform.UV], 3);
GL.Uniform1(Uniforms[(int)Uniform.UV], 3);
GL.VertexAttribPointer ((int)Attrib.Vertex_UV, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray ((int)Attrib.Vertex_UV);
GL.VertexAttribPointer((int)Attrib.Vertex_UV, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray((int)Attrib.Vertex_UV);
GL.VertexAttribPointer ((int)Attrib.TexCoord_UV, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray ((int)Attrib.TexCoord_UV);
GL.VertexAttribPointer((int)Attrib.TexCoord_UV, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray((int)Attrib.TexCoord_UV);
// Blend function to draw the background frame
GL.BlendColor (0, 0, 0, tween);
GL.BlendFunc (BlendingFactorSrc.ConstantAlpha, BlendingFactorDest.OneMinusConstantAlpha);
GL.BlendColor(0, 0, 0, tween);
GL.BlendFunc(BlendingFactorSrc.ConstantAlpha, BlendingFactorDest.OneMinusConstantAlpha);
// Draw the background frame
GL.DrawArrays (BeginMode.TriangleStrip, 0, 4);
// Draw the background frame
GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);
GL.Flush ();
GL.Flush();
foregroundLumaTexture.Dispose ();
foregroundChromaTexture.Dispose ();
backgroundLumaTexture.Dispose ();
backgroundChromaTexture.Dispose ();
destLumaTexture.Dispose ();
destChromaTexture.Dispose ();
this.VideoTextureCache.Flush (0);
EAGLContext.SetCurrentContext (null);
}
}
}
}
bail:
foregroundLumaTexture.Dispose();
foregroundChromaTexture.Dispose();
backgroundLumaTexture.Dispose();
backgroundChromaTexture.Dispose();
destLumaTexture.Dispose();
destChromaTexture.Dispose();
_videoTextureCache.Flush(0);
EAGLContext.SetCurrentContext(null);
}
}
}
}

Просмотреть файл

@ -1,274 +1,279 @@
using System;
using CoreGraphics;
using OpenGLES;
using OpenTK.Graphics.ES20;
using System;
namespace AVCustomEdit
{
public class DiagonalWipeRenderer : OpenGLRenderer
{
const int ForegroundTrack = 0;
const int BackgroundTrack = 1;
public class DiagonalWipeRenderer : OpenGLRenderer
{
private const int ForegroundTrack = 0;
private const int BackgroundTrack = 1;
CGPoint diagonalEnd1;
CGPoint diagonalEnd2;
private CGPoint diagonalEnd1;
private CGPoint diagonalEnd2;
void quadVertexCoordinates (ref float[] vertexCoordinates, int trackID, float tween)
{
/*
diagonalEnd1 and diagonalEnd2 represent the endpoints of a line which partitions the frame on screen into the two parts.
private void QuadVertexCoordinates(ref float[] vertexCoordinates, int trackId, float tween)
{
/*
diagonalEnd1 and diagonalEnd2 represent the endpoints of a line which partitions the frame on screen into the two parts.
diagonalEnd1
------------X-----------
| |
| X diagonalEnd2
| |
| |
------------------------
diagonalEnd1
------------X-----------
| |
| X diagonalEnd2
| |
| |
------------------------
The below conditionals, use the tween factor as a measure to determine the size of the foreground and background quads.
The below conditionals, use the tween factor as a measure to determine the size of the foreground and background quads.
*/
*/
if (tween <= 0.5f) { // The expectation here is that in half the timeRange of the transition we reach the diagonal of the frame
diagonalEnd1 = new CGPoint (1f - tween * 4f, -1f);
diagonalEnd2 = new CGPoint (1f, -1f + tween * 4f);
if (tween <= 0.5f)
{
// The expectation here is that in half the timeRange of the transition we reach the diagonal of the frame
diagonalEnd1 = new CGPoint(1f - tween * 4f, -1f);
diagonalEnd2 = new CGPoint(1f, -1f + tween * 4f);
vertexCoordinates [6] = (float)diagonalEnd2.X;
vertexCoordinates [7] = (float)diagonalEnd2.Y;
vertexCoordinates [8] = (float)diagonalEnd1.X;
vertexCoordinates [9] = (float)diagonalEnd1.Y;
} else if (tween > 0.5f && tween < 1f) {
if (trackID == ForegroundTrack) {
diagonalEnd1 = new CGPoint (-1f, -1 + (tween - 0.5f) * 4f);
diagonalEnd2 = new CGPoint (1f - (tween - 0.5f) * 4f, 1f);
vertexCoordinates[6] = (float)diagonalEnd2.X;
vertexCoordinates[7] = (float)diagonalEnd2.Y;
vertexCoordinates[8] = (float)diagonalEnd1.X;
vertexCoordinates[9] = (float)diagonalEnd1.Y;
}
else if (tween > 0.5f && tween < 1f)
{
if (trackId == ForegroundTrack)
{
diagonalEnd1 = new CGPoint(-1f, -1 + (tween - 0.5f) * 4f);
diagonalEnd2 = new CGPoint(1f - (tween - 0.5f) * 4f, 1f);
vertexCoordinates [2] = (float)diagonalEnd2.X;
vertexCoordinates [3] = (float)diagonalEnd2.Y;
vertexCoordinates [4] = (float)diagonalEnd1.X;
vertexCoordinates [5] = (float)diagonalEnd1.Y;
vertexCoordinates [6] = (float)diagonalEnd1.X;
vertexCoordinates [7] = (float)diagonalEnd1.Y;
vertexCoordinates [8] = (float)diagonalEnd1.X;
vertexCoordinates [9] = (float)diagonalEnd1.Y;
} else if (trackID == BackgroundTrack) {
vertexCoordinates [4] = 1f;
vertexCoordinates [5] = 1f;
vertexCoordinates [6] = -1f;
vertexCoordinates [7] = -1f;
}
} else if (tween >= 1f) {
diagonalEnd1 = new CGPoint (1f, -1f);
diagonalEnd2 = new CGPoint (1f, -1f);
}
}
vertexCoordinates[2] = (float)diagonalEnd2.X;
vertexCoordinates[3] = (float)diagonalEnd2.Y;
vertexCoordinates[4] = (float)diagonalEnd1.X;
vertexCoordinates[5] = (float)diagonalEnd1.Y;
vertexCoordinates[6] = (float)diagonalEnd1.X;
vertexCoordinates[7] = (float)diagonalEnd1.Y;
vertexCoordinates[8] = (float)diagonalEnd1.X;
vertexCoordinates[9] = (float)diagonalEnd1.Y;
}
else if (trackId == BackgroundTrack)
{
vertexCoordinates[4] = 1f;
vertexCoordinates[5] = 1f;
vertexCoordinates[6] = -1f;
vertexCoordinates[7] = -1f;
}
}
else if (tween >= 1f)
{
diagonalEnd1 = new CGPoint(1f, -1f);
diagonalEnd2 = new CGPoint(1f, -1f);
}
}
public override void RenderPixelBuffer (CoreVideo.CVPixelBuffer destinationPixelBuffer, CoreVideo.CVPixelBuffer foregroundPixelBuffer, CoreVideo.CVPixelBuffer backgroundPixelBuffer, float tween)
{
EAGLContext.SetCurrentContext (CurrentContext);
public override void RenderPixelBuffer(CoreVideo.CVPixelBuffer destinationPixelBuffer, CoreVideo.CVPixelBuffer foregroundPixelBuffer, CoreVideo.CVPixelBuffer backgroundPixelBuffer, float tween)
{
EAGLContext.SetCurrentContext(CurrentContext);
if (foregroundPixelBuffer == null && backgroundPixelBuffer == null)
return;
if (foregroundPixelBuffer != null || backgroundPixelBuffer != null)
{
var foregroundLumaTexture = LumaTextureForPixelBuffer(foregroundPixelBuffer);
var foregroundChromaTexture = ChromaTextureForPixelBuffer(foregroundPixelBuffer);
var foregroundLumaTexture = LumaTextureForPixelBuffer (foregroundPixelBuffer);
var foregroundChromaTexture = ChromaTextureForPixelBuffer (foregroundPixelBuffer);
var backgroundLumaTexture = LumaTextureForPixelBuffer(backgroundPixelBuffer);
var backgroundChromaTexture = ChromaTextureForPixelBuffer(backgroundPixelBuffer);
var backgroundLumaTexture = LumaTextureForPixelBuffer (backgroundPixelBuffer);
var backgroundChromaTexture = ChromaTextureForPixelBuffer (backgroundPixelBuffer);
var destLumaTexture = LumaTextureForPixelBuffer(destinationPixelBuffer);
var destChromaTexture = ChromaTextureForPixelBuffer(destinationPixelBuffer);
var destLumaTexture = LumaTextureForPixelBuffer (destinationPixelBuffer);
var destChromaTexture = ChromaTextureForPixelBuffer (destinationPixelBuffer);
GL.UseProgram(ProgramY);
GL.UseProgram (ProgramY);
// Set the render transformq
float[] preferredRenderTransform =
{
(float)RenderTransform.xx, (float) RenderTransform.xy, (float)RenderTransform.x0, 0.0f,
(float)RenderTransform.yx, (float) RenderTransform.yy, (float)RenderTransform.y0, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
// Set the render transformq
float[] preferredRenderTransform = {
(float)RenderTransform.xx,(float) RenderTransform.xy, (float)RenderTransform.x0, 0.0f,
(float)RenderTransform.yx, (float)RenderTransform.yy, (float)RenderTransform.y0, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
GL.UniformMatrix4(Uniforms[(int)Uniform.Y], 1, false, preferredRenderTransform);
GL.UniformMatrix4 (Uniforms [(int)Uniform.Y], 1, false, preferredRenderTransform);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, (int)OffscreenBufferHandle);
GL.BindFramebuffer (FramebufferTarget.Framebuffer, (int)OffscreenBufferHandle);
GL.Viewport(0, 0, (int)destinationPixelBuffer.GetWidthOfPlane(0), (int)destinationPixelBuffer.GetHeightOfPlane(0));
GL.Viewport (0, 0, (int)destinationPixelBuffer.GetWidthOfPlane (0), (int)destinationPixelBuffer.GetHeightOfPlane (0));
// Y planes of foreground and background frame are used to render the Y plane of the destination frame
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(foregroundLumaTexture.Target, foregroundLumaTexture.Name);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
// Y planes of foreground and background frame are used to render the Y plane of the destination frame
GL.ActiveTexture (TextureUnit.Texture0);
GL.BindTexture (foregroundLumaTexture.Target, foregroundLumaTexture.Name);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
GL.ActiveTexture(TextureUnit.Texture1);
GL.BindTexture(backgroundLumaTexture.Target, backgroundLumaTexture.Name);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
GL.ActiveTexture (TextureUnit.Texture1);
GL.BindTexture (backgroundLumaTexture.Target, backgroundLumaTexture.Name);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
// Attach the destination texture as a color attachment to the off screen frame buffer
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer,
FramebufferSlot.ColorAttachment0,
destLumaTexture.Target,
destLumaTexture.Name,
0);
GL.FramebufferTexture2D (FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0,
destLumaTexture.Target, destLumaTexture.Name, 0);
if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete)
{
Console.WriteLine("Failed to make complete frmaebuffer object: {0}", GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer));
goto bail;
}
if (GL.CheckFramebufferStatus (FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete) {
Console.WriteLine ("Failed to make complete frmaebuffer object: {0}", GL.CheckFramebufferStatus (FramebufferTarget.Framebuffer));
GL.ClearColor(0f, 0f, 0f, 1f);
GL.Clear(ClearBufferMask.ColorBufferBit);
foregroundLumaTexture.Dispose ();
foregroundChromaTexture.Dispose ();
backgroundLumaTexture.Dispose ();
backgroundChromaTexture.Dispose ();
destLumaTexture.Dispose ();
destChromaTexture.Dispose ();
float[] quadVertexData1 =
{
-1.0f, 1.0f,
1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, -1.0f,
1.0f, -1.0f,
};
// Periodic texture cache flush every frame
VideoTextureCache.Flush (CoreVideo.CVOptionFlags.None);
// Compute the vertex data for the foreground frame at this instructionLerp
QuadVertexCoordinates(ref quadVertexData1, ForegroundTrack, tween);
EAGLContext.SetCurrentContext (null);
}
// texture data varies from 0 -> 1, whereas vertex data varies from -1 -> 1
float[] quadTextureData1 =
{
0.5f + quadVertexData1[0] / 2f, 0.5f + quadVertexData1[1] / 2f,
0.5f + quadVertexData1[2] / 2f, 0.5f + quadVertexData1[3] / 2f,
0.5f + quadVertexData1[4] / 2f, 0.5f + quadVertexData1[5] / 2f,
0.5f + quadVertexData1[6] / 2f, 0.5f + quadVertexData1[7] / 2f,
0.5f + quadVertexData1[8] / 2f, 0.5f + quadVertexData1[9] / 2f,
};
GL.ClearColor (0f, 0f, 0f, 1f);
GL.Clear (ClearBufferMask.ColorBufferBit);
GL.Uniform1(Uniforms[(int)Uniform.Y], 0f);
float[] quadVertexData1 = {
-1.0f, 1.0f,
1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, -1.0f,
1.0f, -1.0f,
};
// Compute the vertex data for the foreground frame at this instructionLerp
quadVertexCoordinates (ref quadVertexData1, ForegroundTrack, tween);
GL.VertexAttribPointer<float>((int)Attrib.Vertex_Y, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray((int)Attrib.Vertex_Y);
// texture data varies from 0 -> 1, whereas vertex data varies from -1 -> 1
float[] quadTextureData1 = {
0.5f + quadVertexData1[0] / 2f, 0.5f + quadVertexData1[1] / 2f,
0.5f + quadVertexData1[2] / 2f, 0.5f + quadVertexData1[3] / 2f,
0.5f + quadVertexData1[4] / 2f, 0.5f + quadVertexData1[5] / 2f,
0.5f + quadVertexData1[6] / 2f, 0.5f + quadVertexData1[7] / 2f,
0.5f + quadVertexData1[8] / 2f, 0.5f + quadVertexData1[9] / 2f,
};
GL.VertexAttribPointer<float>((int)Attrib.TexCoord_Y, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray((int)Attrib.TexCoord_Y);
GL.Uniform1 (Uniforms [(int)Uniform.Y], 0f);
// Draw the foreground frame
GL.DrawArrays(BeginMode.TriangleStrip, 0, 5);
GL.VertexAttribPointer<float> ((int)Attrib.Vertex_Y, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray ((int)Attrib.Vertex_Y);
float[] quadVertexData2 =
{
(float)diagonalEnd2.X, (float)diagonalEnd2.Y,
(float)diagonalEnd1.X, (float)diagonalEnd1.Y,
1.0f, -1.0f,
1.0f, -1.0f,
1.0f, -1.0f,
};
GL.VertexAttribPointer<float> ((int)Attrib.TexCoord_Y, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray ((int)Attrib.TexCoord_Y);
// Compute the vertex data for the background frame at this instructionLerp
QuadVertexCoordinates(ref quadVertexData2, BackgroundTrack, tween);
GL.DrawArrays (BeginMode.TriangleStrip, 0, 5);
float[] quadTextureData2 =
{
0.5f + quadVertexData2[0] / 2f, 0.5f + quadVertexData2[1] / 2f,
0.5f + quadVertexData2[2] / 2f, 0.5f + quadVertexData2[3] / 2f,
0.5f + quadVertexData2[4] / 2f, 0.5f + quadVertexData2[5] / 2f,
0.5f + quadVertexData2[6] / 2f, 0.5f + quadVertexData2[7] / 2f,
0.5f + quadVertexData2[8] / 2f, 0.5f + quadVertexData2[9] / 2f,
};
float[] quadVertexData2 = {
(float)diagonalEnd2.X, (float)diagonalEnd2.Y,
(float)diagonalEnd1.X, (float)diagonalEnd1.Y,
1.0f, -1.0f,
1.0f, -1.0f,
1.0f, -1.0f,
};
GL.Uniform1(Uniforms[(int)Uniform.Y], 1);
quadVertexCoordinates (ref quadVertexData2, BackgroundTrack, tween);
GL.VertexAttribPointer<float>((int)Attrib.Vertex_Y, 2, VertexAttribPointerType.Float, false, 0, quadVertexData2);
GL.EnableVertexAttribArray((int)Attrib.Vertex_Y);
float[] quadTextureData2 = {
0.5f + quadVertexData2[0] / 2f, 0.5f + quadVertexData2[1] / 2f,
0.5f + quadVertexData2[2] / 2f, 0.5f + quadVertexData2[3] / 2f,
0.5f + quadVertexData2[4] / 2f, 0.5f + quadVertexData2[5] / 2f,
0.5f + quadVertexData2[6] / 2f, 0.5f + quadVertexData2[7] / 2f,
0.5f + quadVertexData2[8] / 2f, 0.5f + quadVertexData2[9] / 2f,
};
GL.VertexAttribPointer<float>((int)Attrib.TexCoord_Y, 2, VertexAttribPointerType.Float, false, 0, quadTextureData2);
GL.EnableVertexAttribArray((int)Attrib.TexCoord_Y);
GL.Uniform1 (Uniforms [(int)Uniform.Y], 1);
// Draw the background frame
GL.DrawArrays(BeginMode.TriangleStrip, 0, 5);
GL.VertexAttribPointer<float> ((int)Attrib.Vertex_Y, 2, VertexAttribPointerType.Float, false, 0, quadVertexData2);
GL.EnableVertexAttribArray ((int)Attrib.Vertex_Y);
// Perform similar operations as above for the UV plane
GL.UseProgram(ProgramUV);
GL.VertexAttribPointer<float> ((int)Attrib.TexCoord_Y, 2, VertexAttribPointerType.Float, false, 0, quadTextureData2);
GL.EnableVertexAttribArray ((int)Attrib.TexCoord_Y);
GL.UniformMatrix4(Uniforms[(int)Uniform.Render_Transform_UV], 1, false, preferredRenderTransform);
// Draw the background frame
GL.DrawArrays (BeginMode.TriangleStrip, 0, 5);
// UV planes of foreground and background frame are used to render the UV plane of the destination frame
GL.ActiveTexture(TextureUnit.Texture2);
GL.BindTexture(foregroundChromaTexture.Target, foregroundChromaTexture.Name);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
// Perform similar operations as above for the UV plane
GL.UseProgram (ProgramUV);
GL.ActiveTexture(TextureUnit.Texture3);
GL.BindTexture(backgroundChromaTexture.Target, backgroundChromaTexture.Name);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
GL.UniformMatrix4 (Uniforms [(int)Uniform.Render_Transform_UV], 1, false, preferredRenderTransform);
GL.Viewport(0, 0, (int)destinationPixelBuffer.GetWidthOfPlane(1), (int)destinationPixelBuffer.GetHeightOfPlane(1));
// UV planes of foreground and background frame are used to render the UV plane of the destination frame
GL.ActiveTexture (TextureUnit.Texture2);
GL.BindTexture (foregroundChromaTexture.Target, foregroundChromaTexture.Name);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
// Attach the destination texture as a color attachment to the off screen frame buffer
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer,
FramebufferSlot.ColorAttachment0,
destChromaTexture.Target,
destChromaTexture.Name,
0);
GL.ActiveTexture (TextureUnit.Texture3);
GL.BindTexture (backgroundChromaTexture.Target, backgroundChromaTexture.Name);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete)
{
Console.WriteLine("Failed to make complete framebuffer object: {0}", GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer));
goto bail;
}
GL.Viewport (0, 0,(int) destinationPixelBuffer.GetWidthOfPlane (1), (int)destinationPixelBuffer.GetHeightOfPlane (1));
GL.ClearColor(0f, 0f, 0f, 1f);
GL.Clear(ClearBufferMask.ColorBufferBit);
// Attach the destination texture as a color attachment to the off screen frame buffer
GL.FramebufferTexture2D (FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, destChromaTexture.Target,
destChromaTexture.Name, 0);
GL.Uniform1(Uniforms[(int)Uniform.UV], 2);
if (GL.CheckFramebufferStatus (FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete) {
Console.WriteLine ("Failed to make complete framebuffer object: {0}",
GL.CheckFramebufferStatus (FramebufferTarget.Framebuffer));
GL.VertexAttribPointer<float>((int)Attrib.Vertex_UV, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray((int)Attrib.Vertex_UV);
foregroundLumaTexture.Dispose ();
foregroundChromaTexture.Dispose ();
backgroundLumaTexture.Dispose ();
backgroundChromaTexture.Dispose ();
destLumaTexture.Dispose ();
destChromaTexture.Dispose ();
GL.VertexAttribPointer<float>((int)Attrib.TexCoord_UV, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray((int)Attrib.TexCoord_UV);
// Periodic texture cache flush every frame
VideoTextureCache.Flush (CoreVideo.CVOptionFlags.None);
// Draw the foreground frame
GL.DrawArrays(BeginMode.TriangleStrip, 0, 5);
EAGLContext.SetCurrentContext (null);
}
GL.Uniform1(Uniforms[(int)Uniform.UV], 3);
GL.ClearColor (0f, 0f, 0f, 1f);
GL.Clear (ClearBufferMask.ColorBufferBit);
GL.VertexAttribPointer<float>((int)Attrib.Vertex_UV, 2, VertexAttribPointerType.Float, false, 0, quadVertexData2);
GL.EnableVertexAttribArray((int)Attrib.Vertex_UV);
GL.Uniform1 (Uniforms [(int)Uniform.UV], 2);
GL.VertexAttribPointer<float>((int)Attrib.TexCoord_UV, 2, VertexAttribPointerType.Float, false, 0, quadTextureData2);
GL.EnableVertexAttribArray((int)Attrib.TexCoord_UV);
GL.VertexAttribPointer<float> ((int)Attrib.Vertex_UV, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
GL.EnableVertexAttribArray ((int)Attrib.Vertex_UV);
// Draw the background frame
GL.DrawArrays(BeginMode.TriangleStrip, 0, 5);
GL.VertexAttribPointer<float> ((int)Attrib.TexCoord_UV, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
GL.EnableVertexAttribArray ((int)Attrib.TexCoord_UV);
GL.Flush();
GL.DrawArrays (BeginMode.TriangleStrip, 0, 5);
bail:
foregroundLumaTexture.Dispose();
foregroundChromaTexture.Dispose();
backgroundLumaTexture.Dispose();
backgroundChromaTexture.Dispose();
destLumaTexture.Dispose();
destChromaTexture.Dispose();
GL.Uniform1 (Uniforms [(int)Uniform.UV], 3);
GL.VertexAttribPointer<float> ((int)Attrib.Vertex_UV, 2, VertexAttribPointerType.Float, false, 0, quadVertexData2);
GL.EnableVertexAttribArray ((int)Attrib.Vertex_UV);
GL.VertexAttribPointer<float> ((int)Attrib.TexCoord_UV, 2, VertexAttribPointerType.Float, false, 0, quadTextureData2);
GL.EnableVertexAttribArray ((int)Attrib.TexCoord_UV);
GL.DrawArrays (BeginMode.TriangleStrip, 0, 5);
GL.Flush ();
foregroundLumaTexture.Dispose ();
foregroundChromaTexture.Dispose ();
backgroundLumaTexture.Dispose ();
backgroundChromaTexture.Dispose ();
destLumaTexture.Dispose ();
destChromaTexture.Dispose ();
// Periodic texture cache flush every frame
VideoTextureCache.Flush (CoreVideo.CVOptionFlags.None);
EAGLContext.SetCurrentContext (null);
}
}
}
// Periodic texture cache flush every frame
_videoTextureCache.Flush(0);
EAGLContext.SetCurrentContext(null);
}
}
}
}

Просмотреть файл

@ -1,294 +1,330 @@
using System;
using Foundation;
using OpenGLES;
using CoreGraphics;
using CoreVideo;
using Foundation;
using OpenGLES;
using OpenTK.Graphics.ES20;
using System;
using System.Text;
namespace AVCustomEdit
{
public class OpenGLRenderer : NSObject
{
public int ProgramY = -1;
public int ProgramUV = -1;
public CGAffineTransform RenderTransform;
public CVOpenGLESTextureCache VideoTextureCache;
public EAGLContext CurrentContext;
public uint OffscreenBufferHandle;
public int[] Uniforms = new int[(int)Uniform.Num_Uniforms];
public class OpenGLRenderer : NSObject
{
private const string VertShaderSource = @"attribute vec4 position;
attribute vec2 texCoord;
uniform mat4 renderTransform;
varying vec2 texCoordVarying;
void main()
{
gl_Position = position * renderTransform;
texCoordVarying = texCoord;
}";
const string vertShaderSource = @"attribute vec4 position;
attribute vec2 texCoord;
uniform mat4 renderTransform;
varying vec2 texCoordVarying;
void main()
{
gl_Position = position * renderTransform;
texCoordVarying = texCoord;
}";
const string fragShaderYSource = @"varying highp vec2 texCoordVarying;
uniform sampler2D SamplerY;
void main()
{
gl_FragColor.r = texture2D(SamplerY, texCoordVarying).r;
}";
const string fragShaderUVSource = @"varying highp vec2 texCoordVarying;
uniform sampler2D SamplerUV;
void main()
{
gl_FragColor.rg = texture2D(SamplerUV, texCoordVarying).rg;
}";
private const string FragShaderYSource = @"varying highp vec2 texCoordVarying;
uniform sampler2D SamplerY;
void main()
{
gl_FragColor.r = texture2D(SamplerY, texCoordVarying).r;
}";
public OpenGLRenderer ()
{
CurrentContext = new EAGLContext (EAGLRenderingAPI.OpenGLES2);
private const string FragShaderUVSource = @"varying highp vec2 texCoordVarying;
uniform sampler2D SamplerUV;
void main()
{
gl_FragColor.rg = texture2D(SamplerUV, texCoordVarying).rg;
}";
EAGLContext.SetCurrentContext (CurrentContext);
public uint OffscreenBufferHandle;
SetupOffScreenRenderContext();
loadShaders ();
public OpenGLRenderer()
{
CurrentContext = new EAGLContext(EAGLRenderingAPI.OpenGLES2);
EAGLContext.SetCurrentContext(CurrentContext);
EAGLContext.SetCurrentContext (null);
SetupOffScreenRenderContext();
LoadShaders();
}
EAGLContext.SetCurrentContext(null);
}
public virtual CVOpenGLESTexture LumaTextureForPixelBuffer (CVPixelBuffer pixelBuffer)
{
CVOpenGLESTexture lumaTexture = null;
CVReturn err;
if (VideoTextureCache == null) {
Console.Error.WriteLine ("No video texture cache");
return lumaTexture;
}
// Periodic texture cache flush every frame
VideoTextureCache.Flush (0);
public int ProgramY { get; set; } = -1;
public int ProgramUV { get; set; } = -1;
public CGAffineTransform RenderTransform { get; set; }
public CVOpenGLESTextureCache _videoTextureCache { get; set; }
public EAGLContext CurrentContext { get; set; }
public int[] Uniforms { get; set; } = new int[(int)Uniform.Num_Uniforms];
// CVOpenGLTextureCacheCreateTextureFromImage will create GL texture optimally from CVPixelBufferRef.
// UV
lumaTexture = VideoTextureCache.TextureFromImage (pixelBuffer, true, All.RedExt, (int)pixelBuffer.Width,(int) pixelBuffer.Height, All.RedExt, DataType.UnsignedByte, 0, out err);
if (lumaTexture == null || err != CVReturn.Success)
Console.Error.WriteLine ("Error at creating luma texture using CVOpenGLESTextureCacheCreateTextureFromImage: {0}", err);
public virtual void RenderPixelBuffer(CVPixelBuffer destinationPixelBuffer, CVPixelBuffer foregroundPixelBuffer, CVPixelBuffer backgroundPixelBuffer, float tween)
{
DoesNotRecognizeSelector(new ObjCRuntime.Selector("_cmd"));
}
return lumaTexture;
}
public void SetupOffScreenRenderContext()
{
//-- Create CVOpenGLESTextureCacheRef for optimal CVPixelBufferRef to GLES texture conversion.
if (_videoTextureCache != null)
{
_videoTextureCache.Dispose();
_videoTextureCache = null;
}
public virtual CVOpenGLESTexture ChromaTextureForPixelBuffer (CVPixelBuffer pixelBuffer)
{
CVOpenGLESTexture chromaTexture = null;
CVReturn err;
if (VideoTextureCache == null) {
Console.Error.WriteLine ("No video texture cache");
return chromaTexture;
}
// Periodic texture cache flush every frame
VideoTextureCache.Flush (0);
_videoTextureCache = CVOpenGLESTextureCache.FromEAGLContext(CurrentContext);
// CVOpenGLTextureCacheCreateTextureFromImage will create GL texture optimally from CVPixelBufferRef.
// UV
var height = pixelBuffer.GetHeightOfPlane (1);
var width = pixelBuffer.GetWidthOfPlane (1);
chromaTexture = VideoTextureCache.TextureFromImage (pixelBuffer, true, All.RgExt, (int)width, (int)height, All.RgExt, DataType.UnsignedByte, 1, out err);
GL.Disable(EnableCap.DepthTest);
GL.GenFramebuffers(1, out OffscreenBufferHandle);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, OffscreenBufferHandle);
}
if (chromaTexture == null || err != CVReturn.Success)
Console.Error.WriteLine ("Error at creating chroma texture using CVOpenGLESTextureCacheCreateTextureFromImage: {0}", err);
public virtual CVOpenGLESTexture LumaTextureForPixelBuffer(CVPixelBuffer pixelBuffer)
{
CVOpenGLESTexture lumaTexture = null;
if (_videoTextureCache == null)
{
Console.Error.WriteLine("No video texture cache");
goto bail;
}
return chromaTexture;
}
// Periodic texture cache flush every frame
_videoTextureCache.Flush(0);
public virtual void RenderPixelBuffer(CVPixelBuffer destinationPixelBuffer, CVPixelBuffer foregroundPixelBuffer, CVPixelBuffer backgroundPixelBuffer, float tween)
{
DoesNotRecognizeSelector (new ObjCRuntime.Selector ("_cmd"));
}
// CVOpenGLTextureCacheCreateTextureFromImage will create GL texture optimally from CVPixelBufferRef.
// Y
lumaTexture = _videoTextureCache.TextureFromImage(pixelBuffer,
true,
All.RedExt,
(int)pixelBuffer.Width,
(int)pixelBuffer.Height,
All.RedExt,
DataType.UnsignedByte,
0,
out CVReturn error);
public void SetupOffScreenRenderContext()
{
//-- Create CVOpenGLESTextureCacheRef for optimal CVPixelBufferRef to GLES texture conversion.
if (VideoTextureCache != null) {
VideoTextureCache.Dispose ();
VideoTextureCache = null;
}
if (lumaTexture == null || error != CVReturn.Success)
{
Console.Error.WriteLine($"Error at creating luma texture using CVOpenGLESTextureCacheCreateTextureFromImage: {error}");
}
VideoTextureCache = CVOpenGLESTextureCache.FromEAGLContext (CurrentContext);
GL.Disable (EnableCap.DepthTest);
GL.GenFramebuffers (1, out OffscreenBufferHandle);
GL.BindFramebuffer (FramebufferTarget.Framebuffer, OffscreenBufferHandle);
}
bail:
return lumaTexture;
}
// OpenGL ES 2 shader compilation
bool loadShaders()
{
int vertShader, fragShaderY, fragShaderUV;
public virtual CVOpenGLESTexture ChromaTextureForPixelBuffer(CVPixelBuffer pixelBuffer)
{
CVOpenGLESTexture chromaTexture = null;
if (_videoTextureCache == null)
{
Console.Error.WriteLine("No video texture cache");
goto bail;
}
// Create the shader program.
ProgramY = GL.CreateProgram ();
ProgramUV = GL.CreateProgram ();
// Periodic texture cache flush every frame
_videoTextureCache.Flush(0);
// Create and compile the vertex shader.
// CVOpenGLTextureCacheCreateTextureFromImage will create GL texture optimally from CVPixelBufferRef.
// UV
var height = pixelBuffer.GetHeightOfPlane(1);
var width = pixelBuffer.GetWidthOfPlane(1);
chromaTexture = _videoTextureCache.TextureFromImage(pixelBuffer,
true,
All.RgExt,
(int)width,
(int)height,
All.RgExt,
DataType.UnsignedByte,
1,
out CVReturn error);
if (!CompileShader (ShaderType.VertexShader, vertShaderSource, out vertShader)) {
Console.Error.WriteLine ("Failed to compile vertex shader");
return false;
}
if (chromaTexture == null || error != CVReturn.Success)
{
Console.Error.WriteLine($"Error at creating chroma texture using CVOpenGLESTextureCacheCreateTextureFromImage: {error}");
}
if(!CompileShader (ShaderType.FragmentShader, fragShaderYSource, out fragShaderY)) {
Console.Error.WriteLine ("Failed to compile Y fragment shader");
return false;
}
bail:
return chromaTexture;
}
if(!CompileShader (ShaderType.FragmentShader, fragShaderUVSource, out fragShaderUV)) {
Console.Error.WriteLine ("Failed to compile UV fragment shader");
return false;
}
#region OpenGL ES 2 shader compilation
GL.AttachShader (ProgramY, vertShader);
GL.AttachShader (ProgramY, fragShaderY);
private bool LoadShaders()
{
int vertShader, fragShaderY, fragShaderUV;
GL.AttachShader (ProgramUV, vertShader);
GL.AttachShader (ProgramUV, fragShaderUV);
// Create the shader program.
ProgramY = GL.CreateProgram();
ProgramUV = GL.CreateProgram();
// Bind attribute locations. This needs to be done prior to linking.
GL.BindAttribLocation (ProgramY,(int) Attrib.Vertex_Y, "position");
GL.BindAttribLocation (ProgramY,(int) Attrib.TexCoord_Y, "texCoord");
GL.BindAttribLocation (ProgramUV,(int) Attrib.Vertex_UV, "position");
GL.BindAttribLocation (ProgramUV, (int)Attrib.TexCoord_UV, "texCoord");
// Create and compile the vertex shader.
if (!CompileShader(ShaderType.VertexShader, VertShaderSource, out vertShader))
{
Console.Error.WriteLine("Failed to compile vertex shader");
return false;
}
// Link the program.
if (!LinkProgram (ProgramY) || !LinkProgram (ProgramUV)) {
Console.Error.WriteLine ("Failed to link program");
if (vertShader != 0) {
GL.DeleteShader (vertShader);
vertShader = 0;
}
if (fragShaderY != 0) {
GL.DeleteShader (fragShaderY);
fragShaderY = 0;
}
if (fragShaderUV != 0) {
GL.DeleteShader (fragShaderUV);
fragShaderUV = 0;
}
if (ProgramY != 0) {
GL.DeleteProgram (ProgramY);
ProgramY = 0;
}
if (ProgramUV != 0) {
GL.DeleteProgram (ProgramUV);
ProgramUV = 0;
}
return false;
}
if (!CompileShader(ShaderType.FragmentShader, FragShaderYSource, out fragShaderY))
{
Console.Error.WriteLine("Failed to compile Y fragment shader");
return false;
}
// Get uniform locations.
Uniforms [(int)Uniform.Y] = GL.GetUniformLocation (ProgramY, "SamplerY");
Uniforms [(int)Uniform.UV] = GL.GetUniformLocation (ProgramUV, "SamplerUV");
Uniforms [(int)Uniform.Render_Transform_Y] = GL.GetUniformLocation (ProgramY, "renderTransform");
Uniforms [(int)Uniform.Render_Transform_UV] = GL.GetUniformLocation (ProgramUV, "renderTransform");
if (!CompileShader(ShaderType.FragmentShader, FragShaderUVSource, out fragShaderUV))
{
Console.Error.WriteLine("Failed to compile UV fragment shader");
return false;
}
//Release vertex and fragment shaders.
if (vertShader != 0) {
GL.DetachShader (ProgramY, vertShader);
GL.DetachShader (ProgramUV, vertShader);
GL.DeleteShader (vertShader);
}
if (fragShaderY != 0) {
GL.DetachShader (ProgramY, fragShaderY);
GL.DeleteShader (fragShaderY);
}
if (fragShaderUV != 0) {
GL.DetachShader (ProgramUV, fragShaderUV);
GL.DeleteShader (fragShaderUV);
}
// Attach vertex shader to programY.
GL.AttachShader(ProgramY, vertShader);
return true;
}
// Attach fragment shader to programY.
GL.AttachShader(ProgramY, fragShaderY);
static bool CompileShader(ShaderType type, string sourceString, out int shader)
{
if (string.IsNullOrEmpty (sourceString)) {
Console.Error.WriteLine ("Failed to load vertex shader: Empty source string");
shader = 0;
return false;
}
// Attach vertex shader to programUV.
GL.AttachShader(ProgramUV, vertShader);
int status;
shader = GL.CreateShader (type);
GL.ShaderSource (shader, sourceString);
GL.CompileShader (shader);
// Attach fragment shader to programUV.
GL.AttachShader(ProgramUV, fragShaderUV);
// Bind attribute locations. This needs to be done prior to linking.
GL.BindAttribLocation(ProgramY, (int)Attrib.Vertex_Y, "position");
GL.BindAttribLocation(ProgramY, (int)Attrib.TexCoord_Y, "texCoord");
GL.BindAttribLocation(ProgramUV, (int)Attrib.Vertex_UV, "position");
GL.BindAttribLocation(ProgramUV, (int)Attrib.TexCoord_UV, "texCoord");
// Link the program.
if (!LinkProgram(ProgramY) || !LinkProgram(ProgramUV))
{
Console.Error.WriteLine("Failed to link program");
if (vertShader != 0)
{
GL.DeleteShader(vertShader);
vertShader = 0;
}
if (fragShaderY != 0)
{
GL.DeleteShader(fragShaderY);
fragShaderY = 0;
}
if (fragShaderUV != 0)
{
GL.DeleteShader(fragShaderUV);
fragShaderUV = 0;
}
if (ProgramY != 0)
{
GL.DeleteProgram(ProgramY);
ProgramY = 0;
}
if (ProgramUV != 0)
{
GL.DeleteProgram(ProgramUV);
ProgramUV = 0;
}
return false;
}
// Get uniform locations.
Uniforms[(int)Uniform.Y] = GL.GetUniformLocation(ProgramY, "SamplerY");
Uniforms[(int)Uniform.UV] = GL.GetUniformLocation(ProgramUV, "SamplerUV");
Uniforms[(int)Uniform.Render_Transform_Y] = GL.GetUniformLocation(ProgramY, "renderTransform");
Uniforms[(int)Uniform.Render_Transform_UV] = GL.GetUniformLocation(ProgramUV, "renderTransform");
// Release vertex and fragment shaders.
if (vertShader != 0)
{
GL.DetachShader(ProgramY, vertShader);
GL.DetachShader(ProgramUV, vertShader);
GL.DeleteShader(vertShader);
}
if (fragShaderY != 0)
{
GL.DetachShader(ProgramY, fragShaderY);
GL.DeleteShader(fragShaderY);
}
if (fragShaderUV != 0)
{
GL.DetachShader(ProgramUV, fragShaderUV);
GL.DeleteShader(fragShaderUV);
}
return true;
}
private static bool CompileShader(ShaderType type, string sourceString, out int shader)
{
if (string.IsNullOrEmpty(sourceString))
{
Console.Error.WriteLine("Failed to load vertex shader: Empty source string");
shader = 0;
return false;
}
shader = GL.CreateShader(type);
GL.ShaderSource(shader, sourceString);
GL.CompileShader(shader);
#if DEBUG
int logLength;
GL.GetShader (shader, ShaderParameter.InfoLogLength, out logLength);
if (logLength > 0) {
var log = GL.GetShaderInfoLog (shader);
Console.WriteLine ("Shader compile log: {0}", log);
}
GL.GetShader(shader, ShaderParameter.InfoLogLength, out int logLength);
if (logLength > 0)
{
var log = GL.GetShaderInfoLog(shader);
Console.WriteLine("Shader compile log: {0}", log);
}
#endif
GL.GetShader (shader, ShaderParameter.CompileStatus, out status);
if (status == 0) {
GL.DeleteShader (shader);
return false;
}
GL.GetShader(shader, ShaderParameter.CompileStatus, out int status);
if (status == 0)
{
GL.DeleteShader(shader);
return false;
}
return true;
}
return true;
}
static bool LinkProgram(int program)
{
int status;
GL.LinkProgram (program);
private static bool LinkProgram(int program)
{
GL.LinkProgram(program);
#if DEBUG
int logLength;
GL.GetProgram(program, ProgramParameter.InfoLogLength, out logLength);
if (logLength > 0) {
var log = new StringBuilder(logLength);
GL.GetProgramInfoLog (program, logLength, out logLength, log);
Console.WriteLine("Program link log: {0}", log);
log.Clear ();
}
GL.GetProgram(program, ProgramParameter.InfoLogLength, out int logLength);
if (logLength > 0)
{
var log = new StringBuilder(logLength);
GL.GetProgramInfoLog(program, logLength, out logLength, log);
Console.WriteLine($"Program link log: {log}");
log.Clear();
}
#endif
GL.GetProgram (program, ProgramParameter.LinkStatus, out status);
return status != 0;
}
GL.GetProgram(program, ProgramParameter.LinkStatus, out int status);
return status != 0;
}
}
static bool ValidateProgram(int program)
{
int logLength;
int status;
GL.ValidateProgram (program);
#endregion
GL.GetProgram (program, ProgramParameter.InfoLogLength, out logLength);
if (logLength > 0) {
var log = new StringBuilder(logLength);
GL.GetProgramInfoLog (program, logLength, out logLength, log);
Console.WriteLine("Program validate log: {0}", log);
log.Clear ();
}
GL.GetProgram (program, ProgramParameter.ValidateStatus, out status);
return status != 0;
}
}
public enum Uniform
{
Y,
UV,
Render_Transform_Y,
Render_Transform_UV,
Num_Uniforms
}
public enum Attrib{
Vertex_Y,
TexCoord_Y,
Vertex_UV,
TexCoord_UV,
Num_Attributes
}
}
public enum Uniform
{
Y,
UV,
Render_Transform_Y,
Render_Transform_UV,
Num_Uniforms
}
public enum Attrib
{
Vertex_Y,
TexCoord_Y,
Vertex_UV,
TexCoord_UV,
Num_Attributes
}
}

Просмотреть файл

@ -1,34 +1,35 @@
// This file has been autogenerated from a class added in the UI designer.
using System;
using AVFoundation;
using Foundation;
using UIKit;
using AVFoundation;
using ObjCRuntime;
using System;
using UIKit;
namespace AVCustomEdit
{
public partial class PlayerView : UIView
{
public AVPlayer player
{
get{
return (this.Layer as AVPlayerLayer).Player;
}
set{
(this.Layer as AVPlayerLayer).Player = value;
}
}
[Register("PlayerView")]
public class PlayerView : UIView
{
public PlayerView(IntPtr handle) : base(handle) { }
public PlayerView (IntPtr handle) : base (handle)
{
}
public AVPlayer Player
{
get
{
return (this.Layer as AVPlayerLayer).Player;
}
set
{
(this.Layer as AVPlayerLayer).Player = value;
}
}
[Export ("layerClass")]
public static Class LayerClass()
{
return new Class (typeof(AVPlayerLayer));
}
}
public static Class LayerClass
{
[Export("layerClass")]
get
{
return new Class(typeof(AVPlayerLayer));
}
}
}
}

40
AVCustomEdit/AVCustomEdit/PlayerView.designer.cs сгенерированный
Просмотреть файл

@ -1,20 +1,20 @@
// WARNING
//
// This file has been generated automatically by Xamarin Studio to store outlets and
// actions made in the UI designer. If it is removed, they will be lost.
// Manual changes to this file may not be handled correctly.
//
using Foundation;
using System.CodeDom.Compiler;
namespace AVCustomEdit
{
[Register ("PlayerView")]
partial class PlayerView
{
void ReleaseDesignerOutlets ()
{
}
}
}
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
namespace AVCustomEdit
{
[Register ("PlayerView")]
partial class PlayerView
{
void ReleaseDesignerOutlets ()
{
}
}
}

Просмотреть файл

@ -1,553 +0,0 @@
// This file has been autogenerated from a class added in the UI designer.
using System;
using System.Collections.Generic;
using Foundation;
using UIKit;
using AVFoundation;
using CoreFoundation;
using CoreMedia;
using System.Threading.Tasks;
using System.IO;
using AssetsLibrary;
namespace AVCustomEdit
{
public partial class PlayerViewController : UIViewController
{
const int NSEC_PER_SEC = 1000000000;
Boolean playing;
Boolean scrubInFlight;
Boolean seekToZeroBeforePlaying;
float lastScrubSliderValue;
float playRateToRestore;
NSObject timeObserver;
float transitionDuration;
int transitionType;
bool transitionsEnabled;
NSObject observer;
NSTimer progressTimer;
public SimpleEditor Editor;
public List<AVAsset> Clips;
public List<NSValue> ClipTimeRanges;
public AVPlayer Player;
public AVPlayerItem PlayerItem;
public UIPopoverController Popover;
public static NSString StatusObservationContext = new NSString("AVCustomEditPlayerViewControllerStatusObservationContext");
public static NSString RateObservationContext = new NSString ("AVCustomEditPlayerViewControllerRateObservationContext");
double playerItemDuration {
get {
if (Player == null)
return Double.PositiveInfinity;
CMTime itemDuration = CMTime.Invalid;
AVPlayerItem playerItem = Player.CurrentItem;
if (Player.Status == AVPlayerStatus.ReadyToPlay) {
itemDuration = playerItem.Duration;
}
return itemDuration.Seconds;
}
}
public PlayerViewController (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
gestureRecognizer.ShouldReceiveTouch = ShouldReceiveTouch;
gestureRecognizer.AddTarget (() => HandleTapGesture (gestureRecognizer));
Editor = new SimpleEditor ();
Clips = new List<AVAsset> ();
ClipTimeRanges = new List<NSValue> ();
transitionType = TransitionTypeController.DiagonalWipeTransition;
transitionDuration = 2.0f;
transitionsEnabled = true;
updateScrubber ();
updateTimeLabel ();
setupEditingAndPlayback ();
}
public override void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
if (Player == null) {
seekToZeroBeforePlaying = false;
Player = new AVPlayer ();
Player.AddObserver (this, (NSString)"rate", NSKeyValueObservingOptions.Old | NSKeyValueObservingOptions.New, RateObservationContext.Handle);
playerView.player = Player;
}
addTimeObserverToPlayer ();
// Build AVComposition and AVVideoComposition objects for playback
Editor.BuildCompositionObjects (true);
synchronizePlayerWithEditor ();
}
public override void ViewWillDisappear (bool animated)
{
base.ViewWillDisappear (animated);
Player.Pause();
removeTimeObserverFromPlayer ();
}
public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
{
if (segue.Identifier == "Transition") {
var transitionController = (segue.DestinationViewController as UINavigationController).TopViewController as TransitionTypeController;
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
Popover = (segue as UIStoryboardPopoverSegue).PopoverController;
transitionController.TransitionTypePicked = TransitionTypePicked;
transitionController.CurrentTransition = transitionType;
if (transitionType == TransitionTypeController.CrossDissolveTransition) {
if (transitionController.CrossDissolveCell == null)
transitionController.LoadView ();
transitionController.CrossDissolveCell.Accessory = UITableViewCellAccessory.Checkmark;
} else {
if (transitionController.DiagonalWipeCell == null)
transitionController.LoadView ();
transitionController.DiagonalWipeCell.Accessory = UITableViewCellAccessory.Checkmark;
}
}
}
//Simple Editor
void setupEditingAndPlayback()
{
var path1 = NSBundle.MainBundle.PathForResource ("sample_clip1", "m4v");
var path2 = NSBundle.MainBundle.PathForResource ("sample_clip2", "mov");
var asset1 = AVAsset.FromUrl (new NSUrl (path1, false)) as AVUrlAsset;
var asset2 = AVAsset.FromUrl (new NSUrl (path2, false)) as AVUrlAsset;
DispatchGroup dispatchGroup = DispatchGroup.Create ();
string[] assetKeys = {
"tracks",
"duration",
"composable"
};
loadAsset (asset1, assetKeys, dispatchGroup);
loadAsset (asset2, assetKeys, dispatchGroup);
// Wait until both assets are loaded
dispatchGroup.Wait (DispatchTime.Forever);
InvokeOnMainThread(delegate{
synchronizeWithEditor();
});
}
void loadAsset(AVAsset asset, string[] assetKeysToLoad, DispatchGroup dispatchGroup)
{
dispatchGroup.Enter ();
asset.LoadValuesAsynchronously (assetKeysToLoad, () => {
foreach(var key in assetKeysToLoad)
{
NSError error;
if(asset.StatusOfValue(key, out error) == AVKeyValueStatus.Failed)
{
Console.Error.WriteLine("Key value loading failed for key {0} with error: {1}", key, error);
dispatchGroup.Leave();
}
}
if(!asset.Composable)
{
Console.Error.WriteLine("Asset is not composable");
dispatchGroup.Leave();
}
Clips.Add(asset);
ClipTimeRanges.Add(NSValue.FromCMTimeRange(new CMTimeRange {
Start = CMTime.FromSeconds(0, 1),
Duration = CMTime.FromSeconds(5,1)
}));
dispatchGroup.Leave();
});
}
void synchronizePlayerWithEditor()
{
if (Player == null)
return;
AVPlayerItem playerItem = Editor.PlayerItem;
var status = (NSString)"status";
if (PlayerItem != playerItem) {
if (PlayerItem != null) {
PlayerItem.RemoveObserver (this, status);
NSNotificationCenter.DefaultCenter.RemoveObserver (observer, AVPlayerItem.DidPlayToEndTimeNotification, PlayerItem);
}
PlayerItem = playerItem;
if (PlayerItem != null) {
PlayerItem.SeekingWaitsForVideoCompositionRendering = true;
PlayerItem.AddObserver (this, status, NSKeyValueObservingOptions.New|
NSKeyValueObservingOptions.Initial, StatusObservationContext.Handle);
observer = NSNotificationCenter.DefaultCenter.AddObserver (AVPlayerItem.DidPlayToEndTimeNotification, notification => {
Console.WriteLine ("Seek Zero = true");
seekToZeroBeforePlaying = true;
}, playerItem);
//NSNotificationCenter.DefaultCenter.AddObserver (this, new MonoTouch.ObjCRuntime.Selector ("playerItemEnded:"), AVPlayerItem.DidPlayToEndTimeNotification, playerItem);
}
Player.ReplaceCurrentItemWithPlayerItem (playerItem);
}
}
[Export("playerItemEnded:")]
void playerItemEnded (NSObject obj)
{
Console.WriteLine("Seek Zero = true");
seekToZeroBeforePlaying = true;
}
void synchronizeWithEditor()
{
//Clips
synchronizeEditorClips ();
synchronizeEditorClipTimeRanges ();
//Transitions
if (transitionsEnabled) {
Editor.TransitionDuration = CMTime.FromSeconds (transitionDuration, 600);
Editor.TransitionType = transitionType;
} else {
Editor.TransitionDuration = CMTime.Invalid;
}
Editor.BuildCompositionObjects (true);
synchronizePlayerWithEditor ();
}
void synchronizeEditorClips()
{
var validClips = new List<AVAsset> ();
foreach (var asset in Clips) {
if (asset != null)
validClips.Add (asset);
}
Editor.Clips = validClips;
}
void synchronizeEditorClipTimeRanges()
{
var validClipTimeRanges = new List<NSValue> ();
foreach (var timeRange in ClipTimeRanges) {
if (timeRange != null)
validClipTimeRanges.Add (timeRange);
}
Editor.ClipTimeRanges = validClipTimeRanges;
}
//Utilities
void addTimeObserverToPlayer()
{
if (timeObserver != null) {
return;
}
if (Player == null)
return;
if (Player.CurrentItem == null)
return;
if (Player.CurrentItem.Status != AVPlayerItemStatus.ReadyToPlay)
return;
double duration = playerItemDuration;
if (!Double.IsInfinity (duration)) {
float width = (float)scrubber.Bounds.Width;
double interval = 0.5 * duration / width;
if (interval > 1.0)
interval = 1.0;
timeObserver = Player.AddPeriodicTimeObserver (CMTime.FromSeconds (interval, NSEC_PER_SEC), DispatchQueue.MainQueue, delegate {
updateScrubber();
updateTimeLabel();
});
}
}
void removeTimeObserverFromPlayer()
{
if (timeObserver != null) {
Player.RemoveTimeObserver (timeObserver);
timeObserver = null;
}
}
public override void ObserveValue (NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context)
{
var ch = new NSObservedChange (change);
if (context == RateObservationContext.Handle) {
//TODO: need debug here.
float newRate = ((NSNumber)ch.NewValue).FloatValue;
var oldRateNum = (NSNumber)ch.OldValue;
if (oldRateNum != null && newRate != oldRateNum.FloatValue) {
playing = (newRate != 0.0f || playRateToRestore != 0.0f);
updatePlayPauseButton ();
updateScrubber ();
updateTimeLabel ();
}
} else if (context == StatusObservationContext.Handle) {
var playerItem = ofObject as AVPlayerItem;
if (playerItem.Status == AVPlayerItemStatus.ReadyToPlay) {
/* Once the AVPlayerItem becomes ready to play, i.e.
[playerItem status] == AVPlayerItemStatusReadyToPlay,
its duration can be fetched from the item. */
addTimeObserverToPlayer ();
} else if (playerItem.Status == AVPlayerItemStatus.Failed) {
reportError (playerItem.Error);
}
} else {
base.ObserveValue (keyPath, ofObject, change, context);
}
}
void updatePlayPauseButton()
{
var style = playing ? UIBarButtonSystemItem.Pause : UIBarButtonSystemItem.Play;
var newPlayPauseButton = new UIBarButtonItem (style, (s, e) => togglePlayPause (s as UIBarButtonItem));
var items = toolBar.Items;
items [0] = newPlayPauseButton;
toolBar.SetItems (items, false);
playPauseButton = newPlayPauseButton;
}
void updateTimeLabel()
{
if (Player == null)
return;
var seconds = Player.CurrentTime.Seconds;
if (double.IsInfinity(seconds))
seconds = 0;
int secondsInt =(int) Math.Round (seconds);
int minutes = secondsInt / 60;
secondsInt -= minutes * 60;
currentTimeLabel.TextColor = UIColor.White;
currentTimeLabel.TextAlignment = UITextAlignment.Center;
currentTimeLabel.Text = string.Format ("{0} : {1}", minutes, secondsInt);
}
void updateScrubber()
{
double duration = playerItemDuration;
if (!double.IsInfinity(duration)) {
double time = Player.CurrentTime.Seconds;
scrubber.Value = (float)(time / duration);
} else {
scrubber.Value = 0.0f;
}
}
void updateProgress(NSTimer timer)
{
var session = timer.UserInfo as AVAssetExportSession;
if (session != null && session.Status == AVAssetExportSessionStatus.Exporting)
exportProgressView.Progress = session.Progress;
}
void reportError(NSError error)
{
DispatchQueue.MainQueue.DispatchAsync (() => {
if (error == null)
return;
new UIAlertView (error.LocalizedDescription, error.DebugDescription, null, "OK", null).Show ();
});
}
partial void togglePlayPause (UIBarButtonItem sender)
{
playing = !playing;
if (playing) {
if (seekToZeroBeforePlaying) {
Player.Seek (CMTime.Zero);
seekToZeroBeforePlaying = false;
// player.Seek (CMTime.Zero, delegate(bool finished) {
// if(finished){
// Console.WriteLine ("Seeked to Zero");
// this.seekToZeroBeforePlaying = false;
// this.player.Play();
// }
// else
// Console.WriteLine ("Seek to Zero Failed");
// });
}
Player.Play();
} else {
Player.Pause();
}
}
partial void beginScrubbing (UISlider sender)
{
seekToZeroBeforePlaying = false;
playRateToRestore = Player.Rate;
Player.Rate = 0f;
removeTimeObserverFromPlayer ();
}
async partial void endScrubbing (UISlider sender)
{
if (scrubInFlight)
await scrubTo (lastScrubSliderValue);
addTimeObserverToPlayer ();
Player.Rate = playRateToRestore;
playRateToRestore = 0f;
}
async partial void scrub (UISlider sender)
{
lastScrubSliderValue = scrubber.Value;
if (!scrubInFlight)
await scrubTo (lastScrubSliderValue);
}
async Task scrubTo (float sliderValue)
{
var duration = playerItemDuration;
if (Double.IsInfinity (duration))
return;
var width = scrubber.Bounds.Width;
var time = duration * sliderValue;
var tolerance = 1f * duration / width;
scrubInFlight = true;
await Player.SeekAsync (CMTime.FromSeconds (time, NSEC_PER_SEC), CMTime.FromSeconds (tolerance, NSEC_PER_SEC), CMTime.FromSeconds (tolerance, NSEC_PER_SEC));
scrubInFlight = false;
updateTimeLabel ();
}
void HandleTapGesture (UITapGestureRecognizer tapGestureRecognizer)
{
toolBar.Hidden = !toolBar.Hidden;
currentTimeLabel.Hidden = !currentTimeLabel.Hidden;
}
partial void exportToMovie (UIBarButtonItem sender)
{
exportProgressView.Hidden = false;
Player.Pause ();
playPauseButton.Enabled = false;
transitionButton.Enabled = false;
scrubber.Enabled = false;
exportButton.Enabled = false;
Editor.BuildCompositionObjects (false);
var session = Editor.AssetExportSession (AVAssetExportSession.PresetMediumQuality);
var filePath = Path.Combine (Path.GetTempPath(), "ExportedProject.mov");
if (File.Exists (filePath))
File.Delete (filePath);
session.OutputUrl = NSUrl.FromFilename (filePath);
session.OutputFileType = AVFileType.QuickTimeMovie;
session.ExportAsynchronously (() => DispatchQueue.MainQueue.DispatchAsync (() => exportCompleted (session)));
progressTimer = NSTimer.CreateRepeatingTimer (0.5, d => updateProgress (progressTimer));
NSRunLoop.Current.AddTimer (progressTimer, NSRunLoopMode.Default);
}
void exportCompleted (AVAssetExportSession session)
{
exportProgressView.Hidden = true;
currentTimeLabel.Hidden = false;
var outputUrl = session.OutputUrl;
progressTimer.Invalidate ();
progressTimer = null;
if (session.Status != AVAssetExportSessionStatus.Completed) {
Console.WriteLine ("exportSession error:{0}", session.Error.LocalizedDescription);
reportError (session.Error);
return;
}
exportProgressView.Progress = 1f;
var library = new ALAssetsLibrary ();
library.WriteVideoToSavedPhotosAlbum (outputUrl, (assetURL, error) => {
if (error != null) {
Console.WriteLine ("writeVideoToAssetsLibrary failed: {0}", error.LocalizedDescription);
reportError (error);
}
library.Dispose();
});
Player.Play ();
playPauseButton.Enabled = true;
transitionButton.Enabled = true;
scrubber.Enabled = true;
exportButton.Enabled = true;
}
bool ShouldReceiveTouch (UIGestureRecognizer gestureRecognizer, UITouch touch)
{
return touch.View == View;
}
public void TransitionTypePicked (int transitionType)
{
this.transitionType = transitionType;
synchronizeWithEditor ();
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
Popover.Dismiss (true);
else
DismissViewController (true, null);
}
}
}

Просмотреть файл

@ -1,112 +0,0 @@
// WARNING
//
// This file has been generated automatically by Xamarin Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using UIKit;
using System.CodeDom.Compiler;
namespace AVCustomEdit
{
[Register ("PlayerViewController")]
partial class PlayerViewController
{
[Outlet]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
UIKit.UILabel currentTimeLabel { get; set; }
[Outlet]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
UIKit.UIBarButtonItem exportButton { get; set; }
[Outlet]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
UIKit.UIProgressView exportProgressView { get; set; }
[Outlet]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
UIKit.UITapGestureRecognizer gestureRecognizer { get; set; }
[Outlet]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
AVCustomEdit.PlayerView playerView { get; set; }
[Outlet]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
UIKit.UIBarButtonItem playPauseButton { get; set; }
[Outlet]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
UIKit.UISlider scrubber { get; set; }
[Outlet]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
UIKit.UIToolbar toolBar { get; set; }
[Outlet]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
UIKit.UIBarButtonItem transitionButton { get; set; }
[Action ("beginScrubbing:")]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
partial void beginScrubbing (UISlider sender);
[Action ("endScrubbing:")]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
partial void endScrubbing (UISlider sender);
[Action ("exportToMovie:")]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
partial void exportToMovie (UIBarButtonItem sender);
[Action ("scrub:")]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
partial void scrub (UISlider sender);
[Action ("togglePlayPause:")]
[GeneratedCodeAttribute ("iOS Designer", "1.0")]
partial void togglePlayPause (UIBarButtonItem sender);
void ReleaseDesignerOutlets ()
{
if (currentTimeLabel != null) {
currentTimeLabel.Dispose ();
currentTimeLabel = null;
}
if (exportButton != null) {
exportButton.Dispose ();
exportButton = null;
}
if (exportProgressView != null) {
exportProgressView.Dispose ();
exportProgressView = null;
}
if (gestureRecognizer != null) {
gestureRecognizer.Dispose ();
gestureRecognizer = null;
}
if (playerView != null) {
playerView.Dispose ();
playerView = null;
}
if (playPauseButton != null) {
playPauseButton.Dispose ();
playPauseButton = null;
}
if (scrubber != null) {
scrubber.Dispose ();
scrubber = null;
}
if (toolBar != null) {
toolBar.Dispose ();
toolBar = null;
}
if (transitionButton != null) {
transitionButton.Dispose ();
transitionButton = null;
}
}
}
}

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичные данные
AVCustomEdit/AVCustomEdit/Resources/Default.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 5.2 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичные данные
AVCustomEdit/AVCustomEdit/Resources/Icon-72.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 6.6 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 18 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 4.2 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.0 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 5.2 KiB

Двоичные данные
AVCustomEdit/AVCustomEdit/Resources/Icon.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 5.1 KiB

Двоичные данные
AVCustomEdit/AVCustomEdit/Resources/Icon@2x.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 14 KiB

Просмотреть файл

@ -1,252 +1,212 @@
using System;
using System.Collections.Generic;
using Foundation;
using CoreMedia;
using AVFoundation;
using CoreMedia;
using Foundation;
using System.Collections.Generic;
namespace AVCustomEdit
{
public class SimpleEditor : NSObject
{
public List<AVAsset> Clips;
public List<NSValue> ClipTimeRanges;
public class SimpleEditor : NSObject
{
private AVMutableComposition composition;
public int TransitionType;
public CMTime TransitionDuration;
AVMutableComposition Composition;
AVMutableVideoComposition VideoComposition;
private AVMutableVideoComposition videoComposition;
void buildTransitionComposition(AVMutableComposition composition, AVMutableVideoComposition videoComposition)
{
CMTime nextClipStartTime = CMTime.Zero;
int clipsCount = Clips.Count;
public List<AVAsset> Clips { get; set; } // array of AVURLAssets
// Make transitionDuration no greater than half the shortest clip duration.
CMTime transitionDuration = TransitionDuration;
public List<NSValue> ClipTimeRanges { get; set; } // array of CMTimeRanges stored in NSValues.
foreach (var clipTimeRange in ClipTimeRanges) {
if (clipTimeRange == null)
continue;
public TransitionType TransitionType { get; set; }
CMTime halfClipDuration = clipTimeRange.CMTimeRangeValue.Duration;
halfClipDuration.TimeScale *= 2;
transitionDuration = CMTime.GetMinimum(transitionDuration,halfClipDuration);
}
public CMTime TransitionDuration { get; set; }
// Add two video tracks and two audio tracks.
var compositionVideoTracks = new AVMutableCompositionTrack [2];
var compositionAudioTracks = new AVMutableCompositionTrack [2];
public AVPlayerItem PlayerItem => new AVPlayerItem(this.composition) { VideoComposition = this.videoComposition };
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);
private void BuildTransitionComposition(AVMutableComposition mutableComposition, AVMutableVideoComposition mutableVideoComposition)
{
var nextClipStartTime = CMTime.Zero;
var clipsCount = this.Clips.Count;
var passThroughTimeRanges = new CMTimeRange[clipsCount];
var transitionTimeRanges = new CMTimeRange[clipsCount];
// Make transitionDuration no greater than half the shortest clip duration.
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);
}
}
// 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);
// Add two video tracks and two audio tracks.
var compositionVideoTracks = new AVMutableCompositionTrack[2];
var compositionAudioTracks = new AVMutableCompositionTrack[2];
AVAssetTrack clipAudioTrack = asset.TracksWithMediaType (AVMediaType.Audio) [0];
compositionAudioTracks [alternatingIndex].InsertTimeRange (timeRangeInAsset, clipAudioTrack, nextClipStartTime, out error);
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);
// 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
};
var passThroughTimeRanges = new CMTimeRange[clipsCount];
var transitionTimeRanges = new CMTimeRange[clipsCount];
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);
// 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 clipTimeRange = this.ClipTimeRanges[i];
// 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);
var timeRangeInAsset = clipTimeRange != null ? clipTimeRange.CMTimeRangeValue
: new CMTimeRange { Start = CMTime.Zero, Duration = asset.Duration };
// Remember the time range for the transition to the next item.
var clipVideoTrack = asset.TracksWithMediaType(AVMediaType.Video)[0];
compositionVideoTracks[alternatingIndex].InsertTimeRange(timeRangeInAsset, clipVideoTrack, nextClipStartTime, out NSError error);
if(i + 1 < clipsCount)
{
transitionTimeRanges [i] = new CMTimeRange {
Start = nextClipStartTime,
Duration = transitionDuration
};
var 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 };
// Set up the video composition to perform cross dissolve or diagonal wipe transitions between clips.
var instructions = new List<AVVideoCompositionInstruction> ();
if (i > 0)
{
passThroughTimeRanges[i].Start = CMTime.Add(passThroughTimeRanges[i].Start, transitionDuration);
passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration, transitionDuration);
}
// 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 (i + 1 < clipsCount)
{
passThroughTimeRanges[i].Duration = CMTime.Subtract(passThroughTimeRanges[i].Duration, transitionDuration);
}
// 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);
// 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);
}
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);
// 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>();
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;
}
// 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
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);
}
}
}
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];
videoComposition.Instructions = instructions.ToArray ();
}
var passThroughLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks[alternatingIndex]);
passThroughInstruction.LayerInstructions = new[] { passThroughLayer };
public void BuildCompositionObjects(bool playBack)
{
if (Clips == null || Clips.Count == 0) {
Composition = null;
VideoComposition = null;
return;
}
instructions.Add(passThroughInstruction);
}
var videoSize = Clips [0].NaturalSize;
var composition = AVMutableComposition.Create ();
AVMutableVideoComposition videoComposition;
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]);
composition.NaturalSize = videoSize;
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;
}
// 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".
instructions.Add(videoInstruction);
}
else
{
var transitionInstruction = AVMutableVideoCompositionInstruction.Create() as AVMutableVideoCompositionInstruction;
transitionInstruction.TimeRange = transitionTimeRanges[i];
videoComposition = AVMutableVideoComposition.Create ();
var fromLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks[alternatingIndex]);
var toLayer = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(compositionVideoTracks[1 - alternatingIndex]);
//Set CustomVideoCompositorClass based on the Compositor user selected.
transitionInstruction.LayerInstructions = new[] { toLayer, fromLayer };
instructions.Add(transitionInstruction);
}
}
}
if (TransitionType == TransitionTypeController.DiagonalWipeTransition) {
videoComposition.CustomVideoCompositorClass = new ObjCRuntime.Class (typeof(DiagonalWipeCompositor));
} else {
videoComposition.CustomVideoCompositorClass = new ObjCRuntime.Class (typeof(CrossDissolveCompositor));
}
mutableVideoComposition.Instructions = instructions.ToArray();
}
buildTransitionComposition (composition, videoComposition);
if (videoComposition != null) {
// Every videoComposition needs these properties to be set:
videoComposition.FrameDuration = new CMTime (1, 30);
videoComposition.RenderSize = videoSize;
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;
}
Composition = composition;
VideoComposition = videoComposition;
}
mutableComposition.NaturalSize = videoSize;
public AVAssetExportSession AssetExportSession (string presetName)
{
var session = new AVAssetExportSession (Composition, presetName);
session.VideoComposition = VideoComposition;
return session;
}
// 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".
public AVPlayerItem PlayerItem {
get {
AVPlayerItem playerItem = AVPlayerItem.FromAsset (Composition);
//TODO:Got an NullReferenceException here if this.videoComposition.CustomVideoCompositorClass is not a "Nil" Class
playerItem.VideoComposition = VideoComposition;
//If set the CustomVideoCompositorClass in playerItem.VideoComposition, will get a System.NotImplementedException
//playerItem.VideoComposition.CustomVideoCompositorClass = new MonoTouch.ObjCRuntime.Class(typeof(CrossDissolveCompositor));
return playerItem;
}
}
}
}
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;
}
}
public AVAssetExportSession AssetExportSessionWithPreset(string presetName)
{
return new AVAssetExportSession(composition, presetName)
{
VideoComposition = videoComposition
};
}
}
}

Просмотреть файл

@ -1,84 +1,68 @@
// This file has been autogenerated from a class added in the UI designer.
using System;
using Foundation;
using System;
using UIKit;
namespace AVCustomEdit
{
public partial class TransitionTypeController : UITableViewController
{
public Action<int> TransitionTypePicked;
public interface ITransitionTypePickerDelegate
{
void DidPickTransitionType(TransitionType transitionType);
}
public const int DiagonalWipeTransition = 0;
public const int CrossDissolveTransition = 1;
public partial class TransitionTypeController : UITableViewController
{
public TransitionTypeController(IntPtr handle) : base(handle) { }
public UITableViewCell CrossDissolveCell {
get {
return crossDissolveCell;
}
set {
crossDissolveCell = value;
}
}
public ITransitionTypePickerDelegate Delegate { get; set; }
public UITableViewCell DiagonalWipeCell {
get {
return diagonalWipeCell;
}
set {
diagonalWipeCell = value;
}
}
public TransitionType CurrentTransition { get; set; }
public int CurrentTransition;
public override void ViewDidLoad()
{
base.ViewDidLoad();
public TransitionTypeController (IntPtr handle) : base (handle)
{
}
switch (this.CurrentTransition)
{
case TransitionType.CrossDissolveTransition:
this.crossDissolveCell.Accessory = UITableViewCellAccessory.Checkmark;
break;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
case TransitionType.DiagonalWipeTransition:
this.diagonalWipeCell.Accessory = UITableViewCellAccessory.Checkmark;
break;
}
}
tableView.Delegate = new TableViewDelegate ();
}
partial void TransitionSelected(UIBarButtonItem sender)
{
this.Delegate.DidPickTransitionType(this.CurrentTransition);
}
partial void TransitionSelected (NSObject sender)
{
TransitionTypePicked (CurrentTransition);
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
var selectedCell = tableView.CellAt(indexPath);
selectedCell.Accessory = UITableViewCellAccessory.Checkmark;
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell selectedCell = tableView.CellAt (indexPath);
selectedCell.EditingAccessory = UITableViewCellAccessory.Checkmark;
if (selectedCell == this.diagonalWipeCell)
{
this.crossDissolveCell.Accessory = UITableViewCellAccessory.None;
this.CurrentTransition = TransitionType.DiagonalWipeTransition;
this.Delegate.DidPickTransitionType(TransitionType.DiagonalWipeTransition);
}
else if (selectedCell == this.crossDissolveCell)
{
this.diagonalWipeCell.Accessory = UITableViewCellAccessory.None;
this.CurrentTransition = TransitionType.CrossDissolveTransition;
this.Delegate.DidPickTransitionType(TransitionType.CrossDissolveTransition);
}
switch (selectedCell.Tag) {
case TransitionTypeController.DiagonalWipeTransition:
CrossDissolveCell.Accessory = UITableViewCellAccessory.None;
if (TransitionTypePicked != null)
TransitionTypePicked (TransitionTypeController.DiagonalWipeTransition);
CurrentTransition = DiagonalWipeTransition;
break;
case TransitionTypeController.CrossDissolveTransition:
DiagonalWipeCell.Accessory = UITableViewCellAccessory.None;
if (TransitionTypePicked != null)
TransitionTypePicked (TransitionTypeController.CrossDissolveTransition);
CurrentTransition = CrossDissolveTransition;
break;
}
tableView.DeselectRow(indexPath, true);
}
}
tableView.DeselectRow (indexPath, true);
}
}
public class TableViewDelegate : UITableViewDelegate
{
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
}
}
}
public enum TransitionType
{
DiagonalWipeTransition = 0,
CrossDissolveTransition = 1,
}
}

Просмотреть файл

@ -1,45 +1,42 @@
// WARNING
//
// This file has been generated automatically by Xamarin Studio to store outlets and
// actions made in the UI designer. If it is removed, they will be lost.
// Manual changes to this file may not be handled correctly.
//
using Foundation;
using System.CodeDom.Compiler;
namespace AVCustomEdit
{
[Register ("TransitionTypeController")]
partial class TransitionTypeController
{
[Outlet]
UIKit.UITableViewCell crossDissolveCell { get; set; }
[Outlet]
UIKit.UITableViewCell diagonalWipeCell { get; set; }
[Outlet]
UIKit.UITableView tableView { get; set; }
[Action ("TransitionSelected:")]
partial void TransitionSelected (Foundation.NSObject sender);
void ReleaseDesignerOutlets ()
{
if (crossDissolveCell != null) {
crossDissolveCell.Dispose ();
crossDissolveCell = null;
}
if (diagonalWipeCell != null) {
diagonalWipeCell.Dispose ();
diagonalWipeCell = null;
}
if (tableView != null) {
tableView.Dispose ();
tableView = null;
}
}
}
}
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace AVCustomEdit
{
[Register ("TransitionTypeController")]
partial class TransitionTypeController
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UITableViewCell crossDissolveCell { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UITableViewCell diagonalWipeCell { get; set; }
[Action ("TransitionSelected:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void TransitionSelected (UIKit.UIBarButtonItem sender);
void ReleaseDesignerOutlets ()
{
if (crossDissolveCell != null) {
crossDissolveCell.Dispose ();
crossDissolveCell = null;
}
if (diagonalWipeCell != null) {
diagonalWipeCell.Dispose ();
diagonalWipeCell = null;
}
}
}
}

Просмотреть файл

@ -0,0 +1,591 @@
using AssetsLibrary;
using AVFoundation;
using CoreFoundation;
using CoreMedia;
using Foundation;
using Photos;
using System;
using System.Collections.Generic;
using System.IO;
using UIKit;
namespace AVCustomEdit
{
public partial class ViewController : UIViewController, IUIGestureRecognizerDelegate, ITransitionTypePickerDelegate
{
private readonly NSString StatusObservationContext = new NSString("AVCustomEditPlayerViewControllerStatusObservationContext");
private readonly NSString RateObservationContext = new NSString("AVCustomEditPlayerViewControllerRateObservationContext");
private SimpleEditor editor;
private List<AVAsset> clips;
private List<NSValue> clipTimeRanges;
private AVPlayer player;
private AVPlayerItem playerItem;
private bool isPlaying;
private bool isScrubInFlight;
private bool isSeekToZeroBeforePlaying;
private float lastScrubSliderValue;
private float playRateToRestore;
private NSObject timeObserver;
private float transitionDuration;
private TransitionType transitionType;
private bool isTransitionsEnabled;
private NSTimer progressTimer;
protected ViewController(IntPtr handle) : base(handle) { }
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.editor = new SimpleEditor();
this.clips = new List<AVAsset>();
this.clipTimeRanges = new List<NSValue>();
// Defaults for the transition settings.
this.transitionType = TransitionType.DiagonalWipeTransition;
this.transitionDuration = 2f;
this.isTransitionsEnabled = true;
this.UpdateScrubber();
this.UpdateTimeLabel();
// Add the clips from the main bundle to create a composition using them
this.SetupEditingAndPlayback();
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
if (this.player == null)
{
this.isSeekToZeroBeforePlaying = false;
this.player = new AVPlayer();
this.player.AddObserver(this, "rate", NSKeyValueObservingOptions.Old | NSKeyValueObservingOptions.New, RateObservationContext.Handle);
this.playerView.Player = this.player;
}
this.AddTimeObserverToPlayer();
// Build AVComposition and AVVideoComposition objects for playback
this.editor.BuildCompositionObjectsForPlayback(true);
this.SynchronizePlayerWithEditor();
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
this.player.Pause();
this.RemoveTimeObserverFromPlayer();
}
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
{
if (segue.Identifier == "Transition")
{
// Setup transition type picker controller before it is shown.
if ((segue.DestinationViewController as UINavigationController)?.TopViewController is TransitionTypeController transitionTypePickerController)
{
transitionTypePickerController.Delegate = this;
transitionTypePickerController.CurrentTransition = this.transitionType;
}
}
}
#region Simple Editor
private void SetupEditingAndPlayback()
{
var path1 = NSBundle.MainBundle.PathForResource("sample_clip1", "m4v");
var path2 = NSBundle.MainBundle.PathForResource("sample_clip2", "mov");
var asset1 = AVAsset.FromUrl(new NSUrl(path1, false)) as AVUrlAsset;
var asset2 = AVAsset.FromUrl(new NSUrl(path2, false)) as AVUrlAsset;
var dispatchGroup = DispatchGroup.Create();
string[] assetKeysToLoadAndTest = { "tracks", "duration", "composable" };
this.LoadAsset(asset1, assetKeysToLoadAndTest, dispatchGroup);
this.LoadAsset(asset2, assetKeysToLoadAndTest, dispatchGroup);
// Wait until both assets are loaded
dispatchGroup.Wait(DispatchTime.Forever);
base.InvokeOnMainThread(() => this.SynchronizeWithEditor());
}
private void LoadAsset(AVAsset asset, string[] assetKeysToLoad, DispatchGroup dispatchGroup)
{
dispatchGroup.Enter();
asset.LoadValuesAsynchronously(assetKeysToLoad, () =>
{
// 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;
}
}
if (!asset.Composable)
{
Console.WriteLine("Asset is not composable");
goto bail;
}
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);
bail:
dispatchGroup.Leave();
});
}
private void SynchronizePlayerWithEditor()
{
if (this.player != null)
{
var playerItem = this.editor.PlayerItem;
if (this.playerItem != playerItem)
{
if (this.playerItem != null)
{
this.playerItem.RemoveObserver(this, "status");
NSNotificationCenter.DefaultCenter.RemoveObserver(this, AVPlayerItem.DidPlayToEndTimeNotification, this.playerItem);
}
this.playerItem = playerItem;
if (this.playerItem != null)
{
this.playerItem.SeekingWaitsForVideoCompositionRendering = true;
// Observe the player item "status" key to determine when it is ready to play
this.playerItem.AddObserver(this, "status", NSKeyValueObservingOptions.New | NSKeyValueObservingOptions.Initial, StatusObservationContext.Handle);
// When the player item has played to its end time we'll set a flag
// so that the next time the play method is issued the player will
// be reset to time zero first.
NSNotificationCenter.DefaultCenter.AddObserver(AVPlayerItem.DidPlayToEndTimeNotification, this.PlayerItemDidReachEnd);
}
this.player.ReplaceCurrentItemWithPlayerItem(this.playerItem);
}
}
}
private void SynchronizeWithEditor()
{
// Clips
this.SynchronizeEditorClipsWithOurClips();
this.SynchronizeEditorClipTimeRangesWithOurClipTimeRanges();
// Transitions
if (this.isTransitionsEnabled)
{
this.editor.TransitionDuration = CMTime.FromSeconds(this.transitionDuration, 600);
this.editor.TransitionType = this.transitionType;
}
else
{
this.editor.TransitionDuration = CMTime.Invalid;
}
// 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;
}
#endregion
#region Utilities
private const int NSEC_PER_SEC = 1000000000;
/// <summary>
/// Update the scrubber and time label periodically.
/// </summary>
private void AddTimeObserverToPlayer()
{
if (this.player?.CurrentItem != null &&
this.player.CurrentItem.Status == AVPlayerItemStatus.ReadyToPlay)
{
var duration = this.GetPlayerItemDuration().Seconds;
if (!double.IsInfinity(duration))
{
var width = this.scrubber.Bounds.Width;
var interval = 0.5 * duration / width;
/* The time label needs to update at least once per second. */
if (interval > 1.0)
{
interval = 1.0;
}
timeObserver = this.player.AddPeriodicTimeObserver(CMTime.FromSeconds(interval, NSEC_PER_SEC),
DispatchQueue.MainQueue,
(time) =>
{
this.UpdateScrubber();
this.UpdateTimeLabel();
});
}
}
}
private void RemoveTimeObserverFromPlayer()
{
if (this.timeObserver != null)
{
this.player.RemoveTimeObserver(this.timeObserver);
this.timeObserver.Dispose();
this.timeObserver = null;
}
}
private CMTime GetPlayerItemDuration()
{
var itemDuration = CMTime.Invalid;
var playerItem = this.player?.CurrentItem;
if (playerItem?.Status == AVPlayerItemStatus.ReadyToPlay)
{
itemDuration = playerItem.Duration;
}
// Will be kCMTimeInvalid if the item is not ready to play.
return itemDuration;
}
public override void ObserveValue(NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context)
{
if (context == this.RateObservationContext.Handle)
{
var changes = new NSObservedChange(change);
if (changes.NewValue is NSNumber newValue &&
(changes.OldValue == null || (changes.OldValue is NSNumber oldRate && oldRate.FloatValue != newValue.FloatValue)))
{
this.isPlaying = (newValue.FloatValue != 0f) || (playRateToRestore != 0f);
this.UpdatePlayPauseButton();
this.UpdateScrubber();
this.UpdateTimeLabel();
// clear
newValue.Dispose();
newValue = null;
}
}
else if (context == this.StatusObservationContext.Handle)
{
if (ofObject is AVPlayerItem playerItem)
{
if (playerItem.Status == AVPlayerItemStatus.ReadyToPlay)
{
/* Once the AVPlayerItem becomes ready to play, i.e.
[playerItem status] == AVPlayerItemStatusReadyToPlay,
its duration can be fetched from the item. */
this.AddTimeObserverToPlayer();
}
else if (playerItem.Status == AVPlayerItemStatus.Failed)
{
this.ReportError(this.playerItem.Error);
}
}
}
else
{
base.ObserveValue(keyPath, ofObject, change, context);
}
}
private void UpdatePlayPauseButton()
{
var style = this.isPlaying ? UIBarButtonSystemItem.Pause : UIBarButtonSystemItem.Play;
using (var newPlayPauseButton = new UIBarButtonItem(style, (sender, e) => this.TogglePlayPause(sender as UIBarButtonItem)))
{
var items = this.toolbar.Items;
items[0] = newPlayPauseButton;
this.toolbar.SetItems(items, false);
this.playPauseButton = newPlayPauseButton;
}
}
private void UpdateTimeLabel()
{
var seconds = this.player != null ? this.player.CurrentTime.Seconds : 0d;
if (double.IsNaN(seconds))
{
seconds = 0;
}
this.currentTimeLabel.TextColor = UIColor.White;
this.currentTimeLabel.TextAlignment = UITextAlignment.Center;
this.currentTimeLabel.Text = TimeSpan.FromSeconds(seconds).ToString(@"mm\:ss");
}
private void UpdateScrubber()
{
var duration = this.GetPlayerItemDuration().Seconds;
if (!double.IsNaN(duration))
{
var time = this.player.CurrentTime.Seconds;
this.scrubber.Value = (float)(time / duration);
}
else
{
this.scrubber.Value = 0f;
}
}
private void UpdateProgress(AVAssetExportSession session)
{
if (session?.Status == AVAssetExportSessionStatus.Exporting)
{
this.exportProgressView.Progress = session.Progress;
}
}
private void ReportError(NSError error)
{
if (error != null)
{
DispatchQueue.MainQueue.DispatchAsync(() =>
{
var alertView = UIAlertController.Create(error.LocalizedDescription, error.LocalizedRecoverySuggestion, UIAlertControllerStyle.Alert);
alertView.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
base.PresentViewController(alertView, true, null);
});
}
}
#endregion
#region IBActions
partial void TogglePlayPause(UIBarButtonItem sender)
{
this.isPlaying = !this.isPlaying;
if (this.isPlaying)
{
if (this.isSeekToZeroBeforePlaying)
{
this.player.Seek(CMTime.Zero);
this.isSeekToZeroBeforePlaying = false;
}
this.player.Play();
}
else
{
this.player.Pause();
}
}
partial void BeginScrubbing(UISlider sender)
{
this.isSeekToZeroBeforePlaying = false;
this.playRateToRestore = this.player.Rate;
this.player.Rate = 0f;
this.RemoveTimeObserverFromPlayer();
}
partial void Scrub(UISlider sender)
{
this.lastScrubSliderValue = this.scrubber.Value;
if (!this.isScrubInFlight)
{
this.ScrubToSliderValue(this.lastScrubSliderValue);
}
}
private void ScrubToSliderValue(float sliderValue)
{
var duration = this.GetPlayerItemDuration().Seconds;
if (!double.IsInfinity(duration))
{
var width = this.scrubber.Bounds.Width;
double time = duration * sliderValue;
double tolerance = 1d * duration / width;
this.isScrubInFlight = true;
this.player.Seek(CMTime.FromSeconds(time, NSEC_PER_SEC),
CMTime.FromSeconds(tolerance, NSEC_PER_SEC),
CMTime.FromSeconds(tolerance, NSEC_PER_SEC),
(finished) =>
{
this.isScrubInFlight = false;
this.UpdateTimeLabel();
});
}
}
partial void EndScrubbing(UISlider sender)
{
if (this.isScrubInFlight)
{
this.ScrubToSliderValue(this.lastScrubSliderValue);
}
this.AddTimeObserverToPlayer();
this.player.Rate = this.playRateToRestore;
this.playRateToRestore = 0f;
}
/// <summary>
/// Called when the player item has played to its end time
/// </summary>
private void PlayerItemDidReachEnd(NSNotification obj)
{
// After the movie has played to its end time, seek back to time zero to play it again.
this.isSeekToZeroBeforePlaying = true;
}
partial void HandleTapGesture(UITapGestureRecognizer sender)
{
this.toolbar.Hidden = !this.toolbar.Hidden;
this.currentTimeLabel.Hidden = !this.currentTimeLabel.Hidden;
}
partial void ExportToMovie(UIBarButtonItem sender)
{
this.exportProgressView.Hidden = false;
this.player.Pause();
this.playPauseButton.Enabled = false;
this.transitionButton.Enabled = false;
this.scrubber.Enabled = false;
this.exportButton.Enabled = false;
this.editor.BuildCompositionObjectsForPlayback(false);
// Get the export session from the editor
var session = this.editor.AssetExportSessionWithPreset(AVAssetExportSession.PresetMediumQuality);
var filePath = Path.Combine(Path.GetTempPath(), "ExportedProject.mov");
if (File.Exists(filePath))
{
File.Delete(filePath);
}
// If a preset that is not compatible with AVFileTypeQuickTimeMovie is used, one can use -[AVAssetExportSession supportedFileTypes] to obtain a supported file type for the output file and UTTypeCreatePreferredIdentifierForTag to obtain an appropriate path extension for the output file type.
session.OutputUrl = NSUrl.FromFilename(filePath);
session.OutputFileType = AVFileType.QuickTimeMovie;
session.ExportAsynchronously(() => DispatchQueue.MainQueue.DispatchAsync(() => OnExportCompleted(session)));
// Update progress view with export progress
this.progressTimer = NSTimer.CreateRepeatingTimer(0.5, d => this.UpdateProgress(session));
NSRunLoop.Current.AddTimer(this.progressTimer, NSRunLoopMode.Default);
}
private void OnExportCompleted(AVAssetExportSession session)
{
this.exportProgressView.Hidden = true;
this.currentTimeLabel.Hidden = false;
var outputURL = session.OutputUrl;
this.progressTimer.Invalidate();
this.progressTimer.Dispose();
this.progressTimer = null;
if (session.Status != AVAssetExportSessionStatus.Completed)
{
Console.WriteLine($"exportSession error:{session.Error}");
this.ReportError(session.Error);
}
else
{
this.exportProgressView.Progress = 1f;
// Save the exported movie to the camera roll
PHPhotoLibrary.RequestAuthorization((status) =>
{
if(status == PHAuthorizationStatus.Authorized)
{
PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => PHAssetChangeRequest.FromVideo(outputURL),
(successfully, error) =>
{
if (error != null)
{
Console.WriteLine($"writeVideoToAssestsLibrary failed: {error}");
this.ReportError(error);
}
base.InvokeOnMainThread(() =>
{
this.playPauseButton.Enabled = true;
this.transitionButton.Enabled = true;
this.scrubber.Enabled = true;
this.exportButton.Enabled = true;
});
});
}
});
}
}
#endregion
#region Gesture recognizer delegate
[Export("gestureRecognizer:shouldReceiveTouch:")]
public bool ShouldReceiveTouch(UIGestureRecognizer recognizer, UITouch touch)
{
return touch.View == this.playerView;
}
#endregion
public void DidPickTransitionType(TransitionType transitionType)
{
this.transitionType = transitionType;
// Let the editor know of the change in transition type.
this.SynchronizeWithEditor();
this.DismissViewController(true, null);
}
}
}

115
AVCustomEdit/AVCustomEdit/ViewController.designer.cs сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,115 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
namespace AVCustomEdit
{
[Register ("ViewController")]
partial class ViewController
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel currentTimeLabel { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIBarButtonItem exportButton { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIProgressView exportProgressView { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
AVCustomEdit.PlayerView playerView { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIBarButtonItem playPauseButton { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UISlider scrubber { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIToolbar toolbar { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIBarButtonItem transitionButton { get; set; }
[Action ("BeginScrubbing:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void BeginScrubbing (UIKit.UISlider sender);
[Action ("EndScrubbing:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void EndScrubbing (UIKit.UISlider sender);
[Action ("ExportToMovie:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void ExportToMovie (UIKit.UIBarButtonItem sender);
[Action ("HandleTapGesture:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void HandleTapGesture (UIKit.UITapGestureRecognizer sender);
[Action ("Scrub:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void Scrub (UIKit.UISlider sender);
[Action ("TogglePlayPause:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void TogglePlayPause (UIKit.UIBarButtonItem sender);
void ReleaseDesignerOutlets ()
{
if (currentTimeLabel != null) {
currentTimeLabel.Dispose ();
currentTimeLabel = null;
}
if (exportButton != null) {
exportButton.Dispose ();
exportButton = null;
}
if (exportProgressView != null) {
exportProgressView.Dispose ();
exportProgressView = null;
}
if (playerView != null) {
playerView.Dispose ();
playerView = null;
}
if (playPauseButton != null) {
playPauseButton.Dispose ();
playPauseButton = null;
}
if (scrubber != null) {
scrubber.Dispose ();
scrubber = null;
}
if (toolbar != null) {
toolbar.Dispose ();
toolbar = null;
}
if (transitionButton != null) {
transitionButton.Dispose ();
transitionButton = null;
}
}
}
}

10
AVCustomEdit/Metadata.xml Normal file
Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<SampleMetadata>
<ID>1ff461ca-3867-43a7-9afb-2a85f08e015b</ID>
<IsFullApplication>true</IsFullApplication>
<Brief>It's a simple AVFoundation based movie editing application demonstrating custom compositing to add transitions. It implements the CustomVideoCompositor and CustomVideoCompositionInstruction protocols to have access to individual source frames, which are then be rendered using OpenGL off screen rendering.</Brief>
<SupportedPlatforms>iOS</SupportedPlatforms>
<Level>Intermediate</Level>
<Tags>AVFoundation, OpenGL</Tags>
<Gallery>true</Gallery>
</SampleMetadata>

Просмотреть файл

@ -5,6 +5,8 @@ AVCustomEdit is a simple AVFoundation based movie editing application demonstrat
This is a port of Apple's iOS7 sample AVCustomEdit.
![Home View](Screenshots/screenshot-1.png)
Instructions
------------
1. Open the transition menu in the lower right. Select a transition.
@ -15,8 +17,12 @@ Build
------------
Building this sample requires Xcode 5.0 and iOS 7 or later.
License
-------
Xamarin port changes are released under the MIT license.
Author
------------
Copyright © 2014 Apple Inc. All Rights Reserved.
Ported to Xamarin.iOS by Timothy Risi.
Ported to Xamarin.iOS by Timothy Risi/Mykyta Bondarenko.

Двоичные данные
AVCustomEdit/Screenshots/screenshot-1.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 392 KiB

Двоичные данные
AVCustomEdit/Screenshots/screenshot-2.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB