├── .gitignore ├── README.md ├── VBPlayerDemo ├── VBPlayerDemo.xcodeproj │ └── project.pbxproj ├── VBPlayerDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── PlayerView.h │ ├── PlayerView.m │ ├── VBDisplayLayer.h │ ├── VBPlayer.a │ ├── VBPlayer.h │ ├── ViewController.h │ ├── ViewController.m │ └── main.m └── VBPlayerDemoTests │ ├── Info.plist │ └── VBPlayerDemoTests.m └── license /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.xcworkspace 7 | !default.xcworkspace 8 | xcuserdata/ 9 | profile 10 | *.moved-aside 11 | DerivedData 12 | .idea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Overview 2 | Viblast Player iOS SDK plays HLS and MPEG DASH streams using the iOS devices hardware decoders for video and audio. The API is similar to Apple's AVPlayer, but much simpler and can be easily integrated into existing projects using the AVPlayer. The Player can be easily configured to use Viblast PDN and enable P2P delivery. 3 | 4 | Visit [Viblast's commercial web page](http://viblast.com/) 5 | 6 | This repository contains an example XCode project to demonstrate the basic usage of the player. 7 | 8 | ### XCode 9 | If you want to start using [Viblast](http://viblast.com/player/)'s player in your XCode project here is what you need to do: 10 | 11 | Drag and drop the library and all of its headers (you can find them inside the example project - all VB\*.\* files) 12 | in your project. When XCode asks you to choose options for added files, don't forget to put a mark on '*Copy items if needed*' option. 13 | The remarkable size of `VBPlayer.a` is due to the fact the library is *fat*. It has 4 different builds inside of it - 2 for device and 2 for simulator (one for 32bit and one for 64bit architectures). 14 | 15 | Go to the project's build target. 16 | **(We've encountered some issues migrating to XCode7 so until we resolve them please set the _Enable Bitcode_ option to "_No_"!)** 17 | Select **Build Phases** and under the **Link Binary With Libraries** section make sure the 18 | following are present: 19 | 20 | * Foundation 21 | * AVFoundation 22 | * VideoToolbox 23 | * CoreGraphics 24 | * CoreMedia 25 | 26 | *NOTE: If you've followed the previous steps, the `VBPlayer.a` lib should 27 | already be there.* 28 | Now select **Build Settings** and add the following in **Other Linker Flags**: 29 | 30 | * -lstdc++ 31 | * -ObjC 32 | 33 | ### Brief documentation 34 | 35 | `VBPlayer.h` is pretty self-explanatory on its own and it can be used as a good source of documentation. 36 | It defines two major interfaces: 37 | 38 | * `VBPlayer` is a player which can play a *HLS* or *DASH* streams provided from a *CDN* and its successor 39 | * `VBDataPlayer` can play separate media segments (or chunks) delivered by the client. 40 | 41 | ##### VBPlayer 42 | The API is reminiscent of Apple's AVPlayer, but much simpler. 43 | You can initialize the player with a single URL of the CDN hosting the stream: 44 | ``` 45 | VBPlayer *player = [[VBPlayer alloc] initWithCDN:@"www.mycdn.com/manifest.mpd"]; 46 | ``` 47 | Immediately after its initialization the player will try to start downloading the stream. The `status` property is *KVO-compliant* and as soon as the player has buffered enough 48 | data it will be set to `VBPlayerStatusReadyToPlay`. 49 | Having this property set means you can assume the following: 50 | * the playback will start simultaneously if you issue `-play` 51 | * `duration` and `currentTime` will be resolved. 52 | 53 | If the player fails for some reason the status will be set to `VBPlayerStatusFailed` and the `error` property will contain 54 | more information about the failure. 55 | The player will stop automatically when it is deallocated. If you need to change the *CDN* source of the player you'll just have to reinitialize it. 56 | 57 | You can use `-seekToTime:` methods to seek the media timeline if the stream is not a live broadcast. To let you help draw 58 | adequate seek bar you can subscribe as a timeline observer using `-addPeriodicTimeObserverForInterval:queue:usingBlock:` 59 | 60 | Setting a `VBPlayerDelegate` will get you notified about a certain playback events, like stalls and when the playback has finished. 61 | 62 | ##### VBDataPlayer 63 | This API lets you feed the player with media segments much like a queue or a buffer: 64 | ```` 65 | VBDataPlayer *player = [VBDataPlayer createDataPlayer]; 66 | ... 67 | NSError *error = nil; 68 | BOOL succ; 69 | NSData *segmentData = ... ; 70 | // NOTE: It will be a good idea not to call this from the main thread. 71 | succ = [player appendData:segmentData coding:(VBDataCodingMP4) error:&error]; 72 | if (!succ) { 73 | // inspect error 74 | } 75 | ```` 76 | Current supported media codings are all variety of the MP4. 77 | 78 | As soon as the player had been supplied with enough data (both audio and video) it will change its `status` property. 79 | You can inspect the buffered duration ahead of time using `-bufferredDuration` method. 80 | This implementation doesn't know when the stream is going to an end so it is the client's responsibility to call `-endOfStream` whenever there is no more data to append. If there is a delegate, `-playerDidFinish` will be called immediately after the last piece of data had been played. 81 | 82 | A thing to **keep in mind** about this player is that **it doesn't cache any data back in time**. This means that anything that 83 | had been played *must* be supplied again if a *seek* is issued. 84 | 85 | ##### VBDisplayLayer 86 | After the player is ready to play (or even if it is not) you can supply it with a render or a display layer using VBPlayer's `-setDisplayLayer` to capture its video output. 87 | A recommended usage of `VBDisplayLayer` is to define your own `UIView` and set it as layer of this view: 88 | ``` 89 | // PlayerView.m 90 | #import "VBDisplayLayer.h" 91 | @implementation PlayerView 92 | + (Class)layerClass { 93 | return [VBDisplayLayer class]; 94 | } 95 | @end 96 | ``` 97 | It has some useful properties like the *KVO-Compliant* `displayRect` which you should observer to position your UI controls. 98 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2C697BDB1B330A360053BAE5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C697BDA1B330A360053BAE5 /* main.m */; }; 11 | 2C697BDE1B330A360053BAE5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C697BDD1B330A360053BAE5 /* AppDelegate.m */; }; 12 | 2C697BE11B330A360053BAE5 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C697BE01B330A360053BAE5 /* ViewController.m */; }; 13 | 2C697BE41B330A360053BAE5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2C697BE21B330A360053BAE5 /* Main.storyboard */; }; 14 | 2C697BE61B330A360053BAE5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C697BE51B330A360053BAE5 /* Images.xcassets */; }; 15 | 2C697BE91B330A360053BAE5 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2C697BE71B330A360053BAE5 /* LaunchScreen.xib */; }; 16 | 2C697BF51B330A370053BAE5 /* VBPlayerDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C697BF41B330A370053BAE5 /* VBPlayerDemoTests.m */; }; 17 | 2C697C001B33142A0053BAE5 /* PlayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C697BFF1B33142A0053BAE5 /* PlayerView.m */; }; 18 | 2C697C051B33149C0053BAE5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C697C041B33149C0053BAE5 /* Foundation.framework */; }; 19 | 2C697C071B3314B90053BAE5 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C697C061B3314B90053BAE5 /* AVFoundation.framework */; }; 20 | 2C697C091B3314C00053BAE5 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C697C081B3314C00053BAE5 /* VideoToolbox.framework */; }; 21 | 2C697C0B1B3314C70053BAE5 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C697C0A1B3314C70053BAE5 /* CoreGraphics.framework */; }; 22 | 2C697C0D1B3314CE0053BAE5 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C697C0C1B3314CE0053BAE5 /* CoreMedia.framework */; }; 23 | 2CD393851B3C08DF00AC9A86 /* VBPlayer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CD393831B3C08DF00AC9A86 /* VBPlayer.a */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | 2C697BEF1B330A370053BAE5 /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = 2C697BCD1B330A360053BAE5 /* Project object */; 30 | proxyType = 1; 31 | remoteGlobalIDString = 2C697BD41B330A360053BAE5; 32 | remoteInfo = VBPlayerDemo; 33 | }; 34 | /* End PBXContainerItemProxy section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | 2C05960C1C4FCB40007A764C /* VBDisplayLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VBDisplayLayer.h; sourceTree = ""; }; 38 | 2C697BD51B330A360053BAE5 /* VBPlayerDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VBPlayerDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 2C697BD91B330A360053BAE5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | 2C697BDA1B330A360053BAE5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 41 | 2C697BDC1B330A360053BAE5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 42 | 2C697BDD1B330A360053BAE5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 43 | 2C697BDF1B330A360053BAE5 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 44 | 2C697BE01B330A360053BAE5 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 45 | 2C697BE31B330A360053BAE5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 46 | 2C697BE51B330A360053BAE5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 47 | 2C697BE81B330A360053BAE5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 48 | 2C697BEE1B330A370053BAE5 /* VBPlayerDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VBPlayerDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 2C697BF31B330A370053BAE5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | 2C697BF41B330A370053BAE5 /* VBPlayerDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VBPlayerDemoTests.m; sourceTree = ""; }; 51 | 2C697BFE1B33142A0053BAE5 /* PlayerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayerView.h; sourceTree = ""; }; 52 | 2C697BFF1B33142A0053BAE5 /* PlayerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PlayerView.m; sourceTree = ""; }; 53 | 2C697C041B33149C0053BAE5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 54 | 2C697C061B3314B90053BAE5 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 55 | 2C697C081B3314C00053BAE5 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; }; 56 | 2C697C0A1B3314C70053BAE5 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 57 | 2C697C0C1B3314CE0053BAE5 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; 58 | 2CD393831B3C08DF00AC9A86 /* VBPlayer.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = VBPlayer.a; sourceTree = ""; }; 59 | 2CD393841B3C08DF00AC9A86 /* VBPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VBPlayer.h; sourceTree = ""; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | 2C697BD21B330A360053BAE5 /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | 2C697C0D1B3314CE0053BAE5 /* CoreMedia.framework in Frameworks */, 68 | 2C697C0B1B3314C70053BAE5 /* CoreGraphics.framework in Frameworks */, 69 | 2C697C091B3314C00053BAE5 /* VideoToolbox.framework in Frameworks */, 70 | 2C697C071B3314B90053BAE5 /* AVFoundation.framework in Frameworks */, 71 | 2CD393851B3C08DF00AC9A86 /* VBPlayer.a in Frameworks */, 72 | 2C697C051B33149C0053BAE5 /* Foundation.framework in Frameworks */, 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | 2C697BEB1B330A370053BAE5 /* Frameworks */ = { 77 | isa = PBXFrameworksBuildPhase; 78 | buildActionMask = 2147483647; 79 | files = ( 80 | ); 81 | runOnlyForDeploymentPostprocessing = 0; 82 | }; 83 | /* End PBXFrameworksBuildPhase section */ 84 | 85 | /* Begin PBXGroup section */ 86 | 2C697BCC1B330A360053BAE5 = { 87 | isa = PBXGroup; 88 | children = ( 89 | 2C697C0C1B3314CE0053BAE5 /* CoreMedia.framework */, 90 | 2C697C0A1B3314C70053BAE5 /* CoreGraphics.framework */, 91 | 2C697C081B3314C00053BAE5 /* VideoToolbox.framework */, 92 | 2C697C061B3314B90053BAE5 /* AVFoundation.framework */, 93 | 2C697C041B33149C0053BAE5 /* Foundation.framework */, 94 | 2C697BD71B330A360053BAE5 /* VBPlayerDemo */, 95 | 2C697BF11B330A370053BAE5 /* VBPlayerDemoTests */, 96 | 2C697BD61B330A360053BAE5 /* Products */, 97 | ); 98 | sourceTree = ""; 99 | }; 100 | 2C697BD61B330A360053BAE5 /* Products */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 2C697BD51B330A360053BAE5 /* VBPlayerDemo.app */, 104 | 2C697BEE1B330A370053BAE5 /* VBPlayerDemoTests.xctest */, 105 | ); 106 | name = Products; 107 | sourceTree = ""; 108 | }; 109 | 2C697BD71B330A360053BAE5 /* VBPlayerDemo */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 2CD393831B3C08DF00AC9A86 /* VBPlayer.a */, 113 | 2C05960C1C4FCB40007A764C /* VBDisplayLayer.h */, 114 | 2CD393841B3C08DF00AC9A86 /* VBPlayer.h */, 115 | 2C697BDC1B330A360053BAE5 /* AppDelegate.h */, 116 | 2C697BDD1B330A360053BAE5 /* AppDelegate.m */, 117 | 2C697BDF1B330A360053BAE5 /* ViewController.h */, 118 | 2C697BE01B330A360053BAE5 /* ViewController.m */, 119 | 2C697BE21B330A360053BAE5 /* Main.storyboard */, 120 | 2C697BE51B330A360053BAE5 /* Images.xcassets */, 121 | 2C697BE71B330A360053BAE5 /* LaunchScreen.xib */, 122 | 2C697BD81B330A360053BAE5 /* Supporting Files */, 123 | 2C697BFE1B33142A0053BAE5 /* PlayerView.h */, 124 | 2C697BFF1B33142A0053BAE5 /* PlayerView.m */, 125 | ); 126 | path = VBPlayerDemo; 127 | sourceTree = ""; 128 | }; 129 | 2C697BD81B330A360053BAE5 /* Supporting Files */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 2C697BD91B330A360053BAE5 /* Info.plist */, 133 | 2C697BDA1B330A360053BAE5 /* main.m */, 134 | ); 135 | name = "Supporting Files"; 136 | sourceTree = ""; 137 | }; 138 | 2C697BF11B330A370053BAE5 /* VBPlayerDemoTests */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 2C697BF41B330A370053BAE5 /* VBPlayerDemoTests.m */, 142 | 2C697BF21B330A370053BAE5 /* Supporting Files */, 143 | ); 144 | path = VBPlayerDemoTests; 145 | sourceTree = ""; 146 | }; 147 | 2C697BF21B330A370053BAE5 /* Supporting Files */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 2C697BF31B330A370053BAE5 /* Info.plist */, 151 | ); 152 | name = "Supporting Files"; 153 | sourceTree = ""; 154 | }; 155 | /* End PBXGroup section */ 156 | 157 | /* Begin PBXNativeTarget section */ 158 | 2C697BD41B330A360053BAE5 /* VBPlayerDemo */ = { 159 | isa = PBXNativeTarget; 160 | buildConfigurationList = 2C697BF81B330A370053BAE5 /* Build configuration list for PBXNativeTarget "VBPlayerDemo" */; 161 | buildPhases = ( 162 | 2C697BD11B330A360053BAE5 /* Sources */, 163 | 2C697BD21B330A360053BAE5 /* Frameworks */, 164 | 2C697BD31B330A360053BAE5 /* Resources */, 165 | ); 166 | buildRules = ( 167 | ); 168 | dependencies = ( 169 | ); 170 | name = VBPlayerDemo; 171 | productName = VBPlayerDemo; 172 | productReference = 2C697BD51B330A360053BAE5 /* VBPlayerDemo.app */; 173 | productType = "com.apple.product-type.application"; 174 | }; 175 | 2C697BED1B330A370053BAE5 /* VBPlayerDemoTests */ = { 176 | isa = PBXNativeTarget; 177 | buildConfigurationList = 2C697BFB1B330A370053BAE5 /* Build configuration list for PBXNativeTarget "VBPlayerDemoTests" */; 178 | buildPhases = ( 179 | 2C697BEA1B330A370053BAE5 /* Sources */, 180 | 2C697BEB1B330A370053BAE5 /* Frameworks */, 181 | 2C697BEC1B330A370053BAE5 /* Resources */, 182 | ); 183 | buildRules = ( 184 | ); 185 | dependencies = ( 186 | 2C697BF01B330A370053BAE5 /* PBXTargetDependency */, 187 | ); 188 | name = VBPlayerDemoTests; 189 | productName = VBPlayerDemoTests; 190 | productReference = 2C697BEE1B330A370053BAE5 /* VBPlayerDemoTests.xctest */; 191 | productType = "com.apple.product-type.bundle.unit-test"; 192 | }; 193 | /* End PBXNativeTarget section */ 194 | 195 | /* Begin PBXProject section */ 196 | 2C697BCD1B330A360053BAE5 /* Project object */ = { 197 | isa = PBXProject; 198 | attributes = { 199 | LastUpgradeCheck = 0630; 200 | ORGANIZATIONNAME = Viblast; 201 | TargetAttributes = { 202 | 2C697BD41B330A360053BAE5 = { 203 | CreatedOnToolsVersion = 6.3.1; 204 | }; 205 | 2C697BED1B330A370053BAE5 = { 206 | CreatedOnToolsVersion = 6.3.1; 207 | TestTargetID = 2C697BD41B330A360053BAE5; 208 | }; 209 | }; 210 | }; 211 | buildConfigurationList = 2C697BD01B330A360053BAE5 /* Build configuration list for PBXProject "VBPlayerDemo" */; 212 | compatibilityVersion = "Xcode 3.2"; 213 | developmentRegion = English; 214 | hasScannedForEncodings = 0; 215 | knownRegions = ( 216 | en, 217 | Base, 218 | ); 219 | mainGroup = 2C697BCC1B330A360053BAE5; 220 | productRefGroup = 2C697BD61B330A360053BAE5 /* Products */; 221 | projectDirPath = ""; 222 | projectRoot = ""; 223 | targets = ( 224 | 2C697BD41B330A360053BAE5 /* VBPlayerDemo */, 225 | 2C697BED1B330A370053BAE5 /* VBPlayerDemoTests */, 226 | ); 227 | }; 228 | /* End PBXProject section */ 229 | 230 | /* Begin PBXResourcesBuildPhase section */ 231 | 2C697BD31B330A360053BAE5 /* Resources */ = { 232 | isa = PBXResourcesBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | 2C697BE41B330A360053BAE5 /* Main.storyboard in Resources */, 236 | 2C697BE91B330A360053BAE5 /* LaunchScreen.xib in Resources */, 237 | 2C697BE61B330A360053BAE5 /* Images.xcassets in Resources */, 238 | ); 239 | runOnlyForDeploymentPostprocessing = 0; 240 | }; 241 | 2C697BEC1B330A370053BAE5 /* Resources */ = { 242 | isa = PBXResourcesBuildPhase; 243 | buildActionMask = 2147483647; 244 | files = ( 245 | ); 246 | runOnlyForDeploymentPostprocessing = 0; 247 | }; 248 | /* End PBXResourcesBuildPhase section */ 249 | 250 | /* Begin PBXSourcesBuildPhase section */ 251 | 2C697BD11B330A360053BAE5 /* Sources */ = { 252 | isa = PBXSourcesBuildPhase; 253 | buildActionMask = 2147483647; 254 | files = ( 255 | 2C697BE11B330A360053BAE5 /* ViewController.m in Sources */, 256 | 2C697BDE1B330A360053BAE5 /* AppDelegate.m in Sources */, 257 | 2C697BDB1B330A360053BAE5 /* main.m in Sources */, 258 | 2C697C001B33142A0053BAE5 /* PlayerView.m in Sources */, 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | 2C697BEA1B330A370053BAE5 /* Sources */ = { 263 | isa = PBXSourcesBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | 2C697BF51B330A370053BAE5 /* VBPlayerDemoTests.m in Sources */, 267 | ); 268 | runOnlyForDeploymentPostprocessing = 0; 269 | }; 270 | /* End PBXSourcesBuildPhase section */ 271 | 272 | /* Begin PBXTargetDependency section */ 273 | 2C697BF01B330A370053BAE5 /* PBXTargetDependency */ = { 274 | isa = PBXTargetDependency; 275 | target = 2C697BD41B330A360053BAE5 /* VBPlayerDemo */; 276 | targetProxy = 2C697BEF1B330A370053BAE5 /* PBXContainerItemProxy */; 277 | }; 278 | /* End PBXTargetDependency section */ 279 | 280 | /* Begin PBXVariantGroup section */ 281 | 2C697BE21B330A360053BAE5 /* Main.storyboard */ = { 282 | isa = PBXVariantGroup; 283 | children = ( 284 | 2C697BE31B330A360053BAE5 /* Base */, 285 | ); 286 | name = Main.storyboard; 287 | sourceTree = ""; 288 | }; 289 | 2C697BE71B330A360053BAE5 /* LaunchScreen.xib */ = { 290 | isa = PBXVariantGroup; 291 | children = ( 292 | 2C697BE81B330A360053BAE5 /* Base */, 293 | ); 294 | name = LaunchScreen.xib; 295 | sourceTree = ""; 296 | }; 297 | /* End PBXVariantGroup section */ 298 | 299 | /* Begin XCBuildConfiguration section */ 300 | 2C697BF61B330A370053BAE5 /* Debug */ = { 301 | isa = XCBuildConfiguration; 302 | buildSettings = { 303 | ALWAYS_SEARCH_USER_PATHS = NO; 304 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 305 | CLANG_CXX_LIBRARY = "libc++"; 306 | CLANG_ENABLE_MODULES = YES; 307 | CLANG_ENABLE_OBJC_ARC = YES; 308 | CLANG_WARN_BOOL_CONVERSION = YES; 309 | CLANG_WARN_CONSTANT_CONVERSION = YES; 310 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 311 | CLANG_WARN_EMPTY_BODY = YES; 312 | CLANG_WARN_ENUM_CONVERSION = YES; 313 | CLANG_WARN_INT_CONVERSION = YES; 314 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 315 | CLANG_WARN_UNREACHABLE_CODE = YES; 316 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 317 | CODE_SIGN_IDENTITY = "iPhone Developer"; 318 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 319 | COPY_PHASE_STRIP = NO; 320 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 321 | ENABLE_BITCODE = NO; 322 | ENABLE_STRICT_OBJC_MSGSEND = YES; 323 | GCC_C_LANGUAGE_STANDARD = gnu99; 324 | GCC_DYNAMIC_NO_PIC = NO; 325 | GCC_NO_COMMON_BLOCKS = YES; 326 | GCC_OPTIMIZATION_LEVEL = 0; 327 | GCC_PREPROCESSOR_DEFINITIONS = ( 328 | "DEBUG=1", 329 | "$(inherited)", 330 | ); 331 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 332 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 333 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 334 | GCC_WARN_UNDECLARED_SELECTOR = YES; 335 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 336 | GCC_WARN_UNUSED_FUNCTION = YES; 337 | GCC_WARN_UNUSED_VARIABLE = YES; 338 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 339 | MTL_ENABLE_DEBUG_INFO = YES; 340 | ONLY_ACTIVE_ARCH = YES; 341 | SDKROOT = iphoneos; 342 | TARGETED_DEVICE_FAMILY = "1,2"; 343 | }; 344 | name = Debug; 345 | }; 346 | 2C697BF71B330A370053BAE5 /* Release */ = { 347 | isa = XCBuildConfiguration; 348 | buildSettings = { 349 | ALWAYS_SEARCH_USER_PATHS = NO; 350 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 351 | CLANG_CXX_LIBRARY = "libc++"; 352 | CLANG_ENABLE_MODULES = YES; 353 | CLANG_ENABLE_OBJC_ARC = YES; 354 | CLANG_WARN_BOOL_CONVERSION = YES; 355 | CLANG_WARN_CONSTANT_CONVERSION = YES; 356 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 357 | CLANG_WARN_EMPTY_BODY = YES; 358 | CLANG_WARN_ENUM_CONVERSION = YES; 359 | CLANG_WARN_INT_CONVERSION = YES; 360 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 361 | CLANG_WARN_UNREACHABLE_CODE = YES; 362 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 363 | CODE_SIGN_IDENTITY = "iPhone Developer"; 364 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 365 | COPY_PHASE_STRIP = NO; 366 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 367 | ENABLE_BITCODE = NO; 368 | ENABLE_NS_ASSERTIONS = NO; 369 | ENABLE_STRICT_OBJC_MSGSEND = YES; 370 | GCC_C_LANGUAGE_STANDARD = gnu99; 371 | GCC_NO_COMMON_BLOCKS = YES; 372 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 373 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 374 | GCC_WARN_UNDECLARED_SELECTOR = YES; 375 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 376 | GCC_WARN_UNUSED_FUNCTION = YES; 377 | GCC_WARN_UNUSED_VARIABLE = YES; 378 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 379 | MTL_ENABLE_DEBUG_INFO = NO; 380 | SDKROOT = iphoneos; 381 | TARGETED_DEVICE_FAMILY = "1,2"; 382 | VALIDATE_PRODUCT = YES; 383 | }; 384 | name = Release; 385 | }; 386 | 2C697BF91B330A370053BAE5 /* Debug */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 390 | INFOPLIST_FILE = VBPlayerDemo/Info.plist; 391 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 392 | LIBRARY_SEARCH_PATHS = ( 393 | "$(inherited)", 394 | "$(PROJECT_DIR)/VBPlayerDemo", 395 | ); 396 | OTHER_LDFLAGS = ( 397 | "-lstdc++", 398 | "-ObjC", 399 | ); 400 | PRODUCT_NAME = "$(TARGET_NAME)"; 401 | }; 402 | name = Debug; 403 | }; 404 | 2C697BFA1B330A370053BAE5 /* Release */ = { 405 | isa = XCBuildConfiguration; 406 | buildSettings = { 407 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 408 | INFOPLIST_FILE = VBPlayerDemo/Info.plist; 409 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 410 | LIBRARY_SEARCH_PATHS = ( 411 | "$(inherited)", 412 | "$(PROJECT_DIR)/VBPlayerDemo", 413 | ); 414 | OTHER_LDFLAGS = ( 415 | "-lstdc++", 416 | "-ObjC", 417 | ); 418 | PRODUCT_NAME = "$(TARGET_NAME)"; 419 | }; 420 | name = Release; 421 | }; 422 | 2C697BFC1B330A370053BAE5 /* Debug */ = { 423 | isa = XCBuildConfiguration; 424 | buildSettings = { 425 | BUNDLE_LOADER = "$(TEST_HOST)"; 426 | FRAMEWORK_SEARCH_PATHS = ( 427 | "$(SDKROOT)/Developer/Library/Frameworks", 428 | "$(inherited)", 429 | ); 430 | GCC_PREPROCESSOR_DEFINITIONS = ( 431 | "DEBUG=1", 432 | "$(inherited)", 433 | ); 434 | INFOPLIST_FILE = VBPlayerDemoTests/Info.plist; 435 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 436 | PRODUCT_NAME = "$(TARGET_NAME)"; 437 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VBPlayerDemo.app/VBPlayerDemo"; 438 | }; 439 | name = Debug; 440 | }; 441 | 2C697BFD1B330A370053BAE5 /* Release */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | BUNDLE_LOADER = "$(TEST_HOST)"; 445 | FRAMEWORK_SEARCH_PATHS = ( 446 | "$(SDKROOT)/Developer/Library/Frameworks", 447 | "$(inherited)", 448 | ); 449 | INFOPLIST_FILE = VBPlayerDemoTests/Info.plist; 450 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 451 | PRODUCT_NAME = "$(TARGET_NAME)"; 452 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VBPlayerDemo.app/VBPlayerDemo"; 453 | }; 454 | name = Release; 455 | }; 456 | /* End XCBuildConfiguration section */ 457 | 458 | /* Begin XCConfigurationList section */ 459 | 2C697BD01B330A360053BAE5 /* Build configuration list for PBXProject "VBPlayerDemo" */ = { 460 | isa = XCConfigurationList; 461 | buildConfigurations = ( 462 | 2C697BF61B330A370053BAE5 /* Debug */, 463 | 2C697BF71B330A370053BAE5 /* Release */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | defaultConfigurationName = Release; 467 | }; 468 | 2C697BF81B330A370053BAE5 /* Build configuration list for PBXNativeTarget "VBPlayerDemo" */ = { 469 | isa = XCConfigurationList; 470 | buildConfigurations = ( 471 | 2C697BF91B330A370053BAE5 /* Debug */, 472 | 2C697BFA1B330A370053BAE5 /* Release */, 473 | ); 474 | defaultConfigurationIsVisible = 0; 475 | defaultConfigurationName = Release; 476 | }; 477 | 2C697BFB1B330A370053BAE5 /* Build configuration list for PBXNativeTarget "VBPlayerDemoTests" */ = { 478 | isa = XCConfigurationList; 479 | buildConfigurations = ( 480 | 2C697BFC1B330A370053BAE5 /* Debug */, 481 | 2C697BFD1B330A370053BAE5 /* Release */, 482 | ); 483 | defaultConfigurationIsVisible = 0; 484 | defaultConfigurationName = Release; 485 | }; 486 | /* End XCConfigurationList section */ 487 | }; 488 | rootObject = 2C697BCD1B330A360053BAE5 /* Project object */; 489 | } 490 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // VBPlayerDemo 4 | // 5 | // Created by Ivan Ermolaev on 6/18/15. 6 | // Copyright (c) 2015 Viblast. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // VBPlayerDemo 4 | // 5 | // Created by Ivan Ermolaev on 6/18/15. 6 | // Copyright (c) 2015 Viblast. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.viblast.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/PlayerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // PlayerView.h 3 | // VBPlayerDemo 4 | // 5 | // Created by Ivan Ermolaev on 6/18/15. 6 | // Copyright (c) 2015 Viblast. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "VBDisplayLayer.h" 12 | 13 | @interface PlayerView : UIView 14 | 15 | - (VBDisplayLayer *)displayLayer; 16 | @end 17 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/PlayerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // PlayerView.m 3 | // VBPlayerDemo 4 | // 5 | // Created by Ivan Ermolaev on 6/18/15. 6 | // Copyright (c) 2015 Viblast. All rights reserved. 7 | // 8 | 9 | #import "PlayerView.h" 10 | 11 | @implementation PlayerView 12 | 13 | + (Class)layerClass { 14 | return [VBDisplayLayer class]; 15 | } 16 | 17 | - (VBDisplayLayer *)displayLayer { 18 | return (VBDisplayLayer *)self.layer; 19 | } 20 | @end 21 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/VBDisplayLayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // VBDisplayLayer.h 3 | // VBPlayer 4 | // 5 | // Created by Ivan Ermolaev on 1/13/16. 6 | // Copyright © 2016 Viblast. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | /* 13 | VBDisplayLayer 14 | 15 | Return VBDisplayLayer class as layerClass of your UIView in order to 16 | display the output of VBPlayer instances via -setDisplayLayer method. 17 | 18 | @implementation MyPlayerView 19 | ... 20 | + (Class)layerClass { 21 | return [VBDisplayLayer class]; 22 | } 23 | ... 24 | @end 25 | */ 26 | @interface VBDisplayLayer : CALayer 27 | 28 | // You can use KVO to observe the following two properties 29 | @property (nonatomic, readonly, getter=isReadyForDisplay) BOOL readyForDisplay; 30 | @property (nonatomic, readonly) CGRect displayRect; 31 | @end 32 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/VBPlayer.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viblast/ios-player-sdk/5232c6daacad03cb122ccbb1243a2385fb3321a1/VBPlayerDemo/VBPlayerDemo/VBPlayer.a -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/VBPlayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // VBPlayer.h 3 | // VBPlayer 4 | // 5 | // Copyright (c) 2015 Viblast. All rights reserved. 6 | // 7 | 8 | #import 9 | #import 10 | #import 11 | 12 | #import "VBDisplayLayer.h" 13 | 14 | #if defined(__cplusplus) 15 | #define VIBLAST_EXPORT extern "C" 16 | #else 17 | #define VIBLAST_EXPORT extern 18 | #endif 19 | 20 | /* 21 | VBPlayerDelegate 22 | 23 | All of the methods are sent on the main thread. 24 | */ 25 | @class VBPlayer; 26 | 27 | @protocol VBPlayerDelegate 28 | 29 | @optional 30 | 31 | - (void)playerDidEnterStall:(VBPlayer *)player; 32 | - (void)playerDidExitStall:(VBPlayer *)player; 33 | 34 | - (void)playerDidFinishPlaying:(VBPlayer *)player; 35 | @end 36 | 37 | /* 38 | VBPlayer 39 | 40 | */ 41 | typedef NS_ENUM(NSInteger, VBPlayerStatus) { 42 | VBPlayerStatusUnknown, 43 | VBPlayerStatusReadyToPlay, 44 | VBPlayerStatusFailed 45 | }; 46 | 47 | @interface VBPlayer : NSObject 48 | 49 | // Contains the error when player's status is set to VBPlayerStatusFailed. 50 | @property (nonatomic, readonly) NSError *error; 51 | 52 | // Use KVO to observe the status of the player so you know when to call play. 53 | // All status notifications during the playback are serialized on the main queue. 54 | // If the state happens to be VBPlayerStatusFailed you must reinitalize the player. 55 | @property (nonatomic, readonly) VBPlayerStatus status; 56 | 57 | // Currently supported values are 0.0 for stopped playback and 1.0 for playing at normal rate. 58 | @property (nonatomic) float rate; 59 | 60 | // Can't use KVO 61 | @property (readonly) CMTime duration; 62 | 63 | // Use periodic time notifications to poll this property. 64 | @property (readonly) CMTime currentTime; 65 | 66 | @property (nonatomic, weak) id delegate; 67 | 68 | - (instancetype)initWithCDN:(NSString *)cdn; 69 | 70 | // For the available settings check the constants below. 71 | - (instancetype)initWithCDN:(NSString *)cdn settings:(NSDictionary *)settings; 72 | 73 | - (instancetype)initWithArgs:(NSString *)args; 74 | 75 | - (void)play; 76 | - (void)pause; 77 | 78 | // Seek to a given |time| (imprecise). 79 | // Depending on the stream the actual seeked time might not be the same as the requested one 80 | // for efficiency reasons. In order to perform a precised seek see seekToTime:tolerance:. 81 | - (void)seekToTime:(CMTime)time; 82 | 83 | // Seek to a given |time| and provide a |tolerance| back in time to restrict the result time that is 84 | // the time seeked to will be in [time - tolerance, time] range. 85 | // Tolerance kCMTimePositiveInfinity will give the same result as seekToTime:. 86 | // Tolerance kCMTimeZero will perform a precise seek. 87 | - (void)seekToTime:(CMTime)time tolerance:(CMTime)tolerance; 88 | 89 | // Use a |completion| handler if you want to be notified when the seek operation completes. 90 | - (void)seekToTime:(CMTime)time completion:(void(^)(void))completion; 91 | - (void)seekToTime:(CMTime)time tolerance:(CMTime)tolerance completion:(void(^)(void))completion; 92 | 93 | 94 | // Observe periodic time changes. 95 | // Must retain the result in order the |block| to be called. 96 | // If |queue| is NULL the updates will be deliverd on the main queue. 97 | // Use |interval| to specify how often the block should be called. 98 | // Inside the observer you can inspect the current time. 99 | // Pair with -removeTimeObserver:. 100 | - (id)addPeriodicTimeObserverForInterval:(CMTime)interval 101 | queue:(dispatch_queue_t)queue 102 | usingBlock:(void (^)(void))block; 103 | - (void)removeTimeObserver:(id)observer; 104 | 105 | // Set a layer to render the player's output 106 | - (void)setDisplayLayer:(VBDisplayLayer *)layer; 107 | 108 | @end 109 | 110 | 111 | 112 | /* 113 | VBDataPlayer 114 | 115 | A subclass of VBPlayer which exposes a buffer-like interface to let you feed the player with media 116 | segments. Current supported media coding is only MP4. 117 | 118 | Things to keep in mind: 119 | * You can manipulate the current time using -seekToTime:. By default it is set to 0. 120 | * The client should append only continuous data. 121 | * Calling -seekToTime:. will discard any buffered data so far so it is a client's responsibility 122 | to cache or acquire the media data again and feed it when appropriate. 123 | * Calling |duration| on this player will result in kCMTimeIndefinite. 124 | * You should again (as in VBPlayer) observer the |status| to know when the player is ready to play. 125 | 126 | */ 127 | 128 | 129 | /* 130 | VBDataCoding 131 | Describes the possible codings of the data you wish to append to the player. 132 | 133 | * VBDataCodingMP4 - Use for MP4 data with multiplexed content, e.g. AV initialization (+ AV data), 134 | * VBDataCodingMP4Audio - Use for MP4 audio only data, e.g. Audio initialization (+ Audio data) 135 | * VBDataCodingMP4Video - Use for MP4 video only data, e.g. Video initialization (+ Video data) 136 | 137 | */ 138 | typedef NS_ENUM(NSInteger, VBDataCoding) { 139 | VBDataCodingMP4, 140 | VBDataCodingMP4Audio, 141 | VBDataCodingMP4Video, 142 | }; 143 | 144 | 145 | @interface VBDataPlayer : VBPlayer 146 | 147 | // Designated initializer 148 | + (instancetype)createDataPlayer; 149 | 150 | // Enqueues media |data| with certain |coding| to be played at some point ahead of time. 151 | // NOTE: Each |data| MUST be the continuation of the data previously appended! This does NOT hold 152 | // if the append is made after a seek or if this is the first append. 153 | - (BOOL)appendData:(NSData *)data coding:(VBDataCoding)coding error:(NSError **)outError; 154 | 155 | // Returns the duration of the data segments haven't been requested for decoding yet. 156 | // This is the minimum between the audio and the video duration. 157 | - (CMTime)bufferedDuration; 158 | 159 | // Tells the player that there is no more data to be played and that it should finish when it has 160 | // played its last piece of data. 161 | // NOTE: Whenever -seekToTime: is issued this information is lost and you have to call this method 162 | // again when appropriate. 163 | - (void)endOfStream; 164 | @end 165 | 166 | // Constants: 167 | VIBLAST_EXPORT NSString *const VBErrorDomain; 168 | 169 | // VBPlayer initialization settings: 170 | VIBLAST_EXPORT NSString *const VBEnablePDNKey; // NSNumber (BOOL) 171 | 172 | // VBPlayerDelegate's methods as notifications: 173 | VIBLAST_EXPORT NSString *const VBPlayerDidEnterStallNotification; 174 | VIBLAST_EXPORT NSString *const VBPlayerDidExitStallNotification; 175 | VIBLAST_EXPORT NSString *const VBPlayerDidFinishPlayingNotification; 176 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // VBPlayerDemo 4 | // 5 | // Created by Ivan Ermolaev on 6/18/15. 6 | // Copyright (c) 2015 Viblast. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // VBPlayerDemo 4 | // 5 | // Created by Ivan Ermolaev on 6/18/15. 6 | // Copyright (c) 2015 Viblast. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "PlayerView.h" 11 | #import "VBPlayer.h" 12 | 13 | static NSUInteger kToolbarPlaybackButtonItemIndex = 1; 14 | static void *kPlayerStatusObserveContext = &kPlayerStatusObserveContext; 15 | 16 | @interface ViewController () 17 | 18 | @property (strong, nonatomic) VBPlayer *player; 19 | @property (weak, nonatomic) IBOutlet PlayerView *playerView; 20 | 21 | @property (weak, nonatomic) IBOutlet UIToolbar *toolbar; 22 | @property (strong, nonatomic) UIBarButtonItem *playButton; 23 | @property (strong, nonatomic) UIBarButtonItem *stopButton; 24 | 25 | @property (nonatomic, strong) UIActivityIndicatorView *loadingView; 26 | @end 27 | 28 | @implementation ViewController 29 | 30 | - (void)viewDidLoad { 31 | [super viewDidLoad]; 32 | 33 | // Set toolbar items 34 | NSMutableArray *items = [NSMutableArray new]; 35 | [items addObject:[[UIBarButtonItem alloc] 36 | initWithBarButtonSystemItem:(UIBarButtonSystemItemFlexibleSpace) 37 | target:nil action:nil] ]; 38 | self.playButton = [[UIBarButtonItem alloc] 39 | initWithBarButtonSystemItem:(UIBarButtonSystemItemPlay) 40 | target:self action:@selector(togglePlayback:)]; 41 | self.stopButton = [[UIBarButtonItem alloc] 42 | initWithBarButtonSystemItem:(UIBarButtonSystemItemPause) 43 | target:self action:@selector(togglePlayback:)]; 44 | [items addObject:self.playButton]; 45 | [items addObject:[[UIBarButtonItem alloc] 46 | initWithBarButtonSystemItem:(UIBarButtonSystemItemFlexibleSpace) 47 | target:nil action:nil]]; 48 | self.toolbar.items = items; 49 | 50 | // Init loading view 51 | self.loadingView = [[UIActivityIndicatorView alloc] 52 | initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleWhiteLarge)]; 53 | self.loadingView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin 54 | | UIViewAutoresizingFlexibleRightMargin 55 | | UIViewAutoresizingFlexibleBottomMargin 56 | | UIViewAutoresizingFlexibleTopMargin); 57 | } 58 | 59 | - (void)didReceiveMemoryWarning { 60 | [super didReceiveMemoryWarning]; 61 | // Dispose of any resources that can be recreated. 62 | } 63 | 64 | - (void)togglePlayback:(UIBarButtonItem *)sender { 65 | NSMutableArray *items = [self.toolbar.items mutableCopy]; 66 | if (sender == self.playButton) { 67 | [self start]; 68 | [items replaceObjectAtIndex:kToolbarPlaybackButtonItemIndex withObject:self.stopButton]; 69 | } else { 70 | [self stop]; 71 | [items replaceObjectAtIndex:kToolbarPlaybackButtonItemIndex withObject:self.playButton]; 72 | } 73 | self.toolbar.items = items; 74 | } 75 | 76 | - (void)start { 77 | [self setLoadingVisible:YES]; 78 | 79 | self.player = [[VBPlayer alloc] 80 | // Viblast: You can also try with your favourite HLS or DASH stream :) 81 | initWithCDN:@"http://cdn3.viblast.com/streams/dash/vod-bunny/SNE_DASH_CASE3B_SD_REVISED.mpd"]; 82 | self.player.delegate = self; 83 | 84 | [self.player addObserver:self 85 | forKeyPath:@"status" 86 | options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionInitial) 87 | context:kPlayerStatusObserveContext]; 88 | } 89 | 90 | - (void)stop { 91 | [self setLoadingVisible:NO]; 92 | [self.player removeObserver:self forKeyPath:@"status"]; 93 | 94 | self.player = nil; 95 | } 96 | 97 | - (void)setLoadingVisible:(BOOL)visible { 98 | if (!visible) { 99 | [self.loadingView stopAnimating]; 100 | [self.loadingView removeFromSuperview]; 101 | } else { 102 | self.loadingView.center = CGPointMake(CGRectGetWidth(self.playerView.bounds)/2.0, 103 | CGRectGetHeight(self.playerView.bounds)/2.0); 104 | [self.playerView addSubview:self.loadingView]; 105 | [self.playerView bringSubviewToFront:self.loadingView]; 106 | [self.loadingView startAnimating]; 107 | } 108 | } 109 | 110 | - (void)observeValueForKeyPath:(NSString *)keyPath 111 | ofObject:(id)object 112 | change:(NSDictionary *)change 113 | context:(void *)context { 114 | if (context == kPlayerStatusObserveContext) { 115 | switch (self.player.status) { 116 | case VBPlayerStatusUnknown: { 117 | break; 118 | } 119 | case VBPlayerStatusReadyToPlay: { 120 | [self setLoadingVisible:NO]; 121 | 122 | [self.player setDisplayLayer:[self.playerView displayLayer]]; 123 | [self.player play]; 124 | break; 125 | } 126 | case VBPlayerStatusFailed: { 127 | UIAlertView *alert = [[UIAlertView alloc] 128 | initWithTitle:@"Error" 129 | message:[self.player.error localizedDescription] 130 | delegate:nil 131 | cancelButtonTitle:@"OK" 132 | otherButtonTitles: nil]; 133 | [alert show]; 134 | 135 | // Restore playback interface 136 | NSMutableArray *items = [self.toolbar.items mutableCopy]; 137 | [items replaceObjectAtIndex:kToolbarPlaybackButtonItemIndex withObject:self.playButton]; 138 | self.toolbar.items = items; 139 | break; 140 | } 141 | } 142 | } 143 | } 144 | 145 | - (void)playerDidEnterStall:(VBPlayer *)player { 146 | [self setLoadingVisible:YES]; 147 | } 148 | 149 | - (void)playerDidExitStall:(VBPlayer *)player { 150 | [self setLoadingVisible:NO]; 151 | } 152 | 153 | @end 154 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // VBPlayerDemo 4 | // 5 | // Created by Ivan Ermolaev on 6/18/15. 6 | // Copyright (c) 2015 Viblast. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.viblast.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /VBPlayerDemo/VBPlayerDemoTests/VBPlayerDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // VBPlayerDemoTests.m 3 | // VBPlayerDemoTests 4 | // 5 | // Created by Ivan Ermolaev on 6/18/15. 6 | // Copyright (c) 2015 Viblast. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface VBPlayerDemoTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation VBPlayerDemoTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | This license does not apply to the VBPlayer.a library, which is proprietary and available through the [Viblast web page](http://viblast.com/). 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Viblast 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | --------------------------------------------------------------------------------