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