// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_CAMERA_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_CAMERA_H_
#pragma once
#include <string>
#include <vector>
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "third_party/skia/include/core/SkBitmap.h"
class Task;
namespace base {
class Thread;
} // namespace base
namespace chromeos {
// Class that wraps interaction with video capturing device. Returns
// frames captured with specified intervals of time via delegate interface.
// All communication with camera driver is performed on a separate camera
// thread. Delegate's callback are called on UI thread.
class Camera : public base::RefCountedThreadSafe<Camera> {
public:
class Delegate {
public:
virtual ~Delegate() {}
// Callbacks that notify of the initialization status.
virtual void OnInitializeSuccess() = 0;
virtual void OnInitializeFailure() = 0;
// Callbacks that notify if video capturing was started successfully or
// not.
virtual void OnStartCapturingSuccess() = 0;
virtual void OnStartCapturingFailure() = 0;
// Notifies the delegate that new frame was captured.
// The frame can be obtained via GetFrame() method.
virtual void OnCaptureSuccess() = 0;
// Notifies the delegate that we failed to capture the next frame.
virtual void OnCaptureFailure() = 0;
};
// Initializes object members. |delegate| is object that will receive
// notifications about success of async method calls. |thread| is a thread
// to post blocking tasks to. |mirrored| determines if the returned video
// image is mirrored horizontally.
Camera(Delegate* delegate, base::Thread* thread, bool mirrored);
// Initializes camera device on camera thread. Corresponding delegate's
// callback is called on UI thread to notify about success or failure. Does
// nothing if camera is successfully initialized already. Sets the desired
// width and height of the frame to receive from camera.
void Initialize(int desired_width, int desired_height);
// Uninitializes the camera on camera thread. Can be called anytime, any
// number of times.
void Uninitialize();
// Starts capturing video frames on camera thread. Frames can be retrieved
// by calling GetFrame method.
void StartCapturing();
// Stops capturing video frames. Can be called anytime, any number of
// times.
void StopCapturing();
// Setter for delegate: allows to set it to NULL when delegate is about to
// be destroyed.
void set_delegate(Delegate* delegate) { delegate_ = delegate; }
// Returns the last successful frame in the member passed.
void GetFrame(SkBitmap* frame);
private:
// Destructor is private so only its base class can delete Camera objects.
~Camera();
friend class base::RefCountedThreadSafe<Camera>;
// Tries to open the device with specified name. Returns opened device
// descriptor if succeeds, -1 otherwise.
int OpenDevice(const char* device_name) const;
// Initializes reading mode for the device. Returns true on success, false
// otherwise.
bool InitializeReadingMode(int fd);
// Unmaps video buffers stored in |buffers_|.
void UnmapVideoBuffers();
// Task for camera thread that queries camera about the next frame and
// saves it to |frame_image| buffer for UI thread to pick up. Schedules the
// next task for itself if capturing still takes place.
void OnCapture();
// Reads a frame from the video device. If retry is needed, returns false.
// Otherwise, returns true despite of success status.
bool ReadFrame();
// Transforms raw data received from camera into SkBitmap with desired
// size and notifies the delegate that the image is ready.
void ProcessImage(void* data);
// Actual routines that run on camera thread and call delegate's callbacks.
// See the corresponding methods without Do prefix for details.
void DoInitialize(int desired_width, int desired_height);
void DoStartCapturing();
void DoUninitialize();
void DoStopCapturing();
// Helper method that reports failure to the delegate via method
// corresponding to the current state of the object.
void ReportFailure();
// Methods called on UI thread to call delegate.
void OnInitializeSuccess();
void OnInitializeFailure();
void OnStartCapturingSuccess();
void OnStartCapturingFailure();
void OnCaptureSuccess();
void OnCaptureFailure();
// Returns true if the code is executed on camera thread right now, false
// otherwise.
bool IsOnCameraThread() const;
// Posts task to camera thread.
void PostCameraTask(const tracked_objects::Location& from_here,
Task* task);
// Defines a buffer in memory where one frame from the camera is stored.
struct VideoBuffer {
void* start;
size_t length;
};
// Delegate that receives the frames from the camera.
// Delegate is accessed only on UI thread.
Delegate* delegate_;
// Thread where all work with the device is going on.
base::Thread* thread_;
// All the members below are accessed only on camera thread.
// Name of the device file, i.e. "/dev/video0".
std::string device_name_;
// File descriptor of the opened device.
int device_descriptor_;
// Vector of buffers where to store video frames from camera.
std::vector<VideoBuffer> buffers_;
// Indicates if capturing has been started.
bool is_capturing_;
// Desired size of the frame to get from camera. If it doesn't match
// camera's supported resolution, higher resolution is selected (if
// available) and frame is cropped. If higher resolution is not available,
// the highest is selected and resized.
int desired_width_;
int desired_height_;
// Size of the frame that camera will give to us. It may not match the
// desired size.
int frame_width_;
int frame_height_;
// If set to true, the returned image will be reflected from the Y axis to
// mimic mirror behavior.
bool mirrored_;
// Image where camera frames are stored for UI thread to pick up.
SkBitmap frame_image_;
// Lock that guards references to |frame_image_|.
mutable base::Lock image_lock_;
// Lock that guards references to |camera_thread_|.
mutable base::Lock thread_lock_;
DISALLOW_COPY_AND_ASSIGN(Camera);
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_CAMERA_H_