Время и представления носителей

Основанные на времени аудиовизуальные данные, такие как файл ролика или видеопоток, представлены в платформе Основы AV AVAsset. Его структура диктует большую часть работ платформы. Несколько низкоуровневых структур данных, что использование Основы AV для представления времени и носителей, таких как демонстрационные буферы прибывает из Базовой платформы Носителей.

Представление активов

AVAsset базовый класс в платформе Основы AV. Это обеспечивает независимую от формата абстракцию основанных на времени аудиовизуальных данных, таких как файл ролика или видеопоток. Во многих случаях Вы работаете с одним из его подклассов: Вы используете подклассы состава при создании новых активов (см. Редактирование), и Вы используете AVURLAsset создать новый экземпляр актива из носителей в данном URL (включая активы от платформы MPMedia или платформы Библиотеки Актива — посмотрите Используя Активы).

../Art/avassetHierarchy_2x.png

Актив содержит набор дорожек, предназначающихся, чтобы быть представленными или обработанными вместе, каждый универсальный тип среды, включая (но не ограничиваясь этим) аудио, видео, текст, субтитры и подзаголовки. Объект актива предоставляет информацию о целом ресурсе, таком как его продолжительность или заголовок, а также подсказывает для представления, такого как его естественный размер. Активы могут также иметь метаданные, представленные экземплярами AVMetadataItem.

Дорожка представлена экземпляром AVAssetTrack. В типичном простом случае одна дорожка представляет аудио компонент, и другой представляет компонент видео; в сложном составе могут быть многократные перекрывающиеся дорожки аудио и видео.

../Art/avassetAndTracks_2x.png

Дорожка имеет много свойств, таких как ее тип (видео или аудио), визуальные и/или слышимые характеристики (как надлежащие), метаданные и временная шкала (выраженный с точки зрения ее родительского актива). Дорожка также имеет массив описаний формата. Массив содержит CMFormatDescription объекты (см. CMFormatDescriptionRef), каждый из которых описывает формат выборок носителей, на которые ссылается дорожка. Дорожка, содержащая универсальные носители (например, все закодированное использование к тем же настройкам) предоставит массиву количество 1.

Дорожка может самостоятельно быть разделена на сегменты, представленные экземплярами AVAssetTrackSegment. Сегмент является временем, отображаясь от источника до временной шкалы дорожки актива.

Представления времени

Время в Основе AV представлено примитивными структурами от Базовой платформы Носителей.

CMTime представляет отрезок времени

CMTime структура C, представляющая время как рациональное число с числителем ( int64_t значение), и знаменатель ( int32_t масштаб времени). Концептуально, масштаб времени указывает часть секунды, которую занимает каждый модуль в числителе. Таким образом, если масштаб времени равняется 4, каждый модуль представляет четверть секунды; если масштаб времени равняется 10, каждый модуль представляет одну десятую секунды и т.д. Вы часто используете масштаб времени 600, потому что это - кратное число нескольких обычно используемых частот кадров: 24 кадр/с для фильма, 30 кадр/с для NTSC (используемый для TV в Северной Америке и Японии), и 25 кадр/с для PAL (используемый для TV в Европе). Используя масштаб времени 600, можно точно представлять любое число кадров в этих системах.

В дополнение к простой временной стоимости, a CMTime структура может представлять нечисловые значения: +infinity, - бесконечность, и неопределенный. Это может также указать, округлилось ли время в некоторый момент, и это поддерживает число эпохи.

Используя CMTime

Вы создаете время с помощью CMTimeMake или одна из связанных функций такой как CMTimeMakeWithSeconds (который позволяет Вам создавать время с помощью значения плавающего и указывать предпочтительный масштаб времени). Существует несколько функций для основанной на времени арифметики и для сравнения времен, как проиллюстрировано в следующем примере:

CMTime time1 = CMTimeMake(200, 2); // 200 half-seconds
CMTime time2 = CMTimeMake(400, 4); // 400 quarter-seconds
 
// time1 and time2 both represent 100 seconds, but using different timescales.
if (CMTimeCompare(time1, time2) == 0) {
    NSLog(@"time1 and time2 are the same");
}
 
Float64 float64Seconds = 200.0 / 3;
CMTime time3 = CMTimeMakeWithSeconds(float64Seconds , 3); // 66.66... third-seconds
time3 = CMTimeMultiply(time3, 3);
// time3 now represents 200 seconds; next subtract time1 (100 seconds).
time3 = CMTimeSubtract(time3, time1);
CMTimeShow(time3);
 
if (CMTIME_COMPARE_INLINE(time2, ==, time3)) {
    NSLog(@"time2 and time3 are the same");
}

Для списка всех доступных функций см. Ссылку CMTime.

Специальные значения CMTime

Базовые Носители обеспечивают константы для специальных значений: kCMTimeZero, kCMTimeInvalid, kCMTimePositiveInfinity, и kCMTimeNegativeInfinity. Существует много путей в который a CMTime структура может, например, представлять время, которое недопустимо. Протестировать ли a CMTime допустимо, или нечисловое значение, необходимо использовать надлежащий макрос, такой как CMTIME_IS_INVALID, CMTIME_IS_POSITIVE_INFINITY, или CMTIME_IS_INDEFINITE.

CMTime myTime = <#Get a CMTime#>;
if (CMTIME_IS_INVALID(myTime)) {
    // Perhaps treat this as an error; display a suitable alert to the user.
}

Вы не должны сравнивать значение произвольного CMTime структура с kCMTimeInvalid.

Представление CMTime как объект

Если необходимо использовать CMTime структуры в аннотациях или Базовых контейнерах Основы, можно преобразовать a CMTime структура к и от a CFDictionary непрозрачный тип (см. CFDictionaryRef) использование CMTimeCopyAsDictionary и CMTimeMakeFromDictionary функции, соответственно. Можно также получить строковое представление a CMTime структура с помощью CMTimeCopyDescription функция.

Эпохи

Число эпохи a CMTime структура обычно устанавливается в 0, но можно использовать ее для различения несвязанных временных шкал. Например, эпоха могла быть постепенно увеличена через каждый цикл с помощью цикла представления, для дифференциации между временем N в цикле 0 и время N в цикле 1.

CMTimeRange представляет диапазон времени

CMTimeRange структура C, имеющая время начала и продолжительность, оба выраженные как CMTime структуры. Диапазон времени не включает время, которое является временем начала плюс продолжительность.

Вы создаете использование диапазона времени CMTimeRangeMake или CMTimeRangeFromTimeToTime. Существуют ограничения на значение CMTime эпохи:

  • CMTimeRange структуры не могут охватить различные эпохи.

  • Эпоха в a CMTime структура, представляющая метку времени, может быть ненулевой, но можно только выполнить операции диапазона (такой как CMTimeRangeGetUnion) на диапазонах, чьи запускают поля, имеют ту же эпоху.

  • Эпоха в a CMTime структура, представляющая продолжительность, должна всегда быть 0, и значение должно быть неотрицательным.

Работа с диапазонами времени

Базовые Носители обеспечивают функции, которые можно использовать, чтобы определить, содержит ли диапазон времени данное время или другой диапазон времени, чтобы определить, располагаются ли в два раза, равны, и вычислить объединения и пересечения диапазонов времени, такой как CMTimeRangeContainsTime, CMTimeRangeEqual, CMTimeRangeContainsTimeRange, и CMTimeRangeGetUnion.

Учитывая, что диапазон времени не включает время, которое является временем начала плюс продолжительность, следующее выражение всегда оценивает ко лжи:

CMTimeRangeContainsTime(range, CMTimeRangeGetEnd(range))

Для списка всех доступных функций посмотрите Ссылку CMTimeRange.

Специальные значения CMTimeRange

Базовые Носители обеспечивают константы для диапазона нулевой длины и недопустимого диапазона, kCMTimeRangeZero и kCMTimeRangeInvalid, соответственно. Существует много путей, хотя в который a CMTimeRange структура может быть недопустимой, или нуль — или неопределенной (если один из CMTime структуры неопределенны. Если необходимо протестировать ли a CMTimeRange структура допустима, нуль, или неопределенна, необходимо использовать надлежащий макрос: CMTIMERANGE_IS_VALID, CMTIMERANGE_IS_INVALID, CMTIMERANGE_IS_EMPTY, или CMTIMERANGE_IS_EMPTY.

CMTimeRange myTimeRange = <#Get a CMTimeRange#>;
if (CMTIMERANGE_IS_EMPTY(myTimeRange)) {
    // The time range is zero.
}

Вы не должны сравнивать значение произвольного CMTimeRange структура с kCMTimeRangeInvalid.

Представление структуры CMTimeRange как объект

Если необходимо использовать CMTimeRange структуры в аннотациях или Базовых контейнерах Основы, можно преобразовать a CMTimeRange структура к и от a CFDictionary непрозрачный тип (см. CFDictionaryRef) использование CMTimeRangeCopyAsDictionary и CMTimeRangeMakeFromDictionary, соответственно. Можно также получить строковое представление a CMTime структура с помощью CMTimeRangeCopyDescription функция.

Представления носителей

Видеоданные и его связанные метаданные представлены в Основе AV непрозрачными объектами от Базовой платформы Носителей. Базовые Носители представляют использование видеоданных CMSampleBuffer (см. CMSampleBufferRef). CMSampleBuffer Базовый Стиль основы непрозрачный тип; экземпляр содержит демонстрационный буфер для кадра видеоданных как Базовый Видео пиксельный буфер (см. CVPixelBufferRef). Вы получаете доступ к пиксельному буферу от демонстрационного буферного использования CMSampleBufferGetImageBuffer:

CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(<#A CMSampleBuffer#>);

От пиксельного буфера можно получить доступ к фактическим видеоданным. Для примера посмотрите Преобразование CMSampleBuffer к Объекту UIImage.

В дополнение к видеоданным можно получить много других аспектов видеокадра:

Преобразование CMSampleBuffer к объекту UIImage

Следующий код показывает, как можно преобразовать a CMSampleBuffer к a UIImage объект. Необходимо рассмотреть требования тщательно перед использованием его. Выполнение преобразования является сравнительно дорогой работой. Это является надлежащим, например, создайте неподвижное изображение из кадра видеоданных, бравшихся каждую секунду или около этого. Вы не должны использовать это в качестве средние значения для управления каждым кадром видео, прибывающего из устройства захвата изображения в режиме реального времени.

// Create a UIImage from sample buffer data
- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer
{
    // Get a CMSampleBuffer's Core Video image buffer for the media data
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    // Lock the base address of the pixel buffer
    CVPixelBufferLockBaseAddress(imageBuffer, 0);
 
    // Get the number of bytes per row for the pixel buffer
    void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
 
    // Get the number of bytes per row for the pixel buffer
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
    // Get the pixel buffer width and height
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
 
    // Create a device-dependent RGB color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
 
    // Create a bitmap graphics context with the sample buffer data
    CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8,
      bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
    // Create a Quartz image from the pixel data in the bitmap graphics context
    CGImageRef quartzImage = CGBitmapContextCreateImage(context);
    // Unlock the pixel buffer
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);
 
    // Free up the context and color space
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
 
    // Create an image object from the Quartz image
    UIImage *image = [UIImage imageWithCGImage:quartzImage];
 
    // Release the Quartz image
    CGImageRelease(quartzImage);
 
    return (image);
}