Friday, May 17, 2024
HomeiOS DevelopmentPlay movies one after the other with none delay or lag iOS...

Play movies one after the other with none delay or lag iOS Swift


I am at the moment engaged on enjoying movies utilizing URLs within the .m3u8 format. Initially, I used AVAudioPlayer to instantly play the .m3u8 URL.

Nevertheless, I encountered a problem the place poor community power on the consumer’s aspect resulted within the video not enjoying easily and displaying progress correctly.

To deal with this, I made a decision to fetch the sub-URLs from the principle .m3u8 URL and play them accordingly.

After fetching, I obtained 4 decision URLs as follows:

Principal Url: -  ***********************playlist.m3u8

Sub urls Url: -  [360p/video.m3u8, 480p/video.m3u8, 720p/video.m3u8, 240p/video.m3u8]

Subsequent, I fetched the bottom decision(240p) URLs to acquire sub-URLs and efficiently retrieved the time-frame of the video, however in .ts format. To proceed, I saved the primary two segments of the video within the .ts format. Nevertheless, I encountered a problem when making an attempt to play the .ts format utilizing AVQueuePlayer.

After fetching, I obtained 4 Sub URLs as follows:

[video0.ts,video1.ts,video2.ts]

To resolve this, I tried to transform the .ts format to .mp4 with out success. It appears direct conversion from .ts to .mp4 shouldn’t be possible.

Under is the related portion of my code:

import UIKit
import AVFoundation

class VideoUrlSegments: UIViewController {

var participant: AVQueuePlayer!
var playerLayer: AVPlayerLayer!
var playlistURL: URL?
var segmentURLsResoltuions: [URL] = []
var currentSegmentIndex: Int = 0
var scrollTimer = Timer()
var segmentURLsSecondsResoltuions: [URL] = []
var currentSecondsResoltuionsIndex: Int = 0

@IBOutlet weak var mianVwPlayer: UIView!

override func viewDidLoad() {
    tremendous.viewDidLoad()
    // Initialize AVQueuePlayer
    participant = AVQueuePlayer()
    playerLayer = AVPlayerLayer(participant: participant)
    playerLayer.body = mianVwPlayer.bounds // Set body relative to mianVwPlayer
    mianVwPlayer.layer.addSublayer(playerLayer)
    participant.isMuted = true
    participant.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1, preferredTimescale: 1), queue: DispatchQueue.principal) { [self] (CMTime) -> Void in
        if let currentItem = self.participant.currentItem {
            let period = CMTimeGetSeconds(currentItem.period)
            let currentTime = CMTimeGetSeconds(currentItem.currentTime())
            if currentTime != 0 {
                scrollTimer.invalidate()
                print("---------  Video Present time:  ---------", Float(currentTime/period))
            }
        }
    }
    
    // Change the URL along with your playlist URL
    playlistURL = URL(string: "***********************playlist.m3u8")
    
    // Begin downloading and enjoying segments
    downloadTheResolutionsUrls()
}

// Perform to obtain the decision URLs from the playlist
func downloadTheResolutionsUrls() {
    guard let playlistURL = playlistURL else {
        print("Invalid playlist URL")
        return
    }
    
    let session = URLSession.shared
    let activity = session.dataTask(with: playlistURL) { [weak self] information, response, error in
        guard let self = self else { return }
        
        if let error = error {
            print("Error: (error)")
            return
        }
        
        guard let information = information, let playlistString = String(information: information, encoding: .utf8) else {
            print("No information obtained or information not convertible to string")
            return
        }
        
        // Parse playlistString to extract decision URLs
        self.segmentURLsResoltuions = self.extractSubUrls(from: playlistString)
        print(self.segmentURLsResoltuions) //[360p/video.m3u8, 480p/video.m3u8, 720p/video.m3u8, 240p/video.m3u8]
        
        
        // Right here i obtained 4 URLs on the time. How i can handle all resolutions? Or do it is advisable to test community power? Now i get the seconds segments.
        self.downloadTheSegmentUrls()
    }
    activity.resume()
}



@objc func addedScrollTimer() {
    print("Taking part in Begin")
}

// Perform to obtain the section URLs for the primary decision
func downloadTheSegmentUrls() {
    let url = segmentURLsResoltuions[currentSegmentIndex]
    let urlMain = URL(string: "***********************" + url.absoluteString)
    
    let activity = URLSession.shared.dataTask(with: URLRequest(url: urlMain!)) { [weak self] information, response, error in
        guard let self = self else { return }
        
        if let error = error {
            print("Error downloading section: (error)")
            return
        }
        
        guard let information = information, let playlistString = String(information: information, encoding: .utf8) else {
            print("No information obtained or information not convertible to string")
            return
        }
        
        // Parse playlistString to extract section URLs
        self.segmentURLsSecondsResoltuions = self.extractSubUrls(from: playlistString)
        
        print(self.segmentURLsSecondsResoltuions)
        
        // Right here i obtained a number of URLs on the time on the primary decision, so now i've to get and save this primary URL information.
        self.downloadTheFirstSegmentAndSaveInLocal()
    }
    activity.resume()
}

// Perform to obtain the primary section and reserve it domestically
func downloadTheFirstSegmentAndSaveInLocal() {
    
    let url = segmentURLsSecondsResoltuions[currentSecondsResoltuionsIndex]
    let urlMain = URL(string: "***********************" + url.absoluteString)
    
    let activity = URLSession.shared.dataTask(with: URLRequest(url: urlMain!)) { [weak self] information, response, error in
        guard let self = self else { return }
        
        if let error = error {
            print("Error downloading section: (error)")
            return
        }
        
        guard let information = information else {
            print("No information obtained for section")
            return
        }
        
        let fileName = "(UUID().uuidString).ts"
        let tempFileURL = self.getFileURL(fileName)
        do {
            strive information.write(to: tempFileURL)
            
            let asset = AVAsset(url: tempFileURL)
            let playerItem = AVPlayerItem(asset: asset)
            self.participant.insert(playerItem, after: nil)
            DispatchQueue.principal.async {
                self.participant.play()
                self.participant.addObserver(self, forKeyPath: "currentItem.standing", choices: .new, context: nil)
            }
        } catch {
            print("Error saving .ts file: (error)")
        }
    }
    activity.resume()
}

// Perform to extract URLs from playlist string
func extractSubUrls(from playlistString: String) -> [URL] {
    var subUrls: [URL] = []
    // Break up playlistString by traces
    let traces = playlistString.parts(separatedBy: .newlines)
    // Filter out traces beginning with '#' (feedback) and empty traces
    let validLines = traces.filter { !$0.begins(with: "#") && !$0.isEmpty }
    // Assemble URLs from legitimate traces
    for line in validLines {
        if let url = URL(string: line) {
            subUrls.append(url)
        }
    }
    return subUrls
}

// Perform to get file URL
func getFileURL(_ fileName: String) -> URL {
    guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
        fatalError("Did not get paperwork listing")
    }
    return documentsDirectory.appendingPathComponent(fileName)
}

// Perform to watch participant standing adjustments
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "currentItem.standing",
       let playerItem = (object as? AVPlayer)?.currentItem,
       playerItem.standing == .failed {
        if let error = playerItem.error as NSError? {
            let errorCode = error.code
            print("Error Code: (errorCode)")
            let url: URL? = (participant.currentItem?.asset as? AVURLAsset)?.url
            print(url as Any)
        }
    } else if keyPath == "currentItem.standing",
              let playerItem = (object as? AVPlayer)?.currentItem,
              playerItem.standing == .readyToPlay {
        (object as? AVPlayer)?.play()
      }
     }
   }

Might somebody please present steering on reaching a selected performance? I’ve tried implementation however have not achieved the specified outcomes but.

My purpose is to allow fast loading of movies on the display screen and easy playback with none lag, much like the expertise on Instagram’s feed sections.

Are there different approaches that may provide higher outcomes?

Any assist could be enormously appreciated.

Thanks upfront.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular