mirror of https://github.com/procxx/kepka.git
Stopping video sound when closing mediaview (destroying Clip::Reader).
Fixed launching video with sound while song is playing.
This commit is contained in:
parent
616d08255c
commit
99b15719cf
|
@ -636,8 +636,14 @@ void AudioPlayer::stop(AudioMsgId::Type type) {
|
||||||
AudioMsgId current;
|
AudioMsgId current;
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&playerMutex);
|
QMutexLocker lock(&playerMutex);
|
||||||
current = dataForType(type)->audio;
|
auto data = dataForType(type);
|
||||||
|
t_assert(data != nullptr);
|
||||||
|
|
||||||
|
current = data->audio;
|
||||||
fadedStop(type);
|
fadedStop(type);
|
||||||
|
if (type == AudioMsgId::Type::Video) {
|
||||||
|
data->clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (current) emit updated(current);
|
if (current) emit updated(current);
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,8 +235,9 @@ AudioPlayerLoader::ReadResult FFMpegLoader::readMore(QByteArray &result, int64 &
|
||||||
if (res != AVERROR_EOF) {
|
if (res != AVERROR_EOF) {
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
LOG(("Audio Error: Unable to av_read_frame() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to av_read_frame() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
return ReadResult::Error;
|
||||||
}
|
}
|
||||||
return ReadResult::Error;
|
return ReadResult::EndOfFile;
|
||||||
}
|
}
|
||||||
if (avpkt.stream_index == streamId) {
|
if (avpkt.stream_index == streamId) {
|
||||||
av_frame_unref(frame);
|
av_frame_unref(frame);
|
||||||
|
|
|
@ -37,6 +37,7 @@ public:
|
||||||
NotYet,
|
NotYet,
|
||||||
Ok,
|
Ok,
|
||||||
Wait,
|
Wait,
|
||||||
|
EndOfFile,
|
||||||
};
|
};
|
||||||
virtual ReadResult readMore(QByteArray &samples, int64 &samplesCount) = 0;
|
virtual ReadResult readMore(QByteArray &samples, int64 &samplesCount) = 0;
|
||||||
|
|
||||||
|
|
|
@ -30,14 +30,14 @@ AudioPlayerLoaders::AudioPlayerLoaders(QThread *thread) : _fromVideoNotify(this,
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioPlayerLoaders::feedFromVideo(VideoSoundPart &&part) {
|
void AudioPlayerLoaders::feedFromVideo(VideoSoundPart &&part) {
|
||||||
bool invoke = true;
|
bool invoke = false;
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&_fromVideoMutex);
|
QMutexLocker lock(&_fromVideoMutex);
|
||||||
if (_fromVideoPlayId == part.videoPlayId) {
|
if (_fromVideoPlayId == part.videoPlayId) {
|
||||||
_fromVideoQueue.enqueue(*part.packet);
|
_fromVideoQueue.enqueue(*part.packet);
|
||||||
|
invoke = true;
|
||||||
} else {
|
} else {
|
||||||
av_packet_unref(part.packet);
|
FFMpeg::freePacket(part.packet);
|
||||||
invoke = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (invoke) {
|
if (invoke) {
|
||||||
|
@ -77,7 +77,7 @@ AudioPlayerLoaders::~AudioPlayerLoaders() {
|
||||||
void AudioPlayerLoaders::clearFromVideoQueue() {
|
void AudioPlayerLoaders::clearFromVideoQueue() {
|
||||||
auto queue = createAndSwap(_fromVideoQueue);
|
auto queue = createAndSwap(_fromVideoQueue);
|
||||||
for (auto &packet : queue) {
|
for (auto &packet : queue) {
|
||||||
av_packet_unref(&packet);
|
FFMpeg::freePacket(&packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ void AudioPlayerLoaders::onLoad(const AudioMsgId &audio) {
|
||||||
loadData(audio, 0);
|
loadData(audio, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioPlayerLoaders::loadData(const AudioMsgId &audio, qint64 position) {
|
void AudioPlayerLoaders::loadData(AudioMsgId audio, qint64 position) {
|
||||||
SetupError err = SetupNoErrorStarted;
|
SetupError err = SetupNoErrorStarted;
|
||||||
auto type = audio.type();
|
auto type = audio.type();
|
||||||
AudioPlayerLoader *l = setupLoader(audio, err, position);
|
AudioPlayerLoader *l = setupLoader(audio, err, position);
|
||||||
|
@ -160,10 +160,13 @@ void AudioPlayerLoaders::loadData(const AudioMsgId &audio, qint64 position) {
|
||||||
}
|
}
|
||||||
finished = true;
|
finished = true;
|
||||||
break;
|
break;
|
||||||
|
} else if (res == Result::EndOfFile) {
|
||||||
|
finished = true;
|
||||||
|
break;
|
||||||
} else if (res == Result::Ok) {
|
} else if (res == Result::Ok) {
|
||||||
errAtStart = false;
|
errAtStart = false;
|
||||||
} else if (res == Result::Wait) {
|
} else if (res == Result::Wait) {
|
||||||
waiting = samples.isEmpty();// (samples.size() < AudioVoiceMsgBufferSize);
|
waiting = (samples.size() < AudioVoiceMsgBufferSize);
|
||||||
if (waiting) {
|
if (waiting) {
|
||||||
l->saveDecodedSamples(&samples, &samplesCount);
|
l->saveDecodedSamples(&samples, &samplesCount);
|
||||||
}
|
}
|
||||||
|
@ -335,11 +338,12 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(const AudioMsgId &audio, Setu
|
||||||
switch (audio.type()) {
|
switch (audio.type()) {
|
||||||
case AudioMsgId::Type::Voice: l = _audioLoader.get(); isGoodId = (_audio == audio); break;
|
case AudioMsgId::Type::Voice: l = _audioLoader.get(); isGoodId = (_audio == audio); break;
|
||||||
case AudioMsgId::Type::Song: l = _songLoader.get(); isGoodId = (_song == audio); break;
|
case AudioMsgId::Type::Song: l = _songLoader.get(); isGoodId = (_song == audio); break;
|
||||||
case AudioMsgId::Type::Video: l = _videoLoader.get(); isGoodId = (_song == audio); break;
|
case AudioMsgId::Type::Video: l = _videoLoader.get(); isGoodId = (_video == audio); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l && (!isGoodId || !l->check(data->file, data->data))) {
|
if (l && (!isGoodId || !l->check(data->file, data->data))) {
|
||||||
clear(audio.type());
|
clear(audio.type());
|
||||||
|
l = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!l) {
|
if (!l) {
|
||||||
|
@ -351,6 +355,12 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(const AudioMsgId &audio, Setu
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio.type() == AudioMsgId::Type::Video) {
|
if (audio.type() == AudioMsgId::Type::Video) {
|
||||||
|
if (!data->videoData) {
|
||||||
|
data->state = AudioPlayerStoppedAtError;
|
||||||
|
emit error(audio);
|
||||||
|
LOG(("Audio Error: video sound data not ready"));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
_videoLoader = std_::make_unique<ChildFFMpegLoader>(std_::move(data->videoData));
|
_videoLoader = std_::make_unique<ChildFFMpegLoader>(std_::move(data->videoData));
|
||||||
l = _videoLoader.get();
|
l = _videoLoader.get();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -78,7 +78,7 @@ private:
|
||||||
SetupErrorLoadedFull = 2,
|
SetupErrorLoadedFull = 2,
|
||||||
SetupNoErrorStarted = 3,
|
SetupNoErrorStarted = 3,
|
||||||
};
|
};
|
||||||
void loadData(const AudioMsgId &audio, qint64 position);
|
void loadData(AudioMsgId audio, qint64 position);
|
||||||
AudioPlayerLoader *setupLoader(const AudioMsgId &audio, SetupError &err, qint64 position);
|
AudioPlayerLoader *setupLoader(const AudioMsgId &audio, SetupError &err, qint64 position);
|
||||||
AudioPlayer::AudioMsg *checkLoader(AudioMsgId::Type type);
|
AudioPlayer::AudioMsg *checkLoader(AudioMsgId::Type type);
|
||||||
|
|
||||||
|
|
|
@ -113,18 +113,23 @@ bool ChildFFMpegLoader::open(qint64 position) {
|
||||||
|
|
||||||
AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(QByteArray &result, int64 &samplesAdded) {
|
AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(QByteArray &result, int64 &samplesAdded) {
|
||||||
if (_queue.isEmpty()) {
|
if (_queue.isEmpty()) {
|
||||||
return ReadResult::Wait;
|
return _eofReached ? ReadResult::EndOfFile : ReadResult::Wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
av_frame_unref(_frame);
|
av_frame_unref(_frame);
|
||||||
int got_frame = 0;
|
int got_frame = 0;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
auto packet = _queue.dequeue();
|
auto packet = _queue.dequeue();
|
||||||
|
_eofReached = FFMpeg::isNullPacket(packet);
|
||||||
|
if (_eofReached) {
|
||||||
|
return ReadResult::EndOfFile;
|
||||||
|
}
|
||||||
|
|
||||||
if ((res = avcodec_decode_audio4(_parentData->context, _frame, &got_frame, &packet)) < 0) {
|
if ((res = avcodec_decode_audio4(_parentData->context, _frame, &got_frame, &packet)) < 0) {
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
LOG(("Audio Error: Unable to avcodec_decode_audio4() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to avcodec_decode_audio4() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
|
||||||
av_packet_unref(&packet);
|
FFMpeg::freePacket(&packet);
|
||||||
if (res == AVERROR_INVALIDDATA) {
|
if (res == AVERROR_INVALIDDATA) {
|
||||||
return ReadResult::NotYet; // try to skip bad packet
|
return ReadResult::NotYet; // try to skip bad packet
|
||||||
}
|
}
|
||||||
|
@ -143,7 +148,7 @@ AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(QByteArray &result, in
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
|
||||||
av_packet_unref(&packet);
|
FFMpeg::freePacket(&packet);
|
||||||
return ReadResult::Error;
|
return ReadResult::Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +156,7 @@ AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(QByteArray &result, in
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
|
||||||
av_packet_unref(&packet);
|
FFMpeg::freePacket(&packet);
|
||||||
return ReadResult::Error;
|
return ReadResult::Error;
|
||||||
}
|
}
|
||||||
int32 resultLen = av_samples_get_buffer_size(0, AudioToChannels, res, AudioToFormat, 1);
|
int32 resultLen = av_samples_get_buffer_size(0, AudioToChannels, res, AudioToFormat, 1);
|
||||||
|
@ -162,7 +167,7 @@ AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(QByteArray &result, in
|
||||||
samplesAdded += _frame->nb_samples;
|
samplesAdded += _frame->nb_samples;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
av_packet_unref(&packet);
|
FFMpeg::freePacket(&packet);
|
||||||
return ReadResult::Ok;
|
return ReadResult::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +179,7 @@ void ChildFFMpegLoader::enqueuePackets(QQueue<AVPacket> &packets) {
|
||||||
ChildFFMpegLoader::~ChildFFMpegLoader() {
|
ChildFFMpegLoader::~ChildFFMpegLoader() {
|
||||||
auto queue = createAndSwap(_queue);
|
auto queue = createAndSwap(_queue);
|
||||||
for (auto &packet : queue) {
|
for (auto &packet : queue) {
|
||||||
av_packet_unref(&packet);
|
FFMpeg::freePacket(&packet);
|
||||||
}
|
}
|
||||||
if (_dstSamplesData) {
|
if (_dstSamplesData) {
|
||||||
if (_dstSamplesData[0]) {
|
if (_dstSamplesData[0]) {
|
||||||
|
|
|
@ -44,6 +44,24 @@ struct VideoSoundPart {
|
||||||
uint64 videoPlayId = 0;
|
uint64 videoPlayId = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace FFMpeg {
|
||||||
|
|
||||||
|
inline bool isNullPacket(const AVPacket &packet) {
|
||||||
|
return packet.data == nullptr && packet.size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isNullPacket(const AVPacket *packet) {
|
||||||
|
return isNullPacket(*packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void freePacket(AVPacket *packet) {
|
||||||
|
if (!isNullPacket(packet)) {
|
||||||
|
av_packet_unref(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace FFMpeg
|
||||||
|
|
||||||
class ChildFFMpegLoader : public AudioPlayerLoader {
|
class ChildFFMpegLoader : public AudioPlayerLoader {
|
||||||
public:
|
public:
|
||||||
ChildFFMpegLoader(std_::unique_ptr<VideoSoundData> &&data);
|
ChildFFMpegLoader(std_::unique_ptr<VideoSoundData> &&data);
|
||||||
|
@ -72,10 +90,15 @@ public:
|
||||||
uint64 playId() const {
|
uint64 playId() const {
|
||||||
return _parentData->videoPlayId;
|
return _parentData->videoPlayId;
|
||||||
}
|
}
|
||||||
|
bool eofReached() const {
|
||||||
|
return _eofReached;
|
||||||
|
}
|
||||||
|
|
||||||
~ChildFFMpegLoader();
|
~ChildFFMpegLoader();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool _eofReached = false;
|
||||||
|
|
||||||
int32 _sampleSize = 2 * sizeof(uint16);
|
int32 _sampleSize = 2 * sizeof(uint16);
|
||||||
int32 _format = AL_FORMAT_STEREO16;
|
int32 _format = AL_FORMAT_STEREO16;
|
||||||
int32 _srcRate = AudioVoiceMsgFrequency;
|
int32 _srcRate = AudioVoiceMsgFrequency;
|
||||||
|
|
|
@ -107,12 +107,11 @@ bool FFMpegReaderImplementation::readNextFrame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eofReached) {
|
if (eofReached) {
|
||||||
|
clearPacketQueue();
|
||||||
if (_mode == Mode::Normal) {
|
if (_mode == Mode::Normal) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearPacketQueue();
|
|
||||||
|
|
||||||
if ((res = avformat_seek_file(_fmtContext, _streamId, std::numeric_limits<int64_t>::min(), 0, std::numeric_limits<int64_t>::max(), 0)) < 0) {
|
if ((res = avformat_seek_file(_fmtContext, _streamId, std::numeric_limits<int64_t>::min(), 0, std::numeric_limits<int64_t>::max(), 0)) < 0) {
|
||||||
if ((res = av_seek_frame(_fmtContext, _streamId, 0, AVSEEK_FLAG_BYTE)) < 0) {
|
if ((res = av_seek_frame(_fmtContext, _streamId, 0, AVSEEK_FLAG_BYTE)) < 0) {
|
||||||
if ((res = av_seek_frame(_fmtContext, _streamId, 0, AVSEEK_FLAG_FRAME)) < 0) {
|
if ((res = av_seek_frame(_fmtContext, _streamId, 0, AVSEEK_FLAG_FRAME)) < 0) {
|
||||||
|
@ -294,6 +293,9 @@ int FFMpegReaderImplementation::duration() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
FFMpegReaderImplementation::~FFMpegReaderImplementation() {
|
FFMpegReaderImplementation::~FFMpegReaderImplementation() {
|
||||||
|
if (_mode == Mode::Normal && _audioStreamId >= 0) {
|
||||||
|
audioPlayer()->stop(AudioMsgId::Type::Video);
|
||||||
|
}
|
||||||
if (_frameRead) {
|
if (_frameRead) {
|
||||||
av_frame_unref(_frame);
|
av_frame_unref(_frame);
|
||||||
_frameRead = false;
|
_frameRead = false;
|
||||||
|
@ -321,6 +323,13 @@ FFMpegReaderImplementation::PacketResult FFMpegReaderImplementation::readPacket(
|
||||||
int res = 0;
|
int res = 0;
|
||||||
if ((res = av_read_frame(_fmtContext, &packet)) < 0) {
|
if ((res = av_read_frame(_fmtContext, &packet)) < 0) {
|
||||||
if (res == AVERROR_EOF) {
|
if (res == AVERROR_EOF) {
|
||||||
|
if (_audioStreamId >= 0) {
|
||||||
|
// queue terminating packet to audio player
|
||||||
|
VideoSoundPart part;
|
||||||
|
part.packet = &_packetNull;
|
||||||
|
part.videoPlayId = _playId;
|
||||||
|
audioPlayer()->feedFromVideo(std_::move(part));
|
||||||
|
}
|
||||||
return PacketResult::EndOfFile;
|
return PacketResult::EndOfFile;
|
||||||
}
|
}
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
|
@ -335,17 +344,8 @@ FFMpegReaderImplementation::PacketResult FFMpegReaderImplementation::readPacket(
|
||||||
int64 packetMs = (packetPts * 1000LL * _fmtContext->streams[packet.stream_index]->time_base.num) / _fmtContext->streams[packet.stream_index]->time_base.den;
|
int64 packetMs = (packetPts * 1000LL * _fmtContext->streams[packet.stream_index]->time_base.num) / _fmtContext->streams[packet.stream_index]->time_base.den;
|
||||||
_lastReadPacketMs = packetMs;
|
_lastReadPacketMs = packetMs;
|
||||||
|
|
||||||
//AVPacket packetForQueue;
|
|
||||||
//av_init_packet(&packetForQueue);
|
|
||||||
//if ((res = av_packet_ref(&packetForQueue, &packet)) < 0) {
|
|
||||||
// char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
|
||||||
// LOG(("Gif Error: Unable to av_packet_ref() %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
|
||||||
// return PacketResult::Error;
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (videoPacket) {
|
if (videoPacket) {
|
||||||
_packetQueue.enqueue(packet);
|
_packetQueue.enqueue(packet);
|
||||||
//_packetQueue.enqueue(packetForQueue);
|
|
||||||
} else if (audioPacket) {
|
} else if (audioPacket) {
|
||||||
// queue packet to audio player
|
// queue packet to audio player
|
||||||
VideoSoundPart part;
|
VideoSoundPart part;
|
||||||
|
@ -356,7 +356,6 @@ FFMpegReaderImplementation::PacketResult FFMpegReaderImplementation::readPacket(
|
||||||
} else {
|
} else {
|
||||||
av_packet_unref(&packet);
|
av_packet_unref(&packet);
|
||||||
}
|
}
|
||||||
//av_packet_unref(&packet);
|
|
||||||
return PacketResult::Ok;
|
return PacketResult::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -222,14 +222,14 @@ bool MediaView::gifShown() const {
|
||||||
_gif->start(_gif->width(), _gif->height(), _gif->width(), _gif->height(), false);
|
_gif->start(_gif->width(), _gif->height(), _gif->width(), _gif->height(), false);
|
||||||
const_cast<MediaView*>(this)->_current = QPixmap();
|
const_cast<MediaView*>(this)->_current = QPixmap();
|
||||||
}
|
}
|
||||||
return _gif->state() != Media::Clip::State::Error;
|
return true;// _gif->state() != Media::Clip::State::Error;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::stopGif() {
|
void MediaView::stopGif() {
|
||||||
delete _gif;
|
delete _gif;
|
||||||
_gif = 0;
|
_gif = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::documentUpdated(DocumentData *doc) {
|
void MediaView::documentUpdated(DocumentData *doc) {
|
||||||
|
@ -506,8 +506,7 @@ void MediaView::clearData() {
|
||||||
_a_state.stop();
|
_a_state.stop();
|
||||||
}
|
}
|
||||||
if (!_animOpacities.isEmpty()) _animOpacities.clear();
|
if (!_animOpacities.isEmpty()) _animOpacities.clear();
|
||||||
delete _gif;
|
stopGif();
|
||||||
_gif = nullptr;
|
|
||||||
delete _menu;
|
delete _menu;
|
||||||
_menu = nullptr;
|
_menu = nullptr;
|
||||||
_history = _migrated = nullptr;
|
_history = _migrated = nullptr;
|
||||||
|
|
Loading…
Reference in New Issue