直接上代码
//
// 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秒, 每张图显示多少帧,来计算出每张图显示的时间
网友评论