You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌入式设备基于libav实现双输出:流媒体推流+无损高帧率文件存储

Great job getting that fragmented MPEG4 livestream up and running with libav on your embedded device! Let's break down the most efficient way to generate your two outputs from a single input—no redundant decoding, which is critical for resource-constrained embedded hardware.

Core Optimal Approach: Single Decode, Dual Encode/Output

The key win here is reusing the decoded frames from your input instead of spinning up two separate decoding pipelines. This cuts down on CPU, memory, and power usage—huge for embedded systems. Here's how to implement it step by step:

1. Reuse Your Existing Input/Decoding Setup

You already have the input stream opened, video stream identified, and decoder initialized. Keep this intact—we'll feed the decoded AVFrames from this pipeline to two separate encoder/output contexts.

2. Initialize Two Independent Output Contexts

Set up each output with its own format, encoder, and destination:

  • Web Lossy Stream (Callback Push)
    • Stick with fragmented MP4 for compatibility, or switch to RTMP/HLS if your target supports it.
    • Use a lossy encoder (like H.264) with Web-friendly parameters: set a reasonable CRF (e.g., 22-25), fast preset, and appropriate bitrate.
    • Configure your custom I/O callback via avio_open2 to handle pushing frames to your streaming endpoint.
  • Lossless High-Frame-Rate File
    • Choose a encoder optimized for lossless storage: FFV1 (great compression ratio, widely supported) or H.264 with crf 0 (hardware-friendly if your platform supports it).
    • Use MKV as the container (better support for lossless codecs and variable frame rates than MP4) or MOV if you need MP4-compatible lossless.
    • Match the input's frame rate and resolution exactly to preserve all detail.

3. Share Decoded Frames Between Outputs

For each decoded AVFrame from your input, create a reference to it (using av_frame_ref) for each encoder. This avoids copying frame data (saves memory!) while ensuring each encoder has its own writable reference.

4. Sync Timestamps & Handle Encoder Output

  • Rescale the frame's PTS/DTS from the decoder's time base to each output stream's time base to avoid playback sync issues.
  • For each encoder, send the referenced frame, retrieve the encoded packet, and write it to either your callback stream or the file.

Example Code Snippet (Simplified)

// Your existing input/decoder setup (already working)
AVFormatContext *input_ctx = ...;
AVCodecContext *dec_ctx = ...;
AVFrame *decoded_frame = av_frame_alloc();

// --- Output 1: Web Lossy Stream (Callback) ---
AVFormatContext *stream_ctx = avformat_alloc_context();
stream_ctx->oformat = av_guess_format("mp4", NULL, NULL);
stream_ctx->oformat->flags |= AVFMT_FLAG_FRAGMENTED; // Keep fragmented MP4

// Hook up your custom push callback
AVIOContext *avio_cb = NULL;
avio_open2(&avio_cb, "stream://", AVIO_FLAG_WRITE, NULL, &your_cb_options);
stream_ctx->pb = avio_cb;

// Initialize H.264 lossy encoder
AVStream *stream_out = avformat_new_stream(stream_ctx, NULL);
avcodec_parameters_copy(stream_out->codecpar, dec_ctx->codecpar);
stream_out->codecpar->codec_id = AV_CODEC_ID_H264;
stream_out->codecpar->bit_rate = 2000000; // 2Mbps for Web
AVCodecContext *stream_enc_ctx = avcodec_alloc_context3(avcodec_find_encoder(AV_CODEC_ID_H264));
stream_enc_ctx->crf = 23;
stream_enc_ctx->preset = "fast";
stream_enc_ctx->time_base = av_inv_q(stream_out->r_frame_rate);
avcodec_open2(stream_enc_ctx, NULL, NULL);

// --- Output 2: Lossless File ---
AVFormatContext *file_ctx = NULL;
avformat_alloc_output_context2(&file_ctx, NULL, "mkv", "lossless_recording.mkv");

// Initialize FFV1 lossless encoder
AVStream *file_out = avformat_new_stream(file_ctx, NULL);
avcodec_parameters_copy(file_out->codecpar, dec_ctx->codecpar);
file_out->codecpar->codec_id = AV_CODEC_ID_FFV1;
AVCodecContext *file_enc_ctx = avcodec_alloc_context3(avcodec_find_encoder(AV_CODEC_ID_FFV1));
file_enc_ctx->flags |= AV_CODEC_FLAG_QSCALE;
file_enc_ctx->global_quality = 0; // Lossless setting
file_enc_ctx->time_base = av_inv_q(file_out->r_frame_rate);
avcodec_open2(file_enc_ctx, NULL, NULL);

// Open both outputs
avformat_write_header(stream_ctx, NULL);
avformat_write_header(file_ctx, NULL);

// --- Main Processing Loop ---
AVPacket input_pkt = {0};
while (av_read_frame(input_ctx, &input_pkt) == 0) {
    if (input_pkt.stream_index == your_video_stream_idx) {
        // Decode the input packet
        avcodec_send_packet(dec_ctx, &input_pkt);
        while (avcodec_receive_frame(dec_ctx, decoded_frame) == 0) {
            // --- Process Web Stream Output ---
            AVPacket stream_pkt = {0};
            AVFrame *stream_frame = av_frame_alloc();
            av_frame_ref(stream_frame, decoded_frame);
            avcodec_send_frame(stream_enc_ctx, stream_frame);
            while (avcodec_receive_packet(stream_enc_ctx, &stream_pkt) == 0) {
                av_packet_rescale_ts(&stream_pkt, dec_ctx->time_base, stream_out->time_base);
                av_interleaved_write_frame(stream_ctx, &stream_pkt);
                av_packet_unref(&stream_pkt);
            }
            av_frame_unref(stream_frame);
            av_frame_free(&stream_frame);

            // --- Process Lossless File Output ---
            AVPacket file_pkt = {0};
            AVFrame *file_frame = av_frame_alloc();
            av_frame_ref(file_frame, decoded_frame);
            avcodec_send_frame(file_enc_ctx, file_frame);
            while (avcodec_receive_packet(file_enc_ctx, &file_pkt) == 0) {
                av_packet_rescale_ts(&file_pkt, dec_ctx->time_base, file_out->time_base);
                av_interleaved_write_frame(file_ctx, &file_pkt);
                av_packet_unref(&file_pkt);
            }
            av_frame_unref(file_frame);
            av_frame_free(&file_frame);
        }
    }
    av_packet_unref(&input_pkt);
}

// Cleanup
av_write_trailer(stream_ctx);
av_write_trailer(file_ctx);
// Free all contexts, frames, packets here (omitted for brevity)

Key Tips for Embedded Optimization

  • Hardware Acceleration: If your platform supports it (e.g., VA-API, Rockchip VPU, NVIDIA NVENC), use hardware decoding/encoding to offload CPU work.
  • Frame Reuse: Avoid allocating new AVFrames for every encode—reuse a small pool of frames to reduce memory fragmentation.
  • Encoder Presets: For the Web stream, use the fastest preset your quality allows (e.g., ultrafast for H.264) to minimize CPU load.
  • Error Handling: Add checks for avcodec_send_frame/avcodec_receive_packet return codes to handle encoder backpressure (critical if your embedded CPU can't keep up with both encodes).

This approach is far more efficient than running two separate pipelines—you only decode once, and split the workload at the frame level, which is perfect for resource-limited embedded devices.

内容的提问来源于stack exchange,提问作者user2333829

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:09:41