Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
e69ff713
Commit
e69ff713
authored
Jun 21, 2019
by
Alexander Alekhin
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #14846 from alalek:videoio_gstreamer_issues_master
parents
9cb23924
2b2633c1
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
808 additions
and
464 deletions
+808
-464
run_long.py
modules/ts/misc/run_long.py
+2
-1
cap_gstreamer.cpp
modules/videoio/src/cap_gstreamer.cpp
+543
-421
test_gstreamer.cpp
modules/videoio/test/test_gstreamer.cpp
+18
-0
test_video_io.cpp
modules/videoio/test/test_video_io.cpp
+110
-39
valgrind.supp
platforms/scripts/valgrind.supp
+37
-0
valgrind_3rdparty.supp
platforms/scripts/valgrind_3rdparty.supp
+98
-3
No files found.
modules/ts/misc/run_long.py
View file @
e69ff713
...
@@ -43,7 +43,8 @@ LONG_TESTS_DEBUG_VALGRIND = [
...
@@ -43,7 +43,8 @@ LONG_TESTS_DEBUG_VALGRIND = [
(
'tracking'
,
'UKF.br_mean_squared_error'
,
5228.27
),
(
'tracking'
,
'UKF.br_mean_squared_error'
,
5228.27
),
(
'tracking'
,
'*DistanceAndOverlap*/1'
,
1000.0
),
# dudek
(
'tracking'
,
'*DistanceAndOverlap*/1'
,
1000.0
),
# dudek
(
'tracking'
,
'*DistanceAndOverlap*/2'
,
1000.0
),
# faceocc2
(
'tracking'
,
'*DistanceAndOverlap*/2'
,
1000.0
),
# faceocc2
(
'videoio'
,
'Videoio_Video.ffmpeg_writebig'
,
1000
),
(
'videoio'
,
'videoio/videoio_ffmpeg.write_big*'
,
1000
),
(
'videoio'
,
'videoio_ffmpeg.parallel'
,
1000
),
(
'xfeatures2d'
,
'Features2d_RotationInvariance_Descriptor_BoostDesc_LBGM.regression'
,
1124.51
),
(
'xfeatures2d'
,
'Features2d_RotationInvariance_Descriptor_BoostDesc_LBGM.regression'
,
1124.51
),
(
'xfeatures2d'
,
'Features2d_RotationInvariance_Descriptor_VGG120.regression'
,
2198.1
),
(
'xfeatures2d'
,
'Features2d_RotationInvariance_Descriptor_VGG120.regression'
,
2198.1
),
(
'xfeatures2d'
,
'Features2d_RotationInvariance_Descriptor_VGG48.regression'
,
1958.52
),
(
'xfeatures2d'
,
'Features2d_RotationInvariance_Descriptor_VGG48.regression'
,
1958.52
),
...
...
modules/videoio/src/cap_gstreamer.cpp
View file @
e69ff713
...
@@ -48,12 +48,13 @@
...
@@ -48,12 +48,13 @@
* \brief Use GStreamer to read/write video
* \brief Use GStreamer to read/write video
*/
*/
#include "precomp.hpp"
#include "precomp.hpp"
#include <opencv2/core/utils/logger.hpp>
#include <opencv2/core/utils/filesystem.hpp>
#include <iostream>
#include <iostream>
using
namespace
std
;
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <string.h>
#include <string.h>
#include <gst/gst.h>
#include <gst/gst.h>
#include <gst/gstbuffer.h>
#include <gst/gstbuffer.h>
#include <gst/video/video.h>
#include <gst/video/video.h>
...
@@ -68,35 +69,104 @@ using namespace std;
...
@@ -68,35 +69,104 @@ using namespace std;
#include <gst/pbutils/encoding-profile.h>
#include <gst/pbutils/encoding-profile.h>
//#include <gst/base/gsttypefindhelper.h>
//#include <gst/base/gsttypefindhelper.h>
#ifdef NDEBUG
#define CV_WARN(...) CV_LOG_WARNING(NULL, "OpenCV | GStreamer warning: " << __VA_ARGS__)
#define CV_WARN(message)
#else
#define CV_WARN(message) CV_LOG_WARNING(0, message)
#endif
#define COLOR_ELEM "videoconvert"
#define COLOR_ELEM "videoconvert"
#define COLOR_ELEM_NAME COLOR_ELEM
#define COLOR_ELEM_NAME COLOR_ELEM
#if defined(_WIN32) || defined(_WIN64)
#define CV_GST_FORMAT(format) (format)
#if defined(__MINGW32__)
inline
char
*
realpath
(
const
char
*
path
,
char
*
resolved_path
)
namespace
cv
{
static
void
toFraction
(
double
decimal
,
CV_OUT
int
&
numerator
,
CV_OUT
int
&
denominator
);
static
void
handleMessage
(
GstElement
*
pipeline
);
namespace
{
template
<
typename
T
>
static
inline
void
GSafePtr_addref
(
T
*
ptr
)
{
{
return
_fullpath
(
resolved_path
,
path
,
PATH_MAX
);
if
(
ptr
)
g_object_ref_sink
(
ptr
);
}
}
template
<
typename
T
>
static
inline
void
GSafePtr_release
(
T
**
pPtr
);
template
<>
inline
void
GSafePtr_release
<
GError
>
(
GError
**
pPtr
)
{
g_clear_error
(
pPtr
);
}
template
<>
inline
void
GSafePtr_release
<
GstElement
>
(
GstElement
**
pPtr
)
{
if
(
pPtr
)
{
gst_object_unref
(
G_OBJECT
(
*
pPtr
));
*
pPtr
=
NULL
;
}
}
template
<>
inline
void
GSafePtr_release
<
GstElementFactory
>
(
GstElementFactory
**
pPtr
)
{
if
(
pPtr
)
{
gst_object_unref
(
G_OBJECT
(
*
pPtr
));
*
pPtr
=
NULL
;
}
}
template
<>
inline
void
GSafePtr_release
<
GstPad
>
(
GstPad
**
pPtr
)
{
if
(
pPtr
)
{
gst_object_unref
(
G_OBJECT
(
*
pPtr
));
*
pPtr
=
NULL
;
}
}
template
<>
inline
void
GSafePtr_release
<
GstCaps
>
(
GstCaps
**
pPtr
)
{
if
(
pPtr
)
{
gst_caps_unref
(
*
pPtr
);
*
pPtr
=
NULL
;
}
}
template
<>
inline
void
GSafePtr_release
<
GstBuffer
>
(
GstBuffer
**
pPtr
)
{
if
(
pPtr
)
{
gst_buffer_unref
(
*
pPtr
);
*
pPtr
=
NULL
;
}
}
template
<>
inline
void
GSafePtr_release
<
GstSample
>
(
GstSample
**
pPtr
)
{
if
(
pPtr
)
{
gst_sample_unref
(
*
pPtr
);
*
pPtr
=
NULL
;
}
}
template
<>
inline
void
GSafePtr_release
<
GstBus
>
(
GstBus
**
pPtr
)
{
if
(
pPtr
)
{
gst_object_unref
(
G_OBJECT
(
*
pPtr
));
*
pPtr
=
NULL
;
}
}
template
<>
inline
void
GSafePtr_release
<
GstMessage
>
(
GstMessage
**
pPtr
)
{
if
(
pPtr
)
{
gst_message_unref
(
*
pPtr
);
*
pPtr
=
NULL
;
}
}
template
<>
inline
void
GSafePtr_release
<
GstEncodingVideoProfile
>
(
GstEncodingVideoProfile
**
pPtr
)
{
if
(
pPtr
)
{
gst_encoding_profile_unref
(
*
pPtr
);
*
pPtr
=
NULL
;
}
}
template
<>
inline
void
GSafePtr_release
<
GstEncodingContainerProfile
>
(
GstEncodingContainerProfile
**
pPtr
)
{
if
(
pPtr
)
{
gst_object_unref
(
G_OBJECT
(
*
pPtr
));
*
pPtr
=
NULL
;
}
}
template
<>
inline
void
GSafePtr_addref
<
char
>
(
char
*
pPtr
);
// declaration only. not defined. should not be used
template
<>
inline
void
GSafePtr_release
<
char
>
(
char
**
pPtr
)
{
if
(
pPtr
)
{
g_free
(
*
pPtr
);
*
pPtr
=
NULL
;
}
}
template
<
typename
T
>
class
GSafePtr
{
protected
:
T
*
ptr
;
public
:
inline
GSafePtr
()
CV_NOEXCEPT
:
ptr
(
NULL
)
{
}
inline
~
GSafePtr
()
CV_NOEXCEPT
{
release
();
}
inline
void
release
()
CV_NOEXCEPT
{
#if 0
printf("release: %s:%d: %p\n", CV__TRACE_FUNCTION, __LINE__, ptr);
if (ptr) {
printf(" refcount: %d\n", (int)GST_OBJECT_REFCOUNT_VALUE(ptr)); \
}
#endif
#endif
#define snprintf _snprintf
if
(
ptr
)
#define vsnprintf _vsnprintf
GSafePtr_release
<
T
>
(
&
ptr
);
#define strcasecmp _stricmp
}
#define strncasecmp _strnicmp
#include <sys/stat.h>
inline
operator
T
*
()
CV_NOEXCEPT
{
return
ptr
;
}
#endif
inline
operator
/*const*/
T
*
()
const
CV_NOEXCEPT
{
return
(
T
*
)
ptr
;
}
// there is no const correctness in Gst C API
inline
T
*
get
()
CV_NOEXCEPT
{
return
ptr
;
}
inline
/*const*/
T
*
get
()
const
CV_NOEXCEPT
{
CV_Assert
(
ptr
);
return
(
T
*
)
ptr
;
}
// there is no const correctness in Gst C API
inline
const
T
*
operator
->
()
const
{
CV_Assert
(
ptr
);
return
ptr
;
}
inline
operator
bool
()
const
CV_NOEXCEPT
{
return
ptr
!=
NULL
;
}
inline
bool
operator
!
()
const
CV_NOEXCEPT
{
return
ptr
==
NULL
;
}
inline
T
**
getRef
()
{
CV_Assert
(
ptr
==
NULL
);
return
&
ptr
;
}
inline
GSafePtr
&
reset
(
T
*
p
)
CV_NOEXCEPT
// pass result of functions with "transfer floating" ownership
{
//printf("reset: %s:%d: %p\n", CV__TRACE_FUNCTION, __LINE__, p);
release
();
if
(
p
)
{
GSafePtr_addref
<
T
>
(
p
);
ptr
=
p
;
}
return
*
this
;
}
void
toFraction
(
double
decimal
,
double
&
numerator
,
double
&
denominator
);
inline
GSafePtr
&
attach
(
T
*
p
)
CV_NOEXCEPT
// pass result of functions with "transfer full" ownership
void
handleMessage
(
GstElement
*
pipeline
);
{
//printf("attach: %s:%d: %p\n", CV__TRACE_FUNCTION, __LINE__, p);
release
();
ptr
=
p
;
return
*
this
;
}
inline
T
*
detach
()
CV_NOEXCEPT
{
T
*
p
=
ptr
;
ptr
=
NULL
;
return
p
;
}
using
namespace
cv
;
inline
void
swap
(
GSafePtr
&
o
)
CV_NOEXCEPT
{
std
::
swap
(
ptr
,
o
.
ptr
);
}
private
:
GSafePtr
(
const
GSafePtr
&
);
// = disabled
GSafePtr
&
operator
=
(
const
T
*
);
// = disabled
};
static
cv
::
Mutex
gst_initializer_mutex
;
}
// namespace
/*!
/*!
* \brief The gst_initializer class
* \brief The gst_initializer class
...
@@ -105,29 +175,50 @@ static cv::Mutex gst_initializer_mutex;
...
@@ -105,29 +175,50 @@ static cv::Mutex gst_initializer_mutex;
class
gst_initializer
class
gst_initializer
{
{
public
:
public
:
static
void
init
()
static
gst_initializer
&
init
()
{
{
gst_initializer_mutex
.
lock
();
static
gst_initializer
g_init
;
static
gst_initializer
init
;
if
(
g_init
.
isFailed
)
gst_initializer_mutex
.
unlock
();
CV_Error
(
Error
::
StsError
,
"Can't initialize GStreamer"
);
return
g_init
;
}
}
private
:
private
:
gst_initializer
()
bool
isFailed
;
bool
call_deinit
;
gst_initializer
()
:
isFailed
(
false
)
{
{
gst_init
(
NULL
,
NULL
);
call_deinit
=
utils
::
getConfigurationParameterBool
(
"OPENCV_VIDEOIO_GSTREAMER_CALL_DEINIT"
,
false
);
GSafePtr
<
GError
>
err
;
gst_init_check
(
NULL
,
NULL
,
err
.
getRef
());
if
(
err
)
{
CV_WARN
(
"Can't initialize GStreamer: "
<<
err
->
message
);
isFailed
=
true
;
return
;
}
guint
major
,
minor
,
micro
,
nano
;
guint
major
,
minor
,
micro
,
nano
;
gst_version
(
&
major
,
&
minor
,
&
micro
,
&
nano
);
gst_version
(
&
major
,
&
minor
,
&
micro
,
&
nano
);
if
(
GST_VERSION_MAJOR
!=
major
)
if
(
GST_VERSION_MAJOR
!=
major
)
{
{
CV_WARN
(
"incompatible gstreamer version"
);
CV_WARN
(
"incompatible GStreamer version"
);
isFailed
=
true
;
return
;
}
}
~
gst_initializer
()
{
if
(
call_deinit
)
{
// Debug leaks: GST_LEAKS_TRACER_STACK_TRACE=1 GST_DEBUG="GST_TRACER:7" GST_TRACERS="leaks"
gst_deinit
();
}
}
// gst_debug_set_active(1);
// gst_debug_set_colored(1);
// gst_debug_set_default_threshold(GST_LEVEL_INFO);
}
}
};
};
inline
static
string
get_gst_propname
(
int
propId
)
inline
static
std
::
string
get_gst_propname
(
int
propId
)
{
{
switch
(
propId
)
switch
(
propId
)
{
{
...
@@ -135,17 +226,15 @@ inline static string get_gst_propname(int propId)
...
@@ -135,17 +226,15 @@ inline static string get_gst_propname(int propId)
case
CV_CAP_PROP_CONTRAST
:
return
"contrast"
;
case
CV_CAP_PROP_CONTRAST
:
return
"contrast"
;
case
CV_CAP_PROP_SATURATION
:
return
"saturation"
;
case
CV_CAP_PROP_SATURATION
:
return
"saturation"
;
case
CV_CAP_PROP_HUE
:
return
"hue"
;
case
CV_CAP_PROP_HUE
:
return
"hue"
;
default:
return
string
();
default
:
return
st
d
::
st
ring
();
}
}
}
}
inline
static
bool
is_gst_element_exists
(
const
std
::
string
&
name
)
inline
static
bool
is_gst_element_exists
(
const
std
::
string
&
name
)
{
{
GstElementFactory
*
testfac
=
gst_element_factory_find
(
name
.
c_str
());
GSafePtr
<
GstElementFactory
>
testfac
;
testfac
.
attach
(
gst_element_factory_find
(
name
.
c_str
()));
if
(
!
testfac
)
return
(
bool
)
testfac
;
return
false
;
g_object_unref
(
G_OBJECT
(
testfac
));
return
true
;
}
}
//==================================================================================================
//==================================================================================================
...
@@ -153,36 +242,35 @@ inline static bool is_gst_element_exists(const std::string & name)
...
@@ -153,36 +242,35 @@ inline static bool is_gst_element_exists(const std::string & name)
class
GStreamerCapture
CV_FINAL
:
public
IVideoCapture
class
GStreamerCapture
CV_FINAL
:
public
IVideoCapture
{
{
private
:
private
:
GstElement
*
pipeline
;
GSafePtr
<
GstElement
>
pipeline
;
GstElement
*
v4l2src
;
GSafePtr
<
GstElement
>
v4l2src
;
GstElement
*
sink
;
GSafePtr
<
GstElement
>
sink
;
GstSample
*
sample
;
GSafePtr
<
GstSample
>
sample
;
GstCaps
*
caps
;
GSafePtr
<
GstCaps
>
caps
;
gint64
duration
;
gint64
duration
;
gint
width
;
gint
width
;
gint
height
;
gint
height
;
gint
channels
;
double
fps
;
double
fps
;
bool
isPosFramesSupported
;
bool
isPosFramesSupported
;
bool
isPosFramesEmulated
;
bool
isPosFramesEmulated
;
gint64
emulatedFrameNumber
;
gint64
emulatedFrameNumber
;
bool
isOutputByteBuffer
;
public
:
public
:
GStreamerCapture
();
GStreamerCapture
();
~
GStreamerCapture
()
;
virtual
~
GStreamerCapture
()
CV_OVERRIDE
;
virtual
bool
grabFrame
()
CV_OVERRIDE
;
virtual
bool
grabFrame
()
CV_OVERRIDE
;
virtual
bool
retrieveFrame
(
int
/*unused*/
,
OutputArray
dst
)
CV_OVERRIDE
;
virtual
bool
retrieveFrame
(
int
/*unused*/
,
OutputArray
dst
)
CV_OVERRIDE
;
virtual
double
getProperty
(
int
propId
)
const
CV_OVERRIDE
;
virtual
double
getProperty
(
int
propId
)
const
CV_OVERRIDE
;
virtual
bool
setProperty
(
int
propId
,
double
value
)
CV_OVERRIDE
;
virtual
bool
setProperty
(
int
propId
,
double
value
)
CV_OVERRIDE
;
virtual
bool
isOpened
()
const
CV_OVERRIDE
;
virtual
bool
isOpened
()
const
CV_OVERRIDE
{
return
(
bool
)
pipeline
;
}
virtual
int
getCaptureDomain
()
CV_OVERRIDE
{
return
cv
::
CAP_GSTREAMER
;
}
virtual
int
getCaptureDomain
()
CV_OVERRIDE
{
return
cv
::
CAP_GSTREAMER
;
}
bool
open
(
int
id
);
bool
open
(
int
id
);
bool
open
(
const
String
&
filename_
);
bool
open
(
const
String
&
filename_
);
static
void
newPad
(
GstElement
*
/*elem*/
,
GstPad
*
pad
,
gpointer
data
);
static
void
newPad
(
GstElement
*
/*elem*/
,
GstPad
*
pad
,
gpointer
data
);
protected
:
protected
:
bool
determineFrameDims
(
Size
&
sz
);
bool
determineFrameDims
(
CV_OUT
Size
&
sz
,
CV_OUT
gint
&
channels
,
CV_OUT
bool
&
isOutputByteBuffer
);
bool
isPipelinePlaying
();
bool
isPipelinePlaying
();
void
startPipeline
();
void
startPipeline
();
void
stopPipeline
();
void
stopPipeline
();
...
@@ -191,21 +279,11 @@ protected:
...
@@ -191,21 +279,11 @@ protected:
void
removeFilter
(
const
char
*
filter
);
void
removeFilter
(
const
char
*
filter
);
};
};
/*!
* \brief CvCapture_GStreamer::init
* inits the class
*/
GStreamerCapture
::
GStreamerCapture
()
:
GStreamerCapture
::
GStreamerCapture
()
:
pipeline
(
NULL
),
v4l2src
(
NULL
),
sink
(
NULL
),
sample
(
NULL
),
duration
(
-
1
),
width
(
-
1
),
height
(
-
1
),
fps
(
-
1
),
#if GST_VERSION_MAJOR == 0
buffer
(
NULL
),
#endif
caps
(
NULL
),
duration
(
-
1
),
width
(
-
1
),
height
(
-
1
),
channels
(
0
),
fps
(
-
1
),
isPosFramesSupported
(
false
),
isPosFramesSupported
(
false
),
isPosFramesEmulated
(
false
),
isPosFramesEmulated
(
false
),
emulatedFrameNumber
(
-
1
),
emulatedFrameNumber
(
-
1
)
isOutputByteBuffer
(
false
)
{
{
}
}
...
@@ -217,10 +295,10 @@ GStreamerCapture::~GStreamerCapture()
...
@@ -217,10 +295,10 @@ GStreamerCapture::~GStreamerCapture()
{
{
if
(
isPipelinePlaying
())
if
(
isPipelinePlaying
())
stopPipeline
();
stopPipeline
();
if
(
pipeline
&&
GST_IS_ELEMENT
(
pipeline
))
if
(
pipeline
&&
GST_IS_ELEMENT
(
pipeline
.
get
()
))
{
{
gst_element_set_state
(
GST_ELEMENT
(
pipeline
)
,
GST_STATE_NULL
);
gst_element_set_state
(
pipeline
,
GST_STATE_NULL
);
gst_object_unref
(
GST_OBJECT
(
pipeline
)
);
pipeline
.
release
(
);
}
}
}
}
...
@@ -232,21 +310,19 @@ GStreamerCapture::~GStreamerCapture()
...
@@ -232,21 +310,19 @@ GStreamerCapture::~GStreamerCapture()
*/
*/
bool
GStreamerCapture
::
grabFrame
()
bool
GStreamerCapture
::
grabFrame
()
{
{
if
(
!
GST_IS_ELEMENT
(
pipeline
))
if
(
!
pipeline
||
!
GST_IS_ELEMENT
(
pipeline
.
get
()
))
return
false
;
return
false
;
// start the pipeline if it was not in playing state yet
// start the pipeline if it was not in playing state yet
if
(
!
this
->
isPipelinePlaying
())
if
(
!
this
->
isPipelinePlaying
())
this
->
startPipeline
();
this
->
startPipeline
();
// bail out if EOS
// bail out if EOS
if
(
gst_app_sink_is_eos
(
GST_APP_SINK
(
sink
)))
if
(
gst_app_sink_is_eos
(
GST_APP_SINK
(
sink
.
get
()
)))
return
false
;
return
false
;
if
(
sample
)
sample
.
attach
(
gst_app_sink_pull_sample
(
GST_APP_SINK
(
sink
.
get
())));
gst_sample_unref
(
sample
);
if
(
!
sample
)
sample
=
gst_app_sink_pull_sample
(
GST_APP_SINK
(
sink
));
if
(
!
sample
)
return
false
;
return
false
;
if
(
isPosFramesEmulated
)
if
(
isPosFramesEmulated
)
...
@@ -262,25 +338,28 @@ bool GStreamerCapture::grabFrame()
...
@@ -262,25 +338,28 @@ bool GStreamerCapture::grabFrame()
*/
*/
bool
GStreamerCapture
::
retrieveFrame
(
int
,
OutputArray
dst
)
bool
GStreamerCapture
::
retrieveFrame
(
int
,
OutputArray
dst
)
{
{
if
(
!
sample
)
if
(
!
sample
)
return
false
;
return
false
;
Size
sz
;
Size
sz
;
if
(
!
determineFrameDims
(
sz
))
gint
channels
=
0
;
bool
isOutputByteBuffer
=
false
;
if
(
!
determineFrameDims
(
sz
,
channels
,
isOutputByteBuffer
))
return
false
;
return
false
;
// gstreamer expects us to handle the memory at this point
// gstreamer expects us to handle the memory at this point
// so we can just wrap the raw buffer and be done with it
// so we can just wrap the raw buffer and be done with it
GstBuffer
*
buf
=
gst_sample_get_buffer
(
sample
);
GstBuffer
*
buf
=
gst_sample_get_buffer
(
sample
);
// no lifetime transfer
if
(
!
buf
)
if
(
!
buf
)
return
false
;
return
false
;
GstMapInfo
info
;
GstMapInfo
info
=
{}
;
if
(
!
gst_buffer_map
(
buf
,
&
info
,
GST_MAP_READ
))
if
(
!
gst_buffer_map
(
buf
,
&
info
,
GST_MAP_READ
))
{
{
//something weird went wrong here. abort. abort.
//something weird went wrong here. abort. abort.
CV_WARN
(
"Failed to map GStreamerbuffer to system memory"
);
CV_WARN
(
"Failed to map GStreamer
buffer to system memory"
);
return
false
;
return
false
;
}
}
try
{
{
Mat
src
;
Mat
src
;
if
(
isOutputByteBuffer
)
if
(
isOutputByteBuffer
)
...
@@ -290,31 +369,40 @@ bool GStreamerCapture::retrieveFrame(int, OutputArray dst)
...
@@ -290,31 +369,40 @@ bool GStreamerCapture::retrieveFrame(int, OutputArray dst)
CV_Assert
(
src
.
isContinuous
());
CV_Assert
(
src
.
isContinuous
());
src
.
copyTo
(
dst
);
src
.
copyTo
(
dst
);
}
}
catch
(...)
{
gst_buffer_unmap
(
buf
,
&
info
);
throw
;
}
gst_buffer_unmap
(
buf
,
&
info
);
gst_buffer_unmap
(
buf
,
&
info
);
return
true
;
return
true
;
}
}
bool
GStreamerCapture
::
determineFrameDims
(
Size
&
sz
)
bool
GStreamerCapture
::
determineFrameDims
(
Size
&
sz
,
gint
&
channels
,
bool
&
isOutputByteBuffer
)
{
{
GstCaps
*
frame_caps
=
gst_sample_get_caps
(
sample
);
GstCaps
*
frame_caps
=
gst_sample_get_caps
(
sample
);
// no lifetime transfer
// bail out in no caps
// bail out in no caps
if
(
!
GST_CAPS_IS_SIMPLE
(
frame_caps
))
if
(
!
GST_CAPS_IS_SIMPLE
(
frame_caps
))
return
false
;
return
false
;
GstStructure
*
structure
=
gst_caps_get_structure
(
frame_caps
,
0
);
GstStructure
*
structure
=
gst_caps_get_structure
(
frame_caps
,
0
);
// no lifetime transfer
// bail out if width or height are 0
// bail out if width or height are 0
if
(
!
gst_structure_get_int
(
structure
,
"width"
,
&
width
)
if
(
!
gst_structure_get_int
(
structure
,
"width"
,
&
width
)
||
!
gst_structure_get_int
(
structure
,
"height"
,
&
height
))
||
!
gst_structure_get_int
(
structure
,
"height"
,
&
height
))
{
CV_WARN
(
"Can't query frame size from GStreeamer buffer"
);
return
false
;
return
false
;
}
sz
=
Size
(
width
,
height
);
sz
=
Size
(
width
,
height
);
const
gchar
*
name
=
gst_structure_get_name
(
structure
);
const
gchar
*
name_
=
gst_structure_get_name
(
structure
);
if
(
!
name_
)
if
(
!
name
)
return
false
;
return
false
;
std
::
string
name
=
toLowerCase
(
std
::
string
(
name_
));
// we support 11 types of data:
// we support 11 types of data:
// video/x-raw, format=BGR -> 8bit, 3 channels
// video/x-raw, format=BGR -> 8bit, 3 channels
...
@@ -330,49 +418,55 @@ bool GStreamerCapture::determineFrameDims(Size &sz)
...
@@ -330,49 +418,55 @@ bool GStreamerCapture::determineFrameDims(Size &sz)
// image/jpeg -> 8bit, mjpeg: buffer_size x 1 x 1
// image/jpeg -> 8bit, mjpeg: buffer_size x 1 x 1
// bayer data is never decoded, the user is responsible for that
// bayer data is never decoded, the user is responsible for that
// everything is 8 bit, so we just test the caps for bit depth
// everything is 8 bit, so we just test the caps for bit depth
if
(
strcasecmp
(
name
,
"video/x-raw"
)
==
0
)
if
(
name
==
"video/x-raw"
)
{
{
const
gchar
*
format
=
gst_structure_get_string
(
structure
,
"format"
);
const
gchar
*
format
_
=
gst_structure_get_string
(
structure
,
"format"
);
if
(
!
format
)
if
(
!
format
_
)
return
false
;
return
false
;
if
(
strcasecmp
(
format
,
"BGR"
)
==
0
)
std
::
string
format
=
toUpperCase
(
std
::
string
(
format_
));
if
(
format
==
"BGR"
)
{
{
channels
=
3
;
channels
=
3
;
}
}
else
if
(
(
strcasecmp
(
format
,
"UYVY"
)
==
0
)
||
(
strcasecmp
(
format
,
"YUY2"
)
==
0
)
||
(
strcasecmp
(
format
,
"YVYU"
)
==
0
)
)
else
if
(
format
==
"UYVY"
||
format
==
"YUY2"
||
format
==
"YVYU"
)
{
{
channels
=
2
;
channels
=
2
;
}
}
else
if
(
(
strcasecmp
(
format
,
"NV12"
)
==
0
)
||
(
strcasecmp
(
format
,
"NV21"
)
==
0
)
||
(
strcasecmp
(
format
,
"YV12"
)
==
0
)
||
(
strcasecmp
(
format
,
"I420"
)
==
0
)
)
else
if
(
format
==
"NV12"
||
format
==
"NV21"
||
format
==
"YV12"
||
format
==
"I420"
)
{
{
channels
=
1
;
channels
=
1
;
sz
.
height
=
sz
.
height
*
3
/
2
;
sz
.
height
=
sz
.
height
*
3
/
2
;
}
}
else
if
(
strcasecmp
(
format
,
"GRAY8"
)
==
0
)
else
if
(
format
==
"GRAY8"
)
{
{
channels
=
1
;
channels
=
1
;
}
}
else
{
CV_Error_
(
Error
::
StsNotImplemented
,
(
"Unsupported GStreamer format: %s"
,
format
.
c_str
()));
}
}
}
else
if
(
strcasecmp
(
name
,
"video/x-bayer"
)
==
0
)
else
if
(
name
==
"video/x-bayer"
)
{
{
channels
=
1
;
channels
=
1
;
}
}
else
if
(
strcasecmp
(
name
,
"image/jpeg"
)
==
0
)
else
if
(
name
==
"image/jpeg"
)
{
{
// the correct size will be set once the first frame arrives
// the correct size will be set once the first frame arrives
channels
=
1
;
channels
=
1
;
isOutputByteBuffer
=
true
;
isOutputByteBuffer
=
true
;
}
}
else
{
CV_Error_
(
Error
::
StsNotImplemented
,
(
"Unsupported GStreamer layer type: %s"
,
name
.
c_str
()));
}
return
true
;
return
true
;
}
}
/*!
* \brief CvCapture_GStreamer::isPipelinePlaying
* \return if the pipeline is currently playing.
*/
bool
GStreamerCapture
::
isPipelinePlaying
()
bool
GStreamerCapture
::
isPipelinePlaying
()
{
{
if
(
!
GST_IS_ELEMENT
(
pipeline
))
if
(
!
pipeline
||
!
GST_IS_ELEMENT
(
pipeline
.
get
()
))
{
{
CV_WARN
(
"GStreamer: pipeline have not been created"
);
CV_WARN
(
"GStreamer: pipeline have not been created"
);
return
false
;
return
false
;
...
@@ -382,7 +476,7 @@ bool GStreamerCapture::isPipelinePlaying()
...
@@ -382,7 +476,7 @@ bool GStreamerCapture::isPipelinePlaying()
GstStateChangeReturn
ret
=
gst_element_get_state
(
pipeline
,
&
current
,
&
pending
,
timeout
);
GstStateChangeReturn
ret
=
gst_element_get_state
(
pipeline
,
&
current
,
&
pending
,
timeout
);
if
(
!
ret
)
if
(
!
ret
)
{
{
CV_WARN
(
"
GStreamer:
unable to query pipeline state"
);
CV_WARN
(
"unable to query pipeline state"
);
return
false
;
return
false
;
}
}
return
current
==
GST_STATE_PLAYING
;
return
current
==
GST_STATE_PLAYING
;
...
@@ -394,7 +488,7 @@ bool GStreamerCapture::isPipelinePlaying()
...
@@ -394,7 +488,7 @@ bool GStreamerCapture::isPipelinePlaying()
*/
*/
void
GStreamerCapture
::
startPipeline
()
void
GStreamerCapture
::
startPipeline
()
{
{
if
(
!
GST_IS_ELEMENT
(
pipeline
))
if
(
!
pipeline
||
!
GST_IS_ELEMENT
(
pipeline
.
get
()
))
{
{
CV_WARN
(
"GStreamer: pipeline have not been created"
);
CV_WARN
(
"GStreamer: pipeline have not been created"
);
return
;
return
;
...
@@ -408,9 +502,8 @@ void GStreamerCapture::startPipeline()
...
@@ -408,9 +502,8 @@ void GStreamerCapture::startPipeline()
if
(
status
==
GST_STATE_CHANGE_FAILURE
)
if
(
status
==
GST_STATE_CHANGE_FAILURE
)
{
{
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
gst_object_unref
(
pipeline
);
pipeline
.
release
();
pipeline
=
NULL
;
CV_WARN
(
"unable to start pipeline"
);
CV_WARN
(
"GStreamer: unable to start pipeline"
);
return
;
return
;
}
}
...
@@ -420,22 +513,17 @@ void GStreamerCapture::startPipeline()
...
@@ -420,22 +513,17 @@ void GStreamerCapture::startPipeline()
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
}
}
/*!
* \brief CvCapture_GStreamer::stopPipeline
* Stop the pipeline by setting it to NULL
*/
void
GStreamerCapture
::
stopPipeline
()
void
GStreamerCapture
::
stopPipeline
()
{
{
if
(
!
GST_IS_ELEMENT
(
pipeline
))
if
(
!
pipeline
||
!
GST_IS_ELEMENT
(
pipeline
.
get
()
))
{
{
CV_WARN
(
"GStreamer: pipeline have not been created"
);
CV_WARN
(
"GStreamer: pipeline have not been created"
);
return
;
return
;
}
}
if
(
gst_element_set_state
(
pipeline
,
GST_STATE_NULL
)
==
GST_STATE_CHANGE_FAILURE
)
if
(
gst_element_set_state
(
pipeline
,
GST_STATE_NULL
)
==
GST_STATE_CHANGE_FAILURE
)
{
{
CV_WARN
(
"GStreamer: unable to stop pipeline"
);
CV_WARN
(
"unable to stop pipeline"
);
gst_object_unref
(
pipeline
);
pipeline
.
release
();
pipeline
=
NULL
;
}
}
}
}
...
@@ -461,31 +549,35 @@ void GStreamerCapture::restartPipeline()
...
@@ -461,31 +549,35 @@ void GStreamerCapture::restartPipeline()
*/
*/
void
GStreamerCapture
::
setFilter
(
const
char
*
prop
,
int
type
,
int
v1
,
int
v2
)
void
GStreamerCapture
::
setFilter
(
const
char
*
prop
,
int
type
,
int
v1
,
int
v2
)
{
{
if
(
!
caps
||
!
(
GST_IS_CAPS
(
caps
)
))
if
(
!
caps
||
!
(
GST_IS_CAPS
(
caps
.
get
())
))
{
{
if
(
type
==
G_TYPE_INT
)
if
(
type
==
G_TYPE_INT
)
{
{
caps
=
gst_caps_new_simple
(
"video/x-raw"
,
"format"
,
G_TYPE_STRING
,
"BGR"
,
prop
,
type
,
v1
,
NULL
);
caps
.
attach
(
gst_caps_new_simple
(
"video/x-raw"
,
"format"
,
G_TYPE_STRING
,
"BGR"
,
prop
,
type
,
v1
,
NULL
)
);
}
}
else
else
{
{
caps
=
gst_caps_new_simple
(
"video/x-raw"
,
"format"
,
G_TYPE_STRING
,
"BGR"
,
prop
,
type
,
v1
,
v2
,
NULL
);
caps
.
attach
(
gst_caps_new_simple
(
"video/x-raw"
,
"format"
,
G_TYPE_STRING
,
"BGR"
,
prop
,
type
,
v1
,
v2
,
NULL
)
);
}
}
}
}
else
else
{
{
if
(
!
gst_caps_is_writable
(
caps
))
if
(
!
gst_caps_is_writable
(
caps
.
get
()))
caps
=
gst_caps_make_writable
(
caps
);
caps
.
attach
(
gst_caps_make_writable
(
caps
.
detach
()));
if
(
type
==
G_TYPE_INT
){
if
(
type
==
G_TYPE_INT
)
{
gst_caps_set_simple
(
caps
,
prop
,
type
,
v1
,
NULL
);
gst_caps_set_simple
(
caps
,
prop
,
type
,
v1
,
NULL
);
}
else
{
}
else
{
gst_caps_set_simple
(
caps
,
prop
,
type
,
v1
,
v2
,
NULL
);
gst_caps_set_simple
(
caps
,
prop
,
type
,
v1
,
v2
,
NULL
);
}
}
}
}
caps
=
gst_caps_fixate
(
caps
);
caps
.
attach
(
gst_caps_fixate
(
caps
.
detach
())
);
gst_app_sink_set_caps
(
GST_APP_SINK
(
sink
),
caps
);
gst_app_sink_set_caps
(
GST_APP_SINK
(
sink
.
get
()),
caps
);
GST_LOG
(
"filtering with caps: %"
GST_PTR_FORMAT
,
caps
.
get
());
}
}
/*!
/*!
...
@@ -498,13 +590,15 @@ void GStreamerCapture::removeFilter(const char *filter)
...
@@ -498,13 +590,15 @@ void GStreamerCapture::removeFilter(const char *filter)
if
(
!
caps
)
if
(
!
caps
)
return
;
return
;
if
(
!
gst_caps_is_writable
(
caps
))
if
(
!
gst_caps_is_writable
(
caps
.
get
()
))
caps
=
gst_caps_make_writable
(
caps
);
caps
.
attach
(
gst_caps_make_writable
(
caps
.
detach
())
);
GstStructure
*
s
=
gst_caps_get_structure
(
caps
,
0
);
GstStructure
*
s
=
gst_caps_get_structure
(
caps
,
0
);
// no lifetime transfer
gst_structure_remove_field
(
s
,
filter
);
gst_structure_remove_field
(
s
,
filter
);
gst_app_sink_set_caps
(
GST_APP_SINK
(
sink
),
caps
);
caps
.
attach
(
gst_caps_fixate
(
caps
.
detach
()));
gst_app_sink_set_caps
(
GST_APP_SINK
(
sink
.
get
()),
caps
);
}
}
/*!
/*!
...
@@ -516,30 +610,24 @@ void GStreamerCapture::removeFilter(const char *filter)
...
@@ -516,30 +610,24 @@ void GStreamerCapture::removeFilter(const char *filter)
*/
*/
void
GStreamerCapture
::
newPad
(
GstElement
*
,
GstPad
*
pad
,
gpointer
data
)
void
GStreamerCapture
::
newPad
(
GstElement
*
,
GstPad
*
pad
,
gpointer
data
)
{
{
G
stPad
*
sinkpad
;
G
SafePtr
<
GstPad
>
sinkpad
;
GstElement
*
color
=
(
GstElement
*
)
data
;
GstElement
*
color
=
(
GstElement
*
)
data
;
sinkpad
=
gst_element_get_static_pad
(
color
,
"sink"
);
sinkpad
.
attach
(
gst_element_get_static_pad
(
color
,
"sink"
));
if
(
!
sinkpad
){
if
(
!
sinkpad
)
{
CV_WARN
(
"no pad named sink"
);
return
;
return
;
}
}
gst_pad_link
(
pad
,
sinkpad
);
gst_pad_link
(
pad
,
sinkpad
.
get
());
gst_object_unref
(
sinkpad
);
}
bool
GStreamerCapture
::
isOpened
()
const
{
return
pipeline
!=
NULL
;
}
}
/*!
/*!
* \brief CvCapture_GStreamer::open Open the given file with gstreamer
* \brief Create GStreamer pipeline
* \param type CvCapture type. One of CV_CAP_GSTREAMER_*
* \param filename Filename to open in case of CV_CAP_GSTREAMER_FILE
* \param filename Filename to open in case of CV_CAP_GSTREAMER_FILE
* \return boolean. Specifies if opening was successful.
* \return boolean. Specifies if opening was successful.
*
*
* In case of
CV_CAP_GSTREAMER_V4L(2), a pipelin
is constructed as follows:
* In case of
camera 'index', a pipeline
is constructed as follows:
* v4l2src ! autoconvert ! appsink
* v4l2src ! autoconvert ! appsink
*
*
*
*
...
@@ -553,16 +641,12 @@ bool GStreamerCapture::isOpened() const
...
@@ -553,16 +641,12 @@ bool GStreamerCapture::isOpened() const
* e.g. videotestsrc ! videoconvert ! appsink
* e.g. videotestsrc ! videoconvert ! appsink
* the appsink name should be either 'appsink0' (the default) or 'opencvsink'
* the appsink name should be either 'appsink0' (the default) or 'opencvsink'
*
*
* When dealing with a file, CvCapture_GStreamer will not drop frames if the grabbing interval
* GStreamer will not drop frames if the grabbing interval larger than the framerate period.
* larger than the framerate period. (Unlike the uri or manual pipeline description, which assume
* To support dropping for live streams add appsink 'drop' parameter into your custom pipeline.
* a live source)
*
*
* The pipeline will only be started whenever the first frame is grabbed. Setting pipeline properties
* The pipeline will only be started whenever the first frame is grabbed. Setting pipeline properties
* is really slow if we need to restart the pipeline over and over again.
* is really slow if we need to restart the pipeline over and over again.
*
*
* TODO: the 'type' parameter is imo unneeded. for v4l2, filename 'v4l2:///dev/video0' can be used.
* I expect this to be the same for CV_CAP_GSTREAMER_1394. Is anyone actually still using v4l (v1)?
*
*/
*/
bool
GStreamerCapture
::
open
(
int
id
)
bool
GStreamerCapture
::
open
(
int
id
)
{
{
...
@@ -573,7 +657,7 @@ bool GStreamerCapture::open(int id)
...
@@ -573,7 +657,7 @@ bool GStreamerCapture::open(int id)
std
::
ostringstream
desc
;
std
::
ostringstream
desc
;
desc
<<
"v4l2src device=/dev/video"
<<
id
desc
<<
"v4l2src device=/dev/video"
<<
id
<<
" ! "
<<
COLOR_ELEM
<<
" ! "
<<
COLOR_ELEM
<<
" ! appsink"
;
<<
" ! appsink
drop=true
"
;
return
open
(
desc
.
str
());
return
open
(
desc
.
str
());
}
}
...
@@ -581,14 +665,13 @@ bool GStreamerCapture::open(const String &filename_)
...
@@ -581,14 +665,13 @@ bool GStreamerCapture::open(const String &filename_)
{
{
gst_initializer
::
init
();
gst_initializer
::
init
();
const
gchar
*
filename
=
filename_
.
c_str
();
const
gchar
*
filename
=
filename_
.
c_str
();
bool
file
=
false
;
bool
file
=
false
;
//bool stream = false;
bool
manualpipeline
=
false
;
bool
manualpipeline
=
false
;
char
*
uri
=
NULL
;
GSafePtr
<
char
>
uri
;
G
stElement
*
uridecodebin
=
NULL
;
G
SafePtr
<
GstElement
>
uridecodebin
;
G
stElement
*
color
=
NULL
;
G
SafePtr
<
GstElement
>
color
;
GstStateChangeReturn
status
;
GstStateChangeReturn
status
;
// test if we have a valid uri. If so, open it with an uridecodebin
// test if we have a valid uri. If so, open it with an uridecodebin
...
@@ -597,74 +680,60 @@ bool GStreamerCapture::open(const String &filename_)
...
@@ -597,74 +680,60 @@ bool GStreamerCapture::open(const String &filename_)
// ordinary file path.
// ordinary file path.
if
(
!
gst_uri_is_valid
(
filename
))
if
(
!
gst_uri_is_valid
(
filename
))
{
{
#ifdef _MSC_VER
if
(
utils
::
fs
::
exists
(
filename_
))
uri
=
new
char
[
2048
];
DWORD
pathSize
=
GetFullPathName
(
filename
,
2048
,
uri
,
NULL
);
struct
stat
buf
;
if
(
pathSize
==
0
||
stat
(
uri
,
&
buf
)
!=
0
)
{
delete
[]
uri
;
uri
=
NULL
;
}
#else
uri
=
realpath
(
filename
,
NULL
);
#endif
//stream = false;
if
(
uri
)
{
{
uri
=
g_filename_to_uri
(
uri
,
NULL
,
NULL
);
uri
.
attach
(
g_filename_to_uri
(
filename
,
NULL
,
NULL
)
);
if
(
uri
)
if
(
uri
)
{
{
file
=
true
;
file
=
true
;
}
}
else
else
{
{
CV_WARN
(
"GStreamer: Error opening file
\n
"
);
CV_WARN
(
"Error opening file: "
<<
filename
<<
" ("
<<
uri
.
get
()
<<
")"
);
CV_WARN
(
filename
);
CV_WARN
(
uri
);
return
false
;
return
false
;
}
}
}
}
else
else
{
{
G
Error
*
err
=
NULL
;
G
SafePtr
<
GError
>
err
;
uridecodebin
=
gst_parse_launch
(
filename
,
&
err
);
uridecodebin
.
attach
(
gst_parse_launch
(
filename
,
err
.
getRef
())
);
if
(
!
uridecodebin
)
if
(
err
)
{
{
CV_WARN
(
"
GStreamer:
Error opening bin: "
<<
err
->
message
);
CV_WARN
(
"Error opening bin: "
<<
err
->
message
);
return
false
;
return
false
;
}
}
//stream = true;
manualpipeline
=
true
;
manualpipeline
=
true
;
}
}
}
}
else
else
{
{
//stream = true;
uri
.
attach
(
g_strdup
(
filename
));
uri
=
g_strdup
(
filename
);
}
}
bool
element_from_uri
=
false
;
bool
element_from_uri
=
false
;
if
(
!
uridecodebin
)
if
(
!
uridecodebin
)
{
{
// At this writing, the v4l2 element (and maybe others too) does not support caps renegotiation.
// At this writing, the v4l2 element (and maybe others too) does not support caps renegotiation.
// This means that we cannot use an uridecodebin when dealing with v4l2, since setting
// This means that we cannot use an uridecodebin when dealing with v4l2, since setting
// capture properties will not work.
// capture properties will not work.
// The solution (probably only until gstreamer 1.2) is to make an element from uri when dealing with v4l2.
// The solution (probably only until gstreamer 1.2) is to make an element from uri when dealing with v4l2.
gchar
*
protocol
=
gst_uri_get_protocol
(
uri
);
GSafePtr
<
gchar
>
protocol_
;
protocol_
.
attach
(
gst_uri_get_protocol
(
uri
));
if
(
!
strcasecmp
(
protocol
,
"v4l2"
))
CV_Assert
(
protocol_
);
std
::
string
protocol
=
toLowerCase
(
std
::
string
(
protocol_
.
get
()));
if
(
protocol
==
"v4l2"
)
{
{
uridecodebin
=
gst_element_make_from_uri
(
GST_URI_SRC
,
uri
,
"src"
,
NULL
);
uridecodebin
.
reset
(
gst_element_make_from_uri
(
GST_URI_SRC
,
uri
.
get
(),
"src"
,
NULL
));
CV_Assert
(
uridecodebin
);
element_from_uri
=
true
;
element_from_uri
=
true
;
}
}
else
else
{
{
uridecodebin
=
gst_element_factory_make
(
"uridecodebin"
,
NULL
);
uridecodebin
.
reset
(
gst_element_factory_make
(
"uridecodebin"
,
NULL
));
g_object_set
(
G_OBJECT
(
uridecodebin
),
"uri"
,
uri
,
NULL
);
CV_Assert
(
uridecodebin
);
g_object_set
(
G_OBJECT
(
uridecodebin
.
get
()),
"uri"
,
uri
.
get
(),
NULL
);
}
}
g_free
(
protocol
);
if
(
!
uridecodebin
)
if
(
!
uridecodebin
)
{
{
CV_WARN
(
"Can not parse GStreamer URI bin"
);
CV_WARN
(
"Can not parse GStreamer URI bin"
);
return
false
;
return
false
;
...
@@ -673,40 +742,39 @@ bool GStreamerCapture::open(const String &filename_)
...
@@ -673,40 +742,39 @@ bool GStreamerCapture::open(const String &filename_)
if
(
manualpipeline
)
if
(
manualpipeline
)
{
{
GstIterator
*
it
=
gst_bin_iterate_elements
(
GST_BIN
(
uridecodebin
));
GstIterator
*
it
=
gst_bin_iterate_elements
(
GST_BIN
(
uridecodebin
.
get
()
));
GstElement
*
element
=
NULL
;
gboolean
done
=
false
;
gboolean
done
=
false
;
gchar
*
name
=
NULL
;
GValue
value
=
G_VALUE_INIT
;
GValue
value
=
G_VALUE_INIT
;
while
(
!
done
)
while
(
!
done
)
{
{
GstElement
*
element
=
NULL
;
GSafePtr
<
gchar
>
name
;
switch
(
gst_iterator_next
(
it
,
&
value
))
switch
(
gst_iterator_next
(
it
,
&
value
))
{
{
case
GST_ITERATOR_OK
:
case
GST_ITERATOR_OK
:
element
=
GST_ELEMENT
(
g_value_get_object
(
&
value
));
element
=
GST_ELEMENT
(
g_value_get_object
(
&
value
));
name
=
gst_element_get_name
(
element
);
name
.
attach
(
gst_element_get_name
(
element
)
);
if
(
name
)
if
(
name
)
{
{
if
(
strstr
(
name
,
"opencvsink"
)
!=
NULL
||
strstr
(
name
,
"appsink"
)
!=
NULL
)
if
(
strstr
(
name
,
"opencvsink"
)
!=
NULL
||
strstr
(
name
,
"appsink"
)
!=
NULL
)
{
{
sink
=
GST_ELEMENT
(
gst_object_ref
(
element
)
);
sink
.
attach
(
GST_ELEMENT
(
gst_object_ref
(
element
))
);
}
}
else
if
(
strstr
(
name
,
COLOR_ELEM_NAME
)
!=
NULL
)
else
if
(
strstr
(
name
,
COLOR_ELEM_NAME
)
!=
NULL
)
{
{
color
=
GST_ELEMENT
(
gst_object_ref
(
element
)
);
color
.
attach
(
GST_ELEMENT
(
gst_object_ref
(
element
))
);
}
}
else
if
(
strstr
(
name
,
"v4l"
)
!=
NULL
)
else
if
(
strstr
(
name
,
"v4l"
)
!=
NULL
)
{
{
v4l2src
=
GST_ELEMENT
(
gst_object_ref
(
element
)
);
v4l2src
.
attach
(
GST_ELEMENT
(
gst_object_ref
(
element
))
);
}
}
g_free
(
name
);
name
.
release
(
);
done
=
sink
&&
color
&&
v4l2src
;
done
=
sink
&&
color
&&
v4l2src
;
}
}
g_value_unset
(
&
value
);
g_value_unset
(
&
value
);
break
;
break
;
case
GST_ITERATOR_RESYNC
:
case
GST_ITERATOR_RESYNC
:
gst_iterator_resync
(
it
);
gst_iterator_resync
(
it
);
...
@@ -721,73 +789,80 @@ bool GStreamerCapture::open(const String &filename_)
...
@@ -721,73 +789,80 @@ bool GStreamerCapture::open(const String &filename_)
if
(
!
sink
)
if
(
!
sink
)
{
{
CV_WARN
(
"
GStreamer: cannot find appsink in manual pipeline
\n
"
);
CV_WARN
(
"
cannot find appsink in manual pipeline
"
);
return
false
;
return
false
;
}
}
pipeline
=
uridecodebin
;
pipeline
.
swap
(
uridecodebin
)
;
}
}
else
else
{
{
pipeline
=
gst_pipeline_new
(
NULL
);
pipeline
.
reset
(
gst_pipeline_new
(
NULL
));
CV_Assert
(
pipeline
);
// videoconvert (in 0.10: ffmpegcolorspace, in 1.x autovideoconvert)
// videoconvert (in 0.10: ffmpegcolorspace, in 1.x autovideoconvert)
//automatically selects the correct colorspace conversion based on caps.
//automatically selects the correct colorspace conversion based on caps.
color
=
gst_element_factory_make
(
COLOR_ELEM
,
NULL
);
color
.
reset
(
gst_element_factory_make
(
COLOR_ELEM
,
NULL
));
sink
=
gst_element_factory_make
(
"appsink"
,
NULL
);
CV_Assert
(
color
);
sink
.
reset
(
gst_element_factory_make
(
"appsink"
,
NULL
));
CV_Assert
(
sink
);
gst_bin_add_many
(
GST_BIN
(
pipeline
),
uridecodebin
,
color
,
sink
,
NULL
);
gst_bin_add_many
(
GST_BIN
(
pipeline
.
get
()),
uridecodebin
.
get
(),
color
.
get
(),
sink
.
get
()
,
NULL
);
if
(
element_from_uri
)
if
(
element_from_uri
)
{
{
if
(
!
gst_element_link
(
uridecodebin
,
color
))
if
(
!
gst_element_link
(
uridecodebin
,
color
.
get
()
))
{
{
CV_WARN
(
"cannot link color -> sink"
);
CV_WARN
(
"cannot link color -> sink"
);
gst_object_unref
(
pipeline
);
pipeline
.
release
();
pipeline
=
NULL
;
return
false
;
return
false
;
}
}
}
}
else
else
{
{
g_signal_connect
(
uridecodebin
,
"pad-added"
,
G_CALLBACK
(
newPad
),
color
);
g_signal_connect
(
uridecodebin
,
"pad-added"
,
G_CALLBACK
(
newPad
),
color
.
get
()
);
}
}
if
(
!
gst_element_link
(
color
,
sink
))
if
(
!
gst_element_link
(
color
.
get
(),
sink
.
get
()
))
{
{
CV_WARN
(
"GStreamer: cannot link color -> sink
\n
"
);
CV_WARN
(
"GStreamer: cannot link color -> sink"
);
gst_object_unref
(
pipeline
);
pipeline
.
release
();
pipeline
=
NULL
;
return
false
;
return
false
;
}
}
}
}
if
(
!
manualpipeline
||
strstr
(
filename
,
" max-buffers="
)
==
NULL
)
{
//TODO: is 1 single buffer really high enough?
//TODO: is 1 single buffer really high enough?
gst_app_sink_set_max_buffers
(
GST_APP_SINK
(
sink
),
1
);
gst_app_sink_set_max_buffers
(
GST_APP_SINK
(
sink
.
get
()),
1
);
// gst_app_sink_set_drop (GST_APP_SINK(sink), stream);
}
//do not emit signals: all calls will be synchronous and blocking
//do not emit signals: all calls will be synchronous and blocking
gst_app_sink_set_emit_signals
(
GST_APP_SINK
(
sink
),
FALSE
);
gst_app_sink_set_emit_signals
(
GST_APP_SINK
(
sink
.
get
()
),
FALSE
);
// gst_base_sink_set_sync(GST_BASE_SINK(sink), FALSE);
caps
=
gst_caps_from_string
(
"video/x-raw, format=(string){BGR, GRAY8}; video/x-bayer,format=(string){rggb,bggr,grbg,gbrg}; image/jpeg"
);
caps
.
attach
(
gst_caps_from_string
(
"video/x-raw, format=(string){BGR, GRAY8}; video/x-bayer,format=(string){rggb,bggr,grbg,gbrg}; image/jpeg"
)
);
if
(
manualpipeline
){
if
(
manualpipeline
)
GstPad
*
sink_pad
=
gst_element_get_static_pad
(
sink
,
"sink"
);
{
GstCaps
*
peer_caps
=
gst_pad_peer_query_caps
(
sink_pad
,
NULL
);
GSafePtr
<
GstCaps
>
peer_caps
;
GSafePtr
<
GstPad
>
sink_pad
;
sink_pad
.
attach
(
gst_element_get_static_pad
(
sink
,
"sink"
));
peer_caps
.
attach
(
gst_pad_peer_query_caps
(
sink_pad
,
NULL
));
if
(
!
gst_caps_can_intersect
(
caps
,
peer_caps
))
{
if
(
!
gst_caps_can_intersect
(
caps
,
peer_caps
))
{
gst_caps_unref
(
caps
);
caps
.
attach
(
gst_caps_from_string
(
"video/x-raw, format=(string){UYVY,YUY2,YVYU,NV12,NV21,YV12,I420}"
)
);
caps
=
gst_caps_from_string
(
"video/x-raw, format=(string){UYVY,YUY2,YVYU,NV12,NV21,YV12,I420}"
);
CV_Assert
(
caps
);
}
}
gst_object_unref
(
sink_pad
);
gst_caps_unref
(
peer_caps
);
}
}
gst_app_sink_set_caps
(
GST_APP_SINK
(
sink
),
caps
);
gst_app_sink_set_caps
(
GST_APP_SINK
(
sink
.
get
()
),
caps
);
gst_caps_unref
(
caps
);
caps
.
release
(
);
{
{
GST_DEBUG_BIN_TO_DOT_FILE
(
GST_BIN
(
pipeline
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"pipeline-init"
);
GST_DEBUG_BIN_TO_DOT_FILE
(
GST_BIN
(
pipeline
.
get
()
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"pipeline-init"
);
status
=
gst_element_set_state
(
GST_ELEMENT
(
pipeline
),
status
=
gst_element_set_state
(
GST_ELEMENT
(
pipeline
.
get
()
),
file
?
GST_STATE_PAUSED
:
GST_STATE_PLAYING
);
file
?
GST_STATE_PAUSED
:
GST_STATE_PLAYING
);
if
(
status
==
GST_STATE_CHANGE_ASYNC
)
if
(
status
==
GST_STATE_CHANGE_ASYNC
)
{
{
...
@@ -796,11 +871,10 @@ bool GStreamerCapture::open(const String &filename_)
...
@@ -796,11 +871,10 @@ bool GStreamerCapture::open(const String &filename_)
}
}
if
(
status
==
GST_STATE_CHANGE_FAILURE
)
if
(
status
==
GST_STATE_CHANGE_FAILURE
)
{
{
GST_DEBUG_BIN_TO_DOT_FILE
(
GST_BIN
(
pipeline
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"pipeline-error"
);
GST_DEBUG_BIN_TO_DOT_FILE
(
GST_BIN
(
pipeline
.
get
()
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"pipeline-error"
);
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
gst_object_unref
(
pipeline
);
pipeline
.
release
();
pipeline
=
NULL
;
CV_WARN
(
"unable to start pipeline"
);
CV_WARN
(
"GStreamer: unable to start pipeline
\n
"
);
return
false
;
return
false
;
}
}
...
@@ -810,30 +884,29 @@ bool GStreamerCapture::open(const String &filename_)
...
@@ -810,30 +884,29 @@ bool GStreamerCapture::open(const String &filename_)
if
(
!
gst_element_query_duration
(
sink
,
format
,
&
duration
))
if
(
!
gst_element_query_duration
(
sink
,
format
,
&
duration
))
{
{
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
CV_WARN
(
"
GStreamer:
unable to query duration of stream"
);
CV_WARN
(
"unable to query duration of stream"
);
duration
=
-
1
;
duration
=
-
1
;
}
}
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
GstPad
*
pad
=
gst_element_get_static_pad
(
sink
,
"sink"
);
GSafePtr
<
GstPad
>
pad
;
GstCaps
*
buffer_caps
=
gst_pad_get_current_caps
(
pad
);
pad
.
attach
(
gst_element_get_static_pad
(
sink
,
"sink"
));
const
GstStructure
*
structure
=
gst_caps_get_structure
(
buffer_caps
,
0
);
if
(
!
gst_structure_get_int
(
structure
,
"width"
,
&
width
))
GSafePtr
<
GstCaps
>
buffer_caps
;
{
buffer_caps
.
attach
(
gst_pad_get_current_caps
(
pad
));
CV_WARN
(
"Cannot query video width
\n
"
);
}
if
(
!
gst_structure_get_int
(
structure
,
"height"
,
&
height
))
const
GstStructure
*
structure
=
gst_caps_get_structure
(
buffer_caps
,
0
);
// no lifetime transfer
if
(
!
gst_structure_get_int
(
structure
,
"width"
,
&
width
)
||
!
gst_structure_get_int
(
structure
,
"height"
,
&
height
))
{
{
CV_WARN
(
"
Cannot query video height
\n
"
);
CV_WARN
(
"
cannot query video width/height
"
);
}
}
gint
num
=
0
,
denom
=
1
;
gint
num
=
0
,
denom
=
1
;
if
(
!
gst_structure_get_fraction
(
structure
,
"framerate"
,
&
num
,
&
denom
))
if
(
!
gst_structure_get_fraction
(
structure
,
"framerate"
,
&
num
,
&
denom
))
{
{
CV_WARN
(
"
Cannot query video fps
\n
"
);
CV_WARN
(
"
cannot query video fps
"
);
}
}
fps
=
(
double
)
num
/
(
double
)
denom
;
fps
=
(
double
)
num
/
(
double
)
denom
;
...
@@ -845,7 +918,7 @@ bool GStreamerCapture::open(const String &filename_)
...
@@ -845,7 +918,7 @@ bool GStreamerCapture::open(const String &filename_)
format_
=
GST_FORMAT_DEFAULT
;
format_
=
GST_FORMAT_DEFAULT
;
status_
=
gst_element_query_position
(
sink
,
format_
,
&
value_
);
status_
=
gst_element_query_position
(
sink
,
CV_GST_FORMAT
(
format_
)
,
&
value_
);
if
(
!
status_
||
value_
!=
0
||
duration
<
0
)
if
(
!
status_
||
value_
!=
0
||
duration
<
0
)
{
{
CV_WARN
(
"Cannot query video position: status="
<<
status_
<<
", value="
<<
value_
<<
", duration="
<<
duration
);
CV_WARN
(
"Cannot query video position: status="
<<
status_
<<
", value="
<<
value_
<<
", duration="
<<
duration
);
...
@@ -857,7 +930,7 @@ bool GStreamerCapture::open(const String &filename_)
...
@@ -857,7 +930,7 @@ bool GStreamerCapture::open(const String &filename_)
isPosFramesSupported
=
true
;
isPosFramesSupported
=
true
;
}
}
GST_DEBUG_BIN_TO_DOT_FILE
(
GST_BIN
(
pipeline
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"pipeline"
);
GST_DEBUG_BIN_TO_DOT_FILE
(
GST_BIN
(
pipeline
.
get
()
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"pipeline"
);
}
}
return
true
;
return
true
;
...
@@ -883,10 +956,11 @@ double GStreamerCapture::getProperty(int propId) const
...
@@ -883,10 +956,11 @@ double GStreamerCapture::getProperty(int propId) const
return
0
;
return
0
;
}
}
switch
(
propId
)
{
switch
(
propId
)
{
case
CV_CAP_PROP_POS_MSEC
:
case
CV_CAP_PROP_POS_MSEC
:
format
=
GST_FORMAT_TIME
;
format
=
GST_FORMAT_TIME
;
status
=
gst_element_query_position
(
sink
,
format
,
&
value
);
status
=
gst_element_query_position
(
sink
.
get
(),
CV_GST_FORMAT
(
format
)
,
&
value
);
if
(
!
status
)
{
if
(
!
status
)
{
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
CV_WARN
(
"GStreamer: unable to query position of stream"
);
CV_WARN
(
"GStreamer: unable to query position of stream"
);
...
@@ -901,7 +975,7 @@ double GStreamerCapture::getProperty(int propId) const
...
@@ -901,7 +975,7 @@ double GStreamerCapture::getProperty(int propId) const
return
0
;
// TODO getProperty() "unsupported" value should be changed
return
0
;
// TODO getProperty() "unsupported" value should be changed
}
}
format
=
GST_FORMAT_DEFAULT
;
format
=
GST_FORMAT_DEFAULT
;
status
=
gst_element_query_position
(
sink
,
format
,
&
value
);
status
=
gst_element_query_position
(
sink
.
get
(),
CV_GST_FORMAT
(
format
)
,
&
value
);
if
(
!
status
)
{
if
(
!
status
)
{
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
CV_WARN
(
"GStreamer: unable to query position of stream"
);
CV_WARN
(
"GStreamer: unable to query position of stream"
);
...
@@ -910,7 +984,7 @@ double GStreamerCapture::getProperty(int propId) const
...
@@ -910,7 +984,7 @@ double GStreamerCapture::getProperty(int propId) const
return
value
;
return
value
;
case
CV_CAP_PROP_POS_AVI_RATIO
:
case
CV_CAP_PROP_POS_AVI_RATIO
:
format
=
GST_FORMAT_PERCENT
;
format
=
GST_FORMAT_PERCENT
;
status
=
gst_element_query_position
(
sink
,
format
,
&
value
);
status
=
gst_element_query_position
(
sink
.
get
(),
CV_GST_FORMAT
(
format
)
,
&
value
);
if
(
!
status
)
{
if
(
!
status
)
{
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
CV_WARN
(
"GStreamer: unable to query position of stream"
);
CV_WARN
(
"GStreamer: unable to query position of stream"
);
...
@@ -931,11 +1005,11 @@ double GStreamerCapture::getProperty(int propId) const
...
@@ -931,11 +1005,11 @@ double GStreamerCapture::getProperty(int propId) const
case
CV_CAP_PROP_HUE
:
case
CV_CAP_PROP_HUE
:
if
(
v4l2src
)
if
(
v4l2src
)
{
{
string
propName
=
get_gst_propname
(
propId
);
st
d
::
st
ring
propName
=
get_gst_propname
(
propId
);
if
(
!
propName
.
empty
())
if
(
!
propName
.
empty
())
{
{
gint32
val
=
0
;
gint32
val
=
0
;
g_object_get
(
G_OBJECT
(
v4l2src
),
propName
.
c_str
(),
&
val
,
NULL
);
g_object_get
(
G_OBJECT
(
v4l2src
.
get
()
),
propName
.
c_str
(),
&
val
,
NULL
);
return
static_cast
<
double
>
(
val
);
return
static_cast
<
double
>
(
val
);
}
}
}
}
...
@@ -946,9 +1020,9 @@ double GStreamerCapture::getProperty(int propId) const
...
@@ -946,9 +1020,9 @@ double GStreamerCapture::getProperty(int propId) const
CV_WARN
(
"there is no sink yet"
);
CV_WARN
(
"there is no sink yet"
);
return
0
;
return
0
;
}
}
return
gst_app_sink_get_max_buffers
(
GST_APP_SINK
(
sink
));
return
gst_app_sink_get_max_buffers
(
GST_APP_SINK
(
sink
.
get
()
));
default
:
default
:
CV_WARN
(
"
GStreamer: unhandled property"
);
CV_WARN
(
"
unhandled property: "
<<
propId
);
break
;
break
;
}
}
...
@@ -980,7 +1054,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
...
@@ -980,7 +1054,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
switch
(
propId
)
switch
(
propId
)
{
{
case
CV_CAP_PROP_POS_MSEC
:
case
CV_CAP_PROP_POS_MSEC
:
if
(
!
gst_element_seek_simple
(
GST_ELEMENT
(
pipeline
),
GST_FORMAT_TIME
,
if
(
!
gst_element_seek_simple
(
GST_ELEMENT
(
pipeline
.
get
()
),
GST_FORMAT_TIME
,
flags
,
(
gint64
)
(
value
*
GST_MSECOND
)))
{
flags
,
(
gint64
)
(
value
*
GST_MSECOND
)))
{
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
CV_WARN
(
"GStreamer: unable to seek"
);
CV_WARN
(
"GStreamer: unable to seek"
);
...
@@ -1017,7 +1091,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
...
@@ -1017,7 +1091,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
return
false
;
return
false
;
CV_WARN
(
"unable to seek"
);
CV_WARN
(
"unable to seek"
);
}
}
if
(
!
gst_element_seek_simple
(
GST_ELEMENT
(
pipeline
),
GST_FORMAT_DEFAULT
,
if
(
!
gst_element_seek_simple
(
GST_ELEMENT
(
pipeline
.
get
()
),
GST_FORMAT_DEFAULT
,
flags
,
(
gint64
)
value
))
{
flags
,
(
gint64
)
value
))
{
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
CV_WARN
(
"GStreamer: unable to seek"
);
CV_WARN
(
"GStreamer: unable to seek"
);
...
@@ -1028,7 +1102,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
...
@@ -1028,7 +1102,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
return
true
;
return
true
;
}
}
case
CV_CAP_PROP_POS_AVI_RATIO
:
case
CV_CAP_PROP_POS_AVI_RATIO
:
if
(
!
gst_element_seek_simple
(
GST_ELEMENT
(
pipeline
),
GST_FORMAT_PERCENT
,
if
(
!
gst_element_seek_simple
(
GST_ELEMENT
(
pipeline
.
get
()
),
GST_FORMAT_PERCENT
,
flags
,
(
gint64
)
(
value
*
GST_FORMAT_PERCENT_MAX
)))
{
flags
,
(
gint64
)
(
value
*
GST_FORMAT_PERCENT_MAX
)))
{
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
CV_WARN
(
"GStreamer: unable to seek"
);
CV_WARN
(
"GStreamer: unable to seek"
);
...
@@ -1063,7 +1137,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
...
@@ -1063,7 +1137,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
break
;
break
;
case
CV_CAP_PROP_FPS
:
case
CV_CAP_PROP_FPS
:
if
(
value
>
0
)
{
if
(
value
>
0
)
{
double
num
=
0
,
denom
=
1
;
int
num
=
0
,
denom
=
1
;
toFraction
(
value
,
num
,
denom
);
toFraction
(
value
,
num
,
denom
);
setFilter
(
"framerate"
,
GST_TYPE_FRACTION
,
value
,
denom
);
setFilter
(
"framerate"
,
GST_TYPE_FRACTION
,
value
,
denom
);
}
else
}
else
...
@@ -1075,11 +1149,11 @@ bool GStreamerCapture::setProperty(int propId, double value)
...
@@ -1075,11 +1149,11 @@ bool GStreamerCapture::setProperty(int propId, double value)
case
CV_CAP_PROP_HUE
:
case
CV_CAP_PROP_HUE
:
if
(
v4l2src
)
if
(
v4l2src
)
{
{
string
propName
=
get_gst_propname
(
propId
);
st
d
::
st
ring
propName
=
get_gst_propname
(
propId
);
if
(
!
propName
.
empty
())
if
(
!
propName
.
empty
())
{
{
gint32
val
=
cv
::
saturate_cast
<
gint32
>
(
value
);
gint32
val
=
cv
::
saturate_cast
<
gint32
>
(
value
);
g_object_set
(
G_OBJECT
(
v4l2src
),
propName
.
c_str
(),
&
val
,
NULL
);
g_object_set
(
G_OBJECT
(
v4l2src
.
get
()
),
propName
.
c_str
(),
&
val
,
NULL
);
return
true
;
return
true
;
}
}
}
}
...
@@ -1094,7 +1168,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
...
@@ -1094,7 +1168,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
CV_WARN
(
"there is no sink yet"
);
CV_WARN
(
"there is no sink yet"
);
return
false
;
return
false
;
}
}
gst_app_sink_set_max_buffers
(
GST_APP_SINK
(
sink
),
(
guint
)
value
);
gst_app_sink_set_max_buffers
(
GST_APP_SINK
(
sink
.
get
()
),
(
guint
)
value
);
return
true
;
return
true
;
}
}
default
:
default
:
...
@@ -1108,7 +1182,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
...
@@ -1108,7 +1182,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
}
}
Ptr
<
IVideoCapture
>
c
v
::
c
reateGStreamerCapture_file
(
const
String
&
filename
)
Ptr
<
IVideoCapture
>
createGStreamerCapture_file
(
const
String
&
filename
)
{
{
Ptr
<
GStreamerCapture
>
cap
=
makePtr
<
GStreamerCapture
>
();
Ptr
<
GStreamerCapture
>
cap
=
makePtr
<
GStreamerCapture
>
();
if
(
cap
&&
cap
->
open
(
filename
))
if
(
cap
&&
cap
->
open
(
filename
))
...
@@ -1116,7 +1190,7 @@ Ptr<IVideoCapture> cv::createGStreamerCapture_file(const String& filename)
...
@@ -1116,7 +1190,7 @@ Ptr<IVideoCapture> cv::createGStreamerCapture_file(const String& filename)
return
Ptr
<
IVideoCapture
>
();
return
Ptr
<
IVideoCapture
>
();
}
}
Ptr
<
IVideoCapture
>
c
v
::
c
reateGStreamerCapture_cam
(
int
index
)
Ptr
<
IVideoCapture
>
createGStreamerCapture_cam
(
int
index
)
{
{
Ptr
<
GStreamerCapture
>
cap
=
makePtr
<
GStreamerCapture
>
();
Ptr
<
GStreamerCapture
>
cap
=
makePtr
<
GStreamerCapture
>
();
if
(
cap
&&
cap
->
open
(
index
))
if
(
cap
&&
cap
->
open
(
index
))
...
@@ -1128,13 +1202,13 @@ Ptr<IVideoCapture> cv::createGStreamerCapture_cam(int index)
...
@@ -1128,13 +1202,13 @@ Ptr<IVideoCapture> cv::createGStreamerCapture_cam(int index)
/*!
/*!
* \brief The CvVideoWriter_GStreamer class
* \brief The CvVideoWriter_GStreamer class
* Use G
s
treamer to write video
* Use G
S
treamer to write video
*/
*/
class
CvVideoWriter_GStreamer
:
public
CvVideoWriter
class
CvVideoWriter_GStreamer
:
public
CvVideoWriter
{
{
public
:
public
:
CvVideoWriter_GStreamer
()
CvVideoWriter_GStreamer
()
:
pipeline
(
0
),
source
(
0
),
encodebin
(
0
),
file
(
0
),
buffer
(
0
),
input_pix_fmt
(
0
),
:
input_pix_fmt
(
0
),
num_frames
(
0
),
framerate
(
0
)
num_frames
(
0
),
framerate
(
0
)
{
{
}
}
...
@@ -1148,15 +1222,14 @@ public:
...
@@ -1148,15 +1222,14 @@ public:
bool
writeFrame
(
const
IplImage
*
image
)
CV_OVERRIDE
;
bool
writeFrame
(
const
IplImage
*
image
)
CV_OVERRIDE
;
protected
:
protected
:
const
char
*
filenameToMimetype
(
const
char
*
filename
);
const
char
*
filenameToMimetype
(
const
char
*
filename
);
GstElement
*
pipeline
;
GSafePtr
<
GstElement
>
pipeline
;
GstElement
*
source
;
GSafePtr
<
GstElement
>
source
;
GstElement
*
encodebin
;
GstElement
*
file
;
GstBuffer
*
buffer
;
int
input_pix_fmt
;
int
input_pix_fmt
;
int
num_frames
;
int
num_frames
;
double
framerate
;
double
framerate
;
void
close_
();
};
};
/*!
/*!
...
@@ -1164,35 +1237,35 @@ protected:
...
@@ -1164,35 +1237,35 @@ protected:
* ends the pipeline by sending EOS and destroys the pipeline and all
* ends the pipeline by sending EOS and destroys the pipeline and all
* elements afterwards
* elements afterwards
*/
*/
void
CvVideoWriter_GStreamer
::
close
()
void
CvVideoWriter_GStreamer
::
close
_
()
{
{
GstStateChangeReturn
status
;
GstStateChangeReturn
status
;
if
(
pipeline
)
if
(
pipeline
)
{
{
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
if
(
gst_app_src_end_of_stream
(
GST_APP_SRC
(
source
))
!=
GST_FLOW_OK
)
if
(
gst_app_src_end_of_stream
(
GST_APP_SRC
(
source
.
get
()
))
!=
GST_FLOW_OK
)
{
{
CV_WARN
(
"Cannot send EOS to GStreamer pipeline
\n
"
);
CV_WARN
(
"Cannot send EOS to GStreamer pipeline"
);
return
;
}
}
else
{
//wait for EOS to trickle down the pipeline. This will let all elements finish properly
//wait for EOS to trickle down the pipeline. This will let all elements finish properly
GstBus
*
bus
=
gst_element_get_bus
(
pipeline
);
GSafePtr
<
GstBus
>
bus
;
bus
.
attach
(
gst_element_get_bus
(
pipeline
));
GstMessage
*
msg
=
gst_bus_timed_pop_filtered
(
bus
,
GST_CLOCK_TIME_NONE
,
(
GstMessageType
)(
GST_MESSAGE_ERROR
|
GST_MESSAGE_EOS
));
if
(
bus
)
if
(
!
msg
||
GST_MESSAGE_TYPE
(
msg
)
==
GST_MESSAGE_ERROR
)
{
{
CV_WARN
(
"Error during VideoWriter finalization
\n
"
);
GSafePtr
<
GstMessage
>
msg
;
msg
.
attach
(
gst_bus_timed_pop_filtered
(
bus
,
GST_CLOCK_TIME_NONE
,
(
GstMessageType
)(
GST_MESSAGE_ERROR
|
GST_MESSAGE_EOS
))
);
if
(
msg
!=
NULL
)
if
(
!
msg
||
GST_MESSAGE_TYPE
(
msg
.
get
())
==
GST_MESSAGE_ERROR
)
{
{
gst_message_unref
(
msg
);
CV_WARN
(
"Error during VideoWriter finalization"
);
g_object_unref
(
G_OBJECT
(
bus
));
handleMessage
(
pipeline
);
}
}
else
{
CV_WARN
(
"can't get GstBus"
);
}
}
return
;
}
}
gst_message_unref
(
msg
);
g_object_unref
(
G_OBJECT
(
bus
));
status
=
gst_element_set_state
(
pipeline
,
GST_STATE_NULL
);
status
=
gst_element_set_state
(
pipeline
,
GST_STATE_NULL
);
if
(
status
==
GST_STATE_CHANGE_ASYNC
)
if
(
status
==
GST_STATE_CHANGE_ASYNC
)
...
@@ -1205,61 +1278,65 @@ void CvVideoWriter_GStreamer::close()
...
@@ -1205,61 +1278,65 @@ void CvVideoWriter_GStreamer::close()
if
(
status
==
GST_STATE_CHANGE_FAILURE
)
if
(
status
==
GST_STATE_CHANGE_FAILURE
)
{
{
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
gst_object_unref
(
GST_OBJECT
(
pipeline
));
CV_WARN
(
"Unable to stop writer pipeline"
);
pipeline
=
NULL
;
CV_WARN
(
"Unable to stop gstreamer pipeline
\n
"
);
return
;
}
}
gst_object_unref
(
GST_OBJECT
(
pipeline
));
pipeline
=
NULL
;
}
}
}
}
void
CvVideoWriter_GStreamer
::
close
()
{
close_
();
source
.
release
();
pipeline
.
release
();
}
/*!
/*!
* \brief
CvVideoWriter_GStreamer::
filenameToMimetype
* \brief filenameToMimetype
* \param filename
* \param filename
* \return mimetype
* \return mimetype
* Re
s
turns a container mime type for a given filename by looking at it's extension
* Returns a container mime type for a given filename by looking at it's extension
*/
*/
const
char
*
CvVideoWriter_GStreamer
::
filenameToMimetype
(
const
char
*
filename
)
const
char
*
CvVideoWriter_GStreamer
::
filenameToMimetype
(
const
char
*
filename
)
{
{
//get extension
//get extension
const
char
*
ext
=
strrchr
(
filename
,
'.'
);
const
char
*
ext_
=
strrchr
(
filename
,
'.'
);
if
(
!
ext
||
ext
==
filename
)
return
NULL
;
if
(
!
ext_
||
ext_
==
filename
)
ext
+=
1
;
//exclude the dot
return
NULL
;
ext_
+=
1
;
//exclude the dot
std
::
string
ext
(
ext_
);
ext
=
toLowerCase
(
ext
);
// return a container mime based on the given extension.
// return a container mime based on the given extension.
// gstreamer's function returns too much possibilities, which is not useful to us
// gstreamer's function returns too much possibilities, which is not useful to us
//return the appropriate mime
//return the appropriate mime
if
(
strncasecmp
(
ext
,
"avi"
,
3
)
==
0
)
if
(
ext
==
"avi"
)
return
(
const
char
*
)
"video/x-msvideo"
;
return
"video/x-msvideo"
;
if
(
strncasecmp
(
ext
,
"mkv"
,
3
)
==
0
||
strncasecmp
(
ext
,
"mk3d"
,
4
)
==
0
||
strncasecmp
(
ext
,
"webm"
,
4
)
==
0
)
if
(
ext
==
"mkv"
||
ext
==
"mk3d"
||
ext
==
"webm"
)
return
(
const
char
*
)
"video/x-matroska"
;
return
"video/x-matroska"
;
if
(
strncasecmp
(
ext
,
"wmv"
,
3
)
==
0
)
if
(
ext
==
"wmv"
)
return
(
const
char
*
)
"video/x-ms-asf"
;
return
"video/x-ms-asf"
;
if
(
strncasecmp
(
ext
,
"mov"
,
3
)
==
0
)
if
(
ext
==
"mov"
)
return
(
const
char
*
)
"video/x-quicktime"
;
return
"video/x-quicktime"
;
if
(
strncasecmp
(
ext
,
"ogg"
,
3
)
==
0
||
strncasecmp
(
ext
,
"ogv"
,
3
)
==
0
)
if
(
ext
==
"ogg"
||
ext
==
"ogv"
)
return
(
const
char
*
)
"application/ogg"
;
return
"application/ogg"
;
if
(
strncasecmp
(
ext
,
"rm"
,
3
)
==
0
)
if
(
ext
==
"rm"
)
return
(
const
char
*
)
"vnd.rn-realmedia"
;
return
"vnd.rn-realmedia"
;
if
(
strncasecmp
(
ext
,
"swf"
,
3
)
==
0
)
if
(
ext
==
"swf"
)
return
(
const
char
*
)
"application/x-shockwave-flash"
;
return
"application/x-shockwave-flash"
;
if
(
strncasecmp
(
ext
,
"mp4"
,
3
)
==
0
)
if
(
ext
==
"mp4"
)
return
(
const
char
*
)
"video/x-quicktime, variant=(string)iso"
;
return
"video/x-quicktime, variant=(string)iso"
;
//default to avi
//default to avi
return
(
const
char
*
)
"video/x-msvideo"
;
return
"video/x-msvideo"
;
}
}
/*!
/*!
...
@@ -1272,7 +1349,7 @@ const char* CvVideoWriter_GStreamer::filenameToMimetype(const char *filename)
...
@@ -1272,7 +1349,7 @@ const char* CvVideoWriter_GStreamer::filenameToMimetype(const char *filename)
* \return success
* \return success
*
*
* We support 2 modes of operation. Either the user enters a filename and a fourcc
* We support 2 modes of operation. Either the user enters a filename and a fourcc
* code, or enters a manual pipeline description like in CvVideoCapture_G
s
treamer.
* code, or enters a manual pipeline description like in CvVideoCapture_G
S
treamer.
* In the latter case, we just push frames on the appsink with appropriate caps.
* In the latter case, we just push frames on the appsink with appropriate caps.
* In the former case, we try to deduce the correct container from the filename,
* In the former case, we try to deduce the correct container from the filename,
* and the correct encoder from the fourcc profile.
* and the correct encoder from the fourcc profile.
...
@@ -1284,55 +1361,66 @@ bool CvVideoWriter_GStreamer::open( const std::string &filename, int fourcc,
...
@@ -1284,55 +1361,66 @@ bool CvVideoWriter_GStreamer::open( const std::string &filename, int fourcc,
double
fps
,
const
cv
::
Size
&
frameSize
,
bool
is_color
)
double
fps
,
const
cv
::
Size
&
frameSize
,
bool
is_color
)
{
{
// check arguments
// check arguments
if
(
filename
.
empty
()
||
frameSize
.
width
<=
0
||
frameSize
.
height
<=
0
||
fps
<=
0
)
CV_Assert
(
!
filename
.
empty
());
return
false
;
CV_Assert
(
fps
>
0
);
CV_Assert
(
frameSize
.
width
>
0
&&
frameSize
.
height
>
0
);
// init gstreamer
// init gstreamer
gst_initializer
::
init
();
gst_initializer
::
init
();
// init vars
// init vars
GSafePtr
<
GstElement
>
file
;
GSafePtr
<
GstElement
>
encodebin
;
bool
manualpipeline
=
true
;
bool
manualpipeline
=
true
;
int
bufsize
=
0
;
int
bufsize
=
0
;
GError
*
err
=
NULL
;
GSafePtr
<
GError
>
err
;
const
char
*
mime
=
NULL
;
GstStateChangeReturn
stateret
;
GstStateChangeReturn
stateret
;
GstCaps
*
caps
=
NULL
;
GSafePtr
<
GstCaps
>
caps
;
GstCaps
*
videocaps
=
NULL
;
GstCaps
*
containercaps
=
NULL
;
GstEncodingContainerProfile
*
containerprofile
=
NULL
;
GstEncodingVideoProfile
*
videoprofile
=
NULL
;
GstIterator
*
it
=
NULL
;
GstIterator
*
it
=
NULL
;
gboolean
done
=
FALSE
;
gboolean
done
=
FALSE
;
GstElement
*
element
=
NULL
;
gchar
*
name
=
NULL
;
// we first try to construct a pipeline from the given string.
// we first try to construct a pipeline from the given string.
// if that fails, we assume it is an ordinary filename
// if that fails, we assume it is an ordinary filename
encodebin
=
gst_parse_launch
(
filename
.
c_str
(),
&
err
);
encodebin
.
attach
(
gst_parse_launch
(
filename
.
c_str
(),
err
.
getRef
())
);
manualpipeline
=
(
encodebin
!=
NULL
)
;
manualpipeline
=
(
bool
)
encodebin
;
if
(
manualpipeline
)
if
(
manualpipeline
)
{
{
it
=
gst_bin_iterate_sources
(
GST_BIN
(
encodebin
));
if
(
err
)
GValue
value
=
G_VALUE_INIT
;
{
CV_WARN
(
"error opening writer pipeline: "
<<
err
->
message
);
if
(
encodebin
)
{
gst_element_set_state
(
encodebin
,
GST_STATE_NULL
);
}
handleMessage
(
encodebin
);
encodebin
.
release
();
return
false
;
}
it
=
gst_bin_iterate_sources
(
GST_BIN
(
encodebin
.
get
()));
while
(
!
done
)
{
while
(
!
done
)
{
GValue
value
=
G_VALUE_INIT
;
GSafePtr
<
gchar
>
name
;
GstElement
*
element
=
NULL
;
switch
(
gst_iterator_next
(
it
,
&
value
))
{
switch
(
gst_iterator_next
(
it
,
&
value
))
{
case
GST_ITERATOR_OK
:
case
GST_ITERATOR_OK
:
element
=
GST_ELEMENT
(
g_value_get_object
(
&
value
));
element
=
GST_ELEMENT
(
g_value_get_object
(
&
value
));
// no lifetime transfer
name
=
gst_element_get_name
(
element
);
name
.
attach
(
gst_element_get_name
(
element
));
if
(
name
){
if
(
name
)
if
(
strstr
(
name
,
"opencvsrc"
)
!=
NULL
||
strstr
(
name
,
"appsrc"
)
!=
NULL
)
{
{
source
=
GST_ELEMENT
(
gst_object_ref
(
element
)
);
if
(
strstr
(
name
.
get
(),
"opencvsrc"
)
!=
NULL
||
strstr
(
name
.
get
(),
"appsrc"
)
!=
NULL
)
{
source
.
attach
(
GST_ELEMENT
(
gst_object_ref
(
element
)));
done
=
TRUE
;
done
=
TRUE
;
}
}
g_free
(
name
);
}
}
g_value_unset
(
&
value
);
g_value_unset
(
&
value
);
break
;
break
;
case
GST_ITERATOR_RESYNC
:
case
GST_ITERATOR_RESYNC
:
...
@@ -1350,15 +1438,15 @@ bool CvVideoWriter_GStreamer::open( const std::string &filename, int fourcc,
...
@@ -1350,15 +1438,15 @@ bool CvVideoWriter_GStreamer::open( const std::string &filename, int fourcc,
CV_WARN
(
"GStreamer: cannot find appsrc in manual pipeline
\n
"
);
CV_WARN
(
"GStreamer: cannot find appsrc in manual pipeline
\n
"
);
return
false
;
return
false
;
}
}
pipeline
=
encodebin
;
pipeline
.
swap
(
encodebin
)
;
}
}
else
else
{
{
pipeline
=
gst_pipeline_new
(
NULL
);
err
.
release
();
pipeline
.
reset
(
gst_pipeline_new
(
NULL
));
// we just got a filename and a fourcc code.
// we just got a filename and a fourcc code.
// first, try to guess the container from the filename
// first, try to guess the container from the filename
//encodebin = gst_element_factory_make("encodebin", NULL);
//proxy old non existing fourcc ids. These were used in previous opencv versions,
//proxy old non existing fourcc ids. These were used in previous opencv versions,
//but do not even exist in gstreamer any more
//but do not even exist in gstreamer any more
...
@@ -1368,97 +1456,112 @@ bool CvVideoWriter_GStreamer::open( const std::string &filename, int fourcc,
...
@@ -1368,97 +1456,112 @@ bool CvVideoWriter_GStreamer::open( const std::string &filename, int fourcc,
//create encoder caps from fourcc
//create encoder caps from fourcc
GSafePtr
<
GstCaps
>
videocaps
;
videocaps
=
gst_riff_create_video_caps
(
fourcc
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
videocaps
.
attach
(
gst_riff_create_video_caps
(
fourcc
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
));
if
(
!
videocaps
){
if
(
!
videocaps
)
CV_WARN
(
"Gstreamer Opencv backend does not support this codec."
);
{
CV_WARN
(
"OpenCV backend does not support passed FOURCC value"
);
return
false
;
return
false
;
}
}
//create container caps from file extension
//create container caps from file extension
mime
=
filenameToMimetype
(
filename
.
c_str
());
const
char
*
mime
=
filenameToMimetype
(
filename
.
c_str
());
if
(
!
mime
)
{
if
(
!
mime
)
CV_WARN
(
"Gstreamer Opencv backend does not support this file type."
);
{
CV_WARN
(
"OpenCV backend does not support this file type (extension): "
<<
filename
);
return
false
;
return
false
;
}
}
containercaps
=
gst_caps_from_string
(
mime
);
//create pipeline elements
encodebin
.
reset
(
gst_element_factory_make
(
"encodebin"
,
NULL
));
GSafePtr
<
GstCaps
>
containercaps
;
GSafePtr
<
GstEncodingContainerProfile
>
containerprofile
;
GSafePtr
<
GstEncodingVideoProfile
>
videoprofile
;
containercaps
.
attach
(
gst_caps_from_string
(
mime
));
//create encodebin profile
//create encodebin profile
containerprofile
=
gst_encoding_container_profile_new
(
"container"
,
"container"
,
containercaps
,
NULL
);
containerprofile
.
attach
(
gst_encoding_container_profile_new
(
"container"
,
"container"
,
containercaps
.
get
(),
NULL
)
);
videoprofile
=
gst_encoding_video_profile_new
(
videocaps
,
NULL
,
NULL
,
1
);
videoprofile
.
reset
(
gst_encoding_video_profile_new
(
videocaps
.
get
(),
NULL
,
NULL
,
1
)
);
gst_encoding_container_profile_add_profile
(
containerprofile
,
(
GstEncodingProfile
*
)
videoprofile
);
gst_encoding_container_profile_add_profile
(
containerprofile
.
get
(),
(
GstEncodingProfile
*
)
videoprofile
.
get
()
);
//create pipeline elements
g_object_set
(
G_OBJECT
(
encodebin
.
get
()),
"profile"
,
containerprofile
.
get
(),
NULL
);
encodebin
=
gst_element_factory_make
(
"encodebin"
,
NULL
);
g_object_set
(
G_OBJECT
(
encodebin
),
"profile"
,
containerprofile
,
NULL
);
source
.
reset
(
gst_element_factory_make
(
"appsrc"
,
NULL
));
source
=
gst_element_factory_make
(
"appsrc"
,
NULL
);
file
.
reset
(
gst_element_factory_make
(
"filesink"
,
NULL
));
file
=
gst_element_factory_make
(
"filesink"
,
NULL
);
g_object_set
(
G_OBJECT
(
file
.
get
()),
"location"
,
(
const
char
*
)
filename
.
c_str
(),
NULL
);
g_object_set
(
G_OBJECT
(
file
),
"location"
,
filename
.
c_str
(),
NULL
);
}
}
int
fps_num
=
0
,
fps_denom
=
1
;
toFraction
(
fps
,
fps_num
,
fps_denom
);
if
(
fourcc
==
CV_FOURCC
(
'M'
,
'J'
,
'P'
,
'G'
)
&&
frameSize
.
height
==
1
)
if
(
fourcc
==
CV_FOURCC
(
'M'
,
'J'
,
'P'
,
'G'
)
&&
frameSize
.
height
==
1
)
{
{
input_pix_fmt
=
GST_VIDEO_FORMAT_ENCODED
;
input_pix_fmt
=
GST_VIDEO_FORMAT_ENCODED
;
caps
=
gst_caps_new_simple
(
"image/jpeg"
,
caps
.
attach
(
gst_caps_new_simple
(
"image/jpeg"
,
"framerate"
,
GST_TYPE_FRACTION
,
int
(
fps
),
1
,
"framerate"
,
GST_TYPE_FRACTION
,
int
(
fps_num
),
int
(
fps_denom
)
,
NULL
);
NULL
)
);
caps
=
gst_caps_fixate
(
caps
);
caps
.
attach
(
gst_caps_fixate
(
caps
.
detach
())
);
}
}
else
if
(
is_color
)
else
if
(
is_color
)
{
{
input_pix_fmt
=
GST_VIDEO_FORMAT_BGR
;
input_pix_fmt
=
GST_VIDEO_FORMAT_BGR
;
bufsize
=
frameSize
.
width
*
frameSize
.
height
*
3
;
bufsize
=
frameSize
.
width
*
frameSize
.
height
*
3
;
caps
=
gst_caps_new_simple
(
"video/x-raw"
,
caps
.
attach
(
gst_caps_new_simple
(
"video/x-raw"
,
"format"
,
G_TYPE_STRING
,
"BGR"
,
"format"
,
G_TYPE_STRING
,
"BGR"
,
"width"
,
G_TYPE_INT
,
frameSize
.
width
,
"width"
,
G_TYPE_INT
,
frameSize
.
width
,
"height"
,
G_TYPE_INT
,
frameSize
.
height
,
"height"
,
G_TYPE_INT
,
frameSize
.
height
,
"framerate"
,
GST_TYPE_FRACTION
,
int
(
fps
),
1
,
"framerate"
,
GST_TYPE_FRACTION
,
gint
(
fps_num
),
gint
(
fps_denom
),
NULL
);
NULL
));
caps
=
gst_caps_fixate
(
caps
);
CV_Assert
(
caps
);
caps
.
attach
(
gst_caps_fixate
(
caps
.
detach
()));
CV_Assert
(
caps
);
}
}
else
else
{
{
input_pix_fmt
=
GST_VIDEO_FORMAT_GRAY8
;
input_pix_fmt
=
GST_VIDEO_FORMAT_GRAY8
;
bufsize
=
frameSize
.
width
*
frameSize
.
height
;
bufsize
=
frameSize
.
width
*
frameSize
.
height
;
caps
=
gst_caps_new_simple
(
"video/x-raw"
,
caps
.
attach
(
gst_caps_new_simple
(
"video/x-raw"
,
"format"
,
G_TYPE_STRING
,
"GRAY8"
,
"format"
,
G_TYPE_STRING
,
"GRAY8"
,
"width"
,
G_TYPE_INT
,
frameSize
.
width
,
"width"
,
G_TYPE_INT
,
frameSize
.
width
,
"height"
,
G_TYPE_INT
,
frameSize
.
height
,
"height"
,
G_TYPE_INT
,
frameSize
.
height
,
"framerate"
,
GST_TYPE_FRACTION
,
int
(
fps
),
1
,
"framerate"
,
GST_TYPE_FRACTION
,
gint
(
fps_num
),
gint
(
fps_denom
)
,
NULL
);
NULL
)
);
caps
=
gst_caps_fixate
(
caps
);
caps
.
attach
(
gst_caps_fixate
(
caps
.
detach
())
);
}
}
gst_app_src_set_caps
(
GST_APP_SRC
(
source
),
caps
);
gst_app_src_set_caps
(
GST_APP_SRC
(
source
.
get
()
),
caps
);
gst_app_src_set_stream_type
(
GST_APP_SRC
(
source
),
GST_APP_STREAM_TYPE_STREAM
);
gst_app_src_set_stream_type
(
GST_APP_SRC
(
source
.
get
()
),
GST_APP_STREAM_TYPE_STREAM
);
gst_app_src_set_size
(
GST_APP_SRC
(
source
),
-
1
);
gst_app_src_set_size
(
GST_APP_SRC
(
source
.
get
()
),
-
1
);
g_object_set
(
G_OBJECT
(
source
),
"format"
,
GST_FORMAT_TIME
,
NULL
);
g_object_set
(
G_OBJECT
(
source
.
get
()
),
"format"
,
GST_FORMAT_TIME
,
NULL
);
g_object_set
(
G_OBJECT
(
source
),
"block"
,
1
,
NULL
);
g_object_set
(
G_OBJECT
(
source
.
get
()
),
"block"
,
1
,
NULL
);
g_object_set
(
G_OBJECT
(
source
),
"is-live"
,
0
,
NULL
);
g_object_set
(
G_OBJECT
(
source
.
get
()
),
"is-live"
,
0
,
NULL
);
if
(
!
manualpipeline
)
if
(
!
manualpipeline
)
{
g_object_set
(
G_OBJECT
(
file
.
get
()),
"buffer-size"
,
bufsize
,
NULL
);
gst_bin_add_many
(
GST_BIN
(
pipeline
.
get
()),
source
.
get
(),
encodebin
.
get
(),
file
.
get
(),
NULL
);
if
(
!
gst_element_link_many
(
source
.
get
(),
encodebin
.
get
(),
file
.
get
(),
NULL
))
{
{
g_object_set
(
G_OBJECT
(
file
),
"buffer-size"
,
bufsize
,
NULL
);
CV_WARN
(
"cannot link elements"
);
gst_bin_add_many
(
GST_BIN
(
pipeline
),
source
,
encodebin
,
file
,
NULL
);
pipeline
.
release
();
if
(
!
gst_element_link_many
(
source
,
encodebin
,
file
,
NULL
))
{
CV_WARN
(
"GStreamer: cannot link elements
\n
"
);
return
false
;
return
false
;
}
}
}
}
GST_DEBUG_BIN_TO_DOT_FILE
(
GST_BIN
(
pipeline
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"write-pipeline"
);
GST_DEBUG_BIN_TO_DOT_FILE
(
GST_BIN
(
pipeline
.
get
()
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"write-pipeline"
);
stateret
=
gst_element_set_state
(
GST_ELEMENT
(
pipeline
),
GST_STATE_PLAYING
);
stateret
=
gst_element_set_state
(
GST_ELEMENT
(
pipeline
.
get
()),
GST_STATE_PLAYING
);
if
(
stateret
==
GST_STATE_CHANGE_FAILURE
)
{
if
(
stateret
==
GST_STATE_CHANGE_FAILURE
)
{
handleMessage
(
pipeline
);
handleMessage
(
pipeline
);
CV_WARN
(
"GStreamer: cannot put pipeline to play
\n
"
);
CV_WARN
(
"GStreamer: cannot put pipeline to play
\n
"
);
pipeline
.
release
();
return
false
;
return
false
;
}
}
...
@@ -1516,7 +1619,7 @@ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
...
@@ -1516,7 +1619,7 @@ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
timestamp
=
num_frames
*
duration
;
timestamp
=
num_frames
*
duration
;
//gst_app_src_push_buffer takes ownership of the buffer, so we need to supply it a copy
//gst_app_src_push_buffer takes ownership of the buffer, so we need to supply it a copy
buffer
=
gst_buffer_new_allocate
(
NULL
,
size
,
NULL
);
GstBuffer
*
buffer
=
gst_buffer_new_allocate
(
NULL
,
size
,
NULL
);
GstMapInfo
info
;
GstMapInfo
info
;
gst_buffer_map
(
buffer
,
&
info
,
(
GstMapFlags
)
GST_MAP_READ
);
gst_buffer_map
(
buffer
,
&
info
,
(
GstMapFlags
)
GST_MAP_READ
);
memcpy
(
info
.
data
,
(
guint8
*
)
image
->
imageData
,
size
);
memcpy
(
info
.
data
,
(
guint8
*
)
image
->
imageData
,
size
);
...
@@ -1527,8 +1630,9 @@ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
...
@@ -1527,8 +1630,9 @@ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
//set the current number in the frame
//set the current number in the frame
GST_BUFFER_OFFSET
(
buffer
)
=
num_frames
;
GST_BUFFER_OFFSET
(
buffer
)
=
num_frames
;
ret
=
gst_app_src_push_buffer
(
GST_APP_SRC
(
source
),
buffer
);
ret
=
gst_app_src_push_buffer
(
GST_APP_SRC
(
source
.
get
()),
buffer
);
if
(
ret
!=
GST_FLOW_OK
)
{
if
(
ret
!=
GST_FLOW_OK
)
{
CV_WARN
(
"Error pushing buffer to GStreamer pipeline"
);
CV_WARN
(
"Error pushing buffer to GStreamer pipeline"
);
return
false
;
return
false
;
}
}
...
@@ -1540,34 +1644,49 @@ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
...
@@ -1540,34 +1644,49 @@ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
return
true
;
return
true
;
}
}
Ptr
<
IVideoWriter
>
c
v
::
c
reate_GStreamer_writer
(
const
std
::
string
&
filename
,
int
fourcc
,
double
fps
,
const
cv
::
Size
&
frameSize
,
bool
isColor
)
Ptr
<
IVideoWriter
>
create_GStreamer_writer
(
const
std
::
string
&
filename
,
int
fourcc
,
double
fps
,
const
cv
::
Size
&
frameSize
,
bool
isColor
)
{
{
CvVideoWriter_GStreamer
*
wrt
=
new
CvVideoWriter_GStreamer
;
CvVideoWriter_GStreamer
*
wrt
=
new
CvVideoWriter_GStreamer
;
try
{
if
(
wrt
->
open
(
filename
,
fourcc
,
fps
,
frameSize
,
isColor
))
if
(
wrt
->
open
(
filename
,
fourcc
,
fps
,
frameSize
,
isColor
))
return
makePtr
<
LegacyWriter
>
(
wrt
);
return
makePtr
<
LegacyWriter
>
(
wrt
);
delete
wrt
;
delete
wrt
;
}
catch
(...)
{
delete
wrt
;
throw
;
}
return
0
;
return
0
;
}
}
// utility functions
// utility functions
/*!
void
toFraction
(
const
double
decimal
,
int
&
numerator_i
,
int
&
denominator_i
)
* \brief toFraction
* \param decimal
* \param numerator
* \param denominator
* Split a floating point value into numerator and denominator
*/
void
toFraction
(
double
decimal
,
double
&
numerator
,
double
&
denominator
)
{
{
double
err
=
1.0
;
int
denominator
=
1
;
double
numerator
=
0
;
for
(
int
check_denominator
=
1
;
;
check_denominator
++
)
{
double
check_numerator
=
(
double
)
check_denominator
*
decimal
;
double
dummy
;
double
dummy
;
double
whole
;
double
check_err
=
modf
(
check_numerator
,
&
dummy
);
decimal
=
modf
(
decimal
,
&
whole
);
if
(
check_err
<
err
)
for
(
denominator
=
1
;
denominator
<=
100
;
denominator
++
){
{
if
(
modf
(
denominator
*
decimal
,
&
dummy
)
<
0.001
f
)
err
=
check_err
;
denominator
=
check_denominator
;
numerator
=
check_numerator
;
if
(
err
<
FLT_EPSILON
)
break
;
break
;
}
}
numerator
=
denominator
*
decimal
;
if
(
check_denominator
==
100
)
// limit
break
;
}
numerator_i
=
cvRound
(
numerator
);
denominator_i
=
denominator
;
//printf("%g: %d/%d (err=%g)\n", decimal, numerator_i, denominator_i, err);
}
}
...
@@ -1577,25 +1696,22 @@ void toFraction(double decimal, double &numerator, double &denominator)
...
@@ -1577,25 +1696,22 @@ void toFraction(double decimal, double &numerator, double &denominator)
*/
*/
void
handleMessage
(
GstElement
*
pipeline
)
void
handleMessage
(
GstElement
*
pipeline
)
{
{
GError
*
err
=
NULL
;
GSafePtr
<
GstBus
>
bus
;
gchar
*
debug
=
NULL
;
GstBus
*
bus
=
NULL
;
GstStreamStatusType
tp
;
GstStreamStatusType
tp
;
GstElement
*
elem
=
NULL
;
GstElement
*
elem
=
NULL
;
GstMessage
*
msg
=
NULL
;
bus
=
gst_element_get_bus
(
pipeline
);
bus
.
attach
(
gst_element_get_bus
(
pipeline
)
);
while
(
gst_bus_have_pending
(
bus
))
{
while
(
gst_bus_have_pending
(
bus
))
msg
=
gst_bus_pop
(
bus
);
if
(
!
msg
||
!
GST_IS_MESSAGE
(
msg
))
{
{
GSafePtr
<
GstMessage
>
msg
;
msg
.
attach
(
gst_bus_pop
(
bus
));
if
(
!
msg
||
!
GST_IS_MESSAGE
(
msg
.
get
()))
continue
;
continue
;
}
if
(
gst_is_missing_plugin_message
(
msg
))
if
(
gst_is_missing_plugin_message
(
msg
))
{
{
CV_WARN
(
"your
gstreamer installation is missing a required plugin
\
n
"
);
CV_WARN
(
"your
GStreamer installation is missing a required plugi
n"
);
}
}
else
else
{
{
...
@@ -1605,11 +1721,18 @@ void handleMessage(GstElement * pipeline)
...
@@ -1605,11 +1721,18 @@ void handleMessage(GstElement * pipeline)
gst_message_parse_state_changed
(
msg
,
&
oldstate
,
&
newstate
,
&
pendstate
);
gst_message_parse_state_changed
(
msg
,
&
oldstate
,
&
newstate
,
&
pendstate
);
break
;
break
;
case
GST_MESSAGE_ERROR
:
case
GST_MESSAGE_ERROR
:
gst_message_parse_error
(
msg
,
&
err
,
&
debug
);
{
g_error_free
(
err
);
GSafePtr
<
GError
>
err
;
g_free
(
debug
);
GSafePtr
<
gchar
>
debug
;
gst_message_parse_error
(
msg
,
err
.
getRef
(),
debug
.
getRef
());
GSafePtr
<
gchar
>
name
;
name
.
attach
(
gst_element_get_name
(
GST_MESSAGE_SRC
(
msg
)));
CV_WARN
(
"Embedded video playback halted; module "
<<
name
.
get
()
<<
" reported: "
<<
err
->
message
);
CV_LOG_DEBUG
(
NULL
,
"GStreamer debug: "
<<
debug
.
get
());
gst_element_set_state
(
GST_ELEMENT
(
pipeline
),
GST_STATE_NULL
);
gst_element_set_state
(
GST_ELEMENT
(
pipeline
),
GST_STATE_NULL
);
break
;
break
;
}
case
GST_MESSAGE_EOS
:
case
GST_MESSAGE_EOS
:
break
;
break
;
case
GST_MESSAGE_STREAM_STATUS
:
case
GST_MESSAGE_STREAM_STATUS
:
...
@@ -1619,12 +1742,11 @@ void handleMessage(GstElement * pipeline)
...
@@ -1619,12 +1742,11 @@ void handleMessage(GstElement * pipeline)
break
;
break
;
}
}
}
}
gst_message_unref
(
msg
);
}
}
gst_object_unref
(
GST_OBJECT
(
bus
));
}
}
}
// namespace cv
//==================================================================================================
//==================================================================================================
#if defined(BUILD_PLUGIN)
#if defined(BUILD_PLUGIN)
...
...
modules/videoio/test/test_gstreamer.cpp
View file @
e69ff713
...
@@ -73,4 +73,22 @@ Param test_data[] = {
...
@@ -73,4 +73,22 @@ Param test_data[] = {
INSTANTIATE_TEST_CASE_P
(
videoio
,
videoio_gstreamer
,
testing
::
ValuesIn
(
test_data
));
INSTANTIATE_TEST_CASE_P
(
videoio
,
videoio_gstreamer
,
testing
::
ValuesIn
(
test_data
));
TEST
(
Videoio_GStreamer
,
unsupported_pipeline
)
{
VideoCaptureAPIs
apiPref
=
CAP_GSTREAMER
;
if
(
!
isBackendAvailable
(
apiPref
,
cv
::
videoio_registry
::
getStreamBackends
()))
throw
SkipTestException
(
cv
::
String
(
"Backend is not available/disabled: "
)
+
cv
::
videoio_registry
::
getBackendName
(
apiPref
));
// could not link videoconvert0 to matroskamux0, matroskamux0 can't handle caps video/x-raw, format=(string)RGBA
std
::
string
pipeline
=
"appsrc ! videoconvert ! video/x-raw, format=(string)RGBA ! matroskamux ! filesink location=test.mkv"
;
Size
frame_size
(
640
,
480
);
VideoWriter
writer
;
EXPECT_NO_THROW
(
writer
.
open
(
pipeline
,
apiPref
,
0
/*fourcc*/
,
30
/*fps*/
,
frame_size
,
true
));
EXPECT_FALSE
(
writer
.
isOpened
());
// no frames
EXPECT_NO_THROW
(
writer
.
release
());
}
}
// namespace
}
// namespace
modules/videoio/test/test_video_io.cpp
View file @
e69ff713
...
@@ -227,8 +227,8 @@ public:
...
@@ -227,8 +227,8 @@ public:
struct
Ext_Fourcc_PSNR
struct
Ext_Fourcc_PSNR
{
{
string
ext
;
const
char
*
ext
;
string
fourcc
;
const
char
*
fourcc
;
float
PSNR
;
float
PSNR
;
VideoCaptureAPIs
api
;
VideoCaptureAPIs
api
;
};
};
...
@@ -345,18 +345,6 @@ INSTANTIATE_TEST_CASE_P(videoio, videoio_bunny,
...
@@ -345,18 +345,6 @@ INSTANTIATE_TEST_CASE_P(videoio, videoio_bunny,
testing
::
ValuesIn
(
backend_params
)));
testing
::
ValuesIn
(
backend_params
)));
//==================================================================================================
inline
Ext_Fourcc_PSNR
makeParam
(
const
char
*
ext
,
const
char
*
fourcc
,
float
psnr
,
VideoCaptureAPIs
apipref
)
{
Ext_Fourcc_PSNR
res
;
res
.
ext
=
ext
;
res
.
fourcc
=
fourcc
;
res
.
PSNR
=
psnr
;
res
.
api
=
apipref
;
return
res
;
}
inline
static
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
const
Ext_Fourcc_PSNR
&
p
)
inline
static
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
const
Ext_Fourcc_PSNR
&
p
)
{
{
out
<<
"FOURCC("
<<
p
.
fourcc
<<
"), ."
<<
p
.
ext
<<
", "
<<
p
.
api
<<
", "
<<
p
.
PSNR
<<
"dB"
;
return
out
;
out
<<
"FOURCC("
<<
p
.
fourcc
<<
"), ."
<<
p
.
ext
<<
", "
<<
p
.
api
<<
", "
<<
p
.
PSNR
<<
"dB"
;
return
out
;
...
@@ -366,41 +354,41 @@ static Ext_Fourcc_PSNR synthetic_params[] = {
...
@@ -366,41 +354,41 @@ static Ext_Fourcc_PSNR synthetic_params[] = {
#ifdef HAVE_MSMF
#ifdef HAVE_MSMF
#if !defined(_M_ARM)
#if !defined(_M_ARM)
makeParam
(
"wmv"
,
"WMV1"
,
30.
f
,
CAP_MSMF
)
,
{
"wmv"
,
"WMV1"
,
30.
f
,
CAP_MSMF
}
,
makeParam
(
"wmv"
,
"WMV2"
,
30.
f
,
CAP_MSMF
)
,
{
"wmv"
,
"WMV2"
,
30.
f
,
CAP_MSMF
}
,
#endif
#endif
makeParam
(
"wmv"
,
"WMV3"
,
30.
f
,
CAP_MSMF
)
,
{
"wmv"
,
"WMV3"
,
30.
f
,
CAP_MSMF
}
,
makeParam
(
"wmv"
,
"WVC1"
,
30.
f
,
CAP_MSMF
)
,
{
"wmv"
,
"WVC1"
,
30.
f
,
CAP_MSMF
}
,
makeParam
(
"mov"
,
"H264"
,
30.
f
,
CAP_MSMF
)
,
{
"mov"
,
"H264"
,
30.
f
,
CAP_MSMF
}
,
#endif
#endif
#ifdef HAVE_AVFOUNDATION
#ifdef HAVE_AVFOUNDATION
makeParam
(
"mov"
,
"H264"
,
30.
f
,
CAP_AVFOUNDATION
)
,
{
"mov"
,
"H264"
,
30.
f
,
CAP_AVFOUNDATION
}
,
makeParam
(
"mov"
,
"MJPG"
,
30.
f
,
CAP_AVFOUNDATION
)
,
{
"mov"
,
"MJPG"
,
30.
f
,
CAP_AVFOUNDATION
}
,
makeParam
(
"mp4"
,
"H264"
,
30.
f
,
CAP_AVFOUNDATION
)
,
{
"mp4"
,
"H264"
,
30.
f
,
CAP_AVFOUNDATION
}
,
makeParam
(
"mp4"
,
"MJPG"
,
30.
f
,
CAP_AVFOUNDATION
)
,
{
"mp4"
,
"MJPG"
,
30.
f
,
CAP_AVFOUNDATION
}
,
makeParam
(
"m4v"
,
"H264"
,
30.
f
,
CAP_AVFOUNDATION
)
,
{
"m4v"
,
"H264"
,
30.
f
,
CAP_AVFOUNDATION
}
,
makeParam
(
"m4v"
,
"MJPG"
,
30.
f
,
CAP_AVFOUNDATION
)
,
{
"m4v"
,
"MJPG"
,
30.
f
,
CAP_AVFOUNDATION
}
,
#endif
#endif
makeParam
(
"avi"
,
"XVID"
,
30.
f
,
CAP_FFMPEG
)
,
{
"avi"
,
"XVID"
,
30.
f
,
CAP_FFMPEG
}
,
makeParam
(
"avi"
,
"MPEG"
,
30.
f
,
CAP_FFMPEG
)
,
{
"avi"
,
"MPEG"
,
30.
f
,
CAP_FFMPEG
}
,
makeParam
(
"avi"
,
"IYUV"
,
30.
f
,
CAP_FFMPEG
)
,
{
"avi"
,
"IYUV"
,
30.
f
,
CAP_FFMPEG
}
,
makeParam
(
"avi"
,
"MJPG"
,
30.
f
,
CAP_FFMPEG
)
,
{
"avi"
,
"MJPG"
,
30.
f
,
CAP_FFMPEG
}
,
makeParam
(
"mkv"
,
"XVID"
,
30.
f
,
CAP_FFMPEG
)
,
{
"mkv"
,
"XVID"
,
30.
f
,
CAP_FFMPEG
}
,
makeParam
(
"mkv"
,
"MPEG"
,
30.
f
,
CAP_FFMPEG
)
,
{
"mkv"
,
"MPEG"
,
30.
f
,
CAP_FFMPEG
}
,
makeParam
(
"mkv"
,
"MJPG"
,
30.
f
,
CAP_FFMPEG
)
,
{
"mkv"
,
"MJPG"
,
30.
f
,
CAP_FFMPEG
}
,
makeParam
(
"avi"
,
"MPEG"
,
30.
f
,
CAP_GSTREAMER
)
,
{
"avi"
,
"MPEG"
,
30.
f
,
CAP_GSTREAMER
}
,
makeParam
(
"avi"
,
"MJPG"
,
30.
f
,
CAP_GSTREAMER
)
,
{
"avi"
,
"MJPG"
,
30.
f
,
CAP_GSTREAMER
}
,
makeParam
(
"avi"
,
"H264"
,
30.
f
,
CAP_GSTREAMER
)
,
{
"avi"
,
"H264"
,
30.
f
,
CAP_GSTREAMER
}
,
makeParam
(
"mkv"
,
"MPEG"
,
30.
f
,
CAP_GSTREAMER
)
,
{
"mkv"
,
"MPEG"
,
30.
f
,
CAP_GSTREAMER
}
,
makeParam
(
"mkv"
,
"MJPG"
,
30.
f
,
CAP_GSTREAMER
)
,
{
"mkv"
,
"MJPG"
,
30.
f
,
CAP_GSTREAMER
}
,
makeParam
(
"mkv"
,
"H264"
,
30.
f
,
CAP_GSTREAMER
)
,
{
"mkv"
,
"H264"
,
30.
f
,
CAP_GSTREAMER
}
,
makeParam
(
"avi"
,
"MJPG"
,
30.
f
,
CAP_OPENCV_MJPEG
)
,
{
"avi"
,
"MJPG"
,
30.
f
,
CAP_OPENCV_MJPEG
}
,
};
};
...
@@ -416,6 +404,89 @@ INSTANTIATE_TEST_CASE_P(videoio, videoio_synthetic,
...
@@ -416,6 +404,89 @@ INSTANTIATE_TEST_CASE_P(videoio, videoio_synthetic,
testing
::
ValuesIn
(
all_sizes
),
testing
::
ValuesIn
(
all_sizes
),
testing
::
ValuesIn
(
synthetic_params
)));
testing
::
ValuesIn
(
synthetic_params
)));
struct
Ext_Fourcc_API
{
const
char
*
ext
;
const
char
*
fourcc
;
VideoCaptureAPIs
api
;
};
inline
static
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
const
Ext_Fourcc_API
&
p
)
{
out
<<
"(FOURCC("
<<
p
.
fourcc
<<
"),
\"
"
<<
p
.
ext
<<
"
\"
, "
<<
p
.
api
<<
")"
;
return
out
;
}
class
Videoio_Writer
:
public
Videoio_Test_Base
,
public
testing
::
TestWithParam
<
Ext_Fourcc_API
>
{
protected
:
Size
frame_size
;
int
fourcc
;
double
fps
;
public
:
Videoio_Writer
()
{
frame_size
=
Size
(
640
,
480
);
const
Ext_Fourcc_API
p
=
GetParam
();
ext
=
p
.
ext
;
fourcc
=
fourccFromString
(
p
.
fourcc
);
if
(
ext
.
size
()
==
3
)
video_file
=
cv
::
tempfile
((
fourccToString
(
fourcc
)
+
"."
+
ext
).
c_str
());
else
video_file
=
ext
;
fps
=
25.
;
apiPref
=
p
.
api
;
}
void
SetUp
()
{
}
void
TearDown
()
{
if
(
ext
.
size
()
==
3
)
(
void
)
remove
(
video_file
.
c_str
());
}
};
TEST_P
(
Videoio_Writer
,
write_nothing
)
{
if
(
!
cv
::
videoio_registry
::
hasBackend
(
apiPref
))
throw
SkipTestException
(
cv
::
String
(
"Backend is not available/disabled: "
)
+
cv
::
videoio_registry
::
getBackendName
(
apiPref
));
VideoWriter
writer
;
EXPECT_NO_THROW
(
writer
.
open
(
video_file
,
apiPref
,
fourcc
,
fps
,
frame_size
,
true
));
ASSERT_TRUE
(
writer
.
isOpened
());
#if 0 // no frames
cv::Mat m(frame_size, CV_8UC3, Scalar::all(127));
writer << m;
#endif
EXPECT_NO_THROW
(
writer
.
release
());
}
static
vector
<
Ext_Fourcc_API
>
generate_Ext_Fourcc_API
()
{
const
size_t
N
=
sizeof
(
synthetic_params
)
/
sizeof
(
synthetic_params
[
0
]);
vector
<
Ext_Fourcc_API
>
result
;
result
.
reserve
(
N
);
for
(
size_t
i
=
0
;
i
<
N
;
i
++
)
{
const
Ext_Fourcc_PSNR
&
src
=
synthetic_params
[
i
];
Ext_Fourcc_API
e
=
{
src
.
ext
,
src
.
fourcc
,
src
.
api
};
result
.
push_back
(
e
);
}
{
Ext_Fourcc_API
e
=
{
"appsrc ! videoconvert ! video/x-raw, format=(string)NV12 ! filesink location=test.nv12"
,
"
\0\0\0\0
"
,
CAP_GSTREAMER
};
result
.
push_back
(
e
);
}
{
Ext_Fourcc_API
e
=
{
"appsrc ! videoconvert ! video/x-raw, format=(string)I420 ! matroskamux ! filesink location=test.mkv"
,
"
\0\0\0\0
"
,
CAP_GSTREAMER
};
result
.
push_back
(
e
);
}
return
result
;
}
INSTANTIATE_TEST_CASE_P
(
videoio
,
Videoio_Writer
,
testing
::
ValuesIn
(
generate_Ext_Fourcc_API
()));
TEST
(
Videoio
,
exceptions
)
TEST
(
Videoio
,
exceptions
)
{
{
VideoCapture
cap
;
VideoCapture
cap
;
...
...
platforms/scripts/valgrind.supp
View file @
e69ff713
...
@@ -218,6 +218,14 @@
...
@@ -218,6 +218,14 @@
fun:__itt_*create*
fun:__itt_*create*
}
}
{
OpenCV-gtk_init
Memcheck:Leak
...
fun:gtk_init
fun:cvInitSystem
}
{
{
OpenCV-FFmpeg-swsscale
OpenCV-FFmpeg-swsscale
Memcheck:Addr16
Memcheck:Addr16
...
@@ -227,6 +235,35 @@
...
@@ -227,6 +235,35 @@
fun:cvWriteFrame_FFMPEG
fun:cvWriteFrame_FFMPEG
}
}
{
OpenCV-GStreamer-gst_init
Memcheck:Leak
...
fun:gst_init
}
{
OpenCV-GStreamer-gst_deinit
Memcheck:Leak
...
fun:gst_deinit
}
{
OpenCV-GStreamer-gst_init_check
Memcheck:Leak
...
fun:gst_init_check
}
{
OpenCV-GStreamer-gst_parse_launch_full-reachable
Memcheck:Leak
match-leak-kinds: reachable
...
fun:gst_parse_launch_full
}
{
{
OpenCV-OpenEXR-ThreadPool
OpenCV-OpenEXR-ThreadPool
Memcheck:Leak
Memcheck:Leak
...
...
platforms/scripts/valgrind_3rdparty.supp
View file @
e69ff713
...
@@ -18,6 +18,15 @@
...
@@ -18,6 +18,15 @@
fun:_ZN7testing8internal11CmpHelperLEIddEENS_15AssertionResultEPKcS4_RKT_RKT0_
fun:_ZN7testing8internal11CmpHelperLEIddEENS_15AssertionResultEPKcS4_RKT_RKT0_
}
}
{
GTest-RegisterTests
Memcheck:Leak
...
fun:RegisterTests
...
fun:_ZN7testing14InitGoogleTestEPiPPc
}
{
{
OpenCL
OpenCL
Memcheck:Cond
Memcheck:Cond
...
@@ -55,10 +64,10 @@
...
@@ -55,10 +64,10 @@
}
}
{
{
glib
GTK-css
Memcheck:Leak
Memcheck:Leak
fun:*alloc
...
obj:*/libglib
*
fun:gtk_css_provider
*
}
}
{
{
...
@@ -120,3 +129,89 @@
...
@@ -120,3 +129,89 @@
...
...
fun:cvWriteFrame_FFMPEG
fun:cvWriteFrame_FFMPEG
}
}
{
GStreamer-orc_program_compile_full
Memcheck:Leak
match-leak-kinds: reachable
...
fun:orc_program_compile_full
...
fun:clone
}
{
GStreamer-orc_program_new_from_static_bytecode
Memcheck:Leak
match-leak-kinds: reachable
...
fun:orc_program_new_from_static_bytecode
...
fun:clone
}
{
GStreamer-matroska-other
Memcheck:Leak
...
fun:gst*
obj:*gstmatroska*
...
obj:*glib*
fun:start_thread
fun:clone
}
{
GStreamer-matroska-gst_riff_create_video_caps
Memcheck:Leak
...
fun:gst_riff_create_video_caps
obj:*gstmatroska*
...
fun:clone
}
{
GStreamer-tls
Memcheck:Leak
match-leak-kinds: possible
fun:calloc
fun:allocate_dtv
fun:_dl_allocate_tls
}
{
GStreamer-registry
Memcheck:Leak
...
fun:gst_update_registry
}
{
GStreamer-plugin_load
Memcheck:Leak
...
fun:gst_plugin_load_by_name
}
{
GStreamer-separate-threads
Memcheck:Leak
...
obj:*/libglib*
fun:start_thread
fun:clone
}
{
clone-unknown-leak
Memcheck:Leak
match-leak-kinds: definite
fun:_Znwm
obj:*
obj:*
fun:start_thread
fun:clone
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment