5
5
6
6
#include "compat.h"
7
7
#include "config.h"
8
+ #include "lock_util.h"
8
9
#include "log.h"
9
10
10
11
static const AVRational SCRCPY_TIME_BASE = {1 , 1000000 }; // timestamps in us
@@ -26,6 +27,82 @@ find_muxer(const char *name) {
26
27
return oformat ;
27
28
}
28
29
30
+ static struct record_packet *
31
+ record_packet_new (const AVPacket * packet ) {
32
+ struct record_packet * rec = SDL_malloc (sizeof (* rec ));
33
+ if (!rec ) {
34
+ return NULL ;
35
+ }
36
+ if (av_packet_ref (& rec -> packet , packet )) {
37
+ SDL_free (rec );
38
+ return NULL ;
39
+ }
40
+ rec -> next = NULL ;
41
+ return rec ;
42
+ }
43
+
44
+ static void
45
+ record_packet_delete (struct record_packet * rec ) {
46
+ av_packet_unref (& rec -> packet );
47
+ SDL_free (rec );
48
+ }
49
+
50
+ static void
51
+ recorder_queue_init (struct recorder_queue * queue ) {
52
+ queue -> first = NULL ;
53
+ // queue->last is undefined if queue->first == NULL
54
+ }
55
+
56
+ static inline bool
57
+ recorder_queue_is_empty (struct recorder_queue * queue ) {
58
+ return !queue -> first ;
59
+ }
60
+
61
+ static bool
62
+ recorder_queue_push (struct recorder_queue * queue , const AVPacket * packet ) {
63
+ struct record_packet * rec = record_packet_new (packet );
64
+ if (!rec ) {
65
+ LOGC ("Could not allocate record packet" );
66
+ return false;
67
+ }
68
+ rec -> next = NULL ;
69
+
70
+ if (recorder_queue_is_empty (queue )) {
71
+ queue -> first = queue -> last = rec ;
72
+ } else {
73
+ // chain rec after the (current) last packet
74
+ queue -> last -> next = rec ;
75
+ // the last packet is now rec
76
+ queue -> last = rec ;
77
+ }
78
+ return true;
79
+ }
80
+
81
+ static inline struct record_packet *
82
+ recorder_queue_take (struct recorder_queue * queue ) {
83
+ SDL_assert (!recorder_queue_is_empty (queue ));
84
+
85
+ struct record_packet * rec = queue -> first ;
86
+ SDL_assert (rec );
87
+
88
+ queue -> first = rec -> next ;
89
+ // no need to update queue->last if the queue is left empty:
90
+ // queue->last is undefined if queue->first == NULL
91
+
92
+ return rec ;
93
+ }
94
+
95
+ static void
96
+ recorder_queue_clear (struct recorder_queue * queue ) {
97
+ struct record_packet * rec = queue -> first ;
98
+ while (rec ) {
99
+ struct record_packet * current = rec ;
100
+ rec = rec -> next ;
101
+ record_packet_delete (current );
102
+ }
103
+ queue -> first = NULL ;
104
+ }
105
+
29
106
bool
30
107
recorder_init (struct recorder * recorder ,
31
108
const char * filename ,
@@ -37,6 +114,24 @@ recorder_init(struct recorder *recorder,
37
114
return false;
38
115
}
39
116
117
+ recorder -> mutex = SDL_CreateMutex ();
118
+ if (!recorder -> mutex ) {
119
+ LOGC ("Could not create mutex" );
120
+ SDL_free (recorder -> filename );
121
+ return false;
122
+ }
123
+
124
+ recorder -> queue_cond = SDL_CreateCond ();
125
+ if (!recorder -> queue_cond ) {
126
+ LOGC ("Could not create cond" );
127
+ SDL_DestroyMutex (recorder -> mutex );
128
+ SDL_free (recorder -> filename );
129
+ return false;
130
+ }
131
+
132
+ recorder_queue_init (& recorder -> queue );
133
+ recorder -> stopped = false;
134
+ recorder -> failed = false;
40
135
recorder -> format = format ;
41
136
recorder -> declared_frame_size = declared_frame_size ;
42
137
recorder -> header_written = false;
@@ -46,6 +141,8 @@ recorder_init(struct recorder *recorder,
46
141
47
142
void
48
143
recorder_destroy (struct recorder * recorder ) {
144
+ SDL_DestroyCond (recorder -> queue_cond );
145
+ SDL_DestroyMutex (recorder -> mutex );
49
146
SDL_free (recorder -> filename );
50
147
}
51
148
@@ -186,3 +283,90 @@ recorder_write(struct recorder *recorder, AVPacket *packet) {
186
283
recorder_rescale_packet (recorder , packet );
187
284
return av_write_frame (recorder -> ctx , packet ) >= 0 ;
188
285
}
286
+
287
+ static int
288
+ run_recorder (void * data ) {
289
+ struct recorder * recorder = data ;
290
+
291
+ for (;;) {
292
+ mutex_lock (recorder -> mutex );
293
+
294
+ while (!recorder -> stopped &&
295
+ recorder_queue_is_empty (& recorder -> queue )) {
296
+ cond_wait (recorder -> queue_cond , recorder -> mutex );
297
+ }
298
+
299
+ // if stopped is set, continue to process the remaining events (to
300
+ // finish the recording) before actually stopping
301
+
302
+ if (recorder -> stopped && recorder_queue_is_empty (& recorder -> queue )) {
303
+ mutex_unlock (recorder -> mutex );
304
+ break ;
305
+ }
306
+
307
+ struct record_packet * rec = recorder_queue_take (& recorder -> queue );
308
+
309
+ mutex_unlock (recorder -> mutex );
310
+
311
+ bool ok = recorder_write (recorder , & rec -> packet );
312
+ record_packet_delete (rec );
313
+ if (!ok ) {
314
+ LOGE ("Could not record packet" );
315
+
316
+ mutex_lock (recorder -> mutex );
317
+ recorder -> failed = true;
318
+ // discard pending packets
319
+ recorder_queue_clear (& recorder -> queue );
320
+ mutex_unlock (recorder -> mutex );
321
+ break ;
322
+ }
323
+
324
+ }
325
+
326
+ LOGD ("Recorder thread ended" );
327
+
328
+ return 0 ;
329
+ }
330
+
331
+ bool
332
+ recorder_start (struct recorder * recorder ) {
333
+ LOGD ("Starting recorder thread" );
334
+
335
+ recorder -> thread = SDL_CreateThread (run_recorder , "recorder" , recorder );
336
+ if (!recorder -> thread ) {
337
+ LOGC ("Could not start recorder thread" );
338
+ return false;
339
+ }
340
+
341
+ return true;
342
+ }
343
+
344
+ void
345
+ recorder_stop (struct recorder * recorder ) {
346
+ mutex_lock (recorder -> mutex );
347
+ recorder -> stopped = true;
348
+ cond_signal (recorder -> queue_cond );
349
+ mutex_unlock (recorder -> mutex );
350
+ }
351
+
352
+ void
353
+ recorder_join (struct recorder * recorder ) {
354
+ SDL_WaitThread (recorder -> thread , NULL );
355
+ }
356
+
357
+ bool
358
+ recorder_push (struct recorder * recorder , const AVPacket * packet ) {
359
+ mutex_lock (recorder -> mutex );
360
+ SDL_assert (!recorder -> stopped );
361
+
362
+ if (recorder -> failed ) {
363
+ // reject any new packet (this will stop the stream)
364
+ return false;
365
+ }
366
+
367
+ bool ok = recorder_queue_push (& recorder -> queue , packet );
368
+ cond_signal (recorder -> queue_cond );
369
+
370
+ mutex_unlock (recorder -> mutex );
371
+ return ok ;
372
+ }
0 commit comments