first commit
This commit is contained in:
207
project/fm_viewer/cfg/fm_base64.cpp
Normal file
207
project/fm_viewer/cfg/fm_base64.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
|
||||
#include "fm_base64.h"
|
||||
#if (ENCODE_CFG_BASE64)
|
||||
#include <QFile>
|
||||
|
||||
static const unsigned char base64_table[65] = "0123456789+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; // Changed Code...
|
||||
|
||||
#define BASE64_MARK_SIZE 4
|
||||
static const unsigned char base64_start_mark[BASE64_MARK_SIZE] = { 0x1B, 0x9B, 0x1B, 0x9C };
|
||||
static const unsigned char base64_end_mark[BASE64_MARK_SIZE] = { 0x1B, 0x9C, 0x1B, 0x9D };
|
||||
|
||||
/* base64_encode - Base64 encode */
|
||||
uint8_t* FMBase64::mg_base64_encode(const uint8_t *src, uint32_t len, uint32_t *out_len)
|
||||
{
|
||||
uint8_t *out, *pos;
|
||||
const uint8_t *end, *in;
|
||||
uint32_t olen;
|
||||
int line_len;
|
||||
|
||||
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
|
||||
olen += olen / 72; /* line feeds */
|
||||
olen++; /* nul termination */
|
||||
if (olen < len) return NULL; /* integer overflow */
|
||||
out = (uint8_t*)malloc(olen+(BASE64_MARK_SIZE*2));
|
||||
memset(out,0,olen+(BASE64_MARK_SIZE*2));
|
||||
|
||||
if (out == NULL) return NULL;
|
||||
|
||||
end = src + len;
|
||||
in = src;
|
||||
pos = out;
|
||||
line_len = 0;
|
||||
|
||||
memcpy((void*)pos, base64_start_mark, BASE64_MARK_SIZE);
|
||||
pos += BASE64_MARK_SIZE;
|
||||
|
||||
while (end - in >= 3) {
|
||||
*pos++ = base64_table[in[0] >> 2];
|
||||
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
|
||||
*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
|
||||
*pos++ = base64_table[in[2] & 0x3f];
|
||||
in += 3;
|
||||
line_len += 4;
|
||||
if (line_len >= 72) {
|
||||
*pos++ = '\n';
|
||||
line_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (end - in) {
|
||||
*pos++ = base64_table[in[0] >> 2];
|
||||
if (end - in == 1) {
|
||||
*pos++ = base64_table[(in[0] & 0x03) << 4];
|
||||
*pos++ = '=';
|
||||
} else {
|
||||
*pos++ = base64_table[((in[0] & 0x03) << 4) |
|
||||
(in[1] >> 4)];
|
||||
*pos++ = base64_table[(in[1] & 0x0f) << 2];
|
||||
}
|
||||
*pos++ = '=';
|
||||
line_len += 4;
|
||||
}
|
||||
|
||||
if (line_len) *pos++ = '\n';
|
||||
|
||||
memcpy((void*)pos, base64_end_mark, BASE64_MARK_SIZE);
|
||||
pos += BASE64_MARK_SIZE;
|
||||
|
||||
*pos = '\0';
|
||||
if (out_len) *out_len = pos - out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/* base64_decode - Base64 decode */
|
||||
uint8_t* FMBase64::mg_base64_decode(uint8_t *src, uint32_t len, uint32_t *out_len)
|
||||
{
|
||||
uint8_t dtable[256], *out, *pos, block[4], tmp;
|
||||
uint32_t i, count, olen;
|
||||
int pad = 0;
|
||||
|
||||
if(src == NULL || len <= BASE64_MARK_SIZE*2) return NULL;
|
||||
if(memcmp((void*)&src[0], base64_start_mark, BASE64_MARK_SIZE) ||
|
||||
memcmp((void*)&src[len-BASE64_MARK_SIZE], base64_end_mark, BASE64_MARK_SIZE)) {
|
||||
return NULL;
|
||||
}
|
||||
src += BASE64_MARK_SIZE;
|
||||
len -= BASE64_MARK_SIZE*2;
|
||||
|
||||
memset((void*)dtable, 0x80, 256);
|
||||
for (i = 0; i < sizeof(base64_table) - 1; i++)
|
||||
dtable[base64_table[i]] = (uint8_t) i;
|
||||
dtable['='] = 0;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (dtable[src[i]] != 0x80) count++;
|
||||
}
|
||||
|
||||
if (count == 0 || count % 4) return NULL;
|
||||
|
||||
olen = count / 4 * 3;
|
||||
//qInfo() << olen << olen + (olen % 2048) << __FUNCTION__;
|
||||
pos = out = (uint8_t*)malloc(qMax(olen,(uint32_t)4096));
|
||||
memset(out,0,olen);
|
||||
if (out == NULL) return NULL;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
tmp = dtable[src[i]];
|
||||
if (tmp == 0x80) continue;
|
||||
|
||||
if (src[i] == '=') pad++;
|
||||
block[count] = tmp;
|
||||
count++;
|
||||
if (count == 4) {
|
||||
*pos++ = (block[0] << 2) | (block[1] >> 4);
|
||||
*pos++ = (block[1] << 4) | (block[2] >> 2);
|
||||
*pos++ = (block[2] << 6) | block[3];
|
||||
count = 0;
|
||||
if (pad) {
|
||||
if (pad == 1) pos--;
|
||||
else if (pad == 2) pos -= 2;
|
||||
else {
|
||||
/* Invalid padding */
|
||||
free((void*)out);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*out_len = pos - out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// 파일 확인하여 텍스트 스트림으로 처리
|
||||
QStringList FMBase64::load(QString path, bool* isEncoded)
|
||||
{
|
||||
QFile file(path);
|
||||
if(file.exists() && file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
uint32_t len = (uint32_t)(file.size() + (file.size() % 8));
|
||||
uint8_t* buffer = (uint8_t*)malloc(len);
|
||||
memset(buffer,0,len);
|
||||
file.read((char*)buffer,file.size());
|
||||
uint8_t* text = buffer;
|
||||
|
||||
// MARK 확인 , 0x9C, 0x1B, 0x9D
|
||||
if(buffer[0] == base64_start_mark[0] &&
|
||||
buffer[1] == base64_start_mark[1] &&
|
||||
buffer[2] == base64_start_mark[2] &&
|
||||
buffer[3] == base64_start_mark[3] &&
|
||||
buffer[file.size()-4] == base64_end_mark[0] &&
|
||||
buffer[file.size()-3] == base64_end_mark[1] &&
|
||||
buffer[file.size()-2] == base64_end_mark[2] &&
|
||||
buffer[file.size()-1] == base64_end_mark[3]) {
|
||||
*isEncoded = true;
|
||||
uint32_t outlen = 0;
|
||||
text = mg_base64_decode(buffer, file.size(),&outlen);
|
||||
text[outlen] = 0;
|
||||
} else {
|
||||
*isEncoded = false;
|
||||
}
|
||||
QString lines = QString::fromLatin1((char*)text);
|
||||
file.close();
|
||||
if(buffer != text) {
|
||||
free(text);
|
||||
}
|
||||
free(buffer);
|
||||
return lines.split(QRegExp("[\r\n]"),QString::SkipEmptyParts);
|
||||
}
|
||||
return QStringList();
|
||||
}
|
||||
void FMBase64::save(QString path, QStringList lines, bool isEncoded)
|
||||
{
|
||||
|
||||
// \r\n
|
||||
QString str = QString();
|
||||
for(int i=0;i<lines.size();i++) {
|
||||
str += lines.at(i);
|
||||
str += "\r\n";
|
||||
}
|
||||
QByteArray ba = str.toLatin1();
|
||||
const uint8_t * src = (uint8_t*)ba.data();
|
||||
uint8_t* dest = NULL;
|
||||
|
||||
uint32_t out_len = ba.size();
|
||||
if(true) { // isEncoded) {
|
||||
dest = mg_base64_encode(src, ba.size(),&out_len);
|
||||
} else {
|
||||
size_t ss = ba.size() + (ba.size() % 8);
|
||||
dest = (uint8_t*)malloc(ss);
|
||||
memset(dest,0,ss);
|
||||
memcpy(dest,ba.data(),ba.size());
|
||||
}
|
||||
|
||||
QFile file(path);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
|
||||
file.write((char*)dest,out_len);
|
||||
file.close();
|
||||
}
|
||||
free(dest);
|
||||
|
||||
}
|
||||
#endif // #if (ENCODE_CFG_BASE64)
|
||||
20
project/fm_viewer/cfg/fm_base64.h
Normal file
20
project/fm_viewer/cfg/fm_base64.h
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
#ifndef FM_BASE64_H
|
||||
#define FM_BASE64_H
|
||||
#include "../rm_include.h"
|
||||
#if (ENCODE_CFG_BASE64)
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
#include <inttypes.h>
|
||||
class FMBase64
|
||||
{
|
||||
public:
|
||||
static QStringList load(QString path, bool* isEncoded);
|
||||
static void save(QString path, QStringList lines, bool isEncoded);
|
||||
private:
|
||||
static uint8_t* mg_base64_encode(const uint8_t *src, uint32_t len, uint32_t *out_len);
|
||||
static uint8_t* mg_base64_decode(uint8_t *src, uint32_t len, uint32_t *out_len);
|
||||
};
|
||||
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
#endif // ENCODE_CFG_BASE64
|
||||
#endif // FM_BASE64_H
|
||||
19
project/fm_viewer/cfg/make_model.bat
Normal file
19
project/fm_viewer/cfg/make_model.bat
Normal file
@@ -0,0 +1,19 @@
|
||||
echo off
|
||||
REM set /p id="IN Model: "
|
||||
REM set /p id="OUT Model: "
|
||||
|
||||
REM set IN_MODEL=%1
|
||||
REM set OUT_MODEL=%2
|
||||
|
||||
REM CALL :make_model 51fr,tr41fw
|
||||
REM CALL :make_model 51fr,tzd201
|
||||
REM CALL :make_model 61fh,tr61fw
|
||||
REM CALL :make_model 91fh,tzd202fw
|
||||
REM CALL :make_model 91fh,tzd203fw
|
||||
|
||||
:make_model
|
||||
copy /y rm_settings_cfg_%~1.h rm_settings_cfg_%~2.h
|
||||
copy /y rm_settings_cfg_%~1.cpp rm_settings_cfg_%~2.cpp
|
||||
copy /y window_settings_%~1.h window_settings_%~2.h
|
||||
copy /y window_settings_%~1.cpp window_settings_%~2.cpp
|
||||
EXIT /B 0
|
||||
227
project/fm_viewer/cfg/rm_admin_passwd.cpp
Normal file
227
project/fm_viewer/cfg/rm_admin_passwd.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
#include "rm_admin_passwd.h"
|
||||
#if (USE_ADMIN_PW_SETTINGS)
|
||||
|
||||
#include "rm_include.h"
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
#include <QLabel>
|
||||
#include <QDebug>
|
||||
#include <QCheckBox>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QLineEdit>
|
||||
#include "../ui/rm_button.h"
|
||||
#include "rm_radio_buttons.h"
|
||||
#include "rm_settings_window_base.h"
|
||||
|
||||
#include "../ui/rm_widget_checkbox.h"
|
||||
|
||||
RMSettingAdminPW::RMSettingAdminPW(unsigned char* data, QList<int> values, QWidget *parent) : QGroupBox(parent)
|
||||
{
|
||||
dataP = data;
|
||||
|
||||
setFixedHeight(120);
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
setObjectName("settings");
|
||||
|
||||
// 管理者PW
|
||||
//setTitle(MKU8("\xe7\xae\xa1\xe7\x90\x86\xe8\x80\x85\x50\x57"));
|
||||
setTitle(FM_WSTR(L"暗証番号"));
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignVCenter | Qt::AlignLeading);
|
||||
layout->setContentsMargins(4,2,4,2);
|
||||
layout->setSpacing(2);
|
||||
|
||||
//QSpacerItem* space = new QSpacerItem(0,10);
|
||||
//layout->addSpacerItem(space);
|
||||
|
||||
// 管理者PW保存
|
||||
#if !(REMOVE_ADMIN_PW_CHECKBOX)
|
||||
saveCheckbox = new RMWidgetCheckBox(this);
|
||||
//#if (LIVE_LANGUAGE_CHANGE)
|
||||
// if(RMLanguage::isJP() == false)
|
||||
// {
|
||||
// check->setText("PC Time Sync.");
|
||||
// }
|
||||
// else {
|
||||
//#else
|
||||
//#endif // LIVE_LANGUAGE_CHANGE
|
||||
//#if (LIVE_LANGUAGE_CHANGE)
|
||||
// }
|
||||
//#endif
|
||||
saveCheckbox->setText(MKU8("\xe7\xae\xa1\xe7\x90\x86\xe8\x80\x85\x50\x57\xe4\xbf\x9d\xe5\xad\x98"));
|
||||
#else
|
||||
|
||||
// ナイトビジョン
|
||||
const int lbWidth = 150;
|
||||
const int rWidth = 360;
|
||||
//RMRadioButtons* rb;
|
||||
//QLabel* tl = new QLabel(this);
|
||||
//static unsigned char dummy = 0;
|
||||
|
||||
// saveRadioButton = new QWidget(this);
|
||||
// saveRadioButton->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
// //setObjectName("test_widget");
|
||||
// saveRadioButton->setFixedHeight(25);
|
||||
|
||||
// QHBoxLayout* qlayout = new QHBoxLayout(saveRadioButton);
|
||||
// qlayout->setContentsMargins(8,2,8,2);
|
||||
// qlayout->setSpacing(2);
|
||||
// qlayout->setAlignment(Qt::AlignJustify);
|
||||
|
||||
// QLabel* qtitleLabel = new QLabel(this);
|
||||
// qtitleLabel->setObjectName("text_normal_label");
|
||||
// qtitleLabel->setText(FM_WSTR(L"暗証番号設定"));
|
||||
// qlayout->addWidget(qtitleLabel);
|
||||
|
||||
// foreach (QString eachTitle, (QStringList() << "OFF" << "ON")) {
|
||||
// QRadioButton* btn = new QRadioButton(saveRadioButton);
|
||||
// btn->setObjectName("settings");
|
||||
// btn->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
// btn->setText(eachTitle);
|
||||
// connect(btn,SIGNAL(clicked()),SLOT(onSelected()));
|
||||
// qlayout->addWidget(btn);
|
||||
// buttons.append(btn);
|
||||
// }
|
||||
|
||||
// buttons.at(0)->setChecked(true);
|
||||
|
||||
saveRadioButton = new RMRadioButtons(this,FM_WSTR(L"暗証番号設定"),(QStringList() << "OFF" << "ON"),dataP,values);
|
||||
connect(saveRadioButton,SIGNAL(selected(int)),SLOT(onSelected(int)));
|
||||
layout->addWidget(saveRadioButton);
|
||||
saveRadioButton->setFixedWidth(rWidth);
|
||||
saveRadioButton->titleLabel->setFixedWidth(lbWidth);
|
||||
//qtitleLabel->setFixedWidth(lbWidth);
|
||||
connect(RMValueUpdater::instance(),SIGNAL(updateByValues()),SLOT(onUpdateByValue()));
|
||||
|
||||
|
||||
//QSpacerItem* space = new QSpacerItem(10,0);
|
||||
//layout->addSpacerItem(space);
|
||||
//QLabel* saveCheckbox = new QLabel(this);
|
||||
//saveCheckbox->setText(MKU8(" \xe7\xae\xa1\xe7\x90\x86\xe8\x80\x85\x50\x57\xe4\xbf\x9d\xe5\xad\x98"));
|
||||
#endif
|
||||
|
||||
//layout->addWidget(saveCheckbox);
|
||||
// connect(check,SIGNAL(clicked()),SLOT(onCheckBoxTimeSync()));
|
||||
//saveCheckbox->setStyleSheet("font-size: 13px;color : white;");
|
||||
|
||||
QWidget* lw = new QWidget(this);
|
||||
layout->addWidget(lw);
|
||||
|
||||
QHBoxLayout* ll = new QHBoxLayout(lw);
|
||||
ll->setAlignment(Qt::AlignLeading);
|
||||
|
||||
// 管理者PW入力
|
||||
QLabel* titleLB = new QLabel(lw);
|
||||
titleLB->setObjectName("text_normal_label");
|
||||
|
||||
ll->addWidget(titleLB);
|
||||
titleLB->setText(FM_WSTR(L"暗証番号変更"));
|
||||
|
||||
//titleLB->setText(MKU8("\xe7\xae\xa1\xe7\x90\x86\xe8\x80\x85\x50\x57\xe5\x85\xa5\xe5\x8a\x9b\x3a"));
|
||||
titleLB->setFixedWidth(lbWidth-10);//100
|
||||
//titleLB->setStyleSheet("font-size: 13px;color : white;");
|
||||
|
||||
editPW = new QLineEdit(lw);
|
||||
editPW->setEchoMode(QLineEdit::Password);
|
||||
editPW->setStyleSheet("font-family: Fixedsys;color : #111111;background-color: #DDDDDD;border:1px;border-style:solid;border-color:#313131;");
|
||||
editPW->setMaxLength(4);
|
||||
editPW->setFixedWidth(80);
|
||||
editPW->setValidator( new QIntValidator(0, 9999, this) );
|
||||
ll->addWidget(editPW);
|
||||
|
||||
editPW->setEnabled(*data == 0);
|
||||
|
||||
// 端末の管理者パスワードが変更された番号にリセットされます。#最大4桁のみ入力可能。
|
||||
lw = new QWidget(this);
|
||||
layout->addWidget(lw);
|
||||
|
||||
QVBoxLayout* lv = new QVBoxLayout(lw);
|
||||
ZERO_LAYOUT(lv);
|
||||
lv->setContentsMargins(11,0,0,0);
|
||||
lv->setSpacing(3);
|
||||
lv->setAlignment(Qt::AlignLeading);
|
||||
|
||||
// 暗証番号設定をONにしているとき、暗証番号変更(4桁)の入力が可能。
|
||||
//QString descString = MKU8("\xe7\xab\xaf\xe6\x9c\xab\xe3\x81\xae\xe7\xae\xa1\xe7\x90\x86\xe8\x80\x85\xe3\x83\x91\xe3\x82\xb9\xe3\x83\xaf\xe3\x83\xbc\xe3\x83\x89\xe3\x81\x8c\xe5\xa4\x89\xe6\x9b\xb4\xe3\x81\x95\xe3\x82\x8c\xe3\x81\x9f\xe7\x95\xaa\xe5\x8f\xb7\xe3\x81\xab\xe3\x83\xaa\xe3\x82\xbb\xe3\x83\x83\xe3\x83\x88\xe3\x81\x95\xe3\x82\x8c\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82");
|
||||
QString descString = FM_WSTR(L"暗証番号設定をONにしているとき、");
|
||||
QLabel* desc = new QLabel(lw);
|
||||
desc->setText(descString);
|
||||
lv->addWidget(desc);
|
||||
desc->setStyleSheet("font-size: 14px; font-weight:bold; color:#eab428;");
|
||||
|
||||
QString descString2 = FM_WSTR(L"暗証番号変更(4桁)の入力が可能。");
|
||||
//QString descString2 = MKU8("\xe6\x9c\x80\xe5\xa4\xa7\x34\xe6\xa1\x81\xe3\x81\xae\xe3\x81\xbf\xe5\x85\xa5\xe5\x8a\x9b\xe5\x8f\xaf\xe8\x83\xbd\xe3\x80\x82");
|
||||
QLabel* desc2 = new QLabel(this);
|
||||
desc2->setText(descString2);
|
||||
lv->addWidget(desc2);
|
||||
desc2->setStyleSheet("font-size: 14px; font-weight:bold; color:#eab428;"); // ffc000
|
||||
//color : white;
|
||||
//font-size: 14px;
|
||||
//font-weight: bold;
|
||||
}
|
||||
void RMSettingAdminPW::onUpdateByValue() {
|
||||
// OFF
|
||||
editPW->setEnabled(*dataP == 0); // ON
|
||||
if(*dataP == 1) {
|
||||
editPW->setText("");
|
||||
}
|
||||
}
|
||||
void RMSettingAdminPW::onSelected(int index)
|
||||
{
|
||||
editPW->setEnabled(index == 1);
|
||||
if(index == 0) {
|
||||
editPW->setText("");
|
||||
}
|
||||
}
|
||||
/*
|
||||
void RMSettingAdminPW::onSelected()
|
||||
{
|
||||
QRadioButton* btn = qobject_cast<QRadioButton*>(sender());
|
||||
int index = buttons.indexOf(btn);
|
||||
qInfo() << index << __FUNCTION__;
|
||||
//*_value = realValue(index);
|
||||
//emit selected(index);
|
||||
if(index == 0) {
|
||||
editPW->setText("");
|
||||
}
|
||||
editPW->setEnabled(index == 1);
|
||||
if (index == 1) {
|
||||
editPW->setFocus();
|
||||
}
|
||||
}
|
||||
*/
|
||||
void RMSettingAdminPW::onSave() {
|
||||
|
||||
QString pws = editPW->text();
|
||||
if(pws.length() == 4)
|
||||
{
|
||||
QString pwPath = QDir::cleanPath(RMSettingsWindowBase::lastSettingDisk + "//admin.cfg");
|
||||
|
||||
if(QFile::exists(pwPath))
|
||||
{
|
||||
QFile::remove(pwPath);
|
||||
}
|
||||
unsigned char pwb[4] = {0,};
|
||||
pwb[0] = QString(pws.at(0)).toInt();
|
||||
pwb[1] = QString(pws[1]).toInt();
|
||||
pwb[2] = QString(pws[2]).toInt();
|
||||
pwb[3] = QString(pws[3]).toInt();
|
||||
|
||||
pwb[0] ^= 0x80;
|
||||
pwb[1] ^= 0x80;
|
||||
pwb[2] ^= 0x80;
|
||||
pwb[3] ^= 0x80;
|
||||
|
||||
QFile f(pwPath);
|
||||
if(f.open(QIODevice::WriteOnly))
|
||||
{
|
||||
f.write((const char*)&pwb[0],4);
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #if (USE_ADMIN_PW_SETTINGS)
|
||||
42
project/fm_viewer/cfg/rm_admin_passwd.h
Normal file
42
project/fm_viewer/cfg/rm_admin_passwd.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef RM_ADMIN_PASSWD_H
|
||||
#define RM_ADMIN_PASSWD_H
|
||||
#if (USE_ADMIN_PW_SETTINGS)
|
||||
|
||||
#include <QWidget>
|
||||
#include <QGroupBox>
|
||||
#include <QComboBox>
|
||||
#include <QList>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDateEdit>
|
||||
#include <QTimeEdit>
|
||||
#include <QTimer>
|
||||
|
||||
#define REMOVE_ADMIN_PW_CHECKBOX 1
|
||||
|
||||
class RMWidgetCheckBox;
|
||||
class RMRadioButtons;
|
||||
class QLabel;
|
||||
class QRadioButton;
|
||||
class RMSettingAdminPW : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RMSettingAdminPW(unsigned char* data, QList<int> values, QWidget *parent = nullptr);
|
||||
QBoxLayout* layout;
|
||||
QLineEdit* editPW;
|
||||
#if !(REMOVE_ADMIN_PW_CHECKBOX)
|
||||
RMWidgetCheckBox* saveCheckbox; // 210924 -> 제거
|
||||
#endif
|
||||
RMRadioButtons* saveRadioButton;
|
||||
//QList<QRadioButton*> buttons;
|
||||
private:
|
||||
unsigned char* dataP;
|
||||
|
||||
public slots:
|
||||
void onSave();
|
||||
void onSelected(int index);
|
||||
void onUpdateByValue();
|
||||
};
|
||||
|
||||
#endif // USE_ADMIN_PW_SETTINGS
|
||||
#endif // RM_ADMIN_PASSWD_H
|
||||
116
project/fm_viewer/cfg/rm_combo_box.cpp
Normal file
116
project/fm_viewer/cfg/rm_combo_box.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
#include "rm_combo_box.h"
|
||||
#include <QLabel>
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
#if (USE_JSON_SETTINGS)
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include "rm_settings_cfg.h"
|
||||
RMComboBox::RMComboBox(QWidget *parent,QString title,int index) : QWidget(parent), RMValueSelector(index)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
//setObjectName("test_widget");
|
||||
layout = new QHBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignLeading | Qt::AlignVCenter);
|
||||
layout->setContentsMargins(0,2,8,2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
if(!title.isEmpty())
|
||||
{
|
||||
titleLabel = new QLabel(this);
|
||||
titleLabel->setObjectName("text_normal_label");
|
||||
titleLabel->setText(title);
|
||||
layout->addWidget(titleLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
titleLabel = NULL;
|
||||
}
|
||||
QJsonObject obj = CFG::items.at(index).toObject();
|
||||
QStringList spacedItems;
|
||||
QJsonArray array = obj.value("value_strings").toArray();
|
||||
for(int i=0;i<array.size();i++)
|
||||
{
|
||||
spacedItems.append(" " + array.at(i).toString());
|
||||
}
|
||||
comboBox = new QComboBox(this);
|
||||
comboBox->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
comboBox->setObjectName("settings");
|
||||
comboBox->addItems(spacedItems);
|
||||
comboBox->setMaxVisibleItems(100);
|
||||
int idx = obj.value("current").toInt();
|
||||
comboBox->setCurrentIndex(realIndex(idx));
|
||||
connect(comboBox,SIGNAL(currentIndexChanged(int)),SLOT(onSelected(int)));
|
||||
layout->addWidget(comboBox);
|
||||
connect(RMValueUpdater::instance(),SIGNAL(updateByValues()),SLOT(onUpdateByValue()));
|
||||
}
|
||||
void RMComboBox::onSelected(int index)
|
||||
{
|
||||
QJsonObject obj = CFG::items.at(_object).toObject();
|
||||
obj.insert("current",QJsonValue(realValue(index)));
|
||||
CFG::items.replace(_object,obj);
|
||||
emit selected(index);
|
||||
}
|
||||
void RMComboBox::onUpdateByValue()
|
||||
{
|
||||
QJsonObject obj = CFG::items.at(_object).toObject();
|
||||
comboBox->setCurrentIndex(realIndex(obj.value("current").toInt()));
|
||||
}
|
||||
#else // USE_JSON_SETTINGS
|
||||
RMComboBox::RMComboBox(QWidget *parent,QString title, QStringList items,unsigned char* value,QList<int> indexMap) : QWidget(parent), RMValueSelector(value,indexMap)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
//setObjectName("test_widget");
|
||||
layout = new QHBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignLeading | Qt::AlignVCenter);
|
||||
layout->setContentsMargins(0,2,8,2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
if(title.length() > 0)
|
||||
{
|
||||
titleLabel = new QLabel(this);
|
||||
titleLabel->setObjectName("text_normal_label");
|
||||
titleLabel->setText(title);
|
||||
layout->addWidget(titleLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
titleLabel = NULL;
|
||||
}
|
||||
QStringList spacedItems;
|
||||
foreach (QString eachItem, items) {
|
||||
spacedItems.append(" " + eachItem);
|
||||
}
|
||||
|
||||
comboBox = new QComboBox(this);
|
||||
comboBox->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
comboBox->setObjectName("settings");
|
||||
comboBox->addItems(spacedItems);
|
||||
comboBox->setMaxVisibleItems(100);
|
||||
comboBox->setCurrentIndex(realIndex(*value));
|
||||
connect(comboBox,SIGNAL(currentIndexChanged(int)),SLOT(onSelected(int)));
|
||||
layout->addWidget(comboBox);
|
||||
|
||||
connect(RMValueUpdater::instance(),SIGNAL(updateByValues()),SLOT(onUpdateByValue()));
|
||||
}
|
||||
void RMComboBox::onSelected(int index)
|
||||
{
|
||||
*_value = realValue(index);
|
||||
emit selected(index);
|
||||
}
|
||||
void RMComboBox::onUpdateByValue()
|
||||
{
|
||||
comboBox->setCurrentIndex(realIndex(*_value));
|
||||
}
|
||||
#endif // USE_JSON_SETTINGS
|
||||
|
||||
|
||||
void RMComboBox::paintEvent(QPaintEvent *pe)
|
||||
{
|
||||
Q_UNUSED(pe);
|
||||
QStyleOption o;
|
||||
o.initFrom(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
|
||||
}
|
||||
|
||||
32
project/fm_viewer/cfg/rm_combo_box.h
Normal file
32
project/fm_viewer/cfg/rm_combo_box.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef RM_COMBO_BOX_H
|
||||
#define RM_COMBO_BOX_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
#include <QList>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include "rm_value_selector.h"
|
||||
class RMComboBox : public QWidget, public RMValueSelector
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
#if (USE_JSON_SETTINGS)
|
||||
explicit RMComboBox(QWidget *parent,QString title, int index);
|
||||
#else // USE_JSON_SETTINGS
|
||||
explicit RMComboBox(QWidget *parent,QString title, QStringList items,unsigned char* value,QList<int> indexMap = QList<int>());
|
||||
#endif // USE_JSON_SETTINGS
|
||||
QHBoxLayout* layout;
|
||||
QComboBox* comboBox;
|
||||
QLabel* titleLabel;
|
||||
private:
|
||||
void paintEvent(QPaintEvent *pe);
|
||||
signals:
|
||||
void selected(int index);
|
||||
|
||||
private slots:
|
||||
void onSelected(int index);
|
||||
void onUpdateByValue();
|
||||
};
|
||||
|
||||
#endif // RM_COMBO_BOX_H
|
||||
43
project/fm_viewer/cfg/rm_group_combo_box.cpp
Normal file
43
project/fm_viewer/cfg/rm_group_combo_box.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "rm_group_combo_box.h"
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
#include <QLabel>
|
||||
#include <QDebug>
|
||||
#include "rm_combo_box.h"
|
||||
#if (USE_JSON_SETTINGS)
|
||||
#include <QJsonObject>
|
||||
#include "rm_settings_cfg.h"
|
||||
RMGroupComboBox::RMGroupComboBox(QWidget *parent,int index) : QGroupBox(parent)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
setObjectName("settings");
|
||||
QJsonObject obj = CFG::items.at(index).toObject();
|
||||
if(obj.contains("title")) {
|
||||
setTitle(obj.value("title").toString());
|
||||
}
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignVCenter | Qt::AlignLeading);
|
||||
layout->setContentsMargins(8,2,8,2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
|
||||
comboBox = new RMComboBox(this,"",index);
|
||||
layout->addWidget(comboBox);
|
||||
}
|
||||
#else
|
||||
RMGroupComboBox::RMGroupComboBox(QWidget *parent,QString title, QStringList titles,unsigned char* value,QList<int> indexMap) : QGroupBox(parent)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
setObjectName("settings");
|
||||
setTitle(title);
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignVCenter | Qt::AlignLeading);
|
||||
layout->setContentsMargins(8,2,8,2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
comboBox = new RMComboBox(this,"",titles,value,indexMap);
|
||||
layout->addWidget(comboBox);
|
||||
}
|
||||
#endif
|
||||
26
project/fm_viewer/cfg/rm_group_combo_box.h
Normal file
26
project/fm_viewer/cfg/rm_group_combo_box.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef RM_GROUP_COMBO_BOX_H
|
||||
#define RM_GROUP_COMBO_BOX_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QGroupBox>
|
||||
#include <QComboBox>
|
||||
#include <QList>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
class RMComboBox;
|
||||
class QJsonObject;
|
||||
|
||||
class RMGroupComboBox : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
#if (USE_JSON_SETTINGS)
|
||||
explicit RMGroupComboBox(QWidget *parent,int index);
|
||||
#else // USE_JSON_SETTINGS
|
||||
explicit RMGroupComboBox(QWidget *parent,QString title, QStringList items,unsigned char* value,QList<int> indexMap = QList<int>());
|
||||
#endif // USE_JSON_SETTINGS
|
||||
QVBoxLayout* layout;
|
||||
RMComboBox* comboBox;
|
||||
};
|
||||
|
||||
#endif // RM_GROUP_COMBO_BOX_H
|
||||
70
project/fm_viewer/cfg/rm_group_radio_buttons.cpp
Normal file
70
project/fm_viewer/cfg/rm_group_radio_buttons.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "rm_group_radio_buttons.h"
|
||||
#include "rm_radio_buttons.h"
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
#if (USE_JSON_SETTINGS)
|
||||
#include <QJsonObject>
|
||||
#include "rm_settings_cfg.h"
|
||||
RMGroupRadioButtons::RMGroupRadioButtons(QWidget *parent,int object) : QGroupBox(parent)
|
||||
{
|
||||
setObjectName("settings");
|
||||
QJsonObject obj = CFG::items.at(object).toObject();
|
||||
if(obj.contains("title")) {
|
||||
setTitle(obj.value("title").toString());
|
||||
}
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignVCenter | Qt::AlignLeading);
|
||||
layout->setContentsMargins(8,2,8,2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
radioButtons = new RMRadioButtons(this, "",object);
|
||||
layout->addWidget(radioButtons);
|
||||
|
||||
}
|
||||
RMGroupRadioButtons::RMGroupRadioButtons(QWidget *parent,int object, bool rowType) : QGroupBox(parent)
|
||||
{
|
||||
setObjectName("settings");
|
||||
QJsonObject obj = CFG::items.at(object).toObject();
|
||||
if(obj.contains("title")) {
|
||||
setTitle(obj.value("title").toString());
|
||||
}
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignVCenter | Qt::AlignLeading);
|
||||
layout->setContentsMargins(8,2,8,2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
radioButtons = new RMRadioButtons(this, "",object,rowType);
|
||||
layout->addWidget(radioButtons);
|
||||
}
|
||||
#else // USE_JSON_SETTINGS
|
||||
RMGroupRadioButtons::RMGroupRadioButtons(QWidget *parent,QString title, QStringList titles,unsigned char* value,QList<int> indexMap) : QGroupBox(parent)
|
||||
{
|
||||
setObjectName("settings");
|
||||
setTitle(title);
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignVCenter | Qt::AlignLeading);
|
||||
layout->setContentsMargins(8,2,8,2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
radioButtons = new RMRadioButtons(this, "",titles,value,indexMap);
|
||||
layout->addWidget(radioButtons);
|
||||
|
||||
}
|
||||
RMGroupRadioButtons::RMGroupRadioButtons(QWidget *parent,QString title, QStringList titles,unsigned char* value,bool rowType, QList<int> indexMap) : QGroupBox(parent)
|
||||
{
|
||||
setObjectName("settings");
|
||||
setTitle(title);
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignVCenter | Qt::AlignLeading);
|
||||
layout->setContentsMargins(8,2,8,2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
radioButtons = new RMRadioButtons(this, "",titles,value,rowType,indexMap);
|
||||
layout->addWidget(radioButtons);
|
||||
}
|
||||
#endif // #if (USE_JSON_SETTINGS)
|
||||
28
project/fm_viewer/cfg/rm_group_radio_buttons.h
Normal file
28
project/fm_viewer/cfg/rm_group_radio_buttons.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef RM_GROUP_RADIO_BUTTONS_H
|
||||
#define RM_GROUP_RADIO_BUTTONS_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QGroupBox>
|
||||
#include <QList>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
class RMRadioButtons;
|
||||
class RMGroupRadioButtons : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
#if (USE_JSON_SETTINGS)
|
||||
explicit RMGroupRadioButtons(QWidget *parent,int object);
|
||||
explicit RMGroupRadioButtons(QWidget *parent,int object,bool rowType);
|
||||
#else // #if (USE_JSON_SETTINGS)
|
||||
explicit RMGroupRadioButtons(QWidget *parent,QString title, QStringList items,unsigned char* value,QList<int> indexMap = QList<int>());
|
||||
explicit RMGroupRadioButtons(QWidget *parent,QString title, QStringList items,unsigned char* value,bool rowType = false,QList<int> indexMap = QList<int>());
|
||||
#endif // #if (USE_JSON_SETTINGS)
|
||||
|
||||
QVBoxLayout* layout;
|
||||
RMRadioButtons* radioButtons;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // RM_GROUP_RADIO_BUTTONS_H
|
||||
243
project/fm_viewer/cfg/rm_radio_buttons.cpp
Normal file
243
project/fm_viewer/cfg/rm_radio_buttons.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
#include "rm_radio_buttons.h"
|
||||
#include <QHBoxLayout>
|
||||
#include <QDebug>
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
#include <QLabel>
|
||||
|
||||
#if (USE_JSON_SETTINGS)
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include "rm_settings_cfg.h"
|
||||
RMRadioButtons::RMRadioButtons(QWidget *parent,
|
||||
QString title, int object, bool rowType) : QWidget(parent), RMValueSelector(object)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
//setObjectName("test_widget");
|
||||
|
||||
if(rowType == true)
|
||||
{
|
||||
layout = new QVBoxLayout(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
setFixedHeight(25);
|
||||
layout = new QHBoxLayout(this);
|
||||
}
|
||||
layout->setContentsMargins(8,2,8,2);
|
||||
layout->setSpacing(2);
|
||||
layout->setAlignment(Qt::AlignJustify);
|
||||
|
||||
if(title.isEmpty() == false) {
|
||||
titleLabel = new QLabel(this);
|
||||
titleLabel->setObjectName("text_normal_label");
|
||||
titleLabel->setText(title);
|
||||
layout->addWidget(titleLabel);
|
||||
}
|
||||
QJsonObject obj = CFG::items.at(object).toObject();
|
||||
//foreach (QString eachTitle, titles) {
|
||||
QJsonArray value_strings = obj.value("value_strings").toArray();
|
||||
for(int i=0;i<value_strings.size();i++) {
|
||||
|
||||
QRadioButton* btn = new QRadioButton(this);
|
||||
btn->setObjectName("settings");
|
||||
btn->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
btn->setText(value_strings.at(i).toString());
|
||||
|
||||
if(rowType == true)
|
||||
{
|
||||
btn->setFixedHeight(25);
|
||||
}
|
||||
connect(btn,SIGNAL(clicked()),SLOT(onSelected()));
|
||||
layout->addWidget(btn);
|
||||
buttons.append(btn);
|
||||
}
|
||||
if(buttons.count() <= realIndex(obj.value("current").toInt()))
|
||||
{
|
||||
obj.insert("current",QJsonValue(0));
|
||||
}
|
||||
buttons[realIndex(obj.value("current").toInt())]->setChecked(true);
|
||||
connect(RMValueUpdater::instance(),SIGNAL(updateByValues()),SLOT(onUpdateByValue()));
|
||||
}
|
||||
|
||||
RMRadioButtons::RMRadioButtons(QWidget *parent,
|
||||
QString title,
|
||||
int object) : QWidget(parent),
|
||||
RMValueSelector(object)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
//setObjectName("test_widget");
|
||||
setFixedHeight(25);
|
||||
|
||||
layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(8,2,8,2);
|
||||
layout->setSpacing(2);
|
||||
layout->setAlignment(Qt::AlignJustify);
|
||||
|
||||
if(title.isEmpty() == false) {
|
||||
titleLabel = new QLabel(this);
|
||||
titleLabel->setObjectName("text_normal_label");
|
||||
titleLabel->setText(title);
|
||||
layout->addWidget(titleLabel);
|
||||
}
|
||||
QJsonObject obj = CFG::items.at(object).toObject();
|
||||
|
||||
//foreach (QString eachTitle, titles) {
|
||||
QJsonArray value_strings = obj.value("value_strings").toArray();
|
||||
for(int i=0;i<value_strings.size();i++) {
|
||||
QRadioButton* btn = new QRadioButton(this);
|
||||
btn->setObjectName("settings");
|
||||
btn->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
btn->setText(value_strings.at(i).toString());
|
||||
connect(btn,SIGNAL(clicked()),SLOT(onSelected()));
|
||||
layout->addWidget(btn);
|
||||
buttons.append(btn);
|
||||
}
|
||||
if(buttons.count() > realIndex(obj.value("current").toInt()))
|
||||
{
|
||||
buttons[realIndex(obj.value("current").toInt())]->setChecked(true);
|
||||
}
|
||||
connect(RMValueUpdater::instance(),SIGNAL(updateByValues()),SLOT(onUpdateByValue()));
|
||||
}
|
||||
void RMRadioButtons::onSelected()
|
||||
{
|
||||
QJsonObject obj = CFG::items.at(_object).toObject();
|
||||
QRadioButton* btn = qobject_cast<QRadioButton*>(sender());
|
||||
int index = buttons.indexOf(btn);
|
||||
obj.insert("current",QJsonValue(realValue(index)));
|
||||
CFG::items.replace(_object,obj);
|
||||
emit selected(index);
|
||||
}
|
||||
void RMRadioButtons::onUpdateByValue()
|
||||
{
|
||||
QJsonObject obj = CFG::items.at(_object).toObject();
|
||||
buttons[realIndex(obj.value("current").toInt())]->setChecked(true);
|
||||
}
|
||||
#else // #if (USE_JSON_SETTINGS)
|
||||
RMRadioButtons::RMRadioButtons(QWidget *parent,
|
||||
QString title,
|
||||
QStringList titles,
|
||||
unsigned char* value,
|
||||
bool rowType,
|
||||
QList<int> indexMap
|
||||
) : QWidget(parent), RMValueSelector(value,indexMap)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
//setObjectName("test_widget");
|
||||
|
||||
if(rowType == true)
|
||||
{
|
||||
layout = new QVBoxLayout(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
setFixedHeight(25);
|
||||
layout = new QHBoxLayout(this);
|
||||
}
|
||||
layout->setContentsMargins(8,2,8,2);
|
||||
layout->setSpacing(2);
|
||||
layout->setAlignment(Qt::AlignJustify);
|
||||
|
||||
if(title.isEmpty() == false) {
|
||||
titleLabel = new QLabel(this);
|
||||
titleLabel->setObjectName("text_normal_label");
|
||||
titleLabel->setText(title);
|
||||
layout->addWidget(titleLabel);
|
||||
}
|
||||
|
||||
foreach (QString eachTitle, titles) {
|
||||
QRadioButton* btn = new QRadioButton(this);
|
||||
btn->setObjectName("settings");
|
||||
btn->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
btn->setText(eachTitle);
|
||||
|
||||
if(rowType == true)
|
||||
{
|
||||
btn->setFixedHeight(25);
|
||||
}
|
||||
connect(btn,SIGNAL(clicked()),SLOT(onSelected()));
|
||||
layout->addWidget(btn);
|
||||
buttons.append(btn);
|
||||
}
|
||||
if(buttons.count() <= realIndex(*_value))
|
||||
{
|
||||
*_value = 0;
|
||||
}
|
||||
buttons[realIndex(*_value)]->setChecked(true);
|
||||
connect(RMValueUpdater::instance(),SIGNAL(updateByValues()),SLOT(onUpdateByValue()));
|
||||
}
|
||||
|
||||
RMRadioButtons::RMRadioButtons(QWidget *parent,
|
||||
QString title,
|
||||
QStringList titles,
|
||||
unsigned char* value,
|
||||
QList<int> indexMap) : QWidget(parent),
|
||||
RMValueSelector(value,indexMap)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
//setObjectName("test_widget");
|
||||
setFixedHeight(25);
|
||||
|
||||
layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(8,2,8,2);
|
||||
layout->setSpacing(2);
|
||||
layout->setAlignment(Qt::AlignJustify);
|
||||
|
||||
if(title.isEmpty() == false) {
|
||||
titleLabel = new QLabel(this);
|
||||
titleLabel->setObjectName("text_normal_label");
|
||||
titleLabel->setText(title);
|
||||
layout->addWidget(titleLabel);
|
||||
}
|
||||
|
||||
foreach (QString eachTitle, titles) {
|
||||
QRadioButton* btn = new QRadioButton(this);
|
||||
btn->setObjectName("settings");
|
||||
btn->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
btn->setText(eachTitle);
|
||||
connect(btn,SIGNAL(clicked()),SLOT(onSelected()));
|
||||
layout->addWidget(btn);
|
||||
buttons.append(btn);
|
||||
}
|
||||
if(buttons.count() > realIndex(*_value))
|
||||
{
|
||||
buttons[realIndex(*_value)]->setChecked(true);
|
||||
}
|
||||
connect(RMValueUpdater::instance(),SIGNAL(updateByValues()),SLOT(onUpdateByValue()));
|
||||
}
|
||||
int RMRadioButtons::currentIndex()
|
||||
{
|
||||
for(int i=0;i<buttons.size();i++) {
|
||||
if(buttons[i]->isChecked()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
void RMRadioButtons::setCurrentIndex(int index)
|
||||
{
|
||||
for(int i=0;i<buttons.size();i++) {
|
||||
buttons[i]->setChecked(i == index);
|
||||
}
|
||||
}
|
||||
void RMRadioButtons::onSelected()
|
||||
{
|
||||
QRadioButton* btn = qobject_cast<QRadioButton*>(sender());
|
||||
int index = buttons.indexOf(btn);
|
||||
*_value = realValue(index);
|
||||
emit selected(index);
|
||||
}
|
||||
void RMRadioButtons::onUpdateByValue()
|
||||
{
|
||||
//qInfo() << buttons[0]->text() << "value:" << *_value << "_indexMap:" << _indexMap.size() << realIndex(*_value) << __FUNCTION__;
|
||||
buttons[realIndex(*_value)]->setChecked(true);
|
||||
}
|
||||
#endif // #else // #if (USE_JSON_SETTINGS)
|
||||
void RMRadioButtons::paintEvent(QPaintEvent *pe)
|
||||
{
|
||||
Q_UNUSED(pe);
|
||||
QStyleOption o;
|
||||
o.initFrom(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
|
||||
}
|
||||
39
project/fm_viewer/cfg/rm_radio_buttons.h
Normal file
39
project/fm_viewer/cfg/rm_radio_buttons.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef RM_RADIO_BUTTONS_H
|
||||
#define RM_RADIO_BUTTONS_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QRadioButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPaintEvent>
|
||||
#include <QLabel>
|
||||
#include "rm_value_selector.h"
|
||||
|
||||
class RMRadioButtons : public QWidget, public RMValueSelector
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
#if (USE_JSON_SETTINGS)
|
||||
explicit RMRadioButtons(QWidget *parent,QString title, int object);
|
||||
explicit RMRadioButtons(QWidget *parent,QString title, int object, bool rowType);
|
||||
#else // USE_JSON_SETTINGS
|
||||
explicit RMRadioButtons(QWidget *parent,QString title, QStringList titles,unsigned char* value, QList<int> indexMap = QList<int>());
|
||||
explicit RMRadioButtons(QWidget *parent,QString title, QStringList titles,unsigned char* value, bool rowType = false,QList<int> indexMap = QList<int>());
|
||||
#endif // USE_JSON_SETTINGS
|
||||
QBoxLayout* layout;
|
||||
//QHBoxLayout* layout;
|
||||
QLabel* titleLabel;
|
||||
void setCurrentIndex(int index);
|
||||
int currentIndex();
|
||||
private:
|
||||
QList<QRadioButton*> buttons;
|
||||
void paintEvent(QPaintEvent *pe);
|
||||
|
||||
signals:
|
||||
void selected(int index);
|
||||
|
||||
private slots:
|
||||
void onSelected();
|
||||
void onUpdateByValue();
|
||||
};
|
||||
|
||||
#endif // RM_RADIO_BUTTONS_H
|
||||
246
project/fm_viewer/cfg/rm_setting_time.cpp
Normal file
246
project/fm_viewer/cfg/rm_setting_time.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
#include "rm_setting_time.h"
|
||||
|
||||
#if (USE_DEVICE_SETTINGS && !USE_DEVICE_SETTINGS_JSON)
|
||||
|
||||
#include "rm_include.h"
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
#include <QLabel>
|
||||
#include <QDebug>
|
||||
#include <QCheckBox>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include "../ui/rm_button.h"
|
||||
#include "rm_settings_window_base.h"
|
||||
|
||||
#include "../ui/rm_widget_checkbox.h"
|
||||
|
||||
RMSettingTime::RMSettingTime(QWidget *parent) : QGroupBox(parent)
|
||||
{
|
||||
setFixedHeight(100);
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
setObjectName("settings");
|
||||
|
||||
// 日時
|
||||
//#if (LIVE_LANGUAGE_CHANGE)
|
||||
// if(RMLanguage::isJP() == false)
|
||||
// {
|
||||
// setTitle("Time");
|
||||
// }
|
||||
// else {
|
||||
//#else
|
||||
setTitle(MKU8("\xe6\x97\xa5\xe6\x99\x82"));
|
||||
//#endif
|
||||
//#if (LIVE_LANGUAGE_CHANGE)
|
||||
// }
|
||||
//#endif
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignVCenter | Qt::AlignLeading);
|
||||
layout->setContentsMargins(4,2,4,2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
QSpacerItem* space = new QSpacerItem(0,10);
|
||||
layout->addSpacerItem(space);
|
||||
|
||||
// パソコンの時刻と同期
|
||||
check = new RMWidgetCheckBox(this);
|
||||
//#if (LIVE_LANGUAGE_CHANGE)
|
||||
// if(RMLanguage::isJP() == false)
|
||||
// {
|
||||
// check->setText("PC Time Sync.");
|
||||
// }
|
||||
// else {
|
||||
//#else
|
||||
check->setText(MKU8("\xe3\x83\x91\xe3\x82\xbd\xe3\x82\xb3\xe3\x83\xb3\xe3\x81\xae\xe6\x99\x82\xe5\x88\xbb\xe3\x81\xa8\xe5\x90\x8c\xe6\x9c\x9f"));
|
||||
//#endif // LIVE_LANGUAGE_CHANGE
|
||||
//#if (LIVE_LANGUAGE_CHANGE)
|
||||
// }
|
||||
//#endif
|
||||
|
||||
layout->addWidget(check);
|
||||
// 시계 기능 없음
|
||||
#if !(SETTINGS_TIME_TYPE2)
|
||||
connect(check,SIGNAL(clicked()),SLOT(onCheckBoxTimeSync()));
|
||||
#endif
|
||||
check->setStyleSheet("font-size: 13px;color : white;");
|
||||
|
||||
|
||||
QWidget* timeWidget = new QWidget(this);
|
||||
layout->addWidget(timeWidget);
|
||||
|
||||
QHBoxLayout* timeLayout = new QHBoxLayout(timeWidget);
|
||||
date = new QDateEdit(timeWidget);
|
||||
date->setCalendarPopup(true);
|
||||
date->setStyleSheet("font-family: Arial;font-size: 14px;");
|
||||
timeLayout->addWidget(date);
|
||||
|
||||
time = new QTimeEdit(timeWidget);
|
||||
timeLayout->addWidget(time);
|
||||
time->setStyleSheet("font-family: Arial;font-size: 14px;");
|
||||
time->setDisplayFormat("AP hh:mm:ss");
|
||||
|
||||
QString applyString = MKU8("\xe9\x81\xa9\xe7\x94\xa8");
|
||||
//#if (LIVE_LANGUAGE_CHANGE)
|
||||
// if(RMLanguage::isJP() == false)
|
||||
// {
|
||||
// applyString = "Apply";
|
||||
// }
|
||||
//#endif
|
||||
#if !(SETTINGS_TIME_TYPE2)
|
||||
#if (LIVE_LANGUAGE2)
|
||||
RMButton* applyButton = RMButton::create2(timeWidget,timeLayout,"button","apply",QSize(60,30));
|
||||
#else // LIVE_LANGUAGE2
|
||||
RMButton* applyButton = RMButton::create(timeWidget,timeLayout,"button",applyString,QSize(60,30));
|
||||
#endif // LIVE_LANGUAGE2
|
||||
applyButton->setText(applyString);
|
||||
connect(applyButton,SIGNAL(clicked()),this,SLOT(onSave()));
|
||||
#endif // SETTINGS_TIME_TYPE2
|
||||
|
||||
_syncTimer = NULL;
|
||||
|
||||
|
||||
// 읽어 오기는 한다 (나머지 공간에 저장값 그대로 유지하기 위해)
|
||||
memset(_buffer,0,TIME_SET_FILE_SIZE);
|
||||
QString timePath = QDir::cleanPath(RMSettingsWindowBase::lastSettingDisk + "//timeset.txt");
|
||||
if(QFile::exists(timePath))
|
||||
{
|
||||
FILE* f = fopen(timePath.toLocal8Bit(),"r+b");
|
||||
if(f != NULL)
|
||||
{
|
||||
fread(_buffer,1,TIME_SET_FILE_SIZE,f);
|
||||
fclose(f);
|
||||
//_readFromBuffer();
|
||||
}
|
||||
}
|
||||
onSyncTime();
|
||||
}
|
||||
|
||||
//void RMSettingTime::_readFromBuffer()
|
||||
//{
|
||||
|
||||
//// 0x10 2BYTE 2019 // 년
|
||||
//// 0x12 2BYTE 01 // 월
|
||||
//// 0x14 2BYTE 01 // 일
|
||||
//// 0x16 2BYTE 01 // 시
|
||||
//// 0x18 2BYTE 00 // 분
|
||||
//// 0x1A 2BYTE 00 // 초
|
||||
|
||||
// int y = _buffer[0x11] << 8 | _buffer[0x10];
|
||||
// int m = _buffer[0x13] << 8 | _buffer[0x12];
|
||||
// int d = _buffer[0x15] << 8 | _buffer[0x14];
|
||||
|
||||
// int h = _buffer[0x17] << 8 | _buffer[0x16];
|
||||
// int mm = _buffer[0x19] << 8 | _buffer[0x18];
|
||||
// int s = _buffer[0x1B] << 8 | _buffer[0x1A];
|
||||
|
||||
// //qInfo() << year << month << day << h << m << s;
|
||||
|
||||
// QDateTime dt;
|
||||
// dt.setDate(QDate(y,m,d));
|
||||
// dt.setTime(QTime(h,mm,s));
|
||||
|
||||
// date->setDate(dt.date());
|
||||
// time->setTime(dt.time());
|
||||
|
||||
// qInfo() << dt;
|
||||
//}
|
||||
void RMSettingTime::onSave()
|
||||
{
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
|
||||
QString timePath = QDir::cleanPath(RMSettingsWindowBase::lastSettingDisk + "//data_time.cfg");
|
||||
|
||||
if(QFile::exists(timePath))
|
||||
{
|
||||
QFile::remove(timePath);
|
||||
}
|
||||
QDateTime dt = date->dateTime();
|
||||
dt.setTime(time->time());
|
||||
// 2020 10 21 17 18 28
|
||||
QString ts = dt.toString("yyyy MM dd HH mm ss");
|
||||
QFile f(timePath);
|
||||
if(f.open(QIODevice::WriteOnly))
|
||||
{
|
||||
f.write(ts.toUtf8());
|
||||
f.close();
|
||||
}
|
||||
#else
|
||||
int y = date->date().year();
|
||||
int m = date->date().month();
|
||||
int d = date->date().day();
|
||||
|
||||
int h = time->time().hour();
|
||||
int mm = time->time().minute();
|
||||
int s = time->time().second();
|
||||
|
||||
_buffer[0x10] = (y) & 0xFF;
|
||||
_buffer[0x11] = (y >> 8) & 0xFF;
|
||||
|
||||
_buffer[0x12] = (m) & 0xFF;
|
||||
_buffer[0x13] = (m >> 8) & 0xFF;
|
||||
|
||||
_buffer[0x14] = (d) & 0xFF;
|
||||
_buffer[0x15] = (d >> 8) & 0xFF;
|
||||
|
||||
_buffer[0x16] = (h) & 0xFF;
|
||||
_buffer[0x17] = (h >> 8) & 0xFF;
|
||||
|
||||
_buffer[0x18] = (mm) & 0xFF;
|
||||
_buffer[0x19] = (mm >> 8) & 0xFF;
|
||||
|
||||
_buffer[0x1A] = (s) & 0xFF;
|
||||
_buffer[0x1B] = (s >> 8) & 0xFF;
|
||||
|
||||
QString timePath = QDir::cleanPath(RMSettingsWindowBase::lastSettingDisk + "//timeset.txt");
|
||||
if(QFile::exists(timePath))
|
||||
{
|
||||
QFile::remove(timePath);
|
||||
}
|
||||
FILE* f = fopen(timePath.toLocal8Bit(),"w+b");
|
||||
if(f != NULL)
|
||||
{
|
||||
fwrite(_buffer,1,TIME_SET_FILE_SIZE,f);
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
void RMSettingTime::onCheckBoxTimeSync()
|
||||
{
|
||||
QCheckBox* checkbox = qobject_cast<QCheckBox *>(QObject::sender());
|
||||
if(checkbox != NULL)
|
||||
{
|
||||
bool turnOn = (checkbox->checkState() != Qt::Unchecked );
|
||||
_startStopTimer(turnOn);
|
||||
}
|
||||
}
|
||||
void RMSettingTime::_startStopTimer(bool bStart)
|
||||
{
|
||||
if(_syncTimer != NULL) {
|
||||
_syncTimer->stop();
|
||||
delete _syncTimer;
|
||||
_syncTimer = NULL;
|
||||
}
|
||||
|
||||
if(bStart) {
|
||||
_syncTimer = new QTimer(this);
|
||||
_syncTimer->setSingleShot(false);
|
||||
_syncTimer->setInterval(1000);
|
||||
connect(_syncTimer,SIGNAL(timeout()),SLOT(onSyncTime()));
|
||||
_syncTimer->start();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RMSettingTime::onSyncTime()
|
||||
{
|
||||
QDateTime d = QDateTime::currentDateTime();
|
||||
date->setDate(d.date());
|
||||
time->setTime(d.time());
|
||||
}
|
||||
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
41
project/fm_viewer/cfg/rm_setting_time.h
Normal file
41
project/fm_viewer/cfg/rm_setting_time.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef RM_SETTING_TIME_H
|
||||
#define RM_SETTING_TIME_H
|
||||
|
||||
#if (USE_DEVICE_SETTINGS && !USE_DEVICE_SETTINGS_JSON)
|
||||
|
||||
#include <QWidget>
|
||||
#include <QGroupBox>
|
||||
#include <QComboBox>
|
||||
#include <QList>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDateEdit>
|
||||
#include <QTimeEdit>
|
||||
#include <QTimer>
|
||||
|
||||
#define TIME_SET_FILE_SIZE 28
|
||||
|
||||
class RMWidgetCheckBox;
|
||||
class RMSettingTime : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RMSettingTime(QWidget *parent = nullptr);
|
||||
QBoxLayout* layout;
|
||||
RMWidgetCheckBox* check;
|
||||
private:
|
||||
QTimer* _syncTimer;
|
||||
void _startStopTimer(bool bStart);
|
||||
QDateEdit* date;
|
||||
QTimeEdit* time;
|
||||
unsigned char _buffer[TIME_SET_FILE_SIZE];
|
||||
|
||||
//void _readFromBuffer();
|
||||
|
||||
public slots:
|
||||
void onSave();
|
||||
void onCheckBoxTimeSync();
|
||||
void onSyncTime();
|
||||
};
|
||||
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
#endif // RM_SETTING_TIME_H
|
||||
15
project/fm_viewer/cfg/rm_settings_cfg.h
Normal file
15
project/fm_viewer/cfg/rm_settings_cfg.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef RM_SETTINGS_CFG_H
|
||||
#define RM_SETTINGS_CFG_H
|
||||
#if (USE_DEVICE_SETTINGS)
|
||||
#include "../rm_include.h"
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
#include "rm_settings_cfg_xdr6688.h"
|
||||
#elif (RM_MODEL_EMT_KR)
|
||||
#include "rm_settings_cfg_emt_kr.h"
|
||||
#else
|
||||
#include "rm_settings_cfg_standard.h"
|
||||
#endif
|
||||
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
#endif // RM_SETTINGS_CFG_H
|
||||
268
project/fm_viewer/cfg/rm_settings_cfg_emt_kr.cpp
Normal file
268
project/fm_viewer/cfg/rm_settings_cfg_emt_kr.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
|
||||
#include "rm_settings_cfg_emt_kr.h"
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <Windows.h>
|
||||
#if (USE_DEVICE_SETTINGS && RM_MODEL_EMT_KR)
|
||||
|
||||
unsigned char CFG::data[SETTINGS_CFG_SIZE] = {0,};
|
||||
unsigned char CFG::stored[SETTINGS_CFG_SIZE] = {0,};
|
||||
EMTINFO CFG::info = {0,};
|
||||
QJsonArray CFG::items;
|
||||
QString CFG::cfgPath = "";
|
||||
|
||||
QStringList CFG::model_names = QStringList() << "NM5000" << "NP5000" << "MIRROR5" << "PRO5" << "360X";
|
||||
uint32_t CFG::model_codes[5] = { NM5000, NP5000, MIRROR5, PRO5, A360X};
|
||||
|
||||
bool CFG::_loadJSon()
|
||||
{
|
||||
// CLEAR
|
||||
while(CFG::items.count()) {
|
||||
CFG::items.pop_back();
|
||||
}
|
||||
|
||||
//QString jsonPath = ":/raw/cfg_5102.json";
|
||||
QString jsonPath = "";
|
||||
switch(info.model) {
|
||||
case NM5000:
|
||||
jsonPath = ":/raw/cfg_nm5000.json";
|
||||
break;
|
||||
case NP5000:
|
||||
jsonPath = ":/raw/cfg_np5000.json";
|
||||
break;
|
||||
case MIRROR5:
|
||||
jsonPath = ":/raw/cfg_mirror5.json";
|
||||
break;
|
||||
case PRO5:
|
||||
jsonPath = ":/raw/cfg_pro5.json";
|
||||
break;
|
||||
case A360X:
|
||||
jsonPath = ":/raw/cfg_360x.json";
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile file(jsonPath);
|
||||
if(file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
CFG::items = QJsonDocument::fromJson(data).array();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void CFG::_getItems(QJsonArray& in, QJsonArray& ret)
|
||||
{
|
||||
for(int i=0;i<in.size();i++) {
|
||||
QJsonObject obj = in.at(i).toObject();
|
||||
if(obj.contains("group") && obj.contains("items")) {
|
||||
_getItems(obj.value("items").toArray(),ret);
|
||||
}
|
||||
else {
|
||||
ret.append(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
void CFG::serializeItems(QJsonArray& citems) {
|
||||
_getItems(CFG::items,citems);
|
||||
return;
|
||||
}
|
||||
void CFG::setDefault()
|
||||
{
|
||||
QJsonArray citems;
|
||||
serializeItems(citems);
|
||||
for(int i=0;i<citems.size();i++) {
|
||||
QJsonObject obj = citems.at(i).toObject();
|
||||
|
||||
//qInfo() << obj << __FUNCTION__;
|
||||
|
||||
if(obj.contains("default") && obj.contains("offset")) {
|
||||
QString type = obj.value("type").toString();
|
||||
if(type == "int") {
|
||||
int offset = obj.value("offset").toInt();
|
||||
CFG::data[offset] = obj.value("default").toInt();
|
||||
//qInfo() << obj << __FUNCTION__;
|
||||
}
|
||||
}
|
||||
}
|
||||
//qInfo() << items << __FUNCTION__;
|
||||
|
||||
}
|
||||
void CFG::backup()
|
||||
{
|
||||
memcpy(CFG::stored,CFG::data,SETTINGS_CFG_SIZE);
|
||||
}
|
||||
void CFG::restore()
|
||||
{
|
||||
memcpy(CFG::data,CFG::stored,SETTINGS_CFG_SIZE);
|
||||
}
|
||||
bool CFG::isEdited()
|
||||
{
|
||||
return (0 != memcmp(CFG::stored,CFG::data,SETTINGS_CFG_SIZE-sizeof(_EMTINFO)));
|
||||
}
|
||||
CFG_ERROR_CODE CFG::load(QString path)
|
||||
{
|
||||
CFG_ERROR_CODE r = CFG_UNKNOWN_ERROR;
|
||||
if(!QFile::exists(path)) {
|
||||
return CFG_IO_ERROR;
|
||||
}
|
||||
|
||||
FILE* f = fopen(path.toLocal8Bit(),"r+b");
|
||||
if(f == NULL) {
|
||||
return CFG_IO_ERROR;
|
||||
}
|
||||
|
||||
unsigned char d[SETTINGS_CFG_SIZE] = {0,};
|
||||
size_t read = fread(d,1,SETTINGS_CFG_SIZE,f);
|
||||
fclose(f);
|
||||
if(read > 0)
|
||||
{
|
||||
cfgPath = path;
|
||||
memcpy(CFG::data,d,read);
|
||||
|
||||
// 나머지 영역 초기화???
|
||||
if(read == SETTINGS_CFG_SIZE) {
|
||||
memcpy(&CFG::info,&d[SETTINGS_CFG_SIZE-sizeof(_EMTINFO)],sizeof(_EMTINFO));
|
||||
//setDefault();
|
||||
r = verifyInfo();
|
||||
if(r != CFG_SUCCESS) {
|
||||
return r;
|
||||
}
|
||||
|
||||
_loadJSon();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setDefault();
|
||||
}
|
||||
|
||||
|
||||
CFG::backup(); // 현재 데이터 보존
|
||||
// CHECKSUM 확인
|
||||
if(!appUserSettingCheck()) {
|
||||
return CFG_CHECKSUM_ERROR;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
CFG_ERROR_CODE CFG::verifyInfo()
|
||||
{
|
||||
if(info.magic != 0xA5A5CC33) {
|
||||
return CFG_WRONG_FILE;
|
||||
}
|
||||
// Magnus : 5101
|
||||
// Trinity : 5102
|
||||
// Mirror5 : 5103
|
||||
// Pro5 : 5104
|
||||
// 360X : 5105
|
||||
// qInfo() << info.file1 << info.file2 << __FUNCTION__; // ?? 값이 정확하지 않음
|
||||
// qInfo() << "MODEL CODE:" << info.model << "FILE SIZE:" << info.file1 << info.file2 << __FUNCTION__;
|
||||
if(info.model < 5101 || info.model > 5105)
|
||||
{
|
||||
return CFG_WRONG_FILE;
|
||||
}
|
||||
return CFG_SUCCESS;
|
||||
}
|
||||
QString CFG::modelName()
|
||||
{
|
||||
for(int i=0;i<model_names.size();i++) {
|
||||
if(model_codes[i] == info.model) {
|
||||
return model_names.at(i);
|
||||
}
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
uint32_t CFG::version()
|
||||
{
|
||||
return info.version;
|
||||
}
|
||||
void CFG::clear()
|
||||
{
|
||||
memset(CFG::stored,0,SETTINGS_CFG_SIZE);
|
||||
memset(CFG::data,0,SETTINGS_CFG_SIZE);
|
||||
}
|
||||
|
||||
bool CFG::save(QString path)
|
||||
{
|
||||
bool bSuccess = false;
|
||||
|
||||
DWORD dwAttrib = ::GetFileAttributes((LPCTSTR)path.utf16());
|
||||
if((dwAttrib & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
::SetFileAttributes((LPCTSTR)path.utf16(),FILE_ATTRIBUTE_NORMAL);
|
||||
}
|
||||
|
||||
FILE* f = fopen(path.toLocal8Bit(),"w+b");
|
||||
if(f != NULL)
|
||||
{
|
||||
if(isEdited())
|
||||
{
|
||||
CFG::data[SD_VIEWSETTING_OFFSET] = 1;
|
||||
_updateCheckSum(); // 다시 계산
|
||||
}
|
||||
|
||||
size_t write = 0;
|
||||
write = fwrite(CFG::data,1,SETTINGS_CFG_SIZE,f);
|
||||
bSuccess = write > 0;
|
||||
fclose(f);
|
||||
|
||||
::SetFileAttributes((LPCTSTR)path.utf16(),FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN);
|
||||
}
|
||||
CFG::backup();
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
#define COMBINE_16(h, l) (uint16_t)((((uint16_t)h)<<8) | (uint16_t)l)
|
||||
uint16_t CFG::checkSum() // appGetSum16_Emt(uint16_t *Buf, uint32_t Size)
|
||||
{
|
||||
// 마지막 1은?
|
||||
uint32_t Size = ((SETTINGS_CFG_SIZE - sizeof(_EMTINFO)) / 2) - 1;
|
||||
|
||||
//uint8_t bSettingFileOK = TRUE;
|
||||
uint16_t* pbuf = (uint16_t*)&data[0];
|
||||
|
||||
uint16_t Sum = 0;
|
||||
uint32_t SumTemp = 0;
|
||||
while( Size )
|
||||
{
|
||||
SumTemp += (uint32_t)pbuf[--Size];
|
||||
}
|
||||
Sum = (uint16_t)((uint16_t)((SumTemp >> 16) & 0x0000ffff) | (uint16_t)(SumTemp & 0x0000ffff));
|
||||
return Sum;
|
||||
}
|
||||
void CFG::_updateCheckSum()
|
||||
{
|
||||
uint16_t c = checkSum();
|
||||
data[SETTINGS_CFG_SIZE-sizeof(_EMTINFO)-2] = ((c >> 8) & 0xFF);
|
||||
data[SETTINGS_CFG_SIZE-sizeof(_EMTINFO)-1] = (c & 0xFF);
|
||||
}
|
||||
bool CFG::appUserSettingCheck()
|
||||
{
|
||||
/*
|
||||
uint16_t* pbuf = (uint16_t*)&data[0];
|
||||
uint16_t checkSum, CalCheckSum;
|
||||
|
||||
// 설정 영역의 마지막 2BYTE
|
||||
uint8_t checkData1 = data[SETTINGS_CFG_SIZE-sizeof(_EMTINFO)-2];
|
||||
uint8_t checkData2 = data[SETTINGS_CFG_SIZE-sizeof(_EMTINFO)-1];
|
||||
|
||||
const uint32_t dataSize = SETTINGS_CFG_SIZE - sizeof(_EMTINFO);
|
||||
checkSum = COMBINE_16(checkData1, checkData2);
|
||||
CalCheckSum = appGetSum16_Emt(pbuf, (dataSize / 2)); // sizeof(uiParamSetting_t)
|
||||
return (checkSum != CalCheckSum);
|
||||
*/
|
||||
// 설정 영역의 마지막 2BYTE
|
||||
uint8_t checkData1 = data[SETTINGS_CFG_SIZE-sizeof(_EMTINFO)-2];
|
||||
uint8_t checkData2 = data[SETTINGS_CFG_SIZE-sizeof(_EMTINFO)-1];
|
||||
//qInfo() << "CHECKED:" << COMBINE_16(checkData1,checkData2) << "CALCED:" << checkSum() <<__FUNCTION__;
|
||||
return (COMBINE_16(checkData1,checkData2) == checkSum());
|
||||
}
|
||||
//uint16_t CFG::checkSum()
|
||||
//{
|
||||
// uint16_t* pbuf = (uint16_t*)&data[0];
|
||||
// const uint32_t dataSize = SETTINGS_CFG_SIZE - sizeof(_EMTINFO);
|
||||
// return appGetSum16_Emt(pbuf, (dataSize / 2) - 1);
|
||||
//}
|
||||
|
||||
#endif // #if (USE_DEVICE_SETTINGS && RM_MODEL_EMT_KR)
|
||||
101
project/fm_viewer/cfg/rm_settings_cfg_emt_kr.h
Normal file
101
project/fm_viewer/cfg/rm_settings_cfg_emt_kr.h
Normal file
@@ -0,0 +1,101 @@
|
||||
#ifndef RM_SETTINGS_CFG_EMT_KR_H
|
||||
#define RM_SETTINGS_CFG_EMT_KR_H
|
||||
#if (USE_DEVICE_SETTINGS && RM_MODEL_EMT_KR)
|
||||
#include <QObject>
|
||||
#include <QJsonArray>
|
||||
#include <stdint.h>
|
||||
|
||||
#define SETTINGS_CFG_SIZE 248 // 248 BYTE
|
||||
typedef enum
|
||||
{
|
||||
CFG_SUCCESS = 0, // 성공
|
||||
CFG_IO_ERROR = 1, // 파일 열기, 읽기 실패
|
||||
CFG_WRONG_FILE = 2, // 잘못된 파일 에러
|
||||
CFG_CHECKSUM_ERROR = 3, // 체크섬 확인실패
|
||||
// CFG_MODEL_CODE_ERROR = 3, // 모델코드 에러 UI 에서 확인
|
||||
CFG_UNKNOWN_ERROR = 99, // ??
|
||||
} CFG_ERROR_CODE;
|
||||
|
||||
typedef struct _EMTINFO
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t model; //micom ver : 31 ~ 16, model : 15 ~ 0
|
||||
uint32_t version;//F/W version
|
||||
uint32_t file1; //1 bit + 31 bit ( 1 : file exist, 31 : file size )
|
||||
uint32_t file2; //1 bit + 31 bit ( 1 : file exist, 31 : file size )
|
||||
} EMTINFO;
|
||||
|
||||
// 제품 코드에 따라 설정항목이 달라짐
|
||||
// NM5000(5101),MIRROR5(5103) = MAGNUS
|
||||
// NP5000(5102),PRO5(5104) = TRINITY
|
||||
typedef enum
|
||||
{
|
||||
NM5000 = 5101, // NM5000 OFFLINE
|
||||
NP5000 = 5102, // TRINITY OFFLINE
|
||||
MIRROR5 = 5103, // Mirror5(MAGNUS ONLINE)
|
||||
PRO5 = 5104, // Pro5(TRINITY ONLINE)
|
||||
A360X = 5105, // Cyclops = 360X
|
||||
} MODEL_CODE;
|
||||
|
||||
// 설정 편집시 1로 지정해야 하는 OFFSET
|
||||
#define SD_VIEWSETTING_OFFSET 143
|
||||
|
||||
class CFG : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QString cfgPath;
|
||||
static QStringList model_names;// = QStringList() << "NM5000" << "NP5000";
|
||||
static uint32_t model_codes[];// = { 5101, 5102};
|
||||
|
||||
static QJsonArray items;
|
||||
static QJsonObject _findType(QString key,int* index);
|
||||
|
||||
static unsigned char data[SETTINGS_CFG_SIZE];
|
||||
static unsigned char stored[SETTINGS_CFG_SIZE];
|
||||
static EMTINFO info;
|
||||
|
||||
//! \brief 모델에 따른 JSON 파일 확인
|
||||
//! \return
|
||||
static bool _loadJSon();
|
||||
static CFG_ERROR_CODE load(QString path);
|
||||
static bool save(QString path);
|
||||
|
||||
static void backup();
|
||||
static void restore();
|
||||
static void setDefault();
|
||||
//! \brief 데이터 수정여부 확인
|
||||
//! \return
|
||||
static bool isEdited();
|
||||
|
||||
static void clear();
|
||||
|
||||
static QString modelName();
|
||||
static uint32_t version();
|
||||
|
||||
private:
|
||||
//! \brief 모델정보등 검증
|
||||
//! \return
|
||||
static CFG_ERROR_CODE verifyInfo();
|
||||
//static uint16_t appGetSum16_Emt(); // uint16_t *Buf, uint32_t Size
|
||||
static bool appUserSettingCheck();
|
||||
|
||||
// 현재 데이터 CHECKSUM 계산하여 반영
|
||||
static void _updateCheckSum();
|
||||
|
||||
// 설정항목을 그룹 제외하고 직렬화
|
||||
static void _getItems(QJsonArray& in, QJsonArray& ret);
|
||||
static void serializeItems(QJsonArray& citems);
|
||||
|
||||
// checkData1 << 8 | checkData2
|
||||
//! \brief EMTINFO 를 제외한 데이터를 확인하여
|
||||
//! \return checkData1 << 8 | checkData2
|
||||
static uint16_t checkSum();
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
#endif // #if (USE_DEVICE_SETTINGS && RM_MODEL_EMT_KR)
|
||||
#endif // RM_SETTINGS_CFG_EMT_KR_H
|
||||
301
project/fm_viewer/cfg/rm_settings_cfg_standard.cpp
Normal file
301
project/fm_viewer/cfg/rm_settings_cfg_standard.cpp
Normal file
@@ -0,0 +1,301 @@
|
||||
#include "rm_settings_cfg_standard.h"
|
||||
#if (USE_DEVICE_SETTINGS && !(RM_MODEL_EMT_KR))
|
||||
|
||||
#include <QDebug>
|
||||
#include <stdio.h>
|
||||
#include <QFile>
|
||||
|
||||
#if !(RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
unsigned char CFG::data[SETTINGS_CFG_SIZE] = {0,};
|
||||
unsigned char CFG::stored[SETTINGS_CFG_SIZE] = {0,};
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
|
||||
#if (ENCODE_CFG_BASE64)
|
||||
#include "fm_base64.h"
|
||||
#endif // ENCODE_CFG_BASE64
|
||||
|
||||
QJsonArray CFG::items;
|
||||
|
||||
QJsonObject CFG::_findType(QString key, int* index)
|
||||
{
|
||||
for(int i=0;i<items.size();i++) {
|
||||
QJsonObject obj = items.at(i).toObject();
|
||||
if(obj.value("key").toString() == key) {
|
||||
*index = i;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
*index = -1;
|
||||
return QJsonObject();
|
||||
}
|
||||
#endif // AN6000
|
||||
|
||||
#if (ENCODE_CFG_BASE64)
|
||||
bool CFG::isEncoded = false;
|
||||
#endif // #if (ENCODE_CFG_BASE64)
|
||||
|
||||
void CFG::setDefault()
|
||||
{
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
// CLEAR
|
||||
while(CFG::items.count()) {
|
||||
CFG::items.pop_back();
|
||||
}
|
||||
#if (AN6000_YEC)
|
||||
const char* fname = ":/html/an6000_cfg_yec.json";
|
||||
#else
|
||||
const char* fname = ":/html/an6000_cfg.json";
|
||||
#endif
|
||||
|
||||
QFile file(fname); // ":/html/an6000_cfg.json"
|
||||
if(file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
CFG::items = QJsonDocument::fromJson(data).array();
|
||||
}
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
|
||||
for(int i=0;i<items.size();i++) {
|
||||
QJsonObject obj = items.at(i).toObject();
|
||||
if(obj.contains("default")) {
|
||||
QString type = obj.value("type").toString();
|
||||
if(type == "int") {
|
||||
obj.insert("current",QJsonValue(obj.value("default").toInt()));
|
||||
}
|
||||
else if(type == "text") {
|
||||
obj.insert("current",QJsonValue(obj.value("default").toString()));
|
||||
}
|
||||
items.replace(i,obj); // 반영
|
||||
}
|
||||
}
|
||||
//qInfo() << items << __FUNCTION__;
|
||||
#else // !RM_MODEL_TYPE_AN6000
|
||||
// CS-32FH
|
||||
unsigned char def[SETTINGS_CFG_SIZE] = {0x00,// 0
|
||||
0x00,// 1
|
||||
0x00,// 2
|
||||
0x00,// 3
|
||||
0x00,// 4
|
||||
0x00,// 5
|
||||
0x00,// 6
|
||||
0x00,// 7
|
||||
0x00,// 8
|
||||
0x00,// 9
|
||||
0x00,// 10
|
||||
0x00,// 11
|
||||
0x00,// 12
|
||||
0x00,// 13
|
||||
0x00,// 14
|
||||
0x00,// 15
|
||||
0x00,// 16
|
||||
0x00,// 17
|
||||
0x00,// 18
|
||||
0x00,// 19
|
||||
0x00,// 20
|
||||
0x02,// 21 // SD_SENSOR = SENSOR_MIDDLE
|
||||
0x00,// 22 // SD_SIZE = SIZE_800x600
|
||||
0x00,// 23 // SD_FRAME = FRAME_20
|
||||
0x04,// 24 // SD_VOLUME = VOLUME_4
|
||||
0x01,// 25 // SD_VOICE = VOICE_ENABLE
|
||||
0x00 // RESERVED
|
||||
};
|
||||
memcpy(CFG::data,def,SETTINGS_CFG_SIZE);
|
||||
#endif // RM_MODEL_TYPE_AN6000
|
||||
}
|
||||
void CFG::backup()
|
||||
{
|
||||
#if !(RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
memcpy(CFG::stored,CFG::data,SETTINGS_CFG_SIZE);
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
}
|
||||
|
||||
void CFG::restore()
|
||||
{
|
||||
#if !(RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
memcpy(CFG::data,CFG::stored,SETTINGS_CFG_SIZE);
|
||||
#endif // #if !(RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
}
|
||||
|
||||
|
||||
bool CFG::load(QString path)
|
||||
{
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
// CLEAR
|
||||
while(CFG::items.count()) {
|
||||
CFG::items.pop_back();
|
||||
}
|
||||
#if (AN6000_YEC)
|
||||
const char* fname = ":/html/an6000_cfg_yec.json";
|
||||
#else
|
||||
const char* fname = ":/html/an6000_cfg.json";
|
||||
#endif
|
||||
QFile file(fname); // ":/html/an6000_cfg.json"
|
||||
if(file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
CFG::items = QJsonDocument::fromJson(data).array();
|
||||
setDefault();
|
||||
}
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
|
||||
|
||||
bool bSuccess = false;
|
||||
if(QFile::exists(path)) {
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
#if (ENCODE_CFG_BASE64)
|
||||
QStringList lines = FMBase64::load(path,&isEncoded);
|
||||
qInfo() << lines << __FUNCTION__;
|
||||
for(int i=0;i<lines.size();i++) {
|
||||
QString line = lines.at(i);
|
||||
QStringList items = line.split('=');
|
||||
if(items.size() != 2) {
|
||||
qInfo() << "ERROR:" << line << __FUNCTION__;
|
||||
continue;
|
||||
}
|
||||
QString key = items.at(0);
|
||||
key = key.trimmed();
|
||||
QString value = items.at(1);
|
||||
value = value.trimmed();
|
||||
|
||||
int kidx = -1;
|
||||
QJsonObject obj = _findType(key,&kidx);
|
||||
if(obj.isEmpty() || kidx < 0) {
|
||||
qInfo() << "KEY ERROR:" << line << __FUNCTION__;
|
||||
continue;
|
||||
}
|
||||
QString otype = obj.value("type").toString();
|
||||
if(otype == "text") {
|
||||
obj.insert("current",QJsonValue(value));
|
||||
CFG::items.replace(kidx,obj);
|
||||
} else if (otype == "int") {
|
||||
obj.insert("current",QJsonValue(value.toInt()));
|
||||
CFG::items.replace(kidx,obj);
|
||||
}
|
||||
}
|
||||
#else // #if (ENCODE_CFG_BASE64)
|
||||
QFile file(path);
|
||||
if(file.exists() && file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QTextStream in(&file);
|
||||
while(!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
QStringList items = line.split('=');
|
||||
if(items.size() != 2) {
|
||||
qInfo() << "ERROR:" << line << __FUNCTION__;
|
||||
continue;
|
||||
}
|
||||
QString key = items.at(0);
|
||||
key = key.trimmed();
|
||||
QString value = items.at(1);
|
||||
value = value.trimmed();
|
||||
|
||||
int kidx = -1;
|
||||
QJsonObject obj = _findType(key,&kidx);
|
||||
if(obj.isEmpty() || kidx < 0) {
|
||||
qInfo() << "KEY ERROR:" << line << __FUNCTION__;
|
||||
continue;
|
||||
}
|
||||
QString otype = obj.value("type").toString();
|
||||
if(otype == "text") {
|
||||
obj.insert("current",QJsonValue(value));
|
||||
CFG::items.replace(kidx,obj);
|
||||
} else if (otype == "int") {
|
||||
obj.insert("current",QJsonValue(value.toInt()));
|
||||
CFG::items.replace(kidx,obj);
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
#endif // #else // #if (ENCODE_CFG_BASE64)
|
||||
#else // !AN6000
|
||||
FILE* f = fopen(path.toLocal8Bit(),"r+b");
|
||||
if(f != NULL)
|
||||
{
|
||||
unsigned char d[SETTINGS_CFG_SIZE] = {0,};
|
||||
size_t read = fread(d,1,SETTINGS_CFG_SIZE,f);
|
||||
fclose(f);
|
||||
#if (CFG_SEARCH_DISK)
|
||||
bSuccess = read > 0 && strncmp(SETTINGS_TAG,(const char*)d,strlen(SETTINGS_TAG)) == 0;
|
||||
#else
|
||||
bSuccess = read > 0;
|
||||
#endif
|
||||
if(bSuccess == true)
|
||||
{
|
||||
memcpy(CFG::data,d,SETTINGS_CFG_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
setDefault();
|
||||
}
|
||||
}
|
||||
#endif // #else // !AN6000
|
||||
}
|
||||
CFG::backup(); // 현재 데이터 보존
|
||||
return bSuccess;
|
||||
}
|
||||
bool CFG::save(QString path)
|
||||
{
|
||||
bool bSuccess = false;
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
|
||||
#if (ENCODE_CFG_BASE64)
|
||||
QStringList lines = QStringList();
|
||||
for(int i=0;i<items.size();i++) {
|
||||
QJsonObject obj = items.at(i).toObject();
|
||||
QString type = obj.value("type").toString();
|
||||
QString line;
|
||||
line += obj.value("key").toString();
|
||||
line += "=";
|
||||
if(type == "int") {
|
||||
line += QString::number(obj.value("current").toInt());
|
||||
} else if (type == "text") {
|
||||
line += obj.value("current").toString();
|
||||
}
|
||||
lines.append(line);
|
||||
}
|
||||
FMBase64::save(path,lines,true); // isEncoded // 항상 인코딩된 상태로 저장
|
||||
#else // ENCODE_CFG_BASE64
|
||||
QFile file(path);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
QTextStream stream(&file);
|
||||
//stream << "something" << endl;
|
||||
for(int i=0;i<items.size();i++) {
|
||||
QJsonObject obj = items.at(i).toObject();
|
||||
QString type = obj.value("type").toString();
|
||||
QString line;
|
||||
line += obj.value("key").toString();
|
||||
line += "=";
|
||||
if(type == "int") {
|
||||
line += QString::number(obj.value("current").toInt());
|
||||
} else if (type == "text") {
|
||||
line += obj.value("current").toString();
|
||||
}
|
||||
stream << line << endl;
|
||||
qInfo() << line << __FUNCTION__;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
#endif // ENCODE_CFG_BASE64
|
||||
|
||||
|
||||
#else // !AN6000
|
||||
FILE* f = fopen(path.toLocal8Bit(),"w+b");
|
||||
if(f != NULL)
|
||||
{
|
||||
size_t write = fwrite(CFG::data,1,SETTINGS_CFG_SIZE,f);
|
||||
bSuccess = write > 0;
|
||||
fclose(f);
|
||||
}
|
||||
#endif // #if (RM_MODEL = RM_MODEL_TYPE_AN6000)
|
||||
CFG::backup();
|
||||
return bSuccess;
|
||||
}
|
||||
#endif // #if (USE_DEVICE_SETTINGS && !(RM_MODEL_EMT_KR))
|
||||
54
project/fm_viewer/cfg/rm_settings_cfg_standard.h
Normal file
54
project/fm_viewer/cfg/rm_settings_cfg_standard.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef RM_SETTINGS_CFG_STANDARD_H
|
||||
#define RM_SETTINGS_CFG_STANDARD_H
|
||||
#if (USE_DEVICE_SETTINGS && !(RM_MODEL_EMT_KR))
|
||||
#include "../rm_include.h"
|
||||
|
||||
|
||||
#include <QObject>
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
#include <QJsonArray>
|
||||
#endif
|
||||
|
||||
#if !(RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
#define SETTINGS_CFG_SIZE 0x2D // 45 BYTE
|
||||
typedef enum
|
||||
{
|
||||
SD_SENSOR = 21, // SENSOR_LOW = 0, SENSOR_LOW_MID, SENSOR_MIDDLE, SENSOR_MID_HI,SENSOR_HIGH
|
||||
SD_SIZE = 22, // SIZE_800x600, SIZE_640x320
|
||||
SD_FRAME = 23, // FRAME_20, FRAME_25, FRAME_30
|
||||
SD_VOLUME = 24, // VOLUME_0~5
|
||||
SD_VOICE = 25, // VOICE_DISABLE, VOICE_ENABLE
|
||||
} SD_TYPE;
|
||||
#endif // !RM_MODEL_TYPE_AN6000
|
||||
class CFG : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
#if (ENCODE_CFG_BASE64)
|
||||
static bool isEncoded; // 암호화 되지 않은 CFG 파일의 경우 저장시에도 암호화 하지 않음
|
||||
#endif // ENCODE_CFG_BASE64
|
||||
static QJsonArray items;
|
||||
static QJsonObject _findType(QString key,int* index);
|
||||
#else
|
||||
static unsigned char data[SETTINGS_CFG_SIZE];
|
||||
static unsigned char stored[SETTINGS_CFG_SIZE];
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
|
||||
static bool load(QString path);
|
||||
static bool save(QString path);
|
||||
|
||||
static void backup();
|
||||
static void restore();
|
||||
|
||||
static void setDefault();
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
//#endif // #if (RM_MODEL == RM_SETTINGS_CFG_STANDARD_H)
|
||||
#endif // (USE_DEVICE_SETTINGS && !(RM_MODEL_EMT_KR))
|
||||
#endif // RM_SETTINGS_CFG_STANDARD_H
|
||||
199
project/fm_viewer/cfg/rm_settings_cfg_xdr6688.cpp
Normal file
199
project/fm_viewer/cfg/rm_settings_cfg_xdr6688.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
#include "rm_settings_cfg_xdr6688.h"
|
||||
#if (USE_DEVICE_SETTINGS)
|
||||
|
||||
#include <QDebug>
|
||||
#include <stdio.h>
|
||||
#include <QFile>
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
unsigned char CFG::data[SETTINGS_CFG_SIZE] = {0,};
|
||||
unsigned char CFG::stored[SETTINGS_CFG_SIZE] = {0,};
|
||||
MODEL_XDR CFG::model = MODEL_XDR_NOT_DEFINED;
|
||||
|
||||
|
||||
|
||||
void CFG::setDefault()
|
||||
{
|
||||
switch (CFG::model) {
|
||||
case MODEL_XDR_66:
|
||||
CFG66::setDefault();
|
||||
break;
|
||||
case MODEL_XDR_88:
|
||||
CFG88::setDefault();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void CFG::backup()
|
||||
{
|
||||
memcpy(CFG::stored,CFG::data,SETTINGS_CFG_SIZE);
|
||||
}
|
||||
|
||||
void CFG::restore()
|
||||
{
|
||||
memcpy(CFG::data,CFG::stored,SETTINGS_CFG_SIZE);
|
||||
}
|
||||
QString CFG::modelName()
|
||||
{
|
||||
switch (CFG::model)
|
||||
{
|
||||
case MODEL_XDR_66:
|
||||
return "XDR-66";
|
||||
case MODEL_XDR_88:
|
||||
return "XLDR-88";
|
||||
default:
|
||||
qInfo() << "MODEL NOT DEFINED";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
bool CFG::setModel(QString modelString)
|
||||
{
|
||||
bool bSuccess = true;
|
||||
if(modelString == "XDR-66") {
|
||||
CFG::model = MODEL_XDR_66;
|
||||
}
|
||||
else if(modelString == "XLDR-88") {
|
||||
CFG::model = MODEL_XDR_88;
|
||||
}
|
||||
else
|
||||
{
|
||||
bSuccess = false;
|
||||
}
|
||||
return bSuccess;
|
||||
}
|
||||
bool CFG::load(QString path)
|
||||
{
|
||||
bool bSuccess = false;
|
||||
if(QFile::exists(path)) {
|
||||
FILE* f = fopen(path.toLocal8Bit(),"r+b");
|
||||
if(f != NULL)
|
||||
{
|
||||
size_t readSize = (model == MODEL_XDR_66) ? SETTINGS_CFG_SIZE : SETTINGS_CFG_SIZE_88;
|
||||
unsigned char d[SETTINGS_CFG_SIZE] = {0,};
|
||||
size_t read = fread(d,1,SETTINGS_CFG_SIZE,f);
|
||||
fclose(f);
|
||||
#if (CFG_SEARCH_DISK)
|
||||
bSuccess = read > 0 && strncmp(SETTINGS_TAG,(const char*)d,strlen(SETTINGS_TAG)) == 0;
|
||||
#else
|
||||
bSuccess = read > 0;
|
||||
#endif
|
||||
|
||||
if(bSuccess == true)
|
||||
{
|
||||
memcpy(CFG::data,d,read);
|
||||
// EMS 데이터로 나머지는 초기화 해야함
|
||||
if(read != readSize) {
|
||||
setDefault();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
CFG::backup(); // 현재 데이터 보존
|
||||
return bSuccess;
|
||||
}
|
||||
bool CFG::save(QString path)
|
||||
{
|
||||
bool bSuccess = false;
|
||||
FILE* f = fopen(path.toLocal8Bit(),"w+b");
|
||||
if(f != NULL)
|
||||
{
|
||||
size_t write = 0;
|
||||
if(model == MODEL_XDR_88) {
|
||||
write = fwrite(CFG::data,1,SETTINGS_CFG_SIZE_88,f);
|
||||
}
|
||||
else {
|
||||
write = fwrite(CFG::data,1,SETTINGS_CFG_SIZE,f);
|
||||
}
|
||||
bSuccess = write > 0;
|
||||
fclose(f);
|
||||
}
|
||||
CFG::backup();
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
void CFG66::setDefault() {
|
||||
// XDR-66
|
||||
// SD_SENSOR = 21, // SENSOR_LOW = 0, SENSOR_LOW_MID, SENSOR_MIDDLE, SENSOR_MID_HI,SENSOR_HIGH
|
||||
// SD_SIZE = 22, // SIZE_800x600, SIZE_640x320
|
||||
// SD_FRAME = 23, // FRAME_20, FRAME_25, FRAME_30
|
||||
// SD_VOLUME = 24, // VOLUME_0~5
|
||||
// SD_VOICE = 25, // VOICE_DISABLE, VOICE_ENABLE
|
||||
|
||||
unsigned char def[SETTINGS_CFG_SIZE] = { 0x00,// 0
|
||||
0x00,// 1
|
||||
0x00,// 2
|
||||
0x00,// 3
|
||||
0x00,// 4
|
||||
0x00,// 5
|
||||
0x00,// 6
|
||||
0x00,// 7
|
||||
0x00,// 8
|
||||
0x00,// 9
|
||||
0x00,// 10
|
||||
0x00,// 11
|
||||
0x00,// 12
|
||||
0x00,// 13
|
||||
0x00,// 14
|
||||
0x00,// 15
|
||||
0x00,// 16
|
||||
0x00,// 17
|
||||
0x00,// 18
|
||||
0x00,// 19
|
||||
0x00,// 20
|
||||
0x02,// 21 // SD_SENSOR = SENSOR_MIDDLE
|
||||
0x00,// 22 // SD_SIZE = SIZE_800x600
|
||||
0x00,// 23 // SD_FRAME = FRAME_20
|
||||
0x04,// 24 // SD_VOLUME = VOLUME_4
|
||||
0x01,// 25 // SD_VOICE = VOICE_ENABLE
|
||||
0x00 // RESERVED
|
||||
};
|
||||
// 부분만 초기화함
|
||||
memcpy(&CFG::data[21],&def[21],5);
|
||||
}
|
||||
void CFG88::setDefault() {
|
||||
// XLDR-88
|
||||
unsigned char def[SETTINGS_CFG_SIZE_88] = { 0x00,// 0
|
||||
0x00,// 1
|
||||
0x00,// 2
|
||||
0x00,// 3
|
||||
0x00,// 4
|
||||
0x00,// 5
|
||||
0x00,// 6
|
||||
0x00,// 7
|
||||
0x00,// 8
|
||||
0x00,// 9
|
||||
0x00,// 10
|
||||
0x00,// 11
|
||||
0x00,// 12
|
||||
0x00,// 13
|
||||
0x00,// 14
|
||||
0x00,// 15
|
||||
0x00,// 16
|
||||
0x01,// 17 // SD88_SCREEN_SAVEER
|
||||
0x02,// 18 // SD88_SCREEN_PIP
|
||||
0x03,// 19 // SD88_SPEAKER
|
||||
0x01,// 20 // SD88_MIC
|
||||
0x00,// 21 // SD88_VOLUME
|
||||
0x02,// 22 // SD88_GSENSOR_NORMAL
|
||||
0x02,// 23 // SD88_GSENSOR_PARKING
|
||||
0x00,// 24 // SD88_PARKING_ON (2021/04/01 OFF)
|
||||
0x00,// 25 // SD88_PARKING_VOLTAGE
|
||||
0x00,// 26 // SD88_VIDEO_RESOLUTION
|
||||
0x01,// 27 // SD88_ADMIN_PW (SD88_VIDEO_QUALITY) -> 비밀번호 ON:/OFF1
|
||||
0x02,// 28 // SD88_VIDEO_FRAME
|
||||
0x01,// 29 // SD88_VIDEO_SUB_CAMERA
|
||||
0x01,// 30 // SD88_VIDEO_HDR
|
||||
0x01,// 31 // SD88_VIDEO_NIGHT_VISION (2021/04/01 OFF)
|
||||
};
|
||||
// 부분만 초기화 함
|
||||
//memcpy(&CFG::data[11],&def[11],21);
|
||||
memcpy(&CFG::data[17],&def[17],15);
|
||||
|
||||
//memcpy(CFG::data,def,SETTINGS_CFG_SIZE_88);
|
||||
}
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
106
project/fm_viewer/cfg/rm_settings_cfg_xdr6688.h
Normal file
106
project/fm_viewer/cfg/rm_settings_cfg_xdr6688.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#ifndef RM_SETTINGS_CFG_XDR6688_H
|
||||
#define RM_SETTINGS_CFG_XDR6688_H
|
||||
#if (USE_DEVICE_SETTINGS)
|
||||
#include "../rm_include.h"
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
|
||||
#include <QObject>
|
||||
#define SETTINGS_CFG_SIZE 45 // 45 BYTE
|
||||
#define SETTINGS_CFG_SIZE_88 0x20 // 32 BYTE
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MODEL_XDR_NOT_DEFINED = 0,
|
||||
MODEL_XDR_66 = 1,
|
||||
MODEL_XDR_88 = 2,
|
||||
} MODEL_XDR;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SD_SENSOR = 21, // SENSOR_LOW = 0, SENSOR_LOW_MID, SENSOR_MIDDLE, SENSOR_MID_HI,SENSOR_HIGH
|
||||
SD_SIZE = 22, // SIZE_800x600, SIZE_640x320
|
||||
SD_FRAME = 23, // FRAME_20, FRAME_25, FRAME_30
|
||||
SD_VOLUME = 24, // VOLUME_0~5
|
||||
SD_VOICE = 25, // VOICE_DISABLE, VOICE_ENABLE
|
||||
} SD_TYPE_66;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SD88_ADMIN_PW = 27, // 관리자 암호 지정 0:ON 1:OFF
|
||||
|
||||
// SYSTEM システム
|
||||
SD88_SCREEN_SAVEER = 17, // 画面表示, 1分後画面OFF, 常時ON, 1分後時計画面
|
||||
SD88_SCREEN_PIP = 18, // 録画画面, フロント, リア, フロント/リア,リア/フロント
|
||||
SD88_SPEAKER = 19, // Off,1 Level,2 Level,3 Level,4 Level,5 Level
|
||||
SD88_MIC = 20, // Off, On
|
||||
|
||||
// STORAGE, メモリ割当
|
||||
SD88_VOLUME = 21, // メモリ割当: 常時録画重視, 駐車録画重視, イベント録画重視
|
||||
|
||||
// G-SENSOR, センサー感度
|
||||
SD88_GSENSOR_NORMAL = 22, // 常時センサー感度: Off, Low, Middle-Low, Middle, Middle-High, High
|
||||
SD88_GSENSOR_PARKING = 23, // 駐車センサー感度: Off, Low, Middle-Low, Middle, Middle-High, High
|
||||
|
||||
// PARKING MODE, 駐車録画
|
||||
SD88_PARKING_ON = 24, // 駐車録画機能: Off, On
|
||||
SD88_PARKING_VOLTAGE = 25, // 放電遮断電圧: 표시만
|
||||
|
||||
// VIDEO, 録画設定
|
||||
SD88_VIDEO_RESOLUTION = 26, // 解像度: "1920*1080", "1280*720"
|
||||
//SD88_VIDEO_QUALITY = 27, // 画質: 低,中, 高
|
||||
SD88_VIDEO_FRAME = 28, // 録画フレーム数: 4.9,19.1,29.1
|
||||
SD88_VIDEO_SUB_CAMERA = 29, // サブカメラ録画: Off, On
|
||||
SD88_VIDEO_HDR = 30, // HDR: Off, On
|
||||
SD88_VIDEO_NIGHT_VISION = 31, // ナイトビジョン: Off, On
|
||||
} SD_TYPE_88;
|
||||
|
||||
class CFG : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static MODEL_XDR model;
|
||||
static QString modelName();
|
||||
static bool setModel(QString modelString);
|
||||
|
||||
static unsigned char data[SETTINGS_CFG_SIZE];
|
||||
static unsigned char stored[SETTINGS_CFG_SIZE];
|
||||
|
||||
static bool load(QString path);
|
||||
static bool save(QString path);
|
||||
|
||||
static void backup();
|
||||
static void restore();
|
||||
|
||||
static void setDefault();
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
// XDR-66
|
||||
class CFG66 : public CFG
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static void setDefault();
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
// XDR-88
|
||||
class CFG88 : public CFG
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static void setDefault();
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
|
||||
#endif // #if (RM_MODEL)
|
||||
#endif
|
||||
#endif // RM_SETTINGS_CFG_XDR6688_H
|
||||
442
project/fm_viewer/cfg/rm_settings_window_base.cpp
Normal file
442
project/fm_viewer/cfg/rm_settings_window_base.cpp
Normal file
@@ -0,0 +1,442 @@
|
||||
#include "rm_settings_window_base.h"
|
||||
#if (USE_DEVICE_SETTINGS && !USE_DEVICE_SETTINGS_JSON)
|
||||
|
||||
#include "../fm_dimensions.h"
|
||||
|
||||
#include "../ui/title_widget.h"
|
||||
#include "rm_combo_box.h"
|
||||
#include "rm_radio_buttons.h"
|
||||
#include "rm_group_combo_box.h"
|
||||
#include "rm_group_radio_buttons.h"
|
||||
#include "../core/fm_strings.h"
|
||||
#include "rm_settings_cfg.h"
|
||||
#include <QComboBox>
|
||||
#include <QGridLayout>
|
||||
#include <QDir>
|
||||
|
||||
#if (SETTINGS_WINDOW_SCROLL)
|
||||
#include <QScrollArea>
|
||||
#include <QScrollBar>
|
||||
#include "../ui/fm_colors.h"
|
||||
#endif
|
||||
|
||||
#if (DETECT_SETTING_USB_EJECT && !DETECT_USB_CHANGE)
|
||||
#include "../core/rm_usb.h"
|
||||
#include "../rm_application.h"
|
||||
#endif
|
||||
|
||||
// 문자열 처리 UTF
|
||||
// https://www.branah.com/unicode-converter
|
||||
|
||||
//bool RMSettingsWindowBase::loaded = false;
|
||||
QString RMSettingsWindowBase::lastSettingDisk = "";
|
||||
|
||||
//const int gComboBoxWidth = 200;
|
||||
//const int gTitleWidth = 50;
|
||||
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
static const QStringList gOnOff = QStringList() << "ON" << "OFF";
|
||||
#else // RM_MODEL_EMT_KR
|
||||
static const QStringList gOnOff = QStringList() << MKU8("\xe3\x82\xaa\xe3\x83\xb3") << MKU8("\xe3\x82\xaa\xe3\x83\x95");
|
||||
#endif // RM_MODEL_EMT_KR
|
||||
static const QStringList gEOnOff = QStringList() << "ON" << "OFF";
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
RMSettingsWindowBase::RMSettingsWindowBase(QWidget *parent) : RMPopup(parent,FMS::txt("settings"),"")
|
||||
#else
|
||||
RMSettingsWindowBase::RMSettingsWindowBase(QWidget *parent) : RMPopup(parent,"","title_settings.png")
|
||||
#endif
|
||||
{
|
||||
// 이미 로딩됨
|
||||
#if !(RM_MODEL_EMT_KR)
|
||||
QString path = QDir::cleanPath(lastSettingDisk + SETTINGS_FILE_NAME);
|
||||
|
||||
// 모델 디스크가 아닐 경우
|
||||
#if (MULTI_MODEL_VIEWER)
|
||||
if(RMApp::isModelDisk(lastSettingDisk,NULL) == false)
|
||||
#else // MULTI_MODEL_VIEWER
|
||||
if(RMApp::isModelDisk(lastSettingDisk) == false)
|
||||
#endif // MULTI_MODEL_VIEWER
|
||||
{
|
||||
CFG::setDefault();
|
||||
#if !(DO_NOT_MAKE_CFG)
|
||||
CFG::save(path);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
CFG::load(path);
|
||||
}
|
||||
#endif // #if !(RM_MODEL_EMT_KR)
|
||||
#if (SETTINGS_WINDOW_SCROLL)
|
||||
this->setFixedSize(SETTINGS_WINDOW_WIDTH,SETTINGS_WiNDOW_SCROLL_HEIGHT);
|
||||
#else
|
||||
this->setFixedSize(SETTINGS_WINDOW_WIDTH,SETTINGS_WiNDOW_HEIGHT);
|
||||
#endif
|
||||
|
||||
//_contentWidget->setObjectName("bg_dark_widget");
|
||||
layout = new QHBoxLayout(_contentWidget);
|
||||
layout->setMargin(8);
|
||||
layout->setSpacing(8);
|
||||
|
||||
QWidget* bwLeft = new QWidget(_buttonWidget);
|
||||
_buttonLayout->addWidget(bwLeft);
|
||||
|
||||
QWidget* bwRight = new QWidget(_buttonWidget);
|
||||
_buttonLayout->addWidget(bwRight);
|
||||
|
||||
QHBoxLayout* blLeft = new QHBoxLayout(bwLeft);
|
||||
blLeft->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
|
||||
|
||||
QHBoxLayout* blRight = new QHBoxLayout(bwRight);
|
||||
blRight->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
||||
#if (LIVE_LANGUAGE2)
|
||||
RMButton* defaultButton = RMButton::create2(bwRight,blRight,"button","default",QSize(120,30));
|
||||
defaultButton->setText(FMS::txt("default"));
|
||||
connect(defaultButton,SIGNAL(clicked()),SLOT(onDefault()));
|
||||
|
||||
RMButton* okButton = RMButton::create2(bwRight,blRight,"button","ok",QSize(120,30));
|
||||
okButton->setText(FMS::txt("ok"));
|
||||
connect(okButton,SIGNAL(clicked()),this,SLOT(onSaveAnAccept()));
|
||||
|
||||
RMButton* cancelButton = RMButton::create2(bwRight,blRight,"button","cancel",QSize(120,30));
|
||||
cancelButton->setText(FMS::txt("cancel"));
|
||||
connect(cancelButton,SIGNAL(clicked()),this,SLOT(onCancel()));
|
||||
#else // LIVE_LANGUAGE2
|
||||
// 初期値
|
||||
QString title = MKU8("\xe5\x88\x9d\xe6\x9c\x9f\xe5\x80\xa4");
|
||||
#if (LIVE_LANGUAGE_CHANGE)
|
||||
if(RMLanguage::isJP() == false) { title = "Reset"; }
|
||||
#endif
|
||||
RMButton* defaultButton = RMButton::create(bwRight,blRight,"button",FMS::txt("default"),QSize(120,30));
|
||||
|
||||
//RMButton* defaultButton = RMButton::create(bwLeft,blLeft,"popup_button",title,QSize(120,30));
|
||||
defaultButton->setText(FMS::txt("default"));
|
||||
connect(defaultButton,SIGNAL(clicked()),SLOT(onDefault()));
|
||||
|
||||
|
||||
// 適用
|
||||
title = MKU8("\xe9\x81\xa9\xe7\x94\xa8");
|
||||
#if (LIVE_LANGUAGE_CHANGE)
|
||||
if(RMLanguage::isJP() == false) { title = "Save";}
|
||||
#endif
|
||||
|
||||
//#if !(MODEL_WATEX)
|
||||
// RMButton* applyButton = RMButton::create(bwRight,blRight,"popup_button",title,QSize(120,30));
|
||||
// applyButton->setText(title);
|
||||
// connect(applyButton,SIGNAL(clicked()),this,SLOT(onSave()));
|
||||
//#endif
|
||||
|
||||
RMButton* okButton = RMButton::create(bwRight,blRight,"button",FMS::txt("ok"),QSize(120,30));
|
||||
//RMButton* okButton = RMButton::create(bwRight,blRight,"popup_button",QString("OK"),QSize(120,30));
|
||||
okButton->setText(FMS::txt("ok"));
|
||||
connect(okButton,SIGNAL(clicked()),this,SLOT(onSaveAnAccept()));
|
||||
|
||||
|
||||
#if (MODEL_WATEX)
|
||||
title = MKU8("\xe3\x82\xad\xe3\x83\xa3\xe3\x83\xb3\xe3\x82\xbb\xe3\x83\xab"); // キャンセル
|
||||
#else
|
||||
title = MKU8("\xe9\x96\x89\xe3\x81\x98\xe3\x82\x8b"); // 閉じる
|
||||
#endif
|
||||
#if (LIVE_LANGUAGE_CHANGE)
|
||||
if(RMLanguage::isJP() == false) { title = "Cancel";}
|
||||
#endif
|
||||
|
||||
RMButton* cancelButton = RMButton::create(bwRight,blRight,"button",FMS::txt("cancel"),QSize(120,30));
|
||||
cancelButton->setText(FMS::txt("cancel"));
|
||||
// connect(okButton,SIGNAL(clicked()),this,SLOT(onOK()));
|
||||
|
||||
|
||||
// RMButton* cancelButton = RMButton::create(bwRight,blRight,"popup_button",title,QSize(120,30));
|
||||
// cancelButton->setText(title);
|
||||
connect(cancelButton,SIGNAL(clicked()),this,SLOT(onCancel()));
|
||||
|
||||
/* 모델명 사용하지 않음
|
||||
QLabel* modelName = new QLabel(_title->_toolBar);
|
||||
modelName->setText(QString((const char*)CFG::data) + " ");
|
||||
modelName->setObjectName("title_label");
|
||||
_title->_toolBarLayout->insertWidget(0,modelName);
|
||||
*/
|
||||
#endif // #else // LIVE_LANGUAGE2
|
||||
|
||||
#if (DETECT_SETTING_USB_EJECT && !DETECT_USB_CHANGE)
|
||||
_usb = new rm_usb(this);
|
||||
_usb->registerEvent(this);
|
||||
RMApplication::instance()->installNativeEventFilter(_usb);
|
||||
connect(_usb,SIGNAL(usbChanged(bool,QString&)),SLOT(onUSBChange(bool,QString&)));
|
||||
#endif // @DETECT_SETTING_USB_EJECT
|
||||
|
||||
#if (SETTINGS_WINDOW_SCROLL)
|
||||
|
||||
layout->setMargin(0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
// 스크롤 영역 생성
|
||||
_contentScrollArea = new QScrollArea(_contentWidget);
|
||||
_contentScrollArea->setStyleSheet("QScrollArea { background: transparent; }");
|
||||
_contentScrollArea->setWidgetResizable( true );
|
||||
layout->addWidget(_contentScrollArea);
|
||||
_contentScrollWidget = new QWidget(); // _contentScrollArea
|
||||
//_contentScrollWidget->setStyleSheet("QWidget { background: #FF0000;}");
|
||||
|
||||
_contentScrollLayout = new QHBoxLayout(_contentScrollWidget);
|
||||
//ZERO_LAYOUT(_contentScrollLayout);
|
||||
//_contentScrollLayout->setMargin(8);
|
||||
_contentScrollLayout->setSpacing(8);
|
||||
|
||||
|
||||
_contentScrollLayout->setContentsMargins(8,10,8,10); // 상하단 마진
|
||||
_contentScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
_contentScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
// 자동 설정
|
||||
//_contentScrollWidget->setFixedHeight(SETTINGS_WiNDOW_HEIGHT);
|
||||
_contentScrollWidget->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
|
||||
_contentScrollArea->setFrameShape(QFrame::NoFrame);
|
||||
_contentScrollWidget->setObjectName("scroll2");
|
||||
_contentScrollWidget->setStyleSheet("QWidget#scroll2 { background: transparent; }");
|
||||
//_contentScrollWidget->setFixedHeight(SETTINGS_WiNDOW_HEIGHT);
|
||||
|
||||
_contentScrollArea->setWidget(_contentScrollWidget);
|
||||
|
||||
|
||||
QString scrollStyle = "QScrollBar:vertical\
|
||||
{\
|
||||
border-width: 0px;\
|
||||
border-style: solid;\
|
||||
background: #3B3B3B;\
|
||||
width: 10px;\
|
||||
margin: 0px 0 0px 0;\
|
||||
}\
|
||||
QScrollBar::handle:vertical:disabled{background: #3B3B3B;}\
|
||||
QScrollBar::handle:vertical\
|
||||
{\
|
||||
background: $HANDLE_COLOR$;\
|
||||
min-height: 25px;\
|
||||
margin: 2px 1px 2px 1px;\
|
||||
}\
|
||||
QScrollBar::add-line:vertical\
|
||||
{\
|
||||
border: none;\
|
||||
background: none;\
|
||||
height: 0px;\
|
||||
width: 0px;\
|
||||
subcontrol-position: bottom;\
|
||||
subcontrol-origin: margin;\
|
||||
}\
|
||||
QScrollBar::sub-line:vertical\
|
||||
{\
|
||||
border: none;\
|
||||
background: none;\
|
||||
height: 0px;\
|
||||
width: 0px;\
|
||||
subcontrol-position: top;\
|
||||
subcontrol-origin: margin;\
|
||||
}\
|
||||
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical\
|
||||
{\
|
||||
background: #3A3A3A;\
|
||||
}\
|
||||
QScrollBar::up-arrow:vertical\
|
||||
{\
|
||||
border: none;\
|
||||
background: #3A3A3A;\
|
||||
}\
|
||||
QScrollBar::down-arrow:vertical\
|
||||
{\
|
||||
border: none;\
|
||||
background: #5A5A5A;\
|
||||
}";
|
||||
_contentScrollArea->verticalScrollBar()->setStyleSheet(scrollStyle.replace("$HANDLE_COLOR$",QString().sprintf("#%06X",FM_SILDER_COLOR)));
|
||||
|
||||
#endif // SCROLL
|
||||
|
||||
|
||||
}
|
||||
#if (DETECT_SETTING_USB_EJECT && !DETECT_USB_CHANGE)
|
||||
void RMSettingsWindowBase::onUSBChange(bool inserted, QString& drive)
|
||||
{
|
||||
// qInfo() << __FUNCTION__;
|
||||
if(inserted == false && RMSettingsWindowBase::lastSettingDisk.contains(drive,Qt::CaseInsensitive)) {
|
||||
reject();
|
||||
}
|
||||
}
|
||||
#elif (DETECT_USB_CHANGE)
|
||||
void RMSettingsWindowBase::onUsbRemoved()
|
||||
{
|
||||
reject();
|
||||
}
|
||||
#endif // @DETECT_SETTING_USB_EJECT
|
||||
|
||||
#if (USE_JSON_SETTINGS)
|
||||
#else // #if (USE_JSON_SETTINGS)
|
||||
RMGroupRadioButtons* RMSettingsWindowBase::_MGR_ONOFF(QWidget* parent,QString title,QLayout* layout,int type)
|
||||
{
|
||||
#if (LIVE_LANGUAGE_CHANGE && !RM_MODEL_EMT_KR)
|
||||
if(RMLanguage::isJP() == false) { return _MGR(parent,title,layout,gEOnOff,type); }
|
||||
#endif
|
||||
return _MGR(parent,title,layout,gOnOff,type);
|
||||
}
|
||||
RMRadioButtons* RMSettingsWindowBase::_MR_ONOFF(QWidget* parent,QString title,QLayout* layout,int type,QLabel** titleLabel)
|
||||
{
|
||||
#if (LIVE_LANGUAGE_CHANGE && !RM_MODEL_EMT_KR)
|
||||
if(RMLanguage::isJP() == false) { return _MR(parent,title,layout,gEOnOff,type,QList<int>(),titleLabel); }
|
||||
#endif
|
||||
return _MR(parent,title,layout,gOnOff,type,QList<int>(),titleLabel);
|
||||
}
|
||||
RMGroupRadioButtons* RMSettingsWindowBase::_MGR(QWidget *parent,QString title,QLayout* layout,QStringList items,int type,QList<int> indexMap)
|
||||
{
|
||||
RMGroupRadioButtons* gr = new RMGroupRadioButtons(parent,title,items,&CFG::data[type],indexMap);
|
||||
layout->addWidget(gr);
|
||||
return gr;
|
||||
}
|
||||
RMGroupRadioButtons* RMSettingsWindowBase::_MGRR(QWidget *parent,QString title,QLayout* layout,QStringList items,int type,QList<int> indexMap)
|
||||
{
|
||||
RMGroupRadioButtons* gr = new RMGroupRadioButtons(parent,title,items,&CFG::data[type],true,indexMap);
|
||||
layout->addWidget(gr);
|
||||
return gr;
|
||||
}
|
||||
RMRadioButtons* RMSettingsWindowBase::_MR(QWidget *parent,QString title,QLayout* layout,QStringList items,int type,QList<int> indexMap,QLabel** titleLabel)
|
||||
{
|
||||
RMRadioButtons* gr = NULL;
|
||||
if(strcmp(layout->metaObject()->className(),"QGridLayout") == 0)
|
||||
{
|
||||
// (qobject_cast<QGridLayout*>)
|
||||
QGridLayout* gl = (QGridLayout*)layout;
|
||||
int row = ceil((double)layout->count() / 2.0);
|
||||
|
||||
QLabel* tl = new QLabel(this);
|
||||
tl->setObjectName("text_normal_label");
|
||||
tl->setText(title);
|
||||
gl->addWidget(tl,row,0,Qt::AlignLeft);
|
||||
// qInfo() << title << "MR row:" << row;
|
||||
gr = new RMRadioButtons(parent,"",items,&CFG::data[type],indexMap);
|
||||
gl->addWidget(gr,row,1,Qt::AlignLeft);
|
||||
|
||||
if(titleLabel != NULL) {
|
||||
*titleLabel = tl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gr = new RMRadioButtons(parent,title,items,&CFG::data[type],indexMap);
|
||||
layout->addWidget(gr);
|
||||
}
|
||||
return gr;
|
||||
}
|
||||
|
||||
void RMSettingsWindowBase::_MGT(QWidget *parent,QString title,QLayout* layout, QString text,QLabel** titleLabel)
|
||||
{
|
||||
if(strcmp(layout->metaObject()->className(),"QGridLayout") == 0)
|
||||
{
|
||||
QGridLayout* gl = (QGridLayout*)layout;
|
||||
int row = ceil(((double)layout->count()) / 2.0);
|
||||
|
||||
int column = 0;
|
||||
int columnSpan = 2;
|
||||
if(title.length() > 0) {
|
||||
QLabel* tl = new QLabel(this);
|
||||
tl->setObjectName("text_normal_label");
|
||||
tl->setText(title);
|
||||
gl->addWidget(tl,row,0,Qt::AlignLeft);
|
||||
column = 1;
|
||||
columnSpan = 1;
|
||||
|
||||
if(titleLabel != NULL) {
|
||||
*titleLabel = tl;
|
||||
}
|
||||
}
|
||||
|
||||
if(text.length() > 0)
|
||||
{
|
||||
QLabel* textLabel = new QLabel(parent);
|
||||
textLabel->setObjectName("text_normal_label");
|
||||
textLabel->setText(text);
|
||||
gl->addWidget(textLabel,row,column,1,columnSpan,Qt::AlignLeft);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QLabel* textLabel = new QLabel(parent);
|
||||
textLabel->setObjectName("text_normal_label");
|
||||
textLabel->setText(text);
|
||||
layout->addWidget(textLabel);
|
||||
};
|
||||
}
|
||||
|
||||
RMComboBox* RMSettingsWindowBase::_MC(QWidget *parent,QString title,QLayout* layout, QStringList items,int type,QList<int> indexMap,QLabel** titleLabel)
|
||||
{
|
||||
RMComboBox* c = NULL;
|
||||
if(strcmp(layout->metaObject()->className(),"QGridLayout") == 0)
|
||||
{
|
||||
QGridLayout* gl = (QGridLayout*)layout;
|
||||
int row = ceil(((double)layout->count()) / 2.0);
|
||||
|
||||
int column = 0;
|
||||
int columnSpan = 2;
|
||||
if(title.length() > 0) {
|
||||
QLabel* tl = new QLabel(this);
|
||||
tl->setObjectName("text_normal_label");
|
||||
tl->setText(title);
|
||||
gl->addWidget(tl,row,0,Qt::AlignLeft);
|
||||
column = 1;
|
||||
columnSpan = 1;
|
||||
|
||||
if(titleLabel != NULL) {
|
||||
*titleLabel = tl;
|
||||
}
|
||||
}
|
||||
//qInfo() << "row" << row << " column:" << column;
|
||||
c = new RMComboBox(parent,"",items,&CFG::data[type],indexMap);
|
||||
gl->addWidget(c,row,column,1,columnSpan,Qt::AlignLeft);
|
||||
}
|
||||
else
|
||||
{
|
||||
c = new RMComboBox(parent,title,items,&CFG::data[type],indexMap);
|
||||
layout->addWidget(c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
RMGroupComboBox* RMSettingsWindowBase::_MGC(QWidget *parent,QString title,QLayout* layout,QStringList items,int type,QList<int> indexMap)
|
||||
{
|
||||
RMGroupComboBox* c = new RMGroupComboBox(parent,title,items,&CFG::data[type],indexMap);
|
||||
layout->addWidget(c);
|
||||
return c;
|
||||
}
|
||||
#endif // #else // #if (USE_JSON_SETTINGS)
|
||||
void RMSettingsWindowBase::onSaveAnAccept()
|
||||
{
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
QString path = CFG::cfgPath;
|
||||
#else // RM_MODEL_EMT_KR
|
||||
QString path = QDir::cleanPath(lastSettingDisk + SETTINGS_FILE_NAME);
|
||||
#endif // RM_MODEL_EMT_KR
|
||||
if(validateData()) {
|
||||
CFG::save(path);
|
||||
afterSave();
|
||||
accept();
|
||||
}
|
||||
}
|
||||
RMSettingsWindowBase::~RMSettingsWindowBase()
|
||||
{
|
||||
|
||||
}
|
||||
void RMSettingsWindowBase::onSave()
|
||||
{
|
||||
QString path = QDir::cleanPath(lastSettingDisk + SETTINGS_FILE_NAME);
|
||||
if(validateData()) {
|
||||
CFG::save(path);
|
||||
afterSave();
|
||||
}
|
||||
}
|
||||
void RMSettingsWindowBase::onCancel()
|
||||
{
|
||||
CFG::restore();
|
||||
reject();
|
||||
}
|
||||
|
||||
void RMSettingsWindowBase::onDefault()
|
||||
{
|
||||
CFG::setDefault();
|
||||
emit RMValueUpdater::instance()->updateByValues();
|
||||
// 레코드 세팅 문제로 (Combo box event 발생하면 default 값이 save 됨)
|
||||
CFG::setDefault();
|
||||
}
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
131
project/fm_viewer/cfg/rm_settings_window_base.h
Normal file
131
project/fm_viewer/cfg/rm_settings_window_base.h
Normal file
@@ -0,0 +1,131 @@
|
||||
#ifndef RM_SETTINGS_WINDOW_BASE_H
|
||||
#define RM_SETTINGS_WINDOW_BASE_H
|
||||
|
||||
#if (USE_DEVICE_SETTINGS && !USE_DEVICE_SETTINGS_JSON)
|
||||
|
||||
#include "../ui/rm_popup.h"
|
||||
#include <QGroupBox>
|
||||
#include <QRadioButton>
|
||||
|
||||
class RMRadioButtons;
|
||||
class RMGroupComboBox;
|
||||
class RMGroupRadioButtons;
|
||||
class RMComboBox;
|
||||
class QJsonObject;
|
||||
class QScrollArea;
|
||||
|
||||
#if (DETECT_SETTING_USB_EJECT)
|
||||
class rm_usb;
|
||||
#endif
|
||||
|
||||
extern const QStringList gOnOff;
|
||||
|
||||
class RMSettingsWindowBase : public RMPopup
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
//static bool loaded;
|
||||
static QString lastSettingDisk;
|
||||
explicit RMSettingsWindowBase(QWidget *parent = 0);
|
||||
~RMSettingsWindowBase();
|
||||
virtual void afterSave() = NULL;
|
||||
virtual bool validateData() = NULL;
|
||||
|
||||
protected:
|
||||
|
||||
#if (DETECT_SETTING_USB_EJECT)
|
||||
rm_usb* _usb;
|
||||
#endif // @DETECT_SETTING_USB_EJECT
|
||||
|
||||
#if (SETTINGS_WINDOW_SCROLL)
|
||||
QScrollArea* _contentScrollArea;
|
||||
QWidget* _contentScrollWidget;
|
||||
QHBoxLayout* _contentScrollLayout;
|
||||
#endif // SCROLL
|
||||
|
||||
QHBoxLayout* layout;
|
||||
|
||||
// ON,OFF 기능만 하는 라디오 버튼 생성
|
||||
#if (USE_JSON_SETTINGS)
|
||||
RMGroupRadioButtons* _MGR_ONOFF(QWidget* parent,
|
||||
QJsonObject* object,
|
||||
QLayout* layout);
|
||||
|
||||
RMGroupRadioButtons* _MGR(QWidget *parent,
|
||||
QLayout* layout,
|
||||
QJsonObject* object);
|
||||
|
||||
RMGroupComboBox* _MGC(QWidget *parent,
|
||||
QLayout* layout,
|
||||
QJsonObject* object);
|
||||
|
||||
#else // USE_JSON_SETTINGS
|
||||
RMGroupRadioButtons* _MGR_ONOFF(QWidget* parent,
|
||||
QString title,
|
||||
QLayout* layout,
|
||||
int type
|
||||
);
|
||||
RMRadioButtons* _MR_ONOFF(QWidget* parent,
|
||||
QString title,
|
||||
QLayout* layout,
|
||||
int type,
|
||||
QLabel** titleLabel = NULL);
|
||||
RMGroupRadioButtons* _MGR(QWidget *parent,
|
||||
QString title,
|
||||
QLayout* layout,
|
||||
QStringList items,
|
||||
int type,
|
||||
QList<int> indexMap = QList<int>());
|
||||
|
||||
RMGroupRadioButtons* _MGRR(QWidget *parent,
|
||||
QString title,
|
||||
QLayout* layout,
|
||||
QStringList items,
|
||||
int type,
|
||||
QList<int> indexMap = QList<int>());
|
||||
|
||||
RMRadioButtons* _MR(QWidget *parent,
|
||||
QString title,
|
||||
QLayout* layout,
|
||||
QStringList items,
|
||||
int type,
|
||||
QList<int> indexMap = QList<int>(),
|
||||
QLabel** titleLabel = NULL);
|
||||
void _MGT(QWidget *parent,QString title,QLayout* layout, QString text,QLabel** titleLabel = NULL);
|
||||
RMComboBox* _MC(QWidget *parent,
|
||||
QString title,
|
||||
QLayout* layout,
|
||||
QStringList items,
|
||||
int type,
|
||||
QList<int> indexMap = QList<int>(),
|
||||
QLabel** titleLabel = NULL);
|
||||
RMGroupComboBox* _MGC(QWidget *parent,
|
||||
QString title,
|
||||
QLayout* layout,
|
||||
QStringList items,
|
||||
int type,
|
||||
QList<int> indexMap = QList<int>());
|
||||
|
||||
#endif // USE_JSON_SETTINGS
|
||||
|
||||
|
||||
|
||||
|
||||
protected slots:
|
||||
void onDefault();
|
||||
void onSave();
|
||||
void onCancel();
|
||||
void onSaveAnAccept();
|
||||
|
||||
// DETECT_USB_CHANGE 사용시에는 직접 처리하여 필요없음???
|
||||
#if (DETECT_SETTING_USB_EJECT && !DETECT_USB_CHANGE)
|
||||
void onUSBChange(bool inserted, QString& drive);
|
||||
#elif (DETECT_USB_CHANGE)
|
||||
void onUsbRemoved();
|
||||
#endif
|
||||
|
||||
};
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
#endif // RM_SETTINGS_WINDOW_BASE_H
|
||||
86
project/fm_viewer/cfg/rm_text_edit.cpp
Normal file
86
project/fm_viewer/cfg/rm_text_edit.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
|
||||
#include "rm_text_edit.h"
|
||||
#if (USE_JSON_SETTINGS)
|
||||
#include <QJsonObject>
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
#include "rm_settings_cfg.h"
|
||||
RMTextEdit::RMTextEdit(QWidget *parent,QString title, int index) : QWidget(parent), RMValueSelector(index)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
layout = new QHBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignLeading | Qt::AlignVCenter);
|
||||
layout->setContentsMargins(0,2,8,2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
if(!title.isEmpty())
|
||||
{
|
||||
titleLabel = new QLabel(this);
|
||||
titleLabel->setObjectName("text_normal_label");
|
||||
titleLabel->setText(title);
|
||||
layout->addWidget(titleLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
titleLabel = NULL;
|
||||
}
|
||||
QJsonObject obj = CFG::items.at(index).toObject();
|
||||
edit = new QLineEdit(this);
|
||||
edit->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
edit->setObjectName("file");
|
||||
edit->setText(obj.value("current").toString());
|
||||
|
||||
/*
|
||||
if(obj.contains("regex")) {
|
||||
QRegExp re(obj.value("regex").toString());
|
||||
QRegExpValidator *validator = new QRegExpValidator(re, this);
|
||||
edit->setValidator(validator);
|
||||
}
|
||||
|
||||
if(obj.contains("input_mask")) {
|
||||
edit->setInputMask(obj.value("input_mask").toString());
|
||||
}
|
||||
*/
|
||||
connect(edit,SIGNAL(textChanged(const QString &)),SLOT(onTextChanged(const QString &)));
|
||||
layout->addWidget(edit);
|
||||
connect(RMValueUpdater::instance(),SIGNAL(updateByValues()),SLOT(onUpdateByValue()));
|
||||
}
|
||||
void RMTextEdit::onTextChanged(const QString &text) {
|
||||
QJsonObject obj = CFG::items.at(_object).toObject();
|
||||
obj.insert("current",QJsonValue(text));
|
||||
CFG::items.replace(_object,obj);
|
||||
//qInfo() << text << __FUNCTION__;
|
||||
}
|
||||
void RMTextEdit::paintEvent(QPaintEvent *pe)
|
||||
{
|
||||
Q_UNUSED(pe);
|
||||
QStyleOption o;
|
||||
o.initFrom(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
|
||||
}
|
||||
void RMTextEdit::onUpdateByValue()
|
||||
{
|
||||
QJsonObject obj = CFG::items.at(_object).toObject();
|
||||
edit->setText(obj.value("current").toString());
|
||||
}
|
||||
RMGroupTextEdit::RMGroupTextEdit(QWidget *parent,int index) : QGroupBox(parent)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
|
||||
setObjectName("settings");
|
||||
QJsonObject obj = CFG::items.at(index).toObject();
|
||||
if(obj.contains("title")) {
|
||||
setTitle(obj.value("title").toString());
|
||||
}
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignVCenter | Qt::AlignLeading);
|
||||
layout->setContentsMargins(8,2,8,2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
|
||||
text = new RMTextEdit(this,"",index);
|
||||
layout->addWidget(text);
|
||||
}
|
||||
|
||||
#endif // #if (USE_JSON_SETTINGS)
|
||||
44
project/fm_viewer/cfg/rm_text_edit.h
Normal file
44
project/fm_viewer/cfg/rm_text_edit.h
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
#ifndef RM_TEXT_EDIT_H
|
||||
#define RM_TEXT_EDIT_H
|
||||
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QList>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QGroupBox>
|
||||
#include "rm_value_selector.h"
|
||||
#if (USE_JSON_SETTINGS)
|
||||
|
||||
class RMTextEdit : public QWidget, public RMValueSelector
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RMTextEdit(QWidget *parent,QString title, int index);
|
||||
QHBoxLayout* layout;
|
||||
QLineEdit* edit;
|
||||
QLabel* titleLabel;
|
||||
private:
|
||||
void paintEvent(QPaintEvent *pe);
|
||||
signals:
|
||||
void selected(int index);
|
||||
|
||||
private slots:
|
||||
void onTextChanged(const QString &text);
|
||||
void onUpdateByValue();
|
||||
};
|
||||
|
||||
class RMGroupTextEdit : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RMGroupTextEdit(QWidget *parent,int index);
|
||||
QVBoxLayout* layout;
|
||||
RMTextEdit* text;
|
||||
};
|
||||
|
||||
#endif // USE_JSON_SETTINGS
|
||||
#endif // RM_TEXT_EDIT_H
|
||||
39
project/fm_viewer/cfg/rm_value_selector.cpp
Normal file
39
project/fm_viewer/cfg/rm_value_selector.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "rm_value_selector.h"
|
||||
#if (USE_JSON_SETTINGS)
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include "rm_settings_cfg.h"
|
||||
RMValueSelector::RMValueSelector(int object)
|
||||
{
|
||||
_object = object;
|
||||
}
|
||||
unsigned char RMValueSelector::realValue(int index)
|
||||
{
|
||||
QJsonObject obj = CFG::items.at(_object).toObject();
|
||||
if(obj.contains("index_map")) {
|
||||
QJsonArray a = obj.value("index_map").toArray();
|
||||
return a.at(index).toInt();
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
int RMValueSelector::realIndex(unsigned char value)
|
||||
{
|
||||
QJsonObject obj = CFG::items.at(_object).toObject();
|
||||
if(obj.contains("index_map")) {
|
||||
QJsonArray a = obj.value("index_map").toArray();
|
||||
for(int i=0;i<a.size();i++) {
|
||||
if(a.at(i).toInt() == value) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
#else // USE_JSON_SETTINGS
|
||||
RMValueSelector::RMValueSelector(unsigned char* value,QList<int> indexMap)
|
||||
{
|
||||
_value = value;
|
||||
_indexMap = indexMap;
|
||||
}
|
||||
#endif // USE_JSON_SETTINGS
|
||||
60
project/fm_viewer/cfg/rm_value_selector.h
Normal file
60
project/fm_viewer/cfg/rm_value_selector.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef RM_VALUE_SELECTOR_H
|
||||
#define RM_VALUE_SELECTOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
|
||||
class QJsonObject;
|
||||
class RMValueSelector
|
||||
{
|
||||
public:
|
||||
|
||||
#if (USE_JSON_SETTINGS)
|
||||
explicit RMValueSelector(int object);
|
||||
protected:
|
||||
int _object;
|
||||
unsigned char realValue(int index);
|
||||
int realIndex(unsigned char value);
|
||||
#else // USE_JSON_SETTINGS
|
||||
public:
|
||||
RMValueSelector(unsigned char* value,QList<int> indexMap);
|
||||
unsigned char realValue(int index)
|
||||
{
|
||||
return _indexMap.isEmpty() ? (unsigned char)index : (unsigned char)_indexMap[index];
|
||||
}
|
||||
|
||||
int realIndex(unsigned char value)
|
||||
{
|
||||
return _indexMap.isEmpty() ? (int)value : _indexMap.indexOf(value);
|
||||
}
|
||||
protected:
|
||||
QList<int> _indexMap;
|
||||
unsigned char* _value;
|
||||
#endif // USE_JSON_SETTINGS
|
||||
};
|
||||
|
||||
class RMValueUpdater : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RMValueUpdater(QObject* parent = nullptr) : QObject(parent){
|
||||
|
||||
}
|
||||
|
||||
// SIGNAL 연동을 위해 사용
|
||||
static RMValueUpdater* instance()
|
||||
{
|
||||
static RMValueUpdater * _instance = 0;
|
||||
if ( _instance == 0 ) {
|
||||
_instance = new RMValueUpdater();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
|
||||
signals:
|
||||
void updateByValues();
|
||||
};
|
||||
|
||||
|
||||
#endif // RM_VALUE_SELECTOR_H
|
||||
19
project/fm_viewer/cfg/window_settings.h
Normal file
19
project/fm_viewer/cfg/window_settings.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef WINDOW_SETTINGS_COMMON_H
|
||||
#define WINDOW_SETTINGS_COMMON_H
|
||||
#if (USE_DEVICE_SETTINGS)
|
||||
#include "../rm_include.h"
|
||||
|
||||
#if (USE_DEVICE_SETTINGS_JSON)
|
||||
#include "window_settings_json.h"
|
||||
#else // USE_DEVICE_SETTINGS_JSON
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
#include "window_settings_xdr6688.h"
|
||||
#elif (RM_MODEL_EMT_KR)
|
||||
#include "window_settings_emt_kr.h"
|
||||
#else
|
||||
#include "window_settings_standard.h"
|
||||
#endif
|
||||
#endif // USE_DEVICE_SETTINGS_JSON
|
||||
|
||||
#endif // USE_DEVICE_SETTINGS
|
||||
#endif // WINDOW_SETTINGS_COMMON_H
|
||||
420
project/fm_viewer/cfg/window_settings_emt_kr.cpp
Normal file
420
project/fm_viewer/cfg/window_settings_emt_kr.cpp
Normal file
@@ -0,0 +1,420 @@
|
||||
#include "window_settings_emt_kr.h"
|
||||
#if (USE_DEVICE_SETTINGS && !USE_DEVICE_SETTINGS_JSON && RM_MODEL_EMT_KR)
|
||||
|
||||
#include "../fm_dimensions.h"
|
||||
#include "../ui/title_widget.h"
|
||||
#include "rm_combo_box.h"
|
||||
#include "rm_radio_buttons.h"
|
||||
#include "rm_group_combo_box.h"
|
||||
#include "rm_group_radio_buttons.h"
|
||||
#include "rm_text_edit.h"
|
||||
|
||||
//#include "rm_setting_time.h"
|
||||
#include <QComboBox>
|
||||
#include <QGridLayout>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QJsonObject>
|
||||
#include "rm_settings_cfg_emt_kr.h"
|
||||
|
||||
#if (DETECT_SETTING_USB_EJECT)
|
||||
#include "../core/rm_usb.h"
|
||||
#include "../rm_application.h"
|
||||
#endif
|
||||
|
||||
|
||||
// 문자열 처리 UTF
|
||||
// https://www.branah.com/unicode-converter
|
||||
|
||||
const int gComboBoxWidth = 200;
|
||||
const int gTitleWidth = 50;
|
||||
const int defaultHeight = 55;
|
||||
const int subHeight = 30;
|
||||
|
||||
WindowSettings::WindowSettings(QWidget *parent) : RMSettingsWindowBase(parent)
|
||||
{
|
||||
QWidget* row = NULL;
|
||||
QVBoxLayout* rowLayout = _createRow(&row);
|
||||
_createRowS(row,rowLayout,CFG::items,0,200);
|
||||
_refresh(CFG::items,0);
|
||||
}
|
||||
void WindowSettings::afterSave()
|
||||
{
|
||||
|
||||
}
|
||||
bool WindowSettings::validateData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
QStringList WindowSettings::_valueStrings(QJsonObject& object,const char* key)
|
||||
{
|
||||
QStringList ret = QStringList();
|
||||
if(object.contains(key)) {
|
||||
QJsonArray array = object.value(key).toArray();
|
||||
for(int i=0;i<array.size();i++) {
|
||||
ret.append(array.at(i).toString());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
QList<int> WindowSettings::_valueIndices(QJsonObject& object,const char* key)
|
||||
{
|
||||
QList<int> ret = QList<int>();
|
||||
if(object.contains(key)) {
|
||||
QJsonArray array = object.value(key).toArray();
|
||||
for(int i=0;i<array.size();i++) {
|
||||
ret.append(array.at(i).toInt());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int WindowSettings::_getObjectIndex(QString& id)
|
||||
{
|
||||
QObject* obj = _controlByNames.value(id);
|
||||
RMComboBox* combo = qobject_cast<RMComboBox*>(obj);
|
||||
if(combo != NULL) {
|
||||
return combo->comboBox->currentIndex();
|
||||
}
|
||||
else {
|
||||
RMRadioButtons* radios = qobject_cast<RMRadioButtons*>(obj);
|
||||
if(radios != NULL) {
|
||||
return radios->currentIndex();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
void WindowSettings::_refresh(QJsonArray items,int depth)
|
||||
{
|
||||
for(int i=0;i<items.size();i++) {
|
||||
QJsonObject obj = items.at(i).toObject();
|
||||
|
||||
// sub group
|
||||
if(obj.contains("group")) {
|
||||
_refresh(obj.value("items").toArray(),depth+1);
|
||||
}
|
||||
|
||||
if(obj.contains("events")) {
|
||||
//qInfo() << obj << __FUNCTION__;
|
||||
QStringList eventList = _valueStrings(obj,"events");
|
||||
|
||||
QString keyString = obj.value("key").toString();
|
||||
int index = _getObjectIndex(keyString);
|
||||
//qInfo() << index << __FUNCTION__;
|
||||
_processEvent(keyString,eventList,index);
|
||||
}
|
||||
}
|
||||
}
|
||||
void WindowSettings::_createRowS(QWidget* parent, QLayout* playout, QJsonArray items, int depth, int value_column_width)
|
||||
{
|
||||
|
||||
for(int i=0;i<items.size();i++) {
|
||||
QJsonObject obj = items.at(i).toObject();
|
||||
|
||||
if(obj.contains("hidden")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 열 변환
|
||||
if(obj.contains("column_break")) {
|
||||
QWidget* row = NULL;
|
||||
QVBoxLayout* rowLayout = _createRow(&row);
|
||||
|
||||
parent = row;
|
||||
playout = rowLayout;
|
||||
}
|
||||
if(!obj.contains("key")) {
|
||||
qInfo() << "ERROR:" << obj << __FUNCTION__;
|
||||
continue;
|
||||
}
|
||||
QString key = obj.value("key").toString();
|
||||
|
||||
QString title = "";
|
||||
if(obj.contains("title")) {
|
||||
title = obj.value("title").toString();
|
||||
}
|
||||
|
||||
QObject* keyObject = NULL;
|
||||
|
||||
// 그룹 타입의 경우
|
||||
if(obj.contains("group")) {
|
||||
QGroupBox* g = new QGroupBox(parent);
|
||||
keyObject = g;
|
||||
//g->setFixedHeight(160);
|
||||
g->setObjectName("settings");
|
||||
playout->addWidget(g);
|
||||
g->setTitle(title);
|
||||
QLayout *gg = NULL;
|
||||
if(!obj.contains("no_grid")) {
|
||||
QGridLayout* gl = new QGridLayout(g);
|
||||
gl->setMargin(8);
|
||||
gl->setSpacing(4);
|
||||
gg = gl;
|
||||
} else {
|
||||
QVBoxLayout* gl = new QVBoxLayout(g);
|
||||
gl->setMargin(8);
|
||||
gl->setSpacing(4);
|
||||
gg = gl;
|
||||
}
|
||||
int vcw = value_column_width;
|
||||
if(obj.contains("value_column_width")) {
|
||||
vcw = obj.value("value_column_width").toInt(value_column_width);
|
||||
}
|
||||
_createRowS(g,gg,obj.value("items").toArray(),depth+1,vcw);
|
||||
}
|
||||
else if(obj.contains("control")) {
|
||||
QString ctype = obj.value("control").toString();
|
||||
if(ctype == "radio" || ctype == "combo") {
|
||||
|
||||
if (!obj.contains("value_strings") || !obj.contains("offset")) {
|
||||
qInfo() << "ERROR ITEM:" << obj << __FUNCTION__;
|
||||
continue;
|
||||
}
|
||||
QStringList items = _valueStrings(obj,"value_strings"); // .value("value_strings").toArray()
|
||||
int offset = obj.value("offset").toInt();
|
||||
QList<int> indexMap = QList<int>();
|
||||
if(obj.contains("values")) {
|
||||
indexMap = _valueIndices(obj,"values");
|
||||
}
|
||||
QLabel* titleLabel = NULL;
|
||||
if(ctype == "radio") {
|
||||
RMRadioButtons* rrb = NULL;
|
||||
if(depth == 0 || obj.contains("group_box")) {
|
||||
RMGroupRadioButtons* rb = _MGR(parent,title,playout,items,offset,indexMap);
|
||||
rb->setFixedHeight(defaultHeight);
|
||||
rrb = rb->radioButtons;
|
||||
} else {
|
||||
rrb = _MR(parent,title,playout,items,offset,indexMap,&titleLabel);
|
||||
rrb->setFixedHeight(subHeight);
|
||||
rrb->setFixedWidth(value_column_width);
|
||||
//titleLabel->setFixedWidth(100);
|
||||
}
|
||||
keyObject = rrb;
|
||||
if(obj.contains("events")) {
|
||||
connect(rrb,SIGNAL(selected(int)),SLOT(onSelected(int)));
|
||||
}
|
||||
if(obj.contains("disabled")) {
|
||||
rrb->setEnabled(false);
|
||||
}
|
||||
} else {
|
||||
RMComboBox* ccb = NULL;
|
||||
if(depth == 0 || obj.contains("group_box")) {
|
||||
RMGroupComboBox* cb = _MGC(parent,title,playout,items,offset,indexMap);
|
||||
cb->comboBox->setFixedWidth(gComboBoxWidth);
|
||||
cb->setFixedHeight(defaultHeight);
|
||||
ccb = cb->comboBox;
|
||||
} else {
|
||||
ccb = _MC(parent,title,playout,items,offset,indexMap,&titleLabel);
|
||||
ccb->setFixedHeight(subHeight);
|
||||
ccb->setFixedWidth(value_column_width);
|
||||
//titleLabel->setFixedWidth(100);
|
||||
}
|
||||
keyObject = ccb;
|
||||
if(obj.contains("events")) {
|
||||
connect(ccb,SIGNAL(selected(int)),SLOT(onSelected(int)));
|
||||
}
|
||||
if(obj.contains("disabled")) {
|
||||
//qInfo() << "disabled" << title << __FUNCTION__;
|
||||
ccb->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(keyObject != NULL) {
|
||||
_controlByNames.insert(key,keyObject);
|
||||
_controlByObjects.insert(keyObject,key);
|
||||
|
||||
// 이벤트 추가
|
||||
if(obj.contains("events")) {
|
||||
|
||||
QStringList eventList = _valueStrings(obj,"events");
|
||||
// QJsonArray events = obj.value("events").toArray();
|
||||
// QStringList eventList = QStringList();
|
||||
// for(int e=0;e<events.size();e++) {
|
||||
// eventList.append(events.at(e).toString());
|
||||
// }
|
||||
_controlEvents.insert(keyObject,eventList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void WindowSettings::_processEvent(QString& key, QStringList& eventStrings, int index)
|
||||
{
|
||||
for(int e=0;e<eventStrings.size();e++) {
|
||||
QString event = eventStrings.at(e);
|
||||
if(event.startsWith("UPDATEVALUES")) {
|
||||
_processUpdateEvent(key,event,index);
|
||||
}
|
||||
else if(event.startsWith("ENABLED")) {
|
||||
_processEnableEvent(key,event,index);
|
||||
}
|
||||
else if (event.startsWith("UPDATE_OTHER_BY_EVENTS")) {
|
||||
_processUpdateOtherEvent(key,event,index);
|
||||
}
|
||||
}
|
||||
}
|
||||
void WindowSettings::_setObjectIndex(QObject* sender, int index)
|
||||
{
|
||||
RMComboBox* combo = qobject_cast<RMComboBox*>(sender);
|
||||
if(combo != NULL) {
|
||||
combo->comboBox->setCurrentIndex(index);
|
||||
}
|
||||
else {
|
||||
RMRadioButtons* radios = qobject_cast<RMRadioButtons*>(sender);
|
||||
if(radios != NULL) {
|
||||
radios->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
void WindowSettings::_setObjectEnable(QObject* sender, bool enabled)
|
||||
{
|
||||
RMComboBox* combo = qobject_cast<RMComboBox*>(sender);
|
||||
if(combo != NULL) {
|
||||
combo->setEnabled(enabled);
|
||||
}
|
||||
else {
|
||||
RMRadioButtons* radios = qobject_cast<RMRadioButtons*>(sender);
|
||||
if(radios != NULL) {
|
||||
radios->setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
void WindowSettings::_processUpdateOtherEvent(QString& key, QString& event, int index)
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
Q_UNUSED(key)
|
||||
|
||||
QStringList args = event.split(",");
|
||||
if(args.size() < 2) {
|
||||
return;
|
||||
}
|
||||
//qInfo() << "key:" << key << __FUNCTION__;
|
||||
// SD_OMAKASE의 항목을 확인하여
|
||||
QString target = args.at(1); // = SD_OMAKASE
|
||||
QObject* tt = _controlByNames.value(target); // 프리셋 컨트롤
|
||||
|
||||
// "UPDATEVALUES,0,SD_DRIVERECMODE=0,SD_PARKINGRECMODE=4,SD_VIDEOQUALITY=1,SD_VIDEOFRAME=1",
|
||||
// "UPDATEVALUES,1,SD_DRIVERECMODE=0,SD_PARKINGRECMODE=1,SD_VIDEOQUALITY=2,SD_VIDEOFRAME=1",
|
||||
// "UPDATEVALUES,2,SD_DRIVERECMODE=0,SD_PARKINGRECMODE=3,SD_VIDEOQUALITY=0,SD_VIDEOFRAME=0"
|
||||
QStringList targetEvents = _controlEvents.value(tt);
|
||||
for(int e=0;e<targetEvents.size();e++) {
|
||||
// "UPDATEVALUES,0,SD_DRIVERECMODE=0,SD_PARKINGRECMODE=4,SD_VIDEOQUALITY=1,SD_VIDEOFRAME=1",
|
||||
|
||||
QStringList eargs = targetEvents.at(e).split(",");
|
||||
|
||||
// UPDATEVALUES 항목이 아닌 경우 무시
|
||||
if(eargs.at(0) != "UPDATEVALUES") {
|
||||
//qInfo() << eargs.at(0) << __FUNCTION__;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 각 KEY=VALUE 확인 모든 조합이 일치하면
|
||||
bool bAllEqual = true;
|
||||
for(int a=2;a<eargs.size();a++) {
|
||||
QString etarget = eargs[a]; // SD_DRIVERECMODE=0
|
||||
QStringList etargetList = etarget.split("=");
|
||||
QString etargetKey = etargetList.at(0); // SD_DRIVERECMODE
|
||||
int etargetValue = etargetList.at(1).toInt(); // 0
|
||||
int eidx = _getObjectIndex(etargetKey); // 현재 컨트롤 값
|
||||
//QObject* ct = _controlByNames.value(etargetKey); // 컨트롤 값 확인
|
||||
// 조합이 틀린경우 다음 UPDATEVALUES 로 이동
|
||||
if(eidx != etargetValue) {
|
||||
bAllEqual = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 모든 항목이 일치하는 조합이 발생하면 해당 컨트롤 업데이트 후 종료
|
||||
if(bAllEqual) {
|
||||
int foundIndex = eargs.at(1).toInt(); // UPDATEVALUES,0 -> 0
|
||||
_setObjectIndex(tt,foundIndex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 발견된 조합이 없을 경우 NOT_FOUND 확인 (VERIFYVALUES_BY,SD_OMAKASE,NOT_FOUND=4)
|
||||
if(args.size() >= 3) {
|
||||
QString nf = args.at(2);
|
||||
if(nf.startsWith("NOT_FOUND")) {
|
||||
int idx = nf.split("=").at(1).toInt();
|
||||
//QObject* tt = _controlByNames.value(target);
|
||||
_setObjectIndex(tt,idx);
|
||||
}
|
||||
}
|
||||
//qInfo() << args << __FUNCTION__;
|
||||
}
|
||||
void WindowSettings::_processUpdateEvent(QString& key, QString& event, int index)
|
||||
{
|
||||
Q_UNUSED(key)
|
||||
|
||||
QStringList args = event.split(",");
|
||||
// 업데이트 명령일 경우
|
||||
if(args[1].toInt() != index) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 각 업데이트 확인
|
||||
for(int a=2;a<args.size();a++) {
|
||||
QString target = args[a];
|
||||
QStringList taget = target.split("=");
|
||||
QString targetKey = taget.at(0);
|
||||
int targetValue = taget.at(1).toInt();
|
||||
QObject* tt = _controlByNames.value(targetKey);
|
||||
_setObjectIndex(tt,targetValue);
|
||||
}
|
||||
}
|
||||
void WindowSettings::_processEnableEvent(QString& key, QString& event, int index)
|
||||
{
|
||||
Q_UNUSED(key)
|
||||
// SHOWHIDE,1,SD_PARKING_CUTOFF_NORMAL=1,SD_PARKING_CUTOFF_HYBRID=0,SD_PARKING_CUTOFF_ELECTRIC=0
|
||||
QStringList args = event.split(",");
|
||||
|
||||
// 선택된 인덱스의 항목이 아닐 경우
|
||||
if(args[1].toInt() != index) {
|
||||
return;
|
||||
}
|
||||
// 각 업데이트 확인
|
||||
for(int a=2;a<args.size();a++) {
|
||||
QString target = args[a];
|
||||
QStringList taget = target.split("=");
|
||||
QString targetKey = taget.at(0);
|
||||
int targetValue = taget.at(1).toInt();
|
||||
QObject* tt = _controlByNames.value(targetKey);
|
||||
//qInfo() << tt << taget << targetValue << __FUNCTION__;
|
||||
_setObjectEnable(tt,targetValue == 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WindowSettings::onSelected(int index)
|
||||
{
|
||||
QObject* s = sender();
|
||||
// 정보 존재
|
||||
if(_controlEvents.contains(s)) {
|
||||
|
||||
QStringList eventStrings = _controlEvents.value(s);
|
||||
QString key = _controlByObjects[s];
|
||||
_processEvent(key,eventStrings,index);
|
||||
}
|
||||
}
|
||||
|
||||
QVBoxLayout* WindowSettings::_createRow(QWidget** rw)
|
||||
{
|
||||
const int width = SETTINGS_WINDOW_WIDTH - _contentScrollLayout->contentsMargins().left() - _contentScrollLayout->contentsMargins().right() - _contentScrollLayout->spacing() - 20;
|
||||
*rw = new QWidget(_contentScrollWidget);
|
||||
(*rw)->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
|
||||
(*rw)->setFixedWidth(width / 2);
|
||||
_contentScrollLayout->addWidget(*rw);
|
||||
_contentScrollLayout->setAlignment(Qt::AlignTop);
|
||||
|
||||
QVBoxLayout* l = new QVBoxLayout(*rw);
|
||||
l->setMargin(0);
|
||||
l->setSpacing(10);
|
||||
l->setAlignment(Qt::AlignTop);
|
||||
return l;
|
||||
}
|
||||
WindowSettings::~WindowSettings()
|
||||
{
|
||||
|
||||
}
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
//#endif // #if (RM_MODEL == RM_MODEL_TYPE_CS_32FH)
|
||||
|
||||
68
project/fm_viewer/cfg/window_settings_emt_kr.h
Normal file
68
project/fm_viewer/cfg/window_settings_emt_kr.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef WINDOW_SETTINGS_H
|
||||
#define WINDOW_SETTINGS_H
|
||||
#if (USE_DEVICE_SETTINGS && !USE_DEVICE_SETTINGS_JSON && RM_MODEL_EMT_KR)
|
||||
|
||||
#include "../rm_include.h"
|
||||
#include "rm_settings_window_base.h"
|
||||
|
||||
#include "../ui/rm_popup.h"
|
||||
#include <QGroupBox>
|
||||
#include <QRadioButton>
|
||||
|
||||
#define SETTING_NUM_ROW 2
|
||||
|
||||
class RMTextEdit;
|
||||
class WindowSettings : public RMSettingsWindowBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WindowSettings(QWidget *parent = 0);
|
||||
~WindowSettings();
|
||||
virtual void afterSave() override;
|
||||
virtual bool validateData() override;
|
||||
|
||||
private:
|
||||
QHash<QString,QObject*> _controlByNames; ///! 명칭으로 Contro(Combo,Button) 확인
|
||||
QHash<QObject*,QString> _controlByObjects; ///! 컨트롤로 명칭 확인
|
||||
QHash<QObject*,QStringList> _controlEvents; ///! 컨트롤로 이벤트 확인
|
||||
|
||||
|
||||
// Utility
|
||||
QVBoxLayout* _createRow(QWidget** rw);
|
||||
|
||||
void _createRowS(QWidget* parent, QLayout* playout, QJsonArray items, int depth, int value_column_width = -1);
|
||||
|
||||
// 이벤트가 존재하는 항목 확인하여 ENABLE/DISABLED 등 처리함
|
||||
// 항목 사용에 따라 값을 변경
|
||||
void _refresh(QJsonArray items,int depth);
|
||||
|
||||
// 설정 항목별 리스트를 확인
|
||||
static QStringList _valueStrings(QJsonObject& object,const char* key);
|
||||
|
||||
// 설정 항목별 저장값을 확인
|
||||
static QList<int> _valueIndices(QJsonObject& object,const char* key);
|
||||
|
||||
void _processEvent(QString& key, QStringList& events, int index);
|
||||
|
||||
//! \brief 항목이 변경되면 다른 항목을 업데이트함
|
||||
//! \param event
|
||||
//! \param index
|
||||
void _processUpdateEvent(QString& key, QString& event, int index);
|
||||
void _processEnableEvent(QString& key, QString& event, int index);
|
||||
|
||||
//! \brief 항목이 변경되면 다른 항목을 (UpdateEvent) 를 참조하여 업데이트함
|
||||
//! eg. 화질설정이 변경되면 프리셋을 프리셋내의 UPDATES.. 를 확인하여 업데이트
|
||||
//! \param event
|
||||
//! \param index
|
||||
void _processUpdateOtherEvent(QString& key, QString& event, int index);
|
||||
|
||||
int _getObjectIndex(QString& id);
|
||||
void _setObjectIndex(QObject* sender, int index);
|
||||
void _setObjectEnable(QObject* sender, bool enabled);
|
||||
private slots:
|
||||
void onSelected(int index);
|
||||
|
||||
};
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
#endif // WINDOW_SETTINGS_H
|
||||
69
project/fm_viewer/cfg/window_settings_json.cpp
Normal file
69
project/fm_viewer/cfg/window_settings_json.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#if (USE_DEVICE_SETTINGS_JSON)
|
||||
#include "window_settings_json.h"
|
||||
|
||||
#include "../ui/title_widget.h"
|
||||
#include "../core/fm_strings.h"
|
||||
#include "rm_combo_box.h"
|
||||
#include "rm_radio_buttons.h"
|
||||
#include "rm_group_combo_box.h"
|
||||
#include "rm_group_radio_buttons.h"
|
||||
#include "rm_text_edit.h"
|
||||
//#include "rm_settings_cfg_standard.h"
|
||||
//#include "rm_setting_time.h"
|
||||
#include <QComboBox>
|
||||
#include <QGridLayout>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
|
||||
#if (DETECT_SETTING_USB_EJECT)
|
||||
#include "../core/rm_usb.h"
|
||||
#include "../rm_application.h"
|
||||
#endif
|
||||
|
||||
QString WindowSettings::lastSettingDisk = "";
|
||||
|
||||
WindowSettings::WindowSettings(QWidget *parent) : RMPopup(parent,"","title_settings.png")
|
||||
{
|
||||
if(RMApp::isModelDisk(lastSettingDisk) == false)
|
||||
{
|
||||
// CFG::setDefault();
|
||||
// CFG::save(path);
|
||||
}
|
||||
else {
|
||||
// CFG::load(path);
|
||||
}
|
||||
this->setFixedSize(640,480);
|
||||
_contentWidget->setObjectName("bg_dark_widget");
|
||||
layout = new QHBoxLayout(_contentWidget);
|
||||
layout->setMargin(8);
|
||||
layout->setSpacing(8);
|
||||
|
||||
QWidget* bwLeft = new QWidget(_buttonWidget);
|
||||
_buttonLayout->addWidget(bwLeft);
|
||||
|
||||
QWidget* bwRight = new QWidget(_buttonWidget);
|
||||
_buttonLayout->addWidget(bwRight);
|
||||
|
||||
QHBoxLayout* blLeft = new QHBoxLayout(bwLeft);
|
||||
blLeft->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
|
||||
|
||||
QHBoxLayout* blRight = new QHBoxLayout(bwRight);
|
||||
blRight->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
||||
|
||||
RMButton* defaultButton = RMButton::create2(bwRight,blRight,"button","default",QSize(120,30));
|
||||
defaultButton->setText(FMS::txt("default"));
|
||||
connect(defaultButton,SIGNAL(clicked()),SLOT(onDefault()));
|
||||
|
||||
RMButton* okButton = RMButton::create2(bwRight,blRight,"button","ok",QSize(120,30));
|
||||
okButton->setText(FMS::txt("ok"));
|
||||
connect(okButton,SIGNAL(clicked()),this,SLOT(onSaveAnAccept()));
|
||||
|
||||
RMButton* cancelButton = RMButton::create2(bwRight,blRight,"button","cancel",QSize(120,30));
|
||||
cancelButton->setText(FMS::txt("cancel"));
|
||||
connect(cancelButton,SIGNAL(clicked()),this,SLOT(onCancel()));
|
||||
}
|
||||
WindowSettings::~WindowSettings()
|
||||
{
|
||||
|
||||
}
|
||||
#endif // #if (USE_DEVICE_SETTINGS_JSON)
|
||||
20
project/fm_viewer/cfg/window_settings_json.h
Normal file
20
project/fm_viewer/cfg/window_settings_json.h
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
#ifndef WINDOW_SETTINGS_JSON_H
|
||||
#define WINDOW_SETTINGS_JSON_H
|
||||
#if (USE_DEVICE_SETTINGS_JSON)
|
||||
#include "../ui/rm_popup.h"
|
||||
|
||||
class WindowSettings : public RMPopup
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WindowSettings(QWidget *parent = 0);
|
||||
~WindowSettings();
|
||||
static QString lastSettingDisk;
|
||||
private:
|
||||
QHBoxLayout* layout;
|
||||
QVBoxLayout* _createRow(QWidget** rw);
|
||||
};
|
||||
#endif // #if (USE_DEVICE_SETTINGS_JSON)
|
||||
#endif // WINDOW_SETTINGS_JSON_H
|
||||
184
project/fm_viewer/cfg/window_settings_standard.cpp
Normal file
184
project/fm_viewer/cfg/window_settings_standard.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
#include "window_settings_standard.h"
|
||||
#if (USE_DEVICE_SETTINGS && !USE_DEVICE_SETTINGS_JSON && !RM_MODEL_EMT_KR)
|
||||
|
||||
#include "../fm_dimensions.h"
|
||||
//#if (RM_MODEL == RM_MODEL_TYPE_STANDARD || RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
|
||||
#include "../ui/title_widget.h"
|
||||
#include "rm_combo_box.h"
|
||||
#include "rm_radio_buttons.h"
|
||||
#include "rm_group_combo_box.h"
|
||||
#include "rm_group_radio_buttons.h"
|
||||
#include "rm_text_edit.h"
|
||||
|
||||
#include "rm_settings_cfg_standard.h"
|
||||
#include "rm_setting_time.h"
|
||||
#include <QComboBox>
|
||||
#include <QGridLayout>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
|
||||
#if (DETECT_SETTING_USB_EJECT)
|
||||
#include "../core/rm_usb.h"
|
||||
#include "../rm_application.h"
|
||||
#endif
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
#include <QJsonObject>
|
||||
#endif // RM_MODEL_TYPE_AN6000
|
||||
|
||||
// 문자열 처리 UTF
|
||||
// https://www.branah.com/unicode-converter
|
||||
|
||||
const int gComboBoxWidth = 200;
|
||||
const int gTitleWidth = 50;
|
||||
|
||||
static const QString glevel = MKU8("\xe3\x83\xac\xe3\x83\x99\xe3\x83\xab");
|
||||
|
||||
|
||||
WindowSettings::WindowSettings(QWidget *parent) : RMSettingsWindowBase(parent)
|
||||
{
|
||||
_createRowA();
|
||||
}
|
||||
void WindowSettings::afterSave()
|
||||
{
|
||||
|
||||
}
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
bool WindowSettings::validateData()
|
||||
{
|
||||
const QList<QString> keys = validateList.keys();
|
||||
for(int i=0;i<keys.size();i++){
|
||||
QPair<QString,RMTextEdit*> item = validateList[keys.at(i)];
|
||||
QString str = item.second->edit->text();
|
||||
QString reg = item.first;
|
||||
QRegExp regexp(reg);
|
||||
if(!regexp.exactMatch(str)) {
|
||||
QMessageBox msgBox(QMessageBox::Warning,
|
||||
"AN6000",
|
||||
FM_WSTR(L"「入力内容にエラーがあります。\n修正して再度ご登録をお願いいたします。」"),
|
||||
QMessageBox::Ok,
|
||||
this);
|
||||
msgBox.exec();
|
||||
QTimer::singleShot(0, item.second->edit, SLOT(setFocus()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
void WindowSettings::_createRowA()
|
||||
{
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
QWidget* row = NULL;
|
||||
QVBoxLayout* rowLayout = NULL;
|
||||
rowLayout = _createRow(&row);
|
||||
|
||||
int fh = 55;
|
||||
|
||||
for(int i=0;i<CFG::items.size();i++) {
|
||||
QJsonObject obj = CFG::items.at(i).toObject();
|
||||
|
||||
if(obj.contains("hidden")) {
|
||||
continue;
|
||||
}
|
||||
if(obj.contains("control")) {
|
||||
QString ctype = obj.value("control").toString();
|
||||
if(ctype == "radio") {
|
||||
RMGroupRadioButtons* rb = new RMGroupRadioButtons(row,i);
|
||||
rowLayout->addWidget(rb);
|
||||
rb->setFixedHeight(fh);
|
||||
} else if(ctype == "combo") {
|
||||
RMGroupComboBox* cb = new RMGroupComboBox(row,i);
|
||||
rowLayout->addWidget(cb);
|
||||
cb->comboBox->setFixedWidth(gComboBoxWidth);
|
||||
cb->setFixedHeight(fh);
|
||||
} else if(ctype == "text") {
|
||||
RMGroupTextEdit* tb = new RMGroupTextEdit(row,i);
|
||||
// REGEX 포함 데이터일 경우 추가
|
||||
if(obj.contains("regex")) {
|
||||
validateList.insert(obj.value("key").toString(),QPair<QString,RMTextEdit*>(obj.value("regex").toString(),tb->text));
|
||||
}
|
||||
rowLayout->addWidget(tb);
|
||||
tb->text->setFixedWidth(gComboBoxWidth);
|
||||
tb->setFixedHeight(fh);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else // AN6000
|
||||
QWidget* row = NULL;
|
||||
QVBoxLayout* rowLayout = NULL;
|
||||
rowLayout = _createRow(&row);
|
||||
|
||||
int fh = 65;
|
||||
|
||||
RMGroupComboBox* gs = new RMGroupComboBox(row,
|
||||
MKU8("\x33\x47\xe3\x82\xbb\xe3\x83\xb3\xe3\x82\xb5\xe3\x83\xbc\xe6\x84\x9f\xe5\xba\xa6"),
|
||||
QStringList() << glevel + "1" << glevel + "2" << glevel + "3" \
|
||||
<< glevel + "4" << glevel + "5",
|
||||
&CFG::data[SD_SENSOR]);
|
||||
|
||||
rowLayout->addWidget(gs);
|
||||
gs->comboBox->setFixedWidth(gComboBoxWidth);
|
||||
gs->setFixedHeight(fh);
|
||||
|
||||
// 画像 SIZE_800x600, SIZE_640x320
|
||||
RMGroupRadioButtons* gr = _MGR(row,MKU8("\xe7\x94\xbb\xe5\x83\x8f"),rowLayout,QStringList() << "800x600" << "640x320",SD_SIZE);
|
||||
gr->setFixedHeight(fh);
|
||||
|
||||
// 録画フレームレート
|
||||
gr = _MGR(row,
|
||||
MKU8("\xe9\x8c\xb2\xe7\x94\xbb\xe3\x83\x95\xe3\x83\xac\xe3\x83\xbc\xe3\x83\xa0\xe3\x83\xac\xe3\x83\xbc\xe3\x83\x88"),
|
||||
rowLayout,
|
||||
QStringList()
|
||||
<< "20 fps"
|
||||
<< "25 fps"
|
||||
<< "30 fps",SD_FRAME);
|
||||
gr->setFixedHeight(fh);
|
||||
|
||||
|
||||
// 音量調整
|
||||
gr = _MGR(row,
|
||||
MKU8("\xe9\x9f\xb3\xe9\x87\x8f\xe8\xaa\xbf\xe6\x95\xb4") + " ",
|
||||
rowLayout,
|
||||
QStringList() << "0" << "1" << "2" << "3" << "4" << "5",
|
||||
SD_VOLUME);
|
||||
gr->setFixedHeight(fh);
|
||||
|
||||
// ボイス
|
||||
gr = _MGR(row,
|
||||
MKU8("\xe3\x83\x9c\xe3\x82\xa4\xe3\x82\xb9") + " ",
|
||||
rowLayout,
|
||||
QStringList() << MKU8("\xe3\x82\xaa\xe3\x83\x95") << MKU8("\xe3\x82\xaa\xe3\x83\xb3"),
|
||||
SD_VOICE);
|
||||
gr->setFixedHeight(fh);
|
||||
|
||||
|
||||
RMSettingTime* time = new RMSettingTime(row);
|
||||
rowLayout->addWidget(time);
|
||||
#endif // #else // AN6000
|
||||
}
|
||||
|
||||
QVBoxLayout* WindowSettings::_createRow(QWidget** rw)
|
||||
{
|
||||
*rw = new QWidget(_contentWidget);
|
||||
(*rw)->setFixedWidth(SETTINGS_WINDOW_WIDTH-(8*2));
|
||||
layout->addWidget(*rw);
|
||||
|
||||
QVBoxLayout* l = new QVBoxLayout(*rw);
|
||||
l->setMargin(0);
|
||||
l->setSpacing(4);
|
||||
l->setAlignment(Qt::AlignTop);
|
||||
return l;
|
||||
}
|
||||
WindowSettings::~WindowSettings()
|
||||
{
|
||||
|
||||
}
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
//#endif // #if (RM_MODEL == RM_MODEL_TYPE_CS_32FH)
|
||||
|
||||
53
project/fm_viewer/cfg/window_settings_standard.h
Normal file
53
project/fm_viewer/cfg/window_settings_standard.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef WINDOW_SETTINGS_H
|
||||
#define WINDOW_SETTINGS_H
|
||||
#if (USE_DEVICE_SETTINGS && !USE_DEVICE_SETTINGS_JSON && !RM_MODEL_EMT_KR)
|
||||
|
||||
#include "../rm_include.h"
|
||||
#include "rm_settings_window_base.h"
|
||||
//#if (RM_MODEL == RM_MODEL_TYPE_STANDARD || RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
|
||||
#include "../ui/rm_popup.h"
|
||||
#include <QGroupBox>
|
||||
#include <QRadioButton>
|
||||
|
||||
#define SETTING_NUM_ROW 3
|
||||
|
||||
class RMTextEdit;
|
||||
class WindowSettings : public RMSettingsWindowBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit WindowSettings(QWidget *parent = 0);
|
||||
~WindowSettings();
|
||||
virtual void afterSave() override;
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
virtual bool validateData() override;
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
|
||||
private:
|
||||
// Utility
|
||||
QVBoxLayout* _createRow(QWidget** rw);
|
||||
|
||||
RMRadioButtons* videoResolution; // 1
|
||||
RMRadioButtons* videoQuality; // 2
|
||||
RMRadioButtons* videoBrightness; // 3
|
||||
RMRadioButtons* videoContrast; // 4
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
// 검증용 데이터 KEY 명칭, (REGEX,CONTROL)
|
||||
QMap<QString,QPair<QString,RMTextEdit*>> validateList;
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
|
||||
void _createRowA();
|
||||
|
||||
|
||||
private slots:
|
||||
|
||||
// void onRecordSetting(int index);
|
||||
// void onGSensorSensitivity(int index);
|
||||
};
|
||||
//#endif // #if (RM_MODEL == RM_MODEL_TYPE_CS_91FH)
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
#endif // WINDOW_SETTINGS_H
|
||||
402
project/fm_viewer/cfg/window_settings_xdr6688.cpp
Normal file
402
project/fm_viewer/cfg/window_settings_xdr6688.cpp
Normal file
@@ -0,0 +1,402 @@
|
||||
#include "window_settings_xdr6688.h"
|
||||
#if (USE_DEVICE_SETTINGS)
|
||||
|
||||
#include "../fm_dimensions.h"
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
|
||||
#include "../ui/title_widget.h"
|
||||
#include "rm_combo_box.h"
|
||||
#include "rm_radio_buttons.h"
|
||||
#include "rm_group_combo_box.h"
|
||||
#include "rm_group_radio_buttons.h"
|
||||
|
||||
#include "rm_settings_cfg_xdr6688.h"
|
||||
#include "rm_setting_time.h"
|
||||
#include "rm_admin_passwd.h"
|
||||
#include <QComboBox>
|
||||
#include <QGridLayout>
|
||||
#include <QDir>
|
||||
#include "../ui/rm_widget_checkbox.h"
|
||||
|
||||
#if (DETECT_SETTING_USB_EJECT)
|
||||
#include "../core/rm_usb.h"
|
||||
#include "../rm_application.h"
|
||||
#endif
|
||||
|
||||
// 문자열 처리 UTF
|
||||
// https://www.branah.com/unicode-converter
|
||||
|
||||
const int gComboBoxWidth = 200;
|
||||
const int gTitleWidth = 50;
|
||||
|
||||
static const QString glevel = MKU8("\xe3\x83\xac\xe3\x83\x99\xe3\x83\xab");
|
||||
static const QStringList gEOffOn = QStringList() << "OFF" << "ON";
|
||||
|
||||
|
||||
WindowSettings::WindowSettings(QWidget *parent) : RMSettingsWindowBase(parent)
|
||||
{
|
||||
//_createRowA();
|
||||
}
|
||||
|
||||
WindowSettings::~WindowSettings()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// XDR-66
|
||||
WindowSettings66::WindowSettings66(QWidget *parent) : WindowSettings(parent)
|
||||
{
|
||||
_wwidth = SETTINGS_WINDOW_WIDTH;
|
||||
_wheight = 600;
|
||||
setFixedSize(_wwidth,_wheight);
|
||||
_createRowA();
|
||||
}
|
||||
QVBoxLayout* WindowSettings66::_createRow(QWidget** rw)
|
||||
{
|
||||
*rw = new QWidget(_contentWidget);
|
||||
(*rw)->setFixedWidth(_wwidth-(8*2));
|
||||
layout->addWidget(*rw);
|
||||
|
||||
QVBoxLayout* l = new QVBoxLayout(*rw);
|
||||
l->setMargin(0);
|
||||
l->setSpacing(4);
|
||||
l->setAlignment(Qt::AlignTop);
|
||||
return l;
|
||||
}
|
||||
void WindowSettings66::_createRowA()
|
||||
{
|
||||
QWidget* row = NULL;
|
||||
QVBoxLayout* rowLayout = NULL;
|
||||
|
||||
rowLayout = _createRow(&row);
|
||||
|
||||
int fh = 65;
|
||||
|
||||
RMGroupComboBox* gs = new RMGroupComboBox(row,
|
||||
MKU8("\x33\x47\xe3\x82\xbb\xe3\x83\xb3\xe3\x82\xb5\xe3\x83\xbc\xe6\x84\x9f\xe5\xba\xa6"),
|
||||
QStringList() << glevel + "1" << glevel + "2" << glevel + "3" \
|
||||
<< glevel + "4" << glevel + "5",
|
||||
&CFG::data[SD_SENSOR]);
|
||||
|
||||
rowLayout->addWidget(gs);
|
||||
gs->comboBox->setFixedWidth(gComboBoxWidth);
|
||||
gs->setFixedHeight(fh);
|
||||
|
||||
// 画像 SIZE_800x600, SIZE_640x320
|
||||
RMGroupRadioButtons* gr = _MGR(row,MKU8("\xe7\x94\xbb\xe5\x83\x8f"),rowLayout,QStringList() << "800x600" << "640x320",SD_SIZE);
|
||||
gr->setFixedHeight(fh);
|
||||
|
||||
// 録画フレームレート
|
||||
gr = _MGR(row,
|
||||
MKU8("\xe9\x8c\xb2\xe7\x94\xbb\xe3\x83\x95\xe3\x83\xac\xe3\x83\xbc\xe3\x83\xa0\xe3\x83\xac\xe3\x83\xbc\xe3\x83\x88"),
|
||||
rowLayout,
|
||||
QStringList()
|
||||
<< "20 fps"
|
||||
<< "25 fps"
|
||||
<< "30 fps",SD_FRAME);
|
||||
gr->setFixedHeight(fh);
|
||||
|
||||
|
||||
// 音量調整
|
||||
gr = _MGR(row,
|
||||
MKU8("\xe9\x9f\xb3\xe9\x87\x8f\xe8\xaa\xbf\xe6\x95\xb4") + " ",
|
||||
rowLayout,
|
||||
QStringList() << "0" << "1" << "2" << "3" << "4" << "5",
|
||||
SD_VOLUME);
|
||||
gr->setFixedHeight(fh);
|
||||
|
||||
// ボイス
|
||||
gr = _MGR(row,
|
||||
MKU8("\xe3\x83\x9c\xe3\x82\xa4\xe3\x82\xb9") + " ",
|
||||
rowLayout,
|
||||
QStringList() << MKU8("\xe3\x82\xaa\xe3\x83\x95") << MKU8("\xe3\x82\xaa\xe3\x83\xb3"),
|
||||
SD_VOICE);
|
||||
gr->setFixedHeight(fh);
|
||||
|
||||
|
||||
time = new RMSettingTime(row);
|
||||
rowLayout->addWidget(time);
|
||||
}
|
||||
void WindowSettings66::afterSave()
|
||||
{
|
||||
if(time->check->isChecked()) {
|
||||
time->onSave();
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
// XDR-88
|
||||
WindowSettings88::WindowSettings88(QWidget *parent) : WindowSettings(parent)
|
||||
{
|
||||
_wwidth = 800;
|
||||
_wheight = 550;
|
||||
setFixedSize(_wwidth,_wheight);
|
||||
|
||||
_createRowA();
|
||||
_createRowB();
|
||||
}
|
||||
QVBoxLayout* WindowSettings88::_createRow(QWidget** rw)
|
||||
{
|
||||
*rw = new QWidget(_contentWidget);
|
||||
(*rw)->setFixedWidth((_wwidth-(8*4))/2);
|
||||
layout->addWidget(*rw);
|
||||
|
||||
QVBoxLayout* l = new QVBoxLayout(*rw);
|
||||
l->setMargin(0);
|
||||
l->setSpacing(4);
|
||||
l->setAlignment(Qt::AlignTop);
|
||||
return l;
|
||||
}
|
||||
void WindowSettings88::_createRowA()
|
||||
{
|
||||
QWidget* row = NULL;
|
||||
QVBoxLayout* rowLayout = NULL;
|
||||
QLabel* tl;
|
||||
RMRadioButtons* rb;
|
||||
|
||||
rowLayout = _createRow(&row);
|
||||
|
||||
|
||||
// システム
|
||||
QGroupBox* g = new QGroupBox(row);
|
||||
g->setObjectName("settings");
|
||||
rowLayout->addWidget(g);
|
||||
const int lbWidth = 130;
|
||||
const int cWidth = 150;
|
||||
const int rWidth = 220;
|
||||
|
||||
g->setTitle(MKU8("\xe3\x82\xb7\xe3\x82\xb9\xe3\x83\x86\xe3\x83\xa0"));
|
||||
|
||||
QGridLayout* gl = new QGridLayout(g);
|
||||
gl->setMargin(8);
|
||||
gl->setSpacing(4);
|
||||
g->setFixedHeight(160);
|
||||
|
||||
// 画面表示
|
||||
// 1分後画面OFF
|
||||
// 常時ON
|
||||
// 1分後時計画面
|
||||
// RMComboBox* RMSettingsWindowBase::_MC(QWidget *parent,QString title,QLayout* layout, QStringList items,int type,QList<int> indexMap,QLabel** titleLabel)
|
||||
RMComboBox* tc;
|
||||
tc = _MC(g,
|
||||
MKU8("\xe7\x94\xbb\xe9\x9d\xa2\xe8\xa1\xa8\xe7\xa4\xba"),
|
||||
gl,
|
||||
QStringList() << MKU8("\x31\xe5\x88\x86\xe5\xbe\x8c\xe7\x94\xbb\xe9\x9d\xa2\x4f\x46\x46") \
|
||||
<< MKU8("\xe5\xb8\xb8\xe6\x99\x82\x4f\x4e") \
|
||||
<< MKU8("\x31\xe5\x88\x86\xe5\xbe\x8c\xe6\x99\x82\xe8\xa8\x88\xe7\x94\xbb\xe9\x9d\xa2"),
|
||||
SD88_SCREEN_SAVEER,
|
||||
QList<int>(),&tl);
|
||||
tl->setFixedWidth(lbWidth);
|
||||
tc->comboBox->setFixedWidth(cWidth);
|
||||
|
||||
// 録画画面
|
||||
// フロント
|
||||
// リア
|
||||
// フロント/リア
|
||||
// リア/フロント
|
||||
tc = _MC(g,
|
||||
MKU8("\xe9\x8c\xb2\xe7\x94\xbb\xe7\x94\xbb\xe9\x9d\xa2"),
|
||||
gl,
|
||||
QStringList() << FM_WSTR(L"フロント") << FM_WSTR(L"サブ") << FM_WSTR(L"フロント/サブ") << FM_WSTR(L"サブ/フロント"),
|
||||
SD88_SCREEN_PIP,
|
||||
QList<int>(),&tl);
|
||||
tl->setFixedWidth(lbWidth);
|
||||
tc->comboBox->setFixedWidth(cWidth);
|
||||
|
||||
// スピーカー音量
|
||||
tc = _MC(g,
|
||||
MKU8("\xe3\x82\xb9\xe3\x83\x94\xe3\x83\xbc\xe3\x82\xab\xe3\x83\xbc\xe9\x9f\xb3\xe9\x87\x8f"),
|
||||
gl,
|
||||
QStringList() << "Off" << "1" << "2" << "3" << "4" << "5",
|
||||
SD88_SPEAKER,
|
||||
QList<int>(),&tl);
|
||||
tl->setFixedWidth(lbWidth);
|
||||
tc->comboBox->setFixedWidth(cWidth);
|
||||
|
||||
// MIC
|
||||
rb = _MR(g,FM_WSTR(L"録音設定"),gl,gEOffOn,SD88_MIC,QList<int>(),&tl);;
|
||||
tl->setFixedWidth(lbWidth);
|
||||
rb->setFixedWidth(rWidth);
|
||||
|
||||
|
||||
|
||||
// GROUP 2 STORAGE, メモリ割当
|
||||
g = new QGroupBox(row);
|
||||
g->setObjectName("settings");
|
||||
rowLayout->addWidget(g);
|
||||
g->setTitle(MKU8("\xe3\x83\xa1\xe3\x83\xa2\xe3\x83\xaa\xe5\x89\xb2\xe5\xbd\x93"));
|
||||
g->setFixedHeight(89);
|
||||
|
||||
gl = new QGridLayout(g);
|
||||
gl->setMargin(8);
|
||||
gl->setSpacing(4);
|
||||
|
||||
// メモリ割当情報
|
||||
// 常時録画重視
|
||||
// 駐車録画重視
|
||||
// イベント録画重視
|
||||
tc = _MC(g,
|
||||
MKU8("\xe3\x83\xa1\xe3\x83\xa2\xe3\x83\xaa\xe5\x89\xb2\xe5\xbd\x93\xe6\x83\x85\xe5\xa0\xb1"),
|
||||
gl,
|
||||
QStringList() << MKU8("\xe5\xb8\xb8\xe6\x99\x82\xe9\x8c\xb2\xe7\x94\xbb\xe9\x87\x8d\xe8\xa6\x96") \
|
||||
<< MKU8("\xe9\xa7\x90\xe8\xbb\x8a\xe9\x8c\xb2\xe7\x94\xbb\xe9\x87\x8d\xe8\xa6\x96") \
|
||||
<< MKU8("\xe3\x82\xa4\xe3\x83\x99\xe3\x83\xb3\xe3\x83\x88\xe9\x8c\xb2\xe7\x94\xbb\xe9\x87\x8d\xe8\xa6\x96"),
|
||||
SD88_VOLUME,
|
||||
QList<int>(),&tl);
|
||||
tl->setFixedWidth(lbWidth);
|
||||
tc->comboBox->setFixedWidth(cWidth);
|
||||
|
||||
|
||||
// GROUP 3 G-SENSOR, センサー感度
|
||||
g = new QGroupBox(row);
|
||||
g->setObjectName("settings");
|
||||
rowLayout->addWidget(g);
|
||||
g->setTitle(MKU8("\xe3\x82\xbb\xe3\x83\xb3\xe3\x82\xb5\xe3\x83\xbc\xe6\x84\x9f\xe5\xba\xa6"));
|
||||
g->setFixedHeight(120);
|
||||
|
||||
gl = new QGridLayout(g);
|
||||
gl->setMargin(8);
|
||||
gl->setSpacing(4);
|
||||
|
||||
// 常時センサー感度
|
||||
//QStringList sensors = QStringList() << "Low" << "Middle-Low" << "Middle" << "Middle-High" << "High";
|
||||
QStringList sensors = QStringList() << "1" << "2" << "3" << "4" << "5";
|
||||
|
||||
tc = _MC(g,
|
||||
MKU8("\xe5\xb8\xb8\xe6\x99\x82\xe3\x82\xbb\xe3\x83\xb3\xe3\x82\xb5\xe3\x83\xbc\xe6\x84\x9f\xe5\xba\xa6"),
|
||||
gl,
|
||||
sensors,
|
||||
SD88_GSENSOR_NORMAL,
|
||||
QList<int>(),&tl);
|
||||
tl->setFixedWidth(lbWidth);
|
||||
tc->comboBox->setFixedWidth(cWidth);
|
||||
|
||||
// 駐車センサー感度
|
||||
tc = _MC(g,
|
||||
MKU8("\xe9\xa7\x90\xe8\xbb\x8a\xe3\x82\xbb\xe3\x83\xb3\xe3\x82\xb5\xe3\x83\xbc\xe6\x84\x9f\xe5\xba\xa6"),
|
||||
gl,
|
||||
sensors,
|
||||
SD88_GSENSOR_PARKING,
|
||||
QList<int>(),&tl);
|
||||
tl->setFixedWidth(lbWidth);
|
||||
tc->comboBox->setFixedWidth(cWidth);
|
||||
|
||||
// GROUP 4 PARKING MODE, 駐車録画
|
||||
g = new QGroupBox(row);
|
||||
g->setObjectName("settings");
|
||||
rowLayout->addWidget(g);
|
||||
g->setTitle(MKU8("\xe9\xa7\x90\xe8\xbb\x8a\xe9\x8c\xb2\xe7\x94\xbb"));
|
||||
|
||||
gl = new QGridLayout(g);
|
||||
gl->setMargin(8);
|
||||
gl->setSpacing(4);
|
||||
|
||||
//駐車録画機能
|
||||
rb = _MR(g,MKU8("\xe9\xa7\x90\xe8\xbb\x8a\xe9\x8c\xb2\xe7\x94\xbb\xe6\xa9\x9f\xe8\x83\xbd"),gl,gEOffOn,SD88_PARKING_ON,QList<int>(),&tl);;
|
||||
tl->setFixedWidth(lbWidth);
|
||||
rb->setFixedWidth(rWidth);
|
||||
rb->setFixedHeight(45);
|
||||
|
||||
// 放電遮断電圧
|
||||
/*
|
||||
tl = new QLabel(this);
|
||||
tl->setObjectName("text_normal_label");
|
||||
tl->setText(MKU8("\xe6\x94\xbe\xe9\x9b\xbb\xe9\x81\xae\xe6\x96\xad\xe9\x9b\xbb\xe5\x9c\xa7"));
|
||||
gl->addWidget(tl,1,0,Qt::AlignLeft);
|
||||
*/
|
||||
|
||||
}
|
||||
void WindowSettings88::_createRowB()
|
||||
{
|
||||
QWidget* row = NULL;
|
||||
QVBoxLayout* rowLayout = NULL;
|
||||
QLabel* tl;
|
||||
RMRadioButtons* rb;
|
||||
const int lbWidth = 130;
|
||||
//const int cWidth = 150;
|
||||
const int rWidth = 220;
|
||||
|
||||
rowLayout = _createRow(&row);
|
||||
|
||||
//int fh = 55;
|
||||
|
||||
QGroupBox* g;
|
||||
QGridLayout* gl;
|
||||
|
||||
|
||||
|
||||
//暗証番号暗証番号設定OFF 0 ON暗証番号変更暗証番号設定をONにしているとき暗証番号変更(4桁)の入力が可能。
|
||||
|
||||
// GROUP 5 VIDEO, 録画設定
|
||||
g = new QGroupBox(row);
|
||||
g->setObjectName("settings");
|
||||
rowLayout->addWidget(g);
|
||||
g->setTitle(MKU8("\xe9\x8c\xb2\xe7\x94\xbb\xe8\xa8\xad\xe5\xae\x9a"));
|
||||
g->setFixedHeight(220);
|
||||
|
||||
gl = new QGridLayout(g);
|
||||
gl->setMargin(8);
|
||||
gl->setSpacing(4);
|
||||
|
||||
// 解像度
|
||||
rb = _MR(g,MKU8("\xe8\xa7\xa3\xe5\x83\x8f\xe5\xba\xa6"),gl,QStringList() << "FHD" << "HD",SD88_VIDEO_RESOLUTION,QList<int>(),&tl);;
|
||||
tl->setFixedWidth(lbWidth);
|
||||
rb->setFixedWidth(rWidth);
|
||||
|
||||
// 画質
|
||||
// 低
|
||||
// 中
|
||||
// 高
|
||||
/* 2021/11/22 수정제거
|
||||
rb = _MR(g,MKU8("\xe7\x94\xbb\xe8\xb3\xaa"),gl,QStringList() << MKU8("\xe4\xbd\x8e") << MKU8("\xe4\xb8\xad") << MKU8("\xe9\xab\x98"),SD88_VIDEO_QUALITY,QList<int>(),&tl);;
|
||||
tl->setFixedWidth(lbWidth);
|
||||
rb->setFixedWidth(rWidth);
|
||||
*/
|
||||
|
||||
// 録画フレーム数
|
||||
rb = _MR(g,MKU8("\xe9\x8c\xb2\xe7\x94\xbb\xe3\x83\x95\xe3\x83\xac\xe3\x83\xbc\xe3\x83\xa0\xe6\x95\xb0"),gl,QStringList() << "4.9 fps" << "19.1 fps" << "29.1 fps",SD88_VIDEO_FRAME,QList<int>(),&tl);;
|
||||
tl->setFixedWidth(lbWidth);
|
||||
rb->setFixedWidth(rWidth);
|
||||
|
||||
// サブカメラ録画
|
||||
rb = _MR(g,MKU8("\xe3\x82\xb5\xe3\x83\x96\xe3\x82\xab\xe3\x83\xa1\xe3\x83\xa9\xe9\x8c\xb2\xe7\x94\xbb"),gl,gEOffOn,SD88_VIDEO_SUB_CAMERA,QList<int>(),&tl);;
|
||||
tl->setFixedWidth(lbWidth);
|
||||
rb->setFixedWidth(rWidth);
|
||||
|
||||
// HDR
|
||||
rb = _MR(g,"HDR",gl,gEOffOn,SD88_VIDEO_HDR,QList<int>(),&tl);;
|
||||
tl->setFixedWidth(lbWidth);
|
||||
rb->setFixedWidth(rWidth);
|
||||
|
||||
// ナイトビジョン
|
||||
rb = _MR(g,MKU8("\xe3\x83\x8a\xe3\x82\xa4\xe3\x83\x88\xe3\x83\x93\xe3\x82\xb8\xe3\x83\xa7\xe3\x83\xb3"),gl,gEOffOn,SD88_VIDEO_NIGHT_VISION,QList<int>(),&tl);;
|
||||
tl->setFixedWidth(lbWidth);
|
||||
rb->setFixedWidth(rWidth);
|
||||
|
||||
// 관리자 암호 설정도 저장
|
||||
pw = new RMSettingAdminPW(&CFG::data[SD88_ADMIN_PW],(QList<int>() << 1 << 0), row);
|
||||
rowLayout->addWidget(pw);
|
||||
|
||||
//time = new RMSettingTime(row);
|
||||
//time->setFixedHeight(100);
|
||||
//rowLayout->addWidget(time);
|
||||
}
|
||||
void WindowSettings88::afterSave()
|
||||
{
|
||||
// if(time->check->isChecked()) {
|
||||
// time->onSave();
|
||||
// }
|
||||
#if (REMOVE_ADMIN_PW_CHECKBOX)
|
||||
// 저장
|
||||
if(CFG::data[SD88_ADMIN_PW] == 0) { // pw->buttons.at(1)->isChecked()) {
|
||||
#else
|
||||
if(pw->saveCheckbox->isChecked()) {
|
||||
#endif
|
||||
pw->onSave();
|
||||
}
|
||||
//qInfo() << __FUNCTION__;
|
||||
}
|
||||
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
#endif // #if (RM_MODEL)
|
||||
|
||||
71
project/fm_viewer/cfg/window_settings_xdr6688.h
Normal file
71
project/fm_viewer/cfg/window_settings_xdr6688.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef WINDOW_SETTINGS_H
|
||||
#define WINDOW_SETTINGS_H
|
||||
#if (USE_DEVICE_SETTINGS)
|
||||
|
||||
#include "../rm_include.h"
|
||||
#include "rm_settings_window_base.h"
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
|
||||
#include "../ui/rm_popup.h"
|
||||
#include <QGroupBox>
|
||||
#include <QRadioButton>
|
||||
|
||||
#define SETTING_NUM_ROW 3
|
||||
class RMSettingTime;
|
||||
class WindowSettings : public RMSettingsWindowBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
int _wwidth;
|
||||
int _wheight;
|
||||
explicit WindowSettings(QWidget *parent = 0);
|
||||
~WindowSettings();
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private slots:
|
||||
};
|
||||
|
||||
// XDR-66
|
||||
class WindowSettings66 : public WindowSettings
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WindowSettings66(QWidget *parent = 0);
|
||||
QVBoxLayout* _createRow(QWidget** rw);
|
||||
void afterSave() override;
|
||||
bool validateData(){return true;}
|
||||
private:
|
||||
RMSettingTime* time;
|
||||
void _createRowA();
|
||||
|
||||
private slots:
|
||||
};
|
||||
|
||||
// XDR-88
|
||||
class RMSettingAdminPW;
|
||||
class RMSettingTime;
|
||||
class WindowSettings88 : public WindowSettings
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WindowSettings88(QWidget *parent = 0);
|
||||
QVBoxLayout* _createRow(QWidget** rw);
|
||||
void afterSave() override;
|
||||
bool validateData(){return true;}
|
||||
private:
|
||||
RMSettingAdminPW* pw;
|
||||
//RMSettingTime* time;
|
||||
void _createRowA();
|
||||
void _createRowB();
|
||||
private slots:
|
||||
};
|
||||
|
||||
#endif // #if (RM_MODEL)
|
||||
#endif // #if (USE_DEVICE_SETTINGS)
|
||||
#endif // WINDOW_SETTINGS_H
|
||||
61
project/fm_viewer/cfg/window_settings_xldr_adas.h
Normal file
61
project/fm_viewer/cfg/window_settings_xldr_adas.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef WINDOW_SETTINGS_H
|
||||
#define WINDOW_SETTINGS_H
|
||||
|
||||
#include "../rm_include.h"
|
||||
#include "rm_settings_window_base.h"
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_F_ADAS)
|
||||
|
||||
#include "../ui/rm_popup.h"
|
||||
#include <QGroupBox>
|
||||
#include <QRadioButton>
|
||||
|
||||
#define SETTING_NUM_ROW 3
|
||||
|
||||
class WindowSettings : public RMSettingsWindowBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit WindowSettings(QWidget *parent = 0);
|
||||
~WindowSettings();
|
||||
|
||||
private:
|
||||
|
||||
// custom value save
|
||||
//int _lastRecordingSetting;
|
||||
//void _saveCustomRecordingSetting();
|
||||
//void _loadCustomRecordingSetting();
|
||||
|
||||
// Utility
|
||||
QVBoxLayout* _createRow(QWidget** rw);
|
||||
|
||||
//void _createRecordSetting(QWidget* row,QVBoxLayout* rowLayout);
|
||||
// RMRadioButtons* videoResolution; // 1
|
||||
// RMRadioButtons* videoQuality; // 2
|
||||
// RMRadioButtons* videoBrightness; // 3
|
||||
// RMRadioButtons* videoContrast; // 4
|
||||
|
||||
// void _createGSensorSensitivity(QWidget* row,QVBoxLayout* rowLayout);
|
||||
// RMGroupComboBox* gSensorSensitivity;
|
||||
// RMComboBox* gSensorSensitivityFB;
|
||||
// RMComboBox* gSensorSensitivityLR;
|
||||
// RMComboBox* gSensorSensitivityUD;
|
||||
|
||||
//void _createOrbis(QWidget* row,QVBoxLayout* rowLayout);
|
||||
//void _createDisasterAlarm(QWidget* row,QVBoxLayout* rowLayout);
|
||||
void _createFCWS(QWidget* row,QVBoxLayout* rowLayout);
|
||||
//void _createBCWS(QWidget* row,QVBoxLayout* rowLayout);
|
||||
//void _createFLIP(QWidget* row,QVBoxLayout* rowLayout);
|
||||
|
||||
void _createRowA();
|
||||
void _createRowB();
|
||||
//void _createRowC();
|
||||
|
||||
private slots:
|
||||
|
||||
//void onRecordSetting(int index);
|
||||
//void onGSensorSensitivity(int index);
|
||||
};
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_CS_91FH)
|
||||
#endif // WINDOW_SETTINGS_H
|
||||
805
project/fm_viewer/core/fm_strings.cpp
Normal file
805
project/fm_viewer/core/fm_strings.cpp
Normal file
@@ -0,0 +1,805 @@
|
||||
#include "fm_strings.h"
|
||||
#define DEBUG_FM_STRINGS 0
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#if (FM_STR_TYPE2)
|
||||
QMap<QString,QStringList> FMS::strings = QMap<QString,QStringList>();
|
||||
#else // FM_STR_TYPE2
|
||||
|
||||
#if !(MODEL_KOREAN_ONLY)
|
||||
QMap<QString,QString> FMS::jps = QMap<QString,QString>();
|
||||
#endif // MODEL_KOREAN_ONLY
|
||||
|
||||
#if(RM_MODEL == RM_MODEL_TYPE_ADT_CAPS || RM_MODEL == RM_MODEL_TYPE_TB4000 || RM_MODEL == RM_MODEL_TYPE_BV2000 || SUB_MODEL_KEIYO_KR || RM_MODEL == RM_MODEL_TYPE_MH9000 || RM_MODEL_TYPE_EMT_KR)
|
||||
QMap<QString,QString> FMS::kos = QMap<QString,QString>();
|
||||
#endif
|
||||
|
||||
#if(SUB_MODEL_BV5000 || RM_MODEL == RM_MODEL_TYPE_MH9000 || RM_MODEL_TYPE_EMT_KR)
|
||||
QMap<QString,QString> FMS::ens = QMap<QString,QString>();
|
||||
#endif
|
||||
#endif // FM_STR_TYPE2
|
||||
|
||||
bool FMS::_loaded = false;
|
||||
|
||||
#if (FM_STR_TYPE2)
|
||||
void FMS::load()
|
||||
{
|
||||
if(QFile::exists(":/raw/strings.txt"))
|
||||
{
|
||||
QFile f(":/raw/strings.txt");
|
||||
if (f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QTextStream in(&f);
|
||||
in.setCodec("UTF-8");
|
||||
while (!in.atEnd())
|
||||
{
|
||||
QString line = in.readLine();
|
||||
QStringList lst = line.split("|");
|
||||
QString key = lst.first();
|
||||
lst.removeFirst();
|
||||
FMS::strings.insert(key,lst);
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
QString FMS::txtLine(const char* key)
|
||||
{
|
||||
return txt(key).replace("\\n","\n");
|
||||
}
|
||||
QString FMS::txt(const char* key)
|
||||
{
|
||||
if(!_loaded) {
|
||||
load();
|
||||
_loaded = true;
|
||||
}
|
||||
return txt(key,RMLanguage::instance()->language());
|
||||
}
|
||||
|
||||
QString FMS::txt(const char* key,RMLanguage::LANGUAGE_TYPE type)
|
||||
{
|
||||
if(!strings.contains(key)) {
|
||||
qInfo() << "KEY NOT FOUND:" << key << __FUNCTION__;
|
||||
return "";
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
switch (type) {
|
||||
case RMLanguage::LANGUAGE_JP:
|
||||
idx = 1;
|
||||
break;
|
||||
case RMLanguage::LANGUAGE_KR:
|
||||
idx = 0;
|
||||
break;
|
||||
case RMLanguage::LANGUAGE_EN:
|
||||
idx = 2;
|
||||
break;
|
||||
}
|
||||
QStringList l = strings[key];
|
||||
if(l.size() > idx) {
|
||||
return l.at(idx);
|
||||
}
|
||||
qInfo() << "LANGUAGE NOT FOUND:" << key << "type:" << type << __FUNCTION__;
|
||||
return "";
|
||||
}
|
||||
#else // FM_STR_TYPE2
|
||||
void FMS::load()
|
||||
{
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_TBD360) // ENG
|
||||
jps.insert("report","Report");
|
||||
jps.insert("map","Map");
|
||||
jps.insert("language","Language");
|
||||
|
||||
jps.insert("file_type","Type");
|
||||
jps.insert("file_name","File Name");
|
||||
jps.insert("file_duration","Duration");
|
||||
|
||||
jps.insert("restart_msg","The application must restart in order to enable/disable H/W acceleration");
|
||||
|
||||
// ビューア情報
|
||||
jps.insert("viewer_info","Viewer Info.");
|
||||
|
||||
jps.insert("capture","Capture");
|
||||
jps.insert("close","Close");
|
||||
jps.insert("minimize","Minimize");
|
||||
jps.insert("low_speed","Low Speed");
|
||||
jps.insert("high_speed","High Speed");
|
||||
jps.insert("flip_h","Flip Horizontal");
|
||||
jps.insert("flip_v","Flip Vertical");
|
||||
|
||||
// フロント・リア切替え
|
||||
jps.insert("swap","Swap Screen");
|
||||
|
||||
jps.insert("mode_360","Camera Mode");
|
||||
jps.insert("zoom_360","Zoom Mode");
|
||||
jps.insert("reset_360","Reset Camera");
|
||||
|
||||
jps.insert("fullscreen","Full Screen");
|
||||
|
||||
jps.insert("graph_zoom_in","Zoom In");
|
||||
jps.insert("graph_zoom_out","Zoom Out");
|
||||
|
||||
jps.insert("brightness","Brightness");
|
||||
jps.insert("contrast","Contrast");
|
||||
jps.insert("play_speed","Speed");
|
||||
jps.insert("volume_mute","Mute");
|
||||
jps.insert("volume_un_mute","Unmute");
|
||||
|
||||
jps.insert("play_backward","Seek backward");
|
||||
jps.insert("play_forward","Seek forward");
|
||||
|
||||
jps.insert("play_play","Play");
|
||||
jps.insert("play_stop","Stop");
|
||||
jps.insert("play_file_previous","Previous File");
|
||||
jps.insert("play_file_next","Next File");
|
||||
jps.insert("open","Open");
|
||||
jps.insert("play_pause","Pause");
|
||||
|
||||
jps.insert("backup","Backup");
|
||||
|
||||
jps.insert("viewer_sw_version","S/W Version");
|
||||
jps.insert("hw_accel","Graphic Accelation");
|
||||
|
||||
jps.insert("ok","OK");
|
||||
jps.insert("cancel","Cancel");
|
||||
jps.insert("change","Change");
|
||||
|
||||
// 入力,確認
|
||||
jps.insert("input","Input");
|
||||
jps.insert("confirm","Confirm");
|
||||
jps.insert("old","Previous");
|
||||
// 間違ったパスワード
|
||||
jps.insert("password_wrong","Wrong Password");
|
||||
|
||||
// 注意
|
||||
jps.insert("warning","Warning");
|
||||
|
||||
jps.insert("save","Save");
|
||||
|
||||
// 初期値
|
||||
jps.insert("default","Default");
|
||||
|
||||
// 緯度
|
||||
jps.insert("lat","LAT:");
|
||||
|
||||
//経度
|
||||
jps.insert("lon","LON:");
|
||||
|
||||
// 録画ファイルがあるフォルダを選択
|
||||
jps.insert("open_message","Select the folder");
|
||||
#else
|
||||
|
||||
#if (SUB_MODEL_BV5000 || RM_MODEL == RM_MODEL_TYPE_MH9000 || RM_MODEL_TYPE_EMT_KR)
|
||||
ens.insert("report","Report");
|
||||
ens.insert("map","Map");
|
||||
ens.insert("language","Language");
|
||||
ens.insert("auto_select","Auto");
|
||||
|
||||
|
||||
ens.insert("file_type","Type");
|
||||
ens.insert("file_name","File Name");
|
||||
ens.insert("file_duration","Duration");
|
||||
|
||||
ens.insert("file_date","Date");
|
||||
ens.insert("file_size","Size");
|
||||
|
||||
ens.insert("restart_msg","The application must restart in order to enable/disable H/W acceleration");
|
||||
|
||||
// ビューア情報
|
||||
ens.insert("viewer_info","Viewer Info.");
|
||||
|
||||
ens.insert("capture","Capture");
|
||||
ens.insert("close","Close");
|
||||
ens.insert("minimize","Minimize");
|
||||
ens.insert("maximize","Maximize");
|
||||
ens.insert("restore_window","Restore Window");
|
||||
ens.insert("low_speed","Low Speed");
|
||||
ens.insert("high_speed","High Speed");
|
||||
ens.insert("flip_h","Flip Horizontal");
|
||||
ens.insert("flip_v","Flip Vertical");
|
||||
|
||||
// フロント・リア切替え
|
||||
ens.insert("swap","Swap Screen");
|
||||
|
||||
ens.insert("mode_360","Camera Mode");
|
||||
ens.insert("zoom_360","Zoom Mode");
|
||||
ens.insert("reset_360","Reset Camera");
|
||||
|
||||
ens.insert("fullscreen","Full Screen");
|
||||
|
||||
ens.insert("graph_zoom_in","Zoom In");
|
||||
ens.insert("graph_zoom_out","Zoom Out");
|
||||
|
||||
ens.insert("brightness","Brightness");
|
||||
ens.insert("contrast","Contrast");
|
||||
ens.insert("play_speed","Speed");
|
||||
ens.insert("volume_mute","Mute");
|
||||
ens.insert("volume_un_mute","Unmute");
|
||||
|
||||
ens.insert("play_backward","Seek backward");
|
||||
ens.insert("play_forward","Seek forward");
|
||||
|
||||
ens.insert("play_play","Play");
|
||||
ens.insert("play_stop","Stop");
|
||||
ens.insert("play_file_previous","Previous File");
|
||||
ens.insert("play_file_next","Next File");
|
||||
ens.insert("open","Open");
|
||||
ens.insert("play_pause","Pause");
|
||||
|
||||
ens.insert("backup","Backup");
|
||||
|
||||
ens.insert("viewer_sw_version","S/W Version");
|
||||
ens.insert("hw_accel","Graphic Accelation");
|
||||
|
||||
ens.insert("ok","OK");
|
||||
ens.insert("cancel","Cancel");
|
||||
ens.insert("change","Change");
|
||||
|
||||
// 入力,確認
|
||||
ens.insert("input","Input");
|
||||
ens.insert("confirm","Confirm");
|
||||
ens.insert("old","Previous");
|
||||
// 間違ったパスワード
|
||||
ens.insert("password_wrong","Wrong Password");
|
||||
|
||||
// 注意
|
||||
ens.insert("warning","Warning");
|
||||
|
||||
ens.insert("save","Save");
|
||||
|
||||
// 初期値
|
||||
ens.insert("default","Default");
|
||||
|
||||
// 緯度
|
||||
ens.insert("lat","LAT:");
|
||||
|
||||
//経度
|
||||
ens.insert("lon","LON:");
|
||||
|
||||
// 録画ファイルがあるフォルダを選択
|
||||
ens.insert("open_message","Select the folder");
|
||||
#endif // BV5000 ENG
|
||||
|
||||
#if !(MODEL_KOREAN_ONLY)
|
||||
// 파일 저장
|
||||
// ファイルの保存
|
||||
jps.insert("backup_title",FM_WSTR(L"バックアップ中"));
|
||||
|
||||
// 파일 종류
|
||||
jps.insert("type_event",FM_WSTR(L"衝撃検知"));
|
||||
jps.insert("type_manual",FM_WSTR(L"手動"));
|
||||
jps.insert("type_parking_normal",FM_WSTR(L"駐車監視"));
|
||||
jps.insert("type_parking",FM_WSTR(L"パーキング"));
|
||||
jps.insert("type_parking_event",FM_WSTR(L"駐車衝撃"));
|
||||
jps.insert("type_normal",FM_WSTR(L"常時"));
|
||||
#endif // #if !(MODEL_KOREAN_ONLY)
|
||||
|
||||
#if(SUB_MODEL_BV5000 || RM_MODEL == RM_MODEL_TYPE_MH9000 || RM_MODEL_TYPE_EMT_KR)
|
||||
ens.insert("type_event","EVENT");
|
||||
ens.insert("type_manual","MANUAL");
|
||||
ens.insert("type_parking_normal","PARKING");
|
||||
ens.insert("type_parking","PARKING");
|
||||
ens.insert("type_parking_event","PAKING.E");
|
||||
ens.insert("type_normal","NORMAL");
|
||||
#endif // #if(SUPPORT_LANGUAGE_INSERT)
|
||||
|
||||
#if (RC_LANGUAGE==0x0412 || MODEL_KOREAN_ONLY)
|
||||
kos.insert("type_event",FM_WSTR(L"이벤트"));
|
||||
kos.insert("type_manual",FM_WSTR(L"수동"));
|
||||
kos.insert("type_parking_normal",FM_WSTR(L"주차감시"));
|
||||
kos.insert("type_parking",FM_WSTR(L"주차"));
|
||||
kos.insert("type_parking_event",FM_WSTR(L"주차E"));
|
||||
kos.insert("type_normal",FM_WSTR(L"상시"));
|
||||
kos.insert("restart_msg",FM_WSTR(L"설정 적용을 위해 뷰어를 다시 시작 합니다."));
|
||||
kos.insert("report",FM_WSTR(L"보고서"));
|
||||
kos.insert("map",FM_WSTR(L"지도"));
|
||||
kos.insert("language",FM_WSTR(L"언어"));
|
||||
kos.insert("file_type",FM_WSTR(L"분류"));
|
||||
kos.insert("file_name",FM_WSTR(L"파일명"));
|
||||
kos.insert("file_date",FM_WSTR(L"날짜"));
|
||||
kos.insert("file_duration",FM_WSTR(L"재생시간"));
|
||||
kos.insert("file_size",FM_WSTR(L"크기")); // タイプ
|
||||
|
||||
kos.insert("viewer_info",FM_WSTR(L"S/W 정보"));
|
||||
kos.insert("speed_warning",FM_WSTR(L"GPS 속도는 실제 속도와 다를 수 있습니다."));
|
||||
kos.insert("capture",FM_WSTR(L"JPG 저장"));
|
||||
kos.insert("capture_desc",FM_WSTR(L"현재 화면을 JPEG 파일로 저장 합니다"));
|
||||
|
||||
kos.insert("close",FM_WSTR(L"닫기"));
|
||||
kos.insert("minimize",FM_WSTR(L"최소화"));
|
||||
kos.insert("maximize",FM_WSTR(L"최대화"));
|
||||
kos.insert("restore_window",FM_WSTR(L"이전 크기로 복원"));
|
||||
kos.insert("low_speed",FM_WSTR(L"저속"));
|
||||
kos.insert("high_speed",FM_WSTR(L"고속"));
|
||||
kos.insert("flip_h",FM_WSTR(L"좌우반전"));
|
||||
kos.insert("flip_v",FM_WSTR(L"상하반전"));
|
||||
kos.insert("swap",FM_WSTR(L"전후방 화면 전환"));
|
||||
kos.insert("indoor",FM_WSTR(L"실내외 화면 전환"));
|
||||
kos.insert("fullscreen",FM_WSTR(L"전체화면"));
|
||||
kos.insert("graph_zoom_in",FM_WSTR(L"확대"));
|
||||
kos.insert("graph_zoom_out",FM_WSTR(L"축소"));
|
||||
kos.insert("brightness",FM_WSTR(L"밝기조정"));
|
||||
kos.insert("contrast",FM_WSTR(L"대비조정"));
|
||||
kos.insert("play_speed",FM_WSTR(L"재생속도"));
|
||||
kos.insert("volume_mute",FM_WSTR(L"음량"));
|
||||
kos.insert("volume_un_mute",FM_WSTR(L"음량"));
|
||||
|
||||
kos.insert("play_backward",FM_WSTR(L"1초 이전으로 이동"));
|
||||
kos.insert("play_forward",FM_WSTR(L"1초 이후로 이동"));
|
||||
|
||||
kos.insert("play_play",FM_WSTR(L"재생"));
|
||||
kos.insert("play_stop",FM_WSTR(L"정지"));
|
||||
kos.insert("play_file_previous",FM_WSTR(L"이전 파일"));
|
||||
kos.insert("play_file_next",FM_WSTR(L"다음 파일"));
|
||||
kos.insert("open",FM_WSTR(L"파일 열기"));
|
||||
kos.insert("open_title",FM_WSTR(L"파일 열기"));
|
||||
kos.insert("play_pause",FM_WSTR(L"일시 정지"));
|
||||
kos.insert("backup_title",FM_WSTR(L"파일 저장"));
|
||||
kos.insert("file_exist",FM_WSTR(L"이 위치에 같은 이름의 파일이 있습니다."));
|
||||
kos.insert("apply_rule",FM_WSTR(L"동일한 작업을 다음의"));
|
||||
kos.insert("after_files",FM_WSTR(L"파일에도 적용"));
|
||||
kos.insert("skip",FM_WSTR(L"건너뛰기"));
|
||||
kos.insert("overwrite",FM_WSTR(L"덮어쓰기"));
|
||||
kos.insert("auto_select",FM_WSTR(L"자동선택"));
|
||||
kos.insert("select_language",FM_WSTR(L"언어 선택"));
|
||||
kos.insert("enter_file_name",FM_WSTR(L"파일명을 입력해 주십시오"));
|
||||
kos.insert("front_suffix",FM_WSTR(L"전방"));
|
||||
kos.insert("rear_suffix",FM_WSTR(L"후방"));
|
||||
kos.insert("save_jpg_fail",FM_WSTR(L"JPEG 파일 생성 실패"));
|
||||
|
||||
kos.insert("thumbnail",FM_WSTR(L"썸네일보기"));
|
||||
kos.insert("register",FM_WSTR(L"적발원부"));
|
||||
kos.insert("save_video",FM_WSTR(L"영상저장"));
|
||||
|
||||
kos.insert("reset_360",FM_WSTR(L"초기화"));
|
||||
kos.insert("save_360",FM_WSTR(L"파일로 저장"));
|
||||
|
||||
//
|
||||
kos.insert("backup_title",FM_WSTR(L"파일 저장중..."));
|
||||
|
||||
kos.insert("change_folder",FM_WSTR(L"폴더 선택"));
|
||||
kos.insert("backup",FM_WSTR(L"파일 저장"));
|
||||
kos.insert("viewer_sw_version",FM_WSTR(L"Viewer S/W 버전 정보"));
|
||||
kos.insert("hw_accel",FM_WSTR(L"H/W 가속 설정"));
|
||||
kos.insert("pw_message",FM_WSTR(L"암호 (4 자 이상 20 자 이하) 생성."));
|
||||
kos.insert("password",FM_WSTR(L"암호"));
|
||||
kos.insert("password_new",FM_WSTR(L"신규 암호"));
|
||||
kos.insert("password_input",FM_WSTR(L"암호 입력"));
|
||||
kos.insert("password_change",FM_WSTR(L"암호 변경"));
|
||||
kos.insert("ok",FM_WSTR(L"확인"));
|
||||
kos.insert("cancel",FM_WSTR(L"취소"));
|
||||
kos.insert("change",FM_WSTR(L"변경"));
|
||||
kos.insert("input",FM_WSTR(L"입력"));
|
||||
kos.insert("confirm",FM_WSTR(L"확인"));
|
||||
kos.insert("old",FM_WSTR(L"이전"));
|
||||
kos.insert("password_wrong",FM_WSTR(L"잘못된 암호"));
|
||||
kos.insert("invalid_media",FM_WSTR(L"재생할 수 없는 파일입니다"));
|
||||
kos.insert("warning",FM_WSTR(L"주의"));
|
||||
kos.insert("file_not_exist",FM_WSTR(L"파일이 존재하지 않습니다"));
|
||||
|
||||
kos.insert("save",FM_WSTR(L"저장"));
|
||||
kos.insert("default",FM_WSTR(L"초기화"));
|
||||
kos.insert("lat",FM_WSTR(L"위도"));
|
||||
kos.insert("lon",FM_WSTR(L"경도"));
|
||||
kos.insert("open_message",FM_WSTR(L"녹화 파일이 있는 폴더를 선택"));
|
||||
|
||||
kos.insert("password",FM_WSTR(L"비밀번호설정"));
|
||||
|
||||
#endif // SUPPORT_LANGUAGE_INSERT || MODEL_KOREAN_ONLY
|
||||
|
||||
#if !(MODEL_KOREAN_ONLY)
|
||||
jps.insert("settings",FM_WSTR(L"設定"));
|
||||
#endif // MODEL_KOREAN_ONLY
|
||||
kos.insert("settings",FM_WSTR(L"설정"));
|
||||
ens.insert("settings",FM_WSTR(L"Settings"));
|
||||
|
||||
#if(SUPPORT_LANGUAGE_INSERT || RM_MODEL == RM_MODEL_TYPE_MH9000)
|
||||
ens.insert("open_title","Open");
|
||||
ens.insert("select_language","Select language");
|
||||
|
||||
#endif // #if(SUPPORT_LANGUAGE_INSERT)
|
||||
|
||||
#if !(MODEL_KOREAN_ONLY)
|
||||
jps.insert("info",FM_WSTR(L"ビューアー情報"));
|
||||
#endif // #if !(MODEL_KOREAN_ONLY)
|
||||
|
||||
#if(SUPPORT_LANGUAGE_INSERT)
|
||||
kos.insert("info",FM_WSTR(L"뷰어정보"));
|
||||
ens.insert("info",FM_WSTR(L"Viewer Info."));
|
||||
#endif // #if(SUPPORT_LANGUAGE_INSERT)
|
||||
|
||||
#if !(MODEL_KOREAN_ONLY)
|
||||
jps.insert("report","\xe3\x83\xac\xe3\x83\x9d\xe3\x83\xbc\xe3\x83\x88");
|
||||
jps.insert("map","\xe5\x9c\xb0\xe5\x9b\xb3");
|
||||
jps.insert("language","\xe8\xa8\x80\xe8\xaa\x9e\xe9\x81\xb8\xe6\x8a\x9e");
|
||||
|
||||
jps.insert("file_type","\xe3\x82\xbf\xe3\x82\xa4\xe3\x83\x97"); // タイプ
|
||||
jps.insert("file_name","\xe3\x83\x95\xe3\x82\xa1\xe3\x82\xa4\xe3\x83\xab\xe5\x90\x8d"); // ファイル名
|
||||
jps.insert("file_date",FM_WSTR(L"ファイル日付")); // ファイル名
|
||||
jps.insert("file_duration","\xe9\x8c\xb2\xe7\x94\xbb\xe6\x99\x82\xe9\x96\x93"); // 録画時間
|
||||
jps.insert("file_size",FM_WSTR(L"サイズ")); // タイプ
|
||||
|
||||
// 재기동 경고 再起動します
|
||||
jps.insert("restart_msg","\xe5\x86\x8d\xe8\xb5\xb7\xe5\x8b\x95\xe3\x81\x97\xe3\x81\xbe\xe3\x81\x99");
|
||||
|
||||
// ビューア情報
|
||||
jps.insert("viewer_info","\xe3\x83\x93\xe3\x83\xa5\xe3\x83\xbc\xe3\x82\xa2\xe6\x83\x85\xe5\xa0\xb1");
|
||||
|
||||
//速度はGPS算出値となります。実際の速度とは異なります。
|
||||
jps.insert("speed_warning","\xe9\x80\x9f\xe5\xba\xa6\xe3\x81\xaf\x47\x50\x53\xe7\xae\x97\xe5\x87\xba\xe5\x80\xa4\xe3\x81\xa8\xe3\x81\xaa\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe5\xae\x9f\xe9\x9a\x9b\xe3\x81\xae\xe9\x80\x9f\xe5\xba\xa6\xe3\x81\xa8\xe3\x81\xaf\xe7\x95\xb0\xe3\x81\xaa\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82");
|
||||
|
||||
jps.insert("capture","\x4a\x50\x47 \xe4\xbf\x9d\xe5\xad\x98");
|
||||
jps.insert("capture_desc",FM_WSTR(L"キャプチャーをJPEGで保存します"));
|
||||
//
|
||||
jps.insert("close","\xe9\x96\x89\xe3\x81\x98\xe3\x82\x8b"); // 閉じる
|
||||
jps.insert("minimize","\xe6\x9c\x80\xe5\xb0\x8f\xe5\x8c\x96"); // 最小化
|
||||
jps.insert("maximize","\xe6\x9c\x80\xe5\xa4\xa7\xe5\x8c\x96"); // 最大化
|
||||
jps.insert("restore_window","\xe5\x85\x83\xe3\x81\xab\xe6\x88\xbb\xe3\x81\x99\xef\xbc\x88\xe7\xb8\xae\xe5\xb0\x8f\xef\xbc\x89"); // 元に戻す(縮小)
|
||||
jps.insert("low_speed","\xe4\xbd\x8e\xe9\x80\x9f");
|
||||
jps.insert("high_speed","\xe9\xab\x98\xe9\x80\x9f \x28 \x31\x33\x30 \x4b\x6d\x2f\x68 \xe4\xbb\xa5\xe4\xb8\x8a \x29");
|
||||
jps.insert("flip_h","\xe5\xb7\xa6\xe5\x8f\xb3\xe5\x8f\x8d\xe8\xbb\xa2"); // 左右反転
|
||||
jps.insert("flip_v","\xe4\xb8\x8a\xe4\xb8\x8b\xe5\x8f\x8d\xe8\xbb\xa2"); // 上下反転
|
||||
|
||||
|
||||
// フロント・リア切替え
|
||||
// フロント・サブ切替え
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
jps.insert("swap",FM_WSTR(L"フロント・サブ切替え"));
|
||||
#else
|
||||
// フロント・リア切替え
|
||||
#if (SUB_MODEL_KEIYO_360)
|
||||
jps.insert("swap",FM_WSTR(L"360度・ワイド切り替え"));
|
||||
#else // SUB_MODEL_KEIYO_360
|
||||
jps.insert("swap",FM_WSTR(L"フロント・リア切替え"));
|
||||
#endif // SUB_MODEL_KEIYO_360
|
||||
#endif
|
||||
jps.insert("indoor",FM_WSTR(L"室内・外切替え"));
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MBJ5010 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_BV2000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_FC_DR232W) // 最大化,フルスクリーン
|
||||
// フルスクリーン
|
||||
jps.insert("fullscreen","\xe3\x83\x95\xe3\x83\xab\xe3\x82\xb9\xe3\x82\xaf\xe3\x83\xaa\xe3\x83\xbc\xe3\x83\xb3");
|
||||
#else
|
||||
jps.insert("fullscreen","\xe6\x9c\x80\xe5\xa4\xa7\xe5\x8c\x96");
|
||||
#endif
|
||||
|
||||
jps.insert("graph_zoom_in","\xe6\x8b\xa1\xe5\xa4\xa7"); // 拡大
|
||||
jps.insert("graph_zoom_out","\xe7\xb8\xae\xe5\xb0\x8f"); // 縮小
|
||||
|
||||
jps.insert("brightness","\xe6\x98\x8e\xe3\x82\x8b\xe3\x81\x95"); // 明るさ
|
||||
jps.insert("contrast","\xe3\x82\xb3\xe3\x83\xb3\xe3\x83\x88\xe3\x83\xa9\xe3\x82\xb9\xe3\x83\x88"); // コントラスト
|
||||
jps.insert("play_speed","\xe5\x86\x8d\xe7\x94\x9f\xe9\x80\x9f\xe5\xba\xa6"); // 再生速度
|
||||
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_BV2000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MBJ5010 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_FC_DR232W) // 音量
|
||||
jps.insert("volume_mute","\xe9\x9f\xb3\xe9\x87\x8f"); // 音量
|
||||
jps.insert("volume_un_mute","\xe9\x9f\xb3\xe9\x87\x8f");
|
||||
#else
|
||||
jps.insert("volume_mute","\xe6\xb6\x88\xe9\x9f\xb3\xe3\x83\xa2\xe3\x83\xbc\xe3\x83\x89");
|
||||
jps.insert("volume_un_mute","\xe3\x83\x9f\xe3\x83\xa5\xe3\x83\xbc\xe3\x83\x88\xe3\x81\xae\xe8\xa7\xa3\xe9\x99\xa4");
|
||||
#endif
|
||||
|
||||
|
||||
#if (SEEK_STEP_SIZE == 10)
|
||||
jps.insert("play_backward","\x31\x30\xe7\xa7\x92\xe5\x89\x8d\xe3\x81\xb8"); // 10秒前へ
|
||||
jps.insert("play_forward","\x31\x30\xe7\xa7\x92\xe9\x80\xb2\xe3\x82\x80"); // 10秒進む
|
||||
#else
|
||||
jps.insert("play_backward","\x31\xe7\xa7\x92\xe5\x89\x8d\xe3\x81\xb8");
|
||||
jps.insert("play_forward","\x31\xe7\xa7\x92\xe9\x80\xb2\xe3\x82\x80");
|
||||
#endif
|
||||
jps.insert("play_play","\xe5\x86\x8d\xe7\x94\x9f"); // 再生
|
||||
jps.insert("play_stop","\xe5\x81\x9c\xe6\xad\xa2"); // 停止
|
||||
jps.insert("play_file_previous","\xe5\x89\x8d\xe3\x81\xae\xe3\x83\x95\xe3\x82\xa1\xe3\x82\xa4\xe3\x83\xab"); // 前のファイル <- \xe4\xbb\xa5\xe5\x89\x8d\xe3\x83\x95\xe3\x82\xa1\xe3\x82\xa4\xe3\x83\xab
|
||||
jps.insert("play_file_next","\xe6\xac\xa1\xe3\x81\xae\xe3\x83\x95\xe3\x82\xa1\xe3\x82\xa4\xe3\x83\xab");
|
||||
jps.insert("open","\xe3\x83\x95\xe3\x82\xa1\xe3\x82\xa4\xe3\x83\xab\xe3\x82\x92\xe9\x96\x8b\xe3\x81\x8f");
|
||||
jps.insert("play_pause","\xe4\xb8\x80\xe6\x99\x82\xe5\x81\x9c\xe6\xad\xa2");
|
||||
jps.insert("open_title",FM_WSTR(L"ファイルOPEN"));
|
||||
|
||||
|
||||
//
|
||||
jps.insert("backup_title",FM_WSTR(L"ファイルの保存"));
|
||||
|
||||
jps.insert("file_exist",FM_WSTR(L"この場所に同じ名前のファイルがあります。"));
|
||||
|
||||
jps.insert("apply_rule",FM_WSTR(L"同じ処理を次の"));
|
||||
jps.insert("after_files",FM_WSTR(L"個の競合に適用"));
|
||||
|
||||
jps.insert("skip",FM_WSTR(L"スキップ"));
|
||||
|
||||
jps.insert("overwrite",FM_WSTR(L"置き換える"));
|
||||
|
||||
jps.insert("auto_select",FM_WSTR(L"自動"));
|
||||
|
||||
jps.insert("select_language",FM_WSTR(L"言語を選択してください"));
|
||||
|
||||
jps.insert("enter_file_name",FM_WSTR(L"ファイル名を入れてください。"));
|
||||
|
||||
jps.insert("front_suffix",FM_WSTR(L"前方"));
|
||||
jps.insert("rear_suffix",FM_WSTR(L"後方"));
|
||||
|
||||
jps.insert("save_jpg_fail",FM_WSTR(L"JPEGファイル生成に失敗しました。"));
|
||||
|
||||
jps.insert("change_folder",FM_WSTR(L"フォルダー変更"));
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MBJ5010 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_BV2000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_FC_DR232W)
|
||||
jps.insert("backup","\xe3\x82\xb3\xe3\x83\x94\xe3\x83\xbc"); // コピー
|
||||
#else
|
||||
jps.insert("backup","\xe4\xbf\x9d\xe5\xad\x98");
|
||||
#endif
|
||||
|
||||
// Viewer S/W バージョン情報
|
||||
jps.insert("viewer_sw_version","\x56\x69\x65\x77\x65\x72 \x53\x2f\x57 \xe3\x83\x90\xe3\x83\xbc\xe3\x82\xb8\xe3\x83\xa7\xe3\x83\xb3\xe6\x83\x85\xe5\xa0\xb1");
|
||||
// ハードウェアアクセラレーション
|
||||
jps.insert("hw_accel","\xe3\x83\x8f\xe3\x83\xbc\xe3\x83\x89\xe3\x82\xa6\xe3\x82\xa7\xe3\x82\xa2\xe3\x82\xa2\xe3\x82\xaf\xe3\x82\xbb\xe3\x83\xa9\xe3\x83\xac\xe3\x83\xbc\xe3\x82\xb7\xe3\x83\xa7\xe3\x83\xb3");
|
||||
|
||||
jps.insert("directx_audio",FM_WSTR(L"DirectX Audio でサウンド再生"));
|
||||
|
||||
// パスワード作成(4文字以上20文字以内)生成。
|
||||
jps.insert("pw_message","\xe3\x83\x91\xe3\x82\xb9\xe3\x83\xaf\xe3\x83\xbc\xe3\x83\x89\xe4\xbd\x9c\xe6\x88\x90\xef\xbc\x88\x34\xe6\x96\x87\xe5\xad\x97\xe4\xbb\xa5\xe4\xb8\x8a\x32\x30\xe6\x96\x87\xe5\xad\x97\xe4\xbb\xa5\xe5\x86\x85\xef\xbc\x89\xe7\x94\x9f\xe6\x88\x90\xe3\x80\x82");
|
||||
|
||||
// パスワード
|
||||
jps.insert("password","\xe3\x83\x91\xe3\x82\xb9\xe3\x83\xaf\xe3\x83\xbc\xe3\x83\x89");
|
||||
|
||||
// パスワード作成
|
||||
jps.insert("password_new","\xe3\x83\x91\xe3\x82\xb9\xe3\x83\xaf\xe3\x83\xbc\xe3\x83\x89\xe4\xbd\x9c\xe6\x88\x90");
|
||||
|
||||
// パスワード入力
|
||||
jps.insert("password_input","\xe3\x83\x91\xe3\x82\xb9\xe3\x83\xaf\xe3\x83\xbc\xe3\x83\x89\xe5\x85\xa5\xe5\x8a\x9b");
|
||||
// パスワード変更
|
||||
jps.insert("password_change","\xe3\x83\x91\xe3\x82\xb9\xe3\x83\xaf\xe3\x83\xbc\xe3\x83\x89\xe5\xa4\x89\xe6\x9b\xb4");
|
||||
|
||||
|
||||
jps.insert("ok","\x4f\x4b");
|
||||
|
||||
jps.insert("cancel","\xe3\x82\xad\xe3\x83\xa3\xe3\x83\xb3\xe3\x82\xbb\xe3\x83\xab"); // キャンセル
|
||||
|
||||
jps.insert("change","\xe5\xa4\x89\xe6\x9b\xb4"); // 変更
|
||||
|
||||
// 入力,確認
|
||||
jps.insert("input","\xe5\x85\xa5\xe5\x8a\x9b"); // 入力
|
||||
jps.insert("confirm","\xe7\xa2\xba\xe8\xaa\x8d"); // 確認
|
||||
jps.insert("old","\xe4\xbb\xa5\xe5\x89\x8d"); // 以前
|
||||
|
||||
//jps.insert("file_open_title","\xe3\x83\x95\xe3\x82\xa1\xe3\x82\xa4\xe3\x83\xab\x4f\x50\x45\x4e")
|
||||
|
||||
|
||||
// 間違ったパスワード
|
||||
jps.insert("password_wrong","\xe9\x96\x93\xe9\x81\x95\xe3\x81\xa3\xe3\x81\x9f\xe3\x83\x91\xe3\x82\xb9\xe3\x83\xaf\xe3\x83\xbc\xe3\x83\x89");
|
||||
|
||||
// 注意
|
||||
jps.insert("warning","\xe6\xb3\xa8\xe6\x84\x8f");
|
||||
jps.insert("file_not_exist",FM_WSTR(L"ファイルがありません"));
|
||||
|
||||
// \x4a\x50\x47 \xe4\xbf\x9d\xe5\xad\x98
|
||||
// 保存 \xe4\xbf\x9d\xe5\xad\x98
|
||||
jps.insert("save","\xe4\xbf\x9d\xe5\xad\x98");
|
||||
|
||||
// 初期値
|
||||
jps.insert("default","\xe5\x88\x9d\xe6\x9c\x9f\xe5\x80\xa4");
|
||||
|
||||
// 緯度
|
||||
jps.insert("lat","\xe7\xb7\xaf\xe5\xba\xa6");
|
||||
|
||||
//経度
|
||||
jps.insert("lon","\xe7\xb5\x8c\xe5\xba\xa6");
|
||||
|
||||
// 録画ファイルがあるフォルダを選択
|
||||
jps.insert("open_message","\xe9\x8c\xb2\xe7\x94\xbb\xe3\x83\x95\xe3\x82\xa1\xe3\x82\xa4\xe3\x83\xab\xe3\x81\x8c\xe3\x81\x82\xe3\x82\x8b\xe3\x83\x95\xe3\x82\xa9\xe3\x83\xab\xe3\x83\x80\xe3\x82\x92\xe9\x81\xb8\xe6\x8a\x9e");
|
||||
|
||||
|
||||
// ファイル分割
|
||||
jps.insert("split_files",FM_WSTR(L"ファイル分割"));
|
||||
|
||||
#endif // #if !(MODEL_KOREAN_ONLY)
|
||||
|
||||
#if(RM_MODEL == RM_MODEL_TYPE_ADT_CAPS)
|
||||
kos.insert("report","\xeb\xb3\xb4\xea\xb3\xa0\xec\x84\x9c");
|
||||
kos.insert("map","\xec\xa7\x80\xeb\x8f\x84");
|
||||
kos.insert("language","\xec\x96\xb8\xec\x96\xb4");
|
||||
kos.insert("viewer_info","\xeb\xb7\xb0\xec\x96\xb4\xec\xa0\x95\xeb\xb3\xb4");
|
||||
kos.insert("capture","\xed\x99\x94\xeb\xa9\xb4\xec\xba\xa1\xec\xb3\x90");
|
||||
kos.insert("setup","");
|
||||
kos.insert("close","\xeb\x8b\xab\xea\xb8\xb0"); // 닫기
|
||||
kos.insert("minimize","\xec\xb5\x9c\xec\x86\x8c\xed\x99\x94"); // 최소화
|
||||
kos.insert("low_speed","\xec\xa0\x80\xec\x86\x8d");
|
||||
kos.insert("high_speed","\xea\xb3\xa0\xec\x86\x8d \x28 \x31\x33\x30 \x4b\x6d\x2f\x68 \xec\x9d\xb4\xec\x83\x81 \x29");
|
||||
|
||||
kos.insert("flip_h","\xed\x99\x94\xeb\xa9\xb4\xec\xa2\x8c\xec\x9a\xb0\xeb\xb0\x98\xec\xa0\x84");
|
||||
kos.insert("flip_v","\xed\x99\x94\xeb\xa9\xb4\xec\x83\x81\xed\x95\x98\xeb\xb0\x98\xec\xa0\x84");
|
||||
kos.insert("swap","\xec\xb1\x84\xeb\x84\x90\xec\xa0\x84\xed\x99\x98");
|
||||
kos.insert("fullscreen","\xec\xa0\x84\xec\xb2\xb4\xed\x99\x94\xeb\xa9\xb4");
|
||||
kos.insert("graph_zoom_in","\xed\x99\x95\xeb\x8c\x80");
|
||||
kos.insert("graph_zoom_out","\xec\xb6\x95\xec\x86\x8c");
|
||||
|
||||
kos.insert("brightness","\xeb\xb0\x9d\xea\xb8\xb0\xec\xa1\xb0\xec\xa0\x95");
|
||||
kos.insert("contrast","\xeb\x8c\x80\xeb\xb9\x84\xec\xa1\xb0\xec\xa0\x95");
|
||||
kos.insert("play_speed","\xec\x9e\xac\xec\x83\x9d\xec\x86\x8d\xeb\x8f\x84");
|
||||
kos.insert("volume_mute","\xec\x9d\x8c\xec\x86\x8c\xea\xb1\xb0");
|
||||
kos.insert("volume_un_mute","\xec\x9d\x8c\xec\x86\x8c\xea\xb1\xb0 \xed\x95\xb4\xec\xa0\x9c");
|
||||
|
||||
kos.insert("play_backward","\x31\xec\xb4\x88\xed\x9b\x84\xeb\xb0\xa9\xec\x9d\xb4\xeb\x8f\x99");
|
||||
kos.insert("play_play","\xec\x9e\xac\xec\x83\x9d\xec\x8b\x9c\xec\x9e\x91");
|
||||
kos.insert("play_stop","\xec\xa0\x95\xec\xa7\x80");
|
||||
kos.insert("play_forward","\x31\xec\xb4\x88\xec\xa0\x84\xeb\xb0\xa9\xec\x9d\xb4\xeb\x8f\x99");
|
||||
kos.insert("play_file_previous","\xec\x9d\xb4\xec\xa0\x84\xed\x8c\x8c\xec\x9d\xbc\xec\x9e\xac\xec\x83\x9d");
|
||||
kos.insert("play_file_next","\xeb\x8b\xa4\xec\x9d\x8c\xed\x8c\x8c\xec\x9d\xbc\xec\x9e\xac\xec\x83\x9d");
|
||||
kos.insert("open","\xed\x8c\x8c\xec\x9d\xbc\xec\x97\xb4\xea\xb8\xb0");
|
||||
kos.insert("play_pause","\xec\x9d\xbc\xec\x8b\x9c\xec\xa0\x95\xec\xa7\x80");
|
||||
kos.insert("backup","\xed\x8c\x8c\xec\x9d\xbc\xeb\xb3\xb4\xec\xa1\xb4");
|
||||
kos.insert("viewer_sw_version","\xeb\xb7\xb0\xec\x96\xb4 \x53\x2f\x57 \xeb\xb2\x84\xec\xa0\x84 \xec\xa0\x95\xeb\xb3\xb4");
|
||||
kos.insert("hw_accel","\x48\x2f\x57 \xea\xb7\xb8\xeb\x9e\x98\xed\x94\xbd \xea\xb0\x80\xec\x86\x8d \xec\x82\xac\xec\x9a\xa9");
|
||||
#endif
|
||||
#endif // ENG
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_MH9000)
|
||||
jps.insert("select_fr",FM_WSTR(L"フロント l リア"));
|
||||
jps.insert("select_lr",FM_WSTR(L"左サイド l 右サイド"));
|
||||
jps.insert("select_front",FM_WSTR(L"フロント"));
|
||||
jps.insert("select_rear",FM_WSTR(L"リア"));
|
||||
jps.insert("select_left",FM_WSTR(L"左サイド"));
|
||||
jps.insert("select_right",FM_WSTR(L"右サイド"));
|
||||
jps.insert("select_asst",FM_WSTR(L"サブカメラ"));
|
||||
jps.insert("select_indoor",FM_WSTR(L"車内カメラ"));
|
||||
kos.insert("select_fr",FM_WSTR(L"전후방"));
|
||||
kos.insert("select_lr",FM_WSTR(L"좌우측"));
|
||||
kos.insert("select_front",FM_WSTR(L"전방"));
|
||||
kos.insert("select_rear",FM_WSTR(L"후방"));
|
||||
kos.insert("select_left",FM_WSTR(L"좌측"));
|
||||
kos.insert("select_right",FM_WSTR(L"우측"));
|
||||
kos.insert("select_asst",FM_WSTR(L"보조캠"));
|
||||
kos.insert("select_indoor",FM_WSTR(L"실내캠"));
|
||||
ens.insert("select_fr","Front|Rear");
|
||||
ens.insert("select_lr",FM_WSTR(L"Left|Right"));
|
||||
ens.insert("select_front",FM_WSTR(L"Front"));
|
||||
ens.insert("select_rear",FM_WSTR(L"Rear"));
|
||||
ens.insert("select_left",FM_WSTR(L"Left"));
|
||||
ens.insert("select_right",FM_WSTR(L"Right"));
|
||||
ens.insert("select_asst",FM_WSTR(L"Assistant"));
|
||||
ens.insert("select_indoor",FM_WSTR(L"Indoor"));
|
||||
#endif //
|
||||
|
||||
#if (DEBUG_FM_STRINGS)
|
||||
QFile logFile("C:\\home\\temp2\\fmviewer.txt");
|
||||
if (logFile.open(QFile::WriteOnly | QFile::Text))
|
||||
{
|
||||
QTextStream ts(&logFile);
|
||||
ts.setCodec("UTF-8");
|
||||
foreach (QString key, kos.keys())
|
||||
{
|
||||
ts << "\"" << key << "\",\"" << kos[key] << "\",\"" << jps[key] << "\",\"" << ens[key] << "\"\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if (MODEL_KOREAN_ONLY)
|
||||
QString FMS::txt(const char* key,RMLanguage::LANGUAGE_TYPE type) {
|
||||
Q_UNUSED(type)
|
||||
return FMS::txt(key);
|
||||
}
|
||||
#else // #if !(MODEL_KOREAN_ONLY)
|
||||
QString FMS::txt(const char* key,RMLanguage::LANGUAGE_TYPE type) {
|
||||
if(!_loaded) {
|
||||
load();
|
||||
_loaded = true;
|
||||
}
|
||||
QMap<QString,QString>* l = NULL;
|
||||
switch (type) {
|
||||
case RMLanguage::LANGUAGE_JP:
|
||||
l = &FMS::jps;
|
||||
break;
|
||||
#if (RC_LANGUAGE == 0x0412)
|
||||
case RMLanguage::LANGUAGE_KR:
|
||||
l = &FMS::kos;
|
||||
break;
|
||||
#endif // #if (RC_LANGUAGE == 0x0412)
|
||||
#if(SUB_MODEL_BV5000 || RM_MODEL == RM_MODEL_TYPE_MH9000 || RM_MODEL == RM_MODEL_TYPE_EMT_KR)
|
||||
case RMLanguage::LANGUAGE_EN:
|
||||
l = &FMS::ens;
|
||||
break;
|
||||
#endif // #if(SUB_MODEL_BV5000)
|
||||
}
|
||||
if(l->contains(key)) {
|
||||
return l->value(key);
|
||||
} else {
|
||||
qInfo() << "STN:!!!" << key << RMLanguage::instance()->language() <<__FUNCTION__;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
#endif // #if !(MODEL_KOREAN_ONLY)
|
||||
QString FMS::txt(const char* key)
|
||||
{
|
||||
if(!_loaded) {
|
||||
load();
|
||||
_loaded = true;
|
||||
}
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_NX_DRW22 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_KEIYO1 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MBJ5010 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_TBD360 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_FC_DR232W || \
|
||||
RM_MODEL == RM_MODEL_TYPE_AN6000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
//qInfo() << jps.contains(key) << key << ":" << jps[key] << __FUNCTION__;
|
||||
//qInfo() << key << QString::fromUtf8(jps[key]) << __FUNCTION__;
|
||||
#if (MODEL_KOREAN_ONLY)
|
||||
return kos[key];
|
||||
#else // MODEL_KOREAN_ONLY
|
||||
return jps[key];
|
||||
#endif // MODEL_KOREAN_ONLY
|
||||
#elif(RM_MODEL == RM_MODEL_TYPE_ADT_CAPS)
|
||||
return kos[key];//QString::fromUtf8(kos[key]);
|
||||
#elif (SUB_MODEL_BV5000 || RM_MODEL == RM_MODEL_TYPE_MH9000)
|
||||
QMap<QString,QString>* l = NULL;
|
||||
switch (RMLanguage::instance()->language()) {
|
||||
case RMLanguage::LANGUAGE_JP:
|
||||
l = &FMS::jps;
|
||||
break;
|
||||
case RMLanguage::LANGUAGE_KR:
|
||||
l = &FMS::kos;
|
||||
break;
|
||||
case RMLanguage::LANGUAGE_EN:
|
||||
l = &FMS::ens;
|
||||
break;
|
||||
}
|
||||
if(l->contains(key)) {
|
||||
return l->value(key);
|
||||
} else {
|
||||
qInfo() << "STN:!!!" << key << RMLanguage::instance()->language() <<__FUNCTION__;
|
||||
return "";
|
||||
}
|
||||
#elif (RC_LANGUAGE == 0x0412)
|
||||
if(!kos.contains(key) || kos.contains(key) == NULL) {
|
||||
qInfo() << "LANGUAGE ERROR:" << key << __FUNCTION__ ;
|
||||
return "";
|
||||
}
|
||||
return kos[key];
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
#if(SUPPORT_LANGUAGE_INSERT)
|
||||
// 1:KR 2:JP, 3:EN
|
||||
void FMS::insert_if_not_exist(int type,QString key, QString text)
|
||||
{
|
||||
QMap<QString,QString>* l = NULL;
|
||||
switch (type) {
|
||||
case 2:
|
||||
l = &FMS::jps;
|
||||
break;
|
||||
case 3:
|
||||
l = &FMS::ens;
|
||||
break;
|
||||
case 1:
|
||||
l = &FMS::kos;
|
||||
break;
|
||||
}
|
||||
|
||||
//qInfo() << type << key << text << __FUNCTION__;
|
||||
|
||||
if(l != NULL && !l->contains(key)) {
|
||||
l->insert(key,text);
|
||||
}
|
||||
|
||||
}
|
||||
#endif // #SUPPORT_LANGUAGE_INSERT
|
||||
#endif // FM_STR_TYPE2
|
||||
|
||||
|
||||
|
||||
|
||||
47
project/fm_viewer/core/fm_strings.h
Normal file
47
project/fm_viewer/core/fm_strings.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef FM_STRINGS_H
|
||||
#define FM_STRINGS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
#include "rm_include.h"
|
||||
|
||||
|
||||
class FMS : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
static bool _loaded;
|
||||
public:
|
||||
explicit FMS(QObject *parent = nullptr) : QObject(parent){}
|
||||
|
||||
#if (FM_STR_TYPE2)
|
||||
static QMap<QString,QStringList> strings;
|
||||
#else // FM_STR_TYPE2
|
||||
#if !(MODEL_KOREAN_ONLY)
|
||||
static QMap<QString,QString> jps;
|
||||
#endif
|
||||
|
||||
#if(RM_MODEL == RM_MODEL_TYPE_ADT_CAPS || RM_MODEL == RM_MODEL_TYPE_TB4000 || RM_MODEL == RM_MODEL_TYPE_BV2000 || SUB_MODEL_KEIYO_KR || RM_MODEL == RM_MODEL_TYPE_MH9000 || RM_MODEL_TYPE_EMT_KR)
|
||||
static QMap<QString,QString> kos;
|
||||
#endif
|
||||
|
||||
#if(SUB_MODEL_BV5000 || RM_MODEL == RM_MODEL_TYPE_MH9000 || RM_MODEL_TYPE_EMT_KR)
|
||||
static QMap<QString,QString> ens;
|
||||
#endif
|
||||
#endif // FM_STR_TYPE2
|
||||
|
||||
static void load();
|
||||
static QString txt(const char* key);
|
||||
static QString txt(const char* key,RMLanguage::LANGUAGE_TYPE type);
|
||||
static QString txtLine(const char* key);
|
||||
|
||||
#if(SUPPORT_LANGUAGE_INSERT)
|
||||
// 1:JP, 2:EN, 3:KR
|
||||
static void insert_if_not_exist(int type,QString key, QString text);
|
||||
#endif // SUB_MODEL_BV5000
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
#endif // FM_STRINGS_H
|
||||
678
project/fm_viewer/core/fm_video_split.cpp
Normal file
678
project/fm_viewer/core/fm_video_split.cpp
Normal file
@@ -0,0 +1,678 @@
|
||||
#include "fm_video_split.h"
|
||||
#if (SUPPORT_AVI_SPLIT)
|
||||
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
#include "../ui/QProgressIndicator.h"
|
||||
|
||||
#if !(USE_FFMPEG_TO_SPLIT)
|
||||
//#include "../data/rm_format_avi.h"
|
||||
//#include "../data/fileio.h"
|
||||
#else
|
||||
extern "C" {
|
||||
//#define __STDC_FORMAT_MACROS
|
||||
//#include <libavutil/timestamp.h>
|
||||
#include <libavformat/avformat.h>
|
||||
}
|
||||
#endif // #if (USE_FFMPEG_TO_SPLIT)
|
||||
|
||||
FMProgressDialog* FMVideoSplit::progress = NULL;
|
||||
|
||||
FMVideoSplit::FMVideoSplit(QString path)
|
||||
{
|
||||
_path = path;
|
||||
idx = NULL;
|
||||
}
|
||||
|
||||
#if !(USE_FFMPEG_TO_SPLIT)
|
||||
|
||||
#define A4_CHAR_TO_NUM(cs) ((((int32_t)cs[3])<<24)|(((int32_t)cs[2])<<16)|(((int32_t)cs[1])<<8)|(((int32_t)cs[0])))
|
||||
void FMVideoSplit::run()
|
||||
{
|
||||
QString document = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
|
||||
bFirstVideo = true;
|
||||
QString dest = QDir::cleanPath(document + QDir::separator() + QFileInfo(_path).baseName() + "_F" + ".AVI");
|
||||
if(QFile(dest).exists()) {
|
||||
QFile(dest).remove();
|
||||
}
|
||||
|
||||
convert(_path,dest);
|
||||
|
||||
bFirstVideo = false;
|
||||
dest = QDir::cleanPath(document + QDir::separator() + QFileInfo(_path).baseName() + "_R" + ".AVI");
|
||||
|
||||
if(QFile(dest).exists()) {
|
||||
QFile(dest).remove();
|
||||
}
|
||||
convert(_path,dest);
|
||||
|
||||
emit done();
|
||||
|
||||
}
|
||||
void FMVideoSplit::convert(QString path,QString dest)
|
||||
{
|
||||
FILE *file = _wfopen(path.toStdWString().c_str(),L"rb");
|
||||
memset(&root,0,sizeof(_RIFF_TREE));
|
||||
fread(&root.tag,4,1,file);
|
||||
fread(&root.size,4,1,file);
|
||||
fread(&root.type,4,1,file);
|
||||
root.offset = ftell(file);
|
||||
|
||||
//debugPrint(&root);
|
||||
|
||||
bFirstVideoStreamFound = false;
|
||||
readTree(file,&root,0);
|
||||
|
||||
root.offset_w = root.offset;
|
||||
//debugTree(&root);
|
||||
makeOffset(&root);
|
||||
makeIndex(&root);
|
||||
root.size_w += 4;
|
||||
//debugTree(&root);
|
||||
|
||||
//QString dest = "C:\\home\\temp\\copy2.avi";
|
||||
// QByteArray ba = str1.toLocal8Bit();
|
||||
//const char *c_str2 = ba.data();
|
||||
//FILE *wf = fopen(dest.toLocal8Bit().data(),"wb");
|
||||
FILE *wf = _wfopen(dest.toStdWString().c_str(),L"wb");
|
||||
saveTree(&root,file,wf);
|
||||
fclose(wf);
|
||||
fclose(file);
|
||||
|
||||
//qInfo() << "---------------------------------------------------";
|
||||
//
|
||||
free(idx);
|
||||
idx = NULL;
|
||||
freeTree(&root);
|
||||
|
||||
|
||||
QThread::msleep(100);
|
||||
}
|
||||
void FMVideoSplit::debugPrint(RIFF_TREE* item)
|
||||
{
|
||||
QString tab = "";
|
||||
for(int i=0;i<item->depth;i++) {
|
||||
tab += " ";
|
||||
}
|
||||
// RIFF_TREE* p = item->depth;
|
||||
// while(p != NULL) {
|
||||
// p = p->parent;
|
||||
// }
|
||||
|
||||
if(item->tag == A4_CHAR_TO_NUM("LIST") || item->tag == A4_CHAR_TO_NUM("RIFF")) {
|
||||
qInfo() << tab + QString().sprintf("OFFSET: %d",item->offset) +
|
||||
QString().sprintf(" W_OFFSET: %d COUNT:%d",item->offset_w,item->count) +
|
||||
QString().sprintf(" TAG:[%c%c%c%c]",(char)((item->tag >> 0) & 0xFF),(char)((item->tag >> 8) & 0xFF),(char)((item->tag >> 16) & 0xFF),(char)((item->tag >> 24) & 0xFF)) +
|
||||
QString().sprintf(" TYPE:[%c%c%c%c]",(char)(item->type >> 0 & 0xFF),(char)(item->type >> 8 & 0xFF),(char)(item->type >> 16 & 0xFF),(char)((item->type >> 24) & 0xFF)) +
|
||||
QString().sprintf(" SIZE: %d",item->size) + QString().sprintf(" SIZE_W: %d REMOVE:%d",item->size_w, item->remove);
|
||||
}
|
||||
else {
|
||||
qInfo() << tab + QString().sprintf("OFFSET: %d",item->offset) +
|
||||
QString().sprintf(" W_OFFSET: %d",item->offset_w) +
|
||||
QString().sprintf(" TAG:[%c%c%c%c]",(char)((item->tag >> 0) & 0xFF),(char)((item->tag >> 8) & 0xFF),(char)((item->tag >> 16) & 0xFF),(char)((item->tag >> 24) & 0xFF)) +
|
||||
QString().sprintf(" SIZE: %d",item->size) + QString().sprintf(" SIZE_W: %d REMOVE:%d",item->size_w, item->remove);
|
||||
}
|
||||
|
||||
}
|
||||
void FMVideoSplit::debugTree(RIFF_TREE* p)
|
||||
{
|
||||
//p->parent = NULL;
|
||||
debugPrint(p);
|
||||
int32_t sz = 0;
|
||||
for(int i=0;i<p->count;i++) {
|
||||
if(p->type == A4_CHAR_TO_NUM("movi")) {
|
||||
|
||||
// sz += 8;
|
||||
// sz = sz + p->childs[i].size + (p->childs[i].size % 2);
|
||||
// qInfo() << "+" << sz;
|
||||
}
|
||||
else {
|
||||
//p->childs[i].parent = NULL;
|
||||
debugTree(&p->childs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(p->type == A4_CHAR_TO_NUM("movi")) {
|
||||
qInfo() << "MOVI SIZE:" << sz;
|
||||
}
|
||||
}
|
||||
void FMVideoSplit::freeTree(RIFF_TREE* p)
|
||||
{
|
||||
if(p->childs != NULL) {
|
||||
// CHILD 가 존재할 경우 처리
|
||||
for(int i=0;i<p->count;i++) {
|
||||
if(p->childs[i].childs != NULL) {
|
||||
freeTree(&p->childs[i]);
|
||||
}
|
||||
}
|
||||
// SUB 가 없을 경우
|
||||
//debugPrint(parent);
|
||||
free(p->childs);
|
||||
}
|
||||
}
|
||||
void FMVideoSplit::saveTree(RIFF_TREE* p,FILE* read,FILE* write)
|
||||
{
|
||||
if(p->remove != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
//debugPrint(p);
|
||||
int roffset_w = p->offset_w - 8;
|
||||
if(p->count > 0) {
|
||||
roffset_w -= 4; // TYPE
|
||||
}
|
||||
fseek(write,roffset_w,SEEK_SET);
|
||||
|
||||
|
||||
|
||||
fwrite(&p->tag,4,1,write);
|
||||
fwrite(&p->size_w,4,1,write);
|
||||
|
||||
|
||||
if(p->count > 0) {
|
||||
if(p->count > 0) {
|
||||
fwrite(&p->type,4,1,write);
|
||||
}
|
||||
for(int i=0;i<p->count;i++) {
|
||||
saveTree(&p->childs[i],read,write);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if(p->tag == A4_CHAR_TO_NUM("idx1")) {
|
||||
fwrite(idx,p->size_w,1,write);
|
||||
}
|
||||
else {
|
||||
// 그냥 이동하면 데이터 영역임
|
||||
fseek(read,p->offset,SEEK_SET);
|
||||
void* buffer = malloc(p->size);
|
||||
fread(buffer,p->size_w,1,read);
|
||||
|
||||
if(p->tag == A4_CHAR_TO_NUM("avih")) {
|
||||
AVIHeader* h = (AVIHeader*)buffer;
|
||||
h->NumberOfStreams = 3;
|
||||
//qInfo() << "NumberOfStreams:" << h->NumberOfStreams << "h->DataLength:" << h->DataLength ;
|
||||
}
|
||||
|
||||
fwrite(buffer,p->size_w,1,write);
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
// OFFSET 우선 처리하고 index 처리
|
||||
void FMVideoSplit::makeIndex(RIFF_TREE* p)
|
||||
{
|
||||
RIFF_TREE* movi = NULL;
|
||||
for(int i=0;i<p->count;i++) {
|
||||
if(p->childs[i].type == A4_CHAR_TO_NUM("movi")) {
|
||||
movi = &p->childs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
//qInfo() << "MOV:" << movi->count << movi->count * 16;
|
||||
|
||||
idx = (int32_t*)malloc(movi->count * 16);
|
||||
int realCount = 0;
|
||||
for(int i=0;i<movi->count;i++) {
|
||||
RIFF_TREE* t = &movi->childs[i];
|
||||
|
||||
if(t->tag == A4_CHAR_TO_NUM("01dc")) {
|
||||
t->tag = A4_CHAR_TO_NUM("00dc");
|
||||
}
|
||||
else if (t->tag == A4_CHAR_TO_NUM("02wb")) {
|
||||
t->tag = A4_CHAR_TO_NUM("01wb");
|
||||
}
|
||||
else if (t->tag == A4_CHAR_TO_NUM("03tx")) {
|
||||
t->tag = A4_CHAR_TO_NUM("02tx");
|
||||
}
|
||||
int ri = realCount * 4;
|
||||
idx[ri + 0] = t->tag;
|
||||
idx[ri + 1] = 16;
|
||||
idx[ri + 2] = t->offset_w - 8;
|
||||
idx[ri + 3] = t->size;
|
||||
|
||||
if(t->remove != 1) {
|
||||
realCount++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RIFF_TREE* idx1 = NULL;
|
||||
for(int i=0;i<p->count;i++) {
|
||||
if(p->childs[i].tag == A4_CHAR_TO_NUM("idx1")) {
|
||||
idx1 = &p->childs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
idx1->size_w = realCount * 16;
|
||||
int diff = (idx1->size - (realCount * 16));
|
||||
p->size_w -= diff;
|
||||
//qInfo() << "IDX:" << idx1->size << idx1->size_w << "DIFF:" << diff;
|
||||
|
||||
}
|
||||
|
||||
// TREE 탐색하며 OFFSET 생성, SIZE 는 유지
|
||||
void FMVideoSplit::makeOffset(RIFF_TREE* p)
|
||||
{
|
||||
// if(p->remove != 0) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
int offset = p->offset_w; // SIZE + TAG 는 항상 존재
|
||||
|
||||
for(int i=0;i<p->count;i++) {
|
||||
|
||||
if(p->childs[i].remove == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int add = 8;
|
||||
if(p->childs[i].tag == A4_CHAR_TO_NUM("LIST")) {
|
||||
add += 4;
|
||||
}
|
||||
|
||||
// 쓰기 옵셋
|
||||
p->childs[i].offset_w = offset + add;
|
||||
|
||||
// if(p->childs[i].offset_w != p->childs[i].offset) {
|
||||
// qInfo() << offset << "--------------------------------------------";
|
||||
// debugPrint(&p->childs[i]);
|
||||
// qInfo() << add << "--------------------------------------------";
|
||||
// }
|
||||
|
||||
|
||||
if(p->childs[i].count > 0) {
|
||||
p->childs[i].size_w = 4; //???
|
||||
makeOffset(&p->childs[i]);
|
||||
}
|
||||
else if (p->childs[i].remove == 0){
|
||||
p->childs[i].size_w = p->childs[i].size;
|
||||
}
|
||||
|
||||
if(p->childs[i].remove == 0) {
|
||||
|
||||
|
||||
p->size_w = p->size_w + p->childs[i].size_w + (p->childs[i].size_w % 2);
|
||||
p->size_w += 8;
|
||||
|
||||
// if(p->type == A4_CHAR_TO_NUM("movi")) {
|
||||
// debugPrint(&p->childs[i]);
|
||||
// qInfo() << i << p->size_w;
|
||||
// }
|
||||
|
||||
// if(p->childs[i].tag == A4_CHAR_TO_NUM("LIST")) {
|
||||
// p->size_w += 4;
|
||||
// }
|
||||
|
||||
offset += 8; // TAG+SIZE
|
||||
offset += p->childs[i].size_w;
|
||||
|
||||
// PAD 2
|
||||
if(offset % 2 == 1) {
|
||||
offset += 1;
|
||||
}
|
||||
}
|
||||
//parent->childs[i].offset = offset;
|
||||
}
|
||||
|
||||
}
|
||||
void FMVideoSplit::resizeTree(RIFF_TREE* item,int count)
|
||||
{
|
||||
// qInfo() << "REALLOC-----------" << count;
|
||||
// debugPrint(item);
|
||||
// qInfo() << "------------------";
|
||||
|
||||
RIFF_TREE* temp = (RIFF_TREE*)malloc(sizeof(_RIFF_TREE) * count);
|
||||
memset(temp,0,sizeof(_RIFF_TREE) * count);
|
||||
|
||||
memcpy(temp,item->childs,sizeof(_RIFF_TREE) * item->count);
|
||||
free(item->childs);
|
||||
item->childs = temp;
|
||||
}
|
||||
void FMVideoSplit::readTree(FILE* file, RIFF_TREE* p, int32_t depth)
|
||||
{
|
||||
const int buffer_count = 100;
|
||||
int current_buffer_count = 100;
|
||||
// if(p->type != A4_CHAR_TO_NUM("movi")) {
|
||||
// qInfo() << "CHECK:" << p->offset + p->size << "TELL:" << ftell(file);
|
||||
// }
|
||||
|
||||
while (ftell(file)<(p->offset + p->size - 4))
|
||||
{
|
||||
if(p->childs == NULL) {
|
||||
p->childs = (RIFF_TREE*)malloc(sizeof(_RIFF_TREE) * buffer_count);
|
||||
memset(p->childs,0,sizeof(_RIFF_TREE) * buffer_count);
|
||||
current_buffer_count = buffer_count;
|
||||
}
|
||||
|
||||
if(p->count + 1 >= current_buffer_count) {
|
||||
current_buffer_count += buffer_count;
|
||||
// 기존 레코드 복사
|
||||
resizeTree(p,current_buffer_count);
|
||||
}
|
||||
|
||||
RIFF_TREE* item = &p->childs[p->count];
|
||||
fread(&item->tag,4,1,file);
|
||||
fread(&item->size,4,1,file);
|
||||
item->offset = ftell(file); // SIZE 읽은 후 OFFSET 지정
|
||||
item->depth = depth + 1;
|
||||
//item->parent = p;
|
||||
|
||||
// 리스트만 처리
|
||||
if(item->tag == A4_CHAR_TO_NUM("LIST")) {
|
||||
|
||||
item->offset += 4; // LIST 는 TYPE 이 존재하여 추가
|
||||
fread(&item->type,4,1,file);
|
||||
//debugPrint(item);
|
||||
readTree(file,item,item->depth + 1);
|
||||
|
||||
// if(item->type == A4_CHAR_TO_NUM("movi")) {
|
||||
// item->remove = 1;
|
||||
// }
|
||||
}
|
||||
else {
|
||||
//if(p->type != A4_CHAR_TO_NUM("movi")) {
|
||||
//debugPrint(item);
|
||||
//}
|
||||
|
||||
if(item->tag == A4_CHAR_TO_NUM("strh")) {
|
||||
void* v = malloc(item->size);
|
||||
fread(v,item->size,1,file);
|
||||
_STRHeader* h = (_STRHeader*)v;
|
||||
if(h->DataType[0] == 'v' && h->DataType[1] == 'i' && h->DataType[2] == 'd' && h->DataType[3] == 's')
|
||||
{
|
||||
if(bFirstVideoStreamFound) {
|
||||
if(bFirstVideo) {
|
||||
p->remove = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!bFirstVideo) {
|
||||
p->remove = 1;
|
||||
}
|
||||
}
|
||||
bFirstVideoStreamFound = true;
|
||||
}
|
||||
//qInfo() << "STRH" << h->DataType;
|
||||
}
|
||||
|
||||
// if(item->tag == A4_CHAR_TO_NUM("idx1")) {
|
||||
// item->remove = 1;
|
||||
// }
|
||||
|
||||
if(item->tag == A4_CHAR_TO_NUM("01dc") && bFirstVideo) {
|
||||
item->remove = 1;
|
||||
}
|
||||
else if(item->tag == A4_CHAR_TO_NUM("00dc") && !bFirstVideo) {
|
||||
item->remove = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 2 BIT PAD
|
||||
int32_t seek = item->offset + item->size;
|
||||
if(seek % 2 == 1) {
|
||||
seek += 1;
|
||||
}
|
||||
fseek(file,seek,SEEK_SET);
|
||||
}
|
||||
p->count += 1;
|
||||
}
|
||||
resizeTree(p,p->count);
|
||||
}
|
||||
#else // (USE_FFMPEG_TO_SPLIT)
|
||||
// MP4 의 경우 PCM 오디오 인코딩이 안됨
|
||||
// MOV 의 경우 PCM 이 되나 미디어 플레이어에서 재생안됨
|
||||
// https://cpp.hotexamples.com/examples/-/-/avformat_write_header/cpp-avformat_write_header-function-examples.html
|
||||
bool FMVideoSplit::start(QString path)
|
||||
{
|
||||
//av_register_all();
|
||||
|
||||
QString outFile = "C:\\home\\temp\\test.mov";
|
||||
char buffer[1024] = {0,};
|
||||
qInfo() << path << __FUNCTION__;
|
||||
const AVOutputFormat *ofmt = NULL;
|
||||
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
|
||||
AVPacket *pkt = NULL;
|
||||
//const char *in_filename, *out_filename;
|
||||
int ret, i;
|
||||
int stream_index = 0;
|
||||
int *stream_mapping = NULL;
|
||||
int stream_mapping_size = 0;
|
||||
|
||||
pkt = av_packet_alloc();
|
||||
if (!pkt) {
|
||||
qInfo() << "Could not allocate AVPacket";
|
||||
// fprintf(stderr, "Could not allocate AVPacket\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// d->format_ctx->probesize = 8000000;
|
||||
// d->format_ctx->max_analyze_duration = 8000000;
|
||||
// ret = avformat_find_stream_info(d->format_ctx, NULL);
|
||||
|
||||
if ((ret = avformat_open_input(&ifmt_ctx, path.toUtf8().constData(), 0, 0)) < 0) {
|
||||
qInfo() << "Could not open input file " << path;
|
||||
// fprintf(stderr, "Could not open input file '%s'", .toUtf8().constData());
|
||||
goto end;
|
||||
}
|
||||
// ifmt_ctx->probesize = 8000000;
|
||||
// ifmt_ctx->max_analyze_duration = 8000000;
|
||||
|
||||
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
|
||||
qInfo() << "Failed to retrieve input stream information";
|
||||
//fprintf(stderr, "Failed to retrieve input stream information");
|
||||
goto end;
|
||||
}
|
||||
|
||||
av_dump_format(ifmt_ctx, 0, path.toUtf8().constData(), 0);
|
||||
|
||||
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, outFile.toUtf8().constData());
|
||||
if (!ofmt_ctx) {
|
||||
qInfo() << "Could not create output context";
|
||||
//fprintf(stderr, "Could not create output context\n");
|
||||
ret = AVERROR_UNKNOWN;
|
||||
goto end;
|
||||
}
|
||||
|
||||
stream_mapping_size = ifmt_ctx->nb_streams;
|
||||
stream_mapping = (int*)av_calloc(stream_mapping_size, sizeof(*stream_mapping));
|
||||
if (!stream_mapping) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ofmt = ofmt_ctx->oformat;
|
||||
|
||||
bool bVideo = false;
|
||||
|
||||
int subtitle_stream = -1;
|
||||
|
||||
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
|
||||
AVStream *out_stream;
|
||||
AVStream *in_stream = ifmt_ctx->streams[i];
|
||||
AVCodecParameters *in_codecpar = in_stream->codecpar;
|
||||
|
||||
if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
|
||||
in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
|
||||
in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
|
||||
stream_mapping[i] = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// bVideo
|
||||
if(in_codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !bVideo) {
|
||||
|
||||
bVideo = true;
|
||||
//qInfo() << "TEST" << __FUNCTION__;
|
||||
stream_mapping[i] = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(in_codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
|
||||
//qInfo() << "TEST" << __FUNCTION__;
|
||||
//stream_mapping[i] = -1;
|
||||
//continue;
|
||||
}
|
||||
|
||||
if(in_codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
|
||||
|
||||
subtitle_stream = i;
|
||||
in_codecpar->codec_id = AV_CODEC_ID_MOV_TEXT;//AV_CODEC_ID_TEXT;
|
||||
//in_codecpar->codec_id = AV_CODEC_ID_TEXT;
|
||||
//qInfo() << "TEST" << __FUNCTION__;
|
||||
//stream_mapping[i] = -1;
|
||||
//continue;
|
||||
}
|
||||
|
||||
|
||||
stream_mapping[i] = stream_index++;
|
||||
|
||||
out_stream = avformat_new_stream(ofmt_ctx, NULL);
|
||||
if (!out_stream) {
|
||||
qInfo() << "Failed allocating output stream";
|
||||
//fprintf(stderr, "Failed allocating output stream\n");
|
||||
ret = AVERROR_UNKNOWN;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
|
||||
if (ret < 0) {
|
||||
qInfo() << "Failed to copy codec parameters";
|
||||
//fprintf(stderr, "Failed to copy codec parameters\n");
|
||||
goto end;
|
||||
}
|
||||
out_stream->codecpar->codec_tag = 0;
|
||||
}
|
||||
// AUDIO STREAM
|
||||
//open_audio(ofmt_ctx, audio_codec, &audio_st, opt);
|
||||
|
||||
av_dump_format(ofmt_ctx, 0, outFile.toUtf8().constData(), 1);
|
||||
|
||||
if (!(ofmt->flags & AVFMT_NOFILE)) {
|
||||
ret = avio_open(&ofmt_ctx->pb, outFile.toUtf8().constData(), AVIO_FLAG_WRITE);
|
||||
if (ret < 0) {
|
||||
qInfo() << "Could not open output file " << outFile;
|
||||
//fprintf(stderr, "Could not open output file '%s'", outFile.toUtf8().constData());
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/31846650/avformat-write-header-return-error-code-when-trying-to-write-pcmu-encoded-frame
|
||||
ret = avformat_write_header(ofmt_ctx, NULL);
|
||||
if (ret < 0) {
|
||||
memset(buffer,0,1024);
|
||||
av_strerror(ret,buffer,1024);
|
||||
qInfo() << "Error occurred when opening output file" << buffer;
|
||||
// fprintf(stderr, "Error occurred when opening output file\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
AVStream *in_stream, *out_stream;
|
||||
|
||||
ret = av_read_frame(ifmt_ctx, pkt);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
in_stream = ifmt_ctx->streams[pkt->stream_index];
|
||||
if (pkt->stream_index >= stream_mapping_size ||
|
||||
stream_mapping[pkt->stream_index] < 0) {
|
||||
av_packet_unref(pkt);
|
||||
continue;
|
||||
}
|
||||
|
||||
// SUB TITLE 일 경우
|
||||
if(in_stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
|
||||
qInfo() << (const char*)pkt->data << __FUNCTION__;
|
||||
}
|
||||
|
||||
pkt->stream_index = stream_mapping[pkt->stream_index];
|
||||
out_stream = ofmt_ctx->streams[pkt->stream_index];
|
||||
//log_packet(ifmt_ctx, pkt, "in");
|
||||
|
||||
/* copy packet */
|
||||
av_packet_rescale_ts(pkt, in_stream->time_base, out_stream->time_base);
|
||||
pkt->pos = -1;
|
||||
//log_packet(ofmt_ctx, pkt, "out");
|
||||
|
||||
ret = av_interleaved_write_frame(ofmt_ctx, pkt);
|
||||
/* pkt is now blank (av_interleaved_write_frame() takes ownership of
|
||||
* its contents and resets pkt), so that no unreferencing is necessary.
|
||||
* This would be different if one used av_write_frame(). */
|
||||
if (ret < 0) {
|
||||
qInfo() << "Error muxing packet";
|
||||
//fprintf(stderr, "Error muxing packet\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
av_write_trailer(ofmt_ctx);
|
||||
end:
|
||||
av_packet_free(&pkt);
|
||||
|
||||
avformat_close_input(&ifmt_ctx);
|
||||
|
||||
/* close output */
|
||||
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
|
||||
avio_closep(&ofmt_ctx->pb);
|
||||
avformat_free_context(ofmt_ctx);
|
||||
|
||||
av_freep(&stream_mapping);
|
||||
|
||||
if (ret < 0 && ret != AVERROR_EOF) {
|
||||
//fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
|
||||
return 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // USE_FFMPEG_TO_SPLIT
|
||||
|
||||
|
||||
|
||||
FMProgressDialog::FMProgressDialog(QWidget *parent, QString title) : QDialog(parent)
|
||||
{
|
||||
setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
|
||||
setModal(true);
|
||||
setStyleSheet("FMProgressDialog{ background-color: #3a3a3a; border: 3px solid #666666;}"); //
|
||||
setFixedSize(120,120);
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setMargin(0);
|
||||
layout->setSpacing(20);
|
||||
layout->setAlignment(Qt::AlignCenter);
|
||||
QLabel* top = new QLabel(this);
|
||||
top->setAlignment(Qt::AlignCenter);
|
||||
top->setText(title); // QString::fromWCharArray(L"ファイル分割中")
|
||||
top->setStyleSheet("font-family: MS PGothic; font-style: bold;font-size:14px; color : #6699FF");
|
||||
layout->addWidget(top);
|
||||
|
||||
|
||||
indicator = new QProgressIndicator(this);
|
||||
indicator->setFixedSize(120,50);
|
||||
indicator->setColor(QColor(0x6699FF));
|
||||
indicator->show();
|
||||
indicator->startAnimation();
|
||||
layout->addWidget(indicator);
|
||||
|
||||
// QLabel* bottom = new QLabel(this);
|
||||
// bottom->setAlignment(Qt::AlignCenter);
|
||||
// bottom->setText(QString::fromWCharArray(L"8〜30秒かかります"));
|
||||
// bottom->setStyleSheet("font-family: MS PGothic; font-style: black;font-size:18px; color : #FFFFFF");
|
||||
// layout->addWidget(bottom);
|
||||
|
||||
}
|
||||
|
||||
void FMProgressDialog::paintEvent(QPaintEvent *pe)
|
||||
{
|
||||
Q_UNUSED(pe);
|
||||
|
||||
QStyleOption o;
|
||||
o.initFrom(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
|
||||
}
|
||||
|
||||
|
||||
#endif // #if (SUPPORT_AVI_SPLIT)
|
||||
86
project/fm_viewer/core/fm_video_split.h
Normal file
86
project/fm_viewer/core/fm_video_split.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef FM_VIDEO_SPLIT_H
|
||||
#define FM_VIDEO_SPLIT_H
|
||||
#if (SUPPORT_AVI_SPLIT)
|
||||
|
||||
#include <QObject>
|
||||
#include <QtCore>
|
||||
#include <QDialog>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// MP4 의 경우 PCM 오디오 인코딩이 안됨
|
||||
// MOV 의 경우 PCM 이 되나 미디어 플레이어에서 재생안됨
|
||||
// AVI RIFF 처리로 분리 해야함..
|
||||
// https://cpp.hotexamples.com/examples/-/-/avformat_write_header/cpp-avformat_write_header-function-examples.html
|
||||
#define USE_FFMPEG_TO_SPLIT 0
|
||||
|
||||
#if !(USE_FFMPEG_TO_SPLIT)
|
||||
#include "../data/rm_format_avi.h"
|
||||
#endif // USE_FFMPEG_TO_SPLIT
|
||||
|
||||
|
||||
class QProgressIndicator;
|
||||
class FMProgressDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FMProgressDialog(QWidget *parent, QString title);
|
||||
QProgressIndicator* indicator;
|
||||
private:
|
||||
void paintEvent(QPaintEvent *pe) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct _RIFF_TREE
|
||||
{
|
||||
int32_t tag;
|
||||
int32_t type;
|
||||
int32_t offset;
|
||||
int32_t offset_w;
|
||||
int32_t size;
|
||||
int32_t size_w;
|
||||
int32_t depth;
|
||||
int32_t remove; // 제거
|
||||
//_RIFF_TREE* parent; // REALLOCATE 로 링크가 깨짐 readTree 내부에서만 사용
|
||||
int32_t count;
|
||||
_RIFF_TREE* childs;
|
||||
} RIFF_TREE;
|
||||
|
||||
class FMVideoSplit : public QObject, public QRunnable
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FMVideoSplit(QString path);
|
||||
//bool start(QString path);
|
||||
virtual void run();
|
||||
|
||||
static FMProgressDialog* progress;
|
||||
|
||||
private:
|
||||
|
||||
#if !(USE_FFMPEG_TO_SPLIT)
|
||||
|
||||
QString _path;
|
||||
|
||||
int32_t *idx;
|
||||
|
||||
bool bFirstVideo;
|
||||
bool bFirstVideoStreamFound;
|
||||
RIFF_TREE root;
|
||||
void debugPrint(RIFF_TREE* item);
|
||||
void debugTree(RIFF_TREE* p);
|
||||
void freeTree(RIFF_TREE* p);
|
||||
void makeOffset(RIFF_TREE* p);
|
||||
void makeIndex(RIFF_TREE* p);
|
||||
void saveTree(RIFF_TREE* p,FILE* read, FILE* write);
|
||||
void resizeTree(RIFF_TREE* item,int count);
|
||||
void readTree(FILE* file, RIFF_TREE* p,int32_t depth);
|
||||
void convert(QString path,QString dest);
|
||||
#endif
|
||||
signals:
|
||||
void done();
|
||||
};
|
||||
#endif // (SUPPORT_AVI_SPLIT)
|
||||
#endif // FM_VIDEO_SPLIT_H
|
||||
260
project/fm_viewer/core/rm_excel_report.cpp
Normal file
260
project/fm_viewer/core/rm_excel_report.cpp
Normal file
@@ -0,0 +1,260 @@
|
||||
#include "rm_excel_report.h"
|
||||
#include "../rm_app.h"
|
||||
#include "../rm_include.h"
|
||||
#include "../fm_dimensions.h"
|
||||
#include "../ui/rm_dialog_map.h"
|
||||
#include "../ui/rm_widget_map.h"
|
||||
#include "../core/rm_math.h"
|
||||
#include <QDir>
|
||||
#include <QPainter>
|
||||
|
||||
// Screen Capture
|
||||
#include <QPixmap>
|
||||
#include <QScreen>
|
||||
#include <QGuiApplication>
|
||||
#include <QMainWindow>
|
||||
#include <QDialog>
|
||||
#include <QDate>
|
||||
#include <QDateTime>
|
||||
|
||||
#if (USE_JP_ADDRESS)
|
||||
#include "../data/fm_address.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
float QAspectScaleFit(QSize sourceSize, QRect destRect)
|
||||
{
|
||||
QSize destSize = destRect.size();
|
||||
float scaleW = (float)destSize.width() / (float)sourceSize.width();
|
||||
float scaleH = (float)destSize.height() / (float)sourceSize.height();
|
||||
return MIN(scaleW, scaleH);
|
||||
}
|
||||
|
||||
|
||||
// Fit
|
||||
QRect QRectAspectFitRect(QSize sourceSize, QRect destRect)
|
||||
{
|
||||
QSize destSize = destRect.size();
|
||||
float destScale = QAspectScaleFit(sourceSize, destRect);
|
||||
|
||||
float newWidth = (float)sourceSize.width() * destScale;
|
||||
float newHeight = (float)sourceSize.height() * destScale;
|
||||
|
||||
float dWidth = (((float)destSize.width() - newWidth) / 2.0f);
|
||||
float dHeight = (((float)destSize.height() - newHeight) / 2.0f);
|
||||
|
||||
QRect rect = QRect(dWidth + destRect.left(), dHeight + destRect.top(), newWidth, newHeight);
|
||||
return rect;
|
||||
}
|
||||
*/
|
||||
|
||||
RMExcelReport::RMExcelReport(QObject *parent) : QAxObject("Excel.Application",parent)
|
||||
{
|
||||
_workbooks = NULL;
|
||||
_workbook = NULL;
|
||||
_sheets = NULL;
|
||||
_sheet = NULL;
|
||||
_shapes = NULL;
|
||||
_picture = NULL;
|
||||
}
|
||||
|
||||
void RMExcelReport::clearAll()
|
||||
{
|
||||
// 순서대로 제거해야함!!
|
||||
if(_picture != NULL) {
|
||||
delete _picture;
|
||||
_picture = NULL;
|
||||
}
|
||||
if(_shapes != NULL) {
|
||||
delete _shapes;
|
||||
_shapes = NULL;
|
||||
}
|
||||
if(_sheet != NULL) {
|
||||
delete _sheet;
|
||||
_sheet = NULL;
|
||||
}
|
||||
if(_sheets != NULL) {
|
||||
delete _sheets;
|
||||
_sheets = NULL;
|
||||
}
|
||||
if(_workbook != NULL) {
|
||||
delete _workbook;
|
||||
_workbook = NULL;
|
||||
}
|
||||
if(_workbooks != NULL) {
|
||||
delete _workbooks;
|
||||
_workbooks = NULL;
|
||||
}
|
||||
}
|
||||
#if (USE_JP_ADDRESS)
|
||||
bool RMExcelReport::prepare(QString& path,QDateTime* pDateTime, double lon, double lat)
|
||||
#else
|
||||
bool RMExcelReport::prepare(QString& path,QDateTime* pDateTime)
|
||||
#endif
|
||||
{
|
||||
#if (RM_MODEL != RM_MODEL_TYPE_XLDR_88)
|
||||
Q_UNUSED(pDateTime)
|
||||
#endif // !RM_MODEL_TYPE_XLDR_88
|
||||
QDateTime date = QDateTime::currentDateTime();
|
||||
|
||||
|
||||
_workbooks = querySubObject("Workbooks");
|
||||
if(_workbooks == NULL)
|
||||
{
|
||||
clearAll();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 저장 완료
|
||||
QString tempReportPath = QDir::cleanPath(RMApp::appPath(RMApp::CAPTURE) + "/_report" + date.toString("yyyy_MMdd_HHmmss") + ".xls");
|
||||
QFile::copy(":/report/report.xls",tempReportPath);
|
||||
QFile::setPermissions(tempReportPath,QFile::permissions(tempReportPath) | QFileDevice::WriteOther);
|
||||
// qInfo() << tempReportPath;
|
||||
|
||||
// QDir::toNativeSeparators(last);
|
||||
|
||||
|
||||
|
||||
QString srcPath = QDir::toNativeSeparators(tempReportPath);
|
||||
|
||||
|
||||
|
||||
_workbook = _workbooks->querySubObject( "Open(const QString&)", srcPath );
|
||||
if(_workbook == NULL) {
|
||||
clearAll();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 경고 표시 방지
|
||||
_workbook->setProperty("DisplayAlerts", false);
|
||||
_sheets = _workbook->querySubObject( "Worksheets" );
|
||||
if(_sheets == NULL)
|
||||
{
|
||||
clearAll();
|
||||
return false;
|
||||
}
|
||||
|
||||
// sheet 가져옴
|
||||
_sheet = _sheets->querySubObject( "Item( int )", 1 );
|
||||
if(_sheet == NULL)
|
||||
{
|
||||
clearAll();
|
||||
return false;
|
||||
}
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
|
||||
//qInfo() << time << __FUNCTION__;
|
||||
QAxObject * range;
|
||||
|
||||
// 보고서 작성일을 기준으로 생성
|
||||
QDateTime current = QDateTime::currentDateTime();
|
||||
|
||||
range = _sheet->querySubObject("Range(AQ2)");
|
||||
range->setProperty("Value",current.toString("yyyy"));
|
||||
|
||||
range = _sheet->querySubObject("Range(AU2)");
|
||||
range->setProperty("Value",current.toString("MM"));
|
||||
|
||||
range = _sheet->querySubObject("Range(AX2)");
|
||||
range->setProperty("Value",current.toString("dd"));
|
||||
|
||||
// 사고 발생일은 데이터 시간
|
||||
range = _sheet->querySubObject("Range(H12)");
|
||||
range->setProperty("Value",pDateTime->toString("yyyy-MM-dd"));
|
||||
|
||||
QString pam = pDateTime->time().hour() > 12 ? "PM" : "AM";
|
||||
|
||||
range = _sheet->querySubObject("Range(W12)");
|
||||
range->setProperty("Value",pam + " " + pDateTime->toString("HH") + QString::fromUtf8("\xe6\x99\x82") + pDateTime->toString("mm"));
|
||||
|
||||
#if (USE_JP_ADDRESS)
|
||||
|
||||
if(IS_VALID_LOCATION(lon,lat))
|
||||
{
|
||||
// 발생장소
|
||||
if(FMAddress::instance()->open()) {
|
||||
QStringList res;
|
||||
if(FMAddress::instance()->search(lon,lat,res)) {
|
||||
|
||||
range = _sheet->querySubObject("Range(H14)");
|
||||
QString address = (res.at(0) + " " + res.at(1) + " " + res.at(2) + " " + res.at(3) + "-" + res.at(4));
|
||||
range->setProperty("Value",address);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // USE_JP_ADDRESS
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
QScreen *screen = QGuiApplication::primaryScreen();
|
||||
QPixmap originalPixmap = screen->grabWindow(RMApp::instance()->pMainWindow->winId());
|
||||
|
||||
QPainter painter(&originalPixmap);
|
||||
|
||||
#if !(DO_NOT_USE_MAP)
|
||||
// 지도 크기로 생성
|
||||
#if (USE_WEBVIEW2)
|
||||
QPixmap mapPixmap;
|
||||
#else // #if (USE_WEBVIEW2)
|
||||
QPixmap mapPixmap(RMDialogMap::instance()->_map->size());
|
||||
// 그린다
|
||||
// qInfo() << RMDialogMap::instance()->isGPSExist();
|
||||
if(RMDialogMap::instance()->isGPSExist()) {
|
||||
RMDialogMap::instance()->_map->render(&mapPixmap);
|
||||
}
|
||||
#endif // #if (USE_WEBVIEW2)
|
||||
|
||||
// 지도 그릴 영역
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
QRect targetRect = QRect(699,285,352,391);
|
||||
#else
|
||||
QRect targetRect = QRect(681,331,339,358);
|
||||
#endif
|
||||
|
||||
QRect cropSrc = QRect();
|
||||
cropSrc.setSize(targetRect.size());
|
||||
QRect cropRect = QRectAspectFitRect(targetRect.size(),cropSrc);
|
||||
#if (DUAL_VIEWER)
|
||||
QPixmap cropped = mapPixmap.copy(0,(358-225)/2,cropRect.width(),cropRect.height());
|
||||
#else
|
||||
// 크롭
|
||||
QPixmap cropped = mapPixmap.copy(cropRect);
|
||||
#endif
|
||||
|
||||
// 지도 그림
|
||||
painter.drawPixmap(targetRect.left(),targetRect.top(),targetRect.width(),targetRect.height(),cropped);
|
||||
#endif // #if !(DO_NOT_USE_MAP)
|
||||
|
||||
// 저장 (엑셀에서 불러오기 위해)
|
||||
QString tempImagePath = QDir::cleanPath(RMApp::appPath(RMApp::CAPTURE) + "/_report" + date.toString("yyyy_MMdd_HHmmss") + ".jpg");
|
||||
QFile imageFile(tempImagePath);
|
||||
if(imageFile.exists())
|
||||
{
|
||||
QFile::remove(tempImagePath);
|
||||
}
|
||||
imageFile.open(QIODevice::WriteOnly);
|
||||
originalPixmap.save(&imageFile, "JPG");
|
||||
imageFile.close();
|
||||
|
||||
// 엑셀파일 이미지 영역
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
QRect imageRect(33,633,507,507*MAIN_WINDOW_HEIGHT/MAIN_WINDOW_WIDTH);
|
||||
#else
|
||||
QRect imageRect(781,409,480,480*MAIN_WINDOW_HEIGHT/MAIN_WINDOW_WIDTH);
|
||||
#endif
|
||||
QRect destRect = QRectAspectFitRect(originalPixmap.size(),imageRect);
|
||||
|
||||
_shapes = _sheet->querySubObject("Shapes");
|
||||
_picture = _shapes->querySubObject("AddPicture( QString&, bool, bool, double, double, double, double)",QDir::toNativeSeparators(tempImagePath),true,true,destRect.left(),destRect.top(),destRect.width(),destRect.height());
|
||||
|
||||
|
||||
_workbook->dynamicCall("SaveAs (const QString&)", QDir::toNativeSeparators(path));
|
||||
_workbook->dynamicCall("Close()");
|
||||
|
||||
clearAll();
|
||||
dynamicCall("Quit()");
|
||||
QFile::remove(tempReportPath);
|
||||
QFile::remove(tempImagePath);
|
||||
return true;
|
||||
}
|
||||
30
project/fm_viewer/core/rm_excel_report.h
Normal file
30
project/fm_viewer/core/rm_excel_report.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef RM_EXCEL_REPORT_H
|
||||
#define RM_EXCEL_REPORT_H
|
||||
|
||||
#include <QAxObject>
|
||||
|
||||
class RMExcelReport : public QAxObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RMExcelReport(QObject *parent = nullptr);
|
||||
#if (USE_JP_ADDRESS)
|
||||
bool prepare(QString& path,QDateTime* pDateTime, double lon, double lat);
|
||||
#else
|
||||
bool prepare(QString& path,QDateTime* pDateTime);
|
||||
#endif
|
||||
private:
|
||||
void clearAll();
|
||||
QAxObject* _workbooks;
|
||||
QAxObject* _workbook;
|
||||
QAxObject* _sheets;
|
||||
QAxObject* _sheet;
|
||||
|
||||
QAxObject* _shapes;
|
||||
QAxObject* _picture;
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
#endif // RM_EXCEL_REPORT_H
|
||||
79
project/fm_viewer/core/rm_key_event.cpp
Normal file
79
project/fm_viewer/core/rm_key_event.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "rm_key_event.h"
|
||||
#include "ui/fm_button.h"
|
||||
#if (USE_RM_KEYBOARD_EVENT)
|
||||
|
||||
|
||||
RMKeyEvent::RMKeyEvent(QObject *parent) : QObject(parent)
|
||||
{
|
||||
_lastKey = -1;
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
void RMKeyEvent::pressed(int key)
|
||||
{
|
||||
// KEY PRESS + MOUSE PRESS 동시 처리할 경우
|
||||
if(_enabled && exist(key) && _lastKey != key)
|
||||
{
|
||||
// 이전 pressed 된 이후 released 안된 버튼 존재할 경우
|
||||
if(_lastKey != -1)
|
||||
{
|
||||
released(_lastKey);
|
||||
}
|
||||
|
||||
_lastKey = key;
|
||||
switch (key) {
|
||||
case Qt::Key_Right:
|
||||
// qInfo() << "F1 start";
|
||||
emit pressedF1();
|
||||
break;
|
||||
case Qt::Key_Left:
|
||||
//qInfo() << "B1 start";
|
||||
emit pressedB1();
|
||||
break;
|
||||
case Qt::Key_F:
|
||||
//qInfo() << "FF start";
|
||||
emit pressedFF();
|
||||
break;
|
||||
case Qt::Key_D:
|
||||
//qInfo() << "FF start";
|
||||
emit pressedBF();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RMKeyEvent::released(int key)
|
||||
{
|
||||
FMButton* btn = qobject_cast<FMButton*>(sender());
|
||||
if(btn != NULL) {
|
||||
btn->blockFor(100);
|
||||
}
|
||||
|
||||
if(_enabled && exist(key) && key == _lastKey)
|
||||
{
|
||||
_lastKey = -1;
|
||||
switch (key) {
|
||||
case Qt::Key_Right:
|
||||
// qInfo() << "F1 end";
|
||||
emit releasedF1();
|
||||
break;
|
||||
case Qt::Key_Left:
|
||||
//qInfo() << "B1 end";
|
||||
emit releasedB1();
|
||||
break;
|
||||
case Qt::Key_F:
|
||||
//qInfo() << "FF end";
|
||||
emit releasedFF();
|
||||
break;
|
||||
case Qt::Key_D:
|
||||
//qInfo() << "FF end";
|
||||
emit releasedBF();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
74
project/fm_viewer/core/rm_key_event.h
Normal file
74
project/fm_viewer/core/rm_key_event.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef RM_KEY_EVENT_H
|
||||
#define RM_KEY_EVENT_H
|
||||
#include "../rm_include.h"
|
||||
#if (USE_RM_KEYBOARD_EVENT)
|
||||
|
||||
#include <QObject>
|
||||
#include <QKeyEvent>
|
||||
|
||||
class RMKeyEvent : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RMKeyEvent(QObject *parent = nullptr);
|
||||
static RMKeyEvent* instance()
|
||||
{
|
||||
static RMKeyEvent * _instance = 0;
|
||||
if ( _instance == 0 ) {
|
||||
_instance = new RMKeyEvent();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
void pressed(int key);
|
||||
void released(int key);
|
||||
inline static bool exist(int key)
|
||||
{
|
||||
return (key == Qt::Key_Left || key == Qt::Key_Right || key == Qt::Key_F || key == Qt::Key_D);
|
||||
}
|
||||
inline bool exist()
|
||||
{
|
||||
return (_lastKey != -1);
|
||||
}
|
||||
|
||||
void setEnabled(bool enabled)
|
||||
{
|
||||
_enabled = enabled;
|
||||
_lastKey = -1;
|
||||
}
|
||||
|
||||
private:
|
||||
int _lastKey;
|
||||
bool _enabled;
|
||||
signals:
|
||||
|
||||
void pressedF1();
|
||||
void releasedF1();
|
||||
void pressedB1();
|
||||
void releasedB1();
|
||||
void pressedFF();
|
||||
void releasedFF();
|
||||
void pressedBF();
|
||||
void releasedBF();
|
||||
|
||||
public slots:
|
||||
void onPressedF1()
|
||||
{
|
||||
pressed(Qt::Key_Right);
|
||||
}
|
||||
void onReleasedF1()
|
||||
{
|
||||
released(Qt::Key_Right);
|
||||
}
|
||||
void onPressedB1()
|
||||
{
|
||||
pressed(Qt::Key_Left);
|
||||
}
|
||||
void onReleasedB1()
|
||||
{
|
||||
released(Qt::Key_Left);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // #if (USE_RM_KEYBOARD_EVENT)
|
||||
|
||||
#endif // RM_KEY_EVENT_H
|
||||
136
project/fm_viewer/core/rm_language.cpp
Normal file
136
project/fm_viewer/core/rm_language.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
#include "rm_language.h"
|
||||
#if(LIVE_LANGUAGE_CHANGE)
|
||||
#include <QDebug>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include "../rm_settings.h"
|
||||
#include "../rm_include.h"
|
||||
#include "fm_strings.h"
|
||||
#include <QLocale>
|
||||
#if (INITIAL_LANGUAGE_AUTO)
|
||||
bool RMLanguage::isAuto = true;
|
||||
#else
|
||||
bool RMLanguage::isAuto = false;
|
||||
#endif
|
||||
|
||||
RMLanguage::RMLanguage(QObject *parent) : QObject(parent)
|
||||
{
|
||||
#if (FIXED_ENGLISH)
|
||||
RMLanguage::isAuto = false;
|
||||
_currentLanguage = LANGUAGE_EN;
|
||||
#else
|
||||
RMLanguage::isAuto = RMSettings::instance()->autoLanguage();
|
||||
_currentLanguage = (LANGUAGE_TYPE)RMSettings::instance()->language();
|
||||
#endif
|
||||
_list = new QHash<qint64,QHash<int,QString>*>();
|
||||
}
|
||||
RMLanguage::LANGUAGE_TYPE RMLanguage::systemLanguage()
|
||||
{
|
||||
QString lan = QLocale::system().name();
|
||||
#if (LIVE_LANGUAGE2)
|
||||
if(lan.contains("JP",Qt::CaseInsensitive))
|
||||
{
|
||||
return RMLanguage::LANGUAGE_JP;
|
||||
}
|
||||
else if (lan.contains("KR",Qt::CaseInsensitive)) {
|
||||
return RMLanguage::LANGUAGE_KR;
|
||||
}
|
||||
return RMLanguage::LANGUAGE_EN;
|
||||
#else // #if (LIVE_LANGUAGE2)
|
||||
#if (LANGUAGE_REMOVE_ENG) // WATEX
|
||||
return RMLanguage::LANGUAGE_JP;
|
||||
#else
|
||||
if(lan.contains("JP",Qt::CaseInsensitive))
|
||||
{
|
||||
return RMLanguage::LANGUAGE_JP;
|
||||
}
|
||||
return RMLanguage::LANGUAGE_EN;
|
||||
#endif
|
||||
#endif // #if (LIVE_LANGUAGE2)
|
||||
}
|
||||
|
||||
|
||||
#if (LIVE_LANGUAGE2)
|
||||
void RMLanguage::append(const char* key,RMLanguage::TEXT_TYPE type,QObject* control)
|
||||
{
|
||||
qint64 object_key = (qint64)control;
|
||||
//qInfo() << control << "key:" << key;
|
||||
QHash<int,QString>* info = _list->value(object_key);
|
||||
if(info == NULL)
|
||||
{
|
||||
info = new QHash<int,QString>();
|
||||
_list->insert(object_key,info);
|
||||
}
|
||||
info->insert((LANGUAGE_JP | type),FMS::txt(key,LANGUAGE_JP));
|
||||
info->insert((LANGUAGE_EN | type),FMS::txt(key,LANGUAGE_EN));
|
||||
info->insert((LANGUAGE_KR | type),FMS::txt(key,LANGUAGE_KR));
|
||||
}
|
||||
#else // LIVE_LANGUAGE2
|
||||
void RMLanguage::append(RMLanguage::LANGUAGE_TYPE language,RMLanguage::TEXT_TYPE type, QObject* control,QString str)
|
||||
{
|
||||
//QMutableHashIterator itr = _list->iterator;
|
||||
//_controls->append(control);
|
||||
qint64 key = (qint64)control;
|
||||
//qInfo() << control << "key:" << key;
|
||||
QHash<int,QString>* info = _list->value(key);
|
||||
if(info == NULL)
|
||||
{
|
||||
info = new QHash<int,QString>();
|
||||
_list->insert(key,info);
|
||||
}
|
||||
info->insert((language | type),str);
|
||||
//info->insert((LANGUAGE_EN | type),"TEST");
|
||||
//qInfo()<< "insert:" << str;
|
||||
}
|
||||
#endif // LIVE_LANGUAGE2
|
||||
|
||||
void RMLanguage::setLanguage(RMLanguage::LANGUAGE_TYPE language)
|
||||
{
|
||||
#if (FIXED_ENGLISH)
|
||||
Q_UNUSED(language);
|
||||
#else
|
||||
_currentLanguage = language;
|
||||
refresh();
|
||||
RMSettings::instance()->setLanguage(_currentLanguage);
|
||||
emit languageChange(_currentLanguage);
|
||||
#endif
|
||||
}
|
||||
void RMLanguage::remove(QObject* control)
|
||||
{
|
||||
qint64 key = (qint64)control;
|
||||
_list->remove(key);
|
||||
}
|
||||
void RMLanguage::refresh()
|
||||
{
|
||||
RMLanguage::LANGUAGE_TYPE language = _currentLanguage;
|
||||
foreach (qint64 key, _list->keys()) {
|
||||
|
||||
QHash<int,QString>* info = _list->value(key);
|
||||
// qInfo() << control;
|
||||
|
||||
QObject* control = (QObject*)key;
|
||||
if(control->inherits("QPushButton"))
|
||||
{
|
||||
QString str = info->value(language | TOOLTIP_TEXT);
|
||||
QPushButton* btn = (QPushButton*)control;
|
||||
if(str.length() > 0)
|
||||
{
|
||||
btn->setToolTip(str);
|
||||
}
|
||||
str = info->value(language | TITLE_TEXT);
|
||||
if(str.length() > 0)
|
||||
{
|
||||
btn->setText(str);
|
||||
}
|
||||
}
|
||||
else if (control->inherits("QLabel"))
|
||||
{
|
||||
QLabel* lb = (QLabel*)control;
|
||||
QString str = info->value(language | TITLE_TEXT);
|
||||
//qInfo() << info->values();
|
||||
lb->setText(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
134
project/fm_viewer/core/rm_language.h
Normal file
134
project/fm_viewer/core/rm_language.h
Normal file
@@ -0,0 +1,134 @@
|
||||
#ifndef RM_LANGUAGE_H
|
||||
#define RM_LANGUAGE_H
|
||||
#if(LIVE_LANGUAGE_CHANGE)
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QHash>
|
||||
|
||||
// 등록(append)하여 자동으로 변경되는 타입(Button,Label)과
|
||||
// signal/slot 방식으로 처리 (TableWidget Header.. etc)
|
||||
class RMLanguage : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LANGUAGE_JP = 1 << 0, // 1
|
||||
LANGUAGE_EN = 1 << 1, // 2
|
||||
#if (RC_LANGUAGE == 0x0412)
|
||||
LANGUAGE_KR = 1 << 2, // 4
|
||||
#endif
|
||||
} LANGUAGE_TYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TITLE_TEXT = 1 << 8,
|
||||
TOOLTIP_TEXT = 1 << 9,
|
||||
} TEXT_TYPE;
|
||||
|
||||
explicit RMLanguage(QObject *parent = NULL);
|
||||
|
||||
static RMLanguage* instance()
|
||||
{
|
||||
static RMLanguage * _instance = NULL;
|
||||
if ( _instance == 0 ) {
|
||||
_instance = new RMLanguage();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
static RMLanguage::LANGUAGE_TYPE systemLanguage();
|
||||
static bool isAuto;
|
||||
#if !(REMOVE_OLD_C)
|
||||
static bool isJP() // 제거예정
|
||||
{
|
||||
#if (FIXED_ENGLISH)
|
||||
return false;
|
||||
#else
|
||||
return (RMLanguage::instance()->language() == RMLanguage::LANGUAGE_JP);
|
||||
#endif
|
||||
}
|
||||
#endif // #if !(REMOVE_OLD_C)
|
||||
static QString languageTag()
|
||||
{
|
||||
#if (LANGUAGE_REMOVE_ENG)
|
||||
return "";
|
||||
#else // LANGUAGE_REMOVE_ENG
|
||||
#if (FIXED_ENGLISH)
|
||||
return "_en";
|
||||
#else // FIXED_ENGLISH
|
||||
#if (SUB_MODEL_BV5000 == 1 || RM_MODEL == 16 || SUPPORT_MULTI_LANGUAGE)
|
||||
switch(RMLanguage::instance()->language()) {
|
||||
case RMLanguage::LANGUAGE_EN:
|
||||
return "_en";
|
||||
case RMLanguage::LANGUAGE_JP:
|
||||
return "_jp";
|
||||
case RMLanguage::LANGUAGE_KR:
|
||||
return "";
|
||||
}
|
||||
#else
|
||||
return (RMLanguage::instance()->language() == RMLanguage::LANGUAGE_EN) ? "_en" : "";
|
||||
#endif //SUB_MODEL_BV5000
|
||||
#endif // FIXED_ENGLISH
|
||||
#endif // LANGUAGE_REMOVE_ENG
|
||||
return "";
|
||||
}
|
||||
|
||||
#if (LIVE_LANGUAGE2)
|
||||
void append(const char* key,RMLanguage::TEXT_TYPE type,QObject* control);
|
||||
#else // LIVE_LANGUAGE2
|
||||
void append(RMLanguage::LANGUAGE_TYPE language,RMLanguage::TEXT_TYPE type, QObject* control,QString str);
|
||||
void appendENGToolTip(QObject* control,QString str)
|
||||
{
|
||||
#if (LANGUAGE_REMOVE_ENG)
|
||||
Q_UNUSED(control)
|
||||
Q_UNUSED(str)
|
||||
#else
|
||||
append(RMLanguage::LANGUAGE_EN,RMLanguage::TOOLTIP_TEXT,control,str);
|
||||
#endif
|
||||
}
|
||||
#endif // LIVE_LANGUAGE2
|
||||
|
||||
|
||||
void remove(QObject* control);
|
||||
|
||||
void setLanguage(RMLanguage::LANGUAGE_TYPE language);
|
||||
RMLanguage::LANGUAGE_TYPE language()
|
||||
{
|
||||
#if (FIXED_ENGLISH)
|
||||
return RMLanguage::LANGUAGE_EN;
|
||||
#else
|
||||
return _currentLanguage;
|
||||
#endif
|
||||
}
|
||||
|
||||
// 0:자동, 1:일본어, 2:영어, 3:한국어
|
||||
int languageIndex() {
|
||||
if(RMLanguage::isAuto) {
|
||||
return 0;
|
||||
}
|
||||
switch (_currentLanguage) {
|
||||
case LANGUAGE_JP:
|
||||
return 2;
|
||||
case LANGUAGE_EN:
|
||||
return 3;
|
||||
#if (RC_LANGUAGE == 0x0412)
|
||||
case LANGUAGE_KR:
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
RMLanguage::LANGUAGE_TYPE _currentLanguage;
|
||||
|
||||
QHash<qint64,QHash<int,QString>*>* _list;
|
||||
signals:
|
||||
void languageChange(RMLanguage::LANGUAGE_TYPE language);
|
||||
|
||||
};
|
||||
|
||||
#endif // LIVE_LANGUAGE_CHANGE
|
||||
#endif // RM_LANGUAGE_H
|
||||
64
project/fm_viewer/core/rm_math.cpp
Normal file
64
project/fm_viewer/core/rm_math.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "rm_math.h"
|
||||
#include <qmath.h>
|
||||
|
||||
float QAspectScaleFit(QSize sourceSize, QRect destRect)
|
||||
{
|
||||
QSize destSize = destRect.size();
|
||||
float scaleW = (float)destSize.width() / (float)sourceSize.width();
|
||||
float scaleH = (float)destSize.height() / (float)sourceSize.height();
|
||||
return qMin(scaleW, scaleH);
|
||||
}
|
||||
QRect QRectFRound(QRectF r)
|
||||
{
|
||||
double xmin = floor(r.left());
|
||||
double ymin = floor(r.top());
|
||||
|
||||
double width = ceil(r.width() + (r.left()-xmin));
|
||||
double height = ceil(r.height() + (r.top()-ymin));
|
||||
return QRect(xmin,ymin,width,height);
|
||||
}
|
||||
|
||||
// Fit
|
||||
QRect QRectAspectFitRect(QSize sourceSize, QRect destRect)
|
||||
{
|
||||
QSize destSize = destRect.size();
|
||||
float destScale = QAspectScaleFit(sourceSize, destRect);
|
||||
|
||||
float newWidth = (float)sourceSize.width() * destScale;
|
||||
float newHeight = (float)sourceSize.height() * destScale;
|
||||
|
||||
float dWidth = (((float)destSize.width() - newWidth) / 2.0f);
|
||||
float dHeight = (((float)destSize.height() - newHeight) / 2.0f);
|
||||
|
||||
QRect rect = QRect(dWidth + destRect.left(), dHeight + destRect.top(), newWidth, newHeight);
|
||||
return rect;
|
||||
}
|
||||
QRect QRectCenter(QSize sourceSize, QRect destRect)
|
||||
{
|
||||
int xo = (destRect.width() - sourceSize.width()) / 2;
|
||||
int yo = (destRect.height() - sourceSize.height()) / 2;
|
||||
return QRect(destRect.left()+xo,destRect.top()+yo,sourceSize.width(),sourceSize.height());
|
||||
}
|
||||
|
||||
QRect QRectAspectFillRect(QSize sourceSize, QRect destRect)
|
||||
{
|
||||
QSize destSize = destRect.size();
|
||||
float destScale = QAspectScaleFill(sourceSize, destRect);
|
||||
|
||||
float newWidth = (float)sourceSize.width() * destScale;
|
||||
float newHeight = (float)sourceSize.height() * destScale;
|
||||
|
||||
float dWidth = (((float)destSize.width() - newWidth) / 2.0f);
|
||||
float dHeight = (((float)destSize.height() - newHeight) / 2.0f);
|
||||
|
||||
// l,t,r,b
|
||||
QRect rect = QRect(dWidth + destRect.left(), dHeight + destRect.top(), newWidth, newHeight);
|
||||
return rect;
|
||||
}
|
||||
float QAspectScaleFill(QSize sourceSize, QRect destRect)
|
||||
{
|
||||
QSize destSize = destRect.size();
|
||||
float scaleW = (float)destSize.width() / (float)sourceSize.width();
|
||||
float scaleH = (float)destSize.height() / (float)sourceSize.height();
|
||||
return qMax(scaleW, scaleH);
|
||||
}
|
||||
13
project/fm_viewer/core/rm_math.h
Normal file
13
project/fm_viewer/core/rm_math.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef RM_MATH_H
|
||||
#define RM_MATH_H
|
||||
|
||||
#include <QRect>
|
||||
#include <QRectF>
|
||||
|
||||
QRect QRectAspectFitRect(QSize sourceSize, QRect destRect);
|
||||
float QAspectScaleFit(QSize sourceSize, QRect destRect);
|
||||
QRect QRectAspectFillRect(QSize sourceSize, QRect destRect);
|
||||
float QAspectScaleFill(QSize sourceSize, QRect destRect);
|
||||
QRect QRectFRound(QRectF r);
|
||||
QRect QRectCenter(QSize sourceSize, QRect destRect);
|
||||
#endif // RM_MATH_H
|
||||
161
project/fm_viewer/core/rm_play_process.cpp
Normal file
161
project/fm_viewer/core/rm_play_process.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
#include "rm_play_process.h"
|
||||
#include "rm_player.h"
|
||||
#include "../ui/rm_widget_video_list.h"
|
||||
#include "../data/rm_video_item_loader.h"
|
||||
#include <QThreadPool>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
|
||||
|
||||
bool RMPlayProcess::bConnected = false;
|
||||
bool RMPlayProcess::bProcessing = false;
|
||||
|
||||
#if (PLAYER_ONLY_LIBRARY_MODE)
|
||||
void RMPlayProcess::connectEvents()
|
||||
{
|
||||
if(RMPlayProcess::bConnected == false) {
|
||||
RMPlayProcess::bConnected = true;
|
||||
|
||||
// 리스트에서 파일 플레이 요청되면 로딩 시작
|
||||
//connect(listWidget,SIGNAL(listSelected(RMVideoItem*)),this,SLOT(onVideoLoadingStart(RMVideoItem*)));
|
||||
RMPlayer* player = RMPlayer::instance();
|
||||
|
||||
// 플레이 중 버튼 상태 업데이트
|
||||
connect(player,SIGNAL(playEvent(PLAY_EVENT, RMVideoItem*)),SLOT(onPlayEvent(PLAY_EVENT, RMVideoItem*)));
|
||||
|
||||
}
|
||||
}
|
||||
#else // PLAYER_ONLY_LIBRARY_MODE
|
||||
void RMPlayProcess::connectEvents(RMWidgetVideoList* listWidget)
|
||||
{
|
||||
_loadingItem = NULL;
|
||||
|
||||
if(RMPlayProcess::bConnected == false) {
|
||||
RMPlayProcess::bConnected = true;
|
||||
|
||||
// 리스트에서 파일 플레이 요청되면 로딩 시작
|
||||
connect(listWidget,SIGNAL(listSelected(RMVideoItem*)),this,SLOT(onVideoLoadingStart(RMVideoItem*)));
|
||||
RMPlayer* player = RMPlayer::instance();
|
||||
|
||||
// 비디오 로딩 종료시
|
||||
//connect(player,SIGNAL(mediaLoadEnd(RMVideoItem*)),SLOT(onVideoLoadingEnd(RMVideoItem*)));
|
||||
|
||||
// 플레이 중 버튼 상태 업데이트
|
||||
connect(player,SIGNAL(playEvent(PLAY_EVENT, RMVideoItem*)),SLOT(onPlayEvent(PLAY_EVENT, RMVideoItem*)));
|
||||
|
||||
}
|
||||
}
|
||||
#endif // #else // PLAYER_ONLY_LIBRARY_MODE
|
||||
void RMPlayProcess::onVideoLoadingStart(RMVideoItem* item)
|
||||
{
|
||||
//qInfo() << item << __FUNCTION__;
|
||||
RMPlayProcess::bProcessing = true;
|
||||
// QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
// 기존 item 및 설정 초기화
|
||||
RMPlayer* player = RMPlayer::instance();
|
||||
#if !(PLAY_CONTINUE_EVENT)
|
||||
connect(player,SIGNAL(playerClearedDone()),SLOT(onPlayerClearDone()));
|
||||
#endif
|
||||
// cpu limit https://technet.microsoft.com/en-us/library/ff384148(v=ws.10).aspx
|
||||
// sid wmic useraccount get name,sid
|
||||
|
||||
_loadingItem = item; // 먼저 설정하고..
|
||||
player->stop(); // 플레이어 종료
|
||||
|
||||
//#if (USE_LIBRARY_MODE)
|
||||
// if(RMPlayer::libraryInstance != NULL) {
|
||||
// RMPlayer::libraryInstance->stop();
|
||||
// }
|
||||
//#endif // USE_LIBRARY_MODE
|
||||
}
|
||||
|
||||
#if !(PLAY_CONTINUE_EVENT)
|
||||
void RMPlayProcess::onPlayerClearDone()
|
||||
{
|
||||
RMPlayer* player = RMPlayer::instance();
|
||||
disconnect(player,SIGNAL(playerClearedDone()),this,SLOT(onPlayerClearDone()));
|
||||
|
||||
if (_loadingItem != NULL)
|
||||
{
|
||||
#if (!PRE_LOAD_SENSOR_DATA)
|
||||
// 센서 정보 로딩
|
||||
connect(_loadingItem,SIGNAL(loadAVIInfoEnd()),SLOT(onInfoLoadingEnd()),Qt::UniqueConnection); // -> 로딩완료시
|
||||
|
||||
// qInfo() << "2. start sensor data loading ----------------- ";
|
||||
// Loader delete???
|
||||
// GPS, 및 기타 센서 정보 가져오기
|
||||
// QRunnable 은 자동으로 delete 됨
|
||||
RMVideoItemLoader* loader = new RMVideoItemLoader(_loadingItem);
|
||||
QThreadPool::globalInstance()->start(loader,LOADER_THREAD_PRIORITY);
|
||||
_loadingItem = NULL;
|
||||
#else
|
||||
RMPlayer::instance()->onLoad(_loadingItem);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if (!PRE_LOAD_SENSOR_DATA)
|
||||
void RMPlayProcess::onInfoLoadingEnd() // 현재 사용되지 않는다.????
|
||||
{
|
||||
RMVideoItem* item = qobject_cast <RMVideoItem*>(QObject::sender());
|
||||
|
||||
// 연결해제
|
||||
disconnect(item,SIGNAL(loadAVIInfoEnd()),this,SLOT(onInfoLoadingEnd()));
|
||||
|
||||
//#if (USE_LIBRARY_MODE)
|
||||
// if(RMApp::isTB5000 && RMPlayer::libraryInstance != NULL) {
|
||||
// RMPlayer::libraryInstance->onLoad(item);
|
||||
// return;
|
||||
// }
|
||||
//#endif // USE_LIBRARY_MODE
|
||||
|
||||
// 동영상 로딩시작 및 플레이
|
||||
RMPlayer::instance()->onLoad(item);
|
||||
}
|
||||
#endif
|
||||
|
||||
void RMPlayProcess::onPlayEvent(PLAY_EVENT event, RMVideoItem* item)
|
||||
{
|
||||
Q_UNUSED(item)
|
||||
if(event == PLAY_DID_LOADED)
|
||||
{
|
||||
//QApplication::restoreOverrideCursor();
|
||||
RMPlayProcess::bProcessing = false;
|
||||
if(item != NULL)
|
||||
{
|
||||
// _plotWidget->onUpdateGraph(item);
|
||||
|
||||
// no sensor 의 경우 update map 처리하면 onUpdateMap 처리됨
|
||||
// emit _mapWidget->updateMap(item);
|
||||
}
|
||||
}
|
||||
#if (PLAY_CONTINUE_EVENT)
|
||||
else if (event == PLAY_DID_CLEARED && _loadingItem != NULL)
|
||||
{
|
||||
// DELAY 처리해도 멈추는 증상 발생함.
|
||||
// RMPlayer::instance()->onLoad(_loadingItem);
|
||||
// qInfo() << "START LOAD NEXT FILE" << __FUNCTION__ << __LINE__;
|
||||
// _loadingItem = NULL;
|
||||
//#if (SUPPORT_LIBRARY_MODE)
|
||||
// onStartNext();
|
||||
// const int mWait = 100;
|
||||
//#else // SUPPORT_LIBRARY_MODE
|
||||
const int mWait = 1;
|
||||
//#endif // SUPPORT_LIBRARY_MODE
|
||||
QTimer::singleShot(mWait,Qt::PreciseTimer,this,SLOT(onStartNext()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void RMPlayProcess::onStartNext()
|
||||
{
|
||||
//#if !(PLAYER_ONLY_LIBRARY_MODE)
|
||||
// FIXED_SLEEP; //qInfo() << "START LOAD NEXT FILE" << __FUNCTION__ << __LINE__;
|
||||
//#endif//
|
||||
//qInfo() << "::onStartNext" << _loadingItem->title();
|
||||
RMPlayer::instance()->onLoad(_loadingItem);
|
||||
_loadingItem = NULL;
|
||||
}
|
||||
60
project/fm_viewer/core/rm_play_process.h
Normal file
60
project/fm_viewer/core/rm_play_process.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef RM_PLAY_PROCESS_H
|
||||
#define RM_PLAY_PROCESS_H
|
||||
|
||||
#include "../rm_include.h"
|
||||
#include "rm_player_base.h"
|
||||
#include <QObject>
|
||||
class RMVideoItem;
|
||||
class RMWidgetVideoList;
|
||||
class RMPlayProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static RMPlayProcess* instance()
|
||||
{
|
||||
static RMPlayProcess * _instance = 0;
|
||||
if ( _instance == 0 ) {
|
||||
_instance = new RMPlayProcess();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
// STOP (PLAY_DID_CLEARED) 이벤트 발생시 다음 파일 로딩 중인지 확인해서
|
||||
// 화면 깜빡거리지 않도록 처리
|
||||
bool isLoadingNextFile() {
|
||||
return (_loadingItem != NULL);
|
||||
}
|
||||
|
||||
// 모든 윈도우 및 instance 생성 후 연결해야함
|
||||
#if (PLAYER_ONLY_LIBRARY_MODE)
|
||||
void connectEvents();
|
||||
#else // PLAYER_ONLY_LIBRARY_MODE
|
||||
void connectEvents(RMWidgetVideoList* listWidget);
|
||||
#endif // PLAYER_ONLY_LIBRARY_MODE
|
||||
|
||||
// 다른 프로세스 중지
|
||||
static bool bProcessing;
|
||||
private:
|
||||
static bool bConnected;
|
||||
RMVideoItem* _loadingItem;
|
||||
|
||||
private slots:
|
||||
|
||||
void onPlayEvent(PLAY_EVENT event, RMVideoItem* item);
|
||||
|
||||
// Play Control (from mainWindow)
|
||||
#if (PLAYER_ONLY_LIBRARY_MODE)
|
||||
public slots:
|
||||
#endif
|
||||
void onVideoLoadingStart(RMVideoItem* item); // 1. 플레이 시작
|
||||
#if !(PLAY_CONTINUE_EVENT)
|
||||
void onPlayerClearDone(); // 2. 기존 파일 unload 종료
|
||||
#endif
|
||||
|
||||
#if (!PRE_LOAD_SENSOR_DATA)
|
||||
void onInfoLoadingEnd(); // 3. 파일 센서 정보 읽어 오기
|
||||
#endif
|
||||
void onStartNext();
|
||||
//void onVideoLoadingEnd(RMVideoItem* item); // 4. Player 에서 Video Loading 완료
|
||||
};
|
||||
|
||||
#endif // RM_PLAY_PROCESS_H
|
||||
1786
project/fm_viewer/core/rm_player.cpp
Normal file
1786
project/fm_viewer/core/rm_player.cpp
Normal file
File diff suppressed because it is too large
Load Diff
383
project/fm_viewer/core/rm_player.h
Normal file
383
project/fm_viewer/core/rm_player.h
Normal file
@@ -0,0 +1,383 @@
|
||||
#ifndef RM_PLAYER_H
|
||||
#define RM_PLAYER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <qslider.h>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "rm_constants.h"
|
||||
#include "rm_include.h"
|
||||
#include "rm_player_base.h"
|
||||
#include "rm_player_zoom.h"
|
||||
|
||||
|
||||
#define DEBUG_RM_PLAYER 0
|
||||
#define USE_RM_D2_PLAYER 0
|
||||
#define CAPTURE_DEBUG 0
|
||||
|
||||
class RMVideoItem;
|
||||
class RMFrameSlider;
|
||||
|
||||
#if (MODEL_BBVIEWER)
|
||||
class RMEQWidget;
|
||||
#endif
|
||||
|
||||
#define DEBUG_HIGH_SPEED_STOP 0
|
||||
#define REMOVE_CLOCK_UPDATE_WHEN_SEEKING 1
|
||||
#define STEP_SEEK_DURATION 34
|
||||
|
||||
|
||||
//extern const int g_PlaySpeed1XIndex;
|
||||
|
||||
#if (MODEL_BBVIEWER)
|
||||
#define PLAY_SPEED_COUNT 5
|
||||
#elif (RM_MODEL == RM_MODEL_TYPE_TB4000 || RM_MODEL_EMT_KR)
|
||||
#define PLAY_SPEED_COUNT 5
|
||||
#else
|
||||
#define PLAY_SPEED_COUNT 4
|
||||
#endif
|
||||
extern float g_PlaySpeedList[PLAY_SPEED_COUNT];
|
||||
|
||||
extern int DEFAULT_SPEED_INDEX;
|
||||
|
||||
class RMPlayer : public RMPlayerZoom
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static RMPlayer* instance()
|
||||
{
|
||||
static RMPlayer * _instance = 0;
|
||||
if ( _instance == NULL ) {
|
||||
_instance = new RMPlayer();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
//#if (USE_LIBRARY_MODE) // 360 DLL
|
||||
// static RMPlayer* libraryInstance;
|
||||
//#endif //
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
// 는 _isSwapped() 와는 별도로 사용자 swap 상태만 확인하기 위해 사용
|
||||
bool isSwapped() { return _swaped; }
|
||||
#endif
|
||||
void stop() override;
|
||||
|
||||
QString currentTimeString(double* lat, double* lon);
|
||||
#if (PENTA_CHANNEL)
|
||||
void changeCHMode(RMApp::ChannelMode mode) override;
|
||||
#endif
|
||||
void updateSpeedForce(qreal speed)
|
||||
{
|
||||
_speedValue = speed;
|
||||
updateSpeed(_speedValue);
|
||||
}
|
||||
#if !(RM_MODEL == RM_MODEL_TYPE_TB4000)
|
||||
void setMuteButton(FMButton* btn) {
|
||||
_muteButton = btn;
|
||||
}
|
||||
#endif // #if !(RM_MODEL == RM_MODEL_TYPE_TB4000)
|
||||
void setSlider(QSlider* slider) {
|
||||
_slider = slider;
|
||||
|
||||
// PRESSED -> MOVED -> RELEASED 순서대로 호출 되도록 이벤트 처리해야함
|
||||
// 노브가 아닌 지점 CLICK 시에는 Slider는 (Slider)PRESSED 이벤트 만 호출됨 (RMSlider 내부에서 구현)
|
||||
// PRESSED 이벤트 발생시 KNOB 가 false 일 경우 released 이벤트 발생하지 않으니 별도의 처리 하지 말아야함
|
||||
connect(_slider, SIGNAL(sliderPressedWithKnob(bool)),SLOT(onSliderPress(bool))); // 이벤트 두번씩 발생함
|
||||
|
||||
connect(_slider, SIGNAL(sliderMoved(int)),SLOT(onSliderMove(int))); // 슬라이더 컨트롤
|
||||
connect(_slider, SIGNAL(mouseReleased()),SLOT(onSliderRelease()));
|
||||
}
|
||||
#if !(RM_MODEL == RM_MODEL_TYPE_TB4000)
|
||||
void setVolumeSlider(QSlider* slider) {
|
||||
_volumeSlider = slider;
|
||||
connect(_volumeSlider, SIGNAL(sliderPressed()), SLOT(onSetVolume()));
|
||||
connect(_volumeSlider, SIGNAL(valueChanged(int)), SLOT(onSetVolume()));
|
||||
onSetVolume();
|
||||
}
|
||||
#endif // RM_MODEL_TYPE_TB4000
|
||||
|
||||
void setSpeedSlider(QSlider* slider, QLabel* label) {
|
||||
_speedLabel = label;
|
||||
connect(slider, SIGNAL(mouseReleased()),SLOT(onSpeedSliderReleased()));
|
||||
connect(slider, SIGNAL(sliderMoved(int)),SLOT(onSpeedSliderMoved(int)));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// SLIDER 이동중에는 강제 PAUSE
|
||||
bool _pauseWhileSeek;
|
||||
|
||||
QTimer* _captureTimer;
|
||||
QTimer* _captureWatcher;
|
||||
//#if (SEEK_BY_SLIDER)
|
||||
// QTimer* _seekPositionTimer;
|
||||
// void startSeekTimer();
|
||||
//#endif
|
||||
|
||||
#if (USE_RM_KEYBOARD_EVENT)
|
||||
int _seekAcceleration; // 가속
|
||||
QTimer* _seekPressedTimer; // Slider 이동 타이머
|
||||
QTimer* _seekReleasedTimer; // Seek Update 타이머
|
||||
QTimer* _seekUpdateTimer; // Pressed 중간 Seek Update 타이머
|
||||
void startSeekUpdateTimer();
|
||||
void stopSeekUpdateTimer() override;
|
||||
|
||||
bool isSeekProcessing() override
|
||||
{
|
||||
return (_seekPressedTimer != NULL || _seekReleasedTimer != NULL || _seekUpdateTimer != NULL);
|
||||
}
|
||||
|
||||
//#else
|
||||
// QElapsedTimer _stepTimer;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual void timerEvent(QTimerEvent *e);
|
||||
|
||||
public:
|
||||
|
||||
explicit RMPlayer(QObject *parent = 0);
|
||||
|
||||
RMVideoItem* getCurrentItem()
|
||||
{
|
||||
return _currentItem;
|
||||
}
|
||||
QDateTime currentTime(double* lon = NULL,double* lat = NULL);
|
||||
|
||||
VIDEO_MODE videoMode()
|
||||
{
|
||||
return _videoMode;
|
||||
}
|
||||
|
||||
FAV::AVPlayer* playerF()
|
||||
{
|
||||
return _playerF;
|
||||
}
|
||||
|
||||
QWidget* playWidgetF()
|
||||
{
|
||||
return _videoOutputF->widget();
|
||||
}
|
||||
#if ((!SINGLE_CH_VIEWER && !TOGGLE_PLAYER) || DUAL_VIEWER || DUAL_VIDEO_WIDGET)
|
||||
QWidget* playWidgetR()
|
||||
{
|
||||
return _videoOutputR->widget();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
FAV::AVPlayer* playerR()
|
||||
{
|
||||
return _playerR;
|
||||
}
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
|
||||
#if (RM_MODEL_360)
|
||||
// SWAP 되더라도 메인 Renderer 는 항상 _videoOutputF 임
|
||||
FAV::VideoRenderer* mainRenderer() {
|
||||
return _videoOutputF;
|
||||
}
|
||||
FAV::VideoRenderer* renderer360() {
|
||||
#if (SINGLE_CH_VIEWER)
|
||||
return _videoOutputF;
|
||||
#else // SINGLE_CH_VIEWER
|
||||
return _swaped ? _videoOutputR : _videoOutputF;
|
||||
#endif // SINGLE_CH_VIEWER
|
||||
}
|
||||
#endif // RM_MODEL_360
|
||||
|
||||
//void setSliderFrame(RMFrameSlider* frame); // 슬라이더 설정
|
||||
#if (MODEL_BBVIEWER)
|
||||
void setEQFrame(RMEQWidget* eq);
|
||||
#endif
|
||||
// 비디오 캡쳐 요청
|
||||
bool requestVideoCapture();
|
||||
|
||||
qreal speedValue()
|
||||
{
|
||||
return _speedValue;
|
||||
}
|
||||
#if (SUPPORT_WIDE_MODE)
|
||||
/**
|
||||
* @brief 현재 재생중인 영상이 WIDE 모드 지원 영상일 경우
|
||||
* @return
|
||||
*/
|
||||
bool itemIsWideMode();
|
||||
|
||||
/**
|
||||
* @brief 현재 재생중인 모드가 WIDE 모드일 경우
|
||||
* @return
|
||||
*/
|
||||
bool isWideMode();
|
||||
#endif // SUPPORT_WIDE_MODE
|
||||
|
||||
#if (RM_TESTING)
|
||||
FAV::LibAVFilterVideo* _testFilterF;
|
||||
void applyTestFilter(QString filter);
|
||||
#endif
|
||||
|
||||
qint64 titleSeconds; // 슬라이더에 표시된 시간 (Capture 등에서 동기화 처리위해 사용)
|
||||
|
||||
public slots:
|
||||
|
||||
void requestVideoCaptureProcess();
|
||||
|
||||
// Slider Control
|
||||
void onSliderPress(bool bKnob);
|
||||
void onSliderMove(int value);
|
||||
void onSliderRelease();
|
||||
|
||||
//void onPlotMove(qreal ratio);
|
||||
|
||||
|
||||
// 사용자 정지
|
||||
void onUserStop();
|
||||
|
||||
#if (USE_RM_KEYBOARD_EVENT)
|
||||
void onSeekForwardStart();
|
||||
void onSeekBackwardStart();
|
||||
void onSeekFrameForwardStart();
|
||||
#if (PLAY_SYNC_FIX2)
|
||||
void onSeekFrameBackwardStart();
|
||||
#endif // PLAY_SYNC_FIX2
|
||||
void onSeekStepEnd();
|
||||
#endif
|
||||
|
||||
#if (PLAYER_ONLY_LIBRARY_MODE)
|
||||
void clear();
|
||||
void create();
|
||||
#endif // PLAYER_ONLY_LIBRARY_MODE
|
||||
|
||||
bool prepareForCapture();
|
||||
void onCaptureSavedFront(const QString& path);
|
||||
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
void onCaptureSavedRear(const QString& path);
|
||||
void toggleSwap(bool forceEmit = false);
|
||||
#endif
|
||||
|
||||
#if (TRI_CHANNEL || TRI_CHANNEL2)
|
||||
void toggleIndoor(bool forceEmit = false); // 후방 <-> 실내
|
||||
#endif
|
||||
#if (SUPPORT_WIDE_MODE)
|
||||
void toggleWide(); // NORMAL <-> WIDE
|
||||
#endif // SUPPORT_WIDE_MODE
|
||||
|
||||
void onSpeedSliderMoved(int position);
|
||||
void onSpeedSliderReleased();
|
||||
|
||||
|
||||
private:
|
||||
// 재생시간이 AVI:60260 VIDEO(Audio):59281 일 경우
|
||||
// 현재 POSITION + step 을
|
||||
// 실제 재생시간을 N 분할 하여 사용자가 보기 적합한 간격으로 표시함
|
||||
// eg 988.0166667 msec 씩 이동할 경우
|
||||
#if (USE_RM_KEYBOARD_EVENT)
|
||||
quint64 _stepPosition();
|
||||
//#else
|
||||
// quint64 _stepPosition(int step=1); // +1,-1
|
||||
#endif
|
||||
bool _isLastStep();
|
||||
|
||||
|
||||
// 이벤트 블럭처리함
|
||||
void blockEvents(int msec,bool b_show_indicator = false);
|
||||
|
||||
// pause 된 상태에서도 positionChanged 가 계속호출되어 방지용
|
||||
// int timeToSliderValue(qint64 time);
|
||||
qint64 ratioToSliderValue(qreal ratio);
|
||||
|
||||
QString _captureDir;
|
||||
QList<QString>* _captureFileList;
|
||||
|
||||
|
||||
// 통합관리 + 화면갱신을 위한 seek 구분
|
||||
void seek(qint64 pos,bool refresh) override;
|
||||
|
||||
// 정지된 상태에서 SEEK 를 통해 화면 갱신
|
||||
void updatePausedScreen();
|
||||
|
||||
void seekFrontOnly(qint64 pos,bool refresh);
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
void seekRearOnly(qint64 pos,bool refresh);
|
||||
#endif
|
||||
|
||||
// 후방만 갱신
|
||||
#if (!(SINGLE_CH_VIEWER || TOGGLE_PLAYER) || PENTA_CHANNEL)
|
||||
void updatePausedScreenRearOnly();
|
||||
#endif
|
||||
void updatePausedScreenFrontOnly();
|
||||
void clearCaptureTimer();
|
||||
void clearCaptureWatcher();
|
||||
|
||||
//void clearSliderReleaseTimer();
|
||||
|
||||
// Rear 는 V+H Flip 모두 지원
|
||||
void updateRearFlip();
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_TELEBIT)
|
||||
void updateFrontFlip();
|
||||
#endif
|
||||
|
||||
// 메인 clock 과 각 player 의 clock 동기화
|
||||
void clear_seek_timer();
|
||||
void sync_clock();
|
||||
|
||||
|
||||
|
||||
private slots:
|
||||
|
||||
#if (USE_RM_KEYBOARD_EVENT)
|
||||
void onSeekUpdate(); // 업데이트 후 타이머 제거하지 않음
|
||||
void onSeekLastUpdate(); // 업데이트 후 타이머 제거
|
||||
void onSeekPressed();
|
||||
#endif
|
||||
|
||||
#if (CAPTURE_DEBUG)
|
||||
void onSeekCapture();
|
||||
void onImageCaptured(const QImage& image);
|
||||
void onCaptureFailed();
|
||||
#endif
|
||||
|
||||
//#if !(FORCE_SINGLE_PLAYER)
|
||||
// 이벤트 블럭 해제 (전후방 swap 중에 별도 이벤트 받지 못하도록 처리)
|
||||
void onReleaseBlockEvent();
|
||||
//#endif
|
||||
|
||||
// 캡쳐 대기 완료
|
||||
void onReadyForCapture();
|
||||
|
||||
// 캡쳐 실패
|
||||
void onFailToCapture();
|
||||
|
||||
|
||||
|
||||
#if (PENTA_CHANNEL)
|
||||
void onUpdateCHMode() override;
|
||||
#endif // PENTA_CHANNEL
|
||||
|
||||
|
||||
// 동기화 시작 타이머
|
||||
void on_sync_timer_restarted();
|
||||
|
||||
// 처음으로 이동
|
||||
void onPlayRestart();
|
||||
//----------------------------------------------------------------------------------------------
|
||||
signals:
|
||||
|
||||
|
||||
void videoCaptureDone(QList<QString>* list);
|
||||
void swapChanged(bool swap);
|
||||
|
||||
|
||||
|
||||
#if (H265_SUPPORT)
|
||||
void show_indicator(bool show);
|
||||
#endif
|
||||
|
||||
void cancelFullScreen();
|
||||
|
||||
void userStop();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // RM_PLAYER_H
|
||||
2931
project/fm_viewer/core/rm_player_base.cpp
Normal file
2931
project/fm_viewer/core/rm_player_base.cpp
Normal file
File diff suppressed because it is too large
Load Diff
481
project/fm_viewer/core/rm_player_base.h
Normal file
481
project/fm_viewer/core/rm_player_base.h
Normal file
@@ -0,0 +1,481 @@
|
||||
#ifndef RM_PLAY_CONTROL_H
|
||||
#define RM_PLAY_CONTROL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimerEvent>
|
||||
#include <QSlider>
|
||||
|
||||
#include <QWaitCondition>
|
||||
|
||||
#include "../fav/fav.h"
|
||||
#include "../rm_include.h"
|
||||
#include "../fm_event_types.h"
|
||||
|
||||
|
||||
// 단말기 별로 설정 가능
|
||||
typedef enum
|
||||
{
|
||||
VIDEO_MODE_UNDEFINED = 0,
|
||||
VIDEO_MODE_OPENGL_ES = 1,
|
||||
VIDEO_MODE_WINDOW = 2,
|
||||
} VIDEO_MODE;
|
||||
|
||||
#if (USE_RM_KEYBOARD_EVENT)
|
||||
typedef enum
|
||||
{
|
||||
STEP_MODE_NONE = 0, // 일반 재생
|
||||
STEP_MODE_F1 = 1, // 1초 전방 이동
|
||||
STEP_MODE_B1 = 2, // 2초 후방 이동
|
||||
STEP_MODE_FF = 3, // 1 Frame 전방 이동
|
||||
#if (PLAY_SYNC_FIX2)
|
||||
STEP_MODE_BF = 4, // 1 Frame 후방 이동
|
||||
#endif
|
||||
} STEP_MODE;
|
||||
#endif
|
||||
|
||||
// Video Seek 방식 (KeyFrameSeek 처리하면 안됨)
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || RM_MODEL == RM_MODEL_TYPE_MBJ5010 || RM_MODEL == RM_MODEL_TYPE_FC_DR232W)
|
||||
#define VIDEO_SEEK_TYPE FAV::KeyFrameSeek //AccurateSeek
|
||||
#else
|
||||
#define VIDEO_SEEK_TYPE FAV::AccurateSeek // FAV::AccurateSeek, KeyFrameSeek
|
||||
#endif
|
||||
|
||||
#define INITIAL_VIDEO_POSITION 1 // msec
|
||||
#define PLAYER_MUTE_INTERVAL 10 // //const int kMuteInterval = 10;//100;
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || RM_MODEL == RM_MODEL_TYPE_MBJ5010 || RM_MODEL == RM_MODEL_TYPE_FC_DR232W)
|
||||
#define PLAYER_SYNC_INTERVAL 300 //const int kSyncInterval = 500;
|
||||
#else
|
||||
#define PLAYER_SYNC_INTERVAL 500 //const int kSyncInterval = 500;
|
||||
#endif
|
||||
#define PLAYER_VOLUME_INTERVAL 0.1 // const qreal kVolumeInterval = 0.1;
|
||||
#define PLAYER_END_LIMIT 0 // 영상 마지막에 깨진 패킷 등이 있거나, 실제 영상 길이가 짧은 경우가 있어
|
||||
// 종료 시간은 duration 보다 n 초 빠르게 처리함
|
||||
#define PLAYER_START_LIMIT 50 // 실제 0 POS 은 이동하기 어렵고 33 정도
|
||||
|
||||
class FMButton;
|
||||
class RMVideoItem;
|
||||
class QOpenGLContext;
|
||||
|
||||
#if (USE_DRAG_ZOOM)
|
||||
class FMDragZoomWidget;
|
||||
#endif // #if (USE_DRAG_ZOOM)
|
||||
class RMPlayerBase : public QObject
|
||||
{
|
||||
friend class RMFrameVideoBase;
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
explicit RMPlayerBase(QObject *parent = 0);
|
||||
#if (PLAY_CONTINUE_EVENT)
|
||||
virtual void stop(); // 종료 bUserStop == 사용자가 강제 종료
|
||||
#else
|
||||
void stop();
|
||||
#endif
|
||||
|
||||
// 전/후방 스텝모드 모두 종료
|
||||
virtual bool isSeekProcessing()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void endStepMode() {
|
||||
_stepMode = STEP_MODE_NONE;
|
||||
}
|
||||
|
||||
FAV::VideoRenderer* _rendererFBackup;
|
||||
FAV::VideoRenderer* _rendererRBackup;
|
||||
|
||||
// 화면에 업데이트 하지 않도록 처리
|
||||
void pauseRenderer()
|
||||
{
|
||||
_rendererFBackup = _playerF->renderer();
|
||||
_playerF->setRenderer(NULL);
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
_rendererRBackup = _playerR->renderer();
|
||||
_playerR->setRenderer(NULL);
|
||||
#endif
|
||||
|
||||
#if (TRI_CHANNEL)
|
||||
_rendererRBackup = _playerI->renderer();
|
||||
_playerI->setRenderer(NULL);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if (PENTA_CHANNEL)
|
||||
//! \brief 채널 모드 변경
|
||||
//! \param mode : 변경할 모드
|
||||
virtual void changeCHMode(RMApp::ChannelMode mode){Q_UNUSED(mode)}
|
||||
#endif // PENTA_CHANNEL
|
||||
|
||||
#if (TOGGLE_PLAYER)
|
||||
bool _tempSwapInResetPlayer; // PLAYER 초기화 중 임시로 SWAP 복구 처리되고 있는 경우
|
||||
#endif
|
||||
|
||||
// 전체화면 전환시 비율 조정
|
||||
|
||||
// void updateMainPlayerAspect(FAV::VideoRenderer::OutAspectRatioMode mode)
|
||||
// {
|
||||
// // TOGGLE 처리할 수 있어 전부 변경
|
||||
// _videoOutputF->setOutAspectRatioMode(mode);
|
||||
// _videoOutputR->setOutAspectRatioMode(mode);
|
||||
// }
|
||||
|
||||
public:
|
||||
QString lastError;
|
||||
FAV::VideoRenderer* _videoOutputF;
|
||||
#if ((!SINGLE_CH_VIEWER && !TOGGLE_PLAYER) || DUAL_VIEWER || PENTA_CHANNEL)
|
||||
FAV::VideoRenderer* _videoOutputR;
|
||||
#endif
|
||||
|
||||
#if (KEEP_ROI_ON_CAPTURE)
|
||||
int _roiX, _roiY, _roiW, _roiH; ///< 화면 CROP 영역 pixel
|
||||
int _roiX2, _roiY2, _roiW2, _roiH2; ///< 후방 화면 CROP 영역 pixel
|
||||
#endif // KEEP_ROI_ON_CAPTURE
|
||||
|
||||
#if (USE_DRAG_ZOOM)
|
||||
bool isROI()
|
||||
{
|
||||
return (_hROIFilter != NULL);
|
||||
}
|
||||
bool isROIRear()
|
||||
{
|
||||
return (_hROIFilterRear != NULL);
|
||||
}
|
||||
#endif // #if (USE_DRAG_ZOOM)
|
||||
|
||||
QSize frameSize();
|
||||
#if ((!SINGLE_CH_VIEWER && !TOGGLE_PLAYER) || DUAL_VIEWER || PENTA_CHANNEL)
|
||||
/**
|
||||
* @brief 2CH 프레임 크기
|
||||
* @return 없을 경우 0,0
|
||||
*/
|
||||
QSize rearFrameSize();
|
||||
#endif // SINGLE_CH_VIEWER
|
||||
|
||||
#if (SUPPORT_LIBRARY_MODE)
|
||||
/**
|
||||
* @brief 360(1:1) 영상 존재여부
|
||||
* @return 1,2CH 모두 확인하여 1:1 영상 존재할 경우 true
|
||||
*/
|
||||
bool isContain360Frame();
|
||||
#endif
|
||||
|
||||
#if (TOPDOWN_360_QUAD_MODE)
|
||||
FAV::VideoRenderer* _videoOutput2; // 우상단
|
||||
FAV::VideoRenderer* _videoOutput3; // 좌하단
|
||||
FAV::VideoRenderer* _videoOutput4; // 우하단
|
||||
void setQuadMode(bool quad);
|
||||
#endif // TOPDOWN_360_QUAD_MODE
|
||||
|
||||
#if (PAUSED_FRAME_REFRESH)
|
||||
// 정지 상태에서 프레임 필터 업데이트
|
||||
// 필터, MODE: 0=생성,1=해제,2=UPDATE
|
||||
void applyPausedFilter(FAV::VideoRenderer* out,FAV::LibAVFilterVideo* filter,int mode);
|
||||
#else // PAUSED_FRAME_UPDATE
|
||||
#if (USE_DRAG_ZOOM)
|
||||
void updatePausedScreen();
|
||||
#endif // USE_DRAG_ZOOM
|
||||
#endif // PAUSED_FRAME_UPDATE
|
||||
|
||||
#if (USE_DRAG_ZOOM)
|
||||
FMDragZoomWidget* _roiWidget;
|
||||
FMDragZoomWidget* _roiWidgetRear;
|
||||
FAV::LibAVFilterVideo* _hROIFilter;
|
||||
FAV::LibAVFilterVideo* _hROIFilterRear;
|
||||
void resetROIRear();
|
||||
void resetROI();
|
||||
|
||||
void setROIWidget(FMDragZoomWidget* widget);
|
||||
void setROIWidgetRear(FMDragZoomWidget* widget);
|
||||
void EnableROIWidget(bool enabled);
|
||||
#endif // #if (USE_DRAG_ZOOM)
|
||||
|
||||
protected:
|
||||
|
||||
FAV::VideoRendererId _renderID; // 비디오 랜더링 ID
|
||||
FAV::AVPlayer* _playerF; // 전방 (MULTI PLAYER 에서는 포인터만 할당)
|
||||
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
FAV::AVPlayer* _playerR; // 후방 (MULTI PLAYER 에서는 포인터만 할당)
|
||||
#endif
|
||||
|
||||
#if (TRI_CHANNEL)
|
||||
FAV::AVPlayer* _playerI; // 실내
|
||||
#endif
|
||||
|
||||
#if (PENTA_CHANNEL)
|
||||
FAV::AVPlayer* _players[5]; // 전후방 포함 (FRONT,REAR,LEFT,RIGHT,SUB)
|
||||
|
||||
//! \brief 이벤트 제거
|
||||
void _clearPlayerConnection();
|
||||
//! \brief 이벤트 연결, 정리
|
||||
void _updatePlayerConnection();
|
||||
#endif // PENTA_CHANNEL
|
||||
|
||||
|
||||
#if !(DO_NOT_USE_ZOOM)
|
||||
FAV::VideoRenderer* _videoOutputZOOMMain;
|
||||
#if !((SINGLE_CH_VIEWER || TOGGLE_PLAYER) && (!DUAL_VIEWER)) // DUAL 은 사용함
|
||||
FAV::VideoRenderer* _videoOutputZOOMSub;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 메인 클럭 (전/후방 동기화를 관리)
|
||||
int _timer_id;
|
||||
bool _sync_time;
|
||||
FAV::AVClock* _clock;
|
||||
QTimer* _sync_restart_timer;
|
||||
qint64 _lastPosition;
|
||||
|
||||
#if (TOGGLE_PLAYER)
|
||||
void resetPlayer(); // 전후방 변경되어 있을 경우 복구
|
||||
void restorePlayer();
|
||||
#endif
|
||||
|
||||
#if (START_FROM_FIRST_FRAME)
|
||||
qreal _startPTS;
|
||||
#endif
|
||||
|
||||
// Player
|
||||
VIDEO_MODE _videoMode;
|
||||
|
||||
#if (TRI_CHANNEL || TRI_CHANNEL2)
|
||||
bool _ch3mode; // 후방화면에 실내 영상 처리
|
||||
#endif
|
||||
|
||||
// SEEK
|
||||
// step 처리중 (다시 플레이시)
|
||||
#if (PLAY_SEEK_FILE_MOVE)
|
||||
|
||||
#if (USE_RM_KEYBOARD_EVENT)
|
||||
STEP_MODE _stepMode;
|
||||
bool _firstStep; // 파일 오픈 후 처음 step
|
||||
#endif
|
||||
#endif
|
||||
// 슬라이드 이동중에는 강제 PAUSE 하는 것이 좋겠는데...
|
||||
//bool _sliderMoving; // 슬라이드 이동중에는 다음파일로 이동하지 않도록
|
||||
|
||||
bool _stepping; // ?? 사용하지 않는것 같은데 제거
|
||||
|
||||
bool _refreshSeeking; // 화면갱신을 위해 SEEK
|
||||
qint64 _pausePosition; // 처리하지 않으면 전방으로 이동함
|
||||
|
||||
// CONTROL + EVENT
|
||||
QSlider* _slider; // "
|
||||
#if !(RM_MODEL == RM_MODEL_TYPE_TB4000)
|
||||
FMButton* _muteButton; // 참조용
|
||||
QSlider* _volumeSlider; // "
|
||||
#endif // #if !(RM_MODEL == RM_MODEL_TYPE_TB4000)
|
||||
|
||||
bool _forceStop; // control -> 사용자 중지
|
||||
bool _pausedState; // 현재 플레이어는 정지된 상태 (임시 저장)
|
||||
// media change 또는 position 종료시 naturla end 2회 발생할 수 있음
|
||||
bool _onNaturalEnd;
|
||||
bool _sliderMoving; // 슬라이더로 포지션 변경 (중)
|
||||
|
||||
qreal _speedValue;
|
||||
QLabel* _speedLabel;
|
||||
// 플레이 중 버퍼 일시 중지
|
||||
bool _muteIfRequired;
|
||||
|
||||
// Video Data
|
||||
RMVideoItem* _currentItem;
|
||||
// 후방 파일 존재 (전방 파일 처리후 사용해야함)
|
||||
// 전방에 후방 파일을 설정했을 경우 (1개 파일만 존재하는 경우) -> 로딩하지 않는다.
|
||||
QString _realRearFile();
|
||||
|
||||
|
||||
// 이벤트 처리하지 않는다
|
||||
QTimer* _blockTimer;
|
||||
bool _eventBlocking;
|
||||
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
FAV::AVPlayer* mainScreenPlayer() {
|
||||
return _isSwaped() ? _playerR : _playerF;
|
||||
}
|
||||
|
||||
FAV::AVPlayer* subScreenPlayer() {
|
||||
#if (TRI_CHANNEL)
|
||||
if(_isSwaped()) {
|
||||
return _playerF;
|
||||
}
|
||||
return _ch3mode ? _playerI : _playerR;
|
||||
#else // TRI_CHANNEL
|
||||
return _isSwaped() ? _playerF : _playerR;
|
||||
#endif // TRI_CHANNEL
|
||||
}
|
||||
|
||||
FAV::VideoRenderer* _currentVideoRenderer(FAV::AVPlayer* player)
|
||||
{
|
||||
#if (TOGGLE_PLAYER)
|
||||
Q_UNUSED(player)
|
||||
return _videoOutputF;
|
||||
#else // TOGGLE_PLAYER
|
||||
if(player == _playerF) {
|
||||
return _isSwaped() ? _videoOutputR : _videoOutputF;
|
||||
}
|
||||
else if (player == _playerR) {
|
||||
return _isSwaped() ? _videoOutputF : _videoOutputR;
|
||||
}
|
||||
return NULL;
|
||||
#endif // TOGGLE_PLAYER
|
||||
}
|
||||
|
||||
bool _swaped;
|
||||
//bool _rear_swaped;
|
||||
|
||||
// 전방, 후방 파일만 존재하는 경우 _playerF 에 rear 파일을 로딩해서 처리
|
||||
// SWAP 확인하려면 _swaped 및 _rear_swaped 모두 확인해야함
|
||||
bool _isSwaped()
|
||||
{
|
||||
// 둘다 swaped 인 경우 false
|
||||
// player swap 상태일 경우 _rear_swaped 인 경우는 swap 이 아님, player swap 상태가 아닌 경우 _rear_swap 상태일 경우 swap 상태임
|
||||
return _swaped;// ? !_rear_swaped : _rear_swaped;
|
||||
}
|
||||
#endif // SINGLE_CH_VIEWER
|
||||
|
||||
|
||||
// media change 상태에서 로딩하면 loaded 가 true 되어 있지 않음
|
||||
void playOrPause(bool forcePlay);
|
||||
void updateSpeed(qreal speed);
|
||||
// 슬라이드 이동 등에서 mute 처리함 (timer > 0 자동 릴리즈)
|
||||
void muteIfRequired(int timer);
|
||||
void unMuteIfMuted();
|
||||
bool _isMuted();
|
||||
|
||||
|
||||
|
||||
// 화면 CLEAR (BLACK)
|
||||
virtual void clearScreen(bool front);
|
||||
|
||||
// 통합관리 + 화면갱신을 위한 seek 구분
|
||||
virtual void seek(qint64 pos,bool refresh);
|
||||
|
||||
// 강제 pause / unpause
|
||||
void _pause(bool bPause, bool waitUntil = false, qint64 pos = -1);
|
||||
|
||||
// 전후방 seek 가 모두 종료 되었을 때 동기화 타이머를 다시 시작한다
|
||||
void restart_sync_timer();
|
||||
public:
|
||||
#if (TRI_CHANNEL || TRI_CHANNEL2)
|
||||
bool isIndoor() {
|
||||
return _ch3mode;
|
||||
}
|
||||
#endif // TRI_CHANNEL
|
||||
protected:
|
||||
int _playerStopCount; // 전후방 동시 종료시 모두 종료된 상황을 확인하기 위해 count 처리
|
||||
void _createVideoPlayers(); // 초기 플레이어 생성
|
||||
void _configureVideoRenderers(); // 파일 set 상태에 따라 renderer 설정
|
||||
void _setItemToPlayers(RMVideoItem* item); // 파일 set
|
||||
virtual void stopSeekUpdateTimer();
|
||||
|
||||
//virtual void _updateEQFilter(bool bForce = false){Q_UNUSED(bForce)}
|
||||
|
||||
signals:
|
||||
void playEvent(PLAY_EVENT event, RMVideoItem* item);
|
||||
void positionChanged(qint64 current,qint64 total); // 다른 컨트롤에 상태 변경 신호
|
||||
|
||||
|
||||
#if !(PLAY_CONTINUE_EVENT)
|
||||
void playerClearedDone(); // STOP/UNLOAD 완료시 처리
|
||||
#endif
|
||||
|
||||
protected slots:
|
||||
// 소리 정지 해제 (slide move)
|
||||
void onUnMuteIfRequired();
|
||||
void onSetVolume();
|
||||
void onMute();
|
||||
|
||||
void updateSlider(qint64 value); //
|
||||
void updateSlider(); //
|
||||
|
||||
void changeClockType();
|
||||
|
||||
#if (PENTA_CHANNEL)
|
||||
void onMediaChangedM(FAV::MediaStatus mediaStatus);
|
||||
#else // PENTA_CHANNEL
|
||||
void onMediaChangedF(FAV::MediaStatus mediaStatus);
|
||||
|
||||
#if !(FORCE_SINGLE_PLAYER)
|
||||
void onMediaChangedR(FAV::MediaStatus mediaStatus);
|
||||
#endif // #if (FORCE_SINGLE_PLAYER)
|
||||
#if (TRI_CHANNEL)
|
||||
void onMediaChangedI(FAV::MediaStatus mediaStatus);
|
||||
#endif
|
||||
#endif // PENTA_CHANNEL
|
||||
|
||||
void onPositionChanged(qint64 value);
|
||||
|
||||
|
||||
|
||||
#if (PENTA_CHANNEL)
|
||||
void onStoppedM();
|
||||
void onSeekFinishedM(qint64 pos);
|
||||
#else // PENTA_CHANNEL
|
||||
void onSeekFinishedF(qint64 pos);
|
||||
void onStoppedF();
|
||||
#if !(FORCE_SINGLE_PLAYER)
|
||||
void onStoppedR();
|
||||
void onSeekFinishedR(qint64 pos);
|
||||
#endif // FORCE_SINGLE_PLAYER
|
||||
#endif // PENTA_CHANNEL
|
||||
|
||||
void onFirstFrame(qreal pts);
|
||||
#if(PROFILE_BUILD)
|
||||
void onFirstFrameR(qreal pts);
|
||||
#endif //
|
||||
|
||||
#if (FIXED_FPS_DURATION && (!FORCE_BREAK_EOF || PREVENT_OVER_DURATION_RENDER))
|
||||
void onMediaEnded();
|
||||
#endif
|
||||
|
||||
void onRestoreRenderer();
|
||||
|
||||
void onTest();
|
||||
// void onTest2();
|
||||
// void onTest3();
|
||||
|
||||
public slots:
|
||||
void onPlayOrPause();
|
||||
|
||||
#if (PENTA_CHANNEL)
|
||||
virtual void onUpdateCHMode() {}
|
||||
#endif // PENTA_CHANNEL
|
||||
|
||||
// 파일리스트 클릭시 발생
|
||||
void onLoad(RMVideoItem* item);
|
||||
void onStartPause();
|
||||
#if (PENTA_CHANNEL)
|
||||
void onPlayerM(const FAV::AVError&);
|
||||
#else // PENTA_CHANNEL
|
||||
void onPlayerF(const FAV::AVError&);
|
||||
#if !(FORCE_SINGLE_PLAYER || SINGLE_CH_VIEWER || TOGGLE_PLAYER)
|
||||
void onPlayerR(const FAV::AVError&);
|
||||
#endif
|
||||
|
||||
#if (TRI_CHANNEL)
|
||||
void onPlayerI(const FAV::AVError&);
|
||||
#endif
|
||||
#endif // PENTA_CHANNEL
|
||||
|
||||
#if (PAUSED_FRAME_REFRESH)
|
||||
#if (USE_DRAG_ZOOM)
|
||||
void zoomPausedScreen(bool bFront, bool clear, bool onStartStop);
|
||||
#endif // #if (USE_DRAG_ZOOM)
|
||||
#endif // PAUSED_CROP_FRAME
|
||||
|
||||
#if (USE_DRAG_ZOOM)
|
||||
void onClearROI(bool bStartStop = false); // 지난 영역 제거
|
||||
void onClearROIRear(bool bStartStop = false); // 지난 영역 제거
|
||||
void onROISelected(double fx, double fy, double width, double height);
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
void onROISelectedRear(double fx, double fy, double width, double height);
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
#endif // #if (USE_DRAG_ZOOM)
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // RM_PLAY_CONTROL_H
|
||||
700
project/fm_viewer/core/rm_player_zoom.cpp
Normal file
700
project/fm_viewer/core/rm_player_zoom.cpp
Normal file
@@ -0,0 +1,700 @@
|
||||
#include "rm_player_zoom.h"
|
||||
|
||||
#if (USE_EQ_FILTER)
|
||||
#include "../ui/rm_slider.h"
|
||||
#endif
|
||||
#include "rm_utility.h"
|
||||
|
||||
#if (MODEL_360 || RM_MODEL_360 || ZOOM_SHADER || PAUSED_FRAME_REFRESH)
|
||||
#include "fav/OpenGLVideo.h"
|
||||
#include "fav/OpenGLRendererBase.h"
|
||||
#endif
|
||||
|
||||
#if (ZOOM_SHADER)
|
||||
RMPlayerZoom::RMPlayerZoom(QObject *parent) : RMPlayerBase(parent)
|
||||
{
|
||||
|
||||
}
|
||||
// ZOOM 모드 시작
|
||||
void RMPlayerZoom::startZoom(bool mainVideo)
|
||||
{
|
||||
|
||||
}
|
||||
// ZOOM 종료
|
||||
void RMPlayerZoom::stopZoom(bool mainVideo)
|
||||
{
|
||||
|
||||
}
|
||||
// ZOOM 위치 변경 + 프레임 크기가 확정되기 전에는 return false
|
||||
bool RMPlayerZoom::updateZoom(float x, float y, bool mainVideo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#else //ZOOM_SHADER
|
||||
RMPlayerZoom::RMPlayerZoom(QObject *parent) : RMPlayerBase(parent)
|
||||
{
|
||||
#if !(DO_NOT_USE_ZOOM)
|
||||
zoomTargetMain = NULL;
|
||||
#if !((SINGLE_CH_VIEWER || TOGGLE_PLAYER) && (!DUAL_VIEWER))
|
||||
zoomTargetSub = NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !(DO_NOT_USE_FLIP)
|
||||
#if !(USE_SHADER_FLIP)
|
||||
_hMainFilter = NULL;
|
||||
_hRearFilter = NULL;
|
||||
#endif //
|
||||
|
||||
_bHFlipMain = false;
|
||||
_bVFlipMain = false;
|
||||
_bHFlipSub = false;
|
||||
_bVFlipSub = false;
|
||||
#endif // ?USE_SHADER_FLIP
|
||||
|
||||
#if (USE_EQ_FILTER)
|
||||
_brightness = -1000; // -1 ~ 1
|
||||
_contrast = -1000; // 0.0 ~ 2.0
|
||||
_hEQFilterF = NULL;
|
||||
#if (!SINGLE_CH_VIEWER)
|
||||
_hEQFilterR = NULL;
|
||||
#endif // #if (!SINGLE_CH_VIEWER)
|
||||
#endif // USE_EQ_FILTER
|
||||
|
||||
#if (RESIZE_FILTER)
|
||||
_hResizeFilterF = NULL;
|
||||
_hResizeFilterR = NULL;
|
||||
#endif
|
||||
|
||||
}
|
||||
#if !(DO_NOT_USE_ZOOM)
|
||||
QWidget* RMPlayerZoom::startZoom(bool mainVideo)
|
||||
{
|
||||
//qInfo() << "START ZOOM";
|
||||
#if !(SINGLE_CH_VIEWER || TOGGLE_PLAYER)
|
||||
FAV::AVPlayer* player = mainVideo ? mainScreenPlayer() : subScreenPlayer();
|
||||
#else
|
||||
FAV::AVPlayer* player = _playerF;
|
||||
#endif
|
||||
if(player->videoOutputs().length() == 0)
|
||||
{
|
||||
qDebug() << "NO OUTPUTS" << __FUNCTION__;
|
||||
return NULL;
|
||||
}
|
||||
#if !(SINGLE_CH_VIEWER || TOGGLE_PLAYER)
|
||||
FAV::VideoRenderer* zt = NULL;
|
||||
if (mainVideo) {
|
||||
zt = zoomTargetMain = player->videoOutputs().first();
|
||||
}
|
||||
else {
|
||||
zt = zoomTargetSub = player->videoOutputs().first();
|
||||
}
|
||||
#else
|
||||
|
||||
#if (DUAL_VIEWER && MODEL_360)
|
||||
FAV::VideoRenderer* zt = NULL;
|
||||
if (mainVideo) {
|
||||
zt = zoomTargetMain = player->videoOutputs().first();
|
||||
}
|
||||
else {
|
||||
zt = zoomTargetSub = player->videoOutputs().at(1); // 1,2,3
|
||||
}
|
||||
#else
|
||||
FAV::VideoRenderer*zt = zoomTargetMain = player->videoOutputs().first();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
zt->setRegionOfInterest(QRectF(0.25,0.25,0.5,0.5));
|
||||
|
||||
// QSize vSize = zt->videoFrameSize() / 2;
|
||||
// zt->setRegionOfInterest(QRect(vSize.width()/2,vSize.height()/2,vSize.width(),vSize.height()));
|
||||
|
||||
FAV::VideoRenderer* vr = NULL;
|
||||
if (mainVideo) {
|
||||
if(_videoOutputZOOMMain == NULL)
|
||||
{
|
||||
// ZOOM Rendered
|
||||
_videoOutputZOOMMain = FAV::VideoRenderer::create(_renderID);
|
||||
// 비율을 고정할 경우 setOutAspectRatioMode(FAV::VideoRenderer::CustomAspectRation) +
|
||||
// setOutAspectRatio(16.0 / 9.0); 사용
|
||||
_videoOutputZOOMMain->setOutAspectRatioMode(FAV::VideoRenderer::CustomAspectRation);
|
||||
_videoOutputZOOMMain->setOutAspectRatio(16.0 / 9.0);
|
||||
vr = _videoOutputZOOMMain;
|
||||
}
|
||||
}
|
||||
#if !((SINGLE_CH_VIEWER || TOGGLE_PLAYER) && (!DUAL_VIEWER))
|
||||
else {
|
||||
if(_videoOutputZOOMSub == NULL)
|
||||
{
|
||||
// ZOOM Rendered
|
||||
_videoOutputZOOMSub = FAV::VideoRenderer::create(_renderID);
|
||||
_videoOutputZOOMSub->setOutAspectRatioMode(FAV::VideoRenderer::CustomAspectRation);
|
||||
_videoOutputZOOMSub->setOutAspectRatio(16.0 / 9.0);
|
||||
vr = _videoOutputZOOMSub;
|
||||
}
|
||||
}
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
|
||||
player->addVideoRenderer(vr);
|
||||
|
||||
if(player->isPaused() ) {
|
||||
player->seek(MIN(player->position(),player->duration()));
|
||||
}
|
||||
|
||||
#if (DUAL_VIEWER && MODEL_360) // 360 ONLY
|
||||
vr->opengl()->setDualMode(1); // 2D
|
||||
vr->opengl()->setDualFront(mainVideo); // 전후방
|
||||
|
||||
#if (USE_ZOOM_WH_RATIO)
|
||||
// 해상도 높이가 1/2 로 다시 처리 해야함
|
||||
QSize r = _playerF->videoResolution();
|
||||
float wr = ((double)r.width()) / ((double)r.height() / 2.0) ;
|
||||
vr->setOutAspectRatioMode(FAV::VideoRenderer::CustomAspectRation);
|
||||
vr->setOutAspectRatio(wr); // 16.0/9.0
|
||||
#endif // USE_ZOOM_WH_RATIO
|
||||
#endif
|
||||
|
||||
#if !((SINGLE_CH_VIEWER || TOGGLE_PLAYER) && (!DUAL_VIEWER))
|
||||
return mainVideo ? _videoOutputZOOMMain->widget() : _videoOutputZOOMSub->widget();
|
||||
#else
|
||||
return _videoOutputZOOMMain->widget();
|
||||
#endif
|
||||
}
|
||||
void RMPlayerZoom::stopZoom(bool mainVideo)
|
||||
{
|
||||
//qInfo() << "STOP ZOOM";
|
||||
#if !((SINGLE_CH_VIEWER || TOGGLE_PLAYER) && (!DUAL_VIEWER))
|
||||
FAV::VideoRenderer* zt = mainVideo ? zoomTargetMain : zoomTargetSub;
|
||||
#else
|
||||
FAV::VideoRenderer* zt = zoomTargetMain;
|
||||
#endif
|
||||
if(zt == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 복구 처리 해야함 + 다음파일 재생시 비디오 크기에 따라 다시 조절 해야함
|
||||
zt->setRegionOfInterest(QRectF(0,0,0,0));
|
||||
|
||||
if(mainVideo) {
|
||||
#if !(SINGLE_CH_VIEWER || TOGGLE_PLAYER)
|
||||
mainScreenPlayer()->removeVideoRenderer(_videoOutputZOOMMain);
|
||||
#else
|
||||
_playerF->removeVideoRenderer(_videoOutputZOOMMain);
|
||||
#endif
|
||||
delete _videoOutputZOOMMain;
|
||||
_videoOutputZOOMMain = NULL;
|
||||
zoomTargetMain = NULL;
|
||||
}
|
||||
#if !((SINGLE_CH_VIEWER || TOGGLE_PLAYER) && (!DUAL_VIEWER))
|
||||
else
|
||||
{
|
||||
#if (DUAL_VIEWER)
|
||||
_playerF->removeVideoRenderer(_videoOutputZOOMSub);
|
||||
#else
|
||||
subScreenPlayer()->removeVideoRenderer(_videoOutputZOOMSub);
|
||||
#endif
|
||||
delete _videoOutputZOOMSub;
|
||||
_videoOutputZOOMSub = NULL;
|
||||
zoomTargetSub = NULL;
|
||||
}
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
}
|
||||
|
||||
#if (USE_ZOOM_WH_RATIO)
|
||||
void RMPlayerZoom::updateZoomAspectRatio()
|
||||
{
|
||||
// 해상도 높이가 1/2 로 다시 처리 해야함
|
||||
QSize r = _playerF->videoResolution();
|
||||
float wr = ((double)r.width()) / ((double)r.height() / 2.0) ;
|
||||
if(_videoOutputZOOMMain != NULL) {
|
||||
_videoOutputZOOMMain->setOutAspectRatioMode(FAV::VideoRenderer::CustomAspectRation);
|
||||
_videoOutputZOOMMain->setOutAspectRatio(wr); // 16.0/9.0
|
||||
}
|
||||
if(_videoOutputZOOMSub != NULL) {
|
||||
_videoOutputZOOMSub->setOutAspectRatioMode(FAV::VideoRenderer::CustomAspectRation);
|
||||
_videoOutputZOOMSub->setOutAspectRatio(wr); // 16.0/9.0
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool RMPlayerZoom::updateZoom(float x, float y, bool mainVideo)
|
||||
{
|
||||
#if !((SINGLE_CH_VIEWER || TOGGLE_PLAYER) && (!DUAL_VIEWER))
|
||||
FAV::VideoRenderer* zt = mainVideo ? zoomTargetMain : zoomTargetSub;
|
||||
#else
|
||||
FAV::VideoRenderer* zt = zoomTargetMain;
|
||||
#endif
|
||||
if(zt != NULL)
|
||||
{
|
||||
// y 를 0.001 로 처리하면 깨지는 증상이 발생함
|
||||
x = ((int)(x * 100.0)) / 100.0;
|
||||
y = ((int)(y * 100.0)) / 100.0;
|
||||
|
||||
//x = 0.152256;
|
||||
// Ratio(0~1.0) 로 변경하면 해상도 변경시 문제 없음
|
||||
zt->setRegionOfInterest(QRectF(x,y,0.5,0.5));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void RMPlayerZoom::clearScreen(bool front)
|
||||
{
|
||||
#if !((SINGLE_CH_VIEWER || TOGGLE_PLAYER) && (!DUAL_VIEWER))
|
||||
|
||||
#if (DUAL_VIEWER)
|
||||
FAV::VideoRenderer* r = front ? _videoOutputF : _videoOutputR;
|
||||
#else
|
||||
FAV::AVPlayer* p = front ? _playerF : _playerR;
|
||||
FAV::VideoRenderer* r = _currentVideoRenderer(p);
|
||||
#endif
|
||||
if(r != NULL) {
|
||||
r->receive(FAV::VideoFrame());
|
||||
}
|
||||
#if !(DO_NOT_USE_ZOOM)
|
||||
r = front ? _videoOutputZOOMMain : _videoOutputZOOMSub;
|
||||
if(r != NULL) {
|
||||
r->receive(FAV::VideoFrame());
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if(_videoOutputF != NULL) {
|
||||
_videoOutputF->receive(FAV::VideoFrame());
|
||||
}
|
||||
#if !(DO_NOT_USE_ZOOM)
|
||||
if(_videoOutputZOOMMain != NULL) {
|
||||
_videoOutputZOOMMain->receive(FAV::VideoFrame());
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
|
||||
//#if (MODEL_BBVIEWER)
|
||||
// emit playEvent(front ? PLAY_DID_CLEAR_SCREEN_F : PLAY_DID_CLEAR_SCREEN_R, NULL);
|
||||
//#endif
|
||||
}
|
||||
|
||||
#if (RESIZE_FILTER && !DO_NOT_USE_ZOOM)
|
||||
void RMPlayerZoom::resizeFilter(QSize size, bool bMain)
|
||||
{
|
||||
qInfo() << __FUNCTION__ << size;
|
||||
|
||||
if(size.width() < 0) {
|
||||
|
||||
if(_hResizeFilterF != NULL) {
|
||||
_hResizeFilterF->uninstall();
|
||||
delete _hResizeFilterF;
|
||||
_hResizeFilterF = NULL;
|
||||
}
|
||||
if(_hResizeFilterR != NULL) {
|
||||
_hResizeFilterR->uninstall();
|
||||
delete _hResizeFilterR;
|
||||
_hResizeFilterR = NULL;
|
||||
}
|
||||
updatePausedScreenFrontOnly();
|
||||
updatePausedScreenRearOnly();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
FAV::LibAVFilterVideo* f = bMain ? _hResizeFilterF : _hResizeFilterR;
|
||||
if(f != NULL)
|
||||
{
|
||||
f->uninstall();
|
||||
delete f;
|
||||
f = NULL;
|
||||
}
|
||||
|
||||
//size *= 2.0;
|
||||
|
||||
//bilinear,, format=pix_fmts=yuv420p,
|
||||
QString filterString = QString().sprintf("scale=%d:%d:force_original_aspect_ratio=decrease:flags=lanczos",size.width(),size.height());
|
||||
qInfo() << filterString;
|
||||
// QString filterString = QString().sprintf("scale=%d:%d -sws_flags bilinear",size.width(),size.height());
|
||||
//QString filterString = QString().sprintf("format=pix_fmts=rgb24,scale=%d:%d",size.width(),size.height());
|
||||
if(bMain == true)
|
||||
{
|
||||
f = new FAV::LibAVFilterVideo(_playerF);
|
||||
f->installTo(_playerF);
|
||||
f->setOptions(filterString);
|
||||
_hResizeFilterF = f;
|
||||
}
|
||||
else
|
||||
{
|
||||
f = new FAV::LibAVFilterVideo(_playerR);
|
||||
f->installTo(_playerR);
|
||||
f->setOptions(filterString);
|
||||
_hResizeFilterR = f;
|
||||
}
|
||||
updatePausedScreenFrontOnly();
|
||||
updatePausedScreenRearOnly();
|
||||
|
||||
}
|
||||
#endif //RESIZE_FILTER
|
||||
|
||||
|
||||
#if !(DO_NOT_USE_FLIP)
|
||||
#if (USE_SHADER_FLIP)
|
||||
void RMPlayerZoom::updateFlip(bool bMain)
|
||||
{
|
||||
if(bMain) {
|
||||
FAV::VideoRenderer* vr = _currentVideoRenderer(_playerF);
|
||||
vr->opengl()->setVFlip(_bVFlipMain);
|
||||
vr->opengl()->setHFlip(_bHFlipMain);
|
||||
vr->widget()->update();
|
||||
} else {
|
||||
FAV::VideoRenderer* vr = _currentVideoRenderer(_playerR);
|
||||
vr->opengl()->setVFlip(_bVFlipSub);
|
||||
vr->opengl()->setHFlip(_bHFlipSub);
|
||||
vr->widget()->update();
|
||||
}
|
||||
}
|
||||
#else // USE_SHADER_FLIP
|
||||
void RMPlayerZoom::updateFlip(bool bMain)
|
||||
{
|
||||
#if (PENTA_CHANNEL)
|
||||
if(_hMainFilter != NULL)
|
||||
{
|
||||
_hMainFilter->uninstall();
|
||||
delete _hMainFilter;
|
||||
_hMainFilter = NULL;
|
||||
}
|
||||
if(_hRearFilter != NULL)
|
||||
{
|
||||
_hRearFilter->uninstall();
|
||||
delete _hRearFilter;
|
||||
_hRearFilter = NULL;
|
||||
}
|
||||
QString filterString = "format=pix_fmts=rgb24";
|
||||
if(_bHFlipMain || _bVFlipMain )
|
||||
{
|
||||
_hMainFilter = new FAV::LibAVFilterVideo(_playerF);
|
||||
_hMainFilter->installTo(_playerF);
|
||||
if(_bHFlipMain) {
|
||||
filterString += ",hflip";
|
||||
}
|
||||
if(_bVFlipMain) {
|
||||
filterString += ",vflip";
|
||||
}
|
||||
_hMainFilter->setOptions(filterString);
|
||||
}
|
||||
updatePausedScreenFrontOnly();
|
||||
|
||||
if(_playerR != NULL) {
|
||||
if(_bHFlipMain || _bVFlipMain ) { // PENTA 는 SUB가 없음
|
||||
_hRearFilter = new FAV::LibAVFilterVideo(_playerR);
|
||||
_hRearFilter->installTo(_playerR);
|
||||
if(_bHFlipSub) {
|
||||
filterString += ",hflip";
|
||||
}
|
||||
if(_bVFlipSub) {
|
||||
filterString += ",vflip";
|
||||
}
|
||||
_hRearFilter->setOptions(filterString);
|
||||
}
|
||||
updatePausedScreenRearOnly();
|
||||
}
|
||||
#else // PENTA_CHANNEL
|
||||
FAV::LibAVFilterVideo* f = bMain ? _hMainFilter : _hRearFilter;
|
||||
if(f != NULL)
|
||||
{
|
||||
f->uninstall();
|
||||
delete f;
|
||||
f = NULL;
|
||||
}
|
||||
QString filterString = "format=pix_fmts=rgb24";
|
||||
if(bMain == true)
|
||||
{
|
||||
if(_bHFlipMain == false && _bVFlipMain == false)
|
||||
{
|
||||
_hMainFilter = NULL;
|
||||
updatePausedScreenFrontOnly();
|
||||
return;
|
||||
}
|
||||
f = new FAV::LibAVFilterVideo(_playerF);
|
||||
f->installTo(_playerF);
|
||||
|
||||
if(_bHFlipMain) {
|
||||
filterString += ",hflip";
|
||||
}
|
||||
if(_bVFlipMain) {
|
||||
filterString += ",vflip";
|
||||
}
|
||||
|
||||
f->setOptions(filterString);
|
||||
_hMainFilter = f;
|
||||
|
||||
updatePausedScreenFrontOnly();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(_bHFlipSub == false && _bVFlipSub == false)
|
||||
{
|
||||
_hRearFilter = NULL;
|
||||
#if (TOGGLE_PLAYER)
|
||||
updatePausedScreenFrontOnly();
|
||||
#else // TOGGLE_PLAYER
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
updatePausedScreenRearOnly();
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
#endif // TOGGLE_PLAYER
|
||||
return;
|
||||
}
|
||||
#if (TOGGLE_PLAYER)
|
||||
f = new FAV::LibAVFilterVideo(_playerF);
|
||||
f->installTo(_playerF);
|
||||
#else
|
||||
#if (TRI_CHANNEL)
|
||||
f = new FAV::LibAVFilterVideo(isIndoor() ? _playerI : _playerR);
|
||||
f->installTo(isIndoor() ? _playerI : _playerR);
|
||||
#else // TRI_CHANNEL
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
f = new FAV::LibAVFilterVideo(_playerR);
|
||||
f->installTo(_playerR);
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
#endif // TRI_CHANNEL
|
||||
#endif
|
||||
if(_bHFlipSub) {
|
||||
filterString += ",hflip";
|
||||
}
|
||||
if(_bVFlipSub) {
|
||||
filterString += ",vflip";
|
||||
}
|
||||
f->setOptions(filterString);
|
||||
_hRearFilter = f;
|
||||
#if (TOGGLE_PLAYER)
|
||||
updatePausedScreenFrontOnly();
|
||||
#else
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
updatePausedScreenRearOnly();
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif // PENTA_CHANNEL
|
||||
}
|
||||
#endif // #if !(USE_SHADER_FLIP)
|
||||
void RMPlayerZoom::onToggleHFlipMain()
|
||||
{
|
||||
bool main = true;
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
if(_swaped)
|
||||
{
|
||||
_bHFlipSub =!_bHFlipSub;
|
||||
main = false;
|
||||
}
|
||||
else
|
||||
#endif // SINGLE_CH_VIEWER
|
||||
{
|
||||
_bHFlipMain =!_bHFlipMain;
|
||||
main = true;
|
||||
}
|
||||
updateFlip(main);
|
||||
}
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
void RMPlayerZoom::onToggleHFlipSub()
|
||||
{
|
||||
bool main;
|
||||
if(_swaped)
|
||||
{
|
||||
_bHFlipMain =!_bHFlipMain;
|
||||
main = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bHFlipSub =!_bHFlipSub;
|
||||
main = false;
|
||||
}
|
||||
updateFlip(main);
|
||||
}
|
||||
void RMPlayerZoom::onToggleVFlipSub()
|
||||
{
|
||||
bool main;
|
||||
if(_swaped)
|
||||
{
|
||||
main = true;
|
||||
_bVFlipMain =!_bVFlipMain;
|
||||
}
|
||||
else
|
||||
{
|
||||
main = false;
|
||||
_bVFlipSub =!_bVFlipSub;
|
||||
}
|
||||
updateFlip(main);
|
||||
}
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
|
||||
void RMPlayerZoom::onToggleVFlipMain()
|
||||
{
|
||||
bool main;
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
if(_swaped)
|
||||
{
|
||||
main = false;
|
||||
_bVFlipSub =!_bVFlipSub;
|
||||
}
|
||||
else
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
{
|
||||
main = true;
|
||||
_bVFlipMain =!_bVFlipMain;
|
||||
}
|
||||
updateFlip(main);
|
||||
}
|
||||
|
||||
#endif // #if !(DO_NOT_USE_FLIP)
|
||||
|
||||
|
||||
|
||||
#if (USE_EQ_FILTER)
|
||||
|
||||
// 0~100 = -0.5 ~ 0.5
|
||||
void RMPlayerZoom::onSetBrightness()
|
||||
{
|
||||
RMSlider* slider = qobject_cast<RMSlider*>(sender());
|
||||
// 0~100 = -0.9 ~ 0.9
|
||||
_brightness = RMUtility::range(0.0f,100.0f,-0.3f,0.3f,(float)slider->value());
|
||||
//_brightness = RMUtility::range(0.0f,100.0f,-0.5f,0.5f,(float)slider->value());
|
||||
//qInfo() << "B:" << slider->value() << _brightness;
|
||||
_updateEQFilter();
|
||||
}
|
||||
|
||||
// 0~100 = 0.1 ~ 1.9
|
||||
void RMPlayerZoom::onSetContrast()
|
||||
{
|
||||
RMSlider* slider = qobject_cast<RMSlider*>(sender());
|
||||
_contrast = RMUtility::range(0.0f,100.0f,0.6f,1.4f,(float)slider->value());
|
||||
//_contrast = RMUtility::range(0.0f,100.0f,0.1f,1.9f,(float)slider->value());
|
||||
//qInfo() << "C:" << slider->value() << _contrast;
|
||||
_updateEQFilter();
|
||||
}
|
||||
void RMPlayerZoom::_updateEQFilter(bool bForce)
|
||||
{
|
||||
if(_brightness < 0.05f && _brightness > -0.05f)
|
||||
{
|
||||
_brightness = -1000.0f;
|
||||
}
|
||||
if(_contrast > 0.95f && _contrast < 1.05f)
|
||||
{
|
||||
_contrast = -1000.0f;
|
||||
}
|
||||
|
||||
bool bExist = _brightness > -100.0f || _contrast > -100.0f;
|
||||
|
||||
if(bExist == false)
|
||||
{
|
||||
if(_hEQFilterF != NULL)
|
||||
{
|
||||
_hEQFilterF->uninstall();
|
||||
delete _hEQFilterF;
|
||||
_hEQFilterF = NULL;
|
||||
}
|
||||
#if (!SINGLE_CH_VIEWER)
|
||||
if(_hEQFilterR != NULL)
|
||||
{
|
||||
_hEQFilterR->uninstall();
|
||||
delete _hEQFilterR;
|
||||
_hEQFilterR = NULL;
|
||||
}
|
||||
#endif // #if (!SINGLE_CH_VIEWER)
|
||||
}
|
||||
else
|
||||
{
|
||||
// 강제 삭제
|
||||
if(bForce) {
|
||||
if(_hEQFilterF != NULL)
|
||||
{
|
||||
_hEQFilterF->uninstall();
|
||||
delete _hEQFilterF;
|
||||
_hEQFilterF = NULL;
|
||||
}
|
||||
#if (!SINGLE_CH_VIEWER)
|
||||
if(_hEQFilterR != NULL)
|
||||
{
|
||||
_hEQFilterR->uninstall();
|
||||
delete _hEQFilterR;
|
||||
_hEQFilterR = NULL;
|
||||
}
|
||||
#endif // #if (!SINGLE_CH_VIEWER)
|
||||
}
|
||||
|
||||
|
||||
QString filterString = "format=pix_fmts=rgb24,eq=";
|
||||
if(_brightness > -100)
|
||||
{
|
||||
filterString += "brightness=";
|
||||
filterString += QString().sprintf("%.3f",_brightness);
|
||||
|
||||
if(_contrast > -100)
|
||||
{
|
||||
filterString += ":";
|
||||
}
|
||||
}
|
||||
if(_contrast > -100)
|
||||
{
|
||||
filterString += "contrast=";
|
||||
filterString += QString().sprintf("%.3f",_contrast);
|
||||
}
|
||||
//qInfo() << "filter:" << filterString;
|
||||
|
||||
if(_hEQFilterF == NULL)
|
||||
{
|
||||
_hEQFilterF = new FAV::LibAVFilterVideo(this);
|
||||
_hEQFilterF->installTo(_playerF);
|
||||
}
|
||||
#if (!SINGLE_CH_VIEWER)
|
||||
if(_hEQFilterR == NULL && _playerR != NULL)
|
||||
{
|
||||
_hEQFilterR = new FAV::LibAVFilterVideo(this);
|
||||
_hEQFilterR->installTo(_playerR);
|
||||
}
|
||||
#endif // #if (!SINGLE_CH_VIEWER)
|
||||
_hEQFilterF->setOptions(filterString);
|
||||
#if (!SINGLE_CH_VIEWER)
|
||||
if(_hEQFilterR != NULL) {
|
||||
_hEQFilterR->setOptions(filterString);
|
||||
}
|
||||
#endif // #if (!SINGLE_CH_VIEWER)
|
||||
|
||||
}
|
||||
updatePausedScreenFrontOnly();
|
||||
#if (!SINGLE_CH_VIEWER && !(TOGGLE_PLAYER))
|
||||
updatePausedScreenRearOnly();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#if (!(SINGLE_CH_VIEWER || TOGGLE_PLAYER) || PENTA_CHANNEL)
|
||||
void RMPlayerZoom::updatePausedScreenRearOnly()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
void RMPlayerZoom::updatePausedScreenFrontOnly()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#if (RM_MODEL_360)
|
||||
void RMPlayerZoom::onClearROI()
|
||||
{
|
||||
#if (USE_DRAG_ZOOM)
|
||||
RMPlayerBase::onClearROI();
|
||||
#endif // USE_DRAG_ZOOM
|
||||
|
||||
//FAV::VideoRenderer* vr = playerF()->renderer();
|
||||
_videoOutputF->opengl()->clearROI();
|
||||
_videoOutputF->widget()->update();
|
||||
if(_videoOutputF->opengl()->mode() == 0) {
|
||||
_videoOutputF->setOutAspectRatioMode(FAV::VideoRenderer::VideoAspectRatio);
|
||||
}
|
||||
#if (REAR_VIEW_ZOOM)
|
||||
_videoOutputR->opengl()->clearROI();
|
||||
_videoOutputR->widget()->update();
|
||||
if(_videoOutputR->opengl()->mode() == 0) {
|
||||
_videoOutputR->setOutAspectRatioMode(FAV::VideoRenderer::VideoAspectRatio);
|
||||
}
|
||||
#endif // REAR_VIEW_ZOOM
|
||||
}
|
||||
#endif // RM_MODEL_360
|
||||
#endif // //ZOOM_SHADER
|
||||
126
project/fm_viewer/core/rm_player_zoom.h
Normal file
126
project/fm_viewer/core/rm_player_zoom.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#ifndef RM_PLAYER_ZOOM_H
|
||||
#define RM_PLAYER_ZOOM_H
|
||||
|
||||
#include "rm_player_base.h"
|
||||
|
||||
#if (ZOOM_SHADER)
|
||||
class RMPlayerZoom : public RMPlayerBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RMPlayerZoom(QObject *parent = nullptr);
|
||||
|
||||
// ZOOM 모드 시작
|
||||
void startZoom(bool mainVideo);
|
||||
|
||||
// ZOOM 종료
|
||||
void stopZoom(bool mainVideo);
|
||||
|
||||
// ZOOM 위치 변경 + 프레임 크기가 확정되기 전에는 return false
|
||||
bool updateZoom(float x, float y, bool mainVideo);
|
||||
};
|
||||
#else // ZOOM_SHADER
|
||||
class RMPlayerZoom : public RMPlayerBase
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
#if !(DO_NOT_USE_FLIP)
|
||||
bool _bHFlipMain;
|
||||
bool _bVFlipMain;
|
||||
bool _bHFlipSub;
|
||||
bool _bVFlipSub;
|
||||
#endif
|
||||
|
||||
#if (USE_EQ_FILTER)
|
||||
float _brightness;
|
||||
float _contrast;
|
||||
|
||||
FAV::LibAVFilterVideo* _hEQFilterF;
|
||||
#if (!SINGLE_CH_VIEWER)
|
||||
FAV::LibAVFilterVideo* _hEQFilterR;
|
||||
#endif // SINGLE_CH_VIEWER
|
||||
protected:
|
||||
void _updateEQFilter(bool bForce = false);
|
||||
private:
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if (RESIZE_FILTER)
|
||||
FAV::LibAVFilterVideo* _hResizeFilterF;
|
||||
FAV::LibAVFilterVideo* _hResizeFilterR;
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit RMPlayerZoom(QObject *parent = nullptr);
|
||||
#if !(DO_NOT_USE_ZOOM)
|
||||
|
||||
void resizeFilter(QSize size, bool mainVideo);
|
||||
|
||||
// ZOOM 모드 시작
|
||||
QWidget* startZoom(bool mainVideo);
|
||||
|
||||
// ZOOM 종료
|
||||
void stopZoom(bool mainVideo);
|
||||
|
||||
// ZOOM 위치 변경 + 프레임 크기가 확정되기 전에는 return false
|
||||
bool updateZoom(float x, float y, bool mainVideo);
|
||||
|
||||
#if (USE_ZOOM_WH_RATIO)
|
||||
void updateZoomAspectRatio();
|
||||
#endif
|
||||
|
||||
// ZOOM TARGET 저장
|
||||
FAV::VideoRenderer* zoomTargetMain;
|
||||
#if !((SINGLE_CH_VIEWER || TOGGLE_PLAYER) && (!DUAL_VIEWER))
|
||||
FAV::VideoRenderer* zoomTargetSub;
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
#endif // #if !(DO_NOT_USE_ZOOM)
|
||||
|
||||
#if !(DO_NOT_USE_FLIP)
|
||||
#if !(USE_SHADER_FLIP)
|
||||
FAV::LibAVFilterVideo* _hMainFilter;
|
||||
FAV::LibAVFilterVideo* _hRearFilter;
|
||||
#endif // !USE_SHADER_FLIP
|
||||
void updateFlip(bool bMain);
|
||||
#endif // USE_SHADER_FLIP
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
void clearScreen(bool front) override;
|
||||
//void _updateEQFilter() override;
|
||||
|
||||
private:
|
||||
#if (!(SINGLE_CH_VIEWER || TOGGLE_PLAYER) || PENTA_CHANNEL)
|
||||
virtual void updatePausedScreenRearOnly();
|
||||
#endif
|
||||
virtual void updatePausedScreenFrontOnly();
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
#if !(DO_NOT_USE_FLIP)
|
||||
void onToggleHFlipMain();
|
||||
void onToggleVFlipMain();
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
void onToggleHFlipSub();
|
||||
void onToggleVFlipSub();
|
||||
#endif // #if !(SINGLE_CH_VIEWER)
|
||||
#endif
|
||||
|
||||
#if (RM_MODEL_360)
|
||||
void onClearROI();
|
||||
#endif
|
||||
|
||||
#if (USE_EQ_FILTER)
|
||||
// 0~100 = -0.9 ~ 0.9
|
||||
void onSetBrightness();
|
||||
|
||||
// 0~100 = 0.1 ~ 1.9
|
||||
void onSetContrast();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // ZOOM_SHADER
|
||||
#endif // RM_PLAYER_ZOOM_H
|
||||
340
project/fm_viewer/core/rm_usb.cpp
Normal file
340
project/fm_viewer/core/rm_usb.cpp
Normal file
@@ -0,0 +1,340 @@
|
||||
#include "rm_usb.h"
|
||||
#include <Windows.h>
|
||||
#include <dbt.h>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
#include "../cfg/rm_settings_cfg_emt_kr.h"
|
||||
#endif
|
||||
|
||||
#if (DETECT_SETTING_USB_EJECT || DETECT_USB_CHANGE)
|
||||
|
||||
rm_usb::rm_usb(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
_hDevNotify = NULL;
|
||||
_insertringDrive = 0;
|
||||
_removingDrive = 0;
|
||||
_openDrive = "";
|
||||
_irTimer = NULL;
|
||||
}
|
||||
rm_usb::~rm_usb()
|
||||
{
|
||||
if(_hDevNotify != NULL) {
|
||||
::UnregisterDeviceNotification(_hDevNotify);
|
||||
}
|
||||
_cancelIRTimer();
|
||||
}
|
||||
|
||||
// 항상 대문자로 리턴됨
|
||||
char rm_usb::_firstDriveFromMask( uint unitmask )
|
||||
{
|
||||
char i;
|
||||
|
||||
for (i = 0; i < 26; ++i)
|
||||
{
|
||||
if (unitmask & 0x1)
|
||||
break;
|
||||
unitmask = unitmask >> 1;
|
||||
}
|
||||
return( i + 'A' );
|
||||
}
|
||||
void rm_usb::_startIRTimer()
|
||||
{
|
||||
_cancelIRTimer();
|
||||
_irTimer = new QTimer(this);
|
||||
_irTimer->setSingleShot(true);
|
||||
_irTimer->setInterval(1000);
|
||||
connect(_irTimer,SIGNAL(timeout()),SLOT(onClearIR()));
|
||||
_irTimer->start();
|
||||
}
|
||||
void rm_usb::_cancelIRTimer()
|
||||
{
|
||||
if(_irTimer != NULL) {
|
||||
_irTimer->stop();
|
||||
delete _irTimer;
|
||||
_irTimer = NULL;
|
||||
}
|
||||
}
|
||||
void rm_usb::onClearIR()
|
||||
{
|
||||
_insertringDrive = 0;
|
||||
_removingDrive = 0;
|
||||
}
|
||||
|
||||
bool rm_usb::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
|
||||
{
|
||||
Q_UNUSED(eventType);
|
||||
Q_UNUSED(result);
|
||||
#ifdef Q_OS_WIN32
|
||||
MSG *msg = (MSG *)message;
|
||||
if( WM_DEVICECHANGE == msg->message && DBT_DEVICEARRIVAL == msg->wParam )
|
||||
{
|
||||
DEV_BROADCAST_HDR* dev = (DEV_BROADCAST_HDR*)msg->lParam;
|
||||
if (dev->dbch_devicetype == DBT_DEVTYP_VOLUME)
|
||||
{
|
||||
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)dev;
|
||||
char driver = _firstDriveFromMask(lpdbv->dbcv_unitmask);
|
||||
|
||||
// 다중 호출 방지 -> 처리 끝나면 초기화 해야 함
|
||||
if (_insertringDrive != driver)
|
||||
{
|
||||
_insertringDrive = driver;
|
||||
QString driver_letter(driver);
|
||||
driver_letter += ":";
|
||||
// qInfo() << "USB arrival detected:" << driver;
|
||||
*result = 1;
|
||||
emit usbChanged(true,driver_letter);
|
||||
_startIRTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( WM_DEVICECHANGE == msg->message && DBT_DEVICEREMOVECOMPLETE == msg->wParam )
|
||||
{
|
||||
DEV_BROADCAST_HDR* dev = (DEV_BROADCAST_HDR*)msg->lParam;
|
||||
if (dev->dbch_devicetype == DBT_DEVTYP_VOLUME)
|
||||
{
|
||||
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)dev;
|
||||
char driver = _firstDriveFromMask(lpdbv->dbcv_unitmask);
|
||||
if (_removingDrive != driver)
|
||||
{
|
||||
_removingDrive = driver;
|
||||
QString driver_letter(driver);
|
||||
driver_letter += ":";
|
||||
// qInfo() << "USB departure detected:" << " driver:" << driver;
|
||||
*result = 1;
|
||||
emit usbChanged(false,driver_letter);
|
||||
_startIRTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // Q_OS_WIN32
|
||||
// Return false so that the event is propagated
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void rm_usb::registerEvent(QWidget *window)
|
||||
{
|
||||
if( window != nullptr )
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 };
|
||||
//GUID WusbrawGUID = {0xa5dcbf10, 0x6530, 0x11d2, 0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51, 0xed };
|
||||
//GUID WusbGUID = {0x88BAE032, 0x5A81, 0x49f0, 0xBC, 0x3D, 0xA4, 0xFF, 0x13, 0x82, 0x16, 0xD6 };
|
||||
|
||||
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
|
||||
|
||||
::ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
|
||||
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
|
||||
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
||||
NotificationFilter.dbcc_classguid = WceusbshGUID;
|
||||
_hDevNotify = ::RegisterDeviceNotification((HANDLE)window->winId(), &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
if( NULL == _hDevNotify )
|
||||
{
|
||||
// Print error
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
bool rm_usb::isRemovablePath(QString path)
|
||||
{
|
||||
if(path.contains(":")) {
|
||||
QString driver = path.split(":").first();
|
||||
WCHAR diskName[4] = {0,};
|
||||
driver = driver.left(1) + ":\\";
|
||||
driver.toWCharArray(diskName);
|
||||
if(::GetDriveType(diskName) == DRIVE_REMOVABLE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void rm_usb::setOpenDriveWithPath(QString path)
|
||||
{
|
||||
if(rm_usb::isRemovablePath(path)) {
|
||||
_openDrive = path.left(1).toUpper() + ":";
|
||||
}
|
||||
}
|
||||
int rm_usb::isDeviceDriver(QString folder, bool loadCFG)
|
||||
{
|
||||
#if (RM_MODEL_TB) // RM_MODEL == RM_MODEL_TYPE_TB4000
|
||||
return QDir(folder).exists() && QDir(folder + QDir::separator() + QString("Video")).exists() && QDir(folder + QDir::separator() + QString("Photo")).exists();
|
||||
#elif (RM_MODEL_EMT_KR)
|
||||
// 각 모델별로 확인
|
||||
for(int i=0;i<CFG::model_names.size();i++) {
|
||||
QString path = folder + "Setting" + QDir::separator() + CFG::model_names.at(i) + "_setting.cfg";
|
||||
if(QFile::exists(path)) {
|
||||
// 설정파일 읽을 필요 없음
|
||||
if(!loadCFG) {
|
||||
return 0;
|
||||
}
|
||||
// checksum + 크기 + 모델코드 확인
|
||||
CFG_ERROR_CODE code = CFG::load(path);
|
||||
if(code != CFG_SUCCESS) {
|
||||
if(code == CFG_CHECKSUM_ERROR) {
|
||||
return code;
|
||||
}
|
||||
//qInfo() << path << " MODEL CODE:" << CFG::info.model << "ERROR:" << code << __FUNCTION__;
|
||||
}
|
||||
if(code == CFG_SUCCESS && CFG::info.model == CFG::model_codes[i])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// E:\Setting , NM5000_setting.cfg
|
||||
// Magnus : 5101
|
||||
// Trinity : 5102
|
||||
// Mirror5 : 5103
|
||||
// Pro5 : 5104
|
||||
// 360X : 5105
|
||||
|
||||
return 999;
|
||||
#else //
|
||||
return false;
|
||||
#endif;
|
||||
}
|
||||
|
||||
// Disk 의 볼륨명이 모델명과 동일함
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
QString rm_usb::getRemovableDisk()
|
||||
{
|
||||
#if defined(WIN32)
|
||||
WCHAR szLogicalDrives[MAX_PATH * sizeof(TCHAR)];
|
||||
DWORD dwByte = ::GetLogicalDriveStrings(MAX_PATH, szLogicalDrives);
|
||||
|
||||
for(DWORD i=0; i<dwByte / 4; i++)
|
||||
{
|
||||
WCHAR* diskName = &szLogicalDrives[i * 4];
|
||||
UINT type = ::GetDriveType(diskName);
|
||||
if(DRIVE_REMOVABLE == type)
|
||||
{
|
||||
#if (!NO_SD_CHECK)
|
||||
QString diskLetter = QString::fromUtf16((const ushort*)diskName);
|
||||
|
||||
diskLetter.replace("\\","");
|
||||
|
||||
diskLetter = "\\\\.\\" + diskLetter;
|
||||
|
||||
// qInfo() << "check disk name:" << diskLetter;
|
||||
// empty media check
|
||||
HANDLE hDisk = ::CreateFile(reinterpret_cast<LPCWSTR>(diskLetter.utf16()),
|
||||
FILE_READ_DATA,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if(hDisk == INVALID_HANDLE_VALUE || hDisk == NULL)
|
||||
{
|
||||
//qInfo() << "INVALID_HANDLE_VALUE" << diskLetter << "type" << type;
|
||||
continue;
|
||||
}
|
||||
|
||||
DWORD dwBytesReturned;
|
||||
ULONG MediaChangeCount;
|
||||
BOOL res = ::DeviceIoControl( hDisk,
|
||||
IOCTL_STORAGE_CHECK_VERIFY,
|
||||
NULL,
|
||||
0,
|
||||
&MediaChangeCount,
|
||||
sizeof(ULONG),
|
||||
&dwBytesReturned,
|
||||
NULL);
|
||||
::CloseHandle(hDisk);
|
||||
if(res == FALSE)
|
||||
{
|
||||
//qInfo() << "empty" << QString::fromUtf16((const ushort*)diskName) << "type" << type;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
QString diskPath = QString::fromUtf16((const ushort*)diskName);
|
||||
// 설정파일 존재 확인
|
||||
if(isDeviceDriver(diskPath,false) == 0) {
|
||||
return diskPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
#else // TB
|
||||
QString rm_usb::getRemovableDisk(QString volume)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
WCHAR szLogicalDrives[MAX_PATH * sizeof(TCHAR)];
|
||||
DWORD dwByte = ::GetLogicalDriveStrings(MAX_PATH, szLogicalDrives);
|
||||
|
||||
for(DWORD i=0; i<dwByte / 4; i++)
|
||||
{
|
||||
WCHAR* diskName = &szLogicalDrives[i * 4];
|
||||
UINT type = ::GetDriveType(diskName);
|
||||
if(DRIVE_REMOVABLE == type)
|
||||
{
|
||||
|
||||
#if (!NO_SD_CHECK)
|
||||
QString diskLetter = QString::fromUtf16((const ushort*)diskName);
|
||||
|
||||
diskLetter.replace("\\","");
|
||||
|
||||
diskLetter = "\\\\.\\" + diskLetter;
|
||||
|
||||
// qInfo() << "check disk name:" << diskLetter;
|
||||
// empty media check
|
||||
HANDLE hDisk = ::CreateFile(reinterpret_cast<LPCWSTR>(diskLetter.utf16()),
|
||||
FILE_READ_DATA,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if(hDisk == INVALID_HANDLE_VALUE || hDisk == NULL)
|
||||
{
|
||||
//qInfo() << "INVALID_HANDLE_VALUE" << diskLetter << "type" << type;
|
||||
continue;
|
||||
}
|
||||
|
||||
DWORD dwBytesReturned;
|
||||
ULONG MediaChangeCount;
|
||||
BOOL res = ::DeviceIoControl( hDisk,
|
||||
IOCTL_STORAGE_CHECK_VERIFY,
|
||||
NULL,
|
||||
0,
|
||||
&MediaChangeCount,
|
||||
sizeof(ULONG),
|
||||
&dwBytesReturned,
|
||||
NULL);
|
||||
::CloseHandle(hDisk);
|
||||
if(res == FALSE)
|
||||
{
|
||||
//qInfo() << "empty" << QString::fromUtf16((const ushort*)diskName) << "type" << type;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
WCHAR volumeNameW[MAX_PATH * sizeof(TCHAR)] = {0,};
|
||||
|
||||
::GetVolumeInformation(diskName,volumeNameW, 1024, NULL, NULL, NULL, NULL, MAX_PATH);
|
||||
|
||||
QString volumeName = QString::fromUtf16((const ushort*)volumeNameW);
|
||||
QString diskPath = QString::fromUtf16((const ushort*)diskName);
|
||||
//qInfo() << volumeName << __FUNCTION__;
|
||||
if(volume.isEmpty() || volume.compare(volumeName,Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
diskPath = diskPath.replace("\\","");
|
||||
//rm_usb::current_driver = diskPath.at(0).toLatin1();
|
||||
return diskPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
#endif // #if (RM_MODEL_EMT_KR)
|
||||
#endif // #if (USE_SD_CARD_DETECT)
|
||||
74
project/fm_viewer/core/rm_usb.h
Normal file
74
project/fm_viewer/core/rm_usb.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef RM_USB_H
|
||||
#define RM_USB_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include <QMainWindow>
|
||||
#include "../rm_include.h"
|
||||
|
||||
#if (DETECT_SETTING_USB_EJECT || DETECT_USB_CHANGE)
|
||||
class rm_usb : public QObject, public QAbstractNativeEventFilter
|
||||
{
|
||||
friend class RMWindowsDisk;
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit rm_usb(QObject *parent = 0);
|
||||
~rm_usb();
|
||||
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);
|
||||
|
||||
//! \brief 지정된 볼륨의 USB 장치 탐색
|
||||
//! \param volume: 탐색할 볼륨명
|
||||
//! \return 탐색된 USB 폴더명
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
static QString getRemovableDisk();
|
||||
#else // RM_MODEL_EMT_KR
|
||||
static QString getRemovableDisk(QString volume);
|
||||
#endif // RM_MODEL_EMT_KR
|
||||
QString _openDrive; ///!< 현재 사용된 드라이버
|
||||
|
||||
//! \brief 지정된 경로가 USB 디스크인지 확인
|
||||
//! \param volume
|
||||
//! \return true:YES
|
||||
static bool isRemovablePath(QString path);
|
||||
|
||||
//! \brief setopenDriveWithFolder
|
||||
//! 경로의 드라이버가 removeable 일 경우 _openDrive 지정
|
||||
//! \param path: 경로
|
||||
void setOpenDriveWithPath(QString path);
|
||||
|
||||
//! \brief 장치 드라이버인지 확인
|
||||
//! 내부의 폴더, 볼륨명 등으로 확인
|
||||
//! 설정파일도 읽고 검증
|
||||
//! \param path: 경로
|
||||
//! \return 0:success other:CFG_ERROR_CODE
|
||||
static int isDeviceDriver(QString path,bool loadCFG = false);
|
||||
|
||||
private:
|
||||
char _firstDriveFromMask(uint unitmask );
|
||||
char _insertringDrive; // 다중호출 방지, 현재 추가되고 있는 드라이브
|
||||
char _removingDrive; // " 제거되고 있는 드라이브
|
||||
QTimer* _irTimer; ///! 동시 다중호출 방지를 위해 사용하는 _insertringDrive, _removingDrive 초기화
|
||||
|
||||
|
||||
//! \brief 초기화(_insertringDrive,_removingDrive) 타이머 시작
|
||||
void _startIRTimer();
|
||||
|
||||
//! \brief 초기화(_insertringDrive,_removingDrive) 타이머 취소
|
||||
void _cancelIRTimer();
|
||||
|
||||
void* _hDevNotify;
|
||||
signals:
|
||||
void usbChanged(bool inserted, QString& drive); // or removed
|
||||
|
||||
//! \brief 잘못된 SD 카드
|
||||
//! \param code: CFG_ERROR_CODE
|
||||
void wrongSDCard(int code);
|
||||
public slots:
|
||||
void registerEvent(QWidget *window);
|
||||
|
||||
//! \brief _insertringDrive, _removingDrive 초기화
|
||||
void onClearIR();
|
||||
};
|
||||
|
||||
#endif // USE_SD_CARD_DETECT
|
||||
#endif // RM_USB_H
|
||||
12
project/fm_viewer/core/rm_utility.cpp
Normal file
12
project/fm_viewer/core/rm_utility.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "rm_utility.h"
|
||||
|
||||
RMUtility::RMUtility()
|
||||
{
|
||||
|
||||
}
|
||||
float RMUtility::range(float fmin, float fmax,float tmin, float tmax, float value)
|
||||
{
|
||||
const float newRange = tmax - tmin;
|
||||
const float oldRange = fmax - fmin;
|
||||
return ((((value - (fmin)) * newRange) / oldRange) + tmin);
|
||||
}
|
||||
14
project/fm_viewer/core/rm_utility.h
Normal file
14
project/fm_viewer/core/rm_utility.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef RM_UTILITY_H
|
||||
#define RM_UTILITY_H
|
||||
|
||||
|
||||
class RMUtility
|
||||
{
|
||||
public:
|
||||
RMUtility();
|
||||
|
||||
static float range(float fmin, float fmax,float tmin, float tmax, float value);
|
||||
|
||||
};
|
||||
|
||||
#endif // RM_UTILITY_H
|
||||
373
project/fm_viewer/data/an6000_decode.cpp
Normal file
373
project/fm_viewer/data/an6000_decode.cpp
Normal file
@@ -0,0 +1,373 @@
|
||||
|
||||
#include "an6000_decode.h"
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
volatile unsigned long size;
|
||||
volatile char type[4];
|
||||
} BoxHeader_t;
|
||||
|
||||
typedef struct _BoxAddress_t {
|
||||
fpos_t addr;
|
||||
unsigned long size;
|
||||
} BoxAddress_t;
|
||||
|
||||
/**
|
||||
* @brief Convert the Byte-order(32bit) <for little-endian environment>
|
||||
*
|
||||
* @param[in] val target value
|
||||
*
|
||||
* @return convert value
|
||||
*/
|
||||
unsigned long convertEndian_32(unsigned long val)
|
||||
{
|
||||
unsigned long result = 0;
|
||||
unsigned char *p1 = (unsigned char *)&val;
|
||||
unsigned char *p2 = (unsigned char *)&result;
|
||||
p2[0] = p1[3];
|
||||
p2[1] = p1[2];
|
||||
p2[2] = p1[1];
|
||||
p2[3] = p1[0];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [DEBUG] Box data analysis
|
||||
*
|
||||
* @param[in] fp target file pointer
|
||||
* @param[in] level analysis depth
|
||||
* @param[in] parentSize parent box size
|
||||
*/
|
||||
void BoxAnalysis(FILE *fp, int level, size_t parentSize)
|
||||
{
|
||||
BoxHeader_t boxHead, childBoxHead;
|
||||
char typeDesc[8] = {0};
|
||||
size_t readSize;
|
||||
int i;
|
||||
int isNotAscii;
|
||||
char *pbuf = NULL;
|
||||
fpos_t pos;
|
||||
|
||||
while (1) {
|
||||
// read box header
|
||||
readSize = fread(&boxHead, 1, sizeof(BoxHeader_t), fp);
|
||||
if ((feof(fp) != 0) || (readSize == 0)) {
|
||||
break;
|
||||
}
|
||||
boxHead.size = convertEndian_32(boxHead.size);
|
||||
strncpy(typeDesc, (const char *)&boxHead.type[0], 4);
|
||||
if (boxHead.size == 0) {
|
||||
break;
|
||||
}
|
||||
fgetpos(fp, &pos);
|
||||
printf("[%08X] ", (unsigned long)(pos - sizeof(BoxHeader_t)));
|
||||
for (i = 0; i < level; i++) {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%s[%d]\n", typeDesc, boxHead.size);
|
||||
if (parentSize != (size_t)-1) {
|
||||
parentSize -= boxHead.size;
|
||||
}
|
||||
|
||||
// check child box exist
|
||||
readSize = fread(&childBoxHead, 1, sizeof(BoxHeader_t), fp);
|
||||
childBoxHead.size = convertEndian_32(childBoxHead.size);
|
||||
isNotAscii = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((childBoxHead.type[i] < 'a') || (childBoxHead.type[i] > 'z')) {
|
||||
++isNotAscii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fseek(fp, -(long)sizeof(BoxHeader_t), SEEK_CUR);
|
||||
|
||||
if ((boxHead.size > childBoxHead.size) && (isNotAscii == 0)) {
|
||||
// child box exist
|
||||
BoxAnalysis(fp, level + 1, boxHead.size - sizeof(BoxHeader_t));
|
||||
}
|
||||
else {
|
||||
// child box not exist
|
||||
pbuf = (char *)malloc(boxHead.size - sizeof(BoxHeader_t));
|
||||
fread(pbuf, 1, boxHead.size - sizeof(BoxHeader_t), fp);
|
||||
free(pbuf);
|
||||
}
|
||||
|
||||
// check of continue the child box loop
|
||||
if (parentSize == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// terminal box
|
||||
if (strncmp((const char *)boxHead.type, "FWVR", 4) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parentSize == (size_t)-1) {
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the crypt target box information
|
||||
*
|
||||
* @param[in] fp target file pointer
|
||||
* @param[out] buf target box information
|
||||
* @param[in] bufSize number of \a buf buffer
|
||||
* @param[in] level analysis depth
|
||||
* @param[in] parentSize parent box size
|
||||
*
|
||||
* @return number of available target box information
|
||||
*/
|
||||
static bool gFound_stsz = false;
|
||||
static bool gFount_udat = false;
|
||||
|
||||
size_t GetCryptTarget(FILE *fp, BoxAddress_t *buf, size_t bufSize, int level, size_t parentSize)
|
||||
{
|
||||
size_t buf_num = 0;
|
||||
BoxHeader_t boxHead = {0,};
|
||||
BoxHeader_t childBoxHead = {0,};
|
||||
size_t readSize = 0;
|
||||
int isNotAscii = 0;
|
||||
int i = 0;
|
||||
//char *pbuf = NULL;
|
||||
fpos_t pos = 0;
|
||||
|
||||
if (bufSize == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
// read box header
|
||||
readSize = fread(&boxHead, 1, sizeof(BoxHeader_t), fp);
|
||||
if (readSize == 0) {
|
||||
break;
|
||||
}
|
||||
boxHead.size = convertEndian_32(boxHead.size);
|
||||
if (boxHead.size == 0) {
|
||||
break;
|
||||
}
|
||||
if (parentSize != (size_t)-1) {
|
||||
parentSize -= boxHead.size;
|
||||
}
|
||||
|
||||
// check crypt target box
|
||||
|
||||
if (((strncmp((const char *)boxHead.type, "stsz", 4) == 0) && (gFound_stsz == false) )
|
||||
|| (strncmp((const char *)boxHead.type, "udat", 4) == 0) && (gFount_udat == false)){
|
||||
fgetpos(fp, &pos);
|
||||
buf[buf_num].addr = pos - sizeof(BoxHeader_t);
|
||||
buf[buf_num].size = boxHead.size;
|
||||
fseek(fp, boxHead.size - sizeof(BoxHeader_t), SEEK_CUR);
|
||||
|
||||
if(strncmp((const char *)boxHead.type, "stsz", 4) == 0)
|
||||
{
|
||||
gFound_stsz = true;
|
||||
}
|
||||
else if(strncmp((const char *)boxHead.type, "udat", 4) == 0)
|
||||
{
|
||||
gFount_udat = true;
|
||||
}
|
||||
|
||||
if (++buf_num == bufSize) {
|
||||
return buf_num;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Existence check of child box
|
||||
readSize = fread(&childBoxHead, 1, sizeof(BoxHeader_t), fp);
|
||||
fseek(fp, -(long)sizeof(BoxHeader_t), SEEK_CUR);
|
||||
childBoxHead.size = convertEndian_32(childBoxHead.size);
|
||||
isNotAscii = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((childBoxHead.type[i] < 'a') || (childBoxHead.type[i] > 'z')) {
|
||||
++isNotAscii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((boxHead.size > childBoxHead.size) && (isNotAscii == 0)) {
|
||||
// child box is exist
|
||||
buf_num += GetCryptTarget(fp, &buf[buf_num], bufSize - buf_num, level + 1, boxHead.size - sizeof(BoxHeader_t));
|
||||
if (buf_num == bufSize) {
|
||||
return buf_num;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// child box is not exist
|
||||
fseek(fp, boxHead.size - sizeof(BoxHeader_t), SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
// check of continue the child box loop
|
||||
if (parentSize == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// terminal box
|
||||
if (strncmp((const char *)boxHead.type, "FWVR", 4) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return buf_num;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encrypt MP4 File
|
||||
*
|
||||
* @param[in] filename target file name
|
||||
*
|
||||
* @retval 0 successful
|
||||
* @retval non-zero failed
|
||||
*/
|
||||
int encrypt_an6000(const wchar_t *filename)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
BoxAddress_t tgtInfo[8];
|
||||
size_t infoSize, i, x;
|
||||
char *pbuf;
|
||||
char key = 0x19;
|
||||
char preData, enc;
|
||||
|
||||
memset(tgtInfo, 0, sizeof(tgtInfo));
|
||||
infoSize = sizeof(tgtInfo) / sizeof(BoxAddress_t);
|
||||
|
||||
fp = _wfopen(filename,L"r+b");
|
||||
//fp = fopen(filename, "r+b");
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
// Analysis box information
|
||||
//BoxAnalysis(fp, 0, (size_t)-1);
|
||||
infoSize = GetCryptTarget(fp, tgtInfo, infoSize, 0, -1);
|
||||
|
||||
for (i = 0; i < infoSize; i++) {
|
||||
pbuf = (char*)malloc(tgtInfo[i].size);
|
||||
|
||||
// read the target data
|
||||
fsetpos(fp, &tgtInfo[i].addr);
|
||||
fread(pbuf, 1, tgtInfo[i].size, fp);
|
||||
|
||||
// data encrypt
|
||||
preData = 0;
|
||||
for (x = 8; x < tgtInfo[i].size; x++) {
|
||||
enc = ((~pbuf[x]) ^ preData) ^ key;
|
||||
preData = pbuf[x];
|
||||
pbuf[x] = enc;
|
||||
}
|
||||
|
||||
// over-write the target data
|
||||
fsetpos(fp, &tgtInfo[i].addr);
|
||||
fwrite(pbuf, 1, tgtInfo[i].size, fp);
|
||||
|
||||
free(pbuf);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decrypt MP4 File
|
||||
*
|
||||
* @param[in] filename target file name
|
||||
*
|
||||
* @retval 0 successful
|
||||
* @retval non-zero failed
|
||||
*/
|
||||
int decrypt_an6000(const wchar_t *filename)
|
||||
{
|
||||
gFound_stsz = false;
|
||||
gFount_udat = false;
|
||||
|
||||
FILE *fp = NULL;
|
||||
BoxAddress_t tgtInfo[8] = {0,};
|
||||
size_t infoSize, i, x;
|
||||
char *pbuf = NULL;
|
||||
char key = 0x19;
|
||||
char preData = 0;
|
||||
|
||||
memset(tgtInfo, 0, sizeof(_BoxAddress_t) * 8);
|
||||
infoSize = sizeof(tgtInfo) / sizeof(_BoxAddress_t);
|
||||
|
||||
// filePathCH2.toStdWString().c_str()
|
||||
fp = _wfopen(filename,L"r+b");
|
||||
//fp = fopen(filename, "r+b");
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
// Analysis box information
|
||||
infoSize = GetCryptTarget(fp, tgtInfo, infoSize, 0, -1);
|
||||
|
||||
for (i = 0; i < infoSize; i++) {
|
||||
pbuf = (char*)malloc(tgtInfo[i].size);
|
||||
|
||||
// read the target data
|
||||
fsetpos(fp, &tgtInfo[i].addr);
|
||||
fread(pbuf, 1, tgtInfo[i].size, fp);
|
||||
|
||||
// data decrypt
|
||||
preData = 0;
|
||||
for (x = 8; x < tgtInfo[i].size; x++) {
|
||||
pbuf[x] = ~((pbuf[x] ^ key) ^ preData);
|
||||
preData = pbuf[x];
|
||||
}
|
||||
|
||||
// over-write the target data
|
||||
fsetpos(fp, &tgtInfo[i].addr);
|
||||
fwrite(pbuf, 1, tgtInfo[i].size, fp);
|
||||
|
||||
free(pbuf);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
bool is_encrypted_an6000(const wchar_t *filename)
|
||||
{
|
||||
gFound_stsz = false;
|
||||
gFount_udat = false;
|
||||
|
||||
FILE *fp = NULL;
|
||||
BoxAddress_t tgtInfo[8] = {0,};
|
||||
size_t infoSize, i, x;
|
||||
|
||||
memset(tgtInfo, 0, sizeof(_BoxAddress_t) * 8);
|
||||
infoSize = sizeof(tgtInfo) / sizeof(_BoxAddress_t);
|
||||
|
||||
fp = _wfopen(filename,L"r+b");
|
||||
if (fp == NULL) {
|
||||
return false;
|
||||
}
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
infoSize = GetCryptTarget(fp, tgtInfo, infoSize, 0, -1);
|
||||
|
||||
char buffer[16] = {0,};
|
||||
for (i = 0; i < infoSize; i++) {
|
||||
// read the target data
|
||||
tgtInfo[i].addr += 4;
|
||||
fsetpos(fp, &tgtInfo[i].addr);
|
||||
fread(buffer, 1, 16, fp);
|
||||
if(buffer[0] == 's' && buffer[1] =='t' && buffer[2] =='s' && buffer[3] =='z') {
|
||||
|
||||
bool enc = (buffer[4] != 0 || buffer[5] != 0 || buffer[6] != 0 || buffer[7] != 0);
|
||||
fclose(fp);
|
||||
return enc;//(buffer[4] != 0 || buffer[5] != 0 || buffer[6] != 0 || buffer[7] != 0);
|
||||
}
|
||||
//printf("%c:%c:%c:%c\n",buffer[0],buffer[1],buffer[2],buffer[3]);
|
||||
//printf("%02X:%02X:%02X:%02X %02X:%02X:%02X:%02X\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7]);
|
||||
}
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
12
project/fm_viewer/data/an6000_decode.h
Normal file
12
project/fm_viewer/data/an6000_decode.h
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
#ifndef AN6000_DECODE_H
|
||||
#define AN6000_DECODE_H
|
||||
#include "../rm_include.h"
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
|
||||
int decrypt_an6000(const wchar_t *filename);
|
||||
int encrypt_an6000(const wchar_t *filename);
|
||||
bool is_encrypted_an6000(const wchar_t *filename);
|
||||
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
#endif // AN6000_DECODE_H
|
||||
37
project/fm_viewer/data/fileio.c
Normal file
37
project/fm_viewer/data/fileio.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "fileio.h"
|
||||
|
||||
int read_long(FILE *in)
|
||||
{
|
||||
int c;
|
||||
|
||||
c=getc(in);
|
||||
c=c+(getc(in)<<8);
|
||||
c=c+(getc(in)<<16);
|
||||
c=c+(getc(in)<<24);
|
||||
return c;
|
||||
}
|
||||
|
||||
int read_word(FILE *in)
|
||||
{
|
||||
int c;
|
||||
|
||||
c=getc(in);
|
||||
c=c+(getc(in)<<8);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int read_chars(FILE *in, char *s, int count)
|
||||
{
|
||||
int t;
|
||||
|
||||
for (t=0; t<count; t++)
|
||||
{
|
||||
s[t]=getc(in);
|
||||
}
|
||||
|
||||
s[t]=0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
22
project/fm_viewer/data/fileio.h
Normal file
22
project/fm_viewer/data/fileio.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef FILEIO_H
|
||||
#define FILEIO_H
|
||||
|
||||
// #include "rm_constants.h"
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef FILE* RMfile;
|
||||
#define RMfread(__BUFFER,__SIZE,__COUNT,__FILE) fread(__BUFFER,__SIZE,__COUNT,__FILE)
|
||||
#define RMftell(__FILE) ftell(__FILE)
|
||||
#define RMfseek(__FILE,__OFSET,__SEEK_TYPE) fseek(__FILE,__OFSET,__SEEK_TYPE)
|
||||
#define RMgetc(__FILE) getc(__FILE)
|
||||
#define RMfeof(__FILE) feof(__FILE)
|
||||
|
||||
|
||||
|
||||
int read_long(RMfile in);
|
||||
int read_word(RMfile in);
|
||||
int read_chars(RMfile in, char *s, int count);
|
||||
|
||||
#endif
|
||||
1149
project/fm_viewer/data/fm_address.cpp
Normal file
1149
project/fm_viewer/data/fm_address.cpp
Normal file
File diff suppressed because it is too large
Load Diff
196
project/fm_viewer/data/fm_address.h
Normal file
196
project/fm_viewer/data/fm_address.h
Normal file
@@ -0,0 +1,196 @@
|
||||
#ifndef FM_ADDRESS_H
|
||||
#define FM_ADDRESS_H
|
||||
|
||||
#if (USE_JP_ADDRESS)
|
||||
|
||||
#include <QString>
|
||||
#include <inttypes.h>
|
||||
#include <QMap>
|
||||
|
||||
#define USE_ADDR_DB_TYPE 1
|
||||
|
||||
// // _maxLenPref: 4 _maxLenCity: 8 _maxLenChome: 12
|
||||
#define MAX_JA_AREA_NAME_LEN 30
|
||||
#define MAX_PREF_COUNT 50 // 도도부현 개수
|
||||
#define MAX_CITY_COUNT 200 // 도도부현당 최대 시/구 개수, "北海道" 52, "大阪府" 64
|
||||
|
||||
#if (USE_ADDR_DB_TYPE == 0)
|
||||
#define MAX_JIBUN_COUNT 4000 // 3381
|
||||
#define MAX_CHOME_COUNT 1500 // 시/구당 최대 마을 개수 旭川市 1475
|
||||
#elif (USE_ADDR_DB_TYPE == 1)
|
||||
#define MAX_JIBUN_COUNT 20000 // 20000
|
||||
#define MAX_CHOME_COUNT 5000 // 福島県, 시/구당 최대 마을 개수 旭川市 1475
|
||||
#endif
|
||||
typedef struct _JA_HEADER {
|
||||
char header[128]; // 0
|
||||
char date[24]; // 128
|
||||
char version[24]; // 152
|
||||
uint32_t stringSize; // 176 문자열 테이블 크기
|
||||
//uint32_t prefOffset; // 180 도도부현 시작 옵셋 (=sizeof header + stringSize) + ....
|
||||
uint32_t pref_count; // 184 pref 개수
|
||||
uint32_t city_count; // 188 전체 city 개수
|
||||
uint32_t town_count; // 192 전체 town 개수
|
||||
uint32_t jibun_count; // 196 전체 지번 개수
|
||||
int32_t xmin; // 영역..
|
||||
int32_t ymin;
|
||||
int32_t xmax;
|
||||
int32_t ymax;
|
||||
|
||||
} JA_HEADER;
|
||||
|
||||
// 저장용 구조체
|
||||
typedef struct _JA_AREA_PACKET
|
||||
{
|
||||
uint32_t nameOffset;
|
||||
uint32_t sub_count;
|
||||
uint32_t sub_offset;
|
||||
int32_t xmin;
|
||||
int32_t ymin;
|
||||
int32_t xmax;
|
||||
int32_t ymax;
|
||||
uint8_t bits[4]; // CHOME 만 사용 (BITS X,Y,A0,A1)
|
||||
} JA_AREA_PACKET;
|
||||
|
||||
#if (USE_JP_ADDRESS_TOOL)
|
||||
|
||||
// 주소(지번) -> 처리용 구조체
|
||||
typedef struct _JA_JIBUN {
|
||||
uint16_t a0; // 150 : 8bit
|
||||
uint16_t a1; // 732 : 10bit
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} JA_JIBUN; // 12BYTE
|
||||
|
||||
// 도도부현,시구,마을(丁目) -> 처리용 구조체
|
||||
typedef struct _JA_AREA {
|
||||
ushort name[MAX_JA_AREA_NAME_LEN]; // 16(12 * 2)
|
||||
|
||||
int32_t count; // sub area(or a) count
|
||||
_JA_AREA* subAreas;
|
||||
_JA_JIBUN* subJibuns;
|
||||
uint32_t offset; // sub area offset // or Pointer
|
||||
|
||||
int32_t xmin;
|
||||
int32_t ymin;
|
||||
int32_t xmax;
|
||||
int32_t ymax;
|
||||
|
||||
uint32_t nameOffset;
|
||||
|
||||
uint16_t a0min; // BYTE PACK 계산하기 위해 사용
|
||||
uint16_t a0max;
|
||||
uint16_t a1min;
|
||||
uint16_t a1max;
|
||||
|
||||
uint8_t bits[4]; // CHOME 의 경우 포함된 지번 데이터의 BIT PACK
|
||||
} JA_AREA;
|
||||
|
||||
#endif // #if (USE_JP_ADDRESS_TOOL)
|
||||
|
||||
|
||||
// 北海道 深川市 一条 (3066,1474)
|
||||
// 神奈川県 横浜市鶴見区 大黒町 (879,2625)
|
||||
// XMAX: 12bit, YMAX:12bit,
|
||||
// a0: // 150 : 8bit
|
||||
// a1: // 732 : 10bit
|
||||
|
||||
class FMAddress
|
||||
{
|
||||
private:
|
||||
|
||||
// 탐색 결과
|
||||
int _found_a0;
|
||||
int _found_a1;
|
||||
int _found_dist_sq; // 거리^2
|
||||
int _found_x;
|
||||
int _found_y;
|
||||
|
||||
JA_HEADER _header; // 헤더
|
||||
JA_AREA_PACKET* _areas; // 도도부현, 시구군, 읍면동..
|
||||
uint8_t* _strings; // 문자열 "
|
||||
FILE* _file;
|
||||
|
||||
// TOWN내에서 가장 가까운 지번 탐색 town, x,y (return dist, a0:대번지, a1:소번지)
|
||||
bool _searchTown(JA_AREA_PACKET* town,int x, int y,int tolerance);
|
||||
|
||||
public:
|
||||
FMAddress();
|
||||
~FMAddress();
|
||||
|
||||
static FMAddress* instance()
|
||||
{
|
||||
static FMAddress * _instance = 0;
|
||||
if ( _instance == 0 ) {
|
||||
_instance = new FMAddress();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
bool isOpened() {
|
||||
return (_areas != NULL && _strings != NULL && _file != NULL);
|
||||
}
|
||||
|
||||
bool open(); // 파일열기 (실행파일경로 or 테스트 경로)
|
||||
|
||||
bool open(QString path); // 파일열기
|
||||
// 탐색 (경위도, 도도부현, 시구군, 읍면동, 탐색거리, 허용 오차m)
|
||||
bool search(double lon,double lat,wchar_t** pref,wchar_t** city,wchar_t** town,int* a0, int*a1, int* pdist, int tolerance = 200);
|
||||
|
||||
// 탐색 결과 도도부현,시군구,읍면동,번지,호,거리
|
||||
bool search(double lon, double lat,QStringList& result, int tolerance = 200);
|
||||
|
||||
#if (USE_JP_ADDRESS_TOOL)
|
||||
void debugList(); // 디버그
|
||||
void _debugTown(JA_AREA_PACKET* town); //
|
||||
|
||||
public:
|
||||
bool convert(QString src, QString target);
|
||||
bool verify(QString src); // TXT 데이터와 비교
|
||||
// CODE,PREF,CITY,CHOME,A0,A1,LON,LAT,CDATE
|
||||
static QMap<QString,uint32_t> _stringTable;
|
||||
private:
|
||||
|
||||
static void _updateBound(_JA_AREA* dest, _JA_AREA* src);
|
||||
static void _updateBoundP(_JA_AREA* dest, _JA_JIBUN* src);
|
||||
static void _initBound(_JA_AREA* dest);
|
||||
static void _calculateBitPack(_JA_AREA * src); // , uint8_t* byte
|
||||
static void _copyPacket(JA_AREA_PACKET* dest, JA_AREA* src);
|
||||
|
||||
void _freeConvertData();
|
||||
void _resizeChome(JA_AREA* chome); // MAX 크기로 할당된 지번을 원래 개수대로 변경
|
||||
void _createStatCSV(); // 통계 생성
|
||||
void _saveData();
|
||||
void _saveStringTable();
|
||||
void _savePref(); // 도도부현 저장
|
||||
void _sortJIBUN(JA_AREA* chome); // 지번 XY 순으로 정렬
|
||||
bool _packJibun(JA_AREA* town,uint8_t* buffer,uint32_t* offset); // 지번 BIT PACK
|
||||
|
||||
uint32_t _totalJibunBytes; // 전체 지번 할당 데이터
|
||||
uint32_t _writeOffset; // 현재 파일 포인터
|
||||
FILE* _outFile; // 파일
|
||||
|
||||
uint32_t _totalStringBufferLength; // 전체 문자열 버퍼 크기(중복제거)
|
||||
uint32_t _totalStringLength; // 전체 문자열 크기
|
||||
uint32_t _currentStringOffset; // 현재 문자열 버퍼 옵셋
|
||||
void _setStringOffset(JA_AREA* area,QString name); // 문자열 추가 + 옵셋처리
|
||||
|
||||
// 현재 처리중인 도도부현,...
|
||||
QString _currentPrefName;
|
||||
QString _currentCityName;
|
||||
QString _currentChomeName;
|
||||
JA_AREA* _prefs; // 도도부현 저장
|
||||
|
||||
JA_AREA* _currentPref; // 현재 도도부현
|
||||
JA_AREA* _currentCity; // " 시군구
|
||||
JA_AREA* _currentChome; // " 마을
|
||||
JA_JIBUN* _currentJibun; // " 지번
|
||||
|
||||
int _maxLenPref; // 통계 확인용
|
||||
int _maxLenCity; // "
|
||||
int _maxLenChome; // "
|
||||
int _maxA0; // " 지번 대번지 최대값
|
||||
int _maxA1; // " " 소번지
|
||||
#endif // USE_JP_ADDRESS_TOOL
|
||||
};
|
||||
|
||||
#endif // USE_JP_ADDRESS
|
||||
#endif // FM_ADDRESS_H
|
||||
151
project/fm_viewer/data/fm_parse_gps.cpp
Normal file
151
project/fm_viewer/data/fm_parse_gps.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
#include "fm_parse_gps.h"
|
||||
|
||||
bool FMParseGPS::ParseRMC(char szSentence[], NMEA_INFO* data, int nPacketSize)
|
||||
{
|
||||
Q_UNUSED(nPacketSize);
|
||||
|
||||
// qDebug() << szSentence;
|
||||
|
||||
char szItem[NMEA_TOKEN_SIZE]={0,};
|
||||
long nTemp;
|
||||
|
||||
// 의미없으니 하지 말자
|
||||
// DWORD dwCheckSum = 0;
|
||||
//for (i = 1; i < strlen(szSentence) && szSentence[i] != '*'; i++)
|
||||
// dwCheckSum ^= szSentence[i];
|
||||
|
||||
//NMEA_INFO* data = &_gpsData[index];
|
||||
|
||||
//0th
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
|
||||
// 1th
|
||||
char szUtc[11] = {0,};
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
strncpy(szUtc, szItem, sizeof(szUtc));
|
||||
|
||||
// 2th
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
char cStatus = szItem[0];
|
||||
|
||||
// 3th
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
data->Latitude = atof(szItem);
|
||||
|
||||
// 4th
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
unsigned char cLatitudeDir = szItem[0];
|
||||
|
||||
// 5th
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
data->Longitude = atof(szItem);
|
||||
|
||||
// 6th
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
unsigned char cLongitudeDir = szItem[0];
|
||||
|
||||
// 7th
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
double speed = atof(szItem);
|
||||
|
||||
// 8th
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
double track = atof(szItem);
|
||||
|
||||
// 9th
|
||||
char szDate[7] = {0,};
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
strncpy(szDate, szItem, sizeof(szDate));
|
||||
|
||||
// 10th
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
// double Mag = atof(szItem); // Magnetic variation
|
||||
|
||||
// 11th
|
||||
szSentence = _GetNextToken(szSentence, szItem);
|
||||
// unsigned char cMagDir = szItem[0];
|
||||
|
||||
// Set GPS Info
|
||||
if (strlen(szUtc) >= 6)
|
||||
{
|
||||
data->nHour = (szUtc[0] - 48) * 10 + (szUtc[1] - 48);
|
||||
data->nMin = (szUtc[2] - 48) * 10 + (szUtc[3] - 48);
|
||||
data->nSec = (szUtc[4] - 48) * 10 + (szUtc[5] - 48);
|
||||
}
|
||||
if (strlen(szDate) >= 6)
|
||||
{
|
||||
data->nDay = (szDate[0] - 48) * 10 + (szDate[1] - 48);
|
||||
data->nMonth = (szDate[2] - 48) * 10 + (szDate[3] - 48);
|
||||
data->nYear = (szDate[4] - 48) * 10 + (szDate[5] - 48);
|
||||
if (data->nYear > 80)
|
||||
{
|
||||
data->nYear += 1900;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->nYear += 2000;
|
||||
}
|
||||
}
|
||||
// printf("date:%d-%d-%d %d:%d:%d\n",data->nYear,data->nMonth,data->nDay,data->nHour,data->nMin,data->nSec);
|
||||
data->nStatus = (cStatus == 'A') ? 1 : 0;
|
||||
|
||||
data->Latitude = data->Latitude / 100.0;
|
||||
nTemp = (long)data->Latitude;
|
||||
data->Latitude = (double)nTemp + (double)(data->Latitude - nTemp) * 100.0 / 60.0;
|
||||
if (cLatitudeDir == 'S')
|
||||
{
|
||||
data->Latitude *= -1;
|
||||
}
|
||||
|
||||
data->Longitude = data->Longitude / 100.0;
|
||||
nTemp = (long)data->Longitude;
|
||||
data->Longitude = (double)nTemp + (double)(data->Longitude - nTemp) * 100.0 / 60.0;
|
||||
|
||||
if (cLongitudeDir == 'W')
|
||||
{
|
||||
data->Longitude *= -1;
|
||||
}
|
||||
|
||||
data->Speed = speed * 1.852; // 1 knots는 1해리를 1시간에 가는 속력으로 1해리는 1852m
|
||||
|
||||
data->nAngle = (uint8_t) track;
|
||||
// // data->nAngle = (long) track;
|
||||
// if((data->nAngle-track>5 || data->nAngle-track<-5) ||
|
||||
// (_nLastAngle[1]==_nLastAngle[0] && _nLastAngle[0] == track ))
|
||||
// {
|
||||
// data->nAngle = (uint8_t) track;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// _nLastAngle[1] = _nLastAngle[0];
|
||||
// _nLastAngle[0] = (long)track;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
char* FMParseGPS::_GetNextToken(char* lpSentence, char* lpToken, int iTokenSize)
|
||||
{
|
||||
lpToken[0] = '\0';
|
||||
if (lpSentence == NULL || lpSentence[0] == '\0')
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (lpSentence[0] == ',')
|
||||
{
|
||||
return lpSentence + 1;
|
||||
}
|
||||
iTokenSize--;
|
||||
|
||||
while( *lpSentence != ',' &&
|
||||
*lpSentence != '\0' &&
|
||||
*lpSentence != '*'&& iTokenSize > 0)
|
||||
{
|
||||
*lpToken = *lpSentence;
|
||||
lpToken++;
|
||||
lpSentence++;
|
||||
iTokenSize--;
|
||||
}
|
||||
lpSentence++;
|
||||
*lpToken = '\0';
|
||||
return lpSentence;
|
||||
}
|
||||
15
project/fm_viewer/data/fm_parse_gps.h
Normal file
15
project/fm_viewer/data/fm_parse_gps.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef FM_PARSE_GPS_H
|
||||
#define FM_PARSE_GPS_H
|
||||
|
||||
#include "rm_sensordata.h"
|
||||
|
||||
#define NMEA_TOKEN_SIZE 51
|
||||
class FMParseGPS
|
||||
{
|
||||
public:
|
||||
static bool ParseRMC(char szSentence[], NMEA_INFO* data, int nPacketSize);
|
||||
private:
|
||||
static char* _GetNextToken(char* lpSentence, char* lpToken, int iTokenSize = NMEA_TOKEN_SIZE);
|
||||
};
|
||||
|
||||
#endif // FM_PARSE_GPS_H
|
||||
461
project/fm_viewer/data/fm_video_edit.cpp
Normal file
461
project/fm_viewer/data/fm_video_edit.cpp
Normal file
@@ -0,0 +1,461 @@
|
||||
|
||||
#include "fm_video_edit.h"
|
||||
#if (FM_VIDEO_EDIT)
|
||||
|
||||
#if (USE_LIB_MP4V2)
|
||||
#include "mp4v2.h"
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
}
|
||||
#endif // extern C
|
||||
#endif //USE_LIB_MP4V2
|
||||
|
||||
#define MAX_VIDEO_STREAM_COUNT 10
|
||||
|
||||
|
||||
FMVideoEdit::FMVideoEdit(QStringList files, QStringList dests, EditMode mode, bool deleteSrcDone)
|
||||
{
|
||||
_files = files;
|
||||
_dests = dests;
|
||||
_mode = mode;
|
||||
_deleteSrcAfter = deleteSrcDone;
|
||||
}
|
||||
|
||||
void FMVideoEdit::run()
|
||||
{
|
||||
_splitMP4VideoTracks();
|
||||
}
|
||||
|
||||
int _find_video_stream_index(int stream_id, int *streams) {
|
||||
for(int i=0;i<MAX_VIDEO_STREAM_COUNT;i++) {
|
||||
if(stream_id == streams[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
void _clean_output_contexts(AVFormatContext** ctxs) {
|
||||
for(int i=0;i<MAX_VIDEO_STREAM_COUNT;i++) {
|
||||
if (ctxs[i] != NULL) {
|
||||
avformat_free_context(ctxs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FMVideoEdit::_splitMP4VideoTracks()
|
||||
{
|
||||
QString src = _files.first();
|
||||
|
||||
AVFormatContext *input_ctx = NULL;
|
||||
|
||||
int video_stream_index[MAX_VIDEO_STREAM_COUNT] = {-1,};
|
||||
bool video_stream_validation[MAX_VIDEO_STREAM_COUNT] = {true,}; // 정상 Video Stream 확인
|
||||
|
||||
int video_stream_count = 0;
|
||||
int real_video_stream_count = 0; // 실제 비디오 스트림 개수
|
||||
int audio_stream_index = -1; // Audio 가 존재하지 않을 경우 stream index 를 2가 아닌 1로 작성하기 위해 사용
|
||||
int video_frame_count = -1; // Progress 처리하기 위해 사용
|
||||
|
||||
// 입력 파일 열기
|
||||
if (avformat_open_input(&input_ctx, src.toUtf8().constData(), NULL, NULL) < 0) {
|
||||
emit done(ErrorFileOpen);
|
||||
return;
|
||||
}
|
||||
|
||||
// 메타 정보 확인
|
||||
// major_brand : isom
|
||||
// minor_version : 512
|
||||
// compatible_brands : isomiso2avc1mp41
|
||||
/*
|
||||
AVDictionaryEntry *tag = NULL;
|
||||
while ((tag = av_dict_get(input_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
|
||||
qInfo() << tag->key << ":" << tag->value << __FUNCTION__;
|
||||
}
|
||||
*/
|
||||
|
||||
// 스트림 정보 읽기
|
||||
if (avformat_find_stream_info(input_ctx, NULL) < 0) {
|
||||
emit done(ErrorOpenStream);
|
||||
avformat_close_input(&input_ctx);
|
||||
return;
|
||||
}
|
||||
// 각 비디오 스트림 + 오디오/자막 스트림 인덱스 확인
|
||||
for (unsigned int i = 0; i < input_ctx->nb_streams; i++) {
|
||||
AVMediaType type = input_ctx->streams[i]->codecpar->codec_type;
|
||||
if (type == AVMEDIA_TYPE_VIDEO) {
|
||||
|
||||
// 프레임이 없는 N 번째 영상 스트림 제거
|
||||
video_stream_validation[i] = (input_ctx->streams[i]->nb_frames > 0);
|
||||
// if(input_ctx->streams[i]->nb_frames == 0) {
|
||||
// video_stream_validation[i] = false;
|
||||
// }
|
||||
if(video_stream_validation[i])
|
||||
{
|
||||
real_video_stream_count += 1;
|
||||
}
|
||||
|
||||
// Progress 처리하기 위해
|
||||
if(video_frame_count < 0) {
|
||||
video_frame_count = input_ctx->streams[i]->nb_frames;
|
||||
}
|
||||
// AVStream* ps = input_ctx->streams[i];
|
||||
// qInfo() << "VSTREAM:" << i << ps->discard << __FUNCTION__;
|
||||
video_stream_index[video_stream_count] = i;
|
||||
video_stream_count++;
|
||||
} else if (type == AVMEDIA_TYPE_AUDIO) {
|
||||
audio_stream_index = i;
|
||||
} //else if (type == AVMEDIA_TYPE_SUBTITLE) {
|
||||
// subtitle_stream_index = i;
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
// 실제 영상 스트림이 출력 개수보다 많을 경우에만 처리
|
||||
//video_stream_count = 2;
|
||||
if(real_video_stream_count > _dests.size()) {
|
||||
emit done(ErrorWrongTrackCount);
|
||||
avformat_close_input(&input_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
// 한번에 모든 패킷을 여러 파일에 저장하기 위해 동시 생성
|
||||
AVFormatContext *output_ctx[MAX_VIDEO_STREAM_COUNT] = {NULL,};
|
||||
AVStream *out_video_stream[MAX_VIDEO_STREAM_COUNT] = {NULL,};
|
||||
AVStream *out_audio_stream[MAX_VIDEO_STREAM_COUNT] = {NULL,};
|
||||
AVStream *out_subtitle_stream[MAX_VIDEO_STREAM_COUNT] = {NULL,};
|
||||
|
||||
for(int s=0;s<video_stream_count;s++) {
|
||||
|
||||
// 프레임 없는 영상 스트림 SKIP
|
||||
if(!video_stream_validation[s]) {
|
||||
continue;
|
||||
}
|
||||
// 복사할 비디오 스트림 인덱스
|
||||
// int current_video_stream = video_stream_index[s];
|
||||
|
||||
// 출력 파일 생성
|
||||
//AVFormatContext *output_ctx = NULL;
|
||||
QString destString = _dests.at(s);
|
||||
char dest[4096] = {0,};
|
||||
memcpy(dest,destString.toUtf8().constData(),destString.toUtf8().length());
|
||||
// MP4는 PCM 데이터를 저장하지 못하므로 확장자는 MP4 이나 강제로 MOV 포멧으로 지정
|
||||
avformat_alloc_output_context2(&output_ctx[s], NULL, "mov", dest);
|
||||
|
||||
if (!output_ctx[s]) {
|
||||
emit done(ErrorFileCreate);
|
||||
avformat_close_input(&input_ctx);
|
||||
_clean_output_contexts(output_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
// 비디오 스트림 생성
|
||||
out_video_stream[s] = avformat_new_stream(output_ctx[s], NULL);
|
||||
if (!out_video_stream[s]) {
|
||||
emit done(ErrorCreateStream);
|
||||
_clean_output_contexts(output_ctx);
|
||||
avformat_close_input(&input_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
// 스트림 파라미터 복사
|
||||
int ret = avcodec_parameters_copy(out_video_stream[s]->codecpar, input_ctx->streams[video_stream_index[s]]->codecpar);
|
||||
if (ret < 0) {
|
||||
emit done(ErrorCopyStreamParameters);
|
||||
_clean_output_contexts(output_ctx);
|
||||
avformat_close_input(&input_ctx);
|
||||
return;
|
||||
}
|
||||
out_video_stream[s]->codecpar->codec_tag = 0;
|
||||
|
||||
// 나머지 스트림들 복사
|
||||
for (unsigned int i = 0; i < input_ctx->nb_streams; i++) {
|
||||
AVMediaType type = input_ctx->streams[i]->codecpar->codec_type;
|
||||
if (type == AVMEDIA_TYPE_AUDIO) {
|
||||
out_audio_stream[s] = avformat_new_stream(output_ctx[s], NULL);
|
||||
if (!out_audio_stream[s]) {
|
||||
emit done(ErrorCreateStream);
|
||||
_clean_output_contexts(output_ctx);
|
||||
avformat_close_input(&input_ctx);
|
||||
return;
|
||||
}
|
||||
ret = avcodec_parameters_copy(out_audio_stream[s]->codecpar, input_ctx->streams[i]->codecpar);
|
||||
if (ret < 0) {
|
||||
emit done(ErrorCopyStreamParameters);
|
||||
_clean_output_contexts(output_ctx);
|
||||
avformat_close_input(&input_ctx);
|
||||
return;
|
||||
}
|
||||
out_audio_stream[s]->codecpar->codec_tag = 0;
|
||||
}
|
||||
// 자막 스트림 복사
|
||||
if (type == AVMEDIA_TYPE_SUBTITLE) {
|
||||
out_subtitle_stream[s] = avformat_new_stream(output_ctx[s], NULL);
|
||||
if (!out_subtitle_stream[s]) {
|
||||
emit done(ErrorCreateStream);
|
||||
_clean_output_contexts(output_ctx);
|
||||
avformat_close_input(&input_ctx);
|
||||
return;
|
||||
}
|
||||
ret = avcodec_parameters_copy(out_subtitle_stream[s]->codecpar, input_ctx->streams[i]->codecpar);
|
||||
if (ret < 0) {
|
||||
emit done(ErrorCopyStreamParameters);
|
||||
_clean_output_contexts(output_ctx);
|
||||
avformat_close_input(&input_ctx);
|
||||
return;
|
||||
}
|
||||
out_subtitle_stream[s]->codecpar->codec_tag = 0;
|
||||
}
|
||||
} // 나머지 스트림 복사
|
||||
|
||||
// 출력 파일 헤더 쓰기
|
||||
av_dump_format(output_ctx[s], 0, dest, 1);
|
||||
|
||||
|
||||
|
||||
if (!(output_ctx[s]->oformat->flags & AVFMT_NOFILE)) {
|
||||
if (avio_open(&output_ctx[s]->pb, dest, AVIO_FLAG_WRITE) < 0) {
|
||||
emit done(ErrorFileWrite);
|
||||
_clean_output_contexts(output_ctx);
|
||||
avformat_close_input(&input_ctx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// major_brand를 'isom'으로 설정
|
||||
// AVDictionary *options = NULL;
|
||||
// av_dict_set(&options, "major_brand", "isom", 0);
|
||||
// av_dict_set(&options, "compatible_brands", "isomiso2avc1mp41", 0);
|
||||
//&options
|
||||
int res = avformat_write_header(output_ctx[s], NULL); // &options
|
||||
if (res < 0)
|
||||
{
|
||||
//char ebuffer[1024] = {0,};
|
||||
//av_strerror(res,ebuffer,1024);
|
||||
qInfo() << "VIDEO STREAM:" << s << " HEADER WRITE ERROR" << __FUNCTION__;
|
||||
emit done(ErrorFileWrite);
|
||||
_clean_output_contexts(output_ctx);
|
||||
avformat_close_input(&input_ctx);
|
||||
// av_dict_free(&options);
|
||||
return;
|
||||
}
|
||||
} // 파일 생성 및 스트림 정보 복사
|
||||
|
||||
// 패킷 복사
|
||||
AVPacket packet;
|
||||
|
||||
// for 문으로 처리시 처음으로 다시 돌아가는 기능 필요...
|
||||
// av_seek_frame(input_ctx, -1, 0, AVSEEK_FLAG_BACKWARD);
|
||||
|
||||
int frame_processed = 0; // Progress 처리
|
||||
while (av_read_frame(input_ctx, &packet) >= 0) {
|
||||
AVMediaType type = input_ctx->streams[packet.stream_index]->codecpar->codec_type;
|
||||
|
||||
// 입력 스트림과 출력 스트림의 타임베이스 정보를 가져옵니다.
|
||||
const AVRational& in_time_base = input_ctx->streams[packet.stream_index]->time_base;
|
||||
|
||||
if(type == AVMEDIA_TYPE_VIDEO) {
|
||||
|
||||
// video 순서 index 확인
|
||||
int vindex = _find_video_stream_index(packet.stream_index,video_stream_index);
|
||||
if(!video_stream_validation[vindex]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 시간계산 비디오 스트림 인덱스는 무조건 0
|
||||
const AVRational& out_time_base = output_ctx[vindex]->streams[0]->time_base;
|
||||
|
||||
// 모든 패킷 RESCALE 하지 않으면 재생시간 짧아짐
|
||||
packet.pts = av_rescale_q(packet.pts, in_time_base, out_time_base);
|
||||
packet.dts = av_rescale_q(packet.dts, in_time_base, out_time_base);
|
||||
packet.duration = av_rescale_q(packet.duration, in_time_base, out_time_base);
|
||||
|
||||
packet.stream_index = 0; // 출력 비디오 스트림 인덱스
|
||||
av_interleaved_write_frame(output_ctx[vindex], &packet);
|
||||
if(vindex == 0 && video_frame_count > 0) {
|
||||
frame_processed++;
|
||||
int percent = int (((double)frame_processed) / ((double)video_frame_count) * 100.0);
|
||||
emit progress(percent);
|
||||
//qInfo() << progress << __FUNCTION__;
|
||||
}
|
||||
} else if (type == AVMEDIA_TYPE_AUDIO) {
|
||||
|
||||
|
||||
// 패킷을 여러번 쓰기 위해서는 av_packet_clone 해서 처리해야함..
|
||||
for(int s=0;s<video_stream_count;s++) { // 모든 파일에 오디오 패킷 쓰기
|
||||
if(!video_stream_validation[s]) { // invalid video 스트림 SKIP
|
||||
continue;
|
||||
}
|
||||
|
||||
// 패킷 시간 RESCALE 처리해아함 // AUDIO STREAM INDEX 는 무조건 1
|
||||
const AVRational& out_time_base = output_ctx[s]->streams[1]->time_base;
|
||||
|
||||
AVPacket* cp = av_packet_clone(&packet);
|
||||
|
||||
// 모든 패킷 RESCALE 하지 않으면 재생시간 짧아짐
|
||||
cp->pts = av_rescale_q(cp->pts, in_time_base, out_time_base);
|
||||
cp->dts = av_rescale_q(cp->dts, in_time_base, out_time_base);
|
||||
cp->duration = av_rescale_q(cp->duration, in_time_base, out_time_base);
|
||||
|
||||
cp->stream_index = 1; //출력 오디오 스트림 인덱스
|
||||
av_interleaved_write_frame(output_ctx[s], cp);
|
||||
av_packet_free(&cp);
|
||||
}
|
||||
} else if (type == AVMEDIA_TYPE_SUBTITLE) {
|
||||
// AUDIO 가 존재하지 않을경우 1 존재할 경우 2
|
||||
const int subtitle_stream_index = audio_stream_index >= 0 ? 2 : 1;
|
||||
|
||||
|
||||
for(int s=0;s<video_stream_count;s++) { // 모든 파일에 자막 패킷 쓰기
|
||||
if(!video_stream_validation[s]) { // invalid video 스트림 SKIP
|
||||
continue;
|
||||
}
|
||||
|
||||
// 패킷 시간 RESCALE 처리해아함
|
||||
const AVRational& out_time_base = output_ctx[s]->streams[subtitle_stream_index]->time_base;
|
||||
|
||||
AVPacket* cp = av_packet_clone(&packet);
|
||||
// 모든 패킷 RESCALE 하지 않으면 재생시간 짧아짐 for 에서 누적되니 신규 packet 에만 처리
|
||||
cp->pts = av_rescale_q(cp->pts, in_time_base, out_time_base);
|
||||
cp->dts = av_rescale_q(cp->dts, in_time_base, out_time_base);
|
||||
cp->duration = av_rescale_q(cp->duration, in_time_base, out_time_base);
|
||||
|
||||
|
||||
cp->stream_index = subtitle_stream_index;
|
||||
av_interleaved_write_frame(output_ctx[s], cp);
|
||||
av_packet_free(&cp);
|
||||
}
|
||||
}
|
||||
av_packet_unref(&packet);
|
||||
}
|
||||
|
||||
for(int s=0;s<video_stream_count;s++) {
|
||||
if(!video_stream_validation[s]) { // invalid video 스트림 파일 SKIP
|
||||
continue;
|
||||
}
|
||||
// 트레일러 쓰기 및 파일 닫기
|
||||
av_write_trailer(output_ctx[s]);
|
||||
|
||||
if (!(output_ctx[s]->oformat->flags & AVFMT_NOFILE)) {
|
||||
avio_closep(&output_ctx[s]->pb);
|
||||
}
|
||||
//av_dict_free(&options);
|
||||
avformat_free_context(output_ctx[s]);
|
||||
}
|
||||
avformat_close_input(&input_ctx);
|
||||
|
||||
_afterProcess();
|
||||
emit done(ErrorNone);
|
||||
}
|
||||
void FMVideoEdit::_afterProcess()
|
||||
{
|
||||
if(_deleteSrcAfter) {
|
||||
for(int i=0;i<_files.size();i++) {
|
||||
QFile(_files.at(i)).remove();
|
||||
qInfo() << "DELETE:" << _files.at(i) << __FUNCTION__;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if (USE_LIB_MP4V2)
|
||||
void FMVideoEdit::_splitVideoTracks()
|
||||
{
|
||||
QString src = _files.first();
|
||||
|
||||
/* 최적화 하여 마지막 이상한 atom 제거해도 수정이 안됨
|
||||
QFileInfo fi = QFileInfo(src2);
|
||||
QString src = QDir::cleanPath(fi.dir().path() + QDir::separator() + fi.baseName() + "_2.mp4");
|
||||
if(!MP4Optimize(src2.toLocal8Bit().data(),src.toLocal8Bit().data())) {
|
||||
//qInfo() << "OPTIMIZE FAILED.." << __FUNCTION__;
|
||||
return;
|
||||
} */
|
||||
|
||||
MP4FileHandle inputFile = MP4Read(src.toLocal8Bit().data());
|
||||
if(MP4_INVALID_FILE_HANDLE == inputFile) {
|
||||
emit done(ErrorFileOpen);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t numTrack = MP4GetNumberOfTracks(inputFile,NULL,0);
|
||||
//qInfo() << QString(MP4Info(mp4File)) << __FUNCTION__;
|
||||
qInfo() << "numTrack" << numTrack << __FUNCTION__;
|
||||
QList<MP4TrackId> videoTracks = QList<MP4TrackId>();
|
||||
QList<MP4TrackId> otherTracks = QList<MP4TrackId>(); // 영상을 제외한 트랙들
|
||||
for(uint32_t i=0;i<numTrack;i++) {
|
||||
MP4TrackId tid = MP4FindTrackId (inputFile, i, NULL,0);
|
||||
const char* type = MP4GetTrackType(inputFile,tid);
|
||||
if(strcmp(type,MP4_VIDEO_TRACK_TYPE) == 0) {
|
||||
videoTracks.append(tid);
|
||||
qInfo() << "TRACK:" << i << " ID:" << tid << " TYPE:" << type << __FUNCTION__;
|
||||
} else if (strcmp(type,MP4_AUDIO_TRACK_TYPE) != 0) { // else { //
|
||||
// 오디오 트랙만 처리하면 atom size 에러가 발생함...
|
||||
otherTracks.append(tid);
|
||||
qInfo() << "OTHER TRACK:" << i << " ID:" << tid << " TYPE:" << type << __FUNCTION__;
|
||||
}
|
||||
}
|
||||
if(videoTracks.size() != _dests.size()) {
|
||||
emit done(ErrorWrongTrackCount);
|
||||
MP4Close(inputFile);
|
||||
}
|
||||
for(int i=0;i<_dests.size();i++) {
|
||||
QString dest = _dests.at(i);
|
||||
MP4FileHandle outputFile = MP4Create(dest.toLocal8Bit().data());
|
||||
if (outputFile == MP4_INVALID_FILE_HANDLE) {
|
||||
emit done(ErrorFileCreate);
|
||||
MP4Close(inputFile);
|
||||
return;
|
||||
}
|
||||
|
||||
// 입력 파일의 일반적인 정보를 출력 파일에 복사
|
||||
MP4SetTimeScale(outputFile, MP4GetTimeScale(inputFile));
|
||||
|
||||
QList<MP4TrackId> cloneTracks = QList<MP4TrackId>();
|
||||
cloneTracks.append(videoTracks.at(i)); // 영상 트랙
|
||||
cloneTracks.append(otherTracks); // 나머지 트랙(자막,메타,음성)
|
||||
qInfo() << "cloneTracks:" << cloneTracks << __FUNCTION__;
|
||||
|
||||
// 트랙 복제
|
||||
for (int j=0;j<cloneTracks.size();j++) {
|
||||
|
||||
MP4TrackId srcID = cloneTracks.at(j);
|
||||
MP4TrackId outputVideoTrackId = MP4CloneTrack(inputFile, srcID, outputFile);
|
||||
qInfo() << "CLONE TRACK SRC:" << srcID << " OUT:" << outputVideoTrackId << __FUNCTION__;
|
||||
if (outputVideoTrackId == MP4_INVALID_TRACK_ID) {
|
||||
MP4Close(inputFile);
|
||||
MP4Close(outputFile);
|
||||
emit done(ErrorTrackClone);
|
||||
return;
|
||||
}
|
||||
|
||||
// 샘플 복사
|
||||
uint32_t sampleId = 1;
|
||||
MP4SampleId sampleCount = MP4GetTrackNumberOfSamples(inputFile, srcID);
|
||||
while (sampleId <= sampleCount) {
|
||||
uint8_t* sampleData = nullptr;
|
||||
uint32_t sampleSize = 0;
|
||||
MP4Timestamp startTime = 0;
|
||||
MP4Duration sampleDuration = 0;
|
||||
if (MP4ReadSample(inputFile, srcID, sampleId, &sampleData, &sampleSize,&startTime, &sampleDuration)) {
|
||||
if (!MP4WriteSample(outputFile, outputVideoTrackId, sampleData, sampleSize, sampleDuration)) {
|
||||
emit done(ErrorWriteSample);
|
||||
MP4Free(sampleData);
|
||||
break;
|
||||
}
|
||||
MP4Free(sampleData);
|
||||
} else {
|
||||
emit done(ErrorReadSample);
|
||||
break;
|
||||
}
|
||||
sampleId++;
|
||||
}
|
||||
} // 각 트랙 복사
|
||||
MP4Close(outputFile);
|
||||
}
|
||||
MP4Close(inputFile);
|
||||
}
|
||||
#endif // #if (USE_LIB_MP4V2)
|
||||
|
||||
#endif // #if (FM_VIDEO_EDIT)
|
||||
|
||||
75
project/fm_viewer/data/fm_video_edit.h
Normal file
75
project/fm_viewer/data/fm_video_edit.h
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
#ifndef FM_VIDEO_EDIT_H
|
||||
#define FM_VIDEO_EDIT_H
|
||||
|
||||
#if (FM_VIDEO_EDIT)
|
||||
#include <QtCore>
|
||||
|
||||
/**
|
||||
* @brief 영상(MP4,AVI) 편집(FILE JOIN,TRACK SPLIT) 기능
|
||||
* @example
|
||||
* FMVideoEdit* ed = new FMVideoEdit(...,...);
|
||||
connect(sp, SIGNAL(done()), SLOT(onSplitVideoDone()));
|
||||
QThreadPool::globalInstance()->start(sp,LOADER_THREAD_PRIORITY);
|
||||
*/
|
||||
class FMVideoEdit : public QObject, public QRunnable
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum EditMode {
|
||||
FileJoin,
|
||||
VideoTrackSplit,
|
||||
};
|
||||
|
||||
enum ErrorCode {
|
||||
ErrorNone = 0,
|
||||
ErrorWrongTrackCount,
|
||||
ErrorFileOpen,
|
||||
ErrorOpenStream,
|
||||
ErrorFileCreate,
|
||||
ErrorCreateStream,
|
||||
ErrorCopyStreamParameters,
|
||||
ErrorFileWrite,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 생성
|
||||
* @param files: 처리할 파일경로(들) - 동일 포맷(+코덱,etc)만 가능
|
||||
* @param dests: 처리완료된 파일경로(들)
|
||||
* @param mode: 처리 모드
|
||||
*/
|
||||
FMVideoEdit(QStringList files, QStringList dests, EditMode mode, bool deleteSrcDone = true);
|
||||
virtual void run();
|
||||
private:
|
||||
QStringList _files; //! 처리할 파일(들)
|
||||
QStringList _dests; //! 처리 결과물 파일 경로(들)
|
||||
EditMode _mode; //! 처리 모드
|
||||
bool _deleteSrcAfter; //! 처리 완료 후 소스 영상 삭제
|
||||
|
||||
/**
|
||||
* @brief 멀티트랙 영상을 N개의 단일트랙 영상+오디오 파일로 저장
|
||||
*/
|
||||
void _splitMP4VideoTracks();
|
||||
|
||||
/**
|
||||
* @brief 처리 완료 후 진행
|
||||
* eg. 소스 파일 삭제 등
|
||||
*/
|
||||
void _afterProcess();
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief 처리완료 (또는 ERROR)
|
||||
* @param error: 에러코드, 0=성공
|
||||
*/
|
||||
void done(int error); //! 처리 완료 결과
|
||||
|
||||
/**
|
||||
* @brief 처리 경과
|
||||
* @param progress , 0~100%
|
||||
*/
|
||||
void progress(int progress); //! 처리 프로그래스
|
||||
};
|
||||
|
||||
#endif // FM_VIDEO_EDIT
|
||||
#endif // FM_VIDEO_EDIT_H
|
||||
1760
project/fm_viewer/data/rm_avirepair.cpp
Normal file
1760
project/fm_viewer/data/rm_avirepair.cpp
Normal file
File diff suppressed because it is too large
Load Diff
32
project/fm_viewer/data/rm_avirepair.h
Normal file
32
project/fm_viewer/data/rm_avirepair.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef RM_AVIREPAIR_H
|
||||
#define RM_AVIREPAIR_H
|
||||
|
||||
#include <QObject>
|
||||
//#include "rm_constants.h"
|
||||
|
||||
|
||||
class RMAVIRepair : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RMAVIRepair(QObject *parent = 0);
|
||||
static bool repair(QString& filePath, QString& destPath);
|
||||
#if (SUPPORT_AVI_FIX_DURL)
|
||||
static bool repairV50(QString& filePath, QString& destPath);
|
||||
#endif
|
||||
|
||||
static bool clipToPair(QString& filePath, QString& pairfilePath);
|
||||
#if (REPAIR_CHECK_SUBTITLE)
|
||||
// 파일명과 비교하여 30분이상 차이나면 처리하지 않음
|
||||
static bool compare_subtitle_time(QString& filePath, char* subtitle);
|
||||
#endif
|
||||
// 명칭뒤에 _f 추가
|
||||
#if (REPAIR_FAILED_TAG)
|
||||
static void rename_failed(QString& filePath);
|
||||
#endif
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
#endif // RM_AVIREPAIR_H
|
||||
29
project/fm_viewer/data/rm_format.h
Normal file
29
project/fm_viewer/data/rm_format.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef RM_FORMAT_H
|
||||
#define RM_FORMAT_H
|
||||
|
||||
#if !defined(BBEXTRACT)
|
||||
#include "../rm_include.h"
|
||||
#endif
|
||||
|
||||
typedef struct _VideoPreInfo {
|
||||
|
||||
bool bDuration;
|
||||
unsigned int duration;
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
bool bMOVSize;
|
||||
unsigned int movSize;
|
||||
#endif
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
} VideoPreInfo;
|
||||
|
||||
|
||||
typedef enum {
|
||||
VideoReadSensor = 0, // 센서 데이터 읽어 오기
|
||||
VideoReadDuration = 1, // 재생시간만 확인
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
VideoReadMOVSize = 2, // duration + 'mov' 크기 확인 (후방카메라 연결되지 않은경우 확인)
|
||||
#endif
|
||||
} VideoReadMode;
|
||||
|
||||
#endif // RM_FORMAT_H
|
||||
883
project/fm_viewer/data/rm_format_avi.cpp
Normal file
883
project/fm_viewer/data/rm_format_avi.cpp
Normal file
@@ -0,0 +1,883 @@
|
||||
#if (FILE_FORMAT_AVI)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(BBEXTRACT)
|
||||
|
||||
#include <QtCore>
|
||||
#include "rm_constants.h"
|
||||
|
||||
#if (APPLICATION_PROFILE)
|
||||
#include <QElapsedTimer>
|
||||
#include <QDebug>
|
||||
#endif
|
||||
|
||||
#endif //#if !defined(BBEXTRACT)
|
||||
|
||||
|
||||
|
||||
#include "rm_format_avi.h"
|
||||
extern "C" {
|
||||
#include "fileio.h"
|
||||
}
|
||||
|
||||
// 참조: https://github.com/masayukig/jpegtoavi/blob/master/aviformat.txt
|
||||
// http://telnet.or.kr/directx/htm/avirifffilereference.htm
|
||||
// http://blog.naver.com/PostView.nhn?blogId=shlee7708&logNo=120121689464 <- 제일 편함!!
|
||||
|
||||
//static int skip_chunk(FILE *in)
|
||||
//{
|
||||
//char chunk_id[5];
|
||||
//int chunk_size;
|
||||
//int end_of_chunk;
|
||||
|
||||
// read_chars(_file,chunk_id,4);
|
||||
// chunk_size=read_long(_file);
|
||||
|
||||
// printf("Uknown Chunk at %d\n",(int)ftell(_file));
|
||||
// printf("-------------------------------\n");q
|
||||
// printf(" chunk_id: %s\n",chunk_id);
|
||||
// printf(" chunk_size: %d\n",chunk_size);
|
||||
// printf("\n");
|
||||
|
||||
// end_of_chunk=ftell(_file)+chunk_size;
|
||||
// if ((end_of_chunk%4)!=0)
|
||||
// {
|
||||
// end_of_chunk=end_of_chunk+(4-(end_of_chunk%4));
|
||||
// }
|
||||
|
||||
// RMfseek(_file,end_of_chunk,SEEK_SET);
|
||||
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
//AVIRiff(RMfile in,bool durationOnly = false);
|
||||
AVIRiff::AVIRiff(RMfile in,VideoReadMode mode, VideoPreInfo* info)
|
||||
{
|
||||
_readMode = mode;
|
||||
_preInfo = info;
|
||||
|
||||
#if (SENSOR_AVI_SUBTITLE)
|
||||
subtitles = NULL;
|
||||
#endif
|
||||
|
||||
if(_preInfo != NULL) {
|
||||
_preInfo->bDuration = false;
|
||||
_preInfo->duration = 0;
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
_preInfo->movSize = 0;
|
||||
_preInfo->bMOVSize = false;
|
||||
#endif
|
||||
_preInfo->width = 0;
|
||||
_preInfo->height = 0;
|
||||
}
|
||||
_isValid = false;
|
||||
_file = in;
|
||||
_videoStreamCount = 0;
|
||||
|
||||
#if (AVI_CHUNHO_SENSOR_FORMAT_1)
|
||||
_gps_buffer = NULL;
|
||||
_sensor_buffer = NULL;
|
||||
_gps_buffer_size = 0;
|
||||
_sensor_buffer_size = 0;
|
||||
#endif
|
||||
parse_riff();
|
||||
|
||||
|
||||
}
|
||||
|
||||
AVIRiff::~AVIRiff()
|
||||
{
|
||||
for(int i=0;i<_videoStreamCount;i++)
|
||||
{
|
||||
if(_videoStreamFormat[i].palette != NULL)
|
||||
{
|
||||
free(_videoStreamFormat[i].palette);
|
||||
}
|
||||
}
|
||||
#if (AVI_CHUNHO_SENSOR_FORMAT_1)
|
||||
if(_gps_buffer != NULL)
|
||||
{
|
||||
free(_gps_buffer);
|
||||
}
|
||||
if(_sensor_buffer != NULL)
|
||||
{
|
||||
free(_sensor_buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (SENSOR_AVI_SUBTITLE)
|
||||
if(subtitles != NULL) {
|
||||
|
||||
for(int i=0;i<subtitles->size();i++) {
|
||||
free(subtitles->at(i));
|
||||
}
|
||||
delete subtitles;
|
||||
subtitles = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
int AVIRiff::hex_dump_chunk(int chunk_len)
|
||||
{
|
||||
#if (USE_AVI_DUMP)
|
||||
char chars[17];
|
||||
int ch,n;
|
||||
|
||||
chars[16]=0;
|
||||
|
||||
int line = 0;
|
||||
for (n=0; n<chunk_len; n++)
|
||||
{
|
||||
if ((n%16)==0)
|
||||
{
|
||||
if (n!=0)
|
||||
{
|
||||
printf("%s\n", chars);
|
||||
}
|
||||
printf("%04d ",line++);
|
||||
memset(chars, ' ', 16);
|
||||
}
|
||||
ch=getc(_file);
|
||||
if (ch==EOF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
printf("%02x ", ch);
|
||||
if (ch>=' ' && ch<=126)
|
||||
{
|
||||
chars[n%16]=ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
chars[n%16]='.';
|
||||
}
|
||||
}
|
||||
|
||||
if ((n%16)!=0)
|
||||
{
|
||||
for (ch=n%16; ch<16; ch++)
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf("%s\n", chars);
|
||||
#else
|
||||
#if !defined(BBEXTRACT)
|
||||
Q_UNUSED(chunk_len);
|
||||
#endif // #if !defined(BBEXTRACT)
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
int AVIRiff::parse_idx1(int chunk_len)
|
||||
{
|
||||
index_entry_t index_entry;
|
||||
int t;
|
||||
|
||||
printf(" IDX1\n");
|
||||
printf(" -------------------------------\n");
|
||||
printf(" ckid dwFlags dwChunkOffset dwChunkLength\n");
|
||||
|
||||
for (t=0; t<chunk_len/16; t++)
|
||||
{
|
||||
read_chars(_file,index_entry.ckid,4);
|
||||
index_entry.dwFlags=read_long(_file);
|
||||
index_entry.dwChunkOffset=read_long(_file);
|
||||
index_entry.dwChunkLength=read_long(_file);
|
||||
|
||||
printf(" %s 0x%08x 0x%08x 0x%08x\n",
|
||||
index_entry.ckid,
|
||||
index_entry.dwFlags,
|
||||
index_entry.dwChunkOffset,
|
||||
index_entry.dwChunkLength);
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int AVIRiff::read_avi_header() // ,struct avi_header_t *avi_header
|
||||
{
|
||||
// 연결되지 않은 영상 Bit rate : 121 kb/s
|
||||
// 연결된 영상 Bit rate : 4 493 kb/s
|
||||
|
||||
//long offset=ftell(_file);
|
||||
AVIHeader* avi_header = &_avi_header;
|
||||
|
||||
avi_header->TimeBetweenFrames=read_long(_file); // AVI TYPE 1 = 0
|
||||
avi_header->MaximumDataRate=read_long(_file);
|
||||
avi_header->PaddingGranularity=read_long(_file);
|
||||
avi_header->Flags=read_long(_file);
|
||||
avi_header->TotalNumberOfFrames=read_long(_file);
|
||||
avi_header->NumberOfInitialFrames=read_long(_file);
|
||||
avi_header->NumberOfStreams=read_long(_file);
|
||||
avi_header->SuggestedBufferSize=read_long(_file);
|
||||
avi_header->Width=read_long(_file);
|
||||
avi_header->Height=read_long(_file);
|
||||
avi_header->TimeScale=read_long(_file);
|
||||
avi_header->DataRate=read_long(_file);
|
||||
avi_header->StartTime=read_long(_file);
|
||||
avi_header->DataLength=read_long(_file);
|
||||
|
||||
if(_preInfo != NULL)
|
||||
{
|
||||
_preInfo->width = avi_header->Width;
|
||||
_preInfo->height = avi_header->Height;
|
||||
}
|
||||
|
||||
#if (DEBUG_AVI_HEADER)
|
||||
printf(" offset=0x%lx\n",offset);
|
||||
printf(" TimeBetweenFrames: %d\n",avi_header->TimeBetweenFrames);
|
||||
printf(" MaximumDataRate: %d\n",avi_header->MaximumDataRate);
|
||||
printf(" PaddingGranularity: %d\n",avi_header->PaddingGranularity);
|
||||
printf(" Flags: %d\n",avi_header->Flags);
|
||||
printf(" TotalNumberOfFrames: %d\n",avi_header->TotalNumberOfFrames);
|
||||
printf(" NumberOfInitialFrames: %d\n",avi_header->NumberOfInitialFrames);
|
||||
printf(" NumberOfStreams: %d\n",avi_header->NumberOfStreams);
|
||||
printf(" SuggestedBufferSize: %d\n",avi_header->SuggestedBufferSize);
|
||||
printf(" Width: %d\n",avi_header->Width);
|
||||
printf(" Height: %d\n",avi_header->Height);
|
||||
printf(" TimeScale: %d\n",avi_header->TimeScale);
|
||||
printf(" DataRate: %d\n",avi_header->DataRate);
|
||||
printf(" StartTime: %d\n",avi_header->StartTime);
|
||||
printf(" DataLength: %d\n",avi_header->DataLength);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AVIRiff::print_data_handler(unsigned char *handler)
|
||||
{
|
||||
int t;
|
||||
|
||||
for (t=0; t<4; t++)
|
||||
{
|
||||
if ((handler[t]>='a' && handler[t]<='z') ||
|
||||
(handler[t]>='A' && handler[t]<='Z') ||
|
||||
(handler[t]>='0' && handler[t]<='9'))
|
||||
{
|
||||
printf("%c",handler[t]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[0x%02x]",handler[t]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int AVIRiff::read_stream_header(stream_header_t *stream_header)
|
||||
{
|
||||
#if (DEBUG_AVI_STREAM_HEADER)
|
||||
long offset=ftell(_file);
|
||||
#endif
|
||||
|
||||
read_chars(_file,stream_header->DataType,4);
|
||||
read_chars(_file,stream_header->DataHandler,4);
|
||||
stream_header->Flags=read_long(_file);
|
||||
stream_header->Priority=read_long(_file);
|
||||
stream_header->InitialFrames=read_long(_file);
|
||||
stream_header->TimeScale=read_long(_file);
|
||||
stream_header->DataRate=read_long(_file);
|
||||
stream_header->StartTime=read_long(_file);
|
||||
stream_header->DataLength=read_long(_file);
|
||||
stream_header->SuggestedBufferSize=read_long(_file);
|
||||
stream_header->Quality=read_long(_file);
|
||||
stream_header->SampleSize=read_long(_file);
|
||||
|
||||
if(_preInfo != NULL) {
|
||||
if(_preInfo->duration == 0 && stream_header->TimeScale != 0)
|
||||
{
|
||||
_preInfo->bDuration = true;
|
||||
_preInfo->duration = (unsigned int)(((double)(stream_header->TimeScale * 1000) / (double)stream_header->DataRate) * (double)stream_header->DataLength);
|
||||
}
|
||||
}
|
||||
|
||||
#if (DEBUG_AVI_STREAM_HEADER)
|
||||
printf("------------------------------------------------------------\n");
|
||||
printf(" offset=0x%lx\n",offset);
|
||||
printf(" DataType: %s\n",stream_header->DataType);
|
||||
printf(" DataHandler: ");
|
||||
print_data_handler((unsigned char *)stream_header->DataHandler);
|
||||
printf("\n");
|
||||
printf(" Flags: %d\n",stream_header->Flags);
|
||||
printf(" Priority: %d\n",stream_header->Priority);
|
||||
printf(" InitialFrames: %d\n",stream_header->InitialFrames);
|
||||
printf(" TimeScale: %d\n",stream_header->TimeScale);
|
||||
printf(" DataRate: %d\n",stream_header->DataRate);
|
||||
printf(" StartTime: %d\n",stream_header->StartTime);
|
||||
printf(" DataLength: %d\n",stream_header->DataLength);
|
||||
printf(" SuggestedBufferSize: %d\n",stream_header->SuggestedBufferSize);
|
||||
printf(" Quality: %d\n",stream_header->Quality);
|
||||
printf(" SampleSize: %d\n",stream_header->SampleSize);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AVIRiff::read_stream_format(stream_format_t *stream_format)
|
||||
{
|
||||
int t,r,g,b;
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
long offset=ftell(_file);
|
||||
#endif
|
||||
|
||||
stream_format->header_size=read_long(_file);
|
||||
stream_format->image_width=read_long(_file);
|
||||
stream_format->image_height=read_long(_file);
|
||||
stream_format->number_of_planes=read_word(_file);
|
||||
stream_format->bits_per_pixel=read_word(_file);
|
||||
stream_format->compression_type=read_long(_file);
|
||||
stream_format->image_size_in_bytes=read_long(_file);
|
||||
stream_format->x_pels_per_meter=read_long(_file);
|
||||
stream_format->y_pels_per_meter=read_long(_file);
|
||||
stream_format->colors_used=read_long(_file);
|
||||
stream_format->colors_important=read_long(_file);
|
||||
stream_format->palette=0;
|
||||
|
||||
if (stream_format->colors_important!=0)
|
||||
{
|
||||
stream_format->palette= (int*) malloc(stream_format->colors_important*sizeof(int));
|
||||
for (t=0; t<stream_format->colors_important; t++)
|
||||
{
|
||||
b=RMgetc(_file);
|
||||
g=RMgetc(_file);
|
||||
r=RMgetc(_file);
|
||||
stream_format->palette[t]=(r<<16)+(g<<8)+b;
|
||||
}
|
||||
}
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" offset=0x%lx\n",offset);
|
||||
printf(" header_size: %d\n",stream_format->header_size);
|
||||
printf(" image_width: %d\n",stream_format->image_width);
|
||||
printf(" image_height: %d\n",stream_format->image_height);
|
||||
printf(" number_of_planes: %d\n",stream_format->number_of_planes);
|
||||
printf(" bits_per_pixel: %d\n",stream_format->bits_per_pixel);
|
||||
printf(" compression_type: %04x (%c%c%c%c)\n",stream_format->compression_type,
|
||||
((stream_format->compression_type)&255),
|
||||
((stream_format->compression_type>>8)&255),
|
||||
((stream_format->compression_type>>16)&255),
|
||||
((stream_format->compression_type>>24)&255));
|
||||
printf(" image_size_in_bytes: %d\n",stream_format->image_size_in_bytes);
|
||||
printf(" x_pels_per_meter: %d\n",stream_format->x_pels_per_meter);
|
||||
printf(" y_pels_per_meter: %d\n",stream_format->y_pels_per_meter);
|
||||
printf(" colors_used: %d\n",stream_format->colors_used);
|
||||
printf(" colors_important: %d\n",stream_format->colors_important);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AVIRiff::read_stream_format_auds(stream_format_auds_t *stream_format)
|
||||
{
|
||||
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
long offset=RMftell(_file);
|
||||
#endif
|
||||
|
||||
stream_format->format=read_word(_file);
|
||||
stream_format->channels=read_word(_file);
|
||||
stream_format->samples_per_second=read_long(_file);
|
||||
stream_format->bytes_per_second=read_long(_file);
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
int block_align=read_word(_file);
|
||||
#endif
|
||||
stream_format->block_size_of_data=read_word(_file);
|
||||
stream_format->bits_per_sample=read_word(_file);
|
||||
//stream_format->extended_size=read_word(_file);
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" offset=0x%lx\n",offset);
|
||||
printf(" format: %d\n",stream_format->format);
|
||||
printf(" channels: %d\n",stream_format->channels);
|
||||
printf(" samples_per_second: %d\n",stream_format->samples_per_second);
|
||||
printf(" bytes_per_second: %d\n",stream_format->bytes_per_second);
|
||||
printf(" block_align: %d\n",block_align);
|
||||
printf(" block_size_of_data: %d\n",stream_format->block_size_of_data);
|
||||
printf(" bits_per_sample: %d\n",stream_format->bits_per_sample);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AVIRiff::parse_hdrl_list()
|
||||
{
|
||||
// stream_format_auds_t stream_format_auds;
|
||||
// stream_header_t stream_header_auds;
|
||||
char chunk_id[5];
|
||||
int chunk_size;
|
||||
char chunk_type[5];
|
||||
int end_of_chunk;
|
||||
int next_chunk;
|
||||
//long offset=RMftell(_file);
|
||||
|
||||
AVI_STREAM_TYPE stream_type = UNDEFINED_STREAM;
|
||||
|
||||
read_chars(_file,chunk_id,4);
|
||||
chunk_size=read_long(_file);
|
||||
read_chars(_file,chunk_type,4);
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" AVI Header LIST (id=%s size=%d type=%s offset=0x%lx)\n",chunk_id,chunk_size,chunk_type,offset);
|
||||
printf(" {\n");
|
||||
#endif
|
||||
|
||||
end_of_chunk=RMftell(_file)+chunk_size-4;
|
||||
if ((end_of_chunk%4)!=0)
|
||||
{
|
||||
//printf("Adjusting end of chunk %d\n", end_of_chunk);
|
||||
//end_of_chunk=end_of_chunk+(4-(end_of_chunk%4));
|
||||
//printf("Adjusting end of chunk %d\n", end_of_chunk);
|
||||
}
|
||||
|
||||
if (strcmp(chunk_id,"JUNK")==0)
|
||||
{
|
||||
RMfseek(_file,end_of_chunk,SEEK_SET);
|
||||
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" }\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
while (RMftell(_file)<end_of_chunk)
|
||||
{
|
||||
//long offset=RMftell(_file);
|
||||
|
||||
read_chars(_file,chunk_type,4);
|
||||
chunk_size=read_long(_file);
|
||||
next_chunk=RMftell(_file)+chunk_size;
|
||||
if ((chunk_size%4)!=0)
|
||||
{
|
||||
//printf("Chunk size not a multiple of 4?\n");
|
||||
//chunk_size=chunk_size+(4-(chunk_size%4));
|
||||
}
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" %.4s (size=%d offset=0x%lx)\n",chunk_type,chunk_size,offset);
|
||||
printf(" {\n");
|
||||
#endif
|
||||
if (strcasecmp("strh",chunk_type)==0)
|
||||
{
|
||||
long marker=RMftell(_file);
|
||||
char buffer[5];
|
||||
read_chars(_file,buffer,4);
|
||||
RMfseek(_file,marker,SEEK_SET);
|
||||
|
||||
if (strcmp(buffer, "vids")==0)
|
||||
{
|
||||
stream_type = VIDEO_STREAM;
|
||||
|
||||
read_stream_header(&_videoStreamHeaders[_videoStreamCount]); // format 읽은후에 ++
|
||||
}
|
||||
else if (strcmp(buffer, "auds")==0)
|
||||
{
|
||||
stream_type = AUDIO_STREAM;
|
||||
read_stream_header(&_audioStreamHeader);
|
||||
}
|
||||
else if (strcmp(buffer, "txts")==0)
|
||||
{
|
||||
stream_type = TXT_STREAM;
|
||||
read_stream_header(&_txtStreamHeader);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf("Unknown stream type %s\n", buffer);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (strcasecmp("strf",chunk_type)==0)
|
||||
{
|
||||
if (stream_type == VIDEO_STREAM)
|
||||
{
|
||||
read_stream_format(&_videoStreamFormat[_videoStreamCount]);
|
||||
_videoStreamCount++;
|
||||
}
|
||||
else if (stream_type==1)
|
||||
{
|
||||
read_stream_format_auds(&_audioStreamFormat);
|
||||
}
|
||||
else if (stream_type==2) // subtitle
|
||||
{
|
||||
// STRF 에는 아무 정보도 없음
|
||||
//hex_dump_chunk(in,371);
|
||||
//read_stream_format_auds(in,&stream_format_auds);
|
||||
}
|
||||
|
||||
}
|
||||
else if (strcasecmp("strd",chunk_type)==0)
|
||||
{
|
||||
//RMfseek(_file,offset,SEEK_SET);
|
||||
//read_strd_format(chunk_size);
|
||||
//_stopProcessing = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" Unknown chunk type: %s\n",chunk_type);
|
||||
#endif
|
||||
// skip_chunk(_file);
|
||||
}
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" }\n");
|
||||
#endif
|
||||
RMfseek(_file,next_chunk,SEEK_SET);
|
||||
}
|
||||
//printf("@@@@ %ld %d\n", RMftell(_file), end_of_chunk);
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" }\n");
|
||||
#endif
|
||||
RMfseek(_file,end_of_chunk,SEEK_SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (SENSOR_AVI_SUBTITLE)
|
||||
// 자막 데이터 AVI TYPE2
|
||||
int AVIRiff::add_subtitle(long chunkSize)
|
||||
{
|
||||
if(subtitles == NULL) {
|
||||
subtitles = new QList<char*>();
|
||||
}
|
||||
|
||||
char* buffer = (char*)malloc(chunkSize + 1);
|
||||
memset(buffer,0,chunkSize + 1);
|
||||
RMfread(buffer,chunkSize,1,_file);
|
||||
//qInfo() << buffer;
|
||||
//QString str = QString(buffer);
|
||||
subtitles->append(buffer);
|
||||
//free(buffer);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int AVIRiff::parse_movi_list(unsigned int size)
|
||||
{
|
||||
#if (APPLICATION_PROFILE)
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
#endif
|
||||
|
||||
char chunk_id[5] = {0,};
|
||||
long chunk_size;
|
||||
long end_of_chunk;
|
||||
|
||||
long offset=RMftell(_file);
|
||||
#if (DEBUG_AVI_MOVI)
|
||||
printf(" AVI MOVI Chunk (id=%s size=%d offset=0x%lx)\n",chunk_id,chunk_size,offset);
|
||||
printf(" {\n");
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
//int txtCount = 0;
|
||||
while(RMftell(_file)< offset+(long)size-4)
|
||||
{
|
||||
|
||||
read_chars(_file,chunk_id,4); // 4 byte
|
||||
chunk_size=read_long(_file); // 4 byte
|
||||
|
||||
// pack 하지 않는다.. 다음 chunk 의 chunk_id + size 제외하고 이동
|
||||
end_of_chunk= RMftell(_file) + chunk_size;
|
||||
|
||||
// H265 AVI 는 2 BYTE pack 되어 있음..
|
||||
if ((end_of_chunk % 2) == 1)
|
||||
{
|
||||
end_of_chunk += 1;
|
||||
}
|
||||
|
||||
if(chunk_id[2] == 't' && chunk_id[3] == 'x')
|
||||
{
|
||||
#if (SENSOR_AVI_SUBTITLE)
|
||||
add_subtitle(chunk_size);
|
||||
#endif
|
||||
|
||||
#if (DEBUG_AVI_MOVI)
|
||||
printf(" MOVI TXT (id(%04d)=%s size=%d offset=%ld)\n",txtCount++,chunk_id,chunk_size,ftell(_file));
|
||||
// hex_dump_chunk(chunk_size);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// 이후 NAL SEI 처리 기능 추가
|
||||
}
|
||||
RMfseek(_file,end_of_chunk,SEEK_SET);
|
||||
}
|
||||
#if (DEBUG_AVI_MOVI)
|
||||
printf(" }\n");
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
#if (APPLICATION_PROFILE)
|
||||
qInfo () << "Elapsed Time(parse_movi_list):" << timer.elapsed() << " msec" << " count:" << txtCount;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
//int AVIRiff::parse_hdrl(stream_format_t *stream_format, unsigned int size)
|
||||
int AVIRiff::parse_hdrl(unsigned int size)
|
||||
{
|
||||
char chunk_id[5];
|
||||
long chunk_size;
|
||||
long end_of_chunk;
|
||||
long offset=RMftell(_file);
|
||||
|
||||
read_chars(_file,chunk_id,4);
|
||||
chunk_size=read_long(_file);
|
||||
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" AVI Header Chunk (id=%s size=%d offset=0x%lx)\n",chunk_id,chunk_size,offset);
|
||||
printf(" {\n");
|
||||
#endif
|
||||
|
||||
end_of_chunk=RMftell(_file)+chunk_size;
|
||||
if ((end_of_chunk%4)!=0) // 4BYTE PACK
|
||||
{
|
||||
end_of_chunk=end_of_chunk+(4-(end_of_chunk%4));
|
||||
}
|
||||
|
||||
read_avi_header(); // 메인 헤더 읽기
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" }\n");
|
||||
#endif
|
||||
while(RMftell(_file)<offset+(long)size-4)
|
||||
{
|
||||
//printf("Should end at 0x%lx 0x%lx\n",offset+size,RMftell(_file));
|
||||
parse_hdrl_list();
|
||||
//parse_hdrl_list(stream_header,stream_format);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AVIRiff::parse_riff()
|
||||
{
|
||||
_isValid = false; // TAG 문제시만..
|
||||
|
||||
// 개별 chunk 처리
|
||||
char chunk_id[5] = {0,};
|
||||
int chunk_size;
|
||||
char chunk_type[5] = {0,};
|
||||
|
||||
int end_of_chunk, end_of_subchunk;
|
||||
|
||||
//struct avi_header_t avi_header;
|
||||
|
||||
|
||||
// stream_header_t stream_header;
|
||||
// stream_format_t stream_format={0};
|
||||
|
||||
read_chars(_file,chunk_id,4);
|
||||
chunk_size=read_long(_file);
|
||||
read_chars(_file,chunk_type,4);
|
||||
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
long offset=RMftell(_file);
|
||||
printf("RIFF Chunk (id=%s size=%d type=%s offset=0x%lx)\n",chunk_id,chunk_size,chunk_type, offset);
|
||||
printf("{\n");
|
||||
#endif
|
||||
|
||||
if (strcasecmp("RIFF",chunk_id)!=0)
|
||||
{
|
||||
//printf("Not a RIFF file.\n");
|
||||
return 1;
|
||||
}
|
||||
else if (strcasecmp("AVI ",chunk_type)!=0)
|
||||
{
|
||||
//printf("Not an AVI file.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
end_of_chunk=RMftell(_file)+chunk_size-4;
|
||||
|
||||
#if (AVI_CHUNHO_SENSOR_FORMAT_1)
|
||||
// Sensor 는 STRD 와 유사하게 end_of_chunk 뒤에 위치함
|
||||
if(_preInfo == NULL)
|
||||
{
|
||||
RMfseek(_file,end_of_chunk,SEEK_SET);
|
||||
|
||||
bool b_gps_read = false;
|
||||
bool b_sensor_read = false;
|
||||
|
||||
// 파일 끝까지 확인
|
||||
int tryCount = 0;
|
||||
while (RMfeof(_file) == 0 && tryCount++ < 100)
|
||||
{
|
||||
int offset = RMftell(_file);
|
||||
#if !defined(BBEXTRACT)
|
||||
QString offsetStr;
|
||||
offsetStr.sprintf("%08X",offset);
|
||||
#endif
|
||||
read_chars(_file,chunk_id,4); // ID
|
||||
chunk_size=read_long(_file); // 크기
|
||||
|
||||
// 센서 데이터 깨진 파일이 존재함 (chunck offset 이 짧거나..)
|
||||
// qInfo() << "chunk_id:" << chunk_id << " chunk_size:" << chunk_size << " offset:" << offsetStr;
|
||||
|
||||
//end_of_subchunk=RMftell(_file)+chunk_size; // 범위 지정
|
||||
|
||||
//IDIT : 9355386 = 20
|
||||
//gpsa : 9355398 = 4
|
||||
//gps0 : 9357326 = 1920
|
||||
//gsea : 9357354 = 20
|
||||
//gsen : 9361576 = 4214
|
||||
// 14 BYTE
|
||||
if (strcasecmp("gps0",chunk_id)==0)
|
||||
{
|
||||
_gps_buffer_size = chunk_size;
|
||||
_gps_buffer = (uint8_t*)malloc(chunk_size);
|
||||
RMfread(_gps_buffer,_gps_buffer_size,1,_file);
|
||||
b_gps_read = true;
|
||||
}
|
||||
else if (strcasecmp("gsen",chunk_id)==0)
|
||||
{
|
||||
if(chunk_size > 0) {
|
||||
//qInfo() << "gsen offset:" << offsetStr;
|
||||
_sensor_buffer_size = chunk_size;
|
||||
_sensor_buffer = (uint8_t*)malloc(chunk_size);
|
||||
RMfread(_sensor_buffer,_sensor_buffer_size,1,_file);
|
||||
b_sensor_read = true;
|
||||
}
|
||||
}
|
||||
// 깨진 데이터는 1 BYTE 씩 탐색
|
||||
else if(chunk_size < 0 ||
|
||||
(strcasecmp("IDIT",chunk_id) != 0 &&
|
||||
strcasecmp("gpsa",chunk_id) != 0 &&
|
||||
strcasecmp("gsea",chunk_id) != 0)) {
|
||||
chunk_size = -7;
|
||||
}
|
||||
end_of_subchunk = offset + 8 + chunk_size;
|
||||
|
||||
if(b_sensor_read && b_gps_read)
|
||||
{
|
||||
break;
|
||||
}
|
||||
//qInfo() << chunk_id << ":" << end_of_subchunk << " =" << chunk_size;
|
||||
RMfseek(_file,end_of_subchunk,SEEK_SET);
|
||||
}
|
||||
_isValid = true;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
while (RMftell(_file)<end_of_chunk)
|
||||
{
|
||||
read_chars(_file,chunk_id,4); // ID
|
||||
chunk_size=read_long(_file); // 크기
|
||||
end_of_subchunk=RMftell(_file)+chunk_size; // 범위 지정
|
||||
|
||||
if (strcasecmp("JUNK",chunk_id)==0 || strcasecmp("PAD ",chunk_id)==0) // ID 가 JUNK 또는 PAD 일 경우 ...
|
||||
{
|
||||
chunk_type[0]=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_chars(_file,chunk_type,4); // 타입이 존재할 경우
|
||||
}
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
long offset=RMftell(_file); // 현재 옵셋
|
||||
printf(" New Chunk (id=%s size=%d type=%s offset=0x%lx)\n",chunk_id,chunk_size,chunk_type,offset);
|
||||
printf(" {\n");
|
||||
fflush(stdout);
|
||||
#endif
|
||||
if (strcasecmp("JUNK",chunk_id)==0 || strcasecmp("PAD ",chunk_id)==0) // 사용되지 않음
|
||||
{
|
||||
if ((chunk_size%4)!=0)
|
||||
{
|
||||
chunk_size=chunk_size+(4-(chunk_size%4));
|
||||
}
|
||||
#if (DEBUG_AVI_JUNK)
|
||||
hex_dump_chunk(chunk_size);
|
||||
#endif
|
||||
}
|
||||
else if (strcasecmp("INFO",chunk_type)==0) // 사용되지 않음..
|
||||
{
|
||||
if ((chunk_size%4)!=0)
|
||||
{
|
||||
chunk_size=chunk_size+(4-(chunk_size%4));
|
||||
}
|
||||
#if (DEBUG_AVI_INFO)
|
||||
hex_dump_chunk(chunk_size);
|
||||
#endif
|
||||
}
|
||||
else if (strcasecmp("hdrl",chunk_type)==0) // 헤더 리스트 처리
|
||||
{
|
||||
parse_hdrl(chunk_size);
|
||||
// 기본 모드가 아닐 경우 종료 (subtitle 모델 체크는 subtitle 확인해야함)
|
||||
// skip_chunk(_file);
|
||||
}
|
||||
else if (strcasecmp("movi",chunk_type)==0) // 'movi' 리스트 처리
|
||||
{
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
if(_readMode == AVIReadMOVSize && _preInfo != NULL) {
|
||||
_preInfo->bMOVSize = true;
|
||||
_preInfo->movSize = chunk_size;
|
||||
}
|
||||
#endif
|
||||
// 처리할 필요 없음
|
||||
#if (SENSOR_AVI_SUBTITLE)
|
||||
if(_readMode == VideoReadSensor) {
|
||||
parse_movi_list(chunk_size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (strcasecmp("idx1",chunk_id)==0) // 인덱스 처리
|
||||
{
|
||||
RMfseek(_file,RMftell(_file)-4,SEEK_SET);
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
parse_idx1(chunk_size);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" Unknown chunk at %d (%4s)\n",(int)RMftell(_file)-8,chunk_type);
|
||||
#endif
|
||||
if (chunk_size==0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 필요한 정보 모두 수집되었는지 확인
|
||||
if(_readMode == VideoReadDuration && _preInfo != NULL && _preInfo->bDuration == true) {
|
||||
_isValid = true;
|
||||
return 0;
|
||||
}
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
else if(_readMode == VideoReadMOVSize && _preInfo != NULL && _preInfo->bDuration == true && _preInfo->bMOVSize)
|
||||
{
|
||||
_isValid = true;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
RMfseek(_file,end_of_subchunk,SEEK_SET);
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf(" }\n");
|
||||
#endif
|
||||
}
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
printf("}\n");
|
||||
#endif
|
||||
_isValid = true;
|
||||
return 0;
|
||||
}
|
||||
bool AVIRiff::duration(RMfile in, VideoPreInfo* info)
|
||||
{
|
||||
AVIRiff avi = AVIRiff(in,VideoReadDuration,info);
|
||||
return avi.isValid();
|
||||
}
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
bool AVIRiff::movSize(RMfile in, VideoPreInfo* info)
|
||||
{
|
||||
AVIRiff avi = AVIRiff(in,VideoReadMOVSize,info);
|
||||
return avi.isValid();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #if (FILE_FORMAT_AVI)
|
||||
263
project/fm_viewer/data/rm_format_avi.h
Normal file
263
project/fm_viewer/data/rm_format_avi.h
Normal file
@@ -0,0 +1,263 @@
|
||||
#ifndef RM_FORMAT_AVI_H
|
||||
#define RM_FORMAT_AVI_H
|
||||
|
||||
#if (FILE_FORMAT_AVI)
|
||||
|
||||
#if !defined(BBEXTRACT)
|
||||
#include "../rm_include.h"
|
||||
#include <QString>
|
||||
#endif
|
||||
#include "rm_format.h"
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include "fileio.h"
|
||||
}
|
||||
|
||||
// DEBUG 용
|
||||
#define DEBUG_AVI_FORMAT 0
|
||||
#define USE_AVI_DUMP 0
|
||||
#define DEBUG_AVI_JUNK 0
|
||||
#define DEBUG_AVI_INFO 0
|
||||
#define DEBUG_AVI_HEADER 0 // 메인헤더
|
||||
#define DEBUG_AVI_STREAM_HEADER 0 // 스트림 헤더
|
||||
#define DEBUG_AVI_MOVI 0 // 스트림 데이터 리스트
|
||||
|
||||
// http://www.econote.co.kr/main/view_post.asp?post_seq_no=49407 정리 잘 되어 있음
|
||||
// AVI RIFF 구조는
|
||||
// RIFF
|
||||
// - hdrl(LIST)
|
||||
// - avih : AVI 파일 전체 기본 정보
|
||||
// - strl (LIST)
|
||||
// - strh (vids) : 영상 스트림 헤더
|
||||
// - strf " 포멧
|
||||
// - strl (LIST)
|
||||
// - strh (auds) : 음성 스트림 헤더
|
||||
// - strf " 포멧
|
||||
// - strl (LIST)
|
||||
// - strh (txts) : 자막 스트림 헤더
|
||||
// - strf " 포멧
|
||||
// - IDIT
|
||||
// - INFO(LIST) : 정보
|
||||
// -ISFT : 업체정보
|
||||
// - movi(LIST) : 실제 데이터
|
||||
// - 00dc/b : 음성패킷 (c:압축,b:비압축)
|
||||
// - 00wb/c : 영상패킷 (")
|
||||
// - 00tx : 자막
|
||||
// - idx1: 프레임의 위치 (binary 로 01wb,flag,offset,size ..... 00dc,flat,offset,size..
|
||||
|
||||
#define MAX_VIDEO_STREAM_COUNT 4
|
||||
|
||||
// TimeScale 등이 0 라 재생시간 처리에 문제가 생김
|
||||
|
||||
// avi 정보 (AVI Header,'avih')
|
||||
typedef struct _AVIHeader
|
||||
{
|
||||
int TimeBetweenFrames;
|
||||
int MaximumDataRate;
|
||||
int PaddingGranularity;
|
||||
int Flags;
|
||||
int TotalNumberOfFrames;
|
||||
int NumberOfInitialFrames;
|
||||
int NumberOfStreams;
|
||||
int SuggestedBufferSize;
|
||||
int Width;
|
||||
int Height;
|
||||
int TimeScale;
|
||||
int DataRate;
|
||||
int StartTime;
|
||||
int DataLength;
|
||||
} AVIHeader;
|
||||
|
||||
// str(eam) 정보 (Stream Header,'strh') / Video('vids')
|
||||
typedef struct _STRHeader
|
||||
{
|
||||
char DataType[5];
|
||||
char DataHandler[5];
|
||||
int Flags;
|
||||
int Priority;
|
||||
int InitialFrames;
|
||||
int TimeScale;
|
||||
int DataRate;
|
||||
int StartTime;
|
||||
int DataLength;
|
||||
int SuggestedBufferSize;
|
||||
int Quality;
|
||||
int SampleSize;
|
||||
|
||||
} stream_header_t;
|
||||
|
||||
// str(eam) 포멧 (Stream Format,'strf') / Video('vids')
|
||||
typedef struct _STRFormat
|
||||
{
|
||||
int header_size;
|
||||
int image_width;
|
||||
int image_height;
|
||||
int number_of_planes;
|
||||
int bits_per_pixel;
|
||||
int compression_type;
|
||||
int image_size_in_bytes;
|
||||
int x_pels_per_meter;
|
||||
int y_pels_per_meter;
|
||||
int colors_used;
|
||||
int colors_important;
|
||||
int *palette;
|
||||
|
||||
} stream_format_t;
|
||||
|
||||
// str(eam) 정보 (Stream Header,'strh') / Audio('auds')
|
||||
typedef struct _STRHeaderAudio
|
||||
{
|
||||
int format_type;
|
||||
int number_of_channels;
|
||||
int sample_rate;
|
||||
int bytes_per_second;
|
||||
int block_size_of_data;
|
||||
int bits_per_sample;
|
||||
int byte_count_extended;
|
||||
|
||||
}stream_header_auds_t;
|
||||
|
||||
// str(eam) 포멧 (Stream Format,'strf') / Video('auds')
|
||||
typedef struct _STRFormatAudio
|
||||
{
|
||||
int header_size;
|
||||
int format;
|
||||
int channels;
|
||||
int samples_per_second;
|
||||
int bytes_per_second;
|
||||
int block_size_of_data;
|
||||
int bits_per_sample;
|
||||
int extended_size;
|
||||
|
||||
} stream_format_auds_t;
|
||||
|
||||
// 인덱스 구조 ('idx1')
|
||||
typedef struct _AVIDX
|
||||
{
|
||||
char ckid[5];
|
||||
int dwFlags;
|
||||
int dwChunkOffset;
|
||||
int dwChunkLength;
|
||||
} index_entry_t;
|
||||
|
||||
|
||||
|
||||
|
||||
class AVIRiff
|
||||
{
|
||||
private:
|
||||
VideoReadMode _readMode; // 현재 모드
|
||||
VideoPreInfo* _preInfo; // 기본 정보 (존재할 경우 ReadMode == PreInfo)
|
||||
bool _isValid; // 센서 관련?
|
||||
|
||||
|
||||
public:
|
||||
|
||||
#if (SENSOR_AVI_SUBTITLE)
|
||||
QList<char*>* subtitles; // 자막 센서 포멧
|
||||
#endif
|
||||
|
||||
|
||||
AVIRiff(RMfile in,VideoReadMode mode = VideoReadSensor, VideoPreInfo* info = NULL);
|
||||
|
||||
|
||||
static bool duration(RMfile in,VideoPreInfo* info);
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
static bool movSize(RMfile in,VideoPreInfo* info);
|
||||
#endif
|
||||
~AVIRiff();
|
||||
|
||||
bool isValid()
|
||||
{
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
// MOV 크기와 재생시간 그리고 오디오 bitrate (kb/sec) 를 입력받아 mov bitrate 를 계산한다
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
static int videoBitrate(VideoPreInfo* info, double audioBitrate = 256) {
|
||||
|
||||
const double kb = 1000.0; // 1024?
|
||||
const double durationInSec = (double)(info->duration) / 1000.0;
|
||||
double audioSize = durationInSec * audioBitrate * kb / 8.0; // kb SEC
|
||||
double videoSize = (double)(info->movSize) - audioSize;
|
||||
return videoSize * 8.0 / durationInSec / kb;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (AVI_CHUNHO_SENSOR_FORMAT_1)
|
||||
uint8_t* _gps_buffer;
|
||||
size_t _gps_buffer_size;
|
||||
uint8_t* _sensor_buffer;
|
||||
size_t _sensor_buffer_size;
|
||||
|
||||
void getChunckData(uint8_t** gps,size_t* gps_size,uint8_t** sensor,size_t* sensor_size)
|
||||
{
|
||||
*gps = _gps_buffer;
|
||||
*sensor = _sensor_buffer;
|
||||
*gps_size = _gps_buffer_size;
|
||||
*sensor_size = _sensor_buffer_size;
|
||||
}
|
||||
#endif
|
||||
typedef enum
|
||||
{
|
||||
UNDEFINED_STREAM = 0,
|
||||
VIDEO_STREAM,
|
||||
AUDIO_STREAM,
|
||||
TXT_STREAM,
|
||||
} AVI_STREAM_TYPE;
|
||||
|
||||
RMfile _file;
|
||||
|
||||
AVIHeader _avi_header; // 파일헤더
|
||||
|
||||
stream_header_t _audioStreamHeader;
|
||||
stream_format_auds_t _audioStreamFormat;
|
||||
|
||||
int _videoStreamCount; // 현재까지 로딩된 입력된 스트림 인덱스
|
||||
stream_header_t _videoStreamHeaders[MAX_VIDEO_STREAM_COUNT]; // N개
|
||||
stream_format_t _videoStreamFormat[MAX_VIDEO_STREAM_COUNT];
|
||||
|
||||
stream_header_t _txtStreamHeader; // TXT 스트림 헤더
|
||||
|
||||
int parse_riff();
|
||||
int hex_dump_chunk(int chunk_len);
|
||||
|
||||
#if (DEBUG_AVI_FORMAT)
|
||||
int parse_idx1(int chunk_len);
|
||||
#endif
|
||||
|
||||
int read_avi_header(); // 메인 헤더
|
||||
|
||||
#if (SENSOR_AVI_SUBTITLE)
|
||||
int add_subtitle(long chunkSize); // 자막 처리
|
||||
#endif
|
||||
|
||||
void print_data_handler(unsigned char *handler); // Data Handler 출력 (DEBUG)
|
||||
|
||||
int read_stream_header(stream_header_t *stream_header);
|
||||
int read_stream_format(stream_format_t *stream_format);
|
||||
int read_stream_format_auds(stream_format_auds_t *stream_format);
|
||||
|
||||
//int read_strd_format(long strdSize);
|
||||
//int add_subtitle(long chunkSize);
|
||||
|
||||
int parse_hdrl(unsigned int size);
|
||||
int parse_hdrl_list();
|
||||
int parse_movi_list(unsigned int size);
|
||||
|
||||
};
|
||||
|
||||
#endif // #if (FILE_FORMAT_AVI)
|
||||
#endif // RM_FORMAT_AVI_H
|
||||
1538
project/fm_viewer/data/rm_format_mov.cpp
Normal file
1538
project/fm_viewer/data/rm_format_mov.cpp
Normal file
File diff suppressed because it is too large
Load Diff
308
project/fm_viewer/data/rm_format_mov.h
Normal file
308
project/fm_viewer/data/rm_format_mov.h
Normal file
@@ -0,0 +1,308 @@
|
||||
#ifndef RM_FORMAT_MOV_H
|
||||
#define RM_FORMAT_MOV_H
|
||||
|
||||
#if (FILE_FORMAT_MOV)
|
||||
|
||||
// 기본정보(duration + bitrate) 읽기 + 센서 파서
|
||||
// 기존 mov_reader.h/cpp + rm_mov_format.h/cpp 통합 버전
|
||||
|
||||
|
||||
#if !defined(BBEXTRACT)
|
||||
#include "../rm_include.h"
|
||||
#include <QString>
|
||||
#endif
|
||||
#include "rm_format.h"
|
||||
|
||||
extern "C" {
|
||||
#include "fileio.h"
|
||||
}
|
||||
#include <stdint.h>
|
||||
|
||||
// 최대 tag 탐색 깊이
|
||||
#define RM_MOV_MAX_DEPTH 10
|
||||
|
||||
// 마지막 탐색된 tag 의 최대 크기 (eg. 3개 trak 에서 mdia->stbl->stsd stsd 가 text 인 tag 탐색시
|
||||
#if(RM_MODEL == RM_MODEL_TYPE_TB4000 || RM_MODEL == RM_MODEL_TYPE_MH9000)
|
||||
#define RM_MOV_MAX_TAG_VALUE_SIZE 100
|
||||
#else // 4000
|
||||
#define RM_MOV_MAX_TAG_VALUE_SIZE 10
|
||||
#endif // 4000
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_NX_DRW22)
|
||||
typedef struct _GPS0
|
||||
{
|
||||
double lat; // 0
|
||||
double lon; // 8
|
||||
uint32_t alt; // 16
|
||||
uint16_t speed; // 20
|
||||
uint8_t year; // 22
|
||||
uint8_t month; // 23
|
||||
uint8_t day; // 24
|
||||
uint8_t hour; // 25
|
||||
uint8_t min; // 26
|
||||
uint8_t sec; // 27
|
||||
uint8_t degree; // 28
|
||||
uint8_t status; // 29
|
||||
uint8_t version; // 30
|
||||
uint8_t reserved;
|
||||
} GPS0;
|
||||
#elif (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || RM_MODEL == RM_MODEL_TYPE_MBJ5010 || RM_MODEL == RM_MODEL_TYPE_FC_DR232W || RM_MODEL == RM_MODEL_TYPE_BV2000)
|
||||
// #define SENSOR_INTERVAL 1 // 2초 간격으로 저장
|
||||
// #define SENSOR_FPS 40 // " 40개씩 저장됨
|
||||
#define MAX_SENSOR_FPS 40
|
||||
#endif // RM_MODEL_TYPE_NX_DRW22
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_TB4000)
|
||||
//typedef struct GPSINFOCHUCKTIME_s
|
||||
//{
|
||||
// unsigned char byYear; // < Years since 1900
|
||||
// unsigned char byMon; // < Months since January - [0,11]
|
||||
// unsigned char byDay; // < Day of the month - [1,31]
|
||||
// unsigned char byHour; // < Hours since midnight - [0,23]
|
||||
// unsigned char byMin; // < Minutes after the hour - [0,59]
|
||||
// unsigned char bySec; // < Seconds after the minute - [0,59]
|
||||
//} GPSINFOCHUCKTIME;
|
||||
typedef struct _GPSINFOCHUCK_TELEBIT
|
||||
{
|
||||
double dwLat; //< Latitude in NDEG - +/-[degree][min].[sec/60]
|
||||
double dwLon; //< Longitude in NDEG - +/-[degree][min].[sec/60]
|
||||
long lAlt; //< Altitude in meter +-:under/below sea level
|
||||
unsigned short usSpeed; //< Speed unit: km/h
|
||||
unsigned char datetime[6]; // byYear(from 1900), byMon, byDay, byHour, byMin, bySec
|
||||
//GPSINFOCHUCKTIME sUTC; //< UTC of position
|
||||
unsigned char ubDirection; //< Clockwise degree from the North.
|
||||
unsigned char ubFlag; //< Check if the GPS data is valid;
|
||||
unsigned char ubVersion; //< Stuture Version
|
||||
unsigned char ubReserved;
|
||||
} GPSINFOCHUCK_TELEBIT;
|
||||
|
||||
#endif // 4000
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_MH9000)
|
||||
#pragma pack(push, 1)
|
||||
typedef struct _gps_chunk_t
|
||||
{
|
||||
char header[4]; // id = "DVAL"
|
||||
unsigned short year;
|
||||
unsigned short mon;
|
||||
unsigned short mday;
|
||||
unsigned short hour;
|
||||
unsigned short min;
|
||||
unsigned short sec;
|
||||
char vehicle_id[16];
|
||||
char driver_id[16];
|
||||
char rec_type; // 0:normal, 1:event
|
||||
char event_gsensor;
|
||||
char event_smoke;
|
||||
char event_dsm;
|
||||
char flag_seat_b;
|
||||
char flag_side_b;
|
||||
char flag_wink_l;
|
||||
char flag_wink_r;
|
||||
char flag_foot_b;
|
||||
char flag_gron_b;
|
||||
char blank_a[2];
|
||||
char flag_smoke;
|
||||
char flag_dsm;
|
||||
char blank_b[2];
|
||||
unsigned short speed;
|
||||
unsigned short rpm;
|
||||
unsigned short gps_speed;
|
||||
char blank_c[2];
|
||||
unsigned int latitude; // lat * 100000
|
||||
unsigned int longitude; // long * 100000
|
||||
unsigned short gx[10]; // (g x 100) 100ms x 10 = 1sec
|
||||
unsigned short gy[10]; // (g x 100) 100ms x 10 = 1sec
|
||||
unsigned short gz[10]; // (g x 100) 100ms x 10 = 1sec
|
||||
char fw_version[16];
|
||||
long lAlt; /**< Altitude in meter +-:under/below sea level*/
|
||||
unsigned char ubDirection; /**< Clockwise degree from the North.*/
|
||||
} gps_chunk_t;
|
||||
#pragma pack(pop)
|
||||
#endif // MH9000
|
||||
|
||||
class MOVFormat
|
||||
{
|
||||
// 재생시간 및 bitrate parser
|
||||
private:
|
||||
VideoReadMode _readMode; // 현재 모드
|
||||
VideoPreInfo* _preInfo; // 기본 정보 (존재할 경우 ReadMode == PreInfo)
|
||||
bool _isValid; // 센서 관련?
|
||||
|
||||
// Python..
|
||||
unsigned int _offset;
|
||||
RMfile _file;
|
||||
|
||||
private:
|
||||
// parse 중지
|
||||
bool _stop_parse;
|
||||
|
||||
// 탐색할 tag 리스트 (최대 depth = 10)
|
||||
int _tag_count;
|
||||
long _tag_list[RM_MOV_MAX_DEPTH];
|
||||
|
||||
// 탐색 tag (depth) offset
|
||||
unsigned int _tag_offset_list[RM_MOV_MAX_DEPTH];
|
||||
|
||||
// 탐색 tag (depth) size
|
||||
long _tag_size_list[RM_MOV_MAX_DEPTH];
|
||||
|
||||
// 탐색 중 확인할 value (자막의 경우 track 중 value 가 txt 인지 확인해야함)
|
||||
char _tag_search_value[RM_MOV_MAX_TAG_VALUE_SIZE];
|
||||
|
||||
// 초기화
|
||||
void init_parser();
|
||||
|
||||
void set_tags(const char* tag,...);
|
||||
|
||||
// 현재 tag value 가 _tag_search_value 와 동일한지 확인
|
||||
bool check_tag_value(long atom_type, unsigned int offset, long size);
|
||||
|
||||
// 처음부터 끝까지 depth 0 에서 parse 시작
|
||||
void parse_all();
|
||||
|
||||
// 센서 데이터만 parse
|
||||
//void parse_sensor();
|
||||
|
||||
// bitrate 만 parse
|
||||
#if !defined(BBEXTRACT)
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
bool parse_bitrate();
|
||||
#endif // CHECK_VIDEO_BITRATE
|
||||
void parse_avc1(long offset, long size); // H264 Video
|
||||
#endif // #if !defined(BBEXTRACT)
|
||||
bool parse_duration();
|
||||
bool parse_sensor();
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88 || SUB_MODEL_CARROT_EMT)
|
||||
bool parse_buffer(uint8_t* buffer,long size);
|
||||
#endif
|
||||
|
||||
// _tag 로 지정된 tag 의 옵셋 가져오기
|
||||
void parse(unsigned int offset, unsigned int length, int depth = 0);
|
||||
unsigned int get_tag_list_offset();
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_NX_DRW22)
|
||||
GPS0* _gps0;
|
||||
int16_t *_zyx; // 20201005 XYZ->ZYX 로 수정요청
|
||||
#elif (RM_MODEL == RM_MODEL_TYPE_ADT_CAPS || \
|
||||
RM_MODEL == RM_MODEL_TYPE_BV2000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_XLDR_88 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_KEIYO1 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MBJ5010 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_FC_DR232W)
|
||||
void* _nmea; // NMEA INFO
|
||||
void* _sens; // _SEN
|
||||
#elif (RM_MODEL == RM_MODEL_TYPE_MH9000)
|
||||
gps_chunk_t* _sens;
|
||||
#elif (RM_MODEL_EMT_KR)
|
||||
void* _nmea; // NMEA INFO
|
||||
#endif
|
||||
|
||||
#if (RM_MODEL != RM_MODEL_TYPE_MH9000 && !RM_MODEL_EMT_KR)
|
||||
int _gps0Count;
|
||||
#endif // _sens 에 통합
|
||||
int _gsenCount;
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_BV2000 ||\
|
||||
RM_MODEL == RM_MODEL_TYPE_KEIYO1 ||\
|
||||
RM_MODEL == RM_MODEL_TYPE_MBJ5010 ||\
|
||||
RM_MODEL == RM_MODEL_TYPE_MH9000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_FC_DR232W)
|
||||
int _sensorFPS;
|
||||
void process_subtitle(const char* subtitle);
|
||||
#elif (RM_MODEL_EMT_KR)
|
||||
void process_subtitle(const char* subtitle);
|
||||
#endif
|
||||
|
||||
public:
|
||||
MOVFormat(RMfile in,VideoReadMode mode = VideoReadSensor, VideoPreInfo* info = NULL);
|
||||
static bool duration(RMfile in,VideoPreInfo* info);
|
||||
#if !defined(BBEXTRACT)
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
static bool movSize(RMfile in,VideoPreInfo* info);
|
||||
#endif
|
||||
#endif // #if !defined(BBEXTRACT)
|
||||
~MOVFormat();
|
||||
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
QString modelName;
|
||||
#endif
|
||||
|
||||
bool isValid()
|
||||
{
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
// MOV 크기와 재생시간 그리고 오디오 bitrate (kb/sec) 를 입력받아 mov bitrate 를 계산한다
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
static int videoBitrate(VideoPreInfo* info) {
|
||||
|
||||
const double kb = 1000.0; // 1024?
|
||||
const double durationInSec = (double)(info->duration) / 1000.0;
|
||||
double videoSize = (double)(info->movSize);
|
||||
return videoSize * 8.0 / durationInSec / kb;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_NX_DRW22)
|
||||
int getGPS(GPS0** gps)
|
||||
{
|
||||
*gps = _gps0;
|
||||
return _gps0Count;
|
||||
}
|
||||
int getSensor(int16_t** sensor)
|
||||
{
|
||||
*sensor = _zyx;
|
||||
return _gsenCount;
|
||||
}
|
||||
#elif (RM_MODEL_EMT_KR)
|
||||
int getNMEA(void** nmea)
|
||||
{
|
||||
*nmea = _nmea;
|
||||
return _gsenCount;
|
||||
}
|
||||
#elif (RM_MODEL == RM_MODEL_TYPE_ADT_CAPS || \
|
||||
RM_MODEL == RM_MODEL_TYPE_XLDR_88 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_KEIYO1 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MBJ5010 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_BV2000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MH9000 | \
|
||||
RM_MODEL == RM_MODEL_TYPE_FC_DR232W)
|
||||
// MH9000은 sensor 에 통합되어 있음
|
||||
#if (RM_MODEL != RM_MODEL_TYPE_MH9000)
|
||||
int getGPS(void** nmea)
|
||||
{
|
||||
*nmea = _nmea;
|
||||
return _gps0Count;
|
||||
}
|
||||
#endif //
|
||||
int getSensor(void** sensor)
|
||||
{
|
||||
*sensor = _sens;
|
||||
return _gsenCount;
|
||||
}
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MBJ5010 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_FC_DR232W || \
|
||||
RM_MODEL == RM_MODEL_TYPE_BV2000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MH9000)
|
||||
int getSensorFPS() {
|
||||
return _sensorFPS;
|
||||
}
|
||||
|
||||
#endif
|
||||
#elif (RM_MODEL == RM_MODEL_TYPE_TB4000)
|
||||
GPSINFOCHUCK_TELEBIT* _nmea; // NMEA INFO
|
||||
int getGPS(GPSINFOCHUCK_TELEBIT** nmea)
|
||||
{
|
||||
*nmea = _nmea;
|
||||
return _gps0Count;
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // #if (FILE_FORMAT_MOV)
|
||||
|
||||
#endif // RM_FORMAT_MOV_H
|
||||
179
project/fm_viewer/data/rm_format_mov_emtudat.cpp
Normal file
179
project/fm_viewer/data/rm_format_mov_emtudat.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
#include "rm_format_mov.h"
|
||||
#include "fm_parse_gps.h"
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
#define GPSR_FLAG ('G' | 'P' << 8 | 'S' << 16 | 'R' << 24)
|
||||
#define SENS_FLAG ('S' | 'E' << 8 | 'N' << 16 | 'S' << 24)
|
||||
#define BYTE_SWAP_32(__num) ( ((__num>>24)&0xff) | ((__num<<8)&0xff0000) | ((__num>>8)&0xff00) | ((__num<<24)&0xff000000))
|
||||
//#define GPRS_SENTENCE_SIZE 128
|
||||
|
||||
bool MOVFormat::parse_buffer(uint8_t* strd,long strdSize)
|
||||
{
|
||||
size_t check_offset = 0;
|
||||
|
||||
// GPSR 및 데이터 시작 위치가 다름 (이벤트에 따라)
|
||||
for(long i=0;i<strdSize;i++)
|
||||
{
|
||||
if(*((int32_t*)&strd[i]) == GPSR_FLAG || *((int32_t*)&strd[i]) == SENS_FLAG)
|
||||
{
|
||||
check_offset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (check_offset == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long offset = 0;
|
||||
int32_t flag;// = *((int32_t*)&strd[offset]);
|
||||
offset += (check_offset - 4); // GRSP 앞쪽 4BYTE 에 크기가 시작됨
|
||||
|
||||
bool gpsDone = false;
|
||||
bool sensorDone = false;
|
||||
|
||||
while(offset < strdSize)
|
||||
{
|
||||
// 데이터 크기는 GPS 및 센서 데이터 앞쪽에 있음
|
||||
int32_t dataSize = *((int32_t*)&strd[offset]); // data to offset 이 가장 먼저 있음
|
||||
offset += 4;
|
||||
dataSize = BYTE_SWAP_32(dataSize); // eg. 4088 byte 부터 sensor data 시작, 센서는 9032
|
||||
|
||||
int32_t nextOffset = dataSize + (check_offset - 4); // 4088 + 24(front) = 4120 (file offset: )
|
||||
|
||||
flag = *((int32_t*)&strd[offset]); // flag (type)
|
||||
offset += 4;
|
||||
|
||||
int index = 0;
|
||||
|
||||
if(flag == GPSR_FLAG) // GPS Data
|
||||
{
|
||||
//_gps0Count = dataSize / (GPRS_SENTENCE_SIZE + 4 + 4); // 136 = 0x88
|
||||
//qInfo() << "GPSR_FLAG found:" << _gpsCount;
|
||||
|
||||
if(_nmea != NULL)
|
||||
{
|
||||
free(_nmea);
|
||||
}
|
||||
//_bGPSExist = true;
|
||||
NMEA_INFO* nmea = (NMEA_INFO*)malloc(sizeof(_NMEA_INFO) * 1000);
|
||||
_nmea = nmea;
|
||||
|
||||
//#if (DEBUG_SENSOR_DATA)
|
||||
// printf("gps data size:%d count:%d test:%f\n",dataSize,_gpsCount,(float)dataSize / (float)(GPRS_SENTENCE_SIZE + 4 + 4));
|
||||
//#endif
|
||||
// bool validGPSFound = false;
|
||||
while(offset < dataSize)
|
||||
{
|
||||
// int32_t frameNumber = *((int32_t*)&strd[offset]);
|
||||
//offset += 4;
|
||||
|
||||
int32_t packetSize = strd[offset];
|
||||
offset += 1;
|
||||
|
||||
char* buffer = (char*)&strd[offset];
|
||||
if(strncmp(buffer,"$GPRMC",6) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
FMParseGPS::ParseRMC(buffer, &nmea[index],packetSize);
|
||||
char deb[1024] = {0,};
|
||||
strncpy(deb,buffer,packetSize);
|
||||
// qInfo() << index << ":" << deb << " =" << QString().sprintf("%X",offset);
|
||||
//_ParseRMC(buffer,index,NMEA_TOKEN_SIZE);
|
||||
//#if (GPRMC_VALID_CHECK)
|
||||
// if( validGPSFound == false &&
|
||||
// _gpsData[index].nStatus == 1 &&
|
||||
// IS_VALID_LOCATION(_gpsData[index].Longitude,_gpsData[index].Latitude) == true)
|
||||
//#else
|
||||
// if( validGPSFound == false && IS_VALID_LOCATION(_gpsData[index].Longitude,_gpsData[index].Latitude) == true)
|
||||
//#endif
|
||||
// {
|
||||
// validGPSFound = true;
|
||||
// }
|
||||
|
||||
offset +=packetSize;
|
||||
// _bGPSExist = validGPSFound;
|
||||
index++;
|
||||
}
|
||||
gpsDone = true;
|
||||
_gps0Count = index;
|
||||
|
||||
}
|
||||
else if(flag == SENS_FLAG) // Sensor Data
|
||||
{
|
||||
dataSize -= 8; // size + flag = 8 byte
|
||||
_gsenCount = dataSize / SENS_PACKET_SIZE;
|
||||
|
||||
if(_sens != NULL)
|
||||
{
|
||||
free(_sens);
|
||||
}
|
||||
float* sens = (float*)malloc(SENS_PACKET_SIZE * _gsenCount);
|
||||
_sens = sens;
|
||||
|
||||
//printf("----------------------------------------------------------\n");
|
||||
//printf("sensor data:%d\n",_sensorCount);
|
||||
//printf("----------------------------------------------------------\n");
|
||||
#if (DEBUG_SENSOR_DATA)
|
||||
printf("sensor data size:%d count:%d test:%f\n",dataSize,_sensorCount,(float)dataSize / (float)(SENS_PACKET_SIZE));
|
||||
#endif
|
||||
while(index < _gsenCount)
|
||||
{
|
||||
memcpy(&sens[index * NUM_SENSOR_DATA],&strd[offset],SENS_PACKET_SIZE);
|
||||
offset += SENS_PACKET_SIZE;
|
||||
//qInfo() << QString().sprintf("%.2f,%.2f,%.2f", sens[(index * NUM_SENSOR_DATA)+0],sens[(index * NUM_SENSOR_DATA)+1],sens[(index * NUM_SENSOR_DATA)+2]);
|
||||
//printf("%d,%.5f,%.5f,%.5f\n",index, _sensorData[(index * NUM_SENSOR_DATA)+0],_sensorData[(index * NUM_SENSOR_DATA)+1],_sensorData[(index * NUM_SENSOR_DATA)+2]);
|
||||
#if (DEBUG_SENSOR_DATA)
|
||||
printf("idx:%d x:%.5f y:%.5f z:%.5f\n",index, _sensorData[(index * NUM_SENSOR_DATA)+0],_sensorData[(index * NUM_SENSOR_DATA)+1],_sensorData[(index * NUM_SENSOR_DATA)+2]);
|
||||
#endif
|
||||
index++;
|
||||
}
|
||||
sensorDone = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break; // flag 가 아닐경우
|
||||
}
|
||||
|
||||
if(gpsDone == true && sensorDone == true)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
offset = nextOffset;// dataSize; // 어차피 같아야함..
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MOVFormat::parse_sensor()
|
||||
{
|
||||
init_parser();
|
||||
|
||||
// 1. udat
|
||||
// user 데이터 확인 완료
|
||||
set_tags("udat",NULL);
|
||||
// 탐색 시작
|
||||
parse_all();
|
||||
if(_stop_parse == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
unsigned int udat_offset = _tag_offset_list[0];
|
||||
long udat_size = _tag_size_list[0];
|
||||
if(udat_offset != 0 && udat_size != 0)
|
||||
{
|
||||
//qInfo() << QString().sprintf("%X,%d",udat_offset+8,udat_size-8);
|
||||
RMfseek(_file,udat_offset+8,SEEK_SET);
|
||||
uint8_t *buffer = (uint8_t*)malloc(udat_size-8);
|
||||
RMfread(buffer,udat_size-8,1,_file);
|
||||
|
||||
parse_buffer(buffer,udat_size-8);
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
10
project/fm_viewer/data/rm_overwrite.cpp
Normal file
10
project/fm_viewer/data/rm_overwrite.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "rm_overwrite.h"
|
||||
|
||||
QMutex RMOverwrite::_lock;
|
||||
|
||||
QWaitCondition RMOverwrite::_wait;
|
||||
|
||||
int RMOverwrite::gCurrent = OVERWRITE_OPTION_ASK | OVERWRITE_OPTION_ALL;
|
||||
|
||||
QString RMOverwrite::currentFileName;
|
||||
int RMOverwrite::currentCount = 0;
|
||||
56
project/fm_viewer/data/rm_overwrite.h
Normal file
56
project/fm_viewer/data/rm_overwrite.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef RM_OVERWRITE_H
|
||||
#define RM_OVERWRITE_H
|
||||
|
||||
#include <QWaitCondition>
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
|
||||
// 백업시 파일 존재할 경우 처리 방법
|
||||
typedef enum
|
||||
{
|
||||
OVERWRITE_OPTION_ASK = 1 << 0, // 확인
|
||||
OVERWRITE_OPTION_SKIP = 1 << 1, // 스킵
|
||||
OVERWRITE_OPTION_WRITE = 1 << 2, // 덮어쓰기
|
||||
OVERWRITE_OPTION_CANCEL = 1 << 3, // 취소
|
||||
OVERWRITE_OPTION_ALL = 1 << 4, // 전체
|
||||
} OVERWRITE_OPTION;
|
||||
|
||||
|
||||
class RMOverwrite
|
||||
{
|
||||
private:
|
||||
static QMutex _lock; // 프로세스 잠금/WAIT (백업 중 동일 파일 존재 ETC)
|
||||
static QWaitCondition _wait; // 대기
|
||||
|
||||
public:
|
||||
static void lock () {
|
||||
RMOverwrite::_lock.lock();
|
||||
}
|
||||
static void unlock () {
|
||||
RMOverwrite::_lock.unlock();
|
||||
}
|
||||
static void wait() {
|
||||
RMOverwrite::_wait.wait(&RMOverwrite::_lock);
|
||||
}
|
||||
static void unwait() {
|
||||
RMOverwrite::_wait.wakeAll();
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
RMOverwrite::gCurrent = OVERWRITE_OPTION_ASK;
|
||||
RMOverwrite::currentFileName = "";
|
||||
RMOverwrite::currentCount = 0;
|
||||
}
|
||||
|
||||
static QString currentFileName; // 중복된 파일명
|
||||
static int currentCount; // 남은 파일 개수
|
||||
|
||||
//static OVERWRITE_OPTION gGlobal; // 전체 옵션 (eg. 모두 skip, etc)
|
||||
static int gCurrent; // 현재 옵션 (다이얼로그 선택)
|
||||
|
||||
static bool check(OVERWRITE_OPTION with) {
|
||||
return ((RMOverwrite::gCurrent & with) == with);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // RM_OVERWRITE_H
|
||||
1362
project/fm_viewer/data/rm_sensordata.cpp
Normal file
1362
project/fm_viewer/data/rm_sensordata.cpp
Normal file
File diff suppressed because it is too large
Load Diff
328
project/fm_viewer/data/rm_sensordata.h
Normal file
328
project/fm_viewer/data/rm_sensordata.h
Normal file
@@ -0,0 +1,328 @@
|
||||
#ifndef RM_SENSORDATA_H
|
||||
#define RM_SENSORDATA_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#if !defined(BBEXTRACT)
|
||||
#include "../rm_include.h"
|
||||
#endif // #if !defined(BBEXTRACT)
|
||||
|
||||
#if !defined(MIN)
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
#if !defined(MAX)
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
#include "rm_format_avi.h"
|
||||
|
||||
#define DEBUG_SENSOR_DATA 0
|
||||
#define GPRMC_VALID_CHECK 1
|
||||
|
||||
|
||||
#define NUM_SENSOR_DATA 3 // XYZ
|
||||
#define SENS_PACKET_SIZE (NUM_SENSOR_DATA * sizeof(float))
|
||||
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
// 모든 자막에 GPS+SENSOR 같은 숫자로 존재
|
||||
typedef struct _NMEA_INFO
|
||||
{
|
||||
uint16_t nYear; // (UTC)년(+9시간)
|
||||
uint8_t nMonth; // (UTC)월
|
||||
uint8_t nDay; // (UTC)일
|
||||
|
||||
uint8_t nHour; // (UTC)시
|
||||
uint8_t nMin; // (UTC)분
|
||||
uint8_t nSec; // (UTC)초
|
||||
uint8_t reserved; // ... (64 bit pack)
|
||||
|
||||
double Latitude; // 위도
|
||||
double Longitude; // 경도
|
||||
float Speed; // 속도 (Km/h)
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float Voltage; // 전압
|
||||
float Temperature; // 온도
|
||||
|
||||
uint8_t nStatus; // 상태(0,1)
|
||||
uint8_t nAngle; // 방위각
|
||||
#if (USE_TRIGGER)
|
||||
uint8_t eTrigger; // 트리거 E (255 가 아닌 위치index 가 발생위치임)
|
||||
uint8_t mTrigger; // " M (255 가 아닌 위치index 가 발생위치임)
|
||||
uint8_t reserved2[4]; // 64 bit pack
|
||||
#else // USE_TRIGGER
|
||||
uint8_t reserved2[6]; // 64 bit pack
|
||||
#endif // USE_TRIGGER
|
||||
} NMEA_INFO;
|
||||
#else // #if (RM_MODEL_EMT_KR)
|
||||
typedef struct _NMEA_INFO
|
||||
{
|
||||
uint16_t nYear; // (UTC)년(+9시간)
|
||||
uint8_t nMonth; // (UTC)월
|
||||
uint8_t nDay; // (UTC)일
|
||||
|
||||
uint8_t nHour; // (UTC)시
|
||||
uint8_t nMin; // (UTC)분
|
||||
uint8_t nSec; // (UTC)초
|
||||
uint8_t reserved; // ... (64 bit pack)
|
||||
|
||||
double Latitude; // 위도
|
||||
double Longitude; // 경도
|
||||
double Speed; // 속도 (Km/h)
|
||||
|
||||
uint8_t nStatus; // 상태(0,1)
|
||||
uint8_t nAngle; // 방위각
|
||||
uint8_t reserved2[6]; // 64 bit pack
|
||||
} NMEA_INFO;
|
||||
#endif //
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_ADT_CAPS && !SUB_MODEL_CARROT_EMT)
|
||||
typedef struct _SEN {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float gcal;
|
||||
uint32_t drive;
|
||||
uint32_t parking;
|
||||
} SEN;
|
||||
#endif // RM_MODEL_TYPE_ADT_CAPS
|
||||
|
||||
|
||||
class RMSensorData
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
FILE_TYPE_AVI = 0,
|
||||
FILE_TYPE_MOV = 1, // MP4
|
||||
} FILE_TYPE;
|
||||
RMSensorData(FILE* f,FILE_TYPE type);
|
||||
~RMSensorData();
|
||||
QString modelName;
|
||||
|
||||
uint32_t getSensorCount()
|
||||
{
|
||||
return _sensorCount;
|
||||
}
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
const NMEA_INFO* getSensor()
|
||||
{
|
||||
return _sensorData;
|
||||
}
|
||||
uint32_t getGPSCount()
|
||||
{
|
||||
return _bGPSExist ? _sensorCount : 0;
|
||||
}
|
||||
const NMEA_INFO* getGPS()
|
||||
{
|
||||
return _bGPSExist ? _sensorData : NULL;
|
||||
}
|
||||
const bool getGPSCoord(double ratio,double* lat, double* lon)
|
||||
{
|
||||
if(_bGPSExist)
|
||||
{
|
||||
unsigned int index = (int)((double)_sensorCount * ratio);
|
||||
if(index <= _sensorCount) // 마지막 1초는 오차 범위
|
||||
{
|
||||
index = MIN(index,_sensorCount-1);
|
||||
*lat = _sensorData[index].Latitude;
|
||||
*lon = _sensorData[index].Longitude;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const double getGPSSpeed(double ratio)
|
||||
{
|
||||
if(_bGPSExist)
|
||||
{
|
||||
unsigned int index = (int)((double)_sensorCount * ratio);
|
||||
if(index <= _sensorCount) // 마지막 1초는 오차 범위
|
||||
{
|
||||
index = MIN(index,_sensorCount-1);
|
||||
//qInfo() << "SPD:" << index << _gpsData[index].nStatus << _gpsData[index].Speed;
|
||||
return _sensorData[index].nStatus == 1 ? _sensorData[index].Speed : -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
bool getGPSPosition(double ratio,double* lonX, double* latY, double* speed)
|
||||
{
|
||||
if(_bGPSExist)
|
||||
{
|
||||
unsigned int index = (int)((double)_sensorCount * ratio);
|
||||
if(index < _sensorCount && _sensorData[index].nStatus == 1)
|
||||
{
|
||||
*lonX = _sensorData[index].Longitude;
|
||||
*latY = _sensorData[index].Latitude;
|
||||
*speed = _sensorData[index].Speed;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#else // RM_MODEL_EMT_KR
|
||||
const float* getSensor()
|
||||
{
|
||||
return _sensorData;
|
||||
}
|
||||
uint32_t getGPSCount()
|
||||
{
|
||||
return _bGPSExist ? _gpsCount : 0;
|
||||
}
|
||||
const NMEA_INFO* getGPS()
|
||||
{
|
||||
return _bGPSExist ? _gpsData : NULL;
|
||||
}
|
||||
const bool getGPSCoord(double ratio,double* lat, double* lon)
|
||||
{
|
||||
if(_bGPSExist)
|
||||
{
|
||||
unsigned int index = (int)((double)_gpsCount * ratio);
|
||||
if(index <= _gpsCount) // 마지막 1초는 오차 범위
|
||||
{
|
||||
index = MIN(index,_gpsCount-1);
|
||||
*lat = _gpsData[index].Latitude;
|
||||
*lon = _gpsData[index].Longitude;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const double getGPSSpeed(double ratio)
|
||||
{
|
||||
#if !(SPEED_ALWAYS_EXITS)
|
||||
if(_bGPSExist)
|
||||
#endif
|
||||
{
|
||||
unsigned int index = (int)((double)_gpsCount * ratio);
|
||||
if(index <= _gpsCount) // 마지막 1초는 오차 범위
|
||||
{
|
||||
index = MIN(index,_gpsCount-1);
|
||||
#if (SPEED_ALWAYS_EXITS)
|
||||
//qInfo() << "SPD:" << index << _gpsData[index].nStatus << _gpsData[index].Speed;
|
||||
return _gpsData[index].Speed;
|
||||
#else
|
||||
//qInfo() << "SPD:" << index << _gpsData[index].nStatus << _gpsData[index].Speed;
|
||||
return _gpsData[index].nStatus == 1 ? _gpsData[index].Speed : -1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
bool getGPSPosition(double ratio,double* lonX, double* latY, double* speed)
|
||||
{
|
||||
if(_bGPSExist)
|
||||
{
|
||||
unsigned int index = (int)((double)_gpsCount * ratio);
|
||||
if(index < _gpsCount && _gpsData[index].nStatus == 1)
|
||||
{
|
||||
*lonX = _gpsData[index].Longitude;
|
||||
*latY = _gpsData[index].Latitude;
|
||||
*speed = _gpsData[index].Speed;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#if (CLIP_SENSOR_DATA)
|
||||
void clipWithDuration(qint64 duration);
|
||||
void clipSensorCount(int number);
|
||||
void clipGPSCount(int number);
|
||||
void fixGPS();
|
||||
#endif
|
||||
#endif // RM_MODEL_EMT_KR
|
||||
|
||||
#if (USE_TRIGGER)
|
||||
float triggerE; // 트리거 위치 (ratio 0~1.0)
|
||||
float triggerM;
|
||||
#endif // USE_TRIGGER
|
||||
|
||||
#if defined(MODEL_BBVIEWER) && (!MODEL_WATEX)
|
||||
const double getOBDSpeed(double ratio)
|
||||
{
|
||||
if(_sensorData != NULL && _sensorCount > 0)
|
||||
{
|
||||
unsigned int index = (int)(((double)_sensorCount) * ratio);
|
||||
//qInfo() << "SENSOR INDEX:" << index;
|
||||
if(index < _sensorCount)
|
||||
{
|
||||
return _OBDSpeed[index];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // BB
|
||||
|
||||
|
||||
// 재생시간과 센서 데이터 동기화 (짧으면 추가, 길면 자르기)
|
||||
void processWithDuration(qint64 ms);
|
||||
|
||||
private:
|
||||
#if (CLIP_SENSOR_DATA)
|
||||
int _skipSensorCount;
|
||||
#endif
|
||||
bool _bGPSExist;
|
||||
long _nLastAngle[2]; // RMC 데이터 처리용
|
||||
|
||||
#if(RM_MODEL_EMT_KR)
|
||||
uint32_t _sensorCount;
|
||||
NMEA_INFO* _sensorData;
|
||||
#else // RM_MODEL_EMT_KR
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MBJ5010 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_FC_DR232W || \
|
||||
RM_MODEL == RM_MODEL_TYPE_BV2000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MH9000 )
|
||||
int _sensorFPS;
|
||||
#endif
|
||||
uint32_t _gpsCount;
|
||||
uint32_t _sensorCount;
|
||||
#if defined(BBEXTRACT)
|
||||
GSENSOR* _sensorData;
|
||||
#else
|
||||
float* _sensorData;
|
||||
#endif
|
||||
NMEA_INFO* _gpsData;
|
||||
|
||||
#if (MODEL_BBVIEWER && !MODEL_WATEX)
|
||||
float* _OBDSpeed; // GPS 속도인지 ODB 속도인지 확인
|
||||
#endif
|
||||
#endif // !RM_MODEL_EMT_KR
|
||||
|
||||
#if (FILE_FORMAT_MOV)
|
||||
bool loadMOV(FILE* f);
|
||||
|
||||
#if !(RM_MODEL_EMT_KR)
|
||||
#if(RM_MODEL == RM_MODEL_TYPE_MH9000)
|
||||
bool loadMOVGPSNR(void* p,uint32_t count);
|
||||
#else // RM_MODEL_TYPE_MH9000
|
||||
bool loadMOVGPSNR(void* p,uint32_t count, void* ps, uint32_t sensorCount);
|
||||
//bool loadMOVGPSNR(void* p,uint32_t count);
|
||||
#endif // RM_MODEL_TYPE_MH9000
|
||||
#endif // #if !(RM_MODEL_EMT_KR)
|
||||
|
||||
#endif // FILE_FORMAT_MOV
|
||||
|
||||
#if (FILE_FORMAT_AVI)
|
||||
bool loadAVIRiff(FILE* f); // TYPE 1
|
||||
#if (AVI_CHUNHO_SENSOR_FORMAT_1)
|
||||
bool loadAVIChunck(uint8_t* gps, size_t gps_size,uint8_t* sensor, size_t sensor_size);
|
||||
#endif
|
||||
|
||||
#if (SENSOR_AVI_SUBTITLE)
|
||||
bool loadAVISubTitle(QList<char*>* subTitles); // AVI TYPE 2 불러오기
|
||||
#endif
|
||||
#endif // FILE_FORMAT_AVI
|
||||
|
||||
};
|
||||
|
||||
#endif // RM_SENSORDATA_H
|
||||
1135
project/fm_viewer/data/rm_video_item_2ch.cpp
Normal file
1135
project/fm_viewer/data/rm_video_item_2ch.cpp
Normal file
File diff suppressed because it is too large
Load Diff
236
project/fm_viewer/data/rm_video_item_2ch.h
Normal file
236
project/fm_viewer/data/rm_video_item_2ch.h
Normal file
@@ -0,0 +1,236 @@
|
||||
#ifndef RM_VIDEOITEM_2CH_H
|
||||
#define RM_VIDEOITEM_2CH_H
|
||||
|
||||
// 각 채널별 파일이 구분되어 있는 단말기의 경우 RMVideoItem 을 별도로 사용함
|
||||
|
||||
#include "../rm_include.h"
|
||||
#include "rm_video_list.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QRunnable>
|
||||
#include <QDateTime>
|
||||
#include <QThread>
|
||||
|
||||
// 분리 채널 파일 포멧만 사용
|
||||
#if (RM_USE_SEPARATED_CH_FILE)
|
||||
|
||||
class RMSensorData;
|
||||
class RMVideoItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class RMVideoListLoader;
|
||||
friend class RMVideoItemLoader;
|
||||
friend class RMPlayerBase;
|
||||
|
||||
public:
|
||||
#ifdef _DEBUG
|
||||
void print();
|
||||
#endif
|
||||
#if (USE_DEBUG_FUNCTIONS)
|
||||
static void make_many_files(QString path);
|
||||
#endif
|
||||
|
||||
RMVideoFileList::GROUP_TYPE type;
|
||||
|
||||
bool checked; ///! 백업용 FLAG
|
||||
bool dropItem; // dropitem = single path
|
||||
bool added; // 신규로 추가된 아이템을 확인하기위해 추가시 초기화 한다.
|
||||
// bool forceSwap; // 후방만 존재하고 전방이 없을 경우=> Player 의 RearSwap.. 을 사용
|
||||
|
||||
int width; // 해상도 (1CH, 현재 AVI 만 구현)
|
||||
int height; // "
|
||||
|
||||
QString filePath;
|
||||
QString fileName; // 경로 제외 명칭
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
QString decodedPath;
|
||||
void removeTemp();
|
||||
#endif // RM_MODEL_TYPE_AN6000
|
||||
|
||||
#if (DUAL_CH_FILE && DUAL_CH_1CH_EXIST)
|
||||
bool only1CH;
|
||||
#endif
|
||||
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
QString modelName; //! WIDE 지원 모델 영상
|
||||
#endif
|
||||
|
||||
#if (TRI_CHANNEL)
|
||||
RMVideoItem(QString path,int CH,QDateTime* pDateTime); // CH 1,2,3
|
||||
#else
|
||||
RMVideoItem(QString path,bool CH2,QDateTime* pDateTime);
|
||||
#endif
|
||||
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
bool isWideMode() {
|
||||
return (modelName == "360X" && realCHCount() > 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
// MP4 CH2 파일
|
||||
QString filePathCH2;
|
||||
|
||||
#if (TRI_CHANNEL)
|
||||
QString filePathCH3;
|
||||
bool isCH3Exist() {
|
||||
return !filePathCH3.isEmpty();
|
||||
}
|
||||
#elif (PENTA_CHANNEL)
|
||||
QString filePathCH3;
|
||||
QString filePathCH4;
|
||||
QString filePathCH5;
|
||||
#endif // PENTA_CHANNEL
|
||||
QString& anyFilePath()
|
||||
{
|
||||
return filePath.length() > 0 ? filePath : filePathCH2;
|
||||
}
|
||||
bool isRearOnly() {
|
||||
return (filePath.isEmpty() && (filePathCH2.isEmpty() == false));
|
||||
}
|
||||
bool isFrontOnly() {
|
||||
return (filePathCH2.isEmpty() && (filePath.isEmpty() == false));
|
||||
}
|
||||
|
||||
bool isSingleChannel()
|
||||
{
|
||||
#if (DUAL_CH_FILE && DUAL_CH_1CH_EXIST) // 2CH 파일이나 후방없는 1CH 파일도 존재
|
||||
return only1CH;
|
||||
#elif (DUAL_CH_FILE || SINGLE_CH_VIEWER)
|
||||
return false;
|
||||
#else
|
||||
return (filePath.length() == 0 || filePathCH2.length() == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (TRI_CHANNEL2)
|
||||
int _realCHCount;
|
||||
//! \brief 프레임이 존재하지 않는 채널 제외한 채널 개수 확인
|
||||
//! AVDemux 에서 확인됨, 초기값은 0
|
||||
//! \return
|
||||
int realCHCount() {
|
||||
return _realCHCount;
|
||||
}
|
||||
#endif // TRI_CHANNEL2
|
||||
|
||||
|
||||
#if (CHECK_VIDEO_BITRATE)
|
||||
// 후방 채널 비디오 비트레이트 확인해서 일정 기준 미만이면 제거
|
||||
void testBitrate2CH();
|
||||
#endif
|
||||
|
||||
#if !(SINGLE_CH_VIEWER)
|
||||
#if (!FORCE_2CH || (RM_MODEL == RM_MODEL_TYPE_XLDR_88 || SUB_MODEL_CARROT_EMT))
|
||||
// 채널정보를 제외한 파일명을 리턴한다
|
||||
static QString fileNameWithoutChannel(QString& path);
|
||||
#endif
|
||||
#endif // SINGLE_CH_VIEWER
|
||||
|
||||
~RMVideoItem();
|
||||
|
||||
static bool FileExist(QString path);
|
||||
static int IsFeasible(QString path, QDateTime* pDateTime = NULL);
|
||||
|
||||
int fileFormat();
|
||||
|
||||
QString title();
|
||||
|
||||
QString typeString();
|
||||
|
||||
QString titleDate();
|
||||
QString titleTime();
|
||||
QString titleDateTime();
|
||||
QString titleDuration();
|
||||
#if !(DUAL_CH_FILE || SINGLE_CH_VIEWER)
|
||||
QString titleFrontRear();
|
||||
#endif
|
||||
QString titlePrefix();
|
||||
|
||||
QString titleSize();
|
||||
|
||||
QString titleCapture(qint64 secs);
|
||||
|
||||
RMSensorData* getSensorData()
|
||||
{
|
||||
return sensorData;
|
||||
}
|
||||
|
||||
//static QString recoveredPath(QString filePath);
|
||||
static QString durationString(unsigned int sec,bool hms);
|
||||
unsigned int durationInMSecs()
|
||||
{
|
||||
return _durationInMSecs;
|
||||
}
|
||||
#if (PLAY_SYNC_FIX2)
|
||||
unsigned int packetDurationInMSecs; // 재생시작해야 발생함???
|
||||
#endif // PLAY_SYNC_FIX2
|
||||
|
||||
// ?? 사용되지 않는다???
|
||||
QDateTime dateTimeInPosition(qreal ratio,double* lat, double* lon); // 전체 플레이 ratio 를 통해 시간 가져오기
|
||||
|
||||
bool isValid()
|
||||
{
|
||||
#if (SKIP_VIDEO_PREINFO)
|
||||
return true;
|
||||
#else
|
||||
return (_durationInMSecs > 300); // 0.3?
|
||||
#endif
|
||||
}
|
||||
|
||||
QDateTime& startTime()
|
||||
{
|
||||
return _dateTime;
|
||||
}
|
||||
|
||||
#if (CHECK_REAR_DURATION)
|
||||
bool isRearDuration();
|
||||
#endif
|
||||
|
||||
// 인덱스 순으로 정렬
|
||||
//int fileIndex();
|
||||
|
||||
protected:
|
||||
#if (!PRE_LOAD_SENSOR_DATA)
|
||||
void load()
|
||||
{
|
||||
emit loadSensorInfoStarted();
|
||||
if(getSensorData() == NULL)
|
||||
{
|
||||
loadSensorInfo();
|
||||
}
|
||||
emit loadSensorInfoEnd();
|
||||
}
|
||||
#endif
|
||||
void loadSensorInfo();
|
||||
private:
|
||||
|
||||
|
||||
signals:
|
||||
void loadSensorInfoStarted();
|
||||
void loadSensorInfoEnd();
|
||||
void loadSensorInfoFail();
|
||||
|
||||
private:
|
||||
#if (TRI_CHANNEL)
|
||||
QString filePathWithCH(int ch);
|
||||
#endif
|
||||
QDateTime _dateTime;
|
||||
#if (TRI_CHANNEL)
|
||||
bool _loadDuration(int ch); // 1,2,3
|
||||
#else
|
||||
bool _loadDuration(bool rear = false);
|
||||
#endif
|
||||
|
||||
qint64 _fileSize;
|
||||
|
||||
// 1초 미만 파일이 있음
|
||||
unsigned int _durationInMSecs;
|
||||
RMSensorData* sensorData;
|
||||
|
||||
static QDateTime _fileNameToDateTime(QString baseName);
|
||||
public slots:
|
||||
void onChecked();
|
||||
};
|
||||
#endif // #if (RM_USE_SEPARATED_CH_FILE)
|
||||
#endif // RM_VIDEOITEM_2CH_H
|
||||
2
project/fm_viewer/data/rm_video_item_loader.cpp
Normal file
2
project/fm_viewer/data/rm_video_item_loader.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "rm_video_item_loader.h"
|
||||
|
||||
26
project/fm_viewer/data/rm_video_item_loader.h
Normal file
26
project/fm_viewer/data/rm_video_item_loader.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef RM_VIDEO_ITEM_LOADER_H
|
||||
#define RM_VIDEO_ITEM_LOADER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QRunnable>
|
||||
#include "rm_video_item_2ch.h"
|
||||
#if (!PRE_LOAD_SENSOR_DATA)
|
||||
class RMVideoItemLoader : public QRunnable
|
||||
{
|
||||
private:
|
||||
RMVideoItem* _item;
|
||||
public:
|
||||
|
||||
RMVideoItemLoader(RMVideoItem* item)
|
||||
{
|
||||
_item = item;
|
||||
}
|
||||
|
||||
virtual void run()
|
||||
{
|
||||
_item->load();
|
||||
}
|
||||
};
|
||||
#endif // PRE_LOAD_SENSOR_DATA
|
||||
|
||||
#endif // RM_VIDEO_ITEM_LOADER_H
|
||||
2030
project/fm_viewer/data/rm_video_list.cpp
Normal file
2030
project/fm_viewer/data/rm_video_list.cpp
Normal file
File diff suppressed because it is too large
Load Diff
435
project/fm_viewer/data/rm_video_list.h
Normal file
435
project/fm_viewer/data/rm_video_list.h
Normal file
@@ -0,0 +1,435 @@
|
||||
#ifndef RM_VIDEOFILELIST_H
|
||||
#define RM_VIDEOFILELIST_H
|
||||
|
||||
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
#include <qstring.h>
|
||||
#include <QMainWindow>
|
||||
#include <QDebug>
|
||||
|
||||
#include "../rm_include.h"
|
||||
class RMVideoItem;
|
||||
|
||||
|
||||
// #include "rm_video_group.h"
|
||||
|
||||
class RMVideoFileList : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
friend class RMWidgetVideoListDelegate;
|
||||
friend class RMWidgetVideoList;
|
||||
friend class RMVideoFileListLoader;
|
||||
friend class RMVideoFileListBackup;
|
||||
static int n_lastPercent;
|
||||
|
||||
static QList<QString> fileFilters;
|
||||
|
||||
|
||||
|
||||
#if (SUPPORT_LOADING_CANCEL)
|
||||
// 로딩 취소
|
||||
bool bCancelLoading;
|
||||
#endif
|
||||
|
||||
// item 으로 이동
|
||||
typedef enum
|
||||
{
|
||||
// 주행 / 주행 이벤트 / 주차 / 주차 충격 / 수동 녹화( / 보관함???)
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
FILTER_NONE = 0,
|
||||
FILTER_NORMAL = 1 << 0, // 주행
|
||||
FILTER_EVENT = 1 << 1, // 주행 이벤트
|
||||
FILTER_PARK = 1 << 2, // 주차
|
||||
FILTER_PARK_EVENT = 1 << 3, // 주차 충격
|
||||
FILTER_MANUAL = 1 << 4, // 수동 녹화
|
||||
FILTER_MYBOX = 1 << 5, // 보관함 (포함된 폴더가 MYBOX 일 경우 분류 관계없이)
|
||||
#else // RM_MODEL_EMT_KR
|
||||
FILTER_NONE = 0,
|
||||
FILTER_NORMAL = 1 << 0,
|
||||
FILTER_EVENT = 1 << 1,
|
||||
#if ((RM_MODEL == RM_MODEL_TYPE_XLDR_88 || SUB_MODEL_CARROT_EMT) || \
|
||||
RM_MODEL == RM_MODEL_TYPE_BV2000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_KEIYO1 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_TBD360 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MBJ5010 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MH9000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_FC_DR232W)
|
||||
FILTER_PARK = 1 << 2,
|
||||
#endif // 주차 사용
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_KEIYO1 ||\
|
||||
RM_MODEL == RM_MODEL_TYPE_BV2000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MH9000 || \
|
||||
RM_MODEL == RM_MODEL_TYPE_MBJ5010 ||\
|
||||
RM_MODEL == RM_MODEL_TYPE_FC_DR232W)
|
||||
FILTER_MANUAL = 1 << 3,
|
||||
FILTER_ALL = FILTER_NORMAL | FILTER_EVENT | FILTER_PARK | FILTER_MANUAL,
|
||||
#elif (RM_MODEL == RM_MODEL_TYPE_XLDR_88 || SUB_MODEL_CARROT_EMT || RM_MODEL == RM_MODEL_TYPE_MH9000 )
|
||||
FILTER_ALL = FILTER_NORMAL | FILTER_EVENT | FILTER_PARK,
|
||||
#elif !(RM_MODEL == RM_MODEL_TYPE_TBD360)
|
||||
FILTER_ALL = FILTER_NORMAL | FILTER_EVENT,
|
||||
#endif
|
||||
#endif // RM_MODEL_EMT_KR
|
||||
|
||||
} FILTER;
|
||||
|
||||
// 단말기 별로 설정 가능
|
||||
typedef enum
|
||||
{
|
||||
TYPE_NORMAL = 0,
|
||||
TYPE_EVENT = 1,
|
||||
TYPE_MANUAL = 2,
|
||||
TYPE_PARKING = 3,
|
||||
TYPE_PARKING_EVENT = 4,
|
||||
TYPE_PARKING_MOTION = 5,
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
TYPE_MY_BOX = 6,
|
||||
#endif // #if (RM_MODEL_EMT_KR)
|
||||
TYPE_UNDEFINED = 9999,
|
||||
|
||||
} GROUP_TYPE;
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
void removeTemps();
|
||||
#endif //
|
||||
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
static RMVideoFileList::GROUP_TYPE parseName(QString baseName, QDateTime* dateTime, int* tag);
|
||||
#endif
|
||||
|
||||
#if (USE_1HOUR_FILTER)
|
||||
//! \brief 1시간 단위 필터 설정
|
||||
//! \param b1Hour true: 1시간 단위 표시, false: 전체 표시
|
||||
//! \param bEmit: listUpdateEnd 발생여부
|
||||
void set1HourList(bool b1Hour, bool bEmit, RMVideoItem* selected);
|
||||
bool get1HourList()
|
||||
{
|
||||
return b1HourList;
|
||||
}
|
||||
//! \brief 시간순, 최신순으로 정렬
|
||||
//! \param bAsc: true: 시간순
|
||||
void setSortList(bool bAsc);
|
||||
bool getSortList()
|
||||
{
|
||||
return bSortDsc;
|
||||
}
|
||||
bool bSortDsc; // 시간순으로 정렬, 최신순으로 정렬
|
||||
|
||||
//! \brief 전체 항목에서 1시간 항목 추출
|
||||
//! \param res : 결과
|
||||
void load1HourList(QList<RMVideoItem*>& res);
|
||||
|
||||
//! \brief 전달된 item 에 속하는 모든 RMVideoItem 추출
|
||||
//! - Thumbnail 에서 사용
|
||||
//! \param dt : 탐색할 아이템 시간
|
||||
//! \param res : 결과
|
||||
void load1HourInList(QDateTime dt, QList<RMVideoItem*>& res);
|
||||
|
||||
//! \brief RMVideoItem 리스트 에서 썸네일 경로 추출
|
||||
//! \param src : 추출할 VideoItem 리스트
|
||||
//! \param res : Thumbnail 경로 <CH1,CH2>
|
||||
void loadThumbnails(QList<RMVideoItem*>& src, QList<QPair<QString,QString>>& res);
|
||||
#endif // USE_1HOUR_FILTER
|
||||
|
||||
#if (USE_DATE_TIME_LIST)
|
||||
//! \brief 파일리스트 중 지정된 년/월 에 영상인 포함된 날짜만 리턴
|
||||
//! \param year: 지정된 년
|
||||
//! \param month: 지정된 월
|
||||
//! \param ret<out>: 영상이 존재하는 일 리스트
|
||||
//! \param dayItems<out>: 속도개선을 위해 해당일자의 파일리스트 리턴
|
||||
void getMonthList(int year, int month, QSet<int>& ret, QList<RMVideoItem*>& dayItems);
|
||||
|
||||
//! \brief 로딩된 파일 중 가장 먼저 녹화된 날짜 확인
|
||||
//! \return
|
||||
QDate getFirstDate();
|
||||
|
||||
#endif// USE_DATE_TIME_LIST
|
||||
|
||||
#ifdef _DEBUG
|
||||
void print();
|
||||
#endif
|
||||
|
||||
#if !(USE_1HOUR_FILTER)
|
||||
//! \brief 백업용으로 선택된 항목 초기화
|
||||
void clearChecked();
|
||||
#endif // #if !(USE_1HOUR_FILTER)
|
||||
private:
|
||||
|
||||
#if (USE_1HOUR_FILTER)
|
||||
bool b1HourList; // 1시간 단위 리스트
|
||||
public:
|
||||
|
||||
int count1Hour; // 텍스트 표시용
|
||||
//! \brief 데이터 로딩 후 All 및 1Hour 영상 개수 확인
|
||||
void count1HourItems();
|
||||
|
||||
QDateTime simpleFromDateTime(QDateTime& startTime);
|
||||
//! \brief 리스트 텍스트 색사용
|
||||
//! \param startTime
|
||||
//! \return
|
||||
QDateTime simpleFromDateTime2(QDateTime& startTime);
|
||||
private:
|
||||
|
||||
//! \brief 현재 선택된 아이템이 전체<->1HOUR 리스트 전환시 유지
|
||||
//! \param searchItem: 현재 선택된 아이템
|
||||
//! \return 이후 선택될 아이템
|
||||
RMVideoItem* findFirstItemIn1Hour(RMVideoItem* searchItem);
|
||||
#endif // #if (USE_1HOUR_FILTER)
|
||||
|
||||
QList<RMVideoItem*> _items; // 전체 아이템
|
||||
QList<RMVideoItem*> _filteredItems; // 필터 적용된 아이템
|
||||
#if !(USE_1HOUR_FILTER)
|
||||
void _updateItemsByFilter(); // 필터 적용 후
|
||||
#endif // #if (USE_1HOUR_FILTER)
|
||||
|
||||
|
||||
|
||||
#if !(RECURSIVE_APPEND_FILE)
|
||||
static void _appendFrontRear(QString& folder,QList<QUrl>& list);
|
||||
#endif
|
||||
|
||||
#if (!(FORCE_2CH) && (!SINGLE_CH_VIEWER))
|
||||
#if (TRI_CHANNEL || PENTA_CHANNEL)
|
||||
QString _checkChannelInfo(QString filePath,int *ch);
|
||||
#else // TRI_CHANNEL
|
||||
QString _checkChannelInfo(QString filePath,bool *isCH2, bool *is2CH = NULL);
|
||||
#endif // TRI_CHANNEL
|
||||
bool _addOtherChannelFile(RMVideoItem* item);
|
||||
#endif
|
||||
void _backupOverwrite(QString target,QString src,int countLeft);
|
||||
|
||||
public:
|
||||
void loadFromList(QList<QUrl> list,bool bPlayFirstAdded = false);
|
||||
|
||||
//! \brief 리스트 삭제하고 이벤트 전달
|
||||
void clearList();
|
||||
|
||||
//! \brief item 존재할 경우 파일 재생
|
||||
//! \param item: 재생할 item
|
||||
void playItem(RMVideoItem* item);
|
||||
|
||||
//! \brief 파일 경로로 item 탐색
|
||||
//! \param path : 탐색할 경로
|
||||
//! \return
|
||||
RMVideoItem* itemWithPath(QString path);
|
||||
|
||||
//!
|
||||
//! \brief 파일 로딩 후 선택된 녹화타입 확인용
|
||||
//! 현재 선택된 필터의 INDEX 를 리턴
|
||||
//!
|
||||
int currentFilterIndex();
|
||||
|
||||
protected:
|
||||
int _filter;
|
||||
RMVideoItem* _playItem; // 현재 플레이 아이템
|
||||
|
||||
void backup(QString dest); // 보존
|
||||
|
||||
bool addItem(QString filePath, QDateTime* pDateTime,GROUP_TYPE type);
|
||||
|
||||
bool itemExist(QString filePath);
|
||||
// List Widget 에서만 호출 할 수 있도록 변경
|
||||
void setPlayItem(RMVideoItem* item)
|
||||
{
|
||||
_playItem = item;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
explicit RMVideoFileList(QObject* parent = 0);
|
||||
|
||||
//! \brief 파일 시작명으로 재생 아이템 탐색
|
||||
//! \param prefix: eg. 20231007-040556_PSR0_0017
|
||||
//! \return 탐색된 재생 리스트 아이템 , 없으면 NULL
|
||||
RMVideoItem* searchPlayItem(QString prefix);
|
||||
|
||||
static FILTER filterTypeFromGroupType(GROUP_TYPE type)
|
||||
{
|
||||
FILTER t = FILTER_NONE;
|
||||
switch (type) {
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_XLDR_88)
|
||||
case TYPE_NORMAL:
|
||||
case TYPE_MANUAL:
|
||||
t = FILTER_NORMAL;
|
||||
break;
|
||||
case TYPE_EVENT:
|
||||
case TYPE_PARKING_EVENT:
|
||||
case TYPE_PARKING_MOTION:
|
||||
t = FILTER_EVENT;
|
||||
break;
|
||||
case TYPE_PARKING:
|
||||
t = FILTER_PARK;
|
||||
break;
|
||||
}
|
||||
#elif (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || RM_MODEL == RM_MODEL_TYPE_MBJ5010 || RM_MODEL == RM_MODEL_TYPE_FC_DR232W || RM_MODEL == RM_MODEL_TYPE_BV2000 || RM_MODEL == RM_MODEL_TYPE_MH9000)
|
||||
case TYPE_NORMAL:
|
||||
t = FILTER_NORMAL;
|
||||
break;
|
||||
//#if !(RM_MODEL == RM_MODEL_TYPE_MH9000)
|
||||
case TYPE_MANUAL:
|
||||
t = FILTER_MANUAL;
|
||||
break;
|
||||
//#endif // RM_MODEL == RM_MODEL_TYPE_MH9000
|
||||
case TYPE_PARKING:
|
||||
case TYPE_PARKING_EVENT:
|
||||
t = FILTER_PARK;
|
||||
break;
|
||||
case TYPE_EVENT:
|
||||
case TYPE_PARKING_MOTION:
|
||||
t = FILTER_EVENT;
|
||||
break;
|
||||
}
|
||||
#elif (RM_MODEL_EMT_KR)
|
||||
case TYPE_NORMAL:
|
||||
t = FILTER_NORMAL;
|
||||
break;
|
||||
case TYPE_EVENT:
|
||||
t = FILTER_EVENT;
|
||||
break;
|
||||
case TYPE_PARKING:
|
||||
t = FILTER_PARK;
|
||||
break;
|
||||
case TYPE_PARKING_EVENT:
|
||||
t = FILTER_PARK_EVENT;
|
||||
break;
|
||||
case TYPE_MANUAL:
|
||||
t = FILTER_MANUAL;
|
||||
break;
|
||||
case TYPE_MY_BOX:
|
||||
t = FILTER_MYBOX;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case TYPE_NORMAL:
|
||||
t = FILTER_NORMAL;
|
||||
break;
|
||||
case TYPE_EVENT:
|
||||
case TYPE_PARKING_EVENT:
|
||||
case TYPE_PARKING_MOTION:
|
||||
t = FILTER_EVENT;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
QList<RMVideoItem*>& allItems() { return _items; }
|
||||
QList<RMVideoItem*>& filteredItems()
|
||||
{
|
||||
return _filteredItems;
|
||||
}
|
||||
void checkedItems(QList<RMVideoItem*>& items);
|
||||
|
||||
#if (PLAYER_ONLY_LIBRARY_MODE)
|
||||
static RMVideoFileList * _instance;
|
||||
static void updateInstance(RMVideoFileList* instance)
|
||||
{
|
||||
_instance = instance;
|
||||
}
|
||||
static RMVideoFileList* instance()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
#else // PLAYER_ONLY_LIBRARY_MODE
|
||||
// singletone
|
||||
static RMVideoFileList* instance()
|
||||
{
|
||||
static RMVideoFileList * _instance = 0;
|
||||
if ( _instance == 0 ) {
|
||||
_instance = new RMVideoFileList();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
#endif // PLAYER_ONLY_LIBRARY_MODE
|
||||
|
||||
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
|
||||
/**
|
||||
* @brief 로딩된 파일 중 가장 많은 파일이 존재하는 녹화타입 선택
|
||||
*/
|
||||
void selectMaxCountFilter();
|
||||
#endif // RM_MODEL_EMT_KR
|
||||
|
||||
#if !(USE_1HOUR_FILTER)
|
||||
bool checkFilter(RMVideoFileList::FILTER filter)
|
||||
{
|
||||
return ((_filter & filter) == filter);
|
||||
}
|
||||
|
||||
void setFilter(RMVideoFileList::FILTER filter, bool on);
|
||||
void setFilterSingle(RMVideoFileList::FILTER filter);
|
||||
#endif // #if !(USE_1HOUR_FILTER)
|
||||
|
||||
RMVideoItem* getPlayItem() // 현재 플레이 중이면 다시 플레이 하지 않는다.
|
||||
{
|
||||
return _playItem;
|
||||
}
|
||||
int getPlayIndex() // 현재 그룹에서 플레이 중인 인덱스 리턴
|
||||
{
|
||||
if(_playItem == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return filteredItems().indexOf(_playItem);
|
||||
}
|
||||
//! \brief 영상 경로를 썸네일 경로로 변경
|
||||
//! \param item: 추출할 아이템
|
||||
//! \return
|
||||
static QPair<QString,QString> getThumbnailPath(RMVideoItem* item);
|
||||
|
||||
static bool isRootPath(QString folderPath);
|
||||
int removeItem(RMVideoItem* item); // 플레이중 삭제 등으로 사라진 아이템 제거
|
||||
|
||||
// List.appendToList
|
||||
#if (RECURSIVE_APPEND_FILE)
|
||||
static void appendFolderToList(QString rootFolderPath,QList<QUrl>& list,int depth=0);
|
||||
#else
|
||||
static void appendFolderToList(QString rootFolderPath,QList<QUrl>& list);
|
||||
// Group.appendToList
|
||||
static void appendToList(QString folderPath,QList<QUrl>& list, bool baseFolderOnly);
|
||||
#endif
|
||||
|
||||
static RMVideoFileList::GROUP_TYPE checkGroupTypeFromFolderPath(QString folderPath);
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
||||
static int parseSerial(QString baseName);
|
||||
static QString groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type, int* serial);
|
||||
#else // RM_MODEL_TYPE_AN6000
|
||||
static QString groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type);
|
||||
#endif // RM_MODEL_TYPE_AN6000
|
||||
bool isNextPlayItemExist(bool bNext);
|
||||
RMVideoItem* nexItem(bool bNext);
|
||||
private:
|
||||
bool _searchItem(bool next, RMVideoItem** item,int fromIndex); // 탐색 next = +1, previous = -1
|
||||
|
||||
|
||||
|
||||
public slots:
|
||||
void onPlayNextVideo(int fromIndex);
|
||||
void onPlayPreviousVideo(int fromIndex);
|
||||
|
||||
signals:
|
||||
// 리스트 업데이트 시작(파일 로딩 또는 필터 변경시 호출)
|
||||
void listUpdateStarted(bool bLoading);
|
||||
void listUpdateEnd(bool bLoading,RMVideoItem* selected);
|
||||
|
||||
// 리스트의 경우 타입이 변경되어도 이벤트가 발생하니 로딩 종료시에만 처리
|
||||
void loadListEnd();
|
||||
|
||||
void backupStarted();
|
||||
void backupEnd();
|
||||
void backupPaused(bool bPaused);
|
||||
|
||||
// 다음 플레이 아이템 확인, 더이상 없음
|
||||
void playItemFound(RMVideoItem* item,int old);
|
||||
void playNoMoreItem();
|
||||
|
||||
void updateProgress(int value);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // RM_VIDEOFILELIST_H
|
||||
6
project/fm_viewer/data/rm_video_list_loader.cpp
Normal file
6
project/fm_viewer/data/rm_video_list_loader.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "rm_video_list_loader.h"
|
||||
|
||||
//RMVideoListLoader::RMVideoListLoader()
|
||||
//{
|
||||
|
||||
//}
|
||||
42
project/fm_viewer/data/rm_video_list_loader.h
Normal file
42
project/fm_viewer/data/rm_video_list_loader.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef RM_VIDEO_LIST_LOADER_H
|
||||
#define RM_VIDEO_LIST_LOADER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QRunnable>
|
||||
#include <QThreadPool>
|
||||
#include "../rm_include.h"
|
||||
#include "rm_video_list.h"
|
||||
|
||||
class RMVideoFileListLoader : public QRunnable
|
||||
{
|
||||
private:
|
||||
QList<QUrl> _list;
|
||||
bool _bPlayFirstAdded; // 추가된 1st 파일 즉시 플레이
|
||||
public:
|
||||
RMVideoFileListLoader(QList<QUrl>& list, bool bPlayFirstAdded = false)
|
||||
{
|
||||
_bPlayFirstAdded = bPlayFirstAdded;
|
||||
_list = list;
|
||||
}
|
||||
virtual void run()
|
||||
{
|
||||
RMVideoFileList::instance()->loadFromList(_list,_bPlayFirstAdded);
|
||||
}
|
||||
};
|
||||
|
||||
class RMVideoFileListBackup : public QRunnable
|
||||
{
|
||||
private:
|
||||
QString _dest;
|
||||
public:
|
||||
RMVideoFileListBackup(QString dest)
|
||||
{
|
||||
_dest = dest;
|
||||
}
|
||||
virtual void run()
|
||||
{
|
||||
RMVideoFileList::instance()->backup(_dest);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // RM_VIDEO_LIST_LOADER_H
|
||||
275
project/fm_viewer/fav/AVClock.cpp
Normal file
275
project/fm_viewer/fav/AVClock.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#include "AVClock.h"
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QTimerEvent>
|
||||
#include <QtCore/QDateTime>
|
||||
#include "Logger.h"
|
||||
|
||||
namespace FAV {
|
||||
enum {
|
||||
kRunning,
|
||||
kPaused,
|
||||
kStopped
|
||||
};
|
||||
AVClock::AVClock(AVClock::ClockType c, QObject *parent):
|
||||
QObject(parent)
|
||||
, auto_clock(true)
|
||||
, m_state(kStopped)
|
||||
, clock_type(c)
|
||||
, mSpeed(1.0)
|
||||
, value0(0)
|
||||
, avg_err(0)
|
||||
, nb_restarted(0)
|
||||
, nb_sync(0)
|
||||
, sync_id(0)
|
||||
{
|
||||
last_pts = pts_ = pts_v = delay_ = 0;
|
||||
}
|
||||
|
||||
AVClock::AVClock(QObject *parent):
|
||||
QObject(parent)
|
||||
, auto_clock(true)
|
||||
, m_state(kStopped)
|
||||
, clock_type(AudioClock)
|
||||
, mSpeed(1.0)
|
||||
, value0(0)
|
||||
, avg_err(0)
|
||||
, nb_restarted(0)
|
||||
, nb_sync(0)
|
||||
, sync_id(0)
|
||||
{
|
||||
last_pts = pts_ = pts_v = delay_ = 0;
|
||||
}
|
||||
|
||||
void AVClock::setClockType(ClockType ct)
|
||||
{
|
||||
if (clock_type == ct)
|
||||
return;
|
||||
clock_type = ct;
|
||||
QTimer::singleShot(0, this, SLOT(restartCorrectionTimer()));
|
||||
}
|
||||
|
||||
AVClock::ClockType AVClock::clockType() const
|
||||
{
|
||||
return clock_type;
|
||||
}
|
||||
|
||||
bool AVClock::isActive() const
|
||||
{
|
||||
return clock_type == AudioClock || timer.isValid();
|
||||
}
|
||||
|
||||
void AVClock::setInitialValue(double v)
|
||||
{
|
||||
value0 = v;
|
||||
qDebug("Clock initial value: %f", v);
|
||||
}
|
||||
|
||||
double AVClock::initialValue() const
|
||||
{
|
||||
return value0;
|
||||
}
|
||||
|
||||
void AVClock::setClockAuto(bool a)
|
||||
{
|
||||
auto_clock = a;
|
||||
}
|
||||
|
||||
bool AVClock::isClockAuto() const
|
||||
{
|
||||
return auto_clock;
|
||||
}
|
||||
|
||||
void AVClock::updateExternalClock(qint64 msecs)
|
||||
{
|
||||
if (clock_type == AudioClock)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if !(OFF_OTHER_DEBUG)
|
||||
qDebug("External clock change: %f ==> %f", value(), double(msecs) * kThousandth);
|
||||
#endif
|
||||
pts_ = double(msecs) * kThousandth; //can not use msec/1000.
|
||||
if (!isPaused())
|
||||
{
|
||||
timer.restart();
|
||||
}
|
||||
|
||||
last_pts = pts_;
|
||||
t = QDateTime::currentMSecsSinceEpoch();
|
||||
if (clockType() == VideoClock)
|
||||
{
|
||||
pts_v = pts_;
|
||||
}
|
||||
}
|
||||
|
||||
void AVClock::updateExternalClock(const AVClock &clock)
|
||||
{
|
||||
if (clock_type != ExternalClock)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if !(OFF_OTHER_DEBUG)
|
||||
qDebug("External clock change: %f ==> %f", value(), clock.value());
|
||||
#endif
|
||||
pts_ = clock.value();
|
||||
|
||||
// qInfo() << "C:" << pts_;
|
||||
if (!isPaused())
|
||||
timer.restart();
|
||||
|
||||
last_pts = pts_;
|
||||
t = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
void AVClock::setSpeed(qreal speed)
|
||||
{
|
||||
mSpeed = speed;
|
||||
}
|
||||
|
||||
bool AVClock::isPaused() const
|
||||
{
|
||||
return m_state == kPaused;
|
||||
}
|
||||
|
||||
// SYNC START 처리하면
|
||||
//
|
||||
int AVClock::syncStart(int count)
|
||||
{
|
||||
static int sId = 0;
|
||||
nb_sync = count;
|
||||
if (sId == -1) {
|
||||
sId = 0;
|
||||
}
|
||||
sync_id = ++sId;
|
||||
return sId;
|
||||
}
|
||||
|
||||
bool AVClock::syncEndOnce(int id)
|
||||
{
|
||||
if (id != sync_id)
|
||||
{
|
||||
qWarning("bad sync id: %d, current: %d", id, sync_id);
|
||||
return true;
|
||||
}
|
||||
if (!nb_sync.deref()) {
|
||||
sync_id = 0;
|
||||
}
|
||||
return sync_id;
|
||||
}
|
||||
|
||||
void AVClock::start()
|
||||
{
|
||||
m_state = kRunning;
|
||||
qDebug("AVClock started!!!!!!!!");
|
||||
timer.start();
|
||||
QTimer::singleShot(0, this, SLOT(restartCorrectionTimer()));
|
||||
Q_EMIT started();
|
||||
}
|
||||
//remember last value because we don't reset pts_, pts_v, delay_
|
||||
void AVClock::pause(bool p)
|
||||
{
|
||||
if (isPaused() == p)
|
||||
return;
|
||||
if (clock_type == AudioClock)
|
||||
return;
|
||||
m_state = p ? kPaused : kRunning;
|
||||
if (p) {
|
||||
QTimer::singleShot(0, this, SLOT(stopCorrectionTimer()));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
timer.invalidate();
|
||||
#else
|
||||
timer.stop();
|
||||
#endif //QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
Q_EMIT paused();
|
||||
} else {
|
||||
timer.start();
|
||||
QTimer::singleShot(0, this, SLOT(restartCorrectionTimer()));
|
||||
Q_EMIT resumed();
|
||||
}
|
||||
t = QDateTime::currentMSecsSinceEpoch();
|
||||
Q_EMIT paused(p);
|
||||
}
|
||||
|
||||
void AVClock::reset()
|
||||
{
|
||||
nb_sync = 0;
|
||||
sync_id = 0;
|
||||
// keep mSpeed
|
||||
m_state = kStopped;
|
||||
value0 = 0;
|
||||
pts_ = pts_v = delay_ = 0;
|
||||
QTimer::singleShot(0, this, SLOT(stopCorrectionTimer()));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
timer.invalidate();
|
||||
#else
|
||||
timer.stop();
|
||||
#endif //QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
t = QDateTime::currentMSecsSinceEpoch();
|
||||
Q_EMIT resetted();
|
||||
}
|
||||
|
||||
void AVClock::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
Q_ASSERT_X(clockType() != AudioClock, "AVClock::timerEvent", "Internal error. AudioClock can not call this");
|
||||
if (event->timerId() != correction_schedule_timer.timerId())
|
||||
return;
|
||||
if (isPaused())
|
||||
return;
|
||||
const double delta_pts = (value() - last_pts)/speed();
|
||||
//const double err = double(correction_timer.restart()) * kThousandth - delta_pts;
|
||||
const qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||
const double err = double(now - t) * kThousandth - delta_pts;
|
||||
t = now;
|
||||
// FIXME: avfoundation camera error is large (about -0.6s)
|
||||
if (qAbs(err*10.0) < kCorrectionInterval || clock_type == VideoClock) {
|
||||
avg_err += err/(nb_restarted+1);
|
||||
}
|
||||
//qDebug("correction timer event. error = %f, avg_err=%f, nb_restarted=%d", err, avg_err, nb_restarted);
|
||||
last_pts = value();
|
||||
nb_restarted = 0;
|
||||
}
|
||||
|
||||
void AVClock::restartCorrectionTimer()
|
||||
{
|
||||
nb_restarted = 0;
|
||||
avg_err = 0;
|
||||
correction_schedule_timer.stop();
|
||||
if (clockType() == AudioClock) // TODO: for all clock type
|
||||
return;
|
||||
// parameters are reset. do not start correction timer if not running
|
||||
if (m_state != kRunning)
|
||||
return;
|
||||
// timer is always started in AVClock::start()
|
||||
if (!timer.isValid())
|
||||
return;
|
||||
t = QDateTime::currentMSecsSinceEpoch();
|
||||
correction_schedule_timer.start(kCorrectionInterval*1000, this);
|
||||
}
|
||||
|
||||
void AVClock::stopCorrectionTimer()
|
||||
{
|
||||
nb_restarted = 0;
|
||||
avg_err = 0;
|
||||
correction_schedule_timer.stop();
|
||||
}
|
||||
} //namespace FAV
|
||||
221
project/fm_viewer/fav/AVClock.h
Normal file
221
project/fm_viewer/fav/AVClock.h
Normal file
@@ -0,0 +1,221 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef QTAV_AVCLOCK_H
|
||||
#define QTAV_AVCLOCK_H
|
||||
|
||||
#include "_fav_constants.h"
|
||||
#include <QtCore/QAtomicInt>
|
||||
#include <QtCore/QBasicTimer>
|
||||
#include <QtCore/QObject>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#else
|
||||
#include <QtCore/QTime>
|
||||
typedef QTime QElapsedTimer;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AVClock is created by AVPlayer. The only way to access AVClock is through AVPlayer::masterClock()
|
||||
* The default clock type is Audio's clock, i.e. vedio synchronizes to audio. If audio stream is not
|
||||
* detected, then the clock will set to External clock automatically.
|
||||
* I name it ExternalClock because the clock can be corrected outside, though it is a clock inside AVClock
|
||||
*/
|
||||
namespace FAV {
|
||||
|
||||
static const double kThousandth = 0.001;
|
||||
|
||||
class Q_AV_EXPORT AVClock : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef enum {
|
||||
AudioClock = 0,
|
||||
ExternalClock = 1,
|
||||
VideoClock = 2, //sync to video timestamp
|
||||
} ClockType;
|
||||
|
||||
AVClock(ClockType c, QObject* parent = 0);
|
||||
AVClock(QObject* parent = 0);
|
||||
void setClockType(ClockType ct);
|
||||
ClockType clockType() const;
|
||||
bool isActive() const;
|
||||
/*!
|
||||
* \brief setInitialValue
|
||||
* Usually for ExternalClock. For example, media start time is not 0, clock have to set initial value as media start time
|
||||
*/
|
||||
void setInitialValue(double v);
|
||||
double initialValue() const;
|
||||
/*
|
||||
* auto clock: use audio clock if audio stream found, otherwise use external clock
|
||||
*/
|
||||
void setClockAuto(bool a);
|
||||
bool isClockAuto() const;
|
||||
/*in seconds*/
|
||||
inline double pts() const;
|
||||
/*!
|
||||
* \brief value
|
||||
* the real timestamp in seconds: pts + delay
|
||||
* \return
|
||||
*/
|
||||
inline double value() const;
|
||||
inline void updateValue(double pts); //update the pts
|
||||
/*used when seeking and correcting from external*/
|
||||
void updateExternalClock(qint64 msecs);
|
||||
/*external clock outside still running, so it's more accurate for syncing multiple clocks serially*/
|
||||
void updateExternalClock(const AVClock& clock);
|
||||
|
||||
inline void updateVideoTime(double pts);
|
||||
inline double videoTime() const;
|
||||
inline double delay() const; //playing audio spends some time
|
||||
inline void updateDelay(double delay);
|
||||
inline qreal diff() const;
|
||||
|
||||
void setSpeed(qreal speed);
|
||||
inline qreal speed() const;
|
||||
|
||||
bool isPaused() const;
|
||||
|
||||
/*!
|
||||
* \brief syncStart
|
||||
* For internal use now
|
||||
* Start to sync "count" objects. Call syncEndOnce(id) "count" times to end sync.
|
||||
* \param count Number of objects to sync. Each one should call syncEndOnce(int id)
|
||||
* \return an id
|
||||
*/
|
||||
int syncStart(int count);
|
||||
int syncId() const {return sync_id;}
|
||||
/*!
|
||||
* \brief syncEndOnce
|
||||
* Decrease sync objects count if id is current sync id.
|
||||
* \return true if sync is end for id or id is not current sync id
|
||||
*/
|
||||
bool syncEndOnce(int id);
|
||||
|
||||
Q_SIGNALS:
|
||||
void paused(bool);
|
||||
void paused(); //equals to paused(true)
|
||||
void resumed();//equals to paused(false)
|
||||
void started();
|
||||
void resetted();
|
||||
public Q_SLOTS:
|
||||
//these slots are not frequently used. so not inline
|
||||
/*start the external clock*/
|
||||
void start();
|
||||
/*pause external clock*/
|
||||
void pause(bool p);
|
||||
/*reset clock intial value and external clock parameters (and stop timer). keep speed() and isClockAuto()*/
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
virtual void timerEvent(QTimerEvent *event);
|
||||
private Q_SLOTS:
|
||||
/// make sure QBasic timer start/stop in a right thread
|
||||
void restartCorrectionTimer();
|
||||
void stopCorrectionTimer();
|
||||
private:
|
||||
bool auto_clock;
|
||||
int m_state;
|
||||
ClockType clock_type;
|
||||
mutable double pts_;
|
||||
mutable double pts_v;
|
||||
double delay_;
|
||||
mutable QElapsedTimer timer;
|
||||
qreal mSpeed;
|
||||
double value0;
|
||||
/*!
|
||||
* \brief correction_schedule_timer
|
||||
* accumulative error is too large using QElapsedTimer.restart() frequently.
|
||||
* we periodically correct value() to keep the error always less
|
||||
* than the error of calling QElapsedTimer.restart() once
|
||||
* see github issue 46, 307 etc
|
||||
*/
|
||||
QBasicTimer correction_schedule_timer;
|
||||
qint64 t; // absolute time for elapsed timer correction
|
||||
static const int kCorrectionInterval = 1; // 1000ms
|
||||
double last_pts;
|
||||
double avg_err; // average error of restart()
|
||||
mutable int nb_restarted;
|
||||
QAtomicInt nb_sync;
|
||||
int sync_id;
|
||||
};
|
||||
|
||||
double AVClock::value() const
|
||||
{
|
||||
if (clock_type == AudioClock) {
|
||||
// TODO: audio clock need a timer too
|
||||
// timestamp from media stream is >= value0
|
||||
return pts_ == 0 ? value0 : pts_ + delay_;
|
||||
} else if (clock_type == ExternalClock) {
|
||||
if (timer.isValid()) {
|
||||
++nb_restarted;
|
||||
pts_ += (double(timer.restart()) * kThousandth + avg_err)* speed();
|
||||
} else {//timer is paused
|
||||
//qDebug("clock is paused. return the last value %f", pts_);
|
||||
}
|
||||
return pts_ + value0;
|
||||
} else {
|
||||
return pts_v; // value0 is 1st video pts_v already
|
||||
}
|
||||
}
|
||||
|
||||
void AVClock::updateValue(double pts)
|
||||
{
|
||||
if (clock_type == AudioClock)
|
||||
{
|
||||
pts_ = pts;
|
||||
}
|
||||
}
|
||||
|
||||
void AVClock::updateVideoTime(double pts)
|
||||
{
|
||||
pts_v = pts;
|
||||
if (clock_type == VideoClock)
|
||||
timer.restart();
|
||||
}
|
||||
|
||||
double AVClock::videoTime() const
|
||||
{
|
||||
return pts_v;
|
||||
}
|
||||
|
||||
double AVClock::delay() const
|
||||
{
|
||||
return delay_;
|
||||
}
|
||||
|
||||
void AVClock::updateDelay(double delay)
|
||||
{
|
||||
delay_ = delay;
|
||||
}
|
||||
|
||||
qreal AVClock::diff() const
|
||||
{
|
||||
return value() - videoTime();
|
||||
}
|
||||
|
||||
qreal AVClock::speed() const
|
||||
{
|
||||
return mSpeed;
|
||||
}
|
||||
|
||||
} //namespace FAV
|
||||
#endif // QTAV_AVCLOCK_H
|
||||
415
project/fm_viewer/fav/AVCompat.cpp
Normal file
415
project/fm_viewer/fav/AVCompat.cpp
Normal file
@@ -0,0 +1,415 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
|
||||
#include "AVCompat.h"
|
||||
#include "version.h"
|
||||
|
||||
#if !FFMPEG_MODULE_CHECK(LIBAVFORMAT, 56, 4, 101)
|
||||
int avio_feof(AVIOContext *s)
|
||||
{
|
||||
#if QTAV_USE_FFMPEG(LIBAVFORMAT)
|
||||
return url_feof(s);
|
||||
#else
|
||||
return s && s->eof_reached;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if QTAV_USE_LIBAV(LIBAVFORMAT)
|
||||
int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *oformat, const char *format, const char *filename)
|
||||
{
|
||||
AVFormatContext *s = avformat_alloc_context();
|
||||
int ret = 0;
|
||||
|
||||
*avctx = NULL;
|
||||
if (!s)
|
||||
goto nomem;
|
||||
|
||||
if (!oformat) {
|
||||
if (format) {
|
||||
oformat = av_guess_format(format, NULL, NULL);
|
||||
if (!oformat) {
|
||||
av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);
|
||||
ret = AVERROR(EINVAL);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
oformat = av_guess_format(NULL, filename, NULL);
|
||||
if (!oformat) {
|
||||
ret = AVERROR(EINVAL);
|
||||
av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n",
|
||||
filename);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s->oformat = oformat;
|
||||
if (s->oformat->priv_data_size > 0) {
|
||||
s->priv_data = av_mallocz(s->oformat->priv_data_size);
|
||||
if (!s->priv_data)
|
||||
goto nomem;
|
||||
if (s->oformat->priv_class) {
|
||||
*(const AVClass**)s->priv_data= s->oformat->priv_class;
|
||||
av_opt_set_defaults(s->priv_data);
|
||||
}
|
||||
} else
|
||||
s->priv_data = NULL;
|
||||
|
||||
if (filename)
|
||||
av_strlcpy(s->filename, filename, sizeof(s->filename));
|
||||
*avctx = s;
|
||||
return 0;
|
||||
nomem:
|
||||
av_log(s, AV_LOG_ERROR, "Out of memory\n");
|
||||
ret = AVERROR(ENOMEM);
|
||||
error:
|
||||
avformat_free_context(s);
|
||||
return ret;
|
||||
}
|
||||
#endif //QTAV_USE_LIBAV(LIBAVFORMAT)
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 32, 0)
|
||||
static const struct {
|
||||
const char *name;
|
||||
int nb_channels;
|
||||
uint64_t layout;
|
||||
} channel_layout_map[] = {
|
||||
{ "mono", 1, AV_CH_LAYOUT_MONO },
|
||||
{ "stereo", 2, AV_CH_LAYOUT_STEREO },
|
||||
{ "4.0", 4, AV_CH_LAYOUT_4POINT0 },
|
||||
{ "quad", 4, AV_CH_LAYOUT_QUAD },
|
||||
{ "5.0", 5, AV_CH_LAYOUT_5POINT0 },
|
||||
{ "5.0", 5, AV_CH_LAYOUT_5POINT0_BACK },
|
||||
{ "5.1", 6, AV_CH_LAYOUT_5POINT1 },
|
||||
{ "5.1", 6, AV_CH_LAYOUT_5POINT1_BACK },
|
||||
{ "5.1+downmix", 8, AV_CH_LAYOUT_5POINT1|AV_CH_LAYOUT_STEREO_DOWNMIX, },
|
||||
{ "7.1", 8, AV_CH_LAYOUT_7POINT1 },
|
||||
{ "7.1(wide)", 8, AV_CH_LAYOUT_7POINT1_WIDE },
|
||||
{ "7.1+downmix", 10, AV_CH_LAYOUT_7POINT1|AV_CH_LAYOUT_STEREO_DOWNMIX, },
|
||||
{ 0 }
|
||||
};
|
||||
int64_t av_get_default_channel_layout(int nb_channels) {
|
||||
int i;
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
|
||||
if (nb_channels == channel_layout_map[i].nb_channels)
|
||||
return channel_layout_map[i].layout;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* always need this function if avresample available
|
||||
* use AVAudioResampleContext to avoid func type confliction when swr is also available
|
||||
*/
|
||||
#if QTAV_HAVE(AVRESAMPLE)
|
||||
AVAudioResampleContext *swr_alloc_set_opts(AVAudioResampleContext *s
|
||||
, int64_t out_ch_layout
|
||||
, enum AVSampleFormat out_sample_fmt
|
||||
, int out_sample_rate
|
||||
, int64_t in_ch_layout
|
||||
, enum AVSampleFormat in_sample_fmt
|
||||
, int in_sample_rate
|
||||
, int log_offset, void *log_ctx)
|
||||
{
|
||||
//DO NOT use swr_alloc() because it's not defined as a macro in QtAV_Compat.h
|
||||
if (!s)
|
||||
s = avresample_alloc_context();
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
Q_UNUSED(log_offset);
|
||||
Q_UNUSED(log_ctx);
|
||||
|
||||
av_opt_set_int(s, "out_channel_layout", out_ch_layout , 0);
|
||||
av_opt_set_int(s, "out_sample_fmt" , out_sample_fmt , 0);
|
||||
av_opt_set_int(s, "out_sample_rate" , out_sample_rate, 0);
|
||||
av_opt_set_int(s, "in_channel_layout" , in_ch_layout , 0);
|
||||
av_opt_set_int(s, "in_sample_fmt" , in_sample_fmt , 0);
|
||||
av_opt_set_int(s, "in_sample_rate" , in_sample_rate , 0);
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !AV_MODULE_CHECK(LIBAVUTIL, 52, 3, 0, 13, 100)
|
||||
extern const AVPixFmtDescriptor av_pix_fmt_descriptors[];
|
||||
const AVPixFmtDescriptor *av_pix_fmt_desc_get(AVPixelFormat pix_fmt)
|
||||
{
|
||||
if (pix_fmt < 0 || pix_fmt >= QTAV_PIX_FMT_C(NB))
|
||||
return NULL;
|
||||
return &av_pix_fmt_descriptors[pix_fmt];
|
||||
}
|
||||
|
||||
const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev)
|
||||
{
|
||||
if (!prev)
|
||||
return &av_pix_fmt_descriptors[0];
|
||||
// can not use sizeof(av_pix_fmt_descriptors)
|
||||
while (prev - av_pix_fmt_descriptors < QTAV_PIX_FMT_C(NB) - 1) {
|
||||
prev++;
|
||||
if (prev->name)
|
||||
return prev;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc)
|
||||
{
|
||||
if (desc < av_pix_fmt_descriptors ||
|
||||
desc >= av_pix_fmt_descriptors + QTAV_PIX_FMT_C(NB))
|
||||
return QTAV_PIX_FMT_C(NONE);
|
||||
|
||||
return AVPixelFormat(desc - av_pix_fmt_descriptors);
|
||||
}
|
||||
#endif // !AV_MODULE_CHECK(LIBAVUTIL, 52, 3, 0, 13, 100)
|
||||
#if !FFMPEG_MODULE_CHECK(LIBAVUTIL, 52, 48, 101)
|
||||
enum AVColorSpace av_frame_get_colorspace(const AVFrame *frame)
|
||||
{
|
||||
if (!frame)
|
||||
return AVCOL_SPC_NB;
|
||||
#if LIBAV_MODULE_CHECK(LIBAVUTIL, 53, 16, 0) //8c02adc
|
||||
return frame->colorspace;
|
||||
#endif
|
||||
return AVCOL_SPC_NB;
|
||||
}
|
||||
|
||||
enum AVColorRange av_frame_get_color_range(const AVFrame *frame)
|
||||
{
|
||||
if (!frame)
|
||||
return AVCOL_RANGE_UNSPECIFIED;
|
||||
#if LIBAV_MODULE_CHECK(LIBAVUTIL, 53, 16, 0) //8c02adc
|
||||
return frame->color_range;
|
||||
#endif
|
||||
return AVCOL_RANGE_UNSPECIFIED;
|
||||
}
|
||||
#endif //!FFMPEG_MODULE_CHECK(LIBAVUTIL, 52, 28, 101)
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 38, 100)
|
||||
int av_pix_fmt_count_planes(AVPixelFormat pix_fmt)
|
||||
{
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
|
||||
int i, planes[4] = { 0 }, ret = 0;
|
||||
|
||||
if (!desc)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
for (i = 0; i < desc->nb_components; i++)
|
||||
planes[desc->comp[i].plane] = 1;
|
||||
for (i = 0; i < (int)FF_ARRAY_ELEMS(planes); i++)
|
||||
ret += planes[i];
|
||||
return ret;
|
||||
}
|
||||
#endif //AV_VERSION_INT(52, 38, 100)
|
||||
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 73, 101)
|
||||
int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset,
|
||||
int src_offset, int nb_samples, int nb_channels,
|
||||
enum AVSampleFormat sample_fmt)
|
||||
{
|
||||
int planar = av_sample_fmt_is_planar(sample_fmt);
|
||||
int planes = planar ? nb_channels : 1;
|
||||
int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels);
|
||||
int data_size = nb_samples * block_align;
|
||||
int i;
|
||||
|
||||
dst_offset *= block_align;
|
||||
src_offset *= block_align;
|
||||
|
||||
if((dst[0] < src[0] ? src[0] - dst[0] : dst[0] - src[0]) >= data_size) {
|
||||
for (i = 0; i < planes; i++)
|
||||
memcpy(dst[i] + dst_offset, src[i] + src_offset, data_size);
|
||||
} else {
|
||||
for (i = 0; i < planes; i++)
|
||||
memmove(dst[i] + dst_offset, src[i] + src_offset, data_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif //AV_VERSION_INT(51, 73, 101)
|
||||
|
||||
#if QTAV_USE_LIBAV(LIBAVCODEC)
|
||||
const char *avcodec_get_name(enum AVCodecID id)
|
||||
{
|
||||
const AVCodecDescriptor *cd;
|
||||
AVCodec *codec;
|
||||
|
||||
if (id == AV_CODEC_ID_NONE)
|
||||
return "none";
|
||||
cd = avcodec_descriptor_get(id);
|
||||
if (cd)
|
||||
return cd->name;
|
||||
av_log(NULL, AV_LOG_WARNING, "Codec 0x%x is not in the full list.\n", id);
|
||||
codec = avcodec_find_decoder(id);
|
||||
if (codec)
|
||||
return codec->name;
|
||||
codec = avcodec_find_encoder(id);
|
||||
if (codec)
|
||||
return codec->name;
|
||||
return "unknown_codec";
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !AV_MODULE_CHECK(LIBAVCODEC, 55, 55, 0, 68, 100)
|
||||
void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
|
||||
{
|
||||
if (pkt->pts != (int64_t)AV_NOPTS_VALUE)
|
||||
pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb);
|
||||
if (pkt->dts != (int64_t)AV_NOPTS_VALUE)
|
||||
pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb);
|
||||
if (pkt->duration > 0)
|
||||
pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb);
|
||||
if (pkt->convergence_duration > 0)
|
||||
pkt->convergence_duration = av_rescale_q(pkt->convergence_duration, src_tb, dst_tb);
|
||||
}
|
||||
#endif
|
||||
// since libav-11, ffmpeg-2.1
|
||||
#if !LIBAV_MODULE_CHECK(LIBAVCODEC, 56, 1, 0) && !FFMPEG_MODULE_CHECK(LIBAVCODEC, 55, 39, 100)
|
||||
int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
|
||||
{
|
||||
dst->pts = src->pts;
|
||||
dst->dts = src->dts;
|
||||
dst->pos = src->pos;
|
||||
dst->duration = src->duration;
|
||||
dst->convergence_duration = src->convergence_duration;
|
||||
dst->flags = src->flags;
|
||||
dst->stream_index = src->stream_index;
|
||||
|
||||
for (int i = 0; i < src->side_data_elems; i++) {
|
||||
enum AVPacketSideDataType type = src->side_data[i].type;
|
||||
int size = src->side_data[i].size;
|
||||
uint8_t *src_data = src->side_data[i].data;
|
||||
uint8_t *dst_data = av_packet_new_side_data(dst, type, size);
|
||||
|
||||
if (!dst_data) {
|
||||
av_packet_free_side_data(dst);
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
memcpy(dst_data, src_data, size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
// since libav-10, ffmpeg-2.1
|
||||
#if !LIBAV_MODULE_CHECK(LIBAVCODEC, 55, 34, 1) && !FFMPEG_MODULE_CHECK(LIBAVCODEC, 55, 39, 100)
|
||||
void av_packet_free_side_data(AVPacket *pkt)
|
||||
{
|
||||
for (int i = 0; i < pkt->side_data_elems; ++i)
|
||||
av_freep(&pkt->side_data[i].data);
|
||||
av_freep(&pkt->side_data);
|
||||
pkt->side_data_elems = 0;
|
||||
}
|
||||
#endif
|
||||
#if !AV_MODULE_CHECK(LIBAVCODEC, 55, 34, 1, 39, 101)
|
||||
int av_packet_ref(AVPacket *dst, const AVPacket *src)
|
||||
{
|
||||
#if QTAV_USE_FFMPEG(LIBAVCODEC)
|
||||
return av_copy_packet(dst, const_cast<AVPacket*>(src)); // not const in these versions
|
||||
#else // libav <=11 has no av_copy_packet
|
||||
#define DUP_DATA(dst, src, size, padding) \
|
||||
do { \
|
||||
void *data; \
|
||||
if (padding) { \
|
||||
if ((unsigned)(size) > \
|
||||
(unsigned)(size) + FF_INPUT_BUFFER_PADDING_SIZE) \
|
||||
goto failed_alloc; \
|
||||
data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); \
|
||||
} else { \
|
||||
data = av_malloc(size); \
|
||||
} \
|
||||
if (!data) \
|
||||
goto failed_alloc; \
|
||||
memcpy(data, src, size); \
|
||||
if (padding) \
|
||||
memset((uint8_t*)data + size, 0, \
|
||||
FF_INPUT_BUFFER_PADDING_SIZE); \
|
||||
*((void**)&dst) = data; \
|
||||
} while (0)
|
||||
|
||||
*dst = *src;
|
||||
dst->data = NULL;
|
||||
dst->side_data = NULL;
|
||||
DUP_DATA(dst->data, src->data, dst->size, 1);
|
||||
dst->destruct = av_destruct_packet;
|
||||
if (dst->side_data_elems) {
|
||||
int i;
|
||||
DUP_DATA(dst->side_data, src->side_data,
|
||||
dst->side_data_elems * sizeof(*dst->side_data), 0);
|
||||
memset(dst->side_data, 0,
|
||||
dst->side_data_elems * sizeof(*dst->side_data));
|
||||
for (i = 0; i < dst->side_data_elems; i++) {
|
||||
DUP_DATA(dst->side_data[i].data, src->side_data[i].data, src->side_data[i].size, 1);
|
||||
dst->side_data[i].size = src->side_data[i].size;
|
||||
dst->side_data[i].type = src->side_data[i].type;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
failed_alloc:
|
||||
av_destruct_packet(dst);
|
||||
return AVERROR(ENOMEM);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if !AV_MODULE_CHECK(LIBAVCODEC, 55, 52, 0, 63, 100)
|
||||
void avcodec_free_context(AVCodecContext **pavctx)
|
||||
{
|
||||
|
||||
AVCodecContext *avctx = *pavctx;
|
||||
if (!avctx)
|
||||
return;
|
||||
avcodec_close(avctx);
|
||||
av_freep(&avctx->extradata);
|
||||
av_freep(&avctx->subtitle_header);
|
||||
av_freep(&avctx->intra_matrix);
|
||||
av_freep(&avctx->inter_matrix);
|
||||
av_freep(&avctx->rc_override);
|
||||
av_freep(pavctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *get_codec_long_name(enum AVCodecID id)
|
||||
{
|
||||
if (id == AV_CODEC_ID_NONE)
|
||||
return "none";
|
||||
const AVCodecDescriptor *cd = avcodec_descriptor_get(id);
|
||||
if (cd)
|
||||
return cd->long_name;
|
||||
av_log(NULL, AV_LOG_WARNING, "Codec 0x%x is not in the full list.\n", id);
|
||||
AVCodec *codec = avcodec_find_decoder(id);
|
||||
if (codec)
|
||||
return codec->long_name;
|
||||
codec = avcodec_find_encoder(id);
|
||||
if (codec)
|
||||
return codec->long_name;
|
||||
return "unknown_codec";
|
||||
}
|
||||
|
||||
#if QTAV_HAVE(AVFILTER)
|
||||
#if !AV_MODULE_CHECK(LIBAVFILTER, 2, 22, 0, 79, 100) //FF_API_AVFILTERPAD_PUBLIC
|
||||
const char *avfilter_pad_get_name(const AVFilterPad *pads, int pad_idx)
|
||||
{
|
||||
return pads[pad_idx].name;
|
||||
}
|
||||
|
||||
enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx)
|
||||
{
|
||||
return pads[pad_idx].type;
|
||||
}
|
||||
#endif
|
||||
#endif //QTAV_HAVE(AVFILTER)
|
||||
460
project/fm_viewer/fav/AVCompat.h
Normal file
460
project/fm_viewer/fav/AVCompat.h
Normal file
@@ -0,0 +1,460 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
solve the version problem and diffirent api in FFmpeg and libav
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#ifndef QTAV_COMPAT_H
|
||||
#define QTAV_COMPAT_H
|
||||
|
||||
/*!
|
||||
NOTE: include this at last
|
||||
*/
|
||||
#define QTAV_USE_FFMPEG(MODULE) (MODULE##_VERSION_MICRO >= 100)
|
||||
#define QTAV_USE_LIBAV(MODULE) !QTAV_USE_FFMPEG(MODULE)
|
||||
#define FFMPEG_MODULE_CHECK(MODULE, MAJOR, MINOR, MICRO) \
|
||||
(QTAV_USE_FFMPEG(MODULE) && MODULE##_VERSION_INT >= AV_VERSION_INT(MAJOR, MINOR, MICRO))
|
||||
#define LIBAV_MODULE_CHECK(MODULE, MAJOR, MINOR, MICRO) \
|
||||
(QTAV_USE_LIBAV(MODULE) && MODULE##_VERSION_INT >= AV_VERSION_INT(MAJOR, MINOR, MICRO))
|
||||
#define AV_MODULE_CHECK(MODULE, MAJOR, MINOR, MICRO, MINOR2, MICRO2) \
|
||||
(LIBAV_MODULE_CHECK(MODULE, MAJOR, MINOR, MICRO) || FFMPEG_MODULE_CHECK(MODULE, MAJOR, MINOR2, MICRO2))
|
||||
/// example: AV_ENSURE(avcodec_close(avctx), false) will print error and return false if failed. AV_WARN just prints error.
|
||||
#define AV_ENSURE_OK(FUNC, ...) AV_RUN_CHECK(FUNC, return, __VA_ARGS__)
|
||||
#define AV_ENSURE(FUNC, ...) AV_RUN_CHECK(FUNC, return, __VA_ARGS__)
|
||||
#define AV_WARN(FUNC) AV_RUN_CHECK(FUNC, void)
|
||||
|
||||
#include "_fav_constants.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
/*UINT64_C: C99 math features, need -D__STDC_CONSTANT_MACROS in CXXFLAGS*/
|
||||
#endif /*__cplusplus*/
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavutil/avstring.h>
|
||||
#include <libavutil/dict.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libavutil/log.h>
|
||||
#include <libavutil/mathematics.h> //AV_ROUND_UP, av_rescale_rnd for libav
|
||||
#include <libavutil/cpu.h>
|
||||
#include <libavutil/error.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/parseutils.h>
|
||||
#include <libavutil/pixdesc.h>
|
||||
#include <libavutil/avstring.h>
|
||||
|
||||
#if !FFMPEG_MODULE_CHECK(LIBAVUTIL, 51, 73, 101)
|
||||
#include <libavutil/channel_layout.h>
|
||||
#endif
|
||||
|
||||
/* TODO: how to check whether we have swresample or not? how to check avresample?*/
|
||||
#include <libavutil/samplefmt.h>
|
||||
#if QTAV_HAVE(SWRESAMPLE)
|
||||
#include <libswresample/swresample.h>
|
||||
#ifndef LIBSWRESAMPLE_VERSION_INT //ffmpeg 0.9, swr 0.5
|
||||
#define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, LIBSWRESAMPLE_VERSION_MINOR, LIBSWRESAMPLE_VERSION_MICRO)
|
||||
#endif //LIBSWRESAMPLE_VERSION_INT
|
||||
//ffmpeg >= 0.11.x. swr0.6.100: ffmpeg-0.10.x
|
||||
#define HAVE_SWR_GET_DELAY (LIBSWRESAMPLE_VERSION_INT > AV_VERSION_INT(0, 6, 100))
|
||||
#endif //QTAV_HAVE(SWRESAMPLE)
|
||||
#if QTAV_HAVE(AVRESAMPLE)
|
||||
#include <libavresample/avresample.h>
|
||||
#endif //QTAV_HAVE(AVRESAMPLE)
|
||||
|
||||
#if QTAV_HAVE(AVFILTER)
|
||||
#if !(USE_FFMPEG4)
|
||||
#include <libavfilter/avfiltergraph.h> //code is here for old version
|
||||
#endif // USE_FFMPEG4
|
||||
#include <libavfilter/avfilter.h>
|
||||
#include <libavfilter/buffersink.h>
|
||||
#include <libavfilter/buffersrc.h>
|
||||
#endif //QTAV_HAVE(AVFILTER)
|
||||
|
||||
#if QTAV_HAVE(AVDEVICE)
|
||||
#include <libavdevice/avdevice.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
/*!
|
||||
* Guide to uniform the api for different FFmpeg version(or other libraries)
|
||||
* We use the existing old api to simulater .
|
||||
* 1. The old version does not have this api: Just add it.
|
||||
* 2. The old version has similar api: Try using macro.
|
||||
* e.g. the old is bool my_play(char* data, size_t size)
|
||||
* the new is bool my_play2(const ByteArray& data)
|
||||
* change:
|
||||
* #define my_play2(data) my_play(data.data(), data.size());
|
||||
*
|
||||
* 3. The old version api is conflicted with the latest's. We can redefine the api
|
||||
* e.g. the old is bool my_play(char* data, size_t size)
|
||||
* the new is bool my_play(const ByteArray& data)
|
||||
* change:
|
||||
* typedef bool (*my_play_t)(const ByteArray&);
|
||||
* static my_play_t my_play_ptr = my_play; //using the existing my_play(char*, size_t)
|
||||
* #define my_play my_play_compat
|
||||
* inline bool my_play_compat(const ByteArray& data)
|
||||
* {
|
||||
* return my_play_ptr(data.data(), data.size());
|
||||
* }
|
||||
* 4. conflict macros
|
||||
* see av_err2str
|
||||
*/
|
||||
|
||||
#ifndef AV_VERSION_INT
|
||||
#define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c)
|
||||
#endif /*AV_VERSION_INT*/
|
||||
|
||||
void ffmpeg_version_print();
|
||||
|
||||
#if !FFMPEG_MODULE_CHECK(LIBAVFORMAT, 56, 4, 101)
|
||||
int avio_feof(AVIOContext *s);
|
||||
#endif
|
||||
#if QTAV_USE_LIBAV(LIBAVFORMAT)
|
||||
int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *oformat, const char *format, const char *filename);
|
||||
#endif
|
||||
//TODO: always inline
|
||||
/* --gnu option of the RVCT compiler also defines __GNUC__ */
|
||||
#if defined(__GNUC__) && !(defined(__ARMCC__) || defined(__CC_ARM))
|
||||
#define GCC_VERSION_AT_LEAST(major, minor, patch) \
|
||||
(__GNUC__ > major || (__GNUC__ == major && (__GNUC_MINOR__ > minor \
|
||||
|| (__GNUC_MINOR__ == minor && __GNUC_PATCHLEVEL__ >= patch))))
|
||||
#else
|
||||
/* Define this for !GCC compilers, just so we can write things like GCC_VERSION_AT_LEAST(4, 1, 0). */
|
||||
#define GCC_VERSION_AT_LEAST(major, minor, patch) 0
|
||||
#endif
|
||||
|
||||
//FFmpeg2.0, Libav10 2013-03-08 - Reference counted buffers - lavu 52.19.100/52.8.0, lavc 55.0.100 / 55.0.0, lavf 55.0.100 / 55.0.0, lavd 54.4.100 / 54.0.0, lavfi 3.5.0
|
||||
#define QTAV_HAVE_AVBUFREF AV_MODULE_CHECK(LIBAVUTIL, 52, 8, 0, 19, 100)
|
||||
|
||||
#if defined(_MSC_VER) || !defined(av_err2str) || (GCC_VERSION_AT_LEAST(4, 7, 0) && __cplusplus)
|
||||
#ifdef av_err2str
|
||||
#undef av_err2str
|
||||
/*#define av_make_error_string qtav_make_error_string*/
|
||||
#else
|
||||
/**
|
||||
* Fill the provided buffer with a string containing an error string
|
||||
* corresponding to the AVERROR code errnum.
|
||||
*
|
||||
* @param errbuf a buffer
|
||||
* @param errbuf_size size in bytes of errbuf
|
||||
* @param errnum error code to describe
|
||||
* @return the buffer in input, filled with the error description
|
||||
* @see av_strerror()
|
||||
*/
|
||||
static av_always_inline char *av_make_error_string(char *errbuf, size_t errbuf_size, int errnum)
|
||||
{
|
||||
av_strerror(errnum, errbuf, errbuf_size);
|
||||
return errbuf;
|
||||
}
|
||||
#endif /*av_err2str*/
|
||||
|
||||
#define AV_ERROR_MAX_STRING_SIZE 64
|
||||
#ifdef QT_CORE_LIB
|
||||
#include <QtCore/QSharedPointer>
|
||||
#define av_err2str(e) av_err2str_qsp(e).data()
|
||||
av_always_inline QSharedPointer<char> av_err2str_qsp(int errnum)
|
||||
{
|
||||
QSharedPointer<char> str((char*)calloc(AV_ERROR_MAX_STRING_SIZE, 1), ::free);
|
||||
av_strerror(errnum, str.data(), AV_ERROR_MAX_STRING_SIZE);
|
||||
return str;
|
||||
}
|
||||
#else
|
||||
av_always_inline char* av_err2str(int errnum)
|
||||
{
|
||||
static char str[AV_ERROR_MAX_STRING_SIZE];
|
||||
memset(str, 0, sizeof(str));
|
||||
return av_make_error_string(str, AV_ERROR_MAX_STRING_SIZE, errnum);
|
||||
}
|
||||
#endif /* QT_CORE_LIB */
|
||||
#endif /*!defined(av_err2str) || GCC_VERSION_AT_LEAST(4, 7, 2)*/
|
||||
|
||||
#if (LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(52,23,0))
|
||||
#define avcodec_decode_audio3(avctx, samples, frame_size_ptr, avpkt) \
|
||||
avcodec_decode_audio2(avctx, samples, frame_size_ptr, (*avpkt).data, (*avpkt).size);
|
||||
|
||||
#endif /*AV_VERSION_INT(52,23,0)*/
|
||||
|
||||
#if (LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(52,101,0))
|
||||
#define av_dump_format(...) dump_format(__VA_ARGS__)
|
||||
#endif /*AV_VERSION_INT(52,101,0)*/
|
||||
|
||||
#if QTAV_HAVE(SWRESAMPLE) && (LIBSWRESAMPLE_VERSION_INT <= AV_VERSION_INT(0, 5, 0))
|
||||
#define swresample_version() LIBSWRESAMPLE_VERSION_INT //we can not know the runtime version, so just use build time version
|
||||
#define swresample_configuration() "Not available."
|
||||
#define swresample_license() "Not available."
|
||||
#endif
|
||||
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 32, 0)
|
||||
int64_t av_get_default_channel_layout(int nb_channels);
|
||||
#endif
|
||||
/*
|
||||
* mapping avresample to swresample
|
||||
* https://github.com/xbmc/xbmc/commit/274679d
|
||||
*/
|
||||
#if (QTAV_HAVE(SWR_AVR_MAP) || !QTAV_HAVE(SWRESAMPLE)) && QTAV_HAVE(AVRESAMPLE)
|
||||
#ifndef SWR_CH_MAX
|
||||
#ifdef AVRESAMPLE_MAX_CHANNELS
|
||||
#define SWR_CH_MAX AVRESAMPLE_MAX_CHANNELS
|
||||
#else
|
||||
#define SWR_CH_MAX 64
|
||||
#endif //AVRESAMPLE_MAX_CHANNELS
|
||||
#endif //SWR_CH_MAX
|
||||
#define SwrContext AVAudioResampleContext
|
||||
#define swr_init(ctx) avresample_open(ctx)
|
||||
//free context and set pointer to null. see swresample
|
||||
#define swr_free(ctx) \
|
||||
if (ctx && *ctx) { \
|
||||
avresample_close(*ctx); \
|
||||
*ctx = 0; \
|
||||
}
|
||||
#define swr_get_class() avresample_get_class()
|
||||
#define swr_alloc() avresample_alloc_context()
|
||||
//#define swr_next_pts()
|
||||
#define swr_set_compensation() avresample_set_compensation()
|
||||
#define swr_set_channel_mapping(ctx, map) avresample_set_channel_mapping(ctx, map)
|
||||
#define swr_set_matrix(ctx, matrix, stride) avresample_set_matrix(ctx, matrix, stride)
|
||||
//#define swr_drop_output(ctx, count)
|
||||
//#define swr_inject_silence(ctx, count)
|
||||
#define swr_get_delay(ctx, ...) avresample_get_delay(ctx)
|
||||
#if LIBAVRESAMPLE_VERSION_INT >= AV_VERSION_INT(1, 0, 0) //ffmpeg >= 1.1
|
||||
#define swr_convert(ctx, out, out_count, in, in_count) \
|
||||
avresample_convert(ctx, out, 0, out_count, const_cast<uint8_t**>(in), 0, in_count)
|
||||
#else
|
||||
#define swr_convert(ctx, out, out_count, in, in_count) \
|
||||
avresample_convert(ctx, (void**)out, 0, out_count, (void**)in, 0, in_count)
|
||||
#define HAVE_SWR_GET_DELAY 1
|
||||
#define swr_get_delay(ctx, ...) avresample_get_delay(ctx)
|
||||
#endif
|
||||
struct SwrContext *swr_alloc_set_opts(struct SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, int log_offset, void *log_ctx);
|
||||
#define swresample_version() avresample_version()
|
||||
#define swresample_configuration() avresample_configuration()
|
||||
#define swresample_license() avresample_license()
|
||||
#endif //MAP_SWR_AVR
|
||||
|
||||
|
||||
/* For FFmpeg < 2.0
|
||||
* FF_API_PIX_FMT macro?
|
||||
* 51.42.0: PIX_FMT_* -> AV_PIX_FMT_*, PixelFormat -> AVPixelFormat
|
||||
* so I introduce QTAV_PIX_FMT_C(X) for internal use
|
||||
* FFmpeg n1.1 AVPixelFormat
|
||||
*/
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 13, 100) //(51, 42, 0)
|
||||
typedef enum PixelFormat AVPixelFormat; // so we must avoid using enum AVPixelFormat
|
||||
#define QTAV_PIX_FMT_C(X) PIX_FMT_##X
|
||||
#else //FFmpeg >= 2.0
|
||||
typedef enum AVPixelFormat AVPixelFormat;
|
||||
#define QTAV_PIX_FMT_C(X) AV_PIX_FMT_##X
|
||||
#endif //AV_VERSION_INT(51, 42, 0)
|
||||
// FF_API_PIX_FMT
|
||||
#ifdef PixelFormat
|
||||
#undef PixelFormat
|
||||
#endif
|
||||
|
||||
// AV_PIX_FMT_FLAG_XXX was PIX_FMT_XXX before FFmpeg 2.0
|
||||
// AV_PIX_FMT_FLAG_ALPHA was added at 52.2.0. but version.h not changed
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 2, 1) //git cbe5a60c9d495df0fb4775b064f06719b70b9952
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 22, 1) //git 38d553322891c8e47182f05199d19888422167dc
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 19, 0) //git 6b0768e2021b90215a2ab55ed427bce91d148148
|
||||
#define PIX_FMT_PLANAR 16 ///< At least one pixel component is not in the first data plane
|
||||
#define PIX_FMT_RGB 32 ///< The pixel format contains RGB-like data (as opposed to YUV/grayscale)
|
||||
#endif //AV_VERSION_INT(51, 19, 0)
|
||||
#define PIX_FMT_PSEUDOPAL 64 //why not defined in FFmpeg 0.9 lavu51.32.0 but git log says 51.22.1 defined it?
|
||||
#endif //AV_VERSION_INT(51, 22, 1)
|
||||
#define PIX_FMT_ALPHA 128 ///< The pixel format has an alpha channel
|
||||
#endif //AV_VERSION_INT(52, 2, 1)
|
||||
|
||||
#ifndef PIX_FMT_PLANAR
|
||||
#define PIX_FMT_PLANAR 16
|
||||
#endif //PIX_FMT_PLANAR
|
||||
#ifndef PIX_FMT_RGB
|
||||
#define PIX_FMT_RGB 32
|
||||
#endif //PIX_FMT_RGB
|
||||
#ifndef PIX_FMT_PSEUDOPAL
|
||||
#define PIX_FMT_PSEUDOPAL 64
|
||||
#endif //PIX_FMT_PSEUDOPAL
|
||||
#ifndef PIX_FMT_ALPHA
|
||||
#define PIX_FMT_ALPHA 128
|
||||
#endif //PIX_FMT_ALPHA
|
||||
|
||||
/*
|
||||
* rename PIX_FMT_* flags to AV_PIX_FMT_FLAG_*. git e6c4ac7b5f038be56dfbb0171f5dd0cb850d9b28
|
||||
*/
|
||||
//#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 11, 0)
|
||||
#ifndef AV_PIX_FMT_FLAG_BE
|
||||
#define AV_PIX_FMT_FLAG_BE PIX_FMT_BE
|
||||
#define AV_PIX_FMT_FLAG_PAL PIX_FMT_PAL
|
||||
#define AV_PIX_FMT_FLAG_BITSTREAM PIX_FMT_BITSTREAM
|
||||
#define AV_PIX_FMT_FLAG_HWACCEL PIX_FMT_HWACCEL
|
||||
|
||||
// FFmpeg >= 0.9, libav >= 0.8.8(51,22,1)
|
||||
#define AV_PIX_FMT_FLAG_PLANAR PIX_FMT_PLANAR
|
||||
#define AV_PIX_FMT_FLAG_RGB PIX_FMT_RGB
|
||||
|
||||
// FFmpeg >= 1.0, libav >= 9.7
|
||||
#define AV_PIX_FMT_FLAG_PSEUDOPAL PIX_FMT_PSEUDOPAL
|
||||
// FFmpeg >= 1.1, libav >= 9.7
|
||||
#define AV_PIX_FMT_FLAG_ALPHA PIX_FMT_ALPHA
|
||||
#endif //AV_PIX_FMT_FLAG_BE
|
||||
//#endif //AV_VERSION_INT(52, 11, 0)
|
||||
// FFmpeg >= 1.1, but use internal av_pix_fmt_descriptors. FFmpeg < 1.1 has extern av_pix_fmt_descriptors
|
||||
// used by av_pix_fmt_count_planes
|
||||
#if !AV_MODULE_CHECK(LIBAVUTIL, 52, 3, 0, 13, 100)
|
||||
const AVPixFmtDescriptor *av_pix_fmt_desc_get(AVPixelFormat pix_fmt);
|
||||
const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev);
|
||||
AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc);
|
||||
#endif // !AV_MODULE_CHECK(LIBAVUTIL, 52, 3, 0, 13, 100)
|
||||
#if !FFMPEG_MODULE_CHECK(LIBAVUTIL, 52, 48, 101) // since ffmpeg2.1, libavutil53.16.0 (FF_API_AVFRAME_COLORSPACE), git 8c02adc
|
||||
enum AVColorSpace av_frame_get_colorspace(const AVFrame *frame);
|
||||
enum AVColorRange av_frame_get_color_range(const AVFrame *frame);
|
||||
#endif
|
||||
/*
|
||||
* lavu 52.9.0 git 2c328a907978b61949fd20f7c991803174337855
|
||||
* FFmpeg >= 2.0.
|
||||
*/
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 38, 100)
|
||||
int av_pix_fmt_count_planes(AVPixelFormat pix_fmt);
|
||||
#endif //AV_VERSION_INT(52, 38, 100)
|
||||
|
||||
// FFmpeg < 1.0 has no av_samples_copy
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 73, 101)
|
||||
/**
|
||||
* Copy samples from src to dst.
|
||||
*
|
||||
* @param dst destination array of pointers to data planes
|
||||
* @param src source array of pointers to data planes
|
||||
* @param dst_offset offset in samples at which the data will be written to dst
|
||||
* @param src_offset offset in samples at which the data will be read from src
|
||||
* @param nb_samples number of samples to be copied
|
||||
* @param nb_channels number of audio channels
|
||||
* @param sample_fmt audio sample format
|
||||
*/
|
||||
int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset,
|
||||
int src_offset, int nb_samples, int nb_channels,
|
||||
enum AVSampleFormat sample_fmt);
|
||||
#endif //AV_VERSION_INT(51, 73, 101)
|
||||
|
||||
// < ffmpeg 1.0
|
||||
//#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 59, 100)
|
||||
#if AV_MODULE_CHECK(LIBAVCODEC, 54, 25, 0, 51, 100)
|
||||
#define QTAV_CODEC_ID(X) AV_CODEC_ID_##X
|
||||
#else
|
||||
typedef enum CodecID AVCodecID;
|
||||
#define QTAV_CODEC_ID(X) CODEC_ID_##X
|
||||
#endif
|
||||
|
||||
/* av_frame_alloc
|
||||
* since FFmpeg2.0: 2.0.4 avcodec-55.18.102, avutil-52.38.100 (1.2.7 avcodec-54.92.100,avutil-52.18.100)
|
||||
* since libav10.0: 10.2 avcodec55.34.1, avutil-53.3.0
|
||||
* the same as avcodec_alloc_frame() (deprecated since 2.2). AVFrame was in avcodec.h, now in avutil/frame.h
|
||||
*/
|
||||
#if !AV_MODULE_CHECK(LIBAVCODEC, 55, 34, 0, 18, 100)
|
||||
#define av_frame_alloc() avcodec_alloc_frame()
|
||||
#if QTAV_USE_LIBAV(LIBAVCODEC) || FFMPEG_MODULE_CHECK(LIBAVCODEC, 54, 59, 100)
|
||||
#define av_frame_free(f) avcodec_free_frame(f)
|
||||
#else
|
||||
#define av_frame_free(f) av_free(f)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if QTAV_USE_LIBAV(LIBAVCODEC)
|
||||
const char *avcodec_get_name(enum AVCodecID id);
|
||||
#endif
|
||||
#if !AV_MODULE_CHECK(LIBAVCODEC, 55, 55, 0, 68, 100)
|
||||
void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb);
|
||||
#endif
|
||||
// since libav-11, ffmpeg-2.1
|
||||
#if !LIBAV_MODULE_CHECK(LIBAVCODEC, 56, 1, 0) && !FFMPEG_MODULE_CHECK(LIBAVCODEC, 55, 39, 100)
|
||||
int av_packet_copy_props(AVPacket *dst, const AVPacket *src);
|
||||
#endif
|
||||
// since libav-10, ffmpeg-2.1
|
||||
#if !LIBAV_MODULE_CHECK(LIBAVCODEC, 55, 34, 1) && !FFMPEG_MODULE_CHECK(LIBAVCODEC, 55, 39, 100)
|
||||
void av_packet_free_side_data(AVPacket *pkt);
|
||||
#endif
|
||||
//ffmpeg2.1 libav10
|
||||
#if !AV_MODULE_CHECK(LIBAVCODEC, 55, 34, 1, 39, 101)
|
||||
int av_packet_ref(AVPacket *dst, const AVPacket *src);
|
||||
#define av_packet_unref(pkt) av_free_packet(pkt)
|
||||
#endif
|
||||
|
||||
#if !AV_MODULE_CHECK(LIBAVCODEC, 55, 52, 0, 63, 100)
|
||||
void avcodec_free_context(AVCodecContext **pavctx);
|
||||
#endif
|
||||
|
||||
#if QTAV_HAVE(AVFILTER)
|
||||
// ffmpeg2.0 2013-07-03 - 838bd73 - lavfi 3.78.100 - avfilter.h
|
||||
#if QTAV_USE_LIBAV(LIBAVFILTER)
|
||||
#define avfilter_graph_parse_ptr(pGraph, pFilters, ppInputs, ppOutputs, pLog) avfilter_graph_parse(pGraph, pFilters, *ppInputs, *ppOutputs, pLog)
|
||||
#elif !FFMPEG_MODULE_CHECK(LIBAVFILTER, 3, 78, 100)
|
||||
#define avfilter_graph_parse_ptr(pGraph, pFilters, ppInputs, ppOutputs, pLog) avfilter_graph_parse(pGraph, pFilters, ppInputs, ppOutputs, pLog)
|
||||
#endif //QTAV_USE_LIBAV(LIBAVFILTER)
|
||||
|
||||
//ffmpeg1.0 2012-06-12 - c7b9eab / 84b9fbe - lavfi 2.79.100 / 2.22.0 - avfilter.h
|
||||
#if !AV_MODULE_CHECK(LIBAVFILTER, 2, 22, 0, 79, 100) //FF_API_AVFILTERPAD_PUBLIC
|
||||
const char *avfilter_pad_get_name(const AVFilterPad *pads, int pad_idx);
|
||||
enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx);
|
||||
#endif
|
||||
///ffmpeg1.0 lavfi 2.74.100 / 2.17.0. was in ffmpeg <libavfilter/avcodec.h> in old ffmpeg and now are in avfilter.h and deprecated. declare here to avoid version check
|
||||
#if QTAV_USE_FFMPEG(LIBAVFILTER)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
struct AVFilterBufferRef;
|
||||
int avfilter_copy_buf_props(AVFrame *dst, const AVFilterBufferRef *src);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
#endif //QTAV_HAVE(AVFILTER)
|
||||
|
||||
/* helper functions */
|
||||
const char *get_codec_long_name(AVCodecID id);
|
||||
|
||||
// AV_CODEC_ID_H265 is a macro defined as AV_CODEC_ID_HEVC in ffmpeg but not in libav. so we can use FF_PROFILE_HEVC_MAIN to avoid libavcodec version check. (from ffmpeg 2.1)
|
||||
#ifndef FF_PROFILE_HEVC_MAIN //libav does not define it
|
||||
#define AV_CODEC_ID_HEVC ((AVCodecID)0) //QTAV_CODEC_ID(NONE)
|
||||
#define CODEC_ID_HEVC ((AVCodecID)0) //QTAV_CODEC_ID(NONE)
|
||||
#define FF_PROFILE_HEVC_MAIN -1
|
||||
#define FF_PROFILE_HEVC_MAIN_10 -1
|
||||
#endif
|
||||
#if !FFMPEG_MODULE_CHECK(LIBAVCODEC, 54, 92, 100) && !LIBAV_MODULE_CHECK(LIBAVCODEC, 55, 34, 1) //ffmpeg1.2 libav10
|
||||
#define AV_CODEC_ID_VP9 ((AVCodecID)0) //QTAV_CODEC_ID(NONE)
|
||||
#define CODEC_ID_VP9 ((AVCodecID)0) //QTAV_CODEC_ID(NONE)
|
||||
#endif
|
||||
#ifndef FF_PROFILE_VP9_0
|
||||
#define FF_PROFILE_VP9_0 0
|
||||
#define FF_PROFILE_VP9_1 1
|
||||
#define FF_PROFILE_VP9_2 2
|
||||
#define FF_PROFILE_VP9_3 3
|
||||
#endif
|
||||
|
||||
#define AV_RUN_CHECK(FUNC, RETURN, ...) do { \
|
||||
int ret = FUNC; \
|
||||
if (ret < 0) { \
|
||||
char str[AV_ERROR_MAX_STRING_SIZE]; \
|
||||
memset(str, 0, sizeof(str)); \
|
||||
av_strerror(ret, str, sizeof(str)); \
|
||||
av_log(NULL, AV_LOG_WARNING, "Error " #FUNC " @%d " __FILE__ ": (%#x) %s\n", __LINE__, ret, str); \
|
||||
RETURN __VA_ARGS__; \
|
||||
} } while(0)
|
||||
|
||||
#endif //QTAV_COMPAT_H
|
||||
287
project/fm_viewer/fav/AVDecoder.cpp
Normal file
287
project/fm_viewer/fav/AVDecoder.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
|
||||
#include "AVDecoder.h"
|
||||
#include "AVDecoder_p.h"
|
||||
#include "version.h"
|
||||
#include "internal.h"
|
||||
#include "Logger.h"
|
||||
|
||||
namespace FAV {
|
||||
|
||||
static AVCodec* get_codec(const QString &name, const QString& hwa, AVCodecID cid)
|
||||
{
|
||||
QString fullname(name);
|
||||
if (name.isEmpty()) {
|
||||
if (hwa.isEmpty())
|
||||
return avcodec_find_decoder(cid);
|
||||
fullname = QString("%1_%2").arg(avcodec_get_name(cid)).arg(hwa);
|
||||
}
|
||||
AVCodec *codec = avcodec_find_decoder_by_name(fullname.toUtf8().constData());
|
||||
if (codec)
|
||||
return codec;
|
||||
const AVCodecDescriptor* cd = avcodec_descriptor_get_by_name(fullname.toUtf8().constData());
|
||||
if (cd)
|
||||
return avcodec_find_decoder(cd->id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AVDecoder::AVDecoder(AVDecoderPrivate &d)
|
||||
:DPTR_INIT(&d)
|
||||
{
|
||||
avcodec_register_all(); // avcodec_find_decoder will always be used
|
||||
}
|
||||
|
||||
AVDecoder::~AVDecoder()
|
||||
{
|
||||
setCodecContext(0); // FIXME: will call virtual
|
||||
}
|
||||
|
||||
QString AVDecoder::name() const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString AVDecoder::description() const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool AVDecoder::open()
|
||||
{
|
||||
DPTR_D(AVDecoder);
|
||||
// codec_ctx can't be null for none-ffmpeg based decoders because we may use it's properties in those decoders
|
||||
if (!d.codec_ctx) {
|
||||
qWarning("FFmpeg codec context not ready");
|
||||
return false;
|
||||
}
|
||||
const QString hwa = property("hwaccel").toString();
|
||||
AVCodec* codec = get_codec(codecName(), hwa, d.codec_ctx->codec_id);
|
||||
if (!codec) { // TODO: can be null for none-ffmpeg based decoders
|
||||
QString es("No codec could be found for '%1'");
|
||||
if (d.codec_name.isEmpty()) {
|
||||
es = es.arg(QLatin1String(avcodec_get_name(d.codec_ctx->codec_id)));
|
||||
if (!hwa.isEmpty())
|
||||
es.append('_').append(hwa);
|
||||
} else {
|
||||
es = es.arg(d.codec_name);
|
||||
}
|
||||
qWarning() << es;
|
||||
AVError::ErrorCode ec(AVError::CodecError);
|
||||
switch (d.codec_ctx->codec_type) {
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
ec = AVError::VideoCodecNotFound;
|
||||
break;
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
ec = AVError::AudioCodecNotFound;
|
||||
break;
|
||||
case AVMEDIA_TYPE_SUBTITLE:
|
||||
ec = AVError::SubtitleCodecNotFound;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Q_EMIT error(AVError(ec, es));
|
||||
return false;
|
||||
}
|
||||
// hwa extra init can be here
|
||||
if (!d.open()) {
|
||||
d.close();
|
||||
return false;
|
||||
}
|
||||
// CODEC_FLAG_OUTPUT_CORRUPT, CODEC_FLAG2_SHOW_ALL?
|
||||
// TODO: skip for none-ffmpeg based decoders
|
||||
d.applyOptionsForDict();
|
||||
|
||||
av_opt_set_int(d.codec_ctx, "refcounted_frames", d.enableFrameRef(), 0); // why dict may have no effect?
|
||||
|
||||
d.codec_ctx->thread_count = 1;
|
||||
d.codec_ctx->flags |= AV_CODEC_FLAG_LOW_DELAY;
|
||||
d.codec_ctx->flags2 |= AV_CODEC_FLAG2_CHUNKS;
|
||||
|
||||
// TODO: only open for ff decoders
|
||||
//av_dict_set(&d.dict, "lowres", "1", 0);
|
||||
// dict is used for a specified AVCodec options (priv_class), av_opt_set_xxx(avctx) is only for avctx
|
||||
AV_ENSURE_OK(avcodec_open2(d.codec_ctx, codec, d.options.isEmpty() ? NULL : &d.dict), false);
|
||||
d.is_open = true;
|
||||
static const char* thread_name[] = { "Single", "Frame", "Slice"};
|
||||
qDebug("%s thread type: %s, count: %d", metaObject()->className(), thread_name[d.codec_ctx->active_thread_type], d.codec_ctx->thread_count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AVDecoder::close()
|
||||
{
|
||||
if (!isOpen()) {
|
||||
return true;
|
||||
}
|
||||
DPTR_D(AVDecoder);
|
||||
d.is_open = false;
|
||||
// hwa extra finalize can be here
|
||||
flush();
|
||||
d.close();
|
||||
// TODO: reset config?
|
||||
if (d.codec_ctx) {
|
||||
AV_ENSURE_OK(avcodec_close(d.codec_ctx), false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AVDecoder::isOpen() const
|
||||
{
|
||||
return d_func().is_open;
|
||||
}
|
||||
|
||||
void AVDecoder::flush()
|
||||
{
|
||||
if (!isAvailable())
|
||||
return;
|
||||
if (!isOpen())
|
||||
return;
|
||||
avcodec_flush_buffers(d_func().codec_ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* do nothing if equal
|
||||
* close the old one. the codec context can not be shared in more than 1 decoder.
|
||||
*/
|
||||
void AVDecoder::setCodecContext(void *codecCtx)
|
||||
{
|
||||
DPTR_D(AVDecoder);
|
||||
AVCodecContext *ctx = (AVCodecContext*)codecCtx;
|
||||
if (ctx == NULL || d.codec_ctx == ctx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (isOpen())
|
||||
{
|
||||
#if !(OFF_OTHER_DEBUG)
|
||||
qWarning("Can not copy codec properties when it's open");
|
||||
#endif
|
||||
close(); //
|
||||
}
|
||||
d.is_open = false;
|
||||
if (!ctx) {
|
||||
avcodec_free_context(&d.codec_ctx);
|
||||
d.codec_ctx = 0;
|
||||
return;
|
||||
}
|
||||
if (!d.codec_ctx)
|
||||
d.codec_ctx = avcodec_alloc_context3(NULL);
|
||||
// avcodec_alloc_context3(codec) equals to avcodec_alloc_context3(NULL) + avcodec_get_context_defaults3(codec), codec specified private data is initialized
|
||||
if (!d.codec_ctx) {
|
||||
qWarning("avcodec_alloc_context3 failed");
|
||||
return;
|
||||
}
|
||||
AV_ENSURE_OK(avcodec_copy_context(d.codec_ctx, ctx));
|
||||
}
|
||||
|
||||
//TODO: reset other parameters?
|
||||
void* AVDecoder::codecContext() const
|
||||
{
|
||||
return d_func().codec_ctx;
|
||||
}
|
||||
|
||||
void AVDecoder::setCodecName(const QString &name)
|
||||
{
|
||||
DPTR_D(AVDecoder);
|
||||
if (d.codec_name == name)
|
||||
return;
|
||||
d.codec_name = name;
|
||||
Q_EMIT codecNameChanged();
|
||||
}
|
||||
|
||||
QString AVDecoder::codecName() const
|
||||
{
|
||||
DPTR_D(const AVDecoder);
|
||||
return d.codec_name;
|
||||
}
|
||||
|
||||
bool AVDecoder::isAvailable() const
|
||||
{
|
||||
return d_func().codec_ctx != 0;
|
||||
}
|
||||
|
||||
int AVDecoder::undecodedSize() const
|
||||
{
|
||||
return d_func().undecoded_size;
|
||||
}
|
||||
|
||||
void AVDecoder::setOptions(const QVariantHash &dict)
|
||||
{
|
||||
DPTR_D(AVDecoder);
|
||||
d.options = dict;
|
||||
// if dict is empty, can not return here, default options will be set for AVCodecContext
|
||||
// apply to AVCodecContext
|
||||
d.applyOptionsForContext();
|
||||
/* set AVDecoder meta properties.
|
||||
* we do not check whether the property exists thus we can set dynamic properties.
|
||||
*/
|
||||
if (dict.isEmpty())
|
||||
return;
|
||||
if (name() == QLatin1String("avcodec"))
|
||||
return;
|
||||
QVariant opt(dict);
|
||||
if (dict.contains(name()))
|
||||
opt = dict.value(name());
|
||||
else if (dict.contains(name().toLower()))
|
||||
opt = dict.value(name().toLower());
|
||||
Internal::setOptionsForQObject(opt, this);
|
||||
}
|
||||
|
||||
QVariantHash AVDecoder::options() const
|
||||
{
|
||||
return d_func().options;
|
||||
}
|
||||
|
||||
void AVDecoderPrivate::applyOptionsForDict()
|
||||
{
|
||||
if (dict) {
|
||||
av_dict_free(&dict);
|
||||
dict = 0; //aready 0 in av_free
|
||||
}
|
||||
// enable ref if possible
|
||||
av_dict_set(&dict, "refcounted_frames", enableFrameRef() ? "1" : "0", 0);
|
||||
if (options.isEmpty())
|
||||
return;
|
||||
// TODO: use QVariantMap only
|
||||
if (!options.contains(QStringLiteral("avcodec")))
|
||||
return;
|
||||
qDebug("set AVCodecContext dict:");
|
||||
// workaround for VideoDecoderFFmpeg. now it does not call av_opt_set_xxx, so set here in dict
|
||||
// TODO: wrong if opt is empty
|
||||
Internal::setOptionsToDict(options.value(QStringLiteral("avcodec")), &dict);
|
||||
}
|
||||
|
||||
void AVDecoderPrivate::applyOptionsForContext()
|
||||
{
|
||||
if (!codec_ctx)
|
||||
return;
|
||||
if (options.isEmpty()) {
|
||||
// av_opt_set_defaults(codec_ctx); //can't set default values! result maybe unexpected
|
||||
return;
|
||||
}
|
||||
|
||||
if (!options.contains(QStringLiteral("avcodec")))
|
||||
return;
|
||||
// workaround for VideoDecoderFFmpeg. now it does not call av_opt_set_xxx, so set here in dict
|
||||
// TODO: wrong if opt is empty
|
||||
Internal::setOptionsToFFmpegObj(options.value(QStringLiteral("avcodec")), codec_ctx);
|
||||
}
|
||||
} //namespace FAV
|
||||
97
project/fm_viewer/fav/AVDecoder.h
Normal file
97
project/fm_viewer/fav/AVDecoder.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef QAV_DECODER_H
|
||||
#define QAV_DECODER_H
|
||||
|
||||
#include "AVError.h"
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
namespace FAV {
|
||||
|
||||
class Packet;
|
||||
class AVDecoderPrivate;
|
||||
class Q_AV_EXPORT AVDecoder : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
DPTR_DECLARE_PRIVATE(AVDecoder)
|
||||
//Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
|
||||
public:
|
||||
virtual ~AVDecoder();
|
||||
virtual QString name() const;
|
||||
virtual QString description() const;
|
||||
/*!
|
||||
* default is open FFmpeg codec context
|
||||
* codec config must be done before open
|
||||
* NOTE: open() and close() are not thread safe. You'd better call them in the same thread.
|
||||
*/
|
||||
virtual bool open();
|
||||
virtual bool close();
|
||||
bool isOpen() const;
|
||||
virtual void flush();
|
||||
void setCodecContext(void* codecCtx); //protected
|
||||
void* codecContext() const;
|
||||
/*not available if AVCodecContext == 0*/
|
||||
bool isAvailable() const;
|
||||
#if (PLAY_SYNC_FIX2)
|
||||
virtual bool send(const Packet* packet) = 0;
|
||||
virtual bool receive() = 0;
|
||||
#endif // PLAY_SYNC_FIX2
|
||||
virtual bool decode(const Packet& packet) = 0;
|
||||
|
||||
|
||||
int undecodedSize() const; //TODO: remove. always decode whole input data completely
|
||||
|
||||
// avcodec_open2
|
||||
/*!
|
||||
* \brief setOptions
|
||||
* 1. If has key "avcodec", it's value (suboption, a hash or map) will be used to set AVCodecContext use av_opt_set and av_dict_set. A value of hash type is ignored.
|
||||
* we can ignore the flags used in av_dict_xxx because we can use hash api.
|
||||
* empty value does nothing to current context if it is open, but will clear AVDictionary in the next open.
|
||||
* AVDictionary is used in avcodec_open2() and will not change unless user call setOptions().
|
||||
* 2. Set QObject properties for AVDecoder. Use AVDecoder::name() or lower case as a key to set properties. If key not found, assume key is "avcodec"
|
||||
* 3. If no ket AVDecoder::name() found in the option, set key-value pairs as QObject property-value pairs.
|
||||
* \param dict
|
||||
* example:
|
||||
* "avcodec": {"vismv":"pf"}, "vaapi":{"display":"DRM"}, "copyMode": "ZeroCopy"
|
||||
* means set avcodec context option vismv=>pf, VA-API display (qt property) to DRM when using VA-API, set copyMode (GPU decoders) property to ZeroCopy
|
||||
*/
|
||||
void setOptions(const QVariantHash &dict);
|
||||
QVariantHash options() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void error(const FAV::AVError& e); //explictly use FAV::AVError in connection for Qt4 syntax
|
||||
void descriptionChanged();
|
||||
protected:
|
||||
AVDecoder(AVDecoderPrivate& d);
|
||||
DPTR_DECLARE(AVDecoder)
|
||||
// force a codec. only used by avcodec sw decoders. TODO: move to public? profile set?
|
||||
void setCodecName(const QString& name);
|
||||
QString codecName() const;
|
||||
virtual void codecNameChanged() {}//signals can not be decared virtual (winrt)
|
||||
private:
|
||||
Q_DISABLE_COPY(AVDecoder)
|
||||
AVDecoder(); // base class, not direct create. only final class has is enough
|
||||
};
|
||||
|
||||
} //namespace FAV
|
||||
#endif // QAV_DECODER_H
|
||||
147
project/fm_viewer/fav/AVDecoder_p.h
Normal file
147
project/fm_viewer/fav/AVDecoder_p.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2015 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef QTAV_AVDECODER_P_H
|
||||
#define QTAV_AVDECODER_P_H
|
||||
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QVector>
|
||||
#include "_fav_constants.h"
|
||||
#include "AVCompat.h"
|
||||
|
||||
namespace FAV {
|
||||
|
||||
// always define the class to avoid macro check when using it
|
||||
class AVFrameBuffers {
|
||||
#if QTAV_HAVE(AVBUFREF)
|
||||
QVector<AVBufferRef*> buf;
|
||||
#endif
|
||||
public:
|
||||
AVFrameBuffers(AVFrame* frame) {
|
||||
Q_UNUSED(frame);
|
||||
#if QTAV_HAVE(AVBUFREF)
|
||||
if (!frame->buf[0]) { //not ref counted. duplicate data?
|
||||
return;
|
||||
}
|
||||
|
||||
buf.reserve(frame->nb_extended_buf + FF_ARRAY_ELEMS(frame->buf));
|
||||
buf.resize(frame->nb_extended_buf + FF_ARRAY_ELEMS(frame->buf));
|
||||
for (int i = 0; i < (int)FF_ARRAY_ELEMS(frame->buf); ++i) {
|
||||
if (!frame->buf[i]) //so not use planes + nb_extended_buf!
|
||||
continue;
|
||||
buf[i] = av_buffer_ref(frame->buf[i]);
|
||||
if (!buf[i]) {
|
||||
qWarning("av_buffer_ref(frame->buf[%d]) error", i);
|
||||
}
|
||||
}
|
||||
if (!frame->extended_buf)
|
||||
return;
|
||||
for (int i = 0; i < frame->nb_extended_buf; ++i) {
|
||||
const int k = buf.size() + i - frame->nb_extended_buf;
|
||||
buf[k] = av_buffer_ref(frame->extended_buf[i]);
|
||||
if (!buf[k]) {
|
||||
qWarning("av_buffer_ref(frame->extended_buf[%d]) error", i);
|
||||
}
|
||||
}
|
||||
#endif //QTAV_HAVE(AVBUFREF)
|
||||
}
|
||||
~AVFrameBuffers() {
|
||||
#if QTAV_HAVE(AVBUFREF)
|
||||
foreach (AVBufferRef* b, buf) {
|
||||
av_buffer_unref(&b);
|
||||
}
|
||||
#endif //QTAV_HAVE(AVBUFREF)
|
||||
}
|
||||
};
|
||||
typedef QSharedPointer<AVFrameBuffers> AVFrameBuffersRef;
|
||||
|
||||
class Q_AV_PRIVATE_EXPORT AVDecoderPrivate : public DPtrPrivate<AVDecoder>
|
||||
{
|
||||
public:
|
||||
static const char* getProfileName(AVCodecID id, int profile) {
|
||||
AVCodec *c = avcodec_find_decoder(id);
|
||||
if (!c)
|
||||
return "Unknow";
|
||||
return av_get_profile_name(c, profile);
|
||||
}
|
||||
static const char* getProfileName(const AVCodecContext* ctx) {
|
||||
if (ctx->codec)
|
||||
return av_get_profile_name(ctx->codec, ctx->profile);
|
||||
return getProfileName(ctx->codec_id, ctx->profile);
|
||||
}
|
||||
|
||||
AVDecoderPrivate():
|
||||
codec_ctx(0)
|
||||
, available(true)
|
||||
, is_open(false)
|
||||
, undecoded_size(0)
|
||||
, dict(0)
|
||||
{
|
||||
codec_ctx = avcodec_alloc_context3(NULL);
|
||||
}
|
||||
virtual ~AVDecoderPrivate() {
|
||||
if (dict) {
|
||||
av_dict_free(&dict);
|
||||
}
|
||||
if (codec_ctx) {
|
||||
avcodec_free_context(&codec_ctx);
|
||||
}
|
||||
}
|
||||
virtual bool open() {return true;}
|
||||
virtual void close() {}
|
||||
virtual bool enableFrameRef() const { return true;}
|
||||
void applyOptionsForDict();
|
||||
void applyOptionsForContext();
|
||||
|
||||
AVCodecContext *codec_ctx; //set once and not change
|
||||
bool available; //TODO: true only when context(and hw ctx) is ready
|
||||
bool is_open;
|
||||
int undecoded_size;
|
||||
QString codec_name;
|
||||
QVariantHash options;
|
||||
AVDictionary *dict;
|
||||
};
|
||||
|
||||
class AudioResampler;
|
||||
class AudioDecoderPrivate : public AVDecoderPrivate
|
||||
{
|
||||
public:
|
||||
AudioDecoderPrivate();
|
||||
virtual ~AudioDecoderPrivate();
|
||||
|
||||
AudioResampler *resampler;
|
||||
QByteArray decoded;
|
||||
};
|
||||
|
||||
class Q_AV_PRIVATE_EXPORT VideoDecoderPrivate : public AVDecoderPrivate
|
||||
{
|
||||
public:
|
||||
VideoDecoderPrivate():
|
||||
AVDecoderPrivate()
|
||||
{}
|
||||
virtual ~VideoDecoderPrivate() {}
|
||||
};
|
||||
} //namespace FAV
|
||||
|
||||
Q_DECLARE_METATYPE(FAV::AVFrameBuffersRef)
|
||||
|
||||
#endif // QTAV_AVDECODER_P_H
|
||||
1049
project/fm_viewer/fav/AVDemuxThread.cpp
Normal file
1049
project/fm_viewer/fav/AVDemuxThread.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user