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 "content/renderer/pepper/ppb_video_decoder_impl.h" 6 7 #include <string> 8 9 #include "base/logging.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/metrics/histogram.h" 12 #include "content/renderer/media/pepper_platform_video_decoder.h" 13 #include "content/renderer/pepper/common.h" 14 #include "content/renderer/pepper/host_globals.h" 15 #include "content/renderer/pepper/pepper_platform_context_3d.h" 16 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" 17 #include "content/renderer/pepper/plugin_module.h" 18 #include "content/renderer/pepper/ppb_buffer_impl.h" 19 #include "content/renderer/pepper/ppb_graphics_3d_impl.h" 20 #include "gpu/command_buffer/client/gles2_implementation.h" 21 #include "media/video/picture.h" 22 #include "media/video/video_decode_accelerator.h" 23 #include "ppapi/c/dev/pp_video_dev.h" 24 #include "ppapi/c/dev/ppb_video_decoder_dev.h" 25 #include "ppapi/c/dev/ppp_video_decoder_dev.h" 26 #include "ppapi/c/pp_completion_callback.h" 27 #include "ppapi/c/pp_errors.h" 28 #include "ppapi/shared_impl/resource_tracker.h" 29 #include "ppapi/thunk/enter.h" 30 31 using ppapi::TrackedCallback; 32 using ppapi::thunk::EnterResourceNoLock; 33 using ppapi::thunk::PPB_Buffer_API; 34 using ppapi::thunk::PPB_Graphics3D_API; 35 using ppapi::thunk::PPB_VideoDecoder_API; 36 37 namespace { 38 39 // Convert PP_VideoDecoder_Profile to media::VideoCodecProfile. 40 media::VideoCodecProfile PPToMediaProfile( 41 const PP_VideoDecoder_Profile pp_profile) { 42 switch (pp_profile) { 43 case PP_VIDEODECODER_H264PROFILE_NONE: 44 // HACK: PPAPI contains a bogus "none" h264 profile that doesn't 45 // correspond to anything in h.264; but a number of released chromium 46 // versions silently promoted this to Baseline profile, so we retain that 47 // behavior here. Fall through. 48 case PP_VIDEODECODER_H264PROFILE_BASELINE: 49 return media::H264PROFILE_BASELINE; 50 case PP_VIDEODECODER_H264PROFILE_MAIN: 51 return media::H264PROFILE_MAIN; 52 case PP_VIDEODECODER_H264PROFILE_EXTENDED: 53 return media::H264PROFILE_EXTENDED; 54 case PP_VIDEODECODER_H264PROFILE_HIGH: 55 return media::H264PROFILE_HIGH; 56 case PP_VIDEODECODER_H264PROFILE_HIGH10PROFILE: 57 return media::H264PROFILE_HIGH10PROFILE; 58 case PP_VIDEODECODER_H264PROFILE_HIGH422PROFILE: 59 return media::H264PROFILE_HIGH422PROFILE; 60 case PP_VIDEODECODER_H264PROFILE_HIGH444PREDICTIVEPROFILE: 61 return media::H264PROFILE_HIGH444PREDICTIVEPROFILE; 62 case PP_VIDEODECODER_H264PROFILE_SCALABLEBASELINE: 63 return media::H264PROFILE_SCALABLEBASELINE; 64 case PP_VIDEODECODER_H264PROFILE_SCALABLEHIGH: 65 return media::H264PROFILE_SCALABLEHIGH; 66 case PP_VIDEODECODER_H264PROFILE_STEREOHIGH: 67 return media::H264PROFILE_STEREOHIGH; 68 case PP_VIDEODECODER_H264PROFILE_MULTIVIEWHIGH: 69 return media::H264PROFILE_MULTIVIEWHIGH; 70 case PP_VIDEODECODER_VP8PROFILE_MAIN: 71 return media::VP8PROFILE_MAIN; 72 default: 73 return media::VIDEO_CODEC_PROFILE_UNKNOWN; 74 } 75 } 76 77 PP_VideoDecodeError_Dev MediaToPPError( 78 media::VideoDecodeAccelerator::Error error) { 79 switch (error) { 80 case media::VideoDecodeAccelerator::ILLEGAL_STATE : 81 return PP_VIDEODECODERERROR_ILLEGAL_STATE; 82 case media::VideoDecodeAccelerator::INVALID_ARGUMENT : 83 return PP_VIDEODECODERERROR_INVALID_ARGUMENT; 84 case media::VideoDecodeAccelerator::UNREADABLE_INPUT : 85 return PP_VIDEODECODERERROR_UNREADABLE_INPUT; 86 case media::VideoDecodeAccelerator::PLATFORM_FAILURE : 87 return PP_VIDEODECODERERROR_PLATFORM_FAILURE; 88 default: 89 NOTREACHED(); 90 return PP_VIDEODECODERERROR_ILLEGAL_STATE; 91 } 92 } 93 94 } // namespace 95 96 namespace content { 97 98 PPB_VideoDecoder_Impl::PPB_VideoDecoder_Impl(PP_Instance instance) 99 : PPB_VideoDecoder_Shared(instance), 100 ppp_videodecoder_(NULL) { 101 PluginModule* plugin_module = 102 HostGlobals::Get()->GetInstance(pp_instance())->module(); 103 if (plugin_module) { 104 ppp_videodecoder_ = static_cast<const PPP_VideoDecoder_Dev*>( 105 plugin_module->GetPluginInterface(PPP_VIDEODECODER_DEV_INTERFACE)); 106 } 107 } 108 109 PPB_VideoDecoder_Impl::~PPB_VideoDecoder_Impl() { 110 Destroy(); 111 } 112 113 // static 114 PP_Resource PPB_VideoDecoder_Impl::Create( 115 PP_Instance instance, 116 PP_Resource graphics_context, 117 PP_VideoDecoder_Profile profile) { 118 EnterResourceNoLock<PPB_Graphics3D_API> enter_context(graphics_context, true); 119 if (enter_context.failed()) 120 return 0; 121 PPB_Graphics3D_Impl* graphics3d_impl = 122 static_cast<PPB_Graphics3D_Impl*>(enter_context.object()); 123 124 scoped_refptr<PPB_VideoDecoder_Impl> decoder( 125 new PPB_VideoDecoder_Impl(instance)); 126 if (decoder->Init(graphics_context, graphics3d_impl->platform_context(), 127 graphics3d_impl->gles2_impl(), profile)) 128 return decoder->GetReference(); 129 return 0; 130 } 131 132 bool PPB_VideoDecoder_Impl::Init( 133 PP_Resource graphics_context, 134 PlatformContext3D* context, 135 gpu::gles2::GLES2Implementation* gles2_impl, 136 PP_VideoDecoder_Profile profile) { 137 InitCommon(graphics_context, gles2_impl); 138 139 int command_buffer_route_id = context->GetCommandBufferRouteId(); 140 if (command_buffer_route_id == 0) 141 return false; 142 143 platform_video_decoder_.reset(new PlatformVideoDecoder( 144 this, command_buffer_route_id)); 145 if (!platform_video_decoder_) 146 return false; 147 148 FlushCommandBuffer(); 149 return platform_video_decoder_->Initialize(PPToMediaProfile(profile)); 150 } 151 152 int32_t PPB_VideoDecoder_Impl::Decode( 153 const PP_VideoBitstreamBuffer_Dev* bitstream_buffer, 154 scoped_refptr<TrackedCallback> callback) { 155 if (!platform_video_decoder_) 156 return PP_ERROR_BADRESOURCE; 157 158 EnterResourceNoLock<PPB_Buffer_API> enter(bitstream_buffer->data, true); 159 if (enter.failed()) 160 return PP_ERROR_FAILED; 161 162 PPB_Buffer_Impl* buffer = static_cast<PPB_Buffer_Impl*>(enter.object()); 163 DCHECK_GE(bitstream_buffer->id, 0); 164 media::BitstreamBuffer decode_buffer( 165 bitstream_buffer->id, 166 buffer->shared_memory()->handle(), 167 bitstream_buffer->size); 168 if (!SetBitstreamBufferCallback(bitstream_buffer->id, callback)) 169 return PP_ERROR_BADARGUMENT; 170 171 FlushCommandBuffer(); 172 platform_video_decoder_->Decode(decode_buffer); 173 return PP_OK_COMPLETIONPENDING; 174 } 175 176 void PPB_VideoDecoder_Impl::AssignPictureBuffers( 177 uint32_t no_of_buffers, 178 const PP_PictureBuffer_Dev* buffers) { 179 if (!platform_video_decoder_) 180 return; 181 UMA_HISTOGRAM_COUNTS_100("Media.PepperVideoDecoderPictureCount", 182 no_of_buffers); 183 184 std::vector<media::PictureBuffer> wrapped_buffers; 185 for (uint32 i = 0; i < no_of_buffers; i++) { 186 PP_PictureBuffer_Dev in_buf = buffers[i]; 187 DCHECK_GE(in_buf.id, 0); 188 media::PictureBuffer buffer( 189 in_buf.id, 190 gfx::Size(in_buf.size.width, in_buf.size.height), 191 in_buf.texture_id); 192 wrapped_buffers.push_back(buffer); 193 UMA_HISTOGRAM_COUNTS_10000("Media.PepperVideoDecoderPictureHeight", 194 in_buf.size.height); 195 } 196 197 FlushCommandBuffer(); 198 platform_video_decoder_->AssignPictureBuffers(wrapped_buffers); 199 } 200 201 void PPB_VideoDecoder_Impl::ReusePictureBuffer(int32_t picture_buffer_id) { 202 if (!platform_video_decoder_) 203 return; 204 205 FlushCommandBuffer(); 206 platform_video_decoder_->ReusePictureBuffer(picture_buffer_id); 207 } 208 209 int32_t PPB_VideoDecoder_Impl::Flush(scoped_refptr<TrackedCallback> callback) { 210 if (!platform_video_decoder_) 211 return PP_ERROR_BADRESOURCE; 212 213 if (!SetFlushCallback(callback)) 214 return PP_ERROR_INPROGRESS; 215 216 FlushCommandBuffer(); 217 platform_video_decoder_->Flush(); 218 return PP_OK_COMPLETIONPENDING; 219 } 220 221 int32_t PPB_VideoDecoder_Impl::Reset(scoped_refptr<TrackedCallback> callback) { 222 if (!platform_video_decoder_) 223 return PP_ERROR_BADRESOURCE; 224 225 if (!SetResetCallback(callback)) 226 return PP_ERROR_INPROGRESS; 227 228 FlushCommandBuffer(); 229 platform_video_decoder_->Reset(); 230 return PP_OK_COMPLETIONPENDING; 231 } 232 233 void PPB_VideoDecoder_Impl::Destroy() { 234 FlushCommandBuffer(); 235 236 if (platform_video_decoder_) 237 platform_video_decoder_.release()->Destroy(); 238 ppp_videodecoder_ = NULL; 239 240 ::ppapi::PPB_VideoDecoder_Shared::Destroy(); 241 } 242 243 void PPB_VideoDecoder_Impl::ProvidePictureBuffers( 244 uint32 requested_num_of_buffers, 245 const gfx::Size& dimensions, 246 uint32 texture_target) { 247 if (!ppp_videodecoder_) 248 return; 249 250 PP_Size out_dim = PP_MakeSize(dimensions.width(), dimensions.height()); 251 ppp_videodecoder_->ProvidePictureBuffers(pp_instance(), pp_resource(), 252 requested_num_of_buffers, &out_dim, texture_target); 253 } 254 255 void PPB_VideoDecoder_Impl::PictureReady(const media::Picture& picture) { 256 if (!ppp_videodecoder_) 257 return; 258 259 PP_Picture_Dev output; 260 output.picture_buffer_id = picture.picture_buffer_id(); 261 output.bitstream_buffer_id = picture.bitstream_buffer_id(); 262 ppp_videodecoder_->PictureReady(pp_instance(), pp_resource(), &output); 263 } 264 265 void PPB_VideoDecoder_Impl::DismissPictureBuffer(int32 picture_buffer_id) { 266 if (!ppp_videodecoder_) 267 return; 268 ppp_videodecoder_->DismissPictureBuffer(pp_instance(), pp_resource(), 269 picture_buffer_id); 270 } 271 272 void PPB_VideoDecoder_Impl::NotifyError( 273 media::VideoDecodeAccelerator::Error error) { 274 if (!ppp_videodecoder_) 275 return; 276 277 PP_VideoDecodeError_Dev pp_error = MediaToPPError(error); 278 ppp_videodecoder_->NotifyError(pp_instance(), pp_resource(), pp_error); 279 UMA_HISTOGRAM_ENUMERATION( 280 "Media.PepperVideoDecoderError", error, 281 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); 282 } 283 284 void PPB_VideoDecoder_Impl::NotifyResetDone() { 285 RunResetCallback(PP_OK); 286 } 287 288 void PPB_VideoDecoder_Impl::NotifyEndOfBitstreamBuffer( 289 int32 bitstream_buffer_id) { 290 RunBitstreamBufferCallback(bitstream_buffer_id, PP_OK); 291 } 292 293 void PPB_VideoDecoder_Impl::NotifyFlushDone() { 294 RunFlushCallback(PP_OK); 295 } 296 297 void PPB_VideoDecoder_Impl::NotifyInitializeDone() { 298 NOTREACHED() << "PlatformVideoDecoder::Initialize() is synchronous!"; 299 } 300 301 } // namespace content 302