Stopping video sound when closing mediaview (destroying Clip::Reader).

Fixed launching video with sound while song is playing.
This commit is contained in:
John Preston 2016-07-05 20:44:22 +03:00
parent 616d08255c
commit 99b15719cf
9 changed files with 76 additions and 32 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -37,6 +37,7 @@ public:
NotYet,
Ok,
Wait,
EndOfFile,
};
virtual ReadResult readMore(QByteArray &samples, int64 &samplesCount) = 0;

View File

@ -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 {

View File

@ -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);

View File

@ -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]) {

View File

@ -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;

View File

@ -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;
}

View File

@ -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;