00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "Error.h"
00030 #include "Thread.h"
00031
00032 #include <Argus/Argus.h>
00033 #include <EGLStream/EGLStream.h>
00034 #include <EGLStream/NV/ImageNativeBuffer.h>
00035
00036 #include <NvEglRenderer.h>
00037 #include <NvJpegEncoder.h>
00038
00039 #include <unistd.h>
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <getopt.h>
00043 #include <iostream>
00044 #include <fstream>
00045
00046 using namespace Argus;
00047 using namespace EGLStream;
00048
00049
00050 static const uint32_t CAPTURE_TIME = 1;
00051 static const int DEFAULT_FPS = 30;
00052
00053
00054 static Size PREVIEW_SIZE (640, 480);
00055 static Size CAPTURE_SIZE (1920, 1080);
00056 static bool DO_STAT = false;
00057 static bool VERBOSE_ENABLE = false;
00058
00059 #define JPEG_BUFFER_SIZE (CAPTURE_SIZE.width * CAPTURE_SIZE.height * 3 / 2)
00060
00061
00062 #define PRODUCER_PRINT(...) printf("PRODUCER: " __VA_ARGS__)
00063 #define CONSUMER_PRINT(...) printf("CONSUMER: " __VA_ARGS__)
00064
00065 namespace ArgusSamples
00066 {
00067
00068
00069
00070
00071
00072
00073
00074 class ConsumerThread : public Thread
00075 {
00076 public:
00077 explicit ConsumerThread(OutputStream* stream) :
00078 m_stream(stream),
00079 m_dmabuf(-1)
00080 {
00081 }
00082 virtual ~ConsumerThread();
00083
00084 protected:
00085
00086
00087 virtual bool threadInitialize();
00088 virtual bool threadExecute();
00089 virtual bool threadShutdown();
00090
00091
00092 virtual bool processV4L2Fd(int32_t fd, uint64_t frameNumber) = 0;
00093
00094 OutputStream* m_stream;
00095 UniqueObj<FrameConsumer> m_consumer;
00096 int m_dmabuf;
00097 };
00098
00099 ConsumerThread::~ConsumerThread()
00100 {
00101 if (m_dmabuf != -1)
00102 NvBufferDestroy(m_dmabuf);
00103 }
00104
00105 bool ConsumerThread::threadInitialize()
00106 {
00107
00108 m_consumer = UniqueObj<FrameConsumer>(FrameConsumer::create(m_stream));
00109 if (!m_consumer)
00110 ORIGINATE_ERROR("Failed to create FrameConsumer");
00111
00112 return true;
00113 }
00114
00115 bool ConsumerThread::threadExecute()
00116 {
00117 IStream *iStream = interface_cast<IStream>(m_stream);
00118 IFrameConsumer *iFrameConsumer = interface_cast<IFrameConsumer>(m_consumer);
00119
00120
00121 CONSUMER_PRINT("Waiting until producer is connected...\n");
00122 if (iStream->waitUntilConnected() != STATUS_OK)
00123 ORIGINATE_ERROR("Stream failed to connect.");
00124 CONSUMER_PRINT("Producer has connected; continuing.\n");
00125
00126 while (true)
00127 {
00128
00129 UniqueObj<Frame> frame(iFrameConsumer->acquireFrame());
00130 IFrame *iFrame = interface_cast<IFrame>(frame);
00131 if (!iFrame)
00132 break;
00133
00134
00135 NV::IImageNativeBuffer *iNativeBuffer =
00136 interface_cast<NV::IImageNativeBuffer>(iFrame->getImage());
00137 if (!iNativeBuffer)
00138 ORIGINATE_ERROR("IImageNativeBuffer not supported by Image.");
00139
00140
00141
00142 if (m_dmabuf == -1)
00143 {
00144 m_dmabuf = iNativeBuffer->createNvBuffer(iStream->getResolution(),
00145 NvBufferColorFormat_YUV420,
00146 NvBufferLayout_BlockLinear);
00147 if (m_dmabuf == -1)
00148 CONSUMER_PRINT("\tFailed to create NvBuffer\n");
00149 }
00150 else if (iNativeBuffer->copyToNvBuffer(m_dmabuf) != STATUS_OK)
00151 {
00152 ORIGINATE_ERROR("Failed to copy frame to NvBuffer.");
00153 }
00154
00155
00156 processV4L2Fd(m_dmabuf, iFrame->getNumber());
00157 }
00158
00159 CONSUMER_PRINT("Done.\n");
00160
00161 requestShutdown();
00162
00163 return true;
00164 }
00165
00166 bool ConsumerThread::threadShutdown()
00167 {
00168 return true;
00169 }
00170
00171
00172
00173
00174
00175 class PreviewConsumerThread : public ConsumerThread
00176 {
00177 public:
00178 PreviewConsumerThread(OutputStream *stream, NvEglRenderer *renderer);
00179 ~PreviewConsumerThread();
00180
00181 private:
00182 bool threadInitialize();
00183 bool threadShutdown();
00184 bool processV4L2Fd(int32_t fd, uint64_t frameNumber);
00185
00186 NvEglRenderer *m_renderer;
00187 };
00188
00189 PreviewConsumerThread::PreviewConsumerThread(OutputStream *stream,
00190 NvEglRenderer *renderer) :
00191 ConsumerThread(stream),
00192 m_renderer(renderer)
00193 {
00194 }
00195
00196 PreviewConsumerThread::~PreviewConsumerThread()
00197 {
00198 }
00199
00200 bool PreviewConsumerThread::threadInitialize()
00201 {
00202 if (!ConsumerThread::threadInitialize())
00203 return false;
00204
00205 if (DO_STAT)
00206 m_renderer->enableProfiling();
00207
00208 return true;
00209 }
00210
00211 bool PreviewConsumerThread::threadShutdown()
00212 {
00213 if (DO_STAT)
00214 m_renderer->printProfilingStats();
00215
00216 return ConsumerThread::threadShutdown();
00217 }
00218
00219 bool PreviewConsumerThread::processV4L2Fd(int32_t fd, uint64_t frameNumber)
00220 {
00221 m_renderer->render(fd);
00222 return true;
00223 }
00224
00225
00226
00227
00228
00229 class CaptureConsumerThread : public ConsumerThread
00230 {
00231 public:
00232 CaptureConsumerThread(OutputStream *stream);
00233 ~CaptureConsumerThread();
00234
00235 private:
00236 bool threadInitialize();
00237 bool threadShutdown();
00238 bool processV4L2Fd(int32_t fd, uint64_t frameNumber);
00239
00240 NvJPEGEncoder *m_JpegEncoder;
00241 unsigned char *m_OutputBuffer;
00242 };
00243
00244 CaptureConsumerThread::CaptureConsumerThread(OutputStream *stream) :
00245 ConsumerThread(stream),
00246 m_JpegEncoder(NULL),
00247 m_OutputBuffer(NULL)
00248 {
00249 }
00250
00251 CaptureConsumerThread::~CaptureConsumerThread()
00252 {
00253 if (m_JpegEncoder)
00254 delete m_JpegEncoder;
00255
00256 if (m_OutputBuffer)
00257 delete [] m_OutputBuffer;
00258 }
00259
00260 bool CaptureConsumerThread::threadInitialize()
00261 {
00262 if (!ConsumerThread::threadInitialize())
00263 return false;
00264
00265 m_OutputBuffer = new unsigned char[JPEG_BUFFER_SIZE];
00266 if (!m_OutputBuffer)
00267 return false;
00268
00269 m_JpegEncoder = NvJPEGEncoder::createJPEGEncoder("jpenenc");
00270 if (!m_JpegEncoder)
00271 ORIGINATE_ERROR("Failed to create JPEGEncoder.");
00272
00273 if (DO_STAT)
00274 m_JpegEncoder->enableProfiling();
00275
00276 return true;
00277 }
00278
00279 bool CaptureConsumerThread::threadShutdown()
00280 {
00281 if (DO_STAT)
00282 m_JpegEncoder->printProfilingStats();
00283
00284 return ConsumerThread::threadShutdown();
00285 }
00286
00287 bool CaptureConsumerThread::processV4L2Fd(int32_t fd, uint64_t frameNumber)
00288 {
00289 char filename[FILENAME_MAX];
00290 sprintf(filename, "output%03u.jpg", (unsigned) frameNumber);
00291
00292 std::ofstream *outputFile = new std::ofstream(filename);
00293 if (outputFile)
00294 {
00295 unsigned long size = JPEG_BUFFER_SIZE;
00296 unsigned char *buffer = m_OutputBuffer;
00297 m_JpegEncoder->encodeFromFd(fd, JCS_YCbCr, &buffer, size);
00298 outputFile->write((char *)buffer, size);
00299 delete outputFile;
00300 }
00301
00302 return true;
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312 static bool execute(NvEglRenderer *renderer)
00313 {
00314
00315 UniqueObj<CameraProvider> cameraProvider = UniqueObj<CameraProvider>(CameraProvider::create());
00316 ICameraProvider *iCameraProvider = interface_cast<ICameraProvider>(cameraProvider);
00317 if (!iCameraProvider)
00318 ORIGINATE_ERROR("Failed to create CameraProvider");
00319
00320
00321 std::vector<CameraDevice*> cameraDevices;
00322 iCameraProvider->getCameraDevices(&cameraDevices);
00323 if (cameraDevices.size() == 0)
00324 ORIGINATE_ERROR("No cameras available");
00325
00326
00327 UniqueObj<CaptureSession> captureSession(
00328 iCameraProvider->createCaptureSession(cameraDevices[0]));
00329 ICaptureSession *iCaptureSession = interface_cast<ICaptureSession>(captureSession);
00330 if (!iCaptureSession)
00331 ORIGINATE_ERROR("Failed to get ICaptureSession interface");
00332
00333
00334 PRODUCER_PRINT("Creating output stream\n");
00335 UniqueObj<OutputStreamSettings> streamSettings(iCaptureSession->createOutputStreamSettings());
00336 IOutputStreamSettings *iStreamSettings = interface_cast<IOutputStreamSettings>(streamSettings);
00337 if (!iStreamSettings)
00338 ORIGINATE_ERROR("Failed to get IOutputStreamSettings interface");
00339
00340 iStreamSettings->setPixelFormat(PIXEL_FMT_YCbCr_420_888);
00341 iStreamSettings->setEGLDisplay(renderer->getEGLDisplay());
00342 iStreamSettings->setResolution(PREVIEW_SIZE);
00343 UniqueObj<OutputStream> previewStream(iCaptureSession->createOutputStream(streamSettings.get()));
00344 iStreamSettings->setResolution(CAPTURE_SIZE);
00345 UniqueObj<OutputStream> captureStream(iCaptureSession->createOutputStream(streamSettings.get()));
00346
00347
00348 PRODUCER_PRINT("Launching consumer thread\n");
00349 PreviewConsumerThread previewConsumerThread(previewStream.get(), renderer);
00350 PROPAGATE_ERROR(previewConsumerThread.initialize());
00351 CaptureConsumerThread captureConsumerThread(captureStream.get());
00352 PROPAGATE_ERROR(captureConsumerThread.initialize());
00353
00354
00355
00356 PROPAGATE_ERROR(previewConsumerThread.waitRunning());
00357 PROPAGATE_ERROR(captureConsumerThread.waitRunning());
00358
00359
00360 UniqueObj<Request> request(iCaptureSession->createRequest());
00361 IRequest *iRequest = interface_cast<IRequest>(request);
00362 if (!iRequest)
00363 ORIGINATE_ERROR("Failed to create Request");
00364 iRequest->enableOutputStream(previewStream.get());
00365 iRequest->enableOutputStream(captureStream.get());
00366
00367 ISourceSettings *iSourceSettings = interface_cast<ISourceSettings>(iRequest->getSourceSettings());
00368 if (!iSourceSettings)
00369 ORIGINATE_ERROR("Failed to get ISourceSettings interface");
00370 iSourceSettings->setFrameDurationRange(Range<uint64_t>(1e9/DEFAULT_FPS));
00371
00372
00373 PRODUCER_PRINT("Starting repeat capture requests.\n");
00374 if (iCaptureSession->repeat(request.get()) != STATUS_OK)
00375 ORIGINATE_ERROR("Failed to start repeat capture request");
00376
00377
00378 sleep(CAPTURE_TIME);
00379
00380
00381 iCaptureSession->stopRepeat();
00382 iCaptureSession->waitForIdle();
00383
00384
00385 previewStream.reset();
00386 captureStream.reset();
00387
00388
00389 PROPAGATE_ERROR(previewConsumerThread.shutdown());
00390 PROPAGATE_ERROR(captureConsumerThread.shutdown());
00391
00392 PRODUCER_PRINT("Done -- exiting.\n");
00393
00394 return true;
00395 }
00396
00397 };
00398
00399 static void printHelp()
00400 {
00401 printf("Usage: camera_jpeg_capture [OPTIONS]\n"
00402 "Options:\n"
00403 " --pre-res Preview resolution WxH [Default 640x480]\n"
00404 " --img-res Capture resolution WxH [Default 1920x1080]\n"
00405 " -s Enable profiling\n"
00406 " -v Enable verbose message\n"
00407 " -h Print this help\n");
00408 }
00409
00410 static bool parseCmdline(int argc, char * argv[])
00411 {
00412 enum
00413 {
00414 OPTION_PREVIEW_RESOLUTION = 0x100,
00415 OPTION_CAPTURE_RESOLUTION,
00416 };
00417
00418 static struct option longOptions[] =
00419 {
00420 { "pre-res", 1, NULL, OPTION_PREVIEW_RESOLUTION },
00421 { "img-res", 1, NULL, OPTION_CAPTURE_RESOLUTION },
00422 { 0 },
00423 };
00424
00425 int c, w, h;
00426 while ((c = getopt_long(argc, argv, "s::v::h", longOptions, NULL)) != -1)
00427 {
00428 switch (c)
00429 {
00430 case OPTION_PREVIEW_RESOLUTION:
00431 if (sscanf(optarg, "%dx%d", &w, &h) != 2)
00432 return false;
00433 PREVIEW_SIZE.width = w;
00434 PREVIEW_SIZE.height = h;
00435 break;
00436 case OPTION_CAPTURE_RESOLUTION:
00437 if (sscanf(optarg, "%dx%d", &w, &h) != 2)
00438 return false;
00439 CAPTURE_SIZE.width = w;
00440 CAPTURE_SIZE.height = h;
00441 break;
00442 case 's':
00443 DO_STAT = true;
00444 break;
00445 case 'v':
00446 VERBOSE_ENABLE = true;
00447 break;
00448 default:
00449 return false;
00450 }
00451 }
00452 return true;
00453 }
00454
00455 int main(int argc, char * argv[])
00456 {
00457 if (!parseCmdline(argc, argv))
00458 {
00459 printHelp();
00460 return EXIT_FAILURE;
00461 }
00462
00463 NvEglRenderer *renderer = NvEglRenderer::createEglRenderer("renderer0", PREVIEW_SIZE.width,
00464 PREVIEW_SIZE.height, 0, 0);
00465 if (!renderer)
00466 ORIGINATE_ERROR("Failed to create EGLRenderer.");
00467
00468 if (!ArgusSamples::execute(renderer))
00469 return EXIT_FAILURE;
00470
00471 delete renderer;
00472
00473 return EXIT_SUCCESS;
00474 }