Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(358)

Side by Side Diff: mojo/services/media/common/cpp/video_renderer.cc

Issue 2068043005: Motown: Video renderer library code (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Fix empty packet detection. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 <limits>
6
7 #include "mojo/services/media/common/cpp/timeline.h"
8 #include "mojo/services/media/common/cpp/video_renderer.h"
9
10 namespace mojo {
11 namespace media {
12
13 VideoRenderer::VideoRenderer()
14 : renderer_binding_(this),
15 consumer_binding_(this),
16 control_site_binding_(this),
17 timeline_consumer_binding_(this) {}
18
19 VideoRenderer::~VideoRenderer() {}
20
21 void VideoRenderer::Bind(InterfaceRequest<MediaRenderer> renderer_request) {
22 renderer_binding_.Bind(renderer_request.Pass());
23 }
24
25 void VideoRenderer::GetRgbaFrame(uint8_t* rgba_buffer,
26 size_t width,
27 size_t height,
28 int64_t reference_time) {
29 MaybeApplyPendingTimelineChange(reference_time);
30 MaybePublishEndOfStream();
31
32 int64_t presentation_time = current_timeline_function_(reference_time);
33
34 // Discard empty and old packets. We keep one packet around even if it's old,
35 // so we can show an old frame instead of no frame when we starve.
36 while (!packet_queue_.empty() &&
37 (!packet_queue_.front().packet_->payload ||
38 packet_queue_.front().packet_->payload->length == 0 ||
39 (packet_queue_.size() > 1 &&
40 packet_queue_.front().packet_->pts < presentation_time))) {
41 // TODO(dalesat): Add hysteresis.
42 packet_queue_.pop();
43 }
44
45 // TODO(dalesat): Detect starvation.
46
47 if (packet_queue_.empty()) {
48 memset(rgba_buffer, 0, width * height * 4);
49 } else {
50 const MediaPacketPtr& packet = packet_queue_.front().packet_;
51 converter_.ConvertFrame(
52 rgba_buffer, width, height,
53 shared_buffer_.PtrFromOffset(packet->payload->offset),
54 packet->payload->length);
55 }
56 }
57
58 void VideoRenderer::GetSupportedMediaTypes(
59 const GetSupportedMediaTypesCallback& callback) {
60 VideoMediaTypeSetDetailsPtr video_details = VideoMediaTypeSetDetails::New();
61 video_details->min_width = 1;
62 video_details->max_width = std::numeric_limits<uint32_t>::max();
63 video_details->min_height = 1;
64 video_details->max_height = std::numeric_limits<uint32_t>::max();
65 MediaTypeSetPtr supported_type = MediaTypeSet::New();
66 supported_type->medium = MediaTypeMedium::VIDEO;
67 supported_type->details = MediaTypeSetDetails::New();
68 supported_type->details->set_video(video_details.Pass());
69 supported_type->encodings = Array<String>::New(1);
70 supported_type->encodings[0] = MediaType::kVideoEncodingUncompressed;
71 Array<MediaTypeSetPtr> supported_types = Array<MediaTypeSetPtr>::New(1);
72 supported_types[0] = supported_type.Pass();
73 callback.Run(supported_types.Pass());
74 }
75
76 void VideoRenderer::SetMediaType(MediaTypePtr media_type) {
77 MOJO_DCHECK(media_type);
78 MOJO_DCHECK(media_type->details);
79 const VideoMediaTypeDetailsPtr& details = media_type->details->get_video();
80 MOJO_DCHECK(details);
81
82 converter_.SetMediaType(media_type);
83 }
84
85 void VideoRenderer::GetConsumer(
86 InterfaceRequest<MediaConsumer> consumer_request) {
87 consumer_binding_.Bind(consumer_request.Pass());
88 }
89
90 void VideoRenderer::GetTimelineControlSite(
91 InterfaceRequest<MediaTimelineControlSite> control_site_request) {
92 control_site_binding_.Bind(control_site_request.Pass());
93 }
94
95 void VideoRenderer::SetBuffer(ScopedSharedBufferHandle buffer,
96 const SetBufferCallback& callback) {
97 shared_buffer_.InitFromHandle(buffer.Pass());
98 callback.Run();
99 }
100
101 void VideoRenderer::SendPacket(MediaPacketPtr packet,
102 const SendPacketCallback& callback) {
103 MOJO_DCHECK(packet);
104 if (packet->end_of_stream) {
105 MOJO_DLOG(INFO) << "END_OF_STREAM";
106 end_of_stream_pts_ = packet->pts;
107 }
108
109 packet_queue_.emplace(packet.Pass(), callback);
110 }
111
112 void VideoRenderer::Prime(const PrimeCallback& callback) {
113 callback.Run();
114 }
115
116 void VideoRenderer::Flush(const FlushCallback& callback) {
117 while (!packet_queue_.empty()) {
118 packet_queue_.pop();
119 }
120 callback.Run();
121 }
122
123 void VideoRenderer::GetStatus(uint64_t version_last_seen,
124 const GetStatusCallback& callback) {
125 if (version_last_seen < status_version_) {
126 CompleteGetStatus(callback);
127 } else {
128 pending_status_callbacks_.push_back(callback);
129 }
130 }
131
132 void VideoRenderer::GetTimelineConsumer(
133 InterfaceRequest<TimelineConsumer> timeline_consumer_request) {
134 timeline_consumer_binding_.Bind(timeline_consumer_request.Pass());
135 }
136
137 void VideoRenderer::SetTimelineTransform(
138 int64_t subject_time,
139 uint32_t reference_delta,
140 uint32_t subject_delta,
141 int64_t effective_reference_time,
142 int64_t effective_subject_time,
143 const SetTimelineTransformCallback& callback) {
144 // At most one of the effective times must be specified.
145 MOJO_DCHECK(effective_reference_time == kUnspecifiedTime ||
146 effective_subject_time == kUnspecifiedTime);
147 // effective_subject_time can only be used if we're progressing already.
148 MOJO_DCHECK(effective_subject_time == kUnspecifiedTime ||
149 current_timeline_function_.subject_delta() != 0);
150 MOJO_DCHECK(reference_delta != 0);
151
152 if (subject_time != kUnspecifiedTime &&
153 end_of_stream_pts_ != kUnspecifiedTime) {
154 end_of_stream_pts_ = kUnspecifiedTime;
155 end_of_stream_published_ = false;
156 }
157
158 if (effective_subject_time != kUnspecifiedTime) {
159 // Infer effective_reference_time from effective_subject_time.
160 effective_reference_time =
161 current_timeline_function_.ApplyInverse(effective_subject_time);
162
163 if (subject_time == kUnspecifiedTime) {
164 // Infer subject_time from effective_subject_time.
165 subject_time = effective_subject_time;
166 }
167 } else {
168 if (effective_reference_time == kUnspecifiedTime) {
169 // Neither effective time was specified. Effective time is now.
170 effective_reference_time = Timeline::local_now();
171 }
172
173 if (subject_time == kUnspecifiedTime) {
174 // Infer subject_time from effective_reference_time.
175 subject_time = current_timeline_function_(effective_reference_time);
176 }
177 }
178
179 // Eject any previous pending change.
180 ClearPendingTimelineFunction(false);
181
182 // Queue up the new pending change.
183 pending_timeline_function_ = TimelineFunction(
184 effective_reference_time, subject_time, reference_delta, subject_delta);
185
186 set_timeline_transform_callback_ = callback;
187 }
188
189 void VideoRenderer::ClearPendingTimelineFunction(bool completed) {
190 pending_timeline_function_ =
191 TimelineFunction(kUnspecifiedTime, kUnspecifiedTime, 1, 0);
192 if (!set_timeline_transform_callback_.is_null()) {
193 set_timeline_transform_callback_.Run(completed);
194 set_timeline_transform_callback_.reset();
195 }
196 }
197
198 void VideoRenderer::MaybeApplyPendingTimelineChange(int64_t reference_time) {
199 if (pending_timeline_function_.reference_time() == kUnspecifiedTime ||
200 pending_timeline_function_.reference_time() > reference_time) {
201 return;
202 }
203
204 current_timeline_function_ = pending_timeline_function_;
205 pending_timeline_function_ =
206 TimelineFunction(kUnspecifiedTime, kUnspecifiedTime, 1, 0);
207
208 if (!set_timeline_transform_callback_.is_null()) {
209 set_timeline_transform_callback_.Run(true);
210 set_timeline_transform_callback_.reset();
211 }
212
213 SendStatusUpdates();
214 }
215
216 void VideoRenderer::MaybePublishEndOfStream() {
217 if (!end_of_stream_published_ && end_of_stream_pts_ != kUnspecifiedTime &&
218 current_timeline_function_(Timeline::local_now()) >= end_of_stream_pts_) {
219 end_of_stream_published_ = true;
220 SendStatusUpdates();
221 }
222 }
223
224 void VideoRenderer::SendStatusUpdates() {
225 ++status_version_;
226
227 std::vector<GetStatusCallback> pending_status_callbacks;
228 pending_status_callbacks_.swap(pending_status_callbacks);
229
230 for (const GetStatusCallback& pending_status_callback :
231 pending_status_callbacks) {
232 CompleteGetStatus(pending_status_callback);
233 }
234 }
235
236 void VideoRenderer::CompleteGetStatus(const GetStatusCallback& callback) {
237 MediaTimelineControlSiteStatusPtr status =
238 MediaTimelineControlSiteStatus::New();
239 status->timeline_transform =
240 TimelineTransform::From(current_timeline_function_);
241 status->end_of_stream =
242 end_of_stream_pts_ != kUnspecifiedTime &&
243 current_timeline_function_(Timeline::local_now()) >= end_of_stream_pts_;
244 callback.Run(status_version_, status.Pass());
245 }
246
247 VideoRenderer::PacketAndCallback::PacketAndCallback(
248 MediaPacketPtr packet,
249 const SendPacketCallback& callback)
250 : packet_(packet.Pass()), callback_(callback) {
251 MOJO_DCHECK(packet_);
252 MOJO_DCHECK(!callback.is_null());
253 }
254
255 VideoRenderer::PacketAndCallback::~PacketAndCallback() {
256 callback_.Run(MediaConsumer::SendResult::CONSUMED);
257 }
258
259 } // namespace media
260 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698