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
|
/* SPDX-License-Identifier: GPL-2.0 */
/** \file prebuffer_filter.c Paraslash's prebuffering filter. */
#include <lopsub.h>
#include "para.h"
#include "filter_cmd.lsg.h"
#include "list.h"
#include "sched.h"
#include "buffer_tree.h"
#include "filter.h"
#include "string.h"
#include "error.h"
/** Data specific to the prebuffer filter. */
struct private_prebuffer_data {
/** Number of bytes prebuffered or -1 if no longer prebuffering. */
int prebuffered;
/** End of prebuffering period. */
struct timeval barrier;
};
static void prebuffer_pre_monitor(struct sched *s, void *context)
{
struct filter_node *fn = context;
struct btr_node *btrn = fn->btrn;
size_t iqs = btr_get_input_queue_size(btrn);
struct private_prebuffer_data *ppd = fn->private_data;
struct timeval diff;
if (iqs == 0)
return;
if (ppd->barrier.tv_sec == 0) {
uint32_t duration = FILTER_CMD_OPT_UINT32_VAL(PREBUFFER,
DURATION, fn->lpr);
struct timeval tv;
PARA_INFO_LOG("prebuffer period %" PRIu32 "ms\n", duration);
ms2tv(duration, &tv);
tv_add(&tv, now, &ppd->barrier);
}
if (tv_diff(&ppd->barrier, now, &diff) < 0)
return sched_min_delay(s);
sched_request_timeout(&diff, s);
}
static void prebuffer_close(struct filter_node *fn)
{
free(fn->private_data);
}
static int prebuffer_post_monitor(__a_unused struct sched *s, void *context)
{
struct filter_node *fn = context;
struct btr_node *btrn = fn->btrn;
size_t iqs = btr_get_input_queue_size(btrn);
struct private_prebuffer_data *ppd = fn->private_data;
uint32_t size = FILTER_CMD_OPT_UINT32_VAL(PREBUFFER, SIZE, fn->lpr);
int ret;
ret = task_get_notification(fn->task);
if (ret < 0)
goto fail;
ret = btr_node_status(btrn, size, BTR_NT_INTERNAL);
if (ret < 0)
goto fail;
if (ppd->barrier.tv_sec == 0)
return 0;
if (tv_diff(now, &ppd->barrier, NULL) < 0)
return 0;
if (iqs < size)
return 0;
btr_splice_out_node(&fn->btrn);
return -E_PREBUFFER_SUCCESS;
fail:
btr_remove_node(&fn->btrn);
return ret;
}
static void prebuffer_open(struct filter_node *fn)
{
struct private_prebuffer_data *ppd = zalloc(sizeof(*ppd));
fn->private_data = ppd;
}
/** \cond doxygen_ignore */
const struct filter lsg_filter_cmd_com_prebuffer_user_data = {
.open = prebuffer_open,
.close = prebuffer_close,
.pre_monitor = prebuffer_pre_monitor,
.post_monitor = prebuffer_post_monitor,
};
/** \endcond */
|