mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-03 04:47:58 +00:00
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;
|
||||
{
|
||||
QMutexLocker lock(&playerMutex);
|
||||
current = dataForType(type)->audio;
|
||||
auto data = dataForType(type);
|
||||
t_assert(data != nullptr);
|
||||
|
||||
current = data->audio;
|
||||
fadedStop(type);
|
||||
if (type == AudioMsgId::Type::Video) {
|
||||
data->clear();
|
||||
}
|
||||
}
|
||||
if (current) emit updated(current);
|
||||
}
|
||||
|
@ -235,8 +235,9 @@ AudioPlayerLoader::ReadResult FFMpegLoader::readMore(QByteArray &result, int64 &
|
||||
if (res != AVERROR_EOF) {
|
||||
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)));
|
||||
return ReadResult::Error;
|
||||
}
|
||||
return ReadResult::Error;
|
||||
return ReadResult::EndOfFile;
|
||||
}
|
||||
if (avpkt.stream_index == streamId) {
|
||||
av_frame_unref(frame);
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
NotYet,
|
||||
Ok,
|
||||
Wait,
|
||||
EndOfFile,
|
||||
};
|
||||
virtual ReadResult readMore(QByteArray &samples, int64 &samplesCount) = 0;
|
||||
|
||||
|
@ -30,14 +30,14 @@ AudioPlayerLoaders::AudioPlayerLoaders(QThread *thread) : _fromVideoNotify(this,
|
||||
}
|
||||
|
||||
void AudioPlayerLoaders::feedFromVideo(VideoSoundPart &&part) {
|
||||
bool invoke = true;
|
||||
bool invoke = false;
|
||||
{
|
||||
QMutexLocker lock(&_fromVideoMutex);
|
||||
if (_fromVideoPlayId == part.videoPlayId) {
|
||||
_fromVideoQueue.enqueue(*part.packet);
|
||||
invoke = true;
|
||||
} else {
|
||||
av_packet_unref(part.packet);
|
||||
invoke = false;
|
||||
FFMpeg::freePacket(part.packet);
|
||||
}
|
||||
}
|
||||
if (invoke) {
|
||||
@ -77,7 +77,7 @@ AudioPlayerLoaders::~AudioPlayerLoaders() {
|
||||
void AudioPlayerLoaders::clearFromVideoQueue() {
|
||||
auto queue = createAndSwap(_fromVideoQueue);
|
||||
for (auto &packet : queue) {
|
||||
av_packet_unref(&packet);
|
||||
FFMpeg::freePacket(&packet);
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ void AudioPlayerLoaders::onLoad(const AudioMsgId &audio) {
|
||||
loadData(audio, 0);
|
||||
}
|
||||
|
||||
void AudioPlayerLoaders::loadData(const AudioMsgId &audio, qint64 position) {
|
||||
void AudioPlayerLoaders::loadData(AudioMsgId audio, qint64 position) {
|
||||
SetupError err = SetupNoErrorStarted;
|
||||
auto type = audio.type();
|
||||
AudioPlayerLoader *l = setupLoader(audio, err, position);
|
||||
@ -160,10 +160,13 @@ void AudioPlayerLoaders::loadData(const AudioMsgId &audio, qint64 position) {
|
||||
}
|
||||
finished = true;
|
||||
break;
|
||||
} else if (res == Result::EndOfFile) {
|
||||
finished = true;
|
||||
break;
|
||||
} else if (res == Result::Ok) {
|
||||
errAtStart = false;
|
||||
} else if (res == Result::Wait) {
|
||||
waiting = samples.isEmpty();// (samples.size() < AudioVoiceMsgBufferSize);
|
||||
waiting = (samples.size() < AudioVoiceMsgBufferSize);
|
||||
if (waiting) {
|
||||
l->saveDecodedSamples(&samples, &samplesCount);
|
||||
}
|
||||
@ -335,11 +338,12 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(const AudioMsgId &audio, Setu
|
||||
switch (audio.type()) {
|
||||
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::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))) {
|
||||
clear(audio.type());
|
||||
l = nullptr;
|
||||
}
|
||||
|
||||
if (!l) {
|
||||
@ -351,6 +355,12 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(const AudioMsgId &audio, Setu
|
||||
}
|
||||
|
||||
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));
|
||||
l = _videoLoader.get();
|
||||
} else {
|
||||
|
@ -78,7 +78,7 @@ private:
|
||||
SetupErrorLoadedFull = 2,
|
||||
SetupNoErrorStarted = 3,
|
||||
};
|
||||
void loadData(const AudioMsgId &audio, qint64 position);
|
||||
void loadData(AudioMsgId audio, qint64 position);
|
||||
AudioPlayerLoader *setupLoader(const AudioMsgId &audio, SetupError &err, qint64 position);
|
||||
AudioPlayer::AudioMsg *checkLoader(AudioMsgId::Type type);
|
||||
|
||||
|
@ -113,18 +113,23 @@ bool ChildFFMpegLoader::open(qint64 position) {
|
||||
|
||||
AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(QByteArray &result, int64 &samplesAdded) {
|
||||
if (_queue.isEmpty()) {
|
||||
return ReadResult::Wait;
|
||||
return _eofReached ? ReadResult::EndOfFile : ReadResult::Wait;
|
||||
}
|
||||
|
||||
av_frame_unref(_frame);
|
||||
int got_frame = 0;
|
||||
int res = 0;
|
||||
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) {
|
||||
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)));
|
||||
|
||||
av_packet_unref(&packet);
|
||||
FFMpeg::freePacket(&packet);
|
||||
if (res == AVERROR_INVALIDDATA) {
|
||||
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 };
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -151,7 +156,7 @@ AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(QByteArray &result, in
|
||||
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)));
|
||||
|
||||
av_packet_unref(&packet);
|
||||
FFMpeg::freePacket(&packet);
|
||||
return ReadResult::Error;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
av_packet_unref(&packet);
|
||||
FFMpeg::freePacket(&packet);
|
||||
return ReadResult::Ok;
|
||||
}
|
||||
|
||||
@ -174,7 +179,7 @@ void ChildFFMpegLoader::enqueuePackets(QQueue<AVPacket> &packets) {
|
||||
ChildFFMpegLoader::~ChildFFMpegLoader() {
|
||||
auto queue = createAndSwap(_queue);
|
||||
for (auto &packet : queue) {
|
||||
av_packet_unref(&packet);
|
||||
FFMpeg::freePacket(&packet);
|
||||
}
|
||||
if (_dstSamplesData) {
|
||||
if (_dstSamplesData[0]) {
|
||||
|
@ -44,6 +44,24 @@ struct VideoSoundPart {
|
||||
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 {
|
||||
public:
|
||||
ChildFFMpegLoader(std_::unique_ptr<VideoSoundData> &&data);
|
||||
@ -72,10 +90,15 @@ public:
|
||||
uint64 playId() const {
|
||||
return _parentData->videoPlayId;
|
||||
}
|
||||
bool eofReached() const {
|
||||
return _eofReached;
|
||||
}
|
||||
|
||||
~ChildFFMpegLoader();
|
||||
|
||||
private:
|
||||
bool _eofReached = false;
|
||||
|
||||
int32 _sampleSize = 2 * sizeof(uint16);
|
||||
int32 _format = AL_FORMAT_STEREO16;
|
||||
int32 _srcRate = AudioVoiceMsgFrequency;
|
||||
|
@ -107,12 +107,11 @@ bool FFMpegReaderImplementation::readNextFrame() {
|
||||
}
|
||||
|
||||
if (eofReached) {
|
||||
clearPacketQueue();
|
||||
if (_mode == Mode::Normal) {
|
||||
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 = av_seek_frame(_fmtContext, _streamId, 0, AVSEEK_FLAG_BYTE)) < 0) {
|
||||
if ((res = av_seek_frame(_fmtContext, _streamId, 0, AVSEEK_FLAG_FRAME)) < 0) {
|
||||
@ -294,6 +293,9 @@ int FFMpegReaderImplementation::duration() const {
|
||||
}
|
||||
|
||||
FFMpegReaderImplementation::~FFMpegReaderImplementation() {
|
||||
if (_mode == Mode::Normal && _audioStreamId >= 0) {
|
||||
audioPlayer()->stop(AudioMsgId::Type::Video);
|
||||
}
|
||||
if (_frameRead) {
|
||||
av_frame_unref(_frame);
|
||||
_frameRead = false;
|
||||
@ -321,6 +323,13 @@ FFMpegReaderImplementation::PacketResult FFMpegReaderImplementation::readPacket(
|
||||
int res = 0;
|
||||
if ((res = av_read_frame(_fmtContext, &packet)) < 0) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
_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) {
|
||||
_packetQueue.enqueue(packet);
|
||||
//_packetQueue.enqueue(packetForQueue);
|
||||
} else if (audioPacket) {
|
||||
// queue packet to audio player
|
||||
VideoSoundPart part;
|
||||
@ -356,7 +356,6 @@ FFMpegReaderImplementation::PacketResult FFMpegReaderImplementation::readPacket(
|
||||
} else {
|
||||
av_packet_unref(&packet);
|
||||
}
|
||||
//av_packet_unref(&packet);
|
||||
return PacketResult::Ok;
|
||||
}
|
||||
|
||||
|
@ -222,14 +222,14 @@ bool MediaView::gifShown() const {
|
||||
_gif->start(_gif->width(), _gif->height(), _gif->width(), _gif->height(), false);
|
||||
const_cast<MediaView*>(this)->_current = QPixmap();
|
||||
}
|
||||
return _gif->state() != Media::Clip::State::Error;
|
||||
return true;// _gif->state() != Media::Clip::State::Error;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MediaView::stopGif() {
|
||||
delete _gif;
|
||||
_gif = 0;
|
||||
_gif = nullptr;
|
||||
}
|
||||
|
||||
void MediaView::documentUpdated(DocumentData *doc) {
|
||||
@ -506,8 +506,7 @@ void MediaView::clearData() {
|
||||
_a_state.stop();
|
||||
}
|
||||
if (!_animOpacities.isEmpty()) _animOpacities.clear();
|
||||
delete _gif;
|
||||
_gif = nullptr;
|
||||
stopGif();
|
||||
delete _menu;
|
||||
_menu = nullptr;
|
||||
_history = _migrated = nullptr;
|
||||
|
Loading…
Reference in New Issue
Block a user