📄 hdmi.c
字号:
/* * * Copyright (c) 2001-2007 Sigma Designs, Inc. * All Rights Reserved. Proprietary and Confidential. * *//** @file hdmi.c @brief Interface to access an HDMI capture port @author Christian Wolff, Sean.Sekwon.Choi @date 2007-07-16*/// to enable or disable the debug messages of this source file, put 1 or 0 below#if 1#define LOCALDBG ENABLE#else#define LOCALDBG DISABLE#endif#include "common.h"#include "hdmi.h"#include "SiI9031.h"#include "AD9380.h"#include "../../samples/dvi_hdmi_update.h"#include "../../samples/dvi_hdmi.h"#ifdef _DEBUGstatic const RMascii *CEA861VICNames[] = { "Custom", // 0 "VGA 640x480 60Hz 1X", // 1 " 480p 60Hz 1X 4:3", // 2 " 480p 60Hz 1X 16:9", // 3 " 720p 60Hz 1X 16:9", // 4 "1080i 60Hz 1X 16:9", // 5 " 480i 60Hz 2X 4:3", // 6 " 480i 60Hz 2X 16:9", // 7 " 240p 60Hz 2X 4:3", // 8 " 240p 60Hz 2X 16:9", // 9 " 480i 60Hz 4X 4:3", // 10 " 480i 60Hz 4X 16:9", // 11 " 240p 60Hz 4X 4:3", // 12 " 240p 60Hz 4X 16:9", // 13 " 480p 60Hz 2X 4:3", // 14 " 480p 60Hz 2X 16:9", // 15 "1080p 60Hz 1X 16:9", // 16 " 576p 50Hz 1X 4:3", // 17 " 576p 50Hz 1X 16:9", // 18 " 720p 50Hz 1X 16:9", // 19 "1080i 50Hz 1X 16:9", // 20 " 576i 50Hz 2X 4:3", // 21 " 576i 50Hz 2X 16:9", // 22 " 288p 50Hz 2X 4:3", // 23 " 288p 50Hz 2X 16:9", // 24 " 576i 50Hz 4X 4:3", // 25 " 576i 50Hz 4X 16:9", // 26 " 288p 50Hz 4X 4:3", // 27 " 288p 50Hz 4X 16:9", // 28 " 576p 50Hz 2X 4:3", // 29 " 576p 50Hz 2X 16:9", // 30 "1080p 50Hz 1X 16:9", // 31 "1080p 24Hz 1X 16:9", // 32 "1080p 25Hz 1X 16:9", // 33 "1080p 30Hz 1X 16:9", // 34 " 480p 60Hz 4X 4:3", // 35 " 480p 60Hz 4X 16:9", // 36 " 576p 50Hz 4X 4:3", // 37 " 576p 50Hz 4X 16:9", // 38 "1080i 50Hz 1X 16:9", // 39 "1080i 100Hz 1X 16:9", // 40 " 720p 100Hz 1X 16:9", // 41 " 576p 100Hz 1X 4:3", // 42 " 576p 100Hz 1X 16:9", // 43 " 576i 100Hz 2X 4:3", // 44 " 576i 100Hz 2X 16:9", // 45 "1080i 120Hz 1X 16:9", // 46 " 720p 120Hz 1X 16:9", // 47 " 480p 120Hz 1X 4:3", // 48 " 480p 120Hz 1X 16:9", // 49 " 480i 120Hz 2X 4:3", // 50 " 480i 120Hz 2X 16:9", // 51 " 576p 200Hz 1X 4:3", // 52 " 576p 200Hz 1X 16:9", // 53 " 576i 200Hz 2X 4:3", // 54 " 576i 200Hz 2X 16:9", // 55 " 480p 240Hz 1X 4:3", // 56 " 480p 240Hz 1X 16:9", // 57 " 480i 240Hz 2X 4:3", // 58 " 480i 240Hz 2X 16:9", // 59};#endif/* CEA 861-C/D subset of all EMhwlib video modes *//* translates VIC to enum EMhwlibTVStandard */const enum EMhwlibTVStandard cap_hdmi_cea861_modes[HDMI_CEA861_VIDEOMODES_N] = HDMI_CEA861_VIDEOMODES;// VESA/CVT subset of all EMhwlib video modesconst enum EMhwlibTVStandard cap_hdmi_it_modes[] = HDMI_VESA_CVT_VIDEOMODES;RMuint32 cap_hdmi_it_modes_n;// internal state of the HDMI capture portstruct cap_hdmi_instance { // Access struct RUA *pRUA; struct cap_chip_instance *pChip; // State enum cap_hdmi_mode hdmi_mode; RMbool upsample_from_422; struct cap_hdmi_avi_info last_avi; RMuint8 last_isrc[32]; RMuint8 last_isrc_header; RMbool last_isrc2; enum EMhwlibTVStandard TVStandard; enum EMhwlibColorSpace InputColorSpace; enum EMhwlibInputColorFormat InputColorFormat; struct EMhwlibAspectRatio PictureAspectRatio; struct cap_hdmi_update UpdateHDMI;};RMstatus cap_hdmi_open( struct RUA *pRUA, struct cap_chip_instance *pChip, struct cap_hdmi_instance **ppHDMI){ RMstatus err = RM_OK; struct cap_hdmi_instance *pHDMI; // Sanity checks if (ppHDMI == NULL) return RM_FATALINVALIDPOINTER; *ppHDMI = NULL; if (pRUA == NULL) return RM_FATALINVALIDPOINTER; if (pChip == NULL) return RM_FATALINVALIDPOINTER; // Allocate and clear local instance pHDMI = (struct cap_hdmi_instance *)RMMalloc(sizeof(struct cap_hdmi_instance)); if (pHDMI == NULL) { RMDBGLOG((ENABLE, "FATAL! Not enough memory for struct cap_hdmi_instance!\n")); return RM_FATALOUTOFMEMORY; } RMMemset(pHDMI, 0, sizeof(struct cap_hdmi_instance)); *ppHDMI = pHDMI; cap_hdmi_it_modes_n = sizeof(cap_hdmi_it_modes) / sizeof(cap_hdmi_it_modes[0]); // Set default and non-zero startup values pHDMI->pRUA = pRUA; pHDMI->pChip = pChip; pHDMI->hdmi_mode = cap_hdmi_mode_unknown; pHDMI->UpdateHDMI.APIVersion = 1; // Open selected chip err = RM_OK; switch (pHDMI->pChip->chip) { case cap_chip_none: err = RM_NOT_SUPPORTED; // no "direct" hdmi input break; case cap_chip_SiI9031: err = RM_OK; break; case cap_chip_AD9380: err = RM_OK; break; default: err = RM_INVALID_PARAMETER; } if (RMFAILED(err)) { RMFree(pHDMI); *ppHDMI = NULL; } return err;}RMstatus cap_hdmi_close( struct cap_hdmi_instance *pHDMI){ RMstatus err = RM_OK; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pHDMI == NULL) return RM_OK; // already closed // Free all ressources switch (pHDMI->pChip->chip) { case cap_chip_SiI9031: err = RM_OK; break; case cap_chip_AD9380: err = RM_OK; break; default: err = RM_ERROR; } RMFree(pHDMI); return err;}/*** Chip Setup functions ***//* tri-state all outputs and power down the selected chip */RMstatus cap_hdmi_tristate( struct cap_hdmi_instance *pHDMI){ // Sanity checks if (pHDMI == NULL) return RM_FATALINVALIDPOINTER; switch (pHDMI->pChip->chip) { case cap_chip_SiI9031: return cap_SiI9031_tristate(pHDMI->pChip->instance.pSiI9031); case cap_chip_AD9380: return cap_AD9380_tristate(pHDMI->pChip->instance.pAD9380); default: return RM_ERROR; }}/* prepares the selected input for capture (initializes the chip) */RMstatus cap_hdmi_select_input( struct cap_hdmi_instance *pHDMI, RMuint32 input){ RMstatus err =RM_OK; switch (pHDMI->pChip->chip) { case cap_chip_SiI9031: err = cap_SiI9031_init_capture(pHDMI->pChip->instance.pSiI9031, input, FALSE); break; case cap_chip_AD9380: err = cap_AD9380_init_HDMI_capture(pHDMI->pChip->instance.pAD9380, input); break; default: err = RM_ERROR; break; } if (RMFAILED(err)) { RMDBGLOG((ENABLE, "error in cap_hdmi_select_input\n")); return err; } return err;}/* set the pixel repetition value announced in the AVI info frame. This reduces the pixel clock and all horizontal timing values accordingly. */RMstatus cap_hdmi_apply_pixelrep( struct cap_hdmi_instance *pHDMI, RMuint32 pixel_rep){ switch (pHDMI->pChip->chip) { case cap_chip_SiI9031: return cap_SiI9031_apply_pixelrep(pHDMI->pChip->instance.pSiI9031, pixel_rep); case cap_chip_AD9380: return RM_NOTIMPLEMENTED; // TODO default: return RM_ERROR; }}/** Initializes audio section of HDMI chip Reads channel status from HDMI chip Returns current sample frequency, or 0 if no audio, in *pSamplingRate*/RMstatus cap_hdmi_setup_audio( struct cap_hdmi_instance *pHDMI, RMuint32 MClkFactor, RMuint32 *pSamplingRate){ RMstatus err; RMuint32 pclk, n, cts, fs_n_cts, prev_fs; RMuint8 ch_stat[5]; RMbool obey_hdmi = TRUE; // choice: only use valid HDMI fs, or all SPDIF fs static const RMuint32 fs_tab[16] = { 44100, 0, 48000, 32000, 22050, 11025, 24000, 16000, 88200, 768000, 96000, 0, 176400, 12000, 192000, 0 }; static const RMuint32 fs_tab_hdmi[16] = { 44100, 0, 48000, 32000, 0, 0, 0, 0, 88200, 768000, 96000, 0, 176400, 0, 192000, 0 }; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pHDMI == NULL) return RM_FATALINVALIDPOINTER; if (pSamplingRate == NULL) return RM_FATALINVALIDPOINTER; // remember previous SamplingRate prev_fs = *pSamplingRate; // default SamplingRate to 0 *pSamplingRate = 0; // transmission is not in HDMI mode, no audio expected if (pHDMI->hdmi_mode != cap_hdmi_mode_HDMI){ RMDBGLOG((ENABLE, "XXXXXXXXXXX not HDMI mode\n")); return RM_OK; } // chip specific processing switch (pHDMI->pChip->chip) { case cap_chip_SiI9031: // start audio procesing err = cap_SiI9031_init_audio_clock(pHDMI->pChip->instance.pSiI9031, TRUE, 256); // TODO if (RMFAILED(err)) return err; // read channel status err = cap_SiI9031_get_audio_channel_status(pHDMI->pChip->instance.pSiI9031, ch_stat); if (RMFAILED(err)) return err; RMDBGLOG((ENABLE, "[hdmi] audio channel status [39:0]: %02X.%02X.%02X.%02X.%02X\n", ch_stat[4], ch_stat[3], ch_stat[2], ch_stat[1], ch_stat[0])); // read N/CTS pair, CTS = (f(TMDS clk) * N) / (128 * f(s)) err = cap_SiI9031_get_audio_n_cts(pHDMI->pChip->instance.pSiI9031, &n, &cts, &fs_n_cts); if (RMFAILED(err)) return err; RMDBGLOG((ENABLE, "[hdmi] N/CTS: %lu/%lu\n", n, cts)); break; case cap_chip_AD9380: RMDBGLOG((ENABLE, "XXXXXXXXXXXXXXXXXXXXXXX %s\n",__func__)); err = cap_AD9380_get_audio_channel_status(pHDMI->pChip->instance.pAD9380, ch_stat); break; default: return RM_ERROR; } // not consumer use, or not mode 00 if ((ch_stat[0] & 0xC1) != 0x00) return RM_OK; // extract fs tag from channel status pclk = ch_stat[3] & 0x0F; // no audio present if (pclk == 1) return RM_OK; if (n && cts) { // match approximate SamplingRate from pixel clock and N/CTS to nearest valid sample rate if (fs_n_cts) { RMuint32 i, fs, fs_mult, fs_mod; static const RMuint32 fs_base[] = {8000, 11025, 12000, 32000, 44100, 48000}; RMDBGLOG((ENABLE, "[hdmi] Audio fs from N/CTS: %lu (Approx.)\n", fs_n_cts)); fs = fs_n_cts; for (i = (obey_hdmi ? 3 : 0); i < sizeof(fs_base) / sizeof(RMuint32); i++) { fs_mult = fs / fs_base[i]; fs_mod = fs % fs_base[i]; if (fs_mod < (fs_base[i] / 8)) { fs_n_cts = fs_base[i] * fs_mult; break; } else if (fs_mod > (fs_base[i] * 7 / 8)) { fs_mult++; fs_n_cts = fs_base[i] * fs_mult; break; } } RMDBGLOG((ENABLE, "[hdmi] Audio fs from N/CTS: %lu\n", fs_n_cts)); } // SamplingRate from fs tag *pSamplingRate = obey_hdmi ? fs_tab_hdmi[pclk] : fs_tab[pclk]; if (*pSamplingRate != prev_fs) { RMDBGLOG((ENABLE, "[hdmi] Audio fs from tag: %s, tag=0x%01lX\n", (pclk == 0) ? "44.1 kHz" : (pclk == 1) ? "<not indicated>" : (pclk == 2) ? "48 kHz" : (pclk == 3) ? "32 kHz" : (pclk == 4) ? "22.05 kHz <invalid>" : (pclk == 5) ? "11.025 kHz <invalid>" :
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -