LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 2470|回复: 4

gtk显示视频的问题,请各位老大指点,请版主 realtang指点

[复制链接]
发表于 2008-4-23 16:48:37 | 显示全部楼层 |阅读模式
[具体情况]
要用gtk播放一段视频,视频文件很特殊,是无制式的视频,每一帧图都由bmp的图像数据阵列(注:720*480的8位灰度图像)部分构成,。
[已经实现]
可以显示视频的第一帧。代码如下:
#include <gtk/gtk.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#define BUF_SIZE 720*480

static GtkWidget *window;
static GtkWidget *hbox;
static GtkWidget *drawingarea;

FILE *fp;
char buf[BUF_SIZE];

gboolean draw_some( GtkWidget *widget, GdkEventExpose *event,
gpointer data )
{
gdk_draw_gray_image(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
0,0,720,480,GDK_RGB_DITHER_NORMAL,buf,720);

return TRUE;
}

int main(int argc,gchar *argv[])
{
gtk_init(&argc,&argv);

window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"一个显示视频的应用程序");
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window),720,480);
g_signal_connect(G_OBJECT(window),"delete_event",
G_CALLBACK(gtk_main_quit),NULL);
gtk_widget_show(window);

hbox=gtk_hbox_new(FALSE,0);
gtk_container_add(GTK_CONTAINER(window),hbox);
gtk_widget_show(hbox);

drawingarea=gtk_drawing_area_new();
gtk_box_pack_start(GTK_BOX(hbox),drawingarea,TRUE,TRUE,0);
gtk_widget_show(drawingarea);

if(! (fp=fopen("my.seq","r")))
{
printf("Error in open file my.seq\n");
exit(1);
}

memset(buf,0,BUF_SIZE*sizeof(char));

if(fread(buf,sizeof(char),BUF_SIZE,fp)<0)
{
printf("Error in read file \n");
exit(1);
}
/*
gdk_draw_gray_image(drawingarea->window,
drawingarea->style->fg_gc[GTK_WIDGET_STATE(drawingarea)],
0,0,720,480,GDK_RGB_DITHER_NORMAL,buf,720);
*/
g_signal_connect( G_OBJECT( drawingarea ), "expose_event",
G_CALLBACK( draw_some ), NULL );

if(fclose(fp))
{
printf("Error in close file!\n");
exit(1);
}

gtk_main();
return 0;
}


在下面的代码中,我试图显示一段视频,我开了一个线程来完成这项工作。
#include <gtk/gtk.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#define BUF_SIZE 720*480

static GtkWidget *window;
static GtkWidget *hbox;
static GtkWidget *drawingarea;

FILE *fp;
char buf[BUF_SIZE];
/*刷新画图*/
void like_expose(GtkWidget *widget)
{
for(;;)
{
g_usleep(40000);
gdk_threads_enter();
// fread(buf,sizeof(buf[BUF_SIZE]),1,fp);
fread(buf,sizeof(char),BUF_SIZE,fp);
/*把数据分成每一帧,得到一幅图像*/
if(buf!=NULL)
{
// printf("buf success");
gdk_draw_gray_image(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
0,0,720,480,GDK_RGB_DITHER_NORMAL,buf,720);
fseek(fp,sizeof(buf),SEEK_CUR);
}
else
{
gdk_threads_leave();
break;
}
gdk_threads_leave();
}
}

int main(int argc,gchar *argv[])
{
if(!g_thread_supported())
{
g_thread_init(NULL);
}
gdk_threads_init();

gtk_init(&argc,&argv);

window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"一个显示视频的应用程序");
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window),720,480);
g_signal_connect(G_OBJECT(window),"delete_event",
G_CALLBACK(gtk_main_quit),NULL);
gtk_widget_show(window);

hbox=gtk_hbox_new(FALSE,0);
gtk_container_add(GTK_CONTAINER(window),hbox);
gtk_widget_show(hbox);

drawingarea=gtk_drawing_area_new();
gtk_box_pack_start(GTK_BOX(hbox),drawingarea,TRUE,TRUE,0);
gtk_widget_show(drawingarea);

if(! (fp=fopen("my.seq","r")))
{
printf("Error in open file my.seq\n");
exit(1);
}

memset(buf,0,BUF_SIZE*sizeof(char));
g_thread_create((GThreadFunc)like_expose,drawingarea,FALSE,NULL);

if(fclose(fp))
{
printf("Error in close file!\n");
exit(1);
}

gdk_threads_enter();
gtk_main();
gdk_threads_leave();
return 0;
}

/*Makefile*/
CC=gcc
all:
$(CC) -g -o showvideo showvideo.c `pkg-config --cflags --libs gtk+-2.0 gthread-2.0`

现在视频看不见了。只有白板一块。。。,我想在显示视频的程序中加exposeevent事件。可是不知从何加起,请指教。
发表于 2008-4-23 21:14:42 | 显示全部楼层
正确的做法是把工作线程里读到的数据放在buf里,然后用gtk_widget_queue_draw触发expose事件。然后在主线程的事件处理函数里注册drawing area的expose event处理函数,在这个函数里读取buf数据并加以显示。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-4-24 09:51:11 | 显示全部楼层
谢谢realtang版主的回复

我按照您说的作了一下改动,如下:

#include <gtk/gtk.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#define BUF_SIZE 720*480

static GtkWidget *window;
static GtkWidget *hbox;
static GtkWidget *drawingarea;

FILE *fp;
char buf[BUF_SIZE];

gboolean draw_some( GtkWidget *widget, GdkEventExpose *event,
                           gpointer data )
{
        gdk_draw_gray_image(widget->window,
                        widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
                        0,0,720,480,GDK_RGB_DITHER_NORMAL,buf,720);
        return TRUE;
}

/*刷新画图*/
void like_expose(GtkWidget *widget)
{
        for(;;)
        {
                g_usleep(40000);
                gdk_threads_enter();
                fread(buf,sizeof(char),BUF_SIZE,fp);

                /*把数据分成每一帧,得到一幅图像*/
                if(buf!=NULL)
                {
/*
                        gdk_draw_gray_image(widget->window,
                                        widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
                                        0,0,720,480,GDK_RGB_DITHER_NORMAL,buf,720);
*/
                        gtk_widget_queue_draw(GTK_WIDGET (widget));
                }
                else
                {
                        gdk_threads_leave();
                        break;       
                }
                gdk_threads_leave();
        }
}       

int main(int argc,gchar *argv[])
{       
        if(!g_thread_supported())
        {
                g_thread_init(NULL);
        }
        gdk_threads_init();
       
        gtk_init(&argc,&argv);
       
        window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_title(GTK_WINDOW(window),"一个显示视频的应用程序");
        gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
        gtk_window_set_default_size(GTK_WINDOW(window),720,480);
        g_signal_connect(G_OBJECT(window),"delete_event",
                        G_CALLBACK(gtk_main_quit),NULL);
        gtk_widget_show(window);
       
        hbox=gtk_hbox_new(FALSE,0);
        gtk_container_add(GTK_CONTAINER(window),hbox);
        gtk_widget_show(hbox);
       
        drawingarea=gtk_drawing_area_new();
        gtk_box_pack_start(GTK_BOX(hbox),drawingarea,TRUE,TRUE,0);
        gtk_widget_show(drawingarea);
       
        g_signal_connect( G_OBJECT( drawingarea ), "expose_event",
                        G_CALLBACK( draw_some ), NULL );

        if(! (fp=fopen("my.seq","r")))
        {
                printf("Error in open file my.seq\n");
                exit(1);
        }       
       
        memset(buf,0,BUF_SIZE*sizeof(char));
        g_thread_create((GThreadFunc)like_expose,drawingarea,FALSE,NULL);
       
        if(fclose(fp))
        {
                printf("Error in close file!\n");
                exit(1);
        }       

        gdk_threads_enter();
        gtk_main();
        gdk_threads_leave();
        return 0;
}

还是有问题,显示出来的是黑板一块,调试的时候
86 if(! (fp=fopen("my.seq","r")))
(gdb) n
92 memset(buf,0,BUF_SIZE*sizeof(char));
(gdb) n
93 g_thread_create((GThreadFunc)like_expose,drawingarea,FALSE,NULL);
(gdb) n
[New Thread -1220146288 (LWP 8397)]
95 if(fclose(fp))
(gdb) n
[Switching to Thread -1220146288 (LWP 8397)]

似乎新的线程还没有开始,文件就已经关闭了,这是怎么回事呢?
回复 支持 反对

使用道具 举报

发表于 2008-4-24 20:00:10 | 显示全部楼层
。。。。。。。。。。
这么明显的错误,你的like_expose刚执行,fp就关掉了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-5-8 08:36:02 | 显示全部楼层
呵呵,多谢realtang版主帮助,现在已经可以在pc播放一段视频了,
现在我要把程序移植到开发板上,arm是s3c2440,GUI是Directfb+gtk
一般s3c2440只能支持640*480的分辨率,我们的需求是在vga上显示800*600的分辨率,所以我这边修改了framebuffer驱动程序,使其加大分辨率,同时rgb变为8位灰度图来达到目的。

可是我把他移植到开发板上,发现程序显示的图像不是8位的,而是有大致的形状,图像有一块一块的感觉,我知道Directfb+GTK是支持8位的framebuffer驱动的。但是怎么会有这种现象呢?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表