#include "ANSFilePlayer_CV.h" #include "ANSMatRegistry.h" #include #include #include #include #include #include "media_codec.h" static bool ansfileplayerLicenceValid = false; // Global once_flag to protect license checking static std::once_flag ansfileplayerLicenseOnceFlag; namespace ANSCENTER { #define CHECK_CUDA(call) do { \ cudaError_t err = call; \ if (err != cudaSuccess) { \ std::cout<<"CUDA error: " + std::string(cudaGetErrorString(err)); \ } \ } while (0) #define CHECK_NVJPEG(call) do { \ nvjpegStatus_t status = call; \ if (status != NVJPEG_STATUS_SUCCESS) { \ std::cout <<"nvJPEG error: " + std::to_string(status); \ } \ } while (0) ANSFILEPLAYER_CV::ANSFILEPLAYER_CV() :_stopThread(std::make_shared>(false)) { _resWidth = 0; _resHeight = 0; m_bPaused = false; _crop = false; _isPlaying = false; _lastJpegImage = ""; _bbox = cv::Rect(0, 0, 0, 0); _jpegCompressor = nullptr; _previousPTS = 0; _totalFrames = 0; } ANSFILEPLAYER_CV::~ANSFILEPLAYER_CV() noexcept { try { StopTimerThread(); Destroy(); } catch (...) {} } void ANSFILEPLAYER_CV::Destroy() { std::lock_guard lock(_mutex); try { _previousImage.release(); _lastJpegImage = ""; _isPlaying = false; _resWidth = 0; _resHeight = 0; _currentFrame = 0; _previousPTS = 0; if (cap.isOpened()) { cap.release(); } } catch (const std::exception& e) { _logger.LogError("ANSFILEPLAYER_CV::Destroy. Exception:", e.what(), __FILE__, __LINE__); } catch (...) { _logger.LogError("ANSFILEPLAYER_CV::Destroy.", "Unknown exception", __FILE__, __LINE__); } } static void VerifyGlobalANSFPLicense(const std::string& licenseKey) { try { ansfileplayerLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1007, "ANSCV");//Default productId=1005 if (!ansfileplayerLicenceValid) { // we also support ANSTS license ansfileplayerLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1003, "ANSVIS");//Default productId=1003 (ANSVIS) } if (!ansfileplayerLicenceValid) { // we also support ANSTS license ansfileplayerLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1008, "ANSTS");//Default productId=1008 (ANSTS) } } catch (std::exception& e) { ansfileplayerLicenceValid = false; } } void ANSFILEPLAYER_CV::CheckLicense() { std::lock_guard lock(_mutex); try { // Check once globally std::call_once(ansfileplayerLicenseOnceFlag, [this]() { VerifyGlobalANSFPLicense(_licenseKey); }); // Update this instance's local license flag _licenseValid = ansfileplayerLicenceValid; } catch (const std::exception& e) { this->_logger.LogFatal("ANSFILEPLAYER_CV::CheckLicense. Error:", e.what(), __FILE__, __LINE__); } } bool ANSFILEPLAYER_CV::Init(std::string licenseKey, std::string url) { std::lock_guard lock(_mutex); _licenseKey = licenseKey; CheckLicense(); if (!_licenseValid) { _logger.LogError("ANSFILEPLAYER_CV::Init.", "Invalid license", __FILE__, __LINE__); return false; } _url = url; return Setup(); } bool ANSFILEPLAYER_CV::Setup() { std::lock_guard lock(_mutex); _currentFrame = 0; if (cap.isOpened()) return true; cap.open(_url, cv::CAP_FFMPEG); // USe FFMPEG for better codec support if (!cap.isOpened()) { cap.open(_url, cv::CAP_ANY); if (!cap.isOpened())return false; } try { _resWidth = static_cast(cap.get(cv::CAP_PROP_FRAME_WIDTH)); _resHeight = static_cast(cap.get(cv::CAP_PROP_FRAME_HEIGHT)); _totalFrames = static_cast(cap.get(cv::CAP_PROP_FRAME_COUNT)); _fps = cap.get(cv::CAP_PROP_FPS); cap.set(cv::CAP_PROP_POS_FRAMES, _currentFrame); if (_fps > 0) { if (_timerThread && _timerThread->joinable()) return true; // Exit if the thread is already running int interval_ms = static_cast(1000 / _fps); *_stopThread = false; _timerThread = std::make_shared(&ANSFILEPLAYER_CV::StartTimer, this, _stopThread, interval_ms); } return true; } catch (std::exception& e) { this->_logger.LogError("ANSFILEPLAYER_CV::Setup:", e.what(), __FILE__, __LINE__); return false; } } void ANSFILEPLAYER_CV::StartTimer(std::shared_ptr> stopFlag, int interval_ms) { while (!stopFlag->load()) { std::unique_lock lock(_cvMutex); // Wait for the specified interval or until stopFlag is set if (_cv.wait_for(lock, std::chrono::milliseconds(interval_ms), [&]() { return stopFlag->load(); })) { break; // Exit the loop if stopFlag is true } lock.unlock(); // Unlock to avoid deadlocks in further operations int delayMs = 0; int actualSleepTime = interval_ms; { std::lock_guard lock(_mutex); auto start = std::chrono::system_clock::now(); if (_isPlaying) { try { _currentFrame = static_cast(cap.get(cv::CAP_PROP_POS_FRAMES)); // Add check for _stopThread before blocking operations if (!cap.grab() || _currentFrame >= _totalFrames - 1) { if (cap.isOpened()) { cap.release(); cap.open(_url, cv::CAP_FFMPEG); // USe FFMPEG for better codec support if (!cap.isOpened()) { cap.open(_url, cv::CAP_ANY); } } if (cap.isOpened()) { cap.set(cv::CAP_PROP_POS_FRAMES, 0); _currentFrame = 0; } } } catch (const std::exception& e) { this->_logger.LogError("ANSFILEPLAYER_CV::StartTimer. Exception occurred:", e.what(), __FILE__, __LINE__); } } auto end = std::chrono::system_clock::now(); delayMs = std::chrono::duration_cast(end - start).count(); // Calculate actual sleep time based on any delay introduced actualSleepTime = interval_ms - delayMs; if (actualSleepTime < 1) actualSleepTime = 1; } std::this_thread::sleep_for(std::chrono::milliseconds(actualSleepTime)); } } void ANSFILEPLAYER_CV::StopTimerThread() { *_stopThread = true; // Signal to stop the thread _cv.notify_all(); // Notify the condition variable to unblock the thread if (_timerThread && _timerThread->joinable()) { _timerThread->join(); // Join the timer thread to ensure cleanup } } bool ANSFILEPLAYER_CV::Reconnect() { std::lock_guard lock(_mutex); try { _currentFrame = 0; if (cap.isOpened()) { cap.release(); } Setup(); _isPlaying = cap.isOpened() && cap.grab(); return _isPlaying; } catch (const std::exception& e) { this->_logger.LogError("ANSFILEPLAYER_CV::Reconnect. Exception occurred:", e.what(), __FILE__, __LINE__); _currentFrame = 0; return false; } } bool ANSFILEPLAYER_CV::Start() { std::lock_guard lock(_mutex); try { if (!cap.isOpened()) { cap.open(_url, cv::CAP_FFMPEG); if (!cap.isOpened()) { cap.open(_url, cv::CAP_ANY); } if (!cap.isOpened()) { this->_logger.LogError("ANSFILEPLAYER_CV::Start. Exception occurred:", "Failed to open video source: ", __FILE__, __LINE__); return false; } try { if (!cap.set(cv::CAP_PROP_POS_FRAMES, _currentFrame)) { this->_logger.LogError("ANSFILEPLAYER_CV::Start. Exception occurred:", "Warning: Unable to seek to frame", __FILE__, __LINE__); } } catch (const std::exception& e) { this->_logger.LogError("ANSFILEPLAYER_CV::Start. Exception occurred:", e.what(), __FILE__, __LINE__); } } _isPlaying = cap.isOpened() && cap.grab(); return _isPlaying; } catch (const std::exception& e) { this->_logger.LogError("ANSFILEPLAYER_CV::Start. Exception occurred:", e.what(), __FILE__, __LINE__); return false; } } bool ANSFILEPLAYER_CV::Stop() { std::lock_guard lock(_mutex); try { if (cap.isOpened()) { try { double frame_pos = cap.get(cv::CAP_PROP_POS_FRAMES); if (frame_pos >= 0) { _currentFrame = static_cast(frame_pos); } else { _currentFrame = 0; this->_logger.LogError("ANSFILEPLAYER_CV::Stop. Exception occurred:", "Unable to retrieve current frame position", __FILE__, __LINE__); } } catch (const std::exception& e) { this->_logger.LogError("ANSFILEPLAYER_CV::Stop. Exception occurred:", e.what(), __FILE__, __LINE__); _currentFrame = 0; } cap.release(); } _isPlaying = false; return true; } catch (const std::exception& e) { this->_logger.LogError("ANSFILEPLAYER_CV::Stop. Exception occurred:", e.what(), __FILE__, __LINE__); return false; } } void ANSFILEPLAYER_CV::SetBBox(cv::Rect bbox) { std::lock_guard lock(_mutex); _bbox = bbox; } void ANSFILEPLAYER_CV::SetCrop(bool crop) { std::lock_guard lock(_mutex); _crop = crop; } bool ANSFILEPLAYER_CV::IsPaused() { std::lock_guard lock(_mutex); return !cap.isOpened(); } bool ANSFILEPLAYER_CV::IsPlaying() { std::lock_guard lock(_mutex); return cap.isOpened(); } bool ANSFILEPLAYER_CV::IsRecording() { std::lock_guard lock(_mutex); return false;// do not support recording for webcam } cv::Mat ANSFILEPLAYER_CV::GetImage(int& width, int& height, int64_t& pts) { std::lock_guard lock(_mutex); if (!_isPlaying) { if (!_previousImage.empty()) { width = _previousImage.cols; height = _previousImage.rows; pts = _previousPTS; return _previousImage; } return cv::Mat(); } try { if (!cap.isOpened()) { if (!_previousImage.empty()) { width = _previousImage.cols; height = _previousImage.rows; pts = _previousPTS; return _previousImage; } return cv::Mat(); } cv::Mat frame; if (!cap.read(frame) || frame.empty()) { // Return last good frame if available if (!_previousImage.empty()) { width = _previousImage.cols; height = _previousImage.rows; pts = _previousPTS; return _previousImage; } return cv::Mat(); } cv::Mat result; // Apply cropping if enabled if (_crop) { // Validate and clamp crop region _bbox.x = std::clamp(_bbox.x, 0, frame.cols - 1); _bbox.y = std::clamp(_bbox.y, 0, frame.rows - 1); _bbox.width = std::min(_bbox.width, frame.cols - _bbox.x); _bbox.height = std::min(_bbox.height, frame.rows - _bbox.y); if (_bbox.width > 0 && _bbox.height > 0) { // CRITICAL: Clone to avoid dangling reference result = frame(_bbox).clone(); } else { result = frame.clone(); } } else { result = frame.clone(); } // Apply rotation if specified if (_imageRotateDeg > 0) { // Fast path for 90-degree rotations if (std::abs(_imageRotateDeg - 90.0) < 0.01) { cv::rotate(result, result, cv::ROTATE_90_CLOCKWISE); } else if (std::abs(_imageRotateDeg - 180.0) < 0.01) { cv::rotate(result, result, cv::ROTATE_180); } else if (std::abs(_imageRotateDeg - 270.0) < 0.01) { cv::rotate(result, result, cv::ROTATE_90_COUNTERCLOCKWISE); } else { // Arbitrary angle rotation const cv::Point2f center(result.cols / 2.0f, result.rows / 2.0f); cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, _imageRotateDeg, 1.0); cv::Mat rotated; // Use INTER_LINEAR instead of INTER_CUBIC (2-3x faster, minimal quality loss) cv::warpAffine(result, rotated, rotationMatrix, result.size(), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar()); result = rotated; } } // Update PTS (presentation timestamp) if (_previousPTS < INT64_MAX) { _previousPTS++; } else { _previousPTS = 0; } // Update cached frame _previousImage = result; // Set output parameters width = result.cols; height = result.rows; pts = _previousPTS; return result; } catch (const cv::Exception& e) { this->_logger.LogError("ANSFILEPLAYER_CV::GetImage. OpenCV exception:", e.what(), __FILE__, __LINE__); } catch (const std::exception& e) { this->_logger.LogError("ANSFILEPLAYER_CV::GetImage. Exception:", e.what(), __FILE__, __LINE__); } catch (...) { this->_logger.LogError("ANSFILEPLAYER_CV::GetImage. Unknown exception", "", __FILE__, __LINE__); } return cv::Mat(); } void ANSFILEPLAYER_CV::EnableAudio(bool status) { // please support audio enable for webcam } void ANSFILEPLAYER_CV::SetAudioVolume(int volume) { // support audio volumne } std::string ANSFILEPLAYER_CV::encodeJpegString(const cv::Mat& img, int quality) { std::lock_guard lock(_mutex); if (!_isPlaying) return _lastJpegImage; unsigned char* jpegBuf = nullptr; tjhandle jpegCompressor = nullptr; try { // Initialize TurboJPEG compressor jpegCompressor = tjInitCompress(); if (!jpegCompressor) { this->_logger.LogError("Failed to initialize TurboJPEG compressor.", tjGetErrorStr(), __FILE__, __LINE__); return _lastJpegImage; } int maxBufferSize = img.cols * img.rows * 3; jpegBuf = tjAlloc(maxBufferSize); if (!jpegBuf) { this->_logger.LogError("Failed to allocate memory for JPEG buffer.", tjGetErrorStr(), __FILE__, __LINE__); tjDestroy(jpegCompressor); return _lastJpegImage; } long unsigned int jpegSize = maxBufferSize; int subsamp = TJSAMP_444; int pixelFormat = img.channels() == 3 ? TJPF_BGR : TJPF_GRAY; // Compress the image if (tjCompress2(jpegCompressor, img.data, img.cols, 0, img.rows, pixelFormat, &jpegBuf, &jpegSize, subsamp, quality, TJFLAG_FASTDCT) != 0) { this->_logger.LogError("Compression error:", tjGetErrorStr(), __FILE__, __LINE__); tjFree(jpegBuf); tjDestroy(jpegCompressor); return _lastJpegImage; } // Create string from JPEG buffer std::string jpegString(reinterpret_cast(jpegBuf), jpegSize); _lastJpegImage = jpegString; } catch (const std::exception& e) { this->_logger.LogError("Exception occurred:", e.what(), __FILE__, __LINE__); } // Cleanup resources if (jpegBuf) tjFree(jpegBuf); if (jpegCompressor) tjDestroy(jpegCompressor); return _lastJpegImage; } std::string ANSFILEPLAYER_CV::MatToBinaryData(const cv::Mat& image) { std::lock_guard lock(_mutex); // Check if the image is empty or has invalid data if (!_isPlaying) return _lastJpegImage; if (image.empty() || !image.data || !image.u) { return _lastJpegImage; } try { // Encode the image to a memory buffer return encodeJpegString(image, 85); } catch (const std::exception& e) { this->_logger.LogFatal("ANSFILEPLAYER_CV::MatToBinaryData. Exception occurred:", e.what(), __FILE__, __LINE__); } catch (...) { this->_logger.LogFatal("ANSFILEPLAYER_CV::MatToBinaryData.", "Unknown exception occurred.", __FILE__, __LINE__); } // Return an empty string in case of failure return _lastJpegImage; } std::string ANSFILEPLAYER_CV::GetJpegStringImage(int& width, int& height, int64_t& pts) { std::lock_guard lock(_mutex); if (!_isPlaying) return _lastJpegImage; try { cv::Mat image = GetImage(width, height, pts); std::string jpegString = MatToBinaryData(image); image.release(); return jpegString; } catch (const std::exception& e) { this->_logger.LogError("ANSFILEPLAYER_CV::GetJpegStringImage. Exception occurred:", e.what(), __FILE__, __LINE__); return _lastJpegImage; } } } extern "C" __declspec(dllexport) int CreateANSFileCVPlayerHandle(ANSCENTER::ANSFILEPLAYER_CV** Handle, const char* licenseKey, const char* url) { if (!Handle || !licenseKey || !url) return -1; try { auto ptr = std::make_unique(); bool result = ptr->Init(licenseKey, url); if (result) { *Handle = ptr.release(); extern void anscv_unregister_handle(void*); extern void anscv_register_handle(void*, void(*)(void*)); anscv_register_handle(*Handle, [](void* p) { auto* h = static_cast(p); try { h->Stop(); } catch (...) {} try { h->Destroy(); } catch (...) {} try { delete h; } catch (...) {} }); return 1; } *Handle = nullptr; return 0; } catch (...) { return 0; } } extern "C" __declspec(dllexport) int ReleaseANSFileCVPlayerHandle(ANSCENTER::ANSFILEPLAYER_CV** Handle) { if (Handle == nullptr || *Handle == nullptr) return -1; try { extern void anscv_unregister_handle(void*); anscv_unregister_handle(*Handle); // Destructor calls Destroy() � no need to call it explicitly (avoids double-destroy) std::unique_ptr ptr(*Handle); *Handle = nullptr; return 0; } catch (...) { if (Handle) *Handle = nullptr; return 0; } } extern "C" __declspec(dllexport) int GetFileCVPlayerStrImage(ANSCENTER::ANSFILEPLAYER_CV** Handle, int& width, int& height, int64_t& timeStamp, std::string& jpegImage) { if (Handle == nullptr || *Handle == nullptr) return -1; try { jpegImage = (*Handle)->GetJpegStringImage(width, height, timeStamp); if (!jpegImage.empty()) return 1; else return 0; } catch (const std::exception& e) { std::cerr << "Error getting image data from FilePlayer client: " << e.what() << std::endl; return -1; } catch (...) { return -1; } } extern "C" __declspec(dllexport) int GetFileCVPlayerImage(ANSCENTER::ANSFILEPLAYER_CV** Handle, int& width, int& height, int64_t& timeStamp, LStrHandle jpegImage) { if (Handle == nullptr || *Handle == nullptr) return -1; try { std::string jpegString = (*Handle)->GetJpegStringImage(width, height, timeStamp); int size = jpegString.length(); if (size > 0) { MgErr error; // Resize the jpegImage handle to hold the image data error = DSSetHandleSize(jpegImage, sizeof(int32) + size * sizeof(uChar)); // Check if resizing the handle was successful if (error == noErr) { // Set the size of the image in the handle (*jpegImage)->cnt = size; // Use memcpy to copy the data from the std::string to the LStrHandle's str buffer memcpy((*jpegImage)->str, jpegString.c_str(), size); // Return success return 1; } else { // Return failure if there was an error in resizing the handle std::cerr << "Error resizing jpegImage handle: " << error << std::endl; return 0; } } else { // If the JPEG image string is empty, return failure std::cerr << "No image data retrieved from FilePlayer client." << std::endl; return 0; } } catch (const std::exception& e) { std::cerr << "Error getting image data from FilePlayer client: " << e.what() << std::endl; return -1; } catch (...) { return -1; } } extern "C" __declspec(dllexport) int GetFileCVPlayerCVImage(ANSCENTER::ANSFILEPLAYER_CV** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image) { if (!Handle || !(*Handle) || !image) { std::cerr << "Error: Invalid input parameters in GetFilePlayerCVImage." << std::endl; return -1; } try { cv::Mat img = (*Handle)->GetImage(width, height, timeStamp); if (img.empty()) { return 0; // No valid image retrieved } // anscv_mat_replace has its own internal registry_mutex � no global mutex needed anscv_mat_replace(image, std::move(img)); return 1; // Success } catch (const cv::Exception& e) { std::cerr << "OpenCV exception in GetFilePlayerCVImage: " << e.what() << std::endl; return -2; } catch (const std::exception& e) { std::cerr << "Exception in GetFilePlayerCVImage: " << e.what() << std::endl; return -2; } catch (...) { std::cerr << "Unknown exception in GetFilePlayerCVImage" << std::endl; return -2; } } extern "C" __declspec(dllexport) int StartFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle) { if (Handle == nullptr || *Handle == nullptr) return -1; try { bool result = (*Handle)->Start(); if (result) return 1; else return 0; } catch (const std::exception& e) { std::cerr << "Error starting file player: " << e.what() << std::endl; return -1; } catch (...) { return -1; } } extern "C" __declspec(dllexport) int ReconnectFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle) { if (Handle == nullptr || *Handle == nullptr) return -1; try { bool result = (*Handle)->Reconnect(); if (result) return 1; else return 0; } catch (const std::exception& e) { std::cerr << "Error reconnecting file player: " << e.what() << std::endl; return -1; } catch (...) { return -1; } } extern "C" __declspec(dllexport) int StopFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle) { if (Handle == nullptr || *Handle == nullptr) return -1; try { bool result = (*Handle)->Stop(); if (result) return 1; else return 0; } catch (const std::exception& e) { std::cerr << "Error stopping file player: " << e.what() << std::endl; return -1; } catch (...) { return -1; } } extern "C" __declspec(dllexport) int IsFileCVPlayerPaused(ANSCENTER::ANSFILEPLAYER_CV** Handle) { if (Handle == nullptr || *Handle == nullptr) return -1; try { bool result = (*Handle)->IsPaused(); if (result) return 1; else return 0; } catch (const std::exception& e) { std::cerr << "Error checking if file player is paused: " << e.what() << std::endl; return -1; } catch (...) { return -1; } } extern "C" __declspec(dllexport) int IsFileCVPlayerRunning(ANSCENTER::ANSFILEPLAYER_CV** Handle) { if (Handle == nullptr || *Handle == nullptr) return -1; try { bool result = (*Handle)->IsPlaying(); if (result) return 1; else return 0; } catch (const std::exception& e) { std::cerr << "Error checking if file player is running: " << e.what() << std::endl; return -1; } catch (...) { return -1; } } extern "C" __declspec(dllexport) int IsFileCVPlayerRecording(ANSCENTER::ANSFILEPLAYER_CV** Handle) { if (Handle == nullptr || *Handle == nullptr) return -1; try { bool result = (*Handle)->IsRecording(); if (result) return 1; else return 0; } catch (const std::exception& e) { std::cerr << "Error checking if file player is recording: " << e.what() << std::endl; return -1; } catch (...) { return -1; } } extern "C" __declspec(dllexport) void SetFileCVPlayerAudioVolume(ANSCENTER::ANSFILEPLAYER_CV** Handle, int volume) { if (Handle == nullptr || *Handle == nullptr) return; try { (*Handle)->SetAudioVolume(volume); } catch (...) {} } extern "C" __declspec(dllexport) void EnableFileCVPlayerAudioVolume(ANSCENTER::ANSFILEPLAYER_CV** Handle, int status) { if (Handle == nullptr || *Handle == nullptr) return; try { bool audioStatus = false; if (status == 1)audioStatus = true; (*Handle)->EnableAudio(audioStatus); } catch (const std::exception& e) { std::cerr << "Error enabling audio for file player: " << e.what() << std::endl; } catch (...) {} } extern "C" __declspec(dllexport) void SetFileCVPlayerImageRotation(ANSCENTER::ANSFILEPLAYER_CV** Handle, double rotationAngle) { if (Handle == nullptr || *Handle == nullptr) return; try { (*Handle)->SetImageRotate(rotationAngle); } catch (...) {} } extern "C" __declspec(dllexport) int SetBBoxFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle, int x, int y, int width, int height) { if (Handle == nullptr || *Handle == nullptr) return -1; try { cv::Rect bbox(x, y, width, height); (*Handle)->SetBBox(bbox); return 1; } catch (const std::exception& e) { std::cerr << "Error setting bounding box for file player: " << e.what() << std::endl; return -1; } catch (...) { return -1; } } extern "C" __declspec(dllexport) int SetCropFlagFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle, int cropFlag) { if (Handle == nullptr || *Handle == nullptr) return -1; try { bool crop = false; if (cropFlag == 1)crop = true; (*Handle)->SetCrop(crop); return 1; } catch (const std::exception& e) { std::cerr << "Error setting crop flag for file player: " << e.what() << std::endl; return -1; } catch (...) { return -1; } }