QFileDialog имя расположение файла char*

295
19 сентября 2017, 08:34

При вызове 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.
Answer 1

Если посмотреть на на описание метода 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());
Answer 2

Как я и предположил в комментарии, используется указатель на уже уничтоженный объект.

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());
Answer 3

Данный ответ будет очень занятным по отношению 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;
}

Теперь можно спокойно открывать любой локальный путь.

READ ALSO
Написать и вызвать функцию с переменным количеством параметров

Написать и вызвать функцию с переменным количеством параметров

Задача есть, нужно отдельно задать функцию со сменным числом параметров, а потом ее вызвать

242
Одно действие по двум событиям в jQuery

Одно действие по двум событиям в jQuery

ajax запрос вызывается по двум действиям:

210
Как на мобильном спрятать слайд из Slick-карусели?

Как на мобильном спрятать слайд из Slick-карусели?

Использую карусель Slick в одном из проектовПоставил в неё пять слайдов — четыре картинки и видео

246