static ssize_t SeekCallback(struct archive *p_archive, void *p_object, ssize_t i_offset, int i_whence) { VLC_UNUSED(p_archive); callback_data_t *p_data = (callback_data_t *) p_object; access_sys_t *p_sys = p_data->p_access->p_sys; ssize_t i_pos; switch(i_whence) { case SEEK_CUR: i_pos = stream_Tell(p_sys->p_stream); break; case SEEK_SET: i_pos = 0; break; case SEEK_END: i_pos = stream_Size(p_sys->p_stream) - 1; break; default: return -1; } if (i_pos < 0) return -1; stream_Seek(p_sys->p_stream, i_pos + i_offset); /* We don't care about return val */ return stream_Tell(p_sys->p_stream); }
void vlc_stream_io_callback::setFilePointer(int64_t i_offset, seek_mode mode ) { int64_t i_pos, i_size; switch( mode ) { case seek_beginning: i_pos = i_offset; break; case seek_end: i_pos = stream_Size( s ) - i_offset; break; default: i_pos= stream_Tell( s ) + i_offset; break; } if( i_pos < 0 || ( ( i_size = stream_Size( s ) ) != 0 && i_pos >= i_size ) ) { mb_eof = true; return; } mb_eof = false; if( stream_Seek( s, i_pos ) ) { mb_eof = true; } return; }
static int Seek(access_t *access, uint64_t position) { access_sys_t *sys = access->p_sys; const rar_file_t *file = sys->file; if (position > file->real_size) position = file->real_size; /* Search the chunk */ const rar_file_chunk_t *old_chunk = sys->chunk; for (int i = 0; i < file->chunk_count; i++) { sys->chunk = file->chunk[i]; if (position < sys->chunk->cummulated_size + sys->chunk->size) break; } access->info.i_pos = position; access->info.b_eof = false; const uint64_t offset = sys->chunk->offset + (position - sys->chunk->cummulated_size); if (strcmp(old_chunk->mrl, sys->chunk->mrl)) { if (sys->s) stream_Delete(sys->s); sys->s = stream_UrlNew(access, sys->chunk->mrl); } return sys->s ? stream_Seek(sys->s, offset) : VLC_EGENERIC; }
static ssize_t SkipCallback(struct archive *p_archive, void *p_object, ssize_t i_request) { VLC_UNUSED(p_archive); callback_data_t *p_data = (callback_data_t *) p_object; access_sys_t *p_sys = p_data->p_access->p_sys; ssize_t i_skipped = 0; /* be smart as small seeks converts to reads */ if (p_sys->b_source_canseek) { int64_t i_pos = stream_Tell(p_sys->p_stream); if (i_pos >=0) stream_Seek(p_sys->p_stream, i_pos + i_request); i_skipped = stream_Tell(p_sys->p_stream) - i_pos; } else while(i_request) { int i_skip = __MIN(INT32_MAX, i_request); int i_read = stream_Read(p_sys->p_stream, NULL, i_skip); if (i_read > 0) i_skipped += i_read; else break; i_request -= i_read; } return i_skipped; }
static int Seek( stream_t *p_stream, uint64_t i_pos ) { int i_ret = stream_Seek( p_stream->p_source, i_pos ); if ( i_ret == VLC_SUCCESS ) RemainFlush( p_stream->p_sys ); return i_ret; }
/***************************************************************************** * ParseTags: check if ID3/APE tags at common locations. ****************************************************************************/ static int ParseTags( vlc_object_t *p_this ) { demux_meta_t *p_demux_meta = (demux_meta_t *)p_this; demux_t *p_demux = (demux_t *)p_demux_meta->p_demux; bool b_seekable; int64_t i_init; msg_Dbg( p_demux_meta, "checking for ID3v1/2 and APEv1/2 tags" ); stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_seekable ); if( !b_seekable ) return VLC_EGENERIC; i_init = stream_Tell( p_demux->s ); TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments ); p_demux_meta->p_meta = NULL; /* */ CheckFooter( p_demux_meta ); /* */ CheckHeader( p_demux_meta ); /* Restore position * Demuxer will not see tags at the start as src/input/demux.c skips it * for them */ stream_Seek( p_demux->s, i_init ); if( !p_demux_meta->p_meta && p_demux_meta->i_attachments <= 0 ) return VLC_EGENERIC; return VLC_SUCCESS; }
static void CheckHeader( demux_meta_t *p_demux_meta ) { const uint8_t *p_peek; int i_size; demux_t *p_demux = (demux_t *)p_demux_meta->p_demux; if( stream_Seek( p_demux->s, 0 ) ) return; /* Test ID3v2 first */ if( stream_Peek( p_demux->s, &p_peek, ID3_TAG_QUERYSIZE ) != ID3_TAG_QUERYSIZE ) return; i_size = id3_tag_query( p_peek, ID3_TAG_QUERYSIZE ); if( i_size > 0 && stream_Peek( p_demux->s, &p_peek, i_size ) == i_size ) { msg_Dbg( p_demux, "found ID3v2 tag" ); ParseID3Tag( p_demux_meta, p_peek, i_size ); return; } /* Test APEv1 */ if( stream_Peek( p_demux->s, &p_peek, APE_TAG_HEADERSIZE ) != APE_TAG_HEADERSIZE ) return; i_size = GetAPEvXSize( p_peek, APE_TAG_HEADERSIZE ); if( i_size > 0 && stream_Peek( p_demux->s, &p_peek, i_size ) == i_size ) { msg_Dbg( p_demux, "found APEv1/2 tag" ); ParseAPEvXTag( p_demux_meta, p_peek, i_size ); } }
static int AVI_NextChunk( stream_t *s, avi_chunk_t *p_chk ) { avi_chunk_t chk; if( !p_chk ) { if( AVI_ChunkReadCommon( s, &chk ) ) { return VLC_EGENERIC; } p_chk = &chk; } if( p_chk->common.p_father ) { if( p_chk->common.p_father->common.i_chunk_pos + __EVEN( p_chk->common.p_father->common.i_chunk_size ) + 8 < p_chk->common.i_chunk_pos + __EVEN( p_chk->common.i_chunk_size ) + 8 ) { return VLC_EGENERIC; } } return stream_Seek( s, p_chk->common.i_chunk_pos + __EVEN( p_chk->common.i_chunk_size ) + 8 ); }
static int SeekSet0 (demux_t *demux) { stream_t *stream = demux->s; demux_sys_t *sys = demux->p_sys; /* Default SMF tempo is 120BPM, i.e. half a second per quarter note */ date_Init (&sys->pts, sys->ppqn * 2, 1); date_Set (&sys->pts, VLC_TS_0); sys->pulse = 0; sys->tick = VLC_TS_0; for (unsigned i = 0; i < sys->trackc; i++) { mtrk_t *tr = sys->trackv + i; tr->offset = 0; tr->next = 0; /* Why 0xF6 (Tuning Calibration)? * Because it has zero bytes of data, so the parser will detect the * error if the first event uses running status. */ tr->running_event = 0xF6; if (stream_Seek (stream, tr->start) || ReadDeltaTime (stream, tr)) { msg_Err (demux, "fatal parsing error"); return -1; } } return 0; }
static bool IsTarga(stream_t *s) { /* The header is not enough to ensure proper detection, we need * to have a look at the footer. But doing so can be slow. So * try to avoid it when possible */ const uint8_t *header; if (stream_Peek(s, &header, 18) < 18) /* Targa fixed header */ return false; if (header[1] > 1) /* Color Map Type */ return false; if ((header[1] != 0 || header[3 + 4] != 0) && header[3 + 4] != 8 && header[3 + 4] != 15 && header[3 + 4] != 16 && header[3 + 4] != 24 && header[3 + 4] != 32) return false; if ((header[2] > 3 && header[2] < 9) || header[2] > 11) /* Image Type */ return false; if (GetWLE(&header[8 + 4]) <= 0 || /* Width */ GetWLE(&header[8 + 6]) <= 0) /* Height */ return false; if (header[8 + 8] != 8 && header[8 + 8] != 15 && header[8 + 8] != 16 && header[8 + 8] != 24 && header[8 + 8] != 32) return false; if (header[8 + 9] & 0xc0) /* Reserved bits */ return false; const int64_t size = stream_Size(s); if (size <= 18 + 26) return false; bool can_seek; if (stream_Control(s, STREAM_CAN_SEEK, &can_seek) || !can_seek) return false; const int64_t position = stream_Tell(s); if (stream_Seek(s, size - 26)) return false; const uint8_t *footer; bool is_targa = stream_Peek(s, &footer, 26) >= 26 && !memcmp(&footer[8], "TRUEVISION-XFILE.\x00", 18); stream_Seek(s, position); return is_targa; }
/** ************************************************************************** * \brief seek in the stream * \param opaque should be the stream * \param stream stream created by ZipIO_Open * \param offset positive offset to seek * \param origin current position in stream * \return ¿ VLC_SUCCESS or an error code ? *****************************************************************************/ static long ZCALLBACK ZipIO_Seek ( void *opaque, void *stream, unsigned long offset, int origin ) { (void) stream; stream_t *s = (stream_t*) opaque; long l_ret; uint64_t pos = offset + origin; l_ret = (long) stream_Seek( s->p_source, pos ); return l_ret; }
static void seek_byte( demux_t *p_demux, int64_t i_pos ) { demux_sys_t *p_sys = p_demux->p_sys; if ( ! stream_Seek( p_demux->s, i_pos ) ) { ogg_sync_reset( &p_sys->oy ); p_sys->i_input_position = i_pos; p_sys->b_page_waiting = false; } }
/***************************************************************************** * 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( 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( 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; } 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; }
/* Allow to append indexes after starting playback */ int AVI_ChunkFetchIndexes( stream_t *s, avi_chunk_t *p_riff ) { avi_chunk_t *p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0 ); if ( !p_movi ) return VLC_EGENERIC; avi_chunk_t *p_chk; uint64_t i_indexpos = 8 + p_movi->common.i_chunk_pos + p_movi->common.i_chunk_size; bool b_seekable = false; int i_ret = VLC_SUCCESS; stream_Control( s, STREAM_CAN_SEEK, &b_seekable ); if ( !b_seekable || stream_Seek( s, i_indexpos ) ) return VLC_EGENERIC; for( ; ; ) { p_chk = xmalloc( sizeof( avi_chunk_t ) ); memset( p_chk, 0, sizeof( avi_chunk_t ) ); if (unlikely( !p_riff->common.p_first )) p_riff->common.p_first = p_chk; else p_riff->common.p_last->common.p_next = p_chk; p_riff->common.p_last = p_chk; i_ret = AVI_ChunkRead( s, p_chk, p_riff ); if( i_ret ) break; if( p_chk->common.p_father->common.i_chunk_size > 0 && ( stream_Tell( s ) > (off_t)p_chk->common.p_father->common.i_chunk_pos + (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) ) { break; } /* If we can't seek then stop when we 've found any index */ if( p_chk->common.i_chunk_fourcc == AVIFOURCC_indx || p_chk->common.i_chunk_fourcc == AVIFOURCC_idx1 ) { break; } } return i_ret; }
static int ControlSetTime( demux_t *p_demux, int64_t i_time ) { demux_sys_t *p_sys = p_demux->p_sys; int64_t i_delta_time; bool b_seekable; int i; /* */ stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_seekable ); if( !b_seekable ) return VLC_EGENERIC; /* */ assert( p_sys->i_seekpoint > 0 ); /* ReadMeta ensure at least (0,0) */ for( i = p_sys->i_seekpoint-1; i >= 0; i-- ) { if( p_sys->seekpoint[i]->i_time_offset <= i_time ) break; } i_delta_time = i_time - p_sys->seekpoint[i]->i_time_offset; /* XXX We do exact seek if it's not too far away(45s) */ if( i_delta_time < 45*INT64_C(1000000) ) { if( stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos ) ) return VLC_EGENERIC; p_sys->i_time_offset = p_sys->seekpoint[i]->i_time_offset - p_sys->i_pts; p_sys->i_pts_start = p_sys->i_pts+i_delta_time; es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, p_sys->i_pts_start + p_sys->i_time_offset ); } else { int64_t i_delta_offset; int64_t i_next_time; int64_t i_next_offset; if( i+1 < p_sys->i_seekpoint ) { i_next_time = p_sys->seekpoint[i+1]->i_time_offset; i_next_offset = p_sys->seekpoint[i+1]->i_byte_offset; } else { i_next_time = p_sys->i_length; i_next_offset = stream_Size(p_demux->s)-p_sys->i_data_pos; } i_delta_offset = 0; if( i_next_time-p_sys->seekpoint[i]->i_time_offset > 0 ) i_delta_offset = (i_next_offset - p_sys->seekpoint[i]->i_byte_offset) * i_delta_time / (i_next_time-p_sys->seekpoint[i]->i_time_offset); if( stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos + i_delta_offset ) ) return VLC_EGENERIC; p_sys->i_pts_start = p_sys->i_pts; p_sys->i_time_offset = (p_sys->seekpoint[i]->i_time_offset+i_delta_time) - p_sys->i_pts; } return VLC_SUCCESS; }
static int AStreamSeekStream(stream_t *s, uint64_t i_pos) { stream_sys_t *sys = s->p_sys; stream_track_t *p_current = &sys->tk[sys->i_tk]; if (p_current->i_start >= p_current->i_end && i_pos >= p_current->i_end) return 0; /* EOF */ #ifdef STREAM_DEBUG msg_Dbg(s, "AStreamSeekStream: to %"PRId64" pos=%"PRId64 " tk=%d start=%"PRId64" offset=%d end=%"PRId64, i_pos, sys->i_pos, sys->i_tk, p_current->i_start, sys->i_offset, p_current->i_end); #endif bool b_aseek; stream_Control(s->p_source, STREAM_CAN_SEEK, &b_aseek); if (!b_aseek && i_pos < p_current->i_start) { msg_Warn(s, "AStreamSeekStream: can't seek"); return VLC_EGENERIC; } bool b_afastseek; stream_Control(s->p_source, STREAM_CAN_FASTSEEK, &b_afastseek); /* FIXME compute seek cost (instead of static 'stupid' value) */ uint64_t i_skip_threshold; if (b_aseek) i_skip_threshold = b_afastseek ? 128 : 3 * sys->i_read_size; else i_skip_threshold = INT64_MAX; /* Date the current track */ p_current->date = mdate(); /* Search a new track slot */ stream_track_t *tk = NULL; int i_tk_idx = -1; /* Prefer the current track */ if (p_current->i_start <= i_pos && i_pos <= p_current->i_end + i_skip_threshold) { tk = p_current; i_tk_idx = sys->i_tk; } if (!tk) { /* Try to maximize already read data */ for (int i = 0; i < STREAM_CACHE_TRACK; i++) { stream_track_t *t = &sys->tk[i]; if (t->i_start > i_pos || i_pos > t->i_end) continue; if (!tk || tk->i_end < t->i_end) { tk = t; i_tk_idx = i; } } } if (!tk) { /* Use the oldest unused */ for (int i = 0; i < STREAM_CACHE_TRACK; i++) { stream_track_t *t = &sys->tk[i]; if (!tk || tk->date > t->date) { tk = t; i_tk_idx = i; } } } assert(i_tk_idx >= 0 && i_tk_idx < STREAM_CACHE_TRACK); if (tk != p_current) i_skip_threshold = 0; if (tk->i_start <= i_pos && i_pos <= tk->i_end + i_skip_threshold) { #ifdef STREAM_DEBUG msg_Err(s, "AStreamSeekStream: reusing %d start=%"PRId64 " end=%"PRId64"(%s)", i_tk_idx, tk->i_start, tk->i_end, tk != p_current ? "seek" : i_pos > tk->i_end ? "skip" : "noseek"); #endif if (tk != p_current) { assert(b_aseek); /* Seek at the end of the buffer * TODO it is stupid to seek now, it would be better to delay it */ if (stream_Seek(s->p_source, tk->i_end)) { msg_Err(s, "AStreamSeekStream: hard seek failed"); return VLC_EGENERIC; } } else if (i_pos > tk->i_end) { uint64_t i_skip = i_pos - tk->i_end; while (i_skip > 0) { const int i_read_max = __MIN(10 * STREAM_READ_ATONCE, i_skip); int i_read = 0; if ((i_read = AStreamReadNoSeekStream(s, NULL, i_read_max)) < 0) { msg_Err(s, "AStreamSeekStream: skip failed"); return VLC_EGENERIC; } else if (i_read == 0) return VLC_SUCCESS; /* EOF */ i_skip -= i_read_max; } } } else { #ifdef STREAM_DEBUG msg_Err(s, "AStreamSeekStream: hard seek"); #endif /* Nothing good, seek and choose oldest segment */ if (stream_Seek(s->p_source, i_pos)) { msg_Err(s, "AStreamSeekStream: hard seek failed"); return VLC_EGENERIC; } tk->i_start = i_pos; tk->i_end = i_pos; } sys->i_offset = i_pos - tk->i_start; sys->i_tk = i_tk_idx; sys->i_pos = i_pos; /* If there is not enough data left in the track, refill */ /* TODO How to get a correct value for * - refilling threshold * - how much to refill */ if (tk->i_end < tk->i_start + sys->i_offset + sys->i_read_size) { if (sys->i_used < STREAM_READ_ATONCE / 2) sys->i_used = STREAM_READ_ATONCE / 2; if (AStreamRefillStream(s)) return VLC_EGENERIC; } return VLC_SUCCESS; }
int RarAccessOpen(vlc_object_t *object) { access_t *access = (access_t*)object; const char *name = strchr(access->psz_location, '|'); if (name == NULL) return VLC_EGENERIC; char *base = strndup(access->psz_location, name - access->psz_location); if (unlikely(base == NULL)) return VLC_ENOMEM; name++; decode_URI(base); stream_t *s = stream_UrlNew(access, base); if (!s || RarProbe(s)) goto error; struct { int filescount; rar_file_t **files; unsigned int i_nbvols; } newscheme = { 0, NULL, 0 }, oldscheme = { 0, NULL, 0 }, *p_scheme; if (RarParse(s, &newscheme.filescount, &newscheme.files, &newscheme.i_nbvols, false) || newscheme.filescount < 1 || newscheme.i_nbvols < 2 ) { /* We might want to lookup old naming scheme, could be a part1.rar,part1.r00 */ stream_Seek(s, 0); RarParse(s, &oldscheme.filescount, &oldscheme.files, &oldscheme.i_nbvols, true); } if (oldscheme.filescount >= newscheme.filescount && oldscheme.i_nbvols > newscheme.i_nbvols) { for (int i = 0; i < newscheme.filescount; i++) RarFileDelete(newscheme.files[i]); free(newscheme.files); p_scheme = &oldscheme; msg_Dbg(s, "using rar old naming for %d files nbvols %u", p_scheme->filescount, oldscheme.i_nbvols); } else if (newscheme.filescount) { for (int i = 0; i < oldscheme.filescount; i++) RarFileDelete(oldscheme.files[i]); free(oldscheme.files); p_scheme = &newscheme; msg_Dbg(s, "using rar new naming for %d files nbvols %u", p_scheme->filescount, oldscheme.i_nbvols); } else { msg_Info(s, "Invalid or unsupported RAR archive"); for (int i = 0; i < oldscheme.filescount; i++) RarFileDelete(oldscheme.files[i]); free(oldscheme.files); for (int i = 0; i < newscheme.filescount; i++) RarFileDelete(newscheme.files[i]); free(newscheme.files); goto error; } rar_file_t *file = NULL; for (int i = 0; i < p_scheme->filescount; i++) { if (!file && !strcmp(p_scheme->files[i]->name, name)) file = p_scheme->files[i]; else RarFileDelete(p_scheme->files[i]); } free(p_scheme->files); if (!file) goto error; access_sys_t *sys = access->p_sys = malloc(sizeof(*sys)); sys->s = s; sys->file = file; access->pf_read = Read; access->pf_block = NULL; access->pf_control = Control; access->pf_seek = Seek; access_InitFields(access); rar_file_chunk_t dummy = { .mrl = base, }; sys->chunk = &dummy; Seek(access, 0); free(base); return VLC_SUCCESS; error: if (s) stream_Delete(s); free(base); return VLC_EGENERIC; }
static int HandleMessage (demux_t *p_demux, mtrk_t *tr) { stream_t *s = p_demux->s; block_t *block; uint8_t first, event; unsigned datalen; if (stream_Seek (s, tr->offset) || (stream_Read (s, &first, 1) != 1)) return -1; event = (first & 0x80) ? first : tr->running_event; switch (event & 0xf0) { case 0xF0: /* System Exclusive */ switch (event) { case 0xF0: /* System Specific start */ case 0xF7: /* System Specific continuation */ { /* Variable length followed by SysEx event data */ int32_t len = ReadVarInt (s); if (len == -1) return -1; block = stream_Block (s, len); if (block == NULL) return -1; block = block_Realloc (block, 1, len); if (block == NULL) return -1; block->p_buffer[0] = event; goto send; } case 0xFF: /* SMF Meta Event */ if (HandleMeta (p_demux, tr)) return -1; /* We MUST NOT pass this event forward. It would be * confused as a MIDI Reset real-time event. */ goto skip; case 0xF1: case 0xF3: datalen = 1; break; case 0xF2: datalen = 2; break; case 0xF4: case 0xF5: /* We cannot handle undefined "common" (non-real-time) * events inside SMF, as we cannot differentiate a * one byte delta-time (< 0x80) from event data. */ default: datalen = 0; break; } break; case 0xC0: case 0xD0: datalen = 1; break; default: datalen = 2; break; } /* FIXME: one message per block is very inefficient */ block = block_New (p_demux, 1 + datalen); if (block == NULL) goto skip; block->p_buffer[0] = event; if (first & 0x80) { stream_Read (s, block->p_buffer + 1, datalen); } else { if (datalen == 0) { msg_Err (p_demux, "malformatted MIDI event"); return -1; /* can't use implicit running status with empty payload! */ } block->p_buffer[1] = first; if (datalen > 1) stream_Read (s, block->p_buffer + 2, datalen - 1); } send: block->i_dts = block->i_pts = VLC_TS_0 + date_Get (&p_demux->p_sys->pts); es_out_Send (p_demux->out, p_demux->p_sys->es, block); skip: if (event < 0xF8) /* If event is not real-time, update running status */ tr->running_event = event; tr->offset = stream_Tell (s); return 0; }
/***************************************************************************** * Open: check file and initializes structures *****************************************************************************/ static int Open (vlc_object_t * p_this) { demux_t *p_demux = (demux_t *)p_this; stream_t *stream = p_demux->s; demux_sys_t *p_sys; const uint8_t *peek; unsigned tracks, ppqn; bool multitrack; /* (Try to) parse the SMF header */ /* Header chunk always has 6 bytes payload */ if (stream_Peek (stream, &peek, 14) < 14) return VLC_EGENERIC; /* Skip RIFF MIDI header if present */ if (!memcmp (peek, "RIFF", 4) && !memcmp (peek + 8, "RMID", 4)) { uint32_t riff_len = GetDWLE (peek + 4); msg_Dbg (p_this, "detected RIFF MIDI file (%u bytes)", (unsigned)riff_len); if ((stream_Read (stream, NULL, 12) < 12)) return VLC_EGENERIC; /* Look for the RIFF data chunk */ for (;;) { char chnk_hdr[8]; uint32_t chnk_len; if ((riff_len < 8) || (stream_Read (stream, chnk_hdr, 8) < 8)) return VLC_EGENERIC; riff_len -= 8; chnk_len = GetDWLE (chnk_hdr + 4); if (riff_len < chnk_len) return VLC_EGENERIC; riff_len -= chnk_len; if (!memcmp (chnk_hdr, "data", 4)) break; /* found! */ if (stream_Read (stream, NULL, chnk_len) < (ssize_t)chnk_len) return VLC_EGENERIC; } /* Read real SMF header. Assume RIFF data chunk length is proper. */ if (stream_Peek (stream, &peek, 14) < 14) return VLC_EGENERIC; } if (memcmp (peek, "MThd\x00\x00\x00\x06", 8)) return VLC_EGENERIC; peek += 8; /* First word: SMF type */ switch (GetWBE (peek)) { case 0: multitrack = false; break; case 1: multitrack = true; break; default: /* We don't implement SMF2 (as do many) */ msg_Err (p_this, "unsupported SMF file type %u", GetWBE (peek)); return VLC_EGENERIC; } peek += 2; /* Second word: number of tracks */ tracks = GetWBE (peek); peek += 2; if (!multitrack && (tracks != 1)) { msg_Err (p_this, "invalid SMF type 0 file"); return VLC_EGENERIC; } msg_Dbg (p_this, "detected Standard MIDI File (type %u) with %u track(s)", multitrack, tracks); /* Third/last word: timing */ ppqn = GetWBE (peek); if (ppqn & 0x8000) { /* FIXME */ msg_Err (p_this, "SMPTE timestamps not implemented"); return VLC_EGENERIC; } else { msg_Dbg (p_this, " %u pulses per quarter note", ppqn); } p_sys = malloc (sizeof (*p_sys) + (sizeof (mtrk_t) * tracks)); if (p_sys == NULL) return VLC_ENOMEM; /* We've had a valid SMF header - now skip it*/ if (stream_Read (stream, NULL, 14) < 14) goto error; p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys; /* Default SMF tempo is 120BPM, i.e. half a second per quarter note */ date_Init (&p_sys->pts, ppqn * 2, 1); date_Set (&p_sys->pts, 0); p_sys->pulse = 0; p_sys->ppqn = ppqn; p_sys->trackc = tracks; /* Prefetch track offsets */ for (unsigned i = 0; i < tracks; i++) { uint8_t head[8]; if (i > 0) { /* Seeking screws streaming up, but there is no way around this, * as SMF1 tracks are performed simultaneously. * Not a big deal as SMF1 are usually only a few kbytes anyway. */ if (stream_Seek (stream, p_sys->trackv[i-1].end)) { msg_Err (p_this, "cannot build SMF index (corrupted file?)"); goto error; } } for (;;) { if (stream_Read (stream, head, 8) < 8) { /* FIXME: don't give up if we have at least one valid track */ msg_Err (p_this, "incomplete SMF chunk, file is corrupted"); goto error; } if (memcmp (head, "MTrk", 4) == 0) break; msg_Dbg (p_this, "skipping unknown SMF chunk"); stream_Read (stream, NULL, GetDWBE (head + 4)); } p_sys->trackv[i].offset = stream_Tell (stream); p_sys->trackv[i].end = p_sys->trackv[i].offset + GetDWBE (head + 4); p_sys->trackv[i].next = 0; ReadDeltaTime (stream, p_sys->trackv + i); p_sys->trackv[i].running_event = 0xF6; /* Why 0xF6 (Tuning Calibration)? * Because it has zero bytes of data, so the parser will detect the * error if the first event uses running status. */ } es_format_t fmt; es_format_Init (&fmt, AUDIO_ES, VLC_CODEC_MIDI); fmt.audio.i_channels = 2; fmt.audio.i_rate = 44100; /* dummy value */ p_sys->es = es_out_Add (p_demux->out, &fmt); return VLC_SUCCESS; error: free (p_sys); return VLC_EGENERIC; }
static int stream_seek( struct reader *p_reader, uint64_t i_offset ) { return stream_Seek( p_reader->u.s, i_offset ); }
/***************************************************************************** * CheckFooter: check for ID3/APE at the end of the file * CheckHeader: check for ID3/APE at the begining of the file *****************************************************************************/ static void CheckFooter( demux_meta_t *p_demux_meta ) { demux_t *p_demux = (demux_t *)p_demux_meta->p_demux; const int64_t i_pos = stream_Size( p_demux->s ); const size_t i_peek = 128+APE_TAG_HEADERSIZE; const uint8_t *p_peek; const uint8_t *p_peek_id3; int64_t i_id3v2_pos = -1; int64_t i_apevx_pos = -1; int i_id3v2_size; int i_apevx_size; size_t i_id3v1_size; if( i_pos < i_peek ) return; if( stream_Seek( p_demux->s, i_pos - i_peek ) ) return; if( stream_Peek( p_demux->s, &p_peek, i_peek ) < i_peek ) return; p_peek_id3 = &p_peek[APE_TAG_HEADERSIZE]; /* Check/Parse ID3v1 */ i_id3v1_size = id3_tag_query( p_peek_id3, ID3_TAG_QUERYSIZE ); if( i_id3v1_size == 128 ) { msg_Dbg( p_demux, "found ID3v1 tag" ); ParseID3Tag( p_demux_meta, p_peek_id3, i_id3v1_size ); } /* Compute ID3v2 position */ i_id3v2_size = -id3_tag_query( &p_peek_id3[128-ID3_TAG_QUERYSIZE], ID3_TAG_QUERYSIZE ); if( i_id3v2_size > 0 ) i_id3v2_pos = i_pos - i_id3v2_size; /* Compute APE2v2 position */ i_apevx_size = GetAPEvXSize( &p_peek[128+0], APE_TAG_HEADERSIZE ); if( i_apevx_size > 0 ) { i_apevx_pos = i_pos - i_apevx_size; } else if( i_id3v1_size > 0 ) { /* it can be before ID3v1 */ i_apevx_size = GetAPEvXSize( p_peek, APE_TAG_HEADERSIZE ); if( i_apevx_size > 0 ) i_apevx_pos = i_pos - 128 - i_apevx_size; } if( i_id3v2_pos > 0 && i_apevx_pos > 0 ) { msg_Warn( p_demux, "Both ID3v2 and APEv1/2 at the end of file, ignoring APEv1/2" ); i_apevx_pos = -1; } /* Parse ID3v2.4 */ if( i_id3v2_pos > 0 ) { if( !stream_Seek( p_demux->s, i_id3v2_pos ) && stream_Peek( p_demux->s, &p_peek, i_id3v2_size ) == i_id3v2_size ) { msg_Dbg( p_demux, "found ID3v2 tag at end of file" ); ParseID3Tag( p_demux_meta, p_peek, i_id3v2_size ); } } /* Parse APEv1/2 */ if( i_apevx_pos > 0 ) { if( !stream_Seek( p_demux->s, i_apevx_pos ) && stream_Peek( p_demux->s, &p_peek, i_apevx_size ) == i_apevx_size ) { msg_Dbg( p_demux, "found APEvx tag at end of file" ); ParseAPEvXTag( p_demux_meta, p_peek, i_apevx_size ); } } }
/***************************************************************************** * Open: initializes raw DV demux structures *****************************************************************************/ static int Open( vlc_object_t * p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; int i_width=-1, i_height=-1; unsigned u_fps_num, u_fps_den; vlc_fourcc_t i_chroma = 0; unsigned int i_sar_num; unsigned int i_sar_den; const struct preset_t *p_preset = NULL; const uint8_t *p_peek; bool b_y4m = false; if( stream_Peek( p_demux->s, &p_peek, 9 ) == 9 ) { /* http://wiki.multimedia.cx/index.php?title=YUV4MPEG2 */ if( !strncmp( (char *)p_peek, "YUV4MPEG2", 9 ) ) { b_y4m = true; goto valid; } } if( !p_demux->b_force ) { /* guess preset based on file extension */ if( !p_demux->psz_file ) return VLC_EGENERIC; const char *psz_ext = strrchr( p_demux->psz_file, '.' ); if( !psz_ext ) return VLC_EGENERIC; psz_ext++; for( unsigned i = 0; p_presets[i].psz_ext ; i++ ) { if( !strcasecmp( psz_ext, p_presets[i].psz_ext ) ) { p_preset = &p_presets[i]; goto valid; } } return VLC_EGENERIC; } valid: p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; p_sys->b_y4m = b_y4m; /* guess the parameters based on the preset */ if( p_preset ) { i_width = p_preset->i_width; i_height = p_preset->i_height; u_fps_num = p_preset->u_fps_num; u_fps_den = p_preset->u_fps_den; i_sar_num = p_preset->u_ar_num * p_preset->i_height; i_sar_den = p_preset->u_ar_den * p_preset->i_width; i_chroma = p_preset->i_chroma; } /* override presets if yuv4mpeg2 */ if( b_y4m ) { /* The string should start with "YUV4MPEG2" */ char *psz = stream_ReadLine( p_demux->s ); char *psz_buf; int a = 1; int b = 1; if( unlikely(psz == NULL) ) goto error; /* NB, it is not possible to handle interlaced here, since the * interlaced picture flags are in picture_t not block_t */ #define READ_FRAC( key, num, den ) do { \ psz_buf = strstr( psz+9, key );\ if( psz_buf )\ {\ char *end = strchr( psz_buf+1, ' ' );\ char *sep;\ if( end ) *end = '\0';\ sep = strchr( psz_buf+1, ':' );\ if( sep )\ {\ *sep = '\0';\ den = atoi( sep+1 );\ }\ else\ {\ den = 1;\ }\ num = atoi( psz_buf+2 );\ if( sep ) *sep = ':';\ if( end ) *end = ' ';\ } } while(0) READ_FRAC( " W", i_width, a ); READ_FRAC( " H", i_height, a ); READ_FRAC( " F", u_fps_num, u_fps_den ); READ_FRAC( " A", a, b ); #undef READ_FRAC if( b != 0 ) { i_sar_num = a; i_sar_den = b; } psz_buf = strstr( psz+9, " C" ); if( psz_buf ) { static const struct { const char *psz_name; vlc_fourcc_t i_fcc; } formats[] = { { "420jpeg", VLC_CODEC_I420 }, { "420paldv", VLC_CODEC_I420 }, { "420", VLC_CODEC_I420 }, { "422", VLC_CODEC_I422 }, { "444", VLC_CODEC_I444 }, { "mono", VLC_CODEC_GREY }, { NULL, 0 } }; bool b_found = false; char *psz_end = strchr( psz_buf+1, ' ' ); if( psz_end ) *psz_end = '\0'; psz_buf += 2; for( int i = 0; formats[i].psz_name != NULL; i++ ) { if( !strncmp( psz_buf, formats[i].psz_name, strlen(formats[i].psz_name) ) ) { i_chroma = formats[i].i_fcc; b_found = true; break; } } if( !b_found ) msg_Warn( p_demux, "Unknown YUV4MPEG2 chroma type \"%s\"", psz_buf ); if( psz_end ) *psz_end = ' '; } free( psz ); } /* allow the user to override anything guessed from the input */ int i_tmp; i_tmp = var_CreateGetInteger( p_demux, "rawvid-width" ); if( i_tmp ) i_width = i_tmp; i_tmp = var_CreateGetInteger( p_demux, "rawvid-height" ); if( i_tmp ) i_height = i_tmp; char *psz_tmp; psz_tmp = var_CreateGetNonEmptyString( p_demux, "rawvid-chroma" ); if( psz_tmp ) { if( strlen( psz_tmp ) != 4 ) { msg_Err( p_demux, "Invalid fourcc format/chroma specification %s" " expecting four characters eg, UYVY", psz_tmp ); free( psz_tmp ); goto error; } memcpy( &i_chroma, psz_tmp, 4 ); msg_Dbg( p_demux, "Forcing chroma to 0x%.8x (%4.4s)", i_chroma, (char*)&i_chroma ); free( psz_tmp ); } if( var_InheritURational( p_demux, &u_fps_num, &u_fps_den, "rawvid-fps" ) ) { u_fps_num = 0; u_fps_den = 1; } if( var_InheritURational( p_demux, &i_sar_num, &i_sar_den, "rawvid-aspect-ratio" ) ) i_sar_num = i_sar_den = 1; /* moan about anything wrong */ if( i_width <= 0 || i_height <= 0 ) { msg_Err( p_demux, "width and height must be strictly positive." ); goto error; } if( !u_fps_num || !u_fps_den ) { msg_Err( p_demux, "invalid or no framerate specified." ); goto error; } if( i_chroma == 0 ) { msg_Err( p_demux, "invalid or no chroma specified." ); goto error; } /* fixup anything missing with sensible assumptions */ if( i_sar_num <= 0 || i_sar_den <= 0 ) { /* assume 1:1 sar */ i_sar_num = 1; i_sar_den = 1; } es_format_Init( &p_sys->fmt_video, VIDEO_ES, i_chroma ); video_format_Setup( &p_sys->fmt_video.video, i_chroma, i_width, i_height, i_width, i_height, i_sar_num, i_sar_den ); vlc_ureduce( &p_sys->fmt_video.video.i_frame_rate, &p_sys->fmt_video.video.i_frame_rate_base, u_fps_num, u_fps_den, 0); date_Init( &p_sys->pcr, p_sys->fmt_video.video.i_frame_rate, p_sys->fmt_video.video.i_frame_rate_base ); date_Set( &p_sys->pcr, 0 ); if( !p_sys->fmt_video.video.i_bits_per_pixel ) { msg_Err( p_demux, "Unsupported chroma 0x%.8x (%4.4s)", i_chroma, (char*)&i_chroma ); goto error; } p_sys->frame_size = i_width * i_height * p_sys->fmt_video.video.i_bits_per_pixel / 8; p_sys->p_es_video = es_out_Add( p_demux->out, &p_sys->fmt_video ); p_demux->pf_demux = Demux; p_demux->pf_control = Control; return VLC_SUCCESS; error: stream_Seek( p_demux->s, 0 ); // Workaround, but y4m uses stream_ReadLines free( p_sys ); return VLC_EGENERIC; }
int RarStreamOpen(vlc_object_t *object) { stream_t *s = (stream_t*)object; if (RarProbe(s->p_source)) return VLC_EGENERIC; int count; rar_file_t **files; const int64_t position = stream_Tell(s->p_source); if ((RarParse(s->p_source, &count, &files, false) && RarParse(s->p_source, &count, &files, true )) || count == 0 ) { stream_Seek(s->p_source, position); msg_Info(s, "Invalid or unsupported RAR archive"); free(files); return VLC_EGENERIC; } /* TODO use xspf to have node for directories * Reusing WriteXSPF from the zip access is probably a good idea * (becareful about '\' and '/'. */ char *mrl; if (asprintf(&mrl, "%s://%s", s->psz_access, s->psz_path)< 0) mrl = NULL; char *base; char *encoded = mrl ? encode_URI_component(mrl) : NULL; free(mrl); if (!encoded || asprintf(&base, "rar://%s", encoded) < 0) base = NULL; free(encoded); char *data = strdup("#EXTM3U\n"); for (int i = 0; i < count; i++) { rar_file_t *f = files[i]; char *next; if (base && data && asprintf(&next, "%s" "#EXTINF:,,%s\n" "%s|%s\n", data, f->name, base, f->name) >= 0) { free(data); data = next; } RarFileDelete(f); } free(base); free(files); if (!data) return VLC_EGENERIC; stream_t *payload = stream_MemoryNew(s, (uint8_t*)data, strlen(data), false); if (!payload) { free(data); return VLC_EGENERIC; } s->pf_read = Read; s->pf_peek = Peek; s->pf_control = Control; stream_sys_t *sys = s->p_sys = malloc(sizeof(*sys)); if (!sys) { stream_Delete(payload); return VLC_ENOMEM; } sys->payload = payload; char *tmp; if (asprintf(&tmp, "%s.m3u", s->psz_path) < 0) { RarStreamClose(object); return VLC_ENOMEM; } free(s->psz_path); s->psz_path = tmp; return VLC_SUCCESS; }