devhkh

국내에 AVPlayer라는 앱이 있어서 AVFoundation 안에 포함된 AVPlayer의 정보를 찾기가 상당히 쉽지가 않다.

그래서 일단 제목은 "AVPlayerLayer 사용" 으로 했다.


AVPLayer 사용은 일단 MPMoviePlayerController 와 크게 다르지 않다.

MPMoviePlayerController 객체 선언후 MPMoviePlayerViewController 에 넣은 후 사용하면 되는데 AVPlayer도 마찬가지 이다.


* AVPLayer 사용

#import <AVFoundation/AVFoundation.h>

- (void)loadView {       

[super loadView];


_url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"mp4"]];


UIView *playerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];

    playerView.backgroundColor = [UIColor blackColor];

    {

        AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:_url];

        AVPlayer *avPlayer = [AVPlayer playerWithPlayerItem:playerItem];

        {

            AVPlayerLayer *avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer: avPlayer];

            avPlayerLayer.frame = CGRectMake(0, 0, 320, 480);

            avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspect;

            [playerView.layer addSublayer:avPlayerLayer];

            [self.view addSubview:playerView];

        }

         avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone

        [[NSNotificationCenter defaultCenter] addObserver:self

                                                 selector:@selector(playerItemDidReachEnd:)

                                                     name:AVPlayerItemDidPlayToEndTimeNotification

                                                   object:[ avPlayer currentItem]];

    }

}




- (void)playerItemDidReachEnd:(NSNotification *)notification {

    NSLog(@"video end");

    

}


단순하게 생각해서 AVPlayerLayer 안에 AVPlayer 넣고 이 AVPlayerLayer를 뷰의 Layer에 넣어주면 끝이다.

그리고 마지막에 영상의 재생이 끝날때 노티 설정해주면 끝.




* 비디오 썸네일 만들기

참고자료 

1. 2010 WWDC의 AVFoundation

https://developer.apple.com/videos/wwdc/2010/ (로그인하면 꽁짜로 볼 수 있다.) 

Session 405 - Discovering AV Foundation

Session 407 - Editing Media with AV Foundation

Session 409 - Using the Camera with AV Foundation


2. http://www.subfurther.com/

http://www.subfurther.com/blog/category/avfoundation/

VTM_AVEditor, VTM_Player


우선 썸네일을 만드는게 단순히 한장만 필요한게 아니라 한 비디오의 여러장(수십장)의 썸네일이 필요했다.

왜냐하면 내 목적은 아래의 UI를 만드는게 목적이었기 때문이었다.


이 UI를 기본적으로 제공하지 않기 때문에 고생을 좀 했다.

일단 상단 네비게이션바 아래에 있는 썸네일 이미지를 만들고 UISlider를 투명으로 놓은다음 그 UISlider의 배경을 썸네일로

넣어주고 UISlider가 이동하는 점과 AVPlayer 와 싱크를 맞춰주면 될 것 같다.


우선 썸네일을 생성하기 위해 AVURLAsset에 재생하려는 동영상의 파일 URL을 넣는다.

- (id)init

{

    self = [super init];

    if (self) {


        _url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"mp4"]];

        _asset = [AVURLAsset URLAssetWithURL:_url options:nil];

        

        [self thumbCreate];

        

    }

    return self;

}


썸네일 생성

- (void)thumbCreate {

    

    NSMutableArray *imageArr = [[NSMutableArray alloc]init];

    

    _imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:_asset];

    

    // 썸네일 이미지 생성할때 4개의 이미지를 생성

    Float64 durationSeconds = CMTimeGetSeconds([_asset duration]);

    CMTime firstThird = CMTimeMakeWithSeconds(durationSeconds/3.0, 600);

    CMTime secondThird = CMTimeMakeWithSeconds(durationSeconds*2.0/3.0, 600);

    CMTime end = CMTimeMakeWithSeconds(durationSeconds, 600);

    

    NSArray *times = [NSArray arrayWithObjects:[NSValue valueWithCMTime:kCMTimeZero],

                      [NSValue valueWithCMTime:firstThird], [NSValue valueWithCMTime:secondThird],

                      [NSValue valueWithCMTime:end], nil];

    

    // Async 진행되는 썸네일 이미지 만드는 메소드

    [_imageGenerator generateCGImagesAsynchronouslyForTimes:times

                                          completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime 

                                                             actualTime,

                                                              AVAssetImageGeneratorResult result, NSError 

                                                              *error) {

                                              

                                              NSString *requestedTimeString = (__bridge NSString *) 

                                              CMTimeCopyDescription (NULL, requestedTime);


                                              NSString *actualTimeString = (__bridge NSString *) 

                                              CMTimeCopyDescription(NULL, actualTime);

                                              NSLog(@"Requested: %@; actual %@", requestedTimeString, 

                                              actualTimeString);

                                              

                                              // 이미지 배열에 비디오에서 추출한 이미지 넣기

                                              _imageGenerator.maximumSize = CGSizeMake(66, 44);

                                              [imageArr addObject:[UIImage imageWithCGImage:image]];

                                              

                                              

                                              // 썸네일 이미지 만드는게 성공될 경우 여기로 호출

                                              if (result == AVAssetImageGeneratorSucceeded) {

                                                  

                                                  UIImageView *sliderImageView = [[UIImageView alloc

                                                  initWithFrameCGRectMake(0, 0, 320, 44)];

                                                  

                                                  // 썸네일 이미지를 배열에 넣고 imageView 넣는다.

                                                  for (NSInteger i = 0;i<[imageArr count];i++){

                                                      

                                                      UIImageView *view = [[UIImageView allocinitWithFrame:         

                                                      CGRectMake(i*80, 0, 80, 44)];

                                                      [view setImage:[imageArr objectAtIndex:i]];

                                                      [sliderImageView addSubview:view];

                                                  }

                                                  [_sliderView addSubview:sliderImageView];

                                                  [_sliderView addSubview:_timeSlider];


                                                  

                                                  

                                              }

                                              

                                              if (result == AVAssetImageGeneratorFailed) {

                                                  NSLog(@"Failed with error: %@", [error  

                                                  localizedDescription]);

                                              }

                                              if (result == AVAssetImageGeneratorCancelled) {

                                                  NSLog(@"Canceled");

                                              }

                                              

                                          }];

    

}

무조건 4개의 이미지를 만드는데 이 때 내가 보려는 동영상의 총 시간을 구하고 그 시간을 4등분 해서 각각 0, firstThird, SecondThird, end 로 구분하여 그 4개의 이미지를 생성하도록 했다.


슬라이더 설정

    _sliderView = [[UIView alloc]initWithFrame:CGRectMake(0, 44, 320, 44)];

    [_sliderView setBackgroundColor:[UIColor clearColor]];


    {

        _timeSlider = [[UISlider alloc]initWithFrame:CGRectMake(0, 0, 320, 44)];

        [_timeSlider setThumbTintColor:[UIColor clearColor]];

        [_timeSlider setMaximumTrackImage:[UIImage imageNamed:@"slider.png"] forState:UIControlStateNormal]; 

        [_timeSlider setMinimumTrackImage:[UIImage imageNamed:@"slider.png"] forState:UIControlStateNormal]; 

        _timeSlider.value = 0;

        [_sliderView addSubview:_timeSlider];

    }

    [self.view addSubview:_sliderView];


// avPlayer 플레이타임과 slider 타임의 싱크를 맞추기 위한 타이머

    _sliderTimer = [NSTimer scheduledTimerWithTimeInterval:0.2

                                                    target:self

                                                  selector:@selector (updateSlider:)

                                                  userInfo:nil

                                                   repeats:YES];

슬라이더의 Maximum, Minimum의 트랙 이미지를 투명으로 놓고

그 뒤에 위에서 생성한 썸네일 이미지를 넣도록 한다. 


-(void) timeSliderValueChanged: (id) sender {

    CMTime newTime = CMTimeMakeWithSeconds(_timeSlider.value, 600);

[_avPlayer seekToTime: newTime];

//    NSLog (@"seeking to %f", CMTimeGetSeconds(newTime));

}


// AVPlayer Slider 싱크를 맞춰주는 메소드

- (void) updateSlider :(id) sender  {

    _timeSlider.value = CMTimeGetSeconds(_avPlayer.currentTime);    

}





애플에서 만든 비디오 플레이보다는 훨씬 못미치지만 일단 프로토타입으로 어느정도 느낌은 내 볼수 있었다. 

AVFoundation 도 그렇게 어렵지 않았고 나름대로 재미있었다.


VideoPlayer 앱을 만들어서 배포해볼까(?) 라는 생각도 잠깐 해 볼 수 있었다. 


소스코드 공개

VideoPlayer.zip



'iOS' 카테고리의 다른 글

하위뷰 모두 제거  (0) 2012.06.21
UITabBarController Custom  (0) 2012.04.16
앱 - 앱 간 자료 전송 방법 2가지  (0) 2012.04.03
iOS 전 기종(The new iPad 포함) 아이콘 사이즈 정의  (0) 2012.03.15
APNS 사용  (0) 2012.03.12