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