Время и представления носителей
Основанные на времени аудиовизуальные данные, такие как файл ролика или видеопоток, представлены в платформе Основы AV AVAsset
. Его структура диктует большую часть работ платформы. Несколько низкоуровневых структур данных, что использование Основы AV для представления времени и носителей, таких как демонстрационные буферы прибывает из Базовой платформы Носителей.
Представление активов
AVAsset
базовый класс в платформе Основы AV. Это обеспечивает независимую от формата абстракцию основанных на времени аудиовизуальных данных, таких как файл ролика или видеопоток. Во многих случаях Вы работаете с одним из его подклассов: Вы используете подклассы состава при создании новых активов (см. Редактирование), и Вы используете AVURLAsset
создать новый экземпляр актива из носителей в данном URL (включая активы от платформы MPMedia или платформы Библиотеки Актива — посмотрите Используя Активы).
Актив содержит набор дорожек, предназначающихся, чтобы быть представленными или обработанными вместе, каждый универсальный тип среды, включая (но не ограничиваясь этим) аудио, видео, текст, субтитры и подзаголовки. Объект актива предоставляет информацию о целом ресурсе, таком как его продолжительность или заголовок, а также подсказывает для представления, такого как его естественный размер. Активы могут также иметь метаданные, представленные экземплярами AVMetadataItem
.
Дорожка представлена экземпляром AVAssetTrack
. В типичном простом случае одна дорожка представляет аудио компонент, и другой представляет компонент видео; в сложном составе могут быть многократные перекрывающиеся дорожки аудио и видео.
Дорожка имеет много свойств, таких как ее тип (видео или аудио), визуальные и/или слышимые характеристики (как надлежащие), метаданные и временная шкала (выраженный с точки зрения ее родительского актива). Дорожка также имеет массив описаний формата. Массив содержит 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.
В дополнение к видеоданным можно получить много других аспектов видеокадра:
Информация синхронизации. Вы получаете точные метки времени и в течение времени исходной презентации и в течение времени декодирования с помощью
CMSampleBufferGetPresentationTimeStamp
иCMSampleBufferGetDecodeTimeStamp
соответственно.Данные о формате. Данные о формате инкапсулируются в объекте CMFormatDescription (см.
CMFormatDescriptionRef
). Из описания формата можно получить, например, пиксельный тип и видео использование размерностейCMVideoFormatDescriptionGetCodecType
иCMVideoFormatDescriptionGetDimensions
соответственно.Метаданные. Метаданные сохранены в словаре как присоединение. Вы используете
CMGetAttachment
получать словарь:CMSampleBufferRef sampleBuffer = <#Get a sample buffer#>;
CFDictionaryRef metadataDictionary =
CMGetAttachment(sampleBuffer, CFSTR("MetadataDictionary", NULL);
if (metadataDictionary) {
// Do something with the metadata.
}
Преобразование 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); |
} |