From 9a0e422a6b9fb6e4ebfe47bd35fbcd117e133dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Sun, 22 Jan 2023 19:43:53 +0100 Subject: [PATCH] screencastService: Allow for file extensions depending on encoder used Depending on the encoder we want to use a different container format and therefore a different file extension. Right now this file extension is forced to be webm, so shuffle things around a bit to make that more dynamic. Note that this also introduces removing for the old file created by the recorder, otherwise it would create an empty "mp4" file every time it falls back from "mp4" to "webm". To be nice to external (ie. not gnome-shell) consumers of the screencastService, let's not break the API completely, and detect the ".webm" suffix a little longer to not end up with weird file.webm.webm filenames. Part-of: --- .../screencast/screencastService.js | 41 +++++++++++++------ js/ui/screenshot.js | 4 +- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/js/dbusServices/screencast/screencastService.js b/js/dbusServices/screencast/screencastService.js index 76222d7e2..ac0e461c6 100644 --- a/js/dbusServices/screencast/screencastService.js +++ b/js/dbusServices/screencast/screencastService.js @@ -33,6 +33,7 @@ const PIPELINE_BLOCKLIST_FILENAME = 'gnome-shell-screencast-pipeline-blocklist'; const PIPELINES = [ { id: 'swenc-dmabuf-vp8-vp8enc', + fileExtension: 'webm', pipelineString: 'capsfilter caps=video/x-raw(memory:DMABuf),max-framerate=%F/1 ! \ glupload ! glcolorconvert ! gldownload ! \ @@ -43,6 +44,7 @@ const PIPELINES = [ }, { id: 'swenc-memfd-vp8-vp8enc', + fileExtension: 'webm', pipelineString: 'capsfilter caps=video/x-raw,max-framerate=%F/1 ! \ videoconvert chroma-mode=none dither=none matrix-mode=output-only n-threads=%T ! \ @@ -69,7 +71,7 @@ const SessionState = { }; class Recorder extends Signals.EventEmitter { - constructor(sessionPath, x, y, width, height, filePath, options, + constructor(sessionPath, x, y, width, height, filePathStem, options, invocation) { super(); @@ -79,10 +81,10 @@ class Recorder extends Signals.EventEmitter { this._y = y; this._width = width; this._height = height; - this._filePath = filePath; + this._filePathStem = filePathStem; try { - const dir = Gio.File.new_for_path(filePath).get_parent(); + const dir = Gio.File.new_for_path(filePathStem).get_parent(); dir.make_directory_with_parents(null); } catch (e) { if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)) @@ -232,6 +234,11 @@ class Recorder extends Signals.EventEmitter { } _tryNextPipeline() { + if (this._filePath) { + GLib.unlink(this._filePath); + delete this._filePath; + } + const {done, value: pipelineConfig} = this._pipelineConfigs.next(); if (done) { this._handleFatalPipelineError('All pipelines failed to start', @@ -348,7 +355,7 @@ class Recorder extends Signals.EventEmitter { newState === Gst.State.PLAYING) { this._pipelineState = PipelineState.PLAYING; - this._startRequest.resolve(); + this._startRequest.resolve(this._filePath); delete this._startRequest; } @@ -442,8 +449,9 @@ class Recorder extends Signals.EventEmitter { } _createPipeline(nodeId, pipelineConfig, framerate) { - const {pipelineString} = pipelineConfig; + const {fileExtension, pipelineString} = pipelineConfig; const finalPipelineString = this._substituteVariables(pipelineString, framerate); + this._filePath = `${this._filePathStem}.${fileExtension}`; const fullPipeline = ` pipewiresrc path=${nodeId} @@ -544,6 +552,13 @@ export const ScreencastService = class extends ServiceImplementation { let filename = ''; let escape = false; + // FIXME: temporarily detect and strip .webm prefix to avoid breaking + // external consumers of our API, remove this again + if (template.endsWith('.webm')) { + console.log("'file_template' for screencast includes '.webm' file-extension. Passing the file-extension as part of the filename has been deprecated, pass the 'file_template' without a file-extension instead."); + template = template.substring(0, template.length - '.webm'.length); + } + [...template].forEach(c => { if (escape) { switch (c) { @@ -605,7 +620,7 @@ export const ScreencastService = class extends ServiceImplementation { const [fileTemplate, options] = params; const [screenWidth, screenHeight] = this._introspectProxy.ScreenSize; - const filePath = this._generateFilePath(fileTemplate); + const filePathStem = this._generateFilePath(fileTemplate); let recorder; @@ -614,7 +629,7 @@ export const ScreencastService = class extends ServiceImplementation { sessionPath, 0, 0, screenWidth, screenHeight, - filePath, + filePathStem, options, invocation); } catch (error) { @@ -629,8 +644,8 @@ export const ScreencastService = class extends ServiceImplementation { this._addRecorder(sender, recorder); try { - await recorder.startRecording(); - invocation.return_value(GLib.Variant.new('(bs)', [true, filePath])); + const pathWithExtension = await recorder.startRecording(); + invocation.return_value(GLib.Variant.new('(bs)', [true, pathWithExtension])); } catch (error) { log(`Failed to start recorder: ${error.message}`); this._removeRecorder(sender); @@ -676,7 +691,7 @@ export const ScreencastService = class extends ServiceImplementation { const [sessionPath] = this._proxy.CreateSessionSync({}); const [x, y, width, height, fileTemplate, options] = params; - const filePath = this._generateFilePath(fileTemplate); + const filePathStem = this._generateFilePath(fileTemplate); let recorder; @@ -685,7 +700,7 @@ export const ScreencastService = class extends ServiceImplementation { sessionPath, x, y, width, height, - filePath, + filePathStem, options, invocation); } catch (error) { @@ -700,8 +715,8 @@ export const ScreencastService = class extends ServiceImplementation { this._addRecorder(sender, recorder); try { - await recorder.startRecording(); - invocation.return_value(GLib.Variant.new('(bs)', [true, filePath])); + const pathWithExtension = await recorder.startRecording(); + invocation.return_value(GLib.Variant.new('(bs)', [true, pathWithExtension])); } catch (error) { log(`Failed to start recorder: ${error.message}`); this._removeRecorder(sender); diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js index 77d4c0c6f..f78eeacd1 100644 --- a/js/ui/screenshot.js +++ b/js/ui/screenshot.js @@ -1998,9 +1998,9 @@ export const ScreenshotUI = GObject.registerClass({ _('Screencasts'), /* Translators: this is a filename used for screencast * recording, where "%d" and "%t" date and time, e.g. - * "Screencast from 07-17-2013 10:00:46 PM.webm" */ + * "Screencast from 07-17-2013 10:00:46 PM" */ /* xgettext:no-c-format */ - _('Screencast from %d %t.webm'), + _('Screencast from %d %t'), ]), {'draw-cursor': new GLib.Variant('b', drawCursor)});