15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_controller.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <map>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/debug/trace_event.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/metrics/histogram.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/metrics/sparse_histogram.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/strings/stringprintf.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/media_stream_manager.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_manager.h"
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/common/gpu/client/gl_helper.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "gpu/command_buffer/common/mailbox_holder.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/video_frame.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/video_util.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/yuv_convert.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/libyuv/include/libyuv.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_ANDROID)
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/browser/renderer_host/image_transport_factory_android.h"
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#else
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/browser/compositor/image_transport_factory.h"
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using media::VideoCaptureFormat;
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace {
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static const int kInfiniteRatio = 99999;
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#define UMA_HISTOGRAM_ASPECT_RATIO(name, width, height) \
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    UMA_HISTOGRAM_SPARSE_SLOWLY( \
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        name, \
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        (height) ? ((width) * 100) / (height) : kInfiniteRatio);
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class PoolBuffer : public media::VideoCaptureDevice::Client::Buffer {
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public:
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  PoolBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool,
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)             int buffer_id,
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)             void* data,
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)             size_t size)
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      : Buffer(buffer_id, data, size), pool_(pool) {
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(pool_.get());
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private:
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual ~PoolBuffer() { pool_->RelinquishProducerReservation(id()); }
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const scoped_refptr<VideoCaptureBufferPool> pool_;
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)};
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public:
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  explicit SyncPointClientImpl(GLHelper* gl_helper) : gl_helper_(gl_helper) {}
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual ~SyncPointClientImpl() {}
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual uint32 InsertSyncPoint() OVERRIDE {
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return gl_helper_->InsertSyncPoint();
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE {
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    gl_helper_->WaitSyncPoint(sync_point);
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) private:
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  GLHelper* gl_helper_;
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ReturnVideoFrame(const scoped_refptr<media::VideoFrame>& video_frame,
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                      uint32 sync_point) {
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::UI);
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_ANDROID)
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  GLHelper* gl_helper =
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#else
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(gl_helper);
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // UpdateReleaseSyncPoint() creates a new sync_point using |gl_helper|, so
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // wait the given |sync_point| using |gl_helper|.
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  gl_helper->WaitSyncPoint(sync_point);
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SyncPointClientImpl client(gl_helper);
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  video_frame->UpdateReleaseSyncPoint(&client);
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // anonymous namespace
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct VideoCaptureController::ControllerClient {
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ControllerClient(const VideoCaptureControllerID& id,
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   VideoCaptureControllerEventHandler* handler,
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   base::ProcessHandle render_process,
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   media::VideoCaptureSessionId session_id,
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   const media::VideoCaptureParams& params)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : controller_id(id),
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        event_handler(handler),
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        render_process_handle(render_process),
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        session_id(session_id),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        parameters(params),
10634680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)        session_closed(false),
10734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)        paused(false) {}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~ControllerClient() {}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ID used for identifying this object.
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const VideoCaptureControllerID controller_id;
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  VideoCaptureControllerEventHandler* const event_handler;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Handle to the render process that will receive the capture buffers.
116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const base::ProcessHandle render_process_handle;
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const media::VideoCaptureSessionId session_id;
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const media::VideoCaptureParams parameters;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Buffers that are currently known to this client.
1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::set<int> known_buffers;
1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Buffers currently held by this client, and syncpoint callback to call when
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // they are returned from the client.
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  typedef std::map<int, scoped_refptr<media::VideoFrame> > ActiveBufferMap;
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ActiveBufferMap active_buffers;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // State of capture session, controlled by VideoCaptureManager directly. This
129d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // transitions to true as soon as StopSession() occurs, at which point the
130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // client is sent an OnEnded() event. However, because the client retains a
131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // VideoCaptureController* pointer, its ControllerClient entry lives on until
132d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // it unregisters itself via RemoveClient(), which may happen asynchronously.
133d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //
134d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // TODO(nick): If we changed the semantics of VideoCaptureHost so that
135d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // OnEnded() events were processed synchronously (with the RemoveClient() done
136d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // implicitly), we could avoid tracking this state here in the Controller, and
137d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // simplify the code in both places.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool session_closed;
13934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
14034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  // Indicates whether the client is paused, if true, VideoCaptureController
14134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  // stops updating its buffer.
14234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  bool paused;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Receives events from the VideoCaptureDevice and posts them to a
146d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// VideoCaptureController on the IO thread. An instance of this class may safely
147d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// outlive its target VideoCaptureController.
148d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)//
149d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Methods of this class may be called from any thread, and in practice will
150d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// often be called on some auxiliary thread depending on the platform and the
151d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// device type; including, for example, the DirectShow thread on Windows, the
152d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// v4l2_thread on Linux, and the UI thread for tab capture.
153d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class VideoCaptureController::VideoCaptureDeviceClient
15468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    : public media::VideoCaptureDevice::Client {
155d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public:
156d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  explicit VideoCaptureDeviceClient(
1571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      const base::WeakPtr<VideoCaptureController>& controller,
1581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      const scoped_refptr<VideoCaptureBufferPool>& buffer_pool);
159d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  virtual ~VideoCaptureDeviceClient();
160d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
16168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // VideoCaptureDevice::Client implementation.
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual scoped_refptr<Buffer> ReserveOutputBuffer(
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      media::VideoFrame::Format format,
1641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      const gfx::Size& size) OVERRIDE;
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void OnIncomingCapturedData(const uint8* data,
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      int length,
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      const VideoCaptureFormat& frame_format,
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      int rotation,
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      base::TimeTicks timestamp) OVERRIDE;
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void OnIncomingCapturedVideoFrame(
171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const scoped_refptr<Buffer>& buffer,
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const VideoCaptureFormat& buffer_format,
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const scoped_refptr<media::VideoFrame>& frame,
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::TimeTicks timestamp) OVERRIDE;
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnError(const std::string& reason) OVERRIDE;
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void OnLog(const std::string& message) OVERRIDE;
177d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
178d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private:
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_refptr<Buffer> DoReserveOutputBuffer(media::VideoFrame::Format format,
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              const gfx::Size& dimensions);
1811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
182d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // The controller to which we post events.
183d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const base::WeakPtr<VideoCaptureController> controller_;
184d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
185d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // The pool of shared-memory buffers used for capturing.
1861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
187d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)};
188d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)VideoCaptureController::VideoCaptureController(int max_buffers)
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : buffer_pool_(new VideoCaptureBufferPool(max_buffers)),
1911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      state_(VIDEO_CAPTURE_STATE_STARTED),
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      frame_received_(false),
193d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      weak_ptr_factory_(this) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
196d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient(
1971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const base::WeakPtr<VideoCaptureController>& controller,
1981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const scoped_refptr<VideoCaptureBufferPool>& buffer_pool)
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : controller_(controller), buffer_pool_(buffer_pool) {}
200d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
201d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {}
202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)base::WeakPtr<VideoCaptureController> VideoCaptureController::GetWeakPtr() {
204d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return weak_ptr_factory_.GetWeakPtr();
205d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
20768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)scoped_ptr<media::VideoCaptureDevice::Client>
208d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)VideoCaptureController::NewDeviceClient() {
20968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  scoped_ptr<media::VideoCaptureDevice::Client> result(
2101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new VideoCaptureDeviceClient(this->GetWeakPtr(), buffer_pool_));
211d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return result.Pass();
212d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
213d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
214d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void VideoCaptureController::AddClient(
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VideoCaptureControllerID& id,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VideoCaptureControllerEventHandler* event_handler,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ProcessHandle render_process,
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    media::VideoCaptureSessionId session_id,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const media::VideoCaptureParams& params) {
220effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
221d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DVLOG(1) << "VideoCaptureController::AddClient, id " << id.device_id
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)           << ", " << params.requested_format.frame_size.ToString()
2231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)           << ", " << params.requested_format.frame_rate
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)           << ", " << session_id
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           << ")";
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If this is the first client added to the controller, cache the parameters.
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!controller_clients_.size())
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    video_capture_format_ = params.requested_format;
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Signal error in case device is already in error state.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == VIDEO_CAPTURE_STATE_ERROR) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event_handler->OnError(id);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
237d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Do nothing if this client has called AddClient before.
238d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (FindClient(id, event_handler, controller_clients_))
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ControllerClient* client = new ControllerClient(
242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      id, event_handler, render_process, session_id, params);
243d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // If we already have gotten frame_info from the device, repeat it to the new
244d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // client.
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller_clients_.push_back(client);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
251d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)int VideoCaptureController::RemoveClient(
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VideoCaptureControllerID& id,
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VideoCaptureControllerEventHandler* event_handler) {
254effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
255d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id.device_id;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
257d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ControllerClient* client = FindClient(id, event_handler, controller_clients_);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!client)
259d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return kInvalidMediaCaptureSessionId;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Take back all buffers held by the |client|.
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (ControllerClient::ActiveBufferMap::iterator buffer_it =
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)           client->active_buffers.begin();
2641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       buffer_it != client->active_buffers.end();
2651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       ++buffer_it) {
266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    buffer_pool_->RelinquishConsumerHold(buffer_it->first, 1);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  client->active_buffers.clear();
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int session_id = client->session_id;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  controller_clients_.remove(client);
272d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  delete client;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
274d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return session_id;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)void VideoCaptureController::PauseOrResumeClient(
27834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    const VideoCaptureControllerID& id,
27934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    VideoCaptureControllerEventHandler* event_handler,
28034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    bool pause) {
28134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
28234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DVLOG(1) << "VideoCaptureController::PauseOrResumeClient, id "
28334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)           << id.device_id << ", " << pause;
28434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
28534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  ControllerClient* client = FindClient(id, event_handler, controller_clients_);
28634680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (!client)
28734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    return;
28834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
28934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DCHECK(client->paused != pause);
29034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  client->paused = pause;
29134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)}
29234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
293d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void VideoCaptureController::StopSession(int session_id) {
294effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "VideoCaptureController::StopSession, id " << session_id;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
297d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ControllerClient* client = FindClient(session_id, controller_clients_);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (client) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client->session_closed = true;
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    client->event_handler->OnEnded(client->controller_id);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void VideoCaptureController::ReturnBuffer(
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VideoCaptureControllerID& id,
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VideoCaptureControllerEventHandler* event_handler,
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int buffer_id,
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    uint32 sync_point) {
310effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
312d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ControllerClient* client = FindClient(id, event_handler, controller_clients_);
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If this buffer is not held by this client, or this client doesn't exist
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in controller, do nothing.
316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ControllerClient::ActiveBufferMap::iterator iter;
317a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!client || (iter = client->active_buffers.find(buffer_id)) ==
318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     client->active_buffers.end()) {
319d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    NOTREACHED();
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
321d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
322a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<media::VideoFrame> frame = iter->second;
323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  client->active_buffers.erase(iter);
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (sync_point)
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BrowserThread::PostTask(BrowserThread::UI,
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            FROM_HERE,
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            base::Bind(&ReturnVideoFrame, frame, sync_point));
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const media::VideoCaptureFormat&
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VideoCaptureController::GetVideoCaptureFormat() const {
334effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return video_capture_format_;
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)scoped_refptr<media::VideoCaptureDevice::Client::Buffer>
3391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer(
340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    media::VideoFrame::Format format,
3411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const gfx::Size& size) {
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return DoReserveOutputBuffer(format, size);
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
345a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedData(
34658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const uint8* data,
34758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    int length,
348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const VideoCaptureFormat& frame_format,
34958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    int rotation,
350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::TimeTicks timestamp) {
351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedData");
35258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!frame_format.IsValid())
354d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return;
3551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
356010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Chopped pixels in width/height in case video capture device has odd
357010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // numbers for width/height.
358010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  int chopped_width = 0;
359010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  int chopped_height = 0;
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int new_unrotated_width = frame_format.frame_size.width();
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int new_unrotated_height = frame_format.frame_size.height();
362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (new_unrotated_width & 1) {
364010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    --new_unrotated_width;
365010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    chopped_width = 1;
366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (new_unrotated_height & 1) {
368010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    --new_unrotated_height;
369010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    chopped_height = 1;
370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int destination_width = new_unrotated_width;
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int destination_height = new_unrotated_height;
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (rotation == 90 || rotation == 270) {
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    destination_width = new_unrotated_height;
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    destination_height = new_unrotated_width;
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const gfx::Size dimensions(destination_width, destination_height);
379c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!media::VideoFrame::IsValidConfig(media::VideoFrame::I420,
380c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                        dimensions,
381c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                        gfx::Rect(dimensions),
382c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                        dimensions)) {
383c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
384c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
385c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_refptr<Buffer> buffer =
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DoReserveOutputBuffer(media::VideoFrame::I420, dimensions);
38858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!buffer.get())
39058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
391a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  uint8* yplane = NULL;
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool flip = false;
393a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  yplane = reinterpret_cast<uint8*>(buffer->data());
394f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  uint8* uplane =
395f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      yplane +
396f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      media::VideoFrame::PlaneAllocationSize(
397f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          media::VideoFrame::I420, media::VideoFrame::kYPlane, dimensions);
398f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  uint8* vplane =
399f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      uplane +
400f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      media::VideoFrame::PlaneAllocationSize(
401f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          media::VideoFrame::I420, media::VideoFrame::kUPlane, dimensions);
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int yplane_stride = dimensions.width();
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int uv_plane_stride = yplane_stride / 2;
40458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  int crop_x = 0;
40558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  int crop_y = 0;
40658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY;
407f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
40858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  libyuv::RotationMode rotation_mode = libyuv::kRotate0;
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (rotation == 90)
41058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    rotation_mode = libyuv::kRotate90;
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else if (rotation == 180)
41258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    rotation_mode = libyuv::kRotate180;
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else if (rotation == 270)
41458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    rotation_mode = libyuv::kRotate270;
41558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  switch (frame_format.pixel_format) {
41758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case media::PIXEL_FORMAT_UNKNOWN:  // Color format not set.
41858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
41958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case media::PIXEL_FORMAT_I420:
420010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      DCHECK(!chopped_width && !chopped_height);
42158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      origin_colorspace = libyuv::FOURCC_I420;
42258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
42358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case media::PIXEL_FORMAT_YV12:
424010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      DCHECK(!chopped_width && !chopped_height);
42558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      origin_colorspace = libyuv::FOURCC_YV12;
42658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
42758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case media::PIXEL_FORMAT_NV21:
428010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      DCHECK(!chopped_width && !chopped_height);
429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      origin_colorspace = libyuv::FOURCC_NV21;
43058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
43158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case media::PIXEL_FORMAT_YUY2:
432010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      DCHECK(!chopped_width && !chopped_height);
43358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      origin_colorspace = libyuv::FOURCC_YUY2;
43458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
43558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case media::PIXEL_FORMAT_UYVY:
436010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      DCHECK(!chopped_width && !chopped_height);
43758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      origin_colorspace = libyuv::FOURCC_UYVY;
43858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
43958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case media::PIXEL_FORMAT_RGB24:
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      origin_colorspace = libyuv::FOURCC_24BG;
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_WIN)
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // TODO(wjia): Currently, for RGB24 on WIN, capture device always
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // passes in positive src_width and src_height. Remove this hardcoded
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // value when nagative src_height is supported. The negative src_height
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // indicates that vertical flipping is needed.
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      flip = true;
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
44858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
44958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case media::PIXEL_FORMAT_ARGB:
45058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      origin_colorspace = libyuv::FOURCC_ARGB;
45158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
45258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case media::PIXEL_FORMAT_MJPEG:
45358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      origin_colorspace = libyuv::FOURCC_MJPG;
45458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
45558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    default:
45658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      NOTREACHED();
45758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
45858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  libyuv::ConvertToI420(data,
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        length,
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        yplane,
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        yplane_stride,
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        uplane,
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        uv_plane_stride,
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        vplane,
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        uv_plane_stride,
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        crop_x,
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        crop_y,
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        frame_format.frame_size.width(),
470010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                        (flip ? -frame_format.frame_size.height() :
471010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                frame_format.frame_size.height()),
472010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                        new_unrotated_width,
473010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                        new_unrotated_height,
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        rotation_mode,
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        origin_colorspace);
476a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<media::VideoFrame> frame =
477a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      media::VideoFrame::WrapExternalPackedMemory(
478a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          media::VideoFrame::I420,
479a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          dimensions,
480a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          gfx::Rect(dimensions),
481a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          dimensions,
482a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          yplane,
483a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          media::VideoFrame::AllocationSize(media::VideoFrame::I420,
484a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                            dimensions),
485a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::SharedMemory::NULLHandle(),
486a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::TimeDelta(),
487a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::Closure());
4881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(frame.get());
489c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
490c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  VideoCaptureFormat format(
491c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      dimensions, frame_format.frame_rate, media::PIXEL_FORMAT_I420);
49258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  BrowserThread::PostTask(
49358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      BrowserThread::IO,
49458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      FROM_HERE,
495f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::Bind(
496a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
497f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          controller_,
498f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          buffer,
499a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          format,
500a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          frame,
501f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          timestamp));
50258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
504a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void
505a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
506f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const scoped_refptr<Buffer>& buffer,
507a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const VideoCaptureFormat& buffer_format,
508a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const scoped_refptr<media::VideoFrame>& frame,
509a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::TimeTicks timestamp) {
510f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BrowserThread::PostTask(
511f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      BrowserThread::IO,
512f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FROM_HERE,
513f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::Bind(
514a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
515f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          controller_,
516f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          buffer,
517a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          buffer_format,
518a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          frame,
519f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          timestamp));
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void VideoCaptureController::VideoCaptureDeviceClient::OnError(
5235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& reason) {
5241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const std::string log_message = base::StringPrintf(
5251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      "Error on video capture: %s, OS message: %s",
5261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      reason.c_str(),
5271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      logging::SystemErrorCodeToString(
5281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          logging::GetLastSystemErrorCode()).c_str());
5291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DLOG(ERROR) << log_message;
5301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MediaStreamManager::SendMessageToNativeLog(log_message);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::IO,
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
533d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_));
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
536cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void VideoCaptureController::VideoCaptureDeviceClient::OnLog(
537cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& message) {
538cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  MediaStreamManager::SendMessageToNativeLog("Video capture: " + message);
539cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
540cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
541f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)scoped_refptr<media::VideoCaptureDevice::Client::Buffer>
542f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)VideoCaptureController::VideoCaptureDeviceClient::DoReserveOutputBuffer(
543f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    media::VideoFrame::Format format,
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const gfx::Size& dimensions) {
545a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  size_t frame_bytes = 0;
546a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (format == media::VideoFrame::NATIVE_TEXTURE) {
547a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK_EQ(dimensions.width(), 0);
548a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK_EQ(dimensions.height(), 0);
549a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
550a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // The capture pipeline expects I420 for now.
551a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK_EQ(format, media::VideoFrame::I420)
552a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        << "Non-I420 output buffer format " << format << " requested";
553a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    frame_bytes = media::VideoFrame::AllocationSize(format, dimensions);
554a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
555f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;
557f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int buffer_id =
558f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      buffer_pool_->ReserveForProducer(frame_bytes, &buffer_id_to_drop);
559f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (buffer_id == VideoCaptureBufferPool::kInvalidId)
560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return NULL;
561f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  void* data;
562f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  size_t size;
563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer_pool_->GetBufferInfo(buffer_id, &data, &size);
564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer(
566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      new PoolBuffer(buffer_pool_, buffer_id, data, size));
567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) {
5691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    BrowserThread::PostTask(BrowserThread::IO,
5701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        FROM_HERE,
5711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread,
5721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   controller_, buffer_id_to_drop));
573f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
574f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
575f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return output_buffer;
5767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
5777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VideoCaptureController::~VideoCaptureController() {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteContainerPointers(controller_clients_.begin(),
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             controller_clients_.end());
5811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  UMA_HISTOGRAM_BOOLEAN("Media.VideoCapture.FramesReceived", frame_received_);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
584a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
585a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
586a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const media::VideoCaptureFormat& buffer_format,
587a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const scoped_refptr<media::VideoFrame>& frame,
5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::TimeTicks timestamp) {
589effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
590f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK_NE(buffer->id(), VideoCaptureBufferPool::kInvalidId);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count = 0;
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (ControllerClients::iterator client_it = controller_clients_.begin();
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         client_it != controller_clients_.end(); ++client_it) {
5961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      ControllerClient* client = *client_it;
59734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)      if (client->session_closed || client->paused)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
600a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (frame->format() == media::VideoFrame::NATIVE_TEXTURE) {
601a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        client->event_handler->OnMailboxBufferReady(client->controller_id,
602a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                    buffer->id(),
603a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                    *frame->mailbox_holder(),
604a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                    buffer_format,
605a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                    timestamp);
606a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      } else {
607a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        bool is_new_buffer = client->known_buffers.insert(buffer->id()).second;
608a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (is_new_buffer) {
609a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          // On the first use of a buffer on a client, share the memory handle.
610a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          size_t memory_size = 0;
611a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess(
612a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              buffer->id(), client->render_process_handle, &memory_size);
613a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          client->event_handler->OnBufferCreated(
614a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              client->controller_id, remote_handle, memory_size, buffer->id());
615a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        }
616a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
617a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        client->event_handler->OnBufferReady(
6181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            client->controller_id, buffer->id(), buffer_format,
6191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            frame->visible_rect(), timestamp);
6201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      }
6211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
622a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      bool inserted =
623a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          client->active_buffers.insert(std::make_pair(buffer->id(), frame))
624a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              .second;
625f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer->id();
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      count++;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
6301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!frame_received_) {
6311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width",
6321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         buffer_format.frame_size.width());
6331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height",
6341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         buffer_format.frame_size.height());
6351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio",
6361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               buffer_format.frame_size.width(),
6371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               buffer_format.frame_size.height());
6381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate",
6391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         buffer_format.frame_rate);
6401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UMA_HISTOGRAM_ENUMERATION("Media.VideoCapture.PixelFormat",
6411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              buffer_format.pixel_format,
6421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              media::PIXEL_FORMAT_MAX);
6431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    frame_received_ = true;
6441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
646f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer_pool_->HoldForConsumers(buffer->id(), count);
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void VideoCaptureController::DoErrorOnIOThread() {
650effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
6511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  state_ = VIDEO_CAPTURE_STATE_ERROR;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ControllerClients::iterator client_it = controller_clients_.begin();
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       client_it != controller_clients_.end(); ++client_it) {
6551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    ControllerClient* client = *client_it;
6561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (client->session_closed)
6571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       continue;
658d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    client->event_handler->OnError(client->controller_id);
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void VideoCaptureController::DoBufferDestroyedOnIOThread(
6641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    int buffer_id_to_drop) {
665effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
666d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for (ControllerClients::iterator client_it = controller_clients_.begin();
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       client_it != controller_clients_.end(); ++client_it) {
6691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    ControllerClient* client = *client_it;
6701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (client->session_closed)
6711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      continue;
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (client->known_buffers.erase(buffer_id_to_drop)) {
6741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      client->event_handler->OnBufferDestroyed(client->controller_id,
6751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                               buffer_id_to_drop);
6761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VideoCaptureController::ControllerClient*
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VideoCaptureController::FindClient(
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VideoCaptureControllerID& id,
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VideoCaptureControllerEventHandler* handler,
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ControllerClients& clients) {
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ControllerClients::const_iterator client_it = clients.begin();
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       client_it != clients.end(); ++client_it) {
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*client_it)->controller_id == id &&
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (*client_it)->event_handler == handler) {
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return *client_it;
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VideoCaptureController::ControllerClient*
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VideoCaptureController::FindClient(
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int session_id,
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ControllerClients& clients) {
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ControllerClients::const_iterator client_it = clients.begin();
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       client_it != clients.end(); ++client_it) {
701f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if ((*client_it)->session_id == session_id) {
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return *client_it;
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
70834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)int VideoCaptureController::GetClientCount() const {
709effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
710d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return controller_clients_.size();
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)int VideoCaptureController::GetActiveClientCount() const {
71434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
71534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  int active_client_count = 0;
71634680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  for (ControllerClient* client : controller_clients_) {
71734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    if (!client->paused)
71834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)      ++active_client_count;
71934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  }
72034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  return active_client_count;
72134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)}
72234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
724