-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
true keyframe cut #1984
base: master
Are you sure you want to change the base?
true keyframe cut #1984
Conversation
WalkthroughThe latest update introduces a new option, "True keyframe cut," for aligning segment times in the video editing dialog. This mode replaces the former default setting "before" with "keyframeCutFix." Supporting changes were made across different modules, including updating function parameters, handling logic, and error management to integrate this new mode seamlessly. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as User Interface
participant Dialog as Align Segments Dialog
participant Hook as useSegments Hook
participant FFMPEG as FFMPEG Module
UI->>Dialog: Choose 'True keyframe cut'
Dialog->>Hook: Trigger segment alignment
Hook->>FFMPEG: getStreamFps(videoStream)
FFMPEG->>Hook: Return fps
Hook->>FFMPEG: getDuration(filePath)
FFMPEG->>Hook: Return duration
Hook->>FFMPEG: findKeyframe(mode: 'keyframeCutFix')
FFMPEG->>Hook: Return keyframe time
Hook->>Dialog: Update segment times
Dialog->>UI: Display updated segments
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Review Details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (3)
- src/renderer/src/dialogs/index.tsx (1 hunks)
- src/renderer/src/ffmpeg.ts (2 hunks)
- src/renderer/src/hooks/useSegments.ts (2 hunks)
Additional comments not posted (4)
src/renderer/src/dialogs/index.tsx (1)
329-331
: The addition of the 'consistent' option inaskForAlignSegments
aligns well with the PR's goal to improve keyframe cut precision. Changing the default to 'consistent' is a significant change that should be highlighted in user documentation or release notes.src/renderer/src/ffmpeg.ts (2)
99-99
: The expansion of theFindKeyframeMode
type to include 'consistent' supports the new feature introduced in this PR. This change should be well-documented to inform developers of the new functionality available.
112-114
: The implementation of the 'consistent' mode infindKeyframe
correctly focuses on finding the next keyframe, which is crucial for the true keyframe cut feature. Ensure that this behavior is covered by unit tests to prevent regressions in future changes.src/renderer/src/hooks/useSegments.ts (1)
9-9
: Ensure the newly imported functionsgetStreamFps
andgetDuration
are used appropriately within the file.
|
||
if (filePath == null) throw new Error(); | ||
const frameTime = 1 / (getStreamFps(videoStream) || 1000); | ||
const duration = await getDuration(filePath); | ||
|
||
await modifySelectedSegmentTimes(async (segment) => { | ||
const newSegment = { ...segment }; | ||
|
||
async function align(key) { | ||
async function align(key: string) { | ||
const time = newSegment[key]; | ||
if (filePath == null) throw new Error(); | ||
const keyframe = await findKeyframeNearTime({ filePath, streamIndex: videoStream.index, time, mode }); | ||
if (keyframe == null) throw new Error(`Cannot find any keyframe within 60 seconds of frame ${time}`); | ||
let keyframe = await findKeyframeNearTime({ filePath, streamIndex: videoStream.index, time, mode }); | ||
if (keyframe == null) { | ||
if (mode != 'consistent') { | ||
throw new Error(`Cannot find any keyframe within 60 seconds of frame ${time}`); | ||
} | ||
keyframe = duration; | ||
} | ||
newSegment[key] = keyframe; | ||
} | ||
if (startOrEnd.includes('start')) await align('start'); | ||
if (startOrEnd.includes('end')) await align('end'); | ||
if (startOrEnd.includes('start')) { | ||
if (mode == 'consistent') { | ||
newSegment.start += frameTime * 0.3; | ||
} | ||
await align('start'); | ||
if (mode == 'consistent') { | ||
newSegment.start -= frameTime * 0.7; | ||
} | ||
} | ||
if (startOrEnd.includes('end')) { | ||
await align('end'); | ||
if (mode == 'consistent' && newSegment.end != duration) { | ||
newSegment.end -= frameTime * 0.3; | ||
} | ||
} | ||
if (startOrEnd.includes('start')) { | ||
newSegment.start = Math.min(newSegment.start, newSegment.end - frameTime * 0.99); //don't know how ffmpeg interprets cuts between frames | ||
} | ||
else { | ||
newSegment.end = Math.max(newSegment.start + frameTime * 0.99, newSegment.end); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tip
Codebase Verification
There are no unit tests covering the new 'consistent' keyframe alignment mode or the useSegments
function. This lack of test coverage could lead to untested edge cases and potential issues in production.
- Ensure that unit tests are added to cover the 'consistent' mode, including edge cases where keyframes might not be found within the expected range.
- Consider adding tests for the
useSegments
function to ensure comprehensive coverage.
Analysis chain
The implementation of the new 'consistent' keyframe alignment mode is complex and involves several conditional checks and adjustments to segment times. Ensure thorough testing, especially edge cases where keyframes might not be found within the expected range.
Would you like assistance in writing additional unit tests for this new feature?
Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the new 'consistent' mode is covered by unit tests.
# Test: Search for unit tests covering the 'consistent' mode. Expect: Tests that handle various scenarios including edge cases.
rg --type typescript $'describe.*(consistent)'
Length of output: 82
Script:
#!/bin/bash
# Description: Verify the new 'consistent' mode is covered by unit tests.
# Test: Search for unit tests covering the 'consistent' mode. Expect: Tests that handle various scenarios including edge cases.
rg --type ts $'describe.*(consistent)'
Length of output: 39
Script:
#!/bin/bash
# Description: Verify if there are any tests related to the `useSegments` function.
# Test: Search for test cases related to `useSegments`. Expect: Tests that might indirectly cover the 'consistent' mode.
rg --type ts 'useSegments'
Length of output: 880
Script:
#!/bin/bash
# Description: Verify if there are any test files in the repository.
# Test: Search for test files in the repository. Expect: Files that might contain tests for `useSegments`.
fd --type f --extension ts --exec rg 'test|describe|it'
Length of output: 80538
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (3)
- src/renderer/src/dialogs/index.tsx (1 hunks)
- src/renderer/src/ffmpeg.ts (2 hunks)
- src/renderer/src/hooks/useSegments.ts (2 hunks)
Files skipped from review due to trivial changes (1)
- src/renderer/src/dialogs/index.tsx
Additional context used
Biome
src/renderer/src/ffmpeg.ts
[error] 591-591: Change to an optional chain. (lint/complexity/useOptionalChain)
Unsafe fix: Change to an optional chain.
[error] 592-592: Change to an optional chain. (lint/complexity/useOptionalChain)
Unsafe fix: Change to an optional chain.
[error] 651-651: Change to an optional chain. (lint/complexity/useOptionalChain)
Unsafe fix: Change to an optional chain.
Additional comments not posted (7)
src/renderer/src/ffmpeg.ts (5)
109-109
: Added 'consistent' mode toFindKeyframeMode
.This extension allows the
findKeyframe
function to handle the new 'consistent' mode, aligning with the PR objectives to enhance keyframe cut consistency.
Line range hint
591-591
: Consider using an optional chain to simplify the code.
[REFACTOR_SUGGESTion]
This can make the code cleaner and potentially safer by avoiding undefined errors.- const makeTag = format.tags && format.tags['com.apple.quicktime.make']; + const makeTag = format.tags?.['com.apple.quicktime.make'];
Line range hint
592-592
: Consider using an optional chain for accessing the model tag.
[REFACTOR_SUGGESTion]
This refactoring enhances code readability and robustness.- const modelTag = format.tags && format.tags['com.apple.quicktime.model']; + const modelTag = format.tags?.['com.apple.quicktime.model'];
Line range hint
651-651
: Apply an optional chain for accessing the codec name.
[REFACTOR_SUGGESTion]
Using optional chaining here can prevent potential runtime errors if thestream
object or itscodec_name
property is undefined.- if (stream.codec_type === 'audio') { + if (stream.codec_type === 'audio' && stream?.codec_name) {
122-124
: Review the 'consistent' mode logic infindKeyframe
.The 'consistent' mode currently mirrors the 'after' mode. If this is intentional, consider adding a comment explaining why this logic is reused. Otherwise, review if additional adjustments are needed for the 'consistent' mode to meet its intended behavior.
src/renderer/src/hooks/useSegments.ts (2)
8-8
: Ensure that the newly imported functionsgetStreamFps
andgetDuration
are used appropriately throughout the file.
285-286
: Calculation offrameTime
and fetchingduration
are critical for the new alignment logic. Ensure that these values are accurately retrieved and used.
async function align(key: string) { | ||
const time = newSegment[key]; | ||
if (filePath == null) throw new Error(); | ||
const keyframe = await findKeyframeNearTime({ filePath, streamIndex: videoStream.index, time, mode }); | ||
if (keyframe == null) throw new Error(`Cannot find any keyframe within 60 seconds of frame ${time}`); | ||
let keyframe = await findKeyframeNearTime({ filePath, streamIndex: videoStream.index, time, mode }); | ||
if (keyframe == null) { | ||
if (mode != 'consistent') { | ||
throw new Error(`Cannot find any keyframe within 60 seconds of frame ${time}`); | ||
} | ||
keyframe = duration; | ||
} | ||
newSegment[key] = keyframe; | ||
} | ||
if (startOrEnd.includes('start')) await align('start'); | ||
if (startOrEnd.includes('end')) await align('end'); | ||
if (startOrEnd.includes('start')) { | ||
if (mode == 'consistent') { | ||
newSegment.start += frameTime * 0.3; | ||
} | ||
await align('start'); | ||
if (mode == 'consistent') { | ||
newSegment.start -= frameTime * 0.7; | ||
} | ||
} | ||
if (startOrEnd.includes('end')) { | ||
await align('end'); | ||
if (mode == 'consistent' && newSegment.end != duration) { | ||
newSegment.end -= frameTime * 0.3; | ||
} | ||
} | ||
if (startOrEnd.includes('start')) { | ||
newSegment.start = Math.min(newSegment.start, newSegment.end - frameTime * 0.99); //don't know how ffmpeg interprets cuts between frames | ||
} | ||
else { | ||
newSegment.end = Math.max(newSegment.start + frameTime * 0.99, newSegment.end); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block introduces complex logic for aligning segment times based on the new 'consistent' keyframe mode. Consider breaking down this large anonymous function into smaller, named functions to improve readability and maintainability.
+ async function adjustSegmentTime(segment, key, mode, frameTime, duration) {
+ const time = segment[key];
+ if (filePath == null) throw new Error('File path is required to find keyframes.');
+ let keyframe = await findKeyframeNearTime({ filePath, streamIndex: videoStream.index, time, mode });
+ if (keyframe == null) {
+ if (mode != 'consistent') {
+ throw new Error(`Cannot find any keyframe within 60 seconds of frame ${time}`);
+ }
+ keyframe = duration;
+ }
+ segment[key] = keyframe;
+ return segment;
+ }
- await modifySelectedSegmentTimes(async (segment) => {
+ await modifySelectedSegmentTime(segment => adjustSegmentTime(segment, 'start', mode, frameTime, duration));
+ await modifySelectedSegmentTime(segment => adjustSegmentTime(segment, 'end', mode, frameTime, duration));
Committable suggestion was skipped due to low confidence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (3)
- src/renderer/src/dialogs/index.tsx (1 hunks)
- src/renderer/src/ffmpeg.ts (2 hunks)
- src/renderer/src/hooks/useSegments.ts (2 hunks)
Additional comments not posted (5)
src/renderer/src/ffmpeg.ts (2)
109-109
: Approved: Addition of new mode toFindKeyframeMode
.The addition of
keyframeCutFix
to theFindKeyframeMode
type aligns with the PR's objectives to enhance keyframe cut consistency.
122-124
: Approved: Update tofindKeyframe
function.The addition of the
keyframeCutFix
case in thefindKeyframe
function is implemented correctly by mirroring the 'after' case. However, ensure to verify this new functionality thoroughly to confirm it behaves as expected in all scenarios.Run the following script to verify the new functionality:
Verification successful
Verified:
keyframeCutFix
mode integration.The
keyframeCutFix
mode is correctly integrated into the codebase. It is part of theFindKeyframeMode
type, implemented in thefindKeyframe
function, and has specific handling logic in theuseSegments
hook. This confirms that the new functionality is being used as intended.
- File:
src/renderer/src/ffmpeg.ts
- File:
src/renderer/src/hooks/useSegments.ts
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the new `keyframeCutFix` mode in various scenarios. # Test: Search for the function usage. Expect: Only occurrences of the new signature. rg --type python -A 5 $'keyframeCutFix'Length of output: 69
Script:
#!/bin/bash # Description: Verify the new `keyframeCutFix` mode in various scenarios within TypeScript files. # Test: Search for the usage of `keyframeCutFix` in TypeScript files. rg --type typescript -A 5 'keyframeCutFix'Length of output: 77
Script:
#!/bin/bash # Description: Verify the new `keyframeCutFix` mode in various scenarios within TypeScript files. # Test: Search for the usage of `keyframeCutFix` in .ts files. rg --glob '*.ts' -A 5 'keyframeCutFix'Length of output: 2486
src/renderer/src/dialogs/index.tsx (1)
332-334
: Approved: Update toaskForAlignSegments
function.The addition of the
keyframeCutFix
option and setting it as the default in theaskForAlignSegments
function enhances the user interaction by providing a clearer and more consistent default for segment alignment.src/renderer/src/hooks/useSegments.ts (2)
8-8
: Review the new import statement.The addition of
getStreamFps
from theffmpeg
module is crucial for calculatingframeTime
, which is used in the segment alignment logic. This change supports the PR's objective to enhance keyframe cut consistency.
290-322
: Review the logic for aligning segment times based on keyframes.The logic for adjusting segment times based on the mode 'keyframeCutFix' is complex and involves adding and subtracting fractions of
frameTime
. This approach allows for a more nuanced alignment of segment times, which is crucial for the PR's objective.However, ensure that the adjustments do not introduce errors in segment timing, especially when handling edge cases.
Consider adding unit tests to verify the correctness of these adjustments:
describe('Segment Time Adjustments', () => { it('should correctly adjust segment times based on keyframes', () => { // Example test case }); });
@@ -280,26 +280,55 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt | |||
if (response == null) return; | |||
setWorking({ text: i18n.t('Aligning segments to keyframes') }); | |||
const { mode, startOrEnd } = response; | |||
|
|||
if (filePath == null) throw new Error(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve error handling message.
The error handling at line 284 should provide more descriptive messages to help with debugging, especially since this function deals with critical segment timing adjustments.
Consider adding a more descriptive error message:
- if (filePath == null) throw new Error();
+ if (filePath == null) throw new Error('File path is required for alignment.');
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
if (filePath == null) throw new Error(); | |
if (filePath == null) throw new Error('File path is required for alignment.'); |
aligns the segments to make keyframe cut more consistent
the segment start will be moved to less than one frame before the first keyframe strictly after the start point, ensuring that the cut will be at the last keyframe at or before the start point.
the endpoint can optionally be aligned to a fraction of a frame before the first keyframe at or after the endpoint. this is useful for splitting a video into segments without repeating or missing any frames.