• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
MediaStreamVideoTrackResource(Connection connection,PP_Instance instance,int pending_renderer_id,const std::string & id)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 
MediaStreamVideoTrackResource(Connection connection,PP_Instance instance)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 
~MediaStreamVideoTrackResource()35 MediaStreamVideoTrackResource::~MediaStreamVideoTrackResource() {
36   Close();
37 }
38 
39 thunk::PPB_MediaStreamVideoTrack_API*
AsPPB_MediaStreamVideoTrack_API()40 MediaStreamVideoTrackResource::AsPPB_MediaStreamVideoTrack_API() {
41   return this;
42 }
43 
GetId()44 PP_Var MediaStreamVideoTrackResource::GetId() {
45   return StringVar::StringToPPVar(id());
46 }
47 
HasEnded()48 PP_Bool MediaStreamVideoTrackResource::HasEnded() {
49   return PP_FromBool(has_ended());
50 }
51 
Configure(const int32_t attrib_list[],scoped_refptr<TrackedCallback> callback)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 
GetAttrib(PP_MediaStreamVideoTrack_Attrib attrib,int32_t * value)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 
GetFrame(PP_Resource * frame,scoped_refptr<TrackedCallback> callback)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 
RecycleFrame(PP_Resource frame)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 
Close()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 
GetEmptyFrame(PP_Resource * frame,scoped_refptr<TrackedCallback> callback)161 int32_t MediaStreamVideoTrackResource::GetEmptyFrame(
162     PP_Resource* frame, scoped_refptr<TrackedCallback> callback) {
163   return GetFrame(frame, callback);
164 }
165 
PutFrame(PP_Resource frame)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 
OnNewBufferEnqueued()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 
GetVideoFrame()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 
ReleaseFrames()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 
OnPluginMsgConfigureReply(const ResourceMessageReplyParams & params,const std::string & track_id)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