first commit

This commit is contained in:
2026-02-21 17:11:31 +09:00
commit 18b4338361
4001 changed files with 365464 additions and 0 deletions

View 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

View 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

View 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)

View 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

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

View 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

View 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

View 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

View 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

View 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

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

View 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

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

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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)

View 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

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

View 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