Take a look at my Qt example below, it works. Actually I didn't want to read the whole file and store it in the ram. So I implemented the MediaDescriptor because I will implement a decryption logic in it to read from encrypted files. Btw I used libvlc 3.0.6 x64 pre-built libraries, looks working very well.
MediaDescriptor.h
#pragma once
#include <QObject>
#include <fstream>
class MediaDescriptor : public QObject
{
Q_OBJECT
public:
MediaDescriptor(QString mediaFilePath);
~MediaDescriptor();
bool tryOpen();
uint64_t getMediaLength();
uint64_t getMediaBytes(unsigned char *buffer, uint64_t length);
void setSeek(uint64_t seek);
private:
QString m_mediaFilePath;
std::ifstream *m_mediaFile;
uint64_t m_mediaLength;
uint64_t m_seek;
};
MediaDescriptor.cpp
#include "MediaDescriptor.h"
MediaDescriptor::MediaDescriptor(QString mediaFilePath)
: m_mediaFilePath(mediaFilePath), m_mediaFile(nullptr), m_mediaLength(0), m_seek(0)
{
}
MediaDescriptor::~MediaDescriptor()
{
if (m_mediaFile)
{
m_mediaFile->close();
delete m_mediaFile;
}
}
bool MediaDescriptor::tryOpen()
{
m_mediaFile = new std::ifstream(m_mediaFilePath.toStdString().c_str(), std::ios::binary | std::ios::ate);
if (m_mediaFile->is_open())
{
m_mediaFile->seekg(0, m_mediaFile->end);
m_mediaLength = m_mediaFile->tellg();
return true;
}
delete m_mediaFile;
return false;
}
uint64_t MediaDescriptor::getMediaLength()
{
return m_mediaLength;
}
uint64_t MediaDescriptor::getMediaBytes(unsigned char *buffer, uint64_t length)
{
// to do: decrytion logic
if (m_mediaFile->is_open())
{
uint64_t len = length;
if (m_seek + len > m_mediaLength)
len = (size_t)(m_mediaLength - m_seek);
if (len > 0)
{
m_mediaFile->seekg(m_seek);
m_mediaFile->read((char*)&buffer[0], len);
m_seek += len;
}
return len;
}
return -1;
}
void MediaDescriptor::setSeek(uint64_t seek)
{
m_seek = seek;
}
VLCHelper.h
#pragma once
#include <QObject>
#include <QWidget>
#include <QTime>
#include <mutex>
#include "vlc/vlc.h"
#include "MediaDescriptor.h"
class VLCHelper : public QObject
{
Q_OBJECT
public:
~VLCHelper();
static VLCHelper& getInstance();
int vlcMediaOpenCallback(void* opaque, void** datap, uint64_t* sizep);
int vlcMediaReadCallback(void *opaque, unsigned char* buf, size_t len);
int vlcMediaSeekCallback(void *opaque, uint64_t offset);
void vlcMediaCloseCallback(void *opaque);
void initMedia(MediaDescriptor &mediaDescriptor, QWidget *output = nullptr, int volume = 100, bool repeat = false);
void destroyMedia();
bool isMediaValid();
Q_INVOKABLE void playPauseMedia(bool play);
bool isMediaPlaying();
Q_INVOKABLE void stopMedia();
void setRepeatMedia(bool repeat);
bool getRepeatMedia();
void setMediaPosition(float position);
float getMediaPosition();
QTime getMediaTime();
QTime getMediaTotalTime();
void setMediaVolume(int volume);
int getMediaVolume();
signals:
void mediaEOFReached();
void error(QString error);
private:
VLCHelper();
std::mutex m_callbackMutex;
libvlc_instance_t *m_vlcInstance;
libvlc_media_t *m_vlcMedia;
libvlc_media_player_t *m_vlcMediaPlayer;
bool m_repeat;
bool m_stopRequested;
MediaDescriptor *m_mediaDescriptor;
QWidget *m_output;
};
VLCHelper.cpp
#include "VLCHelper.h"
#pragma region Callback Wrappers
extern "C" int vlcMediaOpenCallbackGateway(void* opaque, void** datap, uint64_t* sizep)
{
return VLCHelper::getInstance().vlcMediaOpenCallback(opaque, datap, sizep);
}
extern "C" int vlcMediaReadCallbackGateway(void *opaque, unsigned char* buf, size_t len)
{
return VLCHelper::getInstance().vlcMediaReadCallback(opaque, buf, len);
}
extern "C" int vlcMediaSeekCallbackGateway(void *opaque, uint64_t offset)
{
return VLCHelper::getInstance().vlcMediaSeekCallback(opaque, offset);
}
extern "C" void vlcMediaCloseCallbackGateway(void *opaque)
{
VLCHelper::getInstance().vlcMediaCloseCallback(opaque);
}
#pragma endregion
VLCHelper::VLCHelper()
: QObject(nullptr),
m_vlcInstance(nullptr),
m_vlcMedia(nullptr),
m_vlcMediaPlayer(nullptr),
m_repeat(false),
m_stopRequested(false)
{
}
VLCHelper::~VLCHelper()
{
}
VLCHelper& VLCHelper::getInstance()
{
static VLCHelper ins;
return ins;
}
void VLCHelper::initMedia(MediaDescriptor &mediaDescriptor, QWidget *output, int volume, bool repeat)
{
m_mediaDescriptor = &mediaDescriptor;
m_output = output;
m_repeat = repeat;
m_vlcInstance = libvlc_new(0, NULL);
m_vlcMedia = libvlc_media_new_callbacks(
m_vlcInstance,
vlcMediaOpenCallbackGateway,
vlcMediaReadCallbackGateway,
vlcMediaSeekCallbackGateway,
vlcMediaCloseCallbackGateway,
0
);
m_vlcMediaPlayer = libvlc_media_player_new_from_media(m_vlcMedia);
#if defined(Q_OS_WIN)
libvlc_media_player_set_hwnd(m_vlcMediaPlayer, output ? (void*)output->winId() : nullptr);
#elif defined(Q_OS_MAC)
libvlc_media_player_set_nsobject(m_vlcMediaPlayer, output ? (void*)output->winId() : nullptr);
#elif defined(Q_OS_LINUX)
libvlc_media_player_set_xwindow(m_vlcMediaPlayer, output ? (void*)output->winId() : nullptr);
#endif
libvlc_audio_set_volume(m_vlcMediaPlayer, volume);
m_mediaDescriptor->setSeek(0);
}
void VLCHelper::destroyMedia()
{
if (!m_vlcInstance)
return;
if (m_vlcMediaPlayer)
{
libvlc_media_player_stop(m_vlcMediaPlayer);
libvlc_media_player_release(m_vlcMediaPlayer);
m_vlcMediaPlayer = nullptr;
}
libvlc_release(m_vlcInstance);
m_vlcInstance = nullptr;
}
bool VLCHelper::isMediaValid()
{
return m_vlcInstance && m_vlcMedia && m_vlcMediaPlayer;
}
void VLCHelper::playPauseMedia(bool play)
{
m_stopRequested = false;
if (isMediaValid())
play ? libvlc_media_player_play(m_vlcMediaPlayer) : libvlc_media_player_pause(m_vlcMediaPlayer);
else
emit error("TO DO");
}
bool VLCHelper::isMediaPlaying()
{
if (isMediaValid())
return libvlc_media_player_is_playing(m_vlcMediaPlayer);
return false;
}
void VLCHelper::stopMedia()
{
m_stopRequested = true;
if (isMediaValid())
libvlc_media_player_stop(m_vlcMediaPlayer);
else
emit error("TO DO");
}
void VLCHelper::setRepeatMedia(bool repeat)
{
m_repeat = repeat;
}
bool VLCHelper::getRepeatMedia()
{
return m_repeat;
}
void VLCHelper::setMediaPosition(float position)
{
if (isMediaValid())
libvlc_media_player_set_position(m_vlcMediaPlayer, position);
else
emit error("TO DO");
}
float VLCHelper::getMediaPosition()
{
if (isMediaValid())
return libvlc_media_player_get_position(m_vlcMediaPlayer);
else
emit error("TO DO");
return -1.0;
}
QTime VLCHelper::getMediaTime()
{
if (isMediaValid())
return QTime::fromMSecsSinceStartOfDay((int)libvlc_media_player_get_time(m_vlcMediaPlayer));
else
emit error("TO DO");
return QTime();
}
QTime VLCHelper::getMediaTotalTime()
{
if (isMediaValid())
return QTime::fromMSecsSinceStartOfDay((int)libvlc_media_player_get_length(m_vlcMediaPlayer));
else
emit error("TO DO");
return QTime();
}
void VLCHelper::setMediaVolume(int volume)
{
if (isMediaValid())
libvlc_audio_set_volume(m_vlcMediaPlayer, volume);
else
emit error("TO DO");
}
int VLCHelper::getMediaVolume()
{
if (isMediaValid())
return libvlc_audio_get_volume(m_vlcMediaPlayer);
else
emit error("TO DO");
return -1;
}
int VLCHelper::vlcMediaOpenCallback(void* opaque, void** datap, uint64_t* sizep)
{
std::lock_guard<std::mutex> lock(m_callbackMutex);
// optional, if comment out libvlc will trigger the 'vlcMediaReadCallback' as more often but for less buffer length
*sizep = m_mediaDescriptor->getMediaLength();
return 0;
}
int VLCHelper::vlcMediaReadCallback(void *opaque, unsigned char* buf, size_t len)
{
std::lock_guard<std::mutex> lock(m_callbackMutex);
return m_mediaDescriptor->getMediaBytes(buf, len);
}
int VLCHelper::vlcMediaSeekCallback(void *opaque, uint64_t offset)
{
std::lock_guard<std::mutex> lock(m_callbackMutex);
// optional, but important for some media types which holds meta data end of the file, for example: .mp4
m_mediaDescriptor->setSeek(offset);
return 0;
}
void VLCHelper::vlcMediaCloseCallback(void *opaque)
{
std::lock_guard<std::mutex> lock(m_callbackMutex);
m_mediaDescriptor->setSeek(0);
if (!m_stopRequested)
{
emit mediaEOFReached();
QMetaObject::invokeMethod(&getInstance(), "stopMedia");
if(m_repeat)
QMetaObject::invokeMethod(&getInstance(), "playPauseMedia", Q_ARG(bool, true));
}
}
And the usage in the player widget:
VLCHelper::getInstance().initMedia(*m_mediaDescriptor, ui.frame_video);
connect(&VLCHelper::getInstance(), SIGNAL(mediaEOFReached()), this, SLOT(vlcMediaEOFReached()));
connect(&VLCHelper::getInstance(), SIGNAL(error(QString)), this, SLOT(vlcError(QString)));
...
void PlayerWidget::on_pushButton_media_play_pause_clicked()
{
VLCHelper::getInstance().playPauseMedia(!VLCHelper::getInstance().isMediaPlaying());
}
void PlayerWidget::on_pushButton_media_stop_clicked()
{
VLCHelper::getInstance().stopMedia();
}
void PlayerWidget::timer_timeout()
{
bool isValid = VLCHelper::getInstance().isMediaValid();
if (isValid)
{
if (VLCHelper::getInstance().isMediaPlaying())
{
// update media position
ui.horizontalSlider_media_position->blockSignals(true);
ui.horizontalSlider_media_position->setValue((int)(VLCHelper::getInstance().getMediaPosition() * 1000.0f));
ui.horizontalSlider_media_position->blockSignals(false);
// update media volume
ui.horizontalSlider_media_volume->blockSignals(true);
ui.horizontalSlider_media_volume->setValue(VLCHelper::getInstance().getMediaVolume());
ui.horizontalSlider_media_volume->blockSignals(false);
// update media time
ui.label_media_time->setText(VLCHelper::getInstance().getMediaTime().toString());
// update media total time
ui.label_media_time_total->setText(VLCHelper::getInstance().getMediaTotalTime().toString());
}
}
ui.horizontalSlider_media_volume->setEnabled(isValid);
ui.pushButton_media_stop->setEnabled(isValid);
ui.pushButton_media_repeat->setEnabled(isValid);
}