impl disposition rewrite

click
Maveno 1 year ago
parent 4d7f728f25
commit dcd79b74fd

@ -12,7 +12,6 @@ VERSION='0.1.0'
DEFAULT_VIDEO_ENCODER = 'vp9'
DEFAULT_QUALITY = 23
DEFAULT_AV1_PRESET = 5
DEFAULT_FILE_FORMAT = 'webm'
@ -230,10 +229,30 @@ def getStreamDescriptor(filename):
s['layout'] = 'undefined'
descriptor[s['codec_type']].append(s)
descriptor[s['codec_type']][-1]['src_sub_index'] = len(descriptor[s['codec_type']]) - 1
return descriptor
def getModifiedStreamOrder(length, last):
"""This is jellyfin specific as the last stream in the order is set as default"""
seq = list(range(length))
if last < 0 or last > length -1:
return seq
seq.pop(last)
seq.append(last)
return seq
def getReorderedSubstreams(subDescriptor, last):
numSubStreams = len(subDescriptor)
modifiedOrder = getModifiedStreamOrder(numSubStreams, last)
reorderedDescriptor = []
for streamIndex in range(numSubStreams):
reorderedDescriptor.append(subDescriptor[modifiedOrder[streamIndex]])
return reorderedDescriptor
def generateAV1Tokens(q, p):
return ['-c:v:0', 'libsvtav1',
@ -321,6 +340,25 @@ def generateClearTokens(streams):
return clearTokens
def generateDispositionTokens(subDescriptor):
"""-disposition:s:X default+forced"""
dispositionTokens = []
for subStreamIndex in range(len(subDescriptor)):
subStream = subDescriptor[subStreamIndex]
streamType = subStream['codec_type'][0] # v|a|s
dispositionFlags = {k for (k,v) in subStream['disposition'].items() if v == 1} if 'disposition' in subStream.keys() else set()
if dispositionFlags:
dispositionTokens += [f"-disposition:{streamType}:{subStreamIndex}", '+'.join(dispositionFlags)]
else:
dispositionTokens += [f"-disposition:{streamType}:{subStreamIndex}", '0']
return dispositionTokens
@click.group()
@click.pass_context
def ffx(ctx):
@ -370,10 +408,10 @@ def streams(filename):
@click.option('-ac3', '--ac3-bitrate', type=int, default=DEFAULT_AC3_BANDWIDTH, help=f"Bitrate in kbit/s to be used to encode 5.1 audio streams (default: {DEFAULT_AC3_BANDWIDTH})")
@click.option('-dts', '--dts-bitrate', type=int, default=DEFAULT_DTS_BANDWIDTH, help=f"Bitrate in kbit/s to be used to encode 6.1 audio streams (default: {DEFAULT_DTS_BANDWIDTH})")
@click.option('-ds', '--default-subtitle', type=int, help='Index of default subtitle stream')
@click.option('-ds', '--default-subtitle', type=int, default=-1, help='Index of default subtitle stream')
@click.option('-fa', '--forced-audio', type=int, help='Index of forced audio stream (including default audio stream tag)')
@click.option('-da', '--default-audio', type=int, help='Index of default audio stream')
@click.option('-fa', '--forced-audio', type=int, default=-1, help='Index of forced audio stream (including default audio stream tag)')
@click.option('-da', '--default-audio', type=int, default=-1, help='Index of default audio stream')
@click.option("--crop", is_flag=False, flag_value="default", default="none")
@ -384,10 +422,12 @@ def streams(filename):
@click.option("-c", "--clear-metadata", is_flag=True, default=False)
@click.option("-d", "--denoise", is_flag=True, default=False)
@click.option("-j", "--no-jellyfin-tweaks", is_flag=True, default=False)
@click.option("--dry-run", is_flag=True, default=False)
def convert(ctx, paths, label, video_encoder, quality, preset, stereo_bitrate, ac3_bitrate, dts_bitrate, default_subtitle, forced_audio, default_audio, crop, output_directory, clear_metadata, denoise, dry_run):
def convert(ctx, paths, label, video_encoder, quality, preset, stereo_bitrate, ac3_bitrate, dts_bitrate, default_subtitle, forced_audio, default_audio, crop, output_directory, clear_metadata, denoise, no_jellyfin_tweaks, dry_run):
"""Batch conversion of audiovideo files in format suitable for web playback, e.g. jellyfin
Files found under PATHS will be converted according to parameters.
@ -483,6 +523,7 @@ def convert(ctx, paths, label, video_encoder, quality, preset, stereo_bitrate, a
print(f"season={season} episode={episode} file={file_index}")
# File specific tokens
targetFilenameTokens = []
targetFilenameExtension = DEFAULT_FILE_EXTENSION
@ -522,22 +563,34 @@ def convert(ctx, paths, label, video_encoder, quality, preset, stereo_bitrate, a
job_index += 1
mappingVideoTokens = ['-map', 'v:0']
mappingTokens = mappingVideoTokens.copy()
dispositionTokens = []
audioTokens = []
audioIndex = 0
for audioStreamDescriptor in streamDescriptor[STREAM_TYPE_AUDIO]:
mappingTokens += ['-map', f"a:{audioIndex}"]
audioTokens += generateAudioTokens(context, audioIndex, audioStreamDescriptor['layout'])
audioIndex += 1
if default_audio == -1:
sourceAudioStreams = streamDescriptor[STREAM_TYPE_AUDIO]
else:
sourceAudioStreams = getReorderedSubstreams(streamDescriptor[STREAM_TYPE_AUDIO], default_audio)
dispositionTokens += generateDispositionTokens(sourceAudioStreams)
if default_subtitle == -1:
sourceSubtitleStreams = streamDescriptor[STREAM_TYPE_SUBTITLE]
else:
sourceSubtitleStreams = getReorderedSubstreams(streamDescriptor[STREAM_TYPE_SUBTITLE], default_subtitle)
dispositionTokens += generateDispositionTokens(sourceSubtitleStreams)
subtitleIndex = 0
for subtitleStreamDescriptor in streamDescriptor[STREAM_TYPE_SUBTITLE]:
mappingTokens += ['-map', f"s:{subtitleIndex}"]
subtitleIndex += 1
for audioStream in sourceAudioStreams:
mappingTokens += ['-map', f"a:{audioStream['src_sub_index']}"]
audioTokens += generateAudioTokens(context, audioStream['src_sub_index'], audioStream['layout'])
for subtitleStream in sourceSubtitleStreams:
mappingTokens += ['-map', f"s:{subtitleStream['src_sub_index']}"]
# Job specific tokens
targetFilenameJobTokens = targetFilenameTokens.copy()
if len(q_list) > 1:
@ -552,10 +605,13 @@ def convert(ctx, paths, label, video_encoder, quality, preset, stereo_bitrate, a
click.echo(f"target filename: {targetFilename}")
if video_encoder == 'av1':
commandSequence = commandTokens + mappingTokens + audioTokens + generateAV1Tokens(q, preset) + audioTokens
commandSequence = (commandTokens
+ mappingTokens
+ dispositionTokens
+ audioTokens
+ generateAV1Tokens(q, preset) + audioTokens)
if clear_metadata:
commandSequence += generateClearTokens(streamDescriptor)
@ -589,7 +645,9 @@ def convert(ctx, paths, label, video_encoder, quality, preset, stereo_bitrate, a
executeProcess(commandSequence1)
commandSequence2 = commandTokens + mappingTokens
commandSequence2 = (commandTokens
+ mappingTokens
+ dispositionTokens)
if denoise:
commandSequence2 += generateDenoiseTokens()

Loading…
Cancel
Save