0

AvAssetReader と AvAssetWriter で録画したビデオにいくつかの画像を重ねようとしています。このチュートリアルに従って、ビデオ (およびオーディオ) を新しいファイルにコピーできます。ここでの目的は、次のコードを使用して、最初のビデオ フレームの一部をいくつかの画像に重ねることです。

while ([assetWriterVideoInput isReadyForMoreMediaData] && !completedOrFailed)
            {
                // Get the next video sample buffer, and append it to the output file.
                CMSampleBufferRef sampleBuffer = [assetReaderVideoOutput copyNextSampleBuffer];

                CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
                CVPixelBufferLockBaseAddress(pixelBuffer, 0);
                EAGLContext *eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
                CIContext *ciContext = [CIContext contextWithEAGLContext:eaglContext options:@{kCIContextWorkingColorSpace : [NSNull null]}];
                UIFont *font = [UIFont fontWithName:@"Helvetica" size:40];
                NSDictionary *attributes = @{NSFontAttributeName:font, NSForegroundColorAttributeName:[UIColor lightTextColor]};
                UIImage *img = [self imageFromText:@"test" :attributes];

                CIImage *filteredImage = [[CIImage alloc] initWithCGImage:img.CGImage];

                [ciContext render:filteredImage toCVPixelBuffer:pixelBuffer bounds:[filteredImage extent] colorSpace:CGColorSpaceCreateDeviceRGB()];


                CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);

                if (sampleBuffer != NULL)
                {
                    BOOL success = [assetWriterVideoInput appendSampleBuffer:sampleBuffer];
                    CFRelease(sampleBuffer);
                    sampleBuffer = NULL;
                    completedOrFailed = !success;
                }
                else
                {
                    completedOrFailed = YES;
                }
            }

テキストから画像を作成するには:

-(UIImage *)imageFromText:(NSString *)text :(NSDictionary *)attributes{
CGSize size = [text sizeWithAttributes:attributes];
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
[text drawAtPoint:CGPointMake(0.0, 0.0) withAttributes:attributes];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}

ビデオとオーディオはコピーされていますが、ビデオにテキストがありません。

質問 1: このコードが機能しないのはなぜですか?

また、現在の読み取りフレームのタイムコードを確認できるようにしたいと考えています。たとえば、ビデオに現在のタイムコードを含むテキストを挿入したいと思います。

私はこのチュートリアルに従ってこのコードを試します:

        AVAsset *localAsset = [AVAsset assetWithURL:mURL];
    NSError *localError;
    AVAssetReader *assetReader = [[AVAssetReader alloc] initWithAsset:localAsset error:&localError];
    BOOL success = (assetReader != nil);

    // Create asset reader output for the first timecode track of the asset
    if (success) {
        AVAssetTrack *timecodeTrack = nil;

        // Grab first timecode track, if the asset has them
        NSArray *timecodeTracks = [localAsset tracksWithMediaType:AVMediaTypeTimecode];
        if ([timecodeTracks count] > 0)
            timecodeTrack = [timecodeTracks objectAtIndex:0];

        if (timecodeTrack) {
            AVAssetReaderTrackOutput *timecodeOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:timecodeTrack outputSettings:nil];
            [assetReader addOutput:timecodeOutput];
        } else {
            NSLog(@"%@ has no timecode tracks", localAsset);
        }
    }

しかし、私はログを取得します:

[...] タイムコード トラックがありません

質問 2: ビデオに AVMediaTypeTimecode がないのはなぜですか? 広告では、現在のフレームのタイムコードを取得するにはどうすればよいですか?

ご協力いただきありがとうございます

4

1 に答える 1

1

私は解決策を見つけました:

ビデオ フレームをオーバーレイするには、解凍設定を修正する必要があります。

NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
NSDictionary* decompressionVideoSettings = [NSDictionary dictionaryWithObject:value forKey:key];
// If there is a video track to read, set the decompression settings for YUV and create the asset reader output.
assetReaderVideoOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:assetVideoTrack outputSettings:decompressionVideoSettings];

フレームのタイムスタンプを取得するには、ビデオ情報を読み取ってから、カウンターを使用して現在のタイムスタンプをインクリメントする必要があります。

durationSeconds = CMTimeGetSeconds(asset.duration);
timePerFrame = 1.0 / (Float64)assetVideoTrack.nominalFrameRate;
totalFrames = durationSeconds * assetVideoTrack.nominalFrameRate;

次に、このループで

while ([assetWriterVideoInput isReadyForMoreMediaData] && !completedOrFailed)

タイムスタンプを見つけることができます:

CMSampleBufferRef sampleBuffer = [assetReaderVideoOutput copyNextSampleBuffer];
if (sampleBuffer != NULL){
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
if (pixelBuffer) {
Float64 secondsIn = ((float)counter/totalFrames)*durationSeconds;
CMTime imageTimeEstimate = CMTimeMakeWithSeconds(secondsIn, 600);
mergeTime = CMTimeGetSeconds(imageTimeEstimate);
                                    counter++;
}
}

お役に立てば幸いです!

于 2016-02-08T15:15:13.560 に答える