blob: d7123980d5d6a8d3770738bac1d5942ece3ec735 [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"
17#define list_last_entry(ptr, type, member) \
18 list_entry((ptr)->prev, type, member)
19
20#include "dvr_wrapper.h"
21
22#define DVR_WRAPPER_DEBUG(_level, _fmt, ...) \
23 DVR_DEBUG(_level, "wrapper %-30.30s:%d " _fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
24
25/*duration of data to resume if paused with EVT_REACHED_END in timeshifting*/
26#define TIMESHIFT_DATA_DURATION_TO_RESUME (2000)
27/*a tolerant gap*/
28#define DVR_PLAYBACK_END_GAP (1000)
29
30enum {
31 W_REC = 1,
32 W_PLAYBACK = 2,
33};
34
35enum {
36 U_PIDS = 0x01,
37 U_STAT = 0x02,
38 U_ALL = U_PIDS | U_STAT,
39};
40
41typedef struct {
42 /*make lock the 1st item in the structure*/
43 pthread_mutex_t lock;
44
45 /*rec or play*/
46 int type;
47
48 /*valid if (sn != 0)*/
49 unsigned long sn;
50 unsigned long sn_linked;
51
52 struct list_head segments; /**<head-add list*/
53 uint64_t current_segment_id; /**<id of the current segment*/
54
55 union {
56 struct {
57 DVR_WrapperRecordOpenParams_t param_open;
58 DVR_RecordStartParams_t param_start;
59 DVR_RecordStartParams_t param_update;
60 DVR_RecordHandle_t recorder;
61 DVR_RecordEventFunction_t event_fn;
62 void *event_userdata;
63
64 /*total status = seg_status + status*/
65 DVR_RecordStatus_t seg_status; /**<status of current segment*/
66 DVR_WrapperRecordStatus_t status; /**<status of remaining segments*/
67 uint64_t next_segment_id;
68 } 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;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080082 } playback;
83 };
84} DVR_WrapperCtx_t;
85
86typedef struct {
87 struct list_head head;
88 unsigned long sn;
89
90 /* rec or playback */
91 int type;
92
93 union {
94 struct {
95 DVR_RecordEvent_t event;
96 DVR_RecordStatus_t status;
97 } record;
98 struct {
99 DVR_PlaybackEvent_t event;
100 DVR_Play_Notify_t status;
101 } playback;
102 };
103} DVR_WrapperEventCtx_t;
104
105typedef struct {
106 pthread_mutex_t lock;
107 char *name;
108 int running;
109 pthread_cond_t cond;
110 pthread_t thread;
111 int type;
112} DVR_WrapperThreadCtx_t;
113
114typedef struct {
115 struct list_head head;
116
117 DVR_RecordSegmentInfo_t seg_info;
118 DVR_PlaybackSegmentInfo_t playback_info;
119} DVR_WrapperPlaybackSegmentInfo_t;
120
121typedef struct {
122 struct list_head head;
123
124 DVR_RecordSegmentInfo_t info;
125} DVR_WrapperRecordSegmentInfo_t;
126
127/* serial num generater */
128static unsigned long sn = 1;
129static pthread_mutex_t sn_lock = PTHREAD_MUTEX_INITIALIZER;
130
131static inline unsigned long get_sn()
132{
133 unsigned long no;
134
135 pthread_mutex_lock(&sn_lock);
136 no = sn++;
137 if (!no)
138 no = sn++;
139 pthread_mutex_unlock(&sn_lock);
140
141 return no;
142}
143
144/* entity ctx */
145#define DVR_WRAPPER_MAX 10
146
147static DVR_WrapperCtx_t record_list[DVR_WRAPPER_MAX] =
148{
149 [0 ... (DVR_WRAPPER_MAX - 1)] =
150 {
151 .lock = PTHREAD_MUTEX_INITIALIZER,
152 .type = W_REC,
153 }
154};
155
156static DVR_WrapperCtx_t playback_list[DVR_WRAPPER_MAX] =
157{
158 [0 ... (DVR_WRAPPER_MAX - 1)] =
159 {
160 .lock = PTHREAD_MUTEX_INITIALIZER,
161 .type = W_PLAYBACK,
162 }
163};
164
165/* events lists */
166static struct list_head record_evt_list = LIST_HEAD_INIT(record_evt_list);
167static struct list_head playback_evt_list = LIST_HEAD_INIT(playback_evt_list);
168
169static pthread_mutex_t record_evt_list_lock = PTHREAD_MUTEX_INITIALIZER;
170static pthread_mutex_t playback_evt_list_lock = PTHREAD_MUTEX_INITIALIZER;
171
172static DVR_WrapperThreadCtx_t wrapper_thread[2] =
173{
174 [0] =
175 {
176 .lock = PTHREAD_MUTEX_INITIALIZER,
177 .running = 0,
178 .name = "record",
179 .type = W_REC,
180 },
181 [1] =
182 {
183 .lock = PTHREAD_MUTEX_INITIALIZER,
184 .running = 0,
185 .name = "playback",
186 .type = W_PLAYBACK,
187 },
188};
189
190/*now only support one timeshift now*/
191static unsigned long sn_timeshift_record;
192static unsigned long sn_timeshift_playback;
193
194static void *wrapper_task(void *arg);
195static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx);
196
197static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata);
198static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata);
199
200static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx);
201static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx);
202
203
204static DVR_WrapperEventCtx_t *ctx_getEvent(struct list_head *list, pthread_mutex_t *list_lock)
205{
206 DVR_WrapperEventCtx_t *pevt;
207
208 pthread_mutex_lock(list_lock);
209 if (list_empty(list))
210 pevt = NULL;
211 else {
212 pevt = list_first_entry(list, DVR_WrapperEventCtx_t, head);
213 list_del(&pevt->head);
214 }
215 pthread_mutex_unlock(list_lock);
216
217 return pevt;
218}
219
220static inline DVR_WrapperEventCtx_t *ctx_getRecordEvent()
221{
222 return ctx_getEvent(&record_evt_list, &record_evt_list_lock);
223}
224
225static inline DVR_WrapperEventCtx_t *ctx_getPlaybackEvent()
226{
227 return ctx_getEvent(&playback_evt_list, &playback_evt_list_lock);
228}
229
230static int ctx_addEvent(struct list_head *list, pthread_mutex_t *lock, DVR_WrapperEventCtx_t *evt)
231{
232 DVR_WrapperEventCtx_t *padd;
233 padd = (DVR_WrapperEventCtx_t *)calloc(1, sizeof(DVR_WrapperEventCtx_t));
234 DVR_RETURN_IF_FALSE(padd);
235
236 *padd = *evt;
237 pthread_mutex_lock(lock);
238 list_add_tail(&padd->head, list);
239 pthread_mutex_unlock(lock);
240 return DVR_SUCCESS;
241}
242
243static inline void ctx_freeEvent(DVR_WrapperEventCtx_t *evt)
244{
245 free(evt);
246}
247
248/*useless*/
249static void ctx_cleanOutdatedEvents(struct list_head *evt_list,
250 pthread_mutex_t *evt_list_lock,
251 DVR_WrapperCtx_t *list)
252{
253 DVR_WrapperEventCtx_t *pevt, *pevt_tmp;
254 unsigned long sns[DVR_WRAPPER_MAX];
255 int cnt = 0;
256 int i;
257 int found = 0;
258
259 /*copy all valid sns*/
260 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
261 sns[cnt] = list[i].sn;
262 if (!sns[cnt])
263 cnt++;
264 }
265
266 /*free evts that not belong to any valid sns*/
267 pthread_mutex_lock(evt_list_lock);
268 list_for_each_entry_safe(pevt, pevt_tmp, evt_list, head) {
269 for (i = 0; i < cnt; i++) {
270 if (pevt->sn == sns[i]) {
271 found = 1;
272 break;
273 }
274 }
275 if (!found) {
276 list_del(&pevt->head);
277 ctx_freeEvent(pevt);
278 }
279 }
280 pthread_mutex_unlock(evt_list_lock);
281}
282
283static inline void ctx_cleanOutdatedRecordEvents()
284{
285 ctx_cleanOutdatedEvents(&record_evt_list, &record_evt_list_lock, record_list);
286}
287
288static inline void ctx_cleanOutdatedPlaybackEvents()
289{
290 ctx_cleanOutdatedEvents(&playback_evt_list, &playback_evt_list_lock, playback_list);
291}
292
293static inline DVR_WrapperCtx_t *ctx_get(unsigned long sn, DVR_WrapperCtx_t *list)
294{
295 int i;
296 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
297 if (list[i].sn == sn)
298 return &list[i];
299 }
300 return NULL;
301}
302
303static inline void ctx_reset(DVR_WrapperCtx_t *ctx)
304{
305 memset((char *)ctx + offsetof(DVR_WrapperCtx_t, sn),
306 0,
307 sizeof(DVR_WrapperCtx_t) - offsetof(DVR_WrapperCtx_t, sn));
308}
309
310static inline int ctx_valid(DVR_WrapperCtx_t *ctx)
311{
312 return (ctx->sn != 0);
313}
314
315static inline DVR_WrapperCtx_t *ctx_getRecord(unsigned long sn)
316{
317 return ctx_get(sn, record_list);
318}
319
320static inline DVR_WrapperCtx_t *ctx_getPlayback(unsigned long sn)
321{
322 return ctx_get(sn, playback_list);
323}
324
325static int wrapper_requestThread(DVR_WrapperThreadCtx_t *ctx, void *(thread_fn)(void *))
326{
327 pthread_mutex_lock(&ctx->lock);
328 if (ctx->running == 0) {
329 pthread_condattr_t attr;
330 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
331 pthread_cond_init(&ctx->cond, &attr);
332 pthread_condattr_destroy(&attr);
333 DVR_WRAPPER_DEBUG(1, "start wrapper thread(%s) ...\n", ctx->name);
334 pthread_create(&ctx->thread, NULL, thread_fn, ctx);
335 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) started\n", ctx->name);
336 }
337 ctx->running++;
338 pthread_mutex_unlock(&ctx->lock);
339 return 0;
340}
341
342static int wrapper_releaseThread(DVR_WrapperThreadCtx_t *ctx)
343{
344 pthread_mutex_lock(&ctx->lock);
345 ctx->running--;
346 if (!ctx->running) {
347 pthread_cond_broadcast(&ctx->cond);
348 pthread_mutex_unlock(&ctx->lock);
349
350 DVR_WRAPPER_DEBUG(1, "stop wrapper thread(%s) ...\n", ctx->name);
351 pthread_join(ctx->thread, NULL);
352 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) stopped\n", ctx->name);
353
354 pthread_mutex_lock(&ctx->lock);
355 if (!ctx->running) /*protect*/
356 pthread_cond_destroy(&ctx->cond);
357 }
358 pthread_mutex_unlock(&ctx->lock);
359 return 0;
360}
361
362#define WRAPPER_THREAD_RECORD (&wrapper_thread[0])
363#define WRAPPER_THREAD_PLAYBACK (&wrapper_thread[1])
364
365static inline int wrapper_requestThreadFor(DVR_WrapperCtx_t *ctx)
366{
367 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
368 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
369 return wrapper_requestThread(thread_ctx, wrapper_task);
370}
371
372static inline int wrapper_releaseThreadFor(DVR_WrapperCtx_t *ctx)
373{
374 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
375 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
376 return wrapper_releaseThread(thread_ctx);
377}
378
379static inline int wrapper_releaseThreadForType(int type)
380{
381 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC)?
382 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
383 return wrapper_releaseThread(thread_ctx);
384}
385
386static inline void wrapper_threadSignal(DVR_WrapperThreadCtx_t *thread_ctx)
387{
388 pthread_cond_signal(&thread_ctx->cond);
389}
390
391static inline int wrapper_threadWait(DVR_WrapperThreadCtx_t *thread_ctx)
392{
393 pthread_cond_wait(&thread_ctx->cond, &thread_ctx->lock);
394 return 0;
395}
396
397static inline void wrapper_threadSignalForType(int type)
398{
399 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC) ?
400 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
401 wrapper_threadSignal(thread_ctx);
402}
403
404static inline void wrapper_threadSignalFor(DVR_WrapperCtx_t *ctx)
405{
406 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
407 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
408 wrapper_threadSignal(thread_ctx);
409}
410
411static inline int wrapper_threadWaitFor(DVR_WrapperCtx_t *ctx)
412{
413 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
414 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
415 wrapper_threadWait(thread_ctx);
416 return 0;
417}
418
419static void get_timeout_real(int timeout, struct timespec *ts)
420{
421 struct timespec ots;
422 int left, diff;
423
424 clock_gettime(CLOCK_REALTIME, &ots);
425
426 ts->tv_sec = ots.tv_sec + timeout/1000;
427 ts->tv_nsec = ots.tv_nsec;
428
429 left = timeout % 1000;
430 left *= 1000000;
431 diff = 1000000000-ots.tv_nsec;
432
433 if (diff <= left) {
434 ts->tv_sec++;
435 ts->tv_nsec = left-diff;
436 } else {
437 ts->tv_nsec += left;
438 }
439}
440
441/*return condition, locked if condition == true*/
442static int wrapper_mutex_lock_if(pthread_mutex_t *lock, int *condition)
443{
444 int r2;
445 do {
446 struct timespec rt2;
447 /*android use real time for mutex timedlock*/
448 get_timeout_real(10, &rt2);
449 r2 = pthread_mutex_timedlock(lock, &rt2);
450 } while (*condition && (r2 == ETIMEDOUT));
451
452 if (!(*condition) && (r2 == 0))
453 pthread_mutex_unlock(lock);
454
455 return *condition;
456}
457
458static void *wrapper_task(void *arg)
459{
460 DVR_WrapperThreadCtx_t *tctx = (DVR_WrapperThreadCtx_t *)arg;
461 DVR_WrapperEventCtx_t *evt;
462
463 pthread_mutex_lock(&tctx->lock);
464
465 while (tctx->running) {
466 {
467 int ret;
468 ret = wrapper_threadWait(tctx);
469 }
470
471 while ((evt = ((tctx->type == W_REC)? ctx_getRecordEvent() : ctx_getPlaybackEvent()))) {
472 DVR_WrapperCtx_t *ctx = (evt->type == W_REC)?
473 ctx_getRecord(evt->sn) : ctx_getPlayback(evt->sn);
474
475 if (tctx->running) {
476 /*
477 continue not break,
478 make all events consumed, or mem leak
479 */
480 if (!wrapper_mutex_lock_if(&ctx->lock, &tctx->running))
481 continue;
482 if (ctx_valid(ctx)) {
483 /*double check after lock*/
484 if (evt->sn == ctx->sn)
485 process_handleEvents(evt, ctx);
486 }
487 pthread_mutex_unlock(&ctx->lock);
488 }
489
490 ctx_freeEvent(evt);
491 }
492 }
493
494 pthread_mutex_unlock(&tctx->lock);
495 return NULL;
496}
497
498static inline int ctx_addRecordEvent(DVR_WrapperEventCtx_t *evt)
499{
500 if (ctx_addEvent(&record_evt_list, &record_evt_list_lock, evt) == 0)
501 wrapper_threadSignalForType(evt->type);
502 return 0;
503}
504
505static inline int ctx_addPlaybackEvent(DVR_WrapperEventCtx_t *evt)
506{
507 if (ctx_addEvent(&playback_evt_list, &playback_evt_list_lock, evt) == 0)
508 wrapper_threadSignalForType(evt->type);
509 return 0;
510}
511
512static inline void ctx_freeSegments(DVR_WrapperCtx_t *ctx)
513{
514 DVR_WrapperPlaybackSegmentInfo_t *pseg, *pseg_tmp;
515 list_for_each_entry_safe(pseg, pseg_tmp, &ctx->segments, head) {
516 list_del(&pseg->head);
517 free(pseg);
518 }
519}
520
521static inline void _updatePlaybackSegment(DVR_WrapperPlaybackSegmentInfo_t *pseg,
522 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
523{
524 (void)ctx;
525 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
526 pseg->seg_info = *seg_info;
527 else if (update_flags & U_PIDS) {
528 pseg->seg_info.nb_pids = seg_info->nb_pids;
529 memcpy(pseg->seg_info.pids, seg_info->pids, sizeof(pseg->seg_info.pids));
530 } else if (update_flags & U_STAT) {
531 pseg->seg_info.duration = seg_info->duration;
532 pseg->seg_info.size = seg_info->size;
533 pseg->seg_info.nb_packets = seg_info->nb_packets;
534 }
535
536 /*no changes
537 DVR_PlaybackSegmentFlag_t flags;
538 pseg->playback_info.segment_id = pseg->seg_info.id;
539 strncpy(pseg->playback_info.location,
540 ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
541 pseg->playback_info.pids = ctx->playback.pids_req;
542 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
543 if (ctx->record.param_open.flags | DVR_RECORD_FLAG_SCRAMBLED)
544 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
545 pseg->playback_info.flags = flags;
546 */
547}
548
549static int wrapper_updatePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
550{
551 DVR_WrapperPlaybackSegmentInfo_t *pseg;
552
553 DVR_WRAPPER_DEBUG(1, "timeshift, update playback segments(wrapper), seg:%lld t/s/p(%ld/%zu/%u)\n",
554 seg_info->id, seg_info->duration, seg_info->size, seg_info->nb_packets);
555
556 if (list_empty(&ctx->segments)) {
557 DVR_WRAPPER_DEBUG(1, "timeshift, update while no segment exists, ignore\n");
558 return DVR_SUCCESS;
559 }
560
561 /*normally, the last segment added will be updated*/
562 pseg =
563 list_first_entry(&ctx->segments, DVR_WrapperPlaybackSegmentInfo_t, head);
564 if (pseg->seg_info.id == seg_info->id) {
565 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
566 } else {
567 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
568 if (pseg->seg_info.id == seg_info->id) {
569 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
570 break;
571 }
572 }
573 }
574
575 /*need to notify the dvr_playback*/
576 if (ctx->playback.param_open.is_timeshift/*should must be timeshift*/
577 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END
578 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
579 if (
580 /*there's $TIMESHIFT_DATA_DURATION_TO_RESUME more of data in the current segment playing*/
581 (ctx->playback.seg_status.segment_id == seg_info->id
582 && (seg_info->duration >= ((time_t)ctx->playback.seg_status.time_cur + TIMESHIFT_DATA_DURATION_TO_RESUME)))
583 ||
584 /*or there's a new segment and has $TIMESHIFT_DATA_DURATION_TO_RESUME of data*/
585 (ctx->playback.seg_status.segment_id != seg_info->id
586 && (seg_info->duration >= TIMESHIFT_DATA_DURATION_TO_RESUME))
587 )
588 {
589 int error;
590
591 error = dvr_playback_resume(ctx->playback.player);
592 DVR_WRAPPER_DEBUG(1, "timeshift, resume playback(sn:%ld) (%d) id/dur: rec(%lld/%ld) play(%lld/%u)\n",
593 ctx->sn, error,
594 seg_info->id, seg_info->duration,
595 ctx->playback.seg_status.segment_id, ctx->playback.seg_status.time_cur);
596 }
597 }
598
599 return DVR_SUCCESS;
600}
601
602static void _updateRecordSegment(DVR_WrapperRecordSegmentInfo_t *pseg,
603 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
604{
605 (void)ctx;
606 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
607 pseg->info = *seg_info;
608 else if (update_flags & U_PIDS) {
609 pseg->info.nb_pids = seg_info->nb_pids;
610 memcpy(pseg->info.pids, seg_info->pids, sizeof(pseg->info.pids));
611 } else if (update_flags & U_STAT) {
612 pseg->info.duration = seg_info->duration;
613 pseg->info.size = seg_info->size;
614 pseg->info.nb_packets = seg_info->nb_packets;
615 }
616}
617
618static int wrapper_updateRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
619{
hualing chen266b9502020-04-04 17:39:39 +0800620 DVR_WrapperRecordSegmentInfo_t *pseg = NULL;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800621
622 /*normally, the last segment added will be updated*/
hualing chen266b9502020-04-04 17:39:39 +0800623 if (!list_empty(&ctx->segments)) {
624 pseg =
625 list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
626 if (pseg->info.id == seg_info->id) {
627 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
628 } else {
629 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
630 if (pseg->info.id == seg_info->id) {
631 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
632 break;
633 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800634 }
635 }
636 }
637
638 /*timeshift, update the segment for playback*/
639 /*
640 the playback should grab the segment info other than the id,
641 and the id will be updated by each segment-add during the recording
642 */
643 /*
644 the playback paused if no data been checked from recording,
645 should resume the player later when there's more data
646 */
647
648 if (ctx->record.param_open.is_timeshift) {
649 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
650
651 if (ctx_playback) {
652 pthread_mutex_lock(&ctx_playback->lock);
653 if (ctx_valid(ctx_playback)
654 && ctx_playback->sn == sn_timeshift_playback) {
655 wrapper_updatePlaybackSegment(ctx_playback, seg_info, update_flags);
656 }
657 pthread_mutex_unlock(&ctx_playback->lock);
658 }
659 }
660
661 return DVR_SUCCESS;
662}
663
664static int wrapper_addPlaybackSegment(DVR_WrapperCtx_t *ctx,
665 DVR_RecordSegmentInfo_t *seg_info,
666 DVR_PlaybackPids_t *p_pids,
667 DVR_PlaybackSegmentFlag_t flags)
668{
669 DVR_WrapperPlaybackSegmentInfo_t *pseg;
670 int error;
671
672 error = 0;
673 pseg = (DVR_WrapperPlaybackSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperPlaybackSegmentInfo_t));
674 if (!pseg) {
675 error = DVR_FAILURE;
676 DVR_WRAPPER_DEBUG(1, "memory fail\n");
677 return error;
678 }
679
680 /*copy the orignal segment info*/
681 pseg->seg_info = *seg_info;
682 /*generate the segment info used in playback*/
683 pseg->playback_info.segment_id = pseg->seg_info.id;
684 strncpy(pseg->playback_info.location, ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
685 pseg->playback_info.pids = *p_pids;
686 pseg->playback_info.flags = flags;
687 list_add(&pseg->head, &ctx->segments);
688
689 error = dvr_playback_add_segment(ctx->playback.player, &pseg->playback_info);
690 if (error) {
691 DVR_WRAPPER_DEBUG(1, "fail to add segment %lld (%d)\n", pseg->playback_info.segment_id, error);
692 } else {
693 ctx->playback.status.info_full.time += pseg->seg_info.duration;
694 ctx->playback.status.info_full.size += pseg->seg_info.size;
695 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
696 }
697
698 return error;
699}
700
701static int wrapper_addRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
702{
703 DVR_WrapperRecordSegmentInfo_t *pseg;
704 int error;
705
706 error = 0;
707 pseg = (DVR_WrapperRecordSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperRecordSegmentInfo_t));
708 if (!pseg) {
709 error = DVR_FAILURE;
710 DVR_WRAPPER_DEBUG(1, "memory fail\n");
711 }
712 pseg->info = *seg_info;
713 list_add(&pseg->head, &ctx->segments);
714
715 if (ctx->record.param_open.is_timeshift) {
716 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
717
718 if (ctx_playback) {
719 pthread_mutex_lock(&ctx_playback->lock);
720 if (ctx_valid(ctx_playback)) {
721 DVR_PlaybackSegmentFlag_t flags;
722
723 /*only if playback has started, the previous segments have been loaded*/
724 if (!list_empty(&ctx_playback->segments)) {
725 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
726 if (ctx->record.param_open.flags | DVR_RECORD_FLAG_SCRAMBLED)
727 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
728 wrapper_addPlaybackSegment(ctx_playback, seg_info, &ctx_playback->playback.pids_req, flags);
729 }
730 }
731 pthread_mutex_unlock(&ctx_playback->lock);
732 }
733 }
734
735 return error;
736}
737
738static int wrapper_removePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
739{
740 int error;
741
742 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->id);
743
744 error = dvr_playback_remove_segment(ctx->playback.player, seg_info->id);
745 if (error) {
746 /*remove playack segment fail*/
747 } else {
748 DVR_WrapperPlaybackSegmentInfo_t *pseg;
749
750 /*normally, should be the earliest segment in the list*/
751 pseg = list_last_entry(&ctx->segments, DVR_WrapperPlaybackSegmentInfo_t, head);
752 if (pseg->seg_info.id == seg_info->id) {
753 list_del(&pseg->head);
754 free(pseg);
755 } else {
756 /*what's going on*/
757 }
758 }
759
760 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->id, error);
761
762 return error;
763}
764
765static int wrapper_removeRecordSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *seg_info)
766{
767 int error;
768 DVR_WrapperRecordSegmentInfo_t *pseg;
769
770 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->info.id);
771
772 /*if timeshifting, notify the playback first, then deal with record*/
773 if (ctx->record.param_open.is_timeshift) {
774 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
775
776 if (ctx_playback) {
777 pthread_mutex_lock(&ctx_playback->lock);
778 if (ctx_valid(ctx_playback)
779 && ctx_playback->sn == sn_timeshift_playback
780 && !list_empty(&ctx_playback->segments)) {
781 error = wrapper_removePlaybackSegment(ctx_playback, &seg_info->info);
782 }
783 pthread_mutex_unlock(&ctx_playback->lock);
784 }
785 }
786
787 /*normally, the earliest segment will be removed*/
788 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
789 if (pseg->info.id == seg_info->info.id) {
790 list_del(&pseg->head);
791 free(pseg);
792 } else {
793 /*should not get here*/
794 }
795
796 error = dvr_segment_delete(ctx->record.param_open.location, seg_info->info.id);
797
798 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->info.id, error);
799
800 return error;
801}
802
803int dvr_wrapper_open_record (DVR_WrapperRecord_t *rec, DVR_WrapperRecordOpenParams_t *params)
804{
805 int error;
806 DVR_WrapperCtx_t *ctx;
807 DVR_RecordOpenParams_t open_param;
808
809 DVR_RETURN_IF_FALSE(rec);
810 DVR_RETURN_IF_FALSE(params);
811
812 /*get a free ctx*/
813 ctx = ctx_getRecord(0);
814 DVR_RETURN_IF_FALSE(ctx);
815
816 pthread_mutex_lock(&ctx->lock);
817
818 DVR_WRAPPER_DEBUG(1, "open record(dmx:%d) ...\n", params->dmx_dev_id);
819
820 ctx_reset(ctx);
821
822 ctx->record.param_open = *params;
823 ctx->record.event_fn = params->event_fn;
824 ctx->record.event_userdata = params->event_userdata;
825 ctx->record.next_segment_id = 0;
826 ctx->current_segment_id = 0;
827 INIT_LIST_HEAD(&ctx->segments);
828 ctx->sn = get_sn();
829
830 wrapper_requestThreadFor(ctx);
831
hualing chen266b9502020-04-04 17:39:39 +0800832 memset(&open_param, 0, sizeof(DVR_RecordOpenParams_t));
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800833 open_param.dmx_dev_id = params->dmx_dev_id;
834 open_param.data_from_memory = 0;
835 open_param.flags = params->flags;
Zhiqiang Han104aed72020-04-03 19:37:43 +0800836 open_param.notification_size = 500*1024;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800837 open_param.event_fn = wrapper_record_event_handler;
838 open_param.event_userdata = (void*)ctx->sn;
839
840 error = dvr_record_open(&ctx->record.recorder, &open_param);
841 if (error) {
842 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) open fail(error:%d).\n", params->dmx_dev_id, error);
843 ctx_reset(ctx);
844 pthread_mutex_unlock(&ctx->lock);
845 wrapper_releaseThreadForType(ctx->type);
846 return DVR_FAILURE;
847 }
848 if (params->is_timeshift)
849 sn_timeshift_record = ctx->sn;
850
851 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
852
hualing chen266b9502020-04-04 17:39:39 +0800853 error = dvr_record_set_encrypt_callback(ctx->record.recorder, params->crypto_fn, params->crypto_data);
854 if (error) {
855 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) set encrypt callback fail(error:%d).\n", params->dmx_dev_id, error);
856 }
857
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800858 pthread_mutex_unlock(&ctx->lock);
859
860 *rec = (DVR_WrapperRecord_t)ctx->sn;
861 return DVR_SUCCESS;
862}
863
864int dvr_wrapper_close_record (DVR_WrapperRecord_t rec)
865{
866 DVR_WrapperCtx_t *ctx;
867 DVR_RecordSegmentInfo_t seg_info;
868 int error;
869
870 DVR_RETURN_IF_FALSE(rec);
871
872 ctx = ctx_getRecord((unsigned long)rec);
873 DVR_RETURN_IF_FALSE(ctx);
874
875 pthread_mutex_lock(&ctx->lock);
876 DVR_WRAPPER_DEBUG(1, "close record(sn:%ld)\n", ctx->sn);
877 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
878
879 memset(&seg_info, 0, sizeof(seg_info));
880 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
881
882 error = dvr_record_close(ctx->record.recorder);
883
884 sn_timeshift_record = 0;
885 ctx_freeSegments(ctx);
886
887 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) closed = (%d).\n", ctx->sn, error);
888 ctx_reset(ctx);
889 pthread_mutex_unlock(&ctx->lock);
890
891 wrapper_releaseThreadForType(ctx->type);
892
893 return error;
894}
895
896int dvr_wrapper_start_record (DVR_WrapperRecord_t rec, DVR_WrapperRecordStartParams_t *params)
897{
898 DVR_WrapperCtx_t *ctx;
899 DVR_RecordStartParams_t *start_param;
900 int i;
901 int error;
902
903 DVR_RETURN_IF_FALSE(rec);
904 DVR_RETURN_IF_FALSE(params);
905
906 ctx = ctx_getRecord((unsigned long)rec);
907 DVR_RETURN_IF_FALSE(ctx);
908
909 pthread_mutex_lock(&ctx->lock);
910 DVR_WRAPPER_DEBUG(1, "start record(sn:%ld, location:%s) ...\n", ctx->sn, ctx->record.param_open.location);
911 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
912
913 start_param = &ctx->record.param_start;
914 memset(start_param, 0, sizeof(*start_param));
915 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
916 start_param->segment.segment_id = ctx->record.next_segment_id++;
917 start_param->segment.nb_pids = params->pids_info.nb_pids;
918 for (i = 0; i < params->pids_info.nb_pids; i++) {
919 start_param->segment.pids[i] = params->pids_info.pids[i];
920 start_param->segment.pid_action[i] = DVR_RECORD_PID_CREATE;
921 }
922
923 {
924 /*sync to update for further use*/
925 DVR_RecordStartParams_t *update_param;
926 update_param = &ctx->record.param_update;
927 memcpy(update_param, start_param, sizeof(*update_param));
928 for (i = 0; i < update_param->segment.nb_pids; i++)
929 update_param->segment.pid_action[i] = DVR_RECORD_PID_KEEP;
930 }
931
932 error = dvr_record_start_segment(ctx->record.recorder, start_param);
933 {
934 DVR_RecordSegmentInfo_t new_seg_info =
935 { .id = start_param->segment.segment_id, };
936 wrapper_addRecordSegment(ctx, &new_seg_info);
937 }
938
939 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) started = (%d)\n", ctx->sn, error);
940
941 pthread_mutex_unlock(&ctx->lock);
942
943 return error;
944}
945
946int dvr_wrapper_stop_record (DVR_WrapperRecord_t rec)
947{
948 DVR_WrapperCtx_t *ctx;
949 DVR_RecordSegmentInfo_t seg_info;
950 int error;
951
952 DVR_RETURN_IF_FALSE(rec);
953
954 ctx = ctx_getRecord((unsigned long)rec);
955 DVR_RETURN_IF_FALSE(ctx);
956
957 pthread_mutex_lock(&ctx->lock);
958 DVR_WRAPPER_DEBUG(1, "stop record(sn:%ld) ...\n", ctx->sn);
959 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
960
961 memset(&seg_info, 0, sizeof(seg_info));
962 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
963 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
964
965 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) stopped = (%d)\n", ctx->sn, error);
966 pthread_mutex_unlock(&ctx->lock);
967
968 return error;
969}
970
971int dvr_wrapper_update_record_pids (DVR_WrapperRecord_t rec, DVR_WrapperUpdatePidsParams_t *params)
972{
973 DVR_WrapperCtx_t *ctx;
974 DVR_RecordStartParams_t *start_param;
975 DVR_RecordSegmentInfo_t seg_info;;
976 int i;
977 int error;
978
979 DVR_RETURN_IF_FALSE(rec);
980 DVR_RETURN_IF_FALSE(params);
981
982 ctx = ctx_getRecord((unsigned long)rec);
983 DVR_RETURN_IF_FALSE(ctx);
984
985 pthread_mutex_lock(&ctx->lock);
986 DVR_WRAPPER_DEBUG(1, "update record(sn:%ld)\n", ctx->sn);
987 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
988
989 start_param = &ctx->record.param_update;
990 memset(start_param, 0, sizeof(*start_param));
991 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
992 start_param->segment.segment_id = ctx->record.next_segment_id++;
993 start_param->segment.nb_pids = params->nb_pids;
994 for (i = 0; i < params->nb_pids; i++) {
995 start_param->segment.pids[i] = params->pids[i];
996 start_param->segment.pid_action[i] = params->pid_action[i];
997 }
998 error = dvr_record_next_segment(ctx->record.recorder, start_param, &seg_info);
999 {
1000 DVR_RecordSegmentInfo_t new_seg_info =
1001 { .id = start_param->segment.segment_id, };
1002 wrapper_updateRecordSegment(ctx, &seg_info, U_PIDS);
1003 wrapper_addRecordSegment(ctx, &new_seg_info);
1004 }
1005
1006 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) updated = (%d)\n", ctx->sn, error);
1007 pthread_mutex_unlock(&ctx->lock);
1008
1009 return error;
1010}
1011
1012int dvr_wrapper_get_record_status(DVR_WrapperRecord_t rec, DVR_WrapperRecordStatus_t *status)
1013{
1014 DVR_WrapperCtx_t *ctx;
1015 DVR_WrapperRecordStatus_t s;
1016 int error;
1017
1018 DVR_RETURN_IF_FALSE(rec);
1019 DVR_RETURN_IF_FALSE(status);
1020
1021 ctx = ctx_getRecord((unsigned long)rec);
1022 DVR_RETURN_IF_FALSE(ctx);
1023
1024 pthread_mutex_lock(&ctx->lock);
1025
1026 DVR_WRAPPER_DEBUG(1, "get record(sn:%ld) status ...\n", ctx->sn);
1027 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1028
1029 error = process_generateRecordStatus(ctx);
1030 s = ctx->record.status;
1031 s.info.time += ctx->record.seg_status.info.duration;
1032 s.info.size += ctx->record.seg_status.info.size;
1033 s.info.pkts += ctx->record.seg_status.info.nb_packets;
1034
1035 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) state/time/size/pkts(%d/%ld/%lld/%u) (%d)\n",
1036 ctx->sn,
1037 s.state,
1038 s.info.time,
1039 s.info.size,
1040 s.info.pkts,
1041 error);
1042
1043 *status = s;
1044
1045 pthread_mutex_unlock(&ctx->lock);
1046
1047 return error;
1048}
1049
hualing chen266b9502020-04-04 17:39:39 +08001050int dvr_wrapper_set_record_secure_buffer (DVR_WrapperRecord_t rec, uint8_t *p_secure_buf, uint32_t len)
1051{
1052 DVR_WrapperCtx_t *ctx;
1053 int error;
1054
1055 DVR_RETURN_IF_FALSE(rec);
1056 DVR_RETURN_IF_FALSE(p_secure_buf);
1057
1058 ctx = ctx_getRecord((unsigned long)rec);
1059 DVR_RETURN_IF_FALSE(ctx);
1060
1061 pthread_mutex_lock(&ctx->lock);
1062 error = dvr_record_set_secure_buffer(ctx->record.recorder, p_secure_buf, len);
1063 pthread_mutex_unlock(&ctx->lock);
1064 return error;
1065}
1066
1067int dvr_wrapper_set_record_decrypt_callback (DVR_WrapperRecord_t rec, DVR_CryptoFunction_t func, void *userdata)
1068{
1069 DVR_WrapperCtx_t *ctx;
1070 int error;
1071
1072 DVR_RETURN_IF_FALSE(rec);
1073 DVR_RETURN_IF_FALSE(func);
1074
1075 ctx = ctx_getRecord((unsigned long)rec);
1076 DVR_RETURN_IF_FALSE(ctx);
1077
1078 pthread_mutex_lock(&ctx->lock);
1079 error = dvr_record_set_encrypt_callback(ctx->record.recorder, func, userdata);
1080 pthread_mutex_unlock(&ctx->lock);
1081 return error;
1082}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001083
1084
1085int dvr_wrapper_open_playback (DVR_WrapperPlayback_t *playback, DVR_WrapperPlaybackOpenParams_t *params)
1086{
1087 DVR_WrapperCtx_t *ctx;
1088 DVR_PlaybackOpenParams_t open_param;
1089 int error;
1090
1091 DVR_RETURN_IF_FALSE(playback);
1092 DVR_RETURN_IF_FALSE(params);
1093 DVR_RETURN_IF_FALSE(params->playback_handle);
1094
1095 /*get a free ctx*/
1096 ctx = ctx_getPlayback(0);
1097 DVR_RETURN_IF_FALSE(ctx);
1098
1099 pthread_mutex_lock(&ctx->lock);
1100
1101 DVR_WRAPPER_DEBUG(1, "open playback(dmx:%d) ...\n", params->dmx_dev_id);
1102
1103 ctx_reset(ctx);
1104
1105 ctx->playback.param_open = *params;
1106 ctx->playback.event_fn = params->event_fn;
1107 ctx->playback.event_userdata = params->event_userdata;
1108 ctx->current_segment_id = 0;
1109 INIT_LIST_HEAD(&ctx->segments);
1110 ctx->sn = get_sn();
1111
1112 wrapper_requestThreadFor(ctx);
1113
hualing chen266b9502020-04-04 17:39:39 +08001114 memset(&open_param, 0, sizeof(DVR_PlaybackOpenParams_t));
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001115 open_param.dmx_dev_id = params->dmx_dev_id;
1116 open_param.block_size = params->block_size;
1117 open_param.is_timeshift = params->is_timeshift;
1118 //open_param.notification_size = 10*1024; //not supported
1119 open_param.event_fn = wrapper_playback_event_handler;
1120 open_param.event_userdata = (void*)ctx->sn;
1121 /*open_param.has_pids = 0;*/
1122
1123 open_param.player_handle = (am_tsplayer_handle)params->playback_handle;
1124
1125 error = dvr_playback_open(&ctx->playback.player, &open_param);
1126 if (error) {
1127 DVR_WRAPPER_DEBUG(1, "playback(dmx:%d) openned fail(error:%d).\n", params->dmx_dev_id, error);
1128 ctx_reset(ctx);
1129 pthread_mutex_unlock(&ctx->lock);
1130 wrapper_releaseThreadForType(ctx->type);
1131 return DVR_FAILURE;
1132 }
1133 if (params->is_timeshift)
1134 sn_timeshift_playback = ctx->sn;
1135
hualing chen266b9502020-04-04 17:39:39 +08001136 DVR_WRAPPER_DEBUG(1, "hanyh: playback(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
1137 error = dvr_playback_set_decrypt_callback(ctx->playback.player, params->crypto_fn, params->crypto_data);
1138 if (error) {
1139 DVR_WRAPPER_DEBUG(1, "playback set deccrypt callback fail(error:%d).\n", error);
1140 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001141 pthread_mutex_unlock(&ctx->lock);
1142
1143 *playback = (DVR_WrapperPlayback_t)ctx->sn;
1144 return DVR_SUCCESS;
1145}
1146
1147int dvr_wrapper_close_playback (DVR_WrapperPlayback_t playback)
1148{
1149 DVR_WrapperCtx_t *ctx;
1150 int error;
1151
1152 DVR_RETURN_IF_FALSE(playback);
1153
1154 ctx = ctx_getPlayback((unsigned long)playback);
1155 DVR_RETURN_IF_FALSE(ctx);
1156
1157 pthread_mutex_lock(&ctx->lock);
1158 DVR_WRAPPER_DEBUG(1, "close playback(sn:%ld)\n", ctx->sn);
1159 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1160
1161 if (ctx->playback.param_open.is_timeshift)
1162 sn_timeshift_playback = 0;
1163
1164 /*try stop first*/
1165 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1166
1167 {
1168 /*remove all segments*/
1169 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1170
1171 list_for_each_entry(pseg, &ctx->segments, head) {
1172 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1173 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1174 ctx->sn, pseg->playback_info.segment_id, error);
1175 }
1176 ctx_freeSegments(ctx);
1177 }
1178
1179 error = dvr_playback_close(ctx->playback.player);
1180
1181 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) closed.\n", ctx->sn);
1182 ctx_reset(ctx);
1183 pthread_mutex_unlock(&ctx->lock);
1184
1185 wrapper_releaseThreadForType(ctx->type);
1186
1187 return error;
1188}
1189
1190int dvr_wrapper_start_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackFlag_t flags, DVR_PlaybackPids_t *p_pids)
1191{
1192 DVR_WrapperCtx_t *ctx;
1193 int error;
1194 uint64_t *p_segment_ids;
1195 uint32_t segment_nb;
1196 uint32_t i;
1197 DVR_RecordSegmentInfo_t seg_info_1st;
1198 int got_1st_seg;
1199
1200 DVR_RETURN_IF_FALSE(playback);
1201 DVR_RETURN_IF_FALSE(p_pids);
1202
1203 ctx = ctx_getPlayback((unsigned long)playback);
1204 DVR_RETURN_IF_FALSE(ctx);
1205
1206 pthread_mutex_lock(&ctx->lock);
1207
1208 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",
1209 ctx->sn,
1210 ctx->playback.param_open.location,
1211 flags,
1212 p_pids->video.pid, p_pids->video.format,
1213 p_pids->audio.pid, p_pids->audio.format,
1214 p_pids->ad.pid, p_pids->ad.format,
1215 p_pids->subtitle.pid, p_pids->subtitle.format,
1216 p_pids->pcr.pid);
1217
1218 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1219
1220 /*obtain all segments in a list*/
1221 segment_nb = 0;
1222 p_segment_ids = NULL;
1223 error = dvr_segment_get_list(ctx->playback.param_open.location, &segment_nb, &p_segment_ids);
1224 DVR_RETURN_IF_FALSE_WITH_UNLOCK(!error, &ctx->lock);
1225
1226 got_1st_seg = 0;
1227 for (i = 0; i < segment_nb; i++) {
1228 DVR_RecordSegmentInfo_t seg_info;
1229 DVR_PlaybackSegmentFlag_t flags;
1230
1231 error = dvr_segment_get_info(ctx->playback.param_open.location, p_segment_ids[i], &seg_info);
1232 if (error) {
1233 error = DVR_FAILURE;
1234 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
1235 ctx->playback.param_open.location, p_segment_ids[i], error);
1236 break;
1237 }
1238
1239 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1240 error = wrapper_addPlaybackSegment(ctx, &seg_info, p_pids, flags);
1241 if (error)
1242 break;
1243
1244 /*copy the 1st segment*/
1245 if (got_1st_seg == 0) {
1246 seg_info_1st = seg_info;
1247 got_1st_seg = 1;
1248 }
1249 }
1250 free(p_segment_ids);
1251
1252 /* return if no segment or fail to add */
1253 DVR_RETURN_IF_FALSE_WITH_UNLOCK(!error && got_1st_seg, &ctx->lock);
1254
1255 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) (%d) segments added\n", ctx->sn, i);
1256
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001257 ctx->playback.speed = 100.0f;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001258 ctx->playback.pids_req = *p_pids;
1259
1260 error = dvr_playback_seek(ctx->playback.player, seg_info_1st.id, 0);
1261 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seek(seg:%llu 0) for start (%d)\n",
1262 ctx->sn, seg_info_1st.id, error);
1263
1264 error = dvr_playback_start(ctx->playback.player, flags);
1265
1266 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) started (%d)\n", ctx->sn, error);
1267
1268 pthread_mutex_unlock(&ctx->lock);
1269
1270 return error;
1271}
1272
1273int dvr_wrapper_stop_playback (DVR_WrapperPlayback_t playback)
1274{
1275 DVR_WrapperCtx_t *ctx;
1276 int error;
1277
1278 DVR_RETURN_IF_FALSE(playback);
1279
1280 ctx = ctx_getPlayback((unsigned long)playback);
1281 DVR_RETURN_IF_FALSE(ctx);
1282
1283 pthread_mutex_lock(&ctx->lock);
1284 DVR_WRAPPER_DEBUG(1, "stop playback(sn:%ld) ...\n", ctx->sn);
1285 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1286
1287 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1288
1289 {
1290 /*remove all segments*/
1291 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1292
1293 list_for_each_entry(pseg, &ctx->segments, head) {
1294 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1295 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1296 ctx->sn, pseg->playback_info.segment_id, error);
1297 }
1298 ctx_freeSegments(ctx);
1299 }
1300
1301 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) stopped (%d)\n", ctx->sn, error);
1302 pthread_mutex_unlock(&ctx->lock);
1303
1304 return error;
1305}
1306
1307int dvr_wrapper_pause_playback (DVR_WrapperPlayback_t playback)
1308{
1309 DVR_WrapperCtx_t *ctx;
1310 int error;
1311
1312 DVR_RETURN_IF_FALSE(playback);
1313
1314 ctx = ctx_getPlayback((unsigned long)playback);
1315 DVR_RETURN_IF_FALSE(ctx);
1316
1317 pthread_mutex_lock(&ctx->lock);
1318 DVR_WRAPPER_DEBUG(1, "pause playback(sn:%ld) ...\n", ctx->sn);
1319 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1320
1321 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
1322
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001323 ctx->playback.speed = 0.0f;
1324
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001325 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) paused (%d)\n", ctx->sn, error);
1326 pthread_mutex_unlock(&ctx->lock);
1327
1328 return error;
1329}
1330
1331int dvr_wrapper_resume_playback (DVR_WrapperPlayback_t playback)
1332{
1333 DVR_WrapperCtx_t *ctx;
1334 int error;
1335
1336 DVR_RETURN_IF_FALSE(playback);
1337
1338 ctx = ctx_getPlayback((unsigned long)playback);
1339 DVR_RETURN_IF_FALSE(ctx);
1340
1341 pthread_mutex_lock(&ctx->lock);
1342 DVR_WRAPPER_DEBUG(1, "resume playback(sn:%ld) ...\n", ctx->sn);
1343 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1344
1345 error = dvr_playback_resume(ctx->playback.player);
1346
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001347 ctx->playback.speed = 100.0f;
1348
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001349 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) resumed (%d)\n", ctx->sn, error);
1350 pthread_mutex_unlock(&ctx->lock);
1351
1352 return error;
1353}
1354
1355int dvr_wrapper_set_playback_speed (DVR_WrapperPlayback_t playback, float speed)
1356{
1357 DVR_WrapperCtx_t *ctx;
1358 int error;
1359 DVR_PlaybackSpeed_t dvr_speed = {
1360 .speed = { speed },
1361 .mode = (speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
1362 };
1363
1364 DVR_RETURN_IF_FALSE(playback);
1365
1366 ctx = ctx_getPlayback((unsigned long)playback);
1367 DVR_RETURN_IF_FALSE(ctx);
1368
1369 pthread_mutex_lock(&ctx->lock);
1370 DVR_WRAPPER_DEBUG(1, "speed playback(sn:%ld) (x%f) ...\n", ctx->sn, speed);
1371 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1372
1373 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
1374
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001375 if (ctx->playback.speed != 0.0f && ctx->playback.speed != 100.0f
1376 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_BEGIN
1377 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
1378 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, paused, do resume first\n", ctx->playback.speed, speed);
1379 error = dvr_playback_resume(ctx->playback.player);
1380 } else if (ctx->playback.speed == 0.0f
1381 && speed != 0.0f
1382 && speed != 100.0f) {
1383 /*libdvr do not support pause with speed=0, will not be here*/
1384 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, do resume first\n", ctx->playback.speed, speed);
1385 error = dvr_playback_resume(ctx->playback.player);
1386 }
1387
1388 ctx->playback.speed = speed;
1389
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001390 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) speeded(x%f) (%d)\n",
1391 ctx->sn, speed, error);
1392 pthread_mutex_unlock(&ctx->lock);
1393
1394 return error;
1395}
1396
1397int dvr_wrapper_seek_playback (DVR_WrapperPlayback_t playback, uint32_t time_offset)
1398{
1399 DVR_WrapperCtx_t *ctx;
1400 int error;
1401 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1402 uint64_t segment_id;
1403 uint32_t off;
1404 uint64_t last_segment_id;
1405 uint32_t pre_off;
1406
1407 DVR_RETURN_IF_FALSE(playback);
1408
1409 ctx = ctx_getPlayback((unsigned long)playback);
1410 DVR_RETURN_IF_FALSE(ctx);
1411
1412 pthread_mutex_lock(&ctx->lock);
1413
1414 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (off:%d) ...\n", ctx->sn, time_offset);
1415 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1416
1417 off = 0;
1418 segment_id = 0;
1419 pre_off = 0;
1420 last_segment_id = 0;
1421
1422 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1423 segment_id = pseg->seg_info.id;
1424
1425 if ((pre_off + pseg->seg_info.duration) > time_offset)
1426 break;
1427
1428 last_segment_id = pseg->seg_info.id;
1429 pre_off += pseg->seg_info.duration;
1430 }
1431
1432 if (last_segment_id == segment_id) {
1433 off = time_offset;
1434 } else {
1435 off = time_offset - pre_off;
1436 }
1437
1438
1439 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (seg:%lld, off:%d)\n", ctx->sn, segment_id, off);
1440 error = dvr_playback_seek(ctx->playback.player, segment_id, off);
1441 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seeked(off:%d) (%d)\n", ctx->sn, time_offset, error);
1442
1443 pthread_mutex_unlock(&ctx->lock);
1444
1445 return error;
1446}
1447
1448int dvr_wrapper_update_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackPids_t *p_pids)
1449{
1450 DVR_WrapperCtx_t *ctx;
1451 int error;
1452 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1453
1454 DVR_RETURN_IF_FALSE(playback);
1455 DVR_RETURN_IF_FALSE(p_pids);
1456
1457 ctx = ctx_getPlayback((unsigned long)playback);
1458 DVR_RETURN_IF_FALSE(ctx);
1459
1460 pthread_mutex_lock(&ctx->lock);
1461
1462 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) ...\n",
1463 ctx->sn,
1464 p_pids->video.pid, p_pids->video.format,
1465 p_pids->audio.pid, p_pids->audio.format);
1466 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1467
1468 ctx->playback.pids_req = *p_pids;
1469
1470 error = 0;
1471 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1472 /*should update the whole list of segments*/
1473 /*if (pseg->seg_info.id == ctx->current_segment_id)*/ {
1474 /*list_for_each_entry_from(pseg, &ctx->segments, head)*/ {
1475 /*check udpate for pids*/
1476 if (memcmp(&pseg->playback_info.pids, p_pids, sizeof(*p_pids)) != 0) {
1477 pseg->playback_info.pids = *p_pids;
1478 error = dvr_playback_update_segment_pids(ctx->playback.player, pseg->seg_info.id, p_pids);
1479 if (error) {
1480 DVR_WRAPPER_DEBUG(1, "failed to playback(sn:%ld) update segment(id:%lld) pids (%d)\n",
1481 ctx->sn, pseg->seg_info.id, error);
1482 /*do not break, let list updated*/
1483 }
1484 }
1485 }
1486 /*break;*/
1487 }
1488 }
1489
1490 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) (%d)\n",
1491 ctx->sn,
1492 p_pids->video.pid, p_pids->video.format,
1493 p_pids->audio.pid, p_pids->audio.format,
1494 error);
1495
1496 pthread_mutex_unlock(&ctx->lock);
1497
1498 return error;
1499}
1500
1501int dvr_wrapper_get_playback_status(DVR_WrapperPlayback_t playback, DVR_WrapperPlaybackStatus_t *status)
1502{
1503 DVR_WrapperCtx_t *ctx;
1504 DVR_WrapperPlaybackStatus_t s;
1505 DVR_PlaybackStatus_t play_status;
1506 int error;
1507
1508 DVR_RETURN_IF_FALSE(playback);
1509 DVR_RETURN_IF_FALSE(status);
1510
1511 ctx = ctx_getPlayback((unsigned long)playback);
1512 DVR_RETURN_IF_FALSE(ctx);
1513
1514 pthread_mutex_lock(&ctx->lock);
1515
1516 DVR_WRAPPER_DEBUG(1, "get playback(sn:%ld) status ...\n", ctx->sn);
1517 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1518
1519 error = dvr_playback_get_status(ctx->playback.player, &play_status);
1520 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) get status (%d)\n", ctx->sn, error);
1521
1522 ctx->playback.seg_status = play_status;
1523 error = process_generatePlaybackStatus(ctx);
1524 s = ctx->playback.status;
1525 s.info_cur.time += ctx->playback.seg_status.time_cur;
1526 /*size and packets are not available*/
1527
1528 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) state/cur/full(%d/%ld/%ld) (%d)\n",
1529 ctx->sn,
1530 s.state,
1531 s.info_cur.time,
1532 s.info_full.time,
1533 error);
1534
1535 *status = s;
1536
1537 pthread_mutex_unlock(&ctx->lock);
1538
1539 return error;
1540}
1541
hualing chen266b9502020-04-04 17:39:39 +08001542int dvr_wrapper_set_playback_secure_buffer (DVR_WrapperPlayback_t playback, uint8_t *p_secure_buf, uint32_t len)
1543{
1544 DVR_WrapperCtx_t *ctx;
1545 int error;
1546
1547 DVR_RETURN_IF_FALSE(playback);
1548 DVR_RETURN_IF_FALSE(p_secure_buf);
1549
1550 ctx = ctx_getPlayback((unsigned long)playback);
1551 DVR_RETURN_IF_FALSE(ctx);
1552
1553 pthread_mutex_lock(&ctx->lock);
1554 error = dvr_playback_set_secure_buffer(ctx->playback.player, p_secure_buf, len);
1555 pthread_mutex_unlock(&ctx->lock);
1556 return error;
1557}
1558
1559int dvr_wrapper_set_playback_decrypt_callback (DVR_WrapperPlayback_t playback, DVR_CryptoFunction_t func, void *userdata)
1560{
1561 DVR_WrapperCtx_t *ctx;
1562 int error;
1563
1564 DVR_RETURN_IF_FALSE(playback);
1565 DVR_RETURN_IF_FALSE(func);
1566
1567 ctx = ctx_getPlayback((unsigned long)playback);
1568 DVR_RETURN_IF_FALSE(ctx);
1569
1570 pthread_mutex_lock(&ctx->lock);
1571 error = dvr_playback_set_decrypt_callback(ctx->playback.player, func, userdata);
1572 pthread_mutex_unlock(&ctx->lock);
1573 return error;
1574}
1575
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001576static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata)
1577{
1578 DVR_WrapperEventCtx_t evt;
1579
1580 DVR_RETURN_IF_FALSE(userdata);
1581
1582 evt.sn = (unsigned long)userdata;
1583 evt.type = W_REC;
1584 evt.record.event = event;
1585 evt.record.status = *(DVR_RecordStatus_t *)params;
1586 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, record, evt:0x%x]\n", evt.sn, evt.record.event);
1587 return ctx_addRecordEvent(&evt);
1588}
1589
1590static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata)
1591{
1592 DVR_WrapperEventCtx_t evt;
1593
1594 DVR_RETURN_IF_FALSE(userdata);
1595
1596 evt.sn = (unsigned long)userdata;
1597 evt.type = W_PLAYBACK;
1598 evt.playback.event = event;
1599 evt.playback.status = *(DVR_Play_Notify_t *)params;
1600 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, playbck, evt:0x%x]\n", evt.sn, evt.playback.event);
1601 return ctx_addPlaybackEvent(&evt);
1602}
1603
1604static inline int process_notifyRecord(DVR_WrapperCtx_t *ctx, DVR_RecordEvent_t evt, DVR_WrapperRecordStatus_t *status)
1605{
1606 DVR_WRAPPER_DEBUG(1, "notify(sn:%ld) evt(0x%x) statistic:time/size/pkts(%lu/%lld/%u) fn:%p\n",
1607 ctx->sn,
1608 evt,
1609 status->info.time,
1610 status->info.size,
1611 status->info.pkts,
1612 ctx->record.event_fn);
1613
1614 if (ctx->record.event_fn)
1615 return ctx->record.event_fn(evt, status, ctx->record.event_userdata);
1616 return 0;
1617}
1618
1619static inline int record_startNextSegment(DVR_WrapperCtx_t *ctx)
1620{
1621 DVR_RecordStartParams_t param;
1622 DVR_RecordSegmentInfo_t seg_info;
1623 int i;
1624 int error;
1625
1626 memcpy(&param, &ctx->record.param_update, sizeof(param));
1627 memset(&ctx->record.param_update.segment, 0, sizeof(ctx->record.param_update.segment));
1628 ctx->record.param_update.segment.segment_id = ctx->record.next_segment_id++;
1629 for (i = 0; i < param.segment.nb_pids; i++) {
1630 if (param.segment.pid_action[i] != DVR_RECORD_PID_CLOSE) {
1631 ctx->record.param_update.segment.pids[ctx->record.param_update.segment.nb_pids] = param.segment.pids[i];
1632 ctx->record.param_update.segment.pid_action[ctx->record.param_update.segment.nb_pids] = DVR_RECORD_PID_KEEP;
1633 ctx->record.param_update.segment.nb_pids++;
1634 }
1635 }
1636 error = dvr_record_next_segment(ctx->record.recorder, &ctx->record.param_update, &seg_info);
1637 {
1638 DVR_RecordSegmentInfo_t new_seg_info =
1639 { .id = ctx->record.param_update.segment.segment_id, };
1640 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
1641 wrapper_addRecordSegment(ctx, &new_seg_info);
1642 }
1643
1644 DVR_WRAPPER_DEBUG(1, "record next segment (%d)\n", error);
1645 return error;
1646}
1647
1648static inline int record_removeSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *pseg)
1649{
1650 return wrapper_removeRecordSegment(ctx, pseg);
1651}
1652
1653/*should run periodically to update the current status*/
1654static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx)
1655{
1656 /*the current seg is not covered in the statistics*/
1657 DVR_WrapperRecordSegmentInfo_t *pseg;
1658
1659 /*re-calculate the all segments, except the current*/
1660 memset(&ctx->record.status, 0, sizeof(ctx->record.status));
1661
1662 ctx->record.status.state = ctx->record.seg_status.state;
1663 ctx->record.status.pids.nb_pids = ctx->record.seg_status.info.nb_pids;
1664 memcpy(ctx->record.status.pids.pids,
1665 ctx->record.seg_status.info.pids,
1666 sizeof(ctx->record.status.pids.pids));
1667 ctx->current_segment_id = ctx->record.seg_status.info.id;
1668
1669 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1670 if (pseg->info.id != ctx->record.seg_status.info.id) {
1671 ctx->record.status.info.time += pseg->info.duration;
1672 ctx->record.status.info.size += pseg->info.size;
1673 ctx->record.status.info.pkts += pseg->info.nb_packets;
1674 }
1675 }
1676
1677 wrapper_updateRecordSegment(ctx, &ctx->record.seg_status.info, U_ALL);
1678 return DVR_SUCCESS;
1679}
1680
1681
1682static int process_handleRecordEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
1683{
1684 DVR_WrapperRecordStatus_t status;
1685
1686 memset(&status, 0, sizeof(status));
1687
1688 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d)\n",
1689 evt->sn, evt->record.event, evt->record.status.state);
1690
1691 switch (evt->record.event)
1692 {
1693 case DVR_RECORD_EVENT_STATUS:
1694 {
1695 switch (evt->record.status.state)
1696 {
1697 case DVR_RECORD_STATE_OPENED:
1698 case DVR_RECORD_STATE_CLOSED:
1699 {
1700 ctx->record.seg_status = evt->record.status;
1701
1702 status.state = evt->record.status.state;
1703 process_notifyRecord(ctx, evt->record.event, &status);
1704 } break;
1705 case DVR_RECORD_STATE_STARTED:
1706 {
1707 int check_ok;
1708
1709 ctx->record.seg_status = evt->record.status;
1710
1711 process_generateRecordStatus(ctx);
1712
1713 status = ctx->record.status;
1714 status.info.time += evt->record.status.info.duration;
1715 status.info.size += evt->record.status.info.size;
1716 status.info.pkts += evt->record.status.info.nb_packets;
1717
1718 process_notifyRecord(ctx, evt->record.event, &status);
1719
1720 check_ok = 1;
1721 if (ctx->record.param_open.max_time
1722 && status.info.time >= ctx->record.param_open.max_time) {
1723 if (!ctx->record.param_open.is_timeshift) {
1724 /*not timeshifting, just stop*/
1725 int error = dvr_record_close(ctx->record.recorder);
1726 DVR_WRAPPER_DEBUG(1, "stop record(%lu)=%d, reaches time limit, curr(%ld) max(%ld)\n",
1727 ctx->sn, error,
1728 status.info.time, ctx->record.param_open.max_time);
1729 status.state = DVR_RECORD_STATE_CLOSED;
1730 process_notifyRecord(ctx, evt->record.event, &status);
1731 check_ok = 0;
1732 } else {
1733 /*timeshifting, remove the 1st segment and notify the player*/
1734 DVR_WrapperRecordSegmentInfo_t *pseg;
1735 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
1736 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
1737 /*only one segment, waiting for more*/
1738 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of max_time(%ld) of record < max size of segment(%lld)\n",
1739 status.info.size,
1740 ctx->record.param_open.max_time,
1741 ctx->record.param_open.segment_size);
1742 } else {
1743 record_removeSegment(ctx, pseg);
1744 }
1745 }
1746 }
1747
1748 if (ctx->record.param_open.max_size
1749 && status.info.size >= ctx->record.param_open.max_size) {
1750 if (!ctx->record.param_open.is_timeshift) {
1751 int error = dvr_record_close(ctx->record.recorder);
1752 DVR_WRAPPER_DEBUG(1, "stop record(%lu)=%d, reaches size limit, curr(%lld) max(%lld)\n",
1753 ctx->sn, error,
1754 status.info.size, ctx->record.param_open.max_size);
1755 status.state = DVR_RECORD_STATE_CLOSED;
1756 process_notifyRecord(ctx, evt->record.event, &status);
1757 check_ok = 0;
1758 } else {
1759 DVR_WrapperRecordSegmentInfo_t *pseg;
1760 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
1761 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
1762 /*only one segment, waiting for more*/
1763 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of record < max size of segment(%lld)\n",
1764 status.info.size,
1765 ctx->record.param_open.segment_size);
1766 } else {
1767 record_removeSegment(ctx, pseg);
1768 }
1769 }
1770 }
1771
1772 /*restart to next segment*/
1773 if (check_ok
1774 && ctx->record.param_open.segment_size
1775 && evt->record.status.info.size >= ctx->record.param_open.segment_size) {
1776 DVR_WRAPPER_DEBUG(1, "start new segment for record(%lu), reaches segment size limit, cur(%zu) max(%lld)\n",
1777 ctx->sn,
1778 evt->record.status.info.size,
1779 ctx->record.param_open.segment_size);
1780 record_startNextSegment(ctx);
1781 }
1782 } break;
1783 case DVR_RECORD_STATE_STOPPED:
1784 {
1785 ctx->record.seg_status = evt->record.status;
1786
1787 process_generateRecordStatus(ctx);
1788
1789 status.info.time += evt->record.status.info.duration;
1790 status.info.size += evt->record.status.info.size;
1791 status.info.pkts += evt->record.status.info.nb_packets;
1792
1793 process_notifyRecord(ctx, evt->record.event, &status);
1794 } break;
1795 default:
1796 break;
1797 }
1798 } break;
1799 default:
1800 break;
1801 }
1802 return DVR_SUCCESS;
1803}
1804
1805static inline int process_notifyPlayback(DVR_WrapperCtx_t *ctx, DVR_PlaybackEvent_t evt, DVR_WrapperPlaybackStatus_t *status)
1806{
1807 DVR_WRAPPER_DEBUG(1, "notify(sn:%ld) evt(0x%x) statistics:state/cur/full(%d/%ld/%ld) fn:%p\n",
1808 ctx->sn,
1809 evt,
1810 status->state,
1811 status->info_cur.time,
1812 status->info_full.time,
1813 ctx->playback.event_fn);
1814
1815 if (ctx->playback.event_fn)
1816 return ctx->playback.event_fn(evt, status, ctx->playback.event_userdata);
1817 return 0;
1818}
1819
1820/*should run periodically to update the current status*/
1821static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx)
1822{
1823 /*the current seg is not covered in the statistics*/
1824 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1825
1826 memset(&ctx->playback.status, 0, sizeof(ctx->playback.status));
1827 ctx->playback.status.pids = ctx->playback.pids_req;
1828
1829 ctx->playback.status.state = ctx->playback.seg_status.state;
1830 ctx->playback.status.speed = ctx->playback.seg_status.speed;
1831 ctx->playback.status.flags = ctx->playback.seg_status.flags;
1832 ctx->current_segment_id = ctx->playback.seg_status.segment_id;
1833
1834 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1835 if (pseg->seg_info.id == ctx->playback.seg_status.segment_id)
1836 break;
1837 ctx->playback.status.info_cur.time += pseg->seg_info.duration;
1838 ctx->playback.status.info_cur.size += pseg->seg_info.size;
1839 ctx->playback.status.info_cur.pkts += pseg->seg_info.nb_packets;
1840 }
1841 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1842 ctx->playback.status.info_full.time += pseg->seg_info.duration;
1843 ctx->playback.status.info_full.size += pseg->seg_info.size;
1844 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
1845 }
1846
1847 return DVR_SUCCESS;
1848}
1849
1850static int process_handlePlaybackEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
1851{
1852 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d) cur(%lld:%u/%u)\n",
1853 evt->sn, evt->playback.event,
1854 evt->playback.status.play_status.state,
1855 evt->playback.status.play_status.segment_id,
1856 evt->playback.status.play_status.time_cur,
1857 evt->playback.status.play_status.time_end);
1858
1859 /*evt PLAYTIME will break the last logic, do not save*/
1860 if (evt->playback.event != DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME)
1861 ctx->playback.last_event = evt->playback.event;
1862
1863 switch (evt->playback.event)
1864 {
1865 case DVR_PLAYBACK_EVENT_FIRST_FRAME:
1866 case DVR_PLAYBACK_EVENT_REACHED_END:
1867 case DVR_PLAYBACK_EVENT_TRANSITION_OK:
1868 case DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME:
1869 {
1870 DVR_WrapperPlaybackStatus_t status;
1871
1872 /*copy status of segment*/
1873 ctx->playback.seg_status = evt->playback.status.play_status;
1874
1875 /*generate status of the whole playback, except current*/
1876 process_generatePlaybackStatus(ctx);
1877
1878 status = ctx->playback.status;
1879 /*deal with current, lack size and pkts with the current*/
1880 status.info_cur.time += ctx->playback.seg_status.time_cur;
1881
1882 if (evt->playback.event == DVR_PLAYBACK_EVENT_REACHED_END) {
1883 if (ctx->playback.param_open.is_timeshift) {
1884 /*wait for more data in recording*/
1885 } else if ((status.info_cur.time + DVR_PLAYBACK_END_GAP) >= ctx->playback.status.info_full.time) {
1886 process_notifyPlayback(ctx, evt->playback.event, &status);
1887 }
1888 } else {
1889 process_notifyPlayback(ctx, evt->playback.event, &status);
1890 }
1891 } break;
1892 case DVR_PLAYBACK_EVENT_ERROR:
1893 case DVR_PLAYBACK_EVENT_TRANSITION_FAILED:
1894 case DVR_PLAYBACK_EVENT_KEY_FAILURE:
1895 case DVR_PLAYBACK_EVENT_NO_KEY:
1896 {
1897 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) error event:0x%x\n", evt->sn, evt->playback.event);
1898 } break;
1899 default:
1900 {
1901 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) unknown event:0x%x\n", evt->sn, evt->playback.event);
1902 } break;
1903 }
1904 return 0;
1905}
1906
1907static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
1908{
1909 return (evt->type == W_REC)? process_handleRecordEvent(evt, ctx) : process_handlePlaybackEvent(evt, ctx);
1910}
1911