
Recherche avancée
Médias (1)
-
Collections - Formulaire de création rapide
19 février 2013, par
Mis à jour : Février 2013
Langue : français
Type : Image
Autres articles (111)
-
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 -
Soumettre bugs et patchs
10 avril 2011Un logiciel n’est malheureusement jamais parfait...
Si vous pensez avoir mis la main sur un bug, reportez le dans notre système de tickets en prenant bien soin de nous remonter certaines informations pertinentes : le type de navigateur et sa version exacte avec lequel vous avez l’anomalie ; une explication la plus précise possible du problème rencontré ; si possibles les étapes pour reproduire le problème ; un lien vers le site / la page en question ;
Si vous pensez avoir résolu vous même le bug (...)
Sur d’autres sites (10930)
-
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. -
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.


-
Revision 34537 : un pour englober le contenu principal de ...
17 janvier 2010, par cedric@… — Logun pour englober le contenu principal de chaque objet. Permet de cibler le debut ou la fin du contenu principal, ou, en passant par le parent, la fin du contenu.