st/omx/dec: set dst rect to match src size
[mesa.git] / src / gallium / state_trackers / omx / vid_dec.c
index 9e7e7ba77878f76ccc3d410465ea13812b26ecb1..f782263bda9a150eedb35a5f29d3ff2122e8304a 100644 (file)
@@ -48,6 +48,7 @@
 #include "pipe/p_video_codec.h"
 #include "util/u_memory.h"
 #include "util/u_surface.h"
+#include "vl/vl_video_buffer.h"
 #include "vl/vl_vlc.h"
 
 #include "entrypoint.h"
@@ -140,7 +141,7 @@ static OMX_ERRORTYPE vid_dec_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING nam
 
    r = omx_base_filter_Constructor(comp, name);
    if (r)
-       return r;
+      return r;
 
    priv->profile = PIPE_VIDEO_PROFILE_UNKNOWN;
 
@@ -162,10 +163,23 @@ static OMX_ERRORTYPE vid_dec_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING nam
       return OMX_ErrorInsufficientResources;
 
    screen = priv->screen->pscreen;
-   priv->pipe = screen->context_create(screen, priv->screen);
+   priv->pipe = screen->context_create(screen, priv->screen, 0);
    if (!priv->pipe)
       return OMX_ErrorInsufficientResources;
 
+   if (!vl_compositor_init(&priv->compositor, priv->pipe)) {
+      priv->pipe->destroy(priv->pipe);
+      priv->pipe = NULL;
+      return OMX_ErrorInsufficientResources;
+   }
+
+   if (!vl_compositor_init_state(&priv->cstate, priv->pipe)) {
+      vl_compositor_cleanup(&priv->compositor);
+      priv->pipe->destroy(priv->pipe);
+      priv->pipe = NULL;
+      return OMX_ErrorInsufficientResources;
+   }
+
    priv->sPortTypesParam[OMX_PortDomainVideo].nStartPortNumber = 0;
    priv->sPortTypesParam[OMX_PortDomainVideo].nPorts = 2;
    priv->ports = CALLOC(2, sizeof(omx_base_PortType *));
@@ -217,8 +231,11 @@ static OMX_ERRORTYPE vid_dec_Destructor(OMX_COMPONENTTYPE *comp)
       priv->ports=NULL;
    }
 
-   if (priv->pipe)
+   if (priv->pipe) {
+      vl_compositor_cleanup_state(&priv->cstate);
+      vl_compositor_cleanup(&priv->compositor);
       priv->pipe->destroy(priv->pipe);
+   }
 
    if (priv->screen)
       omx_put_screen();
@@ -268,7 +285,7 @@ static OMX_ERRORTYPE vid_dec_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE i
       r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE));
       if (r)
          return r;
+
       if (!strcmp((char *)role->cRole, OMX_VID_DEC_MPEG2_ROLE)) {
          priv->profile = PIPE_VIDEO_PROFILE_MPEG2_MAIN;
       } else if (!strcmp((char *)role->cRole, OMX_VID_DEC_AVC_ROLE)) {
@@ -321,7 +338,7 @@ static OMX_ERRORTYPE vid_dec_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE i
          strcpy((char *)role->cRole, OMX_VID_DEC_MPEG2_ROLE);
       else if (priv->profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH)
          strcpy((char *)role->cRole, OMX_VID_DEC_AVC_ROLE);
+
       break;
    }
 
@@ -385,16 +402,38 @@ static OMX_ERRORTYPE vid_dec_MessageHandler(OMX_COMPONENTTYPE* comp, internalReq
 void vid_dec_NeedTarget(vid_dec_PrivateType *priv)
 {
    struct pipe_video_buffer templat = {};
+   struct vl_screen *omx_screen;
+   struct pipe_screen *pscreen;
    omx_base_video_PortType *port;
 
+   omx_screen = priv->screen;
    port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
 
+   assert(omx_screen);
+   assert(port);
+
+   pscreen = omx_screen->pscreen;
+
+   assert(pscreen);
+
    if (!priv->target) {
-      templat.buffer_format = PIPE_FORMAT_NV12;
+      memset(&templat, 0, sizeof(templat));
+
       templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
       templat.width = port->sPortParam.format.video.nFrameWidth;
       templat.height = port->sPortParam.format.video.nFrameHeight;
-      templat.interlaced = false;
+      templat.buffer_format = pscreen->get_video_param(
+            pscreen,
+            PIPE_VIDEO_PROFILE_UNKNOWN,
+            PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
+            PIPE_VIDEO_CAP_PREFERED_FORMAT
+      );
+      templat.interlaced = pscreen->get_video_param(
+          pscreen,
+          PIPE_VIDEO_PROFILE_UNKNOWN,
+          PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
+          PIPE_VIDEO_CAP_PREFERS_INTERLACED
+      );
       priv->target = priv->pipe->create_video_buffer(priv->pipe, &templat);
    }
 }
@@ -419,6 +458,7 @@ static OMX_ERRORTYPE vid_dec_DecodeBuffer(omx_base_PortType *port, OMX_BUFFERHEA
    priv->in_buffers[i] = buf;
    priv->sizes[i] = buf->nFilledLen;
    priv->inputs[i] = buf->pBuffer;
+   priv->timestamps[i] = buf->nTimeStamp;
 
    while (priv->num_in_buffers > (!!(buf->nFlags & OMX_BUFFERFLAG_EOS) ? 0 : 1)) {
       bool eos = !!(priv->in_buffers[0]->nFlags & OMX_BUFFERFLAG_EOS);
@@ -469,12 +509,13 @@ static OMX_ERRORTYPE vid_dec_DecodeBuffer(omx_base_PortType *port, OMX_BUFFERHEA
          priv->in_buffers[0] = priv->in_buffers[1];
          priv->sizes[0] = priv->sizes[1] - delta;
          priv->inputs[0] = priv->inputs[1] + delta;
+         priv->timestamps[0] = priv->timestamps[1];
       }
 
       if (r)
          return r;
    }
+
    return OMX_ErrorNone;
 }
 
@@ -491,34 +532,63 @@ static void vid_dec_FillOutput(vid_dec_PrivateType *priv, struct pipe_video_buff
    OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;
 
    struct pipe_sampler_view **views;
-   struct pipe_transfer *transfer;
-   struct pipe_box box = { };
-   uint8_t *src, *dst;
+   unsigned i, j;
+   unsigned width, height;
 
    views = buf->get_sampler_view_planes(buf);
 
-   dst = output->pBuffer;
+   for (i = 0; i < 2 /* NV12 */; i++) {
+      if (!views[i]) continue;
+      width = def->nFrameWidth;
+      height = def->nFrameHeight;
+      vl_video_buffer_adjust_size(&width, &height, i, buf->chroma_format, buf->interlaced);
+      for (j = 0; j < views[i]->texture->array_size; ++j) {
+         struct pipe_box box = {0, 0, j, width, height, 1};
+         struct pipe_transfer *transfer;
+         uint8_t *map, *dst;
+         map = priv->pipe->transfer_map(priv->pipe, views[i]->texture, 0,
+                  PIPE_TRANSFER_READ, &box, &transfer);
+         if (!map)
+            return;
+
+         dst = ((uint8_t*)output->pBuffer + output->nOffset) + j * def->nStride +
+               i * def->nFrameWidth * def->nFrameHeight;
+         util_copy_rect(dst,
+            views[i]->texture->format,
+            def->nStride * views[i]->texture->array_size, 0, 0,
+            box.width, box.height, map, transfer->stride, 0, 0);
+
+         pipe_transfer_unmap(priv->pipe, transfer);
+      }
+   }
+}
+
+static void vid_dec_deint(vid_dec_PrivateType *priv, struct pipe_video_buffer *src_buf,
+                          struct pipe_video_buffer *dst_buf)
+{
+   struct vl_compositor *compositor = &priv->compositor;
+   struct vl_compositor_state *s = &priv->cstate;
+   struct pipe_surface **dst_surface;
+   struct u_rect dst_rect;
+
+   dst_surface = dst_buf->get_surfaces(dst_buf);
+   vl_compositor_clear_layers(s);
 
-   box.width = def->nFrameWidth;
-   box.height = def->nFrameHeight;
-   box.depth = 1;
+   dst_rect.x0 = 0;
+   dst_rect.x1 = src_buf->width;
+   dst_rect.y0 = 0;
+   dst_rect.y1 = src_buf->height;
 
-   src = priv->pipe->transfer_map(priv->pipe, views[0]->texture, 0,
-                                  PIPE_TRANSFER_READ, &box, &transfer);
-   util_copy_rect(dst, views[0]->texture->format, def->nStride, 0, 0,
-                  box.width, box.height, src, transfer->stride, 0, 0);
-   pipe_transfer_unmap(priv->pipe, transfer);
+   vl_compositor_set_yuv_layer(s, compositor, 0, src_buf, NULL, NULL, true);
+   vl_compositor_set_layer_dst_area(s, 0, &dst_rect);
+   vl_compositor_render(s, compositor, dst_surface[0], NULL, false);
 
-   dst = ((uint8_t*)output->pBuffer) + (def->nStride * box.height);
+   dst_rect.x1 /= 2;
+   dst_rect.y1 /= 2;
 
-   box.width = def->nFrameWidth / 2;
-   box.height = def->nFrameHeight / 2;
-   src = priv->pipe->transfer_map(priv->pipe, views[1]->texture, 0,
-                                  PIPE_TRANSFER_READ, &box, &transfer);
-   util_copy_rect(dst, views[1]->texture->format, def->nStride, 0, 0,
-                  box.width, box.height, src, transfer->stride, 0, 0);
-   pipe_transfer_unmap(priv->pipe, transfer);
+   vl_compositor_set_yuv_layer(s, compositor, 0, src_buf, NULL, NULL, false);
+   vl_compositor_set_layer_dst_area(s, 0, &dst_rect);
+   vl_compositor_render(s, compositor, dst_surface[1], NULL, false);
 }
 
 static void vid_dec_FrameDecoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input,
@@ -526,19 +596,50 @@ static void vid_dec_FrameDecoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE*
 {
    vid_dec_PrivateType *priv = comp->pComponentPrivate;
    bool eos = !!(input->nFlags & OMX_BUFFERFLAG_EOS);
+   OMX_TICKS timestamp;
 
-   if (!input->pInputPortPrivate)
-      input->pInputPortPrivate = priv->Flush(priv);
+   if (!input->pInputPortPrivate) {
+      input->pInputPortPrivate = priv->Flush(priv, &timestamp);
+      if (timestamp != OMX_VID_DEC_TIMESTAMP_INVALID)
+         input->nTimeStamp = timestamp;
+   }
 
    if (input->pInputPortPrivate) {
       if (output->pInputPortPrivate) {
-         struct pipe_video_buffer *tmp = output->pOutputPortPrivate;
+         struct pipe_video_buffer *tmp, *vbuf, *new_vbuf;
+
+         tmp = output->pOutputPortPrivate;
+         vbuf = input->pInputPortPrivate;
+         if (vbuf->interlaced) {
+            /* re-allocate the progressive buffer */
+            omx_base_video_PortType *port;
+            struct pipe_video_buffer templat = {};
+
+            port = (omx_base_video_PortType *)
+                    priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
+            memset(&templat, 0, sizeof(templat));
+            templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
+            templat.width = port->sPortParam.format.video.nFrameWidth;
+            templat.height = port->sPortParam.format.video.nFrameHeight;
+            templat.buffer_format = PIPE_FORMAT_NV12;
+            templat.interlaced = false;
+            new_vbuf = priv->pipe->create_video_buffer(priv->pipe, &templat);
+
+            /* convert the interlaced to the progressive */
+            vid_dec_deint(priv, input->pInputPortPrivate, new_vbuf);
+            priv->pipe->flush(priv->pipe, NULL, 0);
+
+            /* set the progrssive buffer for next round */
+            vbuf->destroy(vbuf);
+            input->pInputPortPrivate = new_vbuf;
+         }
          output->pOutputPortPrivate = input->pInputPortPrivate;
          input->pInputPortPrivate = tmp;
       } else {
          vid_dec_FillOutput(priv, input->pInputPortPrivate, output);
       }
       output->nFilledLen = output->nAllocLen;
+      output->nTimeStamp = input->nTimeStamp;
    }
 
    if (eos && input->pInputPortPrivate)