static void* EncoderThread( void *obj ) { sout_stream_sys_t *p_sys = (sout_stream_sys_t*)obj; sout_stream_id_sys_t *id = p_sys->id_video; picture_t *p_pic = NULL; int canc = vlc_savecancel (); block_t *p_block = NULL; vlc_mutex_lock( &p_sys->lock_out ); for( ;; ) { while( !p_sys->b_abort && (p_pic = picture_fifo_Pop( p_sys->pp_pics )) == NULL ) vlc_cond_wait( &p_sys->cond, &p_sys->lock_out ); if( p_pic ) { /* release lock while encoding */ vlc_mutex_unlock( &p_sys->lock_out ); p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); picture_Release( p_pic ); vlc_mutex_lock( &p_sys->lock_out ); block_ChainAppend( &p_sys->p_buffers, p_block ); } if( p_sys->b_abort ) break; } /*Encode what we have in the buffer on closing*/ while( (p_pic = picture_fifo_Pop( p_sys->pp_pics )) != NULL ) { p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); picture_Release( p_pic ); block_ChainAppend( &p_sys->p_buffers, p_block ); } /*Now flush encoder*/ do { p_block = id->p_encoder->pf_encode_video(id->p_encoder, NULL ); block_ChainAppend( &p_sys->p_buffers, p_block ); } while( p_block ); vlc_mutex_unlock( &p_sys->lock_out ); vlc_restorecancel (canc); return NULL; }
block_t *scan_GetM3U( scan_t *p_scan ) { vlc_object_t *p_obj = p_scan->p_obj; block_t *p_playlist = NULL; if( p_scan->i_service <= 0 ) return NULL; /* */ qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp ); /* */ p_playlist = BlockString( "#EXTM3U\n\n" );/* */ for( int i = 0; i < p_scan->i_service; i++ ) { scan_service_t *s = p_scan->pp_service[i]; if( s->type == SERVICE_UNKNOWN ) { /* We should only select service that have been described by SDT */ msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program ); continue; } const char *psz_type; switch( s->type ) { case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break; case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break; case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break; case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break; default: psz_type = "Unknown"; break; } msg_Warn( p_obj, "scan_GetM3U: service number %d type '%s' name '%s' channel %d cypted=%d| network_id %d (nit:%d sdt:%d)| f=%d bw=%d snr=%d", s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted, s->i_network_id, s->i_nit_version, s->i_sdt_version, s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr ); char *psz; if( asprintf( &psz, "#EXTINF:,,%s\n" "#EXTVLCOPT:program=%d\n" "dvb://frequency=%d:bandwidth=%d\n" "\n", s->psz_name && * s->psz_name ? s->psz_name : "Unknown", s->i_program, s->cfg.i_frequency, s->cfg.i_bandwidth ) < 0 ) psz = NULL; if( psz ) { block_t *p_block = BlockString( psz ); if( p_block ) block_ChainAppend( &p_playlist, p_block ); } } return p_playlist ? block_ChainGather( p_playlist ) : NULL; }
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; block_t * p_nal = NULL; while (p_block->i_buffer > 5 && p_block->p_buffer[p_block->i_buffer-1] == 0x00 ) p_block->i_buffer--; bs_t bs; bs_init(&bs, p_block->p_buffer+3, p_block->i_buffer-3); /* Get NALU type */ uint32_t forbidden_zero_bit = bs_read1(&bs); if (forbidden_zero_bit) { msg_Err(p_dec,"Forbidden zero bit not null, corrupted NAL"); p_sys->p_frame = NULL; p_sys->b_vcl = false; return NULL; } uint32_t nalu_type = bs_read(&bs,6); bs_skip(&bs, 9); if (nalu_type < VPS) { /* NAL is a VCL NAL */ p_sys->b_vcl = true; uint32_t first_slice_in_pic = bs_read1(&bs); if (first_slice_in_pic && p_sys->p_frame) { p_nal = block_ChainGather(p_sys->p_frame); p_sys->p_frame = NULL; } block_ChainAppend(&p_sys->p_frame, p_block); } else { if (p_sys->b_vcl) { p_nal = block_ChainGather(p_sys->p_frame); p_nal->p_next = p_block; p_sys->p_frame = NULL; p_sys->b_vcl =false; } else p_nal = p_block; } *pb_ts_used = false; return p_nal; }
static block_t *EncodeFrame( encoder_t *p_enc, block_t *p_block ) { if (!p_block) /* TODO: flush */ return NULL; encoder_sys_t *p_sys = p_enc->p_sys; block_t *p_pcm_block; block_t *p_chain = NULL; unsigned int i_samples = p_block->i_buffer >> 2 /* s16l stereo */; mtime_t start_date = p_block->i_pts; start_date -= (mtime_t)i_samples * (mtime_t)1000000 / (mtime_t)p_enc->fmt_out.audio.i_rate; VLC_UNUSED(p_enc); do { p_pcm_block = GetPCM( p_enc, p_block ); if( !p_pcm_block ) break; p_block = NULL; /* we don't need it anymore */ int16_t pcm_planar_buf[SHINE_MAX_SAMPLES * 2]; int16_t *pcm_planar_buf_chans[2] = { &pcm_planar_buf[0], &pcm_planar_buf[p_sys->samples_per_frame], }; aout_Deinterleave( pcm_planar_buf, p_pcm_block->p_buffer, p_sys->samples_per_frame, p_enc->fmt_in.audio.i_channels, p_enc->fmt_in.i_codec); long written; unsigned char *buf = shine_encode_buffer(p_sys->s, pcm_planar_buf_chans, &written); block_Release( p_pcm_block ); if (written <= 0) break; block_t *p_mp3_block = block_Alloc( written ); if( !p_mp3_block ) break; memcpy( p_mp3_block->p_buffer, buf, written ); /* date management */ p_mp3_block->i_length = p_sys->samples_per_frame * 1000000 / p_enc->fmt_out.audio.i_rate; start_date += p_mp3_block->i_length; p_mp3_block->i_dts = p_mp3_block->i_pts = start_date; p_mp3_block->i_nb_samples = p_sys->samples_per_frame; block_ChainAppend( &p_chain, p_mp3_block ); } while( p_pcm_block ); return p_chain; }
/**************************************************************************** * PacketizeAVC1: Takes VCL blocks of data and creates annexe B type NAL stream * Will always use 4 byte 0 0 0 1 startcodes * Will prepend a SPS and PPS before each keyframe ****************************************************************************/ static block_t *PacketizeAVC1( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; block_t *p_ret = NULL; uint8_t *p; if( !pp_block || !*pp_block ) return NULL; if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { block_Release( *pp_block ); return NULL; } p_block = *pp_block; *pp_block = NULL; for( p = p_block->p_buffer; p < &p_block->p_buffer[p_block->i_buffer]; ) { block_t *p_pic; bool b_dummy; int i_size = 0; int i; for( i = 0; i < p_sys->i_avcC_length_size; i++ ) { i_size = (i_size << 8) | (*p++); } if( i_size <= 0 || i_size > ( p_block->p_buffer + p_block->i_buffer - p ) ) { msg_Err( p_dec, "Broken frame : size %d is too big", i_size ); break; } block_t *p_part = CreateAnnexbNAL( p_dec, p, i_size ); if( !p_part ) break; p_part->i_dts = p_block->i_dts; p_part->i_pts = p_block->i_pts; /* Parse the NAL */ if( ( p_pic = ParseNALBlock( p_dec, &b_dummy, p_part ) ) ) { block_ChainAppend( &p_ret, p_pic ); } p += i_size; } block_Release( p_block ); return p_ret; }
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; }
static bool RemainAdd( stream_t *p_stream, const uint8_t *p_data, size_t i_size ) { stream_sys_t *p_sys = p_stream->p_sys; if ( i_size == 0 ) return true; block_t *p_block = block_Alloc( i_size ); if ( !p_block ) return false; memcpy( p_block->p_buffer, p_data, i_size ); p_block->i_buffer = i_size; block_ChainAppend( & p_sys->remain.p_list, p_block ); p_sys->remain.i_size += i_size; return true; }
static void* EncoderThread( vlc_object_t* p_this ) { sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_this; sout_stream_id_t *id = p_sys->id_video; picture_t *p_pic; int canc = vlc_savecancel (); while( vlc_object_alive (p_sys) && !p_sys->b_error ) { block_t *p_block; vlc_mutex_lock( &p_sys->lock_out ); while( p_sys->i_last_pic == p_sys->i_first_pic ) { vlc_cond_wait( &p_sys->cond, &p_sys->lock_out ); if( !vlc_object_alive (p_sys) || p_sys->b_error ) break; } if( !vlc_object_alive (p_sys) || p_sys->b_error ) { vlc_mutex_unlock( &p_sys->lock_out ); break; } p_pic = p_sys->pp_pics[p_sys->i_first_pic++]; p_sys->i_first_pic %= PICTURE_RING_SIZE; vlc_mutex_unlock( &p_sys->lock_out ); video_timer_start( id->p_encoder ); p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); video_timer_stop( id->p_encoder ); vlc_mutex_lock( &p_sys->lock_out ); block_ChainAppend( &p_sys->p_buffers, p_block ); vlc_mutex_unlock( &p_sys->lock_out ); picture_Release( p_pic ); } while( p_sys->i_last_pic != p_sys->i_first_pic ) { p_pic = p_sys->pp_pics[p_sys->i_first_pic++]; p_sys->i_first_pic %= PICTURE_RING_SIZE; picture_Release( p_pic ); } block_ChainRelease( p_sys->p_buffers ); vlc_restorecancel (canc); return NULL; }
static block_t *Encode( encoder_t *p_enc, aout_buffer_t *p_aout_buf ) { encoder_sys_t *p_sys = p_enc->p_sys; int16_t *p_buffer = (int16_t *)p_aout_buf->p_buffer; int i_nb_samples = p_aout_buf->i_nb_samples; block_t *p_chain = NULL; mtime_t i_computed_pts = p_aout_buf->start_date - (mtime_t)1000000 * (mtime_t)p_sys->i_nb_samples / (mtime_t)p_enc->fmt_in.audio.i_rate; if ( aout_DateGet( &p_sys->pts ) - i_computed_pts > 10000 || aout_DateGet( &p_sys->pts ) - i_computed_pts < -10000 ) { msg_Dbg( p_enc, "resetting audio date" ); aout_DateSet( &p_sys->pts, i_computed_pts ); } while ( p_sys->i_nb_samples + i_nb_samples >= MPEG_FRAME_SIZE ) { int i_used; block_t *p_block; Uninterleave( p_enc, p_buffer, MPEG_FRAME_SIZE - p_sys->i_nb_samples ); i_nb_samples -= MPEG_FRAME_SIZE - p_sys->i_nb_samples; p_buffer += (MPEG_FRAME_SIZE - p_sys->i_nb_samples) * 2; toolame_encode_buffer( p_sys->p_toolame, p_sys->p_left, p_sys->p_right, MPEG_FRAME_SIZE, p_sys->p_out_buffer, MAX_CODED_FRAME_SIZE, &i_used ); p_sys->i_nb_samples = 0; p_block = block_New( p_enc, i_used ); p_enc->p_vlc->pf_memcpy( p_block->p_buffer, p_sys->p_out_buffer, i_used ); p_block->i_length = (mtime_t)1000000 * (mtime_t)MPEG_FRAME_SIZE / (mtime_t)p_enc->fmt_in.audio.i_rate; p_block->i_dts = p_block->i_pts = aout_DateGet( &p_sys->pts ); aout_DateIncrement( &p_sys->pts, MPEG_FRAME_SIZE ); block_ChainAppend( &p_chain, p_block ); } if ( i_nb_samples ) { Uninterleave( p_enc, p_buffer, i_nb_samples ); p_sys->i_nb_samples += i_nb_samples; } return p_chain; }
static block_t *Encode( encoder_t *p_enc, block_t *p_aout_buf ) { encoder_sys_t *p_sys = p_enc->p_sys; /* FIXME:p_aout_buf is NULL when it's time to flush, does twolame has buffer to flush?*/ if( unlikely( !p_aout_buf ) ) return NULL; int16_t *p_buffer = (int16_t *)p_aout_buf->p_buffer; int i_nb_samples = p_aout_buf->i_nb_samples; block_t *p_chain = NULL; p_sys->i_pts = p_aout_buf->i_pts - (mtime_t)1000000 * (mtime_t)p_sys->i_nb_samples / (mtime_t)p_enc->fmt_out.audio.i_rate; while ( p_sys->i_nb_samples + i_nb_samples >= MPEG_FRAME_SIZE ) { int i_used; block_t *p_block; Bufferize( p_enc, p_buffer, MPEG_FRAME_SIZE - p_sys->i_nb_samples ); i_nb_samples -= MPEG_FRAME_SIZE - p_sys->i_nb_samples; p_buffer += (MPEG_FRAME_SIZE - p_sys->i_nb_samples) * 2; i_used = twolame_encode_buffer_interleaved( p_sys->p_twolame, p_sys->p_buffer, MPEG_FRAME_SIZE, p_sys->p_out_buffer, MAX_CODED_FRAME_SIZE ); p_sys->i_nb_samples = 0; p_block = block_Alloc( i_used ); memcpy( p_block->p_buffer, p_sys->p_out_buffer, i_used ); p_block->i_length = (mtime_t)1000000 * (mtime_t)MPEG_FRAME_SIZE / (mtime_t)p_enc->fmt_out.audio.i_rate; p_block->i_dts = p_block->i_pts = p_sys->i_pts; p_sys->i_pts += p_block->i_length; block_ChainAppend( &p_chain, p_block ); } if ( i_nb_samples ) { Bufferize( p_enc, p_buffer, i_nb_samples ); p_sys->i_nb_samples += i_nb_samples; } return p_chain; }
/***************************************************************************** * Send: Process an input packet *****************************************************************************/ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *p_buffer ) { sout_stream_sys_t *p_sys = p_stream->p_sys; if ( !id->id ) { block_Release( p_buffer ); return VLC_EGENERIC; } if ( !id->b_switcher_video && !id->b_switcher_audio ) { return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer ); } block_ChainAppend( &id->p_queued, p_buffer ); if ( id->b_switcher_video ) { /* Check for commands for every video frame. */ NetCommand( p_stream ); while ( id->p_queued != NULL ) { mtime_t i_dts = 0; int i; if ( p_sys->i_old_cmd != p_sys->i_cmd ) { i_dts = VideoCommand( p_stream, id ); } i_dts = Process( p_stream, id, i_dts ); for ( i = 0; i < MAX_AUDIO; i++ ) { if ( p_sys->pp_audio_ids[i] != NULL ) Process( p_stream, p_sys->pp_audio_ids[i], i_dts ); } } } return VLC_SUCCESS; }
static void* EncoderThread( void *obj ) { sout_stream_sys_t *p_sys = (sout_stream_sys_t*)obj; sout_stream_id_t *id = p_sys->id_video; picture_t *p_pic; int canc = vlc_savecancel (); for( ;; ) { block_t *p_block; vlc_mutex_lock( &p_sys->lock_out ); while( !p_sys->b_abort && p_sys->i_last_pic == p_sys->i_first_pic ) vlc_cond_wait( &p_sys->cond, &p_sys->lock_out ); if( p_sys->b_abort ) { vlc_mutex_unlock( &p_sys->lock_out ); break; } p_pic = p_sys->pp_pics[p_sys->i_first_pic++]; p_sys->i_first_pic %= PICTURE_RING_SIZE; vlc_mutex_unlock( &p_sys->lock_out ); p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); vlc_mutex_lock( &p_sys->lock_out ); block_ChainAppend( &p_sys->p_buffers, p_block ); vlc_mutex_unlock( &p_sys->lock_out ); picture_Release( p_pic ); } while( p_sys->i_last_pic != p_sys->i_first_pic ) { p_pic = p_sys->pp_pics[p_sys->i_first_pic++]; p_sys->i_first_pic %= PICTURE_RING_SIZE; picture_Release( p_pic ); } block_ChainRelease( p_sys->p_buffers ); vlc_restorecancel (canc); return NULL; }
static block_t *EncodeFrame( encoder_t *p_enc, aout_buffer_t *p_block ) { block_t *p_pcm_block; block_t *p_chain = NULL; unsigned int i_samples = p_block->i_buffer >> 2 /* s16l stereo */; mtime_t start_date = p_block->i_pts; start_date -= (mtime_t)i_samples * (mtime_t)1000000 / (mtime_t)p_enc->fmt_out.audio.i_rate; VLC_UNUSED(p_enc); do { p_pcm_block = GetPCM( p_enc, p_block ); if( !p_pcm_block ) break; p_block = NULL; /* we don't need it anymore */ uint32_t enc_buffer[16384]; /* storage for 65536 Bytes XXX: too much */ struct enc_chunk_hdr *chunk = (void*) enc_buffer; chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); encode_frame( (char*)p_pcm_block->p_buffer, chunk ); block_Release( p_pcm_block ); block_t *p_mp3_block = block_New( p_enc, chunk->enc_size ); if( !p_mp3_block ) break; vlc_memcpy( p_mp3_block->p_buffer, chunk->enc_data, chunk->enc_size ); /* date management */ p_mp3_block->i_length = SAMP_PER_FRAME1 * 1000000 / p_enc->fmt_out.audio.i_rate; start_date += p_mp3_block->i_length; p_mp3_block->i_dts = p_mp3_block->i_pts = start_date; p_mp3_block->i_nb_samples = SAMP_PER_FRAME1; block_ChainAppend( &p_chain, p_mp3_block ); } while( p_pcm_block ); return p_chain; }
int transcode_osd_process( sout_stream_t *p_stream, sout_stream_id_sys_t *id, block_t *in, block_t **out ) { sout_stream_sys_t *p_sys = p_stream->p_sys; subpicture_t *p_subpic = NULL; /* Check if we have a subpicture to send */ if( p_sys->p_spu && in->i_dts > VLC_TS_INVALID ) { video_format_t fmt; video_format_Init( &fmt, 0 ); video_format_Setup( &fmt, 0, 720, 576, 720, 576, 1, 1 ); p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt, &fmt, in->i_dts, in->i_dts, false ); } else { msg_Warn( p_stream, "spu channel not initialized, doing it now" ); if( !p_sys->p_spu ) p_sys->p_spu = spu_Create( p_stream ); } if( p_subpic ) { block_t *p_block = NULL; if( p_sys->b_master_sync && p_sys->i_master_drift ) { p_subpic->i_start -= p_sys->i_master_drift; if( p_subpic->i_stop ) p_subpic->i_stop -= p_sys->i_master_drift; } p_block = id->p_encoder->pf_encode_sub( id->p_encoder, p_subpic ); subpicture_Delete( p_subpic ); if( p_block ) { p_block->i_dts = p_block->i_pts = in->i_dts; block_ChainAppend( out, p_block ); return VLC_SUCCESS; } } return VLC_EGENERIC; }
/**************************************************************************** * PacketizeAVC1: Takes VCL blocks of data and creates annexe B type NAL stream * Will always use 4 byte 0 0 0 1 startcodes * Will prepend a SPS and PPS before each keyframe ****************************************************************************/ static block_t *PacketizeAVC1( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; block_t *p_ret = NULL; uint8_t *p; if( !pp_block || !*pp_block ) return NULL; p_block = *pp_block; *pp_block = NULL; for( p = p_block->p_buffer; p < &p_block->p_buffer[p_block->i_buffer]; ) { block_t *p_pic; int i_size = 0; int i; for( i = 0; i < p_sys->i_avcC_length_size; i++ ) { i_size = (i_size << 8) | (*p++); } if( i_size > 0 ) { block_t *p_part = nal_get_annexeb( p_dec, p, i_size ); p_part->i_dts = p_block->i_dts; p_part->i_pts = p_block->i_pts; /* Parse the NAL */ if( ( p_pic = ParseNALBlock( p_dec, p_part ) ) ) { block_ChainAppend( &p_ret, p_pic ); } } p += i_size; } block_Release( p_block ); return p_ret; }
static block_t *Encode( encoder_t *p_enc, aout_buffer_t *p_aout_buf ) { encoder_sys_t *p_sys = p_enc->p_sys; int16_t *p_buffer = (int16_t *)p_aout_buf->p_buffer; int i_nb_samples = p_aout_buf->i_nb_samples; block_t *p_chain = NULL; p_sys->i_pts = p_aout_buf->start_date - (mtime_t)1000000 * (mtime_t)p_sys->i_nb_samples / (mtime_t)p_enc->fmt_out.audio.i_rate; while ( p_sys->i_nb_samples + i_nb_samples >= MPEG_FRAME_SIZE ) { int i_used; block_t *p_block; Bufferize( p_enc, p_buffer, MPEG_FRAME_SIZE - p_sys->i_nb_samples ); i_nb_samples -= MPEG_FRAME_SIZE - p_sys->i_nb_samples; p_buffer += (MPEG_FRAME_SIZE - p_sys->i_nb_samples) * 2; i_used = twolame_encode_buffer_interleaved( p_sys->p_twolame, p_sys->p_buffer, MPEG_FRAME_SIZE, p_sys->p_out_buffer, MAX_CODED_FRAME_SIZE ); p_sys->i_nb_samples = 0; p_block = block_New( p_enc, i_used ); vlc_memcpy( p_block->p_buffer, p_sys->p_out_buffer, i_used ); p_block->i_length = (mtime_t)1000000 * (mtime_t)MPEG_FRAME_SIZE / (mtime_t)p_enc->fmt_out.audio.i_rate; p_block->i_dts = p_block->i_pts = p_sys->i_pts; p_sys->i_pts += p_block->i_length; block_ChainAppend( &p_chain, p_block ); } if ( i_nb_samples ) { Bufferize( p_enc, p_buffer, i_nb_samples ); p_sys->i_nb_samples += i_nb_samples; } return p_chain; }
int transcode_spu_process( sout_stream_t *p_stream, sout_stream_id_sys_t *id, block_t *in, block_t **out ) { sout_stream_sys_t *p_sys = p_stream->p_sys; subpicture_t *p_subpic; *out = NULL; p_subpic = id->p_decoder->pf_decode_sub( id->p_decoder, &in ); if( !p_subpic ) { /* We just don't have anything to handle now, go own*/ return VLC_SUCCESS; } if( p_sys->b_master_sync && p_sys->i_master_drift ) { p_subpic->i_start -= p_sys->i_master_drift; if( p_subpic->i_stop ) p_subpic->i_stop -= p_sys->i_master_drift; } if( p_sys->b_soverlay ) { spu_PutSubpicture( p_sys->p_spu, p_subpic ); return VLC_SUCCESS; } else { block_t *p_block; p_block = id->p_encoder->pf_encode_sub( id->p_encoder, p_subpic ); subpicture_Delete( p_subpic ); if( p_block ) { block_ChainAppend( out, p_block ); return VLC_SUCCESS; } } return VLC_EGENERIC; }
int transcode_spu_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; subpicture_t *p_subpic; *out = NULL; p_subpic = id->p_decoder->pf_decode_sub( id->p_decoder, &in ); if( !p_subpic ) return VLC_EGENERIC; sout_UpdateStatistic( p_stream->p_sout, SOUT_STATISTIC_DECODED_SUBTITLE, 1 ); if( p_sys->b_master_sync && p_sys->i_master_drift ) { p_subpic->i_start -= p_sys->i_master_drift; if( p_subpic->i_stop ) p_subpic->i_stop -= p_sys->i_master_drift; } if( p_sys->b_soverlay ) { spu_PutSubpicture( p_sys->p_spu, p_subpic ); } else { block_t *p_block; p_block = id->p_encoder->pf_encode_sub( id->p_encoder, p_subpic ); spu_del_buffer( id->p_decoder, p_subpic ); if( p_block ) { block_ChainAppend( out, p_block ); return VLC_SUCCESS; } } return VLC_EGENERIC; }
static void* EncoderThread( void *obj ) { sout_stream_sys_t *p_sys = (sout_stream_sys_t*)obj; sout_stream_id_t *id = p_sys->id_video; picture_t *p_pic; int canc = vlc_savecancel (); for( ;; ) { block_t *p_block; vlc_mutex_lock( &p_sys->lock_out ); while( !p_sys->b_abort && (p_pic = picture_fifo_Pop( p_sys->pp_pics )) == NULL ) vlc_cond_wait( &p_sys->cond, &p_sys->lock_out ); if( p_sys->b_abort ) { vlc_mutex_unlock( &p_sys->lock_out ); break; } vlc_mutex_unlock( &p_sys->lock_out ); p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); vlc_mutex_lock( &p_sys->lock_out ); block_ChainAppend( &p_sys->p_buffers, p_block ); vlc_mutex_unlock( &p_sys->lock_out ); picture_Release( p_pic ); } block_ChainRelease( p_sys->p_buffers ); vlc_restorecancel (canc); return NULL; }
static block_t *Encode(encoder_t *enc, block_t *buf) { encoder_sys_t *sys = enc->p_sys; if (!buf) return NULL; mtime_t i_pts = buf->i_pts - (mtime_t) CLOCK_FREQ * (mtime_t) sys->i_samples_delay / (mtime_t) enc->fmt_in.audio.i_rate; sys->i_samples_delay += buf->i_nb_samples; block_t *result = NULL; unsigned src_start = 0; unsigned padding_start = 0; /* The maximum Opus frame size is 1275 bytes + TOC sequence length. */ const unsigned OPUS_MAX_ENCODED_BYTES = ((1275 + 3) * sys->nb_streams) - 2; while (sys->i_nb_samples + buf->i_nb_samples >= OPUS_FRAME_SIZE) { block_t *out_block = block_Alloc(OPUS_MAX_ENCODED_BYTES); /* add padding to beginning */ if (sys->padding) { const size_t leftover_space = OPUS_FRAME_SIZE - sys->i_nb_samples; padding_start = fill_buffer(enc, padding_start, sys->padding, __MIN(sys->padding->i_nb_samples, leftover_space)); if (sys->padding->i_nb_samples <= 0) { block_Release(sys->padding); sys->padding = NULL; } } /* padding may have been freed either before or inside previous * if-statement */ if (!sys->padding) { const size_t leftover_space = OPUS_FRAME_SIZE - sys->i_nb_samples; src_start = fill_buffer(enc, src_start, buf, __MIN(buf->i_nb_samples, leftover_space)); } opus_int32 bytes_encoded = opus_multistream_encode_float(sys->enc, sys->buffer, OPUS_FRAME_SIZE, out_block->p_buffer, out_block->i_buffer); if (bytes_encoded < 0) { block_Release(out_block); } else { out_block->i_length = (mtime_t) CLOCK_FREQ * (mtime_t) OPUS_FRAME_SIZE / (mtime_t) enc->fmt_in.audio.i_rate; out_block->i_dts = out_block->i_pts = i_pts; sys->i_samples_delay -= OPUS_FRAME_SIZE; i_pts += out_block->i_length; sys->i_nb_samples = 0; out_block->i_buffer = bytes_encoded; block_ChainAppend(&result, out_block); } } /* put leftover samples at beginning of buffer */ if (buf->i_nb_samples > 0) fill_buffer(enc, src_start, buf, buf->i_nb_samples); return result; }
/**************************************************************************** * Encode: the whole thing **************************************************************************** * This function spits out encapsulation units. ****************************************************************************/ static block_t *Encode( encoder_t *p_enc, picture_t *p_pic ) { encoder_sys_t *p_sys = p_enc->p_sys; block_t *p_block, *p_output_chain = NULL; int i_plane, i_line, i_width, i_src_stride; uint8_t *p_dst; if( !p_pic ) return NULL; /* we only know if the sequence is interlaced when the first * picture arrives, so final setup is done here */ /* XXX todo, detect change of interlace */ p_sys->ctx.src_params.topfieldfirst = p_pic->b_top_field_first; p_sys->ctx.src_params.source_sampling = !p_pic->b_progressive; if( p_sys->b_auto_field_coding ) p_sys->ctx.enc_params.picture_coding_mode = !p_pic->b_progressive; if( !p_sys->p_dirac ) { date_t date; /* Initialise the encoder with the encoder context */ p_sys->p_dirac = dirac_encoder_init( &p_sys->ctx, 0 ); if( !p_sys->p_dirac ) { msg_Err( p_enc, "Failed to initialize dirac encoder" ); return NULL; } date_Init( &date, p_enc->fmt_in.video.i_frame_rate, p_enc->fmt_in.video.i_frame_rate_base ); #if DIRAC_RESEARCH_VERSION_ATLEAST(1,0,2) int i_delayinpics = dirac_encoder_pts_offset( p_sys->p_dirac ); i_delayinpics /= p_sys->ctx.enc_params.picture_coding_mode + 1; date_Increment( &date, i_delayinpics ); #else date_Increment( &date, 1 ); #endif p_sys->i_pts_offset = date_Get( &date ); /* picture_coding_mode = 1 == FIELD_CODING, two pictures are produced * for each frame input. Calculate time between fields for offsetting * the second field later. */ if( 1 == p_sys->ctx.enc_params.picture_coding_mode ) { date_Set( &date, 0 ); date_Increment( &date, 1 ); p_sys->i_field_time = date_Get( &date ) / 2; } } /* Copy input picture into encoder input buffer (stride by stride) */ /* Would be lovely to just pass the picture in, but there is noway for the * library to free it */ p_dst = p_sys->p_buffer_in; for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) { uint8_t *p_src = p_pic->p[i_plane].p_pixels; i_width = p_pic->p[i_plane].i_visible_pitch; i_src_stride = p_pic->p[i_plane].i_pitch; for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines; i_line++ ) { vlc_memcpy( p_dst, p_src, i_width ); p_dst += i_width; p_src += i_src_stride; } } /* Load one frame of data into encoder */ if( dirac_encoder_load( p_sys->p_dirac, p_sys->p_buffer_in, p_sys->i_buffer_in ) < 0 ) { msg_Dbg( p_enc, "dirac_encoder_load() error" ); return NULL; } /* store pts in a lookaside buffer, so that the same pts may * be used for the picture in coded order */ StorePicturePTS( p_enc, p_sys->i_input_picnum, p_pic->date ); p_sys->i_input_picnum++; /* store dts in a queue, so that they appear in order in * coded order */ p_block = block_New( p_enc, 1 ); if( !p_block ) return NULL; p_block->i_dts = p_pic->date - p_sys->i_pts_offset; block_FifoPut( p_sys->p_dts_fifo, p_block ); p_block = NULL; /* for field coding mode, insert an extra value into both the * pts lookaside buffer and dts queue, offset to correspond * to a one field delay. */ if( 1 == p_sys->ctx.enc_params.picture_coding_mode ) { StorePicturePTS( p_enc, p_sys->i_input_picnum, p_pic->date + p_sys->i_field_time ); p_sys->i_input_picnum++; p_block = block_New( p_enc, 1 ); if( !p_block ) return NULL; p_block->i_dts = p_pic->date - p_sys->i_pts_offset + p_sys->i_field_time; block_FifoPut( p_sys->p_dts_fifo, p_block ); p_block = NULL; } dirac_encoder_state_t state; /* Retrieve encoded frames from encoder */ do { p_sys->p_dirac->enc_buf.buffer = p_sys->p_buffer_out; p_sys->p_dirac->enc_buf.size = p_sys->i_buffer_out; state = dirac_encoder_output( p_sys->p_dirac ); switch( state ) { case ENC_STATE_AVAIL: { uint32_t pic_num; /* extract data from encoder temporary buffer. */ p_block = block_New( p_enc, p_sys->p_dirac->enc_buf.size ); if( !p_block ) return NULL; memcpy( p_block->p_buffer, p_sys->p_dirac->enc_buf.buffer, p_sys->p_dirac->enc_buf.size ); /* if some flags were set for a previous block, prevent * them from getting lost */ if( p_sys->p_chain ) p_block->i_flags |= p_sys->p_chain->i_flags; /* store all extracted blocks in a chain and gather up when an * entire encapsulation unit is avaliable (ends with a picture) */ block_ChainAppend( &p_sys->p_chain, p_block ); /* Presence of a Sequence header indicates a seek point */ if( 0 == p_block->p_buffer[4] ) { p_block->i_flags |= BLOCK_FLAG_TYPE_I; if( !p_enc->fmt_out.p_extra ) { const uint8_t eos[] = { 'B','B','C','D',0x10,0,0,0,13,0,0,0,0 }; uint32_t len = GetDWBE( p_block->p_buffer + 5 ); /* if it hasn't been done so far, stash a copy of the * sequence header for muxers such as ogg */ /* The OggDirac spec advises that a Dirac EOS DataUnit * is appended to the sequence header to allow guard * against poor streaming servers */ /* XXX, should this be done using the packetizer ? */ p_enc->fmt_out.p_extra = malloc( len + sizeof(eos) ); if( !p_enc->fmt_out.p_extra ) return NULL; memcpy( p_enc->fmt_out.p_extra, p_block->p_buffer, len); memcpy( (uint8_t*)p_enc->fmt_out.p_extra + len, eos, sizeof(eos) ); SetDWBE( (uint8_t*)p_enc->fmt_out.p_extra + len + 10, len ); p_enc->fmt_out.i_extra = len + sizeof(eos); } } if( ReadDiracPictureNumber( &pic_num, p_block ) ) { /* Finding a picture terminates an ecapsulation unit, gather * all data and output; use the next dts value queued up * and find correct pts in the tlb */ p_block = block_FifoGet( p_sys->p_dts_fifo ); p_sys->p_chain->i_dts = p_block->i_dts; p_sys->p_chain->i_pts = GetPicturePTS( p_enc, pic_num ); block_Release( p_block ); block_ChainAppend( &p_output_chain, block_ChainGather( p_sys->p_chain ) ); p_sys->p_chain = NULL; } else { p_block = NULL; } break; } case ENC_STATE_BUFFER: break; case ENC_STATE_INVALID: default: break; } } while( state == ENC_STATE_AVAIL ); return p_output_chain; }
static enum raw1394_iso_disposition Raw1394Handler(raw1394handle_t handle, unsigned char *data, unsigned int length, unsigned char channel, unsigned char tag, unsigned char sy, unsigned int cycle, unsigned int dropped) { access_t *p_access = NULL; access_sys_t *p_sys = NULL; block_t *p_block = NULL; VLC_UNUSED(channel); VLC_UNUSED(tag); VLC_UNUSED(sy); VLC_UNUSED(cycle); VLC_UNUSED(dropped); p_access = (access_t *) raw1394_get_userdata( handle ); if( !p_access ) return 0; p_sys = p_access->p_sys; /* skip empty packets */ if( length > 16 ) { unsigned char * p = data + 8; int section_type = p[ 0 ] >> 5; /* section type is in bits 5 - 7 */ int dif_sequence = p[ 1 ] >> 4; /* dif sequence number is in bits 4 - 7 */ int dif_block = p[ 2 ]; vlc_mutex_lock( &p_sys->p_ev->lock ); /* if we are at the beginning of a frame, we put the previous frame in our output_queue. */ if( (section_type == 0) && (dif_sequence == 0) ) { vlc_mutex_lock( &p_sys->lock ); if( p_sys->p_ev->p_frame ) { /* Push current frame to p_access thread. */ //p_sys->p_ev->p_frame->i_pts = mdate(); block_ChainAppend( &p_sys->p_frame, p_sys->p_ev->p_frame ); } /* reset list */ p_sys->p_ev->p_frame = block_Alloc( 144000 ); p_sys->p_ev->pp_last = &p_sys->p_frame; vlc_mutex_unlock( &p_sys->lock ); } p_block = p_sys->p_ev->p_frame; if( p_block ) { switch ( section_type ) { case 0: /* 1 Header block */ /* p[3] |= 0x80; // hack to force PAL data */ memcpy( p_block->p_buffer + dif_sequence * 150 * 80, p, 480 ); break; case 1: /* 2 Subcode blocks */ memcpy( p_block->p_buffer + dif_sequence * 150 * 80 + ( 1 + dif_block ) * 80, p, 480 ); break; case 2: /* 3 VAUX blocks */ memcpy( p_block->p_buffer + dif_sequence * 150 * 80 + ( 3 + dif_block ) * 80, p, 480 ); break; case 3: /* 9 Audio blocks interleaved with video */ memcpy( p_block->p_buffer + dif_sequence * 150 * 80 + ( 6 + dif_block * 16 ) * 80, p, 480 ); break; case 4: /* 135 Video blocks interleaved with audio */ memcpy( p_block->p_buffer + dif_sequence * 150 * 80 + ( 7 + ( dif_block / 15 ) + dif_block ) * 80, p, 480 ); break; default: /* we can´t handle any other data */ block_Release( p_block ); p_block = NULL; break; } } vlc_mutex_unlock( &p_sys->p_ev->lock ); }
static block_t *ParseVCL(decoder_t *p_dec, uint8_t i_nal_type, block_t *p_frag) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_frame = NULL; const uint8_t *p_buffer = p_frag->p_buffer; size_t i_buffer = p_frag->i_buffer; if(unlikely(!hxxx_strip_AnnexB_startcode(&p_buffer, &i_buffer) || i_buffer < 3)) { block_ChainAppend(&p_sys->p_frame, p_frag); /* might corrupt */ return NULL; } bool b_first_slice_in_pic = p_buffer[2] & 0x80; if (b_first_slice_in_pic) { if(p_sys->p_frame) { /* Starting new frame, gather and return previous frame data */ p_frame = block_ChainGather(p_sys->p_frame); p_sys->p_frame = NULL; p_sys->pp_frame_last = &p_sys->p_frame; } switch(i_nal_type) { case HEVC_NAL_BLA_W_LP: case HEVC_NAL_BLA_W_RADL: case HEVC_NAL_BLA_N_LP: case HEVC_NAL_IDR_W_RADL: case HEVC_NAL_IDR_N_LP: case HEVC_NAL_CRA: p_frag->i_flags |= BLOCK_FLAG_TYPE_I; break; default: { hevc_slice_segment_header_t *p_sli = hevc_decode_slice_header( p_buffer, i_buffer, true, p_sys->rgi_p_decsps, p_sys->rgi_p_decpps ); if( p_sli ) { enum hevc_slice_type_e type; if( hevc_get_slice_type( p_sli, &type ) ) { if( type == HEVC_SLICE_TYPE_P ) p_frag->i_flags |= BLOCK_FLAG_TYPE_P; else p_frag->i_flags |= BLOCK_FLAG_TYPE_B; } hevc_rbsp_release_slice_header( p_sli ); } else p_frag->i_flags |= BLOCK_FLAG_TYPE_B; } break; } } block_ChainLastAppend(&p_sys->pp_frame_last, p_frag); return p_frame; }
/***************************************************************************** * Process: Process and dispatch buffers *****************************************************************************/ static mtime_t Process( sout_stream_t *p_stream, sout_stream_id_t *id, mtime_t i_max_dts ) { sout_stream_sys_t *p_sys = p_stream->p_sys; mtime_t i_dts = 0; block_t *p_blocks = NULL; block_t *p_blocks_out = NULL; /* Find out the blocks we need. */ while ( id->p_queued != NULL && (!i_max_dts || id->p_queued->i_dts <= i_max_dts) ) { block_t *p_next = id->p_queued->p_next; id->p_queued->p_next = NULL; i_dts = id->p_queued->i_dts; block_ChainAppend( &p_blocks, id->p_queued ); id->p_queued = p_next; } if ( p_sys->i_old_cmd == 0 ) { /* Full forward */ if ( p_blocks != NULL ) p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks ); return i_dts; } if ( p_sys->i_old_cmd == -1 ) { /* No output at all */ while ( p_blocks != NULL ) { block_t * p_next = p_blocks->p_next; block_Release( p_blocks ); p_blocks = p_next; } return i_dts; } while ( p_blocks != NULL ) { block_t * p_next = p_blocks->p_next; block_t * p_out; if ( id->b_switcher_video ) { p_out = VideoGetBuffer( p_stream, id, p_blocks ); } else { p_out = AudioGetBuffer( p_stream, id, p_blocks ); } p_blocks = p_next; if ( p_out != NULL ) { block_ChainAppend( &p_blocks_out, p_out ); } } if ( p_blocks_out != NULL ) p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks_out ); return i_dts; }
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; if( unlikely( in == NULL ) ) { block_t *p_block; do { p_block = id->p_encoder->pf_encode_audio(id->p_encoder, NULL ); block_ChainAppend( out, p_block ); } while( p_block ); return VLC_SUCCESS; } while( (p_audio_buf = id->p_decoder->pf_decode_audio( id->p_decoder, &in )) ) { if( p_sys->b_master_sync ) { mtime_t i_pts = date_Get( &id->interpolated_pts ) + 1; mtime_t i_drift = 0; if( likely( p_audio_buf->i_pts != VLC_TS_INVALID ) ) i_drift = p_audio_buf->i_pts - i_pts; if ( unlikely(i_drift > MASTER_SYNC_MAX_DRIFT || i_drift < -MASTER_SYNC_MAX_DRIFT) ) { msg_Dbg( p_stream, "audio drift is too high (%"PRId64"), resetting master sync", i_drift ); date_Set( &id->interpolated_pts, p_audio_buf->i_pts ); i_pts = p_audio_buf->i_pts + 1; } if( likely(p_audio_buf->i_pts != VLC_TS_INVALID ) ) p_sys->i_master_drift = p_audio_buf->i_pts - i_pts; date_Increment( &id->interpolated_pts, p_audio_buf->i_nb_samples ); p_audio_buf->i_pts = i_pts; } p_audio_buf->i_dts = p_audio_buf->i_pts; /* Check if audio format has changed, and filters need reinit */ if( unlikely( ( id->p_decoder->fmt_out.audio.i_rate != p_sys->fmt_audio.i_rate ) || ( id->p_decoder->fmt_out.audio.i_physical_channels != p_sys->fmt_audio.i_physical_channels ) ) ) { msg_Info( p_stream, "Audio changed, trying to reinitialize filters" ); if( id->p_af_chain != NULL ) aout_FiltersDelete( (vlc_object_t *)NULL, id->p_af_chain ); /* decoders don't set audio.i_format, but audio filters use it */ id->p_decoder->fmt_out.audio.i_format = id->p_decoder->fmt_out.i_codec; aout_FormatPrepare( &id->p_decoder->fmt_out.audio ); if( transcode_audio_initialize_filters( p_stream, id, p_sys, &id->p_decoder->fmt_out.audio ) != VLC_SUCCESS ) return VLC_EGENERIC; } /* Run filter chain */ p_audio_buf = aout_FiltersPlay( id->p_af_chain, p_audio_buf, INPUT_RATE_DEFAULT ); if( !p_audio_buf ) abort(); p_audio_buf->i_dts = p_audio_buf->i_pts; p_block = id->p_encoder->pf_encode_audio( id->p_encoder, p_audio_buf ); block_ChainAppend( out, p_block ); block_Release( p_audio_buf ); } return VLC_SUCCESS; }
static block_t * Resample( filter_t *p_filter, block_t *p_in ) { filter_sys_t *p_sys = p_filter->p_sys; const vlc_tick_t i_pts = p_in->i_pts; if( p_sys->vr_soxr ) { /* "audio resampler" with variable ratio: use the fixed resampler when * the ratio is the same than the fixed one, otherwise use the variable * resampler. */ soxr_t soxr; block_t *p_flushed_out = NULL, *p_out = NULL; const double f_ratio = p_filter->fmt_out.audio.i_rate / (double) p_filter->fmt_in.audio.i_rate; const size_t i_olen = SoXR_GetOutLen( p_in->i_nb_samples, f_ratio ); if( f_ratio != p_sys->f_fixed_ratio ) { /* using variable resampler */ soxr_set_io_ratio( p_sys->vr_soxr, 1 / f_ratio, i_olen ); soxr = p_sys->vr_soxr; } else if( f_ratio == 1.0f ) { /* not using any resampler */ soxr = NULL; p_out = p_in; } else { /* using fixed resampler */ soxr = p_sys->soxr; } /* If the new soxr is different than the last one, flush it */ if( p_sys->last_soxr && soxr != p_sys->last_soxr && p_sys->i_last_olen ) { p_flushed_out = SoXR_Resample( p_filter, p_sys->last_soxr, NULL, p_sys->i_last_olen ); if( soxr ) msg_Dbg( p_filter, "Using '%s' engine", soxr_engine( soxr ) ); } if( soxr ) { assert( !p_out ); p_out = SoXR_Resample( p_filter, soxr, p_in, i_olen ); if( !p_out ) goto error; } if( p_flushed_out ) { /* Prepend the flushed output data to p_out */ const unsigned i_nb_samples = p_flushed_out->i_nb_samples + p_out->i_nb_samples; block_ChainAppend( &p_flushed_out, p_out ); p_out = block_ChainGather( p_flushed_out ); if( !p_out ) goto error; p_out->i_nb_samples = i_nb_samples; } p_out->i_pts = i_pts; return p_out; } else { /* "audio converter" with fixed ratio */ const size_t i_olen = SoXR_GetOutLen( p_in->i_nb_samples, p_sys->f_fixed_ratio ); block_t *p_out = SoXR_Resample( p_filter, p_sys->soxr, p_in, i_olen ); if( p_out ) p_out->i_pts = i_pts; return p_out; } error: block_Release( p_in ); return NULL; }
int transcode_video_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; bool b_need_duplicate = false; picture_t *p_pic, *p_pic2 = NULL; *out = NULL; if( in == NULL ) { if( p_sys->i_threads == 0 ) { block_t *p_block; do { video_timer_start( id->p_encoder ); p_block = id->p_encoder->pf_encode_video(id->p_encoder, NULL ); video_timer_stop( id->p_encoder ); block_ChainAppend( out, p_block ); } while( p_block ); } else { /* * FIXME: we need EncoderThread() to flush buffers and signal us * when it's done so we can send the last frames to the chain */ } return VLC_SUCCESS; } while( (p_pic = id->p_decoder->pf_decode_video( id->p_decoder, &in )) ) { if( p_stream->p_sout->i_out_pace_nocontrol && p_sys->b_hurry_up ) { mtime_t current_date = mdate(); if( current_date + 50000 > p_pic->date ) { msg_Dbg( p_stream, "late picture skipped (%"PRId64")", current_date + 50000 - p_pic->date ); picture_Release( p_pic ); continue; } } if( p_sys->b_master_sync ) { mtime_t i_video_drift; mtime_t i_master_drift = p_sys->i_master_drift; mtime_t i_pts; i_pts = date_Get( &id->interpolated_pts ) + 1; if ( p_pic->date - i_pts > MASTER_SYNC_MAX_DRIFT || p_pic->date - i_pts < -MASTER_SYNC_MAX_DRIFT ) { msg_Dbg( p_stream, "drift is too high, resetting master sync" ); date_Set( &id->interpolated_pts, p_pic->date ); i_pts = p_pic->date + 1; } i_video_drift = p_pic->date - i_pts; b_need_duplicate = false; /* Set the pts of the frame being encoded */ p_pic->date = i_pts; if( i_video_drift < (i_master_drift - 50000) ) { #if 0 msg_Dbg( p_stream, "dropping frame (%i)", (int)(i_video_drift - i_master_drift) ); #endif picture_Release( p_pic ); continue; } else if( i_video_drift > (i_master_drift + 50000) ) { #if 0 msg_Dbg( p_stream, "adding frame (%i)", (int)(i_video_drift - i_master_drift) ); #endif b_need_duplicate = true; } } if( unlikely( !id->p_encoder->p_module ) ) { transcode_video_encoder_init( p_stream, id ); transcode_video_filter_init( p_stream, id ); if( transcode_video_encoder_open( p_stream, id ) != VLC_SUCCESS ) { picture_Release( p_pic ); transcode_video_close( p_stream, id ); id->b_transcode = false; return VLC_EGENERIC; } } /* Run filter chain */ if( id->p_f_chain ) p_pic = filter_chain_VideoFilter( id->p_f_chain, p_pic ); /* * Encoding */ /* Check if we have a subpicture to overlay */ if( p_sys->p_spu ) { video_format_t fmt; if( filter_chain_GetLength( id->p_f_chain ) > 0 ) fmt = filter_chain_GetFmtOut( id->p_f_chain )->video; else fmt = id->p_decoder->fmt_out.video; subpicture_t *p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt, &fmt, p_pic->date, p_pic->date, false ); /* Overlay subpicture */ if( p_subpic ) { if( picture_IsReferenced( p_pic ) && !filter_chain_GetLength( id->p_f_chain ) ) { /* We can't modify the picture, we need to duplicate it */ picture_t *p_tmp = video_new_buffer_decoder( id->p_decoder ); if( p_tmp ) { picture_Copy( p_tmp, p_pic ); picture_Release( p_pic ); p_pic = p_tmp; } } if( !p_sys->p_spu_blend ) p_sys->p_spu_blend = filter_NewBlend( VLC_OBJECT( p_sys->p_spu ), &fmt ); if( p_sys->p_spu_blend ) picture_BlendSubpicture( p_pic, p_sys->p_spu_blend, p_subpic ); subpicture_Delete( p_subpic ); } } /* Run user specified filter chain */ if( id->p_uf_chain ) p_pic = filter_chain_VideoFilter( id->p_uf_chain, p_pic ); if( p_sys->i_threads == 0 ) { block_t *p_block; video_timer_start( id->p_encoder ); p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); video_timer_stop( id->p_encoder ); block_ChainAppend( out, p_block ); } if( p_sys->b_master_sync ) { mtime_t i_pts = date_Get( &id->interpolated_pts ) + 1; if ( p_pic->date - i_pts > MASTER_SYNC_MAX_DRIFT || p_pic->date - i_pts < -MASTER_SYNC_MAX_DRIFT ) { msg_Dbg( p_stream, "drift is too high, resetting master sync" ); date_Set( &id->interpolated_pts, p_pic->date ); i_pts = p_pic->date + 1; } date_Increment( &id->interpolated_pts, 1 ); if( unlikely( b_need_duplicate ) ) { if( p_sys->i_threads >= 1 ) { /* We can't modify the picture, we need to duplicate it */ p_pic2 = video_new_buffer_decoder( id->p_decoder ); if( p_pic2 != NULL ) { picture_Copy( p_pic2, p_pic ); p_pic2->date = i_pts; } } else { block_t *p_block; p_pic->date = i_pts; video_timer_start( id->p_encoder ); p_block = id->p_encoder->pf_encode_video(id->p_encoder, p_pic); video_timer_stop( id->p_encoder ); block_ChainAppend( out, p_block ); } } } if( p_sys->i_threads == 0 ) { picture_Release( p_pic ); } else { vlc_mutex_lock( &p_sys->lock_out ); p_sys->pp_pics[p_sys->i_last_pic++] = p_pic; p_sys->i_last_pic %= PICTURE_RING_SIZE; *out = p_sys->p_buffers; p_sys->p_buffers = NULL; if( p_pic2 != NULL ) { p_sys->pp_pics[p_sys->i_last_pic++] = p_pic2; p_sys->i_last_pic %= PICTURE_RING_SIZE; } vlc_cond_signal( &p_sys->cond ); vlc_mutex_unlock( &p_sys->lock_out ); } } return VLC_SUCCESS; }
/**************************************************************************** * Encode: the whole thing **************************************************************************** * This function spits out ogg packets. ****************************************************************************/ static block_t *Encode( encoder_t *p_enc, block_t *p_aout_buf ) { encoder_sys_t *p_sys = p_enc->p_sys; ogg_packet oggpacket; block_t *p_block, *p_chain = NULL; float **buffer; /* FIXME: flush buffers in here */ if( unlikely( !p_aout_buf ) ) return NULL; mtime_t i_pts = p_aout_buf->i_pts - (mtime_t)1000000 * (mtime_t)p_sys->i_samples_delay / (mtime_t)p_enc->fmt_in.audio.i_rate; p_sys->i_samples_delay += p_aout_buf->i_nb_samples; buffer = vorbis_analysis_buffer( &p_sys->vd, p_aout_buf->i_nb_samples ); /* convert samples to float and uninterleave */ for( unsigned int i = 0; i < p_sys->i_channels; i++ ) { for( unsigned int j = 0 ; j < p_aout_buf->i_nb_samples ; j++ ) { buffer[i][j]= ((float *)p_aout_buf->p_buffer) [j * p_sys->i_channels + p_sys->pi_chan_table[i]]; } } vorbis_analysis_wrote( &p_sys->vd, p_aout_buf->i_nb_samples ); while( vorbis_analysis_blockout( &p_sys->vd, &p_sys->vb ) == 1 ) { int i_samples; vorbis_analysis( &p_sys->vb, NULL ); vorbis_bitrate_addblock( &p_sys->vb ); while( vorbis_bitrate_flushpacket( &p_sys->vd, &oggpacket ) ) { int i_block_size; p_block = block_Alloc( oggpacket.bytes ); memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes ); i_block_size = vorbis_packet_blocksize( &p_sys->vi, &oggpacket ); if( i_block_size < 0 ) i_block_size = 0; i_samples = ( p_sys->i_last_block_size + i_block_size ) >> 2; p_sys->i_last_block_size = i_block_size; p_block->i_length = (mtime_t)1000000 * (mtime_t)i_samples / (mtime_t)p_enc->fmt_in.audio.i_rate; p_block->i_dts = p_block->i_pts = i_pts; p_sys->i_samples_delay -= i_samples; /* Update pts */ i_pts += p_block->i_length; block_ChainAppend( &p_chain, p_block ); } } return p_chain; }
/**************************************************************************** * EncodeAudio: the whole thing ****************************************************************************/ static block_t *EncodeAudio( encoder_t *p_enc, aout_buffer_t *p_aout_buf ) { encoder_sys_t *p_sys = p_enc->p_sys; block_t *p_block, *p_chain = NULL; char *p_buffer = p_aout_buf->p_buffer; int i_samples = p_aout_buf->i_nb_samples; int i_samples_delay = p_sys->i_samples_delay; p_sys->i_pts = p_aout_buf->start_date - (mtime_t)1000000 * (mtime_t)p_sys->i_samples_delay / (mtime_t)p_enc->fmt_in.audio.i_rate; p_sys->i_samples_delay += i_samples; while( p_sys->i_samples_delay >= p_sys->p_context->frame_size ) { int16_t *p_samples; int i_out; if( i_samples_delay ) { /* Take care of the left-over from last time */ int i_delay_size = i_samples_delay * 2 * p_sys->p_context->channels; int i_size = p_sys->i_frame_size - i_delay_size; p_samples = (int16_t *)p_sys->p_buffer; memcpy( p_sys->p_buffer + i_delay_size, p_buffer, i_size ); p_buffer -= i_delay_size; i_samples += i_samples_delay; i_samples_delay = 0; } else { p_samples = (int16_t *)p_buffer; } i_out = avcodec_encode_audio( p_sys->p_context, p_sys->p_buffer_out, 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE, p_samples ); #if 0 msg_Warn( p_enc, "avcodec_encode_audio: %d", i_out ); #endif if( i_out < 0 ) break; p_buffer += p_sys->i_frame_size; p_sys->i_samples_delay -= p_sys->p_context->frame_size; i_samples -= p_sys->p_context->frame_size; if( i_out == 0 ) continue; p_block = block_New( p_enc, i_out ); memcpy( p_block->p_buffer, p_sys->p_buffer_out, i_out ); p_block->i_length = (mtime_t)1000000 * (mtime_t)p_sys->p_context->frame_size / (mtime_t)p_sys->p_context->sample_rate; p_block->i_dts = p_block->i_pts = p_sys->i_pts; /* Update pts */ p_sys->i_pts += p_block->i_length; block_ChainAppend( &p_chain, p_block ); } /* Backup the remaining raw samples */ if( i_samples ) { memcpy( p_sys->p_buffer + i_samples_delay * 2 * p_sys->p_context->channels, p_buffer, i_samples * 2 * p_sys->p_context->channels ); } return p_chain; }
static block_t *Encode( encoder_t *p_enc, block_t *p_aout_buf ) { encoder_sys_t *p_sys = p_enc->p_sys; block_t *p_chain = NULL; if( unlikely( !p_aout_buf ) ) { int i_used = 0; block_t *p_block; i_used = twolame_encode_flush( p_sys->p_twolame, p_sys->p_out_buffer, MAX_CODED_FRAME_SIZE ); if( i_used <= 0 ) return NULL; p_block = block_Alloc( i_used ); if( !p_block ) return NULL; memcpy( p_block->p_buffer, p_sys->p_out_buffer, i_used ); p_block->i_length = vlc_tick_from_samples( MPEG_FRAME_SIZE, p_enc->fmt_out.audio.i_rate ); p_block->i_dts = p_block->i_pts = p_sys->i_pts; p_sys->i_pts += p_block->i_length; return p_block; } int16_t *p_buffer = (int16_t *)p_aout_buf->p_buffer; int i_nb_samples = p_aout_buf->i_nb_samples; p_sys->i_pts = p_aout_buf->i_pts - vlc_tick_from_samples( p_sys->i_nb_samples, p_enc->fmt_out.audio.i_rate ); while ( p_sys->i_nb_samples + i_nb_samples >= MPEG_FRAME_SIZE ) { int i_used; block_t *p_block; Bufferize( p_enc, p_buffer, MPEG_FRAME_SIZE - p_sys->i_nb_samples ); i_nb_samples -= MPEG_FRAME_SIZE - p_sys->i_nb_samples; p_buffer += (MPEG_FRAME_SIZE - p_sys->i_nb_samples) * 2; i_used = twolame_encode_buffer_interleaved( p_sys->p_twolame, p_sys->p_buffer, MPEG_FRAME_SIZE, p_sys->p_out_buffer, MAX_CODED_FRAME_SIZE ); /* On error, buffer samples and return what was already encoded */ if( i_used < 0 ) { msg_Err( p_enc, "encoder error: %d", i_used ); break; } p_sys->i_nb_samples = 0; p_block = block_Alloc( i_used ); if( !p_block ) { if( p_chain ) block_ChainRelease( p_chain ); return NULL; } memcpy( p_block->p_buffer, p_sys->p_out_buffer, i_used ); p_block->i_length = vlc_tick_from_samples( MPEG_FRAME_SIZE, p_enc->fmt_out.audio.i_rate ); p_block->i_dts = p_block->i_pts = p_sys->i_pts; p_sys->i_pts += p_block->i_length; block_ChainAppend( &p_chain, p_block ); } if ( i_nb_samples ) { Bufferize( p_enc, p_buffer, i_nb_samples ); p_sys->i_nb_samples += i_nb_samples; } return p_chain; }