예제 #1
0
    def export(self):

        # $ dpkg -L openshot-qt | grep export
        # /usr/lib/python3/dist-packages/openshot_qt/windows/export.py
        # /usr/lib/python3/dist-packages/openshot_qt/windows/ui/export.ui

        # Set MaxSize (so we don't have any downsampling)
        #self.timeline.SetMaxSize(video_settings.get("width"), video_settings.get("height"))

        # Set lossless cache settings (temporarily)
        export_cache_object = openshot.CacheMemory(250)
        self.timeline.SetCache(export_cache_object)

        export_file_path = THE_EXPORT_FILE_PATH

        #print(self.timeline.Json())

        #sys.exit(0)

        # /usr/share/doc/libopenshot-doc/html/classopenshot_1_1FFmpegWriter.html
        try:
            w = openshot.FFmpegWriter(export_file_path)

            w.SetVideoOptions(True, "libvpx", openshot.Fraction(24,
                                                                1), 720, 480,
                              openshot.Fraction(1, 1), False, False, 300000)

            w.SetAudioOptions(True, "libvorbis", 44100, 2, 3, 128000)

            # Open the writer
            w.Open()

            #240 = 24fps x 10s;
            #300 = 30fps x 10s;
            for frame in range(1, 240):
                w.WriteFrame(self.timeline.GetFrame(frame))

            # Close writer
            w.Close()
        except Exception as e:
            print(e)
예제 #2
0
    def accept(self):
        """ Start exporting video """

        # Disable controls
        self.txtFileName.setEnabled(False)
        self.txtExportFolder.setEnabled(False)
        self.tabWidget.setEnabled(False)
        self.export_button.setEnabled(False)
        self.exporting = True

        # Determine final exported file path
        file_name_with_ext = "%s.%s" % (self.txtFileName.text().strip(),
                                        self.txtVideoFormat.text().strip())
        export_file_path = os.path.join(self.txtExportFolder.text().strip(),
                                        file_name_with_ext)
        log.info(export_file_path)

        # Translate object
        _ = get_app()._tr

        # Handle exception
        if os.path.exists(export_file_path):
            # File already exists! Prompt user
            ret = QMessageBox.question(
                self, _("Export Video"),
                _("%s already exists.\nDo you want to replace it?") %
                file_name_with_ext, QMessageBox.No | QMessageBox.Yes)
            if ret == QMessageBox.No:
                # Stop and don't do anything
                # Re-enable controls
                self.txtFileName.setEnabled(True)
                self.txtExportFolder.setEnabled(True)
                self.tabWidget.setEnabled(True)
                self.export_button.setEnabled(True)
                self.exporting = False
                return

        # Init export settings
        video_settings = {
            "vformat":
            self.txtVideoFormat.text(),
            "vcodec":
            self.txtVideoCodec.text(),
            "fps": {
                "num": self.txtFrameRateNum.value(),
                "den": self.txtFrameRateDen.value()
            },
            "width":
            self.txtWidth.value(),
            "height":
            self.txtHeight.value(),
            "pixel_ratio": {
                "num": self.txtPixelRatioNum.value(),
                "den": self.txtPixelRatioDen.value()
            },
            "video_bitrate":
            int(self.convert_to_bytes(self.txtVideoBitRate.text())),
            "start_frame":
            self.txtStartFrame.value(),
            "end_frame":
            self.txtEndFrame.value() + 1
        }

        audio_settings = {
            "acodec":
            self.txtAudioCodec.text(),
            "sample_rate":
            self.txtSampleRate.value(),
            "channels":
            self.txtChannels.value(),
            "channel_layout":
            self.cboChannelLayout.currentData(),
            "audio_bitrate":
            int(self.convert_to_bytes(self.txtAudioBitrate.text()))
        }

        # Set lossless cache settings (temporarily)
        export_cache_object = openshot.CacheMemory(250)
        self.timeline.SetCache(export_cache_object)

        # Create FFmpegWriter
        try:
            w = openshot.FFmpegWriter(export_file_path)

            # Set video options
            w.SetVideoOptions(
                True, video_settings.get("vcodec"),
                openshot.Fraction(
                    video_settings.get("fps").get("num"),
                    video_settings.get("fps").get("den")),
                video_settings.get("width"), video_settings.get("height"),
                openshot.Fraction(
                    video_settings.get("pixel_ratio").get("num"),
                    video_settings.get("pixel_ratio").get("den")), False,
                False, video_settings.get("video_bitrate"))

            # Set audio options
            w.SetAudioOptions(True, audio_settings.get("acodec"),
                              audio_settings.get("sample_rate"),
                              audio_settings.get("channels"),
                              audio_settings.get("channel_layout"),
                              audio_settings.get("audio_bitrate"))

            # Open the writer
            w.Open()

            # Notify window of export started
            get_app().window.ExportStarted.emit(
                export_file_path, video_settings.get("start_frame"),
                video_settings.get("end_frame"))

            # Write each frame in the selected range
            for frame in range(video_settings.get("start_frame"),
                               video_settings.get("end_frame")):
                # Update progress bar (emit signal to main window)
                get_app().window.ExportFrame.emit(
                    export_file_path, video_settings.get("start_frame"),
                    video_settings.get("end_frame"), frame)

                # Process events (to show the progress bar moving)
                QCoreApplication.processEvents()

                # Write the frame object to the video
                w.WriteFrame(self.timeline.GetFrame(frame))

                # Check if we need to bail out
                if not self.exporting:
                    break

            # Close writer
            w.Close()

        except Exception as e:
            # TODO: Find a better way to catch the error. This is the only way I have found that
            # does not throw an error
            error_type_str = str(e)
            log.info("Error type string: %s" % error_type_str)

            if "InvalidChannels" in error_type_str:
                log.info("Error setting invalid # of channels (%s)" %
                         (audio_settings.get("channels")))
                track_metric_error("invalid-channels-%s-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec"),
                                    audio_settings.get("channels")))

            elif "InvalidSampleRate" in error_type_str:
                log.info("Error setting invalid sample rate (%s)" %
                         (audio_settings.get("sample_rate")))
                track_metric_error("invalid-sample-rate-%s-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec"),
                                    audio_settings.get("sample_rate")))

            elif "InvalidFormat" in error_type_str:
                log.info("Error setting invalid format (%s)" %
                         (video_settings.get("vformat")))
                track_metric_error("invalid-format-%s" %
                                   (video_settings.get("vformat")))

            elif "InvalidCodec" in error_type_str:
                log.info("Error setting invalid codec (%s/%s/%s)" %
                         (video_settings.get("vformat"),
                          video_settings.get("vcodec"),
                          audio_settings.get("acodec")))
                track_metric_error("invalid-codec-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec")))

            elif "ErrorEncodingVideo" in error_type_str:
                log.info("Error encoding video frame (%s/%s/%s)" %
                         (video_settings.get("vformat"),
                          video_settings.get("vcodec"),
                          audio_settings.get("acodec")))
                track_metric_error("video-encode-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec")))

            # Show friendly error
            friendly_error = error_type_str.split("> ")[0].replace("<", "")

            # Prompt error message
            msg = QMessageBox()
            _ = get_app()._tr
            msg.setWindowTitle(_("Export Error"))
            msg.setText(
                _("Sorry, there was an error exporting your video: \n%s") %
                friendly_error)
            msg.exec_()

        # Notify window of export started
        get_app().window.ExportEnded.emit(export_file_path)

        # Close timeline object
        self.timeline.Close()

        # Clear cache
        export_cache_object.Clear()

        # Accept dialog
        super(Export, self).accept()
예제 #3
0
    def accept(self):
        """ Start exporting video """

        # get translations
        app = get_app()
        _ = app._tr

        # Disable controls
        self.txtFileName.setEnabled(False)
        self.txtExportFolder.setEnabled(False)
        self.tabWidget.setEnabled(False)
        self.export_button.setEnabled(False)
        self.exporting = True

        # Determine type of export (video+audio, video, audio, image sequences)
        # _("Video & Audio"), _("Video Only"), _("Audio Only"), _("Image Sequence")
        export_type = self.cboExportTo.currentText()

        # Determine final exported file path
        if export_type != _("Image Sequence"):
            file_name_with_ext = "%s.%s" % (self.txtFileName.text().strip(),
                                            self.txtVideoFormat.text().strip())
        else:
            file_name_with_ext = "%s%s" % (self.txtFileName.text().strip(),
                                           self.txtImageFormat.text().strip())
        export_file_path = os.path.join(self.txtExportFolder.text().strip(),
                                        file_name_with_ext)
        log.info(export_file_path)

        # Translate object
        _ = get_app()._tr

        file = File.get(path=export_file_path)
        if file:
            ret = QMessageBox.question(
                self, _("Export Video"),
                _("%s is an input file.\nPlease choose a different name.") %
                file_name_with_ext, QMessageBox.Ok)
            self.txtFileName.setEnabled(True)
            self.txtExportFolder.setEnabled(True)
            self.tabWidget.setEnabled(True)
            self.export_button.setEnabled(True)
            self.exporting = False
            return

        # Handle exception
        if os.path.exists(export_file_path) and export_type in [
                _("Video & Audio"),
                _("Video Only"),
                _("Audio Only")
        ]:
            # File already exists! Prompt user
            ret = QMessageBox.question(
                self, _("Export Video"),
                _("%s already exists.\nDo you want to replace it?") %
                file_name_with_ext, QMessageBox.No | QMessageBox.Yes)
            if ret == QMessageBox.No:
                # Stop and don't do anything
                # Re-enable controls
                self.txtFileName.setEnabled(True)
                self.txtExportFolder.setEnabled(True)
                self.tabWidget.setEnabled(True)
                self.export_button.setEnabled(True)
                self.exporting = False
                return

        # Init export settings
        video_settings = {
            "vformat":
            self.txtVideoFormat.text(),
            "vcodec":
            self.txtVideoCodec.text(),
            "fps": {
                "num": self.txtFrameRateNum.value(),
                "den": self.txtFrameRateDen.value()
            },
            "width":
            self.txtWidth.value(),
            "height":
            self.txtHeight.value(),
            "pixel_ratio": {
                "num": self.txtPixelRatioNum.value(),
                "den": self.txtPixelRatioDen.value()
            },
            "video_bitrate":
            int(self.convert_to_bytes(self.txtVideoBitRate.text())),
            "start_frame":
            self.txtStartFrame.value(),
            "end_frame":
            self.txtEndFrame.value() + 1
        }

        audio_settings = {
            "acodec":
            self.txtAudioCodec.text(),
            "sample_rate":
            self.txtSampleRate.value(),
            "channels":
            self.txtChannels.value(),
            "channel_layout":
            self.cboChannelLayout.currentData(),
            "audio_bitrate":
            int(self.convert_to_bytes(self.txtAudioBitrate.text()))
        }

        # Override vcodec and format for Image Sequences
        if export_type == _("Image Sequence"):
            image_ext = os.path.splitext(
                self.txtImageFormat.text().strip())[1].replace(".", "")
            video_settings["vformat"] = image_ext
            if image_ext in ["jpg", "jpeg"]:
                video_settings["vcodec"] = "mjpeg"
            else:
                video_settings["vcodec"] = image_ext

        # Set MaxSize (so we don't have any downsampling)
        self.timeline.SetMaxSize(video_settings.get("width"),
                                 video_settings.get("height"))

        # Set lossless cache settings (temporarily)
        export_cache_object = openshot.CacheMemory(250)
        self.timeline.SetCache(export_cache_object)

        # Create FFmpegWriter
        try:
            w = openshot.FFmpegWriter(export_file_path)

            # Set video options
            if export_type in [
                    _("Video & Audio"),
                    _("Video Only"),
                    _("Image Sequence")
            ]:
                w.SetVideoOptions(
                    True, video_settings.get("vcodec"),
                    openshot.Fraction(
                        video_settings.get("fps").get("num"),
                        video_settings.get("fps").get("den")),
                    video_settings.get("width"), video_settings.get("height"),
                    openshot.Fraction(
                        video_settings.get("pixel_ratio").get("num"),
                        video_settings.get("pixel_ratio").get("den")), False,
                    False, video_settings.get("video_bitrate"))

            # Set audio options
            if export_type in [_("Video & Audio"), _("Audio Only")]:
                w.SetAudioOptions(True, audio_settings.get("acodec"),
                                  audio_settings.get("sample_rate"),
                                  audio_settings.get("channels"),
                                  audio_settings.get("channel_layout"),
                                  audio_settings.get("audio_bitrate"))

            # Open the writer
            w.Open()

            # Notify window of export started
            export_file_path = ""
            get_app().window.ExportStarted.emit(
                export_file_path, video_settings.get("start_frame"),
                video_settings.get("end_frame"))

            progressstep = max(
                1,
                round((video_settings.get("end_frame") -
                       video_settings.get("start_frame")) / 1000))
            start_time_export = time.time()
            start_frame_export = video_settings.get("start_frame")
            end_frame_export = video_settings.get("end_frame")
            # Write each frame in the selected range
            for frame in range(video_settings.get("start_frame"),
                               video_settings.get("end_frame")):
                # Update progress bar (emit signal to main window)
                if (frame % progressstep) == 0:
                    end_time_export = time.time()
                    if (((frame - start_frame_export) != 0) &
                        ((end_time_export - start_time_export) != 0)):
                        seconds_left = round(
                            (start_time_export - end_time_export) *
                            (frame - end_frame_export) /
                            (frame - start_frame_export))
                        fps_encode = ((frame - start_frame_export) /
                                      (end_time_export - start_time_export))
                        export_file_path = _(
                            "%(hours)d:%(minutes)02d:%(seconds)02d Remaining (%(fps)5.2f FPS)"
                        ) % {
                            'hours': seconds_left / 3600,
                            'minutes': (seconds_left / 60) % 60,
                            'seconds': seconds_left % 60,
                            'fps': fps_encode
                        }
                    get_app().window.ExportFrame.emit(
                        export_file_path, video_settings.get("start_frame"),
                        video_settings.get("end_frame"), frame)

                # Process events (to show the progress bar moving)
                QCoreApplication.processEvents()

                # Write the frame object to the video
                w.WriteFrame(self.timeline.GetFrame(frame))

                # Check if we need to bail out
                if not self.exporting:
                    break

            # Close writer
            w.Close()

        except Exception as e:
            # TODO: Find a better way to catch the error. This is the only way I have found that
            # does not throw an error
            error_type_str = str(e)
            log.info("Error type string: %s" % error_type_str)

            if "InvalidChannels" in error_type_str:
                log.info("Error setting invalid # of channels (%s)" %
                         (audio_settings.get("channels")))
                track_metric_error("invalid-channels-%s-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec"),
                                    audio_settings.get("channels")))

            elif "InvalidSampleRate" in error_type_str:
                log.info("Error setting invalid sample rate (%s)" %
                         (audio_settings.get("sample_rate")))
                track_metric_error("invalid-sample-rate-%s-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec"),
                                    audio_settings.get("sample_rate")))

            elif "InvalidFormat" in error_type_str:
                log.info("Error setting invalid format (%s)" %
                         (video_settings.get("vformat")))
                track_metric_error("invalid-format-%s" %
                                   (video_settings.get("vformat")))

            elif "InvalidCodec" in error_type_str:
                log.info("Error setting invalid codec (%s/%s/%s)" %
                         (video_settings.get("vformat"),
                          video_settings.get("vcodec"),
                          audio_settings.get("acodec")))
                track_metric_error("invalid-codec-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec")))

            elif "ErrorEncodingVideo" in error_type_str:
                log.info("Error encoding video frame (%s/%s/%s)" %
                         (video_settings.get("vformat"),
                          video_settings.get("vcodec"),
                          audio_settings.get("acodec")))
                track_metric_error("video-encode-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec")))

            # Show friendly error
            friendly_error = error_type_str.split("> ")[0].replace("<", "")

            # Prompt error message
            msg = QMessageBox()
            _ = get_app()._tr
            msg.setWindowTitle(_("Export Error"))
            msg.setText(
                _("Sorry, there was an error exporting your video: \n%s") %
                friendly_error)
            msg.exec_()

        # Notify window of export started
        get_app().window.ExportEnded.emit(export_file_path)

        # Close timeline object
        self.timeline.Close()

        # Clear all cache
        self.timeline.ClearAllCache()

        # Re-set OMP thread enabled flag
        if self.s.get("omp_threads_enabled"):
            os.environ['OS2_OMP_THREADS'] = "1"
        else:
            os.environ['OS2_OMP_THREADS'] = "0"

        # Accept dialog
        super(Export, self).accept()
예제 #4
0
    def accept(self):
        """ Start exporting video, but don't close window """
        # Get settings
        self.s = settings.get_settings()

        # Set lossless cache settings (temporarily)
        new_cache_object = openshot.CacheMemory(250)
        get_app().window.timeline_sync.timeline.SetCache(new_cache_object)
        # Clear old cache before it goes out of scope
        if get_app().window.cache_object:
            get_app().window.cache_object.Clear()
        # Update cache reference, so it doesn't go out of scope
        get_app().window.cache_object = new_cache_object

        # Disable controls
        self.txtFileName.setEnabled(False)
        self.txtExportFolder.setEnabled(False)
        self.tabWidget.setEnabled(False)
        self.export_button.setEnabled(False)
        self.exporting = True

        # Test Succeeded
        # Determine final exported file path
        file_name_with_ext = "%s.%s" % (self.txtFileName.text().strip(), self.txtVideoFormat.text().strip())
        export_file_path = os.path.join(self.txtExportFolder.text().strip(), file_name_with_ext)
        log.info(export_file_path)

        # Translate object
        _ = get_app()._tr

        # Handle exception
        if os.path.exists(export_file_path):
            # File already exists! Prompt user
            ret = QMessageBox.question(self, _("Export Video"), _("%s already exists.\nDo you want to replace it?") % file_name_with_ext,
                                       QMessageBox.No | QMessageBox.Yes)
            if ret == QMessageBox.No:
                # Stop and don't do anything
                # Re-enable controls
                self.txtFileName.setEnabled(True)
                self.txtExportFolder.setEnabled(True)
                self.tabWidget.setEnabled(True)
                self.export_button.setEnabled(True)
                self.exporting = False
                return

        # Create FFmpegWriter
        try:
            w = openshot.FFmpegWriter(export_file_path)

            # Set video options
            w.SetVideoOptions(True,
                              self.txtVideoCodec.text(),
                              openshot.Fraction(self.txtFrameRateNum.value(),
                                                self.txtFrameRateDen.value()),
                              self.txtWidth.value(),
                              self.txtHeight.value(),
                              openshot.Fraction(self.txtPixelRatioNum.value(),
                                                self.txtPixelRatioDen.value()),
                              False,
                              False,
                              int(self.convert_to_bytes(self.txtVideoBitRate.text())))

            # Set audio options
            w.SetAudioOptions(True,
                              self.txtAudioCodec.text(),
                              self.txtSampleRate.value(),
                              self.txtChannels.value(),
                              self.cboChannelLayout.currentData(),
                              int(self.convert_to_bytes(self.txtAudioBitrate.text())))

            # Open the writer
            w.Open()

            # Init progress bar
            self.progressExportVideo.setMinimum(self.txtStartFrame.value())
            self.progressExportVideo.setMaximum(self.txtEndFrame.value())

            # Write each frame in the selected range
            for frame in range(self.txtStartFrame.value(), self.txtEndFrame.value() + 1):
                # Update progress bar
                self.progressExportVideo.setValue(frame)
                # Process events (to show the progress bar moving)
                QCoreApplication.processEvents()

                # Write the frame object to the video
                w.WriteFrame(get_app().window.timeline_sync.timeline.GetFrame(frame))

                # Check if we need to bail out
                if not self.exporting:
                    break

            # Close writer
            w.Close()


        except Exception as e:
            # TODO: Find a better way to catch the error. This is the only way I have found that
            # does not throw an error
            error_type_str = str(e)
            log.info("Error type string: %s" % error_type_str)

            if "InvalidChannels" in error_type_str:
                log.info("Error setting invalid # of channels (%s)" % (self.txtChannels.value()))
                track_metric_error("invalid-channels-%s-%s-%s-%s" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text(), self.txtChannels.value()))

            elif "InvalidSampleRate" in error_type_str:
                log.info("Error setting invalid sample rate (%s)" % (self.txtSampleRate.value()))
                track_metric_error("invalid-sample-rate-%s-%s-%s-%s" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text(), self.txtSampleRate.value()))

            elif "InvalidFormat" in error_type_str:
                log.info("Error setting invalid format (%s)" % (self.txtVideoFormat.text()))
                track_metric_error("invalid-format-%s" % (self.txtVideoFormat.text()))

            elif "InvalidCodec" in error_type_str:
                log.info("Error setting invalid codec (%s/%s/%s)" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text()))
                track_metric_error("invalid-codec-%s-%s-%s" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text()))

            elif "ErrorEncodingVideo" in error_type_str:
                log.info("Error encoding video frame (%s/%s/%s)" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text()))
                track_metric_error("video-encode-%s-%s-%s" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text()))

            # Show friendly error
            friendly_error = error_type_str.split("> ")[0].replace("<", "")

            # Prompt error message
            msg = QMessageBox()
            _ = get_app()._tr
            msg.setWindowTitle(_("Export Error"))
            msg.setText(_("Sorry, there was an error exporting your video: \n%s") % friendly_error)
            msg.exec_()

        # Accept dialog
        super(Export, self).accept()

        # Restore timeline settings
        self.restoreTimeline()

        # Adjust cache settings back to normal
        get_app().window.InitCacheSettings()

        log.info("End Accept")
예제 #5
0
    def uploadSequence(self):
        """ Start exporting video """

        # get translations
        _ = get_app()._tr

        # Init progress bar
        # 应该仅仅是用来展示进度条
        # self.progressExportVideo.setMinimum(self.txtStartFrame.value())
        # self.progressExportVideo.setMaximum(self.txtEndFrame.value())
        # self.progressExportVideo.setValue(self.txtStartFrame.value())

        # 这个是默认的图片文件输出格式
        self.image_format = "-%05d.png"

        export_type = _("Image Sequence")

        # Determine final exported file path (and replace blank paths with default ones)
        default_filename = "IM"
        default_folder = os.path.join(info.HOME_PATH, 'Desktop/temp')
        # 如果要导出图片序列,就规定好导出文件的命名
        file_name_with_ext = "%s%s" % (default_filename,
                                       self.image_format.strip())

        # 确定导出文件的路径
        export_file_path = os.path.join(default_folder, file_name_with_ext)
        log.info("锁定了的文件保存路径: %s" % export_file_path)

        # Init export settings
        # 以下的设定全部都已经写死了
        video_settings = {
            "vformat": 'mp4',
            "vcodec": 'libx264',
            "fps": {
                "num": 25,
                "den": 1
            },
            "width": 1024,
            "height": 576,
            "pixel_ratio": {
                "num": 1,
                "den": 1
            },
            "video_bitrate": 15000000,
            "start_frame": 1,
            "end_frame": 17
        }

        audio_settings = {
            "acodec": 'aac',
            "sample_rate": 48000,
            "channels": 2,
            "channel_layout": 3,
            "audio_bitrate": 192000
        }

        # Override vcodec and format for Image Sequences
        image_ext = os.path.splitext(self.image_format.strip())[1].replace(
            ".", "")
        video_settings["vformat"] = image_ext
        if image_ext in ["jpg", "jpeg"]:
            video_settings["vcodec"] = "mjpeg"
        else:
            video_settings["vcodec"] = image_ext

        # Store updated export folder path in project file
        get_app().updates.update_untracked(["export_path"],
                                           os.path.dirname(export_file_path))
        # Mark project file as unsaved
        get_app().project.has_unsaved_changes = True

        # Set MaxSize (so we don't have any downsampling)
        self.timeline.SetMaxSize(video_settings.get("width"),
                                 video_settings.get("height"))

        # Set lossless cache settings (temporarily)
        export_cache_object = openshot.CacheMemory(500)
        self.timeline.SetCache(export_cache_object)

        # Rescale all keyframes (if needed)
        if self.export_fps_factor != 1.0:
            log.info("导出文件fps因子不为1")
            # Get a copy of rescaled project data (this does not modify the active project)
            rescaled_app_data = get_app().project.rescale_keyframes(
                self.export_fps_factor)

            # Load the "export" Timeline reader with the JSON from the real timeline
            self.timeline.SetJson(json.dumps(rescaled_app_data))

            # Re-update the timeline FPS again (since the timeline just got clobbered)
            self.updateFrameRate()

        # Create FFmpegWriter
        try:
            w = openshot.FFmpegWriter(export_file_path)

            # Set video options
            if export_type in [
                    _("Video & Audio"),
                    _("Video Only"),
                    _("Image Sequence")
            ]:
                w.SetVideoOptions(
                    True, video_settings.get("vcodec"),
                    openshot.Fraction(
                        video_settings.get("fps").get("num"),
                        video_settings.get("fps").get("den")),
                    video_settings.get("width"), video_settings.get("height"),
                    openshot.Fraction(
                        video_settings.get("pixel_ratio").get("num"),
                        video_settings.get("pixel_ratio").get("den")), False,
                    False, video_settings.get("video_bitrate"))

            # Prepare the streams
            w.PrepareStreams()

            # These extra options should be set in an extra method
            # No feedback is given to the user
            # TODO: Tell user if option is not available
            # Muxing options for mp4/mov
            w.SetOption(openshot.VIDEO_STREAM, "muxing_preset",
                        "mp4_faststart")
            # Set the quality in case crf was selected
            # if "crf" in self.txtVideoBitRate.text():
            #     w.SetOption(openshot.VIDEO_STREAM, "crf", str(int(video_settings.get("video_bitrate"))))
            # # Set the quality in case qp was selected
            # if "qp" in self.txtVideoBitRate.text():
            #     w.SetOption(openshot.VIDEO_STREAM, "qp", str(int(video_settings.get("video_bitrate"))))

            # Open the writer
            w.Open()

            # Notify window of export started
            title_message = ""
            get_app().window.ExportStarted.emit(
                export_file_path, video_settings.get("start_frame"),
                video_settings.get("end_frame"))

            progressstep = max(
                1,
                round((video_settings.get("end_frame") -
                       video_settings.get("start_frame")) / 1000))
            start_time_export = time.time()
            start_frame_export = video_settings.get("start_frame")
            end_frame_export = video_settings.get("end_frame")
            # Write each frame in the selected range
            # 接下来就是导出动作的重要内容
            for frame in range(video_settings.get("start_frame"),
                               video_settings.get("end_frame") + 1):
                # Update progress bar (emit signal to main window)
                if (frame % progressstep) == 0:
                    end_time_export = time.time()
                    if (((frame - start_frame_export) != 0) &
                        ((end_time_export - start_time_export) != 0)):
                        seconds_left = round(
                            (start_time_export - end_time_export) *
                            (frame - end_frame_export) /
                            (frame - start_frame_export))
                        fps_encode = ((frame - start_frame_export) /
                                      (end_time_export - start_time_export))
                        title_message = _(
                            "%(hours)d:%(minutes)02d:%(seconds)02d Remaining (%(fps)5.2f FPS)"
                        ) % {
                            'hours': seconds_left / 3600,
                            'minutes': (seconds_left / 60) % 60,
                            'seconds': seconds_left % 60,
                            'fps': fps_encode
                        }

                    # Emit frame exported
                    # get_app().window.ExportFrame.emit(title_message, video_settings.get("start_frame"), video_settings.get("end_frame"), frame)

                    # Process events (to show the progress bar moving)
                    # QCoreApplication.processEvents()

                # Write the frame object to the video
                w.WriteFrame(self.timeline.GetFrame(frame))

                # Check if we need to bail out
                # if not self.exporting:
                #     break

            # Close writer
            w.Close()

            # 下面的内容应该都是配合进度提示的,删除
            '''
            # Emit final exported frame (with elapsed time)
            seconds_run = round((end_time_export - start_time_export))
            title_message = _("%(hours)d:%(minutes)02d:%(seconds)02d Elapsed (%(fps)5.2f FPS)") % {
                'hours': seconds_run / 3600,
                'minutes': (seconds_run / 60) % 60,
                'seconds': seconds_run % 60,
                'fps': fps_encode}

            get_app().window.ExportFrame.emit(title_message, video_settings.get("start_frame"), video_settings.get("end_frame"), frame)
            '''

        except Exception as e:
            # TODO: Find a better way to catch the error. This is the only way I have found that
            # does not throw an error
            error_type_str = str(e)
            log.info("Error type string: %s" % error_type_str)

            if "InvalidChannels" in error_type_str:
                log.info("Error setting invalid # of channels (%s)" %
                         (audio_settings.get("channels")))
                track_metric_error("invalid-channels-%s-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec"),
                                    audio_settings.get("channels")))

            elif "InvalidSampleRate" in error_type_str:
                log.info("Error setting invalid sample rate (%s)" %
                         (audio_settings.get("sample_rate")))
                track_metric_error("invalid-sample-rate-%s-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec"),
                                    audio_settings.get("sample_rate")))

            elif "InvalidFormat" in error_type_str:
                log.info("Error setting invalid format (%s)" %
                         (video_settings.get("vformat")))
                track_metric_error("invalid-format-%s" %
                                   (video_settings.get("vformat")))

            elif "InvalidCodec" in error_type_str:
                log.info("Error setting invalid codec (%s/%s/%s)" %
                         (video_settings.get("vformat"),
                          video_settings.get("vcodec"),
                          audio_settings.get("acodec")))
                track_metric_error("invalid-codec-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec")))

            elif "ErrorEncodingVideo" in error_type_str:
                log.info("Error encoding video frame (%s/%s/%s)" %
                         (video_settings.get("vformat"),
                          video_settings.get("vcodec"),
                          audio_settings.get("acodec")))
                track_metric_error("video-encode-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec")))

            # Show friendly error
            friendly_error = error_type_str.split("> ")[0].replace("<", "")

            # Prompt error message
            msg = QMessageBox()
            msg.setWindowTitle(_("Export Error"))
            msg.setText(
                _("Sorry, there was an error exporting your video: \n%s") %
                friendly_error)
            msg.exec_()

        # Notify window of export started
        get_app().window.ExportEnded.emit(export_file_path)

        # Close timeline object
        self.timeline.Close()

        # Clear all cache
        self.timeline.ClearAllCache()

        # Re-set OMP thread enabled flag
        if self.s.get("omp_threads_enabled"):
            openshot.Settings.Instance().WAIT_FOR_VIDEO_PROCESSING_TASK = False
        else:
            openshot.Settings.Instance().WAIT_FOR_VIDEO_PROCESSING_TASK = True

        # Return scale mode to lower quality scaling (for faster previews)
        openshot.Settings.Instance().HIGH_QUALITY_SCALING = False

        # Handle end of export (for non-canceled exports)
        # if self.s.get("show_finished_window") and self.exporting:
        #     # Hide cancel and export buttons
        #     self.cancel_button.setVisible(False)
        #     self.export_button.setVisible(False)
        #
        #     # Reveal done button
        #     self.close_button.setVisible(True)
        #
        #     # Make progress bar green (to indicate we are done)
        #     # from PyQt5.QtGui import QPalette
        #     # p = QPalette()
        #     # p.setColor(QPalette.Highlight, Qt.green)
        #     # self.progressExportVideo.setPalette(p)
        #
        #     # Raise the window
        #     self.show()
        # else:
        #     # Accept dialog
        #     super(SuperResolution, self).accept()

        success_hint = QDialog()
        success_hint.setWindowTitle("成功")
        success_hint.exec_()
예제 #6
0
    def accept(self):
        """ Start exporting video """

        # get translations
        app = get_app()
        _ = app._tr

        # Disable controls
        self.txtFileName.setEnabled(False)
        self.txtExportFolder.setEnabled(False)
        self.tabWidget.setEnabled(False)
        self.export_button.setEnabled(False)
        self.exporting = True

        # Determine type of export (video+audio, video, audio, image sequences)
        # _("Video & Audio"), _("Video Only"), _("Audio Only"), _("Image Sequence")
        export_type = self.cboExportTo.currentText()

        # Determine final exported file path
        if export_type != _("Image Sequence"):
            file_name_with_ext = "%s.%s" % (self.txtFileName.text().strip(),
                                            self.txtVideoFormat.text().strip())
        else:
            file_name_with_ext = "%s%s" % (self.txtFileName.text().strip(),
                                           self.txtImageFormat.text().strip())
        export_file_path = os.path.join(self.txtExportFolder.text().strip(),
                                        file_name_with_ext)
        log.info(export_file_path)

        # Translate object
        _ = get_app()._tr

        file = File.get(path=export_file_path)
        if file:
            ret = QMessageBox.question(
                self, _("Export Video"),
                _("%s is an input file.\nPlease choose a different name.") %
                file_name_with_ext, QMessageBox.Ok)
            self.txtFileName.setEnabled(True)
            self.txtExportFolder.setEnabled(True)
            self.tabWidget.setEnabled(True)
            self.export_button.setEnabled(True)
            self.exporting = False
            return

        # Handle exception
        if os.path.exists(export_file_path) and export_type in [
                _("Video & Audio"),
                _("Video Only"),
                _("Audio Only")
        ]:
            # File already exists! Prompt user
            ret = QMessageBox.question(
                self, _("Export Video"),
                _("%s already exists.\nDo you want to replace it?") %
                file_name_with_ext, QMessageBox.No | QMessageBox.Yes)
            if ret == QMessageBox.No:
                # Stop and don't do anything
                # Re-enable controls
                self.txtFileName.setEnabled(True)
                self.txtExportFolder.setEnabled(True)
                self.tabWidget.setEnabled(True)
                self.export_button.setEnabled(True)
                self.exporting = False
                return

        # Init export settings
        video_settings = {
            "vformat":
            self.txtVideoFormat.text(),
            "vcodec":
            self.txtVideoCodec.text(),
            "fps": {
                "num": self.txtFrameRateNum.value(),
                "den": self.txtFrameRateDen.value()
            },
            "width":
            self.txtWidth.value(),
            "height":
            self.txtHeight.value(),
            "pixel_ratio": {
                "num": self.txtPixelRatioNum.value(),
                "den": self.txtPixelRatioDen.value()
            },
            "video_bitrate":
            int(self.convert_to_bytes(self.txtVideoBitRate.text())),
            "start_frame":
            self.txtStartFrame.value(),
            "end_frame":
            self.txtEndFrame.value() + 1
        }

        audio_settings = {
            "acodec":
            self.txtAudioCodec.text(),
            "sample_rate":
            self.txtSampleRate.value(),
            "channels":
            self.txtChannels.value(),
            "channel_layout":
            self.cboChannelLayout.currentData(),
            "audio_bitrate":
            int(self.convert_to_bytes(self.txtAudioBitrate.text()))
        }

        # Override vcodec and format for Image Sequences
        if export_type == _("Image Sequence"):
            image_ext = os.path.splitext(
                self.txtImageFormat.text().strip())[1].replace(".", "")
            video_settings["vformat"] = image_ext
            if image_ext in ["jpg", "jpeg"]:
                video_settings["vcodec"] = "mjpeg"
            else:
                video_settings["vcodec"] = image_ext

        # Set MaxSize (so we don't have any downsampling)
        self.timeline.SetMaxSize(video_settings.get("width"),
                                 video_settings.get("height"))

        # Set lossless cache settings (temporarily)
        export_cache_object = openshot.CacheMemory(250)
        self.timeline.SetCache(export_cache_object)

        # Rescale all keyframes and reload project
        if self.export_fps_factor != 1.0:
            self.keyframes_rescaled = True
            get_app().project.rescale_keyframes(self.export_fps_factor)

            # Load the "export" Timeline reader with the JSON from the real timeline
            json_timeline = json.dumps(get_app().project._data)
            self.timeline.SetJson(json_timeline)

            # Re-update the timeline FPS again (since the timeline just got clobbered)
            self.updateFrameRate()

        # Create FFmpegWriter
        try:
            w = openshot.FFmpegWriter(export_file_path)

            # Set video options
            if export_type in [
                    _("Video & Audio"),
                    _("Video Only"),
                    _("Image Sequence")
            ]:
                w.SetVideoOptions(
                    True, video_settings.get("vcodec"),
                    openshot.Fraction(
                        video_settings.get("fps").get("num"),
                        video_settings.get("fps").get("den")),
                    video_settings.get("width"), video_settings.get("height"),
                    openshot.Fraction(
                        video_settings.get("pixel_ratio").get("num"),
                        video_settings.get("pixel_ratio").get("den")), False,
                    False, video_settings.get("video_bitrate"))

            # Set audio options
            if export_type in [_("Video & Audio"), _("Audio Only")]:
                w.SetAudioOptions(True, audio_settings.get("acodec"),
                                  audio_settings.get("sample_rate"),
                                  audio_settings.get("channels"),
                                  audio_settings.get("channel_layout"),
                                  audio_settings.get("audio_bitrate"))

            # Prepare the streams
            w.PrepareStreams()

            # These extra options should be set in an extra method
            # No feedback is given to the user
            # TODO: Tell user if option is not avaliable
            # Set the quality in case crf was selected
            if "crf" in self.txtVideoBitRate.text():
                w.SetOption(openshot.VIDEO_STREAM, "crf",
                            str(int(video_settings.get("video_bitrate"))))

            # Open the writer
            w.Open()

            # Notify window of export started
            export_file_path = ""
            get_app().window.ExportStarted.emit(
                export_file_path, video_settings.get("start_frame"),
                video_settings.get("end_frame"))
            '''
            progressstep = max(1 , round(( video_settings.get("end_frame") - video_settings.get("start_frame") ) / 1000))
            start_time_export = time.time()
            start_frame_export = video_settings.get("start_frame")
            end_frame_export = video_settings.get("end_frame")
            # Write each frame in the selected range
            for frame in range(video_settings.get("start_frame"), video_settings.get("end_frame")):
                # Update progress bar (emit signal to main window)
                if (frame % progressstep) == 0:
                    end_time_export = time.time()
                    if ((( frame - start_frame_export ) != 0) & (( end_time_export - start_time_export ) != 0)):
                        seconds_left = round(( start_time_export - end_time_export )*( frame - end_frame_export )/( frame - start_frame_export ))
                        fps_encode = ((frame - start_frame_export)/(end_time_export-start_time_export))
                        export_file_path =  _("%(hours)d:%(minutes)02d:%(seconds)02d Remaining (%(fps)5.2f FPS)") % { 'hours' : seconds_left / 3600,
                                                                                                                      'minutes': (seconds_left / 60) % 60,
                                                                                                                      'seconds': seconds_left % 60,
                                                                                                                      'fps': fps_encode }
                    get_app().window.ExportFrame.emit(export_file_path, video_settings.get("start_frame"), video_settings.get("end_frame"), frame)

                # Process events (to show the progress bar moving)
                QCoreApplication.processEvents()

                # Write the frame object to the video
                w.WriteFrame(self.timeline.GetFrame(frame))

                # Check if we need to bail out
                if not self.exporting:
                    break
            '''
            print("====cuts====", self.cuts)
            fps_num = float(video_settings.get("fps").get("num"))
            fps_den = float(video_settings.get("fps").get("den"))

            for cut in self.cuts:
                start_frame_export = round(
                    float(cut["start"]) * fps_num / fps_den) - 1
                end_frame_export = round(
                    float(cut["end"]) * fps_num / fps_den) + 1
                progressstep = max(
                    1,
                    round(end_frame_export - start_frame_export) / 1000)
                start_time_export = time.time()
                # Write each frame in the selected range
                for frame in range(start_frame_export, end_frame_export + 1):
                    print("---frame:", frame)
                    # Update progress bar (emit signal to main window)
                    if (frame % progressstep) == 0:
                        end_time_export = time.time()
                        if (((frame - start_frame_export) != 0) &
                            ((end_time_export - start_time_export) != 0)):
                            seconds_left = round(
                                (start_time_export - end_time_export) *
                                (frame - end_frame_export) /
                                (frame - start_frame_export))
                            fps_encode = (
                                (frame - start_frame_export) /
                                (end_time_export - start_time_export))
                            export_file_path = _(
                                "%(hours)d:%(minutes)02d:%(seconds)02d Remaining (%(fps)5.2f FPS)"
                            ) % {
                                'hours': seconds_left / 3600,
                                'minutes': (seconds_left / 60) % 60,
                                'seconds': seconds_left % 60,
                                'fps': fps_encode
                            }
                        get_app().window.ExportFrame.emit(
                            export_file_path, start_frame_export,
                            end_frame_export, frame)

                    # Process events (to show the progress bar moving)
                    QCoreApplication.processEvents()

                    # Write the frame object to the video
                    w.WriteFrame(self.timeline.GetFrame(frame))

                    # Check if we need to bail out
                    if not self.exporting:
                        break

            # Close writer
            w.Close()

        except Exception as e:
            # TODO: Find a better way to catch the error. This is the only way I have found that
            # does not throw an error
            error_type_str = str(e)
            log.info("Error type string: %s" % error_type_str)

            if "InvalidChannels" in error_type_str:
                log.info("Error setting invalid # of channels (%s)" %
                         (audio_settings.get("channels")))
                track_metric_error("invalid-channels-%s-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec"),
                                    audio_settings.get("channels")))

            elif "InvalidSampleRate" in error_type_str:
                log.info("Error setting invalid sample rate (%s)" %
                         (audio_settings.get("sample_rate")))
                track_metric_error("invalid-sample-rate-%s-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec"),
                                    audio_settings.get("sample_rate")))

            elif "InvalidFormat" in error_type_str:
                log.info("Error setting invalid format (%s)" %
                         (video_settings.get("vformat")))
                track_metric_error("invalid-format-%s" %
                                   (video_settings.get("vformat")))

            elif "InvalidCodec" in error_type_str:
                log.info("Error setting invalid codec (%s/%s/%s)" %
                         (video_settings.get("vformat"),
                          video_settings.get("vcodec"),
                          audio_settings.get("acodec")))
                track_metric_error("invalid-codec-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec")))

            elif "ErrorEncodingVideo" in error_type_str:
                log.info("Error encoding video frame (%s/%s/%s)" %
                         (video_settings.get("vformat"),
                          video_settings.get("vcodec"),
                          audio_settings.get("acodec")))
                track_metric_error("video-encode-%s-%s-%s" %
                                   (video_settings.get("vformat"),
                                    video_settings.get("vcodec"),
                                    audio_settings.get("acodec")))

            # Show friendly error
            friendly_error = error_type_str.split("> ")[0].replace("<", "")

            # Prompt error message
            msg = QMessageBox()
            _ = get_app()._tr
            msg.setWindowTitle(_("Export Error"))
            msg.setText(
                _("Sorry, there was an error exporting your video: \n%s") %
                friendly_error)
            msg.exec_()

        # Notify window of export started
        get_app().window.ExportEnded.emit(export_file_path)

        # Close timeline object
        self.timeline.Close()

        # Clear all cache
        self.timeline.ClearAllCache()

        # Re-set OMP thread enabled flag
        if self.s.get("omp_threads_enabled"):
            openshot.Settings.Instance().WAIT_FOR_VIDEO_PROCESSING_TASK = False
        else:
            openshot.Settings.Instance().WAIT_FOR_VIDEO_PROCESSING_TASK = True

        # Return scale mode to lower quality scaling (for faster previews)
        openshot.Settings.Instance().HIGH_QUALITY_SCALING = False

        # Return keyframes to preview scaling
        if self.keyframes_rescaled:
            get_app().project.rescale_keyframes(self.original_fps_factor)

        # Accept dialog
        super(Exportting, self).accept()