You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
3.7 KiB
132 lines
3.7 KiB
#!/usr/bin/env python3 |
|
""" |
|
xconv ffmpeg wrapper based on AdvancedAV |
|
----------------------------------------------------------- |
|
AdvancedAV helps with constructing FFmpeg commandline arguments. |
|
|
|
It can automatically parse input files with the help of FFmpeg's ffprobe tool (WiP) |
|
and allows programatically mapping streams to output files and setting metadata on them. |
|
----------------------------------------------------------- |
|
Copyright (c) 2015-2017 Taeyeon Mori |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
----------------------------------------------------------- |
|
Decorators for defining xconv profiles |
|
""" |
|
|
|
from .profileman import index, make_qname |
|
|
|
from functools import wraps |
|
|
|
|
|
__all__ = [ |
|
"profile", |
|
"description", |
|
"output", |
|
"defines", |
|
"features", |
|
"singleaudio" |
|
] |
|
|
|
|
|
# == Misc. helpers == |
|
def __update(f, name, update): |
|
if hasattr(f, name): |
|
getattr(f, name).update(update); |
|
else: |
|
setattr(f, name, update) |
|
|
|
def __defaults(obj, **defs): |
|
for k, v in defs.items(): |
|
if not hasattr(obj, k): |
|
setattr(obj, k, v) |
|
|
|
|
|
# == Profile Decorators == |
|
def profile(f): |
|
""" |
|
Define a XConv Profile |
|
|
|
Note: Should be outermost decorator |
|
""" |
|
__defaults(f, |
|
description=None, |
|
container=None, |
|
ext=None, |
|
defines={}, |
|
features={}) |
|
index[make_qname(f.__module__, f.__name__)] = f |
|
return f |
|
|
|
|
|
def description(desc): |
|
""" Add a profile description """ |
|
def apply(f): |
|
f.description = desc |
|
return f |
|
return apply |
|
|
|
|
|
def defines(**defs): |
|
""" Document supported defines with description """ |
|
def apply(f): |
|
__update(f, "defines", defs) |
|
return f |
|
return apply |
|
|
|
|
|
def features(**features): |
|
""" |
|
Set opaque feature flags |
|
|
|
Boolean flags are checked for existance, not actual value. |
|
|
|
Known flags: |
|
- output: Specifies type of the output file [(format, file-extension)] |
|
- argshax: Pass parsed cmdline arguments in 'args' kwd |
|
- singleaudio: Indicates that it operates on a single audio stream. No effects |
|
- no_single_output: Profile doesn't constitute a 1:1 file conversion. Don't use SimpleTask |
|
- skip_existing_output: omit any outputs that already exist. (i.e. always --update) |
|
- advanced_task: reserved |
|
""" |
|
def apply(f): |
|
__update(f, "features", features) |
|
return f |
|
return apply |
|
|
|
|
|
def output(container=None, ext=None): |
|
""" Add output file information """ |
|
return features(output=( |
|
container, |
|
ext if ext else "mkv" if container == "matroska" else container |
|
)) |
|
|
|
|
|
def singleaudio(profile): |
|
""" |
|
Operate on a single audio stream (The first one found) |
|
|
|
The stream will be passed to the decorated function in the "stream" keyword |
|
""" |
|
@wraps(profile) |
|
def wrapper(task, **kwds): |
|
try: |
|
audio_stream = next(task.iter_audio_streams()) |
|
except StopIteration: |
|
print("No audio track in '%s'" % "', '".join(map(lambda x: x.name, task.inputs))) |
|
return False |
|
return profile(task, stream=audio_stream, **kwds) |
|
__update(wrapper, "features", {"singleaudio": None}) |
|
return wrapper
|
|
|