// 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.

#include "media/video/video_decode_accelerator.h"

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include "base/logging.h"
#include "media/base/video_util.h"

namespace media {

VideoDecodeAccelerator::Config::Config() = default;
VideoDecodeAccelerator::Config::Config(const Config& config) = default;

VideoDecodeAccelerator::Config::Config(VideoCodecProfile video_codec_profile)
    : profile(video_codec_profile) {}

VideoDecodeAccelerator::Config::~Config() = default;

std::string VideoDecodeAccelerator::Config::AsHumanReadableString() const {
  std::ostringstream s;
  s << "profile: " << GetProfileName(profile) << " encrypted? "
    << (is_encrypted() ? "true" : "false");
  return s.str();
}

void VideoDecodeAccelerator::Client::NotifyInitializationComplete(
    Status status) {
  NOTREACHED() << "By default deferred initialization is not supported.";
}

void VideoDecodeAccelerator::Client::ProvidePictureBuffersWithVisibleRect(
    uint32_t requested_num_of_buffers,
    VideoPixelFormat format,
    uint32_t textures_per_buffer,
    const gfx::Size& dimensions,
    const gfx::Rect& visible_rect,
    uint32_t texture_target) {
  if (texture_target == GL_TEXTURE_EXTERNAL_OES) {
    // In ALLOCATE mode and when the texture target is GL_TEXTURE_EXTERNAL_OES,
    // |video_decode_accelerator_| is responsible for allocating storage for the
    // result of the decode. However, we are responsible for creating the GL
    // texture to which we'll attach the decoded image. The decoder needs the
    // buffer to be of size = coded size, but for the purposes of working with a
    // graphics API (e.g., GL), the client does not need to know about the
    // non-visible area. For example, for a 360p H.264 video with a visible
    // rectangle of 0,0,640x360, the coded size is 640x368, but the GL texture
    // that the client uses should be only 640x360. Therefore, we pass
    // |visible_rect|.size() here as the requested size of the picture buffers.
    //
    // Note that we use GetRectSizeFromOrigin() to handle the unusual case in
    // which the visible rectangle does not start at (0, 0). For example, for an
    // H.264 video with a visible rectangle of 2,2,635x360, the coded size is
    // 640x360, but the GL texture that the client uses should be 637x362. This
    // is because we want the texture to include the non-visible area to the
    // left and on the top of the visible rectangle so that the compositor can
    // calculate the UV coordinates to omit the non-visible area.
    ProvidePictureBuffers(requested_num_of_buffers, format, textures_per_buffer,
                          GetRectSizeFromOrigin(visible_rect), texture_target);
  } else {
    ProvidePictureBuffers(requested_num_of_buffers, format, textures_per_buffer,
                          dimensions, texture_target);
  }
}

gpu::SharedImageStub* VideoDecodeAccelerator::Client::GetSharedImageStub()
    const {
  return nullptr;
}

VideoDecodeAccelerator::~VideoDecodeAccelerator() = default;

void VideoDecodeAccelerator::Decode(scoped_refptr<DecoderBuffer> buffer,
                                    int32_t bitstream_id) {
  NOTREACHED() << "By default DecoderBuffer is not supported.";
}

bool VideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread(
    const base::WeakPtr<Client>& decode_client,
    const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) {
  // Implementations in the process that VDA runs in must override this.
  LOG(FATAL) << "This may only be called in the same process as VDA impl.";
  return false;
}

void VideoDecodeAccelerator::ImportBufferForPicture(
    int32_t picture_buffer_id,
    VideoPixelFormat pixel_format,
    gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle) {
  NOTREACHED() << "Buffer import not supported.";
}

void VideoDecodeAccelerator::SetOverlayInfo(const OverlayInfo& overlay_info) {
  NOTREACHED() << "Overlays are not supported.";
}

GLenum VideoDecodeAccelerator::GetSurfaceInternalFormat() const {
  return GL_RGBA;
}

bool VideoDecodeAccelerator::SupportsSharedImagePictureBuffers() const {
  return false;
}

VideoDecodeAccelerator::SupportedProfile::SupportedProfile()
    : profile(media::VIDEO_CODEC_PROFILE_UNKNOWN), encrypted_only(false) {}

VideoDecodeAccelerator::SupportedProfile::~SupportedProfile() = default;

VideoDecodeAccelerator::Capabilities::Capabilities() : flags(NO_FLAGS) {}

VideoDecodeAccelerator::Capabilities::Capabilities(const Capabilities& other) =
    default;

VideoDecodeAccelerator::Capabilities::~Capabilities() = default;

std::string VideoDecodeAccelerator::Capabilities::AsHumanReadableString()
    const {
  std::ostringstream s;
  s << "[";
  for (const SupportedProfile& sp : supported_profiles) {
    s << " " << GetProfileName(sp.profile) << ": " << sp.min_resolution.width()
      << "x" << sp.min_resolution.height() << "->" << sp.max_resolution.width()
      << "x" << sp.max_resolution.height();
  }
  s << "]";
  return s.str();
}

} // namespace media

namespace std {

void default_delete<media::VideoDecodeAccelerator>::operator()(
    media::VideoDecodeAccelerator* vda) const {
  vda->Destroy();
}

}  // namespace std
