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

Side by Side Diff: webkit/renderer/media/android/media_source_delegate.cc

Issue 17502007: Move webkit/renderer/media/android/ to content/renderer/media/android/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix shared lib Created 7 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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 "webkit/renderer/media/android/media_source_delegate.h"
6
7 #include "base/message_loop/message_loop_proxy.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "media/base/android/demuxer_stream_player_params.h"
10 #include "media/base/bind_to_loop.h"
11 #include "media/base/demuxer_stream.h"
12 #include "media/base/media_log.h"
13 #include "media/filters/chunk_demuxer.h"
14 #include "third_party/WebKit/public/platform/WebString.h"
15 #include "third_party/WebKit/public/web/WebMediaSource.h"
16 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
17 #include "webkit/renderer/media/android/webmediaplayer_proxy_android.h"
18 #include "webkit/renderer/media/webmediaplayer_util.h"
19 #include "webkit/renderer/media/webmediasourceclient_impl.h"
20
21 using media::DemuxerStream;
22 using media::MediaPlayerHostMsg_DemuxerReady_Params;
23 using media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params;
24 using WebKit::WebMediaPlayer;
25 using WebKit::WebString;
26
27 namespace {
28
29 // The size of the access unit to transfer in an IPC in case of MediaSource.
30 // 16: approximately 250ms of content in 60 fps movies.
31 const size_t kAccessUnitSizeForMediaSource = 16;
32
33 const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff };
34
35 } // namespace
36
37 namespace webkit_media {
38
39 #define BIND_TO_RENDER_LOOP(function) \
40 media::BindToLoop(base::MessageLoopProxy::current(), \
41 base::Bind(function, weak_this_.GetWeakPtr()))
42
43 #define BIND_TO_RENDER_LOOP_1(function, arg1) \
44 media::BindToLoop(base::MessageLoopProxy::current(), \
45 base::Bind(function, weak_this_.GetWeakPtr(), arg1))
46
47 #define BIND_TO_RENDER_LOOP_2(function, arg1, arg2) \
48 media::BindToLoop(base::MessageLoopProxy::current(), \
49 base::Bind(function, weak_this_.GetWeakPtr(), arg1, arg2))
50
51 #define BIND_TO_RENDER_LOOP_3(function, arg1, arg2, arg3) \
52 media::BindToLoop(base::MessageLoopProxy::current(), \
53 base::Bind(function, \
54 weak_this_.GetWeakPtr(), arg1, arg2, arg3))
55
56 static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log,
57 const std::string& error) {
58 media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
59 }
60
61 MediaSourceDelegate::MediaSourceDelegate(WebMediaPlayerProxyAndroid* proxy,
62 int player_id,
63 media::MediaLog* media_log)
64 : weak_this_(this),
65 proxy_(proxy),
66 player_id_(player_id),
67 media_log_(media_log),
68 demuxer_(NULL),
69 audio_params_(new MediaPlayerHostMsg_ReadFromDemuxerAck_Params),
70 video_params_(new MediaPlayerHostMsg_ReadFromDemuxerAck_Params),
71 seeking_(false),
72 key_added_(false),
73 access_unit_size_(0) {
74 }
75
76 MediaSourceDelegate::~MediaSourceDelegate() {
77 DVLOG(1) << "MediaSourceDelegate::~MediaSourceDelegate() : " << player_id_;
78 DCHECK(!chunk_demuxer_);
79 DCHECK(!demuxer_);
80 }
81
82 void MediaSourceDelegate::Destroy() {
83 DVLOG(1) << "MediaSourceDelegate::Destroy() : " << player_id_;
84 if (!demuxer_) {
85 delete this;
86 return;
87 }
88
89 duration_change_cb_.Reset();
90 update_network_state_cb_.Reset();
91 media_source_.reset();
92 proxy_ = NULL;
93
94 demuxer_ = NULL;
95 if (chunk_demuxer_)
96 chunk_demuxer_->Stop(
97 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerStopDone));
98 }
99
100 void MediaSourceDelegate::InitializeMediaSource(
101 WebKit::WebMediaSource* media_source,
102 const media::NeedKeyCB& need_key_cb,
103 const UpdateNetworkStateCB& update_network_state_cb,
104 const DurationChangeCB& duration_change_cb) {
105 DCHECK(media_source);
106 media_source_.reset(media_source);
107 need_key_cb_ = need_key_cb;
108 update_network_state_cb_ = update_network_state_cb;
109 duration_change_cb_ = duration_change_cb;
110
111 chunk_demuxer_.reset(new media::ChunkDemuxer(
112 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerOpened),
113 BIND_TO_RENDER_LOOP_1(&MediaSourceDelegate::OnNeedKey, ""),
114 base::Bind(&MediaSourceDelegate::OnAddTextTrack,
115 base::Unretained(this)),
116 base::Bind(&LogMediaSourceError, media_log_)));
117 chunk_demuxer_->Initialize(this,
118 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone));
119 demuxer_ = chunk_demuxer_.get();
120 access_unit_size_ = kAccessUnitSizeForMediaSource;
121 }
122
123 #if defined(GOOGLE_TV)
124 void MediaSourceDelegate::InitializeMediaStream(
125 media::Demuxer* demuxer,
126 const UpdateNetworkStateCB& update_network_state_cb) {
127 DCHECK(demuxer);
128 demuxer_ = demuxer;
129 update_network_state_cb_ = update_network_state_cb;
130
131 demuxer_->Initialize(this,
132 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone));
133 // When playing Media Stream, don't wait to accumulate multiple packets per
134 // IPC communication.
135 access_unit_size_ = 1;
136 }
137 #endif
138
139 const WebKit::WebTimeRanges& MediaSourceDelegate::Buffered() {
140 buffered_web_time_ranges_ =
141 ConvertToWebTimeRanges(buffered_time_ranges_);
142 return buffered_web_time_ranges_;
143 }
144
145 size_t MediaSourceDelegate::DecodedFrameCount() const {
146 return statistics_.video_frames_decoded;
147 }
148
149 size_t MediaSourceDelegate::DroppedFrameCount() const {
150 return statistics_.video_frames_dropped;
151 }
152
153 size_t MediaSourceDelegate::AudioDecodedByteCount() const {
154 return statistics_.audio_bytes_decoded;
155 }
156
157 size_t MediaSourceDelegate::VideoDecodedByteCount() const {
158 return statistics_.video_bytes_decoded;
159 }
160
161 void MediaSourceDelegate::Seek(base::TimeDelta time) {
162 DVLOG(1) << "MediaSourceDelegate::Seek(" << time.InSecondsF() << ") : "
163 << player_id_;
164 seeking_ = true;
165 DCHECK(demuxer_);
166 if (chunk_demuxer_)
167 chunk_demuxer_->StartWaitingForSeek();
168 demuxer_->Seek(time,
169 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerError));
170 }
171
172 void MediaSourceDelegate::CancelPendingSeek() {
173 if (chunk_demuxer_)
174 chunk_demuxer_->CancelPendingSeek();
175 }
176
177 void MediaSourceDelegate::SetTotalBytes(int64 total_bytes) {
178 NOTIMPLEMENTED();
179 }
180
181 void MediaSourceDelegate::AddBufferedByteRange(int64 start, int64 end) {
182 NOTIMPLEMENTED();
183 }
184
185 void MediaSourceDelegate::AddBufferedTimeRange(base::TimeDelta start,
186 base::TimeDelta end) {
187 buffered_time_ranges_.Add(start, end);
188 }
189
190 void MediaSourceDelegate::SetDuration(base::TimeDelta duration) {
191 DVLOG(1) << "MediaSourceDelegate::SetDuration(" << duration.InSecondsF()
192 << ") : " << player_id_;
193 // Notify our owner (e.g. WebMediaPlayerAndroid) that
194 // duration has changed.
195 if (!duration_change_cb_.is_null())
196 duration_change_cb_.Run(duration);
197 }
198
199 void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type,
200 bool seek_done) {
201 DVLOG(1) << "MediaSourceDelegate::OnReadFromDemuxer(" << type
202 << ", " << seek_done << ") : " << player_id_;
203 if (seeking_ && !seek_done)
204 return; // Drop the request during seeking.
205 seeking_ = false;
206
207 DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO);
208 // The access unit size should have been initialized properly at this stage.
209 DCHECK_GT(access_unit_size_, 0u);
210 MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params =
211 type == DemuxerStream::AUDIO ? audio_params_.get() : video_params_.get();
212 params->type = type;
213 params->access_units.resize(access_unit_size_);
214 DemuxerStream* stream = demuxer_->GetStream(type);
215 DCHECK(stream != NULL);
216 ReadFromDemuxerStream(stream, params, 0);
217 }
218
219 void MediaSourceDelegate::ReadFromDemuxerStream(
220 DemuxerStream* stream,
221 MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
222 size_t index) {
223 stream->Read(BIND_TO_RENDER_LOOP_3(&MediaSourceDelegate::OnBufferReady,
224 stream, params, index));
225 }
226
227 void MediaSourceDelegate::OnBufferReady(
228 DemuxerStream* stream,
229 MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
230 size_t index,
231 DemuxerStream::Status status,
232 const scoped_refptr<media::DecoderBuffer>& buffer) {
233 DVLOG(1) << "MediaSourceDelegate::OnBufferReady() : " << player_id_;
234 DCHECK(status == DemuxerStream::kAborted ||
235 index < params->access_units.size());
236 bool is_audio = stream->type() == DemuxerStream::AUDIO;
237 if (status != DemuxerStream::kAborted &&
238 index >= params->access_units.size()) {
239 LOG(ERROR) << "The internal state inconsistency onBufferReady: "
240 << (is_audio ? "Audio" : "Video") << ", index " << index
241 <<", size " << params->access_units.size()
242 << ", status " << static_cast<int>(status);
243 return;
244 }
245 switch (status) {
246 case DemuxerStream::kAborted:
247 // Because the abort was caused by the seek, don't respond ack.
248 return;
249
250 case DemuxerStream::kConfigChanged:
251 // In case of kConfigChanged, need to read decoder_config once
252 // for the next reads.
253 if (is_audio) {
254 stream->audio_decoder_config();
255 } else {
256 gfx::Size size = stream->video_decoder_config().coded_size();
257 DVLOG(1) << "Video config is changed: " <<
258 size.width() << "x" << size.height();
259 }
260 params->access_units[index].status = status;
261 params->access_units.resize(index + 1);
262 break;
263
264 case DemuxerStream::kOk:
265 params->access_units[index].status = status;
266 if (buffer->IsEndOfStream()) {
267 params->access_units[index].end_of_stream = true;
268 params->access_units.resize(index + 1);
269 break;
270 }
271 // TODO(ycheo): We assume that the inputed stream will be decoded
272 // right away.
273 // Need to implement this properly using MediaPlayer.OnInfoListener.
274 if (is_audio) {
275 statistics_.audio_bytes_decoded += buffer->GetDataSize();
276 } else {
277 statistics_.video_bytes_decoded += buffer->GetDataSize();
278 statistics_.video_frames_decoded++;
279 }
280 params->access_units[index].timestamp = buffer->GetTimestamp();
281 params->access_units[index].data = std::vector<uint8>(
282 buffer->GetData(),
283 buffer->GetData() + buffer->GetDataSize());
284 #if !defined(GOOGLE_TV)
285 // Vorbis needs 4 extra bytes padding on Android. Check
286 // NuMediaExtractor.cpp in Android source code.
287 if (is_audio && media::kCodecVorbis ==
288 stream->audio_decoder_config().codec()) {
289 params->access_units[index].data.insert(
290 params->access_units[index].data.end(), kVorbisPadding,
291 kVorbisPadding + 4);
292 }
293 #endif
294 if (buffer->GetDecryptConfig()) {
295 params->access_units[index].key_id = std::vector<char>(
296 buffer->GetDecryptConfig()->key_id().begin(),
297 buffer->GetDecryptConfig()->key_id().end());
298 params->access_units[index].iv = std::vector<char>(
299 buffer->GetDecryptConfig()->iv().begin(),
300 buffer->GetDecryptConfig()->iv().end());
301 params->access_units[index].subsamples =
302 buffer->GetDecryptConfig()->subsamples();
303 }
304 if (++index < params->access_units.size()) {
305 ReadFromDemuxerStream(stream, params, index);
306 return;
307 }
308 break;
309
310 default:
311 NOTREACHED();
312 }
313
314 if (proxy_)
315 proxy_->ReadFromDemuxerAck(player_id_, *params);
316 params->access_units.resize(0);
317 }
318
319 void MediaSourceDelegate::OnDemuxerError(
320 media::PipelineStatus status) {
321 DVLOG(1) << "MediaSourceDelegate::OnDemuxerError(" << status << ") : "
322 << player_id_;
323 if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null())
324 update_network_state_cb_.Run(PipelineErrorToNetworkState(status));
325 }
326
327 void MediaSourceDelegate::OnDemuxerInitDone(
328 media::PipelineStatus status) {
329 DVLOG(1) << "MediaSourceDelegate::OnDemuxerInitDone(" << status << ") : "
330 << player_id_;
331 if (status != media::PIPELINE_OK) {
332 OnDemuxerError(status);
333 return;
334 }
335 if (CanNotifyDemuxerReady())
336 NotifyDemuxerReady("");
337 }
338
339 void MediaSourceDelegate::OnDemuxerStopDone() {
340 DVLOG(1) << "MediaSourceDelegate::OnDemuxerStopDone() : " << player_id_;
341 chunk_demuxer_.reset();
342 delete this;
343 }
344
345 void MediaSourceDelegate::OnMediaConfigRequest() {
346 if (CanNotifyDemuxerReady())
347 NotifyDemuxerReady("");
348 }
349
350 void MediaSourceDelegate::NotifyKeyAdded(const std::string& key_system) {
351 // TODO(kjyoun): Enhance logic to detect when to call NotifyDemuxerReady()
352 // For now, we calls it when the first key is added.
353 if (key_added_)
354 return;
355 key_added_ = true;
356 if (CanNotifyDemuxerReady())
357 NotifyDemuxerReady(key_system);
358 }
359
360 bool MediaSourceDelegate::CanNotifyDemuxerReady() {
361 if (key_added_)
362 return true;
363 DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO);
364 if (audio_stream && audio_stream->audio_decoder_config().is_encrypted())
365 return false;
366 DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
367 if (video_stream && video_stream->video_decoder_config().is_encrypted())
368 return false;
369 return true;
370 }
371
372 void MediaSourceDelegate::NotifyDemuxerReady(const std::string& key_system) {
373 DCHECK(demuxer_);
374 MediaPlayerHostMsg_DemuxerReady_Params params;
375 DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO);
376 if (audio_stream) {
377 const media::AudioDecoderConfig& config =
378 audio_stream->audio_decoder_config();
379 params.audio_codec = config.codec();
380 params.audio_channels =
381 media::ChannelLayoutToChannelCount(config.channel_layout());
382 params.audio_sampling_rate = config.samples_per_second();
383 params.is_audio_encrypted = config.is_encrypted();
384 params.audio_extra_data = std::vector<uint8>(
385 config.extra_data(), config.extra_data() + config.extra_data_size());
386 }
387 DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
388 if (video_stream) {
389 const media::VideoDecoderConfig& config =
390 video_stream->video_decoder_config();
391 params.video_codec = config.codec();
392 params.video_size = config.natural_size();
393 params.is_video_encrypted = config.is_encrypted();
394 params.video_extra_data = std::vector<uint8>(
395 config.extra_data(), config.extra_data() + config.extra_data_size());
396 }
397 params.duration_ms = GetDurationMs();
398 params.key_system = key_system;
399
400 if (proxy_)
401 proxy_->DemuxerReady(player_id_, params);
402 }
403
404 int MediaSourceDelegate::GetDurationMs() {
405 if (!chunk_demuxer_)
406 return -1;
407
408 double duration_ms = chunk_demuxer_->GetDuration() * 1000;
409 if (duration_ms > std::numeric_limits<int32>::max()) {
410 LOG(WARNING) << "Duration from ChunkDemuxer is too large; probably "
411 "something has gone wrong.";
412 return std::numeric_limits<int32>::max();
413 }
414 return duration_ms;
415 }
416
417 void MediaSourceDelegate::OnDemuxerOpened() {
418 if (!media_source_)
419 return;
420
421 media_source_->open(new WebMediaSourceClientImpl(
422 chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_)));
423 }
424
425 void MediaSourceDelegate::OnNeedKey(const std::string& session_id,
426 const std::string& type,
427 scoped_ptr<uint8[]> init_data,
428 int init_data_size) {
429 if (need_key_cb_.is_null())
430 return;
431
432 need_key_cb_.Run(session_id, type, init_data.Pass(), init_data_size);
433 }
434
435 scoped_ptr<media::TextTrack> MediaSourceDelegate::OnAddTextTrack(
436 media::TextKind kind,
437 const std::string& label,
438 const std::string& language) {
439 return scoped_ptr<media::TextTrack>();
440 }
441
442 } // namespace webkit_media
OLDNEW
« no previous file with comments | « webkit/renderer/media/android/media_source_delegate.h ('k') | webkit/renderer/media/android/proxy_media_keys.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698