1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
media / gpu / android / codec_wrapper.h [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_GPU_ANDROID_CODEC_WRAPPER_H_
#define MEDIA_GPU_ANDROID_CODEC_WRAPPER_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/memory/scoped_refptr.h"
#include "base/synchronization/lock.h"
#include "base/task/sequenced_task_runner.h"
#include "media/base/android/media_codec_bridge.h"
#include "media/base/decoder_buffer.h"
#include "media/base/status.h"
#include "media/gpu/android/codec_surface_bundle.h"
#include "media/gpu/android/device_info.h"
#include "media/gpu/media_gpu_export.h"
namespace media {
class CodecWrapper;
class CodecWrapperImpl;
using CodecSurfacePair = std::pair<std::unique_ptr<MediaCodecBridge>,
scoped_refptr<CodecSurfaceBundle>>;
// A MediaCodec output buffer that can be released on any thread. Releasing a
// CodecOutputBuffer implicitly discards all CodecOutputBuffers that
// precede it in presentation order; i.e., the only supported use case is to
// render output buffers in order. This lets us return buffers to the codec as
// soon as we know we no longer need them.
class MEDIA_GPU_EXPORT CodecOutputBuffer {
public:
CodecOutputBuffer(const CodecOutputBuffer&) = delete;
CodecOutputBuffer& operator=(const CodecOutputBuffer&) = delete;
// Releases the buffer without rendering it.
~CodecOutputBuffer();
// Releases this buffer and renders it to the surface.
bool ReleaseToSurface();
// The size of the image.
gfx::Size size() const { return size_; }
// Returns true if a coded size guess based on `size_` is available.
bool CanGuessCodedSize() const;
// Attempts to guess the coded size. `CanGuessCodedSize` must be true.
gfx::Size GuessCodedSize() const;
// Sets a callback that will be called when we're released to the surface.
// Will not be called if we're dropped.
void set_render_cb(base::OnceClosure render_cb) {
render_cb_ = std::move(render_cb);
}
// Color space of the image.
const gfx::ColorSpace& color_space() const { return color_space_; }
// Note that you can't use the first ctor, since CodecWrapperImpl isn't
// defined here. Use the second, and it'll be nullptr.
template <typename... Args>
static std::unique_ptr<CodecOutputBuffer> CreateForTesting(Args&&... args) {
// std::make_unique can't access the constructor.
return std::unique_ptr<CodecOutputBuffer>(
new CodecOutputBuffer(std::forward<Args>(args)...));
}
private:
// Let CodecWrapperImpl call the constructor.
friend class CodecWrapperImpl;
CodecOutputBuffer(scoped_refptr<CodecWrapperImpl> codec,
int64_t id,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
std::optional<gfx::Size> coded_size_alignment);
// For testing, since CodecWrapperImpl isn't available. Uses nullptr.
CodecOutputBuffer(int64_t id,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
std::optional<gfx::Size> coded_size_alignment);
scoped_refptr<CodecWrapperImpl> codec_;
int64_t id_;
bool was_rendered_ = false;
gfx::Size size_;
base::OnceClosure render_cb_;
gfx::ColorSpace color_space_;
// The alignment to use for width, height when guessing coded size.
const std::optional<gfx::Size> coded_size_alignment_;
};
// This wraps a MediaCodecBridge and provides higher level features and tracks
// more state that is useful for video decoding.
// CodecWrapper is not threadsafe, but the CodecOutputBuffers it outputs
// can be released on any thread.
class MEDIA_GPU_EXPORT CodecWrapper {
public:
// The given codec should be in the flushed state, i.e., freshly configured or
// after a Flush(). The surface must be the one that the codec was configured
// with. |output_buffer_release_cb| will be run whenever an output buffer is
// released back to the codec (whether it's rendered or not). This is a signal
// that the codec might be ready to accept more input. It may be run on any
// thread.
//
// OutputReleasedCB will be called with a bool indicating if CodecWrapper is
// currently draining, is drained, or has run out of output buffers.
//
// `coded_size_alignment` describes how to translate a CodecOutputBuffer's
// visible size into its coded size. It's used to improve coded size guesses
// when rendering the output buffer early isn't allowed. During guessing, the
// output's visible size will be aligned-up by the values specified. E.g., a
// size of 1,1 applies no alignment while a size of 64,1 would round up the
// visible width to the nearest multiple of 64.
using OutputReleasedCB = base::RepeatingCallback<void(bool)>;
CodecWrapper(CodecSurfacePair codec_surface_pair,
OutputReleasedCB output_buffer_release_cb,
const gfx::Size& initial_expected_size,
const gfx::ColorSpace& config_color_space,
std::optional<gfx::Size> coded_size_alignment);
CodecWrapper(const CodecWrapper&) = delete;
CodecWrapper& operator=(const CodecWrapper&) = delete;
~CodecWrapper();
// Takes the backing codec and surface, implicitly discarding all outstanding
// codec buffers. It's safe to use CodecOutputBuffers after this is called,
// but they can no longer be rendered.
CodecSurfacePair TakeCodecSurfacePair();
// Whether the codec is in the flushed state.
bool IsFlushed() const;
// Whether an EOS has been queued but not yet dequeued.
bool IsDraining() const;
// Whether an EOS has been dequeued but the codec hasn't been flushed yet.
bool IsDrained() const;
// Whether there are any dequeued output buffers that have not been released.
bool HasUnreleasedOutputBuffers() const;
// Releases all dequeued output buffers back to the codec without rendering.
void DiscardOutputBuffers();
// Flushes the codec and discards all output buffers.
bool Flush();
// Sets the given surface and returns true on success.
bool SetSurface(scoped_refptr<CodecSurfaceBundle> surface_bundle);
// Returns the surface bundle that the codec is currently configured with.
// Returns null after TakeCodecSurfacePair() is called.
scoped_refptr<CodecSurfaceBundle> SurfaceBundle();
// Queues |buffer| if the codec has an available input buffer.
struct QueueStatusTraits {
enum class Codes { kOk, kError, kTryAgainLater, kNoKey };
static constexpr StatusGroupType Group() { return "QueueStatus"; }
};
using QueueStatus = TypedStatus<QueueStatusTraits>;
QueueStatus QueueInputBuffer(const DecoderBuffer& buffer);
// Like MediaCodecBridge::DequeueOutputBuffer() but it outputs a
// CodecOutputBuffer instead of an index. |*codec_buffer| must be null.
// If this returns kOk then either |*end_of_stream| will be set to true or
// |*codec_buffer| will be non-null. The EOS buffer is returned to the codec
// immediately. Unlike MediaCodecBridge, this does not return
// kOutputBuffersChanged or kOutputFormatChanged.
// It tries to dequeue another buffer instead.
struct DequeueStatusTraits {
enum class Codes : StatusCodeType { kOk, kError, kTryAgainLater };
static constexpr StatusGroupType Group() { return "DequeueStatus"; }
};
using DequeueStatus = TypedStatus<DequeueStatusTraits>;
DequeueStatus DequeueOutputBuffer(
base::TimeDelta* presentation_time,
bool* end_of_stream,
std::unique_ptr<CodecOutputBuffer>* codec_buffer);
size_t GetUnreleasedOutputBufferCount() const;
private:
scoped_refptr<CodecWrapperImpl> impl_;
};
} // namespace media
#endif // MEDIA_GPU_ANDROID_CODEC_WRAPPER_H_