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