Использование AVMutableComposition iPhone

Я использую приведенный ниже код для последовательной потоковой передачи двух видео. Но он не показывает никакого видео в симуляторе, оно абсолютно пустое.

Кроме того, как я могу искать через эти два видео. Мол, если одно видео 2 минуты, а второе 3 минуты. Теперь мне нужно получить общее время этих видео и выполнить поиск по ним. Когда я передвигаю ползунок на 4 минуты, второе видео должно воспроизводиться со второй минуты и далее.

Является ли это возможным?

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    NSURL *url1 = [NSURL URLWithString:@"http://www.tools4movies.com/dvd_catalyst_profile_samples/Harold%20Kumar%203%20Christmas%20bionic.mp4"];
    NSURL *url2 = [NSURL URLWithString:@"http://www.tools4movies.com/dvd_catalyst_profile_samples/Harold%20Kumar%203%20Christmas%20tablet.mp4"];

    NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];

    AVMutableComposition *composition = [[AVMutableComposition alloc] init];

    asset1 = [[AVURLAsset alloc] initWithURL:url1 options:options];
    AVURLAsset * asset2 = [[AVURLAsset alloc]initWithURL:url2 options:options];

    CMTime insertionPoint = kCMTimeZero;
    NSError * error = nil;
    composition = [AVMutableComposition composition];

    if (![composition insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset1.duration) 
                              ofAsset:asset1 
                               atTime:insertionPoint 
                                error:&error]) 
    {
        NSLog(@"error: %@",error);
    }

    insertionPoint = CMTimeAdd(insertionPoint, asset1.duration);

    if (![composition insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset2.duration) 
                              ofAsset:asset2 
                               atTime:insertionPoint 
                                error:&error]) 
    {
        NSLog(@"error: %@",error);
    }

    AVPlayerItem * item = [[AVPlayerItem alloc] initWithAsset:composition];
    player = [AVPlayer playerWithPlayerItem:item];
    AVPlayerLayer * layer = [AVPlayerLayer playerLayerWithPlayer:player];

    [layer setFrame:CGRectMake(0, 0, 320, 480)];
    [[[self view] layer] addSublayer:layer];
    [player play];   
}

Может ли кто-нибудь сказать мне, что это за ошибка в моем коде?


person Omer Waqas Khan    schedule 30.04.2012    source источник
comment
Вы тестировали этот код на устройстве?   -  person Sam    schedule 08.05.2012
comment
См. ответ на этот вопрос: stackoverflow.com/questions/8318422/   -  person djromero    schedule 08.05.2012
comment
@Sam Нет, я не проверял это на реальном устройстве   -  person Omer Waqas Khan    schedule 08.05.2012
comment
@madmw, тогда есть ли другой способ реализовать описанный выше сценарий?   -  person Omer Waqas Khan    schedule 08.05.2012
comment
AVQueuePlayer? Два AV-плеера? Сначала скачивать файлы? Есть варианты. Вам нужно знать продолжительность каждого видео и сделать некоторые расчеты, прежде чем решить, какое видео воспроизводить и в какое время искать.   -  person djromero    schedule 08.05.2012
comment
Да, пробовал, но его воспроизведение не является плавным/непрерывным между видео, также сетевые файлы должны передаваться в потоковом режиме и не должны загружаться, а также должны быть доступны для поиска, как я определил выше.   -  person Omer Waqas Khan    schedule 08.05.2012
comment
Я думаю, что ошибка в том, как вы рассчитываете время. Это переменная insertPoint, которая кажется неправильной. Нужно брать длину композиции, а не длину вашего ассета. Посмотрите в моем ответе ниже, как рассчитать время. Я использую 600 как константу, так что тики очень точные.   -  person JackPearse    schedule 08.05.2012
comment
@madmw У меня есть другой способ решить эту проблему, я сделал несколько экземпляров AVPlayer, но теперь проблема, с которой я сталкиваюсь, заключается в том, что когда я приостанавливаю AVplayer1 и устанавливаю AVPlayerLayer на avplayer2 и играю, происходит рывок между этими двумя видео или представлением avplayerlayer отображается его фон. Как я могу удалить его? Чтобы следующее видео показывалось сразу, а фон просмотра avplayerlayer не отображался   -  person Omer Waqas Khan    schedule 11.05.2012


Ответы (1)


Симулятор НЕ УМЕЕТ отображать видео. Ни встроенный UIImagePickerController, ни какой-либо видеоконтроллер работать не будут. Он не реализован и в симуляторе iOS в основном отображается черным или красным цветом. Вы должны отлаживать цель iOS. Иногда отладка не работает должным образом. Вместо этого используйте NSLog(). Это всегда будет работать (т.е. если вы компилируете без отладочной информации, используя код «выпуска»)

искать можно с помощью плеера:

если mp ваш медиаплеер:

[mp pause];
CMTime position = mp.currentTime;

// maybe replace something
[mp replaceCurrentItemWithPlayerItem:[AVPlayerItem playerItemWithAsset:self.composition]];

[mp seekToTime:length];
[mp play];

сводка:
Редактировать: использовать состав и элемент проигрывателя
Поиск: использовать проигрыватель

Вот краткий формальный пример того, как это сделать (и уже безопасно для потоков):

AVMutableComposition *_composition = [AVMutableComposition composition];

// iterate though all files
// And build mutable composition
for (int i = 0; i < filesCount; i++) {

    AVURLAsset* sourceAsset = nil;

    NSURL* movieURL = [NSURL fileURLWithPath:[paths objectAtIndex:i]];
    sourceAsset = [AVURLAsset URLAssetWithURL:movieURL options:nil];

    // calculate time
    CMTimeRange editRange = CMTimeRangeMake(CMTimeMake(0, 600), sourceAsset.duration);

    NSError *editError;
    BOOL result = [_composition insertTimeRange:editRange
                                        ofAsset:sourceAsset
                                        atTime:_composition.duration
                                        error:&editError];

    dispatch_sync(dispatch_get_main_queue(), ^{

        // maybe you need a progress bar
        self.loaderBar.progress = (float) i / filesCount;
        [self.loaderBar setNeedsDisplay];
     });

}

// make the composition threadsafe if you need it later
self.composition = [[_composition copy] autorelease];

// Player wants mainthread?    
dispatch_sync(dispatch_get_main_queue(), ^{

    mp = [AVPlayer playerWithPlayerItem:[[[AVPlayerItem alloc] initWithAsset:self.composition] autorelease]];

    self.observer = [mp addPeriodicTimeObserverForInterval:CMTimeMake(60, 600) queue:nil usingBlock:^(CMTime time){

        // this is our callback block to set the progressbar
        if (mp.status == AVPlayerStatusReadyToPlay) {

            float actualTime = time.value / time.timescale;

            // avoid division by zero
            if (time.value > 0.) {

                CMTime length = mp.currentItem.asset.duration;
                float lengthTime = length.value / length.timescale;

                if (lengthTime) {

                    self.progressBar.value = actualTime / lengthTime;
                } else {

                        self.progressBar.value = 0.0f;    
                }
            }];
        });

        // the last task must be on mainthread again
        dispatch_sync(dispatch_get_main_queue(), ^{

            // create our playerLayer
            self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:mp];
            self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;  
            self.playerLayer.frame = [self view].layer.bounds;

            // insert into our view (make it visible)
            [[self view].layer insertSublayer:self.playerLayer atIndex:0];
        });

    // and now do the playback, maybe mp is global (self.mp)
    // this depends on your needs
    [mp play];
});

Надеюсь, это поможет.

person JackPearse    schedule 08.05.2012
comment
Итак, означает ли это, что приведенный выше сценарий последовательной потоковой передачи нескольких видео без перерыва и их правильный поиск возможен с помощью AVMutableComposition ? - person Omer Waqas Khan; 08.05.2012
comment
да. Но добавлять видео на лету непросто (могут быть небольшие перерывы, и сначала нужно поставить проигрыватель на паузу). Но если вы СНАЧАЛА сочиняете свои видео, а ПОТОМ воспроизводите их с помощью плеера, это будет похоже на одно непрерывное видео. Преимущество изменяемой композиции заключается в том, что вы можете объединять другие видео с вашей композицией. Это можно сделать с помощью цикла for или while. Вместе с MutableComposition вы свободны в редактировании. После этого просто оберните в playeritem-›player. Затем вы можете воспроизводить все без проблем. - person JackPearse; 08.05.2012
comment
Это также можно сделать с помощью AVQueuePlayer. Но AVQueuePlayer загружает следующее видео после завершения первого. Проигрыватель в очереди не будет вычислять общую длину видео. Это означает, что использование MutableComposition делает ОДНО видео из многих. Игрок в очереди воспроизводит «список воспроизведения». - person JackPearse; 08.05.2012
comment
И последнее, но не менее важное: помните о хранении AVMutableComposition в глобальной области (т. е. с использованием свойства). Изменяемая композиция НЕ является потокобезопасной и может привести к сбою или не отображаться в блоке или любом другом потоке. Если вы хотите сохранить свою композицию внутри своего класса, сначала преобразуйте ее в стандартную композицию. - person JackPearse; 08.05.2012
comment
Спасибо, позвольте мне проверить и вернуться :) - person Omer Waqas Khan; 08.05.2012
comment
Я пробовал, но это не потоковая передача, вы указали локальные файлы в коде, мне нужно передать сетевые файлы ... есть идеи? - person Omer Waqas Khan; 09.05.2012
comment
Я думаю, что потоковая передача напрямую с URL-адреса невозможна с активами, потому что видео должно быть доступно для расчета длины. Сначала вам нужно загрузить файлы, а затем собрать свою композицию. Видеоплеер может транслировать файлы http-lifestreaming и .ts. Но это, кажется, не то, что вы ищете. Попробуйте NSData* video = [NSData dataWithContentsOfURL: yourURL]; [видео writeToFile:yourFilename атомарно:YES]; чтобы скачать ваши видео. А затем играйте из своей песочницы, используя yourFilename. - person JackPearse; 11.05.2012