При вызове QFileDialog::getOpenFileName
, и попытке преобразования QString
в char*
или же const char*
, происходит либо потеря данных, или что-то еще нехорошее, и VLC
отказывается воспринимать переданный MRL
как подходящую строку.
VlcPlayer.h
#ifndef VLCPLAYER_H
#define VLCPLAYER_H
#include <QWidget>
#include <QString>
#include <QFrame>
#include <QDebug>
#include <vlc/vlc.h>
class VlcPlayer : public QWidget
{
Q_OBJECT
public:
explicit VlcPlayer(QWidget *parent = nullptr);
~VlcPlayer();
int play();
void pause();
void stop();
bool init();
bool init(void *hwnd);
bool open(QString filename);
bool set_volume(int value);
int get_volume();
void set_mute(bool value);
bool is_muted();
private:
libvlc_instance_t *vlc_instance_;
libvlc_media_t *vlc_media_;
libvlc_media_player_t *vlc_media_player_;
private:
bool initialized_;
private:
const char* qstrtoc_str(QString &str);
signals:
public slots:
};
#endif // VLCPLAYER_H
VlcPlayer.cpp
#include "vlcplayer.h"
VlcPlayer::VlcPlayer(QWidget *parent) :
QWidget(parent),
vlc_instance_(nullptr),
vlc_media_(nullptr), vlc_media_player_(nullptr),
initialized_(false)
{
}
bool VlcPlayer::init()
{
return init(nullptr);
}
bool VlcPlayer::init(void * hwnd)
{
const char *vlc_argv[] =
{
#if _DEBUG
"--extraintf=logger",
"--verbose=2"
#else
"--quiet"
#endif
};
if(initialized_)
{
qDebug() << "VLCPlayer -> Already initialized\n";
return true;
}
vlc_instance_ = libvlc_new(sizeof(vlc_argv)/sizeof(*vlc_argv),vlc_argv);
if(!vlc_instance_)
{
qDebug() << "VLCPlayer -> Unable to initialize vlc_instance_\n";
initialized_ = false;
return false;
}
vlc_media_player_ = libvlc_media_player_new(vlc_instance_);
if(!vlc_media_player_)
{
qDebug() << "VLCPlayer -> Unable to initialize vlc_media_player_\n";
initialized_ = false;
return false;
}
if(hwnd != nullptr)
{
libvlc_media_player_set_hwnd(vlc_media_player_, hwnd);
}
initialized_ = true;
return true;
}
int VlcPlayer::play()
{
if(!initialized_)
{
qDebug() << "VLCPlayer -> play() called before init()\n";
return 0x4;
}
return libvlc_media_player_play(vlc_media_player_);
}
bool VlcPlayer::open(QString filename)
{
stop();
if(!initialized_)
{
qDebug() << "VLCPlayer -> open(...) called before init()\n";
return false;
}
if(vlc_media_)
{
qDebug() << "VLCPlayer -> media not null, release it\n";
libvlc_media_release(vlc_media_);
}
vlc_media_ = libvlc_media_new_path(vlc_instance_, qstrtoc_str(filename));
libvlc_media_player_set_media(vlc_media_player_, vlc_media_);
libvlc_media_release(vlc_media_);
return true;
}
bool VlcPlayer::set_volume(int value)
{
return libvlc_audio_set_volume(vlc_media_player_, value);
}
int VlcPlayer::get_volume()
{
if(!initialized_)
{
qDebug() << "VLCPlayer -> get_volume() called before init()\n";
return false;
}
return libvlc_audio_get_volume(vlc_media_player_);
}
void VlcPlayer::set_mute(bool value)
{
libvlc_audio_set_mute(vlc_media_player_, value);
}
bool VlcPlayer::is_muted()
{
return libvlc_audio_get_mute(vlc_media_player_);
}
const char *VlcPlayer::qstrtoc_str(QString &str)
{
// как тут не крути, vlc отказывается принимать данные как подходящие
// QByteArray ba = str.toLatin1();
// const char* result = ba.constData();
QByteArray ba = str.toUtf8();
const char* result = ba.data();
return result;
}
void VlcPlayer::pause()
{
if(!initialized_)
{
qDebug() << "VLCPlayer -> pause() called before init()\n";
return;
}
libvlc_media_player_pause(vlc_media_player_);
}
void VlcPlayer::stop()
{
if(!initialized_)
{
qDebug() << "VLCPlayer -> stop() called before init()\n";
return;
}
libvlc_media_player_stop(vlc_media_player_);
}
VlcPlayer::~VlcPlayer()
{
if(vlc_media_player_)
{
if(libvlc_media_player_is_playing(vlc_media_player_))
{
libvlc_media_player_stop(vlc_media_player_);
}
}
if(vlc_media_)
{
libvlc_media_release(vlc_media_);
vlc_media_ = nullptr;
}
if(vlc_media_player_)
{
libvlc_media_player_release(vlc_media_player_);
vlc_media_player_ = nullptr;
}
if(vlc_instance_)
{
libvlc_release(vlc_instance_);
vlc_instance_ = nullptr;
}
initialized_ = false;
}
Методы которые были использованы, которые не сработали:
QString qfilename = QFileDialog::getOpenFileName(this);
const char* filename = str.toStdString().c_str();
---
QString str = QFileDialog::getOpenFileName(this);
QByteArray qstrbyte = str.toLatin1();
char* filename = qstrbyte.data();
и так далее с utf8 и множетсвом других методов, которые доступны в классе QString
Можно как то это решить? Перечитал кучу сайтов с подобной проблемой.
Вывод vlc в окно дебага:
core audio output debug: removing module "directsound"
core input debug: Creating an input for '????????????????????????????????????'
core input debug: using timeshift granularity of 50 MiB, in path 'C:\Users\Username\AppData\Local\Temp'
core input debug: `file:///C:/Users/Username/Documents/QTProjects/build-libvlc_test-Desktop_Qt_5_9_1_MSVC2015_32bit-Debug/libvlc_test/%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD' gives access `file' demux `' path `/C:/Users/Username/Documents/QTProjects/build-libvlc_test-Desktop_Qt_5_9_1_MSVC2015_32bit-Debug/libvlc_test/%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD'
core input debug: specified demux `any'
core input debug: creating demux: access='file' demux='any' location='/C:/Users/Username/Documents/QTProjects/build-libvlc_test-Desktop_Qt_5_9_1_MSVC2015_32bit-Debug/libvlc_test/%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD' file='C:\Users\Username\Documents\QTProjects\build-libvlc_test-Desktop_Qt_5_9_1_MSVC2015_32bit-Debug\libvlc_test\????????????????????????????????????'
core demux debug: looking for access_demux module matching "file": 12 candidates
core demux debug: no access_demux modules matched
core input debug: creating access 'file' location='/C:/Users/Username/Documents/QTProjects/build-libvlc_test-Desktop_Qt_5_9_1_MSVC2015_32bit-Debug/libvlc_test/%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD', path='C:\Users\Username\Documents\QTProjects\build-libvlc_test-Desktop_Qt_5_9_1_MSVC2015_32bit-Debug\libvlc_test\????????????????????????????????????'
core access debug: looking for access module matching "file": 21 candidates
filesystem access debug: opening file `C:\Users\Username\Documents\QTProjects\build-libvlc_test-Desktop_Qt_5_9_1_MSVC2015_32bit-Debug\libvlc_test\????????????????????????????????????'
filesystem access error: cannot open file C:\Users\Username\Documents\QTProjects\build-libvlc_test-Desktop_Qt_5_9_1_MSVC2015_32bit-Debug\libvlc_test\???????????????????????????????????? (No such file or directory)
core access error: File reading failed
core access error: VLC could not open the file "C:\Users\Username\Documents\QTProjects\build-libvlc_test-Desktop_Qt_5_9_1_MSVC2015_32bit-Debug\libvlc_test\????????????????????????????????????" (No such file or directory).
core access debug: no access modules matched
core input error: open of `file:///C:/Users/Username/Documents/QTProjects/build-libvlc_test-Desktop_Qt_5_9_1_MSVC2015_32bit-Debug/libvlc_test/%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD' failed
core input error: Your input can't be opened
core input error: VLC is unable to open the MRL 'file:///C:/Users/Username/Documents/QTProjects/build-libvlc_test-Desktop_Qt_5_9_1_MSVC2015_32bit-Debug/libvlc_test/%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD%DD'. Check the log for details.
Если посмотреть на на описание метода QByteArray::data
, то там можно найти это:
The pointer remains valid as long as the byte array isn't reallocated or destroyed.
Таким образом этот метод
const char *VlcPlayer::qstrtoc_str(QString &str){
QByteArray ba = str.toUtf8();
const char* result = ba.data();
return result;
}
возвращает указатель на освобожденную память.
Попробуйте заменить это:
vlc_media_ = libvlc_media_new_path(vlc_instance_, qstrtoc_str(filename));
на это:
vlc_media_ = libvlc_media_new_path(vlc_instance_, filename.toUtf8().data());
Как я и предположил в комментарии, используется указатель на уже уничтоженный объект.
const char *VlcPlayer::qstrtoc_str(QString &str)
{
QByteArray ba = str.toUtf8(); // ba существует только внутри функции
const char* result = ba.data();
return result; // возврат указателя на данные, связанные с локальным объектом
}
При выходе из функции объект ba
уничтожается, и указатель, возвращенный через вызов data()
адресует уже освобожденные данные.
В качестве решения, я бы предложил либо использовать std::string вместо сырых указателей, в качестве возвращаемого значения.
Будет примерно так:
std::string VlcPlayer::qstrtostr(const QString &str)
{
return str.toUtf8().constData();
}
При вызове:
libvlc_media_new_path(vlc_instance_, qstrtostr(filename).c_str());
Данный ответ будет очень занятным по отношению Qt 5.9.1
и libvlc 2.2.6
Проблема хранится не в классе QString
а в самой библиотеке libvlc.dll
Дело в том что она не понимает путь к файлу, если это система Windows и в пути содержатся не бэкслешы. Т.е. если мы заменим все слеши на бекслешы, то vlc считает путь правильным, и воспроизводит заданный файл.
И так, воспользуемся методом из данного вопроса Replace part of a string with another string, и заменим все слеши на бекслешы.
После перепишем метод std::string VlcPlayer::qstrtoc_str(const QString &str);
std::string VlcPlayer::qstrtoc_str(const QString &str)
{
std::string filepath = str.toStdString();
replaceAll(filepath, "/", "\\");
return filepath;
}
Теперь можно спокойно открывать любой локальный путь.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Какие существуют виды рекламных бордов и как выбрать подходящий?
Задача есть, нужно отдельно задать функцию со сменным числом параметров, а потом ее вызвать
Использую карусель Slick в одном из проектовПоставил в неё пять слайдов — четыре картинки и видео