Alsa Buffer overrun while playback of audio - buffer

I have connected IMX board to pc back to back.
I am running a binary in board which sends audio frames every 5.7ms with 1024 bytes.
The pc receives the frames and writes using
printf("snd_pcm_avail %d \n",snd_pcm_avail (FMWK.FMWK_Handler.playback_handle));
err = snd_pcm_writei(FMWK.FMWK_Handler.playback_handle, OutputPointer, PERIOD_BYTES);
When the playback is happening, after every 6seconds i get broken pipe
Logs when sucessful playback is running
snd_pcm_avail 32
snd_pcm_avail 17
snd_pcm_avail 81
snd_pcm_avail 25
snd_pcm_avail 89
snd_pcm_avail 32
snd_pcm_avail 17
snd_pcm_avail 81
snd_pcm_avail 32
snd_pcm_avail 17
snd_pcm_avail 81
snd_pcm_avail 25
snd_pcm_avail 89
snd_pcm_avail 32
snd_pcm_avail 17
snd_pcm_avail 81
Approximately it is decreasing by 56
When after 5 seconds the avail increases and the buffer overflows the configured limit of buffer_size=256
Logs:
snd_pcm_avail 89
snd_pcm_avail 112
snd_pcm_avail 96
snd_pcm_avail 120
snd_pcm_avail 104
snd_pcm_avail 129
snd_pcm_avail 153
snd_pcm_avail 137
snd_pcm_avail 160
snd_pcm_avail 184
snd_pcm_avail 168
snd_pcm_avail 193
snd_pcm_avail 176
snd_pcm_avail 201
snd_pcm_avail 224
snd_pcm_avail 209
snd_pcm_avail 232
snd_pcm_avail 217
snd_pcm_avail 240
snd_pcm_avail -32
(AVB Info) 12:26:11 PM.606306 (Slave) ==> Broken pipe
snd_pcm_avail 256
snd_pcm_avail 48
I have set period_size as 128
I am not sure whether iam missing something in initial configuration of snd_pcm? It is 44.1khz audio.

What happens there is, that your program can not keep up with the playback of the PCM data by the device. When the "Broken pipe" happens the audio device it waiting for new samples, but your program didn't deliver them in time.
The situation you ran into is the bane of online audio systems; unfortunately the existing Linux audio architecture (ALSA) does not a very good job; PulseAudio + RealtimeKit tried (IMHO not very successfully) to plaster over the cracks, by doing weird and crazy voodoo to not starve ALSA drivers; things get not better by some drivers being broken and not reporting the position of the playback head properly.
In your case here are two things you can do:
Use larger frames (more samples in a buffer)
Queue more frames (queue several buffers) and keep a minimum number of frames in the queue

Audio devices typically have their own sample clock which is not synchronized with the system clock.
So you cannot use the system clock to control how fast to send samples to the device; it will run either too fast or too slow on almost all systems.
To send samples at the correct speed, just try to write your samples as fast as possible; snd_pcm_write* will automatically wait if the buffer is full.
If you cannot control the sender's speed from the receiver (because they are not on the same machine, and you do not have a protocol that provides feedback), you have to measure the relative speeds of the sender and receiver, and resample the data appropriately.

Related

Ceph too many pgs per osd: all you need to know

I am getting both of these errors at the same time. I can't decrease the pg count and I can't add more storage.
This is a new cluster, and I got these warning when I uploaded about 40GB to it. I guess because radosgw created a bunch of pools.
How can ceph have too many pgs per osd, yet have more object per pg than average with a too few pgs suggestion?
HEALTH_WARN too many PGs per OSD (352 > max 300);
pool default.rgw.buckets.data has many more objects per pg than average (too few pgs?)
osds: 4 (2 per site 500GB per osd)
size: 2 (cross site replication)
pg: 64
pgp: 64
pools: 11
Using rbd and radosgw, nothing fancy.
I'm going to answer my own question in hopes that it sheds some light on the issue or similar misconceptions of ceph internals.
Fixing HEALTH_WARN too many PGs per OSD (352 > max 300) once and for all
When balancing placement groups you must take into account:
Data we need
pgs per osd
pgs per pool
pools per osd
the crush map
reasonable default pg and pgp num
replica count
I will use my set up as an example and you should be able to use it as a template for your own.
Data we have
num osds : 4
num sites: 2
pgs per osd: ???
pgs per pool: ???
pools per osd: 10
reasonable default pg and pgp num: 64 (... or is it?)
replica count: 2 (cross site replication)
the crush map
ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY
root ourcompnay
site a
rack a-esx.0
host prdceph-strg01
osd.0 up 1.00000 1.00000
osd.1 up 1.00000 1.00000
site b
rack a-esx.0
host prdceph-strg02
osd.2 up 1.00000 1.00000
osd.3 up 1.00000 1.00000
Our goal is to fill in the '???' above with what we need to serve a HEALTH OK cluster. Our pools are created by the rados gateway when it initialises.
We have a single default.rgw.buckets.data where all data is being stored the rest of the pools are adminitrastive and internal to cephs metadata and book keeping.
PGs per osd (what is a reasonable default anyway???)
The documentation would have us use this calculation to determine our pg count per osd:
(osd * 100)
----------- = pgs UP to nearest power of 2
replica count
It is stated that to round up is optimal. So with our current setup it would be:
(4 * 100)
----------- = (200 to the nearest power of 2) 256
2
osd.1 ~= 256
osd.2 ~= 256
osd.3 ~= 256
osd.4 ~= 256
This is the recommended max number of pgs per osd. So... what do you actually have currently? And why isn't it working? And if you set a
'reasonable default' and understand the above WHY ISN'T IT WORKING!!! >=[
Likely, a few reasons. We have to understand what those 'reasonable defaults' above actually mean, how ceph applies them and to where. One might misunderstand from the above that I could create a new pool like so:
ceph osd pool create <pool> 256 256
or I might even think I could play it safe and follow the documentation which states that (128 pgs for < 5 osds) can use:
ceph osd pool create <pool> 128 128
This is wrong, flat out. Because it in no way explains the relationship or balance between what ceph is actaully doing with these numbers
technically the correct answer is:
ceph osd pool create <pool> 32 32
And let me explain why:
If like me you provisioned your cluster with those 'reasonable defaults' (128 pgs for < 5 osds) as soon as you tried to do anything with rados it created a whole bunch of pools and your cluster spazzed out.
The reason is because I misunderstood the relationship between everything mentioned above.
pools: 10 (created by rados)
pgs per pool: 128 (recommended in docs)
osds: 4 (2 per site)
10 * 128 / 4 = 320 pgs per osd
This ~320 could be a number of pgs per osd on my cluster. But ceph might distribute these differently. Which is exactly what's happening and
is way over the 256 max per osd stated above. My cluster's HEALTH WARN is HEALTH_WARN too many PGs per OSD (368 > max 300).
Using this command we're able to see better the relationship between the numbers:
pool :17 18 19 20 21 22 14 23 15 24 16 | SUM
------------------------------------------------< - *total pgs per osd*
osd.0 35 36 35 29 31 27 30 36 32 27 28 | 361
osd.1 29 28 29 35 33 37 34 28 32 37 36 | 375
osd.2 27 33 31 27 33 35 35 34 36 32 36 | 376
osd.3 37 31 33 37 31 29 29 30 28 32 28 | 360
-------------------------------------------------< - *total pgs per pool*
SUM :128 128 128 128 128 128 128 128 128 128 128
There's a direct correlation between the number of pools you have and the number of placement groups that are assigned to them.
I have 11 pools in the snippet above and they each have 128 pgs and that's too many!! My reasonable defaults are 64! So what happened??
I was misunderstandning how the 'reasonable defaults' were being used. When I set my default to 64, you can see ceph has taking my crush map into account where
I have a failure domain between site a and site b. Ceph has to ensure that everything that's on site a is at least accessible on site b.
WRONG
site a
osd.0
osd.1 TOTAL of ~ 64pgs
site b
osd.2
osd.3 TOTAL of ~ 64pgs
We needed a grand total of 64 pgs per pool so our reasonable defaults should've actually been set to 32 from the start!
If we use ceph osd pool create <pool> 32 32 what this amounts to is that the relationship between our pgs per pool and pgs per osd with those 'reasonable defaults' and our recommened max pgs per osd start to make sense:
So you broke your cluster ^_^
Don't worry we're going to fix it. The procedure here I'm afraid might vary in risk and time depending on how big your cluster. But the only way
to get around altering this is to add more storage, so that the placement groups can redistribute over a larger surface area. OR we have to move everything over to
newly created pools.
I'll show an example of moving the default.rgw.buckets.data pool:
old_pool=default.rgw.buckets.data
new_pool=new.default.rgw.buckets.data
create a new pool, with the correct pg count:
ceph osd pool create $new_pool 32
copy the contents of the old pool the new pool:
rados cppool $old_pool $new_pool
remove the old pool:
ceph osd pool delete $old_pool $old_pool --yes-i-really-really-mean-it
rename the new pool to 'default.rgw.buckets.data'
ceph osd pool rename $new_pool $old_pool
Now it might be a safe bet to restart your radosgws.
FINALLY CORRECT
site a
osd.0
osd.1 TOTAL of ~ 32pgs
site b
osd.2
osd.3 TOTAL of ~ 32pgs
As you can see my pool numbers have incremented since they are added by pool id and are new copies. And our total pgs per osd is way under the ~256 which gives us room to add custom pools if required.
pool : 26 35 27 36 28 29 30 31 32 33 34 | SUM
-----------------------------------------------
osd.0 15 18 16 17 17 15 15 15 16 13 16 | 173
osd.1 17 14 16 15 15 17 17 17 16 19 16 | 179
osd.2 17 14 16 18 12 17 18 14 16 14 13 | 169
osd.3 15 18 16 14 20 15 14 18 16 18 19 | 183
-----------------------------------------------
SUM : 64 64 64 64 64 64 64 64 64 64 64
Now you should test your ceph cluster with whatever is at your disposal. Personally I've written a bunch of python over boto that tests the infrastructure and return buckets stats and metadata rather quickly. They have ensured to me that the cluster is back to working order without any of the issues it suffered from previously. Good luck!
Fixing pool default.rgw.buckets.data has many more objects per pg than average (too few pgs?) once and for all
This quite literally means, you need to increase the pg and pgp num of your pool. So... do it. With everything mentioned above in mind. When you do this however note that the cluster will start backfilling and you can watch this process %: watch ceph -s in another terminal window or screen.
ceph osd pool set default.rgw.buckets.data pg_num 128
ceph osd pool set default.rgw.buckets.data pgp_num 128
Armed with the knowledge and confidence in the system provided in the above segment we can clearly understand the relationship and the influence of such a change on the cluster.
pool : 35 26 27 36 28 29 30 31 32 33 34 | SUM
----------------------------------------------
osd.0 18 64 16 17 17 15 15 15 16 13 16 | 222
osd.1 14 64 16 15 15 17 17 17 16 19 16 | 226
osd.2 14 66 16 18 12 17 18 14 16 14 13 | 218
osd.3 18 62 16 14 20 15 14 18 16 18 19 | 230
-----------------------------------------------
SUM : 64 256 64 64 64 64 64 64 64 64 64
Can you guess which pool id is default.rgw.buckets.data? haha ^_^
In Ceph Nautilus (v14 or later), you can turn on "PG Autotuning". See this documentation and this blog entry for more information.
I accidentally created pools with live data that I could not migrate to repair the PGs. It took some days to recover, but the PGs were optimally adjusted with zero problems.

Websocket - Chrome complaining about mask bit set

I have implemented a websocket server in my existing server. Handshake is good and then I can even send first message and client browser receives it. But any subsequent messages disconnect websocket. On chrome I get following error.
failed: A server must not mask any frames that it sends to the client.
My frame is created like this
Len = erlang:size(Msg),
if
Len < 126 ->
Message = [<<1:1, 0:3,2:4,0:1,Len:7>>,Msg];
Len < 65536 ->
Message = [<<1:1, 0:3,2:4,0:1,126:7,Len:16>>,Msg];
true ->
Message = [<<1:1, 0:3,2:4,0:1,127:7,Len:64>>,Msg]
end,
Now one sample data to be transmitted looks like this
<<130,46,60,115,110,112,95,105,110,102,111,32,97,118,95,112,111,116,61,34,49,49,34,32,104,97,110,100,115,95,112,101,114,95,104,111,117,114,61,34,48,46,50,48,34,32,47,62>>
As you can see in the code above, my mask bit is always set to 0, but I don't why the same message works for the first time and then I send the same message again, it complains about mask bit set.
Anybody got any idea why?
Thanks
The frame sample data you pasted is sane.
48 bytes
ErlangSampleBytes[48] = 82 2E 3C 73 6E 70 5F 69 6E 66 6F 20 61 76 5F 70
6F 74 3D 22 31 31 22 20 68 61 6E 64 73 5F 70 65
72 5F 68 6F 75 72 3D 22 30 2E 32 30 22 20 2F 3E
It Parses/Translates to:
82 = fin:true
rsv1:false
rsv2:false
rsv3:false
opcode:2
2E = masked:false
payloadLength:46 (decimal)
Payload = UTF8 valid:
<snp_info av_pot="11" hands_per_hour="0.20" />
You don't even have a mismatch on the payload length declaration and what is left in the sample buffer.
At this point, it would be wise to look at the chrome inspection tooling to find out what the frames it thinks it got. And a next step after that would be to try to capture the network traffic with a tool like WireShark in an effort to see what is going on.
Suspect that the # of bytes you are sending on the wire, vs what you are declaring in the payloadLength are differing. (common one i've seen is sending more bytes than you declare)
Such as allocating a buffer of 1024 bytes, filling in the first 48 properly, then sending the entire 1024 bytes. That will mess parsing of the next frame.

Indy 10 IdTCPSever Readbytes scrambling data

I am trying to use Indy10 ReadBytes() in Delphi 2007 to read a large download of a series of data segments formatted as [#bytes]\r\n where #bytes indicates the number of bytes. My algorithm is:
Use ReadBytes() to get the [#]\r\n text, which is normally 10 bytes.
Use ReadBytes() to get the specified # data bytes.
Go to step 1 if more data segments need to be processed, i.e., # is negative.
This works well but frequently I don't get the expected text at step 1. Here's a short example after 330 successful data segments:
Data received from last step 2 ReadBytes(). NOTE embedded Step 1 [-08019]\r\n text.
Line|A033164|B033164|C033164|D033164|E033164|F033164|G033164|H033164|EndL\r|Begin
Line|A033165|B033165|C033165|D033165|E033165|F033165|G033165|H033165|EndL\r|Begin
Line|A033166|B033166|C033166|D033166|E033166|F033166|G033166|H033166|EndL\r[-08019]
\r\n|Begin
Line|A033167|B033167|C033167|D033167|E033167|F033167|G033167|H033167|EndL\r|Begin
Line|A033168|B033168|C033168|D033168|E033168|F033168|G033168|H033168|EndL\r|Begin
Socket data captured by WireShark.
0090 30 33 33 31 36 36 7c 42 30 33 33 31 36 36 7c 43 033166|B033166|C
00a0 30 33 33 31 36 36 7c 44 30 33 33 31 36 36 7c 45 033166|D033166|E
00b0 30 33 33 31 36 36 7c 46 30 33 33 31 36 36 7c 47 033166|F033166|G
00c0 30 33 33 31 36 36 7c 48 30 33 33 31 36 36 7c 45 033166|H033166|E
00d0 6e 64 4c 0d ndL.
No. Time Source Destination Protocol Length Info
2837 4.386336000 000.00.247.121 000.00.172.17 TCP 1514 40887 > 57006 [ACK] Seq=2689776 Ack=93 Win=1460 Len=1460
Frame 2837: 1514 bytes on wire (12112 bits), 1514 bytes captured (12112 bits) on interface 0
Ethernet II, Src: Cisco_60:4d:bf (e4:d3:f1:60:4d:bf), Dst: Dell_2a:78:29 (f0:4d:a2:2a:78:29)
Internet Protocol Version 4, Src: 000.00.247.121 (000.00.247.121), Dst: 000.00.172.17 (000.00.172.17)
Transmission Control Protocol, Src Port: 40887 (40887), Dst Port: 57006 (57006), Seq: 2689776, Ack: 93, Len: 1460
Data (1460 bytes)
0000 5b 2d 30 38 30 31 39 5d 0d 0a 7c 42 65 67 69 6e [-08019]..|Begin
0010 20 4c 69 6e 65 7c 41 30 33 33 31 36 37 7c 42 30 Line|A033167|B0
0020 33 33 31 36 37 7c 43 30 33 33 31 36 37 7c 44 30 33167|C033167|D0
0030 33 33 31 36 37 7c 45 30 33 33 31 36 37 7c 46 30 33167|E033167|F0
Does anyone know why this happens? Thanks
More information. We do socket reading from a single thread and don't call Connected() while reading. Here's relevant code snippet:
AClientDebugSocketContext.Connection.Socket.ReadBytes(inBuffer,byteCount,True);
numBytes := Length(inBuffer);
Logger.WriteToLogFile(BytesToString: '+BytesToString(inBuffer,0,numBytes),0);
Move(inBuffer[0], Pointer(Integer(Buffer))^, numBytes);
Embedded data like you describe, especially at random times, usually happens when you read from the same socket in multiple threads at the same time without adequate synchronization between them. One thread may receive a portion of the incoming data, and another thread may receive another portion of the data, and they end up storing their data in the InputBuffer in the wrong order. Hard to say for sure if that your problem since you did not provide any code. The best option is to make sure you never read from the same socket in multiple threads at all. That includes any calls to Connected(), since it performs a read operation internally. You should do all of your reading within a single thread. If that is not an option, then at least wrap your socket I/O with some kind of inter-thread lock, such as a critical section or mutex.
Update: You are accessing a TIdContext object via your own AClientDebugSocketContext variable. Where is that code being used exactly? If it is not in the context of the server's OnConnect, OnDisconnect, OnExecute, or OnException events, then you are reading from the same socket across multiple threads, because TIdTCPServer internally calls Connected() (which does a read) in between calls to the OnExecute event for that TIdContext object.

iPad crash after 20 minutes downloading data to Core Data model

I'm experiencing a crash on my iPad which I think is related to my app just running out of memory, however I can't seem to glean any information about the crash itself in order to resolve it. The app uses ARC.
The app spends about 20 minutes downloading data from our server and populating a Core Data model. Around the 20 minutes mark, the app crashes.
The device isn't running out of space - in fact the downloaded content takes up just a hundred megabytes. I'm using only a single managed context object (nb. I'm not saving the context until the entire data set has downloaded).
When I run in debug with an exception breakpoint enabled, I app just crashes without breaking and without displaying any type of warning or error.
Any advice on how to track down the problem? From the crash log below, does it look like the app is just running out of memory, or might it be
Here's the crash log:
Incident Identifier: A619465F-2E85-4BBC-BBE7-2330D4700FB8
CrashReporter Key: 6fa0c5a4f6cbeaf7a98e6c0e9ad8be6b27789039
Hardware Model: iPad2,2
OS Version: iPhone OS 6.0.1 (10A523)
Kernel Version: Darwin Kernel Version 13.0.0: Wed Oct 10 23:29:31 PDT 2012; root:xnu-2107.2.34~2/RELEASE_ARM_S5L8940X
Date: 2013-04-27 09:53:43 +0200
Time since snapshot: 152 ms
Free pages: 934
Active pages: 3455
Inactive pages: 1821
Throttled pages: 103117
Purgeable pages: 0
Wired pages: 18795
Largest process: GreaseBook
Processes
Name <UUID> rpages recent_max [reason] (state)
MobileMail <27df582d2bed3501834661269810ad98> 3928 3928 [vm] (continuous)
kbd <24d58ac14ed3340380492fef46eac29d> 574 574 [vm] (daemon)
tccd <eb5ddcf533663f8d987d67cae6a4c4ea> 281 281 [vm] (daemon)
GreaseBook <2f5df68a7078386298eadbb24ebbdb33> 84210 84210 [vm] (frontmost) (resume)
ptpd <0cac6936ffeb362d98eb8073af935d21> 992 992 (daemon)
mediaserverd <bdc35c073fe134b9a39b96342a80159e> 1082 1082 (daemon)
syslogd <cbef142fa0a839f0885afb693fb169c3> 281 281 (daemon)
locationd <4bee615548dd33f48e18bfed4296f05d> 1675 1675 (daemon)
wifid <a243b2fcde2537159660b3ee7e809df4> 649 649 (daemon)
aosnotifyd <01901b13681f3582b5bfbe53504d08d6> 480 480 (daemon)
dataaccessd <117e4e475b14305982f52484564cfbc7> 1319 1319 (daemon)
iaptransportd <f784f30dc09d32078d87b450e8113ef6> 241 241 (daemon)
SpringBoard <0e3571e8067533e2811a6d444f10a349> 4058 4058
backboardd <a9b5346126a939dfb0920a4bbc48201b> 6057 6057 (daemon)
imagent <d15f873abdd233f0a34d77a7d36e9e0f> 329 329 (daemon)
mDNSResponder <3e557693f3073697a58da6d27a827d97> 283 283 (daemon)
UserEventAgent <6edfd8d8dba23187b05772dcdfc94f90> 589 589 (daemon)
syslog_relay <45e9844605d737a08368b5215bb54426> 0 0 (daemon)
CVMServer <3ec015e0150d341a929ebbbc45f4c8ac> 104 104 (daemon)
afcd <b0aff2e7952e34a9882fec81a8dcdbb2> 165 165 (daemon)
notification_pro <845b7beebc8538ca9ceef731031983b7> 203 203 (daemon)
filecoordination <fbab576f37a63b56a1039153fc1aa7d8> 195 195 (daemon)
distnoted <a89af76ec8633ac2bbe99bc2b7964bb0> 132 132 (daemon)
apsd <d0e432fd45023d629ffb305b7e79d7fb> 403 403 (daemon)
aggregated <cd70154f955c31bbab58bf5f0acd3acd> 108 108 (daemon)
networkd <b24547cbe04b3e94a4bd406e586cdf8a> 222 222 (daemon)
BTServer <f57113a7cc2c33678ee832bc088276be> 356 356 (daemon)
configd <4245d73a9e96360399452cf6b8671844> 576 576 (daemon)
fairplayd.K94 <1a5f575df8f4368db1eae7ba3da11150> 270 270 (daemon)
fseventsd <996cc4ca03793184aea8d781b55bce08> 362 362 (daemon)
powerd <2d2ffed5e69638aeba1b92ef124ed861> 198 198 (daemon)
securityd <c35e701a5aab3968ae8d93ef8db02e07> 159 159 (daemon)
lockdownd <481275a4062931708a7440ff0f73f229> 495 495 (daemon)
CommCenterClassi <c10fa2a1b7673e1ab14e6ecd11b9b7e7> 557 557 (daemon)
notifyd <51c0e03da8a93ac8a595442fcaac531f> 199 199 (daemon)
**End**
When downloading large data sets into core data, you need to account for lots of things. When it comes to memory management, the more popular issues are described below.
First and foremost, you need to save frequently, which allows you to purge the memory from the NSManagedObjectContext (aka MOC). At any time, you can see what objects the MOC has, by looking at the registeredObjects property of the MOC.
Normally, when you save a MOC, any objects that do not have a strong reference to them are removed from the MOC. Again, you can check after saving by looking at the registeredObjects. However, if you have relationships in your model, then the objects will contain strong references to each other, which creates a retain cycle. Thus, the objects will never be released until the retain cycle is broken.
You break retain cycles in a MOC by using refreshObject:object mergeChanges:NO. You can blow away all objects by calling reset but that is rather draconian, and you need to make sure you do not hold any references to managed objects when you do that.
Even if you don't have retain cycles between your managed objects, you could still be inadvertently retaining objects that you will never use again. This is where, even though you are using ARC, you still need to understand some memory management rules. Specifically, auto released objects. They will get automatically released, but not until the autorelease pool reclaims objects.
Thus, you should wrap your operations in your own autorelease pool. This is very simple:
#autoreleasepool {
// Unless you hold references elsewhere, objects allocated in here will be
// auto released when this scope ends.
}
If you have a thread doing your downloading, and you use a MOC of NSPrivateQueueConcurrencyType, the block you pass to performBlock gets automatically wrapped in an autorelease pool.

How do I capture images in OpenCV and saving in pgm format?

I am brand new to programming in general, and am working on a project for which I need to capture images from my webcam (possibly using OpenCV), and save the images as pgm files.
What's the simplest way to do this? Willow Garage provides this code for image capturing:
http://opencv.willowgarage.com/wiki/CameraCapture
Using this code as a base, how might I modify it to:
capture an image from the live cam every 2 seconds
save the images to a folder in pgm format
Thanks so much for any help you can provide!
First of all, please use newer site - opencv.org. Using outdated references leads to chain effect, when new users see old references, read old docs and post old links again.
There's actually no reason to use old C API. Instead, you can use newer C++ interface, which, among other things, handles capturing video gracefully. Here's shortened version of example from docs on VideoCapture:
#include "opencv2/opencv.hpp"
using namespace cv;
int main(int, char**)
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
return -1;
for(;;)
{
Mat frame;
cap >> frame; // get a new frame from camera
// do any processing
imwrite("path/to/image.png", frame);
if(waitKey(30) >= 0) break; // you can increase delay to 2 seconds here
}
// the camera will be deinitialized automatically in VideoCapture destructor
return 0;
}
Also, if you are new to programming, consider using Python interface to OpenCV - cv2 module. Python is often considered simpler than C++, and using it you can play around with OpenCV functions right in an interactive console. Capturing video with cv2 looks something like this (adopted code from here):
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# do what you want with frame
# and then save to file
cv2.imwrite('path/to/image.png', frame)
if cv2.waitKey(30) & 0xFF == ord('q'): # you can increase delay to 2 seconds here
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
Since ffriend's answer is only partially true, I'll add some more to it (in C++). The author of this question asks explicitly for exporting to PGM (PXM file format that stores each pixel in 8 bits) and not PNG (as ffriend describes in his/her reply). The main issue here is that the official documentation for imwrite is omho not clear about this matter at all:
For PPM, PGM, or PBM, it can be a binary format flag ( CV_IMWRITE_PXM_BINARY ), 0 or 1. Default value is 1.
If we read the sentence in normal English, we have a list of options: CV_IMWRITE_PXM_BINARY, 0 or 1. There is no mention that those can and actually are supposed to be combined! I had to experiment a little bit (I also needed to store 8-bit images for my project) and finally got to the desired solution:
std::vector<int> compression_params; // Stores the compression parameters
compression_params.push_back(CV_IMWRITE_PXM_BINARY); // Set to PXM compression
compression_params.push_back(0); // Set type of PXM in our case PGM
const std::string imageFilename = "myPGM.pgm"; // Some file name - C++ requires an std::string
cv::imwrite(imageFilename, myImageMatrix, compression_params); // Write matrix to file
My investigation was also fueled by this question where the author was (maybe still is) struggling with the very same issue and also by some basic information on the PXM format, which you can find here.
The result (only part of the image) is displayed below:
P2
32 100
255
121 237 26 102 88 143 67 224 160 164 238 8 119 195 138 16 176 244 72 106 72 211 168 45 250 161 37 1 96 130 74 8
126 122 227 86 106 120 102 150 185 218 164 232 111 230 207 191 39 222 236 78 137 71 174 96 146 122 117 175 34 245 6 125
124 121 241 67 225 203 118 209 227 168 175 40 90 19 197 190 40 254 68 90 88 242 136 32 123 201 37 35 99 179 198 163
97 161 129 35 48 140 234 237 98 73 105 77 211 234 88 176 152 12 68 93 159 184 238 5 172 252 38 68 200 130 194 216
160 188 21 53 16 79 71 54 124 234 34 92 246 49 0 17 145 102 72 42 105 252 81 63 161 146 81 16 72 104 66 41
189 100 252 37 13 91 71 40 123 246 33 157 67 96 71 59 17 196 96 110 109 116 253 30 42 203 69 53 97 188 90 68
101 36 84 5 41 59 80 8 107 160 168 9 194 8 71 55 152 132 232 102 12 96 213 24 134 208 1 55 64 43 74 22
92 77 30 44 139 96 70 152 160 146 142 8 87 243 11 91 49 196 104 250 72 67 159 44 240 225 69 29 34 115 42 2
109 176 145 90 137 172 65 25 162 57 169 92 214 211 72 94 149 20 104 56 27 67 218 17 203 182 5 124 138 2 130 48
121 225 25 106 89 76 69 189 34 25 173 8 114 83 72 52 145 154 64 40 91 2 251 53 251 237 20 124 82 2 194 42 ...
Which is exactly what is required in this case. You can see the "P2" marking at the top and also the values are clearly from 0 to 255, which is exactly 8 bits per pixel.
Read most of the answers but none of them could satisfy my requirement. Here's how I implemented it.
This program will use webcam as a camera and clicks picture when you press 'c' - we can change the condition, then make it to click pictures automatically after certain interval
# Created on Sun Aug 12 12:29:05 2018
# #author: CodersMine
import cv2
video_path = 0 # 0 internal cam, 1 external webcam
cap = cv2.VideoCapture(video_path)
img_ctr = 0 # To Generate File Names
while(True):
ret, frame = cap.read()
cv2.imshow("imshow",frame)
key = cv2.waitKey(1)
if key==ord('q'): # Quit
break
if key==ord('c'): # Capture
cv2.imshow("Captured",frame)
flag = cv2.imwrite(f"image{img_ctr}.png", frame)
print(f"Image Written {flag}")
img_ctr += 1
# Release the Camera
cap.release()
cv2.destroyAllWindows()
If you don't need superaccurate 2seconds then simply put a sleep(2) or Sleep(2000) in the while(1) loop to wait fro 2seconds before each grab,
Write images with cvSaveImage() just put the extention .pgm on the filename and it will use pgm.
I believe that the format is chosen from the extension of the filename - so assuming your opencv lib's are linked against the appropriate libs you can do something like: (this is from memory, might not be correct.)
CvCapture* capture = cvCaptureFromCam(0);
IplImage* frame = cvQueryFrame(capture);
while (1) {
frame = cvQueryFrame(capture);
cvSaveImage("foo.pgm", &frame);
sleep(2);
}
cvReleaseImage(&frame);
cvReleaseCapture(&capture);

Resources