1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (c) 2014 Nicolas George 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * This file is part of FFmpeg. 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public License 8cabdff1aSopenharmony_ci * as published by the Free Software Foundation; either 9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 10cabdff1aSopenharmony_ci * 11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14cabdff1aSopenharmony_ci * GNU Lesser General Public License for more details. 15cabdff1aSopenharmony_ci * 16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public License 17cabdff1aSopenharmony_ci * along with FFmpeg; if not, write to the Free Software Foundation, Inc., 18cabdff1aSopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19cabdff1aSopenharmony_ci */ 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 22cabdff1aSopenharmony_ci#include "libavutil/opt.h" 23cabdff1aSopenharmony_ci#include "avformat.h" 24cabdff1aSopenharmony_ci#include "url.h" 25cabdff1aSopenharmony_ci 26cabdff1aSopenharmony_citypedef struct SubfileContext { 27cabdff1aSopenharmony_ci const AVClass *class; 28cabdff1aSopenharmony_ci URLContext *h; 29cabdff1aSopenharmony_ci int64_t start; 30cabdff1aSopenharmony_ci int64_t end; 31cabdff1aSopenharmony_ci int64_t pos; 32cabdff1aSopenharmony_ci} SubfileContext; 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_ci#define OFFSET(field) offsetof(SubfileContext, field) 35cabdff1aSopenharmony_ci#define D AV_OPT_FLAG_DECODING_PARAM 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_cistatic const AVOption subfile_options[] = { 38cabdff1aSopenharmony_ci { "start", "start offset", OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, D }, 39cabdff1aSopenharmony_ci { "end", "end offset", OFFSET(end), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, D }, 40cabdff1aSopenharmony_ci { NULL } 41cabdff1aSopenharmony_ci}; 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_ci#undef OFFSET 44cabdff1aSopenharmony_ci#undef D 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_cistatic const AVClass subfile_class = { 47cabdff1aSopenharmony_ci .class_name = "subfile", 48cabdff1aSopenharmony_ci .item_name = av_default_item_name, 49cabdff1aSopenharmony_ci .option = subfile_options, 50cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 51cabdff1aSopenharmony_ci}; 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_cistatic int slave_seek(URLContext *h) 54cabdff1aSopenharmony_ci{ 55cabdff1aSopenharmony_ci SubfileContext *c = h->priv_data; 56cabdff1aSopenharmony_ci int64_t ret; 57cabdff1aSopenharmony_ci 58cabdff1aSopenharmony_ci if ((ret = ffurl_seek(c->h, c->pos, SEEK_SET)) != c->pos) { 59cabdff1aSopenharmony_ci if (ret >= 0) 60cabdff1aSopenharmony_ci ret = AVERROR_BUG; 61cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Impossible to seek in file: %s\n", 62cabdff1aSopenharmony_ci av_err2str(ret)); 63cabdff1aSopenharmony_ci return ret; 64cabdff1aSopenharmony_ci } 65cabdff1aSopenharmony_ci return 0; 66cabdff1aSopenharmony_ci} 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_cistatic int subfile_open(URLContext *h, const char *filename, int flags, 69cabdff1aSopenharmony_ci AVDictionary **options) 70cabdff1aSopenharmony_ci{ 71cabdff1aSopenharmony_ci SubfileContext *c = h->priv_data; 72cabdff1aSopenharmony_ci int ret; 73cabdff1aSopenharmony_ci 74cabdff1aSopenharmony_ci if (!c->end) 75cabdff1aSopenharmony_ci c->end = INT64_MAX; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci if (c->end <= c->start) { 78cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "end before start\n"); 79cabdff1aSopenharmony_ci return AVERROR(EINVAL); 80cabdff1aSopenharmony_ci } 81cabdff1aSopenharmony_ci av_strstart(filename, "subfile:", &filename); 82cabdff1aSopenharmony_ci ret = ffurl_open_whitelist(&c->h, filename, flags, &h->interrupt_callback, 83cabdff1aSopenharmony_ci options, h->protocol_whitelist, h->protocol_blacklist, h); 84cabdff1aSopenharmony_ci if (ret < 0) 85cabdff1aSopenharmony_ci return ret; 86cabdff1aSopenharmony_ci c->pos = c->start; 87cabdff1aSopenharmony_ci if ((ret = slave_seek(h)) < 0) { 88cabdff1aSopenharmony_ci ffurl_closep(&c->h); 89cabdff1aSopenharmony_ci return ret; 90cabdff1aSopenharmony_ci } 91cabdff1aSopenharmony_ci return 0; 92cabdff1aSopenharmony_ci} 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_cistatic int subfile_close(URLContext *h) 95cabdff1aSopenharmony_ci{ 96cabdff1aSopenharmony_ci SubfileContext *c = h->priv_data; 97cabdff1aSopenharmony_ci return ffurl_closep(&c->h); 98cabdff1aSopenharmony_ci} 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_cistatic int subfile_read(URLContext *h, unsigned char *buf, int size) 101cabdff1aSopenharmony_ci{ 102cabdff1aSopenharmony_ci SubfileContext *c = h->priv_data; 103cabdff1aSopenharmony_ci int64_t rest = c->end - c->pos; 104cabdff1aSopenharmony_ci int ret; 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci if (rest <= 0) 107cabdff1aSopenharmony_ci return AVERROR_EOF; 108cabdff1aSopenharmony_ci size = FFMIN(size, rest); 109cabdff1aSopenharmony_ci ret = ffurl_read(c->h, buf, size); 110cabdff1aSopenharmony_ci if (ret >= 0) 111cabdff1aSopenharmony_ci c->pos += ret; 112cabdff1aSopenharmony_ci return ret; 113cabdff1aSopenharmony_ci} 114cabdff1aSopenharmony_ci 115cabdff1aSopenharmony_cistatic int64_t subfile_seek(URLContext *h, int64_t pos, int whence) 116cabdff1aSopenharmony_ci{ 117cabdff1aSopenharmony_ci SubfileContext *c = h->priv_data; 118cabdff1aSopenharmony_ci int64_t new_pos, end; 119cabdff1aSopenharmony_ci int ret; 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_ci if (whence == AVSEEK_SIZE || whence == SEEK_END) { 122cabdff1aSopenharmony_ci end = c->end; 123cabdff1aSopenharmony_ci if (end == INT64_MAX && (end = ffurl_seek(c->h, 0, AVSEEK_SIZE)) < 0) 124cabdff1aSopenharmony_ci return end; 125cabdff1aSopenharmony_ci } 126cabdff1aSopenharmony_ci 127cabdff1aSopenharmony_ci if (whence == AVSEEK_SIZE) 128cabdff1aSopenharmony_ci return end - c->start; 129cabdff1aSopenharmony_ci switch (whence) { 130cabdff1aSopenharmony_ci case SEEK_SET: 131cabdff1aSopenharmony_ci new_pos = c->start + pos; 132cabdff1aSopenharmony_ci break; 133cabdff1aSopenharmony_ci case SEEK_CUR: 134cabdff1aSopenharmony_ci new_pos = c->pos + pos; 135cabdff1aSopenharmony_ci break; 136cabdff1aSopenharmony_ci case SEEK_END: 137cabdff1aSopenharmony_ci new_pos = end + pos; 138cabdff1aSopenharmony_ci break; 139cabdff1aSopenharmony_ci } 140cabdff1aSopenharmony_ci if (new_pos < c->start) 141cabdff1aSopenharmony_ci return AVERROR(EINVAL); 142cabdff1aSopenharmony_ci c->pos = new_pos; 143cabdff1aSopenharmony_ci if ((ret = slave_seek(h)) < 0) 144cabdff1aSopenharmony_ci return ret; 145cabdff1aSopenharmony_ci return c->pos - c->start; 146cabdff1aSopenharmony_ci} 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_ciconst URLProtocol ff_subfile_protocol = { 149cabdff1aSopenharmony_ci .name = "subfile", 150cabdff1aSopenharmony_ci .url_open2 = subfile_open, 151cabdff1aSopenharmony_ci .url_read = subfile_read, 152cabdff1aSopenharmony_ci .url_seek = subfile_seek, 153cabdff1aSopenharmony_ci .url_close = subfile_close, 154cabdff1aSopenharmony_ci .priv_data_size = sizeof(SubfileContext), 155cabdff1aSopenharmony_ci .priv_data_class = &subfile_class, 156cabdff1aSopenharmony_ci .default_whitelist = "file", 157cabdff1aSopenharmony_ci}; 158