In diesem Thema finden Sie eine Sammlung von Codeausschnitten, die Sie bei der Entwicklung mit dem SDK als Referenz verwenden können. Ausführlichere Lösungen finden Sie in den iOS-Player-Beispielen.
Wenn Sie die Brightcove PlayerUI Steuerelemente verwenden, sind Sie startklar. Die AirPlay-Funktionalität ist sofort einsatzbereit und ermöglicht es Benutzern, Videos mit Apple TV auf High-Definition-Displays zu streamen.
Wenn Sie benutzerdefinierte Steuerelemente verwenden, können Sie die folgenden Schritte ausführen:
Ersetzen Sie Ihre Werte für Richtlinienschlüssel, Konto-ID und Video-ID. Wählen Sie in Ihrem Konto ein Video mit Textspuren aus.
Richten Sie die Player-Ansicht mit einem Standard-VOD-Layout ein:
// Set up our player view. Create with a standard VOD layout.
BCOVPUIPlayerView *playerView = [[BCOVPUIPlayerView alloc]
initWithPlaybackController:self.playbackController options:nil controlsView:
[BCOVPUIBasicControlView basicControlViewWithVODLayout] ];
// Set up our player view. Create with a standard VOD layout.
guard let playerView = BCOVPUIPlayerView(playbackController:
self.playbackController, options: options, controlsView:
BCOVPUIBasicControlView.withVODLayout()) else {
return
}
Der closedCaptionButton ist als a deklariert BCOVPUIButton, was eine Unterklasse von ist UIButton und drei zusätzliche Methoden zur Anpassung hinzufügt. Wann immer Sie BCOVPlayerUI-Steuerelemente anpassen, sollten Sie die nativen Player-APIs verwenden, wo immer sie verfügbar sind. Ihr benutzerdefinierter Code sollte ungefähr so aussehen:
// Customize the CC button.
BCOVPUIButton *ccButton = playerView.controlsView.closedCaptionButton;
ccButton.titleLabel.font = [UIFont systemFontOfSize:14.];
ccButton.primaryTitle = @"CC";
[ccButton showPrimaryTitle:YES];
if let ccButton = playerView.controlsView.closedCaptionButton {
ccButton.titleLabel?.font = UIFont.systemFont(ofSize: 14)
ccButton.primaryTitle = "CC"
ccButton.showPrimaryTitle(true)}
}
Anzeige von FairPlay-Inhalten auf einem externen Bildschirm
Wenn ein externes Display über einen AV-Adapter und ein HDMI-Kabel an ein iOS-Gerät angeschlossen ist, wird standardmäßig der iOS-Bildschirm gespiegelt. Ausgenommen hiervon ist die Verwendung von FairPlay-geschützten Videos, deren Spiegelung von Apple verhindert wird (WWDC 2015, Sitzung 502).
Um FairPlay-geschützte Videos anzuzeigen, legen Sie die AVPlayer-Eigenschaften fest, die über den Brightcove-Wiedergabe-Controller angezeigt werden, damit FairPlay-Videos auf einem externen Display wiedergegeben werden können. Das Video wird im Vollbildmodus abgespielt. Hier ist ein Beispiel für das Festlegen dieser Eigenschaften:
Wenn Sie den Brightcove-Player und die Katalogklasse verwenden, werden Videoanalysen automatisch erfasst und in Ihrem Video Cloud-Analysemodul angezeigt. Für zusätzliche Messwerte können Sie Ihrer App Google Analytics hinzufügen.
Gehen Sie wie folgt vor, um Google Analytics in Ihre App zu integrieren:
Hier ist eine Möglichkeit, wie Sie Google Analytics verwenden können, um die Videowiedergabe mit dem Firebase SDK von Google zu verfolgen:
// This snippet shows one way to track video playback
// using the Firebase SDK from Google Analytics with
// the lifecycle event playback controller delegate method.
- (void)playbackController:(id<BCOVPlaybackController>)controller playbackSession:(id<BCOVPlaybackSession>)session didReceiveLifecycleEvent:(BCOVPlaybackSessionLifecycleEvent *)lifecycleEvent
{
// Common parameters
NSString *video_name = session.video.properties[kBCOVVideoPropertyKeyName];
NSString *video_ID = session.video.properties[kBCOVVideoPropertyKeyId];
// Session is ready to play
if ([kBCOVPlaybackSessionLifecycleEventReady isEqualToString:lifecycleEvent.eventType])
{
[FIRAnalytics logEventWithName:@"bcov_video_ready"
parameters:@{
@"bcov_video_name": video_name,
@"bcov_video_id": video_ID
}];
}
// Session encountered an error
if ([kBCOVPlaybackSessionLifecycleEventError isEqualToString:lifecycleEvent.eventType])
{
NSError *error = lifecycleEvent.properties[kBCOVPlaybackSessionEventKeyError];
int error_code = error.code;
[FIRAnalytics logEventWithName:@"bcov_video_playback_error"
parameters:@{
@"bcov_video_name": video_name,
@"bcov_video_id": video_ID,
@"bcov_video_error_code": @(error_code)
}];
}
// Session has completed
if ([kBCOVPlaybackSessionLifecycleEventTerminate isEqualToString:lifecycleEvent.eventType])
{
[FIRAnalytics logEventWithName:@"bcov_video_terminate"
parameters:@{
@"bcov_video_name": video_name,
@"bcov_video_id": video_ID
}];
}
}
// This snippet shows one way to track video playback
// using the Firebase SDK from Google Analytics with
// the lifecycle event playback controller delegate method.
func playbackController(_ controller: BCOVPlaybackController!, playbackSession session: BCOVPlaybackSession!, didReceive lifecycleEvent: BCOVPlaybackSessionLifecycleEvent!) {
// Common parameters
let video_name = session.video.properties[kBCOVVideoPropertyKeyName]
let video_id = session.video.properties[kBCOVVideoPropertyKeyId]
// Session is ready to play
if (lifecycleEvent.eventType == kBCOVPlaybackSessionLifecycleEventReady) {
if let video_name = video_name as? String, let video_id = video_id as? String {
Analytics.logEvent("bcov_video_ready", parameters: [
"bcov_video_name" : video_name,
"bcov_video_id" : video_id
])
}
}
// Session encountered an error
if (lifecycleEvent.eventType == kBCOVPlaybackSessionLifecycleEventError) {
if let error = lifecycleEvent.properties[kBCOVPlaybackSessionEventKeyError] as? NSError {
let error_code = error.code
if let video_name = video_name as? String, let video_id = video_id as? String {
Analytics.logEvent("bcov_video_playback_error", parameters: [
"bcov_video_name" : video_name,
"bcov_video_id" : video_id,
"bcov_video_error_code" : error_code
])
}
}
}
// Session has completed
if (lifecycleEvent.eventType == kBCOVPlaybackSessionLifecycleEventTerminate) {
if let video_name = video_name as? String, let video_id = video_id as? String {
Analytics.logEvent("bcov_video_terminate", parameters: [
"bcov_video_name" : video_name,
"bcov_video_id" : video_id
])
}
}
}
Begrenzung der Bitrate
Sie können nicht steuern, welche Quelle (Wiedergabeversion) im HLS-Manifest von der ausgewählt wird AVPlayer , aber Sie können eine Bitraten-Obergrenze für die Wiedergabe festlegen. Dadurch wird verhindert, dass der Player Quellen (Wiedergaben) mit einer Bitrate über der angegebenen Bitrate verwendet.
Stellen Sie die preferredPeakBitRate bis zum gewünschten Grenzwert in Bits pro Sekunde des Netzwerkbandbreitenverbrauchs für den gegebenen AVPlayerItem .
In einigen Fällen möchten Sie möglicherweise, dass ein Video automatisch wiedergegeben wird. Dazu können Sie das Lebenszyklusereignis "Ende des Videos" abrufen, zum Anfang suchen und erneut abspielen.
Dieser Code geht davon aus, dass Sie den Delegat des PlaybackControllers mit dieser Methode auf das Objekt gesetzt haben:
func playbackController(_ controller: BCOVPlaybackController!, playbackSession session: BCOVPlaybackSession!, didReceive lifecycleEvent: BCOVPlaybackSessionLifecycleEvent!) {
if (lifecycleEvent.eventType == kBCOVPlaybackSessionLifecycleEventEnd) {
controller.seek(to: CMTime.zero) { (finished: Bool) in
if (finished) {
controller.play()
}
}
}
}
Verwalten von Videos in einer Playlist
Eine Möglichkeit, eine Wiedergabeliste mit Videos zu verwalten, besteht darin, die Videoobjekte in einer Tabelle zu speichern. Wenn der Benutzer ein Video aus der Tabelle auswählt, enthält die Tabellenzeile das Videoobjekt.
func retrievePlaylist() {
refreshControl.beginRefreshing()
let playbackServiceRequestFactory = BCOVPlaybackServiceRequestFactory(accountId: kDynamicDeliveryAccountID, policyKey: kDynamicDeliveryPolicyKey)
let playbackService = BCOVPlaybackService(requestFactory: playbackServiceRequestFactory)
playbackService?.findPlaylist(withPlaylistID: kDynamicDeliveryPlaylistRefID, parameters: nil, completion: { [weak self] (playlist: BCOVPlaylist?, jsonResponse: [AnyHashable:Any]?, error: Error?) in
guard let strongSelf = self else {
return
}
strongSelf.refreshControl.endRefreshing()
if let playlist = playlist {
strongSelf.currentVideos = playlist.videos
strongSelf.currentPlaylistTitle = playlist.properties["name"] as? String ?? ""
strongSelf.currentPlaylistDescription = playlist.properties["description"] as? String ?? ""
print("Retrieved playlist containing \(playlist.videos.count) videos")
strongSelf.usePlaylist(playlist)
} else {
print("No playlist for ID \(kDynamicDeliveryPlaylistRefID) was found.");
}
})
}
Initialisieren Sie die Container, die Informationen zu den Videos in der aktuellen Playlist speichern, neu.
Wenn die Tabellenansicht ausgewählt ist, wird der Index der Zeile verwendet, um eine neue videoDictionary. Als nächstes fragen Sie das Wörterbuch nach dem Video. Wenn das Video nicht null ist, laden Sie das Video in die playbackController.
// Play the video in this row when selected
- (IBAction)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
NSDictionary *videoDictionary = self.videosTableViewData[ (int)indexPath.row ];
BCOVVideo *video = videoDictionary[@"video"];
if (video != nil)
{
[self.playbackController setVideos:@[ video ]];
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let videosTableViewData = videosTableViewData,
let videoDictionary = videosTableViewData[indexPath.row] as?
[AnyHashable:Any], let video = videoDictionary["video"] as? BCOVVideo else {
return
}
playbackController.setVideos([video] as NSFastEnumeration)
}
Um mit Playlists zu arbeiten, können Sie die Playlist in einem anderen Objekt wie einer Tabelle speichern. Basierend auf der Benutzerinteraktion können Sie durch die Indizes des Objekts navigieren und das entsprechende Video auswählen.
Medienfortschrittswerte
Während der Medienwiedergabe können die der Player SDK-Fortschrittsdelegatenmethode gemeldeten Werte einen Anfangswert von negativ unendlich und einen Endwert von positiv unendlich umfassen. Diese Werte werden bei der Verarbeitung von Pre-Roll- und Post-Roll-Anzeigen verwendet.
Wenn diese Werte für Sie nicht wichtig sind oder Ihre eigene Fortschrittsverfolgung stören, können sie mit einer bedingten Anweisung wie dieser einfach ignoriert werden:
- (void)playbackController:(id<BCOVPlaybackController>)controller playbackSession:(id<BCOVPlaybackSession>)session didProgressTo:(NSTimeInterval)progress
{
if (progress < 0.0 || progress >= INFINITY)
{
return;
}
// Your code here
}
func playbackController(_ controller: BCOVPlaybackController!, playbackSession session: BCOVPlaybackSession!, didProgressTo progress: TimeInterval) {
if (progress < 0.0 || progress >= Double.infinity) {
return;
}
// Your code here
}
Sie können die Untertitel jederzeit während der Wiedergabe einstellen, nach dem Ready Veranstaltung eingegangen ist. Dazu können Sie die BCOVPlaybackControllerDelegate.
Hier ist ein Beispiel für die Einstellung der Untertitelsprache auf Spanisch:
let params = [
"limit": 6,
"offset": 9
]
playbackService?.findPlaylist(withPlaylistID: playlistRefID, parameters: params, completion: { (playlist: BCOVPlaylist?, jsonResponse: [AnyHashable:Any]?, error: Error?) in
// Your code here
})
Programmgesteuertes Hinzufügen von Cue-Punkten
Kunden von Video Cloud können einem Video mithilfe von Video Cloud Studio Cue-Punkte hinzufügen, wie in der Hinzufügen von Cue-Punkten zu Videos dokumentieren.
Sie können Ihrem Video auch programmgesteuert Cue-Points hinzufügen. Der folgende Code fügt dem von der Playback API zurückgegebenen Video vierteljährliche Cue-Points hinzu:
// programmatically add cue points to a video
- (void)requestContentFromPlaybackService
{
[self.service findVideoWithVideoID:kViewControllerVideoID parameters:nil completion:^(BCOVVideo *video, NSDictionary *jsonResponse, NSError *error) {
if (video)
{
// Get the video duration from the properties dictionary
NSNumber *durationNumber = video.properties[@"duration"]; // milliseconds
float duration = durationNumber.floatValue / 1000.0; // convert to seconds
video = [video update:^(id<BCOVMutableVideo> mutableVideo)
{
// Add quarterly interval cue points of your own type
BCOVCuePoint *cp1 = [[BCOVCuePoint alloc] initWithType:@"your cue point type" position:CMTimeMake(duration * 250, 1000)];
BCOVCuePoint *cp2 = [[BCOVCuePoint alloc] initWithType:@"your cue point type" position:CMTimeMake(duration * 500, 1000)];
BCOVCuePoint *cp3 = [[BCOVCuePoint alloc] initWithType:@"your cue point type" position:CMTimeMake(duration * 750, 1000)];
BCOVCuePoint *cp4 = [[BCOVCuePoint alloc] initWithType:@"your cue point type" position:CMTimeMake(duration * 1000, 1000)];
// Create new cue point collection using existing cue points and new cue points
NSMutableArray *newCuePoints = [[NSMutableArray alloc] initWithArray:mutableVideo.cuePoints.array];
[newCuePoints addObject:cp1];
[newCuePoints addObject:cp2];
[newCuePoints addObject:cp3];
[newCuePoints addObject:cp4];
mutableVideo.cuePoints = [[BCOVCuePointCollection alloc] initWithArray:newCuePoints];
}];
[self.playbackController setVideos:@[ video ]];
}
else
{
NSLog(@"ViewController Debug - Error retrieving video: `%@`", error);
}
}];
}
// programmatically add cue points to a video
func requestContentFromPlaybackService() {
playbackService?.findVideo(withVideoID: kViewControllerVideoID, parameters: nil)
{ [weak self] (video: BCOVVideo?, jsonResponse: [AnyHashable: Any]?, error: Error?) -> Void in
if let error = error {
print("ViewController Debug - Error retrieving video: `\(error.localizedDescription)`")
}
if let video = video {
// Get the video duration from the properties dictionary
guard let durationNumber = video.properties["duration"] as? NSNumber else {
return
}
let duration = durationNumber.floatValue / 1000.0; // convert to seconds
let updatedVideo = video.update({ (mutableVideo: BCOVMutableVideo?) in
guard let mutableVideo = mutableVideo else {
return
}
// Add quarterly interval cue points of your own type
let cp1Position = CMTimeMake(value: Int64(duration * 250), timescale: 1000)
let cp1 = BCOVCuePoint(type: "your cue point type", position: cp1Position)!
let cp2Position = CMTimeMake(value: Int64(duration * 500), timescale: 1000)
let cp2 = BCOVCuePoint(type: "your cue point type", position: cp2Position)!
let cp3Position = CMTimeMake(value: Int64(duration * 750), timescale: 1000)
let cp3 = BCOVCuePoint(type: "your cue point type", position: cp3Position)!
let cp4Position = CMTimeMake(value: Int64(duration * 1000), timescale: 1000)
let cp4 = BCOVCuePoint(type: "your cue point type", position: cp4Position)!
// Create new cue point collection using existing cue points and new cue points
var newCuePoints = [BCOVCuePoint]()
newCuePoints.append(cp1)
newCuePoints.append(cp2)
newCuePoints.append(cp3)
newCuePoints.append(cp4)
mutableVideo.cuePoints = BCOVCuePointCollection(array: newCuePoints)
})
self?.playbackController.setVideos([updatedVideo] as NSFastEnumeration)
}
}
}
Beachten Sie, dass der Wert von your cue point type kann ein beliebiger String-Wert sein, solange Sie keinen der iOS-Plugins. Einzelheiten finden Sie im BCOVCuePoint-Protokollreferenz dokumentieren.
Wenn Sie Cue-Points mit dem IMA-Plugin verwenden, erfahren Sie mehr darüber im VAST- und VMAP-/serverseitige Anzeigenregeln Abschnitt des IMA-Plug-ins für das Native SDK für iOS-Notizen. Die IMA-Beispiel-App zeigt Ihnen den für IMA-Anzeigen-Cue-Points erforderlichen Wert an.
Der folgende Code lauscht auf Ihre Cue-Punkte und zeigt eine Meldung an:
// listen for cue points and display them
-(void)playbackController:(id<BCOVPlaybackController>)controller playbackSession:(id<BCOVPlaybackSession>)session didPassCuePoints:(NSDictionary *)cuePointInfo
{
BCOVCuePointCollection *cpc = cuePointInfo[@"kBCOVPlaybackSessionEventKeyCuePoints"];
for (BCOVCuePoint *cp in cpc.array)
{
if ([cp.type isEqualToString:@"your cue point type"])
{
NSLog(@"Found your cue point at %f", CMTimeGetSeconds(cp.position));
}
}
}
// listen for cue points and display them
func playbackController(_ controller: BCOVPlaybackController!, playbackSession session: BCOVPlaybackSession!, didPassCuePoints cuePointInfo: [AnyHashable : Any]!) {
if let cpc = cuePointInfo[kBCOVPlaybackSessionEventKeyCuePoints] as? BCOVCuePointCollection {
for cp in cpc.array() {
if let cp = cp as? BCOVCuePoint {
if (cp.type == "your cue point type") {
print("Found your cue point at \(CMTimeGetSeconds(cp.position))")
}
}
}
}
}
Verweise
Weitere Informationen finden Sie in den folgenden Punkten:
Es kann Fälle geben, in denen Sie den Player und die Ansicht entfernen möchten.
Wenn Sie die Zuweisung des View-Controllers aufheben, der Eigentümer eines ist, BCOVPlaybackController wird auch die Zuordnung des Playback-Controllers aufgehoben. Entfernen Sie dazu die Player-Ansicht aus ihrer Übersicht und setzen Sie ihren Wiedergabe-Controller-Zeiger auf nil.
Die Audiositzung behandelt das Audioverhalten auf App-Ebene. Sie können aus mehreren Audiositzungskategorien und -einstellungen wählen, um das Audioverhalten Ihrer App anzupassen.
Wählen Sie die beste Audiositzungskategorie für Ihre App. Weitere Informationen finden Sie in der Dokumentation von Apple:
Für unser Basismuster verwenden wir AVAudioSessionCategoryPlayback. Dies spielt auch dann Audio ab, wenn der Bildschirm gesperrt ist und der Schalter Klingeln/Stumm auf lautlos eingestellt ist. Der Einfachheit halber haben wir den Code dafür im App Delegate hinterlegt.
var categoryError :NSError?
var success: Bool
do {
try AVAudioSession.sharedInstance().setCategory(.playback)
success = true
} catch let error as NSError {
categoryError = error
success = false
}
if !success {
// Handle error
}
Mit anderem Audio mischen
Möglicherweise möchten Sie zulassen, dass Audio von anderen Apps gehört wird, wenn das Audio in Ihrer App stummgeschaltet ist. Dazu können Sie die AVAudioSession im Ansichtscontroller, der Zugriff auf Ihr aktuelles hat AVPlayer.
Einzelheiten finden Sie im mixWithOthers Kategorie Option.
- (void)setUpAudioSession
{
NSError *categoryError = nil;
BOOL success;
// If the player is muted, then allow mixing.
// Ensure other apps can have their background audio active when this app is in foreground
if (self.currentPlayer.isMuted)
{
success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&categoryError];
}
else
{
success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:0 error:&categoryError];
}
if (!success)
{
NSLog(@"AppDelegate Debug - Error setting AVAudioSession category. Because of this, there may be no sound. `%@`", categoryError);
}
}
func setUpAudioSession() {
var categoryError :NSError?
var success: Bool
do {
if let currentPlayer = currentPlayer {
// If the player is muted, then allow mixing.
// Ensure other apps can have their background audio active when this app is in foreground
if currentPlayer.isMuted {
try AVAudioSession.sharedInstance().setCategory(.playback, options: .mixWithOthers)
} else {
try AVAudioSession.sharedInstance().setCategory(.playback, options: AVAudioSession.CategoryOptions(rawValue: 0))
}
} else {
try AVAudioSession.sharedInstance().setCategory(.playback, options: AVAudioSession.CategoryOptions(rawValue: 0))
}
success = true
} catch let error as NSError {
categoryError = error
success = false
}
if !success {
print("AppDelegate Debug - Error setting AVAudioSession category. Because of this, there may be no sound. \(categoryError!)")
}
}
Einstellen der Wiedergaberate
Um die Wiedergaberate zu steuern, können Sie die rate Eigentum auf der AVPlayer Klasse in der Sitzung ausgesetzt.
Standardmäßig kann die Abspielrate nur in regelmäßigen Abständen (0,50, 0,67, 1,0, 1,25, 1,50 und 2,0) eingestellt werden. Durch die Einstellung des AudioTimePitch-Algorithmus können Sie detailliertere Ratenwerte verwenden (z. B. 1,7). Weitere Details finden Sie hier Stackoverflow-Diskussion.
func playbackController(_ controller: BCOVPlaybackController!, playbackSession session: BCOVPlaybackSession!, didReceive lifecycleEvent: BCOVPlaybackSessionLifecycleEvent!) {
if (lifecycleEvent.eventType == kBCOVPlaybackSessionLifecycleEventReady) {
let seconds = CMTimeGetSeconds(session.player.currentTime())
print("kBCOVPlaybackSessionLifecycleEventReady at time \(seconds)")
let avPlayerItem = session.player.currentItem
avPlayerItem?.audioTimePitchAlgorithm = AVAudioTimePitchAlgorithm.varispeed
session.player.rate = 1.7
}
}
Einstellen des VR-Brillenmodus für 360°-Videos
Beim Abspielen eines 360°-Videos können Benutzer die Schaltfläche Video 360 in der Steuerleiste auswählen, um in den VR-Brillenmodus zu wechseln. Sie können dies auch programmgesteuert tun, bevor die Wiedergabe beginnt. Sie können dies tun, indem Sie die BCOVPlaybackController Protokolle viewProjection Eigentum wie folgt:
Wenn Sie ein Video im Hochformat abspielen, bemerken Sie möglicherweise einen schwarzen Rand oberhalb und unterhalb des Players. Die Player-Ansicht hat die Größe des Bildschirms, aber das Video nimmt nur einen kleinen Teil der Mitte der Player-Ansicht ein. Die sichtbaren Teile um das Video herum sind der Hintergrund der Player-Ebene.
Das ist normal AVPlayer Verhalten. Es verkleinert Ihr Video, damit es in die Player-Ebene passt, und der Rest ist der Hintergrund der Player-Ebene.
Sie können den Hintergrund der Player-Ebene mit dem folgenden Code ändern: