Newest 'ffmpeg' Questions - Stack Overflow

http://stackoverflow.com/questions/tagged/ffmpeg

Les articles publiés sur le site

  • Decoding the h.264 stream from a serial port

    18 mars, par Peter

    I would like to know if there is a reliable way to decode an H.264 NAL stream coming through a serial port using software.

    So far, I have managed to decode a single frame using a python script. In this script, I first write the incoming data to a file, and when the end-of-frame marker 00_00_00_01 appears, I display the frame using ffplay.

    import serial
    import subprocess
    import os
    import time
    
    ser = serial.Serial('COM3', 115200, timeout=1)
    output_file = "output.264"
    
    # Variable to store the ffplay process
    ffplay_process = None
    
    # Open the file for writing in binary mode
    with open(output_file, "wb") as file:
    
        print("Writing bytes to output.264. Waiting for the end-of-frame marker 0x00000001.")
    
        buffer = bytearray()
        marker = b'\x00\x00\x00\x01'
    
        try:
            while True:
                if ser.in_waiting:  # If there is data in the buffer
                    data = ser.read(ser.in_waiting)  # Read all available bytes
                    buffer.extend(data)
    
                    # Check if the end-of-frame marker is in the buffer
                    while marker in buffer:
                        index = buffer.index(marker) + len(marker)  # Position after the marker
                        frame = buffer[:index]  # Extract the frame
                        buffer = buffer[index:]  # Keep the remaining data
    
                        print(f"Frame recorded: {len(frame)} bytes")
                        file.write(frame)  # Write the frame to the file
                        file.flush()  # Force writing to disk
    
                        # Close the ffplay window if it is already open
                        if ffplay_process and ffplay_process.poll() is None:
                            ffplay_process.terminate()
                            ffplay_process.wait()  # Wait for the process to terminate
    
                        # Play the recorded frame, reopening the window
                        ffplay_process = subprocess.Popen(["ffplay", "-f", "h264", "-i", output_file])
    
        except KeyboardInterrupt:
            print("\nRecording stopped.")
        finally:
            # Close the serial port and the ffplay process
            ser.close()
    

    However, each time a new end-of-frame marker is detected, the ffplay window closes and reopens to show the next frame. It will flicker when transferring the video. Is there a way to display the frames in the same window for seamless playback when streaming video?

    Or is there a better approach or software that is more suited for this task? I do not know where to start, so I will be glad for any hints.

  • Problems encoding audio stream for RTMP server using ffmpeg libraries

    18 mars, par Filipe José

    I am working on an C++ application that captures audio using miniaudio, and sends the data to a RTMP server running on nginx which will generate an HLS stream to be consumed by a web browser. I was successful in encoding the data and writing to an .flv file (which I believe to be the container for RTMP), and everything works out fine.

    I've also tested the server by running the ffmpeg cli tool directly, and the RTMP server is generating the .m3u8 playlist file as well as the .ts files correctly.

    The problem I'm having is that when I change the output on avio_open2() to use the RTMP server url instead of a file name, the HLS files are not being generated, even though I get logging information about a successful connection, and also see "Audio Data" packets being sent to the server and the respective ACK response when using Wireshark.

    Is there anything that is conceptually different between encoding to a file or to a server when using the ffmpeg libav?

    I have a class for the audio encoding:

    AudioEncoder(int sampleRate){
      av_log_set_level(AV_LOG_DEBUG);
      m_formatContext = avformat_alloc_context();
      const AVOutputFormat* outputFormat = av_guess_format("flv", NULL, NULL);
      if (!outputFormat) {
        std::cerr << "Could not find aac output format" << std::endl;
        exit(-1);
      }
      m_formatContext->oformat = outputFormat;
    
      result = avio_open2(&m_ioContext, "rtmp://localhost/live/test",AVIO_FLAG_WRITE, NULL, NULL);
      if( result < 0){
        std::cerr << "Could not open output stream: " << error_string(result) << std::endl;
        exit(-1); 
      }
      m_formatContext->pb = m_ioContext;
      
      const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
      if(!codec){
        std::cerr << "Codec not found." << std::endl;
        exit(-1);
      }
      
      m_codecContext = avcodec_alloc_context3(codec);
      if (!m_codecContext) {
        std::cerr << "Could not alloc codec context" << std::endl;
        exit(-1);
      }
      AVChannelLayout layout;
      av_channel_layout_default(&layout, 1);
      m_codecContext->sample_fmt = AV_SAMPLE_FMT_FLTP;
      m_codecContext->bit_rate = 128000;
      m_codecContext->sample_rate = sampleRate;
      m_codecContext->ch_layout = layout;
    
      m_avStream = avformat_new_stream(m_formatContext, codec);
      if (!m_avStream) {
        std::cerr << "Could not create stream." << std::endl;
        exit(-1);
      } 
      result = avcodec_parameters_from_context(m_avStream->codecpar, m_codecContext);
      if ( result < 0) {
        std::cerr << "Failed to copy codec parameters to stream: " << error_string(result) << std::endl;
        exit(-1);
      }
      m_avStream->time_base = AVRational{1, m_codecContext->sample_rate};
    
      result = avcodec_open2(m_codecContext, codec, NULL);
      if ( result < 0) {
        std::cerr << "Failed to open codec: "<< error_string(result) << std::endl;
        exit(-1);
      }
    
      result = avformat_write_header(m_formatContext, NULL);
      if ( result < 0) {
        std::cerr << "Failed to write format header: "<< error_string(result) << std::endl;
        exit(-1);
      }
    }
    

    And an Encode function that is called by miniaudio:

    void Encode(const void* data, unsigned int frames){
      AVPacket* packet = av_packet_alloc();
      if (!packet) {
        std::cerr << "Error allocating packet" << std::endl;
        return;
      }
    
      AVFrame* frame = av_frame_alloc();
      if (!frame) {
        std::cerr << "Error allocating frame" << std::endl;
        av_packet_free(&packet);
        return;
      }
      frame->format = m_codecContext->sample_fmt;
      frame->ch_layout = m_codecContext->ch_layout;
      frame->sample_rate = m_codecContext -> sample_rate;
      frame->nb_samples = frames;
      if (frames) {
        int result = av_frame_get_buffer(frame, 0);
        if ( result < 0) {
          std::cerr << "Error allocating frame buffer: " << error_string(result) << std::endl;
          av_frame_free(&frame);
          av_packet_free(&packet);
          return;
        }
      }
      frame->data[0] = (uint8_t*)data;
    
      int result = avcodec_send_frame(m_codecContext, frame); 
      if (result < 0) {
        std::cerr << "Error sending frame to encoder: " << error_string(result) << std::endl; 
      }
    
      result = avcodec_receive_packet(m_codecContext, packet); 
      if (result == AVERROR(EAGAIN) || result == AVERROR_EOF) {
        std::cout << "EAGAIN" << std::endl;
        // If we get AVERROR_EAGAIN, the encoder needs more data, so we'll return and try again later
        av_frame_free(&frame);
        av_packet_free(&packet);
        return;
      } else if (result < 0) {
        std::cerr << "Error receiving packet from encoder: " << error_string(result) << std::endl;
        av_frame_free(&frame);
        av_packet_free(&packet);
        return;
      }
      else {
        packet->stream_index = m_avStream->index;
        packet->pts = av_rescale_q(frames, AVRational{1, m_codecContext->sample_rate}, m_avStream->time_base);
        packet->dts = packet->pts;
        packet->duration = av_rescale_q(1024, AVRational{1, m_codecContext->sample_rate}, m_avStream->time_base);
    
        result = av_write_frame(m_formatContext, packet);
        if ( result < 0) {
          std::cerr << "Error writing frame: " << error_string(result) << std::endl;
        }
      }
      //Clean up resources
      av_frame_free(&frame);
      av_packet_unref(packet);
      av_packet_free(&packet);
    }
    

    On a final note, I have been able to stream to a TCP server developed in Golang using ADTS as the container and the same method, but I've decided to delegate the task to Nginx.

  • why mpd file contain same resolution AdaptationSet

    18 mars, par Jahid Hasan Antor

    this is the code that i used. this code create a minifest.mpd file, with the same resolution AdaptationSet set

    const createCourse = async (req: Request, res: Response, next: NextFunction) => {
        try {
            const VIDEO_STORAGE_PATH = path.join(__dirname, "../../public/uploads").replace(/\\/g, "/");
            const videoId = req.body.videoId;
            const inputPath = path.join(VIDEO_STORAGE_PATH, "original", `${videoId}.mp4`).replace(/\\/g, "/");
            const outputDir = path.join(VIDEO_STORAGE_PATH, "dash", videoId).replace(/\\/g, "/");
    
            if (!fs.existsSync(outputDir)) {
                fs.mkdirSync(outputDir, { recursive: true });
            }
    
            if (!ffmpegStatic) {
                return next(new Error("❌ ffmpegStatic path is null"));
            }
    
            ffmpeg.setFfmpegPath(ffmpegStatic);
    
            const qualities = [
                { resolution: "1280x720", bitrate: "1800k" },
                { resolution: "854x480", bitrate: "1200k" },
                { resolution: "640x360", bitrate: "800k" },
                { resolution: "426x240", bitrate: "400k" }
            ];
    
            const outputMpd = path.join(outputDir, "manifest.mpd").replace(/\\/g, "/");
    
            // Create FFmpeg command
            let command = ffmpeg(inputPath)
                .output(outputMpd)
                .outputOptions([
                    '-f dash', // Output format
                    '-seg_duration 4', // Segment duration in seconds
                    '-window_size 10', // Number of segments in the manifest
                    '-init_seg_name init-stream$RepresentationID$.webm', // Name for initialization segments
                    '-media_seg_name chunk-stream$RepresentationID$-$Number%05d$.webm', // Name for media segments
                ]);
    
            // Add multiple resolutions
            qualities.forEach(({ resolution, bitrate }) => {
                console.log('esolution, bitrate :>> ', resolution, bitrate);
                command
                    .outputOptions([
                        `-map 0:v`, // Map the video stream
                        `-s ${resolution}`, // Set resolution
                        `-b:v ${bitrate}`, // Set bitrate
                        `-c:v libvpx-vp9`, // Use VP9 codec
                        `-c:a libopus`, // Use Opus codec
                    ]);
            });
    
            command
                .on("end", () => {
                    console.log(`🚀 Video processing complete: ${outputMpd}`);
                })
                .on("error", (err) => {
                    console.error("❌ ffmpeg error:", err);
                    next(err);
                })
                .run();
    
  • Error Installing mobile-ffmpeg-full-gpl (4.4.LTS) via CocoaPods - 404 Not Found

    18 mars, par Muhammad Accucia

    I am trying to install mobile-ffmpeg-full-gpl (4.4.LTS) in my iOS project using CocoaPods, but I am encountering a 404 error when CocoaPods attempts to download the framework.

    Here is the error message:

    \[!\] Error installing mobile-ffmpeg-full-gpl
    \[!\] /usr/bin/curl -f -L -o /var/folders/78/lk7swzb97ml4dt3zd9grny0c0000gn/T/d20250201-6580-dtli8h/file.zip https://github.com/tanersener/mobile-ffmpeg/releases/download/v4.4.LTS/mobile-ffmpeg-full-gpl-4.4.LTS-ios-framework.zip --create-dirs --netrc-optional --retry 2 -A 'CocoaPods/1.15.2 cocoapods-downloader/2.1'
    
    % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
    Dload  Upload   Total   Spent    Left  Speed
    0     9    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
    curl: (56) The requested URL returned error: 404
    

    It seems like the requested file is no longer available at the specified URL.

    Checked the official GitHub releases page for mobile-ffmpeg-full-gpl (4.4.LTS), but I couldn't find the exact file.

  • Decoding the h.264 stream from a COM port

    18 mars, par Peter

    I would like to know if there is a reliable way to decode an H.264 NAL stream coming through a serial port using software.

    So far, I have managed to decode a single frame using a python script. In this script, I first write the incoming data to a file, and when the end-of-frame marker 00_00_00_01 appears, I display the frame using ffplay.

    import serial
    import subprocess
    import os
    import time
    
    ser = serial.Serial('COM3', 115200, timeout=1)
    output_file = "output.264"
    
    # Variable to store the ffplay process
    ffplay_process = None
    
    # Open the file for writing in binary mode
    with open(output_file, "wb") as file:
    
        print("Writing bytes to output.264. Waiting for the end-of-frame marker 0x00000001.")
    
        buffer = bytearray()
        marker = b'\x00\x00\x00\x01'
    
        try:
            while True:
                if ser.in_waiting:  # If there is data in the buffer
                    data = ser.read(ser.in_waiting)  # Read all available bytes
                    buffer.extend(data)
    
                    # Check if the end-of-frame marker is in the buffer
                    while marker in buffer:
                        index = buffer.index(marker) + len(marker)  # Position after the marker
                        frame = buffer[:index]  # Extract the frame
                        buffer = buffer[index:]  # Keep the remaining data
    
                        print(f"Frame recorded: {len(frame)} bytes")
                        file.write(frame)  # Write the frame to the file
                        file.flush()  # Force writing to disk
    
                        # Close the ffplay window if it is already open
                        if ffplay_process and ffplay_process.poll() is None:
                            ffplay_process.terminate()
                            ffplay_process.wait()  # Wait for the process to terminate
    
                        # Play the recorded frame, reopening the window
                        ffplay_process = subprocess.Popen(["ffplay", "-f", "h264", "-i", output_file])
    
        except KeyboardInterrupt:
            print("\nRecording stopped.")
        finally:
            # Close the serial port and the ffplay process
            ser.close()
    

    However, each time a new end-of-frame marker is detected, the ffplay window closes and reopens to show the next frame. It will flicker when transferring the video. Is there a way to display the frames in the same window for seamless playback when streaming video?

    Or is there a better approach or software that is more suited for this task? I do not know where to start, so I will be glad for any hints.