Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capturing the first video frame

I found many article in stackoverflow talking about how to capture the first video image frame, but I don't see what I'm doing wrong on the code to make it not working. So if someone can help me, thanks a lot !

HTML code:

<ion-button expand="block" color="primary" (click)="onPickVideo()">
   <ion-icon name="videocam" slot="start"></ion-icon>
   <ion-label>Select video</ion-label>
 </ion-button>

  <input type="file" (change)="onFileChosen($event)" #filePicker/>

<div class="wrapper" *ngIf="flag">
  <video controls >
    <source [src]="videoDetail.dataString" type="video/mp4">
    unsupported video
  </video>
</div>

TS Code:

import { Component, ViewChild, ElementRef } from '@angular/core';

export interface VideoDetail {
  ... Some code ...
}

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {

  ... Some code ...

  onPickVideo() {
    this.filePickerRef.nativeElement.click();
  }


  onFileChosen(ev: Event) {
    const files: FileList = (ev.target as HTMLInputElement).files;

  ... Some code ...      

    this.videoMetadataReader(this.videoBuffer, this.videoDetail);

    this.convertToDataString(this.videoBuffer, this.videoDetail);
  }

  // Metadata video reader
  videoMetadataReader(buffer: File, detail: VideoDetail) {
    const fileReader = new FileReader();
    this.videoBuffer = files[0];   // get video file

    fileReader.onload = () => {
      const blob = new Blob([fileReader.result], {type});

      const url = (URL || webkitURL).createObjectURL(blob);
      const video = document.createElement('video');  // create video element

      video.preload = 'metadata';                     // preload setting
      video.addEventListener('loadedmetadata', () => {

       ... Some code ...

        // Get first frame
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        const img = new Image();


        canvas.height = video.videoHeight;
        canvas.width = video.videoWidth;

        ctx.drawImage(video, 0, 0, canvas.width, canvas.height);


        img.src = canvas.toDataURL();
        detail.videoFrame = img.src;

        console.log('img :', img.src);

      });
      video.src = url; // start video load
    };
    fileReader.readAsArrayBuffer(buffer);
  }

  // File to dataUrl
  convertToDataString(buffer: File, detail: VideoDetail) {
    const fileReader = new FileReader();
    fileReader.onload = () => {
      const dataString = fileReader.result.toString();
      detail.dataString = dataString;
      this.flag = true;
    };
    fileReader.readAsDataURL(buffer);
  }
}

When I see the img in console.log I get an image, but totally white, and it should not be white.

Edit to show screenshot: In red the video frame capture, white.

enter image description here

Thanks again for help :)

Edited to add app link download :

Download source code here

like image 614
JBD Avatar asked Jan 13 '20 10:01

JBD


People also ask

How do I extract a frame from a youtube video?

Click the arrow next to export video at the top right corner of the Studio and select export as image. Use the slider that appears below the video to select the exact frame you want to download. You can also use the left and right arrows on your keyboard for more precision.


1 Answers

I've reproduced your problem: you should replace preload type from preload to auto and event loadedmetadata should be changed to loadeddata or canplay.

BTW, I've used function below to convert blob to dataUri (can be changed to async or promises):

function blobToDataURL(blob, callback) {
  var a = new FileReader();
  a.onload = function(e) {callback(e.target.result);}
  a.readAsDataURL(blob);
}
like image 152
stck Avatar answered Oct 10 '22 18:10

stck