blob: 2ed839070c85d19734c12cf90ca1e07f64ea2c21 [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))
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800481 goto processed;
482
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800483 if (ctx_valid(ctx)) {
484 /*double check after lock*/
485 if (evt->sn == ctx->sn)
486 process_handleEvents(evt, ctx);
487 }
488 pthread_mutex_unlock(&ctx->lock);
489 }
490
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800491processed:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800492 ctx_freeEvent(evt);
493 }
494 }
495
496 pthread_mutex_unlock(&tctx->lock);
497 return NULL;
498}
499
500static inline int ctx_addRecordEvent(DVR_WrapperEventCtx_t *evt)
501{
502 if (ctx_addEvent(&record_evt_list, &record_evt_list_lock, evt) == 0)
503 wrapper_threadSignalForType(evt->type);
504 return 0;
505}
506
507static inline int ctx_addPlaybackEvent(DVR_WrapperEventCtx_t *evt)
508{
509 if (ctx_addEvent(&playback_evt_list, &playback_evt_list_lock, evt) == 0)
510 wrapper_threadSignalForType(evt->type);
511 return 0;
512}
513
514static inline void ctx_freeSegments(DVR_WrapperCtx_t *ctx)
515{
516 DVR_WrapperPlaybackSegmentInfo_t *pseg, *pseg_tmp;
517 list_for_each_entry_safe(pseg, pseg_tmp, &ctx->segments, head) {
518 list_del(&pseg->head);
519 free(pseg);
520 }
521}
522
523static inline void _updatePlaybackSegment(DVR_WrapperPlaybackSegmentInfo_t *pseg,
524 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
525{
526 (void)ctx;
527 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
528 pseg->seg_info = *seg_info;
529 else if (update_flags & U_PIDS) {
530 pseg->seg_info.nb_pids = seg_info->nb_pids;
531 memcpy(pseg->seg_info.pids, seg_info->pids, sizeof(pseg->seg_info.pids));
532 } else if (update_flags & U_STAT) {
533 pseg->seg_info.duration = seg_info->duration;
534 pseg->seg_info.size = seg_info->size;
535 pseg->seg_info.nb_packets = seg_info->nb_packets;
536 }
537
538 /*no changes
539 DVR_PlaybackSegmentFlag_t flags;
540 pseg->playback_info.segment_id = pseg->seg_info.id;
541 strncpy(pseg->playback_info.location,
542 ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
543 pseg->playback_info.pids = ctx->playback.pids_req;
544 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
545 if (ctx->record.param_open.flags | DVR_RECORD_FLAG_SCRAMBLED)
546 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
547 pseg->playback_info.flags = flags;
548 */
549}
550
551static int wrapper_updatePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
552{
553 DVR_WrapperPlaybackSegmentInfo_t *pseg;
554
555 DVR_WRAPPER_DEBUG(1, "timeshift, update playback segments(wrapper), seg:%lld t/s/p(%ld/%zu/%u)\n",
556 seg_info->id, seg_info->duration, seg_info->size, seg_info->nb_packets);
557
558 if (list_empty(&ctx->segments)) {
559 DVR_WRAPPER_DEBUG(1, "timeshift, update while no segment exists, ignore\n");
560 return DVR_SUCCESS;
561 }
562
563 /*normally, the last segment added will be updated*/
564 pseg =
565 list_first_entry(&ctx->segments, DVR_WrapperPlaybackSegmentInfo_t, head);
566 if (pseg->seg_info.id == seg_info->id) {
567 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
568 } else {
569 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
570 if (pseg->seg_info.id == seg_info->id) {
571 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
572 break;
573 }
574 }
575 }
576
577 /*need to notify the dvr_playback*/
578 if (ctx->playback.param_open.is_timeshift/*should must be timeshift*/
579 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END
580 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
581 if (
582 /*there's $TIMESHIFT_DATA_DURATION_TO_RESUME more of data in the current segment playing*/
583 (ctx->playback.seg_status.segment_id == seg_info->id
584 && (seg_info->duration >= ((time_t)ctx->playback.seg_status.time_cur + TIMESHIFT_DATA_DURATION_TO_RESUME)))
585 ||
586 /*or there's a new segment and has $TIMESHIFT_DATA_DURATION_TO_RESUME of data*/
587 (ctx->playback.seg_status.segment_id != seg_info->id
588 && (seg_info->duration >= TIMESHIFT_DATA_DURATION_TO_RESUME))
589 )
590 {
591 int error;
592
593 error = dvr_playback_resume(ctx->playback.player);
594 DVR_WRAPPER_DEBUG(1, "timeshift, resume playback(sn:%ld) (%d) id/dur: rec(%lld/%ld) play(%lld/%u)\n",
595 ctx->sn, error,
596 seg_info->id, seg_info->duration,
597 ctx->playback.seg_status.segment_id, ctx->playback.seg_status.time_cur);
598 }
599 }
600
601 return DVR_SUCCESS;
602}
603
604static void _updateRecordSegment(DVR_WrapperRecordSegmentInfo_t *pseg,
605 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
606{
607 (void)ctx;
608 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
609 pseg->info = *seg_info;
610 else if (update_flags & U_PIDS) {
611 pseg->info.nb_pids = seg_info->nb_pids;
612 memcpy(pseg->info.pids, seg_info->pids, sizeof(pseg->info.pids));
613 } else if (update_flags & U_STAT) {
614 pseg->info.duration = seg_info->duration;
615 pseg->info.size = seg_info->size;
616 pseg->info.nb_packets = seg_info->nb_packets;
617 }
618}
619
620static int wrapper_updateRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
621{
hualing chen266b9502020-04-04 17:39:39 +0800622 DVR_WrapperRecordSegmentInfo_t *pseg = NULL;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800623
624 /*normally, the last segment added will be updated*/
hualing chen266b9502020-04-04 17:39:39 +0800625 if (!list_empty(&ctx->segments)) {
626 pseg =
627 list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
628 if (pseg->info.id == seg_info->id) {
629 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
630 } else {
631 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
632 if (pseg->info.id == seg_info->id) {
633 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
634 break;
635 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800636 }
637 }
638 }
639
640 /*timeshift, update the segment for playback*/
641 /*
642 the playback should grab the segment info other than the id,
643 and the id will be updated by each segment-add during the recording
644 */
645 /*
646 the playback paused if no data been checked from recording,
647 should resume the player later when there's more data
648 */
649
650 if (ctx->record.param_open.is_timeshift) {
651 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
652
653 if (ctx_playback) {
654 pthread_mutex_lock(&ctx_playback->lock);
655 if (ctx_valid(ctx_playback)
656 && ctx_playback->sn == sn_timeshift_playback) {
657 wrapper_updatePlaybackSegment(ctx_playback, seg_info, update_flags);
658 }
659 pthread_mutex_unlock(&ctx_playback->lock);
660 }
661 }
662
663 return DVR_SUCCESS;
664}
665
666static int wrapper_addPlaybackSegment(DVR_WrapperCtx_t *ctx,
667 DVR_RecordSegmentInfo_t *seg_info,
668 DVR_PlaybackPids_t *p_pids,
669 DVR_PlaybackSegmentFlag_t flags)
670{
671 DVR_WrapperPlaybackSegmentInfo_t *pseg;
672 int error;
673
674 error = 0;
675 pseg = (DVR_WrapperPlaybackSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperPlaybackSegmentInfo_t));
676 if (!pseg) {
677 error = DVR_FAILURE;
678 DVR_WRAPPER_DEBUG(1, "memory fail\n");
679 return error;
680 }
681
682 /*copy the orignal segment info*/
683 pseg->seg_info = *seg_info;
684 /*generate the segment info used in playback*/
685 pseg->playback_info.segment_id = pseg->seg_info.id;
686 strncpy(pseg->playback_info.location, ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
687 pseg->playback_info.pids = *p_pids;
688 pseg->playback_info.flags = flags;
689 list_add(&pseg->head, &ctx->segments);
690
691 error = dvr_playback_add_segment(ctx->playback.player, &pseg->playback_info);
692 if (error) {
693 DVR_WRAPPER_DEBUG(1, "fail to add segment %lld (%d)\n", pseg->playback_info.segment_id, error);
694 } else {
695 ctx->playback.status.info_full.time += pseg->seg_info.duration;
696 ctx->playback.status.info_full.size += pseg->seg_info.size;
697 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
698 }
699
700 return error;
701}
702
703static int wrapper_addRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
704{
705 DVR_WrapperRecordSegmentInfo_t *pseg;
706 int error;
707
708 error = 0;
709 pseg = (DVR_WrapperRecordSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperRecordSegmentInfo_t));
710 if (!pseg) {
711 error = DVR_FAILURE;
712 DVR_WRAPPER_DEBUG(1, "memory fail\n");
713 }
714 pseg->info = *seg_info;
715 list_add(&pseg->head, &ctx->segments);
716
717 if (ctx->record.param_open.is_timeshift) {
718 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
719
720 if (ctx_playback) {
721 pthread_mutex_lock(&ctx_playback->lock);
722 if (ctx_valid(ctx_playback)) {
723 DVR_PlaybackSegmentFlag_t flags;
724
725 /*only if playback has started, the previous segments have been loaded*/
726 if (!list_empty(&ctx_playback->segments)) {
727 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
728 if (ctx->record.param_open.flags | DVR_RECORD_FLAG_SCRAMBLED)
729 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
730 wrapper_addPlaybackSegment(ctx_playback, seg_info, &ctx_playback->playback.pids_req, flags);
731 }
732 }
733 pthread_mutex_unlock(&ctx_playback->lock);
734 }
735 }
736
737 return error;
738}
739
740static int wrapper_removePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
741{
742 int error;
743
744 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->id);
745
746 error = dvr_playback_remove_segment(ctx->playback.player, seg_info->id);
747 if (error) {
748 /*remove playack segment fail*/
749 } else {
750 DVR_WrapperPlaybackSegmentInfo_t *pseg;
751
752 /*normally, should be the earliest segment in the list*/
753 pseg = list_last_entry(&ctx->segments, DVR_WrapperPlaybackSegmentInfo_t, head);
754 if (pseg->seg_info.id == seg_info->id) {
755 list_del(&pseg->head);
756 free(pseg);
757 } else {
758 /*what's going on*/
759 }
760 }
761
762 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->id, error);
763
764 return error;
765}
766
767static int wrapper_removeRecordSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *seg_info)
768{
769 int error;
770 DVR_WrapperRecordSegmentInfo_t *pseg;
771
772 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->info.id);
773
774 /*if timeshifting, notify the playback first, then deal with record*/
775 if (ctx->record.param_open.is_timeshift) {
776 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
777
778 if (ctx_playback) {
779 pthread_mutex_lock(&ctx_playback->lock);
780 if (ctx_valid(ctx_playback)
781 && ctx_playback->sn == sn_timeshift_playback
782 && !list_empty(&ctx_playback->segments)) {
783 error = wrapper_removePlaybackSegment(ctx_playback, &seg_info->info);
784 }
785 pthread_mutex_unlock(&ctx_playback->lock);
786 }
787 }
788
789 /*normally, the earliest segment will be removed*/
790 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
791 if (pseg->info.id == seg_info->info.id) {
792 list_del(&pseg->head);
793 free(pseg);
794 } else {
795 /*should not get here*/
796 }
797
798 error = dvr_segment_delete(ctx->record.param_open.location, seg_info->info.id);
799
800 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->info.id, error);
801
802 return error;
803}
804
805int dvr_wrapper_open_record (DVR_WrapperRecord_t *rec, DVR_WrapperRecordOpenParams_t *params)
806{
807 int error;
808 DVR_WrapperCtx_t *ctx;
809 DVR_RecordOpenParams_t open_param;
810
811 DVR_RETURN_IF_FALSE(rec);
812 DVR_RETURN_IF_FALSE(params);
813
814 /*get a free ctx*/
815 ctx = ctx_getRecord(0);
816 DVR_RETURN_IF_FALSE(ctx);
817
818 pthread_mutex_lock(&ctx->lock);
819
820 DVR_WRAPPER_DEBUG(1, "open record(dmx:%d) ...\n", params->dmx_dev_id);
821
822 ctx_reset(ctx);
823
824 ctx->record.param_open = *params;
825 ctx->record.event_fn = params->event_fn;
826 ctx->record.event_userdata = params->event_userdata;
827 ctx->record.next_segment_id = 0;
828 ctx->current_segment_id = 0;
829 INIT_LIST_HEAD(&ctx->segments);
830 ctx->sn = get_sn();
831
832 wrapper_requestThreadFor(ctx);
833
hualing chen266b9502020-04-04 17:39:39 +0800834 memset(&open_param, 0, sizeof(DVR_RecordOpenParams_t));
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800835 open_param.dmx_dev_id = params->dmx_dev_id;
836 open_param.data_from_memory = 0;
837 open_param.flags = params->flags;
Zhiqiang Han104aed72020-04-03 19:37:43 +0800838 open_param.notification_size = 500*1024;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800839 open_param.event_fn = wrapper_record_event_handler;
840 open_param.event_userdata = (void*)ctx->sn;
841
842 error = dvr_record_open(&ctx->record.recorder, &open_param);
843 if (error) {
844 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) open fail(error:%d).\n", params->dmx_dev_id, error);
845 ctx_reset(ctx);
846 pthread_mutex_unlock(&ctx->lock);
847 wrapper_releaseThreadForType(ctx->type);
848 return DVR_FAILURE;
849 }
850 if (params->is_timeshift)
851 sn_timeshift_record = ctx->sn;
852
853 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
854
hualing chen266b9502020-04-04 17:39:39 +0800855 error = dvr_record_set_encrypt_callback(ctx->record.recorder, params->crypto_fn, params->crypto_data);
856 if (error) {
857 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) set encrypt callback fail(error:%d).\n", params->dmx_dev_id, error);
858 }
859
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800860 pthread_mutex_unlock(&ctx->lock);
861
862 *rec = (DVR_WrapperRecord_t)ctx->sn;
863 return DVR_SUCCESS;
864}
865
866int dvr_wrapper_close_record (DVR_WrapperRecord_t rec)
867{
868 DVR_WrapperCtx_t *ctx;
869 DVR_RecordSegmentInfo_t seg_info;
870 int error;
871
872 DVR_RETURN_IF_FALSE(rec);
873
874 ctx = ctx_getRecord((unsigned long)rec);
875 DVR_RETURN_IF_FALSE(ctx);
876
877 pthread_mutex_lock(&ctx->lock);
878 DVR_WRAPPER_DEBUG(1, "close record(sn:%ld)\n", ctx->sn);
879 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
880
881 memset(&seg_info, 0, sizeof(seg_info));
882 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
883
884 error = dvr_record_close(ctx->record.recorder);
885
886 sn_timeshift_record = 0;
887 ctx_freeSegments(ctx);
888
889 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) closed = (%d).\n", ctx->sn, error);
890 ctx_reset(ctx);
891 pthread_mutex_unlock(&ctx->lock);
892
893 wrapper_releaseThreadForType(ctx->type);
894
895 return error;
896}
897
898int dvr_wrapper_start_record (DVR_WrapperRecord_t rec, DVR_WrapperRecordStartParams_t *params)
899{
900 DVR_WrapperCtx_t *ctx;
901 DVR_RecordStartParams_t *start_param;
902 int i;
903 int error;
904
905 DVR_RETURN_IF_FALSE(rec);
906 DVR_RETURN_IF_FALSE(params);
907
908 ctx = ctx_getRecord((unsigned long)rec);
909 DVR_RETURN_IF_FALSE(ctx);
910
911 pthread_mutex_lock(&ctx->lock);
912 DVR_WRAPPER_DEBUG(1, "start record(sn:%ld, location:%s) ...\n", ctx->sn, ctx->record.param_open.location);
913 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
914
915 start_param = &ctx->record.param_start;
916 memset(start_param, 0, sizeof(*start_param));
917 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
918 start_param->segment.segment_id = ctx->record.next_segment_id++;
919 start_param->segment.nb_pids = params->pids_info.nb_pids;
920 for (i = 0; i < params->pids_info.nb_pids; i++) {
921 start_param->segment.pids[i] = params->pids_info.pids[i];
922 start_param->segment.pid_action[i] = DVR_RECORD_PID_CREATE;
923 }
924
925 {
926 /*sync to update for further use*/
927 DVR_RecordStartParams_t *update_param;
928 update_param = &ctx->record.param_update;
929 memcpy(update_param, start_param, sizeof(*update_param));
930 for (i = 0; i < update_param->segment.nb_pids; i++)
931 update_param->segment.pid_action[i] = DVR_RECORD_PID_KEEP;
932 }
933
934 error = dvr_record_start_segment(ctx->record.recorder, start_param);
935 {
936 DVR_RecordSegmentInfo_t new_seg_info =
937 { .id = start_param->segment.segment_id, };
938 wrapper_addRecordSegment(ctx, &new_seg_info);
939 }
940
941 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) started = (%d)\n", ctx->sn, error);
942
943 pthread_mutex_unlock(&ctx->lock);
944
945 return error;
946}
947
948int dvr_wrapper_stop_record (DVR_WrapperRecord_t rec)
949{
950 DVR_WrapperCtx_t *ctx;
951 DVR_RecordSegmentInfo_t seg_info;
952 int error;
953
954 DVR_RETURN_IF_FALSE(rec);
955
956 ctx = ctx_getRecord((unsigned long)rec);
957 DVR_RETURN_IF_FALSE(ctx);
958
959 pthread_mutex_lock(&ctx->lock);
960 DVR_WRAPPER_DEBUG(1, "stop record(sn:%ld) ...\n", ctx->sn);
961 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
962
963 memset(&seg_info, 0, sizeof(seg_info));
964 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
965 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
966
967 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) stopped = (%d)\n", ctx->sn, error);
968 pthread_mutex_unlock(&ctx->lock);
969
970 return error;
971}
972
973int dvr_wrapper_update_record_pids (DVR_WrapperRecord_t rec, DVR_WrapperUpdatePidsParams_t *params)
974{
975 DVR_WrapperCtx_t *ctx;
976 DVR_RecordStartParams_t *start_param;
977 DVR_RecordSegmentInfo_t seg_info;;
978 int i;
979 int error;
980
981 DVR_RETURN_IF_FALSE(rec);
982 DVR_RETURN_IF_FALSE(params);
983
984 ctx = ctx_getRecord((unsigned long)rec);
985 DVR_RETURN_IF_FALSE(ctx);
986
987 pthread_mutex_lock(&ctx->lock);
988 DVR_WRAPPER_DEBUG(1, "update record(sn:%ld)\n", ctx->sn);
989 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
990
991 start_param = &ctx->record.param_update;
992 memset(start_param, 0, sizeof(*start_param));
993 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
994 start_param->segment.segment_id = ctx->record.next_segment_id++;
995 start_param->segment.nb_pids = params->nb_pids;
996 for (i = 0; i < params->nb_pids; i++) {
997 start_param->segment.pids[i] = params->pids[i];
998 start_param->segment.pid_action[i] = params->pid_action[i];
999 }
1000 error = dvr_record_next_segment(ctx->record.recorder, start_param, &seg_info);
1001 {
1002 DVR_RecordSegmentInfo_t new_seg_info =
1003 { .id = start_param->segment.segment_id, };
1004 wrapper_updateRecordSegment(ctx, &seg_info, U_PIDS);
1005 wrapper_addRecordSegment(ctx, &new_seg_info);
1006 }
1007
1008 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) updated = (%d)\n", ctx->sn, error);
1009 pthread_mutex_unlock(&ctx->lock);
1010
1011 return error;
1012}
1013
1014int dvr_wrapper_get_record_status(DVR_WrapperRecord_t rec, DVR_WrapperRecordStatus_t *status)
1015{
1016 DVR_WrapperCtx_t *ctx;
1017 DVR_WrapperRecordStatus_t s;
1018 int error;
1019
1020 DVR_RETURN_IF_FALSE(rec);
1021 DVR_RETURN_IF_FALSE(status);
1022
1023 ctx = ctx_getRecord((unsigned long)rec);
1024 DVR_RETURN_IF_FALSE(ctx);
1025
1026 pthread_mutex_lock(&ctx->lock);
1027
1028 DVR_WRAPPER_DEBUG(1, "get record(sn:%ld) status ...\n", ctx->sn);
1029 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1030
1031 error = process_generateRecordStatus(ctx);
1032 s = ctx->record.status;
1033 s.info.time += ctx->record.seg_status.info.duration;
1034 s.info.size += ctx->record.seg_status.info.size;
1035 s.info.pkts += ctx->record.seg_status.info.nb_packets;
1036
1037 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) state/time/size/pkts(%d/%ld/%lld/%u) (%d)\n",
1038 ctx->sn,
1039 s.state,
1040 s.info.time,
1041 s.info.size,
1042 s.info.pkts,
1043 error);
1044
1045 *status = s;
1046
1047 pthread_mutex_unlock(&ctx->lock);
1048
1049 return error;
1050}
1051
hualing chen266b9502020-04-04 17:39:39 +08001052int dvr_wrapper_set_record_secure_buffer (DVR_WrapperRecord_t rec, uint8_t *p_secure_buf, uint32_t len)
1053{
1054 DVR_WrapperCtx_t *ctx;
1055 int error;
1056
1057 DVR_RETURN_IF_FALSE(rec);
1058 DVR_RETURN_IF_FALSE(p_secure_buf);
1059
1060 ctx = ctx_getRecord((unsigned long)rec);
1061 DVR_RETURN_IF_FALSE(ctx);
1062
1063 pthread_mutex_lock(&ctx->lock);
1064 error = dvr_record_set_secure_buffer(ctx->record.recorder, p_secure_buf, len);
1065 pthread_mutex_unlock(&ctx->lock);
1066 return error;
1067}
1068
1069int dvr_wrapper_set_record_decrypt_callback (DVR_WrapperRecord_t rec, DVR_CryptoFunction_t func, void *userdata)
1070{
1071 DVR_WrapperCtx_t *ctx;
1072 int error;
1073
1074 DVR_RETURN_IF_FALSE(rec);
1075 DVR_RETURN_IF_FALSE(func);
1076
1077 ctx = ctx_getRecord((unsigned long)rec);
1078 DVR_RETURN_IF_FALSE(ctx);
1079
1080 pthread_mutex_lock(&ctx->lock);
1081 error = dvr_record_set_encrypt_callback(ctx->record.recorder, func, userdata);
1082 pthread_mutex_unlock(&ctx->lock);
1083 return error;
1084}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001085
1086
1087int dvr_wrapper_open_playback (DVR_WrapperPlayback_t *playback, DVR_WrapperPlaybackOpenParams_t *params)
1088{
1089 DVR_WrapperCtx_t *ctx;
1090 DVR_PlaybackOpenParams_t open_param;
1091 int error;
1092
1093 DVR_RETURN_IF_FALSE(playback);
1094 DVR_RETURN_IF_FALSE(params);
1095 DVR_RETURN_IF_FALSE(params->playback_handle);
1096
1097 /*get a free ctx*/
1098 ctx = ctx_getPlayback(0);
1099 DVR_RETURN_IF_FALSE(ctx);
1100
1101 pthread_mutex_lock(&ctx->lock);
1102
1103 DVR_WRAPPER_DEBUG(1, "open playback(dmx:%d) ...\n", params->dmx_dev_id);
1104
1105 ctx_reset(ctx);
1106
1107 ctx->playback.param_open = *params;
1108 ctx->playback.event_fn = params->event_fn;
1109 ctx->playback.event_userdata = params->event_userdata;
1110 ctx->current_segment_id = 0;
1111 INIT_LIST_HEAD(&ctx->segments);
1112 ctx->sn = get_sn();
1113
1114 wrapper_requestThreadFor(ctx);
1115
hualing chen266b9502020-04-04 17:39:39 +08001116 memset(&open_param, 0, sizeof(DVR_PlaybackOpenParams_t));
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001117 open_param.dmx_dev_id = params->dmx_dev_id;
1118 open_param.block_size = params->block_size;
1119 open_param.is_timeshift = params->is_timeshift;
1120 //open_param.notification_size = 10*1024; //not supported
1121 open_param.event_fn = wrapper_playback_event_handler;
1122 open_param.event_userdata = (void*)ctx->sn;
1123 /*open_param.has_pids = 0;*/
1124
1125 open_param.player_handle = (am_tsplayer_handle)params->playback_handle;
1126
1127 error = dvr_playback_open(&ctx->playback.player, &open_param);
1128 if (error) {
1129 DVR_WRAPPER_DEBUG(1, "playback(dmx:%d) openned fail(error:%d).\n", params->dmx_dev_id, error);
1130 ctx_reset(ctx);
1131 pthread_mutex_unlock(&ctx->lock);
1132 wrapper_releaseThreadForType(ctx->type);
1133 return DVR_FAILURE;
1134 }
1135 if (params->is_timeshift)
1136 sn_timeshift_playback = ctx->sn;
1137
hualing chen266b9502020-04-04 17:39:39 +08001138 DVR_WRAPPER_DEBUG(1, "hanyh: playback(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
1139 error = dvr_playback_set_decrypt_callback(ctx->playback.player, params->crypto_fn, params->crypto_data);
1140 if (error) {
1141 DVR_WRAPPER_DEBUG(1, "playback set deccrypt callback fail(error:%d).\n", error);
1142 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001143 pthread_mutex_unlock(&ctx->lock);
1144
1145 *playback = (DVR_WrapperPlayback_t)ctx->sn;
1146 return DVR_SUCCESS;
1147}
1148
1149int dvr_wrapper_close_playback (DVR_WrapperPlayback_t playback)
1150{
1151 DVR_WrapperCtx_t *ctx;
1152 int error;
1153
1154 DVR_RETURN_IF_FALSE(playback);
1155
1156 ctx = ctx_getPlayback((unsigned long)playback);
1157 DVR_RETURN_IF_FALSE(ctx);
1158
1159 pthread_mutex_lock(&ctx->lock);
1160 DVR_WRAPPER_DEBUG(1, "close playback(sn:%ld)\n", ctx->sn);
1161 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1162
1163 if (ctx->playback.param_open.is_timeshift)
1164 sn_timeshift_playback = 0;
1165
1166 /*try stop first*/
1167 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1168
1169 {
1170 /*remove all segments*/
1171 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1172
1173 list_for_each_entry(pseg, &ctx->segments, head) {
1174 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1175 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1176 ctx->sn, pseg->playback_info.segment_id, error);
1177 }
1178 ctx_freeSegments(ctx);
1179 }
1180
1181 error = dvr_playback_close(ctx->playback.player);
1182
1183 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) closed.\n", ctx->sn);
1184 ctx_reset(ctx);
1185 pthread_mutex_unlock(&ctx->lock);
1186
1187 wrapper_releaseThreadForType(ctx->type);
1188
1189 return error;
1190}
1191
1192int dvr_wrapper_start_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackFlag_t flags, DVR_PlaybackPids_t *p_pids)
1193{
1194 DVR_WrapperCtx_t *ctx;
1195 int error;
1196 uint64_t *p_segment_ids;
1197 uint32_t segment_nb;
1198 uint32_t i;
1199 DVR_RecordSegmentInfo_t seg_info_1st;
1200 int got_1st_seg;
1201
1202 DVR_RETURN_IF_FALSE(playback);
1203 DVR_RETURN_IF_FALSE(p_pids);
1204
1205 ctx = ctx_getPlayback((unsigned long)playback);
1206 DVR_RETURN_IF_FALSE(ctx);
1207
1208 pthread_mutex_lock(&ctx->lock);
1209
1210 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",
1211 ctx->sn,
1212 ctx->playback.param_open.location,
1213 flags,
1214 p_pids->video.pid, p_pids->video.format,
1215 p_pids->audio.pid, p_pids->audio.format,
1216 p_pids->ad.pid, p_pids->ad.format,
1217 p_pids->subtitle.pid, p_pids->subtitle.format,
1218 p_pids->pcr.pid);
1219
1220 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1221
1222 /*obtain all segments in a list*/
1223 segment_nb = 0;
1224 p_segment_ids = NULL;
1225 error = dvr_segment_get_list(ctx->playback.param_open.location, &segment_nb, &p_segment_ids);
1226 DVR_RETURN_IF_FALSE_WITH_UNLOCK(!error, &ctx->lock);
1227
1228 got_1st_seg = 0;
1229 for (i = 0; i < segment_nb; i++) {
1230 DVR_RecordSegmentInfo_t seg_info;
1231 DVR_PlaybackSegmentFlag_t flags;
1232
1233 error = dvr_segment_get_info(ctx->playback.param_open.location, p_segment_ids[i], &seg_info);
1234 if (error) {
1235 error = DVR_FAILURE;
1236 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
1237 ctx->playback.param_open.location, p_segment_ids[i], error);
1238 break;
1239 }
1240
1241 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1242 error = wrapper_addPlaybackSegment(ctx, &seg_info, p_pids, flags);
1243 if (error)
1244 break;
1245
1246 /*copy the 1st segment*/
1247 if (got_1st_seg == 0) {
1248 seg_info_1st = seg_info;
1249 got_1st_seg = 1;
1250 }
1251 }
1252 free(p_segment_ids);
1253
1254 /* return if no segment or fail to add */
1255 DVR_RETURN_IF_FALSE_WITH_UNLOCK(!error && got_1st_seg, &ctx->lock);
1256
1257 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) (%d) segments added\n", ctx->sn, i);
1258
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001259 ctx->playback.speed = 100.0f;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001260 ctx->playback.pids_req = *p_pids;
1261
1262 error = dvr_playback_seek(ctx->playback.player, seg_info_1st.id, 0);
1263 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seek(seg:%llu 0) for start (%d)\n",
1264 ctx->sn, seg_info_1st.id, error);
1265
1266 error = dvr_playback_start(ctx->playback.player, flags);
1267
1268 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) started (%d)\n", ctx->sn, error);
1269
1270 pthread_mutex_unlock(&ctx->lock);
1271
1272 return error;
1273}
1274
1275int dvr_wrapper_stop_playback (DVR_WrapperPlayback_t playback)
1276{
1277 DVR_WrapperCtx_t *ctx;
1278 int error;
1279
1280 DVR_RETURN_IF_FALSE(playback);
1281
1282 ctx = ctx_getPlayback((unsigned long)playback);
1283 DVR_RETURN_IF_FALSE(ctx);
1284
1285 pthread_mutex_lock(&ctx->lock);
1286 DVR_WRAPPER_DEBUG(1, "stop playback(sn:%ld) ...\n", ctx->sn);
1287 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1288
1289 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1290
1291 {
1292 /*remove all segments*/
1293 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1294
1295 list_for_each_entry(pseg, &ctx->segments, head) {
1296 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1297 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1298 ctx->sn, pseg->playback_info.segment_id, error);
1299 }
1300 ctx_freeSegments(ctx);
1301 }
1302
1303 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) stopped (%d)\n", ctx->sn, error);
1304 pthread_mutex_unlock(&ctx->lock);
1305
1306 return error;
1307}
1308
1309int dvr_wrapper_pause_playback (DVR_WrapperPlayback_t playback)
1310{
1311 DVR_WrapperCtx_t *ctx;
1312 int error;
1313
1314 DVR_RETURN_IF_FALSE(playback);
1315
1316 ctx = ctx_getPlayback((unsigned long)playback);
1317 DVR_RETURN_IF_FALSE(ctx);
1318
1319 pthread_mutex_lock(&ctx->lock);
1320 DVR_WRAPPER_DEBUG(1, "pause playback(sn:%ld) ...\n", ctx->sn);
1321 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1322
1323 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
1324
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001325 ctx->playback.speed = 0.0f;
1326
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001327 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) paused (%d)\n", ctx->sn, error);
1328 pthread_mutex_unlock(&ctx->lock);
1329
1330 return error;
1331}
1332
1333int dvr_wrapper_resume_playback (DVR_WrapperPlayback_t playback)
1334{
1335 DVR_WrapperCtx_t *ctx;
1336 int error;
1337
1338 DVR_RETURN_IF_FALSE(playback);
1339
1340 ctx = ctx_getPlayback((unsigned long)playback);
1341 DVR_RETURN_IF_FALSE(ctx);
1342
1343 pthread_mutex_lock(&ctx->lock);
1344 DVR_WRAPPER_DEBUG(1, "resume playback(sn:%ld) ...\n", ctx->sn);
1345 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1346
1347 error = dvr_playback_resume(ctx->playback.player);
1348
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001349 ctx->playback.speed = 100.0f;
1350
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001351 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) resumed (%d)\n", ctx->sn, error);
1352 pthread_mutex_unlock(&ctx->lock);
1353
1354 return error;
1355}
1356
1357int dvr_wrapper_set_playback_speed (DVR_WrapperPlayback_t playback, float speed)
1358{
1359 DVR_WrapperCtx_t *ctx;
1360 int error;
1361 DVR_PlaybackSpeed_t dvr_speed = {
1362 .speed = { speed },
1363 .mode = (speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
1364 };
1365
1366 DVR_RETURN_IF_FALSE(playback);
1367
1368 ctx = ctx_getPlayback((unsigned long)playback);
1369 DVR_RETURN_IF_FALSE(ctx);
1370
1371 pthread_mutex_lock(&ctx->lock);
1372 DVR_WRAPPER_DEBUG(1, "speed playback(sn:%ld) (x%f) ...\n", ctx->sn, speed);
1373 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1374
1375 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
1376
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001377 if (ctx->playback.speed != 0.0f && ctx->playback.speed != 100.0f
1378 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_BEGIN
1379 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
1380 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, paused, do resume first\n", ctx->playback.speed, speed);
1381 error = dvr_playback_resume(ctx->playback.player);
1382 } else if (ctx->playback.speed == 0.0f
1383 && speed != 0.0f
1384 && speed != 100.0f) {
1385 /*libdvr do not support pause with speed=0, will not be here*/
1386 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, do resume first\n", ctx->playback.speed, speed);
1387 error = dvr_playback_resume(ctx->playback.player);
1388 }
1389
1390 ctx->playback.speed = speed;
1391
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001392 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) speeded(x%f) (%d)\n",
1393 ctx->sn, speed, error);
1394 pthread_mutex_unlock(&ctx->lock);
1395
1396 return error;
1397}
1398
1399int dvr_wrapper_seek_playback (DVR_WrapperPlayback_t playback, uint32_t time_offset)
1400{
1401 DVR_WrapperCtx_t *ctx;
1402 int error;
1403 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1404 uint64_t segment_id;
1405 uint32_t off;
1406 uint64_t last_segment_id;
1407 uint32_t pre_off;
1408
1409 DVR_RETURN_IF_FALSE(playback);
1410
1411 ctx = ctx_getPlayback((unsigned long)playback);
1412 DVR_RETURN_IF_FALSE(ctx);
1413
1414 pthread_mutex_lock(&ctx->lock);
1415
1416 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (off:%d) ...\n", ctx->sn, time_offset);
1417 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1418
1419 off = 0;
1420 segment_id = 0;
1421 pre_off = 0;
1422 last_segment_id = 0;
1423
1424 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1425 segment_id = pseg->seg_info.id;
1426
1427 if ((pre_off + pseg->seg_info.duration) > time_offset)
1428 break;
1429
1430 last_segment_id = pseg->seg_info.id;
1431 pre_off += pseg->seg_info.duration;
1432 }
1433
1434 if (last_segment_id == segment_id) {
1435 off = time_offset;
1436 } else {
1437 off = time_offset - pre_off;
1438 }
1439
1440
1441 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (seg:%lld, off:%d)\n", ctx->sn, segment_id, off);
1442 error = dvr_playback_seek(ctx->playback.player, segment_id, off);
1443 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seeked(off:%d) (%d)\n", ctx->sn, time_offset, error);
1444
1445 pthread_mutex_unlock(&ctx->lock);
1446
1447 return error;
1448}
1449
1450int dvr_wrapper_update_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackPids_t *p_pids)
1451{
1452 DVR_WrapperCtx_t *ctx;
1453 int error;
1454 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1455
1456 DVR_RETURN_IF_FALSE(playback);
1457 DVR_RETURN_IF_FALSE(p_pids);
1458
1459 ctx = ctx_getPlayback((unsigned long)playback);
1460 DVR_RETURN_IF_FALSE(ctx);
1461
1462 pthread_mutex_lock(&ctx->lock);
1463
1464 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) ...\n",
1465 ctx->sn,
1466 p_pids->video.pid, p_pids->video.format,
1467 p_pids->audio.pid, p_pids->audio.format);
1468 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1469
1470 ctx->playback.pids_req = *p_pids;
1471
1472 error = 0;
1473 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1474 /*should update the whole list of segments*/
1475 /*if (pseg->seg_info.id == ctx->current_segment_id)*/ {
1476 /*list_for_each_entry_from(pseg, &ctx->segments, head)*/ {
1477 /*check udpate for pids*/
1478 if (memcmp(&pseg->playback_info.pids, p_pids, sizeof(*p_pids)) != 0) {
1479 pseg->playback_info.pids = *p_pids;
1480 error = dvr_playback_update_segment_pids(ctx->playback.player, pseg->seg_info.id, p_pids);
1481 if (error) {
1482 DVR_WRAPPER_DEBUG(1, "failed to playback(sn:%ld) update segment(id:%lld) pids (%d)\n",
1483 ctx->sn, pseg->seg_info.id, error);
1484 /*do not break, let list updated*/
1485 }
1486 }
1487 }
1488 /*break;*/
1489 }
1490 }
1491
1492 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) (%d)\n",
1493 ctx->sn,
1494 p_pids->video.pid, p_pids->video.format,
1495 p_pids->audio.pid, p_pids->audio.format,
1496 error);
1497
1498 pthread_mutex_unlock(&ctx->lock);
1499
1500 return error;
1501}
1502
1503int dvr_wrapper_get_playback_status(DVR_WrapperPlayback_t playback, DVR_WrapperPlaybackStatus_t *status)
1504{
1505 DVR_WrapperCtx_t *ctx;
1506 DVR_WrapperPlaybackStatus_t s;
1507 DVR_PlaybackStatus_t play_status;
1508 int error;
1509
1510 DVR_RETURN_IF_FALSE(playback);
1511 DVR_RETURN_IF_FALSE(status);
1512
1513 ctx = ctx_getPlayback((unsigned long)playback);
1514 DVR_RETURN_IF_FALSE(ctx);
1515
1516 pthread_mutex_lock(&ctx->lock);
1517
1518 DVR_WRAPPER_DEBUG(1, "get playback(sn:%ld) status ...\n", ctx->sn);
1519 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1520
1521 error = dvr_playback_get_status(ctx->playback.player, &play_status);
1522 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) get status (%d)\n", ctx->sn, error);
1523
1524 ctx->playback.seg_status = play_status;
1525 error = process_generatePlaybackStatus(ctx);
1526 s = ctx->playback.status;
1527 s.info_cur.time += ctx->playback.seg_status.time_cur;
1528 /*size and packets are not available*/
1529
1530 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) state/cur/full(%d/%ld/%ld) (%d)\n",
1531 ctx->sn,
1532 s.state,
1533 s.info_cur.time,
1534 s.info_full.time,
1535 error);
1536
1537 *status = s;
1538
1539 pthread_mutex_unlock(&ctx->lock);
1540
1541 return error;
1542}
1543
hualing chen266b9502020-04-04 17:39:39 +08001544int dvr_wrapper_set_playback_secure_buffer (DVR_WrapperPlayback_t playback, uint8_t *p_secure_buf, uint32_t len)
1545{
1546 DVR_WrapperCtx_t *ctx;
1547 int error;
1548
1549 DVR_RETURN_IF_FALSE(playback);
1550 DVR_RETURN_IF_FALSE(p_secure_buf);
1551
1552 ctx = ctx_getPlayback((unsigned long)playback);
1553 DVR_RETURN_IF_FALSE(ctx);
1554
1555 pthread_mutex_lock(&ctx->lock);
1556 error = dvr_playback_set_secure_buffer(ctx->playback.player, p_secure_buf, len);
1557 pthread_mutex_unlock(&ctx->lock);
1558 return error;
1559}
1560
1561int dvr_wrapper_set_playback_decrypt_callback (DVR_WrapperPlayback_t playback, DVR_CryptoFunction_t func, void *userdata)
1562{
1563 DVR_WrapperCtx_t *ctx;
1564 int error;
1565
1566 DVR_RETURN_IF_FALSE(playback);
1567 DVR_RETURN_IF_FALSE(func);
1568
1569 ctx = ctx_getPlayback((unsigned long)playback);
1570 DVR_RETURN_IF_FALSE(ctx);
1571
1572 pthread_mutex_lock(&ctx->lock);
1573 error = dvr_playback_set_decrypt_callback(ctx->playback.player, func, userdata);
1574 pthread_mutex_unlock(&ctx->lock);
1575 return error;
1576}
1577
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001578static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata)
1579{
1580 DVR_WrapperEventCtx_t evt;
1581
1582 DVR_RETURN_IF_FALSE(userdata);
1583
1584 evt.sn = (unsigned long)userdata;
1585 evt.type = W_REC;
1586 evt.record.event = event;
1587 evt.record.status = *(DVR_RecordStatus_t *)params;
1588 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, record, evt:0x%x]\n", evt.sn, evt.record.event);
1589 return ctx_addRecordEvent(&evt);
1590}
1591
1592static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata)
1593{
1594 DVR_WrapperEventCtx_t evt;
1595
1596 DVR_RETURN_IF_FALSE(userdata);
1597
1598 evt.sn = (unsigned long)userdata;
1599 evt.type = W_PLAYBACK;
1600 evt.playback.event = event;
1601 evt.playback.status = *(DVR_Play_Notify_t *)params;
1602 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, playbck, evt:0x%x]\n", evt.sn, evt.playback.event);
1603 return ctx_addPlaybackEvent(&evt);
1604}
1605
1606static inline int process_notifyRecord(DVR_WrapperCtx_t *ctx, DVR_RecordEvent_t evt, DVR_WrapperRecordStatus_t *status)
1607{
1608 DVR_WRAPPER_DEBUG(1, "notify(sn:%ld) evt(0x%x) statistic:time/size/pkts(%lu/%lld/%u) fn:%p\n",
1609 ctx->sn,
1610 evt,
1611 status->info.time,
1612 status->info.size,
1613 status->info.pkts,
1614 ctx->record.event_fn);
1615
1616 if (ctx->record.event_fn)
1617 return ctx->record.event_fn(evt, status, ctx->record.event_userdata);
1618 return 0;
1619}
1620
1621static inline int record_startNextSegment(DVR_WrapperCtx_t *ctx)
1622{
1623 DVR_RecordStartParams_t param;
1624 DVR_RecordSegmentInfo_t seg_info;
1625 int i;
1626 int error;
1627
1628 memcpy(&param, &ctx->record.param_update, sizeof(param));
1629 memset(&ctx->record.param_update.segment, 0, sizeof(ctx->record.param_update.segment));
1630 ctx->record.param_update.segment.segment_id = ctx->record.next_segment_id++;
1631 for (i = 0; i < param.segment.nb_pids; i++) {
1632 if (param.segment.pid_action[i] != DVR_RECORD_PID_CLOSE) {
1633 ctx->record.param_update.segment.pids[ctx->record.param_update.segment.nb_pids] = param.segment.pids[i];
1634 ctx->record.param_update.segment.pid_action[ctx->record.param_update.segment.nb_pids] = DVR_RECORD_PID_KEEP;
1635 ctx->record.param_update.segment.nb_pids++;
1636 }
1637 }
1638 error = dvr_record_next_segment(ctx->record.recorder, &ctx->record.param_update, &seg_info);
1639 {
1640 DVR_RecordSegmentInfo_t new_seg_info =
1641 { .id = ctx->record.param_update.segment.segment_id, };
1642 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
1643 wrapper_addRecordSegment(ctx, &new_seg_info);
1644 }
1645
1646 DVR_WRAPPER_DEBUG(1, "record next segment (%d)\n", error);
1647 return error;
1648}
1649
1650static inline int record_removeSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *pseg)
1651{
1652 return wrapper_removeRecordSegment(ctx, pseg);
1653}
1654
1655/*should run periodically to update the current status*/
1656static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx)
1657{
1658 /*the current seg is not covered in the statistics*/
1659 DVR_WrapperRecordSegmentInfo_t *pseg;
1660
1661 /*re-calculate the all segments, except the current*/
1662 memset(&ctx->record.status, 0, sizeof(ctx->record.status));
1663
1664 ctx->record.status.state = ctx->record.seg_status.state;
1665 ctx->record.status.pids.nb_pids = ctx->record.seg_status.info.nb_pids;
1666 memcpy(ctx->record.status.pids.pids,
1667 ctx->record.seg_status.info.pids,
1668 sizeof(ctx->record.status.pids.pids));
1669 ctx->current_segment_id = ctx->record.seg_status.info.id;
1670
1671 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1672 if (pseg->info.id != ctx->record.seg_status.info.id) {
1673 ctx->record.status.info.time += pseg->info.duration;
1674 ctx->record.status.info.size += pseg->info.size;
1675 ctx->record.status.info.pkts += pseg->info.nb_packets;
1676 }
1677 }
1678
1679 wrapper_updateRecordSegment(ctx, &ctx->record.seg_status.info, U_ALL);
1680 return DVR_SUCCESS;
1681}
1682
1683
1684static int process_handleRecordEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
1685{
1686 DVR_WrapperRecordStatus_t status;
1687
1688 memset(&status, 0, sizeof(status));
1689
1690 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d)\n",
1691 evt->sn, evt->record.event, evt->record.status.state);
1692
1693 switch (evt->record.event)
1694 {
1695 case DVR_RECORD_EVENT_STATUS:
1696 {
1697 switch (evt->record.status.state)
1698 {
1699 case DVR_RECORD_STATE_OPENED:
1700 case DVR_RECORD_STATE_CLOSED:
1701 {
1702 ctx->record.seg_status = evt->record.status;
1703
1704 status.state = evt->record.status.state;
1705 process_notifyRecord(ctx, evt->record.event, &status);
1706 } break;
1707 case DVR_RECORD_STATE_STARTED:
1708 {
1709 int check_ok;
1710
1711 ctx->record.seg_status = evt->record.status;
1712
1713 process_generateRecordStatus(ctx);
1714
1715 status = ctx->record.status;
1716 status.info.time += evt->record.status.info.duration;
1717 status.info.size += evt->record.status.info.size;
1718 status.info.pkts += evt->record.status.info.nb_packets;
1719
1720 process_notifyRecord(ctx, evt->record.event, &status);
1721
1722 check_ok = 1;
1723 if (ctx->record.param_open.max_time
1724 && status.info.time >= ctx->record.param_open.max_time) {
1725 if (!ctx->record.param_open.is_timeshift) {
1726 /*not timeshifting, just stop*/
1727 int error = dvr_record_close(ctx->record.recorder);
1728 DVR_WRAPPER_DEBUG(1, "stop record(%lu)=%d, reaches time limit, curr(%ld) max(%ld)\n",
1729 ctx->sn, error,
1730 status.info.time, ctx->record.param_open.max_time);
1731 status.state = DVR_RECORD_STATE_CLOSED;
1732 process_notifyRecord(ctx, evt->record.event, &status);
1733 check_ok = 0;
1734 } else {
1735 /*timeshifting, remove the 1st segment and notify the player*/
1736 DVR_WrapperRecordSegmentInfo_t *pseg;
1737 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
1738 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
1739 /*only one segment, waiting for more*/
1740 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of max_time(%ld) of record < max size of segment(%lld)\n",
1741 status.info.size,
1742 ctx->record.param_open.max_time,
1743 ctx->record.param_open.segment_size);
1744 } else {
1745 record_removeSegment(ctx, pseg);
1746 }
1747 }
1748 }
1749
1750 if (ctx->record.param_open.max_size
1751 && status.info.size >= ctx->record.param_open.max_size) {
1752 if (!ctx->record.param_open.is_timeshift) {
1753 int error = dvr_record_close(ctx->record.recorder);
1754 DVR_WRAPPER_DEBUG(1, "stop record(%lu)=%d, reaches size limit, curr(%lld) max(%lld)\n",
1755 ctx->sn, error,
1756 status.info.size, ctx->record.param_open.max_size);
1757 status.state = DVR_RECORD_STATE_CLOSED;
1758 process_notifyRecord(ctx, evt->record.event, &status);
1759 check_ok = 0;
1760 } else {
1761 DVR_WrapperRecordSegmentInfo_t *pseg;
1762 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
1763 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
1764 /*only one segment, waiting for more*/
1765 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of record < max size of segment(%lld)\n",
1766 status.info.size,
1767 ctx->record.param_open.segment_size);
1768 } else {
1769 record_removeSegment(ctx, pseg);
1770 }
1771 }
1772 }
1773
1774 /*restart to next segment*/
1775 if (check_ok
1776 && ctx->record.param_open.segment_size
1777 && evt->record.status.info.size >= ctx->record.param_open.segment_size) {
1778 DVR_WRAPPER_DEBUG(1, "start new segment for record(%lu), reaches segment size limit, cur(%zu) max(%lld)\n",
1779 ctx->sn,
1780 evt->record.status.info.size,
1781 ctx->record.param_open.segment_size);
1782 record_startNextSegment(ctx);
1783 }
1784 } break;
1785 case DVR_RECORD_STATE_STOPPED:
1786 {
1787 ctx->record.seg_status = evt->record.status;
1788
1789 process_generateRecordStatus(ctx);
1790
1791 status.info.time += evt->record.status.info.duration;
1792 status.info.size += evt->record.status.info.size;
1793 status.info.pkts += evt->record.status.info.nb_packets;
1794
1795 process_notifyRecord(ctx, evt->record.event, &status);
1796 } break;
1797 default:
1798 break;
1799 }
1800 } break;
hualing chen4b7c15d2020-04-07 16:13:48 +08001801 case DVR_RECORD_EVENT_WRITE_ERROR: {
1802 ctx->record.seg_status = evt->record.status;
1803 status.state = evt->record.status.state;
1804 process_notifyRecord(ctx, evt->record.event, &status);
1805 }break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001806 default:
1807 break;
1808 }
1809 return DVR_SUCCESS;
1810}
1811
1812static inline int process_notifyPlayback(DVR_WrapperCtx_t *ctx, DVR_PlaybackEvent_t evt, DVR_WrapperPlaybackStatus_t *status)
1813{
1814 DVR_WRAPPER_DEBUG(1, "notify(sn:%ld) evt(0x%x) statistics:state/cur/full(%d/%ld/%ld) fn:%p\n",
1815 ctx->sn,
1816 evt,
1817 status->state,
1818 status->info_cur.time,
1819 status->info_full.time,
1820 ctx->playback.event_fn);
1821
1822 if (ctx->playback.event_fn)
1823 return ctx->playback.event_fn(evt, status, ctx->playback.event_userdata);
1824 return 0;
1825}
1826
1827/*should run periodically to update the current status*/
1828static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx)
1829{
1830 /*the current seg is not covered in the statistics*/
1831 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1832
1833 memset(&ctx->playback.status, 0, sizeof(ctx->playback.status));
1834 ctx->playback.status.pids = ctx->playback.pids_req;
1835
1836 ctx->playback.status.state = ctx->playback.seg_status.state;
1837 ctx->playback.status.speed = ctx->playback.seg_status.speed;
1838 ctx->playback.status.flags = ctx->playback.seg_status.flags;
1839 ctx->current_segment_id = ctx->playback.seg_status.segment_id;
1840
1841 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1842 if (pseg->seg_info.id == ctx->playback.seg_status.segment_id)
1843 break;
1844 ctx->playback.status.info_cur.time += pseg->seg_info.duration;
1845 ctx->playback.status.info_cur.size += pseg->seg_info.size;
1846 ctx->playback.status.info_cur.pkts += pseg->seg_info.nb_packets;
1847 }
1848 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
1849 ctx->playback.status.info_full.time += pseg->seg_info.duration;
1850 ctx->playback.status.info_full.size += pseg->seg_info.size;
1851 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
1852 }
1853
1854 return DVR_SUCCESS;
1855}
1856
1857static int process_handlePlaybackEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
1858{
1859 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d) cur(%lld:%u/%u)\n",
1860 evt->sn, evt->playback.event,
1861 evt->playback.status.play_status.state,
1862 evt->playback.status.play_status.segment_id,
1863 evt->playback.status.play_status.time_cur,
1864 evt->playback.status.play_status.time_end);
1865
1866 /*evt PLAYTIME will break the last logic, do not save*/
1867 if (evt->playback.event != DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME)
1868 ctx->playback.last_event = evt->playback.event;
1869
1870 switch (evt->playback.event)
1871 {
1872 case DVR_PLAYBACK_EVENT_FIRST_FRAME:
1873 case DVR_PLAYBACK_EVENT_REACHED_END:
1874 case DVR_PLAYBACK_EVENT_TRANSITION_OK:
1875 case DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME:
1876 {
1877 DVR_WrapperPlaybackStatus_t status;
1878
1879 /*copy status of segment*/
1880 ctx->playback.seg_status = evt->playback.status.play_status;
1881
1882 /*generate status of the whole playback, except current*/
1883 process_generatePlaybackStatus(ctx);
1884
1885 status = ctx->playback.status;
1886 /*deal with current, lack size and pkts with the current*/
1887 status.info_cur.time += ctx->playback.seg_status.time_cur;
1888
1889 if (evt->playback.event == DVR_PLAYBACK_EVENT_REACHED_END) {
1890 if (ctx->playback.param_open.is_timeshift) {
1891 /*wait for more data in recording*/
1892 } else if ((status.info_cur.time + DVR_PLAYBACK_END_GAP) >= ctx->playback.status.info_full.time) {
1893 process_notifyPlayback(ctx, evt->playback.event, &status);
1894 }
1895 } else {
1896 process_notifyPlayback(ctx, evt->playback.event, &status);
1897 }
1898 } break;
1899 case DVR_PLAYBACK_EVENT_ERROR:
1900 case DVR_PLAYBACK_EVENT_TRANSITION_FAILED:
1901 case DVR_PLAYBACK_EVENT_KEY_FAILURE:
1902 case DVR_PLAYBACK_EVENT_NO_KEY:
1903 {
1904 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) error event:0x%x\n", evt->sn, evt->playback.event);
1905 } break;
1906 default:
1907 {
1908 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) unknown event:0x%x\n", evt->sn, evt->playback.event);
1909 } break;
1910 }
1911 return 0;
1912}
1913
1914static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
1915{
1916 return (evt->type == W_REC)? process_handleRecordEvent(evt, ctx) : process_handlePlaybackEvent(evt, ctx);
1917}
1918