【问题标题】:How can I add overlay text on a video, then re-encode it?如何在视频上添加叠加文本,然后重新编码?
【发布时间】:2014-10-05 16:35:55
【问题描述】:

我想从我的 iOS 应用程序中编辑视频。我想要一些关于语言字幕的源视频文本。然后我想保存覆盖了该文本的视频。文字不仅仅是显示目的。但是当我打开编辑后的视频时,它会显示更新后的视频。

这在 iOS 应用程序中是否可行?如果有,怎么做?

【问题讨论】:

  • 不要要求我们在您的博客上回复您。这不是这个网站的工作方式。我已经删除了你的这部分问题。
  • 我们可以在视频上添加动态文本,例如电影中的演员姓名。

标签: iphone objective-c ios ipad video-editing


【解决方案1】:
- (void)addAnimation
{       
    NSString *filePath = [[NSBundle mainBundle] pathForResource:videoName ofType:ext];

    AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:[NSURL fileURLWithPath:filePath]  options:nil];

    AVMutableComposition* mixComposition = [AVMutableComposition composition];

    AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

    AVAssetTrack *clipVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

    [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:clipVideoTrack atTime:kCMTimeZero error:nil];

    [compositionVideoTrack setPreferredTransform:[[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] preferredTransform]];

    CGSize videoSize = [clipVideoTrack naturalSize];

    UIImage *myImage = [UIImage imageNamed:@"29.png"];
    CALayer *aLayer = [CALayer layer];
    aLayer.contents = (id)myImage.CGImage;
    aLayer.frame = CGRectMake(videoSize.width - 65, videoSize.height - 75, 57, 57);
    aLayer.opacity = 0.65;
    CALayer *parentLayer = [CALayer layer];
    CALayer *videoLayer = [CALayer layer];
    parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
    videoLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
    [parentLayer addSublayer:videoLayer];
    [parentLayer addSublayer:aLayer];

    CATextLayer *titleLayer = [CATextLayer layer];
    titleLayer.string = @"Text goes here";
    titleLayer.font = CFBridgingRetain(@"Helvetica");
    titleLayer.fontSize = videoSize.height / 6;
    //?? titleLayer.shadowOpacity = 0.5;
    titleLayer.alignmentMode = kCAAlignmentCenter;
    titleLayer.bounds = CGRectMake(0, 0, videoSize.width, videoSize.height / 6); //You may need to adjust this for proper display
    [parentLayer addSublayer:titleLayer]; //ONLY IF WE ADDED TEXT

    AVMutableVideoComposition* videoComp = [AVMutableVideoComposition videoComposition];
    videoComp.renderSize = videoSize;
    videoComp.frameDuration = CMTimeMake(1, 30);
    videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [mixComposition duration]);
    AVAssetTrack *videoTrack = [[mixComposition tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    AVMutableVideoCompositionLayerInstruction* layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
    instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
    videoComp.instructions = [NSArray arrayWithObject: instruction];

    AVAssetExportSession *assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];//AVAssetExportPresetPassthrough
    assetExport.videoComposition = videoComp;

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString* VideoName = [NSString stringWithFormat:@"%@/mynewwatermarkedvideo.mp4",documentsDirectory];


    //NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:VideoName];
    NSURL *exportUrl = [NSURL fileURLWithPath:VideoName];

    if ([[NSFileManager defaultManager] fileExistsAtPath:VideoName])
    {
        [[NSFileManager defaultManager] removeItemAtPath:VideoName error:nil];
    }

    assetExport.outputFileType = AVFileTypeQuickTimeMovie;
    assetExport.outputURL = exportUrl;
    assetExport.shouldOptimizeForNetworkUse = YES;

    //[strRecordedFilename setString: exportPath];

    [assetExport exportAsynchronouslyWithCompletionHandler:
     ^(void ) {
         dispatch_async(dispatch_get_main_queue(), ^{
             [self exportDidFinish:assetExport];
         });
     }
     ];
}

-(void)exportDidFinish:(AVAssetExportSession*)session
{
    NSURL *exportUrl = session.outputURL;
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

    if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:exportUrl])
    {
        [library writeVideoAtPathToSavedPhotosAlbum:exportUrl completionBlock:^(NSURL *assetURL, NSError *error)
         {
             dispatch_async(dispatch_get_main_queue(), ^{
                 if (error) {
                     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Video Saving Failed"
                                                                    delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
                     [alert show];
                 } else {
                     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Video Saved" message:@"Saved To Photo Album"
                                                                    delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                     [alert show];
                 }
             });
         }];

    }
    NSLog(@"Completed");
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"AlertView" message:@"Video is edited successfully." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alert show];
}

【讨论】:

  • 非常有帮助。谢谢。
  • @Chaitali Jain 我在您的代码中遇到问题,例如由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“*** -[AVAssetExportSession setVideoComposition:] 视频合成必须具有正的 renderSize”跨度>
  • 我们可以使用视频中不断变化的文字进行编辑,就像电影中演员的名字一一出现。
  • 您可以使用它来将演职员表添加到电影中,但此方法会将文本刻录到视频帧上。之后您无法更改它们。
  • 当我在图像上写文字然后图像与视频合并时,出现文字模糊。你能帮帮我吗?
【解决方案2】:

一种方法是将您的文本叠加层创建为 CoreAnimation CATextLayer,将其附加到 AVAssetExportSession 的 videoComposition,然后导出您的视频。生成的视频将在其上呈现叠加层。

这带来了一些好处:

  1. 您不必停留在 CATextLayer - 您可以构建包含 CAGradientLayer、CAShapeLayer 等的 CALayer 树。
  2. 作为核心 Animation 层,它们的许多属性都是可动画的,因此您可以在视频中免费获得流畅的 iOS 风格动画。

听起来不错,对吧? 一个小副作用:根据您使用的导出预设,您的视频将不可避免地以恒定帧速率重新编码 - 对我来说是 30fps。为了保持较小的文件大小,我故意通过省略冗余帧来降低帧速率,所以为了静态横幅,这对我来说是个大问题。

有一些名为 AVEditDemo 的 Apple 示例代码演示了此功能等。有找到它的说明here

【讨论】:

  • 那么...如果 CoreAnimation 破坏交易,你做了什么来获得你的“静态横幅”?
  • 我将横幅渲染到 YUV 帧上,然后将它们传递给编码器 (AVAssetWriter)。
  • 我们可以使用视频中不断变化的文字进行编辑,就像电影中演员的名字一一出现。
  • @RhythmicFistman 你能建议我如何设置 CATextlayer 的精确框架吗?看我的问题stackoverflow.com/questions/31780060/…
  • @Imran 你有没有找到在电影中添加文字的解决方案,比如演员的名字一个接一个出现的电影?
【解决方案3】:

使用 Chaitali Jain 代码,新视频将在没有音频的情况下保存。 有人对这个问题有想法吗?谢谢!

【讨论】:

  • 她没有添加音轨。 AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; 添加此内容并保存音频
猜你喜欢
  • 1970-01-01
  • 2019-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-07
  • 2019-01-21
  • 1970-01-01
相关资源
最近更新 更多