2 * Copyright (c) 2014 Nicolas George
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "libavutil/avassert.h"
22 #include "libavutil/avstring.h"
23 #include "libavutil/opt.h"
27 typedef struct SubfileContext
{
35 #define OFFSET(field) offsetof(SubfileContext, field)
36 #define D AV_OPT_FLAG_DECODING_PARAM
38 static const AVOption subfile_options
[] = {
39 { "start", "start offset", OFFSET(start
), AV_OPT_TYPE_INT64
, {.i64
= 0}, 0, INT64_MAX
, D
},
40 { "end", "end offset", OFFSET(end
), AV_OPT_TYPE_INT64
, {.i64
= 0}, 0, INT64_MAX
, D
},
47 static const AVClass subfile_class
= {
48 .class_name
= "subfile",
49 .item_name
= av_default_item_name
,
50 .option
= subfile_options
,
51 .version
= LIBAVUTIL_VERSION_INT
,
54 static int slave_seek(URLContext
*h
)
56 SubfileContext
*c
= h
->priv_data
;
59 if ((ret
= ffurl_seek(c
->h
, c
->pos
, SEEK_SET
)) != c
->pos
) {
62 av_log(h
, AV_LOG_ERROR
, "Impossible to seek in file: %s\n",
69 static int subfile_open(URLContext
*h
, const char *filename
, int flags
,
70 AVDictionary
**options
)
72 SubfileContext
*c
= h
->priv_data
;
78 if (c
->end
<= c
->start
) {
79 av_log(h
, AV_LOG_ERROR
, "end before start\n");
80 return AVERROR(EINVAL
);
82 av_strstart(filename
, "subfile:", &filename
);
83 ret
= ffurl_open_whitelist(&c
->h
, filename
, flags
, &h
->interrupt_callback
,
84 options
, h
->protocol_whitelist
, h
->protocol_blacklist
, h
);
88 if ((ret
= slave_seek(h
)) < 0) {
95 static int subfile_close(URLContext
*h
)
97 SubfileContext
*c
= h
->priv_data
;
98 return ffurl_closep(&c
->h
);
101 static int subfile_read(URLContext
*h
, unsigned char *buf
, int size
)
103 SubfileContext
*c
= h
->priv_data
;
104 int64_t rest
= c
->end
- c
->pos
;
109 size
= FFMIN(size
, rest
);
110 ret
= ffurl_read(c
->h
, buf
, size
);
116 static int64_t subfile_seek(URLContext
*h
, int64_t pos
, int whence
)
118 SubfileContext
*c
= h
->priv_data
;
119 int64_t new_pos
, end
;
122 if (whence
== AVSEEK_SIZE
|| whence
== SEEK_END
) {
124 if (end
== INT64_MAX
&& (end
= ffurl_seek(c
->h
, 0, AVSEEK_SIZE
)) < 0)
130 return end
- c
->start
;
132 new_pos
= c
->start
+ pos
;
135 new_pos
= c
->pos
+ pos
;
143 if (new_pos
< c
->start
)
144 return AVERROR(EINVAL
);
146 if ((ret
= slave_seek(h
)) < 0)
148 return c
->pos
- c
->start
;
151 const URLProtocol ff_subfile_protocol
= {
153 .url_open2
= subfile_open
,
154 .url_read
= subfile_read
,
155 .url_seek
= subfile_seek
,
156 .url_close
= subfile_close
,
157 .priv_data_size
= sizeof(SubfileContext
),
158 .priv_data_class
= &subfile_class
,
159 .default_whitelist
= "file",