-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature add linux gstreamer support #11
base: master
Are you sure you want to change the base?
Feature add linux gstreamer support #11
Conversation
… library this is the initial revision, tests are not yet green, to be continued
Hey Henry! That's great! Thanks a lot for the contribution. I will look at it as soon as possible. In the mean time could you please update the travis-ci to retrieve the gstreamer package so that the linux build passes? Thanks, |
audiostream/CMakeLists.txt
Outdated
@@ -71,6 +71,7 @@ endif() | |||
|
|||
set( COMPILE_WITH_COREAUDIO DONT_COMPILE) | |||
set( COMPILE_WITH_MEDIA_FOUNDATION DONT_COMPILE) | |||
set( COMPILE_WITH_GSTREAMER DONT_COMPILE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pedantic: align DONT_COMPILE with above statements
audiostream/CMakeLists.txt
Outdated
@@ -228,6 +252,7 @@ add_src_file (FILES_media_audio_source "src/ni/media/audio/source/container_sou | |||
add_src_file (FILES_media_audio_source "src/ni/media/audio/source/core_audio_file_source.cpp" ${COMPILE_WITH_COREAUDIO} WITH_HEADER ) | |||
add_src_file (FILES_media_audio_source "src/ni/media/audio/source/media_foundation_helper.h" ${COMPILE_WITH_MEDIA_FOUNDATION} ) | |||
add_src_file (FILES_media_audio_source "src/ni/media/audio/source/media_foundation_file_source.cpp" ${COMPILE_WITH_MEDIA_FOUNDATION} WITH_HEADER ) | |||
add_src_file (FILES_media_audio_source "src/ni/media/audio/source/gstreamer_file_source.cpp" ${COMPILE_WITH_GSTREAMER} WITH_HEADER ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pedantic: align with other entires
cmake/FindGStreamer.cmake
Outdated
|
||
|
||
if( GSTREAMER_FOUND ) | ||
if( NOT TARGET GSTREAMER::gstreamer ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pedantic: alignment
cmake/FindGStreamerApp.cmake
Outdated
|
||
|
||
if( GSTREAMERAPP_FOUND ) | ||
if( NOT TARGET GSTREAMERAPP::gstreamerapp ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pedantic: alignment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. I would just ask that you apply the .clang-format
rules found in the root of the repo, along with the other formatting in CMake files
|
||
if ( numBytesRequested ) | ||
{ | ||
tGstPtr<GstElement> sink( gst_bin_get_by_name( GST_BIN( m_pipeline.get() ), "sink" ), gst_object_unref ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to store the sink pointer somewhere instead of retrieving it all the time
{ | ||
pcm::number_type number_type = gst_format_char_to_number_type( format[0] ); | ||
auto srcDepth = std::atol( format + 1 ); | ||
auto endian = ( strcmp( format, "BE" ) == 0 ) ? pcm::big_endian : pcm::little_endian; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably want to use GstAudioInfo
here and in the function above. it gives you a simple C struct with all these information you want to extract from the caps. Also check the GstAudioFormatInfo
that is part of the GstAudioInfo
.
if ( wait_for_async_operation() != GST_STATE_PAUSED ) | ||
throw std::runtime_error( "gstreamer_file_source: pipeline doesn't preroll into paused state" ); | ||
|
||
gst_element_set_state( m_pipeline.get(), GST_STATE_PLAYING ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check return value
|
||
void gstreamer_file_source::preroll_pipeline() | ||
{ | ||
gst_element_set_state( m_pipeline.get(), GST_STATE_PAUSED ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check return value
|
||
gst_bin_add_many( GST_BIN( m_pipeline.get() ), source, decodebin, queue, sink, nullptr ); | ||
gst_element_link_many( source, decodebin, NULL ); | ||
gst_element_link_many( queue, sink, NULL ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
best to check return values, things can fail
auto sinkpad = gst_element_get_static_pad( sink, "sink" ); | ||
auto caps = gst_pad_get_current_caps( sinkpad ); | ||
auto caps_struct = gst_caps_get_structure( caps, 0 ); | ||
fill_format_info( caps_struct, container ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're leaking the caps and sinkpad here.
gstreamer_file_source::~gstreamer_file_source() | ||
{ | ||
gst_element_set_state( m_pipeline.get(), GST_STATE_NULL ); | ||
wait_for_async_operation(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Downwards state change is always sync
@hhoegelo Can you explain the easiest way to reproduce the 1-sample-off problem and what information you gathered so far? If I understand correctly, this happens on specific files (WMA? Or everything? All WMA files or a specific one?) and if you decode from the beginning vs. you seek to a position, you would end up one sample off? Is it always absolutely one sample, or would it sometimes be more or less, or would every seek make it one more sample off? Re main loop: this is not required, correct. You have multiple options, but first of all: why do you care? You want to block until error or reading samples is possible? And then blocking-read the samples?
From what I saw in the code so far I would suggest a combination of 1) and 3). You block until error or the sink is ready (you received the |
Sorry if some comments appeared twice, GitHub had some kind of hickup while I was doing the review and returned a few server errors |
thanks for the thorough look @sdroege really appreciate seeing this level of collab |
… library this is the initial revision, tests are not yet green, to be continued
1c58318
to
54ea50d
Compare
gst_element_set_state( m_pipeline.get(), GST_STATE_PAUSED ); | ||
|
||
if ( wait_for_async_operation() != GST_STATE_PAUSED ) | ||
throw std::runtime_error( "gstreamer_file_source: pipeline doesn't preroll into paused state" ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line randomly throws. There seems to be a race condition when setting / checking the state
@hhoegelo can you please pull in my branch https://github.com/marcrambo/ni-media/tree/feature-add-linux-gstreamer-support? I reenabled the tests and commited a fix for all the tests failing due to an exception thrown while retrieving the track length. Also I improved the logging so we have a better overview of which tests are still failing. |
@sdroege Thanks a lot for your help which is really greatly appreciated! I was wondering if it was possible to run gstreamer in "synchronous" mode i.e. without having to do "preroll pipeline" and so on. Calls to |
@marcrambo That's exactly how it would behave with my suggestion (1 + 3) from comment #11 (comment) While GStreamer is always async to some degree, there is API that makes it easy enough to build a sync API on top |
If you like, you can pull my attempt of adding mp3, m4a, alac and wma support on linux platform by using gstreamer framework. I didn't manage to have all tests green, though. For example, the 'interlaced_by_67_frames'-tests are off by 1 sample, which I - so far - couldn't find a reason for.
Most likely other people won't notice my fork. I hope, if you pull it into the base fork, we have a higher chance that anyone can help fixing.