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