aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp129
1 files changed, 50 insertions, 79 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 0ab002f..9db23e4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -62,7 +62,6 @@ extern "C" {
#include <deque>
#include <future>
-#include <condition_variable>
//#include <CL/cl.h>
@@ -434,7 +433,7 @@ static void receive_frames(AVCodecContext *av_codec_context, int stream_index, A
} else {
av_packet_rescale_ts(&av_packet, av_codec_context->time_base, stream->time_base);
av_packet.stream_index = stream->index;
- int ret = av_interleaved_write_frame(av_format_context, &av_packet);
+ int ret = av_write_frame(av_format_context, &av_packet);
if(ret < 0) {
fprintf(stderr, "Error: Failed to write frame index %d to muxer, reason: %s (%d)\n", av_packet.stream_index, av_error_to_string(ret), ret);
}
@@ -810,33 +809,51 @@ static std::future<void> save_replay_thread;
static std::vector<AVPacket> save_replay_packets;
static std::string save_replay_output_filepath;
-static void save_replay_async(AVCodecContext *video_codec_context, int video_stream_index, std::vector<AudioTrack> &audio_tracks, const std::deque<AVPacket> &frame_data_queue, bool frames_erased, std::string output_dir, std::string container_format) {
+static void save_replay_async(AVCodecContext *video_codec_context, int video_stream_index, std::vector<AudioTrack> &audio_tracks, const std::deque<AVPacket> &frame_data_queue, bool frames_erased, std::string output_dir, std::string container_format, std::mutex &write_output_mutex) {
if(save_replay_thread.valid())
return;
size_t start_index = (size_t)-1;
- for(size_t i = 0; i < frame_data_queue.size(); ++i) {
- const AVPacket &av_packet = frame_data_queue[i];
- if((av_packet.flags & AV_PKT_FLAG_KEY) && av_packet.stream_index == video_stream_index) {
- start_index = i;
- break;
+ int64_t video_pts_offset = 0;
+ int64_t audio_pts_offset = 0;
+
+ {
+ std::lock_guard<std::mutex> lock(write_output_mutex);
+ start_index = (size_t)-1;
+ for(size_t i = 0; i < frame_data_queue.size(); ++i) {
+ const AVPacket &av_packet = frame_data_queue[i];
+ if((av_packet.flags & AV_PKT_FLAG_KEY) && av_packet.stream_index == video_stream_index) {
+ start_index = i;
+ break;
+ }
}
- }
- if(start_index == (size_t)-1)
- return;
+ if(start_index == (size_t)-1)
+ return;
- int64_t pts_offset = 0;
- if(frames_erased)
- pts_offset = frame_data_queue[start_index].pts;
+ if(frames_erased) {
+ video_pts_offset = frame_data_queue[start_index].pts;
+
+ // Find the next audio packet to use as audio pts offset
+ for(size_t i = start_index; i < frame_data_queue.size(); ++i) {
+ const AVPacket &av_packet = frame_data_queue[i];
+ if(av_packet.stream_index != video_stream_index) {
+ audio_pts_offset = av_packet.pts;
+ break;
+ }
+ }
+ } else {
+ start_index = 0;
+ }
- save_replay_packets.resize(frame_data_queue.size());
- for(size_t i = 0; i < frame_data_queue.size(); ++i) {
- av_packet_ref(&save_replay_packets[i], &frame_data_queue[i]);
+ save_replay_packets.resize(frame_data_queue.size());
+ for(size_t i = 0; i < frame_data_queue.size(); ++i) {
+ av_packet_ref(&save_replay_packets[i], &frame_data_queue[i]);
+ }
}
save_replay_output_filepath = output_dir + "/Replay_" + get_date_str() + "." + container_format;
- save_replay_thread = std::async(std::launch::async, [video_stream_index, container_format, start_index, pts_offset, video_codec_context, &audio_tracks]() mutable {
+ save_replay_thread = std::async(std::launch::async, [video_stream_index, container_format, start_index, video_pts_offset, audio_pts_offset, video_codec_context, &audio_tracks]() mutable {
AVFormatContext *av_format_context;
// The output format is automatically guessed from the file extension
avformat_alloc_output_context2(&av_format_context, nullptr, container_format.c_str(), nullptr);
@@ -874,18 +891,22 @@ static void save_replay_async(AVCodecContext *video_codec_context, int video_str
AVStream *stream = video_stream;
AVCodecContext *codec_context = video_codec_context;
- if(av_packet.stream_index != video_stream_index) {
+ if(av_packet.stream_index == video_stream_index) {
+ av_packet.pts -= video_pts_offset;
+ av_packet.dts -= video_pts_offset;
+ } else {
AudioTrack *audio_track = stream_index_to_audio_track_map[av_packet.stream_index];
stream = audio_track->stream;
codec_context = audio_track->codec_context;
+
+ av_packet.pts -= audio_pts_offset;
+ av_packet.dts -= audio_pts_offset;
}
av_packet.stream_index = stream->index;
- av_packet.pts -= pts_offset;
- av_packet.dts -= pts_offset;
av_packet_rescale_ts(&av_packet, codec_context->time_base, stream->time_base);
- int ret = av_interleaved_write_frame(av_format_context, &av_packet);
+ int ret = av_write_frame(av_format_context, &av_packet);
if(ret < 0)
fprintf(stderr, "Error: Failed to write frame index %d to muxer, reason: %s (%d)\n", stream->index, av_error_to_string(ret), ret);
}
@@ -1426,52 +1447,11 @@ int main(int argc, char **argv) {
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
swr_init(swr);
- std::deque<uint8_t*> buffered_audio;
- std::mutex buffered_audio_mutex;
- std::condition_variable buffered_audio_cv;
- bool got_first_batch = false;
-
- // TODO: Make the sound device read async instead of using a thread
- std::thread sound_read_thread([&](){
- while(running) {
- void *sound_buffer;
- int sound_buffer_size = sound_device_read_next_chunk(&audio_track.sound_device, &sound_buffer);
- if(sound_buffer_size >= 0) {
- uint8_t *data = (uint8_t*)malloc(audio_track.sound_device.buffer_size);
- if(data) {
- memcpy(data, sound_buffer, audio_track.sound_device.buffer_size);
- std::unique_lock<std::mutex> lock(buffered_audio_mutex);
- buffered_audio.push_back(data);
- buffered_audio_cv.notify_one();
- }
- }
- }
- });
-
while(running) {
- uint8_t *audio_buffer;
- bool free_audio;
- {
- // TODO: Not a good solution to lack of audio as it causes dropped frames, but it's better then complete audio desync.
- // The first packet is delayed for some reason...
- std::unique_lock<std::mutex> lock(buffered_audio_mutex);
- if(got_first_batch)
- buffered_audio_cv.wait(lock, [&]{ return !running || !buffered_audio.empty(); });
- else
- buffered_audio_cv.wait_for(lock, std::chrono::milliseconds(21), [&]{ return !running || !buffered_audio.empty(); });
- if(!running)
- break;
-
- if(buffered_audio.empty()) {
- audio_buffer = empty_audio;
- free_audio = false;
- } else {
- audio_buffer = buffered_audio.front();
- buffered_audio.pop_front();
- free_audio = true;
- got_first_batch = true;
- }
- }
+ void *sound_buffer;
+ int sound_buffer_size = sound_device_read_next_chunk(&audio_track.sound_device, &sound_buffer);
+ if(sound_buffer_size < 0)
+ sound_buffer = empty_audio;
int ret = av_frame_make_writable(audio_track.frame);
if (ret < 0) {
@@ -1480,7 +1460,7 @@ int main(int argc, char **argv) {
}
// TODO: Instead of converting audio, get float audio from alsa. Or does alsa do conversion internally to get this format?
- swr_convert(swr, &audio_track.frame->data[0], audio_track.frame->nb_samples, (const uint8_t**)&audio_buffer, audio_track.sound_device.frames);
+ swr_convert(swr, &audio_track.frame->data[0], audio_track.frame->nb_samples, (const uint8_t**)&sound_buffer, audio_track.sound_device.frames);
audio_track.frame->pts = (clock_get_monotonic_seconds() - start_time_pts) * AV_TIME_BASE;
ret = avcodec_send_frame(audio_track.codec_context, audio_track.frame);
@@ -1489,17 +1469,9 @@ int main(int argc, char **argv) {
} else {
fprintf(stderr, "Failed to encode audio!\n");
}
-
- if(free_audio)
- free(audio_buffer);
- }
-
- sound_read_thread.join();
- while(!buffered_audio.empty()) {
- free(buffered_audio.front());
- buffered_audio.pop_front();
}
+ sound_device_close(&audio_track.sound_device);
swr_free(&swr);
}, av_format_context, &write_output_mutex);
}
@@ -1749,7 +1721,7 @@ int main(int argc, char **argv) {
if(save_replay == 1 && !save_replay_thread.valid() && replay_buffer_size_secs != -1) {
save_replay = 0;
- save_replay_async(video_codec_context, VIDEO_STREAM_INDEX, audio_tracks, frame_data_queue, frames_erased, filename, container_format);
+ save_replay_async(video_codec_context, VIDEO_STREAM_INDEX, audio_tracks, frame_data_queue, frames_erased, filename, container_format, write_output_mutex);
}
// av_frame_free(&frame);
@@ -1767,7 +1739,6 @@ int main(int argc, char **argv) {
for(AudioTrack &audio_track : audio_tracks) {
audio_track.thread.join();
- sound_device_close(&audio_track.sound_device);
}
if (replay_buffer_size_secs == -1 && av_write_trailer(av_format_context) != 0) {