Skip to content

Commit 5252437

Browse files
Merge pull request #14 from apivideo/add-mimetype
Add mimetype
2 parents b5c1b76 + 910bc78 commit 5252437

File tree

8 files changed

+98
-22
lines changed

8 files changed

+98
-22
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Changelog
22
All changes to this project will be documented in this file.
33

4+
## [0.2.2] - 2023-02-07
5+
- add `getSupportedMimeType` method
6+
- add `mimeType` & `generateFileOnStop` options
7+
48
## [0.2.1] - 2023-01-24
59
- Add `videoPlayable` event
610
- Temporary remove computed audio delay

examples/record.a.video/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12-
"@api.video/media-stream-composer": "0.2.1",
12+
"@api.video/media-stream-composer": "0.2.2",
1313
"@mui/icons-material": "^5.11.0",
1414
"material-ui-popup-state": "^5.0.4",
1515
"next": "13.1.1",

examples/record.a.video/src/components/UploadSettingsDialog.tsx

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
import { FormControl, FormLabel, Input } from '@mui/material'
1+
import { MediaStreamComposer } from '@api.video/media-stream-composer'
2+
import { FormControl, FormControlLabel, FormLabel, Input, MenuItem, Select, Switch } from '@mui/material'
23
import Button from '@mui/material/Button'
34
import Dialog from '@mui/material/Dialog'
45
import DialogActions from '@mui/material/DialogActions'
56
import DialogContent from '@mui/material/DialogContent'
67
import DialogTitle from '@mui/material/DialogTitle'
7-
import { useState } from 'react'
8+
import { useEffect, useState } from 'react'
89

910

1011
export interface UploadSettings {
1112
videoName: string;
13+
mimeType?: string;
14+
downloadVideoFile: boolean;
1215
}
1316

1417
interface UploadSettingsDialogProps {
@@ -21,24 +24,58 @@ interface UploadSettingsDialogProps {
2124

2225
const UploadSettingsDialog = (props: UploadSettingsDialogProps) => {
2326
const [videoName, setVideoName] = useState<string>(props.uploadSettings.videoName);
27+
const [mimeType, setMimeType] = useState<string>("default");
28+
const [downloadVideoFile, setDownloadVideoFile] = useState<boolean>(false);
29+
const [mimeTypes, setMimeTypes] = useState<string[]>([]);
30+
31+
32+
useEffect(() => {
33+
setMimeTypes(MediaStreamComposer.getSupportedMimeTypes());
34+
}, []);
35+
2436

2537

2638
return <Dialog fullWidth={true} open={props.open} onClose={() => props.onClose && props.onClose()}>
2739
<DialogTitle>Upload settings</DialogTitle>
28-
40+
2941
<DialogContent>
3042
<FormControl component="fieldset" style={{ width: "100%" }}>
3143
<FormLabel component="legend">Video name</FormLabel>
3244
<Input value={videoName} onChange={(e) => setVideoName(e.target.value)} />
3345
</FormControl>
46+
47+
<FormControl component="fieldset" fullWidth>
48+
49+
<FormLabel component="legend">Mimetype</FormLabel>
50+
<Select
51+
labelId="audio-source-select-label"
52+
id="audio-source-select"
53+
value={mimeType}
54+
label="Audio source"
55+
onChange={async (a) => {
56+
setMimeType(a.target.value as string);
57+
}}
58+
>
59+
<MenuItem key={"undefined"} value={"default"}>default</MenuItem>
60+
{mimeTypes.map(d => <MenuItem key={d} value={d}>{d}</MenuItem>)}
61+
</Select>
62+
</FormControl>
63+
64+
<FormControl component="fieldset">
65+
<FormLabel component="legend">Options</FormLabel>
66+
<FormControlLabel control={<Switch checked={downloadVideoFile} onChange={(e) => setDownloadVideoFile(e.target.checked)} />} label="Download video file" />
67+
</FormControl>
3468
</DialogContent>
3569

3670
<DialogActions>
3771
<Button onClick={() => props.onClose && props.onClose()}>Cancel</Button>
3872
<Button onClick={() => props.onSubmit && props.onSubmit({
39-
videoName
73+
videoName,
74+
mimeType: mimeType === "default" ? undefined : mimeType,
75+
downloadVideoFile
4076
})}>Submit</Button>
4177
</DialogActions>
78+
4279
</Dialog>
4380
}
4481

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1-
import '../../styles/globals.css'
21
import type { AppProps } from 'next/app'
2+
import Script from 'next/script'
3+
import '../../styles/globals.css'
34

45
function MyApp({ Component, pageProps }: AppProps) {
5-
return <Component {...pageProps} />
6+
return <>
7+
8+
<Script async src="https://www.googletagmanager.com/gtag/js?id=G-N9E9YP1HGF"></Script>
9+
<Script id="ga" dangerouslySetInnerHTML={{
10+
__html: `
11+
window.dataLayer = window.dataLayer || [];
12+
function gtag(){dataLayer.push(arguments);}
13+
gtag('js', new Date());
14+
gtag('config', 'G-N9E9YP1HGF');`}}/>
15+
16+
<Component {...pageProps} />
17+
</>
618
}
719

820
export default MyApp

examples/record.a.video/src/pages/index.tsx

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,21 @@ const composer = (() => {
6161
lineWidth: 6,
6262
autoEraseDelay: 2
6363
});
64+
mediaStreamComposer.addEventListener("recordingStopped", (e: any) => {
65+
if (e.data.file) {
66+
const a = document.createElement("a");
67+
console.log(e.data.file);
68+
let extension = "mp4";
69+
try {
70+
extension = (e.data.file.type.split("/")[1]).split(";")[0];
71+
} catch (e) {
72+
console.error(e);
73+
}
74+
a.href = URL.createObjectURL(e.data.file);
75+
a.download = `video.${extension}`;
76+
a.click();
77+
}
78+
});
6479
return mediaStreamComposer;
6580
})();
6681

@@ -89,6 +104,7 @@ const Home: NextPage = () => {
89104
const [audioStreamId, setAudioStreamId] = useState<string | undefined>();
90105
const [uploadSettings, setUploadSettings] = useState<UploadSettings>({
91106
videoName: "My record.a.video composition",
107+
downloadVideoFile: false,
92108
});
93109
const [videoStatus, setVideoStatus] = useState<"recording" | "encoding" | "playable" | undefined>();
94110

@@ -429,6 +445,8 @@ const Home: NextPage = () => {
429445
composer.startRecording({
430446
uploadToken,
431447
videoName: uploadSettings.videoName,
448+
generateFileOnStop: uploadSettings.downloadVideoFile,
449+
mimeType: uploadSettings.mimeType,
432450
origin: {
433451
application: {
434452
name: "record-a-video",
@@ -445,6 +463,7 @@ const Home: NextPage = () => {
445463
setVideoStatus("playable");
446464
setPlayerUrl((e as any).data.assets.player);
447465
});
466+
448467
setPlayerUrl(null);
449468
setIsRecording(true);
450469
} else {
@@ -479,8 +498,8 @@ const Home: NextPage = () => {
479498
<Step completed={stepNum > 1}>
480499
<StepLabel>Done</StepLabel>
481500
<StepContent>
482-
<Typography>You can watch the recording by clicking here: <a href={playerUrl} rel="noreferrer" target="_blank">open player</a>. Highest qualities are still being processed. The viewing experience will be even better if you refresh the player in a few seconds. </Typography>
483-
<Typography style={{marginTop: "1em"}}>Want to offer a similar experience in your application? <a href="https://dashboard.api.video/register" target="_blank" rel="noreferrer">Create your free api.video account</a> and start building with video now. No cc required.</Typography>
501+
<Typography>You can watch the recording <a href={playerUrl!} rel="noreferrer" target="_blank">by clicking here</a>. Higher qualities are still being processed. The viewing experience will be even better if you refresh the player in a few seconds. </Typography>
502+
<Typography style={{ marginTop: "1em" }}>Want to offer a similar experience in your application? <a href="https://dashboard.api.video/register" target="_blank" rel="noreferrer">Create your free api.video account</a> and start building with video now. No cc required.</Typography>
484503
</StepContent>
485504
</Step>
486505
</Stepper>

package-lock.json

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@api.video/media-stream-composer",
3-
"version": "0.2.1",
3+
"version": "0.2.2",
44
"description": "api.video media stream composer",
55
"repository": {
66
"type": "git",
@@ -41,7 +41,7 @@
4141
"xhr-mock": "^2.5.1"
4242
},
4343
"dependencies": {
44-
"@api.video/media-recorder": "^1.0.8",
44+
"@api.video/media-recorder": "^1.0.10",
4545
"core-js": "^3.23.4"
4646
},
4747
"engines" : {

src/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ApiVideoMediaRecorder, ProgressiveUploaderOptionsWithAccessToken, ProgressiveUploaderOptionsWithUploadToken, VideoUploadResponse } from "@api.video/media-recorder";
1+
import { ApiVideoMediaRecorder, Options as RecorderOptions, ProgressiveUploaderOptionsWithAccessToken, ProgressiveUploaderOptionsWithUploadToken, VideoUploadResponse } from "@api.video/media-recorder";
22
import { DrawingLayer, DrawingSettings } from "./drawing-layer";
33
import MouseEventListener, { DragEvent, MoveEvent } from "./mouse-event-listener";
44
import { Resolution } from "./stream-position";
@@ -46,7 +46,7 @@ declare global {
4646

4747
export type MouseTool = "draw" | "move-resize";
4848

49-
type RecordingOptions = ProgressiveUploaderOptionsWithUploadToken | ProgressiveUploaderOptionsWithAccessToken;
49+
type RecordingOptions = RecorderOptions & (ProgressiveUploaderOptionsWithUploadToken | ProgressiveUploaderOptionsWithAccessToken);
5050

5151
export class MediaStreamComposer {
5252
private result: MediaStream | null = null;
@@ -164,6 +164,10 @@ export class MediaStreamComposer {
164164
return this.result;
165165
}
166166

167+
public static getSupportedMimeTypes() {
168+
return ApiVideoMediaRecorder.getSupportedMimeTypes();
169+
}
170+
167171
public startRecording(options: RecordingOptions) {
168172
if(!this.started) this.init();
169173

0 commit comments

Comments
 (0)