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. 4 5 #include "media/cdm/ppapi/libvpx_cdm_video_decoder.h" 6 7 #include "base/logging.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "media/base/buffers.h" 10 #include "media/base/limits.h" 11 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/vpx_decoder.h" // NOLINT 19 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" 20 } 21 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 25 26 namespace media { 27 28 static const int kDecodeThreads = 2; 29 30 LibvpxCdmVideoDecoder::LibvpxCdmVideoDecoder(CdmHost* host) 31 : is_initialized_(false), 32 host_(host), 33 vpx_codec_(NULL), 34 vpx_image_(NULL) { 35 } 36 37 LibvpxCdmVideoDecoder::~LibvpxCdmVideoDecoder() { 38 Deinitialize(); 39 } 40 41 bool LibvpxCdmVideoDecoder::Initialize(const cdm::VideoDecoderConfig& config) { 42 DVLOG(1) << "Initialize()"; 43 44 if (!IsValidOutputConfig(config.format, config.coded_size)) { 45 LOG(ERROR) << "Initialize(): invalid video decoder configuration."; 46 return false; 47 } 48 49 if (is_initialized_) { 50 LOG(ERROR) << "Initialize(): Already initialized."; 51 return false; 52 } 53 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; 59 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; 69 } 70 71 is_initialized_ = true; 72 return true; 73 } 74 75 void LibvpxCdmVideoDecoder::Deinitialize() { 76 DVLOG(1) << "Deinitialize()"; 77 78 if (vpx_codec_) { 79 vpx_codec_destroy(vpx_codec_); 80 vpx_codec_ = NULL; 81 } 82 83 is_initialized_ = false; 84 } 85 86 void LibvpxCdmVideoDecoder::Reset() { 87 DVLOG(1) << "Reset()"; 88 } 89 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); 99 } 100 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); 108 109 // Pass |compressed_frame| to libvpx. 110 void* user_priv = reinterpret_cast<void*>(×tamp); 111 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_, 112 compressed_frame, 113 compressed_frame_size, 114 user_priv, 115 0); 116 if (status != VPX_CODEC_OK) { 117 LOG(ERROR) << "DecodeFrameLibvpx(): vpx_codec_decode failed, status=" 118 << status; 119 return cdm::kDecodeError; 120 } 121 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; 127 128 if (vpx_image_->user_priv != reinterpret_cast<void*>(×tamp)) { 129 LOG(ERROR) << "DecodeFrameLibvpx() invalid output timestamp."; 130 return cdm::kDecodeError; 131 } 132 decoded_frame->SetTimestamp(timestamp); 133 134 if (!CopyVpxImageTo(decoded_frame)) { 135 LOG(ERROR) << "DecodeFrameLibvpx() could not copy vpx image to output " 136 << "buffer."; 137 return cdm::kDecodeError; 138 } 139 140 return cdm::kSuccess; 141 } 142 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); 148 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; 154 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; 160 } 161 cdm_video_frame->FrameBuffer()->SetSize(space_required); 162 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); 172 173 cdm_video_frame->SetFormat(cdm::kYv12); 174 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); 179 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); 184 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]); 191 192 return true; 193 } 194 195 } // namespace media 196