chunk_demuxer.cc 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/filters/chunk_demuxer.h"
  5. #include <algorithm>
  6. #include <limits>
  7. #include <memory>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/callback_helpers.h"
  11. #include "base/location.h"
  12. #include "base/metrics/histogram_macros.h"
  13. #include "base/strings/string_number_conversions.h"
  14. #include "base/threading/thread_task_runner_handle.h"
  15. #include "base/trace_event/trace_event.h"
  16. #include "media/base/audio_decoder_config.h"
  17. #include "media/base/bind_to_current_loop.h"
  18. #include "media/base/media_tracks.h"
  19. #include "media/base/mime_util.h"
  20. #include "media/base/stream_parser_buffer.h"
  21. #include "media/base/timestamp_constants.h"
  22. #include "media/base/video_codecs.h"
  23. #include "media/base/video_decoder_config.h"
  24. #include "media/filters/frame_processor.h"
  25. #include "media/filters/source_buffer_stream.h"
  26. #include "media/filters/stream_parser_factory.h"
  27. namespace {
  28. // Helper to attempt construction of a StreamParser specific to |content_type|
  29. // and |codecs|.
  30. // TODO(wolenetz): Consider relocating this to StreamParserFactory in
  31. // conjunction with updating StreamParserFactory's isTypeSupported() to also
  32. // parse codecs, rather than require preparsed vector.
  33. std::unique_ptr<media::StreamParser> CreateParserForTypeAndCodecs(
  34. const std::string& content_type,
  35. const std::string& codecs,
  36. media::MediaLog* media_log) {
  37. std::vector<std::string> parsed_codec_ids;
  38. media::SplitCodecs(codecs, &parsed_codec_ids);
  39. return media::StreamParserFactory::Create(content_type, parsed_codec_ids,
  40. media_log);
  41. }
  42. // Helper to calculate the expected codecs parsed from initialization segments
  43. // for a few mime types that have an implicit codec.
  44. std::string ExpectedCodecs(const std::string& content_type,
  45. const std::string& codecs) {
  46. if (codecs == "" && content_type == "audio/aac")
  47. return "aac";
  48. if (codecs == "" &&
  49. (content_type == "audio/mpeg" || content_type == "audio/mp3"))
  50. return "mp3";
  51. return codecs;
  52. }
  53. } // namespace
  54. namespace media {
  55. ChunkDemuxerStream::ChunkDemuxerStream(Type type, MediaTrack::Id media_track_id)
  56. : type_(type),
  57. liveness_(StreamLiveness::kUnknown),
  58. media_track_id_(media_track_id),
  59. state_(UNINITIALIZED),
  60. is_enabled_(true) {}
  61. void ChunkDemuxerStream::StartReturningData() {
  62. DVLOG(1) << "ChunkDemuxerStream::StartReturningData()";
  63. base::AutoLock auto_lock(lock_);
  64. DCHECK(!read_cb_);
  65. ChangeState_Locked(RETURNING_DATA_FOR_READS);
  66. }
  67. void ChunkDemuxerStream::AbortReads() {
  68. DVLOG(1) << "ChunkDemuxerStream::AbortReads()";
  69. base::AutoLock auto_lock(lock_);
  70. ChangeState_Locked(RETURNING_ABORT_FOR_READS);
  71. if (read_cb_)
  72. std::move(read_cb_).Run(kAborted, nullptr);
  73. }
  74. void ChunkDemuxerStream::CompletePendingReadIfPossible() {
  75. base::AutoLock auto_lock(lock_);
  76. if (!read_cb_)
  77. return;
  78. CompletePendingReadIfPossible_Locked();
  79. }
  80. void ChunkDemuxerStream::Shutdown() {
  81. DVLOG(1) << "ChunkDemuxerStream::Shutdown()";
  82. base::AutoLock auto_lock(lock_);
  83. ChangeState_Locked(SHUTDOWN);
  84. // Pass an end of stream buffer to the pending callback to signal that no more
  85. // data will be sent.
  86. if (read_cb_) {
  87. std::move(read_cb_).Run(DemuxerStream::kOk,
  88. StreamParserBuffer::CreateEOSBuffer());
  89. }
  90. }
  91. bool ChunkDemuxerStream::IsSeekWaitingForData() const {
  92. base::AutoLock auto_lock(lock_);
  93. // This method should not be called for text tracks. See the note in
  94. // SourceBufferState::IsSeekWaitingForData().
  95. DCHECK_NE(type_, DemuxerStream::TEXT);
  96. return stream_->IsSeekPending();
  97. }
  98. void ChunkDemuxerStream::Seek(base::TimeDelta time) {
  99. DVLOG(1) << "ChunkDemuxerStream::Seek(" << time.InSecondsF() << ")";
  100. base::AutoLock auto_lock(lock_);
  101. DCHECK(!read_cb_);
  102. DCHECK(state_ == UNINITIALIZED || state_ == RETURNING_ABORT_FOR_READS)
  103. << state_;
  104. stream_->Seek(time);
  105. }
  106. bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) {
  107. if (append_observer_cb_)
  108. append_observer_cb_.Run(&buffers);
  109. if (buffers.empty())
  110. return false;
  111. base::AutoLock auto_lock(lock_);
  112. DCHECK_NE(state_, SHUTDOWN);
  113. stream_->Append(buffers);
  114. if (read_cb_)
  115. CompletePendingReadIfPossible_Locked();
  116. return true;
  117. }
  118. void ChunkDemuxerStream::Remove(base::TimeDelta start,
  119. base::TimeDelta end,
  120. base::TimeDelta duration) {
  121. base::AutoLock auto_lock(lock_);
  122. stream_->Remove(start, end, duration);
  123. }
  124. bool ChunkDemuxerStream::EvictCodedFrames(base::TimeDelta media_time,
  125. size_t newDataSize) {
  126. base::AutoLock auto_lock(lock_);
  127. // If the stream is disabled, then the renderer is not reading from it and
  128. // thus the read position might be stale. MSE GC algorithm uses the read
  129. // position to determine when to stop removing data from the front of buffered
  130. // ranges, so do a Seek in order to update the read position and allow the GC
  131. // to collect unnecessary data that is earlier than the GOP containing
  132. // |media_time|.
  133. if (!is_enabled_)
  134. stream_->Seek(media_time);
  135. // |media_time| is allowed to be a little imprecise here. GC only needs to
  136. // know which GOP currentTime points to.
  137. return stream_->GarbageCollectIfNeeded(media_time, newDataSize);
  138. }
  139. void ChunkDemuxerStream::OnMemoryPressure(
  140. base::TimeDelta media_time,
  141. base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level,
  142. bool force_instant_gc) {
  143. // TODO(sebmarchand): Check if MEMORY_PRESSURE_LEVEL_MODERATE should also be
  144. // ignored.
  145. if (memory_pressure_level ==
  146. base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
  147. return;
  148. }
  149. base::AutoLock auto_lock(lock_);
  150. return stream_->OnMemoryPressure(media_time, memory_pressure_level,
  151. force_instant_gc);
  152. }
  153. void ChunkDemuxerStream::OnSetDuration(base::TimeDelta duration) {
  154. base::AutoLock auto_lock(lock_);
  155. stream_->OnSetDuration(duration);
  156. }
  157. Ranges<base::TimeDelta> ChunkDemuxerStream::GetBufferedRanges(
  158. base::TimeDelta duration) const {
  159. base::AutoLock auto_lock(lock_);
  160. if (type_ == TEXT) {
  161. // Since text tracks are discontinuous and the lack of cues should not block
  162. // playback, report the buffered range for text tracks as [0, |duration|) so
  163. // that intesections with audio & video tracks are computed correctly when
  164. // no cues are present.
  165. Ranges<base::TimeDelta> text_range;
  166. text_range.Add(base::TimeDelta(), duration);
  167. return text_range;
  168. }
  169. Ranges<base::TimeDelta> range = stream_->GetBufferedTime();
  170. if (range.size() == 0u)
  171. return range;
  172. // Clamp the end of the stream's buffered ranges to fit within the duration.
  173. // This can be done by intersecting the stream's range with the valid time
  174. // range.
  175. Ranges<base::TimeDelta> valid_time_range;
  176. valid_time_range.Add(range.start(0), duration);
  177. return range.IntersectionWith(valid_time_range);
  178. }
  179. base::TimeDelta ChunkDemuxerStream::GetHighestPresentationTimestamp() const {
  180. base::AutoLock auto_lock(lock_);
  181. return stream_->GetHighestPresentationTimestamp();
  182. }
  183. base::TimeDelta ChunkDemuxerStream::GetBufferedDuration() const {
  184. base::AutoLock auto_lock(lock_);
  185. return stream_->GetBufferedDuration();
  186. }
  187. size_t ChunkDemuxerStream::GetBufferedSize() const {
  188. base::AutoLock auto_lock(lock_);
  189. return stream_->GetBufferedSize();
  190. }
  191. void ChunkDemuxerStream::OnStartOfCodedFrameGroup(DecodeTimestamp start_dts,
  192. base::TimeDelta start_pts) {
  193. DVLOG(2) << "ChunkDemuxerStream::OnStartOfCodedFrameGroup(dts "
  194. << start_dts.InSecondsF() << ", pts " << start_pts.InSecondsF()
  195. << ")";
  196. if (group_start_observer_cb_)
  197. group_start_observer_cb_.Run(start_dts, start_pts);
  198. base::AutoLock auto_lock(lock_);
  199. stream_->OnStartOfCodedFrameGroup(start_pts);
  200. }
  201. bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config,
  202. bool allow_codec_change,
  203. MediaLog* media_log) {
  204. DCHECK(config.IsValidConfig());
  205. DCHECK_EQ(type_, AUDIO);
  206. base::AutoLock auto_lock(lock_);
  207. if (!stream_) {
  208. DCHECK_EQ(state_, UNINITIALIZED);
  209. stream_ = std::make_unique<SourceBufferStream>(config, media_log);
  210. return true;
  211. }
  212. return stream_->UpdateAudioConfig(config, allow_codec_change);
  213. }
  214. bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config,
  215. bool allow_codec_change,
  216. MediaLog* media_log) {
  217. DCHECK(config.IsValidConfig());
  218. DCHECK_EQ(type_, VIDEO);
  219. base::AutoLock auto_lock(lock_);
  220. if (!stream_) {
  221. DCHECK_EQ(state_, UNINITIALIZED);
  222. stream_ = std::make_unique<SourceBufferStream>(config, media_log);
  223. return true;
  224. }
  225. return stream_->UpdateVideoConfig(config, allow_codec_change);
  226. }
  227. void ChunkDemuxerStream::UpdateTextConfig(const TextTrackConfig& config,
  228. MediaLog* media_log) {
  229. DCHECK_EQ(type_, TEXT);
  230. base::AutoLock auto_lock(lock_);
  231. DCHECK(!stream_);
  232. DCHECK_EQ(state_, UNINITIALIZED);
  233. stream_ = std::make_unique<SourceBufferStream>(config, media_log);
  234. }
  235. void ChunkDemuxerStream::MarkEndOfStream() {
  236. base::AutoLock auto_lock(lock_);
  237. stream_->MarkEndOfStream();
  238. }
  239. void ChunkDemuxerStream::UnmarkEndOfStream() {
  240. base::AutoLock auto_lock(lock_);
  241. stream_->UnmarkEndOfStream();
  242. }
  243. // DemuxerStream methods.
  244. void ChunkDemuxerStream::Read(ReadCB read_cb) {
  245. base::AutoLock auto_lock(lock_);
  246. DCHECK_NE(state_, UNINITIALIZED);
  247. DCHECK(!read_cb_);
  248. read_cb_ = BindToCurrentLoop(std::move(read_cb));
  249. if (!is_enabled_) {
  250. DVLOG(1) << "Read from disabled stream, returning EOS";
  251. std::move(read_cb_).Run(kOk, StreamParserBuffer::CreateEOSBuffer());
  252. return;
  253. }
  254. CompletePendingReadIfPossible_Locked();
  255. }
  256. DemuxerStream::Type ChunkDemuxerStream::type() const { return type_; }
  257. StreamLiveness ChunkDemuxerStream::liveness() const {
  258. base::AutoLock auto_lock(lock_);
  259. return liveness_;
  260. }
  261. AudioDecoderConfig ChunkDemuxerStream::audio_decoder_config() {
  262. CHECK_EQ(type_, AUDIO);
  263. base::AutoLock auto_lock(lock_);
  264. // Trying to track down crash. http://crbug.com/715761
  265. CHECK(stream_);
  266. return stream_->GetCurrentAudioDecoderConfig();
  267. }
  268. VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() {
  269. CHECK_EQ(type_, VIDEO);
  270. base::AutoLock auto_lock(lock_);
  271. // Trying to track down crash. http://crbug.com/715761
  272. CHECK(stream_);
  273. return stream_->GetCurrentVideoDecoderConfig();
  274. }
  275. bool ChunkDemuxerStream::SupportsConfigChanges() { return true; }
  276. bool ChunkDemuxerStream::IsEnabled() const {
  277. base::AutoLock auto_lock(lock_);
  278. return is_enabled_;
  279. }
  280. void ChunkDemuxerStream::SetEnabled(bool enabled, base::TimeDelta timestamp) {
  281. base::AutoLock auto_lock(lock_);
  282. if (enabled == is_enabled_)
  283. return;
  284. is_enabled_ = enabled;
  285. if (enabled) {
  286. DCHECK(stream_);
  287. stream_->Seek(timestamp);
  288. } else if (read_cb_) {
  289. DVLOG(1) << "Read from disabled stream, returning EOS";
  290. std::move(read_cb_).Run(kOk, StreamParserBuffer::CreateEOSBuffer());
  291. }
  292. }
  293. TextTrackConfig ChunkDemuxerStream::text_track_config() {
  294. CHECK_EQ(type_, TEXT);
  295. base::AutoLock auto_lock(lock_);
  296. return stream_->GetCurrentTextTrackConfig();
  297. }
  298. void ChunkDemuxerStream::SetStreamMemoryLimit(size_t memory_limit) {
  299. base::AutoLock auto_lock(lock_);
  300. stream_->set_memory_limit(memory_limit);
  301. }
  302. void ChunkDemuxerStream::SetLiveness(StreamLiveness liveness) {
  303. base::AutoLock auto_lock(lock_);
  304. liveness_ = liveness;
  305. }
  306. void ChunkDemuxerStream::ChangeState_Locked(State state) {
  307. lock_.AssertAcquired();
  308. DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : "
  309. << "type " << type_
  310. << " - " << state_ << " -> " << state;
  311. state_ = state;
  312. }
  313. ChunkDemuxerStream::~ChunkDemuxerStream() = default;
  314. void ChunkDemuxerStream::CompletePendingReadIfPossible_Locked() {
  315. lock_.AssertAcquired();
  316. DCHECK(read_cb_);
  317. DemuxerStream::Status status = DemuxerStream::kAborted;
  318. scoped_refptr<StreamParserBuffer> buffer;
  319. switch (state_) {
  320. case UNINITIALIZED:
  321. NOTREACHED();
  322. return;
  323. case RETURNING_DATA_FOR_READS:
  324. switch (stream_->GetNextBuffer(&buffer)) {
  325. case SourceBufferStreamStatus::kSuccess:
  326. status = DemuxerStream::kOk;
  327. DVLOG(2) << __func__ << ": returning kOk, type " << type_ << ", dts "
  328. << buffer->GetDecodeTimestamp().InSecondsF() << ", pts "
  329. << buffer->timestamp().InSecondsF() << ", dur "
  330. << buffer->duration().InSecondsF() << ", key "
  331. << buffer->is_key_frame();
  332. break;
  333. case SourceBufferStreamStatus::kNeedBuffer:
  334. // Return early without calling |read_cb_| since we don't have
  335. // any data to return yet.
  336. DVLOG(2) << __func__ << ": returning kNeedBuffer, type " << type_;
  337. return;
  338. case SourceBufferStreamStatus::kEndOfStream:
  339. status = DemuxerStream::kOk;
  340. buffer = StreamParserBuffer::CreateEOSBuffer();
  341. DVLOG(2) << __func__ << ": returning kOk with EOS buffer, type "
  342. << type_;
  343. break;
  344. case SourceBufferStreamStatus::kConfigChange:
  345. status = kConfigChanged;
  346. buffer = nullptr;
  347. DVLOG(2) << __func__ << ": returning kConfigChange, type " << type_;
  348. break;
  349. }
  350. break;
  351. case RETURNING_ABORT_FOR_READS:
  352. // Null buffers should be returned in this state since we are waiting
  353. // for a seek. Any buffers in the SourceBuffer should NOT be returned
  354. // because they are associated with the seek.
  355. status = DemuxerStream::kAborted;
  356. buffer = nullptr;
  357. DVLOG(2) << __func__ << ": returning kAborted, type " << type_;
  358. break;
  359. case SHUTDOWN:
  360. status = DemuxerStream::kOk;
  361. buffer = StreamParserBuffer::CreateEOSBuffer();
  362. DVLOG(2) << __func__ << ": returning kOk with EOS buffer, type " << type_;
  363. break;
  364. }
  365. std::move(read_cb_).Run(status, buffer);
  366. }
  367. ChunkDemuxer::ChunkDemuxer(
  368. base::OnceClosure open_cb,
  369. base::RepeatingClosure progress_cb,
  370. EncryptedMediaInitDataCB encrypted_media_init_data_cb,
  371. MediaLog* media_log)
  372. : state_(WAITING_FOR_INIT),
  373. cancel_next_seek_(false),
  374. host_(nullptr),
  375. open_cb_(std::move(open_cb)),
  376. progress_cb_(std::move(progress_cb)),
  377. encrypted_media_init_data_cb_(std::move(encrypted_media_init_data_cb)),
  378. media_log_(media_log),
  379. duration_(kNoTimestamp),
  380. user_specified_duration_(-1) {
  381. DCHECK(open_cb_);
  382. DCHECK(encrypted_media_init_data_cb_);
  383. MEDIA_LOG(INFO, media_log_) << GetDisplayName();
  384. }
  385. std::string ChunkDemuxer::GetDisplayName() const {
  386. return "ChunkDemuxer";
  387. }
  388. void ChunkDemuxer::Initialize(DemuxerHost* host,
  389. PipelineStatusCallback init_cb) {
  390. DVLOG(1) << "Initialize()";
  391. TRACE_EVENT_ASYNC_BEGIN0("media", "ChunkDemuxer::Initialize", this);
  392. base::OnceClosure open_cb;
  393. // Locked scope
  394. {
  395. base::AutoLock auto_lock(lock_);
  396. if (state_ == SHUTDOWN) {
  397. // Init cb must only be run after this method returns, so post.
  398. init_cb_ = BindToCurrentLoop(std::move(init_cb));
  399. RunInitCB_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
  400. return;
  401. }
  402. DCHECK_EQ(state_, WAITING_FOR_INIT);
  403. host_ = host;
  404. // Do not post init_cb once this function returns because if there is an
  405. // error after initialization, the error might be reported before init_cb
  406. // has a chance to run. This is because ChunkDemuxer::ReportError_Locked
  407. // directly calls DemuxerHost::OnDemuxerError: crbug.com/633016.
  408. init_cb_ = std::move(init_cb);
  409. ChangeState_Locked(INITIALIZING);
  410. open_cb = std::move(open_cb_);
  411. }
  412. std::move(open_cb).Run();
  413. }
  414. void ChunkDemuxer::Stop() {
  415. DVLOG(1) << "Stop()";
  416. Shutdown();
  417. }
  418. void ChunkDemuxer::Seek(base::TimeDelta time, PipelineStatusCallback cb) {
  419. DVLOG(1) << "Seek(" << time.InSecondsF() << ")";
  420. DCHECK(time >= base::TimeDelta());
  421. TRACE_EVENT_ASYNC_BEGIN0("media", "ChunkDemuxer::Seek", this);
  422. base::AutoLock auto_lock(lock_);
  423. DCHECK(!seek_cb_);
  424. seek_cb_ = BindToCurrentLoop(std::move(cb));
  425. if (state_ != INITIALIZED && state_ != ENDED) {
  426. RunSeekCB_Locked(PIPELINE_ERROR_INVALID_STATE);
  427. return;
  428. }
  429. if (cancel_next_seek_) {
  430. cancel_next_seek_ = false;
  431. RunSeekCB_Locked(PIPELINE_OK);
  432. return;
  433. }
  434. SeekAllSources(time);
  435. StartReturningData();
  436. if (IsSeekWaitingForData_Locked()) {
  437. DVLOG(1) << "Seek() : waiting for more data to arrive.";
  438. return;
  439. }
  440. RunSeekCB_Locked(PIPELINE_OK);
  441. }
  442. // Demuxer implementation.
  443. base::Time ChunkDemuxer::GetTimelineOffset() const {
  444. return timeline_offset_;
  445. }
  446. std::vector<DemuxerStream*> ChunkDemuxer::GetAllStreams() {
  447. base::AutoLock auto_lock(lock_);
  448. std::vector<DemuxerStream*> result;
  449. // Put enabled streams at the beginning of the list so that
  450. // MediaResource::GetFirstStream returns the enabled stream if there is one.
  451. // TODO(servolk): Revisit this after media track switching is supported.
  452. for (const auto& stream : audio_streams_) {
  453. if (stream->IsEnabled())
  454. result.push_back(stream.get());
  455. }
  456. for (const auto& stream : video_streams_) {
  457. if (stream->IsEnabled())
  458. result.push_back(stream.get());
  459. }
  460. // Put disabled streams at the end of the vector.
  461. for (const auto& stream : audio_streams_) {
  462. if (!stream->IsEnabled())
  463. result.push_back(stream.get());
  464. }
  465. for (const auto& stream : video_streams_) {
  466. if (!stream->IsEnabled())
  467. result.push_back(stream.get());
  468. }
  469. return result;
  470. }
  471. base::TimeDelta ChunkDemuxer::GetStartTime() const {
  472. return base::TimeDelta();
  473. }
  474. int64_t ChunkDemuxer::GetMemoryUsage() const {
  475. base::AutoLock auto_lock(lock_);
  476. int64_t mem = 0;
  477. for (const auto& s : audio_streams_)
  478. mem += s->GetBufferedSize();
  479. for (const auto& s : video_streams_)
  480. mem += s->GetBufferedSize();
  481. return mem;
  482. }
  483. absl::optional<container_names::MediaContainerName>
  484. ChunkDemuxer::GetContainerForMetrics() const {
  485. return absl::nullopt;
  486. }
  487. void ChunkDemuxer::AbortPendingReads() {
  488. base::AutoLock auto_lock(lock_);
  489. DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN ||
  490. state_ == PARSE_ERROR)
  491. << state_;
  492. if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
  493. return;
  494. AbortPendingReads_Locked();
  495. }
  496. void ChunkDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {
  497. DVLOG(1) << "StartWaitingForSeek()";
  498. base::AutoLock auto_lock(lock_);
  499. DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN ||
  500. state_ == PARSE_ERROR) << state_;
  501. DCHECK(!seek_cb_);
  502. if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
  503. return;
  504. AbortPendingReads_Locked();
  505. SeekAllSources(seek_time);
  506. // Cancel state set in CancelPendingSeek() since we want to
  507. // accept the next Seek().
  508. cancel_next_seek_ = false;
  509. }
  510. void ChunkDemuxer::CancelPendingSeek(base::TimeDelta seek_time) {
  511. base::AutoLock auto_lock(lock_);
  512. DCHECK_NE(state_, INITIALIZING);
  513. DCHECK(!seek_cb_ || IsSeekWaitingForData_Locked());
  514. if (cancel_next_seek_)
  515. return;
  516. AbortPendingReads_Locked();
  517. SeekAllSources(seek_time);
  518. if (!seek_cb_) {
  519. cancel_next_seek_ = true;
  520. return;
  521. }
  522. RunSeekCB_Locked(PIPELINE_OK);
  523. }
  524. ChunkDemuxer::Status ChunkDemuxer::AddId(
  525. const std::string& id,
  526. std::unique_ptr<AudioDecoderConfig> audio_config) {
  527. DCHECK(audio_config);
  528. DVLOG(1) << __func__ << " id="
  529. << " audio_config=" << audio_config->AsHumanReadableString();
  530. base::AutoLock auto_lock(lock_);
  531. // Any valid audio config provided by WC is bufferable here, though decode
  532. // error may occur later.
  533. if (!audio_config->IsValidConfig())
  534. return ChunkDemuxer::kNotSupported;
  535. if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
  536. return kReachedIdLimit;
  537. DCHECK(init_cb_);
  538. std::string expected_codec = GetCodecName(audio_config->codec());
  539. std::unique_ptr<media::StreamParser> stream_parser(
  540. media::StreamParserFactory::Create(std::move(audio_config)));
  541. DCHECK(stream_parser);
  542. return AddIdInternal(id, std::move(stream_parser), expected_codec);
  543. }
  544. ChunkDemuxer::Status ChunkDemuxer::AddId(
  545. const std::string& id,
  546. std::unique_ptr<VideoDecoderConfig> video_config) {
  547. DCHECK(video_config);
  548. DVLOG(1) << __func__ << " id="
  549. << " video_config=" << video_config->AsHumanReadableString();
  550. base::AutoLock auto_lock(lock_);
  551. // Any valid video config provided by WC is bufferable here, though decode
  552. // error may occur later.
  553. if (!video_config->IsValidConfig())
  554. return ChunkDemuxer::kNotSupported;
  555. if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
  556. return kReachedIdLimit;
  557. DCHECK(init_cb_);
  558. std::string expected_codec = GetCodecName(video_config->codec());
  559. std::unique_ptr<media::StreamParser> stream_parser(
  560. media::StreamParserFactory::Create(std::move(video_config)));
  561. DCHECK(stream_parser);
  562. return AddIdInternal(id, std::move(stream_parser), expected_codec);
  563. }
  564. ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
  565. const std::string& content_type,
  566. const std::string& codecs) {
  567. DVLOG(1) << __func__ << " id=" << id << " content_type=" << content_type
  568. << " codecs=" << codecs;
  569. base::AutoLock auto_lock(lock_);
  570. if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
  571. return kReachedIdLimit;
  572. // TODO(wolenetz): Change to DCHECK once less verification in release build is
  573. // needed. See https://crbug.com/786975.
  574. CHECK(init_cb_);
  575. std::unique_ptr<media::StreamParser> stream_parser(
  576. CreateParserForTypeAndCodecs(content_type, codecs, media_log_));
  577. if (!stream_parser) {
  578. DVLOG(1) << __func__ << " failed: unsupported content_type=" << content_type
  579. << " codecs=" << codecs;
  580. return ChunkDemuxer::kNotSupported;
  581. }
  582. return AddIdInternal(id, std::move(stream_parser),
  583. ExpectedCodecs(content_type, codecs));
  584. }
  585. ChunkDemuxer::Status ChunkDemuxer::AddIdInternal(
  586. const std::string& id,
  587. std::unique_ptr<media::StreamParser> stream_parser,
  588. std::string expected_codecs) {
  589. DVLOG(2) << __func__ << " id=" << id
  590. << " expected_codecs=" << expected_codecs;
  591. lock_.AssertAcquired();
  592. std::unique_ptr<FrameProcessor> frame_processor =
  593. std::make_unique<FrameProcessor>(
  594. base::BindRepeating(&ChunkDemuxer::IncreaseDurationIfNecessary,
  595. base::Unretained(this)),
  596. media_log_);
  597. std::unique_ptr<SourceBufferState> source_state =
  598. std::make_unique<SourceBufferState>(
  599. std::move(stream_parser), std::move(frame_processor),
  600. base::BindRepeating(&ChunkDemuxer::CreateDemuxerStream,
  601. base::Unretained(this), id),
  602. media_log_);
  603. // TODO(wolenetz): Change these to DCHECKs or switch to returning
  604. // kReachedIdLimit once less verification in release build is needed. See
  605. // https://crbug.com/786975.
  606. CHECK(pending_source_init_ids_.find(id) == pending_source_init_ids_.end());
  607. auto insert_result = pending_source_init_ids_.insert(id);
  608. CHECK(insert_result.first != pending_source_init_ids_.end());
  609. CHECK(*insert_result.first == id);
  610. CHECK(insert_result.second); // Only true if insertion succeeded.
  611. source_state->Init(base::BindOnce(&ChunkDemuxer::OnSourceInitDone,
  612. base::Unretained(this), id),
  613. expected_codecs, encrypted_media_init_data_cb_,
  614. base::NullCallback());
  615. // TODO(wolenetz): Change to DCHECKs once less verification in release build
  616. // is needed. See https://crbug.com/786975.
  617. CHECK(!IsValidId(id));
  618. source_state_map_[id] = std::move(source_state);
  619. CHECK(IsValidId(id));
  620. return kOk;
  621. }
  622. void ChunkDemuxer::SetTracksWatcher(const std::string& id,
  623. MediaTracksUpdatedCB tracks_updated_cb) {
  624. base::AutoLock auto_lock(lock_);
  625. CHECK(IsValidId(id));
  626. source_state_map_[id]->SetTracksWatcher(std::move(tracks_updated_cb));
  627. }
  628. void ChunkDemuxer::SetParseWarningCallback(
  629. const std::string& id,
  630. SourceBufferParseWarningCB parse_warning_cb) {
  631. base::AutoLock auto_lock(lock_);
  632. CHECK(IsValidId(id));
  633. source_state_map_[id]->SetParseWarningCallback(std::move(parse_warning_cb));
  634. }
  635. void ChunkDemuxer::RemoveId(const std::string& id) {
  636. DVLOG(1) << __func__ << " id=" << id;
  637. base::AutoLock auto_lock(lock_);
  638. CHECK(IsValidId(id));
  639. source_state_map_.erase(id);
  640. pending_source_init_ids_.erase(id);
  641. // Remove demuxer streams created for this id.
  642. for (const ChunkDemuxerStream* s : id_to_streams_map_[id]) {
  643. bool stream_found = false;
  644. for (size_t i = 0; i < audio_streams_.size(); ++i) {
  645. if (audio_streams_[i].get() == s) {
  646. stream_found = true;
  647. removed_streams_.push_back(std::move(audio_streams_[i]));
  648. audio_streams_.erase(audio_streams_.begin() + i);
  649. break;
  650. }
  651. }
  652. if (stream_found)
  653. continue;
  654. for (size_t i = 0; i < video_streams_.size(); ++i) {
  655. if (video_streams_[i].get() == s) {
  656. stream_found = true;
  657. removed_streams_.push_back(std::move(video_streams_[i]));
  658. video_streams_.erase(video_streams_.begin() + i);
  659. break;
  660. }
  661. }
  662. CHECK(stream_found);
  663. }
  664. id_to_streams_map_.erase(id);
  665. }
  666. Ranges<base::TimeDelta> ChunkDemuxer::GetBufferedRanges(
  667. const std::string& id) const {
  668. base::AutoLock auto_lock(lock_);
  669. DCHECK(!id.empty());
  670. auto itr = source_state_map_.find(id);
  671. DCHECK(itr != source_state_map_.end());
  672. return itr->second->GetBufferedRanges(duration_, state_ == ENDED);
  673. }
  674. base::TimeDelta ChunkDemuxer::GetHighestPresentationTimestamp(
  675. const std::string& id) const {
  676. base::AutoLock auto_lock(lock_);
  677. DCHECK(!id.empty());
  678. auto itr = source_state_map_.find(id);
  679. DCHECK(itr != source_state_map_.end());
  680. return itr->second->GetHighestPresentationTimestamp();
  681. }
  682. void ChunkDemuxer::FindAndEnableProperTracks(
  683. const std::vector<MediaTrack::Id>& track_ids,
  684. base::TimeDelta curr_time,
  685. DemuxerStream::Type track_type,
  686. TrackChangeCB change_completed_cb) {
  687. base::AutoLock auto_lock(lock_);
  688. std::set<ChunkDemuxerStream*> enabled_streams;
  689. for (const auto& id : track_ids) {
  690. auto it = track_id_to_demux_stream_map_.find(id);
  691. if (it == track_id_to_demux_stream_map_.end())
  692. continue;
  693. ChunkDemuxerStream* stream = it->second;
  694. DCHECK(stream);
  695. DCHECK_EQ(track_type, stream->type());
  696. // TODO(servolk): Remove after multiple enabled audio tracks are supported
  697. // by the media::RendererImpl.
  698. if (!enabled_streams.empty()) {
  699. MEDIA_LOG(INFO, media_log_)
  700. << "Only one enabled track is supported, ignoring track " << id;
  701. continue;
  702. }
  703. enabled_streams.insert(stream);
  704. stream->SetEnabled(true, curr_time);
  705. }
  706. bool is_audio = track_type == DemuxerStream::AUDIO;
  707. for (const auto& stream : is_audio ? audio_streams_ : video_streams_) {
  708. if (stream && enabled_streams.find(stream.get()) == enabled_streams.end()) {
  709. DVLOG(1) << __func__ << ": disabling stream " << stream.get();
  710. stream->SetEnabled(false, curr_time);
  711. }
  712. }
  713. std::vector<DemuxerStream*> streams(enabled_streams.begin(),
  714. enabled_streams.end());
  715. std::move(change_completed_cb).Run(track_type, streams);
  716. }
  717. void ChunkDemuxer::OnEnabledAudioTracksChanged(
  718. const std::vector<MediaTrack::Id>& track_ids,
  719. base::TimeDelta curr_time,
  720. TrackChangeCB change_completed_cb) {
  721. FindAndEnableProperTracks(track_ids, curr_time, DemuxerStream::AUDIO,
  722. std::move(change_completed_cb));
  723. }
  724. void ChunkDemuxer::OnSelectedVideoTrackChanged(
  725. const std::vector<MediaTrack::Id>& track_ids,
  726. base::TimeDelta curr_time,
  727. TrackChangeCB change_completed_cb) {
  728. FindAndEnableProperTracks(track_ids, curr_time, DemuxerStream::VIDEO,
  729. std::move(change_completed_cb));
  730. }
  731. void ChunkDemuxer::OnMemoryPressure(
  732. base::TimeDelta currentMediaTime,
  733. base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level,
  734. bool force_instant_gc) {
  735. // TODO(sebmarchand): Check if MEMORY_PRESSURE_LEVEL_MODERATE should also be
  736. // ignored.
  737. if (memory_pressure_level ==
  738. base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
  739. return;
  740. }
  741. base::AutoLock auto_lock(lock_);
  742. for (const auto& [source, state] : source_state_map_) {
  743. state->OnMemoryPressure(currentMediaTime, memory_pressure_level,
  744. force_instant_gc);
  745. }
  746. }
  747. bool ChunkDemuxer::EvictCodedFrames(const std::string& id,
  748. base::TimeDelta currentMediaTime,
  749. size_t newDataSize) {
  750. DVLOG(1) << __func__ << "(" << id << ")"
  751. << " media_time=" << currentMediaTime.InSecondsF()
  752. << " newDataSize=" << newDataSize;
  753. base::AutoLock auto_lock(lock_);
  754. DCHECK(!id.empty());
  755. auto itr = source_state_map_.find(id);
  756. if (itr == source_state_map_.end()) {
  757. LOG(WARNING) << __func__ << " stream " << id << " not found";
  758. return false;
  759. }
  760. return itr->second->EvictCodedFrames(currentMediaTime, newDataSize);
  761. }
  762. bool ChunkDemuxer::AppendData(const std::string& id,
  763. const uint8_t* data,
  764. size_t length,
  765. base::TimeDelta append_window_start,
  766. base::TimeDelta append_window_end,
  767. base::TimeDelta* timestamp_offset) {
  768. DVLOG(1) << "AppendData(" << id << ", " << length << ")";
  769. DCHECK(!id.empty());
  770. DCHECK(timestamp_offset);
  771. Ranges<base::TimeDelta> ranges;
  772. {
  773. base::AutoLock auto_lock(lock_);
  774. DCHECK_NE(state_, ENDED);
  775. // Capture if any of the SourceBuffers are waiting for data before we start
  776. // parsing.
  777. bool old_waiting_for_data = IsSeekWaitingForData_Locked();
  778. if (length == 0u)
  779. return true;
  780. DCHECK(data);
  781. switch (state_) {
  782. case INITIALIZING:
  783. case INITIALIZED:
  784. DCHECK(IsValidId(id));
  785. if (!source_state_map_[id]->Append(data, length, append_window_start,
  786. append_window_end,
  787. timestamp_offset)) {
  788. ReportError_Locked(CHUNK_DEMUXER_ERROR_APPEND_FAILED);
  789. return false;
  790. }
  791. break;
  792. case PARSE_ERROR:
  793. case WAITING_FOR_INIT:
  794. case ENDED:
  795. case SHUTDOWN:
  796. DVLOG(1) << "AppendData(): called in unexpected state " << state_;
  797. return false;
  798. }
  799. // Check to see if data was appended at the pending seek point. This
  800. // indicates we have parsed enough data to complete the seek. Work is still
  801. // in progress at this point, but it's okay since |seek_cb_| will post.
  802. if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && seek_cb_)
  803. RunSeekCB_Locked(PIPELINE_OK);
  804. ranges = GetBufferedRanges_Locked();
  805. }
  806. host_->OnBufferedTimeRangesChanged(ranges);
  807. progress_cb_.Run();
  808. return true;
  809. }
  810. bool ChunkDemuxer::AppendChunks(
  811. const std::string& id,
  812. std::unique_ptr<StreamParser::BufferQueue> buffer_queue,
  813. base::TimeDelta append_window_start,
  814. base::TimeDelta append_window_end,
  815. base::TimeDelta* timestamp_offset) {
  816. DCHECK(buffer_queue);
  817. DVLOG(1) << __func__ << ": " << id
  818. << ", buffer_queue size()=" << buffer_queue->size();
  819. DCHECK(!id.empty());
  820. DCHECK(timestamp_offset);
  821. Ranges<base::TimeDelta> ranges;
  822. {
  823. base::AutoLock auto_lock(lock_);
  824. DCHECK_NE(state_, ENDED);
  825. // Capture if any of the SourceBuffers are waiting for data before we start
  826. // buffering new chunks.
  827. bool old_waiting_for_data = IsSeekWaitingForData_Locked();
  828. if (buffer_queue->size() == 0u)
  829. return true;
  830. switch (state_) {
  831. case INITIALIZING:
  832. case INITIALIZED:
  833. DCHECK(IsValidId(id));
  834. if (!source_state_map_[id]->AppendChunks(
  835. std::move(buffer_queue), append_window_start, append_window_end,
  836. timestamp_offset)) {
  837. ReportError_Locked(CHUNK_DEMUXER_ERROR_APPEND_FAILED);
  838. return false;
  839. }
  840. break;
  841. case PARSE_ERROR:
  842. case WAITING_FOR_INIT:
  843. case ENDED:
  844. case SHUTDOWN:
  845. DVLOG(1) << "AppendChunks(): called in unexpected state " << state_;
  846. return false;
  847. }
  848. // Check to see if data was appended at the pending seek point. This
  849. // indicates we have parsed enough data to complete the seek. Work is still
  850. // in progress at this point, but it's okay since |seek_cb_| will post.
  851. if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && seek_cb_)
  852. RunSeekCB_Locked(PIPELINE_OK);
  853. ranges = GetBufferedRanges_Locked();
  854. }
  855. host_->OnBufferedTimeRangesChanged(ranges);
  856. progress_cb_.Run();
  857. return true;
  858. }
  859. void ChunkDemuxer::ResetParserState(const std::string& id,
  860. base::TimeDelta append_window_start,
  861. base::TimeDelta append_window_end,
  862. base::TimeDelta* timestamp_offset) {
  863. DVLOG(1) << "ResetParserState(" << id << ")";
  864. base::AutoLock auto_lock(lock_);
  865. DCHECK(!id.empty());
  866. CHECK(IsValidId(id));
  867. bool old_waiting_for_data = IsSeekWaitingForData_Locked();
  868. source_state_map_[id]->ResetParserState(append_window_start,
  869. append_window_end,
  870. timestamp_offset);
  871. // ResetParserState can possibly emit some buffers.
  872. // Need to check whether seeking can be completed.
  873. if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && seek_cb_)
  874. RunSeekCB_Locked(PIPELINE_OK);
  875. }
  876. void ChunkDemuxer::Remove(const std::string& id,
  877. base::TimeDelta start,
  878. base::TimeDelta end) {
  879. DVLOG(1) << "Remove(" << id << ", " << start.InSecondsF()
  880. << ", " << end.InSecondsF() << ")";
  881. base::AutoLock auto_lock(lock_);
  882. DCHECK(!id.empty());
  883. CHECK(IsValidId(id));
  884. DCHECK(start >= base::TimeDelta()) << start.InSecondsF();
  885. DCHECK(start < end) << "start " << start.InSecondsF()
  886. << " end " << end.InSecondsF();
  887. DCHECK(duration_ != kNoTimestamp);
  888. DCHECK(start <= duration_) << "start " << start.InSecondsF()
  889. << " duration " << duration_.InSecondsF();
  890. if (start == duration_)
  891. return;
  892. source_state_map_[id]->Remove(start, end, duration_);
  893. host_->OnBufferedTimeRangesChanged(GetBufferedRanges_Locked());
  894. }
  895. bool ChunkDemuxer::CanChangeType(const std::string& id,
  896. const std::string& content_type,
  897. const std::string& codecs) {
  898. // Note, Chromium currently will not compare content_type and codecs, if any,
  899. // with previous content_type and codecs of the SourceBuffer.
  900. // TODO(wolenetz): Consider returning false if the codecs parameters are ever
  901. // made to be precise such that they signal that the number of tracks of
  902. // various media types differ from the first initialization segment (if
  903. // received already). Switching to an audio-only container, when the first
  904. // initialization segment only contained non-audio tracks, is one example we
  905. // could enforce earlier here.
  906. DVLOG(1) << __func__ << " id=" << id << " content_type=" << content_type
  907. << " codecs=" << codecs;
  908. base::AutoLock auto_lock(lock_);
  909. DCHECK(IsValidId(id));
  910. // CanChangeType() doesn't care if there has or hasn't been received a first
  911. // initialization segment for the source buffer corresponding to |id|.
  912. std::unique_ptr<media::StreamParser> stream_parser(
  913. CreateParserForTypeAndCodecs(content_type, codecs, media_log_));
  914. return !!stream_parser;
  915. }
  916. void ChunkDemuxer::ChangeType(const std::string& id,
  917. const std::string& content_type,
  918. const std::string& codecs) {
  919. DVLOG(1) << __func__ << " id=" << id << " content_type=" << content_type
  920. << " codecs=" << codecs;
  921. base::AutoLock auto_lock(lock_);
  922. DCHECK(state_ == INITIALIZING || state_ == INITIALIZED) << state_;
  923. DCHECK(IsValidId(id));
  924. std::unique_ptr<media::StreamParser> stream_parser(
  925. CreateParserForTypeAndCodecs(content_type, codecs, media_log_));
  926. // Caller should query CanChangeType() first to protect from failing this.
  927. DCHECK(stream_parser);
  928. source_state_map_[id]->ChangeType(std::move(stream_parser),
  929. ExpectedCodecs(content_type, codecs));
  930. }
  931. double ChunkDemuxer::GetDuration() {
  932. base::AutoLock auto_lock(lock_);
  933. return GetDuration_Locked();
  934. }
  935. double ChunkDemuxer::GetDuration_Locked() {
  936. lock_.AssertAcquired();
  937. if (duration_ == kNoTimestamp)
  938. return std::numeric_limits<double>::quiet_NaN();
  939. // Return positive infinity if the resource is unbounded.
  940. // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
  941. if (duration_ == kInfiniteDuration)
  942. return std::numeric_limits<double>::infinity();
  943. if (user_specified_duration_ >= 0)
  944. return user_specified_duration_;
  945. return duration_.InSecondsF();
  946. }
  947. void ChunkDemuxer::SetDuration(double duration) {
  948. base::AutoLock auto_lock(lock_);
  949. DVLOG(1) << "SetDuration(" << duration << ")";
  950. DCHECK_GE(duration, 0);
  951. if (duration == GetDuration_Locked())
  952. return;
  953. // Compute & bounds check the base::TimeDelta representation of duration.
  954. // This can be different if the value of |duration| doesn't fit the range or
  955. // precision of base::TimeDelta.
  956. base::TimeDelta min_duration = base::TimeDelta::FromInternalValue(1);
  957. // Don't use base::TimeDelta::Max() here, as we want the largest finite time
  958. // delta.
  959. base::TimeDelta max_duration = base::TimeDelta::FromInternalValue(
  960. std::numeric_limits<int64_t>::max() - 1);
  961. double min_duration_in_seconds = min_duration.InSecondsF();
  962. double max_duration_in_seconds = max_duration.InSecondsF();
  963. base::TimeDelta duration_td;
  964. if (duration == std::numeric_limits<double>::infinity()) {
  965. duration_td = media::kInfiniteDuration;
  966. } else if (duration < min_duration_in_seconds) {
  967. duration_td = min_duration;
  968. } else if (duration > max_duration_in_seconds) {
  969. duration_td = max_duration;
  970. } else {
  971. duration_td =
  972. base::Microseconds(duration * base::Time::kMicrosecondsPerSecond);
  973. }
  974. DCHECK(duration_td.is_positive());
  975. user_specified_duration_ = duration;
  976. duration_ = duration_td;
  977. host_->SetDuration(duration_);
  978. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  979. ++itr) {
  980. itr->second->OnSetDuration(duration_);
  981. }
  982. }
  983. bool ChunkDemuxer::IsParsingMediaSegment(const std::string& id) {
  984. base::AutoLock auto_lock(lock_);
  985. DVLOG(1) << "IsParsingMediaSegment(" << id << ")";
  986. CHECK(IsValidId(id));
  987. return source_state_map_[id]->parsing_media_segment();
  988. }
  989. bool ChunkDemuxer::GetGenerateTimestampsFlag(const std::string& id) {
  990. base::AutoLock auto_lock(lock_);
  991. DVLOG(1) << "GetGenerateTimestampsFlag(" << id << ")";
  992. CHECK(IsValidId(id));
  993. return source_state_map_[id]->generate_timestamps_flag();
  994. }
  995. void ChunkDemuxer::SetSequenceMode(const std::string& id,
  996. bool sequence_mode) {
  997. base::AutoLock auto_lock(lock_);
  998. DVLOG(1) << "SetSequenceMode(" << id << ", " << sequence_mode << ")";
  999. CHECK(IsValidId(id));
  1000. DCHECK_NE(state_, ENDED);
  1001. source_state_map_[id]->SetSequenceMode(sequence_mode);
  1002. }
  1003. void ChunkDemuxer::SetGroupStartTimestampIfInSequenceMode(
  1004. const std::string& id,
  1005. base::TimeDelta timestamp_offset) {
  1006. base::AutoLock auto_lock(lock_);
  1007. DVLOG(1) << "SetGroupStartTimestampIfInSequenceMode(" << id << ", "
  1008. << timestamp_offset.InSecondsF() << ")";
  1009. CHECK(IsValidId(id));
  1010. DCHECK_NE(state_, ENDED);
  1011. source_state_map_[id]->SetGroupStartTimestampIfInSequenceMode(
  1012. timestamp_offset);
  1013. }
  1014. void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) {
  1015. DVLOG(1) << "MarkEndOfStream(" << status << ")";
  1016. base::AutoLock auto_lock(lock_);
  1017. DCHECK_NE(state_, WAITING_FOR_INIT);
  1018. DCHECK_NE(state_, ENDED);
  1019. if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
  1020. return;
  1021. if (state_ == INITIALIZING) {
  1022. MEDIA_LOG(ERROR, media_log_)
  1023. << "MediaSource endOfStream before demuxer initialization completes "
  1024. "(before HAVE_METADATA) is treated as an error. This may also occur "
  1025. "as consequence of other MediaSource errors before HAVE_METADATA.";
  1026. ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
  1027. return;
  1028. }
  1029. bool old_waiting_for_data = IsSeekWaitingForData_Locked();
  1030. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  1031. ++itr) {
  1032. itr->second->MarkEndOfStream();
  1033. }
  1034. CompletePendingReadsIfPossible();
  1035. // Give a chance to resume the pending seek process.
  1036. if (status != PIPELINE_OK) {
  1037. DCHECK(status == CHUNK_DEMUXER_ERROR_EOS_STATUS_DECODE_ERROR ||
  1038. status == CHUNK_DEMUXER_ERROR_EOS_STATUS_NETWORK_ERROR);
  1039. ReportError_Locked(status);
  1040. return;
  1041. }
  1042. ChangeState_Locked(ENDED);
  1043. DecreaseDurationIfNecessary();
  1044. if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && seek_cb_)
  1045. RunSeekCB_Locked(PIPELINE_OK);
  1046. }
  1047. void ChunkDemuxer::UnmarkEndOfStream() {
  1048. DVLOG(1) << "UnmarkEndOfStream()";
  1049. base::AutoLock auto_lock(lock_);
  1050. DCHECK(state_ == ENDED || state_ == SHUTDOWN || state_ == PARSE_ERROR)
  1051. << state_;
  1052. // At least ReportError_Locked()'s error reporting to Blink hops threads, so
  1053. // SourceBuffer may not be aware of media element error on another operation
  1054. // that might race to this point.
  1055. if (state_ == PARSE_ERROR || state_ == SHUTDOWN)
  1056. return;
  1057. ChangeState_Locked(INITIALIZED);
  1058. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  1059. ++itr) {
  1060. itr->second->UnmarkEndOfStream();
  1061. }
  1062. }
  1063. void ChunkDemuxer::Shutdown() {
  1064. DVLOG(1) << "Shutdown()";
  1065. base::AutoLock auto_lock(lock_);
  1066. if (state_ == SHUTDOWN)
  1067. return;
  1068. ShutdownAllStreams();
  1069. ChangeState_Locked(SHUTDOWN);
  1070. if (seek_cb_)
  1071. RunSeekCB_Locked(PIPELINE_ERROR_ABORT);
  1072. }
  1073. void ChunkDemuxer::SetMemoryLimitsForTest(DemuxerStream::Type type,
  1074. size_t memory_limit) {
  1075. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  1076. ++itr) {
  1077. itr->second->SetMemoryLimits(type, memory_limit);
  1078. }
  1079. }
  1080. void ChunkDemuxer::ChangeState_Locked(State new_state) {
  1081. lock_.AssertAcquired();
  1082. DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : "
  1083. << state_ << " -> " << new_state;
  1084. // TODO(wolenetz): Change to DCHECK once less verification in release build is
  1085. // needed. See https://crbug.com/786975.
  1086. // Disallow changes from at or beyond PARSE_ERROR to below PARSE_ERROR.
  1087. CHECK(!(state_ >= PARSE_ERROR && new_state < PARSE_ERROR));
  1088. state_ = new_state;
  1089. }
  1090. ChunkDemuxer::~ChunkDemuxer() {
  1091. DCHECK_NE(state_, INITIALIZED);
  1092. }
  1093. void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
  1094. DVLOG(1) << "ReportError_Locked(" << error << ")";
  1095. lock_.AssertAcquired();
  1096. DCHECK(error != PIPELINE_OK);
  1097. ChangeState_Locked(PARSE_ERROR);
  1098. if (init_cb_) {
  1099. RunInitCB_Locked(error);
  1100. return;
  1101. }
  1102. ShutdownAllStreams();
  1103. if (seek_cb_) {
  1104. RunSeekCB_Locked(error);
  1105. return;
  1106. }
  1107. base::AutoUnlock auto_unlock(lock_);
  1108. host_->OnDemuxerError(error);
  1109. }
  1110. bool ChunkDemuxer::IsSeekWaitingForData_Locked() const {
  1111. lock_.AssertAcquired();
  1112. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  1113. ++itr) {
  1114. if (itr->second->IsSeekWaitingForData())
  1115. return true;
  1116. }
  1117. return false;
  1118. }
  1119. void ChunkDemuxer::OnSourceInitDone(
  1120. const std::string& source_id,
  1121. const StreamParser::InitParameters& params) {
  1122. DVLOG(1) << "OnSourceInitDone source_id=" << source_id
  1123. << " duration=" << params.duration.InSecondsF();
  1124. lock_.AssertAcquired();
  1125. // TODO(wolenetz): Change these to DCHECKs once less verification in release
  1126. // build is needed. See https://crbug.com/786975.
  1127. CHECK(!pending_source_init_ids_.empty());
  1128. CHECK(IsValidId(source_id));
  1129. CHECK(pending_source_init_ids_.find(source_id) !=
  1130. pending_source_init_ids_.end());
  1131. CHECK(init_cb_);
  1132. CHECK_EQ(state_, INITIALIZING);
  1133. if (audio_streams_.empty() && video_streams_.empty()) {
  1134. ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
  1135. return;
  1136. }
  1137. if (!params.duration.is_zero() && duration_ == kNoTimestamp)
  1138. UpdateDuration(params.duration);
  1139. if (!params.timeline_offset.is_null()) {
  1140. if (!timeline_offset_.is_null() &&
  1141. params.timeline_offset != timeline_offset_) {
  1142. MEDIA_LOG(ERROR, media_log_)
  1143. << "Timeline offset is not the same across all SourceBuffers.";
  1144. ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
  1145. return;
  1146. }
  1147. timeline_offset_ = params.timeline_offset;
  1148. }
  1149. if (params.liveness != StreamLiveness::kUnknown) {
  1150. for (const auto& s : audio_streams_)
  1151. s->SetLiveness(params.liveness);
  1152. for (const auto& s : video_streams_)
  1153. s->SetLiveness(params.liveness);
  1154. }
  1155. // Wait until all streams have initialized.
  1156. pending_source_init_ids_.erase(source_id);
  1157. if (!pending_source_init_ids_.empty())
  1158. return;
  1159. SeekAllSources(GetStartTime());
  1160. StartReturningData();
  1161. if (duration_ == kNoTimestamp)
  1162. duration_ = kInfiniteDuration;
  1163. // The demuxer is now initialized after the |start_timestamp_| was set.
  1164. // TODO(wolenetz): Change these to DCHECKs once less verification in release
  1165. // build is needed. See https://crbug.com/786975.
  1166. CHECK_EQ(state_, INITIALIZING);
  1167. ChangeState_Locked(INITIALIZED);
  1168. RunInitCB_Locked(PIPELINE_OK);
  1169. }
  1170. // static
  1171. MediaTrack::Id ChunkDemuxer::GenerateMediaTrackId() {
  1172. static unsigned g_track_count = 0;
  1173. return MediaTrack::Id(base::NumberToString(++g_track_count));
  1174. }
  1175. ChunkDemuxerStream* ChunkDemuxer::CreateDemuxerStream(
  1176. const std::string& source_id,
  1177. DemuxerStream::Type type) {
  1178. // New ChunkDemuxerStreams can be created only during initialization segment
  1179. // processing, which happens when a new chunk of data is appended and the
  1180. // lock_ must be held by ChunkDemuxer::AppendData/Chunks.
  1181. lock_.AssertAcquired();
  1182. MediaTrack::Id media_track_id = GenerateMediaTrackId();
  1183. OwnedChunkDemuxerStreamVector* owning_vector = nullptr;
  1184. switch (type) {
  1185. case DemuxerStream::AUDIO:
  1186. owning_vector = &audio_streams_;
  1187. break;
  1188. case DemuxerStream::VIDEO:
  1189. owning_vector = &video_streams_;
  1190. break;
  1191. case DemuxerStream::TEXT:
  1192. owning_vector = &text_streams_;
  1193. break;
  1194. case DemuxerStream::UNKNOWN:
  1195. NOTREACHED();
  1196. return nullptr;
  1197. }
  1198. std::unique_ptr<ChunkDemuxerStream> stream =
  1199. std::make_unique<ChunkDemuxerStream>(type, media_track_id);
  1200. DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
  1201. track_id_to_demux_stream_map_.end());
  1202. track_id_to_demux_stream_map_[media_track_id] = stream.get();
  1203. id_to_streams_map_[source_id].push_back(stream.get());
  1204. stream->SetEnabled(owning_vector->empty(), base::TimeDelta());
  1205. owning_vector->push_back(std::move(stream));
  1206. return owning_vector->back().get();
  1207. }
  1208. bool ChunkDemuxer::IsValidId(const std::string& source_id) const {
  1209. lock_.AssertAcquired();
  1210. return source_state_map_.count(source_id) > 0u;
  1211. }
  1212. void ChunkDemuxer::UpdateDuration(base::TimeDelta new_duration) {
  1213. DCHECK(duration_ != new_duration ||
  1214. user_specified_duration_ != new_duration.InSecondsF());
  1215. user_specified_duration_ = -1;
  1216. duration_ = new_duration;
  1217. host_->SetDuration(new_duration);
  1218. }
  1219. void ChunkDemuxer::IncreaseDurationIfNecessary(base::TimeDelta new_duration) {
  1220. DCHECK(new_duration != kNoTimestamp);
  1221. DCHECK(new_duration != kInfiniteDuration);
  1222. // Per April 1, 2014 MSE spec editor's draft:
  1223. // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/
  1224. // media-source.html#sourcebuffer-coded-frame-processing
  1225. // 5. If the media segment contains data beyond the current duration, then run
  1226. // the duration change algorithm with new duration set to the maximum of
  1227. // the current duration and the group end timestamp.
  1228. if (new_duration <= duration_)
  1229. return;
  1230. DVLOG(2) << __func__ << ": Increasing duration: " << duration_.InSecondsF()
  1231. << " -> " << new_duration.InSecondsF();
  1232. UpdateDuration(new_duration);
  1233. }
  1234. void ChunkDemuxer::DecreaseDurationIfNecessary() {
  1235. lock_.AssertAcquired();
  1236. base::TimeDelta max_duration;
  1237. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  1238. ++itr) {
  1239. max_duration = std::max(max_duration,
  1240. itr->second->GetMaxBufferedDuration());
  1241. }
  1242. if (max_duration.is_zero())
  1243. return;
  1244. // Note: be careful to also check |user_specified_duration_|, which may have
  1245. // higher precision than |duration_|.
  1246. if (max_duration < duration_ ||
  1247. max_duration.InSecondsF() < user_specified_duration_) {
  1248. UpdateDuration(max_duration);
  1249. }
  1250. }
  1251. Ranges<base::TimeDelta> ChunkDemuxer::GetBufferedRanges() const {
  1252. base::AutoLock auto_lock(lock_);
  1253. return GetBufferedRanges_Locked();
  1254. }
  1255. Ranges<base::TimeDelta> ChunkDemuxer::GetBufferedRanges_Locked() const {
  1256. lock_.AssertAcquired();
  1257. bool ended = state_ == ENDED;
  1258. // TODO(acolwell): When we start allowing SourceBuffers that are not active,
  1259. // we'll need to update this loop to only add ranges from active sources.
  1260. SourceBufferState::RangesList ranges_list;
  1261. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  1262. ++itr) {
  1263. ranges_list.push_back(itr->second->GetBufferedRanges(duration_, ended));
  1264. }
  1265. return SourceBufferState::ComputeRangesIntersection(ranges_list, ended);
  1266. }
  1267. void ChunkDemuxer::StartReturningData() {
  1268. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  1269. ++itr) {
  1270. itr->second->StartReturningData();
  1271. }
  1272. }
  1273. void ChunkDemuxer::AbortPendingReads_Locked() {
  1274. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  1275. ++itr) {
  1276. itr->second->AbortReads();
  1277. }
  1278. }
  1279. void ChunkDemuxer::SeekAllSources(base::TimeDelta seek_time) {
  1280. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  1281. ++itr) {
  1282. itr->second->Seek(seek_time);
  1283. }
  1284. }
  1285. void ChunkDemuxer::CompletePendingReadsIfPossible() {
  1286. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  1287. ++itr) {
  1288. itr->second->CompletePendingReadIfPossible();
  1289. }
  1290. }
  1291. void ChunkDemuxer::ShutdownAllStreams() {
  1292. for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
  1293. ++itr) {
  1294. itr->second->Shutdown();
  1295. }
  1296. }
  1297. void ChunkDemuxer::RunInitCB_Locked(PipelineStatus status) {
  1298. lock_.AssertAcquired();
  1299. DCHECK(init_cb_);
  1300. TRACE_EVENT_ASYNC_END1("media", "ChunkDemuxer::Initialize", this, "status",
  1301. PipelineStatusToString(status));
  1302. std::move(init_cb_).Run(status);
  1303. }
  1304. void ChunkDemuxer::RunSeekCB_Locked(PipelineStatus status) {
  1305. lock_.AssertAcquired();
  1306. DCHECK(seek_cb_);
  1307. TRACE_EVENT_ASYNC_END1("media", "ChunkDemuxer::Seek", this, "status",
  1308. PipelineStatusToString(status));
  1309. std::move(seek_cb_).Run(status);
  1310. }
  1311. } // namespace media