png: Port to 0.11 again

This commit is contained in:
Sebastian Dröge 2012-05-28 15:22:26 +02:00
parent 982c1b479f
commit 5ba30e6111
4 changed files with 147 additions and 93 deletions

View file

@ -30,6 +30,8 @@
#include <stdlib.h>
#include <string.h>
#include <gst/video/video.h>
#include <gst/video/gstvideometa.h>
#include <gst/video/gstvideopool.h>
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY_STATIC (pngdec_debug);
@ -46,17 +48,18 @@ static gboolean gst_pngdec_set_format (GstVideoDecoder * Decoder,
GstVideoCodecState * state);
static GstFlowReturn gst_pngdec_handle_frame (GstVideoDecoder * decoder,
GstVideoCodecFrame * frame);
static gboolean gst_pngdec_decide_allocation (GstVideoDecoder * decoder,
GstQuery * query);
GST_BOILERPLATE (GstPngDec, gst_pngdec, GstVideoDecoder,
GST_TYPE_VIDEO_DECODER);
#define parent_class gst_pngdec_parent_class
G_DEFINE_TYPE (GstPngDec, gst_pngdec, GST_TYPE_VIDEO_DECODER);
static GstStaticPadTemplate gst_pngdec_src_pad_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_RGB ";"
GST_VIDEO_CAPS_ARGB_64 ";"
GST_VIDEO_CAPS_GRAY8 ";" GST_VIDEO_CAPS_GRAY16 ("BIG_ENDIAN"))
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
("{ RGBA, RGB, ARGB64, GRAY8, GRAY16_BE }"))
);
static GstStaticPadTemplate gst_pngdec_sink_pad_template =
@ -67,37 +70,32 @@ GST_STATIC_PAD_TEMPLATE ("sink",
);
static void
gst_pngdec_base_init (gpointer g_class)
gst_pngdec_class_init (GstPngDecClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
GstElementClass *element_class = (GstElementClass *) klass;
GstVideoDecoderClass *vdec_class = (GstVideoDecoderClass *) klass;
gst_element_class_add_static_pad_template (element_class,
&gst_pngdec_src_pad_template);
gst_element_class_add_static_pad_template (element_class,
&gst_pngdec_sink_pad_template);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_pngdec_src_pad_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_pngdec_sink_pad_template));
gst_element_class_set_details_simple (element_class, "PNG image decoder",
"Codec/Decoder/Image",
"Decode a png video frame to a raw image",
"Wim Taymans <wim@fluendo.com>");
}
static void
gst_pngdec_class_init (GstPngDecClass * klass)
{
GstVideoDecoderClass *vdec_class = (GstVideoDecoderClass *) klass;
vdec_class->start = gst_pngdec_start;
vdec_class->reset = gst_pngdec_reset;
vdec_class->set_format = gst_pngdec_set_format;
vdec_class->handle_frame = gst_pngdec_handle_frame;
vdec_class->decide_allocation = gst_pngdec_decide_allocation;
GST_DEBUG_CATEGORY_INIT (pngdec_debug, "pngdec", 0, "PNG image decoder");
}
static void
gst_pngdec_init (GstPngDec * pngdec, GstPngDecClass * klass)
gst_pngdec_init (GstPngDec * pngdec)
{
pngdec->buffer_out = NULL;
pngdec->png = NULL;
pngdec->info = NULL;
pngdec->endinfo = NULL;
@ -124,8 +122,6 @@ user_info_callback (png_structp png_ptr, png_infop info)
{
GstPngDec *pngdec = NULL;
GstFlowReturn ret = GST_FLOW_OK;
size_t buffer_size;
guint height;
GST_LOG ("info ready");
@ -136,24 +132,12 @@ user_info_callback (png_structp png_ptr, png_infop info)
goto beach;
}
height = GST_VIDEO_INFO_HEIGHT (&pngdec->output_state->info);
/* Allocate output buffer */
pngdec->rowbytes = png_get_rowbytes (pngdec->png, pngdec->info);
GST_DEBUG ("png told us each row takes %d bytes", pngdec->rowbytes);
if (pngdec->rowbytes > (G_MAXUINT32 - 3)
|| height > G_MAXUINT32 / pngdec->rowbytes) {
ret = GST_FLOW_ERROR;
goto beach;
}
pngdec->rowbytes = GST_ROUND_UP_4 (pngdec->rowbytes);
buffer_size = height * pngdec->rowbytes;
GST_DEBUG ("Allocating a buffer of %d bytes", buffer_size);
g_assert (pngdec->buffer_out == NULL);
pngdec->buffer_out = pngdec->current_frame->output_buffer =
gst_buffer_new_and_alloc (buffer_size);
ret =
gst_video_decoder_alloc_output_frame (GST_VIDEO_DECODER (pngdec),
pngdec->current_frame);
if (G_UNLIKELY (ret != GST_FLOW_OK))
GST_DEBUG_OBJECT (pngdec, "failed to acquire buffer");
beach:
pngdec->ret = ret;
@ -185,13 +169,26 @@ user_endrow_callback (png_structp png_ptr, png_bytep new_row,
/* If buffer_out doesn't exist, it means buffer_alloc failed, which
* will already have set the return code */
if (GST_IS_BUFFER (pngdec->buffer_out)) {
size_t offset = row_num * pngdec->rowbytes;
if (GST_IS_BUFFER (pngdec->current_frame->output_buffer)) {
GstVideoFrame frame;
GstBuffer *buffer = pngdec->current_frame->output_buffer;
size_t offset;
gint width;
guint8 *data;
if (!gst_video_frame_map (&frame, &pngdec->output_state->info, buffer,
GST_MAP_WRITE)) {
pngdec->ret = GST_FLOW_ERROR;
return;
}
data = GST_VIDEO_FRAME_COMP_DATA (&frame, 0);
offset = row_num * GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0);
GST_LOG ("got row %u, copying in buffer %p at offset %" G_GSIZE_FORMAT,
(guint) row_num, pngdec->buffer_out, offset);
memcpy (GST_BUFFER_DATA (pngdec->buffer_out) + offset, new_row,
pngdec->rowbytes);
(guint) row_num, pngdec->current_frame->output_buffer, offset);
width = GST_ROUND_UP_4 (png_get_rowbytes (pngdec->png, pngdec->info));
memcpy (data + offset, new_row, width);
gst_video_frame_unmap (&frame);
pngdec->ret = GST_FLOW_OK;
}
}
@ -205,14 +202,16 @@ user_end_callback (png_structp png_ptr, png_infop info)
GST_LOG_OBJECT (pngdec, "and we are done reading this image");
if (!pngdec->buffer_out)
if (!pngdec->current_frame->output_buffer)
return;
gst_buffer_unmap (pngdec->current_frame->input_buffer,
&pngdec->current_frame_map);
pngdec->ret =
gst_video_decoder_finish_frame (GST_VIDEO_DECODER (pngdec),
pngdec->current_frame);
pngdec->buffer_out = NULL;
pngdec->image_ready = TRUE;
}
@ -344,7 +343,7 @@ gst_pngdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
GstFlowReturn ret = GST_FLOW_OK;
GST_LOG_OBJECT (pngdec, "Got buffer, size=%u",
GST_BUFFER_SIZE (frame->input_buffer));
gst_buffer_get_size (frame->input_buffer));
/* Let libpng come back here on error */
if (setjmp (png_jmpbuf (pngdec->png))) {
@ -356,9 +355,15 @@ gst_pngdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
pngdec->current_frame = frame;
/* Progressive loading of the PNG image */
if (!gst_buffer_map (frame->input_buffer, &pngdec->current_frame_map,
GST_MAP_READ)) {
GST_WARNING_OBJECT (pngdec, "Failed to map input buffer");
ret = GST_FLOW_ERROR;
goto beach;
}
png_process_data (pngdec->png, pngdec->info,
GST_BUFFER_DATA (frame->input_buffer),
GST_BUFFER_SIZE (frame->input_buffer));
pngdec->current_frame_map.data, pngdec->current_frame_map.size);
if (pngdec->image_ready) {
if (1) {
@ -369,9 +374,13 @@ gst_pngdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
user_info_callback, user_endrow_callback, user_end_callback);
} else {
GST_LOG_OBJECT (pngdec, "sending EOS");
pngdec->ret = GST_FLOW_UNEXPECTED;
pngdec->ret = GST_FLOW_EOS;
}
pngdec->image_ready = FALSE;
} else {
/* An error happened and we have to unmap */
gst_buffer_unmap (pngdec->current_frame->input_buffer,
&pngdec->current_frame_map);
}
ret = pngdec->ret;
@ -380,6 +389,31 @@ beach:
return ret;
}
static gboolean
gst_pngdec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
{
GstBufferPool *pool;
GstStructure *config;
if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query))
return FALSE;
g_assert (gst_query_get_n_allocation_pools (query) > 0);
gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
g_assert (pool != NULL);
config = gst_buffer_pool_get_config (pool);
if (gst_query_has_allocation_meta (query, GST_VIDEO_META_API_TYPE)) {
gst_buffer_pool_config_add_option (config,
GST_BUFFER_POOL_OPTION_VIDEO_META);
}
gst_buffer_pool_set_config (pool, config);
gst_object_unref (pool);
return TRUE;
}
/* Clean up the libpng structures */
static gboolean
gst_pngdec_reset (GstVideoDecoder * decoder, gboolean hard)
@ -472,8 +506,6 @@ gst_pngdec_stop (GstVideoDecoder * decoder)
}
pngdec->color_type = -1;
pngdec->rowbytes = 0;
pngdec->buffer_out = NULL;
return TRUE;
}

View file

@ -44,14 +44,11 @@ struct _GstPngDec
GstVideoCodecState *input_state;
GstVideoCodecState *output_state;
GstMapInfo current_frame_map;
GstVideoCodecFrame *current_frame;
GstFlowReturn ret;
/* Progressive */
GstBuffer *buffer_out;
png_uint_32 rowbytes;
png_structp png;
png_infop info;
png_infop endinfo;

View file

@ -31,6 +31,7 @@
#include <gst/gst.h>
#include "gstpngenc.h"
#include <gst/video/video.h>
#include <gst/video/gstvideometa.h>
#include <zlib.h>
GST_DEBUG_CATEGORY_STATIC (pngenc_debug);
@ -43,7 +44,7 @@ enum
LAST_SIGNAL
};
#define DEFAULT_SNAPSHOT TRUE
#define DEFAULT_SNAPSHOT FALSE
#define DEFAULT_COMPRESSION_LEVEL 6
enum
@ -63,15 +64,14 @@ GST_STATIC_PAD_TEMPLATE ("src",
);
static GstStaticPadTemplate pngenc_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_RGB ";"
GST_VIDEO_CAPS_GRAY8 ";" GST_VIDEO_CAPS_GRAY16 ("BIG_ENDIAN"))
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, RGB, GRAY8, GRAY16_BE }"))
);
GST_BOILERPLATE (GstPngEnc, gst_pngenc, GstVideoEncoder,
GST_TYPE_VIDEO_ENCODER);
#define parent_class gst_pngenc_parent_class
G_DEFINE_TYPE (GstPngEnc, gst_pngenc, GST_TYPE_VIDEO_ENCODER);
static void gst_pngenc_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
@ -82,6 +82,8 @@ static GstFlowReturn gst_pngenc_handle_frame (GstVideoEncoder * encoder,
GstVideoCodecFrame * frame);
static gboolean gst_pngenc_set_format (GstVideoEncoder * encoder,
GstVideoCodecState * state);
static gboolean gst_pngenc_propose_allocation (GstVideoEncoder * encoder,
GstQuery * query);
static void
user_error_fn (png_structp png_ptr, png_const_charp error_msg)
@ -95,28 +97,15 @@ user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
g_warning ("%s", warning_msg);
}
static void
gst_pngenc_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_static_pad_template
(element_class, &pngenc_sink_template);
gst_element_class_add_static_pad_template
(element_class, &pngenc_src_template);
gst_element_class_set_details_simple (element_class, "PNG image encoder",
"Codec/Encoder/Image",
"Encode a video frame to a .png image",
"Jeremy SIMON <jsimon13@yahoo.fr>");
}
static void
gst_pngenc_class_init (GstPngEncClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
GstVideoEncoderClass *venc_class;
gobject_class = (GObjectClass *) klass;
element_class = (GstElementClass *) klass;
venc_class = (GstVideoEncoderClass *) klass;
parent_class = g_type_class_peek_parent (klass);
@ -136,8 +125,18 @@ gst_pngenc_class_init (GstPngEncClass * klass)
DEFAULT_COMPRESSION_LEVEL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_add_pad_template
(element_class, gst_static_pad_template_get (&pngenc_sink_template));
gst_element_class_add_pad_template
(element_class, gst_static_pad_template_get (&pngenc_src_template));
gst_element_class_set_details_simple (element_class, "PNG image encoder",
"Codec/Encoder/Image",
"Encode a video frame to a .png image",
"Jeremy SIMON <jsimon13@yahoo.fr>");
venc_class->set_format = gst_pngenc_set_format;
venc_class->handle_frame = gst_pngenc_handle_frame;
venc_class->propose_allocation = gst_pngenc_propose_allocation;
GST_DEBUG_CATEGORY_INIT (pngenc_debug, "pngenc", 0, "PNG image encoder");
}
@ -185,7 +184,7 @@ gst_pngenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
output_state =
gst_video_encoder_set_output_state (encoder,
gst_caps_new_simple ("image/png", NULL), state);
gst_caps_new_empty_simple ("image/png"), state);
gst_video_codec_state_unref (output_state);
done:
@ -194,7 +193,7 @@ done:
}
static void
gst_pngenc_init (GstPngEnc * pngenc, GstPngEncClass * g_class)
gst_pngenc_init (GstPngEnc * pngenc)
{
/* init settings */
pngenc->png_struct_ptr = NULL;
@ -213,19 +212,34 @@ static void
user_write_data (png_structp png_ptr, png_bytep data, png_uint_32 length)
{
GstPngEnc *pngenc;
GstMemory *mem;
GstMapInfo minfo;
pngenc = (GstPngEnc *) png_get_io_ptr (png_ptr);
if (pngenc->written + length >= GST_BUFFER_SIZE (pngenc->buffer_out)) {
GST_ERROR_OBJECT (pngenc, "output buffer bigger than the input buffer!?");
png_error (png_ptr, "output buffer bigger than the input buffer!?");
mem = gst_allocator_alloc (NULL, length, NULL);
if (!mem) {
GST_ERROR_OBJECT (pngenc, "Failed to allocate memory");
png_error (png_ptr, "Failed to allocate memory");
/* never reached */
return;
}
memcpy (GST_BUFFER_DATA (pngenc->buffer_out) + pngenc->written, data, length);
pngenc->written += length;
if (!gst_memory_map (mem, &minfo, GST_MAP_WRITE)) {
GST_ERROR_OBJECT (pngenc, "Failed to map memory");
gst_memory_unref (mem);
png_error (png_ptr, "Failed to map memory");
/* never reached */
return;
}
memcpy (minfo.data, data, length);
gst_memory_unmap (mem, &minfo);
gst_buffer_append_memory (pngenc->buffer_out, mem);
}
static GstFlowReturn
@ -236,6 +250,7 @@ gst_pngenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
png_byte **row_pointers;
GstFlowReturn ret = GST_FLOW_OK;
GstVideoInfo *info;
GstVideoFrame vframe;
pngenc = GST_PNGENC (encoder);
info = &pngenc->input_state->info;
@ -273,17 +288,21 @@ gst_pngenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
(png_rw_ptr) user_write_data, user_flush_data);
row_pointers = g_new (png_byte *, GST_VIDEO_INFO_HEIGHT (info));
if (!gst_video_frame_map (&vframe, &pngenc->input_state->info,
frame->input_buffer, GST_MAP_READ)) {
GST_ELEMENT_ERROR (pngenc, STREAM, FORMAT, (NULL),
("Failed to map video frame, caps problem?"));
ret = GST_FLOW_ERROR;
goto done;
}
for (row_index = 0; row_index < GST_VIDEO_INFO_HEIGHT (info); row_index++) {
row_pointers[row_index] = GST_BUFFER_DATA (frame->input_buffer) +
(row_index * GST_VIDEO_INFO_COMP_STRIDE (info, 0));
row_pointers[row_index] = GST_VIDEO_FRAME_COMP_DATA (&vframe, 0) +
(row_index * GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 0));
}
/* allocate the output buffer */
pngenc->buffer_out =
gst_buffer_new_and_alloc (GST_VIDEO_INFO_HEIGHT (info) *
GST_VIDEO_INFO_COMP_STRIDE (info, 0));
pngenc->written = 0;
pngenc->buffer_out = gst_buffer_new ();
png_write_info (pngenc->png_struct_ptr, pngenc->png_info_ptr);
png_write_image (pngenc->png_struct_ptr, row_pointers);
@ -295,7 +314,6 @@ gst_pngenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
png_destroy_write_struct (&pngenc->png_struct_ptr, (png_infopp) NULL);
/* Set final size and store */
GST_BUFFER_SIZE (pngenc->buffer_out) = pngenc->written;
frame->output_buffer = pngenc->buffer_out;
pngenc->buffer_out = NULL;
@ -304,7 +322,7 @@ gst_pngenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
goto done;
if (pngenc->snapshot)
ret = GST_FLOW_UNEXPECTED;
ret = GST_FLOW_EOS;
done:
GST_DEBUG_OBJECT (pngenc, "END, ret:%d", ret);
@ -336,6 +354,14 @@ longjmp_fail:
}
}
static gboolean
gst_pngenc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
{
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE);
return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
query);
}
static void
gst_pngenc_get_property (GObject * object,

View file

@ -47,7 +47,6 @@ struct _GstPngEnc
GstVideoCodecState *input_state;
GstBuffer *buffer_out;
guint written;
png_structp png_struct_ptr;
png_infop png_info_ptr;