AVIOContext 再学习
这个目前阶段用的不多,暂时不要花费太多精力。
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))
调用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 函数的功能是啥?
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的机制
需要和如下的结合起来学习,
AVFormatContext 再分析零-CSDN博客
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 thanbuffer+buffer_size if the read function returnedless data than requested, e.g. for streams whereno 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);