调用 gdk_quartz_window_get_nsview() 给我和错误

问题描述

我在我的 mac 上关注这个 gstream tutorial 但我一直收到错误:函数 'gdk_quartz_window_get_nsview' 的隐式声明在 mac 上的 C99 [-Werror,-Wimplicit-function-declaration] 中无效。我知道隐式声明意味着我可能缺少一个包含,但我似乎无法弄清楚需要包含哪个头文件,或者我是否没有导出 pkg。请帮忙。谢谢。这是代码。

#include <string.h>

#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gst/video/videooverlay.h>

#include <gdk/gdk.h>
#if defined (GDK_WINDOWING_X11)
#include <gdk/gdkx.h>
#elif defined (GDK_WINDOWING_WIN32)
#include <gdk/gdkwin32.h>
#elif defined (GDK_WINDOWING_QUARTZ)
#include <gdk/gdkquartz.h>
#endif

/* Structure to contain all our information,so we can pass it around */
typedef struct _CustomData {
  GstElement *playbin;           /* Our one and only pipeline */

  GtkWidget *slider;              /* Slider widget to keep track of current position */
  GtkWidget *streams_list;        /* Text widget to display info about the streams */
  gulong slider_update_signal_id; /* Signal ID for the slider update signal */

  GstState state;                 /* Current state of the pipeline */
  gint64 duration;                /* Duration of the clip,in nanoseconds */
} CustomData;

/* This function is called when the GUI toolkit creates the physical window that will hold the video.
 * At this point we can retrieve its handler (which has a different meaning depending on the windowing system)
 * and pass it to GStreamer through the VideoOverlay interface. */
static void realize_cb (GtkWidget *widget,CustomData *data) {
  GdkWindow *window = gtk_widget_get_window (widget);
  guintptr window_handle;

  if (!gdk_window_ensure_native (window))
    g_error ("Couldn't create native window needed for GstVideoOverlay!");

  /* Retrieve window handler from GDK */
#if defined (GDK_WINDOWING_WIN32)
  window_handle = (guintptr)GDK_WINDOW_HWND (window);
#elif defined (GDK_WINDOWING_QUARTZ)
  window_handle = gdk_quartz_window_get_nsview (window);
#elif defined (GDK_WINDOWING_X11)
  window_handle = GDK_WINDOW_XID (window);
#endif
  /* Pass it to playbin,which implements VideoOverlay and will forward it to the video sink */
  gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (data->playbin),window_handle);
}

/* This function is called when the PLAY button is clicked */
static void play_cb (GtkButton *button,CustomData *data) {
  gst_element_set_state (data->playbin,GST_STATE_PLAYING);
}

/* This function is called when the PAUSE button is clicked */
static void pause_cb (GtkButton *button,GST_STATE_PAUSED);
}

/* This function is called when the STOP button is clicked */
static void stop_cb (GtkButton *button,GST_STATE_READY);
}

/* This function is called when the main window is closed */
static void delete_event_cb (GtkWidget *widget,GdkEvent *event,CustomData *data) {
  stop_cb (NULL,data);
  gtk_main_quit ();
}

/* This function is called everytime the video window needs to be redrawn (due to damage/exposure,* rescaling,etc). GStreamer takes care of this in the PAUSED and PLAYING states,otherwise,* we simply draw a black rectangle to avoid garbage showing up. */
static gboolean draw_cb (GtkWidget *widget,cairo_t *cr,CustomData *data) {
  if (data->state < GST_STATE_PAUSED) {
    GtkAllocation allocation;

    /* Cairo is a 2D graphics library which we use here to clean the video window.
     * It is used by GStreamer for other reasons,so it will always be available to us. */
    gtk_widget_get_allocation (widget,&allocation);
    cairo_set_source_rgb (cr,0);
    cairo_rectangle (cr,allocation.width,allocation.height);
    cairo_fill (cr);
  }

  return FALSE;
}

/* This function is called when the slider changes its position. We perform a seek to the
 * new position here. */
static void slider_cb (GtkRange *range,CustomData *data) {
  gdouble value = gtk_range_get_value (GTK_RANGE (data->slider));
  gst_element_seek_simple (data->playbin,GST_FORMAT_TIME,GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,(gint64)(value * GST_SECOND));
}

/* This creates all the GTK+ widgets that compose our application,and registers the callbacks */
static void create_ui (CustomData *data) {
  GtkWidget *main_window;  /* The uppermost window,containing all other windows */
  GtkWidget *video_window; /* The drawing area where the video will be shown */
  GtkWidget *main_box;     /* VBox to hold main_hbox and the controls */
  GtkWidget *main_hbox;    /* HBox to hold the video_window and the stream info text widget */
  GtkWidget *controls;     /* HBox to hold the buttons and the slider */
  GtkWidget *play_button,*pause_button,*stop_button; /* Buttons */

  main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  g_signal_connect (G_OBJECT (main_window),"delete-event",G_CALLBACK (delete_event_cb),data);

  video_window = gtk_drawing_area_new ();
  gtk_widget_set_double_buffered (video_window,FALSE);
  g_signal_connect (video_window,"realize",G_CALLBACK (realize_cb),data);
  g_signal_connect (video_window,"draw",G_CALLBACK (draw_cb),data);

  play_button = gtk_button_new_from_icon_name ("media-playback-start",GTK_ICON_SIZE_SMALL_TOOLBAR);
  g_signal_connect (G_OBJECT (play_button),"clicked",G_CALLBACK (play_cb),data);

  pause_button = gtk_button_new_from_icon_name ("media-playback-pause",GTK_ICON_SIZE_SMALL_TOOLBAR);
  g_signal_connect (G_OBJECT (pause_button),G_CALLBACK (pause_cb),data);

  stop_button = gtk_button_new_from_icon_name ("media-playback-stop",GTK_ICON_SIZE_SMALL_TOOLBAR);
  g_signal_connect (G_OBJECT (stop_button),G_CALLBACK (stop_cb),data);

  data->slider = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL,100,1);
  gtk_scale_set_draw_value (GTK_SCALE (data->slider),0);
  data->slider_update_signal_id = g_signal_connect (G_OBJECT (data->slider),"value-changed",G_CALLBACK (slider_cb),data);

  data->streams_list = gtk_text_view_new ();
  gtk_text_view_set_editable (GTK_TEXT_VIEW (data->streams_list),FALSE);

  controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,0);
  gtk_box_pack_start (GTK_BOX (controls),play_button,FALSE,2);
  gtk_box_pack_start (GTK_BOX (controls),pause_button,stop_button,data->slider,TRUE,2);

  main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,0);
  gtk_box_pack_start (GTK_BOX (main_hbox),video_window,data->streams_list,2);

  main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL,0);
  gtk_box_pack_start (GTK_BOX (main_box),main_hbox,controls,0);
  gtk_container_add (GTK_CONTAINER (main_window),main_box);
  gtk_window_set_default_size (GTK_WINDOW (main_window),640,480);

  gtk_widget_show_all (main_window);
}

/* This function is called periodically to refresh the GUI */
static gboolean refresh_ui (CustomData *data) {
  gint64 current = -1;

  /* We do not want to update anything unless we are in the PAUSED or PLAYING states */
  if (data->state < GST_STATE_PAUSED)
    return TRUE;

  /* If we didn't know it yet,query the stream duration */
  if (!GST_CLOCK_TIME_IS_VALID (data->duration)) {
    if (!gst_element_query_duration (data->playbin,&data->duration)) {
      g_printerr ("Could not query current duration.\n");
    } else {
      /* Set the range of the slider to the clip duration,in SECONDS */
      gtk_range_set_range (GTK_RANGE (data->slider),(gdouble)data->duration / GST_SECOND);
    }
  }

  if (gst_element_query_position (data->playbin,&current)) {
    /* Block the "value-changed" signal,so the slider_cb function is not called
     * (which would trigger a seek the user has not requested) */
    g_signal_handler_block (data->slider,data->slider_update_signal_id);
    /* Set the position of the slider to the current pipeline positoin,in SECONDS */
    gtk_range_set_value (GTK_RANGE (data->slider),(gdouble)current / GST_SECOND);
    /* Re-enable the signal */
    g_signal_handler_unblock (data->slider,data->slider_update_signal_id);
  }
  return TRUE;
}

/* This function is called when new metadata is discovered in the stream */
static void tags_cb (GstElement *playbin,gint stream,CustomData *data) {
  /* We are possibly in a GStreamer working thread,so we notify the main
   * thread of this event through a message in the bus */
  gst_element_post_message (playbin,gst_message_new_application (GST_OBJECT (playbin),gst_structure_new_empty ("tags-changed")));
}

/* This function is called when an error message is posted on the bus */
static void error_cb (GstBus *bus,GstMessage *msg,CustomData *data) {
  GError *err;
  gchar *debug_info;

  /* Print error details on the screen */
  gst_message_parse_error (msg,&err,&debug_info);
  g_printerr ("Error received from element %s: %s\n",GST_OBJECT_NAME (msg->src),err->message);
  g_printerr ("Debugging information: %s\n",debug_info ? debug_info : "none");
  g_clear_error (&err);
  g_free (debug_info);

  /* Set the pipeline to READY (which stops playback) */
  gst_element_set_state (data->playbin,GST_STATE_READY);
}

/* This function is called when an End-Of-Stream message is posted on the bus.
 * We just set the pipeline to READY (which stops playback) */
static void eos_cb (GstBus *bus,CustomData *data) {
  g_print ("End-Of-Stream reached.\n");
  gst_element_set_state (data->playbin,GST_STATE_READY);
}

/* This function is called when the pipeline changes states. We use it to
 * keep track of the current state. */
static void state_changed_cb (GstBus *bus,CustomData *data) {
  GstState old_state,new_state,pending_state;
  gst_message_parse_state_changed (msg,&old_state,&new_state,&pending_state);
  if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data->playbin)) {
    data->state = new_state;
    g_print ("State set to %s\n",gst_element_state_get_name (new_state));
    if (old_state == GST_STATE_READY && new_state == GST_STATE_PAUSED) {
      /* For extra responsiveness,we refresh the GUI as soon as we reach the PAUSED state */
      refresh_ui (data);
    }
  }
}

/* Extract metadata from all the streams and write it to the text widget in the GUI */
static void analyze_streams (CustomData *data) {
  gint i;
  GstTagList *tags;
  gchar *str,*total_str;
  guint rate;
  gint n_video,n_audio,n_text;
  GtkTextBuffer *text;

  /* Clean current contents of the widget */
  text = gtk_text_view_get_buffer (GTK_TEXT_VIEW (data->streams_list));
  gtk_text_buffer_set_text (text,"",-1);

  /* Read some properties */
  g_object_get (data->playbin,"n-video",&n_video,NULL);
  g_object_get (data->playbin,"n-audio",&n_audio,"n-text",&n_text,NULL);

  for (i = 0; i < n_video; i++) {
    tags = NULL;
    /* Retrieve the stream's video tags */
    g_signal_emit_by_name (data->playbin,"get-video-tags",i,&tags);
    if (tags) {
      total_str = g_strdup_printf ("video stream %d:\n",i);
      gtk_text_buffer_insert_at_cursor (text,total_str,-1);
      g_free (total_str);
      gst_tag_list_get_string (tags,GST_TAG_VIDEO_CODEC,&str);
      total_str = g_strdup_printf ("  codec: %s\n",str ? str : "unknown");
      gtk_text_buffer_insert_at_cursor (text,-1);
      g_free (total_str);
      g_free (str);
      gst_tag_list_free (tags);
    }
  }

  for (i = 0; i < n_audio; i++) {
    tags = NULL;
    /* Retrieve the stream's audio tags */
    g_signal_emit_by_name (data->playbin,"get-audio-tags",&tags);
    if (tags) {
      total_str = g_strdup_printf ("\naudio stream %d:\n",-1);
      g_free (total_str);
      if (gst_tag_list_get_string (tags,GST_TAG_AUDIO_CODEC,&str)) {
        total_str = g_strdup_printf ("  codec: %s\n",str);
        gtk_text_buffer_insert_at_cursor (text,-1);
        g_free (total_str);
        g_free (str);
      }
      if (gst_tag_list_get_string (tags,GST_TAG_LANGUAGE_CODE,&str)) {
        total_str = g_strdup_printf ("  language: %s\n",-1);
        g_free (total_str);
        g_free (str);
      }
      if (gst_tag_list_get_uint (tags,GST_TAG_BITRATE,&rate)) {
        total_str = g_strdup_printf ("  bitrate: %d\n",rate);
        gtk_text_buffer_insert_at_cursor (text,-1);
        g_free (total_str);
      }
      gst_tag_list_free (tags);
    }
  }

  for (i = 0; i < n_text; i++) {
    tags = NULL;
    /* Retrieve the stream's subtitle tags */
    g_signal_emit_by_name (data->playbin,"get-text-tags",&tags);
    if (tags) {
      total_str = g_strdup_printf ("\nsubtitle stream %d:\n",-1);
        g_free (total_str);
        g_free (str);
      }
      gst_tag_list_free (tags);
    }
  }
}

/* This function is called when an "application" message is posted on the bus.
 * Here we retrieve the message posted by the tags_cb callback */
static void application_cb (GstBus *bus,CustomData *data) {
  if (g_strcmp0 (gst_structure_get_name (gst_message_get_structure (msg)),"tags-changed") == 0) {
    /* If the message is the "tags-changed" (only one we are currently issuing),update
     * the stream info GUI */
    analyze_streams (data);
  }
}

int main(int argc,char *argv[]) {
  CustomData data;
  GstStateChangeReturn ret;
  GstBus *bus;

  /* Initialize GTK */
  gtk_init (&argc,&argv);

  /* Initialize GStreamer */
  gst_init (&argc,&argv);

  /* Initialize our data structure */
  memset (&data,sizeof (data));
  data.duration = GST_CLOCK_TIME_NONE;

  /* Create the elements */
  data.playbin = gst_element_factory_make ("playbin","playbin");

  if (!data.playbin) {
    g_printerr ("Not all elements could be created.\n");
    return -1;
  }

  /* Set the URI to play */
  g_object_set (data.playbin,"uri","https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm",NULL);

  /* Connect to interesting signals in playbin */
  g_signal_connect (G_OBJECT (data.playbin),"video-tags-changed",(GCallback) tags_cb,&data);
  g_signal_connect (G_OBJECT (data.playbin),"audio-tags-changed","text-tags-changed",&data);

  /* Create the GUI */
  create_ui (&data);

  /* Instruct the bus to emit signals for each received message,and connect to the interesting signals */
  bus = gst_element_get_bus (data.playbin);
  gst_bus_add_signal_watch (bus);
  g_signal_connect (G_OBJECT (bus),"message::error",(GCallback)error_cb,&data);
  g_signal_connect (G_OBJECT (bus),"message::eos",(GCallback)eos_cb,"message::state-changed",(GCallback)state_changed_cb,"message::application",(GCallback)application_cb,&data);
  gst_object_unref (bus);

  /* Start playing */
  ret = gst_element_set_state (data.playbin,GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    g_printerr ("Unable to set the pipeline to the playing state.\n");
    gst_object_unref (data.playbin);
    return -1;
  }

  /* Register a function that GLib will call every second */
  g_timeout_add_seconds (1,(GSourceFunc)refresh_ui,&data);

  /* Start the GTK main loop. We will not regain control until gtk_main_quit is called. */
  gtk_main ();

  /* Free resources */
  gst_element_set_state (data.playbin,GST_STATE_NULL);
  gst_object_unref (data.playbin);
  return 0;
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...