Search code examples
c++imagesegmentation-faultgstreamer

segmentation fault due to an image file


I have tried to integrate gstreamer c code with ZXing-cpp https://github.com/nu-book/zxing-cpp.

Here is my code

#include "core/ReadBarcode.h"
#include "core/TextUtfEncoding.h"

#include <algorithm>
#include <cctype>
#include <cstring>
#include <iostream>
#include <string>
#include <deque>

#include <gst/gst.h>
#include <gst/app/gstappsink.h>
#include <stdlib.h>

using namespace ZXing;

std::deque<ImageView> frameQueue;

GstFlowReturn
new_preroll(GstAppSink *appsink, gpointer data) {
  g_print ("Got preroll!\n");
  return GST_FLOW_OK;
}

GstFlowReturn
new_sample(GstAppSink *appsink, gpointer data) {
  static int framecount = 0;
  framecount++;

  GstSample *sample = gst_app_sink_pull_sample(appsink);
  GstCaps *caps = gst_sample_get_caps(sample);
  GstBuffer *buffer = gst_sample_get_buffer(sample);
  const GstStructure *info = gst_sample_get_info(sample);

  // ---- Read frame and convert to ImageView format ---------------
  GstMapInfo map;
  gst_buffer_map (buffer, &map, GST_MAP_READ);

  g_print("Processing new data \n");

   ImageView frame( (unsigned char *)map.data, 720, 480,ImageFormat::RGBX);
   frameQueue.push_back(frame);

   gst_buffer_unmap(buffer, &map);

  // ------------------------------------------------------------
  // show caps on first frame
  if (framecount == 1) {
    g_print ("%s\n", gst_caps_to_string(caps));
  }
  gst_sample_unref (sample);

  return GST_FLOW_OK;
}

static gboolean
my_bus_callback (GstBus *bus, GstMessage *message, gpointer data) {
  g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
  switch (GST_MESSAGE_TYPE (message)) {
    case GST_MESSAGE_ERROR: {
      GError *err;
      gchar *debug;

      gst_message_parse_error (message, &err, &debug);
      g_print ("Error: %s\n", err->message);
      g_error_free (err);
      g_free (debug);
      break;
    }
    case GST_MESSAGE_EOS:
      g_print ("End of Stream \n ");
      // end-of-stream
      break;
    case GST_MESSAGE_STATE_CHANGED:
      // state has changed
      break;
    default:
      // unhandled message
      g_print ("Unknown Error \n ");
      break;
  }
  /* we want to be notified again the next time there is a message
   * on the bus, so returning TRUE (FALSE means we want to stop watching
   * for messages on the bus and our callback should not be called again)
   */
  return TRUE;
}

int main (int argc, char *argv[])
{
  GError *error = NULL;

  gst_init (&argc, &argv);

  gchar *descr = g_strdup(
    "v4l2src ! "
    "videorate ! "
    "video/x-raw,width=720,height=480 ! "
    "tee name=qr  "
    "qr. ! queue ! "
    "timeoverlay ! "
    "autovideosink  "
    "qr. ! queue ! "
    "appsink name=qrsink sync=true "
  );

  g_print("launching pipeline \n");
  GstElement *pipeline = gst_parse_launch (descr, &error);

  if (error != NULL) {
    g_print ("could not construct pipeline: %s\n", error->message);
    g_error_free (error);
    exit (-1);
  }

  /* get sink */
  GstElement *sink = gst_bin_get_by_name (GST_BIN (pipeline), "qrsink");

  gst_app_sink_set_emit_signals((GstAppSink*)sink, true);
  gst_app_sink_set_drop((GstAppSink*)sink, true);
  gst_app_sink_set_max_buffers((GstAppSink*)sink, 1);
  GstAppSinkCallbacks callbacks = { NULL, new_preroll, new_sample };
  gst_app_sink_set_callbacks (GST_APP_SINK(sink), &callbacks, NULL, NULL);

  GstBus *bus;
  guint bus_watch_id;
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  bus_watch_id = gst_bus_add_watch (bus, my_bus_callback, NULL);
  gst_object_unref (bus);

  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);

  while(1) {
    // g_main_iteration(false);
    g_main_context_iteration(NULL, false);

    DecodeHints hints;
    bool haveResult;

    if (frameQueue.size() > 0) {
        g_print("Outputting image  \n");
        ImageView subject = frameQueue.front();
        g_print("Begin Image Processing \n");
        auto result = ReadBarcode(subject, hints);
    }
  }

  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
  gst_object_unref (GST_OBJECT (pipeline));

  return 0;
}

Right now I am facing the following error

Segmentation fault: (Core dumped)

I have narrowed down the error to be at this line

auto result = ReadBarcode(subject, hints);

Somehow memory access to the image object(subject is of objectType ImageView whose definition could be found in ZXing-cpp github site ReadBarCode.h/cpp) is not allowed. I wonder what is the problem.

Or wonder could the error be on assignment of gstreamer buffer to a queue

ImageView frame( (unsigned char *)map.data, 720, 480,ImageFormat::RGBX);
frameQueue.push_back(frame);

Thanks for your help


Solution

  • Have made the following changes to the code. Instead of using ImageView(which turns out to be an view of object instead of holding the memory), I have switched to using std::array<unsigned char, memory_size> frame as holder of buffer and used it to pass into the queue

      std::array<unsigned char, FRAME_HEIGHT * FRAME_WIDTH> frame;
      std::memcpy (frame.data(), buf, FRAME_HEIGHT * FRAME_WIDTH);
    
      frameQueue.push_back(frame);
    

    On the other size, i get the front of queue

    auto result = ReadBarcode( { (frameQueue.front()).data(), FRAME_WIDTH, FRAME_HEIGHT, ImageFormat::Lum}, hints);
    

    and when the operation is over

    frameQueue.pop_front()

    Is there anything wrong with this implementation?

    Regards