MPEG DASH - team-wedev/wedev GitHub Wiki
(μ΄λ―Έμ§μΆμ²: http://abt.net/multimedia.php)
Dynamic Adaptive Streaming over HTTP λλ, MPEG-DASHλ web serverμμ media contentλ₯Ό μ 곡ν λ clientμ λ€νΈμν¬ μν©μ λ°λΌ κ·Έμ λ§λ qualityμ media contentλ₯Ό μ 곡νλ κ²μ μλ―Έν©λλ€. μ νμ HLS(HTTP Live Streaming)κ³Ό μ μ¬ν©λλ€.
ffmpegλ₯Ό μ΄μ©νμ¬ client μμ μ λ ₯ν μλ³Έ λμμμ μ¬λ¬ ν΄μλμ λμμμΌλ‘ μΈμ½λ©ν©λλ€.
wget --no-check-certificate "https://docs.google.com/uc?export=download&id=17leZjmhYETsCl67vXBlc3_FO0W0UElyc" -O sample2.mp4
ffmpeg -y -i ./sample/sample.mp4 -c:a aac -ac 2 -ab 256k -ar 48000 -c:v libx264 -x264opts 'keyint=24:min-keyint=24:no-scenecut' -b:v 1500k -maxrate 1500k -bufsize 1000k -vf scale=-1:720 -strict -2 ./sample/sample720.mp4
ffmpeg -y -i ./sample/sample.mp4 -c:a aac -ac 2 -ab 128k -ar 44100 -c:v libx264 -x264opts 'keyint=24:min-keyint=24:no-scenecut' -b:v 800k -maxrate 800k -bufsize 500k -vf scale=-1:540 -strict -2 ./sample/sample540.mp4 -strict -2
ffmpeg -y -i ./sample/sample.mp4 -c:a aac -ac 2 -ab 64k -ar 22050 -c:v libx264 -x264opts 'keyint=24:min-keyint=24:no-scenecut' -b:v 400k -maxrate 400k -bufsize 400k -vf scale=-1:360 -strict -2 ./sample/sample360.mp4 -strict -2
./shaka_packager/src/out/Release/packager \
input=./sample/sample720.mp4,stream=audio,output=./dest/sample720_audio.mp4 \
input=./sample/sample720.mp4,stream=video,output=./dest/sample720_video.mp4 \
input=./sample/sample360.mp4,stream=audio,output=./dest/sample360_audio.mp4 \
input=./sample/sample360.mp4,stream=video,output=./dest/sample360_video.mp4 \
--profile on-demand \
--mpd_output ./manifest/sample-manifest-full.mpd \
--min_buffer_time 3 \
--segment_duration 3
./shaka_packager/src/out/Release/packager \
input=./sample/sample720.mp4,stream=audio,output=./dest/sample720_audio.mp4 \
input=./sample/sample720.mp4,stream=video,output=./dest/sample720_video.mp4 \
--profile on-demand \
--mpd_output ./manifest/sample-720-full.mpd \
--min_buffer_time 3 \
--segment_duration 3
Shaka packager λ₯Ό μ΄μ©νμ¬ κ°κ° λ€λ₯Έ νμ§μ λΉλμ€ νμΌκ³Ό μ€λμ€ νμΌμ μμ±ν©λλ€. Shaka packagerλ μ΄λ₯Ό ν λλ‘ manifest νμΌμ μμ±ν©λλ€.
MDN-DASHμ μ΄μ λν μ νν νλ¦μ΄ λͺ μλμ΄ μμ΅λλ€.
Clientμμλ Shaka playerλ₯Ό μ΄μ©νμ¬ μ¬μ©μμ λ€νΈμν¬ μνμ λ°λ₯Έ λμμ μμ²μ μ€μν©λλ€.
- index.js shaka-player.compiled.js λ shaka player μ€μΉλ₯Ό νλ©΄ λ°μ μ μμ΅λλ€.
<!DOCTYPE html>
<html>
<head>
<script src="/js/shaka-player.compiled.js"></script>
<script>console.log("test");</script>
</head>
<body>
<video id="video" width="640"
controls autoplay"></video>
<script src="/js/myapp.js"></script>
</body>
</html>
- myapp.js
const manifestUrl = "/manifest";
function initApp() {
shaka.polyfill.installAll();
if (shaka.Player.isBrowserSupported()) {
initPlayer();
} else {
console.error("Browser not supported!");
}
}
function initPlayer() {
const video = document.getElementById("video");
const player = new shaka.Player(video);
window.player = player;
player.addEventListener("error", onErrorEvent);
player
.load(manifestUrl)
.then(function() {
console.log("The video has now been loaded!");
})
.catch(onError);
}
function onErrorEvent(event) {
onError(event.detail);
}
function onError(error) {
console.error("Error code", error.code, "object", error);
}
document.addEventListener("DOMContentLoaded", initApp);
- sample-manifest-full.mpd
<?xml version="1.0" encoding="UTF-8"?>
<!--Generated with https://github.com/google/shaka-packager version 1bcaf0a-release-->
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT3S" type="static" mediaPresentationDuration="PT27.33333396911621S">
<Period id="0">
<AdaptationSet id="0" contentType="video" maxWidth="1278" maxHeight="720" frameRate="12288/512" subsegmentAlignment="true" par="16:9">
<Representation id="0" bandwidth="430715" codecs="avc1.64001e" mimeType="video/mp4" sar="639:640" width="640" height="360">
<BaseURL>./dest/sample360_video.mp4</BaseURL>
<SegmentBase indexRange="875-1026" timescale="12288">
<Initialization range="0-874"/>
</SegmentBase>
</Representation>
<Representation id="1" bandwidth="1576446" codecs="avc1.64001f" mimeType="video/mp4" sar="1:1" width="1278" height="720">
<BaseURL>./dest/sample720_video.mp4</BaseURL>
<SegmentBase indexRange="855-1006" timescale="12288">
<Initialization range="0-854"/>
</SegmentBase>
</Representation>
</AdaptationSet>
<AdaptationSet id="1" contentType="audio">
<Representation id="2" bandwidth="79354" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="22050">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
<BaseURL>./dest/sample360_audio.mp4</BaseURL>
<SegmentBase indexRange="789-940" timescale="22050">
<Initialization range="0-788"/>
</SegmentBase>
</Representation>
<Representation id="3" bandwidth="260620" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="48000">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
<BaseURL>./dest/sample720_audio.mp4</BaseURL>
<SegmentBase indexRange="789-940" timescale="48000">
<Initialization range="0-788"/>
</SegmentBase>
</Representation>
</AdaptationSet>
</Period>
</MPD>
const express = require("express");
const fs = require("fs");
const path = require("path");
const app = express();
const PORT = process.env.PORT || 4040;
app.use("/manifest/dest", express.static("public/videos"));
app.use("/js", express.static("public/js"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.get("/", (req, res) => {
console.log("test");
// const html = fs.readFileSync(path.resolve(__dirname, "./view/index.html"));
res.sendFile(path.join(__dirname, "/view/index.html"));
});
app.get("/manifest", (req, res) => {
console.log("manifest");
res.sendFile(
path.join(__dirname, "/public/manifest/sample-manifest-full.mpd")
);
});
app.post("/test", (req, res) => {
console.log(req.body);
console.log("TEST");
res.send("OK");
});
app.listen(PORT, () => {
console.log(`Listening on ${PORT}...........`);
});