这个目前阶段用的不多,暂时不要花费太多精力。
url 的格式不同,使用的传输层协议也不同。这块看代码还没看到自己想的这样。
目前看的信息是:avformatContext 的 io_open 回调函数 在默认情况下叫 io_open_default,在解复用的 avformat_open_input 方法中一定会调用。那么我们如果不使用这个默认的 io_open_default,使用自己写的回调函数,会怎么样呢?
还看到的信息:avformatContext的pb ( AVIOContext *pb;)是通过 avio_alloc_context方法创建的,那么我们如果自己创建,也可以使用avio_alloc_context创建。
AVIOContext *avio_alloc_context(
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
int64_t (*seek)(void *opaque, int64_t offset, int whence))
avio_alloc_context 函数说明
AVIOContext *avio_alloc_context(
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
int64_t (*seek)(void *opaque, int64_t offset, int whence)
);
opaque是 read_packet / write_packet 的第⼀个参数,指向⽤户数据。
buffer和buffer_size是 read_packet / write_packet 的第⼆个和第三个参数,是供FFmpeg使⽤
的数据区。
buffer ⽤作FFmpeg输⼊时,由⽤户负责向 buffer 中填充数据,FFmpeg取⾛数据。
buffer ⽤作FFmpeg输出时,由FFmpeg负责向 buffer 中填充数据,⽤户取⾛数据。
write_flag是缓冲区读写标志,读写的主语是指FFmpeg。
write_flag 为1时, buffer ⽤于写,即作为FFmpeg输出。
write_flag 为0时, buffer ⽤于读,即作为FFmpeg输⼊。
read_packet和write_packet是函数指针,指向⽤户编写的回调函数。
seek也是函数指针,需要⽀持seek时使⽤。 可以类⽐fseek的机制
需要和如下的结合起来学习,
AVIOContext 是 avformatContext 结构体中一个成员变量
是传输层的
中文翻译:
*-demuxing:
要么由用户在avformat_open_input()之前设置(然后用户必须手动关闭它),
要么由avformat_opend_input()设置。这里应该想要表达的是如果不设置,那么avformat_opend_input方法内部会自动查找。
*-muxing:由用户在avformat_write_header()之前设置。调用者必须负责关闭/释放IO上下文。
*如果在中设置了AVFMT_NOFILE标志,则不要设置此字段iform/oform.flags。在这种情况下,(解)复用器将以其他方式处理I/O,此字段将为NULL。
/**
* I/O context.
*
* - demuxing: either set by the user before avformat_open_input() (then
* the user must close it manually) or set by avformat_open_input().
* - muxing: set by the user before avformat_write_header(). The caller must
* take care of closing / freeing the IO context.
*
* Do NOT set this field if AVFMT_NOFILE flag is set in
* iformat/oformat.flags. In such a case, the (de)muxer will handle
* I/O in some other way and this field will be NULL.
*/
AVIOContext *pb;
AVIOContext 自己是一个结构体
/**
* Bytestream IO Context.
* New fields can be added to the end with minor version bumps.
* Removal, reordering and changes to existing fields require a major
* version bump.
* sizeof(AVIOContext) must not be used outside libav*.
*
* @note None of the function pointers in AVIOContext should be called
* directly, they should only be set by the client application
* when implementing custom I/O. Normally these are set to the
* function pointers specified in avio_alloc_context()
*/
typedef struct AVIOContext {
/**
* A class for private options.
*
* If this AVIOContext is created by avio_open2(), av_class is set and
* passes the options down to protocols.
*
* If this AVIOContext is manually allocated, then av_class may be set by
* the caller.
*
* warning -- this field can be NULL, be sure to not pass this AVIOContext
* to any av_opt_* functions in that case.
*/
const AVClass *av_class;
/*
* The following shows the relationship between buffer, buf_ptr,
* buf_ptr_max, buf_end, buf_size, and pos, when reading and when writing
* (since AVIOContext is used for both):
*
**********************************************************************************
* READING
**********************************************************************************
*
* | buffer_size |
* |---------------------------------------|
* | |
*
* buffer buf_ptr buf_end
* +---------------+-----------------------+
* |/ / / / / / / /|/ / / / / / /| |
* read buffer: |/ / consumed / | to be read /| |
* |/ / / / / / / /|/ / / / / / /| |
* +---------------+-----------------------+
*
* pos
* +-------------------------------------------+-----------------+
* input file: | | |
* +-------------------------------------------+-----------------+
*
*
**********************************************************************************
* WRITING
**********************************************************************************
*
* | buffer_size |
* |--------------------------------------|
* | |
*
* buf_ptr_max
* buffer (buf_ptr) buf_end
* +-----------------------+--------------+
* |/ / / / / / / / / / / /| |
* write buffer: | / / to be flushed / / | |
* |/ / / / / / / / / / / /| |
* +-----------------------+--------------+
* buf_ptr can be in this
* due to a backward seek
*
* pos
* +-------------+----------------------------------------------+
* output file: | | |
* +-------------+----------------------------------------------+
*
*/
unsigned char *buffer; /**< Start of the buffer. */
int buffer_size; /**< Maximum buffer size */
unsigned char *buf_ptr; /**< Current position in the buffer */
unsigned char *buf_end; /**< End of the data, may be less than
buffer+buffer_size if the read function returned
less data than requested, e.g. for streams where
no more data has been received yet. */
void *opaque; /**< A private pointer, passed to the read/write/seek/...
functions. */
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
int64_t (*seek)(void *opaque, int64_t offset, int whence);
int64_t pos; /**< position in the file of the current buffer */
int eof_reached; /**< true if was unable to read due to error or eof */
int write_flag; /**< true if open for writing */
int max_packet_size;
unsigned long checksum;
unsigned char *checksum_ptr;
unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
int error; /**< contains the error code or 0 if no error happened */
/**
* Pause or resume playback for network streaming protocols - e.g. MMS.
*/
int (*read_pause)(void *opaque, int pause);
/**
* Seek to a given timestamp in stream with the specified stream_index.
* Needed for some network streaming protocols which don't support seeking
* to byte position.
*/
int64_t (*read_seek)(void *opaque, int stream_index,
int64_t timestamp, int flags);
/**
* A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
*/
int seekable;
/**
* max filesize, used to limit allocations
* This field is internal to libavformat and access from outside is not allowed.
*/
int64_t maxsize;
/**
* avio_read and avio_write should if possible be satisfied directly
* instead of going through a buffer, and avio_seek will always
* call the underlying seek function directly.
*/
int direct;
/**
* Bytes read statistic
* This field is internal to libavformat and access from outside is not allowed.
*/
int64_t bytes_read;
/**
* seek statistic
* This field is internal to libavformat and access from outside is not allowed.
*/
int seek_count;
/**
* writeout statistic
* This field is internal to libavformat and access from outside is not allowed.
*/
int writeout_count;
/**
* Original buffer size
* used internally after probing and ensure seekback to reset the buffer size
* This field is internal to libavformat and access from outside is not allowed.
*/
int orig_buffer_size;
/**
* Threshold to favor readahead over seek.
* This is current internal only, do not use from outside.
*/
int short_seek_threshold;
/**
* ',' separated list of allowed protocols.
*/
const char *protocol_whitelist;
/**
* ',' separated list of disallowed protocols.
*/
const char *protocol_blacklist;
/**
* A callback that is used instead of write_packet.
*/
int (*write_data_type)(void *opaque, uint8_t *buf, int buf_size,
enum AVIODataMarkerType type, int64_t time);
/**
* If set, don't call write_data_type separately for AVIO_DATA_MARKER_BOUNDARY_POINT,
* but ignore them and treat them as AVIO_DATA_MARKER_UNKNOWN (to avoid needlessly
* small chunks of data returned from the callback).
*/
int ignore_boundary_point;
/**
* Internal, not meant to be used from outside of AVIOContext.
*/
enum AVIODataMarkerType current_type;
int64_t last_time;
/**
* A callback that is used instead of short_seek_threshold.
* This is current internal only, do not use from outside.
*/
int (*short_seek_get)(void *opaque);
int64_t written;
/**
* Maximum reached position before a backward seek in the write buffer,
* used keeping track of already written data for a later flush.
*/
unsigned char *buf_ptr_max;
/**
* Try to buffer at least this amount of data before flushing it
*/
int min_packet_size;
} AVIOContext;
ffmpeg 是如何通过参数url 找到具体的 AVIOContext 的?
在解复用一个本地的mp4文件的时候,我们 是这样调用的,传递的 url的值是 "./120/400_300_25.mp4"
const char* url_400 = "./120/400_300_25.mp4";
int ret = avformat_open_input(&avformatContext, url_400, nullptr, nullptr);
调用
AVFormatContext* avformatContext = nullptr;
const char* url_400 = "./120/400_300_25.mp4";
const char* url_1080 = "./120/1920_1080_25.mp4";
int ret = avformat_open_input(&avformatContext, url_400, nullptr, nullptr);
1. avformat_open_input 方法内部会重新创建 avformat_alloc_context,创建 AVFormatContext *s = avformat_alloc_context()
1.1 avformat_alloc_context内部调用 avformat_get_context_defaults
static void avformat_get_context_defaults(AVFormatContext *s)
{
memset(s, 0, sizeof(AVFormatContext));
s->av_class = &av_format_context_class;
s->io_open = io_open_default; //注意这里,设定了 AVFormatContext 的 io_open 回调函数
s->io_close = io_close_default;
av_opt_set_defaults(s);
}
1.2 然后调用
if ((ret = init_input(s, filename, &tmp)) < 0)
------> if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)
------> 也就是调用 io_open_default方法,传递参数为 AVFormatContext,AVFormatContext->pb的地址,后面在
-------> 调用 return ffio_open_whitelist(pb, url, flags, &s->interrupt_callback, options, s->protocol_whitelist, s->protocol_blacklist);
---------> 和当前关系不大 err = ffurl_open_whitelist(&h, filename, flags, int_cb, options, whitelist, blacklist, NULL);
---------> err = ffio_fdopen(s, h);int ffio_fdopen(AVIOContext **s, URLContext *h)
------> ffio_fdopen内部做了 avio_alloc_context,创建了AVIOContext *s,也就是 avformatContext的 pb,
io_open --- A callback for opening new IO streams.
从这里可以看出几点:
0. 当avformat_open_input方法中传递的 avformatContext是nullptr, 则:AVFormatContext->io_open = io_open_default
1.即使我们使用 AVFormatContext *avformat_alloc_context(void)创建了avfromatContext,内部也会 AVFormatContext->io_open = io_open_default
1. io_open 回调函数,在avformat_open_input方法中会调用,也就是说,默认会调用 io_open_default 函数
2. 那么我们可以自己定义 AVFormatContext->io_open的回调函数吗?那要看 io_open_default 函数的功能是啥?