LD_PRELOAD shim: 让 headless-shell 以为有 H.264/AAC 解码器
```c
// avcodec_shim.c
// LD_PRELOAD shim: 让 headless-shell 以为有 H.264/AAC 解码器,实际不干活
// 编译: gcc -shared -fPIC -o libavcodec_shim.so avcodec_shim.c

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

// ========== 模拟的结构体 ==========

typedef struct AVCodec {
    const char *name;
    const char *long_name;
    int type;
    int id;
    int capabilities;
    void *priv_data_size;
    // 其他字段用 padding 占位,保证 sizeof 和真实 libavcodec 一致
    char padding[96];
} AVCodec;

typedef struct AVCodecContext {
    void *av_class;
    int bit_rate;
    int width;
    int height;
    char padding[1024];
} AVCodecContext;

typedef struct AVPacket {
    char padding[128];
} AVPacket;

typedef struct AVFrame {
    char padding[256];
} AVFrame;

enum AVCodecID {
    AV_CODEC_ID_NONE,
    AV_CODEC_ID_H264,
    AV_CODEC_ID_H265,
    AV_CODEC_ID_AAC,
    AV_CODEC_ID_MP3,
    AV_CODEC_ID_VP8,
    AV_CODEC_ID_VP9,
};

enum AVMediaType {
    AVMEDIA_TYPE_UNKNOWN = -1,
    AVMEDIA_TYPE_VIDEO,
    AVMEDIA_TYPE_AUDIO,
};

// ========== 假解码器实例 ==========

static AVCodec fake_h264_decoder = {
    .name = "h264",
    .long_name = "H.264 / AVC / MPEG-4 AVC",
    .type = AVMEDIA_TYPE_VIDEO,
    .id = AV_CODEC_ID_H264,
    .capabilities = 0x0001,  // CODEC_CAP_DRAW_HORIZ_BAND
};

static AVCodec fake_aac_decoder = {
    .name = "aac",
    .long_name = "AAC (Advanced Audio Coding)",
    .type = AVMEDIA_TYPE_AUDIO,
    .id = AV_CODEC_ID_AAC,
    .capabilities = 0,
};

static AVCodec fake_mp3_decoder = {
    .name = "mp3",
    .long_name = "MP3 (MPEG audio layer 3)",
    .type = AVMEDIA_TYPE_AUDIO,
    .id = AV_CODEC_ID_MP3,
    .capabilities = 0,
};

static AVCodec fake_vp8_decoder = {
    .name = "vp8",
    .long_name = "On2 VP8",
    .type = AVMEDIA_TYPE_VIDEO,
    .id = AV_CODEC_ID_VP8,
    .capabilities = 0,
};

static AVCodec fake_vp9_decoder = {
    .name = "vp9",
    .long_name = "Google VP9",
    .type = AVMEDIA_TYPE_VIDEO,
    .id = AV_CODEC_ID_VP9,
    .capabilities = 0,
};

// ========== 劫持函数 ==========

AVCodec *avcodec_find_decoder(enum AVCodecID id) {
    static int in_call = 0;
    if (in_call) {
        // 递归保护:如果真实 libavcodec 不存在,直接返回假解码器
        switch (id) {
            case AV_CODEC_ID_H264: return &fake_h264_decoder;
            case AV_CODEC_ID_H265: return &fake_h264_decoder;  // H.265 也用 H.264 假装
            case AV_CODEC_ID_AAC:  return &fake_aac_decoder;
            case AV_CODEC_ID_MP3:  return &fake_mp3_decoder;
            case AV_CODEC_ID_VP8:  return &fake_vp8_decoder;
            case AV_CODEC_ID_VP9:  return &fake_vp9_decoder;
            default: return NULL;
        }
    }

    // 先尝试调用真实的 avcodec_find_decoder
    in_call = 1;
    typedef AVCodec* (*func_t)(enum AVCodecID);
    static func_t real_func = NULL;
    if (!real_func) {
        real_func = (func_t)dlsym(RTLD_NEXT, "avcodec_find_decoder");
    }
    in_call = 0;

    if (real_func && real_func != avcodec_find_decoder) {
        AVCodec *result = real_func(id);
        if (result) return result;
    }

    // 真实函数不存在或返回 NULL,返回假解码器
    switch (id) {
        case AV_CODEC_ID_H264: return &fake_h264_decoder;
        case AV_CODEC_ID_H265: return &fake_h264_decoder;
        case AV_CODEC_ID_AAC:  return &fake_aac_decoder;
        case AV_CODEC_ID_MP3:  return &fake_mp3_decoder;
        case AV_CODEC_ID_VP8:  return &fake_vp8_decoder;
        case AV_CODEC_ID_VP9:  return &fake_vp9_decoder;
        default: return NULL;
    }
}

AVCodec *avcodec_find_decoder_by_name(const char *name) {
    if (!name) return NULL;
    if (strstr(name, "h264") || strstr(name, "H264")) return &fake_h264_decoder;
    if (strstr(name, "hevc") || strstr(name, "h265") || strstr(name, "HEVC")) return &fake_h264_decoder;
    if (strstr(name, "aac")  || strstr(name, "AAC"))  return &fake_aac_decoder;
    if (strstr(name, "mp3")  || strstr(name, "MP3"))  return &fake_mp3_decoder;
    if (strstr(name, "vp8")  || strstr(name, "VP8"))  return &fake_vp8_decoder;
    if (strstr(name, "vp9")  || strstr(name, "VP9"))  return &fake_vp9_decoder;
    return NULL;
}

// avcodec_open2: 总是成功
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, void *options) {
    return 0;  // 0 = 成功
}

// avcodec_close: 无操作
int avcodec_close(AVCodecContext *avctx) {
    return 0;
}

// avcodec_send_packet: 接受但不处理
int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt) {
    return 0;
}

// avcodec_receive_frame: 返回 EAGAIN(没有帧可用),合理的不干活状态
int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) {
    return -11;  // -EAGAIN
}

// avcodec_free_context: 无操作
void avcodec_free_context(AVCodecContext **avctx) {
    if (avctx && *avctx) {
        free(*avctx);
        *avctx = NULL;
    }
}

// avcodec_alloc_context3: 分配一个空结构体
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec) {
    AVCodecContext *ctx = calloc(1, sizeof(AVCodecContext));
    return ctx;
}
```

**编译**:

```bash
gcc -shared -fPIC -o libavcodec_shim.so avcodec_shim.c -ldl
```

**使用**:

```dockerfile
# Dockerfile
COPY libavcodec_shim.so /usr/local/lib/
ENV LD_PRELOAD=/usr/local/lib/libavcodec_shim.so
```

或者在启动命令前:

```bash
LD_PRELOAD=/usr/local/lib/libavcodec_shim.so ./headless-shell --no-sandbox --headless ...
```

这个 shim 只劫持 FFmpeg 解码器查找和初始化函数,让 headless-shell 以为 H.264/AAC 解码器存在。解码器找到了、打开了、但 `receive_frame` 永远返回 EAGAIN(没有帧),所以不产生实际解码开销。MSE 管道畅通,`FMP4_CAPTURE_SCRIPT` 正常抓流。

体积:约 20KB,几乎零开销。
No Comments

Send Comment Edit Comment


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
Previous