721 lines
22 KiB
C
721 lines
22 KiB
C
|
#ifndef camera_helper_h__
|
||
|
#define camera_helper_h__
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <vector>
|
||
|
|
||
|
#include <cv.h>
|
||
|
#include <highgui.h>
|
||
|
#include <opencv2/imgcodecs.hpp>
|
||
|
|
||
|
#include <mfapi.h>
|
||
|
#include <mfidl.h>
|
||
|
#include <mfreadwrite.h>
|
||
|
#include <mferror.h>
|
||
|
|
||
|
#include <DShow.h>
|
||
|
|
||
|
#include <comet/ptr.h>
|
||
|
|
||
|
#include <comet_task_ptr.h>
|
||
|
#include <comet_com_ptr_array.h>
|
||
|
|
||
|
namespace comet {
|
||
|
|
||
|
#define MAKE_COMET_COMTYPE(T, BASE) \
|
||
|
template<> struct comtype< ::T > \
|
||
|
{ \
|
||
|
static const IID& uuid() { return IID_ ## T; } \
|
||
|
typedef ::BASE base; \
|
||
|
}
|
||
|
|
||
|
MAKE_COMET_COMTYPE(IMF2DBuffer, IUnknown);
|
||
|
MAKE_COMET_COMTYPE(IAMVideoProcAmp, IUnknown);
|
||
|
MAKE_COMET_COMTYPE(IAMCameraControl, IUnknown);
|
||
|
}
|
||
|
|
||
|
struct cam_prop_range
|
||
|
{
|
||
|
long min;
|
||
|
long max;
|
||
|
long step;
|
||
|
long defaultValue;
|
||
|
bool canBeAuto;
|
||
|
bool canBeManual;
|
||
|
};
|
||
|
|
||
|
inline std::ostream& operator<<(std::ostream& os, const cam_prop_range& val)
|
||
|
{
|
||
|
os << "[" << val.min << ":" << val.step << ":" << val.max << "], " << val.defaultValue;
|
||
|
if (val.canBeAuto && val.canBeManual)
|
||
|
os << " (auto/manual)";
|
||
|
else if (val.canBeAuto)
|
||
|
os << " (auto)";
|
||
|
else if (val.canBeManual)
|
||
|
os << " (manual)";
|
||
|
return os;
|
||
|
}
|
||
|
|
||
|
struct cam_prop_value
|
||
|
{
|
||
|
long value;
|
||
|
bool isAuto;
|
||
|
|
||
|
cam_prop_value() : value(0), isAuto(true)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
cam_prop_value(long value, bool isAuto = false) : value(value), isAuto(isAuto)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
operator long() const
|
||
|
{
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
static cam_prop_value AUTO(long value = 0) {
|
||
|
return cam_prop_value(value, true);
|
||
|
};
|
||
|
static cam_prop_value MANUAL(long value = 0) {
|
||
|
return cam_prop_value(value, false);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
inline std::ostream& operator<<(std::ostream& os, const cam_prop_value& val)
|
||
|
{
|
||
|
os << val.value;
|
||
|
os << " (";
|
||
|
if (val.isAuto)
|
||
|
os << "auto";
|
||
|
else
|
||
|
os << "manual";
|
||
|
os << ")";
|
||
|
return os;
|
||
|
}
|
||
|
|
||
|
namespace MediaFormat
|
||
|
{
|
||
|
enum e
|
||
|
{
|
||
|
Unknown,
|
||
|
RGB32, // MFVideoFormat_RGB32
|
||
|
ARGB32, // MFVideoFormat_ARGB32
|
||
|
RGB24, // MFVideoFormat_RGB24
|
||
|
RGB555, // MFVideoFormat_RGB555
|
||
|
RGB565, // MFVideoFormat_RGB565
|
||
|
RGB8, // MFVideoFormat_RGB8
|
||
|
AI44, // MFVideoFormat_AI44
|
||
|
AYUV, // MFVideoFormat_AYUV
|
||
|
YUY2, // MFVideoFormat_YUY2
|
||
|
YVYU, // MFVideoFormat_YVYU
|
||
|
YVU9, // MFVideoFormat_YVU9
|
||
|
UYVY, // MFVideoFormat_UYVY
|
||
|
NV11, // MFVideoFormat_NV11
|
||
|
NV12, // MFVideoFormat_NV12
|
||
|
YV12, // MFVideoFormat_YV12
|
||
|
I420, // MFVideoFormat_I420
|
||
|
IYUV, // MFVideoFormat_IYUV
|
||
|
Y210, // MFVideoFormat_Y210
|
||
|
Y216, // MFVideoFormat_Y216
|
||
|
Y410, // MFVideoFormat_Y410
|
||
|
Y416, // MFVideoFormat_Y416
|
||
|
Y41P, // MFVideoFormat_Y41P
|
||
|
Y41T, // MFVideoFormat_Y41T
|
||
|
Y42T, // MFVideoFormat_Y42T
|
||
|
P210, // MFVideoFormat_P210
|
||
|
P216, // MFVideoFormat_P216
|
||
|
P010, // MFVideoFormat_P010
|
||
|
P016, // MFVideoFormat_P016
|
||
|
v210, // MFVideoFormat_v210
|
||
|
v216, // MFVideoFormat_v216
|
||
|
v410, // MFVideoFormat_v410
|
||
|
MP43, // MFVideoFormat_MP43
|
||
|
MP4S, // MFVideoFormat_MP4S
|
||
|
M4S2, // MFVideoFormat_M4S2
|
||
|
MP4V, // MFVideoFormat_MP4V
|
||
|
WMV1, // MFVideoFormat_WMV1
|
||
|
WMV2, // MFVideoFormat_WMV2
|
||
|
WMV3, // MFVideoFormat_WMV3
|
||
|
WVC1, // MFVideoFormat_WVC1
|
||
|
MSS1, // MFVideoFormat_MSS1
|
||
|
MSS2, // MFVideoFormat_MSS2
|
||
|
MPG1, // MFVideoFormat_MPG1
|
||
|
DVSL, // MFVideoFormat_DVSL
|
||
|
DVSD, // MFVideoFormat_DVSD
|
||
|
DVHD, // MFVideoFormat_DVHD
|
||
|
DV25, // MFVideoFormat_DV25
|
||
|
DV50, // MFVideoFormat_DV50
|
||
|
DVH1, // MFVideoFormat_DVH1
|
||
|
DVC, // MFVideoFormat_DVC
|
||
|
H264, // MFVideoFormat_H264
|
||
|
MJPG, // MFVideoFormat_MJPG
|
||
|
YUV_420O, // MFVideoFormat_420O
|
||
|
H263, // MFVideoFormat_H263
|
||
|
H264_ES, // MFVideoFormat_H264_ES
|
||
|
MPEG2, // MFVideoFormat_MPEG2
|
||
|
};
|
||
|
|
||
|
inline e fromGUID(GUID guid)
|
||
|
{
|
||
|
if (guid == MFVideoFormat_RGB32) return RGB32;
|
||
|
else if (guid == MFVideoFormat_ARGB32) return ARGB32;
|
||
|
else if (guid == MFVideoFormat_RGB24) return RGB24;
|
||
|
else if (guid == MFVideoFormat_RGB555) return RGB555;
|
||
|
else if (guid == MFVideoFormat_RGB565) return RGB565;
|
||
|
else if (guid == MFVideoFormat_RGB8) return RGB8;
|
||
|
else if (guid == MFVideoFormat_AI44) return AI44;
|
||
|
else if (guid == MFVideoFormat_AYUV) return AYUV;
|
||
|
else if (guid == MFVideoFormat_YUY2) return YUY2;
|
||
|
else if (guid == MFVideoFormat_YVYU) return YVYU;
|
||
|
else if (guid == MFVideoFormat_YVU9) return YVU9;
|
||
|
else if (guid == MFVideoFormat_UYVY) return UYVY;
|
||
|
else if (guid == MFVideoFormat_NV11) return NV11;
|
||
|
else if (guid == MFVideoFormat_NV12) return NV12;
|
||
|
else if (guid == MFVideoFormat_YV12) return YV12;
|
||
|
else if (guid == MFVideoFormat_I420) return I420;
|
||
|
else if (guid == MFVideoFormat_IYUV) return IYUV;
|
||
|
else if (guid == MFVideoFormat_Y210) return Y210;
|
||
|
else if (guid == MFVideoFormat_Y216) return Y216;
|
||
|
else if (guid == MFVideoFormat_Y410) return Y410;
|
||
|
else if (guid == MFVideoFormat_Y416) return Y416;
|
||
|
else if (guid == MFVideoFormat_Y41P) return Y41P;
|
||
|
else if (guid == MFVideoFormat_Y41T) return Y41T;
|
||
|
else if (guid == MFVideoFormat_Y42T) return Y42T;
|
||
|
else if (guid == MFVideoFormat_P210) return P210;
|
||
|
else if (guid == MFVideoFormat_P216) return P216;
|
||
|
else if (guid == MFVideoFormat_P010) return P010;
|
||
|
else if (guid == MFVideoFormat_P016) return P016;
|
||
|
else if (guid == MFVideoFormat_v210) return v210;
|
||
|
else if (guid == MFVideoFormat_v216) return v216;
|
||
|
else if (guid == MFVideoFormat_v410) return v410;
|
||
|
else if (guid == MFVideoFormat_MP43) return MP43;
|
||
|
else if (guid == MFVideoFormat_MP4S) return MP4S;
|
||
|
else if (guid == MFVideoFormat_M4S2) return M4S2;
|
||
|
else if (guid == MFVideoFormat_MP4V) return MP4V;
|
||
|
else if (guid == MFVideoFormat_WMV1) return WMV1;
|
||
|
else if (guid == MFVideoFormat_WMV2) return WMV2;
|
||
|
else if (guid == MFVideoFormat_WMV3) return WMV3;
|
||
|
else if (guid == MFVideoFormat_WVC1) return WVC1;
|
||
|
else if (guid == MFVideoFormat_MSS1) return MSS1;
|
||
|
else if (guid == MFVideoFormat_MSS2) return MSS2;
|
||
|
else if (guid == MFVideoFormat_MPG1) return MPG1;
|
||
|
else if (guid == MFVideoFormat_DVSL) return DVSL;
|
||
|
else if (guid == MFVideoFormat_DVSD) return DVSD;
|
||
|
else if (guid == MFVideoFormat_DVHD) return DVHD;
|
||
|
else if (guid == MFVideoFormat_DV25) return DV25;
|
||
|
else if (guid == MFVideoFormat_DV50) return DV50;
|
||
|
else if (guid == MFVideoFormat_DVH1) return DVH1;
|
||
|
else if (guid == MFVideoFormat_DVC) return DVC;
|
||
|
else if (guid == MFVideoFormat_H264) return H264;
|
||
|
else if (guid == MFVideoFormat_MJPG) return MJPG;
|
||
|
else if (guid == MFVideoFormat_420O) return YUV_420O;
|
||
|
else if (guid == MFVideoFormat_H263) return H263;
|
||
|
else if (guid == MFVideoFormat_H264_ES) return H264_ES;
|
||
|
else if (guid == MFVideoFormat_MPEG2) return MPEG2;
|
||
|
else return Unknown;
|
||
|
}
|
||
|
|
||
|
inline const char* to_string (const MediaFormat::e& format)
|
||
|
{
|
||
|
switch (format)
|
||
|
{
|
||
|
case RGB32: return "RGB32";
|
||
|
case ARGB32: return "ARGB32";
|
||
|
case RGB24: return "RGB24";
|
||
|
case RGB555: return "RGB555";
|
||
|
case RGB565: return "RGB565";
|
||
|
case RGB8: return "RGB8";
|
||
|
case AI44: return "AI44";
|
||
|
case AYUV: return "AYUV";
|
||
|
case YUY2: return "YUY2";
|
||
|
case YVYU: return "YVYU";
|
||
|
case YVU9: return "YVU9";
|
||
|
case UYVY: return "UYVY";
|
||
|
case NV11: return "NV11";
|
||
|
case NV12: return "NV12";
|
||
|
case YV12: return "YV12";
|
||
|
case I420: return "I420";
|
||
|
case IYUV: return "IYUV";
|
||
|
case Y210: return "Y210";
|
||
|
case Y216: return "Y216";
|
||
|
case Y410: return "Y410";
|
||
|
case Y416: return "Y416";
|
||
|
case Y41P: return "Y41P";
|
||
|
case Y41T: return "Y41T";
|
||
|
case Y42T: return "Y42T";
|
||
|
case P210: return "P210";
|
||
|
case P216: return "P216";
|
||
|
case P010: return "P010";
|
||
|
case P016: return "P016";
|
||
|
case v210: return "v210";
|
||
|
case v216: return "v216";
|
||
|
case v410: return "v410";
|
||
|
case MP43: return "MP43";
|
||
|
case MP4S: return "MP4S";
|
||
|
case M4S2: return "M4S2";
|
||
|
case MP4V: return "MP4V";
|
||
|
case WMV1: return "WMV1";
|
||
|
case WMV2: return "WMV2";
|
||
|
case WMV3: return "WMV3";
|
||
|
case WVC1: return "WVC1";
|
||
|
case MSS1: return "MSS1";
|
||
|
case MSS2: return "MSS2";
|
||
|
case MPG1: return "MPG1";
|
||
|
case DVSL: return "DVSL";
|
||
|
case DVSD: return "DVSD";
|
||
|
case DVHD: return "DVHD";
|
||
|
case DV25: return "DV25";
|
||
|
case DV50: return "DV50";
|
||
|
case DVH1: return "DVH1";
|
||
|
case DVC: return "DVC";
|
||
|
case H264: return "H264";
|
||
|
case MJPG: return "MJPG";
|
||
|
case YUV_420O: return "420O";
|
||
|
case H263: return "H263";
|
||
|
case H264_ES: return "H264_ES";
|
||
|
case MPEG2: return "MPEG2";
|
||
|
default: return "Unknown";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline std::ostream& operator<< (std::ostream& os, const MediaFormat::e& format)
|
||
|
{
|
||
|
return os << to_string(format);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class media_type
|
||
|
{
|
||
|
public:
|
||
|
media_type() : _ptr(NULL)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
media_type(IMFMediaType* ptr) : _ptr(ptr)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
media_type(comet::com_ptr<IMFMediaType> ptr) : _ptr(ptr)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
cv::Size resolution() const
|
||
|
{
|
||
|
UINT32 width, height;
|
||
|
MFGetAttributeSize(_ptr.in(), MF_MT_FRAME_SIZE, &width, &height) | comet::raise_exception;
|
||
|
return cv::Size(width, height);
|
||
|
}
|
||
|
|
||
|
double framerate() const
|
||
|
{
|
||
|
UINT32 num, denom;
|
||
|
MFGetAttributeRatio(_ptr.in(), MF_MT_FRAME_RATE, &num, &denom) | comet::raise_exception;
|
||
|
return static_cast<double>(num) / denom;
|
||
|
}
|
||
|
|
||
|
MediaFormat::e format() const
|
||
|
{
|
||
|
GUID subtype;
|
||
|
_ptr->GetGUID(MF_MT_SUBTYPE, &subtype) | comet::raise_exception;
|
||
|
return MediaFormat::fromGUID(subtype);
|
||
|
}
|
||
|
|
||
|
#ifdef _TYPEDEF_BOOL_TYPE
|
||
|
typedef media_type _Myt;
|
||
|
_TYPEDEF_BOOL_TYPE;
|
||
|
_OPERATOR_BOOL() const _NOEXCEPT
|
||
|
{ // test for non-null pointer
|
||
|
return (_ptr != 0 ? _CONVERTIBLE_TO_TRUE : 0);
|
||
|
}
|
||
|
#else
|
||
|
explicit operator bool() const
|
||
|
{ // test for non-null pointer
|
||
|
return _ptr != 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
comet::com_ptr<IMFMediaType> _ptr;
|
||
|
};
|
||
|
|
||
|
|
||
|
class camera
|
||
|
{
|
||
|
public:
|
||
|
camera()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
camera(IMFActivate* ptr) : activate_ptr(ptr)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
camera(comet::com_ptr<IMFActivate> ptr) : activate_ptr(ptr)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// TODO actually implement these or make sure they are deleted/created correctly, this might be the reason for weird mapping of stuff
|
||
|
camera(const camera& other)
|
||
|
{
|
||
|
// this->
|
||
|
// this = other;
|
||
|
}
|
||
|
//= delete;
|
||
|
|
||
|
camera(camera&& other)
|
||
|
{
|
||
|
*this = std::move(other);
|
||
|
}
|
||
|
|
||
|
//camera& operator=(const camera& other) = delete;
|
||
|
|
||
|
camera& operator=(camera&& other)
|
||
|
{
|
||
|
activate_ptr.swap(other.activate_ptr);
|
||
|
source_ptr.swap(other.source_ptr);
|
||
|
reader_ptr.swap(other.reader_ptr);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
~camera()
|
||
|
{
|
||
|
shutdown();
|
||
|
}
|
||
|
|
||
|
bool is_active() const
|
||
|
{
|
||
|
return !source_ptr.is_null();
|
||
|
}
|
||
|
|
||
|
void activate()
|
||
|
{
|
||
|
if (activate_ptr)
|
||
|
activate_ptr->ActivateObject(IID_IMFMediaSource, reinterpret_cast<void**>(source_ptr.out())) | comet::raise_exception;
|
||
|
reader_ptr = NULL;
|
||
|
}
|
||
|
|
||
|
void shutdown()
|
||
|
{
|
||
|
if (activate_ptr)
|
||
|
activate_ptr->ShutdownObject() | comet::raise_exception;
|
||
|
source_ptr = NULL;
|
||
|
reader_ptr = NULL;
|
||
|
}
|
||
|
|
||
|
cv::Mat read_frame(int streamIndex = MF_SOURCE_READER_FIRST_VIDEO_STREAM, int bufferIndex = 0)
|
||
|
{
|
||
|
if (!activate_ptr)
|
||
|
return cv::Mat();
|
||
|
|
||
|
if (!reader_ptr)
|
||
|
{
|
||
|
comet::com_ptr<IMFAttributes> pAttributes;
|
||
|
MFCreateAttributes(pAttributes.out(), 1) | comet::raise_exception;
|
||
|
pAttributes->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, TRUE) | comet::raise_exception;
|
||
|
pAttributes->SetUINT32(MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN, TRUE) | comet::raise_exception;
|
||
|
|
||
|
MFCreateSourceReaderFromMediaSource(source_ptr.in(), pAttributes.in(), reader_ptr.out()) | comet::raise_exception;
|
||
|
}
|
||
|
|
||
|
comet::com_ptr<IMFSample> sample;
|
||
|
DWORD actualStreamIndex, flags;
|
||
|
LONGLONG timestamp;
|
||
|
try
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
reader_ptr->ReadSample(
|
||
|
streamIndex, // Stream index.
|
||
|
0, // Flags.
|
||
|
&actualStreamIndex, // Receives the actual stream index.
|
||
|
&flags, // Receives status flags.
|
||
|
×tamp, // Receives the time stamp.
|
||
|
sample.out() // Receives the sample or NULL.
|
||
|
) | comet::raise_exception;
|
||
|
} while (sample == NULL && (flags & MF_SOURCE_READERF_STREAMTICK));
|
||
|
}
|
||
|
catch (std::exception& e)
|
||
|
{
|
||
|
std::cerr << "Error getting frame: " << e.what() << std::endl;
|
||
|
std::cerr << " flags: " << flags << std::endl;
|
||
|
shutdown();
|
||
|
activate();
|
||
|
throw;
|
||
|
}
|
||
|
|
||
|
media_type cur_media_type;
|
||
|
reader_ptr->GetCurrentMediaType(actualStreamIndex, cur_media_type._ptr.out()) | comet::raise_exception;
|
||
|
|
||
|
//PrintAttributes(cur_media_type._ptr.in());
|
||
|
|
||
|
auto format = cur_media_type.format();
|
||
|
|
||
|
cv::Mat ret;
|
||
|
|
||
|
DWORD bufCount;
|
||
|
sample->GetBufferCount(&bufCount) | comet::raise_exception;
|
||
|
|
||
|
DWORD bufIndex = bufferIndex >= 0 ? bufferIndex : bufCount - bufferIndex;
|
||
|
|
||
|
if (bufCount > bufIndex)
|
||
|
{
|
||
|
comet::com_ptr<IMFMediaBuffer> buffer;
|
||
|
sample->GetBufferByIndex(bufferIndex, buffer.out()) | comet::raise_exception;
|
||
|
|
||
|
switch (format)
|
||
|
{
|
||
|
case MediaFormat::RGB24:
|
||
|
case MediaFormat::ARGB32:
|
||
|
case MediaFormat::RGB32:
|
||
|
{
|
||
|
comet::com_ptr<IMF2DBuffer> buf2d = try_cast(buffer);
|
||
|
|
||
|
//DWORD length;
|
||
|
//buf2d->GetContiguousLength(&length) | comet::raise_exception;
|
||
|
|
||
|
//ret.create();
|
||
|
|
||
|
//COMET_ASSERT(ret.dataend - ret.datastart == length);
|
||
|
|
||
|
auto resolution = cur_media_type.resolution();
|
||
|
|
||
|
struct buf2d_lock
|
||
|
{
|
||
|
comet::com_ptr<IMF2DBuffer>& buf2d;
|
||
|
|
||
|
buf2d_lock(comet::com_ptr<IMF2DBuffer>& buf2d, BYTE*& scanline0, LONG& pitch) : buf2d(buf2d)
|
||
|
{
|
||
|
buf2d->Lock2D(&scanline0, &pitch) | comet::raise_exception;
|
||
|
}
|
||
|
|
||
|
~buf2d_lock()
|
||
|
{
|
||
|
buf2d->Unlock2D() | comet::raise_exception;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
BYTE *scanline0;
|
||
|
LONG pitch;
|
||
|
buf2d_lock buf_lock_token(buf2d, scanline0, pitch);
|
||
|
if (pitch >= 0)
|
||
|
{
|
||
|
cv::Mat buf2dmat(resolution,
|
||
|
(format == MediaFormat::RGB24) ? CV_8UC3 : CV_8UC4,
|
||
|
scanline0,
|
||
|
pitch);
|
||
|
buf2dmat.copyTo(ret);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cv::Mat buf2dmat(resolution,
|
||
|
(format == MediaFormat::RGB24) ? CV_8UC3 : CV_8UC4,
|
||
|
scanline0 + pitch*(resolution.height-1),
|
||
|
-pitch);
|
||
|
cv::flip(buf2dmat, ret, 0);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case MediaFormat::MJPG:
|
||
|
{
|
||
|
struct buf_lock
|
||
|
{
|
||
|
comet::com_ptr<IMFMediaBuffer>& buffer;
|
||
|
|
||
|
buf_lock(comet::com_ptr<IMFMediaBuffer>& buffer, BYTE*& data, DWORD& maxLength, DWORD& length) : buffer(buffer)
|
||
|
{
|
||
|
buffer->Lock(&data, &maxLength, &length) | comet::raise_exception;
|
||
|
}
|
||
|
|
||
|
~buf_lock()
|
||
|
{
|
||
|
buffer->Unlock() | comet::raise_exception;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
BYTE* data;
|
||
|
DWORD length;
|
||
|
DWORD maxLength;
|
||
|
|
||
|
buf_lock buf_lock_token(buffer, data, maxLength, length);
|
||
|
|
||
|
ret = cv::imdecode(cv::Mat(length, 1, CV_8U, data), cv::IMREAD_COLOR);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
std::stringstream sstream;
|
||
|
sstream << "Unknown media format: " << format;
|
||
|
throw std::runtime_error(sstream.str());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
std::string name() const
|
||
|
{
|
||
|
return get_attr_str(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME);
|
||
|
}
|
||
|
|
||
|
std::string symlink() const
|
||
|
{
|
||
|
return get_attr_str(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK);
|
||
|
}
|
||
|
|
||
|
// TODO change
|
||
|
//explicit operator bool() const
|
||
|
//{
|
||
|
// return !activate_ptr.is_null();
|
||
|
//}
|
||
|
|
||
|
enum Property
|
||
|
{
|
||
|
// CameraControl
|
||
|
Exposure,
|
||
|
Focus,
|
||
|
Zoom,
|
||
|
Pan,
|
||
|
Tilt,
|
||
|
Roll,
|
||
|
Iris,
|
||
|
|
||
|
// VideoProcAmp
|
||
|
Brightness,
|
||
|
Contrast,
|
||
|
Hue,
|
||
|
Saturation,
|
||
|
Sharpness,
|
||
|
Gamma,
|
||
|
ColorEnable,
|
||
|
WhiteBalance,
|
||
|
BacklightCompensation,
|
||
|
Gain
|
||
|
};
|
||
|
|
||
|
bool has(Property property) const;
|
||
|
cam_prop_range get_range(Property property) const;
|
||
|
cam_prop_value get(Property property) const;
|
||
|
void set(Property property, const cam_prop_value& value);
|
||
|
|
||
|
static std::vector<Property> list_properties();
|
||
|
static const char* property_name(Property);
|
||
|
|
||
|
std::vector<media_type> media_types(int streamIndex = 0) const
|
||
|
{
|
||
|
auto pHandler = getMediaTypeHandler(streamIndex);
|
||
|
|
||
|
DWORD cTypes = 0;
|
||
|
pHandler->GetMediaTypeCount(&cTypes) | comet::raise_exception;
|
||
|
|
||
|
std::vector<media_type> ret;
|
||
|
for (DWORD i = 0; i < cTypes; i++)
|
||
|
{
|
||
|
comet::com_ptr<IMFMediaType> pType;
|
||
|
pHandler->GetMediaTypeByIndex(i, pType.out()) | comet::raise_exception;
|
||
|
ret.emplace_back(pType);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
media_type get_media_type(int streamIndex = 0)
|
||
|
{
|
||
|
media_type ret;
|
||
|
getMediaTypeHandler(streamIndex)->GetCurrentMediaType(ret._ptr.out()) | comet::raise_exception;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void set_media_type(const media_type& type, int streamIndex = 0)
|
||
|
{
|
||
|
getMediaTypeHandler(streamIndex)->SetCurrentMediaType(type._ptr.in()) | comet::raise_exception;
|
||
|
if (reader_ptr)
|
||
|
{
|
||
|
reader_ptr->SetCurrentMediaType(streamIndex, nullptr, type._ptr.in()) | comet::raise_exception;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TODO change
|
||
|
//explicit operator bool() {
|
||
|
// return !activate_ptr.is_null();
|
||
|
//}
|
||
|
|
||
|
private:
|
||
|
std::string get_attr_str(REFGUID guid) const
|
||
|
{
|
||
|
comet::task_ptr<WCHAR> pStr;
|
||
|
UINT32 strLen;
|
||
|
activate_ptr->GetAllocatedString(guid, pStr.out(), &strLen) | comet::raise_exception;
|
||
|
return comet::bstr_t(pStr.in(), strLen).s_str();
|
||
|
}
|
||
|
|
||
|
comet::com_ptr<IMFMediaTypeHandler> getMediaTypeHandler(int streamIndex = 0) const
|
||
|
{
|
||
|
comet::com_ptr<IMFPresentationDescriptor> pPD;
|
||
|
source_ptr->CreatePresentationDescriptor(pPD.out()) | comet::raise_exception;
|
||
|
|
||
|
BOOL fSelected;
|
||
|
comet::com_ptr<IMFStreamDescriptor> pSD;
|
||
|
pPD->GetStreamDescriptorByIndex(streamIndex, &fSelected, pSD.out()) | comet::raise_exception;
|
||
|
|
||
|
comet::com_ptr<IMFMediaTypeHandler> pHandler;
|
||
|
pSD->GetMediaTypeHandler(pHandler.out()) | comet::raise_exception;
|
||
|
|
||
|
return pHandler;
|
||
|
}
|
||
|
|
||
|
comet::com_ptr<IMFActivate> activate_ptr;
|
||
|
comet::com_ptr<IMFMediaSource> source_ptr;
|
||
|
comet::com_ptr<IMFSourceReader> reader_ptr;
|
||
|
};
|
||
|
|
||
|
class camera_helper
|
||
|
{
|
||
|
public:
|
||
|
static std::vector<camera> get_all_cameras()
|
||
|
{
|
||
|
comet::com_ptr<IMFAttributes> config;
|
||
|
MFCreateAttributes(config.out(), 1) | comet::raise_exception;
|
||
|
|
||
|
config->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID) | comet::raise_exception;
|
||
|
|
||
|
comet::com_ptr_array<IMFActivate> com_ptr_array;
|
||
|
MFEnumDeviceSources(config.in(), com_ptr_array.out(), com_ptr_array.out_count()) | comet::raise_exception;
|
||
|
|
||
|
std::vector<camera> ret;
|
||
|
for (size_t i = 0; i < com_ptr_array.count(); ++i)
|
||
|
{
|
||
|
ret.emplace_back(com_ptr_array[i]);
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static camera get_camera_by_symlink(const std::string& symlink)
|
||
|
{
|
||
|
// This is how you should do it, but for some reason it gives an activate pointer with no friendly name
|
||
|
|
||
|
// comet::com_ptr<IMFAttributes> config;
|
||
|
// MFCreateAttributes(config.out(), 1) | comet::raise_exception;
|
||
|
//
|
||
|
// config->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID) | comet::raise_exception;
|
||
|
// comet::bstr_t symlink_bstr(symlink);
|
||
|
// config->SetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, symlink_bstr.c_str()) | comet::raise_exception;
|
||
|
//
|
||
|
// comet::com_ptr<IMFActivate> activate_ptr;
|
||
|
// MFCreateDeviceSourceActivate(config.in(), activate_ptr.out()) | comet::raise_exception;
|
||
|
//
|
||
|
// return camera(activate_ptr);
|
||
|
|
||
|
for(auto&& camera : get_all_cameras())
|
||
|
{
|
||
|
if (camera.symlink() == symlink)
|
||
|
return std::move(camera);
|
||
|
}
|
||
|
|
||
|
throw std::runtime_error("No camera with symlink: " + std::string(symlink));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#endif // camera_helper_h__
|