Play video file from memory using libvlc_media_new_callbacks API

This forum is about all development around libVLC.
Dekel
New Cone
New Cone
Posts: 5
Joined: 23 Oct 2022 13:42

Play video file from memory using libvlc_media_new_callbacks API

Postby Dekel » 23 Oct 2022 14:02

Hello all,

First of all I'll say I'm new to the VLC world (so go easy on me :wink: )
I'm trying to use the libvlc_media_new_callbacks API to open a video file (.mov file to be specific) from memory buffer and play it.
I think my problem is to pass the VLC the right video parameters (format, fps,...) so it could open and read the file correctly.
I tried to look for an example online of something like my case but couldn't find anything.

Properties of the file I'm trying to play:
* Format: HEVC
* Width: 1920 pixels
* Height: 960 pixels
* Frame rate: 25 fps


Tnx :)

This is my code:

Code: Select all

[using namespace std; #include <vlc/vlc.h> #include <memory> #include <cstring> #include <unistd.h> #include <vector> #include <iostream> #include <fstream> #define WIDTH 1920 // 1080 #define HEIGHT 960 // 720 class MemVideoData { public: MemVideoData(char *data, int data_bytes) : video(data), bytes(data_bytes) { } //init ~MemVideoData() {} char* video; // pointer to video in memory size_t bytes; size_t pos = 0; }; ssize_t media_read_cb(void *opaque, unsigned char* buf, size_t len) { MemVideoData *mVid = (MemVideoData*) opaque; //cast and give context size_t copyLen = std::min(mVid->bytes - mVid->pos, len); char *start = mVid->video + mVid->pos; memcpy(buf,start, copyLen); //copy bytes requested to buffer. mVid->pos += (copyLen % mVid->bytes); return copyLen; } int media_open_cb(void* opaque, void** datap, uint64_t* sizep) { //cast opaque to our video state struct MemVideoData *mVid = static_cast<MemVideoData*> (opaque); *sizep = UINT64_MAX; //set stream length *datap = mVid; return 0; } int media_seek_cb(void *opaque, uint64_t offset) { return 0; } void media_close_cb(void *opaque) { } // load a file to memory, write address into "fileInRam" int loadFileToMem(const char* filePath, char** fileInRam) { int bytes = 0; FILE *file=fopen(filePath,"r"); if(NULL == file) { return -1; } fseek(file,0L,SEEK_END); //seek to end bytes = ftell(file); // record size in bytes *fileInRam = new char[bytes]; //allocate ram if(NULL == *fileInRam) { return -2; } fread(fileInRam,sizeof(unsigned char), bytes, file); //read file into ram fclose(file); //close file return bytes; } int main() { int imgSize = HEIGHT*WIDTH*3; char* filePath = (char*)"/usr2/damrani/Downloads/video-h265.mkv"; char* ramBuff; int bytes = loadFileToMem(filePath,&ramBuff); //load file into byte (char) vector if(-1 == bytes) { cout << "Could not open file !" << endl; return -1; } else if(-2 == bytes) { cout << "Could not allocate memory! " << endl; return -1; } else if(0 == bytes) { cout << "File length 0 bytes! " << endl ; return -1; } cout << "Loaded file to memory address: " << std::hex << static_cast<void*>(ramBuff) << endl; cout << "Bytes: " << std::dec << bytes << endl; MemVideoData mem(ramBuff, imgSize);// = new MemVideoData(data, imgSize); libvlc_instance_t *vlc; // add Verbose option to instance std::vector<const char*> options; options.push_back("--verbose=4"); vlc = libvlc_new (int(options.size()), options.data()); libvlc_media_t* media = libvlc_media_new_callbacks(vlc,media_open_cb, media_read_cb, media_seek_cb, media_close_cb, (void*)&mem); // Add the streaming string given by the vlc app //libvlc_media_add_option(media, ":sout=#transcode{vcodec=h264,venc=x264,vb=0,vbv-bufsize=1200,bframes=0,scale=0,acodec=none}:rtp{dst=localhost, port=9555, name=test, mux=ts,sap}"); libvlc_media_add_option(media, ":demux=rawvid"); libvlc_media_add_option(media, ":rawvid-fps=25"); libvlc_media_add_option(media, ":rawvid-height=960"); libvlc_media_add_option(media, ":rawvid-width=1920"); libvlc_media_add_option(media, ":rawvid-chroma=RV32"); //24bit RGB // Create a media player playing environment libvlc_media_player_t *mediaPlayer = libvlc_media_player_new_from_media (media); // play the media_player libvlc_media_player_play (mediaPlayer); sleep(15); // Stop playing libvlc_media_player_stop (mediaPlayer); // Free the media_player libvlc_media_player_release (mediaPlayer); // Free vlc libvlc_release (vlc); }]

chubinou
Developer
Developer
Posts: 521
Joined: 23 Jul 2015 15:19

Re: Play video file from memory using libvlc_media_new_callbacks API

Postby chubinou » 24 Oct 2022 09:36

> libvlc_media_add_option(media, ":demux=rawvid");

your video is not "rawvid", rawvid mean that your video contains only uncompressed picture. the file you're trying to read is an MKV with an H264 compressed video stream

> int imgSize = HEIGHT*WIDTH*3;

your video isn't in a raw format, this size isn't a meaningful size for reading the MKV format, I think this should rather be

Code: Select all

MemVideoData mem(ramBuff, bytes);
> int media_seek_cb(void *opaque, uint64_t offset)

you should implement the seek callback, it will change the mVid->pos

Dekel
New Cone
New Cone
Posts: 5
Joined: 23 Oct 2022 13:42

Re: Play video file from memory using libvlc_media_new_callbacks API

Postby Dekel » 24 Oct 2022 11:22

Thank you for the replay!

Let's say I want to open this video [url][ https://www.videezy.com/abstract/41668- ... the-day-4k] - what do I need to config with the libvlc_media_add_option?
Plus Is there any way that I can give the program just a video (in .mov format) file and the VLC will automatic find the right parameters for the video according to the header file?
My ultimate goal is to stream video data to a specific memory in the pc and ask the VLC to display it - in the first step it will be ש file that we will transfer it's data to the specific memory in cycles and in the next step I want to stream live video to that memory (I refer to the memory as circular memory with write/read pointers).

Thank you:)

chubinou
Developer
Developer
Posts: 521
Joined: 23 Jul 2015 15:19

Re: Play video file from memory using libvlc_media_new_callbacks API

Postby chubinou » 24 Oct 2022 13:43

> what do I need to config with the libvlc_media_add_option

nothing, VLC will figure it out by himself.

you have other issues in your code:

* your not reading anything from your file because you're forgetting to rewind before starting to actually read
* you may not read the whole file at once, fread may return less data than what you requested

try something like this:

Code: Select all

fseek(file, 0L, SEEK_SET); char* ptr = *fileInRam; int remaining = bytes; while (remaining > 0) { ssize_t len = fread(ptr, 1, remaining, file); ptr += len; remaining -= len; } fclose(file); //close file

> I refer to the memory as circular memory with write/read pointers

hum, you want to loop within a video? beware that this may not work as you expect, most file format (mov, mkv, etc...) are not designed for this, you can't stitch them randomly and expect it to work. you may add this to your media if you want to loop through a time segment (:start-time=12 :stop-time=50 :repeat)

Dekel
New Cone
New Cone
Posts: 5
Joined: 23 Oct 2022 13:42

Re: Play video file from memory using libvlc_media_new_callbacks API

Postby Dekel » 24 Oct 2022 14:59

Now it seems that I have problem with the demux.

My operation system is Linux.
VLC media player 3.0.9.2 Vetinari (revision 3.0.9.2-0-gd4c1aefe4d)

The log file was to long so I used pastebin:
[url][https://pastebin.com/31xZj9aG]

+ When I insert a mp4 file it works fine.

chubinou
Developer
Developer
Posts: 521
Joined: 23 Jul 2015 15:19

Re: Play video file from memory using libvlc_media_new_callbacks API

Postby chubinou » 25 Oct 2022 09:28

I *guess* you didn't implement the seek callback

Code: Select all

#include <vlc/vlc.h> #include <memory> #include <cstring> #include <unistd.h> #include <vector> #include <iostream> #include <fstream> using namespace std; class MemVideoData { public: MemVideoData(char *data, int data_bytes) : video(data) , bytes(data_bytes) { } //init ~MemVideoData() {} char* video; // pointer to video in memory size_t bytes; size_t pos = 0; }; ssize_t media_read_cb(void *opaque, unsigned char* buf, size_t len) { MemVideoData *mVid = (MemVideoData*) opaque; //cast and give context size_t copyLen = std::min(mVid->bytes - mVid->pos, len); char *start = mVid->video + mVid->pos; memcpy(buf, start, copyLen); //copy bytes requested to buffer. mVid->pos += copyLen; return copyLen; } int media_open_cb(void* opaque, void** datap, uint64_t* sizep) { //cast opaque to our video state struct MemVideoData *mVid = static_cast<MemVideoData*> (opaque); *sizep = mVid->bytes; //set stream length *datap = mVid; return 0; } int media_seek_cb(void *opaque, uint64_t offset) { MemVideoData *mVid = static_cast<MemVideoData*> (opaque); mVid->pos = offset; return 0; } void media_close_cb(void *opaque) { } // load a file to memory, write address into "fileInRam" int loadFileToMem(const char* filePath, char** fileInRam) { int bytes = 0; FILE *file=fopen(filePath,"r"); if(NULL == file) { return -1; } fseek(file,0L,SEEK_END); //seek to end bytes = ftell(file); // record size in bytes *fileInRam = new char[bytes]; //allocate ram if(NULL == *fileInRam) { return -2; } fseek(file, 0L, SEEK_SET); char* ptr = *fileInRam; int remaining = bytes; while (remaining > 0) { ssize_t len = fread(ptr, 1, remaining, file); ptr += len; remaining -= len; } fclose(file); //close file return bytes; } int main(int argc, const char** argv) { const char* filePath = "/home/pierre/Downloads/VegasDay.mov"; char* ramBuff; int bytes = loadFileToMem(filePath, &ramBuff); //load file into byte (char) vector if(-1 == bytes) { cout << "Could not open file !" << endl; return -1; } else if(-2 == bytes) { cout << "Could not allocate memory! " << endl; return -1; } else if(0 == bytes) { cout << "File length 0 bytes! " << endl ; return -1; } cout << "Loaded file to memory address: " << std::hex << static_cast<void*>(ramBuff) << endl; cout << "Bytes: " << std::dec << bytes << endl; MemVideoData mem(ramBuff, bytes); libvlc_instance_t *vlc; // add Verbose option to instance std::vector<const char*> options; options.push_back("--verbose=4"); vlc = libvlc_new (int(options.size()), options.data()); libvlc_media_t* media = libvlc_media_new_callbacks(vlc, media_open_cb, media_read_cb, media_seek_cb, media_close_cb, (void*)&mem); // Create a media player playing environment libvlc_media_player_t *mediaPlayer = libvlc_media_player_new_from_media (media); // play the media_player libvlc_media_player_play (mediaPlayer); sleep(15); // Stop playing libvlc_media_player_stop (mediaPlayer); // Free the media_player libvlc_media_player_release (mediaPlayer); // Free vlc libvlc_release (vlc); delete[] ramBuf; }

Dekel
New Cone
New Cone
Posts: 5
Joined: 23 Oct 2022 13:42

Re: Play video file from memory using libvlc_media_new_callbacks API

Postby Dekel » 05 Dec 2022 12:09

Thank you @chubinou for your answer - I did forget to implement the seek callback.

My goal is to do live stream - by transmitting chunk of video data to the VLC. My current format I'm using is MP4.
I have a few problems right now.
I implemented an UDP client and server in my code:
The client gets a MP4 file and save the video data in the memory, and then the client sends chunks of the data (8K byte) each "sendto" call (I use the usleep function between each pair of "sendto" calls).
The server is where the libvlc_media_new_callbacks API is implemented, in the media_read_cb I use the "recvfrom" function.
My big problem is that the VLC starts to play the video only after getting somewhere around 10K video chunks and when he gets to the 12,162 chunk - he is not getting any more chunks (the media_read_cb is not called). After checking I saw that the len in the 12,162 media_read_cb call is around 700 byte (so maybe the VLC buffer is full?).

Is there any way I can make the VLC to start displaying the video so it will be more like live streaming?

Regards,
Dekel

chubinou
Developer
Developer
Posts: 521
Joined: 23 Jul 2015 15:19

Re: Play video file from memory using libvlc_media_new_callbacks API

Postby chubinou » 06 Dec 2022 10:35

My advise would be to use a standard streaming protocol rather than packetizing mp4 yourself , for instance you can stream using RTP or MPEG-TS, and ask vlc to directly listen to the stream like "rtp://@:1234" (with 1234 your listening port)

Dekel
New Cone
New Cone
Posts: 5
Joined: 23 Oct 2022 13:42

Re: Play video file from memory using libvlc_media_new_callbacks API

Postby Dekel » 06 Dec 2022 18:02

The problem is that my program (is in the Rx side) receives the video data from another device (that's in the Tx side) that sends the video data in chunks (8KB each chunk), again I can config in advanced the time between each chunk sent.
I choose the UDP protocol because from the Rx side I can't change in real time the pace of arriving chunks from the Tx side.
My current phase is to transmit a single file over and over again.


Return to “Development around libVLC”

Who is online

Users browsing this forum: No registered users and 6 guests