📄 hdmi.c
字号:
(pclk == 6) ? "24 kHz <invalid>" : (pclk == 7) ? "16 kHz <invalid>" : (pclk == 8) ? "88.2 kHz" : (pclk == 9) ? "768 kHz" : (pclk == 10) ? "96 kHz" : (pclk == 11) ? "<reserved>" : (pclk == 12) ? "176.4 kHz" : (pclk == 13) ? "12 kHz <invalid>" : (pclk == 14) ? "192 kHz" : (pclk == 15) ? "<unknown>" : "-", pclk)); } // mismatch between fs tag and N/CTS, use the latter if (fs_n_cts && (*pSamplingRate != fs_n_cts)) { RMDBGLOG((ENABLE, "[hdmi] ERROR: fs tag in channel status does not match frequency from N/CTS PLL!!!\n")); *pSamplingRate = fs_n_cts; } } else { // no audio *pSamplingRate = 0; } if (*pSamplingRate != prev_fs) { RMDBGPRINT((ENABLE, "\n\n\t[hdmi] Audio fs: %lu", *pSamplingRate / 1000)); if (*pSamplingRate % 1000) { RMDBGPRINT((ENABLE, ".%03lu", *pSamplingRate % 1000)); } RMDBGPRINT((ENABLE, " kHz\n\n\n")); } return RM_OK;}/*** Mode Detection functions ***//* Detect HDMI or DVI mode from the chip, signaling necessary actions */RMstatus cap_hdmi_detect_mode( struct cap_hdmi_instance *pHDMI, enum cap_hdmi_mode *pHDMIMode, RMbool *pUpdateAVI, // need to handle AVI Info Frame again RMbool *pUpdateAudio, // need to re-start audio RMbool *pUpdateVideo) // need to detect video mode{ RMstatus err; enum cap_hdmi_mode hdmi_mode; switch (pHDMI->pChip->chip) { case cap_chip_SiI9031: err = cap_SiI9031_detect_mode(pHDMI->pChip->instance.pSiI9031, &hdmi_mode); break; case cap_chip_AD9380: err = cap_AD9380_detect_mode(pHDMI->pChip->instance.pAD9380, &hdmi_mode); break; default: err = RM_ERROR; } if (RMFAILED(err)) return err; if (pHDMIMode) *pHDMIMode = hdmi_mode; if (hdmi_mode != pHDMI->hdmi_mode) { pHDMI->hdmi_mode = hdmi_mode; RMDBGPRINT((ENABLE, "[hdmi] %s mode detected\n", (hdmi_mode == cap_hdmi_mode_HDMI) ? "HDMI" : (hdmi_mode == cap_hdmi_mode_DVI) ? "DVI" : "unknown")); if (hdmi_mode == cap_hdmi_mode_HDMI) { RMDBGPRINT((ENABLE, "[hdmi] re-reading AVI InfoFrame\n")); if (pUpdateAVI) *pUpdateAVI = TRUE; if (pUpdateAudio) *pUpdateAudio = TRUE; } else if (hdmi_mode == cap_hdmi_mode_DVI) { RMDBGPRINT((ENABLE, "[hdmi] re-detecting video mode\n")); if (pUpdateVideo) *pUpdateVideo = TRUE; } switch (pHDMI->pChip->chip) { case cap_chip_SiI9031: err = cap_SiI9031_set_mode(pHDMI->pChip->instance.pSiI9031, hdmi_mode); break; case cap_chip_AD9380: err = RM_OK; // TODO break; default: err = RM_ERROR; break; } } return err;}/* set up certain capture parameters to match DVI capture mode (RGB888) */RMstatus cap_hdmi_prepare_dvi_mode( struct cap_hdmi_instance *pHDMI, enum EMhwlibTVStandard TVStandard, RMbool Wide, enum EMhwlibColorSpace *pInputColorSpace, enum EMhwlibInputColorFormat *pInputColorFormat, RMbool *pUpsample422, RMuint32 *pZoomX, RMuint32 *pZoomY, RMuint32 *pZoomW, RMuint32 *pZoomH, struct EMhwlibAspectRatio *pPictureAspectRatio){ struct EMhwlibAspectRatio PictureAspectRatio; if (pInputColorSpace) *pInputColorSpace = EMhwlibColorSpace_RGB_0_255; if (pInputColorFormat) *pInputColorFormat = EMhwlibInputColorFormat_24BPP; if (pUpsample422) *pUpsample422 = FALSE; if (pZoomX) *pZoomX = ZOOM_0; if (pZoomY) *pZoomY = ZOOM_0; if (pZoomW) *pZoomW = ZOOM_1; if (pZoomH) *pZoomH = ZOOM_1; // determine aspect ratio from video mode if (pPictureAspectRatio) { cap_get_aspect_ratio_from_video_mode( TVStandard, NULL, Wide, &(PictureAspectRatio.X), &(PictureAspectRatio.Y)); RMDBGPRINT((ENABLE, "[hdmi] Aspect Ratio from Video Mode: %lu:%lu\n", PictureAspectRatio.X, PictureAspectRatio.Y)); *pPictureAspectRatio = PictureAspectRatio; } return RM_OK;}/*** Info Frame functions ***//*** Reading Info Frames ***//* read an info frame of the specified 'type' from the selected chip *//* set 'version' to a specific requested version, or to 0 for any */RMstatus cap_hdmi_read_info_frame( struct cap_hdmi_instance *pHDMI, RMuint8 type, RMuint8 version, RMuint8 *header, RMuint8 *data, RMuint32 size, RMbool honor_checksum){ RMstatus err; RMuint32 i, checksum; RMuint8 offset, next_type = 0; RMbool checksum_available = TRUE; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pHDMI == NULL) return RM_FATALINVALIDPOINTER; switch (pHDMI->pChip->chip) { case cap_chip_SiI9031: // translate type to SiI9031 offset err = cap_SiI9031_get_info_frame_offset(pHDMI->pChip->instance.pSiI9031, type, &offset); if (RMFAILED(err)) return err; // read the info frame from the chip err = cap_SiI9031_read_info_frame(pHDMI->pChip->instance.pSiI9031, offset, header, data, size, honor_checksum); if (RMFAILED(err) || (header[0] && type && (header[0] != type))) { // not what was expected, try to prepare receive area for the requested type next_type = type; } else { // ISRC1 and ISRC2 share one receive area, alternate between them if (type == 0x05) { // ISRC1 if (RMunshiftBool(header[1], 7)) next_type = 0x06; // expect ISRC2 next } else if (type == 0x06) { // ISRC2 next_type = 0x05; // expect ISRC1 next } } if (next_type) { // only works for SPD, MPEG, ACP areas, ignore return status cap_SiI9031_set_info_frame_receive_type(pHDMI->pChip->instance.pSiI9031, offset, next_type); } break; case cap_chip_AD9380: err = cap_AD9380_read_info_frame(pHDMI->pChip->instance.pAD9380, type, header, data, size); checksum_available = FALSE; break; default: err = RM_ERROR; } if (RMFAILED(err)) { RMDBGLOG((FUNCNAME, "%s return ERROR \n",__func__)); return err; } if (checksum_available && (header[0] & 0x80)) { // CEA861 info frame: calculate checksum checksum = 0; for (i = 0; i < 3; i++) checksum += header[i]; for (i = 0; i < RMmin((RMuint32)header[2] + 1, size); i++) checksum += data[i]; } else { // HDMI packet: no checksum checksum = 0; } if (checksum & 0xFF) { if (header[0]) { RMDBGPRINT((ENABLE, "info frame checksum error at 0x%02X, type 0x%02X: 0x%02lX\n", offset, header[0], checksum & 0xFF)); } if (honor_checksum) return RM_ERROR; } if ((type && (header[0] != type)) || (version && (header[1] != version))) { if (header[0]) { RMDBGLOG((ENABLE, "Error, wrong Info Frame Type/Version: 0x%02X/0x%02X\n", header[0], header[1])); RMDBGPRINT((ENABLE, "type=0x%02lX ", header[0])); RMDBGPRINT((ENABLE, " ver=0x%02lX ", header[1])); RMDBGPRINT((ENABLE, " len=0x%02lX ", header[2])); RMDBGPRINT((ENABLE, " chk=0x%02X ", data[0])); for (i = 1; i < size; i++) { RMDBGPRINT((ENABLE, "%4l=0x%02X ", i, data[i])); } RMDBGPRINT((ENABLE, "\n")); } if (honor_checksum) return RM_ERROR; } return RM_OK;}/* signal intent to read the next available info frame of the specified 'type' */RMstatus cap_hdmi_prepare_info_frame( struct cap_hdmi_instance *pHDMI, RMuint8 type){ RMstatus err; RMuint8 offset; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pHDMI == NULL) return RM_FATALINVALIDPOINTER; switch (pHDMI->pChip->chip) { case cap_chip_SiI9031: // translate type to SiI9031 offset err = cap_SiI9031_get_info_frame_offset(pHDMI->pChip->instance.pSiI9031, type, &offset); if (RMFAILED(err)) return err; // prepare receive area err = cap_SiI9031_set_info_frame_receive_type(pHDMI->pChip->instance.pSiI9031, offset, type); break; case cap_chip_AD9380: err = RM_NOTIMPLEMENTED; // TODO break; default: err = RM_ERROR; } return err;}/*** Parsing Info Frames ***//* parses an AVI data block into a struct cap_hdmi_avi_info */void cap_hdmi_parse_avi_struct(RMuint8 *avi_data, struct cap_hdmi_avi_info *avi){ RMDBGLOG((FUNCNAME, "%s\n",__func__)); avi->valid = TRUE; avi->color_format = (avi_data[1] >> 5) & 0x03; avi->active_format = (avi_data[1] & 0x10) | (avi_data[2] & 0x0F); avi->h_bar = (avi_data[1] & 0x08) ? TRUE : FALSE; avi->v_bar = (avi_data[1] & 0x04) ? TRUE : FALSE; avi->scan_info = avi_data[1] & 0x03; avi->color_space = (avi_data[2] >> 6) & 0x03; avi->aspect_ratio = (avi_data[2] >> 4) & 0x03; avi->scaling = avi_data[3] & 0x03; avi->quantisation = (avi_data[3] >> 2) & 0x03; avi->ext_col = (avi_data[3] >> 4) & 0x07; avi->it_content = (avi_data[3] & 0x80) ? TRUE : FALSE; avi->vic = avi_data[4] & 0x7F; avi->pixel_rep = avi_data[5] & 0x0F; avi->top = (avi_data[7] << 8) | avi_data[6]; avi->bottom = (avi_data[9] << 8) | avi_data[8]; avi->left = (avi_data[11] << 8) | avi_data[10]; avi->right = (avi_data[13] << 8) | avi_data[12];}/* debug print of the AVI Info Frame, formatted same as the table in CEA-861 */RMstatus cap_hdmi_print_avi_info_frame( struct cap_hdmi_instance *pHDMI, RMuint8 *avi_header, RMuint8 *avi_data, struct cap_hdmi_avi_info *avi){ RMstatus err; struct cap_hdmi_avi_info avi_info; RMuint8 header[3], data[16]; RMDBGLOG((FUNCNAME, "%s\n",__func__)); if ((avi_data == NULL) && (avi_header == NULL)) { if (pHDMI == NULL) return RM_FATALINVALIDPOINTER; err = cap_hdmi_read_info_frame(pHDMI, 0x82, 0x00, header, data, sizeof(data) / sizeof(RMuint8), FALSE); if (RMSUCCEEDED(err)) { avi_data = data; avi_header = header; } else { RMDBGPRINT((ENABLE, "Error, can not read AVI info frame from HDMI chip!\n")); return err; } } if (avi == NULL) { avi = &avi_info; cap_hdmi_parse_avi_struct(avi_data, avi); } //RMDBGPRINT((ENABLE, "\017")); if (0) { RMuint32 i; for(i=32;i<256;i++){ if((i&15)==0)RMDBGPRINT((ENABLE,"%lu: ",i)); RMDBGPRINT((ENABLE,"%c",(RMascii)i)); if((i&15)==15)RMDBGPRINT((ENABLE,"\n")); } } //RMDBGPRINT((ENABLE, "\016")); //RMDBGPRINT((ENABLE, "\033)B\033%%@")); RMDBGPRINT((ENABLE, "+-----------------------------------------------+\n")); if (avi_header) { RMDBGPRINT((ENABLE, "| AVI Info Frame, Type 0x%02X Version 0x%02X Len %2u |\n", avi_header[0], avi_header[1], avi_header[2])); } else { RMDBGPRINT((ENABLE, "| AVI Info Frame |\n")); } RMDBGPRINT((ENABLE, "+-----+-----+-----+-----+-----+-----+-----+-----+\n")); RMDBGPRINT((ENABLE, "| %u | Y=%lu (%s)) | A=%u |Bh=%u |Bv=%u |Su=%u |So=%u |\n", (avi_data[1]&0x80)?1:0, avi->color_format, (avi->color_format==0)?"RGB":(avi->color_format==1)?"422":(avi->color_format==2)?"444":"inv", (avi->active_format&0x10)?1:0, avi->h_bar?1:0, avi->v_bar?1:0, (avi->scan_info&0x02)?1:0, (avi->scan_info&0x01)?1:0)); //RMDBGPRINT((ENABLE, "+-----+-----+-----+-----+-----+-----+-----+-----+\n")); RMDBGPRINT((ENABLE, "| C=%lu%-6s | M=%lu%-7s| R=0x%01lX (%s |\n", avi->color_space, (avi->color_space==0)?"(None)":(avi->color_space==1)?" (601)":(avi->color_space==2)?" (709)":" (Ext)", avi->aspect_ratio, (avi->aspect_ratio==0)?"(None)":(avi->aspect_ratio==1)?" (4:3)":(avi->aspect_ratio==2)?"(16:9)":"(Future", avi->active_format&0x0F, ((avi->active_format&0x0F) == DH_af_reserved_0) ? "no info) " : ((avi->active_format&0x0F) == DH_af_16x9_top) ? "16:9top) " : ((avi->active_format&0x0F) == DH_af_14x9_top) ? "14:9top) " : ((avi->active_format&0x0F) == DH_af_64x27_centered) ? "64:27) " : ((avi->active_format&0x0F) == DH_af_same_as_picture) ? "same) " : ((avi->active_format&0x0F) == DH_af_4x3_centered) ? "4:3) " : ((avi->active_format&0x0F) == DH_af_16x9_centered) ? "16:9) " : ((avi->active_format&0x0F) == DH_af_14x9_centered) ? "14:9) " : ((avi->active_format&0x0F) == DH_af_4x3_centered_prot_14x9) ? "4:3/14:9) " : ((avi->active_format&0x0F) == DH_af_16x9_centered_prot_14x9) ? "16:9/14:9)" : ((avi->active_format&0x0F) == DH_af_16x9_centered_prot_4x3) ? "16:9/4:3) " : "unknown) ")); //RMDBGPRINT((ENABLE, "+-----+-----+-----+-----+-----+-----+-----+-----+\n")); RMDBGPRINT((ENABLE, "|ITC=%u| EC=%lu (%s) | Q=%lu (%s) |SCv=%u|SCh=%u|\n", avi->it_content?1:0, avi->ext_col, (avi->ext_col==0)?"xv601":(avi->ext_col==1)?"xv709":"resvd", avi->quantisation, (avi->quantisation==0)?"Def":(avi->quantisation==1)?"Lim":(avi->quantisation==2)?"Ful":"Res", (avi->scaling&0x02)?1:0, (avi->scaling&0x01)?1:0)); //RMDBGPRINT((ENABLE, "+-----+-----+-----+-----+-----+-----+-----+-----+\n")); RMDBGPRINT((ENABLE, "| %u | VIC=%02lu %-19s |\n", (avi_data[4]&0x80)?1:0, avi->vic, CEA861VICNames[avi->vic])); //RMDBGPRINT((ENABLE, "+-----+-----+-----+-----+-----+-----+-----+-----+\n")); RMDBGPRINT((ENABLE, "| %u | %u | %u | %u | PR=%-2lu |\n", (avi_data[5]&0x80)?1:0, (avi_data[5]&0x40)?1:0, (avi_data[5]&0x20)?1:0, (avi_data[5]&0x10)?1:0, avi->pixel_rep)); //RMDBGPRINT((ENABLE, "+-----+-----+-----+-----+-----+-----+-----+-----+\n")); RMDBGPRINT((ENABLE, "| Top hBar = %-5lu | Bottom hBar = %-5lu |\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -