diff --git a/PanoPainter.vcxproj b/PanoPainter.vcxproj
index c2ee88a..93c66de 100644
--- a/PanoPainter.vcxproj
+++ b/PanoPainter.vcxproj
@@ -77,8 +77,8 @@
true
- libs\glm;libs\glew-2.0.0\include;libs\stb;libs\tinyxml2;libs\yoga;libs\curl-win\include;libs\jpeg;libs\wacom;libs\bugtrap-client\include;libs\poly2tri\poly2tri;libs\base64;libs\sqlite3;libs\openvr\headers;libs\nanort;libs\hash-library;libs\fmt\include;libs\glad\include;$(IncludePath)
- libs\curl-win\lib\dll-$(Configuration)-$(PlatformShortName);libs\glew-2.0.0\lib\Release\$(Platform);libs\bugtrap-client\lib;libs\openvr\lib\win64;$(LibraryPath)
+ libs\glm;libs\glew-2.0.0\include;libs\stb;libs\tinyxml2;libs\yoga;libs\curl-win\include;libs\jpeg;libs\wacom;libs\bugtrap-client\include;libs\poly2tri\poly2tri;libs\base64;libs\sqlite3;libs\openvr\headers;libs\nanort;libs\hash-library;libs\fmt\include;libs\glad\include;libs\openh264\include;libs\mp4v2\include;$(IncludePath)
+ libs\curl-win\lib\dll-$(Configuration)-$(PlatformShortName);libs\glew-2.0.0\lib\Release\$(Platform);libs\bugtrap-client\lib;libs\openvr\lib\win64;libs\openh264\lib;libs\mp4v2\lib\win;$(LibraryPath)
false
@@ -87,8 +87,8 @@
false
- libs\glm;libs\glew-2.0.0\include;libs\stb;libs\tinyxml2;libs\yoga;libs\curl-win\include;libs\jpeg;libs\wacom;libs\bugtrap-client\include;libs\poly2tri\poly2tri;libs\base64;libs\sqlite3;libs\openvr\headers;libs\nanort;libs\hash-library;libs\fmt\include;libs\glad\include;$(IncludePath)
- libs\curl-win\lib\dll-$(Configuration)-$(PlatformShortName);libs\glew-2.0.0\lib\Release\$(Platform);libs\bugtrap-client\lib;libs\openvr\lib\win64;$(LibraryPath)
+ libs\glm;libs\glew-2.0.0\include;libs\stb;libs\tinyxml2;libs\yoga;libs\curl-win\include;libs\jpeg;libs\wacom;libs\bugtrap-client\include;libs\poly2tri\poly2tri;libs\base64;libs\sqlite3;libs\openvr\headers;libs\nanort;libs\hash-library;libs\fmt\include;libs\glad\include;libs\openh264\include;libs\mp4v2\include;$(IncludePath)
+ libs\curl-win\lib\dll-$(Configuration)-$(PlatformShortName);libs\glew-2.0.0\lib\Release\$(Platform);libs\bugtrap-client\lib;libs\openvr\lib\win64;libs\openh264\lib;libs\mp4v2\lib\win;$(LibraryPath)
diff --git a/data/layout.xml b/data/layout.xml
index b7628c9..62befa7 100644
--- a/data/layout.xml
+++ b/data/layout.xml
@@ -249,6 +249,10 @@
+
+
+
+
diff --git a/src/app.h b/src/app.h
index a111121..3b41cfb 100644
--- a/src/app.h
+++ b/src/app.h
@@ -255,6 +255,7 @@ public:
void dialog_resize();
void dialog_preset_download();
void dialog_ppbr_export();
+ void dialog_export_mp4();
void cloud_upload();
void cloud_upload_all();
diff --git a/src/app_dialogs.cpp b/src/app_dialogs.cpp
index 3c2233c..e8bf1ea 100644
--- a/src/app_dialogs.cpp
+++ b/src/app_dialogs.cpp
@@ -10,6 +10,10 @@
#include "node_usermanual.h"
#include "node_dialog_export_ppbr.h"
+#include
+#define MP4V2_NO_STDINT_DEFS
+#include
+
#ifdef __QUEST__
#include "oculus_vr.h"
#elif __WEB__
@@ -641,3 +645,177 @@ void App::dialog_ppbr_export()
#endif
};
}
+
+void App::dialog_export_mp4()
+{
+ std::thread([this] {
+ const int video_width = 1024;
+ const int video_height = 512;
+ const int video_frames = 500;
+
+ auto pb = show_progress("Export MP4", video_frames);
+
+ ISVCEncoder* encoder;
+ int rv = WelsCreateSVCEncoder(&encoder);
+
+ //SEncParamBase param;
+ //memset(¶m, 0, sizeof(SEncParamBase));
+ //param.iUsageType = EUsageType::CAMERA_VIDEO_REAL_TIME; //from EUsageType enum
+ //param.fMaxFrameRate = 25;
+ //param.iPicWidth = 400;
+ //param.iPicHeight = 400;
+ //param.iTargetBitrate = 5000000;
+ //param.iRCMode = RC_TIMESTAMP_MODE;
+ //encoder->Initialize(¶m);
+
+ //Encoder params
+ SEncParamExt param;
+ encoder->GetDefaultParams(¶m);
+ param.iUsageType = CAMERA_VIDEO_REAL_TIME;
+ param.fMaxFrameRate = 25.f;
+ param.iLtrMarkPeriod = 75;
+ param.iPicWidth = 1024;
+ param.iPicHeight = 512;
+ param.iTargetBitrate = 1000 << 10;
+ param.bEnableDenoise = false;
+ param.iSpatialLayerNum = 1;
+ param.bUseLoadBalancing = false;
+ param.bEnableSceneChangeDetect = false;
+ param.bEnableBackgroundDetection = false;
+ param.bEnableAdaptiveQuant = false;
+ param.bEnableFrameSkip = false;
+ param.iMultipleThreadIdc = 0;
+ //param.uiIntraPeriod = 10;
+
+ for (int i = 0; i < param.iSpatialLayerNum; i++)
+ {
+ param.sSpatialLayers[i].iVideoWidth = param.iPicWidth >> (param.iSpatialLayerNum - 1 - i);
+ param.sSpatialLayers[i].iVideoHeight = param.iPicHeight >> (param.iSpatialLayerNum - 1 - i);
+ param.sSpatialLayers[i].fFrameRate = 25.f;
+ param.sSpatialLayers[i].iSpatialBitrate = param.iTargetBitrate;
+ param.sSpatialLayers[i].uiProfileIdc = PRO_BASELINE;
+ param.sSpatialLayers[i].uiLevelIdc = LEVEL_4_2;
+ param.sSpatialLayers[i].iDLayerQp = 42;
+
+ //SSliceArgument sliceArg;
+ //sliceArg.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
+ //sliceArg.uiSliceNum = 0;
+ //param.sSpatialLayers[i].sSliceArgument = sliceArg;
+ }
+
+ param.uiMaxNalSize = 1500;
+ param.iTargetBitrate *= param.iSpatialLayerNum;
+ encoder->InitializeExt(¶m);
+
+
+ int trace_level = WELS_LOG_ERROR;
+ encoder->SetOption(ENCODER_OPTION_TRACE_LEVEL, &trace_level);
+ int videoFormat = videoFormatI420;
+ encoder->SetOption(ENCODER_OPTION_DATAFORMAT, &videoFormat);
+
+ int frameSize = param.iPicWidth * param.iPicHeight * 3 / 2;
+ std::vector buf(frameSize);
+
+ SFrameBSInfo info;
+ memset(&info, 0, sizeof(SFrameBSInfo));
+ SSourcePicture pic;
+ memset(&pic, 0, sizeof(SSourcePicture));
+ pic.iPicWidth = param.iPicWidth;
+ pic.iPicHeight = param.iPicHeight;
+ pic.iColorFormat = videoFormatI420;
+ pic.iStride[0] = pic.iPicWidth;
+ pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1;
+ pic.pData[0] = buf.data();
+ pic.pData[1] = pic.pData[0] + (param.iPicWidth * param.iPicHeight);
+ pic.pData[2] = pic.pData[1] + (param.iPicWidth * param.iPicHeight >> 2);
+
+ std::string mp4_path = data_path + "/out.mp4";
+
+ MP4FileHandle mp4 = MP4Create(mp4_path.c_str());
+ MP4TrackId mp4_track = -1;
+ MP4SetTimeScale(mp4, 90000);
+
+ const int frames = 500;
+ //std::ofstream f("out.h264", std::ios::binary);
+ for (int num = 0; num < frames; num++)
+ {
+ pb->increment();
+ printf("encoding %.2f%%\r", (float)num / (float)(frames - 1) * 100.f);
+
+ float value = sinf((float)num / (float)frames * 10.f);
+ for (int y = 0; y < param.iPicHeight; y++)
+ for (int x = 0; x < param.iPicWidth; x++)
+ buf[y * param.iPicWidth + x] = (((y + num / 4) / 10) % 2) * (255.f * value);
+
+ //prepare input data
+ rv = encoder->EncodeFrame(&pic, &info);
+ //pic.uiTimeStamp += (1.f/25.f) * 1000.f;
+ //assert (rv == cmResultSuccess);
+ if (info.eFrameType != videoFrameTypeSkip)
+ {
+ //output bitstream handling
+ for (int layer = 0; layer < info.iLayerNum; layer++)
+ {
+ size_t bs_size = 0;
+ for (int nal = 0; nal < info.sLayerInfo[layer].iNalCount; nal++)
+ {
+ std::array nalu_bytes;
+ for (int i = 0; i < nalu_bytes.size(); i++)
+ nalu_bytes[i] = info.sLayerInfo[layer].pBsBuf[bs_size + i];
+ if (nalu_bytes[4] == 0x67) // SPS
+ {
+ uint8_t avc_profile = info.sLayerInfo[layer].pBsBuf[bs_size + 5];
+ uint8_t avc_profile_compat = info.sLayerInfo[layer].pBsBuf[bs_size + 6];
+ uint8_t avc_level = info.sLayerInfo[layer].pBsBuf[bs_size + 7];
+ if (mp4_track == -1)
+ {
+ mp4_track = MP4AddH264VideoTrack(mp4, 90000, 90000 / 25,
+ param.iPicWidth, param.iPicHeight,
+ avc_profile, avc_profile_compat, avc_level, 3);
+ MP4SetVideoProfileLevel(mp4, 1);
+ }
+ MP4AddH264SequenceParameterSet(mp4, mp4_track, info.sLayerInfo[layer].pBsBuf + bs_size + 4,
+ info.sLayerInfo[layer].pNalLengthInByte[nal] - 4);
+ }
+ else if (nalu_bytes[4] == 0x68) // PPS
+ {
+ MP4AddH264PictureParameterSet(mp4, mp4_track, info.sLayerInfo[layer].pBsBuf + bs_size + 4,
+ info.sLayerInfo[layer].pNalLengthInByte[nal] - 4);
+ }
+ else
+ {
+ int nalu_sz = info.sLayerInfo[layer].pNalLengthInByte[nal];
+ uint8_t* data = info.sLayerInfo[layer].pBsBuf + bs_size;
+ data[0] = (nalu_sz - 4) >> 24;
+ data[1] = (nalu_sz - 4) >> 16;
+ data[2] = (nalu_sz - 4) >> 8;
+ data[3] = (nalu_sz - 4) & 0xff;
+ bool sync = false;
+ if (nalu_bytes[4] == 0x65) // I-frame
+ sync = true;
+ else // 0x61 P-frame
+ sync = false;
+ MP4WriteSample(mp4, mp4_track, data, nalu_sz, MP4_INVALID_DURATION, 0, sync);
+ }
+ //printf("nalu %x\n", nalu_bytes[4]);
+ bs_size += info.sLayerInfo[layer].pNalLengthInByte[nal];
+ }
+ //f.write((const char*)info.sLayerInfo[layer].pBsBuf, bs_size);
+ }
+ }
+ }
+ //f.close();
+
+ printf("\n");
+
+ MP4Close(mp4);
+
+ if (encoder)
+ {
+ encoder->Uninitialize();
+ WelsDestroySVCEncoder(encoder);
+ }
+
+ pb->destroy();
+ }).detach();
+}
\ No newline at end of file
diff --git a/src/app_layout.cpp b/src/app_layout.cpp
index d0f3cc1..0ab3a4b 100644
--- a/src/app_layout.cpp
+++ b/src/app_layout.cpp
@@ -1037,6 +1037,12 @@ void App::init_menu_tools()
popup_exp->destroy();
};
+ popup_exp->find("mp4test")->on_click = [this, popup_exp](Node*) {
+ dialog_export_mp4();
+ popup_exp->mouse_release();
+ popup_exp->destroy();
+ };
+
#if __IOS__
popup_exp->find("sonarpen")->on_click = [this, popup_exp](Node*) {
[ios_app sonarpen_start];
diff --git a/src/pch.cpp b/src/pch.cpp
index ed69b62..b863eb7 100644
--- a/src/pch.cpp
+++ b/src/pch.cpp
@@ -21,4 +21,6 @@
#pragma comment(lib, "Shlwapi.lib")
//#pragma comment(lib, "Shcore.lib")
#pragma comment(lib, "openvr_api.lib")
+ #pragma comment(lib, "openh264-2.0.0-win64.lib")
+ #pragma comment(lib, "libmp4v2.lib")
#endif // _WIN32