下载mse-demo
git clone https://github.com/bitmovin/mse-demo
cog启动
cog运行,每次都要配置编译时用的环境变量
export PATH=$PATH:/home/hui/disk4t/codes/wpe/source/inst/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/hui/disk4t/codes/wpe/source/inst/lib:/home/hui/disk4t/codes/wpe/source/inst/lib/x86_64-linux-gnu
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/hui/disk4t/codes/wpe/source/inst/lib/pkgconfig:/home/hui/disk4t/codes/wpe/source/inst/lib/x86_64-linux-gnu/pkgconfig
cog --platform=x11 file:///home/hui/webkit-debug/mse-demo/index.html
在Tools/TestWebKitAPI/Tests/WebKit/file-with-mse.html
文件中,也是mse的测试代码,可以参考修改下上面的这个html,增加一个button以方便attach到WPEWebprocess进程进行调试。
diff --git a/index.html b/index.html
index 58aa0e5..b22f048 100644
--- a/index.html
+++ b/index.html
@@ -6,12 +6,12 @@
</head>
<body>
<h1>MSE Demo</h1>
- <div>
- <video controls width="80%"></video>
- </div>
-
+ <div>
+ <video id="player" controls width="80%" ></video>
+ </div>
+ <button οnclick="playVideo()">play video</button>
<script type="text/javascript">
- (function() {
+ function playVideo() {
var baseUrl = 'https://bitdash-a.akamaihd.net/content/MI201109210084_1/video/720_2400000/dash/';
var initUrl = baseUrl + 'init.mp4';
var templateUrl = baseUrl + 'segment_$Number$.m4s';
@@ -68,7 +68,7 @@
xhr.send();
}
- })();
+ };
</script>
</body>
-</html>
+</html>
<script> var v = document.getElementById("player"); v.onclick = function() { if (v.playing) { v.play(); } else { v.pause(); } }; </script>
通过增加js代码,直接利用video标签的play按钮的代码不起作用,还需要研究下。
获取journal输出
journalctl -ef | grep -E "WPEWebProcess|WPENetworkProcess"
security origin
运行cog时,发现cog起来后页面加载不出来,chrome播放正常,log中有:
was rejected by SecurityOrigin
是被SecurityOrigin这个地方直接return了,为了测试,直接修改这个地方,返回true,编译运行就可以了。
RefPtr<Frame> frame = document().frame();
if (!frame || !document().securityOrigin().canDisplay(url)) {
if (actionIfInvalid == Complain) {
FrameLoader::reportLocalLoadFailed(frame.get(), url.stringCenterEllipsizedToLength());
ERROR_LOG(LOGIDENTIFIER, url , " was rejected by SecurityOrigin");
}
- return false;
+ return true;
}
在做完这些之后,通过qtcreator断点调试就可以了,可以方便的看到mediasource和sourcebuffer的调用栈。
mediasource的创建
MediaSource是在js中通过代码调用才能创建,并不是所有的html5 video都是MSE,所以刚开始接触的时候,用https://www.w3.org/2010/05/video/mediaevents.html
的测试页面,就没有这个过程,很怀疑是不是代码思路看错了。
1 WebCore::MediaSource::MediaSource
2 WebCore::MediaSource::create
3 WebCore::JSDOMConstructor<WebCore::JSMediaSource>::construct
addSourceBuffer
同样,sourcebuffer的创建也是通过js代码的调用才走到底层C++代码的,addSourceBuffer
1 WebCore::SourceBufferPrivateGStreamer::SourceBufferPrivateGStreamer
2 WebCore::SourceBufferPrivateGStreamer::create
3 WebCore::MediaSourcePrivateGStreamer::addSourceBuffer
4 WebCore::MediaSource::createSourceBufferPrivate
5 WebCore::MediaSource::addSourceBuffer
6 WebCore::jsMediaSourcePrototypeFunction_addSourceBufferBody
8 WebCore::jsMediaSourcePrototypeFunction_addSourceBuffer
通过断点设置,可以快速的看到AppendPipeline的创建所做的工作:
1 WebCore::HTMLMediaElement::prepareToPlay
2 WebCore::HTMLMediaElement::updatePlayState
3 WebCore::HTMLMediaElement::setReadyState
4 WebCore::HTMLMediaElement::mediaPlayerReadyStateChanged
5 WebCore::MediaPlayer::readyStateChanged
6 WebCore::MediaPlayerPrivateGStreamerMSE::setReadyState
7 WebCore::MediaSourcePrivateGStreamer::setReadyState
8 WebCore::SourceBufferPrivateGStreamer::setReadyState
9 WebCore::SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment
10 WebCore::SourceBufferPrivate::didReceiveInitializationSegment
11 WebCore::SourceBufferPrivateGStreamer::didReceiveInitializationSegment
12 WebCore::AppendPipeline::didReceiveInitializationSegment
14 WTF::Detail::CallableWrapper<WebCore::AppendPipeline::AppendPipeline
AppendPipeline在构造函数里面,no-more-pads信号连接的地方,直接通过lambda表达式调用了didReceiveInitializationSegment:
html MSE的全部代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MSE Demo</title>
</head>
<body>
<h1>MSE Demo</h1>
<div>
<video id="player" controls width="80%" ></video>
</div>
<button onclick="playVideo()" >play video</button>
<script type="text/javascript">
function playVideo() {
var baseUrl = 'https://bitdash-a.akamaihd.net/content/MI201109210084_1/video/720_2400000/dash/';
var initUrl = baseUrl + 'init.mp4';
var templateUrl = baseUrl + 'segment_$Number$.m4s';
var sourceBuffer;
var index = 0;
var numberOfChunks = 52;
var video = document.querySelector('video');
if (!window.MediaSource) {
console.error('No Media Source API available');
return;
}
var ms = new MediaSource();
video.src = window.URL.createObjectURL(ms);
ms.addEventListener('sourceopen', onMediaSourceOpen);
function onMediaSourceOpen() {
sourceBuffer = ms.addSourceBuffer('video/mp4; codecs="avc1.4d401f"');
sourceBuffer.addEventListener('updateend', nextSegment);
GET(initUrl, appendToBuffer);
video.play();
}
function nextSegment() {
var url = templateUrl.replace('$Number$', index);
GET(url, appendToBuffer);
index++;
if (index > numberOfChunks) {
sourceBuffer.removeEventListener('updateend', nextSegment);
}
}
function appendToBuffer(videoChunk) {
if (videoChunk) {
sourceBuffer.appendBuffer(new Uint8Array(videoChunk));
}
}
function GET(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (xhr.status != 200) {
console.warn('Unexpected status code ' + xhr.status + ' for ' + url);
return false;
}
callback(xhr.response);
};
xhr.send();
}
};
</script>
</body>
</html>