AV Foundation Transition Music Stopping - xcode

I am using the following code to play music. It plays well :)
var backgroundMusicPlayer = AVAudioPlayer()
func playBackgroundMusic(filename: String) {
let url = NSBundle.mainBundle().URLForResource(filename, withExtension: nil)
guard let newURL = url else {
print("Could not find file: \(filename)")
return
}
do {
backgroundMusicPlayer = try AVAudioPlayer(contentsOfURL: newURL)
backgroundMusicPlayer.numberOfLoops = -1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play()
} catch let error as NSError {
print(error.description)
}
}
playBackgroundMusic("music.wav")
However, I'd like to be able to keep the music playing only through certain transitions. Is this possible?
Cheers :)

Related

Can't play video from AVCaptureFileOutput

I can't play the video the comes from the AVCaptureFileOutputDelegate. I think I'm missing something here's my code.
func recordVideo() {
let recordingDelegate: AVCaptureFileOutputRecordingDelegate? = self
self.session!.addOutput(videoFileOutput)
self.session!.sessionPreset = AVCaptureSessionPresetHigh
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let filePath = documentsURL.appendingPathComponent("temp")
videoFileOutput.startRecording(toOutputFileURL: filePath, recordingDelegate: recordingDelegate)
}
and on the delegate.
func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) {
if error == nil {
print("Play: \(outputFileURL!)")
self.playVideo(path: outputFileURL!)
} else {
print(error)
}
return
}
But the video is not playing. I think I'm missing the file name or something. Pls help. Thanks!

Swift 3: UICollectionView download video snapshot. UI is freezed while trying to download snapshot

I'm trying to download video preview base on remote video URL. In my project, the server cannot return snapshot image of the videos, that's why I have to do it manually.
In table view, I have code like this in cellForItemAt to get video preview
DataManager.sharedInstance.getCachedImage(url: movie.url!, handler: { (image) in
cell.ivCover.image = image
})
and my getCachedImage function in DataManager:
func getCachedImage(url: String, handler: #escaping(_ result:UIImage) -> Void){
DispatchQueue.global().async {
let userDefaults = UserDefaults.standard
if let imageData = userDefaults.object(forKey: url){
if let finalImg = UIImage(data: imageData as! Data){
DispatchQueue.main.async {
handler(finalImg)
}
print("USING CACHED IMG")
}else{
DispatchQueue.main.async {
handler(#imageLiteral(resourceName: "cover"))
}
print("Cannot parse cached data to image. Use default")
}
}else{
let asset = AVURLAsset(url: URL(string: url)!)
let generate = AVAssetImageGenerator(asset: asset)
generate.appliesPreferredTrackTransform = true
var thumbTime = asset.duration
thumbTime.value = 1
var imgRef:CGImage?
do{
print("Downloading thum from url: \(url)")
imgRef = try generate.copyCGImage(at: thumbTime, actualTime: nil)
}catch let error{
print("Error download thum: \(error.localizedDescription)")
}
var finalImg:UIImage
if let _ = imgRef{
finalImg = UIImage(cgImage: imgRef!)
userDefaults.set(UIImagePNGRepresentation(finalImg), forKey: url)
}else{
finalImg = #imageLiteral(resourceName: "cover")
print("Download thumnail failed. Use default")
}
DispatchQueue.main.async {
handler(finalImg)
}
}
}
}
The problem is that, sometimes I scroll the Collection view, UI is freezed, sometimes it's not. Please note that this video is on REMOTE SERVER, NOT local video.
I've spent days to figure out the issue but still not able to find out what went wrong. Please help!
Or is there any existing library I can use?
import UIKit
import Photos
class ImportViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func myButton(_ sender: Any) {
let videoURL = "https://youerdomin.com/file.mp4"
print("1")
DispatchQueue.global(qos: .background).async {
print("2")
if let url = URL(string: videoURL), let urlData = NSData(contentsOf: url) {
print("3")
let documentsPath =
NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
let filePath="\(documentsPath)/tempFile.mp4"
DispatchQueue.main.async {
print("4")
urlData.write(toFile: filePath, atomically: true)
PHPhotoLibrary.shared().performChanges({
print("5")
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: filePath))
}) { completed, error in
print("6")
if completed {
print("Video is saved!")
}else{
print("7: ",filePath)
}
}
}
}else{
print("8")
}
}
}
}

How to create a button which counts how many times it's being pressed and then activates a different function

How to create a button which counts how many user presses and then activate a different sound after a certain number of presses?
#IBAction func button(_ sender: UIButton) {
var buttonCount: Int
buttonAnim.startCanvasAnimation()
let path = Bundle.main.path(forResource: "test", ofType:"wav")!
let url = URL(fileURLWithPath: path)
let path2 = Bundle.main.path(forResource: "stop-it", ofType:"mp3")!
let url2 = URL(fileURLWithPath: path2)
buttonCount = 0
buttonCount = buttonCount + 1
if buttonCount == 10 {
do {
let sound2 = try AVAudioPlayer(contentsOf: url2)
bombSoundEffect2 = sound2
sound2.play()
} catch {
// couldn't load file :(
}
}else{
do {
let sound = try AVAudioPlayer(contentsOf: url)
bombSoundEffect = sound
sound.play()
} catch {
// couldn't load file :(
}
}
}
Here's my button code, I wish make it add on into an Int variable and when that variable reaches 5, it will reset itself and also play a different sound.
edit: I've edited the code, but it says there that the if portion will never be executed.
Declare var buttonCount = 0 out side of the function, and rest it in if condition.
class ViewController: UIViewController {
#IBOutlet weak var dateLabelOutlet: UILabel!
var buttonCount: Int = 0
#IBAction func button(_ sender: UIButton) {
buttonAnim.startCanvasAnimation()
let path = Bundle.main.path(forResource: "test", ofType:"wav")!
let url = URL(fileURLWithPath: path)
let path2 = Bundle.main.path(forResource: "stop-it", ofType:"mp3")!
let url2 = URL(fileURLWithPath: path2)
buttonCount = buttonCount + 1
if buttonCount == 10 {
do {
let sound2 = try AVAudioPlayer(contentsOf: url2)
bombSoundEffect2 = sound2
sound2.play()
} catch {
// couldn't load file :(
}
}else{
do {
let sound = try AVAudioPlayer(contentsOf: url)
bombSoundEffect = sound
sound.play()
} catch {
// couldn't load file :(
}
}
}
}

how to play audio from parse.com in swift 2

i am trying to play audio from parse.com. I am getting the pffile but unable to play audio.
func testing() {
let query = PFQuery(className: "Attractions")
query.whereKey("objectId", equalTo: "hDyP0SwbAQ")
query.findObjectsInBackgroundWithBlock { (result, error) -> Void in
for obj in result! {
let path = obj.objectForKey("attraction_file") as! PFFile
self.playWithURL(path)
}
}
}
func playWithURL(url:PFFile) {
do {
let audioPlayer = try! AVAudioPlayer(contentsOfURL: url)
audioPlayer.prepareToPlay()
audioPlayer.play()
}
}
Thanks In Advance
I Found Answer.
earlier i was using AVAudioPlayer thats why i was getting the error.
now i am using AVPlayer and my code is working perfect.
var avAudioPlayer: AVPlayer? // declared in class
func testing() {
let query = PFQuery(className: "Attractions")
query.whereKey("objectId", equalTo: "hDyP0SwbAQ")
query.findObjectsInBackgroundWithBlock { (result, error) -> Void in
for obj in result! {
let path = obj.objectForKey("SongFile") as! PFFile
self.playWithURL(path)
}
}
}
fun playWithUrl(url : String) {
self.avAudioPlayer = AVPlayer(URL: NSURL(string: url!)!)
avAudioPlayer?.play()
}

Compress video size before attach to an email in swift

Previous, I have ask for how to attach video then send via email. Now it working. Advised by some friend from this website.
I found new problem that video size is very large and larger than send with default email app in iOS for same video file.
Please advice me how to compress video file before attach to an email application.
Thank you everyone.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
if let myImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
image = info[UIImagePickerControllerOriginalImage] as! UIImage
self.dismissViewControllerAnimated(false, completion: nil)
sendmail()
}
else {
//picker.videoQuality = UIImagePickerControllerQualityTypeLow
videoURL = info[UIImagePickerControllerMediaURL] as! NSURL
self.dismissViewControllerAnimated(true, completion: nil)
sendmailVDO()
}
}
Below is the code for Compress video by half of the actual size
var assetWriter:AVAssetWriter?
var assetReader:AVAssetReader?
let bitrate:NSNumber = NSNumber(value:250000)
func compressFile(urlToCompress: URL, outputURL: URL, completion:#escaping (URL)->Void){
//video file to make the asset
var audioFinished = false
var videoFinished = false
let asset = AVAsset(url: urlToCompress);
let duration = asset.duration
let durationTime = CMTimeGetSeconds(duration)
print("Video Actual Duration -- \(durationTime)")
//create asset reader
do{
assetReader = try AVAssetReader(asset: asset)
} catch{
assetReader = nil
}
guard let reader = assetReader else{
fatalError("Could not initalize asset reader probably failed its try catch")
}
let videoTrack = asset.tracks(withMediaType: AVMediaType.video).first!
let audioTrack = asset.tracks(withMediaType: AVMediaType.audio).first!
let videoReaderSettings: [String:Any] = [(kCVPixelBufferPixelFormatTypeKey as String?)!:kCVPixelFormatType_32ARGB ]
// ADJUST BIT RATE OF VIDEO HERE
let videoSettings:[String:Any] = [
AVVideoCompressionPropertiesKey: [AVVideoAverageBitRateKey:self.bitrate],
AVVideoCodecKey: AVVideoCodecType.h264,
AVVideoHeightKey: videoTrack.naturalSize.height,
AVVideoWidthKey: videoTrack.naturalSize.width
]
let assetReaderVideoOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings)
let assetReaderAudioOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil)
if reader.canAdd(assetReaderVideoOutput){
reader.add(assetReaderVideoOutput)
}else{
fatalError("Couldn't add video output reader")
}
if reader.canAdd(assetReaderAudioOutput){
reader.add(assetReaderAudioOutput)
}else{
fatalError("Couldn't add audio output reader")
}
let audioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil)
let videoInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoSettings)
videoInput.transform = videoTrack.preferredTransform
//we need to add samples to the video input
let videoInputQueue = DispatchQueue(label: "videoQueue")
let audioInputQueue = DispatchQueue(label: "audioQueue")
do{
assetWriter = try AVAssetWriter(outputURL: outputURL, fileType: AVFileType.mov)
}catch{
assetWriter = nil
}
guard let writer = assetWriter else{
fatalError("assetWriter was nil")
}
writer.shouldOptimizeForNetworkUse = true
writer.add(videoInput)
writer.add(audioInput)
writer.startWriting()
reader.startReading()
writer.startSession(atSourceTime: kCMTimeZero)
let closeWriter:()->Void = {
if (audioFinished && videoFinished){
self.assetWriter?.finishWriting(completionHandler: {
print("------ Finish Video Compressing")
self.checkFileSize(sizeUrl: (self.assetWriter?.outputURL)!, message: "The file size of the compressed file is: ")
completion((self.assetWriter?.outputURL)!)
})
self.assetReader?.cancelReading()
}
}
audioInput.requestMediaDataWhenReady(on: audioInputQueue) {
while(audioInput.isReadyForMoreMediaData){
let sample = assetReaderAudioOutput.copyNextSampleBuffer()
if (sample != nil){
audioInput.append(sample!)
}else{
audioInput.markAsFinished()
DispatchQueue.main.async {
audioFinished = true
closeWriter()
}
break;
}
}
}
videoInput.requestMediaDataWhenReady(on: videoInputQueue) {
//request data here
while(videoInput.isReadyForMoreMediaData){
let sample = assetReaderVideoOutput.copyNextSampleBuffer()
if (sample != nil){
let timeStamp = CMSampleBufferGetPresentationTimeStamp(sample!)
let timeSecond = CMTimeGetSeconds(timeStamp)
let per = timeSecond / durationTime
print("Duration --- \(per)")
DispatchQueue.main.async {
self.progress.progress = Float(per)
}
videoInput.append(sample!)
}else{
videoInput.markAsFinished()
DispatchQueue.main.async {
videoFinished = true
self.progress.progress = 1.0
closeWriter()
}
break;
}
}
}
}
You can also display the progress of video compression.

Resources