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 "media/filters/vpx_video_decoder.h" 6 7 #include <algorithm> 8 #include <string> 9 10 #include "base/bind.h" 11 #include "base/callback_helpers.h" 12 #include "base/command_line.h" 13 #include "base/location.h" 14 #include "base/logging.h" 15 #include "base/message_loop/message_loop_proxy.h" 16 #include "base/strings/string_number_conversions.h" 17 #include "base/sys_byteorder.h" 18 #include "media/base/bind_to_loop.h" 19 #include "media/base/decoder_buffer.h" 20 #include "media/base/demuxer_stream.h" 21 #include "media/base/media_switches.h" 22 #include "media/base/pipeline.h" 23 #include "media/base/video_decoder_config.h" 24 #include "media/base/video_frame.h" 25 #include "media/base/video_util.h" 26 27 // Include libvpx header files. 28 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide 29 // backwards compatibility for legacy applications using the library. 30 #define VPX_CODEC_DISABLE_COMPAT 1 31 extern "C" { 32 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" 33 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" 34 } 35 36 namespace media { 37 38 // Always try to use three threads for video decoding. There is little reason 39 // not to since current day CPUs tend to be multi-core and we measured 40 // performance benefits on older machines such as P4s with hyperthreading. 41 static const int kDecodeThreads = 2; 42 static const int kMaxDecodeThreads = 16; 43 44 // Returns the number of threads. 45 static int GetThreadCount() { 46 // TODO(scherkus): De-duplicate this function and the one used by 47 // FFmpegVideoDecoder. 48 49 // Refer to http://crbug.com/93932 for tsan suppressions on decoding. 50 int decode_threads = kDecodeThreads; 51 52 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 53 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads)); 54 if (threads.empty() || !base::StringToInt(threads, &decode_threads)) 55 return decode_threads; 56 57 decode_threads = std::max(decode_threads, 0); 58 decode_threads = std::min(decode_threads, kMaxDecodeThreads); 59 return decode_threads; 60 } 61 62 VpxVideoDecoder::VpxVideoDecoder( 63 const scoped_refptr<base::MessageLoopProxy>& message_loop) 64 : message_loop_(message_loop), 65 weak_factory_(this), 66 state_(kUninitialized), 67 vpx_codec_(NULL), 68 vpx_codec_alpha_(NULL) { 69 } 70 71 VpxVideoDecoder::~VpxVideoDecoder() { 72 DCHECK_EQ(kUninitialized, state_); 73 CloseDecoder(); 74 } 75 76 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config, 77 const PipelineStatusCB& status_cb) { 78 DCHECK(message_loop_->BelongsToCurrentThread()); 79 DCHECK(config.IsValidConfig()); 80 DCHECK(!config.is_encrypted()); 81 DCHECK(decode_cb_.is_null()); 82 DCHECK(reset_cb_.is_null()); 83 84 weak_this_ = weak_factory_.GetWeakPtr(); 85 86 if (!ConfigureDecoder(config)) { 87 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); 88 return; 89 } 90 91 // Success! 92 config_ = config; 93 state_ = kNormal; 94 status_cb.Run(PIPELINE_OK); 95 } 96 97 static vpx_codec_ctx* InitializeVpxContext(vpx_codec_ctx* context, 98 const VideoDecoderConfig& config) { 99 context = new vpx_codec_ctx(); 100 vpx_codec_dec_cfg_t vpx_config = {0}; 101 vpx_config.w = config.coded_size().width(); 102 vpx_config.h = config.coded_size().height(); 103 vpx_config.threads = GetThreadCount(); 104 105 vpx_codec_err_t status = vpx_codec_dec_init(context, 106 config.codec() == kCodecVP9 ? 107 vpx_codec_vp9_dx() : 108 vpx_codec_vp8_dx(), 109 &vpx_config, 110 0); 111 if (status != VPX_CODEC_OK) { 112 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status; 113 delete context; 114 return NULL; 115 } 116 return context; 117 } 118 119 bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) { 120 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 121 bool can_handle = false; 122 if (config.codec() == kCodecVP9) 123 can_handle = true; 124 if (cmd_line->HasSwitch(switches::kEnableVp8AlphaPlayback) && 125 config.codec() == kCodecVP8 && config.format() == VideoFrame::YV12A) { 126 can_handle = true; 127 } 128 if (!can_handle) 129 return false; 130 131 CloseDecoder(); 132 133 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); 134 if (!vpx_codec_) 135 return false; 136 137 if (config.format() == VideoFrame::YV12A) { 138 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); 139 if (!vpx_codec_alpha_) 140 return false; 141 } 142 143 return true; 144 } 145 146 void VpxVideoDecoder::CloseDecoder() { 147 if (vpx_codec_) { 148 vpx_codec_destroy(vpx_codec_); 149 delete vpx_codec_; 150 vpx_codec_ = NULL; 151 } 152 if (vpx_codec_alpha_) { 153 vpx_codec_destroy(vpx_codec_alpha_); 154 delete vpx_codec_alpha_; 155 vpx_codec_alpha_ = NULL; 156 } 157 } 158 159 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, 160 const DecodeCB& decode_cb) { 161 DCHECK(message_loop_->BelongsToCurrentThread()); 162 DCHECK(!decode_cb.is_null()); 163 CHECK_NE(state_, kUninitialized); 164 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported."; 165 166 decode_cb_ = BindToCurrentLoop(decode_cb); 167 168 if (state_ == kError) { 169 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL); 170 return; 171 } 172 173 // Return empty frames if decoding has finished. 174 if (state_ == kDecodeFinished) { 175 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); 176 return; 177 } 178 179 DecodeBuffer(buffer); 180 } 181 182 void VpxVideoDecoder::Reset(const base::Closure& closure) { 183 DCHECK(message_loop_->BelongsToCurrentThread()); 184 DCHECK(reset_cb_.is_null()); 185 reset_cb_ = BindToCurrentLoop(closure); 186 187 // Defer the reset if a decode is pending. 188 if (!decode_cb_.is_null()) 189 return; 190 191 DoReset(); 192 } 193 194 void VpxVideoDecoder::Stop(const base::Closure& closure) { 195 DCHECK(message_loop_->BelongsToCurrentThread()); 196 base::ScopedClosureRunner runner(BindToCurrentLoop(closure)); 197 198 if (state_ == kUninitialized) 199 return; 200 201 if (!decode_cb_.is_null()) { 202 base::ResetAndReturn(&decode_cb_).Run(kOk, NULL); 203 // Reset is pending only when decode is pending. 204 if (!reset_cb_.is_null()) 205 base::ResetAndReturn(&reset_cb_).Run(); 206 } 207 208 state_ = kUninitialized; 209 } 210 211 bool VpxVideoDecoder::HasAlpha() const { 212 return vpx_codec_alpha_ != NULL; 213 } 214 215 void VpxVideoDecoder::DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer) { 216 DCHECK(message_loop_->BelongsToCurrentThread()); 217 DCHECK_NE(state_, kUninitialized); 218 DCHECK_NE(state_, kDecodeFinished); 219 DCHECK_NE(state_, kError); 220 DCHECK(reset_cb_.is_null()); 221 DCHECK(!decode_cb_.is_null()); 222 DCHECK(buffer); 223 224 // Transition to kDecodeFinished on the first end of stream buffer. 225 if (state_ == kNormal && buffer->end_of_stream()) { 226 state_ = kDecodeFinished; 227 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); 228 return; 229 } 230 231 scoped_refptr<VideoFrame> video_frame; 232 if (!VpxDecode(buffer, &video_frame)) { 233 state_ = kError; 234 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL); 235 return; 236 } 237 238 // If we didn't get a frame we need more data. 239 if (!video_frame.get()) { 240 base::ResetAndReturn(&decode_cb_).Run(kNotEnoughData, NULL); 241 return; 242 } 243 244 base::ResetAndReturn(&decode_cb_).Run(kOk, video_frame); 245 } 246 247 bool VpxVideoDecoder::VpxDecode(const scoped_refptr<DecoderBuffer>& buffer, 248 scoped_refptr<VideoFrame>* video_frame) { 249 DCHECK(video_frame); 250 DCHECK(!buffer->end_of_stream()); 251 252 // Pass |buffer| to libvpx. 253 int64 timestamp = buffer->timestamp().InMicroseconds(); 254 void* user_priv = reinterpret_cast<void*>(×tamp); 255 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_, 256 buffer->data(), 257 buffer->data_size(), 258 user_priv, 259 0); 260 if (status != VPX_CODEC_OK) { 261 LOG(ERROR) << "vpx_codec_decode() failed, status=" << status; 262 return false; 263 } 264 265 // Gets pointer to decoded data. 266 vpx_codec_iter_t iter = NULL; 267 const vpx_image_t* vpx_image = vpx_codec_get_frame(vpx_codec_, &iter); 268 if (!vpx_image) { 269 *video_frame = NULL; 270 return true; 271 } 272 273 if (vpx_image->user_priv != reinterpret_cast<void*>(×tamp)) { 274 LOG(ERROR) << "Invalid output timestamp."; 275 return false; 276 } 277 278 const vpx_image_t* vpx_image_alpha = NULL; 279 if (vpx_codec_alpha_ && buffer->side_data_size() >= 8) { 280 // Pass alpha data to libvpx. 281 int64 timestamp_alpha = buffer->timestamp().InMicroseconds(); 282 void* user_priv_alpha = reinterpret_cast<void*>(×tamp_alpha); 283 284 // First 8 bytes of side data is side_data_id in big endian. 285 const uint64 side_data_id = base::NetToHost64( 286 *(reinterpret_cast<const uint64*>(buffer->side_data()))); 287 if (side_data_id == 1) { 288 status = vpx_codec_decode(vpx_codec_alpha_, 289 buffer->side_data() + 8, 290 buffer->side_data_size() - 8, 291 user_priv_alpha, 292 0); 293 294 if (status != VPX_CODEC_OK) { 295 LOG(ERROR) << "vpx_codec_decode() failed on alpha, status=" << status; 296 return false; 297 } 298 299 // Gets pointer to decoded data. 300 vpx_codec_iter_t iter_alpha = NULL; 301 vpx_image_alpha = vpx_codec_get_frame(vpx_codec_alpha_, &iter_alpha); 302 if (!vpx_image_alpha) { 303 *video_frame = NULL; 304 return true; 305 } 306 307 if (vpx_image_alpha->user_priv != 308 reinterpret_cast<void*>(×tamp_alpha)) { 309 LOG(ERROR) << "Invalid output timestamp on alpha."; 310 return false; 311 } 312 } 313 } 314 315 CopyVpxImageTo(vpx_image, vpx_image_alpha, video_frame); 316 (*video_frame)->SetTimestamp(base::TimeDelta::FromMicroseconds(timestamp)); 317 return true; 318 } 319 320 void VpxVideoDecoder::DoReset() { 321 DCHECK(decode_cb_.is_null()); 322 323 state_ = kNormal; 324 reset_cb_.Run(); 325 reset_cb_.Reset(); 326 } 327 328 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, 329 const struct vpx_image* vpx_image_alpha, 330 scoped_refptr<VideoFrame>* video_frame) { 331 CHECK(vpx_image); 332 CHECK_EQ(vpx_image->d_w % 2, 0U); 333 CHECK_EQ(vpx_image->d_h % 2, 0U); 334 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || 335 vpx_image->fmt == VPX_IMG_FMT_YV12); 336 337 gfx::Size size(vpx_image->d_w, vpx_image->d_h); 338 339 *video_frame = VideoFrame::CreateFrame( 340 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, 341 size, 342 gfx::Rect(size), 343 config_.natural_size(), 344 kNoTimestamp()); 345 346 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], 347 vpx_image->stride[VPX_PLANE_Y], 348 vpx_image->d_h, 349 video_frame->get()); 350 CopyUPlane(vpx_image->planes[VPX_PLANE_U], 351 vpx_image->stride[VPX_PLANE_U], 352 vpx_image->d_h / 2, 353 video_frame->get()); 354 CopyVPlane(vpx_image->planes[VPX_PLANE_V], 355 vpx_image->stride[VPX_PLANE_V], 356 vpx_image->d_h / 2, 357 video_frame->get()); 358 if (!vpx_codec_alpha_) 359 return; 360 if (!vpx_image_alpha) { 361 MakeOpaqueAPlane( 362 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); 363 return; 364 } 365 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], 366 vpx_image->stride[VPX_PLANE_Y], 367 vpx_image->d_h, 368 video_frame->get()); 369 } 370 371 } // namespace media 372