1// Copyright (c) 2011 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#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_CAMERA_H_
6#define CHROME_BROWSER_CHROMEOS_LOGIN_CAMERA_H_
7#pragma once
8
9#include <string>
10#include <vector>
11
12#include "base/memory/ref_counted.h"
13#include "base/synchronization/lock.h"
14#include "base/threading/thread.h"
15#include "third_party/skia/include/core/SkBitmap.h"
16
17class Task;
18namespace base {
19class Thread;
20}  // namespace base
21
22namespace chromeos {
23
24// Class that wraps interaction with video capturing device. Returns
25// frames captured with specified intervals of time via delegate interface.
26// All communication with camera driver is performed on a separate camera
27// thread. Delegate's callback are called on UI thread.
28class Camera : public base::RefCountedThreadSafe<Camera> {
29 public:
30  class Delegate {
31   public:
32    virtual ~Delegate() {}
33
34    // Callbacks that notify of the initialization status.
35    virtual void OnInitializeSuccess() = 0;
36    virtual void OnInitializeFailure() = 0;
37
38    // Callbacks that notify if video capturing was started successfully or
39    // not.
40    virtual void OnStartCapturingSuccess() = 0;
41    virtual void OnStartCapturingFailure() = 0;
42
43    // Notifies the delegate that new frame was captured.
44    // The frame can be obtained via GetFrame() method.
45    virtual void OnCaptureSuccess() = 0;
46
47    // Notifies the delegate that we failed to capture the next frame.
48    virtual void OnCaptureFailure() = 0;
49  };
50
51  // Initializes object members. |delegate| is object that will receive
52  // notifications about success of async method calls. |thread| is a thread
53  // to post blocking tasks to. |mirrored| determines if the returned video
54  // image is mirrored horizontally.
55  Camera(Delegate* delegate, base::Thread* thread, bool mirrored);
56
57  // Initializes camera device on camera thread. Corresponding delegate's
58  // callback is called on UI thread to notify about success or failure. Does
59  // nothing if camera is successfully initialized already. Sets the desired
60  // width and height of the frame to receive from camera.
61  void Initialize(int desired_width, int desired_height);
62
63  // Uninitializes the camera on camera thread. Can be called anytime, any
64  // number of times.
65  void Uninitialize();
66
67  // Starts capturing video frames on camera thread. Frames can be retrieved
68  // by calling GetFrame method.
69  void StartCapturing();
70
71  // Stops capturing video frames. Can be called anytime, any number of
72  // times.
73  void StopCapturing();
74
75  // Setter for delegate: allows to set it to NULL when delegate is about to
76  // be destroyed.
77  void set_delegate(Delegate* delegate) { delegate_ = delegate; }
78
79  // Returns the last successful frame in the member passed.
80  void GetFrame(SkBitmap* frame);
81
82 private:
83  // Destructor is private so only its base class can delete Camera objects.
84  ~Camera();
85  friend class base::RefCountedThreadSafe<Camera>;
86
87  // Tries to open the device with specified name. Returns opened device
88  // descriptor if succeeds, -1 otherwise.
89  int OpenDevice(const char* device_name) const;
90
91  // Initializes reading mode for the device. Returns true on success, false
92  // otherwise.
93  bool InitializeReadingMode(int fd);
94
95  // Unmaps video buffers stored in |buffers_|.
96  void UnmapVideoBuffers();
97
98  // Task for camera thread that queries camera about the next frame and
99  // saves it to |frame_image| buffer for UI thread to pick up. Schedules the
100  // next task for itself if capturing still takes place.
101  void OnCapture();
102
103  // Reads a frame from the video device. If retry is needed, returns false.
104  // Otherwise, returns true despite of success status.
105  bool ReadFrame();
106
107  // Transforms raw data received from camera into SkBitmap with desired
108  // size and notifies the delegate that the image is ready.
109  void ProcessImage(void* data);
110
111  // Actual routines that run on camera thread and call delegate's callbacks.
112  // See the corresponding methods without Do prefix for details.
113  void DoInitialize(int desired_width, int desired_height);
114  void DoStartCapturing();
115  void DoUninitialize();
116  void DoStopCapturing();
117
118  // Helper method that reports failure to the delegate via method
119  // corresponding to the current state of the object.
120  void ReportFailure();
121
122  // Methods called on UI thread to call delegate.
123  void OnInitializeSuccess();
124  void OnInitializeFailure();
125  void OnStartCapturingSuccess();
126  void OnStartCapturingFailure();
127  void OnCaptureSuccess();
128  void OnCaptureFailure();
129
130  // Returns true if the code is executed on camera thread right now, false
131  // otherwise.
132  bool IsOnCameraThread() const;
133
134  // Posts task to camera thread.
135  void PostCameraTask(const tracked_objects::Location& from_here,
136                      Task* task);
137
138  // Defines a buffer in memory where one frame from the camera is stored.
139  struct VideoBuffer {
140    void* start;
141    size_t length;
142  };
143
144  // Delegate that receives the frames from the camera.
145  // Delegate is accessed only on UI thread.
146  Delegate* delegate_;
147
148  // Thread where all work with the device is going on.
149  base::Thread* thread_;
150
151  // All the members below are accessed only on camera thread.
152  // Name of the device file, i.e. "/dev/video0".
153  std::string device_name_;
154
155  // File descriptor of the opened device.
156  int device_descriptor_;
157
158  // Vector of buffers where to store video frames from camera.
159  std::vector<VideoBuffer> buffers_;
160
161  // Indicates if capturing has been started.
162  bool is_capturing_;
163
164  // Desired size of the frame to get from camera. If it doesn't match
165  // camera's supported resolution, higher resolution is selected (if
166  // available) and frame is cropped. If higher resolution is not available,
167  // the highest is selected and resized.
168  int desired_width_;
169  int desired_height_;
170
171  // Size of the frame that camera will give to us. It may not match the
172  // desired size.
173  int frame_width_;
174  int frame_height_;
175
176  // If set to true, the returned image will be reflected from the Y axis to
177  // mimic mirror behavior.
178  bool mirrored_;
179
180  // Image where camera frames are stored for UI thread to pick up.
181  SkBitmap frame_image_;
182
183  // Lock that guards references to |frame_image_|.
184  mutable base::Lock image_lock_;
185
186  // Lock that guards references to |camera_thread_|.
187  mutable base::Lock thread_lock_;
188
189  DISALLOW_COPY_AND_ASSIGN(Camera);
190};
191
192}  // namespace chromeos
193
194#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_CAMERA_H_
195