diff options
author | Wind Yuan <feng.yuan@intel.com> | 2012-02-10 00:21:04 +0800 |
---|---|---|
committer | Gwenole Beauchesne <gwenole.beauchesne@intel.com> | 2012-04-11 19:38:12 +0200 |
commit | 75e8a7d6f84e24275eaba168fb61ada0dc98c844 (patch) | |
tree | 52be18439ddcc4c1b6541b39717462eda419fef8 | |
parent | c350a0809d3ecb2f47f7fe6c43b319f12d1d5bdd (diff) |
Add initial JPEG decoder.
Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
-rw-r--r-- | configure.ac | 26 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/Makefile.am | 5 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapicodec_objects.c | 59 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapicodec_objects.h | 72 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c | 531 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h | 88 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapidecoder_objects.c | 13 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapidecoder_objects.h | 1 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapiprofile.c | 6 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapiprofile.h | 2 | ||||
-rw-r--r-- | gst/vaapi/gstvaapidecode.c | 6 |
11 files changed, 809 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index d8d45636..4d17ab7e 100644 --- a/configure.ac +++ b/configure.ac @@ -404,6 +404,32 @@ AC_SUBST(LIBVA_GLX_PKGNAME) AC_SUBST(LIBVA_EXTRA_CFLAGS) AC_SUBST(LIBVA_EXTRA_LIBS) +dnl Check for JPEG decoding API (0.33+) +USE_JPEG_DECODER=0 +if test "$enable_codecparsers" = "yes"; then +AC_CACHE_CHECK([for JPEG decoding API], + ac_cv_have_jpeg_decoding_api, [ + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $LIBVA_CFLAGS" + saved_LIBS="$LIBS" + LIBS="$CFLAGS $LIBVA_LIBS" + AC_TRY_COMPILE( + [#include <va/va.h>], + [VAPictureParameterBufferJPEG pic_param; + VASliceParameterBufferJPEG slice_param; + VAIQMatrixBufferJPEG iq_matrix;], + [ac_cv_have_jpeg_decoding_api="yes" USE_JPEG_DECODER=1], + [ac_cv_have_jpeg_decoding_api="no"] + ) + CFLAGS="$saved_CFLAGS" + LIBS="$saved_LIBS" +]) +fi + +AC_DEFINE_UNQUOTED(USE_JPEG_DECODER, $USE_JPEG_DECODER, + [Defined to 1 if JPEG decoder is used]) +AM_CONDITIONAL(USE_JPEG_DECODER, test $USE_JPEG_DECODER -eq 1) + dnl Check for OpenGL support to vaapisink if test "$enable_vaapisink_glx:$USE_GLX" = "yes:1"; then USE_VAAPISINK_GLX=1 diff --git a/gst-libs/gst/vaapi/Makefile.am b/gst-libs/gst/vaapi/Makefile.am index d4e3397b..394e52a7 100644 --- a/gst-libs/gst/vaapi/Makefile.am +++ b/gst-libs/gst/vaapi/Makefile.am @@ -168,6 +168,11 @@ libgstvaapi_source_priv_h += \ $(NULL) libgstvaapi_cflags += $(GST_CODEC_PARSERS_CFLAGS) libgstvaapi_libs += $(GST_CODEC_PARSERS_LIBS) + +if USE_JPEG_DECODER +libgstvaapi_source_c += gstvaapidecoder_jpeg.c +libgstvaapi_source_h += gstvaapidecoder_jpeg.h +endif endif if USE_LOCAL_CODEC_PARSERS diff --git a/gst-libs/gst/vaapi/gstvaapicodec_objects.c b/gst-libs/gst/vaapi/gstvaapicodec_objects.c index fd4822da..63ba30ef 100644 --- a/gst-libs/gst/vaapi/gstvaapicodec_objects.c +++ b/gst-libs/gst/vaapi/gstvaapicodec_objects.c @@ -243,3 +243,62 @@ gst_vaapi_bitplane_new(GstVaapiDecoder *decoder, guint8 *data, guint data_size) return NULL; return GST_VAAPI_BITPLANE_CAST(object); } + +/* ------------------------------------------------------------------------- */ +/* --- JPEG Huffman Tables --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiHuffmanTable, + gst_vaapi_huffman_table, + GST_VAAPI_TYPE_CODEC_OBJECT) + +static void +gst_vaapi_huffman_table_destroy(GstVaapiHuffmanTable *huf_table) +{ + vaapi_destroy_buffer(GET_VA_DISPLAY(huf_table), &huf_table->param_id); + huf_table->param = NULL; +} + +static gboolean +gst_vaapi_huffman_table_create( + GstVaapiHuffmanTable *huf_table, + const GstVaapiCodecObjectConstructorArgs *args +) +{ + return vaapi_create_buffer(GET_VA_DISPLAY(huf_table), + GET_VA_CONTEXT(huf_table), + VAHuffmanTableBufferType, + args->param_size, + args->param, + &huf_table->param_id, + (void **)&huf_table->param); +} + +static void +gst_vaapi_huffman_table_init(GstVaapiHuffmanTable *huf_table) +{ + huf_table->param = NULL; + huf_table->param_id = VA_INVALID_ID; +} + +GstVaapiHuffmanTable * +gst_vaapi_huffman_table_new( + GstVaapiDecoder *decoder, + guint8 *data, + guint data_size +) +{ + GstVaapiCodecObject *object; + + g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL); + + object = gst_vaapi_codec_object_new( + GST_VAAPI_TYPE_HUFFMAN_TABLE, + GST_VAAPI_CODEC_BASE(decoder), + data, data_size, + NULL, 0 + ); + if (!object) + return NULL; + return GST_VAAPI_HUFFMAN_TABLE_CAST(object); +} diff --git a/gst-libs/gst/vaapi/gstvaapicodec_objects.h b/gst-libs/gst/vaapi/gstvaapicodec_objects.h index f379f026..8fb0c15c 100644 --- a/gst-libs/gst/vaapi/gstvaapicodec_objects.h +++ b/gst-libs/gst/vaapi/gstvaapicodec_objects.h @@ -35,6 +35,8 @@ typedef struct _GstVaapiIqMatrix GstVaapiIqMatrix; typedef struct _GstVaapiIqMatrixClass GstVaapiIqMatrixClass; typedef struct _GstVaapiBitPlane GstVaapiBitPlane; typedef struct _GstVaapiBitPlaneClass GstVaapiBitPlaneClass; +typedef struct _GstVaapiHuffmanTable GstVaapiHuffmanTable; +typedef struct _GstVaapiHuffmanTableClass GstVaapiHuffmanTableClass; /* ------------------------------------------------------------------------- */ /* --- Base Codec Object --- */ @@ -257,6 +259,72 @@ gst_vaapi_bitplane_new(GstVaapiDecoder *decoder, guint8 *data, guint data_size) attribute_hidden; /* ------------------------------------------------------------------------- */ +/* --- JPEG Huffman Tables --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_TYPE_HUFFMAN_TABLE \ + (gst_vaapi_huffman_table_get_type()) + +#define GST_VAAPI_HUFFMAN_TABLE_CAST(obj) \ + ((GstVaapiHuffmanTable *)(obj)) + +#define GST_VAAPI_HUFFMAN_TABLE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_HUFFMAN_TABLE, \ + GstVaapiHuffmanTable)) + +#define GST_VAAPI_HUFFMAN_TABLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_HUFFMAN_TABLE, \ + GstVaapiHuffmanTableClass)) + +#define GST_VAAPI_IS_HUFFMAN_TABLE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_HUFFMAN_TABLE)) + +#define GST_VAAPI_IS_HUFFMAN_TABLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_HUFFMAN_TABLE)) + +#define GST_VAAPI_HUFFMAN_TABLE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_HUFFMAN_TABLE, \ + GstVaapiHuffmanTableClass)) + +/** + * GstVaapiHuffmanTable: + * + * A #GstVaapiCodecObject holding huffman table. + */ +struct _GstVaapiHuffmanTable { + /*< private >*/ + GstVaapiCodecObject parent_instance; + VABufferID param_id; + + /*< public >*/ + gpointer param; +}; + +/** + * GstVaapiHuffmanTableClass: + * + * The #GstVaapiHuffmanTable base class. + */ +struct _GstVaapiHuffmanTableClass { + /*< private >*/ + GstVaapiCodecObjectClass parent_class; +}; + +GType +gst_vaapi_huffman_table_get_type(void) + attribute_hidden; + +GstVaapiHuffmanTable * +gst_vaapi_huffman_table_new( + GstVaapiDecoder *decoder, + guint8 *data, + guint data_size +) attribute_hidden; + +/* ------------------------------------------------------------------------- */ /* --- Helpers to create codec-dependent objects --- */ /* ------------------------------------------------------------------------- */ @@ -318,6 +386,10 @@ prefix##_class_init(type##Class *klass) \ #define GST_VAAPI_BITPLANE_NEW(decoder, size) \ gst_vaapi_bitplane_new(GST_VAAPI_DECODER_CAST(decoder), NULL, size) + +#define GST_VAAPI_HUFFMAN_TABLE_NEW(codec, decoder) \ + gst_vaapi_huffman_table_new(GST_VAAPI_DECODER_CAST(decoder), \ + NULL, sizeof(VAHuffmanTableBuffer##codec)) G_END_DECLS diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c new file mode 100644 index 00000000..91c4255e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c @@ -0,0 +1,531 @@ +/* + * gstvaapidecoder_jpeg.c - JPEG decoder + * + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidecoder_jpeg + * @short_description: JPEG decoder + */ + +#include "sysdeps.h" +#include <string.h> +#include <gst/codecparsers/gstjpegparser.h> +#include "gstvaapidecoder_jpeg.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiobject_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDecoderJpeg, + gst_vaapi_decoder_jpeg, + GST_VAAPI_TYPE_DECODER); + +#define GST_VAAPI_DECODER_JPEG_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DECODER_JPEG, \ + GstVaapiDecoderJpegPrivate)) + +struct _GstVaapiDecoderJpegPrivate { + GstVaapiProfile profile; + guint width; + guint height; + GstVaapiPicture *current_picture; + guint is_opened : 1; + guint profile_changed : 1; + guint is_constructed : 1; +}; + + +static GstVaapiDecoderStatus +get_status(GstJpegParserResult result) +{ + GstVaapiDecoderStatus status; + + switch (result) { + case GST_JPEG_PARSER_OK: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + case GST_JPEG_PARSER_FRAME_ERROR: + case GST_JPEG_PARSER_SCAN_ERROR: + case GST_JPEG_PARSER_HUFFMAN_ERROR: + case GST_JPEG_PARSER_QUANT_ERROR: + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + default: + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + break; + } + return status; +} + +static void +gst_vaapi_decoder_jpeg_close(GstVaapiDecoderJpeg *decoder) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + + gst_vaapi_picture_replace(&priv->current_picture, NULL); + + /* Reset all */ + priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + priv->width = 0; + priv->height = 0; + priv->is_opened = FALSE; + priv->profile_changed = TRUE; + priv->is_constructed = FALSE; +} + +static gboolean +gst_vaapi_decoder_jpeg_open(GstVaapiDecoderJpeg *decoder, GstBuffer *buffer) +{ + gst_vaapi_decoder_jpeg_close(decoder); + + return TRUE; +} + +static void +gst_vaapi_decoder_jpeg_destroy(GstVaapiDecoderJpeg *decoder) +{ + gst_vaapi_decoder_jpeg_close(decoder); +} + +static gboolean +gst_vaapi_decoder_jpeg_create(GstVaapiDecoderJpeg *decoder) +{ + if (!GST_VAAPI_DECODER_CODEC(decoder)) + return FALSE; + return TRUE; +} + +static GstVaapiDecoderStatus +ensure_context(GstVaapiDecoderJpeg *decoder) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + GstVaapiProfile profiles[2]; + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + guint i, n_profiles = 0; + gboolean reset_context = FALSE; + + if (priv->profile_changed) { + GST_DEBUG("profile changed"); + priv->profile_changed = FALSE; + reset_context = TRUE; + + profiles[n_profiles++] = priv->profile; + //if (priv->profile == GST_VAAPI_PROFILE_JPEG_EXTENDED) + // profiles[n_profiles++] = GST_VAAPI_PROFILE_JPEG_BASELINE; + + for (i = 0; i < n_profiles; i++) { + if (gst_vaapi_display_has_decoder(GST_VAAPI_DECODER_DISPLAY(decoder), + profiles[i], entrypoint)) + break; + } + if (i == n_profiles) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + priv->profile = profiles[i]; + } + + if (reset_context) { + reset_context = gst_vaapi_decoder_ensure_context( + GST_VAAPI_DECODER(decoder), + priv->profile, + entrypoint, + priv->width, priv->height + ); + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline GstVaapiDecoderStatus +decode_current_picture(GstVaapiDecoderJpeg *decoder) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + GstVaapiPicture * const picture = priv->current_picture; + GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (picture) { + if (!gst_vaapi_picture_decode(picture)) + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + else if (!gst_vaapi_picture_output(picture)) + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + gst_vaapi_picture_replace(&priv->current_picture, NULL); + } + return status; +} + +static gboolean +fill_picture( + GstVaapiDecoderJpeg *decoder, + GstVaapiPicture *picture, + GstJpegImage *jpeg_image +) +{ + VAPictureParameterBufferJPEG *pic_param = picture->param; + guint i; + + g_assert(pic_param); + + memset(pic_param, 0, sizeof(VAPictureParameterBufferJPEG)); + pic_param->type = jpeg_image->frame_type; + pic_param->sample_precision = jpeg_image->sample_precision; + pic_param->image_width = jpeg_image->width; + pic_param->image_height = jpeg_image->height; + + /* XXX: ROI + rotation */ + + pic_param->num_components = jpeg_image->num_components; + for (i = 0; i < pic_param->num_components; i++) { + pic_param->components[i].component_id = + jpeg_image->components[i].identifier; + pic_param->components[i].h_sampling_factor = + jpeg_image->components[i].horizontal_factor; + pic_param->components[i].v_sampling_factor = + jpeg_image->components[i].vertical_factor; + pic_param->components[i].quantiser_table_selector = + jpeg_image->components[i].quant_table_selector; + } + return TRUE; +} + +static gboolean +fill_quantization_table( + GstVaapiDecoderJpeg *decoder, + GstVaapiPicture *picture, + GstJpegImage *jpeg_image +) +{ + VAIQMatrixBufferJPEG *iq_matrix; + int i = 0; + + picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW(JPEG, decoder); + g_assert(picture->iq_matrix); + iq_matrix = picture->iq_matrix->param; + memset(iq_matrix, 0, sizeof(VAIQMatrixBufferJPEG)); + for (i = 0; i < GST_JPEG_MAX_COMPONENTS; i++) { + iq_matrix->precision[i] = jpeg_image->quant_tables[i].quant_precision; + if (iq_matrix->precision[i] == 0) /* 8-bit values*/ + memcpy(iq_matrix->quantiser_matrix[i], jpeg_image->quant_tables[i].quant_table, 64); + else + memcpy(iq_matrix->quantiser_matrix[i], jpeg_image->quant_tables[i].quant_table, 128); + } + return TRUE; +} + +static gboolean +fill_huffman_table( + GstVaapiDecoderJpeg *decoder, + GstVaapiPicture *picture, + GstJpegImage *jpeg_image +) +{ + VAHuffmanTableBufferJPEG *huffman_table; + int i; + + picture->huf_table = GST_VAAPI_HUFFMAN_TABLE_NEW(JPEG, decoder); + g_assert(picture->huf_table); + huffman_table = picture->huf_table->param; + memset(huffman_table, 0, sizeof(VAHuffmanTableBufferJPEG)); + for (i = 0; i < GST_JPEG_MAX_COMPONENTS; i++) { + memcpy(huffman_table->huffman_table[i].dc_bits, + jpeg_image->dc_huf_tables[i].huf_bits, + 16); + memcpy(huffman_table->huffman_table[i].dc_huffval, + jpeg_image->dc_huf_tables[i].huf_values, + 16); + memcpy(huffman_table->huffman_table[i].ac_bits, + jpeg_image->ac_huf_tables[i].huf_bits, + 16); + memcpy(huffman_table->huffman_table[i].ac_huffval, + jpeg_image->ac_huf_tables[i].huf_values, + 256); + } + return TRUE; +} + +static guint +get_max_horizontal_samples(GstJpegImage *jpeg) +{ + guint i, max_factor = 0; + + for (i = 0; i < jpeg->num_components; i++) { + if (jpeg->components[i].horizontal_factor > max_factor) + max_factor = jpeg->components[i].horizontal_factor; + } + return max_factor; +} + +static guint +get_max_vertical_samples(GstJpegImage *jpeg) +{ + guint i, max_factor = 0; + + for (i = 0; i < jpeg->num_components; i++) { + if (jpeg->components[i].vertical_factor > max_factor) + max_factor = jpeg->components[i].vertical_factor; + } + return max_factor; +} + +static gboolean +fill_slices( + GstVaapiDecoderJpeg *decoder, + GstVaapiPicture *picture, + GstJpegImage *jpeg_image +) +{ + VASliceParameterBufferJPEG *slice_param; + GstVaapiSlice *gst_slice; + int i; + const guint8 *sos_src; + guint32 sos_length; + guint total_h_samples, total_v_samples; + + while (gst_jpeg_get_left_size(jpeg_image)) { + sos_src = gst_jpeg_get_position(jpeg_image); + sos_length = gst_jpeg_skip_to_scan_end(jpeg_image); + if (!sos_length) + break; + gst_slice = GST_VAAPI_SLICE_NEW(JPEG, decoder, sos_src, sos_length); + slice_param = gst_slice->param; + slice_param->num_components = jpeg_image->current_scan.num_components; + for (i = 0; i < slice_param->num_components; i++) { + slice_param->components[i].component_id = jpeg_image->current_scan.components[i].component_selector; + slice_param->components[i].dc_selector = jpeg_image->current_scan.components[i].dc_selector; + slice_param->components[i].ac_selector = jpeg_image->current_scan.components[i].ac_selector; + } + slice_param->restart_interval = jpeg_image->restart_interval; + + if (jpeg_image->current_scan.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 == jpeg_image->components[0].identifier) { + slice_param->num_mcus = (jpeg_image->width/8)*(jpeg_image->height/8); + } else { /*Cr, Cb mcu numbers*/ + slice_param->num_mcus = (jpeg_image->width/16)*(jpeg_image->height/16); + } + } else { /* interleaved */ + slice_param->slice_horizontal_position = 0; + slice_param->slice_vertical_position = 0; + total_v_samples = get_max_vertical_samples(jpeg_image); + total_h_samples = get_max_horizontal_samples(jpeg_image); + slice_param->num_mcus = ((jpeg_image->width + total_h_samples*8 - 1)/(total_h_samples*8)) * + ((jpeg_image->height + total_v_samples*8 -1)/(total_v_samples*8)); + } + + gst_vaapi_picture_add_slice(picture, gst_slice); + if (!gst_jpeg_parse_next_scan(jpeg_image)) { + break; + } + } + + if (picture->slices && picture->slices->len) + return TRUE; + return FALSE; +} + +static GstVaapiDecoderStatus +decode_picture( + GstVaapiDecoderJpeg *decoder, + guchar *buf, + guint buf_size, + GstClockTime pts +) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + GstVaapiPicture *picture = NULL; + GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS; + GstJpegImage jpeg_image; + GstJpegParserResult result; + + /* parse jpeg */ + memset(&jpeg_image, 0, sizeof(jpeg_image)); + result = gst_jpeg_parse_image(&jpeg_image, buf, buf_size); + if (result != GST_JPEG_PARSER_OK) { + GST_ERROR("failed to parse image"); + return get_status(result); + } + + /* set info to va parameters in current picture*/ + priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + priv->height = jpeg_image.height; + priv->width = jpeg_image.width; + + status = ensure_context(decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_ERROR("failed to reset context"); + return status; + } + + picture = GST_VAAPI_PICTURE_NEW(JPEG, 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, &jpeg_image)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + if (!fill_quantization_table(decoder, picture, &jpeg_image)) { + GST_ERROR("failed to fill in quantization table"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!fill_huffman_table(decoder, picture, &jpeg_image)) { + GST_ERROR("failed to fill in huffman table"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!fill_slices(decoder, picture, &jpeg_image)) { + GST_ERROR("failed to fill in all scans"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + /* Update presentation time */ + picture->pts = pts; + return status; +} + +static GstVaapiDecoderStatus +decode_buffer(GstVaapiDecoderJpeg *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderStatus status; + GstClockTime pts; + guchar *buf; + guint buf_size; + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + if (!buf && buf_size == 0) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + pts = GST_BUFFER_TIMESTAMP(buffer); + g_assert(GST_CLOCK_TIME_IS_VALID(pts)); + + status = decode_picture(decoder, buf, buf_size, pts); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + return decode_current_picture(decoder); +} + +GstVaapiDecoderStatus +gst_vaapi_decoder_jpeg_decode(GstVaapiDecoder *base, GstBuffer *buffer) +{ + GstVaapiDecoderJpeg * const decoder = GST_VAAPI_DECODER_JPEG(base); + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_jpeg_open(decoder, buffer); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + } + return decode_buffer(decoder, buffer); +} + +static void +gst_vaapi_decoder_jpeg_finalize(GObject *object) +{ + GstVaapiDecoderJpeg * const decoder = GST_VAAPI_DECODER_JPEG(object); + + gst_vaapi_decoder_jpeg_destroy(decoder); + + G_OBJECT_CLASS(gst_vaapi_decoder_jpeg_parent_class)->finalize(object); +} + +static void +gst_vaapi_decoder_jpeg_constructed(GObject *object) +{ + GstVaapiDecoderJpeg * const decoder = GST_VAAPI_DECODER_JPEG(object); + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + GObjectClass *parent_class; + + parent_class = G_OBJECT_CLASS(gst_vaapi_decoder_jpeg_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); + + priv->is_constructed = gst_vaapi_decoder_jpeg_create(decoder); +} + +static void +gst_vaapi_decoder_jpeg_class_init(GstVaapiDecoderJpegClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiDecoderJpegPrivate)); + + object_class->finalize = gst_vaapi_decoder_jpeg_finalize; + object_class->constructed = gst_vaapi_decoder_jpeg_constructed; + + decoder_class->decode = gst_vaapi_decoder_jpeg_decode; +} + +static void +gst_vaapi_decoder_jpeg_init(GstVaapiDecoderJpeg *decoder) +{ + GstVaapiDecoderJpegPrivate *priv; + + priv = GST_VAAPI_DECODER_JPEG_GET_PRIVATE(decoder); + decoder->priv = priv; + priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + priv->width = 0; + priv->height = 0; + priv->current_picture = NULL; + priv->is_opened = FALSE; + priv->profile_changed = TRUE; + priv->is_constructed = FALSE; +} + +/** + * gst_vaapi_decoder_jpeg_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for JPEG decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_jpeg_new(GstVaapiDisplay *display, GstCaps *caps) +{ + GstVaapiDecoderJpeg *decoder; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(GST_IS_CAPS(caps), NULL); + + decoder = g_object_new( + GST_VAAPI_TYPE_DECODER_JPEG, + "display", display, + "caps", caps, + NULL + ); + if (!decoder->priv->is_constructed) { + g_object_unref(decoder); + return NULL; + } + return GST_VAAPI_DECODER_CAST(decoder); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h new file mode 100644 index 00000000..68dab506 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h @@ -0,0 +1,88 @@ +/* + * gstvaapidecoder_jpeg.h - JPEG decoder + * + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_JPEG_H +#define GST_VAAPI_DECODER_JPEG_H + +#include <gst/vaapi/gstvaapidecoder.h> + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DECODER_JPEG \ + (gst_vaapi_decoder_jpeg_get_type()) + +#define GST_VAAPI_DECODER_JPEG(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DECODER_JPEG, \ + GstVaapiDecoderJpeg)) + +#define GST_VAAPI_DECODER_JPEG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DECODER_JPEG, \ + GstVaapiDecoderJpegClass)) + +#define GST_VAAPI_IS_DECODER_JPEG(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DECODER_JPEG)) + +#define GST_VAAPI_IS_DECODER_JPEG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DECODER_JPEG)) + +#define GST_VAAPI_DECODER_JPEG_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DECODER_JPEG, \ + GstVaapiDecoderJpegClass)) + +typedef struct _GstVaapiDecoderJpeg GstVaapiDecoderJpeg; +typedef struct _GstVaapiDecoderJpegPrivate GstVaapiDecoderJpegPrivate; +typedef struct _GstVaapiDecoderJpegClass GstVaapiDecoderJpegClass; + +/** + * GstVaapiDecoderJpeg: + * + * A decoder based on Jpeg. + */ +struct _GstVaapiDecoderJpeg { + /*< private >*/ + GstVaapiDecoder parent_instance; + + GstVaapiDecoderJpegPrivate *priv; +}; + +/** + * GstVaapiDecoderJpegClass: + * + * A decoder class based on Jpeg. + */ +struct _GstVaapiDecoderJpegClass { + /*< private >*/ + GstVaapiDecoderClass parent_class; +}; + +GType +gst_vaapi_decoder_jpeg_get_type(void); + +GstVaapiDecoder * +gst_vaapi_decoder_jpeg_new(GstVaapiDisplay *display, GstCaps *caps); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_JPEG_H */ + diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_objects.c b/gst-libs/gst/vaapi/gstvaapidecoder_objects.c index 4725fac8..5f90fb02 100644 --- a/gst-libs/gst/vaapi/gstvaapidecoder_objects.c +++ b/gst-libs/gst/vaapi/gstvaapidecoder_objects.c @@ -71,6 +71,11 @@ gst_vaapi_picture_destroy(GstVaapiPicture *picture) picture->iq_matrix = NULL; } + if (picture->huf_table) { + gst_mini_object_unref(GST_MINI_OBJECT(picture->huf_table)); + picture->huf_table = NULL; + } + if (picture->bitplane) { gst_mini_object_unref(GST_MINI_OBJECT(picture->bitplane)); picture->bitplane = NULL; @@ -179,6 +184,7 @@ gst_vaapi_picture_init(GstVaapiPicture *picture) picture->param_size = 0; picture->slices = NULL; picture->iq_matrix = NULL; + picture->huf_table = NULL; picture->bitplane = NULL; picture->pts = GST_CLOCK_TIME_NONE; picture->poc = 0; @@ -264,6 +270,7 @@ gst_vaapi_picture_decode(GstVaapiPicture *picture) { GstVaapiIqMatrix *iq_matrix; GstVaapiBitPlane *bitplane; + GstVaapiHuffmanTable *huf_table; VADisplay va_display; VAContextID va_context; VAStatus status; @@ -293,6 +300,12 @@ gst_vaapi_picture_decode(GstVaapiPicture *picture) &bitplane->data_id, (void **)&bitplane->data)) return FALSE; + huf_table = picture->huf_table; + if (huf_table && !do_decode(va_display, va_context, + &huf_table->param_id, + (void **)&huf_table->param)) + return FALSE; + for (i = 0; i < picture->slices->len; i++) { GstVaapiSlice * const slice = g_ptr_array_index(picture->slices, i); VABufferID va_buffers[2]; diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_objects.h b/gst-libs/gst/vaapi/gstvaapidecoder_objects.h index 93d8ce27..56a6fde3 100644 --- a/gst-libs/gst/vaapi/gstvaapidecoder_objects.h +++ b/gst-libs/gst/vaapi/gstvaapidecoder_objects.h @@ -146,6 +146,7 @@ struct _GstVaapiPicture { gpointer param; GPtrArray *slices; GstVaapiIqMatrix *iq_matrix; + GstVaapiHuffmanTable *huf_table; GstVaapiBitPlane *bitplane; GstClockTime pts; gint32 poc; diff --git a/gst-libs/gst/vaapi/gstvaapiprofile.c b/gst-libs/gst/vaapi/gstvaapiprofile.c index 54b7abac..f93e628a 100644 --- a/gst-libs/gst/vaapi/gstvaapiprofile.c +++ b/gst-libs/gst/vaapi/gstvaapiprofile.c @@ -92,6 +92,9 @@ static const GstVaapiProfileMap gst_vaapi_profiles[] = { { GST_VAAPI_PROFILE_VC1_ADVANCED, VAProfileVC1Advanced, "video/x-wmv, wmvversion=3, format=(fourcc)WVC1", "advanced" }, + { GST_VAAPI_PROFILE_JPEG_BASELINE, VAProfileJPEGBaseline, + "image/jpeg", "baseline" + }, { 0, } }; @@ -337,6 +340,9 @@ gst_vaapi_profile_get_codec(GstVaapiProfile profile) case GST_VAAPI_PROFILE_VC1_ADVANCED: codec = GST_VAAPI_CODEC_VC1; break; + case GST_VAAPI_PROFILE_JPEG_BASELINE: + codec = GST_VAAPI_CODEC_JPEG; + break; default: codec = (guint32)profile & GST_MAKE_FOURCC(0xff,0xff,0xff,0); break; diff --git a/gst-libs/gst/vaapi/gstvaapiprofile.h b/gst-libs/gst/vaapi/gstvaapiprofile.h index e16bff95..986c9a26 100644 --- a/gst-libs/gst/vaapi/gstvaapiprofile.h +++ b/gst-libs/gst/vaapi/gstvaapiprofile.h @@ -50,6 +50,7 @@ enum _GstVaapiCodec { GST_VAAPI_CODEC_H264 = GST_MAKE_FOURCC('2','6','4',0), GST_VAAPI_CODEC_WMV3 = GST_MAKE_FOURCC('W','M','V',0), GST_VAAPI_CODEC_VC1 = GST_MAKE_FOURCC('V','C','1',0), + GST_VAAPI_CODEC_JPEG = GST_MAKE_FOURCC('J','P','G',0), }; /** @@ -114,6 +115,7 @@ enum _GstVaapiProfile { GST_VAAPI_PROFILE_VC1_SIMPLE = GST_VAAPI_MAKE_PROFILE(VC1,1), GST_VAAPI_PROFILE_VC1_MAIN = GST_VAAPI_MAKE_PROFILE(VC1,2), GST_VAAPI_PROFILE_VC1_ADVANCED = GST_VAAPI_MAKE_PROFILE(VC1,3), + GST_VAAPI_PROFILE_JPEG_BASELINE = GST_VAAPI_MAKE_PROFILE(JPEG,1), }; /** diff --git a/gst/vaapi/gstvaapidecode.c b/gst/vaapi/gstvaapidecode.c index 638a1574..751c1581 100644 --- a/gst/vaapi/gstvaapidecode.c +++ b/gst/vaapi/gstvaapidecode.c @@ -49,6 +49,7 @@ #endif #if USE_CODEC_PARSERS # include <gst/vaapi/gstvaapidecoder_h264.h> +# include <gst/vaapi/gstvaapidecoder_jpeg.h> # include <gst/vaapi/gstvaapidecoder_mpeg2.h> # include <gst/vaapi/gstvaapidecoder_mpeg4.h> # include <gst/vaapi/gstvaapidecoder_vc1.h> @@ -83,6 +84,7 @@ static const char gst_vaapidecode_sink_caps_str[] = GST_CAPS_CODEC("video/x-h263") GST_CAPS_CODEC("video/x-h264") GST_CAPS_CODEC("video/x-wmv") + GST_CAPS_CODEC("image/jpeg") ; static const char gst_vaapidecode_src_caps_str[] = @@ -343,6 +345,10 @@ gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps) gst_structure_has_name(structure, "video/x-divx") || gst_structure_has_name(structure, "video/x-xvid")) decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps); +#if USE_JPEG_DECODER + else if (gst_structure_has_name(structure, "image/jpeg")) + decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps); +#endif #endif } if (!decode->decoder) |