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/backend/video_pipeline_device.h"
9 #include "chromecast/media/cma/base/buffering_defs.h"
10 #include "chromecast/media/cma/base/cma_logging.h"
11 #include "chromecast/media/cma/base/coded_frame_provider.h"
12 #include "chromecast/media/cma/pipeline/av_pipeline_impl.h"
13 #include "media/base/video_decoder_config.h"
15 namespace chromecast
{
19 const size_t kMaxVideoFrameSize
= 1024 * 1024;
22 VideoPipelineImpl::VideoPipelineImpl(VideoPipelineDevice
* video_device
)
23 : video_device_(video_device
),
25 weak_this_
= weak_factory_
.GetWeakPtr();
26 av_pipeline_impl_
= new AvPipelineImpl(
28 base::Bind(&VideoPipelineImpl::OnUpdateConfig
, base::Unretained(this)));
31 VideoPipelineImpl::~VideoPipelineImpl() {
32 av_pipeline_impl_
->Finalize();
35 void VideoPipelineImpl::SetCodedFrameProvider(
36 scoped_ptr
<CodedFrameProvider
> frame_provider
) {
37 av_pipeline_impl_
->SetCodedFrameProvider(
38 frame_provider
.Pass(), kAppVideoBufferSize
, kMaxVideoFrameSize
);
41 bool VideoPipelineImpl::StartPlayingFrom(
43 const scoped_refptr
<BufferingState
>& buffering_state
) {
44 CMALOG(kLogControl
) << "VideoPipelineImpl::StartPlayingFrom t0="
45 << time
.InMilliseconds();
47 // Reset the pipeline statistics.
48 previous_stats_
= ::media::PipelineStatistics();
51 if (av_pipeline_impl_
->GetState() == AvPipelineImpl::kError
)
53 DCHECK_EQ(av_pipeline_impl_
->GetState(), AvPipelineImpl::kFlushed
);
55 if (!av_pipeline_impl_
->StartPlayingFrom(time
, buffering_state
)) {
56 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kError
);
59 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kPlaying
);
64 void VideoPipelineImpl::Flush(const ::media::PipelineStatusCB
& status_cb
) {
65 CMALOG(kLogControl
) << "VideoPipelineImpl::Flush";
66 if (av_pipeline_impl_
->GetState() == AvPipelineImpl::kError
) {
67 status_cb
.Run(::media::PIPELINE_ERROR_ABORT
);
70 DCHECK_EQ(av_pipeline_impl_
->GetState(), AvPipelineImpl::kPlaying
);
71 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kFlushing
);
72 av_pipeline_impl_
->Flush(
73 base::Bind(&VideoPipelineImpl::OnFlushDone
, weak_this_
, status_cb
));
76 void VideoPipelineImpl::OnFlushDone(
77 const ::media::PipelineStatusCB
& status_cb
) {
78 CMALOG(kLogControl
) << "VideoPipelineImpl::OnFlushDone";
79 if (av_pipeline_impl_
->GetState() == AvPipelineImpl::kError
) {
80 status_cb
.Run(::media::PIPELINE_ERROR_ABORT
);
83 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kFlushed
);
84 status_cb
.Run(::media::PIPELINE_OK
);
87 void VideoPipelineImpl::Stop() {
88 CMALOG(kLogControl
) << "VideoPipelineImpl::Stop";
89 av_pipeline_impl_
->Stop();
90 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kStopped
);
93 void VideoPipelineImpl::SetCdm(BrowserCdmCast
* media_keys
) {
94 av_pipeline_impl_
->SetCdm(media_keys
);
97 void VideoPipelineImpl::SetClient(const VideoPipelineClient
& client
) {
98 video_client_
= client
;
99 av_pipeline_impl_
->SetClient(client
.av_pipeline_client
);
102 void VideoPipelineImpl::Initialize(
103 const ::media::VideoDecoderConfig
& video_config
,
104 scoped_ptr
<CodedFrameProvider
> frame_provider
,
105 const ::media::PipelineStatusCB
& status_cb
) {
106 CMALOG(kLogControl
) << "VideoPipelineImpl::Initialize "
107 << video_config
.AsHumanReadableString();
108 VideoPipelineDevice::VideoClient client
;
109 client
.natural_size_changed_cb
=
110 base::Bind(&VideoPipelineImpl::OnNaturalSizeChanged
, weak_this_
);
111 video_device_
->SetVideoClient(client
);
113 SetCodedFrameProvider(frame_provider
.Pass());
115 if (!video_device_
->SetConfig(video_config
) ||
116 !av_pipeline_impl_
->Initialize()) {
117 status_cb
.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED
);
120 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kFlushed
);
121 status_cb
.Run(::media::PIPELINE_OK
);
124 void VideoPipelineImpl::OnUpdateConfig(
125 const ::media::AudioDecoderConfig
& audio_config
,
126 const ::media::VideoDecoderConfig
& video_config
) {
127 if (video_config
.IsValidConfig()) {
128 CMALOG(kLogControl
) << "VideoPipelineImpl::OnUpdateConfig "
129 << video_config
.AsHumanReadableString();
131 bool success
= video_device_
->SetConfig(video_config
);
133 !video_client_
.av_pipeline_client
.playback_error_cb
.is_null()) {
134 video_client_
.av_pipeline_client
.playback_error_cb
.Run(
135 ::media::PIPELINE_ERROR_DECODE
);
140 void VideoPipelineImpl::OnNaturalSizeChanged(const gfx::Size
& size
) {
141 if (av_pipeline_impl_
->GetState() != AvPipelineImpl::kPlaying
)
144 if (!video_client_
.natural_size_changed_cb
.is_null())
145 video_client_
.natural_size_changed_cb
.Run(size
);
148 void VideoPipelineImpl::UpdateStatistics() {
149 if (video_client_
.av_pipeline_client
.statistics_cb
.is_null())
152 MediaComponentDevice::Statistics device_stats
;
153 if (!video_device_
->GetStatistics(&device_stats
))
156 ::media::PipelineStatistics current_stats
;
157 current_stats
.video_bytes_decoded
= device_stats
.decoded_bytes
;
158 current_stats
.video_frames_decoded
= device_stats
.decoded_samples
;
159 current_stats
.video_frames_dropped
= device_stats
.dropped_samples
;
161 ::media::PipelineStatistics delta_stats
;
162 delta_stats
.video_bytes_decoded
=
163 current_stats
.video_bytes_decoded
- previous_stats_
.video_bytes_decoded
;
164 delta_stats
.video_frames_decoded
=
165 current_stats
.video_frames_decoded
- previous_stats_
.video_frames_decoded
;
166 delta_stats
.video_frames_dropped
=
167 current_stats
.video_frames_dropped
- previous_stats_
.video_frames_dropped
;
169 previous_stats_
= current_stats
;
171 video_client_
.av_pipeline_client
.statistics_cb
.Run(delta_stats
);
175 } // namespace chromecast