Update the VLC Metacube patch to apply against current VLC master.
[cubemap] / vlc-metacube.diff
1 diff --git a/include/metacube2.h b/include/metacube2.h
2 new file mode 100644
3 index 0000000..dfbfd24
4 --- /dev/null
5 +++ b/include/metacube2.h
6 @@ -0,0 +1,27 @@
7 +#ifndef _METACUBE2_H
8 +#define _METACUBE2_H
9 +
10 +/*
11 + * Definitions for the Metacube2 protocol, used to communicate with Cubemap.
12 + *
13 + * Note: This file is meant to compile as both C and C++, for easier inclusion
14 + * in other projects.
15 + */
16 +
17 +#include <stdint.h>
18 +
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
22 +
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. */
28 +};
29 +
30 +/* This code is based on code generated by pycrc. */
31 +uint16_t metacube2_compute_crc(const struct metacube2_block_header *hdr);
32 +
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 * );
39  
40  
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.")
58  
59  
60  vlc_module_begin ()
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 )
68  vlc_module_end ()
69  
70 @@ -80,7 +85,7 @@ vlc_module_end ()
71   * Exported prototypes
72   *****************************************************************************/
73  static const char *const ppsz_sout_options[] = {
74 -    "user", "pwd", "mime", NULL
75 +    "user", "pwd", "mime", "metacube", NULL
76  };
77  
78  static ssize_t Write( sout_access_out_t *, block_t * );
79 @@ -114,6 +119,8 @@ static int Open( vlc_object_t *p_this )
80      char                *psz_pwd;
81      char                *psz_mime;
82  
83 +    bool                b_metacube;
84 +
85      if( !( p_sys = p_access->p_sys =
86                  malloc( sizeof( sout_access_out_sys_t ) ) ) )
87          return VLC_ENOMEM ;
88 @@ -189,9 +196,11 @@ static int Open( vlc_object_t *p_this )
89          psz_mime = var_GetNonEmptyString( p_access, SOUT_CFG_PREFIX "mime" );
90      }
91  
92 +    b_metacube = var_GetBool( p_access, SOUT_CFG_PREFIX "metacube" );
93 +
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 );
98      free( psz_user );
99      free( psz_pwd );
100      free( psz_mime );
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 = \
106  
107  SOURCES_libvlc_httpd = \
108         network/httpd.c \
109 +       network/metacube2.c \
110         $(NULL)
111  
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
117 @@ -40,6 +40,7 @@
118  #include <vlc_url.h>
119  #include <vlc_mime.h>
120  #include <vlc_block.h>
121 +#include <metacube2.h>
122  #include "../libvlc.h"
123  
124  #include <string.h>
125 @@ -630,6 +631,7 @@ struct httpd_stream_t
126      httpd_url_t *url;
127  
128      char    *psz_mime;
129 +    bool    b_metacube;
130  
131      /* Header to send as first packet */
132      uint8_t *p_header;
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 )
136              {
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 )
141 +                {
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 ) );
147 +
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 );
152 +                }
153 +                else
154 +                {
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 );
158 +                }
159              }
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 );
164          }
165          httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
166 +        if( stream->b_metacube )
167 +            httpd_MsgAdd( answer, "Content-encoding",  "metacube");
168          return VLC_SUCCESS;
169      }
170  }
171  
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,
176 +                                 bool b_metacube )
177  {
178      httpd_stream_t *stream = xmalloc( sizeof( httpd_stream_t ) );
179  
180 @@ -814,6 +835,7 @@ httpd_stream_t *httpd_StreamNew( httpd_host_t *host,
181      {
182          stream->psz_mime = strdup( vlc_mime_Ext2Mime( psz_url ) );
183      }
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;
190      }
191  
192 +    if( stream->b_metacube )
193 +    {
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) );
204 +    }
205 +
206      httpd_AppendData( stream, p_block->p_buffer, p_block->i_buffer );
207  
208      vlc_mutex_unlock( &stream->lock );
209 diff --git a/src/network/metacube2.c b/src/network/metacube2.c
210 new file mode 100644
211 index 0000000..353ce88
212 --- /dev/null
213 +++ b/src/network/metacube2.c
214 @@ -0,0 +1,69 @@
215 +/*
216 + * Implementation of Metacube2 utility functions. Taken from the Cubemap
217 + * distribution and then relicensed by the author to LGPL2.1+ for inclusion
218 + * into VLC.
219 + *
220 + * Note: This file is meant to compile as both C and C++, for easier inclusion
221 + * in other projects.
222 + *
223 + * Copyright (C) 2013 Steinar H. Gunderson
224 + *
225 + * Author: Steinar H. Gunderson <steinar+vlc@gunderson.no>
226 + *
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.
231 + *
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.
236 + *
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.
240 + */
241 +
242 +#include <stdlib.h>
243 +
244 +#include "metacube2.h"
245 +
246 +/*
247 + * https://www.ece.cmu.edu/~koopman/pubs/KoopmanCRCWebinar9May2012.pdf
248 + * recommends this for messages as short as ours (see table at page 34).
249 + */
250 +#define METACUBE2_CRC_POLYNOMIAL 0x8FDB
251 +
252 +/* Semi-random starting value to make sure all-zero won't pass. */
253 +#define METACUBE2_CRC_START 0x1234
254 +
255 +uint16_t metacube2_compute_crc(const struct metacube2_block_header *hdr)
256 +{
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;
260 +       int i, j;
261 +
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);
267 +                       if (bit) {
268 +                               crc ^= METACUBE2_CRC_POLYNOMIAL;
269 +                       }
270 +               }
271 +       }
272 +
273 +       /* Finalize. */
274 +       for (i = 0; i < 16; i++) {
275 +               int bit = crc & 0x8000;
276 +               crc = crc << 1;
277 +               if (bit) {
278 +                       crc ^= METACUBE2_CRC_POLYNOMIAL;
279 +               }
280 +       }
281 +
282 +       return crc;
283 +}