Home | History | Annotate | Download | only in pepper
      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