Recherche avancée

Médias (91)

Autres articles (87)

  • Les tâches Cron régulières de la ferme

    1er décembre 2010, par

    La gestion de la ferme passe par l’exécution à intervalle régulier de plusieurs tâches répétitives dites Cron.
    Le super Cron (gestion_mutu_super_cron)
    Cette tâche, planifiée chaque minute, a pour simple effet d’appeler le Cron de l’ensemble des instances de la mutualisation régulièrement. Couplée avec un Cron système sur le site central de la mutualisation, cela permet de simplement générer des visites régulières sur les différents sites et éviter que les tâches des sites peu visités soient trop (...)

  • Encoding and processing into web-friendly formats

    13 avril 2011, par

    MediaSPIP automatically converts uploaded files to internet-compatible formats.
    Video files are encoded in MP4, Ogv and WebM (supported by HTML5) and MP4 (supported by Flash).
    Audio files are encoded in MP3 and Ogg (supported by HTML5) and MP3 (supported by Flash).
    Where possible, text is analyzed in order to retrieve the data needed for search engine detection, and then exported as a series of image files.
    All uploaded files are stored online in their original format, so you can (...)

  • MediaSPIP Player : problèmes potentiels

    22 février 2011, par

    Le lecteur ne fonctionne pas sur Internet Explorer
    Sur Internet Explorer (8 et 7 au moins), le plugin utilise le lecteur Flash flowplayer pour lire vidéos et son. Si le lecteur ne semble pas fonctionner, cela peut venir de la configuration du mod_deflate d’Apache.
    Si dans la configuration de ce module Apache vous avez une ligne qui ressemble à la suivante, essayez de la supprimer ou de la commenter pour voir si le lecteur fonctionne correctement : /** * GeSHi (C) 2004 - 2007 Nigel McNie, (...)

Sur d’autres sites (11439)

  • Issues with Publishing and Subscribing Rates for H.264 Video Streaming over RabbitMQ

    7 octobre 2024, par Luis

    I am working on a project to stream an H.264 video file using RabbitMQ (AMQP protocol) and display it in a web application. The setup involves capturing video frames, encoding them, sending them to RabbitMQ, and then consuming and decoding them on the web application side using Flask and Flask-SocketIO.

    


    However, I am encountering performance issues with the publishing and subscribing rates in RabbitMQ. I cannot seem to achieve more than 10 messages per second. This is not sufficient for smooth video streaming.
I need help to diagnose and resolve these performance bottlenecks.

    


    Here is my code :

    


      

    • Video Capture and Publishing Script :
    • 


    


    # RabbitMQ setup
RABBITMQ_HOST = 'localhost'
EXCHANGE = 'DRONE'
CAM_LOCATION = 'Out_Front'
KEY = f'DRONE_{CAM_LOCATION}'
QUEUE_NAME = f'DRONE_{CAM_LOCATION}_video_queue'

# Path to the H.264 video file
VIDEO_FILE_PATH = 'videos/FPV.h264'

# Configure logging
logging.basicConfig(level=logging.INFO)

@contextmanager
def rabbitmq_channel(host):
    """Context manager to handle RabbitMQ channel setup and teardown."""
    connection = pika.BlockingConnection(pika.ConnectionParameters(host))
    channel = connection.channel()
    try:
        yield channel
    finally:
        connection.close()

def initialize_rabbitmq(channel):
    """Initialize RabbitMQ exchange and queue, and bind them together."""
    channel.exchange_declare(exchange=EXCHANGE, exchange_type='direct')
    channel.queue_declare(queue=QUEUE_NAME)
    channel.queue_bind(exchange=EXCHANGE, queue=QUEUE_NAME, routing_key=KEY)

def send_frame(channel, frame):
    """Encode the video frame using FFmpeg and send it to RabbitMQ."""
    ffmpeg_path = 'ffmpeg/bin/ffmpeg.exe'
    cmd = [
        ffmpeg_path,
        '-f', 'rawvideo',
        '-pix_fmt', 'rgb24',
        '-s', '{}x{}'.format(frame.shape[1], frame.shape[0]),
        '-i', 'pipe:0',
        '-f', 'h264',
        '-vcodec', 'libx264',
        '-pix_fmt', 'yuv420p',
        '-preset', 'ultrafast',
        'pipe:1'
    ]
    
    start_time = time.time()
    process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, err = process.communicate(input=frame.tobytes())
    encoding_time = time.time() - start_time
    
    if process.returncode != 0:
        logging.error("ffmpeg error: %s", err.decode())
        raise RuntimeError("ffmpeg error")
    
    frame_size = len(out)
    logging.info("Sending frame with shape: %s, size: %d bytes", frame.shape, frame_size)
    timestamp = time.time()
    formatted_timestamp = datetime.fromtimestamp(timestamp).strftime('%H:%M:%S.%f')
    logging.info(f"Timestamp: {timestamp}") 
    logging.info(f"Formatted Timestamp: {formatted_timestamp[:-3]}")
    timestamp_bytes = struct.pack('d', timestamp)
    message_body = timestamp_bytes + out
    channel.basic_publish(exchange=EXCHANGE, routing_key=KEY, body=message_body)
    logging.info(f"Encoding time: {encoding_time:.4f} seconds")

def capture_video(channel):
    """Read video from the file, encode frames, and send them to RabbitMQ."""
    if not os.path.exists(VIDEO_FILE_PATH):
        logging.error("Error: Video file does not exist.")
        return
    cap = cv2.VideoCapture(VIDEO_FILE_PATH)
    if not cap.isOpened():
        logging.error("Error: Could not open video file.")
        return
    try:
        while True:
            start_time = time.time()
            ret, frame = cap.read()
            read_time = time.time() - start_time
            if not ret:
                break
            frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame_rgb = np.ascontiguousarray(frame_rgb) # Ensure the frame is contiguous
            send_frame(channel, frame_rgb)
            cv2.imshow('Video', frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
            logging.info(f"Read time: {read_time:.4f} seconds")
    finally:
        cap.release()
        cv2.destroyAllWindows()


    


      

    • the backend (flask) :
    • 


    


    app = Flask(__name__)
CORS(app)
socketio = SocketIO(app, cors_allowed_origins="*")

RABBITMQ_HOST = 'localhost'
EXCHANGE = 'DRONE'
CAM_LOCATION = 'Out_Front'
QUEUE_NAME = f'DRONE_{CAM_LOCATION}_video_queue'

def initialize_rabbitmq():
    connection = pika.BlockingConnection(pika.ConnectionParameters(RABBITMQ_HOST))
    channel = connection.channel()
    channel.exchange_declare(exchange=EXCHANGE, exchange_type='direct')
    channel.queue_declare(queue=QUEUE_NAME)
    channel.queue_bind(exchange=EXCHANGE, queue=QUEUE_NAME, routing_key=f'DRONE_{CAM_LOCATION}')
    return connection, channel

def decode_frame(frame_data):
    # FFmpeg command to decode H.264 frame data
    ffmpeg_path = 'ffmpeg/bin/ffmpeg.exe'
    cmd = [
        ffmpeg_path,
        '-f', 'h264',
        '-i', 'pipe:0',
        '-pix_fmt', 'bgr24',
        '-vcodec', 'rawvideo',
        '-an', '-sn',
        '-f', 'rawvideo',
        'pipe:1'
    ]
    process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    start_time = time.time()  # Start timing the decoding process
    out, err = process.communicate(input=frame_data)
    decoding_time = time.time() - start_time  # Calculate decoding time
    
    if process.returncode != 0:
        print("ffmpeg error: ", err.decode())
        return None
    frame_size = (960, 1280, 3)  # frame dimensions expected by the frontend
    frame = np.frombuffer(out, np.uint8).reshape(frame_size)
    print(f"Decoding time: {decoding_time:.4f} seconds")
    return frame

def format_timestamp(ts):
    dt = datetime.fromtimestamp(ts)
    return dt.strftime('%H:%M:%S.%f')[:-3]

def rabbitmq_consumer():
    connection, channel = initialize_rabbitmq()
    for method_frame, properties, body in channel.consume(QUEUE_NAME):
        message_receive_time = time.time()  # Time when the message is received

        # Extract the timestamp from the message body
        timestamp_bytes = body[:8]
        frame_data = body[8:]
        publish_timestamp = struct.unpack('d', timestamp_bytes)[0]

        print(f"Message Receive Time: {message_receive_time:.4f} ({format_timestamp(message_receive_time)})")
        print(f"Publish Time: {publish_timestamp:.4f} ({format_timestamp(publish_timestamp)})")

        frame = decode_frame(frame_data)
        decode_time = time.time() - message_receive_time  # Calculate decode time

        if frame is not None:
            _, buffer = cv2.imencode('.jpg', frame)
            frame_data = buffer.tobytes()
            socketio.emit('video_frame', {'frame': frame_data, 'timestamp': publish_timestamp}, namespace='/')
            emit_time = time.time()  # Time after emitting the frame

            # Log the time taken to emit the frame and its size
            rtt = emit_time - publish_timestamp  # Calculate RTT from publish to emit
            print(f"Current Time: {emit_time:.4f} ({format_timestamp(emit_time)})")
            print(f"RTT: {rtt:.4f} seconds")
            print(f"Emit time: {emit_time - message_receive_time:.4f} seconds, Frame size: {len(frame_data)} bytes")
        channel.basic_ack(method_frame.delivery_tag)

@app.route('/')
def index():
    return render_template('index.html')

@socketio.on('connect')
def handle_connect():
    print('Client connected')

@socketio.on('disconnect')
def handle_disconnect():
    print('Client disconnected')

if __name__ == '__main__':
    consumer_thread = threading.Thread(target=rabbitmq_consumer)
    consumer_thread.daemon = True
    consumer_thread.start()
    socketio.run(app, host='0.0.0.0', port=5000)



    


    How can I optimize the publishing and subscribing rates to handle a higher number of messages per second ?

    


    Any help or suggestions would be greatly appreciated !

    


    I attempted to use threading and multiprocessing to handle multiple frames concurrently and I tried to optimize the frame decoding function to make it faster but with no success.

    


  • Streaming issues with HLS setup using Nginx and FFmpeg, and TS video files

    12 septembre 2024, par Jacob Anderson

    I've been working on setting up an HLS stream on my Raspberry Pi to broadcast video from a security camera that's physically connected to my Raspberry Pi through my web server, making it accessible via my website. The .ts video files and the .m3u8 playlist are correctly being served from /var/www/html/hls. However, when I attempt to load the stream on Safari (as well as other browsers), the video continuously appears to be loading without ever displaying any content.

    


    Here are some details about my setup :

    


      

    • Camera : I am using an Arducam 1080p Day & Night Vision USB Camera which is available on /dev/video0.
    • 


    • Server Configuration : I haven't noticed any errors in the Safari console or on the server logs. When I access the .ts files directly from the browser, they only show a black screen but they do play.
    • 


    


    Given the situation, I suspect there might be an issue with my FFmpeg command or possibly with my Nginx configuration.

    


    Here is what I have :

    


    ffmpeg stream service :
/etc/systemd/system/ffmpeg-stream.service

    


    [Unit]
Description=FFmpeg RTMP Stream
After=network.target

[Service]
ExecStart=/usr/local/bin/start_ffmpeg.sh
Restart=always
User=jacobanderson
Group=jacobanderson
StandardError=syslog
SyslogIdentifier=ffmpeg-stream
Environment=FFMPEG_LOGLEVEL=error

[Install]
WantedBy=multi-user.target


    


    ffmpeg command :
/usr/local/bin/start_ffmpeg.sh

    


    #!/bin/bash

/usr/bin/ffmpeg -f v4l2 -input_format mjpeg -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec libx264 -preset veryfast -acodec aac -strict -2 -f flv rtmp://localhost/live/


    


    nginx.conf :
/etc/nginx/nginx.conf

    


    user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 768;
    # multi_accept on;
}

rtmp {
    server {
        listen 1935;
        chunk_size 4096;
        #allow publish 127.0.0.1;
        #deny publish all;

    application live {
        #allow 192.168.0.100;
        live on;
        hls on;
        hls_path /var/www/html/hls;
        hls_fragment 3;
        hls_nested on; 
        #hls_fragment_naming stream;
        hls_playlist_length 120;
        hls_cleanup on;
        hls_continuous on;
        #deny play all;
    }
    }
}

http {
    ##
    # Basic Settings
    ##

    sendfile on;
    #sendfile off;
    tcp_nopush on;
    types_hash_max_size 2048;
    # server_tokens off;

    # Additional for video
    directio 512;

    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # SSL Settings
    ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    #ssl_protocols TLSv1.2 TLSv1.3; # Use only secure protocols
    ssl_prefer_server_ciphers on;
    #ssl_ciphers "HIGH:!aNULL:!MD5";

    ##
    # Logging Settings
    ##

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ##
    # Gzip Settings
    ##

    #gzip on;
    gzip off;  # Ensure gzip is off for HLS

    ##
    # Virtual Host Configs
    ##

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}


    


    sites-available :
/etc/nginx/sites-available/myStream.mysite.com

    


    server {
    listen 443 ssl;
    server_name myStream.mysite.com;

    ssl_certificate /etc/letsencrypt/live/myStream.mysite.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/myStream.mysite.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    location / {
        root /var/www/html/hls;
        index index.html;
    }

    location /hls {
        # Password protection
        auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;

        # Disable cache
        add_header Cache-Control no-cache;

        # CORS setup
        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Expose-Headers' 'Content-Length';

        # Allow CORS preflight requests
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            add_header 'Content-Length' 0;
            return 204;
        }

        types {
            application/vnd.apple.mpegurl m3u8;
            video/mp2t ts;
        text/html html;
        text/css css;
        }

    root /var/www/html;
    }
}

server {
    listen 80;
    server_name myStream.mysite.com;

    if ($host = myStream.mysite.com) {
        return 301 https://$host$request_uri;
    }

    return 404; # managed by Certbot
}


    


    index.html :
/var/www/html/hls/index.html

    


    &#xA;&#xA;&#xA;    &#xA;    &#xA;    &#xA;    &#xA;    <code class="echappe-js">&lt;script src='http://stackoverflow.com/feeds/tag/js/hls.min.js'&gt;&lt;/script&gt;&#xA;&#xA;&#xA;    &#xA;        &#xA;    &#xA;    &#xA;&#xA;    &lt;script src=&quot;https://vjs.zencdn.net/7.10.2/video.js&quot;&gt;&lt;/script&gt;&#xA;    &lt;script&gt;&amp;#xA;        if (Hls.isSupported()) {&amp;#xA;            var video = document.getElementById(&amp;#x27;my-video_html5_api&amp;#x27;); // Updated ID to target the correct video element&amp;#xA;            var hls = new Hls();&amp;#xA;            hls.loadSource(&amp;#x27;https://myStream.mysite.com/hls/index.m3u8&amp;#x27;);&amp;#xA;            hls.attachMedia(video);&amp;#xA;            hls.on(Hls.Events.MANIFEST_PARSED,function() {&amp;#xA;                video.play();&amp;#xA;            });&amp;#xA;        } else if (video.canPlayType(&amp;#x27;application/vnd.apple.mpegurl&amp;#x27;)) {&amp;#xA;            video.src = &amp;#x27;https://myStream.mysite.com/hls/index.m3u8&amp;#x27;;&amp;#xA;            video.addEventListener(&amp;#x27;loadedmetadata&amp;#x27;, function() {&amp;#xA;                video.play();&amp;#xA;            });&amp;#xA;        }&amp;#xA;    &lt;/script&gt;&#xA;&#xA;&#xA;

    &#xA;

    Has anyone experienced similar issues or can spot an error in my configuration ? Any help would be greatly appreciated as I have already invested over 30 hours trying to resolve this.

    &#xA;

  • Updating isoparser-1.0-RC-37 from isoparser-1.0-RC-15 issues in getDecodingTimeEntries()

    5 janvier 2017, par Rakki s

    I found sample code to cut the video based on the duration from Link,
    but i cannot find method getDecodingTimeEntries() in isoparser-1.0-RC-37. It’s available in the older version of isoparser(-1.0-RC-15).

    So my question are.

    • Why that methode removed from the update jar ?

    • Is there any alternate method available ?

    • Any one have example source to trim(Cut by duration) using
      isoparser-1.0-RC-37 jar.