static int PeekBlock(stream_t *s, rar_block_t *hdr) { const uint8_t *peek; int peek_size = stream_Peek(s, &peek, 11); if (peek_size < 7) return VLC_EGENERIC; hdr->crc = GetWLE(&peek[0]); hdr->type = peek[2]; hdr->flags = GetWLE(&peek[3]); hdr->size = GetWLE(&peek[5]); hdr->add_size = 0; if ((hdr->flags & 0x8000) || hdr->type == RAR_BLOCK_FILE || hdr->type == RAR_BLOCK_SUBBLOCK) { if (peek_size < 11) return VLC_EGENERIC; hdr->add_size = GetDWLE(&peek[7]); } if (hdr->size < 7) return VLC_EGENERIC; return VLC_SUCCESS; }
/**************************************************************************** * * Basics functions to manipulates chunks * ****************************************************************************/ static int AVI_ChunkReadCommon( stream_t *s, avi_chunk_t *p_chk ) { const uint8_t *p_peek; int i_peek; memset( p_chk, 0, sizeof( avi_chunk_t ) ); if( ( i_peek = 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 = 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:%8.8x (%4.4s) size:%"PRId64" pos:%"PRId64, p_chk->common.i_chunk_fourcc, (char*)&p_chk->common.i_chunk_fourcc, p_chk->common.i_chunk_size, p_chk->common.i_chunk_pos ); #endif return VLC_SUCCESS; }
/***************************************************************************** * Local functions *****************************************************************************/ static int ChunkFind( demux_t *p_demux, const char *fcc, unsigned int *pi_size ) { const uint8_t *p_peek; for( ;; ) { uint32_t i_size; if( stream_Peek( p_demux->s, &p_peek, 8 ) < 8 ) { msg_Err( p_demux, "cannot peek" ); return VLC_EGENERIC; } i_size = GetDWLE( p_peek + 4 ); msg_Dbg( p_demux, "chunk: fcc=`%4.4s` size=%"PRIu32, p_peek, i_size ); if( !memcmp( p_peek, fcc, 4 ) ) { if( pi_size ) { *pi_size = i_size; } return VLC_SUCCESS; } /* Skip chunk */ if( stream_Read( p_demux->s, NULL, 8 ) != 8 || stream_Read( p_demux->s, NULL, i_size ) != (int)i_size || ( (i_size & 1) && stream_Read( p_demux->s, NULL, 1 ) != 1 ) ) return VLC_EGENERIC; } }
/***************************************************************************** * DecodePacket: decodes an OggSpots packet. *****************************************************************************/ static picture_t* DecodePacket(decoder_t* p_dec, block_t* p_block) { decoder_sys_t* p_sys = p_dec->p_sys; uint32_t i_img_offset; picture_t* p_pic; if (p_block->i_buffer < 20) { msg_Dbg(p_dec, "Packet too short"); goto error; } /* Byte offset */ i_img_offset = GetDWLE(p_block->p_buffer); if (i_img_offset < 20) { msg_Dbg(p_dec, "Invalid byte offset"); goto error; } /* Image format */ if ( !memcmp(&p_block->p_buffer[4], "PNG", 3) ) { p_dec->fmt_in.video.i_chroma = VLC_CODEC_PNG; } else if ( !memcmp(&p_block->p_buffer[4], "JPEG", 4) ) { p_dec->fmt_in.video.i_chroma = VLC_CODEC_JPEG; } else { char psz_image_type[8+1]; strncpy(psz_image_type, (char*)&p_block->p_buffer[4], 8); psz_image_type[sizeof(psz_image_type)-1] = '\0'; msg_Dbg(p_dec, "Unsupported image format: %s", psz_image_type); goto error; } /* We currently ignore the rest of the header and let the image format * handle the details */ p_block->i_buffer -= i_img_offset; p_block->p_buffer += i_img_offset; p_pic = image_Read(p_sys->p_image, p_block, &p_dec->fmt_in, &p_dec->fmt_out.video); if (p_pic == NULL) { return NULL; } p_pic->b_force = true; p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma; decoder_UpdateVideoFormat(p_dec); return p_pic; error: block_Release(p_block); return NULL; }
static void U32LDecode( void *outp, const uint8_t *in, unsigned samples ) { uint32_t *out = outp; for( size_t i = 0; i < samples; i++ ) { *(out++) = GetDWLE( in ) - 0x80000000; in += 4; } }
static size_t GetAPEvXSize( const uint8_t *p_data, int i_data ) { uint32_t flags; size_t i_body; if( i_data < APE_TAG_HEADERSIZE || ( GetDWLE( &p_data[8] ) != 1000 && GetDWLE( &p_data[8] ) != 2000 ) || /* v1/v2 only */ strncmp( (char*)p_data, "APETAGEX", 8 ) || GetDWLE( &p_data[8+4+4] ) <= 0 ) return 0; i_body = GetDWLE( &p_data[8+4] ); flags = GetDWLE( &p_data[8+4+4] ); /* is it the header */ if( flags & (1<<29) ) return i_body + ( (flags&(1<<30)) ? APE_TAG_HEADERSIZE : 0 ); /* it is the footer */ return i_body + ( (flags&(1<<31)) ? APE_TAG_HEADERSIZE : 0 ); }
static int comment_add(char **comments, size_t *length, const char *tag, const char *val) { char *p = *comments; int vendor_length = GetDWLE(p + 8); size_t user_comment_list_length = GetDWLE(p + 8 + 4 + vendor_length); size_t tag_len = (tag ? strlen(tag) : 0); size_t val_len = strlen(val); size_t len = (*length) + 4 + tag_len + val_len; p = realloc(p, len); if (p == NULL) return 1; SetDWLE(p + *length, tag_len + val_len); /* length of comment */ if (tag) memcpy(p + *length + 4, tag, tag_len); /* comment */ memcpy(p + *length + 4 + tag_len, val, val_len); /* comment */ SetDWLE(p + 8 + 4 + vendor_length, user_comment_list_length + 1); *comments = p; *length = len; return 0; }
static void S32IDecode( void *outp, const uint8_t *in, unsigned samples ) { int32_t *out = outp; for( size_t i = 0; i < samples; i++ ) { #ifdef WORDS_BIGENDIAN *(out++) = GetDWLE( in ); #else *(out++) = GetDWBE( in ); #endif in += 4; } }
static bool IsBmp(stream_t *s) { const uint8_t *header; if (stream_Peek(s, &header, 18) < 18) return false; if (memcmp(header, "BM", 2) && memcmp(header, "BA", 2) && memcmp(header, "CI", 2) && memcmp(header, "CP", 2) && memcmp(header, "IC", 2) && memcmp(header, "PT", 2)) return false; uint32_t file_size = GetDWLE(&header[2]); uint32_t data_offset = GetDWLE(&header[10]); uint32_t header_size = GetDWLE(&header[14]); if (file_size != 14 && file_size != 14 + header_size && file_size <= data_offset) return false; if (data_offset < header_size + 14) return false; if (header_size != 12 && header_size < 40) return false; return true; }
static void F32IDecode( void *outp, const uint8_t *in, unsigned samples ) { float *out = outp; for( size_t i = 0; i < samples; i++ ) { union { float f; uint32_t u; } s; #ifdef WORDS_BIGENDIAN s.u = GetDWLE( in ); #else s.u = GetDWBE( in ); #endif *(out++) = s.f; in += 4; } }
/***************************************************************************** * Open: check file and initializes 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; unsigned int i_size; unsigned int i_extended; const char *psz_name; WAVEFORMATEXTENSIBLE *p_wf_ext = NULL; WAVEFORMATEX *p_wf = NULL; /* Is it a wav file ? */ if( stream_Peek( p_demux->s, &p_peek, 12 ) < 12 ) return VLC_EGENERIC; if( memcmp( p_peek, "RIFF", 4 ) || memcmp( &p_peek[8], "WAVE", 4 ) ) { return VLC_EGENERIC; } p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys = malloc( sizeof( *p_sys ) ); if( unlikely(!p_sys) ) return VLC_ENOMEM; p_sys->p_es = NULL; p_sys->i_chans_to_reorder = 0; p_sys->i_channel_mask = 0; /* skip riff header */ if( stream_Read( p_demux->s, NULL, 12 ) != 12 ) goto error; /* search fmt chunk */ if( ChunkFind( p_demux, "fmt ", &i_size ) ) { msg_Err( p_demux, "cannot find 'fmt ' chunk" ); goto error; } i_size += 2; if( i_size < sizeof( WAVEFORMATEX ) ) { msg_Err( p_demux, "invalid 'fmt ' chunk" ); goto error; } if( stream_Read( p_demux->s, NULL, 8 ) != 8 ) goto error; /* load waveformatex */ p_wf_ext = malloc( i_size ); if( unlikely( !p_wf_ext ) ) goto error; p_wf = &p_wf_ext->Format; p_wf->cbSize = 0; i_size -= 2; if( stream_Read( p_demux->s, p_wf, i_size ) != (int)i_size || ( ( i_size & 1 ) && stream_Read( p_demux->s, NULL, 1 ) != 1 ) ) { msg_Err( p_demux, "cannot load 'fmt ' chunk" ); goto error; } es_format_Init( &p_sys->fmt, AUDIO_ES, 0 ); wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &p_sys->fmt.i_codec, &psz_name ); p_sys->fmt.audio.i_channels = GetWLE ( &p_wf->nChannels ); p_sys->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec ); p_sys->fmt.audio.i_blockalign = GetWLE( &p_wf->nBlockAlign ); p_sys->fmt.i_bitrate = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8; p_sys->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample ); if( i_size >= sizeof(WAVEFORMATEX) ) p_sys->fmt.i_extra = __MIN( GetWLE( &p_wf->cbSize ), i_size - sizeof(WAVEFORMATEX) ); i_extended = 0; /* Handle new WAVE_FORMAT_EXTENSIBLE wav files */ /* see the following link for more information: * http://www.microsoft.com/whdc/device/audio/multichaud.mspx#EFAA */ if( GetWLE( &p_wf->wFormatTag ) == WAVE_FORMAT_EXTENSIBLE && i_size >= sizeof( WAVEFORMATEXTENSIBLE ) && ( p_sys->fmt.i_extra + sizeof( WAVEFORMATEX ) >= sizeof( WAVEFORMATEXTENSIBLE ) ) ) { unsigned i_channel_mask; GUID guid_subformat; guid_subformat = p_wf_ext->SubFormat; guid_subformat.Data1 = GetDWLE( &p_wf_ext->SubFormat.Data1 ); guid_subformat.Data2 = GetWLE( &p_wf_ext->SubFormat.Data2 ); guid_subformat.Data3 = GetWLE( &p_wf_ext->SubFormat.Data3 ); sf_tag_to_fourcc( &guid_subformat, &p_sys->fmt.i_codec, &psz_name ); i_extended = sizeof( WAVEFORMATEXTENSIBLE ) - sizeof( WAVEFORMATEX ); p_sys->fmt.i_extra -= i_extended; i_channel_mask = GetDWLE( &p_wf_ext->dwChannelMask ); if( i_channel_mask ) { int i_match = 0; for( unsigned i = 0; i < sizeof(pi_channels_src)/sizeof(*pi_channels_src); i++ ) { if( i_channel_mask & pi_channels_src[i] ) { if( !( p_sys->i_channel_mask & pi_channels_in[i] ) ) i_match++; i_channel_mask &= ~pi_channels_src[i]; p_sys->i_channel_mask |= pi_channels_in[i]; if( i_match >= p_sys->fmt.audio.i_channels ) break; } } if( i_channel_mask ) msg_Warn( p_demux, "Some channels are unrecognized or uselessly specified (0x%x)", i_channel_mask ); if( i_match < p_sys->fmt.audio.i_channels ) { int i_missing = p_sys->fmt.audio.i_channels - i_match; msg_Warn( p_demux, "Trying to fill up unspecified position for %d channels", p_sys->fmt.audio.i_channels - i_match ); static const uint32_t pi_pair[] = { AOUT_CHAN_REARLEFT|AOUT_CHAN_REARRIGHT, AOUT_CHAN_MIDDLELEFT|AOUT_CHAN_MIDDLERIGHT, AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT }; /* FIXME: Unused yet static const uint32_t pi_center[] = { AOUT_CHAN_REARCENTER, 0, AOUT_CHAN_CENTER }; */ /* Try to complete with pair */ for( unsigned i = 0; i < sizeof(pi_pair)/sizeof(*pi_pair); i++ ) { if( i_missing >= 2 && !(p_sys->i_channel_mask & pi_pair[i] ) ) { i_missing -= 2; p_sys->i_channel_mask |= pi_pair[i]; } } /* Well fill up with what we can */ for( unsigned i = 0; i < sizeof(pi_channels_in)/sizeof(*pi_channels_in) && i_missing > 0; i++ ) { if( !( p_sys->i_channel_mask & pi_channels_in[i] ) ) { p_sys->i_channel_mask |= pi_channels_in[i]; i_missing--; if( i_missing <= 0 ) break; } } i_match = p_sys->fmt.audio.i_channels - i_missing; } if( i_match < p_sys->fmt.audio.i_channels ) { msg_Err( p_demux, "Invalid/unsupported channel mask" ); p_sys->i_channel_mask = 0; } } } else if( GetWLE( &p_wf->wFormatTag ) == WAVE_FORMAT_PCM && p_sys->fmt.audio.i_channels > 2 && p_sys->fmt.audio.i_channels <= 9 ) { for( int i = 0; i < p_sys->fmt.audio.i_channels; i++ ) p_sys->i_channel_mask |= pi_channels_in[i]; } if( p_sys->i_channel_mask ) { if( p_sys->fmt.i_codec == VLC_FOURCC('a','r','a','w') || p_sys->fmt.i_codec == VLC_FOURCC('p','c','m',' ') || p_sys->fmt.i_codec == VLC_FOURCC('a','f','l','t') ) p_sys->i_chans_to_reorder = aout_CheckChannelReorder( pi_channels_in, NULL, p_sys->i_channel_mask, p_sys->pi_chan_table ); msg_Dbg( p_demux, "channel mask: %x, reordering: %u", p_sys->i_channel_mask, p_sys->i_chans_to_reorder ); } p_sys->fmt.audio.i_physical_channels = p_sys->fmt.audio.i_original_channels = p_sys->i_channel_mask; if( p_sys->fmt.i_extra > 0 ) { p_sys->fmt.p_extra = malloc( p_sys->fmt.i_extra ); if( unlikely(!p_sys->fmt.p_extra) ) { p_sys->fmt.i_extra = 0; goto error; } memcpy( p_sys->fmt.p_extra, (uint8_t *)p_wf + sizeof( WAVEFORMATEX ) + i_extended, p_sys->fmt.i_extra ); } msg_Dbg( p_demux, "format: 0x%4.4x, fourcc: %4.4s, channels: %d, " "freq: %u Hz, bitrate: %uKo/s, blockalign: %d, bits/samples: %d, " "extra size: %d", GetWLE( &p_wf->wFormatTag ), (char *)&p_sys->fmt.i_codec, p_sys->fmt.audio.i_channels, p_sys->fmt.audio.i_rate, p_sys->fmt.i_bitrate / 8 / 1024, p_sys->fmt.audio.i_blockalign, p_sys->fmt.audio.i_bitspersample, p_sys->fmt.i_extra ); free( p_wf ); p_wf = NULL; switch( p_sys->fmt.i_codec ) { case VLC_FOURCC( 'a', 'r', 'a', 'w' ): case VLC_FOURCC( 'a', 'f', 'l', 't' ): case VLC_FOURCC( 'u', 'l', 'a', 'w' ): case VLC_CODEC_ALAW: case VLC_CODEC_MULAW: case VLC_FOURCC( 'p', 'c', 'm', ' ' ): if( FrameInfo_PCM( &p_sys->i_frame_size, &p_sys->i_frame_samples, &p_sys->fmt ) ) goto error; break; case VLC_CODEC_ADPCM_MS: if( FrameInfo_MS_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples, &p_sys->fmt ) ) goto error; break; case VLC_CODEC_ADPCM_IMA_WAV: if( FrameInfo_IMA_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples, &p_sys->fmt ) ) goto error; break; case VLC_FOURCC( 'm', 's', 0x00, 0x61 ): case VLC_FOURCC( 'm', 's', 0x00, 0x62 ): /* FIXME not sure at all FIXME */ if( FrameInfo_MS_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples, &p_sys->fmt ) ) goto error; break; case VLC_CODEC_MPGA: case VLC_CODEC_A52: /* FIXME set end of area FIXME */ goto error; case VLC_CODEC_GSM_MS: case VLC_CODEC_ADPCM_G726: case VLC_CODEC_TRUESPEECH: case VLC_CODEC_ATRAC3: case VLC_CODEC_G723_1: if( FrameInfo_MSGSM( &p_sys->i_frame_size, &p_sys->i_frame_samples, &p_sys->fmt ) ) goto error; break; default: msg_Err( p_demux, "unsupported codec (%4.4s)", (char*)&p_sys->fmt.i_codec ); goto error; } if( p_sys->i_frame_size <= 0 || p_sys->i_frame_samples <= 0 ) { msg_Dbg( p_demux, "invalid frame size: %i %i", p_sys->i_frame_size, p_sys->i_frame_samples ); goto error; } if( p_sys->fmt.audio.i_rate <= 0 ) { msg_Dbg( p_demux, "invalid sample rate: %i", p_sys->fmt.audio.i_rate ); goto error; } msg_Dbg( p_demux, "found %s audio format", psz_name ); if( ChunkFind( p_demux, "data", &p_sys->i_data_size ) ) { msg_Err( p_demux, "cannot find 'data' chunk" ); goto error; } if( stream_Read( p_demux->s, NULL, 8 ) != 8 ) goto error; p_sys->i_data_pos = stream_Tell( p_demux->s ); if( p_sys->fmt.i_bitrate <= 0 ) { p_sys->fmt.i_bitrate = (int64_t)p_sys->i_frame_size * p_sys->fmt.audio.i_rate * 8 / p_sys->i_frame_samples; } p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt ); date_Init( &p_sys->pts, p_sys->fmt.audio.i_rate, 1 ); date_Set( &p_sys->pts, 1 ); return VLC_SUCCESS; error: msg_Err( p_demux, "An error occurred during wav demuxing" ); free( p_wf ); free( p_sys ); return VLC_EGENERIC; }
/** * Parse header extension object. Takes a pointer to a newly allocated * header extension structure, a pointer to the data buffer and the * length of the data buffer as its parameters. Subobject contents are * not parsed, but they are added as a linked list to the header object. */ static int asf_parse_headerext(asf_object_headerext_t *header, uint8_t *buf, uint64_t buflen) { int64_t datalen; uint8_t *data; if (header->size < 46) { /* invalide size for headerext */ return ASF_ERROR_INVALID_OBJECT_SIZE; } /* Read reserved and datalen fields from the buffer */ GetGUID(buf + 24, &header->reserved1); header->reserved2 = GetWLE(buf + 40); header->datalen = GetDWLE(buf + 42); if (header->datalen != header->size - 46) { /* invalid header extension data length value */ return ASF_ERROR_INVALID_LENGTH; } header->data = buf + 46; debug_printf("parsing header extension subobjects"); datalen = header->datalen; data = header->data; while (datalen > 0) { asfint_object_t *current; if (datalen < 24) { /* not enough data for reading a new object */ break; } /* Allocate a new subobject */ current = malloc(sizeof(asfint_object_t)); if (!current) { return ASF_ERROR_OUTOFMEM; } asf_parse_read_object(current, data); if (current->size > datalen || current->size < 24) { /* invalid object size */ break; } current->datalen = current->size - 24; current->data = data + 24; /* add to the list of subobjects */ if (!header->first) { header->first = current; header->last = current; } else { header->last->next = current; header->last = current; } data += current->size; datalen -= current->size; } if (datalen != 0) { /* not enough data for reading the whole object */ return ASF_ERROR_INVALID_LENGTH; } debug_printf("header extension subobjects parsed successfully"); return header->size; }
/***************************************************************************** * Open: check file and initializes structures *****************************************************************************/ static int Open( vlc_object_t * p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; xa_header_t p_xa; const uint8_t *p_buf; /* XA file heuristic */ if( stream_Peek( p_demux->s, &p_buf, sizeof( p_xa ) ) < (signed)sizeof( p_xa ) ) return VLC_EGENERIC; memcpy( &p_xa, p_buf, sizeof( p_xa ) ); if( ( strncmp( p_xa.xa_id, "XAI", 4 ) && strncmp( p_xa.xa_id, "XAJ", 4 ) ) || ( GetWLE( &p_xa.wFormatTag ) != 0x0001) || ( GetWLE( &p_xa.wBitsPerSample ) != 16) ) return VLC_EGENERIC; 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->p_es = NULL; /* skip XA header -- cannot fail */ stream_Read( p_demux->s, NULL, sizeof( p_xa ) ); es_format_Init( &p_sys->fmt, AUDIO_ES, VLC_FOURCC('X','A','J',0) ); msg_Dbg( p_demux, "assuming EA ADPCM audio codec" ); p_sys->fmt.audio.i_rate = GetDWLE( &p_xa.nSamplesPerSec ); p_sys->fmt.audio.i_bytes_per_frame = 15 * GetWLE( &p_xa.nChannels ); p_sys->fmt.audio.i_frame_length = 28; /* 28 samples of 4 bits each */ p_sys->fmt.audio.i_channels = GetWLE ( &p_xa.nChannels ); p_sys->fmt.audio.i_blockalign = p_sys->fmt.audio.i_bytes_per_frame; p_sys->fmt.audio.i_bitspersample = 16; p_sys->fmt.i_bitrate = (p_sys->fmt.audio.i_rate * p_sys->fmt.audio.i_bytes_per_frame * 8) / p_sys->fmt.audio.i_frame_length; p_sys->fmt.i_extra = 0; p_sys->fmt.p_extra = NULL; p_sys->i_data_offset = stream_Tell( p_demux->s ); /* FIXME: better computation */ p_sys->i_data_size = p_xa.iSize * 15 / 56; /* How many frames per block (1:1 is too CPU intensive) */ p_sys->i_block_frames = p_sys->fmt.audio.i_rate / (28 * 20) + 1; msg_Dbg( p_demux, "fourcc: %4.4s, channels: %d, " "freq: %d Hz, bitrate: %dKo/s, blockalign: %d", (char *)&p_sys->fmt.i_codec, p_sys->fmt.audio.i_channels, p_sys->fmt.audio.i_rate, p_sys->fmt.i_bitrate / 8192, p_sys->fmt.audio.i_blockalign ); p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt ); date_Init( &p_sys->pts, p_sys->fmt.audio.i_rate, 1 ); date_Set( &p_sys->pts, 1 ); return VLC_SUCCESS; }
/** * Takes an initialized asf_file_t structure file as a parameter. Allocates * a new asf_object_header_t in file->header and uses the file->iostream to * read all fields and subobjects into it. Finally calls the * asf_parse_header_validate function to validate the values and parse the * commonly used values into the asf_file_t struct itself. */ int asf_parse_header(asf_file_t *file) { asf_object_header_t *header; asf_iostream_t *iostream; uint8_t hdata[30]; int tmp; file->header = NULL; iostream = &file->iostream; /* object minimum is 24 bytes and header needs to have * the subobject count field and two reserved fields */ tmp = asf_byteio_read(iostream, hdata, 30); if (tmp < 0) { /* not enough data to read the header object */ return tmp; } file->header = malloc(sizeof(asf_object_header_t)); header = file->header; if (!header) { return ASF_ERROR_OUTOFMEM; } /* read the object and check its size value */ asf_parse_read_object((asfint_object_t *) header, hdata); if (header->size < 30) { /* invalid size for header object */ return ASF_ERROR_INVALID_OBJECT_SIZE; } /* read header object specific compulsory fields */ header->subobjects = GetDWLE(hdata + 24); header->reserved1 = hdata[28]; header->reserved2 = hdata[29]; /* clear header extension object and subobject list */ header->ext = NULL; header->first = NULL; header->last = NULL; /* the header data needs to be allocated for reading */ header->datalen = header->size - 30; header->data = malloc(header->datalen * sizeof(uint8_t)); if (!header->data) { return ASF_ERROR_OUTOFMEM; } tmp = asf_byteio_read(iostream, header->data, header->datalen); if (tmp < 0) { return tmp; } if (header->subobjects > 0) { uint64_t datalen; uint8_t *data; int i; debug_printf("starting to read subobjects"); /* use temporary variables for use during the read */ datalen = header->datalen; data = header->data; for (i=0; i<header->subobjects; i++) { asfint_object_t *current; if (datalen < 24) { /* not enough data for reading object */ break; } current = malloc(sizeof(asfint_object_t)); if (!current) { return ASF_ERROR_OUTOFMEM; } asf_parse_read_object(current, data); if (current->size > datalen || current->size < 24) { /* invalid object size */ break; } /* Check if the current subobject is a header extension * object or just a normal subobject */ if (current->type == GUID_HEADER_EXTENSION && !header->ext) { int ret; asf_object_headerext_t *headerext; /* we handle header extension separately because it has * some subobjects as well */ current = realloc(current, sizeof(asf_object_headerext_t)); headerext = (asf_object_headerext_t *) current; headerext->first = NULL; headerext->last = NULL; ret = asf_parse_headerext(headerext, data, datalen); if (ret < 0) { /* error parsing header extension */ return ret; } header->ext = headerext; } else { if (current->type == GUID_HEADER_EXTENSION) { debug_printf("WARNING! Second header extension object found, ignoring it!"); } current->datalen = current->size - 24; current->data = data + 24; /* add to list of subobjects */ if (!header->first) { header->first = current; header->last = current; } else { header->last->next = current; header->last = current; } } data += current->size; datalen -= current->size; } if (i != header->subobjects || datalen != 0) { /* header data size doesn't match given subobject count */ return ASF_ERROR_INVALID_VALUE; } debug_printf("%d subobjects read successfully", i); } tmp = asf_parse_header_validate(file, file->header); if (tmp < 0) { /* header read ok but doesn't validate correctly */ return tmp; } debug_printf("header validated correctly"); return header->size; }
/** * Takes an initialized asf_file_t structure file as a parameter. Allocates * a new asf_object_index_t in file->index and uses the file->iostream to * read all its compulsory fields into it. Notice that the actual data is * not read in any way, because we need to be able to work with non-seekable * streams as well. */ int asf_parse_index(asf_file_t *file) { asf_object_index_t *index; asf_iostream_t *iostream; uint8_t idata[56]; uint64_t entry_data_size; uint8_t *entry_data = NULL; int tmp, i; file->index = NULL; iostream = &file->iostream; /* read the raw data of an index header */ tmp = asf_byteio_read(iostream, idata, 56); if (tmp < 0) { printf("Could not read index header\n"); return tmp; } /* allocate the index object */ index = malloc(sizeof(asf_object_index_t)); if (!index) { return ASF_ERROR_OUTOFMEM; } asf_parse_read_object((asfint_object_t *) index, idata); if (index->type != GUID_INDEX) { tmp = index->size; free(index); /* The guid type was wrong, just return the bytes to skip */ return tmp; } if (index->size < 56) { /* invalid size for index object */ free(index); return ASF_ERROR_INVALID_OBJECT_SIZE; } GetGUID(idata + 24, &index->file_id); index->entry_time_interval = GetQWLE(idata + 40); index->max_packet_count = GetDWLE(idata + 48); index->entry_count = GetDWLE(idata + 52); printf("INDEX\n"); printf("Total Index Entries %d\n",index->entry_count); printf("Index Size in bytes %Ld\n",index->size); printf("Index Max Packet Count %d\n",index->max_packet_count); printf("Index Entry Time Interval %Ld\n",index->entry_time_interval); if (index->entry_count == 0) { printf("Index has no entries\n"); file->index = index; return index->size; } if (index->entry_count * 6 + 56 > index->size) { free(index); return ASF_ERROR_INVALID_LENGTH; } entry_data_size = index->entry_count * 6; entry_data = malloc(entry_data_size * sizeof(uint8_t)); if (!entry_data) { free(index); return ASF_ERROR_OUTOFMEM; } tmp = asf_byteio_read(iostream, entry_data, entry_data_size); if (tmp < 0) { printf("Could not read entry data\n"); free(index); free(entry_data); return tmp; } index->entries = malloc(index->entry_count * sizeof(asf_index_entry_t)); if (!index->entries) { free(index); free(entry_data); return ASF_ERROR_OUTOFMEM; } for (i=0; i<index->entry_count; i++) { index->entries[i].packet_index = GetDWLE(entry_data + i*6); index->entries[i].packet_count = GetWLE(entry_data + i*6 + 4); } free(entry_data); file->index = index; return index->size; }
/***************************************************************************** * Open: check file and initializes structures *****************************************************************************/ static int Open( vlc_object_t * p_this ) { demux_t *p_demux = (demux_t*)p_this; const uint8_t *peek; /* XA file heuristic */ if( vlc_stream_Peek( p_demux->s, &peek, 10 ) < 10 ) return VLC_EGENERIC; if( memcmp( peek, "XAI", 4 ) && memcmp( peek, "XAJ", 4 ) && memcmp( peek, "XA\0", 4 ) ) return VLC_EGENERIC; if( GetWLE( peek + 8 ) != 1 ) /* format tag */ return VLC_EGENERIC; demux_sys_t *p_sys = vlc_obj_malloc( p_this, sizeof (*p_sys) ); if( unlikely( p_sys == NULL ) ) return VLC_ENOMEM; /* read XA header*/ xa_header_t xa; if( vlc_stream_Read( p_demux->s, &xa, HEADER_LENGTH ) < HEADER_LENGTH ) return VLC_EGENERIC; es_format_t fmt; es_format_Init( &fmt, AUDIO_ES, VLC_CODEC_ADPCM_XA_EA ); msg_Dbg( p_demux, "assuming EA ADPCM audio codec" ); fmt.audio.i_rate = GetDWLE( &xa.nSamplesPerSec ); fmt.audio.i_bytes_per_frame = 15 * GetWLE( &xa.nChannels ); fmt.audio.i_frame_length = FRAME_LENGTH; fmt.audio.i_channels = GetWLE ( &xa.nChannels ); fmt.audio.i_blockalign = fmt.audio.i_bytes_per_frame; fmt.audio.i_bitspersample = GetWLE( &xa.wBitsPerSample ); fmt.i_bitrate = (fmt.audio.i_rate * fmt.audio.i_bytes_per_frame * 8) / fmt.audio.i_frame_length; /* FIXME: better computation */ p_sys->i_data_size = xa.iSize * 15 / 56; /* How many frames per block (1:1 is too CPU intensive) */ p_sys->i_block_frames = fmt.audio.i_rate / (FRAME_LENGTH * 20) + 1; p_sys->i_frame_size = fmt.audio.i_bytes_per_frame; p_sys->i_bitrate = fmt.i_bitrate; msg_Dbg( p_demux, "fourcc: %4.4s, channels: %d, " "freq: %d Hz, bitrate: %dKo/s, blockalign: %d", (char *)&fmt.i_codec, fmt.audio.i_channels, fmt.audio.i_rate, fmt.i_bitrate / 8192, fmt.audio.i_blockalign ); if( fmt.audio.i_rate == 0 || fmt.audio.i_channels == 0 || fmt.audio.i_bitspersample != 16 ) return VLC_EGENERIC; p_sys->p_es = es_out_Add( p_demux->out, &fmt ); if( unlikely(p_sys->p_es == NULL) ) return VLC_ENOMEM; date_Init( &p_sys->pts, fmt.audio.i_rate, 1 ); date_Set( &p_sys->pts, VLC_TICK_0 ); p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys; return VLC_SUCCESS; }
static void ParseAPEvXTag( demux_meta_t *p_demux_meta, const uint8_t *p_data, int i_data ) { vlc_meta_t *p_meta; bool b_start; bool b_end; const uint8_t *p_header = NULL; int i_entry; if( i_data < APE_TAG_HEADERSIZE ) return; b_start = !strncmp( (char*)&p_data[0], "APETAGEX", 8 ); b_end = !strncmp( (char*)&p_data[i_data-APE_TAG_HEADERSIZE], "APETAGEX", 8 ); if( !b_end && !b_start ) return; if( !p_demux_meta->p_meta ) p_demux_meta->p_meta = vlc_meta_New(); p_meta = p_demux_meta->p_meta; if( b_start ) { p_header = &p_data[0]; p_data += APE_TAG_HEADERSIZE; i_data -= APE_TAG_HEADERSIZE; } if( b_end ) { p_header = &p_data[i_data-APE_TAG_HEADERSIZE]; i_data -= APE_TAG_HEADERSIZE; } if( i_data <= 0 ) return; i_entry = GetDWLE( &p_header[8+4+4] ); if( i_entry <= 0 ) return; while( i_entry > 0 && i_data >= 10 ) { const int i_size = GetDWLE( &p_data[0] ); const uint32_t flags = GetDWLE( &p_data[4] ); char psz_name[256]; int n; strlcpy( psz_name, (char*)&p_data[8], sizeof(psz_name) ); n = strlen( psz_name ); if( n <= 0 ) break; p_data += 8+n+1; i_data -= 8+n+1; if( i_data < i_size ) break; /* Retreive UTF-8 fields only */ if( ((flags>>1) & 0x03) == 0x00 ) { /* FIXME list are separated by '\0' */ char *psz_value = strndup( (char*)&p_data[0], i_size ); EnsureUTF8( psz_name ); EnsureUTF8( psz_value ); #define IS(s) (!strcasecmp( psz_name, s ) ) if( IS( "Title" ) ) vlc_meta_SetTitle( p_meta, psz_value ); else if( IS( "Artist" ) ) vlc_meta_SetArtist( p_meta, psz_value ); else if( IS( "Album" ) ) vlc_meta_SetAlbum( p_meta, psz_value ); else if( IS( "Publisher" ) ) vlc_meta_SetPublisher( p_meta, psz_value ); else if( IS( "Track" ) ) { char *p = strchr( psz_value, '/' ); if( p ) *p++ = '\0'; vlc_meta_SetTrackNum( p_meta, psz_value ); } else if( IS( "Comment" ) ) vlc_meta_SetDescription( p_meta, psz_value ); else if( IS( "Copyright" ) ) vlc_meta_SetCopyright( p_meta, psz_value ); else if( IS( "Year" ) ) vlc_meta_SetDate( p_meta, psz_value ); else if( IS( "Genre" ) ) vlc_meta_SetGenre( p_meta, psz_value ); else if( IS( "Language" ) ) vlc_meta_SetLanguage( p_meta, psz_value ); else vlc_meta_AddExtra( p_meta, psz_name, psz_value ); #undef IS free( psz_value ); } p_data += i_size; i_data -= i_size; i_entry--; } }
/***************************************************************************** * 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; byte_t *p_peek; int i_peek = 0; vlc_bool_t b_big_endian = 0; /* Arbitrary initialisation */ /* Check if we are dealing with a WAV file */ if( stream_Peek( p_demux->s, &p_peek, 12 ) == 12 && !memcmp( p_peek, "RIFF", 4 ) && !memcmp( p_peek + 8, "WAVE", 4 ) ) { int i_size; /* Skip the wave header */ i_peek = 12 + 8; while( stream_Peek( p_demux->s, &p_peek, i_peek ) == i_peek && memcmp( p_peek + i_peek - 8, "data", 4 ) ) { i_peek += GetDWLE( p_peek + i_peek - 4 ) + 8; } /* TODO: should check wave format and sample_rate */ /* Some A52 wav files don't begin with a sync code so we do a more * extensive search */ i_size = stream_Peek( p_demux->s, &p_peek, i_peek + A52_PACKET_SIZE * 2); i_size -= (PCM_FRAME_SIZE + A52_MAX_HEADER_SIZE); while( i_peek < i_size ) { if( CheckSync( p_peek + i_peek, &b_big_endian ) != VLC_SUCCESS ) /* The data is stored in 16 bits words */ i_peek += 2; else { /* Check following sync code */ if( CheckSync( p_peek + i_peek + PCM_FRAME_SIZE, &b_big_endian ) != VLC_SUCCESS ) { i_peek += 2; continue; } break; } } } /* Have a peep at the show. */ if( stream_Peek( p_demux->s, &p_peek, i_peek + A52_MAX_HEADER_SIZE * 2 ) < i_peek + A52_MAX_HEADER_SIZE * 2 ) { /* Stream too short */ msg_Warn( p_demux, "cannot peek()" ); return VLC_EGENERIC; } if( CheckSync( p_peek + i_peek, &b_big_endian ) != VLC_SUCCESS ) { if( strncmp( p_demux->psz_demux, "a52", 3 ) ) { return VLC_EGENERIC; } /* User forced */ msg_Err( p_demux, "this doesn't look like a A52 audio stream, " "continuing anyway" ); } /* Fill p_demux fields */ 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 = VLC_TRUE; p_sys->i_mux_rate = 0; p_sys->b_big_endian = b_big_endian; /* * Load the A52 packetizer */ p_sys->p_packetizer = vlc_object_create( p_demux, VLC_OBJECT_DECODER ); p_sys->p_packetizer->pf_decode_audio = 0; p_sys->p_packetizer->pf_decode_video = 0; p_sys->p_packetizer->pf_decode_sub = 0; p_sys->p_packetizer->pf_packetize = 0; /* Initialization of decoder structure */ es_format_Init( &p_sys->p_packetizer->fmt_in, AUDIO_ES, VLC_FOURCC( 'a', '5', '2', ' ' ) ); p_sys->p_packetizer->p_module = module_Need( p_sys->p_packetizer, "packetizer", NULL, 0 ); if( !p_sys->p_packetizer->p_module ) { msg_Err( p_demux, "cannot find A52 packetizer" ); return VLC_EGENERIC; } /* Create one program */ p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_in ); return VLC_SUCCESS; }
void vorbis_ParseComment( es_format_t *p_fmt, vlc_meta_t **pp_meta, const uint8_t *p_data, int i_data, int *i_attachments, input_attachment_t ***attachments, int *i_cover_score, int *i_cover_idx, int *i_seekpoint, seekpoint_t ***ppp_seekpoint, float (* ppf_replay_gain)[AUDIO_REPLAY_GAIN_MAX], float (* ppf_replay_peak)[AUDIO_REPLAY_GAIN_MAX] ) { int n; int i_comment; if( i_data < 8 ) return; n = GetDWLE(p_data); RM(4); if( n < 0 || n > i_data ) return; #if 0 if( n > 0 ) { /* TODO report vendor string ? */ char *psz_vendor = psz_vendor = strndup( p_data, n ); free( psz_vendor ); } #endif RM(n); if( i_data < 4 ) return; i_comment = GetDWLE(p_data); RM(4); if( i_comment <= 0 ) return; /* */ vlc_meta_t *p_meta = *pp_meta; if( !p_meta ) *pp_meta = p_meta = vlc_meta_New(); if( !p_meta ) return; /* */ bool hasTitle = false; bool hasArtist = false; bool hasGenre = false; bool hasCopyright = false; bool hasAlbum = false; bool hasTrackNum = false; bool hasDescription = false; bool hasRating = false; bool hasDate = false; bool hasLanguage = false; bool hasPublisher = false; bool hasEncodedBy = false; bool hasTrackTotal = false; chapters_array_t chapters_array = { 0, NULL }; for( ; i_comment > 0; i_comment-- ) { char *psz_comment; if( i_data < 4 ) break; n = GetDWLE(p_data); RM(4); if( n > i_data ) break; if( n <= 0 ) continue; psz_comment = strndup( (const char*)p_data, n ); RM(n); EnsureUTF8( psz_comment ); #define IF_EXTRACT(txt,var) \ if( !strncasecmp(psz_comment, txt, strlen(txt)) ) \ { \ const char *oldval = vlc_meta_Get( p_meta, vlc_meta_ ## var ); \ if( oldval && has##var) \ { \ char * newval; \ if( asprintf( &newval, "%s,%s", oldval, &psz_comment[strlen(txt)] ) == -1 ) \ newval = NULL; \ vlc_meta_Set( p_meta, vlc_meta_ ## var, newval ); \ free( newval ); \ } \ else \ vlc_meta_Set( p_meta, vlc_meta_ ## var, &psz_comment[strlen(txt)] ); \ has##var = true; \ } #define IF_EXTRACT_ONCE(txt,var) \ if( !strncasecmp(psz_comment, txt, strlen(txt)) && !has##var ) \ { \ vlc_meta_Set( p_meta, vlc_meta_ ## var, &psz_comment[strlen(txt)] ); \ has##var = true; \ } #define IF_EXTRACT_FMT(txt,var,fmt,target) \ IF_EXTRACT(txt,var)\ if( fmt && !strncasecmp(psz_comment, txt, strlen(txt)) )\ {\ if ( fmt->target ) free( fmt->target );\ fmt->target = strdup(&psz_comment[strlen(txt)]);\ } IF_EXTRACT("TITLE=", Title ) else IF_EXTRACT("ARTIST=", Artist ) else IF_EXTRACT("GENRE=", Genre ) else IF_EXTRACT("COPYRIGHT=", Copyright ) else IF_EXTRACT("ALBUM=", Album ) else if( !hasTrackNum && !strncasecmp(psz_comment, "TRACKNUMBER=", strlen("TRACKNUMBER=" ) ) ) { /* Yeah yeah, such a clever idea, let's put xx/xx inside TRACKNUMBER * Oh, and let's not use TRACKTOTAL or TOTALTRACKS... */ short unsigned u_track, u_total; if( sscanf( &psz_comment[strlen("TRACKNUMBER=")], "%hu/%hu", &u_track, &u_total ) == 2 ) { char str[6]; snprintf(str, 6, "%u", u_track); vlc_meta_Set( p_meta, vlc_meta_TrackNumber, str ); hasTrackNum = true; snprintf(str, 6, "%u", u_total); vlc_meta_Set( p_meta, vlc_meta_TrackTotal, str ); hasTrackTotal = true; } else { vlc_meta_Set( p_meta, vlc_meta_TrackNumber, &psz_comment[strlen("TRACKNUMBER=")] ); hasTrackNum = true; } } else IF_EXTRACT_ONCE("TRACKTOTAL=", TrackTotal ) else IF_EXTRACT_ONCE("TOTALTRACKS=", TrackTotal ) else IF_EXTRACT("DESCRIPTION=", Description ) else IF_EXTRACT("COMMENT=", Description ) else IF_EXTRACT("COMMENTS=", Description ) else IF_EXTRACT("RATING=", Rating ) else IF_EXTRACT("DATE=", Date ) else IF_EXTRACT_FMT("LANGUAGE=", Language, p_fmt, psz_language ) else IF_EXTRACT("ORGANIZATION=", Publisher ) else IF_EXTRACT("ENCODER=", EncodedBy ) else if( !strncasecmp( psz_comment, "METADATA_BLOCK_PICTURE=", strlen("METADATA_BLOCK_PICTURE="))) { if( attachments == NULL ) continue; uint8_t *p_picture; size_t i_size = vlc_b64_decode_binary( &p_picture, &psz_comment[strlen("METADATA_BLOCK_PICTURE=")]); input_attachment_t *p_attachment = ParseFlacPicture( p_picture, i_size, *i_attachments, i_cover_score, i_cover_idx ); free( p_picture ); if( p_attachment ) { TAB_APPEND_CAST( (input_attachment_t**), *i_attachments, *attachments, p_attachment ); } } else if ( ppf_replay_gain && ppf_replay_peak && !strncmp(psz_comment, "REPLAYGAIN_", 11) ) { char *p = strchr( psz_comment, '=' ); if (!p) continue; if ( !strncasecmp(psz_comment, "REPLAYGAIN_TRACK_GAIN=", 22) ) { (*ppf_replay_gain)[AUDIO_REPLAY_GAIN_TRACK] = us_atof( ++p ); } else if ( !strncasecmp(psz_comment, "REPLAYGAIN_ALBUM_GAIN=", 22) ) { (*ppf_replay_gain)[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( ++p ); } else if ( !strncasecmp(psz_comment, "REPLAYGAIN_ALBUM_PEAK=", 22) ) { (*ppf_replay_peak)[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( ++p ); } else if ( !strncasecmp(psz_comment, "REPLAYGAIN_TRACK_PEAK=", 22) ) { (*ppf_replay_peak)[AUDIO_REPLAY_GAIN_TRACK] = us_atof( ++p ); } } else if( !strncasecmp(psz_comment, "CHAPTER", 7) ) { unsigned int i_chapt; seekpoint_t *p_seekpoint = NULL; for( int i = 0; psz_comment[i] && psz_comment[i] != '='; i++ ) if( psz_comment[i] >= 'a' && psz_comment[i] <= 'z' ) psz_comment[i] -= 'a' - 'A'; if( strstr( psz_comment, "NAME=" ) && sscanf( psz_comment, "CHAPTER%uNAME=", &i_chapt ) == 1 ) { char *p = strchr( psz_comment, '=' ); p_seekpoint = getChapterEntry( i_chapt, &chapters_array ); if ( !p || ! p_seekpoint ) continue; if ( ! p_seekpoint->psz_name ) p_seekpoint->psz_name = strdup( ++p ); } else if( sscanf( psz_comment, "CHAPTER%u=", &i_chapt ) == 1 ) { unsigned int h, m, s, ms; char *p = strchr( psz_comment, '=' ); if( p && sscanf( ++p, "%u:%u:%u.%u", &h, &m, &s, &ms ) == 4 ) { p_seekpoint = getChapterEntry( i_chapt, &chapters_array ); if ( ! p_seekpoint ) continue; p_seekpoint->i_time_offset = (((int64_t)h * 3600 + (int64_t)m * 60 + (int64_t)s) * 1000 + ms) * 1000; } } } else if( strchr( psz_comment, '=' ) ) { /* generic (PERFORMER/LICENSE/ORGANIZATION/LOCATION/CONTACT/ISRC, * undocumented tags and replay gain ) */ char *p = strchr( psz_comment, '=' ); *p++ = '\0'; for( int i = 0; psz_comment[i]; i++ ) if( psz_comment[i] >= 'a' && psz_comment[i] <= 'z' ) psz_comment[i] -= 'a' - 'A'; vlc_meta_AddExtra( p_meta, psz_comment, p ); } #undef IF_EXTRACT free( psz_comment ); }
if( fseek( p_file, sizeof(index_record) * i_frame, SEEK_SET ) != 0 ) return false; if( fread( &index_record, sizeof(index_record), 1, p_file ) < 1 ) return false; /* VDR usually (only?) runs on little endian machines, but VLC has a * broader audience. See recording.* in VDR source for data layout. */ if( b_ts ) { uint64_t i_index_entry = GetQWLE( &index_record ); *pi_offset = i_index_entry & UINT64_C(0xFFFFFFFFFF); *pi_file_num = i_index_entry >> 48; } else { *pi_offset = GetDWLE( &index_record ); *pi_file_num = index_record[5]; } return true; } /***************************************************************************** * Convert time stamp from file to frame number *****************************************************************************/ static int64_t ParseFrameNumber( const char *psz_line, float fps ) { unsigned h, m, s, f, n; /* hour:min:sec.frame (frame is optional) */ n = sscanf( psz_line, "%u:%u:%u.%u", &h, &m, &s, &f );
static int SkipFile(stream_t *s, int *count, rar_file_t ***file, const rar_block_t *hdr, const char *volume_mrl) { const uint8_t *peek; int min_size = 7+21; if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH) min_size += 8; if (hdr->size < (unsigned)min_size) return VLC_EGENERIC; if (stream_Peek(s, &peek, min_size) < min_size) return VLC_EGENERIC; /* */ uint32_t file_size_low = GetDWLE(&peek[7+4]); uint8_t method = peek[7+18]; uint16_t name_size = GetWLE(&peek[7+19]); uint32_t file_size_high = 0; if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH) file_size_high = GetDWLE(&peek[7+25]); const uint64_t file_size = ((uint64_t)file_size_high << 32) | file_size_low; char *name = calloc(1, name_size + 1); if (!name) return VLC_EGENERIC; const int name_offset = (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH) ? (7+33) : (7+25); if (name_offset + name_size <= hdr->size) { const int max_size = name_offset + name_size; if (stream_Peek(s, &peek, max_size) < max_size) { free(name); return VLC_EGENERIC; } memcpy(name, &peek[name_offset], name_size); } rar_file_t *current = NULL; if (method != 0x30) { msg_Warn(s, "Ignoring compressed file %s (method=0x%2.2x)", name, method); goto exit; } /* */ if( *count > 0 ) current = (*file)[*count - 1]; if (current && (current->is_complete || strcmp(current->name, name) || (hdr->flags & RAR_BLOCK_FILE_HAS_PREVIOUS) == 0)) current = NULL; if (!current) { if (hdr->flags & RAR_BLOCK_FILE_HAS_PREVIOUS) goto exit; current = malloc(sizeof(*current)); if (!current) goto exit; TAB_APPEND(*count, *file, current); current->name = name; current->size = file_size; current->is_complete = false; current->real_size = 0; TAB_INIT(current->chunk_count, current->chunk); name = NULL; } /* Append chunks */ rar_file_chunk_t *chunk = malloc(sizeof(*chunk)); if (chunk) { chunk->mrl = strdup(volume_mrl); chunk->offset = stream_Tell(s) + hdr->size; chunk->size = hdr->add_size; chunk->cummulated_size = 0; if (current->chunk_count > 0) { rar_file_chunk_t *previous = current->chunk[current->chunk_count-1]; chunk->cummulated_size += previous->cummulated_size + previous->size; } TAB_APPEND(current->chunk_count, current->chunk, chunk); current->real_size += hdr->add_size; } if ((hdr->flags & RAR_BLOCK_FILE_HAS_NEXT) == 0) current->is_complete = true; exit: /* */ free(name); /* We stop on the first non empty file if we cannot seek */ if (current) { bool can_seek = false; stream_Control(s, STREAM_CAN_SEEK, &can_seek); if (!can_seek && current->size > 0) return VLC_EGENERIC; } if (SkipBlock(s, hdr)) return VLC_EGENERIC; return VLC_SUCCESS; }
/***************************************************************************** * 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; }