fix export animation frames and add export mp4

This commit is contained in:
2020-05-26 08:58:52 +02:00
parent f041559212
commit 5394cbf8c3
7 changed files with 129 additions and 170 deletions

View File

@@ -496,6 +496,36 @@ void App::dialog_export_layers()
}
}
void App::dialog_export_anim_frames()
{
if (!check_license())
{
message_box("License", "This function is disabled in demo mode.");
return;
}
if (canvas)
{
#if defined(__IOS__)
auto dir = work_path + "/" + doc_name + "_frames";
if (Asset::create_dir(dir))
{
auto p = dir + "/" + doc_name;
canvas->m_canvas->export_anim_frames(p, [this, p] {
message_box("Export Layers", "Image layers exported to Files/PanoPainter");
});
}
#else
pick_dir([this](std::string path) {
auto p = path + "/" + doc_name;
canvas->m_canvas->export_anim_frames(p, [this, p] {
message_box("Export Layers", "Layers exported to: " + p);
});
});
#endif
}
}
void App::dialog_export_depth()
{
if (!check_license())
@@ -657,7 +687,7 @@ void App::dialog_timelapse_export()
rec_export(path);
},
[this](const std::string& path, bool saved) {
message_box("Export Timelapse", "Timelapse exported succesfully.");
message_box("Export Timelapse", "Timelapse exported successfully.");
}
);
#else
@@ -673,174 +703,22 @@ void App::dialog_timelapse_export()
void App::dialog_export_mp4()
{
std::thread([this] {
BT_SetTerminate();
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(&param, 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(&param);
//Encoder params
SEncParamExt param;
encoder->GetDefaultParams(&param);
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;
#if __IOS__ || __WEB__
pick_file_save("mp4", doc_name + "-animation",
[this](std::string path) {
export_anim_mp4(path);
},
[this](const std::string& path, bool saved) {
message_box("Export Animation", "Animation exported successfully.");
}
param.uiMaxNalSize = 1500;
param.iTargetBitrate *= param.iSpatialLayerNum;
encoder->InitializeExt(&param);
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<uint8_t> 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<uint8_t, 5> 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;
*(uint32_t*)data = BinaryStream::htonx(nalu_sz - 4);
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();
);
#else
pick_file_save({ "mp4" }, [this](std::string path) {
Canvas::I->export_anim_mp4(path, [this, path] {
message_box("Export Animation", "Animation exported to: " + path);
});
});
#endif
}
void App::dialog_whatsnew(bool force_show)