#c #c #gtk #gstreamer
#c #c #gtk #gstreamer
Вопрос:
Я пытаюсь написать небольшой медиаплеер, используя GTK и GStreamer, и в настоящее время использую интерфейс XOverlay для встраивания видео в область GtkDrawing ВНУТРИ главного окна.
Программа была скомпилирована с помощью этой команды:
g /home/phongcao/cacao.cc -o /home/phongcao/cacao `pkg-config --cflags --libs gtk -2.0 gstreamer-0.10 gstreamer-plugins-base-0.10 gstreamer-interfaces-0.10`
Проблема в том, что видео отображалось в ОТДЕЛЬНОМ окне (вместо под панелью инструментов главного окна):
Вот исходный код программы:
#include <gst/interfaces/xoverlay.h>
#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gdk/gdkx.h>
GstElement *play;
GtkAdjustment *progress;
GtkWidget *mainwindow, *drawingarea;
class TopWin
{
public:
TopWin();
~TopWin();
int Initialize(int argc, char *argv[]);
int Execute();
static void FileChooser(GtkButton *button, GtkWindow *mainwindow);
static int Play(gchar *addr);
static gboolean print_position(GstElement *element);
private:
};
TopWin::TopWin() {
}
TopWin::~TopWin() {
}
gboolean TopWin::print_position(GstElement *play) {
GstFormat fmt = GST_FORMAT_TIME;
gint64 pos, len;
if (gst_element_query_position(play, amp;fmt, amp;pos) amp;amp; gst_element_query_duration(play, amp;fmt, amp;len)) {
g_print("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "r", GST_TIME_ARGS(pos), GST_TIME_ARGS(len));
gtk_adjustment_set_value(GTK_ADJUSTMENT(progress), (pos*100)/len);
}
return TRUE;
}
int TopWin::Play(gchar *addr) {
GMainLoop *loop;
GstBus *bus;
loop = g_main_loop_new(NULL, FALSE);
play = gst_element_factory_make("playbin", "play");
g_object_set(G_OBJECT(play), "uri", addr, NULL);
bus = gst_pipeline_get_bus(GST_PIPELINE(play));
gst_object_unref(bus);
GstElement* x_overlay = gst_element_factory_make("xvimagesink", "videosink");
g_object_set(G_OBJECT(play), "video-sink", x_overlay, NULL);
gst_x_overlay_set_window_handle(GST_X_OVERLAY(x_overlay), GDK_WINDOW_XID(drawingarea->window));
gst_element_set_state(play, GST_STATE_NULL);
g_timeout_add(1000, (GSourceFunc) print_position, play);
gtk_adjustment_set_value(GTK_ADJUSTMENT(progress), 0);
gst_element_set_state(play, GST_STATE_PLAYING);
g_main_loop_run(loop);
gst_element_set_state(play, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(play));
gtk_widget_show_all(mainwindow);
gtk_widget_realize(drawingarea);
return 0;
}
void TopWin::FileChooser(GtkButton *button, GtkWindow *mainwindow) {
GtkWidget *filechooser;
gchar *uri;
filechooser = gtk_file_chooser_dialog_new("Open File...", mainwindow, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser), FALSE);
gint response = gtk_dialog_run(GTK_DIALOG(filechooser));
if (response == GTK_RESPONSE_OK) {
uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(filechooser));
gtk_widget_destroy(filechooser);
Play(uri);
g_free(uri);
}
else if (response == GTK_RESPONSE_CANCEL) {
gtk_widget_destroy(filechooser);
}
}
int TopWin::Initialize(int argc, char *argv[]) {
GtkWidget *playbutton, *openbutton, *volumebutton;
GtkWidget *prefbutton, *notebook;
GtkWidget *vbox, *hbox;
GtkWidget *entry, *hscale;
gtk_init(amp;argc, amp;argv);
gst_init(amp;argc, amp;argv);
mainwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width(GTK_CONTAINER(mainwindow), 0);
g_signal_connect(G_OBJECT(mainwindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);
playbutton = gtk_button_new();
gtk_button_set_image(GTK_BUTTON(playbutton), gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_SMALL_TOOLBAR));
openbutton = gtk_button_new();
gtk_button_set_image(GTK_BUTTON(openbutton), gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_SMALL_TOOLBAR));
g_signal_connect(G_OBJECT(openbutton), "clicked", G_CALLBACK(TopWin::FileChooser), (gpointer) mainwindow);
volumebutton = gtk_button_new();
gtk_button_set_image(GTK_BUTTON(volumebutton), gtk_image_new_from_file("volume.png"));
prefbutton = gtk_button_new();
gtk_button_set_image(GTK_BUTTON(prefbutton), gtk_image_new_from_stock(GTK_STOCK_EXECUTE, GTK_ICON_SIZE_SMALL_TOOLBAR));
entry = gtk_entry_new();
progress = GTK_ADJUSTMENT(gtk_adjustment_new(0.00, 0.00, 100.00, 1.00, 0.00, 0.00));
hscale = gtk_hscale_new(progress);
gtk_scale_set_draw_value(GTK_SCALE(hscale), FALSE);
gtk_widget_set_size_request(hscale, 200, NULL);
hbox = gtk_hbox_new(FALSE, 0);
drawingarea = gtk_drawing_area_new();
vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), openbutton, FALSE, FALSE, 2);
gtk_box_pack_start(GTK_BOX(hbox), playbutton, FALSE, FALSE, 2);
gtk_box_pack_start(GTK_BOX(hbox), hscale, FALSE, FALSE, 2);
gtk_box_pack_start(GTK_BOX(hbox), volumebutton, FALSE, FALSE, 2);
gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 2);
gtk_box_pack_start(GTK_BOX(hbox), prefbutton, FALSE, FALSE, 2);
gtk_button_set_relief(GTK_BUTTON(playbutton), GTK_RELIEF_NONE);
gtk_button_set_relief(GTK_BUTTON(openbutton), GTK_RELIEF_NONE);
gtk_button_set_relief(GTK_BUTTON(volumebutton), GTK_RELIEF_NONE);
gtk_button_set_relief(GTK_BUTTON(prefbutton), GTK_RELIEF_NONE);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), drawingarea, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(mainwindow), vbox);
gtk_widget_show_all(mainwindow);
gtk_widget_realize(drawingarea);
return 0;
}
int TopWin::Execute() {
gtk_main();
return 0;
}
int main(int argc, char *argv[])
{
int result = 0;
TopWin* topwin = new TopWin();
if (0 == topwin->Initialize(argc, argv)) {
result = topwin->Execute();
}
delete topwin;
return resu<
}
Спасибо, что помогли мне с этой проблемой! Я потратил почти 3 дня, ломая голову над этим. Ссылка на XOverlay на веб-сайте GStreamer настолько запутанна … : (
Пожалуйста, скажите мне, нужна ли вам какая-либо дополнительная информация… Спасибо!!
Ответ №1:
Вам нужно сделать что-то вроде этого:
GstElement* x_overlay=gst_element_factory_make ("xvimagesink", "videosink");
g_object_set(G_OBJECT(play),"video-sink",x_overlay,NULL);
gst_x_overlay_set_window_handle(GST_X_OVERLAY(x_overlay), GDK_WINDOW_XID(drawingarea->window));
Создайте новый видеоприемник XV. Установите его в качестве видеопотока в вашей корзине воспроизведения. Прикрепите видеоприемник xv к вашему идентификатору окна drawingarea. Перед этим вам также нужно добавить drawingarea
в какой-нибудь контейнер.
Ваша программа выдает предупреждения и ошибки gtk, они могут быть источником некоторых ваших проблем, лучше исправьте их.
Комментарии:
1. Спасибо вам за ваш ответ! Я уже отредактировал приведенный выше код в соответствии с тем, что вы сказали. Затем я скомпилировал исходный код и получил эту ошибку: «/ home/phongcao/cacao.cc:61: ошибка: ‘gst_x_overlay_set_window_handle’ не был объявлен в этой области». Не уверен, ошибка ли это GStreamer или моя вина… Не могли бы вы, пожалуйста, скопировать и вставить приведенный выше код и попытаться скомпилировать на своем компьютере, чтобы посмотреть, работает ли GStreamer… Большое тебе спасибо, Бантар!!
2. @phngcv: У меня это прекрасно работает. Попробуйте обновить свой GStreamer или измените эту функцию на
gst_x_overlay_set_xwindow_id
. Если это не поможет, откройтеgst/interfaces/xoverlay.h
и проверьте, какие функции объявлены.3. Просто хочу предупредить вас, что строка
gst_x_overlay_set_window_handle(GST_X_OVERLAY(x_overlay), GDK_WINDOW_XID(drawingarea->window));
не является потокобезопасной. Вам нужно поместить обработчик в сигнал реализации, чтобы получить xid сGDK_WINDOW_XID(drawingarea->window);
сохранением этого значения и последующим его использованием сgst_x_overlay_set_window_handle
.
Ответ №2:
gst_x_overlay_set_window_handle
интерфейс в последней библиотеке gstreamer устарел. Появился новый интерфейс gst_video_overlay_set_window_handle
. Простое дополнение может быть размещено из https://web.archive.org/web/20190628124320/http://wikistack.com/how-to-make-your-own-media-player-in-linux-using-gtk-and-gstreamer/