command: redo ancient TV/DVB/PVR commands

Convert all these commands to properties. (Except tv_last_channel, not
sure what to do with this.) Also, internally, don't access stream
details directly, but dispatch commands with stream ctrls.

Many of the new properties are a bit strange, because they're write-
only. Also remove some OSD output these commands produced, because I
couldn't be bothered to port these.

In general, this makes everything much cleaner, and will also make it
easier to e.g. move the demuxer to its own thread.

Don't bother updating input.conf, but changes.rst documents how old
commands map to the new ones.

Mostly untested, due to lack of hardware.
This commit is contained in:
wm4 2014-06-09 23:38:28 +02:00
parent 9420eb5a07
commit e033f3c8bc
14 changed files with 262 additions and 210 deletions

View File

@ -274,6 +274,32 @@ input.conf and Slave Commands
+--------------------------------+----------------------------------------+
| ``af_switch``, ``af_add``, ... | ``af set|add|...`` |
+--------------------------------+----------------------------------------+
| ``tv_start_scan`` | ``set tv-scan yes`` |
+--------------------------------+----------------------------------------+
| ``tv_set_channel <val>`` | ``set tv-channel <val>`` |
+--------------------------------+----------------------------------------+
| ``tv_step_channel`` | ``cycle tv-channel`` |
+--------------------------------+----------------------------------------+
| ``dvb_set_channel <v1> <v2>`` | ``set dvb-channel <v1>-<v2>`` |
+--------------------------------+----------------------------------------+
| ``dvb_step_channel`` | ``cycle dvb-channel`` |
+--------------------------------+----------------------------------------+
| ``tv_set_freq <val>`` | ``set tv-freq <val>`` |
+--------------------------------+----------------------------------------+
| ``tv_step_freq`` | ``cycle tv-freq`` |
+--------------------------------+----------------------------------------+
| ``tv_set_norm <norm>`` | ``set tv-norm <norm>`` |
+--------------------------------+----------------------------------------+
| ``tv_step_norm`` | ``cycle tv-norm`` |
+--------------------------------+----------------------------------------+
.. note::
Due to lack of hardware and users using the TV/DVB/PVR features, and
due to the need to cleanup the related command code, it's possible
that the new commands are buggy or behave worse. This can be improved
if testers are available. Otherwise, some of the TV code will be
removed at some point.
Slave mode
~~~~~~~~~~

View File

@ -493,11 +493,8 @@ Input Commands that are Possibly Subject to Change
be used in input.conf to reassign such bindings.)
Undocumented commands: ``tv_start_scan``, ``tv_step_channel``, ``tv_step_norm``,
``tv_step_chanlist``, ``tv_set_channel``, ``tv_last_channel``, ``tv_set_freq``,
``tv_step_freq``, ``tv_set_norm``, ``dvb_set_channel`` (all of these
should be replaced by properties), ``stop`` (questionable use), ``get_property``
(?), ``vo_cmdline`` (experimental).
Undocumented commands: ``tv_last_channel`` (TV/DVB only), ``stop`` (questionable
use), ``get_property`` (?), ``vo_cmdline`` (experimental).
Input Command Prefixes
----------------------

View File

@ -56,6 +56,13 @@ enum demux_ctrl {
DEMUXER_CTRL_GET_START_TIME,
DEMUXER_CTRL_RESYNC,
DEMUXER_CTRL_IDENTIFY_PROGRAM,
DEMUXER_CTRL_STREAM_CTRL, // stupid workaround for legacy TV code
};
struct demux_ctrl_stream_ctrl {
int ctrl;
void *arg;
int res;
};
#define SEEK_ABSOLUTE (1 << 0)

View File

@ -156,12 +156,6 @@
#l cycle quvi-format 1
#L cycle quvi-format -1
# TV
#h tv_step_channel 1
#k tv_step_channel -1
#n tv_step_norm
#u tv_step_chanlist
# Apple Remote section
#AR_PLAY cycle pause
#AR_PLAY_HOLD quit

View File

@ -93,17 +93,7 @@ const struct mp_cmd_def mp_cmds[] = {
{ MP_CMD_SUB_REMOVE, "sub_remove", { OARG_INT(-1) } },
{ MP_CMD_SUB_RELOAD, "sub_reload", { OARG_INT(-1) } },
{ MP_CMD_TV_START_SCAN, "tv_start_scan", },
{ MP_CMD_TV_STEP_CHANNEL, "tv_step_channel", { ARG_INT } },
{ MP_CMD_TV_STEP_NORM, "tv_step_norm", },
{ MP_CMD_TV_STEP_CHANNEL_LIST, "tv_step_chanlist", },
{ MP_CMD_TV_SET_CHANNEL, "tv_set_channel", { ARG_STRING } },
{ MP_CMD_TV_LAST_CHANNEL, "tv_last_channel", },
{ MP_CMD_TV_SET_FREQ, "tv_set_freq", { ARG_FLOAT } },
{ MP_CMD_TV_STEP_FREQ, "tv_step_freq", { ARG_FLOAT } },
{ MP_CMD_TV_SET_NORM, "tv_set_norm", { ARG_STRING } },
{ MP_CMD_DVB_SET_CHANNEL, "dvb_set_channel", { ARG_INT, ARG_INT } },
{ MP_CMD_SCREENSHOT, "screenshot", {
OARG_CHOICE(2, ({"video", 0},

View File

@ -46,9 +46,6 @@ enum mp_command_type {
MP_CMD_PLAYLIST_NEXT,
MP_CMD_PLAYLIST_PREV,
MP_CMD_OSD,
MP_CMD_TV_STEP_CHANNEL,
MP_CMD_TV_STEP_NORM,
MP_CMD_TV_STEP_CHANNEL_LIST,
MP_CMD_SCREENSHOT,
MP_CMD_SCREENSHOT_TO_FILE,
MP_CMD_LOADFILE,
@ -58,10 +55,7 @@ enum mp_command_type {
MP_CMD_PLAYLIST_MOVE,
MP_CMD_SUB_STEP,
MP_CMD_SUB_SEEK,
MP_CMD_TV_SET_CHANNEL,
MP_CMD_TV_LAST_CHANNEL,
MP_CMD_TV_SET_FREQ,
MP_CMD_TV_SET_NORM,
MP_CMD_FRAME_STEP,
MP_CMD_FRAME_BACK_STEP,
MP_CMD_RUN,
@ -77,8 +71,6 @@ enum mp_command_type {
MP_CMD_CYCLE,
MP_CMD_MULTIPLY,
MP_CMD_CYCLE_VALUES,
MP_CMD_TV_STEP_FREQ,
MP_CMD_TV_START_SCAN,
MP_CMD_STOP,
MP_CMD_ENABLE_INPUT_SECTION,
@ -86,9 +78,6 @@ enum mp_command_type {
MP_CMD_DISCNAV,
/// DVB commands
MP_CMD_DVB_SET_CHANNEL,
/// Audio Filter commands
MP_CMD_AF,

View File

@ -59,11 +59,6 @@
#include "video/decode/dec_video.h"
#include "audio/decode/dec_audio.h"
#include "options/path.h"
#include "stream/tv.h"
#include "stream/pvr.h"
#if HAVE_DVBIN
#include "stream/dvbin.h"
#endif
#include "screenshot.h"
#if HAVE_SYS_MMAN_H
#include <sys/mman.h>
@ -2102,33 +2097,120 @@ static int mp_property_sub_pos(m_option_t *prop, int action, void *arg,
return property_osd_helper(prop, action, arg, mpctx);
}
#if HAVE_TV
static tvi_handle_t *get_tvh(struct MPContext *mpctx)
static int demux_stream_control(struct MPContext *mpctx, int ctrl, void *arg)
{
if (!(mpctx->master_demuxer && mpctx->master_demuxer->type == DEMUXER_TYPE_TV))
return NULL;
return mpctx->master_demuxer->priv;
int r = STREAM_UNSUPPORTED;
if (mpctx->stream)
r = stream_control(mpctx->stream, ctrl, arg);
if (r == STREAM_UNSUPPORTED && mpctx->demuxer) {
struct demux_ctrl_stream_ctrl c = {ctrl, arg, STREAM_UNSUPPORTED};
demux_control(mpctx->demuxer, DEMUXER_CTRL_STREAM_CTRL, &c);
r = c.res;
}
return r;
}
static int prop_stream_ctrl(struct MPContext *mpctx, int ctrl, void *arg)
{
int r = demux_stream_control(mpctx, ctrl, arg);
switch (r) {
case STREAM_OK: return M_PROPERTY_OK;
case STREAM_UNSUPPORTED: return M_PROPERTY_UNAVAILABLE;
default: return M_PROPERTY_ERROR;
}
}
static int mp_property_tv_norm(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
switch (action) {
case M_PROPERTY_SET:
return prop_stream_ctrl(mpctx, STREAM_CTRL_TV_SET_NORM, *(char **)arg);
case M_PROPERTY_SWITCH:
return prop_stream_ctrl(mpctx, STREAM_CTRL_TV_STEP_NORM, NULL);
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
static int mp_property_tv_scan(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
switch (action) {
case M_PROPERTY_SET:
return prop_stream_ctrl(mpctx, STREAM_CTRL_TV_SET_SCAN, arg);
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
/// TV color settings (RW)
static int mp_property_tv_color(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
tvi_handle_t *tvh = get_tvh(mpctx);
if (!tvh)
return M_PROPERTY_UNAVAILABLE;
int req[2] = {prop->offset};
switch (action) {
case M_PROPERTY_SET:
return tv_set_color_options(tvh, prop->offset, *(int *) arg);
case M_PROPERTY_GET:
return tv_get_color_options(tvh, prop->offset, arg);
req[1] = *(int *)arg;
return prop_stream_ctrl(mpctx, STREAM_CTRL_SET_TV_COLORS, req);
case M_PROPERTY_GET: {
int r = prop_stream_ctrl(mpctx, STREAM_CTRL_GET_TV_COLORS, req);
if (r == M_PROPERTY_OK)
*(int *)arg = req[1];
return r;
}
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
#endif
static int mp_property_tv_freq(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
switch (action) {
case M_PROPERTY_SET:
return prop_stream_ctrl(mpctx, STREAM_CTRL_SET_TV_FREQ, arg);
case M_PROPERTY_GET:
return prop_stream_ctrl(mpctx, STREAM_CTRL_GET_TV_FREQ, arg);
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
static int mp_property_tv_channel(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
switch (action) {
case M_PROPERTY_SET:
return prop_stream_ctrl(mpctx, STREAM_CTRL_TV_SET_CHAN, *(char **)arg);
case M_PROPERTY_SWITCH: {
struct m_property_switch_arg *sa = arg;
int dir = sa->inc >= 0 ? 1 : -1;
return prop_stream_ctrl(mpctx, STREAM_CTRL_TV_STEP_CHAN, &dir);
}
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
static int mp_property_dvb_channel(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
int r;
switch (action) {
case M_PROPERTY_SET:
mpctx->last_dvb_step = 1;
r = prop_stream_ctrl(mpctx, STREAM_CTRL_DVB_SET_CHANNEL, arg);
if (r == M_PROPERTY_OK)
mpctx->stop_play = PT_RELOAD_DEMUXER;
return r;
case M_PROPERTY_SWITCH: {
struct m_property_switch_arg *sa = arg;
int dir = sa->inc >= 0 ? 1 : -1;
mpctx->last_dvb_step = dir;
r = prop_stream_ctrl(mpctx, STREAM_CTRL_DVB_STEP_CHANNEL, &dir);
if (r == M_PROPERTY_OK)
mpctx->stop_play = PT_RELOAD_DEMUXER;
return r;
}
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
static int mp_property_playlist_pos(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
@ -2490,7 +2572,6 @@ static const m_option_t mp_properties[] = {
M_OPTION_PROPERTY_CUSTOM("vf", mp_property_vf),
M_OPTION_PROPERTY_CUSTOM("af", mp_property_af),
#if HAVE_TV
{ "tv-brightness", mp_property_tv_color, CONF_TYPE_INT,
M_OPT_RANGE, -100, 100, .offset = TV_COLOR_BRIGHTNESS },
{ "tv-contrast", mp_property_tv_color, CONF_TYPE_INT,
@ -2499,7 +2580,12 @@ static const m_option_t mp_properties[] = {
M_OPT_RANGE, -100, 100, .offset = TV_COLOR_SATURATION },
{ "tv-hue", mp_property_tv_color, CONF_TYPE_INT,
M_OPT_RANGE, -100, 100, .offset = TV_COLOR_HUE },
#endif
{ "tv-freq", mp_property_tv_freq, CONF_TYPE_FLOAT, },
{ "tv-norm", mp_property_tv_norm, CONF_TYPE_STRING, },
{ "tv-scan", mp_property_tv_scan, CONF_TYPE_FLAG,
M_OPT_RANGE, 0, 1 },
{ "tv-channel", mp_property_tv_channel, CONF_TYPE_STRING, },
{ "dvb-channel", mp_property_dvb_channel, &m_option_type_intpair, },
M_PROPERTY_ALIAS("video", "vid"),
M_PROPERTY_ALIAS("audio", "aid"),
@ -3432,142 +3518,10 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd)
(bar_osd ? OSD_SEEK_INFO_BAR : 0);
break;
#if HAVE_TV
case MP_CMD_TV_START_SCAN:
if (get_tvh(mpctx))
tv_start_scan(get_tvh(mpctx), 1);
case MP_CMD_TV_LAST_CHANNEL: {
demux_stream_control(mpctx, STREAM_CTRL_TV_LAST_CHAN, NULL);
break;
case MP_CMD_TV_SET_FREQ:
if (get_tvh(mpctx))
tv_set_freq(get_tvh(mpctx), cmd->args[0].v.f * 16.0);
#if HAVE_PVR
else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
pvr_set_freq(mpctx->stream, ROUND(cmd->args[0].v.f));
set_osd_msg(mpctx, osdl, osd_duration, "%s: %s",
pvr_get_current_channelname(mpctx->stream),
pvr_get_current_stationname(mpctx->stream));
}
#endif /* HAVE_PVR */
break;
case MP_CMD_TV_STEP_FREQ:
if (get_tvh(mpctx))
tv_step_freq(get_tvh(mpctx), cmd->args[0].v.f * 16.0);
#if HAVE_PVR
else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
pvr_force_freq_step(mpctx->stream, ROUND(cmd->args[0].v.f));
set_osd_msg(mpctx, osdl, osd_duration, "%s: f %d",
pvr_get_current_channelname(mpctx->stream),
pvr_get_current_frequency(mpctx->stream));
}
#endif /* HAVE_PVR */
break;
case MP_CMD_TV_SET_NORM:
if (get_tvh(mpctx))
tv_set_norm(get_tvh(mpctx), cmd->args[0].v.s);
break;
case MP_CMD_TV_STEP_CHANNEL:
if (get_tvh(mpctx)) {
int v = cmd->args[0].v.i;
if (v > 0) {
tv_step_channel(get_tvh(mpctx), TV_CHANNEL_HIGHER);
} else {
tv_step_channel(get_tvh(mpctx), TV_CHANNEL_LOWER);
}
if (tv_channel_list) {
set_osd_msg(mpctx, osdl, osd_duration,
"Channel: %s", tv_channel_current->name);
}
}
#if HAVE_PVR
else if (mpctx->stream &&
mpctx->stream->type == STREAMTYPE_PVR) {
pvr_set_channel_step(mpctx->stream, cmd->args[0].v.i);
set_osd_msg(mpctx, osdl, osd_duration, "%s: %s",
pvr_get_current_channelname(mpctx->stream),
pvr_get_current_stationname(mpctx->stream));
}
#endif /* HAVE_PVR */
#if HAVE_DVBIN
if (mpctx->stream && mpctx->stream->type == STREAMTYPE_DVB) {
int dir;
int v = cmd->args[0].v.i;
mpctx->last_dvb_step = v;
if (v > 0)
dir = DVB_CHANNEL_HIGHER;
else
dir = DVB_CHANNEL_LOWER;
if (dvb_step_channel(mpctx->stream, dir)) {
mpctx->stop_play = PT_RELOAD_DEMUXER;
}
}
#endif /* HAVE_DVBIN */
break;
case MP_CMD_TV_SET_CHANNEL:
if (get_tvh(mpctx)) {
tv_set_channel(get_tvh(mpctx), cmd->args[0].v.s);
if (tv_channel_list) {
set_osd_msg(mpctx, osdl, osd_duration,
"Channel: %s", tv_channel_current->name);
}
}
#if HAVE_PVR
else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
pvr_set_channel(mpctx->stream, cmd->args[0].v.s);
set_osd_msg(mpctx, osdl, osd_duration, "%s: %s",
pvr_get_current_channelname(mpctx->stream),
pvr_get_current_stationname(mpctx->stream));
}
#endif /* HAVE_PVR */
break;
#if HAVE_DVBIN
case MP_CMD_DVB_SET_CHANNEL:
if (mpctx->stream && mpctx->stream->type == STREAMTYPE_DVB) {
mpctx->last_dvb_step = 1;
if (dvb_set_channel(mpctx->stream, cmd->args[1].v.i,
cmd->args[0].v.i)) {
mpctx->stop_play = PT_RELOAD_DEMUXER;
}
}
break;
#endif /* HAVE_DVBIN */
case MP_CMD_TV_LAST_CHANNEL:
if (get_tvh(mpctx)) {
tv_last_channel(get_tvh(mpctx));
if (tv_channel_list) {
set_osd_msg(mpctx, osdl, osd_duration,
"Channel: %s", tv_channel_current->name);
}
}
#if HAVE_PVR
else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
pvr_set_lastchannel(mpctx->stream);
set_osd_msg(mpctx, osdl, osd_duration, "%s: %s",
pvr_get_current_channelname(mpctx->stream),
pvr_get_current_stationname(mpctx->stream));
}
#endif /* HAVE_PVR */
break;
case MP_CMD_TV_STEP_NORM:
if (get_tvh(mpctx))
tv_step_norm(get_tvh(mpctx));
break;
case MP_CMD_TV_STEP_CHANNEL_LIST:
if (get_tvh(mpctx))
tv_step_chanlist(get_tvh(mpctx));
break;
#endif /* HAVE_TV */
}
case MP_CMD_SUB_ADD: {
struct track *sub = mp_add_subtitles(mpctx, cmd->args[0].v.s);

View File

@ -1257,20 +1257,13 @@ goto_reopen_demuxer: ;
//==================== START PLAYING =======================
if (!mpctx->d_video && !mpctx->d_audio) {
struct stream *s = mpctx->stream;
MP_FATAL(mpctx, "No video or audio streams selected.\n");
#if HAVE_DVBIN
if (mpctx->stream->type == STREAMTYPE_DVB) {
int dir;
int v = mpctx->last_dvb_step;
if (v > 0)
dir = DVB_CHANNEL_HIGHER;
else
dir = DVB_CHANNEL_LOWER;
if (dvb_step_channel(mpctx->stream, dir))
if (s->uncached_type == STREAMTYPE_DVB) {
int dir = mpctx->last_dvb_step;
if (stream_control(s, STREAM_CTRL_DVB_STEP_CHANNEL, &dir) > 0)
mpctx->stop_play = PT_RELOAD_DEMUXER;
}
#endif
goto terminate_playback;
}

View File

@ -303,7 +303,6 @@ struct MPContext *mp_create(void)
struct MPContext *mpctx = talloc(NULL, MPContext);
*mpctx = (struct MPContext){
.last_dvb_step = 1,
.last_chapter = -2,
.term_osd_contents = talloc_strdup(mpctx, ""),
.osd_progbar = { .type = -1 },

View File

@ -92,7 +92,19 @@ enum stream_ctrl {
STREAM_CTRL_GET_BASE_FILENAME,
STREAM_CTRL_GET_NAV_EVENT, // struct mp_nav_event**
STREAM_CTRL_NAV_CMD, // struct mp_nav_cmd*
STREAM_CTRL_GET_DISC_NAME
STREAM_CTRL_GET_DISC_NAME,
STREAM_CTRL_TV_SET_SCAN,
STREAM_CTRL_SET_TV_FREQ,
STREAM_CTRL_GET_TV_FREQ,
STREAM_CTRL_SET_TV_COLORS,
STREAM_CTRL_GET_TV_COLORS,
STREAM_CTRL_TV_SET_NORM,
STREAM_CTRL_TV_STEP_NORM,
STREAM_CTRL_TV_SET_CHAN,
STREAM_CTRL_TV_STEP_CHAN,
STREAM_CTRL_TV_LAST_CHAN,
STREAM_CTRL_DVB_SET_CHANNEL,
STREAM_CTRL_DVB_STEP_CHANNEL,
};
struct stream_lang_req {
@ -106,6 +118,12 @@ struct stream_dvd_info_req {
int num_subs;
};
// for STREAM_CTRL_SET_TV_COLORS
#define TV_COLOR_BRIGHTNESS 1
#define TV_COLOR_HUE 2
#define TV_COLOR_SATURATION 3
#define TV_COLOR_CONTRAST 4
struct stream;
typedef struct stream_info_st {
const char *name;

View File

@ -550,13 +550,26 @@ int dvb_step_channel(stream_t *stream, int dir)
return 0;
}
new_current = (list->NUM_CHANNELS + list->current + (dir == DVB_CHANNEL_HIGHER ? 1 : -1)) % list->NUM_CHANNELS;
new_current = (list->NUM_CHANNELS + list->current + (dir >= 0 ? 1 : -1)) % list->NUM_CHANNELS;
return dvb_set_channel(stream, priv->card, new_current);
}
static int dvbin_stream_control(struct stream *s, int cmd, void *arg)
{
int r;
switch (cmd) {
case STREAM_CTRL_DVB_SET_CHANNEL: {
int *iarg = arg;
r = dvb_set_channel(s, iarg[1], iarg[0]);
return r ? STREAM_OK : STREAM_ERROR;
}
case STREAM_CTRL_DVB_STEP_CHANNEL:
r = dvb_step_channel(s, *(int *)arg);
return r ? STREAM_OK : STREAM_ERROR;
}
return STREAM_UNSUPPORTED;
}
static void dvbin_close(stream_t *stream)
{
@ -692,6 +705,7 @@ static int dvb_open(stream_t *stream)
stream->type = STREAMTYPE_DVB;
stream->fill_buffer = dvb_streaming_read;
stream->close = dvbin_close;
stream->control = dvbin_stream_control;
stream->demuxer = "lavf";
stream->lavf_type = "mpegts";

View File

@ -142,6 +142,8 @@ struct pvr_t {
int stream_type;
};
static int pvr_stream_control(struct stream *s, int cmd, void *arg);
static struct pvr_t *
pvr_init (void)
{
@ -1608,6 +1610,7 @@ pvr_stream_open (stream_t *stream)
stream->type = STREAMTYPE_PVR;
stream->fill_buffer = pvr_stream_read;
stream->close = pvr_stream_close;
stream->control = pvr_stream_control;
return STREAM_OK;
}
@ -1698,6 +1701,28 @@ pvr_force_freq_step (stream_t *stream, int step)
return force_freq_step (pvr, step);
}
static int pvr_stream_control(struct stream *s, int cmd, void *arg)
{
switch (cmd) {
case STREAM_CTRL_SET_TV_FREQ:
pvr_set_freq(s, (int)(*(float *)arg + 0.5f));
return STREAM_OK;
case STREAM_CTRL_GET_TV_FREQ:
*(float *)arg = pvr_get_current_frequency(s);
return STREAM_OK;
case STREAM_CTRL_TV_SET_CHAN:
pvr_set_channel(s, (char *)arg);
return STREAM_OK;
case STREAM_CTRL_TV_STEP_CHAN:
pvr_set_channel_step(s, *(int *)arg);
return STREAM_OK;
case STREAM_CTRL_TV_LAST_CHAN:
pvr_set_lastchannel(s);
return STREAM_OK;
}
return STREAM_UNSUPPORTED;
}
const stream_info_t stream_info_pvr = {
.name = "pvr",
.open = pvr_stream_open,

View File

@ -1087,9 +1087,58 @@ int tv_step_norm(tvi_handle_t *tvh)
return 1;
}
int tv_step_chanlist(tvi_handle_t *tvh)
static int tv_stream_control(tvi_handle_t *tvh, int cmd, void *arg)
{
return 1;
switch (cmd) {
case STREAM_CTRL_TV_SET_SCAN:
tv_start_scan(tvh, *(int *)arg);
return STREAM_OK;
case STREAM_CTRL_SET_TV_FREQ:
tv_set_freq(tvh, *(float *)arg * 16.0f);
return STREAM_OK;
case STREAM_CTRL_GET_TV_FREQ: {
unsigned long tmp = 0;
tv_get_freq(tvh, &tmp);
*(float *)arg = tmp / 16.0f;
return STREAM_OK;
}
case STREAM_CTRL_SET_TV_COLORS:
tv_set_color_options(tvh, ((int *)arg)[0], ((int *)arg)[1]);
return STREAM_OK;
case STREAM_CTRL_GET_TV_COLORS:
tv_get_color_options(tvh, ((int *)arg)[0], &((int *)arg)[1]);
return STREAM_OK;
case STREAM_CTRL_TV_SET_NORM:
tv_set_norm(tvh, (char *)arg);
return STREAM_OK;
case STREAM_CTRL_TV_STEP_NORM:
tv_step_norm(tvh);
return STREAM_OK;
case STREAM_CTRL_TV_SET_CHAN:
tv_set_channel(tvh, (char *)arg);
return STREAM_OK;
case STREAM_CTRL_TV_STEP_CHAN:
if (*(int *)arg >= 0) {
tv_step_channel(tvh, TV_CHANNEL_HIGHER);
} else {
tv_step_channel(tvh, TV_CHANNEL_LOWER);
}
return STREAM_OK;
case STREAM_CTRL_TV_LAST_CHAN:
tv_last_channel(tvh);
return STREAM_OK;
}
return STREAM_UNSUPPORTED;
}
static int demux_tv_control(demuxer_t *demuxer, int cmd, void *arg)
{
tvi_handle_t *tvh=(tvi_handle_t*)(demuxer->priv);
if (cmd != DEMUXER_CTRL_STREAM_CTRL)
return DEMUXER_CTRL_NOTIMPL;
struct demux_ctrl_stream_ctrl *ctrl = arg;
ctrl->res = tv_stream_control(tvh, ctrl->ctrl, ctrl->arg);
return DEMUXER_CTRL_OK;
}
demuxer_desc_t demuxer_desc_tv = {
@ -1097,6 +1146,7 @@ demuxer_desc_t demuxer_desc_tv = {
.desc = "TV card demuxer",
.type = DEMUXER_TYPE_TV,
.fill_buffer = demux_tv_fill_buffer,
.control = demux_tv_control,
.open = demux_open_tv,
.close = demux_close_tv,
};

View File

@ -201,10 +201,6 @@ typedef struct {
int tv_set_color_options(tvi_handle_t *tvh, int opt, int val);
int tv_get_color_options(tvi_handle_t *tvh, int opt, int* val);
#define TV_COLOR_BRIGHTNESS 1
#define TV_COLOR_HUE 2
#define TV_COLOR_SATURATION 3
#define TV_COLOR_CONTRAST 4
int tv_step_channel_real(tvi_handle_t *tvh, int direction);
int tv_step_channel(tvi_handle_t *tvh, int direction);