Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [SOLVED] loadFromMemory vs loadFromStream  (Read 6724 times)

0 Members and 1 Guest are viewing this topic.

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
[SOLVED] loadFromMemory vs loadFromStream
« on: November 17, 2013, 03:14:20 pm »
I have some file where several texture images are packed. I wanted to do so
        result = texture.loadFromStream(input);
But it fails, log message is "Failed to load image from stream. Reason : Image not of any known type, or corrupt".

So i changed to
        void* data = malloc(size);
        input.read(data, size);
        texture.loadFromMemory(data, size);
        free(data);
and it works fine, but there reduntant memory allocation operations. Any thoughts how to do it better?
« Last Edit: November 18, 2013, 10:01:26 am by ChronicRat »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: loadFromMemory vs loadFromStream
« Reply #1 on: November 17, 2013, 04:03:19 pm »
I think you have to give us some more info you that magic "input" object. Does it support streaming? Does it stream things correctly? etc
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re: loadFromMemory vs loadFromStream
« Reply #2 on: November 17, 2013, 06:49:54 pm »
Well, yes it's sf::InputStream based object. It support memory, file and zip archive. And this stream is well tested many times. I do not think it's fault of "input" stream. =)

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: loadFromMemory vs loadFromStream
« Reply #3 on: November 17, 2013, 07:02:14 pm »
What you could test is, loading a different image, writing the stream to a log and check whether everything is in order or not, take a look at SFML's implementation and file history to see if nothing has been missed.

Can you tell us what you're streaming? And at best make a minimal example, otherwise we can essentially just keep guessing... ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re: loadFromMemory vs loadFromStream
« Reply #4 on: November 17, 2013, 07:19:27 pm »
Minimal example in topic... =) Else it will be FULL example. Several images are packed in file one by one. These images can be RAW, PNG or JPEG. To read compressed data used loadFromStream - does not work, and loadFromMemory - perfectly works, where input stream is the same for each method. So i want to know, why loadFromStream can't load from stream. =)

ps Do you understand me? =(

wintertime

  • Sr. Member
  • ****
  • Posts: 255
    • View Profile
Re: loadFromMemory vs loadFromStream
« Reply #5 on: November 18, 2013, 01:10:25 am »
So you have a perfectly working solution and only because you guess a single allocation would slow down your program you want to add a 10 times more complicated solution?
Please, consider profiling, if it really bothers you.
Then dont forget to also try out alternatives like mmap/CreateFileMapping.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: loadFromMemory vs loadFromStream
« Reply #6 on: November 18, 2013, 01:58:02 am »
Minimal example in topic... =) Else it will be FULL example.
It's always meant as minimal and complete. The thing is a few lines of code can sometimes be enough, but most of the time it's not. Since InputStream should work and it doesn't for you and you can't figure out why, we'd have to reproduce the issue and without the code we can't test it, thus leaving your issue unresolved. ;)

Several images are packed in file one by one. These images can be RAW, PNG or JPEG. To read compressed data used loadFromStream - does not work, and loadFromMemory - perfectly works, where input stream is the same for each method. So i want to know, why loadFromStream can't load from stream. =)
Well what image are you loading when it fails? Does it fail with all? Did you already output the data via stream and check for corruption? Just because it works with read doesn't automatically mean that streaming will work, both use different approaches, so you should look at the stream on it's own to see what's going wrong there.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re: loadFromMemory vs loadFromStream
« Reply #7 on: November 18, 2013, 09:19:16 am »
I think loadFromStream tries to load image from BEGIN of the input stream. If it correct behavior, so no any questions from me. But i think that loadFromStream have to read image from CURRENT position and read size of image header.  :-\

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: loadFromMemory vs loadFromStream
« Reply #8 on: November 18, 2013, 09:39:32 am »
Yes, loadFromStream reads from the begining of the stream, not from the current position. Your stream should really provide an interface to the file that you want to load, and nothing else. A stream instance is not meant to be used for loading several resources.

So you would not do this

MyStream stream("all_my_textures.pak");
texture1.loadFromStream(stream);
texture2.loadFromStream(stream);
...

But rather

MyStream stream1("all_my_textures.pak", 1); // second argument refers to the texture, it can be an index of a relative path
texture1.loadFromStream(stream);

MyStream stream2("all_my_textures.pak", 2);
texture2.loadFromStream(stream);

Or, if you don't want to open the package everytime

MyPackage pack("all_my_textures.pak");

MyStream stream1(pack, 1);
texture1.loadFromStream(stream1);

MyStream stream2(pack, 2);
texture2.loadFromStream(stream2);
« Last Edit: November 18, 2013, 10:07:30 am by Laurent »
Laurent Gomila - SFML developer

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re: loadFromMemory vs loadFromStream
« Reply #9 on: November 18, 2013, 10:00:57 am »
That's what I wanted to hear. =) Thanks to all!

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re: [SOLVED] loadFromMemory vs loadFromStream
« Reply #10 on: November 19, 2013, 07:58:41 am »
So, result of discussion is something like that:
(i removed some code for simplicity)

class SubStream: public sf::InputStream
{
public:

        explicit SubStream(sf::InputStream* stream, size_t begin, size_t size);
        virtual ~SubStream();

        virtual sf::Int64 read(void* data, sf::Int64 size) override;
        virtual sf::Int64 seek(sf::Int64 position) override;
        virtual sf::Int64 tell() override;
        virtual sf::Int64 getSize() override;

protected:

        sf::InputStream*        mStream = nullptr;
        size_t  mBegin = 0;
        size_t  mSize = 0;
        size_t  mOffset = 0;
};

SubStream::SubStream(sf::InputStream* stream, size_t begin, size_t size):
        mStream(stream),
        mBegin(begin),
        mSize(size),
        mOffset(0)
{
        mIsOk = mStream != nullptr && mSize > 0;
}



SubStream::~SubStream()
{
}



/* virtual */ sf::Int64 SubStream::read(void* data, sf::Int64 size)
{
        if (mIsOk)
        {
                sf::Int64 readed = mStream->read(data, size);

                if (readed != -1)
                {
                        mOffset += readed;
                        return readed;
                }
        }

        return -1;
}



/* virtual */ sf::Int64 SubStream::seek(sf::Int64 position)
{
        if ( (size_t) position < mSize)
        {
                mOffset = (size_t) position;
                mStream->seek(mBegin + mOffset);
                return (sf::Int64) mOffset;
        }

        return -1;
}



/* virtual */ sf::Int64 SubStream::tell()
{
        return (sf::Int64) mOffset;
}




/* virtual */ sf::Int64 SubStream::getSize()
{
        return (sf::Int64) mSize;
}
 
It works very well, and a little bit faster than use of redundant malloc/free .
« Last Edit: November 19, 2013, 08:00:58 am by ChronicRat »