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/pipeline/video_pipeline_impl.h"
8 #include "chromecast/media/cma/base/buffering_defs.h"
9 #include "chromecast/media/cma/base/cma_logging.h"
10 #include "chromecast/media/cma/base/coded_frame_provider.h"
11 #include "chromecast/media/cma/base/decoder_config_adapter.h"
12 #include "chromecast/media/cma/pipeline/av_pipeline_impl.h"
13 #include "chromecast/media/cma/pipeline/video_pipeline_device_client_impl.h"
14 #include "chromecast/public/graphics_types.h"
15 #include "chromecast/public/media/decoder_config.h"
16 #include "chromecast/public/media/video_pipeline_device.h"
17 #include "media/base/video_decoder_config.h"
19 namespace chromecast
{
23 const size_t kMaxVideoFrameSize
= 1024 * 1024;
26 VideoPipelineImpl::VideoPipelineImpl(VideoPipelineDevice
* video_device
)
27 : video_device_(video_device
),
29 weak_this_
= weak_factory_
.GetWeakPtr();
30 av_pipeline_impl_
.reset(new AvPipelineImpl(
32 base::Bind(&VideoPipelineImpl::OnUpdateConfig
, base::Unretained(this))));
35 VideoPipelineImpl::~VideoPipelineImpl() {
38 void VideoPipelineImpl::SetCodedFrameProvider(
39 scoped_ptr
<CodedFrameProvider
> frame_provider
) {
40 av_pipeline_impl_
->SetCodedFrameProvider(
41 frame_provider
.Pass(), kAppVideoBufferSize
, kMaxVideoFrameSize
);
44 bool VideoPipelineImpl::StartPlayingFrom(
46 const scoped_refptr
<BufferingState
>& buffering_state
) {
47 CMALOG(kLogControl
) << "VideoPipelineImpl::StartPlayingFrom t0="
48 << time
.InMilliseconds();
50 // Reset the pipeline statistics.
51 previous_stats_
= ::media::PipelineStatistics();
54 if (av_pipeline_impl_
->GetState() == AvPipelineImpl::kError
)
56 DCHECK_EQ(av_pipeline_impl_
->GetState(), AvPipelineImpl::kFlushed
);
58 if (!av_pipeline_impl_
->StartPlayingFrom(time
, buffering_state
)) {
59 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kError
);
62 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kPlaying
);
67 void VideoPipelineImpl::Flush(const ::media::PipelineStatusCB
& status_cb
) {
68 CMALOG(kLogControl
) << "VideoPipelineImpl::Flush";
69 if (av_pipeline_impl_
->GetState() == AvPipelineImpl::kError
) {
70 status_cb
.Run(::media::PIPELINE_ERROR_ABORT
);
73 DCHECK_EQ(av_pipeline_impl_
->GetState(), AvPipelineImpl::kPlaying
);
74 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kFlushing
);
75 av_pipeline_impl_
->Flush(
76 base::Bind(&VideoPipelineImpl::OnFlushDone
, weak_this_
, status_cb
));
79 void VideoPipelineImpl::OnFlushDone(
80 const ::media::PipelineStatusCB
& status_cb
) {
81 CMALOG(kLogControl
) << "VideoPipelineImpl::OnFlushDone";
82 if (av_pipeline_impl_
->GetState() == AvPipelineImpl::kError
) {
83 status_cb
.Run(::media::PIPELINE_ERROR_ABORT
);
86 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kFlushed
);
87 status_cb
.Run(::media::PIPELINE_OK
);
90 void VideoPipelineImpl::Stop() {
91 CMALOG(kLogControl
) << "VideoPipelineImpl::Stop";
92 av_pipeline_impl_
->Stop();
93 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kStopped
);
96 void VideoPipelineImpl::SetCdm(BrowserCdmCast
* media_keys
) {
97 av_pipeline_impl_
->SetCdm(media_keys
);
100 void VideoPipelineImpl::SetClient(const VideoPipelineClient
& client
) {
101 video_client_
= client
;
102 av_pipeline_impl_
->SetClient(client
.av_pipeline_client
);
105 void VideoPipelineImpl::Initialize(
106 const std::vector
<::media::VideoDecoderConfig
>& configs
,
107 scoped_ptr
<CodedFrameProvider
> frame_provider
,
108 const ::media::PipelineStatusCB
& status_cb
) {
109 DCHECK_GT(configs
.size(), 0u);
110 for (const auto& config
: configs
) {
111 CMALOG(kLogControl
) << __FUNCTION__
<< " "
112 << config
.AsHumanReadableString();
114 video_device_
->SetVideoClient(new VideoPipelineDeviceClientImpl(
115 base::Bind(&VideoPipelineImpl::OnNaturalSizeChanged
, weak_this_
)));
117 SetCodedFrameProvider(frame_provider
.Pass());
119 if (configs
.empty()) {
120 status_cb
.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED
);
123 DCHECK(configs
.size() <= 2);
124 DCHECK(configs
[0].IsValidConfig());
125 VideoConfig video_config
=
126 DecoderConfigAdapter::ToCastVideoConfig(kPrimary
, configs
[0]);
127 VideoConfig secondary_config
;
128 if (configs
.size() == 2) {
129 DCHECK(configs
[1].IsValidConfig());
130 secondary_config
= DecoderConfigAdapter::ToCastVideoConfig(kSecondary
,
132 video_config
.additional_config
= &secondary_config
;
135 if (!video_device_
->SetConfig(video_config
) ||
136 !av_pipeline_impl_
->Initialize()) {
137 status_cb
.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED
);
140 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kFlushed
);
141 status_cb
.Run(::media::PIPELINE_OK
);
144 void VideoPipelineImpl::OnUpdateConfig(
146 const ::media::AudioDecoderConfig
& audio_config
,
147 const ::media::VideoDecoderConfig
& video_config
) {
148 if (video_config
.IsValidConfig()) {
149 CMALOG(kLogControl
) << "VideoPipelineImpl::OnUpdateConfig id:" << id
<< " "
150 << video_config
.AsHumanReadableString();
152 bool success
= video_device_
->SetConfig(
153 DecoderConfigAdapter::ToCastVideoConfig(id
, video_config
));
155 !video_client_
.av_pipeline_client
.playback_error_cb
.is_null()) {
156 video_client_
.av_pipeline_client
.playback_error_cb
.Run(
157 ::media::PIPELINE_ERROR_DECODE
);
162 void VideoPipelineImpl::OnNaturalSizeChanged(const Size
& size
) {
163 if (av_pipeline_impl_
->GetState() != AvPipelineImpl::kPlaying
)
166 if (!video_client_
.natural_size_changed_cb
.is_null()) {
167 video_client_
.natural_size_changed_cb
.Run(
168 gfx::Size(size
.width
, size
.height
));
172 void VideoPipelineImpl::UpdateStatistics() {
173 if (video_client_
.av_pipeline_client
.statistics_cb
.is_null())
176 MediaComponentDevice::Statistics device_stats
;
177 if (!video_device_
->GetStatistics(&device_stats
))
180 ::media::PipelineStatistics current_stats
;
181 current_stats
.video_bytes_decoded
= device_stats
.decoded_bytes
;
182 current_stats
.video_frames_decoded
= device_stats
.decoded_samples
;
183 current_stats
.video_frames_dropped
= device_stats
.dropped_samples
;
185 ::media::PipelineStatistics delta_stats
;
186 delta_stats
.video_bytes_decoded
=
187 current_stats
.video_bytes_decoded
- previous_stats_
.video_bytes_decoded
;
188 delta_stats
.video_frames_decoded
=
189 current_stats
.video_frames_decoded
- previous_stats_
.video_frames_decoded
;
190 delta_stats
.video_frames_dropped
=
191 current_stats
.video_frames_dropped
- previous_stats_
.video_frames_dropped
;
193 previous_stats_
= current_stats
;
195 video_client_
.av_pipeline_client
.statistics_cb
.Run(delta_stats
);
199 } // namespace chromecast