c – 使用VLC imem从内存播放h264视频文件,但收到错误“主流错误:无法预填充缓冲区”
作者:互联网
我有一个加载到内存中的h264视频文件,我尝试使用参数“imem-cat = 4”与imem一起播放,这样vlc将使用访问模块来解复用视频,并且vlc启动并接收我的imem参数成功:
[0x7f38a0000e28] access_imem demux debug: Using get(0x404e1d), release(0x404e91), data(0x7fff5b4a9430), cookie("IMEM")
这个类别也意味着我不必提供DTS和PTS.用于VLC的imem模块没有详细记录,但我在几个地方找到了提示,例如:
https://forum.videolan.org/viewtopic.php?t=111917
https://forum.videolan.org/viewtopic.php?f=32&t=93842
Play video using libVLC from memory in python
我的imem-get函数只是在第一次调用时将缓冲区指针设置为视频数据,返回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无法访问视频数据,但错误消息不是很有用,通常是指网络流而不是内存位置.
有没有人以这种方式成功使用过imem,或者对问题是什么有任何想法?视频在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或更少的字节写入缓冲区并返回复制的字节数,阻塞直到准备好一些字节,为EOF返回0或为错误返回-1.
seek()回调用于设置下一个read()将发生的字节索引.
最后,close()不会返回任何内容并用于整理.
以下是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;
}
这里要求的是一个Open回调示例:
int VideoPlayer::memVideo_open(void* opaque, void** datap, uint64_t* sizep)
{
//cast opaque to our video state struct
MemVideoData *mVid = static_cast<MemVideoData*> (opaque);
//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;
}
标签:vlc,c,linux,video,h-264 来源: https://codeday.me/bug/20190824/1709373.html