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