video_capture_host.cc revision 58537e28ecd584eab876aee8be7156509866d23a
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/renderer_host/media/video_capture_host.h"
6
7#include "base/bind.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/stl_util.h"
10#include "content/browser/browser_main_loop.h"
11#include "content/browser/renderer_host/media/media_stream_manager.h"
12#include "content/browser/renderer_host/media/video_capture_manager.h"
13#include "content/common/media/video_capture_messages.h"
14
15namespace content {
16
17struct VideoCaptureHost::Entry {
18  Entry(VideoCaptureController* controller)
19      : controller(controller) {}
20
21  ~Entry() {}
22
23  scoped_refptr<VideoCaptureController> controller;
24};
25
26VideoCaptureHost::VideoCaptureHost(MediaStreamManager* media_stream_manager)
27    : media_stream_manager_(media_stream_manager) {
28}
29
30VideoCaptureHost::~VideoCaptureHost() {}
31
32void VideoCaptureHost::OnChannelClosing() {
33  BrowserMessageFilter::OnChannelClosing();
34
35  // Since the IPC channel is gone, close all requested VideCaptureDevices.
36  for (EntryMap::iterator it = entries_.begin(); it != entries_.end(); it++) {
37    VideoCaptureController* controller = it->second->controller.get();
38    if (controller) {
39      VideoCaptureControllerID controller_id(it->first);
40      controller->StopCapture(controller_id, this);
41      media_stream_manager_->video_capture_manager()->RemoveController(
42          controller, this);
43    }
44  }
45  STLDeleteValues(&entries_);
46}
47
48void VideoCaptureHost::OnDestruct() const {
49  BrowserThread::DeleteOnIOThread::Destruct(this);
50}
51
52///////////////////////////////////////////////////////////////////////////////
53
54// Implements VideoCaptureControllerEventHandler.
55void VideoCaptureHost::OnError(const VideoCaptureControllerID& controller_id) {
56  DVLOG(1) << "VideoCaptureHost::OnError";
57  BrowserThread::PostTask(
58      BrowserThread::IO, FROM_HERE,
59      base::Bind(&VideoCaptureHost::DoHandleErrorOnIOThread,
60                 this, controller_id));
61}
62
63void VideoCaptureHost::OnBufferCreated(
64    const VideoCaptureControllerID& controller_id,
65    base::SharedMemoryHandle handle,
66    int length,
67    int buffer_id) {
68  BrowserThread::PostTask(
69      BrowserThread::IO, FROM_HERE,
70      base::Bind(&VideoCaptureHost::DoSendNewBufferOnIOThread,
71                 this, controller_id, handle, length, buffer_id));
72}
73
74void VideoCaptureHost::OnBufferReady(
75    const VideoCaptureControllerID& controller_id,
76    int buffer_id,
77    base::Time timestamp) {
78  BrowserThread::PostTask(
79      BrowserThread::IO, FROM_HERE,
80      base::Bind(&VideoCaptureHost::DoSendFilledBufferOnIOThread,
81                 this, controller_id, buffer_id, timestamp));
82}
83
84void VideoCaptureHost::OnFrameInfo(
85    const VideoCaptureControllerID& controller_id,
86    const media::VideoCaptureCapability& format) {
87  BrowserThread::PostTask(
88      BrowserThread::IO,
89      FROM_HERE,
90      base::Bind(&VideoCaptureHost::DoSendFrameInfoOnIOThread,
91                 this, controller_id, format));
92}
93
94void VideoCaptureHost::OnFrameInfoChanged(
95    const VideoCaptureControllerID& controller_id,
96    int width,
97    int height,
98    int frame_rate) {
99  BrowserThread::PostTask(
100      BrowserThread::IO, FROM_HERE,
101      base::Bind(&VideoCaptureHost::DoSendFrameInfoChangedOnIOThread,
102                 this, controller_id, width, height, frame_rate));
103}
104
105void VideoCaptureHost::OnEnded(const VideoCaptureControllerID& controller_id) {
106  DVLOG(1) << "VideoCaptureHost::OnEnded";
107  BrowserThread::PostTask(
108      BrowserThread::IO, FROM_HERE,
109      base::Bind(&VideoCaptureHost::DoEndedOnIOThread, this, controller_id));
110}
111
112void VideoCaptureHost::DoSendNewBufferOnIOThread(
113    const VideoCaptureControllerID& controller_id,
114    base::SharedMemoryHandle handle,
115    int length,
116    int buffer_id) {
117  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
118
119  if (entries_.find(controller_id) == entries_.end())
120    return;
121
122  Send(new VideoCaptureMsg_NewBuffer(controller_id.device_id, handle,
123                                     length, buffer_id));
124}
125
126void VideoCaptureHost::DoSendFilledBufferOnIOThread(
127    const VideoCaptureControllerID& controller_id,
128    int buffer_id, base::Time timestamp) {
129  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
130
131  if (entries_.find(controller_id) == entries_.end())
132    return;
133
134  Send(new VideoCaptureMsg_BufferReady(controller_id.device_id, buffer_id,
135                                       timestamp));
136}
137
138void VideoCaptureHost::DoHandleErrorOnIOThread(
139    const VideoCaptureControllerID& controller_id) {
140  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
141
142  if (entries_.find(controller_id) == entries_.end())
143    return;
144
145  Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
146                                        VIDEO_CAPTURE_STATE_ERROR));
147  DeleteVideoCaptureControllerOnIOThread(controller_id);
148}
149
150void VideoCaptureHost::DoEndedOnIOThread(
151    const VideoCaptureControllerID& controller_id) {
152  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
153  DVLOG(1) << "VideoCaptureHost::DoEndedOnIOThread";
154  if (entries_.find(controller_id) == entries_.end())
155    return;
156
157  Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
158                                        VIDEO_CAPTURE_STATE_ENDED));
159  DeleteVideoCaptureControllerOnIOThread(controller_id);
160}
161
162void VideoCaptureHost::DoSendFrameInfoOnIOThread(
163    const VideoCaptureControllerID& controller_id,
164    const media::VideoCaptureCapability& format) {
165  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
166
167  if (entries_.find(controller_id) == entries_.end())
168    return;
169
170  media::VideoCaptureParams params;
171  params.width = format.width;
172  params.height = format.height;
173  params.frame_rate = format.frame_rate;
174  params.frame_size_type = format.frame_size_type;
175  Send(new VideoCaptureMsg_DeviceInfo(controller_id.device_id, params));
176  Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
177                                        VIDEO_CAPTURE_STATE_STARTED));
178}
179
180void VideoCaptureHost::DoSendFrameInfoChangedOnIOThread(
181    const VideoCaptureControllerID& controller_id,
182    int width,
183    int height,
184    int frame_rate) {
185  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
186
187  if (entries_.find(controller_id) == entries_.end())
188    return;
189
190  media::VideoCaptureParams params;
191  params.width = width;
192  params.height = height;
193  params.frame_rate = frame_rate;
194  Send(new VideoCaptureMsg_DeviceInfoChanged(controller_id.device_id, params));
195}
196
197///////////////////////////////////////////////////////////////////////////////
198// IPC Messages handler.
199bool VideoCaptureHost::OnMessageReceived(const IPC::Message& message,
200                                         bool* message_was_ok) {
201  bool handled = true;
202  IPC_BEGIN_MESSAGE_MAP_EX(VideoCaptureHost, message, *message_was_ok)
203    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Start, OnStartCapture)
204    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Pause, OnPauseCapture)
205    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Stop, OnStopCapture)
206    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady, OnReceiveEmptyBuffer)
207    IPC_MESSAGE_UNHANDLED(handled = false)
208  IPC_END_MESSAGE_MAP_EX()
209
210  return handled;
211}
212
213void VideoCaptureHost::OnStartCapture(int device_id,
214                                      const media::VideoCaptureParams& params) {
215  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
216  DVLOG(1) << "VideoCaptureHost::OnStartCapture, device_id " << device_id
217           << ", (" << params.width << ", " << params.height << ", "
218           << params.frame_rate << ", " << params.session_id
219           << ", variable resolution device:"
220           << ((params.frame_size_type ==
221               media::VariableResolutionVideoCaptureDevice) ? "yes" : "no")
222            << ")";
223  VideoCaptureControllerID controller_id(device_id);
224  DCHECK(entries_.find(controller_id) == entries_.end());
225
226  entries_[controller_id] = new Entry(NULL);
227  media_stream_manager_->video_capture_manager()->AddController(
228      params, this, base::Bind(&VideoCaptureHost::OnControllerAdded, this,
229                               device_id, params));
230}
231
232void VideoCaptureHost::OnControllerAdded(
233    int device_id, const media::VideoCaptureParams& params,
234    VideoCaptureController* controller) {
235  BrowserThread::PostTask(
236      BrowserThread::IO, FROM_HERE,
237      base::Bind(&VideoCaptureHost::DoControllerAddedOnIOThread,
238                 this, device_id, params, make_scoped_refptr(controller)));
239}
240
241void VideoCaptureHost::DoControllerAddedOnIOThread(
242    int device_id, const media::VideoCaptureParams params,
243    VideoCaptureController* controller) {
244  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
245  VideoCaptureControllerID controller_id(device_id);
246  EntryMap::iterator it = entries_.find(controller_id);
247  if (it == entries_.end()) {
248    if (controller) {
249      media_stream_manager_->video_capture_manager()->RemoveController(
250          controller, this);
251    }
252    return;
253  }
254
255  if (controller == NULL) {
256    Send(new VideoCaptureMsg_StateChanged(device_id,
257                                          VIDEO_CAPTURE_STATE_ERROR));
258    delete it->second;
259    entries_.erase(controller_id);
260    return;
261  }
262
263  it->second->controller = controller;
264  controller->StartCapture(controller_id, this, PeerHandle(), params);
265}
266
267void VideoCaptureHost::OnStopCapture(int device_id) {
268  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
269  DVLOG(1) << "VideoCaptureHost::OnStopCapture, device_id " << device_id;
270
271  VideoCaptureControllerID controller_id(device_id);
272
273  Send(new VideoCaptureMsg_StateChanged(device_id,
274                                        VIDEO_CAPTURE_STATE_STOPPED));
275  DeleteVideoCaptureControllerOnIOThread(controller_id);
276}
277
278void VideoCaptureHost::OnPauseCapture(int device_id) {
279  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
280  DVLOG(1) << "VideoCaptureHost::OnPauseCapture, device_id " << device_id;
281  // Not used.
282  Send(new VideoCaptureMsg_StateChanged(device_id, VIDEO_CAPTURE_STATE_ERROR));
283}
284
285void VideoCaptureHost::OnReceiveEmptyBuffer(int device_id, int buffer_id) {
286  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
287
288  VideoCaptureControllerID controller_id(device_id);
289  EntryMap::iterator it = entries_.find(controller_id);
290  if (it != entries_.end()) {
291    scoped_refptr<VideoCaptureController> controller = it->second->controller;
292    if (controller.get())
293      controller->ReturnBuffer(controller_id, this, buffer_id);
294  }
295}
296
297void VideoCaptureHost::DeleteVideoCaptureControllerOnIOThread(
298    const VideoCaptureControllerID& controller_id) {
299  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
300
301  EntryMap::iterator it = entries_.find(controller_id);
302  if (it == entries_.end())
303    return;
304
305  VideoCaptureController* controller = it->second->controller.get();
306  if (controller) {
307    controller->StopCapture(controller_id, this);
308    media_stream_manager_->video_capture_manager()->RemoveController(
309        controller, this);
310  }
311  delete it->second;
312  entries_.erase(controller_id);
313}
314
315}  // namespace content
316