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

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: 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 access_unit_size_(0) {
73 }
74
75 MediaSourceDelegate::~MediaSourceDelegate() {
76 DVLOG(1) << "MediaSourceDelegate::~MediaSourceDelegate() : " << player_id_;
77 DCHECK(!chunk_demuxer_);
78 DCHECK(!demuxer_);
79 }
80
81 void MediaSourceDelegate::Destroy() {
82 DVLOG(1) << "MediaSourceDelegate::Destroy() : " << player_id_;
83 if (!demuxer_) {
84 delete this;
85 return;
86 }
87
88 duration_change_cb_.Reset();
89 update_network_state_cb_.Reset();
90 media_source_.reset();
91 proxy_ = NULL;
92
93 demuxer_ = NULL;
94 if (chunk_demuxer_)
95 chunk_demuxer_->Stop(
96 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerStopDone));
97 }
98
99 void MediaSourceDelegate::InitializeMediaSource(
100 WebKit::WebMediaSource* media_source,
101 const media::NeedKeyCB& need_key_cb,
102 const UpdateNetworkStateCB& update_network_state_cb,
103 const DurationChangeCB& duration_change_cb) {
104 DCHECK(media_source);
105 media_source_.reset(media_source);
106 need_key_cb_ = need_key_cb;
107 update_network_state_cb_ = update_network_state_cb;
108 duration_change_cb_ = duration_change_cb;
109
110 chunk_demuxer_.reset(new media::ChunkDemuxer(
111 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerOpened),
112 BIND_TO_RENDER_LOOP_1(&MediaSourceDelegate::OnNeedKey, ""),
113 base::Bind(&MediaSourceDelegate::OnAddTextTrack,
114 base::Unretained(this)),
115 base::Bind(&LogMediaSourceError, media_log_)));
116 chunk_demuxer_->Initialize(this,
117 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone));
118 demuxer_ = chunk_demuxer_.get();
119 access_unit_size_ = kAccessUnitSizeForMediaSource;
120 }
121
122 #if defined(GOOGLE_TV)
123 void MediaSourceDelegate::InitializeMediaStream(
124 media::Demuxer* demuxer,
125 const UpdateNetworkStateCB& update_network_state_cb) {
126 DCHECK(demuxer);
127 demuxer_ = demuxer;
128 update_network_state_cb_ = update_network_state_cb;
129
130 demuxer_->Initialize(this,
131 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone));
132 // When playing Media Stream, don't wait to accumulate multiple packets per
133 // IPC communication.
134 access_unit_size_ = 1;
135 }
136 #endif
137
138 const WebKit::WebTimeRanges& MediaSourceDelegate::Buffered() {
139 buffered_web_time_ranges_ =
140 ConvertToWebTimeRanges(buffered_time_ranges_);
141 return buffered_web_time_ranges_;
142 }
143
144 size_t MediaSourceDelegate::DecodedFrameCount() const {
145 return statistics_.video_frames_decoded;
146 }
147
148 size_t MediaSourceDelegate::DroppedFrameCount() const {
149 return statistics_.video_frames_dropped;
150 }
151
152 size_t MediaSourceDelegate::AudioDecodedByteCount() const {
153 return statistics_.audio_bytes_decoded;
154 }
155
156 size_t MediaSourceDelegate::VideoDecodedByteCount() const {
157 return statistics_.video_bytes_decoded;
158 }
159
160 void MediaSourceDelegate::Seek(base::TimeDelta time) {
161 DVLOG(1) << "MediaSourceDelegate::Seek(" << time.InSecondsF() << ") : "
162 << player_id_;
163 seeking_ = true;
164 DCHECK(demuxer_);
165 if (chunk_demuxer_)
166 chunk_demuxer_->StartWaitingForSeek();
167 demuxer_->Seek(time,
168 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerError));
169 }
170
171 void MediaSourceDelegate::CancelPendingSeek() {
172 if (chunk_demuxer_)
173 chunk_demuxer_->CancelPendingSeek();
174 }
175
176 void MediaSourceDelegate::SetTotalBytes(int64 total_bytes) {
177 NOTIMPLEMENTED();
178 }
179
180 void MediaSourceDelegate::AddBufferedByteRange(int64 start, int64 end) {
181 NOTIMPLEMENTED();
182 }
183
184 void MediaSourceDelegate::AddBufferedTimeRange(base::TimeDelta start,
185 base::TimeDelta end) {
186 buffered_time_ranges_.Add(start, end);
187 }
188
189 void MediaSourceDelegate::SetDuration(base::TimeDelta duration) {
190 DVLOG(1) << "MediaSourceDelegate::SetDuration(" << duration.InSecondsF()
191 << ") : " << player_id_;
192 // Notify our owner (e.g. WebMediaPlayerAndroid) that
193 // duration has changed.
194 if (!duration_change_cb_.is_null())
195 duration_change_cb_.Run(duration);
196 }
197
198 void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type,
199 bool seek_done) {
200 DVLOG(1) << "MediaSourceDelegate::OnReadFromDemuxer(" << type
201 << ", " << seek_done << ") : " << player_id_;
202 if (seeking_ && !seek_done)
203 return; // Drop the request during seeking.
204 seeking_ = false;
205
206 DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO);
207 // The access unit size should have been initialized properly at this stage.
208 DCHECK_GT(access_unit_size_, 0u);
209 MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params =
210 type == DemuxerStream::AUDIO ? audio_params_.get() : video_params_.get();
211 params->type = type;
212 params->access_units.resize(access_unit_size_);
213 DemuxerStream* stream = demuxer_->GetStream(type);
214 DCHECK(stream != NULL);
215 ReadFromDemuxerStream(stream, params, 0);
216 }
217
218 void MediaSourceDelegate::ReadFromDemuxerStream(
219 DemuxerStream* stream,
220 MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
221 size_t index) {
222 stream->Read(BIND_TO_RENDER_LOOP_3(&MediaSourceDelegate::OnBufferReady,
223 stream, params, index));
224 }
225
226 void MediaSourceDelegate::OnBufferReady(
227 DemuxerStream* stream,
228 MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
229 size_t index,
230 DemuxerStream::Status status,
231 const scoped_refptr<media::DecoderBuffer>& buffer) {
232 DVLOG(1) << "MediaSourceDelegate::OnBufferReady() : " << player_id_;
233 DCHECK(status == DemuxerStream::kAborted ||
234 index < params->access_units.size());
235 bool is_audio = stream->type() == DemuxerStream::AUDIO;
236 if (status != DemuxerStream::kAborted &&
237 index >= params->access_units.size()) {
238 LOG(ERROR) << "The internal state inconsistency onBufferReady: "
239 << (is_audio ? "Audio" : "Video") << ", index " << index
240 <<", size " << params->access_units.size()
241 << ", status " << static_cast<int>(status);
242 return;
243 }
244 switch (status) {
245 case DemuxerStream::kAborted:
246 // Because the abort was caused by the seek, don't respond ack.
247 return;
248
249 case DemuxerStream::kConfigChanged:
250 // In case of kConfigChanged, need to read decoder_config once
251 // for the next reads.
252 if (is_audio) {
253 stream->audio_decoder_config();
254 } else {
255 gfx::Size size = stream->video_decoder_config().coded_size();
256 DVLOG(1) << "Video config is changed: " <<
257 size.width() << "x" << size.height();
258 }
259 params->access_units[index].status = status;
260 params->access_units.resize(index + 1);
261 break;
262
263 case DemuxerStream::kOk:
264 params->access_units[index].status = status;
265 if (buffer->IsEndOfStream()) {
266 params->access_units[index].end_of_stream = true;
267 params->access_units.resize(index + 1);
268 break;
269 }
270 // TODO(ycheo): We assume that the inputed stream will be decoded
271 // right away.
272 // Need to implement this properly using MediaPlayer.OnInfoListener.
273 if (is_audio) {
274 statistics_.audio_bytes_decoded += buffer->GetDataSize();
275 } else {
276 statistics_.video_bytes_decoded += buffer->GetDataSize();
277 statistics_.video_frames_decoded++;
278 }
279 params->access_units[index].timestamp = buffer->GetTimestamp();
280 params->access_units[index].data = std::vector<uint8>(
281 buffer->GetData(),
282 buffer->GetData() + buffer->GetDataSize());
283 #if !defined(GOOGLE_TV)
284 // Vorbis needs 4 extra bytes padding on Android. Check
285 // NuMediaExtractor.cpp in Android source code.
286 if (is_audio && media::kCodecVorbis ==
287 stream->audio_decoder_config().codec()) {
288 params->access_units[index].data.insert(
289 params->access_units[index].data.end(), kVorbisPadding,
290 kVorbisPadding + 4);
291 }
292 #endif
293 if (buffer->GetDecryptConfig()) {
294 params->access_units[index].key_id = std::vector<char>(
295 buffer->GetDecryptConfig()->key_id().begin(),
296 buffer->GetDecryptConfig()->key_id().end());
297 params->access_units[index].iv = std::vector<char>(
298 buffer->GetDecryptConfig()->iv().begin(),
299 buffer->GetDecryptConfig()->iv().end());
300 params->access_units[index].subsamples =
301 buffer->GetDecryptConfig()->subsamples();
302 }
303 if (++index < params->access_units.size()) {
304 ReadFromDemuxerStream(stream, params, index);
305 return;
306 }
307 break;
308
309 default:
310 NOTREACHED();
311 }
312
313 if (proxy_)
314 proxy_->ReadFromDemuxerAck(player_id_, *params);
315 params->access_units.resize(0);
316 }
317
318 void MediaSourceDelegate::OnDemuxerError(
319 media::PipelineStatus status) {
320 DVLOG(1) << "MediaSourceDelegate::OnDemuxerError(" << status << ") : "
321 << player_id_;
322 if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null())
323 update_network_state_cb_.Run(PipelineErrorToNetworkState(status));
324 }
325
326 void MediaSourceDelegate::OnDemuxerInitDone(
327 media::PipelineStatus status) {
328 DVLOG(1) << "MediaSourceDelegate::OnDemuxerInitDone(" << status << ") : "
329 << player_id_;
330 if (status != media::PIPELINE_OK) {
331 OnDemuxerError(status);
332 return;
333 }
334 NotifyDemuxerReady("");
335 }
336
337 void MediaSourceDelegate::OnDemuxerStopDone() {
338 DVLOG(1) << "MediaSourceDelegate::OnDemuxerStopDone() : " << player_id_;
339 chunk_demuxer_.reset();
340 delete this;
341 }
342
343 void MediaSourceDelegate::OnMediaConfigRequest() {
344 NotifyDemuxerReady("");
345 }
346
347 void MediaSourceDelegate::NotifyDemuxerReady(const std::string& key_system) {
348 if (!demuxer_)
349 return;
350 MediaPlayerHostMsg_DemuxerReady_Params params;
351 DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO);
352 if (audio_stream) {
353 const media::AudioDecoderConfig& config =
354 audio_stream->audio_decoder_config();
355 params.audio_codec = config.codec();
356 params.audio_channels =
357 media::ChannelLayoutToChannelCount(config.channel_layout());
358 params.audio_sampling_rate = config.samples_per_second();
359 params.is_audio_encrypted = config.is_encrypted();
360 params.audio_extra_data = std::vector<uint8>(
361 config.extra_data(), config.extra_data() + config.extra_data_size());
362 }
363 DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
364 if (video_stream) {
365 const media::VideoDecoderConfig& config =
366 video_stream->video_decoder_config();
367 params.video_codec = config.codec();
368 params.video_size = config.natural_size();
369 params.is_video_encrypted = config.is_encrypted();
370 params.video_extra_data = std::vector<uint8>(
371 config.extra_data(), config.extra_data() + config.extra_data_size());
372 }
373 params.duration_ms = GetDurationMs();
374 params.key_system = key_system;
375
376 bool ready_to_send = (!params.is_audio_encrypted &&
377 !params.is_video_encrypted) || !key_system.empty();
378 if (proxy_ && ready_to_send)
379 proxy_->DemuxerReady(player_id_, params);
380 }
381
382 int MediaSourceDelegate::GetDurationMs() {
383 if (!chunk_demuxer_)
384 return -1;
385
386 double duration_ms = chunk_demuxer_->GetDuration() * 1000;
387 if (duration_ms > std::numeric_limits<int32>::max()) {
388 LOG(WARNING) << "Duration from ChunkDemuxer is too large; probably "
389 "something has gone wrong.";
390 return std::numeric_limits<int32>::max();
391 }
392 return duration_ms;
393 }
394
395 void MediaSourceDelegate::OnDemuxerOpened() {
396 if (!media_source_)
397 return;
398
399 media_source_->open(new WebMediaSourceClientImpl(
400 chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_)));
401 }
402
403 void MediaSourceDelegate::OnNeedKey(const std::string& session_id,
404 const std::string& type,
405 scoped_ptr<uint8[]> init_data,
406 int init_data_size) {
407 if (need_key_cb_.is_null())
408 return;
409
410 need_key_cb_.Run(session_id, type, init_data.Pass(), init_data_size);
411 }
412
413 scoped_ptr<media::TextTrack> MediaSourceDelegate::OnAddTextTrack(
414 media::TextKind kind,
415 const std::string& label,
416 const std::string& language) {
417 return scoped_ptr<media::TextTrack>();
418 }
419
420 } // namespace webkit_media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698