How to play a 60fps video at half speed with Swift & AVMutableComposition and AVPlayer on MacOS - swift

I am adding 60fps video files to an AVMutableComposition and I am wondering if its possible to play that composition back at half speed.
This is where its adding to the video track
do {
try videoTrack?.insertTimeRange(CMTimeRangeMake(start: start, duration: duration),
of: asset.tracks(withMediaType: AVMediaType.video)[0] ,
at: lastTime)
} catch {
print("Failed to insert video track")
}
And thats the part that plays it back in a window
let videoPlayer = AVPlayer(playerItem: playerItem)
playerLayer.player = videoPlayer
videoPlayer.play()
Any pointers to how the playback could be slowed down to 30fps?

videoPlayer.play()
videoPlayer.rate = 0.5
Seems to do the trick, but I don't know of a way to check if its playing 60fps at 30fps, or the default framerate at half speed.

Related

AVPlayer streaming 3m8u video not correct sizes

I want stream video on AVPlayer. Faced with video size problem. For example one video can display good
video1
but another video displaying like this
video2
i tryed to make some changes with AVPlayerLayer but it also have a problem, for example
let playerLayer = AVPlayerLayer.init(player: player)
var bounds:CGRect = view.layer.bounds
playerLayer.frame = view.bounds
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
view.layer.addSublayer(playerLayer)
but in this case some video "protrudes from the screen"
video1
but another ok.
Do i need calculate size of video dynamicaly? Or how i can get correct video sizes?

Black Screen when stream video with avkit

Hi I want to stream remote video on my app. URL is: http://test.ext/myvideo.mkv
I use AVKit with this code but screen and audio not works. I see only progress bar that go forward.
let player = AVPlayer(url: url)
// Create a new AVPlayerViewController and pass it a reference to the player.
let controller = AVPlayerViewController()
controller.player = player
controller.player?.automaticallyWaitsToMinimizeStalling = false
controller.player?.playImmediately(atRate: 1.0)
// Modally present the player and call the player's play() method when complete.
self.present(controller, animated: true) {
player.play()
}
AVPlayer don't support mkv video format.
Anyone have a solution for playing all video format ?
I've tested MobileVLCKit but it's too heavy (1,5Go)...

Failed to get video thumbnail from AVPlayer using Fairplay HLS

I'm trying to build a custom progress bar for a video player app in tvOS, and would like to show thumbnails of the video while the user scans the video.
I'm using AVPlayer and Fairplay HLS to play remote video files. I've tried to do this using 2 methods. One with AVAssetImageGenerator's copyCGImage, and the other with AVPlayerItemVideoOutput's copyPixelBuffer method. Both return nil.
When I tried with a local video file, the first method worked.
Method 1:
let imageGenerator = AVAssetImageGenerator(asset: playerItem.asset)
let progressSeconds = playerItem.duration.seconds * Double(progress)
let time = CMTime(seconds: progressSeconds, preferredTimescale: 5)
if let imageRef = try? imageGenerator.copyCGImage(at: time, actualTime: nil) {
image = UIImage(cgImage:imageRef)
}
Method 2:
let videoThumbnailsOutput = AVPlayerItemVideoOutput(pixelBufferAttributes: [String(kCVPixelBufferPixelFormatTypeKey): NSNumber(value: kCVPixelFormatType_32BGRA)])
player?.currentItem?.add(videoThumbnailsOutput)
if let pixelBuffer = videoThumbnailsOutput.copyPixelBuffer(forItemTime: time, itemTimeForDisplay: nil) {
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
Any ideas what I'm doing wrong or is there any other way?
Thanks!
This is usually done by making use of the trick play stream associated to your actual stream.
https://en.wikipedia.org/wiki/Trick_mode
You can find it declared with the key EXT-X-I-FRAME-STREAM-INF in the manifest of your HLS stream. A regex might be needed in order to parse its value.
"#EXT-X-I-FRAME-STREAM-INF[^#]*URI=[^#]*"
Once you have the URL of the trick play stream, you can use a paused instance of AVPlayer as a thumbnail. And when the user swipe left and right, you should seek the player in the thumbnail to show the right frame.

Sound for Scene Transition, that doesn't stutter

In SpriteKit (for those unfamiliar with it) there's a way to load and unload scenes, and a transition (visual) between them.
I'm trying to make a sound play between scenes, as they transition... that doesn't stutter.
So far, all the ways I've tried either create no sound, or the sound stutters, even using a sound manager, like this:
import AVFoundation
import SpriteKit
open class SoundManager {
static let soundStart = SKAction.playSoundFileNamed("ActionBeep_AP1.7", waitForCompletion: true)
static var coinSound = NSURL(fileURLWithPath:Bundle.main.path(forResource: "ActionBeep_AP1.7", ofType: "wav")!)
static var audioPlayer = AVAudioPlayer()
open static func playCoinSound(){
guard let soundToPlay = try? AVAudioPlayer(contentsOf: coinSound as URL) else {
fatalError("Failed to initialize the audio player with asset: \(coinSound)")
}
soundToPlay.prepareToPlay()
self.audioPlayer = soundToPlay
self.audioPlayer.play()
}
}
Anyone had any success making scene transition sounds run smoothly? I realise there's a lot going on during a scene transition, and that's probably not helping the sound engine. But think there must be a way to make a clear sound play during a scene transition.
And yes, I've tried with .caf and .mp3 and .wav files, all with different "compression" and raw states. I think it's how I play the sounds that's the problem, not the file type.
As crashoverride777 said, you need to change when you load the sound manager. You could set up a thread in your didMoveToView() function to minimize loading time:
DispatchQueue.global(qos: .userInitiated).async {
// Load your sound stuff
}
Now, you have your sound file loaded for whenever you need it, lag-free.

Playing the same sound at the same time? (swift, spritekit)

Im trying to play a pop sound whenever a ball is touched but if the ball is touched again, before the pop sound ends, the sound will not play. I want the pop sound to cut out and start playing again if the ball is touched over and over again. The code i have now is below...
let popSound = NSBundle.mainBundle().URLForResource("pop",withExtension: "wav")
let Pop = AVAudioPlayer(contentsOfURL: popSound, error: nil)
////this is in the touches begin function/////
if touchedNode==ball{
Pop.play()
}
//////////////////////////////////
I fixed it with the help of this post. AVAudioPlayer stop a sound and play it from the beginning
I needed to set the Pop.currentTime to = 0
if touchedNode==ball{
Pop.currentTime=0
Pop.play()
}