Delay on Gstreamer video rendering - rtsp

I am working on an Gstreamer application that renders decoded frames. The input is from another application (gets frames from a network camera) that gives .H264 encoded frames.
The gstreamer pipeline I use is as follows:
appsrc ! h264parse ! avdec_h264 ! videoconvert ! ximagesink
The appsrc creates the GstBuffer and timestamps it, starting from 0.
The rendered output seems approx. 2seconds delayed.
How do I reduce the latency in this case?
Any help is appreciated.
The appsrc's properties are set (using gst_object_set() )as below:
stream-type = 0
format = GST_FORMAT_TIME
is-live = true
max-latency = 0
min-latency = 0
Update:
I tried sending a latency event of -2 seconds (experimental) to the pipeline
GstClockTime latency = (-2 * gst_util_uint64_scale_int (1, GST_SECOND, 1));
GstEvent *event = gst_event_new_latency (latency);
gst_element_send_event (pipeline, event);
This did not help, it made the output really choppy.

As of now, this is my best answer.
Use do-timestamp property of appsrc Gstreamer element.
This eliminated the latency to almost <200ms.

Related

AVCaptureSession audio samples captured at different frequency than AVAudioSession's sample rate

I'm using AVFoundation capture session to output audio buffers through AVCaptureAudioDataOutput. The capture session is using the default application audio session. (ie. captureSession.usesApplicationAudioSession = true). I don't alter the audio session in any way.
The strange behavior is that the capture session returns audio buffers captured at a different frequency than the default audio session's sample rate.
Specifically:
print(AVAudioSession.sharedInstance().sampleRate) \\ 48000
but
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
if connection.audioChannels.first != nil {
print(sampleBuffer.presentationTimeStamp) \\ CMTime(value: 2199812320, timescale: 44100, flags: __C.CMTimeFlags(rawValue: 3), epoch: 0)
delegate?.captureOutput(sampleBuffer: sampleBuffer, mediaType: .audio)
}
}
My expected behavior is that the sample buffer's timescale would also be 48000.
For a little extra info, if I do change the default audio session, for example, change preferred sample rate to 48000, the sample buffer's timescale will change to 48000 as expected. Is this a bug or am I misunderstanding something?
You need to set the capture session's automaticallyConfiguresApplicationAudioSession to false and do your own audio session configuration before starting the capture session.
Like this:
// use audioSession.setPreferredSampleRate() to request desired sample rate
captureSession.automaticallyConfiguresApplicationAudioSession = false
try! AVAudioSession.sharedInstance().setCategory(.playAndRecord) // or just record
try! AVAudioSession.sharedInstance().setActive(true) // worked without this, but feels wrong

Gstreamer custom videosink for playbin

I'm trying to create a custom videosink for playbin in gstreamer 1.6.3
The final idea is to have some videomixer inside the videosink to be able to do.. stuff.
At the moment i would like to simply create a custom Bin that incapsulates a videosink.
The relevant parts of the code at the moment are:
def get_videomix_bin(self):
mix_bin = Gst.Bin.new('sink')
sink = Gst.ElementFactory.make('glimagesink')
gp = Gst.GhostPad.new('vs', sink.get_static_pad('sink'))
mix_bin.add(sink)
mix_bin.add_pad(gp)
return mix_bin
def get_pipeline(self, videosink):
"""A basic playbin pipeline pipeline"""
self.pipeline = Gst.ElementFactory.make('playbin')
videosink = self.get_videomix_bin()
self.pipeline.set_property('video-sink', videosink)
self.fireEvent('pipeline-created')
This code is part of a bigger software that I cannot post whole. But if i comment out the self.pipeline.set_property('video-sink', videosink) part, it works, so i tend to think that the problem is somwhere there.
It... well it basically don't work. The pipeline won't start.
At GST_DEBUG=2 i get this warning
0:00:00.758103367 15560 0x7f81000050a0 WARN uridecodebin gsturidecodebin.c:939:unknown_type_cb:<uridecodebin0> warning: No decoder available for type 'video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)3.1, profile=(string)main, codec_data=(buffer)014d401fffe1001c674d401fe8802802dd80b501010140000003004000000c83c60c448001000468ebaf20, width=(int)1280, height=(int)720, framerate=(fraction)25/1, pixel-aspect-ratio=(fraction)1/1, parsed=(boolean)true'.
You have to call the ghostpad on the videosink bin "sink", not "vs". The pad names are part of the API, and sink elements are expected to have a pad called "sink".

Linux ALSA Driver using channel count 3

Am running my ALSA Driver on Ubuntu 14.04, 64bit, 3.16.0-30-generic Kernel.
Hardware is proprietary hardware, hence cant give much details.
Following is the existing driver implementation:
Driver is provided sample format, sample rate, channel_count as input via module parameter. (Due to requirements need to provide inputs via module parameters)
Initial snd_pcm_hardware structure for playback path.
#define DEFAULT_PERIOD_SIZE (4096)
#define DEFAULT_NO_OF_PERIODS (1024)
static struct snd_pcm_hardware xxx_playback =
{
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_SYNC_START,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = (SNDRV_PCM_RATE_8000 | \
SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_96000),
.rate_min = 8000,
.rate_max = 96000,
.channels_min = 1,
.channels_max = 1,
.buffer_bytes_max = (DEFAULT_PERIOD_SIZE * DEFAULT_NO_OF_PERIODS),
.period_bytes_min = DEFAULT_PERIOD_SIZE,
.period_bytes_max = DEFAULT_PERIOD_SIZE,
.periods_min = DEFAULT_NO_OF_PERIODS,
.periods_max = DEFAULT_NO_OF_PERIODS,
};
Similar values for captures side snd_pcm_hardware structure.
Please, note that the following below values are replaced in playback open entry point, based on the current audio test configuration:
(user provides audio format, audio rate, ch count via module parameters as inputs to the driver, which are refilled in snd_pcm_hardware structure)
xxx_playback.formats = user_format_input
xxx_playback.rates = xxx_playback.rate_min, xxx_playback.rate_max = user_sample_rate_input
xxx_playback.channels_min = xxx_playback.channels_max = user_channel_input
Similarly values are re-filled for capture snd_pcm_hardware structure in capture open entry point.
Hardware is configured for clocks based on channel_count, format, sample_rate and driver registers successfully with ALSA layer
Found aplay/arecord working fine for channel_count = 1 or 2 or 4
During aplay/arecord, in driver when "runtime->channels" value is checked, it reflects the channel_count configured, which sounds correct to me.
Record data matches with played, since its a loop back test.
But when i use channel_count = 3, Both aplay or arecord reports
"Broken configuration for this PCM: no configurations available"!! for a wave file with channel_count '3'
ex: Playing WAVE './xxx.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Channels 3
ALSA lib pcm_params.c:2162:(snd1_pcm_hw_refine_slave) Slave PCM not usable
aplay: set_params:1204: Broken configuration for this PCM: no configurations available
With Following changes I was able to move ahead a bit:
.........................
Method1:
Driver is provided channel_count '3' as input via module parameter
Modified Driver to fill snd_pcm_hardware structure as payback->channels_min = 2 & playback->channels_min = 3; Similar values for capture path
aplay/arecord reports as 'channel count not available', though the wave file in use has 3 channels
ex: aplay -D hw:CARD=xxx,DEV=0 ./xxx.wav Playing WAVE './xxx.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Channels 3
aplay: set_params:1239: Channels count non available
Tried aplay/arecord with plughw, and aplay/arecord moved ahead
arecord -D plughw:CARD=xxx,DEV=0 -d 3 -f S16_LE -r 48000 -c 3 ./xxx_rec0.wav
aplay -D plughw:CARD=xxx,DEV=0 ./xxx.wav
Recording WAVE './xxx_rec0.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Channels 3
Playing WAVE './xxx.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Channels 3
End of Test
During aplay/arecord, In driver when "runtime->channels" value is checked it returns value 2!!! But played wavefile has ch count 3...
When data in recorded file is checked its all silence
.........................
Method2:
Driver is provided channel_count '3' as input via module parameter
Modified Driver to fill snd_pcm_hardware structure as playback->channels_min = 3 & playback->channels_min = 4; Similar values for capture path
aplay/arecord reports as 'channel count not available', though the wave file in use has 3 channels
Tried aplay/arecord with plughw, and aplay/arecord moved ahead
During aplay/arecord, In driver when "runtime->channels" value is checked it returns value 4!!! But played wavefile has ch count 3...
When data in recorded file is checked its all silence
.........................
So from above observations, the runtime->channels is either 2 or 4, but never 3 channels was used by alsa stack though requested. When used Plughw, alsa is converting data to run under 2 or 4 channel.
Can anyone help why am unable to use channel count 3.
Will provide more information if needed.
Thanks in Advance.
A period (and the entire buffer) must contain an integral number of frames, i.e., you cannot have partial frames.
With three channels, one frame has six bytes. The fixed period size (4096) is not divisible by six without remainder.
Thanks CL.
I used period size 4092 for this particular test case with channel count 3, and was able to do loop back successfully (without using plughw).
One last question, when I used plughw earlier, and when runtime->channels was either 2 or 4, why was the recorded data not showing?

RaspBerry pi B rev2 - Issue while sampling a LM335 (temp. sensor) thru a MCP3208 ADC via SPI in Python 3

I tried to interface a RaspBerry pi with a LM335 temperature sensor this week-end. I'm using a MCP 3208 micro controller (channel 0) to interface the sensor. My goal is to collect samples data in SPI mode with python 3 scripts (classes).
I've checked the wiring and everything seems OK for me, I'but I'am a beginner, not really aware of Electronic concepts.
On the software side , I've installed quick2wire that claims to be python 3 compatible. In fact I want to lead the micro-controller with Python 3 API's (not thru shell calls)
Components
Raspberry pi REV2 model B with Rasbian-wheezy / Quick2wire installed. /dev/spix.y devices are listed.
MCP3208 ADC : 12 bits ADC / SPI. I'm using CS0 from the GPIO. The sensor is connected to channel 0 (B). see datasheet.
LM335 : temperature sensor. Outputs 10mV / °K. Min 5muA / Max 5 mA. It's connected to the MCP3208 channel #0 (A). see datasheet
220 ohms resistor (C). set up regarding LM335 outputs and desired temperature range coverage with my own calculations : May be a problem ...
Schematics extract
The LM335 (zener diode like) is connected as :
Wiring
Components are wired as shown bellow. Note that the yellow link is connected behind the cobbler kit on the CS0 SPI channel.
Quick2wire
I use the bellow script to query the CS0/Channel 0 GPIO interface. Unfortunately, I've not found usefull informations on the quick2wire-python-api API's. I've just copy/paste an example found as it was written in the same goal. I'm not sure if it really works :
#!/usr/bin/env python3
from quick2wire.spi import *
import sys, time
try:
channel = int(sys.argv[1])
except:
channel = 0
MCP3208 = SPIDevice(channel, 0)
while True:
try:
response = MCP3208.transaction(writing_bytes(0x41, 0x13), reading(1))
print ("output = %i" % ord(response[0]))
time.sleep(1)
except KeyboardInterrupt:
break
The script outputs :
output = 0
output = 0
output = 0
output = 0
output = 0
....
The result is the same with the channel 1 ( with argv = 1)
As the MCP3208 Din (probe output) receives voltage (see bellow) quick2wire should read at 18°C (rawghly my home inside temperature today)
3,3 V / 2^12 = 805 muA as I understand as "digital step"
18°C + 273°C = 291 => 2,91 V on the micro controller Din pin
and then return 2 910 / 0.805 = 3 615
Am I wrong ?
Controls
I've no oscilloscope, the only measures I can read are :
Voltage is 2.529 V at B checkpoint and 0,5 V (+/-5%) on the other MCP3208 channels
Note : the adjust pin is not used on the LM335 so results way not be accurate but voltage is here !
Seems to be a problem on the quick2wire side I think. But which ?
Code
The quick2wire.spi.SPIDevice class lakes of détails on the transfers parameter in terms of structure, content and output response format.
def transaction(self, *transfers):
"""
Perform an SPI I/O transaction.
Arguments:
*transfers -- SPI transfer requests created by one of the reading,
writing, writing_bytes, duplex or duplex_bytes
functions.
Returns: a list of byte sequences, one for each read or duplex
operation performed.
"""
transfer_count = len(transfers)
ioctl_arg = (spi_ioc_transfer*transfer_count)()
# populate array from transfers
for i, transfer in enumerate(transfers):
ioctl_arg[i] = transfers[i].to_spi_ioc_transfer()
ioctl(self.fd, SPI_IOC_MESSAGE(transfer_count), addressof(ioctl_arg))
return [transfer.to_read_bytes() for t in transfers if t.has_read_buf]
Another question :
how to set SPI configuration values like mode, clock speed, bits per word, LSB ... and so on.
Thanks in advance for your help.
I know you probably intend to learn how to use the ADC, an so this isn't really an answer to your question (I will use your very rich post for sure - thanks), but I'm aware of temperature sensors that already pack data in GPIO serial line, that are best suited for the raspberry.
You really have to read this awesome tutorial, if you haven't already.

GStreamer Custom-Plugin and alsasink Unable to Detect Format

I'm developing a GStreamer plugin following the GStreamer Plugin Writer's Guide and using gst-element-maker from the gst-plugins-bad repository with the base class set to basetransform. As a starting point I have developed a plugin named MyFilter that simply passes the data along the chain. The plugin is working, but when I run gst-launch with the debug level set to 2, I get the following error:
alsa gstalsa.c:124:gst_alsa_detect_formats: skipping non-int format.
I am executing the command:
gst-launch --gst-debug-level=2 --gst-plugin-load=./src/libgstmyfilter.la filesrc location=./song.mp3 ! flump3dec ! audioconvert ! audioresample ! myfilter ! alsasink
From the base class that was created by gst-element-maker I have removed calls to gst_pad_new_from_static_template() because the calls were returning errors reporting that the sink and source pad were already created, I have set the chain function using gst_pad_set_chain_function(), have implemented the function gst_myfilter_transform_caps(), and have added code to handle the GST_EVENT_NEWSEGMENT event. The STATIC_CAPS string I am using for source and sink are:
"audio/x-raw-int, "
"rate = (int) { 16000, 32000, 44100, 48000 }, "
"channels = (int) [ 1, 2 ], "
"endianness = (int) BYTE_ORDER, "
"signed = (boolean) true, "
"width = (int) 16, "
"depth = (int) 16"
I return the caps from gst_myfilter_transform_caps() using gst_pad_get_fixed_caps_func(GST_BASE_TRANSFORM_SRC[[/SINK]]_PAD(trans)). The pad caps are set using the default code created by gst-element-maker in gst_myfilter_base_init() using:
gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&gst_myfilter_sink_template));
Is there a problem with the GstBaseTransform class? I have another custom filter which does not use the GstBaseTransform class and does not have this problem. I am using GStreamer v0.10.36 with Ubuntu 12.04.

Resources