AVFormatContext协议层:理论与实战(二)https://developer.aliyun.com/article/1473890
五、avio 实战 3:自定义数据来源
avio 自定义数据来源:可以是文件, 可以是内存, 可以是网络
本次实战的在实战 2 的基础上自定义了数据来源,即使用内存映射技术将输入视频文件映射到内存中。参考了 ffmepg 官方提供的测试用例avio_read_callback.c
1、示例源码
/** * @file * libavformat AVIOContext API example. * * Make libavformat demuxer access media content through a custom * AVIOContext read callback. * @example avio_reading.c */ #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavformat/avio.h> #include <libavutil/file.h> //自定义缓冲区 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"); input_filename = "./debug/test.mp4"; /* 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; }
av_file_map()
:读取文件,并将其内容放入新分配的缓冲区中。返回的缓冲区必须使用av_file_unmap()
释放;av_dump_format()
:它用于打印关于音频或视频文件格式的详细信息,例如有关音频或视频文件的格式、流和编解码器的详细信息。包括文件格式、编解码器信息、流参数和元数据等;
2、运行结果
Hello,ffmpeg av_file_map,ok avformat_alloc_context,ok avio_alloc_context,ok ptr:04650000 size:1247737 .... ptr:04780000 size:2553 avformat_open_input,ok avformat_find_stream_info,ok ******nb_streams=2 [mov,mp4,m4a,3gp,3g2,mj2 @ 01eb0c40] stream 0, offset 0x30: partial file [mov,mp4,m4a,3gp,3g2,mj2 @ 01eb0c40] Could not find codec parameters for stream 0 (Video: h264 (avc1 / 0x31637661), none, 1280x720, 1638 kb/s): unspecified pixel format Consider increasing the value for the 'analyzeduration' and 'probesize' options Input #0, mov,mp4,m4a,3gp,3g2,mj2, from './debug/output.mp4': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf60.3.100 Duration: 00:00:05.00, start: 0.000000, bitrate: N/A Stream #0:0(und): Video: h264 (avc1 / 0x31637661), none, 1280x720, 1638 kb/s, SAR 1:1 DAR 16:9, 25 fps, 25 tbr, 12800 tbn, 25600 tbc (default) Metadata: handler_name : VideoHandler encoder : Lavc60.3.100 libx264 Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 48000 Hz, 5.1, fltp, 348 kb/s (default) Metadata: handler_name : SoundHandler