Chromium VideoCapture的实现
来源:互联网 发布:淘宝网店名称创意 编辑:程序博客网 时间:2024/05/27 20:11
- javascript中的用法
- videocapture简图
- LocalMedia核心数据的分析
- LocalMedia最上层分析
- WebCore层的数据结构
- webkitURL.createObjectURL
- 几个核心接口
- webrtc::VideoRendererInterface
- webrtc::VideoSourceInterface
- cricket::VideoCapturer
- webrtc::VideoTrackInterface
- 接口间的关系
- 重点类介绍
- 重点类及其继承关系
- 与MediaStreamDescriptor的关系
- LocalMedia管理层次分析
- WebCore层的核心管理类
- WebKit层与Content层对接口的实现
- VideoCapture的管理分析
- 重要的数据结构
- content::MediaStreamDevice
- content::StreamDeviceInfo
- 和VideoCapture相关的两个接口
- StreamCreate相关的消息管理
- Render端StreamCreate的消息类图
- 关键类及其作用
- webkitGetUserMedia的过程
- 获取Stream后的流程
- Host端StreamCreate的消息类图
- 3个主要接口
- 4个主要类
- 消息过程
- Render端StreamCreate的消息类图
- capture的进程间的消息管理
- Render进程capture消息管理类图
- Host端的capture消息管理
- 主要类介绍
- 从Render->Host的消息处理流程
- 从Host到Render的消息处理流程
- Shared Buffer
- Shared Buffer的对应关系
- Shared Buffer的创建过程
- 重要的数据结构
- video标签播放视频流分析
- WebMediaPlayerMS类分析
- 核心类结构图
- 数据流图
- 视频帧数据
- 视频格式及转换
- VideoFrame对象及数据流
- WebMediaPlayerMS类分析
- Android对VideoCapture的实现
- Android层接口类图
- Android层实现的几个关键点
javascript中的用法
首先,打开videocapture对象,使用如下代码
navigator.webkitGetUserMedia({video:true}, gotStream, function() {});
参数依次是:localmedia的配置信息,得到流的回调函数,出现错误时的回调函数。
gotStream的实现是
function gotStream(stream) {
video.src = webkitURL.createObjectURL(stream);
}
video是一个video标签。
stream是获取的stream对象。通过createObjectURL将其转换为url对象,传递给video,实现将流内容显示在video标签上。
videocapture简图
- 蓝色表示信令流
- 黑色标号部分,表示数据流
数据来自与android的Camera对象,获取的是front摄像头。 由于android的Camera必须设置一个Surface或者SurfaceTexture作为预览的目标,否则,将不能获取任何数据。因此,我在内部创建了一个隐藏的SurfaceTexture对象,唯一的目的是让Camera能够获取数据。
Camera获取的是NV21格式(YCrCb420SP),需要转换为YV12(YCrCb420P)。
在渲染时,数据格式被分为Y U V 3个面(Pane),每个面对应一个Texture,因此,共有3个Texture, 将这3个Texture混合在一起(通过YUV2RGB的混合矩阵),得到RGB数据,并被显示在GL的FrameBuffer中。
以上过程,仅仅将各个模块的关键点给出,省略了很多次要过程。
实际上,上述过程设计两个进程:Render和Host进程。 其中的CC(Component Composite) 在Render进程,而GPUHost则在Host进程,它们都在独立线程中运行。
事件通知使用了4种方式:
- 函数回调(包括从Java到C的回调)
- Chromium的异步回调(通过消息循环实现)
- 进程间的通讯(同步通讯)
- signal-slot机制
LocalMedia核心数据的分析
localmedia的实现是非常庞大而复杂的,线索众多并相互交织。因此,我们必须从上至下,一层一层的进行分析,才能很好的解析清楚。
LocalMedia最上层分析
这是LocalMedia的基本原理。
中间部分,是LocalMedia的核心管理部分。
它的基本流程是:
- 从输入设备中得到音频(Macrophone)和视频(camera)数据
- 这些数据被抽象为MediaSource对象,交给核心管理部分
- 核心管理部分,负责将数据流交给不同的Render
- Render和具体的显示或者播放设备连接。对于视频,是针对video标签。
WebCore层的数据结构
WebCore层有两个主要数据:
- WebCore::MediaStreamDescriptor 该数据结构包含了Video和Audo Source对象
- WebCore::MediaConstraints 这个是在navigator.webkitGetUserMedia({video:true}, gotStream, function() {}); 中 {video:true}参数代表的对象
WebCore::MediaConstraints由WebCore::MediaConstraintsImpl,这是一个简单的数据结构,它将传递的数据结构转换为一个hash表保存。
WebCore::MediaStreamDescriptor稍微复杂些,它的层次结构如下:
该数据结构中,重要的数据结构,实际上是MediaStreamSource:ExtraData和MediaStreamDescriptor::ExtraData.
因为,在WebCore这一层,完全不管理具体的音频、视频流,它仅仅管理了两个source,所有和真正Source实现部分,都是保存在MediaStreamSource::ExtraData中的。
而和Render相关的数据,则保存在MediaStreamDescriptor::ExtraData中。
webkitURL.createObjectURL
在js中,得到的stream对象,在C++层面,就是WebCore::MediaStreamDescriptor对象。
由于video标签的src属性,只接收URL,因此,无法直接将WebCore::MediaStreamDescriptor对象传递给video标签,所以,使用createObjectURL。
createObjectURL的实现很简单,就是利用特定算法,将WebCore::MediaStreamDescriptor对象计算为一个唯一的字符串,以此字符串为Key,放在hash表中映射WebCore::MediaStreamDescriptor对象。
关于具体实现,可以查阅源代码。
几个核心接口
以下接口是核心部分(Audo部分的接口参考Video的接口)
- webrtc::VideoRendererInterface
- webrtc::VideoSourceInterface
- cricket::VideoCapturer
- webrtc::VideoTrackInterface
webrtc::VideoRendererInterface
代码摘要:
// Interface for rendering VideoFrames from a VideoTrack
class VideoRendererInterface {
public:
virtual void SetSize(int width, int height) = 0;
virtual void RenderFrame(const cricket::VideoFrame* frame) = 0;protected:
// The destructor is protected to prevent deletion via the interface.
// This is so that we allow reference counted classes, where the destructor
// should never be public, to implement the interface.
virtual ~VideoRendererInterface() {}
};
webrtc::VideoSourceInterface
代码摘要
// VideoSourceInterface is a reference counted source used for VideoTracks.
// The same source can be used in multiple VideoTracks.
// The methods are only supposed to be called by the PeerConnection
// implementation.
class VideoSourceInterface : public MediaSourceInterface {
public:
// Get access to the source implementation of cricket::VideoCapturer.
// This can be used for receiving frames and state notifications.
// But it should not be used for starting or stopping capturing.
virtual cricket::VideoCapturer* GetVideoCapturer() = 0;
// Adds |output| to the source to receive frames.
virtual void AddSink(cricket::VideoRenderer* output) = 0;
virtual void RemoveSink(cricket::VideoRenderer* output) = 0;protected:
virtual ~VideoSourceInterface() {}
};
这里引入的cricket::VideoRenderer接口和webrtc::VideoRendererInterface接口实际上是一样的。
chromium在内部,将对VideoRenderer的调用,转换为对VideoRendererInterface的调用。
之所以提供两个不同的接口,是因为cricket::VideoRenderer是webrtc的第三方库提供的。
cricket::VideoCapturer
该类不是一个纯虚类,而是有部分纯虚函数。下面贴出其纯虚函数:
class VideoCapturer
: public sigslot::has_slots<>,
public talk_base::MessageHandler {
public:
// All signals are marshalled to |thread| or the creating thread if
// none is provided.
VideoCapturer();
explicit VideoCapturer(talk_base::Thread* thread);
virtual ~VideoCapturer() {}......
virtual CaptureState Start(const VideoFormat& capture_format) = 0;
// Stop the video capturer.
virtual void Stop() = 0;
// Check if the video capturer is running.
virtual bool IsRunning() = 0;....
};
webrtc::VideoTrackInterface
代码摘要
class VideoTrackInterface : public MediaStreamTrackInterface {
public:
// Register a renderer that will render all frames received on this track.
virtual void AddRenderer(VideoRendererInterface* renderer) = 0;
// Deregister a renderer.
virtual void RemoveRenderer(VideoRendererInterface* renderer) = 0;
// Gets a pointer to the frame input of this VideoTrack.
// The pointer is valid for the lifetime of this VideoTrack.
// VideoFrames rendered to the cricket::VideoRenderer will be rendered on all
// registered renderers.
virtual cricket::VideoRenderer* FrameInput() = 0;
virtual VideoSourceInterface* GetSource() const = 0;
protected:
virtual ~VideoTrackInterface() {}
};
VideoTrackInterface是一个内部使用的接口,这个接口主要负责将其他接口链接起来。
接口间的关系
可以用下图来描述(仅表示其逻辑关系,不代表代码真实情况。这种逻辑关系,由他们的实现类体现出来)
核心管理的两个接口是:
- VideoTrackInterface
- VideoSourceInterface
其中VideoSourceInterface负责管理Capturer和Renderer,将两者的数据贯穿起来;
而VideoTrackInterface的作用,是将VideoRenderererInterface转换为VideoRenderer接口。而且,将对一个VideoRenderer的调用,转换为对多个VideoRendererInterface的调用。
重点类介绍
本节介绍几个重点类。这些类是上节提到的几个接口的实现类,以及他们和MediaStreamDescriptor如何组合在一起的。这种关系,是实现localmedia的核心所在。
重点类及其继承关系
图例说明:
- 绿色部分表示重要的接口
- 蓝色是实现这些接口的类
- 蓝色虚线箭头,表示类直接的包含关系。与普通的包含不同,蓝色虚线表示它们通过包含类的接口指针来包含这个对象。
与MediaStreamDescriptor的关系
- WebKit::WebMediaStreamDescriptor::ExtraData对应的是WebCore::MediaStreamDescriptor::ExtraData, 同样的,WebKit::WebMediaStreamSource::ExtraData对应的是WebCore::MediaStreamSource::ExtraData。 chromium为了防止直接使用WebCore命名空间的内容,因此,增加了一个WebKit的命名空间,对应的类,都加上了Web前缀。 这样,WebCore::MediaStreamDescriptor实际上通过ExtraData掌握了Source和Render两种数据
- 具体的实现,是在content空间内
- 为了同时掌握audio和video,它增加了一个webrtc::LocalMediaStreamInterface。(另外有一个webrtc::RemoteMediaStreamInterface,用于处理远程render)
LocalMedia管理层次分析
LocalMedia的层次大约有WebCore、WebKit和content三个层次,其中,content又分为render和host两个进程。
WebCore层次主要提供面向javascript和标签的接口;content主要提供具体实现;WebKit层其实是给WebCore层穿了个马甲,隔离WebCore和content层。
我们重点分析的是WebCore和content层。
WebCore层的核心管理类
整个核心,有3个类:
- WebCore::UserMediaController,它提供了接口 requestUserMedia,提供查询和打开设备的接口。UserMediaController和UserMediaClient是一回事。UserMediaController的所有实现,委托给UserMediaClient来实现。
- UserMediaRequest 提供两个重要函数:
- start:它调用UserMediaController的requestUserMedia函数,实现对设备查询和打开;
- succeed: 这是接收requestUserMedia的查询结果的(异步),该函数将收到一个MediaStreamDescriptor类,并将调用js层提供的 gotStream函数。
- MediaStreamCenter是WebCore对外通讯的接口,该类由外部实现,并负责将结果回调给UserMediaRequest。
UserMediaClient和MediaStreamCenter是必须由外部提供和实现的。
WebKit层与Content层对接口的实现
该图按照3个层次划分了各个类。其中最重要的是以下3个类
- content::MediaStreamImpl,它实际上,承担的是WebCore::MediaUserClient的任务,它的任务是
- 实现requestUserMedia函数,负责创建和打开音频和视频设备,并捕获它们的流;
- 它捕获设备打开的结果,并通过WebKit层,调用WebCore::UserMediaRequest的successed和failed函数,告诉js层成功或者失败。它通过content::UserMediaRequestInfo,将MediaStreamDescription和UserMediaRequest这两个对象关联在一起,一同调用;
- 它担负起对音频设备和视频设备的管理职责(VideoCaptureManager)
- MediaStreamCenter:它主要担负起对VideoSourceInterface和VideoTrackInterface的创建工作。并实现了WebCore:MediaStreamCenter的接口实现。
- content::MediaStreamDependencyFactory 这是整个创建Render, Source, Track的类,是整个创建过程的核心中的核心。该类虽然庞大,但是功能单一,就是作为各种类的创建工厂存在的。
VideoCapture的管理分析
对于真实设备的管理,是整个Localmedia的核心。在这一节中,我们重点讨论对真实的Video设备的管理。这些全部的内容,都在content层实现的。
这部分管理分为两部分:
- 针对Capture对象的创建和销毁的管理
- Capture消息本身的管理
这两类消息是通过不同的方法实现的。
重要的数据结构
content::MediaStreamDevice
它有3个重要的数据结构
- MediaStreamType type; 表示这是个音频还是视频设备
- std::string id; 设备的唯一ID,通过这个ID可以打开或者关闭设备
- std::string name; 设备的名称,是提供给人看的
content::StreamDeviceInfo
它有两个数据结构,其中一个,是MediaStreamDevice;另外一个,是 int session_id。这个session_id,代表了一个具体设备,是用于和Host端通讯使用的。
和VideoCapture相关的两个接口
接口cricket::VideoCapturer和media::VideoCapture(注意,一个后有"r",一个没有)。这两个对象,实际上是一回事,但是针对的不同的层次。cricket::VideoCapturer主要针对webrtc和上层关系,而media::VideoCapture主要针对Host,和Host进行通讯。
它们的关系很密切,如下图:
- content::RtcVideoCapturer和content::VideoCaptureImpl是两个实现接口的对象
- content::RtcVideoCaptureDelegate将两个对象连接在一起
- content::VideoCaptureImplManager负担有创建VideoCaptureImpl、管理和host消息通讯的职责
- media::VideoCapture::EventHandler将接收VideoCaptureImpl提供的事件回调,最主要的是收到数据和状态变化。
- RtcVideoCaptureDelegate收到消息后,将通过回调,调用到RtcVideoCapturer中的成员函数:OnFrameCaptured和OnStateChanged中。
StreamCreate相关的消息管理
Render端StreamCreate的消息类图
关键类及其作用
- MediaStreamImpl 这个类是实现UserMediaControlClient的类,响应requestuserMedia调用
- MediaStreamDispater,这个类是实现和Host端通讯的类
- RenderViewImpl 它是MediaStreamImpl和MediaStreamDispater的工厂类,负责创建它们。
MediaStreamImpl直接包含了MediaStreamDispatcher类。 MediaStreamDispatcher类通过MediaStreamDispatcherEventHandler将Host的回馈消息发送给MediaStreamImpl。
MediaStreamImpl通过UserMediaRequestInfo保存对UserMediaRequest的引用。
webkitGetUserMedia的过程
当javascript代码调用webkitGetUserMedia的时候,
- WebCore::UserMediaRequest的didCompleteQuery被调用(通过MediaStreamCenter实现的)
- content::MediaStreamImpl的requestUserMedia将会被调用(通过WebCore::UserMediaControl的UserMediaControlClient实现的,中间透过了WebKit层)
- 调用MediaStreamDispatcher的GenerateStream
- MediaStreamDispatcher向Host发送MediaStreamHostMsg_GenerateStream消息。
获取Stream后的流程
- Host发送MediaStreamMsg_StreamGenerated,由MediaStreamDispatcher接收
- MediaStreamDispatcher调用MediaStreamImpl的OnStreamGenerated
- MediaStreamImpl将创建Webkit::WebMediaStreamDescriptor及对应的WebMediaStreamSource对象
- 通过UserMediaRquestInfo,最终调用到UserMediaRquest的succeed函数,(中间经过若干函数调用,而且为异步调用)
- succeed函数最终会调用javascript提供的gotStream函数,其中,stream就是 WebMediaRequestDescriptor对象。
Host端StreamCreate的消息类图
3个主要接口
- content::MediaStreamRequester :用于接收设备和流创建情况的接口,被MediaStreamDispachterHost所实现
- content::MediaStreamProviderListener:用于接收音频和视频设备创建成功与否与打开成功与否的接口
- content::SettingsRequester:用于接收用户反馈结果的接口
4个主要类
- MediaStreamDispatcherHost : 和Render端通讯类,负责发送和接收消息
- MediaStreamManager:中心类,负责查询、创建、询问的类
- VideoCaptureManager:负责查询和创建视频设备的类
- MediaStreamUIController:负责和用户打交道,询问用户是否启用本地设备的类
media::VideoCaptureDevice是代表一个视频设备的类。
消息过程
整个过程分为两个部分:
- 查询设备,从步骤4~7 蓝色部分 ,
- 第4步骤,在MediaStreamManager中的调用过程是:HandleRequest > StartEnumeration > StartMonitoring
- 第4步骤,在MediaStreamManager中的调用过程是:HandleRequest > StartEnumeration > StartMonitoring
- 打开设备,从步骤8~18红色部分
- 第8步骤,MediaStreamManager通过PostRequestToUI调用
- 第8~12步骤,主要是请求用户是否同意打开设备(目前的实现,直接内部同意了)
- 第13~16步骤,是调用VideoCaptureManager来创建设备。 注意第16步骤由VideoCaptureManager::PostOnOpened调用
中间有若干部分都是异步的。
capture的进程间的消息管理
Render进程的消息,有两个关键类来管理 content::VideoCaptureImpl和content::VideoCaptureMessageFilter。这两个类,其中VideoCaptureImpl负责发送消息,而VideoCaptureMessageFilter负责接收消息。
Render进程capture消息管理类图
- content::VideoCaptureImplManager是个类工厂。它负责创建Thread, filter和capture对象。 对VideoCaptureImpl对象,它使用SessionID为key,管理多个capture对象。
- VideoCaptureMessageFilter负责接收来自Host的消息
- VideoCaptureImpl负责向Host发送消息
- VideoCaptureMessageFilter通过Delegate将收到的消息传递给VideoCaptureImpl
消息的传递和接收,必须严格在IO线程内部。而对capture的所有处理,应该在capture线程。
IO线程来自与ChildProcess,而对应的message_loop_proxy就是 io_message_loop_proxy_
Capture线程来自 VideoCaptureManagerImpl的thread_,对应的message_loop_proxy就是 capture_message_loop_proxy_
VideoCaptureImplManager对象隶属于RenderThreadImpl类,并将VideoCaptureMessageFilter添加到RenderThreadImpl的Filter当中。只有添加到RenderThreadImpl的filter中,VideoCaptureMessageFilter才能接收到来自Host的消息。
Host端的capture消息管理
主要类介绍
- content::VideoCaptureHost 这是负责接收和发送消息的,和VideoCaptureImpl类对应
- content::VideoCaptureManager,Capture的管理类,担负两项职责:
- 作为类工厂,创建和管理 media::VideoCaptureDevice对象和VideoCaptureController对象。
- 作为中转类,负责隔离其他类对VideoCaptureDevice类的调用
- content::VideoCaptureController,这个类的主要职责和获取的数据相关:
- 维护和VideoCaptureImpl的共享内存
- 将从VideoCaptureDevice获取的数据转换为YV12格式
从Render->Host的消息处理流程
- VideoCaptureHost得到消息,调用VideoCaptureManager处理(这里单例模式)
- VideoCaptureManager负责VideoCaptureController和VideoCaptureDevice
- 当VideoCaptureManager创建了必须的对象后,VideoCaptureHost调用VideoCaptureController进行进一步的处理
- VideoCaptureController负责准备好必须的数据,包括共享内存,等
- 一旦准备好后,VideoCaptureController调用VideoCaptureManager的相关接口
- VideoCaptureManager将这种调用,转换为对VideoCaptureDevice的调用
- VideoCaptureDevice和OS的设备进行交互。
从Host到Render的消息处理流程
- VideoCaptureDevice从设备获取到数据后,交给VideoCaptureController(实现了VideoCaptureDevice::EventHandler接口)
- VideoCaptureController将进行数据拷贝和转换,在Android中,将NV21转换为YV12,并存入共享内存中
- VideoCaptureController发送BufferReady消息给VideoCaptureHost (实现了VideoCaptureControllerEventHandler接口)
- VideoCaptureHost将消息发送给VideoCaptureImpl
Host和Render在传送消息时,通过SessionID(有的类里称为DeviceID,或者是DeviceControllerID等)来标示一个唯一的设备。
Shared Buffer
这一节,我们将探讨Shred Buffer的创建和使用的相关细节。
Shared Buffer的对应关系
在Render端,Shared Buffer由VideoCaptureImpl管理;在Host端,SharedBuffer由VideoCaptureController管理。
VideoCaptureImpl:: DIBBuffer对象和VideoCaptureController::SharedDIB 两个类的定义完全一样。
核心是对象base::SharedMemory对象,它负责将创建并管理共享内存。
Shared Buffer的创建过程
SharedBuffer的创建过程是从VideoCaptureDevice对象的Allocate方法开始的。
Allocate方法,是要求VideoCapture创建设备,并为止分配足够的空间。
- 在DoFrameOnIoThread中,创建SharedDIB,同时创建了共享内存。
- 在VideoCaptureControl的OnBufferCreated中,创建了DIBBuffer,并和SharedDIB共享了内存
video标签播放视频流分析
WebMediaPlayerMS类分析
WebMediaPlayerMS派生自WebKit::WebMediaPlayer,它给HTMLVideoElement类提供一个Player对象。
WebMediaPlayerMS在函数RenderViewImpl::createMediaPlayer中被创建。
WebMediaPlayerMS表示获取并播放流对象。WindowMediaPlayer有几个重要的函数:
- load 这是根据URL创建流对象的函数
- OnFrameAvailable 该函数作为回调,提供给流对象,让流对象发送数据给WebMediaPlayerMS
- getCurrentFrame : 这是被CC调用的函数,提供给VideolayerImpl对象,其中包含了视频数据,即YV12格式。
核心类结构图
RTCVideoRenderer一方面实现了接口VideoRendererInterface,从而能够接收来自本地/远程的视频流,另外一方面,实现了VideoFrameProvider接口,能够将这种数据传递给WebMediaPlayerMS。
RTCVideoRender通过回调函数WebMediaPlayerMS::VideoFrameProvider
数据流图
WebMediaPlayerMS在得到数据后,调用Repaint,该函数最终会引起CC层的重新调度。在调度时,VideoLayerImpl就会调用getCurrentFrame获取当前需要绘制的视频帧。
在CC层的处理下,数据最终被绘制到了屏幕上。
VideoLayerImpl和一个video标签是对应的,因此,它能够获得video标签的位置并绘制。
视频帧数据
视频格式及转换
视频数据是YV12格式(详细参阅 YUV http://zh.wikipedia.org/wiki/YUV)。从 android的获得的NV21。
YV12实际上YUV420P,而NV21则是YUV420SP。 ‘S’的含义是交错格式。即U分量和V分量交错存储。P为Plane,表示一个平面。YUV有3个Plane,分别是Y、U(Cb)、V(Cr)
YUV 也可以写为YCbCr
所谓420,含义4个Y,共有一个UV。 即, Y00, Y10, Y01, Y11 共有U00, V00。
YV12的示意图
YU12和YV12属于YUV420格式,也是一种Plane模式,将Y、U、V分量分别打包,依次存储。其每一个像素点的YUV数据提取遵循YUV420格式的提取方式,即4个Y分量共用一组UV。注意,上图中,Y'00、Y'01、Y'10、Y'11共用Cr00、Cb00,其他依次类推。
NV21的示意图
NV12和NV21属于YUV420格式,是一种two-plane模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个plane。其提取方式与上一种类似,即Y'00、Y'01、Y'10、Y'11共用Cr00、Cb00
VideoFrame对象及数据流
表示YUV数据的对象,是VideoFrame对象,但是,在不同的阶段,相同的数据,数据对象类却是不一样的。为了防止造成误解,我把从VideoCapture到MediaPlayer这个过程中,涉及的数据格式和类,用图表表示出来,如下:
左边为设备管理对象,虚线表示函数调用;右边为数据对象,箭头线表示数据转换的方向和方法。
其中,
- VideoCaptureImpl到RtcVideoCapturer中间通过了RtcVideoCaptureDelegate的回调实现。可以查阅RtcVideoCapturer::Start函数,回调函数在此安装;
- RtcVideoCapturer到VideoCapturer的调用,是通过signal-slot完成的。
- 从VideoCapturer到CaptureRenderAdapter的OnVideoFrame调用,也是通过signal-slot完成。
- 从RTCVideoRenderer到WebMediaPlayerMS的调用,是通过回调函数完成的,参阅函数安装点:WebMediaPlayerMS::load函数。
Android对VideoCapture的实现
Chromium暴露给OS层的接口,并要求OS层实现的接口,仅有media::VideoCaptureDevice。只要实现该接口,就能实现对视频设备的支持。
Android层接口类图
- 黄色部分:为java的C++包装类
- 蓝色部分:为java对应的类
Android层实现的几个关键点
- java的VideoCaptureAndroid类中,预览android.hardware.Camera时,必须创建一个SurfaceTexture否则不能启动预览;
- media::VideoCaptureDeviceAndroid的函数Start,等必须在UI线程中调用,否则会出现崩溃。
- Chromium VideoCapture的实现
- 利用OpenCV的VideoCapture类实现视频/摄像头读操作
- chromium设置UI的实现
- 诡异的VideoCapture
- Chromium原码浅析 --- Chromium多线程的实现
- VideoCapture
- Chromium源码浅析 --- MessagePort通信的实现
- chromium中MessageLoop指针的实现
- OpenCv学习笔记(五):使用VideoCapture类函数实现视频的播放
- android4.4 webview chromium实现硬件渲染的chromium内核结构
- Chromium on Android: Android系统上Chromium主消息循环的实现分析
- openCV VideoCapture类的使用例程
- opencv2.4.4 VideoCapture::open()的运用
- python调用videocapture出错的问题
- chromium 书签实现机制
- chromium阅读模式实现
- chromium 书签实现机制
- chromium 书签实现机制
- gtk-gl-slider例程分析
- Eclipse 找不到SDK和AVD的管理项
- RTSP 消息拼装实例代码
- usb协议7.1.7.7 Resume
- OpenCV环境下CUDA编程示例
- Chromium VideoCapture的实现
- VI 命令收集
- 20130621-Allegro16.6状态查看
- session和cookie的最深刻理解
- android问题集合
- 总结:复合数据对象
- sql 分页排序的存储过程
- The Data Warehouse ETL Toolkit学习笔记-需求
- 彻底理解PHP的SESSION机制