// 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 COBALT_MEDIA_BASE_DECODER_BUFFER_H_
#define COBALT_MEDIA_BASE_DECODER_BUFFER_H_

#include <string>
#include <utility>

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/aligned_memory.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/time.h"
#include "build/build_config.h"
#include "cobalt/media/base/decrypt_config.h"
#include "cobalt/media/base/demuxer_stream.h"
#include "cobalt/media/base/media_export.h"
#include "cobalt/media/base/timestamp_constants.h"
#include "nb/multipart_allocator.h"
#include "starboard/memory.h"
#include "starboard/types.h"

namespace cobalt {
namespace media {

// A specialized buffer for interfacing with audio / video decoders.
//
// Specifically ensures that data is aligned and padded as necessary by the
// underlying decoding framework.  On desktop platforms this means memory is
// allocated using FFmpeg with particular alignment and padding requirements.
//
// Also includes decoder specific functionality for decryption.
//
// NOTE: It is illegal to call any method when end_of_stream() is true.
class MEDIA_EXPORT DecoderBuffer
    : public base::RefCountedThreadSafe<DecoderBuffer> {
 public:
  typedef DemuxerStream::Type Type;
  typedef nb::MultipartAllocator Allocator;

  // Create a DecoderBuffer whose |data_| points to a memory with at least
  // |size| bytes.  Buffer will be padded and aligned as necessary.
  // The buffer's |is_key_frame_| will default to false.
  static scoped_refptr<DecoderBuffer> Create(Allocator* allocator, Type type,
                                             size_t size);

  // Create a DecoderBuffer whose |data_| is copied from |data|.  Buffer will be
  // padded and aligned as necessary.  |data| must not be NULL and |size| >= 0.
  // The buffer's |is_key_frame_| will default to false.
  static scoped_refptr<DecoderBuffer> CopyFrom(Allocator* allocator, Type type,
                                               const uint8_t* data,
                                               size_t size);

  // Create a DecoderBuffer indicating we've reached end of stream.
  //
  // Calling any method other than end_of_stream() on the resulting buffer
  // is disallowed.
  static scoped_refptr<DecoderBuffer> CreateEOSBuffer();

  // Returns the allocator.  This is usually used when creating a copy of the
  // buffer.
  Allocator* allocator() const { return data_.allocator(); }

  // Gets the parser's media type associated with this buffer. Value is
  // meaningless for EOS buffers.
  Type type() const { return data_.type(); }
  const char* GetTypeName() const;

  base::TimeDelta timestamp() const {
    DCHECK(!end_of_stream());
    return timestamp_;
  }

  // TODO(dalecurtis): This should be renamed at some point, but to avoid a yak
  // shave keep as a virtual with hacker_style() for now.
  virtual void set_timestamp(base::TimeDelta timestamp);

  base::TimeDelta duration() const {
    DCHECK(!end_of_stream());
    return duration_;
  }

  void set_duration(base::TimeDelta duration) {
    DCHECK(!end_of_stream());
    DCHECK(duration == kNoTimestamp ||
           (duration >= base::TimeDelta() && duration != kInfiniteDuration))
        << duration.InSecondsF();
    duration_ = duration;
  }

  bool has_data() const { return allocations().number_of_buffers() > 0; }

  const Allocator::Allocations& allocations() const {
    return data_.allocations();
  }
  Allocator::Allocations& allocations() { return data_.allocations(); }

  size_t data_size() const {
    DCHECK(!end_of_stream());
    return data_.allocations().size();
  }

  void shrink_to(size_t size) {
    DCHECK_GE(static_cast<int>(size), 0);
    allocations().ShrinkTo(static_cast<int>(size));
  }

  // A discard window indicates the amount of data which should be discard from
  // this buffer after decoding.  The first value is the amount of the front and
  // the second the amount off the back.  A value of kInfiniteDuration for the
  // first value indicates the entire buffer should be discarded; the second
  // value must be base::TimeDelta() in this case.
  typedef std::pair<base::TimeDelta, base::TimeDelta> DiscardPadding;
  const DiscardPadding& discard_padding() const {
    DCHECK(!end_of_stream());
    return discard_padding_;
  }

  void set_discard_padding(const DiscardPadding& discard_padding) {
    DCHECK(!end_of_stream());
    discard_padding_ = discard_padding;
  }

  const DecryptConfig* decrypt_config() const {
    DCHECK(!end_of_stream());
    return decrypt_config_.get();
  }

  void set_decrypt_config(scoped_ptr<DecryptConfig> decrypt_config) {
    DCHECK(!end_of_stream());
    decrypt_config_ = decrypt_config.Pass();
  }

  // If there's no data in this buffer, it represents end of stream.
  bool end_of_stream() const { return !has_data(); }

  // Indicates this buffer is part of a splice around |splice_timestamp_|.
  // Returns kNoTimestamp if the buffer is not part of a splice.
  base::TimeDelta splice_timestamp() const {
    DCHECK(!end_of_stream());
    return splice_timestamp_;
  }

  // When set to anything but kNoTimestamp indicates this buffer is part of a
  // splice around |splice_timestamp|.
  void set_splice_timestamp(base::TimeDelta splice_timestamp) {
    DCHECK(!end_of_stream());
    splice_timestamp_ = splice_timestamp;
  }

  bool is_key_frame() const {
    DCHECK(!end_of_stream());
    return is_key_frame_;
  }

  void set_is_key_frame(bool is_key_frame) {
    DCHECK(!end_of_stream());
    is_key_frame_ = is_key_frame;
  }

  // Returns a human-readable string describing |*this|.
  std::string AsHumanReadableString();

 protected:
  friend class base::RefCountedThreadSafe<DecoderBuffer>;

  // The default ctor creates an EOS buffer without specific stream type.
  DecoderBuffer();

  // Allocates buffer with |size| >= 0.  Buffer will be padded and aligned
  // as necessary, and |is_key_frame_| will default to false.
  DecoderBuffer(Allocator* allocator, Type type, size_t size);

  // Allocates a buffer of size |size| >= 0 and copies |data| into it.  Buffer
  // will be padded and aligned as necessary.  If |data| is NULL then |data_| is
  // set to NULL and |buffer_size_| to 0.  |is_key_frame_| will default to
  // false.
  DecoderBuffer(Allocator* allocator, Type type, const uint8_t* data,
                size_t size);

  // Allocates a buffer to copy the data in |allocations|.  Buffer will be
  // padded and aligned as necessary.  |is_key_frame_| will default to false.
  DecoderBuffer(Allocator* allocator, Type type,
                Allocator::Allocations allocations);

  virtual ~DecoderBuffer();

 private:
  class ScopedAllocatorPtr {
   public:
    ScopedAllocatorPtr(Allocator* allocator, Type type, size_t size);
    ~ScopedAllocatorPtr();

    const Allocator::Allocations& allocations() const { return allocations_; }
    Allocator::Allocations& allocations() { return allocations_; }

    Allocator* allocator() const { return allocator_; }
    Type type() const { return type_; }

   private:
    Allocator* allocator_;
    Type type_;
    Allocator::Allocations allocations_;

    DISALLOW_COPY_AND_ASSIGN(ScopedAllocatorPtr);
  };

  base::TimeDelta timestamp_;
  base::TimeDelta duration_;

  ScopedAllocatorPtr data_;
  scoped_ptr<DecryptConfig> decrypt_config_;
  DiscardPadding discard_padding_;
  base::TimeDelta splice_timestamp_;
  bool is_key_frame_;

  DISALLOW_COPY_AND_ASSIGN(DecoderBuffer);
};

}  // namespace media
}  // namespace cobalt

#endif  // COBALT_MEDIA_BASE_DECODER_BUFFER_H_
