| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 | |
| 5 #include "chromecast/media/cma/ipc_streamer/av_streamer_proxy.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/location.h" | |
| 9 #include "base/single_thread_task_runner.h" | |
| 10 #include "base/threading/thread_task_runner_handle.h" | |
| 11 #include "chromecast/media/cma/base/coded_frame_provider.h" | |
| 12 #include "chromecast/media/cma/base/decoder_buffer_base.h" | |
| 13 #include "chromecast/media/cma/ipc/media_memory_chunk.h" | |
| 14 #include "chromecast/media/cma/ipc/media_message.h" | |
| 15 #include "chromecast/media/cma/ipc/media_message_fifo.h" | |
| 16 #include "chromecast/media/cma/ipc/media_message_type.h" | |
| 17 #include "chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.h" | |
| 18 #include "chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.h" | |
| 19 #include "chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.h" | |
| 20 | |
| 21 namespace chromecast { | |
| 22 namespace media { | |
| 23 | |
| 24 AvStreamerProxy::AvStreamerProxy() | |
| 25 : is_running_(false), | |
| 26 pending_read_(false), | |
| 27 pending_av_data_(false), | |
| 28 weak_factory_(this) { | |
| 29 weak_this_ = weak_factory_.GetWeakPtr(); | |
| 30 thread_checker_.DetachFromThread(); | |
| 31 } | |
| 32 | |
| 33 AvStreamerProxy::~AvStreamerProxy() { | |
| 34 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 35 } | |
| 36 | |
| 37 void AvStreamerProxy::SetCodedFrameProvider( | |
| 38 std::unique_ptr<CodedFrameProvider> frame_provider) { | |
| 39 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 40 DCHECK(!frame_provider_); | |
| 41 frame_provider_.reset(frame_provider.release()); | |
| 42 } | |
| 43 | |
| 44 void AvStreamerProxy::SetMediaMessageFifo( | |
| 45 std::unique_ptr<MediaMessageFifo> fifo) { | |
| 46 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 47 DCHECK(!fifo_); | |
| 48 fifo_.reset(fifo.release()); | |
| 49 } | |
| 50 | |
| 51 void AvStreamerProxy::Start() { | |
| 52 DCHECK(!is_running_); | |
| 53 | |
| 54 is_running_ = true; | |
| 55 RequestBufferIfNeeded(); | |
| 56 } | |
| 57 | |
| 58 void AvStreamerProxy::StopAndFlush(const base::Closure& done_cb) { | |
| 59 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 60 DCHECK(!done_cb.is_null()); | |
| 61 | |
| 62 pending_av_data_ = false; | |
| 63 pending_audio_config_ = ::media::AudioDecoderConfig(); | |
| 64 pending_video_config_ = ::media::VideoDecoderConfig(); | |
| 65 pending_buffer_ = scoped_refptr<DecoderBufferBase>(); | |
| 66 | |
| 67 pending_read_ = false; | |
| 68 is_running_ = false; | |
| 69 | |
| 70 // If there's another pending Flush, for example, the pipeline is stopped | |
| 71 // while another seek is pending, then we don't need to call Flush again. Save | |
| 72 // the callback and fire it later when Flush is done. | |
| 73 pending_stop_flush_cb_list_.push_back(done_cb); | |
| 74 if (pending_stop_flush_cb_list_.size() == 1) { | |
| 75 frame_provider_->Flush( | |
| 76 base::Bind(&AvStreamerProxy::OnStopAndFlushDone, weak_this_)); | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 void AvStreamerProxy::OnStopAndFlushDone() { | |
| 81 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 82 | |
| 83 // Flush is done. Fire all the "flush done" callbacks in order. This is | |
| 84 // necessary to guarantee proper state transition in pipeline. | |
| 85 for (const auto& cb : pending_stop_flush_cb_list_) { | |
| 86 cb.Run(); | |
| 87 } | |
| 88 pending_stop_flush_cb_list_.clear(); | |
| 89 } | |
| 90 | |
| 91 void AvStreamerProxy::OnFifoReadEvent() { | |
| 92 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 93 | |
| 94 // Some enough space might have been released | |
| 95 // to accommodate the pending data. | |
| 96 if (pending_av_data_) | |
| 97 ProcessPendingData(); | |
| 98 } | |
| 99 | |
| 100 void AvStreamerProxy::RequestBufferIfNeeded() { | |
| 101 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 102 | |
| 103 if (!is_running_ || pending_read_ || pending_av_data_) | |
| 104 return; | |
| 105 | |
| 106 // |frame_provider_| is assumed to run on the same message loop. | |
| 107 // Add a BindToCurrentLoop if that's not the case in the future. | |
| 108 pending_read_ = true; | |
| 109 frame_provider_->Read(base::Bind(&AvStreamerProxy::OnNewBuffer, weak_this_)); | |
| 110 } | |
| 111 | |
| 112 void AvStreamerProxy::OnNewBuffer( | |
| 113 const scoped_refptr<DecoderBufferBase>& buffer, | |
| 114 const ::media::AudioDecoderConfig& audio_config, | |
| 115 const ::media::VideoDecoderConfig& video_config) { | |
| 116 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 117 | |
| 118 pending_read_ = false; | |
| 119 | |
| 120 if (buffer->end_of_stream()) | |
| 121 is_running_ = false; | |
| 122 | |
| 123 DCHECK(!pending_av_data_); | |
| 124 pending_av_data_ = true; | |
| 125 | |
| 126 pending_buffer_ = buffer; | |
| 127 pending_audio_config_ = audio_config; | |
| 128 pending_video_config_ = video_config; | |
| 129 | |
| 130 ProcessPendingData(); | |
| 131 } | |
| 132 | |
| 133 void AvStreamerProxy::ProcessPendingData() { | |
| 134 if (pending_audio_config_.IsValidConfig()) { | |
| 135 if (!SendAudioDecoderConfig(pending_audio_config_)) | |
| 136 return; | |
| 137 pending_audio_config_ = ::media::AudioDecoderConfig(); | |
| 138 } | |
| 139 | |
| 140 if (pending_video_config_.IsValidConfig()) { | |
| 141 if (!SendVideoDecoderConfig(pending_video_config_)) | |
| 142 return; | |
| 143 pending_video_config_ = ::media::VideoDecoderConfig(); | |
| 144 } | |
| 145 | |
| 146 if (pending_buffer_.get()) { | |
| 147 if (!SendBuffer(pending_buffer_)) | |
| 148 return; | |
| 149 pending_buffer_ = scoped_refptr<DecoderBufferBase>(); | |
| 150 } | |
| 151 | |
| 152 pending_av_data_ = false; | |
| 153 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 154 FROM_HERE, | |
| 155 base::Bind(&AvStreamerProxy::RequestBufferIfNeeded, weak_this_)); | |
| 156 } | |
| 157 | |
| 158 bool AvStreamerProxy::SendAudioDecoderConfig( | |
| 159 const ::media::AudioDecoderConfig& config) { | |
| 160 // Create a dummy message to calculate first the message size. | |
| 161 std::unique_ptr<MediaMessage> dummy_msg( | |
| 162 MediaMessage::CreateDummyMessage(AudioConfigMediaMsg)); | |
| 163 AudioDecoderConfigMarshaller::Write(config, dummy_msg.get()); | |
| 164 | |
| 165 // Create the real message and write the actual content. | |
| 166 std::unique_ptr<MediaMessage> msg(MediaMessage::CreateMessage( | |
| 167 AudioConfigMediaMsg, base::Bind(&MediaMessageFifo::ReserveMemory, | |
| 168 base::Unretained(fifo_.get())), | |
| 169 dummy_msg->content_size())); | |
| 170 if (!msg) | |
| 171 return false; | |
| 172 | |
| 173 AudioDecoderConfigMarshaller::Write(config, msg.get()); | |
| 174 return true; | |
| 175 } | |
| 176 | |
| 177 bool AvStreamerProxy::SendVideoDecoderConfig( | |
| 178 const ::media::VideoDecoderConfig& config) { | |
| 179 // Create a dummy message to calculate first the message size. | |
| 180 std::unique_ptr<MediaMessage> dummy_msg( | |
| 181 MediaMessage::CreateDummyMessage(VideoConfigMediaMsg)); | |
| 182 VideoDecoderConfigMarshaller::Write(config, dummy_msg.get()); | |
| 183 | |
| 184 // Create the real message and write the actual content. | |
| 185 std::unique_ptr<MediaMessage> msg(MediaMessage::CreateMessage( | |
| 186 VideoConfigMediaMsg, base::Bind(&MediaMessageFifo::ReserveMemory, | |
| 187 base::Unretained(fifo_.get())), | |
| 188 dummy_msg->content_size())); | |
| 189 if (!msg) | |
| 190 return false; | |
| 191 | |
| 192 VideoDecoderConfigMarshaller::Write(config, msg.get()); | |
| 193 return true; | |
| 194 } | |
| 195 | |
| 196 bool AvStreamerProxy::SendBuffer( | |
| 197 const scoped_refptr<DecoderBufferBase>& buffer) { | |
| 198 // Create a dummy message to calculate first the message size. | |
| 199 std::unique_ptr<MediaMessage> dummy_msg( | |
| 200 MediaMessage::CreateDummyMessage(FrameMediaMsg)); | |
| 201 DecoderBufferBaseMarshaller::Write(buffer, dummy_msg.get()); | |
| 202 | |
| 203 // Create the real message and write the actual content. | |
| 204 std::unique_ptr<MediaMessage> msg(MediaMessage::CreateMessage( | |
| 205 FrameMediaMsg, base::Bind(&MediaMessageFifo::ReserveMemory, | |
| 206 base::Unretained(fifo_.get())), | |
| 207 dummy_msg->content_size())); | |
| 208 if (!msg) | |
| 209 return false; | |
| 210 | |
| 211 DecoderBufferBaseMarshaller::Write(buffer, msg.get()); | |
| 212 return true; | |
| 213 } | |
| 214 | |
| 215 } // namespace media | |
| 216 } // namespace chromecast | |
| OLD | NEW |