OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 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 "webkit/media/crypto/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 #include "third_party/libvpx/libvpx.h" |
| 18 } |
| 19 |
| 20 #include "webkit/media/crypto/ppapi/content_decryption_module.h" |
| 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 webkit_media { |
| 27 |
| 28 static const int kDecodeThreads = 1; |
| 29 |
| 30 static void CopyPlane(const uint8_t* source, |
| 31 int32_t source_stride, |
| 32 int32_t target_stride, |
| 33 int32_t rows, |
| 34 int32_t copy_bytes_per_row, |
| 35 uint8_t* target) { |
| 36 DCHECK(source); |
| 37 DCHECK(target); |
| 38 DCHECK_LE(copy_bytes_per_row, source_stride); |
| 39 DCHECK_LE(copy_bytes_per_row, target_stride); |
| 40 |
| 41 for (int i = 0; i < rows; ++i) { |
| 42 const int source_offset = i * source_stride; |
| 43 const int target_offset = i * target_stride; |
| 44 memcpy(target + target_offset, |
| 45 source + source_offset, |
| 46 copy_bytes_per_row); |
| 47 } |
| 48 } |
| 49 |
| 50 LibvpxCdmVideoDecoder::LibvpxCdmVideoDecoder(cdm::Allocator* allocator) |
| 51 : is_initialized_(false), |
| 52 allocator_(allocator), |
| 53 vpx_codec_(NULL), |
| 54 vpx_image_(NULL) { |
| 55 } |
| 56 |
| 57 LibvpxCdmVideoDecoder::~LibvpxCdmVideoDecoder() { |
| 58 Deinitialize(); |
| 59 } |
| 60 |
| 61 bool LibvpxCdmVideoDecoder::Initialize(const cdm::VideoDecoderConfig& config) { |
| 62 DVLOG(1) << "Initialize()"; |
| 63 |
| 64 if (!IsValidOutputConfig(config.format, config.coded_size)) { |
| 65 LOG(ERROR) << "Initialize(): invalid video decoder configuration."; |
| 66 return false; |
| 67 } |
| 68 |
| 69 if (is_initialized_) { |
| 70 LOG(ERROR) << "Initialize(): Already initialized."; |
| 71 return false; |
| 72 } |
| 73 |
| 74 vpx_codec_ = new vpx_codec_ctx(); |
| 75 vpx_codec_dec_cfg_t vpx_config = {0}; |
| 76 vpx_config.w = config.coded_size.width; |
| 77 vpx_config.h = config.coded_size.height; |
| 78 vpx_config.threads = kDecodeThreads; |
| 79 |
| 80 vpx_codec_err_t status = vpx_codec_dec_init(vpx_codec_, |
| 81 vpx_codec_vp8_dx(), |
| 82 &vpx_config, |
| 83 0); |
| 84 if (status != VPX_CODEC_OK) { |
| 85 LOG(ERROR) << "InitializeLibvpx(): vpx_codec_dec_init failed, ret=" |
| 86 << status; |
| 87 delete vpx_codec_; |
| 88 vpx_codec_ = NULL; |
| 89 } |
| 90 |
| 91 is_initialized_ = true; |
| 92 return true; |
| 93 } |
| 94 |
| 95 void LibvpxCdmVideoDecoder::Deinitialize() { |
| 96 DVLOG(1) << "Deinitialize()"; |
| 97 |
| 98 if (vpx_codec_) { |
| 99 vpx_codec_destroy(vpx_codec_); |
| 100 vpx_codec_ = NULL; |
| 101 } |
| 102 |
| 103 is_initialized_ = false; |
| 104 } |
| 105 |
| 106 void LibvpxCdmVideoDecoder::Reset() { |
| 107 DVLOG(1) << "Reset()"; |
| 108 } |
| 109 |
| 110 // static |
| 111 bool LibvpxCdmVideoDecoder::IsValidOutputConfig(cdm::VideoFormat format, |
| 112 const cdm::Size& data_size) { |
| 113 return ((format == cdm::kYv12 || format == cdm::kI420) && |
| 114 (data_size.width % 2) == 0 && (data_size.height % 2) == 0 && |
| 115 data_size.width > 0 && data_size.height > 0 && |
| 116 data_size.width <= media::limits::kMaxDimension && |
| 117 data_size.height <= media::limits::kMaxDimension && |
| 118 data_size.width * data_size.height <= media::limits::kMaxCanvas); |
| 119 } |
| 120 |
| 121 cdm::Status LibvpxCdmVideoDecoder::DecodeFrame( |
| 122 const uint8_t* compressed_frame, |
| 123 int32_t compressed_frame_size, |
| 124 int64_t timestamp, |
| 125 cdm::VideoFrame* decoded_frame) { |
| 126 DVLOG(1) << "DecodeFrame()"; |
| 127 DCHECK(decoded_frame); |
| 128 |
| 129 // Pass |compressed_frame| to libvpx. |
| 130 void* user_priv = reinterpret_cast<void*>(×tamp); |
| 131 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_, |
| 132 compressed_frame, |
| 133 compressed_frame_size, |
| 134 user_priv, |
| 135 0); |
| 136 if (status != VPX_CODEC_OK) { |
| 137 LOG(ERROR) << "DecodeFrameLibvpx(): vpx_codec_decode failed, status=" |
| 138 << status; |
| 139 return cdm::kDecodeError; |
| 140 } |
| 141 |
| 142 // Gets pointer to decoded data. |
| 143 vpx_codec_iter_t iter = NULL; |
| 144 vpx_image_ = vpx_codec_get_frame(vpx_codec_, &iter); |
| 145 if (!vpx_image_) |
| 146 return cdm::kNeedMoreData; |
| 147 |
| 148 if (vpx_image_->user_priv != reinterpret_cast<void*>(×tamp)) { |
| 149 LOG(ERROR) << "DecodeFrameLibvpx() invalid output timestamp."; |
| 150 return cdm::kDecodeError; |
| 151 } |
| 152 decoded_frame->set_timestamp(timestamp); |
| 153 |
| 154 if (!CopyVpxImageTo(decoded_frame)) { |
| 155 LOG(ERROR) << "DecodeFrameLibvpx() could not copy vpx image to output " |
| 156 << "buffer."; |
| 157 return cdm::kDecodeError; |
| 158 } |
| 159 |
| 160 return cdm::kSuccess; |
| 161 |
| 162 } |
| 163 |
| 164 bool LibvpxCdmVideoDecoder::CopyVpxImageTo(cdm::VideoFrame* cdm_video_frame) { |
| 165 DCHECK(cdm_video_frame); |
| 166 DCHECK_EQ(vpx_image_->fmt, VPX_IMG_FMT_I420); |
| 167 DCHECK_EQ(vpx_image_->d_w % 2, 0U); |
| 168 DCHECK_EQ(vpx_image_->d_h % 2, 0U); |
| 169 |
| 170 #if defined(USE_COPYPLANE_WITH_LIBVPX) |
| 171 const int y_size = vpx_image_->d_w * vpx_image_->d_h; |
| 172 const int uv_size = y_size / 2; |
| 173 const int space_required = y_size + (uv_size * 2); |
| 174 |
| 175 DCHECK(!cdm_video_frame->frame_buffer()); |
| 176 cdm_video_frame->set_frame_buffer(allocator_->Allocate(space_required)); |
| 177 if (!cdm_video_frame->frame_buffer()) { |
| 178 LOG(ERROR) << "CopyVpxImageTo() cdm::Allocator::Allocate failed."; |
| 179 return false; |
| 180 } |
| 181 |
| 182 CopyPlane(vpx_image_->planes[VPX_PLANE_Y], |
| 183 vpx_image_->stride[VPX_PLANE_Y], |
| 184 vpx_image_->d_w, |
| 185 vpx_image_->d_h, |
| 186 vpx_image_->d_w, |
| 187 cdm_video_frame->frame_buffer()->data()); |
| 188 |
| 189 const int uv_stride = vpx_image_->d_w / 2; |
| 190 const int uv_rows = vpx_image_->d_h / 2; |
| 191 CopyPlane(vpx_image_->planes[VPX_PLANE_U], |
| 192 vpx_image_->stride[VPX_PLANE_U], |
| 193 uv_stride, |
| 194 uv_rows, |
| 195 uv_stride, |
| 196 cdm_video_frame->frame_buffer()->data() + y_size); |
| 197 |
| 198 CopyPlane(vpx_image_->planes[VPX_PLANE_V], |
| 199 vpx_image_->stride[VPX_PLANE_V], |
| 200 uv_stride, |
| 201 uv_rows, |
| 202 uv_stride, |
| 203 cdm_video_frame->frame_buffer()->data() + y_size + uv_size); |
| 204 |
| 205 cdm_video_frame->set_format(cdm::kYv12); |
| 206 |
| 207 cdm::Size video_frame_size; |
| 208 video_frame_size.width = vpx_image_->d_w; |
| 209 video_frame_size.height = vpx_image_->d_h; |
| 210 cdm_video_frame->set_size(video_frame_size); |
| 211 |
| 212 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kYPlane, 0); |
| 213 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kUPlane, y_size); |
| 214 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kVPlane, |
| 215 y_size + uv_size); |
| 216 |
| 217 cdm_video_frame->set_stride(cdm::VideoFrame::kYPlane, vpx_image_->d_w); |
| 218 cdm_video_frame->set_stride(cdm::VideoFrame::kUPlane, uv_stride); |
| 219 cdm_video_frame->set_stride(cdm::VideoFrame::kVPlane, uv_stride); |
| 220 #else |
| 221 const int y_size = vpx_image_->stride[VPX_PLANE_Y] * vpx_image_->d_h; |
| 222 const int uv_rows = vpx_image_->d_h / 2; |
| 223 const int u_size = vpx_image_->stride[VPX_PLANE_U] * uv_rows; |
| 224 const int v_size = vpx_image_->stride[VPX_PLANE_V] * uv_rows; |
| 225 const int space_required = y_size + u_size + v_size; |
| 226 |
| 227 DCHECK(!cdm_video_frame->frame_buffer()); |
| 228 cdm_video_frame->set_frame_buffer(allocator_->Allocate(space_required)); |
| 229 if (!cdm_video_frame->frame_buffer()) { |
| 230 LOG(ERROR) << "CopyVpxImageTo() cdm::Allocator::Allocate failed."; |
| 231 return false; |
| 232 } |
| 233 |
| 234 memcpy(cdm_video_frame->frame_buffer()->data(), |
| 235 vpx_image_->planes[VPX_PLANE_Y], |
| 236 y_size); |
| 237 memcpy(cdm_video_frame->frame_buffer()->data() + y_size, |
| 238 vpx_image_->planes[VPX_PLANE_U], |
| 239 u_size); |
| 240 memcpy(cdm_video_frame->frame_buffer()->data() + y_size + u_size, |
| 241 vpx_image_->planes[VPX_PLANE_V], |
| 242 v_size); |
| 243 |
| 244 cdm_video_frame->set_format(cdm::kYv12); |
| 245 |
| 246 cdm::Size video_frame_size; |
| 247 video_frame_size.width = vpx_image_->d_w; |
| 248 video_frame_size.height = vpx_image_->d_h; |
| 249 cdm_video_frame->set_size(video_frame_size); |
| 250 |
| 251 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kYPlane, 0); |
| 252 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kUPlane, y_size); |
| 253 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kVPlane, |
| 254 y_size + u_size); |
| 255 |
| 256 cdm_video_frame->set_stride(cdm::VideoFrame::kYPlane, |
| 257 vpx_image_->stride[VPX_PLANE_Y]); |
| 258 cdm_video_frame->set_stride(cdm::VideoFrame::kUPlane, |
| 259 vpx_image_->stride[VPX_PLANE_U]); |
| 260 cdm_video_frame->set_stride(cdm::VideoFrame::kVPlane, |
| 261 vpx_image_->stride[VPX_PLANE_V]); |
| 262 #endif // USE_COPYPLANE_WITH_LIBVPX |
| 263 |
| 264 return true; |
| 265 } |
| 266 |
| 267 } // namespace webkit_media |
OLD | NEW |