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