struct stream_sys_t
{
- block_t *peeked;
- uint64_t offset;
+ /* Thread data */
+ int write_fd;
+
+ /* Shared data */
+ vlc_cond_t wait;
+ vlc_mutex_t lock;
+ bool paused;
+
+ /* Caller data */
vlc_thread_t thread;
pid_t pid;
- int write_fd, read_fd;
+
+ uint64_t offset;
+ block_t *peeked;
+
+ int read_fd;
bool can_pace;
+ bool can_pause;
+ int64_t pts_delay;
};
extern char **environ;
vlc_cleanup_push (free, buf);
#endif
+ vlc_mutex_lock (&p_sys->lock);
+ while (p_sys->paused) /* practically always false, but... */
+ vlc_cond_wait (&p_sys->wait, &p_sys->lock);
len = stream_Read (stream->p_source, buf, bufsize);
+ vlc_mutex_unlock (&p_sys->lock);
+
vlc_restorecancel (canc);
error = len <= 0;
{
if (j == 0)
errno = EPIPE;
- msg_Err (stream, "cannot write data (%m)");
+ msg_Err (stream, "cannot write data: %s",
+ vlc_strerror_c(errno));
error = true;
break;
}
*/
static int Read (stream_t *stream, void *buf, unsigned int buflen)
{
- stream_sys_t *p_sys = stream->p_sys;
- block_t *peeked;
- ssize_t length;
+ stream_sys_t *sys = stream->p_sys;
+ unsigned ret = 0;
if (buf == NULL) /* caller skips data, get big enough peek buffer */
buflen = Peek (stream, &(const uint8_t *){ NULL }, buflen);
- if ((peeked = p_sys->peeked) != NULL)
+ block_t *peeked = sys->peeked;
+ if (peeked != NULL)
{ /* dequeue peeked data */
- length = (buflen > peeked->i_buffer) ? peeked->i_buffer : buflen;
+ size_t length = peeked->i_buffer;
+ if (length > buflen)
+ length = buflen;
+
if (buf != NULL)
{
memcpy (buf, peeked->p_buffer, length);
buflen -= length;
peeked->p_buffer += length;
peeked->i_buffer -= length;
+
if (peeked->i_buffer == 0)
{
block_Release (peeked);
- p_sys->peeked = NULL;
+ sys->peeked = NULL;
}
- p_sys->offset += length;
- if (buflen > 0)
- length += Read (stream, ((char *)buf) + length, buflen - length);
- return length;
+ sys->offset += length;
+ ret += length;
}
assert ((buf != NULL) || (buflen == 0));
- length = net_Read (stream, p_sys->read_fd, NULL, buf, buflen, false);
- if (length < 0)
- return 0;
- p_sys->offset += length;
- return length;
+ ssize_t val = net_Read (stream, sys->read_fd, NULL, buf, buflen, false);
+ if (val > 0)
+ {
+ sys->offset += val;
+ ret += val;
+ }
+ return ret;
}
/**
*/
static int Peek (stream_t *stream, const uint8_t **pbuf, unsigned int len)
{
- stream_sys_t *p_sys = stream->p_sys;
- block_t *peeked = p_sys->peeked;
- size_t curlen = 0;
- int fd = p_sys->read_fd;
+ stream_sys_t *sys = stream->p_sys;
+ block_t *peeked = sys->peeked;
+ size_t curlen;
- if (peeked == NULL)
+ if (peeked != NULL)
+ {
+ curlen = peeked->i_buffer;
+ if (curlen < len)
+ peeked = block_Realloc (peeked, 0, len);
+ }
+ else
+ {
+ curlen = 0;
peeked = block_Alloc (len);
- else if ((curlen = peeked->i_buffer) < len)
- peeked = block_Realloc (peeked, 0, len);
+ }
- if ((p_sys->peeked = peeked) == NULL)
+ sys->peeked = peeked;
+ if (unlikely(peeked == NULL))
return 0;
- if (curlen < len)
+ while (curlen < len)
{
- ssize_t val = net_Read (stream, fd, NULL, peeked->p_buffer + curlen,
- len - curlen, true);
- if (val >= 0)
- {
- curlen += val;
- peeked->i_buffer = curlen;
- }
+ ssize_t val;
+
+ val = net_Read (stream, sys->read_fd, NULL,
+ peeked->p_buffer + curlen, len - curlen, false);
+ if (val <= 0)
+ break;
+ curlen += val;
+ peeked->i_buffer = curlen;
}
*pbuf = peeked->p_buffer;
return curlen;
{
case STREAM_CAN_SEEK:
case STREAM_CAN_FASTSEEK:
- case STREAM_CAN_PAUSE: /* TODO: support pause */
*(va_arg (args, bool *)) = false;
break;
+ case STREAM_CAN_PAUSE:
+ *(va_arg (args, bool *)) = p_sys->can_pause;
+ break;
case STREAM_CAN_CONTROL_PACE:
*(va_arg (args, bool *)) = p_sys->can_pace;
break;
case STREAM_GET_SIZE:
*(va_arg (args, uint64_t *)) = 0;
break;
+ case STREAM_GET_PTS_DELAY:
+ *va_arg (args, int64_t *) = p_sys->pts_delay;
+ break;
+ case STREAM_SET_PAUSE_STATE:
+ {
+ bool paused = va_arg (args, unsigned);
+
+ vlc_mutex_lock (&p_sys->lock);
+ stream_Control (stream->p_source, STREAM_SET_PAUSE_STATE, paused);
+ p_sys->paused = paused;
+ vlc_cond_signal (&p_sys->wait);
+ vlc_mutex_unlock (&p_sys->lock);
+ break;
+ }
default:
return VLC_EGENERIC;
}
stream->pf_read = Read;
stream->pf_peek = Peek;
stream->pf_control = Control;
- p_sys->peeked = NULL;
- p_sys->offset = 0;
+
+ vlc_cond_init (&p_sys->wait);
+ vlc_mutex_init (&p_sys->lock);
+ p_sys->paused = false;
p_sys->pid = -1;
+ p_sys->offset = 0;
+ p_sys->peeked = NULL;
+ stream_Control (stream->p_source, STREAM_CAN_PAUSE, &p_sys->can_pause);
stream_Control (stream->p_source, STREAM_CAN_CONTROL_PACE,
&p_sys->can_pace);
+ stream_Control (stream->p_source, STREAM_GET_PTS_DELAY, &p_sys->pts_delay);
/* I am not a big fan of the pyramid style, but I cannot think of anything
* better here. There are too many failure cases. */
}
else
{
- msg_Err (stream, "Cannot execute %s", path);
+ msg_Err (stream, "cannot execute %s", path);
p_sys->pid = -1;
}
posix_spawn_file_actions_destroy (&actions);
switch (p_sys->pid = fork ())
{
case -1:
- msg_Err (stream, "Cannot fork (%m)");
+ msg_Err (stream, "cannot fork: %s", vlc_strerror_c(errno));
break;
case 0:
dup2 (comp[0], 0);
}
close (comp[0]);
if (ret != VLC_SUCCESS)
- {
close (comp[1]);
- if (p_sys->pid != -1)
- while (waitpid (p_sys->pid, &(int){ 0 }, 0) == -1);
- }
}
+
+ if (ret == VLC_SUCCESS)
+ return VLC_SUCCESS;
+
+ if (p_sys->pid != -1)
+ while (waitpid (p_sys->pid, &(int){ 0 }, 0) == -1);
+ vlc_mutex_destroy (&p_sys->lock);
+ vlc_cond_destroy (&p_sys->wait);
+ free (p_sys);
return ret;
}
if (p_sys->peeked)
block_Release (p_sys->peeked);
+ vlc_mutex_destroy (&p_sys->lock);
+ vlc_cond_destroy (&p_sys->wait);
free (p_sys);
}