오픈 소스 썸네일 라이브러리인 ReactJS에서 비디오 썸네일을 생성합니다.

사용자가 동영상을 업로드하고 썸네일을 선택할 수 있는 옵션이 필요한 적이 있습니까? 그렇다면 계속 읽으십시오.

최근에 저는 사용자가 비디오를 업로드하고 해당 비디오의 썸네일을 선택할 수 있는 내 프로젝트 중 하나에서 서비스를 생성해야 했으며 비디오의 다양한 시간대에서 여러 썸네일을 생성해야 했습니다. 따라서 사용자는 주어진 썸네일 중 하나를 선택할 수 있습니다.

이런 식으로 [원본 화면을 업로드할 수 없습니다]



나는 나를 위해 이것을 할 수 있지만 결국 내 자신의 NPM 패키지를 만드는 JS 라이브러리를 검색합니다.
video-thumbnails-generator
기여를 환영합니다. 저는 이미 Readme.md에 로드맵을 추가했습니다.

그러나 먼저 장면 뒤에서 어떻게 작동하는지 살펴보겠습니다.



🔵 Index.js 드라이버

// convert image to object part instead of base64 for better performance
// https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
export const importFileandPreview = (file, revoke) => {
    return new Promise((resolve, reject) => {
        window.URL = window.URL || window.webkitURL;
        let preview = window.URL.createObjectURL(file);
        // remove reference
        if (revoke) {
            window.URL.revokeObjectURL(preview);
        }
        setTimeout(() => {
            resolve(preview);
        }, 100);
    });
}


/**
 *
 * @param videoFile {FIle} // the video file
 * @param numberOfThumbnails {number} //number of thumbnails you want to generate
 * @returns {string[]} // an array of base64 thumbnails images
 *
 * @abstract
 * Idea taken from - https://codepen.io/aertmann/pen/mrVaPx
 * The original functionality of getVideoThumbnail() function is customized as per working code
 * If it didn't work in future then replace it with about links working example
 */
export const generateVideoThumbnails = async (videoFile, numberOfThumbnails) => {

    let thumbnail = [];
    let fractions = [];
    return new Promise(async (resolve, reject) => {
        if (!videoFile.type?.includes("video")) reject("not a valid video file");
        await getVideoDuration(videoFile).then(async (duration) => {
            // divide the video timing into particular timestamps in respective to number of thumbnails
            // ex if time is 10 and numOfthumbnails is 4 then result will be -> 0, 2.5, 5, 7.5 ,10
            // we will use this timestamp to take snapshots
            for (let i = 0; i <= duration; i += duration / numberOfThumbnails) {
                fractions.push(Math.floor(i));
            }
            // the array of promises
            let promiseArray = fractions.map((time) => {
                return getVideoThumbnail(videoFile, time)
            })
            // console.log('promiseArray', promiseArray)
            // console.log('duration', duration)
            // console.log('fractions', fractions)
            await Promise.all(promiseArray).then((res) => {
                res.forEach((res) => {
                    // console.log('res', res.slice(0,8))
                    thumbnail.push(res);
                });
                // console.log('thumbnail', thumbnail)
                resolve(thumbnail);
            }).catch((err) => {
                console.error(err)
            }).finally((res) => {
                console.log(res);
                resolve(thumbnail);
            })
        });
        reject("something went wront");
    });
};

const getVideoThumbnail = (file, videoTimeInSeconds) => {
    return new Promise((resolve, reject) => {
        if (file.type.match("video")) {
            importFileandPreview(file).then((urlOfFIle) => {
                var video = document.createElement("video");
                var timeupdate = function () {
                    if (snapImage()) {
                        video.removeEventListener("timeupdate", timeupdate);
                        video.pause();
                    }
                };
                video.addEventListener("loadeddata", function () {
                    if (snapImage()) {
                        video.removeEventListener("timeupdate", timeupdate);
                    }
                });
                var snapImage = function () {
                    var canvas = document.createElement("canvas");
                    canvas.width = video.videoWidth;
                    canvas.height = video.videoHeight;
                    canvas.getContext("2d").drawImage(video, 0, 0, canvas.width, canvas.height);
                    var image = canvas.toDataURL();
                    var success = image.length > 100000;
                    if (success) {
                        URL.revokeObjectURL(urlOfFIle);
                        resolve(image);
                    }
                    return success;
                };
                video.addEventListener("timeupdate", timeupdate);
                video.preload = "metadata";
                video.src = urlOfFIle;
                // Load video in Safari / IE11
                video.muted = true;
                video.playsInline = true;
                video.currentTime = videoTimeInSeconds;
                video.play();
            });
        } else {
            reject("file not valid");
        }
    });
};

/**
 *
 * @param videoFile {File}
 * @returns {number} the duration of video in seconds
 */
export const getVideoDuration = (videoFile)=> {
    return new Promise((resolve, reject) => {
        if (videoFile) {
            if (videoFile.type.match("video")) {
                importFileandPreview(videoFile).then((url) => {
                    let video = document.createElement("video");
                    video.addEventListener("loadeddata", function () {
                        resolve(video.duration);
                    });
                    video.preload = "metadata";
                    video.src = url;
                    // Load video in Safari / IE11
                    video.muted = true;
                    video.playsInline = true;
                    video.play();
                    //  window.URL.revokeObjectURL(url);
                });
            }
        } else {
            reject(0);
        }
    });
};


🔵 설명
importFileandPreview()
/**
* This function will take an File object and will convert it
* into windowObjectURI which look something like this - 
* blob:http://localhost/2d7b2c97-02f3-4e7d-a6c1-d04746c27730
*/
export const importFileandPreview = (file, revoke) => {
    return new Promise((resolve, reject) => {
       //@todo - your logic here
    });
}

getVideoDuration()
/**
 * @abbrivation This function takes a video File object as an 
 * input and returns the duration of that video.
 *
 * @param videoFile {File}
 * @returns {number} the duration of video in seconds
 */
export const getVideoDuration = (videoFile)=> {
    return new Promise((resolve, reject) => {
        if (videoFile) {
           resolve(duration);
        } else {
            reject(0);
        }
    });
};


getVideoThumbnail()
/**
* @abbrivation 
* This function takes a video File Object and the time where we
* need a snapshot of video screen.
* It will return a snapshot of the video at the given time
* in `base64` format.
*
* @param {File} file 
* @param {number} videoTimeInSeconds 
* @returns string // base64Image 
*/
const getVideoThumbnail = (file, videoTimeInSeconds) => {
    return new Promise((resolve, reject) => {
        if (file.type.match("video")) {
            resolve(thumbnail); //base64 image
        } else {
            reject("file not valid");
        }
    });
};


generateVideoThumbnails()
/**
 * This functin will take two input video File and Number
 * And It will generate that many thumbnails.
 *
 * @param videoFile {FIle} // the video file
 * @param numberOfThumbnails {number} //number of thumbnails you want to generate
 * @returns {string[]} // an array of base64 thumbnails images
 *
 * @abstract
 * Idea taken from - https://codepen.io/aertmann/pen/mrVaPx
 * The original functionality of getVideoThumbnail() function is customized as per working code
 * If it didn't work in future then replace it with about links working example
 */
export const generateVideoThumbnails = async (videoFile, numberOfThumbnails) => {

    let thumbnail = [];
    let fractions = [];
    return new Promise(async (resolve, reject) => {
        if (!videoFile.type?.includes("video")) reject("not a valid video file");
            // first we get video duration
            // then we calculate how many thumbnails to generate
            // we cann generateThumbnail() function that many times
            // then we resolve all those promises and return result.
            await Promise.all(promiseArray).then((res) => {
                res.forEach((res) => {
                    thumbnail.push(res);
                });
                resolve(thumbnail);
            }).catch((err) => {
                console.error(err)
            }).finally((res) => {
                resolve(thumbnail);
            })
        });
        reject("something went wrong");
    });
};


실제 작동 확인 - Live Demo .



즐겁게 읽으셨기를 바랍니다. 히트 댓 하트 아이콘 잊지마세요😀 새로운 소재👋로 곧 만나요.

좋은 웹페이지 즐겨찾기