/*************************************************************************** * Copyright (c) 2003-2006, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: * * Revision History: * * $brcm_Log: $ * ***************************************************************************/ #include "bsettop_decode.h" #include "bsettop_p_stream.h" #ifdef CONFIG_EIA_708 #include "bvbilib.h" #include "bvbilib_dccparse.h" #endif #include "gist.h" #ifndef NO_VCHIP #include "xds_ctrl.h" #endif #include "bos_task_priorities.h" #include "bkni_multi.h" #include "ts_psi.h" /* Included for PMT stream type definitions */ BDBG_MODULE(decode); bool g_disable_fcc = false; #define VBI_CC_DATA_TIMEOUT (30 * 1000) /* 30 seconds */ #ifdef CONFIG_EIA_708 extern bresult bdisplay_vbi_clear_cc(void); extern bresult vbi_cc_write_isr(const unsigned char* ccData, size_t length); #endif #ifdef BCM_DEBUG #define INIT_CHECK(a) \ { \ BDBG_MSG((#a " - Enter\n")); \ if (a != BERR_SUCCESS) \ { \ BDBG_ERR((#a " #### failed in %s:%d\n",__FUNCTION__,__LINE__)); \ goto failed; \ } \ BDBG_MSG((#a " - Exit\n")); \ } #else /* BCM_DEBUG */ #define INIT_CHECK(x) if (x != BERR_SUCCESS) goto failed #endif #define MAX_TRIPLETS (0x1F * 3) #define DECWD_TASK_STACK 0x100 /* changed from 0x400 */ struct bdecode { bool initialized; bool first_pts_pending; bool seq_pending; unsigned int start_ticks; bdecode_status status; bdecode_config config; BAVC_XptContextMap videoCtxMap; b_mutex_t mutex; bstream_t stream; BXVD_Userdata_Handle userDataHandle; unsigned char triplets[MAX_TRIPLETS]; bool b708cc; int cc608_format; unsigned int cc708_timeout; /* reset b708cc if no 708 data for giving timeout time */ #ifndef NO_VCHIP xds_ctrl_t xds_ctrl; #endif unsigned int vbi_cc_data_ticks; /* keep tracking vbi cc data timing */ bool vbi_cc_data; /* true if we have vbi cc data went to vbi encoder */ bool bypass_tsm; /* flag to bypass TSM mode if video is H.264 to show video as long as got the GOP */ BKNI_EventHandle wdEvent; b_task_params task_params; b_task_t task_h; unsigned int task_stack[DECWD_TASK_STACK]; }; #define DECODE_MUTEX_TIMEOUT 1000 #define DEF_708CC_TIMEOUT_MS 5000 static struct bdecode s_decode = { false, false, false, 0, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,false,false,false,false,0}, { NULL, NULL, NULL, NULL, NULL,0,0,0,0,0,0,0,{0, 0}, {NULL, NULL}}, { 0,0,0,0,0,0,0,0,0,0,0,0}, { 0,0,0}, NULL, }; b_mutex_t *s_p_mutex = NULL; /** Summary: Supported audio and video formats */ const bsettop_av_stream_type_t s_video_stream_types[] = { { TS_PSI_ST_13818_2_Video, BAVC_VideoCompressionStd_eMPEG2, 0,"MPEG-2"}, { TS_PSI_ST_ATSC_Video, BAVC_VideoCompressionStd_eMPEG2, 0,"MPEG-2"}, { TS_PSI_ST_AVS_Video, BAVC_VideoCompressionStd_eAVS, 0,"AVS"}, { TS_PSI_ST_14496_10_Video, BAVC_VideoCompressionStd_eH264, 0,"H.264"}, { TS_PSI_ST_SMPTE_VC1, BAVC_VideoCompressionStd_eVC1, 0,"VC1"}, { TS_PSI_ST_14496_2_Video, BAVC_VideoCompressionStd_eMPEG4Part2, 0,"MP4p2"} }; const int s_video_stream_types_num = sizeof(s_video_stream_types)/sizeof(s_video_stream_types[0]); /** Summary: Supported video format. Returns NULL if stream_type (from PMT) not supported. **/ bsettop_av_stream_type_t *bdecode_supported_video(unsigned char stream_type) { int i; for (i = 0; i < s_video_stream_types_num; ++i) { if (stream_type == s_video_stream_types[i].format) { BDBG_MSG(("Video format[0x%02x]: %s\n",s_video_stream_types[i].format,s_video_stream_types[i].format_name)); return(bsettop_av_stream_type_t*)&s_video_stream_types[i]; } } BDBG_MSG(("Unsupported Video format[0x%02x]\n",stream_type)); return NULL; } static void bdecode_watchdog_task(void *arg); #define dcc_CheckParity(b) (!((b) & 0x80)) /************************************************************************** * * * * Function: ConvertParity * * * * Inputs: * * in - input byte * * * * Outputs: * * * * Returns: converted byte * * * * Description: * * * * ConvertParity() examines the input byte and determines whether or * * not it has a parity error, based on ODD parity. The upper bit is * * converted from the parity bit to the parity error bit, meaning the * * high bit of the output byte is 1 iff there was a parity error on the * * input byte. * * * **************************************************************************/ unsigned char dcc_608_P_ConvertParity(unsigned char in) { static unsigned char ParityErrorArray[] = {1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1} ; unsigned char temp = ((in & 0x0F) ^ (in >> 4)) ; return((ParityErrorArray[temp]<<7) | (in&0x7F)) ; } #ifdef CONFIG_EIA_708 /**************************************************************** * * INPUTS: pointer to cc data1, and cc data 2, scte_20 (DVS157), scte_21 (DVS053) or ATSC53 flag * * OUTPUTS: modified cc data if any * * RETURNS: true if ignore the pair, false good for encoding * * FUNCTION: check ctrl pair to filter out bad pair or redundant pair * ****************************************************************/ bool dcc_check_ctrl_pair(size_t *cc1, size_t *cc2, int format) { static unsigned char LastB1[3], LastB2[3]; static bool bLastPairWasCtrl[3] = { false, false }; int fmt; unsigned char b1, b2; bool bThisPairWasCtrl[3]; bool bIgnore = false; if (format == BVBIlib_DCCparse_Format_DVS053) fmt = 0; /* SCTE 21 */ else if (format == BVBIlib_DCCparse_Format_DVS157) fmt = 1; /* SCTE 21 */ else if (format == BVBIlib_DCCparse_Format_ATSC53) fmt = 2; /* ATSC 53 */ else { BDBG_WRN(("%s: format %d not supported", __func__, format)); return false; } /* * * ConvertParity converts bit 7 from * * parity_bit to parity_error * */ b1 = dcc_608_P_ConvertParity(*cc1); b2 = dcc_608_P_ConvertParity(*cc2); bThisPairWasCtrl[fmt] = false; if ( !dcc_CheckParity(b1) ) { /* if 1st fails parity, ignore pair */ BDBG_MSG(("1st failes parity, ignore")) ; bIgnore = true; } else { if (0x14 == (b1 & 0x7f) || 0x1c == (b1 & 0x7f)) { BDBG_MSG(("%d 0x%02x 0x%02x, lb1=%02x, lb2=%02x", fmt ? 20 : 21, b1, b2, LastB1[fmt], LastB2[fmt])) ; if ( !dcc_CheckParity(b2) ) { /* if 2nd fails parity, ignore pair */ BDBG_MSG(("2nd failes parity, ignore")) ; bIgnore = true; } else { bThisPairWasCtrl[fmt] = true; /* currently we just check EOC */ if ((b2 == LastB2[fmt]) && (b1 == LastB1[fmt]) && (0x2f == b2)) { BDBG_MSG(("lastCtrl=%d, redundant 0x%02x 0x%02x", bLastPairWasCtrl[fmt], b1, b2)) ; bIgnore = true; } } } } if ( bThisPairWasCtrl[fmt] ) { LastB1[fmt] = b1; LastB2[fmt] = b2; } bLastPairWasCtrl[fmt] = bThisPairWasCtrl[fmt]; return bIgnore; } #endif #if SUPPORT_DST_PLATFORM BXVD_PictureParameterInfo* s_PrevStreamInfo; // last seqhdr info bdecode_callback_t s_userdata_callback = NULL; bdecode_callback_t s_vec_isr_callback= NULL; bdecode_callback_t s_seq_hdr_callback= NULL; bdecode_callback_t s_picture_isr_callback= NULL; bdecode_callback_t s_video_err_callback= NULL; bdecode_callback_t bdecode_register_callback(enum bdecode_callback_type type, bdecode_callback_t fn) { // cafrii 081212 add check whether fn is same as old one. // print error msg and return null unsigned int flag; bdecode_callback_t oldcb = NULL; flag = bos_enter_critical(); switch (type) { #if 1 case bdecode_callback_type_userdata: if (s_userdata_callback == fn) goto err; oldcb = s_userdata_callback; s_userdata_callback = fn; break; #endif case bdecode_callback_type_vec_isr: if (s_vec_isr_callback == fn) goto err; oldcb = s_vec_isr_callback; s_vec_isr_callback = fn; break; #if 0 case bdecode_callback_type_seq_hdr_isr: if (s_seq_hdr_callback == fn) goto err; oldcb = s_seq_hdr_callback; s_seq_hdr_callback = fn; break; #endif case bdecode_callback_type_picture_isr: if (s_picture_isr_callback == fn) goto err; oldcb = s_picture_isr_callback; s_picture_isr_callback = fn; break; case bdecode_callback_type_video_err: if (s_video_err_callback == fn) goto err; oldcb = s_video_err_callback; s_video_err_callback = fn; break; } goto end; err: BDBG_ERR(("%s: callback type %d: fn 0x%x is same as prev one\n", __func__, type, fn)); end: bos_exit_critical(flag); return oldcb; } static unsigned char s_StreamInfoReceived = 1; static unsigned char s_CaptionInfoReceived = 1; static unsigned char s_MonitorFieldInfoChange; // each bit corresponds to BAVC_Polarity value. // BAVC_Polarity_eTopField => bit 0, 0x1 // BAVC_Polarity_eBotField => bit 1, 0x2 /* WARNING!! this query should be used just after sequence header callback is called. do not use in arbitrary time. returned BMVD_StreamInfo may not be same as last sequence header event info. */ BXVD_PictureParameterInfo *bdecode_get_stream_info(BXVD_PictureParameterInfo *status) { if (s_StreamInfoReceived) { uint32_t flag = bos_enter_critical(); status = s_PrevStreamInfo; bos_exit_critical(flag); return s_PrevStreamInfo; } return NULL; } #endif // SUPPORT_DST_PLATFORM /** Summary: XVD Video decoder watchdog handler. **/ void VideoDecoderWatchdog_isr(void *pParm1, int parm2, void *pXVD_data) { bdecode_t decode = (bdecode_t)pParm1; BDBG_ASSERT(decode); BDBG_ERR(("BXVD_ProcessWatchdog being called!!!")); BKNI_SetEvent(decode->wdEvent); decode->status.watchdog_cnt++; } /** Summary: XVD Video decoder PTS error handler. **/ void VideoDecoder_PtsError_isr(void *data, int unused, void *pts_info) { bdecode_t decode = (bdecode_t)data; BXVD_PTSInfo *pPts = (BXVD_PTSInfo *)pts_info; unsigned int stc; BDBG_ASSERT(pts_info); BDBG_ASSERT(decode); BDBG_ASSERT(decode->stream); BDBG_ASSERT(decode->stream->hPcrOffset); BSTD_UNUSED(unused); BSTD_UNUSED(pPts); stc = BXPT_PcrOffset_GetStc_isr(decode->stream->hPcrOffset) + BXPT_PcrOffset_GetOffset_isr(decode->stream->hPcrOffset); BDBG_MSG(("VideoDecoder_PtsError_isr pts = %x, stc = %x, offset = %x", pPts->ui32RunningPTS,stc,pPts->uiPCROffset)); bstream_p_pcroffset_update(decode->stream); decode->status.pts_err_cnt++; } /** Summary: XVD Video decoder PTS error handler. **/ void VideoDecoder_RequestStc_isr(void *data, int unused, void *pts_info) { bdecode_t decode = (bdecode_t)data; BXVD_PTSInfo *pPts = (BXVD_PTSInfo *)pts_info; unsigned int stc; BDBG_ASSERT(pts_info); BDBG_ASSERT(decode); BDBG_ASSERT(decode->stream); BDBG_ASSERT(decode->stream->hPcrOffset); BSTD_UNUSED(unused); BSTD_UNUSED(pPts); stc = BXPT_PcrOffset_GetStc_isr(decode->stream->hPcrOffset) + BXPT_PcrOffset_GetOffset_isr(decode->stream->hPcrOffset); BDBG_MSG(("VideoDecoder_RequestStc_isr pts = %x, stc = %x, offset = %x", pPts->ui32RunningPTS,stc,pPts->uiPCROffset)); bstream_p_pcroffset_update(decode->stream); decode->status.req_stc_cnt++; } /** Summary: XVD Video decoder PTS error handler. **/ void VideoDecoder_FirstPtsPassed_isr(void *data, int unused, void *pts_info) { bdecode_t decode = (bdecode_t)data; BXVD_PTSInfo *pPts = (BXVD_PTSInfo *)pts_info; unsigned int stc; BDBG_ASSERT(pts_info); BDBG_ASSERT(decode); BDBG_ASSERT(decode->stream); BDBG_ASSERT(decode->stream->hPcrOffset); BSTD_UNUSED(unused); BSTD_UNUSED(pPts); stc = BXPT_PcrOffset_GetStc_isr(decode->stream->hPcrOffset) + BXPT_PcrOffset_GetOffset_isr(decode->stream->hPcrOffset); BDBG_MSG(("VideoDecoder_FirstPtsPassed_isr pts = %x, stc = %x, offset = %x", pPts->ui32RunningPTS,stc,pPts->uiPCROffset)); decode->status.first_pts_cnt++; if (decode->first_pts_pending) { decode->first_pts_pending = false; decode->status.first_pts_ticks = bos_getticks()-decode->start_ticks; if (s_decode.config.first_pts_callback) { s_decode.config.first_pts_callback(); } } } /** Summary: XVD Video decoder PTS error handler. **/ void VideoDecoder_PtsStcOffset_isr(void *data, int unused, void *offset) { uint32_t uiOffset; bdecode_t decode = (bdecode_t)data; BDBG_ASSERT(offset); BDBG_ASSERT(decode); BSTD_UNUSED(data); BSTD_UNUSED(unused); uiOffset = *(uint32_t*)offset; BDBG_MSG(("VideoDecoder_PtsStcOffset_isr offset = %x", uiOffset)); decode->status.offset_cnt++; } /** Summary: XVD Video decoder picture info isr. **/ void VideoDecoder_PictureParams_isr(void *data, int unused, void *info) { bdecode_t decode = (bdecode_t)data; BXVD_PictureParameterInfo *picInfo = (BXVD_PictureParameterInfo *)info; BDBG_ASSERT(decode); BDBG_ASSERT(picInfo); BSTD_UNUSED(unused); #if SUPPORT_DST_PLATFORM//BKTEMP s_PrevStreamInfo = (BXVD_PictureParameterInfo *)info; #endif decode->status.bFrameProgressive = picInfo->bFrameProgressive; decode->status.bStreamProgressive = picInfo->bStreamProgressive; decode->status.display_width = picInfo->ulDisplayHorizontalSize; decode->status.display_height = picInfo->ulSourceVerticalSize; decode->status.hPanScan = picInfo->i32_HorizontalPanScan; decode->status.source_height = picInfo->ulSourceVerticalSize; decode->status.source_width = picInfo->ulSourceHorizontalSize; decode->status.video_aspect_ratio = picInfo->eAspectRatio; decode->status.video_format = picInfo->uiVideoFormat; decode->status.video_framerate = picInfo->eFrameRateCode; decode->status.vPanScan = picInfo->i32_VerticalPanScan; decode->status.bitRate = picInfo->uiBitRate; decode->status.profile = picInfo->uiProfile; decode->status.level = picInfo->uiLevel; decode->status.pic_info_cnt++; if (decode->seq_pending) { decode->seq_pending = false; decode->status.seq_ticks = bos_getticks()-decode->start_ticks; if (s_decode.config.seq_hdr_callback) { s_decode.config.seq_hdr_callback(); } #if SUPPORT_DST_PLATFORM if(s_seq_hdr_callback) { s_seq_hdr_callback(bdecode_callback_type_seq_hdr_isr, NULL); } #endif if (decode->bypass_tsm) { BXVD_SetVideoDisplayMode(GetXVDCh(), BXVD_DisplayMode_eTSMMode);//jglee 2014.05.08 BXVD_DisplayMode_eTSMMode - > BXVD_DisplayMode_eVSYNCMode decode->bypass_tsm = false; } } if (s_decode.vbi_cc_data && ((s_decode.vbi_cc_data_ticks + MS_TO_TICKS(VBI_CC_DATA_TIMEOUT) < bos_getticks()))) { s_decode.vbi_cc_data = false; #ifdef CONFIG_EIA_708 bdisplay_vbi_clear_cc(); #endif } } /** Summary: XVD Video decoder picture info isr. **/ void VideoDecoder_DecodeError_isr(void *data, int unused, void *info) { bdecode_t decode = (bdecode_t)data; BDBG_ASSERT(decode); decode->status.decode_err_cnt++; } /** Summary: XVD Video decoder TSM result handler **/ void VideoDecoder_TSMResult_isr(void *data, int unused, void *info) { BXDM_PictureProvider_TSMInfo *pTSMInfo = (BXDM_PictureProvider_TSMInfo *)info; BDBG_ASSERT(pTSMInfo); BSTD_UNUSED(data); BSTD_UNUSED(unused); BDBG_MSG(("TSMResult=%d", pTSMInfo->eTSMResult)); switch (pTSMInfo->eTSMResult) { case BXDM_PictureProvider_TSMResult_eTooLate: pTSMInfo->ePictureHandlingMode = BXDM_PictureProvider_PictureHandlingMode_eDrop; break; default: pTSMInfo->ePictureHandlingMode = BXDM_PictureProvider_PictureHandlingMode_eDefault; break; } } /* Summary: Use VBI lib to parse userdata */ #ifdef CONFIG_EIA_708 #define B_MAX_VBI_CC_COUNT 32 /* required by VBIlib */ /* to reorder UserData since some ATSC53 userdata encoder messed up field order */ static void Reorder_UserData(BVBIlib_DCCparse_ccdata ccData[], int i) { BVBIlib_DCCparse_ccdata ccTmp; if (i < (B_MAX_VBI_CC_COUNT - 4)) { if ((ccData[i].polarity == ccData[i + 1].polarity) && (ccData[i + 2].polarity == ccData[i + 3].polarity) && (ccData[i].polarity != ccData[i + 2].polarity) && (ccData[i + 2].polarity < 2)) { ccTmp = ccData[i + 1]; ccData[i + 1] = ccData[i + 2]; ccData[i + 2] = ccTmp; } } } static void ParseUserdata_isr(bdecode_t decode, const BAVC_USERDATA_info *info) { uint32_t offset = 0; int triplet_cnt = 0; int vbi_cnt = 0; static uint8_t vbi_data[100]; BDBG_MSG(("ParseUserdata %d:%d:%#x:%d:%d", info->eUserDataType, info->ui32UserDataBufSize, (unsigned)info->pUserDataBuffer, info->bTopFieldFirst, info->bRepeatFirstField)); #if SUPPORT_DST_PLATFORM if(s_userdata_callback) { s_userdata_callback(bdecode_callback_type_userdata, NULL); } #endif while (offset < info->ui32UserDataBufSize) { BERR_Code rc; unsigned i; size_t bytesParsed = 0; uint8_t ccCount = 0; BVBIlib_DCCparse_ccdata ccData[B_MAX_VBI_CC_COUNT]; /* TODO: The BVBIlib_DCCparse functions should be _isr. They should also be refactored out of VBIlib. VBIlib is a syslib which is owned by the Display module. It should not be called from VideoDecoder. */ if (decode->stream->mpeg.video[0].format == BAVC_VideoCompressionStd_eH264) { rc = BVBIlib_DCCparse_SEI(info, offset, &bytesParsed, &ccCount, ccData); } #if 0 else if (videoDecoder->transportType == BAVC_VideoCompressionStd_eMPEG2DTV) { /* only applies to DSS ES (SD), not DSS PES (HD) */ rc = BVBIlib_DCCparse_DSS(info, offset, &bytesParsed, &ccCount, ccData); } #endif else { rc = BVBIlib_DCCparse(info, offset, &bytesParsed, &ccCount, ccData); } /* VBIlib takes pointer w/o size, so this must be true. Otherwise we have overflow, from which there is no recovery. */ BDBG_ASSERT(ccCount <= B_MAX_VBI_CC_COUNT); if (bytesParsed==0) { /* we aren't going anywhere */ break; } offset += bytesParsed; /* We process bytesParsed even with error code. seems a bit dangerous. */ if (rc == BERR_BVBIlib_PARSE_ERROR) { break; } else if (rc != BERR_SUCCESS) { continue; } for (i=0;icc608_format = ccData[i].format; } /* discard DVS157 CC data if ATSC53 CC presents, please check s_mpegParsers for the array order */ if (ccData[i].format < decode->cc608_format) continue; /* discard other formats that not supported, NOTE that the AFD was handled by our code already */ /* TODO confirm if we need to support DVS053? */ if (ccData[i].format > BVBIlib_DCCparse_Format_DVS053) continue; /* pass to VBI encoder */ if (ccData[i].cc_valid) { size_t cc1, cc2; #ifndef ACB612 if (ccData[i].format == BVBIlib_DCCparse_Format_ATSC53) { if (0 == i) { Reorder_UserData(ccData, i); } } #endif cc1 = ccData[i].cc_data_1; cc2 = ccData[i].cc_data_2; #ifndef ACB612 if (dcc_check_ctrl_pair(&cc1, &cc2, ccData[i].format)) { BDBG_MSG(("%s not good Ctrl Code, drop",__func__)); continue; } #endif /* don't encode empty data? */ if (0x80 == cc1 && 0x80 == cc2) continue; vbi_data[vbi_cnt] = (ccData[i].polarity == BAVC_Polarity_eTopField)?0:1; vbi_data[vbi_cnt+1] = (unsigned char)cc1; vbi_data[vbi_cnt+2] = (unsigned char)cc2; vbi_cnt+=3; #ifndef NO_VCHIP if (ccData[i].polarity == BAVC_Polarity_eBotField) { xds_ctrl_feed(&s_decode.xds_ctrl, ccData[i].cc_data_1&0x7F, ccData[i].cc_data_2&0x7F); } #endif } /* 608 triplet will be rendered only when program doesn't have 708 cc */ if (decode->b708cc == false) { if ((ccData[i].cc_valid) && ((triplet_cnt + 3) < MAX_TRIPLETS)) { s_decode.triplets[triplet_cnt] = (ccData[i].polarity==BAVC_Polarity_eTopField) ? 0 : 1; s_decode.triplets[triplet_cnt + 1] = ccData[i].cc_data_1; s_decode.triplets[triplet_cnt + 2] = ccData[i].cc_data_2; triplet_cnt += 3; } else { /* don't send invalid 608 data */ } } else { if (bos_getticks() > decode->cc708_timeout) { if (triplet_cnt) { /* post current data before new data that is different */ if (s_decode.config.cc_callback && s_decode.config.cc_enabled) { s_decode.config.cc_callback((unsigned char*)s_decode.triplets,triplet_cnt, decode->b708cc?false:true); } } decode->b708cc = false; triplet_cnt = 0; } } } else { /* primary CC is 708 */ /* discard DCC data if not valid */ if (!ccData[i].cc_valid) { if (0 == ccData[i].cc_data_1 && 0 == ccData[i].cc_data_2) continue; } if (decode->b708cc == false) { /* if has left over from 608 data */ if (triplet_cnt) { /* post current data before new data that is different */ if (s_decode.config.cc_callback && s_decode.config.cc_enabled) { s_decode.config.cc_callback((unsigned char*)s_decode.triplets,triplet_cnt, decode->b708cc?false:true); } } /* 708cc is detected. clear the 608cc */ triplet_cnt = 0; decode->b708cc = true; } /* tracking 708cc timeout */ decode->cc708_timeout = bos_getticks() + MS_TO_TICKS(DEF_708CC_TIMEOUT_MS); if ((triplet_cnt + 3) < MAX_TRIPLETS) { s_decode.triplets[triplet_cnt] = ccData[i].seq.cc_type; s_decode.triplets[triplet_cnt + 1] = ccData[i].cc_data_1; s_decode.triplets[triplet_cnt + 2] = ccData[i].cc_data_2; triplet_cnt += 3; } else { BDBG_WRN(("%s triplet overflow\n",__FUNCTION__)); } } } if (s_decode.config.cc_callback && s_decode.config.cc_enabled && (triplet_cnt > 0)) { s_decode.config.cc_callback((unsigned char*)s_decode.triplets,triplet_cnt, decode->b708cc?false:true); } if ((vbi_cnt>0)&&(!s_decode.config.block_vbi)) { //if ((info->bTopFieldFirst && vbi_data[0] != 0) && (BAVC_VideoCompressionStd_eH264 != decode->stream->mpeg.video[0].format) // && (BVBIlib_DCCparse_Format_ATSC53 != decode->cc608_format)) { if (0) { continue; } else { if (BERR_SUCCESS != vbi_cc_write_isr(vbi_data, vbi_cnt/3)) { BDBG_WRN(("%s vbi_cc_write_isr failed\n",__func__)); } else { s_decode.vbi_cc_data_ticks = bos_getticks(); s_decode.vbi_cc_data = true; } } } } return; } /* Summary: User data callback */ void UserdataReady_isr(void *data, int unused, void *not_used) { BERR_Code rc = BXVD_ERR_USERDATA_NONE; BAVC_USERDATA_info info; bdecode_t decode = (bdecode_t)data; BSTD_UNUSED(unused); BSTD_UNUSED(not_used); for ( ;; ) { /* TODO: reduce XVD userdata buffer size because we evacuate XVD at isr time */ /* get data */ rc = BXVD_Userdata_Read_isr(decode->userDataHandle, &info); if ( rc==BXVD_ERR_USERDATA_NONE ) { break; } else if ( rc==BXVD_ERR_USERDATA_INVALID ) { continue; /* keep reading data */ } else if ( rc!=BERR_SUCCESS ) { BDBG_ERR(("BXVD_Userdata_Read_isr returned error %#x, ignore", rc)); break; } /* parse and send data to VideoInput (in Display module) */ /* process CC/VCHIP data even though cc is disabled, DIG-D04 */ // if (decode->config.cc_callback && decode->config.cc_enabled) { ParseUserdata_isr(decode, &info); } } } #endif /* CONFIG_EIA_708 */ /* Summary: Open a decode engine. Description: */ bdecode_t bdecode_open( bobject_t decode_id /* decode object id */ ) { if (s_decode.initialized) { return(bdecode_t)0; } if (bos_create_mutex(&(s_decode.mutex)) != b_ok) { return(bdecode_t)0; } s_p_mutex = &(s_decode.mutex); s_decode.task_params.name="vdecode"; s_decode.task_params.priority = DECWD_PRIORITY; s_decode.task_params.stack_size = DECWD_TASK_STACK; s_decode.task_params.stack = s_decode.task_stack; INIT_CHECK(BXVD_InstallDeviceInterruptCallback(GetXVD(), BXVD_DeviceInterrupt_eWatchdog, VideoDecoderWatchdog_isr, &s_decode, 0)); INIT_CHECK(BXVD_InstallInterruptCallback(GetXVDCh(), BXVD_Interrupt_ePTSError, VideoDecoder_PtsError_isr, &s_decode, 0)); INIT_CHECK(BXVD_InstallInterruptCallback(GetXVDCh(), BXVD_Interrupt_eFirstPTSPassed, VideoDecoder_FirstPtsPassed_isr, &s_decode, 0)); INIT_CHECK(BXVD_InstallInterruptCallback(GetXVDCh(), BXVD_Interrupt_ePtsStcOffset, VideoDecoder_PtsStcOffset_isr, &s_decode, 0)); INIT_CHECK(BXVD_InstallInterruptCallback(GetXVDCh(), BXVD_Interrupt_ePictureParameters, VideoDecoder_PictureParams_isr, &s_decode, 0)); INIT_CHECK(BXVD_InstallInterruptCallback(GetXVDCh(), BXVD_Interrupt_eDecodeError, VideoDecoder_DecodeError_isr, &s_decode, 0)); INIT_CHECK(BXVD_InstallInterruptCallback(GetXVDCh(), BXVD_Interrupt_eClipStart, VideoDecoder_FirstPtsPassed_isr, &s_decode, 0)); INIT_CHECK(BXVD_InstallInterruptCallback(GetXVDCh(), BXVD_Interrupt_eRequestSTC, VideoDecoder_RequestStc_isr, &s_decode, 0)); INIT_CHECK(BXVD_InstallInterruptCallback(GetXVDCh(), BXVD_Interrupt_eTSMResult, VideoDecoder_TSMResult_isr, &s_decode, 0)); INIT_CHECK(BXVD_Userdata_Open(GetXVDCh(), &(s_decode.userDataHandle), NULL)); #ifdef CONFIG_EIA_708 INIT_CHECK(BXVD_Userdata_InstallInterruptCallback(s_decode.userDataHandle, (BINT_CallbackFunc)UserdataReady_isr, &(s_decode), 0)); BXVD_Userdata_Enable(s_decode.userDataHandle,true); #endif #ifndef NO_VCHIP xds_ctrl_init(&s_decode.xds_ctrl); #endif BKNI_CreateEvent(&(s_decode.wdEvent)); bos_start_task(&(s_decode.task_h),&(s_decode.task_params),bdecode_watchdog_task,&s_decode); s_decode.initialized = true; return(bdecode_t)&s_decode; failed: return(bdecode_t)0; } /* Summary: Close a decode engine. Description: The decode should be stopped before closing. After closing, the bdecode_t handle is invalid. */ void bdecode_close( bdecode_t decode /* handle returned by bdecode_open */ ){ BDBG_ASSERT(decode); if (s_decode.userDataHandle) { BXVD_Userdata_Close(s_decode.userDataHandle); s_decode.userDataHandle = NULL; } if (decode->initialized) { bos_delete_mutex(&(decode->mutex)); } bos_stop_task(decode->task_h); BKNI_DestroyEvent(decode->wdEvent); decode->initialized = false; } /* Summary: Start decoding a stream. */ bresult bdecode_start( bdecode_t decode, /* handle returned by bdecode_open */ bstream_t source, /* source for the decode, either analog or digital */ bdecode_window_t window /* window to render decode */ ){ BERR_Code err; BXVD_DecodeSettings decodeSettings; long lDisplayOffsetValue; BDBG_ASSERT(decode); BDBG_ASSERT(source); BDBG_ASSERT(source->hRaveCx); if (decode->status.bVideoDecoding) { bdecode_stop(decode); } #ifdef CONFIG_EIA_708 decode->b708cc = false; decode->cc608_format = BVBIlib_DCCparse_Format_DVS157; #endif /* clear vbi cc data flag */ decode->vbi_cc_data = false; err = BERR_OS_ERROR; if (bos_acquire_mutex(s_p_mutex,DECODE_MUTEX_TIMEOUT) == b_ok) { decode->stream = source; BDBG_MSG(("%s codec id = %d\n",__FUNCTION__,decode->stream->mpeg.video[0].format)); err = BXVD_GetDecodeDefaultSettings(GetXVDCh(), &decodeSettings); decodeSettings.eVideoCmprStd = decode->stream->mpeg.video[0].format; /* Mpeg2 or AVC */ decodeSettings.ulMultiStreamId = 0; decodeSettings.ulVideoSubStreamId = 0; decodeSettings.bCrcMode = false; decodeSettings.bPlayback = false; decodeSettings.stDataXprtOutput.eXptOutputId = BAVC_XptOutputId_eParserBand0; decodeSettings.stDataXprtOutput.eXptSourceId = BAVC_XptOutputId_eParserBand0; decodeSettings.eTimeBase = BAVC_Timebase_e0; err = bstream_p_get_rave_context_map(decode->stream,&(decode->videoCtxMap)); BDBG_ASSERT(err == BERR_SUCCESS); decodeSettings.pContextMap = &(decode->videoCtxMap); bstream_p_pcroffset_pid_ch_config(decode->stream, decode->stream->pid_ch); err = bstream_p_attach_rave(decode->stream,true); if (err != BERR_SUCCESS) { BDBG_ERR(("%s bstream_p_attach_rave failed %d\n",__FUNCTION__,err)); } //ccmode = BXVD_ChannelChangeMode_eLastFramePreviousChannel; //decode->config.channel_change = BXVD_ChannelChangeMode_eLastFramePreviousWithFirstPicturePreview; decode->config.channel_change = BXVD_ChannelChangeMode_eMute; BXVD_SetChannelChangeMode(GetXVDCh(), decode->config.channel_change); //BXVD_SetVideoDisplayMode(GetXVDCh(),BXVD_DisplayMode_eTSMMode); //BXVD_SetVideoDisplayMode(GetXVDCh(),BXVD_DisplayMode_eVSYNCMode); /* note that BXVD_ChannelChangeMode_eLastFramePreviousWithFirstPicturePreview seems not work well for H.264 preview */ /* currently just for H.264 stream to force first picture preview on H.264 stream */ if (decode->stream->mpeg.video[0].format == BAVC_VideoCompressionStd_eH264) { BXVD_SetVideoDisplayMode(GetXVDCh(),BXVD_DisplayMode_eVSYNCMode); decode->bypass_tsm = true; } else { //RLQ, to display video for sake of channel change time BXVD_SetVideoDisplayMode(GetXVDCh(),BXVD_DisplayMode_eTSMMode); decode->bypass_tsm = true; } if (g_disable_fcc) { bstream_p_rave_enable(decode->stream,false); bstream_p_rave_flush(decode->stream); } err = BXVD_StartDecode(GetXVDCh(), &decodeSettings); if (err != BERR_SUCCESS) { bstream_p_rave_enable(decode->stream,false); bstream_p_rave_flush(decode->stream); bos_release_mutex(s_p_mutex); BXVD_ProcessWatchdog(GetXVD()); if (bos_acquire_mutex(s_p_mutex,DECODE_MUTEX_TIMEOUT) != b_ok) { BDBG_ERR(("%s bos_acquire_mutex failed\n",__FUNCTION__)); } err = BXVD_StartDecode(GetXVDCh(), &decodeSettings); } if (err == BERR_SUCCESS) { decode->status.bVideoDecoding = true; decode->first_pts_pending = true; decode->seq_pending = true; //megakiss 2014.05.08 first video still true->false // jglee 2014.05.08 false -> true decode->start_ticks = bos_getticks(); bstream_p_rave_enable(decode->stream,true); bstream_pcroffset_config_context(decode->stream); #if 0 err = BXVD_GetDisplayOffset(GetXVDCh(), &lDisplayOffsetValue); if (BERR_SUCCESS != err) { BDBG_ERR(("%s BXVD_GetDisplayOffset failed (err=0x%x)\n",__func__,err)); } BDBG_WRN(("%s display offset=%ld\n",__func__,lDisplayOffsetValue)); #endif lDisplayOffsetValue = (15 * 45000) / 1000; err = BXVD_SetDisplayOffset(GetXVDCh(), lDisplayOffsetValue); bos_release_mutex(s_p_mutex); return b_ok; } else { BDBG_ERR(("%s BXVD_StartDecode failed %d\n",__FUNCTION__,err)); bstream_p_attach_rave(decode->stream,false); } bos_release_mutex(s_p_mutex); } return err; } /* Summary: Stop decoding a stream. Description: The stream remains valid after decode is stopped. Decode could be restarted without retuning or restarting playback. */ void bdecode_stop( bdecode_t decode /* handle returned by bdecode_open */ ){ BERR_Code berr; BDBG_ASSERT(decode); if (!decode->status.bVideoDecoding) return; #ifdef CONFIG_EIA_708 bdisplay_vbi_clear_cc(); #endif BDBG_ASSERT(decode->stream); BDBG_ASSERT(decode->stream->hRaveCx); if (bos_acquire_mutex(s_p_mutex,DECODE_MUTEX_TIMEOUT) == b_ok) { //RLQ, move it after stop decoder to fix decoder FW timeout issue if changing channel too fast //bstream_p_attach_rave(decode->stream,false); berr = BXVD_StopDecode(GetXVDCh()); if (berr != BERR_SUCCESS) { BDBG_ERR(("%s BXVD_StopDecode failed\n",__FUNCTION__)); } bstream_p_attach_rave(decode->stream,false); decode->status.bVideoDecoding = false; bos_release_mutex(s_p_mutex); } //decode->status.bVideoDecoding = false; } /* Summary: Get the status of the decoder and current source. */ bresult bdecode_get_status( bdecode_t decode, /* handle returned by bdecode_open */ bdecode_status *status /* [out] status to be populated */ ){ BXPT_Rave_BufferInfo bufInfo; BXPT_Rave_RecordStats recStats; BXVD_PTSInfo PTSInfo; BXVD_ChannelStatus xvdStatus; BXVD_DisplayMode displayMode; BDBG_ASSERT(decode); BKNI_Memset(status, 0, sizeof(*status)); if (!decode->status.bVideoDecoding) { return b_ok; } BDBG_ASSERT(decode->stream); BDBG_ASSERT(decode->stream->hRaveCx); BKNI_Memcpy(status,&(decode->status),sizeof(decode->status)); BKNI_Memset(&recStats, 0, sizeof(recStats)); BKNI_Memset(&bufInfo, 0, sizeof(bufInfo)); if (BXPT_Rave_GetBufferInfo(decode->stream->hRaveCx, &bufInfo) == BERR_SUCCESS) { status->video_fifo_depth = bufInfo.CdbDepth; status->video_fifo_size = bufInfo.CdbSize; } if (BXVD_GetPTS(GetXVDCh(),&PTSInfo) == BERR_SUCCESS) { status->video_pts = PTSInfo.ui32RunningPTS; status->video_pts_error = PTSInfo.uiPCROffset; } status->bPCR_Lock = BXPT_PcrOffset_IsOffsetValid(decode->stream->hPcrOffset); status->vPID = decode->stream->mpeg.video[0].pid; status->pcrPID = decode->stream->mpeg.pcr_pid; status->video_stc = BXPT_PcrOffset_GetStc_isr(decode->stream->hPcrOffset) + BXPT_PcrOffset_GetOffset_isr(decode->stream->hPcrOffset); BXVD_GetChannelStatus(GetXVDCh(), &xvdStatus); status->xvdch_status = xvdStatus.uiAVDStatusBlock; status->underflow_cnt = xvdStatus.ulUnderflowCount; status->decoder_drop_cnt = xvdStatus.uiDecoderDroppedCount; status->display_drop_cnt = xvdStatus.uiDisplayManagerDroppedCount; status->pic_received = xvdStatus.uiPicturesReceivedCount; BXVD_GetVideoDisplayMode(GetXVDCh(), &displayMode); status->TSM_Mode = displayMode; return b_ok; } /* Summary: Get the config for the decoder. */ void bdecode_get_config( bdecode_t decode, /* handle returned by bdecode_open */ bdecode_config *cfg /* [out] configuration structure to be populated */ ){ unsigned int flags; flags = bos_enter_critical(); *cfg = decode->config; bos_exit_critical(flags); } /* Summary: Set the config for the decoder. */ void bdecode_set_config( bdecode_t decode, /* handle returned by bdecode_open */ bdecode_config *cfg /* configuration */ ) { BERR_Code rc; if (cfg->mute != decode->config.mute) { rc = BXVD_EnableMute(GetXVDCh(),cfg->mute); if (BERR_SUCCESS != rc) { BDBG_ERR(("BXVD_EnableMute failed %d", rc)); goto failed; } } if ((cfg->channel_change != decode->config.channel_change) && !(cfg->channel_change&decode->config.channel_change)) { BXVD_SetChannelChangeMode(GetXVDCh(), cfg->channel_change); } #ifndef NO_VCHIP xds_ctrl_set_cb(&decode->xds_ctrl, (xds_callback_t)cfg->xds_callback); #endif if (!decode->config.block_vbi && cfg->block_vbi) { #ifdef CONFIG_EIA_708 bdisplay_vbi_clear_cc(); #endif } #ifdef ACB612 else { if (cfg->block_vbi) { #ifdef CONFIG_EIA_708 bdisplay_vbi_clear_cc(); #endif } } #endif decode->config = *cfg; return; failed: BDBG_ERR(("bdecode_set_config failed")); } static void bdecode_watchdog_task(void *arg) { BERR_Code rc = BERR_SUCCESS; bdecode_t decode = (bdecode_t)arg; BDBG_ASSERT(decode); while (1) { if (BKNI_WaitForEvent(decode->wdEvent,BKNI_INFINITE) != BERR_SUCCESS) { BDBG_ERR(("BKNI_WaitForEvent failed in %s",__FUNCTION__)); continue; } if (b_ok != bos_acquire_mutex(&decode->mutex, -1)) continue; BDBG_WRN(("process watchdog....!!!")); rc = bstream_p_rave_enable(decode->stream,false); if (BERR_SUCCESS != rc) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); continue; } rc = bstream_p_rave_flush(decode->stream); if (BERR_SUCCESS != rc) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); continue; } bos_release_mutex(&decode->mutex); BXVD_ProcessWatchdog(GetXVD()); if (b_ok != bos_acquire_mutex(&decode->mutex, -1)) continue; rc = bstream_p_rave_enable(decode->stream,true); bos_release_mutex(&decode->mutex); if (BERR_SUCCESS != rc) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); } } }