Commit cca698a0 authored by Rafaël Carré's avatar Rafaël Carré

avio access: use new API

- fix bug in ACCESS_GET_PTS_DELAY where it would fall through the next case
- print error messages from libavformat
- remove useless strdup
- check for exclusive access to avio when context open succeeded
- support for multiple input / output at the same time with libavformat > 54 (untested)
parent 7f510436
...@@ -34,6 +34,20 @@ ...@@ -34,6 +34,20 @@
#include "avio.h" #include "avio.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 * Module descriptor
*****************************************************************************/ *****************************************************************************/
...@@ -53,38 +67,58 @@ static ssize_t Write(sout_access_out_t *, block_t *); ...@@ -53,38 +67,58 @@ static ssize_t Write(sout_access_out_t *, block_t *);
static int OutControl(sout_access_out_t *, int, va_list); static int OutControl(sout_access_out_t *, int, va_list);
static int OutSeek (sout_access_out_t *, off_t); static int OutSeek (sout_access_out_t *, off_t);
static int SetupAvio(vlc_object_t *); static int UrlInterruptCallback(void *access)
{
return !vlc_object_alive((vlc_object_t*)access);
}
struct access_sys_t { struct access_sys_t {
URLContext *context; AVIOContext *context;
}; };
struct sout_access_out_sys_t { struct sout_access_out_sys_t {
URLContext *context; AVIOContext *context;
}; };
/* */ /* */
int OpenAvio(vlc_object_t *object)
{
access_t *access = (access_t*)object;
access_sys_t *sys;
/* */ #if LIBAVFORMAT_VERSION_MAJOR < 54
access->p_sys = sys = malloc(sizeof(*sys)); static vlc_object_t *current_access = NULL;
if (!sys)
return VLC_ENOMEM;
/* We can either accept only one user (actually) or multiple ones static int UrlInterruptCallbackSingle(void)
* with an exclusive lock */ {
if (SetupAvio(VLC_OBJECT(access))) { return UrlInterruptCallback(current_access);
msg_Err(access, "Module aready in use"); }
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; return VLC_EGENERIC;
} }
url_set_interrupt_cb(access ? UrlInterruptCallback : NULL);
/* */ current_access = access;
vlc_avcodec_lock();
av_register_all(); vlc_mutex_unlock(&avio_lock);
vlc_avcodec_unlock();
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: /* We accept:
* - avio://full_url * - avio://full_url
...@@ -97,20 +131,51 @@ int OpenAvio(vlc_object_t *object) ...@@ -97,20 +131,51 @@ int OpenAvio(vlc_object_t *object)
access->psz_location) < 0) access->psz_location) < 0)
url = NULL; url = NULL;
if (!url) if (!url) {
goto error; free(sys);
return VLC_ENOMEM;
}
msg_Dbg(access, "Opening '%s'", url); /* */
if (url_open(&sys->context, url, URL_RDONLY) < 0) vlc_avcodec_lock();
sys->context = NULL; av_register_all();
vlc_avcodec_unlock();
int ret;
#if LIBAVFORMAT_VERSION_MAJOR < 54
ret = avio_open(&sys->context, url, AVIO_FLAG_READ);
#else
AVIOInterruptCB cb = {
.callback = UrlInterruptCallback,
.opaque = access,
};
ret = avio_open2(&sys->context, url, AVIO_FLAG_READ, &cb, NULL /* options */);
#endif
if (ret < 0) {
errno = AVUNERROR(ret);
msg_Err(access, "Failed to open %s: %m", url);
free(url);
goto error;
}
free(url); free(url);
if (!sys->context) { #if LIBAVFORMAT_VERSION_MAJOR < 54
msg_Err(access, "Failed to open url using libavformat"); /* 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; goto error;
} }
const int64_t size = url_filesize(sys->context); #endif
msg_Dbg(access, "is_streamed=%d size=%"PRIi64, sys->context->is_streamed, size);
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); access_InitFields(access);
...@@ -125,7 +190,6 @@ int OpenAvio(vlc_object_t *object) ...@@ -125,7 +190,6 @@ int OpenAvio(vlc_object_t *object)
return VLC_SUCCESS; return VLC_SUCCESS;
error: error:
SetupAvio(NULL);
free(sys); free(sys);
return VLC_EGENERIC; return VLC_EGENERIC;
} }
...@@ -134,42 +198,43 @@ error: ...@@ -134,42 +198,43 @@ error:
int OutOpenAvio(vlc_object_t *object) int OutOpenAvio(vlc_object_t *object)
{ {
sout_access_out_t *access = (sout_access_out_t*)object; sout_access_out_t *access = (sout_access_out_t*)object;
sout_access_out_sys_t *sys; sout_access_out_sys_t *sys = malloc(sizeof(*sys));
/* */
access->p_sys = sys = malloc(sizeof(*sys));
if (!sys) if (!sys)
return VLC_ENOMEM; return VLC_ENOMEM;
sys->context = NULL;
/* We can either accept only one user (actually) or multiple ones
* with an exclusive lock */
if (SetupAvio(VLC_OBJECT(access))) {
msg_Err(access, "Module aready in use");
free(sys);
return VLC_EGENERIC;
}
/* */ /* */
vlc_avcodec_lock(); vlc_avcodec_lock();
av_register_all(); av_register_all();
vlc_avcodec_unlock(); vlc_avcodec_unlock();
char *url = NULL; if (!access->psz_path)
if (access->psz_path)
url = strdup(access->psz_path);
if (!url)
goto error; goto error;
msg_Dbg(access, "avio_output Opening '%s'", url); int ret;
if (url_open(&sys->context, url, URL_WRONLY) < 0) #if LIBAVFORMAT_VERSION_MAJOR < 54
sys->context = NULL; ret = avio_open(&sys->context, access->psz_path, AVIO_FLAG_WRITE);
free(url); #else
AVIOInterruptCB cb = {
.callback = UrlInterruptCallback,
.opaque = access,
};
ret = avio_open2(&sys->context, access->psz_path, AVIO_FLAG_WRITE,
&cb, NULL /* options */);
#endif
if (ret < 0) {
errno = AVUNERROR(ret);
msg_Err(access, "Failed to open %s", access->psz_path);
goto error;
}
if (!sys->context) { #if LIBAVFORMAT_VERSION_MAJOR < 54
msg_Err(access, "Failed to open url using libavformat"); /* We can accept only one active user at any time */
if (SetupAvioCb(VLC_OBJECT(access))) {
msg_Err(access, "Module aready in use");
goto error; goto error;
} }
#endif
access->pf_write = Write; access->pf_write = Write;
access->pf_control = OutControl; access->pf_control = OutControl;
...@@ -179,7 +244,6 @@ int OutOpenAvio(vlc_object_t *object) ...@@ -179,7 +244,6 @@ int OutOpenAvio(vlc_object_t *object)
return VLC_SUCCESS; return VLC_SUCCESS;
error: error:
SetupAvio(NULL);
free(sys); free(sys);
return VLC_EGENERIC; return VLC_EGENERIC;
} }
...@@ -189,10 +253,11 @@ void CloseAvio(vlc_object_t *object) ...@@ -189,10 +253,11 @@ void CloseAvio(vlc_object_t *object)
access_t *access = (access_t*)object; access_t *access = (access_t*)object;
access_sys_t *sys = access->p_sys; access_sys_t *sys = access->p_sys;
url_close(sys->context); #if LIBAVFORMAT_VERSION_MAJOR < 54
SetupAvioCb(NULL);
SetupAvio(NULL); #endif
avio_close(sys->context);
free(sys); free(sys);
} }
...@@ -201,23 +266,21 @@ void OutCloseAvio(vlc_object_t *object) ...@@ -201,23 +266,21 @@ void OutCloseAvio(vlc_object_t *object)
sout_access_out_t *access = (sout_access_out_t*)object; sout_access_out_t *access = (sout_access_out_t*)object;
sout_access_out_sys_t *sys = access->p_sys; sout_access_out_sys_t *sys = access->p_sys;
url_close(sys->context); #if LIBAVFORMAT_VERSION_MAJOR < 54
SetupAvioCb(NULL);
SetupAvio(NULL); #endif
avio_close(sys->context);
free(sys); free(sys);
} }
static ssize_t Read(access_t *access, uint8_t *data, size_t size) 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 int r = avio_read(access->p_sys->context, data, size);
* of error. if (r > 0)
*/
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; access->info.i_pos += r;
else
access->info.b_eof = true;
return r; return r;
} }
...@@ -232,7 +295,14 @@ static ssize_t Write(sout_access_out_t *p_access, block_t *p_buffer) ...@@ -232,7 +295,14 @@ static ssize_t Write(sout_access_out_t *p_access, block_t *p_buffer)
while (p_buffer != NULL) { while (p_buffer != NULL) {
block_t *p_next = p_buffer->p_next;; block_t *p_next = p_buffer->p_next;;
#if LIBAVFORMAT_VERSION_MAJOR < 54
i_write += url_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer); i_write += url_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer);
#else
/* FIXME : how are errors notified ?? */
avio_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer);
i_write += p_buffer->i_buffer;
#endif
block_Release(p_buffer); block_Release(p_buffer);
p_buffer = p_next; p_buffer = p_next;
...@@ -244,10 +314,15 @@ static ssize_t Write(sout_access_out_t *p_access, block_t *p_buffer) ...@@ -244,10 +314,15 @@ static ssize_t Write(sout_access_out_t *p_access, block_t *p_buffer)
static int Seek(access_t *access, uint64_t position) static int Seek(access_t *access, uint64_t position)
{ {
access_sys_t *sys = access->p_sys; access_sys_t *sys = access->p_sys;
int ret;
if (position > INT64_MAX ||
url_seek(sys->context, position, SEEK_SET) < 0) { if (position > INT64_MAX)
msg_Err(access, "Seek to %"PRIu64" failed\n", position); 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) if (access->info.i_size <= 0 || position != access->info.i_size)
return VLC_EGENERIC; return VLC_EGENERIC;
} }
...@@ -260,7 +335,7 @@ static int OutSeek(sout_access_out_t *p_access, off_t i_pos) ...@@ -260,7 +335,7 @@ static int OutSeek(sout_access_out_t *p_access, off_t i_pos)
{ {
sout_access_out_sys_t *sys = p_access->p_sys; sout_access_out_sys_t *sys = p_access->p_sys;
if (url_seek(sys->context, i_pos, SEEK_SET) < 0) if (avio_seek(sys->context, i_pos, SEEK_SET) < 0)
return VLC_EGENERIC; return VLC_EGENERIC;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -287,31 +362,38 @@ static int OutControl(sout_access_out_t *p_access, int i_query, va_list args) ...@@ -287,31 +362,38 @@ static int OutControl(sout_access_out_t *p_access, int i_query, va_list args)
static int Control(access_t *access, int query, va_list args) static int Control(access_t *access, int query, va_list args)
{ {
access_sys_t *sys = access->p_sys; access_sys_t *sys = access->p_sys;
bool *b;
switch (query) { switch (query) {
case ACCESS_CAN_SEEK: case ACCESS_CAN_SEEK:
case ACCESS_CAN_FASTSEEK: { /* FIXME how to do that ? */ case ACCESS_CAN_FASTSEEK: /* FIXME how to do that ? */
bool *b = va_arg(args, bool *); b = va_arg(args, bool *);
#if LIBAVFORMAT_VERSION_MAJOR < 54
*b = !sys->context->is_streamed; *b = !sys->context->is_streamed;
#else
*b = sys->context->seekable;
#endif
return VLC_SUCCESS; return VLC_SUCCESS;
} case ACCESS_CAN_PAUSE:
case ACCESS_CAN_PAUSE: { b = va_arg(args, bool *);
bool *b = va_arg(args, bool *); #if LIBAVFORMAT_VERSION_MAJOR < 54
*b = sys->context->prot->url_read_pause != NULL; /* FIXME Unsure */ *b = sys->context->prot->url_read_pause != NULL;
#else
*b = sys->context->read_pause != NULL;
#endif
return VLC_SUCCESS; return VLC_SUCCESS;
} case ACCESS_CAN_CONTROL_PACE:
case ACCESS_CAN_CONTROL_PACE: { b = va_arg(args, bool *);
bool *b = va_arg(args, bool *);
*b = true; /* FIXME */ *b = true; /* FIXME */
return VLC_SUCCESS; return VLC_SUCCESS;
}
case ACCESS_GET_PTS_DELAY: { case ACCESS_GET_PTS_DELAY: {
int64_t *delay = va_arg(args, int64_t *); int64_t *delay = va_arg(args, int64_t *);
*delay = DEFAULT_PTS_DELAY; /* FIXME */ *delay = DEFAULT_PTS_DELAY; /* FIXME */
return VLC_SUCCESS;
} }
case ACCESS_SET_PAUSE_STATE: { case ACCESS_SET_PAUSE_STATE: {
bool is_paused = va_arg(args, int); 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_EGENERIC;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -328,30 +410,3 @@ static int Control(access_t *access, int query, va_list args) ...@@ -328,30 +410,3 @@ static int Control(access_t *access, int query, va_list args)
return VLC_EGENERIC; return VLC_EGENERIC;
} }
} }
/* */
static vlc_mutex_t avio_lock = VLC_STATIC_MUTEX;
static vlc_object_t *current_access = NULL;
static int UrlInterruptCallback(void)
{
assert(current_access);
return !vlc_object_alive(current_access);
}
static int SetupAvio(vlc_object_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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment