| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/android/media_source_player.h" | 5 #include "media/base/android/media_source_player.h" |
| 6 | 6 |
| 7 #include "base/android/jni_android.h" | 7 #include "base/android/jni_android.h" |
| 8 #include "base/android/jni_string.h" | 8 #include "base/android/jni_string.h" |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 codec->Start(audio_codec, sample_rate, channel_count, extra_data, | 185 codec->Start(audio_codec, sample_rate, channel_count, extra_data, |
| 186 extra_data_size, true); | 186 extra_data_size, true); |
| 187 media_codec_bridge_.reset(codec.release()); | 187 media_codec_bridge_.reset(codec.release()); |
| 188 thread_.reset(new base::Thread("MediaSource_AudioDecoderThread")); | 188 thread_.reset(new base::Thread("MediaSource_AudioDecoderThread")); |
| 189 } | 189 } |
| 190 | 190 |
| 191 MediaSourcePlayer::MediaSourcePlayer( | 191 MediaSourcePlayer::MediaSourcePlayer( |
| 192 int player_id, | 192 int player_id, |
| 193 MediaPlayerManager* manager) | 193 MediaPlayerManager* manager) |
| 194 : MediaPlayerAndroid(player_id, manager), | 194 : MediaPlayerAndroid(player_id, manager), |
| 195 pending_play_(false), | 195 pending_event_(NO_EVENT_PENDING), |
| 196 active_decoding_tasks_(0), |
| 196 width_(0), | 197 width_(0), |
| 197 height_(0), | 198 height_(0), |
| 198 audio_codec_(kUnknownAudioCodec), | 199 audio_codec_(kUnknownAudioCodec), |
| 199 video_codec_(kUnknownVideoCodec), | 200 video_codec_(kUnknownVideoCodec), |
| 200 num_channels_(0), | 201 num_channels_(0), |
| 201 sampling_rate_(0), | 202 sampling_rate_(0), |
| 202 seekable_(true), | 203 seekable_(true), |
| 203 audio_finished_(true), | 204 audio_finished_(true), |
| 204 video_finished_(true), | 205 video_finished_(true), |
| 205 playing_(false), | 206 playing_(false), |
| 206 audio_access_unit_index_(0), | 207 audio_access_unit_index_(0), |
| 207 video_access_unit_index_(0), | 208 video_access_unit_index_(0), |
| 208 waiting_for_audio_data_(false), | 209 waiting_for_audio_data_(false), |
| 209 waiting_for_video_data_(false), | 210 waiting_for_video_data_(false), |
| 211 use_empty_surface_(true), |
| 210 weak_this_(this) { | 212 weak_this_(this) { |
| 211 } | 213 } |
| 212 | 214 |
| 213 MediaSourcePlayer::~MediaSourcePlayer() { | 215 MediaSourcePlayer::~MediaSourcePlayer() { |
| 214 Release(); | 216 Release(); |
| 215 } | 217 } |
| 216 | 218 |
| 217 void MediaSourcePlayer::SetVideoSurface(jobject surface) { | 219 void MediaSourcePlayer::SetVideoSurface(jobject surface) { |
| 218 video_decoder_job_.reset(); | 220 use_empty_surface_ = surface ? false : true; |
| 219 if (!surface) { | 221 |
| 222 // If we haven't processed a surface change event, do so now. |
| 223 if (active_decoding_tasks_ > 0) { |
| 224 pending_event_ |= SURFACE_CHANGE_EVENT_PENDING; |
| 225 // Request a seek so that the next decoder will decode an I-frame first. |
| 226 // Or otherwise, MediaCodec might crash. See b/8950387. |
| 227 pending_event_ |= SEEK_EVENT_PENDING; |
| 228 ProcessPendingEvents(); |
| 220 return; | 229 return; |
| 221 } | 230 } |
| 222 | 231 |
| 223 if (HasVideo()) { | 232 if (HasVideo()) { |
| 224 video_decoder_job_.reset(new VideoDecoderJob( | 233 video_decoder_job_.reset(new VideoDecoderJob( |
| 225 base::MessageLoopProxy::current(), video_codec_, | 234 base::MessageLoopProxy::current(), video_codec_, |
| 226 gfx::Size(width_, height_), surface)); | 235 gfx::Size(width_, height_), surface)); |
| 227 } | 236 } |
| 228 | 237 |
| 229 if (pending_play_) | |
| 230 StartInternal(); | |
| 231 | |
| 232 // Inform the fullscreen view the player is ready. | 238 // Inform the fullscreen view the player is ready. |
| 233 // TODO(qinmin): refactor MediaPlayerBridge so that we have a better way | 239 // TODO(qinmin): refactor MediaPlayerBridge so that we have a better way |
| 234 // to inform ContentVideoView. | 240 // to inform ContentVideoView. |
| 235 OnMediaMetadataChanged(duration_, width_, height_, true); | 241 OnMediaMetadataChanged(duration_, width_, height_, true); |
| 242 |
| 243 if (pending_event_ & SURFACE_CHANGE_EVENT_PENDING) { |
| 244 // We should already requested a seek in this case. |
| 245 pending_event_ &= ~SURFACE_CHANGE_EVENT_PENDING; |
| 246 } else { |
| 247 // Perform a seek so the new decoder can get the I-frame first. |
| 248 pending_event_ |= SEEK_EVENT_PENDING; |
| 249 ProcessPendingEvents(); |
| 250 return; |
| 251 } |
| 252 |
| 253 if (playing_) |
| 254 StartInternal(); |
| 236 } | 255 } |
| 237 | 256 |
| 238 void MediaSourcePlayer::Start() { | 257 void MediaSourcePlayer::Start() { |
| 258 playing_ = true; |
| 239 if (HasAudio() && !audio_decoder_job_) { | 259 if (HasAudio() && !audio_decoder_job_) { |
| 240 audio_decoder_job_.reset(new AudioDecoderJob( | 260 audio_decoder_job_.reset(new AudioDecoderJob( |
| 241 base::MessageLoopProxy::current(), audio_codec_, sampling_rate_, | 261 base::MessageLoopProxy::current(), audio_codec_, sampling_rate_, |
| 242 num_channels_, &audio_extra_data_[0], audio_extra_data_.size())); | 262 num_channels_, &audio_extra_data_[0], audio_extra_data_.size())); |
| 243 } | 263 } |
| 244 | 264 |
| 245 if (HasVideo() && !video_decoder_job_) { | 265 if (HasVideo() && !video_decoder_job_) { |
| 246 // StartInternal() will be delayed until SetVideoSurface() gets called. | 266 // StartInternal() will be delayed until SetVideoSurface() gets called. |
| 247 pending_play_ = true; | |
| 248 return; | 267 return; |
| 249 } | 268 } |
| 250 | 269 |
| 251 StartInternal(); | 270 StartInternal(); |
| 252 } | 271 } |
| 253 | 272 |
| 254 void MediaSourcePlayer::Pause() { | 273 void MediaSourcePlayer::Pause() { |
| 255 pending_play_ = false; | |
| 256 playing_ = false; | 274 playing_ = false; |
| 257 start_wallclock_time_ = base::Time(); | 275 start_wallclock_time_ = base::Time(); |
| 258 } | 276 } |
| 259 | 277 |
| 260 bool MediaSourcePlayer::IsPlaying() { | 278 bool MediaSourcePlayer::IsPlaying() { |
| 261 return pending_play_ || playing_; | 279 return playing_; |
| 262 } | 280 } |
| 263 | 281 |
| 264 int MediaSourcePlayer::GetVideoWidth() { | 282 int MediaSourcePlayer::GetVideoWidth() { |
| 265 return width_; | 283 return width_; |
| 266 } | 284 } |
| 267 | 285 |
| 268 int MediaSourcePlayer::GetVideoHeight() { | 286 int MediaSourcePlayer::GetVideoHeight() { |
| 269 return height_; | 287 return height_; |
| 270 } | 288 } |
| 271 | 289 |
| 272 void MediaSourcePlayer::SeekTo(base::TimeDelta timestamp) { | 290 void MediaSourcePlayer::SeekTo(base::TimeDelta timestamp) { |
| 273 last_presentation_timestamp_ = timestamp; | 291 last_presentation_timestamp_ = timestamp; |
| 274 start_wallclock_time_ = base::Time(); | 292 pending_event_ |= SEEK_EVENT_PENDING; |
| 275 last_seek_time_ = base::Time::Now(); | 293 ProcessPendingEvents(); |
| 276 if (audio_decoder_job_) | |
| 277 audio_decoder_job_->Flush(); | |
| 278 if (video_decoder_job_) | |
| 279 video_decoder_job_->Flush(); | |
| 280 received_audio_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); | |
| 281 received_video_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); | |
| 282 audio_access_unit_index_ = 0; | |
| 283 video_access_unit_index_ = 0; | |
| 284 OnSeekComplete(); | |
| 285 } | 294 } |
| 286 | 295 |
| 287 base::TimeDelta MediaSourcePlayer::GetCurrentTime() { | 296 base::TimeDelta MediaSourcePlayer::GetCurrentTime() { |
| 288 return last_presentation_timestamp_; | 297 return last_presentation_timestamp_; |
| 289 } | 298 } |
| 290 | 299 |
| 291 base::TimeDelta MediaSourcePlayer::GetDuration() { | 300 base::TimeDelta MediaSourcePlayer::GetDuration() { |
| 292 return duration_; | 301 return duration_; |
| 293 } | 302 } |
| 294 | 303 |
| 295 void MediaSourcePlayer::Release() { | 304 void MediaSourcePlayer::Release() { |
| 305 ClearDecodingData(); |
| 296 audio_decoder_job_.reset(); | 306 audio_decoder_job_.reset(); |
| 297 video_decoder_job_.reset(); | 307 video_decoder_job_.reset(); |
| 308 active_decoding_tasks_ = 0; |
| 309 playing_ = false; |
| 310 pending_event_ = NO_EVENT_PENDING; |
| 298 ReleaseMediaResourcesFromManager(); | 311 ReleaseMediaResourcesFromManager(); |
| 299 } | 312 } |
| 300 | 313 |
| 301 void MediaSourcePlayer::SetVolume(float leftVolume, float rightVolume) { | 314 void MediaSourcePlayer::SetVolume(float leftVolume, float rightVolume) { |
| 302 } | 315 } |
| 303 | 316 |
| 304 bool MediaSourcePlayer::CanPause() { | 317 bool MediaSourcePlayer::CanPause() { |
| 305 return seekable_; | 318 return seekable_; |
| 306 } | 319 } |
| 307 | 320 |
| 308 bool MediaSourcePlayer::CanSeekForward() { | 321 bool MediaSourcePlayer::CanSeekForward() { |
| 309 return seekable_; | 322 return seekable_; |
| 310 } | 323 } |
| 311 | 324 |
| 312 bool MediaSourcePlayer::CanSeekBackward() { | 325 bool MediaSourcePlayer::CanSeekBackward() { |
| 313 return seekable_; | 326 return seekable_; |
| 314 } | 327 } |
| 315 | 328 |
| 316 bool MediaSourcePlayer::IsPlayerReady() { | 329 bool MediaSourcePlayer::IsPlayerReady() { |
| 317 return audio_decoder_job_ || video_decoder_job_; | 330 return audio_decoder_job_ || video_decoder_job_; |
| 318 } | 331 } |
| 319 | 332 |
| 320 void MediaSourcePlayer::StartInternal() { | 333 void MediaSourcePlayer::StartInternal() { |
| 321 if (playing_) | 334 // Do nothing if the decoders are already running. |
| 335 if (active_decoding_tasks_ > 0 || pending_event_ != NO_EVENT_PENDING) |
| 322 return; | 336 return; |
| 323 playing_ = true; | |
| 324 | 337 |
| 325 if (HasAudio()) { | 338 if (HasAudio()) { |
| 326 audio_finished_ = false; | 339 audio_finished_ = false; |
| 327 DecodeMoreAudio(); | 340 DecodeMoreAudio(); |
| 328 } | 341 } |
| 329 if (HasVideo()) { | 342 if (HasVideo()) { |
| 330 video_finished_ = false; | 343 video_finished_ = false; |
| 331 DecodeMoreVideo(); | 344 DecodeMoreVideo(); |
| 332 } | 345 } |
| 333 } | 346 } |
| 334 | 347 |
| 335 void MediaSourcePlayer::DemuxerReady( | 348 void MediaSourcePlayer::DemuxerReady( |
| 336 const MediaPlayerHostMsg_DemuxerReady_Params& params) { | 349 const MediaPlayerHostMsg_DemuxerReady_Params& params) { |
| 337 if (params.duration_ms == std::numeric_limits<int>::max()) | 350 if (params.duration_ms == std::numeric_limits<int>::max()) |
| 338 seekable_ = false; | 351 seekable_ = false; |
| 339 duration_ = base::TimeDelta::FromMilliseconds(params.duration_ms); | 352 duration_ = base::TimeDelta::FromMilliseconds(params.duration_ms); |
| 340 width_ = params.video_size.width(); | 353 width_ = params.video_size.width(); |
| 341 height_ = params.video_size.height(); | 354 height_ = params.video_size.height(); |
| 342 num_channels_ = params.audio_channels; | 355 num_channels_ = params.audio_channels; |
| 343 sampling_rate_ = params.audio_sampling_rate; | 356 sampling_rate_ = params.audio_sampling_rate; |
| 344 audio_codec_ = params.audio_codec; | 357 audio_codec_ = params.audio_codec; |
| 345 video_codec_ = params.video_codec; | 358 video_codec_ = params.video_codec; |
| 346 audio_extra_data_ = params.audio_extra_data; | 359 audio_extra_data_ = params.audio_extra_data; |
| 347 OnMediaMetadataChanged(duration_, width_, height_, true); | 360 OnMediaMetadataChanged(duration_, width_, height_, true); |
| 348 } | 361 } |
| 349 | 362 |
| 350 void MediaSourcePlayer::ReadFromDemuxerAck( | 363 void MediaSourcePlayer::ReadFromDemuxerAck( |
| 351 const MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params) { | 364 const MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params) { |
| 365 if (params.type == DemuxerStream::AUDIO) |
| 366 waiting_for_audio_data_ = false; |
| 367 else |
| 368 waiting_for_video_data_ = false; |
| 369 |
| 370 // If there is a pending seek request, ignore the data from the chunk demuxer. |
| 371 // The data will be requested later when OnSeekRequestAck() is called. |
| 372 if (pending_event_ & SEEK_EVENT_PENDING) |
| 373 return; |
| 374 |
| 352 if (params.type == DemuxerStream::AUDIO) { | 375 if (params.type == DemuxerStream::AUDIO) { |
| 353 DCHECK_EQ(0u, audio_access_unit_index_); | 376 DCHECK_EQ(0u, audio_access_unit_index_); |
| 354 received_audio_ = params; | 377 received_audio_ = params; |
| 355 waiting_for_audio_data_ = false; | 378 if (!pending_event_) |
| 356 DecodeMoreAudio(); | 379 DecodeMoreAudio(); |
| 357 } else { | 380 } else { |
| 358 DCHECK_EQ(0u, video_access_unit_index_); | 381 DCHECK_EQ(0u, video_access_unit_index_); |
| 359 received_video_ = params; | 382 received_video_ = params; |
| 360 waiting_for_video_data_ = false; | 383 if (!pending_event_) |
| 361 DecodeMoreVideo(); | 384 DecodeMoreVideo(); |
| 362 } | 385 } |
| 363 } | 386 } |
| 364 | 387 |
| 388 void MediaSourcePlayer::OnSeekRequestAck() { |
| 389 pending_event_ &= ~SEEK_EVENT_PENDING; |
| 390 OnSeekComplete(); |
| 391 if (playing_) |
| 392 StartInternal(); |
| 393 } |
| 394 |
| 365 void MediaSourcePlayer::UpdateTimestamps( | 395 void MediaSourcePlayer::UpdateTimestamps( |
| 366 const base::Time& kickoff_time, | |
| 367 const base::TimeDelta& presentation_timestamp, | 396 const base::TimeDelta& presentation_timestamp, |
| 368 const base::Time& wallclock_time) { | 397 const base::Time& wallclock_time) { |
| 369 // If the job was posted after last seek, update the presentation time. | 398 last_presentation_timestamp_ = presentation_timestamp; |
| 370 // Otherwise, ignore it. | 399 OnTimeUpdated(); |
| 371 if (kickoff_time > last_seek_time_) { | 400 if (start_wallclock_time_.is_null() && playing_) { |
| 372 last_presentation_timestamp_ = presentation_timestamp; | 401 start_wallclock_time_ = wallclock_time; |
| 373 OnTimeUpdated(); | 402 start_presentation_timestamp_ = last_presentation_timestamp_; |
| 374 if (start_wallclock_time_.is_null() && playing_) { | |
| 375 start_wallclock_time_ = wallclock_time; | |
| 376 start_presentation_timestamp_ = last_presentation_timestamp_; | |
| 377 } | |
| 378 } | 403 } |
| 379 } | 404 } |
| 380 | 405 |
| 406 void MediaSourcePlayer::ProcessPendingEvents() { |
| 407 // Wait for all the decoding jobs to finish before sending a seek request. |
| 408 if (active_decoding_tasks_ > 0) |
| 409 return; |
| 410 |
| 411 DCHECK(pending_event_ != NO_EVENT_PENDING); |
| 412 if (use_empty_surface_ && (pending_event_ & SURFACE_CHANGE_EVENT_PENDING)) { |
| 413 video_decoder_job_.reset(); |
| 414 pending_event_ &= ~SURFACE_CHANGE_EVENT_PENDING; |
| 415 } |
| 416 |
| 417 ClearDecodingData(); |
| 418 manager()->OnMediaSeekRequest(player_id(), |
| 419 last_presentation_timestamp_, |
| 420 pending_event_ & SURFACE_CHANGE_EVENT_PENDING); |
| 421 } |
| 422 |
| 381 void MediaSourcePlayer::MediaDecoderCallback( | 423 void MediaSourcePlayer::MediaDecoderCallback( |
| 382 bool is_audio, const base::Time& kickoff_time, | 424 bool is_audio, const base::TimeDelta& presentation_timestamp, |
| 383 const base::TimeDelta& presentation_timestamp, | |
| 384 const base::Time& wallclock_time, bool end_of_stream) { | 425 const base::Time& wallclock_time, bool end_of_stream) { |
| 426 if (active_decoding_tasks_ > 0) |
| 427 active_decoding_tasks_--; |
| 428 |
| 429 if (pending_event_ != NO_EVENT_PENDING) { |
| 430 ProcessPendingEvents(); |
| 431 return; |
| 432 } |
| 433 |
| 385 if (is_audio || !HasAudio()) | 434 if (is_audio || !HasAudio()) |
| 386 UpdateTimestamps(kickoff_time, presentation_timestamp, wallclock_time); | 435 UpdateTimestamps(presentation_timestamp, wallclock_time); |
| 387 | 436 |
| 388 if (end_of_stream) { | 437 if (end_of_stream) { |
| 389 PlaybackCompleted(is_audio); | 438 PlaybackCompleted(is_audio); |
| 390 return; | 439 return; |
| 391 } | 440 } |
| 392 | 441 |
| 393 if (!playing_) | 442 if (!playing_) |
| 394 return; | 443 return; |
| 395 | 444 |
| 396 if (is_audio) | 445 if (is_audio) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 407 audio_access_unit_index_ = 0; | 456 audio_access_unit_index_ = 0; |
| 408 waiting_for_audio_data_ = true; | 457 waiting_for_audio_data_ = true; |
| 409 } | 458 } |
| 410 return; | 459 return; |
| 411 } | 460 } |
| 412 | 461 |
| 413 audio_decoder_job_->Decode( | 462 audio_decoder_job_->Decode( |
| 414 received_audio_.access_units[audio_access_unit_index_], | 463 received_audio_.access_units[audio_access_unit_index_], |
| 415 start_wallclock_time_, start_presentation_timestamp_, | 464 start_wallclock_time_, start_presentation_timestamp_, |
| 416 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, | 465 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, |
| 417 weak_this_.GetWeakPtr(), true, base::Time::Now())); | 466 weak_this_.GetWeakPtr(), true)); |
| 418 ++audio_access_unit_index_; | 467 active_decoding_tasks_++; |
| 468 audio_access_unit_index_++; |
| 419 } | 469 } |
| 420 | 470 |
| 421 void MediaSourcePlayer::DecodeMoreVideo() { | 471 void MediaSourcePlayer::DecodeMoreVideo() { |
| 422 if (video_access_unit_index_ >= received_video_.access_units.size()) { | 472 if (video_access_unit_index_ >= received_video_.access_units.size()) { |
| 423 if (!waiting_for_video_data_) { | 473 if (!waiting_for_video_data_) { |
| 424 manager()->OnReadFromDemuxer(player_id(), DemuxerStream::VIDEO, true); | 474 manager()->OnReadFromDemuxer(player_id(), DemuxerStream::VIDEO, true); |
| 425 received_video_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); | 475 received_video_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); |
| 426 video_access_unit_index_ = 0; | 476 video_access_unit_index_ = 0; |
| 427 waiting_for_video_data_ = true; | 477 waiting_for_video_data_ = true; |
| 428 } | 478 } |
| 429 return; | 479 return; |
| 430 } | 480 } |
| 431 | 481 |
| 432 video_decoder_job_->Decode( | 482 video_decoder_job_->Decode( |
| 433 received_video_.access_units[video_access_unit_index_], | 483 received_video_.access_units[video_access_unit_index_], |
| 434 start_wallclock_time_, start_presentation_timestamp_, | 484 start_wallclock_time_, start_presentation_timestamp_, |
| 435 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, | 485 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, |
| 436 weak_this_.GetWeakPtr(), false, base::Time::Now())); | 486 weak_this_.GetWeakPtr(), false)); |
| 437 ++video_access_unit_index_; | 487 active_decoding_tasks_++; |
| 488 video_access_unit_index_++; |
| 438 } | 489 } |
| 439 | 490 |
| 440 | 491 |
| 441 void MediaSourcePlayer::PlaybackCompleted(bool is_audio) { | 492 void MediaSourcePlayer::PlaybackCompleted(bool is_audio) { |
| 442 if (is_audio) | 493 if (is_audio) |
| 443 audio_finished_ = true; | 494 audio_finished_ = true; |
| 444 else | 495 else |
| 445 video_finished_ = true; | 496 video_finished_ = true; |
| 446 | 497 |
| 447 if ((!HasAudio() || audio_finished_) && (!HasVideo() || video_finished_)) { | 498 if ((!HasAudio() || audio_finished_) && (!HasVideo() || video_finished_)) { |
| 448 playing_ = false; | 499 playing_ = false; |
| 449 start_wallclock_time_ = base::Time(); | 500 start_wallclock_time_ = base::Time(); |
| 450 OnPlaybackComplete(); | 501 OnPlaybackComplete(); |
| 451 } | 502 } |
| 452 } | 503 } |
| 453 | 504 |
| 505 void MediaSourcePlayer::ClearDecodingData() { |
| 506 if (audio_decoder_job_) |
| 507 audio_decoder_job_->Flush(); |
| 508 if (video_decoder_job_) |
| 509 video_decoder_job_->Flush(); |
| 510 start_wallclock_time_ = base::Time(); |
| 511 received_audio_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); |
| 512 received_video_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); |
| 513 audio_access_unit_index_ = 0; |
| 514 video_access_unit_index_ = 0; |
| 515 } |
| 516 |
| 454 bool MediaSourcePlayer::HasVideo() { | 517 bool MediaSourcePlayer::HasVideo() { |
| 455 return kUnknownVideoCodec != video_codec_; | 518 return kUnknownVideoCodec != video_codec_; |
| 456 } | 519 } |
| 457 | 520 |
| 458 bool MediaSourcePlayer::HasAudio() { | 521 bool MediaSourcePlayer::HasAudio() { |
| 459 return kUnknownAudioCodec != audio_codec_; | 522 return kUnknownAudioCodec != audio_codec_; |
| 460 } | 523 } |
| 461 | 524 |
| 462 } // namespace media | 525 } // namespace media |
| OLD | NEW |