Added initial support for transcoding.

This commit is contained in:
John Törblom 2013-05-09 21:51:27 +02:00
parent 84c1c05d73
commit 60bdb16c9d
11 changed files with 1578 additions and 5 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

@ -137,6 +137,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

@ -46,7 +46,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>
@ -177,6 +179,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 */
@ -282,13 +288,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);
}
@ -1328,6 +1344,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);
@ -1640,6 +1682,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
*/
@ -1669,6 +1733,9 @@ struct {
{ "subscriptionSkip", htsp_method_skip, ACCESS_STREAMING},
{ "subscriptionSpeed", htsp_method_speed, ACCESS_STREAMING},
{ "subscriptionLive", htsp_method_live, 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},

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

@ -908,6 +908,8 @@ psi_caid2name(uint16_t caid)
*
*/
static struct strtab streamtypetab[] = {
{ "NONE", SCT_NONE },
{ "UNKNOWN", SCT_UNKNOWN },
{ "MPEG2VIDEO", SCT_MPEG2VIDEO },
{ "MPEG2AUDIO", SCT_MPEG2AUDIO },
{ "H264", SCT_H264 },
@ -920,7 +922,7 @@ static struct strtab streamtypetab[] = {
{ "MPEGTS", SCT_MPEGTS },
{ "TEXTSUB", SCT_TEXTSUB },
{ "EAC3", SCT_EAC3 },
{ "AAC", SCT_MP4A },
{ "AAC", SCT_MP4A },
};
@ -933,6 +935,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

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

@ -40,6 +40,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"
@ -548,6 +549,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
*/
@ -660,6 +702,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;
@ -689,6 +734,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;
@ -710,6 +763,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);