2018-02-22 16:52:49 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Copyright (C) 2018 F4HKW //
|
|
|
|
// for F4EXB / SDRAngel //
|
|
|
|
// //
|
|
|
|
// This program is free software; you can redistribute it and/or modify //
|
|
|
|
// it under the terms of the GNU General Public License as published by //
|
|
|
|
// the Free Software Foundation as version 3 of the License, or //
|
2019-04-11 00:39:30 -04:00
|
|
|
// (at your option) any later version. //
|
2018-02-22 16:52:49 -05:00
|
|
|
// //
|
|
|
|
// This program is distributed in the hope that it will be useful, //
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
|
|
// GNU General Public License V3 for more details. //
|
|
|
|
// //
|
|
|
|
// You should have received a copy of the GNU General Public License //
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#ifndef DATVIDEORENDER_H
|
|
|
|
#define DATVIDEORENDER_H
|
|
|
|
|
|
|
|
#include <QEvent>
|
|
|
|
#include <QIODevice>
|
|
|
|
#include <QThread>
|
2019-03-19 20:14:38 -04:00
|
|
|
#include <QWidget>
|
2021-10-30 06:35:02 -04:00
|
|
|
#include <QTextStream>
|
|
|
|
#include <QDebug>
|
2018-02-22 16:52:49 -05:00
|
|
|
|
|
|
|
#include "datvideostream.h"
|
2019-03-19 20:14:38 -04:00
|
|
|
#include "gui/tvscreen.h"
|
2018-02-22 16:52:49 -05:00
|
|
|
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
#include "libavcodec/avcodec.h"
|
|
|
|
#include "libavformat/avformat.h"
|
|
|
|
|
|
|
|
#include <libavutil/channel_layout.h>
|
|
|
|
#include <libavutil/common.h>
|
|
|
|
#include <libavutil/imgutils.h>
|
|
|
|
#include <libavutil/mathematics.h>
|
2019-03-19 20:14:38 -04:00
|
|
|
#include <libavutil/opt.h>
|
2018-02-22 16:52:49 -05:00
|
|
|
#include <libavutil/samplefmt.h>
|
|
|
|
|
|
|
|
#include "libswscale/swscale.h"
|
|
|
|
}
|
|
|
|
|
2019-03-19 18:12:54 -04:00
|
|
|
class AudioFifo;
|
|
|
|
|
2018-02-22 16:52:49 -05:00
|
|
|
struct DataTSMetaData2
|
|
|
|
{
|
|
|
|
int PID;
|
|
|
|
int CodecID;
|
2018-02-25 19:04:45 -05:00
|
|
|
|
|
|
|
bool OK_Data;
|
|
|
|
bool OK_Decoding;
|
|
|
|
bool OK_TransportStream;
|
|
|
|
bool OK_VideoStream;
|
|
|
|
|
2018-02-22 16:52:49 -05:00
|
|
|
QString Program;
|
|
|
|
QString Stream;
|
|
|
|
|
|
|
|
int Width;
|
|
|
|
int Height;
|
|
|
|
int BitRate;
|
|
|
|
int Channels;
|
2018-02-25 19:04:45 -05:00
|
|
|
|
2018-02-22 16:52:49 -05:00
|
|
|
QString CodecDescription;
|
|
|
|
|
|
|
|
DataTSMetaData2()
|
|
|
|
{
|
2021-03-21 22:12:58 -04:00
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset()
|
|
|
|
{
|
2019-03-19 20:14:38 -04:00
|
|
|
CodecID = -1;
|
2021-03-21 22:12:58 -04:00
|
|
|
PID = -1;
|
2019-03-19 20:14:38 -04:00
|
|
|
Program = "";
|
|
|
|
Stream = "";
|
|
|
|
Width = -1;
|
|
|
|
Height = -1;
|
|
|
|
BitRate = -1;
|
|
|
|
Channels = -1;
|
|
|
|
CodecDescription = "";
|
2021-03-21 22:12:58 -04:00
|
|
|
|
2019-03-19 20:14:38 -04:00
|
|
|
OK_Data = false;
|
|
|
|
OK_Decoding = false;
|
|
|
|
OK_TransportStream = false;
|
|
|
|
OK_VideoStream = false;
|
2018-02-22 16:52:49 -05:00
|
|
|
}
|
2021-03-28 12:40:43 -04:00
|
|
|
|
|
|
|
void formatString(QString &s)
|
|
|
|
{
|
|
|
|
QTextStream out(&s);
|
|
|
|
out << " CodecID:" << CodecID
|
|
|
|
<< " PID:" << PID
|
|
|
|
<< " Program:" << Program
|
|
|
|
<< " Stream:" << Stream
|
|
|
|
<< " Width:" << Width
|
|
|
|
<< " Height:" << Height
|
|
|
|
<< " BitRate:" << BitRate
|
|
|
|
<< " Channels:" << Channels
|
|
|
|
<< " CodecDescription:" << CodecDescription;
|
|
|
|
}
|
2018-02-22 16:52:49 -05:00
|
|
|
};
|
|
|
|
|
2018-03-11 11:39:02 -04:00
|
|
|
class DATVideoRender : public TVScreen
|
2018-02-22 16:52:49 -05:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
2018-02-25 19:04:45 -05:00
|
|
|
|
2019-03-19 20:14:38 -04:00
|
|
|
public:
|
|
|
|
explicit DATVideoRender(QWidget *parent);
|
2019-03-22 03:05:01 -04:00
|
|
|
~DATVideoRender();
|
|
|
|
|
2021-04-05 07:13:57 -04:00
|
|
|
void setFullScreen(bool blnFullScreen);
|
2018-02-22 16:52:49 -05:00
|
|
|
|
2021-03-28 12:40:43 -04:00
|
|
|
void setAudioFIFO(AudioFifo *fifo) { m_audioFifo = fifo; }
|
2021-04-05 07:13:57 -04:00
|
|
|
bool openStream(DATVideostream *objDevice);
|
|
|
|
bool renderStream();
|
|
|
|
bool closeStream(QIODevice *objDevice);
|
2018-02-22 16:52:49 -05:00
|
|
|
|
2019-03-19 19:07:05 -04:00
|
|
|
int getVideoStreamIndex() const { return m_videoStreamIndex; }
|
2019-03-19 18:12:54 -04:00
|
|
|
int getAudioStreamIndex() const { return m_audioStreamIndex; }
|
|
|
|
|
2019-03-22 03:05:01 -04:00
|
|
|
void setAudioMute(bool audioMute) { m_audioMute = audioMute; }
|
2019-03-23 01:06:42 -04:00
|
|
|
void setVideoMute(bool videoMute) { m_videoMute = videoMute; }
|
2019-03-22 03:05:01 -04:00
|
|
|
void setAudioVolume(int audioVolume);
|
|
|
|
|
2019-03-23 04:38:29 -04:00
|
|
|
bool getAudioDecodeOK() const { return m_audioDecodeOK; }
|
|
|
|
bool getVideoDecodeOK() const { return m_videoDecodeOK; }
|
|
|
|
|
2019-03-19 20:14:38 -04:00
|
|
|
private:
|
2021-03-21 22:12:58 -04:00
|
|
|
struct DataTSMetaData2 m_metaData;
|
2019-03-23 18:37:26 -04:00
|
|
|
QWidget *m_parentWidget;
|
|
|
|
Qt::WindowFlags m_originalWindowFlags;
|
|
|
|
QSize m_originalSize;
|
2019-03-19 20:14:38 -04:00
|
|
|
bool m_isFullScreen;
|
|
|
|
bool m_isOpen;
|
|
|
|
SwsContext *m_swsCtx;
|
2019-03-19 19:07:05 -04:00
|
|
|
AVFormatContext *m_formatCtx;
|
|
|
|
AVCodecContext *m_videoDecoderCtx;
|
|
|
|
AVCodecContext *m_audioDecoderCtx;
|
|
|
|
AVFrame *m_frame;
|
2019-03-19 18:12:54 -04:00
|
|
|
AudioFifo *m_audioFifo;
|
2019-03-19 21:15:59 -04:00
|
|
|
struct SwrContext* m_audioSWR;
|
|
|
|
int m_audioSampleRate;
|
2019-03-21 03:35:29 -04:00
|
|
|
static const int m_audioFifoBufferSize = 16000;
|
2019-03-23 01:06:42 -04:00
|
|
|
int16_t m_audioFifoBuffer[m_audioFifoBufferSize*2]; // 2 channels
|
2019-03-21 03:35:29 -04:00
|
|
|
int m_audioFifoBufferIndex;
|
2019-03-22 03:05:01 -04:00
|
|
|
bool m_audioMute;
|
2019-03-23 01:06:42 -04:00
|
|
|
bool m_videoMute;
|
|
|
|
float m_audioVolume;
|
2019-03-19 18:12:54 -04:00
|
|
|
|
2021-04-05 07:13:57 -04:00
|
|
|
uint8_t *m_decodedData[4];
|
|
|
|
int m_decodedLineSize[4];
|
2018-02-22 16:52:49 -05:00
|
|
|
|
2019-03-19 19:07:05 -04:00
|
|
|
int m_frameCount;
|
|
|
|
int m_videoStreamIndex;
|
2019-03-19 18:12:54 -04:00
|
|
|
int m_audioStreamIndex;
|
2018-02-22 16:52:49 -05:00
|
|
|
|
2019-03-19 20:14:38 -04:00
|
|
|
int m_currentRenderWidth;
|
|
|
|
int m_currentRenderHeight;
|
2018-02-22 16:52:49 -05:00
|
|
|
|
2019-03-23 04:38:29 -04:00
|
|
|
bool m_audioDecodeOK;
|
|
|
|
bool m_videoDecodeOK;
|
|
|
|
|
2021-04-05 07:13:57 -04:00
|
|
|
static int ReadFunction(void *opaque, uint8_t *buf, int buf_size);
|
|
|
|
static int64_t SeekFunction(void *opaque, int64_t offset, int whence);
|
|
|
|
|
|
|
|
bool preprocessStream();
|
|
|
|
void resetMetaData();
|
2018-02-22 16:52:49 -05:00
|
|
|
|
2021-04-05 07:13:57 -04:00
|
|
|
int newDecode(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *pkt);
|
2019-03-22 03:05:01 -04:00
|
|
|
void setResampler();
|
2018-06-12 18:20:51 -04:00
|
|
|
|
2019-03-19 20:14:38 -04:00
|
|
|
protected:
|
2018-02-22 16:52:49 -05:00
|
|
|
virtual bool eventFilter(QObject *obj, QEvent *event);
|
|
|
|
|
2019-03-19 20:14:38 -04:00
|
|
|
signals:
|
|
|
|
void onMetaDataChanged(DataTSMetaData2 *metaData);
|
2018-02-22 16:52:49 -05:00
|
|
|
};
|
|
|
|
|
2018-02-25 19:04:45 -05:00
|
|
|
//To run Video Rendering with a dedicated thread
|
2019-03-19 20:14:38 -04:00
|
|
|
class DATVideoRenderThread : public QThread
|
2018-02-22 16:52:49 -05:00
|
|
|
{
|
2019-03-19 20:14:38 -04:00
|
|
|
public:
|
|
|
|
DATVideoRenderThread()
|
|
|
|
{
|
|
|
|
m_renderer = nullptr;
|
|
|
|
m_stream = nullptr;
|
|
|
|
m_renderingVideo = false;
|
|
|
|
}
|
2018-02-22 16:52:49 -05:00
|
|
|
|
2019-03-19 20:14:38 -04:00
|
|
|
DATVideoRenderThread(DATVideoRender *renderer, DATVideostream *stream)
|
|
|
|
{
|
|
|
|
m_renderer = renderer;
|
|
|
|
m_stream = stream;
|
|
|
|
m_renderingVideo = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setStreamAndRenderer(DATVideoRender *renderer, DATVideostream *stream)
|
|
|
|
{
|
2021-03-23 03:35:30 -04:00
|
|
|
m_renderingVideo = false;
|
2019-03-19 20:14:38 -04:00
|
|
|
m_renderer = renderer;
|
|
|
|
m_stream = stream;
|
|
|
|
}
|
2018-02-22 16:52:49 -05:00
|
|
|
|
2019-03-19 20:14:38 -04:00
|
|
|
void run()
|
|
|
|
{
|
2021-03-23 03:35:30 -04:00
|
|
|
if (m_renderingVideo) {
|
2019-03-19 20:14:38 -04:00
|
|
|
return;
|
2018-02-22 16:52:49 -05:00
|
|
|
}
|
|
|
|
|
2021-03-23 03:35:30 -04:00
|
|
|
if ((m_renderer == nullptr) || (m_stream == nullptr)) {
|
2019-03-19 20:14:38 -04:00
|
|
|
return;
|
|
|
|
}
|
2018-02-22 16:52:49 -05:00
|
|
|
|
2021-04-05 07:13:57 -04:00
|
|
|
m_renderingVideo = m_renderer->openStream(m_stream);
|
2018-02-22 16:52:49 -05:00
|
|
|
|
2021-03-23 03:35:30 -04:00
|
|
|
if (!m_renderingVideo) {
|
2019-03-19 20:14:38 -04:00
|
|
|
return;
|
2018-02-22 16:52:49 -05:00
|
|
|
}
|
|
|
|
|
2021-03-27 00:33:09 -04:00
|
|
|
while ((m_renderingVideo == true) && (m_renderer))
|
2018-02-22 16:52:49 -05:00
|
|
|
{
|
2021-04-05 07:13:57 -04:00
|
|
|
if (!m_renderer->renderStream()) {
|
2021-03-23 03:35:30 -04:00
|
|
|
break;
|
|
|
|
}
|
2018-02-22 16:52:49 -05:00
|
|
|
}
|
|
|
|
|
2021-04-05 07:13:57 -04:00
|
|
|
m_renderer->closeStream(m_stream);
|
2019-03-19 20:14:38 -04:00
|
|
|
m_renderingVideo = false;
|
|
|
|
}
|
|
|
|
|
2021-03-30 23:03:10 -04:00
|
|
|
void stopRendering() {
|
2019-03-19 20:14:38 -04:00
|
|
|
m_renderingVideo = false;
|
|
|
|
}
|
2018-02-22 16:52:49 -05:00
|
|
|
|
2021-04-04 20:42:36 -04:00
|
|
|
static const int videoThreadTimeoutMs = 1000;
|
2021-03-28 12:40:43 -04:00
|
|
|
|
2019-03-19 20:14:38 -04:00
|
|
|
private:
|
|
|
|
DATVideoRender *m_renderer;
|
|
|
|
DATVideostream *m_stream;
|
|
|
|
bool m_renderingVideo;
|
2018-02-22 16:52:49 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif // DATVIDEORENDER_H
|