mirror of
https://github.com/flutter/holobooth.git
synced 2025-05-17 21:36:00 +08:00
fix: making the correct image adjustments on the cloud functions (#299)
* fix: making the correct image adjustments on the cloud functions * fixing lint and timeout issue
This commit is contained in:
1343
functions/package-lock.json
generated
1343
functions/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -27,6 +27,7 @@
|
||||
"firebase-functions": "^4.1.0",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"fs": "^0.0.1-security",
|
||||
"jimp": "^0.16.2",
|
||||
"mustache": "^4.2.0",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
|
@ -120,7 +120,6 @@ function setUpReadable(currentEvent: string) {
|
||||
return readable;
|
||||
}
|
||||
|
||||
|
||||
jest.mock('busboy', () => () => {
|
||||
return {
|
||||
end: jest.fn(),
|
||||
@ -135,6 +134,20 @@ jest.mock('busboy', () => () => {
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('jimp', () => {
|
||||
return {
|
||||
read: jest.fn().mockImplementation((name) => {
|
||||
const _name = name || '';
|
||||
return {
|
||||
bitmap: {
|
||||
width: _name.indexOf('odd') != -1 ? 501 : 600,
|
||||
height: _name.indexOf('odd') != -1 ? 301 : 400,
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('fluent-ffmpeg', () => () => {
|
||||
return {
|
||||
addInput: jest.fn().mockReturnThis(),
|
||||
@ -340,6 +353,33 @@ describe('convertToVideo', () => {
|
||||
).resolves.toBe(`${tempDir}/video.mp4`);
|
||||
});
|
||||
|
||||
describe('when the dimensions of the image are even', () => {
|
||||
it('keeps the dimension on the scale flag', async () => {
|
||||
setUpFfmpeg('end');
|
||||
await convert.convertToVideo(ffmpeg, [ `${tempDir}/frame_1.png` ], tempDir);
|
||||
|
||||
expect(ffmpeg.addOptions).toHaveBeenCalledWith([
|
||||
'-codec:v libx264',
|
||||
'-s 600x400',
|
||||
'-pix_fmt yuv420p',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the dimensions of the image are odd', () => {
|
||||
it('uses the nearest (down) even number', async () => {
|
||||
setUpFfmpeg('end');
|
||||
|
||||
await convert.convertToVideo(ffmpeg, [ `${tempDir}/frame_odd.png` ], tempDir);
|
||||
|
||||
expect(ffmpeg.addOptions).toHaveBeenCalledWith([
|
||||
'-codec:v libx264',
|
||||
'-s 500x300',
|
||||
'-pix_fmt yuv420p',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('throws error when unable to convert frames.', async () => {
|
||||
setUpFfmpeg('error');
|
||||
|
||||
|
@ -4,6 +4,8 @@ import * as path from 'path';
|
||||
|
||||
import { UPLOAD_PATH, ALLOWED_HOSTS } from '../config';
|
||||
import ffmpeg from 'fluent-ffmpeg';
|
||||
import Jimp from 'jimp';
|
||||
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import _busboy from 'busboy';
|
||||
@ -33,7 +35,7 @@ export const convert = functions.https.onRequest(async (req, res) => {
|
||||
export async function convertImages(
|
||||
req: functions.https.Request,
|
||||
): Promise<{
|
||||
status: number;
|
||||
status: number,
|
||||
videoUrl: string,
|
||||
gifUrl: string,
|
||||
}> {
|
||||
@ -59,8 +61,10 @@ export async function convertImages(
|
||||
const videoPath = await convertToVideo(ffmpeg(), frames, tempDir);
|
||||
const gifPath = await convertVideoToGif(ffmpeg(), videoPath, tempDir);
|
||||
|
||||
const videoUrl = await uploadFile(userId + '.mp4', videoPath);
|
||||
const gifUrl = await uploadFile(userId + '.gif', gifPath);
|
||||
const [ videoUrl, gifUrl ] = await Promise.all([
|
||||
uploadFile(userId + '.mp4', videoPath),
|
||||
uploadFile(userId + '.gif', gifPath),
|
||||
]);
|
||||
|
||||
return { status: 200, videoUrl, gifUrl };
|
||||
} catch (error) {
|
||||
@ -132,16 +136,35 @@ export async function proceedFile(
|
||||
});
|
||||
}
|
||||
|
||||
function adjustDimensions(width: number, height: number): {
|
||||
width: number,
|
||||
height: number,
|
||||
} {
|
||||
const w = width % 2 == 0 ? width : width - 1;
|
||||
const h = height % 2 == 0 ? height : height - 1;
|
||||
|
||||
return { width: w, height: h };
|
||||
}
|
||||
|
||||
export async function convertToVideo(
|
||||
ffmpeg: ffmpeg,
|
||||
frames: string[],
|
||||
folder: string
|
||||
): Promise<string> {
|
||||
const videoPath = `${folder}/video.mp4`;
|
||||
|
||||
const image = await Jimp.read(frames[0]);
|
||||
const adjustedDimensions = adjustDimensions(
|
||||
image.bitmap.width,
|
||||
image.bitmap.height,
|
||||
);
|
||||
|
||||
const scaleArg = `${adjustedDimensions.width}x${adjustedDimensions.height}`;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
ffmpeg
|
||||
.addInput(folder + '/frame_%d.png')
|
||||
.addOptions([ '-codec:v libx264', '-s 980x620', '-pix_fmt yuv420p' ])
|
||||
.addOptions([ '-codec:v libx264', `-s ${scaleArg}`, '-pix_fmt yuv420p' ])
|
||||
.inputFPS(frames.length / 5)
|
||||
.mergeToFile(videoPath)
|
||||
.on('end', () => {
|
||||
|
Reference in New Issue
Block a user