Вопрос по ios, iphone – Аппаратное ускорение декодирования h.264 до текстуры, оверлея или аналогичного в iOS

10

Возможно ли и поддерживается ли аппаратное ускорение API декодирования h.264 для iOS, чтобы декодировать локальный (не потоковый) видеофайл, а затем создавать поверх него другие объекты?

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

Исходя из DirectX, OpenGL и OpenGL ES для Android, я представляю что-то вроде рендеринга видео в текстуру и использую эту текстуру для рисования полноэкранного четырехугольника, а затем использую другие спрайты для рисования остальных объектов; или, возможно, написание промежуточного фильтра непосредственно перед рендерингом, чтобы я мог манипулировать отдельными выходными кадрами и рисовать свои вещи; или, может быть, рисование в 2D-слой поверх видео.

Похоже на AV Foundation или Core Mediamay помогите мне сделать то, что я делаю, но прежде чем углубляться в детали, я хотел бы узнать, возможно ли вообще делать то, что я хочу, и каковы мои основные пути решения проблемы.

Please refrain from "this is too advanced for you, try hello world first" answers. I know my stuff, and just want to know if what I want to do is possible (and most importantly, supported, so the app won't get eventually rejected), before I study the details by myself.

редактировать:

Я не разбираюсь в разработке под iOS, но профессионально занимаюсь DirectX, OpenGL и OpenGL ES для Android. Я подумываю сделать iOS-версию приложения для Android, которое у меня сейчас есть, и я просто хочу знать, возможно ли это. Если так, у меня есть достаточно времени, чтобы начать разработку iOS с нуля, вплоть до того, что я хочу делать. Если это невозможно, я просто не буду тратить время на изучение всей платформы в это время.

Следовательно, это вопрос технической осуществимости. Я не запрашиваю код. Я ищу ответы типа "Да, вы можете сделать это". Просто используйте A и B, используйте C для рендеринга в D и нарисуйте ваши вещи с помощью E "или" Нет, вы можете ". Аппаратное ускоренное декодирование недоступно для сторонних приложений & quot; (это то, что друг сказал мне). Только это, и я буду в пути.

Я прочитал обзор видео технологий на странице 32Обзор технологии IOS, Это в значительной степени говорит о том, что я могу использовать Media Player для наиболее простой функциональности воспроизведения (не то, что я ищу), UIKit для встраивания видео с чуть большим контролем над встраиванием, но не над фактическим воспроизведением (не то, что я & apos; я ищу), AVFoundation для большего контроля над воспроизведением (может быть, то, что мне нужно, но большинство ресурсов, которые я нахожу в Интернете, рассказывают о том, как использовать камеру), или Core Media, чтобы иметь полный низкоуровневый контроль над видео (вероятно, то, что я нужно, нокрайне плохо документированои даже больше не хватает ресурсов на воспроизведение, чем даже AVFoundation).

Я обеспокоен тем, что могу посвятить следующие шесть месяцев полному изучению программирования на iOS, но в конце обнаружу, что соответствующий API недоступен сторонним разработчикам и что я хочу сделать, неприемлемо для развертывания магазина iTunes. Это то, что сказал мне мой друг, но, похоже, я не могу найти что-то подходящее в руководствах по разработке приложений. Поэтому я пришел сюда, чтобы спросить людей, которые имеют больше опыта в этой области, возможно ли то, что я хочу сделать. Больше не надо.

Я считаю это актуальным вопросом высокого уровня, который может быть неверно истолкован как вопрос «я ничего не делаю», «прошу дать мне кодек». Если мое суждение здесь было ошибочным, не стесняйтесь удалить или опровергнуть этот вопрос к своему сердцу.

SO о предоставлении ответов на основе содержания вопроса. Если бы нам хотелось сказать «начни с привет, мир», мы бы это сказали. Что касается вашего вопроса, вы смотрели наAVComposition? CodaFi

Ваш Ответ

1   ответ
25

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

AV Foundation позволяет выполнять аппаратное ускорение декодирования видео H.264 с использованием AVAssetReader, после чего вы передаете необработанные декодированные кадры видео в формате BGRA. Они могут быть загружены в текстуру, используя либоglTexImage2D() или более эффективные кэши текстур в iOS 5.0. Оттуда вы можете обрабатывать для отображения или извлекать кадры из OpenGL ES и использовать AVAssetWriter для выполнения аппаратно-ускоренного кодирования H.264 результата. Все это использует общедоступные API-интерфейсы, поэтому вы нигде не найдете ничего, что могло бы привести к отказу от App Store.

Однако вам не нужно накатывать собственную реализацию этого. Моя BSD-лицензированная платформа с открытым исходным кодомGPUImage инкапсулирует эти операции и обрабатывает все это для вас. Вы создаете экземпляр GPUImageMovie для входного фильма H.264, прикрепляете к нему фильтры (например, накладываемые наложения или операции цветового ввода), а затем присоединяете эти фильтры к GPUImageView для отображения и / или к GPUImageMovieWriter для перекодирования H. 264 фильма из обработанного видео.

Единственная проблема, которая у меня есть в настоящее время, заключается в том, что я не подчиняюсь меткам времени в видео для воспроизведения, поэтому кадры обрабатываются так же быстро, как и декодируются из фильма. Для фильтрации и перекодирования видео это не является проблемой, поскольку временные метки передаются на записывающее устройство, но для прямого отображения на экране это означает, что видео может быть ускорено в 2-4 раза. Я приветствую любые материалы, которые позволят вам синхронизировать скорость воспроизведения с фактическими временными метками видео.

В настоящее время я могу воспроизводить, фильтровать и перекодировать видео с разрешением 640x480 со скоростью более 30 кадров в секунду на видео iPhone 4 и 720p со скоростью ~ 20-25 кадров в секунду, а iPhone 4S способен фильтровать и кодировать 1080p со скоростью, значительно превышающей 30 кадров в секунду. , Некоторые из более дорогих фильтров могут нагружать графический процессор и немного замедлять его, но большинство фильтров работают в этих диапазонах частоты кадров.

Если вы хотите, вы можете проверить класс GPUImageMovie, чтобы увидеть, как он выполняет эту загрузку в OpenGL ES, но соответствующий код выглядит следующим образом:

- (void)startProcessing;
{
    NSDictionary *inputOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
    AVURLAsset *inputAsset = [[AVURLAsset alloc] initWithURL:self.url options:inputOptions];

    [inputAsset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:@"tracks"] completionHandler: ^{
        NSError *error = nil;
        AVKeyValueStatus tracksStatus = [inputAsset statusOfValueForKey:@"tracks" error:&error];
        if (!tracksStatus == AVKeyValueStatusLoaded) 
        {
            return;
        }
        reader = [AVAssetReader assetReaderWithAsset:inputAsset error:&error];

        NSMutableDictionary *outputSettings = [NSMutableDictionary dictionary];
        [outputSettings setObject: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA]  forKey: (NSString*)kCVPixelBufferPixelFormatTypeKey];
        // Maybe set alwaysCopiesSampleData to NO on iOS 5.0 for faster video decoding
        AVAssetReaderTrackOutput *readerVideoTrackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:[[inputAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] outputSettings:outputSettings];
        [reader addOutput:readerVideoTrackOutput];

        NSArray *audioTracks = [inputAsset tracksWithMediaType:AVMediaTypeAudio];
        BOOL shouldRecordAudioTrack = (([audioTracks count] > 0) && (self.audioEncodingTarget != nil) );
        AVAssetReaderTrackOutput *readerAudioTrackOutput = nil;

        if (shouldRecordAudioTrack)
        {            
            audioEncodingIsFinished = NO;

            // This might need to be extended to handle movies with more than one audio track
            AVAssetTrack* audioTrack = [audioTracks objectAtIndex:0];
            readerAudioTrackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:nil];
            [reader addOutput:readerAudioTrackOutput];
        }

        if ([reader startReading] == NO) 
        {
            NSLog(@"Error reading from file at URL: %@", self.url);
            return;
        }

        if (synchronizedMovieWriter != nil)
        {
            __unsafe_unretained GPUImageMovie *weakSelf = self;

            [synchronizedMovieWriter setVideoInputReadyCallback:^{
                [weakSelf readNextVideoFrameFromOutput:readerVideoTrackOutput];
            }];

            [synchronizedMovieWriter setAudioInputReadyCallback:^{
                [weakSelf readNextAudioSampleFromOutput:readerAudioTrackOutput];
            }];

            [synchronizedMovieWriter enableSynchronizationCallbacks];
        }
        else
        {
            while (reader.status == AVAssetReaderStatusReading) 
            {
                [self readNextVideoFrameFromOutput:readerVideoTrackOutput];

                if ( (shouldRecordAudioTrack) && (!audioEncodingIsFinished) )
                {
                    [self readNextAudioSampleFromOutput:readerAudioTrackOutput];
                }

            }            

            if (reader.status == AVAssetWriterStatusCompleted) {
                [self endProcessing];
            }
        }
    }];
}

- (void)readNextVideoFrameFromOutput:(AVAssetReaderTrackOutput *)readerVideoTrackOutput;
{
    if (reader.status == AVAssetReaderStatusReading)
    {
        CMSampleBufferRef sampleBufferRef = [readerVideoTrackOutput copyNextSampleBuffer];
        if (sampleBufferRef) 
        {
            runOnMainQueueWithoutDeadlocking(^{
                [self processMovieFrame:sampleBufferRef]; 
            });

            CMSampleBufferInvalidate(sampleBufferRef);
            CFRelease(sampleBufferRef);
        }
        else
        {
            videoEncodingIsFinished = YES;
            [self endProcessing];
        }
    }
    else if (synchronizedMovieWriter != nil)
    {
        if (reader.status == AVAssetWriterStatusCompleted) 
        {
            [self endProcessing];
        }
    }
}

- (void)processMovieFrame:(CMSampleBufferRef)movieSampleBuffer; 
{
    CMTime currentSampleTime = CMSampleBufferGetOutputPresentationTimeStamp(movieSampleBuffer);
    CVImageBufferRef movieFrame = CMSampleBufferGetImageBuffer(movieSampleBuffer);

    int bufferHeight = CVPixelBufferGetHeight(movieFrame);
    int bufferWidth = CVPixelBufferGetWidth(movieFrame);

    CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();

    if ([GPUImageOpenGLESContext supportsFastTextureUpload])
    {
        CVPixelBufferLockBaseAddress(movieFrame, 0);

        [GPUImageOpenGLESContext useImageProcessingContext];
        CVOpenGLESTextureRef texture = NULL;
        CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, coreVideoTextureCache, movieFrame, NULL, GL_TEXTURE_2D, GL_RGBA, bufferWidth, bufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0, &texture);

        if (!texture || err) {
            NSLog(@"Movie CVOpenGLESTextureCacheCreateTextureFromImage failed (error: %d)", err);  
            return;
        }

        outputTexture = CVOpenGLESTextureGetName(texture);
        //        glBindTexture(CVOpenGLESTextureGetTarget(texture), outputTexture);
        glBindTexture(GL_TEXTURE_2D, outputTexture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        for (id<GPUImageInput> currentTarget in targets)
        {            
            NSInteger indexOfObject = [targets indexOfObject:currentTarget];
            NSInteger targetTextureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];

            [currentTarget setInputSize:CGSizeMake(bufferWidth, bufferHeight) atIndex:targetTextureIndex];
            [currentTarget setInputTexture:outputTexture atIndex:targetTextureIndex];

            [currentTarget newFrameReadyAtTime:currentSampleTime];
        }

        CVPixelBufferUnlockBaseAddress(movieFrame, 0);

        // Flush the CVOpenGLESTexture cache and release the texture
        CVOpenGLESTextureCacheFlush(coreVideoTextureCache, 0);
        CFRelease(texture);
        outputTexture = 0;        
    }
    else
    {
        // Upload to texture
        CVPixelBufferLockBaseAddress(movieFrame, 0);

        glBindTexture(GL_TEXTURE_2D, outputTexture);
        // Using BGRA extension to pull in video frame data directly
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bufferWidth, bufferHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, CVPixelBufferGetBaseAddress(movieFrame));

        CGSize currentSize = CGSizeMake(bufferWidth, bufferHeight);
        for (id<GPUImageInput> currentTarget in targets)
        {
            NSInteger indexOfObject = [targets indexOfObject:currentTarget];
            NSInteger targetTextureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];

            [currentTarget setInputSize:currentSize atIndex:targetTextureIndex];
            [currentTarget newFrameReadyAtTime:currentSampleTime];
        }
        CVPixelBufferUnlockBaseAddress(movieFrame, 0);
    }

    if (_runBenchmark)
    {
        CFAbsoluteTime currentFrameTime = (CFAbsoluteTimeGetCurrent() - startTime);
        NSLog(@"Current frame time : %f ms", 1000.0 * currentFrameTime);
    }
}
Я вижу, что вы также извлекаете звуковую дорожку, а также другой выход, как бы вы воспроизвели этот звук для синхронизации с видео, я скачал вашу библиотеку, просмотрел код и не смог понять
О, ты прав. Я на самом деле связан с неправильным вопросом. Я имел в виду это:stackoverflow.com/questions/5621627/… user1003819
Большое спасибо. Я спрошу моего друга об этом. Я также нашелstackoverflow.com/questions/4237538/… Кажется, это очень похоже на то, что вы делаете. user1003819
@machinram - К сожалению, я не закончил работу с воспроизведением фильмов на реальных скоростях, поэтому у меня нет ничего в рамках синхронизации звука с воспроизведением видео. Вы можете поработать над этим и подать запрос на извлечение, если он у вас работает.
@ user1003819 - В этом случае Томми описывает, как отправлять кадры входящего видео в графический процессор, что я также обрабатываю в вышеупомянутой интегрированной среде (на самом деле, это ее основной фокус). Существует еще более быстрый способ загрузки кадров живой камеры в iOS 5.0, чем тот, который он описывает, который вышел после того, как он опубликовал это. Опять же, код для этого в моей структуре с открытым исходным кодом.

Похожие вопросы