[vlc-devel] [PATCH 2/2] Add a simple raw hevc demux
Denis Charmet
typx at dinauz.org
Tue Feb 11 01:00:10 CET 2014
---
modules/demux/Makefile.am | 3 +
modules/demux/mpeg/hevc.c | 349 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 352 insertions(+)
create mode 100644 modules/demux/mpeg/hevc.c
diff --git a/modules/demux/Makefile.am b/modules/demux/Makefile.am
index 6eb646d..0cab9eb 100644
--- a/modules/demux/Makefile.am
+++ b/modules/demux/Makefile.am
@@ -162,6 +162,9 @@ demux_LTLIBRARIES += libes_plugin.la
libh264_plugin_la_SOURCES = demux/mpeg/h264.c
demux_LTLIBRARIES += libh264_plugin.la
+libhevc_plugin_la_SOURCES = demux/mpeg/hevc.c
+demux_LTLIBRARIES += libhevc_plugin.la
+
libmkv_plugin_la_SOURCES = \
demux/mkv/util.hpp demux/mkv/util.cpp \
demux/mkv/virtual_segment.hpp demux/mkv/virtual_segment.cpp \
diff --git a/modules/demux/mpeg/hevc.c b/modules/demux/mpeg/hevc.c
new file mode 100644
index 0000000..fa58f8f
--- /dev/null
+++ b/modules/demux/mpeg/hevc.c
@@ -0,0 +1,349 @@
+/*****************************************************************************
+ * hevc.c : HEVC Video demuxer
+ *****************************************************************************
+ * Copyright (C) 2014 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_demux.h>
+#include <vlc_codec.h>
+#include <vlc_bits.h>
+
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+#define FPS_TEXT N_("Frames per Second")
+#define FPS_LONGTEXT N_("Desired frame rate for the stream.")
+
+
+vlc_module_begin ()
+ set_shortname( "HEVC")
+ set_category( CAT_INPUT )
+ set_subcategory( SUBCAT_INPUT_DEMUX )
+ set_description( N_("HEVC/H.265 video demuxer" ) )
+ set_capability( "demux", 0 )
+ add_float( "hevc-force-fps", 0.0, FPS_TEXT, FPS_LONGTEXT, true )
+ set_callbacks( Open, Close )
+ add_shortcut( "hevc" )
+vlc_module_end ()
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+struct demux_sys_t
+{
+ mtime_t i_dts;
+ es_out_id_t *p_es;
+
+ float f_force_fps;
+ float f_fps;
+ decoder_t *p_packetizer;
+};
+
+static int Demux( demux_t * );
+static int Control( demux_t *, int, va_list );
+
+static int32_t getFPS( demux_t *, block_t * );
+
+#define HEVC_BLOCK_SIZE 2048
+
+/*****************************************************************************
+ * Open: initializes demux structures
+ *****************************************************************************/
+static int Open( vlc_object_t * p_this )
+{
+ demux_t *p_demux = (demux_t*)p_this;
+ demux_sys_t *p_sys;
+ const uint8_t *p_peek;
+ es_format_t fmt;
+
+ if( stream_Peek( p_demux->s, &p_peek, 5 ) < 5 ) return VLC_EGENERIC;
+
+ if( p_peek[0] != 0x00 || p_peek[1] != 0x00 ||
+ p_peek[2] != 0x00 || p_peek[3] != 0x01 ||
+ (p_peek[4]&0xFE) != 0x40 ) /* VPS & forbidden zero bit*/
+ {
+ if( !p_demux->b_force )
+ {
+ msg_Warn( p_demux, "hevc module discarded (no startcode)" );
+ return VLC_EGENERIC;
+ }
+
+ msg_Err( p_demux, "this doesn't look like a HEVC ES stream, "
+ "continuing anyway" );
+ }
+
+ p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
+
+ if( !p_demux->p_sys )
+ return VLC_ENOMEM;
+
+ p_sys->p_es = NULL;
+ p_sys->i_dts = 0;
+ p_sys->f_force_fps = var_CreateGetFloat( p_demux, "hevc-force-fps" );
+ if( p_sys->f_force_fps != 0.0f )
+ {
+ p_sys->f_fps = ( p_sys->f_force_fps < 0.001f )? 0.001f:
+ p_sys->f_force_fps;
+ msg_Dbg( p_demux, "using %.2f fps", p_sys->f_fps );
+ }
+ else
+ p_sys->f_fps = 0.0f;
+
+ /* Load the hevc packetizer */
+ es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_HEVC );
+ p_sys->p_packetizer = demux_PacketizerNew( p_demux, &fmt, "hevc" );
+ if( !p_sys->p_packetizer )
+ {
+ free( p_sys );
+ return VLC_EGENERIC;
+ }
+
+ p_sys->p_packetizer->fmt_out.b_packetized = true;
+ p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_out);
+
+ if( !p_sys->p_es )
+ {
+ demux_PacketizerDestroy( p_sys->p_packetizer );
+ free( p_sys );
+ return VLC_ENOMEM;
+ }
+ p_demux->pf_demux = Demux;
+ p_demux->pf_control= Control;
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close: frees unused data
+ *****************************************************************************/
+static void Close( vlc_object_t * p_this )
+{
+ demux_t *p_demux = (demux_t*)p_this;
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ demux_PacketizerDestroy( p_sys->p_packetizer );
+ free( p_sys );
+}
+
+/*****************************************************************************
+ * Demux: reads and demuxes data packets
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+static int Demux( demux_t *p_demux)
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ block_t *p_block_in, *p_block_out;
+
+ if( ( p_block_in = stream_Block( p_demux->s, HEVC_BLOCK_SIZE ) ) == NULL )
+ {
+ return 0;
+ }
+
+ p_block_in->i_dts = VLC_TS_INVALID;
+ p_block_in->i_pts = VLC_TS_INVALID;
+
+ while( (p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, &p_block_in )) )
+ {
+ while( p_block_out )
+ {
+ block_t *p_next = p_block_out->p_next;
+
+ p_block_out->p_next = NULL;
+
+ p_block_out->i_dts = VLC_TS_0 + p_sys->i_dts;
+ p_block_out->i_pts = VLC_TS_INVALID;
+
+ /*Get fps from vps if available and not already forced*/
+ if( p_sys->f_fps == 0.0f && ( p_block_out->p_buffer[3] & 0x7E ) == 0x40 )
+ {
+ if( getFPS( p_demux, p_block_out) )
+ {
+ msg_Err(p_demux,"getFPS failed");
+ return 0;
+ }
+ }
+
+ /* Update DTS only on VCL NAL*/
+ if( ( p_block_out->p_buffer[3]&0x7E ) < 0x40 && p_sys->f_fps )
+ {
+ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_dts );
+ p_sys->i_dts += (int64_t)((double)1000000.0 / p_sys->f_fps);
+ }
+
+ es_out_Send( p_demux->out, p_sys->p_es, p_block_out );
+
+ p_block_out = p_next;
+
+ }
+ }
+ return 1;
+}
+
+/*****************************************************************************
+ * Control:
+ *****************************************************************************/
+static int Control( demux_t *p_demux, int i_query, va_list args )
+{
+ return demux_vaControlHelper( p_demux->s,
+ 0, -1,
+ 0, 1, i_query, args );
+}
+
+
+static void CreateDecodedNAL( uint8_t **pp_ret, int *pi_ret,
+ const uint8_t *src, int i_src )
+{
+ const uint8_t *end = &src[i_src];
+ uint8_t *dst = malloc( i_src );
+ if( !dst )
+ return;
+
+ *pp_ret = dst;
+
+ if( dst )
+ {
+ while( src < end )
+ {
+ if( src < end - 3 && src[0] == 0x00 && src[1] == 0x00 &&
+ src[2] == 0x03 )
+ {
+ *dst++ = 0x00;
+ *dst++ = 0x00;
+
+ src += 3;
+ continue;
+ }
+ *dst++ = *src++;
+ }
+ }
+ *pi_ret = dst - *pp_ret;
+}
+
+
+static void skipProfileTiersLevel( bs_t * bs, int32_t max_sub_layer_minus1 )
+{
+ uint8_t sub_layer_profile_present_flag[8];
+ uint8_t sub_layer_level_present_flag[8];
+
+ /* skipping useless fields of the VPS see https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.265-201304-I!!PDF-E&type=item */
+ bs_skip( bs, 2 + 1 + 5 + 32 + 1 + 1 + 1 + 1 + 44 + 8 );
+
+ for( int32_t i = 0; i < max_sub_layer_minus1; i++ )
+ {
+ sub_layer_profile_present_flag[i] = bs_read1( bs );
+ sub_layer_level_present_flag[i] = bs_read1( bs );
+ }
+
+ if(max_sub_layer_minus1 > 0)
+ bs_skip( bs, (8 - max_sub_layer_minus1) * 2 );
+
+ for( int32_t i = 0; i < max_sub_layer_minus1; i++ )
+ {
+ if( sub_layer_profile_present_flag[i] )
+ bs_skip( bs, 2 + 1 + 5 + 32 + 1 + 1 + 1 + 1 + 44 );
+ if( sub_layer_level_present_flag[i] )
+ bs_skip( bs, 8 );
+ }
+}
+
+static uint32_t read_ue( bs_t * bs )
+{
+ int32_t i = 0;
+
+ while( bs_read1( bs ) == 0 && bs->p < bs->p_end && i < 32 )
+ i++;
+
+ return (1 << i) - 1 + bs_read( bs, i );
+}
+
+static int32_t getFPS( demux_t *p_demux, block_t * p_block )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ bs_t bs;
+ uint8_t * p_decoded_nal;
+ int i_decoded_nal;
+
+ if( p_block->i_buffer < 5 )
+ return -1;
+
+ CreateDecodedNAL( &p_decoded_nal, &i_decoded_nal,
+ p_block->p_buffer+3, p_block->i_buffer-3 );
+
+ if( !p_decoded_nal )
+ return -1;
+
+ bs_init( &bs, p_decoded_nal, i_decoded_nal );
+ bs_skip( &bs, 12 );
+ int32_t max_sub_layer_minus1 = bs_read( &bs, 3 );
+ bs_skip( &bs, 17 );
+
+ skipProfileTiersLevel( &bs, max_sub_layer_minus1 );
+
+ int32_t vps_sub_layer_ordering_info_present_flag = bs_read1( &bs );
+ int32_t i = vps_sub_layer_ordering_info_present_flag? 0 : max_sub_layer_minus1;
+ for( ; i <= max_sub_layer_minus1; i++ )
+ {
+ read_ue( &bs );
+ read_ue( &bs );
+ read_ue( &bs );
+ }
+ uint32_t vps_max_layer_id = bs_read( &bs, 6);
+ uint32_t vps_num_layer_sets_minus1 = read_ue( &bs );
+ bs_skip( &bs, vps_max_layer_id * vps_num_layer_sets_minus1 );
+
+ if( bs_read1( &bs ))
+ {
+ uint32_t num_units_in_tick = bs_read( &bs, 32 );
+ uint32_t time_scale = bs_read( &bs, 32 );
+ if( num_units_in_tick )
+ {
+ p_sys->f_fps = ( (float) time_scale )/( (float) num_units_in_tick );
+ msg_Dbg(p_demux,"Using framerate %f fps from VPS", p_sys->f_fps);
+ }
+ else
+ {
+ msg_Err( p_demux, "vps_num_units_in_tick null defaulting to 25 fps");
+ p_sys->f_fps = 25.0f;
+ }
+ }
+ else
+ {
+ msg_Err( p_demux, "No timing info in VPS defaulting to 25 fps");
+ p_sys->f_fps = 25.0f;
+ }
+ free(p_decoded_nal);
+ return 0;
+}
--
1.9.rc1
More information about the vlc-devel
mailing list