You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
7.0 KiB

/*****************************************************************************
* cast.cpp: Chromecast sout module for vlc
*****************************************************************************
* Copyright © 2014-2015 VideoLAN
*
* Authors: Adrien Maglo <magsoft@videolan.org>
* Jean-Baptiste Kempf <jb@videolan.org>
* Steve Lhomme <robux4@videolabs.io>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "chromecast.h"
#include <vlc_sout.h>
#include <cassert>
struct sout_stream_sys_t
{
sout_stream_sys_t(intf_sys_t *intf, sout_stream_t *sout, bool has_video)
: p_out(sout)
, p_intf(intf)
, b_has_video(has_video)
{
assert(p_intf != NULL);
}
~sout_stream_sys_t()
{
sout_StreamChainDelete(p_out, p_out);
}
sout_stream_t * const p_out;
intf_sys_t * const p_intf;
const bool b_has_video;
};
#define SOUT_CFG_PREFIX "sout-chromecast-"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Open(vlc_object_t *);
static void Close(vlc_object_t *);
static const char *const ppsz_sout_options[] = {
"http-port", "mux", "mime", "video", NULL
};
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#define HTTP_PORT_TEXT N_("HTTP port")
#define HTTP_PORT_LONGTEXT N_("This sets the HTTP port of the server " \
"used to stream the media to the Chromecast.")
#define HAS_VIDEO_TEXT N_("Video")
#define HAS_VIDEO_LONGTEXT N_("The Chromecast receiver can receive video.")
#define MUX_TEXT N_("Muxer")
#define MUX_LONGTEXT N_("This sets the muxer used to stream to the Chromecast.")
#define MIME_TEXT N_("MIME content type")
#define MIME_LONGTEXT N_("This sets the media MIME content type sent to the Chromecast.")
vlc_module_begin ()
set_shortname(N_("Chromecast"))
set_description(N_("Chromecast stream output"))
set_capability("sout stream", 0)
add_shortcut("chromecast")
set_category(CAT_SOUT)
set_subcategory(SUBCAT_SOUT_STREAM)
set_callbacks(Open, Close)
add_integer(SOUT_CFG_PREFIX "http-port", HTTP_PORT, HTTP_PORT_TEXT, HTTP_PORT_LONGTEXT, false)
add_bool(SOUT_CFG_PREFIX "video", true, HAS_VIDEO_TEXT, HAS_VIDEO_LONGTEXT, false)
add_string(SOUT_CFG_PREFIX "mux", "mp4stream", MUX_TEXT, MUX_LONGTEXT, false)
add_string(SOUT_CFG_PREFIX "mime", "video/mp4", MIME_TEXT, MIME_LONGTEXT, false)
vlc_module_end ()
/*****************************************************************************
* Sout callbacks
*****************************************************************************/
static sout_stream_id_sys_t *Add(sout_stream_t *p_stream, const es_format_t *p_fmt)
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
if (!p_sys->b_has_video)
{
if (p_fmt->i_cat != AUDIO_ES)
return NULL;
}
return sout_StreamIdAdd(p_sys->p_out, p_fmt);
}
static void Del(sout_stream_t *p_stream, sout_stream_id_sys_t *id)
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
sout_StreamIdDel(p_sys->p_out, id);
}
static int Send(sout_stream_t *p_stream, sout_stream_id_sys_t *id,
block_t *p_buffer)
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
return sout_StreamIdSend(p_sys->p_out, id, p_buffer);
}
static void Flush( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
sout_StreamFlush( p_sys->p_out, id );
}
static int Control(sout_stream_t *p_stream, int i_query, va_list args)
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
if ( !p_sys->p_out->pf_control )
return VLC_EGENERIC;
return p_sys->p_out->pf_control( p_sys->p_out, i_query, args );
}
/*****************************************************************************
* Open: connect to the Chromecast and initialize the sout
*****************************************************************************/
static int Open(vlc_object_t *p_this)
{
sout_stream_t *p_stream = reinterpret_cast<sout_stream_t*>(p_this);
sout_stream_sys_t *p_sys = NULL;
intf_sys_t *p_intf = NULL;
char *psz_mux = NULL;
char *psz_var_mime = NULL;
sout_stream_t *p_sout = NULL;
bool b_has_video = true;
std::stringstream ss;
config_ChainParse(p_stream, SOUT_CFG_PREFIX, ppsz_sout_options, p_stream->p_cfg);
psz_mux = var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX "mux");
if (psz_mux == NULL)
{
goto error;
}
psz_var_mime = var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX "mime");
if (psz_var_mime == NULL)
goto error;
ss << "http{dst=:" << var_InheritInteger(p_stream, SOUT_CFG_PREFIX "http-port") << "/stream"
<< ",mux=" << psz_mux
<< ",access=http{mime=" << psz_var_mime << "}}";
p_sout = sout_StreamChainNew( p_stream->p_sout, ss.str().c_str(), NULL, NULL);
if (p_sout == NULL) {
msg_Dbg(p_stream, "could not create sout chain:%s", ss.str().c_str());
goto error;
}
b_has_video = var_GetBool(p_stream, SOUT_CFG_PREFIX "video");
p_sys = new(std::nothrow) sout_stream_sys_t(p_intf, p_sout, b_has_video);
if (unlikely(p_sys == NULL))
goto error;
// Set the sout callbacks.
p_stream->pf_add = Add;
p_stream->pf_del = Del;
p_stream->pf_send = Send;
p_stream->pf_flush = Flush;
p_stream->pf_control = Control;
p_stream->p_sys = p_sys;
free(psz_mux);
free(psz_var_mime);
return VLC_SUCCESS;
error:
sout_StreamChainDelete(p_sout, p_sout);
free(psz_mux);
free(psz_var_mime);
delete p_sys;
return VLC_EGENERIC;
}
/*****************************************************************************
* Close: destroy interface
*****************************************************************************/
static void Close(vlc_object_t *p_this)
{
sout_stream_t *p_stream = reinterpret_cast<sout_stream_t*>(p_this);
delete p_stream->p_sys;
}