정책 키, 계정 ID 및 비디오 ID의 값을 바꿉니다. 계정에서 텍스트 트랙이있는 비디오를 선택하십시오.
표준 VOD 레이아웃으로 플레이어 보기를 설정합니다.
// 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
}
closedCaptionButton는 의BCOVPUIButton서브클래스인 a로UIButton선언되며 사용자 지정을 위한 세 가지 추가 메서드를 추가합니다. BCOVPlayerUI 컨트롤을 사용자 정의 할 때마다 사용 가능한 모든 곳에서 Native Player API를 사용해야합니다. 사용자 정의 코드는 다음과 유사해야합니다.
// 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)}
}
외부 화면에 FairPlay 콘텐츠 표시
AV 어댑터와 HDMI 케이블을 사용하여 외부 디스플레이가 iOS 장치에 연결되어있는 경우 기본 동작은 iOS 화면을 미러링하는 것입니다. 단, 페어플레이로 보호된 비디오를 사용하는 경우는 예외이며, Apple은 이를 미러링하지 못하도록 차단합니다 ( WWDC 2015, 세션 502 ).
FairPlay로 보호 된 비디오를 표시하려면 Brightcove 재생 컨트롤러를 통해 노출되는 AVPlayer 속성을 설정하여 FairPlay 비디오를 외부 디스플레이에서 재생할 수 있도록합니다. 비디오가 전체 화면 모드로 재생됩니다. 다음은 이러한 속성을 설정하는 예입니다.
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.");
}
})
}
현재 재생 목록의 비디오와 관련된 정보를 저장하는 컨테이너를 다시 초기화합니다.
테이블 보기를 선택하면 행의 인덱스가 새 테이블을 만드는 데 사용됩니다videoDictionary . 다음으로 사전에 비디오를 요청하십시오. 비디오가 null이 아닌 경우 비디오를 에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)
}
재생 목록으로 작업하려면 테이블과 같은 다른 개체에 재생 목록을 저장할 수 있습니다. 사용자 상호 작용을 기반으로 개체의 인덱스를 탐색하고 적절한 비디오를 선택할 수 있습니다.
미디어 진행 값
미디어 재생 중에 Player SDK 진행 델리게이트 메서드에보고되는 값에는 초기 값인 음의 무한대와 최종 값의 양의 무한대가 포함될 수 있습니다. 이 값은 프리 롤 및 포스트 롤 광고를 처리 할 때 사용됩니다.
이러한 값이 중요하지 않거나 진행 상황 추적을 방해하는 경우 다음과 같은 조건문을 사용하여 쉽게 무시할 수 있습니다.
- (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
}
let params = [
"limit": 6,
"offset": 9
]
playbackService?.findPlaylist(withPlaylistID: playlistRefID, parameters: params, completion: { (playlist: BCOVPlaylist?, jsonResponse: [AnyHashable:Any]?, error: Error?) in
// Your code here
})
프로그래밍 방식으로 큐 포인트 추가
Video Cloud 고객은 Video Cloud Studio를 사용하여 비디오에 큐 포인트를 추가할 수 있습니다. 비디오에 큐 포인트 추가문서.
프로그래밍 방식으로 비디오에 큐 포인트를 추가 할 수도 있습니다. 아래 코드는 Playback API에서 반환 된 동영상에 분기 별 간격 큐 포인트를 추가합니다.
// 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)
}
}
}
의 값에 유의하십시오. your cue point type 다음 중 어떤 것도 사용하지 않는 한 원하는 모든 문자열 값이 될 수 있습니다. iOS 플러그인 . 자세한 내용은 BCV CuePoint 프로토콜 참조문서를 참조하십시오.
// 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))")
}
}
}
}
}
- (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!)")
}
}
재생 속도 설정
재생 속도를 제어하려면 다음을 설정할 수 있습니다. rate 재산AVPlayer 세션에 노출된 클래스.
기본적으로 재생 속도는 일정한 간격 (0.50, 0.67, 1.0, 1.25, 1.50 및 2.0)으로 만 설정할 수 있습니다. AudioTimePitch 알고리즘을설정하면 더 세분화된 속도 값 (예: 1.7) 을 사용할 수 있습니다. 자세한 내용은 이스택 오버플로 토론을 참조하십시오 .
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
}
}
360° 비디오에 대한 VR 고글 모드 설정
360° 비디오를 재생할 때 사용자는 컨트롤 막대에서 Video 360 버튼을 선택하여 VR 고글 모드로 전환할 수 있습니다. 재생이 시작되기 전에 프로그래밍 방식으로이 작업을 수행 할 수도 있습니다. 다음과 같이BCOVPlaybackController 프로토콜의viewProjection 속성을 업데이트하여 이 작업을 수행할 수 있습니다.