1 diff --git a/include/metacube2.h b/include/metacube2.h
5 +++ b/include/metacube2.h
11 + * Definitions for the Metacube2 protocol, used to communicate with Cubemap.
13 + * Note: This file is meant to compile as both C and C++, for easier inclusion
14 + * in other projects.
19 +#define METACUBE2_SYNC "cube!map" /* 8 bytes long. */
20 +#define METACUBE_FLAGS_HEADER 0x1
21 +#define METACUBE_FLAGS_NOT_SUITABLE_FOR_STREAM_START 0x2
23 +struct metacube2_block_header {
24 + char sync[8]; /* METACUBE2_SYNC */
25 + uint32_t size; /* Network byte order. Does not include header. */
26 + uint16_t flags; /* Network byte order. METACUBE_FLAGS_*. */
27 + uint16_t csum; /* Network byte order. CRC16 of size and flags. */
30 +/* This code is based on code generated by pycrc. */
31 +uint16_t metacube2_compute_crc(const struct metacube2_block_header *hdr);
33 +#endif /* !defined(_METACUBE_H) */
34 diff --git a/include/vlc_httpd.h b/include/vlc_httpd.h
35 index 9eb0b15..8eacf68 100644
36 --- a/include/vlc_httpd.h
37 +++ b/include/vlc_httpd.h
38 @@ -135,7 +135,7 @@ VLC_API void httpd_RedirectDelete( httpd_redirect_t * );
41 typedef struct httpd_stream_t httpd_stream_t;
42 -VLC_API httpd_stream_t * httpd_StreamNew( httpd_host_t *, const char *psz_url, const char *psz_mime, const char *psz_user, const char *psz_password ) VLC_USED;
43 +VLC_API httpd_stream_t * httpd_StreamNew( httpd_host_t *, const char *psz_url, const char *psz_mime, const char *psz_user, const char *psz_password, bool b_metacube ) VLC_USED;
44 VLC_API void httpd_StreamDelete( httpd_stream_t * );
45 VLC_API int httpd_StreamHeader( httpd_stream_t *, uint8_t *p_data, int i_data );
46 VLC_API int httpd_StreamSend( httpd_stream_t *, const block_t *p_block );
47 diff --git a/modules/access_output/http.c b/modules/access_output/http.c
48 index bf75130..e608f8d 100644
49 --- a/modules/access_output/http.c
50 +++ b/modules/access_output/http.c
51 @@ -57,6 +57,9 @@ static void Close( vlc_object_t * );
52 #define MIME_TEXT N_("Mime")
53 #define MIME_LONGTEXT N_("MIME returned by the server (autodetected " \
54 "if not specified)." )
55 +#define METACUBE_TEXT N_("Metacube")
56 +#define METACUBE_LONGTEXT N_("Use the Metacube protocol. Needed for streaming " \
57 + "to the Cubemap reflector.")
61 @@ -72,6 +75,8 @@ vlc_module_begin ()
62 PASS_TEXT, PASS_LONGTEXT, true )
63 add_string( SOUT_CFG_PREFIX "mime", "",
64 MIME_TEXT, MIME_LONGTEXT, true )
65 + add_bool( SOUT_CFG_PREFIX "metacube", false,
66 + METACUBE_TEXT, METACUBE_LONGTEXT, true )
67 set_callbacks( Open, Close )
70 @@ -80,7 +85,7 @@ vlc_module_end ()
72 *****************************************************************************/
73 static const char *const ppsz_sout_options[] = {
74 - "user", "pwd", "mime", NULL
75 + "user", "pwd", "mime", "metacube", NULL
78 static ssize_t Write( sout_access_out_t *, block_t * );
79 @@ -114,6 +119,8 @@ static int Open( vlc_object_t *p_this )
85 if( !( p_sys = p_access->p_sys =
86 malloc( sizeof( sout_access_out_sys_t ) ) ) )
88 @@ -189,9 +196,11 @@ static int Open( vlc_object_t *p_this )
89 psz_mime = var_GetNonEmptyString( p_access, SOUT_CFG_PREFIX "mime" );
92 + b_metacube = var_GetBool( p_access, SOUT_CFG_PREFIX "metacube" );
94 p_sys->p_httpd_stream =
95 httpd_StreamNew( p_sys->p_httpd_host, path, psz_mime,
96 - psz_user, psz_pwd );
97 + psz_user, psz_pwd, b_metacube );
101 diff --git a/src/Makefile.am b/src/Makefile.am
102 index a7f42ef..18ffaa0 100644
103 --- a/src/Makefile.am
104 +++ b/src/Makefile.am
105 @@ -480,6 +480,7 @@ SOURCES_libvlc_common = \
107 SOURCES_libvlc_httpd = \
109 + network/metacube2.c \
112 SOURCES_libvlc_sout = \
113 diff --git a/src/network/httpd.c b/src/network/httpd.c
114 index ff7e653..b8f6768 100644
115 --- a/src/network/httpd.c
116 +++ b/src/network/httpd.c
119 #include <vlc_mime.h>
120 #include <vlc_block.h>
121 +#include <metacube2.h>
122 #include "../libvlc.h"
125 @@ -630,6 +631,7 @@ struct httpd_stream_t
131 /* Header to send as first packet */
133 @@ -739,9 +741,25 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
134 /* Send the header */
135 if( stream->i_header > 0 )
137 - answer->i_body = stream->i_header;
138 - answer->p_body = xmalloc( stream->i_header );
139 - memcpy( answer->p_body, stream->p_header, stream->i_header );
140 + if ( stream->b_metacube )
142 + struct metacube2_block_header hdr;
143 + memcpy( hdr.sync, METACUBE2_SYNC, sizeof(METACUBE2_SYNC) );
144 + hdr.size = htonl( stream->i_header );
145 + hdr.flags = htons( METACUBE_FLAGS_HEADER );
146 + hdr.csum = htons( metacube2_compute_crc( &hdr ) );
148 + answer->i_body = stream->i_header + sizeof( hdr );
149 + answer->p_body = xmalloc( answer->i_body );
150 + memcpy( answer->p_body, &hdr, sizeof( hdr ) );
151 + memcpy( answer->p_body + sizeof( hdr ), stream->p_header, stream->i_header );
155 + answer->i_body = stream->i_header;
156 + answer->p_body = xmalloc( stream->i_header );
157 + memcpy( answer->p_body, stream->p_header, stream->i_header );
160 answer->i_body_offset = stream->i_buffer_last_pos;
161 if( stream->b_has_keyframes )
162 @@ -789,13 +807,16 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
163 httpd_MsgAdd( answer, "Content-type", "%s", stream->psz_mime );
165 httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
166 + if( stream->b_metacube )
167 + httpd_MsgAdd( answer, "Content-encoding", "metacube");
172 httpd_stream_t *httpd_StreamNew( httpd_host_t *host,
173 const char *psz_url, const char *psz_mime,
174 - const char *psz_user, const char *psz_password )
175 + const char *psz_user, const char *psz_password,
178 httpd_stream_t *stream = xmalloc( sizeof( httpd_stream_t ) );
180 @@ -814,6 +835,7 @@ httpd_stream_t *httpd_StreamNew( httpd_host_t *host,
182 stream->psz_mime = strdup( vlc_mime_Ext2Mime( psz_url ) );
184 + stream->b_metacube = b_metacube;
185 stream->i_header = 0;
186 stream->p_header = NULL;
187 stream->i_buffer_size = 5000000; /* 5 Mo per stream */
188 @@ -890,6 +912,20 @@ int httpd_StreamSend( httpd_stream_t *stream, const block_t *p_block )
189 stream->i_last_keyframe_seen_pos = stream->i_buffer_pos;
192 + if( stream->b_metacube )
194 + struct metacube2_block_header hdr;
195 + memcpy( hdr.sync, METACUBE2_SYNC, sizeof(METACUBE2_SYNC) );
196 + hdr.size = htonl( p_block->i_buffer );
197 + hdr.flags = htons( 0 );
198 + if( p_block->i_flags & BLOCK_FLAG_HEADER )
199 + hdr.flags |= htons( METACUBE_FLAGS_HEADER );
200 + if( stream->b_has_keyframes && !( p_block->i_flags & BLOCK_FLAG_TYPE_I ) )
201 + hdr.flags |= htons( METACUBE_FLAGS_NOT_SUITABLE_FOR_STREAM_START );
202 + hdr.csum = htons( metacube2_compute_crc( &hdr ) );
203 + httpd_AppendData( stream, (uint8_t *)&hdr, sizeof(hdr) );
206 httpd_AppendData( stream, p_block->p_buffer, p_block->i_buffer );
208 vlc_mutex_unlock( &stream->lock );
209 diff --git a/src/network/metacube2.c b/src/network/metacube2.c
211 index 0000000..353ce88
213 +++ b/src/network/metacube2.c
216 + * Implementation of Metacube2 utility functions. Taken from the Cubemap
217 + * distribution and then relicensed by the author to LGPL2.1+ for inclusion
220 + * Note: This file is meant to compile as both C and C++, for easier inclusion
221 + * in other projects.
223 + * Copyright (C) 2013 Steinar H. Gunderson
225 + * Author: Steinar H. Gunderson <steinar+vlc@gunderson.no>
227 + * This program is free software; you can redistribute it and/or modify it
228 + * under the terms of the GNU Lesser General Public License as published by
229 + * the Free Software Foundation; either version 2.1 of the License, or
230 + * (at your option) any later version.
232 + * This program is distributed in the hope that it will be useful,
233 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
234 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
235 + * GNU Lesser General Public License for more details.
237 + * You should have received a copy of the GNU Lesser General Public License
238 + * along with this program; if not, write to the Free Software Foundation,
239 + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
244 +#include "metacube2.h"
247 + * https://www.ece.cmu.edu/~koopman/pubs/KoopmanCRCWebinar9May2012.pdf
248 + * recommends this for messages as short as ours (see table at page 34).
250 +#define METACUBE2_CRC_POLYNOMIAL 0x8FDB
252 +/* Semi-random starting value to make sure all-zero won't pass. */
253 +#define METACUBE2_CRC_START 0x1234
255 +uint16_t metacube2_compute_crc(const struct metacube2_block_header *hdr)
257 + static const int data_len = sizeof(hdr->size) + sizeof(hdr->flags);
258 + const uint8_t *data = (uint8_t *)&hdr->size;
259 + uint16_t crc = METACUBE2_CRC_START;
262 + for (i = 0; i < data_len; ++i) {
263 + uint8_t c = data[i];
264 + for (j = 0; j < 8; j++) {
265 + int bit = crc & 0x8000;
266 + crc = (crc << 1) | ((c >> (7 - j)) & 0x01);
268 + crc ^= METACUBE2_CRC_POLYNOMIAL;
274 + for (i = 0; i < 16; i++) {
275 + int bit = crc & 0x8000;
278 + crc ^= METACUBE2_CRC_POLYNOMIAL;