Compare commits

...

16 Commits
v0.2 ... master

Author SHA1 Message Date
Taeho Oh
f445979318 Add INSTALL.macos. 2017-01-07 00:32:57 +09:00
Taeho Oh
9f477e32d2 Update ver to v0.4. 2016-07-27 11:08:53 +09:00
Taeho Oh
ad95a4c05f Use g_get_real_time() in m3u filename generation.
g_get_monotonic_time() resets after reboot in some platforms.
Use g_get_real_time() instead of g_get_monotonic_time() to avoid
m3u filename collision.
2016-07-27 10:58:10 +09:00
Taeho Oh
20fcf95852 Add udp scan option. The default is rtp scan. 2016-07-27 10:56:38 +09:00
Taeho Oh
7181e74c46 Write about WinPcap in INSTALL.windows. 2016-03-03 10:58:08 +09:00
Taeho Oh
ffc2d1c497 Write build information in README file. 2016-03-03 10:34:41 +09:00
Taeho Oh
db12c70938 Write more detailed explanation in README file. 2016-03-03 02:24:02 +09:00
Taeho Oh
973f48702b Update ver to v0.3. 2016-02-23 00:42:01 +09:00
Taeho Oh
da327ab47d Change typo omvp to omvs. 2016-02-22 23:54:01 +09:00
Taeho Oh
15aa054470 Cleanup g_print msg. 2016-02-22 23:50:46 +09:00
Taeho Oh
32b602aad3 Add timestamp to m3u filename. Change print fmt. 2016-02-22 23:23:41 +09:00
Taeho Oh
65477c5009 Save m3u file. 2016-02-22 22:45:44 +09:00
Taeho Oh
e672832cdf Support rtp protocol url. 2016-02-22 21:07:12 +09:00
Taeho Oh
9a277b2aed Add a license in omvs_main.c. 2016-02-22 20:45:41 +09:00
Taeho Oh
6cfa826913 Fix filename memory leak. 2016-02-22 18:43:01 +09:00
Taeho Oh
3c969575fd Add Waiting for multicast packet mode. 2016-02-22 18:24:14 +09:00
14 changed files with 1084 additions and 52 deletions

13
INSTALL.macos Normal file
View File

@ -0,0 +1,13 @@
1) Install Mac OS X El Capitan Version 10.11.6
2) Install Homebrew from http://brew.sh
3) Run as follows.
-------------------------------------------------------------------------------
$ brew install gstreamer gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav
$ git clone https://bitbucket.org/ohhara/ohmulticastvideoscanner.git
$ cd ohmulticastvideoscanner
$ ./configure
$ make
$ sudo ./omvs 233.19.187.192/30 233.19.187.244 233.19.187.1
-------------------------------------------------------------------------------

View File

@ -23,11 +23,12 @@ $ pacman -S VCS base-devel mingw-w64-x86_64-toolchain mingw-w64-x86_64-gstreamer
9) Start "MinGW-w64 Win64 Shell". 9) Start "MinGW-w64 Win64 Shell".
10) Run as follows. Set CFLAGS and LDFLAGS properly when you run ./configure. 10) Run as follows. Set CFLAGS and LDFLAGS properly to find WinPcap Developer's
Pack when you run ./configure.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
$ git clone https://bitbucket.org/ohhara/ohmulticastvideoscanner.git $ git clone https://bitbucket.org/ohhara/ohmulticastvideoscanner.git
$ cd ohmultivideoscanner $ cd ohmultivideoscanner
$ CFLAGS="-IWpdPack/Include" LDFLAGS="-LWpdPack/Lib/x64" ./configure $ CFLAGS="-I../WpdPack/Include" LDFLAGS="-L../WpdPack/Lib/x64" ./configure
$ make $ make
$ ./omvs 233.19.187.192/30 233.19.187.244 233.19.187.1 $ ./omvs 233.19.187.192/30 233.19.187.244 233.19.187.1
------------------------------------------------------------------------------- -------------------------------------------------------------------------------

View File

@ -1,6 +1,13 @@
bin_PROGRAMS = omvs bin_PROGRAMS = omvs
omvs_SOURCES = omvs_main.c omvs_gst.h omvs_gst.c omvs_SOURCES = \
omvs_main.c \
omvs_gst.h \
omvs_gst.c \
omvs_gst_plugin.h \
omvs_gst_plugin.c \
omvs_gst_plugin_rtpsrc.h \
omvs_gst_plugin_rtpsrc.c
omvs_CFLAGS = $(GLIB_CFLAGS) $(GIO_CFLAGS) $(GSTREAMER_CFLAGS) omvs_CFLAGS = $(GLIB_CFLAGS) $(GIO_CFLAGS) $(GSTREAMER_CFLAGS)
omvs_CFLAGS += -std=gnu99 -W -Wall -Wno-unused-result -pedantic omvs_CFLAGS += -std=gnu99 -W -Wall -Wno-unused-result -pedantic
omvs_LDADD = $(GLIB_LIBS) $(GIO_LIBS) $(GSTREAMER_LIBS) omvs_LDADD = $(GLIB_LIBS) $(GIO_LIBS) $(GSTREAMER_LIBS)
ACLOCAL_AMFLAGS= -I m4 ACLOCAL_AMFLAGS = -I m4

View File

@ -100,7 +100,9 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES = CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)" am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS) PROGRAMS = $(bin_PROGRAMS)
am_omvs_OBJECTS = omvs-omvs_main.$(OBJEXT) omvs-omvs_gst.$(OBJEXT) am_omvs_OBJECTS = omvs-omvs_main.$(OBJEXT) omvs-omvs_gst.$(OBJEXT) \
omvs-omvs_gst_plugin.$(OBJEXT) \
omvs-omvs_gst_plugin_rtpsrc.$(OBJEXT)
omvs_OBJECTS = $(am_omvs_OBJECTS) omvs_OBJECTS = $(am_omvs_OBJECTS)
am__DEPENDENCIES_1 = am__DEPENDENCIES_1 =
omvs_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ omvs_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@ -316,7 +318,15 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
omvs_SOURCES = omvs_main.c omvs_gst.h omvs_gst.c omvs_SOURCES = \
omvs_main.c \
omvs_gst.h \
omvs_gst.c \
omvs_gst_plugin.h \
omvs_gst_plugin.c \
omvs_gst_plugin_rtpsrc.h \
omvs_gst_plugin_rtpsrc.c
omvs_CFLAGS = $(GLIB_CFLAGS) $(GIO_CFLAGS) $(GSTREAMER_CFLAGS) \ omvs_CFLAGS = $(GLIB_CFLAGS) $(GIO_CFLAGS) $(GSTREAMER_CFLAGS) \
-std=gnu99 -W -Wall -Wno-unused-result -pedantic -std=gnu99 -W -Wall -Wno-unused-result -pedantic
omvs_LDADD = $(GLIB_LIBS) $(GIO_LIBS) $(GSTREAMER_LIBS) omvs_LDADD = $(GLIB_LIBS) $(GIO_LIBS) $(GSTREAMER_LIBS)
@ -436,6 +446,8 @@ distclean-compile:
-rm -f *.tab.c -rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omvs-omvs_gst.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omvs-omvs_gst.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omvs-omvs_gst_plugin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omvs-omvs_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omvs-omvs_main.Po@am__quote@
.c.o: .c.o:
@ -487,6 +499,34 @@ omvs-omvs_gst.obj: omvs_gst.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -c -o omvs-omvs_gst.obj `if test -f 'omvs_gst.c'; then $(CYGPATH_W) 'omvs_gst.c'; else $(CYGPATH_W) '$(srcdir)/omvs_gst.c'; fi` @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -c -o omvs-omvs_gst.obj `if test -f 'omvs_gst.c'; then $(CYGPATH_W) 'omvs_gst.c'; else $(CYGPATH_W) '$(srcdir)/omvs_gst.c'; fi`
omvs-omvs_gst_plugin.o: omvs_gst_plugin.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -MT omvs-omvs_gst_plugin.o -MD -MP -MF $(DEPDIR)/omvs-omvs_gst_plugin.Tpo -c -o omvs-omvs_gst_plugin.o `test -f 'omvs_gst_plugin.c' || echo '$(srcdir)/'`omvs_gst_plugin.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/omvs-omvs_gst_plugin.Tpo $(DEPDIR)/omvs-omvs_gst_plugin.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='omvs_gst_plugin.c' object='omvs-omvs_gst_plugin.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -c -o omvs-omvs_gst_plugin.o `test -f 'omvs_gst_plugin.c' || echo '$(srcdir)/'`omvs_gst_plugin.c
omvs-omvs_gst_plugin.obj: omvs_gst_plugin.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -MT omvs-omvs_gst_plugin.obj -MD -MP -MF $(DEPDIR)/omvs-omvs_gst_plugin.Tpo -c -o omvs-omvs_gst_plugin.obj `if test -f 'omvs_gst_plugin.c'; then $(CYGPATH_W) 'omvs_gst_plugin.c'; else $(CYGPATH_W) '$(srcdir)/omvs_gst_plugin.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/omvs-omvs_gst_plugin.Tpo $(DEPDIR)/omvs-omvs_gst_plugin.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='omvs_gst_plugin.c' object='omvs-omvs_gst_plugin.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -c -o omvs-omvs_gst_plugin.obj `if test -f 'omvs_gst_plugin.c'; then $(CYGPATH_W) 'omvs_gst_plugin.c'; else $(CYGPATH_W) '$(srcdir)/omvs_gst_plugin.c'; fi`
omvs-omvs_gst_plugin_rtpsrc.o: omvs_gst_plugin_rtpsrc.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -MT omvs-omvs_gst_plugin_rtpsrc.o -MD -MP -MF $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Tpo -c -o omvs-omvs_gst_plugin_rtpsrc.o `test -f 'omvs_gst_plugin_rtpsrc.c' || echo '$(srcdir)/'`omvs_gst_plugin_rtpsrc.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Tpo $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='omvs_gst_plugin_rtpsrc.c' object='omvs-omvs_gst_plugin_rtpsrc.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -c -o omvs-omvs_gst_plugin_rtpsrc.o `test -f 'omvs_gst_plugin_rtpsrc.c' || echo '$(srcdir)/'`omvs_gst_plugin_rtpsrc.c
omvs-omvs_gst_plugin_rtpsrc.obj: omvs_gst_plugin_rtpsrc.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -MT omvs-omvs_gst_plugin_rtpsrc.obj -MD -MP -MF $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Tpo -c -o omvs-omvs_gst_plugin_rtpsrc.obj `if test -f 'omvs_gst_plugin_rtpsrc.c'; then $(CYGPATH_W) 'omvs_gst_plugin_rtpsrc.c'; else $(CYGPATH_W) '$(srcdir)/omvs_gst_plugin_rtpsrc.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Tpo $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='omvs_gst_plugin_rtpsrc.c' object='omvs-omvs_gst_plugin_rtpsrc.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -c -o omvs-omvs_gst_plugin_rtpsrc.obj `if test -f 'omvs_gst_plugin_rtpsrc.c'; then $(CYGPATH_W) 'omvs_gst_plugin_rtpsrc.c'; else $(CYGPATH_W) '$(srcdir)/omvs_gst_plugin_rtpsrc.c'; fi`
mostlyclean-libtool: mostlyclean-libtool:
-rm -f *.lo -rm -f *.lo

11
NEWS
View File

@ -1,3 +1,14 @@
Oh! Multicast Video Scanner 0.4 2016-07-27
===============================================================================
* Support udp protocol.
* Fix m3u filename collision.
Oh! Multicast Video Scanner 0.3 2016-02-23
===============================================================================
* Add waiting for multicast packet mode.
* Support rtp protocol uri.
* Generate m3u file.
Oh! Multicast Video Scanner 0.2 2016-01-29 Oh! Multicast Video Scanner 0.2 2016-01-29
=============================================================================== ===============================================================================
* Improve documents. * Improve documents.

202
README
View File

@ -8,42 +8,186 @@ something, omvs tries to decode it with gstreamer and saves it as png file in
the output directory. There are many cases omvs finds something but png file is the output directory. There are many cases omvs finds something but png file is
not stored. Such as, the video is scrambled(encrypted, not free), multicasting not stored. Such as, the video is scrambled(encrypted, not free), multicasting
data doesn't contain video(audio only, data only), gstreamer doesn't recognize data doesn't contain video(audio only, data only), gstreamer doesn't recognize
it(unknown codec), etc. If you increase the number of jobs with "-j" command it(unknown codec), etc. If png file is successfully stored, the multicast ip
line option, you can scan faster. However, You need take caution, because it address is stored in an m3u file in the output directory.
can cause network congestion.
As omvs uses libpcap to capture raw packet, root privilege is required to run Disable all network device interfaces except for one network device interface
omvs. is recommended, which means disabling all wifi network device interfaces and
disabling all unused ethernet network device interfaces.
With "-i" option, you can decide which network device interface is used. Use the
dev_idx from "-l" option output.
With "-l" option, you can see the available network device interface list.
With "-j" option, you can change the number of jobs. If you increase the number
of jobs, you can scan faster. However, You need take caution, because it can
cause network congestion.
With "-o" option, you can change the output directory. The default directory is
"omvs_out".
With "-s" option, you can change how long you sleep after finishing scanning an
multicast ip address before starting scanning the next ip address. The default
is 1000ms(1 second).
With "-t" option, you can change the scan timeout. The default scan timeout is
10000ms(10 seconds). It tries to get png image file while scanning. If it can't
get the png image file for the timeout, it gives up and tries the next
multicast ip address.
With "-u" option, you can scan with udp protocol instead of rtp protocol. The
default is scanning with rtp protocol.
With "-q" option, you can disable the log printing.
With "-w" option, you can wait for the multicast packet without specifying the
scanning ip addresses. When it detects multicast packet from the specified
network device, it tries to scan the ip address from multicast packet and save
the png file from the multicast ip address. In order to use "-w" option,
the network device interface need to be connected where it can sniff multicast
packet. The environment such as connection to switch hub without igmp-snooping
function is necessary. Press Ctrl-C if you want to stop waiting.
As omvs uses libpcap(or WinPcap on MS Windows) to capture raw packet, root
privilege is required to run omvs.
Run "./configure ; make" to build omvs. Run "./omvs" with scanning multicast ip Run "./configure ; make" to build omvs. Run "./omvs" with scanning multicast ip
addresses. addresses. For the detailed build information, consult INSTALL, INSTALL.ubuntu,
or INSTALL.windows.
e.g.) e.g.)
Scanning multicast ip addresses.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
$ sudo ./omvs 233.19.187.192/30 233.19.187.244 233.19.187.1 $ ifconfig
[0x21be1e0] start scanning 233.19.187.192 eth0 Link encap:Ethernet HWaddr 80:ee:73:a2:58:4b
[0x21be1e0] trying to save udp://233.19.187.192:5000 to omvs_out/233.19.187.192-5000.png inet addr:172.30.1.201 Bcast:172.30.1.255 Mask:255.255.255.0
[0x21be1e0] finish scanning 233.19.187.192 inet6 addr: fe80::82ee:73ff:fea2:584b/64 Scope:Link
[0x21be1e0] start scanning 233.19.187.193 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
[0x21be1e0] trying to save udp://233.19.187.193:5000 to omvs_out/233.19.187.193-5000.png RX packets:41357508 errors:0 dropped:5 overruns:0 frame:0
[0x21be1e0] finish scanning 233.19.187.193 TX packets:827665 errors:0 dropped:0 overruns:0 carrier:0
[0x21be1e0] start scanning 233.19.187.194 collisions:0 txqueuelen:1000
[0x21be1e0] trying to save udp://233.19.187.194:5000 to omvs_out/233.19.187.194-5000.png RX bytes:56530625218 (56.5 GB) TX bytes:99250131 (99.2 MB)
[0x21be1e0] finish scanning 233.19.187.194
[0x21be1e0] start scanning 233.19.187.195 eth1 Link encap:Ethernet HWaddr 80:ee:73:a2:58:4a
[0x21be1e0] trying to save udp://233.19.187.195:5000 to omvs_out/233.19.187.195-5000.png UP BROADCAST MULTICAST MTU:1500 Metric:1
[0x21be1e0] finish scanning 233.19.187.195 RX packets:0 errors:0 dropped:0 overruns:0 frame:0
[0x21be1e0] start scanning 233.19.187.244 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
[0x21be1e0] trying to save udp://233.19.187.244:5000 to omvs_out/233.19.187.244-5000.png collisions:0 txqueuelen:1000
[0x21be1e0] finish scanning 233.19.187.244 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[0x21be1e0] start scanning 233.19.187.1
[0x21be1e0] finish scanning 233.19.187.1 lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:38983 errors:0 dropped:0 overruns:0 frame:0
TX packets:38983 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:15278201 (15.2 MB) TX bytes:15278201 (15.2 MB)
$ sudo ./omvs -l
dev_idx(0) dev_name(eth0) dev_desc((null))
dev_idx(1) dev_name(bluetooth0) dev_desc(Bluetooth adapter number 0)
dev_idx(2) dev_name(nflog) dev_desc(Linux netfilter log (NFLOG) interface)
dev_idx(3) dev_name(nfqueue) dev_desc(Linux netfilter queue (NFQUEUE) interface)
dev_idx(4) dev_name(eth1) dev_desc((null))
dev_idx(5) dev_name(any) dev_desc(Pseudo-device that captures on all interfaces)
dev_idx(6) dev_name(lo) dev_desc((null))
$ sudo ./omvs -i 0 233.19.187.192/30 233.19.187.244 233.19.187.1
openning omvs_out/omvs_67883420797.m3u
[0x18c6230] start scanning 233.19.187.192
[0x18c6230] trying to save rtp://233.19.187.192:5000 to omvs_out/233.19.187.192-5000.png
[0x18c6230] finish scanning 233.19.187.192
[0x18c6230] start scanning 233.19.187.193
[0x18c6230] trying to save rtp://233.19.187.193:5000 to omvs_out/233.19.187.193-5000.png
[0x18c6230] finish scanning 233.19.187.193
[0x18c6230] start scanning 233.19.187.194
[0x18c6230] trying to save rtp://233.19.187.194:5000 to omvs_out/233.19.187.194-5000.png
[0x18c6230] finish scanning 233.19.187.194
[0x18c6230] start scanning 233.19.187.195
[0x18c6230] trying to save rtp://233.19.187.195:5000 to omvs_out/233.19.187.195-5000.png
[0x18c6230] finish scanning 233.19.187.195
[0x18c6230] start scanning 233.19.187.244
[0x18c6230] trying to save rtp://233.19.187.244:5000 to omvs_out/233.19.187.244-5000.png
[0x18c6230] finish scanning 233.19.187.244
[0x18c6230] start scanning 233.19.187.1
[0x18c6230] finish scanning 233.19.187.1
$ ls -l omvs_out $ ls -l omvs_out
total 1960 total 1692
-rw-r--r-- 1 root root 545742 Jan 23 21:55 233.19.187.193-5000.png -rw-r--r-- 1 root root 442585 Mar 3 01:54 233.19.187.193-5000.png
-rw-r--r-- 1 root root 477971 Jan 23 21:55 233.19.187.194-5000.png -rw-r--r-- 1 root root 600331 Mar 3 01:54 233.19.187.194-5000.png
-rw-r--r-- 1 root root 398304 Jan 23 21:55 233.19.187.195-5000.png -rw-r--r-- 1 root root 217721 Mar 3 01:54 233.19.187.195-5000.png
-rw-r--r-- 1 root root 574233 Jan 23 21:55 233.19.187.244-5000.png -rw-r--r-- 1 root root 458283 Mar 3 01:54 233.19.187.244-5000.png
-rw-r--r-- 1 root root 160 Mar 3 01:54 omvs_67883420797.m3u
$ cat omvs_out/omvs_67883420797.m3u
#EXTM3U
#EXTINF:1,1
rtp://233.19.187.193:5000
#EXTINF:2,2
rtp://233.19.187.194:5000
#EXTINF:3,3
rtp://233.19.187.195:5000
#EXTINF:4,4
rtp://233.19.187.244:5000
$
-------------------------------------------------------------------------------
Waiting for the multicast packet.
-------------------------------------------------------------------------------
$ ifconfig
eth0 Link encap:Ethernet HWaddr 80:ee:73:a2:58:4b
inet6 addr: fe80::82ee:73ff:fea2:584b/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:41357843 errors:0 dropped:5 overruns:0 frame:0
TX packets:828004 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:56530695954 (56.5 GB) TX bytes:99292621 (99.2 MB)
eth1 Link encap:Ethernet HWaddr 80:ee:73:a2:58:4a
inet addr:183.101.193.195 Bcast:183.101.193.255 Mask:255.255.255.0
inet6 addr: fe80::82ee:73ff:fea2:584a/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:408 errors:0 dropped:0 overruns:0 frame:0
TX packets:149 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:44532 (44.5 KB) TX bytes:23688 (23.6 KB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:39301 errors:0 dropped:0 overruns:0 frame:0
TX packets:39301 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:15311882 (15.3 MB) TX bytes:15311882 (15.3 MB)
$ sudo ./omvs -l
dev_idx(0) dev_name(eth0) dev_desc((null))
dev_idx(1) dev_name(bluetooth0) dev_desc(Bluetooth adapter number 0)
dev_idx(2) dev_name(nflog) dev_desc(Linux netfilter log (NFLOG) interface)
dev_idx(3) dev_name(nfqueue) dev_desc(Linux netfilter queue (NFQUEUE) interface)
dev_idx(4) dev_name(eth1) dev_desc((null))
dev_idx(5) dev_name(any) dev_desc(Pseudo-device that captures on all interfaces)
dev_idx(6) dev_name(lo) dev_desc((null))
$ sudo ./omvs -i 4 -w
openning omvs_out/omvs_68456824735.m3u
[0x1029840] start scanning 233.18.158.252
[0x1029840] trying to save rtp://233.18.158.252:1901 to omvs_out/233.18.158.252-1901.png
[0x1029840] finish scanning 233.18.158.252
[0x1029840] start scanning 233.14.173.241
[0x1029840] trying to save rtp://233.14.173.241:5000 to omvs_out/233.14.173.241-5000.png
[0x1029840] finish scanning 233.14.173.241
[0x1029840] start scanning 233.18.158.250
[0x1029840] trying to save rtp://233.18.158.250:1902 to omvs_out/233.18.158.250-1902.png
[0x1029840] finish scanning 233.18.158.250
[0x1029840] start scanning 233.18.158.206
[0x1029840] trying to save rtp://233.18.158.206:5000 to omvs_out/233.18.158.206-5000.png
[0x1029840] finish scanning 233.18.158.206
[0x1029840] start scanning 233.18.158.75
[0x1029840] trying to save rtp://233.18.158.75:5000 to omvs_out/233.18.158.75-5000.png
[0x1029840] finish scanning 233.18.158.75
^C$ ls -l omvs_out
total 3876
-rw-r--r-- 1 root root 1917823 Mar 3 02:05 233.18.158.206-5000.png
-rw-r--r-- 1 root root 2040917 Mar 3 02:07 233.18.158.75-5000.png
-rw-r--r-- 1 root root 83 Mar 3 02:07 omvs_68456824735.m3u
$ cat omvs_out/omvs_68456824735.m3u
#EXTM3U
#EXTINF:1,1
rtp://233.18.158.206:5000
#EXTINF:2,2
rtp://233.18.158.75:5000
$ $
------------------------------------------------------------------------------- -------------------------------------------------------------------------------

20
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for Oh! Multicast Video Scanner 0.2. # Generated by GNU Autoconf 2.69 for Oh! Multicast Video Scanner 0.4.
# #
# Report bugs to <ohhara@postech.edu>. # Report bugs to <ohhara@postech.edu>.
# #
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='Oh! Multicast Video Scanner' PACKAGE_NAME='Oh! Multicast Video Scanner'
PACKAGE_TARNAME='omvs' PACKAGE_TARNAME='omvs'
PACKAGE_VERSION='0.2' PACKAGE_VERSION='0.4'
PACKAGE_STRING='Oh! Multicast Video Scanner 0.2' PACKAGE_STRING='Oh! Multicast Video Scanner 0.4'
PACKAGE_BUGREPORT='ohhara@postech.edu' PACKAGE_BUGREPORT='ohhara@postech.edu'
PACKAGE_URL='http://ohhara.sarang.net/omvs' PACKAGE_URL='http://ohhara.sarang.net/omvs'
@ -1332,7 +1332,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures Oh! Multicast Video Scanner 0.2 to adapt to many kinds of systems. \`configure' configures Oh! Multicast Video Scanner 0.4 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1402,7 +1402,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of Oh! Multicast Video Scanner 0.2:";; short | recursive ) echo "Configuration of Oh! Multicast Video Scanner 0.4:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1524,7 +1524,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
Oh! Multicast Video Scanner configure 0.2 Oh! Multicast Video Scanner configure 0.4
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -1893,7 +1893,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by Oh! Multicast Video Scanner $as_me 0.2, which was It was created by Oh! Multicast Video Scanner $as_me 0.4, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -2757,7 +2757,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='omvs' PACKAGE='omvs'
VERSION='0.2' VERSION='0.4'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -13266,7 +13266,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by Oh! Multicast Video Scanner $as_me 0.2, which was This file was extended by Oh! Multicast Video Scanner $as_me 0.4, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -13333,7 +13333,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
Oh! Multicast Video Scanner config.status 0.2 Oh! Multicast Video Scanner config.status 0.4
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@ -1,5 +1,5 @@
AC_PREREQ([2.69]) AC_PREREQ([2.69])
AC_INIT([Oh! Multicast Video Scanner], [0.2], [ohhara@postech.edu], [omvs], AC_INIT([Oh! Multicast Video Scanner], [0.4], [ohhara@postech.edu], [omvs],
[http://ohhara.sarang.net/omvs]) [http://ohhara.sarang.net/omvs])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([-Wall]) AM_INIT_AUTOMAKE([-Wall])

View File

@ -18,6 +18,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include <gst/gst.h> #include <gst/gst.h>
#include "omvs_gst.h" #include "omvs_gst.h"
@ -29,6 +30,9 @@ typedef struct _OMVSGstImpl {
OMVSGst omvs_gst_open(const gchar *uri, const gchar *filename) { OMVSGst omvs_gst_open(const gchar *uri, const gchar *filename) {
guint flags; guint flags;
OMVSGstImpl *gst_impl; OMVSGstImpl *gst_impl;
gchar *protocol;
gchar *location;
gchar *real_uri;
GstElement *play; GstElement *play;
GstElement *conv; GstElement *conv;
GstElement *png; GstElement *png;
@ -37,9 +41,34 @@ OMVSGst omvs_gst_open(const gchar *uri, const gchar *filename) {
GstPad *pad; GstPad *pad;
GstPad *ghostpad; GstPad *ghostpad;
if (gst_uri_is_valid(uri)) {
protocol = gst_uri_get_protocol(uri);
if (protocol) {
location = gst_uri_get_location(uri);
if (location) {
if (!gst_uri_protocol_is_supported(GST_URI_SRC, protocol)) {
if (strcmp(protocol, "rtp") == 0) {
g_free(protocol);
protocol = g_strdup("ortp");
}
}
real_uri = g_strdup_printf("%s://%s", protocol, location);
g_free(location);
} else {
real_uri = g_strdup(uri);
}
g_free(protocol);
} else {
real_uri = g_strdup(uri);
}
} else {
real_uri = g_strdup(uri);
}
gst_impl = g_malloc0(sizeof(OMVSGstImpl)); gst_impl = g_malloc0(sizeof(OMVSGstImpl));
gst_impl->play = play = gst_element_factory_make("playbin", "play"); gst_impl->play = play = gst_element_factory_make("playbin", "play");
g_object_set(G_OBJECT(play), "uri", uri, NULL); g_object_set(G_OBJECT(play), "uri", real_uri, NULL);
g_free(real_uri);
g_object_get(play, "flags", &flags, NULL); g_object_get(play, "flags", &flags, NULL);
flags &= (~0x00000002); flags &= (~0x00000002);
g_object_set(play, "flags", flags, NULL); g_object_set(play, "flags", flags, NULL);

53
omvs_gst_plugin.c Normal file
View File

@ -0,0 +1,53 @@
/*
Oh! Multicast Video Scanner
Copyright (C) 2016 Taeho Oh <ohhara@postech.edu>
This file is part of Oh! Multicast Video Scanner.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "omvs_gst_plugin.h"
#include "omvs_gst_plugin_rtpsrc.h"
#if 0
static gboolean omvs_gst_plugin_init(GstPlugin *plugin);
static gboolean omvs_gst_plugin_init(GstPlugin *plugin) {
if (!omvs_gst_plugin_rtpsrc_init(plugin)) {
return FALSE;
}
return TRUE;
}
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR, omvsrtp,
"RTP protocol for " PACKAGE, omvs_gst_plugin_init, PACKAGE_VERSION, "GPL",
PACKAGE, PACKAGE_URL)
#else
gboolean omvs_gst_plugin_register(void) {
gboolean ret;
ret = gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
"omvsrtpsrc", "RTP protocol for " PACKAGE, omvs_gst_plugin_rtpsrc_init,
PACKAGE_VERSION, "GPL", PACKAGE, PACKAGE, PACKAGE_URL);
return ret;
}
#endif

28
omvs_gst_plugin.h Normal file
View File

@ -0,0 +1,28 @@
/*
Oh! Multicast Video Scanner
Copyright (C) 2016 Taeho Oh <ohhara@postech.edu>
This file is part of Oh! Multicast Video Scanner.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _OMVS_GST_PLUGIN_H_
#define _OMVS_GST_PLUGIN_H_
#include <gst/gst.h>
extern gboolean omvs_gst_plugin_register(void);
#endif /* _OMVS_GST_PLUGIN_H_ */

398
omvs_gst_plugin_rtpsrc.c Normal file
View File

@ -0,0 +1,398 @@
/*
Oh! Multicast Video Scanner
Copyright (C) 2016 Taeho Oh <ohhara@postech.edu>
This file is part of Oh! Multicast Video Scanner.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "config.h"
#include "omvs_gst_plugin_rtpsrc.h"
GST_DEBUG_CATEGORY_STATIC(omvs_rtpsrc_debug);
#define GST_CAT_DEFAULT omvs_rtpsrc_debug
enum {
PROP_0,
PROP_URI,
PROP_LAST
};
#define DEFAULT_PROP_URI (NULL)
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("src",
GST_PAD_SRC, GST_PAD_SOMETIMES, GST_STATIC_CAPS("application/x-rtp"));
static gboolean gst_omvs_rtpsrc_parse_uri(const gchar *uristr, gchar **host,
guint16 *port);
static GstURIType gst_omvs_rtpsrc_uri_get_type(GType type);
static const gchar *const *gst_omvs_rtpsrc_uri_get_protocols(GType type);
static gchar *gst_omvs_rtpsrc_uri_get_uri(GstURIHandler *handler);
static gboolean gst_omvs_rtpsrc_uri_set_uri(GstURIHandler *handler,
const gchar *uri, GError **error);
static void gst_omvs_rtpsrc_uri_handler_init(gpointer g_iface,
gpointer iface_data);
static void gst_omvs_rtpsrc_set_property(GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
static void gst_omvs_rtpsrc_get_property(GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static void gst_omvs_rtpsrc_finalize(GObject *gobject);
static void gst_omvs_rtpsrc_rtpbin_pad_added_cb(GstElement *element,
GstPad *pad, gpointer data);
static gboolean gst_omvs_rtpsrc_start(GstOMVSRtpSrc *rtpsrc);
static GstStateChangeReturn gst_omvs_rtpsrc_change_state(GstElement *element,
GstStateChange transition);
static gboolean gst_omvs_rtpsrc_parse_uri(const gchar *uristr, gchar **host,
guint16 *port) {
gchar *protocol, *location_start;
gchar *location, *location_end;
gchar *colptr;
protocol = gst_uri_get_protocol(uristr);
if (!protocol) {
goto no_protocol;
}
if (strcmp(protocol, "ortp") != 0) {
goto wrong_protocol;
}
g_free(protocol);
location_start = gst_uri_get_location(uristr);
if (!location_start) {
return FALSE;
}
GST_DEBUG("got location '%s'", location_start);
location = g_strstr_len(location_start, -1, "@");
if (location == NULL) {
location = location_start;
}
else {
location += 1;
}
if (location[0] == '[') {
GST_DEBUG("parse IPV6 address '%s'", location);
location_end = strchr(location, ']');
if (location_end == NULL) {
goto wrong_address;
}
*host = g_strndup(location + 1, location_end - location - 1);
colptr = strrchr(location_end, ':');
} else {
GST_DEBUG("parse IPV4 address '%s'", location);
colptr = strrchr(location, ':');
if (colptr != NULL) {
*host = g_strndup(location, colptr - location);
} else {
*host = g_strdup(location);
}
}
GST_DEBUG("host set to '%s'", *host);
if (colptr != NULL) {
*port = g_ascii_strtoll(colptr + 1, NULL, 10);
} else {
*port = 0;
}
g_free(location_start);
return TRUE;
no_protocol:
{
GST_ERROR("error parsing uri %s: no protocol", uristr);
return FALSE;
}
wrong_protocol:
{
GST_ERROR("error parsing uri %s: wrong protocol (%s != ortp)", uristr,
protocol);
g_free(protocol);
return FALSE;
}
wrong_address:
{
GST_ERROR("error parsing uri %s", uristr);
g_free(location);
return FALSE;
}
}
#define gst_omvs_rtpsrc_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE(GstOMVSRtpSrc, gst_omvs_rtpsrc, GST_TYPE_BIN,
G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER,
gst_omvs_rtpsrc_uri_handler_init))
static void gst_omvs_rtpsrc_class_init(GstOMVSRtpSrcClass *klass) {
GObjectClass *oclass = G_OBJECT_CLASS(klass);
GstElementClass *gstelement_class = GST_ELEMENT_CLASS(klass);
oclass->set_property = gst_omvs_rtpsrc_set_property;
oclass->get_property = gst_omvs_rtpsrc_get_property;
oclass->finalize = gst_omvs_rtpsrc_finalize;
g_object_class_install_property(oclass, PROP_URI,
g_param_spec_string("uri", "URI", "URI of the media to play",
DEFAULT_PROP_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_add_pad_template(gstelement_class,
gst_static_pad_template_get(&src_template));
gstelement_class->change_state =
GST_DEBUG_FUNCPTR(gst_omvs_rtpsrc_change_state);
gst_element_class_set_static_metadata(gstelement_class, "omvsrtpsrc",
"Generic/Bin/Src", "OMVS RTP Src", "Taeho Oh <ohhara@postech.edu>");
GST_DEBUG_CATEGORY_INIT(omvs_rtpsrc_debug, "omvsrtpsrc", 0, "OMVS RTP Src");
}
static void gst_omvs_rtpsrc_init(GstOMVSRtpSrc *rtpsrc) {
rtpsrc->uri = NULL;
rtpsrc->udpsrc = NULL;
rtpsrc->rtpbin = NULL;
rtpsrc->n_pads = 0;
GST_DEBUG_OBJECT(rtpsrc, "omvsrtpsrc initialized");
}
static GstURIType gst_omvs_rtpsrc_uri_get_type(GType type) {
(void)type;
return GST_URI_SRC;
}
static const gchar *const *gst_omvs_rtpsrc_uri_get_protocols(GType type) {
static const gchar *protocols[] = { "ortp", NULL };
(void)type;
return protocols;
}
static gchar *gst_omvs_rtpsrc_uri_get_uri(GstURIHandler *handler) {
GstOMVSRtpSrc *rtpsrc = GST_OMVS_RTPSRC(handler);
return g_strdup(rtpsrc->uri);
}
static gboolean gst_omvs_rtpsrc_uri_set_uri(GstURIHandler *handler,
const gchar *uri, GError **error) {
GstOMVSRtpSrc *rtpsrc = (GstOMVSRtpSrc *)handler;
(void)error;
g_object_set(G_OBJECT(rtpsrc), "uri", uri, NULL);
return TRUE;
}
static void gst_omvs_rtpsrc_uri_handler_init(gpointer g_iface,
gpointer iface_data) {
GstURIHandlerInterface *iface = (GstURIHandlerInterface *)g_iface;
(void)iface_data;
iface->get_type = gst_omvs_rtpsrc_uri_get_type;
iface->get_protocols = gst_omvs_rtpsrc_uri_get_protocols;
iface->get_uri = gst_omvs_rtpsrc_uri_get_uri;
iface->set_uri = gst_omvs_rtpsrc_uri_set_uri;
}
static void gst_omvs_rtpsrc_set_property(GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec) {
GstOMVSRtpSrc *rtpsrc = GST_OMVS_RTPSRC(object);
switch (prop_id) {
case PROP_URI:
g_free(rtpsrc->uri);
rtpsrc->uri = g_strdup(g_value_get_string(value));
if (rtpsrc->udpsrc) {
gchar *host;
guint16 port;
if (gst_omvs_rtpsrc_parse_uri(rtpsrc->uri, &host, &port)) {
gchar *udpsrc_uri;
udpsrc_uri = g_strdup_printf("udp://%s:%u", host, port);
g_object_set(G_OBJECT(rtpsrc->udpsrc), "uri", udpsrc_uri, NULL);
g_free(host);
g_free(udpsrc_uri);
}
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void gst_omvs_rtpsrc_get_property(GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec) {
GstOMVSRtpSrc *rtpsrc = GST_OMVS_RTPSRC(object);
switch (prop_id) {
case PROP_URI:
g_value_set_string(value, rtpsrc->uri);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void gst_omvs_rtpsrc_finalize(GObject *gobject) {
GstOMVSRtpSrc *rtpsrc = GST_OMVS_RTPSRC(gobject);
g_free(rtpsrc->uri);
rtpsrc->uri = NULL;
rtpsrc->udpsrc = NULL;
rtpsrc->rtpbin = NULL;
rtpsrc->n_pads = 0;
G_OBJECT_CLASS(parent_class)->finalize(gobject);
}
static void gst_omvs_rtpsrc_rtpbin_pad_added_cb(GstElement *element,
GstPad *pad, gpointer data) {
gchar *name;
GstOMVSRtpSrc *rtpsrc = (GstOMVSRtpSrc *)data;
(void)element;
name = gst_pad_get_name(pad);
GST_DEBUG_OBJECT(rtpsrc, "adding a pad %s", name);
if (strncmp(name, "recv_rtp_src_", strlen("recv_rtp_src_")) != 0) {
g_free(name);
GST_DEBUG_OBJECT(rtpsrc, "Pad name does not start with recv_rtp_src_");
return;
}
g_free(name);
if (GST_PAD_DIRECTION(pad) == GST_PAD_SINK) {
GST_DEBUG_OBJECT(rtpsrc, "Pad is not src pad");
return;
}
gst_object_ref(pad);
if (rtpsrc->n_pads) {
GST_DEBUG_OBJECT(rtpsrc, "Ignore SSRC");
gst_ghost_pad_set_target(GST_GHOST_PAD(rtpsrc->ghostpad), pad);
gst_object_unref(pad);
return;
}
rtpsrc->ghostpad = gst_ghost_pad_new("src", pad);
gst_pad_set_active(rtpsrc->ghostpad, TRUE);
gst_element_add_pad(GST_ELEMENT(rtpsrc), rtpsrc->ghostpad);
gst_object_unref(pad);
rtpsrc->n_pads++;
gst_element_no_more_pads(GST_ELEMENT(rtpsrc));
return;
}
static gboolean gst_omvs_rtpsrc_start(GstOMVSRtpSrc *rtpsrc) {
gchar *host;
guint16 port;
GstCaps *caps;
GST_DEBUG_OBJECT(rtpsrc, "Creating elements");
rtpsrc->udpsrc = gst_element_factory_make("udpsrc", NULL);
if (!rtpsrc->udpsrc) {
return FALSE;
}
rtpsrc->rtpbin = gst_element_factory_make("rtpbin", NULL);
if (!rtpsrc->rtpbin) {
gst_object_unref(rtpsrc->udpsrc);
rtpsrc->udpsrc = NULL;
return FALSE;
}
caps = gst_caps_new_simple("application/x-rtp",
"media", G_TYPE_STRING, "video",
"clock-rate", G_TYPE_INT, 90000,
"payload", G_TYPE_INT, 33,
NULL);
g_object_set(G_OBJECT(rtpsrc->udpsrc), "caps", caps, NULL);
gst_caps_unref(caps);
if (gst_omvs_rtpsrc_parse_uri(rtpsrc->uri, &host, &port)) {
gchar *udpsrc_uri;
udpsrc_uri = g_strdup_printf("udp://%s:%u", host, port);
g_object_set(G_OBJECT(rtpsrc->udpsrc), "uri", udpsrc_uri, NULL);
g_free(host);
g_free(udpsrc_uri);
}
gst_bin_add_many(GST_BIN(rtpsrc), rtpsrc->udpsrc, rtpsrc->rtpbin, NULL);
gst_element_link_pads(rtpsrc->udpsrc, "src", rtpsrc->rtpbin,
"recv_rtp_sink_0");
g_signal_connect(rtpsrc->rtpbin, "pad-added",
G_CALLBACK(gst_omvs_rtpsrc_rtpbin_pad_added_cb), rtpsrc);
if (!gst_element_sync_state_with_parent(rtpsrc->udpsrc)) {
GST_ERROR_OBJECT(rtpsrc, "Could not set udpsrc to playing");
}
if (!gst_element_sync_state_with_parent(rtpsrc->rtpbin)) {
GST_ERROR_OBJECT(rtpsrc, "Could not set rtpbin to playing");
}
return TRUE;
}
static GstStateChangeReturn gst_omvs_rtpsrc_change_state(GstElement *element,
GstStateChange transition) {
GstOMVSRtpSrc *rtpsrc = GST_OMVS_RTPSRC(element);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
GST_DEBUG_OBJECT(rtpsrc, "Configuring omvsrtpsrc");
if (!gst_omvs_rtpsrc_start(rtpsrc)) {
GST_DEBUG_OBJECT(rtpsrc, "Start failed");
return GST_STATE_CHANGE_FAILURE;
}
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
break;
default:
break;
}
return GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
}
gboolean omvs_gst_plugin_rtpsrc_init(GstPlugin *plugin) {
gboolean ret;
ret = gst_element_register(plugin, "omvsrtpsrc", GST_RANK_NONE,
GST_TYPE_OMVS_RTPSRC);
return ret;
}

58
omvs_gst_plugin_rtpsrc.h Normal file
View File

@ -0,0 +1,58 @@
/*
Oh! Multicast Video Scanner
Copyright (C) 2016 Taeho Oh <ohhara@postech.edu>
This file is part of Oh! Multicast Video Scanner.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _OMVS_GST_PLUGIN_RTPSRC_H_
#define _OMVS_GST_PLUGIN_RTPSRC_H_
#include <gst/gst.h>
#define GST_TYPE_OMVS_RTPSRC (gst_omvs_rtpsrc_get_type())
#define GST_OMVS_RTPSRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_OMVS_RTPSRC, GstOMVSRtpSrc))
#define GST_OMVS_RTPSRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_OMVS_RTPSRC, GstOMVSRtpSrcClass))
#define GST_IS_OMVS_RTPSRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OMVS_RTPSRC))
#define GST_IS_OMVS_RTPSRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_OMVS_RTPSRC))
#define GST_OMVS_RTPSRC_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_OMVS_RTPSRC, GstOMVSRtpSrcClass))
typedef struct _GstOMVSRtpSrcClass GstOMVSRtpSrcClass;
typedef struct _GstOMVSRtpSrc GstOMVSRtpSrc;
struct _GstOMVSRtpSrcClass {
GstBinClass parent_class;
};
struct _GstOMVSRtpSrc {
GstBin parent_instance;
gchar *uri;
GstElement *udpsrc;
GstElement *rtpbin;
GstPad *ghostpad;
gint n_pads;
};
extern GType gst_omvs_rtpsrc_get_type(void);
extern gboolean omvs_gst_plugin_rtpsrc_init(GstPlugin *plugin);
#endif /* _OMVS_GST_PLUGIN_RTPSRC_H_ */

View File

@ -1,3 +1,23 @@
/*
Oh! Multicast Video Scanner
Copyright (C) 2016 Taeho Oh <ohhara@postech.edu>
This file is part of Oh! Multicast Video Scanner.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h> #include <string.h>
#include <pcap/pcap.h> #include <pcap/pcap.h>
#include <glib.h> #include <glib.h>
@ -7,6 +27,7 @@
#include "config.h" #include "config.h"
#include "omvs_gst.h" #include "omvs_gst.h"
#include "omvs_gst_plugin.h"
#define _OMVS_IPPROTO_UDP 17 #define _OMVS_IPPROTO_UDP 17
@ -16,11 +37,16 @@ static gchar *_omvs_outdir = "omvs_out";
static gint _omvs_jobs = 1; static gint _omvs_jobs = 1;
static gint _omvs_sleep = 1000; static gint _omvs_sleep = 1000;
static gint _omvs_timeout = 10000; static gint _omvs_timeout = 10000;
static gboolean _omvs_udp_scan;
static gboolean _omvs_quiet; static gboolean _omvs_quiet;
static gboolean _omvs_wait;
static gchar **_omvs_net_dev_names; static gchar **_omvs_net_dev_names;
static gchar **_omvs_net_dev_descs; static gchar **_omvs_net_dev_descs;
static gint _omvs_num_net_devs; static gint _omvs_num_net_devs;
static FILE *_omvs_m3u_fp;
static gint _omvs_m3u_idx;
static GMutex _omvs_mutex;
static GOptionEntry _omvs_entries[] = static GOptionEntry _omvs_entries[] =
{ {
@ -36,8 +62,12 @@ static GOptionEntry _omvs_entries[] =
"Sleep time(milliseconds) between scans", "ms" }, "Sleep time(milliseconds) between scans", "ms" },
{ "timeout", 't', 0, G_OPTION_ARG_INT, &_omvs_timeout, { "timeout", 't', 0, G_OPTION_ARG_INT, &_omvs_timeout,
"Timeout time(milliseconds) in each scan", "ms" }, "Timeout time(milliseconds) in each scan", "ms" },
{ "udp", 'u', 0, G_OPTION_ARG_NONE, &_omvs_udp_scan,
"Use udp protocol instead of rtp", NULL },
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &_omvs_quiet, { "quiet", 'q', 0, G_OPTION_ARG_NONE, &_omvs_quiet,
"Print no log except for errors", NULL }, "Print no log except for errors", NULL },
{ "wait", 'w', 0, G_OPTION_ARG_NONE, &_omvs_wait,
"Wait for multicast packet", NULL },
{ NULL } { NULL }
}; };
@ -84,6 +114,7 @@ static gint _omvs_print_net_devs_info(void);
static gint _omvs_deinit_net_devs_info(void); static gint _omvs_deinit_net_devs_info(void);
static gint _omvs_start_scan(OMVSScanner *scanner); static gint _omvs_start_scan(OMVSScanner *scanner);
static gpointer _omvs_start_scan_job(gpointer data); static gpointer _omvs_start_scan_job(gpointer data);
static gint _omvs_wait_for_multicast_packet(void);
static gint _omvs_init_net_devs_info(void) { static gint _omvs_init_net_devs_info(void) {
gchar errbuf[PCAP_ERRBUF_SIZE]; gchar errbuf[PCAP_ERRBUF_SIZE];
@ -92,7 +123,7 @@ static gint _omvs_init_net_devs_info(void) {
gint i; gint i;
if (pcap_findalldevs(&alldevs, errbuf) != 0) { if (pcap_findalldevs(&alldevs, errbuf) != 0) {
g_print("pcap_findalldevs() fail: %s", errbuf); g_print("pcap_findalldevs() fail: %s\n", errbuf);
return -1; return -1;
} }
dev = alldevs; dev = alldevs;
@ -198,7 +229,7 @@ static gpointer _omvs_start_scan_job(gpointer data) {
addr[3] = (guint8)((o_ipaddr->addr >> 0) & 0xff); addr[3] = (guint8)((o_ipaddr->addr >> 0) & 0xff);
addr_str = addr_str =
g_strdup_printf("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); g_strdup_printf("%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]);
if (!_omvs_quiet) { if (!_omvs_quiet) {
g_print("[%p] start scanning %s\n", (void *)g_thread_self(), addr_str); g_print("[%p] start scanning %s\n", (void *)g_thread_self(), addr_str);
@ -284,7 +315,11 @@ static gpointer _omvs_start_scan_job(gpointer data) {
if (!is_udp_port_found) { if (!is_udp_port_found) {
gchar *uri; gchar *uri;
gchar *filename; gchar *filename;
if (_omvs_udp_scan) {
uri = g_strdup_printf("udp://%s:%d", addr_str, udp_port); uri = g_strdup_printf("udp://%s:%d", addr_str, udp_port);
} else {
uri = g_strdup_printf("rtp://%s:%d", addr_str, udp_port);
}
filename = filename =
g_strdup_printf("%s/%s-%d.png", _omvs_outdir, addr_str, udp_port); g_strdup_printf("%s/%s-%d.png", _omvs_outdir, addr_str, udp_port);
if (!_omvs_quiet) { if (!_omvs_quiet) {
@ -333,6 +368,25 @@ static gpointer _omvs_start_scan_job(gpointer data) {
omvs_gst_close(o_ipaddr->gsts[j]); omvs_gst_close(o_ipaddr->gsts[j]);
} }
g_free(o_ipaddr->gsts); g_free(o_ipaddr->gsts);
for (j = 0; j < o_ipaddr->num_ports; j++) {
gchar *filename;
filename = g_strdup_printf("%s/%s-%d.png", _omvs_outdir, addr_str,
o_ipaddr->ports[j]);
if (g_access(filename, F_OK) == 0) {
_omvs_m3u_idx++;
g_mutex_lock(&_omvs_mutex);
fprintf(_omvs_m3u_fp, "#EXTINF:%u,%u\n", _omvs_m3u_idx, _omvs_m3u_idx);
if (_omvs_udp_scan) {
fprintf(_omvs_m3u_fp, "udp://%s:%u\n", addr_str, o_ipaddr->ports[j]);
} else {
fprintf(_omvs_m3u_fp, "rtp://%s:%u\n", addr_str, o_ipaddr->ports[j]);
}
fflush(_omvs_m3u_fp);
g_mutex_unlock(&_omvs_mutex);
}
g_free(filename);
}
g_free(o_ipaddr->ports);
if (!_omvs_quiet) { if (!_omvs_quiet) {
g_print("[%p] finish scanning %s\n", (void *)g_thread_self(), addr_str); g_print("[%p] finish scanning %s\n", (void *)g_thread_self(), addr_str);
@ -392,6 +446,175 @@ static gint _omvs_start_scan(OMVSScanner *scanner) {
return 0; return 0;
} }
static gint _omvs_wait_for_multicast_packet(void) {
pcap_t *pcap;
gchar errbuf[PCAP_ERRBUF_SIZE];
const guint8 *packet;
struct pcap_pkthdr *header;
GHashTable *urihashtable;
gint64 time1, time2;
OMVSGst gst;
gchar *cur_uri;
gchar *cur_addr_str;
gint udp_port;
pcap = pcap_open_live(_omvs_net_dev_names[_omvs_net_dev_idx],
sizeof(OMVSEthHdr) + sizeof(OMVSIPHdr) + sizeof(OMVSUDPHdr),
TRUE, 500, errbuf);
if (pcap == NULL) {
g_printerr("[%p] can't open pcap: %s\n", (void *)g_thread_self(), errbuf);
goto finish_return2;
}
if (pcap_datalink(pcap) != DLT_EN10MB) {
g_printerr("[%p] %s is not ethernet\n", (void *)g_thread_self(),
_omvs_net_dev_names[_omvs_net_dev_idx]);
goto finish_return3;
}
gst = NULL;
cur_uri = NULL;
cur_addr_str = NULL;
urihashtable =
g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
time1 = g_get_monotonic_time();
for (;;) {
gint ret;
guint caplen;
OMVSIPHdr *ip;
OMVSUDPHdr *udp;
guint ip_hdr_len;
GInetAddress *addr;
gchar *addr_str;
guint32 haddr;
gchar *uri;
gchar *filename;
ret = pcap_next_ex(pcap, &header, &packet);
if (ret < 0) {
break;
}
if (gst) {
time2 = g_get_monotonic_time();
if (omvs_gst_is_finished(gst) ||
time2 - time1 > (gint64)((gint64)_omvs_timeout * 1000)) {
if (!_omvs_quiet) {
g_print("[%p] finish scanning %s\n", (void *)g_thread_self(),
cur_addr_str);
}
omvs_gst_close(gst);
gst = NULL;
filename = g_strdup_printf("%s/%s-%d.png", _omvs_outdir, cur_addr_str,
udp_port);
if (g_access(filename, F_OK) == 0) {
_omvs_m3u_idx++;
g_mutex_lock(&_omvs_mutex);
fprintf(_omvs_m3u_fp, "#EXTINF:%u,%u\n", _omvs_m3u_idx,
_omvs_m3u_idx);
fprintf(_omvs_m3u_fp, "%s\n", cur_uri);
fflush(_omvs_m3u_fp);
g_mutex_unlock(&_omvs_mutex);
}
g_free(filename);
g_free(cur_uri);
g_free(cur_addr_str);
cur_uri = NULL;
cur_addr_str = NULL;
} else {
continue;
}
}
if (ret == 0) {
continue;
}
caplen = header->caplen;
if (caplen < sizeof(OMVSEthHdr)) {
continue;
}
packet += sizeof(OMVSEthHdr);
caplen -= sizeof(OMVSEthHdr);
if (caplen < sizeof(OMVSIPHdr)) {
continue;
}
ip = (OMVSIPHdr *)packet;
ip_hdr_len = (ip->vhl & 0x0f) * 4;
if (caplen < ip_hdr_len) {
continue;
}
if (ip->protocol != _OMVS_IPPROTO_UDP) {
continue;
}
addr = g_inet_address_new_from_bytes(
(const guint8 *)&ip->daddr, G_SOCKET_FAMILY_IPV4);
if (!g_inet_address_get_is_multicast(addr)) {
g_object_unref(addr);
continue;
}
g_object_unref(addr);
packet += ip_hdr_len;
caplen -= ip_hdr_len;
if (caplen < sizeof(OMVSUDPHdr)) {
continue;
}
udp = (OMVSUDPHdr *)packet;
udp_port = g_ntohs(udp->uh_dport);
haddr = g_ntohl(ip->daddr);
addr_str = g_strdup_printf("%u.%u.%u.%u",
(haddr >> 24) & 0xff,
(haddr >> 16) & 0xff,
(haddr >> 8) & 0xff,
(haddr >> 0) & 0xff);
if (_omvs_udp_scan) {
uri = g_strdup_printf("udp://%s:%u", addr_str, udp_port);
} else {
uri = g_strdup_printf("rtp://%s:%u", addr_str, udp_port);
}
if (!g_hash_table_replace(urihashtable, uri, addr_str)) {
continue;
}
g_assert(cur_uri == NULL);
cur_uri = g_strdup(uri);
g_assert(cur_addr_str == NULL);
cur_addr_str = g_strdup(addr_str);
filename =
g_strdup_printf("%s/%s-%d.png", _omvs_outdir, cur_addr_str, udp_port);
if (!_omvs_quiet) {
g_print("[%p] start scanning %s\n", (void *)g_thread_self(),
cur_addr_str);
g_print("[%p] trying to save %s to %s\n", (void *)g_thread_self(),
cur_uri, filename);
}
time1 = g_get_monotonic_time();
g_assert(gst == NULL);
gst = omvs_gst_open(cur_uri, filename);
g_free(filename);
}
g_hash_table_destroy(urihashtable);
return 0;
finish_return3:
pcap_close(pcap);
finish_return2:
return -1;
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
GError *error = NULL; GError *error = NULL;
GOptionContext *context; GOptionContext *context;
@ -400,6 +623,8 @@ int main(int argc, char *argv[]) {
gint num_ipaddrs; gint num_ipaddrs;
gint idx_ipaddr; gint idx_ipaddr;
OMVSScanner omvs_scanner; OMVSScanner omvs_scanner;
gchar *m3u_path;
gint64 time;
if (_omvs_init_net_devs_info() != 0) { if (_omvs_init_net_devs_info() != 0) {
ret = -1; ret = -1;
@ -428,16 +653,38 @@ int main(int argc, char *argv[]) {
goto finish_return; goto finish_return;
} }
if (argc < 2 || _omvs_net_dev_idx >= _omvs_num_net_devs) { if ((!_omvs_wait && argc < 2) || _omvs_net_dev_idx >= _omvs_num_net_devs) {
gchar *help_msg; gchar *help_msg;
help_msg = g_option_context_get_help(context, TRUE, NULL); help_msg = g_option_context_get_help(context, TRUE, NULL);
g_print("%s", help_msg); g_print("%s", help_msg);
g_free(help_msg); g_free(help_msg);
ret = -2; ret = -6;
goto finish_return; goto finish_return;
} }
omvs_gst_plugin_register();
g_mkdir(_omvs_outdir, 0755); g_mkdir(_omvs_outdir, 0755);
time = g_get_real_time();
m3u_path = g_strdup_printf("%s/omvs_%" G_GUINT64_FORMAT ".m3u", _omvs_outdir,
time);
if (!_omvs_quiet) {
g_print("openning %s\n", m3u_path);
}
_omvs_m3u_fp = fopen(m3u_path, "w");
if (_omvs_m3u_fp == NULL) {
g_print("can't create %s\n", m3u_path);
g_free(m3u_path);
ret = -7;
goto finish_return;
}
g_free(m3u_path);
fprintf(_omvs_m3u_fp, "#EXTM3U\n");
if (_omvs_wait) {
_omvs_wait_for_multicast_packet();
goto finish_return;
}
num_ipaddrs = 0; num_ipaddrs = 0;
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
@ -514,6 +761,9 @@ int main(int argc, char *argv[]) {
finish_return: finish_return:
g_option_context_free(context); g_option_context_free(context);
_omvs_deinit_net_devs_info(); _omvs_deinit_net_devs_info();
if (_omvs_m3u_fp) {
fclose(_omvs_m3u_fp);
}
finish_return2: finish_return2:
return ret; return ret;