/****************************************************************************** * (c)2008-2009 Broadcom Corporation * * This program is the proprietary software of Broadcom Corporation and/or its licensors, * and may only be used, duplicated, modified or distributed pursuant to the terms and * conditions of a separate, written license agreement executed between you and Broadcom * (an "Authorized License"). Except as set forth in an Authorized License, Broadcom grants * no license (express or implied), right to use, or waiver of any kind with respect to the * Software, and Broadcom expressly reserves all rights in and to the Software and all * intellectual property rights therein. IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU * HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY * NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE. * * Except as expressly set forth in the Authorized License, * * 1. This program, including its structure, sequence and organization, constitutes the valuable trade * secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof, * and to use this information only in connection with your use of Broadcom integrated circuit products. * * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" * AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO * THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, * LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION * OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF * USE OR PERFORMANCE OF THE SOFTWARE. * * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS * LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR * EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR * USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT * ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF * ANY LIMITED REMEDY. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: * * Utility to handle the frontend configuration and tuning. * * Revision History: * * Created: 09/28/2009 by Jeff Fisher * * $brcm_Log: $ * * *****************************************************************************/ #include "bapp_av.h" #include "bapp_util.h" #include "bapp_hdmi.h" #include "bsettop_p_stream.h" #include "nexus_timebase.h" #include "ts_psi.h" BDBG_MODULE(bapp_av); /* Register software module with debug interface */ #define MAX_DECODE_CHANNELS BSETTOP_MAX_STREAMS struct bapp_av { bapp_nexus_t *p_nexus; bool video_decoding; bool audio_decoding; bool start_compressed; /* Decode */ NEXUS_VideoDecoderHandle videoDecodeHandle; NEXUS_VideoWindowHandle window; NEXUS_AudioDecoderHandle pcmDecoder; NEXUS_AudioDecoderHandle compressedDecoder; NEXUS_AudioDecoderStartSettings audioSettings; bsettop_p_stream_t *p_stream_info; }; /** Summary: Supported audio and video formats */ const bapp_av_stream_type_t s_video_stream_types[] = { { TS_PSI_ST_13818_2_Video, NEXUS_VideoCodec_eMpeg2, 0,"MPEG-2" }, { TS_PSI_ST_ATSC_Video, NEXUS_VideoCodec_eMpeg2, 0,"MPEG-2" }, { TS_PSI_ST_AVS_Video, NEXUS_VideoCodec_eAvs, 0,"AVS" }, { TS_PSI_ST_14496_10_Video, NEXUS_VideoCodec_eH264, 0,"H.264" }, { TS_PSI_ST_SMPTE_VC1, NEXUS_VideoCodec_eVc1, 0,"VC1" }, { TS_PSI_ST_14496_2_Video, NEXUS_VideoCodec_eMpeg4Part2, 0,"MP4p2" } }; const int s_video_stream_types_num = sizeof(s_video_stream_types)/sizeof(s_video_stream_types[0]); const bapp_av_stream_type_t s_audio_stream_types[] = { { TS_PSI_ST_11172_3_Audio, NEXUS_AudioCodec_eMpeg, 0,"MPEG" }, { TS_PSI_ST_13818_3_Audio, NEXUS_AudioCodec_eMpeg, 0,"MPEG" }, { TS_PSI_ST_ATSC_AC3, NEXUS_AudioCodec_eAc3, 0,"AC3" }, { TS_PSI_ST_AVS_Audio, NEXUS_AudioCodec_eAvs, 0,"AVS" }, { TS_PSI_ST_ATSC_EAC3, NEXUS_AudioCodec_eAc3Plus, 0,"AC3+" } }; const int s_audio_stream_types_num = sizeof(s_audio_stream_types)/sizeof(s_audio_stream_types[0]); /** Summary: Return a bapp_av_t handle. **/ bapp_result_t bapp_av_open(bapp_av_t *p_av, bapp_nexus_t *p_nexus) { NEXUS_VideoDecoderSettings settings; bapp_av_t p_tmp_av = (bapp_av_t)bapp_util_malloc(sizeof(struct bapp_av)); if (!p_tmp_av) return eBAPP_RESULT_ALLOC_FAILURE; BKNI_Memset(p_tmp_av,0,sizeof(struct bapp_av)); p_tmp_av->p_nexus = p_nexus; /* Bring up audio decoders and connect to outputs */ p_tmp_av->pcmDecoder = NEXUS_AudioDecoder_Open(0, NULL); p_tmp_av->compressedDecoder = NEXUS_AudioDecoder_Open(1, NULL); p_tmp_av->window = NEXUS_VideoWindow_Open(p_nexus->display, 0); p_tmp_av->videoDecodeHandle = NEXUS_VideoDecoder_Open(0, NULL); /* take default capabilities */ BDBG_ASSERT(p_tmp_av->videoDecodeHandle); NEXUS_VideoDecoder_GetSettings(p_tmp_av->videoDecodeHandle,&settings); settings.channelChangeMode = NEXUS_VideoDecoder_ChannelChangeMode_eHoldUntilFirstPicture; NEXUS_VideoDecoder_SetSettings(p_tmp_av->videoDecodeHandle,&settings); bstream_init(p_tmp_av->videoDecodeHandle); NEXUS_VideoWindow_AddInput(p_tmp_av->window, NEXUS_VideoDecoder_GetConnector(p_tmp_av->videoDecodeHandle)); /* Force a hotplug to switch to preferred format */ bapp_hdmi_hotplug_callback(p_tmp_av->p_nexus->platformConfig.outputs.hdmi[0], (int)p_tmp_av->p_nexus->display); *p_av = p_tmp_av; return eBAPP_RESULT_OK; } /** Summary: Release resources. **/ bapp_result_t bapp_av_close(bapp_av_t p_av) { BDBG_ASSERT(p_av); if (p_av->window) NEXUS_VideoWindow_Close(p_av->window); if (p_av->videoDecodeHandle) NEXUS_VideoDecoder_Close(p_av->videoDecodeHandle); /* take default capabilities */ if (p_av->pcmDecoder) NEXUS_AudioDecoder_Close(p_av->pcmDecoder); if (p_av->compressedDecoder) NEXUS_AudioDecoder_Close(p_av->compressedDecoder); if (p_av->window) NEXUS_VideoWindow_Close(p_av->window); bapp_util_free(p_av); return eBAPP_RESULT_OK; } /** Summary: Lock the frontend. **/ bapp_result_t bapp_audio_start(bapp_av_t p_av,bstream_t p_stream) { NEXUS_Error nerr; bstream_status status; bsettop_p_stream_t *p_stream_info; NEXUS_HdmiOutputStatus hdmi_status; NEXUS_TimebaseSettings timebaseSettings; bstream_get_status(p_stream,&status); p_stream_info = bstream_get_info(p_stream); if ((status.mpeg.audio[0].pid == 0) || !p_stream_info) { return eBAPP_RESULT_FAILURE; } if (p_av->audio_decoding) bapp_audio_stop(p_av); BDBG_ASSERT(p_stream_info->audioPidChannel); BDBG_ASSERT(p_stream_info->stcChannel); NEXUS_AudioDecoder_GetDefaultStartSettings(&p_av->audioSettings); p_av->audioSettings.codec = status.mpeg.audio[0].format; p_av->audioSettings.pidChannel = p_stream_info->audioPidChannel; p_av->audioSettings.stcChannel = p_stream_info->stcChannel; BDBG_MSG(("%s(0x%04x,0x%04x) %d\n",__FUNCTION__,status.mpeg.audio[0].pid,status.mpeg.pcr_pid)); if (!p_av->video_decoding) { NEXUS_Timebase_GetSettings(NEXUS_Timebase_e0, &timebaseSettings); timebaseSettings.sourceType = NEXUS_TimebaseSourceType_ePcr; timebaseSettings.sourceSettings.pcr.pidChannel = p_stream_info->pcrPidChannel; timebaseSettings.sourceSettings.pcr.maxPcrError = 0xff; timebaseSettings.sourceSettings.pcr.trackRange = NEXUS_TimebaseTrackRange_e61ppm; NEXUS_Timebase_SetSettings(NEXUS_Timebase_e0, &timebaseSettings); } NEXUS_AudioOutput_RemoveAllInputs(NEXUS_AudioDac_GetConnector(p_av->p_nexus->platformConfig.outputs.audioDacs[0])); NEXUS_AudioOutput_RemoveAllInputs(NEXUS_SpdifOutput_GetConnector(p_av->p_nexus->platformConfig.outputs.spdif[0])); NEXUS_AudioOutput_AddInput(NEXUS_AudioDac_GetConnector(p_av->p_nexus->platformConfig.outputs.audioDacs[0]), NEXUS_AudioDecoder_GetConnector(p_av->pcmDecoder, NEXUS_AudioDecoderConnectorType_eStereo)); #if 1 NEXUS_HdmiOutput_GetStatus(p_av->p_nexus->platformConfig.outputs.hdmi[0], &hdmi_status); if ( hdmi_status.connected ) { NEXUS_AudioOutput_RemoveAllInputs(NEXUS_HdmiOutput_GetAudioConnector(p_av->p_nexus->platformConfig.outputs.hdmi[0])); NEXUS_AudioOutput_AddInput(NEXUS_HdmiOutput_GetAudioConnector(p_av->p_nexus->platformConfig.outputs.hdmi[0]), NEXUS_AudioDecoder_GetConnector(p_av->pcmDecoder, NEXUS_AudioDecoderConnectorType_eStereo)); } #endif p_av->start_compressed = false; if ( p_av->audioSettings.codec == NEXUS_AudioCodec_eAc3 ) { /* Only pass through AC3 */ NEXUS_AudioOutput_AddInput(NEXUS_SpdifOutput_GetConnector(p_av->p_nexus->platformConfig.outputs.spdif[0]), NEXUS_AudioDecoder_GetConnector(p_av->compressedDecoder, NEXUS_AudioDecoderConnectorType_eCompressed)); p_av->start_compressed = true; } else { NEXUS_AudioOutput_AddInput(NEXUS_SpdifOutput_GetConnector(p_av->p_nexus->platformConfig.outputs.spdif[0]), NEXUS_AudioDecoder_GetConnector(p_av->pcmDecoder, NEXUS_AudioDecoderConnectorType_eStereo)); } nerr = NEXUS_AudioDecoder_Start(p_av->pcmDecoder,&p_av->audioSettings); if (nerr != NEXUS_SUCCESS) { BDBG_ERR(("%s NEXUS_AudioDecoder_Start pcm failed %d\n",__FUNCTION__,nerr)); } else { p_av->audio_decoding = true; } if (p_av->start_compressed) { nerr = NEXUS_AudioDecoder_Start(p_av->compressedDecoder,&p_av->audioSettings); if (nerr != NEXUS_SUCCESS) { BDBG_ERR(("%s NEXUS_AudioDecoder_Start compressed failed %d\n",__FUNCTION__,nerr)); } } return eBAPP_RESULT_OK; } /** Summary: Unlock the frontend. **/ bapp_result_t bapp_audio_stop(bapp_av_t p_av) { if (!p_av->audio_decoding) return eBAPP_RESULT_OK; NEXUS_AudioDecoder_Stop(p_av->pcmDecoder); if (p_av->start_compressed) { NEXUS_AudioDecoder_Stop(p_av->compressedDecoder); } p_av->audio_decoding = false; return eBAPP_RESULT_OK; } /** Summary: Lock the frontend. **/ bapp_result_t bapp_video_start(bapp_av_t p_av,bstream_t p_stream) { bstream_status status; NEXUS_TimebaseSettings timebaseSettings; bstream_get_status(p_stream,&status); if (status.mpeg.video[0].pid == 0) { BDBG_ERR(("%s(0x%04x,0x%04x)\n",__FUNCTION__,status.mpeg.video[0].pid,status.mpeg.pcr_pid)); return eBAPP_RESULT_FAILURE; } if (p_av->video_decoding) { BDBG_ERR(("%s(0x%04x,0x%04x) already decoding\n",__FUNCTION__,status.mpeg.video[0].pid,status.mpeg.pcr_pid)); return eBAPP_RESULT_FAILURE; } p_av->p_stream_info = bstream_get_info(p_stream); if (!p_av->p_stream_info) { BDBG_ERR(("%s(0x%04x,0x%04x) invalid stream info\n",__FUNCTION__,status.mpeg.video[0].pid,status.mpeg.pcr_pid)); return eBAPP_RESULT_FAILURE; } BDBG_ASSERT(p_av->p_stream_info->videoPidChannel); BDBG_ASSERT(p_av->p_stream_info->stcChannel); NEXUS_VideoDecoder_GetDefaultStartSettings(&(p_av->p_stream_info->decodeSettings)); p_av->p_stream_info->decodeSettings.codec = status.mpeg.video[0].format; p_av->p_stream_info->decodeSettings.pidChannel = p_av->p_stream_info->videoPidChannel; p_av->p_stream_info->decodeSettings.stcChannel = p_av->p_stream_info->stcChannel; p_av->p_stream_info->decodeSettings.prerollRate = 1; NEXUS_Timebase_GetSettings(NEXUS_Timebase_e0, &timebaseSettings); timebaseSettings.sourceType = NEXUS_TimebaseSourceType_ePcr; timebaseSettings.sourceSettings.pcr.pidChannel = p_av->p_stream_info->pcrPidChannel; timebaseSettings.sourceSettings.pcr.maxPcrError = 0xff; timebaseSettings.sourceSettings.pcr.trackRange = NEXUS_TimebaseTrackRange_e61ppm; NEXUS_Timebase_SetSettings(NEXUS_Timebase_e0, &timebaseSettings); BDBG_ERR(("NEXUS_VideoDecoder_StartDecodeWithPrimer(0x%08x)\n",p_av->p_stream_info->primerHandle)); BDBG_ASSERT(p_av->p_stream_info->decodeSettings.stcChannel); NEXUS_VideoDecoder_StartDecodeWithPrimer(p_av->videoDecodeHandle, p_av->p_stream_info->primerHandle); p_av->video_decoding = true; return eBAPP_RESULT_OK; } /** Summary: Unlock the frontend. **/ bapp_result_t bapp_video_stop(bapp_av_t p_av) { if (!p_av->video_decoding) return eBAPP_RESULT_OK; BDBG_ASSERT(p_av->p_stream_info); BDBG_ASSERT(p_av->p_stream_info->primerHandle); BDBG_ERR(("NEXUS_VideoDecoder_Stop(0x%08x)\n",p_av->videoDecodeHandle)); NEXUS_VideoDecoder_Stop(p_av->videoDecodeHandle); BDBG_ERR(("NEXUS_VideoDecoder_StartPrimer(0x%08x)\n",p_av->p_stream_info->primerHandle)); NEXUS_VideoDecoder_StartPrimer(p_av->videoDecodeHandle, p_av->p_stream_info->primerHandle,&(p_av->p_stream_info->decodeSettings)); p_av->video_decoding = false; return eBAPP_RESULT_OK; } /** Summary: Supported video format. Returns NULL if stream_type (from PMT) not supported. **/ bapp_av_stream_type_t *bapp_av_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_WRN(("Video format[0x%02x]: %s\n",s_video_stream_types[i].format,s_video_stream_types[i].format_name)); return &s_video_stream_types[i]; } } BDBG_WRN(("Unsupported Video format[0x%02x]\n",stream_type)); return NULL; } /** Summary: Supported audio format. Returns NULL if stream_type (from PMT) not supported. **/ bapp_av_stream_type_t *bapp_av_supported_audio(unsigned char stream_type) { int i; for (i = 0; i < s_audio_stream_types_num; ++i) { if (stream_type == s_audio_stream_types[i].format) { BDBG_WRN(("Audio format[0x%02x]: %s\n",s_audio_stream_types[i].format,s_audio_stream_types[i].format_name)); return &s_audio_stream_types[i]; } } BDBG_WRN(("Unsupported Audio format[0x%02x]\n",stream_type)); return NULL; } /** Summary: Return decode status. **/ bapp_result_t bapp_av_status(bapp_av_t p_av, NEXUS_VideoDecoderStatus *p_vStatus, NEXUS_AudioDecoderStatus *p_aStatus) { BDBG_ASSERT (p_av); BDBG_ASSERT (p_av->videoDecodeHandle); BDBG_ASSERT (p_av->pcmDecoder); BDBG_ASSERT (p_vStatus); BDBG_ASSERT (p_aStatus); NEXUS_VideoDecoder_GetStatus(p_av->videoDecodeHandle,p_vStatus); NEXUS_AudioDecoder_GetStatus(p_av->pcmDecoder,p_aStatus); return eBAPP_RESULT_OK; }