AVPlayer won't play HLS stream URL with special characters - ios

I want to play a streaming video on iOS. Users upload the video with special characters in the filename (😂.mp4). It works well when AVPlayer plays it with the encoded URL (https://.../%F0%9F%98%82.mp4). But if I use AWS MediaConvert to convert it to M3U8 (https://.../%F0%9F%98%82.m3u8), AVPlayer plays it with the error:
https://.../%F0%9F%98%82_hls_qvbr_7_2000k_00001.ts CoreMediaErrorDomain -12938 - HTTP 404: File Not Found.
I checked the content of M3U8, names look correct:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:BANDWIDTH=232969,AVERAGE-BANDWIDTH=231047,CODECS="avc1.77.30,mp4a.40.2",RESOLUTION=640x480,FRAME-RATE=30.000
😂_hls_qvbr_9_6000k.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=205897,AVERAGE-BANDWIDTH=204707,CODECS="avc1.77.30,mp4a.40.2",RESOLUTION=640x480,FRAME-RATE=30.000
😂_hls_qvbr_7_2000k.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:1
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:10,
😂_hls_qvbr_7_2000k_00001.ts
#EXTINF:10,
😂_hls_qvbr_7_2000k_00002.ts
...
I tried the same URL with the VLC player, it can play. Can anyone help me?

Related

How to change url from m3u8 to .ts

I'm trying to make an iptv link work on my receiver
this is the original link that i want to convert
http://s7.iapi.com:8000/re-NBA/index.m3u8?token=BzyIVQOtO77MTw
and this is the format that i want to reach in the end.
http://pro-vision.dyndns.pro:12580/live/laurent/laurent/2791.ts
An m3u8 file is just a text file that acts as an index for media streams - it will contain 'pointers' to the location of video and audio streams themselves.
A TS file is a 'container' that contains the video and audio streams themselves - i.e. the actual video and audio data.
You can't simply convert any m3u8 to a ts file or stream, but you can extract from the m3u8 file a ts file URL, which maybe is what you want.
If you look at the overview section of the m3u8 definition there is a very simple example which is maybe the best way of understanding this:
https://datatracker.ietf.org/doc/html/draft-pantos-http-live-streaming-19
The m3u8 file includes the ts references and can be seen in this extract from the above document:
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXTINF:9.009,
http://media.example.com/first.ts
#EXTINF:9.009,
http://media.example.com/second.ts
#EXTINF:3.003,
http://media.example.com/third.ts
The numbers here refer to the length of the stream. More complex examples allow you have multiple variants of a particular stream, to allow different bit rate versions of a video for Adaptive Bit Rate (ABR) streaming for example.

HLS 'EVENT' playlists failing to start in players

I have HLS playlists that look like this:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:10
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.97667,
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence0.ts
#EXTINF:9.97667,
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence1.ts
#EXTINF:9.97667,
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence2.ts
#EXTINF:9.97667,
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence3.ts
They are of EVENT type, meaning, chunks are appended as they become available, and when all chunks are there, an #EXT-X-ENDLIST tag is appended at the end.
So when all chunks are uploaded, we end up with a playlist that looks something like:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:10
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.97667,
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence0.ts
#EXTINF:9.97667,
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence1.ts
#EXTINF:9.97667,
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence2.ts
#EXTINF:9.97667,
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence3.ts
#EXTINF:9.97667,
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence4.ts
#EXTINF:9.97667,
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence5.ts
#EXT-X-ENDLIST
We are seeing odd behaviour in all our clients. If you open the m3u8 playlist in iOS and Safari when the first chunk (or even after say, 3 chunks) are uploaded, the player will start playing the video as it should. Occasionally it will stop however, and be unable to resume. More often than not, it won't even begin playing.
Fully formed playlists (i.e. with an #EXT-X-ENDLIST tag) play perfectly. It's just when the playlist is partially done.
We have tried a variety of players: Quicktime, Safari, iOS, VLC, Flowplayer etc. All have a variety of issues, but this is the most pressing.
Any insight into where to look in solving this problem would be greatly appreciated.
Edit: We have tried HLS.js and it plays perfectly. Such a nice user experience too
Edit 2: To reproduce, I recommend having some sort of local HTTP server (I use python -m SimpleHTTPServer serving up a playlist above. Then literally append the files to the playlist to simulate the uploading of files, and watch the players break.
Edit 3: Okay, I have built a simple testing tool to observe the behaviour. https://github.com/dbousamra/m3u8-example Run node app.js and then try and open http://localhost:3001/playlist.m3u8 in Safari or whatever player you want. It should play fine, as it is a complete playlist.**
If however, you add a query param ?start=<some unix timestamp>, it will simulate appending of events, 1 chunk every 6 seconds, from that timestamp, until all chunks are done, at which point it will append an #EXT-X-ENDLIST line.
Example URL: http://localhost:3001/playlist.m3u8?start=1460092250872
Edit 5: I've got it up on Heroku now: http://guarded-mesa-71212.herokuapp.com/playlist.m3u8?start=
Here is what happened:
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:11
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
if you return the above file, safari will not request the next file at all, the playing just dead.
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:11
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.999367,
https://cammy-bucket-staging-sydney.s3.amazonaws.com/9fc1a264af66e8acb04953bc6634fb6e.ts
if you return the above, safari will request next file around 11/2 seconds, playing will not start at this point.
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:11
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.999367,
https://cammy-bucket-staging-sydney.s3.amazonaws.com/9fc1a264af66e8acb04953bc6634fb6e.ts
#EXTINF:9.968911,
https://cammy-bucket-staging-sydney.s3.amazonaws.com/3e52720b320379de8afc940c3d1b7d34.ts
if you return the above, safari will start playing because the available media 9.999367+9.968911 is great than EXT-X-TARGETDURATION, and you will see another request around 9.999367+9.968911+11/2, it's all about timing!
The #EXT-X-DISCONTINUITY tag is used to indicate changes in file format, encoding parameters, number of tracks, and so on. If the segments in the playlist are identical in regard to these things, you can remove the #EXT-X-DISCONTINUITY tags from the playlist - you don't need them.
Some clients may not be compatible with version 6 of the protocol. You don't appear to be using any version 6 specific features so try setting the version number to 3 to see if that helps.

HLS stream not working on Apple devices

I have a live RTSP stream that i have managed to transcode to HLS via VLC. Now it works perfect on Android and on desktop browsers (via flash).
But not on Apple (i can test it on iPad and desktop Safari on my virtual machine). I can see the player but when i press the 'play' button all i see is a black rectangle inside the player. On desktop Safari there is also a text 'Loading...' near the play/pause button and nothing else happens.
My HTML:
<video id="player" controls style="width:100%; height:100%">
<source src="http://178.79.164.114/playlist.m3u8" type="application/x-mpegURL">
</video>
The command for vlc:
vlc -I dummy rtsp://<stream-url> --sout '#transcode{width=320,height=240,fps=25,vcodec=h264,vb=256,acodec=none,venc=x264{aud,profile=baseline,level=30,keyint=30,bframes=0,ref=1,nocabac}}:std{access=livehttp{seglen=10,delsegs=true,numsegs=5,index=/path/to/server/directory/playlist.m3u8,index-url=http://178.79.164.114/seg-########.ts},mux=ts{use-key-frames},dst=/path/to/server/directory/seg-########.ts}'
And an example of the playlist file:
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:179
#EXTINF:9.60,
http://178.79.164.114/seg-00000179.ts
#EXTINF:9.60,
http://178.79.164.114/seg-00000180.ts
#EXTINF:9.60,
http://178.79.164.114/seg-00000181.ts
#EXTINF:9.61,
http://178.79.164.114/seg-00000182.ts
#EXTINF:9.59,
http://178.79.164.114/seg-00000183.ts
And here is the strange output of ffprobe http://178.79.164.114/playlist.m3u8 (why there are these N/A and the variant_bitrate is 0?). Maybe it can help:
Input #0, hls,applehttp, from 'http://178.79.164.114/playlist.m3u8':
Duration: N/A, start: 3995.330722, bitrate: N/A
Program 0
Metadata:
variant_bitrate : 0
Stream #0:0: Video: h264 (Constrained Baseline) ([27][0][0][0] / 0x001B), yuv420p, 320x240 [SAR 11:12 DAR 11:9], 25 fps, 25 tbr, 90k tbn, 50 tbc
I have also configured correct MIME types for .m3u8 and .ts files and spent a day searching and trying different options for the transcode command: width, height, bitrate, fps, different profiles and levels... - nothing works. But if i try some examples from apple (http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8) - all is fine, though it's not a live stream.
If anyone has any ideas or has a possibility to test my stream with the mediastreamvalidator - please help.
UPDATE
Now i'm experimenting with variant playlist but it changes nothing.
The player might expect muxed video and audio so add a silent audio track.
The Apple HLS documentation says:
The media segment files are normally produced by the stream segmenter, based on input from the encoder, and consist of a series of .ts files containing segments of an MPEG-2 Transport Stream carrying H.264 video and AAC, MP3, or AC-3 audio
Support for audio-only streams is mentioned in Technical Note TN2224 and the 7th revision of the protocol introduced support for alternate renditions (unmuxed streams) but this is done with EXT-X-MEDIA tags in a master playlist controlling the playback (yours is a media playlist).

AVPlayer seeking a HLS Audio Stream

I'm using AVPlayer to stream a hls stream. The issue I'm having is that I'm incapable of seeking to a time.
The seeking logic works fine with the Apple's example hls stream. It also works fine with the non-hls stream I have but we wanted to use hls on this project.
So my belief is that problem is more likely with our stream and how AVPlayer handles it.
The playlist.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=61378,CODECS="mp4a.40.34"
chunklist_w1105403169.m3u8
The chunklist_w1105403169.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:5015
#EXTINF:10.028,
media_w1105403169_5015.mp3
#EXTINF:10.036,
media_w1105403169_5016.mp3
#EXTINF:10.027,
media_w1105403169_5017.mp3
I have checked the stream using mediastreamvalidator and I do get:
Warning: (0:-16230) #EXT-X-ALLOW-CACHE should only be in master playlist
but its my understanding Apple ignores this flag.
I've no control over the stream but can request changes.
A cut down version of my implementation:
Setup of the player
AVPlayer *player = [[AVPlayer alloc] initWithURL:url];
Seeking back by x seconds
- (void)trySeekBackBy:(NSTimeInterval )seconds
CMTime minus = CMTimeMakeWithSeconds(seconds, 1);
CMTime time = CMTimeSubtract(self.currentTime, minus);
//check that time is within the seek able range.
if ([self canSeekToTime:time]) {
//I normally just seekToTime:
[self seekToTime:time toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
}
/ /else work down till we can find a range we can seek to
}

Encoding SWF to video with Melt

I'm doing a project which requires converting SWF movies to H.264 video on server-side, to be able to play them both in Flash player and on iPhone/iPad. And I really got stuck.
I'm using Melt from http://www.mltframework.org/ and this is my command-line:
melt movie.swf -consumer avformat:video.mp4 r=30 s=640x360 f=mp4 acodec=aac ab=128k ar=48000 vcodec=libx264 b=1000k an=1
It does play in Flash player, but fails to play on iDevices. I googled for iPhone video requirements and it seems my video files do satisfy them(frame size, framerate and bitrate). What settings should I change to make it play?
I've spent a lot of time in google but managed to gather all the pieces, so these are parameters that work for iPhone:
r=30 s=640x360 f=mp4 acodec=aac ab=128k ar=48000 vcodec=libx264 level=30 b=1024k flags=+loop+mv4 cmp=256 partitions=+parti4x4+parti8x8+partp4x4+partp8x8+partb8x8 me_method=hex subq=7 trellis=1 refs=1 bf=0 flags2=+mixed_refs-wpred-dct8x8 coder=0 wpredp=0 me_range=16 g=250 keyint_min=25 sc_threshold=40 i_qfactor=0.71 qmin=10 qmax=51 qdiff=4 maxrate=10M bufsize=10M an=1 threads=0
Also, I use faac -w to convert audio to appropriate format and MP4Box to join video and sound.

Resources