#include"acidcam_window.hpp" #include"ipc_client.hpp" #ifdef SYPHON_SERVER #include "syphon.h" #endif #include<cstdlib> #include"stereo.h" #ifdef MIDI_ENABLED #include"midi.hpp" midi::MIDI_Config config; #endif acidcam::AcidCam_Window main_window; std::unordered_map<std::string, int> draw_strings_map; void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) { main_window.keypress(key, scancode, action, mode); } void window_size_callback(GLFWwindow* win, int newWidth, int newHeight) { main_window.resize(newWidth, newHeight); } void character_callback(GLFWwindow* window, unsigned int codepoint) { main_window.typeKey(codepoint); } //ffmpeg -f avfoundation -r 30 -video_device_index 3 -i "default" test.mpg std::string outstr_arr[] = { "Written by Jared Bruni", "http://lostsidedead.com", "Arguments:", " -A autofilter file", " -X codec", " -o output filename", " -S filter start index", " -H shader start index", " -Z Starting ilter by Name", " -C set color map", " -T set material texture filename", " -s image output format", " -N play list slideshow timeout", " -k shortcut-key file", " -L playlist of filters", " -b restore black", " -g output debug strings", " -u fps", " -n print filter name", " -e snapshot prefix", " -p shader path", " -M monitor index", " -f fullscreen (resize)", " -F fullscreen (windowed mode)", " -d capture device", " -i input_video.mp4", " -R loop input video", " -x Stereo Mode", " -r resolution 1920x1080", " -c Camera resolution 1280x720", " -G Screen Capture Mode", " -Y Enable Syphon Server", " -U Screen Capture Position X,Y", " -P Redirect Standard Output to Socket", " -W custom filter path", " -B enable playback filter mode", " -q shuffle playlist", " -w beats per minute for shuffle", " -l list filters", " -t list filters no info", " -l list search", " -v version", " -4 enable ffmpeg x264 support", " -5 enable ffmpeg x265 support", " -E encode codec (h264_nvenc, hevc_nvenc, av1_nvenc, h264_videotoolbox, hevc_videotoolbox, h264_qsv, hevc_qsv, av1_qsv, h264_amf, hevc_amf)", " -m crf for x265 for video mode", " -1 for ffmpeg path", " -7 for video start offset in seconds.", " -3 Plugin Path", " -9 Number of threads", " -8 Set Max Allocated Frames", " -I Set Number of Channels for Input Device", " -V Reactivity Sensitivity", " -y Disable Audio", " -O for file mode do not copy audio frrom original file", " --mux outputted_file source_file [ Mux audio (copy audio) ]", " --list display capture device list", " --rotate src output", " ", "Enviorment Variables:", " SHADER_PATH path to shaders", " AC_CUSTOM_PATH", " FFMPEG_PATH", #ifndef _WIN32 " AC_PLUGIN_PATH", #endif #ifdef MIDI_ENABLED " AC_MIDI", #endif " ", "Controls:", " ", " L - enable disable playlist", " N - set index to the end", " P - index reset to zero", " K - jump forward index by 25", " J - jump backwar index by 25", " Z - take screenshot", " H - Shuffle Playlist", " [SHIFT]+H - AutoFilter Shuffle Lock On/Off", " M - Enable/Disable Playlist Slideside random timeout", " F - process keyboard input for index", " S - process keyboard input for shader", " C - clear keyboard input", " [+] - increase blend percentage", " [-] = decrease blend percentage", " [SPACE] - Acid Cam filters enabled/disabled", " [SHIFT]+[SPACE] - Toggle Autofilter on and off", " [LEFT] - Filter index move left", " [RIGHT] - filter index move right", " [SHIFT]+1 - Stereo Mode toggle On/Off", " [SHIFT]+2 - Toggle Time Control On / Off ", " [SHIFT]+3 - Restore Time Value ", " [SHIFT]+4 - Enable Audio Reacitivty (if supported)", " [SHIFT]+[LEFT] - Time control move backard", " [SHIFT]+[RIGHT] - TIme control move forward", " [UP] - Shader Index move up", " [DOWN] - Shader Index move down", " [ENTER] - Jump to currently typed index (type index with number keys at anytime)", " [SHIFT]+[ENTER] - Release Stored Frames ", " [PAGEUP] - Store Index Position", " [PAGEDOWN] - Restore Position Index", " Q,Q,E,R,Y,U,I,O - move movement rate", " T - reset color offset", "[end]" }; int acidcam::redir = 0; int acidcam::syphon_enabled = 0; int cmd[2]; float pos_frames = 0; void print_help_message() { std::cout << "acidcamGL " << version_info << " \n"; for (int i = 0; outstr_arr[i] != "[end]"; ++i) std::cout << outstr_arr[i] << "\n"; } int findFilter(std::string f) { auto pos = draw_strings_map.find(f); if (pos == draw_strings_map.end()) return -1; return pos->second; } #ifndef _WIN32 CoutRedirect* redirect = 0; #endif void acidcam::updateError() { #if defined(__APPLE__) || defined(__linux__) if (redirect != 0) { std::string text = redirect->getString(); sendString(text); } #endif exit(EXIT_FAILURE); } void mux_audio_ac(std::string output, std::string filenamex) { std::string filename = filenamex; std::string output_file = output; std::string filename_audio = output_file.substr(0, output_file.rfind(".")); //filename.substr(0, filename.rfind(".")); std::string ext = filename.substr(filename.rfind("."), filename.length()); filename_audio += "_with_source_audio" + ext; mux_audio(output_file.c_str(), filename.c_str(), filename_audio.c_str()); std::cout << "\nacidcam: muxed " << output_file << " " << filename << " " << filename_audio << "\n"; } void rotate90(std::string input, std::string filename) { rotate_90(input.c_str(), filename.c_str()); std::cout << "\nacidcam: rotated 90 degrees\n"; } #if defined(SYPHON_SERVER) extern void messageOutput(std::string title, std::string text); #endif void system_pause() { #ifdef _WIN32 glfwTerminate(); //system("PAUSE"); #endif } #ifdef REACTIVE_ENABLED float gAmplitude = 0.0f; float amp_sense = 25.0f; int audioCallback(void* outputBuffer, void* inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void* userData) { if (status) { std::cerr << "Stream underflow detected!" << std::endl; } float* in = static_cast<float*>(inputBuffer); float* out = static_cast<float*>(outputBuffer); float sum = 0.0f; for (unsigned int i = 0; i < nBufferFrames * 2; ++i) { // assuming stereo input sum += std::abs(in[i]); out[i] = in[i]; // Pass-through } gAmplitude = sum / (nBufferFrames * 2); main_window.setAmp(gAmplitude, amp_sense); return 0; } #endif #ifdef MIDI_ENABLED std::unordered_map<std::pair<int, int>, int> key_values; void the_callback(std::vector<unsigned char>* message) { if (message->size() >= 2) { unsigned int nBytes = message->size(); std::cout << "acidcam: MIDI message: {\n"; for (unsigned int i = 0; i < nBytes; i++) { std::cout << static_cast<int>(message->at(i)) << " "; } std::cout << "\n}\n"; auto keyd = config.lookup_nov(midi::Key(message->at(0), message->at(1), message->at(2))); if (keyd.first != -1) { if (keyd.second == 0 && message->at(2) == 0) main_window.keypress(keyd.first, 0, GLFW_RELEASE, 0); if (keyd.second != 0) { if (key_values[keyd] == 0) key_values[keyd] = message->at(2); else { int val = key_values[keyd]; if (val < message->at(2)) { main_window.keypress(keyd.first, 0, GLFW_RELEASE, 0); key_values[keyd] = val; } else if (val > message->at(2)) { main_window.keypress(keyd.second, 0, GLFW_RELEASE, 0); key_values[keyd] = val; } } } } else { } } } #endif std::string to_lower(const std::string& s) { std::string temp; for (size_t i = 0; i < s.length(); ++i) { temp += tolower(s[i]); } return temp; } bool is_file_image(const std::string& f) { std::string lf = to_lower(f); if (lf.find(".png") != std::string::npos || lf.find(".jpg") != std::string::npos || lf.find(".tiff") != std::string::npos || lf.find(".bmp") != std::string::npos) return true; return false; } int main(int argc, char** argv) { // Enable unbuffered output so text appears immediately in launcher window std::cout << std::unitbuf; std::cerr << std::unitbuf; setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); atexit(system_pause); if (argc == 1) { #if defined(SYPHON_SERVER) std::string text = "Arguments Required: \n\n"; for (int i = 0; outstr_arr[i] != "[end]"; ++i) { text += outstr_arr[i] + "\n"; } messageOutput(std::string("acidcamGL ") + version_info, text); #else print_help_message(); #endif exit(EXIT_SUCCESS); } if (std::string(argv[1]) == "--mux" && argc == 4) { mux_audio_ac(argv[2], argv[3]); std::cout << "acidcam: exiting...\n"; exit(0); } else if (std::string(argv[1]) == "--list" && argc == 2) { list_devices(); exit(EXIT_SUCCESS); } else if (std::string(argv[1]) == "--rotate" && argc == 4) { rotate90(argv[2], argv[3]); std::cout << "acidcam: exiting...\n"; exit(0); } if (!glfwInit()) { std::cout << "acidcam: Error initalizing GLFW...\n"; acidcam::updateError(); } #ifdef MIDI_ENABLED #ifdef _WIN32 const char* m_p; char* px; size_t lenx; errno_t errx = _dupenv_s(&px, &lenx, "AC_MIDI"); if (lenx > 0) m_p = px; else m_p = "midi.midi_cfg"; std::cout << "acidcam: MIDI config path: " << m_p << "\n"; #else const char* m_p = getenv("AC_MIDI"); if (m_p == NULL) { std::cerr << "acidcam: Error requires enviorment variable AC_MIDI \nwith path to midi_config file.\n"; exit(EXIT_FAILURE); } #endif config.read(m_p); setup_main(&the_callback); #endif ac::init(); std::string filename; int w = 1280, h = 720; int cw = 1280, ch = 720; int opt = 0; int device = 0; int start_shader = 0; bool full = false; int joy_index = -1; std::string shader_path; bool print_text = false; double fps = 24.0; bool debug_val = false; std::string key_val; std::string snapshot_prefix = "AcidCamGL_Snapshot"; bool restore_black = false; std::string list_var; std::string output_file; std::string filter_string; bool h264 = false; bool force_full = false; int monitor = 0; int set_index = 0; bool repeat = false; int color_map = -1; bool screen_mode = false; std::string material; int res_w = 0, res_h = 0; int screen_x = 100, screen_y = 100; std::string custom_path; bool playback_mode = false; bool playback_sort = false; int playback_timeout = 1; bool stereo_ = false; int bpm = 0; std::string codec; std::string crf = "22"; bool ffmpeg_enabled = false; std::string res_v, fres_v; std::string ff_codec = "libx265"; std::string list_path; bool cubeapp = false; std::string plugins; bool value_enabled = false; int value_index = 0; std::string output_format = "png"; std::string autofilter_file; std::string custom_index; bool enable_audio_ex = true; bool stop_audio_mux = false; #ifdef REACTIVE_ENABLED int input_channels = 2; #endif while ((opt = getopt(argc, argv, "A:s:6:3:21:a:45E:m:w:xN:X:qBU:W:GYPT:C:Z:H:S:M:Fhbgu:p:i:c:r:Rd:fhvj:snlk:e:L:o:tQ:7:9:8:yV:I:O")) != -1) { switch (opt) { case 'O': stop_audio_mux = true; break; case 'I': #ifdef REACTIVE_ENABLED if (optarg != NULL) input_channels = atoi(optarg); #endif break; case 'V': #ifdef REACTIVE_ENABLED if (optarg != NULL) amp_sense = atof(optarg); #endif break; case 'y': enable_audio_ex = false; break; case '8': if (optarg != 0) { int max_frames = atoi(optarg); if (max_frames > 32) { ac::setMaxAllocated(atoi(optarg)); } else { std::cerr << "acidcam: Invalid max frames must be greater than 32..\n"; exit(EXIT_FAILURE); } } break; case '9': if (optarg != 0) { int count = atoi(optarg); if (count < 2) { std::cerr << "acidcam: Invalid thread count..\n"; exit(EXIT_FAILURE); } ac::setThreadCount(count); std::cout << "acidcam: Thread Count set to: " << count << "\n"; } break; case 'A': if (optarg != 0) { autofilter_file = optarg; } break; case 's': if (optarg != 0) output_format = optarg; break; case '7': pos_frames = atof(optarg); break; case '6': value_enabled = true; value_index = atoi(optarg); break; case '3': plugins = optarg; break; case '2': cubeapp = true; break; case '1': ffmpeg_path = optarg; std::cout << "acidcam: path to ffmpeg executable: " << ffmpeg_path << "\n"; break; case 'a': list_path = optarg; break; case '4': ffmpeg_enabled = true; ff_codec = "libx264"; break; case '5': ffmpeg_enabled = true; ff_codec = "libx265"; break; case 'E': if (optarg != NULL) { ffmpeg_enabled = true; ff_codec = optarg; std::cout << "acidcam: Using hardware codec: " << ff_codec << "\n"; } break; case 'm': crf = optarg; break; case 'w': bpm = atoi(optarg); break; case 'x': stereo_ = true; break; case 'N': playback_timeout = atoi(optarg); break; case 'X': codec = optarg; break; case 'q': playback_sort = true; break; case 'B': playback_mode = true; break; case 'W': custom_path = optarg; break; case 'Y': #ifdef SYPHON_SERVER syphon_start(); std::cout << "acidcam: Syphon Server Startup...\n"; acidcam::syphon_enabled = 1; #endif break; case 'G': screen_mode = true; break; case 'P': #if defined(__APPLE__) || defined(__linux__) redirect = new CoutRedirect(); client_main(); sendString("\nacidcam: Code Startup\n"); acidcam::redir = 1; #endif break; case 'T': material = optarg; break; case 'C': color_map = atoi(optarg); if (color_map > 19 || color_map < 0) { std::cout << "acidcam: error color map out of range\n"; acidcam::updateError(); } break; case 'Z': filter_string = optarg; break; case 'H': start_shader = atoi(optarg); break; case 'R': repeat = true; break; case 'S': custom_index = optarg; set_index = atoi(optarg); break; case 'M': monitor = atoi(optarg); break; case 'F': force_full = true; break; case 'h': h264 = true; break; case 'o': output_file = optarg; break; case 'L': list_var = optarg; break; case 'b': restore_black = true; break; case 'e': snapshot_prefix = optarg; break; case 'k': key_val = optarg; break; case 'Q': { for (int i = 0; i < ac::solo_filter.size(); ++i) { if (ac::solo_filter[i].find(optarg) != std::string::npos) std::cout << ac::solo_filter[i] << "\n"; } exit(EXIT_SUCCESS); } break; case 't': for (int i = 0; i < ac::solo_filter.size(); ++i) { std::cout << ac::solo_filter[i] << "\n"; } exit(EXIT_SUCCESS); break; case 'l': std::cout << "Filters by Index: \n"; for (int i = 0; i < ac::solo_filter.size(); ++i) { std::cout << i << ": " << ac::solo_filter[i] << "\n"; } exit(EXIT_SUCCESS); break; case 'g': debug_val = true; break; case 'u': fps = atof(optarg); break; case 'n': print_text = true; break; case 'p': { shader_path = optarg; } break; case 'i': filename = optarg; break; case 'v': print_help_message(); exit(EXIT_SUCCESS); break; case 'f': full = true; break; case 'd': device = atoi(optarg); cmd[0] = device; break; case 'r': { std::string pos = optarg; if (pos.rfind("x") == std::string::npos) { std::cout << "acidcam: Invalid format for resolution string...1920x1080 is proper.\n"; acidcam::updateError(); } std::string left = pos.substr(0, pos.rfind("x")); std::string right = pos.substr(pos.rfind("x") + 1, pos.length()); w = atoi(left.c_str()); h = atoi(right.c_str()); res_w = w; res_h = h; if (w <= 0 || h <= 0) { std::cout << "acidcam: Invalid resolution..\n"; acidcam::updateError(); } std::ostringstream stream; stream << res_w << "x" << res_h; fres_v = stream.str(); std::cout << "acidcam: Setting Window Resolution at: " << w << "x" << h << "\n"; } break; case 'U': { std::string pos = optarg; if (pos.rfind(",") == std::string::npos) { std::cout << "acidcam: Invalid format for position string... 100,100 is proper.\n"; acidcam::updateError(); } std::string left = pos.substr(0, pos.rfind(",")); std::string right = pos.substr(pos.rfind(",") + 1, pos.length()); screen_x = atoi(left.c_str()); screen_y = atoi(right.c_str()); } break; case 'c': { std::string pos = optarg; if (pos.rfind("x") == std::string::npos) { std::cout << "acidcam: Invalid format for resolution string...1920x1080 is proper.\n"; acidcam::updateError(); } std::string left = pos.substr(0, pos.rfind("x")); std::string right = pos.substr(pos.rfind("x") + 1, pos.length()); cw = atoi(left.c_str()); ch = atoi(right.c_str()); if (w <= 0 || h <= 0) { std::cout << "Invalid resolution..\n"; acidcam::updateError(); } std::cout << "acidcam: Desired Capture Resolution: " << cw << "x" << ch << "\n"; res_v = optarg; } break; case 'j': joy_index = atoi(optarg); break; } } #ifndef WIN32 char* p = getenv("SHADER_PATH"); if (p != NULL) shader_path = p; p = getenv("AC_PLUGIN_PATH"); if (p != NULL) plugins = p; p = getenv("AC_CUSTOM_PATH"); if (p != NULL) custom_path = p; p = getenv("FFMPEG_PATH"); if (p != NULL) ffmpeg_path = p; #else char* p; size_t len; errno_t err = _dupenv_s(&p, &len, "SHADER_PATH"); if (len > 0) shader_path = p; err = _dupenv_s(&p, &len, "AC_CUSTOM_PATH"); if (len > 0) custom_path = p; #endif main_window.enableCube(cubeapp); if (shader_path.length() == 0) { std::cout << "acidcam: Error: must provide path to shaders...\n"; acidcam::updateError(); } #ifdef REACTIVE_ENABLED RtAudio audio; if (enable_audio_ex && audio.getDeviceCount() < 1) { std::cerr << "No audio devices found!" << std::endl; #ifdef _WIN32 system("PAUSE"); #endif return 1; } else { std::cout << "acidcam: Audio device found...\n"; } unsigned int sampleRate = 44100; unsigned int bufferFrames = 512; RtAudio::StreamParameters inputParams, outputParams; if (enable_audio_ex) { unsigned int inputDeviceId = audio.getDefaultInputDevice(); unsigned int outputDeviceId = audio.getDefaultOutputDevice(); if (inputDeviceId == 0) { std::cout << "acidcam: No Input device found...\n"; enable_audio_ex = false; return 1; } else if (outputDeviceId == 0) { std::cout << "acidcam: No Output device found...\n"; enable_audio_ex = false; return 1; } else { inputParams.deviceId = audio.getDefaultInputDevice(); inputParams.nChannels = input_channels; inputParams.firstChannel = 0; outputParams.deviceId = audio.getDefaultOutputDevice(); outputParams.nChannels = 2; outputParams.firstChannel = 0; std::vector<unsigned int> sampleRates = audio.getDeviceInfo(inputDeviceId).sampleRates; if (std::find(sampleRates.begin(), sampleRates.end(), sampleRate) == sampleRates.end()) { sampleRate = 48000; if (std::find(sampleRates.begin(), sampleRates.end(), sampleRate) == sampleRates.end()) { sampleRate = sampleRates[0]; // Choose the first supported sample rate } } } } #endif cv::VideoWriter writer; int camera_mode = 0; if (screen_mode == false) { if (filename.length() != 0 && is_file_image(filename) == true) { cv::Mat input_file = cv::imread(filename); if (!input_file.empty()) { std::cout << "acidcam: Loading from Image: " << filename << "\n"; } else { std::cout << "acidcam: Could not load image: " << filename << "\n"; acidcam::updateError(); } main_window.setImageMode(input_file, fps); cw = input_file.cols; ch = input_file.rows; camera_mode = 1; if (res_w == 0 && res_h == 0) { w = cw; h = ch; } } else if (filename.length() == 0) { #ifdef _WIN32 acidcam::cap.open(device, cv::CAP_DSHOW); #elif defined(__linux__) acidcam::cap.open(device, cv::CAP_V4L2); #else acidcam::cap.open(device); #endif if (!acidcam::cap.isOpened()) { std::cout << "acidcam: Could not open capture device...\n"; acidcam::updateError(); } acidcam::cap.set(cv::CAP_PROP_BUFFERSIZE, 1); acidcam::cap.set(cv::CAP_PROP_FRAME_WIDTH, w); acidcam::cap.set(cv::CAP_PROP_FRAME_HEIGHT, h); acidcam::cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M','J','P','G')); acidcam::cap.set(cv::CAP_PROP_FPS, fps); w = static_cast<int>(acidcam::cap.get(cv::CAP_PROP_FRAME_WIDTH)); h = static_cast<int>(acidcam::cap.get(cv::CAP_PROP_FRAME_HEIGHT)); fps = acidcam::cap.get(cv::CAP_PROP_FPS); camera_mode = 0; } else { acidcam::cap.open(filename); if (!acidcam::cap.isOpened()) { std::cout << "acidcam: Error could not open file: " << filename << "\n"; acidcam::updateError(); } cw = acidcam::cap.get(cv::CAP_PROP_FRAME_WIDTH); ch = acidcam::cap.get(cv::CAP_PROP_FRAME_HEIGHT); fps = acidcam::cap.get(cv::CAP_PROP_FPS); if (res_w == 0 && res_h == 0) { w = cw; h = ch; } if (pos_frames > 0) { int frame_index = static_cast<int>(pos_frames * fps); acidcam::cap.set(cv::CAP_PROP_POS_FRAMES, frame_index); std::cout << "acidcam: video offset set to frame: " << frame_index << "\n"; } camera_mode = 1; } } std::cout << "acidcam: " << version_info << "\n"; std::cout << "acidcam: shader path: " << shader_path << "\n"; std::ostringstream rv; rv << cw << "x" << ch; res_v = rv.str(); if (fres_v.length() == 0) fres_v = res_v; if (force_full == true) { main_window.create(false, true, false, "acidcamGL", w, h, monitor); } else { main_window.create(false, full, true, "acidcamGL", w, h, monitor); } if (screen_mode) main_window.enableScreenMode(true, screen_x, screen_y, cw, ch); if (filename.length() == 0) main_window.setVideoMode(false, 0); else if (is_file_image(filename) == false) main_window.setVideoMode(true, fps); std::cout << "acidcam: Acid Cam Filter Library Version: " << ac::getVersion() << "\n"; std::cout << "acidcam: GL Version: " << glGetString(GL_VERSION) << "\n"; std::cout << "acidcam: Actual " << ((filename.length() == 0) ? "Camera" : "File") << " Resolution: " << cw << "x" << ch << "p" << fps << " \n"; glfwSetKeyCallback(main_window.win(), key_callback); glfwSetWindowSizeCallback(main_window.win(), window_size_callback); glfwSetCharCallback(main_window.win(), character_callback); if (custom_path.length() != 0) main_window.loadCustom(custom_path); if (plugins.length() > 0) main_window.loadPlugins(plugins); for (int i = 0; i < ac::solo_filter.size(); ++i) draw_strings_map[ac::solo_filter[i]] = i; if (autofilter_file != "") main_window.loadAutoFilter(autofilter_file); main_window.setOutputFormat(output_format); if (list_var.length() > 0) main_window.loadList(list_var, playback_sort); main_window.setDebug(debug_val); main_window.setRepeat(filename, repeat); if (set_index < 0 || set_index > ac::solo_filter.size() - 1) { std::cout << "acidcam: Error invalid starting index...\n"; acidcam::updateError(); } if (material.length() > 0) main_window.genMaterial(material); main_window.loadShaders(shader_path); main_window.setShader(start_shader); if (list_path.length() > 0) main_window.loadShaderList(list_path); if (filter_string.length() > 0) { if (filter_string.find(",") != std::string::npos) { set_index = main_window.setCustomFilter(filter_string); } else { set_index = findFilter(filter_string); if (set_index == -1) { std::cout << "acidcam: Error could not find filter: " << filter_string << "\n"; acidcam::updateError(); } } } if (custom_index.length() > 0 && custom_index.find(",") != std::string::npos) { set_index = main_window.setCustomFilterByIndex(custom_index); } main_window.setFilterIndex(set_index); main_window.setPrintText(print_text); main_window.setPrefix(snapshot_prefix); main_window.setRestoreBlack(restore_black); main_window.setColorMap(color_map); main_window.setStereo(stereo_); FILE* fptr = 0; std::cout << "acidcam: Loaded: " << ac::solo_filter.size() << " Filters\n"; std::cout << "acidcam: initialized...\n"; if (output_file.length() > 0) { if (ffmpeg_enabled == false) { if (codec.length() > 0) writer.open(output_file, cv::VideoWriter::fourcc(codec[0], codec[1], codec[2], codec[3]), fps, cv::Size(w, h), true); else writer.open(output_file, cv::VideoWriter::fourcc('m', 'p', '4', 'v'), fps, cv::Size(w, h), true); if (!writer.isOpened()) { std::cout << "acidcam: Error opening video writer...\n"; acidcam::updateError(); } std::cout << "acidcam: record " << output_file << " " << w << "x" << h << " " << fps << "\n"; main_window.setWriter(writer, w, h); } else { std::ostringstream fps_; fps_ << fps; std::cout << "acidcam: writing with " << codec << " " << output_file << " " << res_v << " " << fres_v << " " << fps << "\n"; fptr = open_ffmpeg(output_file.c_str(), ff_codec.c_str(), res_v.c_str(), fres_v.c_str(), fps_.str().c_str(), crf.c_str()); main_window.setWriter(writer, w, h); main_window.setFilePointer(fptr, w, h); } } if (key_val.length() > 0) main_window.loadKeys(key_val); if (playback_mode) { int value = 0; value = fps * 60 / bpm; main_window.setPlaybackMode(playback_mode, playback_timeout, value, bpm, playback_sort); if (value == 0) { std::cout << "acidcam: Error invalid bpm info.\n"; acidcam::updateError(); } } if (acidcam::redir == 1) { #ifndef _WIN32 if (redirect != 0) { std::string text = redirect->getString(); sendString(text); } #endif } cmd[0] = device; cmd[1] = value_index; if (value_enabled && cmd[0] >= 0 && cmd[1] >= 0) { if (cw != res_w || ch != res_h) { std::cout << "acidcam: Error stereo cam resolution must be window resolution.\n"; acidcam::updateError(); } main_window.StereoX(cmd, cw, ch, fps); } #ifdef REACTIVE_ENABLED if (enable_audio_ex) { std::cout << "acidcam: Setting input channels to: " << input_channels << "\n"; std::cout << "acidcam: Setting sample rate to: " << sampleRate << "\n"; try { audio.openStream(&outputParams, &inputParams, RTAUDIO_FLOAT32, sampleRate, &bufferFrames, &audioCallback); audio.startStream(); if (audio.isStreamOpen()) std::cout << "acidcam: Audio stream opened...\n"; } catch (std::exception& e) { std::cerr << "Standard exception: " << e.what() << std::endl; if (audio.isStreamOpen()) audio.closeStream(); return 1; } catch (...) { std::cerr << "Unknown error occurred!" << std::endl; if (audio.isStreamOpen()) audio.closeStream(); return 1; } } #endif main_window.loop(); writer.release(); acidcam::cap.release(); if (fptr != 0) { #ifndef _WIN32 pclose(fptr); #else _pclose(fptr); #endif } else writer.release(); if (writer.isOpened()) std::cout << "acidcam: wrote to file [" << output_file << "]\n"; else if (ffmpeg_enabled) std::cout << "acidcam: wrote file with ffmpeg: [" << output_file << "]\n"; if (is_file_image(filename) == false && camera_mode == 1 && ffmpeg_enabled && stop_audio_mux == false) { mux_audio_ac(output_file, filename); } #ifdef MIDI_ENABLED midi_cleanup(); std::cout << "acidcam: MIDI shutdown.\n"; #endif #ifdef REACTIVE_ENABLED if (enable_audio_ex && audio.isStreamOpen()) { audio.closeStream(); std::cout << "acidcam: Audio stream closed.\n"; } #endif std::cout << "acidcam: exited\n"; if (acidcam::redir == 1) { #if defined(__APPLE__) || defined(__linux__) std::string text = redirect->getString(); sendString(text); #endif } #ifdef SYPHON_SERVER if (acidcam::syphon_enabled) { syphon_stop(); syphon_exit(); } #endif #ifdef FOR_LINUX if (acidcam::screen_shot != nullptr) delete acidcam::screen_shot; #endif glfwTerminate(); return EXIT_SUCCESS; }