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;
}
相关推荐
数据与后端架构提升之路1 小时前
从神经元到神经网络:深度学习的进化之旅
人工智能·神经网络·学习
一行11 小时前
电脑蓝屏debug学习
学习·电脑
星LZX1 小时前
WireShark入门学习笔记
笔记·学习·wireshark
阑梦清川1 小时前
在鱼皮的模拟面试里面学习有感
学习·面试·职场和发展
qq_433099401 小时前
Isaac Gym学习笔记——概述
学习
秃头佛爷3 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
dayouziei5 小时前
java的类加载机制的学习
java·学习
dsywws9 小时前
Linux学习笔记之vim入门
linux·笔记·学习
晨曦_子画9 小时前
3种最难学习和最容易学习的 3 种编程语言
学习
城南vision10 小时前
Docker学习—Docker核心概念总结
java·学习·docker