/*****************************************************************************
+ * crystalhd.c: CrystalHD decoder
+ *****************************************************************************
* Copyright © 2010-2011 VideoLAN
*
* Authors: Jean-Baptiste Kempf <jb@videolan.org>
* Narendra Sankar <nsankar@broadcom.com>
*
- * 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
+ * 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.
+ * 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.
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
# include "config.h"
#endif
+/* TODO
+ * - pts = 0?
+ * - mpeg4-asp
+ * - win32 testing
+ */
+
/* VLC includes */
#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__)
uint32_t i_nal_size; /* NAL header size */
+ /* Callback */
+ picture_t *p_pic;
+ BC_DTS_PROC_OUT *proc_out;
+
#ifdef USE_DL_OPENING
HINSTANCE p_bcm_dll;
BC_STATUS (WINAPI *OurDtsCloseDecoder)( HANDLE hDevice );
BC_STATUS (WINAPI *OurDtsDeviceClose)( HANDLE hDevice );
BC_STATUS (WINAPI *OurDtsFlushInput)( HANDLE hDevice, U32 Mode );
BC_STATUS (WINAPI *OurDtsStopDecoder)( HANDLE hDevice );
- BC_STATUS (WINAPI *OurDtsGetDriverStatus)( HANDLE hDevice, BC_DTS_STATUS *pStatus );
+ BC_STATUS (WINAPI *OurDtsGetDriverStatus)( HANDLE hDevice,
+ BC_DTS_STATUS *pStatus );
BC_STATUS (WINAPI *OurDtsProcInput)( HANDLE hDevice, U8 *pUserData,
U32 ulSizeInBytes, U64 timeStamp, BOOL encrypted );
- BC_STATUS (WINAPI *OurDtsProcOutput)( HANDLE hDevice, U32 milliSecWait, BC_DTS_PROC_OUT *pOut );
+ BC_STATUS (WINAPI *OurDtsProcOutput)( HANDLE hDevice, U32 milliSecWait,
+ BC_DTS_PROC_OUT *pOut );
BC_STATUS (WINAPI *OurDtsIsEndOfStream)( HANDLE hDevice, U8* bEOS );
#endif
};
return VLC_ENOMEM;
/* Fill decoder_sys_t */
- p_dec->p_sys = p_sys;
- p_sys->i_nal_size = 4; // assume 4 byte start codes
- p_sys->i_sps_pps_size = 0;
- p_sys->p_sps_pps_buf = NULL;
+ p_dec->p_sys = p_sys;
+ p_sys->i_nal_size = 4; // assume 4 byte start codes
+ p_sys->i_sps_pps_size = 0;
+ p_sys->p_sps_pps_buf = NULL;
+ p_dec->p_sys->p_pic = NULL;
+ p_dec->p_sys->proc_out = NULL;
/* Win32 code *
* We cannot link and ship BCM dll, even with LGPL license (too big)
}
#define LOAD_SYM( a ) \
- BC_FUNC( a ) = (void *)GetProcAddress(p_sys->p_bcm_dll, TEXT( #a ) ); \
- if( !BC_FUNC( a ) ) { msg_Err( p_dec, "missing symbol " # a ); return VLC_EGENERIC; }
+ BC_FUNC( a ) = (void *)GetProcAddress( p_sys->p_bcm_dll, TEXT( #a ) ); \
+ if( !BC_FUNC( a ) ) { \
+ msg_Err( p_dec, "missing symbol " # a ); return VLC_EGENERIC; }
#define LOAD_SYM_PSYS( a ) \
- p_sys->BC_FUNC( a ) = (void *)GetProcAddress(p_sys->p_bcm_dll, #a ); \
- if( !p_sys->BC_FUNC( a ) ) { msg_Err( p_dec, "missing symbol " # a ); return VLC_EGENERIC; }
+ p_sys->BC_FUNC( a ) = (void *)GetProcAddress( p_sys->p_bcm_dll, #a ); \
+ if( !p_sys->BC_FUNC( a ) ) { \
+ msg_Err( p_dec, "missing symbol " # a ); return VLC_EGENERIC; }
BC_STATUS (WINAPI *OurDtsDeviceOpen)( HANDLE *hDevice, U32 mode );
LOAD_SYM( DtsDeviceOpen );
/* Get the handle for the device */
if( BC_FUNC(DtsDeviceOpen)( &p_sys->bcm_handle,
- (DTS_PLAYBACK_MODE | DTS_LOAD_FILE_PLAY_FW | DTS_SKIP_TX_CHK_CPB ) )
- // | DTS_DFLT_RESOLUTION(vdecRESOLUTION_720p29_97) ) )
- != BC_STS_SUCCESS )
+ (DTS_PLAYBACK_MODE | DTS_LOAD_FILE_PLAY_FW | DTS_SKIP_TX_CHK_CPB) )
+ // | DTS_DFLT_RESOLUTION(vdecRESOLUTION_720p29_97) ) )
+ != BC_STS_SUCCESS )
{
msg_Err( p_dec, "Couldn't find and open the BCM CrystalHD device" );
free( p_sys );
if( BC_FUNC(DtsCrystalHDVersion)( p_sys->bcm_handle, &info ) == BC_STS_SUCCESS )
{
msg_Dbg( p_dec, "Using CrystalHD Driver version: %i.%i.%i, "
- "Library version: %i.%i.%i, "
- "Firmware version: %i.%i.%i",
- info.drvVersion.drvRelease, info.drvVersion.drvMajor, info.drvVersion.drvMinor,
- info.dilVersion.dilRelease, info.dilVersion.dilMajor, info.dilVersion.dilMinor,
- info.fwVersion.fwRelease, info.fwVersion.fwMajor, info.fwVersion.fwMinor );
+ "Library version: %i.%i.%i, Firmware version: %i.%i.%i",
+ info.drvVersion.drvRelease, info.drvVersion.drvMajor,
+ info.drvVersion.drvMinor,
+ info.dilVersion.dilRelease, info.dilVersion.dilMajor,
+ info.dilVersion.dilMinor,
+ info.fwVersion.fwRelease, info.fwVersion.fwMajor,
+ info.fwVersion.fwMinor );
}
#endif
}
/* Always use YUY2 color */
- if( BC_FUNC(DtsSetColorSpace)( p_sys->bcm_handle, OUTPUT_MODE422_YUY2 ) != BC_STS_SUCCESS )
+ if( BC_FUNC(DtsSetColorSpace)( p_sys->bcm_handle, OUTPUT_MODE422_YUY2 )
+ != BC_STS_SUCCESS )
{
msg_Err( p_dec, "Couldn't set the color space. Please report this!" );
goto error;
}
/* Open a decoder */
- if( BC_FUNC(DtsOpenDecoder)( p_sys->bcm_handle, BC_STREAM_TYPE_ES ) != BC_STS_SUCCESS )
+ if( BC_FUNC(DtsOpenDecoder)( p_sys->bcm_handle, BC_STREAM_TYPE_ES )
+ != BC_STS_SUCCESS )
{
msg_Err( p_dec, "Couldn't open the CrystalHD decoder" );
goto error;
free( p_sys );
}
+static BC_STATUS ourCallback(void *shnd, uint32_t width, uint32_t height, uint32_t stride, void *pOut)
+{
+ VLC_UNUSED(width); VLC_UNUSED(height); VLC_UNUSED(stride);
+
+ decoder_t *p_dec = (decoder_t *)shnd;
+ BC_DTS_PROC_OUT *proc_out = p_dec->p_sys->proc_out;
+ BC_DTS_PROC_OUT *proc_in = (BC_DTS_PROC_OUT*)pOut;
+
+ /* Direct Rendering */
+ /* Do not allocate for the second-field in the pair, in interlaced */
+ if( !(proc_in->PicInfo.flags & VDEC_FLAG_INTERLACED_SRC) ||
+ !(proc_in->PicInfo.flags & VDEC_FLAG_FIELDPAIR) )
+ p_dec->p_sys->p_pic = decoder_NewPicture( p_dec );
+
+ /* */
+ picture_t *p_pic = p_dec->p_sys->p_pic;
+ if( !p_pic )
+ return BC_STS_ERROR;
+
+ /* Interlacing */
+ p_pic->b_progressive = !(proc_in->PicInfo.flags & VDEC_FLAG_INTERLACED_SRC);
+ p_pic->b_top_field_first = !(proc_in->PicInfo.flags & VDEC_FLAG_BOTTOM_FIRST);
+ p_pic->i_nb_fields = p_pic->b_progressive? 1: 2;
+
+ /* Filling out the struct */
+ proc_out->Ybuff = !(proc_in->PicInfo.flags & VDEC_FLAG_FIELDPAIR) ?
+ &p_pic->p[0].p_pixels[0] :
+ &p_pic->p[0].p_pixels[p_pic->p[0].i_pitch];
+ proc_out->YbuffSz = 2 * p_pic->p[0].i_pitch;
+ proc_out->StrideSz = (proc_in->PicInfo.flags & VDEC_FLAG_INTERLACED_SRC)?
+ 2 * (p_pic->p[0].i_pitch/2) - p_dec->fmt_out.video.i_width:
+ p_pic->p[0].i_pitch/2 - p_dec->fmt_out.video.i_width;
+ proc_out->PoutFlags |= BC_POUT_FLAGS_STRIDE; /* Trust Stride info */
+
+ return BC_STS_SUCCESS;
+}
+
/****************************************************************************
* DecodeBlock: the whole thing
****************************************************************************/
BC_DTS_PROC_OUT proc_out;
BC_DTS_STATUS driver_stat;
- picture_t *p_pic;
-
/* First check the status of the decode to produce pictures */
if( BC_FUNC_PSYS(DtsGetDriverStatus)( p_sys->bcm_handle, &driver_stat ) != BC_STS_SUCCESS )
return NULL;
memset( &proc_out, 0, sizeof(BC_DTS_PROC_OUT) );
proc_out.PicInfo.width = p_dec->fmt_out.video.i_width;
proc_out.PicInfo.height = p_dec->fmt_out.video.i_height;
- proc_out.YbuffSz = p_dec->fmt_out.video.i_width * p_dec->fmt_out.video.i_height / 2;
proc_out.PoutFlags = BC_POUT_FLAGS_SIZE;
+ proc_out.AppCallBack = ourCallback;
+ proc_out.hnd = p_dec;
+ p_sys->proc_out = &proc_out;
-#ifdef DEBUG_CRYSTALHD
- msg_Dbg( p_dec, "%i, %i", p_dec->fmt_out.video.i_width, p_dec->fmt_out.video.i_height );
-#endif
-
- if( proc_out.PicInfo.width == 0 || proc_out.PicInfo.height == 0 )
- {
- /* decoder_NewPicture would fail in this case */
- proc_out.Ybuff = NULL;
- p_pic = NULL;
- }
- else
- {
- /* Direct Rendering */
- p_pic = decoder_NewPicture( p_dec );
- if( !p_pic )
- return NULL;
- proc_out.Ybuff = p_pic->p[0].p_pixels;
- proc_out.StrideSz = p_pic->p[0].i_pitch /2 - p_dec->fmt_out.video.i_width;
- proc_out.PoutFlags |= BC_POUT_FLAGS_STRIDE; /* trust Stride info */
- }
-
+ /* */
BC_STATUS sts = BC_FUNC_PSYS(DtsProcOutput)( p_sys->bcm_handle, 128, &proc_out );
#ifdef DEBUG_CRYSTALHD
if( sts != BC_STS_SUCCESS )
#endif
uint8_t b_eos;
+ picture_t *p_pic = p_sys->p_pic;
switch( sts )
{
case BC_STS_SUCCESS:
if( !p_pic )
break;
+ /* In interlaced mode, do not push the first field in the pipeline */
+ if( (proc_out.PicInfo.flags & VDEC_FLAG_INTERLACED_SRC) &&
+ !(proc_out.PicInfo.flags & VDEC_FLAG_FIELDPAIR) )
+ return NULL;
+
// crystal_CopyPicture( p_pic, &proc_out );
- p_pic->date = proc_out.PicInfo.timeStamp > 0 ? FROM_BC_PTS(proc_out.PicInfo.timeStamp) : VLC_TS_INVALID;
+ p_pic->date = proc_out.PicInfo.timeStamp > 0 ?
+ FROM_BC_PTS(proc_out.PicInfo.timeStamp) : VLC_TS_INVALID;
//p_pic->date += 100 * 1000;
#ifdef DEBUG_CRYSTALHD
msg_Dbg( p_dec, "TS Output is %"PRIu64, p_pic->date);
#endif
- // free( proc_out.Ybuff );
return p_pic;
case BC_STS_DEC_NOT_OPEN:
p_dec->fmt_out.video.i_height = proc_out.PicInfo.height;
if( proc_out.PicInfo.height == 1088 )
p_dec->fmt_out.video.i_height = 1080;
-#define setAR( a, b, c ) case a: p_dec->fmt_out.video.i_sar_num = b; p_dec->fmt_out.video.i_sar_den = c; break;
+#define setAR( a, b, c ) case a: p_dec->fmt_out.video.i_sar_num = b; \
+ p_dec->fmt_out.video.i_sar_den = c; break;
switch( proc_out.PicInfo.aspect_ratio )
{
setAR( vdecAspectRatioSquare, 1, 1 )
#undef setAR
msg_Dbg( p_dec, "Format Change Detected [%i, %i], AR: %i/%i",
proc_out.PicInfo.width, proc_out.PicInfo.height,
- p_dec->fmt_out.video.i_sar_num, p_dec->fmt_out.video.i_sar_den );
+ p_dec->fmt_out.video.i_sar_num,
+ p_dec->fmt_out.video.i_sar_den );
break;
/* Nothing is documented here... */
case BC_STS_NO_DATA:
- if( BC_FUNC_PSYS(DtsIsEndOfStream)( p_sys->bcm_handle, &b_eos ) == BC_STS_SUCCESS )
+ if( BC_FUNC_PSYS(DtsIsEndOfStream)( p_sys->bcm_handle, &b_eos )
+ == BC_STS_SUCCESS )
if( b_eos )
msg_Dbg( p_dec, "End of Stream" );
break;
p_dst_end = p_dst + (i_dst_stride * p_out->PicInfo.height);
for( ; p_dst < p_dst_end; p_dst += i_dst_stride, p_src += (p_out->PicInfo.width * 2))
- vlc_memcpy( p_dst, p_src, p_out->PicInfo.width * 2); // Copy in bytes
+ memcpy( p_dst, p_src, p_out->PicInfo.width * 2); // Copy in bytes
}
#endif
/* Parse the SPS/PPS Metadata to feed the decoder for avc1 */
-static int crystal_insert_sps_pps(decoder_t *p_dec, uint8_t *p_buf, uint32_t i_buf_size)
+static int crystal_insert_sps_pps( decoder_t *p_dec,
+ uint8_t *p_buf,
+ 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;
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;
-
- 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;
+ 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;
- 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;
}