How to get std::basic_istream from AAssetManager?

谁说我不能喝 提交于 2020-04-16 05:48:33

问题


I am using NDK and I need to read resource media file. So, as far as I understand in order to access to resources I need to use AAssetManager, and eventually I need to get std::basic_istream to work with it.

So, question is, how to get std::basic_istream from AAssetManager?


回答1:


The answer is actually very different whether you have a compressed asset (e.g. text) or uncompressed (by default, Jpeg images and mp3 are stored by the packer). For these uncompressed assets, you can get the file descriptor with AAsset_openFileDescriptor(), and then follow the ways of How to construct a c++ fstream from a POSIX file descriptor?. For compressed assets, you may look for a (potentially API-level-dependent) hack that will let you get the file descriptor (or file path) to the transient file that the OS opens for you when it unpacks your asset.




回答2:


You can adapt this example to work with the "buffer" mode of AAssetManager.

This will read the entire asset into memory, though. You could make an implementation that works more like std::fstream by reading chunks into a memory buffer, but that is significantly more complex.

Note: I only test-compiled the code below.

class asset_streambuf : public std::streambuf {
    public:
        asset_streambuf(AAsset * the_asset)
            : the_asset_(the_asset) {
                begin_ = current_ = (const char *)AAsset_getBuffer(the_asset);
                end_   = begin_ + AAsset_getLength64(the_asset);
            }
        ~asset_streambuf() {
            AAsset_close(the_asset_);
        }
    private:
        int_type underflow() {
            if (current_ == end_) {
                return traits_type::eof();
            }
            return traits_type::to_int_type(*current_);
        }
        int_type uflow() {
            if (current_ == end_) {
                return traits_type::eof();
            }
            return traits_type::to_int_type(*current_++);
        }

        int_type pbackfail(int_type ch) {
            if (current_ == begin_ || (ch != traits_type::eof() && ch != current_[-1])) {
                return traits_type::eof();
            }
            return traits_type::to_int_type(*--current_);
        }

        std::streamsize showmanyc() {
            return end_ - current_;
        }

        AAsset * the_asset_;
        const char * begin_;
        const char * end_;
        const char * current_ = nullptr;
};

Usage:

AAsset * asset = AAssetManager_open(mgr, "some_asset.bin", AASSET_MODE_BUFFER);
asset_streambuf sb(asset);
std::istream is(&sb);


来源:https://stackoverflow.com/questions/61190087/how-to-get-stdbasic-istream-from-aassetmanager

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!