コード例 #1
0
ファイル: libde265-dec.c プロジェクト: 0p1pp1/gst-plugins-bad
static int
gst_libde265_dec_get_buffer (de265_decoder_context * ctx,
    struct de265_image_spec *spec, struct de265_image *img, void *userdata)
{
  GstVideoDecoder *base = (GstVideoDecoder *) userdata;
  GstLibde265Dec *dec = GST_LIBDE265_DEC (base);
  GstVideoCodecFrame *frame = NULL;
  int i;
  int width = spec->width;
  int height = spec->height;
  GstFlowReturn ret;
  struct GstLibde265FrameRef *ref;
  GstVideoInfo *info;
  int frame_number;

  frame_number = (uintptr_t) de265_get_image_user_data (img) - 1;
  if (G_UNLIKELY (frame_number == -1)) {
    /* should not happen... */
    GST_WARNING_OBJECT (base, "Frame has no number assigned!");
    goto fallback;
  }

  frame = gst_video_decoder_get_frame (base, frame_number);
  if (G_UNLIKELY (frame == NULL)) {
    /* should not happen... */
    GST_WARNING_OBJECT (base, "Couldn't get codec frame!");
    goto fallback;
  }

  if (width % spec->alignment) {
    width += spec->alignment - (width % spec->alignment);
  }
  if (width != spec->visible_width || height != spec->visible_height) {
    /* clipping not supported for now */
    goto fallback;
  }

  ret = _gst_libde265_image_available (base, width, height);
  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
    GST_ERROR_OBJECT (dec, "Failed to notify about available image");
    goto fallback;
  }

  ret =
      gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (dec), frame);
  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
    GST_ERROR_OBJECT (dec, "Failed to allocate output buffer");
    goto fallback;
  }

  ref = (struct GstLibde265FrameRef *) g_malloc0 (sizeof (*ref));
  g_assert (ref != NULL);
  ref->decoder = base;
  ref->frame = frame;

  gst_buffer_replace (&ref->buffer, frame->output_buffer);
  gst_buffer_replace (&frame->output_buffer, NULL);

  info = &dec->output_state->info;
  if (!gst_video_frame_map (&ref->vframe, info, ref->buffer, GST_MAP_READWRITE)) {
    GST_ERROR_OBJECT (dec, "Failed to map frame output buffer");
    goto error;
  }

  ref->mapped = TRUE;
  if (GST_VIDEO_FRAME_PLANE_STRIDE (&ref->vframe,
          0) < width * GST_VIDEO_FRAME_COMP_PSTRIDE (&ref->vframe, 0)) {
    GST_DEBUG_OBJECT (dec, "plane 0: pitch too small (%d/%d*%d)",
        GST_VIDEO_FRAME_PLANE_STRIDE (&ref->vframe, 0), width,
        GST_VIDEO_FRAME_COMP_PSTRIDE (&ref->vframe, 0));
    goto error;
  }

  if (GST_VIDEO_FRAME_COMP_HEIGHT (&ref->vframe, 0) < height) {
    GST_DEBUG_OBJECT (dec, "plane 0: lines too few (%d/%d)",
        GST_VIDEO_FRAME_COMP_HEIGHT (&ref->vframe, 0), height);
    goto error;
  }

  for (i = 0; i < 3; i++) {
    uint8_t *data;
    int stride = GST_VIDEO_FRAME_PLANE_STRIDE (&ref->vframe, i);
    if (stride % spec->alignment) {
      GST_DEBUG_OBJECT (dec, "plane %d: pitch not aligned (%d%%%d)",
          i, stride, spec->alignment);
      goto error;
    }

    data = GST_VIDEO_FRAME_PLANE_DATA (&ref->vframe, i);
    if ((uintptr_t) (data) % spec->alignment) {
      GST_DEBUG_OBJECT (dec, "plane %d not aligned", i);
      goto error;
    }

    de265_set_image_plane (img, i, data, stride, ref);
  }
  return 1;

error:
  gst_libde265_dec_release_frame_ref (ref);
  frame = NULL;

fallback:
  if (frame != NULL) {
    gst_video_codec_frame_unref (frame);
  }
  return de265_get_default_image_allocation_functions ()->get_buffer (ctx,
      spec, img, userdata);
}
コード例 #2
0
ファイル: libde265-dec.c プロジェクト: 0p1pp1/gst-plugins-bad
static GstFlowReturn
_gst_libde265_return_image (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame, const struct de265_image *img)
{
  GstLibde265Dec *dec = GST_LIBDE265_DEC (decoder);
  struct GstLibde265FrameRef *ref;
  GstFlowReturn result;
  GstVideoFrame outframe;
  GstVideoCodecFrame *out_frame;
  int frame_number;
  int plane;

  ref = (struct GstLibde265FrameRef *) de265_get_image_plane_user_data (img, 0);
  if (ref != NULL) {
    /* decoder is using direct rendering */
    out_frame = gst_video_codec_frame_ref (ref->frame);
    if (frame != NULL) {
      gst_video_codec_frame_unref (frame);
    }
    gst_buffer_replace (&out_frame->output_buffer, ref->buffer);
    gst_buffer_replace (&ref->buffer, NULL);
    return gst_video_decoder_finish_frame (decoder, out_frame);
  }

  result =
      _gst_libde265_image_available (decoder, de265_get_image_width (img, 0),
      de265_get_image_height (img, 0));
  if (result != GST_FLOW_OK) {
    GST_ERROR_OBJECT (dec, "Failed to notify about available image");
    return result;
  }

  frame_number = (uintptr_t) de265_get_image_user_data (img) - 1;
  if (frame_number != -1) {
    out_frame = gst_video_decoder_get_frame (decoder, frame_number);
  } else {
    out_frame = NULL;
  }
  if (frame != NULL) {
    gst_video_codec_frame_unref (frame);
  }

  if (out_frame == NULL) {
    GST_ERROR_OBJECT (dec, "No frame available to return");
    return GST_FLOW_ERROR;
  }

  result = gst_video_decoder_allocate_output_frame (decoder, out_frame);
  if (result != GST_FLOW_OK) {
    GST_ERROR_OBJECT (dec, "Failed to allocate output frame");
    return result;
  }

  g_assert (dec->output_state != NULL);
  if (!gst_video_frame_map (&outframe, &dec->output_state->info,
          out_frame->output_buffer, GST_MAP_WRITE)) {
    GST_ERROR_OBJECT (dec, "Failed to map output buffer");
    return GST_FLOW_ERROR;
  }

  for (plane = 0; plane < 3; plane++) {
    int width = de265_get_image_width (img, plane);
    int height = de265_get_image_height (img, plane);
    int srcstride = width;
    int dststride = GST_VIDEO_FRAME_COMP_STRIDE (&outframe, plane);
    const uint8_t *src = de265_get_image_plane (img, plane, &srcstride);
    uint8_t *dest = GST_VIDEO_FRAME_COMP_DATA (&outframe, plane);
    if (srcstride == width && dststride == width) {
      memcpy (dest, src, height * width);
    } else {
      while (height--) {
        memcpy (dest, src, width);
        src += srcstride;
        dest += dststride;
      }
    }
  }
  gst_video_frame_unmap (&outframe);
  return gst_video_decoder_finish_frame (decoder, out_frame);
}
コード例 #3
0
static GstFlowReturn gst_libde265_dec_parse_data (VIDEO_DECODER_BASE * parse,
    gboolean at_eos)
#endif
{
    GstLibde265Dec *dec = GST_LIBDE265_DEC (parse);
    const struct de265_image *img;
    de265_error ret = DE265_OK;
    int more = 0;
#if GST_CHECK_VERSION(1,0,0)
    de265_PTS pts = (de265_PTS) frame->pts;
#else
    de265_PTS pts = 0;
#endif
    
    if (dec->buffer_full) {
        // return any pending images before decoding more data
        if ((img = de265_peek_next_picture(dec->ctx)) != NULL) {
            return _gst_libde265_image_available(parse, img);
        }
        dec->buffer_full = 0;
    }
    
#if !GST_CHECK_VERSION(1,0,0)
    GstAdapter *adapter = parse->input_adapter;
#endif
    gsize size = gst_adapter_available (adapter);
    if (size == 0) {
        return NEED_DATA_RESULT;
    }
    
    GstBuffer *buf = gst_adapter_take_buffer(adapter, size);
    uint8_t *frame_data;
    uint8_t *end_data;
#if GST_CHECK_VERSION(1,0,0)
    GstMapInfo info;
    if (!gst_buffer_map(buf, &info, GST_MAP_READWRITE)) {
        return GST_FLOW_ERROR;
    }
    
    frame_data = info.data;
#else
    frame_data = GST_BUFFER_DATA(buf);
#endif
    end_data = frame_data + size;
    
    if (size > 0) {
        if (dec->mode == GST_TYPE_LIBDE265_DEC_PACKETIZED) {
            // replace 4-byte length fields with NAL start codes
            uint8_t *start_data = frame_data;
            while (start_data + 4 <= end_data) {
                int nal_size = READ_BE32(start_data);
                if (start_data + nal_size > end_data) {
                    GST_ELEMENT_ERROR (parse, STREAM, DECODE,
                        ("Overflow in input data, check data mode"),
                        (NULL));
                    goto error;
                }
                ret = de265_push_NAL(dec->ctx, start_data + 4, nal_size, pts, NULL);
                if (ret != DE265_OK) {
                    GST_ELEMENT_ERROR (parse, STREAM, DECODE,
                        ("Error while pushing data: %s (code=%d)", de265_get_error_text(ret), ret),
                        (NULL));
                    goto error;
                }
                start_data += 4 + nal_size;
            }
        } else {
            ret = de265_push_data(dec->ctx, frame_data, size, pts, NULL);
        }
    } else {
        ret = de265_flush_data(dec->ctx);
    }
    
    // decode as much as possible
    do {
        ret = de265_decode(dec->ctx, &more);
    } while (more && ret == DE265_OK);
#if GST_CHECK_VERSION(1,0,0)
    gst_buffer_unmap(buf, &info);
#endif
    gst_buffer_unref(buf);
    switch (ret) {
    case DE265_OK:
        break;

    case DE265_ERROR_IMAGE_BUFFER_FULL:
        dec->buffer_full = 1;
        if ((img = de265_peek_next_picture(dec->ctx)) == NULL) {
            return NEED_DATA_RESULT;
        }
        return _gst_libde265_image_available(parse, img);;

    case DE265_ERROR_WAITING_FOR_INPUT_DATA:
        return NEED_DATA_RESULT;

    default:
        GST_ELEMENT_ERROR (parse, STREAM, DECODE,
            ("Error while decoding: %s (code=%d)", de265_get_error_text(ret), ret),
            (NULL));
        return GST_FLOW_ERROR;
    }
    
    while ((ret = de265_get_warning(dec->ctx)) != DE265_OK) {
        GST_ELEMENT_WARNING (parse, STREAM, DECODE,
            ("%s (code=%d)", de265_get_error_text(ret), ret),
            (NULL));
    }
    
    if ((img = de265_peek_next_picture(dec->ctx)) == NULL) {
        // need more data
        return NEED_DATA_RESULT;
    }
    
    return _gst_libde265_image_available(parse, img);

error:
#if GST_CHECK_VERSION(1,0,0)
    gst_buffer_unmap(buf, &info);
#endif
    gst_buffer_unref(buf);
    return GST_FLOW_ERROR;
}