blob: c80188bcd38aacb4374f4257f7aaceb0a244c512 [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
20#define DVR_WRAPPER_DEBUG(_level, _fmt, ...) \
21 DVR_DEBUG(_level, "wrapper %-30.30s:%d " _fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
22
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;
471 ret = wrapper_threadWait(tctx);
472 }
473
474 while ((evt = ((tctx->type == W_REC)? ctx_getRecordEvent() : ctx_getPlaybackEvent()))) {
475 DVR_WrapperCtx_t *ctx = (evt->type == W_REC)?
476 ctx_getRecord(evt->sn) : ctx_getPlayback(evt->sn);
477
478 if (tctx->running) {
479 /*
480 continue not break,
481 make all events consumed, or mem leak
482 */
483 if (!wrapper_mutex_lock_if(&ctx->lock, &tctx->running))
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800484 goto processed;
485
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800486 if (ctx_valid(ctx)) {
487 /*double check after lock*/
488 if (evt->sn == ctx->sn)
489 process_handleEvents(evt, ctx);
490 }
491 pthread_mutex_unlock(&ctx->lock);
492 }
493
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800494processed:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800495 ctx_freeEvent(evt);
496 }
497 }
498
499 pthread_mutex_unlock(&tctx->lock);
500 return NULL;
501}
502
503static inline int ctx_addRecordEvent(DVR_WrapperEventCtx_t *evt)
504{
505 if (ctx_addEvent(&record_evt_list, &record_evt_list_lock, evt) == 0)
506 wrapper_threadSignalForType(evt->type);
507 return 0;
508}
509
510static inline int ctx_addPlaybackEvent(DVR_WrapperEventCtx_t *evt)
511{
512 if (ctx_addEvent(&playback_evt_list, &playback_evt_list_lock, evt) == 0)
513 wrapper_threadSignalForType(evt->type);
514 return 0;
515}
516
517static inline void ctx_freeSegments(DVR_WrapperCtx_t *ctx)
518{
519 DVR_WrapperPlaybackSegmentInfo_t *pseg, *pseg_tmp;
520 list_for_each_entry_safe(pseg, pseg_tmp, &ctx->segments, head) {
521 list_del(&pseg->head);
522 free(pseg);
523 }
524}
525
526static inline void _updatePlaybackSegment(DVR_WrapperPlaybackSegmentInfo_t *pseg,
527 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
528{
529 (void)ctx;
530 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
531 pseg->seg_info = *seg_info;
532 else if (update_flags & U_PIDS) {
533 pseg->seg_info.nb_pids = seg_info->nb_pids;
534 memcpy(pseg->seg_info.pids, seg_info->pids, sizeof(pseg->seg_info.pids));
535 } else if (update_flags & U_STAT) {
536 pseg->seg_info.duration = seg_info->duration;
537 pseg->seg_info.size = seg_info->size;
538 pseg->seg_info.nb_packets = seg_info->nb_packets;
539 }
540
541 /*no changes
542 DVR_PlaybackSegmentFlag_t flags;
543 pseg->playback_info.segment_id = pseg->seg_info.id;
544 strncpy(pseg->playback_info.location,
545 ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
546 pseg->playback_info.pids = ctx->playback.pids_req;
547 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
548 if (ctx->record.param_open.flags | DVR_RECORD_FLAG_SCRAMBLED)
549 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
550 pseg->playback_info.flags = flags;
551 */
552}
553
554static int wrapper_updatePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
555{
556 DVR_WrapperPlaybackSegmentInfo_t *pseg;
557
558 DVR_WRAPPER_DEBUG(1, "timeshift, update playback segments(wrapper), seg:%lld t/s/p(%ld/%zu/%u)\n",
559 seg_info->id, seg_info->duration, seg_info->size, seg_info->nb_packets);
560
561 if (list_empty(&ctx->segments)) {
562 DVR_WRAPPER_DEBUG(1, "timeshift, update while no segment exists, ignore\n");
563 return DVR_SUCCESS;
564 }
565
566 /*normally, the last segment added will be updated*/
567 pseg =
568 list_first_entry(&ctx->segments, DVR_WrapperPlaybackSegmentInfo_t, head);
569 if (pseg->seg_info.id == seg_info->id) {
570 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
571 } else {
572 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
573 if (pseg->seg_info.id == seg_info->id) {
574 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
575 break;
576 }
577 }
578 }
579
580 /*need to notify the dvr_playback*/
581 if (ctx->playback.param_open.is_timeshift/*should must be timeshift*/
582 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END
583 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
584 if (
585 /*there's $TIMESHIFT_DATA_DURATION_TO_RESUME more of data in the current segment playing*/
586 (ctx->playback.seg_status.segment_id == seg_info->id
587 && (seg_info->duration >= ((time_t)ctx->playback.seg_status.time_cur + TIMESHIFT_DATA_DURATION_TO_RESUME)))
588 ||
589 /*or there's a new segment and has $TIMESHIFT_DATA_DURATION_TO_RESUME of data*/
590 (ctx->playback.seg_status.segment_id != seg_info->id
591 && (seg_info->duration >= TIMESHIFT_DATA_DURATION_TO_RESUME))
592 )
593 {
594 int error;
hualing chen36e0dfd2020-05-02 16:33:06 +0800595 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +0800596 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +0800597 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800598
599 error = dvr_playback_resume(ctx->playback.player);
600 DVR_WRAPPER_DEBUG(1, "timeshift, resume playback(sn:%ld) (%d) id/dur: rec(%lld/%ld) play(%lld/%u)\n",
601 ctx->sn, error,
602 seg_info->id, seg_info->duration,
603 ctx->playback.seg_status.segment_id, ctx->playback.seg_status.time_cur);
604 }
605 }
606
607 return DVR_SUCCESS;
608}
609
610static void _updateRecordSegment(DVR_WrapperRecordSegmentInfo_t *pseg,
611 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
612{
613 (void)ctx;
614 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
615 pseg->info = *seg_info;
616 else if (update_flags & U_PIDS) {
617 pseg->info.nb_pids = seg_info->nb_pids;
618 memcpy(pseg->info.pids, seg_info->pids, sizeof(pseg->info.pids));
619 } else if (update_flags & U_STAT) {
620 pseg->info.duration = seg_info->duration;
621 pseg->info.size = seg_info->size;
622 pseg->info.nb_packets = seg_info->nb_packets;
623 }
624}
625
626static int wrapper_updateRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
627{
hualing chen266b9502020-04-04 17:39:39 +0800628 DVR_WrapperRecordSegmentInfo_t *pseg = NULL;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800629
630 /*normally, the last segment added will be updated*/
hualing chen266b9502020-04-04 17:39:39 +0800631 if (!list_empty(&ctx->segments)) {
632 pseg =
633 list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
634 if (pseg->info.id == seg_info->id) {
635 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
636 } else {
637 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
638 if (pseg->info.id == seg_info->id) {
639 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
640 break;
641 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800642 }
643 }
644 }
645
646 /*timeshift, update the segment for playback*/
647 /*
648 the playback should grab the segment info other than the id,
649 and the id will be updated by each segment-add during the recording
650 */
651 /*
652 the playback paused if no data been checked from recording,
653 should resume the player later when there's more data
654 */
655
656 if (ctx->record.param_open.is_timeshift) {
657 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
658
659 if (ctx_playback) {
660 pthread_mutex_lock(&ctx_playback->lock);
661 if (ctx_valid(ctx_playback)
662 && ctx_playback->sn == sn_timeshift_playback) {
663 wrapper_updatePlaybackSegment(ctx_playback, seg_info, update_flags);
664 }
665 pthread_mutex_unlock(&ctx_playback->lock);
666 }
667 }
668
669 return DVR_SUCCESS;
670}
671
672static int wrapper_addPlaybackSegment(DVR_WrapperCtx_t *ctx,
673 DVR_RecordSegmentInfo_t *seg_info,
674 DVR_PlaybackPids_t *p_pids,
675 DVR_PlaybackSegmentFlag_t flags)
676{
677 DVR_WrapperPlaybackSegmentInfo_t *pseg;
678 int error;
679
680 error = 0;
681 pseg = (DVR_WrapperPlaybackSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperPlaybackSegmentInfo_t));
682 if (!pseg) {
683 error = DVR_FAILURE;
684 DVR_WRAPPER_DEBUG(1, "memory fail\n");
685 return error;
686 }
687
688 /*copy the orignal segment info*/
689 pseg->seg_info = *seg_info;
690 /*generate the segment info used in playback*/
691 pseg->playback_info.segment_id = pseg->seg_info.id;
692 strncpy(pseg->playback_info.location, ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
693 pseg->playback_info.pids = *p_pids;
694 pseg->playback_info.flags = flags;
695 list_add(&pseg->head, &ctx->segments);
696
697 error = dvr_playback_add_segment(ctx->playback.player, &pseg->playback_info);
698 if (error) {
699 DVR_WRAPPER_DEBUG(1, "fail to add segment %lld (%d)\n", pseg->playback_info.segment_id, error);
700 } else {
701 ctx->playback.status.info_full.time += pseg->seg_info.duration;
702 ctx->playback.status.info_full.size += pseg->seg_info.size;
703 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
704 }
705
706 return error;
707}
708
709static int wrapper_addRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
710{
711 DVR_WrapperRecordSegmentInfo_t *pseg;
712 int error;
713
714 error = 0;
715 pseg = (DVR_WrapperRecordSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperRecordSegmentInfo_t));
716 if (!pseg) {
717 error = DVR_FAILURE;
718 DVR_WRAPPER_DEBUG(1, "memory fail\n");
719 }
720 pseg->info = *seg_info;
721 list_add(&pseg->head, &ctx->segments);
722
723 if (ctx->record.param_open.is_timeshift) {
724 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
725
726 if (ctx_playback) {
727 pthread_mutex_lock(&ctx_playback->lock);
728 if (ctx_valid(ctx_playback)) {
729 DVR_PlaybackSegmentFlag_t flags;
730
731 /*only if playback has started, the previous segments have been loaded*/
732 if (!list_empty(&ctx_playback->segments)) {
733 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
734 if (ctx->record.param_open.flags | DVR_RECORD_FLAG_SCRAMBLED)
735 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
736 wrapper_addPlaybackSegment(ctx_playback, seg_info, &ctx_playback->playback.pids_req, flags);
737 }
738 }
739 pthread_mutex_unlock(&ctx_playback->lock);
740 }
741 }
742
743 return error;
744}
745
746static int wrapper_removePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
747{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800748 int error = -1;
749 DVR_WrapperPlaybackSegmentInfo_t *pseg = NULL, *pseg_tmp;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800750
751 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->id);
752
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800753 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800754 if (pseg->seg_info.id == seg_info->id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800755
756 if (ctx->current_segment_id == seg_info->id) {
757 DVR_WrapperPlaybackSegmentInfo_t *next_seg;
758
759 /*drive the player out of this will-be-deleted segment*/
760 next_seg = list_prev_entry(pseg, head);
761
762 if (ctx->playback.speed != 100.0f) {
763 error = dvr_playback_resume(ctx->playback.player);
764 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), resume for new start (%d)\n", ctx->sn, error);
765 }
766
767 error = dvr_playback_seek(ctx->playback.player, next_seg->seg_info.id, 0);
768 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);
769
770 if (ctx->playback.speed == 0.0f) {
771 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
772 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last paused from new start (%d)\n", ctx->sn, error);
773 } else if (ctx->playback.speed != 100.0f) {
774 DVR_PlaybackSpeed_t dvr_speed = {
775 .speed = { ctx->playback.speed },
776 .mode = ( ctx->playback.speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
777 };
778 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
779 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last speed(x%f) from new start (%d)\n", ctx->sn,ctx->playback.speed, error);
780 }
781 }
782
783 error = dvr_playback_remove_segment(ctx->playback.player, seg_info->id);
784 if (error) {
785 /*remove playack segment fail*/
786 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), failed to remove segment(%llu) (%d)\n", ctx->sn, seg_info->id, error);
787 }
788
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800789 list_del(&pseg->head);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800790
791 /*record the obsolete*/
792 ctx->playback.obsolete.time += pseg->seg_info.duration;
793 ctx->playback.obsolete.size += pseg->seg_info.size;
794 ctx->playback.obsolete.pkts += pseg->seg_info.nb_packets;
795
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800796 free(pseg);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800797 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800798 }
799 }
800
801 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->id, error);
802
803 return error;
804}
805
806static int wrapper_removeRecordSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *seg_info)
807{
808 int error;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800809 DVR_WrapperRecordSegmentInfo_t *pseg, *pseg_tmp;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800810
811 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->info.id);
812
813 /*if timeshifting, notify the playback first, then deal with record*/
814 if (ctx->record.param_open.is_timeshift) {
815 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
816
817 if (ctx_playback) {
818 pthread_mutex_lock(&ctx_playback->lock);
819 if (ctx_valid(ctx_playback)
820 && ctx_playback->sn == sn_timeshift_playback
821 && !list_empty(&ctx_playback->segments)) {
822 error = wrapper_removePlaybackSegment(ctx_playback, &seg_info->info);
823 }
824 pthread_mutex_unlock(&ctx_playback->lock);
825 }
826 }
827
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800828 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
829 if (pseg->info.id == seg_info->info.id) {
830 list_del(&pseg->head);
831
832 /*record the obsolete*/
833 ctx->record.obsolete.time += pseg->info.duration;
834 ctx->record.obsolete.size += pseg->info.size;
835 ctx->record.obsolete.pkts += pseg->info.nb_packets;
836
837 free(pseg);
838 break;
839 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800840 }
841
842 error = dvr_segment_delete(ctx->record.param_open.location, seg_info->info.id);
843
844 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->info.id, error);
845
846 return error;
847}
848
849int dvr_wrapper_open_record (DVR_WrapperRecord_t *rec, DVR_WrapperRecordOpenParams_t *params)
850{
851 int error;
852 DVR_WrapperCtx_t *ctx;
853 DVR_RecordOpenParams_t open_param;
854
855 DVR_RETURN_IF_FALSE(rec);
856 DVR_RETURN_IF_FALSE(params);
857
858 /*get a free ctx*/
859 ctx = ctx_getRecord(0);
860 DVR_RETURN_IF_FALSE(ctx);
861
862 pthread_mutex_lock(&ctx->lock);
863
864 DVR_WRAPPER_DEBUG(1, "open record(dmx:%d) ...\n", params->dmx_dev_id);
865
866 ctx_reset(ctx);
867
868 ctx->record.param_open = *params;
869 ctx->record.event_fn = params->event_fn;
870 ctx->record.event_userdata = params->event_userdata;
871 ctx->record.next_segment_id = 0;
872 ctx->current_segment_id = 0;
873 INIT_LIST_HEAD(&ctx->segments);
874 ctx->sn = get_sn();
875
876 wrapper_requestThreadFor(ctx);
877
hualing chen266b9502020-04-04 17:39:39 +0800878 memset(&open_param, 0, sizeof(DVR_RecordOpenParams_t));
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800879 open_param.dmx_dev_id = params->dmx_dev_id;
880 open_param.data_from_memory = 0;
881 open_param.flags = params->flags;
Zhiqiang Han104aed72020-04-03 19:37:43 +0800882 open_param.notification_size = 500*1024;
Zhiqiang Han31505452020-05-06 15:08:10 +0800883 open_param.flush_size = params->flush_size;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800884 open_param.event_fn = wrapper_record_event_handler;
885 open_param.event_userdata = (void*)ctx->sn;
886
887 error = dvr_record_open(&ctx->record.recorder, &open_param);
888 if (error) {
889 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) open fail(error:%d).\n", params->dmx_dev_id, error);
890 ctx_reset(ctx);
891 pthread_mutex_unlock(&ctx->lock);
892 wrapper_releaseThreadForType(ctx->type);
893 return DVR_FAILURE;
894 }
895 if (params->is_timeshift)
896 sn_timeshift_record = ctx->sn;
897
898 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
899
hualing chen266b9502020-04-04 17:39:39 +0800900 error = dvr_record_set_encrypt_callback(ctx->record.recorder, params->crypto_fn, params->crypto_data);
901 if (error) {
902 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) set encrypt callback fail(error:%d).\n", params->dmx_dev_id, error);
903 }
904
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800905 pthread_mutex_unlock(&ctx->lock);
906
907 *rec = (DVR_WrapperRecord_t)ctx->sn;
908 return DVR_SUCCESS;
909}
910
911int dvr_wrapper_close_record (DVR_WrapperRecord_t rec)
912{
913 DVR_WrapperCtx_t *ctx;
914 DVR_RecordSegmentInfo_t seg_info;
915 int error;
916
917 DVR_RETURN_IF_FALSE(rec);
918
919 ctx = ctx_getRecord((unsigned long)rec);
920 DVR_RETURN_IF_FALSE(ctx);
921
922 pthread_mutex_lock(&ctx->lock);
923 DVR_WRAPPER_DEBUG(1, "close record(sn:%ld)\n", ctx->sn);
924 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
925
926 memset(&seg_info, 0, sizeof(seg_info));
927 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
928
929 error = dvr_record_close(ctx->record.recorder);
930
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800931 if (ctx->record.param_open.is_timeshift)
932 sn_timeshift_record = 0;
933
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800934 ctx_freeSegments(ctx);
935
936 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) closed = (%d).\n", ctx->sn, error);
937 ctx_reset(ctx);
938 pthread_mutex_unlock(&ctx->lock);
939
940 wrapper_releaseThreadForType(ctx->type);
941
942 return error;
943}
944
945int dvr_wrapper_start_record (DVR_WrapperRecord_t rec, DVR_WrapperRecordStartParams_t *params)
946{
947 DVR_WrapperCtx_t *ctx;
948 DVR_RecordStartParams_t *start_param;
949 int i;
950 int error;
951
952 DVR_RETURN_IF_FALSE(rec);
953 DVR_RETURN_IF_FALSE(params);
954
955 ctx = ctx_getRecord((unsigned long)rec);
956 DVR_RETURN_IF_FALSE(ctx);
957
958 pthread_mutex_lock(&ctx->lock);
959 DVR_WRAPPER_DEBUG(1, "start record(sn:%ld, location:%s) ...\n", ctx->sn, ctx->record.param_open.location);
960 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
961
962 start_param = &ctx->record.param_start;
963 memset(start_param, 0, sizeof(*start_param));
964 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
965 start_param->segment.segment_id = ctx->record.next_segment_id++;
966 start_param->segment.nb_pids = params->pids_info.nb_pids;
967 for (i = 0; i < params->pids_info.nb_pids; i++) {
968 start_param->segment.pids[i] = params->pids_info.pids[i];
969 start_param->segment.pid_action[i] = DVR_RECORD_PID_CREATE;
970 }
hualing chen7a56cba2020-04-14 14:09:27 +0800971 dvr_segment_del_by_location(start_param->location);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800972 {
973 /*sync to update for further use*/
974 DVR_RecordStartParams_t *update_param;
975 update_param = &ctx->record.param_update;
976 memcpy(update_param, start_param, sizeof(*update_param));
977 for (i = 0; i < update_param->segment.nb_pids; i++)
978 update_param->segment.pid_action[i] = DVR_RECORD_PID_KEEP;
979 }
980
981 error = dvr_record_start_segment(ctx->record.recorder, start_param);
982 {
983 DVR_RecordSegmentInfo_t new_seg_info =
984 { .id = start_param->segment.segment_id, };
985 wrapper_addRecordSegment(ctx, &new_seg_info);
986 }
987
988 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) started = (%d)\n", ctx->sn, error);
989
990 pthread_mutex_unlock(&ctx->lock);
991
992 return error;
993}
994
995int dvr_wrapper_stop_record (DVR_WrapperRecord_t rec)
996{
997 DVR_WrapperCtx_t *ctx;
998 DVR_RecordSegmentInfo_t seg_info;
999 int error;
1000
1001 DVR_RETURN_IF_FALSE(rec);
1002
1003 ctx = ctx_getRecord((unsigned long)rec);
1004 DVR_RETURN_IF_FALSE(ctx);
1005
1006 pthread_mutex_lock(&ctx->lock);
1007 DVR_WRAPPER_DEBUG(1, "stop record(sn:%ld) ...\n", ctx->sn);
1008 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1009
1010 memset(&seg_info, 0, sizeof(seg_info));
1011 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
1012 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
1013
1014 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) stopped = (%d)\n", ctx->sn, error);
1015 pthread_mutex_unlock(&ctx->lock);
1016
1017 return error;
1018}
1019
1020int dvr_wrapper_update_record_pids (DVR_WrapperRecord_t rec, DVR_WrapperUpdatePidsParams_t *params)
1021{
1022 DVR_WrapperCtx_t *ctx;
1023 DVR_RecordStartParams_t *start_param;
1024 DVR_RecordSegmentInfo_t seg_info;;
1025 int i;
1026 int error;
1027
1028 DVR_RETURN_IF_FALSE(rec);
1029 DVR_RETURN_IF_FALSE(params);
1030
1031 ctx = ctx_getRecord((unsigned long)rec);
1032 DVR_RETURN_IF_FALSE(ctx);
1033
1034 pthread_mutex_lock(&ctx->lock);
1035 DVR_WRAPPER_DEBUG(1, "update record(sn:%ld)\n", ctx->sn);
1036 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1037
1038 start_param = &ctx->record.param_update;
1039 memset(start_param, 0, sizeof(*start_param));
1040 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
1041 start_param->segment.segment_id = ctx->record.next_segment_id++;
1042 start_param->segment.nb_pids = params->nb_pids;
1043 for (i = 0; i < params->nb_pids; i++) {
1044 start_param->segment.pids[i] = params->pids[i];
1045 start_param->segment.pid_action[i] = params->pid_action[i];
1046 }
1047 error = dvr_record_next_segment(ctx->record.recorder, start_param, &seg_info);
1048 {
1049 DVR_RecordSegmentInfo_t new_seg_info =
1050 { .id = start_param->segment.segment_id, };
1051 wrapper_updateRecordSegment(ctx, &seg_info, U_PIDS);
1052 wrapper_addRecordSegment(ctx, &new_seg_info);
1053 }
1054
1055 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) updated = (%d)\n", ctx->sn, error);
1056 pthread_mutex_unlock(&ctx->lock);
1057
1058 return error;
1059}
1060
1061int dvr_wrapper_get_record_status(DVR_WrapperRecord_t rec, DVR_WrapperRecordStatus_t *status)
1062{
1063 DVR_WrapperCtx_t *ctx;
1064 DVR_WrapperRecordStatus_t s;
1065 int error;
1066
1067 DVR_RETURN_IF_FALSE(rec);
1068 DVR_RETURN_IF_FALSE(status);
1069
1070 ctx = ctx_getRecord((unsigned long)rec);
1071 DVR_RETURN_IF_FALSE(ctx);
1072
1073 pthread_mutex_lock(&ctx->lock);
1074
1075 DVR_WRAPPER_DEBUG(1, "get record(sn:%ld) status ...\n", ctx->sn);
1076 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1077
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001078 error = process_generateRecordStatus(ctx, &s);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001079
1080 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) state/time/size/pkts(%d/%ld/%lld/%u) (%d)\n",
1081 ctx->sn,
1082 s.state,
1083 s.info.time,
1084 s.info.size,
1085 s.info.pkts,
1086 error);
1087
1088 *status = s;
1089
1090 pthread_mutex_unlock(&ctx->lock);
1091
1092 return error;
1093}
1094
hualing chen266b9502020-04-04 17:39:39 +08001095int dvr_wrapper_set_record_secure_buffer (DVR_WrapperRecord_t rec, uint8_t *p_secure_buf, uint32_t len)
1096{
1097 DVR_WrapperCtx_t *ctx;
1098 int error;
1099
1100 DVR_RETURN_IF_FALSE(rec);
1101 DVR_RETURN_IF_FALSE(p_secure_buf);
1102
1103 ctx = ctx_getRecord((unsigned long)rec);
1104 DVR_RETURN_IF_FALSE(ctx);
1105
1106 pthread_mutex_lock(&ctx->lock);
1107 error = dvr_record_set_secure_buffer(ctx->record.recorder, p_secure_buf, len);
1108 pthread_mutex_unlock(&ctx->lock);
1109 return error;
1110}
1111
1112int dvr_wrapper_set_record_decrypt_callback (DVR_WrapperRecord_t rec, DVR_CryptoFunction_t func, void *userdata)
1113{
1114 DVR_WrapperCtx_t *ctx;
1115 int error;
1116
1117 DVR_RETURN_IF_FALSE(rec);
1118 DVR_RETURN_IF_FALSE(func);
1119
1120 ctx = ctx_getRecord((unsigned long)rec);
1121 DVR_RETURN_IF_FALSE(ctx);
1122
1123 pthread_mutex_lock(&ctx->lock);
1124 error = dvr_record_set_encrypt_callback(ctx->record.recorder, func, userdata);
1125 pthread_mutex_unlock(&ctx->lock);
1126 return error;
1127}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001128
1129
1130int dvr_wrapper_open_playback (DVR_WrapperPlayback_t *playback, DVR_WrapperPlaybackOpenParams_t *params)
1131{
1132 DVR_WrapperCtx_t *ctx;
1133 DVR_PlaybackOpenParams_t open_param;
1134 int error;
1135
1136 DVR_RETURN_IF_FALSE(playback);
1137 DVR_RETURN_IF_FALSE(params);
1138 DVR_RETURN_IF_FALSE(params->playback_handle);
1139
1140 /*get a free ctx*/
1141 ctx = ctx_getPlayback(0);
1142 DVR_RETURN_IF_FALSE(ctx);
1143
1144 pthread_mutex_lock(&ctx->lock);
1145
1146 DVR_WRAPPER_DEBUG(1, "open playback(dmx:%d) ...\n", params->dmx_dev_id);
1147
1148 ctx_reset(ctx);
1149
1150 ctx->playback.param_open = *params;
1151 ctx->playback.event_fn = params->event_fn;
1152 ctx->playback.event_userdata = params->event_userdata;
1153 ctx->current_segment_id = 0;
1154 INIT_LIST_HEAD(&ctx->segments);
1155 ctx->sn = get_sn();
1156
1157 wrapper_requestThreadFor(ctx);
1158
hualing chen266b9502020-04-04 17:39:39 +08001159 memset(&open_param, 0, sizeof(DVR_PlaybackOpenParams_t));
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001160 open_param.dmx_dev_id = params->dmx_dev_id;
1161 open_param.block_size = params->block_size;
1162 open_param.is_timeshift = params->is_timeshift;
1163 //open_param.notification_size = 10*1024; //not supported
1164 open_param.event_fn = wrapper_playback_event_handler;
1165 open_param.event_userdata = (void*)ctx->sn;
1166 /*open_param.has_pids = 0;*/
1167
1168 open_param.player_handle = (am_tsplayer_handle)params->playback_handle;
hualing chenfbf8e022020-06-15 13:43:11 +08001169 open_param.vendor = DVR_PLAYBACK_VENDOR_AML;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001170
1171 error = dvr_playback_open(&ctx->playback.player, &open_param);
1172 if (error) {
1173 DVR_WRAPPER_DEBUG(1, "playback(dmx:%d) openned fail(error:%d).\n", params->dmx_dev_id, error);
1174 ctx_reset(ctx);
1175 pthread_mutex_unlock(&ctx->lock);
1176 wrapper_releaseThreadForType(ctx->type);
1177 return DVR_FAILURE;
1178 }
1179 if (params->is_timeshift)
1180 sn_timeshift_playback = ctx->sn;
1181
hualing chen266b9502020-04-04 17:39:39 +08001182 DVR_WRAPPER_DEBUG(1, "hanyh: playback(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
1183 error = dvr_playback_set_decrypt_callback(ctx->playback.player, params->crypto_fn, params->crypto_data);
1184 if (error) {
1185 DVR_WRAPPER_DEBUG(1, "playback set deccrypt callback fail(error:%d).\n", error);
1186 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001187 pthread_mutex_unlock(&ctx->lock);
1188
1189 *playback = (DVR_WrapperPlayback_t)ctx->sn;
1190 return DVR_SUCCESS;
1191}
1192
1193int dvr_wrapper_close_playback (DVR_WrapperPlayback_t playback)
1194{
1195 DVR_WrapperCtx_t *ctx;
1196 int error;
1197
1198 DVR_RETURN_IF_FALSE(playback);
1199
1200 ctx = ctx_getPlayback((unsigned long)playback);
1201 DVR_RETURN_IF_FALSE(ctx);
1202
1203 pthread_mutex_lock(&ctx->lock);
1204 DVR_WRAPPER_DEBUG(1, "close playback(sn:%ld)\n", ctx->sn);
1205 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1206
1207 if (ctx->playback.param_open.is_timeshift)
1208 sn_timeshift_playback = 0;
1209
1210 /*try stop first*/
1211 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1212
1213 {
1214 /*remove all segments*/
1215 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1216
1217 list_for_each_entry(pseg, &ctx->segments, head) {
1218 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1219 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1220 ctx->sn, pseg->playback_info.segment_id, error);
1221 }
1222 ctx_freeSegments(ctx);
1223 }
1224
1225 error = dvr_playback_close(ctx->playback.player);
1226
1227 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) closed.\n", ctx->sn);
1228 ctx_reset(ctx);
1229 pthread_mutex_unlock(&ctx->lock);
1230
1231 wrapper_releaseThreadForType(ctx->type);
1232
1233 return error;
1234}
1235
1236int dvr_wrapper_start_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackFlag_t flags, DVR_PlaybackPids_t *p_pids)
1237{
1238 DVR_WrapperCtx_t *ctx;
1239 int error;
1240 uint64_t *p_segment_ids;
1241 uint32_t segment_nb;
1242 uint32_t i;
1243 DVR_RecordSegmentInfo_t seg_info_1st;
1244 int got_1st_seg;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001245 DVR_WrapperCtx_t *ctx_record;/*for timeshift*/
1246
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001247
1248 DVR_RETURN_IF_FALSE(playback);
1249 DVR_RETURN_IF_FALSE(p_pids);
1250
1251 ctx = ctx_getPlayback((unsigned long)playback);
1252 DVR_RETURN_IF_FALSE(ctx);
1253
1254 pthread_mutex_lock(&ctx->lock);
1255
1256 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",
1257 ctx->sn,
1258 ctx->playback.param_open.location,
1259 flags,
1260 p_pids->video.pid, p_pids->video.format,
1261 p_pids->audio.pid, p_pids->audio.format,
1262 p_pids->ad.pid, p_pids->ad.format,
1263 p_pids->subtitle.pid, p_pids->subtitle.format,
1264 p_pids->pcr.pid);
1265
1266 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1267
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001268 ctx_record = NULL;
1269 if (ctx->playback.param_open.is_timeshift) {
1270 /*lock the recorder to avoid changing the recording segments*/
1271 ctx_record = ctx_getRecord(sn_timeshift_record);
1272
1273 if (ctx_record) {
1274 pthread_mutex_lock(&ctx_record->lock);
1275 if (!ctx_valid(ctx_record)
1276 || ctx_record->sn != sn_timeshift_record) {
1277 DVR_WRAPPER_DEBUG(1, "timeshift, record is not for timeshifting, FATAL error\n");
1278 pthread_mutex_unlock(&ctx_record->lock);
1279 } else {
1280 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) record(sn:%ld) locked ok due to timeshift\n",
1281 ctx->sn, ctx_record->sn);
1282 }
1283 }
1284 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_record, &ctx->lock);
1285 }
1286
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001287 /*obtain all segments in a list*/
1288 segment_nb = 0;
1289 p_segment_ids = NULL;
1290 error = dvr_segment_get_list(ctx->playback.param_open.location, &segment_nb, &p_segment_ids);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001291 if (!error) {
1292 got_1st_seg = 0;
1293 for (i = 0; i < segment_nb; i++) {
1294 DVR_RecordSegmentInfo_t seg_info;
1295 DVR_PlaybackSegmentFlag_t flags;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001296
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001297 error = dvr_segment_get_info(ctx->playback.param_open.location, p_segment_ids[i], &seg_info);
1298 if (error) {
1299 error = DVR_FAILURE;
1300 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
1301 ctx->playback.param_open.location, p_segment_ids[i], error);
1302 break;
1303 }
hualing chen92f3a142020-07-08 20:59:33 +08001304 //add check if has audio or video pid. if not exist. not add segment to playback
1305 int ii = 0;
1306 int has_av = 0;
1307 for (ii = 0; ii < seg_info.nb_pids; ii++) {
1308 int type = (seg_info.pids[ii].type >> 24) & 0x0f;
1309 if (type == DVR_STREAM_TYPE_VIDEO ||
1310 type == DVR_STREAM_TYPE_AUDIO ||
1311 type == DVR_STREAM_TYPE_AD) {
1312 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1313 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,
1314 DVR_STREAM_TYPE_VIDEO,
1315 DVR_STREAM_TYPE_AUDIO,
1316 DVR_STREAM_TYPE_AD);
1317 has_av = 1;
1318 //break;
1319 } else {
1320 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,
1321 DVR_STREAM_TYPE_VIDEO,
1322 DVR_STREAM_TYPE_AUDIO,
1323 DVR_STREAM_TYPE_AD);
1324 }
1325 }
1326 if (has_av == 0) {
1327 DVR_WRAPPER_DEBUG(1, "fail to get seg av info \n");
1328 continue;
1329 } else {
1330 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1331 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001332 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1333 error = wrapper_addPlaybackSegment(ctx, &seg_info, p_pids, flags);
1334 if (error)
1335 break;
1336
1337 /*copy the 1st segment*/
1338 if (got_1st_seg == 0) {
1339 seg_info_1st = seg_info;
1340 got_1st_seg = 1;
1341 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001342 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001343 free(p_segment_ids);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001344
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001345 /* return if no segment or fail to add */
1346 if (!error && got_1st_seg) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001347
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001348 /*copy the obsolete infomation, must for timeshifting*/
1349 if (ctx->playback.param_open.is_timeshift && ctx_record) {
1350 ctx->playback.obsolete = ctx_record->record.obsolete;
1351 }
1352
1353 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) (%d) segments added\n", ctx->sn, i);
1354
1355 ctx->playback.reach_end = DVR_FALSE;
1356 if ((flags&DVR_PLAYBACK_STARTED_PAUSEDLIVE) == DVR_PLAYBACK_STARTED_PAUSEDLIVE)
1357 ctx->playback.speed = 0.0f;
1358 else
1359 ctx->playback.speed = 100.0f;
1360
1361 ctx->playback.pids_req = *p_pids;
1362
1363 error = dvr_playback_seek(ctx->playback.player, seg_info_1st.id, 0);
1364 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seek(seg:%llu 0) for start (%d)\n",
1365 ctx->sn, seg_info_1st.id, error);
1366
1367 error = dvr_playback_start(ctx->playback.player, flags);
1368
1369 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) started (%d)\n", ctx->sn, error);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001370 }
1371 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001372
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001373 if (ctx->playback.param_open.is_timeshift) {
1374 /*unlock the recorder locked above*/
1375 if (ctx_record && ctx_valid(ctx_record)) {
1376 pthread_mutex_unlock(&ctx_record->lock);
1377 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld), record(sn:%ld) unlocked ok due to timeshift\n",
1378 ctx->sn, ctx_record->sn);
1379 }
1380 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001381
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001382
1383 pthread_mutex_unlock(&ctx->lock);
1384
1385 return error;
1386}
1387
1388int dvr_wrapper_stop_playback (DVR_WrapperPlayback_t playback)
1389{
1390 DVR_WrapperCtx_t *ctx;
1391 int error;
1392
1393 DVR_RETURN_IF_FALSE(playback);
1394
1395 ctx = ctx_getPlayback((unsigned long)playback);
1396 DVR_RETURN_IF_FALSE(ctx);
1397
1398 pthread_mutex_lock(&ctx->lock);
1399 DVR_WRAPPER_DEBUG(1, "stop playback(sn:%ld) ...\n", ctx->sn);
1400 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1401
1402 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1403
1404 {
1405 /*remove all segments*/
1406 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1407
1408 list_for_each_entry(pseg, &ctx->segments, head) {
1409 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1410 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1411 ctx->sn, pseg->playback_info.segment_id, error);
1412 }
1413 ctx_freeSegments(ctx);
1414 }
1415
1416 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) stopped (%d)\n", ctx->sn, error);
1417 pthread_mutex_unlock(&ctx->lock);
1418
1419 return error;
1420}
1421
1422int dvr_wrapper_pause_playback (DVR_WrapperPlayback_t playback)
1423{
1424 DVR_WrapperCtx_t *ctx;
1425 int error;
1426
1427 DVR_RETURN_IF_FALSE(playback);
1428
1429 ctx = ctx_getPlayback((unsigned long)playback);
1430 DVR_RETURN_IF_FALSE(ctx);
1431
1432 pthread_mutex_lock(&ctx->lock);
1433 DVR_WRAPPER_DEBUG(1, "pause playback(sn:%ld) ...\n", ctx->sn);
1434 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
hualing chen36e0dfd2020-05-02 16:33:06 +08001435 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +08001436 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +08001437 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001438
1439 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
1440
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001441 ctx->playback.speed = 0.0f;
1442
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001443 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) paused (%d)\n", ctx->sn, error);
1444 pthread_mutex_unlock(&ctx->lock);
1445
1446 return error;
1447}
1448
1449int dvr_wrapper_resume_playback (DVR_WrapperPlayback_t playback)
1450{
1451 DVR_WrapperCtx_t *ctx;
1452 int error;
1453
1454 DVR_RETURN_IF_FALSE(playback);
1455
1456 ctx = ctx_getPlayback((unsigned long)playback);
1457 DVR_RETURN_IF_FALSE(ctx);
1458
1459 pthread_mutex_lock(&ctx->lock);
1460 DVR_WRAPPER_DEBUG(1, "resume playback(sn:%ld) ...\n", ctx->sn);
1461 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1462
1463 error = dvr_playback_resume(ctx->playback.player);
1464
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001465 ctx->playback.speed = 100.0f;
1466
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001467 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) resumed (%d)\n", ctx->sn, error);
1468 pthread_mutex_unlock(&ctx->lock);
1469
1470 return error;
1471}
1472
1473int dvr_wrapper_set_playback_speed (DVR_WrapperPlayback_t playback, float speed)
1474{
1475 DVR_WrapperCtx_t *ctx;
1476 int error;
1477 DVR_PlaybackSpeed_t dvr_speed = {
1478 .speed = { speed },
1479 .mode = (speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
1480 };
1481
1482 DVR_RETURN_IF_FALSE(playback);
1483
1484 ctx = ctx_getPlayback((unsigned long)playback);
1485 DVR_RETURN_IF_FALSE(ctx);
1486
1487 pthread_mutex_lock(&ctx->lock);
hualing chenc70a8df2020-05-12 19:23:11 +08001488 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 +08001489 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1490
1491 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
1492
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001493 if (ctx->playback.speed != 0.0f && ctx->playback.speed != 100.0f
1494 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_BEGIN
1495 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
1496 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, paused, do resume first\n", ctx->playback.speed, speed);
1497 error = dvr_playback_resume(ctx->playback.player);
1498 } else if (ctx->playback.speed == 0.0f
1499 && speed != 0.0f
1500 && speed != 100.0f) {
1501 /*libdvr do not support pause with speed=0, will not be here*/
1502 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, do resume first\n", ctx->playback.speed, speed);
1503 error = dvr_playback_resume(ctx->playback.player);
1504 }
1505
1506 ctx->playback.speed = speed;
1507
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001508 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) speeded(x%f) (%d)\n",
1509 ctx->sn, speed, error);
1510 pthread_mutex_unlock(&ctx->lock);
1511
1512 return error;
1513}
1514
1515int dvr_wrapper_seek_playback (DVR_WrapperPlayback_t playback, uint32_t time_offset)
1516{
1517 DVR_WrapperCtx_t *ctx;
1518 int error;
1519 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1520 uint64_t segment_id;
1521 uint32_t off;
1522 uint64_t last_segment_id;
1523 uint32_t pre_off;
1524
1525 DVR_RETURN_IF_FALSE(playback);
1526
1527 ctx = ctx_getPlayback((unsigned long)playback);
1528 DVR_RETURN_IF_FALSE(ctx);
1529
1530 pthread_mutex_lock(&ctx->lock);
1531
1532 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (off:%d) ...\n", ctx->sn, time_offset);
1533 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1534
1535 off = 0;
1536 segment_id = 0;
1537 pre_off = 0;
1538 last_segment_id = 0;
1539
1540 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1541 segment_id = pseg->seg_info.id;
1542
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001543 if ((ctx->playback.obsolete.time + pre_off + pseg->seg_info.duration) > time_offset)
1544 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001545
1546 last_segment_id = pseg->seg_info.id;
1547 pre_off += pseg->seg_info.duration;
1548 }
1549
1550 if (last_segment_id == segment_id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001551 /*1.only one seg with id:0, 2.offset exceeds the total duration*/
1552 off = time_offset;
1553 } else if (ctx->playback.obsolete.time >= time_offset) {
1554 off = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001555 } else {
hualing chenda76fc52020-05-28 14:56:42 +08001556 off = time_offset - pre_off - ctx->playback.obsolete.time;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001557 }
1558
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001559 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (seg:%lld, off:%d)\n",
1560 ctx->sn, segment_id, off);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001561 error = dvr_playback_seek(ctx->playback.player, segment_id, off);
1562 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seeked(off:%d) (%d)\n", ctx->sn, time_offset, error);
1563
1564 pthread_mutex_unlock(&ctx->lock);
1565
1566 return error;
1567}
1568
1569int dvr_wrapper_update_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackPids_t *p_pids)
1570{
1571 DVR_WrapperCtx_t *ctx;
1572 int error;
1573 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1574
1575 DVR_RETURN_IF_FALSE(playback);
1576 DVR_RETURN_IF_FALSE(p_pids);
1577
1578 ctx = ctx_getPlayback((unsigned long)playback);
1579 DVR_RETURN_IF_FALSE(ctx);
1580
1581 pthread_mutex_lock(&ctx->lock);
1582
1583 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) ...\n",
1584 ctx->sn,
1585 p_pids->video.pid, p_pids->video.format,
1586 p_pids->audio.pid, p_pids->audio.format);
1587 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1588
1589 ctx->playback.pids_req = *p_pids;
1590
1591 error = 0;
1592 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1593 /*should update the whole list of segments*/
1594 /*if (pseg->seg_info.id == ctx->current_segment_id)*/ {
1595 /*list_for_each_entry_from(pseg, &ctx->segments, head)*/ {
1596 /*check udpate for pids*/
1597 if (memcmp(&pseg->playback_info.pids, p_pids, sizeof(*p_pids)) != 0) {
1598 pseg->playback_info.pids = *p_pids;
1599 error = dvr_playback_update_segment_pids(ctx->playback.player, pseg->seg_info.id, p_pids);
1600 if (error) {
1601 DVR_WRAPPER_DEBUG(1, "failed to playback(sn:%ld) update segment(id:%lld) pids (%d)\n",
1602 ctx->sn, pseg->seg_info.id, error);
1603 /*do not break, let list updated*/
1604 }
1605 }
1606 }
1607 /*break;*/
1608 }
1609 }
1610
1611 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) (%d)\n",
1612 ctx->sn,
1613 p_pids->video.pid, p_pids->video.format,
1614 p_pids->audio.pid, p_pids->audio.format,
1615 error);
1616
1617 pthread_mutex_unlock(&ctx->lock);
1618
1619 return error;
1620}
1621
1622int dvr_wrapper_get_playback_status(DVR_WrapperPlayback_t playback, DVR_WrapperPlaybackStatus_t *status)
1623{
1624 DVR_WrapperCtx_t *ctx;
1625 DVR_WrapperPlaybackStatus_t s;
1626 DVR_PlaybackStatus_t play_status;
1627 int error;
1628
1629 DVR_RETURN_IF_FALSE(playback);
1630 DVR_RETURN_IF_FALSE(status);
1631
1632 ctx = ctx_getPlayback((unsigned long)playback);
1633 DVR_RETURN_IF_FALSE(ctx);
1634
1635 pthread_mutex_lock(&ctx->lock);
1636
1637 DVR_WRAPPER_DEBUG(1, "get playback(sn:%ld) status ...\n", ctx->sn);
1638 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1639
1640 error = dvr_playback_get_status(ctx->playback.player, &play_status);
1641 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) get status (%d)\n", ctx->sn, error);
1642
1643 ctx->playback.seg_status = play_status;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001644 error = process_generatePlaybackStatus(ctx, &s);
1645
hualing chenb5cd42e2020-04-15 17:03:34 +08001646 if (ctx->playback.reach_end == DVR_TRUE && ctx->playback.param_open.is_timeshift == DVR_FALSE) {
1647 //reach end need set full time to cur.so app can exist playback.
1648 DVR_WRAPPER_DEBUG(1, "set cur time to full time, reach end occur");
1649 s.info_cur.time = s.info_full.time;
1650 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001651 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) state/cur/full/obsl(%d/%ld/%ld/%ld) (%d)\n",
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001652 ctx->sn,
1653 s.state,
1654 s.info_cur.time,
1655 s.info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001656 s.info_obsolete.time,
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001657 error);
1658
1659 *status = s;
1660
1661 pthread_mutex_unlock(&ctx->lock);
1662
1663 return error;
1664}
1665
hualing chen266b9502020-04-04 17:39:39 +08001666int dvr_wrapper_set_playback_secure_buffer (DVR_WrapperPlayback_t playback, uint8_t *p_secure_buf, uint32_t len)
1667{
1668 DVR_WrapperCtx_t *ctx;
1669 int error;
1670
1671 DVR_RETURN_IF_FALSE(playback);
1672 DVR_RETURN_IF_FALSE(p_secure_buf);
1673
1674 ctx = ctx_getPlayback((unsigned long)playback);
1675 DVR_RETURN_IF_FALSE(ctx);
1676
1677 pthread_mutex_lock(&ctx->lock);
1678 error = dvr_playback_set_secure_buffer(ctx->playback.player, p_secure_buf, len);
1679 pthread_mutex_unlock(&ctx->lock);
1680 return error;
1681}
1682
1683int dvr_wrapper_set_playback_decrypt_callback (DVR_WrapperPlayback_t playback, DVR_CryptoFunction_t func, void *userdata)
1684{
1685 DVR_WrapperCtx_t *ctx;
1686 int error;
1687
1688 DVR_RETURN_IF_FALSE(playback);
1689 DVR_RETURN_IF_FALSE(func);
1690
1691 ctx = ctx_getPlayback((unsigned long)playback);
1692 DVR_RETURN_IF_FALSE(ctx);
1693
1694 pthread_mutex_lock(&ctx->lock);
1695 error = dvr_playback_set_decrypt_callback(ctx->playback.player, func, userdata);
1696 pthread_mutex_unlock(&ctx->lock);
1697 return error;
1698}
1699
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001700static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata)
1701{
1702 DVR_WrapperEventCtx_t evt;
1703
1704 DVR_RETURN_IF_FALSE(userdata);
1705
1706 evt.sn = (unsigned long)userdata;
1707 evt.type = W_REC;
1708 evt.record.event = event;
1709 evt.record.status = *(DVR_RecordStatus_t *)params;
1710 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, record, evt:0x%x]\n", evt.sn, evt.record.event);
1711 return ctx_addRecordEvent(&evt);
1712}
1713
1714static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata)
1715{
1716 DVR_WrapperEventCtx_t evt;
1717
1718 DVR_RETURN_IF_FALSE(userdata);
1719
1720 evt.sn = (unsigned long)userdata;
1721 evt.type = W_PLAYBACK;
1722 evt.playback.event = event;
1723 evt.playback.status = *(DVR_Play_Notify_t *)params;
1724 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, playbck, evt:0x%x]\n", evt.sn, evt.playback.event);
1725 return ctx_addPlaybackEvent(&evt);
1726}
1727
1728static inline int process_notifyRecord(DVR_WrapperCtx_t *ctx, DVR_RecordEvent_t evt, DVR_WrapperRecordStatus_t *status)
1729{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001730 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 +08001731 ctx->sn,
1732 evt,
1733 status->info.time,
1734 status->info.size,
1735 status->info.pkts,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001736 status->info_obsolete.time,
1737 status->info_obsolete.size,
1738 status->info_obsolete.pkts);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001739
1740 if (ctx->record.event_fn)
1741 return ctx->record.event_fn(evt, status, ctx->record.event_userdata);
1742 return 0;
1743}
1744
1745static inline int record_startNextSegment(DVR_WrapperCtx_t *ctx)
1746{
1747 DVR_RecordStartParams_t param;
1748 DVR_RecordSegmentInfo_t seg_info;
1749 int i;
1750 int error;
1751
1752 memcpy(&param, &ctx->record.param_update, sizeof(param));
1753 memset(&ctx->record.param_update.segment, 0, sizeof(ctx->record.param_update.segment));
1754 ctx->record.param_update.segment.segment_id = ctx->record.next_segment_id++;
1755 for (i = 0; i < param.segment.nb_pids; i++) {
1756 if (param.segment.pid_action[i] != DVR_RECORD_PID_CLOSE) {
1757 ctx->record.param_update.segment.pids[ctx->record.param_update.segment.nb_pids] = param.segment.pids[i];
1758 ctx->record.param_update.segment.pid_action[ctx->record.param_update.segment.nb_pids] = DVR_RECORD_PID_KEEP;
1759 ctx->record.param_update.segment.nb_pids++;
1760 }
1761 }
1762 error = dvr_record_next_segment(ctx->record.recorder, &ctx->record.param_update, &seg_info);
1763 {
1764 DVR_RecordSegmentInfo_t new_seg_info =
1765 { .id = ctx->record.param_update.segment.segment_id, };
1766 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
1767 wrapper_addRecordSegment(ctx, &new_seg_info);
1768 }
1769
Zhiqiang Hand977e972020-05-11 11:30:47 +08001770 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 +08001771 return error;
1772}
1773
1774static inline int record_removeSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *pseg)
1775{
1776 return wrapper_removeRecordSegment(ctx, pseg);
1777}
1778
1779/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001780static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001781{
1782 /*the current seg is not covered in the statistics*/
1783 DVR_WrapperRecordSegmentInfo_t *pseg;
1784
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001785 /*re-calculate the all segments*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001786 memset(&ctx->record.status, 0, sizeof(ctx->record.status));
1787
1788 ctx->record.status.state = ctx->record.seg_status.state;
1789 ctx->record.status.pids.nb_pids = ctx->record.seg_status.info.nb_pids;
1790 memcpy(ctx->record.status.pids.pids,
1791 ctx->record.seg_status.info.pids,
1792 sizeof(ctx->record.status.pids.pids));
1793 ctx->current_segment_id = ctx->record.seg_status.info.id;
1794
1795 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1796 if (pseg->info.id != ctx->record.seg_status.info.id) {
1797 ctx->record.status.info.time += pseg->info.duration;
1798 ctx->record.status.info.size += pseg->info.size;
1799 ctx->record.status.info.pkts += pseg->info.nb_packets;
1800 }
1801 }
1802
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001803 ctx->record.status.info_obsolete = ctx->record.obsolete;
1804
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001805 wrapper_updateRecordSegment(ctx, &ctx->record.seg_status.info, U_ALL);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001806
1807 if (status) {
1808 *status = ctx->record.status;
1809 status->info.time += ctx->record.seg_status.info.duration;
1810 status->info.size += ctx->record.seg_status.info.size;
1811 status->info.pkts += ctx->record.seg_status.info.nb_packets;
1812 }
1813
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001814 return DVR_SUCCESS;
1815}
1816
1817
1818static int process_handleRecordEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
1819{
1820 DVR_WrapperRecordStatus_t status;
1821
1822 memset(&status, 0, sizeof(status));
1823
1824 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d)\n",
1825 evt->sn, evt->record.event, evt->record.status.state);
1826
1827 switch (evt->record.event)
1828 {
1829 case DVR_RECORD_EVENT_STATUS:
1830 {
1831 switch (evt->record.status.state)
1832 {
1833 case DVR_RECORD_STATE_OPENED:
1834 case DVR_RECORD_STATE_CLOSED:
1835 {
1836 ctx->record.seg_status = evt->record.status;
1837
1838 status.state = evt->record.status.state;
1839 process_notifyRecord(ctx, evt->record.event, &status);
1840 } break;
1841 case DVR_RECORD_STATE_STARTED:
1842 {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001843 ctx->record.seg_status = evt->record.status;
1844
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001845 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001846 process_notifyRecord(ctx, evt->record.event, &status);
1847
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001848 /*restart to next segment*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001849 if (ctx->record.param_open.segment_size
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001850 && evt->record.status.info.size >= ctx->record.param_open.segment_size) {
1851 DVR_WRAPPER_DEBUG(1, "start new segment for record(%lu), reaches segment size limit, cur(%zu) max(%lld)\n",
1852 ctx->sn,
1853 evt->record.status.info.size,
1854 ctx->record.param_open.segment_size);
Zhiqiang Hand977e972020-05-11 11:30:47 +08001855 if (record_startNextSegment(ctx) != DVR_SUCCESS) {
1856 /*should notify the recording's stop*/
1857 int error = dvr_record_close(ctx->record.recorder);
1858 DVR_WRAPPER_DEBUG(1, "stop record(%lu)=%d, failed to start new segment for recording.",
1859 ctx->sn, error);
1860 status.state = DVR_RECORD_STATE_CLOSED;
1861 process_notifyRecord(ctx, DVR_RECORD_EVENT_WRITE_ERROR, &status);
1862 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001863 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001864
1865 if (ctx->record.param_open.is_timeshift
1866 && ctx->record.param_open.max_time
1867 && status.info.time >= ctx->record.param_open.max_time) {
1868 DVR_WrapperRecordSegmentInfo_t *pseg;
1869
1870 /*as the player do not support null playlist,
1871 there must be one segment existed at any time,
1872 we have to keep two segments before remove one*/
1873 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
1874 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
1875 /*only one segment, waiting for more*/
1876 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of max_time(%ld) of record < max size of segment(%lld)\n",
1877 status.info.size,
1878 ctx->record.param_open.max_time,
1879 ctx->record.param_open.segment_size);
1880 } else {
1881 /*timeshifting, remove the 1st segment and notify the player*/
1882 record_removeSegment(ctx, pseg);
1883
1884 process_generateRecordStatus(ctx, &status);
1885 process_notifyRecord(ctx, evt->record.event, &status);
1886 }
1887 }
1888
1889 if (ctx->record.param_open.is_timeshift
1890 && ctx->record.param_open.max_size
1891 && status.info.size >= ctx->record.param_open.max_size) {
1892 DVR_WrapperRecordSegmentInfo_t *pseg;
1893
1894 /*as the player do not support null playlist,
1895 there must be one segment existed at any time,
1896 we have to keep two segments before remove one*/
1897 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
1898 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
1899 /*only one segment, waiting for more*/
1900 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of record < max size of segment(%lld)\n",
1901 status.info.size,
1902 ctx->record.param_open.segment_size);
1903 } else {
1904 record_removeSegment(ctx, pseg);
1905
1906 process_generateRecordStatus(ctx, &status);
1907 process_notifyRecord(ctx, evt->record.event, &status);
1908 }
1909 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001910 } break;
1911 case DVR_RECORD_STATE_STOPPED:
1912 {
1913 ctx->record.seg_status = evt->record.status;
1914
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001915 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001916 process_notifyRecord(ctx, evt->record.event, &status);
1917 } break;
1918 default:
1919 break;
1920 }
1921 } break;
hualing chen4b7c15d2020-04-07 16:13:48 +08001922 case DVR_RECORD_EVENT_WRITE_ERROR: {
1923 ctx->record.seg_status = evt->record.status;
1924 status.state = evt->record.status.state;
1925 process_notifyRecord(ctx, evt->record.event, &status);
1926 }break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001927 default:
1928 break;
1929 }
1930 return DVR_SUCCESS;
1931}
1932
1933static inline int process_notifyPlayback(DVR_WrapperCtx_t *ctx, DVR_PlaybackEvent_t evt, DVR_WrapperPlaybackStatus_t *status)
1934{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001935 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 +08001936 ctx->sn,
1937 evt,
1938 status->state,
1939 status->info_cur.time,
1940 status->info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001941 status->info_obsolete.time);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001942
1943 if (ctx->playback.event_fn)
1944 return ctx->playback.event_fn(evt, status, ctx->playback.event_userdata);
1945 return 0;
1946}
1947
1948/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001949static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperPlaybackStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001950{
1951 /*the current seg is not covered in the statistics*/
1952 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1953
1954 memset(&ctx->playback.status, 0, sizeof(ctx->playback.status));
1955 ctx->playback.status.pids = ctx->playback.pids_req;
1956
1957 ctx->playback.status.state = ctx->playback.seg_status.state;
1958 ctx->playback.status.speed = ctx->playback.seg_status.speed;
1959 ctx->playback.status.flags = ctx->playback.seg_status.flags;
1960 ctx->current_segment_id = ctx->playback.seg_status.segment_id;
1961
1962 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1963 if (pseg->seg_info.id == ctx->playback.seg_status.segment_id)
1964 break;
1965 ctx->playback.status.info_cur.time += pseg->seg_info.duration;
1966 ctx->playback.status.info_cur.size += pseg->seg_info.size;
1967 ctx->playback.status.info_cur.pkts += pseg->seg_info.nb_packets;
1968 }
1969 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1970 ctx->playback.status.info_full.time += pseg->seg_info.duration;
1971 ctx->playback.status.info_full.size += pseg->seg_info.size;
1972 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
1973 }
1974
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001975 if (status) {
1976 *status = ctx->playback.status;
1977 /*deal with current, lack size and pkts with the current*/
1978 status->info_cur.time += ctx->playback.seg_status.time_cur;
1979 status->info_obsolete.time = ctx->playback.obsolete.time;
1980 }
1981
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001982 return DVR_SUCCESS;
1983}
1984
1985static int process_handlePlaybackEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
1986{
1987 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d) cur(%lld:%u/%u)\n",
1988 evt->sn, evt->playback.event,
1989 evt->playback.status.play_status.state,
1990 evt->playback.status.play_status.segment_id,
1991 evt->playback.status.play_status.time_cur,
1992 evt->playback.status.play_status.time_end);
1993
1994 /*evt PLAYTIME will break the last logic, do not save*/
1995 if (evt->playback.event != DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME)
1996 ctx->playback.last_event = evt->playback.event;
1997
1998 switch (evt->playback.event)
1999 {
2000 case DVR_PLAYBACK_EVENT_FIRST_FRAME:
2001 case DVR_PLAYBACK_EVENT_REACHED_END:
2002 case DVR_PLAYBACK_EVENT_TRANSITION_OK:
2003 case DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME:
hualing chenb5cd42e2020-04-15 17:03:34 +08002004 case DVR_PLAYBACK_EVENT_ERROR:
hualing chenf291cf32020-06-18 10:50:30 +08002005 case DVR_PLAYBACK_EVENT_REACHED_BEGIN:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002006 {
2007 DVR_WrapperPlaybackStatus_t status;
2008
2009 /*copy status of segment*/
2010 ctx->playback.seg_status = evt->playback.status.play_status;
2011
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002012 /*generate status of the whole playback*/
2013 process_generatePlaybackStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002014
2015 if (evt->playback.event == DVR_PLAYBACK_EVENT_REACHED_END) {
2016 if (ctx->playback.param_open.is_timeshift) {
2017 /*wait for more data in recording*/
2018 } else if ((status.info_cur.time + DVR_PLAYBACK_END_GAP) >= ctx->playback.status.info_full.time) {
2019 process_notifyPlayback(ctx, evt->playback.event, &status);
hualing chenb5cd42e2020-04-15 17:03:34 +08002020 } else {
2021 ctx->playback.reach_end = DVR_TRUE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002022 }
hualing chenf291cf32020-06-18 10:50:30 +08002023 } else if (evt->playback.event != DVR_PLAYBACK_EVENT_REACHED_BEGIN) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002024 process_notifyPlayback(ctx, evt->playback.event, &status);
2025 }
2026 } break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002027 case DVR_PLAYBACK_EVENT_TRANSITION_FAILED:
2028 case DVR_PLAYBACK_EVENT_KEY_FAILURE:
2029 case DVR_PLAYBACK_EVENT_NO_KEY:
2030 {
2031 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) error event:0x%x\n", evt->sn, evt->playback.event);
2032 } break;
2033 default:
2034 {
2035 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) unknown event:0x%x\n", evt->sn, evt->playback.event);
2036 } break;
2037 }
2038 return 0;
2039}
2040
2041static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2042{
2043 return (evt->type == W_REC)? process_handleRecordEvent(evt, ctx) : process_handlePlaybackEvent(evt, ctx);
2044}
2045