Sync with tvheadend/master and merge in changes.

This commit is contained in:
Bernhard Froehlich 2013-05-24 19:03:40 +02:00
commit 5691e131a9
20 changed files with 1729 additions and 39 deletions

View file

@ -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
View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -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)

View file

@ -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);

View file

@ -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;
}
/**
*
*/

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View 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);

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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)

View file

@ -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:

View file

@ -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',

View file

@ -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);