Changeset View
Changeset View
Standalone View
Standalone View
native/media/video-utils.js
Show All 13 Lines | import type { | ||||
TranscodeVideoMediaMissionStep, | TranscodeVideoMediaMissionStep, | ||||
VideoGenerateThumbnailMediaMissionStep, | VideoGenerateThumbnailMediaMissionStep, | ||||
Dimensions, | Dimensions, | ||||
} from 'lib/types/media-types.js'; | } from 'lib/types/media-types.js'; | ||||
import { getMessageForException } from 'lib/utils/errors.js'; | import { getMessageForException } from 'lib/utils/errors.js'; | ||||
import { ffmpeg } from './ffmpeg.js'; | import { ffmpeg } from './ffmpeg.js'; | ||||
import { temporaryDirectoryPath } from './file-utils.js'; | import { temporaryDirectoryPath } from './file-utils.js'; | ||||
import { generateThumbhashStep } from './media-utils.js'; | |||||
// These are some numbers I sorta kinda made up | // These are some numbers I sorta kinda made up | ||||
// We should try to calculate them on a per-device basis | // We should try to calculate them on a per-device basis | ||||
const uploadSpeeds = Object.freeze({ | const uploadSpeeds = Object.freeze({ | ||||
wifi: 4096, // in KiB/s | wifi: 4096, // in KiB/s | ||||
cellular: 512, // in KiB/s | cellular: 512, // in KiB/s | ||||
}); | }); | ||||
const clientTranscodeSpeed = 1.15; // in seconds of video transcoded per second | const clientTranscodeSpeed = 1.15; // in seconds of video transcoded per second | ||||
Show All 13 Lines | |||||
type ProcessVideoResponse = { | type ProcessVideoResponse = { | ||||
+success: true, | +success: true, | ||||
+uri: string, | +uri: string, | ||||
+thumbnailURI: string, | +thumbnailURI: string, | ||||
+mime: string, | +mime: string, | ||||
+dimensions: Dimensions, | +dimensions: Dimensions, | ||||
+loop: boolean, | +loop: boolean, | ||||
+thumbHash: ?string, | |||||
}; | }; | ||||
async function processVideo( | async function processVideo( | ||||
input: ProcessVideoInfo, | input: ProcessVideoInfo, | ||||
config: VideoProcessConfig, | config: VideoProcessConfig, | ||||
): Promise<{ | ): Promise<{ | ||||
steps: $ReadOnlyArray<MediaMissionStep>, | steps: $ReadOnlyArray<MediaMissionStep>, | ||||
result: MediaMissionFailure | ProcessVideoResponse, | result: MediaMissionFailure | ProcessVideoResponse, | ||||
}> { | }> { | ||||
Show All 40 Lines | if (plan.action === 'none') { | ||||
steps.push(thumbnailStep); | steps.push(thumbnailStep); | ||||
if (!thumbnailStep.success) { | if (!thumbnailStep.success) { | ||||
unlink(plan.thumbnailPath); | unlink(plan.thumbnailPath); | ||||
return { | return { | ||||
steps, | steps, | ||||
result: { success: false, reason: 'video_generate_thumbnail_failed' }, | result: { success: false, reason: 'video_generate_thumbnail_failed' }, | ||||
}; | }; | ||||
} | } | ||||
const thumbnailURI = `file://${plan.thumbnailPath}`; | |||||
const thumbhashStep = await generateThumbhashStep(thumbnailURI); | |||||
steps.push(thumbhashStep); | |||||
const { thumbHash } = thumbhashStep; | |||||
return { | return { | ||||
steps, | steps, | ||||
result: { | result: { | ||||
success: true, | success: true, | ||||
uri: input.uri, | uri: input.uri, | ||||
thumbnailURI: `file://${plan.thumbnailPath}`, | thumbnailURI, | ||||
thumbHash, | |||||
mime: 'video/mp4', | mime: 'video/mp4', | ||||
dimensions: input.dimensions, | dimensions: input.dimensions, | ||||
loop: false, | loop: false, | ||||
}, | }, | ||||
}; | }; | ||||
} | } | ||||
const [thumbnailStep, transcodeStep] = await Promise.all([ | const [thumbnailStep, transcodeStep] = await Promise.all([ | ||||
Show All 39 Lines | ): Promise<{ | ||||
const dimensions = transcodeProbeStep.dimensions | const dimensions = transcodeProbeStep.dimensions | ||||
? transcodeProbeStep.dimensions | ? transcodeProbeStep.dimensions | ||||
: input.dimensions; | : input.dimensions; | ||||
const loop = !!( | const loop = !!( | ||||
mediaConfig[input.mime] && | mediaConfig[input.mime] && | ||||
mediaConfig[input.mime].videoConfig && | mediaConfig[input.mime].videoConfig && | ||||
mediaConfig[input.mime].videoConfig.loop | mediaConfig[input.mime].videoConfig.loop | ||||
); | ); | ||||
const thumbnailURI = `file://${plan.thumbnailPath}`; | |||||
const thumbhashStep = await generateThumbhashStep(thumbnailURI); | |||||
steps.push(thumbhashStep); | |||||
const { thumbHash } = thumbhashStep; | |||||
return { | return { | ||||
steps, | steps, | ||||
result: { | result: { | ||||
success: true, | success: true, | ||||
uri: `file://${plan.outputPath}`, | uri: `file://${plan.outputPath}`, | ||||
thumbnailURI: `file://${plan.thumbnailPath}`, | thumbnailURI, | ||||
thumbHash, | |||||
mime: 'video/mp4', | mime: 'video/mp4', | ||||
dimensions, | dimensions, | ||||
loop, | loop, | ||||
}, | }, | ||||
}; | }; | ||||
} | } | ||||
async function generateThumbnail( | async function generateThumbnail( | ||||
▲ Show 20 Lines • Show All 101 Lines • Show Last 20 Lines |