Skip to content

Commit

Permalink
DVR now has its own thread so it does not impact main video screen
Browse files Browse the repository at this point in the history
  • Loading branch information
gehee committed Jun 27, 2024
1 parent 50ec24e commit 5c303ae
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 34 deletions.
Empty file modified CMakeLists.txt
100755 → 100644
Empty file.
2 changes: 1 addition & 1 deletion fpvue_config.h
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#define fpvue_VERSION_MAJOR 0
#define fpvue_VERSION_MINOR 13
#define fpvue_VERSION_MINOR 13.1
89 changes: 72 additions & 17 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#include <unistd.h>
#include <inttypes.h>
#include <signal.h>
#include <fstream>
#include <queue>
#include <mutex>
#include <condition_variable>

#include <arpa/inet.h>
#include <netinet/in.h>
Expand Down Expand Up @@ -74,6 +78,8 @@ pthread_mutex_t video_mutex;
pthread_cond_t video_cond;

int video_zpos = 1;
int video_framerate = -1;
int mp4_fragmentation_mode = 0;

VideoCodec codec = VideoCodec::H265;
FILE *dvr_file = NULL;
Expand Down Expand Up @@ -171,7 +177,7 @@ void init_buffer(MppFrame frame) {
// dvr setup
if (dvr_file != NULL){
printf("setting up dvr and mux\n");
mux = MP4E_open(0 /*sequential_mode*/, 0 /*fragmentation_mode*/, dvr_file, write_callback);
mux = MP4E_open(0 /*sequential_mode*/, mp4_fragmentation_mode, dvr_file, write_callback);
if (MP4E_STATUS_OK != mp4_h26x_write_init(&mp4wr, mux, output_list->video_frm_width, output_list->video_frm_height, codec==VideoCodec::H265))
{
printf("error: mp4_h26x_write_init failed\n");
Expand Down Expand Up @@ -349,6 +355,42 @@ void sig_handler(int signum)
osd_thread_signal++;
}

std::queue<std::shared_ptr<std::vector<uint8_t>>> dvrQueue;
std::mutex mtx;
std::condition_variable cv;

void *__DVR_THREAD__(void *param) {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [dvrQueue, signal_flag] { return !dvrQueue.empty() || signal_flag; });
if (signal_flag && dvrQueue.empty()) {
break;
}
if (!dvrQueue.empty()) {
std::shared_ptr<std::vector<uint8_t>> frame = dvrQueue.front();
dvrQueue.pop();
lock.unlock();
// Process the frame
auto res = mp4_h26x_write_nal(&mp4wr, frame->data(), frame->size(), 90000/video_framerate);
if (!(MP4E_STATUS_OK == res || MP4E_STATUS_BAD_ARGUMENTS == res)) {
printf("mp4_h26x_write_nal failed with error %d\n", res);
}
}
}
MP4E_close(mux);
mp4_h26x_write_close(&mp4wr);
fclose(dvr_file);
printf("DVR thread done.\n");
}

void enqueueDvrPacket(std::shared_ptr<std::vector<uint8_t>> frame) {
{
std::lock_guard<std::mutex> lock(mtx);
dvrQueue.push(frame);
}
cv.notify_one();
}

int decoder_stalled_count=0;
bool feed_packet_to_decoder(MppPacket *packet,void* data_p,int data_len){
mpp_packet_set_data(packet, data_p);
Expand All @@ -369,14 +411,6 @@ bool feed_packet_to_decoder(MppPacket *packet,void* data_p,int data_len){
}
usleep(2 * 1000);
}

if (dvr_file!=NULL && mux != NULL){
int res = mp4_h26x_write_nal(&mp4wr, (const unsigned char*)data_p, data_len, -1);
// if (MP4E_STATUS_OK != res) {
// // This is expected to fail until a keyframe arrives.
// //printf("mp4_h26x_write_nal failed with %d", res);
// }
}
return true;
}

Expand All @@ -401,6 +435,8 @@ void read_gstreamerpipe_stream(MppPacket *packet, int gst_udp_port, const VideoC
bytes_received = 0;
}
feed_packet_to_decoder(packet,frame->data(),frame->size());

enqueueDvrPacket(frame);
};
receiver.start_receiving(cb);
while (!signal_flag){
Expand Down Expand Up @@ -482,6 +518,10 @@ void printHelp() {
"\n"
" --dvr - Save the video feed (no osd) to the provided filename\n"
"\n"
" --dvr-framerate - Force the dvr framerate fro smoother dvr\n"
"\n"
" --dvr-fmp4 - Save the video feed as a fragmented mp4\n"
"\n"
" --screen-mode - Override default screen mode. ex:1920x1080@120\n"
"\n", fpvue_VERSION_MAJOR , fpvue_VERSION_MINOR
);
Expand Down Expand Up @@ -526,6 +566,16 @@ int main(int argc, char **argv)
continue;
}

__OnArgument("--dvr-framerate") {
video_framerate = atoi(__ArgValue);
continue;
}

__OnArgument("--dvr-fmp4") {
mp4_fragmentation_mode = 1;
continue;
}

__OnArgument("--mavlink-port") {
mavlink_port = atoi(__ArgValue);
continue;
Expand Down Expand Up @@ -591,6 +641,11 @@ int main(int argc, char **argv)

__EndParseConsoleArguments__

if (dvr_file != NULL && video_framerate < 0 ) {
printf("--dvr-framerate must be provided when dvr is enabled.\n");
return 0;
}

printf("FPVue Rockchip %d.%d\n", fpvue_VERSION_MAJOR , fpvue_VERSION_MINOR);

if (enable_osd == 0 ) {
Expand Down Expand Up @@ -646,7 +701,10 @@ int main(int argc, char **argv)
ret = pthread_cond_init(&video_cond, NULL);
assert(!ret);

pthread_t tid_frame, tid_display, tid_osd, tid_mavlink;
pthread_t tid_frame, tid_display, tid_osd, tid_mavlink, tid_dvr;
if (dvr_file != NULL) {
ret = pthread_create(&tid_dvr, NULL, __DVR_THREAD__, NULL);
}
ret = pthread_create(&tid_frame, NULL, __FRAME_THREAD__, NULL);
assert(!ret);
ret = pthread_create(&tid_display, NULL, __DISPLAY_THREAD__, NULL);
Expand All @@ -666,13 +724,6 @@ int main(int argc, char **argv)
////////////////////////////////////////////// MAIN LOOP
read_gstreamerpipe_stream((void**)packet, listen_port, codec);

// Close dvr file
if (dvr_file != NULL) {
MP4E_close(mux);
mp4_h26x_write_close(&mp4wr);
fclose(dvr_file);
}

////////////////////////////////////////////// MPI CLEANUP

ret = pthread_join(tid_frame, NULL);
Expand Down Expand Up @@ -701,6 +752,10 @@ int main(int argc, char **argv)
ret = pthread_join(tid_osd, NULL);
assert(!ret);
}
if (dvr_file != NULL ){
ret = pthread_join(tid_dvr, NULL);
assert(!ret);
}

ret = mpi.mpi->reset(mpi.ctx);
assert(!ret);
Expand Down
20 changes: 4 additions & 16 deletions minimp4.h
Original file line number Diff line number Diff line change
Expand Up @@ -2322,11 +2322,10 @@ static int mp4_h265_write_nal(mp4_h26x_writer_t *h, const unsigned char *nal, in

uint64_t last_ms = 0;

int mp4_h26x_write_nal(mp4_h26x_writer_t *h, const unsigned char *nal, int length, int duration)
int mp4_h26x_write_nal(mp4_h26x_writer_t *h, const unsigned char *nal, int length, int timeStamp90kHz_next)
{
const unsigned char *eof = nal + length;
int payload_type, sizeof_nal, err = MP4E_STATUS_OK;
uint64_t cur_time = get_time_ms();
for (;;nal++)
{
#if MINIMP4_TRANSCODE_SPS_ID
Expand All @@ -2337,11 +2336,7 @@ int mp4_h26x_write_nal(mp4_h26x_writer_t *h, const unsigned char *nal, int lengt
break;
if (h->is_hevc)
{
if (duration==-1){
int dur = cur_time - last_ms;
duration = (dur/1000.0)*90000.0;
}
ERR(mp4_h265_write_nal(h, nal, sizeof_nal, duration));
ERR(mp4_h265_write_nal(h, nal, sizeof_nal, timeStamp90kHz_next));
continue;
}
payload_type = nal[0] & 31;
Expand Down Expand Up @@ -2407,7 +2402,7 @@ int mp4_h26x_write_nal(mp4_h26x_writer_t *h, const unsigned char *nal, int lengt
sample_kind = MP4E_SAMPLE_CONTINUATION;
else if (payload_type == 5)
sample_kind = MP4E_SAMPLE_RANDOM_ACCESS;
err = MP4E_put_sample(h->mux, h->mux_track_id, nal2, sizeof_nal, duration, sample_kind);
err = MP4E_put_sample(h->mux, h->mux_track_id, nal2, sizeof_nal, timeStamp90kHz_next, sample_kind);
}
break;
}
Expand Down Expand Up @@ -2451,11 +2446,7 @@ int mp4_h26x_write_nal(mp4_h26x_writer_t *h, const unsigned char *nal, int lengt
sample_kind = MP4E_SAMPLE_CONTINUATION;
else if (payload_type == 5)
sample_kind = MP4E_SAMPLE_RANDOM_ACCESS;
if (duration==-1){
int dur = cur_time - last_ms;
duration = (dur/1000)*90000;
}
err = MP4E_put_sample(h->mux, h->mux_track_id, tmp, 4 + sizeof_nal, duration, sample_kind);
err = MP4E_put_sample(h->mux, h->mux_track_id, tmp, 4 + sizeof_nal, timeStamp90kHz_next, sample_kind);
free(tmp);
}
break;
Expand All @@ -2464,9 +2455,6 @@ int mp4_h26x_write_nal(mp4_h26x_writer_t *h, const unsigned char *nal, int lengt
if (err)
break;
}
if (payload_type != 9) {
last_ms = cur_time;
}
return err;
}

Expand Down

0 comments on commit 5c303ae

Please sign in to comment.