I'm writing a live TV application using Flowplayer 6.0.5.
I'm using the following code:
<div class="player">
<video>
<source type="application/x-mpegurl" src="http://10.10.11.101/response2/index.m3u8?ch=<?php echo $_SESSION['chnId']; ?>&request=playlist&session=<?php echo $sess_id; ?>">
</video>
</div>
var playero = $('.player').flowplayer({
autoplay: true
});
It's working fine during livestream, but when I switch channels or use seek I occasionally (about once in 10 times absolutely randomly) get this error:
When switching channels (same when using seek), I just send the request to server to change the playlist and then use
player.load();
I have searched everywhere but couldn't find why could this be happening.
Any help will be appreaciated, thanks!
Believe it or not, I suspect the issue is your app being mistaken for some Flash adverts provider.
Browsers don't think "Oh FlowPlayer? That one's okay", all they know is an SWF file embedded on the page is constantly loading various unique streams (like rotating a playlist of video adverts? Oh oh).
This now makes your app show same behaviour as those annoying Flash banners.
It is then auto-blocked (like all Flash banner ads are nowadays) until user chooses to enable playback.
I'm confused by seeking though. network activity did not show new requests but yet for you it gets blocked after a while? I tested this FlowPlayer link.
All I know is these things below will avoid auto block...
If the SWF is loaded from same server as .html that embeds, thats fine.
If the SWF is loading videos from same server as itself, thats fine.
If the SWF is loading a single video source, that's fine.
You're likely doing the first thing but it's not possible to do the second one since video is from RTMP server.
For yourself : Can PHP be used here as a "middle man" proxy? Basically for RTMP streaming, point your SWF input URL to the PHP file (so technically its always loading one file) but the PHP should Echo back any changed RTMP stream data (channel or seeked).
Please update your flowplayer version from your flowplayer account page, because there are some fixes made in your version(6.0.5). You can review that fixes.
Related
Description
With the fast approaching removal of synchronous XMLHttpRequest (i.e.: Chrome 88 is removing this), I am looking for the next optimal alternative method to precache a video.
"Sychronous XMLHttpRequest is a horrible idea" -
said no one ever
Yes, you're right for most scenarios but this is different.
Previously
On android and ios, the company I work for has an SDK that opens a webview in the background, injects HTML into it and waits for the onload event to fire. This notifies the SDK when the webview is ready to be shown to the user.
It is imperative that when a video plays there is NO buffering whatsoever for the best possible experience.
This is why when the webview is loading in the background, we precache the video synchronously with XMLHttpRequest (which by consequence, delays the onload event from being fired).
Possible solutions
We've thought about some different solutions, and they each have their pros and cons; here are a few:
Preload content via <link rel="preload" ... />
Embed the video within the index.html page in base64 (if the video weights 2-3Mo, it'll weigh 30% more after converting to base64)
(1) is the cleanest method, but requires some heavy changes on our backend for various reasons. There is also no guarantee that the video will be fully cached by the time the browser/webview appears. There is no guarantee that the priority of the precaching will be the same across webviews and mobile browsers. Users can deactivate the precaching features, for example, in their Chrome configuration. It also does not work when the connection is 4G or lower (sigh).
(2) is a hacky and unoptimized method but is relatively simple to implement compared to (1)
Question
What is the next best method to precache a video in the background of a webview/mobile browser that:
Guarantees (or closely guarantees) no buffering when the video is played
Is done within webview/browser
Is (preferably) cross mobile browser/webview compatible
(preferably and not required) delays the onload event from being triggered
Note: not all users may have a 4g or wifi connection.
Note2: tag is in autoplay
To guarantee that there is no buffering when the video is played, the video can first be downloaded as a blob using the native fetch API and then converted to objectURL using window.URL.createObjectURL. This URL can then be used as the source for video element
This is a native API built-in the webview/browser and the compatibility report can be found here Can I use fetch
And instead of listening for onload event, listen for some other custom made event which you can manually control. This will give better flexibility in future also.
<script>
fetch('http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4').then(response => {
//Video Download Started
return response.blob();
}).then(data => {
//Video Downloaded"
let objectUrl = window.URL.createObjectURL(data);
document.querySelector("#myvideoPlayer").src = objectUrl;
//Trigger a custom event here
}).catch(error => {
// Log Error
})
</script>
<video controls id="myvideoPlayer"></video>
The new solution is by using the Cache API
caches = window.caches;
caches.open("app-assets").then((cache) => {
cache.add(linkToFileToBeCached).then(() => {
// Now the file is cached. Start rendering the app!
});
});
If you are loading an html page - use preload="auto" in the video tag. This tells the browser to download the entire video on page load (the default is preload = "metadata" which downloads 3-5% of the video).
You can then look at the mediaEvent canPlayThrough to fire to know when the video is ready to play(MDN reference).
Have you thought about streaming the video? A properly configured stream should begin playback immediately, and have little to no buffering as the adaptive bitrate algorithm can change the video delivered based on the device screen AND network throughput. api.video has a great service (with SDKs for iOS, Android and several web backends)
I'm trying to display a continuous video stream (live-stream) in a browser.
Description:
My client reported a video stream doesn't work in the Chrome browser. I thought it will be an easy case, I even tried to write a demo, to prove streaming should be available with just HTML5 native video tag:
https://github.com/mishaszu/streaming-video-demo
No problems with random video but:
the particular video stream on client-side doesn't work.
With html code:
<video id="video-block" width="320" height="200" autoplay>
<source src="url/to/my/video" type="video/mp4">
</video>
it shows loader for a while and dies.
What I know about the stream:
1. Codec used: H264-MPEG-4 AVC (part 10) (avc1)
2. It's a live stream, not a file, so I can't use command like MP4Box from a terminal with it
3. Because it's live stream it probably doesn't have "end of file"
4. I know it's not broken because VLC is able to display it
5. I tried native HTML 5 video tag with all Media type strings (just in case to check all codecs for mp4)
As I mentioned trying different mime types didn't help, I also tried to use MediaSource but I am really not sure how to use it with a live stream, as all information I found made assumptions:
a) waiting for resolve promise and then appends buffer
b) adding the event listener for updateend to appends buffer
I think in the case of a live stream it won't work.
Conclusion:
I found a lot of information about how a streamed file might contain metadata (at the beginning of the file or at the end)... and I ended up with a conclusion that maybe I do not fully understand what's going on.
Questions:
What's the proper way to handle the mp4 live stream?
If a native HTML video tag should support the live stream, how to debug it?
I thought that maybe I should look for something like HLS but for mp4 format?
I've went through the same - I needed to mux an incoming live stream from rtsp to HTML5 video, and sadly this may become non-trivial.
So, for a live stream you need a fragmented mp4 (check this SO question if you do not know what that is:). The is the isobmff specification, which sets rules on what boxes should be present in the stream. From my experience though browsers have their own quirks (had to debug chrome/firefox to find them) when it comes to a live stream. Chrome has chrome://media-internals/ tab, which shows the errors for all loaded players - this can help debugging as well.
So my shortlist to solve this would be:
1) If you say that VLC plays the stream, open the Messages window in VLC ( Tools -> Messages ), set severity to debug, and you should see the mp4 box info in there as the stream comes in, verify that moof boxes are present
2a) Load the stream in chrome, open chrome://media-internals/ in a new tab and inspect errors
2b) Chrome uses ffmpeg underneath, so you could try playing the stream with ffplay as well and check for any errors.
2c) You are actually incorrect about mp4box - you could simply load a number of starting bytes from the stream, save to a file and use mp4box or other tools on that (at worst it should complain about some corrupted boxes at the end if you cut a box short)
If none of 2a/2b/2c provide any relevant error info that you can fix yourself, update the question with the outputs from these, so that others have more info.
I'm trying to play an mp3 file and I want to jump to specific location in the file. In Chrome 33 on Windows, the file jumps the correct position (as compared with VLC playing the mp3 locally) but in Firefox 28 on Windows it plays too far forward and in Internet Explorer 11 it plays too far behind.
It used to work correctly in Firefox 27 and earlier.
Is there a better way of doing this?
EDIT: The problem doesn't even require SoundManager2. You can replicate the same issue with just the <audio> tag in Firefox. These two lines are all the code you need to reproduce it:
<audio autoplay id="audio" src="http://ivdemo.chaseits.co.uk/enron/20050204-4026(7550490)a.mp3" controls preload></audio>
<button onclick="javascript:document.getElementById('audio').currentTime = 10;">Jump to 10 secs "...be with us in, er, 1 minute... ok" </button>
Try it here: http://jsfiddle.net/cpickard/29Gt3/
EDIT: Tried with Firefox Nightly, no improvement. I have reported it as bug 994561 in bugzilla. Still looking for a workaround for now.
The problem lies in the VBR encoding of the mp3.
Download that mp3 to disk and convert it to fixed bit rate, say with Audacity.
Run the example from disk:
<audio autoplay id="audio" src="./converted.mp3" controls preload></audio>
<button onclick="javascript:document.getElementById('audio').currentTime = 10;">
Jump to 10 secs "...be with us in, er, 1 minute... ok" </button>
and it works fine for me.
So my suggestion for workaround is is to upload an alternative fixed-bit mp3 file in place of the one you are using. Then it should work in the current FFx.
I work on SoundJS and while implementing audio sprites recently ran into similar issues. According to the spec, setting the position of html audio playhead can be inaccurate by up to 300ms. So that could explain some of the issues you are seeing.
Interestingly, your fiddle plays correctly for me in FF 28 on win 8.1 if I just let it play through from the start.
There are also some known issues with audio length accuracy that may also have an effect, which you can read about here.
If you want precision, I would definitely recommend using Web Audio where possible or a library like SoundJS.
Hope that helps.
I met the same issue, and I solved it by converting my MP3 file to the CBR(Constant Bit Rate) format. Then, it can solve the inconsistent issue between the currentTime and the real sound.
Choose the CBR format
Steps:
Download and install "Audacity" (it's a free for any platform)
Open your MP3 file
Click [File] -> [Export] -> [Options] -> [Constant] (See: Converting MP3 to Constant Bit Rate)
Audacity will ask you to provide the LAME MP3 encoder
(See: [download and install the LAME MP3 encoder])
There will be no inconsistent/asynchronous issue.
Also see:
HTML5 audio starts from the wrong position in Firefox
Inconsistent seeking in HTML5 Audio player
tsungjung411#gmail.com
I just tried your code with another audio url here, it seemed to work and i did not experience a delay of any sort in Firefox( v29) which i did previously.
<audio autoplay id="audio" src="http://mediaelementjs.com/media/AirReview-Landmarks-02-ChasingCorporate.mp3" controls preload></audio>
I guess to jump around an audio file, your server must be configured properly.
The client sends byte range requests to seek and play certain regions of a file, so the server must response adequately:
In order to support seeking and playing back regions of the media that
aren't yet downloaded, Gecko uses HTTP 1.1 byte-range requests to
retrieve the media from the seek target position. In addition, if you
don't serve X-Content-Duration headers, Gecko uses byte-range requests
to seek to the end of the media (assuming you serve the Content-Length
header) in order to determine the duration of the media.
Hope this helps..
You could also try looking into Web Audio API for sound-effect-like playback which gives you some guarantees about the playback delays.
After testing the fiddle it is noticable that there is some issue with FF , anywho , after searching sometime , the issue is due to "Performance lag" , but the good news is that someone has found a solution to that issue , you may want to read this :
http://lowlag.alienbill.com/
a single script will solve it all.
I'm building a simple Javascript jukebox using the latest SoundManager2 for audio playback, with local MP3 files being the source. I've got file loading and playing sorted, and at the moment I'm trying to get access to the ID3 info of these MP3 files, but the onid3() callback is not firing. I'm using Flash and have verified that ID3 info is present in the files. Below is my implementation of onid3():
function playNextSongInQueue()
{
// Get the first element of the songQueue array
var nextSongInQueue = songQueue.shift();
// Start playback from the queue
var jukeboxTune = soundManager.createSound({
id: 'currentTune',
url: 'audio/' + nextSongInQueue.name,
onload: function() {
this.play();
},
onid3: function() {
alert('ID3 present!');
},
onfinish: function() {
this.destruct(); // Destroy this sound on finish
songFinish(); // Run the songFinish() function, so decide what to do next
}
});
jukeboxTune.load();
//jukeboxTune.play(); // The jukebox running!
songPlaying = true; // Set songPlaying flag
updateSongQueueDisplay(); // Refresh the song queue display (for debug)
return nextSongInQueue.name;
}
The other callbacks work fine, but the onid3() alert never comes up. I even separated the load and play portions of audio playback to see if that helped. SoundManager spots that onid3() is there because it switches usePolicyFile to true - seeing as the MP3s are local I am assuming I don't need to worry about the cross-domain XML file.
Can anybody shed light on why this isn't working? I've scoured Google looking for implementations that work but have come up with nothing helpful. I've seen Jacob Seidelin's pure Javascript workaround but would rather stick with SoundManager if possible, and would rather not use a PHP solution.
Thanks,
Adam
This problem is probably too esoteric for any solid answers, so I decided to investigate possible Javascript solutions outside the SM2 library.
I started with Nihilogic's library for reading ID3v1 tags (at http://blog.nihilogic.dk/2008/08/reading-id3-tags-with-javascript.html), but moved to antimatter15's js-id3v2 library (https://github.com/antimatter15/js-id3v2) as it can read ID3v2 tags. Adapting code from the provided example I have managed to successfully parse the main tags required when the MP3s are loaded via the <input> control.
For local files, i speak of "user local files" (not "server" local files) i get some success with id3v2.js
To get ID3, SM2 need a cross domain on the mp3 host, if it's another domain.
Plus i have encountered difficulties with Soundcloud as they redirect MP3 to dynamic Amazon S3 storage... so i have to do a PHP script to guest final URL and then SM2 can get proper crossdomain.xml (Check https://getsatisfaction.com/schillmania/topics/displaying_waveformdata_of_soundcloud_hosted_track_prompts_securityerror_error_2122 )
The problem is both S3 links and local user files (blob) do have a short expiration delay.
Good luck !
Users run my HTML files locally, straight from a CD.
I want to allow them to choose a bunch of videos and create a playlist on the fly.
This works very well if I run a web server but when I run the HTML itself it fails.
The player is created (using swfobject) and all my other code runs but playerReady never fires so I can never get the current play list to add to it.
Any ideas on how I can fix this or, more likely, work around it?
If the player is created, but you're not getting a playerReady, one of two things could be happening.
There's another playerReady on the page that's catching your playerReady. Make sure that there's just one playerReady on the page.
You haven't enabled JavaScript access for Flash. The code for that would look like this:
SWFObject:
var so = new SWFObject('player.swf','ply','470','320','9','#000000');
so.addParam('allowfullscreen','true');
so.addParam('allowscriptaccess','always');
so.addParam('wmode','opaque');
so.addVariable('file','video.flv');
so.write('mediaspace');
I should also note that there are some additional Flash security restrictions because you're accessing the player from disk. Namely, you can't access both a disk source and a network source (the Internet) simultaneously.
Best,
Zach
Developer, LongTail Video