blob: 61c790a8d90e2d6cf5c93a476ce8dba8969148c0 [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{
138 unsigned long no;
139
140 pthread_mutex_lock(&sn_lock);
141 no = sn++;
142 if (!no)
143 no = sn++;
144 pthread_mutex_unlock(&sn_lock);
145
146 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
321static inline DVR_WrapperCtx_t *ctx_get(unsigned long sn, DVR_WrapperCtx_t *list)
322{
323 int i;
324 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
325 if (list[i].sn == sn)
326 return &list[i];
327 }
328 return NULL;
329}
330
331static inline void ctx_reset(DVR_WrapperCtx_t *ctx)
332{
333 memset((char *)ctx + offsetof(DVR_WrapperCtx_t, sn),
334 0,
335 sizeof(DVR_WrapperCtx_t) - offsetof(DVR_WrapperCtx_t, sn));
336}
337
338static inline int ctx_valid(DVR_WrapperCtx_t *ctx)
339{
340 return (ctx->sn != 0);
341}
342
343static inline DVR_WrapperCtx_t *ctx_getRecord(unsigned long sn)
344{
345 return ctx_get(sn, record_list);
346}
347
348static inline DVR_WrapperCtx_t *ctx_getPlayback(unsigned long sn)
349{
350 return ctx_get(sn, playback_list);
351}
352
353static int wrapper_requestThread(DVR_WrapperThreadCtx_t *ctx, void *(thread_fn)(void *))
354{
355 pthread_mutex_lock(&ctx->lock);
356 if (ctx->running == 0) {
357 pthread_condattr_t attr;
358 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
359 pthread_cond_init(&ctx->cond, &attr);
360 pthread_condattr_destroy(&attr);
361 DVR_WRAPPER_DEBUG(1, "start wrapper thread(%s) ...\n", ctx->name);
362 pthread_create(&ctx->thread, NULL, thread_fn, ctx);
363 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) started\n", ctx->name);
364 }
365 ctx->running++;
366 pthread_mutex_unlock(&ctx->lock);
367 return 0;
368}
369
370static int wrapper_releaseThread(DVR_WrapperThreadCtx_t *ctx)
371{
372 pthread_mutex_lock(&ctx->lock);
373 ctx->running--;
374 if (!ctx->running) {
375 pthread_cond_broadcast(&ctx->cond);
376 pthread_mutex_unlock(&ctx->lock);
377
378 DVR_WRAPPER_DEBUG(1, "stop wrapper thread(%s) ...\n", ctx->name);
379 pthread_join(ctx->thread, NULL);
380 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) stopped\n", ctx->name);
381
382 pthread_mutex_lock(&ctx->lock);
383 if (!ctx->running) /*protect*/
384 pthread_cond_destroy(&ctx->cond);
385 }
386 pthread_mutex_unlock(&ctx->lock);
387 return 0;
388}
389
390#define WRAPPER_THREAD_RECORD (&wrapper_thread[0])
391#define WRAPPER_THREAD_PLAYBACK (&wrapper_thread[1])
392
393static inline int wrapper_requestThreadFor(DVR_WrapperCtx_t *ctx)
394{
395 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
396 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
397 return wrapper_requestThread(thread_ctx, wrapper_task);
398}
399
400static inline int wrapper_releaseThreadFor(DVR_WrapperCtx_t *ctx)
401{
402 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
403 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
404 return wrapper_releaseThread(thread_ctx);
405}
406
407static inline int wrapper_releaseThreadForType(int type)
408{
409 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC)?
410 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
411 return wrapper_releaseThread(thread_ctx);
412}
413
414static inline void wrapper_threadSignal(DVR_WrapperThreadCtx_t *thread_ctx)
415{
416 pthread_cond_signal(&thread_ctx->cond);
417}
418
419static inline int wrapper_threadWait(DVR_WrapperThreadCtx_t *thread_ctx)
420{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800421 struct timespec rt;
422 get_timespec_timeout(200, &rt);
423 pthread_cond_timedwait(&thread_ctx->cond, &thread_ctx->lock, &rt);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800424 return 0;
425}
426
427static inline void wrapper_threadSignalForType(int type)
428{
429 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC) ?
430 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
431 wrapper_threadSignal(thread_ctx);
432}
433
434static inline void wrapper_threadSignalFor(DVR_WrapperCtx_t *ctx)
435{
436 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
437 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
438 wrapper_threadSignal(thread_ctx);
439}
440
441static inline int wrapper_threadWaitFor(DVR_WrapperCtx_t *ctx)
442{
443 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
444 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
445 wrapper_threadWait(thread_ctx);
446 return 0;
447}
448
449static void get_timeout_real(int timeout, struct timespec *ts)
450{
451 struct timespec ots;
452 int left, diff;
453
454 clock_gettime(CLOCK_REALTIME, &ots);
455
456 ts->tv_sec = ots.tv_sec + timeout/1000;
457 ts->tv_nsec = ots.tv_nsec;
458
459 left = timeout % 1000;
460 left *= 1000000;
461 diff = 1000000000-ots.tv_nsec;
462
463 if (diff <= left) {
464 ts->tv_sec++;
465 ts->tv_nsec = left-diff;
466 } else {
467 ts->tv_nsec += left;
468 }
469}
470
471/*return condition, locked if condition == true*/
472static int wrapper_mutex_lock_if(pthread_mutex_t *lock, int *condition)
473{
474 int r2;
475 do {
476 struct timespec rt2;
477 /*android use real time for mutex timedlock*/
478 get_timeout_real(10, &rt2);
479 r2 = pthread_mutex_timedlock(lock, &rt2);
480 } while (*condition && (r2 == ETIMEDOUT));
481
482 if (!(*condition) && (r2 == 0))
483 pthread_mutex_unlock(lock);
484
485 return *condition;
486}
487
488static void *wrapper_task(void *arg)
489{
490 DVR_WrapperThreadCtx_t *tctx = (DVR_WrapperThreadCtx_t *)arg;
491 DVR_WrapperEventCtx_t *evt;
492
493 pthread_mutex_lock(&tctx->lock);
494
495 while (tctx->running) {
496 {
497 int ret;
hualing chene3797f02021-01-13 14:53:28 +0800498
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800499 evt = (tctx->type == W_REC)? ctx_getRecordEvent() : ctx_getPlaybackEvent();
500 if (!evt)
501 ret = wrapper_threadWait(tctx);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800502 }
503
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800504 while (evt) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800505 DVR_WrapperCtx_t *ctx = (evt->type == W_REC)?
506 ctx_getRecord(evt->sn) : ctx_getPlayback(evt->sn);
hualing chenbc0aec92021-03-18 14:52:40 +0800507 if (ctx == NULL) {
508 DVR_WRAPPER_DEBUG(1, "warp not get ctx.free event..\n");
509 goto processed;
510 }
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800511 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 +0800512 if (tctx->running) {
513 /*
514 continue not break,
515 make all events consumed, or mem leak
516 */
517 if (!wrapper_mutex_lock_if(&ctx->lock, &tctx->running))
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800518 goto processed;
519
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800520 if (ctx_valid(ctx)) {
521 /*double check after lock*/
522 if (evt->sn == ctx->sn)
523 process_handleEvents(evt, ctx);
524 }
525 pthread_mutex_unlock(&ctx->lock);
526 }
527
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800528processed:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800529 ctx_freeEvent(evt);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800530
531 evt = (tctx->type == W_REC)? ctx_getRecordEvent() : ctx_getPlaybackEvent();
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800532 }
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800533 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 +0800534 }
535
536 pthread_mutex_unlock(&tctx->lock);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800537 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 +0800538 return NULL;
539}
540
541static inline int ctx_addRecordEvent(DVR_WrapperEventCtx_t *evt)
542{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800543 pthread_mutex_lock(&WRAPPER_THREAD_RECORD->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800544 if (ctx_addEvent(&record_evt_list, &record_evt_list_lock, evt) == 0)
545 wrapper_threadSignalForType(evt->type);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800546 pthread_mutex_unlock(&WRAPPER_THREAD_RECORD->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800547 return 0;
548}
549
550static inline int ctx_addPlaybackEvent(DVR_WrapperEventCtx_t *evt)
551{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800552 pthread_mutex_lock(&WRAPPER_THREAD_PLAYBACK->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800553 if (ctx_addEvent(&playback_evt_list, &playback_evt_list_lock, evt) == 0)
554 wrapper_threadSignalForType(evt->type);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800555 pthread_mutex_unlock(&WRAPPER_THREAD_PLAYBACK->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800556 return 0;
557}
558
559static inline void ctx_freeSegments(DVR_WrapperCtx_t *ctx)
560{
561 DVR_WrapperPlaybackSegmentInfo_t *pseg, *pseg_tmp;
562 list_for_each_entry_safe(pseg, pseg_tmp, &ctx->segments, head) {
563 list_del(&pseg->head);
564 free(pseg);
565 }
566}
567
568static inline void _updatePlaybackSegment(DVR_WrapperPlaybackSegmentInfo_t *pseg,
569 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
570{
571 (void)ctx;
572 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
573 pseg->seg_info = *seg_info;
574 else if (update_flags & U_PIDS) {
575 pseg->seg_info.nb_pids = seg_info->nb_pids;
576 memcpy(pseg->seg_info.pids, seg_info->pids, sizeof(pseg->seg_info.pids));
577 } else if (update_flags & U_STAT) {
578 pseg->seg_info.duration = seg_info->duration;
579 pseg->seg_info.size = seg_info->size;
580 pseg->seg_info.nb_packets = seg_info->nb_packets;
581 }
582
583 /*no changes
584 DVR_PlaybackSegmentFlag_t flags;
585 pseg->playback_info.segment_id = pseg->seg_info.id;
586 strncpy(pseg->playback_info.location,
587 ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
588 pseg->playback_info.pids = ctx->playback.pids_req;
589 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
590 if (ctx->record.param_open.flags | DVR_RECORD_FLAG_SCRAMBLED)
591 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
592 pseg->playback_info.flags = flags;
593 */
594}
595
596static int wrapper_updatePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
597{
598 DVR_WrapperPlaybackSegmentInfo_t *pseg;
599
600 DVR_WRAPPER_DEBUG(1, "timeshift, update playback segments(wrapper), seg:%lld t/s/p(%ld/%zu/%u)\n",
601 seg_info->id, seg_info->duration, seg_info->size, seg_info->nb_packets);
602
603 if (list_empty(&ctx->segments)) {
604 DVR_WRAPPER_DEBUG(1, "timeshift, update while no segment exists, ignore\n");
605 return DVR_SUCCESS;
606 }
607
608 /*normally, the last segment added will be updated*/
609 pseg =
610 list_first_entry(&ctx->segments, DVR_WrapperPlaybackSegmentInfo_t, head);
611 if (pseg->seg_info.id == seg_info->id) {
612 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
613 } else {
614 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
615 if (pseg->seg_info.id == seg_info->id) {
616 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
617 break;
618 }
619 }
620 }
621
622 /*need to notify the dvr_playback*/
623 if (ctx->playback.param_open.is_timeshift/*should must be timeshift*/
624 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END
625 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
626 if (
627 /*there's $TIMESHIFT_DATA_DURATION_TO_RESUME more of data in the current segment playing*/
628 (ctx->playback.seg_status.segment_id == seg_info->id
629 && (seg_info->duration >= ((time_t)ctx->playback.seg_status.time_cur + TIMESHIFT_DATA_DURATION_TO_RESUME)))
630 ||
631 /*or there's a new segment and has $TIMESHIFT_DATA_DURATION_TO_RESUME of data*/
632 (ctx->playback.seg_status.segment_id != seg_info->id
633 && (seg_info->duration >= TIMESHIFT_DATA_DURATION_TO_RESUME))
634 )
635 {
636 int error;
hualing chen36e0dfd2020-05-02 16:33:06 +0800637 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +0800638 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +0800639 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800640
641 error = dvr_playback_resume(ctx->playback.player);
642 DVR_WRAPPER_DEBUG(1, "timeshift, resume playback(sn:%ld) (%d) id/dur: rec(%lld/%ld) play(%lld/%u)\n",
643 ctx->sn, error,
644 seg_info->id, seg_info->duration,
645 ctx->playback.seg_status.segment_id, ctx->playback.seg_status.time_cur);
646 }
647 }
648
649 return DVR_SUCCESS;
650}
651
652static void _updateRecordSegment(DVR_WrapperRecordSegmentInfo_t *pseg,
653 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
654{
655 (void)ctx;
656 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
657 pseg->info = *seg_info;
658 else if (update_flags & U_PIDS) {
659 pseg->info.nb_pids = seg_info->nb_pids;
660 memcpy(pseg->info.pids, seg_info->pids, sizeof(pseg->info.pids));
661 } else if (update_flags & U_STAT) {
662 pseg->info.duration = seg_info->duration;
663 pseg->info.size = seg_info->size;
664 pseg->info.nb_packets = seg_info->nb_packets;
665 }
666}
667
668static int wrapper_updateRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
669{
hualing chen266b9502020-04-04 17:39:39 +0800670 DVR_WrapperRecordSegmentInfo_t *pseg = NULL;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800671
672 /*normally, the last segment added will be updated*/
hualing chen266b9502020-04-04 17:39:39 +0800673 if (!list_empty(&ctx->segments)) {
674 pseg =
675 list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
676 if (pseg->info.id == seg_info->id) {
677 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
678 } else {
679 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
680 if (pseg->info.id == seg_info->id) {
681 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
682 break;
683 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800684 }
685 }
686 }
687
688 /*timeshift, update the segment for playback*/
689 /*
690 the playback should grab the segment info other than the id,
691 and the id will be updated by each segment-add during the recording
692 */
693 /*
694 the playback paused if no data been checked from recording,
695 should resume the player later when there's more data
696 */
697
698 if (ctx->record.param_open.is_timeshift) {
699 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
700
701 if (ctx_playback) {
702 pthread_mutex_lock(&ctx_playback->lock);
703 if (ctx_valid(ctx_playback)
704 && ctx_playback->sn == sn_timeshift_playback) {
705 wrapper_updatePlaybackSegment(ctx_playback, seg_info, update_flags);
706 }
707 pthread_mutex_unlock(&ctx_playback->lock);
708 }
709 }
710
711 return DVR_SUCCESS;
712}
713
714static int wrapper_addPlaybackSegment(DVR_WrapperCtx_t *ctx,
715 DVR_RecordSegmentInfo_t *seg_info,
716 DVR_PlaybackPids_t *p_pids,
717 DVR_PlaybackSegmentFlag_t flags)
718{
719 DVR_WrapperPlaybackSegmentInfo_t *pseg;
720 int error;
721
722 error = 0;
723 pseg = (DVR_WrapperPlaybackSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperPlaybackSegmentInfo_t));
724 if (!pseg) {
725 error = DVR_FAILURE;
726 DVR_WRAPPER_DEBUG(1, "memory fail\n");
727 return error;
728 }
729
730 /*copy the orignal segment info*/
731 pseg->seg_info = *seg_info;
732 /*generate the segment info used in playback*/
733 pseg->playback_info.segment_id = pseg->seg_info.id;
734 strncpy(pseg->playback_info.location, ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
735 pseg->playback_info.pids = *p_pids;
736 pseg->playback_info.flags = flags;
737 list_add(&pseg->head, &ctx->segments);
738
739 error = dvr_playback_add_segment(ctx->playback.player, &pseg->playback_info);
740 if (error) {
741 DVR_WRAPPER_DEBUG(1, "fail to add segment %lld (%d)\n", pseg->playback_info.segment_id, error);
742 } else {
743 ctx->playback.status.info_full.time += pseg->seg_info.duration;
744 ctx->playback.status.info_full.size += pseg->seg_info.size;
745 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
746 }
747
748 return error;
749}
750
751static int wrapper_addRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
752{
753 DVR_WrapperRecordSegmentInfo_t *pseg;
754 int error;
755
756 error = 0;
757 pseg = (DVR_WrapperRecordSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperRecordSegmentInfo_t));
758 if (!pseg) {
759 error = DVR_FAILURE;
760 DVR_WRAPPER_DEBUG(1, "memory fail\n");
761 }
762 pseg->info = *seg_info;
763 list_add(&pseg->head, &ctx->segments);
764
765 if (ctx->record.param_open.is_timeshift) {
766 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
767
768 if (ctx_playback) {
769 pthread_mutex_lock(&ctx_playback->lock);
770 if (ctx_valid(ctx_playback)) {
771 DVR_PlaybackSegmentFlag_t flags;
772
773 /*only if playback has started, the previous segments have been loaded*/
774 if (!list_empty(&ctx_playback->segments)) {
775 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
Gong Ke2a0ebbe2021-05-25 15:22:50 +0800776 if (ctx->record.param_open.flags & DVR_RECORD_FLAG_SCRAMBLED)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800777 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
778 wrapper_addPlaybackSegment(ctx_playback, seg_info, &ctx_playback->playback.pids_req, flags);
779 }
780 }
781 pthread_mutex_unlock(&ctx_playback->lock);
782 }
Zhiqiang Hane0a1c382021-06-08 11:28:05 +0800783 } else {
784 dvr_segment_link_op(ctx->record.param_open.location, 1, &seg_info->id, LSEG_OP_ADD);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800785 }
786
787 return error;
788}
789
790static int wrapper_removePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
791{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800792 int error = -1;
793 DVR_WrapperPlaybackSegmentInfo_t *pseg = NULL, *pseg_tmp;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800794
795 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->id);
796
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800797 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800798 if (pseg->seg_info.id == seg_info->id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800799
800 if (ctx->current_segment_id == seg_info->id) {
801 DVR_WrapperPlaybackSegmentInfo_t *next_seg;
802
803 /*drive the player out of this will-be-deleted segment*/
804 next_seg = list_prev_entry(pseg, head);
805
806 if (ctx->playback.speed != 100.0f) {
807 error = dvr_playback_resume(ctx->playback.player);
808 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), resume for new start (%d)\n", ctx->sn, error);
809 }
810
811 error = dvr_playback_seek(ctx->playback.player, next_seg->seg_info.id, 0);
812 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);
813
814 if (ctx->playback.speed == 0.0f) {
815 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
816 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last paused from new start (%d)\n", ctx->sn, error);
817 } else if (ctx->playback.speed != 100.0f) {
818 DVR_PlaybackSpeed_t dvr_speed = {
819 .speed = { ctx->playback.speed },
820 .mode = ( ctx->playback.speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
821 };
822 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
823 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last speed(x%f) from new start (%d)\n", ctx->sn,ctx->playback.speed, error);
824 }
825 }
826
827 error = dvr_playback_remove_segment(ctx->playback.player, seg_info->id);
828 if (error) {
829 /*remove playack segment fail*/
830 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), failed to remove segment(%llu) (%d)\n", ctx->sn, seg_info->id, error);
831 }
832
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800833 list_del(&pseg->head);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800834
835 /*record the obsolete*/
836 ctx->playback.obsolete.time += pseg->seg_info.duration;
837 ctx->playback.obsolete.size += pseg->seg_info.size;
838 ctx->playback.obsolete.pkts += pseg->seg_info.nb_packets;
839
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800840 free(pseg);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800841 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800842 }
843 }
844
845 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->id, error);
846
847 return error;
848}
849
850static int wrapper_removeRecordSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *seg_info)
851{
852 int error;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800853 DVR_WrapperRecordSegmentInfo_t *pseg, *pseg_tmp;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800854
855 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->info.id);
856
857 /*if timeshifting, notify the playback first, then deal with record*/
858 if (ctx->record.param_open.is_timeshift) {
859 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
860
861 if (ctx_playback) {
862 pthread_mutex_lock(&ctx_playback->lock);
863 if (ctx_valid(ctx_playback)
864 && ctx_playback->sn == sn_timeshift_playback
865 && !list_empty(&ctx_playback->segments)) {
866 error = wrapper_removePlaybackSegment(ctx_playback, &seg_info->info);
867 }
868 pthread_mutex_unlock(&ctx_playback->lock);
869 }
870 }
871
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800872 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
873 if (pseg->info.id == seg_info->info.id) {
874 list_del(&pseg->head);
875
876 /*record the obsolete*/
877 ctx->record.obsolete.time += pseg->info.duration;
878 ctx->record.obsolete.size += pseg->info.size;
879 ctx->record.obsolete.pkts += pseg->info.nb_packets;
880
881 free(pseg);
882 break;
883 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800884 }
885
886 error = dvr_segment_delete(ctx->record.param_open.location, seg_info->info.id);
887
888 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->info.id, error);
889
890 return error;
891}
892
893int dvr_wrapper_open_record (DVR_WrapperRecord_t *rec, DVR_WrapperRecordOpenParams_t *params)
894{
895 int error;
896 DVR_WrapperCtx_t *ctx;
897 DVR_RecordOpenParams_t open_param;
898
899 DVR_RETURN_IF_FALSE(rec);
900 DVR_RETURN_IF_FALSE(params);
901
902 /*get a free ctx*/
903 ctx = ctx_getRecord(0);
904 DVR_RETURN_IF_FALSE(ctx);
905
906 pthread_mutex_lock(&ctx->lock);
907
hualing chen51652f02020-12-29 16:59:31 +0800908 DVR_WRAPPER_DEBUG(1, "open record(dmx:%d) .istf(%d)..time (%ld)ms max size(%lld)byte seg size(%lld)byte\n",
909 params->dmx_dev_id, params->is_timeshift, params->max_time, params->max_size, params->segment_size);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800910
911 ctx_reset(ctx);
912
913 ctx->record.param_open = *params;
914 ctx->record.event_fn = params->event_fn;
915 ctx->record.event_userdata = params->event_userdata;
916 ctx->record.next_segment_id = 0;
917 ctx->current_segment_id = 0;
918 INIT_LIST_HEAD(&ctx->segments);
919 ctx->sn = get_sn();
920
921 wrapper_requestThreadFor(ctx);
922
hualing chen266b9502020-04-04 17:39:39 +0800923 memset(&open_param, 0, sizeof(DVR_RecordOpenParams_t));
Yahui Hance15e9c2020-12-08 18:08:32 +0800924 open_param.fend_dev_id = params->fend_dev_id;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800925 open_param.dmx_dev_id = params->dmx_dev_id;
926 open_param.data_from_memory = 0;
927 open_param.flags = params->flags;
Zhiqiang Han104aed72020-04-03 19:37:43 +0800928 open_param.notification_size = 500*1024;
Zhiqiang Han31505452020-05-06 15:08:10 +0800929 open_param.flush_size = params->flush_size;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800930 open_param.event_fn = wrapper_record_event_handler;
931 open_param.event_userdata = (void*)ctx->sn;
932
933 error = dvr_record_open(&ctx->record.recorder, &open_param);
934 if (error) {
935 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) open fail(error:%d).\n", params->dmx_dev_id, error);
936 ctx_reset(ctx);
937 pthread_mutex_unlock(&ctx->lock);
938 wrapper_releaseThreadForType(ctx->type);
939 return DVR_FAILURE;
940 }
941 if (params->is_timeshift)
942 sn_timeshift_record = ctx->sn;
943
944 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
945
hualing chen266b9502020-04-04 17:39:39 +0800946 error = dvr_record_set_encrypt_callback(ctx->record.recorder, params->crypto_fn, params->crypto_data);
947 if (error) {
948 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) set encrypt callback fail(error:%d).\n", params->dmx_dev_id, error);
949 }
950
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800951 pthread_mutex_unlock(&ctx->lock);
952
953 *rec = (DVR_WrapperRecord_t)ctx->sn;
954 return DVR_SUCCESS;
955}
956
957int dvr_wrapper_close_record (DVR_WrapperRecord_t rec)
958{
959 DVR_WrapperCtx_t *ctx;
960 DVR_RecordSegmentInfo_t seg_info;
961 int error;
962
963 DVR_RETURN_IF_FALSE(rec);
964
965 ctx = ctx_getRecord((unsigned long)rec);
966 DVR_RETURN_IF_FALSE(ctx);
967
968 pthread_mutex_lock(&ctx->lock);
969 DVR_WRAPPER_DEBUG(1, "close record(sn:%ld)\n", ctx->sn);
970 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
971
972 memset(&seg_info, 0, sizeof(seg_info));
973 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
974
975 error = dvr_record_close(ctx->record.recorder);
976
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800977 if (ctx->record.param_open.is_timeshift)
978 sn_timeshift_record = 0;
979
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800980 ctx_freeSegments(ctx);
981
982 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) closed = (%d).\n", ctx->sn, error);
983 ctx_reset(ctx);
984 pthread_mutex_unlock(&ctx->lock);
985
986 wrapper_releaseThreadForType(ctx->type);
987
988 return error;
989}
990
991int dvr_wrapper_start_record (DVR_WrapperRecord_t rec, DVR_WrapperRecordStartParams_t *params)
992{
993 DVR_WrapperCtx_t *ctx;
994 DVR_RecordStartParams_t *start_param;
995 int i;
996 int error;
997
998 DVR_RETURN_IF_FALSE(rec);
999 DVR_RETURN_IF_FALSE(params);
1000
1001 ctx = ctx_getRecord((unsigned long)rec);
1002 DVR_RETURN_IF_FALSE(ctx);
1003
1004 pthread_mutex_lock(&ctx->lock);
1005 DVR_WRAPPER_DEBUG(1, "start record(sn:%ld, location:%s) ...\n", ctx->sn, ctx->record.param_open.location);
1006 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1007
1008 start_param = &ctx->record.param_start;
1009 memset(start_param, 0, sizeof(*start_param));
1010 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
1011 start_param->segment.segment_id = ctx->record.next_segment_id++;
1012 start_param->segment.nb_pids = params->pids_info.nb_pids;
1013 for (i = 0; i < params->pids_info.nb_pids; i++) {
1014 start_param->segment.pids[i] = params->pids_info.pids[i];
1015 start_param->segment.pid_action[i] = DVR_RECORD_PID_CREATE;
1016 }
hualing chen7a56cba2020-04-14 14:09:27 +08001017 dvr_segment_del_by_location(start_param->location);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001018 {
1019 /*sync to update for further use*/
1020 DVR_RecordStartParams_t *update_param;
1021 update_param = &ctx->record.param_update;
1022 memcpy(update_param, start_param, sizeof(*update_param));
1023 for (i = 0; i < update_param->segment.nb_pids; i++)
1024 update_param->segment.pid_action[i] = DVR_RECORD_PID_KEEP;
1025 }
1026
1027 error = dvr_record_start_segment(ctx->record.recorder, start_param);
1028 {
1029 DVR_RecordSegmentInfo_t new_seg_info =
1030 { .id = start_param->segment.segment_id, };
1031 wrapper_addRecordSegment(ctx, &new_seg_info);
1032 }
1033
1034 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) started = (%d)\n", ctx->sn, error);
1035
1036 pthread_mutex_unlock(&ctx->lock);
1037
1038 return error;
1039}
1040
1041int dvr_wrapper_stop_record (DVR_WrapperRecord_t rec)
1042{
1043 DVR_WrapperCtx_t *ctx;
1044 DVR_RecordSegmentInfo_t seg_info;
1045 int error;
1046
1047 DVR_RETURN_IF_FALSE(rec);
1048
1049 ctx = ctx_getRecord((unsigned long)rec);
1050 DVR_RETURN_IF_FALSE(ctx);
1051
1052 pthread_mutex_lock(&ctx->lock);
1053 DVR_WRAPPER_DEBUG(1, "stop record(sn:%ld) ...\n", ctx->sn);
1054 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1055
1056 memset(&seg_info, 0, sizeof(seg_info));
1057 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
1058 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
1059
1060 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) stopped = (%d)\n", ctx->sn, error);
1061 pthread_mutex_unlock(&ctx->lock);
1062
1063 return error;
1064}
1065
1066int dvr_wrapper_update_record_pids (DVR_WrapperRecord_t rec, DVR_WrapperUpdatePidsParams_t *params)
1067{
1068 DVR_WrapperCtx_t *ctx;
1069 DVR_RecordStartParams_t *start_param;
1070 DVR_RecordSegmentInfo_t seg_info;;
1071 int i;
1072 int error;
1073
1074 DVR_RETURN_IF_FALSE(rec);
1075 DVR_RETURN_IF_FALSE(params);
1076
1077 ctx = ctx_getRecord((unsigned long)rec);
1078 DVR_RETURN_IF_FALSE(ctx);
1079
1080 pthread_mutex_lock(&ctx->lock);
1081 DVR_WRAPPER_DEBUG(1, "update record(sn:%ld)\n", ctx->sn);
1082 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1083
1084 start_param = &ctx->record.param_update;
1085 memset(start_param, 0, sizeof(*start_param));
1086 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
1087 start_param->segment.segment_id = ctx->record.next_segment_id++;
1088 start_param->segment.nb_pids = params->nb_pids;
1089 for (i = 0; i < params->nb_pids; i++) {
1090 start_param->segment.pids[i] = params->pids[i];
1091 start_param->segment.pid_action[i] = params->pid_action[i];
1092 }
1093 error = dvr_record_next_segment(ctx->record.recorder, start_param, &seg_info);
1094 {
1095 DVR_RecordSegmentInfo_t new_seg_info =
1096 { .id = start_param->segment.segment_id, };
1097 wrapper_updateRecordSegment(ctx, &seg_info, U_PIDS);
1098 wrapper_addRecordSegment(ctx, &new_seg_info);
1099 }
1100
1101 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) updated = (%d)\n", ctx->sn, error);
1102 pthread_mutex_unlock(&ctx->lock);
1103
1104 return error;
1105}
1106
1107int dvr_wrapper_get_record_status(DVR_WrapperRecord_t rec, DVR_WrapperRecordStatus_t *status)
1108{
1109 DVR_WrapperCtx_t *ctx;
1110 DVR_WrapperRecordStatus_t s;
1111 int error;
1112
1113 DVR_RETURN_IF_FALSE(rec);
1114 DVR_RETURN_IF_FALSE(status);
1115
1116 ctx = ctx_getRecord((unsigned long)rec);
1117 DVR_RETURN_IF_FALSE(ctx);
1118
1119 pthread_mutex_lock(&ctx->lock);
1120
1121 DVR_WRAPPER_DEBUG(1, "get record(sn:%ld) status ...\n", ctx->sn);
1122 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1123
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001124 error = process_generateRecordStatus(ctx, &s);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001125
1126 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) state/time/size/pkts(%d/%ld/%lld/%u) (%d)\n",
1127 ctx->sn,
1128 s.state,
1129 s.info.time,
1130 s.info.size,
1131 s.info.pkts,
1132 error);
1133
1134 *status = s;
1135
1136 pthread_mutex_unlock(&ctx->lock);
1137
1138 return error;
1139}
1140
hualing chen4fe3bee2020-10-23 13:58:52 +08001141int dvr_wrapper_record_is_secure_mode(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 error = dvr_record_is_secure_mode(ctx->record.recorder);
1153 pthread_mutex_unlock(&ctx->lock);
1154 return error;
1155}
1156
hualing chen266b9502020-04-04 17:39:39 +08001157int dvr_wrapper_set_record_secure_buffer (DVR_WrapperRecord_t rec, uint8_t *p_secure_buf, uint32_t len)
1158{
1159 DVR_WrapperCtx_t *ctx;
1160 int error;
1161
1162 DVR_RETURN_IF_FALSE(rec);
1163 DVR_RETURN_IF_FALSE(p_secure_buf);
1164
1165 ctx = ctx_getRecord((unsigned long)rec);
1166 DVR_RETURN_IF_FALSE(ctx);
1167
1168 pthread_mutex_lock(&ctx->lock);
1169 error = dvr_record_set_secure_buffer(ctx->record.recorder, p_secure_buf, len);
1170 pthread_mutex_unlock(&ctx->lock);
1171 return error;
1172}
1173
1174int dvr_wrapper_set_record_decrypt_callback (DVR_WrapperRecord_t rec, DVR_CryptoFunction_t func, void *userdata)
1175{
1176 DVR_WrapperCtx_t *ctx;
1177 int error;
1178
1179 DVR_RETURN_IF_FALSE(rec);
1180 DVR_RETURN_IF_FALSE(func);
1181
1182 ctx = ctx_getRecord((unsigned long)rec);
1183 DVR_RETURN_IF_FALSE(ctx);
1184
1185 pthread_mutex_lock(&ctx->lock);
1186 error = dvr_record_set_encrypt_callback(ctx->record.recorder, func, userdata);
1187 pthread_mutex_unlock(&ctx->lock);
1188 return error;
1189}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001190
1191
1192int dvr_wrapper_open_playback (DVR_WrapperPlayback_t *playback, DVR_WrapperPlaybackOpenParams_t *params)
1193{
1194 DVR_WrapperCtx_t *ctx;
1195 DVR_PlaybackOpenParams_t open_param;
1196 int error;
1197
1198 DVR_RETURN_IF_FALSE(playback);
1199 DVR_RETURN_IF_FALSE(params);
1200 DVR_RETURN_IF_FALSE(params->playback_handle);
1201
1202 /*get a free ctx*/
1203 ctx = ctx_getPlayback(0);
1204 DVR_RETURN_IF_FALSE(ctx);
1205
1206 pthread_mutex_lock(&ctx->lock);
1207
hualing chen90b3ae62021-03-30 10:49:28 +08001208 DVR_WRAPPER_DEBUG(1, "open playback(dmx:%d) ..vendor[%d].\n", params->dmx_dev_id, params->vendor);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001209
1210 ctx_reset(ctx);
1211
1212 ctx->playback.param_open = *params;
1213 ctx->playback.event_fn = params->event_fn;
1214 ctx->playback.event_userdata = params->event_userdata;
1215 ctx->current_segment_id = 0;
1216 INIT_LIST_HEAD(&ctx->segments);
1217 ctx->sn = get_sn();
1218
1219 wrapper_requestThreadFor(ctx);
1220
hualing chen266b9502020-04-04 17:39:39 +08001221 memset(&open_param, 0, sizeof(DVR_PlaybackOpenParams_t));
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001222 open_param.dmx_dev_id = params->dmx_dev_id;
1223 open_param.block_size = params->block_size;
1224 open_param.is_timeshift = params->is_timeshift;
1225 //open_param.notification_size = 10*1024; //not supported
1226 open_param.event_fn = wrapper_playback_event_handler;
1227 open_param.event_userdata = (void*)ctx->sn;
1228 /*open_param.has_pids = 0;*/
hualing chene3797f02021-01-13 14:53:28 +08001229 open_param.is_notify_time = params->is_notify_time;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001230 open_param.player_handle = (am_tsplayer_handle)params->playback_handle;
hualing chen90b3ae62021-03-30 10:49:28 +08001231 open_param.vendor = params->vendor;
1232
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001233
1234 error = dvr_playback_open(&ctx->playback.player, &open_param);
1235 if (error) {
1236 DVR_WRAPPER_DEBUG(1, "playback(dmx:%d) openned fail(error:%d).\n", params->dmx_dev_id, error);
1237 ctx_reset(ctx);
1238 pthread_mutex_unlock(&ctx->lock);
1239 wrapper_releaseThreadForType(ctx->type);
1240 return DVR_FAILURE;
1241 }
1242 if (params->is_timeshift)
1243 sn_timeshift_playback = ctx->sn;
1244
hualing chen266b9502020-04-04 17:39:39 +08001245 DVR_WRAPPER_DEBUG(1, "hanyh: playback(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
1246 error = dvr_playback_set_decrypt_callback(ctx->playback.player, params->crypto_fn, params->crypto_data);
1247 if (error) {
1248 DVR_WRAPPER_DEBUG(1, "playback set deccrypt callback fail(error:%d).\n", error);
1249 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001250 pthread_mutex_unlock(&ctx->lock);
1251
1252 *playback = (DVR_WrapperPlayback_t)ctx->sn;
1253 return DVR_SUCCESS;
1254}
1255
1256int dvr_wrapper_close_playback (DVR_WrapperPlayback_t playback)
1257{
1258 DVR_WrapperCtx_t *ctx;
1259 int error;
1260
1261 DVR_RETURN_IF_FALSE(playback);
1262
1263 ctx = ctx_getPlayback((unsigned long)playback);
1264 DVR_RETURN_IF_FALSE(ctx);
1265
1266 pthread_mutex_lock(&ctx->lock);
1267 DVR_WRAPPER_DEBUG(1, "close playback(sn:%ld)\n", ctx->sn);
1268 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1269
1270 if (ctx->playback.param_open.is_timeshift)
1271 sn_timeshift_playback = 0;
1272
1273 /*try stop first*/
1274 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1275
1276 {
1277 /*remove all segments*/
1278 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1279
1280 list_for_each_entry(pseg, &ctx->segments, head) {
1281 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1282 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1283 ctx->sn, pseg->playback_info.segment_id, error);
1284 }
1285 ctx_freeSegments(ctx);
1286 }
1287
1288 error = dvr_playback_close(ctx->playback.player);
1289
1290 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) closed.\n", ctx->sn);
1291 ctx_reset(ctx);
1292 pthread_mutex_unlock(&ctx->lock);
1293
1294 wrapper_releaseThreadForType(ctx->type);
1295
1296 return error;
1297}
1298
1299int dvr_wrapper_start_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackFlag_t flags, DVR_PlaybackPids_t *p_pids)
1300{
1301 DVR_WrapperCtx_t *ctx;
1302 int error;
1303 uint64_t *p_segment_ids;
1304 uint32_t segment_nb;
1305 uint32_t i;
1306 DVR_RecordSegmentInfo_t seg_info_1st;
1307 int got_1st_seg;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001308 DVR_WrapperCtx_t *ctx_record;/*for timeshift*/
hualing chenc110f952021-01-18 11:25:37 +08001309 DVR_Bool_t is_timeshift = DVR_FALSE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001310
1311 DVR_RETURN_IF_FALSE(playback);
1312 DVR_RETURN_IF_FALSE(p_pids);
1313
hualing chenc110f952021-01-18 11:25:37 +08001314 ctx_record = NULL;
1315
1316 /*lock the recorder to avoid changing the recording segments*/
1317 ctx_record = ctx_getRecord(sn_timeshift_record);
1318
1319 if (ctx_record) {
1320 pthread_mutex_lock(&ctx_record->lock);
1321 if (!ctx_valid(ctx_record)
1322 || ctx_record->sn != sn_timeshift_record) {
1323 DVR_WRAPPER_DEBUG(1, "timeshift, record is not for timeshifting, FATAL error found\n");
1324 pthread_mutex_unlock(&ctx_record->lock);
1325 is_timeshift = DVR_FALSE;
1326 } else {
1327 is_timeshift = DVR_TRUE;
1328 }
1329 }
1330
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001331 ctx = ctx_getPlayback((unsigned long)playback);
1332 DVR_RETURN_IF_FALSE(ctx);
1333
1334 pthread_mutex_lock(&ctx->lock);
1335
1336 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",
1337 ctx->sn,
1338 ctx->playback.param_open.location,
1339 flags,
1340 p_pids->video.pid, p_pids->video.format,
1341 p_pids->audio.pid, p_pids->audio.format,
1342 p_pids->ad.pid, p_pids->ad.format,
1343 p_pids->subtitle.pid, p_pids->subtitle.format,
1344 p_pids->pcr.pid);
1345
1346 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1347
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001348 if (ctx->playback.param_open.is_timeshift) {
1349 /*lock the recorder to avoid changing the recording segments*/
hualing chenc110f952021-01-18 11:25:37 +08001350 if (is_timeshift == DVR_FALSE) {
1351 DVR_WRAPPER_DEBUG(1, "timeshift, record is not for timeshifting, FATAL error return\n");
1352 pthread_mutex_unlock(&ctx->lock);
1353 return DVR_FAILURE;
1354 } else {
1355 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) record(sn:%ld) locked ok due to timeshift\n",
1356 ctx->sn, ctx_record->sn);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001357 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001358 }
1359
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001360 /*obtain all segments in a list*/
1361 segment_nb = 0;
1362 p_segment_ids = NULL;
1363 error = dvr_segment_get_list(ctx->playback.param_open.location, &segment_nb, &p_segment_ids);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001364 if (!error) {
1365 got_1st_seg = 0;
1366 for (i = 0; i < segment_nb; i++) {
1367 DVR_RecordSegmentInfo_t seg_info;
1368 DVR_PlaybackSegmentFlag_t flags;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001369
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001370 error = dvr_segment_get_info(ctx->playback.param_open.location, p_segment_ids[i], &seg_info);
1371 if (error) {
1372 error = DVR_FAILURE;
1373 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
1374 ctx->playback.param_open.location, p_segment_ids[i], error);
1375 break;
1376 }
hualing chen92f3a142020-07-08 20:59:33 +08001377 //add check if has audio or video pid. if not exist. not add segment to playback
1378 int ii = 0;
1379 int has_av = 0;
1380 for (ii = 0; ii < seg_info.nb_pids; ii++) {
1381 int type = (seg_info.pids[ii].type >> 24) & 0x0f;
1382 if (type == DVR_STREAM_TYPE_VIDEO ||
1383 type == DVR_STREAM_TYPE_AUDIO ||
1384 type == DVR_STREAM_TYPE_AD) {
1385 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1386 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,
1387 DVR_STREAM_TYPE_VIDEO,
1388 DVR_STREAM_TYPE_AUDIO,
1389 DVR_STREAM_TYPE_AD);
1390 has_av = 1;
1391 //break;
1392 } else {
1393 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,
1394 DVR_STREAM_TYPE_VIDEO,
1395 DVR_STREAM_TYPE_AUDIO,
1396 DVR_STREAM_TYPE_AD);
1397 }
1398 }
1399 if (has_av == 0) {
1400 DVR_WRAPPER_DEBUG(1, "fail to get seg av info \n");
1401 continue;
1402 } else {
1403 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1404 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001405 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1406 error = wrapper_addPlaybackSegment(ctx, &seg_info, p_pids, flags);
1407 if (error)
1408 break;
1409
1410 /*copy the 1st segment*/
1411 if (got_1st_seg == 0) {
1412 seg_info_1st = seg_info;
1413 got_1st_seg = 1;
1414 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001415 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001416 free(p_segment_ids);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001417
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001418 /* return if no segment or fail to add */
1419 if (!error && got_1st_seg) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001420
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001421 /*copy the obsolete infomation, must for timeshifting*/
1422 if (ctx->playback.param_open.is_timeshift && ctx_record) {
1423 ctx->playback.obsolete = ctx_record->record.obsolete;
1424 }
1425
1426 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) (%d) segments added\n", ctx->sn, i);
1427
1428 ctx->playback.reach_end = DVR_FALSE;
1429 if ((flags&DVR_PLAYBACK_STARTED_PAUSEDLIVE) == DVR_PLAYBACK_STARTED_PAUSEDLIVE)
1430 ctx->playback.speed = 0.0f;
1431 else
1432 ctx->playback.speed = 100.0f;
1433
1434 ctx->playback.pids_req = *p_pids;
1435
1436 error = dvr_playback_seek(ctx->playback.player, seg_info_1st.id, 0);
1437 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seek(seg:%llu 0) for start (%d)\n",
1438 ctx->sn, seg_info_1st.id, error);
1439
1440 error = dvr_playback_start(ctx->playback.player, flags);
1441
1442 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) started (%d)\n", ctx->sn, error);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001443 }
1444 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001445
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001446 if (ctx->playback.param_open.is_timeshift) {
1447 /*unlock the recorder locked above*/
1448 if (ctx_record && ctx_valid(ctx_record)) {
1449 pthread_mutex_unlock(&ctx_record->lock);
1450 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld), record(sn:%ld) unlocked ok due to timeshift\n",
1451 ctx->sn, ctx_record->sn);
1452 }
1453 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001454
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001455
1456 pthread_mutex_unlock(&ctx->lock);
1457
1458 return error;
1459}
1460
1461int dvr_wrapper_stop_playback (DVR_WrapperPlayback_t playback)
1462{
1463 DVR_WrapperCtx_t *ctx;
1464 int error;
1465
1466 DVR_RETURN_IF_FALSE(playback);
1467
1468 ctx = ctx_getPlayback((unsigned long)playback);
1469 DVR_RETURN_IF_FALSE(ctx);
1470
1471 pthread_mutex_lock(&ctx->lock);
1472 DVR_WRAPPER_DEBUG(1, "stop playback(sn:%ld) ...\n", ctx->sn);
1473 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1474
1475 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1476
1477 {
1478 /*remove all segments*/
1479 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1480
1481 list_for_each_entry(pseg, &ctx->segments, head) {
1482 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1483 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1484 ctx->sn, pseg->playback_info.segment_id, error);
1485 }
1486 ctx_freeSegments(ctx);
1487 }
1488
1489 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) stopped (%d)\n", ctx->sn, error);
1490 pthread_mutex_unlock(&ctx->lock);
1491
1492 return error;
1493}
1494
1495int dvr_wrapper_pause_playback (DVR_WrapperPlayback_t playback)
1496{
1497 DVR_WrapperCtx_t *ctx;
1498 int error;
1499
1500 DVR_RETURN_IF_FALSE(playback);
1501
1502 ctx = ctx_getPlayback((unsigned long)playback);
1503 DVR_RETURN_IF_FALSE(ctx);
1504
1505 pthread_mutex_lock(&ctx->lock);
1506 DVR_WRAPPER_DEBUG(1, "pause playback(sn:%ld) ...\n", ctx->sn);
1507 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
hualing chen36e0dfd2020-05-02 16:33:06 +08001508 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +08001509 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +08001510 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001511
1512 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
1513
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001514 ctx->playback.speed = 0.0f;
1515
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001516 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) paused (%d)\n", ctx->sn, error);
1517 pthread_mutex_unlock(&ctx->lock);
1518
1519 return error;
1520}
1521
1522int dvr_wrapper_resume_playback (DVR_WrapperPlayback_t playback)
1523{
1524 DVR_WrapperCtx_t *ctx;
1525 int error;
1526
1527 DVR_RETURN_IF_FALSE(playback);
1528
1529 ctx = ctx_getPlayback((unsigned long)playback);
1530 DVR_RETURN_IF_FALSE(ctx);
1531
1532 pthread_mutex_lock(&ctx->lock);
1533 DVR_WRAPPER_DEBUG(1, "resume playback(sn:%ld) ...\n", ctx->sn);
1534 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1535
1536 error = dvr_playback_resume(ctx->playback.player);
1537
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001538 ctx->playback.speed = 100.0f;
1539
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001540 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) resumed (%d)\n", ctx->sn, error);
1541 pthread_mutex_unlock(&ctx->lock);
1542
1543 return error;
1544}
1545
1546int dvr_wrapper_set_playback_speed (DVR_WrapperPlayback_t playback, float speed)
1547{
1548 DVR_WrapperCtx_t *ctx;
1549 int error;
1550 DVR_PlaybackSpeed_t dvr_speed = {
1551 .speed = { speed },
1552 .mode = (speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
1553 };
1554
1555 DVR_RETURN_IF_FALSE(playback);
1556
1557 ctx = ctx_getPlayback((unsigned long)playback);
1558 DVR_RETURN_IF_FALSE(ctx);
1559
1560 pthread_mutex_lock(&ctx->lock);
hualing chenc70a8df2020-05-12 19:23:11 +08001561 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 +08001562 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1563
1564 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
1565
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001566 if (ctx->playback.speed != 0.0f && ctx->playback.speed != 100.0f
1567 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_BEGIN
1568 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
1569 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, paused, do resume first\n", ctx->playback.speed, speed);
1570 error = dvr_playback_resume(ctx->playback.player);
1571 } else if (ctx->playback.speed == 0.0f
1572 && speed != 0.0f
1573 && speed != 100.0f) {
1574 /*libdvr do not support pause with speed=0, will not be here*/
1575 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, do resume first\n", ctx->playback.speed, speed);
1576 error = dvr_playback_resume(ctx->playback.player);
1577 }
1578
1579 ctx->playback.speed = speed;
1580
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001581 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) speeded(x%f) (%d)\n",
1582 ctx->sn, speed, error);
1583 pthread_mutex_unlock(&ctx->lock);
1584
1585 return error;
1586}
1587
1588int dvr_wrapper_seek_playback (DVR_WrapperPlayback_t playback, uint32_t time_offset)
1589{
1590 DVR_WrapperCtx_t *ctx;
1591 int error;
1592 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1593 uint64_t segment_id;
1594 uint32_t off;
1595 uint64_t last_segment_id;
1596 uint32_t pre_off;
1597
1598 DVR_RETURN_IF_FALSE(playback);
1599
1600 ctx = ctx_getPlayback((unsigned long)playback);
1601 DVR_RETURN_IF_FALSE(ctx);
1602
1603 pthread_mutex_lock(&ctx->lock);
1604
1605 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (off:%d) ...\n", ctx->sn, time_offset);
1606 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1607
1608 off = 0;
1609 segment_id = 0;
1610 pre_off = 0;
1611 last_segment_id = 0;
1612
1613 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1614 segment_id = pseg->seg_info.id;
1615
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001616 if ((ctx->playback.obsolete.time + pre_off + pseg->seg_info.duration) > time_offset)
1617 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001618
1619 last_segment_id = pseg->seg_info.id;
1620 pre_off += pseg->seg_info.duration;
1621 }
1622
1623 if (last_segment_id == segment_id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001624 /*1.only one seg with id:0, 2.offset exceeds the total duration*/
1625 off = time_offset;
1626 } else if (ctx->playback.obsolete.time >= time_offset) {
1627 off = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001628 } else {
hualing chenda76fc52020-05-28 14:56:42 +08001629 off = time_offset - pre_off - ctx->playback.obsolete.time;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001630 }
1631
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001632 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (seg:%lld, off:%d)\n",
1633 ctx->sn, segment_id, off);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001634 error = dvr_playback_seek(ctx->playback.player, segment_id, off);
1635 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seeked(off:%d) (%d)\n", ctx->sn, time_offset, error);
1636
1637 pthread_mutex_unlock(&ctx->lock);
1638
1639 return error;
1640}
1641
1642int dvr_wrapper_update_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackPids_t *p_pids)
1643{
1644 DVR_WrapperCtx_t *ctx;
1645 int error;
1646 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1647
1648 DVR_RETURN_IF_FALSE(playback);
1649 DVR_RETURN_IF_FALSE(p_pids);
1650
1651 ctx = ctx_getPlayback((unsigned long)playback);
1652 DVR_RETURN_IF_FALSE(ctx);
1653
1654 pthread_mutex_lock(&ctx->lock);
1655
1656 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) ...\n",
1657 ctx->sn,
1658 p_pids->video.pid, p_pids->video.format,
1659 p_pids->audio.pid, p_pids->audio.format);
1660 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1661
1662 ctx->playback.pids_req = *p_pids;
1663
1664 error = 0;
1665 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1666 /*should update the whole list of segments*/
1667 /*if (pseg->seg_info.id == ctx->current_segment_id)*/ {
1668 /*list_for_each_entry_from(pseg, &ctx->segments, head)*/ {
1669 /*check udpate for pids*/
1670 if (memcmp(&pseg->playback_info.pids, p_pids, sizeof(*p_pids)) != 0) {
1671 pseg->playback_info.pids = *p_pids;
1672 error = dvr_playback_update_segment_pids(ctx->playback.player, pseg->seg_info.id, p_pids);
1673 if (error) {
1674 DVR_WRAPPER_DEBUG(1, "failed to playback(sn:%ld) update segment(id:%lld) pids (%d)\n",
1675 ctx->sn, pseg->seg_info.id, error);
1676 /*do not break, let list updated*/
1677 }
1678 }
1679 }
1680 /*break;*/
1681 }
1682 }
1683
1684 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) (%d)\n",
1685 ctx->sn,
1686 p_pids->video.pid, p_pids->video.format,
1687 p_pids->audio.pid, p_pids->audio.format,
1688 error);
1689
1690 pthread_mutex_unlock(&ctx->lock);
1691
1692 return error;
1693}
1694
1695int dvr_wrapper_get_playback_status(DVR_WrapperPlayback_t playback, DVR_WrapperPlaybackStatus_t *status)
1696{
1697 DVR_WrapperCtx_t *ctx;
1698 DVR_WrapperPlaybackStatus_t s;
1699 DVR_PlaybackStatus_t play_status;
1700 int error;
1701
1702 DVR_RETURN_IF_FALSE(playback);
1703 DVR_RETURN_IF_FALSE(status);
1704
1705 ctx = ctx_getPlayback((unsigned long)playback);
1706 DVR_RETURN_IF_FALSE(ctx);
1707
1708 pthread_mutex_lock(&ctx->lock);
1709
1710 DVR_WRAPPER_DEBUG(1, "get playback(sn:%ld) status ...\n", ctx->sn);
1711 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1712
1713 error = dvr_playback_get_status(ctx->playback.player, &play_status);
1714 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) get status (%d)\n", ctx->sn, error);
1715
1716 ctx->playback.seg_status = play_status;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001717 error = process_generatePlaybackStatus(ctx, &s);
1718
hualing chenb5cd42e2020-04-15 17:03:34 +08001719 if (ctx->playback.reach_end == DVR_TRUE && ctx->playback.param_open.is_timeshift == DVR_FALSE) {
1720 //reach end need set full time to cur.so app can exist playback.
1721 DVR_WRAPPER_DEBUG(1, "set cur time to full time, reach end occur");
1722 s.info_cur.time = s.info_full.time;
1723 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001724 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) state/cur/full/obsl(%d/%ld/%ld/%ld) (%d)\n",
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001725 ctx->sn,
1726 s.state,
1727 s.info_cur.time,
1728 s.info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001729 s.info_obsolete.time,
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001730 error);
1731
1732 *status = s;
1733
1734 pthread_mutex_unlock(&ctx->lock);
1735
1736 return error;
1737}
1738
hualing chen266b9502020-04-04 17:39:39 +08001739int dvr_wrapper_set_playback_secure_buffer (DVR_WrapperPlayback_t playback, uint8_t *p_secure_buf, uint32_t len)
1740{
1741 DVR_WrapperCtx_t *ctx;
1742 int error;
1743
1744 DVR_RETURN_IF_FALSE(playback);
1745 DVR_RETURN_IF_FALSE(p_secure_buf);
1746
1747 ctx = ctx_getPlayback((unsigned long)playback);
1748 DVR_RETURN_IF_FALSE(ctx);
1749
1750 pthread_mutex_lock(&ctx->lock);
1751 error = dvr_playback_set_secure_buffer(ctx->playback.player, p_secure_buf, len);
1752 pthread_mutex_unlock(&ctx->lock);
1753 return error;
1754}
1755
1756int dvr_wrapper_set_playback_decrypt_callback (DVR_WrapperPlayback_t playback, DVR_CryptoFunction_t func, void *userdata)
1757{
1758 DVR_WrapperCtx_t *ctx;
1759 int error;
1760
1761 DVR_RETURN_IF_FALSE(playback);
1762 DVR_RETURN_IF_FALSE(func);
1763
1764 ctx = ctx_getPlayback((unsigned long)playback);
1765 DVR_RETURN_IF_FALSE(ctx);
1766
1767 pthread_mutex_lock(&ctx->lock);
1768 error = dvr_playback_set_decrypt_callback(ctx->playback.player, func, userdata);
1769 pthread_mutex_unlock(&ctx->lock);
1770 return error;
1771}
1772
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001773static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata)
1774{
1775 DVR_WrapperEventCtx_t evt;
1776
1777 DVR_RETURN_IF_FALSE(userdata);
1778
1779 evt.sn = (unsigned long)userdata;
1780 evt.type = W_REC;
1781 evt.record.event = event;
1782 evt.record.status = *(DVR_RecordStatus_t *)params;
1783 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, record, evt:0x%x]\n", evt.sn, evt.record.event);
1784 return ctx_addRecordEvent(&evt);
1785}
1786
1787static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata)
1788{
1789 DVR_WrapperEventCtx_t evt;
1790
1791 DVR_RETURN_IF_FALSE(userdata);
1792
1793 evt.sn = (unsigned long)userdata;
1794 evt.type = W_PLAYBACK;
1795 evt.playback.event = event;
1796 evt.playback.status = *(DVR_Play_Notify_t *)params;
1797 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, playbck, evt:0x%x]\n", evt.sn, evt.playback.event);
1798 return ctx_addPlaybackEvent(&evt);
1799}
1800
1801static inline int process_notifyRecord(DVR_WrapperCtx_t *ctx, DVR_RecordEvent_t evt, DVR_WrapperRecordStatus_t *status)
1802{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001803 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 +08001804 ctx->sn,
1805 evt,
1806 status->info.time,
1807 status->info.size,
1808 status->info.pkts,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001809 status->info_obsolete.time,
1810 status->info_obsolete.size,
1811 status->info_obsolete.pkts);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001812
1813 if (ctx->record.event_fn)
1814 return ctx->record.event_fn(evt, status, ctx->record.event_userdata);
1815 return 0;
1816}
1817
1818static inline int record_startNextSegment(DVR_WrapperCtx_t *ctx)
1819{
1820 DVR_RecordStartParams_t param;
1821 DVR_RecordSegmentInfo_t seg_info;
1822 int i;
1823 int error;
1824
1825 memcpy(&param, &ctx->record.param_update, sizeof(param));
1826 memset(&ctx->record.param_update.segment, 0, sizeof(ctx->record.param_update.segment));
1827 ctx->record.param_update.segment.segment_id = ctx->record.next_segment_id++;
1828 for (i = 0; i < param.segment.nb_pids; i++) {
1829 if (param.segment.pid_action[i] != DVR_RECORD_PID_CLOSE) {
1830 ctx->record.param_update.segment.pids[ctx->record.param_update.segment.nb_pids] = param.segment.pids[i];
1831 ctx->record.param_update.segment.pid_action[ctx->record.param_update.segment.nb_pids] = DVR_RECORD_PID_KEEP;
1832 ctx->record.param_update.segment.nb_pids++;
1833 }
1834 }
1835 error = dvr_record_next_segment(ctx->record.recorder, &ctx->record.param_update, &seg_info);
1836 {
1837 DVR_RecordSegmentInfo_t new_seg_info =
1838 { .id = ctx->record.param_update.segment.segment_id, };
1839 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
1840 wrapper_addRecordSegment(ctx, &new_seg_info);
1841 }
1842
Zhiqiang Hand977e972020-05-11 11:30:47 +08001843 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 +08001844 return error;
1845}
1846
1847static inline int record_removeSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *pseg)
1848{
1849 return wrapper_removeRecordSegment(ctx, pseg);
1850}
1851
1852/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001853static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001854{
1855 /*the current seg is not covered in the statistics*/
1856 DVR_WrapperRecordSegmentInfo_t *pseg;
1857
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001858 /*re-calculate the all segments*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001859 memset(&ctx->record.status, 0, sizeof(ctx->record.status));
1860
1861 ctx->record.status.state = ctx->record.seg_status.state;
1862 ctx->record.status.pids.nb_pids = ctx->record.seg_status.info.nb_pids;
1863 memcpy(ctx->record.status.pids.pids,
1864 ctx->record.seg_status.info.pids,
1865 sizeof(ctx->record.status.pids.pids));
1866 ctx->current_segment_id = ctx->record.seg_status.info.id;
1867
1868 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1869 if (pseg->info.id != ctx->record.seg_status.info.id) {
1870 ctx->record.status.info.time += pseg->info.duration;
1871 ctx->record.status.info.size += pseg->info.size;
1872 ctx->record.status.info.pkts += pseg->info.nb_packets;
1873 }
1874 }
1875
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001876 ctx->record.status.info_obsolete = ctx->record.obsolete;
1877
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001878 wrapper_updateRecordSegment(ctx, &ctx->record.seg_status.info, U_ALL);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001879
1880 if (status) {
1881 *status = ctx->record.status;
1882 status->info.time += ctx->record.seg_status.info.duration;
1883 status->info.size += ctx->record.seg_status.info.size;
1884 status->info.pkts += ctx->record.seg_status.info.nb_packets;
1885 }
1886
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001887 return DVR_SUCCESS;
1888}
1889
1890
1891static int process_handleRecordEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
1892{
1893 DVR_WrapperRecordStatus_t status;
1894
1895 memset(&status, 0, sizeof(status));
1896
1897 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d)\n",
1898 evt->sn, evt->record.event, evt->record.status.state);
hualing chend3b55ab2021-05-06 09:56:27 +08001899 if (ctx->record.param_update.segment.segment_id != evt->record.status.info.id) {
1900 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) cur id:0x%x (event id:%d)\n",
Gong Ke2a0ebbe2021-05-25 15:22:50 +08001901 evt->sn, (int)ctx->record.param_update.segment.segment_id, (int)evt->record.status.info.id);
hualing chend3b55ab2021-05-06 09:56:27 +08001902 return 0;
1903 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001904 switch (evt->record.event)
1905 {
1906 case DVR_RECORD_EVENT_STATUS:
1907 {
1908 switch (evt->record.status.state)
1909 {
1910 case DVR_RECORD_STATE_OPENED:
1911 case DVR_RECORD_STATE_CLOSED:
1912 {
1913 ctx->record.seg_status = evt->record.status;
1914
1915 status.state = evt->record.status.state;
1916 process_notifyRecord(ctx, evt->record.event, &status);
1917 } break;
1918 case DVR_RECORD_STATE_STARTED:
1919 {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001920 ctx->record.seg_status = evt->record.status;
1921
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001922 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001923 process_notifyRecord(ctx, evt->record.event, &status);
1924
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001925 /*restart to next segment*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001926 if (ctx->record.param_open.segment_size
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001927 && evt->record.status.info.size >= ctx->record.param_open.segment_size) {
1928 DVR_WRAPPER_DEBUG(1, "start new segment for record(%lu), reaches segment size limit, cur(%zu) max(%lld)\n",
1929 ctx->sn,
1930 evt->record.status.info.size,
1931 ctx->record.param_open.segment_size);
Zhiqiang Hand977e972020-05-11 11:30:47 +08001932 if (record_startNextSegment(ctx) != DVR_SUCCESS) {
1933 /*should notify the recording's stop*/
1934 int error = dvr_record_close(ctx->record.recorder);
1935 DVR_WRAPPER_DEBUG(1, "stop record(%lu)=%d, failed to start new segment for recording.",
1936 ctx->sn, error);
1937 status.state = DVR_RECORD_STATE_CLOSED;
1938 process_notifyRecord(ctx, DVR_RECORD_EVENT_WRITE_ERROR, &status);
1939 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001940 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001941
1942 if (ctx->record.param_open.is_timeshift
1943 && ctx->record.param_open.max_time
1944 && status.info.time >= ctx->record.param_open.max_time) {
1945 DVR_WrapperRecordSegmentInfo_t *pseg;
1946
1947 /*as the player do not support null playlist,
1948 there must be one segment existed at any time,
1949 we have to keep two segments before remove one*/
1950 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
1951 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
1952 /*only one segment, waiting for more*/
1953 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of max_time(%ld) of record < max size of segment(%lld)\n",
1954 status.info.size,
1955 ctx->record.param_open.max_time,
1956 ctx->record.param_open.segment_size);
1957 } else {
1958 /*timeshifting, remove the 1st segment and notify the player*/
1959 record_removeSegment(ctx, pseg);
1960
1961 process_generateRecordStatus(ctx, &status);
1962 process_notifyRecord(ctx, evt->record.event, &status);
1963 }
1964 }
1965
1966 if (ctx->record.param_open.is_timeshift
1967 && ctx->record.param_open.max_size
1968 && status.info.size >= ctx->record.param_open.max_size) {
1969 DVR_WrapperRecordSegmentInfo_t *pseg;
1970
1971 /*as the player do not support null playlist,
1972 there must be one segment existed at any time,
1973 we have to keep two segments before remove one*/
1974 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
1975 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
1976 /*only one segment, waiting for more*/
1977 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of record < max size of segment(%lld)\n",
1978 status.info.size,
1979 ctx->record.param_open.segment_size);
1980 } else {
1981 record_removeSegment(ctx, pseg);
1982
1983 process_generateRecordStatus(ctx, &status);
1984 process_notifyRecord(ctx, evt->record.event, &status);
1985 }
1986 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001987 } break;
1988 case DVR_RECORD_STATE_STOPPED:
1989 {
1990 ctx->record.seg_status = evt->record.status;
1991
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001992 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001993 process_notifyRecord(ctx, evt->record.event, &status);
1994 } break;
1995 default:
1996 break;
1997 }
1998 } break;
hualing chen4b7c15d2020-04-07 16:13:48 +08001999 case DVR_RECORD_EVENT_WRITE_ERROR: {
2000 ctx->record.seg_status = evt->record.status;
2001 status.state = evt->record.status.state;
2002 process_notifyRecord(ctx, evt->record.event, &status);
2003 }break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002004 default:
2005 break;
2006 }
2007 return DVR_SUCCESS;
2008}
2009
2010static inline int process_notifyPlayback(DVR_WrapperCtx_t *ctx, DVR_PlaybackEvent_t evt, DVR_WrapperPlaybackStatus_t *status)
2011{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002012 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 +08002013 ctx->sn,
2014 evt,
2015 status->state,
2016 status->info_cur.time,
2017 status->info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002018 status->info_obsolete.time);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002019
2020 if (ctx->playback.event_fn)
2021 return ctx->playback.event_fn(evt, status, ctx->playback.event_userdata);
2022 return 0;
2023}
2024
2025/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002026static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperPlaybackStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002027{
2028 /*the current seg is not covered in the statistics*/
2029 DVR_WrapperPlaybackSegmentInfo_t *pseg;
2030
2031 memset(&ctx->playback.status, 0, sizeof(ctx->playback.status));
2032 ctx->playback.status.pids = ctx->playback.pids_req;
2033
2034 ctx->playback.status.state = ctx->playback.seg_status.state;
2035 ctx->playback.status.speed = ctx->playback.seg_status.speed;
2036 ctx->playback.status.flags = ctx->playback.seg_status.flags;
2037 ctx->current_segment_id = ctx->playback.seg_status.segment_id;
2038
2039 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2040 if (pseg->seg_info.id == ctx->playback.seg_status.segment_id)
2041 break;
2042 ctx->playback.status.info_cur.time += pseg->seg_info.duration;
2043 ctx->playback.status.info_cur.size += pseg->seg_info.size;
2044 ctx->playback.status.info_cur.pkts += pseg->seg_info.nb_packets;
2045 }
2046 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2047 ctx->playback.status.info_full.time += pseg->seg_info.duration;
2048 ctx->playback.status.info_full.size += pseg->seg_info.size;
2049 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
2050 }
2051
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002052 if (status) {
2053 *status = ctx->playback.status;
2054 /*deal with current, lack size and pkts with the current*/
2055 status->info_cur.time += ctx->playback.seg_status.time_cur;
2056 status->info_obsolete.time = ctx->playback.obsolete.time;
2057 }
2058
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002059 return DVR_SUCCESS;
2060}
2061
2062static int process_handlePlaybackEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2063{
2064 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d) cur(%lld:%u/%u)\n",
2065 evt->sn, evt->playback.event,
2066 evt->playback.status.play_status.state,
2067 evt->playback.status.play_status.segment_id,
2068 evt->playback.status.play_status.time_cur,
2069 evt->playback.status.play_status.time_end);
2070
2071 /*evt PLAYTIME will break the last logic, do not save*/
hualing chene3797f02021-01-13 14:53:28 +08002072 if (evt->playback.event != DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME
2073 && evt->playback.event != DVR_PLAYBACK_EVENT_NODATA
2074 && evt->playback.event != DVR_PLAYBACK_EVENT_DATARESUME
2075 )
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002076 ctx->playback.last_event = evt->playback.event;
2077
2078 switch (evt->playback.event)
2079 {
2080 case DVR_PLAYBACK_EVENT_FIRST_FRAME:
2081 case DVR_PLAYBACK_EVENT_REACHED_END:
2082 case DVR_PLAYBACK_EVENT_TRANSITION_OK:
2083 case DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME:
hualing chenb5cd42e2020-04-15 17:03:34 +08002084 case DVR_PLAYBACK_EVENT_ERROR:
hualing chenf291cf32020-06-18 10:50:30 +08002085 case DVR_PLAYBACK_EVENT_REACHED_BEGIN:
hualing chene3797f02021-01-13 14:53:28 +08002086 case DVR_PLAYBACK_EVENT_NODATA:
2087 case DVR_PLAYBACK_EVENT_DATARESUME:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002088 {
2089 DVR_WrapperPlaybackStatus_t status;
2090
2091 /*copy status of segment*/
2092 ctx->playback.seg_status = evt->playback.status.play_status;
2093
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002094 /*generate status of the whole playback*/
2095 process_generatePlaybackStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002096
2097 if (evt->playback.event == DVR_PLAYBACK_EVENT_REACHED_END) {
2098 if (ctx->playback.param_open.is_timeshift) {
2099 /*wait for more data in recording*/
2100 } else if ((status.info_cur.time + DVR_PLAYBACK_END_GAP) >= ctx->playback.status.info_full.time) {
2101 process_notifyPlayback(ctx, evt->playback.event, &status);
hualing chenb5cd42e2020-04-15 17:03:34 +08002102 } else {
2103 ctx->playback.reach_end = DVR_TRUE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002104 }
hualing chenf291cf32020-06-18 10:50:30 +08002105 } else if (evt->playback.event != DVR_PLAYBACK_EVENT_REACHED_BEGIN) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002106 process_notifyPlayback(ctx, evt->playback.event, &status);
2107 }
2108 } break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002109 case DVR_PLAYBACK_EVENT_TRANSITION_FAILED:
2110 case DVR_PLAYBACK_EVENT_KEY_FAILURE:
2111 case DVR_PLAYBACK_EVENT_NO_KEY:
2112 {
2113 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) error event:0x%x\n", evt->sn, evt->playback.event);
2114 } break;
2115 default:
2116 {
2117 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) unknown event:0x%x\n", evt->sn, evt->playback.event);
2118 } break;
2119 }
2120 return 0;
2121}
2122
2123static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2124{
2125 return (evt->type == W_REC)? process_handleRecordEvent(evt, ctx) : process_handlePlaybackEvent(evt, ctx);
2126}
2127