Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
568 changes: 560 additions & 8 deletions src/esp32cam.cpp

Large diffs are not rendered by default.

243 changes: 227 additions & 16 deletions src/esp32cam.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@

namespace esp32cam {

struct StreamMjpegConfig
{
/// minimum interval between frame captures.
int minInterval = 0;
/// maximum number of frames before disconnecting.
int maxFrames = -1;
/// time limit of writing one frame in millis.
int frameTimeout = 10000;
/// Abort flags
bool bAbort = false;

};

class CameraClass
{
public:
Expand All @@ -29,33 +42,231 @@ class CameraClass
bool
changeResolution(const Resolution& resolution, int sleepFor = 500);

/** \brief Change camera resolution.
* \pre Change Camera Frequence Clock
* \param iMhz new Frequence, must be in MHZ
*/
bool
changeFrequence(int iMhz);

/** \brief Change Sensor Contrast level
* must be -2 to +2, default 0
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't proper Doxygen syntax.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with commit -a -amend, please verify if it is correct now - have not used doxygen yet

*/
bool
changeContrast(int ilevel);

/** \brief Change Brightness level
* \param ilevel must be -2 to +2, default 0
*/
bool
changeBrightness(int ilevel);

/** \brief Change Saturation level
* \param ilevel must be -2 to +2, default 0
*/
bool
changeSaturation(int ilevel);

/** \brief Change SpecialEffect
* \param ilevel must be > 0 && <= NUM_SPECIAL_EFFECTS, default 0
* \ 1 = no effect
* \ 2 = negative
* \ 3 = black and white
* \ 4 = reddish
* \ 5 = greenish
* \ 6 = blue
* \ 7 = retro
*/
bool
changeSpecialEffect(int ilevel);

/** \brief Change WbMode
* \param ilevel must be > 0 && <= NUM_WB_MODES, default 0
* \ 0 = default
* \ 1 = sunny
* \ 2 = cloudy
* \ 3 = office
* \ 4 = home
*/
bool
changeWbMode(int ilevel);

/** \brief Change AE Levels
* \param ilevel must be -2 to +2, default 0
*/
bool
changeAeLevels(int ilevel);

/** \brief Enable/Disable AEC (Auto Exposure Control)
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changAutoExposurecontrol(int iEnable);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some drive-by comments while I was looking at OV2640 libraries...

There are a bunch of methods named chang.... I think you mean change...


/** \brief Change AGC Gain
* \param ilevel must be >= 0 and <= 30, default 30
*/
bool
changAgcGain(int ilevel);

/** \brief Change Gainceiling
* \param iGainCeiling must be between GAINCEILING_2X and GAINCEILING_128X
*/
bool
changGainceilingSensor(int iGainCeiling);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't that be changeGainCeilingSensor to match the iGainCeiling parameter?

Can GAINCEILING_nX be any integer between 2 and 128, in which case shouldn't it just be an integer? If it's an enum, change the parameter description to reference the enum?

And maybe drop Sensor entirely? Having sensor in the name is either redundant because it's implicit that you're manipulating some of the sensor settings, or it's wrong because it suggests that there is some kind of a sensor that measures something about the gain, like there might be temperature sensor.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible that some settings did not work at all.
I wanted to have as many sensor options available for testing as possible,


/** \brief Enable/Disable Awb GainControl
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changeAwbGainControl(int iEnable);

/** \brief Enable/Disable Gaincontrol
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changeGaincontrol(int iEnable);

/** \brief Enable/Disable Testing Colorbar
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changeColorbar(int iEnable);

/** \brief Enable/Disable Whitebalance
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changeWhitebalance(int iEnable);

/** \brief Change JPEG Quality
* \param iEnable iQuality must be within 0 and 63
*/
bool changeQuality(int iQuality);

/** \brief Change AEC Value
* \param iEnable iValue must be 0 to 1200, default 0
*/
bool
changeAecValue(int iValue);

/** \brief Enable/Disable Auto/Manual Exposure control
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changAec2(int iEnable);

/** \brief Enable/Disable horizontal mirror
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changHMirror(int iEnable);

/** \brief Enable/Disable vertical mirror
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changVFlip(int iEnable);

/** \brief Enable/Disable black pixel correction
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changBPC(int iEnable);

/** \brief Enable/Disable white pixel correction
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changWPC(int iEnable);

/** \brief Enable/Disable Denoise Control
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changDenoise(int iEnable);

/** \brief Enable/Disable Lenc Correction
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is Lenc correction?

Copy link
Author

@alorbach alorbach Jun 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some questions will be answered here:
https://github.com/espressif/esp32-camera/blob/e689c3b082985ee7b90198be32d330ce51ac5367/sensors/ov2640.c

And some you need to research in ov2640 sensor doc (Or whatever sensor you have)
https://www.uctronics.com/download/cam_module/OV2640DS.pdf

I remember the lenc and rawgma had big impact on how low light is being handeled.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changLenc(int iEnable);

/** \brief Enable/Disable RAW Gamma
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changRawGMA(int iEnable);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changeRawGamma?


/** \brief Enable/Disable DCW
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is DCW?

* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changDcw(int iEnable);

/** \brief Enable/Disable COM7_ZOOM_EN
* \param iEnable must be 0(disable) or 1 (enable)
*/
bool
changeZoom(int iEnable);

/** \brief Get detectedBandMode Light Frequence Detection (Antiflicker)
* return
* \ 0 = 60hz
* \ 1 = 50hz
*/
int
getBandMode(void);

/** \brief Change BandMode Light Frequewnce Detection (Antiflicker)
* \param ilevel must be > 0 && <= NUM_SPECIAL_EFFECTS, default 0
* \ 0 = AUTO
* \ 1 = MANUAL 50hz
* \ 2 = MANUAL 60hz
*/
bool
changeBandMode(int ilevel);

/** \brief TODO
* \param iMul
* \param iPclk
* \param iPre
* \ is set to 50hz or 60hz.
*/
bool
changePll(int iMul, int iPre, int iPclk);

/** \brief Set Double Clock Mode for ov2640
*/
bool
setDoubleClk();

/** \brief Capture a frame of picture.
*/
std::unique_ptr<Frame>
capture();

struct StreamMjpegConfig
{
/// minimum interval between frame captures.
int minInterval = 0;
/// maximum number of frames before disconnecting.
int maxFrames = -1;
/// time limit of writing one frame in millis.
int frameTimeout = 10000;
};

/** \brief Stream Motion JPEG.
* \pre The camera has been initialized to JPEG mode.
* \return number of frames streamed.
*/
int
streamMjpeg(Client& client, const StreamMjpegConfig& cfg);

int
streamMjpeg(Client& client)
{
int streamMjpeg(Client& client, const StreamMjpegConfig& cfg);
int streamMjpeg(Client& client) {
return streamMjpeg(client, StreamMjpegConfig());
}

/** \brief Stream Motion JPEG.
* \Function cloned for AsyncClient
* \pre The camera has been initialized to JPEG mode.
* \return number of frames streamed.
*/
int streamMjpeg(AsyncClient& client, const StreamMjpegConfig* cfg);

/** \brief Return value for esp API calls
* \Store last api return value here useful for error handling!
*/
esp_err_t lastEspErr;

};

extern CameraClass Camera;
Expand Down
15 changes: 15 additions & 0 deletions src/internal/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ Config::setRgb()
return *this;
}

Config&
Config::setRgb888()
{
m_cfg->pixel_format = PIXFORMAT_RGB888;
return *this;
}


Config&
Config::setYuv()
{
Expand All @@ -100,4 +108,11 @@ Config::setJpeg(int quality)
return *this;
}

Config&
Config::setFreqHz(int freq)
{
m_cfg->xclk_freq_hz = freq;
return *this;
}

} // namespace esp32cam
11 changes: 11 additions & 0 deletions src/internal/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ class Config
*/
Config& setRgb();

/** \brief Change pixel format to RGB888.
*/
Config&
setRgb888();

/** \brief Change pixel format to YUV422.
*/
Config& setYuv();
Expand All @@ -49,6 +54,12 @@ class Config
*/
Config& setJpeg(int quality);

/** \brief Change xclk freq hz
* \param Change xclk freq hz default 20000000
*/
Config&
setFreqHz(int freq);

private:
class CameraConfigT; ///< camera_config_t
CameraConfigT* m_cfg;
Expand Down
45 changes: 35 additions & 10 deletions src/internal/frame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,38 +38,63 @@ Frame::releaseFb()
}
}

bool
Frame::writeTo(Print& os, int timeout)
{
bool
Frame::writeTo(Print& os, int timeout) {
return writeToImpl(os, timeout, nullptr);
}

bool
Frame::writeTo(Client& os, int timeout)
{
bool
Frame::writeTo(Client& os, int timeout) {
return writeToImpl(os, timeout, &os);
}

bool
Frame::writeToImpl(Print& os, int timeout, Client* client)
{
bool
Frame::writeTo(AsyncClient& os, int timeout) {
return writeToImpl(timeout, &os);
}

bool
Frame::writeToImpl(Print& os, int timeout, Client* client) {
auto startTime = millis();
for (size_t i = 0; i < m_size; i += os.write(&m_data[i], m_size - i)) {
if (millis() - startTime > static_cast<unsigned long>(timeout) ||
(client != nullptr && !client->connected())) {
return false;
}
yield();
}
return true;
}

bool
Frame::writeToImpl(int timeout, AsyncClient* client) {
auto startTime = millis();
for (size_t i = 0; i < m_size; i += client->write((const char*) &m_data[i], m_size - i)) {
if (millis() - startTime > static_cast<unsigned long>(timeout) ||
(client != nullptr && !client->connected())) {
return false;
}
// Force send now
client->send();
taskYIELD();
}
return true;
}


bool
Frame::isJpeg() const
{
return m_pixFormat == PIXFORMAT_JPEG;
}

void
Frame::setData(uint8_t* newdata, size_t newsize, bool bIsBmp) {
releaseFb();
m_data = newdata;
m_size = newsize;
m_pixFormat = (int)(bIsBmp ? PIXFORMAT_BMP : PIXFORMAT_JPEG);
}

bool
Frame::toJpeg(int quality)
{
Expand Down
Loading