
Recherche avancée
Autres articles (74)
-
Gestion de la ferme
2 mars 2010, parLa ferme est gérée dans son ensemble par des "super admins".
Certains réglages peuvent être fais afin de réguler les besoins des différents canaux.
Dans un premier temps il utilise le plugin "Gestion de mutualisation" -
Utilisation et configuration du script
19 janvier 2011, parInformations spécifiques à la distribution Debian
Si vous utilisez cette distribution, vous devrez activer les dépôts "debian-multimedia" comme expliqué ici :
Depuis la version 0.3.1 du script, le dépôt peut être automatiquement activé à la suite d’une question.
Récupération du script
Le script d’installation peut être récupéré de deux manières différentes.
Via svn en utilisant la commande pour récupérer le code source à jour :
svn co (...) -
Script d’installation automatique de MediaSPIP
25 avril 2011, parAfin de palier aux difficultés d’installation dues principalement aux dépendances logicielles coté serveur, un script d’installation "tout en un" en bash a été créé afin de faciliter cette étape sur un serveur doté d’une distribution Linux compatible.
Vous devez bénéficier d’un accès SSH à votre serveur et d’un compte "root" afin de l’utiliser, ce qui permettra d’installer les dépendances. Contactez votre hébergeur si vous ne disposez pas de cela.
La documentation de l’utilisation du script d’installation (...)
Sur d’autres sites (9646)
-
Creating HLS stream from webm 10sec chunks
23 avril 2021, par pawelmI want to make some live streaming functionality. I've got a page, where JS catches camera and sends about 10sec chunks to PHP script. It uses mediaDevices.getUserMedia(). Then my PHP script catches these chunks and save them as .webm. Next step is converting .webm chunks to .ts files and finally creating .m3u8 playlist file. Then .m3u8 playlist file is linked to video-js player with hls extension on watching page.


.ts and .m3u8 files generating works well - when I start recording and finish it ex. after 30 - 40 secs, .m3u8 ends up with '#EXT-X-ENDLIST' and JS HLS player successfully plays the whole recorded video. Problems appear in two situations :


- 

- When stream recording is in progress, .ts files are being generated and .m3u8 file is being constantly updated with every next .ts - but when I try to play the stream via HLS player it plays the first chunk and then stops with loading icon. I can see in browser console that it downloads next .ts frames and updates the .m3u8 file, but player is freezing with loading icon.
- When the stream is long, for example has 20-30 .ts files (few minutes) and I try to play it via HLS player - it tries to start from n chunk to present live video, not past fragments. I can see in browser console, that it starts downloading from ex. 10. .ts file or later, not the first one. But in player the result is black screen - it doesn't start playing.






I think that problem is in converting webm to ts - there must be some options which I don't use properly or that I don't know about. Or maybe something is wrong with created .m3u8 file, this is my code (not optimized, firstly I want it start working) :


// get params - chunk number and stream identifier
$prefix = $_GET['n'];
$num = $_GET['c'];
$isFirst = false;
$isLast = isset($_GET['f']) && $_GET['f'];

if(str_replace('0', '', $num) == '') {
 mkdir('videos/'.$prefix);
 $isFirst = true;
}

$fp = 'videos\\'.$prefix.'\\'.$num.'.webm';
$msg = 'got '.$fp;

$data = file_get_contents('php://input');
file_put_contents($fp, $data);

// we determine exact chunk length
$detailsTxt = 'videos\\'.$prefix.'\\'.$num.'.txt';
exec("ffmpeg -i .\\$fp -f null - > .\\$detailsTxt 2>&1");

preg_match('/(\d{2}:\d{2}:(\d{2}.\d{2}))/', file_get_contents($detailsTxt), $matches);
$matches = array_filter($matches);
$duration = (float)trim($matches[2], '0');

$durationTxt = 'videos\\'.$prefix.'\\'.$num.'_dur.txt';
file_put_contents($durationTxt, $duration);

// ts convertion

// counting start timestamp
$FPS = 25;
$t0 = 0;
$cursorTxt = 'videos\\'.$prefix.'\\cursor.txt';
if(file_exists($cursorTxt)) $t0 = (float)file_get_contents($cursorTxt);
file_put_contents($cursorTxt, $t0 + $duration /*+ 1/$FPS*/);

$fp2 = str_replace('.webm', '.ts', $fp);
$details2Txt = 'videos\\'.$prefix.'\\'.$num.'_conv.txt';

$convertCommand = [
 'ffmpeg',
 '-v', 'quiet',
 '-loglevel', 'error',
 '-i', ".\\$fp",
 '-vcodec', 'libx264',
 '-acodec', 'aac',
 '-r', $FPS,
 '-profile:v', 'baseline',
 '-b:v', '800k',
 '-b:a', '48k',
 '-f', 'mpegts',
 '-strict', 'experimental',
 '-mpegts_copyts', '1',
 '-filter:v', 'setpts=PTS+' . $t0 . '/TB', // $t0
 '-y',
 ".\\$fp2",
 "> .\\$details2Txt 2>&1"
];

exec(implode(" ", $convertCommand));

// generating m3u8 file

// counting max duration
$maxDuration = $duration;
$durationTxt = 'videos\\'.$prefix.'\\duration.txt';
if(file_exists($durationTxt)) {
 $tempDuration = (float)file_get_contents($durationTxt);
 if($tempDuration > $maxDuration) $maxDuration = $tempDuration;
 else file_put_contents($durationTxt, $maxDuration);
}else file_put_contents($durationTxt, $maxDuration);

file_put_contents($cursorTxt, $t0 + $duration);

$m3u8File = 'videos\\'.$prefix.'\\playlist.m3u8';
$m3u8Content = [];

$counter = 0;
do {
 $paddedCounter = str_pad($counter, 5, '0', STR_PAD_LEFT);
 $chunkFile = 'videos\\'.$prefix.'\\'.$paddedCounter.'.ts';
 if(!file_exists($chunkFile)) break;
 $counter++;
}while(true);

$m3u8Content[] = "#EXTM3U";
$m3u8Content[] = "#EXT-X-VERSION:3";
$m3u8Content[] = "#EXT-X-MEDIA-SEQUENCE:$counter";
$m3u8Content[] = "#EXT-X-ALLOW-CACHE:YES";
$m3u8Content[] = "#EXT-X-TARGETDURATION:".ceil($maxDuration);
$m3u8Content[] = "";

$counter = 0;
do {
 $paddedCounter = str_pad($counter, 5, '0', STR_PAD_LEFT);
 $chunkFile = 'videos\\'.$prefix.'\\'.$paddedCounter.'.ts';
 if(!file_exists($chunkFile)) break;

 $durationTxt = 'videos\\'.$prefix.'\\'.$paddedCounter.'_dur.txt';
 $duration = (float)file_get_contents($durationTxt);

 $m3u8Content[] = "#EXTINF:$duration,";
 $m3u8Content[] = "$paddedCounter.ts";

 $counter++;
}while(true);

if($isLast) $m3u8Content[] = "#EXT-X-ENDLIST";
$m3u8Content[] = "";

file_put_contents($m3u8File, implode("\n", $m3u8Content));



EDIT : I've just discovered, that everything works well when I disable audio stream recording in getUserMedia - so when I record only video stream. That's weird - like some synchronization between audio and video streams problem.


-
File encoded as FFV1 with ffmpeg is unplayable
18 novembre 2016, par Ali AlidoustI’m using the following code to encode a series of frames into an mkv or avi file with FFV1 encoding :
HRESULT Session::createContext(LPCSTR filepath, UINT width, UINT height, UINT fps_num, UINT fps_den) {
LOG(filepath);
this->codec = avcodec_find_encoder(AV_CODEC_ID_FFV1);
RET_IF_NULL(this->codec, "Could not create codec", E_FAIL);
this->oformat = av_guess_format(NULL, filepath, NULL);
RET_IF_NULL(this->oformat, "Could not create format", E_FAIL);
this->oformat->video_codec = AV_CODEC_ID_FFV1;
this->width = width;
this->height = height;
this->context = avcodec_alloc_context3(this->codec);
RET_IF_NULL(this->context, "Could not allocate context for the codec", E_FAIL);
this->context->codec = this->codec;
this->context->codec_id = AV_CODEC_ID_FFV1;
this->context->codec_type = AVMEDIA_TYPE_VIDEO;
this->context->pix_fmt = AV_PIX_FMT_YUV420P;
this->context->width = this->width;
this->context->height = this->height;
this->context->time_base.num = fps_num;
this->context->time_base.den = fps_den;
this->context->gop_size = 1;
av_opt_set_int(this->context->priv_data, "coder", 0, 0);
av_opt_set_int(this->context->priv_data, "context", 1, 0);
av_opt_set_int(this->context->priv_data, "slicecrc", 1, 0);
avformat_alloc_output_context2(&fmtContext, NULL, NULL, filepath);
this->fmtContext->oformat = this->oformat;
this->fmtContext->video_codec_id = AV_CODEC_ID_FFV1;
this->stream = avformat_new_stream(this->fmtContext, this->codec);
RET_IF_NULL(this->fmtContext, "Could not create new stream", E_FAIL);
avcodec_parameters_from_context(this->stream->codecpar, this->context);
this->stream->codecpar->level = 3;
/*if (this->fmtContext->oformat->flags & AVFMT_GLOBALHEADER)
{*/
this->context->flags |= CODEC_FLAG_GLOBAL_HEADER;
/*}*/
RET_IF_FAILED_AV(avcodec_open2(this->context, this->codec, NULL), "Could not open codec", E_FAIL);
RET_IF_FAILED_AV(avio_open(&this->fmtContext->pb, filepath, AVIO_FLAG_READ_WRITE), "Could not open output file", E_FAIL);
RET_IF_NULL(this->fmtContext->pb, "Could not open output file", E_FAIL);
RET_IF_FAILED_AV(avformat_write_header(this->fmtContext, NULL), "Could not write header", E_FAIL);
frame = av_frame_alloc();
RET_IF_NULL(frame, "Could not allocate frame", E_FAIL);
frame->format = this->context->pix_fmt;
frame->width = width;
frame->height = height;
// RET_IF_FAILED(av_image_alloc(frame->data, frame->linesize, context->width, context->height, context->pix_fmt, 32), "Could not allocate image", E_FAIL);
return S_OK;
}
HRESULT Session::writeFrame(IMFSample * pSample) {
IMFMediaBuffer *mediaBuffer = NULL;
BYTE *pData = NULL;
DWORD length;
RET_IF_FAILED(pSample->ConvertToContiguousBuffer(&mediaBuffer), "Could not convert IMFSample to contagiuous buffer", E_FAIL);
RET_IF_FAILED(mediaBuffer->GetCurrentLength(&length), "Could not get buffer length", E_FAIL);
RET_IF_FAILED(mediaBuffer->Lock(&pData, NULL, NULL), "Could not lock the buffer", E_FAIL);
RET_IF_FAILED(av_image_fill_arrays(frame->data, frame->linesize, pData, AV_PIX_FMT_YUV420P, this->width, this->height, 1), "Could not fill the frame with data from the buffer", E_FAIL);
LOG_IF_FAILED(mediaBuffer->Unlock(), "Could not unlock the buffer");
frame->pts = this->pts++;
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
RET_IF_FAILED_AV(avcodec_send_frame(this->context, frame), "Could not send the frame to the encoder", E_FAIL);
if (SUCCEEDED(avcodec_receive_packet(this->context, &pkt))) {
RET_IF_FAILED_AV(av_interleaved_write_frame(this->fmtContext, &pkt), "Could not write the received packet.", E_FAIL);
}
av_packet_unref(&pkt);
return S_OK;
}
HRESULT Session::endSession() {
LOG("Ending session...");
LOG("Closing files...");
av_write_trailer(this->fmtContext);
avio_close(this->fmtContext->pb);
avcodec_close(this->context);
av_free(this->context);
//fclose(this->file);
LOG("Done.");
return S_OK;
}The problem is that the generated file is not playable in either VLC or MPC-HC. However, MPC-HC reports following info in file properties :
General
Unique ID : 202978442142665779317960161865934977227 (0x98B439D9BE859109BD5EC00A62A238CB)
Complete name : T:\Test.mkv
Format : Matroska
Format version : Version 4 / Version 2
File size : 24.6 MiB
Duration : 147ms
Overall bit rate : 1 401 Mbps
Writing application : Lavf57.57.100
Writing library : Lavf57.57.100
Video
ID : 1
Format : FFV1
Format version : Version 0
Codec ID : V_MS/VFW/FOURCC / FFV1
Duration : 147ms
Width : 1 280 pixels
Height : 720 pixels
Display aspect ratio : 16:9
Frame rate mode : Constant
Frame rate : 1 000.000 fps
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Compression mode : Lossless
Default : Yes
Forced : No
DURATION : 00:00:00.147000000
coder_type : Golomb RiceSomething to note is that it reports 1000 FPS which is weird since I’ve set
AVCodecContext::time_base
in the code. -
ffmpeg : init filtergraphs only after we have a frame on each input
27 mai 2016, par Anton Khirnovffmpeg : init filtergraphs only after we have a frame on each input
This makes sure the actual stream parameters are used, which is
important mainly for hardware decoding+filtering cases, which would
previously require various weird workarounds to handle the fact that a
fake software graph has to be constructed, but never used.
This should also improve behaviour in rare cases where
avformat_find_stream_info() does not provide accurate information.This merges Libav commit a3a0230. It was previously skipped.
The code in flush_encoders() which sets up a "fake" format wasn’t in
Libav. I’m not sure if it’s a good idea, but it tends to give
behavior closer to the old one in certain corner cases.The vp8-size-change gives different result, because now the size of
the first frame is used. libavformat reported the size of the largest
frame for some reason.The exr tests now use the sample aspect ratio of the first frame. For
some reason libavformat determines 0/1 as aspect ratio, while the
decoder returns the correct one.The ffm and mxf tests change the field_order values. I’m assuming
another libavformat/decoding mismatch.Signed-off-by : wm4 <nfxjfg@googlemail.com>
- [DH] ffmpeg.c
- [DH] ffmpeg.h
- [DH] ffmpeg_cuvid.c
- [DH] ffmpeg_filter.c
- [DH] ffmpeg_opt.c
- [DH] ffmpeg_qsv.c
- [DH] tests/ref/fate/exr-rgb-scanline-pxr24-half-uint32-13x9
- [DH] tests/ref/fate/exr-rgba-scanline-float-half-b44-12x8-l1
- [DH] tests/ref/fate/exr-rgba-scanline-float-half-b44-12x8-l2
- [DH] tests/ref/fate/exr-rgba-scanline-float-half-b44-13x9-l1
- [DH] tests/ref/fate/exr-rgba-scanline-float-half-b44-13x9-l2
- [DH] tests/ref/fate/exr-rgba-scanline-float-half-b44a-12x8-l1
- [DH] tests/ref/fate/exr-rgba-scanline-float-half-b44a-12x8-l2
- [DH] tests/ref/fate/exr-rgba-scanline-float-half-b44a-13x9-l1
- [DH] tests/ref/fate/exr-rgba-scanline-float-half-b44a-13x9-l2
- [DH] tests/ref/fate/vp8-size-change
- [DH] tests/ref/lavf/ffm
- [DH] tests/ref/lavf/mxf