Gstreamer1.0 - проблема видео-фризе в Gtk3.0 - PullRequest
1 голос
/ 05 марта 2019

Мой английский не очень хорош.Если вы не понимаете, пожалуйста, хотите более четкое объяснение.У меня есть графический интерфейс на Allwinnwer A13.Я использую Gtk3.0 для этого.Также я играю видео в графическом интерфейсе и использую gstreamer1.0 для воспроизведения видео.Я создал GUI с glade.

GUI при воспроизведении видео, в то же время программа воспроизводит информационное сообщение в нужное время.Файл информационных сообщений .wav.Если я не использую информационное сообщение, видео воспроизводится повторно.Если я использую информационное сообщение (в среднем 20 раз), видео начинает сокращаться.Я попытался очистить до gst_element_set_state, но, похоже, не работает.Как я могу исправить эту проблему?Мой код ниже.Я только написал о предмете.Если весь код необходим, пожалуйста, сообщите мне.

#include <string.h>
#include <stdbool.h> 

#include <gtk/gtk.h>
#include <gst/gst.h>
#include <cairo.h>
#include <gst/video/videooverlay.h>
#include "uart.h"
#include  "global.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, *videosink, *announce;           /* Our one and only pipeline */
  GtkImage *image; // image definition
  GtkBuilder *builder; //builder definition

  GtkFixed *fixed; // Fixed
  GtkWidget *label1, *label2;   //label definition
  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;

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 */

  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);


  data->slider = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 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);

  data->builder = gtk_builder_new();
  gtk_builder_add_from_file(data->builder,"/home/olimex/Desktop/NewGUI/GUI_test/builder.glade",NULL);



  main_window=GTK_WINDOW(gtk_builder_get_object(data->builder,"window")); //Definition window of glade
  gtk_builder_connect_signals(data->builder,NULL);

  data->fixed=GTK_WIDGET(gtk_builder_get_object(data->builder,"fixed2"));

  data->image=gtk_image_new_from_file("/home/olimex/Desktop/NewGUI/GUI_test/upArrow2.png");



  data->image=GTK_WIDGET(gtk_builder_get_object(data->builder,"image1")); // Definition image of glade

  data->label1=GTK_WIDGET(gtk_builder_get_object(data->builder,"label4")); // Definition label4 of glade
  data->label2=GTK_WIDGET(gtk_builder_get_object(data->builder,"label5")); // Definition label5 of glade




  main_box=GTK_WIDGET(gtk_builder_get_object(data->builder,"box1")); // Definition video box of glade
  gtk_box_pack_start(GTK_BOX(main_box), video_window,TRUE,TRUE,0); // video play in GUI window
  gtk_window_set_decorated(GTK_WINDOW(main_window),FALSE);  //Hide menu bar

  gtk_container_add(GTK_CONTAINER(main_window),main_box);
  //gtk_widget_reparent(main_window,main_box);

  gtk_label_set_markup(GTK_LABEL(data->label1), "<span foreground=\"white\" font=\"Arial\" size='150050'>0</span>"); // if use one number size should be 300100. setting color and size
  gtk_label_set_markup(GTK_LABEL(data->label2), "<span foreground=\"white\" font=\"Arial\" size='150050'>0</span>"); // if use one number size should be 300100


  GdkRGBA color;
  gdk_rgba_parse(&color,"#2080FF");
  gtk_widget_override_background_color(main_window, GTK_STATE_FLAG_NORMAL, &color);

  g_object_unref(data->builder);
  gtk_widget_show_all (main_window);
}

/* This function is called periodically to refresh the GUI */
static gboolean refresh_ui (CustomData *data) {
  gint64 current = -1;
  char announceBuffer[128];
  int a=0;



  gint x1; //for place of label1
  gint y1;

  gint x2; //for place of label2
  gint y2;


  recv_data ();
  sprintf(printBuffer1, "<span foreground=\"white\" font=\"Arial\" size='150050'>%c</span>", floorLevel1);
  sprintf(printBuffer2, "<span foreground=\"white\" font=\"Arial\" size='150050'>%c</span>", floorLevel2);



  gtk_label_set_markup(GTK_LABEL(data->label1), printBuffer1); // if use one number size should be 300100
  gtk_label_set_markup(GTK_LABEL(data->label2), printBuffer2); // if use one number size should be 300100



  if(floorLevel1=='-' || (floorLevel1>='1' && floorLevel1<='4')) 
  {

      snprintf(announceBuffer,sizeof(announceBuffer),"playbin uri=file:///home/olimex/Desktop/TR/%c%c.wav",floorLevel1,floorLevel2);

  }
    else
    {

        if(floorLevel1=='0') 
            snprintf(announceBuffer,sizeof(announceBuffer),"playbin uri=file:///home/olimex/Desktop/TR/%c.wav",floorLevel1); 

        else
            snprintf(announceBuffer,sizeof(announceBuffer),"playbin uri=file:///home/olimex/Desktop/TR/%c.wav",floorLevel2); 
    }


    if (travelDownDirectionFlag==1){

        x1=250;
        y1=0;

        x2=350;
        y2=0;

        if (floorLevel1=='0')
        {   printf("floorlevel 0");
            gtk_widget_hide(data->label2);
            x1=350;
            y1=0;
        }

        else
            gtk_widget_show(data->label2);

        //gtk_widget_show(data->label2);

        gtk_fixed_move(data->fixed, data->label1, x1, y1);
        gtk_fixed_move(data->fixed, data->label2, x2, y2);

        gtk_image_set_from_file(data->image,"/home/olimex/Desktop/NewGUI/GUI_test/downArrow2.png");
        announceFlag=true;

        if (announceFlag==false)
        {   data->announce=gst_parse_launch(NULL,NULL); //Build floorLevel announce
            gst_element_set_state(data->announce, GST_STATE_NULL); 
            g_object_unref(data->announce);
        }
        announceFlag=true;
    }

    else if (travelUpDirectionFlag==1)
    {


        x1=250;
        y1=0;

        x2=350;
        y2=0;

        if (floorLevel1=='0')   
        {
            gtk_widget_hide(data->label2);
            x1=350;
            y1=0;
        }

        else
            gtk_widget_show(data->label2);



        gtk_fixed_move(data->fixed, data->label1, x1, y1);  //set place label1
        gtk_fixed_move(data->fixed, data->label2, x2, y2);  //set place label2
        gtk_image_set_from_file(data->image,"/home/olimex/Desktop/NewGUI/GUI_test/upArrow2.png");
        announceFlag=true;

        if (announceFlag==false)
        {
            data->announce=gst_parse_launch(NULL,NULL); //Build floorLevel announce
            gst_element_set_state(data->announce, GST_STATE_NULL);
            g_object_unref(data->announce);
        }
        announceFlag=true;
    }

    else
    {
        x1=120;
        y1=0;

        x2=220;
        y2=0;

        if (floorLevel1=='0') 
        {
            gtk_widget_hide(data->label2);
            x1=150;
            y1=0;
        }

        else
            gtk_widget_show(data->label2);

        gtk_image_set_from_file(data->image,NULL);
        gtk_fixed_move(data->fixed, data->label1, x1, y1);  //set place label1
        gtk_fixed_move(data->fixed, data->label2, x2, y2);  //set place label2

        if (announceFlag==true)
        {
            data->announce=gst_parse_launch(announceBuffer,NULL); 
            gst_element_set_state(data->announce, GST_STATE_PLAYING);  //Start playing floorLevel
            announceFlag=false;

        }

    }




  /* 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, GST_FORMAT_TIME, &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), 0, (gdouble)data->duration / GST_SECOND);
    }
  }

  if (gst_element_query_position (data->playbin, GST_FORMAT_TIME, &current)) {
  }
  return TRUE;
}


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

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

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

  /* Initialize our data structure */
  memset (&data, 0, 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);

  //g_object_set(data.playbin,"video-sink",NULL); Warning veriyor
  g_object_set(data.playbin,"uri","file:///home/olimex/Desktop/sample.mp4",NULL);

  data.announce=gst_parse_launch("playbin uri=file:///home/olimex/Desktop/TR/1.wav",NULL); //Build annonce. Firt play is empty.
  gst_element_set_state(data.announce, GST_STATE_PLAYING); //Start playing

  bus=gst_element_get_bus(data.announce); //Wait until error
  msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS); //Wait until EOS

  //free resource
  if(msg != NULL)
    gst_message_unref(msg);
  gst_object_unref(bus);
  gst_element_set_state(data.announce,GST_STATE_NULL);
  gst_object_unref(data.announce);


  /* 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", (GCallback) tags_cb, &data);
  g_signal_connect (G_OBJECT (data.playbin), "text-tags-changed", (GCallback) tags_cb, &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, &data);
  g_signal_connect (G_OBJECT (bus), "message::state-changed", (GCallback)state_changed_cb, &data);
  g_signal_connect (G_OBJECT (bus), "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;
  }

    UartInit();
  /* 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;
}
...