From 82be4ad39537c8328dc9d458e4ecbde8c68e3770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 21 Jun 2015 11:20:57 +0100 Subject: examples: add small jpeg codecparser test https://bugzilla.gnome.org/show_bug.cgi?id=673925 --- .gitignore | 1 + configure.ac | 1 + tests/examples/Makefile.am | 6 +- tests/examples/codecparsers/Makefile.am | 7 + tests/examples/codecparsers/parse-jpeg.c | 307 +++++++++++++++++++++++++++++++ 5 files changed, 319 insertions(+), 3 deletions(-) create mode 100644 tests/examples/codecparsers/Makefile.am create mode 100644 tests/examples/codecparsers/parse-jpeg.c diff --git a/.gitignore b/.gitignore index aac56a80f..90b053792 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ gst*orc.h /ext/gsettings/org.freedesktop.gstreamer-0.10.default-elements.gschema.xml /tests/check/orc +/tests/examples/codecparsers/parse-jpeg /tests/examples/shapewipe/shapewipe-example /tests/examples/jack/jack_client /tests/examples/opencv/gstmotioncells_dynamic_test diff --git a/configure.ac b/configure.ac index 3de8d6853..501cdef50 100644 --- a/configure.ac +++ b/configure.ac @@ -3273,6 +3273,7 @@ tests/files/Makefile tests/examples/Makefile tests/examples/avsamplesink/Makefile tests/examples/camerabin2/Makefile +tests/examples/codecparsers/Makefile tests/examples/directfb/Makefile tests/examples/gl/Makefile tests/examples/gl/cocoa/Makefile diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am index 009ff73f4..c26d3d9fd 100644 --- a/tests/examples/Makefile.am +++ b/tests/examples/Makefile.am @@ -46,8 +46,8 @@ playout_SOURCES = playout.c playout_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) playout_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(GST_LIBS) -SUBDIRS= mpegts $(DIRECTFB_DIR) $(GTK_EXAMPLES) $(OPENCV_EXAMPLES) $(GL_DIR) \ - $(GTK3_DIR) $(AVSAMPLE_DIR) -DIST_SUBDIRS= mpegts camerabin2 directfb mxf opencv uvch264 gl gtk avsamplesink +SUBDIRS= codecparsers mpegts $(DIRECTFB_DIR) $(GTK_EXAMPLES) $(OPENCV_EXAMPLES) \ + $(GL_DIR) $(GTK3_DIR) $(AVSAMPLE_DIR) +DIST_SUBDIRS= codecparsers mpegts camerabin2 directfb mxf opencv uvch264 gl gtk avsamplesink include $(top_srcdir)/common/parallel-subdirs.mak diff --git a/tests/examples/codecparsers/Makefile.am b/tests/examples/codecparsers/Makefile.am new file mode 100644 index 000000000..1a3b87ce5 --- /dev/null +++ b/tests/examples/codecparsers/Makefile.am @@ -0,0 +1,7 @@ +noinst_PROGRAMS = parse-jpeg + +parse_jpeg_SOURCES = parse-jpeg.c +parse_jpeg_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_CFLAGS) +parse_jpeg_LDFLAGS = $(GST_LIBS) +parse_jpeg_LDADD = \ + $(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-$(GST_API_VERSION).la diff --git a/tests/examples/codecparsers/parse-jpeg.c b/tests/examples/codecparsers/parse-jpeg.c new file mode 100644 index 000000000..fe429998f --- /dev/null +++ b/tests/examples/codecparsers/parse-jpeg.c @@ -0,0 +1,307 @@ +/* GStreamer JPEG parser test utility + * Copyright (C) 2015 Tim-Philipp Müller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +static GstBuffer *app_segments[16]; /* NULL */ + +static const gchar * +get_marker_name (guint8 marker) +{ + switch (marker) { + case GST_JPEG_MARKER_SOF0: + return "SOF (Baseline)"; + case GST_JPEG_MARKER_SOF1: + return "SOF (Extended Sequential, Huffman)"; + case GST_JPEG_MARKER_SOF2: + return "SOF (Extended Progressive, Huffman)"; + case GST_JPEG_MARKER_SOF3: + return "SOF (Lossless, Huffman)"; + case GST_JPEG_MARKER_SOF5: + return "SOF (Differential Sequential, Huffman)"; + case GST_JPEG_MARKER_SOF6: + return "SOF (Differential Progressive, Huffman)"; + case GST_JPEG_MARKER_SOF7: + return "SOF (Differential Lossless, Huffman)"; + case GST_JPEG_MARKER_SOF9: + return "SOF (Extended Sequential, Arithmetic)"; + case GST_JPEG_MARKER_SOF10: + return "SOF (Progressive, Arithmetic)"; + case GST_JPEG_MARKER_SOF11: + return "SOF (Lossless, Arithmetic)"; + case GST_JPEG_MARKER_SOF13: + return "SOF (Differential Sequential, Arithmetic)"; + case GST_JPEG_MARKER_SOF14: + return "SOF (Differential Progressive, Arithmetic)"; + case GST_JPEG_MARKER_SOF15: + return "SOF (Differential Lossless, Arithmetic)"; + case GST_JPEG_MARKER_DHT: + return "DHT"; + case GST_JPEG_MARKER_DAC: + return "DAC"; + case GST_JPEG_MARKER_SOI: + return "SOI"; + case GST_JPEG_MARKER_EOI: + return "EOI"; + case GST_JPEG_MARKER_SOS: + return "SOS"; + case GST_JPEG_MARKER_DQT: + return "DQT"; + case GST_JPEG_MARKER_DNL: + return "DNL"; + case GST_JPEG_MARKER_DRI: + return "DRI"; + case GST_JPEG_MARKER_APP0: + return "APP0"; + case GST_JPEG_MARKER_APP1: + return "APP1"; + case GST_JPEG_MARKER_APP2: + return "APP2"; + case GST_JPEG_MARKER_APP3: + return "APP3"; + case GST_JPEG_MARKER_APP4: + return "APP4"; + case GST_JPEG_MARKER_APP5: + return "APP5"; + case GST_JPEG_MARKER_APP6: + return "APP6"; + case GST_JPEG_MARKER_APP7: + return "APP7"; + case GST_JPEG_MARKER_APP8: + return "APP8"; + case GST_JPEG_MARKER_APP9: + return "APP9"; + case GST_JPEG_MARKER_APP10: + return "APP10"; + case GST_JPEG_MARKER_APP11: + return "APP11"; + case GST_JPEG_MARKER_APP12: + return "APP12"; + case GST_JPEG_MARKER_APP13: + return "APP13"; + case GST_JPEG_MARKER_APP14: + return "APP14"; + case GST_JPEG_MARKER_APP15: + return "APP15"; + case GST_JPEG_MARKER_COM: + return "COM"; + default: + if (marker > GST_JPEG_MARKER_RST_MIN && marker < GST_JPEG_MARKER_RST_MAX) + return "RST"; + break; + } + return "???"; +} + +static gboolean +parse_jpeg_segment (GstJpegSegment * segment) +{ + switch (segment->marker) { + case GST_JPEG_MARKER_SOF0: + case GST_JPEG_MARKER_SOF1: + case GST_JPEG_MARKER_SOF2: + case GST_JPEG_MARKER_SOF3: + case GST_JPEG_MARKER_SOF9: + case GST_JPEG_MARKER_SOF10: + case GST_JPEG_MARKER_SOF11:{ + GstJpegFrameHdr hdr; + int i; + + if (!gst_jpeg_segment_parse_frame_header (segment, &hdr)) { + g_printerr ("Failed to parse frame header!\n"); + return FALSE; + } + + g_print ("\t\twidth x height = %u x %u\n", hdr.width, hdr.height); + g_print ("\t\tsample precision = %u\n", hdr.sample_precision); + g_print ("\t\tnum components = %u\n", hdr.num_components); + for (i = 0; i < hdr.num_components; ++i) { + g_print ("\t\t%d: id=%d, h=%d, v=%d, qts=%d\n", i, + hdr.components[i].identifier, hdr.components[i].horizontal_factor, + hdr.components[i].vertical_factor, + hdr.components[i].quant_table_selector); + } + break; + } + case GST_JPEG_MARKER_DHT:{ + GstJpegHuffmanTables ht; + + if (!gst_jpeg_segment_parse_huffman_table (segment, &ht)) { + g_printerr ("Failed to parse huffman table!\n"); + return FALSE; + } + break; + } + case GST_JPEG_MARKER_DQT:{ + GstJpegQuantTables qt; + + if (!gst_jpeg_segment_parse_quantization_table (segment, &qt)) { + g_printerr ("Failed to parse quantization table!\n"); + return FALSE; + } + break; + } + case GST_JPEG_MARKER_SOS:{ + GstJpegScanHdr hdr; + int i; + + if (!gst_jpeg_segment_parse_scan_header (segment, &hdr)) { + g_printerr ("Failed to parse scan header!\n"); + return FALSE; + } + + g_print ("\t\tnum components = %u\n", hdr.num_components); + for (i = 0; i < hdr.num_components; ++i) { + g_print ("\t\t %d: cs=%d, dcs=%d, acs=%d\n", i, + hdr.components[i].component_selector, + hdr.components[i].dc_selector, hdr.components[i].ac_selector); + } + } + case GST_JPEG_MARKER_COM: + /* gst_util_dump_mem (segment->data + segment->offset, segment->size); */ + break; + default: + if (segment->marker >= GST_JPEG_MARKER_APP_MIN + && segment->marker <= GST_JPEG_MARKER_APP_MAX) { + guint n = segment->marker - GST_JPEG_MARKER_APP_MIN; + + if (app_segments[n] == NULL) + app_segments[n] = gst_buffer_new (); + + gst_buffer_append_memory (app_segments[n], + gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, + (guint8 *) segment->data + segment->offset, + segment->size, 0, segment->size, NULL, NULL)); + } + break; + } + return TRUE; +} + +static void +parse_jpeg (const guint8 * data, gsize size) +{ + GstJpegSegment segment; + guint offset = 0; + + while (gst_jpeg_parse (&segment, data, size, offset)) { + if (segment.offset > offset + 2) + g_print (" skipped %u bytes\n", (guint) segment.offset - offset - 2); + + g_print ("%6d bytes at offset %-8u : %s\n", (gint) segment.size, + segment.offset, get_marker_name (segment.marker)); + + if (segment.marker == GST_JPEG_MARKER_EOI) + break; + + if (offset + segment.size < size && + parse_jpeg_segment (&segment) && segment.size >= 0) + offset = segment.offset + segment.size; + else + offset += 2; + }; +} + +static void +process_file (const gchar * fn) +{ + GError *err = NULL; + gchar *data = NULL; + gsize size = 0; + guint i; + + g_print ("===============================================================\n"); + g_print (" %s\n", fn); + g_print ("===============================================================\n"); + + if (!g_file_get_contents (fn, &data, &size, &err)) { + g_error ("%s", err->message); + g_error_free (err); + return; + } + + parse_jpeg ((const guint8 *) data, size); + + for (i = 0; i < G_N_ELEMENTS (app_segments); ++i) { + if (app_segments[i] != NULL) { + GstMapInfo map = GST_MAP_INFO_INIT; + + /* Could parse/extract tags here */ + gst_buffer_map (app_segments[i], &map, GST_MAP_READ); + g_print ("\tAPP%-2u : %u bytes\n", i, (guint) map.size); + gst_util_dump_mem ((guchar *) map.data, MIN (map.size, 16)); + gst_buffer_unmap (app_segments[i], &map); + gst_buffer_unref (app_segments[i]); + app_segments[i] = NULL; + } + } + + g_free (data); +} + +int +main (int argc, gchar ** argv) +{ + gchar **filenames = NULL; + GOptionEntry options[] = { + {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL}, + {NULL} + }; + GOptionContext *ctx; + GError *err = NULL; + guint i, num; + + gst_init (&argc, &argv); + + if (argc == 1) { + g_printerr ("Usage: %s FILE.JPG [FILE2.JPG] [FILE..JPG]\n", argv[0]); + return -1; + } + + ctx = g_option_context_new ("JPEG FILES"); + g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE); + g_option_context_add_group (ctx, gst_init_get_option_group ()); + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + g_print ("Error initializing: %s\n", GST_STR_NULL (err->message)); + exit (1); + } + g_option_context_free (ctx); + + if (filenames == NULL || *filenames == NULL) { + g_printerr ("Please provide one or more filenames."); + return 1; + } + + num = g_strv_length (filenames); + + for (i = 0; i < num; ++i) { + process_file (filenames[i]); + } + + g_strfreev (filenames); + + return 0; +} -- cgit v1.2.1