/***************************************************************************** * sout_MuxSendBuffer: *****************************************************************************/ int sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input, block_t *p_buffer ) { mtime_t i_dts = p_buffer->i_dts; block_FifoPut( p_input->p_fifo, p_buffer ); if( p_mux->p_sout->i_out_pace_nocontrol ) { mtime_t current_date = mdate(); if ( current_date > i_dts ) msg_Warn( p_mux, "late buffer for mux input (%"PRId64")", current_date - i_dts ); } if( p_mux->b_waiting_stream ) { const int64_t i_caching = var_GetInteger( p_mux->p_sout, "sout-mux-caching" ) * INT64_C(1000); if( p_mux->i_add_stream_start < 0 ) p_mux->i_add_stream_start = i_dts; /* Wait until we have enough data before muxing */ if( p_mux->i_add_stream_start < 0 || i_dts < p_mux->i_add_stream_start + i_caching ) return VLC_SUCCESS; p_mux->b_waiting_stream = false; } return p_mux->pf_mux( p_mux ); }
/** * Do the actual work with the new sample. * @param p_filter: filter object * @param p_in_buf: input buffer */ static block_t *DoWork(filter_t *p_filter, block_t *p_in_buf) { block_t *block = block_Duplicate(p_in_buf); if (likely(block != NULL)) block_FifoPut(p_filter->p_sys->fifo, block); return p_in_buf; }
static void CommandPush( vod_t *p_vod, rtsp_cmd_type_t i_type, vod_media_t *p_media, const char *psz_arg ) { rtsp_cmd_t cmd; block_t *p_cmd; cmd.i_type = i_type; cmd.p_media = p_media; if( psz_arg ) cmd.psz_arg = strdup(psz_arg); else cmd.psz_arg = NULL; p_cmd = block_Alloc( sizeof(rtsp_cmd_t) ); memcpy( p_cmd->p_buffer, &cmd, sizeof(cmd) ); block_FifoPut( p_vod->p_sys->p_fifo_cmd, p_cmd ); }
static void DStreamDelete( stream_t *s ) { stream_sys_t *p_sys = s->p_sys; block_t *p_empty; atomic_store( &p_sys->active, false ); p_empty = block_Alloc( 0 ); block_FifoPut( p_sys->p_fifo, p_empty ); vlc_join( p_sys->thread, NULL ); vlc_mutex_destroy( &p_sys->lock ); if( p_sys->p_block ) block_Release( p_sys->p_block ); block_FifoRelease( p_sys->p_fifo ); free( p_sys->psz_name ); free( p_sys ); }
/**************************************************************************** * 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; }
/* We split/pack PCM blocks to a fixed size: pcm_chunk_size bytes */ static block_t *GetPCM( encoder_t *p_enc, aout_buffer_t *p_block ) { encoder_sys_t *p_sys = p_enc->p_sys; block_t *p_pcm_block; if( !p_block ) goto buffered; /* just return a block if we can */ /* Put the PCM samples sent by VLC in the Fifo */ while( p_sys->i_buffer + p_block->i_buffer >= pcm_chunk_size ) { unsigned int i_buffer = 0; p_pcm_block = block_New( p_enc, pcm_chunk_size ); if( !p_pcm_block ) break; if( p_sys->i_buffer ) { vlc_memcpy( p_pcm_block->p_buffer, p_sys->p_buffer, p_sys->i_buffer ); i_buffer = p_sys->i_buffer; p_sys->i_buffer = 0; free( p_sys->p_buffer ); } vlc_memcpy( p_pcm_block->p_buffer + i_buffer, p_block->p_buffer, pcm_chunk_size - i_buffer ); p_block->p_buffer += pcm_chunk_size - i_buffer; p_block->i_buffer -= pcm_chunk_size - i_buffer; block_FifoPut( p_sys->p_fifo, p_pcm_block ); } /* We hadn't enough data to make a block, put it in standby */ if( p_block->i_buffer ) { uint8_t *p_tmp; if( p_sys->i_buffer > 0 ) p_tmp = realloc( p_sys->p_buffer, p_block->i_buffer + p_sys->i_buffer ); else p_tmp = malloc( p_block->i_buffer ); if( !p_tmp ) { p_sys->i_buffer = 0; free( p_sys->p_buffer ); p_sys->p_buffer = NULL; return NULL; } p_sys->p_buffer = p_tmp; vlc_memcpy( p_sys->p_buffer + p_sys->i_buffer, p_block->p_buffer, p_block->i_buffer ); p_sys->i_buffer += p_block->i_buffer; p_block->i_buffer = 0; } buffered: /* and finally get a block back */ return block_FifoCount( p_sys->p_fifo ) > 0 ? block_FifoGet( p_sys->p_fifo ) : NULL; }
void stream_DemuxSend( stream_t *s, block_t *p_block ) { stream_sys_t *p_sys = s->p_sys; block_FifoPut( p_sys->p_fifo, p_block ); }
/***************************************************************************** * ThreadWrite: Write a packet on the network at the good time. *****************************************************************************/ static void* ThreadWrite( void *data ) { sout_access_out_t *p_access = data; sout_access_out_sys_t *p_sys = p_access->p_sys; mtime_t i_date_last = -1; const unsigned i_group = var_GetInteger( p_access, SOUT_CFG_PREFIX "group" ); mtime_t i_to_send = i_group; unsigned i_dropped_packets = 0; for (;;) { block_t *p_pk = block_FifoGet( p_sys->p_fifo ); mtime_t i_date, i_sent; i_date = p_sys->i_caching + p_pk->i_dts; if( i_date_last > 0 ) { if( i_date - i_date_last > 2000000 ) { if( !i_dropped_packets ) msg_Dbg( p_access, "mmh, hole (%"PRId64" > 2s) -> drop", i_date - i_date_last ); block_FifoPut( p_sys->p_empty_blocks, p_pk ); i_date_last = i_date; i_dropped_packets++; continue; } else if( i_date - i_date_last < -1000 ) { if( !i_dropped_packets ) msg_Dbg( p_access, "mmh, packets in the past (%"PRId64")", i_date_last - i_date ); } } block_cleanup_push( p_pk ); i_to_send--; if( !i_to_send || (p_pk->i_flags & BLOCK_FLAG_CLOCK) ) { mwait( i_date ); i_to_send = i_group; } if ( send( p_sys->i_handle, p_pk->p_buffer, p_pk->i_buffer, 0 ) == -1 ) msg_Warn( p_access, "send error: %s", vlc_strerror_c(errno) ); vlc_cleanup_pop(); if( i_dropped_packets ) { msg_Dbg( p_access, "dropped %i packets", i_dropped_packets ); i_dropped_packets = 0; } #if 1 i_sent = mdate(); if ( i_sent > i_date + 20000 ) { msg_Dbg( p_access, "packet has been sent too late (%"PRId64 ")", i_sent - i_date ); } #endif block_FifoPut( p_sys->p_empty_blocks, p_pk ); i_date_last = i_date; } return NULL; }
/***************************************************************************** * Write: standard write on a file descriptor. *****************************************************************************/ static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer ) { sout_access_out_sys_t *p_sys = p_access->p_sys; int i_len = 0; while( p_buffer ) { block_t *p_next; int i_packets = 0; mtime_t now = mdate(); if( !p_sys->b_mtu_warning && p_buffer->i_buffer > p_sys->i_mtu ) { msg_Warn( p_access, "packet size > MTU, you should probably " "increase the MTU" ); p_sys->b_mtu_warning = true; } /* Check if there is enough space in the buffer */ if( p_sys->p_buffer && p_sys->p_buffer->i_buffer + p_buffer->i_buffer > p_sys->i_mtu ) { if( p_sys->p_buffer->i_dts + p_sys->i_caching < now ) { msg_Dbg( p_access, "late packet for UDP input (%"PRId64 ")", now - p_sys->p_buffer->i_dts - p_sys->i_caching ); } block_FifoPut( p_sys->p_fifo, p_sys->p_buffer ); p_sys->p_buffer = NULL; } i_len += p_buffer->i_buffer; while( p_buffer->i_buffer ) { size_t i_payload_size = p_sys->i_mtu; size_t i_write = __MIN( p_buffer->i_buffer, i_payload_size ); i_packets++; if( !p_sys->p_buffer ) { p_sys->p_buffer = NewUDPPacket( p_access, p_buffer->i_dts ); if( !p_sys->p_buffer ) break; } memcpy( p_sys->p_buffer->p_buffer + p_sys->p_buffer->i_buffer, p_buffer->p_buffer, i_write ); p_sys->p_buffer->i_buffer += i_write; p_buffer->p_buffer += i_write; p_buffer->i_buffer -= i_write; if ( p_buffer->i_flags & BLOCK_FLAG_CLOCK ) { if ( p_sys->p_buffer->i_flags & BLOCK_FLAG_CLOCK ) msg_Warn( p_access, "putting two PCRs at once" ); p_sys->p_buffer->i_flags |= BLOCK_FLAG_CLOCK; } if( p_sys->p_buffer->i_buffer == p_sys->i_mtu || i_packets > 1 ) { /* Flush */ if( p_sys->p_buffer->i_dts + p_sys->i_caching < now ) { msg_Dbg( p_access, "late packet for udp input (%"PRId64 ")", mdate() - p_sys->p_buffer->i_dts - p_sys->i_caching ); } block_FifoPut( p_sys->p_fifo, p_sys->p_buffer ); p_sys->p_buffer = NULL; } } p_next = p_buffer->p_next; block_Release( p_buffer ); p_buffer = p_next; } return i_len; }