blob: 6cc2964f4d6c66093bcfeaf4112a4faf10c2e5b6 [file] [log] [blame]
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001#include <stddef.h>
Zhiqiang Han620b9252021-11-09 14:23:20 +08002#include <unistd.h>
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08003#include <stdlib.h>
4#include <pthread.h>
5#include <string.h>
6#include <time.h>
7#include <errno.h>
Zhiqiang Han18f42c82021-08-11 17:13:28 +08008#include <sys/time.h>
9#include <time.h>
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080010
11#include "dvr_types.h"
12#include "dvr_record.h"
13#include "dvr_crypto.h"
14#include "dvr_playback.h"
15#include "dvr_segment.h"
16
17#include "AmTsPlayer.h"
18
19#include "list.h"
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080020
21#include "dvr_wrapper.h"
22
Gong Ke2a0ebbe2021-05-25 15:22:50 +080023#define DVR_WRAPPER_DEBUG(_level, _fmt...) \
24 DVR_DEBUG_FL(_level, "wrapper", _fmt)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080025
26/*duration of data to resume if paused with EVT_REACHED_END in timeshifting*/
hualing chen2932d372020-04-29 13:44:00 +080027#define TIMESHIFT_DATA_DURATION_TO_RESUME (600)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080028/*a tolerant gap*/
29#define DVR_PLAYBACK_END_GAP (1000)
30
31enum {
32 W_REC = 1,
33 W_PLAYBACK = 2,
34};
35
36enum {
37 U_PIDS = 0x01,
38 U_STAT = 0x02,
39 U_ALL = U_PIDS | U_STAT,
40};
41
42typedef struct {
43 /*make lock the 1st item in the structure*/
44 pthread_mutex_t lock;
45
46 /*rec or play*/
47 int type;
48
49 /*valid if (sn != 0)*/
50 unsigned long sn;
51 unsigned long sn_linked;
52
53 struct list_head segments; /**<head-add list*/
54 uint64_t current_segment_id; /**<id of the current segment*/
55
56 union {
57 struct {
58 DVR_WrapperRecordOpenParams_t param_open;
59 DVR_RecordStartParams_t param_start;
60 DVR_RecordStartParams_t param_update;
61 DVR_RecordHandle_t recorder;
62 DVR_RecordEventFunction_t event_fn;
63 void *event_userdata;
64
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080065 /*total status = seg_status + status + obsolete*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080066 DVR_RecordStatus_t seg_status; /**<status of current segment*/
67 DVR_WrapperRecordStatus_t status; /**<status of remaining segments*/
68 uint64_t next_segment_id;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080069
70 DVR_WrapperInfo_t obsolete; /**<data obsolete due to the max limit*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080071 } record;
72
73 struct {
74 DVR_WrapperPlaybackOpenParams_t param_open;
75 DVR_PlaybackHandle_t player;
76 DVR_PlaybackEventFunction_t event_fn;
77 void *event_userdata;
78
79 /*total status = seg_status + status*/
80 DVR_PlaybackStatus_t seg_status;
81 DVR_WrapperPlaybackStatus_t status;
82 DVR_PlaybackPids_t pids_req;
83 DVR_PlaybackEvent_t last_event;
Zhiqiang Han3eb75f92020-04-08 10:07:55 +080084 float speed;
hualing chenb5cd42e2020-04-15 17:03:34 +080085 DVR_Bool_t reach_end;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080086
87 DVR_WrapperInfo_t obsolete;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080088 } playback;
89 };
90} DVR_WrapperCtx_t;
91
92typedef struct {
93 struct list_head head;
94 unsigned long sn;
95
96 /* rec or playback */
97 int type;
98
99 union {
100 struct {
101 DVR_RecordEvent_t event;
102 DVR_RecordStatus_t status;
103 } record;
104 struct {
105 DVR_PlaybackEvent_t event;
106 DVR_Play_Notify_t status;
107 } playback;
108 };
109} DVR_WrapperEventCtx_t;
110
111typedef struct {
112 pthread_mutex_t lock;
113 char *name;
114 int running;
115 pthread_cond_t cond;
116 pthread_t thread;
117 int type;
118} DVR_WrapperThreadCtx_t;
119
120typedef struct {
121 struct list_head head;
122
123 DVR_RecordSegmentInfo_t seg_info;
124 DVR_PlaybackSegmentInfo_t playback_info;
125} DVR_WrapperPlaybackSegmentInfo_t;
126
127typedef struct {
128 struct list_head head;
129
130 DVR_RecordSegmentInfo_t info;
131} DVR_WrapperRecordSegmentInfo_t;
132
133/* serial num generater */
134static unsigned long sn = 1;
135static pthread_mutex_t sn_lock = PTHREAD_MUTEX_INITIALIZER;
136
137static inline unsigned long get_sn()
138{
hualing chenab0d1262021-09-26 15:22:50 +0800139 unsigned long no = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800140
141 pthread_mutex_lock(&sn_lock);
142 no = sn++;
143 if (!no)
144 no = sn++;
145 pthread_mutex_unlock(&sn_lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800146 return no;
147}
148
149/* entity ctx */
150#define DVR_WRAPPER_MAX 10
151
152static DVR_WrapperCtx_t record_list[DVR_WRAPPER_MAX] =
153{
154 [0 ... (DVR_WRAPPER_MAX - 1)] =
155 {
156 .lock = PTHREAD_MUTEX_INITIALIZER,
157 .type = W_REC,
158 }
159};
160
161static DVR_WrapperCtx_t playback_list[DVR_WRAPPER_MAX] =
162{
163 [0 ... (DVR_WRAPPER_MAX - 1)] =
164 {
165 .lock = PTHREAD_MUTEX_INITIALIZER,
166 .type = W_PLAYBACK,
167 }
168};
169
170/* events lists */
171static struct list_head record_evt_list = LIST_HEAD_INIT(record_evt_list);
172static struct list_head playback_evt_list = LIST_HEAD_INIT(playback_evt_list);
173
174static pthread_mutex_t record_evt_list_lock = PTHREAD_MUTEX_INITIALIZER;
175static pthread_mutex_t playback_evt_list_lock = PTHREAD_MUTEX_INITIALIZER;
176
177static DVR_WrapperThreadCtx_t wrapper_thread[2] =
178{
179 [0] =
180 {
181 .lock = PTHREAD_MUTEX_INITIALIZER,
182 .running = 0,
183 .name = "record",
184 .type = W_REC,
185 },
186 [1] =
187 {
188 .lock = PTHREAD_MUTEX_INITIALIZER,
189 .running = 0,
190 .name = "playback",
191 .type = W_PLAYBACK,
192 },
193};
194
195/*now only support one timeshift now*/
196static unsigned long sn_timeshift_record;
197static unsigned long sn_timeshift_playback;
198
199static void *wrapper_task(void *arg);
200static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx);
201
202static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata);
203static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata);
204
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800205static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordStatus_t *status);
206static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperPlaybackStatus_t *status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800207
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800208static int get_timespec_timeout(int timeout, struct timespec *ts)
209{
210 struct timespec ots;
211 int left, diff;
212
213 clock_gettime(CLOCK_MONOTONIC, &ots);
214
215 ts->tv_sec = ots.tv_sec + timeout / 1000;
216 ts->tv_nsec = ots.tv_nsec;
217
218 left = timeout % 1000;
219 left *= 1000000;
220 diff = 1000000000 - ots.tv_nsec;
221
222 if (diff <= left) {
223 ts->tv_sec++;
224 ts->tv_nsec = left-diff;
225 } else {
226 ts->tv_nsec += left;
227 }
228
229 return 0;
230}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800231
232static DVR_WrapperEventCtx_t *ctx_getEvent(struct list_head *list, pthread_mutex_t *list_lock)
233{
234 DVR_WrapperEventCtx_t *pevt;
235
236 pthread_mutex_lock(list_lock);
237 if (list_empty(list))
238 pevt = NULL;
239 else {
240 pevt = list_first_entry(list, DVR_WrapperEventCtx_t, head);
241 list_del(&pevt->head);
242 }
243 pthread_mutex_unlock(list_lock);
244
245 return pevt;
246}
247
248static inline DVR_WrapperEventCtx_t *ctx_getRecordEvent()
249{
250 return ctx_getEvent(&record_evt_list, &record_evt_list_lock);
251}
252
253static inline DVR_WrapperEventCtx_t *ctx_getPlaybackEvent()
254{
255 return ctx_getEvent(&playback_evt_list, &playback_evt_list_lock);
256}
257
258static int ctx_addEvent(struct list_head *list, pthread_mutex_t *lock, DVR_WrapperEventCtx_t *evt)
259{
260 DVR_WrapperEventCtx_t *padd;
261 padd = (DVR_WrapperEventCtx_t *)calloc(1, sizeof(DVR_WrapperEventCtx_t));
262 DVR_RETURN_IF_FALSE(padd);
263
264 *padd = *evt;
265 pthread_mutex_lock(lock);
266 list_add_tail(&padd->head, list);
267 pthread_mutex_unlock(lock);
268 return DVR_SUCCESS;
269}
270
271static inline void ctx_freeEvent(DVR_WrapperEventCtx_t *evt)
272{
273 free(evt);
274}
275
276/*useless*/
277static void ctx_cleanOutdatedEvents(struct list_head *evt_list,
278 pthread_mutex_t *evt_list_lock,
279 DVR_WrapperCtx_t *list)
280{
281 DVR_WrapperEventCtx_t *pevt, *pevt_tmp;
282 unsigned long sns[DVR_WRAPPER_MAX];
283 int cnt = 0;
284 int i;
285 int found = 0;
286
287 /*copy all valid sns*/
288 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
289 sns[cnt] = list[i].sn;
290 if (!sns[cnt])
291 cnt++;
292 }
293
294 /*free evts that not belong to any valid sns*/
295 pthread_mutex_lock(evt_list_lock);
296 list_for_each_entry_safe(pevt, pevt_tmp, evt_list, head) {
297 for (i = 0; i < cnt; i++) {
298 if (pevt->sn == sns[i]) {
299 found = 1;
300 break;
301 }
302 }
303 if (!found) {
304 list_del(&pevt->head);
305 ctx_freeEvent(pevt);
306 }
307 }
308 pthread_mutex_unlock(evt_list_lock);
309}
310
311static inline void ctx_cleanOutdatedRecordEvents()
312{
313 ctx_cleanOutdatedEvents(&record_evt_list, &record_evt_list_lock, record_list);
314}
315
316static inline void ctx_cleanOutdatedPlaybackEvents()
317{
318 ctx_cleanOutdatedEvents(&playback_evt_list, &playback_evt_list_lock, playback_list);
319}
320
hualing chenb9b358a2021-08-17 15:06:36 +0800321//check this play is recording file
322//return 0 if not the recording
323//else return record id
324static inline int ctx_isPlay_recording(char *play_location)
325{
326 int i;
327 DVR_WrapperCtx_t *cnt;
328
329 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
330 cnt = &record_list[i];
331 //DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]R:[%s]P:[%s] ...\n", i, cnt->sn, cnt->record.param_open.location, play_location);
332 if (!strcmp(cnt->record.param_open.location, play_location)) {
333 DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]R:[%s]P:[%s] .found..\n", i, cnt->sn, cnt->record.param_open.location, play_location);
334 return cnt->sn;
335 }
336 }
337 DVR_WRAPPER_DEBUG(1, " not found play is recing [%d]", DVR_WRAPPER_MAX);
338 return 0;
339}
340//check this record is playing file
341//return 0 if not the playing
342//else return playback id
343static inline int ctx_isRecord_playing(char *rec_location)
344{
345 int i;
346 DVR_WrapperCtx_t *cnt;
347 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
348 cnt = &playback_list[i];
349 //DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]P[%s]R[%s] ...\n", i, cnt->sn, cnt->playback.param_open.location, rec_location);
350 if (!strcmp(cnt->playback.param_open.location, rec_location)) {
351 DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]P[%s]R[%s] ..found.\n",i, cnt->sn, cnt->playback.param_open.location, rec_location);
352 return cnt->sn;
353 }
354 }
355 DVR_WRAPPER_DEBUG(1, " not found rec is playing [%d]", DVR_WRAPPER_MAX);
356 return 0;
357}
358
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800359static inline DVR_WrapperCtx_t *ctx_get(unsigned long sn, DVR_WrapperCtx_t *list)
360{
361 int i;
362 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
363 if (list[i].sn == sn)
364 return &list[i];
365 }
366 return NULL;
367}
368
369static inline void ctx_reset(DVR_WrapperCtx_t *ctx)
370{
371 memset((char *)ctx + offsetof(DVR_WrapperCtx_t, sn),
372 0,
373 sizeof(DVR_WrapperCtx_t) - offsetof(DVR_WrapperCtx_t, sn));
374}
375
376static inline int ctx_valid(DVR_WrapperCtx_t *ctx)
377{
378 return (ctx->sn != 0);
379}
380
381static inline DVR_WrapperCtx_t *ctx_getRecord(unsigned long sn)
382{
383 return ctx_get(sn, record_list);
384}
385
386static inline DVR_WrapperCtx_t *ctx_getPlayback(unsigned long sn)
387{
388 return ctx_get(sn, playback_list);
389}
390
391static int wrapper_requestThread(DVR_WrapperThreadCtx_t *ctx, void *(thread_fn)(void *))
392{
393 pthread_mutex_lock(&ctx->lock);
394 if (ctx->running == 0) {
395 pthread_condattr_t attr;
396 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
397 pthread_cond_init(&ctx->cond, &attr);
398 pthread_condattr_destroy(&attr);
399 DVR_WRAPPER_DEBUG(1, "start wrapper thread(%s) ...\n", ctx->name);
400 pthread_create(&ctx->thread, NULL, thread_fn, ctx);
401 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) started\n", ctx->name);
402 }
403 ctx->running++;
404 pthread_mutex_unlock(&ctx->lock);
405 return 0;
406}
407
408static int wrapper_releaseThread(DVR_WrapperThreadCtx_t *ctx)
409{
410 pthread_mutex_lock(&ctx->lock);
411 ctx->running--;
412 if (!ctx->running) {
413 pthread_cond_broadcast(&ctx->cond);
414 pthread_mutex_unlock(&ctx->lock);
415
416 DVR_WRAPPER_DEBUG(1, "stop wrapper thread(%s) ...\n", ctx->name);
417 pthread_join(ctx->thread, NULL);
418 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) stopped\n", ctx->name);
419
420 pthread_mutex_lock(&ctx->lock);
421 if (!ctx->running) /*protect*/
422 pthread_cond_destroy(&ctx->cond);
423 }
424 pthread_mutex_unlock(&ctx->lock);
425 return 0;
426}
427
428#define WRAPPER_THREAD_RECORD (&wrapper_thread[0])
429#define WRAPPER_THREAD_PLAYBACK (&wrapper_thread[1])
430
431static inline int wrapper_requestThreadFor(DVR_WrapperCtx_t *ctx)
432{
433 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
434 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
435 return wrapper_requestThread(thread_ctx, wrapper_task);
436}
437
438static inline int wrapper_releaseThreadFor(DVR_WrapperCtx_t *ctx)
439{
440 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
441 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
442 return wrapper_releaseThread(thread_ctx);
443}
444
445static inline int wrapper_releaseThreadForType(int type)
446{
447 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC)?
448 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
449 return wrapper_releaseThread(thread_ctx);
450}
451
452static inline void wrapper_threadSignal(DVR_WrapperThreadCtx_t *thread_ctx)
453{
454 pthread_cond_signal(&thread_ctx->cond);
455}
456
457static inline int wrapper_threadWait(DVR_WrapperThreadCtx_t *thread_ctx)
458{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800459 struct timespec rt;
460 get_timespec_timeout(200, &rt);
461 pthread_cond_timedwait(&thread_ctx->cond, &thread_ctx->lock, &rt);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800462 return 0;
463}
464
465static inline void wrapper_threadSignalForType(int type)
466{
467 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC) ?
468 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
469 wrapper_threadSignal(thread_ctx);
470}
471
472static inline void wrapper_threadSignalFor(DVR_WrapperCtx_t *ctx)
473{
474 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
475 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
476 wrapper_threadSignal(thread_ctx);
477}
478
479static inline int wrapper_threadWaitFor(DVR_WrapperCtx_t *ctx)
480{
481 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
482 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
483 wrapper_threadWait(thread_ctx);
484 return 0;
485}
486
487static void get_timeout_real(int timeout, struct timespec *ts)
488{
489 struct timespec ots;
490 int left, diff;
491
492 clock_gettime(CLOCK_REALTIME, &ots);
493
494 ts->tv_sec = ots.tv_sec + timeout/1000;
495 ts->tv_nsec = ots.tv_nsec;
496
497 left = timeout % 1000;
498 left *= 1000000;
499 diff = 1000000000-ots.tv_nsec;
500
501 if (diff <= left) {
502 ts->tv_sec++;
503 ts->tv_nsec = left-diff;
504 } else {
505 ts->tv_nsec += left;
506 }
507}
508
509/*return condition, locked if condition == true*/
510static int wrapper_mutex_lock_if(pthread_mutex_t *lock, int *condition)
511{
512 int r2;
513 do {
514 struct timespec rt2;
515 /*android use real time for mutex timedlock*/
516 get_timeout_real(10, &rt2);
517 r2 = pthread_mutex_timedlock(lock, &rt2);
518 } while (*condition && (r2 == ETIMEDOUT));
519
520 if (!(*condition) && (r2 == 0))
521 pthread_mutex_unlock(lock);
522
523 return *condition;
524}
525
526static void *wrapper_task(void *arg)
527{
528 DVR_WrapperThreadCtx_t *tctx = (DVR_WrapperThreadCtx_t *)arg;
529 DVR_WrapperEventCtx_t *evt;
530
531 pthread_mutex_lock(&tctx->lock);
532
533 while (tctx->running) {
534 {
535 int ret;
hualing chene3797f02021-01-13 14:53:28 +0800536
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800537 evt = (tctx->type == W_REC)? ctx_getRecordEvent() : ctx_getPlaybackEvent();
538 if (!evt)
539 ret = wrapper_threadWait(tctx);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800540 }
541
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800542 while (evt) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800543 DVR_WrapperCtx_t *ctx = (evt->type == W_REC)?
544 ctx_getRecord(evt->sn) : ctx_getPlayback(evt->sn);
hualing chenbc0aec92021-03-18 14:52:40 +0800545 if (ctx == NULL) {
546 DVR_WRAPPER_DEBUG(1, "warp not get ctx.free event..\n");
547 goto processed;
548 }
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800549 DVR_WRAPPER_DEBUG(1, "start name(%s) sn(%d) running(%d) type(%d)\n", tctx->name, (int)ctx->sn, tctx->running, tctx->type);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800550 if (tctx->running) {
551 /*
552 continue not break,
553 make all events consumed, or mem leak
554 */
555 if (!wrapper_mutex_lock_if(&ctx->lock, &tctx->running))
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800556 goto processed;
557
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800558 if (ctx_valid(ctx)) {
559 /*double check after lock*/
Zhiqiang Han3b9c9082021-11-10 10:41:09 +0800560 if (evt->sn == ctx->sn) {
561 pthread_mutex_unlock(&tctx->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800562 process_handleEvents(evt, ctx);
Zhiqiang Han3b9c9082021-11-10 10:41:09 +0800563 pthread_mutex_lock(&tctx->lock);
564 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800565 }
566 pthread_mutex_unlock(&ctx->lock);
567 }
568
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800569processed:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800570 ctx_freeEvent(evt);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800571
572 evt = (tctx->type == W_REC)? ctx_getRecordEvent() : ctx_getPlaybackEvent();
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800573 }
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800574 DVR_WRAPPER_DEBUG(1, "start name(%s) running(%d) type(%d) con...\n", tctx->name, tctx->running, tctx->type);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800575 }
576
577 pthread_mutex_unlock(&tctx->lock);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800578 DVR_WRAPPER_DEBUG(1, "end name(%s) running(%d) type(%d) end...\n", tctx->name, tctx->running, tctx->type);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800579 return NULL;
580}
581
582static inline int ctx_addRecordEvent(DVR_WrapperEventCtx_t *evt)
583{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800584 pthread_mutex_lock(&WRAPPER_THREAD_RECORD->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800585 if (ctx_addEvent(&record_evt_list, &record_evt_list_lock, evt) == 0)
586 wrapper_threadSignalForType(evt->type);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800587 pthread_mutex_unlock(&WRAPPER_THREAD_RECORD->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800588 return 0;
589}
590
591static inline int ctx_addPlaybackEvent(DVR_WrapperEventCtx_t *evt)
592{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800593 pthread_mutex_lock(&WRAPPER_THREAD_PLAYBACK->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800594 if (ctx_addEvent(&playback_evt_list, &playback_evt_list_lock, evt) == 0)
595 wrapper_threadSignalForType(evt->type);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800596 pthread_mutex_unlock(&WRAPPER_THREAD_PLAYBACK->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800597 return 0;
598}
599
600static inline void ctx_freeSegments(DVR_WrapperCtx_t *ctx)
601{
602 DVR_WrapperPlaybackSegmentInfo_t *pseg, *pseg_tmp;
603 list_for_each_entry_safe(pseg, pseg_tmp, &ctx->segments, head) {
604 list_del(&pseg->head);
605 free(pseg);
606 }
607}
608
609static inline void _updatePlaybackSegment(DVR_WrapperPlaybackSegmentInfo_t *pseg,
610 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
611{
612 (void)ctx;
613 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
614 pseg->seg_info = *seg_info;
615 else if (update_flags & U_PIDS) {
616 pseg->seg_info.nb_pids = seg_info->nb_pids;
617 memcpy(pseg->seg_info.pids, seg_info->pids, sizeof(pseg->seg_info.pids));
618 } else if (update_flags & U_STAT) {
619 pseg->seg_info.duration = seg_info->duration;
620 pseg->seg_info.size = seg_info->size;
621 pseg->seg_info.nb_packets = seg_info->nb_packets;
622 }
hualing chen03fd4942021-07-15 15:56:41 +0800623 //update current segment duration on timeshift mode
hualing chenb9b358a2021-08-17 15:06:36 +0800624 if (ctx->playback.param_open.is_timeshift
625 || ctx_isPlay_recording(ctx->playback.param_open.location))
hualing chen03fd4942021-07-15 15:56:41 +0800626 dvr_playback_update_duration(ctx->playback.player,pseg->seg_info.id,pseg->seg_info.duration);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800627 /*no changes
628 DVR_PlaybackSegmentFlag_t flags;
629 pseg->playback_info.segment_id = pseg->seg_info.id;
630 strncpy(pseg->playback_info.location,
631 ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
632 pseg->playback_info.pids = ctx->playback.pids_req;
633 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
634 if (ctx->record.param_open.flags | DVR_RECORD_FLAG_SCRAMBLED)
635 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
636 pseg->playback_info.flags = flags;
637 */
638}
639
640static int wrapper_updatePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
641{
642 DVR_WrapperPlaybackSegmentInfo_t *pseg;
643
644 DVR_WRAPPER_DEBUG(1, "timeshift, update playback segments(wrapper), seg:%lld t/s/p(%ld/%zu/%u)\n",
645 seg_info->id, seg_info->duration, seg_info->size, seg_info->nb_packets);
646
647 if (list_empty(&ctx->segments)) {
648 DVR_WRAPPER_DEBUG(1, "timeshift, update while no segment exists, ignore\n");
649 return DVR_SUCCESS;
650 }
651
652 /*normally, the last segment added will be updated*/
653 pseg =
654 list_first_entry(&ctx->segments, DVR_WrapperPlaybackSegmentInfo_t, head);
655 if (pseg->seg_info.id == seg_info->id) {
656 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
657 } else {
658 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
659 if (pseg->seg_info.id == seg_info->id) {
660 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
661 break;
662 }
663 }
664 }
665
666 /*need to notify the dvr_playback*/
hualing chenb9b358a2021-08-17 15:06:36 +0800667 if ((ctx->playback.param_open.is_timeshift/*should must be timeshift*/
668 || ctx_isPlay_recording(ctx->playback.param_open.location))
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800669 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END
670 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
671 if (
672 /*there's $TIMESHIFT_DATA_DURATION_TO_RESUME more of data in the current segment playing*/
673 (ctx->playback.seg_status.segment_id == seg_info->id
674 && (seg_info->duration >= ((time_t)ctx->playback.seg_status.time_cur + TIMESHIFT_DATA_DURATION_TO_RESUME)))
675 ||
676 /*or there's a new segment and has $TIMESHIFT_DATA_DURATION_TO_RESUME of data*/
677 (ctx->playback.seg_status.segment_id != seg_info->id
678 && (seg_info->duration >= TIMESHIFT_DATA_DURATION_TO_RESUME))
679 )
680 {
681 int error;
hualing chen36e0dfd2020-05-02 16:33:06 +0800682 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +0800683 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +0800684 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800685
686 error = dvr_playback_resume(ctx->playback.player);
687 DVR_WRAPPER_DEBUG(1, "timeshift, resume playback(sn:%ld) (%d) id/dur: rec(%lld/%ld) play(%lld/%u)\n",
688 ctx->sn, error,
689 seg_info->id, seg_info->duration,
690 ctx->playback.seg_status.segment_id, ctx->playback.seg_status.time_cur);
691 }
692 }
693
694 return DVR_SUCCESS;
695}
696
697static void _updateRecordSegment(DVR_WrapperRecordSegmentInfo_t *pseg,
698 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
699{
700 (void)ctx;
701 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
702 pseg->info = *seg_info;
703 else if (update_flags & U_PIDS) {
704 pseg->info.nb_pids = seg_info->nb_pids;
705 memcpy(pseg->info.pids, seg_info->pids, sizeof(pseg->info.pids));
706 } else if (update_flags & U_STAT) {
707 pseg->info.duration = seg_info->duration;
708 pseg->info.size = seg_info->size;
709 pseg->info.nb_packets = seg_info->nb_packets;
710 }
711}
712
713static int wrapper_updateRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
714{
hualing chen266b9502020-04-04 17:39:39 +0800715 DVR_WrapperRecordSegmentInfo_t *pseg = NULL;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800716
717 /*normally, the last segment added will be updated*/
hualing chen266b9502020-04-04 17:39:39 +0800718 if (!list_empty(&ctx->segments)) {
719 pseg =
720 list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
721 if (pseg->info.id == seg_info->id) {
722 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
723 } else {
724 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
725 if (pseg->info.id == seg_info->id) {
726 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
727 break;
728 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800729 }
730 }
731 }
732
733 /*timeshift, update the segment for playback*/
734 /*
735 the playback should grab the segment info other than the id,
736 and the id will be updated by each segment-add during the recording
737 */
738 /*
739 the playback paused if no data been checked from recording,
740 should resume the player later when there's more data
741 */
hualing chenb9b358a2021-08-17 15:06:36 +0800742 int sn = 0;
743 if (ctx->record.param_open.is_timeshift ||
744 (sn = ctx_isRecord_playing(ctx->record.param_open.location))) {
745 DVR_WrapperCtx_t *ctx_playback;
746 if (ctx->record.param_open.is_timeshift)
747 ctx_playback = ctx_getPlayback(sn_timeshift_playback);
748 else
749 ctx_playback = ctx_getPlayback(sn);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800750
751 if (ctx_playback) {
752 pthread_mutex_lock(&ctx_playback->lock);
753 if (ctx_valid(ctx_playback)
hualing chenb9b358a2021-08-17 15:06:36 +0800754 && (ctx_playback->sn == sn_timeshift_playback ||
755 ctx_playback->sn == sn)) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800756 wrapper_updatePlaybackSegment(ctx_playback, seg_info, update_flags);
757 }
758 pthread_mutex_unlock(&ctx_playback->lock);
759 }
760 }
761
762 return DVR_SUCCESS;
763}
764
765static int wrapper_addPlaybackSegment(DVR_WrapperCtx_t *ctx,
766 DVR_RecordSegmentInfo_t *seg_info,
767 DVR_PlaybackPids_t *p_pids,
768 DVR_PlaybackSegmentFlag_t flags)
769{
770 DVR_WrapperPlaybackSegmentInfo_t *pseg;
771 int error;
772
773 error = 0;
774 pseg = (DVR_WrapperPlaybackSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperPlaybackSegmentInfo_t));
775 if (!pseg) {
776 error = DVR_FAILURE;
777 DVR_WRAPPER_DEBUG(1, "memory fail\n");
778 return error;
779 }
780
781 /*copy the orignal segment info*/
782 pseg->seg_info = *seg_info;
783 /*generate the segment info used in playback*/
784 pseg->playback_info.segment_id = pseg->seg_info.id;
785 strncpy(pseg->playback_info.location, ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
786 pseg->playback_info.pids = *p_pids;
787 pseg->playback_info.flags = flags;
788 list_add(&pseg->head, &ctx->segments);
hualing chen03fd4942021-07-15 15:56:41 +0800789 pseg->playback_info.duration = pseg->seg_info.duration;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800790
791 error = dvr_playback_add_segment(ctx->playback.player, &pseg->playback_info);
792 if (error) {
793 DVR_WRAPPER_DEBUG(1, "fail to add segment %lld (%d)\n", pseg->playback_info.segment_id, error);
794 } else {
795 ctx->playback.status.info_full.time += pseg->seg_info.duration;
796 ctx->playback.status.info_full.size += pseg->seg_info.size;
797 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
798 }
799
800 return error;
801}
802
803static int wrapper_addRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
804{
805 DVR_WrapperRecordSegmentInfo_t *pseg;
806 int error;
hualing chenab0d1262021-09-26 15:22:50 +0800807 int sn = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800808
809 error = 0;
810 pseg = (DVR_WrapperRecordSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperRecordSegmentInfo_t));
811 if (!pseg) {
812 error = DVR_FAILURE;
813 DVR_WRAPPER_DEBUG(1, "memory fail\n");
814 }
815 pseg->info = *seg_info;
816 list_add(&pseg->head, &ctx->segments);
hualing chenab0d1262021-09-26 15:22:50 +0800817
hualing chenb9b358a2021-08-17 15:06:36 +0800818 if (ctx->record.param_open.is_timeshift ||
819 (sn = ctx_isRecord_playing(ctx->record.param_open.location))) {
820
821 DVR_WrapperCtx_t *ctx_playback;
822 if (ctx->record.param_open.is_timeshift)
823 ctx_playback = ctx_getPlayback(sn_timeshift_playback);
824 else
825 ctx_playback = ctx_getPlayback(sn);
826
827 DVR_WRAPPER_DEBUG(1, "ctx_playback ---- add segment\n");
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800828
829 if (ctx_playback) {
830 pthread_mutex_lock(&ctx_playback->lock);
831 if (ctx_valid(ctx_playback)) {
832 DVR_PlaybackSegmentFlag_t flags;
833
834 /*only if playback has started, the previous segments have been loaded*/
835 if (!list_empty(&ctx_playback->segments)) {
836 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
Gong Ke2a0ebbe2021-05-25 15:22:50 +0800837 if (ctx->record.param_open.flags & DVR_RECORD_FLAG_SCRAMBLED)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800838 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
839 wrapper_addPlaybackSegment(ctx_playback, seg_info, &ctx_playback->playback.pids_req, flags);
840 }
hualing chenb9b358a2021-08-17 15:06:36 +0800841 } else {
842 DVR_WRAPPER_DEBUG(1, "ctx_playback ---- not valid\n");
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800843 }
844 pthread_mutex_unlock(&ctx_playback->lock);
845 }
Zhiqiang Hane0a1c382021-06-08 11:28:05 +0800846 } else {
hualing chenb9b358a2021-08-17 15:06:36 +0800847 DVR_WRAPPER_DEBUG(1, "ctx_playback -sn[%d]-\n", sn);
Zhiqiang Hane0a1c382021-06-08 11:28:05 +0800848 dvr_segment_link_op(ctx->record.param_open.location, 1, &seg_info->id, LSEG_OP_ADD);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800849 }
850
851 return error;
852}
853
854static int wrapper_removePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
855{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800856 int error = -1;
857 DVR_WrapperPlaybackSegmentInfo_t *pseg = NULL, *pseg_tmp;
hualing chenb9a1a2c2021-12-31 11:27:59 +0800858 uint32_t off_set = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800859 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->id);
860
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800861 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800862 if (pseg->seg_info.id == seg_info->id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800863
864 if (ctx->current_segment_id == seg_info->id) {
865 DVR_WrapperPlaybackSegmentInfo_t *next_seg;
866
867 /*drive the player out of this will-be-deleted segment*/
868 next_seg = list_prev_entry(pseg, head);
869
870 if (ctx->playback.speed != 100.0f) {
871 error = dvr_playback_resume(ctx->playback.player);
872 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), resume for new start (%d)\n", ctx->sn, error);
873 }
hualing chenb9a1a2c2021-12-31 11:27:59 +0800874 if (ctx->playback.param_open.vendor == DVR_PLAYBACK_VENDOR_AMAZON)
875 off_set = 10 * 1000;
876 error = dvr_playback_seek(ctx->playback.player, next_seg->seg_info.id, off_set);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800877 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), seek(seg:%llu 0) from new start (%d)\n", ctx->sn, next_seg->seg_info.id, error);
878
879 if (ctx->playback.speed == 0.0f) {
880 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
881 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last paused from new start (%d)\n", ctx->sn, error);
882 } else if (ctx->playback.speed != 100.0f) {
883 DVR_PlaybackSpeed_t dvr_speed = {
884 .speed = { ctx->playback.speed },
885 .mode = ( ctx->playback.speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
886 };
887 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
888 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last speed(x%f) from new start (%d)\n", ctx->sn,ctx->playback.speed, error);
889 }
890 }
891
892 error = dvr_playback_remove_segment(ctx->playback.player, seg_info->id);
893 if (error) {
894 /*remove playack segment fail*/
895 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), failed to remove segment(%llu) (%d)\n", ctx->sn, seg_info->id, error);
896 }
897
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800898 list_del(&pseg->head);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800899
900 /*record the obsolete*/
901 ctx->playback.obsolete.time += pseg->seg_info.duration;
902 ctx->playback.obsolete.size += pseg->seg_info.size;
903 ctx->playback.obsolete.pkts += pseg->seg_info.nb_packets;
hualing chen03fd4942021-07-15 15:56:41 +0800904 dvr_playback_set_obsolete(ctx->playback.player, ctx->playback.obsolete.time);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800905 free(pseg);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800906 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800907 }
908 }
909
910 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->id, error);
911
912 return error;
913}
914
915static int wrapper_removeRecordSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *seg_info)
916{
917 int error;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800918 DVR_WrapperRecordSegmentInfo_t *pseg, *pseg_tmp;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800919
920 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->info.id);
921
922 /*if timeshifting, notify the playback first, then deal with record*/
923 if (ctx->record.param_open.is_timeshift) {
924 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
925
926 if (ctx_playback) {
927 pthread_mutex_lock(&ctx_playback->lock);
928 if (ctx_valid(ctx_playback)
929 && ctx_playback->sn == sn_timeshift_playback
930 && !list_empty(&ctx_playback->segments)) {
931 error = wrapper_removePlaybackSegment(ctx_playback, &seg_info->info);
932 }
933 pthread_mutex_unlock(&ctx_playback->lock);
934 }
935 }
936
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800937 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
938 if (pseg->info.id == seg_info->info.id) {
939 list_del(&pseg->head);
940
941 /*record the obsolete*/
942 ctx->record.obsolete.time += pseg->info.duration;
943 ctx->record.obsolete.size += pseg->info.size;
944 ctx->record.obsolete.pkts += pseg->info.nb_packets;
945
946 free(pseg);
947 break;
948 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800949 }
950
951 error = dvr_segment_delete(ctx->record.param_open.location, seg_info->info.id);
952
953 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->info.id, error);
954
955 return error;
956}
957
958int dvr_wrapper_open_record (DVR_WrapperRecord_t *rec, DVR_WrapperRecordOpenParams_t *params)
959{
960 int error;
961 DVR_WrapperCtx_t *ctx;
962 DVR_RecordOpenParams_t open_param;
963
964 DVR_RETURN_IF_FALSE(rec);
965 DVR_RETURN_IF_FALSE(params);
966
967 /*get a free ctx*/
968 ctx = ctx_getRecord(0);
969 DVR_RETURN_IF_FALSE(ctx);
970
971 pthread_mutex_lock(&ctx->lock);
972
hualing chen51652f02020-12-29 16:59:31 +0800973 DVR_WRAPPER_DEBUG(1, "open record(dmx:%d) .istf(%d)..time (%ld)ms max size(%lld)byte seg size(%lld)byte\n",
974 params->dmx_dev_id, params->is_timeshift, params->max_time, params->max_size, params->segment_size);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800975
976 ctx_reset(ctx);
977
978 ctx->record.param_open = *params;
979 ctx->record.event_fn = params->event_fn;
980 ctx->record.event_userdata = params->event_userdata;
981 ctx->record.next_segment_id = 0;
982 ctx->current_segment_id = 0;
983 INIT_LIST_HEAD(&ctx->segments);
984 ctx->sn = get_sn();
985
986 wrapper_requestThreadFor(ctx);
987
hualing chen266b9502020-04-04 17:39:39 +0800988 memset(&open_param, 0, sizeof(DVR_RecordOpenParams_t));
Yahui Hance15e9c2020-12-08 18:08:32 +0800989 open_param.fend_dev_id = params->fend_dev_id;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800990 open_param.dmx_dev_id = params->dmx_dev_id;
991 open_param.data_from_memory = 0;
992 open_param.flags = params->flags;
Yahui Han15a00f12021-11-15 19:44:39 +0800993 if (params->flush_size) {
994 open_param.notification_size = params->flush_size;
995 } else {
996 open_param.notification_size = 64*1024;
997 }
Zhiqiang Han31505452020-05-06 15:08:10 +0800998 open_param.flush_size = params->flush_size;
hualing chen03fd4942021-07-15 15:56:41 +0800999 open_param.ringbuf_size = params->ringbuf_size;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001000 open_param.event_fn = wrapper_record_event_handler;
1001 open_param.event_userdata = (void*)ctx->sn;
Yahui Han1fbf3292021-11-08 18:17:19 +08001002 if (params->keylen) {
1003 open_param.clearkey = params->clearkey;
1004 open_param.cleariv = params->cleariv;
1005 open_param.keylen = params->keylen;
1006 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001007
1008 error = dvr_record_open(&ctx->record.recorder, &open_param);
1009 if (error) {
1010 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) open fail(error:%d).\n", params->dmx_dev_id, error);
1011 ctx_reset(ctx);
1012 pthread_mutex_unlock(&ctx->lock);
1013 wrapper_releaseThreadForType(ctx->type);
1014 return DVR_FAILURE;
1015 }
1016 if (params->is_timeshift)
1017 sn_timeshift_record = ctx->sn;
1018
1019 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
1020
Yahui Han1fbf3292021-11-08 18:17:19 +08001021 if (params->crypto_fn) {
1022 error = dvr_record_set_encrypt_callback(ctx->record.recorder, params->crypto_fn, params->crypto_data);
1023 if (error) {
1024 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) set encrypt callback fail(error:%d).\n", params->dmx_dev_id, error);
1025 }
hualing chen266b9502020-04-04 17:39:39 +08001026 }
1027
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001028 pthread_mutex_unlock(&ctx->lock);
1029
1030 *rec = (DVR_WrapperRecord_t)ctx->sn;
1031 return DVR_SUCCESS;
1032}
1033
1034int dvr_wrapper_close_record (DVR_WrapperRecord_t rec)
1035{
1036 DVR_WrapperCtx_t *ctx;
1037 DVR_RecordSegmentInfo_t seg_info;
1038 int error;
1039
1040 DVR_RETURN_IF_FALSE(rec);
1041
1042 ctx = ctx_getRecord((unsigned long)rec);
1043 DVR_RETURN_IF_FALSE(ctx);
1044
1045 pthread_mutex_lock(&ctx->lock);
1046 DVR_WRAPPER_DEBUG(1, "close record(sn:%ld)\n", ctx->sn);
1047 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1048
1049 memset(&seg_info, 0, sizeof(seg_info));
1050 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
1051
1052 error = dvr_record_close(ctx->record.recorder);
1053
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001054 if (ctx->record.param_open.is_timeshift)
1055 sn_timeshift_record = 0;
1056
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001057 ctx_freeSegments(ctx);
1058
1059 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) closed = (%d).\n", ctx->sn, error);
1060 ctx_reset(ctx);
1061 pthread_mutex_unlock(&ctx->lock);
1062
1063 wrapper_releaseThreadForType(ctx->type);
1064
1065 return error;
1066}
1067
1068int dvr_wrapper_start_record (DVR_WrapperRecord_t rec, DVR_WrapperRecordStartParams_t *params)
1069{
1070 DVR_WrapperCtx_t *ctx;
1071 DVR_RecordStartParams_t *start_param;
1072 int i;
1073 int error;
1074
1075 DVR_RETURN_IF_FALSE(rec);
1076 DVR_RETURN_IF_FALSE(params);
1077
1078 ctx = ctx_getRecord((unsigned long)rec);
1079 DVR_RETURN_IF_FALSE(ctx);
1080
1081 pthread_mutex_lock(&ctx->lock);
hualing chena5f03222021-12-02 11:22:35 +08001082 DVR_WRAPPER_DEBUG(1, "start record(sn:%ld, location:%s) save(%d)...\n", ctx->sn, ctx->record.param_open.location, params->save_rec_file);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001083 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1084
1085 start_param = &ctx->record.param_start;
1086 memset(start_param, 0, sizeof(*start_param));
1087 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
1088 start_param->segment.segment_id = ctx->record.next_segment_id++;
1089 start_param->segment.nb_pids = params->pids_info.nb_pids;
1090 for (i = 0; i < params->pids_info.nb_pids; i++) {
1091 start_param->segment.pids[i] = params->pids_info.pids[i];
1092 start_param->segment.pid_action[i] = DVR_RECORD_PID_CREATE;
1093 }
hualing chena5f03222021-12-02 11:22:35 +08001094 if (params->save_rec_file == 0)//default is not save
1095 dvr_segment_del_by_location(start_param->location);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001096 {
1097 /*sync to update for further use*/
1098 DVR_RecordStartParams_t *update_param;
1099 update_param = &ctx->record.param_update;
1100 memcpy(update_param, start_param, sizeof(*update_param));
1101 for (i = 0; i < update_param->segment.nb_pids; i++)
1102 update_param->segment.pid_action[i] = DVR_RECORD_PID_KEEP;
1103 }
1104
1105 error = dvr_record_start_segment(ctx->record.recorder, start_param);
1106 {
1107 DVR_RecordSegmentInfo_t new_seg_info =
1108 { .id = start_param->segment.segment_id, };
1109 wrapper_addRecordSegment(ctx, &new_seg_info);
1110 }
1111
1112 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) started = (%d)\n", ctx->sn, error);
1113
1114 pthread_mutex_unlock(&ctx->lock);
1115
1116 return error;
1117}
1118
1119int dvr_wrapper_stop_record (DVR_WrapperRecord_t rec)
1120{
1121 DVR_WrapperCtx_t *ctx;
1122 DVR_RecordSegmentInfo_t seg_info;
1123 int error;
1124
1125 DVR_RETURN_IF_FALSE(rec);
1126
1127 ctx = ctx_getRecord((unsigned long)rec);
1128 DVR_RETURN_IF_FALSE(ctx);
1129
1130 pthread_mutex_lock(&ctx->lock);
1131 DVR_WRAPPER_DEBUG(1, "stop record(sn:%ld) ...\n", ctx->sn);
1132 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1133
1134 memset(&seg_info, 0, sizeof(seg_info));
1135 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
1136 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
1137
1138 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) stopped = (%d)\n", ctx->sn, error);
1139 pthread_mutex_unlock(&ctx->lock);
1140
1141 return error;
1142}
1143
hualing chen03fd4942021-07-15 15:56:41 +08001144int dvr_wrapper_pause_record (DVR_WrapperRecord_t rec)
1145{
1146 DVR_WrapperCtx_t *ctx;
1147 int error;
1148
1149 DVR_RETURN_IF_FALSE(rec);
1150
1151 ctx = ctx_getRecord((unsigned long)rec);
1152 DVR_RETURN_IF_FALSE(ctx);
1153
1154 pthread_mutex_lock(&ctx->lock);
1155 DVR_WRAPPER_DEBUG(1, "pause record(sn:%ld) ...\n", ctx->sn);
1156 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1157
1158 error = dvr_record_pause(ctx->record.recorder);
1159
1160 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) pauseed = (%d)\n", ctx->sn, error);
1161 pthread_mutex_unlock(&ctx->lock);
1162
1163 return error;
1164}
1165
1166int dvr_wrapper_resume_record (DVR_WrapperRecord_t rec)
1167{
1168 DVR_WrapperCtx_t *ctx;
1169 int error;
1170
1171 DVR_RETURN_IF_FALSE(rec);
1172
1173 ctx = ctx_getRecord((unsigned long)rec);
1174 DVR_RETURN_IF_FALSE(ctx);
1175
1176 pthread_mutex_lock(&ctx->lock);
1177 DVR_WRAPPER_DEBUG(1, "resume record(sn:%ld) ...\n", ctx->sn);
1178 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1179
1180 error = dvr_record_resume(ctx->record.recorder);
1181
1182 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) resumed = (%d)\n", ctx->sn, error);
1183 pthread_mutex_unlock(&ctx->lock);
1184
1185 return error;
1186}
1187
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001188int dvr_wrapper_update_record_pids (DVR_WrapperRecord_t rec, DVR_WrapperUpdatePidsParams_t *params)
1189{
1190 DVR_WrapperCtx_t *ctx;
1191 DVR_RecordStartParams_t *start_param;
1192 DVR_RecordSegmentInfo_t seg_info;;
1193 int i;
1194 int error;
1195
1196 DVR_RETURN_IF_FALSE(rec);
1197 DVR_RETURN_IF_FALSE(params);
1198
1199 ctx = ctx_getRecord((unsigned long)rec);
1200 DVR_RETURN_IF_FALSE(ctx);
1201
1202 pthread_mutex_lock(&ctx->lock);
1203 DVR_WRAPPER_DEBUG(1, "update record(sn:%ld)\n", ctx->sn);
1204 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1205
1206 start_param = &ctx->record.param_update;
1207 memset(start_param, 0, sizeof(*start_param));
1208 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
1209 start_param->segment.segment_id = ctx->record.next_segment_id++;
1210 start_param->segment.nb_pids = params->nb_pids;
1211 for (i = 0; i < params->nb_pids; i++) {
1212 start_param->segment.pids[i] = params->pids[i];
1213 start_param->segment.pid_action[i] = params->pid_action[i];
1214 }
1215 error = dvr_record_next_segment(ctx->record.recorder, start_param, &seg_info);
1216 {
1217 DVR_RecordSegmentInfo_t new_seg_info =
1218 { .id = start_param->segment.segment_id, };
1219 wrapper_updateRecordSegment(ctx, &seg_info, U_PIDS);
1220 wrapper_addRecordSegment(ctx, &new_seg_info);
1221 }
1222
1223 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) updated = (%d)\n", ctx->sn, error);
1224 pthread_mutex_unlock(&ctx->lock);
1225
1226 return error;
1227}
1228
1229int dvr_wrapper_get_record_status(DVR_WrapperRecord_t rec, DVR_WrapperRecordStatus_t *status)
1230{
1231 DVR_WrapperCtx_t *ctx;
1232 DVR_WrapperRecordStatus_t s;
1233 int error;
1234
1235 DVR_RETURN_IF_FALSE(rec);
1236 DVR_RETURN_IF_FALSE(status);
1237
1238 ctx = ctx_getRecord((unsigned long)rec);
1239 DVR_RETURN_IF_FALSE(ctx);
1240
1241 pthread_mutex_lock(&ctx->lock);
1242
1243 DVR_WRAPPER_DEBUG(1, "get record(sn:%ld) status ...\n", ctx->sn);
1244 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1245
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001246 error = process_generateRecordStatus(ctx, &s);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001247
1248 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) state/time/size/pkts(%d/%ld/%lld/%u) (%d)\n",
1249 ctx->sn,
1250 s.state,
1251 s.info.time,
1252 s.info.size,
1253 s.info.pkts,
1254 error);
1255
1256 *status = s;
1257
1258 pthread_mutex_unlock(&ctx->lock);
1259
1260 return error;
1261}
1262
hualing chen4fe3bee2020-10-23 13:58:52 +08001263int dvr_wrapper_record_is_secure_mode(DVR_WrapperRecord_t rec)
1264{
1265 DVR_WrapperCtx_t *ctx;
1266 int error;
1267
1268 DVR_RETURN_IF_FALSE(rec);
1269
1270 ctx = ctx_getRecord((unsigned long)rec);
1271 DVR_RETURN_IF_FALSE(ctx);
1272
1273 pthread_mutex_lock(&ctx->lock);
1274 error = dvr_record_is_secure_mode(ctx->record.recorder);
1275 pthread_mutex_unlock(&ctx->lock);
1276 return error;
1277}
1278
hualing chen266b9502020-04-04 17:39:39 +08001279int dvr_wrapper_set_record_secure_buffer (DVR_WrapperRecord_t rec, uint8_t *p_secure_buf, uint32_t len)
1280{
1281 DVR_WrapperCtx_t *ctx;
1282 int error;
1283
1284 DVR_RETURN_IF_FALSE(rec);
1285 DVR_RETURN_IF_FALSE(p_secure_buf);
1286
1287 ctx = ctx_getRecord((unsigned long)rec);
1288 DVR_RETURN_IF_FALSE(ctx);
1289
1290 pthread_mutex_lock(&ctx->lock);
1291 error = dvr_record_set_secure_buffer(ctx->record.recorder, p_secure_buf, len);
1292 pthread_mutex_unlock(&ctx->lock);
1293 return error;
1294}
1295
1296int dvr_wrapper_set_record_decrypt_callback (DVR_WrapperRecord_t rec, DVR_CryptoFunction_t func, void *userdata)
1297{
1298 DVR_WrapperCtx_t *ctx;
1299 int error;
1300
1301 DVR_RETURN_IF_FALSE(rec);
1302 DVR_RETURN_IF_FALSE(func);
1303
1304 ctx = ctx_getRecord((unsigned long)rec);
1305 DVR_RETURN_IF_FALSE(ctx);
1306
1307 pthread_mutex_lock(&ctx->lock);
1308 error = dvr_record_set_encrypt_callback(ctx->record.recorder, func, userdata);
1309 pthread_mutex_unlock(&ctx->lock);
1310 return error;
1311}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001312
1313
1314int dvr_wrapper_open_playback (DVR_WrapperPlayback_t *playback, DVR_WrapperPlaybackOpenParams_t *params)
1315{
1316 DVR_WrapperCtx_t *ctx;
1317 DVR_PlaybackOpenParams_t open_param;
1318 int error;
1319
1320 DVR_RETURN_IF_FALSE(playback);
1321 DVR_RETURN_IF_FALSE(params);
1322 DVR_RETURN_IF_FALSE(params->playback_handle);
1323
1324 /*get a free ctx*/
1325 ctx = ctx_getPlayback(0);
1326 DVR_RETURN_IF_FALSE(ctx);
1327
1328 pthread_mutex_lock(&ctx->lock);
1329
hualing chena5f03222021-12-02 11:22:35 +08001330 DVR_WRAPPER_DEBUG(1, "open playback(dmx:%d) ..vendor[%d]params->block_size[%d].\n", params->dmx_dev_id, params->vendor, params->block_size);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001331
1332 ctx_reset(ctx);
1333
1334 ctx->playback.param_open = *params;
1335 ctx->playback.event_fn = params->event_fn;
1336 ctx->playback.event_userdata = params->event_userdata;
1337 ctx->current_segment_id = 0;
1338 INIT_LIST_HEAD(&ctx->segments);
1339 ctx->sn = get_sn();
1340
1341 wrapper_requestThreadFor(ctx);
1342
hualing chen266b9502020-04-04 17:39:39 +08001343 memset(&open_param, 0, sizeof(DVR_PlaybackOpenParams_t));
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001344 open_param.dmx_dev_id = params->dmx_dev_id;
1345 open_param.block_size = params->block_size;
1346 open_param.is_timeshift = params->is_timeshift;
1347 //open_param.notification_size = 10*1024; //not supported
1348 open_param.event_fn = wrapper_playback_event_handler;
1349 open_param.event_userdata = (void*)ctx->sn;
1350 /*open_param.has_pids = 0;*/
hualing chene3797f02021-01-13 14:53:28 +08001351 open_param.is_notify_time = params->is_notify_time;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001352 open_param.player_handle = (am_tsplayer_handle)params->playback_handle;
hualing chen90b3ae62021-03-30 10:49:28 +08001353 open_param.vendor = params->vendor;
1354
Yahui Han1fbf3292021-11-08 18:17:19 +08001355 if (params->keylen) {
1356 open_param.clearkey = params->clearkey;
1357 open_param.cleariv = params->cleariv;
1358 open_param.keylen = params->keylen;
1359 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001360
1361 error = dvr_playback_open(&ctx->playback.player, &open_param);
1362 if (error) {
1363 DVR_WRAPPER_DEBUG(1, "playback(dmx:%d) openned fail(error:%d).\n", params->dmx_dev_id, error);
1364 ctx_reset(ctx);
1365 pthread_mutex_unlock(&ctx->lock);
1366 wrapper_releaseThreadForType(ctx->type);
1367 return DVR_FAILURE;
1368 }
1369 if (params->is_timeshift)
1370 sn_timeshift_playback = ctx->sn;
1371
hualing chen266b9502020-04-04 17:39:39 +08001372 DVR_WRAPPER_DEBUG(1, "hanyh: playback(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
1373 error = dvr_playback_set_decrypt_callback(ctx->playback.player, params->crypto_fn, params->crypto_data);
1374 if (error) {
1375 DVR_WRAPPER_DEBUG(1, "playback set deccrypt callback fail(error:%d).\n", error);
1376 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001377 pthread_mutex_unlock(&ctx->lock);
1378
1379 *playback = (DVR_WrapperPlayback_t)ctx->sn;
1380 return DVR_SUCCESS;
1381}
1382
1383int dvr_wrapper_close_playback (DVR_WrapperPlayback_t playback)
1384{
1385 DVR_WrapperCtx_t *ctx;
1386 int error;
1387
1388 DVR_RETURN_IF_FALSE(playback);
1389
1390 ctx = ctx_getPlayback((unsigned long)playback);
1391 DVR_RETURN_IF_FALSE(ctx);
1392
1393 pthread_mutex_lock(&ctx->lock);
1394 DVR_WRAPPER_DEBUG(1, "close playback(sn:%ld)\n", ctx->sn);
1395 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1396
1397 if (ctx->playback.param_open.is_timeshift)
1398 sn_timeshift_playback = 0;
1399
1400 /*try stop first*/
1401 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1402
1403 {
1404 /*remove all segments*/
1405 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1406
1407 list_for_each_entry(pseg, &ctx->segments, head) {
1408 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1409 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1410 ctx->sn, pseg->playback_info.segment_id, error);
1411 }
1412 ctx_freeSegments(ctx);
1413 }
1414
1415 error = dvr_playback_close(ctx->playback.player);
1416
1417 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) closed.\n", ctx->sn);
1418 ctx_reset(ctx);
1419 pthread_mutex_unlock(&ctx->lock);
1420
1421 wrapper_releaseThreadForType(ctx->type);
1422
1423 return error;
1424}
1425
1426int dvr_wrapper_start_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackFlag_t flags, DVR_PlaybackPids_t *p_pids)
1427{
1428 DVR_WrapperCtx_t *ctx;
Wentao MA9aa0aa02021-12-23 18:30:17 +08001429 int error=0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001430 uint64_t *p_segment_ids;
1431 uint32_t segment_nb;
1432 uint32_t i;
1433 DVR_RecordSegmentInfo_t seg_info_1st;
Wentao MA9aa0aa02021-12-23 18:30:17 +08001434 int got_1st_seg=0;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001435 DVR_WrapperCtx_t *ctx_record;/*for timeshift*/
hualing chenc110f952021-01-18 11:25:37 +08001436 DVR_Bool_t is_timeshift = DVR_FALSE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001437
1438 DVR_RETURN_IF_FALSE(playback);
1439 DVR_RETURN_IF_FALSE(p_pids);
1440
hualing chenc110f952021-01-18 11:25:37 +08001441 ctx_record = NULL;
1442
1443 /*lock the recorder to avoid changing the recording segments*/
1444 ctx_record = ctx_getRecord(sn_timeshift_record);
1445
1446 if (ctx_record) {
1447 pthread_mutex_lock(&ctx_record->lock);
1448 if (!ctx_valid(ctx_record)
1449 || ctx_record->sn != sn_timeshift_record) {
1450 DVR_WRAPPER_DEBUG(1, "timeshift, record is not for timeshifting, FATAL error found\n");
1451 pthread_mutex_unlock(&ctx_record->lock);
1452 is_timeshift = DVR_FALSE;
1453 } else {
1454 is_timeshift = DVR_TRUE;
1455 }
1456 }
1457
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001458 ctx = ctx_getPlayback((unsigned long)playback);
1459 DVR_RETURN_IF_FALSE(ctx);
1460
1461 pthread_mutex_lock(&ctx->lock);
1462
1463 DVR_WRAPPER_DEBUG(1, "start playback(sn:%ld) (%s)\n\t flags(0x%x) v/a/ad/sub/pcr(%d:%d %d:%d %d:%d %d:%d %d)\n",
1464 ctx->sn,
1465 ctx->playback.param_open.location,
1466 flags,
1467 p_pids->video.pid, p_pids->video.format,
1468 p_pids->audio.pid, p_pids->audio.format,
1469 p_pids->ad.pid, p_pids->ad.format,
1470 p_pids->subtitle.pid, p_pids->subtitle.format,
1471 p_pids->pcr.pid);
1472
1473 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1474
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001475 if (ctx->playback.param_open.is_timeshift) {
1476 /*lock the recorder to avoid changing the recording segments*/
hualing chenc110f952021-01-18 11:25:37 +08001477 if (is_timeshift == DVR_FALSE) {
1478 DVR_WRAPPER_DEBUG(1, "timeshift, record is not for timeshifting, FATAL error return\n");
1479 pthread_mutex_unlock(&ctx->lock);
1480 return DVR_FAILURE;
1481 } else {
1482 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) record(sn:%ld) locked ok due to timeshift\n",
1483 ctx->sn, ctx_record->sn);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001484 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001485 }
1486
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001487 /*obtain all segments in a list*/
1488 segment_nb = 0;
1489 p_segment_ids = NULL;
1490 error = dvr_segment_get_list(ctx->playback.param_open.location, &segment_nb, &p_segment_ids);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001491 if (!error) {
1492 got_1st_seg = 0;
hualing chenb9a02922021-12-14 11:29:47 +08001493 struct list_head info_list; /**< segment list head*/
1494 INIT_LIST_HEAD(&info_list);
1495
hualing chenb9b358a2021-08-17 15:06:36 +08001496 DVR_WRAPPER_DEBUG(1, "get list segment_nb::%d",segment_nb);
hualing chenb9a02922021-12-14 11:29:47 +08001497 //we need free info list buf when we used end.
1498 error = dvr_segment_get_allInfo(ctx->playback.param_open.location, &info_list);
hualing chen926a8ec2021-12-20 20:38:24 +08001499 if (error == DVR_FAILURE) {
hualing chenb9a02922021-12-14 11:29:47 +08001500 error = DVR_FAILURE;
1501 DVR_WRAPPER_DEBUG(1, "fail to get all seg info (location:%s, seg:%llu), (error:%d)\n",
1502 ctx->playback.param_open.location, p_segment_ids[i], error);
1503 for (i = 0; i < segment_nb; i++) {
1504 DVR_RecordSegmentInfo_t seg_info;
1505 DVR_PlaybackSegmentFlag_t flags;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001506
hualing chenb9a02922021-12-14 11:29:47 +08001507 error = dvr_segment_get_info(ctx->playback.param_open.location, p_segment_ids[i], &seg_info);
1508 if (error) {
1509 error = DVR_FAILURE;
1510 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
1511 ctx->playback.param_open.location, p_segment_ids[i], error);
1512 break;
1513 }
1514 //add check if has audio or video pid. if not exist. not add segment to playback
1515 int ii = 0;
1516 int has_av = 0;
1517 for (ii = 0; ii < seg_info.nb_pids; ii++) {
1518 int type = (seg_info.pids[ii].type >> 24) & 0x0f;
1519 if (type == DVR_STREAM_TYPE_VIDEO ||
1520 type == DVR_STREAM_TYPE_AUDIO ||
1521 type == DVR_STREAM_TYPE_AD) {
1522 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1523 DVR_WRAPPER_DEBUG(1, "success to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info.pids[ii].type >> 24)&0x0f,seg_info.pids[ii].pid,
1524 DVR_STREAM_TYPE_VIDEO,
1525 DVR_STREAM_TYPE_AUDIO,
1526 DVR_STREAM_TYPE_AD);
1527 has_av = 1;
1528 //break;
1529 } else {
1530 DVR_WRAPPER_DEBUG(1, "error to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info.pids[ii].type >> 24)&0x0f,seg_info.pids[ii].pid,
1531 DVR_STREAM_TYPE_VIDEO,
1532 DVR_STREAM_TYPE_AUDIO,
1533 DVR_STREAM_TYPE_AD);
1534 }
1535 }
1536 if (has_av == 0) {
1537 DVR_WRAPPER_DEBUG(1, "fail to get seg av info \n");
1538 continue;
1539 } else {
1540 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1541 }
1542 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1543 error = wrapper_addPlaybackSegment(ctx, &seg_info, p_pids, flags);
1544 if (error)
1545 break;
1546 /*copy the 1st segment*/
1547 if (got_1st_seg == 0) {
1548 seg_info_1st = seg_info;
1549 got_1st_seg = 1;
1550 }
1551 }
1552 } else {
1553 for (i = 0; i < segment_nb; i++) {
1554 DVR_RecordSegmentInfo_t *seg_info;
1555 DVR_PlaybackSegmentFlag_t flags;
1556 int found = 0;
1557 list_for_each_entry(seg_info, &info_list, head)
1558 {
hualing chen8aed9582021-12-24 17:59:56 +08001559 if (seg_info->id == p_segment_ids[i]) {
hualing chenb9a02922021-12-14 11:29:47 +08001560 found = 1;
1561 DVR_WRAPPER_DEBUG(1, "get segment info::%d", i);
1562 break;
1563 }
1564 }
1565 if (!found) {
hualing chen8aed9582021-12-24 17:59:56 +08001566 //last info is not found if when recording occured power off.
1567 if (p_segment_ids[i] == segment_nb - 1) {
1568 DVR_RecordSegmentInfo_t seg_info;
1569 DVR_PlaybackSegmentFlag_t flags;
1570
1571 error = dvr_segment_get_info(ctx->playback.param_open.location, p_segment_ids[i], &seg_info);
1572 if (error) {
1573 error = DVR_FAILURE;
1574 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
1575 ctx->playback.param_open.location, p_segment_ids[i], error);
1576 break;
1577 }
1578 //
1579 //add check if has audio or video pid. if not exist. not add segment to playback
1580 int ii = 0;
1581 int has_av = 0;
1582 for (ii = 0; ii < seg_info.nb_pids; ii++) {
1583 int type = (seg_info.pids[ii].type >> 24) & 0x0f;
1584 if (type == DVR_STREAM_TYPE_VIDEO ||
1585 type == DVR_STREAM_TYPE_AUDIO ||
1586 type == DVR_STREAM_TYPE_AD) {
1587 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1588 DVR_WRAPPER_DEBUG(1, "success to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info.pids[ii].type >> 24)&0x0f,seg_info.pids[ii].pid,
1589 DVR_STREAM_TYPE_VIDEO,
1590 DVR_STREAM_TYPE_AUDIO,
1591 DVR_STREAM_TYPE_AD);
1592 has_av = 1;
1593 //break;
1594 } else {
1595 DVR_WRAPPER_DEBUG(1, "error to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info.pids[ii].type >> 24)&0x0f,seg_info.pids[ii].pid,
1596 DVR_STREAM_TYPE_VIDEO,
1597 DVR_STREAM_TYPE_AUDIO,
1598 DVR_STREAM_TYPE_AD);
1599 }
1600 }
1601 if (has_av == 0) {
1602 DVR_WRAPPER_DEBUG(1, "fail to get seg av info \n");
1603 continue;
1604 } else {
1605 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1606 }
1607 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1608 error = wrapper_addPlaybackSegment(ctx, &seg_info, p_pids, flags);
1609 if (error)
1610 break;
1611 }
hualing chenb9a02922021-12-14 11:29:47 +08001612 continue;
1613 }
1614
1615 //add check if has audio or video pid. if not exist. not add segment to playback
1616 int ii = 0;
1617 int has_av = 0;
1618 for (ii = 0; ii < seg_info->nb_pids; ii++) {
1619 int type = (seg_info->pids[ii].type >> 24) & 0x0f;
1620 if (type == DVR_STREAM_TYPE_VIDEO ||
1621 type == DVR_STREAM_TYPE_AUDIO ||
1622 type == DVR_STREAM_TYPE_AD) {
1623 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1624 DVR_WRAPPER_DEBUG(1, "success to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info->pids[ii].type >> 24)&0x0f,seg_info->pids[ii].pid,
1625 DVR_STREAM_TYPE_VIDEO,
1626 DVR_STREAM_TYPE_AUDIO,
1627 DVR_STREAM_TYPE_AD);
1628 has_av = 1;
1629 //break;
1630 } else {
1631 DVR_WRAPPER_DEBUG(1, "error to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info->pids[ii].type >> 24)&0x0f,seg_info->pids[ii].pid,
1632 DVR_STREAM_TYPE_VIDEO,
1633 DVR_STREAM_TYPE_AUDIO,
1634 DVR_STREAM_TYPE_AD);
1635 }
1636 }
1637 if (has_av == 0) {
1638 DVR_WRAPPER_DEBUG(1, "fail to get seg av info \n");
1639 continue;
1640 } else {
1641 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1642 }
1643 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1644 error = wrapper_addPlaybackSegment(ctx, seg_info, p_pids, flags);
1645 if (error)
1646 break;
1647
1648 /*copy the 1st segment*/
1649 if (got_1st_seg == 0) {
1650 seg_info_1st = *seg_info;
1651 got_1st_seg = 1;
1652 }
hualing chen92f3a142020-07-08 20:59:33 +08001653 }
hualing chenb9a02922021-12-14 11:29:47 +08001654 //free list
1655 DVR_RecordSegmentInfo_t *segment = NULL;
1656 DVR_RecordSegmentInfo_t *segment_tmp = NULL;
1657 list_for_each_entry_safe(segment, segment_tmp, &info_list, head)
1658 {
1659 if (segment) {
1660 list_del(&segment->head);
1661 free(segment);
1662 }
1663 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001664 }
hualing chenb9a02922021-12-14 11:29:47 +08001665
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001666 free(p_segment_ids);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001667
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001668 /* return if no segment or fail to add */
1669 if (!error && got_1st_seg) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001670
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001671 /*copy the obsolete infomation, must for timeshifting*/
1672 if (ctx->playback.param_open.is_timeshift && ctx_record) {
1673 ctx->playback.obsolete = ctx_record->record.obsolete;
1674 }
1675
1676 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) (%d) segments added\n", ctx->sn, i);
1677
1678 ctx->playback.reach_end = DVR_FALSE;
1679 if ((flags&DVR_PLAYBACK_STARTED_PAUSEDLIVE) == DVR_PLAYBACK_STARTED_PAUSEDLIVE)
1680 ctx->playback.speed = 0.0f;
1681 else
1682 ctx->playback.speed = 100.0f;
1683
1684 ctx->playback.pids_req = *p_pids;
hualing chen03fd4942021-07-15 15:56:41 +08001685 //calualte segment id and pos
1686 if (dvr_playback_check_limit(ctx->playback.player)) {
1687 pthread_mutex_unlock(&ctx->lock);
1688 dvr_wrapper_seek_playback(playback, 0);
1689 pthread_mutex_lock(&ctx->lock);
1690 error = dvr_playback_start(ctx->playback.player, flags);
1691 } else {
1692 error = dvr_playback_seek(ctx->playback.player, seg_info_1st.id, 0);
1693 error = dvr_playback_start(ctx->playback.player, flags);
1694 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seek(seg:%llu 0) for start (%d)\n",
1695 ctx->sn, seg_info_1st.id, error);
1696 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001697 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) started (%d)\n", ctx->sn, error);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001698 }
1699 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001700
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001701 if (ctx->playback.param_open.is_timeshift) {
1702 /*unlock the recorder locked above*/
1703 if (ctx_record && ctx_valid(ctx_record)) {
1704 pthread_mutex_unlock(&ctx_record->lock);
1705 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld), record(sn:%ld) unlocked ok due to timeshift\n",
1706 ctx->sn, ctx_record->sn);
1707 }
1708 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001709 pthread_mutex_unlock(&ctx->lock);
1710
1711 return error;
1712}
1713
1714int dvr_wrapper_stop_playback (DVR_WrapperPlayback_t playback)
1715{
1716 DVR_WrapperCtx_t *ctx;
1717 int error;
1718
1719 DVR_RETURN_IF_FALSE(playback);
1720
1721 ctx = ctx_getPlayback((unsigned long)playback);
1722 DVR_RETURN_IF_FALSE(ctx);
1723
1724 pthread_mutex_lock(&ctx->lock);
1725 DVR_WRAPPER_DEBUG(1, "stop playback(sn:%ld) ...\n", ctx->sn);
1726 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1727
1728 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1729
1730 {
1731 /*remove all segments*/
1732 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1733
1734 list_for_each_entry(pseg, &ctx->segments, head) {
1735 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1736 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1737 ctx->sn, pseg->playback_info.segment_id, error);
1738 }
1739 ctx_freeSegments(ctx);
1740 }
1741
1742 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) stopped (%d)\n", ctx->sn, error);
1743 pthread_mutex_unlock(&ctx->lock);
1744
1745 return error;
1746}
1747
1748int dvr_wrapper_pause_playback (DVR_WrapperPlayback_t playback)
1749{
1750 DVR_WrapperCtx_t *ctx;
1751 int error;
1752
1753 DVR_RETURN_IF_FALSE(playback);
1754
1755 ctx = ctx_getPlayback((unsigned long)playback);
1756 DVR_RETURN_IF_FALSE(ctx);
1757
1758 pthread_mutex_lock(&ctx->lock);
1759 DVR_WRAPPER_DEBUG(1, "pause playback(sn:%ld) ...\n", ctx->sn);
1760 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
hualing chen36e0dfd2020-05-02 16:33:06 +08001761 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +08001762 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +08001763 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001764
1765 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
1766
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001767 ctx->playback.speed = 0.0f;
1768
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001769 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) paused (%d)\n", ctx->sn, error);
1770 pthread_mutex_unlock(&ctx->lock);
1771
1772 return error;
1773}
1774
1775int dvr_wrapper_resume_playback (DVR_WrapperPlayback_t playback)
1776{
1777 DVR_WrapperCtx_t *ctx;
1778 int error;
1779
1780 DVR_RETURN_IF_FALSE(playback);
1781
1782 ctx = ctx_getPlayback((unsigned long)playback);
1783 DVR_RETURN_IF_FALSE(ctx);
hualing chen03fd4942021-07-15 15:56:41 +08001784 //if set limit.we need check if seek to valid data when resume
1785 uint32_t time_offset = ctx->playback.status.info_cur.time + ctx->playback.status.info_obsolete.time;
1786 if (dvr_playback_check_limit(ctx->playback.player)) {
1787 int expired = dvr_playback_calculate_expiredlen(ctx->playback.player);
1788 if (expired > time_offset) {
1789 DVR_WRAPPER_DEBUG(1, "seek before resume reset offset playback(sn:%ld) (off:%d expired:%d)\n",
1790 ctx->sn, time_offset, expired);
1791 time_offset = expired;
1792 dvr_wrapper_seek_playback(playback, time_offset);
1793 }
1794 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001795 pthread_mutex_lock(&ctx->lock);
1796 DVR_WRAPPER_DEBUG(1, "resume playback(sn:%ld) ...\n", ctx->sn);
1797 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1798
1799 error = dvr_playback_resume(ctx->playback.player);
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001800 ctx->playback.speed = 100.0f;
1801
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001802 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) resumed (%d)\n", ctx->sn, error);
1803 pthread_mutex_unlock(&ctx->lock);
1804
1805 return error;
1806}
1807
1808int dvr_wrapper_set_playback_speed (DVR_WrapperPlayback_t playback, float speed)
1809{
1810 DVR_WrapperCtx_t *ctx;
1811 int error;
1812 DVR_PlaybackSpeed_t dvr_speed = {
1813 .speed = { speed },
1814 .mode = (speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
1815 };
1816
1817 DVR_RETURN_IF_FALSE(playback);
1818
1819 ctx = ctx_getPlayback((unsigned long)playback);
1820 DVR_RETURN_IF_FALSE(ctx);
1821
1822 pthread_mutex_lock(&ctx->lock);
hualing chenc70a8df2020-05-12 19:23:11 +08001823 DVR_WRAPPER_DEBUG(1, "speed playback(sn:%ld) (x%f) .(x%f)..\n", ctx->sn, speed, ctx->playback.speed);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001824 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1825
1826 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
1827
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001828 if (ctx->playback.speed != 0.0f && ctx->playback.speed != 100.0f
1829 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_BEGIN
1830 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
1831 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, paused, do resume first\n", ctx->playback.speed, speed);
1832 error = dvr_playback_resume(ctx->playback.player);
1833 } else if (ctx->playback.speed == 0.0f
1834 && speed != 0.0f
1835 && speed != 100.0f) {
1836 /*libdvr do not support pause with speed=0, will not be here*/
1837 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, do resume first\n", ctx->playback.speed, speed);
1838 error = dvr_playback_resume(ctx->playback.player);
1839 }
1840
1841 ctx->playback.speed = speed;
1842
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001843 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) speeded(x%f) (%d)\n",
1844 ctx->sn, speed, error);
1845 pthread_mutex_unlock(&ctx->lock);
1846
1847 return error;
1848}
1849
hualing chen03fd4942021-07-15 15:56:41 +08001850int dvr_wrapper_setlimit_playback (DVR_WrapperPlayback_t playback, uint64_t time, int32_t limit)
1851{
1852 DVR_WrapperCtx_t *ctx;
1853 int error;
1854
1855 DVR_RETURN_IF_FALSE(playback);
1856
1857 ctx = ctx_getPlayback((unsigned long)playback);
1858 DVR_RETURN_IF_FALSE(ctx);
1859
1860 pthread_mutex_lock(&ctx->lock);
1861
1862 DVR_WRAPPER_DEBUG(1, "setlimit playback(sn:%ld) (time:%lld limit:%d) ...\n", ctx->sn, time, limit);
1863 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1864
1865 error = dvr_playback_setlimit(ctx->playback.player, time, limit);
1866 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) setlimit(time:%lld limit:%d) ...\n", ctx->sn, time, limit);
1867
1868 pthread_mutex_unlock(&ctx->lock);
1869
1870 return error;
1871}
1872
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001873int dvr_wrapper_seek_playback (DVR_WrapperPlayback_t playback, uint32_t time_offset)
1874{
1875 DVR_WrapperCtx_t *ctx;
1876 int error;
1877 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1878 uint64_t segment_id;
1879 uint32_t off;
1880 uint64_t last_segment_id;
1881 uint32_t pre_off;
1882
1883 DVR_RETURN_IF_FALSE(playback);
1884
1885 ctx = ctx_getPlayback((unsigned long)playback);
1886 DVR_RETURN_IF_FALSE(ctx);
1887
1888 pthread_mutex_lock(&ctx->lock);
1889
1890 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (off:%d) ...\n", ctx->sn, time_offset);
1891 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1892
1893 off = 0;
1894 segment_id = 0;
1895 pre_off = 0;
1896 last_segment_id = 0;
1897
hualing chen03fd4942021-07-15 15:56:41 +08001898 //if set limit info we need check ts data is
1899 //expired when seek
1900 if (dvr_playback_check_limit(ctx->playback.player)) {
1901 int expired = dvr_playback_calculate_expiredlen(ctx->playback.player);
1902 if (expired > time_offset) {
1903 DVR_WRAPPER_DEBUG(1, "seek reset offset playback(sn:%ld) (off:%d expired:%d)\n",
1904 ctx->sn, time_offset, expired);
1905 time_offset = expired;
1906 }
1907 }
1908
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001909 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1910 segment_id = pseg->seg_info.id;
1911
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001912 if ((ctx->playback.obsolete.time + pre_off + pseg->seg_info.duration) > time_offset)
1913 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001914
1915 last_segment_id = pseg->seg_info.id;
1916 pre_off += pseg->seg_info.duration;
1917 }
1918
1919 if (last_segment_id == segment_id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001920 /*1.only one seg with id:0, 2.offset exceeds the total duration*/
1921 off = time_offset;
1922 } else if (ctx->playback.obsolete.time >= time_offset) {
1923 off = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001924 } else {
hualing chenda76fc52020-05-28 14:56:42 +08001925 off = time_offset - pre_off - ctx->playback.obsolete.time;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001926 }
1927
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001928 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (seg:%lld, off:%d)\n",
1929 ctx->sn, segment_id, off);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001930 error = dvr_playback_seek(ctx->playback.player, segment_id, off);
1931 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seeked(off:%d) (%d)\n", ctx->sn, time_offset, error);
1932
1933 pthread_mutex_unlock(&ctx->lock);
1934
1935 return error;
1936}
1937
1938int dvr_wrapper_update_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackPids_t *p_pids)
1939{
1940 DVR_WrapperCtx_t *ctx;
1941 int error;
1942 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1943
1944 DVR_RETURN_IF_FALSE(playback);
1945 DVR_RETURN_IF_FALSE(p_pids);
1946
1947 ctx = ctx_getPlayback((unsigned long)playback);
1948 DVR_RETURN_IF_FALSE(ctx);
1949
1950 pthread_mutex_lock(&ctx->lock);
1951
1952 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) ...\n",
1953 ctx->sn,
1954 p_pids->video.pid, p_pids->video.format,
1955 p_pids->audio.pid, p_pids->audio.format);
1956 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1957
1958 ctx->playback.pids_req = *p_pids;
1959
1960 error = 0;
1961 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1962 /*should update the whole list of segments*/
1963 /*if (pseg->seg_info.id == ctx->current_segment_id)*/ {
1964 /*list_for_each_entry_from(pseg, &ctx->segments, head)*/ {
1965 /*check udpate for pids*/
1966 if (memcmp(&pseg->playback_info.pids, p_pids, sizeof(*p_pids)) != 0) {
1967 pseg->playback_info.pids = *p_pids;
1968 error = dvr_playback_update_segment_pids(ctx->playback.player, pseg->seg_info.id, p_pids);
1969 if (error) {
1970 DVR_WRAPPER_DEBUG(1, "failed to playback(sn:%ld) update segment(id:%lld) pids (%d)\n",
1971 ctx->sn, pseg->seg_info.id, error);
1972 /*do not break, let list updated*/
1973 }
1974 }
1975 }
1976 /*break;*/
1977 }
1978 }
1979
1980 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) (%d)\n",
1981 ctx->sn,
1982 p_pids->video.pid, p_pids->video.format,
1983 p_pids->audio.pid, p_pids->audio.format,
1984 error);
1985
1986 pthread_mutex_unlock(&ctx->lock);
1987
1988 return error;
1989}
1990
hualing chena5f03222021-12-02 11:22:35 +08001991int dvr_wrapper_only_update_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackPids_t *p_pids)
1992{
1993 DVR_WrapperCtx_t *ctx;
1994 int error;
1995 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1996
1997 DVR_RETURN_IF_FALSE(playback);
1998 DVR_RETURN_IF_FALSE(p_pids);
1999
2000 ctx = ctx_getPlayback((unsigned long)playback);
2001 DVR_RETURN_IF_FALSE(ctx);
2002
2003 pthread_mutex_lock(&ctx->lock);
2004
2005 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) ...\n",
2006 ctx->sn,
2007 p_pids->video.pid, p_pids->video.format,
2008 p_pids->audio.pid, p_pids->audio.format);
2009 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
2010
2011 ctx->playback.pids_req = *p_pids;
2012
2013 error = 0;
2014 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2015 /*should update the whole list of segments*/
2016 /*if (pseg->seg_info.id == ctx->current_segment_id)*/ {
2017 /*list_for_each_entry_from(pseg, &ctx->segments, head)*/ {
2018 /*check udpate for pids*/
2019 if (memcmp(&pseg->playback_info.pids, p_pids, sizeof(*p_pids)) != 0) {
2020 pseg->playback_info.pids = *p_pids;
2021 error = dvr_playback_only_update_segment_pids(ctx->playback.player, pseg->seg_info.id, p_pids);
2022 if (error) {
2023 DVR_WRAPPER_DEBUG(1, "failed to playback(sn:%ld) update segment(id:%lld) pids (%d)\n",
2024 ctx->sn, pseg->seg_info.id, error);
2025 /*do not break, let list updated*/
2026 }
2027 }
2028 }
2029 /*break;*/
2030 }
2031 }
2032
2033 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) (%d)\n",
2034 ctx->sn,
2035 p_pids->video.pid, p_pids->video.format,
2036 p_pids->audio.pid, p_pids->audio.format,
2037 error);
2038
2039 pthread_mutex_unlock(&ctx->lock);
2040
2041 return error;
2042}
2043
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002044int dvr_wrapper_get_playback_status(DVR_WrapperPlayback_t playback, DVR_WrapperPlaybackStatus_t *status)
2045{
2046 DVR_WrapperCtx_t *ctx;
2047 DVR_WrapperPlaybackStatus_t s;
2048 DVR_PlaybackStatus_t play_status;
2049 int error;
2050
2051 DVR_RETURN_IF_FALSE(playback);
2052 DVR_RETURN_IF_FALSE(status);
2053
2054 ctx = ctx_getPlayback((unsigned long)playback);
2055 DVR_RETURN_IF_FALSE(ctx);
2056
2057 pthread_mutex_lock(&ctx->lock);
2058
2059 DVR_WRAPPER_DEBUG(1, "get playback(sn:%ld) status ...\n", ctx->sn);
2060 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
2061
2062 error = dvr_playback_get_status(ctx->playback.player, &play_status);
2063 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) get status (%d)\n", ctx->sn, error);
2064
2065 ctx->playback.seg_status = play_status;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002066 error = process_generatePlaybackStatus(ctx, &s);
2067
hualing chenb5cd42e2020-04-15 17:03:34 +08002068 if (ctx->playback.reach_end == DVR_TRUE && ctx->playback.param_open.is_timeshift == DVR_FALSE) {
2069 //reach end need set full time to cur.so app can exist playback.
2070 DVR_WRAPPER_DEBUG(1, "set cur time to full time, reach end occur");
2071 s.info_cur.time = s.info_full.time;
2072 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002073 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) state/cur/full/obsl(%d/%ld/%ld/%ld) (%d)\n",
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002074 ctx->sn,
2075 s.state,
2076 s.info_cur.time,
2077 s.info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002078 s.info_obsolete.time,
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002079 error);
2080
2081 *status = s;
2082
2083 pthread_mutex_unlock(&ctx->lock);
2084
2085 return error;
2086}
2087
hualing chen266b9502020-04-04 17:39:39 +08002088int dvr_wrapper_set_playback_secure_buffer (DVR_WrapperPlayback_t playback, uint8_t *p_secure_buf, uint32_t len)
2089{
2090 DVR_WrapperCtx_t *ctx;
2091 int error;
2092
2093 DVR_RETURN_IF_FALSE(playback);
2094 DVR_RETURN_IF_FALSE(p_secure_buf);
2095
2096 ctx = ctx_getPlayback((unsigned long)playback);
2097 DVR_RETURN_IF_FALSE(ctx);
2098
2099 pthread_mutex_lock(&ctx->lock);
2100 error = dvr_playback_set_secure_buffer(ctx->playback.player, p_secure_buf, len);
2101 pthread_mutex_unlock(&ctx->lock);
2102 return error;
2103}
2104
2105int dvr_wrapper_set_playback_decrypt_callback (DVR_WrapperPlayback_t playback, DVR_CryptoFunction_t func, void *userdata)
2106{
2107 DVR_WrapperCtx_t *ctx;
2108 int error;
2109
2110 DVR_RETURN_IF_FALSE(playback);
2111 DVR_RETURN_IF_FALSE(func);
2112
2113 ctx = ctx_getPlayback((unsigned long)playback);
2114 DVR_RETURN_IF_FALSE(ctx);
2115
2116 pthread_mutex_lock(&ctx->lock);
2117 error = dvr_playback_set_decrypt_callback(ctx->playback.player, func, userdata);
2118 pthread_mutex_unlock(&ctx->lock);
2119 return error;
2120}
2121
Zhiqiang Han620b9252021-11-09 14:23:20 +08002122int dvr_wrapper_segment_del_by_location (const char *location)
2123{
2124 char fpath[DVR_MAX_LOCATION_SIZE];
2125
2126 DVR_RETURN_IF_FALSE(location);
2127
2128 /*del the stats file*/
2129 sprintf(fpath, "%s.stats", location);
2130 unlink(fpath);
2131
2132 return dvr_segment_del_by_location(location);
2133}
2134
2135int dvr_wrapper_segment_get_info_by_location (const char *location, DVR_WrapperInfo_t *p_info)
2136{
2137 FILE *fp;
2138 char fpath[DVR_MAX_LOCATION_SIZE];
2139
2140 DVR_RETURN_IF_FALSE(location);
2141 DVR_RETURN_IF_FALSE(p_info);
2142
2143 if (p_info)
2144 memset(p_info, 0, sizeof(p_info[0]));
2145
2146 memset(fpath, 0, sizeof(fpath));
2147 sprintf(fpath, "%s.stats", location);
2148
2149 /*stats file exists*/
2150 if ((fp = fopen(fpath, "r"))) {
2151 char buf[256];
2152
2153 if (fgets(buf, sizeof(buf), fp) != NULL
2154 && (sscanf(buf, ":%llu:%lu:%u",
2155 &p_info->size,
2156 &p_info->time,
2157 &p_info->pkts) == 3)) {
2158 fclose(fp);
2159 DVR_WRAPPER_DEBUG(1, "rec(%s) t/s/p:(%lu/%llu/%u)\n", location, p_info->time, p_info->size, p_info->pkts);
2160 return DVR_SUCCESS;
2161 }
Zhiqiang Hanb9785922021-11-26 18:47:39 +08002162 fclose(fp);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002163 }
2164
2165 /*fallback, slow on mass files*/
Zhiqiang Hanb9785922021-11-26 18:47:39 +08002166 DVR_WRAPPER_DEBUG(1, "rec '%s.stats' invalid.\n", location);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002167
2168 int error;
2169 uint32_t n_ids;
2170 uint64_t *p_ids;
Zhiqiang Han620b9252021-11-09 14:23:20 +08002171
hualing chen8aed9582021-12-24 17:59:56 +08002172 error = dvr_segment_get_list(location, &n_ids, &p_ids);
hualing chenb9a02922021-12-14 11:29:47 +08002173
Zhiqiang Han620b9252021-11-09 14:23:20 +08002174 if (!error) {
2175 int i;
hualing chenb9a02922021-12-14 11:29:47 +08002176 struct list_head info_list; /**< segment list head*/
2177 INIT_LIST_HEAD(&info_list);
2178
2179 //we need free info list buf when we used end.
hualing chen8aed9582021-12-24 17:59:56 +08002180 error = dvr_segment_get_allInfo(location, &info_list);
2181 if (error == DVR_FAILURE) {
hualing chenb9a02922021-12-14 11:29:47 +08002182 DVR_RecordSegmentInfo_t info;
2183
2184 memset(&info, 0, sizeof(info));
2185 error = DVR_FAILURE;
2186 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
hualing chen8aed9582021-12-24 17:59:56 +08002187 location, 0, error);
hualing chenb9a02922021-12-14 11:29:47 +08002188
2189 for (i = 0; i < n_ids; i++) {
hualing chen8aed9582021-12-24 17:59:56 +08002190 error = dvr_segment_get_info(location, p_ids[i], &info);
hualing chenb9a02922021-12-14 11:29:47 +08002191 if (!error) {
2192 p_info->size += info.size;
2193 p_info->time += info.duration;
2194 p_info->pkts += info.nb_packets;
2195 } else {
hualing chen8aed9582021-12-24 17:59:56 +08002196 DVR_WRAPPER_DEBUG(1, "%s:%lld get seg info fail.\n", location, p_ids[i]);
hualing chenb9a02922021-12-14 11:29:47 +08002197 break;
2198 }
2199 }
2200 } else {
2201 DVR_WRAPPER_DEBUG(1, "get list segment_nb::%d",n_ids);
2202 for (i = 0; i < n_ids; i++) {
2203
2204 DVR_RecordSegmentInfo_t *seg_info;
2205 DVR_PlaybackSegmentFlag_t flags;
2206 int found = 0;
2207 list_for_each_entry(seg_info, &info_list, head)
2208 {
hualing chen8aed9582021-12-24 17:59:56 +08002209 if (seg_info->id == p_ids[i]) {
hualing chenb9a02922021-12-14 11:29:47 +08002210 found = 1;
2211 break;
2212 }
2213 }
2214 if (!found) {
hualing chen8aed9582021-12-24 17:59:56 +08002215 DVR_WRAPPER_DEBUG(1, "get segment info::%d [%d]n_ids[%d]error", i, p_ids[i], n_ids);
2216 if (p_ids[i] == n_ids - 1) {
2217 DVR_RecordSegmentInfo_t info;
2218 DVR_WRAPPER_DEBUG(1, "get last segment info::%d [%d]n_ids[%d] from subfile", i, p_ids[i], n_ids);
2219 error = dvr_segment_get_info(location, p_ids[i], &info);
2220 if (!error) {
2221 p_info->size += info.size;
2222 p_info->time += info.duration;
2223 p_info->pkts += info.nb_packets;
2224 } else {
2225 DVR_WRAPPER_DEBUG(1, "%s:%lld get seg info fail.\n", location, p_ids[i]);
2226 break;
2227 }
2228 }
hualing chenb9a02922021-12-14 11:29:47 +08002229 continue;
2230 }
2231
2232 if (!error) {
2233 p_info->size += seg_info->size;
2234 p_info->time += seg_info->duration;
2235 p_info->pkts += seg_info->nb_packets;
2236 } else {
hualing chen8aed9582021-12-24 17:59:56 +08002237 DVR_WRAPPER_DEBUG(1, "%s:%lld get seg info fail.\n", location, p_ids[i]);
hualing chenb9a02922021-12-14 11:29:47 +08002238 break;
2239 }
2240 }
2241 //free list
2242 DVR_RecordSegmentInfo_t *segment = NULL;
2243 DVR_RecordSegmentInfo_t *segment_tmp = NULL;
2244 list_for_each_entry_safe(segment, segment_tmp, &info_list, head)
2245 {
2246 if (segment) {
2247 list_del(&segment->head);
2248 free(segment);
2249 }
2250 }
2251 }
2252 free(p_ids);
Zhiqiang Hanb9785922021-11-26 18:47:39 +08002253 } else {
2254 n_ids = 0;
Zhiqiang Han620b9252021-11-09 14:23:20 +08002255 }
Zhiqiang Hanb9785922021-11-26 18:47:39 +08002256 DVR_WRAPPER_DEBUG(1, "rec(%s)... t/s/p:(%lu/%llu/%u) segs(%u) error(%d)\n", location, p_info->time, p_info->size, p_info->pkts, n_ids, error);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002257
2258 return (error)? DVR_FAILURE : DVR_SUCCESS;
2259}
2260
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002261static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata)
2262{
2263 DVR_WrapperEventCtx_t evt;
2264
2265 DVR_RETURN_IF_FALSE(userdata);
2266
2267 evt.sn = (unsigned long)userdata;
2268 evt.type = W_REC;
2269 evt.record.event = event;
2270 evt.record.status = *(DVR_RecordStatus_t *)params;
2271 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, record, evt:0x%x]\n", evt.sn, evt.record.event);
2272 return ctx_addRecordEvent(&evt);
2273}
2274
2275static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata)
2276{
2277 DVR_WrapperEventCtx_t evt;
2278
2279 DVR_RETURN_IF_FALSE(userdata);
2280
2281 evt.sn = (unsigned long)userdata;
2282 evt.type = W_PLAYBACK;
2283 evt.playback.event = event;
2284 evt.playback.status = *(DVR_Play_Notify_t *)params;
2285 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, playbck, evt:0x%x]\n", evt.sn, evt.playback.event);
2286 return ctx_addPlaybackEvent(&evt);
2287}
2288
2289static inline int process_notifyRecord(DVR_WrapperCtx_t *ctx, DVR_RecordEvent_t evt, DVR_WrapperRecordStatus_t *status)
2290{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002291 DVR_WRAPPER_DEBUG(1, "notify(sn:%ld) evt(0x%x) statistic:time/size/pkts(%ld/%lld/%u) obsl:(%ld/%llu/%u)\n",
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002292 ctx->sn,
2293 evt,
2294 status->info.time,
2295 status->info.size,
2296 status->info.pkts,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002297 status->info_obsolete.time,
2298 status->info_obsolete.size,
2299 status->info_obsolete.pkts);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002300
2301 if (ctx->record.event_fn)
2302 return ctx->record.event_fn(evt, status, ctx->record.event_userdata);
2303 return 0;
2304}
2305
Zhiqiang Han620b9252021-11-09 14:23:20 +08002306static int wrapper_saveRecordStatistics(const char *location, DVR_WrapperRecordStatus_t *p_status)
2307{
2308 FILE *fp;
2309 char fpath[DVR_MAX_LOCATION_SIZE];
2310
2311 DVR_RETURN_IF_FALSE(location);
2312 DVR_RETURN_IF_FALSE(p_status);
2313
2314 sprintf(fpath, "%s.stats", location);
2315
2316 /*stats file*/
2317 if ((fp = fopen(fpath, "w"))) {
2318 char buf[256];
2319 snprintf(buf, sizeof(buf), ":%llu:%lu:%u\n",
2320 p_status->info.size - p_status->info_obsolete.size,
2321 p_status->info.time - p_status->info_obsolete.time,
2322 p_status->info.pkts - p_status->info_obsolete.pkts);
2323 fputs(buf, fp);
2324 fclose(fp);
2325 return DVR_SUCCESS;
2326 }
2327
2328 return DVR_FAILURE;
2329}
2330
2331
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002332static inline int record_startNextSegment(DVR_WrapperCtx_t *ctx)
2333{
2334 DVR_RecordStartParams_t param;
2335 DVR_RecordSegmentInfo_t seg_info;
2336 int i;
2337 int error;
2338
2339 memcpy(&param, &ctx->record.param_update, sizeof(param));
2340 memset(&ctx->record.param_update.segment, 0, sizeof(ctx->record.param_update.segment));
2341 ctx->record.param_update.segment.segment_id = ctx->record.next_segment_id++;
2342 for (i = 0; i < param.segment.nb_pids; i++) {
2343 if (param.segment.pid_action[i] != DVR_RECORD_PID_CLOSE) {
2344 ctx->record.param_update.segment.pids[ctx->record.param_update.segment.nb_pids] = param.segment.pids[i];
2345 ctx->record.param_update.segment.pid_action[ctx->record.param_update.segment.nb_pids] = DVR_RECORD_PID_KEEP;
2346 ctx->record.param_update.segment.nb_pids++;
2347 }
2348 }
2349 error = dvr_record_next_segment(ctx->record.recorder, &ctx->record.param_update, &seg_info);
2350 {
2351 DVR_RecordSegmentInfo_t new_seg_info =
2352 { .id = ctx->record.param_update.segment.segment_id, };
2353 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
2354 wrapper_addRecordSegment(ctx, &new_seg_info);
2355 }
2356
Zhiqiang Hand977e972020-05-11 11:30:47 +08002357 DVR_WRAPPER_DEBUG(1, "record next segment(%llu)=(%d)\n", ctx->record.param_update.segment.segment_id, error);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002358 return error;
2359}
2360
2361static inline int record_removeSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *pseg)
2362{
2363 return wrapper_removeRecordSegment(ctx, pseg);
2364}
2365
2366/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002367static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002368{
2369 /*the current seg is not covered in the statistics*/
2370 DVR_WrapperRecordSegmentInfo_t *pseg;
2371
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002372 /*re-calculate the all segments*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002373 memset(&ctx->record.status, 0, sizeof(ctx->record.status));
2374
2375 ctx->record.status.state = ctx->record.seg_status.state;
2376 ctx->record.status.pids.nb_pids = ctx->record.seg_status.info.nb_pids;
2377 memcpy(ctx->record.status.pids.pids,
2378 ctx->record.seg_status.info.pids,
2379 sizeof(ctx->record.status.pids.pids));
2380 ctx->current_segment_id = ctx->record.seg_status.info.id;
2381
2382 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2383 if (pseg->info.id != ctx->record.seg_status.info.id) {
2384 ctx->record.status.info.time += pseg->info.duration;
2385 ctx->record.status.info.size += pseg->info.size;
2386 ctx->record.status.info.pkts += pseg->info.nb_packets;
2387 }
2388 }
2389
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002390 ctx->record.status.info_obsolete = ctx->record.obsolete;
2391
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002392 wrapper_updateRecordSegment(ctx, &ctx->record.seg_status.info, U_ALL);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002393
2394 if (status) {
2395 *status = ctx->record.status;
2396 status->info.time += ctx->record.seg_status.info.duration;
2397 status->info.size += ctx->record.seg_status.info.size;
2398 status->info.pkts += ctx->record.seg_status.info.nb_packets;
2399 }
2400
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002401 return DVR_SUCCESS;
2402}
2403
2404
2405static int process_handleRecordEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2406{
2407 DVR_WrapperRecordStatus_t status;
2408
2409 memset(&status, 0, sizeof(status));
2410
2411 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d)\n",
2412 evt->sn, evt->record.event, evt->record.status.state);
hualing chend3b55ab2021-05-06 09:56:27 +08002413 if (ctx->record.param_update.segment.segment_id != evt->record.status.info.id) {
2414 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) cur id:0x%x (event id:%d)\n",
Gong Ke2a0ebbe2021-05-25 15:22:50 +08002415 evt->sn, (int)ctx->record.param_update.segment.segment_id, (int)evt->record.status.info.id);
hualing chend3b55ab2021-05-06 09:56:27 +08002416 return 0;
2417 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002418 switch (evt->record.event)
2419 {
2420 case DVR_RECORD_EVENT_STATUS:
2421 {
2422 switch (evt->record.status.state)
2423 {
2424 case DVR_RECORD_STATE_OPENED:
2425 case DVR_RECORD_STATE_CLOSED:
2426 {
2427 ctx->record.seg_status = evt->record.status;
2428
2429 status.state = evt->record.status.state;
2430 process_notifyRecord(ctx, evt->record.event, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002431 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002432 } break;
2433 case DVR_RECORD_STATE_STARTED:
2434 {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002435 ctx->record.seg_status = evt->record.status;
2436
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002437 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002438 process_notifyRecord(ctx, evt->record.event, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002439 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002440
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002441 /*restart to next segment*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002442 if (ctx->record.param_open.segment_size
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002443 && evt->record.status.info.size >= ctx->record.param_open.segment_size) {
2444 DVR_WRAPPER_DEBUG(1, "start new segment for record(%lu), reaches segment size limit, cur(%zu) max(%lld)\n",
2445 ctx->sn,
2446 evt->record.status.info.size,
2447 ctx->record.param_open.segment_size);
Zhiqiang Hand977e972020-05-11 11:30:47 +08002448 if (record_startNextSegment(ctx) != DVR_SUCCESS) {
2449 /*should notify the recording's stop*/
2450 int error = dvr_record_close(ctx->record.recorder);
2451 DVR_WRAPPER_DEBUG(1, "stop record(%lu)=%d, failed to start new segment for recording.",
2452 ctx->sn, error);
2453 status.state = DVR_RECORD_STATE_CLOSED;
2454 process_notifyRecord(ctx, DVR_RECORD_EVENT_WRITE_ERROR, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002455 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Hand977e972020-05-11 11:30:47 +08002456 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002457 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002458
2459 if (ctx->record.param_open.is_timeshift
2460 && ctx->record.param_open.max_time
2461 && status.info.time >= ctx->record.param_open.max_time) {
2462 DVR_WrapperRecordSegmentInfo_t *pseg;
2463
2464 /*as the player do not support null playlist,
2465 there must be one segment existed at any time,
2466 we have to keep two segments before remove one*/
2467 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
2468 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
2469 /*only one segment, waiting for more*/
2470 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of max_time(%ld) of record < max size of segment(%lld)\n",
2471 status.info.size,
2472 ctx->record.param_open.max_time,
2473 ctx->record.param_open.segment_size);
2474 } else {
2475 /*timeshifting, remove the 1st segment and notify the player*/
2476 record_removeSegment(ctx, pseg);
2477
2478 process_generateRecordStatus(ctx, &status);
2479 process_notifyRecord(ctx, evt->record.event, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002480 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002481 }
2482 }
2483
2484 if (ctx->record.param_open.is_timeshift
2485 && ctx->record.param_open.max_size
2486 && status.info.size >= ctx->record.param_open.max_size) {
2487 DVR_WrapperRecordSegmentInfo_t *pseg;
2488
2489 /*as the player do not support null playlist,
2490 there must be one segment existed at any time,
2491 we have to keep two segments before remove one*/
2492 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
2493 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
2494 /*only one segment, waiting for more*/
2495 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of record < max size of segment(%lld)\n",
2496 status.info.size,
2497 ctx->record.param_open.segment_size);
2498 } else {
2499 record_removeSegment(ctx, pseg);
2500
2501 process_generateRecordStatus(ctx, &status);
2502 process_notifyRecord(ctx, evt->record.event, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002503 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002504 }
2505 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002506 } break;
2507 case DVR_RECORD_STATE_STOPPED:
2508 {
2509 ctx->record.seg_status = evt->record.status;
2510
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002511 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002512 process_notifyRecord(ctx, evt->record.event, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002513 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002514 } break;
2515 default:
2516 break;
2517 }
2518 } break;
hualing chen4b7c15d2020-04-07 16:13:48 +08002519 case DVR_RECORD_EVENT_WRITE_ERROR: {
2520 ctx->record.seg_status = evt->record.status;
2521 status.state = evt->record.status.state;
2522 process_notifyRecord(ctx, evt->record.event, &status);
2523 }break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002524 default:
2525 break;
2526 }
2527 return DVR_SUCCESS;
2528}
2529
2530static inline int process_notifyPlayback(DVR_WrapperCtx_t *ctx, DVR_PlaybackEvent_t evt, DVR_WrapperPlaybackStatus_t *status)
2531{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002532 DVR_WRAPPER_DEBUG(1, "notify(sn:%ld) evt(0x%x) statistics:state/cur/full/obsl(%d/%ld/%ld/%ld)\n",
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002533 ctx->sn,
2534 evt,
2535 status->state,
2536 status->info_cur.time,
2537 status->info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002538 status->info_obsolete.time);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002539
2540 if (ctx->playback.event_fn)
2541 return ctx->playback.event_fn(evt, status, ctx->playback.event_userdata);
2542 return 0;
2543}
2544
2545/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002546static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperPlaybackStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002547{
2548 /*the current seg is not covered in the statistics*/
2549 DVR_WrapperPlaybackSegmentInfo_t *pseg;
2550
2551 memset(&ctx->playback.status, 0, sizeof(ctx->playback.status));
2552 ctx->playback.status.pids = ctx->playback.pids_req;
2553
2554 ctx->playback.status.state = ctx->playback.seg_status.state;
2555 ctx->playback.status.speed = ctx->playback.seg_status.speed;
2556 ctx->playback.status.flags = ctx->playback.seg_status.flags;
2557 ctx->current_segment_id = ctx->playback.seg_status.segment_id;
2558
2559 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2560 if (pseg->seg_info.id == ctx->playback.seg_status.segment_id)
2561 break;
2562 ctx->playback.status.info_cur.time += pseg->seg_info.duration;
2563 ctx->playback.status.info_cur.size += pseg->seg_info.size;
2564 ctx->playback.status.info_cur.pkts += pseg->seg_info.nb_packets;
2565 }
2566 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2567 ctx->playback.status.info_full.time += pseg->seg_info.duration;
2568 ctx->playback.status.info_full.size += pseg->seg_info.size;
2569 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
2570 }
2571
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002572 if (status) {
2573 *status = ctx->playback.status;
2574 /*deal with current, lack size and pkts with the current*/
2575 status->info_cur.time += ctx->playback.seg_status.time_cur;
2576 status->info_obsolete.time = ctx->playback.obsolete.time;
2577 }
2578
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002579 return DVR_SUCCESS;
2580}
2581
2582static int process_handlePlaybackEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2583{
2584 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d) cur(%lld:%u/%u)\n",
2585 evt->sn, evt->playback.event,
2586 evt->playback.status.play_status.state,
2587 evt->playback.status.play_status.segment_id,
2588 evt->playback.status.play_status.time_cur,
2589 evt->playback.status.play_status.time_end);
2590
2591 /*evt PLAYTIME will break the last logic, do not save*/
hualing chene3797f02021-01-13 14:53:28 +08002592 if (evt->playback.event != DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME
2593 && evt->playback.event != DVR_PLAYBACK_EVENT_NODATA
2594 && evt->playback.event != DVR_PLAYBACK_EVENT_DATARESUME
2595 )
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002596 ctx->playback.last_event = evt->playback.event;
2597
2598 switch (evt->playback.event)
2599 {
2600 case DVR_PLAYBACK_EVENT_FIRST_FRAME:
2601 case DVR_PLAYBACK_EVENT_REACHED_END:
2602 case DVR_PLAYBACK_EVENT_TRANSITION_OK:
2603 case DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME:
hualing chenb5cd42e2020-04-15 17:03:34 +08002604 case DVR_PLAYBACK_EVENT_ERROR:
hualing chenf291cf32020-06-18 10:50:30 +08002605 case DVR_PLAYBACK_EVENT_REACHED_BEGIN:
hualing chene3797f02021-01-13 14:53:28 +08002606 case DVR_PLAYBACK_EVENT_NODATA:
2607 case DVR_PLAYBACK_EVENT_DATARESUME:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002608 {
2609 DVR_WrapperPlaybackStatus_t status;
2610
2611 /*copy status of segment*/
2612 ctx->playback.seg_status = evt->playback.status.play_status;
2613
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002614 /*generate status of the whole playback*/
2615 process_generatePlaybackStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002616
2617 if (evt->playback.event == DVR_PLAYBACK_EVENT_REACHED_END) {
Zhiqiang Han31846002021-11-04 10:49:06 +08002618 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) event:0x%x\n", evt->sn, evt->playback.event);
hualing chenb9b358a2021-08-17 15:06:36 +08002619 if (ctx->playback.param_open.is_timeshift
2620 || ctx_isPlay_recording(ctx->playback.param_open.location)) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002621 /*wait for more data in recording*/
Zhiqiang Han31846002021-11-04 10:49:06 +08002622 }
2623 /*trust the low level, make NO check.
2624 As this evt is changed to only once due to some operations(paused) in low level.
2625 else if ((status.info_cur.time + DVR_PLAYBACK_END_GAP) >= ctx->playback.status.info_full.time) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002626 process_notifyPlayback(ctx, evt->playback.event, &status);
Zhiqiang Han31846002021-11-04 10:49:06 +08002627 }
2628 */
2629 else {
2630 process_notifyPlayback(ctx, evt->playback.event, &status);
hualing chenb5cd42e2020-04-15 17:03:34 +08002631 ctx->playback.reach_end = DVR_TRUE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002632 }
hualing chenf291cf32020-06-18 10:50:30 +08002633 } else if (evt->playback.event != DVR_PLAYBACK_EVENT_REACHED_BEGIN) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002634 process_notifyPlayback(ctx, evt->playback.event, &status);
2635 }
2636 } break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002637 case DVR_PLAYBACK_EVENT_TRANSITION_FAILED:
2638 case DVR_PLAYBACK_EVENT_KEY_FAILURE:
2639 case DVR_PLAYBACK_EVENT_NO_KEY:
2640 {
2641 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) error event:0x%x\n", evt->sn, evt->playback.event);
2642 } break;
2643 default:
2644 {
2645 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) unknown event:0x%x\n", evt->sn, evt->playback.event);
2646 } break;
2647 }
2648 return 0;
2649}
2650
2651static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2652{
2653 return (evt->type == W_REC)? process_handleRecordEvent(evt, ctx) : process_handlePlaybackEvent(evt, ctx);
2654}
2655