Beispiel #1
0
    /**
     * 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;
    }
Beispiel #2
0
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;
}
Beispiel #3
0
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;
    }
}
Beispiel #4
0
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;
}
Beispiel #5
0
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
}
Beispiel #6
0
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();
}
Beispiel #7
0
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();
}
Beispiel #8
0
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();
    }
}
Beispiel #9
0
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
}
Beispiel #10
0
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;
}
Beispiel #11
0
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;
}
Beispiel #12
0
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;
}
Beispiel #13
0
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
}
Beispiel #14
0
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;
}
Beispiel #15
0
// 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;
}
Beispiel #16
0
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
}
Beispiel #17
0
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;
}