blob: 83802fda48112b5e38b4ae12c36c893ae3f266e9 [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>
7
8#include "dvr_types.h"
9#include "dvr_record.h"
10#include "dvr_crypto.h"
11#include "dvr_playback.h"
12#include "dvr_segment.h"
13
14#include "AmTsPlayer.h"
15
16#include "list.h"
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080017
18#include "dvr_wrapper.h"
19
Gong Ke2a0ebbe2021-05-25 15:22:50 +080020#define DVR_WRAPPER_DEBUG(_level, _fmt...) \
21 DVR_DEBUG_FL(_level, "wrapper", _fmt)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080022
23/*duration of data to resume if paused with EVT_REACHED_END in timeshifting*/
hualing chen2932d372020-04-29 13:44:00 +080024#define TIMESHIFT_DATA_DURATION_TO_RESUME (600)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080025/*a tolerant gap*/
26#define DVR_PLAYBACK_END_GAP (1000)
27
28enum {
29 W_REC = 1,
30 W_PLAYBACK = 2,
31};
32
33enum {
34 U_PIDS = 0x01,
35 U_STAT = 0x02,
36 U_ALL = U_PIDS | U_STAT,
37};
38
39typedef struct {
40 /*make lock the 1st item in the structure*/
41 pthread_mutex_t lock;
42
43 /*rec or play*/
44 int type;
45
46 /*valid if (sn != 0)*/
47 unsigned long sn;
48 unsigned long sn_linked;
49
50 struct list_head segments; /**<head-add list*/
51 uint64_t current_segment_id; /**<id of the current segment*/
52
53 union {
54 struct {
55 DVR_WrapperRecordOpenParams_t param_open;
56 DVR_RecordStartParams_t param_start;
57 DVR_RecordStartParams_t param_update;
58 DVR_RecordHandle_t recorder;
59 DVR_RecordEventFunction_t event_fn;
60 void *event_userdata;
61
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080062 /*total status = seg_status + status + obsolete*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080063 DVR_RecordStatus_t seg_status; /**<status of current segment*/
64 DVR_WrapperRecordStatus_t status; /**<status of remaining segments*/
65 uint64_t next_segment_id;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080066
67 DVR_WrapperInfo_t obsolete; /**<data obsolete due to the max limit*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080068 } record;
69
70 struct {
71 DVR_WrapperPlaybackOpenParams_t param_open;
72 DVR_PlaybackHandle_t player;
73 DVR_PlaybackEventFunction_t event_fn;
74 void *event_userdata;
75
76 /*total status = seg_status + status*/
77 DVR_PlaybackStatus_t seg_status;
78 DVR_WrapperPlaybackStatus_t status;
79 DVR_PlaybackPids_t pids_req;
80 DVR_PlaybackEvent_t last_event;
Zhiqiang Han3eb75f92020-04-08 10:07:55 +080081 float speed;
hualing chenb5cd42e2020-04-15 17:03:34 +080082 DVR_Bool_t reach_end;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080083
84 DVR_WrapperInfo_t obsolete;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080085 } playback;
86 };
87} DVR_WrapperCtx_t;
88
89typedef struct {
90 struct list_head head;
91 unsigned long sn;
92
93 /* rec or playback */
94 int type;
95
96 union {
97 struct {
98 DVR_RecordEvent_t event;
99 DVR_RecordStatus_t status;
100 } record;
101 struct {
102 DVR_PlaybackEvent_t event;
103 DVR_Play_Notify_t status;
104 } playback;
105 };
106} DVR_WrapperEventCtx_t;
107
108typedef struct {
109 pthread_mutex_t lock;
110 char *name;
111 int running;
112 pthread_cond_t cond;
113 pthread_t thread;
114 int type;
115} DVR_WrapperThreadCtx_t;
116
117typedef struct {
118 struct list_head head;
119
120 DVR_RecordSegmentInfo_t seg_info;
121 DVR_PlaybackSegmentInfo_t playback_info;
122} DVR_WrapperPlaybackSegmentInfo_t;
123
124typedef struct {
125 struct list_head head;
126
127 DVR_RecordSegmentInfo_t info;
128} DVR_WrapperRecordSegmentInfo_t;
129
130/* serial num generater */
131static unsigned long sn = 1;
132static pthread_mutex_t sn_lock = PTHREAD_MUTEX_INITIALIZER;
133
134static inline unsigned long get_sn()
135{
136 unsigned long no;
137
138 pthread_mutex_lock(&sn_lock);
139 no = sn++;
140 if (!no)
141 no = sn++;
142 pthread_mutex_unlock(&sn_lock);
143
144 return no;
145}
146
147/* entity ctx */
148#define DVR_WRAPPER_MAX 10
149
150static DVR_WrapperCtx_t record_list[DVR_WRAPPER_MAX] =
151{
152 [0 ... (DVR_WRAPPER_MAX - 1)] =
153 {
154 .lock = PTHREAD_MUTEX_INITIALIZER,
155 .type = W_REC,
156 }
157};
158
159static DVR_WrapperCtx_t playback_list[DVR_WRAPPER_MAX] =
160{
161 [0 ... (DVR_WRAPPER_MAX - 1)] =
162 {
163 .lock = PTHREAD_MUTEX_INITIALIZER,
164 .type = W_PLAYBACK,
165 }
166};
167
168/* events lists */
169static struct list_head record_evt_list = LIST_HEAD_INIT(record_evt_list);
170static struct list_head playback_evt_list = LIST_HEAD_INIT(playback_evt_list);
171
172static pthread_mutex_t record_evt_list_lock = PTHREAD_MUTEX_INITIALIZER;
173static pthread_mutex_t playback_evt_list_lock = PTHREAD_MUTEX_INITIALIZER;
174
175static DVR_WrapperThreadCtx_t wrapper_thread[2] =
176{
177 [0] =
178 {
179 .lock = PTHREAD_MUTEX_INITIALIZER,
180 .running = 0,
181 .name = "record",
182 .type = W_REC,
183 },
184 [1] =
185 {
186 .lock = PTHREAD_MUTEX_INITIALIZER,
187 .running = 0,
188 .name = "playback",
189 .type = W_PLAYBACK,
190 },
191};
192
193/*now only support one timeshift now*/
194static unsigned long sn_timeshift_record;
195static unsigned long sn_timeshift_playback;
196
197static void *wrapper_task(void *arg);
198static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx);
199
200static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata);
201static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata);
202
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800203static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordStatus_t *status);
204static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperPlaybackStatus_t *status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800205
206
207static DVR_WrapperEventCtx_t *ctx_getEvent(struct list_head *list, pthread_mutex_t *list_lock)
208{
209 DVR_WrapperEventCtx_t *pevt;
210
211 pthread_mutex_lock(list_lock);
212 if (list_empty(list))
213 pevt = NULL;
214 else {
215 pevt = list_first_entry(list, DVR_WrapperEventCtx_t, head);
216 list_del(&pevt->head);
217 }
218 pthread_mutex_unlock(list_lock);
219
220 return pevt;
221}
222
223static inline DVR_WrapperEventCtx_t *ctx_getRecordEvent()
224{
225 return ctx_getEvent(&record_evt_list, &record_evt_list_lock);
226}
227
228static inline DVR_WrapperEventCtx_t *ctx_getPlaybackEvent()
229{
230 return ctx_getEvent(&playback_evt_list, &playback_evt_list_lock);
231}
232
233static int ctx_addEvent(struct list_head *list, pthread_mutex_t *lock, DVR_WrapperEventCtx_t *evt)
234{
235 DVR_WrapperEventCtx_t *padd;
236 padd = (DVR_WrapperEventCtx_t *)calloc(1, sizeof(DVR_WrapperEventCtx_t));
237 DVR_RETURN_IF_FALSE(padd);
238
239 *padd = *evt;
240 pthread_mutex_lock(lock);
241 list_add_tail(&padd->head, list);
242 pthread_mutex_unlock(lock);
243 return DVR_SUCCESS;
244}
245
246static inline void ctx_freeEvent(DVR_WrapperEventCtx_t *evt)
247{
248 free(evt);
249}
250
251/*useless*/
252static void ctx_cleanOutdatedEvents(struct list_head *evt_list,
253 pthread_mutex_t *evt_list_lock,
254 DVR_WrapperCtx_t *list)
255{
256 DVR_WrapperEventCtx_t *pevt, *pevt_tmp;
257 unsigned long sns[DVR_WRAPPER_MAX];
258 int cnt = 0;
259 int i;
260 int found = 0;
261
262 /*copy all valid sns*/
263 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
264 sns[cnt] = list[i].sn;
265 if (!sns[cnt])
266 cnt++;
267 }
268
269 /*free evts that not belong to any valid sns*/
270 pthread_mutex_lock(evt_list_lock);
271 list_for_each_entry_safe(pevt, pevt_tmp, evt_list, head) {
272 for (i = 0; i < cnt; i++) {
273 if (pevt->sn == sns[i]) {
274 found = 1;
275 break;
276 }
277 }
278 if (!found) {
279 list_del(&pevt->head);
280 ctx_freeEvent(pevt);
281 }
282 }
283 pthread_mutex_unlock(evt_list_lock);
284}
285
286static inline void ctx_cleanOutdatedRecordEvents()
287{
288 ctx_cleanOutdatedEvents(&record_evt_list, &record_evt_list_lock, record_list);
289}
290
291static inline void ctx_cleanOutdatedPlaybackEvents()
292{
293 ctx_cleanOutdatedEvents(&playback_evt_list, &playback_evt_list_lock, playback_list);
294}
295
296static inline DVR_WrapperCtx_t *ctx_get(unsigned long sn, DVR_WrapperCtx_t *list)
297{
298 int i;
299 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
300 if (list[i].sn == sn)
301 return &list[i];
302 }
303 return NULL;
304}
305
306static inline void ctx_reset(DVR_WrapperCtx_t *ctx)
307{
308 memset((char *)ctx + offsetof(DVR_WrapperCtx_t, sn),
309 0,
310 sizeof(DVR_WrapperCtx_t) - offsetof(DVR_WrapperCtx_t, sn));
311}
312
313static inline int ctx_valid(DVR_WrapperCtx_t *ctx)
314{
315 return (ctx->sn != 0);
316}
317
318static inline DVR_WrapperCtx_t *ctx_getRecord(unsigned long sn)
319{
320 return ctx_get(sn, record_list);
321}
322
323static inline DVR_WrapperCtx_t *ctx_getPlayback(unsigned long sn)
324{
325 return ctx_get(sn, playback_list);
326}
327
328static int wrapper_requestThread(DVR_WrapperThreadCtx_t *ctx, void *(thread_fn)(void *))
329{
330 pthread_mutex_lock(&ctx->lock);
331 if (ctx->running == 0) {
332 pthread_condattr_t attr;
333 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
334 pthread_cond_init(&ctx->cond, &attr);
335 pthread_condattr_destroy(&attr);
336 DVR_WRAPPER_DEBUG(1, "start wrapper thread(%s) ...\n", ctx->name);
337 pthread_create(&ctx->thread, NULL, thread_fn, ctx);
338 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) started\n", ctx->name);
339 }
340 ctx->running++;
341 pthread_mutex_unlock(&ctx->lock);
342 return 0;
343}
344
345static int wrapper_releaseThread(DVR_WrapperThreadCtx_t *ctx)
346{
347 pthread_mutex_lock(&ctx->lock);
348 ctx->running--;
349 if (!ctx->running) {
350 pthread_cond_broadcast(&ctx->cond);
351 pthread_mutex_unlock(&ctx->lock);
352
353 DVR_WRAPPER_DEBUG(1, "stop wrapper thread(%s) ...\n", ctx->name);
354 pthread_join(ctx->thread, NULL);
355 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) stopped\n", ctx->name);
356
357 pthread_mutex_lock(&ctx->lock);
358 if (!ctx->running) /*protect*/
359 pthread_cond_destroy(&ctx->cond);
360 }
361 pthread_mutex_unlock(&ctx->lock);
362 return 0;
363}
364
365#define WRAPPER_THREAD_RECORD (&wrapper_thread[0])
366#define WRAPPER_THREAD_PLAYBACK (&wrapper_thread[1])
367
368static inline int wrapper_requestThreadFor(DVR_WrapperCtx_t *ctx)
369{
370 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
371 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
372 return wrapper_requestThread(thread_ctx, wrapper_task);
373}
374
375static inline int wrapper_releaseThreadFor(DVR_WrapperCtx_t *ctx)
376{
377 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
378 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
379 return wrapper_releaseThread(thread_ctx);
380}
381
382static inline int wrapper_releaseThreadForType(int type)
383{
384 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC)?
385 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
386 return wrapper_releaseThread(thread_ctx);
387}
388
389static inline void wrapper_threadSignal(DVR_WrapperThreadCtx_t *thread_ctx)
390{
391 pthread_cond_signal(&thread_ctx->cond);
392}
393
394static inline int wrapper_threadWait(DVR_WrapperThreadCtx_t *thread_ctx)
395{
396 pthread_cond_wait(&thread_ctx->cond, &thread_ctx->lock);
397 return 0;
398}
399
400static inline void wrapper_threadSignalForType(int type)
401{
402 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC) ?
403 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
404 wrapper_threadSignal(thread_ctx);
405}
406
407static inline void wrapper_threadSignalFor(DVR_WrapperCtx_t *ctx)
408{
409 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
410 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
411 wrapper_threadSignal(thread_ctx);
412}
413
414static inline int wrapper_threadWaitFor(DVR_WrapperCtx_t *ctx)
415{
416 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
417 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
418 wrapper_threadWait(thread_ctx);
419 return 0;
420}
421
422static void get_timeout_real(int timeout, struct timespec *ts)
423{
424 struct timespec ots;
425 int left, diff;
426
427 clock_gettime(CLOCK_REALTIME, &ots);
428
429 ts->tv_sec = ots.tv_sec + timeout/1000;
430 ts->tv_nsec = ots.tv_nsec;
431
432 left = timeout % 1000;
433 left *= 1000000;
434 diff = 1000000000-ots.tv_nsec;
435
436 if (diff <= left) {
437 ts->tv_sec++;
438 ts->tv_nsec = left-diff;
439 } else {
440 ts->tv_nsec += left;
441 }
442}
443
444/*return condition, locked if condition == true*/
445static int wrapper_mutex_lock_if(pthread_mutex_t *lock, int *condition)
446{
447 int r2;
448 do {
449 struct timespec rt2;
450 /*android use real time for mutex timedlock*/
451 get_timeout_real(10, &rt2);
452 r2 = pthread_mutex_timedlock(lock, &rt2);
453 } while (*condition && (r2 == ETIMEDOUT));
454
455 if (!(*condition) && (r2 == 0))
456 pthread_mutex_unlock(lock);
457
458 return *condition;
459}
460
461static void *wrapper_task(void *arg)
462{
463 DVR_WrapperThreadCtx_t *tctx = (DVR_WrapperThreadCtx_t *)arg;
464 DVR_WrapperEventCtx_t *evt;
465
466 pthread_mutex_lock(&tctx->lock);
467
468 while (tctx->running) {
469 {
470 int ret;
hualing chene3797f02021-01-13 14:53:28 +0800471
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800472 ret = wrapper_threadWait(tctx);
473 }
474
475 while ((evt = ((tctx->type == W_REC)? ctx_getRecordEvent() : ctx_getPlaybackEvent()))) {
476 DVR_WrapperCtx_t *ctx = (evt->type == W_REC)?
477 ctx_getRecord(evt->sn) : ctx_getPlayback(evt->sn);
hualing chenbc0aec92021-03-18 14:52:40 +0800478 if (ctx == NULL) {
479 DVR_WRAPPER_DEBUG(1, "warp not get ctx.free event..\n");
480 goto processed;
481 }
Gong Ke2a0ebbe2021-05-25 15:22:50 +0800482 DVR_WRAPPER_DEBUG(1, "start name(%s) sn(%d) runing(%d) type(%d)event end...\n", tctx->name, (int)ctx->sn, tctx->running, tctx->type);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800483 if (tctx->running) {
484 /*
485 continue not break,
486 make all events consumed, or mem leak
487 */
488 if (!wrapper_mutex_lock_if(&ctx->lock, &tctx->running))
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800489 goto processed;
490
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800491 if (ctx_valid(ctx)) {
492 /*double check after lock*/
493 if (evt->sn == ctx->sn)
494 process_handleEvents(evt, ctx);
495 }
496 pthread_mutex_unlock(&ctx->lock);
497 }
498
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800499processed:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800500 ctx_freeEvent(evt);
501 }
Gong Ke2a0ebbe2021-05-25 15:22:50 +0800502 DVR_WRAPPER_DEBUG(1, "start name(%s) runing(%d) type(%d)event con...\n", tctx->name, tctx->running, tctx->type);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800503 }
504
505 pthread_mutex_unlock(&tctx->lock);
hualing chene3797f02021-01-13 14:53:28 +0800506 DVR_WRAPPER_DEBUG(1, "end name(%s) runing(%d) type(%d)event end...\n", tctx->name, tctx->running, tctx->type);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800507 return NULL;
508}
509
510static inline int ctx_addRecordEvent(DVR_WrapperEventCtx_t *evt)
511{
512 if (ctx_addEvent(&record_evt_list, &record_evt_list_lock, evt) == 0)
513 wrapper_threadSignalForType(evt->type);
514 return 0;
515}
516
517static inline int ctx_addPlaybackEvent(DVR_WrapperEventCtx_t *evt)
518{
519 if (ctx_addEvent(&playback_evt_list, &playback_evt_list_lock, evt) == 0)
520 wrapper_threadSignalForType(evt->type);
521 return 0;
522}
523
524static inline void ctx_freeSegments(DVR_WrapperCtx_t *ctx)
525{
526 DVR_WrapperPlaybackSegmentInfo_t *pseg, *pseg_tmp;
527 list_for_each_entry_safe(pseg, pseg_tmp, &ctx->segments, head) {
528 list_del(&pseg->head);
529 free(pseg);
530 }
531}
532
533static inline void _updatePlaybackSegment(DVR_WrapperPlaybackSegmentInfo_t *pseg,
534 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
535{
536 (void)ctx;
537 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
538 pseg->seg_info = *seg_info;
539 else if (update_flags & U_PIDS) {
540 pseg->seg_info.nb_pids = seg_info->nb_pids;
541 memcpy(pseg->seg_info.pids, seg_info->pids, sizeof(pseg->seg_info.pids));
542 } else if (update_flags & U_STAT) {
543 pseg->seg_info.duration = seg_info->duration;
544 pseg->seg_info.size = seg_info->size;
545 pseg->seg_info.nb_packets = seg_info->nb_packets;
546 }
547
548 /*no changes
549 DVR_PlaybackSegmentFlag_t flags;
550 pseg->playback_info.segment_id = pseg->seg_info.id;
551 strncpy(pseg->playback_info.location,
552 ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
553 pseg->playback_info.pids = ctx->playback.pids_req;
554 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
555 if (ctx->record.param_open.flags | DVR_RECORD_FLAG_SCRAMBLED)
556 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
557 pseg->playback_info.flags = flags;
558 */
559}
560
561static int wrapper_updatePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
562{
563 DVR_WrapperPlaybackSegmentInfo_t *pseg;
564
565 DVR_WRAPPER_DEBUG(1, "timeshift, update playback segments(wrapper), seg:%lld t/s/p(%ld/%zu/%u)\n",
566 seg_info->id, seg_info->duration, seg_info->size, seg_info->nb_packets);
567
568 if (list_empty(&ctx->segments)) {
569 DVR_WRAPPER_DEBUG(1, "timeshift, update while no segment exists, ignore\n");
570 return DVR_SUCCESS;
571 }
572
573 /*normally, the last segment added will be updated*/
574 pseg =
575 list_first_entry(&ctx->segments, DVR_WrapperPlaybackSegmentInfo_t, head);
576 if (pseg->seg_info.id == seg_info->id) {
577 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
578 } else {
579 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
580 if (pseg->seg_info.id == seg_info->id) {
581 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
582 break;
583 }
584 }
585 }
586
587 /*need to notify the dvr_playback*/
588 if (ctx->playback.param_open.is_timeshift/*should must be timeshift*/
589 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END
590 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
591 if (
592 /*there's $TIMESHIFT_DATA_DURATION_TO_RESUME more of data in the current segment playing*/
593 (ctx->playback.seg_status.segment_id == seg_info->id
594 && (seg_info->duration >= ((time_t)ctx->playback.seg_status.time_cur + TIMESHIFT_DATA_DURATION_TO_RESUME)))
595 ||
596 /*or there's a new segment and has $TIMESHIFT_DATA_DURATION_TO_RESUME of data*/
597 (ctx->playback.seg_status.segment_id != seg_info->id
598 && (seg_info->duration >= TIMESHIFT_DATA_DURATION_TO_RESUME))
599 )
600 {
601 int error;
hualing chen36e0dfd2020-05-02 16:33:06 +0800602 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +0800603 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +0800604 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800605
606 error = dvr_playback_resume(ctx->playback.player);
607 DVR_WRAPPER_DEBUG(1, "timeshift, resume playback(sn:%ld) (%d) id/dur: rec(%lld/%ld) play(%lld/%u)\n",
608 ctx->sn, error,
609 seg_info->id, seg_info->duration,
610 ctx->playback.seg_status.segment_id, ctx->playback.seg_status.time_cur);
611 }
612 }
613
614 return DVR_SUCCESS;
615}
616
617static void _updateRecordSegment(DVR_WrapperRecordSegmentInfo_t *pseg,
618 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
619{
620 (void)ctx;
621 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
622 pseg->info = *seg_info;
623 else if (update_flags & U_PIDS) {
624 pseg->info.nb_pids = seg_info->nb_pids;
625 memcpy(pseg->info.pids, seg_info->pids, sizeof(pseg->info.pids));
626 } else if (update_flags & U_STAT) {
627 pseg->info.duration = seg_info->duration;
628 pseg->info.size = seg_info->size;
629 pseg->info.nb_packets = seg_info->nb_packets;
630 }
631}
632
633static int wrapper_updateRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
634{
hualing chen266b9502020-04-04 17:39:39 +0800635 DVR_WrapperRecordSegmentInfo_t *pseg = NULL;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800636
637 /*normally, the last segment added will be updated*/
hualing chen266b9502020-04-04 17:39:39 +0800638 if (!list_empty(&ctx->segments)) {
639 pseg =
640 list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
641 if (pseg->info.id == seg_info->id) {
642 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
643 } else {
644 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
645 if (pseg->info.id == seg_info->id) {
646 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
647 break;
648 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800649 }
650 }
651 }
652
653 /*timeshift, update the segment for playback*/
654 /*
655 the playback should grab the segment info other than the id,
656 and the id will be updated by each segment-add during the recording
657 */
658 /*
659 the playback paused if no data been checked from recording,
660 should resume the player later when there's more data
661 */
662
663 if (ctx->record.param_open.is_timeshift) {
664 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
665
666 if (ctx_playback) {
667 pthread_mutex_lock(&ctx_playback->lock);
668 if (ctx_valid(ctx_playback)
669 && ctx_playback->sn == sn_timeshift_playback) {
670 wrapper_updatePlaybackSegment(ctx_playback, seg_info, update_flags);
671 }
672 pthread_mutex_unlock(&ctx_playback->lock);
673 }
674 }
675
676 return DVR_SUCCESS;
677}
678
679static int wrapper_addPlaybackSegment(DVR_WrapperCtx_t *ctx,
680 DVR_RecordSegmentInfo_t *seg_info,
681 DVR_PlaybackPids_t *p_pids,
682 DVR_PlaybackSegmentFlag_t flags)
683{
684 DVR_WrapperPlaybackSegmentInfo_t *pseg;
685 int error;
686
687 error = 0;
688 pseg = (DVR_WrapperPlaybackSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperPlaybackSegmentInfo_t));
689 if (!pseg) {
690 error = DVR_FAILURE;
691 DVR_WRAPPER_DEBUG(1, "memory fail\n");
692 return error;
693 }
694
695 /*copy the orignal segment info*/
696 pseg->seg_info = *seg_info;
697 /*generate the segment info used in playback*/
698 pseg->playback_info.segment_id = pseg->seg_info.id;
699 strncpy(pseg->playback_info.location, ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
700 pseg->playback_info.pids = *p_pids;
701 pseg->playback_info.flags = flags;
702 list_add(&pseg->head, &ctx->segments);
703
704 error = dvr_playback_add_segment(ctx->playback.player, &pseg->playback_info);
705 if (error) {
706 DVR_WRAPPER_DEBUG(1, "fail to add segment %lld (%d)\n", pseg->playback_info.segment_id, error);
707 } else {
708 ctx->playback.status.info_full.time += pseg->seg_info.duration;
709 ctx->playback.status.info_full.size += pseg->seg_info.size;
710 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
711 }
712
713 return error;
714}
715
716static int wrapper_addRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
717{
718 DVR_WrapperRecordSegmentInfo_t *pseg;
719 int error;
720
721 error = 0;
722 pseg = (DVR_WrapperRecordSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperRecordSegmentInfo_t));
723 if (!pseg) {
724 error = DVR_FAILURE;
725 DVR_WRAPPER_DEBUG(1, "memory fail\n");
726 }
727 pseg->info = *seg_info;
728 list_add(&pseg->head, &ctx->segments);
729
730 if (ctx->record.param_open.is_timeshift) {
731 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
732
733 if (ctx_playback) {
734 pthread_mutex_lock(&ctx_playback->lock);
735 if (ctx_valid(ctx_playback)) {
736 DVR_PlaybackSegmentFlag_t flags;
737
738 /*only if playback has started, the previous segments have been loaded*/
739 if (!list_empty(&ctx_playback->segments)) {
740 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
Gong Ke2a0ebbe2021-05-25 15:22:50 +0800741 if (ctx->record.param_open.flags & DVR_RECORD_FLAG_SCRAMBLED)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800742 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
743 wrapper_addPlaybackSegment(ctx_playback, seg_info, &ctx_playback->playback.pids_req, flags);
744 }
745 }
746 pthread_mutex_unlock(&ctx_playback->lock);
747 }
Zhiqiang Hane0a1c382021-06-08 11:28:05 +0800748 } else {
749 dvr_segment_link_op(ctx->record.param_open.location, 1, &seg_info->id, LSEG_OP_ADD);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800750 }
751
752 return error;
753}
754
755static int wrapper_removePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
756{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800757 int error = -1;
758 DVR_WrapperPlaybackSegmentInfo_t *pseg = NULL, *pseg_tmp;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800759
760 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->id);
761
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800762 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800763 if (pseg->seg_info.id == seg_info->id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800764
765 if (ctx->current_segment_id == seg_info->id) {
766 DVR_WrapperPlaybackSegmentInfo_t *next_seg;
767
768 /*drive the player out of this will-be-deleted segment*/
769 next_seg = list_prev_entry(pseg, head);
770
771 if (ctx->playback.speed != 100.0f) {
772 error = dvr_playback_resume(ctx->playback.player);
773 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), resume for new start (%d)\n", ctx->sn, error);
774 }
775
776 error = dvr_playback_seek(ctx->playback.player, next_seg->seg_info.id, 0);
777 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);
778
779 if (ctx->playback.speed == 0.0f) {
780 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
781 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last paused from new start (%d)\n", ctx->sn, error);
782 } else if (ctx->playback.speed != 100.0f) {
783 DVR_PlaybackSpeed_t dvr_speed = {
784 .speed = { ctx->playback.speed },
785 .mode = ( ctx->playback.speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
786 };
787 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
788 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last speed(x%f) from new start (%d)\n", ctx->sn,ctx->playback.speed, error);
789 }
790 }
791
792 error = dvr_playback_remove_segment(ctx->playback.player, seg_info->id);
793 if (error) {
794 /*remove playack segment fail*/
795 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), failed to remove segment(%llu) (%d)\n", ctx->sn, seg_info->id, error);
796 }
797
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800798 list_del(&pseg->head);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800799
800 /*record the obsolete*/
801 ctx->playback.obsolete.time += pseg->seg_info.duration;
802 ctx->playback.obsolete.size += pseg->seg_info.size;
803 ctx->playback.obsolete.pkts += pseg->seg_info.nb_packets;
804
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800805 free(pseg);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800806 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800807 }
808 }
809
810 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->id, error);
811
812 return error;
813}
814
815static int wrapper_removeRecordSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *seg_info)
816{
817 int error;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800818 DVR_WrapperRecordSegmentInfo_t *pseg, *pseg_tmp;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800819
820 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->info.id);
821
822 /*if timeshifting, notify the playback first, then deal with record*/
823 if (ctx->record.param_open.is_timeshift) {
824 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
825
826 if (ctx_playback) {
827 pthread_mutex_lock(&ctx_playback->lock);
828 if (ctx_valid(ctx_playback)
829 && ctx_playback->sn == sn_timeshift_playback
830 && !list_empty(&ctx_playback->segments)) {
831 error = wrapper_removePlaybackSegment(ctx_playback, &seg_info->info);
832 }
833 pthread_mutex_unlock(&ctx_playback->lock);
834 }
835 }
836
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800837 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
838 if (pseg->info.id == seg_info->info.id) {
839 list_del(&pseg->head);
840
841 /*record the obsolete*/
842 ctx->record.obsolete.time += pseg->info.duration;
843 ctx->record.obsolete.size += pseg->info.size;
844 ctx->record.obsolete.pkts += pseg->info.nb_packets;
845
846 free(pseg);
847 break;
848 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800849 }
850
851 error = dvr_segment_delete(ctx->record.param_open.location, seg_info->info.id);
852
853 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->info.id, error);
854
855 return error;
856}
857
858int dvr_wrapper_open_record (DVR_WrapperRecord_t *rec, DVR_WrapperRecordOpenParams_t *params)
859{
860 int error;
861 DVR_WrapperCtx_t *ctx;
862 DVR_RecordOpenParams_t open_param;
863
864 DVR_RETURN_IF_FALSE(rec);
865 DVR_RETURN_IF_FALSE(params);
866
867 /*get a free ctx*/
868 ctx = ctx_getRecord(0);
869 DVR_RETURN_IF_FALSE(ctx);
870
871 pthread_mutex_lock(&ctx->lock);
872
hualing chen51652f02020-12-29 16:59:31 +0800873 DVR_WRAPPER_DEBUG(1, "open record(dmx:%d) .istf(%d)..time (%ld)ms max size(%lld)byte seg size(%lld)byte\n",
874 params->dmx_dev_id, params->is_timeshift, params->max_time, params->max_size, params->segment_size);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800875
876 ctx_reset(ctx);
877
878 ctx->record.param_open = *params;
879 ctx->record.event_fn = params->event_fn;
880 ctx->record.event_userdata = params->event_userdata;
881 ctx->record.next_segment_id = 0;
882 ctx->current_segment_id = 0;
883 INIT_LIST_HEAD(&ctx->segments);
884 ctx->sn = get_sn();
885
886 wrapper_requestThreadFor(ctx);
887
hualing chen266b9502020-04-04 17:39:39 +0800888 memset(&open_param, 0, sizeof(DVR_RecordOpenParams_t));
Yahui Hance15e9c2020-12-08 18:08:32 +0800889 open_param.fend_dev_id = params->fend_dev_id;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800890 open_param.dmx_dev_id = params->dmx_dev_id;
891 open_param.data_from_memory = 0;
892 open_param.flags = params->flags;
Zhiqiang Han104aed72020-04-03 19:37:43 +0800893 open_param.notification_size = 500*1024;
Zhiqiang Han31505452020-05-06 15:08:10 +0800894 open_param.flush_size = params->flush_size;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800895 open_param.event_fn = wrapper_record_event_handler;
896 open_param.event_userdata = (void*)ctx->sn;
897
898 error = dvr_record_open(&ctx->record.recorder, &open_param);
899 if (error) {
900 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) open fail(error:%d).\n", params->dmx_dev_id, error);
901 ctx_reset(ctx);
902 pthread_mutex_unlock(&ctx->lock);
903 wrapper_releaseThreadForType(ctx->type);
904 return DVR_FAILURE;
905 }
906 if (params->is_timeshift)
907 sn_timeshift_record = ctx->sn;
908
909 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
910
hualing chen266b9502020-04-04 17:39:39 +0800911 error = dvr_record_set_encrypt_callback(ctx->record.recorder, params->crypto_fn, params->crypto_data);
912 if (error) {
913 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) set encrypt callback fail(error:%d).\n", params->dmx_dev_id, error);
914 }
915
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800916 pthread_mutex_unlock(&ctx->lock);
917
918 *rec = (DVR_WrapperRecord_t)ctx->sn;
919 return DVR_SUCCESS;
920}
921
922int dvr_wrapper_close_record (DVR_WrapperRecord_t rec)
923{
924 DVR_WrapperCtx_t *ctx;
925 DVR_RecordSegmentInfo_t seg_info;
926 int error;
927
928 DVR_RETURN_IF_FALSE(rec);
929
930 ctx = ctx_getRecord((unsigned long)rec);
931 DVR_RETURN_IF_FALSE(ctx);
932
933 pthread_mutex_lock(&ctx->lock);
934 DVR_WRAPPER_DEBUG(1, "close record(sn:%ld)\n", ctx->sn);
935 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
936
937 memset(&seg_info, 0, sizeof(seg_info));
938 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
939
940 error = dvr_record_close(ctx->record.recorder);
941
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800942 if (ctx->record.param_open.is_timeshift)
943 sn_timeshift_record = 0;
944
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800945 ctx_freeSegments(ctx);
946
947 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) closed = (%d).\n", ctx->sn, error);
948 ctx_reset(ctx);
949 pthread_mutex_unlock(&ctx->lock);
950
951 wrapper_releaseThreadForType(ctx->type);
952
953 return error;
954}
955
956int dvr_wrapper_start_record (DVR_WrapperRecord_t rec, DVR_WrapperRecordStartParams_t *params)
957{
958 DVR_WrapperCtx_t *ctx;
959 DVR_RecordStartParams_t *start_param;
960 int i;
961 int error;
962
963 DVR_RETURN_IF_FALSE(rec);
964 DVR_RETURN_IF_FALSE(params);
965
966 ctx = ctx_getRecord((unsigned long)rec);
967 DVR_RETURN_IF_FALSE(ctx);
968
969 pthread_mutex_lock(&ctx->lock);
970 DVR_WRAPPER_DEBUG(1, "start record(sn:%ld, location:%s) ...\n", ctx->sn, ctx->record.param_open.location);
971 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
972
973 start_param = &ctx->record.param_start;
974 memset(start_param, 0, sizeof(*start_param));
975 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
976 start_param->segment.segment_id = ctx->record.next_segment_id++;
977 start_param->segment.nb_pids = params->pids_info.nb_pids;
978 for (i = 0; i < params->pids_info.nb_pids; i++) {
979 start_param->segment.pids[i] = params->pids_info.pids[i];
980 start_param->segment.pid_action[i] = DVR_RECORD_PID_CREATE;
981 }
hualing chen7a56cba2020-04-14 14:09:27 +0800982 dvr_segment_del_by_location(start_param->location);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800983 {
984 /*sync to update for further use*/
985 DVR_RecordStartParams_t *update_param;
986 update_param = &ctx->record.param_update;
987 memcpy(update_param, start_param, sizeof(*update_param));
988 for (i = 0; i < update_param->segment.nb_pids; i++)
989 update_param->segment.pid_action[i] = DVR_RECORD_PID_KEEP;
990 }
991
992 error = dvr_record_start_segment(ctx->record.recorder, start_param);
993 {
994 DVR_RecordSegmentInfo_t new_seg_info =
995 { .id = start_param->segment.segment_id, };
996 wrapper_addRecordSegment(ctx, &new_seg_info);
997 }
998
999 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) started = (%d)\n", ctx->sn, error);
1000
1001 pthread_mutex_unlock(&ctx->lock);
1002
1003 return error;
1004}
1005
1006int dvr_wrapper_stop_record (DVR_WrapperRecord_t rec)
1007{
1008 DVR_WrapperCtx_t *ctx;
1009 DVR_RecordSegmentInfo_t seg_info;
1010 int error;
1011
1012 DVR_RETURN_IF_FALSE(rec);
1013
1014 ctx = ctx_getRecord((unsigned long)rec);
1015 DVR_RETURN_IF_FALSE(ctx);
1016
1017 pthread_mutex_lock(&ctx->lock);
1018 DVR_WRAPPER_DEBUG(1, "stop record(sn:%ld) ...\n", ctx->sn);
1019 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1020
1021 memset(&seg_info, 0, sizeof(seg_info));
1022 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
1023 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
1024
1025 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) stopped = (%d)\n", ctx->sn, error);
1026 pthread_mutex_unlock(&ctx->lock);
1027
1028 return error;
1029}
1030
1031int dvr_wrapper_update_record_pids (DVR_WrapperRecord_t rec, DVR_WrapperUpdatePidsParams_t *params)
1032{
1033 DVR_WrapperCtx_t *ctx;
1034 DVR_RecordStartParams_t *start_param;
1035 DVR_RecordSegmentInfo_t seg_info;;
1036 int i;
1037 int error;
1038
1039 DVR_RETURN_IF_FALSE(rec);
1040 DVR_RETURN_IF_FALSE(params);
1041
1042 ctx = ctx_getRecord((unsigned long)rec);
1043 DVR_RETURN_IF_FALSE(ctx);
1044
1045 pthread_mutex_lock(&ctx->lock);
1046 DVR_WRAPPER_DEBUG(1, "update record(sn:%ld)\n", ctx->sn);
1047 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1048
1049 start_param = &ctx->record.param_update;
1050 memset(start_param, 0, sizeof(*start_param));
1051 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
1052 start_param->segment.segment_id = ctx->record.next_segment_id++;
1053 start_param->segment.nb_pids = params->nb_pids;
1054 for (i = 0; i < params->nb_pids; i++) {
1055 start_param->segment.pids[i] = params->pids[i];
1056 start_param->segment.pid_action[i] = params->pid_action[i];
1057 }
1058 error = dvr_record_next_segment(ctx->record.recorder, start_param, &seg_info);
1059 {
1060 DVR_RecordSegmentInfo_t new_seg_info =
1061 { .id = start_param->segment.segment_id, };
1062 wrapper_updateRecordSegment(ctx, &seg_info, U_PIDS);
1063 wrapper_addRecordSegment(ctx, &new_seg_info);
1064 }
1065
1066 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) updated = (%d)\n", ctx->sn, error);
1067 pthread_mutex_unlock(&ctx->lock);
1068
1069 return error;
1070}
1071
1072int dvr_wrapper_get_record_status(DVR_WrapperRecord_t rec, DVR_WrapperRecordStatus_t *status)
1073{
1074 DVR_WrapperCtx_t *ctx;
1075 DVR_WrapperRecordStatus_t s;
1076 int error;
1077
1078 DVR_RETURN_IF_FALSE(rec);
1079 DVR_RETURN_IF_FALSE(status);
1080
1081 ctx = ctx_getRecord((unsigned long)rec);
1082 DVR_RETURN_IF_FALSE(ctx);
1083
1084 pthread_mutex_lock(&ctx->lock);
1085
1086 DVR_WRAPPER_DEBUG(1, "get record(sn:%ld) status ...\n", ctx->sn);
1087 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1088
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001089 error = process_generateRecordStatus(ctx, &s);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001090
1091 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) state/time/size/pkts(%d/%ld/%lld/%u) (%d)\n",
1092 ctx->sn,
1093 s.state,
1094 s.info.time,
1095 s.info.size,
1096 s.info.pkts,
1097 error);
1098
1099 *status = s;
1100
1101 pthread_mutex_unlock(&ctx->lock);
1102
1103 return error;
1104}
1105
hualing chen4fe3bee2020-10-23 13:58:52 +08001106int dvr_wrapper_record_is_secure_mode(DVR_WrapperRecord_t rec)
1107{
1108 DVR_WrapperCtx_t *ctx;
1109 int error;
1110
1111 DVR_RETURN_IF_FALSE(rec);
1112
1113 ctx = ctx_getRecord((unsigned long)rec);
1114 DVR_RETURN_IF_FALSE(ctx);
1115
1116 pthread_mutex_lock(&ctx->lock);
1117 error = dvr_record_is_secure_mode(ctx->record.recorder);
1118 pthread_mutex_unlock(&ctx->lock);
1119 return error;
1120}
1121
hualing chen266b9502020-04-04 17:39:39 +08001122int dvr_wrapper_set_record_secure_buffer (DVR_WrapperRecord_t rec, uint8_t *p_secure_buf, uint32_t len)
1123{
1124 DVR_WrapperCtx_t *ctx;
1125 int error;
1126
1127 DVR_RETURN_IF_FALSE(rec);
1128 DVR_RETURN_IF_FALSE(p_secure_buf);
1129
1130 ctx = ctx_getRecord((unsigned long)rec);
1131 DVR_RETURN_IF_FALSE(ctx);
1132
1133 pthread_mutex_lock(&ctx->lock);
1134 error = dvr_record_set_secure_buffer(ctx->record.recorder, p_secure_buf, len);
1135 pthread_mutex_unlock(&ctx->lock);
1136 return error;
1137}
1138
1139int dvr_wrapper_set_record_decrypt_callback (DVR_WrapperRecord_t rec, DVR_CryptoFunction_t func, void *userdata)
1140{
1141 DVR_WrapperCtx_t *ctx;
1142 int error;
1143
1144 DVR_RETURN_IF_FALSE(rec);
1145 DVR_RETURN_IF_FALSE(func);
1146
1147 ctx = ctx_getRecord((unsigned long)rec);
1148 DVR_RETURN_IF_FALSE(ctx);
1149
1150 pthread_mutex_lock(&ctx->lock);
1151 error = dvr_record_set_encrypt_callback(ctx->record.recorder, func, userdata);
1152 pthread_mutex_unlock(&ctx->lock);
1153 return error;
1154}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001155
1156
1157int dvr_wrapper_open_playback (DVR_WrapperPlayback_t *playback, DVR_WrapperPlaybackOpenParams_t *params)
1158{
1159 DVR_WrapperCtx_t *ctx;
1160 DVR_PlaybackOpenParams_t open_param;
1161 int error;
1162
1163 DVR_RETURN_IF_FALSE(playback);
1164 DVR_RETURN_IF_FALSE(params);
1165 DVR_RETURN_IF_FALSE(params->playback_handle);
1166
1167 /*get a free ctx*/
1168 ctx = ctx_getPlayback(0);
1169 DVR_RETURN_IF_FALSE(ctx);
1170
1171 pthread_mutex_lock(&ctx->lock);
1172
hualing chen90b3ae62021-03-30 10:49:28 +08001173 DVR_WRAPPER_DEBUG(1, "open playback(dmx:%d) ..vendor[%d].\n", params->dmx_dev_id, params->vendor);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001174
1175 ctx_reset(ctx);
1176
1177 ctx->playback.param_open = *params;
1178 ctx->playback.event_fn = params->event_fn;
1179 ctx->playback.event_userdata = params->event_userdata;
1180 ctx->current_segment_id = 0;
1181 INIT_LIST_HEAD(&ctx->segments);
1182 ctx->sn = get_sn();
1183
1184 wrapper_requestThreadFor(ctx);
1185
hualing chen266b9502020-04-04 17:39:39 +08001186 memset(&open_param, 0, sizeof(DVR_PlaybackOpenParams_t));
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001187 open_param.dmx_dev_id = params->dmx_dev_id;
1188 open_param.block_size = params->block_size;
1189 open_param.is_timeshift = params->is_timeshift;
1190 //open_param.notification_size = 10*1024; //not supported
1191 open_param.event_fn = wrapper_playback_event_handler;
1192 open_param.event_userdata = (void*)ctx->sn;
1193 /*open_param.has_pids = 0;*/
hualing chene3797f02021-01-13 14:53:28 +08001194 open_param.is_notify_time = params->is_notify_time;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001195 open_param.player_handle = (am_tsplayer_handle)params->playback_handle;
hualing chen90b3ae62021-03-30 10:49:28 +08001196 open_param.vendor = params->vendor;
1197
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001198
1199 error = dvr_playback_open(&ctx->playback.player, &open_param);
1200 if (error) {
1201 DVR_WRAPPER_DEBUG(1, "playback(dmx:%d) openned fail(error:%d).\n", params->dmx_dev_id, error);
1202 ctx_reset(ctx);
1203 pthread_mutex_unlock(&ctx->lock);
1204 wrapper_releaseThreadForType(ctx->type);
1205 return DVR_FAILURE;
1206 }
1207 if (params->is_timeshift)
1208 sn_timeshift_playback = ctx->sn;
1209
hualing chen266b9502020-04-04 17:39:39 +08001210 DVR_WRAPPER_DEBUG(1, "hanyh: playback(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
1211 error = dvr_playback_set_decrypt_callback(ctx->playback.player, params->crypto_fn, params->crypto_data);
1212 if (error) {
1213 DVR_WRAPPER_DEBUG(1, "playback set deccrypt callback fail(error:%d).\n", error);
1214 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001215 pthread_mutex_unlock(&ctx->lock);
1216
1217 *playback = (DVR_WrapperPlayback_t)ctx->sn;
1218 return DVR_SUCCESS;
1219}
1220
1221int dvr_wrapper_close_playback (DVR_WrapperPlayback_t playback)
1222{
1223 DVR_WrapperCtx_t *ctx;
1224 int error;
1225
1226 DVR_RETURN_IF_FALSE(playback);
1227
1228 ctx = ctx_getPlayback((unsigned long)playback);
1229 DVR_RETURN_IF_FALSE(ctx);
1230
1231 pthread_mutex_lock(&ctx->lock);
1232 DVR_WRAPPER_DEBUG(1, "close playback(sn:%ld)\n", ctx->sn);
1233 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1234
1235 if (ctx->playback.param_open.is_timeshift)
1236 sn_timeshift_playback = 0;
1237
1238 /*try stop first*/
1239 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1240
1241 {
1242 /*remove all segments*/
1243 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1244
1245 list_for_each_entry(pseg, &ctx->segments, head) {
1246 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1247 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1248 ctx->sn, pseg->playback_info.segment_id, error);
1249 }
1250 ctx_freeSegments(ctx);
1251 }
1252
1253 error = dvr_playback_close(ctx->playback.player);
1254
1255 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) closed.\n", ctx->sn);
1256 ctx_reset(ctx);
1257 pthread_mutex_unlock(&ctx->lock);
1258
1259 wrapper_releaseThreadForType(ctx->type);
1260
1261 return error;
1262}
1263
1264int dvr_wrapper_start_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackFlag_t flags, DVR_PlaybackPids_t *p_pids)
1265{
1266 DVR_WrapperCtx_t *ctx;
1267 int error;
1268 uint64_t *p_segment_ids;
1269 uint32_t segment_nb;
1270 uint32_t i;
1271 DVR_RecordSegmentInfo_t seg_info_1st;
1272 int got_1st_seg;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001273 DVR_WrapperCtx_t *ctx_record;/*for timeshift*/
hualing chenc110f952021-01-18 11:25:37 +08001274 DVR_Bool_t is_timeshift = DVR_FALSE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001275
1276 DVR_RETURN_IF_FALSE(playback);
1277 DVR_RETURN_IF_FALSE(p_pids);
1278
hualing chenc110f952021-01-18 11:25:37 +08001279 ctx_record = NULL;
1280
1281 /*lock the recorder to avoid changing the recording segments*/
1282 ctx_record = ctx_getRecord(sn_timeshift_record);
1283
1284 if (ctx_record) {
1285 pthread_mutex_lock(&ctx_record->lock);
1286 if (!ctx_valid(ctx_record)
1287 || ctx_record->sn != sn_timeshift_record) {
1288 DVR_WRAPPER_DEBUG(1, "timeshift, record is not for timeshifting, FATAL error found\n");
1289 pthread_mutex_unlock(&ctx_record->lock);
1290 is_timeshift = DVR_FALSE;
1291 } else {
1292 is_timeshift = DVR_TRUE;
1293 }
1294 }
1295
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001296 ctx = ctx_getPlayback((unsigned long)playback);
1297 DVR_RETURN_IF_FALSE(ctx);
1298
1299 pthread_mutex_lock(&ctx->lock);
1300
1301 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",
1302 ctx->sn,
1303 ctx->playback.param_open.location,
1304 flags,
1305 p_pids->video.pid, p_pids->video.format,
1306 p_pids->audio.pid, p_pids->audio.format,
1307 p_pids->ad.pid, p_pids->ad.format,
1308 p_pids->subtitle.pid, p_pids->subtitle.format,
1309 p_pids->pcr.pid);
1310
1311 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1312
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001313 if (ctx->playback.param_open.is_timeshift) {
1314 /*lock the recorder to avoid changing the recording segments*/
hualing chenc110f952021-01-18 11:25:37 +08001315 if (is_timeshift == DVR_FALSE) {
1316 DVR_WRAPPER_DEBUG(1, "timeshift, record is not for timeshifting, FATAL error return\n");
1317 pthread_mutex_unlock(&ctx->lock);
1318 return DVR_FAILURE;
1319 } else {
1320 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) record(sn:%ld) locked ok due to timeshift\n",
1321 ctx->sn, ctx_record->sn);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001322 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001323 }
1324
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001325 /*obtain all segments in a list*/
1326 segment_nb = 0;
1327 p_segment_ids = NULL;
1328 error = dvr_segment_get_list(ctx->playback.param_open.location, &segment_nb, &p_segment_ids);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001329 if (!error) {
1330 got_1st_seg = 0;
1331 for (i = 0; i < segment_nb; i++) {
1332 DVR_RecordSegmentInfo_t seg_info;
1333 DVR_PlaybackSegmentFlag_t flags;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001334
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001335 error = dvr_segment_get_info(ctx->playback.param_open.location, p_segment_ids[i], &seg_info);
1336 if (error) {
1337 error = DVR_FAILURE;
1338 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
1339 ctx->playback.param_open.location, p_segment_ids[i], error);
1340 break;
1341 }
hualing chen92f3a142020-07-08 20:59:33 +08001342 //add check if has audio or video pid. if not exist. not add segment to playback
1343 int ii = 0;
1344 int has_av = 0;
1345 for (ii = 0; ii < seg_info.nb_pids; ii++) {
1346 int type = (seg_info.pids[ii].type >> 24) & 0x0f;
1347 if (type == DVR_STREAM_TYPE_VIDEO ||
1348 type == DVR_STREAM_TYPE_AUDIO ||
1349 type == DVR_STREAM_TYPE_AD) {
1350 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1351 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,
1352 DVR_STREAM_TYPE_VIDEO,
1353 DVR_STREAM_TYPE_AUDIO,
1354 DVR_STREAM_TYPE_AD);
1355 has_av = 1;
1356 //break;
1357 } else {
1358 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,
1359 DVR_STREAM_TYPE_VIDEO,
1360 DVR_STREAM_TYPE_AUDIO,
1361 DVR_STREAM_TYPE_AD);
1362 }
1363 }
1364 if (has_av == 0) {
1365 DVR_WRAPPER_DEBUG(1, "fail to get seg av info \n");
1366 continue;
1367 } else {
1368 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1369 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001370 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1371 error = wrapper_addPlaybackSegment(ctx, &seg_info, p_pids, flags);
1372 if (error)
1373 break;
1374
1375 /*copy the 1st segment*/
1376 if (got_1st_seg == 0) {
1377 seg_info_1st = seg_info;
1378 got_1st_seg = 1;
1379 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001380 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001381 free(p_segment_ids);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001382
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001383 /* return if no segment or fail to add */
1384 if (!error && got_1st_seg) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001385
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001386 /*copy the obsolete infomation, must for timeshifting*/
1387 if (ctx->playback.param_open.is_timeshift && ctx_record) {
1388 ctx->playback.obsolete = ctx_record->record.obsolete;
1389 }
1390
1391 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) (%d) segments added\n", ctx->sn, i);
1392
1393 ctx->playback.reach_end = DVR_FALSE;
1394 if ((flags&DVR_PLAYBACK_STARTED_PAUSEDLIVE) == DVR_PLAYBACK_STARTED_PAUSEDLIVE)
1395 ctx->playback.speed = 0.0f;
1396 else
1397 ctx->playback.speed = 100.0f;
1398
1399 ctx->playback.pids_req = *p_pids;
1400
1401 error = dvr_playback_seek(ctx->playback.player, seg_info_1st.id, 0);
1402 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seek(seg:%llu 0) for start (%d)\n",
1403 ctx->sn, seg_info_1st.id, error);
1404
1405 error = dvr_playback_start(ctx->playback.player, flags);
1406
1407 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) started (%d)\n", ctx->sn, error);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001408 }
1409 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001410
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001411 if (ctx->playback.param_open.is_timeshift) {
1412 /*unlock the recorder locked above*/
1413 if (ctx_record && ctx_valid(ctx_record)) {
1414 pthread_mutex_unlock(&ctx_record->lock);
1415 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld), record(sn:%ld) unlocked ok due to timeshift\n",
1416 ctx->sn, ctx_record->sn);
1417 }
1418 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001419
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001420
1421 pthread_mutex_unlock(&ctx->lock);
1422
1423 return error;
1424}
1425
1426int dvr_wrapper_stop_playback (DVR_WrapperPlayback_t playback)
1427{
1428 DVR_WrapperCtx_t *ctx;
1429 int error;
1430
1431 DVR_RETURN_IF_FALSE(playback);
1432
1433 ctx = ctx_getPlayback((unsigned long)playback);
1434 DVR_RETURN_IF_FALSE(ctx);
1435
1436 pthread_mutex_lock(&ctx->lock);
1437 DVR_WRAPPER_DEBUG(1, "stop playback(sn:%ld) ...\n", ctx->sn);
1438 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1439
1440 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1441
1442 {
1443 /*remove all segments*/
1444 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1445
1446 list_for_each_entry(pseg, &ctx->segments, head) {
1447 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1448 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1449 ctx->sn, pseg->playback_info.segment_id, error);
1450 }
1451 ctx_freeSegments(ctx);
1452 }
1453
1454 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) stopped (%d)\n", ctx->sn, error);
1455 pthread_mutex_unlock(&ctx->lock);
1456
1457 return error;
1458}
1459
1460int dvr_wrapper_pause_playback (DVR_WrapperPlayback_t playback)
1461{
1462 DVR_WrapperCtx_t *ctx;
1463 int error;
1464
1465 DVR_RETURN_IF_FALSE(playback);
1466
1467 ctx = ctx_getPlayback((unsigned long)playback);
1468 DVR_RETURN_IF_FALSE(ctx);
1469
1470 pthread_mutex_lock(&ctx->lock);
1471 DVR_WRAPPER_DEBUG(1, "pause playback(sn:%ld) ...\n", ctx->sn);
1472 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
hualing chen36e0dfd2020-05-02 16:33:06 +08001473 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +08001474 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +08001475 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001476
1477 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
1478
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001479 ctx->playback.speed = 0.0f;
1480
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001481 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) paused (%d)\n", ctx->sn, error);
1482 pthread_mutex_unlock(&ctx->lock);
1483
1484 return error;
1485}
1486
1487int dvr_wrapper_resume_playback (DVR_WrapperPlayback_t playback)
1488{
1489 DVR_WrapperCtx_t *ctx;
1490 int error;
1491
1492 DVR_RETURN_IF_FALSE(playback);
1493
1494 ctx = ctx_getPlayback((unsigned long)playback);
1495 DVR_RETURN_IF_FALSE(ctx);
1496
1497 pthread_mutex_lock(&ctx->lock);
1498 DVR_WRAPPER_DEBUG(1, "resume playback(sn:%ld) ...\n", ctx->sn);
1499 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1500
1501 error = dvr_playback_resume(ctx->playback.player);
1502
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001503 ctx->playback.speed = 100.0f;
1504
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001505 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) resumed (%d)\n", ctx->sn, error);
1506 pthread_mutex_unlock(&ctx->lock);
1507
1508 return error;
1509}
1510
1511int dvr_wrapper_set_playback_speed (DVR_WrapperPlayback_t playback, float speed)
1512{
1513 DVR_WrapperCtx_t *ctx;
1514 int error;
1515 DVR_PlaybackSpeed_t dvr_speed = {
1516 .speed = { speed },
1517 .mode = (speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
1518 };
1519
1520 DVR_RETURN_IF_FALSE(playback);
1521
1522 ctx = ctx_getPlayback((unsigned long)playback);
1523 DVR_RETURN_IF_FALSE(ctx);
1524
1525 pthread_mutex_lock(&ctx->lock);
hualing chenc70a8df2020-05-12 19:23:11 +08001526 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 +08001527 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1528
1529 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
1530
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001531 if (ctx->playback.speed != 0.0f && ctx->playback.speed != 100.0f
1532 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_BEGIN
1533 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
1534 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, paused, do resume first\n", ctx->playback.speed, speed);
1535 error = dvr_playback_resume(ctx->playback.player);
1536 } else if (ctx->playback.speed == 0.0f
1537 && speed != 0.0f
1538 && speed != 100.0f) {
1539 /*libdvr do not support pause with speed=0, will not be here*/
1540 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, do resume first\n", ctx->playback.speed, speed);
1541 error = dvr_playback_resume(ctx->playback.player);
1542 }
1543
1544 ctx->playback.speed = speed;
1545
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001546 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) speeded(x%f) (%d)\n",
1547 ctx->sn, speed, error);
1548 pthread_mutex_unlock(&ctx->lock);
1549
1550 return error;
1551}
1552
1553int dvr_wrapper_seek_playback (DVR_WrapperPlayback_t playback, uint32_t time_offset)
1554{
1555 DVR_WrapperCtx_t *ctx;
1556 int error;
1557 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1558 uint64_t segment_id;
1559 uint32_t off;
1560 uint64_t last_segment_id;
1561 uint32_t pre_off;
1562
1563 DVR_RETURN_IF_FALSE(playback);
1564
1565 ctx = ctx_getPlayback((unsigned long)playback);
1566 DVR_RETURN_IF_FALSE(ctx);
1567
1568 pthread_mutex_lock(&ctx->lock);
1569
1570 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (off:%d) ...\n", ctx->sn, time_offset);
1571 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1572
1573 off = 0;
1574 segment_id = 0;
1575 pre_off = 0;
1576 last_segment_id = 0;
1577
1578 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1579 segment_id = pseg->seg_info.id;
1580
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001581 if ((ctx->playback.obsolete.time + pre_off + pseg->seg_info.duration) > time_offset)
1582 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001583
1584 last_segment_id = pseg->seg_info.id;
1585 pre_off += pseg->seg_info.duration;
1586 }
1587
1588 if (last_segment_id == segment_id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001589 /*1.only one seg with id:0, 2.offset exceeds the total duration*/
1590 off = time_offset;
1591 } else if (ctx->playback.obsolete.time >= time_offset) {
1592 off = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001593 } else {
hualing chenda76fc52020-05-28 14:56:42 +08001594 off = time_offset - pre_off - ctx->playback.obsolete.time;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001595 }
1596
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001597 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (seg:%lld, off:%d)\n",
1598 ctx->sn, segment_id, off);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001599 error = dvr_playback_seek(ctx->playback.player, segment_id, off);
1600 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seeked(off:%d) (%d)\n", ctx->sn, time_offset, error);
1601
1602 pthread_mutex_unlock(&ctx->lock);
1603
1604 return error;
1605}
1606
1607int dvr_wrapper_update_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackPids_t *p_pids)
1608{
1609 DVR_WrapperCtx_t *ctx;
1610 int error;
1611 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1612
1613 DVR_RETURN_IF_FALSE(playback);
1614 DVR_RETURN_IF_FALSE(p_pids);
1615
1616 ctx = ctx_getPlayback((unsigned long)playback);
1617 DVR_RETURN_IF_FALSE(ctx);
1618
1619 pthread_mutex_lock(&ctx->lock);
1620
1621 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) ...\n",
1622 ctx->sn,
1623 p_pids->video.pid, p_pids->video.format,
1624 p_pids->audio.pid, p_pids->audio.format);
1625 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1626
1627 ctx->playback.pids_req = *p_pids;
1628
1629 error = 0;
1630 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1631 /*should update the whole list of segments*/
1632 /*if (pseg->seg_info.id == ctx->current_segment_id)*/ {
1633 /*list_for_each_entry_from(pseg, &ctx->segments, head)*/ {
1634 /*check udpate for pids*/
1635 if (memcmp(&pseg->playback_info.pids, p_pids, sizeof(*p_pids)) != 0) {
1636 pseg->playback_info.pids = *p_pids;
1637 error = dvr_playback_update_segment_pids(ctx->playback.player, pseg->seg_info.id, p_pids);
1638 if (error) {
1639 DVR_WRAPPER_DEBUG(1, "failed to playback(sn:%ld) update segment(id:%lld) pids (%d)\n",
1640 ctx->sn, pseg->seg_info.id, error);
1641 /*do not break, let list updated*/
1642 }
1643 }
1644 }
1645 /*break;*/
1646 }
1647 }
1648
1649 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) (%d)\n",
1650 ctx->sn,
1651 p_pids->video.pid, p_pids->video.format,
1652 p_pids->audio.pid, p_pids->audio.format,
1653 error);
1654
1655 pthread_mutex_unlock(&ctx->lock);
1656
1657 return error;
1658}
1659
1660int dvr_wrapper_get_playback_status(DVR_WrapperPlayback_t playback, DVR_WrapperPlaybackStatus_t *status)
1661{
1662 DVR_WrapperCtx_t *ctx;
1663 DVR_WrapperPlaybackStatus_t s;
1664 DVR_PlaybackStatus_t play_status;
1665 int error;
1666
1667 DVR_RETURN_IF_FALSE(playback);
1668 DVR_RETURN_IF_FALSE(status);
1669
1670 ctx = ctx_getPlayback((unsigned long)playback);
1671 DVR_RETURN_IF_FALSE(ctx);
1672
1673 pthread_mutex_lock(&ctx->lock);
1674
1675 DVR_WRAPPER_DEBUG(1, "get playback(sn:%ld) status ...\n", ctx->sn);
1676 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1677
1678 error = dvr_playback_get_status(ctx->playback.player, &play_status);
1679 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) get status (%d)\n", ctx->sn, error);
1680
1681 ctx->playback.seg_status = play_status;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001682 error = process_generatePlaybackStatus(ctx, &s);
1683
hualing chenb5cd42e2020-04-15 17:03:34 +08001684 if (ctx->playback.reach_end == DVR_TRUE && ctx->playback.param_open.is_timeshift == DVR_FALSE) {
1685 //reach end need set full time to cur.so app can exist playback.
1686 DVR_WRAPPER_DEBUG(1, "set cur time to full time, reach end occur");
1687 s.info_cur.time = s.info_full.time;
1688 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001689 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) state/cur/full/obsl(%d/%ld/%ld/%ld) (%d)\n",
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001690 ctx->sn,
1691 s.state,
1692 s.info_cur.time,
1693 s.info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001694 s.info_obsolete.time,
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001695 error);
1696
1697 *status = s;
1698
1699 pthread_mutex_unlock(&ctx->lock);
1700
1701 return error;
1702}
1703
hualing chen266b9502020-04-04 17:39:39 +08001704int dvr_wrapper_set_playback_secure_buffer (DVR_WrapperPlayback_t playback, uint8_t *p_secure_buf, uint32_t len)
1705{
1706 DVR_WrapperCtx_t *ctx;
1707 int error;
1708
1709 DVR_RETURN_IF_FALSE(playback);
1710 DVR_RETURN_IF_FALSE(p_secure_buf);
1711
1712 ctx = ctx_getPlayback((unsigned long)playback);
1713 DVR_RETURN_IF_FALSE(ctx);
1714
1715 pthread_mutex_lock(&ctx->lock);
1716 error = dvr_playback_set_secure_buffer(ctx->playback.player, p_secure_buf, len);
1717 pthread_mutex_unlock(&ctx->lock);
1718 return error;
1719}
1720
1721int dvr_wrapper_set_playback_decrypt_callback (DVR_WrapperPlayback_t playback, DVR_CryptoFunction_t func, void *userdata)
1722{
1723 DVR_WrapperCtx_t *ctx;
1724 int error;
1725
1726 DVR_RETURN_IF_FALSE(playback);
1727 DVR_RETURN_IF_FALSE(func);
1728
1729 ctx = ctx_getPlayback((unsigned long)playback);
1730 DVR_RETURN_IF_FALSE(ctx);
1731
1732 pthread_mutex_lock(&ctx->lock);
1733 error = dvr_playback_set_decrypt_callback(ctx->playback.player, func, userdata);
1734 pthread_mutex_unlock(&ctx->lock);
1735 return error;
1736}
1737
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001738static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata)
1739{
1740 DVR_WrapperEventCtx_t evt;
1741
1742 DVR_RETURN_IF_FALSE(userdata);
1743
1744 evt.sn = (unsigned long)userdata;
1745 evt.type = W_REC;
1746 evt.record.event = event;
1747 evt.record.status = *(DVR_RecordStatus_t *)params;
1748 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, record, evt:0x%x]\n", evt.sn, evt.record.event);
1749 return ctx_addRecordEvent(&evt);
1750}
1751
1752static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata)
1753{
1754 DVR_WrapperEventCtx_t evt;
1755
1756 DVR_RETURN_IF_FALSE(userdata);
1757
1758 evt.sn = (unsigned long)userdata;
1759 evt.type = W_PLAYBACK;
1760 evt.playback.event = event;
1761 evt.playback.status = *(DVR_Play_Notify_t *)params;
1762 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, playbck, evt:0x%x]\n", evt.sn, evt.playback.event);
1763 return ctx_addPlaybackEvent(&evt);
1764}
1765
1766static inline int process_notifyRecord(DVR_WrapperCtx_t *ctx, DVR_RecordEvent_t evt, DVR_WrapperRecordStatus_t *status)
1767{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001768 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 +08001769 ctx->sn,
1770 evt,
1771 status->info.time,
1772 status->info.size,
1773 status->info.pkts,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001774 status->info_obsolete.time,
1775 status->info_obsolete.size,
1776 status->info_obsolete.pkts);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001777
1778 if (ctx->record.event_fn)
1779 return ctx->record.event_fn(evt, status, ctx->record.event_userdata);
1780 return 0;
1781}
1782
1783static inline int record_startNextSegment(DVR_WrapperCtx_t *ctx)
1784{
1785 DVR_RecordStartParams_t param;
1786 DVR_RecordSegmentInfo_t seg_info;
1787 int i;
1788 int error;
1789
1790 memcpy(&param, &ctx->record.param_update, sizeof(param));
1791 memset(&ctx->record.param_update.segment, 0, sizeof(ctx->record.param_update.segment));
1792 ctx->record.param_update.segment.segment_id = ctx->record.next_segment_id++;
1793 for (i = 0; i < param.segment.nb_pids; i++) {
1794 if (param.segment.pid_action[i] != DVR_RECORD_PID_CLOSE) {
1795 ctx->record.param_update.segment.pids[ctx->record.param_update.segment.nb_pids] = param.segment.pids[i];
1796 ctx->record.param_update.segment.pid_action[ctx->record.param_update.segment.nb_pids] = DVR_RECORD_PID_KEEP;
1797 ctx->record.param_update.segment.nb_pids++;
1798 }
1799 }
1800 error = dvr_record_next_segment(ctx->record.recorder, &ctx->record.param_update, &seg_info);
1801 {
1802 DVR_RecordSegmentInfo_t new_seg_info =
1803 { .id = ctx->record.param_update.segment.segment_id, };
1804 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
1805 wrapper_addRecordSegment(ctx, &new_seg_info);
1806 }
1807
Zhiqiang Hand977e972020-05-11 11:30:47 +08001808 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 +08001809 return error;
1810}
1811
1812static inline int record_removeSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *pseg)
1813{
1814 return wrapper_removeRecordSegment(ctx, pseg);
1815}
1816
1817/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001818static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001819{
1820 /*the current seg is not covered in the statistics*/
1821 DVR_WrapperRecordSegmentInfo_t *pseg;
1822
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001823 /*re-calculate the all segments*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001824 memset(&ctx->record.status, 0, sizeof(ctx->record.status));
1825
1826 ctx->record.status.state = ctx->record.seg_status.state;
1827 ctx->record.status.pids.nb_pids = ctx->record.seg_status.info.nb_pids;
1828 memcpy(ctx->record.status.pids.pids,
1829 ctx->record.seg_status.info.pids,
1830 sizeof(ctx->record.status.pids.pids));
1831 ctx->current_segment_id = ctx->record.seg_status.info.id;
1832
1833 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1834 if (pseg->info.id != ctx->record.seg_status.info.id) {
1835 ctx->record.status.info.time += pseg->info.duration;
1836 ctx->record.status.info.size += pseg->info.size;
1837 ctx->record.status.info.pkts += pseg->info.nb_packets;
1838 }
1839 }
1840
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001841 ctx->record.status.info_obsolete = ctx->record.obsolete;
1842
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001843 wrapper_updateRecordSegment(ctx, &ctx->record.seg_status.info, U_ALL);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001844
1845 if (status) {
1846 *status = ctx->record.status;
1847 status->info.time += ctx->record.seg_status.info.duration;
1848 status->info.size += ctx->record.seg_status.info.size;
1849 status->info.pkts += ctx->record.seg_status.info.nb_packets;
1850 }
1851
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001852 return DVR_SUCCESS;
1853}
1854
1855
1856static int process_handleRecordEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
1857{
1858 DVR_WrapperRecordStatus_t status;
1859
1860 memset(&status, 0, sizeof(status));
1861
1862 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d)\n",
1863 evt->sn, evt->record.event, evt->record.status.state);
hualing chend3b55ab2021-05-06 09:56:27 +08001864 if (ctx->record.param_update.segment.segment_id != evt->record.status.info.id) {
1865 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) cur id:0x%x (event id:%d)\n",
Gong Ke2a0ebbe2021-05-25 15:22:50 +08001866 evt->sn, (int)ctx->record.param_update.segment.segment_id, (int)evt->record.status.info.id);
hualing chend3b55ab2021-05-06 09:56:27 +08001867 return 0;
1868 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001869 switch (evt->record.event)
1870 {
1871 case DVR_RECORD_EVENT_STATUS:
1872 {
1873 switch (evt->record.status.state)
1874 {
1875 case DVR_RECORD_STATE_OPENED:
1876 case DVR_RECORD_STATE_CLOSED:
1877 {
1878 ctx->record.seg_status = evt->record.status;
1879
1880 status.state = evt->record.status.state;
1881 process_notifyRecord(ctx, evt->record.event, &status);
1882 } break;
1883 case DVR_RECORD_STATE_STARTED:
1884 {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001885 ctx->record.seg_status = evt->record.status;
1886
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001887 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001888 process_notifyRecord(ctx, evt->record.event, &status);
1889
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001890 /*restart to next segment*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001891 if (ctx->record.param_open.segment_size
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001892 && evt->record.status.info.size >= ctx->record.param_open.segment_size) {
1893 DVR_WRAPPER_DEBUG(1, "start new segment for record(%lu), reaches segment size limit, cur(%zu) max(%lld)\n",
1894 ctx->sn,
1895 evt->record.status.info.size,
1896 ctx->record.param_open.segment_size);
Zhiqiang Hand977e972020-05-11 11:30:47 +08001897 if (record_startNextSegment(ctx) != DVR_SUCCESS) {
1898 /*should notify the recording's stop*/
1899 int error = dvr_record_close(ctx->record.recorder);
1900 DVR_WRAPPER_DEBUG(1, "stop record(%lu)=%d, failed to start new segment for recording.",
1901 ctx->sn, error);
1902 status.state = DVR_RECORD_STATE_CLOSED;
1903 process_notifyRecord(ctx, DVR_RECORD_EVENT_WRITE_ERROR, &status);
1904 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001905 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001906
1907 if (ctx->record.param_open.is_timeshift
1908 && ctx->record.param_open.max_time
1909 && status.info.time >= ctx->record.param_open.max_time) {
1910 DVR_WrapperRecordSegmentInfo_t *pseg;
1911
1912 /*as the player do not support null playlist,
1913 there must be one segment existed at any time,
1914 we have to keep two segments before remove one*/
1915 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
1916 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
1917 /*only one segment, waiting for more*/
1918 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of max_time(%ld) of record < max size of segment(%lld)\n",
1919 status.info.size,
1920 ctx->record.param_open.max_time,
1921 ctx->record.param_open.segment_size);
1922 } else {
1923 /*timeshifting, remove the 1st segment and notify the player*/
1924 record_removeSegment(ctx, pseg);
1925
1926 process_generateRecordStatus(ctx, &status);
1927 process_notifyRecord(ctx, evt->record.event, &status);
1928 }
1929 }
1930
1931 if (ctx->record.param_open.is_timeshift
1932 && ctx->record.param_open.max_size
1933 && status.info.size >= ctx->record.param_open.max_size) {
1934 DVR_WrapperRecordSegmentInfo_t *pseg;
1935
1936 /*as the player do not support null playlist,
1937 there must be one segment existed at any time,
1938 we have to keep two segments before remove one*/
1939 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
1940 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
1941 /*only one segment, waiting for more*/
1942 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of record < max size of segment(%lld)\n",
1943 status.info.size,
1944 ctx->record.param_open.segment_size);
1945 } else {
1946 record_removeSegment(ctx, pseg);
1947
1948 process_generateRecordStatus(ctx, &status);
1949 process_notifyRecord(ctx, evt->record.event, &status);
1950 }
1951 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001952 } break;
1953 case DVR_RECORD_STATE_STOPPED:
1954 {
1955 ctx->record.seg_status = evt->record.status;
1956
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001957 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001958 process_notifyRecord(ctx, evt->record.event, &status);
1959 } break;
1960 default:
1961 break;
1962 }
1963 } break;
hualing chen4b7c15d2020-04-07 16:13:48 +08001964 case DVR_RECORD_EVENT_WRITE_ERROR: {
1965 ctx->record.seg_status = evt->record.status;
1966 status.state = evt->record.status.state;
1967 process_notifyRecord(ctx, evt->record.event, &status);
1968 }break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001969 default:
1970 break;
1971 }
1972 return DVR_SUCCESS;
1973}
1974
1975static inline int process_notifyPlayback(DVR_WrapperCtx_t *ctx, DVR_PlaybackEvent_t evt, DVR_WrapperPlaybackStatus_t *status)
1976{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001977 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 +08001978 ctx->sn,
1979 evt,
1980 status->state,
1981 status->info_cur.time,
1982 status->info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001983 status->info_obsolete.time);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001984
1985 if (ctx->playback.event_fn)
1986 return ctx->playback.event_fn(evt, status, ctx->playback.event_userdata);
1987 return 0;
1988}
1989
1990/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001991static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperPlaybackStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001992{
1993 /*the current seg is not covered in the statistics*/
1994 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1995
1996 memset(&ctx->playback.status, 0, sizeof(ctx->playback.status));
1997 ctx->playback.status.pids = ctx->playback.pids_req;
1998
1999 ctx->playback.status.state = ctx->playback.seg_status.state;
2000 ctx->playback.status.speed = ctx->playback.seg_status.speed;
2001 ctx->playback.status.flags = ctx->playback.seg_status.flags;
2002 ctx->current_segment_id = ctx->playback.seg_status.segment_id;
2003
2004 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2005 if (pseg->seg_info.id == ctx->playback.seg_status.segment_id)
2006 break;
2007 ctx->playback.status.info_cur.time += pseg->seg_info.duration;
2008 ctx->playback.status.info_cur.size += pseg->seg_info.size;
2009 ctx->playback.status.info_cur.pkts += pseg->seg_info.nb_packets;
2010 }
2011 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2012 ctx->playback.status.info_full.time += pseg->seg_info.duration;
2013 ctx->playback.status.info_full.size += pseg->seg_info.size;
2014 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
2015 }
2016
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002017 if (status) {
2018 *status = ctx->playback.status;
2019 /*deal with current, lack size and pkts with the current*/
2020 status->info_cur.time += ctx->playback.seg_status.time_cur;
2021 status->info_obsolete.time = ctx->playback.obsolete.time;
2022 }
2023
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002024 return DVR_SUCCESS;
2025}
2026
2027static int process_handlePlaybackEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2028{
2029 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d) cur(%lld:%u/%u)\n",
2030 evt->sn, evt->playback.event,
2031 evt->playback.status.play_status.state,
2032 evt->playback.status.play_status.segment_id,
2033 evt->playback.status.play_status.time_cur,
2034 evt->playback.status.play_status.time_end);
2035
2036 /*evt PLAYTIME will break the last logic, do not save*/
hualing chene3797f02021-01-13 14:53:28 +08002037 if (evt->playback.event != DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME
2038 && evt->playback.event != DVR_PLAYBACK_EVENT_NODATA
2039 && evt->playback.event != DVR_PLAYBACK_EVENT_DATARESUME
2040 )
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002041 ctx->playback.last_event = evt->playback.event;
2042
2043 switch (evt->playback.event)
2044 {
2045 case DVR_PLAYBACK_EVENT_FIRST_FRAME:
2046 case DVR_PLAYBACK_EVENT_REACHED_END:
2047 case DVR_PLAYBACK_EVENT_TRANSITION_OK:
2048 case DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME:
hualing chenb5cd42e2020-04-15 17:03:34 +08002049 case DVR_PLAYBACK_EVENT_ERROR:
hualing chenf291cf32020-06-18 10:50:30 +08002050 case DVR_PLAYBACK_EVENT_REACHED_BEGIN:
hualing chene3797f02021-01-13 14:53:28 +08002051 case DVR_PLAYBACK_EVENT_NODATA:
2052 case DVR_PLAYBACK_EVENT_DATARESUME:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002053 {
2054 DVR_WrapperPlaybackStatus_t status;
2055
2056 /*copy status of segment*/
2057 ctx->playback.seg_status = evt->playback.status.play_status;
2058
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002059 /*generate status of the whole playback*/
2060 process_generatePlaybackStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002061
2062 if (evt->playback.event == DVR_PLAYBACK_EVENT_REACHED_END) {
2063 if (ctx->playback.param_open.is_timeshift) {
2064 /*wait for more data in recording*/
2065 } else if ((status.info_cur.time + DVR_PLAYBACK_END_GAP) >= ctx->playback.status.info_full.time) {
2066 process_notifyPlayback(ctx, evt->playback.event, &status);
hualing chenb5cd42e2020-04-15 17:03:34 +08002067 } else {
2068 ctx->playback.reach_end = DVR_TRUE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002069 }
hualing chenf291cf32020-06-18 10:50:30 +08002070 } else if (evt->playback.event != DVR_PLAYBACK_EVENT_REACHED_BEGIN) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002071 process_notifyPlayback(ctx, evt->playback.event, &status);
2072 }
2073 } break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002074 case DVR_PLAYBACK_EVENT_TRANSITION_FAILED:
2075 case DVR_PLAYBACK_EVENT_KEY_FAILURE:
2076 case DVR_PLAYBACK_EVENT_NO_KEY:
2077 {
2078 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) error event:0x%x\n", evt->sn, evt->playback.event);
2079 } break;
2080 default:
2081 {
2082 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) unknown event:0x%x\n", evt->sn, evt->playback.event);
2083 } break;
2084 }
2085 return 0;
2086}
2087
2088static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2089{
2090 return (evt->type == W_REC)? process_handleRecordEvent(evt, ctx) : process_handlePlaybackEvent(evt, ctx);
2091}
2092