14 #include "rpi_omx_broadcom.h" 16 #include <IL/OMX_Core.h> 17 #include <IL/OMX_Component.h> 18 #include <IL/OMX_Video.h> 19 #include <IL/OMX_Broadcom.h> 21 #define debug_print(...) fprintf(stderr, "[RPiCamera] " __VA_ARGS__) 22 #define ERR_OMX(err, msg) if ((err) != OMX_ErrorNone) throw OMXExeption(err, __FILE__, __LINE__, msg) 27 typedef broadcom::ComponentType ComponentType;
28 using broadcom::componentType2name;
29 using broadcom::componentPortsCount;
34 const char * err2str(OMX_ERRORTYPE error);
35 void printEvent(
const char * compName, OMX_HANDLETYPE hComponent, OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2);
36 void dump_portdef(OMX_PARAM_PORTDEFINITIONTYPE * portdef);
37 void dump_formats(OMX_VIDEO_PARAM_PORTFORMATTYPE * portformat);
39 extern OMX_CALLBACKTYPE cbsEvents;
45 static const unsigned MAX_LEN = 256;
47 OMXExeption(OMX_ERRORTYPE errCode,
const char * file,
unsigned line,
const char * msg =
nullptr)
50 setLastError(errCode);
53 snprintf(m_msg, MAX_LEN,
"%s:%d OpenMAX IL error: 0x%08x. %s", file, line, errCode, msg);
55 snprintf(m_msg, MAX_LEN,
"%s:%d OpenMAX IL error: 0x%08x", file, line, errCode);
58 OMX_ERRORTYPE code()
const {
return m_errCode; }
59 virtual const char * what()
const noexcept
override {
return m_msg; }
61 static bool hasError() {
return lastError() || eventError(); }
62 static uint32_t lastError() {
return m_lastError; }
63 static uint32_t eventError() {
return m_eventError; }
64 static void setLastError(uint32_t code = OMX_ErrorNone) { m_lastError.store(code); }
65 static void setEventError(uint32_t code = OMX_ErrorNone) { m_eventError.store(code); }
68 OMX_ERRORTYPE m_errCode;
70 static std::atomic<uint32_t> m_lastError;
71 static std::atomic<uint32_t> m_eventError;
101 static const VideoFromat VF_1920x1080x25 = { 1920, 1080, 25, VideoFromat::RATIO_16x9,
false };
102 static const VideoFromat VF_1280x960 = { 1280, 960, 30, VideoFromat::RATIO_4x3,
true };
103 static const VideoFromat VF_1280x720 = { 1280, 720, 30, VideoFromat::RATIO_16x9,
true };
104 static const VideoFromat VF_640x480 = { 640, 480, 30, VideoFromat::RATIO_4x3,
true };
106 static const VideoFromat VF_RESIZED_640x480 = VF_640x480;
107 static const VideoFromat VF_RESIZED_320x240 = { 320, 240, 30, VideoFromat::RATIO_4x3,
true };
108 static const VideoFromat VF_RESIZED_256x192 = { 256, 192, 30, VideoFromat::RATIO_4x3,
true };
109 static const VideoFromat VF_RESIZED_160x120 = { 160, 120, 30, VideoFromat::RATIO_4x3,
true };
110 static const VideoFromat VF_RESIZED_128x96 = { 128, 96, 30, VideoFromat::RATIO_4x3,
true };
112 static const VideoFromat VF_RESIZED_960x540 = { 960, 540, 30, VideoFromat::RATIO_16x9,
false };
113 static const VideoFromat VF_RESIZED_640x360 = { 640, 360, 30, VideoFromat::RATIO_16x9,
false };
114 static const VideoFromat VF_RESIZED_480x270 = { 480, 270, 30, VideoFromat::RATIO_16x9,
false };
115 static const VideoFromat VF_RESIZED_384x216 = { 384, 216, 30, VideoFromat::RATIO_16x9,
false };
116 static const VideoFromat VF_RESIZED_320x180 = { 320, 180, 30, VideoFromat::RATIO_16x9,
false };
117 static const VideoFromat VF_RESIZED_240x135 = { 240, 135, 30, VideoFromat::RATIO_16x9,
false };
120 template <
typename T>
131 memset(&m_param, 0,
sizeof(m_param));
132 m_param.nSize =
sizeof(m_param);
133 m_param.nVersion.nVersion = OMX_VERSION;
134 m_param.nVersion.s.nVersionMajor = OMX_VERSION_MAJOR;
135 m_param.nVersion.s.nVersionMinor = OMX_VERSION_MINOR;
136 m_param.nVersion.s.nRevision = OMX_VERSION_REVISION;
137 m_param.nVersion.s.nStep = OMX_VERSION_STEP;
140 T& operator * () {
return m_param; }
141 T* operator & () {
return &m_param; }
142 T* operator -> () {
return &m_param; }
144 const T& operator * ()
const {
return m_param; }
145 const T* operator & ()
const {
return &m_param; }
146 const T* operator -> ()
const {
return &m_param; }
157 : m_ppBuffer(
nullptr),
161 bool filled()
const {
return m_fillDone; }
162 void setFilled(
bool val =
true) { m_fillDone = val; }
164 OMX_BUFFERHEADERTYPE ** pHeader() {
return &m_ppBuffer; }
165 OMX_BUFFERHEADERTYPE * header() {
return m_ppBuffer; }
166 OMX_U32 flags()
const {
return m_ppBuffer->nFlags; }
167 OMX_U32& flags() {
return m_ppBuffer->nFlags; }
168 OMX_TICKS timeStamp()
const {
return m_ppBuffer->nTimeStamp; }
170 OMX_U8 * data() {
return m_ppBuffer->pBuffer + m_ppBuffer->nOffset; }
171 OMX_U32 dataSize()
const {
return m_ppBuffer->nFilledLen; }
172 OMX_U32 allocSize()
const {
return m_ppBuffer->nAllocLen; }
175 OMX_BUFFERHEADERTYPE * m_ppBuffer;
176 std::atomic_bool m_fillDone;
183 OMX_HANDLETYPE& component() {
return m_component; }
184 ComponentType type()
const {
return m_type; }
185 const char * name()
const {
return componentType2name(m_type); }
186 unsigned numPorts()
const {
return componentPortsCount(m_type); }
188 void dumpPort(OMX_U32 nPortIndex,
bool dumpFormats =
false)
191 getPortDefinition(nPortIndex, portdef);
193 dump_portdef(&portdef);
198 portformat->nPortIndex = nPortIndex;
199 portformat->nIndex = 0;
201 for (;; portformat->nIndex++)
203 OMX_ERRORTYPE err = OMX_GetParameter(m_component, OMX_IndexParamVideoPortFormat, &portformat);
204 if (err != OMX_ErrorNone)
207 dump_formats(&portformat);
212 OMX_STATETYPE state()
215 ERR_OMX( OMX_GetState(m_component, &state),
"OMX_GetState" );
219 void switchState(OMX_STATETYPE newState)
221 unsigned value = m_eventState + 1;
222 ERR_OMX( OMX_SendCommand(m_component, OMX_CommandStateSet, newState, NULL),
"switch state");
224 if (! waitValue(m_eventState, value))
225 debug_print(
"%s - lost state changed event\n", name());
227 if (state() != newState)
228 ERR_OMX( OMX_ErrorInvalidState,
"can't switch state" );
231 unsigned count2wait(OMX_U32 nPortIndex)
const {
return (nPortIndex == OMX_ALL) ? numPorts() : 1; }
233 void enablePort(OMX_U32 nPortIndex = OMX_ALL)
235 unsigned value = m_eventEnabled + count2wait(nPortIndex);
236 ERR_OMX( OMX_SendCommand(m_component, OMX_CommandPortEnable, nPortIndex, NULL),
"enable port");
238 if (! waitValue(m_eventEnabled, value))
239 debug_print(
"%s - port %d lost enable port event\n", name(), nPortIndex);
242 void disablePort(OMX_U32 nPortIndex = OMX_ALL)
244 unsigned value = m_eventDisabled + count2wait(nPortIndex);
245 ERR_OMX( OMX_SendCommand(m_component, OMX_CommandPortDisable, nPortIndex, NULL),
"disable port");
247 if (! waitValue(m_eventDisabled, value))
248 debug_print(
"%s - port %d lost disable port event\n", name(), nPortIndex);
251 void flushPort(OMX_U32 nPortIndex = OMX_ALL)
253 unsigned value = m_eventFlushed + count2wait(nPortIndex);
254 ERR_OMX( OMX_SendCommand(m_component, OMX_CommandFlush, nPortIndex, NULL),
"flush buffers");
256 if (! waitValue(m_eventFlushed, value))
257 debug_print(
"%s - port %d lost flush port event\n", name(), nPortIndex);
262 portDef->nPortIndex = nPortIndex;
263 ERR_OMX( OMX_GetParameter(m_component, OMX_IndexParamPortDefinition, &portDef),
"get port definition");
268 portDef->nPortIndex = nPortIndex;
269 ERR_OMX( OMX_SetParameter(m_component, OMX_IndexParamPortDefinition, &portDef),
"set port definition");
272 void allocBuffers(OMX_U32 nPortIndex,
Buffer& buffer)
275 getPortDefinition(nPortIndex, portDef);
277 ERR_OMX( OMX_AllocateBuffer(m_component, buffer.pHeader(), nPortIndex, 0, portDef->nBufferSize),
"OMX_AllocateBuffer");
280 void freeBuffers(OMX_U32 nPortIndex,
Buffer& buffer)
282 ERR_OMX( OMX_FreeBuffer(m_component, nPortIndex, buffer.header()),
"OMX_FreeBuffer");
285 void callFillThisBuffer(
Buffer& buffer)
287 ERR_OMX( OMX_FillThisBuffer(m_component, buffer.header()),
"OMX_FillThisBuffer");
292 void eventCmdComplete(OMX_U32 cmd, OMX_U32 )
296 case OMX_CommandStateSet:
300 case OMX_CommandFlush:
304 case OMX_CommandPortDisable:
308 case OMX_CommandPortEnable:
312 case OMX_CommandMarkBuffer:
318 void eventPortSettingsChanged(OMX_U32 )
325 OMX_HANDLETYPE m_component;
326 ComponentType m_type;
329 Component(ComponentType type, OMX_PTR pAppData, OMX_CALLBACKTYPE * callbacks)
337 OMX_STRING xName =
const_cast<OMX_STRING
>(name());
338 ERR_OMX( OMX_GetHandle(&m_component, xName, pAppData, callbacks),
"OMX_GetHandle");
347 ERR_OMX( OMX_FreeHandle(m_component),
"OMX_FreeHandle" );
351 OMXExeption::setLastError(e.code());
352 debug_print(
"OMXExeption: OMX_FreeHandle(), %s", e.what());
357 unsigned n2idx(OMX_U32 nPortIndex)
const {
return nPortIndex - m_type; }
358 unsigned idx2n(
unsigned idx)
const {
return m_type + idx; }
361 std::atomic<uint32_t> m_eventState;
362 std::atomic<uint32_t> m_eventFlushed;
363 std::atomic<uint32_t> m_eventDisabled;
364 std::atomic<uint32_t> m_eventEnabled;
366 bool waitValue(std::atomic<uint32_t>& value,
unsigned wantedValue)
368 static const unsigned WAIT_CHANGES_US = 10000;
369 static const unsigned MAX_WAIT_COUNT = 200;
371 for (
unsigned i = 0; i < MAX_WAIT_COUNT; ++i)
373 if (value >= wantedValue)
376 usleep(WAIT_CHANGES_US);
387 static const ComponentType cType = broadcom::CAMERA;
389 static const unsigned OPORT_PREVIEW = 70;
390 static const unsigned OPORT_VIDEO = 71;
391 static const unsigned OPORT_STILL = 72;
392 static const unsigned IPORT = 73;
394 static const unsigned CAM_DEVICE_NUMBER = 0;
396 static int32_t align(
unsigned x,
unsigned y)
398 return (x + y - 1) & (~(y - 1));
412 :
Component(cType, (OMX_PTR)
this, &cbsEvents),
416 setDeviceNumber(CAM_DEVICE_NUMBER);
419 tsMode->eTimestampMode = OMX_TimestampModeRawStc;
421 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexParamCommonUseStcTimestamps, &tsMode),
"camera timestamp mode");
424 void requestCallback()
427 cbtype->nPortIndex = OMX_ALL;
428 cbtype->nIndex = OMX_IndexParamCameraDeviceNumber;
429 cbtype->bEnable = OMX_TRUE;
431 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexConfigRequestCallback, &cbtype),
"request callbacks");
434 void setDeviceNumber(
unsigned camNumber)
437 device->nPortIndex = OMX_ALL;
438 device->nU32 = camNumber;
440 ERR_OMX( OMX_SetParameter(m_component, OMX_IndexParamCameraDeviceNumber, &device),
"set camera device number");
443 void setVideoFromat(
const VideoFromat& videoFormat)
446 getPortDefinition(OPORT_VIDEO, portDef);
448 portDef->format.video.nFrameWidth = videoFormat.width;
449 portDef->format.video.nFrameHeight = videoFormat.height;
450 portDef->format.video.xFramerate = videoFormat.framerate << 16;
451 portDef->format.video.nStride = align(portDef->format.video.nFrameWidth, portDef->nBufferAlignment);
452 portDef->format.video.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
454 setPortDefinition(OPORT_VIDEO, portDef);
458 void setFramerate(
unsigned fps)
461 framerate->xEncodeFramerate = fps << 16;
462 framerate->nPortIndex = OPORT_VIDEO;
464 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexConfigVideoFramerate, &framerate),
"set framerate");
468 void setSharpness(OMX_U32 nPortIndex = OMX_ALL, OMX_S32 nSharpness = 0)
471 sharpness->nPortIndex = nPortIndex;
472 sharpness->nSharpness = nSharpness;
474 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexConfigCommonSharpness, &sharpness),
"set camera sharpness");
478 void setContrast(OMX_U32 nPortIndex = OMX_ALL, OMX_S32 nContrast = 0)
481 contrast->nPortIndex = nPortIndex;
482 contrast->nContrast = nContrast;
484 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexConfigCommonContrast, &contrast),
"set camera contrast");
488 void setSaturation(OMX_U32 nPortIndex = OMX_ALL, OMX_S32 nSaturation = 0)
491 saturation->nPortIndex = nPortIndex;
492 saturation->nSaturation = nSaturation;
494 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexConfigCommonSaturation, &saturation),
"set camera saturation");
498 void setBrightness(OMX_U32 nPortIndex = OMX_ALL, OMX_U32 nBrightness = 50)
501 brightness->nPortIndex = nPortIndex;
502 brightness->nBrightness = nBrightness;
504 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexConfigCommonBrightness, &brightness),
"set camera brightness");
507 void setExposureValue(OMX_U32 nPortIndex = OMX_ALL,
508 OMX_S32 xEVCompensation = 0, OMX_U32 nSensitivity = 100, OMX_BOOL bAutoSensitivity = OMX_FALSE)
511 exposure_value->nPortIndex = nPortIndex;
512 exposure_value->xEVCompensation = xEVCompensation;
513 exposure_value->nSensitivity = nSensitivity;
514 exposure_value->bAutoSensitivity = bAutoSensitivity;
516 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexConfigCommonExposureValue, &exposure_value),
"set camera exposure value");
519 void setFrameStabilisation(OMX_U32 nPortIndex = OMX_ALL, OMX_BOOL bStab = OMX_TRUE)
522 frame_stabilisation_control->nPortIndex = nPortIndex;
523 frame_stabilisation_control->bStab = bStab;
525 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexConfigCommonFrameStabilisation, &frame_stabilisation_control),
526 "set camera frame stabilisation");
529 void setWhiteBalanceControl(OMX_U32 nPortIndex = OMX_ALL, OMX_WHITEBALCONTROLTYPE eWhiteBalControl = OMX_WhiteBalControlAuto)
532 white_balance_control->nPortIndex = nPortIndex;
533 white_balance_control->eWhiteBalControl = eWhiteBalControl;
535 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexConfigCommonWhiteBalance, &white_balance_control),
536 "set camera frame white balance");
539 void setImageFilter(OMX_U32 nPortIndex = OMX_ALL, OMX_IMAGEFILTERTYPE eImageFilter = OMX_ImageFilterNone)
542 image_filter->nPortIndex = nPortIndex;
543 image_filter->eImageFilter = eImageFilter;
545 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexConfigCommonImageFilter, &image_filter),
"set camera image filter");
549 void setMirror(OMX_U32 nPortIndex, OMX_MIRRORTYPE eMirror = OMX_MirrorNone)
552 mirror->nPortIndex = nPortIndex;
553 mirror->eMirror = eMirror;
555 ERR_OMX( OMX_SetConfig(m_component, OMX_IndexConfigCommonMirror, &mirror),
"set cammera mirror");
558 void setImageDefaults()
565 setFrameStabilisation();
566 setWhiteBalanceControl();
570 void capture(OMX_U32 nPortIndex, OMX_BOOL bEnabled)
573 capture->nPortIndex = nPortIndex;
574 capture->bEnabled = bEnabled;
576 ERR_OMX( OMX_SetParameter(m_component, OMX_IndexConfigPortCapturing, &capture),
"switch capture on port");
581 Component::allocBuffers(IPORT, m_bufferIn);
586 Component::freeBuffers(IPORT, m_bufferIn);
596 static const unsigned TIMEOUT_US = 100000;
597 static const unsigned MAX_ATTEMPTS = 10;
599 for (
unsigned i = 0; i < MAX_ATTEMPTS; ++i)
606 debug_print(
"lost ready event for Camera\n");
612 std::atomic_bool m_ready;
619 static const ComponentType cType = broadcom::VIDEO_ENCODER;
621 static const unsigned IPORT = 200;
622 static const unsigned OPORT = 201;
625 :
Component(cType, (OMX_PTR)
this, &cbsEvents),
633 getPortDefinition(OPORT, portDef);
635 portDef->format.video.nFrameWidth = cameraPortDef->format.video.nFrameWidth;
636 portDef->format.video.nFrameHeight = cameraPortDef->format.video.nFrameHeight;
637 portDef->format.video.xFramerate = cameraPortDef->format.video.xFramerate;
638 portDef->format.video.nStride = cameraPortDef->format.video.nStride;
639 portDef->format.video.nBitrate = bitrate;
642 portDef->format.video.xFramerate = framerate;
644 setPortDefinition(OPORT, portDef);
647 void setCodec(OMX_VIDEO_CODINGTYPE codec)
650 format->nPortIndex = OPORT;
651 format->eCompressionFormat = codec;
653 ERR_OMX( OMX_SetParameter(m_component, OMX_IndexParamVideoPortFormat, &format),
"set video format");
656 ppsOption->nPortIndex = OPORT;
657 ppsOption->bEnabled = OMX_TRUE;
659 ERR_OMX( OMX_SetParameter(m_component, OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, &ppsOption),
"enable SPS/PPS insertion");
662 void setBitrate(OMX_U32 bitrate, OMX_VIDEO_CONTROLRATETYPE type = OMX_Video_ControlRateVariable)
665 brate->nPortIndex = OPORT;
666 brate->eControlRate = type;
667 brate->nTargetBitrate = bitrate;
669 ERR_OMX( OMX_SetParameter(m_component, OMX_IndexParamVideoBitrate, &brate),
"set bitrate");
672 void setIFramePeriod(
unsigned value)
675 period->nPortIndex = OPORT;
676 period->nU32 = value;
678 ERR_OMX( OMX_SetParameter(m_component, OMX_IndexConfigBrcmVideoIntraPeriod, &period),
"set IFrame period");
683 Component::allocBuffers(OPORT, m_bufferOut);
689 Component::freeBuffers(OPORT, m_bufferOut);
692 void callFillThisBuffer()
694 Component::callFillThisBuffer(m_bufferOut);
701 callFillThisBuffer();
706 Buffer& outBuffer() {
return m_bufferOut; }
718 static const ComponentType cType = broadcom::NULL_SINK;
720 static const unsigned IPORT = 240;
723 :
Component(cType, (OMX_PTR)
this, &cbsEvents)
732 static const ComponentType cType = broadcom::VIDEO_SPLITTER;
734 static const unsigned IPORT = 250;
735 static const unsigned OPORT_1 = 251;
736 static const unsigned OPORT_2 = 252;
737 static const unsigned OPORT_3 = 253;
738 static const unsigned OPORT_4 = 254;
741 :
Component(cType, (OMX_PTR)
this, &cbsEvents)
750 static const ComponentType cType = broadcom::RESIZER;
752 static const unsigned IPORT = 60;
753 static const unsigned OPORT = 61;
756 :
Component(cType, (OMX_PTR)
this, &cbsEvents)
760 void setupOutputPort(
unsigned newWidth,
unsigned newHeight)
763 getPortDefinition(IPORT, portDef);
765 portDef->format.image.nFrameWidth = newWidth;
766 portDef->format.image.nFrameHeight = newHeight;
767 portDef->format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
769 portDef->format.image.nSliceHeight = 0;
770 portDef->format.image.nStride = 0;
772 setPortDefinition(OPORT, portDef);
Handler for OpenMAX IL errors.
Definition: rpi_omx.h:42
Base class for OpenMAX IL components.
Definition: rpi_omx.h:180
OpenMAX IL parameter.
Definition: rpi_omx.h:121
Raspberry Pi OpenMAX IL layer.
Definition: rpi_omx.cpp:5
OMX.broadcom.camera.
Definition: rpi_omx.h:384
OpenMAX IL CPU<->GPU buffer.
Definition: rpi_omx.h:153
Definition: rpi_omx_broadcom.h:67
static const VideoFromat VF_1920x1080
Definition: rpi_omx.h:100
OMX.broadcom.video_splitter.
Definition: rpi_omx.h:729
OMX.broadcom.null_sink.
Definition: rpi_omx.h:715
OMX.broadcom.video_encode.
Definition: rpi_omx.h:616
Definition: rpi_omx_broadcom.h:87
OMX.broadcom.resize.
Definition: rpi_omx.h:747