/* * returns one or a combination of VC_ messages * pData and iSize can be NULL, this means we should flush the rest of the data. */ int CDVDVideoCodecA10::Decode(BYTE* pData, int iSize, double dts, double pts) { s32 ret; u8 *buf0, *buf1; u32 bufsize0, bufsize1; cedarv_stream_data_info_t dinf; cedarv_picture_t picture; if (!pData) return VC_BUFFER; if (!m_hcedarv) return VC_ERROR; ret = m_hcedarv->request_write(m_hcedarv, iSize, &buf0, &bufsize0, &buf1, &bufsize1); if(ret < 0) { CLog::Log(LOGERROR, "A10: request_write failed.\n"); return VC_ERROR; } if (bufsize1) { memcpy(buf0, pData, bufsize0); memcpy(buf1, pData+bufsize0, bufsize1); } else { memcpy(buf0, pData, iSize); } memset(&dinf, 0, sizeof(dinf)); dinf.lengh = iSize; #ifdef CEDARV_FLAG_DECODE_NO_DELAY dinf.flags = CEDARV_FLAG_FIRST_PART | CEDARV_FLAG_LAST_PART | CEDARV_FLAG_DECODE_NO_DELAY; #else dinf.flags = CEDARV_FLAG_FIRST_PART | CEDARV_FLAG_LAST_PART; #endif m_hcedarv->update_data(m_hcedarv, &dinf); ret = m_hcedarv->decode(m_hcedarv); if (ret > 3 || ret < 0) { CLog::Log(LOGERROR, "A10: decode(%d): %d\n", iSize, ret); } if (ret == 4) { pthread_mutex_lock(&m_dispq_mutex); CLog::Log(LOGNOTICE, "A10: Out of decoder frame buffers. Freeing the queue.\n"); // DvdPlayer is dropping/queueing more frames then libcedarv has // frame buffers. Free the decoder frame queue. // The next few frames in the display queue will get overwritten, // but better than stopping the flow. for (int i = 0; i < DISPQS; i++) { if ((int)m_dispq[i].picture.id != -1) { m_hcedarv->display_release(m_hcedarv, m_dispq[i].picture.id); m_dispq[i].picture.id = -1; } } pthread_mutex_unlock(&m_dispq_mutex); return VC_ERROR; } ret = m_hcedarv->display_request(m_hcedarv, &picture); if (ret > 3 || ret < -1) { CLog::Log(LOGERROR, "A10: display_request(%d): %d\n", iSize, ret); } if (ret == 0) { float aspect_ratio = m_aspect; m_picture.pts = pts; m_picture.dts = dts; m_picture.iWidth = picture.display_width; m_picture.iHeight = picture.display_height; if (picture.is_progressive) m_picture.iFlags &= ~DVP_FLAG_INTERLACED; else m_picture.iFlags |= DVP_FLAG_INTERLACED; /* XXX: we suppose the screen has a 1.0 pixel ratio */ // CDVDVideo will compensate it. if (aspect_ratio <= 0.0) aspect_ratio = (float)m_picture.iWidth / (float)m_picture.iHeight; m_picture.iDisplayHeight = m_picture.iHeight; m_picture.iDisplayWidth = ((int)lrint(m_picture.iHeight * aspect_ratio)) & -3; if (m_picture.iDisplayWidth > m_picture.iWidth) { m_picture.iDisplayWidth = m_picture.iWidth; m_picture.iDisplayHeight = ((int)lrint(m_picture.iWidth / aspect_ratio)) & -3; } if (m_hwrender) { pthread_mutex_lock(&m_dispq_mutex); A10VideoBuffer *buffer = &m_dispq[m_wridx]; buffer->codec = this; buffer->decnr = m_decnr++; buffer->picture = picture; m_picture.format = RENDER_FMT_A10BUF; m_picture.a10buffer = buffer; m_picture.iFlags |= DVP_FLAG_ALLOCATED; m_wridx++; if (m_wridx >= DISPQS) m_wridx = 0; pthread_mutex_unlock(&m_dispq_mutex); //CLog::Log(LOGDEBUG, "A10: decode %d\n", buffer->picture.id); } else { ScalerParameter cdx_scaler_para; u32 width32; u32 height32; u32 height64; u32 ysize; u32 csize; m_picture.format = RENDER_FMT_YUV420P; width32 = (picture.display_width + 31) & ~31; height32 = (picture.display_height + 31) & ~31; height64 = (picture.display_height + 63) & ~63; ysize = width32*height32; //* for y. csize = width32*height64/2; //* for u and v together. if (!m_yuvdata) { m_yuvdata = (u8*)mem_palloc(ysize + csize, 1024); if (!m_yuvdata) { CLog::Log(LOGERROR, "A10: can not alloc m_yuvdata!"); m_hcedarv->display_release(m_hcedarv, picture.id); return VC_ERROR; } } cdx_scaler_para.width_in = picture.display_width; cdx_scaler_para.height_in = picture.display_height; cdx_scaler_para.addr_y_in = mem_get_phy_addr((u32)picture.y); cdx_scaler_para.addr_c_in = mem_get_phy_addr((u32)picture.u); cdx_scaler_para.width_out = picture.display_width; cdx_scaler_para.height_out = picture.display_height; cdx_scaler_para.addr_y_out = mem_get_phy_addr((u32)m_yuvdata); cdx_scaler_para.addr_u_out = cdx_scaler_para.addr_y_out + ysize; cdx_scaler_para.addr_v_out = cdx_scaler_para.addr_u_out + csize/2; if (!(m_picture.iFlags & DVP_FLAG_ALLOCATED)) { u32 width16 = (picture.display_width + 15) & ~15; m_picture.iFlags |= DVP_FLAG_ALLOCATED; m_picture.iLineSize[0] = width16; //Y m_picture.iLineSize[1] = width16/2; //U m_picture.iLineSize[2] = width16/2; //V m_picture.iLineSize[3] = 0; m_picture.data[0] = m_yuvdata; m_picture.data[1] = m_yuvdata+ysize; m_picture.data[2] = m_yuvdata+ysize+csize/2; #ifdef A10DEBUG CLog::Log(LOGDEBUG, "A10: p1=%d %d %d %d (%d)\n", picture.width, picture.height, picture.display_width, picture.display_height, picture.pixel_format); CLog::Log(LOGDEBUG, "A10: p2=%d %d %d %d\n", m_picture.iWidth, m_picture.iHeight, m_picture.iDisplayWidth, m_picture.iDisplayHeight); #endif } if (!HardwarePictureScaler(&cdx_scaler_para)) { CLog::Log(LOGERROR, "A10: hardware scaler failed.\n"); m_hcedarv->display_release(m_hcedarv, picture.id); return VC_ERROR; } m_hcedarv->display_release(m_hcedarv, picture.id); } return VC_PICTURE | VC_BUFFER; } return VC_BUFFER; }
void CDVDVideoCodecA10::RenderBuffer(A10VideoBuffer *buffer, CRect &srcRect, CRect &dstRect) { unsigned long args[4]; __disp_layer_info_t layera; __disp_video_fb_t frmbuf; __disp_colorkey_t colorkey; int curnr; if (buffer->decnr == m_prevnr) return; memset(&frmbuf, 0, sizeof(__disp_video_fb_t )); frmbuf.interlace = buffer->picture.is_progressive? 0 : 1; frmbuf.top_field_first = buffer->picture.top_field_first; //frmbuf.frame_rate = buffer->picture.frame_rate; frmbuf.addr[0] = mem_get_phy_addr((u32)buffer->picture.y); frmbuf.addr[1] = mem_get_phy_addr((u32)buffer->picture.u); frmbuf.id = buffer->decnr; if (m_firstframe) { int screen_width, screen_height; //query screen dimensions args[0] = m_scrid; args[1] = 0; args[2] = 0; args[3] = 0; screen_width = ioctl(m_hdisp, DISP_CMD_SCN_GET_WIDTH, args); args[0] = m_scrid; args[1] = 0; args[2] = 0; args[3] = 0; screen_height = ioctl(m_hdisp, DISP_CMD_SCN_GET_HEIGHT, args); memset(&layera, 0, sizeof(layera)); //set video layer attribute layera.mode = DISP_LAYER_WORK_MODE_SCALER; layera.b_from_screen = 0; //what is this? if enabled all is black layera.pipe = 1; //use alpha blend layera.alpha_en = 0; layera.alpha_val = 0xff; layera.ck_enable = 0; layera.b_trd_out = 0; layera.out_trd_mode = (__disp_3d_out_mode_t)0; //frame buffer pst and size information if (buffer->picture.display_height < 720) { layera.fb.cs_mode = DISP_BT601; } else { layera.fb.cs_mode = DISP_BT709; } layera.fb.mode = DISP_MOD_MB_UV_COMBINED; layera.fb.format = buffer->picture.pixel_format == CEDARV_PIXEL_FORMAT_AW_YUV422 ? DISP_FORMAT_YUV422 : DISP_FORMAT_YUV420; layera.fb.br_swap = 0; layera.fb.seq = DISP_SEQ_UVUV; layera.fb.addr[0] = frmbuf.addr[0]; layera.fb.addr[1] = frmbuf.addr[1]; layera.fb.b_trd_src = 0; layera.fb.trd_mode = (__disp_3d_src_mode_t)0; layera.fb.size.width = buffer->picture.display_width; layera.fb.size.height = buffer->picture.display_height; //source window information layera.src_win.x = lrint(srcRect.x1); layera.src_win.y = lrint(srcRect.y1); layera.src_win.width = lrint(srcRect.x2-srcRect.x1); layera.src_win.height = lrint(srcRect.y2-srcRect.y1); //screen window information layera.scn_win.x = lrint(dstRect.x1); layera.scn_win.y = lrint(dstRect.y1); layera.scn_win.width = lrint(dstRect.x2-dstRect.x1); layera.scn_win.height = lrint(dstRect.y2-dstRect.y1); CLog::Log(LOGDEBUG, "A10: srcRect=(%lf,%lf)-(%lf,%lf)\n", srcRect.x1, srcRect.y1, srcRect.x2, srcRect.y2); CLog::Log(LOGDEBUG, "A10: dstRect=(%lf,%lf)-(%lf,%lf)\n", srcRect.x1, srcRect.y1, srcRect.x2, srcRect.y2); if ((layera.scn_win.x < 0) || (layera.scn_win.y < 0)) { CLog::Log(LOGERROR, "A10: oops, bad dimensions\n"); //TODO: //dvdplayer is giving negative values in the destination rect. //we can not do that, so we have to adjust the source rect. //header file says that only width and height can be used //in scaler mode. } args[0] = m_scrid; args[1] = m_hlayer; args[2] = (unsigned long)&layera; args[3] = 0; if(ioctl(m_hdisp, DISP_CMD_LAYER_SET_PARA, args)) CLog::Log(LOGERROR, "A10: DISP_CMD_LAYER_SET_PARA failed.\n"); //open layer args[0] = m_scrid; args[1] = m_hlayer; args[2] = 0; args[3] = 0; if (ioctl(m_hdisp, DISP_CMD_LAYER_OPEN, args)) CLog::Log(LOGERROR, "A10: DISP_CMD_LAYER_OPEN failed.\n"); //put behind system layer args[0] = m_scrid; args[1] = m_hlayer; args[2] = 0; args[3] = 0; if (ioctl(m_hdisp, DISP_CMD_LAYER_BOTTOM, args)) CLog::Log(LOGERROR, "A10: DISP_CMD_LAYER_BOTTOM failed.\n"); //turn off colorkey (system layer) args[0] = m_scrid; args[1] = 0x64; args[2] = 0; args[3] = 0; if (ioctl(m_hdisp, DISP_CMD_LAYER_CK_OFF, args)) CLog::Log(LOGERROR, "A10: DISP_CMD_LAYER_CK_OFF failed.\n"); if ((screen_height > 720) && (getenv("A10AB") == NULL)) { //no tearing at the cost off alpha blending... //set colorkey colorkey.ck_min.alpha = 0; colorkey.ck_min.red = 1; colorkey.ck_min.green = 2; colorkey.ck_min.blue = 3; colorkey.ck_max = colorkey.ck_min; colorkey.ck_max.alpha = 255; colorkey.red_match_rule = 2; colorkey.green_match_rule = 2; colorkey.blue_match_rule = 2; args[0] = m_scrid; args[1] = (unsigned long)&colorkey; args[2] = 0; args[3] = 0; if (ioctl(m_hdisp, DISP_CMD_SET_COLORKEY, args)) CLog::Log(LOGERROR, "A10: DISP_CMD_SET_COLORKEY failed.\n"); //turn on colorkey args[0] = m_scrid; args[1] = m_hlayer; args[2] = 0; args[3] = 0; if (ioctl(m_hdisp, DISP_CMD_LAYER_CK_ON, args)) CLog::Log(LOGERROR, "A10: DISP_CMD_LAYER_CK_ON failed.\n"); //turn on global alpha (system layer) args[0] = m_scrid; args[1] = 0x64; args[2] = 0; args[3] = 0; if (ioctl(m_hdisp, DISP_CMD_LAYER_ALPHA_ON, args)) CLog::Log(LOGERROR, "A10: DISP_CMD_LAYER_ALPHA_ON failed.\n"); } else { //turn off global alpha (system layer) args[0] = m_scrid; args[1] = 0x64; args[2] = 0; args[3] = 0; if (ioctl(m_hdisp, DISP_CMD_LAYER_ALPHA_OFF, args)) CLog::Log(LOGERROR, "A10: DISP_CMD_LAYER_ALPHA_OFF failed.\n"); } //start video args[0] = m_scrid; args[1] = m_hlayer; args[2] = 0; args[3] = 0; if (ioctl(m_hdisp, DISP_CMD_VIDEO_START, args)) CLog::Log(LOGERROR, "A10: DISP_CMD_VIDEO_START failed.\n"); } args[0] = m_scrid; args[1] = m_hlayer; args[2] = (unsigned long)&frmbuf; args[3] = 0; if (ioctl(m_hdisp, DISP_CMD_VIDEO_SET_FB, args)) CLog::Log(LOGERROR, "A10: DISP_CMD_VIDEO_SET_FB failed.\n"); //CLog::Log(LOGDEBUG, "A10: render %d\n", buffer->picture.id); args[0] = m_scrid; args[1] = m_hlayer; args[2] = 0; args[3] = 0; curnr = ioctl(m_hdisp, DISP_CMD_VIDEO_GET_FRAME_ID, args); if (curnr != m_lastnr) { //free older frames, displayed or not pthread_mutex_lock(&m_dispq_mutex); for (int i = 0; i < DISPQS; i++) { if(m_dispq[m_rdidx].decnr < curnr) { int id = m_dispq[m_rdidx].picture.id; if (id != -1) { //CLog::Log(LOGDEBUG, "A10: release %d\n", id); m_hcedarv->display_release(m_hcedarv, id); m_dispq[m_rdidx].picture.id = -1; } m_rdidx++; if (m_rdidx >= DISPQS) m_rdidx = 0; } else break; } pthread_mutex_unlock(&m_dispq_mutex); } m_lastnr = curnr; m_prevnr = buffer->decnr; m_firstframe = false; }
static s32 vdecoder_display_request(cedarv_decoder_t* p, cedarv_picture_t* picture) { #if (DISPLAY_FREE_RUN == 0) u32 video_time; #endif vpicture_t* frame; video_decoder_t* decoder; if(p == NULL) return CEDARV_RESULT_ERR_INVALID_PARAM; decoder = (video_decoder_t*)p; if(decoder->fbm == NULL) { if(decoder->ve == NULL) return CEDARV_RESULT_ERR_FAIL; decoder->fbm = libve_get_fbm(decoder->ve); if(decoder->fbm == NULL) return CEDARV_RESULT_ERR_FAIL; } if(decoder->status == CEDARV_STATUS_PREVIEW) frame = fbm_display_request_frame(decoder->fbm); else { #if (DISPLAY_FREE_RUN == 1) frame = fbm_display_request_frame(decoder->fbm); #else if(decoder->display_already_begin == 1) { get_frame_again: frame = fbm_display_pick_frame(decoder->fbm); if(frame != NULL) { if(frame->pts != (u64)(-1)) { video_time = esMODS_MIoctrl(vdrv_com->avsync, DRV_AVS_CMD_GET_VID_TIME, DRV_AVS_TIME_TOTAL, 0); //* get system time. if(decoder->status == CEDARV_STATUS_BACKWARD) { if(video_time > (frame->pts/1000) + DISPLAY_TIME_WINDOW_WIDTH) return -1; //* too early to display. } else { if(video_time + DISPLAY_TIME_WINDOW_WIDTH < (frame->pts/1000)) return -1; //* too early to display. } frame = fbm_display_request_frame(decoder->fbm); if(decoder->status == CEDARV_STATUS_PLAY) { if((frame->pts/1000) + DISPLAY_TIME_WINDOW_WIDTH < video_time) { if(fbm_display_pick_frame(decoder->fbm) != NULL) { fbm_display_return_frame(frame, decoder->fbm); if(p->release_frame_buffer_sem != NULL) p->release_frame_buffer_sem(p->cedarx_cookie); goto get_frame_again; } } } } else { frame = fbm_display_request_frame(decoder->fbm); } } } else { frame = fbm_display_request_frame(decoder->fbm); } #endif } if(frame == NULL) return CEDARV_RESULT_ERR_FAIL; picture->id = frame->id; picture->width = frame->width; picture->height = frame->height; picture->top_offset = frame->top_offset; picture->left_offset = frame->left_offset; picture->display_width = frame->display_width; picture->display_height = frame->display_height; picture->rotate_angle = frame->rotate_angle; picture->horizontal_scale_ratio = frame->horizontal_scale_ratio; picture->vertical_scale_ratio = frame->vertical_scale_ratio; picture->store_width = frame->store_width; picture->store_height = frame->store_height; picture->frame_rate = frame->frame_rate; picture->aspect_ratio = frame->aspect_ratio; picture->is_progressive = frame->is_progressive; picture->top_field_first = frame->top_field_first; picture->repeat_top_field = frame->repeat_top_field; picture->repeat_bottom_field = frame->repeat_bottom_field; picture->size_y = frame->size_y; picture->size_u = frame->size_u; picture->size_v = frame->size_v; if(frame->pixel_format == PIXEL_FORMAT_AW_YUV422) picture->pixel_format = CEDARV_PIXEL_FORMAT_AW_YUV422; else if(frame->pixel_format == PIXEL_FORMAT_AW_YUV411) picture->pixel_format = CEDARV_PIXEL_FORMAT_AW_YUV411; else picture->pixel_format = CEDARV_PIXEL_FORMAT_AW_YUV420; picture->pts = frame->pts; picture->pcr = frame->pcr; //* the CedarX player need we return physic address of display frame. picture->y = mem_get_phy_addr(frame->y); picture->u = mem_get_phy_addr(frame->u); picture->v = NULL; picture->alpha = NULL; decoder->last_frame_index = frame->id; if(decoder->display_already_begin == 0) decoder->display_already_begin = 1; return CEDARV_RESULT_OK; }