158 lines
5.2 KiB
C++
158 lines
5.2 KiB
C++
/*
|
|
*******************************************************************************
|
|
* INCLUDE
|
|
*******************************************************************************
|
|
*/
|
|
#include "Input.h"
|
|
#include "Capture.h"
|
|
#include "InputFormat.h"
|
|
#include "../core/System.h"
|
|
#include "Logger.h"
|
|
|
|
namespace Video
|
|
{
|
|
namespace V4L2
|
|
{
|
|
/*
|
|
*******************************************************************************
|
|
* CLASS DEFINE
|
|
*******************************************************************************
|
|
*/
|
|
Input::Input(const std::string& name): VideoComponent(name), _task(name)
|
|
{
|
|
}
|
|
|
|
Input::~Input()
|
|
{
|
|
}
|
|
|
|
void Input::start()
|
|
{
|
|
_task.run(
|
|
[this](std::atomic<bool>& isCancelled) -> void
|
|
{
|
|
const std::string path = getPath();
|
|
|
|
setCodecID(Core::CodecID::MJPEG);
|
|
setSignalLost(true);
|
|
|
|
while (!isCancelled)
|
|
{
|
|
Poco::SharedPtr<Capture> pCapture;
|
|
InputFormat::Collection formats;
|
|
try
|
|
{
|
|
InputFormat::enumerate(path, formats);
|
|
|
|
if (formats.empty())
|
|
{
|
|
Poco::Thread::sleep(2000);
|
|
continue;
|
|
}
|
|
|
|
for (auto& c : formats)
|
|
{
|
|
if (V4L2_PIX_FMT_MJPEG == c.pixelFormat && !c.resolutions.empty())
|
|
{
|
|
auto p = c.resolutions.begin();
|
|
uint64_t maxProduct = 0;
|
|
for (auto it = c.resolutions.begin(); it != c.resolutions.end(); ++it)
|
|
{
|
|
uint32_t fps = it->width * it->height > 3686400 ? 30 : 60;
|
|
if (it->width <= 2560 && it->height <= 1440 && it->fps <= fps)
|
|
{
|
|
uint64_t product = static_cast<uint64_t>(it->width) * it->height * it->fps;
|
|
if (product > maxProduct)
|
|
{
|
|
logger().debug("%s: ", name());
|
|
maxProduct = product;
|
|
p = it;
|
|
}
|
|
}
|
|
}
|
|
|
|
DeviceParameters param(path.c_str(), c.pixelFormat, p->width, p->height, p->fps);
|
|
pCapture = Capture::create(param);
|
|
if (pCapture.isNull())
|
|
continue;
|
|
|
|
logger().information("%s: Camera [%s] found, %s, %ux%u@%u", name(), pCapture->getName(),
|
|
c.description, p->width, p->height, p->fps);
|
|
|
|
setWidth(p->width);
|
|
setHeight(p->height);
|
|
setFrameRate(p->fps);
|
|
setSignalLost(false);
|
|
serialCodeManager().increment();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
Poco::Thread::sleep(2000);
|
|
continue;
|
|
}
|
|
|
|
uint8_t* pBuffer = nullptr;
|
|
;
|
|
while (!isCancelled)
|
|
{
|
|
try
|
|
{
|
|
struct timeval tv = {1, 0};
|
|
if (!pCapture->isReadable(&tv))
|
|
break;
|
|
|
|
int len = pCapture->getBufferSize();
|
|
pBuffer = new uint8_t[len];
|
|
int rsize = pCapture->read((char*)pBuffer, len);
|
|
if (rsize < 0)
|
|
{
|
|
logger().error("%s: Failed to read frame!", pCapture->getName());
|
|
delete pBuffer;
|
|
pBuffer = nullptr;
|
|
break;
|
|
}
|
|
|
|
int64_t ts = Core::System::timestamp();
|
|
Core::Packet::Ptr pPacket = new Core::Packet(
|
|
serialCodeManager().code(), Core::Packet::FLAG_IS_VIDEO, pBuffer, rsize, ts, ts);
|
|
|
|
pBuffer = nullptr;
|
|
postToNextComponents(sharedFromThis(), pPacket, Core::MediaType::VIDEO);
|
|
}
|
|
catch (...)
|
|
{
|
|
if (pBuffer)
|
|
{
|
|
delete pBuffer;
|
|
pBuffer = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
setSignalLost(true);
|
|
logger().warning("%s: Camera [%s] lost!", name(), pCapture->getName());
|
|
}
|
|
});
|
|
}
|
|
|
|
void Input::stop()
|
|
{
|
|
_task.cancel();
|
|
}
|
|
|
|
void Input::onConfigChanged(ParameterNames& names)
|
|
{
|
|
if (!started())
|
|
return;
|
|
|
|
if (names.exists(_Path))
|
|
{
|
|
stop();
|
|
start();
|
|
}
|
|
}
|
|
}
|
|
}
|