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 pending_av_data_
= false;
60 pending_audio_config_
= ::media::AudioDecoderConfig();
61 pending_video_config_
= ::media::VideoDecoderConfig();
62 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
64 pending_read_
= false;
66 // StopAndFlush may happen twice in a row when Stop happens while a previous
67 // pending Seek (which requires Flush). We only need to perform Flush once
68 // when entering stopped state. Chromium pipeline will call Start eventually
69 // to set is_running_, after Seek (next state of Seek is Play), which
70 // guarantees Flush be called when there is no pending tasks.
72 frame_provider_
->Flush(done_cb
);
77 void AvStreamerProxy::OnFifoReadEvent() {
78 DCHECK(thread_checker_
.CalledOnValidThread());
80 // Some enough space might have been released
81 // to accommodate the pending data.
86 void AvStreamerProxy::RequestBufferIfNeeded() {
87 DCHECK(thread_checker_
.CalledOnValidThread());
89 if (!is_running_
|| pending_read_
|| pending_av_data_
)
92 // |frame_provider_| is assumed to run on the same message loop.
93 // Add a BindToCurrentLoop if that's not the case in the future.
95 frame_provider_
->Read(base::Bind(&AvStreamerProxy::OnNewBuffer
, weak_this_
));
98 void AvStreamerProxy::OnNewBuffer(
99 const scoped_refptr
<DecoderBufferBase
>& buffer
,
100 const ::media::AudioDecoderConfig
& audio_config
,
101 const ::media::VideoDecoderConfig
& video_config
) {
102 DCHECK(thread_checker_
.CalledOnValidThread());
104 pending_read_
= false;
106 if (buffer
->end_of_stream())
109 DCHECK(!pending_av_data_
);
110 pending_av_data_
= true;
112 pending_buffer_
= buffer
;
113 pending_audio_config_
= audio_config
;
114 pending_video_config_
= video_config
;
116 ProcessPendingData();
119 void AvStreamerProxy::ProcessPendingData() {
120 if (pending_audio_config_
.IsValidConfig()) {
121 if (!SendAudioDecoderConfig(pending_audio_config_
))
123 pending_audio_config_
= ::media::AudioDecoderConfig();
126 if (pending_video_config_
.IsValidConfig()) {
127 if (!SendVideoDecoderConfig(pending_video_config_
))
129 pending_video_config_
= ::media::VideoDecoderConfig();
132 if (pending_buffer_
.get()) {
133 if (!SendBuffer(pending_buffer_
))
135 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
138 pending_av_data_
= false;
139 base::ThreadTaskRunnerHandle::Get()->PostTask(
141 base::Bind(&AvStreamerProxy::RequestBufferIfNeeded
, weak_this_
));
144 bool AvStreamerProxy::SendAudioDecoderConfig(
145 const ::media::AudioDecoderConfig
& config
) {
146 // Create a dummy message to calculate first the message size.
147 scoped_ptr
<MediaMessage
> dummy_msg(
148 MediaMessage::CreateDummyMessage(AudioConfigMediaMsg
));
149 AudioDecoderConfigMarshaller::Write(config
, dummy_msg
.get());
151 // Create the real message and write the actual content.
152 scoped_ptr
<MediaMessage
> msg(
153 MediaMessage::CreateMessage(
155 base::Bind(&MediaMessageFifo::ReserveMemory
,
156 base::Unretained(fifo_
.get())),
157 dummy_msg
->content_size()));
161 AudioDecoderConfigMarshaller::Write(config
, msg
.get());
165 bool AvStreamerProxy::SendVideoDecoderConfig(
166 const ::media::VideoDecoderConfig
& config
) {
167 // Create a dummy message to calculate first the message size.
168 scoped_ptr
<MediaMessage
> dummy_msg(
169 MediaMessage::CreateDummyMessage(VideoConfigMediaMsg
));
170 VideoDecoderConfigMarshaller::Write(config
, dummy_msg
.get());
172 // Create the real message and write the actual content.
173 scoped_ptr
<MediaMessage
> msg(
174 MediaMessage::CreateMessage(
176 base::Bind(&MediaMessageFifo::ReserveMemory
,
177 base::Unretained(fifo_
.get())),
178 dummy_msg
->content_size()));
182 VideoDecoderConfigMarshaller::Write(config
, msg
.get());
186 bool AvStreamerProxy::SendBuffer(
187 const scoped_refptr
<DecoderBufferBase
>& buffer
) {
188 // Create a dummy message to calculate first the message size.
189 scoped_ptr
<MediaMessage
> dummy_msg(
190 MediaMessage::CreateDummyMessage(FrameMediaMsg
));
191 DecoderBufferBaseMarshaller::Write(buffer
, dummy_msg
.get());
193 // Create the real message and write the actual content.
194 scoped_ptr
<MediaMessage
> msg(
195 MediaMessage::CreateMessage(
197 base::Bind(&MediaMessageFifo::ReserveMemory
,
198 base::Unretained(fifo_
.get())),
199 dummy_msg
->content_size()));
203 DecoderBufferBaseMarshaller::Write(buffer
, msg
.get());
208 } // namespace chromecast