使用VLC imem从内存中播放h264video文件,但接收错误“主stream错误:不能预先填充缓冲区”

我有一个加载到内存中的h264video文件,我尝试用imem参数“imem-cat = 4”播放它,这样vlc将使用访问模块来解复用video,而vlc启动并接收我的imem成功参数:

[0x7f38a0000e28] access_imem demux debug: Using get(0x404e1d), release(0x404e91), data(0x7fff5b4a9430), cookie("IMEM") 

这个类别也意味着我不必提供DTS和PTS。 用于VLC的imem模块没有很好的文档logging,但是我已经在几个地方发现了提示,例如

https://forum.videolan.org/viewtopic.php?t=111917

https://forum.videolan.org/viewtopic.php?f=32&t=93842

在python中使用内存中的libVLC播放video

我的imem-get函数只是简单地将缓冲区指针设置为第一次调用时的video数据,返回0,任何进一步的调用返回1表示没有更多的数据:

 int MyImemGetCallback (void *data, const char *cookie, int64_t *dts, int64_t *pts, unsigned *flags, size_t * bufferSize, void ** buffer) { ImemData* imem = (ImemData*)data; cookie = imem->cookieString; if(imem == NULL || imem->allBuffered==true) //indicate all data has been get()ted return 1; *buffer = (void*) imem->video; bufferSize = (size_t*) &(imem->bytes); imem->allBuffered=true; return 0; } 

不幸的是,在第一次通话后,我收到以下错误:

 [0x189cb18] main input debug: Creating an input for 'imem://' [0x189cb18] main input debug: using timeshift granularity of 50 MiB, in path '/tmp' [0x189cb18] main input debug: `imem://' gives access `imem' demux `' path `' [0x189cb18] main input debug: creating demux: access='imem' demux='' location='' file='(null)' [0x7f2808000e28] main demux debug: looking for access_demux module matching "imem": 20 candidates [0x7f2808000e28] access_imem demux debug: Using get(0x404e1d), release(0x404e91), data(0x7ffe0da3b940), cookie("h264") [0x7f2808000e28] main demux debug: no access_demux modules matched [0x189cb18] main input debug: creating access 'imem' location='', path='(null)' [0x7f2808001958] main access debug: looking for access module matching "imem": 25 candidates [0x7f2808001958] access_imem access debug: Using get(0x404e1d), release(0x404e91), data(0x7ffe0da3b940), cookie("h264") [0x7f2808001958] main access debug: using access module "access_imem" [0x7f2808000e28] main stream debug: Using block method for AStream* [0x7f2808000e28] main stream debug: starting pre-buffering [0x7f2808000e28] main stream error: cannot pre fill buffer [0x7f2808001958] main access debug: removing module "access_imem" [0x189cb18] main input warning: cannot create a stream_t from access [0x17d7298] main libvlc debug: removing all interfaces [0x17d7298] main libvlc debug: exiting [0x17d7298] main libvlc debug: no exit handler [0x17d7298] main libvlc debug: removing stats 

出于某种原因,似乎vlc不能访问video数据,但错误信息并不是很有帮助,通常是指networkingstream而不是内存位置。

有没有人以这种方式成功地使用过imem,或者对这个问题有什么想法? video完全从磁盘播放VLC。 谢谢你的帮助。

编辑

它看起来像项目接口可能实际上不支持这种方式播放。 但是,libVLC提供了libvlc_media_t和livblc_media_new_callbacks,可以让我实现我想要的。 我会报告回来,如果我得到它的工作。

所以我不能让Imem工作,但是在VLC论坛上,我指出了3.0.0版本中提供了一个新的API。 我不得不删除我目前安装的vlc和libvlc-dev,并将VLC每日构建的PPA添加到Ubuntu安装中,然后安装这些版本。

API是libvlc_media_new_callbacks :

 LIBVLC_API libvlc_media_t * libvlc_media_new_callbacks (libvlc_instance_t *instance, libvlc_media_open_cb open_cb, libvlc_media_read_cb read_cb, libvlc_media_seek_cb seek_cb, libvlc_media_close_cb close_cb, void *opaque) 

您必须实现每个回调才能使VLC访问内存中的流。 虽然文档指出执行seek()回调是不必要的,我不能没有它的h264视频播放。

open()回调应该传递一个指向你的视频数据的指针,我推荐一个容器类,这样你可以存储最后一个字节的索引。

read()回调用于将len字节读入传入指针的缓冲区。 在这里你可以写len或者更少的字节到缓冲区并且返回复制的字节数,直到你有一些字节准备好,返回0代表EOF或者-1代表错误。

seek()回调用于设置下一个read()将发生的字节索引。

最后关闭()不会返回任何东西,并用于清理。

这是一个read()实现的例子:

 class MemVideoData { public: MemVideoData(char *data, int data_bytes) : video(data), bytes(data_bytes), lastByteIndex(0) {} //init ~MemVideoData() {} char* video; // pointer to video in memory int bytes; int lastByteIndex; }; ssize_t memVideo_read(void *opaque, unsigned char* buf, size_t len) { //TODO: block if not end of stream but no bytes available MemVideoData *mVid = (MemVideoData*) opaque; //cast and give context int bytesToCopy=0; int bytesSoFar = mVid->lastByteIndex; int bytesRemaining = mVid->bytes - mVid->lastByteIndex; if(bytesRemaining >= len) //at least as many bytes remaining as requested { bytesToCopy = len; } else if (bytesRemaining < len) //less that requested number of bytes remaining { bytesToCopy = bytesRemaining; } else { return 0; // no bytes left to copy } char *start = mVid->video; std::memcpy(buf,&start[mVid->lastByteIndex], bytesToCopy); //copy bytes requested to buffer. mVid->lastByteIndex = mVid->lastByteIndex + bytesToCopy; //increment bytes read count return bytesToCopy; } 

按照要求这里是一个打开回调的例子:

 int VideoPlayer::memVideo_open(void* opaque, void** datap, uint64_t* sizep) { MemVideoData *mVid = static_cast<MemVideoData*> (opaque); //cast and give context //TODO: get mutex on MemVideoData object pointed to by opaque *sizep = (uint64_t) mVid->bytesTotal; //set stream length *datap = mVid; /*point to entire object. Think this was intended to point to the raw video data but we use the MemVideoData object in read() and seek()*/ mVid->lastByteReadIndex=0; return 0; }