Skip to content

Commit

Permalink
Add litecam
Browse files Browse the repository at this point in the history
  • Loading branch information
yushulx committed Dec 19, 2024
1 parent e776308 commit dddc501
Show file tree
Hide file tree
Showing 17 changed files with 3,695 additions and 0 deletions.
67 changes: 67 additions & 0 deletions litecam/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
cmake_minimum_required(VERSION 3.10)

# Project name and version
project(CameraProject VERSION 1.0 LANGUAGES CXX)

# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# Define include directories
set(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include)

# Define source files for the Camera library
if (WIN32)
set(LIBRARY_SOURCES
src/CameraWindows.cpp
src/CameraPreviewWindows.cpp
)
elseif (UNIX AND NOT APPLE)
set(LIBRARY_SOURCES
src/CameraLinux.cpp
src/CameraPreviewLinux.cpp
)
elseif (APPLE)
set(LIBRARY_SOURCES
src/CameraMacOS.mm
src/CameraPreviewMacOS.mm
)
endif()

# Define source files for the executable
set(EXECUTABLE_SOURCES
src/main.cpp
)

# Add the Camera shared library
add_library(Camera SHARED ${LIBRARY_SOURCES})

# Set include directories for the Camera library
target_include_directories(Camera PUBLIC ${INCLUDE_DIR})

# Define the CAMERA_EXPORTS macro for the shared library
target_compile_definitions(Camera PRIVATE CAMERA_EXPORTS)

# Platform-specific dependencies for the Camera library
if (UNIX AND NOT APPLE)
find_package(X11 REQUIRED)
if (X11_FOUND)
target_include_directories(Camera PUBLIC ${X11_INCLUDE_DIR})
target_link_libraries(Camera PRIVATE ${X11_LIBRARIES} pthread)
endif()
elseif (APPLE)
find_library(COCOA_LIBRARY Cocoa)
find_library(AVFOUNDATION_LIBRARY AVFoundation)
target_link_libraries(Camera PRIVATE ${AVFOUNDATION_LIBRARY})
elseif (WIN32)
target_link_libraries(Camera PRIVATE ole32 uuid mfplat mf mfreadwrite mfuuid)
endif()

# Add the camera_capture executable
add_executable(camera_capture ${EXECUTABLE_SOURCES})

# Link the Camera library to the executable
target_link_libraries(camera_capture PRIVATE Camera)

# Include the shared library's headers in the executable
target_include_directories(camera_capture PRIVATE ${INCLUDE_DIR})
105 changes: 105 additions & 0 deletions litecam/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# LiteCam

LiteCam is a lightweight, cross-platform library for capturing RGB frames from cameras and displaying them. Designed with simplicity and ease of integration in mind, LiteCam supports Windows and Linux platforms.

## Features

- Capture RGB frames from video devices.
- Display live frames in a window.
- Draw contours and text directly on the displayed frames.
- Simple API for quick integration.

## Supported Platforms

- **Windows**: Uses Media Foundation for video capture.
- **Linux**: Uses Video4Linux (V4L2) and X11 for video capture and rendering.

## Requirements

- CMake

### Windows
- Visual Studio 2019 or later
- Media Foundation (included with Windows)

### Linux
- GCC or Clang
- Development libraries for:
- Video4Linux2 (libv4l2)
- X11 (libX11)

## Installation

1. Clone the repository:
```bash
git clone https://github.com/yushulx/cmake-cpp-barcode-qrcode-mrz.git
cd litecam
```

2. Build the library:

```bash
mkdir build && cd build
cmake ..
cmake --build .
```

3. Link the library to your project.

## Usage

### Basic Example

```cpp
#include "Camera.h"
#include "CameraPreview.h"
int main()
{
Camera camera;
if (!camera.Open(0)) {
std::cerr << "Failed to open camera." << std::endl;
return -1;
}
CameraWindow window(640, 480, "LiteCam Preview");
if (!window.Create()) {
std::cerr << "Failed to create window." << std::endl;
return -1;
}
window.Show();
while (window.WaitKey('q')) {
FrameData frame = camera.CaptureFrame();
if (frame.rgbData) {
window.ShowFrame(frame.rgbData, frame.width, frame.height);
camera.ReleaseFrame(frame);
}
}
camera.Release();
return 0;
}
```
### API Overview
#### Camera
- **`bool Open(int cameraIndex)`**: Opens the camera with the specified index.
- **`FrameData CaptureFrame()`**: Captures a single RGB frame.
- **`void ReleaseFrame(FrameData &frame)`**: Releases the memory allocated for a frame.
- **`void Release()`**: Closes the camera and releases resources.
- **`void saveFrameAsJPEG(const char *filename, const unsigned char *rgbData, int width, int height)`**: Saves the frame as a JPEG image.
#### CameraWindow
- **`bool Create()`**: Initializes and creates a window.
- **`void Show()`**: Displays the window.
- **`bool WaitKey(char key)`**: Waits for user input; returns `false` if the specified key is pressed or the window is closed.
- **`void ShowFrame(const unsigned char *rgbData, int width, int height)`**: Displays an RGB frame.
- **`void DrawContour(const std::vector<std::pair<int, int>> &points)`**: Draws contours on the frame.
- **`void DrawText(const std::string &text, int x, int y, int fontSize, const Color &color)`**: Draws text on the frame.
199 changes: 199 additions & 0 deletions litecam/dist/include/Camera.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
#ifndef CAMERA_H
#define CAMERA_H

#include <vector>
#include <string>
#include <iostream>
#include <cstdint>

// Export macro for shared library
#ifdef _WIN32
#ifdef CAMERA_EXPORTS
#define CAMERA_API __declspec(dllexport)
#else
#define CAMERA_API __declspec(dllimport)
#endif
#elif defined(__linux__) || defined(__APPLE__)
#define CAMERA_API __attribute__((visibility("default")))
#else
#define CAMERA_API
#endif

// Platform-specific includes
#ifdef _WIN32
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfobjects.h>
#include <mfreadwrite.h>
#include <wrl/client.h>
#include <dshow.h>

#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mf.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "mfuuid.lib")

using Microsoft::WRL::ComPtr;
#elif __linux__
#include <linux/videodev2.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

struct Buffer
{
void *start;
size_t length;
};

#elif __APPLE__
#include <AVFoundation/AVFoundation.h>
#endif

///////////////////////////////////////////////////////////////////////////////
// Save a frame as a JPEG image using the STB library
// https://github.com/nothings/stb/blob/master/stb_image_write.h
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
void saveFrameAsJPEG(const unsigned char *data, int width, int height, const std::string &filename)
{
// Simple image saving using STB library or another JPEG encoding method
if (stbi_write_jpg(filename.c_str(), width, height, 3, data, 90))
{
std::cout << "Saved frame to " << filename << std::endl;
}
else
{
std::cerr << "Error saving frame as JPEG." << std::endl;
}
}
///////////////////////////////////////////////////////////////////////////////

unsigned char clamp(double value, double min, double max)
{
if (value < min)
return static_cast<unsigned char>(min);
if (value > max)
return static_cast<unsigned char>(max);
return static_cast<unsigned char>(value);
}

void ConvertYUY2ToRGB(const unsigned char *yuy2Data, unsigned char *rgbData, int width, int height)
{
int rgbIndex = 0;
for (int i = 0; i < width * height * 2; i += 4)
{
// Extract YUV values
unsigned char y1 = yuy2Data[i];
unsigned char u = yuy2Data[i + 1];
unsigned char y2 = yuy2Data[i + 2];
unsigned char v = yuy2Data[i + 3];

#ifdef _WIN32
// Convert first pixel (Y1, U, V) to RGB
rgbData[rgbIndex++] = clamp(y1 + 1.772 * (u - 128), 0.0, 255.0);
rgbData[rgbIndex++] = clamp(y1 - 0.344136 * (u - 128) - 0.714136 * (v - 128), 0.0, 255.0);
rgbData[rgbIndex++] = clamp(y1 + 1.402 * (v - 128), 0.0, 255.0);

// Convert second pixel (Y2, U, V) to RGB
rgbData[rgbIndex++] = clamp(y2 + 1.772 * (u - 128), 0.0, 255.0);
rgbData[rgbIndex++] = clamp(y2 - 0.344136 * (u - 128) - 0.714136 * (v - 128), 0.0, 255.0);
rgbData[rgbIndex++] = clamp(y2 + 1.402 * (v - 128), 0.0, 255.0);
#else
// Convert first pixel (Y1, U, V) to RGB
rgbData[rgbIndex++] = clamp(y1 + 1.402 * (v - 128), 0.0, 255.0);
rgbData[rgbIndex++] = clamp(y1 - 0.344136 * (u - 128) - 0.714136 * (v - 128), 0.0, 255.0);
rgbData[rgbIndex++] = clamp(y1 + 1.772 * (u - 128), 0.0, 255.0);

// Convert second pixel (Y2, U, V) to RGB
rgbData[rgbIndex++] = clamp(y2 + 1.402 * (v - 128), 0.0, 255.0);
rgbData[rgbIndex++] = clamp(y2 - 0.344136 * (u - 128) - 0.714136 * (v - 128), 0.0, 255.0);
rgbData[rgbIndex++] = clamp(y2 + 1.772 * (u - 128), 0.0, 255.0);
#endif
}
}

// Struct definitions
struct CAMERA_API FrameData
{
unsigned char *rgbData; // RGB pixel data
int width; // Frame width
int height; // Frame height
size_t size;
};

struct CAMERA_API MediaTypeInfo
{
uint32_t width;
uint32_t height;
#ifdef _WIN32
wchar_t subtypeName[512]; // Wide characters for Windows
#else
char subtypeName[512]; // Narrow characters for Linux/macOS
#endif
};

struct CAMERA_API CaptureDeviceInfo
{

#ifdef _WIN32
wchar_t friendlyName[512];
#else
char friendlyName[512]; // Narrow characters for Linux/macOS
#endif
};

// Exported functions
CAMERA_API std::vector<CaptureDeviceInfo> ListCaptureDevices();

// Camera class
class CAMERA_API Camera
{
public:
#ifdef _WIN32
Camera();
~Camera();
#elif __linux__
Camera() : fd(-1), frameWidth(640), frameHeight(480), buffers(nullptr), bufferCount(0) {}
~Camera() { Release(); }
#endif

bool Open(int cameraIndex);
void Release();

std::vector<MediaTypeInfo> ListSupportedMediaTypes();
FrameData CaptureFrame();
void ReleaseFrame(FrameData &frame);
bool SetResolution(int width, int height);

uint32_t frameWidth;
uint32_t frameHeight;

private:
#ifdef _WIN32
ComPtr<IMFSourceReader> reader;

bool initialized;
void InitializeMediaFoundation();
void ShutdownMediaFoundation();
#endif

#ifdef __linux__
int fd;
Buffer *buffers;
unsigned int bufferCount;

bool InitDevice();
void UninitDevice();
bool StartCapture();
void StopCapture();
#endif

#ifdef __APPLE__
void *captureSession; // AVFoundation session object
#endif
};

#endif // CAMERA_H
Loading

0 comments on commit dddc501

Please sign in to comment.