Extract the audio stream shape into shared types

The { index, channels, channelLayout } shape was repeated inline in the
preview's main and renderer signatures. Move it to src/common/types.ts as
AudioStreamInfo, and let getFixChannelLayoutFilter take the narrower
AudioChannelInfo it actually needs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCf7BBiPqNLUjVoN7rTCF6
pull/3038/head
Claude 3 weeks ago
parent c743d484d4
commit 53fafbc9f6
No known key found for this signature in database

@ -9,6 +9,19 @@ export interface KeyBinding {
export type FfmpegHwAccel = 'none' | 'auto' | 'vdpau' | 'dxva2' | 'd3d11va' | 'vaapi' | 'qsv' | 'videotoolbox';
/**
* The parts of an audio stream's ffprobe data needed to decide whether its channel layout
* has to be fixed up before ffmpeg can resample or downmix it. See `getFixChannelLayoutFilter`.
*/
export interface AudioChannelInfo {
channels?: number | undefined,
channelLayout?: string | undefined,
}
export interface AudioStreamInfo extends AudioChannelInfo {
index: number,
}
export type CaptureFormat = 'jpeg' | 'png' | 'webp';
export type TimecodeFormat = 'timecodeWithDecimalFraction' | 'frameCount' | 'seconds' | 'timecodeWithFramesFraction';

@ -1,4 +1,4 @@
import type { FfmpegHwAccel } from './types.ts';
import type { AudioChannelInfo, FfmpegHwAccel } from './types.ts';
export const parseFfprobeDuration = (durationStr: string | undefined) => (
durationStr != null ? parseFloat(durationStr) : undefined
@ -41,10 +41,7 @@ export const hasCustomChannelLayout = (channelLayout: string | undefined) => (
// The `channelmap` filter re-labels the channels without touching the samples, which turns the layout
// into a plain "N channels" (unspecified) layout. swresample handles those by skipping the rematrixing
// step entirely, so the stream then behaves exactly as if it had carried no channel layout information.
export function getFixChannelLayoutFilter({ channels, channelLayout }: {
channels?: number | undefined,
channelLayout?: string | undefined,
}) {
export function getFixChannelLayoutFilter({ channels, channelLayout }: AudioChannelInfo) {
if (channels == null || channels <= 0 || !hasCustomChannelLayout(channelLayout)) return undefined;
return `channelmap=${Array.from({ length: channels }, (_, i) => i).join('|')}`;
}

@ -10,7 +10,7 @@ import type { Readable } from 'node:stream';
import { app, clipboard, nativeImage } from 'electron';
import { platform, arch, isWindows, isLinux } from './util.js';
import type { CaptureFormat, FfmpegHwAccel } from '../common/types.js';
import type { AudioStreamInfo, CaptureFormat, FfmpegHwAccel } from '../common/types.js';
import type { FFprobeFormat } from '../common/ffprobe.js';
import isDev from './isDev.js';
import logger from './logger.js';
@ -594,7 +594,7 @@ const encode = true;
export function createMediaSourceProcess({ path, videoStreamIndex, audioStreams, seekTo, size, fps, rotate, forceColorspace, ffmpegHwaccel }: {
path: string,
videoStreamIndex?: number | undefined,
audioStreams: { index: number, channels?: number | undefined, channelLayout?: string | undefined }[],
audioStreams: AudioStreamInfo[],
seekTo: number,
size?: number | undefined,
fps?: number | undefined,
@ -666,7 +666,7 @@ export function createMediaSourceProcess({ path, videoStreamIndex, audioStreams,
if (audioStreams.length > 0) {
// some streams have a channel layout that ffmpeg cannot resample or downmix, so relabel it first
const getAudioFilters = (stream: typeof audioStreams[number], rest: string[]) => {
const getAudioFilters = (stream: AudioStreamInfo, rest: string[]) => {
const filters = [getFixChannelLayoutFilter(stream), ...rest].filter((filter) => filter != null);
return filters.length > 0 ? filters.join(',') : 'anull';
};

@ -8,7 +8,7 @@ import isDev from './isDev';
import type { ChromiumHTMLVideoElement } from './types';
import type { FFprobeStream } from '../../common/ffprobe';
import { getFrameDuration } from './util';
import type { FfmpegHwAccel } from '../../common/types';
import type { AudioStreamInfo, FfmpegHwAccel } from '../../common/types';
const { compatPlayer: { createMediaSourceStream } } = window.require('@electron/remote').require('./index.js');
@ -18,7 +18,7 @@ async function startPlayback({ path, slaveVideo, masterVideo, videoStreamIndex,
slaveVideo: ChromiumHTMLVideoElement,
masterVideo: ChromiumHTMLVideoElement,
videoStreamIndex?: number | undefined,
audioStreams: { index: number, channels?: number | undefined, channelLayout?: string | undefined }[],
audioStreams: AudioStreamInfo[],
seekTo: number,
signal: AbortSignal,
size?: number | undefined,

Loading…
Cancel
Save