Техническое примечание TN2267

Видео ускоряющая ссылка платформы декодирования

Эта ссылка описывает Видео Ускоряющую платформу Декодирования, доступную на Mac OS X v10.6.3 и позже с моделями Mac, оборудованными NVIDIA GeForce 9400M, GeForce 320M, GeForce GT 330M, ATI HD Radeon GFX, Intel HD Graphics и другие.

Обзор
Функции
Выходной обратный вызов
Типы данных
Константы
Коды результата
Пример кода
Загрузка
Ссылка
История версии документа

Обзор

Платформа VideoDecodeAcceleration

Заголовок VDADecoder.h

Видео Ускоряющая платформа Декодирования является интерфейсом программирования C, обеспечивающим низкоуровневый доступ к возможностям декодирования H.264 совместимого GPUs, таким как NVIDIA GeForce 9400M, GeForce 320M, GeForce GT 330M, ATI HD Radeon GFX, Intel HD Graphics и другие. Это предназначается для использования опытными разработчиками, которым в частности нужно аппаратно ускоренный, декодируют видеокадров.

Платформа позволяет Вам:

Видео Ускоряющая платформа Декодирования доступна на Mac OS X 10.6.3 и позже. Посмотрите Загрузку.

Функции

VDADecoderCreate

Создает новое VDADecoder объект.

OSStatus VDADecoderCreate(CFDictionaryRef           decoderConfiguration,
                          CFDictionaryRef           destinationImageBufferAttributes,
                          VDADecoderOutputCallback  *outputCallback, 
                          void                      *decoderOutputCallbackRefcon,
                          VDADecoder                *decoderOut)

Параметры

  • decoderConfiguration - A CFDictionaryRef содержа kVDADecoderConfiguratioXXX ключи, описывающие исходные данные и конфигурацию для декодера. Посмотрите Ключи Конфигурации Декодера.

  • destinationImageBufferAttributes- A CFDictionaryRef описание клиентских требований для вывода отображает буферы. Этот параметр может быть NULL если у клиента нет определенного предпочтения формата выходных буферов изображения. Если NULL используется, клиент не должен делать предположения относительно возвращенных буферов изображения. Посмотрите Буферные Ключи Атрибута Конечного изображения.

  • outputCallback- A VDADecoderOutputCallback функция, вызванная декодером, когда возврат распаковал буферы изображения клиенту.

  • decoderOutputCallbackRefcon - Указатель на пользовательские данные передал выходному обратному вызову для всех кадров от этого объекта декодера.

  • decoderOut - На выводе, недавно создаваемом объекте декодера.

Обсуждение

Создает интерфейс для использования аппаратных ресурсов для декодирования видео путем возврата a VDADecoder объект. Если аппаратные средства не будут существовать для декодирования предоставленного формата или если будут недостаточные аппаратные ресурсы для выполнения аппаратного декодирования, то надлежащий код результата будет возвращен.

Декодируемые кадры испускаются через VDADecoderOutputCallback функция передала в вызывающей стороной.

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

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

Возвращаемое значение

Код результата. Посмотрите Коды Результата.

VDADecoderDestroy

Выпускает объект декодера.

OSStatus VDADecoderDestroy(VDADecoder decoder)

Параметры

  • decoder - Аппаратный уничтожаемый объект декодера.

Обсуждение

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

Возвращаемое значение

Код результата. Посмотрите Коды Результата.

VDADecoderDecode

Отправьте включенные сжатые данные в аппаратный объект декодера для декодирования.

OSStatus VDADecoderDecode(VDADecoder      decoder,
                          uint32_t        decodeFlags,
                          CFTypeRef       compressedBuffer,
                          CFDictionaryRef frameInfo)

Параметры

  • decoder - Аппаратный объект декодера выполнение работы декодирования.

  • decodeFlags- Флаги, содержащие любые специальные запросы на эту работу декодирования. Посмотрите Декодируют Флаги.

  • compressedBuffer- A CFDataRef содержа единственный H.264 сжатый кадр, который будет декодироваться.

  • frameInfo - A CFDictionaryRef содержа информацию, которая будет возвращена в выходном обратном вызове для этого кадра. Этот словарь может содержать предоставленную информацию клиента, связанную с декодируемым кадром, например время представления. CFDictionaryRef будет сохранен платформой.

Обсуждение

Этот вызов передаст единственному H.264 сжатый кадр, упакованный как a CFDataRef к аппаратным средствам декодер возражают для декодирования. Декодируемый кадр выводится через выходной обратный вызов.

Возвращаемое значение

Код результата. Посмотрите Коды Результата.

VDADecoderFlush

Сбросьте все кадры, в настоящее время декодируемые аппаратным декодером.

OSStatus VDADecoderFlush(VDADecoder decoder, uint32_t flushFlags)

Параметры

  • decoder - Аппаратный объект декодера выполнение работы декодирования.

  • flushFlags- Флаги, управляющие поведением сброса, например, декодируют ли в настоящее время в рейсе операции, испустят кадры. Посмотрите Флаги Сброса.

Обсуждение

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

Выходной обратный вызов все еще вызывают для всех вспыхнувших кадров, но не будут возвращены никакие буферы изображения.

Если kVDADecoderFlush_emitFrames флаг указан, работа сброса возвратит буферы изображения в выходном обратном вызове.

Возвращаемое значение

Код результата. Коды результата.

Выходной обратный вызов

Когда кадр декодируется путем вызова, прототип для функции обратного вызова вызвал VDADecoderDecode.

typedef void (*VDADecoderOutputCallback)(void             *decompressionOutputRefCon,
                                         CFDictionaryRef  frameInfo,
                                         OSStatus         status,
                                         uint32_t         infoFlags,
                                         CVImageBufferRef imageBuffer)

Параметры

  • decompressionOutputRefCon - Пользовательский указатель данных, как передано в VDADecoderCreate для decoderOutputCallbackRefcon.

  • frameInfo- frameInfo словарь передал VDADecoderDecode для этого кадра. CFDictionaryRef будет выпущен после возврата из обратного вызова. Клиент должен сохранить его, если это необходимо вне объема выходного обратного вызова.

  • status - Если распаковка не была успешна, код ошибки возвращается. Посмотрите Коды Результата.

  • infoFlags - Содержит информацию о работе декодирования. Например, kVDADecodeInfo_FrameDropped если кадр был отброшен, флаг может быть установлен. Посмотрите Декодируют Информационные Флаги.

  • imageBuffer - Базовый буфер Видеоизображения, содержащий распакованный видеокадр. Клиент должен сохранить возвращенные буферы изображения и выпустить их, когда они больше не необходимы. Буферы изображения НЕ принадлежат экземпляру декодера.

Обсуждение

При создании a VDADecoder объект, передайте в a VDADecoderOutputCallback функция, которая будет использоваться для возврата распакованных кадров. Выходной обратный вызов может быть призван, декодируют порядок представления, а не порядок.

Типы данных

VDADecoder

OpaqueVDADecoder*  VDADecoder

Ссылка на объект видеодекодера.

Константы

Ключи конфигурации декодера

  • kVDADecoderConfiguration_Height - A CFNumberRef указание исходной высоты.

  • kVDADecoderConfiguration_Width - A CFNumberRef указание исходной ширины.

  • kVDADecoderConfiguration_SourceFormat - A CFNumberRef (kCFNumberSInt32Type Четыре Кода символа) указание исходного формата. Например, 'avc1'.

  • kVDADecoderConfiguration_avcCData - A CFDataRef содержа avcC данные от потока битов H.264. В файле фильма в формате QuickTime это - те же данные, хранящиеся в описании изображения как avcC атом.

Буфер конечного изображения приписывает ключи

Перечисленный обычно используемые ключи, для полного списка доступных ключей Core Video Pixel Buffer посмотрите CoreVideo/CVPixelBuffer.h

  • kCVPixelBufferPixelFormatTypeKey - Сингл CFNumberRef (OSType) или массив CFNumberRef (OSTypes) указание формата выходного пикселя. Например, kCVPixelFormatType_422YpCbCr8.

  • kCVPixelBufferWidthKey - A CFNumberRef указание ширины пиксельного буфера.

  • kCVPixelBufferHeightKey - A CFNumberRef указание высоты пиксельного буфера.

  • kCVPixelBufferIOSurfacePropertiesKey - A CFDictionaryRef из свойств IOSurface. Присутствие этого ключа запрашивает распределение буферов через IOSurface. Если a destinationImageBufferAttributes словарь указан в VDADecoderCreate, тот словарь MUST содержит этот ключ. Значение для этого ключа является чаще всего просто пустым словарем. Если NULL указан в VDADecoderCreate для destinationImageBufferAttributes словарь, этот ключ, как предполагается, устанавливается. Аппаратный декодер требует IOSurface поддержанные буферы изображения для рендеринга. Посмотрите IOSurface/IOSurfaceAPI.h для полного списка доступных свойств IOSurface.

Декодируйте флаги

Флаги, используемые с VDADecoderDecode.

kVDADecoderDecodeFlags_DontEmitFrame = 1 << 0

Указывает, что декодер не должен возвращать буфер изображения в выходном обратном вызове. Обратите внимание на то, что выходной обратный вызов все еще вызывается.

Флаги сброса

Флаги, используемые с VDADecoderFlush.

kVDADecoderFlush_EmitFrames = 1 << 0

Во время работы сброса этот флаг указывает, что декодер должен декодировать и возвратить буферы изображения для всех в настоящее время кадров с очередями.

Декодируйте информационные флаги

Во время декодирования флаги могут быть установлены в infoFlags поле выходного обратного вызова, передающего дополнительную информацию о работе декодирования.

kVDADecodeInfo_Asynchronous = 1UL << 0 kVDADecodeInfo_FrameDropped = 1UL << 1
  • kVDADecodeInfo_Asynchronous - Указывает асинхронное декодирование. Поскольку асинхронное декодирование является нормальным рабочим режимом объекта декодера, этот флаг будет всегда устанавливаться во время нормального функционирования.

  • kVDADecodeInfo_FrameDropped - Указывает, что был отброшен кадр.

Коды результата

Ошибки возвратились из VDADecoder APIs.

kVDADecoderNoErr                    = 0
kVDADecoderHardwareNotSupportedErr  = -12470 
kVDADecoderFormatNotSupportedErr    = -12471
kVDADecoderConfigurationError       = -12472
kVDADecoderDecoderFailedErr         = -12473

Пример кода

На следующие типы данных и функции помощника ссылаются в листингах кода ниже и представляют в иллюстративных целях только. Они не часть платформы.

// tracks a frame in and output queue in display order
typedef struct myDisplayFrame {
    int64_t                 frameDisplayTime;
    CVPixelBufferRef        frame;
    struct myDisplayFrame   *nextFrame;
} myDisplayFrame, *myDisplayFramePtr;

// some user data
typedef struct MyUserData 
{
    ...

    myDisplayFramePtr displayQueue; // display-order queue - next display frame is always at the queue head
    int32_t           queueDepth; // we will try to keep the queue depth around 10 frames
    pthread_mutex_t   queueMutex; // mutex protecting queue manipulation

     ...
} MyUserData, *MyUserDataPtr;

// example helper function that wraps a time into a dictionary
static CFDictionaryRef MakeDictionaryWithDisplayTime(int64_t inFrameDisplayTime)
{
    CFStringRef key = CFSTR("MyFrameDisplayTimeKey");
    CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &inFrameDisplayTime);

    return CFDictionaryCreate(kCFAllocatorDefault,
                              (const void **)&key,
                              (const void **)&value,
                              1,
                              &kCFTypeDictionaryKeyCallBacks,
                              &kCFTypeDictionaryValueCallBacks);
}

// example helper function to extract a time from our dictionary
static int64_t GetFrameDisplayTimeFromDictionary(CFDictionaryRef inFrameInfoDictionary)
{
    CFNumberRef timeNumber = NULL;
    int64_t outValue = 0;

    if (NULL == inFrameInfoDictionary) return 0;

    timeNumber = CFDictionaryGetValue(inFrameInfoDictionary, CFSTR("MyFrameDisplayTimeKey"));
    if (timeNumber) CFNumberGetValue(timeNumber, kCFNumberSInt64Type, &outValue);

    return outValue;
}

Создание декодера

Перечисление 1 иллюстрирует основные шаги, требуемые создать декодер.

Функция требует, чтобы параметры, описывающие сжатый исходный поток битов носителей (размерности, тип формата и конфигурация декодера), были переданы в вызывающей стороной. Эти параметры используются для создания словаря конфигурации декодера. Дополнительный словарь атрибута формата пикселя также создается, запрашивая '2vuy' как формат возвращенных буферов изображения. Этот словарь может быть NULL если вызывающая сторона не имеет никакого предпочтения относительно формата пикселя возвращенных буферов изображения.

Если создание декодера было успешно, a VDADecoder объект возвращается к вызывающей стороне через decoderOut.

Перечисление 1  

OSStatus CreateDecoder(SInt32 inHeight, SInt32 inWidth,
                       OSType inSourceFormat, CFDataRef inAVCCData,
                       VDADecoder *decoderOut)
{
    OSStatus status;

    CFMutableDictionaryRef decoderConfiguration = NULL;
    CFMutableDictionaryRef destinationImageBufferAttributes = NULL;
    CFDictionaryRef emptyDictionary; 

    CFNumberRef height = NULL;
    CFNumberRef width= NULL;
    CFNumberRef sourceFormat = NULL;
    CFNumberRef pixelFormat = NULL; 

    // source must be H.264
    if (inSourceFormat != 'avc1') {
        fprintf(stderr, "Source format is not H.264!\n");
        return paramErr;
    }

    // the avcC data chunk from the bitstream must be present
    if (inAVCCData == NULL) {
        fprintf(stderr, "avc1 decoder configuration data cannot be NULL!\n");
        return paramErr;
    }

    // create a CFDictionary describing the source material for decoder configuration
    decoderConfiguration = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                                     4,
                                                     &kCFTypeDictionaryKeyCallBacks,
                                                     &kCFTypeDictionaryValueCallBacks);

    height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inHeight);
    width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inWidth);
    sourceFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inSourceFormat);

    CFDictionarySetValue(decoderConfiguration, kVDADecoderConfiguration_Height, height);
    CFDictionarySetValue(decoderConfiguration, kVDADecoderConfiguration_Width, width);
    CFDictionarySetValue(decoderConfiguration, kVDADecoderConfiguration_SourceFormat, sourceFormat);
    CFDictionarySetValue(decoderConfiguration, kVDADecoderConfiguration_avcCData, inAVCCData);

    // create a CFDictionary describing the wanted destination image buffer
    destinationImageBufferAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                                                 2,
                                                                 &kCFTypeDictionaryKeyCallBacks,
                                                                 &kCFTypeDictionaryValueCallBacks);

    OSType cvPixelFormatType = kCVPixelFormatType_422YpCbCr8;
    pixelFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &cvPixelFormatType);
    emptyDictionary = CFDictionaryCreate(kCFAllocatorDefault, // our empty IOSurface properties dictionary
                                         NULL,
                                         NULL,
                                         0,
                                         &kCFTypeDictionaryKeyCallBacks,
                                         &kCFTypeDictionaryValueCallBacks);

    CFDictionarySetValue(destinationImageBufferAttributes, kCVPixelBufferPixelFormatTypeKey, pixelFormat);
    CFDictionarySetValue(destinationImageBufferAttributes,
                         kCVPixelBufferIOSurfacePropertiesKey,
                         emptyDictionary);

    // create the hardware decoder object
    status = VDADecoderCreate(decoderConfiguration,
                              destinationImageBufferAttributes, 
                              (VDADecoderOutputCallback*)myDecoderOutputCallback,
                              (void *)myUserData,
                              decoderOut);

    if (kVDADecoderNoErr != status) {
        fprintf(stderr, "VDADecoderCreate failed. err: %d\n", status);
    }

    if (decoderConfiguration) CFRelease(decoderConfiguration);
    if (destinationImageBufferAttributes) CFRelease(destinationImageBufferAttributes);
    if (emptyDictionary) CFRelease(emptyDictionary);

    return status;
}

Выходной обратный вызов

Перечисление 2 демонстрирует гипотетический выходной обратный вызов.

Клиенты не должны выполнять тяжелые задачи непосредственно в обратном вызове или вызове ни в какие платформы, которые могут блокировать в течение длительного периода времени. Если намерение состоит в том, чтобы вывести на экран кадры, обратите внимание на то, что буферы изображения могут не быть в порядке дисплея. Идеально, кадры, возвращенные в выходном обратном вызове, будут ставиться в очередь для обработки или дисплея на другом потоке.

Перечисление 2  

void myDecoderOutputCallback(void               *decompressionOutputRefCon,
                             CFDictionaryRef    frameInfo,
                             OSStatus           status, 
                             uint32_t           infoFlags,
                             CVImageBufferRef   imageBuffer)
{
    MyUserDataPtr myUserData = (MyUserDataPtr)decompressionOutputRefCon;

    myDisplayFramePtr newFrame = NULL;
    myDisplayFramePtr queueWalker = myUserData->displayQueue;

    if (NULL == imageBuffer) {
        printf("myDecoderOutputCallback - NULL image buffer!\n");
        if (kVDADecodeInfo_FrameDropped & infoFlags) {
            printf("myDecoderOutputCallback - frame dropped!\n");
        }
        return;
    }

    if ('2vuy' != CVPixelBufferGetPixelFormatType(imageBuffer)) {
        printf("myDecoderOutputCallback - image buffer format not '2vuy'!\n");
        return;
    }

    // allocate a new frame and populate it with some information
    // this pointer to a myDisplayFrame type keeps track of the newest decompressed frame
    // and is then inserted into a linked list of  frame pointers depending on the display time
    // parsed out of the bitstream and stored in the frameInfo dictionary by the client
    newFrame = calloc(sizeof(myDisplayFrame), 1);
    newFrame->frame = CVBufferRetain(imageBuffer);
    newFrame->frameDisplayTime = GetFrameDisplayTimeFromDictionary(frameInfo);

    // since the frames we get may be in decode order rather than presentation order
    // our hypothetical callback places them in a queue of frames which will
    // hold them in display order for display on another thread
    pthread_mutex_lock(&myUserData->queueMutex);

    if (!queueWalker || (newFrame->frameDisplayTime < queueWalker->frameDisplayTime)) {
        // we have an empty queue, or this frame earlier than the current queue head
        newFrame->nextFrame = queueWalker;
        myUserData->displayQueue = newFrame;
    } else {
        // walk the queue and insert this frame where it belongs in display order
        Boolean         frameInserted = false;
        myDisplayFramePtr nextFrame = NULL;

        while (!frameInserted) {
            nextFrame = queueWalker->nextFrame;
            if (!nextFrame || (newFrame->frameDisplayTime < nextFrame->frameDisplayTime)) {
                // if the next frame is the tail of the queue, or our new frame is ealier
                newFrame->nextFrame = nextFrame;
                queueWalker->nextFrame = newFrame;
                frameInserted = true;
            }
            queueWalker = nextFrame;
        }
    }

    myUserData->queueDepth++;

    pthread_mutex_unlock(&myUserData->queueMutex);
}

Декодирование кадра

Перечисление 3 демонстрирует использование VDADecoderDecode распаковать единственный кадр видео H.264.

Функция берет a CFDataRef содержа сжатый видеокадр и время кадра (предоставленный клиентом от потока битов), который упаковывается в информационном словаре кадра. Информационный словарь кадра передается выходному обратному вызову для этого кадра, когда распаковано и может содержать любое число пользовательских определенных свойств, предоставленных клиентом как пары ключ/значение.

Перечисление 3  

OSStatus DecodeAFrame(VDADecoder inDecoder, CFDataRef inCompressedFrame, int64_t inFrameDisplayTime)
{
    CFDictionaryRef frameInfo = NULL;
    OSStatus status = kVDADecoderNoErr;

    // create a dictionary containg some information about the frame being decoded
    // in this case, we pass in the display time aquired from the stream
    frameInfo = MakeDictionaryWithDisplayTime(inFrameDisplayTime);

    // ask the hardware to decode our frame, frameInfo will be retained and pased back to us
    // in the output callback for this frame
    status = VDADecoderDecode(inDecoder, 0, inCompressedFrame, frameInfo);
    if (kVDADecoderNoErr != status) {
        fprintf(stderr, "VDADecoderDecode failed. err: %d\n", status);
    }

    // the dictionary passed into decode is retained by the framework so
    // make sure to release it here
    CFRelease(frameInfo);

    return status;
}

Загрузка

Эта загрузка включает Видео Ускоряющую платформу Декодирования и инструкции для установки его в папку Mac OS X 10.6 SDK.

Дополнения XCode для Видео Ускоряющей Платформы Декодирования

Ссылка

Для Mac информация о модели см.: Об интегрированном видео на основанном на Intel Macs



История версии документа


ДатаПримечания
24.05.2011

Передовая статья

27.04.2011

Передовая статья

19.04.2010

Добавленный примечание, описывающее, где заставить платформу соединяться против.

29.03.2010

Новый документ, описывающий Видео Ускоряющую Платформу Декодирования APIs, доступный на Mac OS v10.6.3 и позже с определенными моделями Mac.