aboutsummaryrefslogtreecommitdiff
path: root/components/V4L2ComponentFactory.cpp
blob: 049edceb7d78efbbe8e99c39a8325efc94177f07 (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
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//#define LOG_NDEBUG 0
#define LOG_TAG "V4L2ComponentFactory"

#include <string>

#include <C2ComponentFactory.h>
#include <SimpleC2Interface.h>
#include <codec2/hidl/1.0/InputBufferManager.h>
#include <log/log.h>
#include <util/C2InterfaceHelper.h>

#include <v4l2_codec2/common/V4L2ComponentCommon.h>
#include <v4l2_codec2/components/V4L2DecodeComponent.h>
#include <v4l2_codec2/components/V4L2DecodeInterface.h>
#include <v4l2_codec2/components/V4L2EncodeComponent.h>
#include <v4l2_codec2/components/V4L2EncodeInterface.h>
#include <v4l2_codec2/store/V4L2ComponentStore.h>

namespace android {

class V4L2ComponentFactory : public C2ComponentFactory {
public:
    V4L2ComponentFactory(const char* componentName, bool isEncoder);
    ~V4L2ComponentFactory() override;

    // Implementation of C2ComponentFactory.
    c2_status_t createComponent(c2_node_id_t id, std::shared_ptr<C2Component>* const component,
                                ComponentDeleter deleter) override;
    c2_status_t createInterface(c2_node_id_t id,
                                std::shared_ptr<C2ComponentInterface>* const interface,
                                InterfaceDeleter deleter) override;

private:
    const std::string mComponentName;
    const bool mIsEncoder;
    std::shared_ptr<C2ReflectorHelper> mReflector;
};

V4L2ComponentFactory::V4L2ComponentFactory(const char* componentName, bool isEncoder)
      : mComponentName(componentName), mIsEncoder(isEncoder) {
    auto componentStore = V4L2ComponentStore::Create();
    if (componentStore == nullptr) {
        ALOGE("Could not create V4L2ComponentStore.");
        return;
    }
    mReflector = std::static_pointer_cast<C2ReflectorHelper>(componentStore->getParamReflector());

    {
        using namespace ::android::hardware::media::c2::V1_0;
        // To minimize IPC, we generally want the codec2 framework to release and
        // recycle input buffers when the corresponding work item is done. However,
        // sometimes it is necessary to provide more input to unblock a decoder.
        //
        // Optimally we would configure this on a per-context basis. However, the
        // InputBufferManager is a process-wide singleton, so we need to configure it
        // pessimistically. Basing the interval on frame timing can be suboptimal if
        // the decoded output isn't being displayed, but that's not a primary use case
        // and few videos will actually rely on this behavior.
        constexpr nsecs_t kMinFrameIntervalNs = 1000000000ull / 60;
        uint32_t delayCount = 0;
        for (auto c : kAllCodecs) {
            delayCount = std::max(delayCount, V4L2DecodeInterface::getOutputDelay(c));
        }
        utils::InputBufferManager::setNotificationInterval(delayCount * kMinFrameIntervalNs / 2);
    }
}

V4L2ComponentFactory::~V4L2ComponentFactory() = default;

c2_status_t V4L2ComponentFactory::createComponent(c2_node_id_t id,
                                                  std::shared_ptr<C2Component>* const component,
                                                  ComponentDeleter deleter) {
    ALOGV("%s(%d), componentName: %s, isEncoder: %d", __func__, id, mComponentName.c_str(),
          mIsEncoder);

    if (mReflector == nullptr) {
        ALOGE("mReflector doesn't exist.");
        return C2_CORRUPTED;
    }

    if (mIsEncoder) {
        *component = V4L2EncodeComponent::create(mComponentName, id, mReflector, deleter);
    } else {
        *component = V4L2DecodeComponent::create(mComponentName, id, mReflector, deleter);
    }
    return *component ? C2_OK : C2_NO_MEMORY;
}

c2_status_t V4L2ComponentFactory::createInterface(
        c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
        InterfaceDeleter deleter) {
    ALOGV("%s(), componentName: %s", __func__, mComponentName.c_str());

    if (mReflector == nullptr) {
        ALOGE("mReflector doesn't exist.");
        return C2_CORRUPTED;
    }

    if (mIsEncoder) {
        *interface = std::shared_ptr<C2ComponentInterface>(
                new SimpleInterface<V4L2EncodeInterface>(
                        mComponentName.c_str(), id,
                        std::make_shared<V4L2EncodeInterface>(mComponentName, mReflector)),
                deleter);
        return C2_OK;
    } else {
        *interface = std::shared_ptr<C2ComponentInterface>(
                new SimpleInterface<V4L2DecodeInterface>(
                        mComponentName.c_str(), id,
                        std::make_shared<V4L2DecodeInterface>(mComponentName, mReflector)),
                deleter);
        return C2_OK;
    }
}

}  // namespace android

__attribute__((cfi_canonical_jump_table)) extern "C" ::C2ComponentFactory* CreateCodec2Factory(
        const char* componentName) {
    ALOGV("%s(%s)", __func__, componentName);

    if (!android::V4L2ComponentName::isValid(componentName)) {
        ALOGE("Invalid component name: %s", componentName);
        return nullptr;
    }

    bool isEncoder = android::V4L2ComponentName::isEncoder(componentName);
    return new android::V4L2ComponentFactory(componentName, isEncoder);
}

__attribute__((cfi_canonical_jump_table)) extern "C" void DestroyCodec2Factory(
        ::C2ComponentFactory* factory) {
    ALOGV("%s()", __func__);
    delete factory;
}