Recherche avancée

Médias (91)

Autres articles (48)

  • MediaSPIP Player : les contrôles

    26 mai 2010, par

    Les contrôles à la souris du lecteur
    En plus des actions au click sur les boutons visibles de l’interface du lecteur, il est également possible d’effectuer d’autres actions grâce à la souris : Click : en cliquant sur la vidéo ou sur le logo du son, celui ci se mettra en lecture ou en pause en fonction de son état actuel ; Molette (roulement) : en plaçant la souris sur l’espace utilisé par le média (hover), la molette de la souris n’exerce plus l’effet habituel de scroll de la page, mais diminue ou (...)

  • L’agrémenter visuellement

    10 avril 2011

    MediaSPIP est basé sur un système de thèmes et de squelettes. Les squelettes définissent le placement des informations dans la page, définissant un usage spécifique de la plateforme, et les thèmes l’habillage graphique général.
    Chacun peut proposer un nouveau thème graphique ou un squelette et le mettre à disposition de la communauté.

  • ANNEXE : Les plugins utilisés spécifiquement pour la ferme

    5 mars 2010, par

    Le site central/maître de la ferme a besoin d’utiliser plusieurs plugins supplémentaires vis à vis des canaux pour son bon fonctionnement. le plugin Gestion de la mutualisation ; le plugin inscription3 pour gérer les inscriptions et les demandes de création d’instance de mutualisation dès l’inscription des utilisateurs ; le plugin verifier qui fournit une API de vérification des champs (utilisé par inscription3) ; le plugin champs extras v2 nécessité par inscription3 (...)

Sur d’autres sites (5254)

  • WebM file not seekable in Chrome, when generated with ffmpeg

    11 avril 2014, par Zoon

    I am having a mind-boggling problem, I just can't seem to resolve.

    Providing a WebM file through PHP is nothing new in my world, and I even know how to work with HTTP 206 Partial Content. But for some reason Chrome does not like it.

    A simple HTML5 video playback

    <video width="640" height="360" poster="picture/preview/V00000006.jpg" controls="controls" preload="preload">
       <source type="video/webm" src="/video/V00000006.webm">
    </source></video>

    where /video/V00000006.webm is rewritten to a PHP-file in Apache, will playback just fine.
    But in Chrome the seekbar is not effective. When clicking on the seekbar the player will freeze and no longer playback until page is refreshed. Firefox handles it just fine !

    If I change /video/V00000006.webm to be a direct link to the same video it works just fine. I even compared the network requests between the two versions (with and without PHP) and there is barely any difference in the first request, but the second is failing in the PHP-delivered video.

    Initial request and seek request for Apache-delivered video file :

        Request URL :http://mytestserver.net/movie1152x720.webm
        Request Method:GET
        Status Code:206 Partial Content
        Request Headers
        Accept :*/*
        Accept-Encoding:identity ;q=1, * ;q=0
        Accept-Language:da-DK,da ;q=0.8,en-US ;q=0.6,en ;q=0.4
        Cache-Control:no-cache
        Connection:keep-alive
        Cookie:PHPSESSID=i562540rek172mnv3nk528acj0 ; userPassword= ; userEmail=
        Host:mytestserver.net
        Pragma:no-cache
        Range:bytes=0-
        Referer :http://mytestserver.net/video.html
        User-Agent:Mozilla/5.0 (X11 ; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36
        Response Headers
        Accept-Ranges:bytes
        Connection:close
        Content-Length:4446451
        Content-Range:bytes 0-4446450/4446451
        Content-Type:video/webm
        Date:Fri, 11 Apr 2014 13:07:30 GMT
        ETag :"d2d0027-43d8f3-b91417c0"
        Last-Modified:Fri, 11 Apr 2014 12:46:31 GMT
        Server:Apache/2.2.3 (CentOS)
    

    Request URL :http://mytestserver.net/movie1152x720.webm
    Request Method:GET
    Status Code:206 Partial Content
    Request Headers
    Accept :*/*
    Accept-Encoding:identity ;q=1, * ;q=0
    Accept-Language:da-DK,da ;q=0.8,en-US ;q=0.6,en ;q=0.4
    Cache-Control:no-cache
    Connection:keep-alive
    Cookie:PHPSESSID=i562540rek172mnv3nk528acj0 ; userPassword= ; userEmail=
    Host:mytestserver.net
    Pragma:no-cache
    Range:bytes=4445881-
    Referer :http://mytestserver.net/video.html
    User-Agent:Mozilla/5.0 (X11 ; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36
    Response Headers
    Accept-Ranges:bytes
    Connection:close
    Content-Length:570
    Content-Range:bytes 4445881-4446450/4446451
    Content-Type:video/webm
    Date:Fri, 11 Apr 2014 13:09:02 GMT
    ETag :"d2d0027-43d8f3-b91417c0"
    Last-Modified:Fri, 11 Apr 2014 12:46:31 GMT
    Server:Apache/2.2.3 (CentOS)

    Initial request and seek request for PHP-streamed video :

        Request URL :http://mytestserver.net/video/V00000006.webm
        Request Method:GET
        Status Code:206 Partial Content
        Request Headers
        Accept :*/*
        Accept-Encoding:identity ;q=1, * ;q=0
        Accept-Language:da-DK,da ;q=0.8,en-US ;q=0.6,en ;q=0.4
        Cache-Control:no-cache
        Connection:keep-alive
        Cookie:PHPSESSID=i562540rek172mnv3nk528acj0 ; userPassword= ; userEmail=
        Host:mytestserver.net
        Pragma:no-cache
        Range:bytes=0-
        Referer :http://mytestserver.net/video.html
        User-Agent:Mozilla/5.0 (X11 ; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36
        Response Headers
        Accept-Ranges:bytes
        Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0
        Connection:close
        Content-Length:8566268
        Content-Range:bytes 0-8566267/8566268
        Content-Type:video/webm
        Date:Fri, 11 Apr 2014 13:31:27 GMT
        Expires:Thu, 19 Nov 1981 08:52:00 GMT
        Pragma:no-cache
        Server:Apache/2.2.3 (CentOS)
        X-Powered-By:PHP/5.3.27
    

    Request URL :http://mytestserver.net/video/V00000006.webm
    Request Headers CAUTION : Provisional headers are shown.
    Accept-Encoding:identity ;q=1, * ;q=0
    Cache-Control:no-cache
    Pragma:no-cache
    Range:bytes=4338314-
    Referer :http://mytestserver.net/video.html
    User-Agent:Mozilla/5.0 (X11 ; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36

    Notice how the second request does not complete, Provisional headers are shown.

    I have tried altering the cache headers, setting it to the future, setting them blank and using file attachment headers.

    I tried fiddling around a lot with the serving code, but lately I have ended up with a simple example.

    &lt;?php

    $path = &#39;test.webm&#39;;

    $size=filesize($path);

    $fm=@fopen($path,&#39;rb&#39;);
    if(!$fm) {
     header ("HTTP/1.0 404 Not Found");
     die();
    }

    $begin=0;
    $end = $size-1;

    if(isset($_SERVER[&#39;HTTP_RANGE&#39;])) {
     if(preg_match(&#39;/bytes=\h*(\d+)-(\d*)[\D.*]?/i&#39;, $_SERVER[&#39;HTTP_RANGE&#39;], $matches)) {
       $begin=intval($matches[0]);
       if(!empty($matches[1])) {
         $end=intval($matches[1]);
       }
     }
    }

    if($begin>0||$end&lt;$size)
     header(&#39;HTTP/1.0 206 Partial Content&#39;);
    else
     header(&#39;HTTP/1.0 200 OK&#39;);

    header("Content-Type: video/webm");
    header(&#39;Accept-Ranges: bytes&#39;);
    header(&#39;Content-Length:&#39;.($end-$begin+1));
    header("Content-Disposition: inline;");
    header("Content-Range: bytes $begin-$end/$size");
    header("Content-Transfer-Encoding: binary\n");
    header(&#39;Connection: close&#39;);

    ob_get_clean();
    flush();

    $f = fopen($path, &#39;r&#39;);
    fseek($f, $offset);

    $pos = 0;
    $length = $end-$begin;

    while($pos &lt; $length)
    {
       $chunk = min($length-$pos, 1024);

       echo fread($f, $chunk);
       flush();

       $pos += $chunk;
    }
    ?>

    Please note, entering the PHP-delivered video URL directly into the browser does not make a difference from showing it in a HTML page.

    I hope someone has an answer to why seeking might not work. Let me know if you have any suggestions.

    Thanks !

  • offloading to ffmpeg via named pipes in c#/dotnet core

    1er avril 2022, par bep

    I tried to break this down to the base elements so I hope this is clear. I want to take in a network stream, it may be a 1 way, it may be a protocol that requires 2 way communication, such as RTMP during handshake.

    &#xA;

    I want to pass that stream straight through to a spawned FFMPEG process. I then want to capture the output of FFMPEG, in this example I just want to pipe it out to a file. The file is not my end goal, but for simplicity if I can get that far I think I'll be ok.

    &#xA;

    enter image description here

    &#xA;

    I want the code to be as plain as possible and offload the core processing to FFMPEG. If I ask FFMPEG to output webrtc stream, a file, whatever, I just want to capture that. FFMPEG shouldn't be used directly, just indirectly via IncomingConnectionHandler.

    &#xA;

    Only other component is OBS, which I am using to create the RTMP stream coming in.

    &#xA;

    As things stand now, running this results in the following error, which I'm a little unclear on. I don't feel like I'm causing concurrent reads at any point.

    &#xA;

    System.InvalidOperationException: Concurrent reads are not allowed&#xA;         at Medallion.Shell.Throw`1.If(Boolean condition, String message)&#xA;         at Medallion.Shell.Streams.Pipe.ReadAsync(Byte[] buffer, Int32 offset, Int32 count, TimeSpan timeout, CancellationToken cancellationToken)&#xA;         at Medallion.Shell.Streams.Pipe.PipeOutputStream.ReadAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)&#xA;         at System.IO.Stream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)&#xA;         at System.IO.StreamReader.ReadBufferAsync(CancellationToken cancellationToken)&#xA;         at System.IO.StreamReader.ReadLineAsyncInternal()&#xA;         at Medallion.Shell.Streams.MergedLinesEnumerable.GetEnumeratorInternal()&#x2B;MoveNext()&#xA;         at System.String.Join(String separator, IEnumerable`1 values)&#xA;         at VideoIngest.IncomingRtmpConnectionHandler.OnConnectedAsync(ConnectionContext connection) in Program.cs:line 55&#xA;         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.KestrelConnection`1.ExecuteAsync()&#xA;

    &#xA;

    Code :

    &#xA;

    namespace VideoIngest&#xA;{&#xA;    public class IncomingRtmpConnectionHandler : ConnectionHandler&#xA;    {&#xA;        private readonly ILogger<incomingrtmpconnectionhandler> logger;&#xA;&#xA;        public IncomingRtmpConnectionHandler(ILogger<incomingrtmpconnectionhandler> logger)&#xA;        {&#xA;            this.logger = logger;&#xA;        }&#xA;&#xA;        public override async Task OnConnectedAsync(ConnectionContext connection)&#xA;        {&#xA;            logger?.LogInformation("connection started");&#xA;&#xA;            var outputFileName = @"C:\Temp\bunny.mp4";&#xA;&#xA;            var rtmpPassthroughPipeName = Guid.NewGuid().ToString();&#xA;            var cmdPath = @"C:\Opt\ffmpeg\bin\ffmpeg.exe";&#xA;            var cmdArgs = $"-i pipe:{rtmpPassthroughPipeName} -preset slow -c copy -f mp4 -y pipe:1";&#xA;&#xA;            var cancellationToken = connection.ConnectionClosed;&#xA;            var rtmpStream = connection.Transport;&#xA;&#xA;            using (var outputStream = new FileStream(outputFileName, FileMode.Create))&#xA;            using (var cmd = Command.Run(cmdPath, options: o => { o.StartInfo(i => i.Arguments = cmdArgs); o.CancellationToken(cancellationToken); }))&#xA;            {&#xA;                // create a pipe to pass the RTMP data straight to FFMPEG. This code should be dumb to proto etc being used&#xA;                var ffmpegPassthroughStream = new NamedPipeServerStream(rtmpPassthroughPipeName, PipeDirection.InOut, 10, PipeTransmissionMode.Byte, System.IO.Pipes.PipeOptions.Asynchronous);&#xA;&#xA;                // take the network stream and pass data to/from ffmpeg process&#xA;                var fromFfmpegTask = ffmpegPassthroughStream.CopyToAsync(rtmpStream.Output.AsStream(), cancellationToken);&#xA;                var toFfmpegTask = rtmpStream.Input.AsStream().CopyToAsync(ffmpegPassthroughStream, cancellationToken);&#xA;&#xA;                // take the ffmpeg process output (not stdout) into target file&#xA;                var outputTask = cmd.StandardOutput.PipeToAsync(outputStream);&#xA;&#xA;                while (!outputTask.IsCompleted &amp;&amp; !outputTask.IsCanceled)&#xA;                {&#xA;                    var errs = cmd.GetOutputAndErrorLines();&#xA;                    logger.LogInformation(string.Join(Environment.NewLine, errs));&#xA;&#xA;                    await Task.Delay(1000);&#xA;                }&#xA;&#xA;                CommandResult result = result = cmd.Result;&#xA;&#xA;                if (result != null &amp;&amp; result.Success)&#xA;                {&#xA;                    logger.LogInformation("Created file");&#xA;                }&#xA;                else&#xA;                {&#xA;                    logger.LogError(result.StandardError);&#xA;                }&#xA;            }&#xA;&#xA;            logger?.LogInformation("connection closed");&#xA;        }&#xA;    }&#xA;&#xA;    public class Startup&#xA;    {&#xA;        public void ConfigureServices(IServiceCollection services) { }&#xA;&#xA;        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)&#xA;        {&#xA;            app.Run(async (context) =>&#xA;            {&#xA;                var log = context.RequestServices.GetRequiredService>();&#xA;                await context.Response.WriteAsync("Hello World!");&#xA;            });&#xA;        }&#xA;    }&#xA;&#xA;    public class Program&#xA;    {&#xA;        public static void Main(string[] args)&#xA;        {&#xA;            CreateHostBuilder(args).Build().Run();&#xA;        }&#xA;&#xA;        public static IWebHostBuilder CreateHostBuilder(string[] args) =>&#xA;            WebHost&#xA;                .CreateDefaultBuilder(args)&#xA;                .ConfigureServices(services =>&#xA;                {&#xA;                    services.AddLogging(options =>&#xA;                    {&#xA;                        options.AddDebug().AddConsole().SetMinimumLevel(LogLevel.Information);&#xA;                    });&#xA;                })&#xA;                .UseKestrel(options =>&#xA;                {&#xA;                    options.ListenAnyIP(15666, builder =>&#xA;                    {&#xA;                        builder.UseConnectionHandler<incomingrtmpconnectionhandler>();&#xA;                    });&#xA;&#xA;                    options.ListenLocalhost(5000);&#xA;&#xA;                    // HTTPS 5001&#xA;                    options.ListenLocalhost(5001, builder =>&#xA;                    {&#xA;                        builder.UseHttps();&#xA;                    });&#xA;                })&#xA;                .UseStartup<startup>();&#xA;    }&#xA;    &#xA;&#xA;}&#xA;</startup></incomingrtmpconnectionhandler></incomingrtmpconnectionhandler></incomingrtmpconnectionhandler>

    &#xA;

    Questions :

    &#xA;

      &#xA;
    1. Is this a valid approach, do you see any fundamental issues ?
    2. &#xA;

    3. Is the pipe naming correct, is the convention just pipe:someName ?
    4. &#xA;

    5. Any ideas on what specifically may be causing the Concurrent reads are not allowed ?
    6. &#xA;

    7. If #3 is solved, does the rest of this seem valid ?
    8. &#xA;

    &#xA;

  • Fill patterns

    26 avril 2008, par Mikko Koppanen — Imagick, PHP stuff

    My work life has been quite busy lately and I haven’t had a chance to sit down and blog. I have been touring around London and some parts of the northern England consulting and organizing some training here and there. Luckily I have had the chance to do some work on Imagick and the 2.2.0 beta release is getting closer. The internal structure was completely restructured and broken down into several smaller files. During this time Imagick was adapted to follow the PHP Coding Standards more closely. Still a work in progress :)

    I committed slightly modified version of this example to PHP Manual http://uk.php.net/manual/en/imagick.examples.php page a few days ago. The example illustrates using an image as a part of a named fill pattern. The fill pattern is used to annotate text but the named pattern could also be used to fill any shapes that allow fill to be specified (include circles, ellipses, rectangles, polygons etc etc). The code itself is pretty straight forward : Read the image, create the pattern and use the pattern as a fill.

    The ice formations image is from http://www.photoeverywhere.co.uk/west/winterholiday/slides/iceformations5679.htm.

    1. < ?php
    2.  
    3. /* Create a new imagick object */
    4. $im = new Imagick( ’iceformations5679.JPG’ ) ;
    5.  
    6. /* Create imagickdraw object */
    7. $draw = new ImagickDraw() ;
    8.  
    9. /* Start a new pattern called "ice" */
    10. $draw->pushPattern( ’ice’ , 0 , 0 , 50 , 50 ) ;
    11.  
    12. /* Composite the image on the pattern */
    13. $draw->composite( Imagick: :COMPOSITE_OVER, 0, 0, 50, 50, $im ) ;
    14.  
    15. /* Close the pattern */
    16. $draw->popPattern() ;
    17.  
    18. /* Use the pattern called "ice" as the fill */
    19. $draw->setFillPatternURL( ’#ice’ ) ;
    20.  
    21. /* Set font size to 52 */
    22. $draw->setFontSize( 52 ) ;
    23.  
    24. /* Annotate some text */
    25. $draw->annotation( 5, 50, "Hello World !" ) ;
    26.  
    27. /* Create a new canvas and white image */
    28. $canvas = new Imagick() ;
    29. $canvas->newImage( 310, 70, "white" ) ;
    30.  
    31. /* Add black border around the resulting image */
    32. $canvas->borderImage( ’black’, 1, 1 ) ;
    33.  
    34. /* Draw the ImagickDraw on to the canvas */
    35. $canvas->drawImage( $draw ) ;
    36.  
    37. /* Set the format to PNG */
    38. $canvas->setImageFormat( ’png’ ) ;
    39.  
    40. /* Output the image */
    41. header( "Content-Type : image/png" ) ;
    42. echo $canvas ;
    43.  ?>

    And the result is here :