webcodecs_encoded_chunk_stream_parser.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Copyright 2020 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/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.h"
  5. #include <string>
  6. #include "base/callback.h"
  7. #include "base/logging.h"
  8. #include "base/notreached.h"
  9. #include "media/base/media_log.h"
  10. #include "media/base/media_track.h"
  11. #include "media/base/media_tracks.h"
  12. #include "media/base/stream_parser_buffer.h"
  13. #include "media/base/text_track_config.h"
  14. #include "media/base/timestamp_constants.h"
  15. namespace {
  16. // TODO(crbug.com/1144908): Since these must be identical to those generated
  17. // in the SourceBuffer, consider moving these to possibly stream_parser.h.
  18. // Meanwhile, must be kept in sync with similar constexpr in SourceBuffer
  19. // manually.
  20. constexpr media::StreamParser::TrackId kWebCodecsAudioTrackId = 1;
  21. constexpr media::StreamParser::TrackId kWebCodecsVideoTrackId = 2;
  22. } // namespace
  23. namespace media {
  24. WebCodecsEncodedChunkStreamParser::WebCodecsEncodedChunkStreamParser(
  25. std::unique_ptr<AudioDecoderConfig> audio_config)
  26. : state_(kWaitingForInit), audio_config_(std::move(audio_config)) {
  27. DCHECK(audio_config_ && !video_config_);
  28. }
  29. WebCodecsEncodedChunkStreamParser::WebCodecsEncodedChunkStreamParser(
  30. std::unique_ptr<VideoDecoderConfig> video_config)
  31. : state_(kWaitingForInit), video_config_(std::move(video_config)) {
  32. DCHECK(video_config_ && !audio_config_);
  33. }
  34. WebCodecsEncodedChunkStreamParser::~WebCodecsEncodedChunkStreamParser() =
  35. default;
  36. void WebCodecsEncodedChunkStreamParser::Init(
  37. InitCB init_cb,
  38. const NewConfigCB& config_cb,
  39. const NewBuffersCB& new_buffers_cb,
  40. bool /* ignore_text_tracks */,
  41. const EncryptedMediaInitDataCB& /* ignored */,
  42. const NewMediaSegmentCB& new_segment_cb,
  43. const EndMediaSegmentCB& end_of_segment_cb,
  44. MediaLog* media_log) {
  45. DCHECK_EQ(state_, kWaitingForInit);
  46. DCHECK(!init_cb_);
  47. DCHECK(init_cb);
  48. DCHECK(config_cb);
  49. DCHECK(new_buffers_cb);
  50. DCHECK(new_segment_cb);
  51. DCHECK(end_of_segment_cb);
  52. ChangeState(kWaitingForConfigEmission);
  53. init_cb_ = std::move(init_cb);
  54. config_cb_ = config_cb;
  55. new_buffers_cb_ = new_buffers_cb;
  56. new_segment_cb_ = new_segment_cb;
  57. end_of_segment_cb_ = end_of_segment_cb;
  58. media_log_ = media_log;
  59. }
  60. void WebCodecsEncodedChunkStreamParser::Flush() {
  61. DCHECK_NE(state_, kWaitingForInit);
  62. if (state_ == kWaitingForEncodedChunks)
  63. ChangeState(kWaitingForConfigEmission);
  64. }
  65. bool WebCodecsEncodedChunkStreamParser::GetGenerateTimestampsFlag() const {
  66. return false;
  67. }
  68. bool WebCodecsEncodedChunkStreamParser::Parse(const uint8_t* /* buf */,
  69. int /* size */) {
  70. // TODO(crbug.com/1144908): Protect against app reaching this (and similer
  71. // inverse case in other parsers) simply by using the wrong append method on
  72. // the SourceBuffer. Maybe a better MEDIA_LOG here would be sufficient? Or
  73. // instead have the top-level SourceBuffer throw synchronous exception when
  74. // attempting the wrong append method, without causing parse/decode error?
  75. NOTREACHED(); // ProcessChunks() is the method to use instead for this
  76. // parser.
  77. return false;
  78. }
  79. bool WebCodecsEncodedChunkStreamParser::ProcessChunks(
  80. std::unique_ptr<BufferQueue> buffer_queue) {
  81. DCHECK_NE(state_, kWaitingForInit);
  82. if (state_ == kError)
  83. return false;
  84. if (state_ == kWaitingForConfigEmission) {
  85. // Must (still) have only one config. We'll retain ownership.
  86. // MediaTracks::AddAudio/VideoTrack copies the config.
  87. DCHECK((audio_config_ && !video_config_) ||
  88. (video_config_ && !audio_config_));
  89. auto media_tracks = std::make_unique<MediaTracks>();
  90. if (audio_config_) {
  91. media_tracks->AddAudioTrack(
  92. *audio_config_, kWebCodecsAudioTrackId, MediaTrack::Kind("main"),
  93. MediaTrack::Label(""), MediaTrack::Language(""));
  94. } else if (video_config_) {
  95. media_tracks->AddVideoTrack(
  96. *video_config_, kWebCodecsVideoTrackId, MediaTrack::Kind("main"),
  97. MediaTrack::Label(""), MediaTrack::Language(""));
  98. }
  99. if (!config_cb_.Run(std::move(media_tracks), TextTrackConfigMap())) {
  100. ChangeState(kError);
  101. return false;
  102. }
  103. if (init_cb_) {
  104. InitParameters params(kInfiniteDuration);
  105. params.liveness = StreamLiveness::kUnknown;
  106. if (audio_config_)
  107. params.detected_audio_track_count = 1;
  108. if (video_config_)
  109. params.detected_video_track_count = 1;
  110. params.detected_text_track_count = 0;
  111. std::move(init_cb_).Run(params);
  112. }
  113. ChangeState(kWaitingForEncodedChunks);
  114. }
  115. DCHECK_EQ(state_, kWaitingForEncodedChunks);
  116. // All of |buffer_queue| must be of the media type (audio or video)
  117. // corresponding to the exactly one type of decoder config we have. Otherwise,
  118. // the caller has provided encoded chunks for the wrong kind of config.
  119. DemuxerStream::Type expected_type =
  120. audio_config_ ? DemuxerStream::AUDIO : DemuxerStream::VIDEO;
  121. for (const auto& it : *buffer_queue) {
  122. if (it->type() != expected_type) {
  123. MEDIA_LOG(ERROR, media_log_)
  124. << "Incorrect EncodedChunk type (audio vs video) appended";
  125. ChangeState(kError);
  126. return false;
  127. }
  128. }
  129. // TODO(crbug.com/1144908): Add a different new_buffers_cb type for us to use
  130. // so that we can just std::move the buffer_queue, and avoid potential issues
  131. // with out-of-order timestamps in the caller-provided queue that would
  132. // otherwise cause parse failure in MergeBufferQueues with the current, legacy
  133. // style of new_buffers_cb that depends on parsers to emit sanely time-ordered
  134. // groups of frames from *muxed* multi-track bytestreams. FrameProcessor is
  135. // capable of handling our buffer_queue verbatim.
  136. BufferQueueMap buffers;
  137. if (audio_config_)
  138. buffers.insert(std::make_pair(kWebCodecsAudioTrackId, *buffer_queue));
  139. else
  140. buffers.insert(std::make_pair(kWebCodecsVideoTrackId, *buffer_queue));
  141. new_segment_cb_.Run();
  142. if (!new_buffers_cb_.Run(buffers))
  143. return false;
  144. end_of_segment_cb_.Run();
  145. return true;
  146. }
  147. void WebCodecsEncodedChunkStreamParser::ChangeState(State new_state) {
  148. DVLOG(1) << __func__ << ": " << state_ << " -> " << new_state;
  149. state_ = new_state;
  150. }
  151. } // namespace media