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

sfeMovie play hanging on latest sfml #71

Closed hsdk123 closed 9 years ago

hsdk123 commented 9 years ago

I've just tried updating to the latest vs13 binaries here: http://www.nightlybuilds.ch/project/show/1/SFML/

I'm realising that movie.play() now hangs on windows. Any idea what might be happening? (Everything builds fine, just the hanging on play())

Ceylo commented 9 years ago

Can you tell more? What's the callstack if you stop the process in the debugger while it's hung?

hsdk123 commented 9 years ago

If I put a breakpoint on movie.play() and press f10 to continue, vs hangs for about a second or 2 and then I get the following error:

First-chance exception at 0x777A2F71 in sfml_test.exe: Microsoft C++ exception: std::runtime_error at memory location 0x011AFAF0.
Unhandled exception at 0x777A2F71 in sfml_test.exe: Microsoft C++ exception: std::runtime_error at memory location 0x011AFAF0.

VS doesn't seem to display any useful stack information:

    KernelBase.dll!777a2f71()   Unknown
    [Frames below may be incorrect and/or missing, no symbols loaded for KernelBase.dll]    
    [External Code] 
>   sfml_test.exe!main() Line 112   C++
    [External Code] 
bluekirby0 commented 9 years ago

std::runtime_error is about the most annoying error type to debug (silent buffer overflows that corrupt your program's bytecode or dumps crazy values into other variables are worse).

First, try a different build of SFML to ensure its not just that build.

It doesn't look like pdb files are distributed with those builds so even debug libraries probably won't do you much good here. It may be easiest to build your own SFML to debug this so you can get a proper backtrace.

Also as a small point of clarification because it can get very confusing especially with the more recent vs versions... vs13 is not VS 2013 vs12 is also known as VS 2013 vs13 is also known as VS 2015 preview

hsdk123 commented 9 years ago

@bluekirby0 Thanks for the reply, I'll try the other builds and get back. I'm using Visual studio ultimate 2013.

hsdk123 commented 9 years ago

I've just tried using the debug libraries (I built them on my side) from the latest sfml master. The error seems to occur here:

Run-Time Check Failure #3 - The variable 'packet' is being used without being initialized.

Stack:

>   sfml_test.exe!sfe::AudioStream::onGetData(sf::SoundStream::Chunk & data) Line 168   C++
    sfml_test.exe!sf::SoundStream::fillAndPushBuffer(unsigned int bufferNum) Line 400   C++
    sfml_test.exe!sf::SoundStream::fillQueue() Line 448 C++
    sfml_test.exe!sf::SoundStream::streamData() Line 284    C++
    sfml_test.exe!sf::priv::ThreadMemberFunc<sf::SoundStream>::run() Line 58    C++
    sfml_test.exe!sf::Thread::run() Line 83 C++
    sfml_test.exe!sf::priv::ThreadImpl::entryPoint(void * userData) Line 86 C++
    [External Code] 
    [Frames below may be incorrect and/or missing, no symbols loaded for msvcr120d.dll] 
bluekirby0 commented 9 years ago

Looks like sfml_test is not part of sfeMovie, which means the problem you discovered is in your code. Make sure you initialize all your variables before attempting to use them. If you need help, post the code around where "packet" is declared and where it is being used.

hsdk123 commented 9 years ago

@bluekirby0 sfml_test is my test program with the following code:

sf::RenderWindow window( sf::VideoMode( 1024, 576 ), "sfml test", sf::Style::Titlebar | sf::Style::Close );
    //renderWindow.setActive( false );

    auto movie = make_shared<sfe::Movie>();
    if ( !movie->openFromFile( "test_suzumiya.mp4" ) ) {
        return 1;
    }
    movie->fit( 0, 0, 1024, 576, false );
    movie->play();

"packet" is part of code from AudioStream.cpp - a file from sfeMovie

hsdk123 commented 9 years ago

Here's the part in AudioStream.cpp (sfeMovie file) that vs is having problems with:

bool AudioStream::onGetData(sf::SoundStream::Chunk& data)
    {
        AVPacket* packet;
        data.samples = m_samplesBuffer;

        while (data.sampleCount < av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO) * m_sampleRate &&
               (NULL != (packet = popEncodedData())))
        {
            bool needsMoreDecoding = false;
            bool gotFrame = false;

            do
            {
                needsMoreDecoding = decodePacket(packet, m_audioFrame, gotFrame);

                if (gotFrame)
                {
                    uint8_t* samples = NULL;
                    int nbSamples = 0;
                    int samplesLength = 0;

                    resampleFrame(m_audioFrame, samples, nbSamples, samplesLength);
                    CHECK(samples, "AudioStream::onGetData() - resampleFrame() error");
                    CHECK(nbSamples > 0, "AudioStream::onGetData() - resampleFrame() error");
                    CHECK(nbSamples == samplesLength / 2, "AudioStream::onGetData() resampleFrame() inconsistency");

                    CHECK(data.sampleCount + nbSamples < m_sampleRate * 2 * av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO), "AudioStream::onGetData() - Going to overflow!!");

                    std::memcpy((void *)(data.samples + data.sampleCount),
                                samples, samplesLength);
                    data.sampleCount += nbSamples;
                }
            } while (needsMoreDecoding);

            av_free_packet(packet);
            av_free(packet);
        }

        if (!packet) //////////////LINE WHERE VS BREAKS SAYING UNINITIALISED
        {
            sfeLogDebug("No more audio packets, do not go further");
        }
        return (packet != NULL);
    }
bluekirby0 commented 9 years ago

Ok so it looks like if the while conditions are never true then packet is never initialized. It also appears that

if  (!packet) 

is being tested after the allocated memory is freed, but its not explicitly set to NULL or nullptr (maybe av_free does that for you?)

Try this: Change

AVPacket* packet;

to

AVPacket* packet = NULL;

then rebuild sfeMovie and relink your test program. If it is fine then the while condition was never being met. If it still fails then it seems av_free is not setting the pointer to NULL for us, so we will want to do that after calling it.

hsdk123 commented 9 years ago

@bluekirby0 Done. I'm now getting these errors:

First-chance exception at 0x777A2F71 in sfml_test.exe: Microsoft C++ exception: std::runtime_error at memory location 0x0023EFC8.
Unhandled exception at 0x777A2F71 in sfml_test.exe: Microsoft C++ exception: std::runtime_error at memory location 0x0023EFC8.

Call Stack:

    KernelBase.dll!777a2f71()   Unknown
    [Frames below may be incorrect and/or missing, no symbols loaded for KernelBase.dll]    
    [External Code] 
>   sfml_test.exe!sfe::Timer::notifyObservers(sfe::Status futureStatus) Line 174    C++
    sfml_test.exe!sfe::Timer::play() Line 104   C++
    sfml_test.exe!sfe::MovieImpl::play() Line 157   C++
    sfml_test.exe!sfe::Movie::play() Line 68    C++
    sfml_test.exe!main() Line 116   C++
    [External Code] 

Code that VS hits on:

void Timer::notifyObservers(Status futureStatus)
    {
        std::set<Observer*>::iterator it;
        for (it = m_observers.begin(); it != m_observers.end(); it++)
        {
            Observer* obs = *it;

            switch(futureStatus)
            {
                case Playing:
                    obs->willPlay(*this); ///////////////////////////VS HIT LINE
                    break;

                default:
                    CHECK(false, "Timer::notifyObservers() - unhandled case in switch");
            }
        }
    }

The error is still triggering on movie.play()

bluekirby0 commented 9 years ago

Looks like too many dereferences here...try changing

obs->willPlay(*this);

to

obs.willPlay(*this);

EDIT: Actually, no...my iterators are a little rusty ^^; That should be okay on further examination.

hsdk123 commented 9 years ago

From what I understand, SFML went through a few changes in audio implementation some time in July: https://github.com/LaurentGomila/SFML/issues/604

This is the output I get from sfeMovie's debug console:

image

I don't know much about sfeMovie, but I get the feeling that the 'No more audio packets, do not go further` shouldn't be happening since the video hasn't started playing at all. Could this be some problem with audio?

hsdk123 commented 9 years ago

Has anyone else tried the latest SFML master by the way?

bluekirby0 commented 9 years ago
while (data.sampleCount < av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO) * m_sampleRate && (NULL != (packet = popEncodedData())))

The problem most likely lies somewhere in there, as anything not evaluating as true in there will result in no decoding occuring.

Two obvious places to check for sane values: the value of data.sampleCount the return value from popEncodedData()

Ceylo commented 9 years ago

I suppose you're trying to play the exact same file that was playing fine (except the fit thing) with SFML 2.1 and you only replaced the SFML libraries ?

By any chance I see that you use C++11, I don't know if SFML did the switch on development version too. I don't know if it can introduce issues with sfeMovie (it doesn't prevent C++11 but there is no explicit compilation flag to build it against this standard).

I ask this because on OS X std::string from C++11 runtime is not compatible with std::string from C++03 runtime (but you get explicit build errors about this).

Ceylo commented 9 years ago

And no I didn't try SFML master yet.

hsdk123 commented 9 years ago

@Ceylo Thank for the reply, I don't think this would have much to do with c++11 though. The same code works just fine if I use some earlier SFML libraries.

hsdk123 commented 9 years ago

In relation back to the nightly builds here: http://www.nightlybuilds.ch/project/show/1/SFML/ The 2014-04-23 version works fine with sfeMovie, all builds afterwards either hang at movie.play() or window.display().