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

Side by Side Diff: media/base/android/video_media_codec_decoder.cc

Issue 2276343005: Delete MediaCodecPlayer, it's time! (Closed)
Patch Set: Created 4 years, 3 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
« no previous file with comments | « media/base/android/video_media_codec_decoder.h ('k') | media/base/media_switches.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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 "media/base/android/video_media_codec_decoder.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "media/base/android/media_statistics.h"
12 #include "media/base/android/sdk_media_codec_bridge.h"
13 #include "media/base/demuxer_stream.h"
14 #include "media/base/timestamp_constants.h"
15
16 namespace media {
17
18 namespace {
19 const int kDelayForStandAloneEOS = 2; // milliseconds
20 }
21
22 VideoMediaCodecDecoder::VideoMediaCodecDecoder(
23 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
24 FrameStatistics* frame_statistics,
25 const base::Closure& request_data_cb,
26 const base::Closure& starvation_cb,
27 const base::Closure& decoder_drained_cb,
28 const base::Closure& stop_done_cb,
29 const base::Closure& waiting_for_decryption_key_cb,
30 const base::Closure& error_cb,
31 const SetTimeCallback& update_current_time_cb,
32 const VideoSizeChangedCallback& video_size_changed_cb)
33 : MediaCodecDecoder("VideoDecoder",
34 media_task_runner,
35 frame_statistics,
36 request_data_cb,
37 starvation_cb,
38 decoder_drained_cb,
39 stop_done_cb,
40 waiting_for_decryption_key_cb,
41 error_cb),
42 is_protected_surface_required_(false),
43 update_current_time_cb_(update_current_time_cb),
44 video_size_changed_cb_(video_size_changed_cb) {}
45
46 VideoMediaCodecDecoder::~VideoMediaCodecDecoder() {
47 DCHECK(media_task_runner_->BelongsToCurrentThread());
48 DVLOG(1) << "VideoDecoder::~VideoDecoder()";
49 ReleaseDecoderResources();
50 }
51
52 const char* VideoMediaCodecDecoder::class_name() const {
53 return "VideoDecoder";
54 }
55
56 bool VideoMediaCodecDecoder::HasStream() const {
57 DCHECK(media_task_runner_->BelongsToCurrentThread());
58
59 return configs_.video_codec != kUnknownVideoCodec;
60 }
61
62 void VideoMediaCodecDecoder::SetDemuxerConfigs(const DemuxerConfigs& configs) {
63 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << configs;
64
65 configs_ = configs;
66
67 if (video_size_.IsEmpty()) {
68 video_size_ = configs_.video_size;
69 media_task_runner_->PostTask(
70 FROM_HERE, base::Bind(video_size_changed_cb_, video_size_));
71 }
72 }
73
74 bool VideoMediaCodecDecoder::IsContentEncrypted() const {
75 // Make sure SetDemuxerConfigs() as been called.
76 DCHECK(configs_.video_codec != kUnknownVideoCodec);
77 return configs_.is_video_encrypted;
78 }
79
80 void VideoMediaCodecDecoder::ReleaseDecoderResources() {
81 DCHECK(media_task_runner_->BelongsToCurrentThread());
82 DVLOG(1) << class_name() << "::" << __FUNCTION__;
83
84 DoEmergencyStop();
85
86 ReleaseMediaCodec();
87
88 surface_ = gl::ScopedJavaSurface();
89 }
90
91 void VideoMediaCodecDecoder::ReleaseMediaCodec() {
92 DCHECK(media_task_runner_->BelongsToCurrentThread());
93
94 MediaCodecDecoder::ReleaseMediaCodec();
95 delayed_buffers_.clear();
96 }
97
98 void VideoMediaCodecDecoder::SetVideoSurface(gl::ScopedJavaSurface surface) {
99 DCHECK(media_task_runner_->BelongsToCurrentThread());
100
101 DVLOG(1) << class_name() << "::" << __FUNCTION__
102 << (surface.IsEmpty() ? " empty" : " non-empty");
103
104 surface_ = std::move(surface);
105
106 needs_reconfigure_ = true;
107 }
108
109 bool VideoMediaCodecDecoder::HasVideoSurface() const {
110 DCHECK(media_task_runner_->BelongsToCurrentThread());
111
112 return !surface_.IsEmpty();
113 }
114
115 void VideoMediaCodecDecoder::SetProtectedSurfaceRequired(bool value) {
116 DCHECK(media_task_runner_->BelongsToCurrentThread());
117
118 is_protected_surface_required_ = value;
119 }
120
121 bool VideoMediaCodecDecoder::IsProtectedSurfaceRequired() const {
122 DCHECK(media_task_runner_->BelongsToCurrentThread());
123
124 return is_protected_surface_required_;
125 }
126
127 bool VideoMediaCodecDecoder::IsCodecReconfigureNeeded(
128 const DemuxerConfigs& next) const {
129 if (always_reconfigure_for_tests_)
130 return true;
131
132 if (configs_.video_codec != next.video_codec ||
133 configs_.is_video_encrypted != next.is_video_encrypted) {
134 return true;
135 }
136
137 // Only size changes below this point
138
139 if (configs_.video_size.width() == next.video_size.width() &&
140 configs_.video_size.height() == next.video_size.height()) {
141 return false; // i.e. configs_ == next
142 }
143
144 return !static_cast<VideoCodecBridge*>(media_codec_bridge_.get())
145 ->IsAdaptivePlaybackSupported(next.video_size.width(),
146 next.video_size.height());
147 }
148
149 MediaCodecDecoder::ConfigStatus VideoMediaCodecDecoder::ConfigureInternal(
150 jobject media_crypto) {
151 DCHECK(media_task_runner_->BelongsToCurrentThread());
152
153 DVLOG(1) << class_name() << "::" << __FUNCTION__;
154
155 // If we cannot find a key frame in cache, the browser seek is needed.
156 if (!au_queue_.RewindToLastKeyFrame()) {
157 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " key frame required";
158 return kConfigKeyFrameRequired;
159 }
160
161 if (configs_.video_codec == kUnknownVideoCodec) {
162 DVLOG(0) << class_name() << "::" << __FUNCTION__
163 << ": configuration parameters are required";
164 return kConfigFailure;
165 }
166
167 if (surface_.IsEmpty()) {
168 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": surface is required";
169 return kConfigFailure;
170 }
171
172 bool is_secure = IsContentEncrypted() && is_protected_surface_required_;
173
174 media_codec_bridge_.reset(VideoCodecBridge::CreateDecoder(
175 configs_.video_codec, is_secure, configs_.video_size,
176 surface_.j_surface().obj(), media_crypto));
177
178 if (!media_codec_bridge_) {
179 DVLOG(0) << class_name() << "::" << __FUNCTION__
180 << " failed: cannot create video codec";
181 return kConfigFailure;
182 }
183
184 DVLOG(0) << class_name() << "::" << __FUNCTION__ << " succeeded";
185
186 if (!codec_created_for_tests_cb_.is_null())
187 media_task_runner_->PostTask(FROM_HERE, codec_created_for_tests_cb_);
188
189 return kConfigOk;
190 }
191
192 void VideoMediaCodecDecoder::AssociateCurrentTimeWithPTS(base::TimeDelta pts) {
193 DCHECK(media_task_runner_->BelongsToCurrentThread());
194
195 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " pts:" << pts;
196
197 start_time_ticks_ = base::TimeTicks::Now();
198 start_pts_ = pts;
199 last_seen_pts_ = pts;
200 }
201
202 void VideoMediaCodecDecoder::DissociatePTSFromTime() {
203 DCHECK(media_task_runner_->BelongsToCurrentThread());
204
205 start_pts_ = last_seen_pts_ = kNoTimestamp;
206 }
207
208 bool VideoMediaCodecDecoder::OnOutputFormatChanged() {
209 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
210
211 gfx::Size prev_size = video_size_;
212
213 // See b/18224769. The values reported from MediaCodecBridge::GetOutputSize
214 // correspond to the actual video frame size, but this is not necessarily the
215 // size that should be output.
216 video_size_ = configs_.video_size;
217 if (video_size_ != prev_size) {
218 media_task_runner_->PostTask(
219 FROM_HERE, base::Bind(video_size_changed_cb_, video_size_));
220 }
221 return true;
222 }
223
224 bool VideoMediaCodecDecoder::Render(int buffer_index,
225 size_t offset,
226 size_t size,
227 RenderMode render_mode,
228 base::TimeDelta pts,
229 bool eos_encountered) {
230 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
231
232 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts
233 << (eos_encountered ? " EOS " : " ") << AsString(render_mode);
234
235 // Normally EOS comes as a separate access unit that does not have data,
236 // the corresponding |size| will be 0.
237 if (!size && eos_encountered) {
238 // Stand-alone EOS
239 // Discard the PTS that comes with it and ensure it is released last.
240 pts = last_seen_pts_ +
241 base::TimeDelta::FromMilliseconds(kDelayForStandAloneEOS);
242 } else {
243 // Keep track of last seen PTS
244 last_seen_pts_ = pts;
245 }
246
247 // Do not update time for stand-alone EOS.
248 const bool update_time = !(eos_encountered && size == 0u);
249
250 // For video we simplify the preroll operation and render the first frame
251 // after preroll during the preroll phase, i.e. without waiting for audio
252 // stream to finish prerolling.
253 switch (render_mode) {
254 case kRenderSkip:
255 ReleaseOutputBuffer(buffer_index, pts, false, false, eos_encountered);
256 return true;
257 case kRenderAfterPreroll:
258 // We get here in the preroll phase. Render now as explained above.
259 // |start_pts_| is not set yet, thus we cannot calculate |time_to_render|.
260 ReleaseOutputBuffer(buffer_index, pts, (size > 0), update_time,
261 eos_encountered);
262 return true;
263 case kRenderNow:
264 break;
265 }
266
267 DCHECK_EQ(kRenderNow, render_mode);
268 DCHECK_NE(kNoTimestamp, start_pts_); // start_pts_ must be set
269
270 base::TimeDelta time_to_render =
271 pts - (base::TimeTicks::Now() - start_time_ticks_ + start_pts_);
272
273 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts
274 << " ticks delta:" << (base::TimeTicks::Now() - start_time_ticks_)
275 << " time_to_render:" << time_to_render;
276
277 const bool render = (size > 0);
278
279 if (render)
280 frame_statistics_->IncrementFrameCount();
281
282 if (time_to_render < base::TimeDelta()) {
283 if (render) {
284 DVLOG(2) << class_name() << "::" << __FUNCTION__
285 << " LATE FRAME delay:" << (-1) * time_to_render;
286
287 frame_statistics_->IncrementLateFrameCount();
288 }
289
290 // Render late frames immediately.
291 ReleaseOutputBuffer(buffer_index, pts, render, update_time,
292 eos_encountered);
293 return true;
294 }
295
296 delayed_buffers_.insert(buffer_index);
297
298 decoder_thread_.task_runner()->PostDelayedTask(
299 FROM_HERE, base::Bind(&VideoMediaCodecDecoder::ReleaseOutputBuffer,
300 base::Unretained(this), buffer_index, pts, render,
301 update_time, eos_encountered),
302 time_to_render);
303
304 return true;
305 }
306
307 int VideoMediaCodecDecoder::NumDelayedRenderTasks() const {
308 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
309
310 return delayed_buffers_.size();
311 }
312
313 void VideoMediaCodecDecoder::ReleaseDelayedBuffers() {
314 // Media thread
315 // Called when there is no decoder thread
316 for (int index : delayed_buffers_)
317 media_codec_bridge_->ReleaseOutputBuffer(index, false);
318
319 delayed_buffers_.clear();
320 }
321
322 #ifndef NDEBUG
323 void VideoMediaCodecDecoder::VerifyUnitIsKeyFrame(
324 const AccessUnit* unit) const {
325 // The first video frame in a sequence must be a key frame or stand-alone EOS.
326 DCHECK(unit);
327 bool stand_alone_eos = unit->is_end_of_stream && unit->data.empty();
328 DCHECK(stand_alone_eos || unit->is_key_frame);
329 }
330 #endif
331
332 void VideoMediaCodecDecoder::ReleaseOutputBuffer(int buffer_index,
333 base::TimeDelta pts,
334 bool render,
335 bool update_time,
336 bool eos_encountered) {
337 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
338
339 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts;
340
341 // Do not render if we are in emergency stop, there might be no surface.
342 if (InEmergencyStop())
343 render = false;
344
345 media_codec_bridge_->ReleaseOutputBuffer(buffer_index, render);
346
347 delayed_buffers_.erase(buffer_index);
348
349 CheckLastFrame(eos_encountered, !delayed_buffers_.empty());
350
351 // |update_current_time_cb_| might be null if there is audio stream.
352 // Do not update current time for stand-alone EOS frames.
353 if (!update_current_time_cb_.is_null() && update_time) {
354 media_task_runner_->PostTask(
355 FROM_HERE, base::Bind(update_current_time_cb_, pts, pts, false));
356 }
357 }
358
359 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/video_media_codec_decoder.h ('k') | media/base/media_switches.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698