Using Imem to play h264 from memory
Posted: 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:
This seems to be close to working, but unfortunately this is the output:
Thanks!
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;
}
Does anyone have an idea what might be going wrong??[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
Thanks!