SoftVPX.cpp revision 84333e0475bc911adc16417f4ca327c975cf6c36
1bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber/*
2bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * Copyright (C) 2011 The Android Open Source Project
3bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber *
4bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * you may not use this file except in compliance with the License.
6bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * You may obtain a copy of the License at
7bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber *
8bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
9bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber *
10bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * Unless required by applicable law or agreed to in writing, software
11bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * See the License for the specific language governing permissions and
14bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * limitations under the License.
15bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber */
16bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
17bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber//#define LOG_NDEBUG 0
18bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#define LOG_TAG "SoftVPX"
19bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include <utils/Log.h>
20bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
21bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include "SoftVPX.h"
22bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
23bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include <media/stagefright/foundation/ADebug.h>
24bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include <media/stagefright/MediaDefs.h>
25bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
26bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include "vpx/vpx_decoder.h"
27bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include "vpx/vpx_codec.h"
28bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include "vpx/vp8dx.h"
29bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
30bbba88cb1bdc34705d1477208990a06904c022e7Andreas Hubernamespace android {
31bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
32bbba88cb1bdc34705d1477208990a06904c022e7Andreas HuberSoftVPX::SoftVPX(
33bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        const char *name,
3494705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        const char *componentRole,
3594705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        OMX_VIDEO_CODINGTYPE codingType,
36bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        const OMX_CALLBACKTYPE *callbacks,
37bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_PTR appData,
38bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_COMPONENTTYPE **component)
397f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar    : SoftVideoDecoderOMXComponent(
4094705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang            name, componentRole, codingType,
417f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar            NULL /* profileLevels */, 0 /* numProfileLevels */,
427f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar            320 /* width */, 240 /* height */, callbacks, appData, component),
4394705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang      mMode(codingType == OMX_VIDEO_CodingVP8 ? MODE_VP8 : MODE_VP9),
447f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar      mCtx(NULL) {
457f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar    initPorts(kNumBuffers, 768 * 1024 /* inputBufferSize */,
4694705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang            kNumBuffers,
4794705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang            codingType == OMX_VIDEO_CodingVP8 ? MEDIA_MIMETYPE_VIDEO_VP8 : MEDIA_MIMETYPE_VIDEO_VP9);
487f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar
49bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    CHECK_EQ(initDecoder(), (status_t)OK);
50bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
51bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
52bbba88cb1bdc34705d1477208990a06904c022e7Andreas HuberSoftVPX::~SoftVPX() {
53bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    vpx_codec_destroy((vpx_codec_ctx_t *)mCtx);
54bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    delete (vpx_codec_ctx_t *)mCtx;
55bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    mCtx = NULL;
56bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
57bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
58f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dongstatic int GetCPUCoreCount() {
59f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    int cpuCoreCount = 1;
60f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong#if defined(_SC_NPROCESSORS_ONLN)
61f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
62f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong#else
63f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    // _SC_NPROC_ONLN must be defined...
64f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
65f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong#endif
66f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    CHECK(cpuCoreCount >= 1);
673856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("Number of CPU cores: %d", cpuCoreCount);
68f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    return cpuCoreCount;
69f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong}
70f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong
71bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huberstatus_t SoftVPX::initDecoder() {
72bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    mCtx = new vpx_codec_ctx_t;
73bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    vpx_codec_err_t vpx_err;
74f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    vpx_codec_dec_cfg_t cfg;
75f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
76f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    cfg.threads = GetCPUCoreCount();
77bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    if ((vpx_err = vpx_codec_dec_init(
7894705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                (vpx_codec_ctx_t *)mCtx,
7994705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                 mMode == MODE_VP8 ? &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo,
8094705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                 &cfg, 0))) {
8129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("on2 decoder failed to initialize. (%d)", vpx_err);
82bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        return UNKNOWN_ERROR;
83bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    }
84bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
85bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    return OK;
86bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
87bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
8884333e0475bc911adc16417f4ca327c975cf6c36Andreas Hubervoid SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) {
89bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    if (mOutputPortSettingsChange != NONE) {
90bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        return;
91bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    }
92bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
93bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    List<BufferInfo *> &inQueue = getPortQueue(0);
94bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    List<BufferInfo *> &outQueue = getPortQueue(1);
95a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar    bool EOSseen = false;
96bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
97bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    while (!inQueue.empty() && !outQueue.empty()) {
98bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        BufferInfo *inInfo = *inQueue.begin();
99bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
100bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
101bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        BufferInfo *outInfo = *outQueue.begin();
102bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
103bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
104bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
105a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar            EOSseen = true;
106a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar            if (inHeader->nFilledLen == 0) {
107a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar                inQueue.erase(inQueue.begin());
108a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar                inInfo->mOwnedByUs = false;
109a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar                notifyEmptyBufferDone(inHeader);
110a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar
111a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar                outHeader->nFilledLen = 0;
112a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
113a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar
114a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar                outQueue.erase(outQueue.begin());
115a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar                outInfo->mOwnedByUs = false;
116a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar                notifyFillBufferDone(outHeader);
117a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar                return;
118a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar            }
119bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        }
120bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
121bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        if (vpx_codec_decode(
122bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                    (vpx_codec_ctx_t *)mCtx,
123bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                    inHeader->pBuffer + inHeader->nOffset,
124bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                    inHeader->nFilledLen,
125bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                    NULL,
126bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                    0)) {
12729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("on2 decoder failed to decode frame.");
128bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
129bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
130bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            return;
131bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        }
132bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
133bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        vpx_codec_iter_t iter = NULL;
134bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
135bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
136bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        if (img != NULL) {
137bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            CHECK_EQ(img->fmt, IMG_FMT_I420);
138bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
1397f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar            uint32_t width = img->d_w;
1407f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar            uint32_t height = img->d_h;
141bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
142bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            if (width != mWidth || height != mHeight) {
143bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                mWidth = width;
144bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                mHeight = height;
145bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
146bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                updatePortDefinitions();
147bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
148bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
149bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                mOutputPortSettingsChange = AWAITING_DISABLED;
150bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                return;
151bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            }
152bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
153bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            outHeader->nOffset = 0;
154bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            outHeader->nFilledLen = (width * height * 3) / 2;
155a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar            outHeader->nFlags = EOSseen ? OMX_BUFFERFLAG_EOS : 0;
156bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            outHeader->nTimeStamp = inHeader->nTimeStamp;
157bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
158bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            const uint8_t *srcLine = (const uint8_t *)img->planes[PLANE_Y];
159bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            uint8_t *dst = outHeader->pBuffer;
160bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            for (size_t i = 0; i < img->d_h; ++i) {
161bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                memcpy(dst, srcLine, img->d_w);
162bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
163bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                srcLine += img->stride[PLANE_Y];
164bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                dst += img->d_w;
165bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            }
166bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
167bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            srcLine = (const uint8_t *)img->planes[PLANE_U];
168bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            for (size_t i = 0; i < img->d_h / 2; ++i) {
169bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                memcpy(dst, srcLine, img->d_w / 2);
170bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
171bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                srcLine += img->stride[PLANE_U];
172bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                dst += img->d_w / 2;
173bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            }
174bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
175bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            srcLine = (const uint8_t *)img->planes[PLANE_V];
176bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            for (size_t i = 0; i < img->d_h / 2; ++i) {
177bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                memcpy(dst, srcLine, img->d_w / 2);
178bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
179bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                srcLine += img->stride[PLANE_V];
180bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber                dst += img->d_w / 2;
181bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            }
182bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
183bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            outInfo->mOwnedByUs = false;
184bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            outQueue.erase(outQueue.begin());
185bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            outInfo = NULL;
186bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            notifyFillBufferDone(outHeader);
187bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber            outHeader = NULL;
188bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        }
189bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
190bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        inInfo->mOwnedByUs = false;
191bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        inQueue.erase(inQueue.begin());
192bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        inInfo = NULL;
193bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        notifyEmptyBufferDone(inHeader);
194bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        inHeader = NULL;
195bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    }
196bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
197bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
198bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}  // namespace android
199bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
200bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huberandroid::SoftOMXComponent *createSoftOMXComponent(
201bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        const char *name, const OMX_CALLBACKTYPE *callbacks,
202bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
20394705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    if (!strcmp(name, "OMX.google.vp8.decoder")) {
20494705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        return new android::SoftVPX(
20594705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                name, "video_decoder.vp8", OMX_VIDEO_CodingVP8,
20694705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                callbacks, appData, component);
20794705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    } else if (!strcmp(name, "OMX.google.vp9.decoder")) {
20894705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        return new android::SoftVPX(
20994705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                name, "video_decoder.vp9", OMX_VIDEO_CodingVP9,
21094705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                callbacks, appData, component);
21194705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    } else {
21294705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        CHECK(!"Unknown component");
21394705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    }
214bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
215