网页中javascript是通过MediaSource object把media的数据 传入c++代码中的, MediaSource是被javascript创建,同时与一个HTMLMediaElement对象绑定。MediaSource对象是HTMLMediaElement对象的数据源。MediaSource会把media data添加在SourceBuffer对象中。
1.创建 MediaSource
MediaSource的js和c++代码的接口定义在MediaSource.idl文件中,在这个文件中的接口,js都可以直接调用,接口对接c++代码。
js代码中调用new MediaSource(),会生成一个MediaSource对象。 时序图如下:
从上图可以看到js代码将关联object url和一个MediaSource对象,并将保存在m_mediaSource的set集合中。这样做是为了后面将一个MediaSource和一个HTMLMediaElement相关联。MediaSourceRegistry是HTMLMediaSource和MediaSource的桥梁,我们从最主要的代码就是从调用的MediaSourceRegistry::registry()开始
在MediaSourceRegistry.cpp中,registry是静态成员函数:
MediaSourceRegistry& MediaSourceRegistry::registry() {
DEFINE_STATIC_LOCAL(MediaSourceRegistry, instance, ());
return instance;
}
DEFINE_STATIC_LOCAL定义在base/macros.h中 :
#define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \
static type& name = *new type arguments
从上面可以看到是new了一个对象。
所以在registry中调用了MediaSourceRegistry的构造函数,在构造函数中将该对象注册到HTMLMediaSource中
MediaSourceRegistry::MediaSourceRegistry() {
HTMLMediaSource::setRegistry(this);
}
而在MediaSourceRegistry::registerURL中将url和MediaSource保存在一个m_mediaSources集合中:
void MediaSourceRegistry::registerURL(SecurityOrigin*, const KURL& url, URLRegistrable* registrable) {
MediaSource* source = static_cast(registrable);
........
m_mediaSources.set(url.string(), source);
}
HTMLMediaSource公有继承URLRegistrable,MediaSource公有继承HTMLMediaSource。
因此HTMLMediaSource就可以通过MediaSourceRegistry拿到对应url的MediaSource了。
2. 关联 MediaSource 和 HTMLMediaElement
通过关联HTMLMediaElement, MediaSource就可以与HTMLMediaElement单方面“通信”了。
在HTMLMediaElement.cpp文件中
void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType, const String& keySystem) {
.....
m_mediaSource = HTMLMediaSource::lookup(url.string());
if (m_mediaSource) {
m_mediaSource->attachToElement(this);
....
}
....
}
HTMLMediaSource::lookup在HTMLMediaSource.h文件中
static HTMLMediaSource* lookup(const String& url) {
return s_registry ? static_cast(s_registry->lookup(url)) : 0;
}
在Create MediaSource的时序图中可以看到在MediaSourceRegistry中调用HTMLMediaSource::setRegistry将MediaSourceRegistry注册到HTMLMediaSource中,因此s_registry就是MediaSourceRegistry对象,在MediaSourceRegistry.cpp中
URLRegistrable* MediaSourceRegistry::lookup(const String& url) {
return m_mediaSources.get(url);
}
再回过头来看 attach到一个HTMLMediaElement对象,拿到一个MediaSource对象时,调用attachToElement方法
bool MediaSource::attachToElement(HTMLMediaElement* element) {
......
m_attachedElement = element;
return true;
}
bool MediaSource::isTypeSupported(const String& type) {
.....
if (HTMLMediaElement::supportsType(contentType) == WebMimeRegistry::IsNotSupported){
...
}
...
bool result = MIMETypeRegistry::isSupportedMediaSourceMIMEType(contentType.type(), codecs);
return result;
}
这两次的检测的方法异曲同工,都是拿type和已经配置好的config比较,所谓的配置就是mimetype和对应的codec绑定在一起。下面我们拿 MIMETypeRegistry
:: isSupportedMediaSourceMIMEType举例说明。
static bool CheckTypeAndCodecs(const std::string& type,const std::vector& codecs,const LogCB& log_cb,ParserFactoryFunction* factory_function,std::vector* audio_codecs,std::vector* video_codecs) {
.....
for(size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
...
const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
...
}
}
从上面的代码中看到kSupportedTypeInfo中应该保存有配置信息。
static const SupportedTypeInfo kSupportedTypeInfo[] = {
{ "video/webm", &BuildWebMParser, kVideoWebMCodecs },
{ "audio/webm", &BuildWebMParser, kAudioWebMCodecs },
....
};
"video/webm"和“audio/webm”就是mimetype, BuildWebMParser是用来创建StreamParser对象的,kVideoWebMCodecs是已经配置好的codec。
static StreamParser* BuildWebMParser(const std::vector& codecs,const LogCB& log_cb) {
return new WebMStreamParser();
}
static const CodecInfo* kVideoWebMCodecs[] = {
&kVP8CodecInfo,
&kVP9CodecInfo,
&kVorbisCodecInfo,
&kOpusCodecInfo,
NULL
};
static const CodecInfo kVP8CodecInfo = { "vp8", CodecInfo::VIDEO, NULL,CodecInfo::HISTOGRAM_VP8 };
PassOwnPtr MediaSource::createWebSourceBuffer(const String& type, const Vector& codecs, ExceptionState& exceptionState)
{
WebSourceBuffer* webSourceBuffer = 0;
switch (m_webMediaSource->addSourceBuffer(type, codecs, &webSourceBuffer)) {
....
}
....
}
SourceBuffer* MediaSource::addSourceBuffer(const String& type, ExceptionState& exceptionState)
{
if (!isTypeSupported(type)) {
...
}
//Create a new SourceBuffer object and associated resources.
ContentType contentType(type);
Vector codecs = contentType.codecs();
OwnPtr webSourceBuffer = createWebSourceBuffer(contentType.type(), codecs, exceptionState);
...
SourceBuffer* buffer = SourceBuffer::create(webSourceBuffer.release(), this, m_asyncEventQueue.get());
//Add the new object to sourceBuffers and fire a addsourcebuffer on that object.
m_sourceBuffers->add(buffer);
}
以上就是MediaSource和SourceBuffer的创建过程,下篇文章将分析appendBuffer的过程。