media_source_delegate.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/renderer/media/android/media_source_delegate.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <limits> 858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <string> 958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <vector> 1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "content/renderer/media/android/renderer_demuxer_android.h" 147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "content/renderer/media/webmediaplayer_util.h" 153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/renderer/media/webmediasource_impl.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "media/base/android/demuxer_stream_player_params.h" 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/base/bind_to_current_loop.h" 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "media/base/demuxer_stream.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "media/base/media_log.h" 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "media/filters/chunk_demuxer.h" 21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "media/filters/decrypting_demuxer_stream.h" 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebString.h" 237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using media::DemuxerStream; 26424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using media::DemuxerConfigs; 27424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using media::DemuxerData; 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebMediaPlayer; 29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebString; 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// The size of the access unit to transfer in an IPC in case of MediaSource. 3423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// 4: approximately 64ms of content in 60 fps movies. 3523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)const size_t kAccessUnitSizeForMediaSource = 4; 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff }; 3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace content { 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log, 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& error) { 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error)); 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)MediaSourceDelegate::MediaSourceDelegate( 49d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) RendererDemuxerAndroid* demuxer_client, 50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) int demuxer_client_id, 513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const scoped_refptr<base::MessageLoopProxy>& media_loop, 523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) media::MediaLog* media_log) 5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) : demuxer_client_(demuxer_client), 54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) demuxer_client_id_(demuxer_client_id), 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) media_log_(media_log), 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch is_demuxer_ready_(false), 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_stream_(NULL), 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch video_stream_(NULL), 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) seeking_(false), 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) is_video_encrypted_(false), 611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) doing_browser_seek_(false), 621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) browser_seek_time_(media::kNoTimestamp()), 631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) expecting_regular_seek_(false), 6423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) access_unit_size_(0), 6523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) main_loop_(base::MessageLoopProxy::current()), 6623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) media_loop_(media_loop), 6723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) main_weak_factory_(this), 6823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) media_weak_factory_(this), 6923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) main_weak_this_(main_weak_factory_.GetWeakPtr()) { 7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)MediaSourceDelegate::~MediaSourceDelegate() { 743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 75d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) DCHECK(!chunk_demuxer_); 77d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(!demuxer_client_); 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(!audio_decrypting_demuxer_stream_); 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(!video_decrypting_demuxer_stream_); 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(!audio_stream_); 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(!video_stream_); 8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void MediaSourceDelegate::Destroy() { 853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 86d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 87d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!chunk_demuxer_) { 8968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) DCHECK(!demuxer_client_); 9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) delete this; 9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return; 9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) duration_change_cb_.Reset(); 9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) update_network_state_cb_.Reset(); 963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) media_source_opened_cb_.Reset(); 9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) main_weak_factory_.InvalidateWeakPtrs(); 9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(!main_weak_factory_.HasWeakPtrs()); 1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chunk_demuxer_->Shutdown(); 10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // |this| will be transferred to the callback StopDemuxer() and 10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // OnDemuxerStopDone(). They own |this| and OnDemuxerStopDone() will delete 10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // it when called, hence using base::Unretained(this) is safe here. 1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) media_loop_->PostTask(FROM_HERE, 1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::Bind(&MediaSourceDelegate::StopDemuxer, 1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::Unretained(this))); 1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool MediaSourceDelegate::IsVideoEncrypted() { 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::AutoLock auto_lock(is_video_encrypted_lock_); 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return is_video_encrypted_; 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 117010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)base::Time MediaSourceDelegate::GetTimelineOffset() const { 118010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 119010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!chunk_demuxer_) 120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return base::Time(); 121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return chunk_demuxer_->GetTimelineOffset(); 123010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void MediaSourceDelegate::StopDemuxer() { 12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(chunk_demuxer_); 1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 12968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) demuxer_client_->RemoveDelegate(demuxer_client_id_); 13068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) demuxer_client_ = NULL; 13168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_stream_ = NULL; 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch video_stream_ = NULL; 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // TODO(xhwang): Figure out if we need to Reset the DDSs after Seeking or 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // before destroying them. 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_decrypting_demuxer_stream_.reset(); 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch video_decrypting_demuxer_stream_.reset(); 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) media_weak_factory_.InvalidateWeakPtrs(); 14058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(!media_weak_factory_.HasWeakPtrs()); 1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // The callback OnDemuxerStopDone() owns |this| and will delete it when 1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // called. Hence using base::Unretained(this) is safe here. 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chunk_demuxer_->Stop(base::Bind(&MediaSourceDelegate::OnDemuxerStopDone, 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(this))); 14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void MediaSourceDelegate::InitializeMediaSource( 1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const MediaSourceOpenedCB& media_source_opened_cb, 1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const media::Demuxer::NeedKeyCB& need_key_cb, 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const media::SetDecryptorReadyCB& set_decryptor_ready_cb, 1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const UpdateNetworkStateCB& update_network_state_cb, 15368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const DurationChangeCB& duration_change_cb) { 1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(!media_source_opened_cb.is_null()); 1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) media_source_opened_cb_ = media_source_opened_cb; 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) need_key_cb_ = need_key_cb; 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch set_decryptor_ready_cb_ = set_decryptor_ready_cb; 1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); 160d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) duration_change_cb_ = duration_change_cb; 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch access_unit_size_ = kAccessUnitSizeForMediaSource; 162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) chunk_demuxer_.reset(new media::ChunkDemuxer( 164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch media::BindToCurrentLoop( 165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::Bind(&MediaSourceDelegate::OnDemuxerOpened, main_weak_this_)), 166effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch media::BindToCurrentLoop( 167effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::Bind(&MediaSourceDelegate::OnNeedKey, main_weak_this_)), 168effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::Bind(&LogMediaSourceError, media_log_), 169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch false)); 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // |this| will be retained until StopDemuxer() is posted, so Unretained() is 1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // safe here. 1733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) media_loop_->PostTask(FROM_HERE, 1743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::Bind(&MediaSourceDelegate::InitializeDemuxer, 1753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::Unretained(this))); 1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 1773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void MediaSourceDelegate::InitializeDemuxer() { 17958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 18068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) demuxer_client_->AddDelegate(demuxer_client_id_, this); 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chunk_demuxer_->Initialize(this, 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&MediaSourceDelegate::OnDemuxerInitDone, 183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) media_weak_factory_.GetWeakPtr()), 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) false); 185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)blink::WebTimeRanges MediaSourceDelegate::Buffered() const { 188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return ConvertToWebTimeRanges(buffered_time_ranges_); 189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)size_t MediaSourceDelegate::DecodedFrameCount() const { 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return statistics_.video_frames_decoded; 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)size_t MediaSourceDelegate::DroppedFrameCount() const { 196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return statistics_.video_frames_dropped; 197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)size_t MediaSourceDelegate::AudioDecodedByteCount() const { 200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return statistics_.audio_bytes_decoded; 201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)size_t MediaSourceDelegate::VideoDecodedByteCount() const { 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return statistics_.video_bytes_decoded; 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 20768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void MediaSourceDelegate::CancelPendingSeek(const base::TimeDelta& seek_time) { 2083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 20968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : " 210d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) << demuxer_client_id_; 211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!chunk_demuxer_) 2131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return; 2141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) { 2161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Remember to trivially finish any newly arriving browser seek requests 2171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // that may arrive prior to the next regular seek request. 2181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::AutoLock auto_lock(seeking_lock_); 2191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) expecting_regular_seek_ = true; 220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 2211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Cancel any previously expected or in-progress regular or browser seek. 2231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // It is possible that we have just finished the seek, but caller does 2241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // not know this yet. It is still safe to cancel in this case because the 2251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // caller will always call StartWaitingForSeek() when it is notified of 2261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // the finished seek. 2271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) chunk_demuxer_->CancelPendingSeek(seek_time); 22868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 23068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void MediaSourceDelegate::StartWaitingForSeek( 23168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const base::TimeDelta& seek_time) { 23268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 23368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : " 23468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) << demuxer_client_id_; 23568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 2361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!chunk_demuxer_) 2371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return; 2381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) bool cancel_browser_seek = false; 2401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) { 2411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Remember to trivially finish any newly arriving browser seek requests 2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // that may arrive prior to the next regular seek request. 2431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::AutoLock auto_lock(seeking_lock_); 2441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) expecting_regular_seek_ = true; 2451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Remember to cancel any in-progress browser seek. 2471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (seeking_) { 2481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(doing_browser_seek_); 2491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) cancel_browser_seek = true; 2501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (cancel_browser_seek) 2541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) chunk_demuxer_->CancelPendingSeek(seek_time); 2551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) chunk_demuxer_->StartWaitingForSeek(seek_time); 25668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 25768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 2581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void MediaSourceDelegate::Seek( 2591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const base::TimeDelta& seek_time, bool is_browser_seek) { 26068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 2611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ", " 2621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) << (is_browser_seek ? "browser seek" : "regular seek") << ") : " 26368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) << demuxer_client_id_; 26468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 2651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::TimeDelta internal_seek_time = seek_time; 2661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) { 2671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::AutoLock auto_lock(seeking_lock_); 2681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(!seeking_); 2691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) seeking_ = true; 2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) doing_browser_seek_ = is_browser_seek; 2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (doing_browser_seek_ && (!chunk_demuxer_ || expecting_regular_seek_)) { 2731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Trivially finish the browser seek without actually doing it. Reads will 2741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // continue to be |kAborted| until the next regular seek is done. Browser 2751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // seeking is not supported unless using a ChunkDemuxer; browser seeks are 2761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // trivially finished if |chunk_demuxer_| is NULL. 2771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) seeking_ = false; 2781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) doing_browser_seek_ = false; 2791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time); 2801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return; 2811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (doing_browser_seek_) { 2841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) internal_seek_time = FindBufferedBrowserSeekTime_Locked(seek_time); 2851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) browser_seek_time_ = internal_seek_time; 2861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else { 2871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) expecting_regular_seek_ = false; 2881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) browser_seek_time_ = media::kNoTimestamp(); 2891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Prepare |chunk_demuxer_| for browser seek. 2931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (is_browser_seek) { 2941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) chunk_demuxer_->CancelPendingSeek(internal_seek_time); 2951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) chunk_demuxer_->StartWaitingForSeek(internal_seek_time); 2961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) SeekInternal(internal_seek_time); 29968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 30058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 30168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void MediaSourceDelegate::SeekInternal(const base::TimeDelta& seek_time) { 30258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 30368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) DCHECK(IsSeeking()); 3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chunk_demuxer_->Seek(seek_time, base::Bind( 30568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) &MediaSourceDelegate::OnDemuxerSeekDone, 30668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) media_weak_factory_.GetWeakPtr())); 30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MediaSourceDelegate::AddBufferedTimeRange(base::TimeDelta start, 310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::TimeDelta end) { 311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) buffered_time_ranges_.Add(start, end); 312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MediaSourceDelegate::SetDuration(base::TimeDelta duration) { 315d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 316d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << "(" << duration.InSecondsF() << ") : " 317d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) << demuxer_client_id_; 318d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 319d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Force duration change notification to be async to avoid reentrancy into 320d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // ChunkDemxuer. 321d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) main_loop_->PostTask(FROM_HERE, base::Bind( 322d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) &MediaSourceDelegate::OnDurationChanged, main_weak_this_, duration)); 323d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 324d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 325d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void MediaSourceDelegate::OnDurationChanged(const base::TimeDelta& duration) { 326d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 327d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (demuxer_client_) 328d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) demuxer_client_->DurationChanged(demuxer_client_id_, duration); 3297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!duration_change_cb_.is_null()) 3307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) duration_change_cb_.Run(duration); 331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type) { 33458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 335d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << "(" << type << ") : " << demuxer_client_id_; 3363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (IsSeeking()) 337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; // Drop the request during seeking. 338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO); 340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // The access unit size should have been initialized properly at this stage. 341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_GT(access_unit_size_, 0u); 342424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) scoped_ptr<DemuxerData> data(new DemuxerData()); 343424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->type = type; 344424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units.resize(access_unit_size_); 345424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) ReadFromDemuxerStream(type, data.Pass(), 0); 346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 348424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void MediaSourceDelegate::ReadFromDemuxerStream(media::DemuxerStream::Type type, 349424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) scoped_ptr<DemuxerData> data, 350424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) size_t index) { 35158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // DemuxerStream::Read() always returns the read callback asynchronously. 353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DemuxerStream* stream = 354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_; 3553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) stream->Read(base::Bind( 3563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) &MediaSourceDelegate::OnBufferReady, 35758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) media_weak_factory_.GetWeakPtr(), type, base::Passed(&data), index)); 358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MediaSourceDelegate::OnBufferReady( 361eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch media::DemuxerStream::Type type, 362424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) scoped_ptr<DemuxerData> data, 363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t index, 364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DemuxerStream::Status status, 365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const scoped_refptr<media::DecoderBuffer>& buffer) { 36658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 367d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << "(" << index << ", " << status << ", " 368a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) << ((!buffer || buffer->end_of_stream()) ? 369a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) -1 : buffer->timestamp().InMilliseconds()) 370d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) << ") : " << demuxer_client_id_; 3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(chunk_demuxer_); 372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // No new OnReadFromDemuxer() will be called during seeking. So this callback 374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // must be from previous OnReadFromDemuxer() call and should be ignored. 3753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (IsSeeking()) { 376d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << ": Ignore previous read during seeking."; 377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool is_audio = (type == DemuxerStream::AUDIO); 381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (status != DemuxerStream::kAborted && 382424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) index >= data->access_units.size()) { 383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(ERROR) << "The internal state inconsistency onBufferReady: " 384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) << (is_audio ? "Audio" : "Video") << ", index " << index 385424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) << ", size " << data->access_units.size() 386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) << ", status " << static_cast<int>(status); 387eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch NOTREACHED(); 388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 390eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) switch (status) { 392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) case DemuxerStream::kAborted: 393d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << " : Aborted"; 394424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units[index].status = status; 395424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units.resize(index + 1); 396424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) break; 397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) case DemuxerStream::kConfigChanged: 399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) CHECK((is_audio && audio_stream_) || (!is_audio && video_stream_)); 400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) data->demuxer_configs.resize(1); 401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) CHECK(GetDemuxerConfigFromStream(&data->demuxer_configs[0], is_audio)); 402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!is_audio) { 403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::Size size = data->demuxer_configs[0].video_size; 404eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DVLOG(1) << "Video config is changed: " << size.width() << "x" 405eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << size.height(); 406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 407424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units[index].status = status; 408424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units.resize(index + 1); 409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) break; 410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) case DemuxerStream::kOk: 412424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units[index].status = status; 413ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (buffer->end_of_stream()) { 414424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units[index].end_of_stream = true; 415424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units.resize(index + 1); 416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) break; 417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(ycheo): We assume that the inputed stream will be decoded 419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // right away. 420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Need to implement this properly using MediaPlayer.OnInfoListener. 421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (is_audio) { 422ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch statistics_.audio_bytes_decoded += buffer->data_size(); 423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 424ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch statistics_.video_bytes_decoded += buffer->data_size(); 425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) statistics_.video_frames_decoded++; 426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 427424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units[index].timestamp = buffer->timestamp(); 4284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) data->access_units[index].data.assign( 4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) buffer->data(), buffer->data() + buffer->data_size()); 43190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Vorbis needs 4 extra bytes padding on Android. Check 43290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // NuMediaExtractor.cpp in Android source code. 43390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (is_audio && media::kCodecVorbis == 434eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_stream_->audio_decoder_config().codec()) { 435424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units[index].data.insert( 436424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units[index].data.end(), kVorbisPadding, 43790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) kVorbisPadding + 4); 43890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 439ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (buffer->decrypt_config()) { 440424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units[index].key_id = std::vector<char>( 441ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch buffer->decrypt_config()->key_id().begin(), 442ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch buffer->decrypt_config()->key_id().end()); 443424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units[index].iv = std::vector<char>( 444ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch buffer->decrypt_config()->iv().begin(), 445ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch buffer->decrypt_config()->iv().end()); 446424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data->access_units[index].subsamples = 447ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch buffer->decrypt_config()->subsamples(); 448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 449424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (++index < data->access_units.size()) { 450424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) ReadFromDemuxerStream(type, data.Pass(), index); 451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) break; 454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) default: 456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NOTREACHED(); 457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 459d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (!IsSeeking() && demuxer_client_) 460d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) demuxer_client_->ReadFromDemuxerAck(demuxer_client_id_, *data); 461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 463eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) { 464d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; 4653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // |update_network_state_cb_| is bound to the main thread. 46690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null()) 46790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) update_network_state_cb_.Run(PipelineErrorToNetworkState(status)); 468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 470f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MediaSourceDelegate::AddTextStream( 471f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) media::DemuxerStream* /* text_stream */ , 472f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const media::TextTrackConfig& /* config */ ) { 473f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // TODO(matthewjheaney): add text stream (http://crbug/322115). 474f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) NOTIMPLEMENTED(); 475f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 476f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 477f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MediaSourceDelegate::RemoveTextStream( 478f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) media::DemuxerStream* /* text_stream */ ) { 479f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // TODO(matthewjheaney): remove text stream (http://crbug/322115). 480f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) NOTIMPLEMENTED(); 481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 482f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 483eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) { 48458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 485d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; 4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(chunk_demuxer_); 487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (status != media::PIPELINE_OK) { 489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch OnDemuxerError(status); 490eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 491eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 492eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) audio_stream_ = chunk_demuxer_->GetStream(DemuxerStream::AUDIO); 4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) video_stream_ = chunk_demuxer_->GetStream(DemuxerStream::VIDEO); 495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 4967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() && 4977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch !set_decryptor_ready_cb_.is_null()) { 498eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch InitAudioDecryptingDemuxerStream(); 499eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // InitVideoDecryptingDemuxerStream() will be called in 500eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // OnAudioDecryptingDemuxerStreamInitDone(). 501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 502eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() && 5057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch !set_decryptor_ready_cb_.is_null()) { 506eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch InitVideoDecryptingDemuxerStream(); 507eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 508eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 509eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 510eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Notify demuxer ready when both streams are not encrypted. 511eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch is_demuxer_ready_ = true; 512f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) NotifyDemuxerReady(); 513eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 514eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 515eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MediaSourceDelegate::InitAudioDecryptingDemuxerStream() { 51658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 517d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 5187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DCHECK(!set_decryptor_ready_cb_.is_null()); 5197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 520eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( 521d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) media_loop_, set_decryptor_ready_cb_)); 522eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_decrypting_demuxer_stream_->Initialize( 523eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_stream_, 5243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone, 52558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) media_weak_factory_.GetWeakPtr())); 526eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 527eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 528eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MediaSourceDelegate::InitVideoDecryptingDemuxerStream() { 52958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 530d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 5317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DCHECK(!set_decryptor_ready_cb_.is_null()); 5327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 533eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( 534d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) media_loop_, set_decryptor_ready_cb_)); 535eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch video_decrypting_demuxer_stream_->Initialize( 536eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch video_stream_, 5373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone, 53858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) media_weak_factory_.GetWeakPtr())); 539eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 540eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 541eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone( 542eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch media::PipelineStatus status) { 54358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 544d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; 5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(chunk_demuxer_); 546eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 547eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (status != media::PIPELINE_OK) 548eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_decrypting_demuxer_stream_.reset(); 549eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch else 550eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_stream_ = audio_decrypting_demuxer_stream_.get(); 551eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 552eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) { 553eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch InitVideoDecryptingDemuxerStream(); 554eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 555eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 556eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 557eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Try to notify demuxer ready when audio DDS initialization finished and 558eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // video is not encrypted. 559eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch is_demuxer_ready_ = true; 560f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) NotifyDemuxerReady(); 561eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 562eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 563eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone( 564c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) media::PipelineStatus status) { 56558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 566d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; 5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(chunk_demuxer_); 568eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 569eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (status != media::PIPELINE_OK) 570eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch video_decrypting_demuxer_stream_.reset(); 571eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch else 572eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch video_stream_ = video_decrypting_demuxer_stream_.get(); 573eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 574eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Try to notify demuxer ready when video DDS initialization finished. 575eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch is_demuxer_ready_ = true; 576f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) NotifyDemuxerReady(); 577eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 578eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 57968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void MediaSourceDelegate::OnDemuxerSeekDone(media::PipelineStatus status) { 58058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 581d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; 5823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(IsSeeking()); 583eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 584c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (status != media::PIPELINE_OK) { 585c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OnDemuxerError(status); 586c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 588eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 589eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ResetAudioDecryptingDemuxerStream(); 590eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 591eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 592eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() { 59358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 594d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 595eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (audio_decrypting_demuxer_stream_) { 596eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_decrypting_demuxer_stream_->Reset( 597eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Bind(&MediaSourceDelegate::ResetVideoDecryptingDemuxerStream, 59858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) media_weak_factory_.GetWeakPtr())); 59958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 600eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 60158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 60258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ResetVideoDecryptingDemuxerStream(); 603eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 604eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 605eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() { 60658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 607d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 608eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (video_decrypting_demuxer_stream_) { 60958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) video_decrypting_demuxer_stream_->Reset(base::Bind( 61058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) &MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams, 61158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) media_weak_factory_.GetWeakPtr())); 61258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 613eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 61458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 61558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) FinishResettingDecryptingDemuxerStreams(); 61658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 61758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 61858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams() { 61958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 620d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 6211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 6221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::AutoLock auto_lock(seeking_lock_); 6231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(seeking_); 6241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) seeking_ = false; 6251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) doing_browser_seek_ = false; 6261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) demuxer_client_->DemuxerSeekDone(demuxer_client_id_, browser_seek_time_); 627c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 62990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void MediaSourceDelegate::OnDemuxerStopDone() { 6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 6315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 6325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) main_loop_->PostTask( 6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 6345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&MediaSourceDelegate::DeleteSelf, base::Unretained(this))); 6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaSourceDelegate::DeleteSelf() { 6383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 639d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 64090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) chunk_demuxer_.reset(); 64190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) delete this; 64290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 64390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 644eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MediaSourceDelegate::NotifyDemuxerReady() { 64558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 646d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 647f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(is_demuxer_ready_); 648eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 649424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) scoped_ptr<DemuxerConfigs> configs(new DemuxerConfigs()); 650cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GetDemuxerConfigFromStream(configs.get(), true); 651cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GetDemuxerConfigFromStream(configs.get(), false); 6520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch configs->duration = GetDuration(); 653c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 654d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (demuxer_client_) 655d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) demuxer_client_->DemuxerReady(demuxer_client_id_, *configs); 6565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 6575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::AutoLock auto_lock(is_video_encrypted_lock_); 6585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) is_video_encrypted_ = configs->is_video_encrypted; 659c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 660c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 6610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbase::TimeDelta MediaSourceDelegate::GetDuration() const { 66258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 663868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!chunk_demuxer_) 6640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return media::kNoTimestamp(); 665868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 6660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch double duration = chunk_demuxer_->GetDuration(); 6670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (duration == std::numeric_limits<double>::infinity()) 6680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return media::kInfiniteDuration(); 6690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 6700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return ConvertSecondsToTimestamp(duration); 671868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 672868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 673c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MediaSourceDelegate::OnDemuxerOpened() { 6743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 6753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (media_source_opened_cb_.is_null()) 67690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return; 67790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 6783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) media_source_opened_cb_.Run(new WebMediaSourceImpl( 679c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_))); 680c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 681c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 68258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void MediaSourceDelegate::OnNeedKey(const std::string& type, 683424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) const std::vector<uint8>& init_data) { 6843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 685868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (need_key_cb_.is_null()) 686c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 687c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 6884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) need_key_cb_.Run(type, init_data); 68990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 69090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 6913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool MediaSourceDelegate::IsSeeking() const { 6923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::AutoLock auto_lock(seeking_lock_); 6933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return seeking_; 6943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 6953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 6961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)base::TimeDelta MediaSourceDelegate::FindBufferedBrowserSeekTime_Locked( 6971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const base::TimeDelta& seek_time) const { 6981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) seeking_lock_.AssertAcquired(); 6991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(seeking_); 7001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(doing_browser_seek_); 7011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(chunk_demuxer_) << "Browser seek requested, but no chunk demuxer"; 7021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 7031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) media::Ranges<base::TimeDelta> buffered = 7041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) chunk_demuxer_->GetBufferedRanges(); 7051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 7061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (size_t i = 0; i < buffered.size(); ++i) { 7071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::TimeDelta range_start = buffered.start(i); 7081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::TimeDelta range_end = buffered.end(i); 7091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (range_start <= seek_time) { 7101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (range_end >= seek_time) 7111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return seek_time; 7121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) continue; 7131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 7141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 7151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // If the start of the next buffered range after |seek_time| is too far 7161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // into the future, do not jump forward. 7171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if ((range_start - seek_time) > base::TimeDelta::FromMilliseconds(100)) 7181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) break; 7191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 7201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // TODO(wolenetz): Remove possibility that this browser seek jumps 7211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // into future when the requested range is unbuffered but there is some 7221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // other buffered range after it. See http://crbug.com/304234. 7231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return range_start; 7241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 7251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 7261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // We found no range containing |seek_time| or beginning shortly after 7271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // |seek_time|. While possible that such data at and beyond the player's 7281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // current time have been garbage collected or removed by the web app, this is 7291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // unlikely. This may cause unexpected playback stall due to seek pending an 7301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // append for a GOP prior to the last GOP demuxed. 7311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // TODO(wolenetz): Remove the possibility for this seek to cause unexpected 7321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // player stall by replaying cached data since last keyframe in browser player 7331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // rather than issuing browser seek. See http://crbug.com/304234. 7341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return seek_time; 7351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 7361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 737cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool MediaSourceDelegate::GetDemuxerConfigFromStream( 738cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) media::DemuxerConfigs* configs, bool is_audio) { 739cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(media_loop_->BelongsToCurrentThread()); 740f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!is_demuxer_ready_) 741cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return false; 742cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (is_audio && audio_stream_) { 743cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) media::AudioDecoderConfig config = audio_stream_->audio_decoder_config(); 744cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) configs->audio_codec = config.codec(); 745cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) configs->audio_channels = 746cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) media::ChannelLayoutToChannelCount(config.channel_layout()); 747cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) configs->audio_sampling_rate = config.samples_per_second(); 748cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) configs->is_audio_encrypted = config.is_encrypted(); 749cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) configs->audio_extra_data = std::vector<uint8>( 750cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) config.extra_data(), config.extra_data() + config.extra_data_size()); 751cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return true; 752cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 753cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!is_audio && video_stream_) { 754cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) media::VideoDecoderConfig config = video_stream_->video_decoder_config(); 755cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) configs->video_codec = config.codec(); 756cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) configs->video_size = config.natural_size(); 757cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) configs->is_video_encrypted = config.is_encrypted(); 758cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) configs->video_extra_data = std::vector<uint8>( 759cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) config.extra_data(), config.extra_data() + config.extra_data_size()); 760cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return true; 761cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 762cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return false; 763cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 764cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 765eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace content 766