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