Home | History | Annotate | Download | only in proxy
      1 // Copyright 2014 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 "ppapi/proxy/media_stream_video_track_resource.h"
      6 
      7 #include "base/logging.h"
      8 #include "ppapi/proxy/ppapi_messages.h"
      9 #include "ppapi/proxy/video_frame_resource.h"
     10 #include "ppapi/shared_impl/media_stream_buffer.h"
     11 #include "ppapi/shared_impl/media_stream_video_track_shared.h"
     12 #include "ppapi/shared_impl/var.h"
     13 
     14 namespace ppapi {
     15 namespace proxy {
     16 
     17 MediaStreamVideoTrackResource::MediaStreamVideoTrackResource(
     18     Connection connection,
     19     PP_Instance instance,
     20     int pending_renderer_id,
     21     const std::string& id)
     22     : MediaStreamTrackResourceBase(
     23         connection, instance, pending_renderer_id, id),
     24       get_frame_output_(NULL) {
     25 }
     26 
     27 MediaStreamVideoTrackResource::MediaStreamVideoTrackResource(
     28     Connection connection,
     29     PP_Instance instance)
     30     : MediaStreamTrackResourceBase(connection, instance),
     31       get_frame_output_(NULL) {
     32   SendCreate(RENDERER, PpapiHostMsg_MediaStreamVideoTrack_Create());
     33 }
     34 
     35 MediaStreamVideoTrackResource::~MediaStreamVideoTrackResource() {
     36   Close();
     37 }
     38 
     39 thunk::PPB_MediaStreamVideoTrack_API*
     40 MediaStreamVideoTrackResource::AsPPB_MediaStreamVideoTrack_API() {
     41   return this;
     42 }
     43 
     44 PP_Var MediaStreamVideoTrackResource::GetId() {
     45   return StringVar::StringToPPVar(id());
     46 }
     47 
     48 PP_Bool MediaStreamVideoTrackResource::HasEnded() {
     49   return PP_FromBool(has_ended());
     50 }
     51 
     52 int32_t MediaStreamVideoTrackResource::Configure(
     53     const int32_t attrib_list[],
     54     scoped_refptr<TrackedCallback> callback) {
     55   if (has_ended())
     56     return PP_ERROR_FAILED;
     57 
     58   if (TrackedCallback::IsPending(configure_callback_) ||
     59       TrackedCallback::IsPending(get_frame_callback_)) {
     60     return PP_ERROR_INPROGRESS;
     61   }
     62 
     63   // Do not support configure, if frames are hold by plugin.
     64   if (!frames_.empty())
     65     return PP_ERROR_INPROGRESS;
     66 
     67   MediaStreamVideoTrackShared::Attributes attributes;
     68   int i = 0;
     69   for (;attrib_list[i] != PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE; i += 2) {
     70     switch (attrib_list[i]) {
     71     case PP_MEDIASTREAMVIDEOTRACK_ATTRIB_BUFFERED_FRAMES:
     72       attributes.buffers = attrib_list[i + 1];
     73       break;
     74     case PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH:
     75       attributes.width = attrib_list[i + 1];
     76       break;
     77     case PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT:
     78       attributes.height = attrib_list[i + 1];
     79       break;
     80     case PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT:
     81       attributes.format = static_cast<PP_VideoFrame_Format>(attrib_list[i + 1]);
     82       break;
     83     default:
     84       return PP_ERROR_BADARGUMENT;
     85     }
     86   }
     87 
     88   if (!MediaStreamVideoTrackShared::VerifyAttributes(attributes))
     89     return PP_ERROR_BADARGUMENT;
     90 
     91   configure_callback_ = callback;
     92   Call<PpapiPluginMsg_MediaStreamVideoTrack_ConfigureReply>(
     93       RENDERER,
     94       PpapiHostMsg_MediaStreamVideoTrack_Configure(attributes),
     95       base::Bind(&MediaStreamVideoTrackResource::OnPluginMsgConfigureReply,
     96                  base::Unretained(this)),
     97       callback);
     98   return PP_OK_COMPLETIONPENDING;
     99 }
    100 
    101 int32_t MediaStreamVideoTrackResource::GetAttrib(
    102     PP_MediaStreamVideoTrack_Attrib attrib,
    103     int32_t* value) {
    104   // TODO(penghuang): implement this function.
    105   return PP_ERROR_NOTSUPPORTED;
    106 }
    107 
    108 int32_t MediaStreamVideoTrackResource::GetFrame(
    109     PP_Resource* frame,
    110     scoped_refptr<TrackedCallback> callback) {
    111   if (has_ended())
    112     return PP_ERROR_FAILED;
    113 
    114   if (TrackedCallback::IsPending(configure_callback_) ||
    115       TrackedCallback::IsPending(get_frame_callback_)) {
    116     return PP_ERROR_INPROGRESS;
    117   }
    118 
    119   *frame = GetVideoFrame();
    120   if (*frame)
    121     return PP_OK;
    122 
    123   get_frame_output_ = frame;
    124   get_frame_callback_ = callback;
    125   return PP_OK_COMPLETIONPENDING;
    126 }
    127 
    128 int32_t MediaStreamVideoTrackResource::RecycleFrame(PP_Resource frame) {
    129   FrameMap::iterator it = frames_.find(frame);
    130   if (it == frames_.end())
    131     return PP_ERROR_BADRESOURCE;
    132 
    133   scoped_refptr<VideoFrameResource> frame_resource = it->second;
    134   frames_.erase(it);
    135 
    136   if (has_ended())
    137     return PP_OK;
    138 
    139   DCHECK_GE(frame_resource->GetBufferIndex(), 0);
    140 
    141   SendEnqueueBufferMessageToHost(frame_resource->GetBufferIndex());
    142   frame_resource->Invalidate();
    143   return PP_OK;
    144 }
    145 
    146 void MediaStreamVideoTrackResource::Close() {
    147   if (has_ended())
    148     return;
    149 
    150   if (TrackedCallback::IsPending(get_frame_callback_)) {
    151     *get_frame_output_ = 0;
    152     get_frame_callback_->PostAbort();
    153     get_frame_callback_ = NULL;
    154     get_frame_output_ = 0;
    155   }
    156 
    157   ReleaseFrames();
    158   MediaStreamTrackResourceBase::CloseInternal();
    159 }
    160 
    161 int32_t MediaStreamVideoTrackResource::GetEmptyFrame(
    162     PP_Resource* frame, scoped_refptr<TrackedCallback> callback) {
    163   return GetFrame(frame, callback);
    164 }
    165 
    166 int32_t MediaStreamVideoTrackResource::PutFrame(PP_Resource frame) {
    167   // TODO(ronghuawu): Consider to rename RecycleFrame to PutFrame and use
    168   // one set of GetFrame and PutFrame for both input and output.
    169   return RecycleFrame(frame);
    170 }
    171 
    172 void MediaStreamVideoTrackResource::OnNewBufferEnqueued() {
    173   if (!TrackedCallback::IsPending(get_frame_callback_))
    174     return;
    175 
    176   *get_frame_output_ = GetVideoFrame();
    177   int32_t result = *get_frame_output_ ? PP_OK : PP_ERROR_FAILED;
    178   get_frame_output_ = NULL;
    179   scoped_refptr<TrackedCallback> callback;
    180   callback.swap(get_frame_callback_);
    181   callback->Run(result);
    182 }
    183 
    184 PP_Resource MediaStreamVideoTrackResource::GetVideoFrame() {
    185   int32_t index = buffer_manager()->DequeueBuffer();
    186   if (index < 0)
    187     return 0;
    188 
    189   MediaStreamBuffer* buffer = buffer_manager()->GetBufferPointer(index);
    190   DCHECK(buffer);
    191   scoped_refptr<VideoFrameResource> resource =
    192       new VideoFrameResource(pp_instance(), index, buffer);
    193   // Add |pp_resource()| and |resource| into |frames_|.
    194   // |frames_| uses scoped_ptr<> to hold a ref of |resource|. It keeps the
    195   // resource alive.
    196   frames_.insert(FrameMap::value_type(resource->pp_resource(), resource));
    197   return resource->GetReference();
    198 }
    199 
    200 void MediaStreamVideoTrackResource::ReleaseFrames() {
    201   for (FrameMap::iterator it = frames_.begin(); it != frames_.end(); ++it) {
    202     // Just invalidate and release VideoFrameResorce, but keep PP_Resource.
    203     // So plugin can still use |RecycleFrame()|.
    204     it->second->Invalidate();
    205     it->second = NULL;
    206   }
    207 }
    208 
    209 void MediaStreamVideoTrackResource::OnPluginMsgConfigureReply(
    210     const ResourceMessageReplyParams& params,
    211     const std::string& track_id) {
    212   if (id().empty()) {
    213     set_id(track_id);
    214   } else {
    215     DCHECK_EQ(id(), track_id);
    216   }
    217   if (TrackedCallback::IsPending(configure_callback_)) {
    218     scoped_refptr<TrackedCallback> callback;
    219     callback.swap(configure_callback_);
    220     callback->Run(params.result());
    221   }
    222 }
    223 
    224 }  // namespace proxy
    225 }  // namespace ppapi
    226