添加到视频合成并导出时,叠加图像会变得像素化

Posted

技术标签:

【中文标题】添加到视频合成并导出时,叠加图像会变得像素化【英文标题】:Overlay image becomes pixelated when added to video composition and exported 【发布时间】:2016-05-01 06:19:23 【问题描述】:

目标是在视频上叠加图像,但使用 AVVideoCompositionCoreAnimationTool 像素化图像。

图片尺寸为 640x1136。视频导出尺寸为 320x568(模仿 5S 设备),因此图像应该可以很好地缩小。图像本身很清晰,但导出过程中的某些东西会导致像素化。

使用 AVMutableVideoComposition 的 renderScale 并没有帮助,因为如果值不是 1.0,AVAssetExportSession 会引发异常。

为保存图像的图层设置 contentsGravity 似乎没有效果。

目标是让用户录制视频然后在视频上绘图。 (图像代表用户绘图。)最终,导出的视频应该与用户在视频预览中看到的内容和用户绘制的内容相匹配,具有相同的质量和尺寸。这个问题有助于叠加图像像素化。

帮助?

    // Create main composition & its tracks
    let mainComposition = AVMutableComposition()
    let compositionVideoTrack = mainComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid))
    let compositionAudioTrack = mainComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid))

    // Get source video & audio tracks
    let videoURL = NSURL(fileURLWithPath: videoURL)
    let videoAsset = AVURLAsset(URL: videoURL, options: nil)
    let sourceVideoTrack = videoAsset.tracksWithMediaType(AVMediaTypeVideo)[0]
    let sourceAudioTrack = videoAsset.tracksWithMediaType(AVMediaTypeAudio)[0]

    // Add source tracks to composition
    do 
        try compositionVideoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), ofTrack: sourceVideoTrack, atTime: kCMTimeZero)
        try compositionAudioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), ofTrack: sourceAudioTrack, atTime: kCMTimeZero)
     catch 
        print("Error with insertTimeRange while exporting video: \(error)")
    

    // Create video composition
    let videoComposition = AVMutableVideoComposition()
    print("Video composition duration: \(CMTimeGetSeconds(mainComposition.duration))")

    // -- Set parent layer & set size equal to device bounds
    let parentLayer = CALayer()
    parentLayer.frame = CGRectMake(0, 0, view.bounds.width, view.bounds.height)
    parentLayer.backgroundColor = UIColor.redColor().CGColor
    parentLayer.contentsGravity = kCAGravityResizeAspectFill

    // -- Set composition equal to capture settings
    videoComposition.renderSize = CGSize(width: view.bounds.width, height: view.bounds.height)
    videoComposition.frameDuration = CMTimeMake(1, Int32(frameRate))

    // -- Add instruction to  video composition object
    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, compositionVideoTrack.asset!.duration)
    let videoLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: compositionVideoTrack)
    instruction.layerInstructions = [videoLayerInstruction]
    videoComposition.instructions = [instruction]

    // -- Create video layer
    let videoLayer = CALayer()
    videoLayer.frame = parentLayer.frame
    videoLayer.contentsGravity = kCAGravityResizeAspectFill

    // -- Create overlay layer
    let overlayLayer = CALayer()
    overlayLayer.frame = parentLayer.frame
    overlayLayer.contentsGravity = kCAGravityResizeAspectFill
    overlayLayer.contents = overlayImage!.CGImage
    overlayLayer.contentsScale = overlayImage!.scale

    // -- Add sublayers to parent layer
    parentLayer.addSublayer(videoLayer)
    parentLayer.addSublayer(overlayLayer)
    //overlayLayer.shouldRasterize = true

    // -- Set animation tool
    videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, inLayer: parentLayer)

    // Create exporter
    let outputURL = getFilePath(getUniqueFilename(gMP4File))
    let exporter = AVAssetExportSession(asset: mainComposition, presetName: AVAssetExportPresetHighestQuality)!
    exporter.outputURL = NSURL(fileURLWithPath: outputURL)
    exporter.outputFileType = AVFileTypeMPEG4
    exporter.videoComposition = videoComposition
    exporter.shouldOptimizeForNetworkUse = true

【问题讨论】:

【参考方案1】:

在对 rasterizationScale 和 contentsScale 进行了几次测试后,将两者结合起来最有帮助,尽管线条仍然不如原来的那么清晰。

希望有人找到有关如何在与视频合并时保留原始图像清晰度的答案。

请注意,如果使用 rasterizationScale,您可能还需要 shouldRasterize。

这些测试是在设备规模(例如,5S 的 2.0)和 2x 设备规模(例如,5S 的 4.0)下进行的。看到其他地方使用了 2x 设备比例,因此决定尝试一下,尽管效果尚不清楚。

contentsScale 2.0:直线清晰,但圆圈包含伪影。

contentsScale 4.0:直线还可以,但不如 2.0 清晰,但圆圈包含的伪影更少。整体形象更好。

rasterizationScale 2.0:直线变形但圆形区域(例如,像字母“R”中的)很可怕

rasterizationScale 4.0:直线没有那么锐利,但圆形区域更好

rasterizationScale + contentsScale 2.0:最佳折衷方案,线条仍然不如原始图像清晰

【讨论】:

谢谢。现在好多了。 :)

以上是关于添加到视频合成并导出时,叠加图像会变得像素化的主要内容,如果未能解决你的问题,请参考以下文章

VectorDrawable 图像变得像素化

UISlider 拇指图像像素化

将图保存为高分辨率或无损图像,可以放大而不像素化

添加到子视图时,UIView 神秘地扩展了 1 个像素

opencv标定板像素尺寸

模拟器应用预览视频像素化