Yalir / sfeMovie

sfeMovie is a simple C++ library that lets you play movies in SFML based applications. It relies on FFmpeg to read medias and remains consistent with SFML's naming conventions.
http://sfemovie.yalir.org/
GNU Lesser General Public License v2.1
114 stars 37 forks source link

Clear movie & loading from stream ? #91

Closed StefanTrifunovic closed 9 years ago

StefanTrifunovic commented 9 years ago

I use sfeMovie for my project, and it works really great. Really great project !

I was wondering how do I clear/delete movie ?

I have one sfe::Movie* variable, that is used to load different clips using openFromFile function, but each time I load new clip, the memory grows, until it eventualy breaks...

I deleted the variable and free the memory each time, but it still stays in memory it seems to me...

What am I doing wrong ?

Also another question, is there a possibility to load movie from stream, rather then file ? I wanted to load movie from zip file...

Thanks in advance for any help, any help will be appreciated...

feliwir commented 9 years ago

Hi, nice that you find our project interesting :) to answer your questions: Can you show me your codefragment please? There should be no memory leak (use the Load method only once per instance). Loading from stream isn't supporter yet, but i might tackle that in the future.

StefanTrifunovic commented 9 years ago

Thanks for quick response.

Here's snippet from game state code :

#include <SFML/Config.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>
#include <iostream>
#include <algorithm>
#include "../framework/BFramework.h"
#include "../states/include.h" // INCLUDE ALL STATES

void GameState::init()
{
    sf::Vector2f screenSize = BFramework::getInstance().getScreenSize();

    _BallMovie = 0;
    _BallMaskMovie = 0;
    std::string mediaFile = "Greenball.ogv";
    std::cout << "Going to open movie file \"" << mediaFile << "\"" << std::endl;

    _CurrentNum = -1;
    _LastNum = -1;

    _BallMovie = new sfe::Movie();
    if (!_BallMovie->openFromFile(mediaFile))
    {

    }
    _BallMaskMovie = new sfe::Movie();
    if (!_BallMaskMovie->openFromFile("Ballmask.ogv"))
    {

    }
    _BackgroundMovie = 0;

    _BackgroundMovie = new sfe::Movie();
    if (!_BackgroundMovie->openFromFile("wait_video_old.ogv"))
    {

    }
    _BackgroundMovie->fit(0, 0, screenSize.x, screenSize.y, false);
    _BallMovie->fit(screenSize.x / 2, 225 , 256, 256,true);

    _BallMovie->setOrigin(128,128);

    clock = sf::Clock();

    sf::Image image;
    image.loadFromFile("particle.png");

    texBohatera = sf::Texture();
    texBohatera.loadFromImage(image);

    shader.loadFromFile("video_alpha.frag", sf::Shader::Fragment);

    _BingoBoardDisplay = new BingoBoardDisplay();
    // Instantiate particle system and add custom affector
    system = thor::ParticleSystem();
    system.setTexture(texBohatera);
    system.addAffector(FireworkAffector());

}

void GameState::update(sf::Time delta)
{
    if (_BackgroundMovie){
        _BackgroundMovie->update();
        if (_BackgroundMovie->getStatus() == sfe::Status::Stopped)
            _BackgroundMovie->play();
    }

//  _TestMovie->update(delta);

    if (_BallMovie && _BallMaskMovie){
        _BallMovie->update();
        _BallMaskMovie->update();
    }
    explosionTimer.update();
    system.update(delta);

}

void GameState::draw(sf::RenderWindow* window)
{

    if (_BackgroundMovie)
        window->draw(*_BackgroundMovie);

    if (_BingoBoardDisplay)
        _BingoBoardDisplay->draw(window);

    if (_BallMovie){

        if (_BallMovie->getStatus() == sfe::Status::Playing){

            // Set shader for transparent 
            shader.setParameter("texture", _BallMovie->getCurrentImage());
            shader.setParameter("maskTex", _BallMaskMovie->getCurrentImage());

            window->draw(*_BallMovie, &shader);

        }

        if (_BallMovie->getStatus() == sfe::Status::Stopped){

            if (_LastNum != _CurrentNum && _CurrentNum < 35){
                system.addEmitter(FireworkEmitter(_BingoBoardDisplay->getSlotPosition(_CurrentNum)), explosionDuration);
                _BingoBoardDisplay->setSlot(_CurrentNum, 0);
                _LastNum = _CurrentNum;
            }

        }
    }

    window->draw(system, sf::BlendAdd);

}

void GameState::cleanup()
{

    if (_BackgroundMovie){
        delete _BackgroundMovie;
        _BackgroundMovie = NULL;
    }

    if (_BallMovie){
        delete _BallMovie;
        _BallMovie = NULL;
    }

    if (_BallMaskMovie){
        delete _BallMaskMovie;
        _BallMaskMovie = NULL;
    }

    if (_BingoBoardDisplay){
        delete _BingoBoardDisplay;
        _BingoBoardDisplay = NULL;
    }
}

void GameState::processInput(const sf::Event& event)
{
    if (event.key.code == sf::Keyboard::R){
        BFramework::getInstance().restartState();
    }
    if (event.key.code == sf::Keyboard::E){
        BFramework::getInstance().changeState(new WaitState());
    }
    if (event.key.code == sf::Keyboard::Escape){
        BFramework::getInstance().exit();
    }

    if (event.key.code == sf::Keyboard::O){
        sf::Vector2f position(thor::randomDev(400.f, 300.f), thor::randomDev(300.f, 200.f));
        system.addEmitter(FireworkEmitter(position), explosionDuration);
    }

    if (event.key.code == sf::Keyboard::RControl && event.key.code == sf::Keyboard::Return && event.type == sf::Event::KeyPressed){
        BFramework::getInstance().toggleFullscreen();
    }

    if (event.key.code == sf::Keyboard::P){
        if (_BallMovie->getStatus() == sfe::Status::Stopped &&
            _BallMaskMovie->getStatus() == sfe::Status::Stopped){

            std::string ballName = "";
            int num = rand() % 7 + 1;

            switch (num)
            {
                case 1:
                    ballName = "Blackball.ogv";
                    break;
                case 2:
                    ballName = "Blueball.ogv";
                    break;
                case 3:
                    ballName = "Brownball.ogv";
                    break;
                case 4:
                    ballName = "Greenball.ogv";
                    break;
                case 5:
                    ballName = "Purpleball.ogv";
                    break;
                case 6:
                    ballName = "Redball.ogv";
                    break;
                case 7:
                    ballName = "Yellowball.ogv";
                    break;
            }

            sf::Vector2f screenSize = BFramework::getInstance().getScreenSize();
            _BallMovie->stop();
            delete _BallMovie;
            _BallMovie = NULL;
            _BallMovie = new sfe::Movie();
            _BallMovie->openFromFile(ballName);
            shader.loadFromFile("video_alpha.frag", sf::Shader::Fragment);

            _BallMovie->fit(screenSize.x / 2, 225, 256, 256, true);
            _BallMovie->setOrigin(128, 128);
            _BallMovie->setPlayingOffset(sf::seconds(0));
            _BallMaskMovie->setPlayingOffset(sf::seconds(0));
            _BallMovie->play();
            _BallMaskMovie->play();
            _CurrentNum++;
        }
    }
}

void GameState::resize(float width, float height)
{
    _BackgroundMovie->fit(0, 0, width, height,false);
    _BallMovie->fit(width / 2, 200, 256, 256, true);
}

Each time I press P button it creates new movie clip... Thanks for any help...

Ceylo commented 9 years ago

Hi, first of all I would recommend that you make use of smart pointers. This way Movie object get deleted when you game state is deleted too. It also makes impossible to re-create a new Movie without deleting the previous one.

Apart from that there is nothing specific to do to clean a Movie object. If there is a leak in it, then it's a bug :) Your code sample does not allow determining if there are leaks, because it really depends on how your class is used.

If you want us to investigate we would need to have a minimalist and complete code that reproduces the issue. What do you mean with "it breaks" ?

Edit: https://github.com/Yalir/sfeMovie/issues/90 also reports a leak but it looks to be a false positive for now. Maybe your issue is related too?

StefanTrifunovic commented 9 years ago

Thanks for help. I use VLD for memory leek detection, and for now i don't have memory leeks... I'll investigate this a little more. By "breaks" I mean it fills up memory until it eventually crashes :( . If I run out of ideas, I'll create minimalist test project.

StefanTrifunovic commented 9 years ago

Here's a small sample : https://drive.google.com/file/d/0B37C-1orWIk7dDg0RXplRUk0bk0/view?usp=sharing Hope you can help. Thanks in advance...

Ceylo commented 9 years ago

Sorry but this is really too big. I really meant a minimal example, at most a single file where you have removed everything unnecessary to reproduce the issue.

Ceylo commented 9 years ago

Actually thanks to http://sfemovie.yalir.org/forum/viewtopic.php?id=50 I've been able to reproduce a leak. It looks similar to your: happening after reloading new media files.

StefanTrifunovic commented 9 years ago

Yea, I seen post on forum, it's excatly the same problem as mine... Thanks for investigating :) I was a bit busy at work, so I haven't got time to create minimal example like you requested, sorry for that...

Ceylo commented 9 years ago

I've pushed a fix on branch bugfix/90+91_LeakOnReload You can also find debug binaries with all decoders here:

Could you test for the OS you use and tell me if it's ok on your side too?

Ceylo commented 9 years ago

Fix has been reported to be ok on forum so I merge to master and close this issue.

StefanTrifunovic commented 9 years ago

Yes, now everything work great. Good job !