text: // Copyright (c) 2010 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/lock.h"
  #include "base/ref_counted.h"
  #include "base/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 Lock image_lock_;
  
    // Lock that guards references to |camera_thread_|.
    mutable Lock thread_lock_;
  
    DISALLOW_COPY_AND_ASSIGN(Camera);
  };
  
  }  // namespace chromeos
  
  #endif  // CHROME_BROWSER_CHROMEOS_LOGIN_CAMERA_H_
  