video_capture_host.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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 "content/browser/browser_main_loop.h"
10#include "content/browser/renderer_host/media/media_stream_manager.h"
11#include "content/browser/renderer_host/media/video_capture_manager.h"
12#include "content/common/media/video_capture_messages.h"
13
14namespace content {
15
16VideoCaptureHost::VideoCaptureHost(MediaStreamManager* media_stream_manager)
17    : BrowserMessageFilter(VideoCaptureMsgStart),
18      media_stream_manager_(media_stream_manager) {
19}
20
21VideoCaptureHost::~VideoCaptureHost() {}
22
23void VideoCaptureHost::OnChannelClosing() {
24  // Since the IPC channel is gone, close all requested VideoCaptureDevices.
25  for (EntryMap::iterator it = entries_.begin(); it != entries_.end(); ) {
26    const base::WeakPtr<VideoCaptureController>& controller = it->second;
27    if (controller) {
28      VideoCaptureControllerID controller_id(it->first);
29      media_stream_manager_->video_capture_manager()->StopCaptureForClient(
30          controller.get(), controller_id, this, false);
31      ++it;
32    } else {
33      // Remove the entry for this controller_id so that when the controller
34      // is added, the controller will be notified to stop for this client
35      // in DoControllerAddedOnIOThread.
36      entries_.erase(it++);
37    }
38  }
39}
40
41void VideoCaptureHost::OnDestruct() const {
42  BrowserThread::DeleteOnIOThread::Destruct(this);
43}
44
45///////////////////////////////////////////////////////////////////////////////
46
47// Implements VideoCaptureControllerEventHandler.
48void VideoCaptureHost::OnError(const VideoCaptureControllerID& controller_id) {
49  DVLOG(1) << "VideoCaptureHost::OnError";
50  BrowserThread::PostTask(
51      BrowserThread::IO, FROM_HERE,
52      base::Bind(&VideoCaptureHost::DoHandleErrorOnIOThread,
53                 this, controller_id));
54}
55
56void VideoCaptureHost::OnBufferCreated(
57    const VideoCaptureControllerID& controller_id,
58    base::SharedMemoryHandle handle,
59    int length,
60    int buffer_id) {
61  BrowserThread::PostTask(
62      BrowserThread::IO, FROM_HERE,
63      base::Bind(&VideoCaptureHost::DoSendNewBufferOnIOThread,
64                 this, controller_id, handle, length, buffer_id));
65}
66
67void VideoCaptureHost::OnBufferDestroyed(
68    const VideoCaptureControllerID& controller_id,
69    int buffer_id) {
70  BrowserThread::PostTask(
71      BrowserThread::IO, FROM_HERE,
72      base::Bind(&VideoCaptureHost::DoSendFreeBufferOnIOThread,
73                 this, controller_id, buffer_id));
74}
75
76void VideoCaptureHost::OnBufferReady(
77    const VideoCaptureControllerID& controller_id,
78    int buffer_id,
79    const media::VideoCaptureFormat& frame_format,
80    base::TimeTicks timestamp) {
81  BrowserThread::PostTask(
82      BrowserThread::IO,
83      FROM_HERE,
84      base::Bind(&VideoCaptureHost::DoSendFilledBufferOnIOThread,
85                 this,
86                 controller_id,
87                 buffer_id,
88                 frame_format,
89                 timestamp));
90}
91
92void VideoCaptureHost::OnMailboxBufferReady(
93    const VideoCaptureControllerID& controller_id,
94    int buffer_id,
95    const gpu::MailboxHolder& mailbox_holder,
96    const media::VideoCaptureFormat& frame_format,
97    base::TimeTicks timestamp) {
98  BrowserThread::PostTask(
99      BrowserThread::IO,
100      FROM_HERE,
101      base::Bind(&VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread,
102                 this,
103                 controller_id,
104                 buffer_id,
105                 mailbox_holder,
106                 frame_format,
107                 timestamp));
108}
109
110void VideoCaptureHost::OnEnded(const VideoCaptureControllerID& controller_id) {
111  DVLOG(1) << "VideoCaptureHost::OnEnded";
112  BrowserThread::PostTask(
113      BrowserThread::IO, FROM_HERE,
114      base::Bind(&VideoCaptureHost::DoEndedOnIOThread, this, controller_id));
115}
116
117void VideoCaptureHost::DoSendNewBufferOnIOThread(
118    const VideoCaptureControllerID& controller_id,
119    base::SharedMemoryHandle handle,
120    int length,
121    int buffer_id) {
122  DCHECK_CURRENTLY_ON(BrowserThread::IO);
123
124  if (entries_.find(controller_id) == entries_.end())
125    return;
126
127  Send(new VideoCaptureMsg_NewBuffer(controller_id.device_id, handle,
128                                     length, buffer_id));
129}
130
131void VideoCaptureHost::DoSendFreeBufferOnIOThread(
132    const VideoCaptureControllerID& controller_id,
133    int buffer_id) {
134  DCHECK_CURRENTLY_ON(BrowserThread::IO);
135
136  if (entries_.find(controller_id) == entries_.end())
137    return;
138
139  Send(new VideoCaptureMsg_FreeBuffer(controller_id.device_id, buffer_id));
140}
141
142void VideoCaptureHost::DoSendFilledBufferOnIOThread(
143    const VideoCaptureControllerID& controller_id,
144    int buffer_id,
145    const media::VideoCaptureFormat& format,
146    base::TimeTicks timestamp) {
147  DCHECK_CURRENTLY_ON(BrowserThread::IO);
148
149  if (entries_.find(controller_id) == entries_.end())
150    return;
151
152  Send(new VideoCaptureMsg_BufferReady(
153      controller_id.device_id, buffer_id, format, timestamp));
154}
155
156void VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread(
157    const VideoCaptureControllerID& controller_id,
158    int buffer_id,
159    const gpu::MailboxHolder& mailbox_holder,
160    const media::VideoCaptureFormat& format,
161    base::TimeTicks timestamp) {
162  DCHECK_CURRENTLY_ON(BrowserThread::IO);
163
164  if (entries_.find(controller_id) == entries_.end())
165    return;
166
167  Send(new VideoCaptureMsg_MailboxBufferReady(
168      controller_id.device_id, buffer_id, mailbox_holder, format, timestamp));
169}
170
171void VideoCaptureHost::DoHandleErrorOnIOThread(
172    const VideoCaptureControllerID& controller_id) {
173  DCHECK_CURRENTLY_ON(BrowserThread::IO);
174
175  if (entries_.find(controller_id) == entries_.end())
176    return;
177
178  Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
179                                        VIDEO_CAPTURE_STATE_ERROR));
180  DeleteVideoCaptureControllerOnIOThread(controller_id, true);
181}
182
183void VideoCaptureHost::DoEndedOnIOThread(
184    const VideoCaptureControllerID& controller_id) {
185  DCHECK_CURRENTLY_ON(BrowserThread::IO);
186  DVLOG(1) << "VideoCaptureHost::DoEndedOnIOThread";
187  if (entries_.find(controller_id) == entries_.end())
188    return;
189
190  Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
191                                        VIDEO_CAPTURE_STATE_ENDED));
192  DeleteVideoCaptureControllerOnIOThread(controller_id, false);
193}
194
195///////////////////////////////////////////////////////////////////////////////
196// IPC Messages handler.
197bool VideoCaptureHost::OnMessageReceived(const IPC::Message& message,
198                                         bool* message_was_ok) {
199  bool handled = true;
200  IPC_BEGIN_MESSAGE_MAP_EX(VideoCaptureHost, message, *message_was_ok)
201    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Start, OnStartCapture)
202    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Pause, OnPauseCapture)
203    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Stop, OnStopCapture)
204    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady, OnReceiveEmptyBuffer)
205    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_GetDeviceSupportedFormats,
206                        OnGetDeviceSupportedFormats)
207    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_GetDeviceFormatsInUse,
208                        OnGetDeviceFormatsInUse)
209    IPC_MESSAGE_UNHANDLED(handled = false)
210  IPC_END_MESSAGE_MAP_EX()
211
212  return handled;
213}
214
215void VideoCaptureHost::OnStartCapture(int device_id,
216                                      media::VideoCaptureSessionId session_id,
217                                      const media::VideoCaptureParams& params) {
218  DCHECK_CURRENTLY_ON(BrowserThread::IO);
219  DVLOG(1) << "VideoCaptureHost::OnStartCapture:"
220           << " session_id=" << session_id
221           << ", device_id=" << device_id
222           << ", format=" << params.requested_format.frame_size.ToString()
223           << "@" << params.requested_format.frame_rate
224           << " (" << (params.allow_resolution_change ? "variable" : "constant")
225           << ")";
226  VideoCaptureControllerID controller_id(device_id);
227  if (entries_.find(controller_id) != entries_.end()) {
228    Send(new VideoCaptureMsg_StateChanged(device_id,
229                                          VIDEO_CAPTURE_STATE_ERROR));
230    return;
231  }
232
233  entries_[controller_id] = base::WeakPtr<VideoCaptureController>();
234  media_stream_manager_->video_capture_manager()->StartCaptureForClient(
235      session_id,
236      params,
237      PeerHandle(),
238      controller_id,
239      this,
240      base::Bind(&VideoCaptureHost::OnControllerAdded, this, device_id));
241}
242
243void VideoCaptureHost::OnControllerAdded(
244    int device_id,
245    const base::WeakPtr<VideoCaptureController>& controller) {
246  BrowserThread::PostTask(
247      BrowserThread::IO,
248      FROM_HERE,
249      base::Bind(&VideoCaptureHost::DoControllerAddedOnIOThread,
250                 this,
251                 device_id,
252                 controller));
253}
254
255void VideoCaptureHost::DoControllerAddedOnIOThread(
256    int device_id,
257    const base::WeakPtr<VideoCaptureController>& controller) {
258  DCHECK_CURRENTLY_ON(BrowserThread::IO);
259  VideoCaptureControllerID controller_id(device_id);
260  EntryMap::iterator it = entries_.find(controller_id);
261  if (it == entries_.end()) {
262    if (controller) {
263      media_stream_manager_->video_capture_manager()->StopCaptureForClient(
264          controller.get(), controller_id, this, false);
265    }
266    return;
267  }
268
269  if (!controller) {
270    Send(new VideoCaptureMsg_StateChanged(device_id,
271                                          VIDEO_CAPTURE_STATE_ERROR));
272    entries_.erase(controller_id);
273    return;
274  }
275
276  DCHECK(!it->second);
277  it->second = controller;
278}
279
280void VideoCaptureHost::OnStopCapture(int device_id) {
281  DCHECK_CURRENTLY_ON(BrowserThread::IO);
282  DVLOG(1) << "VideoCaptureHost::OnStopCapture, device_id " << device_id;
283
284  VideoCaptureControllerID controller_id(device_id);
285
286  Send(new VideoCaptureMsg_StateChanged(device_id,
287                                        VIDEO_CAPTURE_STATE_STOPPED));
288  DeleteVideoCaptureControllerOnIOThread(controller_id, false);
289}
290
291void VideoCaptureHost::OnPauseCapture(int device_id) {
292  DCHECK_CURRENTLY_ON(BrowserThread::IO);
293  DVLOG(1) << "VideoCaptureHost::OnPauseCapture, device_id " << device_id;
294  // Not used.
295  Send(new VideoCaptureMsg_StateChanged(device_id, VIDEO_CAPTURE_STATE_ERROR));
296}
297
298void VideoCaptureHost::OnReceiveEmptyBuffer(
299    int device_id,
300    int buffer_id,
301    const std::vector<uint32>& sync_points) {
302  DCHECK_CURRENTLY_ON(BrowserThread::IO);
303
304  VideoCaptureControllerID controller_id(device_id);
305  EntryMap::iterator it = entries_.find(controller_id);
306  if (it != entries_.end()) {
307    const base::WeakPtr<VideoCaptureController>& controller = it->second;
308    if (controller)
309      controller->ReturnBuffer(controller_id, this, buffer_id, sync_points);
310  }
311}
312
313void VideoCaptureHost::OnGetDeviceSupportedFormats(
314    int device_id,
315    media::VideoCaptureSessionId capture_session_id) {
316  DCHECK_CURRENTLY_ON(BrowserThread::IO);
317  DVLOG(1) << "VideoCaptureHost::OnGetDeviceFormats, capture_session_id "
318           << capture_session_id;
319  media::VideoCaptureFormats device_supported_formats;
320  if (!media_stream_manager_->video_capture_manager()
321           ->GetDeviceSupportedFormats(capture_session_id,
322                                       &device_supported_formats)) {
323    DLOG(WARNING)
324        << "Could not retrieve device supported formats for device_id="
325        << device_id << " capture_session_id=" << capture_session_id;
326  }
327  Send(new VideoCaptureMsg_DeviceSupportedFormatsEnumerated(
328      device_id, device_supported_formats));
329}
330
331void VideoCaptureHost::OnGetDeviceFormatsInUse(
332    int device_id,
333    media::VideoCaptureSessionId capture_session_id) {
334  DCHECK_CURRENTLY_ON(BrowserThread::IO);
335  DVLOG(1) << "VideoCaptureHost::OnGetDeviceFormatsInUse, capture_session_id "
336           << capture_session_id;
337  media::VideoCaptureFormats formats_in_use;
338  if (!media_stream_manager_->video_capture_manager()->GetDeviceFormatsInUse(
339           capture_session_id, &formats_in_use)) {
340    DVLOG(1) << "Could not retrieve device format(s) in use for device_id="
341             << device_id << " capture_session_id=" << capture_session_id;
342  }
343  Send(new VideoCaptureMsg_DeviceFormatsInUseReceived(device_id,
344                                                      formats_in_use));
345}
346
347void VideoCaptureHost::DeleteVideoCaptureControllerOnIOThread(
348    const VideoCaptureControllerID& controller_id, bool on_error) {
349  DCHECK_CURRENTLY_ON(BrowserThread::IO);
350
351  EntryMap::iterator it = entries_.find(controller_id);
352  if (it == entries_.end())
353    return;
354
355  if (it->second) {
356    media_stream_manager_->video_capture_manager()->StopCaptureForClient(
357        it->second.get(), controller_id, this, on_error);
358  }
359  entries_.erase(it);
360}
361
362}  // namespace content
363