Skip to content

Commit 135f2e9

Browse files
committed
Adding audio and actually have it work required a major refactor to have mp4 recording be its own reader/writer that closes per file.
1 parent 3d965ef commit 135f2e9

32 files changed

+3990
-2442
lines changed

Diff for: include/video/mp4_recording.h

+30-12
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,54 @@
1+
/**
2+
* MP4 Recording Module
3+
*
4+
* This module is responsible for managing MP4 recording threads.
5+
* Each recording thread is responsible for starting and stopping an MP4 recorder
6+
* for a specific stream. The actual RTSP interaction is contained within the
7+
* MP4 writer module.
8+
*/
9+
110
#ifndef MP4_RECORDING_H
211
#define MP4_RECORDING_H
312

413
#include <pthread.h>
514
#include "core/config.h"
615
#include "video/mp4_writer.h"
7-
#include "video/stream_reader.h"
816

9-
// Structure for MP4 recording context
17+
/**
18+
* Structure for MP4 recording context
19+
*
20+
* This structure represents a single recording thread that manages
21+
* an MP4 writer for a specific stream. The MP4 writer handles all
22+
* RTSP interaction internally.
23+
*/
1024
typedef struct {
11-
stream_config_t config;
12-
int running;
13-
pthread_t thread;
14-
char output_path[MAX_PATH_LENGTH];
15-
mp4_writer_t *mp4_writer;
16-
// CRITICAL FIX: Removed reader_ctx field since we now use the HLS streaming thread
17-
// to write packets to the MP4 file instead of a dedicated stream reader
25+
stream_config_t config; // Stream configuration
26+
int running; // Flag indicating if the thread is running
27+
pthread_t thread; // Recording thread
28+
char output_path[MAX_PATH_LENGTH]; // Path to the output MP4 file
29+
mp4_writer_t *mp4_writer; // MP4 writer instance
1830
} mp4_recording_ctx_t;
1931

2032
/**
2133
* Initialize MP4 recording backend
34+
*
35+
* This function initializes the recording contexts array and resets the shutdown flag.
2236
*/
2337
void init_mp4_recording_backend(void);
2438

2539
/**
2640
* Cleanup MP4 recording backend
41+
*
42+
* This function stops all recording threads and frees all recording contexts.
2743
*/
2844
void cleanup_mp4_recording_backend(void);
2945

3046
/**
3147
* Start MP4 recording for a stream
3248
*
49+
* This function creates a new recording thread for the specified stream.
50+
* The recording thread will create an MP4 writer and start the RTSP recording.
51+
*
3352
* @param stream_name Name of the stream to record
3453
* @return 0 on success, non-zero on failure
3554
*/
@@ -38,6 +57,8 @@ int start_mp4_recording(const char *stream_name);
3857
/**
3958
* Stop MP4 recording for a stream
4059
*
60+
* This function stops the recording thread for the specified stream.
61+
*
4162
* @param stream_name Name of the stream to stop recording
4263
* @return 0 on success, non-zero on failure
4364
*/
@@ -72,7 +93,4 @@ void unregister_mp4_writer_for_stream(const char *stream_name);
7293
*/
7394
void close_all_mp4_writers(void);
7495

75-
// The get_recording_state function is already defined in src/video/recording.c
76-
// We'll use that implementation instead of defining it here
77-
7896
#endif /* MP4_RECORDING_H */

Diff for: include/video/mp4_recording_internal.h

+26-36
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,34 @@
1+
/**
2+
* MP4 Recording Internal Header
3+
*
4+
* This header contains internal declarations for the MP4 recording module.
5+
* It is not intended to be used by external modules.
6+
*/
7+
18
#ifndef MP4_RECORDING_INTERNAL_H
29
#define MP4_RECORDING_INTERNAL_H
310

4-
#include <libavformat/avformat.h>
511
#include "video/mp4_recording.h"
6-
7-
// Maximum number of frames to pre-buffer (about 2 seconds at 30fps)
8-
#define MAX_PREBUFFER_FRAMES 60
9-
10-
// Structure for buffered packet
11-
typedef struct {
12-
AVPacket *packet;
13-
AVRational time_base;
14-
} buffered_packet_t;
15-
16-
// Structure for frame buffer
17-
typedef struct {
18-
buffered_packet_t *frames;
19-
int capacity;
20-
int count;
21-
int head;
22-
int tail;
23-
pthread_mutex_t mutex;
24-
} frame_buffer_t;
25-
26-
// External declarations for shared variables
12+
#include "video/thread_utils.h"
13+
14+
/**
15+
* External declarations for shared variables
16+
*
17+
* These variables are defined in mp4_recording_core.c and are used
18+
* by other files in the MP4 recording module.
19+
*/
2720
extern mp4_recording_ctx_t *recording_contexts[MAX_STREAMS];
28-
extern mp4_writer_t *mp4_writers[MAX_STREAMS];
29-
extern char mp4_writer_stream_names[MAX_STREAMS][64];
30-
extern frame_buffer_t frame_buffers[MAX_STREAMS];
31-
32-
// Frame buffer functions
33-
int init_frame_buffer(const char *stream_name, int capacity);
34-
void add_to_frame_buffer(int buffer_idx, const AVPacket *pkt, const AVStream *stream);
35-
void flush_frame_buffer(int buffer_idx, mp4_writer_t *writer);
36-
void free_frame_buffer(int buffer_idx);
37-
38-
// Add a packet to the pre-buffer for a stream
39-
void add_packet_to_prebuffer(const char *stream_name, const AVPacket *pkt, const AVStream *stream);
4021

41-
// Flush the pre-buffered frames to the MP4 writer
42-
void flush_prebuffer_to_mp4(const char *stream_name);
22+
/**
23+
* Update MP4 recording metadata in the database
24+
*
25+
* This function is called periodically to update the recording metadata
26+
* in the database.
27+
*
28+
* @param stream_name Name of the stream
29+
*/
30+
void update_mp4_recording(const char *stream_name);
31+
32+
// We'll use the pthread_join_with_timeout function from thread_utils.h
4333

4434
#endif /* MP4_RECORDING_INTERNAL_H */

Diff for: include/video/mp4_writer.h

+80-5
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,53 @@
66
#define MP4_WRITER_H
77

88
#include <libavformat/avformat.h>
9+
#include <pthread.h>
910
#include "core/config.h" // For MAX_PATH_LENGTH and MAX_STREAM_NAME
1011

1112
// Forward declaration of the MP4 writer structure
1213
typedef struct mp4_writer mp4_writer_t;
1314

15+
// Audio stream state structure - completely separate from video
16+
typedef struct {
17+
int stream_idx; // Index of the audio stream in the output context
18+
int64_t first_dts; // First audio DTS for timestamp reference
19+
int64_t last_pts; // Last audio PTS written
20+
int64_t last_dts; // Last audio DTS written
21+
int initialized; // Flag to track if audio has been initialized
22+
AVRational time_base; // Audio stream timebase
23+
pthread_mutex_t mutex; // Mutex to protect audio state
24+
} mp4_audio_state_t;
25+
1426
// Full definition of the MP4 writer structure
1527
struct mp4_writer {
1628
char output_path[MAX_PATH_LENGTH];
1729
char stream_name[MAX_STREAM_NAME];
1830
AVFormatContext *output_ctx;
1931
int video_stream_idx;
20-
int audio_stream_idx; // Index of the audio stream (-1 if none)
2132
int has_audio; // Flag indicating if audio is enabled
22-
int64_t first_dts;
23-
int64_t first_pts;
24-
int64_t last_dts;
25-
AVRational time_base;
33+
int64_t first_dts; // First video DTS
34+
int64_t first_pts; // First video PTS
35+
int64_t last_dts; // Last video DTS
36+
AVRational time_base; // Video stream timebase
2637
int is_initialized;
2738
time_t creation_time;
2839
time_t last_packet_time; // Time when the last packet was written
40+
mp4_audio_state_t audio; // Audio state - completely separate from video
41+
pthread_mutex_t mutex; // Mutex to protect video state
42+
uint64_t current_recording_id; // ID of the current recording in the database
43+
44+
// Segment-related fields
45+
int segment_duration; // Duration of each segment in seconds
46+
time_t last_rotation_time;// Time of the last rotation
47+
int waiting_for_keyframe; // Flag indicating if we're waiting for a keyframe to rotate
48+
int is_rotating; // Flag indicating if rotation is in progress
49+
char output_dir[MAX_PATH_LENGTH]; // Directory where MP4 files are stored
50+
51+
// RTSP thread context
52+
void *thread_ctx; // Opaque pointer to thread context
53+
54+
// Shutdown coordination
55+
int shutdown_component_id; // ID assigned by the shutdown coordinator
2956
};
3057

3158
/**
@@ -39,6 +66,7 @@ mp4_writer_t *mp4_writer_create(const char *output_path, const char *stream_name
3966

4067
/**
4168
* Write a packet to the MP4 file
69+
* This function handles both video and audio packets
4270
*
4371
* @param writer The MP4 writer instance
4472
* @param pkt The packet to write
@@ -47,11 +75,58 @@ mp4_writer_t *mp4_writer_create(const char *output_path, const char *stream_name
4775
*/
4876
int mp4_writer_write_packet(mp4_writer_t *writer, const AVPacket *pkt, const AVStream *input_stream);
4977

78+
/**
79+
* Safely add audio stream to MP4 writer
80+
*
81+
* @param writer The MP4 writer instance
82+
* @param codec_params Codec parameters for the audio stream
83+
* @param time_base Time base for the audio stream
84+
* @return 0 on success, negative on error
85+
*/
86+
int mp4_writer_add_audio_stream(mp4_writer_t *writer, const AVCodecParameters *codec_params,
87+
const AVRational *time_base);
88+
5089
/**
5190
* Close the MP4 writer and release resources
5291
*
5392
* @param writer The MP4 writer instance
5493
*/
5594
void mp4_writer_close(mp4_writer_t *writer);
5695

96+
/**
97+
* Set the segment duration for MP4 rotation
98+
*
99+
* @param writer The MP4 writer instance
100+
* @param segment_duration Duration of each segment in seconds
101+
*/
102+
void mp4_writer_set_segment_duration(mp4_writer_t *writer, int segment_duration);
103+
104+
// Rotation is now handled entirely by the writer thread in mp4_writer_rtsp.c
105+
106+
/**
107+
* Start a recording thread that reads from the RTSP stream and writes to the MP4 file
108+
* This function creates a new thread that handles all the recording logic
109+
*
110+
* @param writer The MP4 writer instance
111+
* @param rtsp_url The URL of the RTSP stream to record
112+
* @return 0 on success, negative on error
113+
*/
114+
int mp4_writer_start_recording_thread(mp4_writer_t *writer, const char *rtsp_url);
115+
116+
/**
117+
* Stop the recording thread
118+
* This function signals the recording thread to stop and waits for it to exit
119+
*
120+
* @param writer The MP4 writer instance
121+
*/
122+
void mp4_writer_stop_recording_thread(mp4_writer_t *writer);
123+
124+
/**
125+
* Check if the recording thread is running
126+
*
127+
* @param writer The MP4 writer instance
128+
* @return 1 if running, 0 if not
129+
*/
130+
int mp4_writer_is_recording(mp4_writer_t *writer);
131+
57132
#endif /* MP4_WRITER_H */

Diff for: include/video/mp4_writer_internal.h

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Internal header file for MP4 writer implementation
3+
*/
4+
5+
#ifndef MP4_WRITER_INTERNAL_H
6+
#define MP4_WRITER_INTERNAL_H
7+
8+
#include <libavformat/avformat.h>
9+
#include "video/mp4_writer.h"
10+
11+
/**
12+
* Initialize the MP4 writer with the first packet
13+
*
14+
* @param writer The MP4 writer instance
15+
* @param pkt The first packet to write
16+
* @param input_stream The original input stream (for codec parameters)
17+
* @return 0 on success, negative on error
18+
*/
19+
int mp4_writer_initialize(mp4_writer_t *writer, const AVPacket *pkt, const AVStream *input_stream);
20+
21+
/**
22+
* Apply h264_mp4toannexb bitstream filter to convert H.264 stream from MP4 format to Annex B format
23+
* This is needed for some RTSP cameras that send H.264 in MP4 format instead of Annex B format
24+
*
25+
* @param packet The packet to convert
26+
* @param codec_id The codec ID of the stream
27+
* @return 0 on success, negative on error
28+
*/
29+
int apply_h264_annexb_filter(AVPacket *packet, enum AVCodecID codec_id);
30+
31+
/**
32+
* Write a packet to the MP4 file
33+
* This function handles both video and audio packets
34+
*
35+
* @param writer The MP4 writer instance
36+
* @param in_pkt The packet to write
37+
* @param input_stream The original input stream (for codec parameters)
38+
* @return 0 on success, negative on error
39+
*/
40+
int mp4_writer_write_packet(mp4_writer_t *writer, const AVPacket *in_pkt, const AVStream *input_stream);
41+
42+
#endif /* MP4_WRITER_INTERNAL_H */

Diff for: include/video/recording_types.h

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Header file for recording types
3+
*/
4+
5+
#ifndef RECORDING_TYPES_H
6+
#define RECORDING_TYPES_H
7+
8+
#include <time.h>
9+
#include <stdint.h>
10+
#include "../core/config.h" // For MAX_PATH_LENGTH and MAX_STREAM_NAME
11+
12+
// Structure for active recording tracking
13+
typedef struct {
14+
uint64_t recording_id; // Database ID of the recording
15+
char stream_name[MAX_STREAM_NAME]; // Name of the stream being recorded
16+
char output_path[MAX_PATH_LENGTH]; // Path where recording is stored
17+
time_t start_time; // When the recording started
18+
} active_recording_t;
19+
20+
#endif /* RECORDING_TYPES_H */

0 commit comments

Comments
 (0)