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

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

Issue 1194423008: Revert of Audio and video decoders for MediaCodecPlayer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 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
« no previous file with comments | « media/base/android/media_codec_video_decoder.h ('k') | media/base/android/test_data_factory.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/media_codec_video_decoder.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "media/base/android/media_codec_bridge.h"
10 #include "media/base/buffers.h"
11 #include "media/base/demuxer_stream.h"
12
13 namespace media {
14
15 namespace {
16 const int kDelayForStandAloneEOS = 2; // milliseconds
17 }
18
19 MediaCodecVideoDecoder::MediaCodecVideoDecoder(
20 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
21 const base::Closure& request_data_cb,
22 const base::Closure& starvation_cb,
23 const base::Closure& stop_done_cb,
24 const base::Closure& error_cb,
25 const SetTimeCallback& update_current_time_cb,
26 const VideoSizeChangedCallback& video_size_changed_cb,
27 const base::Closure& codec_created_cb)
28 : MediaCodecDecoder(media_task_runner,
29 request_data_cb,
30 starvation_cb,
31 stop_done_cb,
32 error_cb,
33 "VideoDecoder"),
34 update_current_time_cb_(update_current_time_cb),
35 video_size_changed_cb_(video_size_changed_cb),
36 codec_created_cb_(codec_created_cb) {
37 }
38
39 MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
40 DVLOG(1) << "VideoDecoder::~VideoDecoder()";
41 }
42
43 const char* MediaCodecVideoDecoder::class_name() const {
44 return "VideoDecoder";
45 }
46
47 bool MediaCodecVideoDecoder::HasStream() const {
48 DCHECK(media_task_runner_->BelongsToCurrentThread());
49
50 return configs_.video_codec != kUnknownVideoCodec;
51 }
52
53 void MediaCodecVideoDecoder::SetDemuxerConfigs(const DemuxerConfigs& configs) {
54 DCHECK(media_task_runner_->BelongsToCurrentThread());
55
56 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << configs;
57
58 configs_ = configs;
59
60 if (video_size_.IsEmpty()) {
61 video_size_ = configs_.video_size;
62 media_task_runner_->PostTask(
63 FROM_HERE, base::Bind(video_size_changed_cb_, video_size_));
64 }
65 }
66
67 void MediaCodecVideoDecoder::ReleaseDecoderResources() {
68 DCHECK(media_task_runner_->BelongsToCurrentThread());
69
70 DVLOG(1) << class_name() << "::" << __FUNCTION__;
71
72 MediaCodecDecoder::ReleaseDecoderResources();
73 surface_ = gfx::ScopedJavaSurface();
74 delayed_buffers_.clear();
75 }
76
77 void MediaCodecVideoDecoder::SetPendingSurface(gfx::ScopedJavaSurface surface) {
78 DCHECK(media_task_runner_->BelongsToCurrentThread());
79
80 surface_ = surface.Pass();
81
82 if (surface_.IsEmpty()) {
83 // Synchronously stop decoder thread and release MediaCodec
84 ReleaseDecoderResources();
85 }
86 }
87
88 bool MediaCodecVideoDecoder::HasPendingSurface() const {
89 DCHECK(media_task_runner_->BelongsToCurrentThread());
90
91 return !surface_.IsEmpty();
92 }
93
94 bool MediaCodecVideoDecoder::IsCodecReconfigureNeeded(
95 const DemuxerConfigs& curr,
96 const DemuxerConfigs& next) const {
97 if (curr.video_codec != next.video_codec ||
98 curr.is_video_encrypted != next.is_video_encrypted) {
99 return true;
100 }
101
102 // Only size changes below this point
103
104 if (curr.video_size.width() == next.video_size.width() &&
105 curr.video_size.height() == next.video_size.height()) {
106 return false; // i.e. curr == next
107 }
108
109 return !static_cast<VideoCodecBridge*>(media_codec_bridge_.get())
110 ->IsAdaptivePlaybackSupported(next.video_size.width(),
111 next.video_size.height());
112 }
113
114 MediaCodecDecoder::ConfigStatus MediaCodecVideoDecoder::ConfigureInternal() {
115 DCHECK(media_task_runner_->BelongsToCurrentThread());
116
117 DVLOG(1) << class_name() << "::" << __FUNCTION__;
118
119 // If we cannot find a key frame in cache, the browser seek is needed.
120 if (!au_queue_.RewindToLastKeyFrame()) {
121 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " key frame required";
122
123 // The processing of CONFIG_KEY_FRAME_REQUIRED is not implemented yet,
124 // return error for now.
125 // TODO(timav): Replace this with the following line together with
126 // implementing the browser seek:
127 // return CONFIG_KEY_FRAME_REQUIRED;
128 return CONFIG_FAILURE;
129 }
130
131 // TODO(timav): implement DRM.
132 // bool is_secure = is_content_encrypted() && drm_bridge() &&
133 // drm_bridge()->IsProtectedSurfaceRequired();
134
135 bool is_secure = false; // DRM is not implemented
136
137 if (surface_.IsEmpty()) {
138 DVLOG(0) << class_name() << "::" << __FUNCTION__ << " surface required";
139 return CONFIG_FAILURE;
140 }
141
142 media_codec_bridge_.reset(VideoCodecBridge::CreateDecoder(
143 configs_.video_codec,
144 is_secure,
145 configs_.video_size,
146 surface_.j_surface().obj(),
147 GetMediaCrypto().obj()));
148
149 if (!media_codec_bridge_) {
150 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " failed";
151 return CONFIG_FAILURE;
152 }
153
154 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " succeeded";
155
156 media_task_runner_->PostTask(FROM_HERE, codec_created_cb_);
157
158 return CONFIG_OK;
159 }
160
161 void MediaCodecVideoDecoder::SynchronizePTSWithTime(
162 base::TimeDelta current_time) {
163 DCHECK(media_task_runner_->BelongsToCurrentThread());
164
165 start_time_ticks_ = base::TimeTicks::Now();
166 start_pts_ = current_time;
167 last_seen_pts_ = current_time;
168 }
169
170 void MediaCodecVideoDecoder::OnOutputFormatChanged() {
171 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
172
173 gfx::Size prev_size = video_size_;
174
175 // See b/18224769. The values reported from MediaCodecBridge::GetOutputFormat
176 // correspond to the actual video frame size, but this is not necessarily the
177 // size that should be output.
178 video_size_ = configs_.video_size;
179 if (video_size_ != prev_size) {
180 media_task_runner_->PostTask(
181 FROM_HERE, base::Bind(video_size_changed_cb_, video_size_));
182 }
183 }
184
185 void MediaCodecVideoDecoder::Render(int buffer_index,
186 size_t size,
187 bool render_output,
188 base::TimeDelta pts,
189 bool eos_encountered) {
190 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
191
192 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts
193 << " index:" << buffer_index << (eos_encountered ? " EOS" : "");
194
195 // Normally EOS comes as a separate access unit that does not have data,
196 // the corresponding |size| will be 0.
197 if (!size && eos_encountered) {
198 // Stand-alone EOS
199 // Discard the PTS that comes with it and ensure it is released last.
200 pts = last_seen_pts_ +
201 base::TimeDelta::FromMilliseconds(kDelayForStandAloneEOS);
202 } else {
203 // Keep track of last seen PTS
204 last_seen_pts_ = pts;
205 }
206
207 if (!render_output) {
208 ReleaseOutputBuffer(buffer_index, pts, false, eos_encountered);
209 return;
210 }
211
212 base::TimeDelta time_to_render =
213 pts - (base::TimeTicks::Now() - start_time_ticks_ + start_pts_);
214
215 if (time_to_render < base::TimeDelta()) {
216 // Skip late frames
217 ReleaseOutputBuffer(buffer_index, pts, false, eos_encountered);
218 return;
219 }
220
221 delayed_buffers_.insert(buffer_index);
222
223 bool do_render = size > 0;
224 decoder_thread_.task_runner()->PostDelayedTask(
225 FROM_HERE, base::Bind(&MediaCodecVideoDecoder::ReleaseOutputBuffer,
226 base::Unretained(this), buffer_index, pts,
227 do_render, eos_encountered),
228 time_to_render);
229 }
230
231 int MediaCodecVideoDecoder::NumDelayedRenderTasks() const {
232 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
233
234 return delayed_buffers_.size();
235 }
236
237 void MediaCodecVideoDecoder::ReleaseDelayedBuffers() {
238 // Media thread
239 // Called when there is no decoder thread
240 for (int index : delayed_buffers_)
241 media_codec_bridge_->ReleaseOutputBuffer(index, false);
242 delayed_buffers_.clear();
243 }
244
245 void MediaCodecVideoDecoder::ReleaseOutputBuffer(int buffer_index,
246 base::TimeDelta pts,
247 bool render,
248 bool eos_encountered) {
249 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
250
251 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts;
252
253 media_codec_bridge_->ReleaseOutputBuffer(buffer_index, render);
254
255 delayed_buffers_.erase(buffer_index);
256
257 CheckLastFrame(eos_encountered, !delayed_buffers_.empty());
258
259 // |update_current_time_cb_| might be null if there is audio stream.
260 // Do not update current time for EOS frames.
261 if (!update_current_time_cb_.is_null() && !eos_encountered) {
262 media_task_runner_->PostTask(FROM_HERE,
263 base::Bind(update_current_time_cb_, pts, pts));
264 }
265 }
266
267 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/media_codec_video_decoder.h ('k') | media/base/android/test_data_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698