1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-13 20:01:46 -05:00

DATV: fixed DATVideoRender crash at close time when active: DATVDemodBaseband delete later

This commit is contained in:
f4exb 2021-03-23 08:35:30 +01:00
parent 6810990c99
commit 4ce2ae5ae5
7 changed files with 294 additions and 335 deletions

View File

@ -35,9 +35,8 @@ DATVDemod::DATVDemod(DeviceAPI *deviceAPI) :
{ {
qDebug("DATVDemod::DATVDemod"); qDebug("DATVDemod::DATVDemod");
setObjectName("DATVDemod"); setObjectName("DATVDemod");
m_thread = new QThread(this);
m_basebandSink = new DATVDemodBaseband(); m_basebandSink = new DATVDemodBaseband();
m_basebandSink->moveToThread(m_thread); m_basebandSink->moveToThread(&m_thread);
applySettings(m_settings, true); applySettings(m_settings, true);
@ -51,8 +50,12 @@ DATVDemod::~DATVDemod()
qDebug("DATVDemod::~DATVDemod"); qDebug("DATVDemod::~DATVDemod");
m_deviceAPI->removeChannelSinkAPI(this); m_deviceAPI->removeChannelSinkAPI(this);
m_deviceAPI->removeChannelSink(this); m_deviceAPI->removeChannelSink(this);
delete m_basebandSink;
delete m_thread; if (m_basebandSink->isRunning()) {
stop();
}
m_basebandSink->deleteLater();
} }
void DATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) void DATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst)
@ -70,14 +73,19 @@ void DATVDemod::start()
} }
m_basebandSink->reset(); m_basebandSink->reset();
m_thread->start(); m_basebandSink->startWork();
m_thread.start();
DATVDemodBaseband::MsgConfigureDATVDemodBaseband *msg = DATVDemodBaseband::MsgConfigureDATVDemodBaseband::create(m_settings, true);
m_basebandSink->getInputMessageQueue()->push(msg);
} }
void DATVDemod::stop() void DATVDemod::stop()
{ {
qDebug("DATVDemod::stop"); qDebug("DATVDemod::stop");
m_thread->exit(); m_basebandSink->stopWork();
m_thread->wait(); m_thread.quit();
m_thread.wait();
} }
bool DATVDemod::handleMessage(const Message& cmd) bool DATVDemod::handleMessage(const Message& cmd)

View File

@ -22,6 +22,8 @@
class DeviceAPI; class DeviceAPI;
#include <QThread>
#include "channel/channelapi.h" #include "channel/channelapi.h"
#include "dsp/basebandsamplesink.h" #include "dsp/basebandsamplesink.h"
#include "dsp/devicesamplesource.h" #include "dsp/devicesamplesource.h"
@ -30,7 +32,6 @@ class DeviceAPI;
#include "datvdemodbaseband.h" #include "datvdemodbaseband.h"
class DATVDemod : public BasebandSampleSink, public ChannelAPI class DATVDemod : public BasebandSampleSink, public ChannelAPI
{ {
Q_OBJECT Q_OBJECT
@ -115,7 +116,7 @@ public:
private: private:
DeviceAPI* m_deviceAPI; DeviceAPI* m_deviceAPI;
QThread *m_thread; QThread m_thread;
DATVDemodBaseband* m_basebandSink; DATVDemodBaseband* m_basebandSink;
DATVDemodSettings m_settings; DATVDemodSettings m_settings;
int m_basebandSampleRate; //!< stored from device message used when starting baseband sink int m_basebandSampleRate; //!< stored from device message used when starting baseband sink

View File

@ -27,21 +27,12 @@ MESSAGE_CLASS_DEFINITION(DATVDemodBaseband::MsgConfigureDATVDemodBaseband, Messa
MESSAGE_CLASS_DEFINITION(DATVDemodBaseband::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(DATVDemodBaseband::MsgConfigureChannelizer, Message)
DATVDemodBaseband::DATVDemodBaseband() : DATVDemodBaseband::DATVDemodBaseband() :
m_running(false),
m_mutex(QMutex::Recursive) m_mutex(QMutex::Recursive)
{ {
qDebug("DATVDemodBaseband::DATVDemodBaseband"); qDebug("DATVDemodBaseband::DATVDemodBaseband");
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(48000)); m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(48000));
m_channelizer = new DownChannelizer(&m_sink); m_channelizer = new DownChannelizer(&m_sink);
QObject::connect(
&m_sampleFifo,
&SampleSinkFifo::dataReady,
this,
&DATVDemodBaseband::handleData,
Qt::QueuedConnection
);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
} }
DATVDemodBaseband::~DATVDemodBaseband() DATVDemodBaseband::~DATVDemodBaseband()
@ -55,6 +46,33 @@ void DATVDemodBaseband::reset()
m_sampleFifo.reset(); m_sampleFifo.reset();
} }
void DATVDemodBaseband::startWork()
{
QMutexLocker mutexLocker(&m_mutex);
QObject::connect(
&m_sampleFifo,
&SampleSinkFifo::dataReady,
this,
&DATVDemodBaseband::handleData,
Qt::QueuedConnection
);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
m_running = true;
}
void DATVDemodBaseband::stopWork()
{
QMutexLocker mutexLocker(&m_mutex);
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
QObject::disconnect(
&m_sampleFifo,
&SampleSinkFifo::dataReady,
this,
&DATVDemodBaseband::handleData
);
m_running = false;
}
void DATVDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) void DATVDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
{ {
m_sampleFifo.write(begin, end); m_sampleFifo.write(begin, end);

View File

@ -81,6 +81,8 @@ public:
DATVDemodBaseband(); DATVDemodBaseband();
~DATVDemodBaseband(); ~DATVDemodBaseband();
void reset(); void reset();
void startWork();
void stopWork();
void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end); void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
int getChannelSampleRate() const; int getChannelSampleRate() const;
@ -102,6 +104,7 @@ public:
int getModcodModulation() const { return m_sink.getModcodModulation(); } int getModcodModulation() const { return m_sink.getModcodModulation(); }
int getModcodCodeRate() const { return m_sink.getModcodCodeRate(); } int getModcodCodeRate() const { return m_sink.getModcodCodeRate(); }
bool isCstlnSetByModcod() const { return m_sink.isCstlnSetByModcod(); } bool isCstlnSetByModcod() const { return m_sink.isCstlnSetByModcod(); }
bool isRunning() const { return m_running; }
private: private:
SampleSinkFifo m_sampleFifo; SampleSinkFifo m_sampleFifo;
@ -109,6 +112,7 @@ private:
DATVDemodSink m_sink; DATVDemodSink m_sink;
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
DATVDemodSettings m_settings; DATVDemodSettings m_settings;
bool m_running;
QMutex m_mutex; QMutex m_mutex;
bool handleMessage(const Message& cmd); bool handleMessage(const Message& cmd);

View File

@ -75,9 +75,8 @@ DATVDemodSink::~DATVDemodSink()
{ {
m_objRenderThread->stopRendering(); m_objRenderThread->stopRendering();
m_objRenderThread->quit(); m_objRenderThread->quit();
m_objRenderThread->wait();
} }
m_objRenderThread->wait(2000);
} }
CleanUpDATVFramework(); CleanUpDATVFramework();

View File

@ -33,7 +33,6 @@ DATVideoRender::DATVideoRender(QWidget *parent) : TVScreen(true, parent), m_pare
{ {
installEventFilter(this); installEventFilter(this);
m_isFullScreen = false; m_isFullScreen = false;
m_running = 0;
m_isFFMPEGInitialized = false; m_isFFMPEGInitialized = false;
m_isOpen = false; m_isOpen = false;
m_formatCtx = nullptr; m_formatCtx = nullptr;
@ -69,6 +68,8 @@ DATVideoRender::DATVideoRender(QWidget *parent) : TVScreen(true, parent), m_pare
DATVideoRender::~DATVideoRender() DATVideoRender::~DATVideoRender()
{ {
qDebug("DATVideoRender::~DATVideoRender");
if (m_audioSWR) { if (m_audioSWR) {
swr_free(&m_audioSWR); swr_free(&m_audioSWR);
} }
@ -387,94 +388,62 @@ bool DATVideoRender::OpenStream(DATVideostream *device)
return false; return false;
} }
//Only once execution m_metaData.OK_Data = true;
if (m_running.testAndSetOrdered(0,1)) emit onMetaDataChanged(new DataTSMetaData2(m_metaData));
InitializeFFMPEG();
if (!m_isFFMPEGInitialized)
{ {
m_metaData.OK_Data = true; qDebug() << "DATVideoRender::OpenStream FFMPEG not initialized";
emit onMetaDataChanged(new DataTSMetaData2(m_metaData)); return false;
InitializeFFMPEG();
if (!m_isFFMPEGInitialized)
{
qDebug() << "DATVideoRender::OpenStream FFMPEG not initialized";
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
return false;
}
if (!device->open(QIODevice::ReadOnly))
{
qDebug() << "DATVideoRender::OpenStream cannot open QIODevice";
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
return false;
}
//Connect QIODevice to FFMPEG Reader
m_formatCtx = avformat_alloc_context();
if (m_formatCtx == nullptr)
{
qDebug() << "DATVideoRender::OpenStream cannot alloc format FFMPEG context";
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
return false;
}
ptrIOBuffer = (unsigned char *)av_malloc(ioBufferSize + AV_INPUT_BUFFER_PADDING_SIZE);
ioCtx = avio_alloc_context(ptrIOBuffer,
ioBufferSize,
0,
reinterpret_cast<void *>(device),
&ReadFunction,
nullptr,
&SeekFunction);
m_formatCtx->pb = ioCtx;
m_formatCtx->flags |= AVFMT_FLAG_CUSTOM_IO;
if (avformat_open_input(&m_formatCtx, nullptr, nullptr, nullptr) < 0)
{
qDebug() << "DATVideoRender::OpenStream cannot open stream";
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
return false;
}
if (!PreprocessStream())
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
return false;
}
m_isOpen = true;
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
} }
if (!device->open(QIODevice::ReadOnly))
{
qDebug() << "DATVideoRender::OpenStream cannot open QIODevice";
return false;
}
//Connect QIODevice to FFMPEG Reader
m_formatCtx = avformat_alloc_context();
if (m_formatCtx == nullptr)
{
qDebug() << "DATVideoRender::OpenStream cannot alloc format FFMPEG context";
return false;
}
ptrIOBuffer = (unsigned char *)av_malloc(ioBufferSize + AV_INPUT_BUFFER_PADDING_SIZE);
ioCtx = avio_alloc_context(
ptrIOBuffer,
ioBufferSize,
0,
reinterpret_cast<void *>(device),
&ReadFunction,
nullptr,
&SeekFunction
);
m_formatCtx->pb = ioCtx;
m_formatCtx->flags |= AVFMT_FLAG_CUSTOM_IO;
if (avformat_open_input(&m_formatCtx, nullptr, nullptr, nullptr) < 0)
{
qDebug() << "DATVideoRender::OpenStream cannot open stream";
return false;
}
if (!PreprocessStream())
{
return false;
}
qDebug("DATVideoRender::OpenStream: successful");
m_isOpen = true;
return true; return true;
} }
@ -490,210 +459,180 @@ bool DATVideoRender::RenderStream()
return false; return false;
} }
//Only once execution //********** Rendering **********
if (m_running.testAndSetOrdered(0,1)) if (av_read_frame(m_formatCtx, &packet) < 0)
{ {
//********** Rendering ********** qDebug() << "DATVideoRender::RenderStream reading packet error";
if (av_read_frame(m_formatCtx, &packet) < 0) return false;
}
//Video channel
if ((packet.stream_index == m_videoStreamIndex) && (!m_videoMute))
{
memset(m_frame, 0, sizeof(AVFrame));
av_frame_unref(m_frame);
gotFrame = 0;
if (new_decode(m_videoDecoderCtx, m_frame, &gotFrame, &packet) >= 0)
{ {
qDebug() << "DATVideoRender::RenderStream reading packet error"; m_videoDecodeOK = true;
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
return false;
}
//Video channel if (gotFrame)
if ((packet.stream_index == m_videoStreamIndex) && (!m_videoMute))
{
memset(m_frame, 0, sizeof(AVFrame));
av_frame_unref(m_frame);
gotFrame = 0;
if (new_decode(m_videoDecoderCtx, m_frame, &gotFrame, &packet) >= 0)
{ {
m_videoDecodeOK = true; //Rendering and RGB Converter setup
needRenderingSetup = (m_frameCount == 0);
needRenderingSetup |= (m_swsCtx == nullptr);
if (gotFrame) if ((m_currentRenderWidth != m_frame->width) || (m_currentRenderHeight != m_frame->height))
{ {
//Rendering and RGB Converter setup needRenderingSetup = true;
needRenderingSetup = (m_frameCount == 0); }
needRenderingSetup |= (m_swsCtx == nullptr);
if ((m_currentRenderWidth != m_frame->width) || (m_currentRenderHeight != m_frame->height)) if (needRenderingSetup)
{
if (m_swsCtx != nullptr)
{ {
needRenderingSetup = true; sws_freeContext(m_swsCtx);
m_swsCtx = nullptr;
} }
if (needRenderingSetup) //Convertisseur YUV -> RGB
m_swsCtx = sws_alloc_context();
av_opt_set_int(m_swsCtx, "srcw", m_frame->width, 0);
av_opt_set_int(m_swsCtx, "srch", m_frame->height, 0);
av_opt_set_int(m_swsCtx, "src_format", m_frame->format, 0);
av_opt_set_int(m_swsCtx, "dstw", m_frame->width, 0);
av_opt_set_int(m_swsCtx, "dsth", m_frame->height, 0);
av_opt_set_int(m_swsCtx, "dst_format", AV_PIX_FMT_RGB24, 0);
av_opt_set_int(m_swsCtx, "sws_flag", SWS_FAST_BILINEAR /* SWS_BICUBIC*/, 0);
if (sws_init_context(m_swsCtx, nullptr, nullptr) < 0)
{ {
if (m_swsCtx != nullptr) qDebug() << "DATVideoRender::RenderStream cannont init video data converter";
{ m_swsCtx = nullptr;
sws_freeContext(m_swsCtx);
m_swsCtx = nullptr;
}
//Convertisseur YUV -> RGB
m_swsCtx = sws_alloc_context();
av_opt_set_int(m_swsCtx, "srcw", m_frame->width, 0);
av_opt_set_int(m_swsCtx, "srch", m_frame->height, 0);
av_opt_set_int(m_swsCtx, "src_format", m_frame->format, 0);
av_opt_set_int(m_swsCtx, "dstw", m_frame->width, 0);
av_opt_set_int(m_swsCtx, "dsth", m_frame->height, 0);
av_opt_set_int(m_swsCtx, "dst_format", AV_PIX_FMT_RGB24, 0);
av_opt_set_int(m_swsCtx, "sws_flag", SWS_FAST_BILINEAR /* SWS_BICUBIC*/, 0);
if (sws_init_context(m_swsCtx, nullptr, nullptr) < 0)
{
qDebug() << "DATVideoRender::RenderStream cannont init video data converter";
m_swsCtx = nullptr;
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
return false;
}
if ((m_currentRenderHeight > 0) && (m_currentRenderWidth > 0))
{
//av_freep(&m_pbytDecodedData[0]);
//av_freep(&m_pintDecodedLineSize[0]);
}
if (av_image_alloc(m_pbytDecodedData, m_pintDecodedLineSize, m_frame->width, m_frame->height, AV_PIX_FMT_RGB24, 1) < 0)
{
qDebug() << "DATVideoRender::RenderStream cannont init video image buffer";
sws_freeContext(m_swsCtx);
m_swsCtx = nullptr;
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
return false;
}
//Rendering device setup
resizeTVScreen(m_frame->width, m_frame->height);
update();
resetImage();
m_currentRenderWidth = m_frame->width;
m_currentRenderHeight = m_frame->height;
m_metaData.Width = m_frame->width;
m_metaData.Height = m_frame->height;
m_metaData.OK_Decoding = true;
emit onMetaDataChanged(new DataTSMetaData2(m_metaData));
}
//Frame rendering
if (sws_scale(m_swsCtx, m_frame->data, m_frame->linesize, 0, m_frame->height, m_pbytDecodedData, m_pintDecodedLineSize) < 0)
{
qDebug() << "DATVideoRender::RenderStream error converting video frame to RGB";
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
return false; return false;
} }
renderImage(m_pbytDecodedData[0]); if ((m_currentRenderHeight > 0) && (m_currentRenderWidth > 0))
av_frame_unref(m_frame); {
m_frameCount++; //av_freep(&m_pbytDecodedData[0]);
//av_freep(&m_pintDecodedLineSize[0]);
}
if (av_image_alloc(m_pbytDecodedData, m_pintDecodedLineSize, m_frame->width, m_frame->height, AV_PIX_FMT_RGB24, 1) < 0)
{
qDebug() << "DATVideoRender::RenderStream cannont init video image buffer";
sws_freeContext(m_swsCtx);
m_swsCtx = nullptr;
return false;
}
//Rendering device setup
resizeTVScreen(m_frame->width, m_frame->height);
update();
resetImage();
m_currentRenderWidth = m_frame->width;
m_currentRenderHeight = m_frame->height;
m_metaData.Width = m_frame->width;
m_metaData.Height = m_frame->height;
m_metaData.OK_Decoding = true;
emit onMetaDataChanged(new DataTSMetaData2(m_metaData));
} }
}
else
{
m_videoDecodeOK = false;
// qDebug() << "DATVideoRender::RenderStream video decode error";
}
}
// Audio channel
else if ((packet.stream_index == m_audioStreamIndex) && (m_audioFifo) && (swr_is_initialized(m_audioSWR)) && (!m_audioMute))
{
if (m_updateAudioResampler)
{
setResampler();
m_updateAudioResampler = false;
}
memset(m_frame, 0, sizeof(AVFrame)); //Frame rendering
av_frame_unref(m_frame);
gotFrame = 0;
if (new_decode(m_audioDecoderCtx, m_frame, &gotFrame, &packet) >= 0) if (sws_scale(m_swsCtx, m_frame->data, m_frame->linesize, 0, m_frame->height, m_pbytDecodedData, m_pintDecodedLineSize) < 0)
{
m_audioDecodeOK = true;
if (gotFrame)
{ {
int16_t *audioBuffer = nullptr; qDebug() << "DATVideoRender::RenderStream error converting video frame to RGB";
av_samples_alloc((uint8_t**) &audioBuffer, nullptr, 2, m_frame->nb_samples, AV_SAMPLE_FMT_S16, 0); return false;
int samples_per_channel = swr_convert(m_audioSWR, (uint8_t**) &audioBuffer, m_frame->nb_samples, (const uint8_t**) m_frame->data, m_frame->nb_samples);
if (samples_per_channel < m_frame->nb_samples) {
qDebug("DATVideoRender::RenderStream: converted samples missing %d/%d returned", samples_per_channel, m_frame->nb_samples);
}
// direct writing:
std::for_each(audioBuffer, audioBuffer + 2*samples_per_channel, [this](int16_t &x) {
x *= m_audioVolume;
});
int ret = m_audioFifo->write((const quint8*) &audioBuffer[0], samples_per_channel);
if (ret < samples_per_channel) {
qDebug("DATVideoRender::RenderStream: audio samples missing %d/%d written", ret, samples_per_channel);
}
// buffered writing:
// if (m_audioFifoBufferIndex + samples_per_channel < m_audioFifoBufferSize)
// {
// std::copy(&audioBuffer[0], &audioBuffer[2*samples_per_channel], &m_audioFifoBuffer[2*m_audioFifoBufferIndex]);
// m_audioFifoBufferIndex += samples_per_channel;
// }
// else
// {
// int remainder = m_audioFifoBufferSize - m_audioFifoBufferIndex;
// std::copy(&audioBuffer[0], &audioBuffer[2*remainder], &m_audioFifoBuffer[2*m_audioFifoBufferIndex]);
// std::for_each(m_audioFifoBuffer, m_audioFifoBuffer+2*m_audioFifoBufferSize, [this](int16_t &x) {
// x *= m_audioVolume;
// });
// int ret = m_audioFifo->write((const quint8*) &m_audioFifoBuffer[0], m_audioFifoBufferSize);
// if (ret < m_audioFifoBufferSize) {
// qDebug("DATVideoRender::RenderStream: audio samples missing %d/%d written", ret, m_audioFifoBufferSize);
// }
// std::copy(&audioBuffer[2*remainder], &audioBuffer[2*samples_per_channel], &m_audioFifoBuffer[0]);
// m_audioFifoBufferIndex = samples_per_channel - remainder;
// }
av_freep(&audioBuffer);
} }
}
else renderImage(m_pbytDecodedData[0]);
{ av_frame_unref(m_frame);
m_audioDecodeOK = false; m_frameCount++;
// qDebug("DATVideoRender::RenderStream: audio decode error");
} }
} }
else
av_packet_unref(&packet); {
//********** Rendering ********** m_videoDecodeOK = false;
// qDebug() << "DATVideoRender::RenderStream video decode error";
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) }
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
} }
// Audio channel
else if ((packet.stream_index == m_audioStreamIndex) && (m_audioFifo) && (swr_is_initialized(m_audioSWR)) && (!m_audioMute))
{
if (m_updateAudioResampler)
{
setResampler();
m_updateAudioResampler = false;
}
memset(m_frame, 0, sizeof(AVFrame));
av_frame_unref(m_frame);
gotFrame = 0;
if (new_decode(m_audioDecoderCtx, m_frame, &gotFrame, &packet) >= 0)
{
m_audioDecodeOK = true;
if (gotFrame)
{
int16_t *audioBuffer = nullptr;
av_samples_alloc((uint8_t**) &audioBuffer, nullptr, 2, m_frame->nb_samples, AV_SAMPLE_FMT_S16, 0);
int samples_per_channel = swr_convert(m_audioSWR, (uint8_t**) &audioBuffer, m_frame->nb_samples, (const uint8_t**) m_frame->data, m_frame->nb_samples);
if (samples_per_channel < m_frame->nb_samples) {
qDebug("DATVideoRender::RenderStream: converted samples missing %d/%d returned", samples_per_channel, m_frame->nb_samples);
}
// direct writing:
std::for_each(audioBuffer, audioBuffer + 2*samples_per_channel, [this](int16_t &x) {
x *= m_audioVolume;
});
int ret = m_audioFifo->write((const quint8*) &audioBuffer[0], samples_per_channel);
if (ret < samples_per_channel) {
// qDebug("DATVideoRender::RenderStream: audio samples missing %d/%d written", ret, samples_per_channel);
}
// buffered writing:
// if (m_audioFifoBufferIndex + samples_per_channel < m_audioFifoBufferSize)
// {
// std::copy(&audioBuffer[0], &audioBuffer[2*samples_per_channel], &m_audioFifoBuffer[2*m_audioFifoBufferIndex]);
// m_audioFifoBufferIndex += samples_per_channel;
// }
// else
// {
// int remainder = m_audioFifoBufferSize - m_audioFifoBufferIndex;
// std::copy(&audioBuffer[0], &audioBuffer[2*remainder], &m_audioFifoBuffer[2*m_audioFifoBufferIndex]);
// std::for_each(m_audioFifoBuffer, m_audioFifoBuffer+2*m_audioFifoBufferSize, [this](int16_t &x) {
// x *= m_audioVolume;
// });
// int ret = m_audioFifo->write((const quint8*) &m_audioFifoBuffer[0], m_audioFifoBufferSize);
// if (ret < m_audioFifoBufferSize) {
// qDebug("DATVideoRender::RenderStream: audio samples missing %d/%d written", ret, m_audioFifoBufferSize);
// }
// std::copy(&audioBuffer[2*remainder], &audioBuffer[2*samples_per_channel], &m_audioFifoBuffer[0]);
// m_audioFifoBufferIndex = samples_per_channel - remainder;
// }
av_freep(&audioBuffer);
}
}
else
{
m_audioDecodeOK = false;
// qDebug("DATVideoRender::RenderStream: audio decode error");
}
}
av_packet_unref(&packet);
//********** Rendering **********
return true; return true;
} }
@ -735,6 +674,8 @@ void DATVideoRender::setResampler()
bool DATVideoRender::CloseStream(QIODevice *device) bool DATVideoRender::CloseStream(QIODevice *device)
{ {
qDebug("DATVideoRender::CloseStream");
if (!device) if (!device)
{ {
qDebug() << "DATVideoRender::CloseStream QIODevice is nullptr"; qDebug() << "DATVideoRender::CloseStream QIODevice is nullptr";
@ -753,46 +694,35 @@ bool DATVideoRender::CloseStream(QIODevice *device)
return false; return false;
} }
//Only once execution // maybe done in the avcodec_close
if (m_running.testAndSetOrdered(0,1)) // avformat_close_input(&m_formatCtx);
// m_formatCtx=nullptr;
if (m_videoDecoderCtx)
{ {
// maybe done in the avcodec_close avcodec_close(m_videoDecoderCtx);
// avformat_close_input(&m_formatCtx); m_videoDecoderCtx = nullptr;
// m_formatCtx=nullptr;
if (m_videoDecoderCtx)
{
avcodec_close(m_videoDecoderCtx);
m_videoDecoderCtx = nullptr;
}
if (m_frame)
{
av_frame_unref(m_frame);
av_frame_free(&m_frame);
}
if (m_swsCtx != nullptr)
{
sws_freeContext(m_swsCtx);
m_swsCtx = nullptr;
}
device->close();
m_isOpen = false;
m_currentRenderWidth = -1;
m_currentRenderHeight = -1;
ResetMetaData();
emit onMetaDataChanged(new DataTSMetaData2(m_metaData));
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_running.storeRelaxed(0);
#else
m_running.store(0);
#endif
} }
if (m_frame)
{
av_frame_unref(m_frame);
av_frame_free(&m_frame);
}
if (m_swsCtx != nullptr)
{
sws_freeContext(m_swsCtx);
m_swsCtx = nullptr;
}
device->close();
m_isOpen = false;
m_currentRenderWidth = -1;
m_currentRenderHeight = -1;
ResetMetaData();
return true; return true;
} }

View File

@ -119,7 +119,6 @@ class DATVideoRender : public TVScreen
Qt::WindowFlags m_originalWindowFlags; Qt::WindowFlags m_originalWindowFlags;
QSize m_originalSize; QSize m_originalSize;
QAtomicInt m_running;
bool m_isFullScreen; bool m_isFullScreen;
bool m_isFFMPEGInitialized; bool m_isFFMPEGInitialized;
@ -188,32 +187,32 @@ class DATVideoRenderThread : public QThread
void setStreamAndRenderer(DATVideoRender *renderer, DATVideostream *stream) void setStreamAndRenderer(DATVideoRender *renderer, DATVideostream *stream)
{ {
m_renderingVideo = false;
m_renderer = renderer; m_renderer = renderer;
m_stream = stream; m_stream = stream;
m_renderingVideo = false;
} }
void run() void run()
{ {
if (m_renderingVideo) if (m_renderingVideo) {
{
return; return;
} }
if ((m_renderer == nullptr) || (m_stream == nullptr)) if ((m_renderer == nullptr) || (m_stream == nullptr)) {
{
return; return;
} }
m_renderingVideo = m_renderer->OpenStream(m_stream); m_renderingVideo = m_renderer->OpenStream(m_stream);
if (!m_renderingVideo) if (!m_renderingVideo) {
{
return; return;
} }
while ((m_renderer->RenderStream()) && (m_renderingVideo == true)) while (m_renderingVideo == true)
{ {
if (!m_renderer->RenderStream()) {
break;
}
} }
m_renderer->CloseStream(m_stream); m_renderer->CloseStream(m_stream);