static GstVaapiDecoderStatus
decode_picture (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg)
{
  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
  GstJpegFrameHdr *const frame_hdr = &priv->frame_hdr;

  if (!VALID_STATE (decoder, GOT_SOI))
    return GST_VAAPI_DECODER_STATUS_SUCCESS;

  switch (seg->marker) {
    case GST_JPEG_MARKER_SOF_MIN:
      priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE;
      break;
    default:
      GST_ERROR ("unsupported profile %d", seg->marker);
      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
  }

  memset (frame_hdr, 0, sizeof (*frame_hdr));
  if (!gst_jpeg_segment_parse_frame_header (seg, frame_hdr)) {
    GST_ERROR ("failed to parse image");
    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
  }

  if (priv->height != frame_hdr->height || priv->width != frame_hdr->width)
    priv->size_changed = TRUE;

  priv->height = frame_hdr->height;
  priv->width = frame_hdr->width;

  priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_SOF;
  return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
decode_current_picture (GstVaapiDecoderJpeg * decoder)
{
  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
  GstVaapiPicture *const picture = priv->current_picture;

  if (!VALID_STATE (decoder, VALID_PICTURE))
    goto drop_frame;
  priv->decoder_state = 0;

  if (!picture)
    return GST_VAAPI_DECODER_STATUS_SUCCESS;

  if (!gst_vaapi_picture_decode (picture))
    goto error;
  if (!gst_vaapi_picture_output (picture))
    goto error;
  gst_vaapi_picture_replace (&priv->current_picture, NULL);
  return GST_VAAPI_DECODER_STATUS_SUCCESS;

  /* ERRORS */
error:
  {
    gst_vaapi_picture_replace (&priv->current_picture, NULL);
    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
  }

drop_frame:
  {
    priv->decoder_state = 0;
    return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME;
  }
}
示例#3
0
文件: door.c 项目: mortenmj/heis
/* Update the state machine */
void
door_update_state (void)
{
  new_event = get_new_event ();
  if (VALID_STATE(door_current_state) && VALID_EVENT(new_event))
    {
      door_state_table [door_current_state][new_event] ();
    }
}
static GstVaapiDecoderStatus
decode_restart_interval (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg)
{
  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;

  if (!VALID_STATE (decoder, GOT_SOI))
    return GST_VAAPI_DECODER_STATUS_SUCCESS;

  if (!gst_jpeg_segment_parse_restart_interval (seg, &priv->mcu_restart)) {
    GST_ERROR ("failed to parse restart interval");
    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
  }
  return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
decode_quant_table (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg)
{
  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;

  if (!VALID_STATE (decoder, GOT_SOI))
    return GST_VAAPI_DECODER_STATUS_SUCCESS;

  if (!gst_jpeg_segment_parse_quantization_table (seg, &priv->quant_tables)) {
    GST_ERROR ("failed to parse quantization table");
    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
  }

  priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_IQ_TABLE;
  return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
fill_quantization_table (GstVaapiDecoderJpeg * decoder,
    GstVaapiPicture * picture)
{
  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
  VAIQMatrixBufferJPEGBaseline *iq_matrix;
  guint i, j, num_tables;

  if (!VALID_STATE (decoder, GOT_IQ_TABLE))
    gst_jpeg_get_default_quantization_tables (&priv->quant_tables);

  picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (JPEGBaseline, decoder);
  if (!picture->iq_matrix) {
    GST_ERROR ("failed to allocate quantiser table");
    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
  }
  iq_matrix = picture->iq_matrix->param;

  num_tables = MIN (G_N_ELEMENTS (iq_matrix->quantiser_table),
      GST_JPEG_MAX_QUANT_ELEMENTS);

  for (i = 0; i < num_tables; i++) {
    GstJpegQuantTable *const quant_table = &priv->quant_tables.quant_tables[i];

    iq_matrix->load_quantiser_table[i] = quant_table->valid;
    if (!iq_matrix->load_quantiser_table[i])
      continue;

    if (quant_table->quant_precision != 0) {
      // Only Baseline profile is supported, thus 8-bit Qk values
      GST_ERROR ("unsupported quantization table element precision");
      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT;
    }

    for (j = 0; j < GST_JPEG_MAX_QUANT_ELEMENTS; j++)
      iq_matrix->quantiser_table[i][j] = quant_table->quant_table[j];
    iq_matrix->load_quantiser_table[i] = 1;
    quant_table->valid = FALSE;
  }
  return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
gst_vaapi_decoder_jpeg_start_frame (GstVaapiDecoder * base_decoder,
    GstVaapiDecoderUnit * base_unit)
{
  GstVaapiDecoderJpeg *const decoder =
      GST_VAAPI_DECODER_JPEG_CAST (base_decoder);
  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
  GstVaapiPicture *picture;
  GstVaapiDecoderStatus status;

  if (!VALID_STATE (decoder, GOT_SOF))
    return GST_VAAPI_DECODER_STATUS_SUCCESS;

  status = ensure_context (decoder);
  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
    GST_ERROR ("failed to reset context");
    return status;
  }

  picture = GST_VAAPI_PICTURE_NEW (JPEGBaseline, decoder);
  if (!picture) {
    GST_ERROR ("failed to allocate picture");
    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
  }
  gst_vaapi_picture_replace (&priv->current_picture, picture);
  gst_vaapi_picture_unref (picture);

  if (!fill_picture (decoder, picture, &priv->frame_hdr))
    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;

  status = fill_quantization_table (decoder, picture);
  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
    return status;

  /* Update presentation time */
  picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;
  return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
gst_vaapi_decoder_jpeg_parse (GstVaapiDecoder * base_decoder,
    GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
{
  GstVaapiDecoderJpeg *const decoder =
      GST_VAAPI_DECODER_JPEG_CAST (base_decoder);
  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
  GstVaapiParserState *const ps = GST_VAAPI_PARSER_STATE (base_decoder);
  GstVaapiDecoderStatus status;
  GstJpegMarker marker;
  GstJpegSegment seg;
  const guchar *buf;
  guint buf_size, flags;
  gint ofs1, ofs2;

  status = ensure_decoder (decoder);
  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
    return status;

  /* Expect at least 2 bytes for the marker */
  buf_size = gst_adapter_available (adapter);
  if (buf_size < 2)
    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;

  buf = gst_adapter_map (adapter, buf_size);
  if (!buf)
    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;

  ofs1 = ps->input_offset1 - 2;
  if (ofs1 < 0)
    ofs1 = 0;

  for (;;) {
    // Skip any garbage until we reach SOI, if needed
    if (!gst_jpeg_parse (&seg, buf, buf_size, ofs1)) {
      gst_adapter_unmap (adapter);
      ps->input_offset1 = buf_size;
      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
    }
    ofs1 = seg.offset;

    marker = seg.marker;
    if (!VALID_STATE (parser, GOT_SOI) && marker != GST_JPEG_MARKER_SOI)
      continue;
    if (marker == GST_JPEG_MARKER_SOS) {
      ofs2 = ps->input_offset2 - 2;
      if (ofs2 < ofs1 + seg.size)
        ofs2 = ofs1 + seg.size;

      // Parse the whole scan + ECSs, including RSTi
      for (;;) {
        if (!gst_jpeg_parse (&seg, buf, buf_size, ofs2)) {
          gst_adapter_unmap (adapter);
          ps->input_offset1 = ofs1;
          ps->input_offset2 = buf_size;
          return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
        }

        if (is_scan_complete (seg.marker))
          break;
        ofs2 = seg.offset + seg.size;
      }
      ofs2 = seg.offset - 2;
    } else {
      // Check that the whole segment is actually available (in buffer)
      ofs2 = ofs1 + seg.size;
      if (ofs2 > buf_size) {
        gst_adapter_unmap (adapter);
        ps->input_offset1 = ofs1;
        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
      }
    }
    break;
  }
  gst_adapter_unmap (adapter);

  unit->size = ofs2 - ofs1;
  unit_set_marker_code (unit, marker);
  gst_adapter_flush (adapter, ofs1);
  ps->input_offset1 = 2;
  ps->input_offset2 = 2;

  flags = 0;
  switch (marker) {
    case GST_JPEG_MARKER_SOI:
      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
      priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOI;
      break;
    case GST_JPEG_MARKER_EOI:
      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
      priv->parser_state = 0;
      break;
    case GST_JPEG_MARKER_SOS:
      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
      priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOS;
      break;
    case GST_JPEG_MARKER_DAC:
    case GST_JPEG_MARKER_DHT:
    case GST_JPEG_MARKER_DQT:
      if (priv->parser_state & GST_JPEG_VIDEO_STATE_GOT_SOF)
        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
      break;
    case GST_JPEG_MARKER_DRI:
      if (priv->parser_state & GST_JPEG_VIDEO_STATE_GOT_SOS)
        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
      break;
    case GST_JPEG_MARKER_DNL:
      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
      break;
    case GST_JPEG_MARKER_COM:
      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
      break;
    default:
      /* SOFn segments */
      if (marker >= GST_JPEG_MARKER_SOF_MIN &&
          marker <= GST_JPEG_MARKER_SOF_MAX)
        priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOF;

      /* Application segments */
      else if (marker >= GST_JPEG_MARKER_APP_MIN &&
          marker <= GST_JPEG_MARKER_APP_MAX)
        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;

      /* Reserved */
      else if (marker >= 0x02 && marker <= 0xbf)
        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
      break;
  }
  GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
  return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
decode_scan (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg)
{
  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
  GstVaapiPicture *const picture = priv->current_picture;
  GstVaapiSlice *slice;
  VASliceParameterBufferJPEGBaseline *slice_param;
  GstJpegScanHdr scan_hdr;
  guint scan_hdr_size, scan_data_size;
  guint i, h_max, v_max, mcu_width, mcu_height;

  if (!VALID_STATE (decoder, GOT_SOF))
    return GST_VAAPI_DECODER_STATUS_SUCCESS;

  scan_hdr_size = (seg->data[seg->offset] << 8) | seg->data[seg->offset + 1];
  scan_data_size = seg->size - scan_hdr_size;

  memset (&scan_hdr, 0, sizeof (scan_hdr));
  if (!gst_jpeg_segment_parse_scan_header (seg, &scan_hdr)) {
    GST_ERROR ("failed to parse scan header");
    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
  }

  slice = GST_VAAPI_SLICE_NEW (JPEGBaseline, decoder,
      seg->data + seg->offset + scan_hdr_size, scan_data_size);
  if (!slice) {
    GST_ERROR ("failed to allocate slice");
    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
  }
  gst_vaapi_picture_add_slice (picture, slice);

  if (!VALID_STATE (decoder, GOT_HUF_TABLE))
    gst_jpeg_get_default_huffman_tables (&priv->huf_tables);

  // Update VA Huffman table if it changed for this scan
  if (huffman_tables_updated (&priv->huf_tables)) {
    slice->huf_table = GST_VAAPI_HUFFMAN_TABLE_NEW (JPEGBaseline, decoder);
    if (!slice->huf_table) {
      GST_ERROR ("failed to allocate Huffman tables");
      huffman_tables_reset (&priv->huf_tables);
      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
    }
    fill_huffman_table (slice->huf_table, &priv->huf_tables);
    huffman_tables_reset (&priv->huf_tables);
  }

  slice_param = slice->param;
  slice_param->num_components = scan_hdr.num_components;
  for (i = 0; i < scan_hdr.num_components; i++) {
    slice_param->components[i].component_selector =
        scan_hdr.components[i].component_selector;
    slice_param->components[i].dc_table_selector =
        scan_hdr.components[i].dc_selector;
    slice_param->components[i].ac_table_selector =
        scan_hdr.components[i].ac_selector;
  }
  slice_param->restart_interval = priv->mcu_restart;
  slice_param->slice_horizontal_position = 0;
  slice_param->slice_vertical_position = 0;

  get_max_sampling_factors (&priv->frame_hdr, &h_max, &v_max);
  mcu_width = 8 * h_max;
  mcu_height = 8 * v_max;

  if (scan_hdr.num_components == 1) {   // Non-interleaved
    const guint Csj = slice_param->components[0].component_selector;
    const GstJpegFrameComponent *const fcp =
        get_component (&priv->frame_hdr, Csj);

    if (!fcp || fcp->horizontal_factor == 0 || fcp->vertical_factor == 0) {
      GST_ERROR ("failed to validate image component %u", Csj);
      return GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER;
    }
    mcu_width /= fcp->horizontal_factor;
    mcu_height /= fcp->vertical_factor;
  }
  slice_param->num_mcus =
      ((priv->frame_hdr.width + mcu_width - 1) / mcu_width) *
      ((priv->frame_hdr.height + mcu_height - 1) / mcu_height);

  priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_SOS;
  return GST_VAAPI_DECODER_STATUS_SUCCESS;
}