[vlc-devel] [PATCH] Add avparser packetizer for VP9 handling

Denis Charmet typx at dinauz.org
Thu Feb 26 17:32:29 CET 2015


From: CHARMET Denis <typx at dinauz.org>

Fix #12944
---
 modules/codec/avcodec/video.c                |    4 +
 modules/demux/mkv/matroska_segment_parse.cpp |    1 +
 modules/packetizer/Makefile.am               |   13 ++
 modules/packetizer/avparser.c                |  188 ++++++++++++++++++++++++++
 4 files changed, 206 insertions(+)
 create mode 100644 modules/packetizer/avparser.c

diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c
index 5ba6e2e..381fe62 100644
--- a/modules/codec/avcodec/video.c
+++ b/modules/codec/avcodec/video.c
@@ -454,6 +454,10 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context,
     }
 
     p_dec->pf_decode_video = DecodeVideo;
+
+    if ( p_dec->fmt_in.i_codec == VLC_CODEC_VP9 )
+        p_dec->b_need_packetized = true;
+
     return VLC_SUCCESS;
 }
 
diff --git a/modules/demux/mkv/matroska_segment_parse.cpp b/modules/demux/mkv/matroska_segment_parse.cpp
index 7f3bcb2..ff47a2b5 100644
--- a/modules/demux/mkv/matroska_segment_parse.cpp
+++ b/modules/demux/mkv/matroska_segment_parse.cpp
@@ -1370,6 +1370,7 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
     else if( !strncmp( p_tk->psz_codec, "V_VP9", 5 ) )
     {
         p_tk->fmt.i_codec = VLC_CODEC_VP9;
+        p_tk->fmt.b_packetized = false;
         fill_extra_data( p_tk, 0 );
     }
     else if( !strncmp( p_tk->psz_codec, "V_MPEG4", 7 ) )
diff --git a/modules/packetizer/Makefile.am b/modules/packetizer/Makefile.am
index ff28b08..ce71ce2 100644
--- a/modules/packetizer/Makefile.am
+++ b/modules/packetizer/Makefile.am
@@ -13,6 +13,14 @@ libpacketizer_dirac_plugin_la_SOURCES = packetizer/dirac.c
 libpacketizer_flac_plugin_la_SOURCES = packetizer/flac.c
 libpacketizer_hevc_plugin_la_SOURCES = packetizer/hevc.c
 
+libpacketizer_avparser_plugin_la_SOURCES = packetizer/avparser.c \
+	codec/avcodec/avcommon.h \
+	codec/avcodec/avcodec.h \
+	codec/avcodec/fourcc.c
+libpacketizer_avparser_plugin_la_CFLAGS = $(AVCODEC_CFLAGS) $(AVUTIL_CFLAGS) $(AM_CFLAGS)
+libpacketizer_avparser_plugin_la_LIBADD = $(AVCODEC_LIBS) $(AVUTIL_LIBS) $(LIBM)
+
+
 noinst_HEADERS += packetizer/packetizer_helper.h
 
 packetizer_LTLIBRARIES = \
@@ -29,3 +37,8 @@ packetizer_LTLIBRARIES = \
 if ENABLE_SOUT
 packetizer_LTLIBRARIES += libpacketizer_copy_plugin.la
 endif
+
+if HAVE_AVCODEC
+packetizer_LTLIBRARIES += libpacketizer_avparser_plugin.la
+endif
+
diff --git a/modules/packetizer/avparser.c b/modules/packetizer/avparser.c
new file mode 100644
index 0000000..d172462
--- /dev/null
+++ b/modules/packetizer/avparser.c
@@ -0,0 +1,188 @@
+/*****************************************************************************
+ * avparser.c
+ *****************************************************************************
+ * Copyright (C) 2015 VLC authors and VideoLAN
+ * $Id$
+ *
+ * Authors: Denis Charmet <typx at videolan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_codec.h>
+#include <vlc_block.h>
+
+#include "../codec/avcodec/avcodec.h"
+#include "../codec/avcodec/avcommon.h"
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int  Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+vlc_module_begin ()
+    set_category( CAT_SOUT )
+    set_subcategory( SUBCAT_SOUT_PACKETIZER )
+    set_description( N_("avparser packetizer") )
+    set_capability( "packetizer", 1 )
+    set_callbacks( Open, Close )
+vlc_module_end ()
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+struct decoder_sys_t
+{
+    AVCodecParserContext * p_parser_ctx;
+    AVCodecContext * p_codec_ctx;
+    int i_offset;
+};
+
+static block_t * Packetize( decoder_t *, block_t ** );
+
+/*****************************************************************************
+ * Open: probe the packetizer and return score
+ *****************************************************************************
+ * Tries to launch a decoder and return score so that the interface is able
+ * to choose.
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    decoder_t     *p_dec = (decoder_t*)p_this;
+    decoder_sys_t *p_sys;
+
+    /* Restrict to VP9 for now */
+    if( p_dec->fmt_in.i_codec != VLC_CODEC_VP9 )
+        return VLC_EGENERIC;
+
+    unsigned i_avcodec_id;
+
+    if( !GetFfmpegCodec( p_dec->fmt_in.i_codec, NULL, &i_avcodec_id, NULL ) )
+        return VLC_EGENERIC;
+
+    /* init avcodec */
+    vlc_init_avcodec(p_this);
+
+    /* It is less likely to have a parser than a codec, start by that */
+    AVCodecParserContext * p_ctx = av_parser_init( i_avcodec_id );
+    if( !p_ctx )
+        return VLC_EGENERIC;
+    
+    AVCodec * p_codec = avcodec_find_decoder( i_avcodec_id );
+    if( unlikely( !p_codec ) )
+    {
+        av_parser_close( p_ctx );
+        return VLC_EGENERIC;
+    }
+  
+    AVCodecContext * p_codec_ctx = avcodec_alloc_context3( p_codec );
+    if( unlikely( !p_codec_ctx ) )
+    {
+        av_parser_close( p_ctx );
+        return VLC_ENOMEM;
+    }
+
+    p_dec->p_sys = p_sys = malloc( sizeof(*p_sys) );
+
+    if( unlikely( !p_sys ) )
+    {
+        avcodec_free_context( &p_codec_ctx );
+        av_parser_close( p_ctx );
+        return VLC_ENOMEM;
+    }
+    p_dec->pf_packetize = Packetize;
+    p_sys->p_parser_ctx = p_ctx;
+    p_sys->p_codec_ctx = p_codec_ctx;
+    p_sys->i_offset = 0;
+    es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+static void Close( vlc_object_t *p_this )
+{
+    decoder_t     *p_dec = (decoder_t*)p_this;
+    avcodec_free_context( &p_dec->p_sys->p_codec_ctx );
+    av_parser_close( p_dec->p_sys->p_parser_ctx );
+    es_format_Clean( &p_dec->fmt_out );
+    free( p_dec->p_sys );
+}
+
+/*****************************************************************************
+ * Packetize: packetize a frame
+ *****************************************************************************/
+static block_t *Packetize ( decoder_t *p_dec, block_t **pp_block )
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
+    if( pp_block == NULL || *pp_block == NULL )
+        return NULL;
+    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
+    {
+        block_Release( *pp_block );
+        return NULL;
+    }
+
+    block_t * p_block = *pp_block;
+
+    uint8_t * p_indata = p_block->p_buffer + p_sys->i_offset;
+    int i_inlen = p_block->i_buffer -  p_sys->i_offset;
+    uint8_t * p_outdata;
+    int i_outlen;
+
+    if( p_sys->i_offset == i_inlen )
+        goto out;
+
+    p_sys->i_offset += av_parser_parse2( p_sys->p_parser_ctx, p_sys->p_codec_ctx,
+                                         &p_outdata, &i_outlen, p_indata, i_inlen,
+                                         p_block->i_pts, p_block->i_dts, -1);
+
+    if( unlikely( i_outlen <= 0 || !p_outdata ) )
+        goto out;
+
+    block_t * p_ret = block_Alloc( i_outlen );
+
+    if( unlikely ( !p_ret ) )
+        goto out;
+
+    memcpy( p_ret->p_buffer, p_outdata, i_outlen );
+    p_ret->i_pts = p_block->i_pts;
+    p_ret->i_dts = p_block->i_dts;
+
+    p_block->i_pts = p_block->i_dts = VLC_TS_INVALID;
+
+    return p_ret;
+    
+out:
+    p_sys->i_offset = 0;
+    block_Release( *pp_block );
+    *pp_block == NULL;
+    return NULL;
+}
+
-- 
1.7.9.5




More information about the vlc-devel mailing list