美文网首页
iOS 多图片合成视频

iOS 多图片合成视频

作者: 秋叶红90 | 来源:发表于2020-06-06 20:29 被阅读0次

直接上代码

//
//  ViewController.swift
//  PictureToVideo
//
//  Created by Mac on 2020/6/6.
//  Copyright © 2020 Mac. All rights reserved.
//

import CoreGraphics
import AVKit
import UIKit

class ViewController: UIViewController {
    
    var playyer:AVPlayerLayer? = nil
    var player:AVPlayer? = nil
    
    var movePath:String? = nil
    
    var videoSize:CGSize = CGSize.init(width: 320, height: 480)
    var indexImg:Int = 0
    @IBOutlet weak var imgView: UIImageView!
    var images:[UIImage] = [UIImage]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        self.addPicture()
        
        
        
    }
    
    
    func addPicture() {
        self.images.removeAll()
        for item in 1...17 {
            if let img = UIImage.init(named: "\(item)") {
                if let newImg = self.imageWithImageScaleTosize(image: img, size: self.videoSize) {
                    self.images.append(newImg)
                }
                
            }
            
        }
    }
    
    @IBAction func lookPicClick(_ sender: Any) {
        if self.images.count == 0 {
            return
        }
        let index = self.indexImg%self.images.count
        self.imgView.image = self.images[index]
        
        self.indexImg += 1
    }
    

    func imageWithImageScaleTosize(image:UIImage,size:CGSize) -> UIImage? {
        
        let or_size = image.size
        
        let rate = or_size.height/or_size.width
        
        let newImg_w = size.width
        let nwImg_h = rate * size.width
        
        
        //    新创建的位图上下文 newSize为其大小
        UIGraphicsBeginImageContext(size);
        
        let context = UIGraphicsGetCurrentContext();
        context!.setFillColor(UIColor.black.cgColor);
        context!.fill(CGRect.init(x: 0, y: 0, width: size.width, height: size.height));
        //    对图片进行尺寸的改变
        image.draw(in: CGRect.init(origin: CGPoint.init(x: 0, y: (size.height - nwImg_h)/2), size: CGSize.init(width: newImg_w, height: nwImg_h)))
        //    从当前上下文中获取一个UIImage对象  即获取新的图片对象
        let newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return newImage
    }
    
    @IBAction func mergenClick(_ sender: Any) {
        if  let caches = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first {
            //设置mov路径
            let movePath = "\(caches)/move.mov"
            self.movePath = movePath
            print("movePath  \(movePath)")
            //定义视频的大小320 480 倍数
            let  size = self.videoSize
            
            let videoWriter = try! AVAssetWriter.init(url: URL.init(fileURLWithPath: movePath), fileType: AVFileType.mov)
            
            //mov的格式设置 编码格式 宽度 高度
            let videoSettings:[String : Any] = [
                AVVideoCodecKey:AVVideoCodecType.h264,
                AVVideoWidthKey:size.width,
                AVVideoHeightKey:size.height
                ]
               
            let writerInput = AVAssetWriterInput.init(mediaType: AVMediaType.video, outputSettings: videoSettings)
               
            let sourcePixelBufferAttributesDictionary: [String : Any] = [
                kCVPixelBufferPixelFormatTypeKey as String:kCVPixelFormatType_32ARGB
                
            ]
            let adaptor = AVAssetWriterInputPixelBufferAdaptor.init(assetWriterInput: writerInput, sourcePixelBufferAttributes: sourcePixelBufferAttributesDictionary)
            
            if videoWriter.canAdd(writerInput) {
                print("===")
                videoWriter.add(writerInput)
                
                videoWriter.startWriting()
                videoWriter.startSession(atSourceTime: CMTime.zero)
                let dispatchQueue = DispatchQueue.init(label: "mediaInputQueue")
                
                var  frame = 0;
                
                writerInput.requestMediaDataWhenReady(on: dispatchQueue) {
                    while writerInput.isReadyForMoreMediaData {
                        frame += 1
                        
                        if(frame >= self.images.count * 10) {
                            writerInput.markAsFinished()
                            videoWriter.finishWriting {
                                print("完成")
                            }
                         
                            break;
                            
                        }
                        
                        
                        var idx = frame / 10;
                        NSLog("idx==%d",idx);
                        
                        
                        if let buffer = self.pixelBufferFromCGImage(img: self.images[idx%self.images.count], size: size){
                            
                            //设置每秒钟播放图片的个数
                            if !adaptor.append(buffer, withPresentationTime: CMTime.init(value: CMTimeValue(frame), timescale: 20)) {
                                
                                NSLog("FAIL");
                                
                            } else {
                                
                                NSLog("OK");
                            }
                            
//                            CFRelease(buffer);
                        }
                        
                        
                    }
                    
                    
                }
            }
            
        }
       
           
           
        
        
    }
    
    
    func pixelBufferFromCGImage(img:UIImage,size:CGSize) -> CVPixelBuffer? {
        guard let image = img.cgImage else {
            return nil
        }
        let options = [
            kCVPixelBufferCGImageCompatibilityKey:true,
            kCVPixelBufferCGBitmapContextCompatibilityKey:true
        ];
           
        var pxbuffer:CVPixelBuffer? = nil;
        let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(size.width), Int(size.height), kCVPixelFormatType_32ARGB, options as CFDictionary, &pxbuffer)
        
        
        if let px = pxbuffer  {
            CVPixelBufferLockBaseAddress(px,CVPixelBufferLockFlags(rawValue: 0));
            var pxdata = CVPixelBufferGetBaseAddress(px);
            var rgbColorSpace = CGColorSpaceCreateDeviceRGB();
            
            //    当你调用这个函数的时候,Quartz创建一个位图绘制环境,也就是位图上下文。当你向上下文中绘制信息时,Quartz把你要绘制的信息作为位图数据绘制到指定的内存块。一个新的位图上下文的像素格式由三个参数决定:每个组件的位数,颜色空间,alpha选项
        
            if let context = CGContext(data: pxdata,width: Int(size.width),height: Int(size.height),bitsPerComponent: 8,bytesPerRow: 4*Int(size.width),space: rgbColorSpace,bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue) {
                //使用CGContextDrawImage绘制图片  这里设置不正确的话 会导致视频颠倒
                                    
                                      //    当通过CGContextDrawImage绘制图片到一个context中时,如果传入的是UIImage的CGImageRef,因为UIKit和CG坐标系y轴相反,所以图片绘制将会上下颠倒
                let rect = CGRect.init(x: 0, y: 0, width: image.width, height: image.height)
                context.draw(image, in: rect)
                                      
                            // 释放色彩空间
                        
                //      CGColorSpaceRelease(rgbColorSpace);
                                      
                                      // 释放context
                                      
//                CGContextRelease(context);
                                      
                // 解锁pixel buffer
                                      
                CVPixelBufferUnlockBaseAddress(px,CVPixelBufferLockFlags(rawValue: 0));
                                      
                return pxbuffer;
            }
            
            
            
        }
        
        
           
           
           
           
        return nil
    }
    
    @IBAction func playClick(_ sender: Any) {
        
        if self.playyer == nil {
             let layerr = AVPlayerLayer.init(player: AVPlayer.init(playerItem: AVPlayerItem.init(url: URL.init(fileURLWithPath: self.movePath!))))
            layerr.frame = self.imgView.frame
                   
                   self.view.layer.addSublayer(layerr)
                   
                   layerr.player?.play()
            self.player = layerr.player
            self.playyer = layerr
        }else{
            self.player?.seek(to: CMTime.init(value: 0, timescale: 10))
            self.player?.play()
            
        }
    }
    
}


注意事项

图片适配尺寸,不同规格的都居中显示,留有黑边,

时间控制,多少帧为1秒, 每张图显示多少帧,来计算出每张图显示的时间

相关文章

网友评论

      本文标题:iOS 多图片合成视频

      本文链接:https://www.haomeiwen.com/subject/whyftktx.html