int ijk_av_dict_copy(IjkAVDictionary **dst, const IjkAVDictionary *src, int flags) { IjkAVDictionaryEntry *t = NULL; while ((t = ijk_av_dict_get(src, "", t, IJK_AV_DICT_IGNORE_SUFFIX))) { int ret = ijk_av_dict_set(dst, t->key, t->value, flags); if (ret < 0) return ret; } return 0; }
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; }
int ijk_av_dict_set(IjkAVDictionary **pm, const char *key, const char *value, int flags) { IjkAVDictionary *m = *pm; IjkAVDictionaryEntry *tag = NULL; char *oldval = NULL, *copy_key = NULL, *copy_value = NULL; if (!(flags & IJK_AV_DICT_MULTIKEY)) { tag = ijk_av_dict_get(m, key, NULL, flags); } if (flags & IJK_AV_DICT_DONT_STRDUP_KEY) copy_key = (void *)key; else copy_key = strdup(key); if (flags & IJK_AV_DICT_DONT_STRDUP_VAL) copy_value = (void *)value; else if (copy_key) copy_value = strdup(value); if (!m) m = *pm = (IjkAVDictionary *)calloc(1, sizeof(*m)); if (!m || (key && !copy_key) || (value && !copy_value)) goto err_out; if (tag) { if (flags & IJK_AV_DICT_DONT_OVERWRITE) { free(copy_key); free(copy_value); return 0; } if (flags & IJK_AV_DICT_APPEND) oldval = tag->value; else free(tag->value); free(tag->key); *tag = m->elems[--m->count]; } else if (copy_value) { IjkAVDictionaryEntry *tmp = (IjkAVDictionaryEntry *)realloc(m->elems, (m->count + 1) * sizeof(*m->elems)); if (!tmp) goto err_out; m->elems = tmp; } if (copy_value) { m->elems[m->count].key = copy_key; m->elems[m->count].value = copy_value; if (oldval && flags & IJK_AV_DICT_APPEND) { size_t len = strlen(oldval) + strlen(copy_value) + 1; char *newval = (char *)calloc(1, len); if (!newval) goto err_out; strlcat(newval, oldval, len); ijk_av_freep(&oldval); strlcat(newval, copy_value, len); m->elems[m->count].value = newval; ijk_av_freep(©_value); } m->count++; } else { ijk_av_freep(©_key); } if (!m->count) { ijk_av_freep(&m->elems); ijk_av_freep(pm); } return 0; err_out: if (m && !m->count) { ijk_av_freep(&m->elems); ijk_av_freep(pm); } free(copy_key); free(copy_value); return -1; }
static int ijkio_httphook_open(IjkURLContext *h, const char *arg, int flags, IjkAVDictionary **options) { Context *c = h->priv_data; int ret = 0; IjkAVDictionaryEntry *t = NULL; c->ijkio_app_ctx = h->ijkio_app_ctx; c->ijkio_interrupt_callback = h->ijkio_app_ctx->ijkio_interrupt_callback; t = ijk_av_dict_get(*options, "ijkapplication", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->app_ctx_intptr = (int64_t)strtoll(t->value, NULL, 10); c->app_ctx = (AVApplicationContext *)(intptr_t)c->app_ctx_intptr; } else { goto fail; } t = ijk_av_dict_get(*options, "ijkinject-segment-index", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->segment_index = (int)strtoll(t->value, NULL, 10); } t = ijk_av_dict_get(*options, "ijkhttphook-test-fail-point", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->test_fail_point = (int64_t)strtoll(t->value, NULL, 10); } ijk_av_strstart(arg, "httphook:", &arg); ret = ijkio_urlhook_init(h, arg, flags, options); if (ret) goto fail; ret = ijkio_urlhook_call_inject(h); if (ret) goto fail; ret = ijkio_urlhook_reconnect(h, NULL); while (ret && c->abort_request == 0) { int inject_ret = 0; switch (ret) { case IJKAVERROR_EXIT: goto fail; } c->app_io_ctrl.retry_counter++; inject_ret = ijkio_urlhook_call_inject(h); if (inject_ret) { ret = IJKAVERROR_EXIT; goto fail; } if (!c->app_io_ctrl.is_handled) goto fail; av_log(NULL, AV_LOG_INFO, "%s: will reconnect at start\n", __func__); ret = ijkio_httphook_reconnect_at(h, 0); av_log(NULL, AV_LOG_INFO, "%s: did reconnect at start: %d\n", __func__, ret); if (ret) c->app_io_ctrl.retry_counter++; } fail: return 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; }