kcat / alure

Alure is a utility library for OpenAL, providing a C++ API and managing common tasks that include file loading, caching, and streaming
zlib License
70 stars 20 forks source link

fill buffer with data not from file but of a known format #41

Open lain3d opened 4 years ago

lain3d commented 4 years ago

Just as a test I've done this:

struct membuf : std::streambuf
{
    membuf(char* begin, char* end) {
        this->setg(begin, begin, end);
    }
};

class FileFactory final : public alure::FileIOFactory {
private:
    membuf buf;
public:
    FileFactory(membuf &bufin) : buf(bufin)
    {
        std::cout << "hello" << std::endl;
    }

    alure::UniquePtr<std::istream> openFile(const alure::String &name) noexcept override
    {
        auto stream = alure::MakeUnique<std::istream>(&buf);
        if (stream->fail()) {
            std::cout << "failed" << std::endl;
        }
        return std::move(stream); 
    }
};

In my main function I have:
membuf sbuf(existing_buff, existing_buff + sz);
alure::FileIOFactory::set(alure::MakeUnique<FileFactory>(sbuf));

When I run my test I get: Failed to rewind file for the next decoder factory

This is just a test, I was planning to pass in a map of id,buf in the constructor to the factory if I got this to work.

kcat commented 4 years ago

This doesn't look like proper use of the file IO factory. Each given filename needs to return a unique file/istream handle for the named file, rather than one membuf for all files. Your custom istream handle type also needs to implement seeking, or else the decoders will have problems.

McSinyx commented 4 years ago

I think OP's final goal is to have an istream created from the factory from each ID, which is analogous to file handling. @lain3d: Here is a quite informative article on properly deriving std::streambuf.

lain3d commented 4 years ago

@McSinyx I'm now using the std::streambuf for that example + this seekoff:

membuf::pos_type membuf::seekoff(off_type off,
                 std::ios_base::seekdir dir,
                 std::ios_base::openmode which = std::ios_base::in) {
    if (dir == std::ios_base::cur)
        gbump(off);
    else if (dir == std::ios_base::end)
        setg(eback(), egptr() + off, egptr());
    else if (dir == std::ios_base::beg)
        setg(eback(), eback() + off, egptr());
    return gptr() - eback();
}

Unfortunately when I'm creating the object it looks like the underlying std::basic_streambuf is not updated..? So I'm still having the same problem as before.

image

lain3d commented 4 years ago

After I implemented membuf::seekpos it's getting further but for some reason not decoding the frame properly..

image

But if I instead use the file the audio plays fine.

kcat commented 4 years ago

FWIW, this is what I use to create a std::istream that reads from a memory buffer instead of a file on disk: https://github.com/kcat/openal-soft/blob/openal-soft-1.20.1/alc/hrtf.cpp#L111...L178

Your factory's openFile method would just need to create an idstream using the appropriate start and end data pointers.

lain3d commented 4 years ago

Hell yeah, got it working thanks to that.. I needed to have

this->setg(const_cast<char_type*>(begin_), const_cast<char_type*>(begin_),
         const_cast<char_type*>(end_)); 

in my constructor (I took it out earlier because the example from the above link did not have setg).. Thanks. :)