예제 #1
0
/*
 * 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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}