Remove MPEGPS/V4L support
This commit is contained in:
parent
dddc4249ef
commit
6cd5f1b379
6 changed files with 1 additions and 884 deletions
8
configure
vendored
8
configure
vendored
|
@ -19,7 +19,6 @@ OPTIONS=(
|
|||
"cwc:yes"
|
||||
"capmt:yes"
|
||||
"constcw:yes"
|
||||
"v4l:no"
|
||||
"linuxdvb:yes"
|
||||
"satip_server:yes"
|
||||
"satip_client:yes"
|
||||
|
@ -465,10 +464,9 @@ if [ ${PLATFORM} = "freebsd" ] || [ ${PLATFORM} = "darwin" ]; then
|
|||
fi
|
||||
|
||||
#
|
||||
# MPEGTS/PS support
|
||||
# MPEGTS support
|
||||
#
|
||||
disable mpegts
|
||||
disable mpegps
|
||||
disable mpegts_dvb
|
||||
if enabled linuxdvb || enabled iptv || enabled tsfile || enabled satip_client || \
|
||||
enabled hdhomerun_client || enabled satip_server;
|
||||
|
@ -479,10 +477,6 @@ if enabled linuxdvb || enabled satip_client || enabled hdhomerun_client || enabl
|
|||
enable mpegts_dvb
|
||||
fi
|
||||
|
||||
if enabled v4l; then
|
||||
enable mpegps
|
||||
fi
|
||||
|
||||
#
|
||||
# DBus
|
||||
#
|
||||
|
|
|
@ -124,10 +124,6 @@ void tvh_input_stream_destroy ( tvh_input_stream_t *st );
|
|||
* Input subsystem includes
|
||||
*/
|
||||
|
||||
#if ENABLE_MPEGPS
|
||||
#include "input/mpegps.h"
|
||||
#endif
|
||||
|
||||
#if ENABLE_MPEGTS
|
||||
#include "input/mpegts.h"
|
||||
#include "input/mpegts/mpegts_mux_sched.h"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
v4l/v4l.h
|
|
@ -1,789 +0,0 @@
|
|||
/*
|
||||
* TV Input - Linux analogue (v4lv2) interface
|
||||
* Copyright (C) 2007 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "service.h"
|
||||
#include "v4l.h"
|
||||
#include "parsers.h"
|
||||
#include "notify.h"
|
||||
#include "psi.h"
|
||||
#include "channels.h"
|
||||
|
||||
struct v4l_adapter_queue v4l_adapters;
|
||||
|
||||
static void v4l_adapter_notify(v4l_adapter_t *va);
|
||||
|
||||
const idclass_t v4l_class = {
|
||||
.ic_super = &service_class,
|
||||
.ic_class = "v4l",
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
v4l_input(v4l_adapter_t *va)
|
||||
{
|
||||
service_t *t = va->va_current_service;
|
||||
elementary_stream_t *st;
|
||||
uint8_t buf[4000];
|
||||
uint8_t *ptr, *pkt;
|
||||
int len, l, r;
|
||||
|
||||
len = read(va->va_fd, buf, 4000);
|
||||
if(len < 1)
|
||||
return;
|
||||
|
||||
ptr = buf;
|
||||
|
||||
pthread_mutex_lock(&t->s_stream_mutex);
|
||||
|
||||
service_set_streaming_status_flags(t,
|
||||
TSS_INPUT_HARDWARE | TSS_INPUT_SERVICE);
|
||||
|
||||
while(len > 0) {
|
||||
|
||||
switch(va->va_startcode) {
|
||||
default:
|
||||
va->va_startcode = va->va_startcode << 8 | *ptr;
|
||||
va->va_lenlock = 0;
|
||||
ptr++; len--;
|
||||
continue;
|
||||
|
||||
case 0x000001e0:
|
||||
st = t->s_video;
|
||||
break;
|
||||
case 0x000001c0:
|
||||
st = t->s_audio;
|
||||
break;
|
||||
}
|
||||
|
||||
if(va->va_lenlock == 2) {
|
||||
l = st->es_buf_ps.sb_size;
|
||||
st->es_buf_ps.sb_data = pkt = realloc(st->es_buf_ps.sb_data, l);
|
||||
|
||||
r = l - st->es_buf_ps.sb_ptr;
|
||||
if(r > len)
|
||||
r = len;
|
||||
memcpy(pkt + st->es_buf_ps.sb_ptr, ptr, r);
|
||||
|
||||
ptr += r;
|
||||
len -= r;
|
||||
|
||||
st->es_buf_ps.sb_ptr += r;
|
||||
if(st->es_buf_ps.sb_ptr == l) {
|
||||
|
||||
service_set_streaming_status_flags(t, TSS_MUX_PACKETS);
|
||||
|
||||
parse_mpeg_ps(t, st, pkt + 6, l - 6);
|
||||
|
||||
st->es_buf_ps.sb_size = 0;
|
||||
va->va_startcode = 0;
|
||||
} else {
|
||||
assert(st->es_buf_ps.sb_ptr < l);
|
||||
}
|
||||
|
||||
} else {
|
||||
st->es_buf_ps.sb_size = st->es_buf_ps.sb_size << 8 | *ptr;
|
||||
va->va_lenlock++;
|
||||
if(va->va_lenlock == 2) {
|
||||
st->es_buf_ps.sb_size += 6;
|
||||
st->es_buf_ps.sb_ptr = 6;
|
||||
}
|
||||
ptr++; len--;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&t->s_stream_mutex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void *
|
||||
v4l_thread(void *aux)
|
||||
{
|
||||
v4l_adapter_t *va = aux;
|
||||
struct pollfd pfd[2];
|
||||
int r;
|
||||
|
||||
pfd[0].fd = va->va_pipe[0];
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[1].fd = va->va_fd;
|
||||
pfd[1].events = POLLIN;
|
||||
|
||||
while(1) {
|
||||
|
||||
r = poll(pfd, 2, -1);
|
||||
if(r < 0) {
|
||||
tvhlog(LOG_ALERT, "v4l", "%s: poll() error %s, sleeping one second",
|
||||
va->va_path, strerror(errno));
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(pfd[0].revents & POLLIN) {
|
||||
// Message on control pipe, used to exit thread, do so
|
||||
break;
|
||||
}
|
||||
|
||||
if(pfd[1].revents & POLLIN) {
|
||||
v4l_input(va);
|
||||
}
|
||||
}
|
||||
|
||||
close(va->va_pipe[0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
v4l_service_start(service_t *t, int instance)
|
||||
{
|
||||
v4l_adapter_t *va = t->s_v4l_adapter;
|
||||
int frequency = t->s_v4l_frequency;
|
||||
struct v4l2_frequency vf;
|
||||
int result;
|
||||
v4l2_std_id std = 0xff;
|
||||
int fd;
|
||||
|
||||
if(va->va_current_service != NULL)
|
||||
return 1; // Adapter busy
|
||||
|
||||
fd = tvh_open(va->va_path, O_RDWR | O_NONBLOCK, 0);
|
||||
if(fd == -1) {
|
||||
tvhlog(LOG_ERR, "v4l",
|
||||
"%s: Unable to open device: %s\n", va->va_path,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!va->va_file) {
|
||||
|
||||
result = ioctl(fd, VIDIOC_S_STD, &std);
|
||||
if(result < 0) {
|
||||
tvhlog(LOG_ERR, "v4l",
|
||||
"%s: Unable to set PAL -- %s", va->va_path, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&vf, 0, sizeof(vf));
|
||||
|
||||
vf.tuner = 0;
|
||||
vf.type = V4L2_TUNER_ANALOG_TV;
|
||||
vf.frequency = (frequency * 16) / 1000000;
|
||||
result = ioctl(fd, VIDIOC_S_FREQUENCY, &vf);
|
||||
if(result < 0) {
|
||||
tvhlog(LOG_ERR, "v4l",
|
||||
"%s: Unable to tune to %dHz", va->va_path, frequency);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tvhlog(LOG_INFO, "v4l",
|
||||
"%s: Tuned to %dHz", va->va_path, frequency);
|
||||
}
|
||||
if(pipe(va->va_pipe)) {
|
||||
tvhlog(LOG_ERR, "v4l",
|
||||
"%s: Unable to create control pipe [%s]", va->va_path, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
va->va_fd = fd;
|
||||
va->va_current_service = t;
|
||||
tvhthread_create(&va->va_thread, NULL, v4l_thread, va);
|
||||
v4l_adapter_notify(va);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
v4l_service_refresh(service_t *t)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
v4l_service_stop(service_t *t)
|
||||
{
|
||||
char c = 'q';
|
||||
v4l_adapter_t *va = t->s_v4l_adapter;
|
||||
|
||||
assert(va->va_current_service != NULL);
|
||||
|
||||
if(tvh_write(va->va_pipe[1], &c, 1))
|
||||
tvhlog(LOG_ERR, "v4l", "Unable to close video thread -- %s",
|
||||
strerror(errno));
|
||||
|
||||
pthread_join(va->va_thread, NULL);
|
||||
|
||||
close(va->va_pipe[1]);
|
||||
close(va->va_fd);
|
||||
|
||||
va->va_current_service = NULL;
|
||||
v4l_adapter_notify(va);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
v4l_service_save(service_t *t)
|
||||
{
|
||||
v4l_adapter_t *va = t->s_v4l_adapter;
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_u32(m, "frequency", t->s_v4l_frequency);
|
||||
|
||||
if(t->s_ch != NULL) {
|
||||
htsmsg_add_str(m, "channelname", t->s_ch->ch_name);
|
||||
htsmsg_add_u32(m, "mapped", 1);
|
||||
}
|
||||
|
||||
|
||||
pthread_mutex_lock(&t->s_stream_mutex);
|
||||
psi_save_service_settings(m, t);
|
||||
pthread_mutex_unlock(&t->s_stream_mutex);
|
||||
|
||||
hts_settings_save(m, "v4lservices/%s/%s",
|
||||
va->va_identifier, idnode_uuid_as_str(&t->s_id));
|
||||
|
||||
htsmsg_destroy(m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
v4l_service_is_enabled(service_t *t)
|
||||
{
|
||||
return t->s_enabled;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
v4l_grace_period(service_t *t)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a descriptive name for the source
|
||||
*/
|
||||
static void
|
||||
v4l_service_setsourceinfo(service_t *t, struct source_info *si)
|
||||
{
|
||||
char buf[64];
|
||||
memset(si, 0, sizeof(struct source_info));
|
||||
|
||||
si->si_type = S_MPEG_PS;
|
||||
si->si_adapter = strdup(t->s_v4l_adapter->va_displayname);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d Hz", t->s_v4l_frequency);
|
||||
si->si_mux = strdup(buf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
service_t *
|
||||
v4l_service_find(v4l_adapter_t *va, const char *id, int create)
|
||||
{
|
||||
service_t *t;
|
||||
char buf[200];
|
||||
|
||||
int vaidlen = strlen(va->va_identifier);
|
||||
|
||||
if(id != NULL) {
|
||||
|
||||
if(strncmp(id, va->va_identifier, vaidlen))
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(t, &va->va_services, s_group_link)
|
||||
if(!strcmp(idnode_uuid_as_str(&t->s_id), id))
|
||||
return t;
|
||||
}
|
||||
|
||||
if(create == 0)
|
||||
return NULL;
|
||||
|
||||
if(id == NULL) {
|
||||
va->va_tally++;
|
||||
snprintf(buf, sizeof(buf), "%s_%d", va->va_identifier, va->va_tally);
|
||||
id = buf;
|
||||
} else {
|
||||
va->va_tally = MAX(atoi(id + vaidlen + 1), va->va_tally);
|
||||
}
|
||||
|
||||
t = service_create(id, 0, &v4l_class);
|
||||
|
||||
t->s_start_feed = v4l_service_start;
|
||||
t->s_refresh_feed = v4l_service_refresh;
|
||||
t->s_stop_feed = v4l_service_stop;
|
||||
t->s_config_save = v4l_service_save;
|
||||
t->s_setsourceinfo = v4l_service_setsourceinfo;
|
||||
t->s_is_enabled = v4l_service_is_enabled;
|
||||
t->s_grace_period = v4l_grace_period;
|
||||
t->s_iptv_fd = -1;
|
||||
t->s_v4l_adapter = va;
|
||||
|
||||
pthread_mutex_lock(&t->s_stream_mutex);
|
||||
service_make_nicename(t);
|
||||
t->s_video = service_stream_create(t, -1, SCT_MPEG2VIDEO);
|
||||
t->s_audio = service_stream_create(t, -1, SCT_MPEG2AUDIO);
|
||||
pthread_mutex_unlock(&t->s_stream_mutex);
|
||||
|
||||
LIST_INSERT_HEAD(&va->va_services, t, s_group_link);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
v4l_adapter_add(const char *path, const char *displayname,
|
||||
const char *devicename, int file)
|
||||
{
|
||||
v4l_adapter_t *va;
|
||||
int i, r;
|
||||
|
||||
va = calloc(1, sizeof(v4l_adapter_t));
|
||||
|
||||
va->va_identifier = strdup(path);
|
||||
|
||||
r = strlen(va->va_identifier);
|
||||
for(i = 0; i < r; i++)
|
||||
if(!isalnum((int)va->va_identifier[i]))
|
||||
va->va_identifier[i] = '_';
|
||||
|
||||
va->va_displayname = strdup(displayname);
|
||||
va->va_path = path ? strdup(path) : NULL;
|
||||
va->va_devicename = devicename ? strdup(devicename) : NULL;
|
||||
va->va_file = file;
|
||||
|
||||
TAILQ_INSERT_TAIL(&v4l_adapters, va, va_global_link);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
v4l_adapter_check(const char *path, int fd)
|
||||
{
|
||||
int r, i;
|
||||
|
||||
char devicename[100];
|
||||
|
||||
struct v4l2_capability caps;
|
||||
|
||||
r = ioctl(fd, VIDIOC_QUERYCAP, &caps);
|
||||
|
||||
if(r) {
|
||||
tvhlog(LOG_WARNING, "v4l",
|
||||
"%s: Can not query capabilities, device skipped", path);
|
||||
return;
|
||||
}
|
||||
|
||||
tvhlog(LOG_INFO, "v4l", "%s: %s %s %s capabilities: 0x%08x",
|
||||
path, caps.driver, caps.card, caps.bus_info, caps.capabilities);
|
||||
|
||||
if(!(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
||||
tvhlog(LOG_WARNING, "v4l",
|
||||
"%s: Device is not a video capture device, device skipped", path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enum video standards */
|
||||
|
||||
for(i = 0;; i++) {
|
||||
struct v4l2_standard standard;
|
||||
memset(&standard, 0, sizeof(standard));
|
||||
standard.index = i;
|
||||
|
||||
if(ioctl(fd, VIDIOC_ENUMSTD, &standard))
|
||||
break;
|
||||
|
||||
tvhlog(LOG_INFO, "v4l",
|
||||
"%s: Standard #%d: %016llx %s, frameperiod: %d/%d, %d lines",
|
||||
path,
|
||||
standard.index,
|
||||
standard.id,
|
||||
standard.name,
|
||||
standard.frameperiod.numerator,
|
||||
standard.frameperiod.denominator,
|
||||
standard.framelines);
|
||||
}
|
||||
|
||||
/* Enum video inputs */
|
||||
|
||||
for(i = 0;; i++) {
|
||||
struct v4l2_input input;
|
||||
memset(&input, 0, sizeof(input));
|
||||
input.index = i;
|
||||
|
||||
if(ioctl(fd, VIDIOC_ENUMINPUT, &input))
|
||||
break;
|
||||
|
||||
const char *type;
|
||||
switch(input.type) {
|
||||
case V4L2_INPUT_TYPE_TUNER:
|
||||
type = "Tuner";
|
||||
break;
|
||||
case V4L2_INPUT_TYPE_CAMERA:
|
||||
type = "Camera";
|
||||
break;
|
||||
default:
|
||||
type = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
int f = input.status;
|
||||
|
||||
tvhlog(LOG_INFO, "v4l",
|
||||
"%s: Input #%d: %s (%s), audio:0x%x, tuner:%d, standard:%016llx, "
|
||||
"%s%s%s",
|
||||
path,
|
||||
input.index,
|
||||
input.name,
|
||||
type,
|
||||
input.audioset,
|
||||
input.tuner,
|
||||
input.std,
|
||||
f & V4L2_IN_ST_NO_POWER ? "[No power] " : "",
|
||||
f & V4L2_IN_ST_NO_SIGNAL ? "[No signal] " : "",
|
||||
f & V4L2_IN_ST_NO_COLOR ? "[No color] " : "");
|
||||
}
|
||||
|
||||
|
||||
int can_mpeg = 0;
|
||||
|
||||
/* Enum formats */
|
||||
for(i = 0;; i++) {
|
||||
|
||||
struct v4l2_fmtdesc fmtdesc;
|
||||
memset(&fmtdesc, 0, sizeof(fmtdesc));
|
||||
fmtdesc.index = i;
|
||||
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
||||
if(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
|
||||
break;
|
||||
|
||||
tvhlog(LOG_INFO, "v4l",
|
||||
"%s: Format #%d: %s [%.4s] %s",
|
||||
path,
|
||||
fmtdesc.index,
|
||||
fmtdesc.description,
|
||||
(char*)&fmtdesc.pixelformat,
|
||||
fmtdesc.flags & V4L2_FMT_FLAG_COMPRESSED ? "(compressed)" : "");
|
||||
|
||||
if(fmtdesc.pixelformat == V4L2_PIX_FMT_MPEG)
|
||||
can_mpeg = 1;
|
||||
}
|
||||
|
||||
|
||||
if(!(caps.capabilities & V4L2_CAP_TUNER)) {
|
||||
tvhlog(LOG_WARNING, "v4l",
|
||||
"%s: Device does not have a tuner, device skipped", path);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!can_mpeg) {
|
||||
tvhlog(LOG_WARNING, "v4l",
|
||||
"%s: Device lacks MPEG encoder, device skipped", path);
|
||||
return;
|
||||
}
|
||||
snprintf(devicename, sizeof(devicename), "%s %s %s",
|
||||
caps.card, caps.driver, caps.bus_info);
|
||||
|
||||
tvhlog(LOG_INFO, "v4l",
|
||||
"%s: Using adapter", devicename);
|
||||
|
||||
v4l_adapter_add(path, devicename, devicename, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
v4l_adapter_probe(const char *path)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = tvh_open(path, O_RDWR | O_NONBLOCK, 0);
|
||||
|
||||
if(fd == -1) {
|
||||
if(errno != ENOENT)
|
||||
tvhlog(LOG_ALERT, "v4l",
|
||||
"Unable to open %s -- %s", path, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
v4l_adapter_check(path, fd);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Save config for the given adapter
|
||||
*/
|
||||
static void
|
||||
v4l_adapter_save(v4l_adapter_t *va)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
htsmsg_add_str(m, "displayname", va->va_displayname);
|
||||
htsmsg_add_u32(m, "logging", va->va_logging);
|
||||
hts_settings_save(m, "v4ladapters/%s", va->va_identifier);
|
||||
htsmsg_destroy(m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
htsmsg_t *
|
||||
v4l_adapter_build_msg(v4l_adapter_t *va)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(m, "identifier", va->va_identifier);
|
||||
htsmsg_add_str(m, "name", va->va_displayname);
|
||||
htsmsg_add_str(m, "type", "v4l");
|
||||
|
||||
if(va->va_path)
|
||||
htsmsg_add_str(m, "path", va->va_path);
|
||||
|
||||
if(va->va_devicename)
|
||||
htsmsg_add_str(m, "devicename", va->va_devicename);
|
||||
|
||||
if(va->va_current_service != NULL) {
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof(buf), "%d Hz",
|
||||
va->va_current_service->s_v4l_frequency);
|
||||
htsmsg_add_str(m, "currentMux", buf);
|
||||
} else {
|
||||
htsmsg_add_str(m, "currentMux", "- inactive -");
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
v4l_adapter_notify(v4l_adapter_t *va)
|
||||
{
|
||||
notify_by_msg("tvAdapter", v4l_adapter_build_msg(va));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
v4l_adapter_t *
|
||||
v4l_adapter_find_by_identifier(const char *identifier)
|
||||
{
|
||||
v4l_adapter_t *va;
|
||||
|
||||
TAILQ_FOREACH(va, &v4l_adapters, va_global_link)
|
||||
if(!strcmp(identifier, va->va_identifier))
|
||||
return va;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
v4l_adapter_set_displayname(v4l_adapter_t *va, const char *name)
|
||||
{
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if(!strcmp(name, va->va_displayname))
|
||||
return;
|
||||
|
||||
tvhlog(LOG_NOTICE, "v4l", "Adapter \"%s\" renamed to \"%s\"",
|
||||
va->va_displayname, name);
|
||||
|
||||
tvh_str_set(&va->va_displayname, name);
|
||||
v4l_adapter_save(va);
|
||||
v4l_adapter_notify(va);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
v4l_adapter_set_logging(v4l_adapter_t *va, int on)
|
||||
{
|
||||
if(va->va_logging == on)
|
||||
return;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
tvhlog(LOG_NOTICE, "v4l", "Adapter \"%s\" detailed logging set to: %s",
|
||||
va->va_displayname, on ? "On" : "Off");
|
||||
|
||||
va->va_logging = on;
|
||||
v4l_adapter_save(va);
|
||||
v4l_adapter_notify(va);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
v4l_service_create_by_msg(v4l_adapter_t *va, htsmsg_t *c, const char *name)
|
||||
{
|
||||
const char *s;
|
||||
unsigned int u32;
|
||||
|
||||
service_t *t = v4l_service_find(va, name, 1);
|
||||
|
||||
if(t == NULL)
|
||||
return;
|
||||
|
||||
s = htsmsg_get_str(c, "channelname");
|
||||
if(htsmsg_get_u32(c, "mapped", &u32))
|
||||
u32 = 0;
|
||||
|
||||
if(!htsmsg_get_u32(c, "frequency", &u32))
|
||||
t->s_v4l_frequency = u32;
|
||||
|
||||
if(s && u32)
|
||||
service_map_channel(t, channel_find_by_name(s, 1, 0), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
v4l_service_load(v4l_adapter_t *va)
|
||||
{
|
||||
htsmsg_t *l, *c;
|
||||
htsmsg_field_t *f;
|
||||
|
||||
if((l = hts_settings_load("v4lservices/%s", va->va_identifier)) == NULL)
|
||||
return;
|
||||
|
||||
HTSMSG_FOREACH(f, l) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL)
|
||||
continue;
|
||||
|
||||
v4l_service_create_by_msg(va, c, f->hmf_name);
|
||||
}
|
||||
htsmsg_destroy(l);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
v4l_init(void)
|
||||
{
|
||||
htsmsg_t *l, *c;
|
||||
htsmsg_field_t *f;
|
||||
char buf[256];
|
||||
int i;
|
||||
v4l_adapter_t *va;
|
||||
|
||||
TAILQ_INIT(&v4l_adapters);
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
snprintf(buf, sizeof(buf), "/dev/video%d", i);
|
||||
v4l_adapter_probe(buf);
|
||||
}
|
||||
|
||||
l = hts_settings_load("v4ladapters");
|
||||
if(l != NULL) {
|
||||
HTSMSG_FOREACH(f, l) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL)
|
||||
continue;
|
||||
|
||||
if((va = v4l_adapter_find_by_identifier(f->hmf_name)) == NULL) {
|
||||
/* Not discovered by hardware, create it */
|
||||
|
||||
va = calloc(1, sizeof(v4l_adapter_t));
|
||||
va->va_identifier = strdup(f->hmf_name);
|
||||
va->va_path = NULL;
|
||||
va->va_devicename = NULL;
|
||||
}
|
||||
|
||||
tvh_str_update(&va->va_displayname, htsmsg_get_str(c, "displayname"));
|
||||
htsmsg_get_u32(c, "logging", &va->va_logging);
|
||||
}
|
||||
htsmsg_destroy(l);
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(va, &v4l_adapters, va_global_link)
|
||||
v4l_service_load(va);
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* TV Input - Linux analogue (v4lv2) interface
|
||||
* Copyright (C) 2007 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef V4L_H_
|
||||
#define V4L_H_
|
||||
|
||||
#define __user
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
LIST_HEAD(v4l_adapter_list, v4l_adapter);
|
||||
TAILQ_HEAD(v4l_adapter_queue, v4l_adapter);
|
||||
|
||||
|
||||
extern struct v4l_adapter_queue v4l_adapters;
|
||||
|
||||
typedef struct v4l_adapter {
|
||||
|
||||
TAILQ_ENTRY(v4l_adapter) va_global_link;
|
||||
|
||||
char *va_path;
|
||||
|
||||
char *va_identifier;
|
||||
|
||||
char *va_displayname;
|
||||
|
||||
char *va_devicename;
|
||||
|
||||
int va_file;
|
||||
|
||||
uint32_t va_logging;
|
||||
|
||||
// struct v4l2_capability va_caps;
|
||||
|
||||
struct service *va_current_service;
|
||||
|
||||
struct service_list va_services;
|
||||
int va_tally;
|
||||
|
||||
/** Receiver thread stuff */
|
||||
|
||||
int va_fd;
|
||||
|
||||
pthread_t va_thread;
|
||||
|
||||
int va_pipe[2];
|
||||
|
||||
/** Mpeg stream parsing */
|
||||
uint32_t va_startcode;
|
||||
int va_lenlock;
|
||||
|
||||
} v4l_adapter_t;
|
||||
|
||||
|
||||
v4l_adapter_t *v4l_adapter_find_by_identifier(const char *identifier);
|
||||
|
||||
void v4l_adapter_set_displayname(v4l_adapter_t *va, const char *name);
|
||||
|
||||
void v4l_adapter_set_logging(v4l_adapter_t *va, int on);
|
||||
|
||||
htsmsg_t *v4l_adapter_build_msg(v4l_adapter_t *va);
|
||||
|
||||
service_t *v4l_service_find(v4l_adapter_t *va, const char *id,
|
||||
int create);
|
||||
|
||||
void v4l_init(void);
|
||||
|
||||
#endif /* V4L_H */
|
|
@ -393,7 +393,6 @@ iptv_input_fd_started ( iptv_mux_t *im )
|
|||
void
|
||||
iptv_input_mux_started ( iptv_mux_t *im )
|
||||
{
|
||||
|
||||
/* Allocate input buffer */
|
||||
sbuf_init_fixed(&im->mm_iptv_buffer, IPTV_BUF_SIZE);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue