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 "mojo/public/cpp/bindings/interface_impl.h"
15 #include "mojo/public/cpp/system/data_pipe.h"
19 MojoDemuxerStreamImpl::MojoDemuxerStreamImpl(media::DemuxerStream
* stream
)
20 : stream_(stream
), weak_factory_(this) {
23 MojoDemuxerStreamImpl::~MojoDemuxerStreamImpl() {
26 void MojoDemuxerStreamImpl::Read(const mojo::Callback
<
27 void(mojo::DemuxerStream::Status
, mojo::MediaDecoderBufferPtr
)>& callback
) {
28 stream_
->Read(base::Bind(&MojoDemuxerStreamImpl::OnBufferReady
,
29 weak_factory_
.GetWeakPtr(),
33 void MojoDemuxerStreamImpl::OnBufferReady(
34 const BufferReadyCB
& callback
,
35 media::DemuxerStream::Status status
,
36 const scoped_refptr
<media::DecoderBuffer
>& buffer
) {
37 if (status
== media::DemuxerStream::kConfigChanged
) {
38 // Send the config change so our client can read it once it parses the
39 // Status obtained via Run() below.
40 if (stream_
->type() == media::DemuxerStream::AUDIO
) {
41 client()->OnAudioDecoderConfigChanged(
42 mojo::AudioDecoderConfig::From(stream_
->audio_decoder_config()));
43 } else if (stream_
->type() == media::DemuxerStream::VIDEO
) {
44 client()->OnVideoDecoderConfigChanged(
45 mojo::VideoDecoderConfig::From(stream_
->video_decoder_config()));
47 NOTREACHED() << "Unsupported config change encountered for type: "
51 callback
.Run(mojo::DemuxerStream::STATUS_CONFIG_CHANGED
,
52 mojo::MediaDecoderBufferPtr());
56 if (status
== media::DemuxerStream::kAborted
) {
57 callback
.Run(mojo::DemuxerStream::STATUS_ABORTED
,
58 mojo::MediaDecoderBufferPtr());
62 DCHECK_EQ(status
, media::DemuxerStream::kOk
);
63 if (!buffer
->end_of_stream()) {
64 DCHECK_GT(buffer
->data_size(), 0);
65 // Serialize the data section of the DecoderBuffer into our pipe.
66 uint32_t num_bytes
= buffer
->data_size();
67 CHECK_EQ(WriteDataRaw(stream_pipe_
.get(), buffer
->data(), &num_bytes
,
68 MOJO_READ_DATA_FLAG_ALL_OR_NONE
),
70 CHECK_EQ(num_bytes
, static_cast<uint32_t>(buffer
->data_size()));
73 // TODO(dalecurtis): Once we can write framed data to the DataPipe, fill via
74 // the producer handle and then read more to keep the pipe full. Waiting for
75 // space can be accomplished using an AsyncWaiter.
76 callback
.Run(static_cast<mojo::DemuxerStream::Status
>(status
),
77 mojo::MediaDecoderBuffer::From(buffer
));
80 void MojoDemuxerStreamImpl::DidConnect() {
81 // This is called when our DemuxerStreamClient has connected itself and is
82 // ready to receive messages. Send an initial config and notify it that
83 // we are now ready for business.
84 if (stream_
->type() == media::DemuxerStream::AUDIO
) {
85 client()->OnAudioDecoderConfigChanged(
86 mojo::AudioDecoderConfig::From(stream_
->audio_decoder_config()));
87 } else if (stream_
->type() == media::DemuxerStream::VIDEO
) {
88 client()->OnVideoDecoderConfigChanged(
89 mojo::VideoDecoderConfig::From(stream_
->video_decoder_config()));
92 MojoCreateDataPipeOptions options
;
93 options
.struct_size
= sizeof(MojoCreateDataPipeOptions
);
94 options
.flags
= MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
;
95 options
.element_num_bytes
= 1;
97 // Allocate DataPipe sizes based on content type to reduce overhead. If this
98 // is still too burdensome we can adjust for sample rate or resolution.
99 if (stream_
->type() == media::DemuxerStream::VIDEO
) {
100 // Video can get quite large; at 4K, VP9 delivers packets which are ~1MB in
101 // size; so allow for 50% headroom.
102 options
.capacity_num_bytes
= 1.5 * (1024 * 1024);
104 // Other types don't require a lot of room, so use a smaller pipe.
105 options
.capacity_num_bytes
= 512 * 1024;
108 mojo::DataPipe
data_pipe(options
);
109 stream_pipe_
= data_pipe
.producer_handle
.Pass();
110 client()->OnStreamReady(data_pipe
.consumer_handle
.Pass());