GithubHelp home page GithubHelp logo

video-upload-streaming's Introduction

๐Ÿ“ผUpload Video with Next.js


Project

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” video streaming ์‚ฌ์ดํŠธ ๊ฐœ๋ฐœ์„ ํ•˜๊ธฐ๋กœ ํ•ด๋ณธ๋‹ค. ๋‹จ์ˆœํ•˜๊ฒŒ video๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ  ์„œ๋ฒ„์—์„œ ์ŠคํŠธ๋ฆฌ๋ฐ ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•จ์œผ๋กœ video ํ”Œ๋žซํผ์˜ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•˜์˜€๋‹ค. ํด๋ผ์ด์–ธํŠธ๋Š” React ํ”„๋ ˆ์ž„์›Œํฌ์ธ Next.js๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

์ฒ˜์Œ์—๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ „์†กํ•œ video ํŒŒ์ผ์„ ์„œ๋ฒ„์—์„œ Buffer๋กœ ๋ฐ›์•„ DB๋กœ ์ €์žฅํ•˜๋ ค๊ณ  ํ•˜์˜€๋‹ค. ํ•˜์ง€๋งŒ ๋‹ค์ˆ˜์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์˜์ƒ์„ ๋™์‹œ์— ์˜ฌ๋ ค๋ ค ํ•œ๋‹ค๋ฉด ์ŠคํŠธ๋ฆฌ๋ฐ๋„ ํ•ด์•ผํ•˜๋Š” ์„œ๋ฒ„์— ๋ถ€๋‹ด์ด ๋  ์ˆ˜๋„ ์žˆ๋‹ค. ๋•Œ๋ฌธ์— ์„œ๋ฒ„๋Š” ์ŠคํŠธ๋ฆฌ๋ฐํ•˜๋Š” ์—ญํ• ๋งŒ ๋‹ด๋‹นํ•˜๊ณ  ์—…๋กœ๋“œ๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ๋‹ด๋‹นํ•˜๊ฒŒ ํ•˜์—ฌ ์—ญํ• ์„ ๋ถ„๋ฆฌํ•˜์˜€๋‹ค.


  • Upload flow


Dependency

mongodb

axios

busboy

yarn create next-app --typescript

yarn add mongodb axios busboy @types/busboy -D


Upload Video

Component Handler

  • setFile to useState
const setFileHandler: React.ChangeEventHandler<HTMLInputElement> = (event: React.ChangeEvent<HTMLInputElement>) => {
    const files = event.target.files;

    if (files?.length) {
        setFile(files[0]);
    }
}

  • submit to /api/videos page
const submitHandler: React.MouseEventHandler<HTMLButtonElement> = async () => {
    const data = new FormData;

    if (!file) return;

    setSubmitting(true);
    data.append('file', file);

    // upload percentage
    // progressEvent info (https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent)
    const config: AxiosRequestConfig = {
        onUploadProgress: function (progressEvent) {
            let percentage = Math.round((progressEvent.loaded * 100) / progressEvent.total);
            setProcess(percentage);
        }
    };

    try {
        await axios.post('/api/videos', data, config);
        console.log(`video upload is Done.`);
    } catch (error: any) {
        setError(error.message);
    } finally {
        setSubmitting(false);
        setProcess(0);
    }
}


API

  • upload Video to DB

what is GridFS ??

async function uploadVideoStream(
    req: NextApiRequest,
    res: NextApiResponse
) {
    const bb = busboy({ headers: req.headers });
    const client: MongoClient = new MongoClient(dbUri);
    await client.connect();
    const db: Db = client.db('videos');
    const bucket = new GridFSBucket(db);
    bb.on('file', (name, file, info) => {
        const { filename, encoding, mimeType } = info;
        console.log(`File[${name}]: filename: ${filename}, encoding: ${encoding}, mimeType: ${mimeType}`);

        const videoUploadStream = bucket.openUploadStream(filename, {
            chunkSizeBytes: 3145728,
            metadata: { field: "free", value: "vlog" }
        });
        file.pipe(videoUploadStream);
    });
    bb.on('close', () => {
        console.log('Done parsing video!');
        res.writeHead(200, { 'Connection': 'close' });
        res.end(`That's all folks`);
    });
    req.pipe(bb);
    return;
}

PostList

DB์— ์ €์žฅ๋œ ๋น„๋””์˜ค ๋ชฉ๋ก์„ ๊ฐ€์ ธ์™€ ํ™”๋ฉด์— ํ‘œ์‹œ

Static Generate

Next.js๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋™์ผํ•œ ํŒŒ์ผ์—์„œ getStaticProps๋ผ๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋นŒ๋“œ ์‹œ ํ˜ธ์ถœ๋˜๋ฉฐ, ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋ง ์‹œ ํŽ˜์ด์ง€์˜ ์†์„ฑ์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋น„๋””์˜ค ๋ชฉ๋ก์˜ ๊ฒฝ์šฐ ๋ฐ”๋กœ๋ฐ”๋กœ ๊ฐฑ์‹ ๋˜์–ด์•ผ ํ•˜๋ฉฐ ์ด๋ฅผ CDN์—์„œ DOM์„ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค. Static Generation์„ page์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ๋นŒ๋“œ ํƒ€์ž„์— HTML์ด ์ƒ์„ฑ๋œ๋‹ค. ์ดˆ๊ธฐ HTML ์ƒ์„ฑ ํ›„ ๊ฐ ์š”์ฒญ์ด ์˜ฌ๋•Œ ๋งˆ๋‹ค HTML์ด ์žฌ์‚ฌ์šฉ ๋œ๋‹ค.

๋™์  ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ํด๋ผ์ด์–ธํŠธ ์ธก ํƒ์ƒ‰์€ next/link๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค. ์•„๋ž˜์˜ PostLIst์—์„œ GetStaticProps์˜ ๊ฒฐ๊ณผ๋กœ ์ƒ์„ฑ๋œ posts์˜ filename์˜ ๊ฒฐ๊ณผ๋ฅผ link๋กœ ํ‘œ์‹œํ•˜๊ฒŒ ๋œ๋‹ค.

  • PostList page
const PostList = ({ posts }: { posts: Post[] }) => {
    return (
        <div>
            {posts.map((post, index) => (
                <Link key={index} href="/videos/[id]" as={`/videos/${post.filename}`}>
                    <a><p>watch {post.filename}</p></a>
                </Link>
            ))}
        </div>
    )
}

export const getStaticProps: GetStaticProps = async () => {
    // Call an external API endpoint to get posts
    const res = await fetch('http://localhost:5000/api/videos/posts')
    const posts = await res.json()

    // By returning { props: { posts } }, the Blog component
    // will receive `posts` as a prop at build time
    return {
        props: {
            posts,
        },
    }
}

Dynamic Routes

page

๋™์  ๊ฒฝ๋กœ์˜ ๊ฒฐ๊ณผ๋กœ ๋ณด์—ฌ์ง€๋Š” VideoPlayer page

import VideoPlayer from "../../components/VideoPlayer";
import { GetServerSideProps } from 'next'
import { useRouter } from "next/router";
export default function VideoPage() {
    const router = useRouter();
    const { id } = router.query as { id: string };
    return (
        <div>
            <VideoPlayer id={id} />
        </div>
    )
}

getServerSideProps

export const getServerSideProps: GetServerSideProps = async (context) => {
    return {
        props: {
            query: context.query
        },
    }
}

Component

export default function VideoPlayer({ id }: { id: string }) {

    return (
        <div>
            <video src={`http://localhost:5000/api/videos/file?videoId=${id}`}
                controls
                preload="metadata"
                width="480px"
                id="video-player"
            />
        </div>
    )
}

Server

server code ํŽ˜์ด์ง€=>> ๐Ÿฆ„๐Ÿฆ„ Streaming Server

video-upload-streaming's People

Contributors

gkdfo40 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.