#include "esp_camera.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <FS.h>
#include "SD_MMC.h"
// Define your WiFi credentials
const char* ssid = "MYSSID";
const char* password = "MYPASS";
// Google Drive upload parameters
const char* gdrive_upload_url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable";
const char* parentFolderId = "MYFOLDERID";
String metadata = "{"parents":["" + String(parentFolderId) + ""]}";
uint8_t *videoBuffer = NULL;
size_t bufferSize = 0;
size_t maxBufferSize = 0;
// Function to connect to WiFi
void connectToWiFi() {
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting...");
}
Serial.println("Connected to WiFi");
}
void captureAndWriteVideoToSD(uint16_t videoDurationInSeconds) {
Serial.println("Starting video capture...");
File videoFile = SD_MMC.open("/video.mp4", FILE_WRITE);
if (!videoFile) {
Serial.println("Failed to open/create file for writing");
return;
}
uint32_t startTime = millis();
uint32_t endTime = startTime + (videoDurationInSeconds * 1000);
while (millis() < endTime) {
camera_fb_t *fb = esp_camera_fb_get();
if (fb) {
// Write frame data to the file
if (videoFile.write(fb->buf, fb->len) != fb->len) {
Serial.println("Write error occurred");
esp_camera_fb_return(fb);
break;
}
esp_camera_fb_return(fb);
} else {
Serial.println("Failed to capture frame");
break;
}
}
// Close the file
if (videoFile) {
videoFile.close();
Serial.println("Video capture complete.");
} else {
Serial.println("Error: File not open.");
}
}
void uploadVideoToDrive() {
Serial.println("Uploading video to Google Drive...");
// Open the file
File videoFile = SD_MMC.open("/video.mp4", FILE_READ);
if (!videoFile) {
Serial.println("Error opening video file!");
return;
}
const size_t chunkSize = 1024; // Define the chunk size
uint8_t chunk[chunkSize]; // Declare the chunk buffer
size_t totalPayloadSize = 0; // Initialize total payload size
// Calculate total payload size
while (videoFile.available()) {
size_t bytesRead = videoFile.readBytes((char*)chunk, chunkSize);
totalPayloadSize += bytesRead;
}
videoFile.seek(0); // Reset file pointer to the beginning
// Make the initial POST request to get the upload session URL
HTTPClient http;
http.begin("https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable");
http.addHeader("Authorization", "Bearer " + gdrive_token);
http.addHeader("Content-Type", "video/mp4");
http.addHeader("Content-Length", "0"); // Set initial Content-Length to 0
int httpResponseCode = http.POST(""); // Send the initial POST request
Serial.println("Initial POST request response:");
Serial.println(http.getString()); // Print response body
if (httpResponseCode != HTTP_CODE_OK) {
Serial.print("Error initiating upload. HTTP response code: ");
Serial.println(httpResponseCode);
http.end();
videoFile.close();
return;
}
String location = http.header("Location"); // Get the upload session URL
http.end(); // Close the connection
Serial.print("Upload session URL: ");
Serial.println(location);
// Check if location is empty or null
if (location.isEmpty()) {
Serial.println("Error: Upload session URL not found.");
videoFile.close();
return;
}
// Send the file contents in chunks with the correct range headers
size_t totalBytesSent = 0; // Initialize totalBytesSent
while (videoFile.available()) {
size_t bytesRead = videoFile.readBytes((char*)chunk, chunkSize);
http.begin(location); // Use the upload session URL
http.addHeader("Authorization", "Bearer " + gdrive_token);
http.addHeader("Content-Range", "bytes " + String(totalBytesSent) + "-" + String(totalBytesSent + bytesRead - 1) + "/" + String(totalPayloadSize));
httpResponseCode = http.sendRequest("PUT", chunk, bytesRead);
if (httpResponseCode != HTTP_CODE_OK && httpResponseCode != HTTP_CODE_CREATED) {
Serial.print("Error uploading chunk. HTTP response code: ");
Serial.println(httpResponseCode);
Serial.println(http.getString());
http.end();
videoFile.close();
return;
}
totalBytesSent += bytesRead;
Serial.print("Uploaded ");
Serial.print(totalBytesSent);
Serial.print(" bytes out of ");
Serial.println(totalPayloadSize);
http.end();
delay(10); // Small delay between requests
}
Serial.println("Upload complete.");
// Close the file
videoFile.close();
}
void setup() {
Serial.begin(115200);
// Initialize camera
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = 5; // Y2
config.pin_d1 = 18; // Y3
config.pin_d2 = 19; // Y4
config.pin_d3 = 21; // Y5
config.pin_d4 = 36; // Y6
config.pin_d5 = 39; // Y7
config.pin_d6 = 34; // Y8
config.pin_d7 = 35; // Y9
config.pin_xclk = 0; // XCLK_GPIO_NUM
config.pin_pclk = 22; // PCLK_GPIO_NUM
config.pin_vsync = 25; // VSYNC_GPIO_NUM
config.pin_href = 23; // HREF_GPIO_NUM
config.pin_sscb_sda = 26; // SIOD_GPIO_NUM
config.pin_sscb_scl = 27; // SIOC_GPIO_NUM
config.pin_pwdn = 32; // PWDN_GPIO_NUM
config.pin_reset = -1; // RESET_GPIO_NUM, -1 if not used
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
// Init with high specs to pre-allocate larger buffers
if (psramFound()) {
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// Initialize camera
esp_err_t err = esp_camera_init(&config;);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
while (!SD_MMC.begin()) {}
connectToWiFi();
captureAndWriteVideoToSD(10);
uploadVideoToDrive();
}
void loop() {
// captureAndWriteVideoToSD(10);
// // Check if video capture was successful
// if (bufferSize > 0) {
// uploadVideoToDrive(videoBuffer, bufferSize, gdrive_upload_url, gdrive_token);
// // Free the memory allocated for videoBuffer
// videoBuffer = NULL;
// bufferSize = 0;
// maxBufferSize = 0;
// }
delay(1000);
}