Skip to content

Commit

Permalink
Merge branch 'main' into pr/4284
Browse files Browse the repository at this point in the history
  • Loading branch information
JonnyBurger committed Sep 9, 2024
2 parents aaa6b97 + 9ec263e commit 611921a
Show file tree
Hide file tree
Showing 149 changed files with 7,927 additions and 2,767 deletions.
8 changes: 8 additions & 0 deletions packages/convert/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": ["@jonny/eslint-config/react"],
"rules": {
"no-console": "error",
"react/function-component-definition": "off",
"react/require-default-props": "off",
},
}
5 changes: 5 additions & 0 deletions packages/convert/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules

/.cache
build
.env
18 changes: 18 additions & 0 deletions packages/convert/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# @remotion/convert

Video conversion tool - convert.remotion.dev

[![NPM Downloads](https://img.shields.io/npm/dm/@remotion/convert.svg?style=flat&color=black&label=Downloads)](https://npmcharts.com/compare/@remotion/convert?minimal=true)

## Installation

```bash
npm install @remotion/convert --save-exact
```

When installing a Remotion package, make sure to align the version of all `remotion` and `@remotion/*` packages to the same version.
Remove the `^` character from the version number to use the exact version.

## Usage

See the [documentation](https://convert.remotion.dev) for more information.
35 changes: 35 additions & 0 deletions packages/convert/app/components/AudioTrackOverview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type {AudioTrack} from '@remotion/media-parser';
import {Table, TableBody, TableCell, TableRow} from './ui/table';

export const AudioTrackOverview: React.FC<{
readonly track: AudioTrack;
}> = ({track}) => {
return (
<Table>
<TableBody>
<TableRow>
<TableCell colSpan={3}>Type</TableCell>
<TableCell className="text-right">Audio</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>Codec</TableCell>
<TableCell className="text-right">
{track.codecWithoutConfig}
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>WebCodecs Codec String</TableCell>
<TableCell className="text-right">{track.codec}</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>Channels</TableCell>
<TableCell className="text-right">{track.numberOfChannels}</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>Sample Rate</TableCell>
<TableCell className="text-right">{track.sampleRate}</TableCell>
</TableRow>
</TableBody>
</Table>
);
};
116 changes: 116 additions & 0 deletions packages/convert/app/components/ContainerOverview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import {Table, TableBody, TableCell, TableRow} from '@/components/ui/table';
import type {
Dimensions,
MediaParserAudioCodec,
MediaParserVideoCodec,
ParseMediaContainer,
} from '@remotion/media-parser';
import React from 'react';
import {formatBytes} from '~/lib/format-bytes';
import {Skeleton} from './ui/skeleton';

const formatSeconds = (seconds: number) => {
const minutes = Math.floor(seconds / 60);
const secondsLeft = seconds % 60;

return `${minutes}:${secondsLeft < 10 ? '0' : ''}${Math.round(secondsLeft)} min`;
};

export const ContainerOverview: React.FC<{
readonly dimensions: Dimensions | null;
readonly durationInSeconds: number | null;
readonly videoCodec: MediaParserVideoCodec | null;
readonly audioCodec: MediaParserAudioCodec | null;
readonly size: number | null;
readonly fps: number | null | undefined;
readonly container: ParseMediaContainer | null;
}> = ({
container,
dimensions,
videoCodec,
durationInSeconds,
audioCodec,
size,
fps,
}) => {
return (
<Table>
<TableBody>
<TableRow>
<TableCell colSpan={3}>Size</TableCell>
<TableCell className="text-right">
{size === null ? (
<Skeleton className="h-3 w-[100px] inline-block" />
) : (
<>{formatBytes(size)}</>
)}
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>Container</TableCell>
<TableCell className="text-right">
{container ? (
<>{String(container)}</>
) : (
<Skeleton className="h-3 w-[100px] inline-block" />
)}
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>Duration</TableCell>
<TableCell className="text-right">
{durationInSeconds === null ? (
<Skeleton className="h-3 w-[100px] inline-block" />
) : (
<>{formatSeconds(durationInSeconds)}</>
)}
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>Dimensions</TableCell>
<TableCell className="text-right">
{dimensions === null ? (
<Skeleton className="h-3 w-[100px] inline-block" />
) : (
<>
{dimensions.width}x{dimensions.height}
</>
)}
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>Frame Rate</TableCell>
<TableCell className="text-right">
{fps === undefined ? (
<Skeleton className="h-3 w-[100px] inline-block" />
) : fps ? (
<>{fps} FPS</>
) : (
'N/A'
)}
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>Video Codec</TableCell>
<TableCell className="text-right">
{videoCodec === null ? (
<Skeleton className="h-3 w-[100px] inline-block" />
) : (
videoCodec
)}
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>Audio Codec</TableCell>
<TableCell className="text-right">
{audioCodec === null ? (
<Skeleton className="h-3 w-[100px] inline-block" />
) : (
audioCodec
)}
</TableCell>
</TableRow>
</TableBody>
</Table>
);
};
98 changes: 98 additions & 0 deletions packages/convert/app/components/ConvertUi.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import {Button} from '@/components/ui/button';
import {CardContent, CardTitle} from '@/components/ui/card';
import {Label} from '@/components/ui/label';
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import {convertMedia} from '@remotion/webcodecs';
import {useCallback, useState} from 'react';
import {Badge} from './ui/badge';

export default function ConvertUI({src}: {readonly src: string}) {
const [abortController] = useState<AbortController>(
() => new AbortController(),
);

const [container, setContainer] = useState('webm');
const [videoCodec, setVideoCodec] = useState('vp8');
const [audioCodec, setAudioCodec] = useState('opus');

const onClick = useCallback(async () => {
await convertMedia({
src,
onVideoFrame: () => {
// console.log('frame', frame);
return Promise.resolve();
},
onMediaStateUpdate: () => {
// console.log('update', s);
},
videoCodec: videoCodec as 'vp8',
audioCodec: audioCodec as 'opus',
to: container as 'webm',
signal: abortController.signal,
});
}, [abortController.signal, src, container, videoCodec, audioCodec]);

return (
<div className="w-[380px]">
<CardContent className="gap-4">
<div className="grid w-full items-center gap-4">
<div className="flex flex-row">
<CardTitle>Convert video</CardTitle>
<div className="w-2" />
<Badge variant={'default'}>Alpha</Badge>
</div>
<div>
<Label htmlFor="container">Container</Label>
<Select value={container} onValueChange={setContainer}>
<SelectTrigger id="container">
<SelectValue placeholder="Select a container" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="webm">WebM</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="videoCodec">Video codec</Label>
<Select value={videoCodec} onValueChange={setVideoCodec}>
<SelectTrigger id="videoCodec">
<SelectValue placeholder="Select a video codec" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="vp8">VP8</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="audioCodec">Audio codec</Label>
<Select value={audioCodec} onValueChange={setAudioCodec}>
<SelectTrigger id="audioCodec">
<SelectValue placeholder="Select a audio codec" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="opus">Opus</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</div>
<div className="h-4" />
<Button className="block w-full" type="button" onClick={onClick}>
Convert
</Button>
</CardContent>
</div>
);
}
Loading

0 comments on commit 611921a

Please sign in to comment.