Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}