X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Favio.c;h=ddd7988f831a086be0ffc437360173dd321bf737;hb=8972d2f2083810e33951c0b0c7995e77b3c2c951;hp=aeeda4acb83035d4a68bf9f261d8c4ef13e63e84;hpb=df6df8dfcafc55e31164d6b2a179321b36f317f4;p=vlc diff --git a/modules/access/avio.c b/modules/access/avio.c index aeeda4acb8..ddd7988f83 100644 --- a/modules/access/avio.c +++ b/modules/access/avio.c @@ -6,19 +6,19 @@ * * Authors: Laurent Aimar * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #ifdef HAVE_CONFIG_H @@ -29,9 +29,25 @@ #include #include #include +#include #include #include "avio.h" +#include "../codec/avcodec/avcommon.h" + +#if LIBAVFORMAT_VERSION_MAJOR < 54 +# define AVIOContext URLContext + +# define avio_open url_open +# define avio_close url_close +# define avio_read url_read +# define avio_seek url_seek +# define avio_pause av_url_read_pause + +# define AVIO_FLAG_READ URL_RDONLY +# define AVIO_FLAG_WRITE URL_WRONLY +# define avio_size url_filesize +#endif /***************************************************************************** * Module descriptor @@ -46,37 +62,64 @@ vlc_module_end() * Local prototypes *****************************************************************************/ static ssize_t Read (access_t *, uint8_t *, size_t); -static int Seek (access_t *, int64_t); +static int Seek (access_t *, uint64_t); static int Control(access_t *, int, va_list); +static ssize_t Write(sout_access_out_t *, block_t *); +static int OutControl(sout_access_out_t *, int, va_list); +static int OutSeek (sout_access_out_t *, off_t); -static int SetupAvio(access_t *); +static int UrlInterruptCallback(void *access) +{ + return !vlc_object_alive((vlc_object_t*)access); +} struct access_sys_t { - URLContext *context; + AVIOContext *context; +}; + +struct sout_access_out_sys_t { + AVIOContext *context; }; + /* */ -int OpenAvio(vlc_object_t *object) -{ - access_t *access = (access_t*)object; - access_sys_t *sys; - /* */ - access->p_sys = sys = malloc(sizeof(*sys)); - if (!sys) - return VLC_ENOMEM; +#if LIBAVFORMAT_VERSION_MAJOR < 54 +static vlc_object_t *current_access = NULL; - /* We can either accept only one user (actually) or multiple ones - * with an exclusive lock */ - if (SetupAvio(access)) { - msg_Err(access, "Module aready in use"); +static int UrlInterruptCallbackSingle(void) +{ + return UrlInterruptCallback(current_access); +} + +static int SetupAvioCb(vlc_object_t *access) +{ + static vlc_mutex_t avio_lock = VLC_STATIC_MUTEX; + vlc_mutex_lock(&avio_lock); + assert(!access != !current_access); + if (access && current_access) { + vlc_mutex_unlock(&avio_lock); return VLC_EGENERIC; } + url_set_interrupt_cb(access ? UrlInterruptCallbackSingle : NULL); - /* */ - vlc_avcodec_lock(); - av_register_all(); - vlc_avcodec_unlock(); + current_access = access; + + vlc_mutex_unlock(&avio_lock); + + return VLC_SUCCESS; +} +#endif + +/* */ + +int OpenAvio(vlc_object_t *object) +{ + access_t *access = (access_t*)object; + access_sys_t *sys = malloc(sizeof(*sys)); + if (!sys) + return VLC_ENOMEM; + sys->context = NULL; /* We accept: * - avio://full_url @@ -84,24 +127,64 @@ int OpenAvio(vlc_object_t *object) */ char *url; if (!strcmp(access->psz_access, "avio")) - url = strdup(access->psz_path); - else if (asprintf(&url, "%s://%s", access->psz_access, access->psz_path) < 0) + url = strdup(access->psz_location); + else if (asprintf(&url, "%s://%s", access->psz_access, + access->psz_location) < 0) url = NULL; - if (!url) - goto error; + if (!url) { + free(sys); + return VLC_ENOMEM; + } - msg_Dbg(access, "Opening '%s'", url); - if (url_open(&sys->context, url, URL_RDONLY) < 0 ) - sys->context = NULL; + /* */ + vlc_init_avformat(); + + int ret; +#if LIBAVFORMAT_VERSION_MAJOR < 54 + ret = avio_open(&sys->context, url, AVIO_FLAG_READ); +#else + AVIOInterruptCB cb = { + .callback = UrlInterruptCallback, + .opaque = access, + }; + AVDictionary *options = NULL; + char *psz_opts = var_InheritString(access, "avio-options"); + if (psz_opts && *psz_opts) { + options = vlc_av_get_options(psz_opts); + free(psz_opts); + } + ret = avio_open2(&sys->context, url, AVIO_FLAG_READ, &cb, &options); + AVDictionaryEntry *t = NULL; + while ((t = av_dict_get(options, "", t, AV_DICT_IGNORE_SUFFIX))) + msg_Err( access, "unknown option \"%s\"", t->key ); + av_dict_free(&options); +#endif + if (ret < 0) { + errno = AVUNERROR(ret); + msg_Err(access, "Failed to open %s: %m", url); + free(url); + goto error; + } free(url); - if (!sys->context) { - msg_Err(access, "Failed to open url using libavformat"); +#if LIBAVFORMAT_VERSION_MAJOR < 54 + /* We can accept only one active user at any time */ + if (SetupAvioCb(VLC_OBJECT(access))) { + msg_Err(access, "Module aready in use"); + avio_close(sys->context); goto error; } - const int64_t size = url_filesize(sys->context); - msg_Dbg(access, "is_streamed=%d size=%lld", sys->context->is_streamed, size); +#endif + + int64_t size = avio_size(sys->context); + bool seekable; +#if LIBAVFORMAT_VERSION_MAJOR < 54 + seekable = !sys->context->is_streamed; +#else + seekable = sys->context->seekable; +#endif + msg_Dbg(access, "%sseekable, size=%"PRIi64, seekable ? "" : "not ", size); /* */ access_InitFields(access); @@ -116,45 +199,175 @@ int OpenAvio(vlc_object_t *object) return VLC_SUCCESS; error: - SetupAvio(NULL); free(sys); return VLC_EGENERIC; } +/* */ + +static const char *const ppsz_sout_options[] = { + "options", + NULL, +}; + +int OutOpenAvio(vlc_object_t *object) +{ + sout_access_out_t *access = (sout_access_out_t*)object; + + config_ChainParse( access, "sout-avio-", ppsz_sout_options, access->p_cfg ); + + sout_access_out_sys_t *sys = malloc(sizeof(*sys)); + if (!sys) + return VLC_ENOMEM; + sys->context = NULL; + + /* */ + vlc_init_avformat(); + + if (!access->psz_path) + goto error; + + int ret; +#if LIBAVFORMAT_VERSION_MAJOR < 54 + ret = avio_open(&sys->context, access->psz_path, AVIO_FLAG_WRITE); +#else + AVIOInterruptCB cb = { + .callback = UrlInterruptCallback, + .opaque = access, + }; + AVDictionary *options = NULL; + char *psz_opts = var_InheritString(access, "sout-avio-options"); + if (psz_opts && *psz_opts) { + options = vlc_av_get_options(psz_opts); + free(psz_opts); + } + ret = avio_open2(&sys->context, access->psz_path, AVIO_FLAG_WRITE, + &cb, &options); + AVDictionaryEntry *t = NULL; + while ((t = av_dict_get(options, "", t, AV_DICT_IGNORE_SUFFIX))) + msg_Err( access, "unknown option \"%s\"", t->key ); + av_dict_free(&options); +#endif + if (ret < 0) { + errno = AVUNERROR(ret); + msg_Err(access, "Failed to open %s", access->psz_path); + goto error; + } + +#if LIBAVFORMAT_VERSION_MAJOR < 54 + /* We can accept only one active user at any time */ + if (SetupAvioCb(VLC_OBJECT(access))) { + msg_Err(access, "Module aready in use"); + goto error; + } +#endif + + access->pf_write = Write; + access->pf_control = OutControl; + access->pf_seek = OutSeek; + access->p_sys = sys; + + return VLC_SUCCESS; + +error: + free(sys); + return VLC_EGENERIC; +} void CloseAvio(vlc_object_t *object) { access_t *access = (access_t*)object; access_sys_t *sys = access->p_sys; - url_close(sys->context); - - SetupAvio(NULL); +#if LIBAVFORMAT_VERSION_MAJOR < 54 + SetupAvioCb(NULL); +#endif + avio_close(sys->context); free(sys); } +void OutCloseAvio(vlc_object_t *object) +{ + sout_access_out_t *access = (sout_access_out_t*)object; + sout_access_out_sys_t *sys = access->p_sys; + +#if LIBAVFORMAT_VERSION_MAJOR < 54 + SetupAvioCb(NULL); +#endif + + avio_close(sys->context); + free(sys); +} static ssize_t Read(access_t *access, uint8_t *data, size_t size) { - /* FIXME I am unsure of the meaning of the return value in case - * of error. - */ - int r = url_read(access->p_sys->context, data, size); - access->info.b_eof = r <= 0; - if (r < 0) - return -1; - access->info.i_pos += r; + int r = avio_read(access->p_sys->context, data, size); + if (r > 0) + access->info.i_pos += r; + else + access->info.b_eof = true; return r; } +/***************************************************************************** + * Write: + *****************************************************************************/ +static ssize_t Write(sout_access_out_t *p_access, block_t *p_buffer) +{ + access_sys_t *p_sys = (access_sys_t*)p_access->p_sys; + size_t i_write = 0; + + while (p_buffer != NULL) { + block_t *p_next = p_buffer->p_next; + +#if LIBAVFORMAT_VERSION_MAJOR < 54 + int written = url_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer); + if (written < 0) { + errno = AVUNERROR(written); + goto error; + } + i_write += written; +#else + avio_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer); + avio_flush(p_sys->context); + if (p_sys->context->error) { + errno = AVUNERROR(p_sys->context->error); + p_sys->context->error = 0; /* FIXME? */ + goto error; + } + i_write += p_buffer->i_buffer; +#endif + + block_Release(p_buffer); + + p_buffer = p_next; + } + + return i_write; + +error: + msg_Err(p_access, "Wrote only %zu bytes (%m)", i_write); + block_ChainRelease( p_buffer ); + return i_write; +} -static int Seek(access_t *access, int64_t position) +static int Seek(access_t *access, uint64_t position) { access_sys_t *sys = access->p_sys; + int ret; - if (url_seek(sys->context, position, SEEK_SET) < 0) { - msg_Err(access, "Seek to %lld failed\n", position); +#ifndef EOVERFLOW +# define EOVERFLOW EFBIG +#endif + + if (position > INT64_MAX) + ret = AVERROR(EOVERFLOW); + else + ret = avio_seek(sys->context, position, SEEK_SET); + if (ret < 0) { + errno = AVUNERROR(ret); + msg_Err(access, "Seek to %"PRIu64" failed: %m", position); if (access->info.i_size <= 0 || position != access->info.i_size) return VLC_EGENERIC; } @@ -163,35 +376,69 @@ static int Seek(access_t *access, int64_t position) return VLC_SUCCESS; } +static int OutSeek(sout_access_out_t *p_access, off_t i_pos) +{ + sout_access_out_sys_t *sys = p_access->p_sys; + + if (avio_seek(sys->context, i_pos, SEEK_SET) < 0) + return VLC_EGENERIC; + return VLC_SUCCESS; +} + +static int OutControl(sout_access_out_t *p_access, int i_query, va_list args) +{ + sout_access_out_sys_t *p_sys = p_access->p_sys; + + VLC_UNUSED(p_sys); + switch (i_query) { + case ACCESS_OUT_CONTROLS_PACE: { + bool *pb = va_arg(args, bool *); + //*pb = strcmp(p_access->psz_access, "stream"); + *pb = false; + break; + } + + default: + return VLC_EGENERIC; + } + return VLC_SUCCESS; +} static int Control(access_t *access, int query, va_list args) { access_sys_t *sys = access->p_sys; + bool *b; switch (query) { case ACCESS_CAN_SEEK: - case ACCESS_CAN_FASTSEEK: { /* FIXME how to do that ? */ - bool *b = va_arg(args, bool *); + case ACCESS_CAN_FASTSEEK: /* FIXME how to do that ? */ + b = va_arg(args, bool *); +#if LIBAVFORMAT_VERSION_MAJOR < 54 *b = !sys->context->is_streamed; +#else + *b = sys->context->seekable; +#endif return VLC_SUCCESS; - } - case ACCESS_CAN_PAUSE: { - bool *b = va_arg(args, bool *); - *b = sys->context->prot->url_read_pause != NULL; /* FIXME Unsure */ + case ACCESS_CAN_PAUSE: + b = va_arg(args, bool *); +#if LIBAVFORMAT_VERSION_MAJOR < 54 + *b = sys->context->prot->url_read_pause != NULL; +#else + *b = sys->context->read_pause != NULL; +#endif return VLC_SUCCESS; - } - case ACCESS_CAN_CONTROL_PACE: { - bool *b = va_arg(args, bool *); + case ACCESS_CAN_CONTROL_PACE: + b = va_arg(args, bool *); *b = true; /* FIXME */ return VLC_SUCCESS; - } case ACCESS_GET_PTS_DELAY: { int64_t *delay = va_arg(args, int64_t *); *delay = DEFAULT_PTS_DELAY; /* FIXME */ + return VLC_SUCCESS; } case ACCESS_SET_PAUSE_STATE: { bool is_paused = va_arg(args, int); - if (av_url_read_pause(sys->context, is_paused)< 0) + if (avio_pause(sys->context, is_paused)< 0) return VLC_EGENERIC; return VLC_SUCCESS; } @@ -208,31 +455,3 @@ static int Control(access_t *access, int query, va_list args) return VLC_EGENERIC; } } - -/* */ -static vlc_mutex_t avio_lock = VLC_STATIC_MUTEX; -static access_t *current_access = NULL; - - -static int UrlInterruptCallback(void) -{ - assert(current_access); - return !vlc_object_alive(current_access); -} - - -static int SetupAvio(access_t *access) -{ - vlc_mutex_lock(&avio_lock); - assert(!access != !current_access); - if (access && current_access) { - vlc_mutex_unlock(&avio_lock); - return VLC_EGENERIC; - } - url_set_interrupt_cb(access ? UrlInterruptCallback : NULL); - current_access = access; - vlc_mutex_unlock(&avio_lock); - - return VLC_SUCCESS; -} -