lavf: allow custom IO for all files

Some (de)muxers open additional files beyond the main IO context.
Currently, they call avio_open() directly, which prevents the caller
from using custom IO for such streams.

This commit adds callbacks to AVFormatContext that default to
avio_open2()/avio_close(), but can be overridden by the caller. All
muxers and demuxers using AVIO are switched to using those callbacks
instead of calling avio_open()/avio_close() directly.

(de)muxers that use the URLProtocol layer directly instead of AVIO
remain unconverted for now. This should be fixed in later commits.
This commit is contained in:
Anton Khirnov 2016-01-16 17:53:43 +01:00
parent 68395f8c99
commit 9f61abc811
15 changed files with 130 additions and 68 deletions

View File

@ -13,6 +13,10 @@ libavutil: 2015-08-28
API changes, most recent first: API changes, most recent first:
2016-xx-xx - xxxxxxx - lavf 57.3.0 - avformat.h
Add AVFormatContext.opaque, io_open and io_close, allowing custom IO
for muxers and demuxers that open additional files.
2015-xx-xx - xxxxxxx - lavc 57.12.0 - avcodec.h 2015-xx-xx - xxxxxxx - lavc 57.12.0 - avcodec.h
Add AVCodecDescriptor.profiles and avcodec_profile_name(). Add AVCodecDescriptor.profiles and avcodec_profile_name().

View File

@ -1229,6 +1229,39 @@ typedef struct AVFormatContext {
* Must not be accessed in any way by callers. * Must not be accessed in any way by callers.
*/ */
AVFormatInternal *internal; AVFormatInternal *internal;
/**
* Arbitrary user data set by the caller.
*/
void *opaque;
/**
* A callback for opening new IO streams.
*
* Certain muxers or demuxers (e.g. for various playlist-based formats) need
* to open additional files during muxing or demuxing. This callback allows
* the caller to provide custom IO in such cases.
*
* @param s the format context
* @param pb on success, the newly opened IO context should be returned here
* @param url the url to open
* @param flags a combination of AVIO_FLAG_*
* @param options a dictionary of additional options, with the same
* semantics as in avio_open2()
* @return 0 on success, a negative AVERROR code on failure
*
* @note Certain muxers and demuxers do nesting, i.e. they open one or more
* additional internal format contexts. Thus the AVFormatContext pointer
* passed to this callback may be different from the one facing the caller.
* It will, however, have the same 'opaque' field.
*/
int (*io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url,
int flags, AVDictionary **options);
/**
* A callback for closing the streams opened with AVFormatContext.io_open().
*/
void (*io_close)(struct AVFormatContext *s, AVIOContext *pb);
} AVFormatContext; } AVFormatContext;
typedef struct AVPacketList { typedef struct AVPacketList {

View File

@ -444,7 +444,7 @@ static int write_manifest(AVFormatContext *s, int final)
AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0); AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
snprintf(temp_filename, sizeof(temp_filename), "%s.tmp", s->filename); snprintf(temp_filename, sizeof(temp_filename), "%s.tmp", s->filename);
ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL); ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL);
if (ret < 0) { if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
return ret; return ret;
@ -532,7 +532,7 @@ static int write_manifest(AVFormatContext *s, int final)
avio_printf(out, "\t</Period>\n"); avio_printf(out, "\t</Period>\n");
avio_printf(out, "</MPD>\n"); avio_printf(out, "</MPD>\n");
avio_flush(out); avio_flush(out);
avio_close(out); ff_format_io_close(s, &out);
return ff_rename(temp_filename, s->filename); return ff_rename(temp_filename, s->filename);
} }
@ -604,6 +604,9 @@ static int dash_write_header(AVFormatContext *s)
os->ctx = ctx; os->ctx = ctx;
ctx->oformat = oformat; ctx->oformat = oformat;
ctx->interrupt_callback = s->interrupt_callback; ctx->interrupt_callback = s->interrupt_callback;
ctx->opaque = s->opaque;
ctx->io_close = s->io_close;
ctx->io_open = s->io_open;
if (!(st = avformat_new_stream(ctx, NULL))) { if (!(st = avformat_new_stream(ctx, NULL))) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);

View File

@ -140,8 +140,7 @@ static void hds_free(AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++) { for (i = 0; i < s->nb_streams; i++) {
OutputStream *os = &c->streams[i]; OutputStream *os = &c->streams[i];
if (os->out) if (os->out)
avio_close(os->out); ff_format_io_close(s, &os->out);
os->out = NULL;
if (os->ctx && os->ctx_inited) if (os->ctx && os->ctx_inited)
av_write_trailer(os->ctx); av_write_trailer(os->ctx);
if (os->ctx && os->ctx->pb) if (os->ctx && os->ctx->pb)
@ -171,8 +170,7 @@ static int write_manifest(AVFormatContext *s, int final)
snprintf(filename, sizeof(filename), "%s/index.f4m", s->filename); snprintf(filename, sizeof(filename), "%s/index.f4m", s->filename);
snprintf(temp_filename, sizeof(temp_filename), "%s/index.f4m.tmp", s->filename); snprintf(temp_filename, sizeof(temp_filename), "%s/index.f4m.tmp", s->filename);
ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL);
&s->interrupt_callback, NULL);
if (ret < 0) { if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
return ret; return ret;
@ -190,7 +188,7 @@ static int write_manifest(AVFormatContext *s, int final)
int b64_size = AV_BASE64_SIZE(os->metadata_size); int b64_size = AV_BASE64_SIZE(os->metadata_size);
char *base64 = av_malloc(b64_size); char *base64 = av_malloc(b64_size);
if (!base64) { if (!base64) {
avio_close(out); ff_format_io_close(s, &out);
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }
av_base64_encode(base64, b64_size, os->metadata, os->metadata_size); av_base64_encode(base64, b64_size, os->metadata, os->metadata_size);
@ -203,7 +201,7 @@ static int write_manifest(AVFormatContext *s, int final)
} }
avio_printf(out, "</manifest>\n"); avio_printf(out, "</manifest>\n");
avio_flush(out); avio_flush(out);
avio_close(out); ff_format_io_close(s, &out);
return ff_rename(temp_filename, filename); return ff_rename(temp_filename, filename);
} }
@ -240,8 +238,7 @@ static int write_abst(AVFormatContext *s, OutputStream *os, int final)
"%s/stream%d.abst", s->filename, index); "%s/stream%d.abst", s->filename, index);
snprintf(temp_filename, sizeof(temp_filename), snprintf(temp_filename, sizeof(temp_filename),
"%s/stream%d.abst.tmp", s->filename, index); "%s/stream%d.abst.tmp", s->filename, index);
ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL);
&s->interrupt_callback, NULL);
if (ret < 0) { if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
return ret; return ret;
@ -284,15 +281,14 @@ static int write_abst(AVFormatContext *s, OutputStream *os, int final)
} }
update_size(out, afrt_pos); update_size(out, afrt_pos);
update_size(out, 0); update_size(out, 0);
avio_close(out); ff_format_io_close(s, &out);
return ff_rename(temp_filename, filename); return ff_rename(temp_filename, filename);
} }
static int init_file(AVFormatContext *s, OutputStream *os, int64_t start_ts) static int init_file(AVFormatContext *s, OutputStream *os, int64_t start_ts)
{ {
int ret, i; int ret, i;
ret = avio_open2(&os->out, os->temp_filename, AVIO_FLAG_WRITE, ret = s->io_open(s, &os->out, os->temp_filename, AVIO_FLAG_WRITE, NULL);
&s->interrupt_callback, NULL);
if (ret < 0) if (ret < 0)
return ret; return ret;
avio_wb32(os->out, 0); avio_wb32(os->out, 0);
@ -305,14 +301,13 @@ static int init_file(AVFormatContext *s, OutputStream *os, int64_t start_ts)
return 0; return 0;
} }
static void close_file(OutputStream *os) static void close_file(AVFormatContext *s, OutputStream *os)
{ {
int64_t pos = avio_tell(os->out); int64_t pos = avio_tell(os->out);
avio_seek(os->out, 0, SEEK_SET); avio_seek(os->out, 0, SEEK_SET);
avio_wb32(os->out, pos); avio_wb32(os->out, pos);
avio_flush(os->out); avio_flush(os->out);
avio_close(os->out); ff_format_io_close(s, &os->out);
os->out = NULL;
} }
static int hds_write_header(AVFormatContext *s) static int hds_write_header(AVFormatContext *s)
@ -476,7 +471,7 @@ static int hds_flush(AVFormatContext *s, OutputStream *os, int final,
avio_flush(os->ctx->pb); avio_flush(os->ctx->pb);
os->packets_written = 0; os->packets_written = 0;
close_file(os); close_file(s, os);
snprintf(target_filename, sizeof(target_filename), snprintf(target_filename, sizeof(target_filename),
"%s/stream%dSeg1-Frag%d", s->filename, index, os->fragment_index); "%s/stream%dSeg1-Frag%d", s->filename, index, os->fragment_index);

View File

@ -94,6 +94,7 @@ struct variant {
}; };
typedef struct HLSContext { typedef struct HLSContext {
AVFormatContext *ctx;
int n_variants; int n_variants;
struct variant **variants; struct variant **variants;
int cur_seq_no; int cur_seq_no;
@ -207,7 +208,7 @@ static int open_in(HLSContext *c, AVIOContext **in, const char *url)
av_dict_copy(&tmp, c->avio_opts, 0); av_dict_copy(&tmp, c->avio_opts, 0);
ret = avio_open2(in, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); ret = c->ctx->io_open(c->ctx, in, url, AVIO_FLAG_READ, &tmp);
av_dict_free(&tmp); av_dict_free(&tmp);
return ret; return ret;
@ -370,7 +371,7 @@ static int parse_playlist(HLSContext *c, const char *url,
fail: fail:
av_free(new_url); av_free(new_url);
if (close_in) if (close_in)
avio_close(in); ff_format_io_close(c->ctx, &in);
return ret; return ret;
} }
@ -514,6 +515,7 @@ static int hls_read_header(AVFormatContext *s)
HLSContext *c = s->priv_data; HLSContext *c = s->priv_data;
int ret = 0, i, j, stream_offset = 0; int ret = 0, i, j, stream_offset = 0;
c->ctx = s;
c->interrupt_callback = &s->interrupt_callback; c->interrupt_callback = &s->interrupt_callback;
if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0)

View File

@ -74,6 +74,9 @@ static int hls_mux_init(AVFormatContext *s)
oc->oformat = hls->oformat; oc->oformat = hls->oformat;
oc->interrupt_callback = s->interrupt_callback; oc->interrupt_callback = s->interrupt_callback;
oc->opaque = s->opaque;
oc->io_open = s->io_open;
oc->io_close = s->io_close;
for (i = 0; i < s->nb_streams; i++) { for (i = 0; i < s->nb_streams; i++) {
AVStream *st; AVStream *st;
@ -140,8 +143,7 @@ static int hls_window(AVFormatContext *s, int last)
int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->size); int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->size);
snprintf(temp_filename, sizeof(temp_filename), "%s.tmp", s->filename); snprintf(temp_filename, sizeof(temp_filename), "%s.tmp", s->filename);
if ((ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, if ((ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL)) < 0)
&s->interrupt_callback, NULL)) < 0)
goto fail; goto fail;
for (en = hls->list; en; en = en->next) { for (en = hls->list; en; en = en->next) {
@ -178,7 +180,7 @@ static int hls_window(AVFormatContext *s, int last)
avio_printf(out, "#EXT-X-ENDLIST\n"); avio_printf(out, "#EXT-X-ENDLIST\n");
fail: fail:
avio_closep(&out); ff_format_io_close(s, &out);
if (ret >= 0) if (ret >= 0)
ff_rename(temp_filename, s->filename); ff_rename(temp_filename, s->filename);
return ret; return ret;
@ -195,8 +197,7 @@ static int hls_start(AVFormatContext *s)
return AVERROR(EINVAL); return AVERROR(EINVAL);
c->number++; c->number++;
if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, if ((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, NULL)) < 0)
&s->interrupt_callback, NULL)) < 0)
return err; return err;
if (oc->oformat->priv_class && oc->priv_data) if (oc->oformat->priv_class && oc->priv_data)
@ -300,7 +301,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
hls->duration = 0; hls->duration = 0;
av_write_frame(oc, NULL); /* Flush any buffered data */ av_write_frame(oc, NULL); /* Flush any buffered data */
avio_close(oc->pb); ff_format_io_close(s, &oc->pb);
ret = hls_start(s); ret = hls_start(s);
@ -324,7 +325,7 @@ static int hls_write_trailer(struct AVFormatContext *s)
AVFormatContext *oc = hls->avf; AVFormatContext *oc = hls->avf;
av_write_trailer(oc); av_write_trailer(oc);
avio_closep(&oc->pb); ff_format_io_close(s, &oc->pb);
avformat_free_context(oc); avformat_free_context(oc);
av_free(hls->basename); av_free(hls->basename);
append_entry(hls, hls->duration); append_entry(hls, hls->duration);

View File

@ -238,8 +238,7 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
s->img_number) < 0 && s->img_number > 1) s->img_number) < 0 && s->img_number > 1)
return AVERROR(EIO); return AVERROR(EIO);
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if (avio_open2(&f[i], filename, AVIO_FLAG_READ, if (s1->io_open(s1, &f[i], filename, AVIO_FLAG_READ, NULL) < 0) {
&s1->interrupt_callback, NULL) < 0) {
if (i >= 1) if (i >= 1)
break; break;
av_log(s1, AV_LOG_ERROR, "Could not open file : %s\n", av_log(s1, AV_LOG_ERROR, "Could not open file : %s\n",
@ -273,7 +272,7 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
if (f[i]) { if (f[i]) {
ret[i] = avio_read(f[i], pkt->data + pkt->size, size[i]); ret[i] = avio_read(f[i], pkt->data + pkt->size, size[i]);
if (!s->is_pipe) if (!s->is_pipe)
avio_close(f[i]); ff_format_io_close(s1, &f[i]);
if (ret[i] > 0) if (ret[i] > 0)
pkt->size += ret[i]; pkt->size += ret[i];
} }

View File

@ -72,8 +72,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
return AVERROR(EIO); return AVERROR(EIO);
} }
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if (avio_open2(&pb[i], img->tmp, AVIO_FLAG_WRITE, if (s->io_open(s, &pb[i], img->tmp, AVIO_FLAG_WRITE, NULL) < 0) {
&s->interrupt_callback, NULL) < 0) {
av_log(s, AV_LOG_ERROR, "Could not open file : %s\n", img->tmp); av_log(s, AV_LOG_ERROR, "Could not open file : %s\n", img->tmp);
return AVERROR(EIO); return AVERROR(EIO);
} }
@ -91,8 +90,8 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
avio_write(pb[0], pkt->data, ysize); avio_write(pb[0], pkt->data, ysize);
avio_write(pb[1], pkt->data + ysize, (pkt->size - ysize) / 2); avio_write(pb[1], pkt->data + ysize, (pkt->size - ysize) / 2);
avio_write(pb[2], pkt->data + ysize + (pkt->size - ysize) / 2, (pkt->size - ysize) / 2); avio_write(pb[2], pkt->data + ysize + (pkt->size - ysize) / 2, (pkt->size - ysize) / 2);
avio_close(pb[1]); ff_format_io_close(s, &pb[1]);
avio_close(pb[2]); ff_format_io_close(s, &pb[2]);
} else { } else {
if (ff_guess_image2_codec(s->filename) == AV_CODEC_ID_JPEG2000) { if (ff_guess_image2_codec(s->filename) == AV_CODEC_ID_JPEG2000) {
AVStream *st = s->streams[0]; AVStream *st = s->streams[0];
@ -122,7 +121,7 @@ error:
} }
avio_flush(pb[0]); avio_flush(pb[0]);
if (!img->is_pipe) { if (!img->is_pipe) {
avio_close(pb[0]); ff_format_io_close(s, &pb[0]);
ff_rename(img->tmp, filename); ff_rename(img->tmp, filename);
} }

View File

@ -419,4 +419,10 @@ static inline int ff_rename(const char *oldpath, const char *newpath)
return 0; return 0;
} }
/**
* A wrapper around AVFormatContext.io_close that should be used
* intead of calling the pointer directly.
*/
void ff_format_io_close(AVFormatContext *s, AVIOContext **pb);
#endif /* AVFORMAT_INTERNAL_H */ #endif /* AVFORMAT_INTERNAL_H */

View File

@ -2400,8 +2400,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
} }
} }
static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref, static int mov_open_dref(AVFormatContext *s, AVIOContext **pb, char *src,
AVIOInterruptCB *int_cb) MOVDref *ref)
{ {
/* try relative path, we do not try the absolute because it can leak information about our /* try relative path, we do not try the absolute because it can leak information about our
system to an attacker */ system to an attacker */
@ -2436,7 +2436,7 @@ static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref,
av_strlcat(filename, ref->path + l + 1, 1024); av_strlcat(filename, ref->path + l + 1, 1024);
if (!avio_open2(pb, filename, AVIO_FLAG_READ, int_cb, NULL)) if (!s->io_open(s, pb, filename, AVIO_FLAG_READ, NULL))
return 0; return 0;
} }
} }
@ -2485,7 +2485,7 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) { if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) {
MOVDref *dref = &sc->drefs[sc->dref_id - 1]; MOVDref *dref = &sc->drefs[sc->dref_id - 1];
if (c->enable_drefs) { if (c->enable_drefs) {
if (mov_open_dref(&sc->pb, c->fc->filename, dref, &c->fc->interrupt_callback) < 0) if (mov_open_dref(c->fc, &sc->pb, c->fc->filename, dref) < 0)
av_log(c->fc, AV_LOG_ERROR, av_log(c->fc, AV_LOG_ERROR,
"stream %d, error opening alias: path='%s', dir='%s', " "stream %d, error opening alias: path='%s', dir='%s', "
"filename='%s', volume='%s', nlvl_from=%d, nlvl_to=%d\n", "filename='%s', volume='%s', nlvl_from=%d, nlvl_to=%d\n",
@ -3335,7 +3335,7 @@ static int mov_read_close(AVFormatContext *s)
} }
av_freep(&sc->drefs); av_freep(&sc->drefs);
if (sc->pb && sc->pb != s->pb) if (sc->pb && sc->pb != s->pb)
avio_close(sc->pb); ff_format_io_close(s, &sc->pb);
av_freep(&sc->chunk_offsets); av_freep(&sc->chunk_offsets);
av_freep(&sc->stsc_data); av_freep(&sc->stsc_data);

View File

@ -4188,7 +4188,7 @@ static int shift_data(AVFormatContext *s)
* writing, so we re-open the same output, but for reading. It also avoids * writing, so we re-open the same output, but for reading. It also avoids
* a read/seek/write/seek back and forth. */ * a read/seek/write/seek back and forth. */
avio_flush(s->pb); avio_flush(s->pb);
ret = avio_open(&read_pb, s->filename, AVIO_FLAG_READ); ret = s->io_open(s, &read_pb, s->filename, AVIO_FLAG_READ, NULL);
if (ret < 0) { if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Unable to re-open %s output file for " av_log(s, AV_LOG_ERROR, "Unable to re-open %s output file for "
"the second pass (faststart)\n", s->filename); "the second pass (faststart)\n", s->filename);
@ -4220,7 +4220,7 @@ static int shift_data(AVFormatContext *s)
avio_write(s->pb, read_buf[read_buf_id], n); avio_write(s->pb, read_buf[read_buf_id], n);
pos += n; pos += n;
} while (pos < pos_end); } while (pos < pos_end);
avio_close(read_pb); ff_format_io_close(s, &read_pb);
end: end:
av_free(buf); av_free(buf);

View File

@ -90,12 +90,26 @@ static const AVClass av_format_context_class = {
.child_class_next = format_child_class_next, .child_class_next = format_child_class_next,
}; };
static int io_open_default(AVFormatContext *s, AVIOContext **pb,
const char *url, int flags, AVDictionary **options)
{
return avio_open2(pb, url, flags, &s->interrupt_callback, options);
}
static void io_close_default(AVFormatContext *s, AVIOContext *pb)
{
avio_close(pb);
}
static void avformat_get_context_defaults(AVFormatContext *s) static void avformat_get_context_defaults(AVFormatContext *s)
{ {
memset(s, 0, sizeof(AVFormatContext)); memset(s, 0, sizeof(AVFormatContext));
s->av_class = &av_format_context_class; s->av_class = &av_format_context_class;
s->io_open = io_open_default;
s->io_close = io_close_default;
av_opt_set_defaults(s); av_opt_set_defaults(s);
} }

View File

@ -67,6 +67,9 @@ static int segment_mux_init(AVFormatContext *s)
oc->oformat = seg->oformat; oc->oformat = seg->oformat;
oc->interrupt_callback = s->interrupt_callback; oc->interrupt_callback = s->interrupt_callback;
oc->opaque = s->opaque;
oc->io_close = s->io_close;
oc->io_open = s->io_open;
for (i = 0; i < s->nb_streams; i++) { for (i = 0; i < s->nb_streams; i++) {
AVStream *st; AVStream *st;
@ -86,8 +89,7 @@ static int segment_hls_window(AVFormatContext *s, int last)
int i, ret = 0; int i, ret = 0;
char buf[1024]; char buf[1024];
if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE, if ((ret = s->io_open(s, &seg->pb, seg->list, AVIO_FLAG_WRITE, NULL)) < 0)
&s->interrupt_callback, NULL)) < 0)
goto fail; goto fail;
avio_printf(seg->pb, "#EXTM3U\n"); avio_printf(seg->pb, "#EXTM3U\n");
@ -116,7 +118,8 @@ static int segment_hls_window(AVFormatContext *s, int last)
if (last) if (last)
avio_printf(seg->pb, "#EXT-X-ENDLIST\n"); avio_printf(seg->pb, "#EXT-X-ENDLIST\n");
fail: fail:
avio_closep(&seg->pb); ff_format_io_close(s, &seg->pb);
return ret; return ret;
} }
@ -141,8 +144,7 @@ static int segment_start(AVFormatContext *s, int write_header)
s->filename, c->number++) < 0) s->filename, c->number++) < 0)
return AVERROR(EINVAL); return AVERROR(EINVAL);
if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, if ((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, NULL)) < 0)
&s->interrupt_callback, NULL)) < 0)
return err; return err;
if (oc->oformat->priv_class && oc->priv_data) if (oc->oformat->priv_class && oc->priv_data)
@ -163,7 +165,7 @@ static int segment_end(AVFormatContext *oc, int write_trailer)
av_write_frame(oc, NULL); /* Flush any buffered data (fragmented mp4) */ av_write_frame(oc, NULL); /* Flush any buffered data (fragmented mp4) */
if (write_trailer) if (write_trailer)
av_write_trailer(oc); av_write_trailer(oc);
avio_close(oc->pb); ff_format_io_close(oc, &oc->pb);
return ret; return ret;
} }
@ -190,7 +192,7 @@ static void close_null_ctx(AVIOContext *pb)
static void seg_free_context(SegmentContext *seg) static void seg_free_context(SegmentContext *seg)
{ {
avio_closep(&seg->pb); ff_format_io_close(seg->avf, &seg->pb);
avformat_free_context(seg->avf); avformat_free_context(seg->avf);
seg->avf = NULL; seg->avf = NULL;
} }
@ -208,8 +210,7 @@ static int seg_write_header(AVFormatContext *s)
seg->individual_header_trailer = 0; seg->individual_header_trailer = 0;
if (seg->list && seg->list_type != LIST_HLS) if (seg->list && seg->list_type != LIST_HLS)
if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE, if ((ret = s->io_open(s, &seg->pb, seg->list, AVIO_FLAG_WRITE, NULL)) < 0)
&s->interrupt_callback, NULL)) < 0)
goto fail; goto fail;
for (i = 0; i < s->nb_streams; i++) for (i = 0; i < s->nb_streams; i++)
@ -245,8 +246,7 @@ static int seg_write_header(AVFormatContext *s)
} }
if (seg->write_header_trailer) { if (seg->write_header_trailer) {
if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, if ((ret = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, NULL)) < 0)
&s->interrupt_callback, NULL)) < 0)
goto fail; goto fail;
} else { } else {
if ((ret = open_null_ctx(&oc->pb)) < 0) if ((ret = open_null_ctx(&oc->pb)) < 0)
@ -254,14 +254,13 @@ static int seg_write_header(AVFormatContext *s)
} }
if ((ret = avformat_write_header(oc, NULL)) < 0) { if ((ret = avformat_write_header(oc, NULL)) < 0) {
avio_close(oc->pb); ff_format_io_close(oc, &oc->pb);
goto fail; goto fail;
} }
if (!seg->write_header_trailer) { if (!seg->write_header_trailer) {
close_null_ctx(oc->pb); close_null_ctx(oc->pb);
if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, if ((ret = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, NULL)) < 0)
&s->interrupt_callback, NULL)) < 0)
goto fail; goto fail;
} }
@ -321,9 +320,9 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_printf(seg->pb, "%s\n", oc->filename); avio_printf(seg->pb, "%s\n", oc->filename);
avio_flush(seg->pb); avio_flush(seg->pb);
if (seg->size && !(seg->number % seg->size)) { if (seg->size && !(seg->number % seg->size)) {
avio_closep(&seg->pb); ff_format_io_close(s, &seg->pb);
if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE, if ((ret = s->io_open(s, &seg->pb, seg->list,
&s->interrupt_callback, NULL)) < 0) AVIO_FLAG_WRITE, NULL)) < 0)
goto fail; goto fail;
} }
} }
@ -368,7 +367,7 @@ static int seg_write_trailer(struct AVFormatContext *s)
} }
fail: fail:
avio_close(seg->pb); ff_format_io_close(s, &seg->pb);
avformat_free_context(oc); avformat_free_context(oc);
return ret; return ret;
} }

View File

@ -220,7 +220,7 @@ static int write_manifest(AVFormatContext *s, int final)
snprintf(filename, sizeof(filename), "%s/Manifest", s->filename); snprintf(filename, sizeof(filename), "%s/Manifest", s->filename);
snprintf(temp_filename, sizeof(temp_filename), "%s/Manifest.tmp", s->filename); snprintf(temp_filename, sizeof(temp_filename), "%s/Manifest.tmp", s->filename);
ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL); ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL);
if (ret < 0) { if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
return ret; return ret;
@ -282,7 +282,7 @@ static int write_manifest(AVFormatContext *s, int final)
} }
avio_printf(out, "</SmoothStreamingMedia>\n"); avio_printf(out, "</SmoothStreamingMedia>\n");
avio_flush(out); avio_flush(out);
avio_close(out); ff_format_io_close(s, &out);
return ff_rename(temp_filename, filename); return ff_rename(temp_filename, filename);
} }
@ -409,7 +409,7 @@ static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *sta
AVIOContext *in; AVIOContext *in;
int ret; int ret;
uint32_t len; uint32_t len;
if ((ret = avio_open2(&in, filename, AVIO_FLAG_READ, &s->interrupt_callback, NULL)) < 0) if ((ret = s->io_open(s, &in, filename, AVIO_FLAG_READ, NULL)) < 0)
return ret; return ret;
ret = AVERROR(EIO); ret = AVERROR(EIO);
*moof_size = avio_rb32(in); *moof_size = avio_rb32(in);
@ -450,7 +450,7 @@ static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *sta
avio_seek(in, end, SEEK_SET); avio_seek(in, end, SEEK_SET);
} }
fail: fail:
avio_close(in); ff_format_io_close(s, &in);
return ret; return ret;
} }
@ -486,10 +486,10 @@ static int copy_moof(AVFormatContext *s, const char* infile, const char *outfile
{ {
AVIOContext *in, *out; AVIOContext *in, *out;
int ret = 0; int ret = 0;
if ((ret = avio_open2(&in, infile, AVIO_FLAG_READ, &s->interrupt_callback, NULL)) < 0) if ((ret = s->io_open(s, &in, infile, AVIO_FLAG_READ, NULL)) < 0)
return ret; return ret;
if ((ret = avio_open2(&out, outfile, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL)) < 0) { if ((ret = s->io_open(s, &out, outfile, AVIO_FLAG_WRITE, NULL)) < 0) {
avio_close(in); ff_format_io_close(s, &in);
return ret; return ret;
} }
while (size > 0) { while (size > 0) {
@ -504,8 +504,8 @@ static int copy_moof(AVFormatContext *s, const char* infile, const char *outfile
size -= n; size -= n;
} }
avio_flush(out); avio_flush(out);
avio_close(out); ff_format_io_close(s, &out);
avio_close(in); ff_format_io_close(s, &in);
return ret; return ret;
} }

View File

@ -3176,3 +3176,10 @@ uint8_t *av_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type,
sd->size = size; sd->size = size;
return data; return data;
} }
void ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
{
if (*pb)
s->io_close(s, *pb);
*pb = NULL;
}