Tomaka17 Tomaka17 - 4 months ago 16
C Question

Reading a file located in memory with libavformat

I'm currently trying to read small video files sent from a server

In order to read a file using libavformat, you are supposed to call

av_open_input_file(&avFormatContext, "C:\\path\\to\\video.avi", 0, 0, 0);


The problem is that in this case the file is not on the disk, but in memory.

What I'm doing for the moment is downloading the file, writing it on the disk using a temporary name, and then calling
av_open_input_file
with the temporary file name, which is not a very clean solution.

In fact what I want is a function like
av_open_custom(&avFormatContext, &myReadFunction, &mySeekFunction);
but I didn't find any in the documentation.
I guess it is technically possible, since the name of the file is not something that helps the library determine which format it is using.

So is there a function like this, or an alternative to av_open_input_file?

Answer

It's funny how I always find the solution by myself right after I post the question on this site, even though I've been working on this problem for hours.

In fact you have to initialize avFormatContext->pb before calling av_open_input, and pass to it a fake filename. This is not written in the documentation but in a commentary directly in the library's source code.

Example code if you want to load from an istream (untested, just so somebody which has the same problem can get the idea)

static int readFunction(void* opaque, uint8_t* buf, int buf_size) {
    auto& me = *reinterpret_cast<std::istream*>(opaque);
    me.read(reinterpret_cast<char*>(buf), buf_size);
    return me.gcount();
}

std::ifstream stream("file.avi", std::ios::binary);

const std::shared_ptr<unsigned char> buffer(reinterpret_cast<unsigned char*>(av_malloc(8192)), &av_free);
const std::shared_ptr<AVIOContext> avioContext(avio_alloc_context(buffer.get(), 8192, 0, reinterpret_cast<void*>(static_cast<std::istream*>(&stream)), &readFunction, nullptr, nullptr), &av_free);

const auto avFormat = std::shared_ptr<AVFormatContext>(avformat_alloc_context(), &avformat_free_context);
auto avFormatPtr = avFormat.get();
avFormat->pb = avioContext.get();
avformat_open_input(&avFormatPtr, "dummyFilename", nullptr, nullptr);