text_renderer.cc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/base/text_renderer.h"
  5. #include <stddef.h>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/check_op.h"
  10. #include "base/notreached.h"
  11. #include "base/task/single_thread_task_runner.h"
  12. #include "media/base/bind_to_current_loop.h"
  13. #include "media/base/decoder_buffer.h"
  14. #include "media/base/demuxer.h"
  15. #include "media/base/text_cue.h"
  16. namespace media {
  17. TextRenderer::TextRenderer(
  18. const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
  19. const AddTextTrackCB& add_text_track_cb)
  20. : task_runner_(task_runner),
  21. add_text_track_cb_(add_text_track_cb),
  22. state_(kUninitialized),
  23. pending_read_count_(0) {}
  24. TextRenderer::~TextRenderer() {
  25. DCHECK(task_runner_->BelongsToCurrentThread());
  26. text_track_state_map_.clear();
  27. if (pause_cb_)
  28. std::move(pause_cb_).Run();
  29. }
  30. void TextRenderer::Initialize(const base::RepeatingClosure& ended_cb) {
  31. DCHECK(task_runner_->BelongsToCurrentThread());
  32. DCHECK(ended_cb);
  33. DCHECK_EQ(kUninitialized, state_) << "state_ " << state_;
  34. DCHECK(text_track_state_map_.empty());
  35. DCHECK_EQ(pending_read_count_, 0);
  36. DCHECK(pending_eos_set_.empty());
  37. DCHECK(!ended_cb_);
  38. ended_cb_ = ended_cb;
  39. state_ = kPaused;
  40. }
  41. void TextRenderer::StartPlaying() {
  42. DCHECK(task_runner_->BelongsToCurrentThread());
  43. DCHECK_EQ(state_, kPaused) << "state_ " << state_;
  44. for (auto itr = text_track_state_map_.begin();
  45. itr != text_track_state_map_.end(); ++itr) {
  46. TextTrackState* state = itr->second.get();
  47. if (state->read_state == TextTrackState::kReadPending) {
  48. DCHECK_GT(pending_read_count_, 0);
  49. continue;
  50. }
  51. Read(state, itr->first);
  52. }
  53. state_ = kPlaying;
  54. }
  55. void TextRenderer::Pause(base::OnceClosure callback) {
  56. DCHECK(task_runner_->BelongsToCurrentThread());
  57. DCHECK(state_ == kPlaying || state_ == kEnded) << "state_ " << state_;
  58. DCHECK_GE(pending_read_count_, 0);
  59. if (pending_read_count_ == 0) {
  60. state_ = kPaused;
  61. task_runner_->PostTask(FROM_HERE, std::move(callback));
  62. return;
  63. }
  64. pause_cb_ = std::move(callback);
  65. state_ = kPausePending;
  66. }
  67. void TextRenderer::Flush(base::OnceClosure callback) {
  68. DCHECK(task_runner_->BelongsToCurrentThread());
  69. DCHECK_EQ(pending_read_count_, 0);
  70. DCHECK(state_ == kPaused) << "state_ " << state_;
  71. for (auto itr = text_track_state_map_.begin();
  72. itr != text_track_state_map_.end(); ++itr) {
  73. pending_eos_set_.insert(itr->first);
  74. itr->second->text_ranges_.Reset();
  75. }
  76. DCHECK_EQ(pending_eos_set_.size(), text_track_state_map_.size());
  77. task_runner_->PostTask(FROM_HERE, std::move(callback));
  78. }
  79. void TextRenderer::AddTextStream(DemuxerStream* text_stream,
  80. const TextTrackConfig& config) {
  81. DCHECK(task_runner_->BelongsToCurrentThread());
  82. DCHECK(state_ != kUninitialized) << "state_ " << state_;
  83. DCHECK(text_track_state_map_.find(text_stream) ==
  84. text_track_state_map_.end());
  85. DCHECK(pending_eos_set_.find(text_stream) ==
  86. pending_eos_set_.end());
  87. AddTextTrackDoneCB done_cb = BindToCurrentLoop(
  88. base::BindOnce(&TextRenderer::OnAddTextTrackDone,
  89. weak_factory_.GetWeakPtr(), text_stream));
  90. add_text_track_cb_.Run(config, std::move(done_cb));
  91. }
  92. void TextRenderer::RemoveTextStream(DemuxerStream* text_stream) {
  93. DCHECK(task_runner_->BelongsToCurrentThread());
  94. auto itr = text_track_state_map_.find(text_stream);
  95. DCHECK(itr != text_track_state_map_.end());
  96. TextTrackState* state = itr->second.get();
  97. DCHECK_EQ(state->read_state, TextTrackState::kReadIdle);
  98. text_track_state_map_.erase(itr);
  99. pending_eos_set_.erase(text_stream);
  100. }
  101. bool TextRenderer::HasTracks() const {
  102. DCHECK(task_runner_->BelongsToCurrentThread());
  103. return !text_track_state_map_.empty();
  104. }
  105. void TextRenderer::BufferReady(DemuxerStream* stream,
  106. DemuxerStream::Status status,
  107. scoped_refptr<DecoderBuffer> input) {
  108. DCHECK(task_runner_->BelongsToCurrentThread());
  109. DCHECK_NE(status, DemuxerStream::kConfigChanged);
  110. if (status == DemuxerStream::kAborted) {
  111. DCHECK(!input);
  112. DCHECK_GT(pending_read_count_, 0);
  113. DCHECK(pending_eos_set_.find(stream) != pending_eos_set_.end());
  114. auto itr = text_track_state_map_.find(stream);
  115. DCHECK(itr != text_track_state_map_.end());
  116. TextTrackState* state = itr->second.get();
  117. DCHECK_EQ(state->read_state, TextTrackState::kReadPending);
  118. --pending_read_count_;
  119. state->read_state = TextTrackState::kReadIdle;
  120. switch (state_) {
  121. case kPlaying:
  122. return;
  123. case kPausePending:
  124. if (pending_read_count_ == 0) {
  125. state_ = kPaused;
  126. std::move(pause_cb_).Run();
  127. }
  128. return;
  129. case kPaused:
  130. case kUninitialized:
  131. case kEnded:
  132. NOTREACHED();
  133. return;
  134. }
  135. NOTREACHED();
  136. return;
  137. }
  138. if (input->end_of_stream()) {
  139. CueReady(stream, nullptr);
  140. return;
  141. }
  142. DCHECK_EQ(status, DemuxerStream::kOk);
  143. DCHECK_GE(input->side_data_size(), 2u);
  144. // The side data contains both the cue id and cue settings,
  145. // each terminated with a NUL.
  146. const char* id_ptr = reinterpret_cast<const char*>(input->side_data());
  147. size_t id_len = strlen(id_ptr);
  148. std::string id(id_ptr, id_len);
  149. const char* settings_ptr = id_ptr + id_len + 1;
  150. size_t settings_len = strlen(settings_ptr);
  151. std::string settings(settings_ptr, settings_len);
  152. // The cue payload is stored in the data-part of the input buffer.
  153. std::string text(input->data(), input->data() + input->data_size());
  154. scoped_refptr<TextCue> text_cue(
  155. new TextCue(input->timestamp(),
  156. input->duration(),
  157. id,
  158. settings,
  159. text));
  160. CueReady(stream, text_cue);
  161. }
  162. void TextRenderer::CueReady(
  163. DemuxerStream* text_stream,
  164. const scoped_refptr<TextCue>& text_cue) {
  165. DCHECK(task_runner_->BelongsToCurrentThread());
  166. DCHECK_NE(state_, kUninitialized);
  167. DCHECK_GT(pending_read_count_, 0);
  168. DCHECK(pending_eos_set_.find(text_stream) != pending_eos_set_.end());
  169. auto itr = text_track_state_map_.find(text_stream);
  170. DCHECK(itr != text_track_state_map_.end());
  171. TextTrackState* state = itr->second.get();
  172. DCHECK_EQ(state->read_state, TextTrackState::kReadPending);
  173. DCHECK(state->text_track);
  174. --pending_read_count_;
  175. state->read_state = TextTrackState::kReadIdle;
  176. switch (state_) {
  177. case kPlaying: {
  178. if (text_cue.get())
  179. break;
  180. const size_t count = pending_eos_set_.erase(text_stream);
  181. DCHECK_EQ(count, 1U);
  182. if (pending_eos_set_.empty()) {
  183. DCHECK_EQ(pending_read_count_, 0);
  184. state_ = kEnded;
  185. task_runner_->PostTask(FROM_HERE, ended_cb_);
  186. return;
  187. }
  188. DCHECK_GT(pending_read_count_, 0);
  189. return;
  190. }
  191. case kPausePending: {
  192. if (text_cue.get())
  193. break;
  194. const size_t count = pending_eos_set_.erase(text_stream);
  195. DCHECK_EQ(count, 1U);
  196. if (pending_read_count_ > 0) {
  197. DCHECK(!pending_eos_set_.empty());
  198. return;
  199. }
  200. state_ = kPaused;
  201. std::move(pause_cb_).Run();
  202. return;
  203. }
  204. case kPaused:
  205. case kUninitialized:
  206. case kEnded:
  207. NOTREACHED();
  208. return;
  209. }
  210. base::TimeDelta start = text_cue->timestamp();
  211. if (state->text_ranges_.AddCue(start)) {
  212. base::TimeDelta end = start + text_cue->duration();
  213. state->text_track->addWebVTTCue(start, end,
  214. text_cue->id(),
  215. text_cue->text(),
  216. text_cue->settings());
  217. }
  218. if (state_ == kPlaying) {
  219. Read(state, text_stream);
  220. return;
  221. }
  222. if (pending_read_count_ == 0) {
  223. DCHECK_EQ(state_, kPausePending) << "state_ " << state_;
  224. state_ = kPaused;
  225. std::move(pause_cb_).Run();
  226. }
  227. }
  228. void TextRenderer::OnAddTextTrackDone(DemuxerStream* text_stream,
  229. std::unique_ptr<TextTrack> text_track) {
  230. DCHECK(task_runner_->BelongsToCurrentThread());
  231. DCHECK_NE(state_, kUninitialized);
  232. DCHECK(text_stream);
  233. DCHECK(text_track);
  234. std::unique_ptr<TextTrackState> state(
  235. new TextTrackState(std::move(text_track)));
  236. text_track_state_map_[text_stream] = std::move(state);
  237. pending_eos_set_.insert(text_stream);
  238. if (state_ == kPlaying)
  239. Read(text_track_state_map_[text_stream].get(), text_stream);
  240. }
  241. void TextRenderer::Read(
  242. TextTrackState* state,
  243. DemuxerStream* text_stream) {
  244. DCHECK_NE(state->read_state, TextTrackState::kReadPending);
  245. state->read_state = TextTrackState::kReadPending;
  246. ++pending_read_count_;
  247. text_stream->Read(base::BindOnce(&TextRenderer::BufferReady,
  248. weak_factory_.GetWeakPtr(), text_stream));
  249. }
  250. TextRenderer::TextTrackState::TextTrackState(std::unique_ptr<TextTrack> tt)
  251. : read_state(kReadIdle), text_track(std::move(tt)) {}
  252. TextRenderer::TextTrackState::~TextTrackState() = default;
  253. } // namespace media