blob: 2a8edc43975dff7fe76862707362ef6d9c3aa111 [file] [log] [blame]
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001#include <stddef.h>
2#include <stdlib.h>
3#include <pthread.h>
4#include <string.h>
5#include <time.h>
6#include <errno.h>
Zhiqiang Han18f42c82021-08-11 17:13:28 +08007#include <sys/time.h>
8#include <time.h>
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08009
10#include "dvr_types.h"
11#include "dvr_record.h"
12#include "dvr_crypto.h"
13#include "dvr_playback.h"
14#include "dvr_segment.h"
15
16#include "AmTsPlayer.h"
17
18#include "list.h"
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080019
20#include "dvr_wrapper.h"
21
Gong Ke2a0ebbe2021-05-25 15:22:50 +080022#define DVR_WRAPPER_DEBUG(_level, _fmt...) \
23 DVR_DEBUG_FL(_level, "wrapper", _fmt)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080024
25/*duration of data to resume if paused with EVT_REACHED_END in timeshifting*/
hualing chen2932d372020-04-29 13:44:00 +080026#define TIMESHIFT_DATA_DURATION_TO_RESUME (600)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080027/*a tolerant gap*/
28#define DVR_PLAYBACK_END_GAP (1000)
29
30enum {
31 W_REC = 1,
32 W_PLAYBACK = 2,
33};
34
35enum {
36 U_PIDS = 0x01,
37 U_STAT = 0x02,
38 U_ALL = U_PIDS | U_STAT,
39};
40
41typedef struct {
42 /*make lock the 1st item in the structure*/
43 pthread_mutex_t lock;
44
45 /*rec or play*/
46 int type;
47
48 /*valid if (sn != 0)*/
49 unsigned long sn;
50 unsigned long sn_linked;
51
52 struct list_head segments; /**<head-add list*/
53 uint64_t current_segment_id; /**<id of the current segment*/
54
55 union {
56 struct {
57 DVR_WrapperRecordOpenParams_t param_open;
58 DVR_RecordStartParams_t param_start;
59 DVR_RecordStartParams_t param_update;
60 DVR_RecordHandle_t recorder;
61 DVR_RecordEventFunction_t event_fn;
62 void *event_userdata;
63
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080064 /*total status = seg_status + status + obsolete*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080065 DVR_RecordStatus_t seg_status; /**<status of current segment*/
66 DVR_WrapperRecordStatus_t status; /**<status of remaining segments*/
67 uint64_t next_segment_id;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080068
69 DVR_WrapperInfo_t obsolete; /**<data obsolete due to the max limit*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080070 } record;
71
72 struct {
73 DVR_WrapperPlaybackOpenParams_t param_open;
74 DVR_PlaybackHandle_t player;
75 DVR_PlaybackEventFunction_t event_fn;
76 void *event_userdata;
77
78 /*total status = seg_status + status*/
79 DVR_PlaybackStatus_t seg_status;
80 DVR_WrapperPlaybackStatus_t status;
81 DVR_PlaybackPids_t pids_req;
82 DVR_PlaybackEvent_t last_event;
Zhiqiang Han3eb75f92020-04-08 10:07:55 +080083 float speed;
hualing chenb5cd42e2020-04-15 17:03:34 +080084 DVR_Bool_t reach_end;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080085
86 DVR_WrapperInfo_t obsolete;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080087 } playback;
88 };
89} DVR_WrapperCtx_t;
90
91typedef struct {
92 struct list_head head;
93 unsigned long sn;
94
95 /* rec or playback */
96 int type;
97
98 union {
99 struct {
100 DVR_RecordEvent_t event;
101 DVR_RecordStatus_t status;
102 } record;
103 struct {
104 DVR_PlaybackEvent_t event;
105 DVR_Play_Notify_t status;
106 } playback;
107 };
108} DVR_WrapperEventCtx_t;
109
110typedef struct {
111 pthread_mutex_t lock;
112 char *name;
113 int running;
114 pthread_cond_t cond;
115 pthread_t thread;
116 int type;
117} DVR_WrapperThreadCtx_t;
118
119typedef struct {
120 struct list_head head;
121
122 DVR_RecordSegmentInfo_t seg_info;
123 DVR_PlaybackSegmentInfo_t playback_info;
124} DVR_WrapperPlaybackSegmentInfo_t;
125
126typedef struct {
127 struct list_head head;
128
129 DVR_RecordSegmentInfo_t info;
130} DVR_WrapperRecordSegmentInfo_t;
131
132/* serial num generater */
133static unsigned long sn = 1;
134static pthread_mutex_t sn_lock = PTHREAD_MUTEX_INITIALIZER;
135
136static inline unsigned long get_sn()
137{
hualing chenab0d1262021-09-26 15:22:50 +0800138 unsigned long no = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800139
140 pthread_mutex_lock(&sn_lock);
141 no = sn++;
142 if (!no)
143 no = sn++;
144 pthread_mutex_unlock(&sn_lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800145 return no;
146}
147
148/* entity ctx */
149#define DVR_WRAPPER_MAX 10
150
151static DVR_WrapperCtx_t record_list[DVR_WRAPPER_MAX] =
152{
153 [0 ... (DVR_WRAPPER_MAX - 1)] =
154 {
155 .lock = PTHREAD_MUTEX_INITIALIZER,
156 .type = W_REC,
157 }
158};
159
160static DVR_WrapperCtx_t playback_list[DVR_WRAPPER_MAX] =
161{
162 [0 ... (DVR_WRAPPER_MAX - 1)] =
163 {
164 .lock = PTHREAD_MUTEX_INITIALIZER,
165 .type = W_PLAYBACK,
166 }
167};
168
169/* events lists */
170static struct list_head record_evt_list = LIST_HEAD_INIT(record_evt_list);
171static struct list_head playback_evt_list = LIST_HEAD_INIT(playback_evt_list);
172
173static pthread_mutex_t record_evt_list_lock = PTHREAD_MUTEX_INITIALIZER;
174static pthread_mutex_t playback_evt_list_lock = PTHREAD_MUTEX_INITIALIZER;
175
176static DVR_WrapperThreadCtx_t wrapper_thread[2] =
177{
178 [0] =
179 {
180 .lock = PTHREAD_MUTEX_INITIALIZER,
181 .running = 0,
182 .name = "record",
183 .type = W_REC,
184 },
185 [1] =
186 {
187 .lock = PTHREAD_MUTEX_INITIALIZER,
188 .running = 0,
189 .name = "playback",
190 .type = W_PLAYBACK,
191 },
192};
193
194/*now only support one timeshift now*/
195static unsigned long sn_timeshift_record;
196static unsigned long sn_timeshift_playback;
197
198static void *wrapper_task(void *arg);
199static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx);
200
201static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata);
202static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata);
203
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800204static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordStatus_t *status);
205static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperPlaybackStatus_t *status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800206
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800207static int get_timespec_timeout(int timeout, struct timespec *ts)
208{
209 struct timespec ots;
210 int left, diff;
211
212 clock_gettime(CLOCK_MONOTONIC, &ots);
213
214 ts->tv_sec = ots.tv_sec + timeout / 1000;
215 ts->tv_nsec = ots.tv_nsec;
216
217 left = timeout % 1000;
218 left *= 1000000;
219 diff = 1000000000 - ots.tv_nsec;
220
221 if (diff <= left) {
222 ts->tv_sec++;
223 ts->tv_nsec = left-diff;
224 } else {
225 ts->tv_nsec += left;
226 }
227
228 return 0;
229}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800230
231static DVR_WrapperEventCtx_t *ctx_getEvent(struct list_head *list, pthread_mutex_t *list_lock)
232{
233 DVR_WrapperEventCtx_t *pevt;
234
235 pthread_mutex_lock(list_lock);
236 if (list_empty(list))
237 pevt = NULL;
238 else {
239 pevt = list_first_entry(list, DVR_WrapperEventCtx_t, head);
240 list_del(&pevt->head);
241 }
242 pthread_mutex_unlock(list_lock);
243
244 return pevt;
245}
246
247static inline DVR_WrapperEventCtx_t *ctx_getRecordEvent()
248{
249 return ctx_getEvent(&record_evt_list, &record_evt_list_lock);
250}
251
252static inline DVR_WrapperEventCtx_t *ctx_getPlaybackEvent()
253{
254 return ctx_getEvent(&playback_evt_list, &playback_evt_list_lock);
255}
256
257static int ctx_addEvent(struct list_head *list, pthread_mutex_t *lock, DVR_WrapperEventCtx_t *evt)
258{
259 DVR_WrapperEventCtx_t *padd;
260 padd = (DVR_WrapperEventCtx_t *)calloc(1, sizeof(DVR_WrapperEventCtx_t));
261 DVR_RETURN_IF_FALSE(padd);
262
263 *padd = *evt;
264 pthread_mutex_lock(lock);
265 list_add_tail(&padd->head, list);
266 pthread_mutex_unlock(lock);
267 return DVR_SUCCESS;
268}
269
270static inline void ctx_freeEvent(DVR_WrapperEventCtx_t *evt)
271{
272 free(evt);
273}
274
275/*useless*/
276static void ctx_cleanOutdatedEvents(struct list_head *evt_list,
277 pthread_mutex_t *evt_list_lock,
278 DVR_WrapperCtx_t *list)
279{
280 DVR_WrapperEventCtx_t *pevt, *pevt_tmp;
281 unsigned long sns[DVR_WRAPPER_MAX];
282 int cnt = 0;
283 int i;
284 int found = 0;
285
286 /*copy all valid sns*/
287 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
288 sns[cnt] = list[i].sn;
289 if (!sns[cnt])
290 cnt++;
291 }
292
293 /*free evts that not belong to any valid sns*/
294 pthread_mutex_lock(evt_list_lock);
295 list_for_each_entry_safe(pevt, pevt_tmp, evt_list, head) {
296 for (i = 0; i < cnt; i++) {
297 if (pevt->sn == sns[i]) {
298 found = 1;
299 break;
300 }
301 }
302 if (!found) {
303 list_del(&pevt->head);
304 ctx_freeEvent(pevt);
305 }
306 }
307 pthread_mutex_unlock(evt_list_lock);
308}
309
310static inline void ctx_cleanOutdatedRecordEvents()
311{
312 ctx_cleanOutdatedEvents(&record_evt_list, &record_evt_list_lock, record_list);
313}
314
315static inline void ctx_cleanOutdatedPlaybackEvents()
316{
317 ctx_cleanOutdatedEvents(&playback_evt_list, &playback_evt_list_lock, playback_list);
318}
319
hualing chenb9b358a2021-08-17 15:06:36 +0800320//check this play is recording file
321//return 0 if not the recording
322//else return record id
323static inline int ctx_isPlay_recording(char *play_location)
324{
325 int i;
326 DVR_WrapperCtx_t *cnt;
327
328 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
329 cnt = &record_list[i];
330 //DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]R:[%s]P:[%s] ...\n", i, cnt->sn, cnt->record.param_open.location, play_location);
331 if (!strcmp(cnt->record.param_open.location, play_location)) {
332 DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]R:[%s]P:[%s] .found..\n", i, cnt->sn, cnt->record.param_open.location, play_location);
333 return cnt->sn;
334 }
335 }
336 DVR_WRAPPER_DEBUG(1, " not found play is recing [%d]", DVR_WRAPPER_MAX);
337 return 0;
338}
339//check this record is playing file
340//return 0 if not the playing
341//else return playback id
342static inline int ctx_isRecord_playing(char *rec_location)
343{
344 int i;
345 DVR_WrapperCtx_t *cnt;
346 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
347 cnt = &playback_list[i];
348 //DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]P[%s]R[%s] ...\n", i, cnt->sn, cnt->playback.param_open.location, rec_location);
349 if (!strcmp(cnt->playback.param_open.location, rec_location)) {
350 DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]P[%s]R[%s] ..found.\n",i, cnt->sn, cnt->playback.param_open.location, rec_location);
351 return cnt->sn;
352 }
353 }
354 DVR_WRAPPER_DEBUG(1, " not found rec is playing [%d]", DVR_WRAPPER_MAX);
355 return 0;
356}
357
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800358static inline DVR_WrapperCtx_t *ctx_get(unsigned long sn, DVR_WrapperCtx_t *list)
359{
360 int i;
361 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
362 if (list[i].sn == sn)
363 return &list[i];
364 }
365 return NULL;
366}
367
368static inline void ctx_reset(DVR_WrapperCtx_t *ctx)
369{
370 memset((char *)ctx + offsetof(DVR_WrapperCtx_t, sn),
371 0,
372 sizeof(DVR_WrapperCtx_t) - offsetof(DVR_WrapperCtx_t, sn));
373}
374
375static inline int ctx_valid(DVR_WrapperCtx_t *ctx)
376{
377 return (ctx->sn != 0);
378}
379
380static inline DVR_WrapperCtx_t *ctx_getRecord(unsigned long sn)
381{
382 return ctx_get(sn, record_list);
383}
384
385static inline DVR_WrapperCtx_t *ctx_getPlayback(unsigned long sn)
386{
387 return ctx_get(sn, playback_list);
388}
389
390static int wrapper_requestThread(DVR_WrapperThreadCtx_t *ctx, void *(thread_fn)(void *))
391{
392 pthread_mutex_lock(&ctx->lock);
393 if (ctx->running == 0) {
394 pthread_condattr_t attr;
395 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
396 pthread_cond_init(&ctx->cond, &attr);
397 pthread_condattr_destroy(&attr);
398 DVR_WRAPPER_DEBUG(1, "start wrapper thread(%s) ...\n", ctx->name);
399 pthread_create(&ctx->thread, NULL, thread_fn, ctx);
400 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) started\n", ctx->name);
401 }
402 ctx->running++;
403 pthread_mutex_unlock(&ctx->lock);
404 return 0;
405}
406
407static int wrapper_releaseThread(DVR_WrapperThreadCtx_t *ctx)
408{
409 pthread_mutex_lock(&ctx->lock);
410 ctx->running--;
411 if (!ctx->running) {
412 pthread_cond_broadcast(&ctx->cond);
413 pthread_mutex_unlock(&ctx->lock);
414
415 DVR_WRAPPER_DEBUG(1, "stop wrapper thread(%s) ...\n", ctx->name);
416 pthread_join(ctx->thread, NULL);
417 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) stopped\n", ctx->name);
418
419 pthread_mutex_lock(&ctx->lock);
420 if (!ctx->running) /*protect*/
421 pthread_cond_destroy(&ctx->cond);
422 }
423 pthread_mutex_unlock(&ctx->lock);
424 return 0;
425}
426
427#define WRAPPER_THREAD_RECORD (&wrapper_thread[0])
428#define WRAPPER_THREAD_PLAYBACK (&wrapper_thread[1])
429
430static inline int wrapper_requestThreadFor(DVR_WrapperCtx_t *ctx)
431{
432 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
433 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
434 return wrapper_requestThread(thread_ctx, wrapper_task);
435}
436
437static inline int wrapper_releaseThreadFor(DVR_WrapperCtx_t *ctx)
438{
439 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
440 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
441 return wrapper_releaseThread(thread_ctx);
442}
443
444static inline int wrapper_releaseThreadForType(int type)
445{
446 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC)?
447 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
448 return wrapper_releaseThread(thread_ctx);
449}
450
451static inline void wrapper_threadSignal(DVR_WrapperThreadCtx_t *thread_ctx)
452{
453 pthread_cond_signal(&thread_ctx->cond);
454}
455
456static inline int wrapper_threadWait(DVR_WrapperThreadCtx_t *thread_ctx)
457{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800458 struct timespec rt;
459 get_timespec_timeout(200, &rt);
460 pthread_cond_timedwait(&thread_ctx->cond, &thread_ctx->lock, &rt);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800461 return 0;
462}
463
464static inline void wrapper_threadSignalForType(int type)
465{
466 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC) ?
467 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
468 wrapper_threadSignal(thread_ctx);
469}
470
471static inline void wrapper_threadSignalFor(DVR_WrapperCtx_t *ctx)
472{
473 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
474 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
475 wrapper_threadSignal(thread_ctx);
476}
477
478static inline int wrapper_threadWaitFor(DVR_WrapperCtx_t *ctx)
479{
480 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
481 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
482 wrapper_threadWait(thread_ctx);
483 return 0;
484}
485
486static void get_timeout_real(int timeout, struct timespec *ts)
487{
488 struct timespec ots;
489 int left, diff;
490
491 clock_gettime(CLOCK_REALTIME, &ots);
492
493 ts->tv_sec = ots.tv_sec + timeout/1000;
494 ts->tv_nsec = ots.tv_nsec;
495
496 left = timeout % 1000;
497 left *= 1000000;
498 diff = 1000000000-ots.tv_nsec;
499
500 if (diff <= left) {
501 ts->tv_sec++;
502 ts->tv_nsec = left-diff;
503 } else {
504 ts->tv_nsec += left;
505 }
506}
507
508/*return condition, locked if condition == true*/
509static int wrapper_mutex_lock_if(pthread_mutex_t *lock, int *condition)
510{
511 int r2;
512 do {
513 struct timespec rt2;
514 /*android use real time for mutex timedlock*/
515 get_timeout_real(10, &rt2);
516 r2 = pthread_mutex_timedlock(lock, &rt2);
517 } while (*condition && (r2 == ETIMEDOUT));
518
519 if (!(*condition) && (r2 == 0))
520 pthread_mutex_unlock(lock);
521
522 return *condition;
523}
524
525static void *wrapper_task(void *arg)
526{
527 DVR_WrapperThreadCtx_t *tctx = (DVR_WrapperThreadCtx_t *)arg;
528 DVR_WrapperEventCtx_t *evt;
529
530 pthread_mutex_lock(&tctx->lock);
531
532 while (tctx->running) {
533 {
534 int ret;
hualing chene3797f02021-01-13 14:53:28 +0800535
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800536 evt = (tctx->type == W_REC)? ctx_getRecordEvent() : ctx_getPlaybackEvent();
537 if (!evt)
538 ret = wrapper_threadWait(tctx);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800539 }
540
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800541 while (evt) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800542 DVR_WrapperCtx_t *ctx = (evt->type == W_REC)?
543 ctx_getRecord(evt->sn) : ctx_getPlayback(evt->sn);
hualing chenbc0aec92021-03-18 14:52:40 +0800544 if (ctx == NULL) {
545 DVR_WRAPPER_DEBUG(1, "warp not get ctx.free event..\n");
546 goto processed;
547 }
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800548 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 +0800549 if (tctx->running) {
550 /*
551 continue not break,
552 make all events consumed, or mem leak
553 */
554 if (!wrapper_mutex_lock_if(&ctx->lock, &tctx->running))
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800555 goto processed;
556
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800557 if (ctx_valid(ctx)) {
558 /*double check after lock*/
Zhiqiang Han3b9c9082021-11-10 10:41:09 +0800559 if (evt->sn == ctx->sn) {
560 pthread_mutex_unlock(&tctx->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800561 process_handleEvents(evt, ctx);
Zhiqiang Han3b9c9082021-11-10 10:41:09 +0800562 pthread_mutex_lock(&tctx->lock);
563 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800564 }
565 pthread_mutex_unlock(&ctx->lock);
566 }
567
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800568processed:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800569 ctx_freeEvent(evt);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800570
571 evt = (tctx->type == W_REC)? ctx_getRecordEvent() : ctx_getPlaybackEvent();
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800572 }
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800573 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 +0800574 }
575
576 pthread_mutex_unlock(&tctx->lock);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800577 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 +0800578 return NULL;
579}
580
581static inline int ctx_addRecordEvent(DVR_WrapperEventCtx_t *evt)
582{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800583 pthread_mutex_lock(&WRAPPER_THREAD_RECORD->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800584 if (ctx_addEvent(&record_evt_list, &record_evt_list_lock, evt) == 0)
585 wrapper_threadSignalForType(evt->type);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800586 pthread_mutex_unlock(&WRAPPER_THREAD_RECORD->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800587 return 0;
588}
589
590static inline int ctx_addPlaybackEvent(DVR_WrapperEventCtx_t *evt)
591{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800592 pthread_mutex_lock(&WRAPPER_THREAD_PLAYBACK->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800593 if (ctx_addEvent(&playback_evt_list, &playback_evt_list_lock, evt) == 0)
594 wrapper_threadSignalForType(evt->type);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800595 pthread_mutex_unlock(&WRAPPER_THREAD_PLAYBACK->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800596 return 0;
597}
598
599static inline void ctx_freeSegments(DVR_WrapperCtx_t *ctx)
600{
601 DVR_WrapperPlaybackSegmentInfo_t *pseg, *pseg_tmp;
602 list_for_each_entry_safe(pseg, pseg_tmp, &ctx->segments, head) {
603 list_del(&pseg->head);
604 free(pseg);
605 }
606}
607
608static inline void _updatePlaybackSegment(DVR_WrapperPlaybackSegmentInfo_t *pseg,
609 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
610{
611 (void)ctx;
612 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
613 pseg->seg_info = *seg_info;
614 else if (update_flags & U_PIDS) {
615 pseg->seg_info.nb_pids = seg_info->nb_pids;
616 memcpy(pseg->seg_info.pids, seg_info->pids, sizeof(pseg->seg_info.pids));
617 } else if (update_flags & U_STAT) {
618 pseg->seg_info.duration = seg_info->duration;
619 pseg->seg_info.size = seg_info->size;
620 pseg->seg_info.nb_packets = seg_info->nb_packets;
621 }
hualing chen03fd4942021-07-15 15:56:41 +0800622 //update current segment duration on timeshift mode
hualing chenb9b358a2021-08-17 15:06:36 +0800623 if (ctx->playback.param_open.is_timeshift
624 || ctx_isPlay_recording(ctx->playback.param_open.location))
hualing chen03fd4942021-07-15 15:56:41 +0800625 dvr_playback_update_duration(ctx->playback.player,pseg->seg_info.id,pseg->seg_info.duration);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800626 /*no changes
627 DVR_PlaybackSegmentFlag_t flags;
628 pseg->playback_info.segment_id = pseg->seg_info.id;
629 strncpy(pseg->playback_info.location,
630 ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
631 pseg->playback_info.pids = ctx->playback.pids_req;
632 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
633 if (ctx->record.param_open.flags | DVR_RECORD_FLAG_SCRAMBLED)
634 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
635 pseg->playback_info.flags = flags;
636 */
637}
638
639static int wrapper_updatePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
640{
641 DVR_WrapperPlaybackSegmentInfo_t *pseg;
642
643 DVR_WRAPPER_DEBUG(1, "timeshift, update playback segments(wrapper), seg:%lld t/s/p(%ld/%zu/%u)\n",
644 seg_info->id, seg_info->duration, seg_info->size, seg_info->nb_packets);
645
646 if (list_empty(&ctx->segments)) {
647 DVR_WRAPPER_DEBUG(1, "timeshift, update while no segment exists, ignore\n");
648 return DVR_SUCCESS;
649 }
650
651 /*normally, the last segment added will be updated*/
652 pseg =
653 list_first_entry(&ctx->segments, DVR_WrapperPlaybackSegmentInfo_t, head);
654 if (pseg->seg_info.id == seg_info->id) {
655 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
656 } else {
657 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
658 if (pseg->seg_info.id == seg_info->id) {
659 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
660 break;
661 }
662 }
663 }
664
665 /*need to notify the dvr_playback*/
hualing chenb9b358a2021-08-17 15:06:36 +0800666 if ((ctx->playback.param_open.is_timeshift/*should must be timeshift*/
667 || ctx_isPlay_recording(ctx->playback.param_open.location))
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800668 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END
669 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
670 if (
671 /*there's $TIMESHIFT_DATA_DURATION_TO_RESUME more of data in the current segment playing*/
672 (ctx->playback.seg_status.segment_id == seg_info->id
673 && (seg_info->duration >= ((time_t)ctx->playback.seg_status.time_cur + TIMESHIFT_DATA_DURATION_TO_RESUME)))
674 ||
675 /*or there's a new segment and has $TIMESHIFT_DATA_DURATION_TO_RESUME of data*/
676 (ctx->playback.seg_status.segment_id != seg_info->id
677 && (seg_info->duration >= TIMESHIFT_DATA_DURATION_TO_RESUME))
678 )
679 {
680 int error;
hualing chen36e0dfd2020-05-02 16:33:06 +0800681 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +0800682 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +0800683 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800684
685 error = dvr_playback_resume(ctx->playback.player);
686 DVR_WRAPPER_DEBUG(1, "timeshift, resume playback(sn:%ld) (%d) id/dur: rec(%lld/%ld) play(%lld/%u)\n",
687 ctx->sn, error,
688 seg_info->id, seg_info->duration,
689 ctx->playback.seg_status.segment_id, ctx->playback.seg_status.time_cur);
690 }
691 }
692
693 return DVR_SUCCESS;
694}
695
696static void _updateRecordSegment(DVR_WrapperRecordSegmentInfo_t *pseg,
697 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
698{
699 (void)ctx;
700 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
701 pseg->info = *seg_info;
702 else if (update_flags & U_PIDS) {
703 pseg->info.nb_pids = seg_info->nb_pids;
704 memcpy(pseg->info.pids, seg_info->pids, sizeof(pseg->info.pids));
705 } else if (update_flags & U_STAT) {
706 pseg->info.duration = seg_info->duration;
707 pseg->info.size = seg_info->size;
708 pseg->info.nb_packets = seg_info->nb_packets;
709 }
710}
711
712static int wrapper_updateRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
713{
hualing chen266b9502020-04-04 17:39:39 +0800714 DVR_WrapperRecordSegmentInfo_t *pseg = NULL;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800715
716 /*normally, the last segment added will be updated*/
hualing chen266b9502020-04-04 17:39:39 +0800717 if (!list_empty(&ctx->segments)) {
718 pseg =
719 list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
720 if (pseg->info.id == seg_info->id) {
721 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
722 } else {
723 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
724 if (pseg->info.id == seg_info->id) {
725 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
726 break;
727 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800728 }
729 }
730 }
731
732 /*timeshift, update the segment for playback*/
733 /*
734 the playback should grab the segment info other than the id,
735 and the id will be updated by each segment-add during the recording
736 */
737 /*
738 the playback paused if no data been checked from recording,
739 should resume the player later when there's more data
740 */
hualing chenb9b358a2021-08-17 15:06:36 +0800741 int sn = 0;
742 if (ctx->record.param_open.is_timeshift ||
743 (sn = ctx_isRecord_playing(ctx->record.param_open.location))) {
744 DVR_WrapperCtx_t *ctx_playback;
745 if (ctx->record.param_open.is_timeshift)
746 ctx_playback = ctx_getPlayback(sn_timeshift_playback);
747 else
748 ctx_playback = ctx_getPlayback(sn);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800749
750 if (ctx_playback) {
751 pthread_mutex_lock(&ctx_playback->lock);
752 if (ctx_valid(ctx_playback)
hualing chenb9b358a2021-08-17 15:06:36 +0800753 && (ctx_playback->sn == sn_timeshift_playback ||
754 ctx_playback->sn == sn)) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800755 wrapper_updatePlaybackSegment(ctx_playback, seg_info, update_flags);
756 }
757 pthread_mutex_unlock(&ctx_playback->lock);
758 }
759 }
760
761 return DVR_SUCCESS;
762}
763
764static int wrapper_addPlaybackSegment(DVR_WrapperCtx_t *ctx,
765 DVR_RecordSegmentInfo_t *seg_info,
766 DVR_PlaybackPids_t *p_pids,
767 DVR_PlaybackSegmentFlag_t flags)
768{
769 DVR_WrapperPlaybackSegmentInfo_t *pseg;
770 int error;
771
772 error = 0;
773 pseg = (DVR_WrapperPlaybackSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperPlaybackSegmentInfo_t));
774 if (!pseg) {
775 error = DVR_FAILURE;
776 DVR_WRAPPER_DEBUG(1, "memory fail\n");
777 return error;
778 }
779
780 /*copy the orignal segment info*/
781 pseg->seg_info = *seg_info;
782 /*generate the segment info used in playback*/
783 pseg->playback_info.segment_id = pseg->seg_info.id;
784 strncpy(pseg->playback_info.location, ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
785 pseg->playback_info.pids = *p_pids;
786 pseg->playback_info.flags = flags;
787 list_add(&pseg->head, &ctx->segments);
hualing chen03fd4942021-07-15 15:56:41 +0800788 pseg->playback_info.duration = pseg->seg_info.duration;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800789
790 error = dvr_playback_add_segment(ctx->playback.player, &pseg->playback_info);
791 if (error) {
792 DVR_WRAPPER_DEBUG(1, "fail to add segment %lld (%d)\n", pseg->playback_info.segment_id, error);
793 } else {
794 ctx->playback.status.info_full.time += pseg->seg_info.duration;
795 ctx->playback.status.info_full.size += pseg->seg_info.size;
796 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
797 }
798
799 return error;
800}
801
802static int wrapper_addRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
803{
804 DVR_WrapperRecordSegmentInfo_t *pseg;
805 int error;
hualing chenab0d1262021-09-26 15:22:50 +0800806 int sn = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800807
808 error = 0;
809 pseg = (DVR_WrapperRecordSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperRecordSegmentInfo_t));
810 if (!pseg) {
811 error = DVR_FAILURE;
812 DVR_WRAPPER_DEBUG(1, "memory fail\n");
813 }
814 pseg->info = *seg_info;
815 list_add(&pseg->head, &ctx->segments);
hualing chenab0d1262021-09-26 15:22:50 +0800816
hualing chenb9b358a2021-08-17 15:06:36 +0800817 if (ctx->record.param_open.is_timeshift ||
818 (sn = ctx_isRecord_playing(ctx->record.param_open.location))) {
819
820 DVR_WrapperCtx_t *ctx_playback;
821 if (ctx->record.param_open.is_timeshift)
822 ctx_playback = ctx_getPlayback(sn_timeshift_playback);
823 else
824 ctx_playback = ctx_getPlayback(sn);
825
826 DVR_WRAPPER_DEBUG(1, "ctx_playback ---- add segment\n");
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800827
828 if (ctx_playback) {
829 pthread_mutex_lock(&ctx_playback->lock);
830 if (ctx_valid(ctx_playback)) {
831 DVR_PlaybackSegmentFlag_t flags;
832
833 /*only if playback has started, the previous segments have been loaded*/
834 if (!list_empty(&ctx_playback->segments)) {
835 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
Gong Ke2a0ebbe2021-05-25 15:22:50 +0800836 if (ctx->record.param_open.flags & DVR_RECORD_FLAG_SCRAMBLED)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800837 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
838 wrapper_addPlaybackSegment(ctx_playback, seg_info, &ctx_playback->playback.pids_req, flags);
839 }
hualing chenb9b358a2021-08-17 15:06:36 +0800840 } else {
841 DVR_WRAPPER_DEBUG(1, "ctx_playback ---- not valid\n");
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800842 }
843 pthread_mutex_unlock(&ctx_playback->lock);
844 }
Zhiqiang Hane0a1c382021-06-08 11:28:05 +0800845 } else {
hualing chenb9b358a2021-08-17 15:06:36 +0800846 DVR_WRAPPER_DEBUG(1, "ctx_playback -sn[%d]-\n", sn);
Zhiqiang Hane0a1c382021-06-08 11:28:05 +0800847 dvr_segment_link_op(ctx->record.param_open.location, 1, &seg_info->id, LSEG_OP_ADD);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800848 }
849
850 return error;
851}
852
853static int wrapper_removePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
854{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800855 int error = -1;
856 DVR_WrapperPlaybackSegmentInfo_t *pseg = NULL, *pseg_tmp;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800857
858 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->id);
859
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800860 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800861 if (pseg->seg_info.id == seg_info->id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800862
863 if (ctx->current_segment_id == seg_info->id) {
864 DVR_WrapperPlaybackSegmentInfo_t *next_seg;
865
866 /*drive the player out of this will-be-deleted segment*/
867 next_seg = list_prev_entry(pseg, head);
868
869 if (ctx->playback.speed != 100.0f) {
870 error = dvr_playback_resume(ctx->playback.player);
871 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), resume for new start (%d)\n", ctx->sn, error);
872 }
873
874 error = dvr_playback_seek(ctx->playback.player, next_seg->seg_info.id, 0);
875 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);
876
877 if (ctx->playback.speed == 0.0f) {
878 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
879 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last paused from new start (%d)\n", ctx->sn, error);
880 } else if (ctx->playback.speed != 100.0f) {
881 DVR_PlaybackSpeed_t dvr_speed = {
882 .speed = { ctx->playback.speed },
883 .mode = ( ctx->playback.speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
884 };
885 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
886 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last speed(x%f) from new start (%d)\n", ctx->sn,ctx->playback.speed, error);
887 }
888 }
889
890 error = dvr_playback_remove_segment(ctx->playback.player, seg_info->id);
891 if (error) {
892 /*remove playack segment fail*/
893 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), failed to remove segment(%llu) (%d)\n", ctx->sn, seg_info->id, error);
894 }
895
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800896 list_del(&pseg->head);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800897
898 /*record the obsolete*/
899 ctx->playback.obsolete.time += pseg->seg_info.duration;
900 ctx->playback.obsolete.size += pseg->seg_info.size;
901 ctx->playback.obsolete.pkts += pseg->seg_info.nb_packets;
hualing chen03fd4942021-07-15 15:56:41 +0800902 dvr_playback_set_obsolete(ctx->playback.player, ctx->playback.obsolete.time);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800903 free(pseg);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800904 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800905 }
906 }
907
908 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->id, error);
909
910 return error;
911}
912
913static int wrapper_removeRecordSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *seg_info)
914{
915 int error;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800916 DVR_WrapperRecordSegmentInfo_t *pseg, *pseg_tmp;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800917
918 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->info.id);
919
920 /*if timeshifting, notify the playback first, then deal with record*/
921 if (ctx->record.param_open.is_timeshift) {
922 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
923
924 if (ctx_playback) {
925 pthread_mutex_lock(&ctx_playback->lock);
926 if (ctx_valid(ctx_playback)
927 && ctx_playback->sn == sn_timeshift_playback
928 && !list_empty(&ctx_playback->segments)) {
929 error = wrapper_removePlaybackSegment(ctx_playback, &seg_info->info);
930 }
931 pthread_mutex_unlock(&ctx_playback->lock);
932 }
933 }
934
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800935 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
936 if (pseg->info.id == seg_info->info.id) {
937 list_del(&pseg->head);
938
939 /*record the obsolete*/
940 ctx->record.obsolete.time += pseg->info.duration;
941 ctx->record.obsolete.size += pseg->info.size;
942 ctx->record.obsolete.pkts += pseg->info.nb_packets;
943
944 free(pseg);
945 break;
946 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800947 }
948
949 error = dvr_segment_delete(ctx->record.param_open.location, seg_info->info.id);
950
951 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->info.id, error);
952
953 return error;
954}
955
956int dvr_wrapper_open_record (DVR_WrapperRecord_t *rec, DVR_WrapperRecordOpenParams_t *params)
957{
958 int error;
959 DVR_WrapperCtx_t *ctx;
960 DVR_RecordOpenParams_t open_param;
961
962 DVR_RETURN_IF_FALSE(rec);
963 DVR_RETURN_IF_FALSE(params);
964
965 /*get a free ctx*/
966 ctx = ctx_getRecord(0);
967 DVR_RETURN_IF_FALSE(ctx);
968
969 pthread_mutex_lock(&ctx->lock);
970
hualing chen51652f02020-12-29 16:59:31 +0800971 DVR_WRAPPER_DEBUG(1, "open record(dmx:%d) .istf(%d)..time (%ld)ms max size(%lld)byte seg size(%lld)byte\n",
972 params->dmx_dev_id, params->is_timeshift, params->max_time, params->max_size, params->segment_size);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800973
974 ctx_reset(ctx);
975
976 ctx->record.param_open = *params;
977 ctx->record.event_fn = params->event_fn;
978 ctx->record.event_userdata = params->event_userdata;
979 ctx->record.next_segment_id = 0;
980 ctx->current_segment_id = 0;
981 INIT_LIST_HEAD(&ctx->segments);
982 ctx->sn = get_sn();
983
984 wrapper_requestThreadFor(ctx);
985
hualing chen266b9502020-04-04 17:39:39 +0800986 memset(&open_param, 0, sizeof(DVR_RecordOpenParams_t));
Yahui Hance15e9c2020-12-08 18:08:32 +0800987 open_param.fend_dev_id = params->fend_dev_id;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800988 open_param.dmx_dev_id = params->dmx_dev_id;
989 open_param.data_from_memory = 0;
990 open_param.flags = params->flags;
Yahui Han15a00f12021-11-15 19:44:39 +0800991 if (params->flush_size) {
992 open_param.notification_size = params->flush_size;
993 } else {
994 open_param.notification_size = 64*1024;
995 }
Zhiqiang Han31505452020-05-06 15:08:10 +0800996 open_param.flush_size = params->flush_size;
hualing chen03fd4942021-07-15 15:56:41 +0800997 open_param.ringbuf_size = params->ringbuf_size;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800998 open_param.event_fn = wrapper_record_event_handler;
999 open_param.event_userdata = (void*)ctx->sn;
Yahui Han1fbf3292021-11-08 18:17:19 +08001000 if (params->keylen) {
1001 open_param.clearkey = params->clearkey;
1002 open_param.cleariv = params->cleariv;
1003 open_param.keylen = params->keylen;
1004 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001005
1006 error = dvr_record_open(&ctx->record.recorder, &open_param);
1007 if (error) {
1008 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) open fail(error:%d).\n", params->dmx_dev_id, error);
1009 ctx_reset(ctx);
1010 pthread_mutex_unlock(&ctx->lock);
1011 wrapper_releaseThreadForType(ctx->type);
1012 return DVR_FAILURE;
1013 }
1014 if (params->is_timeshift)
1015 sn_timeshift_record = ctx->sn;
1016
1017 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
1018
Yahui Han1fbf3292021-11-08 18:17:19 +08001019 if (params->crypto_fn) {
1020 error = dvr_record_set_encrypt_callback(ctx->record.recorder, params->crypto_fn, params->crypto_data);
1021 if (error) {
1022 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) set encrypt callback fail(error:%d).\n", params->dmx_dev_id, error);
1023 }
hualing chen266b9502020-04-04 17:39:39 +08001024 }
1025
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001026 pthread_mutex_unlock(&ctx->lock);
1027
1028 *rec = (DVR_WrapperRecord_t)ctx->sn;
1029 return DVR_SUCCESS;
1030}
1031
1032int dvr_wrapper_close_record (DVR_WrapperRecord_t rec)
1033{
1034 DVR_WrapperCtx_t *ctx;
1035 DVR_RecordSegmentInfo_t seg_info;
1036 int error;
1037
1038 DVR_RETURN_IF_FALSE(rec);
1039
1040 ctx = ctx_getRecord((unsigned long)rec);
1041 DVR_RETURN_IF_FALSE(ctx);
1042
1043 pthread_mutex_lock(&ctx->lock);
1044 DVR_WRAPPER_DEBUG(1, "close record(sn:%ld)\n", ctx->sn);
1045 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1046
1047 memset(&seg_info, 0, sizeof(seg_info));
1048 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
1049
1050 error = dvr_record_close(ctx->record.recorder);
1051
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001052 if (ctx->record.param_open.is_timeshift)
1053 sn_timeshift_record = 0;
1054
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001055 ctx_freeSegments(ctx);
1056
1057 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) closed = (%d).\n", ctx->sn, error);
1058 ctx_reset(ctx);
1059 pthread_mutex_unlock(&ctx->lock);
1060
1061 wrapper_releaseThreadForType(ctx->type);
1062
1063 return error;
1064}
1065
1066int dvr_wrapper_start_record (DVR_WrapperRecord_t rec, DVR_WrapperRecordStartParams_t *params)
1067{
1068 DVR_WrapperCtx_t *ctx;
1069 DVR_RecordStartParams_t *start_param;
1070 int i;
1071 int error;
1072
1073 DVR_RETURN_IF_FALSE(rec);
1074 DVR_RETURN_IF_FALSE(params);
1075
1076 ctx = ctx_getRecord((unsigned long)rec);
1077 DVR_RETURN_IF_FALSE(ctx);
1078
1079 pthread_mutex_lock(&ctx->lock);
1080 DVR_WRAPPER_DEBUG(1, "start record(sn:%ld, location:%s) ...\n", ctx->sn, ctx->record.param_open.location);
1081 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1082
1083 start_param = &ctx->record.param_start;
1084 memset(start_param, 0, sizeof(*start_param));
1085 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
1086 start_param->segment.segment_id = ctx->record.next_segment_id++;
1087 start_param->segment.nb_pids = params->pids_info.nb_pids;
1088 for (i = 0; i < params->pids_info.nb_pids; i++) {
1089 start_param->segment.pids[i] = params->pids_info.pids[i];
1090 start_param->segment.pid_action[i] = DVR_RECORD_PID_CREATE;
1091 }
hualing chen7a56cba2020-04-14 14:09:27 +08001092 dvr_segment_del_by_location(start_param->location);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001093 {
1094 /*sync to update for further use*/
1095 DVR_RecordStartParams_t *update_param;
1096 update_param = &ctx->record.param_update;
1097 memcpy(update_param, start_param, sizeof(*update_param));
1098 for (i = 0; i < update_param->segment.nb_pids; i++)
1099 update_param->segment.pid_action[i] = DVR_RECORD_PID_KEEP;
1100 }
1101
1102 error = dvr_record_start_segment(ctx->record.recorder, start_param);
1103 {
1104 DVR_RecordSegmentInfo_t new_seg_info =
1105 { .id = start_param->segment.segment_id, };
1106 wrapper_addRecordSegment(ctx, &new_seg_info);
1107 }
1108
1109 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) started = (%d)\n", ctx->sn, error);
1110
1111 pthread_mutex_unlock(&ctx->lock);
1112
1113 return error;
1114}
1115
1116int dvr_wrapper_stop_record (DVR_WrapperRecord_t rec)
1117{
1118 DVR_WrapperCtx_t *ctx;
1119 DVR_RecordSegmentInfo_t seg_info;
1120 int error;
1121
1122 DVR_RETURN_IF_FALSE(rec);
1123
1124 ctx = ctx_getRecord((unsigned long)rec);
1125 DVR_RETURN_IF_FALSE(ctx);
1126
1127 pthread_mutex_lock(&ctx->lock);
1128 DVR_WRAPPER_DEBUG(1, "stop record(sn:%ld) ...\n", ctx->sn);
1129 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1130
1131 memset(&seg_info, 0, sizeof(seg_info));
1132 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
1133 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
1134
1135 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) stopped = (%d)\n", ctx->sn, error);
1136 pthread_mutex_unlock(&ctx->lock);
1137
1138 return error;
1139}
1140
hualing chen03fd4942021-07-15 15:56:41 +08001141int dvr_wrapper_pause_record (DVR_WrapperRecord_t rec)
1142{
1143 DVR_WrapperCtx_t *ctx;
1144 int error;
1145
1146 DVR_RETURN_IF_FALSE(rec);
1147
1148 ctx = ctx_getRecord((unsigned long)rec);
1149 DVR_RETURN_IF_FALSE(ctx);
1150
1151 pthread_mutex_lock(&ctx->lock);
1152 DVR_WRAPPER_DEBUG(1, "pause record(sn:%ld) ...\n", ctx->sn);
1153 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1154
1155 error = dvr_record_pause(ctx->record.recorder);
1156
1157 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) pauseed = (%d)\n", ctx->sn, error);
1158 pthread_mutex_unlock(&ctx->lock);
1159
1160 return error;
1161}
1162
1163int dvr_wrapper_resume_record (DVR_WrapperRecord_t rec)
1164{
1165 DVR_WrapperCtx_t *ctx;
1166 int error;
1167
1168 DVR_RETURN_IF_FALSE(rec);
1169
1170 ctx = ctx_getRecord((unsigned long)rec);
1171 DVR_RETURN_IF_FALSE(ctx);
1172
1173 pthread_mutex_lock(&ctx->lock);
1174 DVR_WRAPPER_DEBUG(1, "resume record(sn:%ld) ...\n", ctx->sn);
1175 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1176
1177 error = dvr_record_resume(ctx->record.recorder);
1178
1179 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) resumed = (%d)\n", ctx->sn, error);
1180 pthread_mutex_unlock(&ctx->lock);
1181
1182 return error;
1183}
1184
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001185int dvr_wrapper_update_record_pids (DVR_WrapperRecord_t rec, DVR_WrapperUpdatePidsParams_t *params)
1186{
1187 DVR_WrapperCtx_t *ctx;
1188 DVR_RecordStartParams_t *start_param;
1189 DVR_RecordSegmentInfo_t seg_info;;
1190 int i;
1191 int error;
1192
1193 DVR_RETURN_IF_FALSE(rec);
1194 DVR_RETURN_IF_FALSE(params);
1195
1196 ctx = ctx_getRecord((unsigned long)rec);
1197 DVR_RETURN_IF_FALSE(ctx);
1198
1199 pthread_mutex_lock(&ctx->lock);
1200 DVR_WRAPPER_DEBUG(1, "update record(sn:%ld)\n", ctx->sn);
1201 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1202
1203 start_param = &ctx->record.param_update;
1204 memset(start_param, 0, sizeof(*start_param));
1205 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
1206 start_param->segment.segment_id = ctx->record.next_segment_id++;
1207 start_param->segment.nb_pids = params->nb_pids;
1208 for (i = 0; i < params->nb_pids; i++) {
1209 start_param->segment.pids[i] = params->pids[i];
1210 start_param->segment.pid_action[i] = params->pid_action[i];
1211 }
1212 error = dvr_record_next_segment(ctx->record.recorder, start_param, &seg_info);
1213 {
1214 DVR_RecordSegmentInfo_t new_seg_info =
1215 { .id = start_param->segment.segment_id, };
1216 wrapper_updateRecordSegment(ctx, &seg_info, U_PIDS);
1217 wrapper_addRecordSegment(ctx, &new_seg_info);
1218 }
1219
1220 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) updated = (%d)\n", ctx->sn, error);
1221 pthread_mutex_unlock(&ctx->lock);
1222
1223 return error;
1224}
1225
1226int dvr_wrapper_get_record_status(DVR_WrapperRecord_t rec, DVR_WrapperRecordStatus_t *status)
1227{
1228 DVR_WrapperCtx_t *ctx;
1229 DVR_WrapperRecordStatus_t s;
1230 int error;
1231
1232 DVR_RETURN_IF_FALSE(rec);
1233 DVR_RETURN_IF_FALSE(status);
1234
1235 ctx = ctx_getRecord((unsigned long)rec);
1236 DVR_RETURN_IF_FALSE(ctx);
1237
1238 pthread_mutex_lock(&ctx->lock);
1239
1240 DVR_WRAPPER_DEBUG(1, "get record(sn:%ld) status ...\n", ctx->sn);
1241 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1242
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001243 error = process_generateRecordStatus(ctx, &s);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001244
1245 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) state/time/size/pkts(%d/%ld/%lld/%u) (%d)\n",
1246 ctx->sn,
1247 s.state,
1248 s.info.time,
1249 s.info.size,
1250 s.info.pkts,
1251 error);
1252
1253 *status = s;
1254
1255 pthread_mutex_unlock(&ctx->lock);
1256
1257 return error;
1258}
1259
hualing chen4fe3bee2020-10-23 13:58:52 +08001260int dvr_wrapper_record_is_secure_mode(DVR_WrapperRecord_t rec)
1261{
1262 DVR_WrapperCtx_t *ctx;
1263 int error;
1264
1265 DVR_RETURN_IF_FALSE(rec);
1266
1267 ctx = ctx_getRecord((unsigned long)rec);
1268 DVR_RETURN_IF_FALSE(ctx);
1269
1270 pthread_mutex_lock(&ctx->lock);
1271 error = dvr_record_is_secure_mode(ctx->record.recorder);
1272 pthread_mutex_unlock(&ctx->lock);
1273 return error;
1274}
1275
hualing chen266b9502020-04-04 17:39:39 +08001276int dvr_wrapper_set_record_secure_buffer (DVR_WrapperRecord_t rec, uint8_t *p_secure_buf, uint32_t len)
1277{
1278 DVR_WrapperCtx_t *ctx;
1279 int error;
1280
1281 DVR_RETURN_IF_FALSE(rec);
1282 DVR_RETURN_IF_FALSE(p_secure_buf);
1283
1284 ctx = ctx_getRecord((unsigned long)rec);
1285 DVR_RETURN_IF_FALSE(ctx);
1286
1287 pthread_mutex_lock(&ctx->lock);
1288 error = dvr_record_set_secure_buffer(ctx->record.recorder, p_secure_buf, len);
1289 pthread_mutex_unlock(&ctx->lock);
1290 return error;
1291}
1292
1293int dvr_wrapper_set_record_decrypt_callback (DVR_WrapperRecord_t rec, DVR_CryptoFunction_t func, void *userdata)
1294{
1295 DVR_WrapperCtx_t *ctx;
1296 int error;
1297
1298 DVR_RETURN_IF_FALSE(rec);
1299 DVR_RETURN_IF_FALSE(func);
1300
1301 ctx = ctx_getRecord((unsigned long)rec);
1302 DVR_RETURN_IF_FALSE(ctx);
1303
1304 pthread_mutex_lock(&ctx->lock);
1305 error = dvr_record_set_encrypt_callback(ctx->record.recorder, func, userdata);
1306 pthread_mutex_unlock(&ctx->lock);
1307 return error;
1308}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001309
1310
1311int dvr_wrapper_open_playback (DVR_WrapperPlayback_t *playback, DVR_WrapperPlaybackOpenParams_t *params)
1312{
1313 DVR_WrapperCtx_t *ctx;
1314 DVR_PlaybackOpenParams_t open_param;
1315 int error;
1316
1317 DVR_RETURN_IF_FALSE(playback);
1318 DVR_RETURN_IF_FALSE(params);
1319 DVR_RETURN_IF_FALSE(params->playback_handle);
1320
1321 /*get a free ctx*/
1322 ctx = ctx_getPlayback(0);
1323 DVR_RETURN_IF_FALSE(ctx);
1324
1325 pthread_mutex_lock(&ctx->lock);
1326
hualing chen90b3ae62021-03-30 10:49:28 +08001327 DVR_WRAPPER_DEBUG(1, "open playback(dmx:%d) ..vendor[%d].\n", params->dmx_dev_id, params->vendor);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001328
1329 ctx_reset(ctx);
1330
1331 ctx->playback.param_open = *params;
1332 ctx->playback.event_fn = params->event_fn;
1333 ctx->playback.event_userdata = params->event_userdata;
1334 ctx->current_segment_id = 0;
1335 INIT_LIST_HEAD(&ctx->segments);
1336 ctx->sn = get_sn();
1337
1338 wrapper_requestThreadFor(ctx);
1339
hualing chen266b9502020-04-04 17:39:39 +08001340 memset(&open_param, 0, sizeof(DVR_PlaybackOpenParams_t));
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001341 open_param.dmx_dev_id = params->dmx_dev_id;
1342 open_param.block_size = params->block_size;
1343 open_param.is_timeshift = params->is_timeshift;
1344 //open_param.notification_size = 10*1024; //not supported
1345 open_param.event_fn = wrapper_playback_event_handler;
1346 open_param.event_userdata = (void*)ctx->sn;
1347 /*open_param.has_pids = 0;*/
hualing chene3797f02021-01-13 14:53:28 +08001348 open_param.is_notify_time = params->is_notify_time;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001349 open_param.player_handle = (am_tsplayer_handle)params->playback_handle;
hualing chen90b3ae62021-03-30 10:49:28 +08001350 open_param.vendor = params->vendor;
1351
Yahui Han1fbf3292021-11-08 18:17:19 +08001352 if (params->keylen) {
1353 open_param.clearkey = params->clearkey;
1354 open_param.cleariv = params->cleariv;
1355 open_param.keylen = params->keylen;
1356 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001357
1358 error = dvr_playback_open(&ctx->playback.player, &open_param);
1359 if (error) {
1360 DVR_WRAPPER_DEBUG(1, "playback(dmx:%d) openned fail(error:%d).\n", params->dmx_dev_id, error);
1361 ctx_reset(ctx);
1362 pthread_mutex_unlock(&ctx->lock);
1363 wrapper_releaseThreadForType(ctx->type);
1364 return DVR_FAILURE;
1365 }
1366 if (params->is_timeshift)
1367 sn_timeshift_playback = ctx->sn;
1368
hualing chen266b9502020-04-04 17:39:39 +08001369 DVR_WRAPPER_DEBUG(1, "hanyh: playback(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
1370 error = dvr_playback_set_decrypt_callback(ctx->playback.player, params->crypto_fn, params->crypto_data);
1371 if (error) {
1372 DVR_WRAPPER_DEBUG(1, "playback set deccrypt callback fail(error:%d).\n", error);
1373 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001374 pthread_mutex_unlock(&ctx->lock);
1375
1376 *playback = (DVR_WrapperPlayback_t)ctx->sn;
1377 return DVR_SUCCESS;
1378}
1379
1380int dvr_wrapper_close_playback (DVR_WrapperPlayback_t playback)
1381{
1382 DVR_WrapperCtx_t *ctx;
1383 int error;
1384
1385 DVR_RETURN_IF_FALSE(playback);
1386
1387 ctx = ctx_getPlayback((unsigned long)playback);
1388 DVR_RETURN_IF_FALSE(ctx);
1389
1390 pthread_mutex_lock(&ctx->lock);
1391 DVR_WRAPPER_DEBUG(1, "close playback(sn:%ld)\n", ctx->sn);
1392 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1393
1394 if (ctx->playback.param_open.is_timeshift)
1395 sn_timeshift_playback = 0;
1396
1397 /*try stop first*/
1398 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1399
1400 {
1401 /*remove all segments*/
1402 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1403
1404 list_for_each_entry(pseg, &ctx->segments, head) {
1405 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1406 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1407 ctx->sn, pseg->playback_info.segment_id, error);
1408 }
1409 ctx_freeSegments(ctx);
1410 }
1411
1412 error = dvr_playback_close(ctx->playback.player);
1413
1414 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) closed.\n", ctx->sn);
1415 ctx_reset(ctx);
1416 pthread_mutex_unlock(&ctx->lock);
1417
1418 wrapper_releaseThreadForType(ctx->type);
1419
1420 return error;
1421}
1422
1423int dvr_wrapper_start_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackFlag_t flags, DVR_PlaybackPids_t *p_pids)
1424{
1425 DVR_WrapperCtx_t *ctx;
1426 int error;
1427 uint64_t *p_segment_ids;
1428 uint32_t segment_nb;
1429 uint32_t i;
1430 DVR_RecordSegmentInfo_t seg_info_1st;
1431 int got_1st_seg;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001432 DVR_WrapperCtx_t *ctx_record;/*for timeshift*/
hualing chenc110f952021-01-18 11:25:37 +08001433 DVR_Bool_t is_timeshift = DVR_FALSE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001434
1435 DVR_RETURN_IF_FALSE(playback);
1436 DVR_RETURN_IF_FALSE(p_pids);
1437
hualing chenc110f952021-01-18 11:25:37 +08001438 ctx_record = NULL;
1439
1440 /*lock the recorder to avoid changing the recording segments*/
1441 ctx_record = ctx_getRecord(sn_timeshift_record);
1442
1443 if (ctx_record) {
1444 pthread_mutex_lock(&ctx_record->lock);
1445 if (!ctx_valid(ctx_record)
1446 || ctx_record->sn != sn_timeshift_record) {
1447 DVR_WRAPPER_DEBUG(1, "timeshift, record is not for timeshifting, FATAL error found\n");
1448 pthread_mutex_unlock(&ctx_record->lock);
1449 is_timeshift = DVR_FALSE;
1450 } else {
1451 is_timeshift = DVR_TRUE;
1452 }
1453 }
1454
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001455 ctx = ctx_getPlayback((unsigned long)playback);
1456 DVR_RETURN_IF_FALSE(ctx);
1457
1458 pthread_mutex_lock(&ctx->lock);
1459
1460 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",
1461 ctx->sn,
1462 ctx->playback.param_open.location,
1463 flags,
1464 p_pids->video.pid, p_pids->video.format,
1465 p_pids->audio.pid, p_pids->audio.format,
1466 p_pids->ad.pid, p_pids->ad.format,
1467 p_pids->subtitle.pid, p_pids->subtitle.format,
1468 p_pids->pcr.pid);
1469
1470 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1471
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001472 if (ctx->playback.param_open.is_timeshift) {
1473 /*lock the recorder to avoid changing the recording segments*/
hualing chenc110f952021-01-18 11:25:37 +08001474 if (is_timeshift == DVR_FALSE) {
1475 DVR_WRAPPER_DEBUG(1, "timeshift, record is not for timeshifting, FATAL error return\n");
1476 pthread_mutex_unlock(&ctx->lock);
1477 return DVR_FAILURE;
1478 } else {
1479 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) record(sn:%ld) locked ok due to timeshift\n",
1480 ctx->sn, ctx_record->sn);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001481 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001482 }
1483
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001484 /*obtain all segments in a list*/
1485 segment_nb = 0;
1486 p_segment_ids = NULL;
1487 error = dvr_segment_get_list(ctx->playback.param_open.location, &segment_nb, &p_segment_ids);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001488 if (!error) {
1489 got_1st_seg = 0;
hualing chenb9b358a2021-08-17 15:06:36 +08001490 DVR_WRAPPER_DEBUG(1, "get list segment_nb::%d",segment_nb);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001491 for (i = 0; i < segment_nb; i++) {
1492 DVR_RecordSegmentInfo_t seg_info;
1493 DVR_PlaybackSegmentFlag_t flags;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001494
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001495 error = dvr_segment_get_info(ctx->playback.param_open.location, p_segment_ids[i], &seg_info);
1496 if (error) {
1497 error = DVR_FAILURE;
1498 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
1499 ctx->playback.param_open.location, p_segment_ids[i], error);
1500 break;
1501 }
hualing chen92f3a142020-07-08 20:59:33 +08001502 //add check if has audio or video pid. if not exist. not add segment to playback
1503 int ii = 0;
1504 int has_av = 0;
1505 for (ii = 0; ii < seg_info.nb_pids; ii++) {
1506 int type = (seg_info.pids[ii].type >> 24) & 0x0f;
1507 if (type == DVR_STREAM_TYPE_VIDEO ||
1508 type == DVR_STREAM_TYPE_AUDIO ||
1509 type == DVR_STREAM_TYPE_AD) {
1510 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1511 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,
1512 DVR_STREAM_TYPE_VIDEO,
1513 DVR_STREAM_TYPE_AUDIO,
1514 DVR_STREAM_TYPE_AD);
1515 has_av = 1;
1516 //break;
1517 } else {
1518 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,
1519 DVR_STREAM_TYPE_VIDEO,
1520 DVR_STREAM_TYPE_AUDIO,
1521 DVR_STREAM_TYPE_AD);
1522 }
1523 }
1524 if (has_av == 0) {
1525 DVR_WRAPPER_DEBUG(1, "fail to get seg av info \n");
1526 continue;
1527 } else {
1528 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1529 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001530 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1531 error = wrapper_addPlaybackSegment(ctx, &seg_info, p_pids, flags);
1532 if (error)
1533 break;
1534
1535 /*copy the 1st segment*/
1536 if (got_1st_seg == 0) {
1537 seg_info_1st = seg_info;
1538 got_1st_seg = 1;
1539 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001540 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001541 free(p_segment_ids);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001542
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001543 /* return if no segment or fail to add */
1544 if (!error && got_1st_seg) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001545
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001546 /*copy the obsolete infomation, must for timeshifting*/
1547 if (ctx->playback.param_open.is_timeshift && ctx_record) {
1548 ctx->playback.obsolete = ctx_record->record.obsolete;
1549 }
1550
1551 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) (%d) segments added\n", ctx->sn, i);
1552
1553 ctx->playback.reach_end = DVR_FALSE;
1554 if ((flags&DVR_PLAYBACK_STARTED_PAUSEDLIVE) == DVR_PLAYBACK_STARTED_PAUSEDLIVE)
1555 ctx->playback.speed = 0.0f;
1556 else
1557 ctx->playback.speed = 100.0f;
1558
1559 ctx->playback.pids_req = *p_pids;
hualing chen03fd4942021-07-15 15:56:41 +08001560 //calualte segment id and pos
1561 if (dvr_playback_check_limit(ctx->playback.player)) {
1562 pthread_mutex_unlock(&ctx->lock);
1563 dvr_wrapper_seek_playback(playback, 0);
1564 pthread_mutex_lock(&ctx->lock);
1565 error = dvr_playback_start(ctx->playback.player, flags);
1566 } else {
1567 error = dvr_playback_seek(ctx->playback.player, seg_info_1st.id, 0);
1568 error = dvr_playback_start(ctx->playback.player, flags);
1569 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seek(seg:%llu 0) for start (%d)\n",
1570 ctx->sn, seg_info_1st.id, error);
1571 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001572 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) started (%d)\n", ctx->sn, error);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001573 }
1574 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001575
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001576 if (ctx->playback.param_open.is_timeshift) {
1577 /*unlock the recorder locked above*/
1578 if (ctx_record && ctx_valid(ctx_record)) {
1579 pthread_mutex_unlock(&ctx_record->lock);
1580 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld), record(sn:%ld) unlocked ok due to timeshift\n",
1581 ctx->sn, ctx_record->sn);
1582 }
1583 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001584 pthread_mutex_unlock(&ctx->lock);
1585
1586 return error;
1587}
1588
1589int dvr_wrapper_stop_playback (DVR_WrapperPlayback_t playback)
1590{
1591 DVR_WrapperCtx_t *ctx;
1592 int error;
1593
1594 DVR_RETURN_IF_FALSE(playback);
1595
1596 ctx = ctx_getPlayback((unsigned long)playback);
1597 DVR_RETURN_IF_FALSE(ctx);
1598
1599 pthread_mutex_lock(&ctx->lock);
1600 DVR_WRAPPER_DEBUG(1, "stop playback(sn:%ld) ...\n", ctx->sn);
1601 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1602
1603 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1604
1605 {
1606 /*remove all segments*/
1607 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1608
1609 list_for_each_entry(pseg, &ctx->segments, head) {
1610 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1611 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1612 ctx->sn, pseg->playback_info.segment_id, error);
1613 }
1614 ctx_freeSegments(ctx);
1615 }
1616
1617 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) stopped (%d)\n", ctx->sn, error);
1618 pthread_mutex_unlock(&ctx->lock);
1619
1620 return error;
1621}
1622
1623int dvr_wrapper_pause_playback (DVR_WrapperPlayback_t playback)
1624{
1625 DVR_WrapperCtx_t *ctx;
1626 int error;
1627
1628 DVR_RETURN_IF_FALSE(playback);
1629
1630 ctx = ctx_getPlayback((unsigned long)playback);
1631 DVR_RETURN_IF_FALSE(ctx);
1632
1633 pthread_mutex_lock(&ctx->lock);
1634 DVR_WRAPPER_DEBUG(1, "pause playback(sn:%ld) ...\n", ctx->sn);
1635 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
hualing chen36e0dfd2020-05-02 16:33:06 +08001636 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +08001637 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +08001638 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001639
1640 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
1641
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001642 ctx->playback.speed = 0.0f;
1643
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001644 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) paused (%d)\n", ctx->sn, error);
1645 pthread_mutex_unlock(&ctx->lock);
1646
1647 return error;
1648}
1649
1650int dvr_wrapper_resume_playback (DVR_WrapperPlayback_t playback)
1651{
1652 DVR_WrapperCtx_t *ctx;
1653 int error;
1654
1655 DVR_RETURN_IF_FALSE(playback);
1656
1657 ctx = ctx_getPlayback((unsigned long)playback);
1658 DVR_RETURN_IF_FALSE(ctx);
hualing chen03fd4942021-07-15 15:56:41 +08001659 //if set limit.we need check if seek to valid data when resume
1660 uint32_t time_offset = ctx->playback.status.info_cur.time + ctx->playback.status.info_obsolete.time;
1661 if (dvr_playback_check_limit(ctx->playback.player)) {
1662 int expired = dvr_playback_calculate_expiredlen(ctx->playback.player);
1663 if (expired > time_offset) {
1664 DVR_WRAPPER_DEBUG(1, "seek before resume reset offset playback(sn:%ld) (off:%d expired:%d)\n",
1665 ctx->sn, time_offset, expired);
1666 time_offset = expired;
1667 dvr_wrapper_seek_playback(playback, time_offset);
1668 }
1669 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001670 pthread_mutex_lock(&ctx->lock);
1671 DVR_WRAPPER_DEBUG(1, "resume playback(sn:%ld) ...\n", ctx->sn);
1672 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1673
1674 error = dvr_playback_resume(ctx->playback.player);
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001675 ctx->playback.speed = 100.0f;
1676
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001677 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) resumed (%d)\n", ctx->sn, error);
1678 pthread_mutex_unlock(&ctx->lock);
1679
1680 return error;
1681}
1682
1683int dvr_wrapper_set_playback_speed (DVR_WrapperPlayback_t playback, float speed)
1684{
1685 DVR_WrapperCtx_t *ctx;
1686 int error;
1687 DVR_PlaybackSpeed_t dvr_speed = {
1688 .speed = { speed },
1689 .mode = (speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
1690 };
1691
1692 DVR_RETURN_IF_FALSE(playback);
1693
1694 ctx = ctx_getPlayback((unsigned long)playback);
1695 DVR_RETURN_IF_FALSE(ctx);
1696
1697 pthread_mutex_lock(&ctx->lock);
hualing chenc70a8df2020-05-12 19:23:11 +08001698 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 +08001699 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1700
1701 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
1702
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001703 if (ctx->playback.speed != 0.0f && ctx->playback.speed != 100.0f
1704 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_BEGIN
1705 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
1706 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, paused, do resume first\n", ctx->playback.speed, speed);
1707 error = dvr_playback_resume(ctx->playback.player);
1708 } else if (ctx->playback.speed == 0.0f
1709 && speed != 0.0f
1710 && speed != 100.0f) {
1711 /*libdvr do not support pause with speed=0, will not be here*/
1712 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, do resume first\n", ctx->playback.speed, speed);
1713 error = dvr_playback_resume(ctx->playback.player);
1714 }
1715
1716 ctx->playback.speed = speed;
1717
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001718 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) speeded(x%f) (%d)\n",
1719 ctx->sn, speed, error);
1720 pthread_mutex_unlock(&ctx->lock);
1721
1722 return error;
1723}
1724
hualing chen03fd4942021-07-15 15:56:41 +08001725int dvr_wrapper_setlimit_playback (DVR_WrapperPlayback_t playback, uint64_t time, int32_t limit)
1726{
1727 DVR_WrapperCtx_t *ctx;
1728 int error;
1729
1730 DVR_RETURN_IF_FALSE(playback);
1731
1732 ctx = ctx_getPlayback((unsigned long)playback);
1733 DVR_RETURN_IF_FALSE(ctx);
1734
1735 pthread_mutex_lock(&ctx->lock);
1736
1737 DVR_WRAPPER_DEBUG(1, "setlimit playback(sn:%ld) (time:%lld limit:%d) ...\n", ctx->sn, time, limit);
1738 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1739
1740 error = dvr_playback_setlimit(ctx->playback.player, time, limit);
1741 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) setlimit(time:%lld limit:%d) ...\n", ctx->sn, time, limit);
1742
1743 pthread_mutex_unlock(&ctx->lock);
1744
1745 return error;
1746}
1747
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001748int dvr_wrapper_seek_playback (DVR_WrapperPlayback_t playback, uint32_t time_offset)
1749{
1750 DVR_WrapperCtx_t *ctx;
1751 int error;
1752 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1753 uint64_t segment_id;
1754 uint32_t off;
1755 uint64_t last_segment_id;
1756 uint32_t pre_off;
1757
1758 DVR_RETURN_IF_FALSE(playback);
1759
1760 ctx = ctx_getPlayback((unsigned long)playback);
1761 DVR_RETURN_IF_FALSE(ctx);
1762
1763 pthread_mutex_lock(&ctx->lock);
1764
1765 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (off:%d) ...\n", ctx->sn, time_offset);
1766 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1767
1768 off = 0;
1769 segment_id = 0;
1770 pre_off = 0;
1771 last_segment_id = 0;
1772
hualing chen03fd4942021-07-15 15:56:41 +08001773 //if set limit info we need check ts data is
1774 //expired when seek
1775 if (dvr_playback_check_limit(ctx->playback.player)) {
1776 int expired = dvr_playback_calculate_expiredlen(ctx->playback.player);
1777 if (expired > time_offset) {
1778 DVR_WRAPPER_DEBUG(1, "seek reset offset playback(sn:%ld) (off:%d expired:%d)\n",
1779 ctx->sn, time_offset, expired);
1780 time_offset = expired;
1781 }
1782 }
1783
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001784 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1785 segment_id = pseg->seg_info.id;
1786
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001787 if ((ctx->playback.obsolete.time + pre_off + pseg->seg_info.duration) > time_offset)
1788 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001789
1790 last_segment_id = pseg->seg_info.id;
1791 pre_off += pseg->seg_info.duration;
1792 }
1793
1794 if (last_segment_id == segment_id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001795 /*1.only one seg with id:0, 2.offset exceeds the total duration*/
1796 off = time_offset;
1797 } else if (ctx->playback.obsolete.time >= time_offset) {
1798 off = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001799 } else {
hualing chenda76fc52020-05-28 14:56:42 +08001800 off = time_offset - pre_off - ctx->playback.obsolete.time;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001801 }
1802
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001803 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (seg:%lld, off:%d)\n",
1804 ctx->sn, segment_id, off);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001805 error = dvr_playback_seek(ctx->playback.player, segment_id, off);
1806 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seeked(off:%d) (%d)\n", ctx->sn, time_offset, error);
1807
1808 pthread_mutex_unlock(&ctx->lock);
1809
1810 return error;
1811}
1812
1813int dvr_wrapper_update_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackPids_t *p_pids)
1814{
1815 DVR_WrapperCtx_t *ctx;
1816 int error;
1817 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1818
1819 DVR_RETURN_IF_FALSE(playback);
1820 DVR_RETURN_IF_FALSE(p_pids);
1821
1822 ctx = ctx_getPlayback((unsigned long)playback);
1823 DVR_RETURN_IF_FALSE(ctx);
1824
1825 pthread_mutex_lock(&ctx->lock);
1826
1827 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) ...\n",
1828 ctx->sn,
1829 p_pids->video.pid, p_pids->video.format,
1830 p_pids->audio.pid, p_pids->audio.format);
1831 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1832
1833 ctx->playback.pids_req = *p_pids;
1834
1835 error = 0;
1836 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1837 /*should update the whole list of segments*/
1838 /*if (pseg->seg_info.id == ctx->current_segment_id)*/ {
1839 /*list_for_each_entry_from(pseg, &ctx->segments, head)*/ {
1840 /*check udpate for pids*/
1841 if (memcmp(&pseg->playback_info.pids, p_pids, sizeof(*p_pids)) != 0) {
1842 pseg->playback_info.pids = *p_pids;
1843 error = dvr_playback_update_segment_pids(ctx->playback.player, pseg->seg_info.id, p_pids);
1844 if (error) {
1845 DVR_WRAPPER_DEBUG(1, "failed to playback(sn:%ld) update segment(id:%lld) pids (%d)\n",
1846 ctx->sn, pseg->seg_info.id, error);
1847 /*do not break, let list updated*/
1848 }
1849 }
1850 }
1851 /*break;*/
1852 }
1853 }
1854
1855 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) (%d)\n",
1856 ctx->sn,
1857 p_pids->video.pid, p_pids->video.format,
1858 p_pids->audio.pid, p_pids->audio.format,
1859 error);
1860
1861 pthread_mutex_unlock(&ctx->lock);
1862
1863 return error;
1864}
1865
1866int dvr_wrapper_get_playback_status(DVR_WrapperPlayback_t playback, DVR_WrapperPlaybackStatus_t *status)
1867{
1868 DVR_WrapperCtx_t *ctx;
1869 DVR_WrapperPlaybackStatus_t s;
1870 DVR_PlaybackStatus_t play_status;
1871 int error;
1872
1873 DVR_RETURN_IF_FALSE(playback);
1874 DVR_RETURN_IF_FALSE(status);
1875
1876 ctx = ctx_getPlayback((unsigned long)playback);
1877 DVR_RETURN_IF_FALSE(ctx);
1878
1879 pthread_mutex_lock(&ctx->lock);
1880
1881 DVR_WRAPPER_DEBUG(1, "get playback(sn:%ld) status ...\n", ctx->sn);
1882 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1883
1884 error = dvr_playback_get_status(ctx->playback.player, &play_status);
1885 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) get status (%d)\n", ctx->sn, error);
1886
1887 ctx->playback.seg_status = play_status;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001888 error = process_generatePlaybackStatus(ctx, &s);
1889
hualing chenb5cd42e2020-04-15 17:03:34 +08001890 if (ctx->playback.reach_end == DVR_TRUE && ctx->playback.param_open.is_timeshift == DVR_FALSE) {
1891 //reach end need set full time to cur.so app can exist playback.
1892 DVR_WRAPPER_DEBUG(1, "set cur time to full time, reach end occur");
1893 s.info_cur.time = s.info_full.time;
1894 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001895 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) state/cur/full/obsl(%d/%ld/%ld/%ld) (%d)\n",
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001896 ctx->sn,
1897 s.state,
1898 s.info_cur.time,
1899 s.info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001900 s.info_obsolete.time,
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001901 error);
1902
1903 *status = s;
1904
1905 pthread_mutex_unlock(&ctx->lock);
1906
1907 return error;
1908}
1909
hualing chen266b9502020-04-04 17:39:39 +08001910int dvr_wrapper_set_playback_secure_buffer (DVR_WrapperPlayback_t playback, uint8_t *p_secure_buf, uint32_t len)
1911{
1912 DVR_WrapperCtx_t *ctx;
1913 int error;
1914
1915 DVR_RETURN_IF_FALSE(playback);
1916 DVR_RETURN_IF_FALSE(p_secure_buf);
1917
1918 ctx = ctx_getPlayback((unsigned long)playback);
1919 DVR_RETURN_IF_FALSE(ctx);
1920
1921 pthread_mutex_lock(&ctx->lock);
1922 error = dvr_playback_set_secure_buffer(ctx->playback.player, p_secure_buf, len);
1923 pthread_mutex_unlock(&ctx->lock);
1924 return error;
1925}
1926
1927int dvr_wrapper_set_playback_decrypt_callback (DVR_WrapperPlayback_t playback, DVR_CryptoFunction_t func, void *userdata)
1928{
1929 DVR_WrapperCtx_t *ctx;
1930 int error;
1931
1932 DVR_RETURN_IF_FALSE(playback);
1933 DVR_RETURN_IF_FALSE(func);
1934
1935 ctx = ctx_getPlayback((unsigned long)playback);
1936 DVR_RETURN_IF_FALSE(ctx);
1937
1938 pthread_mutex_lock(&ctx->lock);
1939 error = dvr_playback_set_decrypt_callback(ctx->playback.player, func, userdata);
1940 pthread_mutex_unlock(&ctx->lock);
1941 return error;
1942}
1943
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001944static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata)
1945{
1946 DVR_WrapperEventCtx_t evt;
1947
1948 DVR_RETURN_IF_FALSE(userdata);
1949
1950 evt.sn = (unsigned long)userdata;
1951 evt.type = W_REC;
1952 evt.record.event = event;
1953 evt.record.status = *(DVR_RecordStatus_t *)params;
1954 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, record, evt:0x%x]\n", evt.sn, evt.record.event);
1955 return ctx_addRecordEvent(&evt);
1956}
1957
1958static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata)
1959{
1960 DVR_WrapperEventCtx_t evt;
1961
1962 DVR_RETURN_IF_FALSE(userdata);
1963
1964 evt.sn = (unsigned long)userdata;
1965 evt.type = W_PLAYBACK;
1966 evt.playback.event = event;
1967 evt.playback.status = *(DVR_Play_Notify_t *)params;
1968 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, playbck, evt:0x%x]\n", evt.sn, evt.playback.event);
1969 return ctx_addPlaybackEvent(&evt);
1970}
1971
1972static inline int process_notifyRecord(DVR_WrapperCtx_t *ctx, DVR_RecordEvent_t evt, DVR_WrapperRecordStatus_t *status)
1973{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001974 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 +08001975 ctx->sn,
1976 evt,
1977 status->info.time,
1978 status->info.size,
1979 status->info.pkts,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001980 status->info_obsolete.time,
1981 status->info_obsolete.size,
1982 status->info_obsolete.pkts);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001983
1984 if (ctx->record.event_fn)
1985 return ctx->record.event_fn(evt, status, ctx->record.event_userdata);
1986 return 0;
1987}
1988
1989static inline int record_startNextSegment(DVR_WrapperCtx_t *ctx)
1990{
1991 DVR_RecordStartParams_t param;
1992 DVR_RecordSegmentInfo_t seg_info;
1993 int i;
1994 int error;
1995
1996 memcpy(&param, &ctx->record.param_update, sizeof(param));
1997 memset(&ctx->record.param_update.segment, 0, sizeof(ctx->record.param_update.segment));
1998 ctx->record.param_update.segment.segment_id = ctx->record.next_segment_id++;
1999 for (i = 0; i < param.segment.nb_pids; i++) {
2000 if (param.segment.pid_action[i] != DVR_RECORD_PID_CLOSE) {
2001 ctx->record.param_update.segment.pids[ctx->record.param_update.segment.nb_pids] = param.segment.pids[i];
2002 ctx->record.param_update.segment.pid_action[ctx->record.param_update.segment.nb_pids] = DVR_RECORD_PID_KEEP;
2003 ctx->record.param_update.segment.nb_pids++;
2004 }
2005 }
2006 error = dvr_record_next_segment(ctx->record.recorder, &ctx->record.param_update, &seg_info);
2007 {
2008 DVR_RecordSegmentInfo_t new_seg_info =
2009 { .id = ctx->record.param_update.segment.segment_id, };
2010 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
2011 wrapper_addRecordSegment(ctx, &new_seg_info);
2012 }
2013
Zhiqiang Hand977e972020-05-11 11:30:47 +08002014 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 +08002015 return error;
2016}
2017
2018static inline int record_removeSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *pseg)
2019{
2020 return wrapper_removeRecordSegment(ctx, pseg);
2021}
2022
2023/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002024static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002025{
2026 /*the current seg is not covered in the statistics*/
2027 DVR_WrapperRecordSegmentInfo_t *pseg;
2028
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002029 /*re-calculate the all segments*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002030 memset(&ctx->record.status, 0, sizeof(ctx->record.status));
2031
2032 ctx->record.status.state = ctx->record.seg_status.state;
2033 ctx->record.status.pids.nb_pids = ctx->record.seg_status.info.nb_pids;
2034 memcpy(ctx->record.status.pids.pids,
2035 ctx->record.seg_status.info.pids,
2036 sizeof(ctx->record.status.pids.pids));
2037 ctx->current_segment_id = ctx->record.seg_status.info.id;
2038
2039 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2040 if (pseg->info.id != ctx->record.seg_status.info.id) {
2041 ctx->record.status.info.time += pseg->info.duration;
2042 ctx->record.status.info.size += pseg->info.size;
2043 ctx->record.status.info.pkts += pseg->info.nb_packets;
2044 }
2045 }
2046
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002047 ctx->record.status.info_obsolete = ctx->record.obsolete;
2048
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002049 wrapper_updateRecordSegment(ctx, &ctx->record.seg_status.info, U_ALL);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002050
2051 if (status) {
2052 *status = ctx->record.status;
2053 status->info.time += ctx->record.seg_status.info.duration;
2054 status->info.size += ctx->record.seg_status.info.size;
2055 status->info.pkts += ctx->record.seg_status.info.nb_packets;
2056 }
2057
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002058 return DVR_SUCCESS;
2059}
2060
2061
2062static int process_handleRecordEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2063{
2064 DVR_WrapperRecordStatus_t status;
2065
2066 memset(&status, 0, sizeof(status));
2067
2068 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d)\n",
2069 evt->sn, evt->record.event, evt->record.status.state);
hualing chend3b55ab2021-05-06 09:56:27 +08002070 if (ctx->record.param_update.segment.segment_id != evt->record.status.info.id) {
2071 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) cur id:0x%x (event id:%d)\n",
Gong Ke2a0ebbe2021-05-25 15:22:50 +08002072 evt->sn, (int)ctx->record.param_update.segment.segment_id, (int)evt->record.status.info.id);
hualing chend3b55ab2021-05-06 09:56:27 +08002073 return 0;
2074 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002075 switch (evt->record.event)
2076 {
2077 case DVR_RECORD_EVENT_STATUS:
2078 {
2079 switch (evt->record.status.state)
2080 {
2081 case DVR_RECORD_STATE_OPENED:
2082 case DVR_RECORD_STATE_CLOSED:
2083 {
2084 ctx->record.seg_status = evt->record.status;
2085
2086 status.state = evt->record.status.state;
2087 process_notifyRecord(ctx, evt->record.event, &status);
2088 } break;
2089 case DVR_RECORD_STATE_STARTED:
2090 {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002091 ctx->record.seg_status = evt->record.status;
2092
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002093 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002094 process_notifyRecord(ctx, evt->record.event, &status);
2095
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002096 /*restart to next segment*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002097 if (ctx->record.param_open.segment_size
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002098 && evt->record.status.info.size >= ctx->record.param_open.segment_size) {
2099 DVR_WRAPPER_DEBUG(1, "start new segment for record(%lu), reaches segment size limit, cur(%zu) max(%lld)\n",
2100 ctx->sn,
2101 evt->record.status.info.size,
2102 ctx->record.param_open.segment_size);
Zhiqiang Hand977e972020-05-11 11:30:47 +08002103 if (record_startNextSegment(ctx) != DVR_SUCCESS) {
2104 /*should notify the recording's stop*/
2105 int error = dvr_record_close(ctx->record.recorder);
2106 DVR_WRAPPER_DEBUG(1, "stop record(%lu)=%d, failed to start new segment for recording.",
2107 ctx->sn, error);
2108 status.state = DVR_RECORD_STATE_CLOSED;
2109 process_notifyRecord(ctx, DVR_RECORD_EVENT_WRITE_ERROR, &status);
2110 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002111 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002112
2113 if (ctx->record.param_open.is_timeshift
2114 && ctx->record.param_open.max_time
2115 && status.info.time >= ctx->record.param_open.max_time) {
2116 DVR_WrapperRecordSegmentInfo_t *pseg;
2117
2118 /*as the player do not support null playlist,
2119 there must be one segment existed at any time,
2120 we have to keep two segments before remove one*/
2121 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
2122 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
2123 /*only one segment, waiting for more*/
2124 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of max_time(%ld) of record < max size of segment(%lld)\n",
2125 status.info.size,
2126 ctx->record.param_open.max_time,
2127 ctx->record.param_open.segment_size);
2128 } else {
2129 /*timeshifting, remove the 1st segment and notify the player*/
2130 record_removeSegment(ctx, pseg);
2131
2132 process_generateRecordStatus(ctx, &status);
2133 process_notifyRecord(ctx, evt->record.event, &status);
2134 }
2135 }
2136
2137 if (ctx->record.param_open.is_timeshift
2138 && ctx->record.param_open.max_size
2139 && status.info.size >= ctx->record.param_open.max_size) {
2140 DVR_WrapperRecordSegmentInfo_t *pseg;
2141
2142 /*as the player do not support null playlist,
2143 there must be one segment existed at any time,
2144 we have to keep two segments before remove one*/
2145 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
2146 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
2147 /*only one segment, waiting for more*/
2148 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of record < max size of segment(%lld)\n",
2149 status.info.size,
2150 ctx->record.param_open.segment_size);
2151 } else {
2152 record_removeSegment(ctx, pseg);
2153
2154 process_generateRecordStatus(ctx, &status);
2155 process_notifyRecord(ctx, evt->record.event, &status);
2156 }
2157 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002158 } break;
2159 case DVR_RECORD_STATE_STOPPED:
2160 {
2161 ctx->record.seg_status = evt->record.status;
2162
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002163 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002164 process_notifyRecord(ctx, evt->record.event, &status);
2165 } break;
2166 default:
2167 break;
2168 }
2169 } break;
hualing chen4b7c15d2020-04-07 16:13:48 +08002170 case DVR_RECORD_EVENT_WRITE_ERROR: {
2171 ctx->record.seg_status = evt->record.status;
2172 status.state = evt->record.status.state;
2173 process_notifyRecord(ctx, evt->record.event, &status);
2174 }break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002175 default:
2176 break;
2177 }
2178 return DVR_SUCCESS;
2179}
2180
2181static inline int process_notifyPlayback(DVR_WrapperCtx_t *ctx, DVR_PlaybackEvent_t evt, DVR_WrapperPlaybackStatus_t *status)
2182{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002183 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 +08002184 ctx->sn,
2185 evt,
2186 status->state,
2187 status->info_cur.time,
2188 status->info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002189 status->info_obsolete.time);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002190
2191 if (ctx->playback.event_fn)
2192 return ctx->playback.event_fn(evt, status, ctx->playback.event_userdata);
2193 return 0;
2194}
2195
2196/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002197static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperPlaybackStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002198{
2199 /*the current seg is not covered in the statistics*/
2200 DVR_WrapperPlaybackSegmentInfo_t *pseg;
2201
2202 memset(&ctx->playback.status, 0, sizeof(ctx->playback.status));
2203 ctx->playback.status.pids = ctx->playback.pids_req;
2204
2205 ctx->playback.status.state = ctx->playback.seg_status.state;
2206 ctx->playback.status.speed = ctx->playback.seg_status.speed;
2207 ctx->playback.status.flags = ctx->playback.seg_status.flags;
2208 ctx->current_segment_id = ctx->playback.seg_status.segment_id;
2209
2210 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2211 if (pseg->seg_info.id == ctx->playback.seg_status.segment_id)
2212 break;
2213 ctx->playback.status.info_cur.time += pseg->seg_info.duration;
2214 ctx->playback.status.info_cur.size += pseg->seg_info.size;
2215 ctx->playback.status.info_cur.pkts += pseg->seg_info.nb_packets;
2216 }
2217 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2218 ctx->playback.status.info_full.time += pseg->seg_info.duration;
2219 ctx->playback.status.info_full.size += pseg->seg_info.size;
2220 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
2221 }
2222
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002223 if (status) {
2224 *status = ctx->playback.status;
2225 /*deal with current, lack size and pkts with the current*/
2226 status->info_cur.time += ctx->playback.seg_status.time_cur;
2227 status->info_obsolete.time = ctx->playback.obsolete.time;
2228 }
2229
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002230 return DVR_SUCCESS;
2231}
2232
2233static int process_handlePlaybackEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2234{
2235 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d) cur(%lld:%u/%u)\n",
2236 evt->sn, evt->playback.event,
2237 evt->playback.status.play_status.state,
2238 evt->playback.status.play_status.segment_id,
2239 evt->playback.status.play_status.time_cur,
2240 evt->playback.status.play_status.time_end);
2241
2242 /*evt PLAYTIME will break the last logic, do not save*/
hualing chene3797f02021-01-13 14:53:28 +08002243 if (evt->playback.event != DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME
2244 && evt->playback.event != DVR_PLAYBACK_EVENT_NODATA
2245 && evt->playback.event != DVR_PLAYBACK_EVENT_DATARESUME
2246 )
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002247 ctx->playback.last_event = evt->playback.event;
2248
2249 switch (evt->playback.event)
2250 {
2251 case DVR_PLAYBACK_EVENT_FIRST_FRAME:
2252 case DVR_PLAYBACK_EVENT_REACHED_END:
2253 case DVR_PLAYBACK_EVENT_TRANSITION_OK:
2254 case DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME:
hualing chenb5cd42e2020-04-15 17:03:34 +08002255 case DVR_PLAYBACK_EVENT_ERROR:
hualing chenf291cf32020-06-18 10:50:30 +08002256 case DVR_PLAYBACK_EVENT_REACHED_BEGIN:
hualing chene3797f02021-01-13 14:53:28 +08002257 case DVR_PLAYBACK_EVENT_NODATA:
2258 case DVR_PLAYBACK_EVENT_DATARESUME:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002259 {
2260 DVR_WrapperPlaybackStatus_t status;
2261
2262 /*copy status of segment*/
2263 ctx->playback.seg_status = evt->playback.status.play_status;
2264
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002265 /*generate status of the whole playback*/
2266 process_generatePlaybackStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002267
2268 if (evt->playback.event == DVR_PLAYBACK_EVENT_REACHED_END) {
Zhiqiang Han31846002021-11-04 10:49:06 +08002269 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) event:0x%x\n", evt->sn, evt->playback.event);
hualing chenb9b358a2021-08-17 15:06:36 +08002270 if (ctx->playback.param_open.is_timeshift
2271 || ctx_isPlay_recording(ctx->playback.param_open.location)) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002272 /*wait for more data in recording*/
Zhiqiang Han31846002021-11-04 10:49:06 +08002273 }
2274 /*trust the low level, make NO check.
2275 As this evt is changed to only once due to some operations(paused) in low level.
2276 else if ((status.info_cur.time + DVR_PLAYBACK_END_GAP) >= ctx->playback.status.info_full.time) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002277 process_notifyPlayback(ctx, evt->playback.event, &status);
Zhiqiang Han31846002021-11-04 10:49:06 +08002278 }
2279 */
2280 else {
2281 process_notifyPlayback(ctx, evt->playback.event, &status);
hualing chenb5cd42e2020-04-15 17:03:34 +08002282 ctx->playback.reach_end = DVR_TRUE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002283 }
hualing chenf291cf32020-06-18 10:50:30 +08002284 } else if (evt->playback.event != DVR_PLAYBACK_EVENT_REACHED_BEGIN) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002285 process_notifyPlayback(ctx, evt->playback.event, &status);
2286 }
2287 } break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002288 case DVR_PLAYBACK_EVENT_TRANSITION_FAILED:
2289 case DVR_PLAYBACK_EVENT_KEY_FAILURE:
2290 case DVR_PLAYBACK_EVENT_NO_KEY:
2291 {
2292 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) error event:0x%x\n", evt->sn, evt->playback.event);
2293 } break;
2294 default:
2295 {
2296 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) unknown event:0x%x\n", evt->sn, evt->playback.event);
2297 } break;
2298 }
2299 return 0;
2300}
2301
2302static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2303{
2304 return (evt->type == W_REC)? process_handleRecordEvent(evt, ctx) : process_handlePlaybackEvent(evt, ctx);
2305}
2306