mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-05 06:58:56 +00:00
jpeg: make gst_jpeg_parse() support multiple scans.
gst_jpeg_parse() now gathers all scans available in the supplied buffer. A scan comprises of the scan header and any entropy-coded segments or restart marker following it. The size and offset to the associated data (ECS + RST segments) are append to a new GstJpegScanOffsetSize structure. Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
This commit is contained in:
parent
53cbdcc1e6
commit
4c5cc7eff9
3 changed files with 115 additions and 105 deletions
|
@ -438,6 +438,41 @@ gst_jpeg_get_default_quantization_table (GstJpegQuantTable *quant_tables, guint
|
||||||
sizeof(GstJpegQuantTable));
|
sizeof(GstJpegQuantTable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gint32
|
||||||
|
jpeg_scan_to_end (const guint8 *start, guint32 size)
|
||||||
|
{
|
||||||
|
const guint8 *pos = start, *end = start + size;
|
||||||
|
|
||||||
|
for (; pos < end; ++pos) {
|
||||||
|
if (*pos != 0xFF)
|
||||||
|
continue;
|
||||||
|
while (*pos == 0xFF && pos + 1 < end)
|
||||||
|
++pos;
|
||||||
|
if (*pos == 0x00 || *pos == 0xFF ||
|
||||||
|
(*pos >= GST_JPEG_MARKER_RST_MIN && *pos <= GST_JPEG_MARKER_RST_MAX))
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pos >= end)
|
||||||
|
return size;
|
||||||
|
return pos - start - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstJpegTypeOffsetSize *
|
||||||
|
gst_jpeg_segment_new (guint8 marker, guint offset, gint size)
|
||||||
|
{
|
||||||
|
GstJpegTypeOffsetSize *seg;
|
||||||
|
|
||||||
|
if (GST_JPEG_MARKER_SOS == marker)
|
||||||
|
seg = g_malloc0 (sizeof (GstJpegScanOffsetSize));
|
||||||
|
else
|
||||||
|
seg = g_malloc0 (sizeof (GstJpegTypeOffsetSize));
|
||||||
|
seg->type = marker;
|
||||||
|
seg->offset = offset;
|
||||||
|
seg->size = size;
|
||||||
|
return seg;
|
||||||
|
}
|
||||||
|
|
||||||
GList *
|
GList *
|
||||||
gst_jpeg_parse(const guint8 * data, gsize size, guint offset)
|
gst_jpeg_parse(const guint8 * data, gsize size, guint offset)
|
||||||
{
|
{
|
||||||
|
@ -446,6 +481,8 @@ gst_jpeg_parse(const guint8 * data, gsize size, guint offset)
|
||||||
guint16 header_length;
|
guint16 header_length;
|
||||||
GList *segments = NULL;
|
GList *segments = NULL;
|
||||||
GstJpegTypeOffsetSize *seg;
|
GstJpegTypeOffsetSize *seg;
|
||||||
|
const guint8 *scan_start;
|
||||||
|
gint scan_size = 0;
|
||||||
|
|
||||||
size -= offset;
|
size -= offset;
|
||||||
|
|
||||||
|
@ -470,16 +507,24 @@ gst_jpeg_parse(const guint8 * data, gsize size, guint offset)
|
||||||
gst_byte_reader_get_remaining (&bytes_reader) < header_length - 2)
|
gst_byte_reader_get_remaining (&bytes_reader) < header_length - 2)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
seg = g_malloc (sizeof (GstJpegTypeOffsetSize));
|
seg = gst_jpeg_segment_new (marker,
|
||||||
seg->type = marker;
|
gst_byte_reader_get_pos(&bytes_reader) + offset,
|
||||||
seg->offset = gst_byte_reader_get_pos(&bytes_reader) + offset;
|
header_length - 2);
|
||||||
seg->size = header_length - 2;
|
|
||||||
segments = g_list_prepend(segments, seg);
|
segments = g_list_prepend(segments, seg);
|
||||||
gst_byte_reader_skip (&bytes_reader, header_length - 2);
|
gst_byte_reader_skip (&bytes_reader, header_length - 2);
|
||||||
|
|
||||||
/* parser should stop at first scan */
|
if (seg->type == GST_JPEG_MARKER_SOS) {
|
||||||
if (seg->type == GST_JPEG_MARKER_SOS)
|
GstJpegScanOffsetSize * const scan_seg = (GstJpegScanOffsetSize *)seg;
|
||||||
break;
|
scan_start = gst_byte_reader_peek_data_unchecked (&bytes_reader);
|
||||||
|
scan_size = jpeg_scan_to_end (scan_start,
|
||||||
|
gst_byte_reader_get_remaining (&bytes_reader));
|
||||||
|
if (scan_size <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
scan_seg->data_offset = gst_byte_reader_get_pos (&bytes_reader) + offset;
|
||||||
|
scan_seg->data_size = scan_size;
|
||||||
|
gst_byte_reader_skip (&bytes_reader, scan_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return g_list_reverse (segments);
|
return g_list_reverse (segments);
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ typedef struct _GstJpegScanHdr GstJpegScanHdr;
|
||||||
typedef struct _GstJpegFrameComponent GstJpegFrameComponent;
|
typedef struct _GstJpegFrameComponent GstJpegFrameComponent;
|
||||||
typedef struct _GstJpegFrameHdr GstJpegFrameHdr;
|
typedef struct _GstJpegFrameHdr GstJpegFrameHdr;
|
||||||
typedef struct _GstJpegTypeOffsetSize GstJpegTypeOffsetSize;
|
typedef struct _GstJpegTypeOffsetSize GstJpegTypeOffsetSize;
|
||||||
|
typedef struct _GstJpegScanOffsetSize GstJpegScanOffsetSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstJpegParserResult:
|
* GstJpegParserResult:
|
||||||
|
@ -241,6 +242,25 @@ struct _GstJpegTypeOffsetSize
|
||||||
gint size;
|
gint size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstJpegScanOffsetSize:
|
||||||
|
* @header: The header info associated to the scan
|
||||||
|
* @data_offset: The offset to the first entropy-coded segment in bytes
|
||||||
|
* @data_size: The size in bytes of the scan data, including all ECS
|
||||||
|
* and RST segments, or -1 if the end was not found
|
||||||
|
*
|
||||||
|
* A structure that contains information on a scan. A scan comprises of the
|
||||||
|
* scan @header, and all entropy-coded segment (ECS) and restart marker (RST)
|
||||||
|
* associated to it. The header type MUST be set to @GST_JPEG_MARKER_SOS.
|
||||||
|
*/
|
||||||
|
struct _GstJpegScanOffsetSize
|
||||||
|
{
|
||||||
|
GstJpegTypeOffsetSize header;
|
||||||
|
guint data_offset;
|
||||||
|
gint data_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_jpeg_parse:
|
* gst_jpeg_parse:
|
||||||
* @data: The data to parse
|
* @data: The data to parse
|
||||||
|
|
|
@ -433,66 +433,19 @@ decode_restart_interval(
|
||||||
return GST_VAAPI_DECODER_STATUS_SUCCESS;
|
return GST_VAAPI_DECODER_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint32
|
|
||||||
scan_to_end(const guint8 *start, guint32 size)
|
|
||||||
{
|
|
||||||
const guint8 *pos = start, *end = start + size;
|
|
||||||
|
|
||||||
for (; pos < end; ++pos) {
|
|
||||||
if (*pos != 0xFF)
|
|
||||||
continue;
|
|
||||||
while (*pos == 0xFF && pos + 1 < end)
|
|
||||||
++pos;
|
|
||||||
if (*pos == 0x00 || *pos == 0xFF ||
|
|
||||||
(*pos >= GST_JPEG_MARKER_RST_MIN && *pos <= GST_JPEG_MARKER_RST_MAX))
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pos >= end)
|
|
||||||
return size;
|
|
||||||
return pos - start - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
scan_to_next_scan(guint8 *data, guint32 size,
|
|
||||||
guint8 **scan, guint32 *scan_header_size, guint32 *scan_left_size)
|
|
||||||
{
|
|
||||||
GList *seg_list = NULL;
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
|
|
||||||
if (!data || !size)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
seg_list = gst_jpeg_parse(data, size, 0);
|
|
||||||
for (; seg_list; seg_list = seg_list->next) {
|
|
||||||
GstJpegTypeOffsetSize * const seg = seg_list->data;
|
|
||||||
if (seg->type != GST_JPEG_MARKER_SOS)
|
|
||||||
continue;
|
|
||||||
*scan = seg->offset + data;
|
|
||||||
*scan_header_size = seg->size;
|
|
||||||
*scan_left_size = size - seg->offset - seg->size;
|
|
||||||
ret = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
g_list_free_full(seg_list, g_free);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstVaapiDecoderStatus
|
static GstVaapiDecoderStatus
|
||||||
decode_scan(
|
decode_scan(
|
||||||
GstVaapiDecoderJpeg *decoder,
|
GstVaapiDecoderJpeg *decoder,
|
||||||
guchar *scan,
|
guchar *scan_header,
|
||||||
guint scan_header_size,
|
guint scan_header_size,
|
||||||
guint scan_left_size)
|
guchar *scan_data,
|
||||||
|
guint scan_data_size)
|
||||||
{
|
{
|
||||||
GstVaapiDecoderJpegPrivate * const priv = decoder->priv;
|
GstVaapiDecoderJpegPrivate * const priv = decoder->priv;
|
||||||
GstVaapiPicture *picture = priv->current_picture;
|
GstVaapiPicture *picture = priv->current_picture;
|
||||||
GstJpegParserResult result = GST_JPEG_PARSER_OK;
|
GstJpegParserResult result = GST_JPEG_PARSER_OK;
|
||||||
VASliceParameterBufferJPEG *slice_param;
|
VASliceParameterBufferJPEG *slice_param;
|
||||||
GstVaapiSlice *gst_slice;
|
GstVaapiSlice *gst_slice;
|
||||||
guint8 *mcu_start, *next_mark;
|
|
||||||
guint8 *buf_end = scan + scan_header_size + scan_left_size;
|
|
||||||
guint mcu_size;
|
|
||||||
guint total_h_samples, total_v_samples;
|
guint total_h_samples, total_v_samples;
|
||||||
GstJpegScanHdr scan_hdr;
|
GstJpegScanHdr scan_hdr;
|
||||||
guint i;
|
guint i;
|
||||||
|
@ -512,53 +465,40 @@ decode_scan(
|
||||||
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
|
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
mcu_size = scan_left_size;
|
memset(&scan_hdr, 0, sizeof(scan_hdr));
|
||||||
while (scan_left_size) {
|
result = gst_jpeg_parse_scan_hdr(&scan_hdr, scan_header, scan_header_size, 0);
|
||||||
memset(&scan_hdr, 0, sizeof(scan_hdr));
|
if (result != GST_JPEG_PARSER_OK) {
|
||||||
result = gst_jpeg_parse_scan_hdr(&scan_hdr, scan, scan_header_size, 0);
|
GST_DEBUG("Jpeg parsed scan failed.");
|
||||||
if (result != GST_JPEG_PARSER_OK) {
|
return get_status(result);
|
||||||
GST_DEBUG("Jpeg parsed scan failed.");
|
}
|
||||||
return get_status(result);
|
|
||||||
|
gst_slice = GST_VAAPI_SLICE_NEW(JPEG, decoder, scan_data, scan_data_size);
|
||||||
|
gst_vaapi_picture_add_slice(picture, gst_slice);
|
||||||
|
|
||||||
|
slice_param = gst_slice->param;
|
||||||
|
slice_param->num_components = scan_hdr.num_components;
|
||||||
|
for (i = 0; i < scan_hdr.num_components; i++) {
|
||||||
|
slice_param->components[i].component_id = scan_hdr.components[i].component_selector;
|
||||||
|
slice_param->components[i].dc_selector = scan_hdr.components[i].dc_selector;
|
||||||
|
slice_param->components[i].ac_selector = scan_hdr.components[i].ac_selector;
|
||||||
|
}
|
||||||
|
slice_param->restart_interval = priv->mcu_restart;
|
||||||
|
if (scan_hdr.num_components == 1) { /*non-interleaved*/
|
||||||
|
slice_param->slice_horizontal_position = 0;
|
||||||
|
slice_param->slice_vertical_position = 0;
|
||||||
|
/* Y mcu numbers*/
|
||||||
|
if (slice_param->components[0].component_id == priv->frame_hdr.components[0].identifier) {
|
||||||
|
slice_param->num_mcus = (priv->frame_hdr.width/8)*(priv->frame_hdr.height/8);
|
||||||
|
} else { /*Cr, Cb mcu numbers*/
|
||||||
|
slice_param->num_mcus = (priv->frame_hdr.width/16)*(priv->frame_hdr.height/16);
|
||||||
}
|
}
|
||||||
mcu_start = scan + scan_header_size;
|
} else { /* interleaved */
|
||||||
mcu_size = scan_to_end(mcu_start, scan_left_size);
|
slice_param->slice_horizontal_position = 0;
|
||||||
|
slice_param->slice_vertical_position = 0;
|
||||||
gst_slice = GST_VAAPI_SLICE_NEW(JPEG, decoder, mcu_start, mcu_size);
|
total_v_samples = get_max_vertical_samples(&priv->frame_hdr);
|
||||||
gst_vaapi_picture_add_slice(picture, gst_slice);
|
total_h_samples = get_max_horizontal_samples(&priv->frame_hdr);
|
||||||
|
slice_param->num_mcus = ((priv->frame_hdr.width + total_h_samples*8 - 1)/(total_h_samples*8)) *
|
||||||
slice_param = gst_slice->param;
|
((priv->frame_hdr.height + total_v_samples*8 -1)/(total_v_samples*8));
|
||||||
slice_param->num_components = scan_hdr.num_components;
|
|
||||||
for (i = 0; i < scan_hdr.num_components; i++) {
|
|
||||||
slice_param->components[i].component_id = scan_hdr.components[i].component_selector;
|
|
||||||
slice_param->components[i].dc_selector = scan_hdr.components[i].dc_selector;
|
|
||||||
slice_param->components[i].ac_selector = scan_hdr.components[i].ac_selector;
|
|
||||||
}
|
|
||||||
slice_param->restart_interval = priv->mcu_restart;
|
|
||||||
if (scan_hdr.num_components == 1) { /*non-interleaved*/
|
|
||||||
slice_param->slice_horizontal_position = 0;
|
|
||||||
slice_param->slice_vertical_position = 0;
|
|
||||||
/* Y mcu numbers*/
|
|
||||||
if (slice_param->components[0].component_id == priv->frame_hdr.components[0].identifier) {
|
|
||||||
slice_param->num_mcus = (priv->frame_hdr.width/8)*(priv->frame_hdr.height/8);
|
|
||||||
} else { /*Cr, Cb mcu numbers*/
|
|
||||||
slice_param->num_mcus = (priv->frame_hdr.width/16)*(priv->frame_hdr.height/16);
|
|
||||||
}
|
|
||||||
} else { /* interleaved */
|
|
||||||
slice_param->slice_horizontal_position = 0;
|
|
||||||
slice_param->slice_vertical_position = 0;
|
|
||||||
total_v_samples = get_max_vertical_samples(&priv->frame_hdr);
|
|
||||||
total_h_samples = get_max_horizontal_samples(&priv->frame_hdr);
|
|
||||||
slice_param->num_mcus = ((priv->frame_hdr.width + total_h_samples*8 - 1)/(total_h_samples*8)) *
|
|
||||||
((priv->frame_hdr.height + total_v_samples*8 -1)/(total_v_samples*8));
|
|
||||||
}
|
|
||||||
|
|
||||||
next_mark = mcu_start + mcu_size;
|
|
||||||
scan_left_size = buf_end - next_mark;
|
|
||||||
if (scan_left_size < 4) /* Mark_code(2-bytes) + header_length(2-bytes)*/
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!scan_to_next_scan(next_mark, scan_left_size, &scan, &scan_header_size, &scan_left_size))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (picture->slices && picture->slices->len)
|
if (picture->slices && picture->slices->len)
|
||||||
|
@ -608,10 +548,15 @@ decode_buffer(GstVaapiDecoderJpeg *decoder, GstBuffer *buffer)
|
||||||
case GST_JPEG_MARKER_DRI:
|
case GST_JPEG_MARKER_DRI:
|
||||||
status = decode_restart_interval(decoder, buf + seg->offset, seg->size);
|
status = decode_restart_interval(decoder, buf + seg->offset, seg->size);
|
||||||
break;
|
break;
|
||||||
case GST_JPEG_MARKER_SOS:
|
case GST_JPEG_MARKER_SOS: {
|
||||||
status = decode_scan(decoder, buf + seg->offset, seg->size, buf_size - seg->offset - seg->size);
|
GstJpegScanOffsetSize * const scan = (GstJpegScanOffsetSize *)seg;
|
||||||
|
status = decode_scan(
|
||||||
|
decoder, buf + scan->header.offset, scan->header.size,
|
||||||
|
buf + scan->data_offset, scan->data_size
|
||||||
|
);
|
||||||
scan_found = TRUE;
|
scan_found = TRUE;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if (seg->type >= GST_JPEG_MARKER_SOF_MIN &&
|
if (seg->type >= GST_JPEG_MARKER_SOF_MIN &&
|
||||||
seg->type <= GST_JPEG_MARKER_SOF_MAX)
|
seg->type <= GST_JPEG_MARKER_SOF_MAX)
|
||||||
|
|
Loading…
Reference in a new issue