/client/AnyVODClient/src/media/MediaPresenter.cpp
C++ | 8316 lines | 6631 code | 1670 blank | 15 comment | 1083 complexity | 4488bebedeed7fa07cfa0faac6f830f4 MD5 | raw file
- /*************************************************************************
- Copyright (c) 2011-2017, DongRyeol Cha (chadr@dcple.com)
- 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, either version 3 of the License, or
- (at your option) any later version.
- 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 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/>
- *************************************************************************/
- #include <QGlobalStatic>
- #define GL_NV_geometry_program4
- #ifndef Q_OS_WIN
- #define GL_GLEXT_PROTOTYPES
- #endif
- #ifdef Q_OS_WIN
- #ifdef _WIN32_WINNT
- #undef _WIN32_WINNT
- #endif
- #define _WIN32_WINNT 0x0501
- #endif
- #ifndef UNICODE
- #define UNICODE
- #endif
- #ifndef _UNICODE
- #define _UNICODE
- #endif
- #include "MediaPresenter.h"
- #include "MediaState.h"
- #include "core/Utils.h"
- #include "video/Sphere.h"
- #include "media/FrameExtractor.h"
- #if !defined Q_OS_MOBILE
- #include "ui/MainWindow.h"
- #endif
- extern "C"
- {
- #include <libavutil/pixdesc.h>
- #include <libavutil/time.h>
- #include <libavutil/audio_fifo.h>
- #include <libavutil/imgutils.h>
- #include <libswresample/swresample.h>
- #include <libswscale/swscale.h>
- #if !defined Q_OS_MOBILE
- #include <libavdevice/avdevice.h>
- #endif
- }
- #include <ass/ass.h>
- #include <bass/bass_fx.h>
- #include <bass/bassmix.h>
- #ifndef Q_OS_MAC
- #include <omp.h>
- #endif
- #if !defined Q_OS_MOBILE
- #include <MediaInfoDLL/MediaInfoDLL.h>
- #endif
- #if !defined Q_OS_MOBILE
- #include <QApplication>
- #include <QDesktopWidget>
- #endif
- #include <algorithm>
- #include <QStringList>
- #include <QFileInfo>
- #include <qmath.h>
- #include <QTextStream>
- #include <QMutexLocker>
- #include <QRect>
- #include <QPainter>
- #include <QFile>
- #include <QDir>
- #include <QOpenGLFramebufferObject>
- #include <QTemporaryFile>
- #if defined Q_OS_MOBILE
- #include <QOpenGLFunctions>
- #endif
- #include <QDebug>
- #ifdef Q_OS_MAC
- #include <mach/task_info.h>
- #include <mach/task.h>
- #include <mach/mach_init.h>
- #include <mach/mach_traps.h>
- #include <mach/mach_port.h>
- #include <mach/vm_map.h>
- #include <mach/thread_act.h>
- #include <mach/host_info.h>
- #include <mach/mach_host.h>
- #endif
- using namespace std;
- #if !defined Q_OS_MOBILE
- using namespace MediaInfoDLL;
- #endif
- #ifdef Q_OS_WIN
- extern PFNGLBINDBUFFERARBPROC glBindBufferARB;
- extern PFNGLBUFFERDATAARBPROC glBufferDataARB;
- extern PFNGLMAPBUFFERARBPROC glMapBufferARB;
- extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
- extern PFNGLACTIVETEXTUREPROC glActiveTextureARB;
- #endif
- const int MediaPresenter::DEFAULT_VIRT_SUBTITLE_RATIO = 10;
- const int MediaPresenter::DEFAULT_HORI_SUBTITLE_RATIO = 10;
- const int MediaPresenter::OPTION_DESC_TIME = 3000;
- const QString MediaPresenter::SUBTITLE_CODEC_FORMAT = "%1 (%2)";
- const QPoint MediaPresenter::DEFAULT_3D_SUBTITLE_OFFSET = QPoint(2, 0);
- const QPoint MediaPresenter::DEFAULT_VR_SUBTITLE_OFFSET = QPoint(-4, 0);
- const qreal MediaPresenter::DEFAULT_VIRTUAL_3D_DEPTH = 0.15;
- const AVPixelFormat MediaPresenter::DEFAULT_PIX_FORMAT = AV_PIX_FMT_BGR32;
- VirtualFile MediaPresenter::VIRTUAL_FILE;
- DTVReader MediaPresenter::DTV_READER;
- QDataStream& operator << (QDataStream &out, const MediaPresenter::Range &item)
- {
- out << item.start;
- out << item.end;
- out << item.enable;
- return out;
- }
- QDataStream& operator >> (QDataStream &in, MediaPresenter::Range &item)
- {
- in >> item.start;
- in >> item.end;
- in >> item.enable;
- return in;
- }
- #ifdef Q_OS_ANDROID
- static void ff_log_callback(void*, int level, const char *fmt, va_list vl)
- {
- if (level <= av_log_get_level())
- {
- char buf[1024];
- vsnprintf(buf, sizeof(buf), fmt, vl);
- }
- }
- #endif
- MediaPresenter::MediaPresenter(const int width, const int height) :
- QThread(),
- m_volume(this->getMaxVolume() / 2),
- m_width(width),
- m_height(height),
- m_state(nullptr),
- m_forceExit(false),
- m_format(DEFAULT_PIX_FORMAT),
- m_showDetail(false),
- m_isMute(false),
- m_subtitleFontSize(0),
- m_showSubtitle(true),
- m_showOptionDesc(false),
- m_showingOptionDesc(false),
- m_subtitleSync(0.0),
- m_audioSync(0.0),
- m_isRemoteFile(false),
- m_isRemoteProtocol(false),
- m_fontSize(0),
- m_fontOutlineSize(1),
- m_subtitleOutlineSize(0),
- m_subtitleMaxOutlineSize(0),
- m_lastAudioStream(-1),
- m_lastSubtitleStream(-1),
- m_vertPosition(0),
- m_horiPosition(0),
- m_texInfo(nullptr),
- m_isAudioExt(false),
- m_halign(AnyVODEnums::HAM_NONE),
- m_valign(AnyVODEnums::VAM_NONE),
- m_3dMethod(AnyVODEnums::V3M_NONE),
- m_3dSubtitleMethod(AnyVODEnums::S3M_NONE),
- m_vrInputSource(AnyVODEnums::VRI_NONE),
- m_seekKeyFrame(true),
- m_skipOpening(false),
- m_skipEnding(false),
- m_useSkipRange(false),
- m_subtitleOpaque(1.0f),
- m_subtitleSize(1.0f),
- #if defined Q_OS_MOBILE
- m_useHWDecoder(true),
- #else
- m_useHWDecoder(false),
- #endif
- m_useSPDIF(false),
- m_userSPDIFSampleRate(0),
- m_usePBO(false),
- m_enableSearchSubtitle(false),
- m_enableSearchLyrics(false),
- m_autoSaveSearchLyrics(false),
- m_showAlbumJacket(true),
- #if defined Q_OS_MOBILE
- m_useFrameDrop(true),
- #else
- m_useFrameDrop(false),
- #endif
- m_useBufferingMode(false),
- m_SPIDFEncodingMethod(AnyVODEnums::SEM_NONE),
- m_screenRotationDegree(AnyVODEnums::SRD_NONE),
- m_use3DFull(false),
- m_maxTextureSize(0),
- #if defined Q_OS_MOBILE
- m_useGPUConvert(true),
- #else
- m_useGPUConvert(false),
- #endif
- m_anaglyphFrameBuffer(nullptr),
- m_distortionFrameBuffer(nullptr),
- m_leftDistortionFrameBuffer(nullptr),
- m_rightDistortionFrameBuffer(nullptr),
- m_videoThread(this),
- m_subtitleThread(this),
- m_readThread(this),
- m_refreshThread(this),
- #if defined Q_OS_MOBILE
- m_gl(nullptr),
- #endif
- m_audioDevice(-1),
- m_rotation(0.0),
- m_sensorRotation(0.0),
- m_optionDescY(0),
- m_scheduleRecomputeSubtitleSize(false),
- m_useSubtitleCacheMode(false),
- m_devicePixelRatio(1.0),
- m_captureMode(false),
- m_useLowQualityMode(true),
- m_controlLocker(QMutex::Recursive),
- m_screenOffset(0, 0),
- m_useDistortion(true),
- m_barrelDistortionCoefficients(0.05f, 0.20f),
- m_pincushionDistortionCoefficients(0.075f, -0.005f),
- m_distortionLensCenter(0.0f, 0.0f),
- m_cameraLock(QMutex::Recursive),
- m_distortionAdjustMode(AnyVODEnums::DAM_NONE),
- m_virtual3DDepth(DEFAULT_VIRTUAL_3D_DEPTH),
- m_subtitleType(ST_NONE),
- m_isLive(false),
- m_bluetoothHeadsetConnected(false),
- m_bluetoothHeadsetSync(0.0)
- {
- this->reset3DSubtitleOffset();
- }
- MediaPresenter::~MediaPresenter()
- {
- this->close();
- this->clearFrameBuffers();
- }
- void MediaPresenter::init()
- {
- av_log_set_level(AV_LOG_QUIET);
- #ifdef Q_OS_ANDROID
- av_log_set_callback(ff_log_callback);
- #endif
- ffurl_append_protocol(DTV_READER.getProtocol());
- ffurl_append_protocol(VIRTUAL_FILE.getProtocol());
- #if !defined Q_OS_MOBILE
- avdevice_register_all();
- #endif
- avfilter_register_all();
- avcodec_register_all();
- av_register_all();
- avformat_network_init();
- Sphere::init();
- }
- void MediaPresenter::deInit()
- {
- avformat_network_deinit();
- Sphere::deInit();
- }
- bool MediaPresenter::open(const QString &filePath, const QString &title, const ExtraPlayData &data,
- const QString &fontFamily, const int fontSize, const int subtitleOutlineSize,
- const QString &audioPath)
- {
- this->m_filePath = filePath;
- this->m_audioPath = audioPath;
- this->m_isRemoteFile = Utils::determinRemoteFile(filePath);
- this->m_isRemoteProtocol = Utils::determinRemoteProtocol(filePath);
- this->m_isLive = filePath.startsWith("hls+");
- this->m_realFilePath = Utils::removeFFMpegSeparator(filePath);
- this->m_title = title;
- if (!data.isValid())
- {
- #if !defined Q_OS_MOBILE
- MediaInfo mi;
- bool isDevice = false;
- isDevice = Utils::determinDevice(filePath);
- if (!isDevice && mi.Open(filePath.toStdWString()) == 1)
- {
- QString totalTime = QString::fromStdWString(mi.Get(Stream_General, 0, __T("Duration")));
- QString totalFrame = QString::fromStdWString(mi.Get(Stream_Video, 0, __T("FrameCount")));
- if (totalTime.toDouble() < 0.0)
- this->m_playData.duration = 0.0;
- else
- this->m_playData.duration = totalTime.toDouble() / 1000.0;
- this->m_playData.totalFrame = totalFrame.toUInt();
- if (this->m_playData.totalFrame <= 0)
- {
- QString frameRate = QString::fromStdWString(mi.Get(Stream_Video, 0, __T("FrameRate")));
- if (frameRate.isEmpty())
- frameRate = QString::fromStdWString(mi.Get(Stream_Video, 0, __T("FrameRate_Original")));
- if (frameRate.toDouble() < 0)
- this->m_playData.totalFrame = 0;
- else
- this->m_playData.totalFrame = uint32_t(frameRate.toDouble() * this->m_playData.duration);
- }
- QString rotation = QString::fromStdWString(mi.Get(Stream_Video, 0, __T("Rotation")));
- this->m_rotation = rotation.toDouble();
- mi.Close();
- }
- #endif
- this->m_playData.userData = data.userData;
- }
- else
- {
- this->m_playData = data;
- }
- this->m_fontFamily = fontFamily;
- this->m_fontSize = fontSize * this->m_devicePixelRatio;
- this->m_fontOutlineSize = 1 * this->m_devicePixelRatio;
- this->m_subtitleMaxOutlineSize = subtitleOutlineSize * this->m_devicePixelRatio;
- QFileInfo fileInfo(this->m_realFilePath);
- this->m_isAudioExt = Utils::isExtension(fileInfo.suffix(), Utils::MT_AUDIO);
- return true;
- }
- void MediaPresenter::openRemoteSubtitle(const QString &filePath)
- {
- VIRTUAL_FILE.loadSubtitle(filePath, this);
- }
- bool MediaPresenter::saveSubtitleAs(const QString &filePath)
- {
- bool success = false;
- double sync = -this->m_subtitleSync;
- if (this->m_samiParser.isExist())
- success = this->m_samiParser.save(filePath, sync);
- else if (this->m_srtParser.isExist())
- success = this->m_srtParser.save(filePath, sync);
- else if (this->m_lrcParser.isExist())
- success = this->m_lrcParser.save(filePath, sync);
- else if (this->m_youtubeParser.isExist())
- success = this->m_youtubeParser.save(filePath, sync);
- return success;
- }
- bool MediaPresenter::saveSubtitle()
- {
- return this->saveSubtitleAs(this->m_subtitleFilePath);
- }
- QString MediaPresenter::getSubtitlePath() const
- {
- return this->m_subtitleFilePath;
- }
- bool MediaPresenter::openSubtitle(const QString &filePath, bool isExternal)
- {
- bool success = false;
- QFileInfo info(filePath);
- QString ext = info.suffix().toLower();
- if (ext == "smi" || ext == "sami")
- success = this->openSAMI(filePath) || this->openSRT(filePath);
- else if (ext == "ass" || ext == "ssa")
- success = this->openASS(filePath);
- else if (ext == "srt")
- success = this->openSRT(filePath) || this->openSAMI(filePath);
- else if (ext == "lrc")
- success = this->openLRC(filePath);
- if (!success)
- success = this->openAVParser(filePath);
- if (!success && isExternal)
- success = this->openYouTube(filePath);
- this->m_subtitleFilePath = filePath;
- return success;
- }
- bool MediaPresenter::openSAMI(const QString &filePath)
- {
- if (this->m_samiParser.open(filePath))
- {
- this->m_detail.subtitleCodec = "SAMI Parser";
- this->m_subtitleType = ST_SAMI;
- return true;
- }
- return false;
- }
- bool MediaPresenter::openASS(const QString &filePath)
- {
- if (this->m_assParser.open(filePath))
- {
- QFileInfo info(filePath);
- if (info.suffix().toLower() == "ass")
- this->m_detail.subtitleCodec = "ASS Parser";
- else if (info.suffix().toLower() == "ssa")
- this->m_detail.subtitleCodec = "SSA Parser";
- else
- this->m_detail.subtitleCodec = "Unknown Parser";
- this->m_assParser.setDefaultFont(this->m_assFontFamily);
- this->m_subtitleType = ST_ASS;
- return true;
- }
- return false;
- }
- bool MediaPresenter::openSRT(const QString &filePath)
- {
- if (this->m_srtParser.open(filePath))
- {
- this->m_detail.subtitleCodec = "SRT Parser";
- this->m_subtitleType = ST_SRT;
- return true;
- }
- return false;
- }
- bool MediaPresenter::openYouTube(const QString &id)
- {
- if (this->m_youtubeParser.open(id))
- {
- this->m_detail.subtitleCodec = "YouTube Parser";
- this->m_subtitleType = ST_YOUTUBE;
- return true;
- }
- return false;
- }
- bool MediaPresenter::openLRC(const QString &filePath)
- {
- if (this->m_lrcParser.open(filePath))
- {
- this->m_detail.subtitleCodec = "LRC Parser";
- this->m_subtitleType = ST_LRC;
- return true;
- }
- return false;
- }
- bool MediaPresenter::openAVParser(const QString &filePath)
- {
- QString fontPath;
- this->m_assParser.getFontPath(&fontPath);
- if (this->m_avParser.open(filePath, fontPath, this->m_fontFamily))
- {
- this->m_avParser.setCurrentIndex(0);
- this->m_detail.subtitleCodec = "AV Parser";
- this->m_subtitleType = ST_AV;
- return true;
- }
- return false;
- }
- void MediaPresenter::closeAllExternalSubtitles()
- {
- this->m_assParser.close();
- this->m_samiParser.close();
- this->m_srtParser.close();
- this->m_youtubeParser.close();
- this->m_lrcParser.close();
- this->m_avParser.close();
- this->m_subtitleFilePath.clear();
- this->m_subtitleType = ST_NONE;
- this->m_detail.subtitleBitmap = false;
- this->m_detail.subtitleValidColor = true;
- MediaState *ms = this->m_state;
- if (ms && ms->subtitle.stream.stream)
- {
- const AVCodec *codec = ms->subtitle.stream.ctx->codec;
- this->m_detail.subtitleCodec = QString(SUBTITLE_CODEC_FORMAT).arg(QString(codec->name).toUpper()).arg(codec->long_name);
- }
- }
- void MediaPresenter::close()
- {
- QMutexLocker locker(&this->m_controlLocker);
- this->m_forceExit = true;
- if (this->isRunning())
- this->wait();
- this->closeInternal();
- this->m_playData = ExtraPlayData();
- }
- void MediaPresenter::setDevicePixelRatio(double ratio)
- {
- this->m_devicePixelRatio = ratio;
- }
- void MediaPresenter::closeInternal()
- {
- if (this->m_state)
- this->m_state->quit = true;
- this->m_forceExit = false;
- this->closeStream();
- this->closeAllExternalSubtitles();
- this->callEmptyCallback(false);
- this->m_isRemoteFile = false;
- this->m_audioStreamInfo.clear();
- this->m_subtitleStreamInfo.clear();
- this->m_detail = Detail();
- this->m_repeatRange = Range();
- this->m_GOMSubtitleURL.clear();
- this->m_rotation = 0.0;
- this->m_optionDescY = 0;
- this->m_format = DEFAULT_PIX_FORMAT;
- this->m_scheduleRecomputeSubtitleSize = false;
- this->setSensorRotation(0.0);
- this->scheduleInitTextures();
- }
- #if defined Q_OS_MOBILE
- void MediaPresenter::setGL(QOpenGLFunctions *gl)
- {
- this->m_gl = gl;
- this->m_font.setGL(gl);
- this->m_subtitleFont.setGL(gl);
- }
- #endif
- void MediaPresenter::scheduleInitTextures()
- {
- if (this->m_texInfo)
- {
- for (int i = 0; i < TEX_COUNT; i++)
- {
- for (unsigned int j = 0; j < this->m_texInfo[i].textureCount; j++)
- this->m_texInfo[i].init[j] = false;
- }
- }
- }
- bool MediaPresenter::resetScreen(const int width, const int height, TextureInfo *texInfo, bool inContext)
- {
- this->m_width = width;
- this->m_height = height;
- this->m_texInfo = texInfo;
- this->m_ortho.setToIdentity();
- this->m_ortho.ortho(0.0f, (float)width, (float)height, 0.0f, -1.0f, 1.0f);
- this->m_font.setOrtho(this->m_ortho);
- this->m_subtitleFont.setOrtho(this->m_ortho);
- if (inContext)
- {
- this->initFrameBufferObject(&this->m_distortionFrameBuffer, width, height);
- this->initFrameBufferObject(&this->m_leftDistortionFrameBuffer, width, height);
- this->initFrameBufferObject(&this->m_rightDistortionFrameBuffer, width, height);
- }
- this->scheduleInitTextures();
- if (this->m_state && this->m_state->video.stream.stream)
- {
- this->computeFrameSize();
- return true;
- }
- else
- {
- return false;
- }
- }
- bool MediaPresenter::play()
- {
- QMutexLocker locker(&this->m_controlLocker);
- bool success = false;
- success = this->openStream();
- if (success)
- {
- this->start();
- }
- else
- {
- this->m_state->quit = true;
- this->closeStream();
- }
- return success;
- }
- void MediaPresenter::pause()
- {
- QMutexLocker locker(&this->m_controlLocker);
- MediaState *ms = this->m_state;
- if (ms && !ms->pause.pause)
- {
- ms->pause.pause = true;
- ms->pause.startTime = this->getAbsoluteClock();
- ms->pause.lastPausedTime = ms->frameTimer.lastPTS;
- if (this->m_spdif.isOpened())
- this->m_spdif.pause();
- else
- BASS_Pause();
- }
- }
- void MediaPresenter::resume()
- {
- QMutexLocker locker(&this->m_controlLocker);
- MediaState *ms = this->m_state;
- if (ms && ms->pause.pause)
- {
- ms->pause.driftTime += this->getAbsoluteClock() - ms->pause.startTime;
- ms->pause.pause = false;
- ms->seek.inc = 0.0;
- if (this->m_spdif.isOpened())
- this->m_spdif.resume();
- else
- BASS_Start();
- }
- if (ms)
- ms->willBeEnd = false;
- }
- void MediaPresenter::stop()
- {
- this->close();
- }
- bool MediaPresenter::isPlayUserDataEmpty() const
- {
- return this->m_playData.userData.isEmpty();
- }
- QString MediaPresenter::getTitle() const
- {
- return this->m_title;
- }
- void MediaPresenter::prevFrame(int count)
- {
- QMutexLocker locker(&this->m_controlLocker);
- MediaState *ms = this->m_state;
- if (ms)
- {
- double clock = ms->pause.pause ? ms->pause.lastPausedTime : ms->frameTimer.lastPTS;
- double frameTime = this->getDuration() / this->m_detail.videoTotalFrame;
- double target = clock - (count + 1) * frameTime;
- if (!ms->pause.pause)
- this->pause();
- this->seekStream(target, 0.0, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
- }
- }
- void MediaPresenter::nextFrame(int count)
- {
- MediaState *ms = this->m_state;
- if (ms)
- {
- ms->seek.requestPauseOnRender = true;
- ms->seek.pauseOnRenderCount = count;
- this->resume();
- }
- }
- bool MediaPresenter::render(ShaderCompositer &shader)
- {
- QMutexLocker locker(&this->m_controlLocker);
- return this->update(shader);
- }
- void MediaPresenter::setSubtitleSync(double value)
- {
- this->m_subtitleSync = value;
- }
- double MediaPresenter::getSubtitleSync() const
- {
- return this->m_subtitleSync;
- }
- void MediaPresenter::audioSync(double value)
- {
- this->m_audioSync = value;
- }
- double MediaPresenter::getAudioSync() const
- {
- return this->m_audioSync;
- }
- void MediaPresenter::showDetail(bool show)
- {
- this->m_showDetail = show;
- }
- bool MediaPresenter::isShowDetail() const
- {
- return this->m_showDetail;
- }
- const MediaPresenter::Detail& MediaPresenter::getDetail() const
- {
- return this->m_detail;
- }
- void MediaPresenter::getAudioDevices(QStringList *ret) const
- {
- BASS_DEVICEINFO info;
- for (int i = 0; BASS_GetDeviceInfo(i, &info); i++)
- ret->append(QString::fromLocal8Bit(info.name));
- }
- bool MediaPresenter::setAudioDevice(int device)
- {
- this->m_audioDevice = device;
- if (!this->m_spdif.isOpened())
- return this->setAudioDeviceAfter();
- else
- return true;
- }
- int MediaPresenter::getCurrentAudioDevice() const
- {
- return this->m_audioDevice;
- }
- bool MediaPresenter::setAudioDeviceAfter()
- {
- if (this->resetAudioStream())
- return true;
- if (this->m_state)
- this->m_state->audio.stream.index = this->m_lastAudioStream;
- return false;
- }
- void MediaPresenter::getSPDIFAudioDevices(QStringList *ret)
- {
- this->m_spdif.getDeviceList(ret);
- }
- bool MediaPresenter::setSPDIFAudioDevice(int device)
- {
- if (this->m_spdif.setDevice(device))
- {
- if (this->m_spdif.isOpened())
- return this->setAudioDeviceAfter();
- else
- return true;
- }
- return false;
- }
- int MediaPresenter::getCurrentSPDIFAudioDevice() const
- {
- return this->m_spdif.getDevice();
- }
- void MediaPresenter::showSubtitle(bool show)
- {
- this->m_showSubtitle = show;
- }
- bool MediaPresenter::isShowSubtitle() const
- {
- return this->m_showSubtitle;
- }
- bool MediaPresenter::existFileSubtitle()
- {
- return this->m_samiParser.isExist() ||
- this->m_srtParser.isExist() ||
- this->m_youtubeParser.isExist() ||
- this->m_lrcParser.isExist();
- }
- bool MediaPresenter::existSubtitle()
- {
- return (this->m_state && this->m_state->subtitle.stream.stream) ||
- this->m_samiParser.isExist() ||
- this->m_assParser.isExist() ||
- this->m_srtParser.isExist() ||
- this->m_youtubeParser.isExist() ||
- this->m_lrcParser.isExist() ||
- this->m_avParser.isExist();
- }
- bool MediaPresenter::existExternalSubtitle()
- {
- return this->m_samiParser.isExist() ||
- this->m_assParser.isExist() ||
- this->m_srtParser.isExist() ||
- this->m_youtubeParser.isExist() ||
- this->m_lrcParser.isExist() ||
- this->m_avParser.isExist();
- }
- double MediaPresenter::getRotation() const
- {
- return this->m_rotation;
- }
- void MediaPresenter::setSensorRotation(double rot)
- {
- QMutexLocker locker(&this->m_cameraLock);
- this->m_sensorRotation = rot;
- }
- double MediaPresenter::getSensorRotation()
- {
- double rot;
- this->m_cameraLock.lock();
- rot = this->m_sensorRotation;
- this->m_cameraLock.unlock();
- return rot;
- }
- bool MediaPresenter::isAlignable()
- {
- return (this->m_state && this->m_state->subtitle.stream.stream &&
- this->m_state->subtitle.stream.ctx->subtitle_header_size <= 0 &&
- this->m_state->subtitle.isBitmap == false) ||
- this->m_samiParser.isExist() ||
- this->m_youtubeParser.isExist() ||
- this->m_srtParser.isExist();
- }
- AnyVODEnums::HAlignMethod MediaPresenter::getHAlign() const
- {
- return this->m_halign;
- }
- void MediaPresenter::setHAlign(AnyVODEnums::HAlignMethod align)
- {
- this->m_halign = align;
- }
- AnyVODEnums::VAlignMethod MediaPresenter::getVAlign() const
- {
- return this->m_valign;
- }
- void MediaPresenter::setVAlign(AnyVODEnums::VAlignMethod align)
- {
- this->m_valign = align;
- }
- bool MediaPresenter::existAudioSubtitle()
- {
- return this->m_lrcParser.isExist();
- }
- bool MediaPresenter::existAudioSubtitleGender() const
- {
- return this->m_lrcParser.isGenderExist();
- }
- void MediaPresenter::setSubtitleURL(const QString &url)
- {
- this->m_GOMSubtitleURL = url;
- }
- void MediaPresenter::getSubtitleURL(QString *ret) const
- {
- *ret = this->m_GOMSubtitleURL;
- }
- void MediaPresenter::setASSFontPath(const QString &path)
- {
- this->m_assParser.setFontPath(path);
- }
- void MediaPresenter::setASSFontFamily(const QString &family)
- {
- this->m_assFontFamily = family;
- }
- void MediaPresenter::getSubtitleClasses(QStringList *classNames)
- {
- if (this->m_samiParser.isExist())
- {
- this->m_samiParser.getClassNames(classNames);
- }
- else if (this->m_youtubeParser.isExist())
- {
- this->m_youtubeParser.getLanguages(classNames);
- }
- else if (this->m_avParser.isExist())
- {
- QVector<SubtitleStreamInfo> infos;
- this->m_avParser.getStreamInfos(&infos);
- for (int i = 0; i < infos.count(); i++)
- classNames->append(infos[i].name);
- }
- else
- {
- for (int i = 0; i < this->m_subtitleStreamInfo.count(); i++)
- classNames->append(this->m_subtitleStreamInfo[i].name);
- }
- }
- void MediaPresenter::getCurrentSubtitleClass(QString *className)
- {
- if (this->m_samiParser.isExist())
- {
- this->m_samiParser.getDefaultClassName(className);
- }
- else if (this->m_youtubeParser.isExist())
- {
- this->m_youtubeParser.getDefaultLanguage(className);
- }
- else if (this->m_avParser.isExist())
- {
- this->m_avParser.getCurrentName(className);
- }
- else
- {
- if (!this->m_state)
- return;
- QString name;
- for (int i = 0; i < this->m_subtitleStreamInfo.count(); i++)
- {
- if (this->m_subtitleStreamInfo[i].index == this->m_state->subtitle.stream.index)
- {
- name = this->m_subtitleStreamInfo[i].name;
- break;
- }
- }
- *className = name;
- }
- }
- bool MediaPresenter::setCurrentSubtitleClass(const QString &className)
- {
- if (this->m_samiParser.isExist())
- {
- this->m_samiParser.setDefaultClassName(className);
- return true;
- }
- else if (this->m_youtubeParser.isExist())
- {
- this->m_youtubeParser.setDefaultLanguage(className);
- return true;
- }
- else if (this->m_avParser.isExist())
- {
- QVector<SubtitleStreamInfo> infos;
- unsigned int index = 0;
- this->m_avParser.getStreamInfos(&infos);
- for (int i = 0; i < infos.count(); i++)
- {
- if (infos[i].name == className)
- {
- index = infos[i].index;
- break;
- }
- }
- this->m_avParser.setCurrentIndex(index);
- return true;
- }
- else
- {
- if (!this->m_state)
- return false;
- int index = -1;
- for (int i = 0; i < this->m_subtitleStreamInfo.count(); i++)
- {
- if (this->m_subtitleStreamInfo[i].name == className)
- {
- index = this->m_subtitleStreamInfo[i].index;
- break;
- }
- }
- Subtitle &subtitle = this->m_state->subtitle;
- subtitle.stream.queue.flush();
- subtitle.requestReleaseQueue = true;
- return this->changeStream(index, subtitle.stream.index, false, &this->m_lastSubtitleStream, &subtitle.threadQuit);
- }
- }
- void MediaPresenter::resetSubtitlePosition()
- {
- this->m_vertPosition = 0;
- this->m_horiPosition = 0;
- }
- void MediaPresenter::setVerticalSubtitlePosition(int pos)
- {
- this->m_vertPosition += pos;
- }
- void MediaPresenter::setHorizontalSubtitlePosition(int pos)
- {
- this->m_horiPosition += pos;
- }
- void MediaPresenter::setVerticalSubtitleAbsolutePosition(int pos)
- {
- this->m_vertPosition = pos;
- }
- void MediaPresenter::setHorizontalSubtitleAbsolutePosition(int pos)
- {
- this->m_horiPosition = pos;
- }
- int MediaPresenter::getVerticalSubtitlePosition() const
- {
- return this->m_vertPosition;
- }
- int MediaPresenter::getHorizontalSubtitlePosition() const
- {
- return this->m_horiPosition;
- }
- void MediaPresenter::reset3DSubtitleOffset()
- {
- if (this->m_vrInputSource == AnyVODEnums::VRI_NONE)
- this->m_3dSubtitleOffset = DEFAULT_3D_SUBTITLE_OFFSET;
- else
- this->m_3dSubtitleOffset = DEFAULT_VR_SUBTITLE_OFFSET;
- }
- void MediaPresenter::setVertical3DSubtitleOffset(int pos)
- {
- this->m_3dSubtitleOffset.ry() += pos;
- }
- void MediaPresenter::setHorizontal3DSubtitleOffset(int pos)
- {
- this->m_3dSubtitleOffset.rx() += pos;
- }
- void MediaPresenter::setVertical3DSubtitleAbsoluteOffset(int pos)
- {
- this->m_3dSubtitleOffset.ry() = pos;
- }
- void MediaPresenter::setHorizontal3DSubtitleAbsoluteOffset(int pos)
- {
- this->m_3dSubtitleOffset.rx() = pos;
- }
- int MediaPresenter::getVertical3DSubtitleOffset() const
- {
- return this->m_3dSubtitleOffset.y();
- }
- int MediaPresenter::getHorizontal3DSubtitleOffset() const
- {
- return this->m_3dSubtitleOffset.x();
- }
- void MediaPresenter::resetVirtual3DDepth()
- {
- this->m_virtual3DDepth = DEFAULT_VIRTUAL_3D_DEPTH;
- }
- void MediaPresenter::setVirtual3DDepth(qreal depth)
- {
- this->m_virtual3DDepth = depth;
- }
- qreal MediaPresenter::getVirtual3DDepth() const
- {
- return this->m_virtual3DDepth;
- }
- void MediaPresenter::setRepeatStart(double start)
- {
- this->m_repeatRange.start = start;
- }
- void MediaPresenter::setRepeatEnd(double end)
- {
- this->m_repeatRange.end = end;
- }
- void MediaPresenter::setRepeatEnable(bool enable)
- {
- this->m_repeatRange.enable = enable;
- }
- bool MediaPresenter::getRepeatEnable() const
- {
- return this->m_repeatRange.enable;
- }
- double MediaPresenter::getRepeatStart() const
- {
- return this->m_repeatRange.start;
- }
- double MediaPresenter::getRepeatEnd() const
- {
- return this->m_repeatRange.end;
- }
- void MediaPresenter::setCaptureMode(bool capture)
- {
- this->m_captureMode = capture;
- }
- bool MediaPresenter::getCaptureMode() const
- {
- return this->m_captureMode;
- }
- void MediaPresenter::setSeekKeyFrame(bool keyFrame)
- {
- this->m_seekKeyFrame = keyFrame;
- }
- bool MediaPresenter::isSeekKeyFrame() const
- {
- return this->m_seekKeyFrame;
- }
- void MediaPresenter::set3DMethod(AnyVODEnums::Video3DMethod method)
- {
- this->m_3dMethod = method;
- this->computeFrameSize();
- }
- AnyVODEnums::Video3DMethod MediaPresenter::get3DMethod() const
- {
- return this->m_3dMethod;
- }
- void MediaPresenter::setSubtitle3DMethod(AnyVODEnums::Subtitle3DMethod method)
- {
- this->m_3dSubtitleMethod = method;
- }
- AnyVODEnums::Subtitle3DMethod MediaPresenter::getSubtitle3DMethod() const
- {
- return this->m_3dSubtitleMethod;
- }
- void MediaPresenter::setVRInputSource(AnyVODEnums::VRInputSource source)
- {
- this->m_vrInputSource = source;
- this->computeFrameSize();
- this->reset3DSubtitleOffset();
- }
- AnyVODEnums::VRInputSource MediaPresenter::getVRInputSource() const
- {
- return this->m_vrInputSource;
- }
- void MediaPresenter::setDistortionAdjustMode(AnyVODEnums::DistortionAdjustMode mode)
- {
- this->m_distortionAdjustMode = mode;
- }
- AnyVODEnums::DistortionAdjustMode MediaPresenter::getDistortionAdjustMode() const
- {
- return this->m_distortionAdjustMode;
- }
- void MediaPresenter::setSkipRanges(const QVector<Range> &ranges)
- {
- this->m_skipRanges = ranges;
- }
- void MediaPresenter::getSkipRanges(QVector<Range> *ret) const
- {
- *ret = this->m_skipRanges;
- }
- void MediaPresenter::setSkipOpening(bool skip)
- {
- this->m_skipOpening = skip;
- }
- bool MediaPresenter::getSkipOpening() const
- {
- return this->m_skipOpening;
- }
- void MediaPresenter::setSkipEnding(bool skip)
- {
- this->m_skipEnding = skip;
- }
- bool MediaPresenter::getSkipEnding() const
- {
- return this->m_skipEnding;
- }
- void MediaPresenter::setUseSkipRange(bool use)
- {
- this->m_useSkipRange = use;
- }
- bool MediaPresenter::getUseSkipRange() const
- {
- return this->m_useSkipRange;
- }
- double MediaPresenter::getOpeningSkipTime() const
- {
- for (int i = 0; i < this->m_skipRanges.count(); i++)
- {
- if (this->m_skipRanges[i].start < 0.0)
- return this->m_skipRanges[i].end;
- }
- return 0.0;
- }
- double MediaPresenter::getEndingSkipTime() const
- {
- for (int i = 0; i < this->m_skipRanges.count(); i++)
- {
- if (this->m_skipRanges[i].end < 0.0)
- return this->m_skipRanges[i].start;
- }
- return 0.0;
- }
- void MediaPresenter::useNormalizer(bool use)
- {
- if (this->m_spdif.isOpened())
- return;
- this->m_audioEffect.useNormalizer = use;
- if (this->m_state && this->m_state->audio.handle)
- {
- if (use)
- this->initNormalizer();
- else
- this->closeNormalizer();
- }
- }
- bool MediaPresenter::isUsingNormalizer() const
- {
- return this->m_audioEffect.useNormalizer;
- }
- void MediaPresenter::useEqualizer(bool use)
- {
- if (this->m_spdif.isOpened())
- return;
- this->m_audioEffect.useEqualizer = use;
- if (this->m_state && this->m_state->audio.handle)
- {
- if (use)
- this->initEqualizer();
- else
- this->closeEqualizer();
- }
- }
- bool MediaPresenter::isUsingEqualizer() const
- {
- return this->m_audioEffect.useEqualizer;
- }
- void MediaPresenter::useLowerVoice(bool use)
- {
- if (this->m_spdif.isOpened())
- return;
- this->m_audioEffect.useLowerVoice = use;
- if (this->m_state && this->m_state->audio.handle)
- {
- if (use)
- this->initLowerVoice();
- else
- this->closeLowerVoice();
- }
- }
- bool MediaPresenter::isUsingLowerVoice() const
- {
- return this->m_audioEffect.useLowerVoice;
- }
- void MediaPresenter::useHigherVoice(bool use)
- {
- if (this->m_spdif.isOpened())
- return;
- this->m_audioEffect.useHigherVoice = use;
- if (this->m_state && this->m_state->audio.handle)
- {
- if (use)
- this->initHigherVoice();
- else
- this->closeHigherVoice();
- }
- }
- bool MediaPresenter::isUsingHigherVoice() const
- {
- return this->m_audioEffect.useHigherVoice;
- }
- void MediaPresenter::useLowerMusic(bool use)
- {
- if (this->m_spdif.isOpened())
- return;
- this->m_audioEffect.useLowerMusic = use;
- if (this->m_state && this->m_state->audio.handle)
- {
- if (use)
- this->initLowerMusic();
- else
- this->closeLowerMusic();
- }
- }
- bool MediaPresenter::isUsingLowerMusic() const
- {
- return this->m_audioEffect.useLowerMusic;
- }
- void MediaPresenter::setSubtitleOpaque(float opaque)
- {
- this->m_subtitleOpaque = opaque;
- }
- float MediaPresenter::getSubtitleOpaque() const
- {
- return this->m_subtitleOpaque;
- }
- void MediaPresenter::setSubtitleSize(float size)
- {
- this->m_subtitleSize = size;
- if (!this->m_scheduleRecomputeSubtitleSize)
- this->computeSubtitleSize();
- }
- float MediaPresenter::getSubtitleSize() const
- {
- return this->m_subtitleSize;
- }
- void MediaPresenter::setScheduleRecomputeSubtitleSize()
- {
- this->m_scheduleRecomputeSubtitleSize = true;
- }
- bool MediaPresenter::setPreAmp(float dB)
- {
- this->m_audioEffect.preampValue = dB;
- if (this->m_audioEffect.preamp && this->m_state && this->m_state->audio.handle)
- {
- BASS_BFX_VOLUME vol;
- vol.lChannel = 0;
- vol.fVolume = BASS_BFX_dB2Linear(dB);
- if (BASS_FXSetParameters(this->m_audioEffect.preamp, &vol) == TRUE)
- return true;
- }
- else
- {
- return true;
- }
- return false;
- }
- float MediaPresenter::getPreAmp() const
- {
- return this->m_audioEffect.preampValue;
- }
- bool MediaPresenter::setEqualizerGain(int band, float gain)
- {
- QVector<Equalizer> &values = this->m_audioEffect.equalizerValues;
- if (band >= 0 && band < values.count())
- {
- Equalizer &eq = values[band];
- eq.gain = gain;
- if (this->m_audioEffect.eqaulizer && this->m_state && this->m_state->audio.handle)
- {
- BASS_BFX_PEAKEQ eqValue;
- eqValue.fBandwidth = eq.octave;
- eqValue.fCenter = eq.center;
- eqValue.fGain = eq.gain;
- eqValue.lBand = band;
- eqValue.lChannel = BASS_BFX_CHANALL;
- if (BASS_FXSetParameters(this->m_audioEffect.eqaulizer, &eqValue) == TRUE)
- return true;
- }
- else
- {
- return true;
- }
- }
- return false;
- }
- float MediaPresenter::getEqualizerGain(int band) const
- {
- const QVector<Equalizer> &values = this->m_audioEffect.equalizerValues;
- if (band >= 0 && band < values.count())
- return values[band].gain;
- return 0.0f;
- }
- int MediaPresenter::getBandCount() const
- {
- return this->m_audioEffect.equalizerValues.count();
- }
- bool MediaPresenter::isEnableSearchSubtitle() const
- {
- return this->m_enableSearchSubtitle;
- }
- bool MediaPresenter::isEnableSearchLyrics() const
- {
- return this->m_enableSearchLyrics;
- }
- void MediaPresenter::enableSearchSubtitle(bool enable)
- {
- this->m_enableSearchSubtitle = enable;
- }
- void MediaPresenter::enableSearchLyrics(bool enable)
- {
- this->m_enableSearchLyrics = enable;
- }
- void MediaPresenter::enableAutoSaveSearchLyrics(bool enable)
- {
- this->m_autoSaveSearchLyrics = enable;
- }
- bool MediaPresenter::isAutoSaveSearchLyrics() const
- {
- return this->m_autoSaveSearchLyrics;
- }
- void MediaPresenter::showAlbumJacket(bool show)
- {
- this->m_showAlbumJacket = show;
- }
- bool MediaPresenter::isShowAlbumJacket() const
- {
- return this->m_showAlbumJacket;
- }
- void MediaPresenter::useFrameDrop(bool enable)
- {
- this->m_useFrameDrop = enable;
- }
- bool MediaPresenter::isUseFrameDrop() const
- {
- return this->m_useFrameDrop;
- }
- void MediaPresenter::useBufferingMode(bool enable)
- {
- this->m_useBufferingMode = enable;
- }
- bool MediaPresenter::isUseBufferingMode() const
- {
- return this->m_useBufferingMode;
- }
- void MediaPresenter::useGPUConvert(bool use)
- {
- bool prev = this->m_useGPUConvert;
- this->m_useGPUConvert = use;
- if (prev != use)
- {
- if (this->isEnabledVideo())
- this->recover(this->getMasterClock());
- }
- }
- bool MediaPresenter::isUseGPUConvert() const
- {
- return this->m_useGPUConvert;
- }
- void MediaPresenter::seek(double time, bool any)
- {
- QMutexLocker locker(&this->m_controlLocker);
- if (this->m_state)
- {
- double incr = time - this->getCurrentPosition();
- int flag = (this->m_seekKeyFrame && !any) ? 0 : AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY;
- this->seekStream(time, incr, flag);
- }
- }
- uint8_t MediaPresenter::getMaxVolume() const
- {
- return 255;
- }
- void MediaPresenter::mute(bool mute)
- {
- if (mute)
- this->volumeInternal(0);
- else
- this->volume(this->m_volume);
- this->m_isMute = mute;
- }
- void MediaPresenter::volumeInternal(uint8_t volume)
- {
- if (this->m_state && !this->m_spdif.isOpened())
- BASS_ChannelSetAttribute(this->m_state->audio.handle, BASS_ATTRIB_VOL, (float)volume / (float)this->getMaxVolume());
- }
- void MediaPresenter::volume(uint8_t volume)
- {
- if (volume > this->getMaxVolume())
- this->m_volume = this->getMaxVolume();
- else
- this->m_volume = volume;
- this->volumeInternal(this->m_volume);
- }
- uint8_t MediaPresenter::getVolume() const
- {
- return this->m_volume;
- }
- double MediaPresenter::getDuration() const
- {
- if (this->m_state)
- return this->m_playData.duration;
- else
- return 0.0;
- }
- double MediaPresenter::getCurrentPosition()
- {
- if (this->m_state)
- {
- double duration = this->getDuration();
- double clock;
- clock = this->getMasterClock() + this->m_state->seek.inc;
- if (clock > duration)
- return duration;
- else
- return clock;
- }
- else
- {
- return 0.0;
- }
- }
- bool MediaPresenter::hasDuration() const
- {
- return Utils::zeroDouble(this->getDuration()) > 0.0;
- }
- double MediaPresenter::getAspectRatio(bool widthPrio) const
- {
- MediaState *ms = this->m_state;
- double aspectRatio = 0.0;
- if (!ms)
- return 0.0;
- if (!ms->video.stream.stream)
- return 0.0;
- AVCodecContext *codec = ms->video.stream.ctx;
- if (!codec)
- return 0.0;
- if (codec->sample_aspect_ratio.num == 0)
- {
- aspectRatio = 0.0;
- }
- else
- {
- aspectRatio = av_q2d(codec->sample_aspect_ratio);
- if (widthPrio)
- aspectRatio *= (double)codec->height / (double)codec->width;
- else
- aspectRatio *= (double)codec->width / (double)codec->height;
- }
- if (aspectRatio <= 0.0)
- {
- if (widthPrio)
- aspectRatio = (double)codec->height / (double)codec->width;
- else
- aspectRatio = (double)codec->width / (double)codec->height;
- }
- return aspectRatio;
- }
- bool MediaPresenter::isEnabledVideo() const
- {
- if (this->m_state && this->m_state->video.stream.stream)
- return true;
- else
- return false;
- }
- bool MediaPresenter::isAudio() const
- {
- return this->m_playData.totalFrame <= 100 && this->m_isAudioExt;
- }
- bool MediaPresenter::isVideo() const
- {
- return this->isEnabledVideo() && !this->isAudio();
- }
- bool MediaPresenter::isTempoUsable() const
- {
- if (this->m_state)
- {
- if (this->getCurrentAudioStreamIndex() >= 0)
- return this->m_state->audio.tempo != 0;
- else
- return true;
- }
- return false;
- }
- float MediaPresenter::getTempo() const
- {
- float tempo = 0.0f;
- if (this->isTempoUsable())
- {
- if (this->getCurrentAudioStreamIndex() >= 0)
- BASS_ChannelGetAttribute(this->m_state->audio.tempo, BASS_ATTRIB_TEMPO, &tempo);
- else
- tempo = this->m_state->video.tempo;
- }
- return tempo;
- }
- void MediaPresenter::setTempo(float percent)
- {
- if (this->isTempoUsable())
- {
- if (this->getCurrentAudioStreamIndex() >= 0)
- BASS_ChannelSetAttribute(this->m_state->audio.tempo, BASS_ATTRIB_TEMPO, percent);
- else
- this->m_state->video.tempo = percent;
- }
- }
- VirtualFile& MediaPresenter::getVirtualFile()
- {
- return VIRTUAL_FILE;
- }
- DTVReader& MediaPresenter::getDTVReader()
- {
- return DTV_READER;
- }
- bool MediaPresenter::isRemoteFile() const
- {
- return this->m_isRemoteFile;
- }
- bool MediaPresenter::isRemoteProtocol() const
- {
- return this->m_isRemoteProtocol;
- }
- bool MediaPresenter::changeStream(int newIndex, int oldIndex, bool isAudio, int *lastStreamIndex, bool *quitFlag)
- {
- QMutexLocker locker(&this->m_controlLocker);
- bool success = false;
- if (this->m_state == nullptr)
- return false;
- double clock = this->getMasterClock();
- this->m_state->streamChangeStartTime = this->getAbsoluteClock();
- this->m_state->readThreadQuit = true;
- if (this->m_readThread.isRunning())
- this->m_readThread.wait();
- if (quitFlag)
- *quitFlag = true;
- this->closeStreamComponent(oldIndex, isAudio);
- if (this->openStreamComponent(newIndex, isAudio))
- {
- if (newIndex == this->getCurrentAudioStreamIndex())
- {
- if (this->m_spdif.isOpened())
- this->m_spdif.play();
- else
- BASS_ChannelPlay(this->m_state->audio.handle, true);
- }
- this->seekStream(clock, 0.0, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
- if (lastStreamIndex)
- *lastStreamIndex = newIndex;
- success = true;
- }
- this->startReadThread();
- this->m_state->streamChangeDriftTime += this->getAbsoluteClock() - this->m_state->streamChangeStartTime;
- return success;
- }
- int MediaPresenter::getCurrentAudioStreamIndex() const
- {
- if (this->m_state)
- return this->m_state->audio.stream.index;
- else
- return -1;
- }
- void MediaPresenter::getAudioStreamInfo(QVector<AudioStreamInfo> *ret) const
- {
- *ret = this->m_audioStreamInfo;
- }
- bool MediaPresenter::resetAudioStream()
- {
- return this->changeAudioStream(this->getCurrentAudioStreamIndex());
- }
- bool MediaPresenter::changeAudioStream(int index)
- {
- return this->changeStream(index, this->getCurrentAudioStreamIndex(),
- this->isUseAudioPath(), &this->m_lastAudioStream, nullptr);
- }
- HSTREAM MediaPresenter::getAudioHandle() const
- {
- if (this->m_state)
- return this->m_state->audio.handle;
- return 0;
- }
- Deinterlacer& MediaPresenter::getDeinterlacer()
- {
- return this->m_deinterlacer;
- }
- void MediaPresenter::setDeinterlacerAlgorithm(AnyVODEnums::DeinterlaceAlgorithm algorithm)
- {
- this->m_deinterlacer.setAlgorithm(algorithm);
- if (this->m_state)
- {
- Video &video = this->m_state->video;
- this->m_deinterlacer.setCodec(video.stream.ctx, video.pixFormat, video.stream.stream->time_base);
- }
- }
- FilterGraph& MediaPresenter::getFilterGraph()
- {
- return this->m_filterGraph;
- }
- bool MediaPresenter::configFilterGraph()
- {
- if (this->m_state)
- {
- Video &video = this->m_state->video;
- return this->m_filterGraph.setCodec(video.stream.ctx, video.pixFormat, this->m_format, video.stream.stream->time_base);
- }
- return false;
- }
- int MediaPresenter::getOptionDescY() const
- {
- return this->m_optionDescY;
- }
- void MediaPresenter::setOptionDescY(int y)
- {
- this->m_optionDescY = y;
- }
- void MediaPresenter::setVerticalScreenOffset(int offset)
- {
- QMutexLocker locker(&this->m_cameraLock);
- this->m_screenOffset.setY(offset);
- }
- void MediaPresenter::setHorizontalScreenOffset(int offset)
- {
- QMutexLocker locker(&this->m_cameraLock);
- this->m_screenOffset.setX(offset);
- }
- void MediaPresenter::useDistortion(bool use)
- {
- this->m_useDistortion = use;
- }
- bool MediaPresenter::isUseDistortion() const
- {
- return this->m_useDistortion;
- }
- void MediaPresenter::setBarrelDistortionCoefficients(const QVector2D &coefficients)
- {
- this->m_barrelDistortionCoefficients = coefficients;
- }
- QVector2D MediaPresenter::getBarrelDistortionCoefficients() const
- {
- return this->m_barrelDistortionCoefficients;
- }
- void MediaPresenter::setPincushionDistortionCoefficients(const QVector2D &coefficients)
- {
- this->m_pincushionDistortionCoefficients = coefficients;
- }
- QVector2D MediaPresenter::getPincushionDistortionCoefficients() const
- {
- return this->m_pincushionDistortionCoefficients;
- }
- void MediaPresenter::setDistortionLensCenter(const QVector2D &lensCenter)
- {
- this->m_distortionLensCenter = lensCenter;
- }
- QVector2D MediaPresenter::getDistortionLensCenter() const
- {
- return this->m_distortionLensCenter;
- }
- QString MediaPresenter::getRealFilePath() const
- {
- return this->m_realFilePath;
- }
- AVPixelFormat MediaPresenter::getFormat() const
- {
- return this->m_format;
- }
- void MediaPresenter::setBluetoothHeadsetConnected(bool connected)
- {
- this->m_bluetoothHeadsetConnected = connected;
- }
- bool MediaPresenter::getBluetoothHeadsetConnected() const
- {
- return this->m_bluetoothHeadsetConnected;
- }
- void MediaPresenter::setBluetoothHeadsetSync(double sync)
- {
- this->m_bluetoothHeadsetSync = sync;
- }
- double MediaPresenter::getBluetoothHeadsetSync() const
- {
- return this->m_bluetoothHeadsetSync;
- }
- #ifdef Q_OS_IOS
- void MediaPresenter::setIOSNotifyCallback(IOSNOTIFYPROC *proc)
- {
- this->m_iosNotify = proc;
- }
- #endif
- void MediaPresenter::setUserAspectRatio(UserAspectRatio &ratio)
- {
- this->m_userRatio = ratio;
- this->computeFrameSize();
- }
- void MediaPresenter::getUserAspectRatio(UserAspectRatio *ret) const
- {
- *ret = this->m_userRatio;
- }
- void MediaPresenter::setMaxTextureSize(int size)
- {
- this->m_maxTextureSize = size;
- this->initFrameBufferObject(&this->m_anaglyphFrameBuffer, size, size);
- }
- int MediaPresenter::getMaxTextureSize() const
- {
- return this->m_maxTextureSize;
- }
- void MediaPresenter::useSubtitleCacheMode(bool use)
- {
- this->m_useSubtitleCacheMode = use;
- }
- bool MediaPresenter::isUseSubtitleCacheMode() const
- {
- return this->m_useSubtitleCacheMode;
- }
- void MediaPresenter::showOptionDesc(const QString &desc)
- {
- if (this->isRunning())
- {
- QMutexLocker locker(&this->m_optionDescMutex);
- this->m_optionDesc = desc;
- this->m_showOptionDesc = true;
- if (this->m_showAudioOptionDescCallback.callback && this->isAudio())
- this->m_showAudioOptionDescCallback.callback(this->m_showAudioOptionDescCallback.userData, desc, true);
- }
- else
- {
- if (this->m_nonePlayingDescCallback.callback)
- this->m_nonePlayingDescCallback.callback(this->m_nonePlayingDescCallback.userData, desc);
- }
- }
- void MediaPresenter::clearFonts()
- {
- this->m_font.clear();
- this->m_subtitleFont.clear();
- }
- void MediaPresenter::clearFrameBuffers()
- {
- this->destroyFrameBufferObject(&this->m_anaglyphFrameBuffer);
- this->destroyFrameBufferObject(&this->m_distortionFrameBuffer);
- this->destroyFrameBufferObject(&this->m_leftDistortionFrameBuffer);
- this->destroyFrameBufferObject(&this->m_rightDistortionFrameBuffer);
- }
- float MediaPresenter::getCPUUsage()
- {
- qint64 pid = QCoreApplication::applicationPid();
- float usage = 0.0f;
- uint64_t processKernelNow = 0;
- uint64_t processUserNow = 0;
- uint64_t systemKernelNow = 0;
- uint64_t systemUserNow = 0;
- uint64_t processKernelElapsed = 0;
- uint64_t processUserElapsed = 0;
- uint64_t systemKernelElapsed = 0;
- uint64_t systemUserElapsed = 0;
- uint64_t totalProcessElapsed = 0;
- uint64_t totalSystemElapsed = 0;
- #ifdef Q_OS_WIN
- ULARGE_INTEGER int64;
- FILETIME dummy;
- FILETIME processFileTimeKernelNow;
- FILETIME processFileTimeUserNow;
- FILETIME systemFileTimeKernelNow;
- FILETIME systemFileTimeUserNow;
- HANDLE pHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
- if (GetProcessTimes(pHandle, &dummy, &dummy, &processFileTimeKernelNow, &processFileTimeUserNow) &&
- GetSystemTimes(&dummy, &systemFileTimeKernelNow, &systemFileTimeUserNow))
- {
- int64.LowPart = processFileTimeKernelNow.dwLowDateTime;
- int64.HighPart = processFileTimeKernelNow.dwHighDateTime;
- processKernelNow = int64.QuadPart;
- int64.LowPart = processFileTimeUserNow.dwLowDateTime;
- int64.HighPart = processFileTimeUserNow.dwHighDateTime;
- processUserNow = int64.QuadPart;
- int64.LowPart = systemFileTimeKernelNow.dwLowDateTime;
- int64.HighPart = systemFileTimeKernelNow.dwHighDateTime;
- systemKernelNow = int64.QuadPart;
- int64.LowPart = systemFileTimeUserNow.dwLowDateTime;
- int64.HighPart = systemFileTimeUserNow.dwHighDateTime;
- systemUserNow = int64.QuadPart;
- }
- if (pHandle)
- CloseHandle(pHandle);
- #elif defined Q_OS_LINUX
- QFile processStat(QString("/proc/%1/stat").arg(pid));
- QFile systemStat("/proc/stat");
- if (!processStat.open(QIODevice::ReadOnly))
- return 0.0f;
- if (!systemStat.open(QIODevice::ReadOnly))
- return 0.0f;
- QTextStream data;
- QString line;
- int idum;
- QString sdum;
- data.setDevice(&processStat);
- line = data.readLine();
- data.setString(&line);
- data >> idum >> sdum >> sdum;
- data >> idum >> idum >> idum;
- data >> idum >> idum >> idum;
- data >> idum >> idum >> idum >> idum;
- data >> processUserNow;
- data >> processKernelNow;
- data.setDevice(&systemStat);
- line = data.readLine();
- data.setString(&line);
- data >> sdum;
- uint64_t cpuTimes;
- for (int i = 0; i < 10; i++)
- {
- data >> cpuTimes;
- systemKernelNow += cpuTimes;
- }
- systemUserNow = 0;
- #elif defined Q_OS_MAC
- (void)pid;
- thread_array_t threads;
- mach_msg_type_number_t count;
- if (task_threads(mach_task_self(), &threads, &count) != KERN_SUCCESS)
- return 0.0f;
- kern_return_t kr = KERN_SUCCESS;
- mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
- for (mach_msg_type_number_t i = 0; i < count; i++)
- {
- thread_basic_info_data_t info;
- kr = thread_info(threads[i], THREAD_BASIC_INFO, (thread_info_t)&info, &infoCount);
- if (kr != KERN_SUCCESS)
- break;
- usage += (float)info.cpu_usage / TH_USAGE_SCALE;
- }
- for (mach_msg_type_number_t i = 0; i < count; i++)
- mach_port_deallocate(mach_task_self(), threads[i]);
- vm_deallocate(mach_task_self(), (vm_address_t)threads, sizeof(thread_t) * count);
- if (kr != KERN_SUCCESS)
- usage = 0.0f;
- host_basic_info_data_t hostInfo;
- infoCount = HOST_BASIC_INFO_COUNT;
- if (host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount) != KERN_SUCCESS)
- return 0.0f;
- if (hostInfo.avail_cpus <= 0)
- hostInfo.avail_cpus = 1;
- return usage * 100.0f / hostInfo.avail_cpus;
- #endif
- processKernelElapsed = processKernelNow - this->m_detail.lastProcessKernelTime;
- processUserElapsed = processUserNow - this->m_detail.lastProcessUserTime;
- systemKernelElapsed = systemKernelNow - this->m_detail.lastSystemKernelTime;
- systemUserElapsed = systemUserNow - this->m_detail.lastSystemUserTime;
- totalProcessElapsed = processKernelElapsed + processUserElapsed;
- totalSystemElapsed = systemKernelElapsed + systemUserElapsed;
- if (totalSystemElapsed > 0)
- usage = 100.0f * totalProcessElapsed / totalSystemElapsed;
- this->m_detail.lastProcessKernelTime = processKernelNow;
- this->m_detail.lastProcessUserTime = processUserNow;
- this->m_detail.lastSystemKernelTime = systemKernelNow;
- this->m_detail.lastSystemUserTime = systemUserNow;
- return usage;
- }
- Camera& MediaPresenter::getCamera()
- {
- return this->m_camera;
- }
- QMutex& MediaPresenter::getCameraLock()
- {
- return this->m_cameraLock;
- }
- void MediaPresenter::setStatusChangedCallback(EventCallback *playing, EventCallback *ended)
- {
- if (playing)
- this->m_playing = *playing;
- if (ended)
- this->m_ended = *ended;
- }
- void MediaPresenter::setEmptyBufferCallback(EmptyBufferCallback &callback)
- {
- this->m_emptyBufferCallback = callback;
- }
- void MediaPresenter::setShowAudioOptionDescCallback(ShowAudioOptionDescCallback &callback)
- {
- this->m_showAudioOptionDescCallback = callback;
- }
- void MediaPresenter::setAudioSubtitleCallback(AudioSubtitleCallback &callback)
- {
- this->m_audioSubtitleCallback = callback;
- }
- void MediaPresenter::setPaintCallback(PaintCallback &callback)
- {
- this->m_paintCallback = callback;
- }
- void MediaPresenter::setAbortCallback(AbortCallback &callback)
- {
- this->m_abortCallback = callback;
- }
- void MediaPresenter::setNonePlayingDescCallback(NonePlayingDescCallback &callback)
- {
- this->m_nonePlayingDescCallback = callback;
- }
- void MediaPresenter::setRecoverCallback(MediaPresenter::EventCallback &callback)
- {
- this->m_recoverCallback = callback;
- }
- void MediaPresenter::setDisableHWDecoderCallback(MediaPresenter::EventCallback &callback)
- {
- this->m_disableHWDecoder = callback;
- }
- void MediaPresenter::callEmptyCallback(bool show)
- {
- if (this->m_emptyBufferCallback.callback)
- this->m_emptyBufferCallback.callback(this->m_emptyBufferCallback.userData, show);
- }
- void MediaPresenter::abort(int reason)
- {
- if (this->m_abortCallback.callback)
- this->m_abortCallback.callback(this->m_abortCallback.userData, reason);
- }
- double MediaPresenter::getAudioClock()
- {
- Audio &audio = this->m_state->audio;
- QMutexLocker locker(&audio.stream.clockLock);
- double bluetoothSync;
- if (this->m_bluetoothHeadsetConnected)
- bluetoothSync = this->m_bluetoothHeadsetSync;
- else
- bluetoothSync = 0.0;
- return audio.stream.clock - this->m_audioSync - bluetoothSync - audio.spec.latency;
- }
- double MediaPresenter::getVideoClock()
- {
- QMutexLocker locker(&this->m_state->video.stream.clockLock);
- return this->m_state->video.stream.clock;
- }
- double MediaPresenter::getExternalClock() const
- {
- int64_t driftTime = this->m_state->pause.driftTime + this->m_state->video.driftTime
- + this->m_state->seek.videoDiscardDriftTime + this->m_state->seek.readDiscardDriftTime
- + this->m_state->streamChangeDriftTime;
- int64_t base = this->m_state->externalClock.base;
- return (this->getAbsoluteClock() - base - driftTime) / MICRO_SECOND;
- }
- double MediaPresenter::getMasterClock()
- {
- if (this->m_state->syncType == SYNC_VIDEO_MASTER)
- return this->getVideoClock();
- else if (this->m_state->syncType == SYNC_AUDIO_MASTER)
- return this->getAudioClock();
- else
- return this->getExternalClock();
- }
- double MediaPresenter::getAudioClockOffset() const
- {
- MediaState *ms = this->m_state;
- Audio &audio = ms->audio;
- return ms->syncType == SYNC_AUDIO_MASTER ? audio.stream.clockOffset : 0.0;
- }
- double MediaPresenter::frameNumberToClock(int number) const
- {
- return (number * this->getDuration()) / this->m_detail.videoTotalFrame;
- }
- void MediaPresenter::initFrameBufferObject(QOpenGLFramebufferObject **object, int width, int height)
- {
- if (*object)
- {
- if ((*object)->width() != width || (*object)->height() != height)
- delete *object;
- else
- return;
- }
- *object = new QOpenGLFramebufferObject(width, height);
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, (*object)->texture());
- GL_PREFIX glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- GL_PREFIX glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- GL_PREFIX glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- GL_PREFIX glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- (*object)->release();
- }
- void MediaPresenter::destroyFrameBufferObject(QOpenGLFramebufferObject **object)
- {
- if (*object)
- {
- delete *object;
- *object = nullptr;
- }
- }
- bool MediaPresenter::isValid() const
- {
- return this->m_state != nullptr;
- }
- int64_t MediaPresenter::getAbsoluteClock() const
- {
- return av_gettime();
- }
- int MediaPresenter::synchronizeAudio(short *samples, int samplesSize)
- {
- MediaState *ms = this->m_state;
- if (ms->syncType != SYNC_AUDIO_MASTER)
- {
- Audio &audio = ms->audio;
- AVCodecContext *codec = audio.stream.ctx;
- int n = av_get_bytes_per_sample(codec->sample_fmt) * audio.spec.channelCount;
- double diff = this->getAudioClock() - this->getMasterClock();
- if (diff < NOSYNC_THRESHOLD)
- {
- audio.diffComputation = diff + audio.diffAvgCoef * audio.diffComputation;
- if (audio.diffAvgCount < AUDIO_DIFF_AVG_NB)
- {
- audio.diffAvgCount++;
- }
- else
- {
- double avgDiff = audio.diffComputation * (1.0 - audio.diffAvgCoef);
- if (fabs(avgDiff) >= audio.diffThreshold)
- {
- int wantedSize = samplesSize + ((int)(diff * codec->sample_rate) * n);
- int minSize = samplesSize * ((100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100);
- int maxSize = samplesSize * ((100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100);
- if (wantedSize < minSize)
- wantedSize = minSize;
- else if (wantedSize > maxSize)
- wantedSize = maxSize;
- if (wantedSize < samplesSize)
- {
- samplesSize = wantedSize;
- }
- else if (wantedSize > samplesSize)
- {
- int nb = samplesSize - wantedSize;
- uint8_t *samplesEnd = (uint8_t *)samples + samplesSize - n;
- uint8_t *q = samplesEnd + n;
- while (nb > 0)
- {
- memcpy(q, samplesEnd, n);
- q += n;
- nb -= n;
- }
- samplesSize = wantedSize;
- }
- }
- }
- }
- else
- {
- audio.diffAvgCount = 0;
- audio.diffComputation = 0;
- }
- }
- return samplesSize;
- }
- template <typename T1, typename T2>
- int MediaPresenter::downSampleDecode(AVCodecContext *codec, uint8_t *audioBuffer, int bufSize, double maximum, PacketQueue::Packet &packet, int *dataSize) const
- {
- T1 *targetBuffer = (T1*)audioBuffer;
- uint8_t *tmpBuffer = this->m_state->audio.tmpBuffer;
- int decodedSize = bufSize;
- int len = this->decodeAudio(codec, &tmpBuffer, &decodedSize, &packet);
- int count = decodedSize / (int)sizeof(T2);
- for (int i = 0; i < count; i++)
- targetBuffer[i] = ((T2*)tmpBuffer)[i] / maximum;
- *dataSize = decodedSize / (sizeof(T2) / sizeof(T1));
- return len;
- }
- int MediaPresenter::decodeAudioAsSPDIFEncoding(uint8_t *audioBuffer, int bufSize, AVCodecContext *codec, int *dataSize, PacketQueue::Packet *tmpPacket)
- {
- SPDIFEncoding &encoding = this->m_state->audio.spdifEncoding;
- AVCodecContext *encodingCodec = encoding.encoder;
- int sampleCount = 0;
- int len = 0;
- if (!encodingCodec)
- return len;
- if (av_audio_fifo_size(encoding.fifo) < encodingCodec->frame_size)
- {
- len = this->decodeAudioAndSampleCount(codec, encoding.tmpBuffers, dataSize, &sampleCount, tmpPacket);
- if (len > 0 && *dataSize > 0)
- av_audio_fifo_write(encoding.fifo, (void**)encoding.tmpBuffers, sampleCount);
- }
- *dataSize = 0;
- if (av_audio_fifo_size(encoding.fifo) >= encodingCodec->frame_size)
- {
- int ret = 0;
- int gotPacket = 0;
- int wroteSize = 0;
- AVPacket packet;
- av_init_packet(&packet);
- packet.data = nullptr;
- packet.size = 0;
- av_audio_fifo_read(encoding.fifo, (void**)encoding.buffers, encodingCodec->frame_size);
- ret = Utils::encodeFrame(encodingCodec, &packet, encoding.frame, &gotPacket);
- if (ret >= 0 && gotPacket)
- {
- this->m_spdif.setAudioBuffer(audioBuffer, bufSize);
- wroteSize = this->m_spdif.writePacket(packet);
- *dataSize += wroteSize;
- av_packet_unref(&packet);
- }
- }
- return len;
- }
- double MediaPresenter::calFrameDelay(double pts)
- {
- FrameTimer &timer = this->m_state->frameTimer;
- double delay = pts - timer.lastPTS;
- if (delay <= 0.0 || delay >= 1.0)
- delay = timer.lastDelay;
- timer.lastDelay = delay;
- timer.lastPTS = pts;
- return delay;
- }
- void MediaPresenter::processEmptyAudio()
- {
- MediaState *ms = this->m_state;
- Audio &audio = ms->audio;
- if (!ms->pause.pause && !ms->willBeEnd && this->isRemoteProtocol() && !audio.isEmpty)
- {
- audio.isEmpty = true;
- this->callEmptyCallback(true);
- }
- }
- int MediaPresenter::decodeAudioFrame(uint8_t *audioBuffer, int bufSize)
- {
- MediaState *ms = this->m_state;
- Audio &audio = ms->audio;
- PacketQueue::Packet *packet = &audio.packet;
- AVCodecContext *codec = audio.stream.ctx;
- QVector<bool*> quits;
- quits.append(&ms->quit);
- while (true)
- {
- while (audio.packetSize > 0)
- {
- int dataSize = bufSize;
- PacketQueue::Packet tmpPacket;
- int len = 0;
- tmpPacket.discard = audio.packet.discard;
- tmpPacket.packet.data = audio.packetData;
- tmpPacket.packet.size = audio.packetSize;
- if (this->m_spdif.isOpened())
- {
- if (this->isUsingSPDIFEncoding())
- {
- len = this->decodeAudioAsSPDIFEncoding(audioBuffer, bufSize, codec, &dataSize, &tmpPacket);
- }
- else
- {
- this->m_spdif.setAudioBuffer(audioBuffer, bufSize);
- dataSize = this->m_spdif.writePacket(tmpPacket.packet);
- len = tmpPacket.packet.size;
- }
- if (dataSize < 0)
- len = -1;
- }
- else
- {
- switch (audio.spec.format)
- {
- case AV_SAMPLE_FMT_S32:
- case AV_SAMPLE_FMT_S32P:
- len = this->downSampleDecode<float, int32_t>(codec, audioBuffer, bufSize, numeric_limits<int32_t>::max(), tmpPacket, &dataSize);
- break;
- case AV_SAMPLE_FMT_DBL:
- case AV_SAMPLE_FMT_DBLP:
- len = this->downSampleDecode<float, double>(codec, audioBuffer, bufSize, 1.0, tmpPacket, &dataSize);
- break;
- case AV_SAMPLE_FMT_S64:
- case AV_SAMPLE_FMT_S64P:
- len = this->downSampleDecode<float, int64_t>(codec, audioBuffer, bufSize, numeric_limits<int64_t>::max(), tmpPacket, &dataSize);
- break;
- default:
- len = this->decodeAudio(codec, &audioBuffer, &dataSize, &tmpPacket);
- break;
- }
- }
- if (len < 0)
- {
- audio.packetSize = 0;
- break;
- }
- audio.packetData += len;
- audio.packetSize -= len;
- if (dataSize <= 0)
- continue;
- if (!ms->seek.firstAudioAfterFlush)
- {
- ms->seek.firstAudioAfterFlush = true;
- if (ms->syncType == SYNC_AUDIO_MASTER)
- ms->seek.readable = true;
- }
- this->m_detail.audioOutputByteCount.fetchAndAddOrdered(dataSize);
- return dataSize;
- }
- av_packet_unref(&packet->packet);
- if (ms->quit)
- return -1;
- if (this->isUseBufferingMode() && !this->isRemoteFile() && !this->m_isLive)
- {
- if (!ms->willBeEnd && (!audio.stream.queue.hasPacket() || (this->isVideo() && !ms->video.stream.queue.hasPacket())))
- {
- this->processEmptyAudio();
- return -1;
- }
- }
- bool block = false;
- if (!audio.stream.queue.get(packet, quits, &block))
- return -1;
- if (block)
- {
- if (audio.isEmpty)
- {
- audio.isEmpty = false;
- this->callEmptyCallback(false);
- }
- }
- else
- {
- this->processEmptyAudio();
- return -1;
- }
- if (audio.stream.queue.isFlushPacket(packet))
- {
- avcodec_flush_buffers(audio.stream.ctx);
- ms->seek.firstAudioAfterFlush = false;
- continue;
- }
- if (packet->discard)
- {
- packet->discard = false;
- continue;
- }
- this->m_detail.audioInputByteCount.fetchAndAddOrdered(packet->packet.size);
- audio.packetData = packet->packet.data;
- audio.packetSize = packet->packet.size;
- if (packet->packet.pts != AV_NOPTS_VALUE)
- {
- double pts = av_q2d(audio.stream.stream->time_base) * packet->packet.pts;
- QMutexLocker locker(&audio.stream.clockLock);
- audio.stream.clock = pts - audio.stream.clockOffset;
- }
- if (this->m_audioSubtitleCallback.callback && this->existAudioSubtitle())
- {
- if (this->m_showSubtitle)
- {
- QMutexLocker locker(&audio.stream.clockLock);
- uint32_t time = (int32_t)((audio.stream.clock + this->m_subtitleSync) * 1000);
- bool found = true;
- QVector<Lyrics> lines;
- Lyrics line;
- if (this->m_lrcParser.isExist())
- {
- if (this->m_lrcParser.get(time, &line))
- {
- lines.append(line);
- if (this->m_lrcParser.getNext(time, 1, &line))
- {
- lines.append(line);
- if (this->m_lrcParser.getNext(time, 2, &line))
- lines.append(line);
- }
- }
- }
- else
- {
- found = false;
- }
- if (found && lines.count() > 0)
- this->m_audioSubtitleCallback.callback(this->m_audioSubtitleCallback.userData, lines);
- }
- else
- {
- this->m_audioSubtitleCallback.callback(this->m_audioSubtitleCallback.userData, QVector<Lyrics>());
- }
- }
- }
- }
- int MediaPresenter::audioSPDIFCallback(void *buffer, int length, void *user)
- {
- MediaPresenter *parent = (MediaPresenter*)user;
- return (int)parent->audioCallback(HSTREAM(), buffer, (DWORD)length, user);
- }
- DWORD CALLBACK MediaPresenter::audioCallback(HSTREAM, void *buffer, DWORD length, void *user)
- {
- MediaPresenter *parent = (MediaPresenter*)user;
- MediaState *ms = parent->m_state;
- Audio &audio = ms->audio;
- DWORD oriLen = length;
- DWORD wrote = 0;
- uint8_t *stream = (uint8_t*)buffer;
- if (!ms->pause.pause)
- {
- while (length > 0)
- {
- if (audio.bufferIndex >= audio.bufferSize)
- {
- int audioSize = parent->decodeAudioFrame(audio.audioBuffer, sizeof(audio.audioBuffer));
- if (audioSize < 0)
- {
- break;
- }
- else
- {
- if (!parent->m_spdif.isOpened())
- audioSize = parent->synchronizeAudio((int16_t*)audio.audioBuffer, audioSize);
- audio.bufferSize = audioSize;
- }
- audio.bufferIndex = 0;
- }
- DWORD size = min(audio.bufferSize - audio.bufferIndex, (unsigned int)length);
- memcpy(stream, &audio.audioBuffer[audio.bufferIndex], size);
- length -= size;
- stream += size;
- audio.bufferIndex += size;
- }
- wrote = oriLen - length;
- double amount = (double)wrote / audio.spec.bytesPerSec;
- audio.stream.clockLock.lock();
- audio.stream.clock += amount;
- audio.stream.clockLock.unlock();
- }
- if (wrote <= 0 && !ms->willBeEnd)
- {
- AVCodecContext *ctx = audio.stream.ctx;
- if (ctx)
- {
- AVSampleFormat format = av_get_packed_sample_fmt(ctx->sample_fmt);
- int sampleCount = length / av_get_bytes_per_sample(format) / ctx->channels;
- av_samples_set_silence(&stream, 0, sampleCount, ctx->channels, format);
- wrote = length;
- }
- }
- return wrote;
- }
- void MediaPresenter::refreshSchedule(int delay)
- {
- this->m_refreshThread.refreshTimer(delay);
- }
- bool MediaPresenter::getPictureRect(QRect *rect)
- {
- if (this->m_state)
- {
- const FrameSize &frameSize = this->m_state->frameSize;
- QPoint screenOffset;
- this->m_cameraLock.lock();
- screenOffset = this->m_screenOffset;
- this->m_cameraLock.unlock();
- rect->setX((screenOffset.x() * this->m_devicePixelRatio) + ((this->m_width - frameSize.width) / 2));
- rect->setY((screenOffset.y() * this->m_devicePixelRatio) + ((this->m_height - frameSize.height) / 2));
- rect->setWidth(frameSize.width + 1);
- rect->setHeight(frameSize.height + 1);
- return true;
- }
- return false;
- }
- void MediaPresenter::drawDetail(ShaderCompositer &shader, const VideoPicture *vp)
- {
- QString text;
- QString currentTime;
- QString totalTime;
- QString timeFormat = Utils::TIME_HH_MM_SS;
- QColor headerColor(255, 255, 255);
- QColor color(255, 173, 114);
- int initX = 10 * this->m_devicePixelRatio;
- int x = initX;
- int y = 10 * this->m_devicePixelRatio;
- QString subtitle;
- float opaque = 1.0f;
- int lineHeight = this->m_fontSize + (5 * this->m_devicePixelRatio);
- int optionDescYGap = 10;
- if (this->m_vrInputSource != AnyVODEnums::VRI_NONE)
- {
- x /= 2;
- y /= 2;
- initX /= 2;
- lineHeight /= 2;
- optionDescYGap /= 2;
- }
- if (this->existSubtitle())
- {
- if (this->isAudio())
- subtitle = tr("가사 있음");
- else
- subtitle = tr("자막 있음");
- }
- else
- {
- if (this->isAudio())
- subtitle = tr("가사 없음");
- else
- subtitle = tr("자막 없음");
- }
- if (this->m_showingOptionDesc && !this->m_captureMode)
- y += this->m_fontSize + ((this->m_optionDescY + optionDescYGap) * this->m_devicePixelRatio);
- text = tr("파일 이름 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = this->m_detail.fileName;
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- text = QString(" (%1)").arg(subtitle);
- this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- x = initX;
- #if !defined Q_OS_ANDROID && !defined Q_OS_IOS
- if (!Utils::determinDevice(this->m_filePath))
- #endif
- {
- text = tr("재생 위치 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = QString("%1 / %2 (%3%)")
- .arg(*Utils::getTimeString(this->m_detail.currentTime, timeFormat, ¤tTime))
- .arg(*Utils::getTimeString(this->m_detail.totalTime, timeFormat, &totalTime))
- .arg(this->m_detail.timePercentage, 0, 'f', 2);
- this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- y += lineHeight;
- x = initX;
- }
- text = tr("파일 포맷 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = this->m_detail.fileFormat;
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- x = initX;
- text = tr("CPU 사용률 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = QString("%1%").arg(this->m_detail.cpuUsage, 0, 'f', 2);
- this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- x = initX;
- if (DTV_READER.isOpened())
- {
- if (this->m_detail.dtvSignal)
- {
- this->m_detail.dtvSignalStrength = DTV_READER.getSignalStrength();
- this->m_detail.dtvSignal = false;
- }
- text = tr("DTV 신호 감도 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = QString("%1%").arg(this->m_detail.dtvSignalStrength, 0, 'f', 2);
- this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- x = initX;
- }
- y += lineHeight;
- if (this->isEnabledVideo())
- {
- AVCodecContext *ctx = this->m_state->video.stream.ctx;
- text = tr("비디오 코덱 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = this->m_detail.videoCodec;
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- text = QString(" (Type %1, Threads : %2)").arg(ctx->active_thread_type).arg(ctx->thread_count);
- this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- x = initX;
- if (this->m_hwDecoder.isOpened())
- {
- text = tr("하드웨어 디코더 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = this->m_detail.videoHWDecoder;
- this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- x = initX;
- }
- text = tr("입력 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = QString("%1 (%2bits), %3x%4%5, %L6kbps (%L7KiBps / %L8KiB)")
- .arg(this->m_detail.videoInputType)
- .arg(this->m_detail.videoInputBits)
- .arg(this->m_detail.videoInputSize.width())
- .arg(this->m_detail.videoInputSize.height())
- .arg(this->m_detail.videoInterlaced ? "i" : "p")
- .arg(this->m_detail.videoInputByteRate / 1000.0 * 8.0, 0, 'f', 2)
- .arg(this->m_detail.videoInputByteRate / 1024.0, 0, 'f', 2)
- .arg(this->m_state->video.stream.queue.getBufferSizeInByte() / 1024.0, 0, 'f', 2);
- this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- x = initX;
- text = tr("출력 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = QString("%1%2 (%3bits), %4x%5%6, %7, %L8kbps (%L9KiBps)")
- .arg(this->m_detail.videoOutputType)
- .arg(this->isUsingPBO(this->m_format) ? " PBO" : "")
- .arg(this->m_detail.videoOutputBits)
- .arg(this->m_detail.videoOutputSize.width())
- .arg(this->m_detail.videoOutputSize.height())
- .arg(this->m_detail.videoInterlaced && !this->m_detail.videoDeinterlaced ? "i" : "p")
- .arg(this->m_detail.videoFPS, 0, 'f', 2)
- .arg(this->m_detail.videoOutputByteRate / 1000.0 * 8.0, 0, 'f', 2)
- .arg(this->m_detail.videoOutputByteRate / 1024.0, 0, 'f', 2);
- this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- x = initX;
- #if !defined Q_OS_ANDROID && !defined Q_OS_IOS
- if (Utils::determinDevice(this->m_filePath))
- {
- if (this->m_useFrameDrop)
- {
- text = tr("프레임 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = QString("%1 drops").arg(this->m_detail.videoFrameDropCount.fetchAndAddOrdered(0));
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- x = initX;
- }
- }
- else
- #endif
- {
- text = tr("프레임 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = QString("%1 / %2")
- .arg(this->m_detail.videoCurrentFrame.fetchAndAddOrdered(0))
- .arg(this->m_detail.videoTotalFrame);
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- if (this->m_useFrameDrop)
- {
- text = QString(" (%1 drops)").arg(this->m_detail.videoFrameDropCount.fetchAndAddOrdered(0));
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- }
- y += lineHeight;
- x = initX;
- }
- y += lineHeight;
- }
- if (this->getCurrentAudioStreamIndex() != -1)
- {
- text = tr("오디오 코덱 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = this->m_detail.audioCodec;
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- text = QString(" (Type %1)").arg(this->m_state->audio.stream.ctx->active_thread_type);
- this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- x = initX;
- if (this->m_spdif.isOpened())
- {
- text = tr("S/PDIF 오디오 장치 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = this->m_detail.audioSPDIFOutputDevice;
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- if (this->isUsingSPDIFEncoding())
- {
- text = ", " + tr("인코딩 사용");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- QString encoding = " (%1)";
- switch (this->m_SPIDFEncodingMethod)
- {
- case AnyVODEnums::SEM_AC3:
- encoding = encoding.arg("AC3");
- break;
- case AnyVODEnums::SEM_DTS:
- encoding = encoding.arg("DTS");
- break;
- default:
- encoding = encoding.arg("Unknown");
- break;
- }
- text = encoding;
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- }
- y += lineHeight;
- x = initX;
- }
- text = tr("입력 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = QString("%1, %2Hz, %3Ch, %4bits, %L5kbps (%L6KiBps / %L7KiB)")
- .arg(this->m_detail.audioInputType)
- .arg(this->m_detail.audioInputSampleRate)
- .arg(this->m_detail.audioInputChannels)
- .arg(this->m_detail.audioInputBits)
- .arg(this->m_detail.audioInputByteRate / 1000.0 * 8.0, 0, 'f', 2)
- .arg(this->m_detail.audioInputByteRate / 1024.0, 0, 'f', 2)
- .arg(this->m_state->audio.stream.queue.getBufferSizeInByte() / 1024.0, 0, 'f', 2);
- this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- x = initX;
- text = tr("출력 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = QString("%1, %2Hz, %3Ch, %4bits, %L5kbps (%L6KiBps)")
- .arg(this->m_detail.audioOutputType)
- .arg(this->m_detail.audioOutputSampleRate)
- .arg(this->m_detail.audioOutputChannels)
- .arg(this->m_detail.audioOutputBits)
- .arg(this->m_detail.audioOutputByteRate / 1000.0 * 8.0, 0, 'f', 2)
- .arg(this->m_detail.audioOutputByteRate / 1024.0, 0, 'f', 2);
- this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- y += lineHeight;
- y += lineHeight;
- x = initX;
- }
- if (this->existSubtitle())
- {
- if (this->isAudio())
- text = tr("가사 코덱 : ");
- else
- text = tr("자막 코덱 : ");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, headerColor, opaque, vp);
- text = this->m_detail.subtitleCodec;
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- if (this->m_avParser.isExist())
- {
- QString desc;
- if (this->m_avParser.getDesc(&desc))
- {
- text = QString(" (%1)").arg(desc);
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- }
- }
- else if (this->m_youtubeParser.isExist())
- {
- QString lang;
- this->m_youtubeParser.getDefaultLanguage(&lang);
- text = QString(" (%1)").arg(lang);
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- }
- if (this->m_detail.subtitleBitmap)
- {
- if (!this->m_detail.subtitleValidColor)
- {
- text = QString(" Invalid");
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- }
- text = QString(" Colors (%1)").arg(this->m_detail.subtitleColorCount);
- x += this->drawOutlined(shader, this->m_font, QPoint(x, y), text, this->m_fontOutlineSize, color, opaque, vp);
- }
- }
- }
- int MediaPresenter::drawOutlined(ShaderCompositer &shader, Font &font, const QPoint &pos, const QString &text,
- int outline, const Font::Context &context, float opaque, const VideoPicture *vp)
- {
- QColor outlineColor(0, 0, 0);
- int len;
- if (this->m_3dSubtitleMethod == AnyVODEnums::S3M_NONE)
- {
- shader.startSimple();
- len = font.renderText(shader, ShaderCompositer::ST_SIMPLE, pos, text, context, outline, outlineColor, opaque, AnyVODEnums::SD_NONE, 1.0f, false);
- shader.endSimple();
- }
- else
- {
- QPoint firstPos;
- QPoint secondPos;
- AnyVODEnums::ScaleDirection direction;
- QRect frameRect;
- bool colorBlend = false;
- float scale = 0.5f;
- Font::Context firstContext = context;
- Font::Context secondContext = context;
- this->getPictureRect(&frameRect);
- switch (this->m_3dSubtitleMethod)
- {
- case AnyVODEnums::S3M_TOP_BOTTOM:
- {
- firstPos.setX(pos.x());
- firstPos.setY(pos.y() / 2 + frameRect.y());
- secondPos.setX(pos.x());
- secondPos.setY(frameRect.y() + (pos.y() + frameRect.height()) / 2);
- direction = AnyVODEnums::SD_HEIGHT;
- break;
- }
- case AnyVODEnums::S3M_LEFT_RIGHT:
- {
- firstPos.setX(pos.x() / 2 + frameRect.x());
- firstPos.setY(pos.y() + frameRect.y());
- secondPos.setX(frameRect.x() + (pos.x() + frameRect.width()) / 2);
- secondPos.setY(firstPos.y());
- direction = AnyVODEnums::SD_WIDTH;
- break;
- }
- case AnyVODEnums::S3M_PAGE_FLIP:
- {
- firstPos = pos;
- secondPos = pos;
- direction = AnyVODEnums::SD_HEIGHT;
- scale = 1.0f;
- break;
- }
- case AnyVODEnums::S3M_INTERLACED:
- case AnyVODEnums::S3M_CHECKER_BOARD:
- {
- firstPos = pos;
- secondPos = pos;
- direction = AnyVODEnums::SD_HEIGHT;
- scale = 1.0f;
- break;
- }
- case AnyVODEnums::S3M_ANAGLYPH:
- {
- firstPos = pos;
- secondPos = pos;
- direction = AnyVODEnums::SD_HEIGHT;
- colorBlend = true;
- scale = 1.0f;
- break;
- }
- default:
- {
- direction = AnyVODEnums::SD_NONE;
- break;
- }
- }
- if (this->m_vrInputSource != AnyVODEnums::VRI_NONE)
- {
- scale = 0.5f;
- direction = AnyVODEnums::SD_ALL;
- }
- firstPos -= this->m_3dSubtitleOffset * this->m_devicePixelRatio;
- secondPos += this->m_3dSubtitleOffset * this->m_devicePixelRatio;
- switch (this->m_3dSubtitleMethod)
- {
- case AnyVODEnums::S3M_PAGE_FLIP:
- {
- shader.startSimple();
- if (vp->leftOrTop3D)
- len = font.renderText(shader, ShaderCompositer::ST_SIMPLE, firstPos, text, firstContext, outline, outlineColor, opaque, direction, scale, colorBlend);
- else
- len = font.renderText(shader, ShaderCompositer::ST_SIMPLE, secondPos, text, secondContext, outline, outlineColor, opaque, direction, scale, colorBlend);
- shader.endSimple();
- break;
- }
- case AnyVODEnums::S3M_INTERLACED:
- {
- shader.startSubtitleInterlace(shader.getLeftOrTop());
- font.renderText(shader, ShaderCompositer::ST_SUBTITLE_INTERLACE, firstPos, text, firstContext, outline, outlineColor, opaque, direction, scale, colorBlend);
- shader.endSubtitleInterlace();
- shader.startSubtitleInterlace(!shader.getLeftOrTop());
- len = font.renderText(shader, ShaderCompositer::ST_SUBTITLE_INTERLACE, secondPos, text, secondContext, outline, outlineColor, opaque, direction, scale, colorBlend);
- shader.endSubtitleInterlace();
- break;
- }
- case AnyVODEnums::S3M_CHECKER_BOARD:
- {
- shader.startSubtitleCheckerBoard(shader.getLeftOrTop());
- font.renderText(shader, ShaderCompositer::ST_SUBTITLE_CHECKER_BOARD, firstPos, text, firstContext, outline, outlineColor, opaque, direction, scale, colorBlend);
- shader.endSubtitleCheckerBoard();
- shader.startSubtitleCheckerBoard(!shader.getLeftOrTop());
- len = font.renderText(shader, ShaderCompositer::ST_SUBTITLE_CHECKER_BOARD, secondPos, text, secondContext, outline, outlineColor, opaque, direction, scale, colorBlend);
- shader.endSubtitleCheckerBoard();
- break;
- }
- case AnyVODEnums::S3M_ANAGLYPH:
- {
- shader.startSubtitleAnaglyph(shader.getLeftOrTop());
- font.renderText(shader, ShaderCompositer::ST_SUBTITLE_ANAGLYPH, firstPos, text, firstContext, outline, outlineColor, opaque, direction, scale, colorBlend);
- shader.endSubtitleAnaglyph();
- shader.startSubtitleAnaglyph(!shader.getLeftOrTop());
- len = font.renderText(shader, ShaderCompositer::ST_SUBTITLE_ANAGLYPH, secondPos, text, secondContext, outline, outlineColor, opaque, direction, scale, colorBlend);
- shader.endSubtitleAnaglyph();
- break;
- }
- default:
- {
- shader.startSimple();
- font.renderText(shader, ShaderCompositer::ST_SIMPLE, firstPos, text, firstContext, outline, outlineColor, opaque, direction, scale, colorBlend);
- len = font.renderText(shader, ShaderCompositer::ST_SIMPLE, secondPos, text, secondContext, outline, outlineColor, opaque, direction, scale, colorBlend);
- shader.endSimple();
- break;
- }
- }
- }
- return len;
- }
- void MediaPresenter::drawOptionDesc(ShaderCompositer &shader, const VideoPicture *vp)
- {
- QMutexLocker locker(&this->m_optionDescMutex);
- const QColor color(0, 148, 255);
- const int outline = this->m_fontOutlineSize;
- QFontMetrics fm(this->m_font.getQFont());
- QString optionDesc = fm.elidedText(this->m_optionDesc, Qt::ElideMiddle, this->m_width - (10 * 2 * this->m_devicePixelRatio));
- this->drawOutlined(shader, this->m_font, QPoint(10 * this->m_devicePixelRatio, (this->m_optionDescY + 10) * this->m_devicePixelRatio), optionDesc, outline, Font::Context(color), 1.0f, vp);
- }
- void MediaPresenter::getSubtitleSize(const QFontMetrics &fm, const QString &text, QSize *ret) const
- {
- int heightDiv = 1;
- if (this->m_vrInputSource != AnyVODEnums::VRI_NONE)
- heightDiv = 2;
- ret->setWidth(fm.width(text));
- ret->setHeight(fm.height() / heightDiv);
- }
- bool MediaPresenter::isLeftAlignLine(const QString &text) const
- {
- if (this->m_halign != AnyVODEnums::HAM_AUTO)
- return false;
- if (text.startsWith("-"))
- return true;
- else
- return false;
- }
- int MediaPresenter::findWordWrapPos(const QFontMetrics &fm, const QString &text) const
- {
- QSize len;
- int pos = -1;
- int left = 0;
- int right = text.count() - 1;
- int mid = right / 2;
- int maxWidth = this->m_width - fm.maxWidth();
- while (true)
- {
- if (left < right - 1)
- {
- QString sub = text.mid(0, mid);
- this->getSubtitleSize(fm, sub, &len);
- if (len.width() >= maxWidth)
- right = mid;
- else
- left = mid;
- mid = (left + right) / 2;
- continue;
- }
- bool found = false;
- for (int k = mid; k >= 0; k--)
- {
- if (text[k].isSpace())
- {
- pos = k + 1;
- found = true;
- break;
- }
- }
- if (found)
- break;
- pos = mid;
- break;
- }
- return pos;
- }
- void MediaPresenter::applyWordWrap(const QFontMetrics &fm, SAMIParser::Paragraph *ret) const
- {
- int maxWidth = this->m_width - fm.maxWidth();
- for (int i = 0; i < ret->lines.count(); i++)
- {
- SAMIParser::Line &line = ret->lines[i];
- QString totalText;
- QSize len;
- for (int j = 0; j < line.subtitles.count(); j++)
- totalText += line.subtitles[j].text;
- if (totalText.isEmpty())
- continue;
- this->getSubtitleSize(fm, totalText, &len);
- if (len.width() < maxWidth)
- continue;
- int pos = this->findWordWrapPos(fm, totalText);
- int sum = 0;
- int prevSum = 0;
- int toMove = -1;
- if (pos <= 0)
- continue;
- for (int j = 0; j < line.subtitles.count(); j++)
- {
- int count = line.subtitles[j].text.count();
- sum += count;
- if (sum >= pos)
- {
- toMove = j;
- break;
- }
- prevSum = sum;
- }
- SAMIParser::Line newLine;
- for (int j = toMove; j < line.subtitles.count(); j++)
- newLine.subtitles.append(line.subtitles[j]);
- line.subtitles = line.subtitles.mid(0, toMove + 1);
- SAMIParser::Text &oldText = line.subtitles.last();
- SAMIParser::Text &newText = newLine.subtitles.first();
- if (prevSum <= pos)
- pos -= prevSum;
- oldText.text = oldText.text.mid(0, pos).trimmed();
- newText.text = newText.text.mid(pos).trimmed();
- ret->lines.insert(i + 1, newLine);
- }
- }
- void MediaPresenter::applyWordWrap(const QFontMetrics &fm, SRTParser::Item *ret) const
- {
- int maxWidth = this->m_width - fm.maxWidth();
- for (int i = 0; i < ret->texts.count(); i++)
- {
- QString &line = ret->texts[i];
- QSize len;
- if (line.isEmpty())
- continue;
- this->getSubtitleSize(fm, line, &len);
- if (len.width() < maxWidth)
- continue;
- int pos = this->findWordWrapPos(fm, line);
- if (pos <= 0)
- continue;
- QString newLine = line.mid(pos).trimmed();
- line = line.mid(0, pos).trimmed();
- ret->texts.insert(i + 1, newLine);
- }
- }
- int MediaPresenter::drawSubtitleLine(ShaderCompositer &shader, int lineNum, int totalLineCount, const QString &text,
- const QPoint &margin, const Font::Context &context, const QString &totalText, int maxWidth,
- bool forcedLeft, const VideoPicture *vp)
- {
- int defaultLineMargin = 5;
- QPoint point;
- int defaultVMargin;
- int currentLine;
- QSize size;
- int left = 0;
- int base;
- int dir;
- QFontMetrics fm(this->m_subtitleFont.getQFont());
- int baseWidth;
- this->getSubtitleSize(fm, totalText, &size);
- defaultVMargin = -size.height() / 2;
- if (this->m_3dSubtitleMethod == AnyVODEnums::S3M_LEFT_RIGHT)
- baseWidth = this->m_state->frameSize.width;
- else
- baseWidth = this->m_width;
- switch (this->m_halign)
- {
- case AnyVODEnums::HAM_LEFT:
- {
- left = (baseWidth - maxWidth) / 2;
- break;
- }
- case AnyVODEnums::HAM_MIDDLE:
- {
- left = (baseWidth - size.width()) / 2;
- break;
- }
- case AnyVODEnums::HAM_RIGHT:
- {
- left = (baseWidth - maxWidth) / 2 + maxWidth - size.width();
- break;
- }
- default:
- {
- if (forcedLeft)
- left = (baseWidth - maxWidth) / 2;
- else
- left = (baseWidth - size.width()) / 2;
- break;
- }
- }
- point.setX(left + margin.x());
- if (this->m_valign == AnyVODEnums::VAM_TOP)
- {
- currentLine = lineNum;
- if (this->m_vrInputSource != AnyVODEnums::VRI_NONE || this->m_3dSubtitleMethod == AnyVODEnums::S3M_NONE)
- {
- base = 0;
- }
- else
- {
- QRect frameRect;
- this->getPictureRect(&frameRect);
- base = frameRect.y();
- }
- dir = 1;
- }
- else
- {
- currentLine = totalLineCount - lineNum - 1;
- if (this->m_3dSubtitleMethod == AnyVODEnums::S3M_NONE)
- {
- base = this->m_height;
- }
- else if (this->m_3dSubtitleMethod == AnyVODEnums::S3M_LEFT_RIGHT)
- {
- base = this->m_state->frameSize.height;
- }
- else
- {
- QRect frameRect;
- this->getPictureRect(&frameRect);
- base = frameRect.y() + frameRect.height() - 1;
- }
- dir = -1;
- }
- point.setY(base + dir * (size.height() + currentLine * size.height()) + defaultVMargin + margin.y());
- QPoint posOffset;
- this->getSubtitlePositionOffset(&posOffset);
- point -= posOffset;
- point.ry() += defaultLineMargin * dir;
- return this->drawOutlined(shader, this->m_subtitleFont, point, text, this->m_subtitleOutlineSize, context, this->m_subtitleOpaque, vp);
- }
- bool MediaPresenter::needMaxWidth() const
- {
- return this->m_halign != AnyVODEnums::HAM_MIDDLE && this->m_halign != AnyVODEnums::HAM_NONE;
- }
- void MediaPresenter::drawSubtitles(ShaderCompositer &shader, const VideoPicture *vp)
- {
- int maxWidth = 0;
- bool forcedLeft = false;
- QSize size;
- QFontMetrics fm(this->m_subtitleFont.getQFont());
- int32_t time = vp->time;
- int32_t delay = this->m_state->frameTimer.lastDelay * 1000;
- if (this->m_hwDecoder.isOpened())
- time -= this->m_hwDecoder.getSurfaceQueueCount() * delay;
- if (this->m_filterGraph.hasFilters())
- time -= this->m_filterGraph.getDelayCount() * delay;
- if (this->m_samiParser.isExist())
- {
- SAMIParser::Paragraph para;
- QString className;
- this->m_samiParser.getDefaultClassName(&className);
- if (this->m_samiParser.get(className, time, ¶))
- {
- this->applyWordWrap(fm, ¶);
- if (this->needMaxWidth())
- {
- for (int i = 0; i < para.lines.count(); i++)
- {
- SAMIParser::Line &line = para.lines[i];
- QString totalText;
- for (int j = 0; j < line.subtitles.count(); j++)
- totalText += line.subtitles[j].text;
- this->getSubtitleSize(fm, totalText, &size);
- maxWidth = max(maxWidth, size.width());
- forcedLeft |= this->isLeftAlignLine(totalText);
- }
- }
- for (int i = 0; i < para.lines.count(); i++)
- {
- SAMIParser::Line &line = para.lines[i];
- int left = 0;
- QString totalText;
- for (int j = 0; j < line.subtitles.count(); j++)
- totalText += line.subtitles[j].text;
- for (int j = 0; j < line.subtitles.count(); j++)
- {
- SAMIParser::Text &text = line.subtitles[j];
- Font::Context context(text.color, text.bold, text.underline, text.italic, text.strike);
- left += this->drawSubtitleLine(shader, i, para.lines.count(), text.text, QPoint(left, 0), context, totalText, maxWidth, forcedLeft, vp);
- }
- }
- }
- }
- else if (this->m_assParser.isExist())
- {
- this->drawASS(ASSRM_FILE, time, shader, vp);
- }
- else if (this->m_srtParser.isExist() || this->m_youtubeParser.isExist())
- {
- SRTParser::Item item;
- bool exist = false;
- if (this->m_srtParser.isExist())
- exist = this->m_srtParser.get(time, &item);
- else if (this->m_youtubeParser.isExist())
- exist = this->m_youtubeParser.get(time, &item);
- if (exist)
- {
- this->applyWordWrap(fm, &item);
- if (this->needMaxWidth())
- {
- for (int i = 0; i < item.texts.count(); i++)
- {
- this->getSubtitleSize(fm, item.texts[i], &size);
- maxWidth = max(maxWidth, size.width());
- forcedLeft |= this->isLeftAlignLine(item.texts[i]);
- }
- }
- for (int i = 0; i < item.texts.count(); i++)
- this->drawSubtitleLine(shader, i, item.texts.count(), item.texts[i], QPoint(0, 0), Font::Context(Qt::white), item.texts[i], maxWidth, forcedLeft, vp);
- }
- }
- else if (this->m_avParser.isExist())
- {
- AVSubtitle *sp;
- if (this->m_avParser.get(time, &sp))
- {
- if (this->drawAVSubtitle(shader, fm, sp, vp))
- this->drawASS(ASSRM_AV, time, shader, vp);
- }
- }
- else
- {
- MediaState *ms = this->m_state;
- Subtitle &subtitle = ms->subtitle;
- if (subtitle.stream.stream == nullptr)
- return;
- if (subtitle.isASS)
- {
- this->drawASS(ASSRM_SINGLE, time, shader, vp);
- }
- else
- {
- SubtitleFrames &frames = ms->subtitleFrames;
- QMutexLocker locker(&frames.lock);
- int count = frames.items.count();
- if (count <= 0)
- return;
- AVSubtitle *sp = nullptr;
- for (int i = count - 1; i >= 0; i--)
- {
- SubtitleElement &item = frames.items[i];
- AVSubtitle &spItem = item.subtitle;
- uint64_t base = (uint64_t)(item.pts * 1000);
- if (base + spItem.start_display_time <= (uint64_t)time && (uint64_t)time <= base + spItem.end_display_time)
- {
- sp = &spItem;
- break;
- }
- }
- if (sp)
- this->drawAVSubtitle(shader, fm, sp, vp);
- }
- }
- }
- bool MediaPresenter::drawAVSubtitle(ShaderCompositer &shader, const QFontMetrics &fm, const AVSubtitle *sp, const VideoPicture *vp)
- {
- MediaState *ms = this->m_state;
- int currentCount = 0;
- int maxWidth = 0;
- bool forcedLeft = false;
- bool isASS = false;
- QSize size;
- TextureInfo &texInfo = this->m_texInfo[TEX_FFMPEG_SUBTITLE];
- for (unsigned int i = 0; i < sp->num_rects; i++)
- {
- AVSubtitleRect *rect = sp->rects[i];
- if (rect->type == SUBTITLE_BITMAP)
- {
- QRect rc;
- QRect picRect;
- Surface *subtitleImg;
- AVPixelFormat srcFMT;
- QPoint posOffset;
- QPoint newPos(rect->x, rect->y);
- this->getSubtitlePositionOffsetByFrame(QSize(vp->orgWidth, vp->orgHeight), &posOffset);
- this->getPictureRect(&picRect);
- if (rect->x + rect->w > vp->orgWidth)
- newPos.rx() = vp->orgWidth - rect->w;
- if (rect->y + rect->h > vp->orgHeight)
- newPos.ry() = vp->orgHeight - rect->h;
- if (newPos.x() < 0)
- {
- rc.setX(posOffset.x() + picRect.x());
- rc.setWidth(ms->frameSize.width);
- }
- else
- {
- rc.setX(Utils::mapTo(vp->orgWidth, ms->frameSize.width, newPos.x()) - posOffset.x() + picRect.x());
- rc.setWidth(Utils::mapTo(vp->orgWidth, ms->frameSize.width, rect->w));
- }
- if (newPos.y() < 0)
- {
- rc.setY(posOffset.y() + picRect.y());
- rc.setHeight(ms->frameSize.height);
- }
- else
- {
- rc.setY(Utils::mapTo(vp->orgHeight, ms->frameSize.height, newPos.y()) - posOffset.y() + picRect.y());
- rc.setHeight(Utils::mapTo(vp->orgHeight, ms->frameSize.height, rect->h));
- }
- if (rect->nb_colors == 2)
- {
- srcFMT = AV_PIX_FMT_MONOWHITE;
- }
- else if (rect->nb_colors >= 4 && rect->nb_colors <= 256)
- {
- srcFMT = AV_PIX_FMT_PAL8;
- }
- else if (rect->nb_colors == 65536)
- {
- srcFMT = AV_PIX_FMT_RGB555;
- }
- else if (rect->nb_colors == 16777216)
- {
- srcFMT = AV_PIX_FMT_RGB24;
- }
- else
- {
- this->m_detail.subtitleValidColor = false;
- return false;
- }
- this->m_detail.subtitleBitmap = true;
- this->m_detail.subtitleColorCount = rect->nb_colors;
- subtitleImg = this->createSurface(rect->w, rect->h, AV_PIX_FMT_BGR32);
- if (subtitleImg)
- {
- ms->imageRGBConverter = sws_getCachedContext(
- ms->imageRGBConverter,
- rect->w, rect->h, srcFMT,
- rect->w, rect->h, AV_PIX_FMT_BGR32,
- SWS_POINT, nullptr, nullptr, nullptr);
- AVFrame pict;
- memset(&pict, 0, sizeof(pict));
- pict.data[0] = subtitleImg->pixels[0];
- pict.linesize[0] = subtitleImg->lineSize[0];
- if (ms->imageRGBConverter)
- sws_scale(ms->imageRGBConverter, rect->data, rect->linesize, 0, rect->h, pict.data, pict.linesize);
- bool enabledBlend = GL_PREFIX glIsEnabled(GL_BLEND);
- GL_PREFIX glEnable(GL_BLEND);
- QRectF renderRect;
- renderRect = QRectF(0.0, 0.0, 1.0, 1.0);
- for (unsigned int i = 0; i < texInfo.textureCount; i++)
- texInfo.init[i] = false;
- if (this->m_3dSubtitleMethod == AnyVODEnums::S3M_NONE)
- {
- QColor color = Qt::white;
- color.setAlphaF(this->m_subtitleOpaque);
- shader.startSimple();
- GL_PREFIX glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- this->renderTexture(shader, ShaderCompositer::ST_SIMPLE, rc, texInfo, *subtitleImg, renderRect, color, QMatrix4x4(), true);
- shader.endSimple();
- }
- else
- {
- QColor firstColorValue = Qt::white;
- QColor secondColorValue = Qt::white;
- QRect firstRect = rc;
- QRect secondRect = rc;
- firstColorValue.setAlphaF(this->m_subtitleOpaque);
- secondColorValue.setAlphaF(this->m_subtitleOpaque);
- switch (this->m_3dSubtitleMethod)
- {
- case AnyVODEnums::S3M_TOP_BOTTOM:
- {
- firstRect.setTop((rc.y() + picRect.y()) / 2);
- firstRect.setHeight(rc.height() / 2);
- secondRect.setTop(firstRect.y() + (picRect.height() - 1) / 2);
- secondRect.setHeight(rc.height() / 2);
- break;
- }
- case AnyVODEnums::S3M_LEFT_RIGHT:
- {
- firstRect.setLeft((rc.x() + picRect.x()) / 2);
- firstRect.setWidth(rc.width() / 2);
- secondRect.setLeft(firstRect.x() + (picRect.width() - 1) / 2);
- secondRect.setWidth(rc.width() / 2);
- break;
- }
- default:
- {
- break;
- }
- }
- firstRect.translate(-this->m_3dSubtitleOffset * this->m_devicePixelRatio);
- secondRect.translate(this->m_3dSubtitleOffset * this->m_devicePixelRatio);
- switch (this->m_3dSubtitleMethod)
- {
- case AnyVODEnums::S3M_PAGE_FLIP:
- {
- shader.startSimple();
- GL_PREFIX glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- if (vp->leftOrTop3D)
- this->renderTexture(shader, ShaderCompositer::ST_SIMPLE, firstRect, texInfo, *subtitleImg, renderRect, firstColorValue, QMatrix4x4(), true);
- else
- this->renderTexture(shader, ShaderCompositer::ST_SIMPLE, secondRect, texInfo, *subtitleImg, renderRect, firstColorValue, QMatrix4x4(), true);
- shader.endSimple();
- break;
- }
- case AnyVODEnums::S3M_INTERLACED:
- {
- GL_PREFIX glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- shader.startSubtitleInterlace(shader.getLeftOrTop());
- this->renderTexture(shader, ShaderCompositer::ST_SUBTITLE_INTERLACE, firstRect, texInfo, *subtitleImg, renderRect, firstColorValue, QMatrix4x4(), true);
- shader.endSubtitleInterlace();
- shader.startSubtitleInterlace(!shader.getLeftOrTop());
- this->renderTexture(shader, ShaderCompositer::ST_SUBTITLE_INTERLACE, secondRect, texInfo, *subtitleImg, renderRect, firstColorValue, QMatrix4x4(), false);
- shader.endSubtitleInterlace();
- break;
- }
- case AnyVODEnums::S3M_CHECKER_BOARD:
- {
- GL_PREFIX glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- shader.startSubtitleCheckerBoard(shader.getLeftOrTop());
- this->renderTexture(shader, ShaderCompositer::ST_SUBTITLE_CHECKER_BOARD, firstRect, texInfo, *subtitleImg, renderRect, firstColorValue, QMatrix4x4(), true);
- shader.endSubtitleCheckerBoard();
- shader.startSubtitleCheckerBoard(!shader.getLeftOrTop());
- this->renderTexture(shader, ShaderCompositer::ST_SUBTITLE_CHECKER_BOARD, secondRect, texInfo, *subtitleImg, renderRect, firstColorValue, QMatrix4x4(), false);
- shader.endSubtitleCheckerBoard();
- break;
- }
- case AnyVODEnums::S3M_ANAGLYPH:
- {
- GL_PREFIX glBlendFunc(GL_SRC_COLOR, GL_ONE);
- shader.startSubtitleAnaglyph(shader.getLeftOrTop());
- this->renderTexture(shader, ShaderCompositer::ST_SUBTITLE_ANAGLYPH, firstRect, texInfo, *subtitleImg, renderRect, firstColorValue, QMatrix4x4(), true);
- shader.endSubtitleAnaglyph();
- shader.startSubtitleAnaglyph(!shader.getLeftOrTop());
- this->renderTexture(shader, ShaderCompositer::ST_SUBTITLE_ANAGLYPH, secondRect, texInfo, *subtitleImg, renderRect, secondColorValue, QMatrix4x4(), false);
- shader.endSubtitleAnaglyph();
- break;
- }
- default:
- {
- GL_PREFIX glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- shader.startSimple();
- this->renderTexture(shader, ShaderCompositer::ST_SIMPLE, firstRect, texInfo, *subtitleImg, renderRect, firstColorValue, QMatrix4x4(), true);
- this->renderTexture(shader, ShaderCompositer::ST_SIMPLE, secondRect, texInfo, *subtitleImg, renderRect, secondColorValue, QMatrix4x4(), false);
- shader.endSimple();
- break;
- }
- }
- }
- if (!enabledBlend)
- GL_PREFIX glDisable(GL_BLEND);
- this->deleteSurface(subtitleImg);
- }
- }
- else if (rect->type == SUBTITLE_TEXT)
- {
- QString text = QString::fromUtf8(rect->text);
- QStringList texts;
- text.remove('\r');
- texts = text.split('\n');
- if (this->needMaxWidth())
- {
- for (int i = 0; i < texts.count(); i++)
- {
- this->getSubtitleSize(fm, texts[i], &size);
- maxWidth = max(maxWidth, size.width());
- forcedLeft |= this->isLeftAlignLine(texts[i]);
- }
- }
- for (int j = 0; j < texts.count(); j++, currentCount++)
- this->drawSubtitleLine(shader, currentCount, texts.count() * sp->num_rects, texts[j], QPoint(0, 0), Font::Context(Qt::white), texts[j], maxWidth, forcedLeft, vp);
- }
- else if (rect->type == SUBTITLE_ASS)
- {
- isASS = true;
- }
- }
- return isASS;
- }
- void MediaPresenter::drawASS(const ASS_RENDER_METHOD method, const int32_t time, ShaderCompositer &shader, const VideoPicture *vp)
- {
- ASS_Image *images = nullptr;
- bool changed = false;
- bool success = false;
- switch (method)
- {
- case ASSRM_FILE:
- success = this->m_assParser.get(time, &images, &changed);
- break;
- case ASSRM_SINGLE:
- success = this->m_assParser.getSingle(time, &images, &changed);
- break;
- case ASSRM_AV:
- success = this->m_avParser.getASSImage(time, &images, &changed);
- break;
- }
- if (success)
- this->renderASS(images, changed, shader, vp);
- }
- void MediaPresenter::renderASS(ASS_Image *ass, bool blend, ShaderCompositer &shader, const VideoPicture *vp)
- {
- if (ass->w <= 0 || ass->h <= 0)
- return;
- Surface *frame = this->m_state->video.assFrame;
- if (frame == nullptr)
- return;
- if (blend)
- {
- memset(frame->pixels[0], 0, frame->height * frame->lineSize[0]);
- while (ass)
- {
- this->blendASS(ass, frame);
- ass = ass->next;
- }
- }
- QRect rect;
- QPoint posOffset;
- this->getPictureRect(&rect);
- this->getSubtitlePositionOffsetByFrame(QSize(frame->width, frame->height), &posOffset);
- rect.translate(-posOffset);
- bool enabledBlend = GL_PREFIX glIsEnabled(GL_BLEND);
- GL_PREFIX glEnable(GL_BLEND);
- if (this->m_3dSubtitleMethod == AnyVODEnums::S3M_NONE)
- {
- QColor color = Qt::white;
- color.setAlphaF(this->m_subtitleOpaque);
- GL_PREFIX glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- shader.startSimple();
- this->renderASSSub(shader, ShaderCompositer::ST_SIMPLE, rect, *frame, blend, color, true);
- shader.endSimple();
- }
- else
- {
- QColor firstColorValue = Qt::white;
- QColor secondColorValue = Qt::white;
- QRect firstRect = rect;
- QRect secondRect = rect;
- firstColorValue.setAlphaF(this->m_subtitleOpaque);
- secondColorValue.setAlphaF(this->m_subtitleOpaque);
- switch (this->m_3dSubtitleMethod)
- {
- case AnyVODEnums::S3M_TOP_BOTTOM:
- {
- firstRect.setHeight(firstRect.height() / 2);
- secondRect.setY(secondRect.y() + firstRect.height());
- break;
- }
- case AnyVODEnums::S3M_LEFT_RIGHT:
- {
- firstRect.setWidth(firstRect.width() / 2);
- secondRect.setX(secondRect.x() + firstRect.width());
- break;
- }
- default:
- {
- break;
- }
- }
- firstRect.translate(-this->m_3dSubtitleOffset * this->m_devicePixelRatio);
- secondRect.translate(this->m_3dSubtitleOffset * this->m_devicePixelRatio);
- switch (this->m_3dSubtitleMethod)
- {
- case AnyVODEnums::S3M_PAGE_FLIP:
- {
- GL_PREFIX glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- shader.startSimple();
- if (vp->leftOrTop3D)
- this->renderASSSub(shader, ShaderCompositer::ST_SIMPLE, firstRect, *frame, blend, firstColorValue, true);
- else
- this->renderASSSub(shader, ShaderCompositer::ST_SIMPLE, secondRect, *frame, blend, firstColorValue, true);
- shader.endSimple();
- break;
- }
- case AnyVODEnums::S3M_INTERLACED:
- {
- GL_PREFIX glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- shader.startSubtitleInterlace(shader.getLeftOrTop());
- this->renderASSSub(shader, ShaderCompositer::ST_SUBTITLE_INTERLACE, firstRect, *frame, blend, firstColorValue, true);
- shader.endSubtitleInterlace();
- shader.startSubtitleInterlace(!shader.getLeftOrTop());
- this->renderASSSub(shader, ShaderCompositer::ST_SUBTITLE_INTERLACE, secondRect, *frame, blend, firstColorValue, false);
- shader.endSubtitleInterlace();
- break;
- }
- case AnyVODEnums::S3M_CHECKER_BOARD:
- {
- GL_PREFIX glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- shader.startSubtitleCheckerBoard(shader.getLeftOrTop());
- this->renderASSSub(shader, ShaderCompositer::ST_SUBTITLE_CHECKER_BOARD, firstRect, *frame, blend, firstColorValue, true);
- shader.endSubtitleCheckerBoard();
- shader.startSubtitleCheckerBoard(!shader.getLeftOrTop());
- this->renderASSSub(shader, ShaderCompositer::ST_SUBTITLE_CHECKER_BOARD, secondRect, *frame, blend, firstColorValue, false);
- shader.endSubtitleCheckerBoard();
- break;
- }
- case AnyVODEnums::S3M_ANAGLYPH:
- {
- GL_PREFIX glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
- shader.startSubtitleAnaglyph(shader.getLeftOrTop());
- this->renderASSSub(shader, ShaderCompositer::ST_SUBTITLE_ANAGLYPH, firstRect, *frame, blend, firstColorValue, true);
- shader.endSubtitleAnaglyph();
- shader.startSubtitleAnaglyph(!shader.getLeftOrTop());
- this->renderASSSub(shader, ShaderCompositer::ST_SUBTITLE_ANAGLYPH, secondRect, *frame, blend, secondColorValue, false);
- shader.endSubtitleAnaglyph();
- break;
- }
- default:
- {
- GL_PREFIX glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- shader.startSimple();
- this->renderASSSub(shader, ShaderCompositer::ST_SIMPLE, firstRect, *frame, blend, firstColorValue, true);
- this->renderASSSub(shader, ShaderCompositer::ST_SIMPLE, secondRect, *frame, blend, secondColorValue, false);
- shader.endSimple();
- break;
- }
- }
- }
- if (!enabledBlend)
- GL_PREFIX glDisable(GL_BLEND);
- }
- void MediaPresenter::renderASSSub(ShaderCompositer &shader, ShaderCompositer::ShaderType type, const QRect &rect,
- const Surface &frame, bool blend, const QColor &color, bool updateTexture) const
- {
- QRectF renderRect(0.0, 0.0, 1.0, 1.0);
- if (blend)
- {
- this->renderTexture(shader, type, rect, this->m_texInfo[TEX_ASS_SUBTITLE], frame, renderRect, color, QMatrix4x4(), updateTexture);
- }
- else
- {
- Surface tmp = frame;
- tmp.pixels[0] = nullptr;
- this->renderTexture(shader, type, rect, this->m_texInfo[TEX_ASS_SUBTITLE], tmp, renderRect, color, QMatrix4x4(), updateTexture);
- }
- }
- void MediaPresenter::blendASS(ASS_Image *single, Surface *frame) const
- {
- int pixelSize = GET_PIXEL_SIZE(true);
- uint8_t r = GET_RED_VALUE(single->color);
- uint8_t g = GET_GREEN_VALUE(single->color);
- uint8_t b = GET_BLUE_VALUE(single->color);
- uint8_t a = 255 - GET_ALPHA_VALUE(single->color);
- uint8_t *src = single->bitmap;
- uint8_t *dst = frame->pixels[0] + single->dst_y * frame->lineSize[0] + single->dst_x * pixelSize;
- for (int y = 0; y < single->h; ++y)
- {
- for (int x = 0; x < single->w; ++x)
- {
- uint8_t k = src[x] * a / 255;
- uint8_t revOp = 255 - k;
- int xOffset = x * pixelSize;
- if (pixelSize == 4)
- {
- int aOffset = xOffset + 3;
- uint8_t alphaDst = dst[aOffset];
- if (k == 0 && alphaDst == 0)
- continue;
- dst[aOffset] = (k * 255 + revOp * alphaDst) / 255;
- }
- int rOffset = xOffset + 0;
- int gOffset = xOffset + 1;
- int bOffset = xOffset + 2;
- dst[rOffset] = (k * r + revOp * dst[rOffset]) / 255;
- dst[gOffset] = (k * g + revOp * dst[gOffset]) / 255;
- dst[bOffset] = (k * b + revOp * dst[bOffset]) / 255;
- }
- src += single->stride;
- dst += frame->lineSize[0];
- }
- }
- Surface* MediaPresenter::createSurface(int width, int height, AVPixelFormat format) const
- {
- Surface *surface;
- int planes = av_pix_fmt_count_planes(format);
- if (planes <= 0)
- return nullptr;
- surface = new Surface;
- if (!surface)
- return nullptr;
- for (int i = 0; i < planes; i++)
- {
- int lineSize = av_image_get_linesize(format, width, i);
- if (lineSize > 0)
- {
- surface->lineSize[i] = lineSize;
- surface->pixels[i] = (uint8_t*)av_mallocz(surface->lineSize[i] * height);
- }
- }
- surface->height = height;
- surface->width = width;
- surface->format = format;
- surface->plane = planes;
- return surface;
- }
- void MediaPresenter::deleteSurface(Surface *surface) const
- {
- for (int i = 0; i < surface->plane; i++)
- {
- if (surface->pixels[i])
- av_freep(&surface->pixels[i]);
- }
- delete surface;
- }
- bool MediaPresenter::isUseGPUConvert(AVPixelFormat format) const
- {
- bool use = this->m_useGPUConvert;
- #ifdef Q_OS_WIN
- use &= GL_PREFIX glActiveTextureARB != nullptr;
- #endif
- return use && this->isYUV(format);
- }
- bool MediaPresenter::isYUV(AVPixelFormat format) const
- {
- switch (format)
- {
- case AV_PIX_FMT_YUV420P:
- case AV_PIX_FMT_YUYV422:
- case AV_PIX_FMT_UYVY422:
- case AV_PIX_FMT_YVYU422:
- case AV_PIX_FMT_NV12:
- case AV_PIX_FMT_NV21:
- return true;
- default:
- return false;
- }
- }
- AVPixelFormat MediaPresenter::getCompatibleFormat(AVPixelFormat format) const
- {
- if (!this->m_useLowQualityMode)
- return DEFAULT_PIX_FORMAT;
- #if defined Q_OS_MOBILE
- switch (format)
- {
- case AV_PIX_FMT_YUV420P9:
- case AV_PIX_FMT_YUV420P10:
- case AV_PIX_FMT_YUV420P12:
- case AV_PIX_FMT_YUV420P14:
- case AV_PIX_FMT_YUV420P16:
- return AV_PIX_FMT_YUV420P;
- default:
- return DEFAULT_PIX_FORMAT;
- }
- #else
- (void)format;
- return DEFAULT_PIX_FORMAT;
- #endif
- }
- uint8_t MediaPresenter::getLuminanceAvg(uint8_t *data, int size, AVPixelFormat format) const
- {
- if (Utils::is8bitFormat(format) && size)
- {
- uint64_t avg = 0;
- int step = 4;
- for (int i = 0; i < size; i += step)
- avg += data[i];
- return (uint8_t)(avg / (size / step));
- }
- return 127;
- }
- void MediaPresenter::resizePicture(const VideoPicture *src, VideoPicture *dest) const
- {
- MediaState *ms = this->m_state;
- int width = 0;
- int height = 0;
- this->getFrameSize(&width, &height);
- if (src->surface)
- {
- if (width != dest->width || height != dest->height)
- {
- if (dest->surface)
- this->deleteSurface(dest->surface);
- *dest = *src;
- dest->surface = this->createSurface(width, height, src->surface->format);
- dest->height = height;
- dest->width = width;
- }
- dest->lumAvg = src->lumAvg;
- dest->pts = src->pts;
- dest->time = src->time;
- if (dest->surface)
- {
- ms->imageRGBConverter = sws_getCachedContext(
- ms->imageRGBConverter,
- src->width, src->height, src->surface->format,
- width, height, dest->surface->format,
- SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
- AVFrame pict;
- uint8_t *data[PICTURE_MAX_PLANE];
- int lineSize[PICTURE_MAX_PLANE];
- memset(&pict, 0, sizeof(pict));
- memcpy(data, src->surface->pixels, sizeof(data));
- memcpy(lineSize, src->surface->lineSize, sizeof(lineSize));
- memcpy(pict.data, dest->surface->pixels, sizeof(data));
- memcpy(pict.linesize, dest->surface->lineSize, sizeof(lineSize));
- if (ms->imageRGBConverter)
- sws_scale(ms->imageRGBConverter, data, lineSize, 0, src->height, pict.data, pict.linesize);
- }
- }
- }
- void MediaPresenter::copyPicture(const VideoPicture *src, VideoPicture *dest) const
- {
- int width = 0;
- int height = 0;
- this->getFrameSize(&width, &height);
- if (src->surface)
- {
- if (width != dest->width || height != dest->height)
- {
- if (dest->surface)
- this->deleteSurface(dest->surface);
- *dest = *src;
- dest->surface = this->createSurface(width, height, src->surface->format);
- dest->height = height;
- dest->width = width;
- }
- dest->lumAvg = src->lumAvg;
- dest->pts = src->pts;
- dest->time = src->time;
- if (dest->surface)
- {
- AVFrame picDest;
- AVFrame picSrc;
- memcpy(picDest.data, dest->surface->pixels, sizeof(dest->surface->pixels));
- memcpy(picDest.linesize, dest->surface->lineSize, sizeof(dest->surface->lineSize));
- memcpy(picSrc.data, src->surface->pixels, sizeof(src->surface->pixels));
- memcpy(picSrc.linesize, src->surface->lineSize, sizeof(src->surface->lineSize));
- av_image_copy(picDest.data, picDest.linesize, (const uint8_t**)picSrc.data, picSrc.linesize, dest->surface->format, width, height);
- }
- }
- }
- bool MediaPresenter::getFrameSize(int *width, int *height) const
- {
- MediaState *ms = this->m_state;
- if (ms && this->isEnabledVideo())
- {
- AVCodecContext *codec = ms->video.stream.ctx;
- if (codec)
- {
- *width = codec->width;
- *height = codec->height;
- return true;
- }
- }
- return false;
- }
- void MediaPresenter::getSubtitlePositionOffset(QPoint *ret) const
- {
- QRect desktopRect;
- #if defined Q_OS_MOBILE
- desktopRect = QRect(0, 0, this->m_width, this->m_height);
- #else
- QDesktopWidget *desktop = QApplication::desktop();
- desktopRect = desktop->screenGeometry(desktop->primaryScreen());
- #endif
- ret->setX(Utils::mapTo(desktopRect.width(), this->m_width, this->m_horiPosition * MediaPresenter::DEFAULT_HORI_SUBTITLE_RATIO * this->m_devicePixelRatio));
- ret->setY(Utils::mapTo(desktopRect.height(), this->m_height, this->m_vertPosition * MediaPresenter::DEFAULT_VIRT_SUBTITLE_RATIO * this->m_devicePixelRatio));
- }
- void MediaPresenter::getSubtitlePositionOffsetByFrame(const QSize &org, QPoint *ret) const
- {
- const FrameSize &frame = this->m_state->frameSize;
- ret->setX(Utils::mapTo(org.width(), frame.width, this->m_horiPosition * MediaPresenter::DEFAULT_HORI_SUBTITLE_RATIO * this->m_devicePixelRatio));
- ret->setY(Utils::mapTo(org.height(), frame.height, this->m_vertPosition * MediaPresenter::DEFAULT_VIRT_SUBTITLE_RATIO * this->m_devicePixelRatio));
- }
- void MediaPresenter::renderTexture2D(ShaderCompositer &shader, ShaderCompositer::ShaderType type, const QRect &rect,
- AVPixelFormat format, const QMatrix4x4 &modelView, const QRectF &texCoord, const QColor &color) const
- {
- QVector4D vColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
- QVector3D vertices[] =
- {
- QVector3D(rect.left(), rect.bottom(), 0.0f),
- QVector3D(rect.right(), rect.bottom(), 0.0f),
- QVector3D(rect.left(), rect.top(), 0.0f),
- QVector3D(rect.right(), rect.top(), 0.0f)
- };
- QVector2D texCoords[] =
- {
- QVector2D(texCoord.left(), texCoord.bottom()),
- QVector2D(texCoord.right(), texCoord.bottom()),
- QVector2D(texCoord.left(), texCoord.top()),
- QVector2D(texCoord.right(), texCoord.top())
- };
- shader.setRenderData(type, this->m_ortho, modelView, vertices, texCoords, vColor, format);
- GL_PREFIX glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- }
- void MediaPresenter::renderTexture3D(ShaderCompositer &shader, ShaderCompositer::ShaderType type, const QRect &rect, AVPixelFormat format, const QMatrix4x4 &modelView, const QColor &color, bool leftOrTop) const
- {
- QVector4D vColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
- const QVector2D *texCoords;
- switch (this->m_vrInputSource)
- {
- case AnyVODEnums::VRI_LEFT_RIGHT_LEFT_PRIOR:
- texCoords = Sphere::getSBSTexCoords(leftOrTop);
- break;
- case AnyVODEnums::VRI_LEFT_RIGHT_RIGHT_PRIOR:
- texCoords = Sphere::getSBSTexCoords(!leftOrTop);
- break;
- case AnyVODEnums::VRI_TOP_BOTTOM_TOP_PRIOR:
- texCoords = Sphere::getTABTexCoords(leftOrTop);
- break;
- case AnyVODEnums::VRI_TOP_BOTTOM_BOTTOM_PRIOR:
- texCoords = Sphere::getTABTexCoords(!leftOrTop);
- break;
- default:
- texCoords = Sphere::getTexCoords();
- break;
- }
- QMatrix4x4 perspective;
- perspective.setToIdentity();
- if (this->m_vrInputSource == AnyVODEnums::VRI_NONE)
- {
- perspective.perspective(PERSPECTIVE_FOV_Y / 2.0f, (float)this->m_width / this->m_height, PERSPECTIVE_ZNEAR, PERSPECTIVE_ZFAR);
- shader.setRenderData(type, perspective, modelView, Sphere::getVertices(), texCoords, vColor, format);
- GL_PREFIX glDrawElements(GL_TRIANGLES, Sphere::getIndexCount(), GL_UNSIGNED_SHORT, Sphere::getIndices());
- }
- else
- {
- GLint viewport[4];
- perspective.perspective(PERSPECTIVE_FOV_Y, (float)rect.width() / this->m_height, PERSPECTIVE_ZNEAR, PERSPECTIVE_ZFAR);
- GL_PREFIX glGetIntegerv(GL_VIEWPORT, viewport);
- GL_PREFIX glViewport(rect.x(), 0, rect.width(), this->m_height);
- shader.setRenderData(type, perspective, modelView, Sphere::getVertices(), texCoords, vColor, format);
- GL_PREFIX glDrawElements(GL_TRIANGLES, Sphere::getIndexCount(), GL_UNSIGNED_SHORT, Sphere::getIndices());
- GL_PREFIX glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
- }
- }
- void MediaPresenter::renderTexture(ShaderCompositer &shader, ShaderCompositer::ShaderType type,
- const QRect &rect, TextureInfo &texInfo, const Surface &surface,
- const QRectF &renderRect, const QColor &color, const QMatrix4x4 &modelView,
- bool updateTexture) const
- {
- if (this->isUseGPUConvert(surface.format) && type == ShaderCompositer::ST_SCREEN)
- {
- for (int i = 0; i < surface.plane; i++)
- {
- const TextureInfo &info = this->m_texInfo[TEX_YUV_0 + i];
- #ifdef Q_OS_WIN
- GL_PREFIX glActiveTextureARB(GL_TEXTURE0 + i);
- #else
- GL_PREFIX glActiveTexture(GL_TEXTURE0 + i);
- #endif
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, info.id[info.index]);
- shader.setTextureSampler(type, i, surface.format);
- }
- }
- else
- {
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, texInfo.id[texInfo.index]);
- }
- if (surface.pixels[0])
- {
- bool uploadable = true;
- GLvoid *pixels[PICTURE_MAX_PLANE] = {nullptr, };
- bool usePBO = this->isUsingPBO(surface.format);
- if (updateTexture)
- {
- if (usePBO)
- {
- #if !defined Q_OS_MOBILE
- size_t bufSize = surface.lineSize[0] * surface.height;
- GLubyte *buf;
- GL_PREFIX glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, texInfo.idPBO[texInfo.indexPBO]);
- GL_PREFIX glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, bufSize, nullptr, GL_STREAM_DRAW_ARB);
- buf = (GLubyte*)GL_PREFIX glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB);
- if (buf)
- {
- memcpy(buf, surface.pixels[0], bufSize);
- GL_PREFIX glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
- }
- else
- {
- uploadable = false;
- }
- texInfo.indexPBO = (texInfo.indexPBO + 1) % MAX_PBO_COUNT;
- pixels[0] = (GLvoid*)0;
- #endif
- }
- else
- {
- for (int i = 0; i < surface.plane; i++)
- pixels[i] = surface.pixels[i];
- }
- }
- else
- {
- uploadable = false;
- }
- if (uploadable)
- {
- if (surface.plane > 0 && this->isUseGPUConvert(surface.format) && type == ShaderCompositer::ST_SCREEN)
- {
- GLsizei widths[surface.plane];
- GLsizei heights[surface.plane];
- GLenum formats[surface.plane];
- GLint aligns[surface.plane];
- switch (surface.format)
- {
- case AV_PIX_FMT_YUV420P:
- {
- widths[0] = surface.width;
- widths[1] = surface.width / 2;
- widths[2] = surface.width / 2;
- heights[0] = surface.height;
- heights[1] = surface.height / 2;
- heights[2] = surface.height / 2;
- formats[0] = GL_LUMINANCE;
- formats[1] = GL_LUMINANCE;
- formats[2] = GL_LUMINANCE;
- aligns[0] = 1;
- aligns[1] = 1;
- aligns[2] = 1;
- break;
- }
- case AV_PIX_FMT_NV12:
- case AV_PIX_FMT_NV21:
- {
- widths[0] = surface.width;
- widths[1] = surface.width;
- heights[0] = surface.height;
- heights[1] = surface.height / 2;
- formats[0] = GL_LUMINANCE;
- formats[1] = GL_LUMINANCE_ALPHA;
- aligns[0] = 1;
- aligns[1] = 2;
- break;
- }
- case AV_PIX_FMT_YUYV422:
- case AV_PIX_FMT_UYVY422:
- case AV_PIX_FMT_YVYU422:
- {
- widths[0] = surface.width / 2;
- heights[0] = surface.height;
- formats[0] = GL_RGBA;
- aligns[0] = 4;
- break;
- }
- default:
- {
- break;
- }
- }
- for (int i = 0; i < surface.plane; i++)
- {
- TextureInfo &info = this->m_texInfo[TEX_YUV_0 + i];
- GL_PREFIX glPixelStorei(GL_UNPACK_ALIGNMENT, aligns[i]);
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, info.id[info.index]);
- if (info.init[info.index])
- {
- GL_PREFIX glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, widths[i], heights[i], formats[i], GL_UNSIGNED_BYTE, pixels[i]);
- }
- else
- {
- GL_PREFIX glTexImage2D(GL_TEXTURE_2D, 0, formats[i], widths[i], heights[i], 0, formats[i], GL_UNSIGNED_BYTE, pixels[i]);
- info.init[info.index] = true;
- }
- }
- }
- else
- {
- GL_PREFIX glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- if (texInfo.init[texInfo.index])
- {
- GL_PREFIX glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surface.width, surface.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels[0]);
- }
- else
- {
- GL_PREFIX glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface.width, surface.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels[0]);
- texInfo.init[texInfo.index] = true;
- }
- }
- }
- if (updateTexture)
- {
- #if !defined Q_OS_MOBILE
- if (usePBO)
- GL_PREFIX glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
- #endif
- }
- }
- if (this->m_distortionAdjustMode != AnyVODEnums::DAM_NONE)
- {
- float ratio = this->m_width / 2560.0f;
- int verticalGap = 50 * ratio;
- int horizentaGap = 50 * ratio;
- int verticalCount = this->m_width / verticalGap + 1;
- int horizentalCount = this->m_height / horizentaGap + 1;
- bool enabledBlend = GL_PREFIX glIsEnabled(GL_BLEND);
- GLfloat lineWidth = 0.0f;
- GL_PREFIX glGetFloatv(GL_LINE_WIDTH, &lineWidth);
- GL_PREFIX glDisable(GL_BLEND);
- GL_PREFIX glLineWidth(2.0f);
- QVector4D vColor(1.0f, 1.0f, 1.0f, 1.0f);
- QVector<QVector3D> vertices;
- for (int i = 0; i < verticalCount; i++)
- {
- vertices.append(QVector3D(i * verticalGap, 0, 0));
- vertices.append(QVector3D(i * verticalGap, this->m_height, 0));
- }
- for (int i = 0; i < horizentalCount; i++)
- {
- vertices.append(QVector3D(0, i * horizentaGap, 0));
- vertices.append(QVector3D(this->m_width, i * horizentaGap, 0));
- }
- shader.startLine();
- shader.setRenderData(ShaderCompositer::ST_LINE, this->m_ortho, QMatrix4x4(), vertices.data(), nullptr, vColor, AV_PIX_FMT_NONE);
- GL_PREFIX glDrawArrays(GL_LINES, 0, vertices.size());
- shader.endLine();
- if (enabledBlend)
- GL_PREFIX glEnable(GL_BLEND);
- GL_PREFIX glLineWidth(lineWidth);
- }
- else
- {
- if (shader.is360Degree())
- this->renderTexture3D(shader, type, rect, surface.format, modelView, color, updateTexture);
- else
- this->renderTexture2D(shader, type, rect, surface.format, modelView, renderRect, color);
- }
- if (this->isUseGPUConvert(surface.format) && type == ShaderCompositer::ST_SCREEN)
- {
- const MediaState *ms = this->m_state;
- const Pause &pause = ms->pause;
- const Seek &seek = ms->seek;
- bool incIndex = updateTexture && !pause.pause && !seek.requestPauseOnRender && surface.pixels[0];
- for (int i = surface.plane - 1; i >= 0 ; i--)
- {
- #ifdef Q_OS_WIN
- GL_PREFIX glActiveTextureARB(GL_TEXTURE0 + i);
- #else
- GL_PREFIX glActiveTexture(GL_TEXTURE0 + i);
- #endif
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, 0);
- TextureInfo &info = this->m_texInfo[TEX_YUV_0 + i];
- if (incIndex)
- info.index = (info.index + 1) % info.textureCount;
- }
- }
- else
- {
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, 0);
- }
- }
- void MediaPresenter::clearTexture(const QRect &rect, const TextureInfo &texInfo) const
- {
- QImage clear(rect.width(), rect.height(), QImage::Format_ARGB32);
- clear.fill(Qt::transparent);
- for (unsigned int i = 0; i < texInfo.textureCount; i++)
- {
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, texInfo.id[texInfo.index]);
- GL_PREFIX glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- GL_PREFIX glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, clear.constBits());
- }
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, 0);
- }
- bool MediaPresenter::isSideBySide() const
- {
- switch (this->m_3dMethod)
- {
- case AnyVODEnums::V3M_HALF_LEFT:
- case AnyVODEnums::V3M_HALF_RIGHT:
- case AnyVODEnums::V3M_FULL_LEFT_RIGHT:
- case AnyVODEnums::V3M_PAGE_FLIP_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_PAGE_FLIP_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_ROW_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_ROW_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_COL_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_COL_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_RED_CYAN_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_RED_CYAN_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_GREEN_MAGENTA_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_GREEN_MAGENTA_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_YELLOW_BLUE_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_YELLOW_BLUE_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_RED_BLUE_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_RED_BLUE_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_RED_GREEN_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_RED_GREEN_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_CHECKER_BOARD_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_CHECKER_BOARD_LEFT_RIGHT_RIGHT_PRIOR:
- return true;
- default:
- return false;
- }
- }
- bool MediaPresenter::get3DParameters(bool leftOrTop3D, const QSizeF &adjust, const QSizeF &surfaceSize, QRectF *renderRect, bool *sideBySide, bool *leftOrTop)
- {
- switch (this->m_3dMethod)
- {
- case AnyVODEnums::V3M_HALF_LEFT:
- {
- *renderRect = QRectF(0.0, 0.0, surfaceSize.width() / 2.0, surfaceSize.height());
- break;
- }
- case AnyVODEnums::V3M_HALF_RIGHT:
- {
- *renderRect = QRectF(surfaceSize.width() / 2.0, 0.0, surfaceSize.width() / 2.0 + adjust.width(), surfaceSize.height());
- break;
- }
- case AnyVODEnums::V3M_HALF_TOP:
- {
- *renderRect = QRectF(0.0, 0.0, surfaceSize.width(), surfaceSize.height() / 2.0);
- break;
- }
- case AnyVODEnums::V3M_HALF_BOTTOM:
- {
- *renderRect = QRectF(0.0, surfaceSize.height() / 2.0, surfaceSize.width(), surfaceSize.height() / 2.0 + adjust.height());
- break;
- }
- case AnyVODEnums::V3M_FULL_LEFT_RIGHT:
- case AnyVODEnums::V3M_FULL_TOP_BOTTOM:
- {
- *renderRect = QRectF(0.0, 0.0, surfaceSize.width(), surfaceSize.height());
- break;
- }
- case AnyVODEnums::V3M_PAGE_FLIP_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_PAGE_FLIP_LEFT_RIGHT_RIGHT_PRIOR:
- {
- if (leftOrTop3D)
- *renderRect = QRectF(0.0, 0.0, surfaceSize.width() / 2.0, surfaceSize.height());
- else
- *renderRect = QRectF(surfaceSize.width() / 2.0, 0.0, surfaceSize.width() / 2.0 + adjust.width(), surfaceSize.height());
- break;
- }
- case AnyVODEnums::V3M_PAGE_FLIP_TOP_BOTTOM_TOP_PRIOR:
- case AnyVODEnums::V3M_PAGE_FLIP_TOP_BOTTOM_BOTTOM_PRIOR:
- {
- if (leftOrTop3D)
- *renderRect = QRectF(0.0, 0.0, surfaceSize.width(), surfaceSize.height() / 2.0);
- else
- *renderRect = QRectF(0.0, surfaceSize.height() / 2.0, surfaceSize.width(), surfaceSize.height() / 2.0 + adjust.height());
- break;
- }
- case AnyVODEnums::V3M_ROW_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_ROW_TOP_BOTTOM_TOP_PRIOR:
- case AnyVODEnums::V3M_COL_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_COL_TOP_BOTTOM_TOP_PRIOR:
- case AnyVODEnums::V3M_RED_CYAN_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_RED_CYAN_TOP_BOTTOM_TOP_PRIOR:
- case AnyVODEnums::V3M_GREEN_MAGENTA_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_GREEN_MAGENTA_TOP_BOTTOM_TOP_PRIOR:
- case AnyVODEnums::V3M_YELLOW_BLUE_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_YELLOW_BLUE_TOP_BOTTOM_TOP_PRIOR:
- case AnyVODEnums::V3M_RED_BLUE_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_RED_BLUE_TOP_BOTTOM_TOP_PRIOR:
- case AnyVODEnums::V3M_RED_GREEN_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_RED_GREEN_TOP_BOTTOM_TOP_PRIOR:
- case AnyVODEnums::V3M_CHECKER_BOARD_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::V3M_CHECKER_BOARD_TOP_BOTTOM_TOP_PRIOR:
- {
- *leftOrTop = true;
- *renderRect = QRectF(0.0, 0.0, surfaceSize.width(), surfaceSize.height());
- break;
- }
- case AnyVODEnums::V3M_ROW_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_ROW_TOP_BOTTOM_BOTTOM_PRIOR:
- case AnyVODEnums::V3M_COL_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_COL_TOP_BOTTOM_BOTTOM_PRIOR:
- case AnyVODEnums::V3M_RED_CYAN_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_RED_CYAN_TOP_BOTTOM_BOTTOM_PRIOR:
- case AnyVODEnums::V3M_GREEN_MAGENTA_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_GREEN_MAGENTA_TOP_BOTTOM_BOTTOM_PRIOR:
- case AnyVODEnums::V3M_YELLOW_BLUE_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_YELLOW_BLUE_TOP_BOTTOM_BOTTOM_PRIOR:
- case AnyVODEnums::V3M_RED_BLUE_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_RED_BLUE_TOP_BOTTOM_BOTTOM_PRIOR:
- case AnyVODEnums::V3M_RED_GREEN_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_RED_GREEN_TOP_BOTTOM_BOTTOM_PRIOR:
- case AnyVODEnums::V3M_CHECKER_BOARD_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::V3M_CHECKER_BOARD_TOP_BOTTOM_BOTTOM_PRIOR:
- {
- *leftOrTop = false;
- *renderRect = QRectF(0.0, 0.0, surfaceSize.width(), surfaceSize.height());
- break;
- }
- default:
- {
- return false;
- }
- }
- *sideBySide = this->isSideBySide();
- return true;
- }
- void MediaPresenter::drawFonts(ShaderCompositer &shader, QRect rect, const VideoPicture *vp, bool distortionBound)
- {
- if (this->m_3dSubtitleMethod == AnyVODEnums::S3M_ANAGLYPH)
- {
- if (distortionBound)
- this->m_distortionFrameBuffer->release();
- this->m_anaglyphFrameBuffer->bind();
- GL_PREFIX glClear(GL_COLOR_BUFFER_BIT);
- }
- if (this->m_showSubtitle)
- this->drawSubtitles(shader, vp);
- if (this->m_showDetail)
- this->drawDetail(shader, vp);
- if (this->m_showingOptionDesc && !this->m_captureMode)
- this->drawOptionDesc(shader, vp);
- if (this->m_3dSubtitleMethod == AnyVODEnums::S3M_ANAGLYPH)
- {
- this->m_anaglyphFrameBuffer->release();
- if (distortionBound)
- this->m_distortionFrameBuffer->bind();
- GLfloat width = this->m_width / (GLfloat)this->m_anaglyphFrameBuffer->width();
- GLfloat height = this->m_height / (GLfloat)this->m_anaglyphFrameBuffer->height();
- bool enabledBlend = GL_PREFIX glIsEnabled(GL_BLEND);
- shader.startSimple();
- GL_PREFIX glEnable(GL_BLEND);
- GL_PREFIX glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, this->m_anaglyphFrameBuffer->texture());
- QVector4D vColor(1.0f, 1.0f, 1.0f, 1.0f);
- QVector3D vertices[] =
- {
- QVector3D(rect.left(), rect.bottom(), 0.0f),
- QVector3D(rect.right(), rect.bottom(), 0.0f),
- QVector3D(rect.left(), rect.top(), 0.0f),
- QVector3D(rect.right(), rect.top(), 0.0f)
- };
- QVector2D texCoords[] =
- {
- QVector2D(0.0f, 0.0f),
- QVector2D(width, 0.0f),
- QVector2D(0.0f, height),
- QVector2D(width, height)
- };
- shader.setRenderData(ShaderCompositer::ST_SIMPLE, this->m_ortho, QMatrix4x4(), vertices, texCoords, vColor, AV_PIX_FMT_NONE);
- GL_PREFIX glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, 0);
- shader.endSimple();
- if (!enabledBlend)
- GL_PREFIX glDisable(GL_BLEND);
- }
- }
- void MediaPresenter::displayVideo(ShaderCompositer &shader, const VideoPicture *vp)
- {
- Surface *surface = vp->surface;
- QRect rect;
- this->getPictureRect(&rect);
- if (this->m_vrInputSource != AnyVODEnums::VRI_NONE || shader.is360Degree())
- {
- this->m_distortionFrameBuffer->bind();
- GL_PREFIX glClear(GL_COLOR_BUFFER_BIT);
- }
- if (surface)
- {
- QRectF renderRect;
- TextureInfo &texInfo = this->m_texInfo[TEX_MOVIE_FRAME];
- bool leftOrTop = false;
- bool sideBySide = false;
- QSizeF surfaceSize(surface->width, surface->height);
- QSizeF screenSize(1.0, 1.0);
- QSizeF adjust(1.0 / surface->width, 1.0 / surface->height);
- if (!this->get3DParameters(vp->leftOrTop3D, adjust, screenSize, &renderRect, &sideBySide, &leftOrTop))
- renderRect = QRectF(QPointF(0.0, 0.0), screenSize);
- shader.setup3D(sideBySide, leftOrTop);
- shader.startScreen(surfaceSize, screenSize, QSize(texInfo.maxSize, texInfo.maxSize), this->getMasterClock(), vp->lumAvg / 255.0, surface->format);
- GLfloat degree;
- this->m_cameraLock.lock();
- degree = (float)(this->m_rotation + this->m_sensorRotation);
- this->m_cameraLock.unlock();
- switch (this->m_screenRotationDegree)
- {
- case AnyVODEnums::SRD_90:
- degree += 90.0f;
- break;
- case AnyVODEnums::SRD_180:
- degree += 180.0f;
- break;
- case AnyVODEnums::SRD_270:
- degree += 270.0f;
- break;
- default:
- break;
- }
- QMatrix4x4 modelViewLeft;
- QMatrix4x4 modelViewRight;
- if (shader.is360Degree())
- {
- if (this->m_vrInputSource == AnyVODEnums::VRI_VIRTUAL_3D)
- {
- modelViewLeft.setToIdentity();
- modelViewLeft.rotate(-degree, 1.0f, 0.0f, 0.0f);
- modelViewRight = modelViewLeft;
- this->m_cameraLock.lock();
- this->m_camera.moveLeftRight(-this->m_virtual3DDepth);
- modelViewLeft = this->m_camera.getMatrix() * modelViewLeft;
- this->m_camera.moveLeftRight(this->m_virtual3DDepth);
- modelViewRight = this->m_camera.getMatrix() * modelViewRight;
- this->m_camera.resetPosition();
- this->m_cameraLock.unlock();
- }
- else
- {
- this->m_cameraLock.lock();
- modelViewLeft = this->m_camera.getMatrix();
- this->m_cameraLock.unlock();
- modelViewLeft.rotate(-degree, 1.0f, 0.0f, 0.0f);
- }
- }
- else
- {
- if (this->m_vrInputSource == AnyVODEnums::VRI_VIRTUAL_3D)
- {
- modelViewLeft.setToIdentity();
- modelViewLeft.translate((this->m_width / 2.0f), (this->m_height / 2.0f), 0.0f);
- modelViewLeft.rotate(degree, 0.0f, 0.0f, 1.0f);
- modelViewLeft.translate(-(this->m_width / 2.0f), -(this->m_height / 2.0f), 0.0f);
- modelViewRight = modelViewLeft;
- modelViewLeft.translate(-80.0f, 0.0f);
- modelViewRight.translate(80.0f, 0.0f);
- }
- else
- {
- modelViewLeft.setToIdentity();
- modelViewLeft.translate((this->m_width / 2.0f), (this->m_height / 2.0f), 0.0f);
- modelViewLeft.rotate(degree, 0.0f, 0.0f, 1.0f);
- modelViewLeft.translate(-(this->m_width / 2.0f), -(this->m_height / 2.0f), 0.0f);
- }
- }
- QColor color = Qt::white;
- color.setAlphaF(1.0);
- switch (this->m_vrInputSource)
- {
- case AnyVODEnums::VRI_LEFT_RIGHT_LEFT_PRIOR:
- case AnyVODEnums::VRI_LEFT_RIGHT_RIGHT_PRIOR:
- case AnyVODEnums::VRI_TOP_BOTTOM_TOP_PRIOR:
- case AnyVODEnums::VRI_TOP_BOTTOM_BOTTOM_PRIOR:
- {
- QRect firstRect = rect;
- QRect secondRect = rect;
- firstRect.setWidth(rect.width() / 2);
- secondRect.setLeft(rect.x() + (rect.width() - 1) / 2);
- secondRect.setWidth(rect.width() / 2);
- QRectF firstTexRect;
- QRectF secondTexRect;
- if (!shader.is360Degree())
- {
- firstTexRect = renderRect;
- secondTexRect = renderRect;
- if (this->m_vrInputSource == AnyVODEnums::VRI_LEFT_RIGHT_LEFT_PRIOR ||
- this->m_vrInputSource == AnyVODEnums::VRI_LEFT_RIGHT_RIGHT_PRIOR)
- {
- firstTexRect.setWidth(renderRect.width() / 2.0);
- secondTexRect.setLeft(renderRect.right() / 2.0);
- }
- else
- {
- firstTexRect.setHeight(renderRect.height() / 2.0);
- secondTexRect.setTop(renderRect.bottom() / 2.0);
- }
- }
- this->renderTexture(shader, ShaderCompositer::ST_SCREEN, firstRect, texInfo, *surface, firstTexRect, color, modelViewLeft, true);
- this->renderTexture(shader, ShaderCompositer::ST_SCREEN, secondRect, texInfo, *surface, secondTexRect, color, modelViewLeft, false);
- break;
- }
- case AnyVODEnums::VRI_COPY:
- {
- QRect firstRect = rect;
- QRect secondRect = rect;
- firstRect.setWidth(rect.width() / 2);
- secondRect.setLeft(rect.x() + (rect.width() - 1) / 2);
- secondRect.setWidth(rect.width() / 2);
- this->renderTexture(shader, ShaderCompositer::ST_SCREEN, firstRect, texInfo, *surface, renderRect, color, modelViewLeft, true);
- this->renderTexture(shader, ShaderCompositer::ST_SCREEN, secondRect, texInfo, *surface, renderRect, color, modelViewLeft, false);
- break;
- }
- case AnyVODEnums::VRI_VIRTUAL_3D:
- {
- QRect firstRect = rect;
- QRect secondRect = rect;
- firstRect.setWidth(rect.width() / 2);
- secondRect.setLeft(rect.x() + (rect.width() - 1) / 2);
- secondRect.setWidth(rect.width() / 2);
- this->renderTexture(shader, ShaderCompositer::ST_SCREEN, firstRect, texInfo, *surface, renderRect, color, modelViewLeft, true);
- this->renderTexture(shader, ShaderCompositer::ST_SCREEN, secondRect, texInfo, *surface, renderRect, color, modelViewRight, false);
- break;
- }
- default:
- {
- this->renderTexture(shader, ShaderCompositer::ST_SCREEN, rect, texInfo, *surface, renderRect, color, modelViewLeft, true);
- break;
- }
- }
- shader.endScreen(surface->format);
- this->m_detail.videoFrameCount.fetchAndAddOrdered(1);
- }
- if (!shader.is360Degree())
- this->drawFonts(shader, rect, vp, this->m_distortionFrameBuffer->isBound());
- if (this->m_vrInputSource != AnyVODEnums::VRI_NONE || shader.is360Degree())
- {
- this->m_distortionFrameBuffer->release();
- QRect renderRect = QRect(QPoint(0, 0), QSize(this->m_width, this->m_height));
- GLfloat width = this->m_width / (GLfloat)this->m_distortionFrameBuffer->width();
- GLfloat height = this->m_height / (GLfloat)this->m_distortionFrameBuffer->height();
- bool enabledBlend = GL_PREFIX glIsEnabled(GL_BLEND);
- QVector4D vColor(1.0f, 1.0f, 1.0f, 1.0f);
- GL_PREFIX glDisable(GL_BLEND);
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, this->m_distortionFrameBuffer->texture());
- QVector3D vertices[] =
- {
- QVector3D(0.0f, renderRect.bottom(), 0.0f),
- QVector3D(renderRect.right(), renderRect.bottom(), 0.0f),
- QVector3D(renderRect.left(), renderRect.top(), 0.0f),
- QVector3D(renderRect.right(), renderRect.top(), 0.0f)
- };
- if (this->m_vrInputSource != AnyVODEnums::VRI_NONE)
- {
- QVector2D leftTexCoords[] =
- {
- QVector2D(0.0f, 0.0f),
- QVector2D(width / 2.0f, 0.0f),
- QVector2D(0.0f, height),
- QVector2D(width / 2.0f, height)
- };
- QVector2D rightTexCoords[] =
- {
- QVector2D(0.0f + (width / 2.0f), 0.0f),
- QVector2D(width, 0.0f),
- QVector2D(0.0f + (width / 2.0f), height),
- QVector2D(width, height)
- };
- shader.startSimple();
- this->m_leftDistortionFrameBuffer->bind();
- shader.setRenderData(ShaderCompositer::ST_SIMPLE, this->m_ortho, QMatrix4x4(), vertices, leftTexCoords, vColor, AV_PIX_FMT_NONE);
- GL_PREFIX glClear(GL_COLOR_BUFFER_BIT);
- GL_PREFIX glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- this->m_leftDistortionFrameBuffer->release();
- this->m_rightDistortionFrameBuffer->bind();
- shader.setRenderData(ShaderCompositer::ST_SIMPLE, this->m_ortho, QMatrix4x4(), vertices, rightTexCoords, vColor, AV_PIX_FMT_NONE);
- GL_PREFIX glClear(GL_COLOR_BUFFER_BIT);
- GL_PREFIX glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- this->m_rightDistortionFrameBuffer->release();
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, 0);
- shader.endSimple();
- if (enabledBlend)
- GL_PREFIX glEnable(GL_BLEND);
- width = this->m_width / (GLfloat)this->m_leftDistortionFrameBuffer->width();
- height = this->m_height / (GLfloat)this->m_leftDistortionFrameBuffer->height();
- enabledBlend = GL_PREFIX glIsEnabled(GL_BLEND);
- ShaderCompositer::ShaderType shaderType;
- if (this->m_useDistortion)
- {
- if (shader.is360Degree())
- {
- shaderType = ShaderCompositer::ST_PINCUSHION_DISTORTION;
- shader.startPincushionDistortion(QVector2D(1.0f, 1.0f), this->m_distortionLensCenter,
- this->m_pincushionDistortionCoefficients, 1.0f);
- }
- else
- {
- shaderType = ShaderCompositer::ST_BARREL_DISTORTION;
- shader.startBarrelDistortion(QVector2D(1.0f, 1.0f), this->m_distortionLensCenter,
- this->m_barrelDistortionCoefficients, 1.0f);
- }
- }
- else
- {
- shaderType = ShaderCompositer::ST_SIMPLE;
- shader.startSimple();
- }
- GL_PREFIX glDisable(GL_BLEND);
- QVector3D leftVertices[] =
- {
- QVector3D(0.0f, renderRect.bottom(), 0.0f),
- QVector3D(renderRect.right() / 2, renderRect.bottom(), 0.0f),
- QVector3D(renderRect.left(), renderRect.top(), 0.0f),
- QVector3D(renderRect.right() / 2, renderRect.top(), 0.0f)
- };
- QVector3D rightVertices[] =
- {
- QVector3D(renderRect.left() + (renderRect.right() / 2), renderRect.bottom(), 0.0f),
- QVector3D(renderRect.right(), renderRect.bottom(), 0.0f),
- QVector3D(renderRect.left() + (renderRect.right() / 2), renderRect.top(), 0.0f),
- QVector3D(renderRect.right(), renderRect.top(), 0.0f)
- };
- QVector2D distortionTexCoords[] =
- {
- QVector2D(0.0f, 0.0f),
- QVector2D(width, 0.0f),
- QVector2D(0.0f, height),
- QVector2D(width, height)
- };
- shader.setRenderData(shaderType, this->m_ortho, QMatrix4x4(), leftVertices, distortionTexCoords, vColor, AV_PIX_FMT_NONE);
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, this->m_leftDistortionFrameBuffer->texture());
- GL_PREFIX glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- shader.setRenderData(shaderType, this->m_ortho, QMatrix4x4(), rightVertices, distortionTexCoords, vColor, AV_PIX_FMT_NONE);
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, this->m_rightDistortionFrameBuffer->texture());
- GL_PREFIX glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- if (this->m_useDistortion)
- {
- if (shader.is360Degree())
- shader.endPincushionDistortion();
- else
- shader.endBarrelDistortion();
- }
- else
- {
- shader.endSimple();
- }
- }
- else if (shader.is360Degree())
- {
- QVector2D texCoords[] =
- {
- QVector2D(0.0f, 0.0f),
- QVector2D(width, 0.0f),
- QVector2D(0.0f, height),
- QVector2D(width, height)
- };
- ShaderCompositer::ShaderType shaderType;
- if (this->m_useDistortion)
- {
- shaderType = ShaderCompositer::ST_PINCUSHION_DISTORTION;
- shader.startPincushionDistortion(QVector2D(1.0f, 1.0f), this->m_distortionLensCenter,
- this->m_pincushionDistortionCoefficients, 1.0f);
- }
- else
- {
- shaderType = ShaderCompositer::ST_SIMPLE;
- shader.startSimple();
- }
- shader.setRenderData(shaderType, this->m_ortho, QMatrix4x4(), vertices, texCoords, vColor, AV_PIX_FMT_NONE);
- GL_PREFIX glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- if (this->m_useDistortion)
- shader.endPincushionDistortion();
- else
- shader.endSimple();
- }
- GL_PREFIX glBindTexture(GL_TEXTURE_2D, 0);
- if (enabledBlend)
- GL_PREFIX glEnable(GL_BLEND);
- }
- if (shader.is360Degree())
- this->drawFonts(shader, rect, vp, this->m_distortionFrameBuffer->isBound());
- }
- void MediaPresenter::updateVideoRefreshTimer(ShaderCompositer &shader)
- {
- MediaState *ms = this->m_state;
- VideoFrames &frames = ms->videoFrames;
- FrameTimer &timer = ms->frameTimer;
- Pause &pause = ms->pause;
- Seek &seek = ms->seek;
- Video &video = ms->video;
- const VideoPicture *vp = &frames.queue[frames.data.rIndex];
- double pts = vp->pts;
- double delay = this->calFrameDelay(pts);
- int frameDrop = 0;
- if (ms->syncType != SYNC_VIDEO_MASTER)
- {
- double incClock = 0.0;
- if (this->m_hwDecoder.isOpened())
- incClock += this->m_hwDecoder.getSurfaceQueueCount() * delay;
- if (this->m_filterGraph.hasFilters())
- incClock += this->m_filterGraph.getDelayCount() * delay;
- double diff = pts - (this->getMasterClock() + incClock);
- double syncThreshold = max(delay * SYNC_THRESHOLD_MULTI, SYNC_THRESHOLD);
- if (fabs(diff) < NOSYNC_THRESHOLD)
- {
- if (diff <= -syncThreshold)
- {
- if (frameDrop <= 0)
- {
- if (timer.lowFrameCounter > FRAME_LOW_WARNING_THRESHOLD / 4)
- frameDrop = (int)fabs(diff / delay);
- else
- frameDrop = 1;
- }
- delay = 0.0;
- }
- else if (diff >= syncThreshold)
- {
- delay *= 2.0;
- }
- }
- }
- else
- {
- if (video.tempo > 0.0)
- delay /= 1.0 + video.tempo / 100.0;
- else if (video.tempo < 0.0)
- delay *= (150.0 - video.tempo) / 100.0;
- }
- timer.timer += delay * MICRO_SECOND;
- int64_t driftTime = pause.driftTime + video.driftTime +
- seek.videoDiscardDriftTime + seek.readDiscardDriftTime + ms->streamChangeDriftTime;
- double actualDelay = (timer.timer - (this->getAbsoluteClock() - driftTime)) / MICRO_SECOND;
- if (delay <= 0.0 && timer.lowFrameCounter <= FRAME_LOW_WARNING_THRESHOLD)
- timer.lowFrameCounter++;
- else
- timer.lowFrameCounter = 0;
- if (timer.lowFrameCounter > FRAME_LOW_WARNING_THRESHOLD && !this->m_showingOptionDesc)
- this->showOptionDesc(tr("프레임 저하가 일어나고 있습니다. 성능에 영향을 미치는 옵션 또는 수직 동기화를 꺼주세요."));
- int refresh = (int)(actualDelay * 1000 + 0.5);
- this->refreshSchedule(refresh);
- this->displayVideo(shader, vp);
- this->copyPicture(vp, &frames.prevPicture);
- if (this->m_useFrameDrop)
- video.frameDrop = frameDrop;
- else
- video.frameDrop = 0;
- if (seek.requestPauseOnRender)
- {
- if (--seek.pauseOnRenderCount <= 0)
- {
- seek.requestPauseOnRender = false;
- this->pause();
- }
- }
- }
- bool MediaPresenter::update(ShaderCompositer &shader)
- {
- MediaState *ms = this->m_state;
- if (!ms)
- return false;
- if (this->m_scheduleRecomputeSubtitleSize)
- {
- this->computeSubtitleSize();
- this->m_scheduleRecomputeSubtitleSize = false;
- }
- Video &video = ms->video;
- VideoFrames &frames = ms->videoFrames;
- if (!video.stream.stream)
- {
- #if defined Q_OS_MOBILE
- GL_PREFIX glClear(GL_COLOR_BUFFER_BIT);
- #endif
- this->refreshSchedule(NO_AUDIO_ALBUM_JACKET_DELAY);
- #if defined Q_OS_MOBILE
- VideoPicture &audioPicture = frames.audioPicture;
- if (!audioPicture.surface)
- audioPicture.surface = this->createSurface(this->m_width, this->m_height, this->m_format);
- this->displayVideo(shader, &audioPicture);
- return true;
- #else
- return false;
- #endif
- }
- int size;
- frames.data.lock.mutex.lock();
- size = frames.data.size;
- frames.data.lock.mutex.unlock();
- if (size == 0)
- {
- VideoPicture &audioPicture = frames.audioPicture;
- GL_PREFIX glClear(GL_COLOR_BUFFER_BIT);
- if (!this->isRemoteFile() && this->isAudio() && this->isEnabledVideo() && !audioPicture.surface)
- {
- FrameExtractor ex;
- FrameExtractor::FRAME_ITEM item;
- ex.setPixFormat(DEFAULT_PIX_FORMAT);
- if (ex.open(this->m_filePath) && ex.getFrame(0.0, true, &item))
- {
- VideoPicture vp;
- vp.height = item.frame.height();
- vp.width = item.frame.width();
- vp.surface = this->createSurface(vp.width, vp.height, DEFAULT_PIX_FORMAT);
- const uint8_t *buffers[4] = {item.buffer, };
- const int lineSizes[4] = {av_image_get_linesize(DEFAULT_PIX_FORMAT, vp.width, 0), };
- av_image_copy(vp.surface->pixels, vp.surface->lineSize,
- buffers, lineSizes, DEFAULT_PIX_FORMAT, vp.width, vp.height);
- this->resizePicture(&vp, &audioPicture);
- this->deleteSurface(vp.surface);
- }
- if (!audioPicture.surface)
- audioPicture.surface = this->createSurface(this->m_width, this->m_height, this->m_format);
- }
- if (!video.stream.queue.hasPacket() && this->isAudio())
- {
- this->refreshSchedule(DEFAULT_REFRESH_DELAY);
- this->displayVideo(shader, &frames.audioPicture);
- }
- else
- {
- this->refreshSchedule(EMPTY_BUFFER_WAIT_DELAY);
- this->displayVideo(shader, &frames.prevPicture);
- }
- return true;
- }
- GL_PREFIX glClear(GL_COLOR_BUFFER_BIT);
- if (ms->pause.pause)
- {
- const VideoPicture *vp = &frames.queue[frames.data.rIndex];
- this->refreshSchedule(DEFAULT_REFRESH_DELAY);
- this->displayVideo(shader, vp);
- return true;
- }
- this->updateVideoRefreshTimer(shader);
- if (ms->seek.flushed && ms->seek.pauseSeeking)
- {
- int maxCount;
- #if defined Q_OS_WIN
- maxCount = 3;
- #else
- maxCount = 1;
- #endif
- if (ms->seek.discardCount++ >= maxCount)
- {
- ms->seek.flushed = false;
- ms->seek.pauseSeeking = false;
- ms->seek.discardCount = 0;
- this->pause();
- }
- }
- if (!ms->seek.firstFrameAfterFlush)
- ms->seek.firstFrameAfterFlush = true;
- if (++frames.data.rIndex >= VIDEO_PICTURE_QUEUE_SIZE)
- frames.data.rIndex = 0;
- frames.data.lock.mutex.lock();
- if (frames.data.size-- == 0)
- frames.data.size = 0;
- frames.data.lock.cond.wakeOne();
- frames.data.lock.mutex.unlock();
- return true;
- }
- void MediaPresenter::allocPicture()
- {
- MediaState *ms = this->m_state;
- VideoFrames &frames = ms->videoFrames;
- VideoPicture *vp = &frames.queue[frames.data.wIndex];
- if (vp->surface)
- this->deleteSurface(vp->surface);
- AVCodecContext *codec = ms->video.stream.ctx;
- int width = 0;
- int height = 0;
- this->getFrameSize(&width, &height);
- vp->surface = this->createSurface(width, height, this->m_format);
- vp->height = height;
- vp->width = width;
- vp->orgHeight = codec->height;
- vp->orgWidth = codec->width;
- }
- bool MediaPresenter::convertPicture(AVFrame &inFrame, double pts, AVPixelFormat format, bool leftOrTop3D)
- {
- MediaState *ms = this->m_state;
- VideoFrames &frames = ms->videoFrames;
- frames.data.lock.mutex.lock();
- while (frames.data.size >= VIDEO_PICTURE_QUEUE_SIZE && !ms->quit && !ms->video.threadQuit)
- frames.data.lock.cond.wait(&frames.data.lock.mutex);
- frames.data.lock.mutex.unlock();
- if (ms->quit)
- return false;
- if (ms->video.threadQuit)
- return false;
- int destw = 0;
- int desth = 0;
- this->getFrameSize(&destw, &desth);
- VideoPicture *vp = &frames.queue[frames.data.wIndex];
- if (!vp->surface || vp->width != destw || vp->height != desth)
- {
- this->allocPicture();
- if (ms->quit)
- return false;
- }
- if (vp->surface)
- {
- AVCodecContext *codec = ms->video.stream.ctx;
- int w = codec->width;
- int h = codec->height;
- AVFrame *frame;
- bool hasFilters = this->m_filterGraph.hasFilters();
- AVFrame filterd;
- if (hasFilters)
- {
- if (!this->m_filterGraph.getFrame(w, h, format, inFrame, &filterd, &format))
- return true;
- frame = &filterd;
- }
- else
- {
- frame = &inFrame;
- }
- AVPixelFormat realFormat;
- int realLineSize[AV_NUM_DATA_POINTERS] = {0, };
- int realHeight;
- if (this->isUseGPUConvert(format))
- {
- AVFrame dst;
- AVFrame src;
- memcpy(dst.data, vp->surface->pixels, sizeof(vp->surface->pixels));
- memcpy(dst.linesize, vp->surface->lineSize, sizeof(vp->surface->lineSize));
- memcpy(src.data, frame->data, sizeof(frame->data));
- memcpy(src.linesize, frame->linesize, sizeof(frame->linesize));
- av_image_copy(dst.data, dst.linesize, (const uint8_t**)src.data, src.linesize, format, w, h);
- realFormat = format;
- realHeight = h;
- memcpy(realLineSize, frame->linesize, sizeof(frame->linesize));
- }
- else
- {
- ms->imageYUV420PConverter = sws_getCachedContext(
- ms->imageYUV420PConverter,
- w, h, format,
- destw, desth, this->m_format,
- SWS_POINT, nullptr, nullptr, nullptr);
- AVFrame pict;
- memset(&pict, 0, sizeof(pict));
- for (int i = 0; i < vp->surface->plane; i++)
- {
- pict.data[i] = (uint8_t*)vp->surface->pixels[i];
- pict.linesize[i] = vp->surface->lineSize[i];
- realLineSize[i] = pict.linesize[i];
- }
- if (ms->imageYUV420PConverter)
- sws_scale(ms->imageYUV420PConverter, frame->data, frame->linesize, 0, h, pict.data, pict.linesize);
- realFormat = this->m_format;
- realHeight = desth;
- }
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(realFormat);
- if (desc)
- {
- int height2 = AV_CEIL_RSHIFT(realHeight, desc->log2_chroma_h);
- this->m_detail.videoOutputByteCount.fetchAndAddOrdered(realLineSize[0] * realHeight);
- for (int i = 1; i < vp->surface->plane; i++)
- this->m_detail.videoOutputByteCount.fetchAndAddOrdered(realLineSize[i] * height2);
- }
- vp->pts = pts;
- vp->time = (pts + this->m_subtitleSync) * 1000;
- vp->lumAvg = this->getLuminanceAvg(frame->data[0], frame->linesize[0] * h, format);
- vp->leftOrTop3D = leftOrTop3D;
- if (++frames.data.wIndex >= VIDEO_PICTURE_QUEUE_SIZE)
- frames.data.wIndex = 0;
- frames.data.lock.mutex.lock();
- frames.data.size++;
- frames.data.lock.mutex.unlock();
- if (hasFilters)
- av_freep(&filterd.data[0]);
- }
- return true;
- }
- double MediaPresenter::synchronizeVideo(AVFrame *srcFrame, double pts, const AVRational timeBase)
- {
- Video &video = this->m_state->video;
- Seek &seek = this->m_state->seek;
- QMutexLocker locker(&video.stream.clockLock);
- if (pts == 0.0)
- {
- pts = video.stream.clock;
- }
- else
- {
- pts -= this->getAudioClockOffset();
- video.stream.clock = pts;
- }
- #if defined Q_OS_ANDROID
- if (!this->m_hwDecoder.isOpened())
- {
- #endif
- double frameDelay = av_q2d(timeBase);
- frameDelay = srcFrame->repeat_pict * (frameDelay * 0.5);
- video.stream.clock += frameDelay;
- #if defined Q_OS_ANDROID
- }
- #endif
- if (this->m_state->syncType == SYNC_VIDEO_MASTER && seek.firstFrameAfterFlush)
- seek.readable = true;
- return pts;
- }
- int MediaPresenter::getBuffer(AVCodecContext *ctx, AVFrame *pic, int flag)
- {
- int ret;
- MediaPresenter *parent = (MediaPresenter*)ctx->opaque;
- if (parent->m_hwDecoder.isOpened())
- ret = parent->m_hwDecoder.getBuffer(pic) ? 0 : -1;
- else
- ret = avcodec_default_get_buffer2(ctx, pic, flag);
- return ret;
- }
- AVPixelFormat MediaPresenter::getFormat(struct AVCodecContext *ctx, const AVPixelFormat *fmt)
- {
- MediaPresenter *parent = (MediaPresenter*)ctx->opaque;
- bool hwOpened = parent->m_hwDecoder.isOpened();
- for (int i = 0; fmt[i] != AV_PIX_FMT_NONE; i++)
- {
- if (hwOpened && parent->m_hwDecoder.isDecodable(fmt[i]))
- {
- if (parent->m_hwDecoder.prepare(ctx))
- return fmt[i];
- }
- }
- if (hwOpened)
- {
- if (parent->m_disableHWDecoder.callback)
- parent->m_disableHWDecoder.callback(parent->m_disableHWDecoder.userData);
- }
- return avcodec_default_get_format(ctx, fmt);
- }
- int MediaPresenter::decodeAudio(AVCodecContext *ctx, uint8_t **samples, int *frameSize, PacketQueue::Packet *pkt) const
- {
- int sampleCount;
- return this->decodeAudioAndSampleCount(ctx, samples, frameSize, &sampleCount, pkt);
- }
- int MediaPresenter::decodeAudioAndSampleCount(AVCodecContext *ctx, uint8_t **samples, int *frameSize, int *sampleCount, PacketQueue::Packet *pkt) const
- {
- const AudioSpec &spec = this->m_state->audio.spec;
- AVFrame *frame = av_frame_alloc();
- int ret;
- int gotFrame = 0;
- int totalSize = *frameSize;
- bool isDelayed = false;
- ret = Utils::decodeFrame(ctx, &pkt->packet, frame, &gotFrame);
- if (pkt->isNullPacket() && ctx->codec->capabilities & CODEC_CAP_DELAY)
- isDelayed = true;
- *frameSize = 0;
- if ((ret >= 0 || isDelayed) && gotFrame)
- {
- if (ctx->channels == spec.channelCount)
- {
- int dataSize;
- int outCount = totalSize / ctx->channels / av_get_bytes_per_sample(ctx->sample_fmt);
- *sampleCount = swr_convert(this->m_state->audio.audioConverter,
- samples,
- outCount,
- (const uint8_t**)frame->extended_data,
- frame->nb_samples);
- if (*sampleCount < 0)
- dataSize = 0;
- else
- dataSize = av_samples_get_buffer_size(nullptr, ctx->channels, frame->nb_samples, ctx->sample_fmt, 1);
- *frameSize = dataSize;
- }
- }
- if (frame)
- av_frame_free(&frame);
- return ret;
- }
- void MediaPresenter::flushPictureQueue()
- {
- MediaState *ms = this->m_state;
- QMutexLocker locker(&ms->videoFrames.data.lock.mutex);
- ms->videoFrames.data.rIndex = 0;
- ms->videoFrames.data.wIndex = 0;
- ms->videoFrames.data.size = 0;
- }
- void MediaPresenter::closeStreamComponent(unsigned int index, bool isAudio)
- {
- MediaState *ms = this->m_state;
- AVFormatContext *format = isAudio ? ms->audioFormat : ms->format;
- if (index >= format->nb_streams)
- return;
- AVCodecParameters *context = format->streams[index]->codecpar;
- switch (context->codec_type)
- {
- case AVMEDIA_TYPE_AUDIO:
- {
- Audio &audio = ms->audio;
- SPDIFEncoding &encoding = audio.spdifEncoding;
- audio.stream.queue.unlock();
- if (this->m_spdif.isOpened())
- {
- this->m_spdif.close();
- }
- else
- {
- BASS_Stop();
- BASS_Free();
- }
- audio.stream.queue.end();
- audio.stream.stream = nullptr;
- audio.stream.index = -1;
- audio.handle = 0;
- audio.tempo = 0;
- if (audio.audioConverter)
- swr_free(&audio.audioConverter);
- if (encoding.frame)
- av_frame_free(&encoding.frame);
- if (encoding.encoder)
- {
- avcodec_close(encoding.encoder);
- encoding.encoder = nullptr;
- }
- if (encoding.fifo)
- {
- av_audio_fifo_free(encoding.fifo);
- encoding.fifo = nullptr;
- }
- if (encoding.buffers)
- {
- av_freep(&encoding.buffers[0]);
- av_freep(&encoding.buffers);
- encoding.bufferSize = 0;
- }
- if (encoding.tmpBuffers)
- {
- av_freep(&encoding.tmpBuffers[0]);
- av_freep(&encoding.tmpBuffers);
- encoding.tmpBufferSize = 0;
- }
- if (audio.stream.ctx)
- avcodec_free_context(&audio.stream.ctx);
- break;
- }
- case AVMEDIA_TYPE_VIDEO:
- {
- VideoFrames &videoFrames = ms->videoFrames;
- Video &video = ms->video;
- video.threadQuit = true;
- videoFrames.data.lock.mutex.lock();
- videoFrames.data.lock.cond.wakeOne();
- videoFrames.data.lock.mutex.unlock();
- video.stream.queue.unlock();
- if (this->m_videoThread.isRunning())
- this->m_videoThread.wait();
- video.stream.queue.end();
- video.stream.stream = nullptr;
- video.stream.index = -1;
- if (video.assFrame)
- {
- this->deleteSurface(video.assFrame);
- video.assFrame = nullptr;
- }
- this->releasePictures();
- if (this->m_hwDecoder.isOpened())
- this->m_hwDecoder.close();
- if (video.stream.ctx)
- avcodec_free_context(&video.stream.ctx);
- break;
- }
- case AVMEDIA_TYPE_SUBTITLE:
- {
- Subtitle &subtitle = ms->subtitle;
- subtitle.threadQuit = true;
- subtitle.stream.queue.unlock();
- if (this->m_subtitleThread.isRunning())
- this->m_subtitleThread.wait();
- subtitle.stream.queue.end();
- subtitle.stream.stream = nullptr;
- subtitle.stream.index = -1;
- this->releaseSubtitles();
- if (subtitle.stream.ctx)
- avcodec_free_context(&subtitle.stream.ctx);
- break;
- }
- default:
- {
- break;
- }
- }
- }
- Stream* MediaPresenter::getStream(int index)
- {
- Stream *stream = nullptr;
- if (index == this->m_state->video.stream.index)
- stream = &this->m_state->video.stream;
- else if (index == this->m_state->audio.stream.index)
- stream = &this->m_state->audio.stream;
- else if (index == this->m_state->subtitle.stream.index)
- stream = &this->m_state->subtitle.stream;
- return stream;
- }
- AVHWAccel* MediaPresenter::existHWAccel(AVCodecID codecID) const
- {
- AVHWAccel *hwaccel = nullptr;
- while ((hwaccel = av_hwaccel_next(hwaccel)))
- {
- if (hwaccel->id == codecID)
- return hwaccel;
- }
- return nullptr;
- }
- AVHWAccel* MediaPresenter::findHWAccel(AVCodecID codecID) const
- {
- AVHWAccel *hwaccel = nullptr;
- while ((hwaccel = av_hwaccel_next(hwaccel)))
- {
- if (hwaccel->id == codecID && this->m_hwDecoder.isDecodable(hwaccel->pix_fmt))
- return hwaccel;
- }
- return nullptr;
- }
- const char* MediaPresenter::findProfileName(const AVProfile *profiles, int profile) const
- {
- if (profiles)
- {
- for (int i = 0; profiles[i].profile != FF_PROFILE_UNKNOWN; i++)
- {
- if (profiles[i].profile == profile)
- return profiles[i].name;
- }
- }
- return nullptr;
- }
- AVCodec* MediaPresenter::tryInternalHWDecoder(AVCodecContext *context, const QString &postFix) const
- {
- AVCodec *codec = av_codec_next(nullptr);
- while (codec)
- {
- if (codec->id == context->codec_id && QString::fromLatin1(codec->name).contains("_" + postFix))
- {
- if (avcodec_open2(context, codec, nullptr) == 0)
- return codec;
- else
- break;
- }
- codec = av_codec_next(codec);
- }
- return nullptr;
- }
- AVCodec* MediaPresenter::tryCrystalHDDecoder(AVCodecContext *context) const
- {
- return this->tryInternalHWDecoder(context, "crystalhd");
- }
- #if defined Q_OS_RASPBERRY_PI
- AVCodec *MediaPresenter::tryMMALDecoder(AVCodecContext *context) const
- {
- return this->tryInternalHWDecoder(context, "mmal");
- }
- #elif defined Q_OS_ANDROID
- AVCodec *MediaPresenter::tryMediaCodecDecoder(AVCodecContext *context) const
- {
- return this->tryInternalHWDecoder(context, "mediacodec");
- }
- #endif
- void MediaPresenter::getSPDIFParams(const AVCodecContext *context, int *sampleRate, int *channelCount, AVSampleFormat *format)
- {
- this->m_spdif.getParams(context, sampleRate, channelCount, format);
- if (this->m_userSPDIFSampleRate > 0)
- *sampleRate = this->m_userSPDIFSampleRate;
- }
- bool MediaPresenter::initAudio(const AVCodecContext *context)
- {
- MediaState *ms = this->m_state;
- Audio &audio = ms->audio;
- int sampleRate;
- int channelCount;
- AVSampleFormat format;
- if (this->m_spdif.isOpened())
- {
- this->getSPDIFParams(context, &sampleRate, &channelCount, &format);
- if (context->codec_id == AV_CODEC_ID_DTS)
- {
- if (context->profile == FF_PROFILE_DTS_HD_MA || context->profile == FF_PROFILE_DTS_HD_HRA)
- this->m_spdif.setHDRate(sampleRate * channelCount / 2);
- }
- this->m_spdif.setInterval(30);
- audio.spec.latency = this->m_spdif.getLatency();
- audio.spec.currentChannelCount = channelCount;
- this->m_spdif.getDeviceName(this->m_spdif.getDevice(), &this->m_detail.audioSPDIFOutputDevice);
- this->m_detail.audioOutputSampleRate = sampleRate;
- this->m_detail.audioOutputChannels = channelCount;
- this->m_detail.audioOutputBits = 16;
- this->m_detail.audioOutputType = "S/PDIF";
- }
- else
- {
- sampleRate = context->sample_rate;
- channelCount = context->channels;
- format = context->sample_fmt;
- if (!BASS_Init(this->m_audioDevice, sampleRate, BASS_DEVICE_LATENCY, nullptr, nullptr))
- return false;
- if (!BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 30))
- return false;
- if (!BASS_SetConfig(BASS_CONFIG_BUFFER, 200))
- return false;
- #ifdef Q_OS_IOS
- if (!BASS_SetConfig(BASS_CONFIG_IOS_MIXAUDIO, 0))
- return false;
- if (!BASS_SetConfig(BASS_CONFIG_IOS_NOCATEGORY, 1))
- return false;
- if (!BASS_SetConfigPtr(BASS_CONFIG_IOS_NOTIFY, (void*)this->m_iosNotify))
- return false;
- #endif
- DWORD flag;
- switch (format)
- {
- case AV_SAMPLE_FMT_U8:
- case AV_SAMPLE_FMT_U8P:
- flag = BASS_SAMPLE_8BITS;
- break;
- case AV_SAMPLE_FMT_S16:
- case AV_SAMPLE_FMT_S16P:
- flag = 0;
- break;
- case AV_SAMPLE_FMT_S32:
- case AV_SAMPLE_FMT_FLT:
- case AV_SAMPLE_FMT_DBL:
- case AV_SAMPLE_FMT_S32P:
- case AV_SAMPLE_FMT_FLTP:
- case AV_SAMPLE_FMT_DBLP:
- case AV_SAMPLE_FMT_S64:
- case AV_SAMPLE_FMT_S64P:
- flag = BASS_SAMPLE_FLOAT;
- break;
- default:
- return false;
- }
- BASS_INFO info;
- if (!BASS_GetInfo(&info))
- return false;
- audio.handle = BASS_Mixer_StreamCreate(sampleRate, info.speakers, flag);
- if (audio.handle == 0)
- return false;
- flag |= BASS_STREAM_DECODE;
- HSTREAM sourceStream = BASS_StreamCreate(sampleRate, channelCount, flag,
- MediaPresenter::audioCallback, this);
- if (sourceStream == 0)
- return false;
- BASS_FX_GetVersion();
- HSTREAM tempo = BASS_FX_TempoCreate(sourceStream, BASS_STREAM_DECODE | BASS_FX_FREESOURCE);
- if (tempo)
- {
- sourceStream = tempo;
- audio.tempo = sourceStream;
- }
- if (!BASS_Mixer_StreamAddChannel(audio.handle, sourceStream, BASS_MIXER_DOWNMIX | BASS_STREAM_AUTOFREE))
- return false;
- BASS_CHANNELINFO cinfo;
- if (!BASS_ChannelGetInfo(audio.handle, &cinfo))
- return false;
- audio.spec.latency = (info.latency * 2 + BASS_GetConfig(BASS_CONFIG_BUFFER) + BASS_GetConfig(BASS_CONFIG_UPDATEPERIOD)) / 1000.0;
- audio.spec.currentChannelCount = info.speakers;
- this->m_detail.audioInputSampleRate = sampleRate;
- this->m_detail.audioOutputSampleRate = cinfo.freq;
- this->m_detail.audioOutputChannels = cinfo.chans;
- if (IS_BIT_SET(cinfo.flags, BASS_SAMPLE_8BITS))
- {
- this->m_detail.audioOutputBits = 8;
- this->m_detail.audioOutputType = "U8";
- }
- else if (IS_BIT_SET(cinfo.flags, BASS_SAMPLE_FLOAT))
- {
- this->m_detail.audioOutputBits = 32;
- this->m_detail.audioOutputType = "FLT";
- }
- else
- {
- this->m_detail.audioOutputBits = 16;
- this->m_detail.audioOutputType = "S16";
- }
- }
- audio.spec.bytesPerSec = channelCount * sampleRate * av_get_bytes_per_sample(format);
- audio.spec.format = format;
- this->m_detail.audioInputSampleRate = sampleRate;
- return true;
- }
- bool MediaPresenter::openStreamComponent(unsigned int index, bool isAudio)
- {
- MediaState *ms = this->m_state;
- AVFormatContext *format = isAudio ? ms->audioFormat : ms->format;
- if (index >= format->nb_streams)
- return false;
- AVCodecContext *context = avcodec_alloc_context3(nullptr);
- if (avcodec_parameters_to_context(context, format->streams[index]->codecpar) < 0)
- {
- avcodec_free_context(&context);
- return false;
- }
- av_codec_set_pkt_timebase(context, format->streams[index]->time_base);
- AVCodec *codec = nullptr;
- AVCodecID codecID = context->codec_id;
- bool internalHWAccel = false;
- if (this->m_useHWDecoder && context->codec_type == AVMEDIA_TYPE_VIDEO)
- {
- codec = this->tryCrystalHDDecoder(context);
- if (!codec)
- {
- #if defined Q_OS_RASPBERRY_PI
- codec = this->tryMMALDecoder(context);
- #elif defined Q_OS_ANDROID
- codec = this->tryMediaCodecDecoder(context);
- #endif
- }
- if (codec)
- {
- internalHWAccel = true;
- }
- else
- {
- if (avcodec_parameters_to_context(context, format->streams[index]->codecpar) < 0)
- {
- avcodec_free_context(&context);
- return false;
- }
- av_codec_set_pkt_timebase(context, format->streams[index]->time_base);
- codecID = context->codec_id;
- }
- }
- if (!internalHWAccel)
- {
- codec = avcodec_find_decoder(codecID);
- if (!codec)
- return false;
- if (context->codec_type == AVMEDIA_TYPE_VIDEO)
- {
- context->get_buffer2 = MediaPresenter::getBuffer;
- context->get_format = MediaPresenter::getFormat;
- context->thread_safe_callbacks = 1;
- context->thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME;
- context->thread_count = 0;
- context->opaque = this;
- bool hwAccel = false;
- #if defined Q_OS_ANDROID
- hwAccel = true;
- #else
- hwAccel = this->existHWAccel(codecID) ? true : false;
- #endif
- if (this->m_useHWDecoder && hwAccel && this->m_hwDecoder.open(context))
- {
- context->thread_safe_callbacks = 0;
- context->thread_type &= ~FF_THREAD_FRAME;
- context->slice_flags |= SLICE_FLAG_ALLOW_FIELD;
- context->strict_std_compliance = FF_COMPLIANCE_STRICT;
- }
- }
- #if defined Q_OS_ANDROID
- if (!(context->codec_type == AVMEDIA_TYPE_VIDEO && this->m_hwDecoder.isOpened()))
- {
- #endif
- if (avcodec_open2(context, codec, nullptr) < 0)
- return false;
- #if defined Q_OS_ANDROID
- }
- #endif
- }
- const int bufSize = 128;
- char buf[bufSize] = {0, };
- QString codecName;
- QString profile = this->findProfileName(codec->profiles, context->profile);
- profile = profile.isEmpty() ? "" : " " + profile;
- codecName = QString("%1 (%2%3)").arg(QString(codec->name).toUpper()).arg(codec->long_name).arg(profile);
- switch (context->codec_type)
- {
- case AVMEDIA_TYPE_AUDIO:
- {
- Audio &audio = ms->audio;
- SPDIFEncoding &encoding = audio.spdifEncoding;
- AVCodecContext *audioCodec = context;
- QStringList sampleFMT = QString(av_get_sample_fmt_string(buf, bufSize, context->sample_fmt)).split(" ", QString::SkipEmptyParts);
- this->m_detail.audioCodec = codecName;
- this->m_detail.audioCodecSimple = QString(codec->name).toUpper() + profile;
- this->m_detail.audioInputType = QString(sampleFMT[0]).toUpper();
- this->m_detail.audioInputBits = sampleFMT[1].toInt();
- if (this->m_useSPDIF)
- {
- int sampleRate;
- int channelCount;
- AVSampleFormat format;
- bool opened = false;
- AVCodecContext *spdifCodec;
- AVCodecID spdifCodecID;
- if (this->isUsingSPDIFEncoding())
- {
- AVCodec *encodingCodec;
- uint64_t channelLayout;
- switch (this->m_SPIDFEncodingMethod)
- {
- case AnyVODEnums::SEM_AC3:
- spdifCodecID = AV_CODEC_ID_AC3;
- break;
- case AnyVODEnums::SEM_DTS:
- spdifCodecID = AV_CODEC_ID_DTS;
- break;
- default:
- return false;
- }
- encodingCodec = avcodec_find_encoder(spdifCodecID);
- encoding.encoder = avcodec_alloc_context3(encodingCodec);
- switch (this->m_SPIDFEncodingMethod)
- {
- case AnyVODEnums::SEM_AC3:
- encoding.encoder->bit_rate = 640000;
- channelLayout = av_get_default_channel_layout(encoding.encoder->channels);
- break;
- case AnyVODEnums::SEM_DTS:
- encoding.encoder->bit_rate = 768000;
- encoding.encoder->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
- channelLayout = AV_CH_LAYOUT_5POINT1;
- break;
- default:
- channelLayout = av_get_default_channel_layout(encoding.encoder->channels);
- break;
- }
- encoding.encoder->sample_fmt = encodingCodec->sample_fmts[0];
- encoding.encoder->sample_rate = 48000;
- encoding.encoder->channels = 6;
- encoding.encoder->channel_layout = channelLayout;
- encoding.encoder->time_base = (AVRational){ 1, encoding.encoder->sample_rate };
- if (avcodec_open2(encoding.encoder, encodingCodec, nullptr) < 0)
- return false;
- spdifCodec = encoding.encoder;
- audioCodec = spdifCodec;
- }
- else
- {
- spdifCodec = context;
- spdifCodecID = codecID;
- }
- this->getSPDIFParams(spdifCodec, &sampleRate, &channelCount, &format);
- opened = this->m_spdif.open(spdifCodecID, MediaPresenter::audioSPDIFCallback, sampleRate, channelCount, 500, this);
- if (this->m_useSPDIF != opened)
- this->showOptionDesc(tr("S/PDIF 출력 초기화를 실패 하였습니다. PCM 출력으로 전환합니다."));
- this->m_useSPDIF = opened;
- }
- if (!this->initAudio(audioCodec))
- {
- if (this->m_spdif.isOpened())
- this->m_spdif.close();
- else
- BASS_Free();
- return false;
- }
- audio.spec.channelCount = context->channels;
- this->m_detail.audioInputChannels = audio.spec.channelCount;
- this->volume(this->m_volume);
- this->mute(this->m_isMute);
- if (this->m_spdif.isOpened())
- {
- if (this->isUsingSPDIFEncoding())
- {
- uint64_t inputLayout = av_get_default_channel_layout(context->channels);
- uint64_t outputLayout = audioCodec->channel_layout;
- AVSampleFormat srcFormat = context->sample_fmt;
- AVSampleFormat destFormat = audioCodec->sample_fmt;
- int inputSampleRate = context->sample_rate;
- int outputSampleRate = audioCodec->sample_rate;
- int outputChannels = audioCodec->channels;
- int frameSize = audioCodec->frame_size;
- audio.audioConverter = swr_alloc_set_opts(nullptr, outputLayout, destFormat, outputSampleRate, inputLayout, srcFormat, inputSampleRate, 0, nullptr);
- if (audio.audioConverter == nullptr)
- return false;
- if (swr_init(audio.audioConverter) < 0)
- return false;
- encoding.fifo = av_audio_fifo_alloc(destFormat, outputChannels, 1);
- if (encoding.fifo == nullptr)
- return false;
- encoding.bufferSize = av_samples_alloc_array_and_samples(&encoding.buffers, nullptr, outputChannels, frameSize, destFormat, 1);
- if (encoding.bufferSize < 0)
- return false;
- encoding.tmpBufferSize = av_samples_alloc_array_and_samples(&encoding.tmpBuffers, nullptr, outputChannels, frameSize * SPDIF_ENCODING_TMP_BUFFER_SIZE, destFormat, 1);
- if (encoding.tmpBufferSize < 0)
- return false;
- encoding.frame = av_frame_alloc();
- if (encoding.frame == nullptr)
- return false;
- encoding.frame->format = destFormat;
- encoding.frame->nb_samples = frameSize;
- encoding.frame->channel_layout = audioCodec->channel_layout;
- avcodec_fill_audio_frame(encoding.frame, outputChannels, destFormat, encoding.buffers[0], encoding.bufferSize, 1);
- }
- }
- else
- {
- uint64_t layout = av_get_default_channel_layout(context->channels);
- AVSampleFormat srcFormat = context->sample_fmt;
- AVSampleFormat destFormat = av_get_packed_sample_fmt(context->sample_fmt);
- int sampleRate = context->sample_rate;
- audio.audioConverter = swr_alloc_set_opts(nullptr, layout, destFormat, sampleRate, layout, srcFormat, sampleRate, 0, nullptr);
- if (audio.audioConverter == nullptr)
- return false;
- if (swr_init(audio.audioConverter) < 0)
- return false;
- if (this->m_audioEffect.useNormalizer)
- this->initNormalizer();
- if (this->m_audioEffect.useEqualizer)
- this->initEqualizer();
- if (this->m_audioEffect.useLowerMusic)
- this->initLowerMusic();
- if (this->m_audioEffect.useLowerVoice)
- this->initLowerVoice();
- if (this->m_audioEffect.useHigherVoice)
- this->initHigherVoice();
- }
- audio.stream.index = index;
- audio.stream.stream = format->streams[index];
- audio.stream.ctx = context;
- audio.bufferSize = 0;
- audio.bufferIndex = 0;
- audio.diffAvgCoef = exp(log(0.01 / AUDIO_DIFF_AVG_NB));
- audio.diffAvgCount = 0;
- audio.diffThreshold = 2.0 * THRESHOLD_FACTOR / context->sample_rate;
- memset(&audio.packet, 0, sizeof(audio.packet));
- audio.stream.queue.init();
- if (audio.stream.stream->start_time != AV_NOPTS_VALUE)
- audio.stream.clockOffset = av_q2d(audio.stream.stream->time_base) * audio.stream.stream->start_time;
- break;
- }
- case AVMEDIA_TYPE_VIDEO:
- {
- Video &video = ms->video;
- FrameTimer &timer = ms->frameTimer;
- AVPixelFormat pixFormat;
- if (this->m_hwDecoder.isOpened())
- {
- AVHWAccel *hwaccel = this->findHWAccel(codecID);
- QString desc;
- QString decoder;
- this->m_hwDecoder.getDecoderDesc(&desc);
- if (hwaccel)
- decoder = QString("%1 (%2)").arg(hwaccel->name).arg(desc);
- else
- decoder = QString("%1").arg(desc);
- this->m_detail.videoHWDecoder = decoder;
- pixFormat = this->m_hwDecoder.getFormat();
- }
- else
- {
- pixFormat = context->pix_fmt;
- }
- QStringList pixFMT = QString(av_get_pix_fmt_string(buf, bufSize, pixFormat)).split(" ", QString::SkipEmptyParts);
- this->m_detail.videoCodec = codecName;
- #if defined Q_OS_ANDROID || defined Q_OS_MAC
- if (!this->m_hwDecoder.isOpened())
- {
- #endif
- this->m_detail.videoInputType = pixFMT[0].toUpper();
- this->m_detail.videoInputBits = pixFMT[2].toInt();
- if (this->isUseGPUConvert(pixFormat))
- this->m_format = pixFormat;
- else
- this->m_format = this->getCompatibleFormat(pixFormat);
- #if defined Q_OS_ANDROID || defined Q_OS_MAC
- }
- #endif
- this->m_detail.videoInputSize = QSize(context->width, context->height);
- pixFMT = QString(av_get_pix_fmt_string(buf, bufSize, this->m_format)).split(" ", QString::SkipEmptyParts);
- this->m_detail.videoOutputType = pixFMT[0].toUpper();
- this->m_detail.videoOutputBits = pixFMT[2].toInt();
- if (this->m_playData.totalFrame <= 0)
- this->m_playData.totalFrame = (int)format->streams[index]->nb_frames;
- video.stream.index = index;
- video.stream.stream = format->streams[index];
- video.stream.ctx = context;
- timer.timer = this->getAbsoluteClock();
- timer.lastDelay = 0.04;
- video.stream.queue.init();
- video.threadQuit = false;
- this->m_videoThread.start();
- video.assFrame = this->createSurface(context->width, context->height, AV_PIX_FMT_BGR32);
- this->m_assParser.setFrameSize(context->width, context->height);
- this->m_avParser.setFrameSize(QSize(context->width, context->height));
- this->m_deinterlacer.setCodec(video.stream.ctx, pixFormat, video.stream.stream->time_base);
- this->m_filterGraph.setCodec(video.stream.ctx, pixFormat, this->m_format, video.stream.stream->time_base);
- video.pixFormat = pixFormat;
- #ifndef Q_OS_MAC
- int maxThreads = QThread::idealThreadCount() + 1;
- if (maxThreads <= 0)
- maxThreads = 1;
- omp_set_num_threads(maxThreads);
- #endif
- break;
- }
- case AVMEDIA_TYPE_SUBTITLE:
- {
- Subtitle &subtitle = ms->subtitle;
- if (!this->existSubtitle())
- this->m_detail.subtitleCodec = QString(SUBTITLE_CODEC_FORMAT).arg(QString(codec->name).toUpper()).arg(codec->long_name);
- subtitle.stream.index = index;
- subtitle.stream.stream = format->streams[index];
- subtitle.stream.ctx = context;
- subtitle.stream.queue.init();
- QString header;
- if (context->subtitle_header_size)
- header = QString::fromUtf8((char*)context->subtitle_header, context->subtitle_header_size);
- this->m_assParser.setHeader(header);
- subtitle.threadQuit = false;
- this->m_subtitleThread.start();
- break;
- }
- default:
- {
- break;
- }
- }
- return true;
- }
- double MediaPresenter::getAspectRatioByVR(float widthScale, int codecWidth, float heightScale, int codecHeight) const
- {
- if (this->m_vrInputSource == AnyVODEnums::VRI_NONE)
- return ((double)codecWidth * widthScale) / ((double)codecHeight * heightScale);
- else
- return ((double)codecHeight * heightScale) / ((double)codecWidth * widthScale);
- }
- void MediaPresenter::computeFrameSize()
- {
- MediaState *ms = this->m_state;
- if (ms)
- {
- FrameSize &frameSize = ms->frameSize;
- AVCodecContext *codec = ms->video.stream.ctx;
- int orgHeight = this->m_height;
- int orgWidth = this->m_width;
- int codecHeight = codec->height;
- int codecWidth = codec->width;
- int height = 0;
- int width = 0;
- double rot = 0.0;
- switch (this->m_screenRotationDegree)
- {
- case AnyVODEnums::SRD_90:
- rot = 90.0;
- break;
- case AnyVODEnums::SRD_270:
- rot = 270.0;
- break;
- default:
- break;
- }
- if (Utils::isPortrait(this->m_rotation + rot))
- std::swap(orgWidth, orgHeight);
- if (this->m_userRatio.use && this->m_userRatio.fullscreen)
- {
- height = orgHeight;
- width = orgWidth;
- }
- else
- {
- double aspectRatio = 0.0;
- float widthScale = 1.0f;
- float heightScale = 1.0f;
- if (this->m_use3DFull && this->m_3dMethod != AnyVODEnums::V3M_NONE)
- {
- if (this->isSideBySide())
- {
- widthScale = 0.5f;
- heightScale = 1.0f;
- }
- else
- {
- widthScale = 1.0f;
- heightScale = 0.5f;
- }
- }
- if (this->m_vrInputSource != AnyVODEnums::VRI_NONE)
- widthScale *= 2.0f;
- if (this->m_userRatio.use)
- aspectRatio = this->m_userRatio.getRatio();
- else if (codec->sample_aspect_ratio.num == 0)
- aspectRatio = 0.0;
- else
- aspectRatio = av_q2d(codec->sample_aspect_ratio) * this->getAspectRatioByVR(widthScale, codecWidth, heightScale, codecHeight);
- if (aspectRatio <= 0.0)
- aspectRatio = this->getAspectRatioByVR(widthScale, codecWidth, heightScale, codecHeight);
- if (this->m_vrInputSource == AnyVODEnums::VRI_NONE)
- {
- height = orgHeight;
- width = ((int)rint(height * aspectRatio)) & -3;
- if (width > orgWidth)
- {
- width = orgWidth;
- height = ((int)rint(width / aspectRatio)) & -3;
- }
- }
- else
- {
- width = orgWidth;
- height = ((int)rint(width * aspectRatio)) & -3;
- if (height > orgHeight)
- {
- height = orgHeight;
- width = ((int)rint(height / aspectRatio)) & -3;
- }
- }
- }
- frameSize.height = height;
- frameSize.width = width;
- this->m_detail.videoOutputSize = QSize(frameSize.width, frameSize.height);
- #if defined Q_OS_MOBILE
- if (!this->m_captureMode &&
- this->m_vrInputSource == AnyVODEnums::VRI_NONE &&
- this->m_useSubtitleCacheMode &&
- this->m_font.willBeInvalidate(this->m_fontOutlineSize))
- {
- ShaderCompositer dummyShader;
- VideoPicture dummyVP;
- bool isPaused = ms->pause.pause;
- if (!isPaused)
- this->pause();
- this->m_font.setCacheMode(true);
- this->drawDetail(dummyShader, &dummyVP);
- this->m_font.setCacheMode(false);
- if (!isPaused)
- this->resume();
- }
- #endif
- if (!this->m_scheduleRecomputeSubtitleSize)
- this->computeSubtitleSize();
- }
- }
- void MediaPresenter::computeSubtitleSize()
- {
- MediaState *ms = this->m_state;
- if (ms)
- {
- int height = ms->frameSize.height;
- int prevSize = this->m_subtitleFontSize;
- this->m_subtitleFontSize = height * 0.064f * this->m_subtitleSize;
- if (this->m_subtitleFontSize > 0 && this->m_subtitleFontSize != prevSize)
- {
- int fontRatio;
- #if defined Q_OS_MOBILE
- fontRatio = 24;
- if (this->m_vrInputSource != AnyVODEnums::VRI_NONE)
- this->m_subtitleFontSize *= 2;
- #else
- fontRatio = 12;
- #endif
- this->m_subtitleFont.getQFont().setFamily(this->m_fontFamily);
- this->m_subtitleFont.getQFont().setPixelSize(this->m_subtitleFontSize);
- this->m_subtitleOutlineSize = this->m_subtitleFontSize / fontRatio;
- if (this->m_subtitleOutlineSize <= 0)
- this->m_subtitleOutlineSize = 1 * this->m_devicePixelRatio;
- else if (this->m_subtitleOutlineSize > this->m_subtitleMaxOutlineSize)
- this->m_subtitleOutlineSize = this->m_subtitleMaxOutlineSize;
- #if defined Q_OS_MOBILE
- uint32_t duration = this->getDuration() * KILO / 3;
- if (!this->m_captureMode &&
- this->m_vrInputSource == AnyVODEnums::VRI_NONE &&
- this->m_useSubtitleCacheMode && duration > 0 && this->existSubtitle() &&
- this->m_subtitleFont.willBeInvalidate(this->m_subtitleOutlineSize))
- {
- ShaderCompositer dummyShader;
- VideoPicture dummyVP;
- const int gap = 500;
- bool isPaused = ms->pause.pause;
- if (!isPaused)
- this->pause();
- this->m_subtitleFont.setCacheMode(true);
- for (dummyVP.time = 0; dummyVP.time < duration; dummyVP.time += gap)
- this->drawSubtitles(dummyShader, &dummyVP);
- this->m_subtitleFont.setCacheMode(false);
- if (!isPaused)
- this->resume();
- }
- #endif
- }
- }
- }
- const QVector<ChapterInfo>& MediaPresenter::getChapters() const
- {
- return this->m_chapters;
- }
- int MediaPresenter::decodingInterruptCallback(void *userData)
- {
- MediaState *state = (MediaState*)userData;
- return state && state->quit;
- }
- void MediaPresenter::seek()
- {
- MediaState *ms = this->m_state;
- Seek &seek = ms->seek;
- Video &video = ms->video;
- Audio &audio = ms->audio;
- Subtitle &subtitle = ms->subtitle;
- int index = -1;
- int64_t seekTarget = seek.pos;
- int64_t seekTargetAudio = seek.pos;
- if (video.stream.index >= 0 && !this->isAudio())
- index = video.stream.index;
- else if (audio.stream.index >= 0)
- index = audio.stream.index;
- else if (subtitle.stream.index >= 0)
- index = subtitle.stream.index;
- if (index >= 0)
- {
- AVRational r = {1, AV_TIME_BASE};
- seekTarget = av_rescale_q(seekTarget, r, ms->format->streams[index]->time_base);
- if (ms->audioFormat)
- seekTargetAudio = av_rescale_q(seekTargetAudio, r, ms->audioFormat->streams[audio.stream.index]->time_base);
- }
- int ret = av_seek_frame(ms->format, index, seekTarget, seek.flags);
- if (ret >= 0)
- {
- if (ms->audioFormat)
- av_seek_frame(ms->audioFormat, audio.stream.index, seekTargetAudio, seek.flags);
- if (audio.stream.index >= 0)
- {
- audio.stream.queue.flush();
- audio.stream.queue.putFlushPacket();
- }
- if (video.stream.index >= 0)
- {
- video.stream.queue.flush();
- video.stream.queue.putFlushPacket();
- }
- if (subtitle.stream.index >= 0)
- {
- subtitle.stream.queue.flush();
- subtitle.stream.queue.putFlushPacket();
- }
- }
- seek.request = false;
- if (this->m_audioSubtitleCallback.callback && this->existAudioSubtitle())
- {
- if (this->m_showSubtitle)
- {
- Lyrics tmp;
- bool found = false;
- if (this->m_lrcParser.isExist())
- found = this->m_lrcParser.get(seek.time * 1000, &tmp);
- if (!found)
- this->m_audioSubtitleCallback.callback(this->m_audioSubtitleCallback.userData, QVector<Lyrics>());
- }
- else
- {
- this->m_audioSubtitleCallback.callback(this->m_audioSubtitleCallback.userData, QVector<Lyrics>());
- }
- }
- if (seek.pauseSeeking && ret >= 0)
- this->resume();
- }
- bool MediaPresenter::recover(double clock)
- {
- QMutexLocker locker(&this->m_controlLocker);
- bool isPaused;
- QString subtitlePath = this->m_subtitleFilePath;
- QString audioPath = this->m_audioPath;
- ExtraPlayData playData = this->m_playData;
- Range repeatRange = this->m_repeatRange;
- float subtitleSync = this->m_subtitleSync;
- bool result = false;
- bool isTmpSubtitle = false;
- SUBTITLE_TYPE prevSubtitleType = this->m_subtitleType;
- bool isRemoteFile = this->m_isRemoteFile;
- if (this->m_state)
- isPaused = this->m_state->pause.pause;
- else
- isPaused = false;
- if (this->m_isRemoteProtocol)
- {
- if (this->m_subtitleType != ST_YOUTUBE && this->m_subtitleType != ST_AV && this->m_subtitleType != ST_ASS)
- {
- QString tmpFilePath = QDir::tempPath();
- QString ext = QFileInfo(subtitlePath).suffix();
- Utils::appendDirSeparator(&tmpFilePath);
- tmpFilePath += "XXXXXX.";
- tmpFilePath += ext;
- QTemporaryFile tmpFile(tmpFilePath);
- tmpFile.setAutoRemove(false);
- if (tmpFile.open())
- {
- QString filePath = tmpFile.fileName();
- tmpFile.close();
- switch (this->m_subtitleType)
- {
- case ST_SAMI:
- this->m_samiParser.save(filePath, 0.0);
- break;
- case ST_SRT:
- this->m_srtParser.save(filePath, 0.0);
- break;
- case ST_LRC:
- this->m_lrcParser.save(filePath, 0.0);
- break;
- default:
- break;
- }
- isTmpSubtitle = true;
- subtitlePath = filePath;
- }
- }
- }
- this->stop();
- this->m_playData = playData;
- this->m_repeatRange = repeatRange;
- this->m_subtitleSync = subtitleSync;
- this->m_audioPath = audioPath;
- this->m_isRemoteFile = isRemoteFile;
- if (this->play())
- {
- if (!subtitlePath.isEmpty())
- this->openSubtitle(subtitlePath, prevSubtitleType == ST_YOUTUBE);
- if (isPaused)
- this->pause();
- if (isTmpSubtitle)
- {
- QFile f(subtitlePath);
- f.remove();
- }
- this->seekStream(clock, 0.0, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
- result = true;
- }
- if (this->m_recoverCallback.callback)
- this->m_recoverCallback.callback(this->m_recoverCallback.userData);
- return result;
- }
- bool MediaPresenter::isUseAudioPath() const
- {
- return !this->m_audioPath.isEmpty();
- }
- void MediaPresenter::closeStream()
- {
- MediaState *ms = this->m_state;
- if (ms)
- {
- if (this->m_readThread.isRunning())
- this->m_readThread.wait();
- if (ms->video.stream.index >= 0)
- {
- this->closeStreamComponent(ms->video.stream.index, false);
- this->m_subtitleFontSize = 0;
- }
- if (ms->audio.stream.index >= 0)
- this->closeStreamComponent(ms->audio.stream.index, this->isUseAudioPath());
- if (ms->subtitle.stream.index >= 0)
- this->closeStreamComponent(ms->subtitle.stream.index, false);
- if (ms->imageYUV420PConverter)
- sws_freeContext(ms->imageYUV420PConverter);
- if (ms->imageRGBConverter)
- sws_freeContext(ms->imageRGBConverter);
- if (ms->format)
- avformat_close_input(&ms->format);
- if (ms->audioFormat)
- avformat_close_input(&ms->audioFormat);
- this->m_audioPath.clear();
- this->m_assParser.deInit();
- this->m_chapters.clear();
- this->m_cueParser.close();
- this->m_refreshThread.stop();
- delete this->m_state;
- this->m_state = nullptr;
- }
- this->m_subtitleSync = 0.0;
- }
- void MediaPresenter::useHWDecoder(bool enable)
- {
- bool prev = this->m_useHWDecoder;
- this->changeUseHWDecoder(enable);
- if (prev != enable)
- {
- if (this->isEnabledVideo())
- this->recover(this->getMasterClock());
- }
- }
- bool MediaPresenter::isUseHWDecoder() const
- {
- return this->m_useHWDecoder;
- }
- bool MediaPresenter::isOpenedHWDecoder() const
- {
- return this->m_hwDecoder.isOpened();
- }
- void MediaPresenter::changeUseHWDecoder(bool enable)
- {
- this->m_useHWDecoder = enable;
- }
- void MediaPresenter::useLowQualityMode(bool enable)
- {
- bool prev = this->m_useLowQualityMode;
- this->m_useLowQualityMode = enable;
- if (prev != enable)
- {
- if (this->isEnabledVideo())
- this->recover(this->getMasterClock());
- }
- }
- bool MediaPresenter::isUseLowQualityMode() const
- {
- return this->m_useLowQualityMode;
- }
- void MediaPresenter::useSPDIF(bool enable)
- {
- this->m_useSPDIF = enable;
- this->resetAudioStream();
- }
- bool MediaPresenter::isUseSPDIF() const
- {
- return this->m_useSPDIF;
- }
- bool MediaPresenter::isOpenedSPDIF() const
- {
- return this->m_spdif.isOpened();
- }
- bool MediaPresenter::isSPDIFAvailable() const
- {
- return this->m_spdif.isAvailable();
- }
- void MediaPresenter::setSPDIFEncodingMethod(AnyVODEnums::SPDIFEncodingMethod method)
- {
- this->m_SPIDFEncodingMethod = method;
- if (this->m_spdif.isOpened())
- this->resetAudioStream();
- }
- AnyVODEnums::SPDIFEncodingMethod MediaPresenter::getSPDIFEncodingMethod() const
- {
- return this->m_SPIDFEncodingMethod;
- }
- bool MediaPresenter::isUsingSPDIFEncoding() const
- {
- return this->m_SPIDFEncodingMethod != AnyVODEnums::SEM_NONE;
- }
- void MediaPresenter::setScreenRotationDegree(AnyVODEnums::ScreenRotationDegree degree)
- {
- this->m_screenRotationDegree = degree;
- this->computeFrameSize();
- }
- AnyVODEnums::ScreenRotationDegree MediaPresenter::getScreenRotationDegree() const
- {
- return this->m_screenRotationDegree;
- }
- void MediaPresenter::use3DFull(bool enable)
- {
- this->m_use3DFull = enable;
- this->computeFrameSize();
- }
- bool MediaPresenter::isUse3DFull() const
- {
- return this->m_use3DFull;
- }
- void MediaPresenter::usePBO(bool enable)
- {
- this->m_usePBO = enable;
- }
- bool MediaPresenter::isUsePBO() const
- {
- return this->m_usePBO;
- }
- bool MediaPresenter::isUsingPBO(AVPixelFormat format) const
- {
- return this->isUsePBO() && this->isUsablePBO(format);
- }
- QSize MediaPresenter::getSize() const
- {
- return QSize(this->m_width, this->m_height);
- }
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Waddress"
- bool MediaPresenter::isUsablePBO(AVPixelFormat format) const
- {
- #if defined Q_OS_MOBILE
- (void)format;
- return false;
- #else
- return !this->isUseGPUConvert(format) && (GL_PREFIX glBindBufferARB != nullptr) && (GL_PREFIX glBufferDataARB != nullptr) && (GL_PREFIX glMapBufferARB != nullptr) && (GL_PREFIX glUnmapBufferARB != nullptr);
- #endif
- }
- #pragma GCC diagnostic pop
- void MediaPresenter::setUserSPDIFSampleRate(int sampleRate)
- {
- this->m_userSPDIFSampleRate = sampleRate;
- if (this->m_useSPDIF)
- this->useSPDIF(this->m_useSPDIF);
- }
- int MediaPresenter::getUserSPDIFSampleRate() const
- {
- return this->m_userSPDIFSampleRate;
- }
- void MediaPresenter::releaseSubtitles()
- {
- MediaState *ms = this->m_state;
- SubtitleFrames &frames = ms->subtitleFrames;
- frames.lock.lock();
- for (int i = 0; i < frames.items.count(); i++)
- avsubtitle_free(&frames.items[i].subtitle);
- frames.items.clear();
- frames.lock.unlock();
- }
- void MediaPresenter::releasePictures()
- {
- MediaState *ms = this->m_state;
- if (!ms)
- return;
- VideoFrames &frames = ms->videoFrames;
- for (int i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
- {
- VideoPicture *vp = &frames.queue[i];
- if (vp && vp->surface)
- {
- this->deleteSurface(vp->surface);
- *vp = VideoPicture();
- }
- }
- if (frames.audioPicture.surface)
- {
- this->deleteSurface(frames.audioPicture.surface);
- frames.audioPicture = VideoPicture();
- }
- if (frames.prevPicture.surface)
- {
- this->deleteSurface(frames.prevPicture.surface);
- frames.prevPicture = VideoPicture();
- }
- }
- SyncType MediaPresenter::getRecommandSyncType() const
- {
- if (this->m_state->audio.stream.index >= 0)
- return SYNC_AUDIO_MASTER;
- else if (this->m_state->video.stream.index >= 0)
- return SYNC_VIDEO_MASTER;
- else
- return SYNC_EXTERNAL_MASTER;
- }
- bool MediaPresenter::openAudioStream(int *ret)
- {
- AVFormatContext *format = nullptr;
- MediaState *ms = this->m_state;
- QString filePath = this->m_audioPath;
- int audioIndex = -1;
- format = avformat_alloc_context();
- if (!format)
- return false;
- format->interrupt_callback.callback = MediaPresenter::decodingInterruptCallback;
- format->interrupt_callback.opaque = ms;
- if (avformat_open_input(&format, Utils::convertPathToFileSystemRepresentation(filePath), nullptr, nullptr) != 0)
- {
- avformat_close_input(&format);
- return false;
- }
- ms->audioFormat = format;
- if (avformat_find_stream_info(format, nullptr) < 0)
- return false;
- this->m_audioStreamInfo.clear();
- for (unsigned int i = 0; i < format->nb_streams; i++)
- {
- AVCodecParameters *context = format->streams[i]->codecpar;
- AVDictionary *meta = format->streams[i]->metadata;
- AVDictionaryEntry *entry;
- QString desc;
- QString lang;
- entry = av_dict_get(meta, "language", nullptr, AV_DICT_IGNORE_SUFFIX);
- if (entry)
- lang = QString::fromLocal8Bit(entry->value).toUpper();
- AVCodec *codec = avcodec_find_decoder(context->codec_id);
- if (codec)
- desc = QString("%1 %2").arg(codec->long_name).arg(this->findProfileName(codec->profiles, context->profile));
- if (!lang.isEmpty())
- desc = lang + ", " + desc;
- switch (context->codec_type)
- {
- case AVMEDIA_TYPE_AUDIO:
- {
- AudioStreamInfo info;
- info.index = i;
- info.name = QString("%1, %2 Channels").arg(desc).arg(context->channels);
- this->m_audioStreamInfo.append(info);
- break;
- }
- default:
- {
- break;
- }
- }
- }
- if (this->m_audioStreamInfo.count() > 0)
- {
- if (this->m_lastAudioStream == -1 || this->m_lastAudioStream >= (int)format->nb_streams ||
- format->streams[this->m_lastAudioStream]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
- {
- audioIndex = this->m_audioStreamInfo[0].index;
- this->m_lastAudioStream = audioIndex;
- }
- else
- {
- audioIndex = this->m_lastAudioStream;
- }
- }
- *ret = audioIndex;
- return true;
- }
- bool MediaPresenter::openStream()
- {
- MediaState *ms = new MediaState;
- int videoIndex = -1;
- int audioIndex = -1;
- int subtitleIndex = -1;
- AVFormatContext *format = nullptr;
- QString filePath;
- QFileInfo fileInfo(this->m_filePath);
- this->m_state = ms;
- ms->video.stream.index = -1;
- ms->audio.stream.index = -1;
- ms->subtitle.stream.index = -1;
- this->m_assParser.init();
- if (fileInfo.suffix().toLower() == "cue" && this->m_cueParser.open(this->m_filePath))
- {
- this->m_cueParser.getFilePath(&filePath);
- this->m_cueParser.getChapters(&this->m_chapters);
- filePath = fileInfo.absolutePath() + QDir::separator() + filePath;
- }
- else
- {
- filePath = this->m_filePath;
- }
- filePath = filePath.replace("mms://", "mmst://", Qt::CaseInsensitive);
- AVInputFormat *inputFormat = nullptr;
- #if !defined Q_OS_ANDROID && !defined Q_OS_IOS
- if (Utils::determinDevice(filePath))
- {
- QString format = Utils::getDeviceType(filePath);
- inputFormat = av_find_input_format(format.toUtf8());
- if (inputFormat)
- filePath = Utils::getDevicePath(filePath);
- }
- #endif
- format = avformat_alloc_context();
- if (!format)
- return false;
- format->interrupt_callback.callback = MediaPresenter::decodingInterruptCallback;
- format->interrupt_callback.opaque = ms;
- if (avformat_open_input(&format, Utils::convertPathToFileSystemRepresentation(filePath), inputFormat, nullptr) != 0)
- {
- avformat_close_input(&format);
- return false;
- }
- ms->format = format;
- if (avformat_find_stream_info(format, nullptr) < 0)
- return false;
- AVInputFormat *iformat = format->iformat;
- if (iformat)
- this->m_detail.fileFormat = QString("%1 (%2)").arg(QString(iformat->name).toUpper(), iformat->long_name);
- for (unsigned int i = 0; i < format->nb_chapters; i++)
- {
- AVChapter *chapter = format->chapters[i];
- double base = av_q2d(chapter->time_base);
- ChapterInfo info;
- AVDictionaryEntry *entry = av_dict_get(chapter->metadata, "title", nullptr, AV_DICT_IGNORE_SUFFIX);
- info.start = base * chapter->start;
- info.end = base * chapter->end;
- if (entry)
- info.desc = QString::fromUtf8(entry->value);
- this->m_chapters.push_back(info);
- }
- int subtitleNum = 1;
- for (unsigned int i = 0; i < format->nb_streams; i++)
- {
- AVCodecParameters *context = format->streams[i]->codecpar;
- AVDictionary *meta = format->streams[i]->metadata;
- AVDictionaryEntry *entry;
- QString desc;
- QString lang;
- entry = av_dict_get(meta, "language", nullptr, AV_DICT_IGNORE_SUFFIX);
- if (entry)
- lang = QString::fromLocal8Bit(entry->value).toUpper();
- AVCodec *codec = avcodec_find_decoder(context->codec_id);
- if (codec)
- desc = QString("%1 %2").arg(codec->long_name).arg(this->findProfileName(codec->profiles, context->profile));
- if (!lang.isEmpty())
- desc = lang + ", " + desc;
- switch (context->codec_type)
- {
- case AVMEDIA_TYPE_VIDEO:
- {
- if (videoIndex < 0)
- videoIndex = i;
- if (this->isAudio() && !this->m_showAlbumJacket)
- videoIndex = -1;
- if (Utils::zeroDouble(this->m_rotation) <= 0.0)
- {
- QString rotation;
- entry = av_dict_get(meta, "rotate", nullptr, AV_DICT_MATCH_CASE);
- if (entry)
- rotation = QString::fromLocal8Bit(entry->value);
- this->m_rotation = rotation.toDouble();
- }
- break;
- }
- case AVMEDIA_TYPE_AUDIO:
- {
- AudioStreamInfo info;
- info.index = i;
- info.name = QString("%1, %2 Channels").arg(desc).arg(context->channels);
- this->m_audioStreamInfo.append(info);
- break;
- }
- case AVMEDIA_TYPE_SUBTITLE:
- {
- SubtitleStreamInfo info;
- info.index = i;
- info.name = QString("%1 (%2)").arg(desc).arg(subtitleNum);
- subtitleNum++;
- this->m_subtitleStreamInfo.append(info);
- break;
- }
- case AVMEDIA_TYPE_ATTACHMENT:
- {
- switch (context->codec_id)
- {
- case AV_CODEC_ID_OTF:
- case AV_CODEC_ID_TTF:
- {
- AVDictionaryEntry *fileName = av_dict_get(meta, "filename", nullptr, 0);
- if (fileName && fileName->value)
- this->m_assParser.addFont(fileName->value, context->extradata, context->extradata_size);
- break;
- }
- default:
- {
- break;
- }
- }
- break;
- }
- default:
- {
- break;
- }
- }
- }
- if (this->m_audioStreamInfo.count() > 0)
- {
- if (this->m_lastAudioStream == -1 || this->m_lastAudioStream >= (int)format->nb_streams ||
- format->streams[this->m_lastAudioStream]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
- {
- audioIndex = this->m_audioStreamInfo[0].index;
- this->m_lastAudioStream = audioIndex;
- }
- else
- {
- audioIndex = this->m_lastAudioStream;
- }
- }
- if (this->m_subtitleStreamInfo.count() > 0)
- {
- if (this->m_lastSubtitleStream == -1 || this->m_lastSubtitleStream >= (int)format->nb_streams ||
- format->streams[this->m_lastSubtitleStream]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
- {
- subtitleIndex = this->m_subtitleStreamInfo[0].index;
- this->m_lastSubtitleStream = subtitleIndex;
- }
- else
- {
- subtitleIndex = this->m_lastSubtitleStream;
- }
- }
- if (this->isUseAudioPath())
- {
- int retry = 3;
- bool success = false;
- while (retry --> 0)
- {
- if (this->openAudioStream(&audioIndex))
- {
- success = true;
- break;
- }
- }
- if (!success)
- return false;
- }
- this->m_font.getQFont().setFamily(this->m_fontFamily);
- this->m_font.getQFont().setPixelSize(this->m_fontSize);
- if (this->isRemoteFile() && this->isAudio())
- videoIndex = -1;
- if (videoIndex >= 0)
- {
- if (this->openStreamComponent(videoIndex, false))
- this->computeFrameSize();
- else
- return false;
- }
- if (audioIndex >= 0)
- {
- bool success = this->openStreamComponent(audioIndex, this->isUseAudioPath());
- if (!success)
- {
- audioIndex = -1;
- if (this->isAudio())
- return false;
- }
- }
- if (ms->video.stream.index < 0 && ms->audio.stream.index < 0)
- return false;
- if (subtitleIndex >= 0)
- this->openStreamComponent(subtitleIndex, false);
- if (this->m_assParser.isExist() && !this->m_subtitleFilePath.isEmpty())
- {
- QFileInfo f(this->m_subtitleFilePath);
- if (f.exists())
- this->m_assParser.open(this->m_subtitleFilePath);
- }
- this->m_assParser.setDefaultFont(this->m_assFontFamily);
- ms->externalClock.base = this->getAbsoluteClock();
- ms->syncType = this->getRecommandSyncType();
- bool calDuration = true;
- if (this->isRemoteProtocol())
- {
- char path[MAX_FILEPATH_CHAR_SIZE];
- QString pathPart;
- av_url_split(nullptr, 0, nullptr, 0, nullptr, 0, nullptr, path, sizeof(path), this->m_realFilePath.toUtf8().constData());
- pathPart = QString::fromUtf8(path);
- calDuration = !QFileInfo(pathPart).fileName().isEmpty();
- }
- if (calDuration && this->m_playData.duration == 0.0)
- this->m_playData.duration = format->duration / (double)AV_TIME_BASE;
- if (this->m_playData.duration < 0.0)
- this->m_playData.duration = 0.0;
- if (this->m_playData.userData.isEmpty())
- this->m_detail.fileName = QFileInfo(this->m_realFilePath).fileName();
- else
- this->m_detail.fileName = this->m_title;
- this->m_detail.totalTime = this->getDuration();
- if (this->m_playData.totalFrame <= 0 && videoIndex >= 0)
- {
- double total = av_q2d(format->streams[videoIndex]->avg_frame_rate);
- this->m_playData.totalFrame = this->getDuration() * total;
- }
- this->m_detail.videoTotalFrame = this->m_playData.totalFrame;
- if (videoIndex >= 0)
- this->computeSubtitleSize();
- if (audioIndex >= 0)
- {
- if (this->m_spdif.isOpened())
- {
- if (!this->m_spdif.play())
- return false;
- }
- else
- {
- if (!BASS_ChannelPlay(ms->audio.handle, true))
- return false;
- }
- }
- this->startReadThread();
- this->refreshSchedule(FIRST_REFRESH_DELAY);
- this->m_refreshThread.start();
- return true;
- }
- void MediaPresenter::startReadThread()
- {
- this->m_state->readThreadQuit = false;
- this->m_readThread.start();
- }
- void MediaPresenter::seekStream(double pos, double dir, int flag)
- {
- MediaState *ms = this->m_state;
- Seek &seek = ms->seek;
- if (seek.discard || seek.request || (!seek.readable && !ms->pause.pause))
- return;
- seek.flags = dir < 0.0 ? AVSEEK_FLAG_BACKWARD : 0;
- seek.flags |= flag;
- double dur = this->getDuration();
- if (pos > dur)
- {
- pos = dur;
- seek.flags |= AVSEEK_FLAG_BACKWARD;
- }
- if (IS_BIT_SET(seek.flags, AVSEEK_FLAG_BACKWARD))
- ms->willBeEnd = false;
- seek.time = pos + this->getAudioClockOffset();
- seek.pos = (int64_t)(seek.time * AV_TIME_BASE);
- if (ms->pause.pause)
- {
- if (this->isAudio())
- {
- seek.pauseSeeking = false;
- seek.inc += dir;
- }
- else
- {
- seek.pauseSeeking = true;
- seek.flushed = false;
- }
- }
- bool discard = IS_BIT_SET(seek.flags, AVSEEK_FLAG_ANY);
- if (discard)
- {
- if (ms->video.stream.index != -1)
- {
- if (!this->isAudio())
- ms->video.stream.discard = true;
- ms->video.stream.discardCount = 0;
- }
- if (ms->audio.stream.index != -1)
- {
- ms->audio.stream.discard = true;
- ms->audio.stream.discardCount = 0;
- if (this->m_spdif.isOpened())
- this->m_spdif.pause();
- else
- BASS_Pause();
- }
- if (ms->subtitle.stream.index != -1)
- {
- ms->subtitle.stream.discard = true;
- ms->subtitle.stream.discardCount = 0;
- }
- seek.flags &= ~AVSEEK_FLAG_ANY;
- seek.discardTime = pos;
- seek.readDiscardStartTime = this->getAbsoluteClock();
- }
- seek.request = true;
- if (discard)
- seek.discard = true;
- ms->seek.readable = false;
- ms->subtitle.seekFlags = seek.flags;
- }
- bool MediaPresenter::initNormalizer()
- {
- this->closeNormalizer();
- this->m_audioEffect.damp = BASS_ChannelSetFX(this->m_state->audio.handle, BASS_FX_BFX_DAMP, 4);
- if (!this->m_audioEffect.damp)
- return false;
- this->m_audioEffect.compressor = BASS_ChannelSetFX(this->m_state->audio.handle, BASS_FX_BFX_COMPRESSOR2, 3);
- if (!this->m_audioEffect.compressor)
- {
- this->closeNormalizer();
- return false;
- }
- return true;
- }
- void MediaPresenter::closeNormalizer()
- {
- BASS_ChannelRemoveFX(this->m_state->audio.handle, this->m_audioEffect.damp);
- BASS_ChannelRemoveFX(this->m_state->audio.handle, this->m_audioEffect.compressor);
- this->m_audioEffect.damp = 0;
- this->m_audioEffect.compressor = 0;
- }
- bool MediaPresenter::initEqualizer()
- {
- this->closeEqualizer();
- this->m_audioEffect.eqaulizer = BASS_ChannelSetFX(this->m_state->audio.handle, BASS_FX_BFX_PEAKEQ, 5);
- if (!this->m_audioEffect.eqaulizer)
- return false;
- this->m_audioEffect.preamp = BASS_ChannelSetFX(this->m_state->audio.handle, BASS_FX_BFX_VOLUME, 6);
- if (!this->m_audioEffect.preamp)
- {
- this->closeEqualizer();
- return false;
- }
- if (!this->setPreAmp(this->m_audioEffect.preampValue))
- {
- this->closeEqualizer();
- return false;
- }
- QVector<Equalizer> eqValues = this->m_audioEffect.equalizerValues;
- for (int i = 0; i < eqValues.count(); i++)
- {
- if (!this->setEqualizerGain(i, eqValues[i].gain))
- {
- this->closeEqualizer();
- return false;
- }
- }
- return true;
- }
- void MediaPresenter::closeEqualizer()
- {
- BASS_ChannelRemoveFX(this->m_state->audio.handle, this->m_audioEffect.eqaulizer);
- BASS_ChannelRemoveFX(this->m_state->audio.handle, this->m_audioEffect.preamp);
- this->m_audioEffect.eqaulizer = 0;
- this->m_audioEffect.preamp = 0;
- }
- bool MediaPresenter::initLowerVoice()
- {
- this->closeLowerVoice();
- this->m_audioEffect.lowerVoice = BASS_ChannelSetFX(this->m_state->audio.handle, BASS_FX_BFX_BQF, 1);
- if (!this->m_audioEffect.lowerVoice)
- return false;
- BASS_BFX_BQF param;
- param.lFilter = BASS_BFX_BQF_NOTCH;
- param.fCenter = 531.0f;
- param.fBandwidth = 4.0f;
- param.lChannel = BASS_BFX_CHANALL;
- param.fGain = 0.0f;
- param.fS = 0.0f;
- param.fQ = 0.0f;
- if (BASS_FXSetParameters(this->m_audioEffect.lowerVoice, ¶m) == FALSE)
- {
- this->closeLowerVoice();
- return false;
- }
- return true;
- }
- void MediaPresenter::closeLowerVoice()
- {
- BASS_ChannelRemoveFX(this->m_state->audio.handle, this->m_audioEffect.lowerVoice);
- this->m_audioEffect.lowerVoice = 0;
- }
- bool MediaPresenter::initHigherVoice()
- {
- this->closeHigherVoice();
- this->m_audioEffect.higherVoice = BASS_ChannelSetFX(this->m_state->audio.handle, BASS_FX_BFX_PEAKEQ, 2);
- if (!this->m_audioEffect.higherVoice)
- return false;
- BASS_BFX_PEAKEQ value;
- value.fBandwidth = this->m_audioEffect.higherVoiceValue.octave;
- value.fCenter = this->m_audioEffect.higherVoiceValue.center;
- value.fGain = this->m_audioEffect.higherVoiceValue.gain;
- value.lBand = 0;
- value.lChannel = BASS_BFX_CHANALL;
- if (BASS_FXSetParameters(this->m_audioEffect.higherVoice, &value) == FALSE)
- {
- this->closeHigherVoice();
- return false;
- }
- return true;
- }
- void MediaPresenter::closeHigherVoice()
- {
- BASS_ChannelRemoveFX(this->m_state->audio.handle, this->m_audioEffect.higherVoice);
- this->m_audioEffect.higherVoice = 0;
- }
- bool MediaPresenter::initLowerMusic()
- {
- this->closeLowerMusic();
- this->m_audioEffect.lowerMusic = BASS_ChannelSetFX(this->m_state->audio.handle, BASS_FX_BFX_BQF, 0);
- if (!this->m_audioEffect.lowerMusic)
- {
- this->closeLowerMusic();
- return false;
- }
- BASS_BFX_BQF param;
- param.lFilter = BASS_BFX_BQF_BANDPASS;
- param.fCenter = 531.0f;
- param.fBandwidth = 4.0f;
- param.lChannel = BASS_BFX_CHANALL;
- param.fGain = 0.0f;
- param.fS = 0.0f;
- param.fQ = 0.0f;
- if (BASS_FXSetParameters(this->m_audioEffect.lowerMusic, ¶m) == FALSE)
- {
- this->closeLowerMusic();
- return false;
- }
- return true;
- }
- void MediaPresenter::closeLowerMusic()
- {
- BASS_ChannelRemoveFX(this->m_state->audio.handle, this->m_audioEffect.lowerMusic);
- this->m_audioEffect.lowerMusic = 0;
- }
- void MediaPresenter::processSkipRange()
- {
- if (!this->m_state || !this->m_state->seek.readable || this->m_state->seek.discard || !this->hasDuration())
- return;
- for (int i = 0; i < this->m_skipRanges.count(); i++)
- {
- Range &range = this->m_skipRanges[i];
- if (range.end <= range.start)
- {
- if (range.start > 0.0 && range.end > 0.0)
- {
- range.enable = false;
- continue;
- }
- }
- double curTime = this->getCurrentPosition();
- QString startTime;
- QString endTime;
- double destTime = -1.0;
- QString desc;
- if (range.start < 0.0 && curTime < range.end)
- {
- if (!this->m_skipOpening || range.end <= 0.0)
- continue;
- destTime = range.end;
- Utils::getTimeString(range.end, Utils::TIME_HH_MM_SS, &endTime);
- desc = tr("오프닝 스킵 : %1").arg(endTime);
- }
- else if (this->m_playData.duration - range.start <= curTime && range.end < 0.0)
- {
- if (!this->m_skipEnding)
- continue;
- if (this->m_ended.callback)
- this->m_ended.callback(this->m_ended.userData);
- this->pause();
- }
- else if (range.start <= curTime && curTime < range.end)
- {
- if (!range.enable || !this->m_useSkipRange)
- continue;
- destTime = range.end;
- Utils::getTimeString(range.start, Utils::TIME_HH_MM_SS, &startTime);
- Utils::getTimeString(range.end, Utils::TIME_HH_MM_SS, &endTime);
- desc = tr("재생 스킵 : %1 ~ %2").arg(startTime).arg(endTime);
- }
- if (destTime >= 0.0 && destTime < this->getDuration())
- {
- const double offset = destTime > 0.0 ? 0.5 : -0.5;
- QMutexLocker locker(&this->m_controlLocker);
- this->seekStream(destTime + offset, destTime - curTime, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
- if (!desc.isEmpty())
- this->showOptionDesc(desc);
- break;
- }
- }
- }
- void MediaPresenter::run()
- {
- const int playTime = 100;
- const int detailTime = 1000;
- const int cpuUsageTime = 1000;
- const int showOptionDescTime = OPTION_DESC_TIME;
- QTime playingTimer;
- QTime showOptionDescTimer;
- QTime detailTimer;
- QTime cpuUsageTimer;
- MediaState *ms = this->m_state;
- playingTimer.start();
- showOptionDescTimer.start();
- detailTimer.start();
- cpuUsageTimer.start();
- while (!this->m_forceExit)
- {
- this->m_detail.currentTime = this->getCurrentPosition();
- this->m_detail.timePercentage = (this->m_detail.currentTime / this->m_detail.totalTime) * 100.0;
- if (std::isnan(this->m_detail.timePercentage))
- this->m_detail.timePercentage = 0.0;
- this->m_detail.videoCurrentFrame.fetchAndStoreOrdered((this->m_detail.timePercentage * this->m_detail.videoTotalFrame) / 100.0);
- if (detailTimer.elapsed() >= detailTime)
- {
- float elapsed = detailTimer.elapsed() / 1000.0f;
- detailTimer.restart();
- this->m_detail.videoFPS = this->m_detail.videoFrameCount.fetchAndStoreOrdered(0) / elapsed;
- this->m_detail.videoInputByteRate = this->m_detail.videoInputByteCount.fetchAndStoreOrdered(0) / elapsed;
- this->m_detail.videoOutputByteRate = this->m_detail.videoOutputByteCount.fetchAndStoreOrdered(0) / elapsed;
- this->m_detail.audioInputByteRate = this->m_detail.audioInputByteCount.fetchAndStoreOrdered(0) / elapsed;
- this->m_detail.audioOutputByteRate = this->m_detail.audioOutputByteCount.fetchAndStoreOrdered(0) / elapsed;
- this->m_detail.dtvSignal = true;
- }
- if (cpuUsageTimer.elapsed() >= cpuUsageTime)
- {
- cpuUsageTimer.restart();
- this->m_detail.cpuUsage = this->getCPUUsage();
- }
- if (playingTimer.elapsed() >= playTime)
- {
- if (ms && this->m_readThread.isRunning() && ms->seek.readable)
- {
- if (this->m_playing.callback)
- this->m_playing.callback(this->m_playing.userData);
- }
- playingTimer.restart();
- }
- if (this->m_showOptionDesc)
- {
- this->m_showOptionDesc = false;
- this->m_showingOptionDesc = true;
- showOptionDescTimer.restart();
- }
- if (this->m_showingOptionDesc && showOptionDescTimer.elapsed() > showOptionDescTime)
- {
- this->m_showingOptionDesc = false;
- if (this->m_showAudioOptionDescCallback.callback && this->isAudio())
- this->m_showAudioOptionDescCallback.callback(this->m_showAudioOptionDescCallback.userData, QString(), false);
- }
- if (this->m_repeatRange.enable && this->m_state->seek.readable && !this->m_state->seek.discard)
- {
- if (this->m_repeatRange.end <= this->m_repeatRange.start)
- {
- this->m_repeatRange.enable = false;
- }
- else
- {
- double curTime = this->getCurrentPosition();
- if (curTime > this->m_repeatRange.end)
- {
- QString startTime;
- QString endTime;
- QMutexLocker locker(&this->m_controlLocker);
- Utils::getTimeString(this->getRepeatStart(), Utils::TIME_HH_MM_SS_ZZZ, &startTime);
- Utils::getTimeString(this->getRepeatEnd(), Utils::TIME_HH_MM_SS_ZZZ, &endTime);
- this->seekStream(this->m_repeatRange.start, this->m_repeatRange.start - curTime, AVSEEK_FLAG_ANY);
- this->showOptionDesc(tr("구간 반복 : %1 ~ %2").arg(startTime).arg(endTime));
- }
- }
- }
- if (this->m_spdif.isOpened() && this->m_spdif.getFailCount() > SPDIF_MAX_FAIL_COUNT)
- {
- this->useSPDIF(false);
- this->showOptionDesc(tr("S/PDIF 출력을 지원하지 않은 포맷이므로 PCM 출력으로 전환합니다"));
- }
- this->processSkipRange();
- this->msleep(READ_CONTINUE_DELAY);
- }
- }