ffmpeg: avio_reading.c 解读

----------------------------------------
date:2022-08-19
author:hjjdebug
----------------------------------------
avio_reading.c 解读
演示了avformat 是如何通过avio 来读取数据的,下面来看分析
示例代码被我修改过(方便理解),附在后面.

1. ret = av_file_map(input_filename, &file_buf, &file_size, 0, NULL);
    将输入文件读入内存到file_buf,并返回长度file_size, 把它放入对象filemap_obj中
    filemap_obj的成员,就是一个指针,一个大小

2.  fmt_ctx = avformat_alloc_context();
    分配一个format context, 只是一个头而已

3.  data_buf = av_malloc(4096);
    简单的分配一块内存,用data_buf 来指向

4.  avio_ctx = avio_alloc_context(data_buf, 4096,
                                  0, &filemap_obj, &my_read_packet, NULL, NULL);
    分配一个avio_ctx,但它传进入了几个参数.
    a. data_buf指针及其大小4096, 这个缓冲的指针data_buf 及大小4096,将来调用my_read_packet函数时会被传入
    b. 传入了filemap_obj指针,它关联了输入文件内存
    c. 传入了my_read_packet 函数地址, 关联了读packet 操作.
    我们可以打印一下avio_ctx 结构, 是一个复杂的结构,目前使用了如下成员变量,其它用到再介绍.

    unsigned char *buffer; //它自己管理的缓存指针和大小
    int buffer_size;
    unsigned char *buf_ptr; //目前缓存的使用状况,指向了filemap_obj 的什么地方
    unsigned char *buf_end;
    void *opaque;            //这个opaque 就是filemap_obj, 总的缓存数据的大小描述
    int (*read_packet)(void *opaque, uint8_t *dst, int size); //读包函数,需要的时候填满缓冲区
    其中opaque 就是filemap_obj指针, dst及size 就是data_buf 缓冲区


并把avio_ctx 付给fmt_ctx->pb
    fmt_ctx->pb = avio_ctx;

5.  avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
    该函数会通过my_read_packet 读取一个包.目前一包为4096bytes
    我们会看到bd指针向前长0x1000,长度减0x1000
    因为my_read_packet 是我们自定义的函数了,可以加打印信息.

6.  ret = avformat_find_stream_info(fmt_ctx, NULL);
    该函数会通过my_read_packet 读入几十个上百个包不等,它要分析流的信息.
    然后你就可以
    
7.  av_dump_format(fmt_ctx, 0, input_filename, 0);
    打印出流的信息. 如下是打印记录,信息不少!

Input #0, mpegts, from '/opt/test/test1.ts':
  Duration: N/A, start: 1.458667, bitrate: N/A
  Program 1 
    Metadata:
      service_name    : Service01
      service_provider: FFmpeg
  Stream #0:0[0x100]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps, 25 tbr, 90k tbn, 50 tbc
  Stream #0:1[0x101](eng): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 137 kb/s
 

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/file.h>

struct buffer_struct {
    uint8_t *ptr;
    int size; ///< size left in the buffer
};

static int my_read_packet(void *opaque, uint8_t *data, int read_size)
{
	static int count=0;
    struct buffer_struct *filemap_obj = (struct buffer_struct *)opaque;
    read_size = FFMIN(read_size, filemap_obj->size);

    if (!read_size)
        return AVERROR_EOF;
    printf("count:%d, ptr:%p filemap_obj->size:%d,read_size:%u\n",count++, filemap_obj->ptr, filemap_obj->size,read_size);

    /* copy internal data to dst */
    memcpy(data, filemap_obj->ptr, read_size);
    filemap_obj->ptr  += read_size;
    filemap_obj->size -= read_size;

    return read_size;
}

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

    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;
    }
    char *input_filename = argv[1];
	//AV_LOG_PANIC(0), AV_LOG_VERBOSE(40)
	av_log_set_level(56);

	size_t file_size;
    uint8_t *file_buffer = NULL;
    /* slurp file content into buffer */
    int ret = av_file_map(input_filename, &file_buffer, &file_size, 0, NULL);
    if (ret < 0)
        goto end;

    struct buffer_struct filemap_obj = { 0 };
    /* fill opaque structure used by the AVIOContext read callback */
    filemap_obj.ptr  = file_buffer;
    filemap_obj.size = file_size;

    AVFormatContext *fmt_ctx = NULL;
    if (!(fmt_ctx = avformat_alloc_context())) {
        ret = AVERROR(ENOMEM);
        goto end;
    }

	 // description: 创建一个AVIOContext 上下文对象,给fmt_ctx->pb, 它需要的时候会回调读数据函数!
	/* 设定了一次读4096大小 bufsize=4096, write_flag=0,opaque=&filemap_obj, 读包函数my_read_packet
	 * 这里设置了一个缓冲区,一个读包函数及opaque指针, opaque指针会回传给读包函数.
	 * 后面的2个NULL 是写包函数和 seek 函数, 不用可写NULL
	 */
    size_t  bufsize = 4096;
    uint8_t *data_buf = av_malloc(bufsize);
    if (!data_buf) {
        ret = AVERROR(ENOMEM);
        goto end;
    }
    AVIOContext *avio_ctx = avio_alloc_context(data_buf, bufsize,
                                  0, &filemap_obj, &my_read_packet, NULL, NULL); 
    if (!avio_ctx) {
        ret = AVERROR(ENOMEM);
        goto end;
    }
    fmt_ctx->pb = avio_ctx;

	printf("----begin avformat_open_input------\n");
    ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not open input\n");
        goto end;
    }
	int64_t pos=avio_tell(fmt_ctx->pb);
	printf("pos is %ld\n",pos);

	printf("------begin avformat_find_stream_info-----\n");
    ret = avformat_find_stream_info(fmt_ctx, NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not find stream information\n");
        goto end;
    }
	 pos=avio_tell(fmt_ctx->pb);
	printf("pos is %ld\n",pos);
	
//	av_log_set_level(56);
	printf("------begin av_dump_format-----\n");
    av_dump_format(fmt_ctx, 0, input_filename, 0);

end:
    avformat_close_input(&fmt_ctx);

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

    av_file_unmap(file_buffer, file_size);

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

    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值