Antwort

20

Es gibt vier Hauptschritte:

  1. erstellen <canvas> und <video> Elemente.
  2. laden src der Videodatei durch URL.createObjectURL in das <video> Element erzeugt und warten, bis es für bestimmte Ereignisse durch das Hören zu laden gefeuert werden.
  3. Legen Sie die Zeit des Videos an dem Punkt fest, an dem Sie einen Schnappschuss machen möchten und warten Sie auf weitere Ereignisse.
  4. Verwenden Sie die Leinwand, um das Bild aufzunehmen.

Schritt 1 - Erstellen der Elemente

Dies ist sehr einfach: Erstellen Sie nur eine <canvas> und ein <video> Element und hängen Sie sie an <body> (oder irgendwo wirklich, tut es nicht wirklich wichtig):

var canvasElem = $('<canvas class="snapshot-generator"></canvas>').appendTo(document.body)[0]; 
var $video = $('<video muted class="snapshot-generator"></video>').appendTo(document.body); 

Beachten Sie, dass das Video-Element das Attribut muted hat. Fügen Sie keine anderen Attribute wie autoplay oder controls ein. Beachten Sie auch, dass beide die Klasse snapshot-generator haben. Das ist so können wir den Stil für sie beide so eingestellt, dass sie aus dem Weg sind:

.snapshot-generator { 
    display: block; 
    height: 1px; 
    left: 0; 
    object-fit: contain; 
    position: fixed; 
    top: 0; 
    width: 1px; 
    z-index: -1; 
} 

Einige Browser mit ihnen display: none gesetzt funktionieren, aber andere Browser werden ernsthafte Probleme haben, wenn sie auf die gerendert werden Seite, also machen wir sie nur winzig, so dass sie im Wesentlichen unsichtbar sind. (Sie sie nicht, obwohl außerhalb des Ansichtsfenster bewegen, da sonst können Sie einige hässliche Bildlaufleisten auf Ihrer Seite.)

Schritt 2 - Laden Sie das Video

Hier ist, wo die Dinge beginnen, schwierig zu bekommen. Sie müssen auf Ereignisse hören, um zu wissen, wann Sie fortfahren müssen. Verschiedene Browser werden verschiedene Ereignisse, unterschiedliche Zeiten und in verschiedenen Ordnungen abfeuern, so dass ich Ihnen die Mühe ersparen werde. Es gibt drei Ereignisse, die mindestens einmal ausgelöst werden müssen, bevor das Video fertig ist. sie sind:

  • loadedmetadata
  • loadeddata
  • suspendieren

den Event-Handler für diese Ereignisse einrichten und verfolgen, wie viele gefeuert haben. Sobald alle drei gefeuert haben, können Sie fortfahren. Denken Sie daran, dass einige dieser Ereignisse möglicherweise mehr als einmal ausgelöst werden. Sie möchten nur das erste Ereignis jedes Typs behandeln, der ausgelöst wird, und nachfolgende Feuerungen verwerfen. Ich verwendete jQuery .one, die sich darum kümmert.

var step_2_events_fired = 0; 
$video.one('loadedmetadata loadeddata suspend', function() { 
    if (++step_2_events_fired == 3) { 
     // Ready for next step 
    } 
}).prop('src', insert_source_here); 

Die Quelle sollte nur die über URL.createObjectURL(file) erstellte Objekt URL, wo file die Objektdatei ist.

Schritt 3 - Stellen Sie die Zeit

Diese Etappe zum vorherigen ähnlich ist: die Zeit einstellen und dann für eine Veranstaltung hören. In unserem if Block vom vorherigen Code:

$video.one('seeked', function() { 
    // Ready for next step 
}).prop('currentTime', insert_time_here_in_seconds); 

Zum Glück seines nur ein Ereignis dieser Zeit, so ist es ziemlich klar und prägnant. Schließlich ...

Schritt 4 - Ergreifen Sie die Snapshot-

Dieser Teil nur unter Verwendung des <canvas> Element einen Screenshot zu greifen. In unserem seeked Ereignishandler:

canvas_elem.height = this.videoHeight; 
canvas_elem.width = this.videoWidth; 
canvas_elem.getContext('2d').drawImage(this, 0, 0); 
var snapshot = canvas_elem.toDataURL(); 

// Remove elements as they are no longer needed 
$video.remove(); 
$(canvas_elem).remove(); 

Die Leinwand muss die Abmessungen des Videos (nicht das <video> Element) ein richtiges Bild zu erhalten passen. Außerdem setzen wir die internen .height- und .width-Eigenschaften des Canvas, , nicht die Canvas-Höhe/Breite-CSS-Stilwerte.

Der Wert von Snapshot ist eine Daten-URI, die im Grunde nur eine Zeichenfolge ist, die mit data:image/jpeg;base64 und dann die Base64-Daten beginnt.

Unser letzter JS-Code soll wie folgt aussehen:

var step_2_events_fired = 0; 
$video.one('loadedmetadata loadeddata suspend', function() { 
    if (++step_2_events_fired == 3) { 
    $video.one('seeked', function() { 
     canvas_elem.height = this.videoHeight; 
     canvas_elem.width = this.videoWidth; 
     canvas_elem.getContext('2d').drawImage(this, 0, 0); 
     var snapshot = canvas_elem.toDataURL(); 

     // Delete the elements as they are no longer needed 
     $video.remove(); 
     $(canvas_elem).remove(); 
    }).prop('currentTime', insert_time_here_in_seconds); 
    } 
}).prop('src', insert_source_here); 

Feier!

Sie haben Ihr Bild in base64! Senden Sie dies an Ihren Server, geben Sie es als src eines Elements, oder was auch immer.

Zum Beispiel können Sie es in Binärdatei dekodieren und direkt in eine Datei schreiben (trimmen Sie das Präfix zuerst), die eine JPEG-Bilddatei wird.

Sie können dies auch verwenden, um eine Vorschau von Videos zu bieten, während sie hochgeladen werden. Wenn Sie es als src eines <img> setzen, verwenden Sie den vollständigen Daten-URI (das Präfix nicht entfernen).