Sync with tvheadend/master and merge in changes.
This commit is contained in:
commit
5691e131a9
20 changed files with 1729 additions and 39 deletions
3
Makefile
3
Makefile
|
@ -189,7 +189,8 @@ SRCS-$(CONFIG_AVAHI) += src/avahi.c
|
|||
|
||||
# libav
|
||||
SRCS-$(CONFIG_LIBAV) += src/libav.c \
|
||||
src/muxer/muxer_libav.c
|
||||
src/muxer/muxer_libav.c \
|
||||
src/plumbing/transcoding.c \
|
||||
|
||||
# CWC
|
||||
SRCS-${CONFIG_CWC} += src/cwc.c \
|
||||
|
|
4
configure
vendored
4
configure
vendored
|
@ -142,6 +142,10 @@ if enabled_or_auto libav; then
|
|||
has_libav=false
|
||||
fi
|
||||
|
||||
if $has_libav && ! check_pkg libswscale ">=0.13.0"; then
|
||||
has_libav=false
|
||||
fi
|
||||
|
||||
if $has_libav; then
|
||||
enable libav
|
||||
elif enabled libav; then
|
||||
|
|
|
@ -893,13 +893,13 @@ dvb_nit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
tvhtrace("nit", "tableid 0x%02x", tableid);
|
||||
tvhlog_hexdump("nit", ptr, len);
|
||||
|
||||
/* Ignore other network */
|
||||
if(tableid != 0x40) return -1;
|
||||
|
||||
/* Check NID */
|
||||
if(tdmi->tdmi_adapter->tda_nitoid &&
|
||||
tdmi->tdmi_adapter->tda_nitoid != network_id)
|
||||
return -1;
|
||||
/* Specific NID requested */
|
||||
if(tdmi->tdmi_adapter->tda_nitoid) {
|
||||
if (tdmi->tdmi_adapter->tda_nitoid != network_id)
|
||||
return -1;
|
||||
} else if (tableid != 0x40) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Ignore non-current */
|
||||
if((ptr[2] & 1) == 0)
|
||||
|
|
15
src/epg.c
15
src/epg.c
|
@ -1396,12 +1396,16 @@ static void _epg_channel_timer_callback ( void *p )
|
|||
break;
|
||||
}
|
||||
|
||||
/* Change */
|
||||
if (cur != ch->ch_epg_now || nxt != ch->ch_epg_next)
|
||||
/* Change (update HTSP) */
|
||||
if (cur != ch->ch_epg_now || nxt != ch->ch_epg_next) {
|
||||
tvhlog(LOG_DEBUG, "epg", "now/next %u/%u set on %s",
|
||||
ch->ch_epg_now ? ch->ch_epg_now->id : 0,
|
||||
ch->ch_epg_next ? ch->ch_epg_next->id : 0,
|
||||
ch->ch_name);
|
||||
tvhlog(LOG_DEBUG, "epg", "inform HTSP of now event change on %s",
|
||||
ch->ch_name);
|
||||
htsp_channel_update_nownext(ch);
|
||||
}
|
||||
|
||||
/* re-arm */
|
||||
if ( next ) {
|
||||
|
@ -1410,13 +1414,6 @@ static void _epg_channel_timer_callback ( void *p )
|
|||
gtimer_arm_abs(&ch->ch_epg_timer, _epg_channel_timer_callback, ch, next);
|
||||
}
|
||||
|
||||
/* Update HTSP */
|
||||
if ( cur != ch->ch_epg_now ) {
|
||||
tvhlog(LOG_DEBUG, "epg", "inform HTSP of now event change on %s",
|
||||
ch->ch_name);
|
||||
htsp_channel_update_current(ch);
|
||||
}
|
||||
|
||||
/* Remove refs */
|
||||
if (cur) cur->putref(cur);
|
||||
if (nxt) nxt->putref(nxt);
|
||||
|
|
|
@ -48,7 +48,9 @@
|
|||
#if ENABLE_TIMESHIFT
|
||||
#include "timeshift.h"
|
||||
#endif
|
||||
|
||||
#if ENABLE_LIBAV
|
||||
#include "plumbing/transcoding.h"
|
||||
#endif
|
||||
#include <sys/statvfs.h>
|
||||
#include "settings.h"
|
||||
#include <sys/time.h>
|
||||
|
@ -59,7 +61,7 @@
|
|||
|
||||
static void *htsp_server, *htsp_server_2;
|
||||
|
||||
#define HTSP_PROTO_VERSION 10
|
||||
#define HTSP_PROTO_VERSION 11
|
||||
|
||||
#define HTSP_ASYNC_OFF 0x00
|
||||
#define HTSP_ASYNC_ON 0x01
|
||||
|
@ -179,6 +181,10 @@ typedef struct htsp_subscription {
|
|||
streaming_target_t *hs_tshift;
|
||||
#endif
|
||||
|
||||
#if ENABLE_LIBAV
|
||||
streaming_target_t *hs_transcoder;
|
||||
#endif
|
||||
|
||||
htsp_msg_q_t hs_q;
|
||||
|
||||
time_t hs_last_report; /* Last queue status report sent */
|
||||
|
@ -189,6 +195,10 @@ typedef struct htsp_subscription {
|
|||
|
||||
int hs_queue_depth;
|
||||
|
||||
#define NUM_FILTERED_STREAMS (32*16)
|
||||
|
||||
uint32_t hs_filtered_streams[16]; // one bit per stream
|
||||
|
||||
} htsp_subscription_t;
|
||||
|
||||
|
||||
|
@ -210,6 +220,31 @@ typedef struct htsp_file {
|
|||
* Support routines
|
||||
* *************************************************************************/
|
||||
|
||||
static void
|
||||
htsp_disable_stream(htsp_subscription_t *hs, unsigned int id)
|
||||
{
|
||||
if(id < NUM_FILTERED_STREAMS)
|
||||
hs->hs_filtered_streams[id / 32] |= 1 << (id & 31);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
htsp_enable_stream(htsp_subscription_t *hs, unsigned int id)
|
||||
{
|
||||
if(id < NUM_FILTERED_STREAMS)
|
||||
hs->hs_filtered_streams[id / 32] &= ~(1 << (id & 31));
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
htsp_is_stream_enabled(htsp_subscription_t *hs, unsigned int id)
|
||||
{
|
||||
if(id < NUM_FILTERED_STREAMS)
|
||||
return !(hs->hs_filtered_streams[id / 32] & (1 << (id & 31)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -284,13 +319,23 @@ htsp_subscription_destroy(htsp_connection_t *htsp, htsp_subscription_t *hs)
|
|||
{
|
||||
LIST_REMOVE(hs, hs_link);
|
||||
subscription_unsubscribe(hs->hs_s);
|
||||
|
||||
if(hs->hs_tsfix != NULL)
|
||||
tsfix_destroy(hs->hs_tsfix);
|
||||
|
||||
#if ENABLE_LIBAV
|
||||
if(hs->hs_transcoder != NULL)
|
||||
transcoder_destroy(hs->hs_transcoder);
|
||||
#endif
|
||||
|
||||
htsp_flush_queue(htsp, &hs->hs_q);
|
||||
|
||||
#if ENABLE_TIMESHIFT
|
||||
if(hs->hs_tshift)
|
||||
timeshift_destroy(hs->hs_tshift);
|
||||
#endif
|
||||
|
||||
|
||||
free(hs);
|
||||
}
|
||||
|
||||
|
@ -656,11 +701,16 @@ htsp_build_event
|
|||
htsmsg_add_str(out, "summary", str);
|
||||
} else if((str = epg_broadcast_get_summary(e, lang)))
|
||||
htsmsg_add_str(out, "description", str);
|
||||
if (e->serieslink)
|
||||
if (e->serieslink) {
|
||||
htsmsg_add_u32(out, "serieslinkId", e->serieslink->id);
|
||||
if (e->serieslink->uri)
|
||||
htsmsg_add_str(out, "serieslinkUri", e->serieslink->uri);
|
||||
}
|
||||
|
||||
if (ee) {
|
||||
htsmsg_add_u32(out, "episodeId", ee->id);
|
||||
if (ee->uri && strncasecmp(ee->uri,"tvh://",6)) /* tvh:// uris are internal */
|
||||
htsmsg_add_str(out, "episodeUri", ee->uri);
|
||||
if (ee->brand)
|
||||
htsmsg_add_u32(out, "brandId", ee->brand->id);
|
||||
if (ee->season)
|
||||
|
@ -1331,6 +1381,32 @@ htsp_method_subscribe(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
normts = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLE_LIBAV
|
||||
if (transcoding_enabled) {
|
||||
transcoder_props_t props;
|
||||
|
||||
props.tp_vcodec = streaming_component_txt2type(htsmsg_get_str(in, "videoCodec"));
|
||||
props.tp_acodec = streaming_component_txt2type(htsmsg_get_str(in, "audioCodec"));
|
||||
props.tp_scodec = streaming_component_txt2type(htsmsg_get_str(in, "subtitleCodec"));
|
||||
|
||||
props.tp_resolution = htsmsg_get_u32_or_default(in, "maxResolution", 0);
|
||||
props.tp_channels = htsmsg_get_u32_or_default(in, "channels", 0);
|
||||
props.tp_bandwidth = htsmsg_get_u32_or_default(in, "bandwidth", 0);
|
||||
|
||||
if ((str = htsmsg_get_str(in, "language")))
|
||||
strncpy(props.tp_language, str, 3);
|
||||
|
||||
if(props.tp_vcodec != SCT_UNKNOWN ||
|
||||
props.tp_acodec != SCT_UNKNOWN ||
|
||||
props.tp_scodec != SCT_UNKNOWN) {
|
||||
st = hs->hs_transcoder = transcoder_create(st);
|
||||
transcoder_set_properties(st, &props);
|
||||
normts = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(normts)
|
||||
st = hs->hs_tsfix = tsfix_create(st);
|
||||
|
||||
|
@ -1493,6 +1569,44 @@ htsp_method_live(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change filters for a subscription
|
||||
*/
|
||||
static htsmsg_t *
|
||||
htsp_method_filter_stream(htsp_connection_t *htsp, htsmsg_t *in)
|
||||
{
|
||||
htsp_subscription_t *hs;
|
||||
uint32_t sid;
|
||||
htsmsg_t *l;
|
||||
if(htsmsg_get_u32(in, "subscriptionId", &sid))
|
||||
return htsp_error("Missing argument 'subscriptionId'");
|
||||
|
||||
LIST_FOREACH(hs, &htsp->htsp_subscriptions, hs_link)
|
||||
if(hs->hs_sid == sid)
|
||||
break;
|
||||
|
||||
if(hs == NULL)
|
||||
return htsp_error("Requested subscription does not exist");
|
||||
|
||||
if((l = htsmsg_get_list(in, "enable")) != NULL) {
|
||||
htsmsg_field_t *f;
|
||||
HTSMSG_FOREACH(f, l) {
|
||||
if(f->hmf_type == HMF_S64)
|
||||
htsp_enable_stream(hs, f->hmf_s64);
|
||||
}
|
||||
}
|
||||
|
||||
if((l = htsmsg_get_list(in, "disable")) != NULL) {
|
||||
htsmsg_field_t *f;
|
||||
HTSMSG_FOREACH(f, l) {
|
||||
if(f->hmf_type == HMF_S64)
|
||||
htsp_disable_stream(hs, f->hmf_s64);
|
||||
}
|
||||
}
|
||||
return htsmsg_create_map();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open file
|
||||
*/
|
||||
|
@ -1643,6 +1757,28 @@ htsp_method_file_seek(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
return rep;
|
||||
}
|
||||
|
||||
|
||||
#if ENABLE_LIBAV
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
htsp_method_getCodecs(htsp_connection_t *htsp, htsmsg_t *in)
|
||||
{
|
||||
htsmsg_t *out, *l;
|
||||
|
||||
l = htsmsg_create_list();
|
||||
transcoder_get_capabilities(l);
|
||||
|
||||
out = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_msg(out, "encoders", l);
|
||||
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* HTSP methods
|
||||
*/
|
||||
|
@ -1672,6 +1808,10 @@ struct {
|
|||
{ "subscriptionSkip", htsp_method_skip, ACCESS_STREAMING},
|
||||
{ "subscriptionSpeed", htsp_method_speed, ACCESS_STREAMING},
|
||||
{ "subscriptionLive", htsp_method_live, ACCESS_STREAMING},
|
||||
{ "subscriptionFilterStream", htsp_method_filter_stream, ACCESS_STREAMING},
|
||||
#if ENABLE_LIBAV
|
||||
{ "getCodecs", htsp_method_getCodecs, ACCESS_STREAMING},
|
||||
#endif
|
||||
{ "fileOpen", htsp_method_file_open, ACCESS_RECORDER},
|
||||
{ "fileRead", htsp_method_file_read, ACCESS_RECORDER},
|
||||
{ "fileClose", htsp_method_file_close, ACCESS_RECORDER},
|
||||
|
@ -2029,13 +2169,13 @@ htsp_async_send(htsmsg_t *m, int mode)
|
|||
|
||||
|
||||
/**
|
||||
* EPG subsystem calls this function when the current event
|
||||
* EPG subsystem calls this function when the current/next event
|
||||
* changes for a channel, e may be NULL if there is no current event.
|
||||
*
|
||||
* global_lock is held
|
||||
*/
|
||||
void
|
||||
htsp_channel_update_current(channel_t *ch)
|
||||
htsp_channel_update_nownext(channel_t *ch)
|
||||
{
|
||||
epg_broadcast_t *now, *next;
|
||||
htsmsg_t *m;
|
||||
|
@ -2216,6 +2356,11 @@ htsp_stream_deliver(htsp_subscription_t *hs, th_pkt_t *pkt)
|
|||
int64_t ts;
|
||||
int qlen = hs->hs_q.hmq_payload;
|
||||
|
||||
if(!htsp_is_stream_enabled(hs, pkt->pkt_componentindex)) {
|
||||
pkt_ref_dec(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
if((qlen > hs->hs_queue_depth && pkt->pkt_frametype == PKT_B_FRAME) ||
|
||||
(qlen > hs->hs_queue_depth * 2 && pkt->pkt_frametype == PKT_P_FRAME) ||
|
||||
(qlen > hs->hs_queue_depth * 3)) {
|
||||
|
@ -2357,6 +2502,7 @@ htsp_subscription_start(htsp_subscription_t *hs, const streaming_start_t *ss)
|
|||
|
||||
if (SCT_ISAUDIO(ssc->ssc_type))
|
||||
{
|
||||
htsmsg_add_u32(c, "audio_type", ssc->ssc_audio_type);
|
||||
if (ssc->ssc_channels)
|
||||
htsmsg_add_u32(c, "channels", ssc->ssc_channels);
|
||||
if (ssc->ssc_sri)
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
void htsp_init(const char *bindaddr);
|
||||
|
||||
void htsp_channel_update_current(channel_t *ch);
|
||||
void htsp_channel_update_nownext(channel_t *ch);
|
||||
|
||||
void htsp_channel_add(channel_t *ch);
|
||||
void htsp_channel_update(channel_t *ch);
|
||||
|
|
49
src/libav.c
49
src/libav.c
|
@ -91,6 +91,55 @@ streaming_component_type2codec_id(streaming_component_type_t type)
|
|||
return codec_id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translate a libavcodec id to a component type
|
||||
*/
|
||||
streaming_component_type_t
|
||||
codec_id2streaming_component_type(enum CodecID id)
|
||||
{
|
||||
streaming_component_type_t type = CODEC_ID_NONE;
|
||||
|
||||
switch(id) {
|
||||
case CODEC_ID_H264:
|
||||
type = SCT_H264;
|
||||
break;
|
||||
case CODEC_ID_MPEG2VIDEO:
|
||||
type = SCT_MPEG2VIDEO;
|
||||
break;
|
||||
case CODEC_ID_AC3:
|
||||
type = SCT_AC3;
|
||||
break;
|
||||
case CODEC_ID_EAC3:
|
||||
type = SCT_EAC3;
|
||||
break;
|
||||
case CODEC_ID_AAC:
|
||||
type = SCT_AAC;
|
||||
break;
|
||||
case CODEC_ID_MP2:
|
||||
type = SCT_MPEG2AUDIO;
|
||||
break;
|
||||
case CODEC_ID_DVB_SUBTITLE:
|
||||
type = SCT_DVBSUB;
|
||||
break;
|
||||
case CODEC_ID_TEXT:
|
||||
type = SCT_TEXTSUB;
|
||||
break;
|
||||
case CODEC_ID_DVB_TELETEXT:
|
||||
type = SCT_TELETEXT;
|
||||
break;
|
||||
case CODEC_ID_NONE:
|
||||
type = SCT_NONE;
|
||||
break;
|
||||
default:
|
||||
type = SCT_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "tvheadend.h"
|
||||
|
||||
enum CodecID streaming_component_type2codec_id(streaming_component_type_t type);
|
||||
|
||||
streaming_component_type_t codec_id2streaming_component_type(enum CodecID id);
|
||||
void libav_init(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#include "timeshift.h"
|
||||
#if ENABLE_LIBAV
|
||||
#include "libav.h"
|
||||
#include "plumbing/transcoding.h"
|
||||
#endif
|
||||
|
||||
/* Command line option struct */
|
||||
|
@ -126,6 +127,9 @@ const tvh_caps_t tvheadend_capabilities[] = {
|
|||
#if ENABLE_LINUXDVB
|
||||
{ "linuxdvb", NULL },
|
||||
#endif
|
||||
#if ENABLE_LIBAV
|
||||
{ "transcoding", &transcoding_enabled },
|
||||
#endif
|
||||
#if ENABLE_IMAGECACHE
|
||||
{ "imagecache", &imagecache_enabled },
|
||||
#endif
|
||||
|
|
1336
src/plumbing/transcoding.c
Normal file
1336
src/plumbing/transcoding.c
Normal file
File diff suppressed because it is too large
Load diff
42
src/plumbing/transcoding.h
Normal file
42
src/plumbing/transcoding.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Transcoding
|
||||
* Copyright (C) 2013 John Törnblom
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "htsmsg.h"
|
||||
|
||||
typedef struct transcoder_prop {
|
||||
streaming_component_type_t tp_vcodec;
|
||||
streaming_component_type_t tp_acodec;
|
||||
streaming_component_type_t tp_scodec;
|
||||
|
||||
int8_t tp_channels;
|
||||
int32_t tp_bandwidth;
|
||||
char tp_language[4];
|
||||
int32_t tp_resolution;
|
||||
} transcoder_props_t;
|
||||
|
||||
extern uint32_t transcoding_enabled;
|
||||
|
||||
streaming_target_t *transcoder_create (streaming_target_t *output);
|
||||
void transcoder_destroy(streaming_target_t *tr);
|
||||
|
||||
void transcoder_get_capabilities(htsmsg_t *array);
|
||||
void transcoder_set_properties (streaming_target_t *tr,
|
||||
transcoder_props_t *prop);
|
||||
|
64
src/psi.c
64
src/psi.c
|
@ -172,16 +172,17 @@ psi_build_pat(service_t *t, uint8_t *buf, int maxlen, int pmtpid)
|
|||
#define PMT_UPDATE_PCR 0x1
|
||||
#define PMT_UPDATE_NEW_STREAM 0x2
|
||||
#define PMT_UPDATE_LANGUAGE 0x4
|
||||
#define PMT_UPDATE_FRAME_DURATION 0x8
|
||||
#define PMT_UPDATE_COMPOSITION_ID 0x10
|
||||
#define PMT_UPDATE_ANCILLARY_ID 0x20
|
||||
#define PMT_UPDATE_STREAM_DELETED 0x40
|
||||
#define PMT_UPDATE_NEW_CA_STREAM 0x80
|
||||
#define PMT_UPDATE_NEW_CAID 0x100
|
||||
#define PMT_UPDATE_CA_PROVIDER_CHANGE 0x200
|
||||
#define PMT_UPDATE_PARENT_PID 0x400
|
||||
#define PMT_UPDATE_CAID_DELETED 0x800
|
||||
#define PMT_REORDERED 0x1000
|
||||
#define PMT_UPDATE_AUDIO_TYPE 0x8
|
||||
#define PMT_UPDATE_FRAME_DURATION 0x10
|
||||
#define PMT_UPDATE_COMPOSITION_ID 0x20
|
||||
#define PMT_UPDATE_ANCILLARY_ID 0x40
|
||||
#define PMT_UPDATE_STREAM_DELETED 0x80
|
||||
#define PMT_UPDATE_NEW_CA_STREAM 0x100
|
||||
#define PMT_UPDATE_NEW_CAID 0x200
|
||||
#define PMT_UPDATE_CA_PROVIDER_CHANGE 0x400
|
||||
#define PMT_UPDATE_PARENT_PID 0x800
|
||||
#define PMT_UPDATE_CAID_DELETED 0x1000
|
||||
#define PMT_REORDERED 0x2000
|
||||
|
||||
/**
|
||||
* Add a CA descriptor
|
||||
|
@ -397,6 +398,7 @@ psi_parse_pmt(service_t *t, const uint8_t *ptr, int len, int chksvcid,
|
|||
int position = 0;
|
||||
int tt_position = 1000;
|
||||
const char *lang = NULL;
|
||||
uint8_t audio_type = 0;
|
||||
|
||||
caid_t *c, *cn;
|
||||
|
||||
|
@ -529,6 +531,7 @@ psi_parse_pmt(service_t *t, const uint8_t *ptr, int len, int chksvcid,
|
|||
|
||||
case DVB_DESC_LANGUAGE:
|
||||
lang = lang_code_get2((const char*)ptr, 3);
|
||||
audio_type = ptr[3];
|
||||
break;
|
||||
|
||||
case DVB_DESC_TELETEXT:
|
||||
|
@ -601,6 +604,11 @@ psi_parse_pmt(service_t *t, const uint8_t *ptr, int len, int chksvcid,
|
|||
memcpy(st->es_lang, lang, 4);
|
||||
}
|
||||
|
||||
if(st->es_audio_type != audio_type) {
|
||||
update |= PMT_UPDATE_AUDIO_TYPE;
|
||||
st->es_audio_type = audio_type;
|
||||
}
|
||||
|
||||
if(composition_id != -1 && st->es_composition_id != composition_id) {
|
||||
st->es_composition_id = composition_id;
|
||||
update |= PMT_UPDATE_COMPOSITION_ID;
|
||||
|
@ -756,7 +764,7 @@ psi_build_pmt(const streaming_start_t *ss, uint8_t *buf0, int maxlen,
|
|||
buf[0] = DVB_DESC_LANGUAGE;
|
||||
buf[1] = 4;
|
||||
memcpy(&buf[2],ssc->ssc_lang,3);
|
||||
buf[5] = 0; /* Main audio */
|
||||
buf[5] = ssc->ssc_audio_type;
|
||||
dlen = 6;
|
||||
break;
|
||||
case SCT_DVBSUB:
|
||||
|
@ -904,10 +912,26 @@ psi_caid2name(uint16_t caid)
|
|||
return buf;
|
||||
}
|
||||
|
||||
const char *
|
||||
psi_audio_type2desc(uint8_t audio_type)
|
||||
{
|
||||
/* From ISO 13818-1 - ISO 639 language descriptor */
|
||||
switch(audio_type) {
|
||||
case 0: return ""; /* "Undefined" in the standard, but used for normal audio */
|
||||
case 1: return "Clean effects";
|
||||
case 2: return "Hearing impaired";
|
||||
case 3: return "Visually impaired commentary";
|
||||
}
|
||||
|
||||
return "Reserved";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static struct strtab streamtypetab[] = {
|
||||
{ "NONE", SCT_NONE },
|
||||
{ "UNKNOWN", SCT_UNKNOWN },
|
||||
{ "MPEG2VIDEO", SCT_MPEG2VIDEO },
|
||||
{ "MPEG2AUDIO", SCT_MPEG2AUDIO },
|
||||
{ "H264", SCT_H264 },
|
||||
|
@ -920,7 +944,7 @@ static struct strtab streamtypetab[] = {
|
|||
{ "MPEGTS", SCT_MPEGTS },
|
||||
{ "TEXTSUB", SCT_TEXTSUB },
|
||||
{ "EAC3", SCT_EAC3 },
|
||||
{ "AAC", SCT_MP4A },
|
||||
{ "AAC", SCT_MP4A },
|
||||
};
|
||||
|
||||
|
||||
|
@ -933,6 +957,14 @@ streaming_component_type2txt(streaming_component_type_t s)
|
|||
return val2str(s, streamtypetab) ?: "INVALID";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
streaming_component_type_t
|
||||
streaming_component_txt2type(const char *str)
|
||||
{
|
||||
return str ? str2val(str, streamtypetab) : SCT_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store service settings into message
|
||||
|
@ -959,6 +991,9 @@ psi_save_service_settings(htsmsg_t *m, service_t *t)
|
|||
if(st->es_lang[0])
|
||||
htsmsg_add_str(sub, "language", st->es_lang);
|
||||
|
||||
if (SCT_ISAUDIO(st->es_type))
|
||||
htsmsg_add_u32(sub, "audio_type", st->es_audio_type);
|
||||
|
||||
if(st->es_type == SCT_CA) {
|
||||
|
||||
caid_t *c;
|
||||
|
@ -1109,6 +1144,11 @@ psi_load_service_settings(htsmsg_t *m, service_t *t)
|
|||
if((v = htsmsg_get_str(c, "language")) != NULL)
|
||||
strncpy(st->es_lang, lang_code_get(v), 3);
|
||||
|
||||
if (SCT_ISAUDIO(type)) {
|
||||
if(!htsmsg_get_u32(c, "audio_type", &u32))
|
||||
st->es_audio_type = u32;
|
||||
}
|
||||
|
||||
if(!htsmsg_get_u32(c, "position", &u32))
|
||||
st->es_position = u32;
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ int psi_build_pmt(const streaming_start_t *ss, uint8_t *buf, int maxlen,
|
|||
int version, int pcrpid);
|
||||
|
||||
const char *psi_caid2name(uint16_t caid);
|
||||
const char *psi_audio_type2desc(uint8_t audio_type);
|
||||
|
||||
void psi_load_service_settings(htsmsg_t *m, struct service *t);
|
||||
void psi_save_service_settings(htsmsg_t *m, struct service *t);
|
||||
|
|
|
@ -908,6 +908,7 @@ service_build_stream_start(service_t *t)
|
|||
ssc->ssc_type = st->es_type;
|
||||
|
||||
memcpy(ssc->ssc_lang, st->es_lang, 4);
|
||||
ssc->ssc_audio_type = st->es_audio_type;
|
||||
ssc->ssc_composition_id = st->es_composition_id;
|
||||
ssc->ssc_ancillary_id = st->es_ancillary_id;
|
||||
ssc->ssc_pid = st->es_pid;
|
||||
|
|
|
@ -82,6 +82,8 @@ typedef struct elementary_stream {
|
|||
uint16_t es_aspect_den;
|
||||
|
||||
char es_lang[4]; /* ISO 639 2B 3-letter language code */
|
||||
uint8_t es_audio_type; /* Audio type */
|
||||
|
||||
uint16_t es_composition_id;
|
||||
uint16_t es_ancillary_id;
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ typedef struct streaming_start_component {
|
|||
int ssc_index;
|
||||
int ssc_type;
|
||||
char ssc_lang[4];
|
||||
uint8_t ssc_audio_type;
|
||||
uint16_t ssc_composition_id;
|
||||
uint16_t ssc_ancillary_id;
|
||||
uint16_t ssc_pid;
|
||||
|
|
|
@ -184,6 +184,7 @@ int get_device_connection(const char *dev);
|
|||
* Stream component types
|
||||
*/
|
||||
typedef enum {
|
||||
SCT_NONE = -1,
|
||||
SCT_UNKNOWN = 0,
|
||||
SCT_MPEG2VIDEO = 1,
|
||||
SCT_MPEG2AUDIO,
|
||||
|
@ -423,7 +424,7 @@ typedef struct sbuf {
|
|||
} sbuf_t;
|
||||
|
||||
|
||||
|
||||
streaming_component_type_t streaming_component_txt2type(const char *str);
|
||||
const char *streaming_component_type2txt(streaming_component_type_t s);
|
||||
|
||||
static inline unsigned int tvh_strhash(const char *s, unsigned int mod)
|
||||
|
|
|
@ -1635,7 +1635,13 @@ extjs_servicedetails(http_connection_t *hc,
|
|||
case SCT_MP4A:
|
||||
case SCT_AAC:
|
||||
case SCT_MPEG2AUDIO:
|
||||
htsmsg_add_str(c, "details", st->es_lang);
|
||||
if (st->es_audio_type) {
|
||||
snprintf(buf, sizeof(buf), "%s (%s)", st->es_lang,
|
||||
psi_audio_type2desc(st->es_audio_type));
|
||||
htsmsg_add_str(c, "details", buf);
|
||||
} else {
|
||||
htsmsg_add_str(c, "details", st->es_lang);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCT_DVBSUB:
|
||||
|
|
|
@ -99,7 +99,7 @@ tvheadend.showTransportDetails = function(data) {
|
|||
win = new Ext.Window({
|
||||
title : 'Service details for ' + data.title,
|
||||
layout : 'fit',
|
||||
width : 400,
|
||||
width : 450,
|
||||
height : 400,
|
||||
plain : true,
|
||||
bodyStyle : 'padding: 5px',
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "psi.h"
|
||||
#include "plumbing/tsfix.h"
|
||||
#include "plumbing/globalheaders.h"
|
||||
#include "plumbing/transcoding.h"
|
||||
#include "epg.h"
|
||||
#include "muxer.h"
|
||||
#include "dvb/dvb.h"
|
||||
|
@ -555,6 +556,47 @@ page_http_playlist(http_connection_t *hc, const char *remain, void *opaque)
|
|||
}
|
||||
|
||||
|
||||
#if ENABLE_LIBAV
|
||||
static int
|
||||
http_get_transcoder_properties(struct http_arg_list *args,
|
||||
transcoder_props_t *props)
|
||||
{
|
||||
int transcode;
|
||||
const char *s;
|
||||
|
||||
memset(props, 0, sizeof(transcoder_props_t));
|
||||
|
||||
if ((s = http_arg_get(args, "transcode")))
|
||||
transcode = atoi(s);
|
||||
else
|
||||
transcode = 0;
|
||||
|
||||
if ((s = http_arg_get(args, "resolution")))
|
||||
props->tp_resolution = atoi(s);
|
||||
|
||||
if ((s = http_arg_get(args, "channels")))
|
||||
props->tp_channels = atoi(s);
|
||||
|
||||
if ((s = http_arg_get(args, "bandwidth")))
|
||||
props->tp_bandwidth = atoi(s);
|
||||
|
||||
if ((s = http_arg_get(args, "language")))
|
||||
strncpy(props->tp_language, s, 3);
|
||||
|
||||
if ((s = http_arg_get(args, "vcodec")))
|
||||
props->tp_vcodec = streaming_component_txt2type(s);
|
||||
|
||||
if ((s = http_arg_get(args, "acodec")))
|
||||
props->tp_acodec = streaming_component_txt2type(s);
|
||||
|
||||
if ((s = http_arg_get(args, "scodec")))
|
||||
props->tp_scodec = streaming_component_txt2type(s);
|
||||
|
||||
return transcode && transcoding_enabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Subscribes to a service and starts the streaming loop
|
||||
*/
|
||||
|
@ -667,6 +709,9 @@ http_stream_channel(http_connection_t *hc, channel_t *ch)
|
|||
streaming_target_t *gh;
|
||||
streaming_target_t *tsfix;
|
||||
streaming_target_t *st;
|
||||
#if ENABLE_LIBAV
|
||||
streaming_target_t *tr = NULL;
|
||||
#endif
|
||||
dvr_config_t *cfg;
|
||||
int priority = 100;
|
||||
int flags;
|
||||
|
@ -696,6 +741,14 @@ http_stream_channel(http_connection_t *hc, channel_t *ch)
|
|||
} else {
|
||||
streaming_queue_init2(&sq, 0, qsize);
|
||||
gh = globalheaders_create(&sq.sq_st);
|
||||
#if ENABLE_LIBAV
|
||||
transcoder_props_t props;
|
||||
if(http_get_transcoder_properties(&hc->hc_req_args, &props)) {
|
||||
tr = transcoder_create(gh);
|
||||
transcoder_set_properties(tr, &props);
|
||||
tsfix = tsfix_create(tr);
|
||||
} else
|
||||
#endif
|
||||
tsfix = tsfix_create(gh);
|
||||
st = tsfix;
|
||||
flags = 0;
|
||||
|
@ -717,6 +770,12 @@ http_stream_channel(http_connection_t *hc, channel_t *ch)
|
|||
|
||||
if(gh)
|
||||
globalheaders_destroy(gh);
|
||||
|
||||
#if ENABLE_LIBAV
|
||||
if(tr)
|
||||
transcoder_destroy(tr);
|
||||
#endif
|
||||
|
||||
if(tsfix)
|
||||
tsfix_destroy(tsfix);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue