1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
/*
* Copyright (C) 2009 Andre Noll <maan@systemlinux.org>
*
* Licensed under the GPL v2. For licencing details see COPYING.
*/
/** \file prebuffer_filter.c Paraslash's prebuffering filter. */
#include "para.h"
#include "prebuffer_filter.cmdline.h"
#include "list.h"
#include "sched.h"
#include "ggo.h"
#include "filter.h"
#include "string.h"
#include "error.h"
/** Data specific to the prebuffer filter. */
struct private_prebuffer_data {
/** The configuration data for this instance of the filter. */
struct prebuffer_filter_args_info *conf;
/** Number of bytes prebuffered or -1 if no longer prebuffering. */
int prebuffered;
/** End of prebuffering period. */
struct timeval barrier;
};
static ssize_t prebuffer_convert(char *inbuf, size_t inbuf_len,
struct filter_node *fn)
{
struct private_prebuffer_data *ppd = fn->private_data;
struct prebuffer_filter_args_info *conf = ppd->conf;
if (inbuf_len == 0) {
if (*fn->fc->input_error < 0 && ppd->prebuffered >= 0)
goto prebuffer_end;
return 0;
}
if (ppd->prebuffered < 0) {
size_t copy = PARA_MIN(inbuf_len, fn->bufsize - fn->loaded);
memcpy(fn->buf + fn->loaded, inbuf, copy);
fn->loaded += copy;
return copy;
}
if (ppd->prebuffered + inbuf_len > fn->bufsize) {
fn->bufsize = PARA_MAX(2 * fn->bufsize,
ppd->prebuffered + inbuf_len);
fn->buf = para_realloc(fn->buf, fn->bufsize);
}
memcpy(fn->buf + ppd->prebuffered, inbuf, inbuf_len);
if (ppd->prebuffered == 0) {
struct timeval tv;
PARA_INFO_LOG("prebuffer period %dms\n",
conf->duration_arg);
ms2tv(conf->duration_arg, &tv);
tv_add(&tv, now, &ppd->barrier);
}
ppd->prebuffered += inbuf_len;
PARA_DEBUG_LOG("%d bytes prebuffered\n", ppd->prebuffered);
if (*fn->fc->input_error >= 0) {
struct timeval diff;
if (tv_diff(now, &ppd->barrier, &diff) < 0)
goto out;
if (ppd->prebuffered < conf->size_arg)
goto out;
}
prebuffer_end:
fn->loaded = ppd->prebuffered;
ppd->prebuffered = -1;
out:
return inbuf_len;
}
static void prebuffer_close(struct filter_node *fn)
{
free(fn->private_data);
free(fn->buf);
}
static int prebuffer_parse_config(int argc, char **argv, void **config)
{
struct prebuffer_filter_args_info *prebuffer_conf
= para_calloc(sizeof(*prebuffer_conf));
int ret = -E_PREBUFFER_SYNTAX;
if (prebuffer_cmdline_parser(argc, argv, prebuffer_conf))
goto err;
ret = -ERRNO_TO_PARA_ERROR(EINVAL);
if (prebuffer_conf->duration_arg < 0)
goto err;
if (prebuffer_conf->size_arg < 0)
goto err;
PARA_NOTICE_LOG("prebuffering %ims, %i bytes\n",
prebuffer_conf->duration_arg, prebuffer_conf->size_arg);
*config = prebuffer_conf;
return 1;
err:
free(prebuffer_conf);
return ret;
}
static void prebuffer_open(struct filter_node *fn)
{
struct private_prebuffer_data *ppd = para_calloc(sizeof(*ppd));
ppd->conf = fn->conf;
fn->private_data = ppd;
fn->bufsize = 8192; /* gets increased on demand */
fn->buf = para_malloc(fn->bufsize);
}
/**
* The init function of the prebuffer filter.
*
* \param f Pointer to the struct to initialize.
*/
void prebuffer_filter_init(struct filter *f)
{
struct prebuffer_filter_args_info dummy;
prebuffer_cmdline_parser_init(&dummy);
f->open = prebuffer_open;
f->close = prebuffer_close;
f->convert = prebuffer_convert;
f->parse_config = prebuffer_parse_config;
f->help = (struct ggo_help) {
.short_help = prebuffer_filter_args_info_help,
.detailed_help = prebuffer_filter_args_info_detailed_help
};
}
|