Skip to content

Commit

Permalink
fix(merge): Fix wrong tbn values of h264 encoded segments
Browse files Browse the repository at this point in the history
  • Loading branch information
xymaxim committed Apr 19, 2024
1 parent a96fe64 commit e1120bf
Showing 1 changed file with 48 additions and 10 deletions.
58 changes: 48 additions & 10 deletions src/ytpb/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,19 @@ def get_nth_or_none(iterable, n: int) -> Any | None:


def mux_and_cut_boundary_segment(
audio_segment_path: Path, video_segment_path: Path, output_path: Path, **cut_kwargs
audio_segment_path: Path,
video_segment_path: Path,
output_path: Path,
video_codec: str | None = None,
**cut_kwargs,
) -> None:
"""Muxes and cuts a boundary segment.
Args:
audio_segment_path: A path to an audio segment.
video_segment_path: A path to a video segment.
output_path: An output path of the muxed segment.
video_codec: A video codec name.
cut_kwargs: Cut keyword arguments: ``cut_at_start`` and ``cut_at_end``.
"""

Expand All @@ -59,6 +64,11 @@ def prepare_ffmpeg_input_options(
"only cut_at_start or cut_at_end keyword argument is accepted in cut_kwargs"
)

if video_segment_path and video_codec is None:
video_codec = ffmpeg.ffprobe_show_entries(
video_segment_path, "stream=codec_name"
)

ffmpeg_input_options = []
ffmpeg_codecs_options = []

Expand All @@ -77,24 +87,20 @@ def prepare_ffmpeg_input_options(
video_segment_path, **cut_kwargs
)

video_codec_name = ffmpeg.ffprobe_show_entries(
video_segment_path, "stream=codec_name"
)

user_encoding_settings = os.environ.get(
f"YTPB_{video_codec_name.upper()}_ENCODING_SETTINGS", None
f"YTPB_{video_codec.upper()}_ENCODING_SETTINGS", None
)
if user_encoding_settings:
ffmpeg_codecs_options += ["-c:v"] + shlex.split(user_encoding_settings)
else:
try:
ffmpeg_codecs_options += ["-c:v"] + shlex.split(
DEFAULT_VIDEO_ENCODING_SETTINGS[video_codec_name]
DEFAULT_VIDEO_ENCODING_SETTINGS[video_codec]
)
except KeyError:
raise ValueError(
"No encoding settings are availabe for"
f"'{video_codec_name}' video codec"
f"'{video_codec}' video codec"
)

if audio_segment_path:
Expand All @@ -103,8 +109,19 @@ def prepare_ffmpeg_input_options(
)
ffmpeg_codecs_options += ["-c:a", "copy"]

additional_options: list[str] = []
if video_segment_path and video_codec == "h264":
# Ensure to have the same tbn values after re-encoding of segments
# and their concatenation (see the merge_segments() function).
additional_options += ["-video_track_timescale", "1k"]

ffmpeg.run_ffmpeg(
ffmpeg_input_options + ffmpeg_codecs_options + [str(output_path)]
[
*ffmpeg_input_options,
*additional_options,
*ffmpeg_codecs_options,
str(output_path),
]
)


Expand Down Expand Up @@ -226,12 +243,19 @@ def merge_segments(
end_audio_segment_path = get_nth_or_none(audio_segment_paths, -1)
end_video_segment_path = get_nth_or_none(video_segment_paths, -1)

video_codec: str | None = None
if video_segment_paths:
video_codec = ffmpeg.ffprobe_show_entries(
video_segment_paths[0], "stream=codec_name"
)

if num_of_segments == 1:
segment_trimmed_path = Path(temp_directory, "a.a" + output_extension)
mux_and_cut_boundary_segment(
start_audio_segment_path,
start_video_segment_path,
segment_trimmed_path,
video_codec,
cut_at_start=cut_at_start,
)
parts_to_merge = [segment_trimmed_path]
Expand All @@ -241,6 +265,7 @@ def merge_segments(
start_audio_segment_path,
start_video_segment_path,
start_trimmed_path,
video_codec,
cut_at_start=cut_at_start,
)

Expand All @@ -249,6 +274,7 @@ def merge_segments(
end_audio_segment_path,
end_video_segment_path,
end_trimmed_path,
video_codec,
cut_at_end=cut_at_end,
)

Expand All @@ -259,6 +285,7 @@ def merge_segments(
start_audio_segment_path,
start_video_segment_path,
start_trimmed_path,
video_codec,
cut_at_start=cut_at_start,
)

Expand All @@ -269,6 +296,7 @@ def merge_segments(
end_audio_segment_path,
end_video_segment_path,
end_trimmed_path,
video_codec,
cut_at_end=cut_at_end,
)

Expand All @@ -293,8 +321,18 @@ def merge_segments(
concat_filter_options += safe_concat_options + ["-i", concat_file_path]
merge_segments.paths_to_cleanup.append(concat_file_path)

additional_options: list[str] = []
if video_segment_paths and video_codec == "h264":
additional_options += ["-video_track_timescale", "1k"]

ffmpeg.run_ffmpeg(
concat_filter_options + ["-c", "copy", middle_concatenated_path],
[
*concat_filter_options,
*additional_options,
"-c",
"copy",
str(middle_concatenated_path),
],
capture_output=True,
check=True,
)
Expand Down

0 comments on commit e1120bf

Please sign in to comment.