
Recherche avancée
Médias (1)
-
Bug de détection d’ogg
22 mars 2013, par
Mis à jour : Avril 2013
Langue : français
Type : Video
Autres articles (70)
-
Les autorisations surchargées par les plugins
27 avril 2010, parMediaspip core
autoriser_auteur_modifier() afin que les visiteurs soient capables de modifier leurs informations sur la page d’auteurs -
Publier sur MédiaSpip
13 juin 2013Puis-je poster des contenus à partir d’une tablette Ipad ?
Oui, si votre Médiaspip installé est à la version 0.2 ou supérieure. Contacter au besoin l’administrateur de votre MédiaSpip pour le savoir -
Emballe Médias : Mettre en ligne simplement des documents
29 octobre 2010, parLe plugin emballe médias a été développé principalement pour la distribution mediaSPIP mais est également utilisé dans d’autres projets proches comme géodiversité par exemple. Plugins nécessaires et compatibles
Pour fonctionner ce plugin nécessite que d’autres plugins soient installés : CFG Saisies SPIP Bonux Diogène swfupload jqueryui
D’autres plugins peuvent être utilisés en complément afin d’améliorer ses capacités : Ancres douces Légendes photo_infos spipmotion (...)
Sur d’autres sites (7922)
-
Video streamign with FFMpeg and Nest.js+Next.js
17 septembre 2024, par AizenHere is my problem : I have one video src 1080p (on the frontend). On the frontend, I send this video-route to the backend :


const req = async()=>{try{const res = await axios.get('/catalog/item',{params:{SeriesName:seriesName}});return {data:res.data};}catch(err){console.log(err);return false;}}const fetchedData = await req();-On the backend i return seriesName.Now i can make a full path,what the video is,and where it is,code:



const videoUrl = 'C:/Users/arMori/Desktop/RedditClone/reddit/public/videos';console.log('IT VideoURL',videoUrl);



const selectedFile = `${videoUrl}/${fetchedData.data.VideoSource}/${seriesName}-1080p.mp4`
console.log(`ITS'S SELECTED FILE: ${selectedFile}`);



Ok, I have my src 1080p, now is the time to send it to the backend :


const response = await axios.post('/videoFormat', {videoUrl:selectedFile})console.log('Это консоль лог путей: ',response.data);const videoPaths = response.data;



Backend takes it and FFMpqg makes two types of resolution,720p and 480p,save it to the temp storage on backend, and then returns two routes where these videos stores


async videoUpload(videoUrl:string){try{const tempDir = C:/Users/arMori/Desktop/RedditClone/reddit_back/src/video/temp;const inputFile = videoUrl;console.log('VIDEOURL: ',videoUrl);



const outputFiles = [];
 
 await this.createDirectories(tempDir); 
 outputFiles.push(await this.convertVideo(inputFile, '1280x720', '720p.mp4'));
 outputFiles.push(await this.convertVideo(inputFile, '854x480', '480p.mp4'));
 console.log('OUTUPT FILES SERVICE: ',outputFiles);
 
 return outputFiles;

 }catch(err){
 console.error('VideoFormatterService Error: ',err);
 
 }
}

private convertVideo(inputPath:string,resolution:string,outputFileName:string):Promise<string>{
 const temp = `C:/Users/arMori/Desktop/RedditClone/reddit_back/src/video/temp`;
 return new Promise(async(resolve,reject)=>{
 const height = resolution.split('x')[1];
 console.log('HIEGHT: ',height);
 
 const outputDir = `C:/Users/arMori/Desktop/RedditClone/reddit_back/src/video/temp/${height}p`;
 const outputPath = join(outputDir, outputFileName);
 const isExists = await fs.access(outputPath).then(() => true).catch(() => false);
 if(isExists){ 
 console.log(`File already exists: ${outputPath}`);
 return resolve(outputPath)
 };
 ffmpeg(inputPath)
 .size(`${resolution}`)
 .videoCodec('libx264') // Кодек H.264
 .audioCodec('aac') 
 .output(outputPath)
 .on('end',()=>resolve(outputPath))
 .on('error',(err)=>reject(err))
 .run()
 
 })
}

private async createDirectories(temp:string){
 try{
 const dir720p = `${temp}/720p`;
 const dir480p = `${temp}/480p`;
 const dir720pExists = await fs.access(dir720p).then(() => true).catch(() => false);
 const dir480pExists = await fs.access(dir480p).then(() => true).catch(() => false);
 if(dir720pExists && dir480pExists){
 console.log('FILES ALIVE');
 return;
 }
 if (!dir720pExists) {
 await fs.mkdir(dir720p, { recursive: true });
 console.log('Папка 720p создана');
 }
 
 if (!dir480pExists) {
 await fs.mkdir(dir480p, { recursive: true });
 console.log('Папка 480p создана');
 }
 } catch (err) {
 console.error('Ошибка при создании директорий:', err);
 }
}
</string>


Continue frontentd code :


let videoPath;

if (quality === '720p') {
 videoPath = videoPaths[0];
} else if (quality === '480p') {
 videoPath = videoPaths[1];
}

if (!videoPath) {
 console.error('Video path not found!');
 return;
}

// Получаем видео по его пути
console.log('VIDEOPATH LOG: ',videoPath);
 
const videoRes = await axios.get('/videoFormat/getVideo', { 
 params: { path: videoPath } ,
 headers: { Range: 'bytes=0-' },
 responseType: 'blob'
 });
 console.log('Video fetched: ', videoRes);
 const videoBlob = new Blob([videoRes.data], { type: 'video/mp4' });
 const videoURL = URL.createObjectURL(videoBlob);
 return videoURL;
 /* console.log('Видео успешно загружено:', response.data); */
 } catch (error) {
 console.error('Ошибка при загрузке видео:', error);
 }
}



Here I just choose one of the route and make a new GET request (VideoRes), now in the controller in the backend, I'm trying to do a video streaming :


@Public()
 @Get('/getVideo')
 async getVideo(@Query('path') videoPath:string,@Req() req:Request,@Res() res:Response){
 try {
 console.log('PATH ARGUMENT: ',videoPath);
 console.log('VIDEOPATH IN SERVICE: ',videoPath);
 const videoSize = (await fs.stat(videoPath)).size;
 const CHUNK_SIZE = 10 ** 6;
 const range = req.headers['range'] as string | undefined;
 if (!range) {
 return new ForbiddenException('Range не найденно');
 }
 const start = Number(range.replace(/\D/g,""));
 const end = Math.min(start + CHUNK_SIZE,videoSize - 1);

 const contentLength = end - start + 1;
 const videoStream = fsSync.createReadStream(videoPath, { start, end });
 const headers = {
 'Content-Range':`bytes ${start}-${end}/${videoSize}`,
 'Accept-Ranges':'bytes',
 'Content-Length':contentLength,
 'Content-Type':'video/mp4'
 }
 
 res.writeHead(206,headers);

 // Передаем поток в ответ
 videoStream.pipe(res);
 

 // Если возникнет ошибка при стриминге, логируем ошибку
 videoStream.on('error', (error) => {
 console.error('Ошибка при чтении видео:', error);
 res.status(500).send('Ошибка при чтении видео');
 });
 } catch (error) {
 console.error('Ошибка при обработке запросов:', error);
 return res.status(400).json({ message: 'Ошибка при обработке getVideo запросов' });
 }
 }



Send to the frontend


res.writeHead(206,headers);



In the frontend, I make blob url for video src and return it


const videoBlob = new Blob([videoRes.data], { type: 'video/mp4' });const videoURL = URL.createObjectURL(videoBlob);return videoURL;



And assign src to the video :


useVideo(seriesName,quality).then(src => {
 if (src) {
 console.log('ITS VIDEOLOGISC GOIDA!');
 if(!playRef.current) return;
 
 const oldURL = playRef.current.src;
 if (oldURL && oldURL.startsWith('blob:')) {
 URL.revokeObjectURL(oldURL);
 }
 playRef.current.pause();
 playRef.current.src = '';
 setQuality(quality);
 console.log('SRC: ',src);
 
 playRef.current.src = src;
 playRef.current.load();
 console.log('ITS VIDEOURL GOIDA!');
 togglePlayPause();
 }
 })
 .catch(err => console.error('Failed to fetch video', err));



But the problem is :




Vinland-Saga:1 Uncaught (in promise) NotSupportedError : Failed to load because no supported source was found




And I don't know why...


I tried everything, but I don't understand why src is incorrect..


-
Anomalie #2805 : Utiliser les champs nom et email de la table auteur si id_auteur est renseigné
26 juillet 2012, par Maïeul Rouquettepour le 1er point, cela se discute. En revanche pour le second point, cela serait vrai si le formulaire de forum permettait de choisir son prénom + mail bien qu’en étant connecté.
-
Revision 2865 : firefox linux est sensible à la casse (cf ...
6 janvier 2010, par b_b — Logfirefox linux est sensible à la casse (cf http://swfupload.org/forum/generaldiscussion/455), on doublonne les extensions autorisées en MAJ uniquement dans les paramètres de swfupload pour ne pas polluer le texte explicatif.