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 "media/mojo/services/mojo_demuxer_stream_impl.h"
8 #include "base/macros.h"
9 #include "media/base/audio_decoder_config.h"
10 #include "media/base/decoder_buffer.h"
11 #include "media/base/video_decoder_config.h"
12 #include "media/mojo/interfaces/demuxer_stream.mojom.h"
13 #include "media/mojo/services/media_type_converters.h"
14 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_impl.h"
15 #include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
19 MojoDemuxerStreamImpl::MojoDemuxerStreamImpl(media::DemuxerStream
* stream
)
20 : stream_(stream
), weak_factory_(this) {
23 MojoDemuxerStreamImpl::~MojoDemuxerStreamImpl() {
26 // This is called when our DemuxerStreamClient has connected itself and is
27 // ready to receive messages. Send an initial config and notify it that
28 // we are now ready for business.
29 void MojoDemuxerStreamImpl::Initialize(const InitializeCallback
& callback
) {
30 DVLOG(2) << __FUNCTION__
;
31 MojoCreateDataPipeOptions options
;
32 options
.struct_size
= sizeof(MojoCreateDataPipeOptions
);
33 options
.flags
= MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
;
34 options
.element_num_bytes
= 1;
36 // Allocate DataPipe sizes based on content type to reduce overhead. If this
37 // is still too burdensome we can adjust for sample rate or resolution.
38 if (stream_
->type() == media::DemuxerStream::VIDEO
) {
39 // Video can get quite large; at 4K, VP9 delivers packets which are ~1MB in
40 // size; so allow for 50% headroom.
41 options
.capacity_num_bytes
= 1.5 * (1024 * 1024);
43 // Other types don't require a lot of room, so use a smaller pipe.
44 options
.capacity_num_bytes
= 512 * 1024;
47 mojo::DataPipe
data_pipe(options
);
48 stream_pipe_
= data_pipe
.producer_handle
.Pass();
50 // Prepare the initial config.
51 mojo::AudioDecoderConfigPtr audio_config
;
52 mojo::VideoDecoderConfigPtr video_config
;
53 if (stream_
->type() == media::DemuxerStream::AUDIO
) {
55 mojo::AudioDecoderConfig::From(stream_
->audio_decoder_config());
56 } else if (stream_
->type() == media::DemuxerStream::VIDEO
) {
58 mojo::VideoDecoderConfig::From(stream_
->video_decoder_config());
60 NOTREACHED() << "Unsupported stream type: " << stream_
->type();
64 callback
.Run(static_cast<mojo::DemuxerStream::Type
>(stream_
->type()),
65 data_pipe
.consumer_handle
.Pass(), audio_config
.Pass(),
69 void MojoDemuxerStreamImpl::Read(const ReadCallback
& callback
) {
70 stream_
->Read(base::Bind(&MojoDemuxerStreamImpl::OnBufferReady
,
71 weak_factory_
.GetWeakPtr(), callback
));
74 void MojoDemuxerStreamImpl::OnBufferReady(
75 const ReadCallback
& callback
,
76 media::DemuxerStream::Status status
,
77 const scoped_refptr
<media::DecoderBuffer
>& buffer
) {
78 mojo::AudioDecoderConfigPtr audio_config
;
79 mojo::VideoDecoderConfigPtr video_config
;
81 if (status
== media::DemuxerStream::kConfigChanged
) {
82 DVLOG(2) << __FUNCTION__
<< ": ConfigChange!";
83 // Send the config change so our client can read it once it parses the
84 // Status obtained via Run() below.
85 if (stream_
->type() == media::DemuxerStream::AUDIO
) {
87 mojo::AudioDecoderConfig::From(stream_
->audio_decoder_config());
88 } else if (stream_
->type() == media::DemuxerStream::VIDEO
) {
90 mojo::VideoDecoderConfig::From(stream_
->video_decoder_config());
92 NOTREACHED() << "Unsupported config change encountered for type: "
96 callback
.Run(mojo::DemuxerStream::STATUS_CONFIG_CHANGED
,
97 mojo::MediaDecoderBufferPtr(), audio_config
.Pass(),
102 if (status
== media::DemuxerStream::kAborted
) {
103 callback
.Run(mojo::DemuxerStream::STATUS_ABORTED
,
104 mojo::MediaDecoderBufferPtr(), audio_config
.Pass(),
105 video_config
.Pass());
109 DCHECK_EQ(status
, media::DemuxerStream::kOk
);
110 if (!buffer
->end_of_stream()) {
111 DCHECK_GT(buffer
->data_size(), 0);
112 // Serialize the data section of the DecoderBuffer into our pipe.
113 uint32_t num_bytes
= buffer
->data_size();
114 CHECK_EQ(WriteDataRaw(stream_pipe_
.get(), buffer
->data(), &num_bytes
,
115 MOJO_READ_DATA_FLAG_ALL_OR_NONE
),
117 CHECK_EQ(num_bytes
, static_cast<uint32_t>(buffer
->data_size()));
120 // TODO(dalecurtis): Once we can write framed data to the DataPipe, fill via
121 // the producer handle and then read more to keep the pipe full. Waiting for
122 // space can be accomplished using an AsyncWaiter.
123 callback
.Run(static_cast<mojo::DemuxerStream::Status
>(status
),
124 mojo::MediaDecoderBuffer::From(buffer
), audio_config
.Pass(),
125 video_config
.Pass());