summaryrefslogtreecommitdiff
path: root/src
AgeCommit message (Collapse)Author
2021-04-05encode_audio_buffers: remove some pointless duplicationVito Caputo
rmdEncodeAudioBuffers() and rmdSyncEncodeAudioBuffer() each implemented the actual jack vs. non-jack encoding of the buffer redundantly despite being identical. This commit moves that step into a shared private function.
2021-04-04*: s/rmdEncodeImageBuffer/rmdEncodeImageBuffers/Vito Caputo
finishing up mechanical change started in previous commit
2021-04-04*: encode_image_buffer.[ch]->encode_audio_buffers.[ch]Vito Caputo
mechanical change to get filenames more accurate, thread function will be renamed in subsequent commit.
2021-04-04*: s/rmdEncodeAudioBuffer/rmdEncodeAudioBuffers/Vito Caputo
finishing up mechanical change started in previous commit
2021-04-04*: encode_audio_buffer.[ch]->encode_audio_buffers.[ch]Vito Caputo
mechanical change to get filenames more accurate, thread function will be renamed in subsequent commit.
2021-04-04*: trivial cleanupsVito Caputo
s/for(/for (/g
2021-03-15*: random whitespace cleanupsVito Caputo
Mostly trailing space/tab removals, no functional changes.
2021-03-13get_frames: remove superfluous avd assignmentVito Caputo
Since avd is unconditionally copied just a few lines down, this copy is pointless and harms readability. I think when it was originally written there was going to be an else branch where the unconditional copy is currently, but never bothered. The avd shared variable should really get changed to an atomic, removing its lock. To anyone reading: PRs welcome.
2021-02-12cache: _rmdCacheFileClose should always NULL handlesVito Caputo
The existing code would leave the internal handle non-NULL when the underlying close failed. In the event of a transparent close when chapters switch failing, a subsequent explicit close is expected, and the handles must be NULLed out for that explicit close to not blow up because fclose() leaves the handle undefined after errors. It's basically a use after free bug.
2021-01-06rescue: zero initialize structsVito Caputo
Various functions rely on this stuff at least being zeroed, rmd.c already had been fixed but rmd_rescue.c has been neglected.
2021-01-06poll_events: fix clip bounds check in uv_alignVito Caputo
This would potentially exceed the clip w/h on odd inputs because it was wrongly adding the cliprect offset while comparing against coordinates already made relative within the cliprect
2021-01-06load_cache: fix divzero bug introduced by 5ce6553Vito Caputo
--rescue mode doesn't set pdata->capture_frameno to the total The whole --rescue initialization path is a snowflake and should get reworked to share more in common with the normal startup. reported by @xloem, thanks!
2020-11-14poll_events: actually store the result of uv_align()Vito Caputo
Spurious artifacts in the chroma channels when the damage regions weren't aligned showed up because this function wasn't actually doing anything.
2020-11-13opendev: bump granularity of audio capture periodsVito Caputo
This only applies to ALSA, but the av-sync precision is entirely dependent on the granularity of what ALSA refers to as "periods". The pdata->avd delay is decremented by the audio capture in period aligned steps, meaning the smallest decrement it can possibly do is the period size. Between these period sized intervals, rmdGetFrames kind of flies blind if the FPS is high enough for frametime to be substantially smaller than the period time. A smaller period does increase the ALSA capture overhead, basically increasing the number of times ALSA returns data to userspace, kind of like a higher interrupt rate. But it seems negligible for a modern system.
2020-11-13*: rename rmd_get_frame.[ch] to rmd_get_frames.[ch]Vito Caputo
mechanical file rename to plural form
2020-11-13get_frame: s/rmdGetFrame/rmdGetFrames/Vito Caputo
Mechanical rename to more accurate plural form
2020-11-12register_callbacks: permit paused quit and abortVito Caputo
Not sure why the inherited code prohibited this, but it doesn't jive with my expectations to ignore SIGINT just because the recording is paused.
2020-11-12timer: remove unnecessary timer threadVito Caputo
This removes the timer thread entirely in favor of a coordinated delay loop directly within rmdGetFrame. When there's an audio stream to synchronize with, avd is maintained by the pcm buffer updates, and the fps-derived frametimes synchronize with the audio that way. When there's no audio stream (--no-sound), avd is now maintained synthetically via clock_gettime(CLOCK_MONOTONIC) coordinating with the clock instead. There's been some reworking of frame sampling/reusing and cloning logic, which may need some refinement. But for now the tests seem to show promise. The old timer approach just increased the non-determinism by adding more scheduler latency and influence unnecessarily.
2020-11-11macro: enclose MIN/MAX macros in parensVito Caputo
2020-11-11*: add _us suffixes to {frame,period}time namesVito Caputo
Make the names reflect their units of microseconds
2020-11-09cache: overload syncer thread to also pre-allocateVito Caputo
This changes the syncer thread to always be created for writers, and makes it posix_fallocate() the cache file to the maximum size. When the syncer is disabled w/ms=0, it simply returns after the posix_fallocate. posix_fallocate errors are ignored, this is simply an opportunistic optimization. I have some concern about the glibc emulation mentioned in the man page, but writers are opened O_WRONLY which the notes say cause the emulation to fail with EBADF which is preferable, and I'm using O_WRONLY for the writers.
2020-11-09load_cache: treat invalid frame header as EOFVito Caputo
In preparation for posix_fallocate() pre-allocation of cache files, expect zeroes for the header when running off the end of valid data into the only allocated space, and handle gracefully as an EOF equivalent.
2020-11-09cache: introduce "syncer" thread for cache writersVito Caputo
This adds a new flag: --periodic-datasync-ms with a default of 100ms. When a new CacheFile is created for writing, and the datasync period is non-zero, a thread is created for the sole purpose of calling fdatasync() on the underlying fd in a loop separated by sleeps of the specified duration. The purpose of this is to prevent a large backlog of dirty buffers from accumulating until the operating system's normal background dirty sync kicks in. Depending on how the underlying filesystem and storage stack is configured, these bulk writebacks can result in very long stalls on a subsequent write operation. This is easily observed on ext4+lvm+dmcrypt setups, even using a simple test like `dd if=/dev/urandom of=testfile bs=8M`. Despite having plenty of available buffers, once ext4's internal journal fills while a bulk writeback is underway, dd's progress will completely stall until the entire writeback is completed, usually it's in the jbd2 wchan of do_get_write_access(). When this occurs during a recording by recordMyDesktop, the result is dropping frames for the entire duration of the stall. One thing recordMyDesktop could do to insulate from this is perform its own buffering of sampled frames at the YUV stage, with the cache writer consuming from this pool of buffered frames. Then when the cache writer gets stalled on jbd2/dmcrypt holdups, the buffer pool just grows instead of frames being dropped. I may explore this option in the future, but for now simply syncing regularly has been sufficient in my usage, as it keeps the storage subsystem more continuously utilized and spreads out the writebacks so they don't completely back up the journal.
2020-11-08yuv_utils: fixup yuv chroma offset/stride mathVito Caputo
hopefully this is is all of it, will need more testing I noticed during some non-full-shots tests that the dirty areas didn't seem to be getting rounded up properly so my single pixel window border's color was sometimes omitted on the right edge and bottom...
2020-11-08capture_audio: trivial whitespace fixupVito Caputo
2020-11-08cache: pivot to new CacheFile APIVito Caputo
This minimally switches all the ad-hoc image cache files handling over to using CacheFile. I left the audio cache alone for now as it seems to not be compressed. It might make sense in the future to switch that over as well, especially if I start adding features to CacheFile like preallocating and async periodic fdatasync.
2020-11-08cache: introduce rudimentary CacheFile APIVito Caputo
Throughout the existing cache-related code there's constant checking if compression is active or not. This commit introduces a CacheFile ADT with the intention of replacing all the open coded stuff with simple calls into rmdCacheFile* functions operating on CacheFile instances. The management of split up cache files has also been implemented behind this API, so the reads and writes will transparently handle the split files. These have been named "chapters" in new code. No callers have been changed, this only adds the new facility. A subsequent commit will migrate things over.
2020-10-30*: more minor cleanupsVito Caputo
No need for fflush(stderr) when it's already unbuffered by default. According to setvbuf(3): Normally all files are block buffered. If a stream refers to a terminal (as stdout normally does), it is line buffered. The standard error stream stderr is always unbuffered by default.
2020-10-08*: more cosmetic formatting cleanupsVito Caputo
Making things a bit more consistent
2020-09-08cache_audio: s/sound/audio/ where appropriateVito Caputo
Despite this listing already being named rmd_cache_audio, it used sound instead of audio for the api.
2020-09-08encode_audio_buffer: s/sound/audio/ where appropriateVito Caputo
Largely mechanical cosmetic changes for more consistency
2020-09-08encode_sound_buffer: rename to encode_audio_bufferVito Caputo
Cosmetic rename to make naming consistent, normalizing on audio. This is a minimal rename and includes update, subsequent commit will change naming as appropriate in rmd_encode_audio_buffer.[ch]
2020-09-08capture_audio: s/sound/audio/ where reasonableVito Caputo
Largely mechanical change just finishing up cosmetic rename of rmd_capture_sound->rmd_capture_audio
2020-09-08capture_sound: rename to rmd_capture_audio.[ch]Vito Caputo
Make naming consistent with rmd_cache_audio. This commit is minimal renaming of the files and tweaking includes, a subsequent commit will make the various naming within rmd_capture_audio.c consistent.
2020-09-08yuv_utils: privatize matricesVito Caputo
These don't need to be globals anymore since I've gotten rid of the unnecessary macro insanity.
2020-07-15get_frame: refresh capture_frameno post acquireVito Caputo
Acquiring the new frame can take a potentially significant amount of time, rather than letting any frames dropped during the acquire get all taken by the next frame, update this one to include them. It's both more accurate (the dropped frames occurred literally while this was going on) and makes it more likely get_frame() will have to wait on the upcoming cond_wait(time_cond) for the next tick. If the upcoming cond_wait(time_cond) doesn't wait because a new frame is already pending, it makes it more likely get_frame() will snatch yuv_mutex before the encode/cache thread can wake up and grab it. When that occurs it's effectively dropping frames because the encode/cache thread gets blocked on yuv_mutex while the contents get replaced, so the frames the previous contents were going to be applied to will instead get the updated contents that belong to the future sample's frames.
2020-07-15timer: maintain video side of avd in frame timerVito Caputo
Since the frame timer implements a frame counter, and that frame count is propagated through the get->encode pipeline for samples that get through, any missed frames are noticed and dealt with making it not lossy from the point of the timer down to the encoded stream in terms of number of frames. It's certainly lossy in terms of the contents of those frames, but synchronization is all about the temporal domain and as long as the frame counts all make it into the stream as frames, we can account for them at the timer in terms of avd. This in combination with the other commit moving the audio side of avd maintenance immediately upon capture into the raw buffer, shrinks the variable capacitance separating the audio timer and the frame timer to virtually nil. As a consequence, the frame timer can now be much more accurate in terms of how much longer/less to sleep or if a frame should be dropped to get the timer caught up. When avd was being maintained at points far removed from the actual things they represented there was too much elastic capacitance in there for sync_streams() to inform its adjustment accurately.
2020-07-15sound: move avd maintenance to point of captureVito Caputo
Since the sound capture buffers all sound in newly allocated memory, the "stream time" represented by those buffers can be accounted for immediately upon reading into the buffer. Doing it later in the different threads on the other side of the queue, especially after encoding, is an unnecessary pile of variable capacitance that just makes things less synchronized for zero gain.
2020-07-14timer: don't advance time_frameno when pausedVito Caputo
This requires a bit of adjustment in the get_frame time_cond wait loop so it still services the event loop when woken without advance At least now get_frame has no explicit pause code, but it does require the timer keep firing while paused so it signals time_cond.
2020-07-14*: get rid of unused frames_{total,lost}Vito Caputo
these concepts may return but not in this form
2020-07-14*: rework avd/frameno handling for cached modeVito Caputo
This brings the !--on-the-fly-encoding mode up to speed. The cached file header loses the total_frames counter, as the capture_frameno already represents this. Dropped frames are detected by simply looking at the difference between the previous capture_frameno and the current one. This simply gets passed to the encoder as a n_frames count so theora can duplicate the frames as needed. This was being done manually before by looking at the frameno and total frames in each header and maintaining separate counts for "extra frames" "missed frames" etc, and resubmitting entire frames multiply for encoding dropped frames. So a chunk of code has been thrown out from rmd_load_cache.c, and some general cleanups have occurred there as well. I also needed to add more locking around pdata->avd accesses.
2020-07-14timer: implement AV-syncVito Caputo
This is focused on keeping --on-the-fly-encoding in sync even over long videos. The existing code inevitably would fall into a permanently negative pdata->avd value letting things get increasingly out of sync and never correcting. Before removing the vestigial negative avd "don't wait" logic from get_frame when this permanently negative avd state was entered, get_frame would just start sampling at an unregulated fps. The timer thread which drives get_frame now consults avd on every tick, Depending on which which half is ahead, the timer will either cause get_frame to drop frames by advancing the frameno by more than one, or it will adjust its sleep delay in proportion to the delta. See comments in rmd_timer.c for more details. Note that in testing especially with a loaded system I observed some surprisingly large deltas where multi-second sleeps occurred to let the sound catch back up. I expect to revisit this issue more in the future, but would just like to get things more correct for now.
2020-07-14encode_image_buffer: duplicate missed framesVito Caputo
When the encoder finds the encoded - captured frameno delta > 1 it needs to fill the gap somehow. With how things are currently architected, the old yuv countents are gone so there's only the current frame available for filling. The newer theoraenc.h API exposes a theora_control() parameter for this purpose, so I've also added a theoraenc.h include implicitly bumping the libtheora dependency. But by now it shouldn't matter, and the rest of rmd should probably get updated to use the new theora API eventually anyways. I'm still uncertain what role pdata->avd will play in the long-run, but leaving its maintenance for now.
2020-07-14types: add avd_mutex to ProgDataVito Caputo
avd accesses aren't serialized currently despite occurring from concurrent threads. I'm reworking avd but this just introduces and initializes a mutex for the existing variable.
2020-07-14get_frame: s/cond_broadcast/cond_signal/Vito Caputo
Vestigial broadcast, only a single waiter on this now.
2020-07-14get_frame: don't let avd influence frame samplingVito Caputo
Maybe this made sense at some point in the original code, but the way I have this setup currently get_frame() should strictly capture a frame on every tick of the timer at the desired FPS to the best of its ability. The capture_frameno gets propagated to the encoder whenever a new frame is acquired on that timer. When the encoder consumes it, it should just dupe the frame to fill any gaps between the last encoded frameno and the new one. As-is, this avd value seems to drift permanently negative eventually at which point get_frame() ceases ever waiting on the timer. That's obviously broken, and devolves into a pinned CPU with get_frame() attempting an infinitely high frame rate. Which likely just makes things worse not better by starving the encoder of CPU time. I need to go check out the encoder now to make sure it fills frameno gaps.
2020-07-13*: more rmdThreadsSetName() callersVito Caputo
Name the timer and sound capture threads as well, and fixup the rmd{Encode,Cache}Sounds names -> rmd{Encode,Cache}Sound
2020-07-12flush_to_ogg: use enum for audio_or_videoVito Caputo
Nothing changed, just syntactic sugar to make this more readable
2020-07-12*: standardize sleeps on nanosleep()Vito Caputo
usleep() is deprecated by posix in favor of nanosleep(), nanosleep doesn't dick with signals so it's generally better anyways.
2020-07-12get_frame: insert brief sleep when pausedVito Caputo
rmdGetFrame() can't just block on pause_cond because it services the event loop, which may be the very thing responsible for unpausing when not triggered by an external signal. The existing code handles this correctly but it spins on polling the paused flag and running the event loop when paused. This commit just adds a short delay to that cycle so the rmdGetFrame thread doesn't pointlessly burn CPU while paused.
© All Rights Reserved