swiftavfoundationhttp-live-streamingavkitm3u

Video URL not playing in my Swift app (Play button is disabled)


I have a link which I want to play inside my app:

https://video-m2se42aed.msigma.in/video/7282/0/1094/6498c142878c493e93d0e6a90312d6ea/ece_nt_bombay_1/master.m3u8?sd=10&b=1200&rebase=on

The view I am using to play videos:

import SwiftUI
import AVKit
import AVFoundation

struct MyView: UIViewControllerRepresentable {
    
    var videoURLString: String

    typealias UIViewControllerType = AVPlayerViewController
    
    func makeUIViewController(context: Context) -> AVPlayerViewController {
           // Return MyViewController instance
        if let url = URL(string: videoURLString) {
            let player = AVPlayer(url: url)
            let playerViewController = AVPlayerViewController()
            playerViewController.player = player
            return playerViewController
        }
        return AVPlayerViewController()
       }
       
       func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {
       }
}

Then I put it inside another Swiftui view and give it a frame.

When I open the app in simulator or a real device I get:

simulator player disabled

When I put this url in a Chrome tab I get: m3u8 playlist text

I expect the video to play. I have tried using third party video players and SFSafariBrowser to play the url, but it did not help.

Please help me understand what am I doing wrong here and how this can be corrected.


Solution

  • Your link is a m3u8 playlist, its tags identify it as a HTTP Live Streaming (HLS), Apple's extension of the m3u format. Theoretically, AVPlayer should be able to play those playlists.

    Testing with urls like https://m3u8play.dev/?url=https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8 shows that AVPlayer actually can deal with this format. Searching StackOverflow for "play m3u8" shows several questions that point to the fact that AVPlayer seems to be picky about how the playlist manifest is constructed.

    I can't tell yet what's wrong with your playlist, and, if possible, I would recommend you fixing those playlists at the streaming source.

    But if it's this what you have, I have another solution: In your linked m3u8 playlist there is a URI component that can be extracted manually and used as a playable URL. In case you have many playlists in the same form, you can use this to extract the URL:

    // Get first "#EXT-X-STREAM-INF" URI item from given playlist URL
        func getStreamUrl(playlistUrl: URL) -> URL? {
            do {
                let playlist = try String(contentsOf: playlistUrl)
                let playlistLines = playlist.components(separatedBy: .newlines).filter { !$0.isEmpty }        
                guard let streamComponentIndex = playlistLines.firstIndex(where: { $0.starts(with: "#EXT-X-STREAM-INF:") }) else { return nil }
                let streamComponent = playlistLines[streamComponentIndex + 1]
                let streamUrl = playlistUrl.deletingLastPathComponent().appendingPathComponent(streamComponent, conformingTo: .m3uPlaylist)
                
                print(streamUrl.absoluteString)
                return streamUrl
                
            } catch {
                print("ERROR:", error)
            }  
            return nil 
        }
    

    use it like:

    let url = "https://video-m2se42aed.msigma.in/video/7282/0/1094/6498c142878c493e93d0e6a90312d6ea/ece_nt_bombay_1/master.m3u8"
    let streamUrl = getStreamUrl(playlistUrl: videoUrl)!
    // "streamUrl: https://video-m2se42aed.msigma.in/video/7282/0/1094/6498c142878c493e93d0e6a90312d6ea/ece_nt_bombay_1/media-1/stream.m3u8"
    

    Another option:

    I noticed your link plays fine in VLC media player, you could try using VLCKit instead of AVPlayer.


    UPDATE:

    I found something that looks like the cause of your problem: In the m3u8 playlist, your stream is specified like this:

    #EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=390562,BANDWIDTH=603703,CODECS="avc1.4D401F,mp4a.40.2",RESOLUTION=720x576
    media-1/stream.m3u8
    

    I downloaded your "media.ts" stream (linked in "stream.m3u8") with Safari and checked the codec type with MediaInfo. It shows as H.264 Main Profile level 3.1, which according to this Apple FAQ should have a CODECS value of "avc1.4d001f", not "avc1.4D401F".