Создать миниатюру из видеофайла через файловый ввод

Я пытаюсь создать превью эскиза из видеофайла (mp4,3gp) из формы input type='file'. Многие говорят, что это можно делать только на стороне сервера. Мне трудно в это поверить, поскольку я совсем недавно наткнулся на эту скрипку с использованием HTML5 Canvas и Javascript.

Thumbnail Fiddle

Единственная проблема заключается в том, что для этого необходимо, чтобы видео присутствовало и пользователь нажимал кнопку воспроизведения, прежде чем щелкнуть кнопку для захвата миниатюры. Мне интересно, есть ли способ получить те же результаты без присутствия игрока и нажатия кнопки пользователем. Например: пользователь нажимает на загрузку файла и выбирает видеофайл, после чего создается миниатюра. Любая помощь / мысли приветствуются!


person ryan    schedule 13.05.2014    source источник
comment
Очевидно, что игрок должен присутствовать, так как именно он создает изображение для захвата.   -  person vogomatix    schedule 14.05.2014
comment
вы можете скрыть проигрыватель с помощью css и вызвать videoTag.play (), чтобы начать его воспроизведение. Я рекомендую прыгнуть через 18 секунд, подождать, пока он не появится, а затем отправить его в процедуру рисования холста. Таким образом я превратил папку с фильмами в галерею миниатюр в Chrome, так что могу вас заверить, что это работает.   -  person dandavis    schedule 14.05.2014
comment
Прекрасно приготовленные дандави. Теперь может ли файл быть загружен куда-нибудь на сервер или это может быть сделано на стороне клиента. Скажем, пользователь выбирает видео на своем рабочем столе, а затем запускает этот скрипт из того, что находится на входе?   -  person ryan    schedule 14.05.2014
comment
Если видео использует кодек, поддерживаемый текущим браузером, вы можете обработать отброшенный / выбранный видеофайл, получить URL-адрес объекта для видеофайла и установить это значение для атрибута src элемента видео.   -  person Ray Nicholus    schedule 14.05.2014
comment
Недавно я работал над подключаемым модулем, который обращается к элементам вашего вопроса (создание эскизов из <video>s, преобразование _2 _ / _ 3_ в <video> и т. Д.). Посмотрите, возможно, он вам пригодится. github.com/rnicholus/frame-grab.js   -  person Ray Nicholus    schedule 15.05.2014
comment
@RayNicholus это выглядит как очень многообещающий плагин. Прочитал документацию на github. Вопрос в том, может ли эта клиентская часть работать без загрузки видео на сервер? Кроме того, с какими типами файлов он работает? Причина в том, что я разрешаю пользователям загружать .mp4 и .3gp только потому, что мои клиенты предназначены для мобильных устройств.   -  person ryan    schedule 15.05.2014
comment
Возможности frame-grab на 100% принадлежат клиенту. Например, если вы включаете элемент ввода файла или зону перетаскивания на свою страницу. Когда ваш пользователь выбирает / удаляет видеофайл, вы можете передать Blob из события ввода / вывода файла в метод blob_to_video frab-grab, получить <video> и передать его в экземпляр захвата кадра, где вы можете создавать изображения с помощью различные рабочие процессы / методы, представленные в API захвата кадров. Все это происходит в браузере, на сервер ничего не отправляется. Я рекомендую вам задавать вопросы или оставлять запросы функций в репозитории github, и мы можем обсудить там больше.   -  person Ray Nicholus    schedule 15.05.2014
comment
@RayNicholus Я не могу понять, как задавать вопросы на github. Но я скачал ваш плагин и открыл ваш тест. Ничто не связано с тем, что тестовый файл был правильно связан, и как только я все связал, ничего не произошло. Мне удалось воспроизвести видео, которое уже было встроено в тег видео, но не было ввода или эскизов видеофайла.   -  person ryan    schedule 15.05.2014
comment
Если вы хотите запустить тесты, вам нужно будет клонировать репозиторий с помощью git, запустить npm install в клонированном каталоге, а затем запустить grunt. Предварительное требование: должен быть установлен grunt. Если вы просто хотите использовать плагин, просто вставьте его в свой проект вместе с RSVP (обещание impl frame-grab зависит от всего асинхронного материала, который он выполняет). Я разрабатываю это только в свободное от работы время, поздно ночью, так что документы могут быть лучше. Подскажите, пожалуйста, как это можно улучшить. Чтобы задать вопрос, сделайте это в системе отслеживания проблем с захватом кадра. Вот ссылка для создания новой проблемы: github.com/rnicholus/frame-grab .js / issues / new   -  person Ray Nicholus    schedule 15.05.2014
comment
Обратите внимание, что пару недель назад я уже использовал захват кадра в реальном проекте-прототипе. С тех пор я внес в код некоторые изменения, но он тщательно протестирован, поэтому я вполне уверен, что ничего серьезного не сломано.   -  person Ray Nicholus    schedule 15.05.2014
comment
@RayNicholus Я написал комментарий на github. Есть ли способ связаться с вами напрямую, возможно, электронная почта, скайп, ссылка. У меня есть довольно объемный проект, над которым я работаю, и сроки его очень сжатые. Было бы замечательно получить некоторое представление о том, как начать работу. Спасибо   -  person ryan    schedule 16.05.2014
comment
Извините, я работаю над этим плагином в свободное время, так как у меня дневная работа. Я видел вашу проблему, размещенную в репо, и постараюсь ответить сегодня вечером (CST), если позволит график. Я не могу гарантировать каких-либо конкретных сроков обработки ответов по этому проекту. В основном это неторопливый побочный проект, за который мне не платят и я не развиваю его так, как позволяет мой график.   -  person Ray Nicholus    schedule 16.05.2014
comment
@RayNicholus Спасибо за быстрые ответы. Я прекрасно понимаю, что у меня есть работа на полный рабочий день и работа над проектами бесплатно. Я тоже придумал несколько подключаемых модулей, которые работают с использованием Canvas и PHP, чтобы позволить пользователям (детям) отправлять рисунки, которые они рисуют, на мобильные телефоны. Все еще на начальной стадии. Но если бы вы могли держать меня в курсе, это было бы замечательно. Хорошего дня.   -  person ryan    schedule 16.05.2014


Ответы (5)


Canvas.drawImage должен быть основан на HTML-содержимом.

источник

вот более простой jsfiddle

//and code
function capture(){
    var canvas = document.getElementById('canvas');
    var video = document.getElementById('video');
    canvas.getContext('2d').drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
}

Преимущество этого решения заключается в том, что вы можете выбрать нужный эскиз в зависимости от времени видео.

person Giu    schedule 22.04.2015
comment
Есть ли у них способ сделать это, не загружая видео в документ? - person Master Yoda; 28.08.2017
comment
Я могу получить только размер видео 0 0 и белое изображение. - person Becario Senior; 26.09.2017

Недавно понадобилось это, и он провел некоторое тестирование и свел его к минимуму, см. https://codepen.io/aertmann/pen/mAVaPx

Есть некоторые ограничения, где это работает, но в настоящее время довольно хорошая поддержка браузеров: Chrome, Firefox, Safari, Opera, IE10, IE11, Android (Chrome), iOS Safari (10+).

 video.preload = 'metadata';
 video.src = url;
 // Load video in Safari / IE11
 video.muted = true;
 video.playsInline = true;
 video.play();
person Aske Ertmann    schedule 28.09.2016
comment
Кажется, у вас хороший код, но когда я пытаюсь загрузить ›100-мегабайтные видеоролики в портретном режиме на iPhone, иногда скриншоты остаются пустыми, а иногда они загружаются не только. К вашему сведению, я хочу, чтобы размер холста был 170x100. Сталкивались ли вы с подобными проблемами при просмотре видео в портретном режиме на iPhone? - person vbjain; 05.03.2018
comment
@vbjain Нет, не могу сказать, что у меня есть, извините. - person Aske Ertmann; 06.03.2018

Недавно это было необходимо, поэтому я написал функцию, которая берет видео file и желаемое timestamp и возвращает image blob в это время видео.

Пример использования:

try {
    // get the frame at 1.5 seconds of the video file
    const cover = await getVideoCover(file, 1.5);
    // print out the result image blob
    console.log(cover);
} catch (ex) {
    console.log("ERROR: ", ex);
}

Функция:

function getVideoCover(file, seekTo = 0.0) {
    console.log("getting video cover for file: ", file);
    return new Promise((resolve, reject) => {
        // load the file to a video player
        const videoPlayer = document.createElement('video');
        videoPlayer.setAttribute('src', URL.createObjectURL(file));
        videoPlayer.load();
        videoPlayer.addEventListener('error', (ex) => {
            reject("error when loading video file", ex);
        });
        // load metadata of the video to get video duration and dimensions
        videoPlayer.addEventListener('loadedmetadata', () => {
            // seek to user defined timestamp (in seconds) if possible
            if (videoPlayer.duration < seekTo) {
                reject("video is too short.");
                return;
            }
            // delay seeking or else 'seeked' event won't fire on Safari
            setTimeout(() => {
              videoPlayer.currentTime = seekTo;
            }, 200);
            // extract video thumbnail once seeking is complete
            videoPlayer.addEventListener('seeked', () => {
                console.log('video is now paused at %ss.', seekTo);
                // define a canvas to have the same dimension as the video
                const canvas = document.createElement("canvas");
                canvas.width = videoPlayer.videoWidth;
                canvas.height = videoPlayer.videoHeight;
                // draw the video frame to canvas
                const ctx = canvas.getContext("2d");
                ctx.drawImage(videoPlayer, 0, 0, canvas.width, canvas.height);
                // return the canvas image as a blob
                ctx.canvas.toBlob(
                    blob => {
                        resolve(blob);
                    },
                    "image/jpeg",
                    0.75 /* quality */
                );
            });
        });
    });
}
person user1032613    schedule 18.08.2020
comment
ты действительно сэкономил мне время - person shah Safiullah Jan; 01.09.2020
comment
При повторном использовании setTimeout проблема может быть в том, что вы добавляете прослушиватель событий после, когда выполняете поиск? Возможно, имеет смысл сначала добавить слушателя, а затем вызвать поиск. То же самое с загруженными метаданными - person xaphod; 29.09.2020
comment
@xaphod Я помню, что пробовал даже с setTimeout 0, который помещает обратный вызов в очередь событий, но все же не делает его достаточно надежным для сафари. Нужна фактическая задержка. Может быть, просто Safari слишком медленно загружает видео? Удалось ли вам проверить свои предложения по Safari? - person user1032613; 30.09.2020
comment
на моем iMac с последней стабильной версией Safari не требовалось никакого setTimeout - или, по крайней мере, миниатюра сгенерирована нормально. Это связано с добавлением слушателей до запроса поиска. - person xaphod; 30.09.2020
comment
@xaphod Я еще не использую Safari 14, но без установленного тайм-аута примерно 8 из 10 видео будут в порядке, некоторые эпизодические видео не будут работать по непонятной причине - person user1032613; 01.10.2020
comment
Спасибо Вам за информацию. Я оставлю это на всякий случай. - person xaphod; 01.10.2020

С jQuery Lib вы можете использовать здесь мой код. $ video - это элемент Video. Эта функция возвращает строку

function createPoster($video) {
    //here you can set anytime you want
    $video.currentTime = 5;
    var canvas = document.createElement("canvas");
    canvas.width = 350;
    canvas.height = 200;
    canvas.getContext("2d").drawImage($video, 0, 0, canvas.width, canvas.height);
    return canvas.toDataURL("image/jpeg");;
}

Пример использования:

$video.setAttribute("poster", createPoster($video));
person uyghurbeg    schedule 15.09.2020

Самый простой способ отобразить эскиз - использовать сам тег <video>.

<video src="http://www.w3schools.com/html/mov_bbb.mp4"></video>

Используйте #t в URL-адресе, если вы хотите, чтобы эскиз длился x секунд.

E.g.:

<video src="http://www.w3schools.com/html/mov_bbb.mp4#t=5"></video>

Убедитесь, что он не включает никаких атрибутов, таких как autoplay или controls, и не должен иметь тег source в качестве дочернего элемента.

person Reza Saadati    schedule 15.06.2021