我当前正在尝试读取从服务器发送的小视频文件
为了使用libavformat读取文件,您应该调用
av_open_input_file(&avFormatContext, "C:\\path\\to\\video.avi", 0, 0, 0);问题是,在这种情况下,文件不在磁盘上,而是在内存中。
我目前所做的是下载文件,使用临时名称将其写入磁盘,然后使用临时文件名调用av_open_input_file,这不是一个非常干净的解决方案。
事实上,我想要的是一个像av_open_custom(&avFormatContext, &myReadFunction, &mySeekFunction);这样的函数,但我在文档中没有找到任何函数。我想这在技术上是可能的,因为文件名并不能帮助库确定它使用的格式。
那么有没有像这样的函数,或者是av_open_input_file的替代品呢?
发布于 2012-03-08 00:19:44
有趣的是,我总是在我在这个网站上发布问题后就自己找到解决方案,尽管我已经在这个问题上工作了几个小时。
实际上,您必须在调用av_open_input之前初始化avFormatContext->pb,并向其传递一个假文件名。这不是在文档中编写的,而是直接在库的源代码中的注释中编写的。
如果您想要从istream加载的示例代码(未经测试,只是为了让有相同问题的人可以理解)
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);发布于 2013-03-22 23:32:55
这是很好的信息,对我帮助很大,但有几个问题人们应该意识到。libavformat可以并且将会扰乱你提供给avio_alloc_context的缓冲区。这会导致非常恼人的双重释放错误或可能的内存泄漏。当我开始搜索这个问题时,我找到了https://lists.ffmpeg.org/pipermail/libav-user/2012-December/003257.html,它完美地解决了这个问题。
清理这项工作时,我的变通方法是继续调用
av_free(avioContext->buffer)然后将您自己的缓冲区指针(为avio_alloc_context调用分配的)设置为NULL。
发布于 2013-01-26 02:31:17
Tomaka17的出色回答给了我一个良好的开端,让我能够使用Qt QIODevice而不是std::istream来解决类似的问题。我发现我需要将Tomaka17解决方案的一些方面与http://cdry.wordpress.com/2009/09/09/using-custom-io-callbacks-with-ffmpeg/的相关经验相结合
我的自定义读取函数如下所示:
int readFunction(void* opaque, uint8_t* buf, int buf_size)
{
QIODevice* stream = (QIODevice*)opaque;
int numBytes = stream->read((char*)buf, buf_size);
return numBytes;
}...but我还需要创建一个自定义的Seek函数:
int64_t seekFunction(void* opaque, int64_t offset, int whence)
{
if (whence == AVSEEK_SIZE)
return -1; // I don't know "size of my handle in bytes"
QIODevice* stream = (QIODevice*)opaque;
if (stream->isSequential())
return -1; // cannot seek a sequential stream
if (! stream->seek(offset) )
return -1;
return stream->pos();
}...and我把它绑在一起,就像这样:
...
const int ioBufferSize = 32768;
unsigned char * ioBuffer = (unsigned char *)av_malloc(ioBufferSize + FF_INPUT_BUFFER_PADDING_SIZE); // can get av_free()ed by libav
AVIOContext * avioContext = avio_alloc_context(ioBuffer, ioBufferSize, 0, (void*)(&fileStream), &readFunction, NULL, &seekFunction);
AVFormatContext * container = avformat_alloc_context();
container->pb = avioContext;
avformat_open_input(&container, "dummyFileName", NULL, NULL);
...注意:我还没有解决内存管理问题。
https://stackoverflow.com/questions/9604633
复制相似问题