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
;
75 if (c
->end
<= c
->start
) {
76 av_log(h
, AV_LOG_ERROR
, "end before start\n");
77 return AVERROR(EINVAL
);
79 av_strstart(filename
, "subfile:", &filename
);
80 ret
= ffurl_open(&c
->h
, filename
, flags
, &h
->interrupt_callback
, options
);
84 if ((ret
= slave_seek(h
)) < 0) {
91 static int subfile_close(URLContext
*h
)
93 SubfileContext
*c
= h
->priv_data
;
94 return ffurl_close(c
->h
);
97 static int subfile_read(URLContext
*h
, unsigned char *buf
, int size
)
99 SubfileContext
*c
= h
->priv_data
;
100 int64_t rest
= c
->end
- c
->pos
;
105 size
= FFMIN(size
, rest
);
106 ret
= ffurl_read(c
->h
, buf
, size
);
112 static int64_t subfile_seek(URLContext
*h
, int64_t pos
, int whence
)
114 SubfileContext
*c
= h
->priv_data
;
115 int64_t new_pos
= -1;
118 if (whence
== AVSEEK_SIZE
)
119 return c
->end
- c
->start
;
122 new_pos
= c
->start
+ pos
;
128 new_pos
= c
->end
+ c
->pos
;
131 if (new_pos
< c
->start
)
132 return AVERROR(EINVAL
);
134 if ((ret
= slave_seek(h
)) < 0)
136 return c
->pos
- c
->start
;
139 URLProtocol ff_subfile_protocol
= {
141 .url_open2
= subfile_open
,
142 .url_read
= subfile_read
,
143 .url_seek
= subfile_seek
,
144 .url_close
= subfile_close
,
145 .priv_data_size
= sizeof(SubfileContext
),
146 .priv_data_class
= &subfile_class
,