// Copyright (c) 2012 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 WEBKIT_MEDIA_WEBMEDIAPLAYER_PROXY_H_
#define WEBKIT_MEDIA_WEBMEDIAPLAYER_PROXY_H_

#include <list>
#include <string>
#include <vector>

#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "media/base/pipeline.h"
#include "media/crypto/decryptor_client.h"
#include "media/filters/chunk_demuxer.h"
#include "media/filters/chunk_demuxer_client.h"
#include "media/filters/ffmpeg_video_decoder.h"
#include "webkit/media/buffered_data_source.h"
#include "webkit/media/skcanvas_video_renderer.h"

class SkCanvas;

namespace base {
class MessageLoopProxy;
}

namespace gfx {
class Rect;
}

namespace media {
class VideoFrame;
class VideoRendererBase;
}

namespace webkit_media {

class WebMediaPlayerImpl;

// Acts as a thread proxy between the various threads used for multimedia and
// the render thread that WebMediaPlayerImpl is running on.
class WebMediaPlayerProxy
    : public base::RefCountedThreadSafe<WebMediaPlayerProxy>,
      public media::ChunkDemuxerClient,
      public media::DecryptorClient {
 public:
  WebMediaPlayerProxy(const scoped_refptr<base::MessageLoopProxy>& render_loop,
                      WebMediaPlayerImpl* webmediaplayer);
  const scoped_refptr<BufferedDataSource>& data_source() {
    return data_source_;
  }
  void set_data_source(const scoped_refptr<BufferedDataSource>& data_source) {
    data_source_ = data_source;
  }

  // TODO(scherkus): remove this once VideoRendererBase::PaintCB passes
  // ownership of the VideoFrame http://crbug.com/108435
  void set_frame_provider(media::VideoRendererBase* frame_provider) {
    frame_provider_ = frame_provider;
  }

  void set_video_decoder(
      const scoped_refptr<media::FFmpegVideoDecoder>& video_decoder) {
    video_decoder_ = video_decoder;
  }
  const scoped_refptr<media::FFmpegVideoDecoder>& video_decoder() {
    return video_decoder_;
  }

  // Methods for Filter -> WebMediaPlayerImpl communication.
  void Repaint();
  void SetOpaque(bool opaque);

  // Methods for WebMediaPlayerImpl -> Filter communication.
  void Paint(SkCanvas* canvas, const gfx::Rect& dest_rect, uint8_t alpha);
  void Detach();
  void GetCurrentFrame(scoped_refptr<media::VideoFrame>* frame_out);
  void PutCurrentFrame(scoped_refptr<media::VideoFrame> frame);
  bool HasSingleOrigin();
  bool DidPassCORSAccessCheck() const;

  void AbortDataSource();

  // Methods for Pipeline -> WebMediaPlayerImpl communication.
  void PipelineInitializationCallback(media::PipelineStatus status);
  void PipelineSeekCallback(media::PipelineStatus status);
  void PipelineEndedCallback(media::PipelineStatus status);
  void PipelineErrorCallback(media::PipelineStatus error);

  // ChunkDemuxerClient implementation.
  virtual void DemuxerOpened(media::ChunkDemuxer* demuxer) OVERRIDE;
  virtual void DemuxerClosed() OVERRIDE;
  virtual void DemuxerNeedKey(scoped_array<uint8> init_data,
                              int init_data_size) OVERRIDE;

  // Methods for Demuxer communication.
  void DemuxerStartWaitingForSeek();
  media::ChunkDemuxer::Status DemuxerAddId(const std::string& id,
                                           const std::string& type,
                                           std::vector<std::string>& codecs);
  void DemuxerRemoveId(const std::string& id);
  bool DemuxerBufferedRange(const std::string& id,
                            media::ChunkDemuxer::Ranges* ranges_out);
  bool DemuxerAppend(const std::string& id, const uint8* data, size_t length);
  void DemuxerAbort(const std::string& id);
  void DemuxerEndOfStream(media::PipelineStatus status);
  void DemuxerShutdown();

  // DecryptorClient implementation.
  virtual void KeyAdded(const std::string& key_system,
                        const std::string& session_id) OVERRIDE;
  virtual void KeyError(const std::string& key_system,
                        const std::string& session_id,
                        media::AesDecryptor::KeyError error_code,
                        int system_code) OVERRIDE;
  virtual void KeyMessage(const std::string& key_system,
                          const std::string& session_id,
                          scoped_array<uint8> message,
                          int message_length,
                          const std::string& default_url) OVERRIDE;
  virtual void NeedKey(const std::string& key_system,
                       const std::string& session_id,
                       scoped_array<uint8> init_data,
                       int init_data_size) OVERRIDE;

 private:
  friend class base::RefCountedThreadSafe<WebMediaPlayerProxy>;
  virtual ~WebMediaPlayerProxy();

  // Invoke |webmediaplayer_| to perform a repaint.
  void RepaintTask();

  // Notify |webmediaplayer_| that initialization has finished.
  void PipelineInitializationTask(media::PipelineStatus status);

  // Notify |webmediaplayer_| that a seek has finished.
  void PipelineSeekTask(media::PipelineStatus status);

  // Notify |webmediaplayer_| that the media has ended.
  void PipelineEndedTask(media::PipelineStatus status);

  // Notify |webmediaplayer_| that a pipeline error has occurred during
  // playback.
  void PipelineErrorTask(media::PipelineStatus error);

  // Inform |webmediaplayer_| whether the video content is opaque.
  void SetOpaqueTask(bool opaque);

  void DemuxerOpenedTask(const scoped_refptr<media::ChunkDemuxer>& demuxer);
  void DemuxerClosedTask();

  // Notify |webmediaplayer_| that a key has been added.
  void KeyAddedTask(const std::string& key_system,
                    const std::string& session_id);

  // Notify |webmediaplayer_| that a key error occurred.
  void KeyErrorTask(const std::string& key_system,
                    const std::string& session_id,
                    media::AesDecryptor::KeyError error_code,
                    int system_code);

  // Notify |webmediaplayer_| that a key message has been generated.
  void KeyMessageTask(const std::string& key_system,
                      const std::string& session_id,
                      scoped_array<uint8> message,
                      int message_length,
                      const std::string& default_url);

  // Notify |webmediaplayer_| that a key is needed for decryption.
  void NeedKeyTask(const std::string& key_system,
                   const std::string& session_id,
                   scoped_array<uint8> init_data,
                   int init_data_size);

  // The render message loop where WebKit lives.
  scoped_refptr<base::MessageLoopProxy> render_loop_;
  WebMediaPlayerImpl* webmediaplayer_;

  scoped_refptr<BufferedDataSource> data_source_;
  scoped_refptr<media::VideoRendererBase> frame_provider_;
  SkCanvasVideoRenderer video_renderer_;
  scoped_refptr<media::FFmpegVideoDecoder> video_decoder_;

  base::Lock lock_;
  int outstanding_repaints_;

  scoped_refptr<media::ChunkDemuxer> chunk_demuxer_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(WebMediaPlayerProxy);
};

}  // namespace webkit_media

#endif  // WEBKIT_MEDIA_WEBMEDIAPLAYER_PROXY_H_