/** * Create context. */ bool create(const StString& theFile) { if(myFormat == NULL) { return false; } #if !defined(ST_LIBAV_FORK) avformat_alloc_output_context2(&Context, myFormat, NULL, theFile.toCString()); #else Context = avformat_alloc_context(); if(Context == NULL) { return false; } Context->oformat = myFormat; if(Context->oformat->priv_data_size > 0) { Context->priv_data = av_mallocz(Context->oformat->priv_data_size); if(!Context->priv_data) { //goto nomem; } if(Context->oformat->priv_class) { *(const AVClass**)Context->priv_data = Context->oformat->priv_class; //av_opt_set_defaults(aCtxOut->priv_data); } } else { Context->priv_data = NULL; } const size_t aStrLen = stMin(theFile.Size + 1, size_t(1024)); stMemCpy(Context->filename, theFile.toCString(), aStrLen); Context->filename[1023] = '\0'; #endif return Context != NULL; }
int StApplication::getActionIdFromName(const StString& theActionName) const { StString aNameLower = theActionName; aNameLower.toLowerCase(); const std::string aName(aNameLower.toCString()); std::map< std::string, int >::const_iterator anAction = myActionLookup.find(aName); return anAction != myActionLookup.end() ? anAction->second : -1; }
void StApplication::addAction(const int theActionId, const StHandle<StAction>& theAction) { myActions[theActionId] = theAction; if(!theAction.isNull()) { StString aNameLower = theAction->getName(); aNameLower.toLowerCase(); const std::string aName(aNameLower.toCString()); myActionLookup[aName] = theActionId; } }
int StAndroidGlue::openFileDescriptor(const StString& thePath) { if(myJavaVM == NULL) { return -1; } StJNIEnv aJniEnv(myJavaVM); if(aJniEnv.isNull()) { return -1; } jclass aJClass_Activity = aJniEnv->GetObjectClass(myActivity->clazz); jmethodID aJMet_openFileDescriptor = aJniEnv->GetMethodID(aJClass_Activity, "openFileDescriptor", "(Ljava/lang/String;)I"); if(aJMet_openFileDescriptor == NULL) { ST_ERROR_LOG("StAndroidGlue::openFileDescriptor() - method is unavailable!"); return -1; } jstring aJStr = aJniEnv->NewStringUTF(thePath.toCString()); int aFileDesc = aJniEnv->CallIntMethod(myActivity->clazz, aJMet_openFileDescriptor, aJStr); aJniEnv->DeleteLocalRef(aJStr); return aFileDesc; }
HMODULE StLibrary::DLibLoadFull(const StString& theLibName) { #ifdef _WIN32 HMODULE aModule = LoadLibraryW(theLibName.toUtfWide().toCString()); if(aModule == NULL) { ST_DEBUG_LOG("Failed to load library: \"" + theLibName + "\" (" + (int )GetLastError() + ')'); } else { #ifdef ST_DEBUG_LIBS ST_DEBUG_LOG("Loaded library: \"" + theLibName + "\" " + DLibGetVersion(theLibName.toUtfWide())); #endif } return aModule; #else HMODULE aModule = dlopen(theLibName.toCString(), RTLD_NOW); if(aModule == NULL) { ST_DEBUG_LOG("Failed to load library: \"" + theLibName + "\" (" + dlerror() + ')'); } else { #ifdef ST_DEBUG_LIBS ST_DEBUG_LOG("Loaded library: \"" + theLibName + '\"'); #endif } return aModule; #endif }
void StFolder::init(const StArrayList<StString>& theExtensions, int theDeep) { // clean up old list... clear(); StString aSearchFolderPath = getPath(); #ifdef _WIN32 WIN32_FIND_DATAW aFindFile; StString aStrSearchMask = getPath() + StString(SYS_FS_SPLITTER) + '*'; HANDLE hFind = FindFirstFileW(aStrSearchMask.toUtfWide().toCString(), &aFindFile); for(BOOL hasFile = (hFind != INVALID_HANDLE_VALUE); hasFile == TRUE; hasFile = FindNextFileW(hFind, &aFindFile)) { // StString aCurrItemName(aFindFile.cFileName); addItem(theExtensions, theDeep, aSearchFolderPath, aCurrItemName); } FindClose(hFind); #else DIR* aSearchedFolder = opendir(aSearchFolderPath.toCString()); if(aSearchedFolder == NULL) { return; } for(dirent* aDirItem = readdir(aSearchedFolder); aDirItem != NULL; aDirItem = readdir(aSearchedFolder)) { // #if (defined(__APPLE__)) // automatically convert filenames from decomposed form used by Mac OS X file systems StString aCurrItemName = stFromUtf8Mac(aDirItem->d_name); #else StString aCurrItemName(aDirItem->d_name); #endif addItem(theExtensions, theDeep, aSearchFolderPath, aCurrItemName); } closedir(aSearchedFolder); #endif // perform sorting... sort(); }
void StWindowImpl::processEvents() { if(myParentWin == NULL || myToResetDevice) { // window is closed! return; } // check if we are exiting if(myParentWin->ToDestroy()) { myStEvent.Type = stEvent_Close; myStEvent.Close.Time = getEventTime(); signals.onClose->emit(myStEvent.Close); return; } // check onNewIntent event StString aDndFile; myParentWin->setHardwareStereoOn(myToEnableStereoHW); myParentWin->setTrackOrientation(myToTrackOrient); myParentWin->setHideSystemBars(myToHideStatusBar, myToHideNavBar); myParentWin->fetchState(aDndFile, myQuaternion, myToSwapEyesHW, myKeysState); if(!aDndFile.isEmpty()) { std::vector<const char*> aDndList; aDndList.push_back(aDndFile.toCString()); myStEvent.Type = stEvent_FileDrop; myStEvent.DNDrop.Time = getEventTime(); myStEvent.DNDrop.NbFiles = aDndList.size(); myStEvent.DNDrop.Files = &aDndList[0]; myEventsBuffer.append(myStEvent); } updateActiveState(); StPointD_t anOldMousePt = myMousePt; int aPollRes = 0; int aNbEvents = 0; StAndroidPollSource* aSource = NULL; bool toWaitEvents = false; while((aPollRes = ALooper_pollAll(toWaitEvents ? -1 : 0, NULL, &aNbEvents, (void** )&aSource)) >= 0) { if(aSource != NULL) { aSource->process(myParentWin, aSource); } if(myToResetDevice) { break; } // check if we are exiting if(myParentWin->ToDestroy()) { break; } } // check if we are exiting if(myParentWin->ToDestroy()) { myStEvent.Type = stEvent_Close; myStEvent.Close.Time = getEventTime(); signals.onClose->emit(myStEvent.Close); return; } myIsMouseMoved = false; if(myMousePt.x() >= 0.0 && myMousePt.x() <= 1.0 && myMousePt.y() >= 0.0 && myMousePt.y() <= 1.0) { StPointD_t aDspl = myMousePt - anOldMousePt; if(std::abs(aDspl.x()) >= 0.0008 || std::abs(aDspl.y()) >= 0.0008) { myIsMouseMoved = true; } } // update position only when all messages are parsed updateWindowPos(); myIsUpdated = false; // StWindow XLib implementation process events in the same thread // thus this double buffer is not in use // however user events may be posted to it swapEventsBuffers(); }
void StLogger::write(const StString& theMessage, const StLogger::Level theLevel, const StLogContext* ) { if(theLevel > myFilter || theMessage.isEmpty()) { // just ignore return; } // lock for safety if(!myMutex.isNull()) { myMutex->lock(); } // log to the file if(!myFilePath.isEmpty()) { #ifdef _WIN32 myFileHandle = _wfopen(myFilePath.toCString(), L"ab"); #elif defined(__linux__) myFileHandle = fopen(myFilePath.toCString(), "ab"); #endif if(myFileHandle != NULL) { switch(theLevel) { case ST_PANIC: fwrite("PANIC !! ", 1, 9, myFileHandle); fwrite(theMessage.toCString(), 1, theMessage.getSize(), myFileHandle); break; case ST_FATAL: fwrite("FATAL !! ", 1, 9, myFileHandle); fwrite(theMessage.toCString(), 1, theMessage.getSize(), myFileHandle); break; case ST_ERROR: fwrite("ERROR !! ", 1, 9, myFileHandle); fwrite(theMessage.toCString(), 1, theMessage.getSize(), myFileHandle); break; case ST_WARNING: fwrite("WARN -- ", 1, 9, myFileHandle); fwrite(theMessage.toCString(), 1, theMessage.getSize(), myFileHandle); break; case ST_INFO: case ST_VERBOSE: fwrite("INFO -- ", 1, 9, myFileHandle); fwrite(theMessage.toCString(), 1, theMessage.getSize(), myFileHandle); break; case ST_DEBUG: fwrite("DEBUG -- ", 1, 9, myFileHandle); fwrite(theMessage.toCString(), 1, theMessage.getSize(), myFileHandle); break; default: fwrite(theMessage.toCString(), 1, theMessage.getSize(), myFileHandle); break; } fwrite("\n", 1, 1, myFileHandle); fclose(myFileHandle); myFileHandle = NULL; } } // log to standard output (with colored prefix) if(myToLogCout) { switch(theLevel) { case ST_PANIC: ST_LOG_CERR << st::COLOR_FOR_RED << stostream_text("PANIC !! ") << st::COLOR_FOR_WHITE << theMessage << stostream_text('\n'); break; case ST_FATAL: ST_LOG_CERR << st::COLOR_FOR_RED << stostream_text("FATAL !! ") << st::COLOR_FOR_WHITE << theMessage << stostream_text('\n'); break; case ST_ERROR: ST_LOG_CERR << st::COLOR_FOR_RED << stostream_text("ERROR !! ") << st::COLOR_FOR_WHITE << theMessage << stostream_text('\n'); break; case ST_WARNING: ST_LOG_CERR << st::COLOR_FOR_YELLOW_L << stostream_text("WARN -- ") << st::COLOR_FOR_WHITE << theMessage << stostream_text('\n'); break; case ST_INFO: case ST_VERBOSE: ST_LOG_CERR << st::COLOR_FOR_YELLOW_L << stostream_text("INFO -- ") << st::COLOR_FOR_WHITE << theMessage << stostream_text('\n'); break; case ST_DEBUG: ST_LOG_CERR << st::COLOR_FOR_YELLOW_L << stostream_text("DEBUG -- ") << st::COLOR_FOR_WHITE << theMessage << stostream_text('\n'); break; default: ST_LOG_CERR << theMessage << stostream_text('\n'); break; } } // log to the system journal(s) /*#ifdef _WIN32 // get a handle to the event log HANDLE anEventLog = RegisterEventSource(NULL, // local computer L"sView"); // event source name if(anEventLog != NULL) { WORD aLogType = 0; switch(theLevel) { case ST_PANIC: case ST_FATAL: case ST_ERROR: aLogType = EVENTLOG_ERROR_TYPE; break; case ST_WARNING: aLogType = EVENTLOG_WARNING_TYPE; break; case ST_INFO: case ST_VERBOSE: case ST_DEBUG: default: aLogType = EVENTLOG_INFORMATION_TYPE; break; } ReportEvent(anEventLog, aLogType, 0, // event category 0, // event identifier NULL, // no user security identifier 1, // number of substitution strings 0, // no data (LPCWSTR* )&theMessage.utfText(), // pointer to strings NULL)) // no binary data DeregisterEventSource(anEventLog); } #endif*/ // unlock mutex if(!myMutex.isNull()) { myMutex->unlock(); } }
bool StMessageBox::Question(const StString& theMessage) { #ifdef _WIN32 return MessageBoxW(NULL, theMessage.toUtfWide().toCString(), L"Question", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES; #elif defined(__linux__) if(initGlobals()) { gdk_threads_enter(); GtkWidget* aDialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "%s", theMessage.toCString()); gint anAnswer = gtk_dialog_run(GTK_DIALOG(aDialog)); gtk_widget_destroy(aDialog); gdk_flush(); // we need this call! gdk_threads_leave(); return anAnswer == GTK_RESPONSE_YES; } return false; #endif }
bool StFreeImage::save(const StString& theFilePath, ImageType theImageType, StFormatEnum ) { if(!StFreeImage::init()) { setState("FreeImage library is not initialized"); return false; } FREE_IMAGE_FORMAT aFIF = convertToFIF(theImageType); if(aFIF == FIF_UNKNOWN) { setState("FreeImage library, not supported image file format"); return false; } StImage stSaveImage; if(getColorModel() != ImgColor_RGB && getColorModel() != ImgColor_RGBA && getColorModel() != ImgColor_GRAY) { // convert from YUV and so on if(!stSaveImage.initRGB(*this)) { setState("StFreeImage, only RGB image could be saved"); return false; } } else { stSaveImage.initWrapper(*this); } const StImagePlane& stImgPlane = stSaveImage.getPlane(); FREE_IMAGE_TYPE aSaveFormatFI = FIT_UNKNOWN; if(!convertToFreeFormat(stImgPlane.getFormat(), aSaveFormatFI)) { setState("StFreeImage, image format currently not supported"); return false; } // allocate FreeImage native structure FIBITMAP* aSaveDIB = FreeImage_AllocateT(aSaveFormatFI, (int )stImgPlane.getSizeX(), (int )stImgPlane.getSizeY(), (unsigned )stImgPlane.getSizePixelBytes() * 8, 0, 0, 0); if(aSaveDIB == NULL) { setState("FreeImage library, internal error"); FreeImage_Unload(aSaveDIB); return false; } // wrapper the created data StImagePlane stImgPlaneSave; StImagePlane::ImgFormat stImgFormatSave = convertFromFreeFormat(FreeImage_GetImageType(aSaveDIB), FreeImage_GetColorType(aSaveDIB), FreeImage_GetBPP(aSaveDIB)); stImgPlaneSave.initWrapper(stImgFormatSave, FreeImage_GetBits(aSaveDIB), FreeImage_GetWidth(aSaveDIB), FreeImage_GetHeight(aSaveDIB), FreeImage_GetPitch(aSaveDIB)); // FreeImage data should be bottom-up... stImgPlaneSave.setTopDown(false); // copy from local structure to the FreeImage structure size_t aRowInc = (( stImgPlaneSave.isTopDown() && stImgPlane.isTopDown()) || (!stImgPlaneSave.isTopDown() && !stImgPlane.isTopDown())) ? 1 : size_t(-1); size_t aRowTo = (aRowInc == 1) ? 0 : (stImgPlane.getSizeY() - 1); for(size_t aRowFrom = 0; aRowFrom < stImgPlane.getSizeY(); ++aRowFrom, aRowTo += aRowInc) { for(size_t aCol = 0; aCol < stImgPlane.getSizeX(); ++aCol) { stMemCpy(stImgPlaneSave.changeData(aRowTo, aCol), stImgPlane.getData(aRowFrom, aCol), stImgPlane.getSizePixelBytes()); } } // now save the image file! #if defined(_WIN32) if(!FreeImage_Save(aFIF, aSaveDIB, theFilePath.toUtfWide().toCString(), 0)) { #else if(!FreeImage_Save(aFIF, aSaveDIB, theFilePath.toCString(), 0)) { #endif setState("FreeImage library, image save failed"); FreeImage_Unload(aSaveDIB); return false; } // free resources FreeImage_Unload(aSaveDIB); // set debug information StString aDummy, aFileName; StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName); setState(StString("FreeImage library, saved image '") + aFileName + "' " + getDescription()); return true; } bool StFreeImage::resize(size_t , size_t ) { return false; }
bool StAVVideoMuxer::addFile(const StString& theFileToLoad) { StString aFileName, aDummy; StFileNode::getFolderAndFile(theFileToLoad, aDummy, aFileName); AVFormatContext* aFormatCtx = NULL; #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 2, 0)) int avErrCode = avformat_open_input(&aFormatCtx, theFileToLoad.toCString(), NULL, NULL); #else int avErrCode = av_open_input_file (&aFormatCtx, theFileToLoad.toCString(), NULL, 0, NULL); #endif if(avErrCode != 0) { signals.onError(StString("FFmpeg: Couldn't open video file '") + theFileToLoad + "'\nError: " + stAV::getAVErrorDescription(avErrCode)); if(aFormatCtx != NULL) { #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 17, 0)) avformat_close_input(&aFormatCtx); #else av_close_input_file(aFormatCtx); #endif } return false; } // retrieve stream information #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 6, 0)) if(avformat_find_stream_info(aFormatCtx, NULL) < 0) { #else if(av_find_stream_info(aFormatCtx) < 0) { #endif signals.onError(StString("FFmpeg: Couldn't find stream information in '") + theFileToLoad + "'"); if(aFormatCtx != NULL) { #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 17, 0)) avformat_close_input(&aFormatCtx); #else av_close_input_file(aFormatCtx); // close video file at all #endif } return false; } #ifdef ST_DEBUG #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 101, 0)) av_dump_format(aFormatCtx, 0, theFileToLoad.toCString(), false); #else dump_format (aFormatCtx, 0, theFileToLoad.toCString(), false); #endif #endif myCtxListSrc.add(aFormatCtx); return true; } class StAVOutContext { public: AVFormatContext* Context; /** * Empty constructor. */ StAVOutContext() : Context(NULL), myFormat(NULL) {} /** * Determine the format. */ bool findFormat(const char* theShortName, const char* theFilename, const char* theMimeType = NULL) { myFormat = av_guess_format(theShortName, theFilename, theMimeType); return myFormat != NULL; } /** * Create context. */ bool create(const StString& theFile) { if(myFormat == NULL) { return false; } #if !defined(ST_LIBAV_FORK) avformat_alloc_output_context2(&Context, myFormat, NULL, theFile.toCString()); #else Context = avformat_alloc_context(); if(Context == NULL) { return false; } Context->oformat = myFormat; if(Context->oformat->priv_data_size > 0) { Context->priv_data = av_mallocz(Context->oformat->priv_data_size); if(!Context->priv_data) { //goto nomem; } if(Context->oformat->priv_class) { *(const AVClass**)Context->priv_data = Context->oformat->priv_class; //av_opt_set_defaults(aCtxOut->priv_data); } } else { Context->priv_data = NULL; } const size_t aStrLen = stMin(theFile.Size + 1, size_t(1024)); stMemCpy(Context->filename, theFile.toCString(), aStrLen); Context->filename[1023] = '\0'; #endif return Context != NULL; } /** * Destructor. */ ~StAVOutContext() { if(Context == NULL) { return; } if(!(Context->oformat->flags & AVFMT_NOFILE)) { avio_close(Context->pb); } avformat_free_context(Context); } private: AVOutputFormat* myFormat; }; /** * Return string identifier for specified stereo format. */ const char* formatToMetadata(const StFormat theFormat) { switch(theFormat) { case StFormat_Mono: return "mono"; case StFormat_SideBySide_RL: return "right_left"; case StFormat_SideBySide_LR: return "left_right"; case StFormat_TopBottom_RL: return "bottom_top"; case StFormat_TopBottom_LR: return "top_bottom"; case StFormat_Rows: return "row_interleaved_lr"; case StFormat_Columns: return "col_interleaved_lr"; case StFormat_FrameSequence: return "block_lr"; case StFormat_AnaglyphRedCyan: return "anaglyph_cyan_red"; case StFormat_AnaglyphGreenMagenta: return "anaglyph_green_magenta"; case StFormat_AUTO: case StFormat_SeparateFrames: case StFormat_AnaglyphYellowBlue: case StFormat_Tiled4x: case StFormat_NB: return NULL; } return NULL; } bool StAVVideoMuxer::addStream(AVFormatContext* theContext, AVStream* theStream) { #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 0, 0)) AVStream* aStreamOut = avformat_new_stream(theContext, theStream->codec->codec); #else AVStream* aStreamOut = avformat_new_stream(theContext, (AVCodec* )theStream->codec->codec); #endif if(aStreamOut == NULL) { signals.onError(StString("Failed allocating output stream.")); return false; } if(avcodec_copy_context(aStreamOut->codec, theStream->codec) < 0) { signals.onError(StString("Failed to copy context from input to output stream codec context.")); return false; } av_dict_copy(&aStreamOut->metadata, theStream->metadata, AV_DICT_DONT_OVERWRITE); //#if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(54, 2, 100)) // myIsAttachedPic = (theStream->disposition & AV_DISPOSITION_ATTACHED_PIC) != 0; //#endif if(theStream->codec->codec_type == AVMEDIA_TYPE_VIDEO) { aStreamOut->sample_aspect_ratio = theStream->sample_aspect_ratio; aStreamOut->codec->sample_aspect_ratio = aStreamOut->sample_aspect_ratio; } if(theContext->oformat->flags & AVFMT_GLOBALHEADER) { aStreamOut->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; } return true; }
bool StAVVideoMuxer::save(const StString& theFile) { if(myCtxListSrc.isEmpty() || theFile.isEmpty()) { return false; } StString aFormatName = myCtxListSrc[0]->iformat->name; const char* aFormatStr = formatToMetadata(myStereoFormat); std::vector<StRemuxContext> aSrcCtxList; //StArrayList<StRemuxContext> aSrcCtxList; unsigned int aStreamCount = 0; StAVOutContext aCtxOut; if(!aCtxOut.findFormat(NULL, theFile.toCString())) { signals.onError(StString("Unable to find a suitable output format for '") + theFile + "'."); return false; } else if(!aCtxOut.create(theFile)) { signals.onError(StString("Could not create output context.")); return false; } for(size_t aCtxId = 0; aCtxId < myCtxListSrc.size(); ++aCtxId) { StRemuxContext aCtxSrc; aCtxSrc.Context = myCtxListSrc[aCtxId]; if(aCtxId == 0) { av_dict_copy(&aCtxOut.Context->metadata, aCtxSrc.Context->metadata, AV_DICT_DONT_OVERWRITE); av_dict_set(&aCtxOut.Context->metadata, "STEREO_MODE", aFormatStr, 0); } for(unsigned int aStreamId = 0; aStreamId < aCtxSrc.Context->nb_streams; ++aStreamId) { aCtxSrc.Streams.add((unsigned int )-1); AVStream* aStreamSrc = aCtxSrc.Context->streams[aStreamId]; if(aStreamSrc->codec->codec_type == AVMEDIA_TYPE_VIDEO) { if(addStream(aCtxOut.Context, aStreamSrc)) { aCtxSrc.Streams[aStreamId] = aStreamCount++; } } } aSrcCtxList.push_back(aCtxSrc); } // add audio streams after video for(size_t aCtxId = 0; aCtxId < myCtxListSrc.size(); ++aCtxId) { StRemuxContext& aCtxSrc = aSrcCtxList[aCtxId]; for(unsigned int aStreamId = 0; aStreamId < aCtxSrc.Context->nb_streams; ++aStreamId) { AVStream* aStreamSrc = aCtxSrc.Context->streams[aStreamId]; if(aStreamSrc->codec->codec_type == AVMEDIA_TYPE_AUDIO && addStream(aCtxOut.Context, aStreamSrc)) { aCtxSrc.Streams[aStreamId] = aStreamCount++; } } } // add other streams (subtitles) at the end for(size_t aCtxId = 0; aCtxId < myCtxListSrc.size(); ++aCtxId) { StRemuxContext& aCtxSrc = aSrcCtxList[aCtxId]; for(unsigned int aStreamId = 0; aStreamId < aCtxSrc.Context->nb_streams; ++aStreamId) { AVStream* aStreamSrc = aCtxSrc.Context->streams[aStreamId]; if(aStreamSrc->codec->codec_type != AVMEDIA_TYPE_VIDEO && aStreamSrc->codec->codec_type != AVMEDIA_TYPE_AUDIO && addStream(aCtxOut.Context, aStreamSrc)) { aCtxSrc.Streams[aStreamId] = aStreamCount++; } } } av_dump_format(aCtxOut.Context, 0, theFile.toCString(), 1); if(!(aCtxOut.Context->oformat->flags & AVFMT_NOFILE)) { const int aState = avio_open2(&aCtxOut.Context->pb, theFile.toCString(), AVIO_FLAG_WRITE, NULL, NULL); if(aState < 0) { signals.onError(StString("Could not open output file '") + theFile + "' (" + stAV::getAVErrorDescription(aState) + ")"); return false; } } int aState = avformat_write_header(aCtxOut.Context, NULL); if(aState < 0) { signals.onError(StString("Error occurred when opening output file (") + stAV::getAVErrorDescription(aState) + ")."); return false; } AVPacket aPacket; for(;;) { size_t aNbEmpty = 0; for(size_t aCtxId = 0; aCtxId < aSrcCtxList.size(); ++aCtxId) { StRemuxContext& aCtxSrc = aSrcCtxList[aCtxId]; if(!aCtxSrc.State) { ++aNbEmpty; continue; } if(av_read_frame(aCtxSrc.Context, &aPacket) < 0) { aCtxSrc.State = false; ++aNbEmpty; continue; } unsigned int aStreamOutIndex = aCtxSrc.Streams[aPacket.stream_index]; if(aStreamOutIndex == (unsigned int )-1) { continue; } AVStream* aStreamIn = aCtxSrc.Context->streams[aPacket.stream_index]; AVStream* aStreamOut = aCtxOut.Context->streams[aStreamOutIndex]; #ifdef ST_LIBAV_FORK const AVRounding aRoundParams = AV_ROUND_NEAR_INF; #else const AVRounding aRoundParams = AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); #endif aPacket.pts = av_rescale_q_rnd(aPacket.pts, aStreamIn->time_base, aStreamOut->time_base, aRoundParams); aPacket.dts = av_rescale_q_rnd(aPacket.dts, aStreamIn->time_base, aStreamOut->time_base, aRoundParams); aPacket.duration = static_cast<int >(av_rescale_q(aPacket.duration, aStreamIn->time_base, aStreamOut->time_base)); aPacket.pos = -1; aState = av_interleaved_write_frame(aCtxOut.Context, &aPacket); if(aState < 0) { signals.onError(StString("Error muxing packet (") + stAV::getAVErrorDescription(aState) + ")."); return false; } av_free_packet(&aPacket); } if(aNbEmpty == aSrcCtxList.size()) { break; } } av_write_trailer(aCtxOut.Context); return true; }
bool StProcess::execProcess(const StString& theExecutablePath, const StArray<StString>& theArguments) { if(!StFileNode::isFileExists(theExecutablePath)) { return false; } #ifdef _WIN32 // convert to wide strings StStringUtfWide anExecutablePathW = theExecutablePath.toUtfWide(); StArrayList<StStringUtfWide> anArgumentsW(theArguments.size()); StStringUtfWide aSplitter = ' '; StStringUtfWide aCmdLineW = StStringUtfWide('\"') + anExecutablePathW + StStringUtfWide("\" "); for(size_t anElem = 0;;) { // TODO (Kirill Gavrilov#9) we should probably quote arguments with spaces... // how to correctly deal this in the same way for UNIX / Windows? aCmdLineW += theArguments[anElem++].toUtfWide(); if(anElem >= theArguments.size()) { break; } aCmdLineW += aSplitter; } STARTUPINFOW aStartInfo; PROCESS_INFORMATION aProcessInfo; stMemSet(&aStartInfo, 0, sizeof(aStartInfo)); aStartInfo.cb = sizeof(aStartInfo); stMemSet(&aProcessInfo, 0, sizeof(aProcessInfo)); // start the process if(!CreateProcessW(anExecutablePathW.toCString(), (wchar_t* )aCmdLineW.toCString(), NULL, NULL, FALSE, 0, NULL, NULL, &aStartInfo, &aProcessInfo)) { return false; } // close process and thread handles CloseHandle(aProcessInfo.hProcess); CloseHandle(aProcessInfo.hThread); return true; #else char** anArgList = new char*[theArguments.size() + 2]; anArgList[0] = (char* )theExecutablePath.toCString(); for(size_t anArgId = 0; anArgId < theArguments.size(); ++anArgId) { anArgList[anArgId + 1] = (char* )theArguments.getValue(anArgId).toCString(); } anArgList[theArguments.size() + 1] = NULL; pid_t aChildPid = vfork(); if(aChildPid == -1) { // fork fail delete[] anArgList; return false; } else if(aChildPid != 0) { // parent process give the control only after child // calls exit() or exec() functions delete[] anArgList; return true; } // child process execv(theExecutablePath.toCString(), anArgList); // fail _exit(1); #endif }
bool StAVImage::load(const StString& theFilePath, ImageType theImageType, uint8_t* theDataPtr, int theDataSize) { // reset current data StImage::nullify(); setState(); close(); myMetadata.clear(); switch(theImageType) { case ST_TYPE_PNG: case ST_TYPE_PNS: { myCodec = avcodec_find_decoder_by_name("png"); break; } case ST_TYPE_JPEG: case ST_TYPE_MPO: case ST_TYPE_JPS: { myCodec = avcodec_find_decoder_by_name("mjpeg"); break; } case ST_TYPE_EXR: { myCodec = avcodec_find_decoder_by_name("exr"); break; } case ST_TYPE_WEBP: case ST_TYPE_WEBPLL: { myCodec = avcodec_find_decoder_by_name("webp"); break; } default: { break; } } if(theImageType == ST_TYPE_NONE || (theDataPtr == NULL && !StFileNode::isFileExists(theFilePath))) { // open image file and detect its type, its could be non local file! #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 2, 0)) int avErrCode = avformat_open_input(&myFormatCtx, theFilePath.toCString(), myImageFormat, NULL); #else int avErrCode = av_open_input_file (&myFormatCtx, theFilePath.toCString(), myImageFormat, 0, NULL); #endif if(avErrCode != 0 || myFormatCtx->nb_streams < 1 || myFormatCtx->streams[0]->codec->codec_id == 0) { if(myFormatCtx != NULL) { #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 17, 0)) avformat_close_input(&myFormatCtx); #else av_close_input_file(myFormatCtx); myFormatCtx = NULL; #endif } #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 2, 0)) avErrCode = avformat_open_input(&myFormatCtx, theFilePath.toCString(), NULL, NULL); #else avErrCode = av_open_input_file(&myFormatCtx, theFilePath.toCString(), NULL, 0, NULL); #endif } if(avErrCode != 0 || myFormatCtx->nb_streams < 1) { setState(StString("AVFormat library, couldn't open image file. Error: ") + stAV::getAVErrorDescription(avErrCode)); close(); return false; } // find the decoder for the video stream myCodecCtx = myFormatCtx->streams[0]->codec; if(theImageType == ST_TYPE_NONE) { myCodec = avcodec_find_decoder(myCodecCtx->codec_id); } } if(myCodec == NULL) { setState("AVCodec library, video codec not found"); close(); return false; } else if(myFormatCtx == NULL) { // use given image type to load decoder #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) myCodecCtx = avcodec_alloc_context3(myCodec); #else myCodecCtx = avcodec_alloc_context(); #endif } // stupid check if(myCodecCtx == NULL) { setState("AVCodec library, codec context is NULL"); close(); return false; } // open VIDEO codec #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) if(avcodec_open2(myCodecCtx, myCodec, NULL) < 0) { #else if(avcodec_open(myCodecCtx, myCodec) < 0) { #endif setState("AVCodec library, could not open video codec"); close(); return false; } // read one packet or file StRawFile aRawFile(theFilePath); StAVPacket anAvPkt; if(theDataPtr != NULL && theDataSize != 0) { anAvPkt.getAVpkt()->data = theDataPtr; anAvPkt.getAVpkt()->size = theDataSize; } else { if(myFormatCtx != NULL) { if(av_read_frame(myFormatCtx, anAvPkt.getAVpkt()) < 0) { setState("AVFormat library, could not read first packet"); close(); return false; } } else { if(!aRawFile.readFile()) { setState("StAVImage, could not read the file"); close(); return false; } anAvPkt.getAVpkt()->data = (uint8_t* )aRawFile.getBuffer(); anAvPkt.getAVpkt()->size = (int )aRawFile.getSize(); } } anAvPkt.setKeyFrame(); // decode one frame int isFrameFinished = 0; #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 23, 0)) avcodec_decode_video2(myCodecCtx, myFrame.Frame, &isFrameFinished, anAvPkt.getAVpkt()); #else avcodec_decode_video(myCodecCtx, myFrame.Frame, &isFrameFinished, theDataPtr, theDataSize); #endif if(isFrameFinished == 0) { // thats not an image!!! try to decode more packets??? setState("AVCodec library, input file is not an Image!"); close(); return false; } // check frame size if(myCodecCtx->width <= 0 || myCodecCtx->height <= 0) { setState("AVCodec library, codec returns wrong frame size"); close(); return false; } // read aspect ratio if(myCodecCtx->sample_aspect_ratio.num == 0 || myCodecCtx->sample_aspect_ratio.den == 0) { setPixelRatio(1.0f); } else { const GLfloat aRatio = GLfloat(myCodecCtx->sample_aspect_ratio.num) / GLfloat(myCodecCtx->sample_aspect_ratio.den); if(aRatio > 70.0f) { ST_DEBUG_LOG("AVCodec library, igning wrong PAR " + myCodecCtx->sample_aspect_ratio.num + ":" + myCodecCtx->sample_aspect_ratio.den); setPixelRatio(1.0f); } else { setPixelRatio(aRatio); } } #ifdef ST_AV_NEWSTEREO // currently it is unlikelly... but maybe in future? AVFrameSideData* aSideData = av_frame_get_side_data(myFrame.Frame, AV_FRAME_DATA_STEREO3D); if(aSideData != NULL) { AVStereo3D* aStereo = (AVStereo3D* )aSideData->data; mySrcFormat = stAV::stereo3dAvToSt(aStereo->type); if(aStereo->flags & AV_STEREO3D_FLAG_INVERT) { mySrcFormat = st::formatReversed(mySrcFormat); } } else { mySrcFormat = StFormat_AUTO; } #endif // it is unlikely that there would be any metadata from format... // but lets try if(myFormatCtx != NULL) { for(stAV::meta::Tag* aTag = stAV::meta::findTag(myFormatCtx->metadata, "", NULL, stAV::meta::SEARCH_IGNORE_SUFFIX); aTag != NULL; aTag = stAV::meta::findTag(myFormatCtx->metadata, "", aTag, stAV::meta::SEARCH_IGNORE_SUFFIX)) { myMetadata.add(StDictEntry(aTag->key, aTag->value)); } for(stAV::meta::Tag* aTag = stAV::meta::findTag(myFormatCtx->streams[0]->metadata, "", NULL, stAV::meta::SEARCH_IGNORE_SUFFIX); aTag != NULL; aTag = stAV::meta::findTag(myFormatCtx->streams[0]->metadata, "", aTag, stAV::meta::SEARCH_IGNORE_SUFFIX)) { myMetadata.add(StDictEntry(aTag->key, aTag->value)); } } // collect metadata from the frame stAV::meta::Dict* aFrameMetadata = stAV::meta::getFrameMetadata(myFrame.Frame); for(stAV::meta::Tag* aTag = stAV::meta::findTag(aFrameMetadata, "", NULL, stAV::meta::SEARCH_IGNORE_SUFFIX); aTag != NULL; aTag = stAV::meta::findTag(aFrameMetadata, "", aTag, stAV::meta::SEARCH_IGNORE_SUFFIX)) { myMetadata.add(StDictEntry(aTag->key, aTag->value)); } stAV::dimYUV aDimsYUV; if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGB24) { setColorModel(StImage::ImgColor_RGB); changePlane(0).initWrapper(StImagePlane::ImgRGB, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::BGR24) { setColorModel(StImage::ImgColor_RGB); changePlane(0).initWrapper(StImagePlane::ImgBGR, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGBA32) { setColorModel(StImage::ImgColor_RGBA); changePlane(0).initWrapper(StImagePlane::ImgRGBA, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::BGRA32) { setColorModel(StImage::ImgColor_RGBA); changePlane(0).initWrapper(StImagePlane::ImgBGRA, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::GRAY8) { setColorModel(StImage::ImgColor_GRAY); changePlane(0).initWrapper(StImagePlane::ImgGray, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::GRAY16) { setColorModel(StImage::ImgColor_GRAY); changePlane(0).initWrapper(StImagePlane::ImgGray16, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGB48) { setColorModel(StImage::ImgColor_RGB); changePlane(0).initWrapper(StImagePlane::ImgRGB48, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGBA64) { setColorModel(StImage::ImgColor_RGBA); changePlane(0).initWrapper(StImagePlane::ImgRGBA64, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(stAV::isFormatYUVPlanar(myCodecCtx, aDimsYUV)) { #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 29, 0)) if(myCodecCtx->color_range == AVCOL_RANGE_JPEG) { aDimsYUV.isFullScale = true; } #endif setColorModel(StImage::ImgColor_YUV); setColorScale(aDimsYUV.isFullScale ? StImage::ImgScale_Full : StImage::ImgScale_Mpeg); StImagePlane::ImgFormat aPlaneFrmt = StImagePlane::ImgGray; if(aDimsYUV.bitsPerComp == 9) { aPlaneFrmt = StImagePlane::ImgGray16; setColorScale(aDimsYUV.isFullScale ? StImage::ImgScale_Jpeg9 : StImage::ImgScale_Mpeg9); } else if(aDimsYUV.bitsPerComp == 10) { aPlaneFrmt = StImagePlane::ImgGray16; setColorScale(aDimsYUV.isFullScale ? StImage::ImgScale_Jpeg10 : StImage::ImgScale_Mpeg10); } else if(aDimsYUV.bitsPerComp == 16) { aPlaneFrmt = StImagePlane::ImgGray16; } changePlane(0).initWrapper(aPlaneFrmt, myFrame.getPlane(0), size_t(aDimsYUV.widthY), size_t(aDimsYUV.heightY), myFrame.getLineSize(0)); changePlane(1).initWrapper(aPlaneFrmt, myFrame.getPlane(1), size_t(aDimsYUV.widthU), size_t(aDimsYUV.heightU), myFrame.getLineSize(1)); changePlane(2).initWrapper(aPlaneFrmt, myFrame.getPlane(2), size_t(aDimsYUV.widthV), size_t(aDimsYUV.heightV), myFrame.getLineSize(2)); } else { ///ST_DEBUG_LOG("StAVImage, perform conversion from Pixel format '" + avcodec_get_pix_fmt_name(myCodecCtx->pix_fmt) + "' to RGB"); // initialize software scaler/converter SwsContext* pToRgbCtx = sws_getContext(myCodecCtx->width, myCodecCtx->height, myCodecCtx->pix_fmt, // source myCodecCtx->width, myCodecCtx->height, stAV::PIX_FMT::RGB24, // destination SWS_BICUBIC, NULL, NULL, NULL); if(pToRgbCtx == NULL) { setState("SWScale library, failed to create SWScaler context"); close(); return false; } // initialize additional buffer for converted RGB data setColorModel(StImage::ImgColor_RGB); changePlane(0).initTrash(StImagePlane::ImgRGB, myCodecCtx->width, myCodecCtx->height); uint8_t* rgbData[4]; stMemZero(rgbData, sizeof(rgbData)); int rgbLinesize[4]; stMemZero(rgbLinesize, sizeof(rgbLinesize)); rgbData[0] = changePlane(0).changeData(); rgbLinesize[0] = (int )changePlane(0).getSizeRowBytes(); sws_scale(pToRgbCtx, myFrame.Frame->data, myFrame.Frame->linesize, 0, myCodecCtx->height, rgbData, rgbLinesize); // reset original data closeAvCtx(); sws_freeContext(pToRgbCtx); } // set debug information StString aDummy, aFileName; StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName); setState(StString("AVCodec library, loaded image '") + aFileName + "' " + getDescription()); // we should not close the file because decoded image data is in codec context cache return true; } bool StAVImage::save(const StString& theFilePath, ImageType theImageType, StFormat theSrcFormat) { close(); setState(); if(isNull()) { return false; } PixelFormat aPFormatAV = (PixelFormat )getAVPixelFormat(*this); StImage anImage; switch(theImageType) { case ST_TYPE_PNG: case ST_TYPE_PNS: { myCodec = avcodec_find_encoder_by_name("png"); if(myCodec == NULL) { setState("AVCodec library, video codec 'png' not found"); close(); return false; } if(aPFormatAV == stAV::PIX_FMT::RGB24 || aPFormatAV == stAV::PIX_FMT::RGBA32 || aPFormatAV == stAV::PIX_FMT::GRAY8) { anImage.initWrapper(*this); } else { // convert to compatible pixel format anImage.changePlane().initTrash(StImagePlane::ImgRGB, getSizeX(), getSizeY(), getAligned(getSizeX() * 3)); PixelFormat aPFrmtTarget = stAV::PIX_FMT::RGB24; if(!convert(*this, aPFormatAV, anImage, aPFrmtTarget)) { setState("SWScale library, failed to create SWScaler context"); close(); return false; } aPFormatAV = aPFrmtTarget; } #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) myCodecCtx = avcodec_alloc_context3(myCodec); #else myCodecCtx = avcodec_alloc_context(); #endif // setup encoder myCodecCtx->pix_fmt = aPFormatAV; myCodecCtx->width = (int )anImage.getSizeX(); myCodecCtx->height = (int )anImage.getSizeY(); myCodecCtx->compression_level = 9; // 0..9 break; } case ST_TYPE_JPEG: case ST_TYPE_MPO: case ST_TYPE_JPS: { myCodec = avcodec_find_encoder_by_name("mjpeg"); if(myCodec == NULL) { setState("AVCodec library, video codec 'mjpeg' not found"); close(); return false; } if(aPFormatAV == stAV::PIX_FMT::YUVJ420P || aPFormatAV == stAV::PIX_FMT::YUVJ422P //|| aPFormatAV == stAV::PIX_FMT::YUVJ444P not supported by FFmpeg... yet? //|| aPFormatAV == stAV::PIX_FMT::YUVJ440P ) { anImage.initWrapper(*this); } else { // convert to compatible pixel format PixelFormat aPFrmtTarget = aPFormatAV == stAV::PIX_FMT::YUV420P ? stAV::PIX_FMT::YUVJ420P : stAV::PIX_FMT::YUVJ422P; anImage.setColorModel(StImage::ImgColor_YUV); anImage.setColorScale(StImage::ImgScale_Mpeg); anImage.changePlane(0).initTrash(StImagePlane::ImgGray, getSizeX(), getSizeY(), getAligned(getSizeX())); stMemSet(anImage.changePlane(0).changeData(), '\0', anImage.getPlane(0).getSizeBytes()); anImage.changePlane(1).initTrash(StImagePlane::ImgGray, getSizeX(), getSizeY(), getAligned(getSizeX())); stMemSet(anImage.changePlane(1).changeData(), '\0', anImage.getPlane(1).getSizeBytes()); anImage.changePlane(2).initTrash(StImagePlane::ImgGray, getSizeX(), getSizeY(), getAligned(getSizeX())); stMemSet(anImage.changePlane(2).changeData(), '\0', anImage.getPlane(2).getSizeBytes()); if(!convert(*this, aPFormatAV, anImage, aPFrmtTarget)) { setState("SWScale library, failed to create SWScaler context"); close(); return false; } aPFormatAV = aPFrmtTarget; } #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) myCodecCtx = avcodec_alloc_context3(myCodec); #else myCodecCtx = avcodec_alloc_context(); #endif myCodecCtx->pix_fmt = aPFormatAV; myCodecCtx->width = (int )anImage.getSizeX(); myCodecCtx->height = (int )anImage.getSizeY(); myCodecCtx->time_base.num = 1; myCodecCtx->time_base.den = 1; myCodecCtx->qmin = myCodecCtx->qmax = 5; // quality factor - lesser is better break; } case ST_TYPE_NONE: default: close(); return false; } // open VIDEO codec #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) if(avcodec_open2(myCodecCtx, myCodec, NULL) < 0) { #else if(avcodec_open(myCodecCtx, myCodec) < 0) { #endif setState("AVCodec library, could not open video codec"); close(); return false; } // wrap own data into AVFrame myFrame.Frame->format = myCodecCtx->pix_fmt; myFrame.Frame->width = myCodecCtx->width; myFrame.Frame->height = myCodecCtx->height; fillPointersAV(anImage, myFrame.Frame->data, myFrame.Frame->linesize); #ifdef ST_AV_NEWSTEREO bool isReversed = false; AVStereo3DType anAvStereoType = stAV::stereo3dStToAv(theSrcFormat, isReversed); if(anAvStereoType != (AVStereo3DType )-1) { AVStereo3D* aStereo = av_stereo3d_create_side_data(myFrame.Frame); if(aStereo != NULL) { aStereo->type = anAvStereoType; if(isReversed) { aStereo->flags |= AV_STEREO3D_FLAG_INVERT; } } } #endif StJpegParser aRawFile(theFilePath); if(!aRawFile.openFile(StRawFile::WRITE)) { setState("Can not open the file for writing"); close(); return false; } // allocate the buffer, large enough (stupid formula copied from ffmpeg.c) int aBuffSize = int(getSizeX() * getSizeY() * 10); aRawFile.initBuffer(aBuffSize); // encode the image StAVPacket aPacket; aPacket.getAVpkt()->data = (uint8_t* )aRawFile.changeBuffer(); aPacket.getAVpkt()->size = aBuffSize; #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 2, 100)) int isGotPacket = 0; int anEncSize = avcodec_encode_video2(myCodecCtx, aPacket.getAVpkt(), myFrame.Frame, &isGotPacket); if(anEncSize == 0 && isGotPacket != 0) { anEncSize = aPacket.getSize(); } #else int anEncSize = avcodec_encode_video(myCodecCtx, aPacket.changeData(), aPacket.getSize(), myFrame.Frame); #endif if(anEncSize <= 0) { setState("AVCodec library, fail to encode the image"); close(); return false; } aRawFile.setDataSize((size_t )anEncSize); // save metadata when possible if(theImageType == ST_TYPE_JPEG || theImageType == ST_TYPE_JPS) { if(aRawFile.parse()) { if(theSrcFormat != StFormat_AUTO) { aRawFile.setupJps(theSrcFormat); } } else { ST_ERROR_LOG("AVCodec library, created JPEG can not be parsed!"); } } // store current content aRawFile.writeFile(); // and finally close the file handle aRawFile.closeFile(); close(); // set debug information StString aDummy, aFileName; StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName); setState(StString("AVCodec library, saved image '") + aFileName + "' " + getDescription()); return true; }
// function create GUI window bool StWindowImpl::create() { myKeysState.reset(); // replace default XError handler to ignore some errors XSetErrorHandler(stXErrorHandler); myInitState = STWIN_INITNOTSTART; // X-server implementation // create window on unix systems throw X-server int dummy; // open a connection to the X server StXDisplayH stXDisplay = new StXDisplay(); if(!stXDisplay->isOpened()) { stXDisplay.nullify(); stError("X, could not open display"); myInitState = STWIN_ERROR_X_OPENDISPLAY; return false; } myMaster.stXDisplay = stXDisplay; Display* hDisplay = stXDisplay->hDisplay; #if defined(ST_HAVE_EGL) myMaster.hRC = new StWinGlrc(eglGetDisplay(hDisplay), attribs.IsGlDebug, attribs.GlDepthSize); if(!myMaster.hRC->isValid()) { myMaster.close(); mySlave.close(); myInitState = STWIN_ERROR_X_GLRC_CREATE; return false; } XVisualInfo aVisInfo; aVisInfo.visualid = 0; if (eglGetConfigAttrib(myMaster.hRC->getDisplay(), myMaster.hRC->getConfig(), EGL_NATIVE_VISUAL_ID, (EGLint* )&aVisInfo.visualid) != EGL_TRUE) { myMaster.close(); mySlave.close(); myInitState = STWIN_ERROR_X_GLRC_CREATE; return false; } int aNbVisuals = 0; stXDisplay->hVisInfo = XGetVisualInfo(hDisplay, VisualIDMask, &aVisInfo, &aNbVisuals); #else // GLX // make sure OpenGL's GLX extension supported if(!glXQueryExtension(hDisplay, &dummy, &dummy)) { myMaster.close(); stError("X, server has no OpenGL GLX extension"); myInitState = STWIN_ERROR_X_NOGLX; return false; } int anAttribsBuff[] = { GLX_STEREO, attribs.IsGlStereo ? True : False, GLX_X_RENDERABLE, True, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 0, GLX_DEPTH_SIZE, attribs.GlDepthSize, GLX_STENCIL_SIZE, 0, GLX_DOUBLEBUFFER, True, //GLX_SAMPLE_BUFFERS, 1, //GLX_SAMPLES, 4, None }; // FBConfigs were added in GLX version 1.3 int aGlxMajor = 0; int aGlxMinor = 0; const bool hasFBCfg = glXQueryVersion(hDisplay, &aGlxMajor, &aGlxMinor) && ((aGlxMajor == 1 && aGlxMinor >= 3) || (aGlxMajor > 1)); int aFBCount = 0; GLXFBConfig* aFBCfgList = NULL; if(hasFBCfg) { aFBCfgList = glXChooseFBConfig(hDisplay, DefaultScreen(hDisplay), anAttribsBuff, &aFBCount); } if(aFBCfgList == NULL && hasFBCfg && attribs.IsGlStereo) { ST_ERROR_LOG("X, no Quad Buffered visual"); anAttribsBuff[1] = False; aFBCfgList = glXChooseFBConfig(hDisplay, DefaultScreen(hDisplay), anAttribsBuff, &aFBCount); } if(aFBCfgList != NULL && aFBCount >= 1) { stXDisplay->FBCfg = aFBCfgList[0]; stXDisplay->hVisInfo = glXGetVisualFromFBConfig(hDisplay, stXDisplay->FBCfg); } else { // try to use glXChooseVisual... pointless? int aDblBuff[] = { GLX_RGBA, GLX_DEPTH_SIZE, attribs.GlDepthSize, GLX_DOUBLEBUFFER, None }; if(attribs.IsGlStereo) { // find an appropriate visual int aQuadBuff[] = { GLX_RGBA, GLX_DEPTH_SIZE, attribs.GlDepthSize, GLX_DOUBLEBUFFER, GLX_STEREO, None }; stXDisplay->hVisInfo = glXChooseVisual(hDisplay, DefaultScreen(hDisplay), aQuadBuff); if(stXDisplay->hVisInfo == NULL) { ST_ERROR_LOG("X, no Quad Buffered visual"); stXDisplay->hVisInfo = glXChooseVisual(hDisplay, DefaultScreen(hDisplay), aDblBuff); if(stXDisplay->hVisInfo == NULL) { myMaster.close(); stError("X, no RGB visual with depth buffer"); myInitState = STWIN_ERROR_X_NORGB; return false; } } } else { // find an appropriate visual // find an OpenGL-capable RGB visual with depth buffer stXDisplay->hVisInfo = glXChooseVisual(hDisplay, DefaultScreen(hDisplay), aDblBuff); if(stXDisplay->hVisInfo == NULL) { myMaster.close(); stError("X, no RGB visual with depth buffer"); myInitState = STWIN_ERROR_X_NORGB; return false; } } } XFree(aFBCfgList); #endif if(attribs.Slave != StWinSlave_slaveOff) { // just copy handle mySlave.stXDisplay = stXDisplay; } // create an X window with the selected visual XSetWindowAttributes aWinAttribsX = createDefaultAttribs(stXDisplay); updateChildRect(); Window aParentWin = (Window )myParentWin; if(aParentWin == 0 && !attribs.IsNoDecor) { aWinAttribsX.override_redirect = False; myMaster.hWindow = XCreateWindow(hDisplay, stXDisplay->getRootWindow(), myRectNorm.left(), myRectNorm.top(), myRectNorm.width(), myRectNorm.height(), 0, stXDisplay->getDepth(), InputOutput, stXDisplay->getVisual(), CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttribsX); if(myMaster.hWindow == 0) { myMaster.close(); stError("X, XCreateWindow failed for Master"); myInitState = STWIN_ERROR_X_CREATEWIN; return false; } aParentWin = myMaster.hWindow; XSetStandardProperties(hDisplay, myMaster.hWindow, myWindowTitle.toCString(), myWindowTitle.toCString(), None, NULL, 0, NULL); // setup WM_CLASS in sync with .desktop StartupWMClass entity // to ensure Window Manager would show an propriate icon for application XClassHint* aClassHint = XAllocClassHint(); if(aClassHint != NULL) { StString aName = StProcess::getProcessName(); StString aClass("sView"); // const_cast should be harmless here and it seems to be just broken signature of XClassHint structure aClassHint->res_name = const_cast<char* >(aName.toCString()); aClassHint->res_class = const_cast<char* >(aClass.toCString()); XSetClassHint(hDisplay, myMaster.hWindow, aClassHint); XFree(aClassHint); } } aWinAttribsX.override_redirect = True; // GL window always undecorated myMaster.hWindowGl = XCreateWindow(hDisplay, (aParentWin != 0) ? aParentWin : stXDisplay->getRootWindow(), 0, 0, myRectNorm.width(), myRectNorm.height(), 0, stXDisplay->getDepth(), InputOutput, stXDisplay->getVisual(), CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttribsX); if(myMaster.hWindowGl == 0) { myMaster.close(); stError("X, XCreateWindow failed for Master"); myInitState = STWIN_ERROR_X_CREATEWIN; return false; } XSetStandardProperties(hDisplay, myMaster.hWindowGl, "master window", "master window", None, NULL, 0, NULL); if(attribs.Slave != StWinSlave_slaveOff) { aWinAttribsX.event_mask = NoEventMask; // we do not parse any events to slave window! aWinAttribsX.override_redirect = True; // slave window always undecorated mySlave.hWindowGl = XCreateWindow(hDisplay, stXDisplay->getRootWindow(), getSlaveLeft(), getSlaveTop(), getSlaveWidth(), getSlaveHeight(), 0, stXDisplay->getDepth(), InputOutput, stXDisplay->getVisual(), CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttribsX); if(mySlave.hWindowGl == 0) { myMaster.close(); mySlave.close(); stError("X, XCreateWindow failed for Slave"); myInitState = STWIN_ERROR_X_CREATEWIN; return false; } XSetStandardProperties(hDisplay, mySlave.hWindowGl, "slave window", "slave window", None, NULL, 0, NULL); } int isGlCtx = myMaster.glCreateContext(attribs.Slave != StWinSlave_slaveOff ? &mySlave : NULL, myRectNorm, attribs.GlDepthSize, attribs.IsGlStereo, attribs.IsGlDebug); if(isGlCtx != STWIN_INIT_SUCCESS) { myMaster.close(); mySlave.close(); myInitState = isGlCtx; return false; } myGlContext = new StGLContext(myResMgr); if(!myGlContext->stglInit()) { myMaster.close(); mySlave.close(); stError("Critical error - broken GL context!\nInvalid OpenGL driver?"); myInitState = STWIN_ERROR_X_GLRC_CREATE; return false; } // handle close window event if(myMaster.hWindow != 0) { XSetWMProtocols(hDisplay, myMaster.hWindow, &(stXDisplay->wndDestroyAtom), 1); } // Announce XDND support myMaster.setupXDND(); // Initialize XRandr events reception if(XRRQueryExtension(hDisplay, &myMaster.xrandrEventBase, &dummy)) { XRRSelectInput(hDisplay, stXDisplay->getRootWindow(), RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputPropertyNotifyMask); myMaster.isRecXRandrEvents = true; } else { myMaster.isRecXRandrEvents = false; } // request the X window to be displayed on the screen if(attribs.Slave != StWinSlave_slaveOff) { // request the X window to be displayed on the screen if(!attribs.IsSlaveHidden && (!isSlaveIndependent() || myMonitors.size() > 1)) { XMapWindow(hDisplay, mySlave.hWindowGl); //XIfEvent(hDisplay, &myXEvent, stXWaitMapped, (char* )mySlave.hWindowGl); } // always hise mouse cursor on slave window mySlave.setupNoCursor(); } if(!attribs.IsHidden) { if(myMaster.hWindow != 0) { XMapWindow(hDisplay, myMaster.hWindow); //XIfEvent(hDisplay, &myXEvent, stXWaitMapped, (char* )myMaster.hWindow); } XMapWindow(hDisplay, myMaster.hWindowGl); //XIfEvent(hDisplay, &myXEvent, stXWaitMapped, (char* )myMaster.hWindowGl); } // setup default icon if((Window )myParentWin == 0) { XpmCreatePixmapFromData(hDisplay, myMaster.hWindow, (char** )sview_xpm, &myMaster.iconImage, &myMaster.iconShape, NULL); XWMHints anIconHints; anIconHints.flags = IconPixmapHint | IconMaskHint; anIconHints.icon_pixmap = myMaster.iconImage; anIconHints.icon_mask = myMaster.iconShape; XSetWMHints(hDisplay, myMaster.hWindow, &anIconHints); } // we need this call to go around bugs if(!attribs.IsFullScreen && myMaster.hWindow != 0) { XMoveResizeWindow(hDisplay, myMaster.hWindow, myRectNorm.left(), myRectNorm.top(), myRectNorm.width(), myRectNorm.height()); } // flushes the output buffer, most client apps needn't use this cause buffer is automatically flushed as needed by calls to XNextEvent()... XFlush(hDisplay); myMonitors.registerUpdater(true); myIsUpdated = true; myInitState = STWIN_INIT_SUCCESS; return true; }
void StMessageBox::Error(const StString& theMessage) { StLogger::GetDefault().write(theMessage, StLogger::ST_ERROR); #ifdef _WIN32 MessageBoxW(NULL, theMessage.toUtfWide().toCString(), L"Error", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST); #elif defined(__linux__) if(initGlobals()) { gdk_threads_enter(); GtkWidget* dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", theMessage.toCString()); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); gdk_flush(); // we need this call! gdk_threads_leave(); } #endif }
bool StFreeImage::load(const StString& theFilePath, ImageType theImageType, uint8_t* theDataPtr, int theDataSize) { if(!StFreeImage::init()) { setState("FreeImage library is not initialized"); return false; } // reset current data StImage::nullify(); setState(); close(); FREE_IMAGE_FORMAT aFIF = convertToFIF(theImageType); if(theDataPtr != NULL && theDataSize != 0 && aFIF != FIF_UNKNOWN) { FIMEMORY* aFIMemory = FreeImage_OpenMemory(theDataPtr, theDataSize); if(aFIMemory == NULL) { setState("FreeImage library, internal error"); return false; } myDIB = FreeImage_LoadFromMemory(aFIF, aFIMemory, 0); FreeImage_CloseMemory(aFIMemory); } else { // check the file signature and deduce its format #if defined(_WIN32) StStringUtfWide aFilePathWide = theFilePath.toUtfWide(); aFIF = FreeImage_GetFileType(aFilePathWide.toCString(), 0); #else aFIF = FreeImage_GetFileType(theFilePath.toCString(), 0); #endif if(aFIF == FIF_UNKNOWN) { // no signature? try to guess the file format from the file extension #if defined(_WIN32) aFIF = FreeImage_GetFIFFromFilename(aFilePathWide.toCString()); #else aFIF = FreeImage_GetFIFFromFilename(theFilePath.toCString()); #endif } if((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading(aFIF)) { setState("FreeImage library does not support image format"); return false; } int loadFlags = 0; if(aFIF == FIF_GIF) { // GIF_PLAYBACK - 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading loadFlags = 2; } else if(aFIF == FIF_ICO) { // ICO_MAKEALPHA - convert to 32bpp and create an alpha channel from the AND-mask when loading loadFlags = 1; } #if defined(_WIN32) myDIB = FreeImage_Load(aFIF, aFilePathWide.toCString(), loadFlags); #else myDIB = FreeImage_Load(aFIF, theFilePath.toCString(), loadFlags); #endif } if(myDIB == NULL) { setState("FreeImage library, loading file failed"); return false; } StImagePlane::ImgFormat stImgFormat = convertFromFreeFormat(FreeImage_GetImageType(myDIB), FreeImage_GetColorType(myDIB), FreeImage_GetBPP(myDIB)); if(stImgFormat == StImagePlane::ImgUNKNOWN) { setState(StString("StFreeImage, image format ") + FreeImage_GetImageType(myDIB) + ", " + FreeImage_GetColorType(myDIB) + " doesn't supported by application"); close(); return false; } setColorModelPacked(stImgFormat); changePlane(0).initWrapper(stImgFormat, FreeImage_GetBits(myDIB), FreeImage_GetWidth(myDIB), FreeImage_GetHeight(myDIB), FreeImage_GetPitch(myDIB)); // FreeImage data always bottom-up... changePlane(0).setTopDown(false); // set debug information StString aDummy, aFileName; StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName); setState(StString("FreeImage library, loaded image '") + aFileName + "' " + getDescription()); // we should not close the file because we create a wrapper over FreeImage native object return true; }