FFmpeg常用API与示例(一)—— 工具库篇(av_log、AVDictionary、avio)

工具层

1.av_log

可以设置日志的级别,这个看看名字就明白了,也不用过多的解释。

  • AV_LOG_PANIC
  • AV_LOG_FATAL
  • AV_LOG_ERROR
  • AV_LOG_WARNING
  • AV_LOG_INFO
  • AV_LOG_VERBOSE
  • AV_LOG_DEBUG
cpp 复制代码
void test_log()
{
    / av_register_all();
    AVFormatContext *pAVFmtCtx = NULL;
    pAVFmtCtx = avformat_alloc_context();

    printf("====================================\n");
    av_log(pAVFmtCtx, AV_LOG_PANIC, "Panic: Something went really wrong and we will crash now.\n");
    av_log(pAVFmtCtx, AV_LOG_FATAL, "Fatal: Something went wrong and recovery is not possible.\n");
    av_log(pAVFmtCtx, AV_LOG_ERROR, "Error: Something went wrong and cannot losslessly be recovered.\n");
    av_log(pAVFmtCtx, AV_LOG_WARNING, "Warning: This may or may not lead to problems.\n");
    av_log(pAVFmtCtx, AV_LOG_INFO, "Info: Standard information.\n");
    av_log(pAVFmtCtx, AV_LOG_VERBOSE, "Verbose: Detailed information.\n");
    av_log(pAVFmtCtx, AV_LOG_DEBUG, "Debug: Stuff which is only useful for libav* developers.\n");
    printf("====================================\n");

    avformat_free_context(pAVFmtCtx);
}
2.AVDictionary
  • AVDictionary
  • AVDictionaryEntry
  • av_dict_set
  • av_dict_count
  • av_dict_get
  • av_dict_free
cpp 复制代码
void test_avdictionary()
{

    AVDictionary *d = NULL;
    AVDictionaryEntry *t = NULL;

    av_dict_set(&d, "name", "zhangsan", 0);
    av_dict_set(&d, "age", "22", 0);
    av_dict_set(&d, "gender", "man", 0);
    av_dict_set(&d, "email", "www@www.com", 0);
    // av_strdup()
    char *k = av_strdup("location");
    char *v = av_strdup("Beijing-China");
    av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);

    printf("====================================\n");
    int dict_cnt = av_dict_count(d);
    printf("dict_count:%d\n", dict_cnt);

    printf("dict_element:\n");
    while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX))
    {
        printf("key:%10s  |  value:%s\n", t->key, t->value);
    }

    t = av_dict_get(d, "email", t, AV_DICT_IGNORE_SUFFIX);
    printf("email is %s\n", t->value);
    printf("====================================\n");
    av_dict_free(&d);
}
3.AVParseUtil
  • av_parse_video_size
  • av_parse_video_rate
  • av_parse_time
  • av_parse_color
  • av_parse_ratio
cpp 复制代码
void test_parseutil()
{
    char input_str[100] = {0};
    printf("========= Parse Video Size =========\n");
    int output_w = 0;
    int output_h = 0;
    strcpy(input_str, "1920x1080");
    av_parse_video_size(&output_w, &output_h, input_str);
    printf("w:%4d | h:%4d\n", output_w, output_h);

    // strcpy(input_str,"vga");//640x480(4:3)
    // strcpy(input_str,"hd1080");//high definition
    strcpy(input_str, "pal"); // ntsc(N制720x480), pal(啪制720x576)
    av_parse_video_size(&output_w, &output_h, input_str);
    printf("w:%4d | h:%4d\n", output_w, output_h);

    printf("========= Parse Frame Rate =========\n");
    AVRational output_rational = {0, 0};
    strcpy(input_str, "15/1");
    av_parse_video_rate(&output_rational, input_str);
    printf("framerate:%d/%d\n", output_rational.num, output_rational.den);

    strcpy(input_str, "pal"); // fps:25/1
    av_parse_video_rate(&output_rational, input_str);
    printf("framerate:%d/%d\n", output_rational.num, output_rational.den);

    printf("=========== Parse Time =============\n");
    int64_t output_timeval; // 单位:微妙, 1S=1000MilliSeconds, 1MilliS=1000MacroSeconds
    strcpy(input_str, "00:01:01");
    av_parse_time(&output_timeval, input_str, 1);
    printf("microseconds:%lld\n", output_timeval);
    printf("====================================\n");
}

协议层

协议操作:三大数据结构

  • AVIOContext
  • **URLContext **
  • URLProtocol

协议(文件)操作的顶层结构 是 AVIOContext,这个对象实现了带缓冲的读写操作;FFMPEG的输入对象 AVFormat 的 pb 字段指向一个 AVIOContext。

AVIOContext 的 opaque 实际指向一个 URLContext 对象,这个对象封装了协议对象及协议操作对象,其中 prot 指向具体的协议操作对象,priv_data 指向具体的协议对象。

URLProtocol 为协议操作对象,针对每种协议,会有一个这样的对象,每个协议操作对象和一个协议对象关联,比如,文件操作对象为 ff_file_protocol,它关联的结构体是FileContext。

1.avio 实战:打开本地文件或网络直播流
  • avformat_network_init
  • avformat_alloc_context
  • avformat_open_input
  • avformat_find_stream_info
cpp 复制代码
int main_222929s(int argc, char *argv[]){
    /av_register_all();
    avformat_network_init();

    printf("hello,ffmpeg\n");
    AVFormatContext* pFormatCtx = NULL;
    AVInputFormat *piFmt = NULL;

    printf("hello,avformat_alloc_context\n");
    // Allocate the AVFormatContext:
    pFormatCtx = avformat_alloc_context();

    printf("hello,avformat_open_input\n");
    //打开本地文件或网络直播流
    //rtsp://127.0.0.1:8554/rtsp1
    //ande_10s.mp4
    if (avformat_open_input(&pFormatCtx, "rtsp://127.0.0.1:8554/rtsp1", piFmt, NULL) < 0) {
        printf("avformat open failed.\n");
        goto quit;
    }
    else {
        printf("open stream success!\n");
    }

    if (avformat_find_stream_info(pFormatCtx, NULL)<0)
    {
        printf("av_find_stream_info error \n");
        goto quit;
    }
    else {
        printf("av_find_stream_info success \n");
        printf("******nb_streams=%d\n",pFormatCtx->nb_streams);
    }

quit:
    avformat_free_context(pFormatCtx);
    avformat_close_input(&pFormatCtx);
    avformat_network_deinit();

    return 0;
}
2.avio 实战:自定义 AVIO
cpp 复制代码
int read_func(void* ptr, uint8_t* buf, int buf_size)
{
    FILE* fp = (FILE*)ptr;
    size_t size = fread(buf, 1, buf_size, fp);
    int ret = size;
    printf("Read Bytes:%d\n", size);
    return ret;

}


int64_t seek_func(void *opaque, int64_t offset, int whence)
{
    int64_t ret;
    FILE *fp = (FILE*)opaque;
    if (whence == AVSEEK_SIZE) {
        return -1;
    }

    fseek(fp, offset, whence);

    return ftell(fp);

}

int main(int argc, char *argv[]){

    ///av_register_all();
    printf("hello,ffmpeg\n");

    int ret = 0;

    FILE* fp = fopen("ande_10s.flv", "rb");
    int nBufferSize = 1024;
    unsigned char* pBuffer = (unsigned char*)malloc(nBufferSize);

    AVFormatContext* pFormatCtx = NULL;
    AVInputFormat *piFmt = NULL;

    printf("hello,avio_alloc_context\n");
    // Allocate the AVIOContext:
    //请同学们自己揣摩
    AVIOContext* pIOCtx = avio_alloc_context(
                pBuffer, nBufferSize,
        0,
        fp,
        read_func,
        0,
        seek_func);

    printf("hello,avformat_alloc_context\n");
    // Allocate the AVFormatContext:
    pFormatCtx = avformat_alloc_context();

    // Set the IOContext:
    pFormatCtx->pb = pIOCtx;//关联,绑定
    pFormatCtx->flags = AVFMT_FLAG_CUSTOM_IO;

    printf("hello,avformat_open_input\n");
    //打开流
    if (avformat_open_input(&pFormatCtx, "", piFmt, NULL) < 0) {
        printf("avformat open failed.\n");
        goto quit;

    }
    else {
        printf("open stream success!\n");
    }

    if (avformat_find_stream_info(pFormatCtx, NULL)<0)
    {
        printf("av_find_stream_info error \n");
        goto quit;
    }
    else {
        printf("av_find_stream_info success \n");
        printf("******nb_streams=%d\n",pFormatCtx->nb_streams);
    }

quit:
    avformat_free_context(pFormatCtx);
    avformat_close_input(&pFormatCtx);

    free(pBuffer);
    return 0;
}
3.avio 实战:自定义数据来源
  • av_file_map
  • avformat_alloc_context
  • av_malloc
  • avio_alloc_context
  • avformat_open_input
  • avformat_find_stream_info
cpp 复制代码
//自定义缓冲区
struct buffer_data {
    uint8_t *ptr;
    size_t size; ///< size left in the buffer
};

//读取数据(回调函数)
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
{
    struct buffer_data *bd = (struct buffer_data *)opaque;
    buf_size = FFMIN(buf_size, bd->size);

    if (!buf_size)
        return AVERROR_EOF;
    printf("ptr:%p size:%d\n", bd->ptr, bd->size);

    /* copy internal buffer data to buf */
    /// 灵活应用[内存buf]:读取的是内存,比如:加密播放器,这里解密
    memcpy(buf, bd->ptr, buf_size);
    bd->ptr  += buf_size;
    bd->size -= buf_size;

    return buf_size;
}

int main(int argc, char *argv[])
{
    AVFormatContext *fmt_ctx = NULL;
    AVIOContext *avio_ctx = NULL;
    uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
    size_t buffer_size, avio_ctx_buffer_size = 4096;
    char *input_filename = NULL;
    int ret = 0;
    struct buffer_data bd = { 0 };

    printf("Hello,ffmpeg\n");
    if (argc != 2) {
        fprintf(stderr, "usage: %s input_file\n"
                "API example program to show how to read from a custom buffer "
                "accessed through AVIOContext.\n", argv[0]);
        return 1;
    }
    input_filename = argv[1];

    /* slurp file content into buffer */
    ///内存映射文件
    ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);
    if (ret < 0)
        goto end;
    printf("av_file_map,ok\n");

    /* fill opaque structure used by the AVIOContext read callback */
    bd.ptr  = buffer;
    bd.size = buffer_size;

    /// 创建对象:AVFormatContext
    if (!(fmt_ctx = avformat_alloc_context())) {
        ret = AVERROR(ENOMEM);
        goto end;
    }
    printf("avformat_alloc_context,ok\n");

    /// 分配内存
    avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
    if (!avio_ctx_buffer) {
        ret = AVERROR(ENOMEM);
        goto end;
    }

    /// 创建对象:AVIOContext,注意参数
    avio_ctx = avio_alloc_context(
                avio_ctx_buffer, avio_ctx_buffer_size,
                                  0,
                &bd,
                &read_packet,
                NULL,
                NULL);
    if (!avio_ctx) {
        ret = AVERROR(ENOMEM);
        goto end;
    }
    fmt_ctx->pb = avio_ctx;
    printf("avio_alloc_context,ok\n");

    /// 打开输入流
    ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not open input\n");
        goto end;
    }
    printf("avformat_open_input,ok\n");

    /// 查找流信息
    ret = avformat_find_stream_info(fmt_ctx, NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not find stream information\n");
        goto end;
    }
    printf("avformat_find_stream_info,ok\n");
    printf("******nb_streams=%d\n",fmt_ctx->nb_streams);

    av_dump_format(fmt_ctx, 0, input_filename, 0);

end:
    avformat_close_input(&fmt_ctx);

    /* note: the internal buffer could have changed, and be != avio_ctx_buffer */
    if (avio_ctx)
        av_freep(&avio_ctx->buffer);
    avio_context_free(&avio_ctx);

    /// 内存映射文件:解绑定
    av_file_unmap(buffer, buffer_size);

    if (ret < 0) {
        fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
        return 1;
    }

    return 0;
}
相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习