[vlc-devel] [PATCH 2/3] avformat mux: Mark keyframe blocks as such.
Rafaël Carré
funman at videolan.org
Tue Sep 3 14:09:53 CEST 2013
Hello Steinar,
Le 16/08/2013 16:42, Steinar H. Gunderson a écrit :
> Some browsers, such as Firefox, are very picky about WebM streams needing to
> start with a keyframe. To be able to handle this correctly when streaming,
> the avformat mux needs to mark keyframe-containing blocks (or clusters, in
> Matroska terminology) as such even after they have been muxed. The next patch
> in the series will make httpd actually care about this flag.
>
> Unfortunately, as avformat does not actually propagate this status, we need
> to use some heuristics to figure out which blocks contain keyframes. The natural
> thing to do would be to say that when we write a keyframe, the block that comes
> back has to be a keyframe block, but the WebM/Matroska muxer thwarts this by
> having its own internal buffering of clusters, flushing the _previous_ cluster
> when we send it a keyframe. Thus, we need to explicitly send a flush (a NULL
> packet) before the one that comes back when we mux a keyframe.
> ---
> modules/demux/avformat/mux.c | 21 ++++++++++++++++++++-
> 1 file changed, 20 insertions(+), 1 deletion(-)
>
> diff --git a/modules/demux/avformat/mux.c b/modules/demux/avformat/mux.c
> index d1277ce..ab72d03 100644
> --- a/modules/demux/avformat/mux.c
> +++ b/modules/demux/avformat/mux.c
> @@ -58,7 +58,9 @@ struct sout_mux_sys_t
> AVFormatContext *oc;
>
> bool b_write_header;
> + bool b_write_keyframe;
> bool b_error;
> + bool b_allow_flush;
This one is unused, I guess it should be removed.
> };
>
> /*****************************************************************************
> @@ -129,6 +131,7 @@ int OpenMux( vlc_object_t *p_this )
> p_sys->oc->nb_streams = 0;
>
> p_sys->b_write_header = true;
> + p_sys->b_write_keyframe = false;
> p_sys->b_error = false;
>
> /* Fill p_mux fields */
> @@ -275,7 +278,17 @@ static int MuxBlock( sout_mux_t *p_mux, sout_input_t *p_input )
> pkt.size = p_data->i_buffer;
> pkt.stream_index = i_stream;
>
> - if( p_data->i_flags & BLOCK_FLAG_TYPE_I ) pkt.flags |= AV_PKT_FLAG_KEY;
> + if( p_data->i_flags & BLOCK_FLAG_TYPE_I )
> + {
> +#ifdef AVFMT_ALLOW_FLUSH
> + /* Make sure we don't inadvertedly mark buffered data as keyframes. */
> + if( p_sys->oc->oformat->flags & AVFMT_ALLOW_FLUSH )
> + av_write_frame( p_sys->oc, NULL );
> +#endif
> +
> + p_sys->b_write_keyframe = true;
> + pkt.flags |= AV_PKT_FLAG_KEY;
> + }
>
> if( p_data->i_pts > 0 )
> pkt.pts = p_data->i_pts * p_stream->time_base.den /
> @@ -402,6 +415,12 @@ static int IOWrite( void *opaque, uint8_t *buf, int buf_size )
> if( p_mux->p_sys->b_write_header )
> p_buf->i_flags |= BLOCK_FLAG_HEADER;
>
> + if( p_mux->p_sys->b_write_keyframe )
> + {
> + p_buf->i_flags |= BLOCK_FLAG_TYPE_I;
> + p_mux->p_sys->b_write_keyframe = false;
> + }
> +
> i_ret = sout_AccessOutWrite( p_mux->p_access, p_buf );
> return i_ret ? i_ret : -1;
> }
Looks good, thanks
More information about the vlc-devel
mailing list