系统相关
首页 > 系统相关> > c – 使用VLC imem从内存播放h264视频文件,但收到错误“主流错误:无法预填充缓冲区”

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