From c7679a4cd2883c2b826990691bcad08bfde42d6e Mon Sep 17 00:00:00 2001 From: YourMJK Date: Tue, 30 Jan 2024 00:01:07 +0100 Subject: [PATCH 1/2] Add move functionality --- README.md | 6 +- main.cpp | 167 ++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 110 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index aac66d5..3acf823 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ SupMover - Shift timings and Screen Area of PGS/Sup subtitle # Usage -`SupMover ( ) [delay (ms)] [crop ( )] [resync (/ | multFactor)] [add_zero] [tonemap ] [cut_merge ]` +`SupMover ( ) [delay (ms)] [move ( )] [crop ( )] [resync (/ | multFactor)] [add_zero] [tonemap ] [cut_merge ]` `SupMover ( )` old syntax, kept for backward compatibility @@ -11,10 +11,14 @@ SupMover - Shift timings and Screen Area of PGS/Sup subtitle * Apply a milliseconds delay, positive or negative, to all the subpic of the subtitle, it can be fractional as the SUP speficication have a precision of 1/90ms * resync * Multiply all the timestamp by this factor, this can also be supplied as a fraction +* move + * Shift the windows position of all subpic by the inputed parameters (the image data is left untouched). + * Position is clamped to the screen edges so that windows are always fully contained within the screen area. * crop * Crop the windows area of all subpic by the inputed parameters. * This is done losslessly by only shifting the windows position (the image data is left untouched). * Crop functionality is not exstensivelly tested when multiple Composition Object or Windows are present or when the windows are is outside the new screen area, a warning is issued if that's the case and i strongly advise to check the resulting subtitle with a video player, also handling of the Object Cropped flag and windows area bigger than the new screen area is not implemented, a warning is issued if needed + * If both move and crop are selected, the crop is performed after the move. * delay + resync * If both modes are selected the delay will be adjusted if it comes before the resync parameter, for example if the program is launched with `delay 1000 resync 1.001` it will be internally adjusted to 1001ms, instead if it's launched with `resync 1.001 delay 1000` it will not * add_zero diff --git a/main.cpp b/main.cpp index 1fae52d..c344cce 100644 --- a/main.cpp +++ b/main.cpp @@ -27,6 +27,11 @@ struct t_timestamp { unsigned long ms; }; +struct t_move { + int16_t deltaX; + int16_t deltaY; +}; + struct t_crop { uint16_t left; uint16_t top; @@ -138,6 +143,7 @@ struct t_PDS { struct t_cmd { int32_t delay = 0; + t_move move = {}; t_crop crop = {}; double resync = 1; bool addZero = false; @@ -504,6 +510,7 @@ bool parseCutMerge(t_cutMerge* cutMerge) { bool ParseCMD(int32_t argc, char** argv, t_cmd& cmd) { cmd.delay = 0; + cmd.move = {}; cmd.crop = {}; cmd.resync = 1; cmd.addZero = false; @@ -539,6 +546,11 @@ bool ParseCMD(int32_t argc, char** argv, t_cmd& cmd) { */ } } + else if (command == "move") { + cmd.move.deltaX = atoi(argv[i + 1]); + cmd.move.deltaY = atoi(argv[i + 2]); + i += 3; + } else if (command == "crop") { cmd.crop.left = atoi(argv[i + 1]); cmd.crop.top = atoi(argv[i + 2]); @@ -687,7 +699,7 @@ int main(int32_t argc, char** argv) if (argc < 4) { - std::printf("Usage: SupMover ( ) [delay (ms)] [crop ( )] [resync (/ | multFactor)] [add_zero] [tonemap ]\r\n"); + std::printf("Usage: SupMover ( ) [delay (ms)] [move ( )] [crop ( )] [resync (/ | multFactor)] [add_zero] [tonemap ]\r\n"); std::printf("delay and resync command are executed in the order supplied\r\n"); return 0; } @@ -700,11 +712,12 @@ int main(int32_t argc, char** argv) bool doDelay = cmd.delay != 0; + bool doMove = cmd.move.deltaX != 0 || cmd.move.deltaY != 0; bool doCrop = (cmd.crop.left + cmd.crop.top + cmd.crop.right + cmd.crop.bottom) > 0; bool doResync = cmd.resync != 1; bool doTonemap = cmd.tonemap != 1; - bool doSomething = doDelay || doCrop || doResync || cmd.addZero || doTonemap || cmd.cutMerge.doCutMerge; + bool doSomething = doDelay || doMove || doCrop || doResync || cmd.addZero || doTonemap || cmd.cutMerge.doCutMerge; FILE* input = std::fopen(argv[1], "rb"); if (input == nullptr) { @@ -801,7 +814,7 @@ int main(int32_t argc, char** argv) break; case 0x16: //std::printf("PCS\r\n"); - if (doCrop || cmd.addZero || cmd.cutMerge.doCutMerge) { + if (doMove | doCrop || cmd.addZero || cmd.cutMerge.doCutMerge) { pcs = ReadPCS(&buffer[start + HEADER_SIZE]); offesetCurrPCS = start; @@ -904,7 +917,7 @@ int main(int32_t argc, char** argv) case 0x17: //std::printf("WDS\r\n"); fixPCS = false; - if (doCrop) { + if (doMove || doCrop) { wds = ReadWDS(&buffer[start + HEADER_SIZE]); if (wds.numberOfWindows > 1) { @@ -912,71 +925,101 @@ int main(int32_t argc, char** argv) std::printf("Multiple windows at timestamp %lu:%02lu:%02lu.%03lu! Please Check!\r\n", timestamp.hh, timestamp.mm, timestamp.ss, timestamp.ms); } - for (int i = 0; i < wds.numberOfWindows; i++) { - t_rect wndRect; - uint16_t corrHor = 0; - uint16_t corrVer = 0; - - wndRect.x = wds.windows[i].WindowsHorPos; - wndRect.y = wds.windows[i].WindowsVerPos; - wndRect.width = wds.windows[i].WindowsWidth; - wndRect.height = wds.windows[i].WindowsHeight; - - if (wndRect.width > screenRect.width - || wndRect.height > screenRect.height) { - t_timestamp timestamp = PTStoTimestamp(header.pts1); - std::printf("Window is bigger then new screen area at timestamp %lu:%02lu:%02lu.%03lu\r\n", timestamp.hh, timestamp.mm, timestamp.ss, timestamp.ms); - std::printf("Implement it!\r\n"); - /* - pcs.width = wndRect.width; - pcs.height = wndRect.height; - fixPCS = true; - */ - } - else { - if (!rectIsContained(screenRect, wndRect)) { - t_timestamp timestamp = PTStoTimestamp(header.pts1); - std::printf("Window is outside new screen area at timestamp %lu:%02lu:%02lu.%03lu\r\n", timestamp.hh, timestamp.mm, timestamp.ss, timestamp.ms); - - uint16_t wndRightPoint = wndRect.x + wndRect.width; - uint16_t screenRightPoint = screenRect.x + screenRect.width; - if (wndRightPoint > screenRightPoint) { - corrHor = wndRightPoint - screenRightPoint; - } - - uint16_t wndBottomPoint = wndRect.y + wndRect.height; - uint16_t screenBottomPoint = screenRect.y + screenRect.height; - if (wndBottomPoint > screenBottomPoint) { - corrVer = wndBottomPoint - screenBottomPoint; + if (doMove) { + for (int i = 0; i < wds.numberOfWindows; i++) { + t_window *window = &wds.windows[i]; + int16_t minDeltaX = -(int16_t)window->WindowsHorPos; + int16_t minDeltaY = -(int16_t)window->WindowsVerPos; + int16_t maxDeltaX = pcs.width - (window->WindowsHorPos + window->WindowsWidth); + int16_t maxDeltaY = pcs.height - (window->WindowsVerPos + window->WindowsHeight); + int16_t clampedDeltaX = std::min(std::max(cmd.move.deltaX, minDeltaX), maxDeltaX); + int16_t clampedDeltaY = std::min(std::max(cmd.move.deltaY, minDeltaY), maxDeltaY); + + window->WindowsHorPos += clampedDeltaX; + window->WindowsVerPos += clampedDeltaY; + + for (int j = 0; j < pcs.numCompositionObject; j++) { + t_compositionObject *object = &pcs.compositionObject[j]; + if (object->windowID != window->windowID) continue; + + if (object->objectCroppedFlag == 0x40) { + object->objCropHorPos += clampedDeltaX; + object->objCropVerPos += clampedDeltaY; } + object->objectHorPos += clampedDeltaX; + object->objectVerPos += clampedDeltaY; + fixPCS = true; + } + } + } - if (corrHor + corrVer != 0) { - std::printf("Please check\r\n"); + if (doCrop) { + for (int i = 0; i < wds.numberOfWindows; i++) { + t_rect wndRect; + uint16_t corrHor = 0; + uint16_t corrVer = 0; + + wndRect.x = wds.windows[i].WindowsHorPos; + wndRect.y = wds.windows[i].WindowsVerPos; + wndRect.width = wds.windows[i].WindowsWidth; + wndRect.height = wds.windows[i].WindowsHeight; + + if (wndRect.width > screenRect.width + || wndRect.height > screenRect.height) { + t_timestamp timestamp = PTStoTimestamp(header.pts1); + std::printf("Window is bigger then new screen area at timestamp %lu:%02lu:%02lu.%03lu\r\n", timestamp.hh, timestamp.mm, timestamp.ss, timestamp.ms); + std::printf("Implement it!\r\n"); + /* + pcs.width = wndRect.width; + pcs.height = wndRect.height; + fixPCS = true; + */ + } + else { + if (!rectIsContained(screenRect, wndRect)) { + t_timestamp timestamp = PTStoTimestamp(header.pts1); + std::printf("Window is outside new screen area at timestamp %lu:%02lu:%02lu.%03lu\r\n", timestamp.hh, timestamp.mm, timestamp.ss, timestamp.ms); + + uint16_t wndRightPoint = wndRect.x + wndRect.width; + uint16_t screenRightPoint = screenRect.x + screenRect.width; + if (wndRightPoint > screenRightPoint) { + corrHor = wndRightPoint - screenRightPoint; + } + + uint16_t wndBottomPoint = wndRect.y + wndRect.height; + uint16_t screenBottomPoint = screenRect.y + screenRect.height; + if (wndBottomPoint > screenBottomPoint) { + corrVer = wndBottomPoint - screenBottomPoint; + } + + if (corrHor + corrVer != 0) { + std::printf("Please check\r\n"); + } } } - } - if (cmd.crop.left > wds.windows[i].WindowsHorPos) { - wds.windows[i].WindowsHorPos = 0; - } - else { - wds.windows[i].WindowsHorPos -= (cmd.crop.left + corrHor); - } + if (cmd.crop.left > wds.windows[i].WindowsHorPos) { + wds.windows[i].WindowsHorPos = 0; + } + else { + wds.windows[i].WindowsHorPos -= (cmd.crop.left + corrHor); + } - if (cmd.crop.top > wds.windows[i].WindowsVerPos) { - wds.windows[i].WindowsVerPos = 0; - } - else { - wds.windows[i].WindowsVerPos -= (cmd.crop.top + corrVer); - } + if (cmd.crop.top > wds.windows[i].WindowsVerPos) { + wds.windows[i].WindowsVerPos = 0; + } + else { + wds.windows[i].WindowsVerPos -= (cmd.crop.top + corrVer); + } - if (corrVer != 0) { - pcs.compositionObject[i].objectVerPos -= corrVer; - fixPCS = true; - } - if (corrHor != 0) { - pcs.compositionObject[i].objectHorPos -= corrHor; - fixPCS = true; + if (corrVer != 0) { + pcs.compositionObject[i].objectVerPos -= corrVer; + fixPCS = true; + } + if (corrHor != 0) { + pcs.compositionObject[i].objectHorPos -= corrHor; + fixPCS = true; + } } } From 0d16ad3855e849703727f9bab75a0b2e2b3713b5 Mon Sep 17 00:00:00 2001 From: YourMJK Date: Tue, 30 Jan 2024 19:10:19 +0100 Subject: [PATCH 2/2] Remove code for handling manipulation of crop fields and print warning instead --- main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main.cpp b/main.cpp index c344cce..8223fb9 100644 --- a/main.cpp +++ b/main.cpp @@ -943,8 +943,12 @@ int main(int32_t argc, char** argv) if (object->windowID != window->windowID) continue; if (object->objectCroppedFlag == 0x40) { + t_timestamp timestamp = PTStoTimestamp(header.pts1); + std::printf("Object Cropped Flag set at timestamp %lu:%02lu:%02lu.%03lu! Crop fields are not supported yet.\r\n", timestamp.hh, timestamp.mm, timestamp.ss, timestamp.ms); + /* object->objCropHorPos += clampedDeltaX; object->objCropVerPos += clampedDeltaY; + */ } object->objectHorPos += clampedDeltaX; object->objectVerPos += clampedDeltaY;