Exemplo n.º 1
0
class OutputOptions(StreamOptions):
    @staticmethod
    def __convert_overwrite(overwrite):
        if isinstance(overwrite, bool) and not overwrite:
            raise InterruptedSetOption
        return overwrite

    @staticmethod
    def __video_filter(_filter: str):
        check_type(_filter, str)
        if _filter.endswith(","):
            _filter = _filter[:-1]
        return _filter

    def add_video_filter(self, _filter):
        check_type(_filter, str)

        if self.is_set(OutputOptions.video_filter):
            self.video_filter += f",{_filter}"
        else:
            self.video_filter = _filter

    video_filter = option("vf", type_filter(str))
    audio_filter = option("af", type_filter(str))
    frame_rate = option("r", type_filter((float, int)))
    overwrite = option("y", __convert_overwrite)
Exemplo n.º 2
0
class InputOptions(InputOptionsBase, StreamOptions):
    @staticmethod
    def format_video_size(size):
        check_type(size, tuple)
        width, height = size
        return f"{width}x{height}"

    video_size = option('video_size', format_video_size)
    frame_rate = option('r', min_value_filter(0))
Exemplo n.º 3
0
class Stream(Options):
    def __init__(self, codec=None, muxer=None):
        super().__init__()
        if codec is None:
            self.codec = Codec()
        else:
            self.codec = codec

        if muxer is None:
            self.muxer = Muxer()
        else:
            self.muxer = muxer

        self.__path = None

    @property
    def path(self):
        return self.__path

    @path.setter
    def path(self, path):
        self.__path = path

    def __repr__(self):
        _str = ""
        for k, v in self.build().items():
            _str += f"\n\t\"{k}\": "

            if isinstance(v, Options):
                _str += f"{v.__class__.__name__}"
                if v:
                    _str += f"({v.__str__()})"
                else:
                    _str += "(None)"
            else:
                _str += f"{v}"
        if not _str:
            _str = "None"
        return f"{self.__class__.__name__}: \"{self.path}\"{_str}\n"

    def build(self):
        args = []
        options = self.dict()
        for k in sorted(options):
            v = options[k]
            if isinstance(v, Options):
                v = convert_kwargs_to_cmd_line_args(v.dict())
                args.extend(v)
            else:
                args.append(f'-{k}')
                if v is not None:
                    args.append(f'{v}')
        return args

    codec = option("codecs", type_filter(Codec))
    muxer = option("muxers", type_filter(Muxer))
Exemplo n.º 4
0
class LibX265(LibX):
    codec = option(
        LibX.codec,
        in_list_filter(LibXCodec.HEVC,),
        LibXCodec.HEVC
    )

    x265_params = option(
        "x265-params",
        set_filter=set_opt,
        default_value=Params(),
        doc="Set x265 options. See x265 --help for a list of options."
    )
Exemplo n.º 5
0
class VideoEncoding(Video, Encoding):
    def __init__(self):
        for name, opt in self.options():
            if not getattr(Encoding, name, False):
                continue
            if opt.name.endswith(":v"):
                continue
            setattr(self.__class__, name, voption(opt))
        super().__init__()

    gop_size = option("g", min_value_filter(0), doc="GOP size (default: 12)")
    keyint_min = option("keyint_min",
                        type_filter(int),
                        doc="Set minimum interval between IDR-frames.")
    refs = option("refs",
                  type_filter(int),
                  doc="Reference frames to consider for motion compensation")
    brd_scale = option("brd_scale",
                       in_range_filter(0, 3),
                       doc="Downscale frames for dynamic B-frame decision.")
    chroma_offset = option("chromaoffset",
                           type_filter(int),
                           doc="Set chroma qp offset from luma.")
    mv0_threshold = option("mv0_threshold", min_value_filter(0))
    b_sensitivity = option("b_sensitivity",
                           min_value_filter(1),
                           doc="Adjust sensitivity of b_frame_strategy 1.")
    timecode_frame_start = option(
        "timecode_frame_start",
        min_value_filter(-1),
        doc="GOP timecode frame start number, in non-drop-frame format")
Exemplo n.º 6
0
class LibX264(LibX):
    codec = option(
        LibX.codec,
        in_list_filter(LibXCodec.AVC,),
        LibXCodec.AVC
    )

    x264opts = option(
        "x264opts",
        set_filter=set_opt,
        default_value=Params(),
        doc="Set any x264 option. see x264 --fullhelp"
    )

    nal_hrd = option(
        "nal-hrd",
        in_list_filter(NalHRD),
        doc="Set signal HRD information (requires vbv-bufsize to be set)"
    )
Exemplo n.º 7
0
class OutputStream(Stream, OutputOptions):
    def __init__(self, path=None, codec=None, muxer=None):
        if not codec:
            codec = EncodeVideo()

        if not muxer:
            muxer = Muxer()

        super().__init__(codec, muxer)
        self.path = path

    # self.maps = []
    # def multi_output(self, outputs):
    #     for output in outputs:
    # TODO: support multi IO stream. https://trac.ffmpeg.org/wiki/Creating%20multiple%20outputs
    # def map(self, stream, output):
    #     self.maps.append((stream, output))

    def build(self):
        cmd = super().build()
        cmd.append(self.path)
        return cmd

    @staticmethod
    def filter_encoder(encoder):
        if not isinstance(encoder, (EncodeVideo, str)):
            raise TypeError(f"Must be string or EncodeVideo.")

        if isinstance(encoder, str):
            encoder = get_encoder(encoder)
        return encoder

    @staticmethod
    def filter_muxer(muxer):
        if not isinstance(muxer, (str, Muxer)):
            raise TypeError(f"Must be string or Muxer.")

        if isinstance(muxer, str):
            muxer = get_demuxer(muxer)
        return muxer

    codec = option(Stream.codec.name, filter_encoder)
    muxer = option(Stream.muxer.name, filter_muxer)
Exemplo n.º 8
0
class Segment(Muxer):
    format = option(
        Muxer.format,
        in_list_filter([FormatMuxer.SEGMENT]),
        FormatMuxer.SEGMENT
    )
    segment_time = option("segment_time", min_value_filter(0))
    segment_format_options = option("segment_format_options", type_filter(str))
    segment_format = option("segment_format", in_list_filter(FormatMuxer.MP4))
    strftime = option("strftime", in_list_filter([1, 0, '1', '0']))
    reset_timestamps = option("reset_timestamps", in_list_filter((1, 0)))
    segment_atclocktime = option("segment_atclocktime", in_list_filter((1, 0)))
Exemplo n.º 9
0
class Nvenc(LibX):
    codec = option(LibX.codec, set_filter=in_list_filter(NvencCodec))

    rc = option(
        "rc",
        set_filter=in_list_filter(RateControl),
        doc="Override the preset rate-control (from -1 to INT_MAX) (default -1)"
    )

    preset = option("preset",
                    set_filter=in_list_filter(Preset),
                    doc="Set the encoding level restriction.")

    gpu = option("gpu", max_value_filter(number_of_gpus()))
    constant_quality = option("cq", in_range_filter(0, 51))
    strict_gop = option("strict_gop", type_filter(bool))
    zerolatency = option("zerolatency", type_filter(bool))
    cbr = option("cbr", type_filter(bool))
    two_pass = option("2pass", type_filter(bool))
Exemplo n.º 10
0
class MP4(Muxer):
    format = option(
        Muxer.format,
        in_list_filter([FormatMuxer.MOV, FormatMuxer.MP4, FormatMuxer.MPEGTS]),
        FormatMuxer.MP4,
        doc='MP4 muxers')
    movflags = option("movflags",
                      set_flags(MOVFlags),
                      Flags(limit_list=MOVFlags),
                      doc="MOV muxers flags")
    moov_size = option("moov_size", min_value_filter(0))
    frag_duration = option("frag_duration", min_value_filter(0))
    frag_size = option("frag_size", min_value_filter(0))
    min_frag_duration = option("min_frag_duration", min_value_filter(0))
    write_tmcd = option("write_tmcd")
    write_prft = option("write_prft")
Exemplo n.º 11
0
class RawVideo(Demuxer):
    """
    Raw video demuxer. Need framerate(=25), pixel_format(=yuv420p) and video_size to decode raw video data.
    """

    format = option(Demuxer.format,
                    set_filter=in_list_filter(FormatDemuxer.RAW_VIDEO, ),
                    default_value=FormatDemuxer.RAW_VIDEO,
                    doc='Raw video demuxer.')

    framerate = option("framerate",
                       set_filter=min_value_filter(1),
                       doc="Set input video frame rate. Default value is 25.")

    pixel_format = option(
        "pixel_format",
        set_filter=in_list_filter(PixelFormat),
        doc="Set the input video pixel format. Default value is `yuv420p`.")

    video_size = option(
        "video_size",
        set_filter=set_video_size,
        doc="Set the input video size. This value must be specified explicitly."
    )
Exemplo n.º 12
0
class V4L2(Muxer, Demuxer):
    format = option(
        Boxer.format,
        in_list_filter(Format.V4L2,),
        Format.V4L2
    )
Exemplo n.º 13
0
class Muxer(Boxer):
    format = option(Boxer.format, in_list_filter(FormatMuxer), doc='Muxer base')
    fflags = option("fflags", in_list_filter(FFlagsMuxer))
Exemplo n.º 14
0
class Demuxer(Boxer):
    format = option(Boxer.format, in_list_filter(FormatDemuxer), doc="Demuxer base")
    probesize = option('probesize', in_range_filter(32, 5000000))
    analyzeduration = option('analyzeduration', in_range_filter(0, 5000000))
    fflags = option("fflags", in_list_filter(FFlagsDemuxer))
Exemplo n.º 15
0
class Boxer(Options):
    format = option("f", in_list_filter(FormatMuxer), doc='Muxer/demuxer base')
    fflags = option("fflags", in_list_filter(FFlags))
Exemplo n.º 16
0
def aoption(opt):
    if not isinstance(opt, Option):
        raise TypeError("opt must be Option")
    return option(f"{opt.name}:a", opt.set_filter, opt.default_value, opt.doc)
Exemplo n.º 17
0
class HEVCDemuxer(Demuxer):
    format = option(Demuxer.format, in_list_filter(FormatDemuxer.HEVC, ),
                    FormatMuxer.HEVC)
Exemplo n.º 18
0
class FFmpeg(Options):
    """
    FFmpeg command builder

    Parameters
    ----------
    input_stream: InputStream
        Input stream setup

    Attributes
    ----------
    input_stream: InputStream
        Input stream setup

    output_streams: list of OutputStream
        Output stream setup
    """
    def __init__(self, input_stream, *output_streams):
        super().__init__()
        if not isinstance(input_stream, InputStream):
            raise TypeError(f"Required input_stream's type is `InputStream`.")

        self.input_stream = input_stream
        self.output_streams = []

        if output_streams:
            for output_stream in output_streams:
                self.add_output(output_stream)

        # Default setting
        self.hide_banner = None

    def __repr__(self):
        _str = f"{self.__class__.__name__}"
        _str += f"\n{self.input_stream!r}"
        for output_stream in self.output_streams:
            _str += f"\n{output_stream!r}"
        return _str

    @property
    def output_stream(self) -> OutputStream:
        if self.output_streams.__len__() < 1:
            raise ValueError("Output empty!")
        return self.output_streams[0]

    @property
    def source(self):
        return self.input_stream.path

    @source.setter
    def source(self, path):
        self.input_stream.path = path

    def build(self):
        cmd = [FFMPEG_CMD]
        cmd += convert_kwargs_to_cmd_line_args(self.dict())
        cmd += self.input_stream.build()
        for output_stream in self.output_streams:
            if hasattr(output_stream.codec, 'add_params'):
                output_stream.codec.add_params("log-level", self.loglevel)
            cmd += output_stream.build()
        return cmd

    def add_output(self, output_stream):
        check_type(output_stream, OutputStream)

        for output in self.output_streams:
            if output_stream.path == output.path:
                raise ValueError("Stream existed!")

        self.output_streams.append(output_stream)

    def run(self, stdin=None, stdout=None):
        """
        Create ffmpegpy subprocess with current settings
        call .build() to show current settings.
        """
        if self.output_streams.__len__() <= 0:
            raise RuntimeError("Not found any output stream.")

        args = self.build()

        for output_stream in self.output_streams:
            if output_stream.path == PIPE_LINE:
                stdout = Subprocess.PIPE if stdout is None else stdout

        stdin = Subprocess.PIPE if stdin is None else stdin
        return Subprocess(args, stdout=stdout, stdin=stdin)

    hide_banner = option("hide_banner", is_not_params_filter)
    loglevel = option("loglevel", in_list_filter(get_attr_values(LogLevel)))
Exemplo n.º 19
0
class LibX(VideoEncoding):
    """
    LibX of VideoLan. Only using for encoding video.
    CMD: ffmpegpy -hide_banner -h encoder=libx264

    Supported pixel formats: yuv420p yuvj420p yuv422p yuvj422p yuv444p yuvj444p nv12 nv16 nv21 yuv420p10le yuv422p10le
                             yuv444p10le nv20le gray gray10le
    """

    codec = option(
        VideoEncoding.codec,
        in_list_filter(LibXCodec)
    )

    preset = option(
        "preset",
        in_list_filter(Preset),
        doc="Use a preset to select encoding settings (default: medium)"
    )

    tune = option(
        "tune", in_list_filter(Tune),
        doc="Tune the settings for a particular type of source or situation"
    )

    profile = option(
        VideoEncoding.profile,
        in_list_filter(Profile),
        doc="Force the limits of an H.264 profile"
    )

    level = option(
        VideoEncoding.level,
        in_list_filter(LEVEL),
        doc="Specify level (as defined by Annex A)"
    )

    crf = option(
        "crf",
        in_range_filter(0, 51),
        doc="Constant Rate Factor. Select the quality for constant quality mode (0 (lossless) -> 51) (default 23)"
    )

    crf_max = option(
        "crf_max",
        in_range_filter(0, 51),
        doc="In CRF mode, prevents VBV from lowering quality beyond this point. "
            "(from 0 to 51) (default -1: not set)"
    )

    quantization_parameter = option("qp", doc="Constant quantization parameter rate control method")
    quantizer_min = option("qmin", doc="Minimum quantizer scale.")
    quantizer_max = option("qmax", doc="Maximum quantizer scale.")
    quantizer_diff = option("qdiff", doc="Maximum difference between quantizer scales.")
    quantizer_blur = option("qblur", doc="Quantizer curve blur")
    quantizer_compression = option("qcomp", doc="Quantizer curve compression factor")
    refs = option("refs", in_range_filter(1, 16))
    rc_lookahead = option("rc-lookahead", type_filter(int))
Exemplo n.º 20
0
class StreamOptions(Options):
    @staticmethod
    def convert_time(times):
        if isinstance(times, str):
            if len(times) > 8:
                raise ValueError("Time format: %H:%M:%s. Ex: 09:35:12")

            times = REGEX_TIME_FMT.search(times)
            if not bool(times):
                raise ValueError("Time format: %H:%M:%s. Ex: 09:35:12")
            hours, minutes, seconds = times.groups()
        else:
            hours, minutes, seconds = times

        hours = int(hours)
        if hours > 23:
            raise ValueError(
                f"Hour must in 24-hour military time. Got {hours}")

        minutes = int(minutes)
        if minutes > 60:
            raise ValueError(f"Minute must be standard. Got {minutes}")

        seconds = int(seconds)
        if seconds > 60:
            raise ValueError(f"Seconds must be standard. Got {seconds}")

        return f"{hours:02}:{minutes:02}:{seconds:02}"

    an = option("an", is_not_params_filter)
    dn = option("dn", is_not_params_filter)
    sn = option("sn", is_not_params_filter)
    vn = option("vn", is_not_params_filter)
    re = option('re', is_not_params_filter)
    video_sync = option('vsync', in_list_filter(VSync))
    audio_sync = option('async', min_value_filter(1))
    seek = option("ss", convert_time)
    to = option("to", convert_time)
    duration = option("t", min_value_filter(0))
    pix_fmt = option("pix_fmt", in_list_filter(PixelFormat))
Exemplo n.º 21
0
class H264Demuxer(Demuxer):
    format = option(Demuxer.format, in_list_filter(FormatDemuxer.H264, ),
                    FormatMuxer.H264)
Exemplo n.º 22
0
class NvencH264(Nvenc):
    codec = option(Nvenc.codec, in_list_filter(NvencCodec.H264, ),
                   NvencCodec.H264)
    profile = option(Nvenc.profile, in_list_filter(ProfileAVC))
Exemplo n.º 23
0
class InputStream(Stream, InputOptions, HWAccel):
    def __init__(self, path, codec=None, demuxer=None):
        if codec is None:
            codec = DecodeVideo()

        if demuxer is None:
            demuxer = Demuxer()

        super().__init__(codec, demuxer)
        self.path = path

    def build(self):
        cmd = super().build()
        cmd.append("-i")
        cmd.append(self.path)
        return cmd

    @property
    def path(self):
        return self.__path

    @path.setter
    def path(self, path):
        if isinstance(path, int) and sys.platform == "linux":
            path = f"{LINUX_DEVICE}{path}"

            if path.startswith(LINUX_DEVICE):
                self.muxer = V4L2()

            if self.is_existed(InputStream.codec):
                del self.codec
        elif isinstance(self.muxer, V4L2):
            self.muxer = Demuxer()

        if path.startswith("rtsp"):
            self.rtsp_transport = RTSPTransport.TCP
        elif self.is_existed(InputStream.rtsp_transport):
            del self.rtsp_transport

        self.__path = path

    def filter_decoder(self, decoder):
        if not isinstance(decoder, (DecodeVideo, str)):
            raise TypeError(f"Must be string or DecodeVideo.")

        if isinstance(decoder, str):
            decoder = get_decoder(decoder)
            self.hwaccel_device = HWAccelType.CUDA
            self.an = None
        elif self.is_existed(InputStream.hwaccel_device):
            del self.hwaccel_device
        return decoder

    @staticmethod
    def filter_demuxer(demuxer):
        if not isinstance(demuxer, (str, Demuxer)):
            raise TypeError(f"Must be string or Demuxer.")

        if isinstance(demuxer, str):
            demuxer = get_demuxer(demuxer)
        return demuxer

    codec = option(Stream.codec.name, filter_decoder)
    muxer = option(Stream.muxer.name, filter_demuxer)
Exemplo n.º 24
0
class NvencH265(Nvenc):
    codec = option(Nvenc.codec, in_list_filter(NvencCodec.H265, ),
                   NvencCodec.H265)
    profile = option(Nvenc.profile, in_list_filter(ProfileHEVC))
Exemplo n.º 25
0
class MP4Demuxer(Demuxer):
    format = option(Demuxer.format,
                    in_list_filter(FormatDemuxer.MP4, ),
                    FormatDemuxer.MP4,
                    doc='MP4 demuxer')