1. 開啟檔案: if (!fmt || !(fmt->flags & AVFMT_NOFILE)) {
|
因 fmt == NULL, 上面成立, 再看下面的程式碼: ByteIOContext *pb = NULL; // 位元組IO上下文 if ((err=url_fopen(&pb, filename, URL_RDONLY)) < 0) { // 只讀方式開啟輸入的檔案 goto fail; } if (buf_size > 0) { // 因 buf_size == 0, 不成立 url_setbufsize(pb, buf_size);
}
|
進入url_fopen函式: int url_fopen(ByteIOContext **s, // 輸出引數: 位元組IO上下文 const char *filename, // 檔名 int flags) // 標誌 { URLContext *h; // URL(統一資源定位)上下文 int err;
err = url_open(&h, filename, flags); // 開啟URL if (err < 0) return err; err = url_fdopen(s, h); // 用URL上下文開啟位元組IO上下文 if (err < 0) { url_close(h); return err; } return 0; }
|
進入url_open函式: int url_open(URLContext **puc, // 輸出引數: URL上下文
const char *filename, // 檔名
int flags) // 標誌 { URLProtocol *up; const char *p; char proto_str[128], *q;
// 提取協議 p = filename; q = proto_str; while (*p != '' && *p != ':') { // 未結束, 並未遇到分隔符':' if (!isalpha(*p)) // 如果不是英文字母 goto file_proto; if ((q - proto_str) < sizeof(proto_str) - 1) *q++ = *p; // 記錄協議字串 p++; }
if (*p == '' || is_dos_path(filename)) { // 如果上面是因為結束而跳出, 或且 檔名是DOS路徑
file_proto: strcpy(proto_str, "file"); // 檔案協議 } else { *q = ''; // 追加結束符 }
up = first_protocol; while (up != NULL) { if (!strcmp(proto_str, up->name)) // 協議匹配 return url_open_protocol (puc, up, filename, flags); // 用這個協議開啟URL up = up->next; } *puc = NULL; return AVERROR(ENOENT); }
|
進入 url_open_protocol函式: int url_open_protocol (URLContext **puc, // 輸出引數: URL上下文
struct URLProtocol *up, // URL協議
const char *filename, // 檔名
int flags) // 標誌 { URLContext *uc; int err;
// 網路初始化 #if CONFIG_NETWORK if (!ff_network_init()) return AVERROR(EIO); #endif
// 分配URL上下文並加上檔名的儲存空間 uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1); if (!uc) { err = AVERROR(ENOMEM); goto fail; }
// 初始化URL上下文 #if LIBAVFORMAT_VERSION_MAJOR >= 53 uc->av_class = &urlcontext_class; #endif
// 記錄檔名 uc->filename = (char *) &uc[1]; strcpy(uc->filename, filename); uc->prot = up; // URL協議
uc->flags = flags; // 標誌 uc->is_streamed = 0; // 預設不是流, 可以在up->url_open函式里修改 uc->max_packet_size = 0; // 包最大多大, 預設為0, 可以在up->url_open函式里修改 // 開啟URL err = up->url_open(uc, filename, flags); if (err < 0) { av_free(uc); goto fail; }
if( (flags & (URL_WRONLY | URL_RDWR)) // 如果以可寫方式開啟
|| !strcmp(up->name, "file")) // 或且是檔案協議
// 如果不是流並且不可以url_seek
if(!uc->is_streamed && url_seek(uc, 0, SEEK_SET) < 0) uc->is_streamed= 1; // 強制為流
// 輸出 引數: URL上下文
*puc = uc; return 0; fail: *puc = NULL; #if CONFIG_NETWORK ff_network_close(); #endif return err; }
|
先來看看url_get_max_packet_size函式
int url_get_max_packet_size(URLContext *h) { return h->max_packet_size; // 包最大多大, 被上面初始化為0 }
|
進入url_fdopen函式:
int url_fdopen(
ByteIOContext **s, // 輸出引數: 位元組IO上下文
URLContext *h) // URL上下文 { uint8_t *buffer; int buffer_size, max_packet_size;
max_packet_size = url_get_max_packet_size(h); if (max_packet_size) { buffer_size = max_packet_size; } else { buffer_size = IO_BUFFER_SIZE; // 緩衝大小為IO_BUFFER_SIZE } buffer = av_malloc(buffer_size); // 分配緩衝 if (!buffer) return AVERROR(ENOMEM);
*s = av_mallocz(sizeof(ByteIOContext)); // 分配位元組IO上下文
if(!*s) { av_free(buffer); return AVERROR(ENOMEM); }
if (init_put_byte(*s, buffer, buffer_size, (h->flags & URL_WRONLY || h->flags & URL_RDWR), h, url_read, url_write, url_seek) < 0) { av_free(buffer); av_freep(s); return AVERROR(EIO); } (*s)->is_streamed = h->is_streamed; // 是否為流 (*s)->max_packet_size = max_packet_size; // 包最大多大 if(h->prot) { (*s)->read_pause = (int (*)(void *, int))h->prot->url_read_pause; // 讀暫停函式 (*s)->read_seek = (int64_t (*)(void *, int, int64_t, int))h->prot->url_read_seek; // 讀seek函式 } return 0; }
|
進入init_put_byte函式:
int init_put_byte(ByteIOContext *s, // 位元組IO上下文 unsigned char *buffer, // 緩衝 int buffer_size, // 緩衝的大小 int write_flag, // 寫標誌 void *opaque, // URL上下文 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)) // 調整檔案指標 { s->buffer = buffer; s->buffer_size = buffer_size; s->buf_ptr = buffer; s->opaque = opaque; url_resetbuf(s, write_flag ? URL_WRONLY : URL_RDONLY); s->write_packet = write_packet; s->read_packet = read_packet; s->seek = seek; s->pos = 0; s->must_flush = 0; s->eof_reached = 0; s->error = 0; s->is_streamed = 0; s->max_packet_size = 0; s->update_checksum= NULL; if(!read_packet && !write_flag){ s->pos = buffer_size; s->buf_end = s->buffer + buffer_size; } s->read_pause = NULL; s->read_seek = NULL; return 0; }
|
|
|