[vlc-devel] Re: access_demux versus access2 - trying to understand how to write a VCD plugin

Laurent Aimar fenrir at via.ecp.fr
Thu Dec 23 16:44:03 CET 2004

On Thu, Dec 23, 2004, R. Bernstein wrote:
> Since the first time I looked at videolan in to write a VCD plugin
> with playback control, a great deal seems to have changed. 
> One thing that hasn't is the lack of developer information or
> documentation. So I look at close source code and the two things that
> seem the most relevant are dvdnav.c and v4l.c. 
> The things that the VCD plugin needs to do (which it doesn't right
> now) is detect changes in streams between still-frame MPEGs and motion
> MPEGs which may have different aspect ratios. Also it needs to handle
> key events.
> Looking at dvdnav.c and v4l.c I see neither uses
> set_capability("access2") like the VCD and CDDA plugins are, but
> set_capability("access_demux") instead. It seems like they provide
> both the input reading part ("access") as well as the some demuxing
> part at least to be able to signal the kinds of stream changes and
> input events mentioned above. 

The general(main) architecture of vlc input is

 access_t -> stream_t -> demux_t -> es_out_t

You have
 access_t : it does the reading part ('protocol' specific, like http, file).
 demux_t  : it understands a format of encapsulation (like AVI, MPEG-PS),
            it extracts the elementary stream(s), and it handles the seeking

The core provides:
 stream_t : it is the glue between access_t and demux_t (and add a layer
            of abstraction). It also adds a buffering system.
 es_out_t : it handles the ES selection, the packetization and decoding part.
            it converts PTS/DTS given by demuxer in nice system date, and
            it controls the speed of the input (es_out_Send() is blocking).

 This way work swell when a demuxer has a really simple relation with the
access. But some time, the access part (reading) and the demuxer part
(demuxing and seeking) are really tied together. For those cases, a
access_demux_t can be used instead:

 access_demux_t -> es_out_t

 (No more access and no more stream_t).
 The input core will see the access_demux_t as a demux_t except for a few
control (access_demux_t->pf_control).
 The field access_demux_t->s is NULL as it has to do the reading part itself.
 The access_demux_t should provide (as all demuxers):
  - pf_demux: it will read data, demux them and send them to es_out_t.
  - pf_control: various demuxer controls, that the input will call.
 A few DEMUX_* are mandatory (see include/vlc_demux.h)

> Lastly question is on es_out_Control (a static inline function which
> mostly calls out->pf_control) and the other es_out_* routines. How
> does one understand what do what they require or how to use, I guess
> specifically for MPEG streams. 

About es_out_t <-> demux_t the general case will be:
 es_format_t fmt;
 es_out_id_t *p_es;

 // First, declare the ES (at anytime, but the best for user/interface, is
the earlier)

 es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'm', 'p', 'g', 'a' ) );
 fmt.XXX = XXX;
 p_es = es_out_Add( p_demux->out, &fmt );

 // Now when demuxing:

 // If you know that you have a discontinuity (but no need after a seek, the
 input core takes care of that case) then reset the PCR
 if( i_have_detected_a_discontinuity )
     es_out_Control( p_demux->out, p_es, ES_CONTROL_RESET_PCR );

 // You have to send PCR (one a least before the first packet).
 if( i_have_a_new_pcr )
    int64_t i_pcr = my_pcr_in_microsecond;
    es_out_Control( p_demux->out, p_es, ES_CONTROL_SET_PCR, i_pcr );

 // Send data to the decoder (if no decoder, then the data will be discarded)
 // Fill the block_t with the right info before.
 block_t *p_data;
 p_data = block_New( p_demux, my_data_size );
 p_data->i_buffer = my_buffer_size; // (not mandatory, block_New does it).
 memcpy( p_data->p_buffer, my_data, my_data_size );
 if( i_have_a_new_dts )
     p_data->i_dts = my_dts_in_microsecond;
 if( i_have_a_new_pts )
     p_data->i_pts = my_pts_in_microsecond;
 if( is_video_trakc && i_know_the_data_frame_type )
    if( is_i_frame )
        p_data->i_flags |= BLOCK_FALG_TYPE_I;
    else if( is_p_frame )
        p_data->i_flags |= BLOCK_FALG_TYPE_P;
    else if( is_b_frame )
        p_data->i_flags |= BLOCK_FALG_TYPE_B;
    else if( i_only_know_it_is_not_a_key_frame )
        p_data->i_flags |= BLOCK_FALG_TYPE_PB;

 if( i_have_the_sample_length )
     p_data->i_length = my_length_in_microsecond;

 es_out_Send( p_demux->out, p_es, p_data );

 You can do a es_out_Del( p_demux->out, p_es ) to remove a specific ES
 before the end of the input stream.
 (The core will remove all remaining ES after unloading the demux/access_demux
at the end).

(All others ES_OUT_CONTROL_* are used by the core, and you don't need them).
Have a look at include/vlc_es_out.h).

 I hope this will help. If you have others questions, don't hesitate.
(but I won't be able to answer before january).


To unsubscribe, please read http://developers.videolan.org/lists.html

More information about the vlc-devel mailing list