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.
5 #include "chromecast/media/cma/ipc_streamer/av_streamer_proxy.h"
8 #include "base/location.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/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"
21 namespace chromecast
{
24 AvStreamerProxy::AvStreamerProxy()
27 pending_av_data_(false),
29 weak_this_
= weak_factory_
.GetWeakPtr();
30 thread_checker_
.DetachFromThread();
33 AvStreamerProxy::~AvStreamerProxy() {
34 DCHECK(thread_checker_
.CalledOnValidThread());
37 void AvStreamerProxy::SetCodedFrameProvider(
38 scoped_ptr
<CodedFrameProvider
> frame_provider
) {
39 DCHECK(thread_checker_
.CalledOnValidThread());
40 DCHECK(!frame_provider_
);
41 frame_provider_
.reset(frame_provider
.release());
44 void AvStreamerProxy::SetMediaMessageFifo(
45 scoped_ptr
<MediaMessageFifo
> fifo
) {
46 DCHECK(thread_checker_
.CalledOnValidThread());
48 fifo_
.reset(fifo
.release());
51 void AvStreamerProxy::Start() {
55 RequestBufferIfNeeded();
58 void AvStreamerProxy::StopAndFlush(const base::Closure
& done_cb
) {
59 DCHECK(thread_checker_
.CalledOnValidThread());
60 DCHECK(!done_cb
.is_null());
62 pending_av_data_
= false;
63 pending_audio_config_
= ::media::AudioDecoderConfig();
64 pending_video_config_
= ::media::VideoDecoderConfig();
65 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
67 pending_read_
= false;
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_
));
80 void AvStreamerProxy::OnStopAndFlushDone() {
81 DCHECK(thread_checker_
.CalledOnValidThread());
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_
) {
88 pending_stop_flush_cb_list_
.clear();
91 void AvStreamerProxy::OnFifoReadEvent() {
92 DCHECK(thread_checker_
.CalledOnValidThread());
94 // Some enough space might have been released
95 // to accommodate the pending data.
100 void AvStreamerProxy::RequestBufferIfNeeded() {
101 DCHECK(thread_checker_
.CalledOnValidThread());
103 if (!is_running_
|| pending_read_
|| pending_av_data_
)
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_
));
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());
118 pending_read_
= false;
120 if (buffer
->end_of_stream())
123 DCHECK(!pending_av_data_
);
124 pending_av_data_
= true;
126 pending_buffer_
= buffer
;
127 pending_audio_config_
= audio_config
;
128 pending_video_config_
= video_config
;
130 ProcessPendingData();
133 void AvStreamerProxy::ProcessPendingData() {
134 if (pending_audio_config_
.IsValidConfig()) {
135 if (!SendAudioDecoderConfig(pending_audio_config_
))
137 pending_audio_config_
= ::media::AudioDecoderConfig();
140 if (pending_video_config_
.IsValidConfig()) {
141 if (!SendVideoDecoderConfig(pending_video_config_
))
143 pending_video_config_
= ::media::VideoDecoderConfig();
146 if (pending_buffer_
.get()) {
147 if (!SendBuffer(pending_buffer_
))
149 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
152 pending_av_data_
= false;
153 base::ThreadTaskRunnerHandle::Get()->PostTask(
155 base::Bind(&AvStreamerProxy::RequestBufferIfNeeded
, weak_this_
));
158 bool AvStreamerProxy::SendAudioDecoderConfig(
159 const ::media::AudioDecoderConfig
& config
) {
160 // Create a dummy message to calculate first the message size.
161 scoped_ptr
<MediaMessage
> dummy_msg(
162 MediaMessage::CreateDummyMessage(AudioConfigMediaMsg
));
163 AudioDecoderConfigMarshaller::Write(config
, dummy_msg
.get());
165 // Create the real message and write the actual content.
166 scoped_ptr
<MediaMessage
> msg(
167 MediaMessage::CreateMessage(
169 base::Bind(&MediaMessageFifo::ReserveMemory
,
170 base::Unretained(fifo_
.get())),
171 dummy_msg
->content_size()));
175 AudioDecoderConfigMarshaller::Write(config
, msg
.get());
179 bool AvStreamerProxy::SendVideoDecoderConfig(
180 const ::media::VideoDecoderConfig
& config
) {
181 // Create a dummy message to calculate first the message size.
182 scoped_ptr
<MediaMessage
> dummy_msg(
183 MediaMessage::CreateDummyMessage(VideoConfigMediaMsg
));
184 VideoDecoderConfigMarshaller::Write(config
, dummy_msg
.get());
186 // Create the real message and write the actual content.
187 scoped_ptr
<MediaMessage
> msg(
188 MediaMessage::CreateMessage(
190 base::Bind(&MediaMessageFifo::ReserveMemory
,
191 base::Unretained(fifo_
.get())),
192 dummy_msg
->content_size()));
196 VideoDecoderConfigMarshaller::Write(config
, msg
.get());
200 bool AvStreamerProxy::SendBuffer(
201 const scoped_refptr
<DecoderBufferBase
>& buffer
) {
202 // Create a dummy message to calculate first the message size.
203 scoped_ptr
<MediaMessage
> dummy_msg(
204 MediaMessage::CreateDummyMessage(FrameMediaMsg
));
205 DecoderBufferBaseMarshaller::Write(buffer
, dummy_msg
.get());
207 // Create the real message and write the actual content.
208 scoped_ptr
<MediaMessage
> msg(
209 MediaMessage::CreateMessage(
211 base::Bind(&MediaMessageFifo::ReserveMemory
,
212 base::Unretained(fifo_
.get())),
213 dummy_msg
->content_size()));
217 DecoderBufferBaseMarshaller::Write(buffer
, msg
.get());
222 } // namespace chromecast