Skip to content

Commit

Permalink
Progress on media storage
Browse files Browse the repository at this point in the history
  • Loading branch information
Joery committed Apr 11, 2024
1 parent 0dde2bc commit 53bf6da
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 24 deletions.
14 changes: 6 additions & 8 deletions packages/safelight/src/views/Editor/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
</template>

<script setup lang="ts">
import { Storage } from '@safelight/shared/base/Storage';
import MediaManager from '@safelight/shared/Storage/MediaManager';
import { useObservable } from '@vueuse/rxjs';
import SplitterPanel from 'primevue/splitterpanel';
Expand Down Expand Up @@ -61,20 +63,16 @@ fileDialog.onChange((fileList) => {
function loadFile(file: File) {
return new Promise<void>((resolve) => {
const storingProcessing = useObservable(IdbMediaManager.storeMedia(file));
const storingProcessing = useObservable(MediaManager.StoreMedia(file));
watch(storingProcessing, (s) => {
console.log(s?.type, s?.hashProgress);
});
watch(storingProcessing, () => {
watch(storingProcessing, async () => {
if (storingProcessing.value && storingProcessing.value.type == 'done') {
const existingMedia = project.media.some(
(m) => m.id.value == storingProcessing.value!.id
);
if (!existingMedia) {
const media = new Media(storingProcessing.value.id!);
const media = await Storage.getStorage().LoadMedia(storingProcessing.value.id!);
if (media) {
project.media.push(media);
project.activeTimeline.createTimelineItem(media);
}
Expand Down
4 changes: 3 additions & 1 deletion packages/shared/src/Media/Media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,16 @@ export interface VideoTrackInfo {
bitDepth: number;
colorSpace: string;
isHDR: boolean;
title?: string;
title: string;
duration: number;
}

export interface AudioTrackInfo {
codec: string;
sampleRate: number;
channels: number;
title?: string;
duration: number;
}

export interface ImageInfo {
Expand Down
97 changes: 86 additions & 11 deletions packages/shared/src/Storage/MediaManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ import { v4 as uuidv4 } from 'uuid';
import { Storage } from '../base/Storage';
import { generateMediaThumbnail } from '../helpers/Video/GenerateMediaThumbnail';
import { getVideoInfo } from '../helpers/Video/GetVideoInfo';
import type { MediaInfoType } from 'mediainfo.js';
import {
MediaType,
type AudioTrackInfo,
type ImageInfo,
type TextTrackInfo,
type VideoTrackInfo
} from '../Media/Media';

const chunkSize = 64 * 1024 * 1024;

Expand Down Expand Up @@ -60,9 +68,7 @@ export default class MediaManager {
type: 'fileInfo',
hashProgress: 1
});
const fileInfo = await getVideoInfo(file).catch(() => {
return undefined;
});
const fileInfo = await getVideoInfo(file);

// Get thumbnail
subscriber.next({
Expand All @@ -73,21 +79,32 @@ export default class MediaManager {

const uuid = uuidv4();

const trackInfo = this.parseFileInfo(fileInfo);

let type: MediaType = 0;

if (trackInfo.videoTracks.length > 0) {
type = type | MediaType.Video;
}
if (trackInfo.audioTracks.length > 0) {
type = type | MediaType.Audio;
}
if (trackInfo.textTracks.length > 0) {
type = type | MediaType.Text;
}
if (trackInfo.imageInfo) {
type = type | MediaType.Image;
}

Storage.getStorage().SaveMedia({
id: uuid,
name: file.name,
contentHash: hash,
data: file,
fileInfo,
previewImage: thumbnail,

// TODO: Implement

duration: 0,
audioTracks: [],
textTracks: [],
type: 0,
videoTracks: []
type,
...trackInfo
});
subscriber.next({
type: 'done',
Expand All @@ -100,6 +117,64 @@ export default class MediaManager {
})();
});
}

private static parseFileInfo(info: MediaInfoType) {
const videoTracks: VideoTrackInfo[] = [];
const audioTracks: AudioTrackInfo[] = [];
const textTracks: TextTrackInfo[] = [];
const sampledDurations: number[] = [];
let imageInfo: ImageInfo | undefined;

info.media?.track.forEach((track) => {
if (track['@type'] == 'Video') {
videoTracks.push({
title: track.Title ?? `Video Track ${videoTracks.length + 1}`,
bitDepth: track.BitDepth!,
codec: (track.CodecID ?? track.Format)!,
colorSpace: track.ColorSpace!,
frameRate: track.FrameRate!,
frameRateMode:
track.FrameRate_Mode === 'CFR' || !track.FrameRate_Mode ? 'CFR' : 'VFR',
height: track.Height!,
width: track.Width!,
isHDR: 'HDR_Format' in track,
duration: track.Duration!
});
if (track.Duration) {
sampledDurations.push(track.Duration);
}
} else if (track['@type'] == 'Audio') {
audioTracks.push({
title: track.Title ?? `Audio Track ${audioTracks.length + 1}`,
channels: (track.Channels ?? track.Audio_Channels_Total)!,
codec: (track.CodecID ?? track.Format)!,
sampleRate: track.SamplingRate!,
duration: track.Duration!
});
if (track.Duration) {
sampledDurations.push(track.Duration);
}
} else if (track['@type'] == 'Image') {
imageInfo = {
format: track.Format!,
height: track.Height!,
width: track.Width!
};
} else if (track['@type'] == 'Text') {
textTracks.push({
format: track.Format!
});
}
});

return {
videoTracks,
audioTracks,
textTracks,
imageInfo,
duration: Math.max(...sampledDurations)
};
}
}

interface LoadMediaProgress {
Expand Down
14 changes: 10 additions & 4 deletions packages/shared/src/helpers/Video/GenerateMediaThumbnail.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import MimeMatcher from 'mime-matcher';
import MissingThumbnail from '../../../assets/missing_thumbnail.png?url';

export function generateMediaThumbnail(file: File, percent = 0.1, maxWidth = 427, maxHeight = 240) {
return new Promise<Blob | null>((resolve) => {
Expand Down Expand Up @@ -48,9 +49,7 @@ export function generateMediaThumbnail(file: File, percent = 0.1, maxWidth = 427
},
{ once: true }
);
}

if (isVideo) {
} else if (isVideo) {
// Generate video frame

const video = document.createElement('video');
Expand Down Expand Up @@ -104,6 +103,13 @@ export function generateMediaThumbnail(file: File, percent = 0.1, maxWidth = 427
{ once: true }
);
};
} else {
fetch(MissingThumbnail)
.then((r) => r.blob())
.then((img) => resolve(img))
.catch((err) => {
console.error('Could not load missing thumbnail', err);
});
}
});
}
Expand All @@ -124,7 +130,7 @@ function calculateAspectRatioFit(
srcHeight: number,
maxWidth: number,
maxHeight: number
) {
): { width: number; height: number } {
const ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);

return { width: srcWidth * ratio, height: srcHeight * ratio };
Expand Down

0 comments on commit 53bf6da

Please sign in to comment.