Gstreamer splitmuxsink callback when a new file is created - callback

I have a gst pipeline for recording video with splitmuxsink set to create new file every hour. I would like to have some callback when the new file is created.
I have tried
GstElement *sink = gst_element_factory_make ("splitmuxsink", "sink");
g_object_set (sink, "max-size-bytes", 4294967295, NULL);
g_object_set (sink, "max-size-time", 3600000000000, NULL); // 3600000000000 - 1 hour
g_signal_connect (sink, "split-now",G_CALLBACK(split_now_callback_test), &data);
However i found out, that "split-now" is signal which I can pass to the splitmuxsink and not the other way around. Is there a relatively easy way to have some callback a new target file is created?

There is a message that is emitted by the splitmuxsink element when it opens or closes a new fragment: "splitmuxsink-fragment-opened" or "splitmuxsink-fragment-closed". I found these messages in the splitmuxsink source code (search for the gst_element_post_message function call to see where the message is sent).
Here's an SO question about of listening for element messages (from the multifilesink element, which is very similar to the splitmuxsink element). In particular, see this gist from the OP on that question for an example of how to implement this in C.
I didn't validate that the approach above works in C, as I used this splitmuxsink message in a Rust implementation of the pipeline, but I think the general idea, translated to C, is something like this (adapted from GStreamer basic tutorial #3):
/* Listen to the bus */
bus = gst_element_get_bus (data.pipeline);
do {
msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ELEMENT | GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
/* Parse message */
if (msg != NULL) {
GError *err;
gchar *debug_info;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error (msg, &err, &debug_info);
g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
g_clear_error (&err);
g_free (debug_info);
terminate = TRUE;
break;
case GST_MESSAGE_EOS:
g_print ("End-Of-Stream reached.\n");
terminate = TRUE;
break;
case GST_MESSAGE_ELEMENT:
/* Handle element-specific message here */
break;
default:
/* We should not reach here */
g_printerr ("Unexpected message received.\n");
break;
}
gst_message_unref (msg);
}
} while (!terminate);
For more info on element messages and the GstBus, see this page of the GStreamer docs

Related

WSAEventSelect() makes a socket descriptor no longer a socket

I am writing a cross-platform socket handling library (which also handles serial and a whole bunch of other protocols in a protocol agnostic way. - I am not re-inventing the wheel).
I need to emulate the Linux poll function. The code I started with used select and worked fine, but there was no way to interrupt it from another thread, and so I was forced to start using event objects. My initial attempt called:
WSACreateEvent()
WSAEventSelect() to associate the socket with the event object.
WaitForMultipleObjectsEx() to wait on all sockets plus my interrupt event object.
select() to work out what events actually occurred on the socket.
accept()/send()/recv() to process the sockets (later and elsewhere).
This failed. accept() was claiming that the file descriptor was not a socket. If I commented out the call to WSAEventSelect(), essentially reverting to my earlier code, it all works fine (except that I cannot interrupt).
I then realised that I did something wrong (according to the Microsoft dictatorship). Instead of using select() to work out what events have happened on each socket, I should be using WSAEnumNetworkEvents(). So I rewrote my code to do it the proper way, remembering to call WSAEventSelect() afterwards to disassociate the event object from the file descriptor so that (fingers crossed) accept() would now work.
Now WSAEnumNetworkEvents() is returning an error and WSAGetLastError() tells me that the error is WSAENOTSOCK.
This IS a socket. I am doing things the way MSDN tells me I should (allowing for the general poor quality of the documentation). It appears however that WSAEventSelect() is causing the file descriptor to be marked as a file rather than a socket.
I hate Microsoft so much right now.
Here is a cut down version of my code:
bool do_poll(std::vector<struct pollfd> &poll_data, int timeout)
{
...
for (const auto &fd_data : poll_data) {
event_mask = 0;
if (0 != (fd_data.events & POLLIN)) {
// select() will mark a socket as readable when it closes (read size = 0) or (for
// a listen socket) when there is an incoming connection. This is the *nix paradigm.
// WSAEventSelect() hasseparate events.
event_mask |= FD_READ;
event_mask |= FD_ACCEPT;
event_mask |= FD_CLOSE;
}
if (0 != (fd_data.events & POLLOUT)) {
event_mask |= FD_WRITE;
}
event_obj = WSACreateEvent();
events.push_back(event_obj);
if (WSA_INVALID_EVENT != event_obj) {
(void)WSAEventSelect((SOCKET)fd_data.fd, event_obj, event_mask);
}
}
lock.lock();
if (WSA_INVALID_EVENT == interrupt_obj) {
interrupt_obj = WSACreateEvent();
}
if (WSA_INVALID_EVENT != interrupt_obj) {
events.push_back(interrupt_obj);
}
lock.unlock();
...
(void)WaitForMultipleObjectsEx(events.size(), &(events[0]), FALSE, dw_timeout, TRUE);
for (i = 0u; i < poll_data.size(); i++) {
if (WSA_INVALID_EVENT == events[i]) {
poll_data[i].revents |= POLLERR;
} else {
if (0 != WSAEnumNetworkEvents((SOCKET)(poll_data[i].fd), events[i], &revents)) {
poll_data[i].revents |= POLLERR;
} else {
if (0u != (revents.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))) {
poll_data[i].revents |= POLLIN;
}
if (0u != (revents.lNetworkEvents & FD_WRITE)) {
poll_data[i].revents |= POLLOUT;
}
}
(void)WSAEventSelect((SOCKET)(poll_data[i].fd), NULL, 0);
(void)WSACloseEvent(event_obj);
}
}
...
}

Read all available bytes from TCP Socket (unknown byte count)

I am having Problems useing the Indy TIdTCPClient.
I want to call a function, everytime if there is Data available on the socket. For this I have a Thread calling IdTCPClient->Socket->Readable(100).
The function itself looks like this:
TMemoryStream *mStream = new TMemoryStream;
int len = 0;
try
{
if(!Form1->IdTCPClient2->Connected())
Form1->IdTCPClient2->Connect();
mStream->Position = 0;
do
{
Form1->IdTCPClient2->Socket->ReadStream(mStream, 1);
}
while(Form1->IdTCPClient2->Socket->Readable(100));
len = mStream->Position;
mStream->Position = 0;
mStream->Read(Buffer, len);
}catch(Exception &Ex) {
Form1->DisplaySSH->Lines->Add(Ex.Message);
Form1->DisplaySSH->GoToTextEnd();
}
delete mStream;
It will not be called directly within the thread, but the thread triggers an event, which is calling this function. Which means I am using Readable(100) twice, without reading data in betwee.
So since I dont know how many bytes I have to read I thought I can read one byte, check if there is more available and then read another byte.
The Problem here is that the do while loop doesnt loop, it just runs once.
I am guessing that Readable does not quite wokt the way I need it to.
Is there any other way to receive all the bytes available in the Socket?
You should not be using Readable() directly in this situation. That call reports whether the underlying socket has pending unread data in its internal kernel buffer. That does not take into account that the TIdIOHandler may already have unread data in its InputBuffer that is left over from a previous read operation.
Use the TIdIOHandler::CheckForDataOnSource() method instead of TIdIOHandler::Readable():
TMemoryStream *mStream = new TMemoryStream;
try
{
if (!Form1->IdTCPClient2->Connected())
Form1->IdTCPClient2->Connect();
mStream->Position = 0;
do
{
if (Form1->IdTCPClient2->IOHander->InputBufferIsEmpty())
{
if (!Form1->IdTCPClient2->IOHander->CheckForDataOnSource(100))
break;
}
Form1->IdTCPClient2->IOHandler->ReadStream(mStream, Form1->IdTCPClient2->IOHandler->InputBuffer->Size, false);
/* alternatively:
Form1->IdTCPClient2->IOHandler->InputBuffer->ExtractToStream(mStream);
*/
}
while (true);
// use mStream as needed...
}
catch (const Exception &Ex) {
Form1->DisplaySSH->Lines->Add(Ex.Message);
Form1->DisplaySSH->GoToTextEnd();
}
delete mStream;
Or, you can alternatively use TIdIOHandler::ReadBytes() instead of TIdIOHandler::ReadStream(). If you set its AByteCount parameter to -1, it will return only the bytes that are currently available (if the InputBuffer is empty, ReadBytes() will wait up to the ReadTimeout interval for the socket to receive any new bytes) 1:
try
{
if (!Form1->IdTCPClient2->Connected())
Form1->IdTCPClient2->Connect();
TIdBytes data;
do
{
if (Form1->IdTCPClient2->IOHander->InputBufferIsEmpty())
{
if (!Form1->IdTCPClient2->IOHander->CheckForDataOnSource(100))
break;
}
Form1->IdTCPClient2->IOHandler->ReadBytes(data, -1, true);
/* alternatively:
Form1->IdTCPClient2->IOHandler->InputBuffer->ExtractToBytes(data, -1, true);
*/
}
while (true);
// use data as needed...
}
catch (const Exception &Ex) {
Form1->DisplaySSH->Lines->Add(Ex.Message);
Form1->DisplaySSH->GoToTextEnd();
}
1: make sure you are using an up-to-date snapshot of Indy 10. Prior to Oct 6 2016, there was a logic bug in ReadBytes() when AByteCount=-1 that didn't take the InputBuffer into account before checking the socket for new bytes.

Winsock: DisconnectEx with IO Completion port

NB: the OP confirms in the comment thread that the problem was due to a typo, not shown in the posted code.
I was expecting to get a notification using GetQueuedCompletionStatus after scheduling an overlapped disconnect with DisconnectEx. I never get one - is this by design? If I specify a manual reset event in the OVERLAPPED structure this is signalled to indicate that the disconnect is complete, but GetQueuedCompletionStatus never returns.
My call to DisconnectEx looks a bit like this (note that context has an operator LPOVERLAPPED and ol is the first element in the structure):
context.ol.hEvent = hEvent;
BOOL result = DisconnectEx(context.socket, context, TF_REUSE_SOCKET, 0);
if (result)
{
// we completed synchronously:
ProcessCompletion(0, context, 0);
}
else
{
int error = WSAGetLastError();
if (error != ERROR_IO_PENDING)
{
throw ServerSocketException("DisconnectEx failed");
}
WaitForSingleObject(hEvent, INFINITE);
std::cout << "disconnected - event signalled\n";
}
I added the WaitForSingleObject when I found that GetQueuedCompletionStatus didn't return. What is the correct way to detect DisconnectEx completing? I want to use the socket again in a call to AcceptEx.
It appears that this was because of a typo on the OP's part.
(Posting an answer so other people don't have to read the comment thread...)

GStreamer - Sample Plugin

I am a newbie in gstreamer and trying to develop a sample plugin for captions decoding.
I have downloaded the gStreamer Plugin template: based on this information.
When I launched the plugin from command line, it is working fine.
I wrote a sample application to verify the plugin. But now, I am facing a problem in setting pipeline state to PLAYING. Below is the code snippet
Any inputs would be of great help.
Thanks in advance,
Kranti
gst_init(NULL, NULL);
loop = g_main_loop_new (NULL, TRUE);
g_print("\n Gstreamer is Initialized and Created the loop ");
pipeline = gst_pipeline_new ("pipeline");
source = gst_element_factory_make ("filesrc", "source");
filter = gst_element_factory_make ("myfilter", "testfilter");
sink = gst_element_factory_make ("fakesink", "sink");
if((NULL != pipeline) && (NULL != source) && (NULL != filter) && (NULL != sink))
{
g_print("\n Successfully created the factory elements ");
g_object_set(G_OBJECT (source), "location", fileName, NULL);
g_print("\n Set the file name \n");
g_object_set(G_OBJECT (filter), "silent", 1, NULL);
g_print("\n Set the silent type \n");
/* we add a message handler */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
g_print("\n Created bus and a monitor to watch it");
gst_bin_add_many(GST_BIN(pipeline), source, filter, sink, NULL);
gst_element_link_many(source, filter, sink);
g_print("\n Added and Linked the factory elements");
g_signal_connect (filter, "pad-added", G_CALLBACK (on_pad_added), filter);
g_print ("Now reading: %s\n", "test.txt");
g_print ("Setting the pipeline state to PLAYING ");
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
if(ret == GST_STATE_CHANGE_FAILURE)
{
g_print("\n Failure in setting pipeline state to PLAYING \n");
}
else
{
g_print("\n Successfully set the pipeline state to playing \n");
}
}
else
{
g_print("\n Failure in creating factory elements");
}
After trying with few examples on gstreamer elements, found the problem.
Apart from filesrc, filter, fakesink:: If I add 'decoder' element also to the pipeline, then I am able to change the state to PLAYING
But why is that required - I am still trying to figure it out
And sometimes, the name used to create pipeline is also causing problems: Better to use some unique name rather than pipeline in gst_pipeline_new ("pipeline");

Data is getting discarded in TCP/IP with boost::asio::read_some?

I have implemented a TCP server using boost::asio. This server uses basic_stream_socket::read_some function to read data. I know that read_some does not guarantee that supplied buffer will be full before it returns.
In my project I am sending strings separated by a delimiter(if that matters). At client side I am using WinSock::send() function to send data. Now my problem is on server side I am not able to get all the strings which were sent from client side. My suspect is that read_some is receiving some data and discarding leftover data for some reason. Than again in next call its receiving another string.
Is it really possible in TCP/IP ?
I tried to use async_receive but that is eating up all my CPU, also since buffer has to be cleaned up by callback function its causing serious memory leak in my program. (I am using IoService::poll() to call handler. That handler is getting called at a very slow rate compared to calling rate of async_read()).
Again I tried to use free function read but that will not solve my purpose as it blocks for too much time with the buffer size I am supplying.
My previous implementation of the server was with WinSock API where I was able to receive all data using WinSock::recv().
Please give me some leads so that I can receive complete data using boost::asio.
here is my server side thread loop
void
TCPObject::receive()
{
if (!_asyncModeEnabled)
{
std::string recvString;
if ( !_tcpSocket->receiveData( _maxBufferSize, recvString ) )
{
LOG_ERROR("Error Occurred while receiving data on socket.");
}
else
_parseAndPopulateQueue ( recvString );
}
else
{
if ( !_tcpSocket->receiveDataAsync( _maxBufferSize ) )
{
LOG_ERROR("Error Occurred while receiving data on socket.");
}
}
}
receiveData() in TCPSocket
bool
TCPSocket::receiveData( unsigned int bufferSize, std::string& dataString )
{
boost::system::error_code error;
char *buf = new char[bufferSize + 1];
size_t len = _tcpSocket->read_some( boost::asio::buffer((void*)buf, bufferSize), error);
if(error)
{
LOG_ERROR("Error in receiving data.");
LOG_ERROR( error.message() );
_tcpSocket->close();
delete [] buf;
return false;
}
buf[len] ='\0';
dataString.insert( 0, buf );
delete [] buf;
return true;
}
receiveDataAsync in TCP Socket
bool
TCPSocket::receiveDataAsync( unsigned int bufferSize )
{
char *buf = new char[bufferSize + 1];
try
{
_tcpSocket->async_read_some( boost::asio::buffer( (void*)buf, bufferSize ),
boost::bind(&TCPSocket::_handleAsyncReceive,
this,
buf,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred) );
//! Asks io_service to execute callback
_ioService->poll();
}
catch (std::exception& e)
{
LOG_ERROR("Error Receiving Data Asynchronously");
LOG_ERROR( e.what() );
delete [] buf;
return false;
}
//we dont delete buf here as it will be deleted by callback _handleAsyncReceive
return true;
}
Asynch Receive handler
void
TCPSocket::_handleAsyncReceive(char *buf, const boost::system::error_code& ec, size_t size)
{
if(ec)
{
LOG_ERROR ("Error occurred while sending data Asynchronously.");
LOG_ERROR ( ec.message() );
}
else if ( size > 0 )
{
buf[size] = '\0';
emit _asyncDataReceivedSignal( QString::fromLocal8Bit( buf ) );
}
delete [] buf;
}
Client Side sendData function.
sendData(std::string data)
{
if(!_connected)
{
return;
}
const char *pBuffer = data.c_str();
int bytes = data.length() + 1;
int i = 0,j;
while (i < bytes)
{
j = send(_connectSocket, pBuffer+i, bytes-i, 0);
if(j == SOCKET_ERROR)
{
_connected = false;
if(!_bNetworkErrNotified)
{
_bNetworkErrNotified=true;
emit networkErrorSignal(j);
}
LOG_ERROR( "Unable to send Network Packet" );
break;
}
i += j;
}
}
Boost.Asio's TCP capabilities are pretty well used, so I would be hesitant to suspect it is the source of the problem. In most cases of data loss, the problem is the result of application code.
In this case, there is a problem in the receiver code. The sender is delimiting strings with \0. However, the receiver fails to proper handle the delimiter in cases where multiple strings are read in a single read operation, as string::insert() will cause truncation of the char* when it reaches the first delimiter.
For example, the sender writes two strings "Test string\0" and "Another test string\0". In TCPSocket::receiveData(), the receiver reads "Test string\0Another test string\0" into buf. dataString is then populated with dataString.insert(0, buf). This particular overload will copy up to the delimiter, so dataString will contain "Test string". To resolve this, consider using the string::insert() overload that takes the number of characters to insert: dataString.insert(0, buf, len).
I have not used the poll function before. What I did is create a worker thread that is dedicated to processing ASIO handlers with the run function, which blocks. The Boost documentation says that each thread that is to be made available to process async event handlers must first call the io_service:run or io_service:poll method. I'm not sure what else you are doing with the thread that calls poll.
So, I would suggest dedicating at least one worker thread for the async ASIO event handlers and use run instead of poll. If you want that worker thread to continue to process all async messages without returning and exiting, then add a work object to the io_service object. See this link for an example.