Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Original credits to Artem Zuikov
- //clone from https://github.com/4ertus2/rpi-cctv
- // Adding other functionnalities F5OEO Evariste - evaristec@gmail.com
- #ifndef OMX_SKIP64BIT
- #define OMX_SKIP64BIT
- #endif
- #include <cstdlib>
- #include <cstdio>
- #include <cstring>
- #include <string>
- #include <vector>
- #include <iostream>
- #include <inttypes.h>
- #include <math.h>
- #include "bcm_host.h"
- #include <interface/vcos/vcos_semaphore.h>
- #include <interface/vmcs_host/vchost.h>
- #include <IL/OMX_Core.h>
- #include <IL/OMX_Component.h>
- #include <IL/OMX_Video.h>
- #include <IL/OMX_Broadcom.h>
- #include <fcntl.h> /* low-level i/o */
- #include <unistd.h>
- #include <errno.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/mman.h>
- #include <sys/ioctl.h>
- #include "webcam.h"
- #include "MuxTs.h"
- namespace
- {
- static const char * format2str(OMX_VIDEO_CODINGTYPE c)
- {
- switch (c)
- {
- case OMX_VIDEO_CodingUnused: return "not used";
- case OMX_VIDEO_CodingAutoDetect: return "autodetect";
- case OMX_VIDEO_CodingMPEG2: return "MPEG2";
- case OMX_VIDEO_CodingH263: return "H.263";
- case OMX_VIDEO_CodingMPEG4: return "MPEG4";
- case OMX_VIDEO_CodingWMV: return "Windows Media Video";
- case OMX_VIDEO_CodingRV: return "RealVideo";
- case OMX_VIDEO_CodingAVC: return "H.264/AVC";
- case OMX_VIDEO_CodingMJPEG: return "Motion JPEG";
- case OMX_VIDEO_CodingVP6: return "VP6";
- case OMX_VIDEO_CodingVP7: return "VP7";
- case OMX_VIDEO_CodingVP8: return "VP8";
- case OMX_VIDEO_CodingYUV: return "Raw YUV video";
- case OMX_VIDEO_CodingSorenson: return "Sorenson";
- case OMX_VIDEO_CodingTheora: return "OGG Theora";
- case OMX_VIDEO_CodingMVC: return "H.264/MVC";
- default:
- std::cerr << "unknown OMX_VIDEO_CODINGTYPE: " << c << std::endl;
- return "unknown";
- }
- }
- static const char * format2str(OMX_COLOR_FORMATTYPE c)
- {
- switch (c)
- {
- case OMX_COLOR_FormatUnused: return "OMX_COLOR_FormatUnused: not used";
- case OMX_COLOR_FormatMonochrome: return "OMX_COLOR_FormatMonochrome";
- case OMX_COLOR_Format8bitRGB332: return "OMX_COLOR_Format8bitRGB332";
- case OMX_COLOR_Format12bitRGB444: return "OMX_COLOR_Format12bitRGB444";
- case OMX_COLOR_Format16bitARGB4444: return "OMX_COLOR_Format16bitARGB4444";
- case OMX_COLOR_Format16bitARGB1555: return "OMX_COLOR_Format16bitARGB1555";
- case OMX_COLOR_Format16bitRGB565: return "OMX_COLOR_Format16bitRGB565";
- case OMX_COLOR_Format16bitBGR565: return "OMX_COLOR_Format16bitBGR565";
- case OMX_COLOR_Format18bitRGB666: return "OMX_COLOR_Format18bitRGB666";
- case OMX_COLOR_Format18bitARGB1665: return "OMX_COLOR_Format18bitARGB1665";
- case OMX_COLOR_Format19bitARGB1666: return "OMX_COLOR_Format19bitARGB1666";
- case OMX_COLOR_Format24bitRGB888: return "OMX_COLOR_Format24bitRGB888";
- case OMX_COLOR_Format24bitBGR888: return "OMX_COLOR_Format24bitBGR888";
- case OMX_COLOR_Format24bitARGB1887: return "OMX_COLOR_Format24bitARGB1887";
- case OMX_COLOR_Format25bitARGB1888: return "OMX_COLOR_Format25bitARGB1888";
- case OMX_COLOR_Format32bitBGRA8888: return "OMX_COLOR_Format32bitBGRA8888";
- case OMX_COLOR_Format32bitARGB8888: return "OMX_COLOR_Format32bitARGB8888";
- case OMX_COLOR_FormatYUV411Planar: return "OMX_COLOR_FormatYUV411Planar";
- case OMX_COLOR_FormatYUV411PackedPlanar: return "OMX_COLOR_FormatYUV411PackedPlanar: Planes fragmented when a frame is split in multiple buffers";
- case OMX_COLOR_FormatYUV420Planar: return "OMX_COLOR_FormatYUV420Planar: Planar YUV, 4:2:0 (I420)";
- case OMX_COLOR_FormatYUV420PackedPlanar: return "OMX_COLOR_FormatYUV420PackedPlanar: Planar YUV, 4:2:0 (I420), planes fragmented when a frame is split in multiple buffers";
- case OMX_COLOR_FormatYUV420SemiPlanar: return "OMX_COLOR_FormatYUV420SemiPlanar, Planar YUV, 4:2:0 (NV12), U and V planes interleaved with first U value";
- case OMX_COLOR_FormatYUV422Planar: return "OMX_COLOR_FormatYUV422Planar";
- case OMX_COLOR_FormatYUV422PackedPlanar: return "OMX_COLOR_FormatYUV422PackedPlanar: Planes fragmented when a frame is split in multiple buffers";
- case OMX_COLOR_FormatYUV422SemiPlanar: return "OMX_COLOR_FormatYUV422SemiPlanar";
- case OMX_COLOR_FormatYCbYCr: return "OMX_COLOR_FormatYCbYCr";
- case OMX_COLOR_FormatYCrYCb: return "OMX_COLOR_FormatYCrYCb";
- case OMX_COLOR_FormatCbYCrY: return "OMX_COLOR_FormatCbYCrY";
- case OMX_COLOR_FormatCrYCbY: return "OMX_COLOR_FormatCrYCbY";
- case OMX_COLOR_FormatYUV444Interleaved: return "OMX_COLOR_FormatYUV444Interleaved";
- case OMX_COLOR_FormatRawBayer8bit: return "OMX_COLOR_FormatRawBayer8bit";
- case OMX_COLOR_FormatRawBayer10bit: return "OMX_COLOR_FormatRawBayer10bit";
- case OMX_COLOR_FormatRawBayer8bitcompressed: return "OMX_COLOR_FormatRawBayer8bitcompressed";
- case OMX_COLOR_FormatL2: return "OMX_COLOR_FormatL2";
- case OMX_COLOR_FormatL4: return "OMX_COLOR_FormatL4";
- case OMX_COLOR_FormatL8: return "OMX_COLOR_FormatL8";
- case OMX_COLOR_FormatL16: return "OMX_COLOR_FormatL16";
- case OMX_COLOR_FormatL24: return "OMX_COLOR_FormatL24";
- case OMX_COLOR_FormatL32: return "OMX_COLOR_FormatL32";
- case OMX_COLOR_FormatYUV420PackedSemiPlanar: return "OMX_COLOR_FormatYUV420PackedSemiPlanar: Planar YUV, 4:2:0 (NV12), planes fragmented when a frame is split in multiple buffers, U and V planes interleaved with first U value";
- case OMX_COLOR_FormatYUV422PackedSemiPlanar: return "OMX_COLOR_FormatYUV422PackedSemiPlanar: Planes fragmented when a frame is split in multiple buffers";
- case OMX_COLOR_Format18BitBGR666: return "OMX_COLOR_Format18BitBGR666";
- case OMX_COLOR_Format24BitARGB6666: return "OMX_COLOR_Format24BitARGB6666";
- case OMX_COLOR_Format24BitABGR6666: return "OMX_COLOR_Format24BitABGR6666";
- case OMX_COLOR_Format32bitABGR8888: return "OMX_COLOR_Format32bitABGR8888";
- case OMX_COLOR_Format8bitPalette: return "OMX_COLOR_Format8bitPalette";
- case OMX_COLOR_FormatYUVUV128: return "OMX_COLOR_FormatYUVUV128";
- case OMX_COLOR_FormatRawBayer12bit: return "OMX_COLOR_FormatRawBayer12bit";
- case OMX_COLOR_FormatBRCMEGL: return "OMX_COLOR_FormatBRCMEGL";
- case OMX_COLOR_FormatBRCMOpaque: return "OMX_COLOR_FormatBRCMOpaque";
- case OMX_COLOR_FormatYVU420PackedPlanar: return "OMX_COLOR_FormatYVU420PackedPlanar";
- case OMX_COLOR_FormatYVU420PackedSemiPlanar: return "OMX_COLOR_FormatYVU420PackedSemiPlanar";
- default:
- std::cerr << "unknown OMX_COLOR_FORMATTYPE: " << c << std::endl;
- return "unknown";
- }
- }
- static void dump_portdef(OMX_PARAM_PORTDEFINITIONTYPE* portdef)
- {
- fprintf(stderr, "Port %d is %s, %s, buffers wants:%d needs:%d, size:%d, pop:%d, aligned:%d\n",
- portdef->nPortIndex,
- (portdef->eDir == OMX_DirInput ? "input" : "output"),
- (portdef->bEnabled == OMX_TRUE ? "enabled" : "disabled"),
- portdef->nBufferCountActual,
- portdef->nBufferCountMin,
- portdef->nBufferSize,
- portdef->bPopulated,
- portdef->nBufferAlignment);
- OMX_VIDEO_PORTDEFINITIONTYPE *viddef = &portdef->format.video;
- OMX_IMAGE_PORTDEFINITIONTYPE *imgdef = &portdef->format.image;
- switch (portdef->eDomain)
- {
- case OMX_PortDomainVideo:
- fprintf(stderr, "Video type:\n"
- "\tWidth:\t\t%d\n"
- "\tHeight:\t\t%d\n"
- "\tStride:\t\t%d\n"
- "\tSliceHeight:\t%d\n"
- "\tBitrate:\t%d\n"
- "\tFramerate:\t%.02f\n"
- "\tError hiding:\t%s\n"
- "\tCodec:\t\t%s\n"
- "\tColor:\t\t%s\n",
- viddef->nFrameWidth,
- viddef->nFrameHeight,
- viddef->nStride,
- viddef->nSliceHeight,
- viddef->nBitrate,
- ((float)viddef->xFramerate / (float)65536),
- (viddef->bFlagErrorConcealment == OMX_TRUE ? "yes" : "no"),
- format2str(viddef->eCompressionFormat),
- format2str(viddef->eColorFormat));
- break;
- case OMX_PortDomainImage:
- fprintf(stderr, "Image type:\n"
- "\tWidth:\t\t%d\n"
- "\tHeight:\t\t%d\n"
- "\tStride:\t\t%d\n"
- "\tSliceHeight:\t%d\n"
- "\tError hiding:\t%s\n"
- "\tCodec:\t\t%s\n"
- "\tColor:\t\t%s\n",
- imgdef->nFrameWidth,
- imgdef->nFrameHeight,
- imgdef->nStride,
- imgdef->nSliceHeight,
- (imgdef->bFlagErrorConcealment == OMX_TRUE ? "yes" : "no"),
- format2str( (OMX_VIDEO_CODINGTYPE) imgdef->eCompressionFormat ),
- format2str(imgdef->eColorFormat));
- break;
- default:
- break;
- }
- }
- const char * eventType2Str(OMX_EVENTTYPE eEvent)
- {
- switch (eEvent)
- {
- case OMX_EventCmdComplete: return "OMX_EventCmdComplete";
- case OMX_EventError: return "OMX_EventError";
- case OMX_EventMark: return "OMX_EventMark";
- case OMX_EventPortSettingsChanged: return "OMX_EventPortSettingsChanged";
- case OMX_EventBufferFlag: return "OMX_EventBufferFlag";
- case OMX_EventResourcesAcquired: return "OMX_EventResourcesAcquired";
- case OMX_EventComponentResumed: return "OMX_EventComponentResumed";
- case OMX_EventDynamicResourcesAvailable: return "OMX_EventDynamicResourcesAvailable";
- case OMX_EventPortFormatDetected: return "OMX_EventPortFormatDetected";
- case OMX_EventKhronosExtensions: return "OMX_EventKhronosExtensions";
- case OMX_EventVendorStartUnused: return "OMX_EventVendorStartUnused";
- case OMX_EventParamOrConfigChanged: return "OMX_EventParamOrConfigChanged";
- default:
- break;
- };
- return nullptr;
- }
- static void printEvent(const char * compName, OMX_HANDLETYPE hComponent, OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2)
- {
- const char * strEvent = eventType2Str(eEvent);
- if (strEvent)
- fprintf(stderr, "%s (%p) %s, data: %d, %d\n", compName, hComponent, strEvent, nData1, nData2);
- else
- fprintf(stderr, "%s (%p) 0x%08x, data: %d, %d\n", compName, hComponent, eEvent, nData1, nData2);
- }
- }
- namespace broadcom
- {
- // TODO: add all
- typedef enum
- {
- VIDEO_SCHEDULER = 10,
- SOURCE = 20,
- RESIZER = 60,
- CAMERA = 70,
- CLOCK = 80,
- VIDEO_RENDER = 90,
- VIDEO_DECODER = 130,
- VIDEO_ENCODER = 200,
- EGL_RENDER = 220,
- NULL_SINK = 240,
- VIDEO_SPLITTER = 250,
- IMAGE_ENCODE = 340
- } ComponentType;
- static const char * componentType2name(ComponentType type)
- {
- switch (type)
- {
- case VIDEO_SCHEDULER: return "OMX.broadcom.video_scheduler";
- case SOURCE: return "OMX.broadcom.source";
- case RESIZER: return "OMX.broadcom.resize";
- case CAMERA: return "OMX.broadcom.camera";
- case CLOCK: return "OMX.broadcom.clock";
- case VIDEO_RENDER: return "OMX.broadcom.video_render";
- case VIDEO_DECODER: return "OMX.broadcom.video_decode";
- case VIDEO_ENCODER: return "OMX.broadcom.video_encode";
- case EGL_RENDER: return "OMX.broadcom.egl_render";
- case NULL_SINK: return "OMX.broadcom.null_sink";
- case VIDEO_SPLITTER: return "OMX.broadcom.video_splitter";
- case IMAGE_ENCODE: return "OMX.broadcom.image_encode";
- }
- return nullptr;
- }
- static unsigned componentPortsCount(ComponentType type)
- {
- switch (type)
- {
- case VIDEO_SCHEDULER: return 3;
- case SOURCE: return 1;
- case RESIZER: return 2;
- case CAMERA: return 4;
- case CLOCK: return 6;
- case VIDEO_RENDER: return 1;
- case VIDEO_DECODER: return 2;
- case VIDEO_ENCODER: return 2;
- case EGL_RENDER: return 2;
- case NULL_SINK: return 3;
- case VIDEO_SPLITTER: return 5;
- case IMAGE_ENCODE: return 2;
- }
- return 0;
- }
- struct VcosSemaphore
- {
- VcosSemaphore(const char * name)
- {
- if (vcos_semaphore_create(&sem_, name, 1) != VCOS_SUCCESS)
- throw "Failed to create handler lock semaphore";
- }
- ~VcosSemaphore()
- {
- vcos_semaphore_delete(&sem_);
- }
- VCOS_STATUS_T wait() { return vcos_semaphore_wait(&sem_); }
- VCOS_STATUS_T post() { return vcos_semaphore_post(&sem_); }
- private:
- VCOS_SEMAPHORE_T sem_;
- };
- class VcosLock
- {
- public:
- VcosLock(VcosSemaphore * sem)
- : sem_(sem)
- {
- sem_->wait();
- }
- ~VcosLock()
- {
- sem_->post();
- }
- private:
- VcosSemaphore * sem_;
- };
- }
- namespace rpi_omx
- {
- typedef broadcom::ComponentType ComponentType;
- using broadcom::componentType2name;
- using broadcom::componentPortsCount;
- using broadcom::VcosSemaphore;
- using Lock = broadcom::VcosLock;
- VcosSemaphore * pSemaphore;
- //
- static OMX_ERRORTYPE callback_EventHandler(
- OMX_HANDLETYPE hComponent,
- OMX_PTR pAppData,
- OMX_EVENTTYPE eEvent,
- OMX_U32 nData1,
- OMX_U32 nData2,
- OMX_PTR pEventData);
- static OMX_ERRORTYPE callback_EmptyBufferDone(
- OMX_HANDLETYPE hComponent,
- OMX_PTR pAppData,
- OMX_BUFFERHEADERTYPE * pBuffer);
- static OMX_ERRORTYPE callback_FillBufferDone(
- OMX_HANDLETYPE hComponent,
- OMX_PTR pAppData,
- OMX_BUFFERHEADERTYPE * pBuffer);
- OMX_CALLBACKTYPE cbsEvents = {
- .EventHandler = callback_EventHandler,
- .EmptyBufferDone = callback_EmptyBufferDone,
- .FillBufferDone = callback_FillBufferDone
- };
- //
- ///
- class OMXExeption
- {
- public:
- static const unsigned MAX_LEN = 512;
- OMXExeption(OMX_ERRORTYPE errCode, const char * file, unsigned line, const char * msg = nullptr)
- : errCode_(errCode)
- {
- if (msg && msg[0])
- snprintf(msg_, MAX_LEN, "%s:%d OpenMAX IL error: 0x%08x. %s", file, line, errCode, msg);
- else
- snprintf(msg_, MAX_LEN, "%s:%d OpenMAX IL error: 0x%08x", file, line, errCode);
- }
- OMX_ERRORTYPE code() const { return errCode_; }
- const char * what() const { return msg_; }
- static void die(OMX_ERRORTYPE error, const char * str)
- {
- const char * errStr = omxErr2str(error);
- fprintf(stderr, "OMX error: %s: 0x%08x %s\n", str, error, errStr);
- exit(1);
- }
- private:
- OMX_ERRORTYPE errCode_;
- char msg_[MAX_LEN];
- static const char * omxErr2str(OMX_ERRORTYPE error)
- {
- switch (error)
- {
- case OMX_ErrorNone: return "OMX_ErrorNone";
- case OMX_ErrorBadParameter: return "OMX_ErrorBadParameter";
- case OMX_ErrorIncorrectStateOperation: return "OMX_ErrorIncorrectStateOperation";
- case OMX_ErrorIncorrectStateTransition: return "OMX_ErrorIncorrectStateTransition";
- case OMX_ErrorInsufficientResources: return "OMX_ErrorInsufficientResources";
- case OMX_ErrorBadPortIndex: return "OMX_ErrorBadPortIndex";
- case OMX_ErrorHardware: return "OMX_ErrorHardware";
- // ...
- default:
- break;
- }
- return "";
- }
- };
- #define ERR_OMX(err, msg) if ((err) != OMX_ErrorNone) throw OMXExeption(err, __FILE__, __LINE__, msg)
- ///
- struct VideoFromat
- {
- typedef enum
- {
- RATIO_4x3,
- RATIO_16x9
- } Ratio;
- unsigned width;
- unsigned height;
- unsigned framerate;
- Ratio ratio;
- bool fov; //Field of view
- };
- static const VideoFromat VF_640x480 = { 640, 480, 30, VideoFromat:: RATIO_16x9, true };
- ///
- template <typename T>
- class Parameter
- {
- public:
- Parameter()
- {
- init();
- }
- void init()
- {
- memset(¶m_, 0, sizeof(param_));
- param_.nSize = sizeof(param_);
- param_.nVersion.nVersion = OMX_VERSION;
- param_.nVersion.s.nVersionMajor = OMX_VERSION_MAJOR;
- param_.nVersion.s.nVersionMinor = OMX_VERSION_MINOR;
- param_.nVersion.s.nRevision = OMX_VERSION_REVISION;
- param_.nVersion.s.nStep = OMX_VERSION_STEP;
- }
- T& operator * () { return param_; }
- T* operator & () { return ¶m_; }
- T* operator -> () { return ¶m_; }
- const T& operator * () const { return param_; }
- const T* operator & () const { return ¶m_; }
- const T* operator -> () const { return ¶m_; }
- private:
- T param_;
- };
- ///
- class OMXInit
- {
- public:
- OMXInit()
- {
- ERR_OMX( OMX_Init(), "OMX initalization failed" );
- }
- ~OMXInit()
- {
- try
- {
- ERR_OMX( OMX_Deinit(), "OMX de-initalization failed" );
- }
- catch (const OMXExeption& )
- {
- // TODO
- }
- }
- };
- ///
- class Buffer
- {
- public:
- Buffer()
- : ppBuffer_(nullptr),
- fillDone_(false)
- {}
- bool filled() const { return fillDone_; }
- void setFilled(bool val = true)
- {
- Lock lock(pSemaphore); // LOCK
- fillDone_ = val;
- }
- bool setDatasize(OMX_U32 Datasize)
- {
- if(Datasize<=allocSize())
- {
- ppBuffer_->nOffset=0;
- ppBuffer_->nFilledLen=Datasize;
- return true;
- }
- return false;
- }
- OMX_BUFFERHEADERTYPE ** pHeader() { return &ppBuffer_; }
- OMX_BUFFERHEADERTYPE * header() { return ppBuffer_; }
- OMX_U32 flags() const { return ppBuffer_->nFlags; }
- OMX_U32& flags() { return ppBuffer_->nFlags; }
- OMX_U8 * data() { return ppBuffer_->pBuffer + ppBuffer_->nOffset; }
- OMX_U32 dataSize() const { return ppBuffer_->nFilledLen; }
- OMX_U32 allocSize() const { return ppBuffer_->nAllocLen; }
- OMX_U32 TimeStamp() {return ppBuffer_->nTickCount;}
- private:
- OMX_BUFFERHEADERTYPE * ppBuffer_;
- bool fillDone_;
- };
- ///
- class Component
- {
- public:
- OMX_HANDLETYPE& component() { return component_; }
- ComponentType type() const { return type_; }
- const char * name() const { return componentType2name(type_); }
- unsigned numPorts() const { return componentPortsCount(type_); }
- void dumpPort(OMX_U32 nPortIndex, OMX_BOOL dumpFormats = OMX_FALSE)
- {
- Parameter<OMX_PARAM_PORTDEFINITIONTYPE> portdef;
- getPortDefinition(nPortIndex, portdef);
- dump_portdef(&portdef);
- if (dumpFormats)
- {
- Parameter<OMX_VIDEO_PARAM_PORTFORMATTYPE> portformat;
- portformat->nPortIndex = nPortIndex;
- portformat->nIndex = 0;
- std::cerr << "Port " << nPortIndex << " supports these video formats:" << std::endl;
- for (;; portformat->nIndex++)
- {
- OMX_ERRORTYPE err = OMX_GetParameter(component_, OMX_IndexParamVideoPortFormat, &portformat);
- if (err != OMX_ErrorNone)
- break;
- std::cerr << "\t" << format2str(portformat->eColorFormat)
- << ", compression: " << format2str(portformat->eCompressionFormat) << std::endl;
- }
- }
- }
- OMX_STATETYPE state()
- {
- OMX_STATETYPE state;
- ERR_OMX( OMX_GetState(component_, &state), "OMX_GetState" );
- return state;
- }
- void switchState(OMX_STATETYPE newState)
- {
- unsigned value = eventState_;
- ERR_OMX( OMX_SendCommand(component_, OMX_CommandStateSet, newState, NULL), "switch state");
- if (! waitValue(&eventState_, value + 1))
- std::cerr << name() << " lost state changed event" << std::endl;
- #if 0
- if (! waitStateChanged(newState))
- std::cerr << name() << " state wanted: " << newState << " observed: " << state() << std::endl;
- #endif
- }
- unsigned waitCount(OMX_U32 nPortIndex) const { return (nPortIndex == OMX_ALL) ? numPorts() : 1; }
- void enablePort(OMX_U32 nPortIndex = OMX_ALL)
- {
- unsigned value = eventEnabled_;
- ERR_OMX( OMX_SendCommand(component_, OMX_CommandPortEnable, nPortIndex, NULL), "enable port");
- if (! waitValue(&eventEnabled_, value + waitCount(nPortIndex)))
- std::cerr << name() << " port " << nPortIndex << " lost enable port event(s)" << std::endl;
- }
- void disablePort(OMX_U32 nPortIndex = OMX_ALL)
- {
- unsigned value = eventDisabled_;
- ERR_OMX( OMX_SendCommand(component_, OMX_CommandPortDisable, nPortIndex, NULL), "disable port");
- if (! waitValue(&eventDisabled_, value + waitCount(nPortIndex)))
- std::cerr << name() << " port " << nPortIndex << " lost disable port event(s)" << std::endl;
- }
- void flushPort(OMX_U32 nPortIndex = OMX_ALL)
- {
- unsigned value = eventFlushed_;
- ERR_OMX( OMX_SendCommand(component_, OMX_CommandFlush, nPortIndex, NULL), "flush buffers");
- if (! waitValue(&eventFlushed_, value + waitCount(nPortIndex)))
- std::cerr << name() << " port " << nPortIndex << " lost flush port event(s)" << std::endl;
- }
- void getPortDefinition(OMX_U32 nPortIndex, Parameter<OMX_PARAM_PORTDEFINITIONTYPE>& portDef)
- {
- portDef->nPortIndex = nPortIndex;
- ERR_OMX( OMX_GetParameter(component_, OMX_IndexParamPortDefinition, &portDef), "get port definition");
- }
- void setPortDefinition(OMX_U32 nPortIndex, Parameter<OMX_PARAM_PORTDEFINITIONTYPE>& portDef)
- {
- portDef->nPortIndex = nPortIndex;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamPortDefinition, &portDef), "set port definition");
- }
- void allocBuffers(OMX_U32 nPortIndex, Buffer& buffer)
- {
- Parameter<OMX_PARAM_PORTDEFINITIONTYPE> portDef;
- getPortDefinition(nPortIndex, portDef);
- ERR_OMX( OMX_AllocateBuffer(component_, buffer.pHeader(), nPortIndex, NULL, portDef->nBufferSize), "OMX_AllocateBuffer");
- }
- void freeBuffers(OMX_U32 nPortIndex, Buffer& buffer)
- {
- ERR_OMX( OMX_FreeBuffer(component_, nPortIndex, buffer.header()), "OMX_FreeBuffer");
- }
- void callFillThisBuffer(Buffer& buffer)
- {
- ERR_OMX( OMX_FillThisBuffer(component_, buffer.header()), "OMX_FillThisBuffer");
- }
- void callEmptyThisBuffer(Buffer& buffer)
- {
- ERR_OMX( OMX_EmptyThisBuffer(component_, buffer.header()), "OMX_EmptyThisBuffer");
- }
- void eventCmdComplete(OMX_U32 cmd, OMX_U32 /*nPortIndex*/)
- {
- Lock lock(pSemaphore); // LOCK
- switch (cmd)
- {
- case OMX_CommandStateSet:
- ++eventState_;
- break;
- case OMX_CommandFlush:
- ++eventFlushed_;
- break;
- case OMX_CommandPortDisable:
- ++eventDisabled_;
- break;
- case OMX_CommandPortEnable:
- ++eventEnabled_;
- break;
- case OMX_CommandMarkBuffer:
- default:
- break;
- }
- }
- void eventPortSettingsChanged(OMX_U32 nPortIndex)
- {
- Lock lock(pSemaphore); // LOCK
- ++changedPorts_[n2idx(nPortIndex)];
- }
- protected:
- OMX_HANDLETYPE component_;
- ComponentType type_;
- Component(ComponentType type, OMX_PTR pAppData, OMX_CALLBACKTYPE * callbacks)
- : type_(type),
- eventState_(0),
- eventFlushed_(0),
- eventDisabled_(0),
- eventEnabled_(0)
- {
- changedPorts_.resize(numPorts());
- OMX_STRING xName = const_cast<OMX_STRING>(name());
- ERR_OMX( OMX_GetHandle(&component_, xName, pAppData, callbacks), "OMX_GetHandle");
- disablePort();
- }
- ~Component()
- {
- try
- {
- ERR_OMX( OMX_FreeHandle(component_), "OMX_FreeHandle" );
- }
- catch (const OMXExeption& )
- {
- // TODO
- }
- }
- // type_ equals to first port number
- unsigned n2idx(OMX_U32 nPortIndex) const { return nPortIndex - type_; }
- unsigned idx2n(unsigned idx) const { return type_ + idx; }
- private:
- static const unsigned WAIT_CHANGES_US = 1000;
- static const unsigned MAX_WAIT_COUNT = 200;
- unsigned eventState_;
- unsigned eventFlushed_;
- unsigned eventDisabled_;
- unsigned eventEnabled_;
- std::vector<unsigned> changedPorts_;
- // TODO: wait for specific port changes
- bool waitValue(unsigned * pValue, unsigned wantedValue)
- {
- for (unsigned i = 0; i < MAX_WAIT_COUNT; ++i)
- {
- if (*pValue == wantedValue)
- return true;
- usleep(WAIT_CHANGES_US);
- }
- return false;
- }
- #if 0
- bool waitStateChanged(OMX_STATETYPE wantedState)
- {
- for (unsigned i=0; i < MAX_WAIT_COUNT; ++i)
- {
- if (state() == wantedState)
- return true;
- usleep(WAIT_CHANGES_US);
- }
- return false;
- }
- #endif
- };
- ///
- class Encoder : public Component
- {
- public:
- static const ComponentType cType = broadcom::VIDEO_ENCODER;
- static const unsigned IPORT = 200;
- static const unsigned OPORT = 201;
- Encoder()
- : Component(cType, (OMX_PTR) this, &cbsEvents)
- {
- }
- void setupOutputPortFromCamera(const Parameter<OMX_PARAM_PORTDEFINITIONTYPE>& cameraPortDef, unsigned bitrate, unsigned framerate=0 ) // Framerate 0 means get it from Camera when tunelled
- {
- Parameter<OMX_PARAM_PORTDEFINITIONTYPE> portDef;
- getPortDefinition(OPORT, portDef);
- portDef->format.video.nFrameWidth = cameraPortDef->format.video.nFrameWidth;
- portDef->format.video.nFrameHeight = cameraPortDef->format.video.nFrameHeight;
- portDef->format.video.xFramerate = cameraPortDef->format.video.xFramerate;
- portDef->format.video.nStride = cameraPortDef->format.video.nStride;
- portDef->format.video.nBitrate = bitrate;
- printf("FPS=%x\n",cameraPortDef->format.video.xFramerate);
- if (framerate)
- portDef->format.video.xFramerate = framerate<<16;
- setPortDefinition(OPORT, portDef);
- }
- void setupOutputPort(const VideoFromat Videoformat, unsigned bitrate, unsigned framerate = 0)
- {
- // Input Definition
- Parameter<OMX_PARAM_PORTDEFINITIONTYPE> portDefI;
- getPortDefinition(IPORT, portDefI);
- portDefI->format.video.nFrameWidth = Videoformat.width;
- portDefI->format.video.nFrameHeight = Videoformat.height;
- portDefI->format.video.xFramerate = framerate<<16;
- portDefI->format.video.nStride = 0;//(portDefI->format.video.nFrameWidth + portDefI->nBufferAlignment - 1) & (~(portDefI->nBufferAlignment - 1));
- portDefI->format.video.nSliceHeight=0;
- portDefI->format.video.eColorFormat=OMX_COLOR_FormatYUV420PackedPlanar;
- setPortDefinition(IPORT, portDefI);
- // Output definition : copy from input
- Parameter<OMX_PARAM_PORTDEFINITIONTYPE> portDef;
- getPortDefinition(OPORT, portDef);
- //portDefI->nPortIndex = OPORT;
- //portDef->format.video.eColorFormat=OMX_COLOR_FormatUnused;
- portDef->format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
- portDef->format.video.nBitrate=bitrate;
- portDef->format.video.nFrameWidth = Videoformat.width;
- portDef->format.video.nFrameHeight = Videoformat.height;
- portDef->format.video.xFramerate= framerate<<16;
- setPortDefinition(OPORT, portDef);
- }
- void setCodec(OMX_VIDEO_CODINGTYPE codec)
- {
- Parameter<OMX_VIDEO_PARAM_PORTFORMATTYPE> format;
- format->nPortIndex = OPORT;
- format->eCompressionFormat = codec;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamVideoPortFormat, &format), "set video format");
- }
- void setProfileLevel(int Profile=OMX_VIDEO_AVCProfileMain,int Level=OMX_VIDEO_AVCLevel32)
- {
- //OMX_VIDEO_AVCProfileBaseline,OMX_VIDEO_AVCProfileMain,OMX_VIDEO_AVCProfileExtended, OMX_VIDEO_AVCProfileHigh
- //OMX_VIDEO_AVCLevel3
- Parameter<OMX_VIDEO_PARAM_PROFILELEVELTYPE> ProfileLevel;
- ProfileLevel->nPortIndex = OPORT;
- ProfileLevel->eProfile = Profile;
- ProfileLevel->eLevel = Level;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamVideoProfileLevelCurrent, &ProfileLevel), "set Profile/Level");
- }
- void setBitrate(OMX_U32 bitrate, OMX_VIDEO_CONTROLRATETYPE type = OMX_Video_ControlRateVariable)
- {
- // https://github.com/raspberrypi/firmware/issues/329#issuecomment-61696016
- Parameter<OMX_VIDEO_PARAM_BITRATETYPE> brate;
- brate->nPortIndex = OPORT;
- brate->eControlRate = type;
- brate->nTargetBitrate = bitrate;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamVideoBitrate, &brate), "set bitrate");
- }
- void setIDR(OMX_U32 idr_period/*, OMX_U32 nPFrames*/)
- {
- Parameter<OMX_VIDEO_CONFIG_AVCINTRAPERIOD> idr_st;
- idr_st->nPortIndex= OPORT;
- idr_st->nIDRPeriod = idr_period;
- printf("idr %d p%d\n",idr_st->nIDRPeriod,idr_st->nPFrames);
- //idr_st->nPFrames=nPFrames;
- ERR_OMX( OMX_GetParameter(component_, OMX_IndexConfigVideoAVCIntraPeriod, &idr_st)," Get idr");
- idr_st->nPFrames=idr_period-1;
- idr_st->nIDRPeriod = idr_period;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexConfigVideoAVCIntraPeriod, &idr_st), "set idr");
- }
- void setVectorMotion()
- {
- Parameter<OMX_CONFIG_PORTBOOLEANTYPE> motionvector;
- motionvector->nPortIndex= OPORT;
- motionvector->bEnabled=OMX_TRUE;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamBrcmVideoAVCInlineVectorsEnable, &motionvector), "set vector motion");
- }
- // Measure Quality of coding
- void setEED()
- {
- Parameter<OMX_VIDEO_EEDE_ENABLE> EED;
- EED->nPortIndex= OPORT;
- EED->enable=OMX_TRUE;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamBrcmEEDEEnable, &EED), "EED");
- Parameter<OMX_VIDEO_EEDE_LOSSRATE> EEDRate;
- EEDRate->nPortIndex= OPORT;
- EEDRate->loss_rate= 1; // Set to no packet lost on transmission
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamBrcmEEDELossRate, &EEDRate), "EED");
- }
- void setSEIMessage()
- {
- Parameter<OMX_CONFIG_PORTBOOLEANTYPE> InlineHeader; //SPS/PPS
- InlineHeader->nPortIndex= OPORT;
- InlineHeader->bEnabled=OMX_TRUE;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, &InlineHeader), "InlineHeader");
- Parameter<OMX_CONFIG_PORTBOOLEANTYPE> SPSTiming; //SPS Timing Enable
- SPSTiming->nPortIndex= OPORT;
- SPSTiming->bEnabled=OMX_TRUE;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamBrcmVideoAVCSPSTimingEnable, &SPSTiming), "SPS Timing Enable");
- Parameter<OMX_CONFIG_PORTBOOLEANTYPE> SEIMessage;
- SEIMessage->nPortIndex= OPORT;
- SEIMessage->bEnabled=OMX_TRUE;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamBrcmVideoAVCSEIEnable, &SEIMessage), "SEIMessage");
- Parameter<OMX_CONFIG_PORTBOOLEANTYPE> VCLHRD; //HRD ENABLE IN HEADER
- VCLHRD->nPortIndex= OPORT;
- VCLHRD->bEnabled=OMX_TRUE;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamBrcmVideoAVC_VCLHRDEnable, &VCLHRD), "VLCHRD");
- }
- void setLowLatency()
- {
- Parameter<OMX_CONFIG_PORTBOOLEANTYPE> LowHRD; //HRD Low delay FLAG
- LowHRD->nPortIndex= OPORT;
- LowHRD->bEnabled=OMX_TRUE;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamBrcmVideoAVC_LowDelayHRDEnable, &LowHRD), "HRD Low Delay");
- }
- void setSeparateNAL()
- {
- Parameter<OMX_CONFIG_PORTBOOLEANTYPE> SepNAL;
- SepNAL->nPortIndex= OPORT;
- SepNAL->bEnabled=OMX_TRUE;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamBrcmNALSSeparate, &SepNAL), "Separate NAL");
- }
- void setMinizeFragmentation()
- {
- Parameter<OMX_CONFIG_PORTBOOLEANTYPE> MinizeFragmentation;
- MinizeFragmentation->nPortIndex= OPORT;
- MinizeFragmentation->bEnabled=OMX_TRUE;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexConfigMinimiseFragmentation, &MinizeFragmentation), "Minimize Fragmentation");
- }
- void setMaxFrameLimits(int FrameLimitInBits)
- {
- // Seems that if above this limit, encoder do not output frame !!
- Parameter<OMX_PARAM_U32TYPE> MaxFrameLimit;
- MaxFrameLimit->nPortIndex= OPORT;
- MaxFrameLimit->nU32=FrameLimitInBits;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamBrcmVideoFrameLimitBits, &MaxFrameLimit), "MaxFrameLimit");
- }
- void setPeakRate(int PeakRateinKbit)
- {
- Parameter<OMX_PARAM_U32TYPE> PeakRate;
- PeakRate->nPortIndex= OPORT;
- ERR_OMX( OMX_GetParameter(component_, OMX_IndexParamBrcmVideoPeakRate, &PeakRate)," GetPeakRate");
- printf("\nPEAK GET = %d\n",PeakRate->nU32);
- PeakRate->nU32=PeakRateinKbit;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamBrcmVideoPeakRate, &PeakRate), "PeakRateinKbit");
- ERR_OMX( OMX_GetParameter(component_, OMX_IndexParamBrcmVideoPeakRate, &PeakRate)," GetPeakRate");
- printf("\nPEAK GET 2 = %d\n",PeakRate->nU32);
- // Peak video bitrate in bits per second. Must be larger or equal to the average video bitrate. It is ignored if the video bitrate mode is set to constant bitrate.
- }
- void setDynamicBitrate(int VideoBitrate)
- {
- Parameter<OMX_VIDEO_CONFIG_BITRATETYPE> DynamicBitrate;
- DynamicBitrate->nPortIndex= OPORT;
- DynamicBitrate->nEncodeBitrate = VideoBitrate;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexConfigVideoBitrate, &DynamicBitrate), "DynamicVideoBitRate");
- }
- //Set QP restrict QP : means if encoder choose a QP which is not in this range, Frame is dropped
- void setQPLimits(int QMin=0,int QMax=0)
- {
- Parameter<OMX_PARAM_U32TYPE> QPMin;
- QPMin->nPortIndex=OPORT;
- QPMin->nU32=QMin;
- ERR_OMX( OMX_SetParameter(component_,OMX_IndexParamBrcmVideoEncodeMinQuant, &QPMin)," QPMin");
- Parameter<OMX_PARAM_U32TYPE> QPMax;
- QPMax->nPortIndex=OPORT;
- QPMax->nU32=QMax;
- ERR_OMX( OMX_SetParameter(component_,OMX_IndexParamBrcmVideoEncodeMaxQuant, &QPMax)," QPMax");
- }
- void setQFromBitrate(int Bitrate,int fps,int Width,int Height,int MotionType=0)
- {
- int Coeff=2;
- //int QPCalculation=10+Width*Height*fps*Coeff/((Bitrate));
- //For 720*576, 25fps : QP=280birate⁻(0,345)
- int QPCalculation=281*pow(Bitrate*(25/fps)*(720/Width)*(576/Height)/1000.0,-0.345)+10;
- printf("QP=%d\n",QPCalculation);
- if(QPCalculation>48) QPCalculation=48; //Fixme
- if(QPCalculation<10) QPCalculation=10; //Fixme
- setQPLimits(QPCalculation,QPCalculation);
- }
- // ONLY IF RATECONTROL is not CBR/VBR
- void setQP(int QPi,int QPp)
- {
- Parameter<OMX_VIDEO_PARAM_QUANTIZATIONTYPE> QP;
- QP->nPortIndex=OPORT;
- QP->nQpI=QPi;
- QP->nQpP=QPp;
- QP->nQpB=0; // No B Frame, only zero is allowed
- ERR_OMX( OMX_SetParameter(component_,OMX_IndexParamBrcmVideoEncodeQpP, &QP)," QP");
- }
- void setMultiSlice(int SliceSize)
- {
- Parameter<OMX_VIDEO_PARAM_INTRAREFRESHTYPE> IntraRefreshType;
- IntraRefreshType->nPortIndex=OPORT;
- ERR_OMX( OMX_GetParameter(component_, OMX_IndexParamVideoIntraRefresh, &IntraRefreshType)," IntraRefreshMode");
- IntraRefreshType->eRefreshMode=OMX_VIDEO_IntraRefreshCyclicMrows;
- IntraRefreshType->nCirMBs=SliceSize;
- ERR_OMX( OMX_SetParameter(component_, OMX_IndexParamVideoIntraRefresh, &IntraRefreshType)," IntraRefreshMode");
- }
- void getEncoderStat(int Flags)
- {
- char debug[255];
- sprintf(debug,"");
- if(Flags&OMX_BUFFERFLAG_ENDOFFRAME) strcat(debug,"ENDOFFRAME ");
- if(Flags&OMX_BUFFERFLAG_SYNCFRAME) strcat(debug,"SYNCFRAME ");
- if(Flags&OMX_BUFFERFLAG_CODECCONFIG) strcat(debug,"CODECCONFIG ");
- if(Flags&OMX_BUFFERFLAG_ENDOFNAL) strcat(debug,"ENDOFNAL ");
- static struct timespec tbefore;
- static int Count=0;
- Parameter<OMX_CONFIG_BRCMPORTSTATSTYPE> VideoStat;
- VideoStat->nPortIndex= OPORT;
- ERR_OMX( OMX_GetParameter(component_, OMX_IndexConfigBrcmPortStats, &VideoStat)," Get VideoStat");
- struct timespec t;
- clock_gettime(CLOCK_REALTIME, &t);
- printf("VideoStat : %s ByteCount %d Buffer %d - Frame %d = %d Skip %d Discard %d Max Delta%d:%d TIME %li\n",/*VideoStat->nByteCount.nLowPart*8*25/VideoStat->nFrameCount,*/debug,VideoStat->nByteCount.nLowPart,VideoStat->nBufferCount,VideoStat->nFrameCount,VideoStat->nBufferCount-VideoStat->nFrameCount*2,VideoStat->nFrameSkips,VideoStat->nDiscards,VideoStat->nMaxTimeDelta.nHighPart,VideoStat->nMaxTimeDelta.nLowPart,( t.tv_sec -tbefore.tv_sec )*1000ul + ( t.tv_nsec - tbefore.tv_nsec)/1000000);
- tbefore=t;
- Count++;
- }
- void allocBuffers(bool WithBuffIn=false)
- {
- Component::allocBuffers(OPORT, bufferOut_);
- HaveABufferIn=WithBuffIn;
- if(HaveABufferIn)
- {
- Component::allocBuffers(IPORT, bufferIn_);
- }
- }
- void freeBuffers()
- {
- Component::freeBuffers(OPORT, bufferOut_);
- if(HaveABufferIn)
- Component::freeBuffers(IPORT, bufferIn_);
- }
- void callFillThisBuffer()
- {
- Component::callFillThisBuffer(bufferOut_);
- }
- void callEmptyThisBuffer()
- {
- Component::callEmptyThisBuffer(bufferIn_);
- }
- Buffer& outBuffer() { return bufferOut_; }
- Buffer& inBuffer() { return bufferIn_; }
- private:
- Parameter<OMX_PARAM_PORTDEFINITIONTYPE> encoderPortDef_;
- Buffer bufferOut_;
- Buffer bufferIn_;
- bool HaveABufferIn=false;
- };
- class VideoSplitter : public Component
- {
- public:
- static const ComponentType cType = broadcom::VIDEO_SPLITTER;
- static const unsigned IPORT = 250;
- static const unsigned OPORT_1 = 251;
- static const unsigned OPORT_2 = 252;
- static const unsigned OPORT_3 = 253;
- static const unsigned OPORT_4 = 254;
- VideoSplitter()
- : Component(cType, (OMX_PTR) this, &cbsEvents)
- {
- }
- void setupOutputPort(int SrcImageWidth,int SrcImageHeight,const VideoFromat Videoformat,OMX_COLOR_FORMATTYPE colortype)
- {
- Parameter<OMX_PARAM_PORTDEFINITIONTYPE> portDefI;
- getPortDefinition(IPORT, portDefI);
- portDefI->format.video.nFrameWidth = SrcImageWidth;
- portDefI->format.video.nFrameHeight = SrcImageHeight;
- portDefI->format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
- if(colortype==OMX_COLOR_FormatYUV420PackedPlanar)
- {
- portDefI->format.video.nStride = 0;
- portDefI->format.video.nSliceHeight=SrcImageHeight;
- printf("%d * %d\n",portDefI->format.video.nStride,portDefI->format.video.nSliceHeight);
- }
- else
- { portDefI->format.video.nStride =0 ;
- portDefI->format.video.nSliceHeight=0;
- }
- portDefI->format.video.eColorFormat=colortype;
- setPortDefinition(IPORT, portDefI);
- // Output definition
- }
- void allocBuffers()
- {
- Component::allocBuffers(IPORT, bufferIn_);
- }
- void freeBuffers()
- {
- Component::freeBuffers(IPORT, bufferIn_);
- }
- void callEmptyThisBuffer()
- {
- Component::callEmptyThisBuffer(bufferIn_);
- }
- Buffer& inBuffer() { return bufferIn_; }
- private:
- Buffer bufferIn_;
- };
- //
- static OMX_ERRORTYPE callback_EventHandler(
- OMX_HANDLETYPE hComponent,
- OMX_PTR pAppData,
- OMX_EVENTTYPE eEvent,
- OMX_U32 nData1,
- OMX_U32 nData2,
- OMX_PTR pEventData)
- {
- Component * component = static_cast<Component *>(pAppData);
- printEvent(component->name(), hComponent, eEvent, nData1, nData2);
- switch (eEvent)
- {
- case OMX_EventCmdComplete:
- {
- switch (nData1)
- {
- case OMX_CommandFlush:
- case OMX_CommandPortDisable:
- case OMX_CommandPortEnable:
- case OMX_CommandMarkBuffer:
- // nData2 is port index
- component->eventCmdComplete(nData1, nData2);
- break;
- case OMX_CommandStateSet:
- // nData2 is state
- component->eventCmdComplete(nData1, nData2);
- break;
- default:
- break;
- }
- break;
- }
- case OMX_EventPortSettingsChanged:
- {
- // nData1 is port index
- component->eventPortSettingsChanged(nData1);
- break;
- }
- // vendor specific
- case OMX_EventParamOrConfigChanged:
- {
- if (nData2 == OMX_IndexParamCameraDeviceNumber)
- {
- }
- break;
- }
- case OMX_EventError:
- OMXExeption::die( (OMX_ERRORTYPE) nData1, "OMX_EventError received");
- break;
- case OMX_EventMark:
- case OMX_EventResourcesAcquired:
- case OMX_EventBufferFlag:
- default:
- break;
- }
- return OMX_ErrorNone;
- }
- static OMX_ERRORTYPE callback_EmptyBufferDone(OMX_HANDLETYPE, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE * pBuffer)
- {
- Component * component = static_cast<Component *>(pAppData);
- if (component->type() == Encoder::cType)
- {
- //printf("Filled %d Timestamp %li\n",pBuffer->nFilledLen,pBuffer->nTickCount);
- Encoder * encoderHigh = static_cast<Encoder *>(pAppData);
- encoderHigh->inBuffer().setFilled();
- Encoder * encoderLow = static_cast<Encoder *>(pAppData);
- encoderLow->inBuffer().setFilled();
- }
- if (component->type() == VideoSplitter::cType)
- {
- VideoSplitter * vsplitter = static_cast<VideoSplitter *>(pAppData);
- vsplitter->inBuffer().setFilled();
- }
- return OMX_ErrorNone;
- }
- static OMX_ERRORTYPE callback_FillBufferDone(OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE * pBuffer)
- {
- Component * component = static_cast<Component *>(pAppData);
- if (component->type() == Encoder::cType)
- {
- printf("Filled %d Timestamp %li\n",pBuffer->nFilledLen,pBuffer->nTickCount);
- Encoder * encoderHigh = static_cast<Encoder *>(pAppData);
- encoderHigh->outBuffer().setFilled();
- Encoder * encoderLow = static_cast<Encoder *>(pAppData);
- encoderLow->outBuffer().setFilled();
- }
- return OMX_ErrorNone;
- }
- }
- // Global variable used by the signal handler and capture/encoding loop
- static int want_quit = 0;
- #if 1
- // Global signal handler for trapping SIGINT, SIGTERM, and SIGQUIT
- static void signal_handler(int signal)
- {
- want_quit = 1;
- }
- #endif
- using namespace rpi_omx;
- static const unsigned VIDEO_BITRATE_HIGH = 800000;
- static const unsigned VIDEO_BITRATE_LOW = 400000;
- static const unsigned VIDEO_BITRATE_MEDIUM = 100000;
- class PictureTots
- {
- private:
- Encoder encoder;
- VideoSplitter vsplitter;
- Encoder encoderHigh;
- Encoder encoderLow;
- Encoder encoderMedium;
- //ImageEncode colorconverter;
- int EncVideoBitrate;
- bool FirstTime=true;
- uint key_frame=0; //key frame is set to 0. if there is 1 then segmentation fault occurs
- VideoFromat CurrentVideoFormat;
- int Videofps;
- struct timespec last_time;
- int Mode=Mode_V4L2;
- Webcam *pwebcam;
- MuxTs mux;
- FILE * outHigh = fopen("x.h264", "w+");
- FILE *outLow = fopen("y.h264" , "w+");
- FILE *outMedium = fopen("z.h264" , "w+");
- struct timespec InitTime;
- public:
- static const int Mode_PATTERN=0;
- static const int Mode_V4L2=1;
- public:
- void Init(VideoFromat &VideoFormat,char *FileName,int VideoBitrate,int fps=0,int IDRPeriod=100,int ModeInput=Mode_V4L2,char *Extra=NULL)
- {
- Parameter<OMX_PARAM_PORTDEFINITIONTYPE> portDef;
- CurrentVideoFormat=VideoFormat;
- Videofps=fps;
- EncVideoBitrate=VideoBitrate;
- Mode=ModeInput;
- if(Mode==Mode_V4L2)
- {
- pwebcam=new Webcam(Extra);
- int CamWidth,CamHeight;
- pwebcam->GetCameraSize(CamWidth,CamHeight);
- printf("Video Splitter input = %d x %d\n",CamWidth,CamHeight);
- vsplitter.setupOutputPort(CamWidth,CamHeight,VideoFormat,OMX_COLOR_FormatYUV420PackedPlanar);
- }
- if(Mode==Mode_PATTERN)
- {
- vsplitter.setupOutputPort(VideoFormat.width,VideoFormat.height,VideoFormat,OMX_COLOR_FormatYUV420PackedPlanar);
- }
- // configuring encoders
- encoderHigh.setupOutputPort(VideoFormat,VIDEO_BITRATE_HIGH,fps);
- //OMX_Video_ControlRateDisable seems not supported !!!
- encoderHigh.setCodec(OMX_VIDEO_CodingAVC);
- encoderHigh.setBitrate(VIDEO_BITRATE_HIGH,OMX_Video_ControlRateVariable/*OMX_Video_ControlRateConstant*/);
- encoderHigh.setIDR(IDRPeriod);
- encoderHigh.setSEIMessage();
- encoderHigh.setQFromBitrate(VideoBitrate,Videofps,CurrentVideoFormat.width,CurrentVideoFormat.height);
- encoderHigh.setQPLimits(0,0);
- encoderHigh.setQP(0,0);
- encoderHigh.setLowLatency();
- encoderHigh.setSeparateNAL();
- encoderHigh.setMinizeFragmentation();
- encoderHigh.setEED();
- //Low bitrate
- encoderLow.setupOutputPort(VideoFormat,VIDEO_BITRATE_LOW,fps);
- //OMX_Video_ControlRateDisable seems not supported !!!
- encoderLow.setCodec(OMX_VIDEO_CodingAVC);
- encoderLow.setBitrate(VIDEO_BITRATE_LOW,OMX_Video_ControlRateVariable/*OMX_Video_ControlRateConstant*/);
- encoderLow.setIDR(IDRPeriod);
- encoderLow.setSEIMessage();
- encoderLow.setQFromBitrate(VideoBitrate,Videofps,CurrentVideoFormat.width,CurrentVideoFormat.height);
- encoderLow.setQPLimits(0,0);
- encoderLow.setQP(0,0);
- encoderLow.setLowLatency();
- encoderLow.setSeparateNAL();
- encoderLow.setMinizeFragmentation();
- encoderLow.setEED();
- encoderMedium.setupOutputPort(VideoFormat,VIDEO_BITRATE_MEDIUM,fps);
- //OMX_Video_ControlRateDisable seems not supported !!!
- encoderMedium.setCodec(OMX_VIDEO_CodingAVC);
- encoderMedium.setBitrate(VIDEO_BITRATE_MEDIUM,OMX_Video_ControlRateVariable/*OMX_Video_ControlRateConstant*/);
- encoderMedium.setIDR(IDRPeriod);
- encoderMedium.setSEIMessage();
- encoderMedium.setQFromBitrate(VideoBitrate,Videofps,CurrentVideoFormat.width,CurrentVideoFormat.height);
- encoderMedium.setQPLimits(0,0);
- encoderMedium.setQP(0,0);
- encoderMedium.setLowLatency();
- encoderMedium.setSeparateNAL();
- encoderMedium.setMinizeFragmentation();
- encoderMedium.setEED();
- // With Main Profile : have more skipped frame
- ERR_OMX( OMX_SetupTunnel(vsplitter.component(), VideoSplitter::OPORT_1, encoderHigh.component(), Encoder::IPORT),
- "tunnel splitter.output -> encoder.input (high)");
- ERR_OMX( OMX_SetupTunnel(vsplitter.component(), VideoSplitter::OPORT_2, encoderLow.component(), Encoder::IPORT),
- "tunnel splitter.output -> encoder.input (low)");
- ERR_OMX( OMX_SetupTunnel(vsplitter.component(), VideoSplitter::OPORT_3, encoderMedium.component(), Encoder::IPORT),
- "tunnel splitter.output -> encoder.input (Medium)");
- vsplitter.dumpPort(VideoSplitter::IPORT, OMX_FALSE);
- vsplitter.dumpPort(VideoSplitter::OPORT_1, OMX_FALSE);
- vsplitter.dumpPort(VideoSplitter::OPORT_2, OMX_FALSE);
- vsplitter.dumpPort(VideoSplitter::OPORT_3, OMX_FALSE);
- encoderHigh.dumpPort(Encoder::IPORT, OMX_FALSE);
- encoderHigh.dumpPort(Encoder::OPORT, OMX_FALSE);
- encoderLow.dumpPort(Encoder::IPORT, OMX_FALSE);
- encoderLow.dumpPort(Encoder::OPORT, OMX_FALSE);
- encoderMedium.dumpPort(Encoder::IPORT, OMX_FALSE);
- encoderMedium.dumpPort(Encoder::OPORT, OMX_FALSE);
- // switch components to idle state
- {
- vsplitter.switchState(OMX_StateIdle);
- encoderHigh.switchState(OMX_StateIdle);
- encoderLow.switchState(OMX_StateIdle);
- encoderMedium.switchState(OMX_StateIdle);
- }
- // enable ports
- {
- vsplitter.enablePort(VideoSplitter::IPORT);
- vsplitter.enablePort(VideoSplitter::OPORT_1);
- vsplitter.enablePort(VideoSplitter::OPORT_2);
- vsplitter.enablePort(VideoSplitter::OPORT_3);
- encoderHigh.enablePort();
- encoderLow.enablePort();
- encoderMedium.enablePort();
- }
- // allocate buffers
- vsplitter.allocBuffers();
- encoderHigh.allocBuffers();
- encoderLow.allocBuffers();
- encoderMedium.allocBuffers();
- if(Mode==Mode_V4L2)
- {
- pwebcam->SetOmxBuffer((unsigned char*)vsplitter.inBuffer().data());
- }
- // switch state of the components prior to starting
- {
- vsplitter.switchState(OMX_StateExecuting);
- encoderHigh.switchState(OMX_StateExecuting);
- encoderLow.switchState(OMX_StateExecuting);
- encoderMedium.switchState(OMX_StateExecuting);
- }
- }
- void Run(bool want_quit)
- {
- Buffer& encBufferHigh = encoderHigh.outBuffer();
- Buffer& encBufferLow = encoderLow.outBuffer();
- Buffer& encBufferMedium = encoderMedium.outBuffer();
- Buffer& PictureBuffer = vsplitter.inBuffer();
- if(!want_quit&&(FirstTime||PictureBuffer.filled()))
- {
- OMX_U32 filledLen;
- if(Mode==Mode_PATTERN)
- {
- }
- if(Mode==Mode_V4L2)
- {
- auto frame = pwebcam->frame(2);
- filledLen=frame.size;
- }
- PictureBuffer.setDatasize(filledLen);
- PictureBuffer.setFilled(false);
- vsplitter.callEmptyThisBuffer();
- if(FirstTime)
- {
- clock_gettime(CLOCK_REALTIME, &InitTime);
- FirstTime=false;
- encoderHigh.callFillThisBuffer();
- encoderLow.callFillThisBuffer();
- encoderMedium.callFillThisBuffer();
- }
- }
- MuxTs m;
- std::cout<<m.CreateFile("test.ts");
- m.AddNewProgram(0x1000, 0x01);
- m.AddNewStream(0x301,MUXTS_CODEC_H264);
- m.AddNewStream(0x401,MUXTS_CODEC_H264);
- m.AddNewStream(0x501,MUXTS_CODEC_H264);
- if (!want_quit&&(encBufferHigh.filled() && encBufferLow.filled() && encBufferMedium.filled()))
- {
- // for checking how much frames and bytes encoder is giving
- //encoderHigh.getEncoderStat(encBufferHigh.flags());
- //encoderLow.getEncoderStat(encBufferLow.flags());
- //encoderMedium.getEncoderStat(encBufferMedium.flags());
- encoderHigh.setDynamicBitrate(EncVideoBitrate);
- /*if(key_frame%250==0)
- {
- QP--;
- encoder.setQPLimits(QP,QP);
- printf("------ QP =%d\n",QP);
- }*/
- if(encBufferHigh.flags() & OMX_BUFFERFLAG_CODECSIDEINFO)
- {
- printf("CODEC CONFIG>\n");
- int LenVector=encBufferHigh.dataSize();
- for(int j=0;j<CurrentVideoFormat.height/16;j++)
- {
- for(int i=0;i<CurrentVideoFormat.width/16;i++)
- {
- int Motionx=encBufferHigh.data()[(CurrentVideoFormat.width/16*j+i)*4];
- int Motiony=encBufferHigh.data()[(CurrentVideoFormat.width/16*j+i)*4+1];
- int MotionAmplitude=sqrt((double)((Motionx * Motionx) + (Motiony * Motiony)));
- printf("%d ",MotionAmplitude);
- }
- printf("\n");
- }
- encBufferHigh.setFilled(false);
- encoderHigh.callFillThisBuffer();
- return;
- }
- m.WriteFrame(encBufferHigh.data(),encBufferHigh.dataSize(),3600,MUXTS_CODEC_H264);
- // for low data rate saving to file
- if(encBufferLow.flags() & OMX_BUFFERFLAG_CODECSIDEINFO)
- {
- printf("CODEC CONFIG>\n");
- int LenVector=encBufferLow.dataSize();
- for(int j=0;j<CurrentVideoFormat.height/16;j++)
- {
- for(int i=0;i<CurrentVideoFormat.width/16;i++)
- {
- int Motionx=encBufferLow.data()[(CurrentVideoFormat.width/16*j+i)*4];
- int Motiony=encBufferLow.data()[(CurrentVideoFormat.width/16*j+i)*4+1];
- int MotionAmplitude=sqrt((double)((Motionx * Motionx) + (Motiony * Motiony)));
- printf("%d ",MotionAmplitude);
- }
- printf("\n");
- }
- encBufferLow.setFilled(false);
- encoderLow.callFillThisBuffer();
- return;
- }
- m.WriteFrame(encBufferLow.data(),encBufferLow.dataSize(),3601,MUXTS_CODEC_H264);
- // For 3rd bit rate
- if(encBufferMedium.flags() & OMX_BUFFERFLAG_CODECSIDEINFO)
- {
- printf("CODEC CONFIG>\n");
- int LenVector=encBufferMedium.dataSize();
- for(int j=0;j<CurrentVideoFormat.height/16;j++)
- {
- for(int i=0;i<CurrentVideoFormat.width/16;i++)
- {
- int Motionx=encBufferMedium.data()[(CurrentVideoFormat.width/16*j+i)*4];
- int Motiony=encBufferMedium.data()[(CurrentVideoFormat.width/16*j+i)*4+1];
- int MotionAmplitude=sqrt((double)((Motionx * Motionx) + (Motiony * Motiony)));
- printf("%d ",MotionAmplitude);
- }
- printf("\n");
- }
- encBufferMedium.setFilled(false);
- encoderMedium.callFillThisBuffer();
- return;
- }
- m.WriteFrame(encBufferMedium.data(),encBufferMedium.dataSize(),3603,MUXTS_CODEC_H264);
- // Buffer flushed, request a new buffer to be filled by the encoder component
- encBufferHigh.setFilled(false);
- encBufferLow.setFilled(false);
- encBufferMedium.setFilled(false);
- //PictureBuffer.setFilled(true);
- encoderHigh.callFillThisBuffer();
- encoderLow.callFillThisBuffer();
- encoderMedium.callFillThisBuffer();
- m.CloseFile();
- }
- else usleep(1000);
- }
- void Terminate()
- {
- if(Mode==Mode_V4L2)
- {
- free(pwebcam);
- }
- encoderHigh.outBuffer().flags() &= OMX_BUFFERFLAG_EOS;
- encoderLow.outBuffer().flags() &= OMX_BUFFERFLAG_EOS;
- encoderMedium.outBuffer().flags() &= OMX_BUFFERFLAG_EOS;
- // flush the buffers on each component
- {
- vsplitter.flushPort();
- encoderHigh.flushPort();
- encoderLow.flushPort();
- encoderMedium.flushPort();
- }
- // disable all the ports
- {
- vsplitter.disablePort();
- encoderHigh.disablePort();
- encoderLow.disablePort();
- encoderMedium.disablePort();
- }
- // free all the buffers
- {
- vsplitter.freeBuffers();
- encoderHigh.freeBuffers();
- encoderLow.freeBuffers();
- encoderMedium.freeBuffers();
- }
- // transition all the components to idle states
- {
- vsplitter.switchState(OMX_StateIdle);
- encoderHigh.switchState(OMX_StateIdle);
- encoderLow.switchState(OMX_StateIdle);
- encoderMedium.switchState(OMX_StateIdle);
- }
- // transition all the components to loaded states
- {
- vsplitter.switchState(OMX_StateLoaded);
- encoderHigh.switchState(OMX_StateLoaded);
- encoderLow.switchState(OMX_StateLoaded);
- encoderMedium.switchState(OMX_StateLoaded);
- }
- }
- };
- int main(int argc, char **argv)
- {
- char *OutputFileName="out.ts";
- int VideoBitrate=300000;
- int VideoWidth=352;
- int VideoHeight=288;
- int VideoFramerate=30;
- int IDRPeriod=100;
- char *ExtraArg=NULL;
- #define CAMERA 0
- #define PATTERN 1
- #define USB_CAMERA 2
- int TypeInput=USB_CAMERA;
- VideoFromat CurrentVideoFormat;
- CurrentVideoFormat.width=VideoWidth;
- CurrentVideoFormat.height=VideoHeight;
- CurrentVideoFormat.framerate=VideoFramerate;
- CurrentVideoFormat.ratio=VideoFromat::RATIO_16x9;
- CurrentVideoFormat.fov=false; // To check
- bcm_host_init();
- try
- {
- OMXInit omx;
- VcosSemaphore sem("common semaphore");
- pSemaphore = &sem;
- PictureTots *picturetots;
- if(TypeInput==0)
- {
- }
- else
- {
- int PictureMode=PictureTots::Mode_PATTERN;
- switch(TypeInput)
- {
- case PATTERN:PictureMode=PictureTots::Mode_PATTERN;break;
- case USB_CAMERA:PictureMode=PictureTots::Mode_V4L2;
- if(ExtraArg==NULL) ExtraArg="/dev/video0";break;
- }
- picturetots = new PictureTots;
- picturetots->Init(CurrentVideoFormat,OutputFileName,VideoBitrate,VideoFramerate,IDRPeriod,PictureMode,ExtraArg);
- }
- #if 1
- signal(SIGINT, signal_handler);
- signal(SIGTERM, signal_handler);
- signal(SIGQUIT, signal_handler);
- signal(SIGKILL, signal_handler);
- #endif
- std::cerr << "Enter capture and encode loop, press Ctrl-C to quit..." << std::endl;
- unsigned highCount = 0;
- unsigned lowCount = 0;
- unsigned MediumCount = 0;
- while (1)
- {
- if(TypeInput==2)
- picturetots->Run(want_quit);
- ++highCount;
- ++lowCount;
- ++MediumCount;
- if (want_quit /*&& (encBufferLow.flags() & OMX_BUFFERFLAG_SYNCFRAME)*/)
- {
- std::cerr << "Clean Exiting " << std::endl;
- break;
- }
- }
- std::cerr << "high: " << highCount << " low: " << lowCount << "Medium"<< MediumCount << std::endl;
- #if 1
- // Restore signal handlers
- signal(SIGINT, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
- signal(SIGQUIT, SIG_DFL);
- signal(SIGKILL, SIG_DFL);
- #endif
- if(TypeInput==0)
- {
- }
- else
- {
- picturetots->Terminate();
- delete(picturetots);
- }
- }
- catch (const OMXExeption& e)
- {
- OMXExeption::die(e.code(), e.what());
- }
- catch (const char * msg)
- {
- std::cerr << msg;
- return 1;
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement