Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -144,55 +144,6 @@ size_t get_target_fps(){
}


#if 0
class VideoGenerator : public QObject {
// Q_OBJECT
public:
VideoGenerator(QVideoFrameInput *input, std::deque<CompressedVideoFrame> frames)
: m_input(input), m_frames(frames){

// Listen for the signal that the recorder's buffer has space
connect(m_input, &QVideoFrameInput::readyToSendVideoFrame, this, &VideoGenerator::sendNextFrame);
}

public slots:
void sendNextFrame() {
// Send frames in a loop until the buffer is full or we run out of images
if (!m_frames.empty())
{
QVideoFrame frame = decompress_video_frame(m_frames.front().compressed_frame); // m_frameQueue.dequeue();

// Set timestamp (e.g., 30 FPS = 33333 microseconds per frame)
// frame.setStartTime(m_index * 33333);

// 2. ONLY send the frame if the input is ready
bool success = m_input->sendVideoFrame(frame);

// 3. Optional: Check if the frame was dropped (shouldn't happen
// often if you are responding to readyToSendVideoFrame)
if (!success) {
cout << "Frame was rejected, stopping frame emission." << endl;;
// You might re-enqueue the frame or just discard it based on your needs.
}
}
else {
cout << "Queue empty, waiting for more frames...";
// Finalize: Sending an empty frame signals the end of the stream
m_input->sendVideoFrame(QVideoFrame());
emit finished();
}

}

signals:
void finished();

private:
QVideoFrameInput *m_input;
std::deque<CompressedVideoFrame> m_frames;
};
#endif

StreamHistoryTracker::~StreamHistoryTracker(){
m_stopping = true;
m_cv.notify_all();
Expand All @@ -208,11 +159,11 @@ StreamHistoryTracker::StreamHistoryTracker(
)
: m_logger(logger)
, m_window(window)
, m_audio_samples_per_frame(audio_samples_per_frame)
, m_audio_frames_per_second(audio_frames_per_second)
, m_audio_samples_per_second(audio_samples_per_frame * audio_frames_per_second)
, m_microseconds_per_sample(1. / (m_audio_samples_per_second * 1000000.))
, m_has_video(has_video)
// , m_audio_samples_per_frame(audio_samples_per_frame)
// , m_audio_frames_per_second(audio_frames_per_second)
// , m_audio_samples_per_second(audio_samples_per_frame * audio_frames_per_second)
// , m_microseconds_per_sample(1. / (m_audio_samples_per_second * 1000000.))
// , m_has_video(has_video)
, m_target_fps(get_target_fps())
, m_frame_interval(1000000 / m_target_fps)
, m_next_frame_time(WallClock::min())
Expand Down Expand Up @@ -440,254 +391,6 @@ void StreamHistoryTracker::worker_loop() {
}


// bool StreamHistoryTracker::save(const std::string& filename) const{
// m_logger.log("Saving stream history...", COLOR_BLUE);

// std::deque<CompressedVideoFrame> frames;
// {
// // Fast copy the current state of the stream.
// WriteSpinLock lg(m_lock, PA_CURRENT_FUNCTION);
// if (m_compressed_frames.empty()){
// return false;
// }
// frames = m_compressed_frames;
// }

// // Now that the lock is released, we can take our time encoding it.

// // TODO

// #if 0
// WallClock start = WallClock::max();
// if (!frames.empty()){
// start = std::min(start, frames.front()->timestamp);
// }

// #endif


// // run_on_main_thread_and_wait([&]{

// QVideoFrameFormat format(QSize(1920, 1080), QVideoFrameFormat::Format_ARGB8888);
// QVideoFrameInput videoInput(format);

// // cout << "frames = " << frames.size() << endl;

// QMediaCaptureSession session;
// QMediaRecorder recorder;
// session.setVideoFrameInput(&videoInput);
// session.setRecorder(&recorder);
// #if 1
// recorder.setMediaFormat(QMediaFormat::MPEG4);
// #else
// QMediaFormat video_format;
// video_format.setAudioCodec(QMediaFormat::AudioCodec::AAC);
// // video_format.setVideoCodec(QMediaFormat::VideoCodec::H264);
// video_format.setFileFormat(QMediaFormat::MPEG4);
// recorder.setMediaFormat(video_format);
// #endif
// recorder.setQuality(QMediaRecorder::NormalQuality);

// QFileInfo file(QString::fromStdString(filename));
// recorder.setOutputLocation(
// QUrl::fromLocalFile(file.absoluteFilePath())
// );

// VideoGenerator generator(&videoInput, frames);

// QObject::connect(&generator, &VideoGenerator::finished, &recorder, &QMediaRecorder::stop);
// QObject::connect(&recorder, &QMediaRecorder::recorderStateChanged, [](QMediaRecorder::RecorderState state){
// if (state == QMediaRecorder::StoppedState) qApp->quit();
// });

// recorder.record();
// #if 0
// WallClock last_change = current_time();
// bool success = true;

// while (!frames.empty()){
// #if 1
// while (true){
// if (frames.empty()){
// // video_input.sendVideoFrame(QVideoFrame());
// // session.setVideoFrameInput(nullptr);
// break;
// }
// if (!video_input.sendVideoFrame((*frames.begin())->frame)){
// // cout << "Failed Video: " << frames.size() << endl;
// break;
// }
// frames.pop_front();
// last_change = current_time();
// // cout << "Pushed Video: " << frames.size() << endl;
// }
// #endif
// if (current_time() - last_change > std::chrono::seconds(10)){
// m_logger.log("Failed to record stream history: No progress made after 10 seconds.", COLOR_RED);
// success = false;
// break;
// }

// QCoreApplication::processEvents();
// }
// #endif

// recorder.stop();
// m_logger.log("Done saving stream history...", COLOR_BLUE);
// // cout << recorder.duration() << endl;


// // });
// return true;
// }


// #if 0
// bool StreamHistoryTracker::save(const std::string& filename) const{
// m_logger.log("Saving stream history...", COLOR_BLUE);

// std::deque<std::shared_ptr<AudioBlock>> audio;
// std::deque<std::shared_ptr<const VideoFrame>> frames;
// {
// // Fast copy the current state of the stream.
// WriteSpinLock lg(m_lock, PA_CURRENT_FUNCTION);
// if (m_audio.empty() && m_frames.empty()){
// return false;
// }
// audio = m_audio;
// frames = m_frames;
// }

// // Now that the lock is released, we can take our time encoding it.

// // TODO

// #if 0
// WallClock start = WallClock::max();
// if (!audio.empty()){
// start = std::min(start, audio.front()->timestamp);
// }
// if (!frames.empty()){
// start = std::min(start, frames.front()->timestamp);
// }

// #endif


// // run_on_main_thread_and_wait([&]{

// QAudioFormat audio_format;
// audio_format.setChannelCount((int)m_audio_samples_per_frame);
// audio_format.setChannelConfig(m_audio_samples_per_frame == 1 ? QAudioFormat::ChannelConfigMono : QAudioFormat::ChannelConfigStereo);
// audio_format.setSampleRate((int)m_audio_frames_per_second);
// audio_format.setSampleFormat(QAudioFormat::Float);

// // cout << "audio_format = " << audio_format.isValid() << endl;

// QAudioBufferInput audio_input;
// QVideoFrameInput video_input;

// // cout << "audio = " << audio.size() << endl;
// // cout << "frames = " << frames.size() << endl;

// QMediaCaptureSession session;
// QMediaRecorder recorder;
// session.setAudioBufferInput(&audio_input);
// session.setVideoFrameInput(&video_input);
// session.setRecorder(&recorder);
// #if 1
// recorder.setMediaFormat(QMediaFormat::MPEG4);
// #else
// QMediaFormat video_format;
// video_format.setAudioCodec(QMediaFormat::AudioCodec::AAC);
// // video_format.setVideoCodec(QMediaFormat::VideoCodec::H264);
// video_format.setFileFormat(QMediaFormat::MPEG4);
// recorder.setMediaFormat(video_format);
// #endif
// recorder.setQuality(QMediaRecorder::NormalQuality);

// QFileInfo file(QString::fromStdString(filename));
// recorder.setOutputLocation(
// QUrl::fromLocalFile(file.absoluteFilePath())
// );

// recorder.record();

// WallClock last_change = current_time();
// QAudioBuffer audio_buffer;
// bool success = true;
// while (audio_buffer.isValid() || !frames.empty()){
// #if 1
// while (true){
// if (frames.empty()){
// // video_input.sendVideoFrame(QVideoFrame());
// // session.setVideoFrameInput(nullptr);
// break;
// }
// if (!video_input.sendVideoFrame((*frames.begin())->frame)){
// // cout << "Failed Video: " << frames.size() << endl;
// break;
// }
// frames.pop_front();
// last_change = current_time();
// // cout << "Pushed Video: " << frames.size() << endl;
// }
// #endif
// #if 1
// while (true){
// if (!audio_buffer.isValid()){
// if (audio.empty()){
// // audio_input.sendAudioBuffer(QAudioBuffer());
// // session.setAudioBufferInput(nullptr);
// break;
// }
// // cout << "constructing audio buffer: " << audio.size() << endl;
// const std::vector<float>& samples = audio.front()->samples;
// QByteArray bytes((const char*)samples.data(), samples.size() * sizeof(float));
// audio_buffer = QAudioBuffer(
// bytes, audio_format//,
// // std::chrono::duration_cast<std::chrono::microseconds>(audio.front()->timestamp - start).count()
// );
// // cout << "audio_buffer = " << audio_buffer.isValid() << endl;
// audio.pop_front();
// }
// if (!audio_buffer.isValid()){
// break;
// }
// if (!audio_input.sendAudioBuffer(audio_buffer)){
// // cout << "Failed Audio: " << audio.size() << endl;
// // cout << audio_input.captureSession() << endl;
// break;
// }
// audio_buffer = QAudioBuffer();
// last_change = current_time();
// // cout << "Pushed audio: " << audio.size() << endl;
// }
// #endif

// if (current_time() - last_change > std::chrono::seconds(10)){
// m_logger.log("Failed to record stream history: No progress made after 10 seconds.", COLOR_RED);
// success = false;
// break;
// }

// QCoreApplication::processEvents();
// }

// recorder.stop();
// m_logger.log("Done saving stream history...", COLOR_BLUE);
// // cout << recorder.duration() << endl;


// // });
// return success;
// }
// #endif






}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,19 @@ class StreamHistoryTracker{
mutable SpinLock m_lock;
std::chrono::seconds m_window;

const size_t m_audio_samples_per_frame;
const size_t m_audio_frames_per_second;
const size_t m_audio_samples_per_second;
const double m_microseconds_per_sample;
const bool m_has_video;
// const size_t m_audio_samples_per_frame;
// const size_t m_audio_frames_per_second;
// const size_t m_audio_samples_per_second;
// const double m_microseconds_per_sample;
// const bool m_has_video;
size_t m_target_fps;
std::chrono::microseconds m_frame_interval;
WallClock m_next_frame_time;

// We use shared_ptr here so it's fast to snapshot when we need to copy
// everything asynchronously.
std::deque<std::shared_ptr<AudioBlock>> m_audio;
std::deque<std::shared_ptr<const VideoFrame>> m_frames;
// std::deque<std::shared_ptr<AudioBlock>> m_audio;
// std::deque<std::shared_ptr<const VideoFrame>> m_frames;
std::deque<CompressedVideoFrame> m_compressed_frames;

AsyncTask m_worker;
Expand Down