Hi,
I am trying to play multiple videos simultaneously using
GStreamer(vaapidecode and vaapisink plugins) and libVA-1.0.7.
In the sample application I am creating multiple windows using
"XCreateWindow" and passing the generated window ID to vaapisink.
There are two problems I am facing:
1. The first video is getting rendered but the other videos are not
getting rendered.
2. The application crashes randomly.
None of the gstreamer calls return a failure and the state is getting
changed to play successfully. Tried the application with different
container formats.
Also from the command line using "gst-launch" I am able to playback
multiple videos simultaneously.
The backtrace of the gdb log is attached "CrashLog.txt". The log
suggests the crash is in "i965_PutSurface".
I am using the following packages as mentioned on Intel Linux graphics
site "http://intellinuxgraphics.org/2010Q4.html":
2D driver: xf86-video-intel 2.14.0 release
<http://xorg.freedesktop.org/archive/individual/driver/xf86-video-intel-2.14.0.tar.bz2>
3D driver: mesa 7.10 <ftp://freedesktop.org/pub/mesa/7.10/>
Libdrm: libdrm-2.4.23 release
<http://dri.freedesktop.org/libdrm/libdrm-2.4.23.tar.bz2>
Kernel: 2.6.37 release
<http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.37.tar.bz2>
Cairo: cairo-1.10.2 release <http://cairographics.org/news/cairo-1.10.2/>
Libva: libva-1.0.7 release
<http://cgit.freedesktop.org/libva/snapshot/libva-1.0.7.tar.bz2>
xserver: 1.9.3
Apart from this I have installed the following gstreamer packages:
gstreamer-0.10.31
gst-plugins-base-0.10.29
gst-plugins-good-0.10.22
gst-plugins-bad-0.10.19
gst-plugins-ugly-0.10.15
gst-ffmpeg-0.10.10.
For reference attaching the sample application "MultiVideo.c".
I am not sure if it is application problem or plugin or driver
limitation or X? As the same application runs with "ximagesink"and
decoder like ffmpeg.
What could be the problem?
PS : OS : Fedora Core 13. Platform: Sandy Bridge.Kernel : 2.6.37.
Regards,
Jyotsana.
/* Back trace from gdb*/
0xb7fe856c in do_bo_emit_reloc () from /opt/X11R7//lib/libdrm_intel.so.1
#1 0xb7fe882a in drm_intel_gem_bo_emit_reloc () from
/opt/X11R7//lib/libdrm_intel.so.1
#2 0xb7fe36da in drm_intel_bo_emit_reloc () from
/opt/X11R7//lib/libdrm_intel.so.1
#3 0xb130fe3b in intel_batchbuffer_emit_reloc_helper (ctx=<value optimized
out>, batch=0xaf2beb30, bo=0x0, read_domains=16, write_domains=0, delta=0) at
intel_batchbuffer.c:198
#4 0xb1317a19 in gen6_emit_wm_state (ctx=0xaf2bc178, kernel=<value optimized
out>) at i965_render.c:1808
#5 gen6_render_emit_states (ctx=0xaf2bc178, kernel=<value optimized out>) at
i965_render.c:1894
#6 0xb1318f85 in gen6_render_put_surface (ctx=0xaf2bc178, surface=67108868,
srcx=0, srcy=0, srcw=1280, srch=720, destx=0, desty=0, destw=940, desth=528,
flag=0) at i965_render.c:1921
#7 intel_render_put_surface (ctx=0xaf2bc178, surface=67108868, srcx=0, srcy=0,
srcw=1280, srch=720, destx=0, desty=0, destw=940, desth=528, flag=0) at
i965_render.c:2020
#8 0xb131b082 in i965_PutSurface (ctx=0xaf2bc178, surface=67108868,
draw=0x3e00007, srcx=0, srcy=0, srcw=1280, srch=720, destx=0, desty=0,
destw=940, desth=528, cliprects=0x0, number_cliprects=0, flags=0) at
i965_drv_video.c:1772
#9 0xb4902796 in vaPutSurface (dpy=0xaf2bc008, surface=67108868,
draw=65011719, srcx=0, srcy=0, srcw=1280, srch=720, destx=0, desty=0,
destw=940, desth=528, cliprects=0x0, number_cliprects=0, flags=0) at
va_x11.c:288
#10 0xb490ad15 in gst_vaapi_window_x11_render (window=0xb0cc05f8,
surface=0xa95bcc70, src_rect=0xa94fe988, dst_rect=0xaf246598, flags=3) at
gstvaapiwindow_x11.c:424
#11 0xac25a820 in gst_vaapi_window_put_surface (window=0xb0cc05f8,
surface=0xa95bcc70, src_rect=0xa94fe988, dst_rect=0xaf246598, flags=3) at
gstvaapiwindow.c:506
#12 0xb492f2f4 in gst_vaapisink_show_frame_x11 (base_sink=0xaf2463d8,
buffer=0xb65dd6a8) at gstvaapisink.c:680
#13 gst_vaapisink_show_frame (base_sink=0xaf2463d8, buffer=0xb65dd6a8) at
gstvaapisink.c:714
#14 0x4d782435 in gst_base_sink_render_object (basesink=0xaf2463d8,
pad=0xaf2ae998, is_list=0, obj=0xb65dd6a8) at gstbasesink.c:2833
#15 0x4d783eb7 in gst_base_sink_queue_object_unlocked (basesink=0xaf2463d8,
pad=0xaf2ae998, is_list=0, obj=0xb65dd6a8, prerollable=1) at gstbasesink.c:3111
#16 0x4d78a599 in gst_base_sink_chain_unlocked (basesink=0xaf2463d8,
pad=0xaf2ae998, is_list=0, obj=0xb65dd6a8) at gstbasesink.c:3485
#17 0x4d78aa99 in gst_base_sink_chain_main (basesink=<value optimized out>,
pad=0xaf2ae998, is_list=0, obj=0xb65dd6a8) at gstbasesink.c:3523
#18 0x4cad55cd in gst_pad_chain_data_unchecked (pad=0xaf2ae998, is_buffer=1,
data=0xb65dd6a8) at gstpad.c:4190
#19 0x4cad5fe7 in gst_pad_push_data (pad=0xace0c580, is_buffer=1,
data=0xb65dd6a8) at gstpad.c:4419
#20 0xb493427a in gst_vaapidecode_step (pad=0xaf20a268, buf=0xa8313770) at
gstvaapidecode.c:162
#21 gst_vaapidecode_chain (pad=0xaf20a268, buf=0xa8313770) at
gstvaapidecode.c:536
#22 0x4cad55cd in gst_pad_chain_data_unchecked (pad=0xaf20a268, is_buffer=1,
data=0xa8313770) at gstpad.c:4190
#23 0x4cad5fe7 in gst_pad_push_data (pad=0xaf2ae8d0, is_buffer=1,
data=0xa8313770) at gstpad.c:4419
#24 0xb662ada6 in gst_queue_push_one (pad=0xaf2ae8d0) at gstqueue.c:1144
#25 gst_queue_loop (pad=0xaf2ae8d0) at gstqueue.c:1260
#26 0x4cb040f1 in gst_task_func (task=0xaf21f5a8) at gsttask.c:271
#27 0x4cb05727 in default_func (tdata=0xaf201a40, pool=0xb6509408) at
gsttaskpool.c:70
#28 0x4b9e4214 in ?? () from /lib/libglib-2.0.so.0
#29 0x4b9e2210 in ?? () from /lib/libglib-2.0.so.0
#30 0x4b91b919 in start_thread () from /lib/libpthread.so.0
#31 0x4b85de5e in clone () from /lib/libc.so.6
/* Sample application to run multiple videos. Files to be played are hardcorded
in the code with the variable "FileName". */
/* Application supports mov/mpegts container formats, video codec : mpeg2 or
h264, audio codec: mp3.*/
/* To compile the application do: */
/* gcc -I/usr/include/gstreamer-0.10 -I/usr/include/glib-2.0
-I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -I/usr/lib/liboil-0.3
-I/usr/include -L/usr/lib/gstreamer-0.10 -lglib-2.0 -lgmodule-2.0
-lgstreamer-0.10 -lxml2 -lgobject-2.0 -lgthread-2.0 -lgstbase-0.10 -lX11
-lgstinterfaces-0.10 -lgstvaapi-x11-0.10 -lgstvaapi-0.10 MultiVideo_post.c -o
MultiVideo */
#include <string.h>
#include <gst/gst.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <pthread.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <gst/interfaces/xoverlay.h>
#define VIDEO_ENABLE 1
#define AUDIO_ENABLE 0 /* If the video has audio then enable this */
#define NOOFFILES 4 /* Max No of files to be played simultaneously.
Range is 1-4 */
#define MPEGTS 0 /* To playback mpegts files */
#define MOV 1 /* To playback mov/mp4 files */
/* Right now files are hardcoded for mov filescan be
changed to ts files */
/* Variable Declaration */
/* Display and window declaration*/
Display *dis;
Window win[NOOFFILES];
/* Elements*/
GstElement *pipeline[NOOFFILES];
GstElement *videobin[NOOFFILES] ;
GstElement *audiobin[NOOFFILES] ;
GstElement *src[NOOFFILES] ;
GstElement *decoder[NOOFFILES];
GstElement *sink[NOOFFILES];
GstElement *demux[NOOFFILES];
GstPad *videofilterpad[NOOFFILES];
GstPad *audiofilterpad[NOOFFILES];
GstElement *audpipeline[NOOFFILES];
GstElement *audiodec[NOOFFILES];
GstElement *audiosink[NOOFFILES];
GstElement *videoqueue[NOOFFILES];
GstElement *audioqueue[NOOFFILES];
GstElement *filter[NOOFFILES];
GstBus *bus[NOOFFILES];
GMainLoop *loop[NOOFFILES];
char FileName[NOOFFILES][256] = {"Nature Video Clips (For Review)_1280.mov",
"City Video Clips _1280.mov","City Video Clips _1280.mov","City Video Clips
_1280.mov"};
volatile int EOSFlag = 0;
int cntNoOfFiles = 0;
/*Variables for setting the window location */
int x[NOOFFILES] = {0, 550, 0, 550};
int y[NOOFFILES] = {0, 0, 550 , 550};
int width[NOOFFILES] = {500, 500, 500, 500};
int height[NOOFFILES] = {500, 500, 500, 500};
/* Function definitions*/
/* Api to create window and to give the window ID to vaapi sink*/
static GstBusSyncReply
create_window(GstBus * bus, GstMessage * message, void *data)
{
/*printf("Message src = %s\n", gst_object_get_name(GST_MESSAGE_SRC
(message)));*/
/* ignore anything but 'prepare-xwindow-id' element messages */
if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
return GST_BUS_PASS;
if (!gst_structure_has_name (message->structure, "prepare-xwindow-id"))
return GST_BUS_PASS;
static int filenumber = 0;
/* When EOS is received reset the static var */
if(EOSFlag == 1)
{
filenumber = 0;
EOSFlag = 0;
}
/* This is to disable the window manager decorations i.e border, title bar
etc.*/
XSetWindowAttributes stXSWAttr = {0};
int i32XWindowMask = 0;
/* Background color set to black for the display.*/
stXSWAttr.background_pixel = BlackPixel(dis, 0);
/* Set flag to tell Window manager to not intercept commands to this
* window. */
stXSWAttr.override_redirect = True;
/* Set mask. */
i32XWindowMask = CWBackPixel|CWBorderPixel|CWOverrideRedirect;
win[filenumber] = XCreateWindow(dis,
RootWindow(dis,0),
x[filenumber],
y[filenumber],
width[filenumber],
height[filenumber],
0, DefaultDepth(dis,0),
InputOutput,
CopyFromParent,
i32XWindowMask,
&stXSWAttr);
XMapWindow(dis, win[filenumber]);
XFlush (dis);
XSync (dis, False);
/* Tell the sink to render on the X window ID created above */
gst_x_overlay_set_xwindow_id(GST_X_OVERLAY (GST_MESSAGE_SRC (message)),
win[filenumber]);
filenumber++;
gst_message_unref (message);
return GST_BUS_DROP;
}
/* Bus to receive messages like EOS and any error messages */
static gboolean my_bus_callback ( GstBus *bus,
GstMessage *message,
void *data)
{
static int filenumber = 0;
/*printf("Message src = %s\n", gst_object_get_name(GST_MESSAGE_SRC
(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);
g_main_loop_quit (loop[filenumber]);
break;
}/* End of case GST_MESSAGE_ERROR*/
case GST_MESSAGE_EOS:
{
/* end-of-stream received */
printf("Received EOS\n");
/* Stop the gmain loop */
g_main_loop_quit (loop[filenumber]);
/* Destroy the window */
XDestroyWindow(dis, win[filenumber]);
if(filenumber == 0)
EOSFlag = 1;
gst_element_set_state (pipeline[filenumber], GST_STATE_NULL);
gst_element_set_state (pipeline[filenumber], GST_STATE_PLAYING);
g_thread_create ((GThreadFunc)g_main_loop_run, loop[filenumber], TRUE,
NULL);
filenumber++;
/* Reset the static var*/
if(filenumber == NOOFFILES)
filenumber = 0;
break;
}/* End of case GST_MESSAGE_EOS*/
default:
/* unhandled message */
break;
}/* End of switch*/
return TRUE;
}
/* Api to request demuxer pad and to link it the videobin/audiobin*/
static void
cb_newpad (GstElement *demuxbin,
GstPad *pad,
gpointer data)
{
GstCaps *caps;
GstStructure *str;
GstPad *videopad;
GstPad *audiopad;
gchar *tex;
GstElement *trybin = (GstElement *)data;
/* check media type */
caps = gst_pad_get_caps (pad);
str = gst_caps_get_structure (caps, 0);
tex = (gchar*)gst_structure_get_name(str);
if(g_strrstr(tex,"audio"))
{
audiopad = gst_element_get_static_pad(trybin,"sink");
if(GST_PAD_IS_LINKED(audiopad))
{
g_object_unref(audiopad);
}
else
{
gst_pad_link(pad,audiopad);
g_object_unref (audiopad);
}
return;
}
if(g_strrstr(tex,"video"))
{
videopad = gst_element_get_static_pad(trybin,"sink");
if(GST_PAD_IS_LINKED(videopad))
{
g_object_unref(videopad);
}
else
{
gst_pad_link(pad,videopad);
g_object_unref (videopad);
}
return;
}
}
/*Main of the application */
int main (int argc, char *argv[])
{
/* Variable Declaration */
gboolean ret;
GstStateChangeReturn State = GST_STATE_NULL;
/* initialize GStreamer */
gst_init (NULL, NULL);
dis = XOpenDisplay(NULL);
while(cntNoOfFiles < NOOFFILES)
{
printf("\n\n APPLICATION Started -----------------------> \n");
/* Create all elements for the following pipeline */
/* filesrc ! demux d.! queue ! decoder ! sink d.! queue ! audiodec !
audiosink*/
pipeline[cntNoOfFiles] = gst_pipeline_new ("Pipeline to play h264 video
from filesrc.");
if(NULL == pipeline[cntNoOfFiles])
{
printf("ERROR : pipeline could not be created : aborting application \n");
return -1;
}
/* Create a Gmain LOOP */
loop[cntNoOfFiles] = g_main_loop_new (NULL, FALSE);
/* Create a Bus */
bus[cntNoOfFiles] = gst_pipeline_get_bus (GST_PIPELINE
(pipeline[cntNoOfFiles]));
/* Attach a call-back to the BUS */
gst_bus_add_watch (bus[cntNoOfFiles], my_bus_callback, NULL);
/* Set sync handler to create foriegn X window */
gst_bus_set_sync_handler (bus[cntNoOfFiles], (GstBusSyncHandler)
create_window, NULL);
gst_object_unref (bus[cntNoOfFiles]);
src[cntNoOfFiles] = gst_element_factory_make ("filesrc", "file source");
if(NULL == src[cntNoOfFiles])
{
printf("ERROR : Filesrc could not be created : aborting application \n");
return -1;
}
#if MPEGTS
demux = gst_element_factory_make ("ffdemux_mpegts", "demux");
#endif
#if MOV
demux[cntNoOfFiles] = gst_element_factory_make
("ffdemux_mov_mp4_m4a_3gp_3g2_mj2", "demux");
#endif
if(NULL == demux[cntNoOfFiles])
{
printf("ERROR : Demuxer could not be created : aborting application \n");
return -1;
}
decoder[cntNoOfFiles] = gst_element_factory_make ("vaapidecode", "decoder");
if(NULL == decoder[cntNoOfFiles])
{
printf("ERROR : Decoder could not be created : aborting application \n");
return -1;
}
sink[cntNoOfFiles] = gst_element_factory_make ("vaapisink", "sink");
if(NULL == sink[cntNoOfFiles])
{
printf("ERROR : Vaapi sink could not be created : aborting application
\n");
return -1;
}
audiodec[cntNoOfFiles] = gst_element_factory_make ("ffdec_mp3", "audiodec");
if(NULL == audiodec[cntNoOfFiles])
{
printf("ERROR :Audio Decoder could not be created : aborting application
\n");
return -1;
}
audiosink[cntNoOfFiles] = gst_element_factory_make ("alsasink", "alsasink");
if(NULL == audiosink[cntNoOfFiles])
{
printf("ERROR : Audio sink could not be created : aborting application
\n");
return -1;
}
audioqueue[cntNoOfFiles] = gst_element_factory_make ("queue", "audioqueue");
if(NULL == audioqueue[cntNoOfFiles])
{
printf("ERROR : Audio Queue could not be created : aborting application
\n");
return -1;
}
videoqueue[cntNoOfFiles] = gst_element_factory_make ("queue", "videoqueue");
if(NULL == videoqueue[cntNoOfFiles])
{
printf("ERROR : Video Queue could not be created : aborting application
\n");
return -1;
}
g_object_set (G_OBJECT (src[cntNoOfFiles]), "location", (unsigned
char*)FileName[cntNoOfFiles], NULL);
gst_bin_add_many (GST_BIN (pipeline[cntNoOfFiles]), src[cntNoOfFiles],
demux[cntNoOfFiles],NULL);
gst_element_link_many (src[cntNoOfFiles], demux[cntNoOfFiles], NULL);
#if VIDEO_ENABLE
/* create video bin */
videobin[cntNoOfFiles] = gst_bin_new ("videobin");
gst_bin_add_many (GST_BIN (videobin[cntNoOfFiles]),
videoqueue[cntNoOfFiles],
decoder[cntNoOfFiles],
sink[cntNoOfFiles], NULL);
gst_bin_add(GST_BIN(pipeline[cntNoOfFiles]), videobin[cntNoOfFiles]);
videofilterpad[cntNoOfFiles] = gst_element_get_static_pad
(videoqueue[cntNoOfFiles], "sink");
gst_element_add_pad (videobin[cntNoOfFiles], gst_ghost_pad_new ("sink",
videofilterpad[cntNoOfFiles]));
g_signal_connect (demux[cntNoOfFiles], "pad-added", G_CALLBACK (cb_newpad),
videobin[cntNoOfFiles]);
ret = gst_element_link_many (videoqueue[cntNoOfFiles],
decoder[cntNoOfFiles],
sink[cntNoOfFiles], NULL);
if(0 == ret)
{
printf("Failed to link queue decoder and sink.\n");
return -1;
}
gst_object_unref(videofilterpad[cntNoOfFiles]);
#endif
#if AUDIO_ENABLE
/* create audio bin */
audiobin[cntNoOfFiles] = gst_bin_new ("audiobin");
gst_bin_add_many (GST_BIN (audiobin[cntNoOfFiles]),
audioqueue[cntNoOfFiles],audiodec[cntNoOfFiles],audiosink[cntNoOfFiles], NULL);
gst_bin_add(GST_BIN(pipeline[cntNoOfFiles]), audiobin[cntNoOfFiles]);
audiofilterpad[cntNoOfFiles] = gst_element_get_static_pad
(audioqueue[cntNoOfFiles], "sink");
gst_element_add_pad (audiobin[cntNoOfFiles], gst_ghost_pad_new ("sink",
audiofilterpad[cntNoOfFiles]));
g_signal_connect (demux[cntNoOfFiles], "pad-added", G_CALLBACK (cb_newpad),
audiobin[cntNoOfFiles]);
ret = gst_element_link_many
(audioqueue[cntNoOfFiles],audiodec[cntNoOfFiles], audiosink[cntNoOfFiles],
NULL);
if(0 == ret)
{
printf("Failed to link queue decoder and sink.\n");
return -1;
}
gst_object_unref(audiofilterpad[cntNoOfFiles]);
#endif
/* Change the pipeline state to READY */
State = gst_element_set_state (pipeline[cntNoOfFiles], GST_STATE_READY);
if(GST_STATE_CHANGE_FAILURE == State)
{
printf("State = %d.\n", State);
return 0;
}
/* Change the pipeline state to PLAYING */
printf("\npipeline 1 : PLAYING ................................. \n");
State = gst_element_set_state (pipeline[cntNoOfFiles], GST_STATE_PLAYING);
if(GST_STATE_CHANGE_FAILURE == State)
{
printf("State = %d.\n", State);
return 0;
}
/*Start the gmain loop by creating a gthread*/
g_thread_create ((GThreadFunc)g_main_loop_run, loop[cntNoOfFiles], FALSE,
NULL);
sleep(1);
cntNoOfFiles++;
}
while(1);
return 0;
}
/* End of application */
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx