Commit 2ef307b4 authored by Martin Storsjö's avatar Martin Storsjö Committed by Jean-Baptiste Kempf

Split SPS/PPS parsing and annex b conversion to a reusable utility function

Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent 3d511423
......@@ -36,7 +36,7 @@ SOURCES_aes3 = aes3.c
SOURCES_subsdec = subsdec.c substext.h
SOURCES_subsusf = subsusf.c
SOURCES_t140 = t140.c
SOURCES_crystalhd = crystalhd.c
SOURCES_crystalhd = crystalhd.c h264_nal.h
SOURCES_stl = stl.c
SOURCES_ddummy = ddummy.c
SOURCES_edummy = edummy.c
......
......@@ -37,6 +37,7 @@
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_codec.h>
#include "h264_nal.h"
/* Workaround for some versions of libcrystalHD */
#if !defined(_WIN32) && !defined(__APPLE__)
......@@ -606,9 +607,7 @@ static int crystal_insert_sps_pps( decoder_t *p_dec,
uint32_t i_buf_size)
{
decoder_sys_t *p_sys = p_dec->p_sys;
int i_profile;
uint32_t i_data_size = i_buf_size, i_nal_size;
unsigned int i_loop_end;
int ret;
p_sys->i_sps_pps_size = 0;
......@@ -616,68 +615,14 @@ static int crystal_insert_sps_pps( decoder_t *p_dec,
if( !p_sys->p_sps_pps_buf )
return VLC_ENOMEM;
/* */
if( i_data_size < 7 )
{
msg_Err( p_dec, "Input Metadata too small" );
goto error;
}
/* Read infos in first 6 bytes */
i_profile = (p_buf[1] << 16) | (p_buf[2] << 8) | p_buf[3];
p_sys->i_nal_size = (p_buf[4] & 0x03) + 1;
p_buf += 5;
i_data_size -= 5;
for ( unsigned int j = 0; j < 2; j++ )
{
/* First time is SPS, Second is PPS */
if( i_data_size < 1 )
{
msg_Err( p_dec, "PPS too small after processing SPS/PPS %u",
i_data_size );
goto error;
}
i_loop_end = p_buf[0] & (j == 0 ? 0x1f : 0xff);
p_buf++; i_data_size--;
for ( unsigned int i = 0; i < i_loop_end; i++)
{
if( i_data_size < 2 )
{
msg_Err( p_dec, "SPS is too small %u", i_data_size );
goto error;
}
i_nal_size = (p_buf[0] << 8) | p_buf[1];
p_buf += 2;
i_data_size -= 2;
if( i_data_size < i_nal_size )
{
msg_Err( p_dec, "SPS size does not match NAL specified size %u",
i_data_size );
goto error;
}
p_sys->p_sps_pps_buf[p_sys->i_sps_pps_size++] = 0;
p_sys->p_sps_pps_buf[p_sys->i_sps_pps_size++] = 0;
p_sys->p_sps_pps_buf[p_sys->i_sps_pps_size++] = 0;
p_sys->p_sps_pps_buf[p_sys->i_sps_pps_size++] = 1;
ret = convert_sps_pps( p_dec, p_buf, i_buf_size, p_sys->p_sps_pps_buf,
p_dec->fmt_in.i_extra * 2, &p_sys->i_sps_pps_size,
&p_sys->i_nal_size );
if( !ret )
return ret;
memcpy( p_sys->p_sps_pps_buf + p_sys->i_sps_pps_size, p_buf, i_nal_size );
p_sys->i_sps_pps_size += i_nal_size;
p_buf += i_nal_size;
i_data_size -= i_nal_size;
}
}
return VLC_SUCCESS;
error:
free( p_sys->p_sps_pps_buf );
p_sys->p_sps_pps_buf = NULL;
return VLC_ENOMEM;
return ret;
}
/*****************************************************************************
* Copyright © 2010-2011 VideoLAN
*
* Authors: Jean-Baptiste Kempf <jb@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 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.
*****************************************************************************/
/* Parse the SPS/PPS Metadata and convert it to annex b format */
static int convert_sps_pps( decoder_t *p_dec, const uint8_t *p_buf,
uint32_t i_buf_size, uint8_t *p_out_buf,
uint32_t i_out_buf_size, uint32_t *p_sps_pps_size,
uint32_t *p_nal_size)
{
int i_profile;
uint32_t i_data_size = i_buf_size, i_nal_size, i_sps_pps_size = 0;
unsigned int i_loop_end;
/* */
if( i_data_size < 7 )
{
msg_Err( p_dec, "Input Metadata too small" );
return VLC_ENOMEM;
}
/* Read infos in first 6 bytes */
i_profile = (p_buf[1] << 16) | (p_buf[2] << 8) | p_buf[3];
*p_nal_size = (p_buf[4] & 0x03) + 1;
p_buf += 5;
i_data_size -= 5;
for ( unsigned int j = 0; j < 2; j++ )
{
/* First time is SPS, Second is PPS */
if( i_data_size < 1 )
{
msg_Err( p_dec, "PPS too small after processing SPS/PPS %u",
i_data_size );
return VLC_ENOMEM;
}
i_loop_end = p_buf[0] & (j == 0 ? 0x1f : 0xff);
p_buf++; i_data_size--;
for ( unsigned int i = 0; i < i_loop_end; i++)
{
if( i_data_size < 2 )
{
msg_Err( p_dec, "SPS is too small %u", i_data_size );
return VLC_ENOMEM;
}
i_nal_size = (p_buf[0] << 8) | p_buf[1];
p_buf += 2;
i_data_size -= 2;
if( i_data_size < i_nal_size )
{
msg_Err( p_dec, "SPS size does not match NAL specified size %u",
i_data_size );
return VLC_ENOMEM;
}
if( i_sps_pps_size + 4 + i_nal_size > i_out_buf_size )
{
msg_Err( p_dec, "Output SPS/PPS buffer too small" );
return VLC_ENOMEM;
}
p_out_buf[i_sps_pps_size++] = 0;
p_out_buf[i_sps_pps_size++] = 0;
p_out_buf[i_sps_pps_size++] = 0;
p_out_buf[i_sps_pps_size++] = 1;
memcpy( p_out_buf + i_sps_pps_size, p_buf, i_nal_size );
i_sps_pps_size += i_nal_size;
p_buf += i_nal_size;
i_data_size -= i_nal_size;
}
}
*p_sps_pps_size = i_sps_pps_size;
return VLC_SUCCESS;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment