My swift code below uses a avfoudnation uiview to take a photo and save it on the imageview. All I want to do is be able to take a video and save in then have be displayed on the imageview if possible. I am not concern with anything else like playing the video. I added 2 funds startRecord and Save. Which are to be used to start record and save the video to the imageview.
import UIKit;import AVFoundation
class ViewController: UIViewController, AVCapturePhotoCaptureDelegate {
@IBOutlet var previewView : UIView!
@IBOutlet var captureImageView : UIImageView!
var captureSession: AVCaptureSession!
var stillImageOutput: AVCapturePhotoOutput!
var videoPreviewLayer: AVCaptureVideoPreviewLayer!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Setup your camera here...
captureSession = AVCaptureSession()
captureSession.sessionPreset = .medium
guard let backCamera = AVCaptureDevice.default(for: AVMediaType.video)
else {
print("Unable to access back camera!")
return
}
do {
let input = try AVCaptureDeviceInput(device: backCamera)
//Step 9
stillImageOutput = AVCapturePhotoOutput()
stillImageOutput = AVCapturePhotoOutput()
if captureSession.canAddInput(input) && captureSession.canAddOutput(stillImageOutput) {
captureSession.addInput(input)
captureSession.addOutput(stillImageOutput)
setupLivePreview()
}
}
catch let error {
print("Error Unable to initialize back camera: \(error.localizedDescription)")
}
}
func setupLivePreview() {
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoPreviewLayer.videoGravity = .resizeAspect
videoPreviewLayer.connection?.videoOrientation = .portrait
previewView.layer.addSublayer(videoPreviewLayer)
//Step12
DispatchQueue.global(qos: .userInitiated).async { //[weak self] in
self.captureSession.startRunning()
//Step 13
DispatchQueue.main.async {
self.videoPreviewLayer.frame = self.previewView.bounds
}
}
}
@IBAction func startRecord(_ sender: Any) {
}
@IBAction func Save(_ sender: Any) {
}
@IBAction func didTakePhoto(_ sender: Any) {
let settings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])
stillImageOutput.capturePhoto(with: settings, delegate: self)
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
guard let imageData = photo.fileDataRepresentation()
else { return }
let image = UIImage(data: imageData)
captureImageView.image = image
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.captureSession.stopRunning()
}
}
Hi @timswift, are you essentially wanting to create a thumbnail of your video? If so, you can try creating a function to create a thumbnail image with the video URL then use that method to display the thumbnail in an imageView.
import AVKit
@IBOutlet weak var videoThumbnail: UIImageView!
func getThumbnailFromUrl(_ url: String?, _ completion: @escaping ((_ image: UIImage?)->Void)) {
guard let url = URL(string: url ?? "") else { return }
DispatchQueue.main.async {
let asset = AVAsset(url: url)
let assetImgGenerate = AVAssetImageGenerator(asset: asset)
assetImgGenerate.appliesPreferredTrackTransform = true
let time = CMTimeMake(value: 2, timescale: 1)
do {
let img = try assetImgGenerate.copyCGImage(at: time, actualTime: nil)
let thumbnail = UIImage(cgImage: img)
completion(thumbnail)
} catch {
print("Error :: ", error.localizedDescription)
completion(nil)
}
}
}
self.getThumbnailFromUrl(videoURL) { [weak self] (img) in
guard let _ = self else { return }
if let img = img {
self?.videoThumbnail.image = img
}
}
@gdelarosa in what func do I put self.getThumbnailFromUrl(videoURL) { [weak self] (img) in
guard let _ = self else { return }
if let img = img {
self?.imgThumbnail.image = img
}
} ?
You can place that method in the function that you will be retrieving the video URL from. The parameter is expecting a string and in the example “videoURL” would be where you’d place the url of your video.
@gdelarosa A button is going to call the func but I don’t know what to put in the two highlighted blocks.
@IBAction func Save(_ sender: Any) {
//what do I put in the 2 highlighted blocks
getThumbnailFromUrl(<#T##url: String?##String?#>, <#T##completion: ((UIImage?) -> Void)##((UIImage?) -> Void)##(UIImage?) -> Void#>)}
Try creating a constant called videoURL then adding it into the getThumnailFromUrl method. Example below
@IBAction func buttonAction(_ sender: Any) {
let videoURL = "YourVideoURL"
self.getThumbnailFromUrl(videoURL) { [weak self] (img) in
guard let _ = self else { return }
if let img = img {
self?.videoThumnail.image = img
}
}
}
I have not personally tested this out myself, so it may not work and or have a runtime error. If you are unable to achieve your goal with this solution you can also try finding other examples online by searching video thumbnail to imageView in swift.
Hi @timswift,
The videoURL is a fileURL that you would create from the video in your Resource directory of from an actual URL. If you are using a YoutTube Video then it offers Thumbnails in different sizes that you can get directly.
@jayantvarma so If I wanted to take a snapshot from a video on a uiview that is already in the app. What would I do? I guess I would not use a video url because this has nothing to do with a online video.
hi @timswift,
I get that you already have a video in your view hierarchy. How are you playing that video? Is it from a local resource file in your app or is it captured from the camera and held in memory?
Eitherways, the Video URL that is important for AVAssetImageGenerator is not necessarily a remote video url, it can be a local file or by saving the in memory to a temp directory and passing the fileURL to that.
Even if you are getting the video from your Device (Photo Album) you would get a fileURL that you can use.
The other way you can capture and get a screenshot from a UIView irrespective of a video or not is to render the UIView as
This is what I got to compile func snapshot(_ view: UIView) → UIImage {
let imageRenderer = UIGraphicsImageRenderer(bounds: view.bounds)
return imageRenderer.image { context in
videoPreviewLayer.render(in: context as! CGContext)
}
}. Hope it works I am trying to import a video from photo gallery.