summaryrefslogtreecommitdiff
path: root/media/codec2/sfplugin/CCodecConfig.h
blob: 2895746d37741f1855ba706f1d10274716ae591b (plain)
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef C_CODEC_CONFIG_H_
#define C_CODEC_CONFIG_H_

#include <map>
#include <memory>
#include <set>
#include <vector>

#include <C2Component.h>
#include <C2Config.h>
#include <C2Debug.h>

#include <codec2/hidl/client.h>
#include <utils/RefBase.h>

#include "InputSurfaceWrapper.h"
#include "ReflectedParamUpdater.h"

namespace android {

struct AMessage;
struct StandardParams;

/**
 * Struct managing the codec configuration for CCodec.
 */
struct CCodecConfig {
    /**
     * Domain consists of a bitmask divided into fields, and specifiers work by excluding other
     * values in those domains.
     *
     * Component domains are composed by or-ing the individual IS_ constants, e.g.
     * IS_DECODER | IS_AUDIO.
     *
     * Config specifiers are composed by or-ing the individual mask constants, and
     * and-ing these groups: e.g. (DECODER | ENCODER) & AUDIO.
     *
     * The naming of these constants was to limit the length of mask names as these are used more
     * commonly as masks.
     */
    enum Domain : uint32_t {
        // component domain (domain & kind)
        GUARD_BIT   = (1 << 1),   ///< this is to prevent against accidental && or || usage
        IS_AUDIO    = (1 << 2),   ///< for audio codecs
        IS_VIDEO    = (1 << 3),   ///< for video codecs
        IS_IMAGE    = (1 << 4),   ///< for image codecs
        OTHER_DOMAIN = (1 << 5),  ///< for other domains

        IS_ENCODER  = (1 << 6),   ///< for encoders
        IS_DECODER  = (1 << 7),   ///< for decoders
        OTHER_KIND  = (1 << 8),   ///< for other domains

        // config domain
        IS_PARAM    = (1 << 9),   ///< for setParameter
        IS_CONFIG   = (1 << 10),  ///< for configure
        IS_READ     = (1 << 11),  ///< for getFormat

        // port domain
        IS_INPUT    = (1 << 12),  ///< for input port (getFormat)
        IS_OUTPUT   = (1 << 13),  ///< for output port (getFormat)
        IS_RAW      = (1 << 14),  ///< for raw port (input-encoder, output-decoder)
        IS_CODED    = (1 << 15),  ///< for coded port (input-decoder, output-encoder)

        ALL     = ~0U,
        NONE    = 0,

        AUDIO   = ~(IS_IMAGE | IS_VIDEO | OTHER_DOMAIN),
        VIDEO   = ~(IS_AUDIO | IS_IMAGE | OTHER_DOMAIN),
        IMAGE   = ~(IS_AUDIO | IS_VIDEO | OTHER_DOMAIN),

        DECODER = ~(IS_ENCODER | OTHER_KIND),
        ENCODER = ~(IS_DECODER | OTHER_KIND),

        PARAM   = ~(IS_CONFIG | IS_READ),
        CONFIG  = ~(IS_PARAM  | IS_READ),
        READ    = ~(IS_CONFIG | IS_PARAM),

        INPUT   = ~(IS_OUTPUT | IS_RAW    | IS_CODED),
        OUTPUT  = ~(IS_INPUT  | IS_RAW    | IS_CODED),
        RAW     = ~(IS_INPUT  | IS_OUTPUT | IS_CODED),
        CODED   = ~(IS_INPUT  | IS_RAW    | IS_OUTPUT),
    };

    // things required to manage formats
    std::vector<std::shared_ptr<C2ParamDescriptor>> mParamDescs;
    std::shared_ptr<C2ParamReflector> mReflector;

    std::shared_ptr<ReflectedParamUpdater> mParamUpdater;

    Domain mDomain; // component domain
    Domain mInputDomain; // input port domain
    Domain mOutputDomain; // output port domain
    std::string mCodingMediaType;  // media type of the coded stream

    // standard MediaCodec to Codec 2.0 params mapping
    std::shared_ptr<StandardParams> mStandardParams;

    std::set<C2Param::Index> mSupportedIndices; ///< indices supported by the component
    std::set<C2Param::Index> mSubscribedIndices; ///< indices to subscribe to
    size_t mSubscribedIndicesSize; ///< count of currently subscribed indices

    sp<AMessage> mInputFormat;
    sp<AMessage> mOutputFormat;

    bool mUsingSurface; ///< using input or output surface
    bool mBuffersBoundToCodec; ///< whether buffers are bound to codecs or not.

    std::shared_ptr<InputSurfaceWrapper> mInputSurface;
    std::unique_ptr<InputSurfaceWrapper::Config> mISConfig;

    /// the current configuration. Updated after configure() and based on configUpdate in
    /// onWorkDone
    std::map<C2Param::Index, std::unique_ptr<C2Param>> mCurrentConfig;

    typedef std::function<c2_status_t(std::unique_ptr<C2Param>&)> LocalParamValidator;

    /// Parameter indices tracked in current config that are not supported by the component.
    /// these are provided so that optional parameters can remain in the current configuration.
    /// as such, these parameters have no dependencies. TODO: use C2InterfaceHelper for this.
    /// For now support a validation function.
    std::map<C2Param::Index, LocalParamValidator> mLocalParams;

    /// Vendor field name -> index map.
    std::map<std::string, C2Param::Index> mVendorParamIndices;

    std::set<std::string> mLastConfig;

    CCodecConfig();

    /// initializes the members required to manage the format: descriptors, reflector,
    /// reflected param helper, domain, standard params, and subscribes to standard
    /// indices.
    status_t initialize(
            const std::shared_ptr<C2ParamReflector> &client,
            const std::shared_ptr<Codec2Client::Configurable> &configurable);

    /**
     * Adds a locally maintained parameter. This is used for output configuration that can be
     * appended to the output buffers in case it is not supported by the component.
     */
    template<typename T>
    bool addLocalParam(
            const std::string &name,
            C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY,
            std::function<c2_status_t(std::unique_ptr<T>&)> validator_ =
                std::function<c2_status_t(std::unique_ptr<T>&)>()) {
        C2Param::Index index = T::PARAM_TYPE;
        if (mSupportedIndices.count(index) || mLocalParams.count(index)) {
            if (mSupportedIndices.count(index)) {
                mSubscribedIndices.emplace(index);
            }
            ALOGD("ignoring local param %s (%#x) as it is already %s",
                    name.c_str(), (uint32_t)index, mSupportedIndices.count(index) ? "supported" : "local");
            return false; // already supported by the component or already added
        }

        // wrap typed validator into untyped validator
        LocalParamValidator validator;
        if (validator_) {
            validator = [validator_](std::unique_ptr<C2Param>& p){
                c2_status_t res = C2_BAD_VALUE;
                std::unique_ptr<T> typed(static_cast<T*>(p.release()));
                // if parameter is correctly typed
                if (T::From(typed.get())) {
                    res = validator_(typed);
                    p.reset(typed.release());
                }
                return res;
            };
        }

        mLocalParams.emplace(index, validator);
        mParamUpdater->addStandardParam<T>(name, attrib);
        return true;
    }

    /**
     * Adds a locally maintained parameter with a default value.
     */
    template<typename T>
    bool addLocalParam(
            std::unique_ptr<T> default_,
            const std::string &name,
            C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY,
            std::function<c2_status_t(std::unique_ptr<T>&)> validator_ =
                std::function<c2_status_t(std::unique_ptr<T>&)>()) {
        if (addLocalParam<T>(name, attrib, validator_)) {
            if (validator_) {
                c2_status_t err = validator_(default_);
                if (err != C2_OK) {
                    ALOGD("default value for %s is invalid => %s", name.c_str(), asString(err));
                    return false;
                }
            }
            mCurrentConfig[T::PARAM_TYPE] = std::move(default_);
            return true;
        }
        return false;
    }

    template<typename T>
    bool addLocalParam(
            T *default_, const std::string &name,
            C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY,
            std::function<c2_status_t(std::unique_ptr<T>&)> validator_ =
                std::function<c2_status_t(std::unique_ptr<T>&)>()) {
        return addLocalParam(std::unique_ptr<T>(default_), name, attrib, validator_);
    }

    /// Applies configuration updates, and updates format in the specific domain.
    /// Returns true if formats were updated
    /// \param domain input/output bitmask
    bool updateConfiguration(
            std::vector<std::unique_ptr<C2Param>> &configUpdate, Domain domain);

    /// Updates formats in the specific domain. Returns true if any of the formats have changed.
    /// \param domain input/output bitmask
    bool updateFormats(Domain domain);

    /**
     * Applies SDK configurations in a specific configuration domain.
     * Updates relevant input/output formats and subscribes to parameters specified in the
     * configuration.
     * \param domain config/setParam bitmask
     * \param blocking blocking mode to use with the component
     */
    status_t getConfigUpdateFromSdkParams(
            std::shared_ptr<Codec2Client::Configurable> configurable,
            const sp<AMessage> &sdkParams, Domain domain,
            c2_blocking_t blocking,
            std::vector<std::unique_ptr<C2Param>> *configUpdate) const;

    /**
     * Applies a configuration update to the component.
     * Updates relevant input/output formats and subscribes to parameters specified in the
     * configuration.
     * \param blocking blocking mode to use with the component
     */
    status_t setParameters(
            std::shared_ptr<Codec2Client::Configurable> configurable,
            std::vector<std::unique_ptr<C2Param>> &configUpdate,
            c2_blocking_t blocking);

    /// Queries subscribed indices (which contains all SDK-exposed values) and updates
    /// input/output formats.
    status_t queryConfiguration(
            const std::shared_ptr<Codec2Client::Configurable> &configurable);

    /// Queries a configuration parameter value. Returns nullptr if the parameter is not
    /// part of the current configuration
    const C2Param *getConfigParameterValue(C2Param::Index index) const;

    /// Subscribe to all vendor parameters.
    status_t subscribeToAllVendorParams(
            const std::shared_ptr<Codec2Client::Configurable> &configurable,
            c2_blocking_t blocking);

    /**
     * Object that can be used to access configuration parameters and if they change.
     */
    template<typename T>
    struct Watcher {
        ~Watcher() = default;

        /// returns true if the value of this configuration has changed
        bool hasChanged() const {
            const C2Param *value = mParent->getConfigParameterValue(mIndex);
            if (value && mValue) {
                return *value != *mValue;
            } else {
                return value != mValue.get();
            }
        }

        /// updates the current value and returns it
        std::shared_ptr<const T> update() {
            const C2Param *value = mParent->getConfigParameterValue(mIndex);
            if (value) {
                mValue = std::shared_ptr<const T>(T::From(C2Param::Copy(*value).release()));
            }
            return mValue;
        }

    private:
        Watcher(C2Param::Index index, const CCodecConfig *parent)
            : mParent(parent), mIndex(index) {
            update();
        }

        friend struct CCodecConfig;

        const CCodecConfig *mParent;
        std::shared_ptr<const T> mValue;
        C2Param::Index mIndex;
    };

    /**
     * Returns a watcher object for a parameter.
     */
    template<typename T>
    Watcher<T> watch(C2Param::Index index = T::PARAM_TYPE) const {
        if (index.type() != T::PARAM_TYPE) {
            __builtin_trap();
        }
        return Watcher<T>(index, this);
    }

private:

    /// initializes the standard MediaCodec to Codec 2.0 params mapping
    void initializeStandardParams();

    /// Adds indices to the subscribed indices, and updated subscription to component
    /// \param blocking blocking mode to use with the component
    status_t subscribeToConfigUpdate(
            const std::shared_ptr<Codec2Client::Configurable> &configurable,
            const std::vector<C2Param::Index> &indices,
            c2_blocking_t blocking = C2_DONT_BLOCK);

    /// Gets SDK format from codec 2.0 reflected configuration
    /// \param domain input/output bitmask
    sp<AMessage> getFormatForDomain(
            const ReflectedParamUpdater::Dict &reflected,
            Domain domain) const;

    /**
     * Converts a set of configuration parameters in an AMessage to a list of path-based Codec
     * 2.0 configuration parameters.
     *
     * \param domain config/setParam bitmask
     */
    ReflectedParamUpdater::Dict getReflectedFormat(
            const sp<AMessage> &config, Domain domain) const;
};

DEFINE_ENUM_OPERATORS(CCodecConfig::Domain)

}  // namespace android

#endif  // C_CODEC_H_