/* PSResynch: resynch on a system startcode * It doesn't skip more than 512 bytes * -1 -> error, 0 -> not synch, 1 -> ok */ static int ps_pkt_resynch( stream_t *s, int format, bool b_pack ) { const uint8_t *p_peek; int i_peek; int i_skip; if( vlc_stream_Peek( s, &p_peek, 4 ) < 4 ) { return -1; } if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 && p_peek[3] >= PS_STREAM_ID_END_STREAM ) { return 1; } if( ( i_peek = vlc_stream_Peek( s, &p_peek, 512 ) ) < 4 ) { return -1; } i_skip = 0; for( ;; ) { if( i_peek < 4 ) { break; } /* Handle mid stream 24 bytes padding+CRC creating emulated sync codes with incorrect PES sizes and frelling up to UINT16_MAX bytes followed by 24 bytes CDXA Header */ if( format == CDXA_PS && i_skip == 0 && i_peek >= 48 ) { const uint8_t cdxasynccode[12] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; if( !memcmp( &p_peek[24], cdxasynccode, 12 ) ) { i_peek -= 48; p_peek += 48; i_skip += 48; continue; } } if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 && p_peek[3] >= PS_STREAM_ID_END_STREAM && ( !b_pack || p_peek[3] == PS_STREAM_ID_PACK_HEADER ) ) { return vlc_stream_Read( s, NULL, i_skip ) == i_skip ? 1 : -1; } p_peek++; i_peek--; i_skip++; } return vlc_stream_Read( s, NULL, i_skip ) == i_skip ? 0 : -1; }
/***************************************************************************** * Import_M3U: main import function *****************************************************************************/ int Import_M3U( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t *)p_this; const uint8_t *p_peek; char *(*pf_dup) (const char *) = GuessEncoding; int offset = 0; CHECK_FILE(); if( vlc_stream_Peek( p_demux->s, &p_peek, 3 ) == 3 && !memcmp( p_peek, "\xef\xbb\xbf", 3) ) { pf_dup = CheckUnicode; /* UTF-8 Byte Order Mark */ offset = 3; } if( demux_IsPathExtension( p_demux, ".m3u8" ) || demux_IsForced( p_demux, "m3u8" ) || CheckContentType( p_demux->s, "application/vnd.apple.mpegurl" ) ) pf_dup = CheckUnicode; /* UTF-8 file type */ else if( demux_IsPathExtension( p_demux, ".m3u" ) || demux_IsPathExtension( p_demux, ".vlc" ) || demux_IsForced( p_demux, "m3u" ) || ContainsURL( p_demux ) || CheckContentType( p_demux->s, "audio/x-mpegurl") ) ; /* Guess encoding */ else { if( vlc_stream_Peek( p_demux->s, &p_peek, 8 + offset ) < (8 + offset) ) return VLC_EGENERIC; p_peek += offset; if( !strncasecmp( (const char *)p_peek, "RTSPtext", 8 ) ) /* QuickTime */ pf_dup = CheckUnicode; /* UTF-8 */ else if( !memcmp( p_peek, "#EXTM3U", 7 ) ) ; /* Guess encoding */ else return VLC_EGENERIC; } vlc_stream_Seek( p_demux->s, offset ); STANDARD_DEMUX_INIT_MSG( "found valid M3U playlist" ); p_demux->p_sys->psz_prefix = FindPrefix( p_demux ); p_demux->p_sys->pf_dup = pf_dup; return VLC_SUCCESS; }
bool ProbeArchiveFormat(stream_t *p_stream) { struct { const uint16_t i_offset; const uint8_t i_length; const char * const p_bytes; } const magicbytes[9] = { /* keep heaviest at top */ { 257, 5, "ustar" }, //TAR { 0, 7, "Rar!\x1A\x07" }, //RAR { 0, 4, "xar!" }, //XAR { 2, 3, "-lh" }, //LHA/LHZ { 0, 3, "PAX" }, //PAX { 0, 6, "070707" }, //CPIO { 0, 6, "070701" }, //CPIO { 0, 6, "070702" }, //CPIO { 0, 4, "MSCH" }, //CAB }; const uint8_t *p_peek; int i_peek = vlc_stream_Peek(p_stream, &p_peek, magicbytes[0].i_offset + magicbytes[0].i_length); for(int i=0; i<9;i++) { if (i_peek <= magicbytes[i].i_offset + magicbytes[i].i_length) continue; else if ( !memcmp(p_peek + magicbytes[i].i_offset, magicbytes[i].p_bytes, magicbytes[i].i_length) ) return true; } return false; }
/***************************************************************************** * Peek: Helper function to peek data with incremental size. * \return false if peek no more data, true otherwise. *****************************************************************************/ static bool Peek( demux_t *p_demux, bool b_first ) { int i_data; demux_sys_t *p_sys = p_demux->p_sys; if( b_first ) { p_sys->i_data_peeked = 0; } else if( p_sys->i_data_peeked == p_sys->i_frame_size_estimate ) { p_sys->i_frame_size_estimate += 5120; } i_data = vlc_stream_Peek( p_demux->s, &p_sys->p_peek, p_sys->i_frame_size_estimate ); if( i_data == p_sys->i_data_peeked ) { msg_Warn( p_demux, "no more data" ); return false; } p_sys->i_data_peeked = i_data; if( i_data <= 0 ) { msg_Warn( p_demux, "cannot peek data" ); return false; } return true; }
/**************************************************************************** * * Basics functions to manipulates chunks * ****************************************************************************/ static int AVI_ChunkReadCommon( stream_t *s, avi_chunk_t *p_chk ) { const uint8_t *p_peek; memset( p_chk, 0, sizeof( avi_chunk_t ) ); if( vlc_stream_Peek( s, &p_peek, 8 ) < 8 ) return VLC_EGENERIC; p_chk->common.i_chunk_fourcc = GetFOURCC( p_peek ); p_chk->common.i_chunk_size = GetDWLE( p_peek + 4 ); p_chk->common.i_chunk_pos = vlc_stream_Tell( s ); p_chk->common.p_father = NULL; p_chk->common.p_next = NULL; p_chk->common.p_first = NULL; p_chk->common.p_next = NULL; #ifdef AVI_DEBUG msg_Dbg( (vlc_object_t*)s, "found chunk, fourcc: %4.4s size:%"PRId64" pos:%"PRId64, (char*)&p_chk->common.i_chunk_fourcc, p_chk->common.i_chunk_size, p_chk->common.i_chunk_pos ); #endif return VLC_SUCCESS; }
static bool ContainsURL( demux_t *p_demux ) { const uint8_t *p_peek, *p_peek_end; int i_peek; i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 1024 ); if( i_peek <= 0 ) return false; p_peek_end = p_peek + i_peek; while( p_peek + sizeof( "https://" ) < p_peek_end ) { /* One line starting with a URL is enough */ if( !strncasecmp( (const char *)p_peek, "http://", 7 ) || !strncasecmp( (const char *)p_peek, "mms://", 6 ) || !strncasecmp( (const char *)p_peek, "rtsp://", 7 ) || !strncasecmp( (const char *)p_peek, "https://", 8 ) || !strncasecmp( (const char *)p_peek, "ftp://", 6 ) || !strncasecmp( (const char *)p_peek, "ftps://", 7 ) || !strncasecmp( (const char *)p_peek, "ftpes://", 8 ) ) { return true; } /* Comments and blank lines are ignored */ else if( *p_peek != '#' && *p_peek != '\n' && *p_peek != '\r') { return false; } while( p_peek < p_peek_end && *p_peek != '\n' ) p_peek++; if ( *p_peek == '\n' ) p_peek++; } return false; }
static int DemuxOpen( vlc_object_t * p_this ) { demux_t *p_demux = (demux_t *)p_this; const uint8_t *p_peek; int i_size; /* Lets check the content to see if this is a NSC file */ i_size = vlc_stream_Peek( p_demux->s, &p_peek, MAX_LINE ); i_size -= sizeof("NSC Format Version=") - 1; if ( i_size > 0 ) { while ( i_size && strncasecmp( (char *)p_peek, "NSC Format Version=", (int) sizeof("NSC Format Version=") - 1 ) ) { p_peek++; i_size--; } if ( !strncasecmp( (char *)p_peek, "NSC Format Version=", (int) sizeof("NSC Format Version=") -1 ) ) { p_demux->pf_demux = Demux; p_demux->pf_control = Control; return VLC_SUCCESS; } } return VLC_EGENERIC; }
/***************************************************************************** * Open: initializes demux structures *****************************************************************************/ static int Open( vlc_object_t * p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; bool b_forced = false; const uint8_t *p_peek; es_format_t fmt; if( vlc_stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) { msg_Dbg( p_demux, "cannot peek" ); return VLC_EGENERIC; } if( p_demux->obj.force ) b_forced = true; if( p_peek[0] != 0x00 || p_peek[1] != 0x00 || p_peek[2] != 0x01 ) { if( !b_forced ) return VLC_EGENERIC; msg_Err( p_demux, "this doesn't look like an MPEG ES stream, continuing" ); } if( p_peek[3] > 0xb9 ) { if( !b_forced ) return VLC_EGENERIC; msg_Err( p_demux, "this seems to be a system stream (PS plug-in ?), but continuing" ); } p_demux->pf_demux = Demux; p_demux->pf_control= Control; p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); p_sys->b_start = true; p_sys->p_es = NULL; /* Load the mpegvideo packetizer */ es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_MPGV ); p_sys->p_packetizer = demux_PacketizerNew( p_demux, &fmt, "mpeg video" ); if( !p_sys->p_packetizer ) { free( p_sys ); return VLC_EGENERIC; } /* create the output */ p_sys->p_es = es_out_Add( p_demux->out, &fmt ); if( p_sys->p_es == NULL ) { Close( p_this ); return VLC_EGENERIC; } return VLC_SUCCESS; }
static int vlclua_demux_peek( lua_State *L ) { stream_t *s = (stream_t *)vlclua_get_this(L); int n = luaL_checkinteger( L, 1 ); const uint8_t *p_peek; ssize_t val = vlc_stream_Peek(s->s, &p_peek, n); if (val > 0) lua_pushlstring(L, (const char *)p_peek, val); else lua_pushnil( L ); return 1; }
static int vlclua_demux_peek( lua_State *L ) { demux_t *p_demux = (demux_t *)vlclua_get_this( L ); int n = (int)luaL_checkinteger( L, 1 ); const uint8_t *p_peek; int i_peek = vlc_stream_Peek( p_demux->s, &p_peek, n ); if( i_peek > 0 ) lua_pushlstring( L, (const char *)p_peek, i_peek ); else lua_pushnil( L ); return 1; }
/***************************************************************************** * Import_podcast: main import function *****************************************************************************/ int Import_podcast( vlc_object_t *p_this ) { stream_t *p_demux = (stream_t *)p_this; CHECK_FILE(p_demux); if( stream_IsMimeType( p_demux->s, "text/xml" ) || stream_IsMimeType( p_demux->s, "application/xml" ) ) { /* XML: check if the root node is "rss". Use a specific peeked * probestream in order to not modify the source state while probing. * */ const uint8_t *p_peek; ssize_t i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 ); if( unlikely( i_peek <= 0 ) ) return VLC_EGENERIC; stream_t *p_probestream = vlc_stream_MemoryNew( p_demux, (uint8_t *)p_peek, i_peek, true ); if( unlikely( !p_probestream ) ) return VLC_EGENERIC; xml_reader_t *p_xml_reader = xml_ReaderCreate( p_demux, p_probestream ); if( !p_xml_reader ) { vlc_stream_Delete( p_probestream ); return VLC_EGENERIC; } const char *node; int ret; if( ( ret = xml_ReaderNextNode( p_xml_reader, &node ) ) != XML_READER_STARTELEM || strcmp( node, "rss" ) ) { vlc_stream_Delete( p_probestream ); xml_ReaderDelete( p_xml_reader ); return VLC_EGENERIC; } xml_ReaderDelete( p_xml_reader ); vlc_stream_Delete( p_probestream ); /* SUCCESS: this text/xml is a rss file */ } else if( !stream_IsMimeType( p_demux->s, "application/rss+xml" ) ) return VLC_EGENERIC; p_demux->pf_readdir = ReadDir; p_demux->pf_control = access_vaDirectoryControlHelper; msg_Dbg( p_demux, "using podcast reader" ); return VLC_SUCCESS; }
static block_t *ps_pkt_read( stream_t *s ) { const uint8_t *p_peek; int i_peek = vlc_stream_Peek( s, &p_peek, 14 ); if( i_peek < 4 ) return NULL; int i_size = ps_pkt_size( p_peek, i_peek ); if( i_size <= 6 && p_peek[3] > PS_STREAM_ID_PACK_HEADER ) { /* Special case, search the next start code */ i_size = 6; for( ;; ) { i_peek = vlc_stream_Peek( s, &p_peek, i_size + 1024 ); if( i_peek <= i_size + 4 ) { return NULL; } while( i_size <= i_peek - 4 ) { if( p_peek[i_size] == 0x00 && p_peek[i_size+1] == 0x00 && p_peek[i_size+2] == 0x01 && p_peek[i_size+3] >= PS_STREAM_ID_END_STREAM ) { return vlc_stream_Block( s, i_size ); } i_size++; } } } else { /* Normal case */ return vlc_stream_Block( s, i_size ); } return NULL; }
/***************************************************************************** * Activate: initializes m3u demux structures *****************************************************************************/ int Import_SGIMB( vlc_object_t * p_this ) { stream_t *p_demux = (stream_t *)p_this; const uint8_t *p_peek; int i_size; CHECK_FILE(p_demux); /* Lets check the content to see if this is a sgi mediabase file */ i_size = vlc_stream_Peek( p_demux->p_source, &p_peek, MAX_LINE ); i_size -= sizeof("sgiNameServerHost=") - 1; if ( i_size > 0 ) { unsigned int i_len = sizeof("sgiNameServerHost=") - 1; while ( i_size && strncasecmp( (char *)p_peek, "sgiNameServerHost=", i_len ) ) { p_peek++; i_size--; } if ( !strncasecmp( (char *)p_peek, "sgiNameServerHost=", i_len ) ) { demux_sys_t *p_sys = malloc(sizeof (*p_sys)); if( unlikely(p_sys == NULL) ) return VLC_ENOMEM; msg_Dbg( p_demux, "using SGIMB playlist reader" ); p_demux->pf_readdir = ReadDir; p_demux->pf_control = access_vaDirectoryControlHelper; p_demux->p_sys = p_sys; p_sys->psz_uri = NULL; p_sys->psz_server = NULL; p_sys->psz_location = NULL; p_sys->psz_name = NULL; p_sys->psz_user = NULL; p_sys->psz_password = NULL; p_sys->psz_mcast_ip = NULL; p_sys->i_mcast_port = 0; p_sys->i_packet_size = 0; p_sys->i_duration = 0; p_sys->i_port = 0; p_sys->i_sid = 0; p_sys->b_rtsp_kasenna = false; p_sys->b_concert = false; return VLC_SUCCESS; } } return VLC_EGENERIC; }
int Import_WMS(vlc_object_t *obj) { stream_t *demux = (stream_t *)obj; const uint8_t *peek; CHECK_FILE(demux); if (vlc_stream_Peek(demux->s, &peek, 10) < 10 || strncmp((const char *)peek, "[Reference]", 11)) return VLC_EGENERIC; msg_Dbg(demux, "found WMS metafile"); demux->pf_readdir = ReadDir; demux->pf_control = access_vaDirectoryControlHelper; return VLC_SUCCESS; }
/***************************************************************************** * Import_IFO: main import function *****************************************************************************/ int Import_IFO( vlc_object_t *p_this ) { stream_t *p_stream = (stream_t *)p_this; CHECK_FILE(p_stream); if( !stream_HasExtension( p_stream, ".IFO" ) ) return VLC_EGENERIC; const char *psz_location = StreamLocation( p_stream ); if( psz_location == NULL ) return VLC_EGENERIC; size_t len = strlen( psz_location ); if( len < 12 ) return VLC_EGENERIC; const char *psz_probe; const char *psz_file = &psz_location[len - 12]; /* Valid filenames are : * - VIDEO_TS.IFO * - VTS_XX_X.IFO where X are digits */ if( !strncasecmp( psz_file, "VIDEO_TS", 8 ) || !strncasecmp( psz_file, "VTS_", 4 ) ) { psz_probe = "DVDVIDEO"; p_stream->pf_readdir = ReadDVD; } /* Valid filename for DVD-VR is VR_MANGR.IFO */ else if( !strncasecmp( psz_file, "VR_MANGR", 8 ) ) { psz_probe = "DVD_RTR_"; p_stream->pf_readdir = ReadDVD_VR; } else return VLC_EGENERIC; const uint8_t *p_peek; ssize_t i_peek = vlc_stream_Peek( p_stream->s, &p_peek, 8 ); if( i_peek < 8 || memcmp( p_peek, psz_probe, 8 ) ) return VLC_EGENERIC; p_stream->pf_control = access_vaDirectoryControlHelper; return VLC_SUCCESS; }
static int vlclua_demux_read( lua_State *L ) { demux_t *p_demux = (demux_t *)vlclua_get_this( L ); const uint8_t *p_read; int n = (int)luaL_checkinteger( L, 1 ); int i_read = vlc_stream_Peek( p_demux->s, &p_read, n ); if( i_read > 0 ) { lua_pushlstring( L, (const char *)p_read, i_read ); int i_seek = vlc_stream_Read( p_demux->s, NULL, i_read ); assert( i_read == i_seek ); } else lua_pushnil( L ); return 1; }
static int probe( stream_t* source ) { struct { uint16_t i_offset; uint8_t i_length; char const * p_bytes; } const magicbytes[] = { /* keep heaviest at top */ { 257, 5, "ustar" }, //TAR { 0, 7, "Rar!\x1A\x07" }, //RAR { 0, 6, "7z\xBC\xAF\x27\x1C" }, //7z { 0, 4, "xar!" }, //XAR { 0, 4, "PK\x03\x04" }, //ZIP { 0, 4, "PK\x05\x06" }, //ZIP { 0, 4, "PK\x07\x08" }, //ZIP { 2, 3, "-lh" }, //LHA/LHZ { 0, 3, "\x1f\x8b\x08" }, // Gzip { 0, 3, "PAX" }, //PAX { 0, 6, "070707" }, //CPIO { 0, 6, "070701" }, //CPIO { 0, 6, "070702" }, //CPIO { 0, 4, "MSCH" }, //CAB }; const uint8_t *p_peek; int i_peek = vlc_stream_Peek( source, &p_peek, magicbytes[0].i_offset + magicbytes[0].i_length); for(unsigned i=0; i < ARRAY_SIZE( magicbytes ); i++) { if (i_peek < magicbytes[i].i_offset + magicbytes[i].i_length) continue; if ( !memcmp(p_peek + magicbytes[i].i_offset, magicbytes[i].p_bytes, magicbytes[i].i_length) ) return VLC_SUCCESS; } return VLC_EGENERIC; }
/***************************************************************************** * Import_PLS: main import function *****************************************************************************/ int Import_PLS( vlc_object_t *p_this ) { stream_t *p_demux = (stream_t *)p_this; const uint8_t *p_peek; CHECK_FILE(p_demux); if( vlc_stream_Peek( p_demux->p_source , &p_peek, 10 ) < 10 ) { msg_Dbg( p_demux, "not enough data" ); return VLC_EGENERIC; } if( strncasecmp( (const char *)p_peek, "[playlist]", 10 ) && strncasecmp( (const char *)p_peek, "[Reference]", 10 ) && !stream_HasExtension( p_demux, ".pls" ) ) return VLC_EGENERIC; msg_Dbg( p_demux, "found valid PLS playlist file"); p_demux->pf_readdir = ReadDir; p_demux->pf_control = access_vaDirectoryControlHelper; return VLC_SUCCESS; }
/** * Import_RAM: main import function * @param p_this: this demux object * @return VLC_SUCCESS if everything is okay */ int Import_RAM( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t *)p_this; const uint8_t *p_peek; CHECK_FILE(); if(! demux_IsPathExtension( p_demux, ".ram" ) || demux_IsPathExtension( p_demux, ".rm" ) ) return VLC_EGENERIC; /* Many Real Media Files are misdetected */ if( vlc_stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) return VLC_EGENERIC; if( !memcmp( p_peek, ".ra", 3 ) || !memcmp( p_peek, ".RMF", 4 ) ) { return VLC_EGENERIC; } STANDARD_DEMUX_INIT_MSG( "found valid RAM playlist" ); p_demux->p_sys->psz_prefix = FindPrefix( p_demux ); return VLC_SUCCESS; }
/** * Import_RAM: main import function * @param p_this: this demux object * @return VLC_SUCCESS if everything is okay */ int Import_RAM( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t *)p_this; const uint8_t *p_peek; CHECK_FILE(); if(! demux_IsPathExtension( p_demux, ".ram" ) || demux_IsPathExtension( p_demux, ".rm" ) ) return VLC_EGENERIC; /* Many Real Media Files are misdetected */ if( vlc_stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) return VLC_EGENERIC; if( !memcmp( p_peek, ".ra", 3 ) || !memcmp( p_peek, ".RMF", 4 ) ) { return VLC_EGENERIC; } msg_Dbg( p_demux, "found valid RAM playlist" ); p_demux->pf_demux = Demux; p_demux->pf_control = Control; return VLC_SUCCESS; }
/***************************************************************************** * Open: initializes matroska demux structures *****************************************************************************/ static int Open( vlc_object_t * p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; matroska_stream_c *p_stream; matroska_segment_c *p_segment; const uint8_t *p_peek; std::string s_path, s_filename; vlc_stream_io_callback *p_io_callback; EbmlStream *p_io_stream; bool b_need_preload = false; /* peek the begining */ if( vlc_stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) return VLC_EGENERIC; /* is a valid file */ if( p_peek[0] != 0x1a || p_peek[1] != 0x45 || p_peek[2] != 0xdf || p_peek[3] != 0xa3 ) return VLC_EGENERIC; /* Set the demux function */ p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys = new demux_sys_t( *p_demux ); p_io_callback = new vlc_stream_io_callback( p_demux->s, false ); p_io_stream = new (std::nothrow) EbmlStream( *p_io_callback ); if( p_io_stream == NULL ) { msg_Err( p_demux, "failed to create EbmlStream" ); delete p_io_callback; delete p_sys; return VLC_EGENERIC; } p_stream = p_sys->AnalyseAllSegmentsFound( p_demux, p_io_stream, true ); if( p_stream == NULL ) { msg_Err( p_demux, "cannot find KaxSegment or missing mandatory KaxInfo" ); goto error; } p_sys->streams.push_back( p_stream ); p_stream->p_io_callback = p_io_callback; p_stream->p_estream = p_io_stream; for (size_t i=0; i<p_stream->segments.size(); i++) { p_stream->segments[i]->Preload(); b_need_preload |= p_stream->segments[i]->b_ref_external_segments; if ( p_stream->segments[i]->translations.size() && p_stream->segments[i]->translations[0]->codec_id == MATROSKA_CHAPTER_CODEC_DVD && p_stream->segments[i]->families.size() ) b_need_preload = true; } p_segment = p_stream->segments[0]; if( p_segment->cluster == NULL && p_segment->stored_editions.size() == 0 ) { msg_Err( p_demux, "cannot find any cluster or chapter, damaged file ?" ); goto error; } if (b_need_preload && var_InheritBool( p_demux, "mkv-preload-local-dir" )) { msg_Dbg( p_demux, "Preloading local dir" ); /* get the files from the same dir from the same family (based on p_demux->psz_path) */ if ( p_demux->psz_file && !strcmp( p_demux->psz_access, "file" ) ) { // assume it's a regular file // get the directory path s_path = p_demux->psz_file; if (s_path.at(s_path.length() - 1) == DIR_SEP_CHAR) { s_path = s_path.substr(0,s_path.length()-1); } else { if (s_path.find_last_of(DIR_SEP_CHAR) > 0) { s_path = s_path.substr(0,s_path.find_last_of(DIR_SEP_CHAR)); } } DIR *p_src_dir = vlc_opendir(s_path.c_str()); if (p_src_dir != NULL) { const char *psz_file; while ((psz_file = vlc_readdir(p_src_dir)) != NULL) { if (strlen(psz_file) > 4) { s_filename = s_path + DIR_SEP_CHAR + psz_file; #if defined(_WIN32) || defined(__OS2__) if (!strcasecmp(s_filename.c_str(), p_demux->psz_file)) #else if (!s_filename.compare(p_demux->psz_file)) #endif { continue; // don't reuse the original opened file } if (!s_filename.compare(s_filename.length() - 3, 3, "mkv") || !s_filename.compare(s_filename.length() - 3, 3, "mka")) { // test whether this file belongs to our family const uint8_t *p_peek; bool file_ok = false; char *psz_url = vlc_path2uri( s_filename.c_str(), "file" ); stream_t *p_file_stream = vlc_stream_NewURL( p_demux, psz_url ); /* peek the begining */ if( p_file_stream && vlc_stream_Peek( p_file_stream, &p_peek, 4 ) >= 4 && p_peek[0] == 0x1a && p_peek[1] == 0x45 && p_peek[2] == 0xdf && p_peek[3] == 0xa3 ) file_ok = true; if ( file_ok ) { vlc_stream_io_callback *p_file_io = new vlc_stream_io_callback( p_file_stream, true ); EbmlStream *p_estream = new EbmlStream(*p_file_io); p_stream = p_sys->AnalyseAllSegmentsFound( p_demux, p_estream ); if ( p_stream == NULL ) { msg_Dbg( p_demux, "the file '%s' will not be used", s_filename.c_str() ); delete p_estream; delete p_file_io; } else { p_stream->p_io_callback = p_file_io; p_stream->p_estream = p_estream; p_sys->streams.push_back( p_stream ); } } else { if( p_file_stream ) { vlc_stream_Delete( p_file_stream ); } msg_Dbg( p_demux, "the file '%s' cannot be opened", s_filename.c_str() ); } free( psz_url ); } } } closedir( p_src_dir ); } } p_sys->PreloadFamily( *p_segment ); } else if (b_need_preload) msg_Warn( p_demux, "This file references other files, you may want to enable the preload of local directory"); if ( !p_sys->PreloadLinked() || !p_sys->PreparePlayback( *p_sys->p_current_vsegment, 0 ) ) { msg_Err( p_demux, "cannot use the segment" ); goto error; } p_sys->FreeUnused(); p_sys->InitUi(); return VLC_SUCCESS; error: delete p_sys; return VLC_EGENERIC; }
int OpenDemux( vlc_object_t* p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; const uint8_t *p_peek; ssize_t i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 ); if( unlikely( i_peek <= 32 ) ) return VLC_EGENERIC; const char *psz_xml = (const char *) p_peek; size_t i_xml = i_peek; /* Try to probe without xml module/loading the full document */ char *psz_alloc = NULL; switch( GetQWBE(p_peek) ) { /* See RFC 3023 Part 4 */ case UINT64_C(0xFFFE3C003F007800): /* UTF16 BOM<? */ case UINT64_C(0xFFFE3C003F007400): /* UTF16 BOM<t */ case UINT64_C(0xFEFF003C003F0078): /* UTF16 BOM<? */ case UINT64_C(0xFEFF003C003F0074): /* UTF16 BOM<t */ psz_alloc = FromCharset( "UTF-16", p_peek, i_peek ); break; case UINT64_C(0x3C003F0078006D00): /* UTF16-LE <?xm */ case UINT64_C(0x3C003F0074007400): /* UTF16-LE <tt */ psz_alloc = FromCharset( "UTF-16LE", p_peek, i_peek ); break; case UINT64_C(0x003C003F0078006D): /* UTF16-BE <?xm */ case UINT64_C(0x003C003F00740074): /* UTF16-BE <tt */ psz_alloc = FromCharset( "UTF-16BE", p_peek, i_peek ); break; case UINT64_C(0xEFBBBF3C3F786D6C): /* UTF8 BOM<?xml */ case UINT64_C(0x3C3F786D6C207665): /* UTF8 <?xml ve */ case UINT64_C(0xEFBBBF3C74742078): /* UTF8 BOM<tt x*/ break; default: if(GetDWBE(p_peek) != UINT32_C(0x3C747420)) /* tt node without xml document marker */ return VLC_EGENERIC; } if( psz_alloc ) { psz_xml = psz_alloc; i_xml = strlen( psz_alloc ); } /* Simplified probing. Valid TTML must have a namespace declaration */ const char *psz_tt = strnstr( psz_xml, "tt ", i_xml ); if( !psz_tt || psz_tt == psz_xml || (psz_tt[-1] != ':' && psz_tt[-1] != '<') ) { free( psz_alloc ); return VLC_EGENERIC; } else { const char * const rgsz[] = { "=\"http://www.w3.org/ns/ttml\"", "=\"http://www.w3.org/2004/11/ttaf1\"", "=\"http://www.w3.org/2006/04/ttaf1\"", "=\"http://www.w3.org/2006/10/ttaf1\"", }; const char *psz_ns = NULL; for( size_t i=0; i<ARRAY_SIZE(rgsz) && !psz_ns; i++ ) { psz_ns = strnstr( psz_xml, rgsz[i], i_xml - (psz_tt - psz_xml) ); } free( psz_alloc ); if( !psz_ns ) return VLC_EGENERIC; } p_demux->p_sys = p_sys = calloc( 1, sizeof( *p_sys ) ); if( unlikely( p_sys == NULL ) ) return VLC_ENOMEM; p_sys->b_first_time = true; p_sys->temporal_extent.i_type = TT_TIMINGS_PARALLEL; tt_time_Init( &p_sys->temporal_extent.begin ); tt_time_Init( &p_sys->temporal_extent.end ); tt_time_Init( &p_sys->temporal_extent.dur ); p_sys->temporal_extent.begin.base = 0; p_sys->p_xml = xml_Create( p_demux ); if( !p_sys->p_xml ) goto error; p_sys->p_reader = xml_ReaderCreate( p_sys->p_xml, p_demux->s ); if( !p_sys->p_reader ) goto error; #ifndef TTML_DEMUX_DEBUG p_sys->p_reader->obj.flags |= OBJECT_FLAGS_QUIET; #endif if( ReadTTML( p_demux ) != VLC_SUCCESS ) goto error; tt_timings_Resolve( (tt_basenode_t *) p_sys->p_rootnode, &p_sys->temporal_extent, &p_sys->times.p_array, &p_sys->times.i_count ); #ifdef TTML_DEMUX_DEBUG { struct vlc_memstream stream; if( vlc_memstream_open( &stream ) ) goto error; tt_time_t t; tt_time_Init( &t ); tt_node_ToText( &stream, (tt_basenode_t*)p_sys->p_rootnode, &t /* invalid */ ); vlc_memstream_putc( &stream, '\0' ); if( vlc_memstream_close( &stream ) == VLC_SUCCESS ) { msg_Dbg( p_demux, "%s", stream.ptr ); free( stream.ptr ); } } #endif p_demux->pf_demux = Demux; p_demux->pf_control = Control; es_format_t fmt; es_format_Init( &fmt, SPU_ES, VLC_CODEC_TTML ); p_sys->p_es = es_out_Add( p_demux->out, &fmt ); if( !p_sys->p_es ) goto error; es_format_Clean( &fmt ); return VLC_SUCCESS; error: CloseDemux( p_demux ); return VLC_EGENERIC; }
char *vlc_stream_ReadLine( stream_t *s ) { stream_priv_t *priv = (stream_priv_t *)s; char *p_line = NULL; int i_line = 0, i_read = 0; /* Let's fail quickly if this is a readdir access */ if( s->pf_read == NULL ) return NULL; for( ;; ) { char *psz_eol; const uint8_t *p_data; int i_data; int64_t i_pos; /* Probe new data */ i_data = vlc_stream_Peek( s, &p_data, STREAM_PROBE_LINE ); if( i_data <= 0 ) break; /* No more data */ /* BOM detection */ i_pos = vlc_stream_Tell( s ); if( i_pos == 0 && i_data >= 2 ) { const char *psz_encoding = NULL; if( !memcmp( p_data, "\xFF\xFE", 2 ) ) { psz_encoding = "UTF-16LE"; priv->text.little_endian = true; } else if( !memcmp( p_data, "\xFE\xFF", 2 ) ) { psz_encoding = "UTF-16BE"; } /* Open the converter if we need it */ if( psz_encoding != NULL ) { msg_Dbg( s, "UTF-16 BOM detected" ); priv->text.char_width = 2; priv->text.conv = vlc_iconv_open( "UTF-8", psz_encoding ); if( priv->text.conv == (vlc_iconv_t)-1 ) msg_Err( s, "iconv_open failed" ); } } if( i_data % priv->text.char_width ) { /* keep i_char_width boundary */ i_data = i_data - ( i_data % priv->text.char_width ); msg_Warn( s, "the read is not i_char_width compatible"); } if( i_data == 0 ) break; /* Check if there is an EOL */ if( priv->text.char_width == 1 ) { /* UTF-8: 0A <LF> */ psz_eol = memchr( p_data, '\n', i_data ); if( psz_eol == NULL ) /* UTF-8: 0D <CR> */ psz_eol = memchr( p_data, '\r', i_data ); } else { const uint8_t *p_last = p_data + i_data - priv->text.char_width; uint16_t eol = priv->text.little_endian ? 0x0A00 : 0x00A0; assert( priv->text.char_width == 2 ); psz_eol = NULL; /* UTF-16: 000A <LF> */ for( const uint8_t *p = p_data; p <= p_last; p += 2 ) { if( U16_AT( p ) == eol ) { psz_eol = (char *)p + 1; break; } } if( psz_eol == NULL ) { /* UTF-16: 000D <CR> */ eol = priv->text.little_endian ? 0x0D00 : 0x00D0; for( const uint8_t *p = p_data; p <= p_last; p += 2 ) { if( U16_AT( p ) == eol ) { psz_eol = (char *)p + 1; break; } } } } if( psz_eol ) { i_data = (psz_eol - (char *)p_data) + 1; p_line = realloc_or_free( p_line, i_line + i_data + priv->text.char_width ); /* add \0 */ if( !p_line ) goto error; i_data = vlc_stream_Read( s, &p_line[i_line], i_data ); if( i_data <= 0 ) break; /* Hmmm */ i_line += i_data - priv->text.char_width; /* skip \n */; i_read += i_data; /* We have our line */ break; } /* Read data (+1 for easy \0 append) */ p_line = realloc_or_free( p_line, i_line + STREAM_PROBE_LINE + priv->text.char_width ); if( !p_line ) goto error; i_data = vlc_stream_Read( s, &p_line[i_line], STREAM_PROBE_LINE ); if( i_data <= 0 ) break; /* Hmmm */ i_line += i_data; i_read += i_data; if( i_read >= STREAM_LINE_MAX ) goto error; /* line too long */ } if( i_read > 0 ) { memset(p_line + i_line, 0, priv->text.char_width); i_line += priv->text.char_width; /* the added \0 */ if( priv->text.char_width > 1 ) { int i_new_line = 0; size_t i_in = 0, i_out = 0; const char * p_in = NULL; char * p_out = NULL; char * psz_new_line = NULL; /* iconv */ /* UTF-8 needs at most 150% of the buffer as many as UTF-16 */ i_new_line = i_line * 3 / 2; psz_new_line = malloc( i_new_line ); if( psz_new_line == NULL ) goto error; i_in = (size_t)i_line; i_out = (size_t)i_new_line; p_in = p_line; p_out = psz_new_line; if( vlc_iconv( priv->text.conv, &p_in, &i_in, &p_out, &i_out ) == (size_t)-1 ) { msg_Err( s, "iconv failed" ); msg_Dbg( s, "original: %d, in %d, out %d", i_line, (int)i_in, (int)i_out ); } free( p_line ); p_line = psz_new_line; i_line = (size_t)i_new_line - i_out; /* does not include \0 */ } /* Remove trailing LF/CR */ while( i_line >= 2 && ( p_line[i_line-2] == '\r' || p_line[i_line-2] == '\n') ) i_line--; /* Make sure the \0 is there */ p_line[i_line-1] = '\0'; return p_line; } error: /* We failed to read any data, probably EOF */ free( p_line ); /* */ if( priv->text.conv != (vlc_iconv_t)(-1) ) { vlc_iconv_close( priv->text.conv ); priv->text.conv = (vlc_iconv_t)(-1); } return NULL; }
static int Open (vlc_object_t *obj) { demux_t *demux = (demux_t *)obj; demux_sys_t *sys = NULL; es_format_t fmt; bool result = false; SidTune *tune = NULL; sidplay2 *player = NULL; ReSIDBuilder *builder = NULL; int64_t size = stream_Size (demux->s); if (size < 4 || size > LONG_MAX) /* We need to load the whole file for sidplay */ return VLC_EGENERIC; const uint8_t *peek; if (vlc_stream_Peek (demux->s, &peek, 4) < 4) return VLC_EGENERIC; /* sidplay2 can read PSID and the newer RSID formats */ if(memcmp(peek,"PSID",4)!=0 && memcmp(peek,"RSID",4)!=0) return VLC_EGENERIC; uint8_t *data = (uint8_t*) malloc(size); if (unlikely (data==NULL)) goto error; if (vlc_stream_Read (demux->s,data,size) < size) { free (data); goto error; } tune = new (std::nothrow) SidTune(0); if (unlikely (tune==NULL)) { free (data); goto error; } result = tune->read (data, size); free (data); if (!result) goto error; player = new (std::nothrow) sidplay2(); if (unlikely(player==NULL)) goto error; sys = (demux_sys_t*) calloc (1, sizeof(demux_sys_t)); if (unlikely(sys==NULL)) goto error; sys->player = player; sys->tune = tune; tune->getInfo (sys->tuneInfo); sys->info = player->info(); sys->config = player->config(); builder = new (std::nothrow) ReSIDBuilder ("ReSID"); if (unlikely(builder==NULL)) goto error; builder->create (sys->info.maxsids); builder->sampling (sys->config.frequency); sys->config.sidEmulation = builder; sys->config.precision = 16; sys->config.playback = (sys->info.channels == 2 ? sid2_stereo : sid2_mono); player->config (sys->config); sys->bytes_per_frame = sys->info.channels * sys->config.precision / 8; sys->block_size = sys->config.frequency / 10 * sys->bytes_per_frame; es_format_Init (&fmt, AUDIO_ES, VLC_CODEC_S16N); fmt.audio.i_channels = sys->info.channels; fmt.audio.i_bitspersample = sys->config.precision; fmt.audio.i_rate = sys->config.frequency; fmt.audio.i_bytes_per_frame = sys->bytes_per_frame; fmt.audio.i_frame_length = fmt.audio.i_bytes_per_frame; fmt.audio.i_blockalign = fmt.audio.i_bytes_per_frame; fmt.i_bitrate = fmt.audio.i_rate * fmt.audio.i_bytes_per_frame; sys->es = es_out_Add (demux->out, &fmt); date_Init (&sys->pts, fmt.audio.i_rate, 1); date_Set (&sys->pts, 0); sys->tune->selectSong (0); result = (sys->player->load (sys->tune) >=0 ); sys->player->fastForward (100); if (!result) goto error; /* Callbacks */ demux->pf_demux = Demux; demux->pf_control = Control; demux->p_sys = sys; return VLC_SUCCESS; error: msg_Err (demux, "An error occurred during sid demuxing" ); delete player; delete builder; delete tune; free (sys); return VLC_EGENERIC; }
static bool PeekASX( demux_t *p_demux ) { const uint8_t *p_peek; return ( vlc_stream_Peek( p_demux->s, &p_peek, 12 ) == 12 && !memcmp( p_peek, "<asx version", 12 ) ); }
/***************************************************************************** * Open *****************************************************************************/ static int OpenCommon( vlc_object_t *p_this, bool b_force ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; const uint8_t *p_peek; ssize_t i_peek = 0; ssize_t i_offset = 0; ssize_t i_skip = 0; unsigned i_max_packets = PS_PACKET_PROBE; int format = MPEG_PS; int i_mux_rate = 0; vlc_tick_t i_length = VLC_TICK_INVALID; i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 16 ); if( i_peek < 16 ) { msg_Dbg( p_demux, "cannot peek" ); return VLC_EGENERIC; } if( !memcmp( p_peek, "PSMF", 4 ) && (GetDWBE( &p_peek[4] ) & 0x30303030) == 0x30303030 ) { i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 100 ); if( i_peek < 100 ) return VLC_EGENERIC; i_skip = i_offset = GetWBE( &p_peek[10] ); format = PSMF_PS; msg_Info( p_demux, "Detected PSMF-PS header"); i_mux_rate = GetDWBE( &p_peek[96] ); if( GetDWBE( &p_peek[86] ) > 0 ) i_length = vlc_tick_from_samples( GetDWBE( &p_peek[92] ), GetDWBE( &p_peek[86] )); } else if( !memcmp( p_peek, "RIFF", 4 ) && !memcmp( &p_peek[8], "CDXA", 4 ) ) { format = CDXA_PS; i_max_packets = 0; /* We can't probe here */ i_skip = CDXA_HEADER_SIZE; msg_Info( p_demux, "Detected CDXA-PS" ); /* FIXME: have a proper way to decap CD sectors or make an access stream filter */ } else if( b_force ) { msg_Warn( p_demux, "this does not look like an MPEG PS stream, " "continuing anyway" ); i_max_packets = 0; } for( unsigned i=0; i<i_max_packets; i++ ) { if( i_peek < i_offset + 16 ) { i_peek = vlc_stream_Peek( p_demux->s, &p_peek, i_offset + 16 ); if( i_peek < i_offset + 16 ) return VLC_EGENERIC; } const uint8_t startcode[3] = { 0x00, 0x00, 0x01 }; const uint8_t *p_header = &p_peek[i_offset]; if( memcmp( p_header, startcode, 3 ) || ( (p_header[3] & 0xB0) != 0xB0 && !(p_header[3] >= 0xC0 && p_header[3] <= 0xEF) && p_header[3] != PS_STREAM_ID_EXTENDED && p_header[3] != PS_STREAM_ID_DIRECTORY ) ) return VLC_EGENERIC; ssize_t i_pessize = ps_pkt_size( p_header, 16 ); if( i_pessize < 5 ) return VLC_EGENERIC; i_offset += i_pessize; } if( i_skip > 0 && !p_demux->b_preparsing && vlc_stream_Read( p_demux->s, NULL, i_skip ) != i_skip ) return VLC_EGENERIC; /* Fill p_demux field */ p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; p_demux->pf_demux = Demux; p_demux->pf_control = Control; /* Init p_sys */ p_sys->i_mux_rate = i_mux_rate; p_sys->i_pack_scr = VLC_TICK_INVALID; p_sys->i_first_scr = VLC_TICK_INVALID; p_sys->i_scr = VLC_TICK_INVALID; p_sys->i_scr_track_id = 0; p_sys->i_length = i_length; p_sys->i_current_pts = VLC_TICK_INVALID; p_sys->i_time_track_index = -1; p_sys->i_aob_mlp_count = 0; p_sys->i_start_byte = i_skip; p_sys->i_lastpack_byte = i_skip; p_sys->b_lost_sync = false; p_sys->b_have_pack = false; p_sys->b_bad_scr = false; p_sys->b_seekable = false; p_sys->format = format; p_sys->current_title = 0; p_sys->current_seekpoint = 0; p_sys->updates = 0; vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable ); ps_psm_init( &p_sys->psm ); ps_track_init( p_sys->tk ); /* TODO prescanning of ES */ return VLC_SUCCESS; }
/***************************************************************************** * Open: initializes ES structures *****************************************************************************/ static int Open( vlc_object_t * p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; const uint8_t *p_peek; es_format_t fmt; /* Have a peep at the show. */ if( vlc_stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) return VLC_EGENERIC; if( p_peek[0]!='f' || p_peek[1]!='L' || p_peek[2]!='a' || p_peek[3]!='C' ) { if( !p_demux->obj.force && !demux_IsContentType( p_demux, "audio/flac" ) ) return VLC_EGENERIC; /* User forced */ msg_Err( p_demux, "this doesn't look like a flac stream, " "continuing anyway" ); } p_sys = malloc( sizeof( demux_sys_t ) ); if( unlikely(p_sys == NULL) ) return VLC_ENOMEM; p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys; p_sys->b_start = true; p_sys->i_next_block_flags = 0; p_sys->p_packetizer = NULL; p_sys->p_meta = NULL; p_sys->i_length = 0; p_sys->i_pts = VLC_TS_INVALID; p_sys->p_es = NULL; p_sys->p_current_block = NULL; TAB_INIT( p_sys->i_seekpoint, p_sys->seekpoint ); TAB_INIT( p_sys->i_attachments, p_sys->attachments); TAB_INIT( p_sys->i_title_seekpoints, p_sys->pp_title_seekpoints ); p_sys->i_cover_idx = 0; p_sys->i_cover_score = 0; es_format_Init( &fmt, AUDIO_ES, VLC_CODEC_FLAC ); /* We need to read and store the STREAMINFO metadata into fmt extra */ if( ParseHeaders( p_demux, &fmt ) ) goto error; /* Load the FLAC packetizer */ p_sys->p_packetizer = demux_PacketizerNew( p_demux, &fmt, "flac" ); if( !p_sys->p_packetizer ) goto error; if( p_sys->i_cover_idx < p_sys->i_attachments ) { char psz_url[128]; if( !p_sys->p_meta ) p_sys->p_meta = vlc_meta_New(); snprintf( psz_url, sizeof(psz_url), "attachment://%s", p_sys->attachments[p_sys->i_cover_idx]->psz_name ); vlc_meta_Set( p_sys->p_meta, vlc_meta_ArtworkURL, psz_url ); } p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_in ); if( !p_sys->p_es ) goto error; return VLC_SUCCESS; error: Close( p_this ); return VLC_EGENERIC; }
/***************************************************************************** * Validate: try to ensure it is really a mod file. * The tests are not robust enough to replace extension checks in the general * cases. * TODO: maybe it should return a score, which will be used to bypass the * extension checks when high enough. *****************************************************************************/ static int Validate( demux_t *p_demux, const char *psz_ext ) { static const struct { int i_offset; const char *psz_marker; } p_marker[] = { { 0, "ziRCONia" }, /* MMCMP files */ { 0, "Extended Module" }, /* XM */ { 44, "SCRM" }, /* S3M */ { 0, "IMPM" }, /* IT */ { 0, "GF1PATCH110" }, /* PAT */ { 20, "!SCREAM!" }, /* STM */ { 20, "!Scream!" }, /* STM */ { 20, "BMOD2STM" }, /* STM */ { 0, "MMD0" }, /* MED v0 */ { 0, "MMD1" }, /* MED v1 */ { 0, "MMD2" }, /* MED v2 */ { 0, "MMD3" }, /* MED v3 */ { 0, "MTM" }, /* MTM */ { 0, "DMDL" }, /* MDL */ { 0, "DBM0" }, /* DBM */ { 0, "if" }, /* 669 */ { 0, "JN" }, /* 669 */ { 0, "FAR\xfe" }, /* FAR */ { 0, "Extreme" }, /* AMS */ { 0, "OKTASONGCMOD" }, /* OKT */ { 44, "PTMF" }, /* PTM */ { 0, "MAS_UTrack_V00" }, /* Ult */ { 0, "DDMF" }, /* DMF */ { 8, "DSMFSONG" }, /* DSM */ { 0, "\xc1\x83\x2a\x9e" }, /* UMX */ { 0, "ASYLUM Music Format V1.0" }, /* AMF Type 0 */ { 0, "AMF" }, /* AMF */ { 0, "PSM\xfe" }, /* PSM */ { 0, "PSM " }, /* PSM */ { 0, "MT20" }, /* MT2 */ { 1080, "M.K." }, /* MOD */ { 1080, "M!K!" }, { 1080, "M&K!" }, { 1080, "N.T." }, { 1080, "CD81" }, { 1080, "OKTA" }, { 1080, "16CN" }, { 1080, "32CN" }, { 1080, "FLT4" }, { 1080, "FLT8" }, { 1080, "6CHN" }, { 1080, "8CHN" }, { 1080, "FLT" }, { 1080, "TDZ" }, { 1081, "CHN" }, { 1082, "CH" }, { -1, NULL } }; static const char *ppsz_mod_ext[] = { "mod", "s3m", "xm", "it", "669", "amf", "ams", "dbm", "dmf", "dsm", "far", "mdl", "med", "mtm", "okt", "ptm", "stm", "ult", "umx", "mt2", "psm", "abc", NULL }; bool has_valid_extension = false; if( psz_ext ) { for( int i = 0; ppsz_mod_ext[i] != NULL; i++ ) { has_valid_extension |= !strcasecmp( psz_ext, ppsz_mod_ext[i] ); if( has_valid_extension ) break; } } const uint8_t *p_peek; const int i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 ); if( i_peek < 4 ) return VLC_EGENERIC; for( int i = 0; p_marker[i].i_offset >= 0; i++ ) { const char *psz_marker = p_marker[i].psz_marker; const int i_size = strlen( psz_marker ); const int i_offset = p_marker[i].i_offset; if( i_peek < i_offset + i_size ) continue; if( !memcmp( &p_peek[i_offset], psz_marker, i_size ) ) { if( i_size >= 4 || has_valid_extension ) return VLC_SUCCESS; } } /* The only two format left untested are ABC and MOD(old version) * ant they are difficult to test :( */ /* Check for ABC * TODO i_peek = 2048 is too big for such files */ if( psz_ext && !strcasecmp( psz_ext, "abc" ) ) { bool b_k = false; bool b_tx = false; for( int i = 0; i < i_peek-1; i++ ) { b_k |= p_peek[i+0] == 'K' && p_peek[i+1] == ':'; b_tx |= ( p_peek[i+0] == 'X' || p_peek[i+0] == 'T') && p_peek[i+1] == ':'; } if( !b_k || !b_tx ) return VLC_EGENERIC; return VLC_SUCCESS; } /* Check for MOD */ if( psz_ext && !strcasecmp( psz_ext, "mod" ) && i_peek >= 20 + 15 * 30 ) { /* Check that the name is correctly null padded */ const uint8_t *p = memchr( p_peek, '\0', 20 ); if( p ) { for( ; p < &p_peek[20]; p++ ) { if( *p ) return VLC_EGENERIC; } } for( int i = 0; i < 15; i++ ) { const uint8_t *p_sample = &p_peek[20 + i*30]; /* Check correct null padding */ p = memchr( &p_sample[0], '\0', 22 ); if( p ) { for( ; p < &p_sample[22]; p++ ) { if( *p ) return VLC_EGENERIC; } } if( p_sample[25] > 64 ) /* Volume value */ return VLC_EGENERIC; } return VLC_SUCCESS; } return VLC_EGENERIC; }
static int Open(vlc_object_t *object) { demux_t *demux = (demux_t*)object; const uint8_t *peek; if (vlc_stream_Peek(demux->s, &peek, 11) != 11) return VLC_EGENERIC; bool is_stl_25 = !memcmp(&peek[3], "STL25.01", 8); bool is_stl_30 = !memcmp(&peek[3], "STL30.01", 8); if (!is_stl_25 && !is_stl_30) return VLC_EGENERIC; const double fps = is_stl_25 ? 25 : 30; uint8_t header[1024]; if (vlc_stream_Read(demux->s, header, sizeof(header)) != sizeof(header)) { msg_Err(demux, "Incomplete EBU STL header"); return VLC_EGENERIC; } const int cct = ParseInteger(&header[12], 2); const mtime_t program_start = ParseTextTimeCode(&header[256], fps); const int tti_count = ParseInteger(&header[238], 5); msg_Dbg(demux, "Detected EBU STL : CCT=%d TTI=%d start=%8.8s %"PRId64, cct, tti_count, &header[256], program_start); demux_sys_t *sys = xmalloc(sizeof(*sys)); sys->next_date = 0; sys->current = 0; sys->count = 0; sys->index = xcalloc(tti_count, sizeof(*sys->index)); bool comment = false; stl_entry_t *s = &sys->index[0]; s->count = 0; for (int i = 0; i < tti_count; i++) { uint8_t tti[16]; if (vlc_stream_Read(demux->s, tti, 16) != 16 || vlc_stream_Read(demux->s, NULL, 112) != 112) { msg_Warn(demux, "Incomplete EBU STL file"); break; } const int ebn = tti[3]; if (ebn >= 0xf0 && ebn <= 0xfd) continue; if (ebn == 0xfe) continue; if (s->count <= 0) { comment = tti[15] != 0; s->start = ParseTimeCode(&tti[5], fps) - program_start; s->stop = ParseTimeCode(&tti[9], fps) - program_start; s->index = i; } s->count++; if (ebn == 0xff && !comment) s = &sys->index[++sys->count]; if (ebn == 0xff && sys->count < tti_count) s->count = 0; } if (sys->count > 0) vlc_stream_Seek(demux->s, 1024 + 128LL * sys->index[0].index); es_format_t fmt; es_format_Init(&fmt, SPU_ES, VLC_CODEC_EBU_STL); fmt.i_extra = sizeof(header); fmt.p_extra = header; sys->es = es_out_Add(demux->out, &fmt); fmt.i_extra = 0; fmt.p_extra = NULL; es_format_Clean(&fmt); demux->p_sys = sys; demux->pf_demux = Demux; demux->pf_control = Control; return VLC_SUCCESS; }
static int avformat_ProbeDemux( vlc_object_t *p_this, AVInputFormat **pp_fmt, const char *psz_url ) { demux_t *p_demux = (demux_t*)p_this; AVProbeData pd = { 0 }; const uint8_t *peek; /* Init Probe data */ pd.buf_size = vlc_stream_Peek( p_demux->s, &peek, 2048 + 213 ); if( pd.buf_size <= 0 ) { msg_Warn( p_demux, "cannot peek" ); return VLC_EGENERIC; } pd.buf = malloc( pd.buf_size + AVPROBE_PADDING_SIZE ); if( unlikely(pd.buf == NULL) ) return VLC_ENOMEM; memcpy( pd.buf, peek, pd.buf_size ); memset( pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE ); if( psz_url != NULL ) msg_Dbg( p_demux, "trying url: %s", psz_url ); pd.filename = psz_url; vlc_init_avformat(p_this); /* Guess format */ char *psz_format = var_InheritString( p_this, "avformat-format" ); if( psz_format ) { if( (*pp_fmt = av_find_input_format(psz_format)) ) msg_Dbg( p_demux, "forcing format: %s", (*pp_fmt)->name ); free( psz_format ); } if( *pp_fmt == NULL ) *pp_fmt = av_probe_input_format( &pd, 1 ); free( pd.buf ); if( *pp_fmt == NULL ) { msg_Dbg( p_demux, "couldn't guess format" ); return VLC_EGENERIC; } if( !p_demux->obj.force ) { static const char ppsz_blacklist[][16] = { /* Don't handle MPEG unless forced */ "mpeg", "vcd", "vob", "mpegts", /* libavformat's redirector won't work */ "redir", "sdp", /* Don't handle subtitles format */ "ass", "srt", "microdvd", /* No timestamps at all */ "hevc", "h264", "" }; for( int i = 0; *ppsz_blacklist[i]; i++ ) { if( !strcmp( (*pp_fmt)->name, ppsz_blacklist[i] ) ) return VLC_EGENERIC; } } /* Don't trigger false alarms on bin files */ if( !p_demux->obj.force && !strcmp( (*pp_fmt)->name, "psxstr" ) ) { int i_len; if( !p_demux->psz_filepath ) return VLC_EGENERIC; i_len = strlen( p_demux->psz_filepath ); if( i_len < 4 ) return VLC_EGENERIC; if( strcasecmp( &p_demux->psz_filepath[i_len - 4], ".str" ) && strcasecmp( &p_demux->psz_filepath[i_len - 4], ".xai" ) && strcasecmp( &p_demux->psz_filepath[i_len - 3], ".xa" ) ) { return VLC_EGENERIC; } } msg_Dbg( p_demux, "detected format: %s", (*pp_fmt)->name ); return VLC_SUCCESS; }