static int64_t ijkio_cache_file_overrang(IjkURLContext *h, int64_t *cur_pos, int size) { IjkIOCacheContext *c = h->priv_data; av_log(NULL, AV_LOG_WARNING, "ijkio_cache_file_overrang will flush file\n"); pthread_mutex_lock(&h->ijkio_app_ctx->mutex); if (!c->ijkio_app_ctx->shared) { ijk_map_remove(c->cache_info_map, (int64_t)c->cur_file_no); ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy); ijk_map_clear(c->cache_info_map); memset(c->tree_info, 0, sizeof(IjkCacheTreeInfo)); ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info); *c->last_physical_pos = 0; c->cache_physical_pos = 0; c->io_eof_reached = 0; c->file_logical_pos = c->read_logical_pos; *cur_pos = lseek(c->fd, 0, SEEK_SET); if (*cur_pos < 0) { goto fail; } } else { goto fail; } pthread_mutex_unlock(&h->ijkio_app_ctx->mutex); return c->cache_max_capacity; fail: pthread_mutex_unlock(&h->ijkio_app_ctx->mutex); return FILE_RW_ERROR; }
static int ijkio_cache_file_error(IjkURLContext *h) { IjkIOCacheContext *c = h->priv_data; av_log(NULL, AV_LOG_WARNING, "ijkio_cache_file_error\n"); if (c && c->file_handle_retry_count > 3) { pthread_mutex_lock(&h->ijkio_app_ctx->mutex); c->file_error_count++; if (!c->ijkio_app_ctx->shared) { ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy); ijk_map_clear(c->cache_info_map); c->tree_info = NULL; *c->last_physical_pos = 0; c->cache_physical_pos = 0; c->file_inner_pos = 0; c->io_eof_reached = 0; c->file_logical_pos = c->read_logical_pos; close(c->fd); c->fd = -1; c->ijkio_app_ctx->fd = -1; if (c->file_error_count > 3) { c->cache_file_close = 1; remove(c->cache_file_path); av_log(NULL, AV_LOG_WARNING, "ijkio_cache_file_error will remove file\n"); goto fail; } c->fd = open(c->cache_file_path, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0600); c->ijkio_app_ctx->fd = c->fd; if (c->fd >= 0) { c->file_handle_retry_count = 0; c->tree_info = calloc(1, sizeof(IjkCacheTreeInfo)); if (!c->tree_info) { c->cache_file_close = 1; goto fail; } ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info); } else { av_log(NULL, AV_LOG_WARNING, "ijkio_cache_file_error will cache_file_close\n"); c->cache_file_close = 1; goto fail; } } pthread_mutex_unlock(&h->ijkio_app_ctx->mutex); } return 0; fail: pthread_mutex_unlock(&h->ijkio_app_ctx->mutex); return FILE_RW_ERROR; }
int ijkio_manager_io_open(IjkIOManagerContext *h, const char *url, int flags, IjkAVDictionary **options) { int ret = -1; if (!h) return ret; IjkAVDictionaryEntry *t = NULL; t = ijk_av_dict_get(*options, "cache_file_path", t, IJK_AV_DICT_IGNORE_SUFFIX); if (t) { strcpy(h->ijkio_app_ctx->cache_file_path, t->value); } if (h->ijkio_app_ctx == NULL) { return -1; } h->ijkio_app_ctx->ijkio_interrupt_callback = h->ijkio_interrupt_callback; IjkURLContext *inner = NULL; ijkio_alloc_url(&inner, url); if (inner) { inner->ijkio_app_ctx = h->ijkio_app_ctx; if (h->ijk_ctx_map) { ijkio_manager_set_all_ctx_pause(h); inner->state = IJKURL_STARTED; ijk_map_put(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx, inner); } ret = inner->prot->url_open2(inner, url, flags, options); if (ret != 0) goto fail; return ret; } fail: if (inner) { if (inner->prot && inner->prot->url_close) ret = inner->prot->url_close(inner); if (h->ijk_ctx_map) { ijk_map_remove(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx); } ijk_av_freep(&inner->priv_data); ijk_av_freep(&inner); } return -1; }
static int ijkio_cache_sync_read(IjkURLContext *h, unsigned char *buf, int size) { IjkIOCacheContext *c= h->priv_data; int64_t ret = 0; int to_read = size; int to_copy = 0; IjkCacheEntry *entry = NULL, *next_entry = NULL, *next[2] = {NULL, NULL}; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); if (to_read <= 0) { return to_read; } if (c->tree_info) { entry = ijk_av_tree_find(c->tree_info->root, &c->read_logical_pos, cmp, (void**)next); } if (!entry) entry = next[0]; if (entry) { int64_t in_block_pos = c->read_logical_pos - entry->logical_pos; if (in_block_pos < entry->size && entry->logical_pos <= c->read_logical_pos) { int64_t physical_target = entry->physical_pos + in_block_pos; if (c->cache_physical_pos != physical_target) { ret = lseek(c->fd, physical_target, SEEK_SET); } else { ret = c->cache_physical_pos; } if (ret >= 0) { c->cache_physical_pos = ret; to_copy = (int)FFMIN(to_read, entry->size - in_block_pos); ret = wrapped_file_read(h, buf, to_copy); if (ret >= 0) { c->cache_physical_pos += ret; return (int)ret; } } av_log(NULL, AV_LOG_ERROR, "%s cache file is bad, will try recreate\n", __func__); ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy); ijk_map_clear(c->cache_info_map); c->tree_info = NULL; *c->last_physical_pos = 0; c->cache_physical_pos = 0; c->io_eof_reached = 0; close(c->fd); c->fd = open(c->cache_file_path, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0600); c->ijkio_app_ctx->fd = c->fd; if (c->fd >= 0) { c->tree_info = calloc(1, sizeof(IjkCacheTreeInfo)); if (c->tree_info) { ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info); } } } } if (c->read_logical_pos >= c->logical_size) { c->io_eof_reached = 1; return 0; } if (c->async_open > 0) { ret = ijkio_cache_io_open(h, c->inner_url, c->inner_flags, &c->inner_options); if (ret != 0) { return (int)ret; } c->async_open = 0; } if (c->read_inner_pos != c->read_logical_pos) { ret = c->inner->prot->url_seek(c->inner, c->read_logical_pos, SEEK_SET); if (ret < 0) { return (int)ret; } c->read_inner_pos = ret; } next_entry = next[1]; if (next_entry && next_entry->logical_pos > c->read_logical_pos) { to_copy = (int)FFMIN(to_read, next_entry->logical_pos - c->read_logical_pos); } else { to_copy = to_read; } ret = wrapped_url_read(h, buf, to_copy); if (ret <= 0) return (int)ret; c->read_inner_pos += ret; if (c->fd >= 0 && c->tree_info && !c->only_read_file) { sync_add_entry(h, buf, (int)ret); } return (int)ret; }
static int ijkio_cache_open(IjkURLContext *h, const char *url, int flags, IjkAVDictionary **options) { IjkIOCacheContext *c= h->priv_data; int ret = 0; int64_t cur_exist_file_size = 0; if (!c) return IJKAVERROR(ENOSYS); c->ijkio_app_ctx = h->ijkio_app_ctx; if (c->ijkio_app_ctx == NULL) { return -1; } c->async_open = 0; c->ijkio_interrupt_callback = h->ijkio_app_ctx->ijkio_interrupt_callback; c->cache_file_forwards_capacity = 0; ijk_av_strstart(url, "cache:", &url); c->cache_max_capacity = DEFAULT_CACHE_MAX_CAPACITY; IjkAVDictionaryEntry *t = NULL; t = ijk_av_dict_get(*options, "cache_max_capacity", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->cache_max_capacity = strtoll(t->value, NULL, 10); } t = ijk_av_dict_get(*options, "cache_file_forwards_capacity", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->cache_file_forwards_capacity = strtoll(t->value, NULL, 10); } t = ijk_av_dict_get(*options, "cache_file_close", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->cache_file_close = (int)strtol(t->value, NULL, 10); c->cache_file_close = c->cache_file_close != 0 ? 1 : 0; } t = ijk_av_dict_get(*options, "cur_file_no", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->cur_file_no = (int)strtol(t->value, NULL, 10); } t = ijk_av_dict_get(*options, "only_read_file", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->only_read_file = (int)strtol(t->value, NULL, 10); if (c->only_read_file) { c->cache_file_forwards_capacity = 0; } } c->cache_file_path = c->ijkio_app_ctx->cache_file_path; if (c->cache_file_path == NULL || 0 == strlen(c->cache_file_path)) { c->cache_file_close = 1; } c->threadpool_ctx = c->ijkio_app_ctx->threadpool_ctx; c->cache_info_map = c->ijkio_app_ctx->cache_info_map; c->last_physical_pos = &c->ijkio_app_ctx->last_physical_pos; c->cache_count_bytes = &c->ijkio_app_ctx->cache_count_bytes; if (!c->last_physical_pos || !c->threadpool_ctx || !c->cache_info_map) { return -1; } if (!c->cache_file_close) { do { if (c->ijkio_app_ctx->fd >= 0) { c->fd = c->ijkio_app_ctx->fd; } else { if (ijk_map_size(c->cache_info_map) > 0) { av_log(NULL, AV_LOG_INFO, "ijkio cache will use the data that already exists\n"); c->fd = open(c->cache_file_path, O_RDWR | O_BINARY, 0600); c->async_open = 1; cur_exist_file_size = lseek(c->fd, 0, SEEK_END); if (cur_exist_file_size < *c->last_physical_pos) { av_log(NULL, AV_LOG_WARNING, "ijkio cache exist is error, will delete last_physical_pos = %lld, cur_exist_file_size = %lld\n", *c->last_physical_pos, cur_exist_file_size); ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy); ijk_map_clear(c->cache_info_map); *c->last_physical_pos = 0; c->cache_physical_pos = 0; } } else { c->fd = open(c->cache_file_path, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0600); } c->ijkio_app_ctx->fd = c->fd; } if (c->fd < 0) { c->cache_file_close = 1; break; } int64_t seek_ret = lseek(c->fd, *c->last_physical_pos, SEEK_SET); if (seek_ret < 0) { c->cache_file_close = 1; close(c->fd); c->fd = -1; c->ijkio_app_ctx->fd = -1; break; } else { c->cache_physical_pos = *c->last_physical_pos; } c->tree_info = ijk_map_get(c->cache_info_map, (int64_t)c->cur_file_no); if (c->tree_info == NULL) { c->tree_info = calloc(1, sizeof(IjkCacheTreeInfo)); c->tree_info->physical_init_pos = *c->last_physical_pos; ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info); } else { if (c->tree_info->physical_size > 200 * 1024 && c->tree_info->file_size > 0) { c->logical_size = c->tree_info->file_size; c->async_open = 1; } else { c->async_open = 0; } } } while(0); } ret = ijkio_alloc_url(&(c->inner), url); if (c->inner && !ret) { c->inner->ijkio_app_ctx = c->ijkio_app_ctx; if (c->logical_size <= 0 || c->async_open == 0) { c->async_open = 0; ret = ijkio_cache_io_open(h, url, flags, options); if (ret != 0) goto url_fail; } else { c->tree_info->file_size = c->logical_size; ijk_av_dict_copy(&c->inner_options, *options, 0); strcpy(c->inner_url, url); c->inner_flags = flags; call_inject_statistic(h); } } ret = pthread_mutex_init(&c->file_mutex, NULL); if (ret != 0) { av_log(NULL, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", av_err2str(ret)); goto file_mutex_fail; } ret = pthread_cond_init(&c->cond_wakeup_main, NULL); if (ret != 0) { av_log(NULL, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret)); goto cond_wakeup_main_fail; } ret = pthread_cond_init(&c->cond_wakeup_file_background, NULL); if (ret != 0) { av_log(NULL, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret)); goto cond_wakeup_file_background_fail; } ret = pthread_cond_init(&c->cond_wakeup_exit, NULL); if (ret != 0) { av_log(NULL, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret)); goto cond_wakeup_exit_fail; } if (!c->cache_file_close && c->cache_file_forwards_capacity) { c->task_is_running = 1; ret = ijk_threadpool_add(c->threadpool_ctx, ijkio_cache_task, h, NULL, 0); if (ret) { c->task_is_running = 0; pthread_cond_signal(&c->cond_wakeup_exit); goto thread_fail; } } return 0; thread_fail: pthread_cond_destroy(&c->cond_wakeup_exit); cond_wakeup_exit_fail: pthread_cond_destroy(&c->cond_wakeup_file_background); cond_wakeup_file_background_fail: pthread_cond_destroy(&c->cond_wakeup_main); cond_wakeup_main_fail: pthread_mutex_destroy(&c->file_mutex); file_mutex_fail: if (c->async_open) { if (c->inner_options) { ijk_av_dict_free(&c->inner_options); } } else { if (c->inner) { if (c->inner->prot && c->inner->prot->url_close) { c->inner->prot->url_close(c->inner); } } } url_fail: if (c->inner) { ijk_av_freep(&c->inner->priv_data); ijk_av_freep(&c->inner); } return ret; }