Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Скроллер для видео и осознавание представления времени в Objective-C

Anna | 2.07.2014 | нет комментариев

В этой статье я хочу поделиться своим навыком работы с видео в одном из своих последних планов для iOS. Не буду углубляться в подробности, лишь опишу одну из задач, которую не удалось решить с поддержкой поиска по прогру, гитхабу и остальному интернету. Задача состояла в дальнейшем: сделать скроллер для видео, да не примитивный, а Дабы был как в стандартной галерее iOS 7.

Т.к. для воспроизведения видео применялся типовой компонент MPMoviePlayerViewController, а он поддерживает перемотку видео в всякую позицию, то основная задача состояла в том, Дабы получить из видео картинки через равные интервалы времени и положить их на UIView, таким образом, Дабы они оказывались приблизительно под нынешней позицией в видео. Забегая немножко вперед хочу сказать, что по ходу дела пришлось решить еще пару задач: тормоза при генерации картинок из видео на iPad, и различная длина слайдера в вертикальной и горизонтальной ориентации устройства.

Выходит, для начала нам необходимо осознать, каким образом дозволено получить картинки из видео. И в этом нам поможет AVAssetImageGenerator. Данный класс намеренно сделан для того, Дабы получать картинки с произвольного места видео. Будем считать, что наш тестовый файл располагается в домашней папке и именуется test.mov:

NSString *filepath = [NSString stringWithFormat:@"%@/Documents/test.mov", NSHomeDirectory()];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];

Пример применения AVAssetImageGenerator:

// create asset
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:fileURL options:nil];
// create generator
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
// time for preview
CMTime time = CMTimeMake(1, 2);
// get image ref
CGImageRef imageRef = [generator copyCGImageAtTime:time actualTime:nil error:nil];
// create image
UIImage *image = [UIImage imageWithCGImage:oneRef];

Прежде я не сталкивался с CMTime, и для того, Дабы поделить время на равные интервалы, не нехорошо было бы осознать, что представляет из себя эта конструкция данных.

CMTimeMake принимает на вход два довода: value и timescale. Я ознакомился с официальной документацией и хочу объяснить примитивными словами тем, кто не в курсе, что это за доводы.
Во-первых, timescale, это число, на которое будет поделена всякая секунда. С поддержкой этого довода задается точность, с которой мы можем указать необходимый момент времени. Скажем, если timescaleуказать равным 10, то дозволено получить 1/10 часть секунды.
В свою очередь value указывает на надобную часть времени, с учетом timescale. Скажем, мы имеем видео длиной 60 секунд, timescale равен 10, Дабы получить 30 секунду, value должно быть равно 300.
Дабы еще отменнее осознать представление времени с поддержкой CMTime, скажу что число секунд в нынешний момент видео равняется value/timescale. Из предыдущего примера 30 секунда равна 300/10. Если понимать перевод времени из секунд в CMTime и обратно, то дальше ни каких задач с этой конструкцией не должно появиться.

Идем дальше, сейчас нам необходимо узнать длину видео. Это достаточно легко, сделанный ранее объектasset теснее имеет необходимое нам качество.

CMTime duration = asset.duration;

Отлично, у нас есть все для того, Дабы нарезать видео на кучу картинок. Сейчас встает вопрос, сколько их необходимо для портретной и альбомной ориентации устройств. Первое на что необходимо обратить внимание, это высота скроллера в стандартной галерее iPhone и iPad. Да, она примерно идентичная, различается только ширина. Не сложно додуматься, что число картинок равно ширине слайдера поделенной на ширину одной картинки. Я решил, что сделаю квадратные картинки 29х29 точек. Здесь есть один тонкий момент, в генераторе размер картинок необходимо указывать в пикселях, следственно там будет значение 58х58.

generator.maximumSize = CGSizeMake(58.0, 58.0);

Для простоты и комфорта, число картинок я указал в дефайнах

#define iPad (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define ThumbnailsCountInPortrait (iPad ? 25 : 10)
#define ThumbnailsCountInLandscape (iPad ? 38 : 15)

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

NSMutableArray *portraitThumbnails = [NSMutableArray array];
NSMutableArray *landscapeThumbnails = [NSMutableArray array];

// generate portrait thumbnails
for (NSInteger i=0; i < ThumbnailsCountInPortrait; i  ) {
    CMTime time = CMTimeMake(duration.value/ThumbnailsCountInPortrait*i, duration.timescale);
    CGImageRef oneRef = [generator copyCGImageAtTime:time actualTime:nil error:nil];
    [portraitThumbnails addObject:[UIImage imageWithCGImage:oneRef]];
}

// generate landscape thumbnails
for (NSInteger i=0; i < ThumbnailsCountInLandscape; i  ) {
    CMTime time = CMTimeMake(duration.value/ThumbnailsCountInLandscape*i, duration.timescale);
    CGImageRef oneRef = [generator copyCGImageAtTime:time actualTime:nil error:nil];
    [landscapeThumbnails addObject:[UIImage imageWithCGImage:oneRef]];
}

Не думаю, что здесь будет целесообразно рассказывать как размещать полученные картинки в ряд на UIView, и тем больше как их брать из различных массивов при различной ориентации устройства. В этом на самом деле нет ничего трудного и все это дозволено увидеть в готовом примере.

На последок я хотел бы рассказать про способ решения задачи с тормозами. Т.к. слайдер инициализируется при загрузке контроллера, то имеет место быть задержка анимации перехода к нынешнему контроллеру. Самое примитивное решение — dispatch_async. Эта весьма пригодная штука разрешает исполнить содержимое блока асин­хрон­но в фоне, не притормаживая приложение.

Пример применения:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    [videoScroller initializeThumbnails];

    dispatch_sync(dispatch_get_main_queue(), ^{
       [videoScroller loadThumbnails];
    });
});

Думаю ясно, что videoScroller это наш объект, тот, что инициализирует в фоне свои данные, а потом загружает их.

Рабочий пример дозволено взять здесь: https://github.com/iBlacksus/BLVideoScroller

P.S.
Это моя первая статья, если она окажется увлекательной для програжителей, то я готов и дальше делиться своим навыком, в частности планирую написание статьи о создании слайдера, разрешающего предпочесть цвет текста с произвольной палитры, которая представляет из себя легко картинку.

 

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB