Closed paulisidore closed 9 months ago
@paulisidore in Android file:///storage/emulated/0/Documents/KSSV/documents/1/videos/0-12-2023-31230.mp4 in iOS file:///var/mobile/Documents/1/videos/0-12-2023-31230.mp4
Hello @jepiqueau , thank you for your reply, i try the url file:///storage/emulated/0/Documents/KSSV/documents/1/videos/2-12-2023-101222.mp4 like you suggested but still nothing, i got a toast that says file Url not found error. (2-12-2023-101222.mp4 is another video recorded by the phone itself)
@paulisidore you have yo tell me exactely where did you store your video in the Public Documents folder or in the app Documents folder i do not understant what Documents appears two time in your given path
@paulisidore which code did you use to store the video on the device can you share it
Hello @jepiqueau , this is the code i use to record and save file:
async recordVideo2(){
this.videoStream = await navigator.mediaDevices.getUserMedia(
{
video: {
"facingMode": "environment",
},
audio: true
}
);
this.captureElement.nativeElement.srcObject = this.videoStream ;
const options={ mimeType: 'video/webm'};
this.mediaRecorder=new MediaRecorder(this.videoStream,options);
let chunks = <any>[];
this.mediaRecorder.ondataavailable = (event)=>{
if (event.data && event.data.size > 0){
chunks.push(event.data);
}
}
this.mediaRecorder.onstop = async (event)=>{
const videoBuffer = new Blob (chunks,{type: "video/webm"});
if (this.videoStream){
this.videoStream.getAudioTracks().forEach((audio) => {
audio.stop();
});
this.videoStream.getVideoTracks().forEach((video)=>{
video.stop();
});
if (this.mediaRecorder){
this.mediaRecorder.stop();
}
}
//Save to file
const videoInfo = await this.saveVideoBlob(videoBuffer) ;
}
this.videoStream.getTracks().forEach((track) =>
track.addEventListener("ended", () => {
if (this.videoStream){
this.videoStream.getAudioTracks().forEach((audio) => audio.stop());
this.videoStream.getVideoTracks().forEach((video)=>{ video.stop()});
if (this.mediaRecorder){
this.mediaRecorder.stop();
}
}
})
);
this.isRecording = true;
this.mediaRecorder.start(100);
}
async saveVideoBlob(videoBlob: Blob){
var fileN="2-12-2023-101222";
const base64Data = await this.convertBlobToBase64(videoBlob) as string ;
var ext='mp4';
var dossierUtilisateur ="KSSV/documents/1/videos" ;
var vFileName=dossierUtilisateur+"/"+fileN+'.'+ext ;
var fileUri =undefined;
try{
await Filesystem.writeFile({
path: vFileName,
data: base64Data,
recursive: true,
directory: Directory.Documents,
});
}catch(ex: any){
console.error(ex);
}
let infos= await Filesystem.stat({
path: vFileName,
directory: Directory.Documents
}).then(
(reponse)=>{
return reponse ;
},
(err)=>{
console.log(err);
}
)
if (infos){
fileUri = infos.uri;
}
console.log("Video Uri : "+fileUri);
return fileUri;
}
convertBlobToBase64 = (blob: Blob) => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = reject;
reader.onload = () => {
resolve(reader.result);
};
reader.readAsDataURL(blob);
});
For play local video i use this code:
async playVideo2(localUri: any){
//this video Url working fine: https://brenopolanski.github.io/html5-video-webvtt-example/MIB2.mp4");
await this.videoPlayer.initPlayer({
mode: 'fullscreen',
url: localUri,
type: 'video/mp4' ,
playerId: 'fullscreen',
componentTag: 'app-home',
})
}
@paulisidore sorry to come back late but i was working on another plugin, i used the following
have you look in Android Studio in which folder is your file?
@paulisidore i did this:
import { Injectable } from '@angular/core';
import { Filesystem, Directory, StatOptions, GetUriOptions } from '@capacitor/filesystem';
import { Capacitor } from '@capacitor/core';
export interface Video {
id: number;
device: string;
type: string;
title: string;
url: string;
thumb?: string;
note: string;
subtitle?: string;
stlang?: string;
}
@Injectable({
providedIn: 'root'
})
export class DataService {
private videos: Video[] = [
{
id: 1,
type: "mp4",
device: "all",
url: "https://brenopolanski.github.io/html5-video-webvtt-example/MIB2.mp4",
note: "Breno Polanski",
title: "Test MP4 with Subtitle",
subtitle: "https://brenopolanski.github.io/html5-video-webvtt-example/MIB2-subtitles-pt-BR.vtt",
stlang: "es"
},
{
id: 2,
type: "mp4",
device: "all",
url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
note: "By Blender Foundation",
thumb: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg",
title: "Big Buck Bunny"
},
{
id: 3,
type: "mp4",
device: "all",
url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4",
note: "By Blender Foundation",
thumb: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/ElephantsDream.jpg",
title: "Elephant Dream"
},
{
id: 4,
type: "mp4",
device: "all",
url: "https://media.bernat.ch/videos/2019-self-hosted-videos-subtitles/progressive.mp4",
note: "Blender Animation Studio",
thumb: "https://d2pzklc15kok91.cloudfront.net/images/posters/2019-self-hosted-videos-subtitles.3b55d44c736235.jpg",
title: "327",
subtitle: "https://media.bernat.ch/videos/2019-self-hosted-videos-subtitles.en.vtt",
stlang: "en"
},
{
id: 5,
type: "aws",
device: "all",
url: "https://universo-dev-a-m.s3.amazonaws.com/779970/fe774806dbe7ad042c24ce522b7b46594f16c66e",
note: "Custom",
title: "AWS video test",
},
{
id: 6,
type: "hls",
device: "all",
url: "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8",
note: "By Blender Foundation",
title: "Big Buck Bunny",
},
{
id: 7,
type: "mpd",
device: "android",
url: "https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd",
note: "",
title: "MPD video test",
},
{
id: 8,
type: "webm",
device: "android",
url: "https://upload.wikimedia.org/wikipedia/commons/f/f1/Sintel_movie_4K.webm",
note: "Blender Foundation",
thumb: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Sintel_movie_4K.webm/800px--Sintel_movie_4K.webm.jpg?20150505130125",
title: "Webm video test",
},
{
id: 9,
type: "mp4",
device: "android",
url: "public/assets/video/Bike720.mp4",
note: "",
title: "Video from Assets directory",
},
{
id: 10,
type: "mp4",
device: "android",
url: "file:///storage/emulated/0/Documents/Bike720.mp4",
note: "",
title: "Video on Documents directory",
},
{
id: 11,
type: "mp4",
device: "android",
url: "file:///sdcard/Download/Bike720.mp4",
note: "",
title: "Video on sdcard Download directory",
},
{
id: 12,
type: "mp4",
device: "android",
url: "file:///sdcard/DCIM/Camera/Bike720.mp4",
note: "",
title: "Video on sdcard DCIM directory",
},
{
id: 13,
type: "mp4",
device: "android",
url: "file:///sdcard/Documents/KSSV/documents/1/videos/2-12-2023-101222.mp4",
note: "",
title: "Video on sdcard issue#142 directory",
},
{
id: 14,
type: "mp4",
device: "ios",
url: "public/assets/video/Bike720.mp4",
note: "",
title: "Video from Assets directory",
},
{
id: 15,
type: "mp4",
device: "ios",
url: "file:///var/mobile/Containers/Data/Application/22A433FD-D82D-4989-8BE6-9FC49DEA20BB/Documents/Bike720.mp4",
note: "",
title: "Video on App's Documents directory",
},
{
id: 16,
type: "mp4",
device: "ios",
url: "file:///var/mobile/Documents/Bike720.mp4",
note: "",
title: "Video on Documents directory",
},
{
id: 17,
type: "mp4",
device: "ios",
url: "file:///var/mobile/Downloads/Bike720.mp4",
note: "",
title: "Video on Download directory",
},
{
id: 18,
type: "mp4",
device: "ios",
url: "file:///var/mobile/Media/DCIM/100APPLE/Bike720.mp4",
note: "",
title: "Video on Media/DCIM directory",
},
{
id: 19,
type: "mp4",
device: "all",
url: "https://raw.githubusercontent.com/jepiqueau/jepiqueau.github.io/master/videos/Bike720.mp4",
note: "Test Bike720",
title: "Video from ",
},
];
constructor() {
this.createDeviceVideo();
}
public getVideos(platform: string): Video[] {
if (platform === 'web') {
// Filter videos for Web platform (device: 'all')
return this.videos.filter((video) => video.device === 'all');
} else if (platform === 'android') {
// Filter videos for Android platform (device: 'all' or 'android')
return this.videos.filter((video) => video.device === 'all' || video.device === 'android');
} else if (platform === 'ios') {
// Filter videos for iOS platform (device: 'all' or 'ios')
return this.videos.filter((video) => video.device === 'all' || video.device === 'ios');
} else {
return [];
}
}
public getVideoById(id: number): Video | undefined {
return this.videos.find(video => video.id === id);
}
private async createDeviceVideo(): Promise<void> {
const platform = Capacitor.getPlatform();
if (['ios', 'android'].includes(platform)) {
// file Bike720.mp4
const urlBike = "https://raw.githubusercontent.com/jepiqueau/jepiqueau.github.io/master/videos/Bike720.mp4";
// const uri = await this.downloadVideotoDevice(urlBike);
const uri = await this.fetchingVideoToDevice(urlBike, Directory.Documents);
console.log(`###### uri : ${uri} ######`)
if(uri !== undefined) {
await this.copyVideoToOthersDirectories(uri,platform);
}
// test with a given path
const vUri = await this.fetchingVideoToDevice(urlBike, Directory.Documents,"KSSV/documents/1/videos/2-12-2023-101222.mp4" );
console.log(`###### vUri : ${vUri} ######`)
}
}
public async fetchingVideoToDevice(url:string, directory: Directory, path: string = ""): Promise<string | undefined> {
const urlName = path.length === 0 ? this.getFileName(url)! : path;
const isVideoExists = await this.isFileExists(urlName, directory);
console.log(`###### isVideoExists: ${isVideoExists} ######`)
if(!isVideoExists) {
let response = await fetch(url);
console.log(" > fetched url");
let dbBlob = await response.blob();
let vBase64 = await this.getBlobAsBase64(dbBlob);
console.log(" > converted url blob to base64\n");
await Filesystem.writeFile({ data: vBase64, path: urlName, recursive: true, directory: directory });
console.log( " > saved vBase64 in Documents folder\n");
return (await Filesystem.getUri({
path: urlName,
directory: Directory.Documents
})).uri;
} else {
return (await Filesystem.getUri({
path: urlName,
directory: Directory.Documents
})).uri;
}
}
private getBlobAsBase64(blob: Blob): Promise<string> {
return new Promise((resolve, _) => {
let reader = new FileReader();
reader.onload = (event: any) => {
resolve(event.target.result);
};
reader.readAsDataURL(blob);
});
}
private async copyVideoToOthersDirectories(uri: string,platform: string): Promise<void> {
const uriName = this.getFileName(uri);
let toPathDocum: string = "";
let toPathDownl: string = "";
let toPathDCIM: string = "";
if (platform === 'ios') {
const containersIndex = uri.indexOf('Containers');
const folderPath = containersIndex !== -1 ? uri.substring(0, containersIndex) : uri;
toPathDocum = `${folderPath}Documents/${uriName!}`;
toPathDownl = `${folderPath}Downloads/${uriName!}`;
toPathDCIM = `${folderPath}Media/DCIM/100APPLE/${uriName!}`;
} else if (platform === 'android') {
const parentPathIndex = uri.indexOf('Documents');
const parentPath = parentPathIndex !== -1 ? uri.substring(0, parentPathIndex) : uri;
toPathDownl = `${parentPath}Download/${uriName!}`;
toPathDCIM = `${parentPath}DCIM/Camera/${uriName!}`;
}
console.log(`###### toPathDocum : ${toPathDocum} ######`)
console.log(`###### toPathDownl : ${toPathDownl} ######`)
console.log(`###### toPathDCIM : ${toPathDCIM} ######`)
if(toPathDocum.length > 0 && !(await this.isFileExists(toPathDocum))) {
const rc1 = await Filesystem.copy ({
from: uri,
to: toPathDocum
});
console.log(`&&&&rc1 : ${JSON.stringify(rc1)}`)
}
if(toPathDownl.length > 0 && !(await this.isFileExists(toPathDownl))) {
const rc2 = await Filesystem.copy ({
from: uri,
to: toPathDownl
});
console.log(`&&&&rc2 : ${JSON.stringify(rc2)}`)
}
if(toPathDCIM.length > 0 && !(await this.isFileExists(toPathDCIM))) {
const rc3 = await Filesystem.copy ({
from: uri,
to: toPathDCIM
});
console.log(`&&&&rc3 : ${JSON.stringify(rc3)}`)
}
}
private async isFileExists(path: string, directory?: Directory): Promise<boolean> {
try {
const options: StatOptions = {} as StatOptions;
options.path = path;
const dir = directory ? directory : "";
if (dir.length > 0) options.directory = directory;
console.log(`###### isFileExists options: ${JSON.stringify(options)} ######`)
const info = await Filesystem.stat(options);
console.log(`&&&&& info: ${JSON.stringify(info)} &&&&&`)
return true;
} catch (error) {
return false;
}
}
private getFileName(url: string) : string | undefined{
const urlObject = new URL(url);
return urlObject.pathname.split('/').pop();
}
}
if you look at the id=13 you see the url = "file:///sdcard/Documents/KSSV/documents/1/videos/2-12-2023-101222.mp4"
now on the page where you have the call to videoPlayer initPlayer method you will have something like this
private data = inject(DataService);
private videoIndex: number = 13;
private videoPlayer: any;
private platform: string = 'web';
private video: Video | undefined = {} as Video;
...
async ngAfterViewInit() {
// Get the selected video
this.video = this.data.getVideoById(this.videoIndex);
// Define the platform and the video player
const info = await Device.getInfo();
this.platform = info.platform;
this.videoPlayer = CapacitorVideoPlayer;
const props: any = {};
if (this.video!.url != null) {
props.mode = "fullscreen";
props.url = this.video!.url;
props.playerId = 'fullscreen';
props.componentTag = 'YOUR_COMPONENT_TAG';
if(this.video!.subtitle != null) props.subtitle = this.video!.subtitle;
if(this.video!.stlang != null) props.stlang = this.video!.stlang;
console.log('&&&& props: &&&&\n', JSON.stringify(props))
const res: any = await this.videoPlayer.initPlayer(props);
}
}
and this work well
@paulisidore this will come soon in the update version of the tutorial Ionic7Angular-VideoPlayer-App
thank you very much for your support, @jepiqueau , i will come back to you after doing that.
@paulisidore i have updated the tutorial
@paulisidore Where do you stand now ? is it fixed? i close the issue not having news back from you. Fill free to reopen it if it is required
Hello @jepiqueau, sorry for the delay, I have been suffering and very busy taking care of myself. I come back to thank you again your example is perfect and everything works as expected. I implemented the code today with Capacitor 6 instead of 5 as in the project by forcing the installation of the Plugin.
Thank you and again take care of yourself and your family. Very Warmly
@paulisidore thanks for your support. Life is not always easy. Good luck for your project
I got a Video URL not found error when trying to play a local file on an Android device like this https://localhost/_capacitor_file_/storage/emulated/0/Documents/KSSV/documents/1/videos/ 0-12-2023-31230.mp4
While the file exists in the folder and playback is correct with an external video player.
Also, playing https://brenopolanski.github.io/html5-video-webvtt-example/MIB2.mp4 works fine with my code.
I also tried with the Uri file:// but the reading is not done.
Could I have a specific example for reading local files on Ionic7/Angular ? Your plugin example use only a URL hosted on the internet.
THANKS