/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block; vlc_tick_t i_date; p_block = vlc_stream_Block( p_demux->s, CDG_FRAME_SIZE ); if( p_block == NULL ) { msg_Dbg( p_demux, "cannot read data, eof" ); return VLC_DEMUXER_EOF; } i_date = PosToDate( p_demux ); if( i_date >= date_Get( &p_sys->pts ) + CDG_FRAME_DELTA ) { p_block->i_dts = p_block->i_pts = VLC_TICK_0 + i_date; date_Set( &p_sys->pts, VLC_TICK_0 + i_date ); } else { p_block->i_dts = VLC_TICK_0 + i_date; p_block->i_pts = date_Get( &p_sys->pts ); } es_out_SetPCR( p_demux->out, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); return VLC_DEMUXER_SUCCESS; }
/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block; mtime_t i_date; mtime_t i_delta; i_delta = INT64_C(1000000) / CDG_FRAME_RATE; p_block = vlc_stream_Block( p_demux->s, CDG_FRAME_SIZE ); if( p_block == NULL ) { msg_Dbg( p_demux, "cannot read data, eof" ); return 0; } i_date = vlc_stream_Tell( p_demux->s ) / CDG_FRAME_SIZE * i_delta; if( i_date >= date_Get( &p_sys->pts ) + i_delta ) { p_block->i_dts = p_block->i_pts = i_date; date_Set( &p_sys->pts, i_date ); } else { p_block->i_dts = i_date; p_block->i_pts = date_Get( &p_sys->pts ); } es_out_SetPCR( p_demux->out, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); return 1; }
/***************************************************************************** * ProcessPacket: processes a Opus packet. *****************************************************************************/ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block = *pp_block; /* Date management */ if( p_block && p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->end_date ) ) { date_Set( &p_sys->end_date, p_block->i_pts ); } if( !date_Get( &p_sys->end_date ) ) { /* We've just started the stream, wait for the first PTS. */ if( p_block ) block_Release( p_block ); return NULL; } *pp_block = NULL; /* To avoid being fed the same packet again */ if( !p_block ) return NULL; block_t *p_aout_buffer = DecodePacket( p_dec, p_oggpacket, p_block->i_nb_samples, (int)p_block->i_length ); block_Release( p_block ); return p_aout_buffer; }
static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block ) { decoder_t *p_dec = p_private; decoder_sys_t *p_sys = p_dec->p_sys; const uint8_t *p_buf = &p_block->p_buffer[2]; size_t i_buf = p_block->i_buffer - 2; while( i_buf > 4 && p_buf[0] == 0xFF ) { size_t i_size = 2 + GetWBE( &p_buf[2] ); if( i_size > i_buf ) break; if( p_buf[1] == 0xC0 && i_buf > 9 ) { uint16_t i_height = GetWBE( &p_buf[5] ); uint16_t i_width = GetWBE( &p_buf[7] ); if( i_height && i_width && (p_dec->fmt_out.video.i_height != i_height || p_dec->fmt_out.video.i_width != i_width) ) { p_dec->fmt_out.video.i_width = p_dec->fmt_out.video.i_visible_width = i_width; p_dec->fmt_out.video.i_height = p_dec->fmt_out.video.i_visible_height = i_height; } break; } i_buf -= i_size; p_buf += i_size; } if( p_block->i_dts == VLC_TICK_INVALID ) p_block->i_dts = p_block->i_pts; else if( p_block->i_pts == VLC_TICK_INVALID ) p_block->i_pts = p_block->i_dts; vlc_tick_t i_prev_dts = date_Get( &p_sys->date ); if( p_block->i_dts != VLC_TICK_INVALID ) { date_Set( &p_sys->date, p_block->i_dts ); } else if( p_dec->fmt_in.video.i_frame_rate && p_dec->fmt_in.video.i_frame_rate_base ) { date_Increment( &p_sys->date, 1 ); p_block->i_dts = p_block->i_pts = date_Get( &p_sys->date ); } if( i_prev_dts != VLC_TICK_INVALID && p_block->i_dts != VLC_TICK_INVALID ) p_block->i_length = p_block->i_dts - i_prev_dts; *pb_ts_used = true; p_block->i_flags = p_sys->i_next_block_flags | BLOCK_FLAG_TYPE_I; p_sys->i_next_block_flags = 0; return p_block; }
static int Control(demux_t *demux, int query, va_list args) { demux_sys_t *sys = demux->p_sys; switch (query) { case DEMUX_CAN_SEEK: *va_arg(args, bool *) = sys->duration >= 0 && !sys->is_realtime; return VLC_SUCCESS; case DEMUX_GET_POSITION: { double *position = va_arg(args, double *); if (sys->duration > 0) *position = date_Get(&sys->pts) / (double)sys->duration; else *position = 0; return VLC_SUCCESS; } case DEMUX_SET_POSITION: { if (sys->duration < 0 || sys->is_realtime) return VLC_EGENERIC; double position = va_arg(args, double); date_Set(&sys->pts, position * sys->duration); return VLC_SUCCESS; } case DEMUX_GET_TIME: { int64_t *time = va_arg(args, int64_t *); *time = sys->pts_origin + date_Get(&sys->pts); return VLC_SUCCESS; } case DEMUX_SET_TIME: { if (sys->duration < 0 || sys->is_realtime) return VLC_EGENERIC; int64_t time = va_arg(args, int64_t); date_Set(&sys->pts, VLC_CLIP(time - sys->pts_origin, 0, sys->duration)); return VLC_SUCCESS; } case DEMUX_SET_NEXT_DEMUX_TIME: { int64_t pts_next = VLC_TS_0 + va_arg(args, int64_t); if (sys->pts_next <= VLC_TS_INVALID) sys->pts_origin = pts_next; sys->pts_next = pts_next; return VLC_SUCCESS; } case DEMUX_GET_LENGTH: { int64_t *length = va_arg(args, int64_t *); *length = __MAX(sys->duration, 0); return VLC_SUCCESS; } case DEMUX_GET_FPS: { double *fps = va_arg(args, double *); *fps = (double)sys->pts.i_divider_num / sys->pts.i_divider_den; return VLC_SUCCESS; } case DEMUX_GET_META: case DEMUX_HAS_UNSUPPORTED_META: case DEMUX_GET_ATTACHMENTS: default: return VLC_EGENERIC; } }
/***************************************************************************** * Thread: *****************************************************************************/ static void *Thread( void *p_thread_data ) { goom_thread_t *p_thread = (goom_thread_t*)p_thread_data; date_t i_pts; int16_t p_data[2][512]; int i_data = 0, i_count = 0; PluginInfo *p_plugin_info; int canc = vlc_savecancel (); p_plugin_info = goom_init( p_thread->i_width, p_thread->i_height ); for( ;; ) { uint32_t *plane; picture_t *p_pic; /* FIXME the way the update is done is not really good. * Supurious wake up from p_thread->wait will make it generates a frame * without using new samples (probably rare as we should not be waiting * samples). * The frame rate at which the video is generated is not well controlled * nor the time at which each frame is displayed (not smooth) */ /* goom_update is damn slow, so just copy data and release the lock */ vlc_mutex_lock( &p_thread->lock ); if( !p_thread->b_exit && FillBuffer( (int16_t *)p_data, &i_data, &i_pts, &p_thread->date, p_thread ) != VLC_SUCCESS ) vlc_cond_wait( &p_thread->wait, &p_thread->lock ); bool b_exit = p_thread->b_exit; vlc_mutex_unlock( &p_thread->lock ); if( b_exit ) break; /* Speed selection */ if( p_thread->i_speed && (++i_count % (p_thread->i_speed+1)) ) continue; /* Frame dropping if necessary */ if( date_Get( &i_pts ) + GOOM_DELAY <= mdate() ) continue; plane = goom_update( p_plugin_info, p_data, 0, 0.0, NULL, NULL ); p_pic = vout_GetPicture( p_thread->p_vout ); if( unlikely(p_pic == NULL) ) continue; memcpy( p_pic->p[0].p_pixels, plane, p_thread->i_width * p_thread->i_height * 4 ); p_pic->date = date_Get( &i_pts ) + GOOM_DELAY; vout_PutPicture( p_thread->p_vout, p_pic ); } goom_close( p_plugin_info ); vlc_restorecancel (canc); return NULL; }
/**************************************************************************** * DecodeBlock: the whole thing **************************************************************************** * This function must be fed with whole samples (see nBlockAlign). ****************************************************************************/ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; if( !pp_block || !*pp_block ) return NULL; block_t *p_block = *pp_block; if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->end_date ) ) { date_Set( &p_sys->end_date, p_block->i_pts ); } else if( !date_Get( &p_sys->end_date ) ) { /* We've just started the stream, wait for the first PTS. */ block_Release( p_block ); return NULL; } /* Don't re-use the same pts twice */ p_block->i_pts = VLC_TS_INVALID; unsigned samples = (8 * p_block->i_buffer) / p_sys->framebits; if( samples == 0 ) { block_Release( p_block ); return NULL; } /* Create chunks of max 1024 samples */ if( samples > 1024 ) samples = 1024; block_t *p_out = decoder_NewAudioBuffer( p_dec, samples ); if( p_out == NULL ) { block_Release( p_block ); return NULL; } p_out->i_pts = date_Get( &p_sys->end_date ); p_out->i_length = date_Increment( &p_sys->end_date, samples ) - p_out->i_pts; if( p_sys->decode != NULL ) p_sys->decode( p_out->p_buffer, p_block->p_buffer, samples * p_dec->fmt_in.audio.i_channels ); else memcpy( p_out->p_buffer, p_block->p_buffer, p_out->i_buffer ); samples = (samples * p_sys->framebits) / 8; p_block->p_buffer += samples; p_block->i_buffer -= samples; return p_out; }
/**************************************************************************** * DecodeBlock: the whole thing **************************************************************************** * This function must be fed with whole samples (see nBlockAlign). ****************************************************************************/ static int DecodeBlock( decoder_t *p_dec, block_t *p_block ) { decoder_sys_t *p_sys = p_dec->p_sys; if( p_block == NULL ) /* No Drain */ return VLCDEC_SUCCESS; if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED|BLOCK_FLAG_DISCONTINUITY) ) { Flush( p_dec ); if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) goto skip; } if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->end_date ) ) { date_Set( &p_sys->end_date, p_block->i_pts ); } else if( !date_Get( &p_sys->end_date ) ) /* We've just started the stream, wait for the first PTS. */ goto skip; unsigned samples = (8 * p_block->i_buffer) / p_sys->framebits; if( samples == 0 ) goto skip; if( p_sys->decode != NULL ) { if( decoder_UpdateAudioFormat( p_dec ) ) goto skip; block_t *p_out = decoder_NewAudioBuffer( p_dec, samples ); if( p_out == NULL ) goto skip; p_sys->decode( p_out->p_buffer, p_block->p_buffer, samples * p_dec->fmt_in.audio.i_channels ); block_Release( p_block ); p_block = p_out; } else { decoder_UpdateAudioFormat( p_dec ); p_block->i_nb_samples = samples; p_block->i_buffer = samples * (p_sys->framebits / 8); } p_block->i_pts = date_Get( &p_sys->end_date ); p_block->i_length = date_Increment( &p_sys->end_date, samples ) - p_block->i_pts; decoder_QueueAudio( p_dec, p_block ); return VLCDEC_SUCCESS; skip: block_Release( p_block ); return VLCDEC_SUCCESS; }
/***************************************************************************** * Demux: read chunks and send them to the synthesizer ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/ static int Demux (demux_t *p_demux) { stream_t *s = p_demux->s; demux_sys_t *p_sys = p_demux->p_sys; uint64_t pulse = p_sys->pulse, next_pulse = UINT64_MAX; if (pulse == UINT64_MAX) return 0; /* all tracks are done */ es_out_Control (p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + date_Get (&p_sys->pts)); for (unsigned i = 0; i < p_sys->trackc; i++) { mtrk_t *track = p_sys->trackv + i; while (track->next == pulse) { if (HandleMessage (p_demux, track) || ReadDeltaTime (s, track)) { msg_Err (p_demux, "fatal parsing error"); return VLC_EGENERIC; } } if (track->next < next_pulse) next_pulse = track->next; } mtime_t cur_tick = (date_Get (&p_sys->pts) + 9999) / 10000, last_tick; if (next_pulse != UINT64_MAX) last_tick = date_Increment (&p_sys->pts, next_pulse - pulse) / 10000; else last_tick = cur_tick + 1; /* MIDI Tick emulation (ping the decoder every 10ms) */ while (cur_tick < last_tick) { block_t *tick = block_New (p_demux, 1); if (tick == NULL) break; tick->p_buffer[0] = 0xF9; tick->i_dts = tick->i_pts = VLC_TS_0 + cur_tick++ * 10000; es_out_Send (p_demux->out, p_sys->es, tick); } p_sys->pulse = next_pulse; return 1; }
/**************************************************************************** * DecodeBlock: the whole thing **************************************************************************** * This function must be fed with whole samples (see nBlockAlign). ****************************************************************************/ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; if( pp_block == NULL ) return NULL; block_t *p_block = *pp_block; if( p_block == NULL ) return NULL; *pp_block = NULL; if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->end_date ) ) { date_Set( &p_sys->end_date, p_block->i_pts ); } else if( !date_Get( &p_sys->end_date ) ) /* We've just started the stream, wait for the first PTS. */ goto skip; unsigned samples = (8 * p_block->i_buffer) / p_sys->framebits; if( samples == 0 ) goto skip; if( p_sys->decode != NULL ) { block_t *p_out = decoder_NewAudioBuffer( p_dec, samples ); if( p_out == NULL ) goto skip; p_sys->decode( p_out->p_buffer, p_block->p_buffer, samples * p_dec->fmt_in.audio.i_channels ); block_Release( p_block ); p_block = p_out; } else { decoder_UpdateAudioFormat( p_dec ); p_block->i_nb_samples = samples; p_block->i_buffer = samples * (p_sys->framebits / 8); } p_block->i_pts = date_Get( &p_sys->end_date ); p_block->i_length = date_Increment( &p_sys->end_date, samples ) - p_block->i_pts; return p_block; skip: block_Release( p_block ); return NULL; }
static int Demux (demux_t *demux) { demux_sys_t *sys = demux->p_sys; block_t *block = block_Alloc( sys->block_size); if (unlikely(block==NULL)) return 0; if (!sys->tune->getStatus()) { block_Release (block); return 0; } int i_read = sys->player->play ((void*)block->p_buffer, block->i_buffer); if (i_read <= 0) { block_Release (block); return 0; } block->i_buffer = i_read; block->i_pts = block->i_dts = VLC_TS_0 + date_Get (&sys->pts); es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts); es_out_Send (demux->out, sys->es, block); date_Increment (&sys->pts, i_read / sys->bytes_per_frame); return 1; }
/***************************************************************************** * DecodePacket: decodes a Speex packet. *****************************************************************************/ static block_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket ) { decoder_sys_t *p_sys = p_dec->p_sys; if( p_oggpacket->bytes ) { /* Copy Ogg packet to Speex bitstream */ speex_bits_read_from( &p_sys->bits, (char *)p_oggpacket->packet, p_oggpacket->bytes ); p_sys->i_frame_in_packet = 0; } /* Decode one frame at a time */ if( p_sys->i_frame_in_packet < p_sys->p_header->frames_per_packet ) { block_t *p_aout_buffer; if( p_sys->p_header->frame_size == 0 ) return NULL; p_aout_buffer = decoder_NewAudioBuffer( p_dec, p_sys->p_header->frame_size ); if( !p_aout_buffer ) { return NULL; } switch( speex_decode_int( p_sys->p_state, &p_sys->bits, (int16_t *)p_aout_buffer->p_buffer ) ) { case -2: msg_Err( p_dec, "decoding error: corrupted stream?" ); case -1: /* End of stream */ return NULL; } if( speex_bits_remaining( &p_sys->bits ) < 0 ) { msg_Err( p_dec, "decoding overflow: corrupted stream?" ); } if( p_sys->p_header->nb_channels == 2 ) speex_decode_stereo_int( (int16_t *)p_aout_buffer->p_buffer, p_sys->p_header->frame_size, &p_sys->stereo ); /* Date management */ p_aout_buffer->i_pts = date_Get( &p_sys->end_date ); p_aout_buffer->i_length = date_Increment( &p_sys->end_date, p_sys->p_header->frame_size ) - p_aout_buffer->i_pts; p_sys->i_frame_in_packet++; return p_aout_buffer; } else { return NULL; } }
/***************************************************************************** * Demux: *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; block_t *p_frame; const int i_bk = ( p_sys->fmt.audio.i_bitspersample / 8 ) * p_sys->fmt.audio.i_channels; p_frame = block_Alloc( p_sys->fmt.audio.i_rate / 10 * i_bk ); if( !p_frame ) return VLC_DEMUXER_EGENERIC; const int i_read = ModPlug_Read( p_sys->f, p_frame->p_buffer, p_frame->i_buffer ); if( i_read <= 0 ) { /* EOF */ block_Release( p_frame ); return VLC_DEMUXER_EOF; } p_frame->i_buffer = i_read; p_frame->i_dts = p_frame->i_pts = date_Get( &p_sys->pts ); es_out_SetPCR( p_demux->out, p_frame->i_pts ); es_out_Send( p_demux->out, p_sys->es, p_frame ); date_Increment( &p_sys->pts, i_read / i_bk ); return VLC_DEMUXER_SUCCESS; }
/***************************************************************************** * SplitBuffer: Needed because aout really doesn't like big audio chunk and * wma produces easily > 30000 samples... *****************************************************************************/ static aout_buffer_t *SplitBuffer( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; int i_samples = __MIN( p_sys->i_samples, 4096 ); aout_buffer_t *p_buffer; if( i_samples == 0 ) return NULL; if( ( p_buffer = decoder_NewAudioBuffer( p_dec, i_samples ) ) == NULL ) return NULL; p_buffer->i_pts = date_Get( &p_sys->end_date ); p_buffer->i_length = date_Increment( &p_sys->end_date, i_samples ) - p_buffer->i_pts; if( p_sys->b_extract ) aout_ChannelExtract( p_buffer->p_buffer, p_dec->fmt_out.audio.i_channels, p_sys->p_samples, p_sys->p_context->channels, i_samples, p_sys->pi_extraction, p_dec->fmt_out.audio.i_bitspersample ); else memcpy( p_buffer->p_buffer, p_sys->p_samples, p_buffer->i_buffer ); p_sys->p_samples += i_samples * p_sys->p_context->channels * ( p_dec->fmt_out.audio.i_bitspersample / 8 ); p_sys->i_samples -= i_samples; return p_buffer; }
static int Audio_OnNewBlock(decoder_t *p_dec, block_t *p_block, int *p_flags) { decoder_sys_t *p_sys = p_dec->p_sys; /* We've just started the stream, wait for the first PTS. */ if (!date_Get(&p_sys->u.audio.i_end_date)) { if (p_block->i_pts <= VLC_TS_INVALID) return 0; date_Set(&p_sys->u.audio.i_end_date, p_block->i_pts); } /* try delayed opening if there is a new extra data */ if (!p_sys->api->b_started) { p_dec->p_sys->u.audio.i_channels = p_dec->fmt_in.audio.i_channels; *p_flags |= NEWBLOCK_FLAG_RESTART; /* Don't start if we don't have any csd */ if ((p_sys->i_quirks & OMXCODEC_QUIRKS_NEED_CSD) && !p_dec->fmt_in.i_extra) *p_flags &= ~NEWBLOCK_FLAG_RESTART; /* Don't start if we don't have a valid channels count */ if ((p_sys->i_quirks & OMXCODEC_AUDIO_QUIRKS_NEED_CHANNELS) && !p_dec->p_sys->u.audio.i_channels) *p_flags &= ~NEWBLOCK_FLAG_RESTART; } return 1; }
/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block; int64_t i_offset = vlc_stream_Tell( p_demux->s ); unsigned i_frames = p_sys->i_block_frames; if( p_sys->i_data_size > 0 && (i_offset - HEADER_LENGTH) >= p_sys->i_data_size ) { return VLC_DEMUXER_EOF; } p_block = vlc_stream_Block( p_demux->s, p_sys->i_frame_size * i_frames ); if( p_block == NULL ) { msg_Warn( p_demux, "cannot read data" ); return VLC_DEMUXER_EOF; } i_frames = p_block->i_buffer / p_sys->i_frame_size; p_block->i_dts = p_block->i_pts = date_Get( &p_sys->pts ); es_out_SetPCR( p_demux->out, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); date_Increment( &p_sys->pts, i_frames * FRAME_LENGTH ); return VLC_DEMUXER_SUCCESS; }
/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block; int64_t i_offset; unsigned i_frames = p_sys->i_block_frames; i_offset = stream_Tell( p_demux->s ); if( p_sys->i_data_size > 0 && i_offset >= p_sys->i_data_offset + p_sys->i_data_size ) { /* EOF */ return 0; } p_block = stream_Block( p_demux->s, p_sys->fmt.audio.i_bytes_per_frame * i_frames ); if( p_block == NULL ) { msg_Warn( p_demux, "cannot read data" ); return 0; } i_frames = p_block->i_buffer / p_sys->fmt.audio.i_bytes_per_frame; p_block->i_dts = p_block->i_pts = VLC_TS_0 + date_Get( &p_sys->pts ); es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); date_Increment( &p_sys->pts, i_frames * p_sys->fmt.audio.i_frame_length ); return 1; }
/***************************************************************************** * SendFrame: send a video frame to the stream output. *****************************************************************************/ static block_t *SendFrame( decoder_t *p_dec, block_t *p_block ) { decoder_sys_t *p_sys = p_dec->p_sys; p_block->i_dts = p_block->i_pts = date_Get( &p_sys->pts ); if( p_sys->b_invert ) { block_t *out = block_Alloc( p_block->i_buffer ); if( likely(out != NULL) ) { block_CopyProperties( out, p_block ); const uint8_t *p_src = p_block->p_buffer; uint8_t *p_pixels = out->p_buffer; for( unsigned i = 0; i < PICTURE_PLANE_MAX; i++ ) { unsigned pitch = p_sys->pitches[i]; unsigned lines = p_sys->lines[i]; uint8_t *p_dst = p_pixels + (pitch * lines); for( unsigned x = 0; x < lines; x++ ) { p_dst -= p_sys->pitches[i]; memcpy( p_dst, p_src, p_sys->pitches[i] ); p_src += p_sys->pitches[i]; } } } block_Release( p_block ); } return p_block; }
static int DemuxOnce (demux_t *demux, bool master) { demux_sys_t *sys = demux->p_sys; mtime_t pts = date_Get (&sys->date); lldiv_t d; unsigned h, m, s, f; d = lldiv (pts, CLOCK_FREQ); f = d.rem * sys->date.i_divider_num / sys->date.i_divider_den / CLOCK_FREQ; d = lldiv (d.quot, 60); s = d.rem; d = lldiv (d.quot, 60); m = d.rem; h = d.quot; char *str; int len = asprintf (&str, "%02u:%02u:%02u:%02u", h, m, s, f); if (len == -1) return -1; block_t *block = block_heap_Alloc (str, len + 1); if (unlikely(block == NULL)) return -1; block->i_buffer = len; assert(str[len] == '\0'); block->i_pts = block->i_dts = pts; block->i_length = date_Increment (&sys->date, 1) - pts; es_out_Send (demux->out, sys->es, block); if (master) es_out_SetPCR(demux->out, pts); return 1; }
static int Demux (demux_t *demux) { demux_sys_t *sys = demux->p_sys; /* Next track */ if (gme_track_ended (sys->emu)) { msg_Dbg (demux, "track %u ended", sys->track_id); if (++sys->track_id >= (unsigned)gme_track_count (sys->emu)) return 0; demux->info.i_update |= INPUT_UPDATE_TITLE; demux->info.i_title = sys->track_id; gme_start_track (sys->emu, sys->track_id); } block_t *block = block_Alloc (2 * 2 * SAMPLES); if (unlikely(block == NULL)) return 0; gme_err_t ret = gme_play (sys->emu, 2 * SAMPLES, (void *)block->p_buffer); if (ret != NULL) { block_Release (block); msg_Err (demux, "%s", ret); return 0; } block->i_pts = block->i_dts = VLC_TS_0 + date_Get (&sys->pts); es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts); es_out_Send (demux->out, sys->es, block); date_Increment (&sys->pts, SAMPLES); return 1; }
/***************************************************************************** * DecodeFrame: decodes a video frame. *****************************************************************************/ static picture_t *DecodeFrame( decoder_t *p_dec, block_t *p_block ) { decoder_sys_t *p_sys = p_dec->p_sys; picture_t *p_pic; /* Get a new picture */ p_pic = decoder_NewPicture( p_dec ); if( !p_pic ) { block_Release( p_block ); return NULL; } FillPicture( p_dec, p_block, p_pic ); p_pic->date = date_Get( &p_sys->pts ); if( p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK ) { p_pic->b_progressive = false; p_pic->i_nb_fields = 2; if( p_block->i_flags & BLOCK_FLAG_TOP_FIELD_FIRST ) p_pic->b_top_field_first = true; else p_pic->b_top_field_first = false; } else p_pic->b_progressive = true; block_Release( p_block ); return p_pic; }
/***************************************************************************** * ProcessPacket: processes a Vorbis packet. *****************************************************************************/ static block_t *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block = *pp_block; *pp_block = NULL; /* To avoid being fed the same packet again */ if( !p_block ) return NULL; if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { Flush( p_dec ); if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) { block_Release(p_block); return NULL; } } /* Date management */ if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->end_date ) ) { date_Set( &p_sys->end_date, p_block->i_pts ); } if( !date_Get( &p_sys->end_date ) ) { /* We've just started the stream, wait for the first PTS. */ if( p_block ) block_Release( p_block ); return NULL; } if( p_sys->b_packetizer ) { return SendPacket( p_dec, p_oggpacket, p_block ); } else { block_t *p_aout_buffer = DecodePacket( p_dec, p_oggpacket ); if( p_block ) block_Release( p_block ); return p_aout_buffer; } }
/***************************************************************************** * DecodePacket: decodes a Opus packet. *****************************************************************************/ static block_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket, int i_nb_samples, int i_end_trim ) { decoder_sys_t *p_sys = p_dec->p_sys; if( !p_oggpacket->bytes ) return NULL; int spp; spp=opus_packet_get_nb_frames(p_oggpacket->packet,p_oggpacket->bytes); if(spp>0)spp*=opus_packet_get_samples_per_frame(p_oggpacket->packet,48000); if(spp<120||spp>120*48)return NULL; block_t *p_aout_buffer=decoder_NewAudioBuffer( p_dec, spp ); if ( !p_aout_buffer ) { msg_Err(p_dec, "Oops: No new buffer was returned!"); return NULL; } spp=opus_multistream_decode_float(p_sys->p_st, p_oggpacket->packet, p_oggpacket->bytes, (float *)p_aout_buffer->p_buffer, spp, 0); if( spp < 0 || i_nb_samples <= 0 || i_end_trim >= i_nb_samples) { block_Release(p_aout_buffer); if( spp < 0 ) msg_Err( p_dec, "Error: corrupted stream?" ); return NULL; } p_aout_buffer->i_buffer = (i_nb_samples - i_end_trim) * p_sys->header.channels * sizeof(float); if( spp > i_nb_samples ) { memmove(p_aout_buffer->p_buffer, p_aout_buffer->p_buffer + (spp - i_nb_samples)*p_sys->header.channels*sizeof(float), (i_nb_samples - i_end_trim)*p_sys->header.channels*sizeof(float)); } i_nb_samples -= i_end_trim; #ifndef OPUS_SET_GAIN if(p_sys->header.gain!=0) { float gain = pow(10., p_sys->header.gain/5120.); float *buf =(float *)p_aout_buffer->p_buffer; int i; for( i = 0; i < i_nb_samples*p_sys->header.channels; i++) buf[i] *= gain; } #endif p_aout_buffer->i_nb_samples = i_nb_samples; p_aout_buffer->i_pts = date_Get( &p_sys->end_date ); p_aout_buffer->i_length = date_Increment( &p_sys->end_date, i_nb_samples ) - p_aout_buffer->i_pts; return p_aout_buffer; }
/**************************************************************************** * DecodeBlock: the whole thing **************************************************************************** * This function must be fed with complete frames. ****************************************************************************/ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; void *p_buf; if( !pp_block || !*pp_block ) return NULL; p_block = *pp_block; if( p_block->i_pts <= VLC_TS_INVALID && p_block->i_dts <= VLC_TS_INVALID && !date_Get( &p_sys->pts ) ) { /* We've just started the stream, wait for the first PTS. */ block_Release( p_block ); return NULL; } /* Date management: If there is a pts avaliable, use that. */ if( p_block->i_pts > VLC_TS_INVALID ) { date_Set( &p_sys->pts, p_block->i_pts ); } else if( p_block->i_dts > VLC_TS_INVALID ) { /* NB, davidf doesn't quite agree with this in general, it is ok * for rawvideo since it is in order (ie pts=dts), however, it * may not be ok for an out-of-order codec, so don't copy this * without thinking */ date_Set( &p_sys->pts, p_block->i_dts ); } if( p_block->i_buffer < p_sys->i_raw_size ) { msg_Warn( p_dec, "invalid frame size (%zu < %zu)", p_block->i_buffer, p_sys->i_raw_size ); block_Release( p_block ); return NULL; } if( p_sys->b_packetizer ) { p_buf = SendFrame( p_dec, p_block ); } else { p_buf = DecodeFrame( p_dec, p_block ); } /* Date management: 1 frame per packet */ date_Increment( &p_sys->pts, 1 ); *pp_block = NULL; return p_buf; }
/***************************************************************************** * aout_FifoPush : push a packet into the FIFO *****************************************************************************/ void aout_FifoPush( aout_fifo_t * p_fifo, aout_buffer_t * p_buffer ) { *p_fifo->pp_last = p_buffer; p_fifo->pp_last = &p_buffer->p_next; *p_fifo->pp_last = NULL; /* Enforce the continuity of the stream. */ if ( date_Get( &p_fifo->end_date ) ) { p_buffer->i_pts = date_Get( &p_fifo->end_date ); p_buffer->i_length = date_Increment( &p_fifo->end_date, p_buffer->i_nb_samples ); p_buffer->i_length -= p_buffer->i_pts; } else { date_Set( &p_fifo->end_date, p_buffer->i_pts + p_buffer->i_length ); } }
static int Demux(demux_t *demux) { demux_sys_t *sys = demux->p_sys; if (!sys->data) return 0; mtime_t deadline; const mtime_t pts_first = sys->pts_origin + date_Get(&sys->pts); if (sys->pts_next > VLC_TS_INVALID) { deadline = sys->pts_next; } else if (sys->is_realtime) { deadline = mdate(); const mtime_t max_wait = CLOCK_FREQ / 50; if (deadline + max_wait < pts_first) { es_out_Control(demux->out, ES_OUT_SET_PCR, deadline); /* That's ugly, but not yet easily fixable */ mwait(deadline + max_wait); return 1; } } else { deadline = 1 + pts_first; } for (;;) { const mtime_t pts = sys->pts_origin + date_Get(&sys->pts); if (sys->duration >= 0 && pts >= sys->pts_origin + sys->duration) return 0; if (pts >= deadline) return 1; block_t *data = block_Duplicate(sys->data); if (!data) return -1; data->i_dts = data->i_pts = VLC_TS_0 + pts; es_out_Control(demux->out, ES_OUT_SET_PCR, data->i_pts); es_out_Send(demux->out, sys->es, data); date_Increment(&sys->pts, 1); } }
int transcode_audio_process( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *in, block_t **out ) { sout_stream_sys_t *p_sys = p_stream->p_sys; block_t *p_block, *p_audio_buf; *out = NULL; while( (p_audio_buf = id->p_decoder->pf_decode_audio( id->p_decoder, &in )) ) { sout_UpdateStatistic( p_stream->p_sout, SOUT_STATISTIC_DECODED_AUDIO, 1 ); if( p_sys->b_master_sync ) { mtime_t i_dts = date_Get( &id->interpolated_pts ) + 1; if ( p_audio_buf->i_pts - i_dts > MASTER_SYNC_MAX_DRIFT || p_audio_buf->i_pts - i_dts < -MASTER_SYNC_MAX_DRIFT ) { msg_Dbg( p_stream, "drift is too high, resetting master sync" ); date_Set( &id->interpolated_pts, p_audio_buf->i_pts ); i_dts = p_audio_buf->i_pts + 1; } p_sys->i_master_drift = p_audio_buf->i_pts - i_dts; date_Increment( &id->interpolated_pts, p_audio_buf->i_nb_samples ); p_audio_buf->i_pts -= p_sys->i_master_drift; } p_audio_buf->i_dts = p_audio_buf->i_pts; /* Run filter chain */ if( id->p_uf_chain ) { p_audio_buf = filter_chain_AudioFilter( id->p_uf_chain, p_audio_buf ); if( !p_audio_buf ) abort(); } p_audio_buf = filter_chain_AudioFilter( id->p_f_chain, p_audio_buf ); if( !p_audio_buf ) abort(); p_audio_buf->i_dts = p_audio_buf->i_pts; audio_timer_start( id->p_encoder ); p_block = id->p_encoder->pf_encode_audio( id->p_encoder, p_audio_buf ); audio_timer_stop( id->p_encoder ); block_ChainAppend( out, p_block ); block_Release( p_audio_buf ); } return VLC_SUCCESS; }
/***************************************************************************** * Fill buffer *****************************************************************************/ static int FillBuffer( int16_t *p_data, int *pi_data, date_t *pi_date, date_t *pi_date_end, goom_thread_t *p_this ) { int i_samples = 0; block_t *p_block; while( *pi_data < 512 ) { if( !p_this->i_blocks ) return VLC_EGENERIC; p_block = p_this->pp_blocks[0]; i_samples = __MIN( (unsigned)(512 - *pi_data), p_block->i_buffer / sizeof(float) / p_this->i_channels ); /* Date management */ if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( pi_date_end ) ) { date_Set( pi_date_end, p_block->i_pts ); } p_block->i_pts = VLC_TS_INVALID; date_Increment( pi_date_end, i_samples ); while( i_samples > 0 ) { float *p_float = (float *)p_block->p_buffer; p_data[*pi_data] = FloatToInt16( p_float[0] ); if( p_this->i_channels > 1 ) p_data[512 + *pi_data] = FloatToInt16( p_float[1] ); (*pi_data)++; p_block->p_buffer += (sizeof(float) * p_this->i_channels); p_block->i_buffer -= (sizeof(float) * p_this->i_channels); i_samples--; } if( !p_block->i_buffer ) { block_Release( p_block ); p_this->i_blocks--; if( p_this->i_blocks ) memmove( p_this->pp_blocks, p_this->pp_blocks + 1, p_this->i_blocks * sizeof(block_t *) ); } } *pi_date = *pi_date_end; *pi_data = 0; return VLC_SUCCESS; }
/** * Move forwards or backwards all dates in the FIFO. */ static void aout_FifoMoveDates( aout_fifo_t *fifo, mtime_t difference ) { if( date_Get( &fifo->end_date ) == VLC_TS_INVALID ) { assert( fifo->p_first == NULL ); return; } date_Move( &fifo->end_date, difference ); for( block_t *block = fifo->p_first; block != NULL; block = block->p_next ) block->i_pts += difference; }
static int Control (demux_t *demux, int query, va_list args) { demux_sys_t *sys = demux->p_sys; switch (query) { case DEMUX_GET_POSITION: *va_arg (args, float *) = 0.f; break; case DEMUX_GET_LENGTH: *va_arg (args, int64_t *) = INT64_C(0); break; case DEMUX_GET_TIME: *va_arg (args, int64_t *) = date_Get (&sys->date); break; case DEMUX_SET_TIME: date_Set (&sys->date, va_arg (args, int64_t)); break; case DEMUX_SET_NEXT_DEMUX_TIME: { const mtime_t pts = va_arg (args, int64_t ); if (sys->next_time == VLC_TS_INVALID) /* first invocation? */ { date_Set (&sys->date, pts); date_Decrement (&sys->date, 1); } sys->next_time = pts; break; } case DEMUX_GET_PTS_DELAY: { int64_t *v = va_arg (args, int64_t *); *v = INT64_C(1000) * var_InheritInteger (demux, "live-caching"); break; } case DEMUX_CAN_PAUSE: case DEMUX_CAN_CONTROL_PACE: case DEMUX_CAN_SEEK: *va_arg (args, bool *) = true; break; default: return VLC_EGENERIC; } return VLC_SUCCESS; }