示例#1
0
    def video_encode(self, encoding, image, options):
        """
            This method is used by make_data_packet to encode frames using video encoders.
            Video encoders only deal with fixed dimensions,
            so we must clean and reinitialize the encoder if the window dimensions
            has changed.
            Since this runs in the non-UI thread 'data_to_packet', we must
            use the '_lock' to prevent races.
        """
        debug("video_encode%s", (encoding, image, options))
        x, y, w, h = image.get_geometry()[:4]
        assert x==0 and y==0, "invalid position: %s,%s" % (x,y)
        src_format = image.get_pixel_format()
        try:
            self._lock.acquire()
            if not self.check_pipeline(encoding, w, h, src_format):
                raise Exception("failed to setup a video pipeline for %s encoding with source format %s" % (encoding, src_format))

            #dw and dh are the edges we don't handle here
            width = w & self.width_mask
            height = h & self.height_mask
            debug("video_encode%s wxh=%s-%s, widthxheight=%sx%s", (encoding, image, options), w, h, width, height)

            csc_image, csc, enc_width, enc_height = self.csc_image(image, width, height)

            start = time.time()
            data, client_options = self._video_encoder.compress_image(csc_image, options)
            end = time.time()

            if csc_image is image:
                #no csc step, so the image comes from the UI server
                #and must be freed in the UI thread:
                self.idle_add(csc_image.free)
            else:
                #csc temporary images can be freed at will
                csc_image.free()
            del csc_image

            if data is None:
                log.error("video_encode: ouch, %s compression failed", encoding)
                return None, None, 0
            if self.encoding_client_options:
                #tell the client which colour subsampling we used:
                #(note: see csc_equiv!)
                if self.uses_csc_atoms:
                    client_options["csc"] = self.csc_equiv(csc)
                else:
                    #ugly hack: expose internal ffmpeg/libav constant
                    #for old versions without the "csc_atoms" feature:
                    client_options["csc_pixel_format"] = get_avutil_enum_from_colorspace(csc)
                #tell the client about scaling (the size of the encoded picture):
                #(unless the video encoder has already done so):
                if self._csc_encoder and ("scaled_size" not in client_options) and (enc_width!=width or enc_height!=height):
                    client_options["scaled_size"] = enc_width, enc_height
            debug("video_encode encoder: %s %sx%s result is %s bytes (%.1f MPixels/s), client options=%s",
                                encoding, enc_width, enc_height, len(data), (enc_width*enc_height/(end-start+0.000001)/1024.0/1024.0), client_options)
            return self._video_encoder.get_encoding(), Compressed(encoding, data), client_options, width, height, 0, 24
        finally:
            self._lock.release()
示例#2
0
    def __init__(self, *args):
        WindowSource.__init__(self, *args)
        #client uses uses_swscale (has extra limits on sizes)
        self.uses_swscale = self.encoding_options.get("uses_swscale", True)
        self.uses_csc_atoms = self.encoding_options.get("csc_atoms", False)
        self.video_scaling = self.encoding_options.get("video_scaling", False)
        self.video_reinit = self.encoding_options.get("video_reinit", False)
        if not self.encoding_client_options:
            #old clients can only use 420P:
            def_csc_modes = ("YUV420P")
        else:
            #default for newer clients that don't specify "csc_modes":
            def_csc_modes = ("YUV420P", "YUV422P", "YUV444P")
        #0.10 onwards should have specified csc_modes:
        self.csc_modes = self.encoding_options.get("csc_modes", def_csc_modes)

        self.video_encodings = ("vp8", "vp9", "h264")
        for x in self.video_encodings:
            if x in self.server_core_encodings:
                self._encoders[x] = self.video_encode

        #these constraints get updated with real values
        #when we construct the video pipeline:
        self.min_w = 1
        self.min_h = 1
        self.max_w = 16384
        self.max_h = 16384
        self.width_mask = 0xFFFF
        self.height_mask = 0xFFFF
        self.actual_scaling = (1, 1)

        self._csc_encoder = None
        self._video_encoder = None
        self._lock = Lock(
        )  #to ensure we serialize access to the encoder and its internals

        self.last_pipeline_params = None
        self.last_pipeline_scores = []
        self.video_helper = getVideoHelper()
        if self.encoding_options.get("proxy.video", False):
            #if we "proxy video", we will modify the video helper to add
            #new encoders, so we must make a deep copy to preserve the original:
            self.video_helper = getVideoHelper().clone(deep=True)
            #enabling video proxy:
            try:
                self.parse_proxy_video()
            except:
                log.error("failed to parse proxy video", exc_info=True)
示例#3
0
    def __init__(self, *args):
        WindowSource.__init__(self, *args)
        #client uses uses_swscale (has extra limits on sizes)
        self.uses_swscale = self.encoding_options.get("uses_swscale", True)
        self.uses_csc_atoms = self.encoding_options.get("csc_atoms", False)
        self.video_scaling = self.encoding_options.get("video_scaling", False)
        self.video_reinit = self.encoding_options.get("video_reinit", False)
        if not self.encoding_client_options:
            #old clients can only use 420P:
            def_csc_modes = ("YUV420P")
        else:
            #default for newer clients that don't specify "csc_modes":
            def_csc_modes = ("YUV420P", "YUV422P", "YUV444P")
        #0.10 onwards should have specified csc_modes:
        self.csc_modes = self.encoding_options.get("csc_modes", def_csc_modes)

        self.video_encodings = ("vp8", "vp9", "h264")
        for x in self.video_encodings:
            if x in self.server_core_encodings:
                self._encoders[x] = self.video_encode

        #these constraints get updated with real values
        #when we construct the video pipeline:
        self.min_w = 1
        self.min_h = 1
        self.max_w = 16384
        self.max_h = 16384
        self.width_mask = 0xFFFF
        self.height_mask = 0xFFFF
        self.actual_scaling = (1, 1)

        self._csc_encoder = None
        self._video_encoder = None
        self._lock = Lock()               #to ensure we serialize access to the encoder and its internals

        self.last_pipeline_params = None
        self.last_pipeline_scores = []
        self.video_helper = getVideoHelper()
        if self.encoding_options.get("proxy.video", False):
            #if we "proxy video", we will modify the video helper to add
            #new encoders, so we must make a deep copy to preserve the original:
            self.video_helper = getVideoHelper().clone(deep=True)
            #enabling video proxy:
            try:
                self.parse_proxy_video()
            except:
                log.error("failed to parse proxy video", exc_info=True)
示例#4
0
    def video_encode(self, encoding, image, options):
        """
            This method is used by make_data_packet to encode frames using video encoders.
            Video encoders only deal with fixed dimensions,
            so we must clean and reinitialize the encoder if the window dimensions
            has changed.
            Since this runs in the non-UI thread 'data_to_packet', we must
            use the '_lock' to prevent races.
        """
        debug("video_encode%s", (encoding, image, options))
        x, y, w, h = image.get_geometry()[:4]
        assert x == 0 and y == 0, "invalid position: %s,%s" % (x, y)
        src_format = image.get_pixel_format()
        try:
            self._lock.acquire()
            if not self.check_pipeline(encoding, w, h, src_format):
                raise Exception(
                    "failed to setup a video pipeline for %s encoding with source format %s"
                    % (encoding, src_format))

            #dw and dh are the edges we don't handle here
            width = w & self.width_mask
            height = h & self.height_mask
            debug("video_encode%s wxh=%s-%s, widthxheight=%sx%s",
                  (encoding, image, options), w, h, width, height)

            csc_image, csc, enc_width, enc_height = self.csc_image(
                image, width, height)

            start = time.time()
            data, client_options = self._video_encoder.compress_image(
                csc_image, options)
            end = time.time()

            if csc_image is image:
                #no csc step, so the image comes from the UI server
                #and must be freed in the UI thread:
                self.idle_add(csc_image.free)
            else:
                #csc temporary images can be freed at will
                csc_image.free()
            del csc_image

            if data is None:
                log.error("video_encode: ouch, %s compression failed",
                          encoding)
                return None, None, 0
            if self.encoding_client_options:
                #tell the client which colour subsampling we used:
                #(note: see csc_equiv!)
                if self.uses_csc_atoms:
                    client_options["csc"] = self.csc_equiv(csc)
                else:
                    #ugly hack: expose internal ffmpeg/libav constant
                    #for old versions without the "csc_atoms" feature:
                    client_options[
                        "csc_pixel_format"] = get_avutil_enum_from_colorspace(
                            csc)
                #tell the client about scaling (the size of the encoded picture):
                #(unless the video encoder has already done so):
                if self._csc_encoder and ("scaled_size" not in client_options
                                          ) and (enc_width != width
                                                 or enc_height != height):
                    client_options["scaled_size"] = enc_width, enc_height
            debug(
                "video_encode encoder: %s %sx%s result is %s bytes (%.1f MPixels/s), client options=%s",
                encoding, enc_width, enc_height, len(data),
                (enc_width * enc_height /
                 (end - start + 0.000001) / 1024.0 / 1024.0), client_options)
            return self._video_encoder.get_type(), Compressed(
                encoding, data), client_options, width, height, 0, 24
        finally:
            self._lock.release()