title: ffmpeg_sample解读_avio_reading
date: 2020-10-21 10:15:02
tags: [读书笔记]
typora-copy-images-to: ./imgs
typora-root-url: ./imgs
概括
Ffmpeg 项目中的 实例解读. 把他移到安卓项目中来开发了.
这个项目是读取 文件.解码出文件信息.
使用方式 使用 ./avio_reading 1.mp4 读入文件
输出如下
ptr:0x10e1b9000 size:23014356
ptr:0x10e1ba000 size:23010260
ptr:0x10e1bb000 size:23006164
ptr:0x10e1bce2a size:22998442
ptr:0x10e1bde2a size:22994346
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '1.mp4':
Metadata:
major_brand : isom
minor_version : 1
compatible_brands: isomavc1
creation_time : 2013-05-03T22:51:07.000000Z
Duration: 00:00:46.61, start: 0.000000, bitrate: N/A
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 960x400 [SAR 1:1 DAR 12:5], 3859 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
Metadata:
creation_time : 2013-05-03T22:50:47.000000Z
handler_name : GPAC ISO Video Handler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo立体生, fltp, 92 kb/s (default)
Metadata:
creation_time : 2013-05-03T22:51:07.000000Z
handler_name : GPAC ISO Audio Handler
这个源码相对简单.就直接看注释就行了
/**
* @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>
#include "../macro.h"
/**
* 使用 ./avio_reading 1.mp4 读入文件 解码出文件信息
* ptr:0x10e1b9000 size:23014356
ptr:0x10e1ba000 size:23010260
ptr:0x10e1bb000 size:23006164
ptr:0x10e1bce2a size:22998442
ptr:0x10e1bde2a size:22994346
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '1.mp4':
Metadata:
major_brand : isom
minor_version : 1
compatible_brands: isomavc1
creation_time : 2013-05-03T22:51:07.000000Z
Duration: 00:00:46.61, start: 0.000000, bitrate: N/A
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 960x400 [SAR 1:1 DAR 12:5], 3859 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
Metadata:
creation_time : 2013-05-03T22:50:47.000000Z
handler_name : GPAC ISO Video Handler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo立体生, fltp, 92 kb/s (default)
Metadata:
creation_time : 2013-05-03T22:51:07.000000Z
handler_name : GPAC ISO Audio Handler
*/
struct buffer_data {
uint8_t *ptr;
size_t size; ///< size left in the buffer
};
//把 opaque(也就是bd) 中的数据拷贝到 buf中,bd的数据就是读取的文件的数据
//猜测这个buf 应该是 avioContext 内部的buf
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;
LOGE("ptr:%p size:%zu\n", bd->ptr, bd->size);
/* copy internal buffer data to buf */
//从bd 拷贝到buf中. 每次拷贝buf_size个
memcpy(buf, bd->ptr, buf_size);
bd->ptr += buf_size;
bd->size -= buf_size;
return buf_size;
}
int reading_main(int argc, char *argv[]) {
AVFormatContext *fmt_ctx = NULL;
AVIOContext *avio_ctx = NULL;
uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
//size_t可能会提高代码的可移植性、有效性或者可读 无符号整形
size_t buffer_size, avio_ctx_buffer_size = 4096;
char *input_filename = NULL;
int ret = 0;
struct buffer_data bd = {0};
for (int i = 0; i < argc; ++i) {
LOGE("paramets is %s",argv[i]);
}
if (argc != 2) {
LOGE("usage: %s input_file\n API example program to show how to read from a custom buffer accessed through AVIOContext."
,argv[0]);
return 1;
}
input_filename = argv[1];
/* slurp file content into buffer */
//读取文件.写入到buff中,buffer_size指明大小 --buf里没数据.只是分配了空间,建立buffer和文件的映射
ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);
if (ret < 0)
goto end;
//把读取的数据封装到bd结构中, 此时buf 中还没数据.
/* fill opaque structure used by the AVIOContext read callback */
bd.ptr = buffer;
bd.size = buffer_size;
//初始化格式上下文
if (!(fmt_ctx = avformat_alloc_context())) {
ret = AVERROR(ENOMEM);
goto end;
}
//分配一个buffer,具有合适的对齐格式,4096字节大小.此时avio_ctx_buffer 也是空
avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
if (!avio_ctx_buffer) {
ret = AVERROR(ENOMEM);
goto end;
}
//分配io读写上下文 回调是read_packet 0表示从buffer中读数据
//相当于就是可以通过avio_ctx 从 bd 里读去数据,会回调read_packet方法
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;
//打开 输入流,读取数据.这里才是从bd中把数据写入到avio_ctx_buffer中.回调read_packet 函数
ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
if (ret < 0) {
LOGE(stderr, "Could not open input\n");
goto end;
}
// 找到数据中的流信息,此时数据已经都写到 avoiContext中了,
ret = avformat_find_stream_info(fmt_ctx, NULL);
if (ret < 0) {
LOGE(stderr, "Could not find stream information\n");
goto end;
}
//打印数据文件信息
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)//是否内部buffer及io上下问
av_freep(&avio_ctx->buffer);
avio_context_free(&avio_ctx);
av_file_unmap(buffer, buffer_size);
if (ret < 0) {
LOGE(stderr, "Error occurred: %s\n", av_err2str(ret));
return 1;
}
return 0;
}
网友评论