Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / media / cdm / ppapi / external_clear_key / libvpx_cdm_video_decoder.cc
blobb5a804389fdcf28f0350d7d295c55ffcbdc7cdc2
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/cdm/ppapi/external_clear_key/libvpx_cdm_video_decoder.h"
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "media/base/buffers.h"
10 #include "media/base/limits.h"
12 // Include libvpx header files.
13 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide
14 // backwards compatibility for legacy applications using the library.
15 #define VPX_CODEC_DISABLE_COMPAT 1
16 extern "C" {
17 // Note: vpx_decoder.h must be first or compile will fail.
18 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h"
19 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" // NOLINT
22 // Enable USE_COPYPLANE_WITH_LIBVPX to use |CopyPlane()| instead of memcpy to
23 // copy video frame data.
24 // #define USE_COPYPLANE_WITH_LIBVPX 1
26 namespace media {
28 static const int kDecodeThreads = 2;
30 LibvpxCdmVideoDecoder::LibvpxCdmVideoDecoder(CdmHost* host)
31 : is_initialized_(false),
32 host_(host),
33 vpx_codec_(NULL),
34 vpx_image_(NULL) {
37 LibvpxCdmVideoDecoder::~LibvpxCdmVideoDecoder() {
38 Deinitialize();
41 bool LibvpxCdmVideoDecoder::Initialize(const cdm::VideoDecoderConfig& config) {
42 DVLOG(1) << "Initialize()";
44 if (!IsValidOutputConfig(config.format, config.coded_size)) {
45 LOG(ERROR) << "Initialize(): invalid video decoder configuration.";
46 return false;
49 if (is_initialized_) {
50 LOG(ERROR) << "Initialize(): Already initialized.";
51 return false;
54 vpx_codec_ = new vpx_codec_ctx();
55 vpx_codec_dec_cfg_t vpx_config = {0};
56 vpx_config.w = config.coded_size.width;
57 vpx_config.h = config.coded_size.height;
58 vpx_config.threads = kDecodeThreads;
60 vpx_codec_err_t status = vpx_codec_dec_init(vpx_codec_,
61 vpx_codec_vp8_dx(),
62 &vpx_config,
63 0);
64 if (status != VPX_CODEC_OK) {
65 LOG(ERROR) << "InitializeLibvpx(): vpx_codec_dec_init failed, ret="
66 << status;
67 delete vpx_codec_;
68 vpx_codec_ = NULL;
71 is_initialized_ = true;
72 return true;
75 void LibvpxCdmVideoDecoder::Deinitialize() {
76 DVLOG(1) << "Deinitialize()";
78 if (vpx_codec_) {
79 vpx_codec_destroy(vpx_codec_);
80 vpx_codec_ = NULL;
83 is_initialized_ = false;
86 void LibvpxCdmVideoDecoder::Reset() {
87 DVLOG(1) << "Reset()";
90 // static
91 bool LibvpxCdmVideoDecoder::IsValidOutputConfig(cdm::VideoFormat format,
92 const cdm::Size& data_size) {
93 return ((format == cdm::kYv12 || format == cdm::kI420) &&
94 (data_size.width % 2) == 0 && (data_size.height % 2) == 0 &&
95 data_size.width > 0 && data_size.height > 0 &&
96 data_size.width <= limits::kMaxDimension &&
97 data_size.height <= limits::kMaxDimension &&
98 data_size.width * data_size.height <= limits::kMaxCanvas);
101 cdm::Status LibvpxCdmVideoDecoder::DecodeFrame(
102 const uint8_t* compressed_frame,
103 int32_t compressed_frame_size,
104 int64_t timestamp,
105 cdm::VideoFrame* decoded_frame) {
106 DVLOG(1) << "DecodeFrame()";
107 DCHECK(decoded_frame);
109 // Pass |compressed_frame| to libvpx.
110 void* user_priv = reinterpret_cast<void*>(&timestamp);
111 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_,
112 compressed_frame,
113 compressed_frame_size,
114 user_priv,
116 if (status != VPX_CODEC_OK) {
117 LOG(ERROR) << "DecodeFrameLibvpx(): vpx_codec_decode failed, status="
118 << status;
119 return cdm::kDecodeError;
122 // Gets pointer to decoded data.
123 vpx_codec_iter_t iter = NULL;
124 vpx_image_ = vpx_codec_get_frame(vpx_codec_, &iter);
125 if (!vpx_image_)
126 return cdm::kNeedMoreData;
128 if (vpx_image_->user_priv != reinterpret_cast<void*>(&timestamp)) {
129 LOG(ERROR) << "DecodeFrameLibvpx() invalid output timestamp.";
130 return cdm::kDecodeError;
132 decoded_frame->SetTimestamp(timestamp);
134 if (!CopyVpxImageTo(decoded_frame)) {
135 LOG(ERROR) << "DecodeFrameLibvpx() could not copy vpx image to output "
136 << "buffer.";
137 return cdm::kDecodeError;
140 return cdm::kSuccess;
143 bool LibvpxCdmVideoDecoder::CopyVpxImageTo(cdm::VideoFrame* cdm_video_frame) {
144 DCHECK(cdm_video_frame);
145 DCHECK_EQ(vpx_image_->fmt, VPX_IMG_FMT_I420);
146 DCHECK_EQ(vpx_image_->d_w % 2, 0U);
147 DCHECK_EQ(vpx_image_->d_h % 2, 0U);
149 const int y_size = vpx_image_->stride[VPX_PLANE_Y] * vpx_image_->d_h;
150 const int uv_rows = vpx_image_->d_h / 2;
151 const int u_size = vpx_image_->stride[VPX_PLANE_U] * uv_rows;
152 const int v_size = vpx_image_->stride[VPX_PLANE_V] * uv_rows;
153 const int space_required = y_size + u_size + v_size;
155 DCHECK(!cdm_video_frame->FrameBuffer());
156 cdm_video_frame->SetFrameBuffer(host_->Allocate(space_required));
157 if (!cdm_video_frame->FrameBuffer()) {
158 LOG(ERROR) << "CopyVpxImageTo() CdmHost::Allocate failed.";
159 return false;
161 cdm_video_frame->FrameBuffer()->SetSize(space_required);
163 memcpy(cdm_video_frame->FrameBuffer()->Data(),
164 vpx_image_->planes[VPX_PLANE_Y],
165 y_size);
166 memcpy(cdm_video_frame->FrameBuffer()->Data() + y_size,
167 vpx_image_->planes[VPX_PLANE_U],
168 u_size);
169 memcpy(cdm_video_frame->FrameBuffer()->Data() + y_size + u_size,
170 vpx_image_->planes[VPX_PLANE_V],
171 v_size);
173 cdm_video_frame->SetFormat(cdm::kYv12);
175 cdm::Size video_frame_size;
176 video_frame_size.width = vpx_image_->d_w;
177 video_frame_size.height = vpx_image_->d_h;
178 cdm_video_frame->SetSize(video_frame_size);
180 cdm_video_frame->SetPlaneOffset(cdm::VideoFrame::kYPlane, 0);
181 cdm_video_frame->SetPlaneOffset(cdm::VideoFrame::kUPlane, y_size);
182 cdm_video_frame->SetPlaneOffset(cdm::VideoFrame::kVPlane,
183 y_size + u_size);
185 cdm_video_frame->SetStride(cdm::VideoFrame::kYPlane,
186 vpx_image_->stride[VPX_PLANE_Y]);
187 cdm_video_frame->SetStride(cdm::VideoFrame::kUPlane,
188 vpx_image_->stride[VPX_PLANE_U]);
189 cdm_video_frame->SetStride(cdm::VideoFrame::kVPlane,
190 vpx_image_->stride[VPX_PLANE_V]);
192 return true;
195 } // namespace media