/* 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 not supported in this application.*/ /* 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 */ /**************************************************************************************************************************************************/ /*------------------------------ System Includes -----------------------------*/ #include #include #include #include #include #include #include #include #include #include /*------------------------------ Macros -----------------------------*/ #define MAX_VIDEOS 4 /* Maximum number of videos that can be played.*/ #define NOOFWINDOWS 4 /* Max No of windows that can be created 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 */ #define ENABLE_DBGPRINT 0 /* Macro to enable printf*/ /* Macro for printf */ #if (1 == ENABLE_DBGPRINT) #define PRINT(fmt, args...) \ printf("\n DEBUG : TEST => %s : %s:\n " fmt "\n", __FILE__, __FUNCTION__ , ## args); #else #define PRINT(fmt, args...) #endif/*!< #if(1 == ENABLE_DBGPRINT) */ /*------------------------------ Global variables -----------------------------*/ /*Instance of the displayplay connection*/ Display *display; /*Files to be played*/ char FileName[MAX_VIDEOS][256] = {"City Video Clips _1280.mov", "City Video Clips _1280.mov", "City Video Clips _1280.mov", "City Video Clips _1280.mov"}; /*Variables for setting the window location, width and height */ int x[MAX_VIDEOS] = {0, 550, 0, 550}; int y[MAX_VIDEOS] = {0, 0, 550 , 550}; int width[MAX_VIDEOS] = {500, 500, 500, 500}; int height[MAX_VIDEOS] = {500, 500, 500, 500}; /*------------------------------ Structure Declaration -----------------------------*/ /*Holds general info like window ID, width , height etc.*/ typedef struct _tag_APP_GENERALINFO_ST { Window win; int x; int y; int width; int height; char currentfilename[256]; }APP_GENERALINFO_ST; /* Stores information specific to gstreamer */ typedef struct _tag_APP_GSTINFO_ST { GstElement *pipeline; GstElement *filesrc; GstElement *demux; GstElement *videodecoder; GstElement *videobin; GstElement *videosink; GstPad *videofilterpad; GstElement *videoqueue; GstBus *bus; GMainLoop *loop; }APP_GSTINFO_ST; /*Stores all the infomation required by the application*/ typedef struct _tag_APP_INFO_ST { APP_GSTINFO_ST stAppGstInfo; APP_GENERALINFO_ST stAppGeneralInfo; }APP_INFO_ST; /*------------------------------ Function Definitions------------------------*/ /****************************************************************************** * Function : InitializeAppInfostruct * Description : Api to initialize APP_INFO_ST structure. * This will also set the width, height, filename etc. * *****************************************************************************/ void InitializeAppInfostruct(APP_INFO_ST *pstAppInfo, int cntNoofWindows) { memset(pstAppInfo, 0, sizeof(APP_INFO_ST)); pstAppInfo->stAppGeneralInfo.x = x[cntNoofWindows]; pstAppInfo->stAppGeneralInfo.y = y[cntNoofWindows]; pstAppInfo->stAppGeneralInfo.width = width[cntNoofWindows]; pstAppInfo->stAppGeneralInfo.height = height[cntNoofWindows]; strcpy(pstAppInfo->stAppGeneralInfo.currentfilename, FileName[cntNoofWindows]); return; } /****************************************************************************** * Function : CreateApp_Window * Description : Api to create window and to give the window ID * to vaapi sink. * Window ID to be created by the application only * when 'prepare-xwindow-id' message comes. ******************************************************************************/ static GstBusSyncReply CreateApp_Window(GstBus * bus, GstMessage * message, void *pvAppGeneralInfo) { APP_GENERALINFO_ST *pstAppGeneralInfo = pvAppGeneralInfo; PRINT("Message src = %s\n", gst_object_get_name(GST_MESSAGE_SRC (message))); /* Ignore all other messages except '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; /* This is to displayable the window manager decorations i.e border, title bar etc.*/ XSetWindowAttributes stXSWAttr = {0}; int i32XWindowMask = 0; /* Background color set to black for the displayplay.*/ stXSWAttr.background_pixel = BlackPixel(display, 0); /* Set flag to tell Window manager to not intercept commands to this * window. */ stXSWAttr.override_redirect = True; /* Set mask. */ i32XWindowMask = CWBackPixel|CWBorderPixel|CWOverrideRedirect; /* Create X window */ pstAppGeneralInfo->win = XCreateWindow(display, RootWindow(display,0), pstAppGeneralInfo->x, pstAppGeneralInfo->y, pstAppGeneralInfo->width, pstAppGeneralInfo->height, 0, DefaultDepth(display,0), InputOutput, CopyFromParent, i32XWindowMask, &stXSWAttr); /*Map the contents of the window to displayplay */ XMapWindow(display, pstAppGeneralInfo->win); XFlush (display); XSync (display, 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)), pstAppGeneralInfo->win); gst_message_unref (message); return GST_BUS_DROP; } /****************************************************************************** * Function : bus_callback * Description : Callback api for bus to receives messages * like EOS, error etc. ******************************************************************************/ static gboolean bus_callback (GstBus *bus, GstMessage *message, void *pvAppInfo) { APP_INFO_ST *pstAppInfo = pvAppInfo; PRINT("Message src = %s", 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 (pstAppInfo->stAppGstInfo.loop); break; }/* End of case GST_MESSAGE_ERROR*/ case GST_MESSAGE_EOS: { /* end-of-stream received */ PRINT("Received EOS"); /* Stop the gmain loop */ g_main_loop_quit (pstAppInfo->stAppGstInfo.loop); /* Destroy the window */ XDestroyWindow(display, pstAppInfo->stAppGeneralInfo.win); /* Set the pipeline to NULL state */ gst_element_set_state (pstAppInfo->stAppGstInfo.pipeline, GST_STATE_NULL); /* Set the pipeline to PLAYING state */ gst_element_set_state (pstAppInfo->stAppGstInfo.pipeline, GST_STATE_PLAYING); /* Create gthread again and run gmain loop */ g_thread_create ((GThreadFunc)g_main_loop_run, pstAppInfo->stAppGstInfo.loop, TRUE, NULL); break; }/* End of case GST_MESSAGE_EOS*/ default: break; }/* End of switch*/ return TRUE; } /****************************************************************************** * Function : cb_newpad * Description : Linking the demuxer pad to video bin pad. ******************************************************************************/ static void cb_newpad (GstElement *demuxbin, GstPad *pad, gpointer data) { GstCaps *caps; GstStructure *str; GstPad *videopad; 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")) { 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; } } /****************************************************************************** * Function : main * Description : main of the application. * ******************************************************************************/ int main (int argc, char *argv[]) { /* Variable Declaration */ gboolean ret = 0; GstStateChangeReturn State = GST_STATE_NULL; int cntNoOfWindows = 0; APP_INFO_ST stAppInfo[NOOFWINDOWS]; /* initialize GStreamer */ gst_init (NULL, NULL); display = XOpenDisplay(NULL); while(cntNoOfWindows < NOOFWINDOWS) { PRINT("APPLICATION Started -----------------------"); /* Initialize AppInfo struct */ InitializeAppInfostruct(&stAppInfo[cntNoOfWindows], cntNoOfWindows); /* Create all elements for the following pipeline */ /* filesrc ! demux ! queue ! decoder ! sink*/ stAppInfo[cntNoOfWindows].stAppGstInfo.pipeline = gst_pipeline_new ("Pipeline to play video using vaapi"); if(NULL == stAppInfo[cntNoOfWindows].stAppGstInfo.pipeline) { PRINT("ERROR : pipeline could not be created : aborting application"); return -1; } /* Create a Gmain LOOP */ stAppInfo[cntNoOfWindows].stAppGstInfo.loop = g_main_loop_new (NULL, FALSE); /* Create a Bus */ stAppInfo[cntNoOfWindows].stAppGstInfo.bus = gst_pipeline_get_bus (GST_PIPELINE (stAppInfo[cntNoOfWindows].\ stAppGstInfo.pipeline)); /* Attach a call-back to the BUS */ gst_bus_add_watch (stAppInfo[cntNoOfWindows].stAppGstInfo.bus, bus_callback, &stAppInfo[cntNoOfWindows]); /* Set sync handler to create foriegn X window */ gst_bus_set_sync_handler (stAppInfo[cntNoOfWindows].\ stAppGstInfo.bus, (GstBusSyncHandler) CreateApp_Window, &(stAppInfo[cntNoOfWindows].stAppGeneralInfo)); gst_object_unref (stAppInfo[cntNoOfWindows].stAppGstInfo.bus); stAppInfo[cntNoOfWindows].stAppGstInfo.filesrc = gst_element_factory_make ("filesrc", "file source"); if(NULL == stAppInfo[cntNoOfWindows].stAppGstInfo.filesrc) { PRINT("ERROR : Filesrc could not be created : aborting application"); return -1; } #if MPEGTS demux = gst_element_factory_make ("ffdemux_mpegts", "demux"); #endif #if MOV stAppInfo[cntNoOfWindows].stAppGstInfo.demux = gst_element_factory_make ("ffdemux_mov_mp4_m4a_3gp_3g2_mj2", "demux"); #endif if(NULL == stAppInfo[cntNoOfWindows].stAppGstInfo.demux) { PRINT("ERROR : Demuxer could not be created : aborting application"); return -1; } stAppInfo[cntNoOfWindows].stAppGstInfo.videodecoder = gst_element_factory_make ("vaapidecode", "decoder"); if(NULL == stAppInfo[cntNoOfWindows].stAppGstInfo.videodecoder) { PRINT("ERROR : Vaapi Decoder could not be created : aborting application"); return -1; } stAppInfo[cntNoOfWindows].stAppGstInfo.videosink = gst_element_factory_make ("vaapisink", "sink"); if(NULL == stAppInfo[cntNoOfWindows].stAppGstInfo.videosink) { PRINT("ERROR : Vaapi sink could not be created : aborting application"); return -1; } stAppInfo[cntNoOfWindows].stAppGstInfo.videoqueue = gst_element_factory_make ("queue", "videoqueue"); if(NULL == stAppInfo[cntNoOfWindows].stAppGstInfo.videoqueue) { PRINT("ERROR : Video Queue could not be created : aborting application"); return -1; } g_object_set (G_OBJECT (stAppInfo[cntNoOfWindows].stAppGstInfo.filesrc), "location", (unsigned char*)stAppInfo[cntNoOfWindows].stAppGeneralInfo.\ currentfilename, NULL); gst_bin_add_many (GST_BIN (stAppInfo[cntNoOfWindows].stAppGstInfo.pipeline), stAppInfo[cntNoOfWindows].stAppGstInfo.filesrc, stAppInfo[cntNoOfWindows].stAppGstInfo.demux,NULL); gst_element_link_many (stAppInfo[cntNoOfWindows].stAppGstInfo.filesrc, stAppInfo[cntNoOfWindows].stAppGstInfo.demux, NULL); /* create video bin */ stAppInfo[cntNoOfWindows].stAppGstInfo.videobin = gst_bin_new ("videobin"); gst_bin_add_many (GST_BIN (stAppInfo[cntNoOfWindows].stAppGstInfo.videobin), stAppInfo[cntNoOfWindows].stAppGstInfo.videoqueue, stAppInfo[cntNoOfWindows].stAppGstInfo.videodecoder, stAppInfo[cntNoOfWindows].stAppGstInfo.videosink, NULL); gst_bin_add(GST_BIN(stAppInfo[cntNoOfWindows].stAppGstInfo.pipeline), stAppInfo[cntNoOfWindows].stAppGstInfo.videobin); stAppInfo[cntNoOfWindows].stAppGstInfo.videofilterpad = gst_element_get_static_pad (stAppInfo[cntNoOfWindows].stAppGstInfo.videoqueue, "sink"); gst_element_add_pad (stAppInfo[cntNoOfWindows].stAppGstInfo.videobin, gst_ghost_pad_new ("sink", stAppInfo[cntNoOfWindows].stAppGstInfo.videofilterpad)); g_signal_connect (stAppInfo[cntNoOfWindows].stAppGstInfo.demux, "pad-added", G_CALLBACK (cb_newpad), stAppInfo[cntNoOfWindows].stAppGstInfo.videobin); ret = gst_element_link_many (stAppInfo[cntNoOfWindows].stAppGstInfo.videoqueue, stAppInfo[cntNoOfWindows].stAppGstInfo.videodecoder, stAppInfo[cntNoOfWindows].stAppGstInfo.videosink, NULL); if(0 == ret) { PRINT("Failed to link queue, decoder and sink"); return -1; } gst_object_unref(stAppInfo[cntNoOfWindows].stAppGstInfo.videofilterpad); /* Change the pipeline state to READY */ State = gst_element_set_state (stAppInfo[cntNoOfWindows].stAppGstInfo.pipeline, GST_STATE_READY); if(GST_STATE_CHANGE_FAILURE == State) { PRINT("State = %d", State); return 0; } /* Change the pipeline state to PLAYING */ State = gst_element_set_state (stAppInfo[cntNoOfWindows].stAppGstInfo.pipeline, GST_STATE_PLAYING); if(GST_STATE_CHANGE_FAILURE == State) { PRINT("State = %d", State); return 0; } /*Start the gmain loop by creating a gthread*/ g_thread_create ((GThreadFunc)g_main_loop_run, stAppInfo[cntNoOfWindows].stAppGstInfo.loop, FALSE, NULL); sleep(1); cntNoOfWindows++; } while(1); return 0; } /* End of application */