1fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala/* 2fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * Copyright (C) 2013 The Android Open Source Project 3fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * 4fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * Licensed under the Apache License, Version 2.0 (the "License"); 5fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * you may not use this file except in compliance with the License. 6fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * You may obtain a copy of the License at 7fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * 8fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * http://www.apache.org/licenses/LICENSE-2.0 9fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * 10fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * Unless required by applicable law or agreed to in writing, software 11fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * distributed under the License is distributed on an "AS IS" BASIS, 12fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * See the License for the specific language governing permissions and 14fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * limitations under the License. 15fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala */ 16fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 17fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala#ifndef ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H 18fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala#define ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H 19fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 20fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala#include <utils/RefBase.h> 21125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He#include <gui/IProducerListener.h> 22fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala#include <gui/Surface.h> 23fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 24fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala#include "Camera3Stream.h" 25e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin#include "Camera3IOStreamBase.h" 262fba584544e8687b526e3388bf7160b696da1dbaIgor Murashkin#include "Camera3OutputStreamInterface.h" 27125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He#include "Camera3BufferManager.h" 28fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 29fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvalanamespace android { 30fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 31fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvalanamespace camera3 { 32fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 33125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun Heclass Camera3BufferManager; 34125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He 35125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He/** 36125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * Stream info structure that holds the necessary stream info for buffer manager to use for 37125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * buffer allocation and management. 38125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He */ 39125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun Hestruct StreamInfo { 40125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He int streamId; 41125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He int streamSetId; 42125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He uint32_t width; 43125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He uint32_t height; 44125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He uint32_t format; 45125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He android_dataspace dataSpace; 46125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He uint32_t combinedUsage; 47125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He size_t totalBufferCount; 48125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He bool isConfigured; 49125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He StreamInfo(int id = CAMERA3_STREAM_ID_INVALID, 50125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He int setId = CAMERA3_STREAM_SET_ID_INVALID, 51125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He uint32_t w = 0, 52125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He uint32_t h = 0, 53125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He uint32_t fmt = 0, 54125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He android_dataspace ds = HAL_DATASPACE_UNKNOWN, 55125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He uint32_t usage = 0, 56125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He size_t bufferCount = 0, 57125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He bool configured = false) : 58125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He streamId(id), 59125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He streamSetId(setId), 60125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He width(w), 61125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He height(h), 62125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He format(fmt), 63125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He dataSpace(ds), 64125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He combinedUsage(usage), 65125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He totalBufferCount(bufferCount), 66125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He isConfigured(configured){} 67125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He}; 68125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He 69fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala/** 70fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * A class for managing a single stream of output data from the camera device. 71fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala */ 722fba584544e8687b526e3388bf7160b696da1dbaIgor Murashkinclass Camera3OutputStream : 73e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin public Camera3IOStreamBase, 742fba584544e8687b526e3388bf7160b696da1dbaIgor Murashkin public Camera3OutputStreamInterface { 75fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala public: 76fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala /** 77fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * Set up a stream for formats that have 2 dimensions, such as RAW and YUV. 78125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * A valid stream set id needs to be set to support buffer sharing between multiple 79125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * streams. 80fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala */ 81727d172137b4f32681c098de8e2623c0b65a6406Eino-Ville Talvala Camera3OutputStream(int id, sp<Surface> consumer, 823d82c0d9ed2b3e956ad699a9ca2c8a70c9d24678Eino-Ville Talvala uint32_t width, uint32_t height, int format, 83125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He android_dataspace dataSpace, camera3_stream_rotation_t rotation, 84c28dcccb9bc0a94950a7475f9bd8a6a38be34419Shuzhen Wang nsecs_t timestampOffset, int setId = CAMERA3_STREAM_SET_ID_INVALID); 85fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 86fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala /** 87fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * Set up a stream for formats that have a variable buffer size for the same 88fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * dimensions, such as compressed JPEG. 89125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * A valid stream set id needs to be set to support buffer sharing between multiple 90125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * streams. 91fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala */ 92727d172137b4f32681c098de8e2623c0b65a6406Eino-Ville Talvala Camera3OutputStream(int id, sp<Surface> consumer, 933d82c0d9ed2b3e956ad699a9ca2c8a70c9d24678Eino-Ville Talvala uint32_t width, uint32_t height, size_t maxSize, int format, 94125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He android_dataspace dataSpace, camera3_stream_rotation_t rotation, 95c28dcccb9bc0a94950a7475f9bd8a6a38be34419Shuzhen Wang nsecs_t timestampOffset, int setId = CAMERA3_STREAM_SET_ID_INVALID); 96fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 97fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala virtual ~Camera3OutputStream(); 98fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 99fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala /** 100fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * Camera3Stream interface 101fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala */ 102fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 103fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala virtual void dump(int fd, const Vector<String16> &args) const; 104fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 105fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala /** 106fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * Set the transform on the output stream; one of the 107fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants. 108fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala */ 109fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala status_t setTransform(int transform); 110fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 11185a6455f269d79adf9bf48d757a4b1b3c81cf760Chien-Yu Chen /** 11285a6455f269d79adf9bf48d757a4b1b3c81cf760Chien-Yu Chen * Return if this output stream is for video encoding. 11385a6455f269d79adf9bf48d757a4b1b3c81cf760Chien-Yu Chen */ 11485a6455f269d79adf9bf48d757a4b1b3c81cf760Chien-Yu Chen bool isVideoStream() const; 11513a69633108f40f56aa47f1bcbb406cd5173c245Shuzhen Wang /** 11613a69633108f40f56aa47f1bcbb406cd5173c245Shuzhen Wang * Return if this output stream is consumed by hardware composer. 11713a69633108f40f56aa47f1bcbb406cd5173c245Shuzhen Wang */ 11813a69633108f40f56aa47f1bcbb406cd5173c245Shuzhen Wang bool isConsumedByHWComposer() const; 11985a6455f269d79adf9bf48d757a4b1b3c81cf760Chien-Yu Chen 120125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He class BufferReleasedListener : public BnProducerListener { 121125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He public: 122125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He BufferReleasedListener(wp<Camera3OutputStream> parent) : mParent(parent) {} 123125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He 124125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He /** 125125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * Implementation of IProducerListener, used to notify this stream that the consumer 126125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * has returned a buffer and it is ready to return to Camera3BufferManager for reuse. 127125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He */ 128125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He virtual void onBufferReleased(); 129125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He 130125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He private: 131125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He wp<Camera3OutputStream> mParent; 132125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He }; 133125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He 13477c1a3554275a51ac8eb9fbe86f476afc8983192Eino-Ville Talvala virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd); 13577c1a3554275a51ac8eb9fbe86f476afc8983192Eino-Ville Talvala 136125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He /** 137125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * Set the graphic buffer manager to get/return the stream buffers. 138125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * 139125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * It is only legal to call this method when stream is in STATE_CONSTRUCTED state. 140125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He */ 141125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He status_t setBufferManager(sp<Camera3BufferManager> bufferManager); 142125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He 143e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin protected: 144e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin Camera3OutputStream(int id, camera3_stream_type_t type, 1453d82c0d9ed2b3e956ad699a9ca2c8a70c9d24678Eino-Ville Talvala uint32_t width, uint32_t height, int format, 146125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He android_dataspace dataSpace, camera3_stream_rotation_t rotation, 147125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He int setId = CAMERA3_STREAM_SET_ID_INVALID); 148e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin 149124ccf4b5023a40c57b49981123e6c9b61408a5dZhijun He /** 150124ccf4b5023a40c57b49981123e6c9b61408a5dZhijun He * Note that we release the lock briefly in this function 151124ccf4b5023a40c57b49981123e6c9b61408a5dZhijun He */ 152e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin virtual status_t returnBufferCheckedLocked( 153e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin const camera3_stream_buffer &buffer, 154e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin nsecs_t timestamp, 155e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin bool output, 156e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin /*out*/ 157e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin sp<Fence> *releaseFenceOut); 158e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin 1590a21051b91c2e07e49eb6fa568c505aee967ab9dZhijun He virtual status_t disconnectLocked(); 1600a21051b91c2e07e49eb6fa568c505aee967ab9dZhijun He 161727d172137b4f32681c098de8e2623c0b65a6406Eino-Ville Talvala sp<Surface> mConsumer; 162e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin private: 163fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala int mTransform; 164fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 165e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefdIgor Murashkin virtual status_t setTransformLocked(int transform); 166fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 167e0711f2651121754a10c784e3b149024d17fa4d5Ruchit Sharma bool mTraceFirstBuffer; 168e0711f2651121754a10c784e3b149024d17fa4d5Ruchit Sharma 169727d172137b4f32681c098de8e2623c0b65a6406Eino-Ville Talvala // Name of Surface consumer 170727d172137b4f32681c098de8e2623c0b65a6406Eino-Ville Talvala String8 mConsumerName; 171727d172137b4f32681c098de8e2623c0b65a6406Eino-Ville Talvala 172c28dcccb9bc0a94950a7475f9bd8a6a38be34419Shuzhen Wang // Whether consumer assumes MONOTONIC timestamp 173c28dcccb9bc0a94950a7475f9bd8a6a38be34419Shuzhen Wang bool mUseMonoTimestamp; 17413a69633108f40f56aa47f1bcbb406cd5173c245Shuzhen Wang 175fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala /** 176125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * GraphicBuffer manager this stream is registered to. Used to replace the buffer 177125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * allocation/deallocation role of BufferQueue. 178125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He */ 179125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He sp<Camera3BufferManager> mBufferManager; 180125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He 181125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He /** 182125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * Buffer released listener, used to notify the buffer manager that a buffer is released 183125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * from consumer side. 184125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He */ 185125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He sp<BufferReleasedListener> mBufferReleasedListener; 186125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He 187125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He /** 188125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He * Flag indicating if the buffer manager is used to allocate the stream buffers 189125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He */ 190125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He bool mUseBufferManager; 191c28dcccb9bc0a94950a7475f9bd8a6a38be34419Shuzhen Wang 192c28dcccb9bc0a94950a7475f9bd8a6a38be34419Shuzhen Wang /** 193c28dcccb9bc0a94950a7475f9bd8a6a38be34419Shuzhen Wang * Timestamp offset for video and hardware composer consumed streams 194c28dcccb9bc0a94950a7475f9bd8a6a38be34419Shuzhen Wang */ 195c28dcccb9bc0a94950a7475f9bd8a6a38be34419Shuzhen Wang nsecs_t mTimestampOffset; 196c28dcccb9bc0a94950a7475f9bd8a6a38be34419Shuzhen Wang 197125684aba1a11b7adbf5f9d607ee2bcc9449081cZhijun He /** 198fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala * Internal Camera3Stream interface 199fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala */ 200fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala virtual status_t getBufferLocked(camera3_stream_buffer *buffer); 201fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala virtual status_t returnBufferLocked( 202fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala const camera3_stream_buffer &buffer, 203fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala nsecs_t timestamp); 204fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 205fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala virtual status_t configureQueueLocked(); 206b2f5b19e5b6e1408a259add23dba91037756a943Eino-Ville Talvala 2074d44cad22ea925a651463f2d51d6586c14d4b787Eino-Ville Talvala virtual status_t getEndpointUsage(uint32_t *usage) const; 208b2f5b19e5b6e1408a259add23dba91037756a943Eino-Ville Talvala 209fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala}; // class Camera3OutputStream 210fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 211fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala} // namespace camera3 212fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 213fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala} // namespace android 214fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala 215fd58f1a10a749ca72fec1012920d6e94a664cd70Eino-Ville Talvala#endif 216