1 /*****************************************************************************
2 * ram.c : RAM playlist format import
3 *****************************************************************************
4 * Copyright (C) 2009 VLC authors and VideoLAN
7 * Authors: Srikanth Raju <srikiraju@gmail.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
26 rtsp://helixserver.example.com/video1.rm?rpcontextheight=250
27 &rpcontextwidth=280&rpcontexturl="http://www.example.com/relatedinfo1.html"
28 rtsp://helixserver.example.com/video2.rm?rpurl="http://www.example.com/index.html"
29 rtsp://helixserver.example.com/sample1.smil?screensize=full
30 rtsp://helixserver.example.com/audio1.rm?start=55&end=1:25
31 rtsp://helixserver.example.com/introvid.rm?title="Introduction to Streaming Media
32 Production"&author="RealNetworks, Inc."©right="©2001, RealNetworks, Inc."
33 rtsp://helixserver.example.com/song1.rm?clipinfo="title=Artist of the Year|artist name=Your Name
34 Here|album name=My Debut|genre=Rock|copyright=2001|year=2001|comments=This one really
38 http://service.real.com/help/library/guides/realone/IntroGuide/HTML/htmfiles/ramsum.htm
39 http://service.real.com/help/library/guides/realone/IntroGuide/HTML/htmfiles/ramfile.htm
43 /*****************************************************************************
45 *****************************************************************************/
52 #include <vlc_common.h>
53 #include <vlc_access.h>
55 #include <vlc_charset.h>
59 /*****************************************************************************
61 *****************************************************************************/
62 static int ReadDir( stream_t
*, input_item_node_t
* );
63 static void ParseClipInfo( const char * psz_clipinfo
, char **ppsz_artist
, char **ppsz_title
,
64 char **ppsz_album
, char **ppsz_genre
, char **ppsz_year
,
65 char **ppsz_cdnum
, char **ppsz_comments
);
68 * Import_RAM: main import function
69 * @param p_this: this demux object
70 * @return VLC_SUCCESS if everything is okay
72 int Import_RAM( vlc_object_t
*p_this
)
74 stream_t
*p_demux
= (stream_t
*)p_this
;
75 const uint8_t *p_peek
;
78 if( !stream_HasExtension( p_demux
, ".ram" )
79 && !stream_HasExtension( p_demux
, ".rm" ) )
82 /* Many Real Media Files are misdetected */
83 if( vlc_stream_Peek( p_demux
->s
, &p_peek
, 4 ) < 4 )
85 if( !memcmp( p_peek
, ".ra", 3 ) || !memcmp( p_peek
, ".RMF", 4 ) )
90 msg_Dbg( p_demux
, "found valid RAM playlist" );
91 p_demux
->pf_readdir
= ReadDir
;
92 p_demux
->pf_control
= access_vaDirectoryControlHelper
;
98 * Skips blanks in a given buffer
99 * @param s: input string
100 * @param i_strlen: length of the buffer
102 static const char *SkipBlanks( const char *s
, size_t i_strlen
)
104 while( i_strlen
> 0 ) {
122 * Converts a time of format hour:minutes:sec.fraction to seconds
123 * @param s: input string
124 * @param i_strlen: length of the buffer
125 * @return time in seconds
127 static int ParseTime( const char *s
, size_t i_strlen
)
129 // need to parse hour:minutes:sec.fraction string
132 const char *end
= s
+ i_strlen
;
133 // skip leading spaces if any
134 s
= SkipBlanks(s
, i_strlen
);
137 while( (s
< end
) && isdigit((unsigned char)*s
) )
139 int newval
= val
*10 + (*s
- '0');
150 s
= SkipBlanks(s
, end
-s
);
154 s
= SkipBlanks(s
, end
-s
);
155 result
= result
* 60;
157 while( (s
< end
) && isdigit((unsigned char)*s
) )
159 int newval
= val
*10 + (*s
- '0');
170 s
= SkipBlanks(s
, end
-s
);
174 s
= SkipBlanks(s
, end
-s
);
175 result
= result
* 60;
177 while( (s
< end
) && isdigit((unsigned char)*s
) )
179 int newval
= val
*10 + (*s
- '0');
190 // TODO: one day, we may need to parse fraction for sub-second resolution
196 static int ReadDir( stream_t
*p_demux
, input_item_node_t
*p_subitems
)
198 const char *psz_prefix
= p_demux
->psz_url
;
199 if( unlikely(psz_prefix
== NULL
) )
203 char *psz_artist
= NULL
, *psz_album
= NULL
, *psz_genre
= NULL
, *psz_year
= NULL
;
204 char *psz_author
= NULL
, *psz_title
= NULL
, *psz_copyright
= NULL
, *psz_cdnum
= NULL
, *psz_comments
= NULL
;
205 mtime_t i_duration
= -1;
206 const char **ppsz_options
= NULL
;
207 int i_options
= 0, i_start
= 0, i_stop
= 0;
208 bool b_cleanup
= false;
209 input_item_t
*p_input
;
211 psz_line
= vlc_stream_ReadLine( p_demux
->s
);
214 char *psz_parse
= psz_line
;
216 /* Skip leading tabs and spaces */
217 while( *psz_parse
== ' ' || *psz_parse
== '\t' ||
218 *psz_parse
== '\n' || *psz_parse
== '\r' ) psz_parse
++;
220 if( *psz_parse
== '#' )
222 /* Ignore comments */
224 else if( *psz_parse
)
226 char *psz_mrl
, *psz_option_next
, *psz_option
;
227 char *psz_param
, *psz_value
;
229 /* Get the MRL from the file. Note that this might contain parameters of form ?param1=value1¶m2=value2 in a RAM file */
230 psz_mrl
= ProcessMRL( psz_parse
, psz_prefix
);
233 if ( !psz_mrl
) goto error
;
235 /* We have the MRL, now we have to check for options and parse them from MRL */
236 psz_option
= strchr( psz_mrl
, '?' ); /* Look for start of options */
239 /* Remove options from MRL
240 because VLC can't get the file otherwise */
243 psz_option_next
= psz_option
;
244 while( 1 ) /* Process each option */
246 /* Look for end of first option which maybe a & or \0 */
247 psz_option
= psz_option_next
;
248 psz_option_next
= strchr( psz_option
, '&' );
249 if( psz_option_next
)
251 *psz_option_next
= '\0';
255 psz_option_next
= strchr( psz_option
, '\0' );
256 /* Quit if options are over */
257 if( psz_option_next
== psz_option
)
260 /* Parse out param and value */
261 psz_param
= psz_option
;
262 psz_value
= strchr( psz_option
, '=' );
263 if( psz_value
== NULL
)
268 /* Take action based on parameter value in the below if else structure */
269 /* TODO: Remove any quotes surrounding values if required */
270 if( !strcmp( psz_param
, "clipinfo" ) )
272 ParseClipInfo( psz_value
, &psz_artist
, &psz_title
,
273 &psz_album
, &psz_genre
, &psz_year
,
274 &psz_cdnum
, &psz_comments
); /* clipinfo has various sub parameters, which is parsed by this function */
276 else if( !strcmp( psz_param
, "author" ) )
278 psz_author
= vlc_uri_decode_duplicate(psz_value
);
279 EnsureUTF8( psz_author
);
281 else if( !strcmp( psz_param
, "start" )
282 && strncmp( psz_mrl
, "rtsp", 4 ) /* Our rtsp-real or our real demuxer is wrong */ )
284 i_start
= ParseTime( psz_value
, strlen( psz_value
) );
288 if( asprintf( &temp
, ":start-time=%d", i_start
) != -1 )
289 TAB_APPEND( i_options
, ppsz_options
, temp
);
292 else if( !strcmp( psz_param
, "end" ) )
294 i_stop
= ParseTime( psz_value
, strlen( psz_value
) );
298 if( asprintf( &temp
, ":stop-time=%d", i_stop
) != -1 )
299 TAB_APPEND( i_options
, ppsz_options
, temp
);
302 else if( !strcmp( psz_param
, "title" ) )
305 psz_title
= vlc_uri_decode_duplicate(psz_value
);
306 EnsureUTF8( psz_title
);
308 else if( !strcmp( psz_param
, "copyright" ) )
310 psz_copyright
= vlc_uri_decode_duplicate(psz_value
);
311 EnsureUTF8( psz_copyright
);
314 { /* TODO: insert option anyway? Currently ignores*/
315 //TAB_APPEND( i_options, ppsz_options, psz_option );
320 /* Create the input item and pump in all the options into playlist item */
321 p_input
= input_item_NewExt( psz_mrl
, psz_title
, i_duration
,
322 ITEM_TYPE_UNKNOWN
, ITEM_NET_UNKNOWN
);
329 input_item_AddOptions( p_input
, i_options
, ppsz_options
, 0 );
331 if( !EMPTY_STR( psz_artist
) ) input_item_SetArtist( p_input
, psz_artist
);
332 if( !EMPTY_STR( psz_author
) ) input_item_SetPublisher( p_input
, psz_author
);
333 if( !EMPTY_STR( psz_title
) ) input_item_SetTitle( p_input
, psz_title
);
334 if( !EMPTY_STR( psz_copyright
) ) input_item_SetCopyright( p_input
, psz_copyright
);
335 if( !EMPTY_STR( psz_album
) ) input_item_SetAlbum( p_input
, psz_album
);
336 if( !EMPTY_STR( psz_genre
) ) input_item_SetGenre( p_input
, psz_genre
);
337 if( !EMPTY_STR( psz_year
) ) input_item_SetDate( p_input
, psz_year
);
338 if( !EMPTY_STR( psz_cdnum
) ) input_item_SetTrackNum( p_input
, psz_cdnum
);
339 if( !EMPTY_STR( psz_comments
) ) input_item_SetDescription( p_input
, psz_comments
);
341 input_item_node_AppendItem( p_subitems
, p_input
);
342 input_item_Release( p_input
);
347 /* Fetch another line */
349 psz_line
= vlc_stream_ReadLine( p_demux
->s
);
350 if( !psz_line
) b_cleanup
= true;
355 while( i_options
-- ) free( (char*)ppsz_options
[i_options
] );
356 FREENULL( ppsz_options
);
357 FREENULL( psz_artist
);
358 FREENULL( psz_title
);
359 FREENULL( psz_author
);
360 FREENULL( psz_copyright
);
361 FREENULL( psz_album
);
362 FREENULL( psz_genre
);
363 FREENULL( psz_year
);
364 FREENULL( psz_cdnum
);
365 FREENULL( psz_comments
);
377 * Parses clipinfo parameter
378 * @param psz_clipinfo: string containing the clipinfo parameter along with quotes
379 * @param ppsz_artist: Buffer to store artist name
380 * @param ppsz_title: Buffer to store title
381 * @param ppsz_album: Buffer to store album
382 * @param ppsz_genre: Buffer to store genre
383 * @param ppsz_year: Buffer to store year
384 * @param ppsz_cdnum: Buffer to store cdnum
385 * @param ppsz_comments: Buffer to store comments
387 static void ParseClipInfo( const char *psz_clipinfo
, char **ppsz_artist
, char **ppsz_title
,
388 char **ppsz_album
, char **ppsz_genre
, char **ppsz_year
,
389 char **ppsz_cdnum
, char **ppsz_comments
)
391 char *psz_option_next
, *psz_option_start
, *psz_param
, *psz_value
, *psz_suboption
;
392 char *psz_temp_clipinfo
= strdup( psz_clipinfo
);
393 psz_option_start
= strchr( psz_temp_clipinfo
, '"' );
394 if( !psz_option_start
)
396 free( psz_temp_clipinfo
);
401 psz_option_next
= psz_option_start
;
402 while( 1 ) /* Process each sub option */
404 /* Get the sub option */
405 psz_option_start
= psz_option_next
;
406 psz_option_next
= strchr( psz_option_start
, '|' );
407 if( psz_option_next
)
408 *psz_option_next
= '\0';
410 psz_option_next
= strchr( psz_option_start
, '"' );
411 if( psz_option_next
)
412 *psz_option_next
= '\0';
414 psz_option_next
= strchr( psz_option_start
, '\0' );
415 if( psz_option_next
== psz_option_start
)
418 psz_suboption
= strdup( psz_option_start
);
422 /* Parse out param and value */
423 psz_param
= psz_suboption
;
424 if( strchr( psz_suboption
, '=' ) )
426 psz_value
= strchr( psz_suboption
, '=' ) + 1;
427 *( strchr( psz_suboption
, '=' ) ) = '\0';
431 free( psz_suboption
);
435 if( !strcmp( psz_param
, "artist name" ) )
436 *ppsz_artist
= vlc_uri_decode_duplicate( psz_value
);
437 else if( !strcmp( psz_param
, "title" ) )
438 *ppsz_title
= vlc_uri_decode_duplicate( psz_value
);
439 else if( !strcmp( psz_param
, "album name" ) )
440 *ppsz_album
= vlc_uri_decode_duplicate( psz_value
);
441 else if( !strcmp( psz_param
, "genre" ) )
442 *ppsz_genre
= vlc_uri_decode_duplicate( psz_value
);
443 else if( !strcmp( psz_param
, "year" ) )
444 *ppsz_year
= vlc_uri_decode_duplicate( psz_value
);
445 else if( !strcmp( psz_param
, "cdnum" ) )
446 *ppsz_cdnum
= vlc_uri_decode_duplicate( psz_value
);
447 else if( !strcmp( psz_param
, "comments" ) )
448 *ppsz_comments
= vlc_uri_decode_duplicate( psz_value
);
450 free( psz_suboption
);
454 free( psz_temp_clipinfo
);