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.tags/n3.0
@@ -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(). | ||||
@@ -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 { | ||||
@@ -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); | ||||
@@ -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); | |||||
os->out = NULL; | |||||
ff_format_io_close(s, &os->out); | |||||
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, | |||||
&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; | ||||
@@ -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, | |||||
&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; | ||||
@@ -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, | |||||
&s->interrupt_callback, NULL); | |||||
ret = s->io_open(s, &os->out, os->temp_filename, AVIO_FLAG_WRITE, 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); | |||||
os->out = NULL; | |||||
ff_format_io_close(s, &os->out); | |||||
} | } | ||||
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); | ||||
@@ -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) | ||||
@@ -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, | |||||
&s->interrupt_callback, NULL)) < 0) | |||||
if ((ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, 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, | |||||
&s->interrupt_callback, NULL)) < 0) | |||||
if ((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, 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); | ||||
@@ -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, | |||||
&s1->interrupt_callback, NULL) < 0) { | |||||
if (s1->io_open(s1, &f[i], filename, AVIO_FLAG_READ, 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]; | ||||
} | } | ||||
@@ -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, | |||||
&s->interrupt_callback, NULL) < 0) { | |||||
if (s->io_open(s, &pb[i], img->tmp, AVIO_FLAG_WRITE, 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]); | |||||
avio_close(pb[2]); | |||||
ff_format_io_close(s, &pb[1]); | |||||
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); | ||||
} | } | ||||
@@ -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 */ |
@@ -2400,8 +2400,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st) | |||||
} | } | ||||
} | } | ||||
static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref, | |||||
AVIOInterruptCB *int_cb) | |||||
static int mov_open_dref(AVFormatContext *s, AVIOContext **pb, char *src, | |||||
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); | ||||
@@ -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); | ||||
@@ -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); | ||||
} | } | ||||
@@ -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, | |||||
&s->interrupt_callback, NULL)) < 0) | |||||
if ((ret = s->io_open(s, &seg->pb, seg->list, AVIO_FLAG_WRITE, 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, | |||||
&s->interrupt_callback, NULL)) < 0) | |||||
if ((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, 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, | |||||
&s->interrupt_callback, NULL)) < 0) | |||||
if ((ret = s->io_open(s, &seg->pb, seg->list, AVIO_FLAG_WRITE, 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, | |||||
&s->interrupt_callback, NULL)) < 0) | |||||
if ((ret = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, 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, | |||||
&s->interrupt_callback, NULL)) < 0) | |||||
if ((ret = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, 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); | |||||
if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE, | |||||
&s->interrupt_callback, NULL)) < 0) | |||||
ff_format_io_close(s, &seg->pb); | |||||
if ((ret = s->io_open(s, &seg->pb, seg->list, | |||||
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; | ||||
} | } | ||||
@@ -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) { | |||||
avio_close(in); | |||||
if ((ret = s->io_open(s, &out, outfile, AVIO_FLAG_WRITE, NULL)) < 0) { | |||||
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); | |||||
avio_close(in); | |||||
ff_format_io_close(s, &out); | |||||
ff_format_io_close(s, &in); | |||||
return ret; | return ret; | ||||
} | } | ||||
@@ -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; | |||||
} |