From c853aa46eb1b04c81e1c93e0aecf1436b6766bf8 Mon Sep 17 00:00:00 2001 From: Henry Rodrick Date: Thu, 17 Aug 2017 00:54:10 +0100 Subject: [PATCH 1/3] Add basic video streaming example --- examples/browser-video-streaming/README.md | 2 ++ examples/browser-video-streaming/index.html | 10 ++++++ examples/browser-video-streaming/streaming.js | 34 +++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 examples/browser-video-streaming/README.md create mode 100644 examples/browser-video-streaming/index.html create mode 100644 examples/browser-video-streaming/streaming.js diff --git a/examples/browser-video-streaming/README.md b/examples/browser-video-streaming/README.md new file mode 100644 index 0000000000..38ddb7d356 --- /dev/null +++ b/examples/browser-video-streaming/README.md @@ -0,0 +1,2 @@ +# Streaming video in the browser over IPFS + diff --git a/examples/browser-video-streaming/index.html b/examples/browser-video-streaming/index.html new file mode 100644 index 0000000000..74ae11d6d5 --- /dev/null +++ b/examples/browser-video-streaming/index.html @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/examples/browser-video-streaming/streaming.js b/examples/browser-video-streaming/streaming.js new file mode 100644 index 0000000000..21c1f706b3 --- /dev/null +++ b/examples/browser-video-streaming/streaming.js @@ -0,0 +1,34 @@ +'use strict' + +/* global Hls Ipfs HlsjsIpfsLoader */ +/* eslint-env browser */ + +const testhash = 'QmdpAidwAsBGptFB3b6A9Pyi5coEbgjHrL3K2Qrsutmj9K' +const repoPath = 'ipfs-' + Math.random() +const ipfs = new Ipfs({ + init: false, + start: false, + repo: repoPath +}) + +ipfs.init((err) => { + if (err) { + throw err + } + + ipfs.start(() => { + Hls.DefaultConfig.loader = HlsjsIpfsLoader + Hls.DefaultConfig.debug = false + if (Hls.isSupported()) { + const video = document.getElementById('video') + const hls = new Hls() + hls.config.ipfs = ipfs + hls.config.ipfsHash = testhash + hls.loadSource('master.m3u8') + hls.attachMedia(video) + hls.on(Hls.Events.MANIFEST_PARSED, () => { + video.play() + }) + } + }) +}) From 11e847a73e8dba443dabd35b1ae124a11a21e19a Mon Sep 17 00:00:00 2001 From: Henry Rodrick Date: Fri, 18 Aug 2017 03:12:14 +0100 Subject: [PATCH 2/3] Write README for browser-video-streaming example --- examples/browser-video-streaming/README.md | 53 ++++++++++++++++++++- examples/browser-video-streaming/index.html | 3 +- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/examples/browser-video-streaming/README.md b/examples/browser-video-streaming/README.md index 38ddb7d356..14afdcfdde 100644 --- a/examples/browser-video-streaming/README.md +++ b/examples/browser-video-streaming/README.md @@ -1,2 +1,53 @@ -# Streaming video in the browser over IPFS +# Streaming video in the browser with js-ipfs and hls.js + +This example shows a method for video/audio streaming in the browser over IPFS. + +## Why use HLS? +HLS (Apple's HTTP Live Streaming) is one of several protocols currently available for adaptive bitrate streaming. + +One of the advantages of HLS is that the content can be hosted on a plain old web server without any special server-side logic. The way this works is that the original content (the stream or video/audio file) is split up into small MPEG2-TS segments before putting it on the web server. The segments can then be fetched by the HLS player on the fly and spliced together to a continuous stream. + +In addition to the segments there are also a so-called manifests (m3u8 files) which contain metadata about segments and their bitrates. A stream can contain segments of multiple bitrates and the HLS player will automatically select the optimal bitrate based on client performance. + +The fact that HLS content is just "a bunch of files" makes it a good choice for IPFS (another protocol that works like this is MPEG-DASH, which could certainly be a good choice as well). Furthermore, the [hls.js](https://github.com/video-dev/hls.js) library enables straightforward integration with the HTML5 video element. + +## hlsjs-ipfs-loader +The hls.js library ships with a HTTP based content loader, but it's fortunately possible to configure custom content loaders as well, which is what makes IPFS streaming possible in this case. A loader implementation that fetches content using js-ipfs can be found [here](https://www.npmjs.com/package/hlsjs-ipfs-loader), and is easy to integrate on a regular HTML page: + +```html + + + +``` + +## Generating HLS content +In order for any of the above to be useful, we also need to have a way to actually generate a HLS manifests and MPEG2-TS segments from an arbitrary video/audio file. Luckily, most new builds of `ffmpeg` are compiled with this capability. + +For example, say we have a directory containing a video file `BigBuckBunny_320x180.mp4`. We can then create a sub directory and generate the HLS data there, and finally add it to IPFS: + +```bash +> mkdir hls-bunny +> cd hls-bunny +> ffmpeg -i ../BigBuckBunny_320x180.mp4 -profile:v baseline -level 3.0 -start_number 0 -hls_time 5 -hls_list_size 0 -f hls master.m3u8 +> ifps add -Qr . +``` + +The most important piece of information to note down is the name you choose for the HLS manifest (master.m3u8 in this example, but you're free to use any name), and the hash returned by `ipfs add`. Consult [streaming.js](streaming.js) for a full example of how these values are used. + +## Putting it all together + +For a demo of the final result, see https://ipfs.io/ipfs/QmdBZhDLEsooVKkmgRgNzjo2JirSbddp8FvnccJ4c2orH2/ + +*Note:* If you try to run the example locally, some browsers (e.g Chrome) will fail to load the content for security reasons. To get around this, simply cd into the directory of this example and use http-server from npm: + +```bash +> npm install -g http-server +> http-server +``` + +You should then be able to stream Big Buck Bunny by pointing your browser at http://localhost:8080. + +In addition to video streaming, plain audio streaming work fine as well. Simply use the same ffmpeg+ipfs procedure as above, but with your audio file as input, and also change the video tag to `audio` (video tags will play plain audio as well, but the player looks a bit strange). + +On a final note, without diving too deep into what the specific ffmpeg HLS options above mean, it's worth mentioning the `hls_time` option, which defines the length of each HLS chunk (in seconds) and is potentially interesting for performance tuning (see for example [this article](https://bitmovin.com/mpeg-dash-hls-segment-length/)). diff --git a/examples/browser-video-streaming/index.html b/examples/browser-video-streaming/index.html index 74ae11d6d5..b565da987d 100644 --- a/examples/browser-video-streaming/index.html +++ b/examples/browser-video-streaming/index.html @@ -1,9 +1,8 @@ - - + From 8f8c949b5e1be842282a252e62cebd81de41152e Mon Sep 17 00:00:00 2001 From: Henry Rodrick Date: Fri, 18 Aug 2017 18:37:15 +0100 Subject: [PATCH 3/3] Fix typos and wording --- examples/browser-video-streaming/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/browser-video-streaming/README.md b/examples/browser-video-streaming/README.md index 14afdcfdde..db8d7749a6 100644 --- a/examples/browser-video-streaming/README.md +++ b/examples/browser-video-streaming/README.md @@ -5,14 +5,14 @@ This example shows a method for video/audio streaming in the browser over IPFS. ## Why use HLS? HLS (Apple's HTTP Live Streaming) is one of several protocols currently available for adaptive bitrate streaming. -One of the advantages of HLS is that the content can be hosted on a plain old web server without any special server-side logic. The way this works is that the original content (the stream or video/audio file) is split up into small MPEG2-TS segments before putting it on the web server. The segments can then be fetched by the HLS player on the fly and spliced together to a continuous stream. +One of the advantages of HLS over some other streaming technologies is that the content can be hosted on a plain old web server without any special server-side support. The way this works is that the original content (the stream or video/audio file) is split up into small MPEG2-TS segments before being uploaded to the server. The segments are then fetched by the HLS player on the fly (using regular HTTP GET requests) and get spliced together to a continuous stream. -In addition to the segments there are also a so-called manifests (m3u8 files) which contain metadata about segments and their bitrates. A stream can contain segments of multiple bitrates and the HLS player will automatically select the optimal bitrate based on client performance. +In addition to the segments there are also so-called manifests (m3u8 files) which contain metadata about segments and their bitrates. A stream can contain segments of multiple bitrates and the HLS player will automatically switch to the optimal bitrate based on client performance. -The fact that HLS content is just "a bunch of files" makes it a good choice for IPFS (another protocol that works like this is MPEG-DASH, which could certainly be a good choice as well). Furthermore, the [hls.js](https://github.com/video-dev/hls.js) library enables straightforward integration with the HTML5 video element. +The fact that HLS content is just "a bunch of files" makes it a good choice for IPFS (another protocol that works this way is MPEG-DASH, which could certainly be a good choice as well). Furthermore, the [hls.js](https://github.com/video-dev/hls.js) library enables straightforward integration with the HTML5 video element. ## hlsjs-ipfs-loader -The hls.js library ships with a HTTP based content loader, but it's fortunately possible to configure custom content loaders as well, which is what makes IPFS streaming possible in this case. A loader implementation that fetches content using js-ipfs can be found [here](https://www.npmjs.com/package/hlsjs-ipfs-loader), and is easy to integrate on a regular HTML page: +The hls.js library ships with an HTTP based content loader only, but it's fortunately possible to configure custom content loaders as well, which is what makes IPFS streaming possible in this case. A loader implementation that fetches content using js-ipfs can be found [here](https://www.npmjs.com/package/hlsjs-ipfs-loader), and is easy to use on a regular HTML page: ```html @@ -21,7 +21,7 @@ The hls.js library ships with a HTTP based content loader, but it's fortunately ``` ## Generating HLS content -In order for any of the above to be useful, we also need to have a way to actually generate a HLS manifests and MPEG2-TS segments from an arbitrary video/audio file. Luckily, most new builds of `ffmpeg` are compiled with this capability. +In order for any of the above to be useful, we also need to have a way to actually generate HLS manifests and MPEG2-TS segments from an arbitrary video/audio file. Luckily, most new builds of `ffmpeg` are compiled with this capability. For example, say we have a directory containing a video file `BigBuckBunny_320x180.mp4`. We can then create a sub directory and generate the HLS data there, and finally add it to IPFS: @@ -29,7 +29,7 @@ For example, say we have a directory containing a video file `BigBuckBunny_320x1 > mkdir hls-bunny > cd hls-bunny > ffmpeg -i ../BigBuckBunny_320x180.mp4 -profile:v baseline -level 3.0 -start_number 0 -hls_time 5 -hls_list_size 0 -f hls master.m3u8 -> ifps add -Qr . +> ipfs add -Qr . ``` The most important piece of information to note down is the name you choose for the HLS manifest (master.m3u8 in this example, but you're free to use any name), and the hash returned by `ipfs add`. Consult [streaming.js](streaming.js) for a full example of how these values are used. @@ -38,7 +38,7 @@ The most important piece of information to note down is the name you choose for For a demo of the final result, see https://ipfs.io/ipfs/QmdBZhDLEsooVKkmgRgNzjo2JirSbddp8FvnccJ4c2orH2/ -*Note:* If you try to run the example locally, some browsers (e.g Chrome) will fail to load the content for security reasons. To get around this, simply cd into the directory of this example and use http-server from npm: +*Note:* If you try to run the example straight from disk, some browsers (e.g Chrome) might, for security reasons, prevent some resources from loading correctly. To get around this, simply cd into the directory of this example and use http-server from npm: ```bash > npm install -g http-server @@ -47,7 +47,7 @@ For a demo of the final result, see https://ipfs.io/ipfs/QmdBZhDLEsooVKkmgRgNzjo You should then be able to stream Big Buck Bunny by pointing your browser at http://localhost:8080. -In addition to video streaming, plain audio streaming work fine as well. Simply use the same ffmpeg+ipfs procedure as above, but with your audio file as input, and also change the video tag to `audio` (video tags will play plain audio as well, but the player looks a bit strange). +In addition to video streaming, plain audio streaming works fine as well. Simply use the same ffmpeg + ipfs procedure as described above, but with your audio file as input. You may also want to change the video tag to `audio` (video tags will play plain audio as well, but the player looks a bit strange). On a final note, without diving too deep into what the specific ffmpeg HLS options above mean, it's worth mentioning the `hls_time` option, which defines the length of each HLS chunk (in seconds) and is potentially interesting for performance tuning (see for example [this article](https://bitmovin.com/mpeg-dash-hls-segment-length/)).