Using Imem to play h264 from memory

This forum is about all development around libVLC.
stumpsy
New Cone
New Cone
Posts: 3
Joined: 07 Jul 2015 12:54

Using Imem to play h264 from memory

Postby stumpsy » 07 Jul 2015 13:30

Hello,
I've found various references and hints around the web and in these forums but no fully working example. In summary I'm loading an h264 video into memory and I wish to pass it to VLC to be played. Here's what I have so far, derived from examples on Stack Overflow that use a vector of jpegs rather than video. I use "item-category=4' so that vlc will use an access deumux to demux the video and I don't have to provide DTS/PTS:

Code: Select all

#include <iostream> #include <fstream> #include <vector> #include <stdint.h> #include <vlc/vlc.h> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/thread.hpp> //#include <opencv2.hpp> //#include <highgui.hpp> //using namespace cv; using namespace std; class ImemData { public: ImemData(char *data, int data_bytes) : mDts(0), mPts(0), video(data), bytes(data_bytes), buff(0),allBuffered(false),cookieString("h264") {} //init ~ImemData() {} int64_t mDts; //decode timestamp int64_t mPts; //presentation timestamp char* video; // pointer to video in memory int bytes; char* buff; bool allBuffered; char* cookieString; }; 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()tedfIMEM return 1; *buffer = (void*) imem->video; bufferSize = (size_t*) &(imem->bytes); imem->allBuffered=true; // *dts=-1; //Cannot write to these with imem-cat=4 // *pts=-1; return 0; } int MyImemReleaseCallback (void *data, const char *cookie, size_t bufferSize, void * buffer) { //if(buffer!=NULL) //{ // free(buffer); // } return 0; } /* \brief Method to load a series of images to use as raw image data for the network stream. \param[in] sourceFolder Path to folder containing jpeg or png images. */ // load a file to memory, write address into "fileInRam" int loadFileToMem(const char* filename, char** fileInRam) { int bytes = 0; FILE *file=fopen(filename,"r"); if(file==NULL) { return -1; } fseek(file,0L,SEEK_END); //seek to end bytes = ftell(file); // record size in bytes *fileInRam = new char[bytes]; //allocate ram if(*fileInRam==NULL) { return -2; } fread(fileInRam,sizeof(unsigned char), bytes, file); //read file into ram fclose(file); //close file return bytes; } int main(int argc, char* argv[]) { // Load images first since we need to know // the size of the image data for IMEM cout << "VLC RAM player demo" << endl; cout << "============================" << endl << endl ; if(argc < 2) { cout << "No filname specified!" << endl; return -1; } char* filename = argv[1]; cout << "Filename: " << filename << endl; printf("Writing to RAM buffer... "); char* ramBuff; int bytes = loadFileToMem(filename,&ramBuff); //load file into byte (char) vector if(bytes==-1) { cout << "Could not open file !" << endl; return -1; } else if(bytes==-2) { cout << "Could not allocate memory! " << endl; return -1; } else if(bytes==0) { 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; ImemData imem(ramBuff,bytes); //create imem record, set data/video to point to our in-memory video // channels = data.mImages.front().channels(); // You must create an instance of the VLC Library libvlc_instance_t * vlc; // You need a player to play media libvlc_media_player_t *mediaPlayer; // Media object to play. libvlc_media_t *media; // Configure options for this instance of VLC (global settings). // See VLC command line documentation for options. std::vector<const char*> options; std::vector<const char*>::iterator option; options.push_back("--no-video-title-show"); char imemDataArg[256]; sprintf(imemDataArg, "--imem-data=%#p", &imem); //point to our custom imem record - we will pass video data in imem-get() options.push_back(imemDataArg); char imemGetArg[256]; sprintf(imemGetArg, "--imem-get=%#p", MyImemGetCallback); options.push_back(imemGetArg); char imemReleaseArg[256]; sprintf(imemReleaseArg, "--imem-release=%#p", MyImemReleaseCallback); options.push_back(imemReleaseArg); options.push_back("--imem-cookie=\"h264\""); // Codec of data in memory for IMEM options.push_back("--imem-codec=h264"); // data: try to use ACCESS module to fully demux stream/file/data options.push_back("--imem-cat=4"); options.push_back("--verbose=2"); options.push_back("--demux=h264"); // Load the VLC engine vlc = libvlc_new (int(options.size()), options.data()); // Create a media item from file media = libvlc_media_new_location (vlc, "imem://"); // Configure any transcoding or streaming // options for the media source. options.clear(); // Set media options for(option = options.begin(); option != options.end(); option++) { libvlc_media_add_option(media, *option); } // Create a media player playing environment mediaPlayer = libvlc_media_player_new_from_media (media); // No need to keep the media now libvlc_media_release (media); // play the media_player libvlc_media_player_play (mediaPlayer); boost::this_thread::sleep(boost::posix_time::milliseconds(60000)); // Stop playing libvlc_media_player_stop (mediaPlayer); // Free the media_player libvlc_media_player_release (mediaPlayer); // Free vlc libvlc_release (vlc); // free(imem.video); //release // free(&imem); cout << "Done. Press Return." << endl ; cin.get(); cin.get(); return 0; }
This seems to be close to working, but unfortunately this is the output:
[0x214a6d8] main input debug: Creating an input for 'imem://'
[0x214a6d8] main input debug: using timeshift granularity of 50 MiB, in path '/tmp'
[0x214a6d8] main input debug: `imem://' gives access `imem' demux `' path `'
[0x214a6d8] main input debug: enforced demux ` h264'
[0x214a6d8] main input debug: creating demux: access='imem' demux='h264' location='' file='(null)'
[0x7f8bb0000e28] main demux debug: looking for access_demux module matching "imem": 20 candidates
[0x7f8bb0000e28] access_imem demux debug: Using get(0x404e1d), release(0x404e91), data(0x7ffe161b7d90), cookie("h264")
[0x7f8bb0000e28] main demux debug: no access_demux modules matched
[0x214a6d8] main input debug: creating access 'imem' location='', path='(null)'
[0x7f8bb0001978] main access debug: looking for access module matching "imem": 25 candidates
[0x7f8bb0001978] access_imem access debug: Using get(0x404e1d), release(0x404e91), data(0x7ffe161b7d90), cookie("h264")
[0x7f8bb0001978] main access debug: using access module "access_imem"
[0x7f8bb0000e28] main stream debug: Using block method for AStream*
[0x7f8bb0000e28] main stream debug: starting pre-buffering
[0x7f8bb0000e28] main stream error: cannot pre fill buffer
[0x7f8bb0001978] main access debug: removing module "access_imem"
[0x214a6d8] main input warning: cannot create a stream_t from access
Does anyone have an idea what might be going wrong??
Thanks!

Rémi Denis-Courmont
Developer
Developer
Posts: 15268
Joined: 07 Jun 2004 16:01
VLC version: master
Operating System: Linux
Contact:

Re: Using Imem to play h264 from memory

Postby Rémi Denis-Courmont » 07 Jul 2015 14:28

The log means the input stream is empty.

Using imem directly is not supported anyway. The official API is there https://www.videolan.org/developers/vlc ... 2b9b75d8e2
Rémi Denis-Courmont
https://www.remlab.net/
Private messages soliciting support will be systematically discarded

stumpsy
New Cone
New Cone
Posts: 3
Joined: 07 Jul 2015 12:54

Re: Using Imem to play h264 from memory

Postby stumpsy » 08 Jul 2015 12:08

Thanks Rémi, I will now attempt to use the API to play the video from memory.

stumpsy
New Cone
New Cone
Posts: 3
Joined: 07 Jul 2015 12:54

Re: Using Imem to play h264 from memory

Postby stumpsy » 09 Jul 2015 13:47

Wow finally got it working. Thanks for the help. A couple of hints to anyone else that wants to implement this:

- Mind carefully what the opaque pointer for each callback points to, I confused pointers to my raw video and container object.

-Although you can pass NULL when calling libvlc_media_new_callbacks(), I had to implement the seek callback int(* libvlc_media_seek_cb)(void *opaque, uint64_t offset) or I got lots of "Frame num gap ... ..." and decode_slide_header errors when trying to play the video.


Return to “Development around libVLC”

Who is online

Users browsing this forum: No registered users and 6 guests