blob: d3adfaa0731f2f78c46430cbd56ccd844ab23af3 [file] [log] [blame]
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001#include <stddef.h>
Zhiqiang Han620b9252021-11-09 14:23:20 +08002#include <unistd.h>
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08003#include <stdlib.h>
4#include <pthread.h>
5#include <string.h>
6#include <time.h>
7#include <errno.h>
Zhiqiang Han18f42c82021-08-11 17:13:28 +08008#include <sys/time.h>
9#include <time.h>
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080010
11#include "dvr_types.h"
12#include "dvr_record.h"
13#include "dvr_crypto.h"
14#include "dvr_playback.h"
15#include "dvr_segment.h"
16
17#include "AmTsPlayer.h"
18
19#include "list.h"
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080020
21#include "dvr_wrapper.h"
22
Gong Ke2a0ebbe2021-05-25 15:22:50 +080023#define DVR_WRAPPER_DEBUG(_level, _fmt...) \
24 DVR_DEBUG_FL(_level, "wrapper", _fmt)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080025
26/*duration of data to resume if paused with EVT_REACHED_END in timeshifting*/
hualing chen2932d372020-04-29 13:44:00 +080027#define TIMESHIFT_DATA_DURATION_TO_RESUME (600)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080028/*a tolerant gap*/
29#define DVR_PLAYBACK_END_GAP (1000)
30
31enum {
32 W_REC = 1,
33 W_PLAYBACK = 2,
34};
35
36enum {
37 U_PIDS = 0x01,
38 U_STAT = 0x02,
39 U_ALL = U_PIDS | U_STAT,
40};
41
42typedef struct {
43 /*make lock the 1st item in the structure*/
44 pthread_mutex_t lock;
45
46 /*rec or play*/
47 int type;
48
49 /*valid if (sn != 0)*/
50 unsigned long sn;
51 unsigned long sn_linked;
52
53 struct list_head segments; /**<head-add list*/
54 uint64_t current_segment_id; /**<id of the current segment*/
55
56 union {
57 struct {
58 DVR_WrapperRecordOpenParams_t param_open;
59 DVR_RecordStartParams_t param_start;
60 DVR_RecordStartParams_t param_update;
61 DVR_RecordHandle_t recorder;
62 DVR_RecordEventFunction_t event_fn;
63 void *event_userdata;
64
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080065 /*total status = seg_status + status + obsolete*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080066 DVR_RecordStatus_t seg_status; /**<status of current segment*/
67 DVR_WrapperRecordStatus_t status; /**<status of remaining segments*/
68 uint64_t next_segment_id;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080069
70 DVR_WrapperInfo_t obsolete; /**<data obsolete due to the max limit*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080071 } record;
72
73 struct {
74 DVR_WrapperPlaybackOpenParams_t param_open;
75 DVR_PlaybackHandle_t player;
76 DVR_PlaybackEventFunction_t event_fn;
77 void *event_userdata;
78
79 /*total status = seg_status + status*/
80 DVR_PlaybackStatus_t seg_status;
81 DVR_WrapperPlaybackStatus_t status;
82 DVR_PlaybackPids_t pids_req;
83 DVR_PlaybackEvent_t last_event;
Zhiqiang Han3eb75f92020-04-08 10:07:55 +080084 float speed;
hualing chenb5cd42e2020-04-15 17:03:34 +080085 DVR_Bool_t reach_end;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +080086
87 DVR_WrapperInfo_t obsolete;
hualing chen56c0a162022-01-27 17:01:50 +080088 DVR_Bool_t tf_full;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +080089 } playback;
90 };
91} DVR_WrapperCtx_t;
92
93typedef struct {
94 struct list_head head;
95 unsigned long sn;
96
97 /* rec or playback */
98 int type;
99
100 union {
101 struct {
102 DVR_RecordEvent_t event;
103 DVR_RecordStatus_t status;
104 } record;
105 struct {
106 DVR_PlaybackEvent_t event;
107 DVR_Play_Notify_t status;
108 } playback;
109 };
110} DVR_WrapperEventCtx_t;
111
112typedef struct {
113 pthread_mutex_t lock;
114 char *name;
115 int running;
116 pthread_cond_t cond;
117 pthread_t thread;
118 int type;
119} DVR_WrapperThreadCtx_t;
120
121typedef struct {
122 struct list_head head;
123
124 DVR_RecordSegmentInfo_t seg_info;
125 DVR_PlaybackSegmentInfo_t playback_info;
126} DVR_WrapperPlaybackSegmentInfo_t;
127
128typedef struct {
129 struct list_head head;
130
131 DVR_RecordSegmentInfo_t info;
132} DVR_WrapperRecordSegmentInfo_t;
133
134/* serial num generater */
135static unsigned long sn = 1;
136static pthread_mutex_t sn_lock = PTHREAD_MUTEX_INITIALIZER;
137
138static inline unsigned long get_sn()
139{
hualing chenab0d1262021-09-26 15:22:50 +0800140 unsigned long no = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800141
142 pthread_mutex_lock(&sn_lock);
143 no = sn++;
144 if (!no)
145 no = sn++;
146 pthread_mutex_unlock(&sn_lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800147 return no;
148}
149
150/* entity ctx */
151#define DVR_WRAPPER_MAX 10
152
153static DVR_WrapperCtx_t record_list[DVR_WRAPPER_MAX] =
154{
155 [0 ... (DVR_WRAPPER_MAX - 1)] =
156 {
157 .lock = PTHREAD_MUTEX_INITIALIZER,
158 .type = W_REC,
159 }
160};
161
162static DVR_WrapperCtx_t playback_list[DVR_WRAPPER_MAX] =
163{
164 [0 ... (DVR_WRAPPER_MAX - 1)] =
165 {
166 .lock = PTHREAD_MUTEX_INITIALIZER,
167 .type = W_PLAYBACK,
168 }
169};
170
171/* events lists */
172static struct list_head record_evt_list = LIST_HEAD_INIT(record_evt_list);
173static struct list_head playback_evt_list = LIST_HEAD_INIT(playback_evt_list);
174
175static pthread_mutex_t record_evt_list_lock = PTHREAD_MUTEX_INITIALIZER;
176static pthread_mutex_t playback_evt_list_lock = PTHREAD_MUTEX_INITIALIZER;
177
178static DVR_WrapperThreadCtx_t wrapper_thread[2] =
179{
180 [0] =
181 {
182 .lock = PTHREAD_MUTEX_INITIALIZER,
183 .running = 0,
184 .name = "record",
185 .type = W_REC,
186 },
187 [1] =
188 {
189 .lock = PTHREAD_MUTEX_INITIALIZER,
190 .running = 0,
191 .name = "playback",
192 .type = W_PLAYBACK,
193 },
194};
195
196/*now only support one timeshift now*/
197static unsigned long sn_timeshift_record;
198static unsigned long sn_timeshift_playback;
199
200static void *wrapper_task(void *arg);
201static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx);
202
203static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata);
204static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata);
205
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800206static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordStatus_t *status);
207static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperPlaybackStatus_t *status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800208
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800209static int get_timespec_timeout(int timeout, struct timespec *ts)
210{
211 struct timespec ots;
212 int left, diff;
213
214 clock_gettime(CLOCK_MONOTONIC, &ots);
215
216 ts->tv_sec = ots.tv_sec + timeout / 1000;
217 ts->tv_nsec = ots.tv_nsec;
218
219 left = timeout % 1000;
220 left *= 1000000;
221 diff = 1000000000 - ots.tv_nsec;
222
223 if (diff <= left) {
224 ts->tv_sec++;
225 ts->tv_nsec = left-diff;
226 } else {
227 ts->tv_nsec += left;
228 }
229
230 return 0;
231}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800232
233static DVR_WrapperEventCtx_t *ctx_getEvent(struct list_head *list, pthread_mutex_t *list_lock)
234{
235 DVR_WrapperEventCtx_t *pevt;
236
237 pthread_mutex_lock(list_lock);
238 if (list_empty(list))
239 pevt = NULL;
240 else {
241 pevt = list_first_entry(list, DVR_WrapperEventCtx_t, head);
242 list_del(&pevt->head);
243 }
244 pthread_mutex_unlock(list_lock);
245
246 return pevt;
247}
248
249static inline DVR_WrapperEventCtx_t *ctx_getRecordEvent()
250{
251 return ctx_getEvent(&record_evt_list, &record_evt_list_lock);
252}
253
254static inline DVR_WrapperEventCtx_t *ctx_getPlaybackEvent()
255{
256 return ctx_getEvent(&playback_evt_list, &playback_evt_list_lock);
257}
258
259static int ctx_addEvent(struct list_head *list, pthread_mutex_t *lock, DVR_WrapperEventCtx_t *evt)
260{
261 DVR_WrapperEventCtx_t *padd;
262 padd = (DVR_WrapperEventCtx_t *)calloc(1, sizeof(DVR_WrapperEventCtx_t));
263 DVR_RETURN_IF_FALSE(padd);
264
265 *padd = *evt;
266 pthread_mutex_lock(lock);
267 list_add_tail(&padd->head, list);
268 pthread_mutex_unlock(lock);
269 return DVR_SUCCESS;
270}
271
272static inline void ctx_freeEvent(DVR_WrapperEventCtx_t *evt)
273{
274 free(evt);
275}
276
277/*useless*/
278static void ctx_cleanOutdatedEvents(struct list_head *evt_list,
279 pthread_mutex_t *evt_list_lock,
280 DVR_WrapperCtx_t *list)
281{
282 DVR_WrapperEventCtx_t *pevt, *pevt_tmp;
283 unsigned long sns[DVR_WRAPPER_MAX];
284 int cnt = 0;
285 int i;
286 int found = 0;
287
288 /*copy all valid sns*/
289 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
290 sns[cnt] = list[i].sn;
291 if (!sns[cnt])
292 cnt++;
293 }
294
295 /*free evts that not belong to any valid sns*/
296 pthread_mutex_lock(evt_list_lock);
297 list_for_each_entry_safe(pevt, pevt_tmp, evt_list, head) {
298 for (i = 0; i < cnt; i++) {
299 if (pevt->sn == sns[i]) {
300 found = 1;
301 break;
302 }
303 }
304 if (!found) {
305 list_del(&pevt->head);
306 ctx_freeEvent(pevt);
307 }
308 }
309 pthread_mutex_unlock(evt_list_lock);
310}
311
312static inline void ctx_cleanOutdatedRecordEvents()
313{
314 ctx_cleanOutdatedEvents(&record_evt_list, &record_evt_list_lock, record_list);
315}
316
317static inline void ctx_cleanOutdatedPlaybackEvents()
318{
319 ctx_cleanOutdatedEvents(&playback_evt_list, &playback_evt_list_lock, playback_list);
320}
321
hualing chenb9b358a2021-08-17 15:06:36 +0800322//check this play is recording file
323//return 0 if not the recording
324//else return record id
325static inline int ctx_isPlay_recording(char *play_location)
326{
327 int i;
328 DVR_WrapperCtx_t *cnt;
329
330 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
331 cnt = &record_list[i];
332 //DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]R:[%s]P:[%s] ...\n", i, cnt->sn, cnt->record.param_open.location, play_location);
333 if (!strcmp(cnt->record.param_open.location, play_location)) {
334 DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]R:[%s]P:[%s] .found..\n", i, cnt->sn, cnt->record.param_open.location, play_location);
335 return cnt->sn;
336 }
337 }
338 DVR_WRAPPER_DEBUG(1, " not found play is recing [%d]", DVR_WRAPPER_MAX);
339 return 0;
340}
341//check this record is playing file
342//return 0 if not the playing
343//else return playback id
344static inline int ctx_isRecord_playing(char *rec_location)
345{
346 int i;
347 DVR_WrapperCtx_t *cnt;
348 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
349 cnt = &playback_list[i];
350 //DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]P[%s]R[%s] ...\n", i, cnt->sn, cnt->playback.param_open.location, rec_location);
351 if (!strcmp(cnt->playback.param_open.location, rec_location)) {
352 DVR_WRAPPER_DEBUG(1, "[%d]sn[%d]P[%s]R[%s] ..found.\n",i, cnt->sn, cnt->playback.param_open.location, rec_location);
353 return cnt->sn;
354 }
355 }
356 DVR_WRAPPER_DEBUG(1, " not found rec is playing [%d]", DVR_WRAPPER_MAX);
357 return 0;
358}
359
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800360static inline DVR_WrapperCtx_t *ctx_get(unsigned long sn, DVR_WrapperCtx_t *list)
361{
362 int i;
363 for (i = 0; i < DVR_WRAPPER_MAX; i++) {
364 if (list[i].sn == sn)
365 return &list[i];
366 }
367 return NULL;
368}
369
370static inline void ctx_reset(DVR_WrapperCtx_t *ctx)
371{
372 memset((char *)ctx + offsetof(DVR_WrapperCtx_t, sn),
373 0,
374 sizeof(DVR_WrapperCtx_t) - offsetof(DVR_WrapperCtx_t, sn));
375}
376
377static inline int ctx_valid(DVR_WrapperCtx_t *ctx)
378{
379 return (ctx->sn != 0);
380}
381
382static inline DVR_WrapperCtx_t *ctx_getRecord(unsigned long sn)
383{
384 return ctx_get(sn, record_list);
385}
386
387static inline DVR_WrapperCtx_t *ctx_getPlayback(unsigned long sn)
388{
389 return ctx_get(sn, playback_list);
390}
391
392static int wrapper_requestThread(DVR_WrapperThreadCtx_t *ctx, void *(thread_fn)(void *))
393{
394 pthread_mutex_lock(&ctx->lock);
395 if (ctx->running == 0) {
396 pthread_condattr_t attr;
397 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
398 pthread_cond_init(&ctx->cond, &attr);
399 pthread_condattr_destroy(&attr);
400 DVR_WRAPPER_DEBUG(1, "start wrapper thread(%s) ...\n", ctx->name);
401 pthread_create(&ctx->thread, NULL, thread_fn, ctx);
402 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) started\n", ctx->name);
403 }
404 ctx->running++;
405 pthread_mutex_unlock(&ctx->lock);
406 return 0;
407}
408
409static int wrapper_releaseThread(DVR_WrapperThreadCtx_t *ctx)
410{
411 pthread_mutex_lock(&ctx->lock);
412 ctx->running--;
413 if (!ctx->running) {
414 pthread_cond_broadcast(&ctx->cond);
415 pthread_mutex_unlock(&ctx->lock);
416
417 DVR_WRAPPER_DEBUG(1, "stop wrapper thread(%s) ...\n", ctx->name);
418 pthread_join(ctx->thread, NULL);
419 DVR_WRAPPER_DEBUG(1, "wrapper thread(%s) stopped\n", ctx->name);
420
421 pthread_mutex_lock(&ctx->lock);
422 if (!ctx->running) /*protect*/
423 pthread_cond_destroy(&ctx->cond);
424 }
425 pthread_mutex_unlock(&ctx->lock);
426 return 0;
427}
428
429#define WRAPPER_THREAD_RECORD (&wrapper_thread[0])
430#define WRAPPER_THREAD_PLAYBACK (&wrapper_thread[1])
431
432static inline int wrapper_requestThreadFor(DVR_WrapperCtx_t *ctx)
433{
434 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
435 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
436 return wrapper_requestThread(thread_ctx, wrapper_task);
437}
438
439static inline int wrapper_releaseThreadFor(DVR_WrapperCtx_t *ctx)
440{
441 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC)?
442 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
443 return wrapper_releaseThread(thread_ctx);
444}
445
446static inline int wrapper_releaseThreadForType(int type)
447{
448 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC)?
449 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
450 return wrapper_releaseThread(thread_ctx);
451}
452
453static inline void wrapper_threadSignal(DVR_WrapperThreadCtx_t *thread_ctx)
454{
455 pthread_cond_signal(&thread_ctx->cond);
456}
457
458static inline int wrapper_threadWait(DVR_WrapperThreadCtx_t *thread_ctx)
459{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800460 struct timespec rt;
461 get_timespec_timeout(200, &rt);
462 pthread_cond_timedwait(&thread_ctx->cond, &thread_ctx->lock, &rt);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800463 return 0;
464}
465
466static inline void wrapper_threadSignalForType(int type)
467{
468 DVR_WrapperThreadCtx_t *thread_ctx = (type == W_REC) ?
469 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
470 wrapper_threadSignal(thread_ctx);
471}
472
473static inline void wrapper_threadSignalFor(DVR_WrapperCtx_t *ctx)
474{
475 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
476 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
477 wrapper_threadSignal(thread_ctx);
478}
479
480static inline int wrapper_threadWaitFor(DVR_WrapperCtx_t *ctx)
481{
482 DVR_WrapperThreadCtx_t *thread_ctx = (ctx->type == W_REC) ?
483 WRAPPER_THREAD_RECORD : WRAPPER_THREAD_PLAYBACK;
484 wrapper_threadWait(thread_ctx);
485 return 0;
486}
487
488static void get_timeout_real(int timeout, struct timespec *ts)
489{
490 struct timespec ots;
491 int left, diff;
492
493 clock_gettime(CLOCK_REALTIME, &ots);
494
495 ts->tv_sec = ots.tv_sec + timeout/1000;
496 ts->tv_nsec = ots.tv_nsec;
497
498 left = timeout % 1000;
499 left *= 1000000;
500 diff = 1000000000-ots.tv_nsec;
501
502 if (diff <= left) {
503 ts->tv_sec++;
504 ts->tv_nsec = left-diff;
505 } else {
506 ts->tv_nsec += left;
507 }
508}
509
510/*return condition, locked if condition == true*/
511static int wrapper_mutex_lock_if(pthread_mutex_t *lock, int *condition)
512{
513 int r2;
514 do {
515 struct timespec rt2;
516 /*android use real time for mutex timedlock*/
517 get_timeout_real(10, &rt2);
518 r2 = pthread_mutex_timedlock(lock, &rt2);
519 } while (*condition && (r2 == ETIMEDOUT));
520
521 if (!(*condition) && (r2 == 0))
522 pthread_mutex_unlock(lock);
523
524 return *condition;
525}
526
527static void *wrapper_task(void *arg)
528{
529 DVR_WrapperThreadCtx_t *tctx = (DVR_WrapperThreadCtx_t *)arg;
530 DVR_WrapperEventCtx_t *evt;
531
532 pthread_mutex_lock(&tctx->lock);
533
534 while (tctx->running) {
535 {
536 int ret;
hualing chene3797f02021-01-13 14:53:28 +0800537
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800538 evt = (tctx->type == W_REC)? ctx_getRecordEvent() : ctx_getPlaybackEvent();
539 if (!evt)
540 ret = wrapper_threadWait(tctx);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800541 }
542
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800543 while (evt) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800544 DVR_WrapperCtx_t *ctx = (evt->type == W_REC)?
545 ctx_getRecord(evt->sn) : ctx_getPlayback(evt->sn);
hualing chenbc0aec92021-03-18 14:52:40 +0800546 if (ctx == NULL) {
547 DVR_WRAPPER_DEBUG(1, "warp not get ctx.free event..\n");
548 goto processed;
549 }
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800550 DVR_WRAPPER_DEBUG(1, "start name(%s) sn(%d) running(%d) type(%d)\n", tctx->name, (int)ctx->sn, tctx->running, tctx->type);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800551 if (tctx->running) {
552 /*
553 continue not break,
554 make all events consumed, or mem leak
555 */
556 if (!wrapper_mutex_lock_if(&ctx->lock, &tctx->running))
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800557 goto processed;
558
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800559 if (ctx_valid(ctx)) {
560 /*double check after lock*/
Zhiqiang Han3b9c9082021-11-10 10:41:09 +0800561 if (evt->sn == ctx->sn) {
562 pthread_mutex_unlock(&tctx->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800563 process_handleEvents(evt, ctx);
Zhiqiang Han3b9c9082021-11-10 10:41:09 +0800564 pthread_mutex_lock(&tctx->lock);
565 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800566 }
567 pthread_mutex_unlock(&ctx->lock);
568 }
569
Zhiqiang Hanef61c0a2020-04-13 15:49:24 +0800570processed:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800571 ctx_freeEvent(evt);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800572
573 evt = (tctx->type == W_REC)? ctx_getRecordEvent() : ctx_getPlaybackEvent();
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800574 }
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800575 DVR_WRAPPER_DEBUG(1, "start name(%s) running(%d) type(%d) con...\n", tctx->name, tctx->running, tctx->type);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800576 }
577
578 pthread_mutex_unlock(&tctx->lock);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800579 DVR_WRAPPER_DEBUG(1, "end name(%s) running(%d) type(%d) end...\n", tctx->name, tctx->running, tctx->type);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800580 return NULL;
581}
582
583static inline int ctx_addRecordEvent(DVR_WrapperEventCtx_t *evt)
584{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800585 pthread_mutex_lock(&WRAPPER_THREAD_RECORD->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800586 if (ctx_addEvent(&record_evt_list, &record_evt_list_lock, evt) == 0)
587 wrapper_threadSignalForType(evt->type);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800588 pthread_mutex_unlock(&WRAPPER_THREAD_RECORD->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800589 return 0;
590}
591
592static inline int ctx_addPlaybackEvent(DVR_WrapperEventCtx_t *evt)
593{
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800594 pthread_mutex_lock(&WRAPPER_THREAD_PLAYBACK->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800595 if (ctx_addEvent(&playback_evt_list, &playback_evt_list_lock, evt) == 0)
596 wrapper_threadSignalForType(evt->type);
Zhiqiang Han18f42c82021-08-11 17:13:28 +0800597 pthread_mutex_unlock(&WRAPPER_THREAD_PLAYBACK->lock);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800598 return 0;
599}
600
601static inline void ctx_freeSegments(DVR_WrapperCtx_t *ctx)
602{
603 DVR_WrapperPlaybackSegmentInfo_t *pseg, *pseg_tmp;
604 list_for_each_entry_safe(pseg, pseg_tmp, &ctx->segments, head) {
605 list_del(&pseg->head);
606 free(pseg);
607 }
608}
609
610static inline void _updatePlaybackSegment(DVR_WrapperPlaybackSegmentInfo_t *pseg,
611 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
612{
613 (void)ctx;
614 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
615 pseg->seg_info = *seg_info;
616 else if (update_flags & U_PIDS) {
617 pseg->seg_info.nb_pids = seg_info->nb_pids;
618 memcpy(pseg->seg_info.pids, seg_info->pids, sizeof(pseg->seg_info.pids));
619 } else if (update_flags & U_STAT) {
620 pseg->seg_info.duration = seg_info->duration;
621 pseg->seg_info.size = seg_info->size;
622 pseg->seg_info.nb_packets = seg_info->nb_packets;
623 }
hualing chen03fd4942021-07-15 15:56:41 +0800624 //update current segment duration on timeshift mode
hualing chenb9b358a2021-08-17 15:06:36 +0800625 if (ctx->playback.param_open.is_timeshift
626 || ctx_isPlay_recording(ctx->playback.param_open.location))
hualing chen03fd4942021-07-15 15:56:41 +0800627 dvr_playback_update_duration(ctx->playback.player,pseg->seg_info.id,pseg->seg_info.duration);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800628 /*no changes
629 DVR_PlaybackSegmentFlag_t flags;
630 pseg->playback_info.segment_id = pseg->seg_info.id;
631 strncpy(pseg->playback_info.location,
632 ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
633 pseg->playback_info.pids = ctx->playback.pids_req;
634 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
635 if (ctx->record.param_open.flags | DVR_RECORD_FLAG_SCRAMBLED)
636 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
637 pseg->playback_info.flags = flags;
638 */
639}
640
641static int wrapper_updatePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
642{
643 DVR_WrapperPlaybackSegmentInfo_t *pseg;
644
645 DVR_WRAPPER_DEBUG(1, "timeshift, update playback segments(wrapper), seg:%lld t/s/p(%ld/%zu/%u)\n",
646 seg_info->id, seg_info->duration, seg_info->size, seg_info->nb_packets);
647
648 if (list_empty(&ctx->segments)) {
649 DVR_WRAPPER_DEBUG(1, "timeshift, update while no segment exists, ignore\n");
650 return DVR_SUCCESS;
651 }
652
653 /*normally, the last segment added will be updated*/
654 pseg =
655 list_first_entry(&ctx->segments, DVR_WrapperPlaybackSegmentInfo_t, head);
656 if (pseg->seg_info.id == seg_info->id) {
657 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
658 } else {
659 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
660 if (pseg->seg_info.id == seg_info->id) {
661 _updatePlaybackSegment(pseg, seg_info, update_flags, ctx);
662 break;
663 }
664 }
665 }
666
667 /*need to notify the dvr_playback*/
hualing chenb9b358a2021-08-17 15:06:36 +0800668 if ((ctx->playback.param_open.is_timeshift/*should must be timeshift*/
669 || ctx_isPlay_recording(ctx->playback.param_open.location))
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800670 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END
671 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
672 if (
673 /*there's $TIMESHIFT_DATA_DURATION_TO_RESUME more of data in the current segment playing*/
674 (ctx->playback.seg_status.segment_id == seg_info->id
675 && (seg_info->duration >= ((time_t)ctx->playback.seg_status.time_cur + TIMESHIFT_DATA_DURATION_TO_RESUME)))
676 ||
677 /*or there's a new segment and has $TIMESHIFT_DATA_DURATION_TO_RESUME of data*/
678 (ctx->playback.seg_status.segment_id != seg_info->id
679 && (seg_info->duration >= TIMESHIFT_DATA_DURATION_TO_RESUME))
680 )
681 {
682 int error;
hualing chen36e0dfd2020-05-02 16:33:06 +0800683 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +0800684 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +0800685 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800686
687 error = dvr_playback_resume(ctx->playback.player);
688 DVR_WRAPPER_DEBUG(1, "timeshift, resume playback(sn:%ld) (%d) id/dur: rec(%lld/%ld) play(%lld/%u)\n",
689 ctx->sn, error,
690 seg_info->id, seg_info->duration,
691 ctx->playback.seg_status.segment_id, ctx->playback.seg_status.time_cur);
692 }
693 }
694
695 return DVR_SUCCESS;
696}
697
698static void _updateRecordSegment(DVR_WrapperRecordSegmentInfo_t *pseg,
699 DVR_RecordSegmentInfo_t *seg_info, int update_flags, DVR_WrapperCtx_t *ctx)
700{
701 (void)ctx;
702 if ((update_flags & U_PIDS) && (update_flags & U_STAT))
703 pseg->info = *seg_info;
704 else if (update_flags & U_PIDS) {
705 pseg->info.nb_pids = seg_info->nb_pids;
706 memcpy(pseg->info.pids, seg_info->pids, sizeof(pseg->info.pids));
707 } else if (update_flags & U_STAT) {
708 pseg->info.duration = seg_info->duration;
709 pseg->info.size = seg_info->size;
710 pseg->info.nb_packets = seg_info->nb_packets;
711 }
712}
713
714static int wrapper_updateRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info, int update_flags)
715{
hualing chen266b9502020-04-04 17:39:39 +0800716 DVR_WrapperRecordSegmentInfo_t *pseg = NULL;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800717
718 /*normally, the last segment added will be updated*/
hualing chen266b9502020-04-04 17:39:39 +0800719 if (!list_empty(&ctx->segments)) {
720 pseg =
721 list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
722 if (pseg->info.id == seg_info->id) {
723 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
724 } else {
725 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
726 if (pseg->info.id == seg_info->id) {
727 _updateRecordSegment(pseg, seg_info, update_flags, ctx);
728 break;
729 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800730 }
731 }
732 }
733
734 /*timeshift, update the segment for playback*/
735 /*
736 the playback should grab the segment info other than the id,
737 and the id will be updated by each segment-add during the recording
738 */
739 /*
740 the playback paused if no data been checked from recording,
741 should resume the player later when there's more data
742 */
hualing chenb9b358a2021-08-17 15:06:36 +0800743 int sn = 0;
744 if (ctx->record.param_open.is_timeshift ||
745 (sn = ctx_isRecord_playing(ctx->record.param_open.location))) {
746 DVR_WrapperCtx_t *ctx_playback;
747 if (ctx->record.param_open.is_timeshift)
748 ctx_playback = ctx_getPlayback(sn_timeshift_playback);
749 else
750 ctx_playback = ctx_getPlayback(sn);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800751
752 if (ctx_playback) {
753 pthread_mutex_lock(&ctx_playback->lock);
754 if (ctx_valid(ctx_playback)
hualing chenb9b358a2021-08-17 15:06:36 +0800755 && (ctx_playback->sn == sn_timeshift_playback ||
756 ctx_playback->sn == sn)) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800757 wrapper_updatePlaybackSegment(ctx_playback, seg_info, update_flags);
758 }
759 pthread_mutex_unlock(&ctx_playback->lock);
760 }
761 }
762
763 return DVR_SUCCESS;
764}
765
766static int wrapper_addPlaybackSegment(DVR_WrapperCtx_t *ctx,
767 DVR_RecordSegmentInfo_t *seg_info,
768 DVR_PlaybackPids_t *p_pids,
769 DVR_PlaybackSegmentFlag_t flags)
770{
771 DVR_WrapperPlaybackSegmentInfo_t *pseg;
772 int error;
773
774 error = 0;
775 pseg = (DVR_WrapperPlaybackSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperPlaybackSegmentInfo_t));
776 if (!pseg) {
777 error = DVR_FAILURE;
778 DVR_WRAPPER_DEBUG(1, "memory fail\n");
779 return error;
780 }
781
782 /*copy the orignal segment info*/
783 pseg->seg_info = *seg_info;
784 /*generate the segment info used in playback*/
785 pseg->playback_info.segment_id = pseg->seg_info.id;
786 strncpy(pseg->playback_info.location, ctx->playback.param_open.location, sizeof(pseg->playback_info.location));
787 pseg->playback_info.pids = *p_pids;
788 pseg->playback_info.flags = flags;
789 list_add(&pseg->head, &ctx->segments);
hualing chen451c8f72022-03-09 13:05:52 +0800790 DVR_WRAPPER_DEBUG(1, "start to add segment %lld\n", pseg->playback_info.segment_id);
hualing chen03fd4942021-07-15 15:56:41 +0800791 pseg->playback_info.duration = pseg->seg_info.duration;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800792
793 error = dvr_playback_add_segment(ctx->playback.player, &pseg->playback_info);
794 if (error) {
795 DVR_WRAPPER_DEBUG(1, "fail to add segment %lld (%d)\n", pseg->playback_info.segment_id, error);
796 } else {
797 ctx->playback.status.info_full.time += pseg->seg_info.duration;
798 ctx->playback.status.info_full.size += pseg->seg_info.size;
799 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
800 }
801
802 return error;
803}
804
805static int wrapper_addRecordSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
806{
807 DVR_WrapperRecordSegmentInfo_t *pseg;
808 int error;
hualing chenab0d1262021-09-26 15:22:50 +0800809 int sn = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800810
811 error = 0;
812 pseg = (DVR_WrapperRecordSegmentInfo_t *)calloc(1, sizeof(DVR_WrapperRecordSegmentInfo_t));
813 if (!pseg) {
814 error = DVR_FAILURE;
815 DVR_WRAPPER_DEBUG(1, "memory fail\n");
816 }
817 pseg->info = *seg_info;
818 list_add(&pseg->head, &ctx->segments);
hualing chenab0d1262021-09-26 15:22:50 +0800819
hualing chenb9b358a2021-08-17 15:06:36 +0800820 if (ctx->record.param_open.is_timeshift ||
821 (sn = ctx_isRecord_playing(ctx->record.param_open.location))) {
822
823 DVR_WrapperCtx_t *ctx_playback;
824 if (ctx->record.param_open.is_timeshift)
825 ctx_playback = ctx_getPlayback(sn_timeshift_playback);
826 else
827 ctx_playback = ctx_getPlayback(sn);
828
829 DVR_WRAPPER_DEBUG(1, "ctx_playback ---- add segment\n");
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800830
831 if (ctx_playback) {
832 pthread_mutex_lock(&ctx_playback->lock);
833 if (ctx_valid(ctx_playback)) {
834 DVR_PlaybackSegmentFlag_t flags;
835
836 /*only if playback has started, the previous segments have been loaded*/
837 if (!list_empty(&ctx_playback->segments)) {
838 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
Gong Ke2a0ebbe2021-05-25 15:22:50 +0800839 if (ctx->record.param_open.flags & DVR_RECORD_FLAG_SCRAMBLED)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800840 flags |= DVR_PLAYBACK_SEGMENT_ENCRYPTED;
841 wrapper_addPlaybackSegment(ctx_playback, seg_info, &ctx_playback->playback.pids_req, flags);
hualing chen451c8f72022-03-09 13:05:52 +0800842 } else {
843 DVR_WRAPPER_DEBUG(1, "ctx_playback list_empty(&ctx_playback->segments) true\n");
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800844 }
hualing chenb9b358a2021-08-17 15:06:36 +0800845 } else {
846 DVR_WRAPPER_DEBUG(1, "ctx_playback ---- not valid\n");
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800847 }
848 pthread_mutex_unlock(&ctx_playback->lock);
849 }
hualing chen451c8f72022-03-09 13:05:52 +0800850 else
851 {
852 DVR_WRAPPER_DEBUG(1, "ctx_playback ---- not valid 1\n");
853 }
Zhiqiang Hane0a1c382021-06-08 11:28:05 +0800854 } else {
hualing chenb9b358a2021-08-17 15:06:36 +0800855 DVR_WRAPPER_DEBUG(1, "ctx_playback -sn[%d]-\n", sn);
Zhiqiang Hane0a1c382021-06-08 11:28:05 +0800856 dvr_segment_link_op(ctx->record.param_open.location, 1, &seg_info->id, LSEG_OP_ADD);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800857 }
858
859 return error;
860}
861
862static int wrapper_removePlaybackSegment(DVR_WrapperCtx_t *ctx, DVR_RecordSegmentInfo_t *seg_info)
863{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800864 int error = -1;
865 DVR_WrapperPlaybackSegmentInfo_t *pseg = NULL, *pseg_tmp;
hualing chenb9a1a2c2021-12-31 11:27:59 +0800866 uint32_t off_set = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800867 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->id);
868
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800869 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800870 if (pseg->seg_info.id == seg_info->id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800871
872 if (ctx->current_segment_id == seg_info->id) {
873 DVR_WrapperPlaybackSegmentInfo_t *next_seg;
874
875 /*drive the player out of this will-be-deleted segment*/
876 next_seg = list_prev_entry(pseg, head);
877
878 if (ctx->playback.speed != 100.0f) {
879 error = dvr_playback_resume(ctx->playback.player);
880 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), resume for new start (%d)\n", ctx->sn, error);
881 }
hualing chenb9a1a2c2021-12-31 11:27:59 +0800882 if (ctx->playback.param_open.vendor == DVR_PLAYBACK_VENDOR_AMAZON)
883 off_set = 10 * 1000;
884 error = dvr_playback_seek(ctx->playback.player, next_seg->seg_info.id, off_set);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800885 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), seek(seg:%llu 0) from new start (%d)\n", ctx->sn, next_seg->seg_info.id, error);
886
887 if (ctx->playback.speed == 0.0f) {
888 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
889 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last paused from new start (%d)\n", ctx->sn, error);
890 } else if (ctx->playback.speed != 100.0f) {
891 DVR_PlaybackSpeed_t dvr_speed = {
892 .speed = { ctx->playback.speed },
893 .mode = ( ctx->playback.speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
894 };
895 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
896 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), keep last speed(x%f) from new start (%d)\n", ctx->sn,ctx->playback.speed, error);
897 }
898 }
899
900 error = dvr_playback_remove_segment(ctx->playback.player, seg_info->id);
901 if (error) {
902 /*remove playack segment fail*/
903 DVR_WRAPPER_DEBUG(1, "timeshift, playback(sn:%ld), failed to remove segment(%llu) (%d)\n", ctx->sn, seg_info->id, error);
904 }
905
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800906 list_del(&pseg->head);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800907
908 /*record the obsolete*/
909 ctx->playback.obsolete.time += pseg->seg_info.duration;
910 ctx->playback.obsolete.size += pseg->seg_info.size;
911 ctx->playback.obsolete.pkts += pseg->seg_info.nb_packets;
hualing chen56c0a162022-01-27 17:01:50 +0800912 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) ..obs(%d).\n", ctx->sn, seg_info->id, ctx->playback.obsolete.time);
hualing chen03fd4942021-07-15 15:56:41 +0800913 dvr_playback_set_obsolete(ctx->playback.player, ctx->playback.obsolete.time);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800914 free(pseg);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800915 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800916 }
917 }
918
919 DVR_WRAPPER_DEBUG(1, "timeshift, remove playback(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, seg_info->id, error);
920
921 return error;
922}
923
924static int wrapper_removeRecordSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *seg_info)
925{
926 int error;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800927 DVR_WrapperRecordSegmentInfo_t *pseg, *pseg_tmp;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800928
hualing chen56c0a162022-01-27 17:01:50 +0800929 DVR_WRAPPER_DEBUG(1, "---timeshift, remove record(sn:%ld) segment(%lld) ...\n", ctx->sn, seg_info->info.id);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800930
931 /*if timeshifting, notify the playback first, then deal with record*/
932 if (ctx->record.param_open.is_timeshift) {
933 DVR_WrapperCtx_t *ctx_playback = ctx_getPlayback(sn_timeshift_playback);
934
935 if (ctx_playback) {
936 pthread_mutex_lock(&ctx_playback->lock);
hualing chen56c0a162022-01-27 17:01:50 +0800937 if (ctx_playback->current_segment_id == seg_info->info.id && ctx_playback->playback.speed == 100.0f) {
938 ctx_playback->playback.tf_full = DVR_TRUE;
939 DVR_WRAPPER_DEBUG(1, "timeshift, not remove record(sn:%ld) segment(%lld) .(%d) (%f).isplaying.\n", ctx->sn, seg_info->info.id, DVR_TRUE, ctx_playback->playback.speed);
940 pthread_mutex_unlock(&ctx_playback->lock);
941 return DVR_SUCCESS;
942 } else {
943 DVR_WRAPPER_DEBUG(1, "timeshift, start remove record(sn:%ld) segment(%lld) (%lld).(%f)..\n", ctx->sn, seg_info->info.id, ctx_playback->current_segment_id,ctx_playback->playback.speed);
944 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800945 if (ctx_valid(ctx_playback)
946 && ctx_playback->sn == sn_timeshift_playback
947 && !list_empty(&ctx_playback->segments)) {
948 error = wrapper_removePlaybackSegment(ctx_playback, &seg_info->info);
949 }
hualing chen56c0a162022-01-27 17:01:50 +0800950 ctx_playback->playback.tf_full = DVR_FALSE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800951 pthread_mutex_unlock(&ctx_playback->lock);
952 }
953 }
954
Zhiqiang Hanbc3019b2022-03-21 11:31:21 +0800955 uint64_t id = seg_info->info.id;
956
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800957 list_for_each_entry_safe_reverse(pseg, pseg_tmp, &ctx->segments, head) {
Zhiqiang Hanbc3019b2022-03-21 11:31:21 +0800958 if (pseg->info.id == id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +0800959 list_del(&pseg->head);
960
961 /*record the obsolete*/
962 ctx->record.obsolete.time += pseg->info.duration;
963 ctx->record.obsolete.size += pseg->info.size;
964 ctx->record.obsolete.pkts += pseg->info.nb_packets;
965
966 free(pseg);
967 break;
968 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800969 }
970
Zhiqiang Hanbc3019b2022-03-21 11:31:21 +0800971 error = dvr_segment_delete(ctx->record.param_open.location, id);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800972
Zhiqiang Hanbc3019b2022-03-21 11:31:21 +0800973 DVR_WRAPPER_DEBUG(1, "timeshift, remove record(sn:%ld) segment(%lld) =(%d)\n", ctx->sn, id, error);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800974
975 return error;
976}
977
978int dvr_wrapper_open_record (DVR_WrapperRecord_t *rec, DVR_WrapperRecordOpenParams_t *params)
979{
980 int error;
981 DVR_WrapperCtx_t *ctx;
982 DVR_RecordOpenParams_t open_param;
983
984 DVR_RETURN_IF_FALSE(rec);
985 DVR_RETURN_IF_FALSE(params);
986
987 /*get a free ctx*/
988 ctx = ctx_getRecord(0);
989 DVR_RETURN_IF_FALSE(ctx);
990
991 pthread_mutex_lock(&ctx->lock);
992
hualing chen51652f02020-12-29 16:59:31 +0800993 DVR_WRAPPER_DEBUG(1, "open record(dmx:%d) .istf(%d)..time (%ld)ms max size(%lld)byte seg size(%lld)byte\n",
994 params->dmx_dev_id, params->is_timeshift, params->max_time, params->max_size, params->segment_size);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +0800995
996 ctx_reset(ctx);
997
998 ctx->record.param_open = *params;
999 ctx->record.event_fn = params->event_fn;
1000 ctx->record.event_userdata = params->event_userdata;
1001 ctx->record.next_segment_id = 0;
1002 ctx->current_segment_id = 0;
1003 INIT_LIST_HEAD(&ctx->segments);
1004 ctx->sn = get_sn();
1005
1006 wrapper_requestThreadFor(ctx);
1007
hualing chen266b9502020-04-04 17:39:39 +08001008 memset(&open_param, 0, sizeof(DVR_RecordOpenParams_t));
Yahui Hance15e9c2020-12-08 18:08:32 +08001009 open_param.fend_dev_id = params->fend_dev_id;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001010 open_param.dmx_dev_id = params->dmx_dev_id;
1011 open_param.data_from_memory = 0;
1012 open_param.flags = params->flags;
Yahui Han15a00f12021-11-15 19:44:39 +08001013 if (params->flush_size) {
1014 open_param.notification_size = params->flush_size;
1015 } else {
1016 open_param.notification_size = 64*1024;
1017 }
hualing chen002e5b92022-02-23 17:51:21 +08001018 open_param.notification_time = 400;//ms
Zhiqiang Han31505452020-05-06 15:08:10 +08001019 open_param.flush_size = params->flush_size;
hualing chen03fd4942021-07-15 15:56:41 +08001020 open_param.ringbuf_size = params->ringbuf_size;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001021 open_param.event_fn = wrapper_record_event_handler;
1022 open_param.event_userdata = (void*)ctx->sn;
Yahui Han1fbf3292021-11-08 18:17:19 +08001023 if (params->keylen) {
1024 open_param.clearkey = params->clearkey;
1025 open_param.cleariv = params->cleariv;
1026 open_param.keylen = params->keylen;
1027 }
wentao.ma35a69d42022-03-10 18:08:40 +08001028 open_param.force_sysclock = params->force_sysclock;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001029
1030 error = dvr_record_open(&ctx->record.recorder, &open_param);
1031 if (error) {
1032 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) open fail(error:%d).\n", params->dmx_dev_id, error);
1033 ctx_reset(ctx);
1034 pthread_mutex_unlock(&ctx->lock);
1035 wrapper_releaseThreadForType(ctx->type);
1036 return DVR_FAILURE;
1037 }
1038 if (params->is_timeshift)
1039 sn_timeshift_record = ctx->sn;
1040
1041 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
1042
Yahui Han1fbf3292021-11-08 18:17:19 +08001043 if (params->crypto_fn) {
1044 error = dvr_record_set_encrypt_callback(ctx->record.recorder, params->crypto_fn, params->crypto_data);
1045 if (error) {
1046 DVR_WRAPPER_DEBUG(1, "record(dmx:%d) set encrypt callback fail(error:%d).\n", params->dmx_dev_id, error);
1047 }
hualing chen266b9502020-04-04 17:39:39 +08001048 }
1049
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001050 pthread_mutex_unlock(&ctx->lock);
1051
1052 *rec = (DVR_WrapperRecord_t)ctx->sn;
1053 return DVR_SUCCESS;
1054}
1055
1056int dvr_wrapper_close_record (DVR_WrapperRecord_t rec)
1057{
1058 DVR_WrapperCtx_t *ctx;
1059 DVR_RecordSegmentInfo_t seg_info;
1060 int error;
1061
1062 DVR_RETURN_IF_FALSE(rec);
1063
1064 ctx = ctx_getRecord((unsigned long)rec);
1065 DVR_RETURN_IF_FALSE(ctx);
1066
1067 pthread_mutex_lock(&ctx->lock);
1068 DVR_WRAPPER_DEBUG(1, "close record(sn:%ld)\n", ctx->sn);
1069 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1070
1071 memset(&seg_info, 0, sizeof(seg_info));
1072 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
1073
1074 error = dvr_record_close(ctx->record.recorder);
1075
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001076 if (ctx->record.param_open.is_timeshift)
1077 sn_timeshift_record = 0;
1078
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001079 ctx_freeSegments(ctx);
1080
1081 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) closed = (%d).\n", ctx->sn, error);
1082 ctx_reset(ctx);
1083 pthread_mutex_unlock(&ctx->lock);
1084
1085 wrapper_releaseThreadForType(ctx->type);
1086
1087 return error;
1088}
1089
1090int dvr_wrapper_start_record (DVR_WrapperRecord_t rec, DVR_WrapperRecordStartParams_t *params)
1091{
1092 DVR_WrapperCtx_t *ctx;
1093 DVR_RecordStartParams_t *start_param;
1094 int i;
1095 int error;
1096
1097 DVR_RETURN_IF_FALSE(rec);
1098 DVR_RETURN_IF_FALSE(params);
1099
1100 ctx = ctx_getRecord((unsigned long)rec);
1101 DVR_RETURN_IF_FALSE(ctx);
1102
1103 pthread_mutex_lock(&ctx->lock);
hualing chena5f03222021-12-02 11:22:35 +08001104 DVR_WRAPPER_DEBUG(1, "start record(sn:%ld, location:%s) save(%d)...\n", ctx->sn, ctx->record.param_open.location, params->save_rec_file);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001105 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1106
1107 start_param = &ctx->record.param_start;
1108 memset(start_param, 0, sizeof(*start_param));
1109 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
1110 start_param->segment.segment_id = ctx->record.next_segment_id++;
1111 start_param->segment.nb_pids = params->pids_info.nb_pids;
1112 for (i = 0; i < params->pids_info.nb_pids; i++) {
1113 start_param->segment.pids[i] = params->pids_info.pids[i];
1114 start_param->segment.pid_action[i] = DVR_RECORD_PID_CREATE;
1115 }
hualing chena5f03222021-12-02 11:22:35 +08001116 if (params->save_rec_file == 0)//default is not save
1117 dvr_segment_del_by_location(start_param->location);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001118 {
1119 /*sync to update for further use*/
1120 DVR_RecordStartParams_t *update_param;
1121 update_param = &ctx->record.param_update;
1122 memcpy(update_param, start_param, sizeof(*update_param));
1123 for (i = 0; i < update_param->segment.nb_pids; i++)
1124 update_param->segment.pid_action[i] = DVR_RECORD_PID_KEEP;
1125 }
1126
1127 error = dvr_record_start_segment(ctx->record.recorder, start_param);
1128 {
1129 DVR_RecordSegmentInfo_t new_seg_info =
1130 { .id = start_param->segment.segment_id, };
1131 wrapper_addRecordSegment(ctx, &new_seg_info);
1132 }
1133
1134 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) started = (%d)\n", ctx->sn, error);
1135
1136 pthread_mutex_unlock(&ctx->lock);
1137
1138 return error;
1139}
1140
1141int dvr_wrapper_stop_record (DVR_WrapperRecord_t rec)
1142{
1143 DVR_WrapperCtx_t *ctx;
1144 DVR_RecordSegmentInfo_t seg_info;
1145 int error;
1146
1147 DVR_RETURN_IF_FALSE(rec);
1148
1149 ctx = ctx_getRecord((unsigned long)rec);
1150 DVR_RETURN_IF_FALSE(ctx);
1151
1152 pthread_mutex_lock(&ctx->lock);
1153 DVR_WRAPPER_DEBUG(1, "stop record(sn:%ld) ...\n", ctx->sn);
1154 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1155
1156 memset(&seg_info, 0, sizeof(seg_info));
1157 error = dvr_record_stop_segment(ctx->record.recorder, &seg_info);
1158 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
1159
1160 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) stopped = (%d)\n", ctx->sn, error);
1161 pthread_mutex_unlock(&ctx->lock);
1162
1163 return error;
1164}
1165
hualing chen03fd4942021-07-15 15:56:41 +08001166int dvr_wrapper_pause_record (DVR_WrapperRecord_t rec)
1167{
1168 DVR_WrapperCtx_t *ctx;
1169 int error;
1170
1171 DVR_RETURN_IF_FALSE(rec);
1172
1173 ctx = ctx_getRecord((unsigned long)rec);
1174 DVR_RETURN_IF_FALSE(ctx);
1175
1176 pthread_mutex_lock(&ctx->lock);
1177 DVR_WRAPPER_DEBUG(1, "pause record(sn:%ld) ...\n", ctx->sn);
1178 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1179
1180 error = dvr_record_pause(ctx->record.recorder);
1181
1182 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) pauseed = (%d)\n", ctx->sn, error);
1183 pthread_mutex_unlock(&ctx->lock);
1184
1185 return error;
1186}
1187
1188int dvr_wrapper_resume_record (DVR_WrapperRecord_t rec)
1189{
1190 DVR_WrapperCtx_t *ctx;
1191 int error;
1192
1193 DVR_RETURN_IF_FALSE(rec);
1194
1195 ctx = ctx_getRecord((unsigned long)rec);
1196 DVR_RETURN_IF_FALSE(ctx);
1197
1198 pthread_mutex_lock(&ctx->lock);
1199 DVR_WRAPPER_DEBUG(1, "resume record(sn:%ld) ...\n", ctx->sn);
1200 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1201
1202 error = dvr_record_resume(ctx->record.recorder);
1203
1204 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) resumed = (%d)\n", ctx->sn, error);
1205 pthread_mutex_unlock(&ctx->lock);
1206
1207 return error;
1208}
1209
Wentao MAcdea4762022-04-26 13:28:56 +08001210/* Return true if arr1 contains all elements in arr2 */
1211static DVR_Bool_t pids_test_include( DVR_StreamPid_t* arr1, int size1,
1212 DVR_StreamPid_t* arr2, int size2)
wentao.maa69578c2022-04-07 09:27:39 +08001213{
Wentao MAcdea4762022-04-26 13:28:56 +08001214 DVR_Bool_t ret = DVR_TRUE;
1215 for (int i=0;i<size2;i++)
1216 { // iterate all elements in arr2 to check if they exist in arr1
1217 DVR_Bool_t found=DVR_FALSE;
1218 for (int j=0;j<size1;j++)
wentao.maa69578c2022-04-07 09:27:39 +08001219 {
Wentao MAcdea4762022-04-26 13:28:56 +08001220 if (arr2[i].pid == arr1[j].pid)
wentao.maa69578c2022-04-07 09:27:39 +08001221 {
1222 found=DVR_TRUE;
1223 break;
1224 }
1225 }
1226 if (found == DVR_FALSE)
1227 {
Wentao MAcdea4762022-04-26 13:28:56 +08001228 ret=DVR_FALSE;
wentao.maa69578c2022-04-07 09:27:39 +08001229 break;
1230 }
1231 }
Wentao MAcdea4762022-04-26 13:28:56 +08001232 return ret;
1233}
1234
1235static DVR_Bool_t pids_equal(const DVR_RecordSegmentStartParams_t* p1,
1236 const DVR_WrapperUpdatePidsParams_t* p2)
1237{
1238 int i=0;
1239 char buf[128]={0};
1240 int cnt=0;
1241 int chars=0;
1242
1243 DVR_RETURN_IF_FALSE(p1 != NULL && p2 != NULL);
1244 DVR_RETURN_IF_FALSE(p1->nb_pids>0 && p2->nb_pids>0);
1245
1246 DVR_Bool_t cond1 = pids_test_include(p1->pids,p1->nb_pids,p2->pids,p2->nb_pids);
1247 DVR_Bool_t cond2 = pids_test_include(p2->pids,p2->nb_pids,p1->pids,p1->nb_pids);
1248 DVR_Bool_t is_equal = (cond1 && cond2);
1249
1250 for (i=0;i<p1->nb_pids;i++)
1251 {
1252 chars = snprintf(buf+cnt,sizeof(buf)-cnt,"0x%hx,",p1->pids[i].pid);
1253 if (chars<0)
1254 {
1255 break;
1256 }
1257 cnt += chars;
1258 }
1259 dvr_log_print("%s nb_pids1:%d, pids1: %s",__func__,p1->nb_pids,buf);
1260 memset(buf,0,sizeof(buf));
1261
1262 for (i=0,cnt=0;i<p2->nb_pids;i++)
1263 {
1264 chars = snprintf(buf+cnt,sizeof(buf)-cnt,"0x%hx,",p2->pids[i].pid);
1265 if (chars<0)
1266 {
1267 break;
1268 }
1269 cnt += chars;
1270 }
1271 dvr_log_print("%s nb_pids2:%d, pids2: %s",__func__,p2->nb_pids,buf);
wentao.maa69578c2022-04-07 09:27:39 +08001272 dvr_log_print("%s is_equal:%d",__func__,is_equal);
1273 return is_equal;
1274}
1275
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001276int dvr_wrapper_update_record_pids (DVR_WrapperRecord_t rec, DVR_WrapperUpdatePidsParams_t *params)
1277{
1278 DVR_WrapperCtx_t *ctx;
1279 DVR_RecordStartParams_t *start_param;
wentao.maa69578c2022-04-07 09:27:39 +08001280 DVR_RecordSegmentInfo_t seg_info;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001281 int i;
1282 int error;
1283
1284 DVR_RETURN_IF_FALSE(rec);
1285 DVR_RETURN_IF_FALSE(params);
1286
1287 ctx = ctx_getRecord((unsigned long)rec);
1288 DVR_RETURN_IF_FALSE(ctx);
1289
1290 pthread_mutex_lock(&ctx->lock);
1291 DVR_WRAPPER_DEBUG(1, "update record(sn:%ld)\n", ctx->sn);
1292 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1293
1294 start_param = &ctx->record.param_update;
wentao.maa69578c2022-04-07 09:27:39 +08001295 if (pids_equal(&(start_param->segment),params))
1296 {
1297 pthread_mutex_unlock(&ctx->lock);
1298 return DVR_TRUE;
1299 }
1300
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001301 memset(start_param, 0, sizeof(*start_param));
1302 strncpy(start_param->location, ctx->record.param_open.location, sizeof(start_param->location));
1303 start_param->segment.segment_id = ctx->record.next_segment_id++;
1304 start_param->segment.nb_pids = params->nb_pids;
1305 for (i = 0; i < params->nb_pids; i++) {
1306 start_param->segment.pids[i] = params->pids[i];
1307 start_param->segment.pid_action[i] = params->pid_action[i];
1308 }
1309 error = dvr_record_next_segment(ctx->record.recorder, start_param, &seg_info);
1310 {
1311 DVR_RecordSegmentInfo_t new_seg_info =
1312 { .id = start_param->segment.segment_id, };
1313 wrapper_updateRecordSegment(ctx, &seg_info, U_PIDS);
1314 wrapper_addRecordSegment(ctx, &new_seg_info);
1315 }
1316
1317 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) updated = (%d)\n", ctx->sn, error);
1318 pthread_mutex_unlock(&ctx->lock);
1319
1320 return error;
1321}
1322
1323int dvr_wrapper_get_record_status(DVR_WrapperRecord_t rec, DVR_WrapperRecordStatus_t *status)
1324{
1325 DVR_WrapperCtx_t *ctx;
1326 DVR_WrapperRecordStatus_t s;
1327 int error;
1328
1329 DVR_RETURN_IF_FALSE(rec);
1330 DVR_RETURN_IF_FALSE(status);
1331
1332 ctx = ctx_getRecord((unsigned long)rec);
1333 DVR_RETURN_IF_FALSE(ctx);
1334
1335 pthread_mutex_lock(&ctx->lock);
1336
1337 DVR_WRAPPER_DEBUG(1, "get record(sn:%ld) status ...\n", ctx->sn);
1338 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1339
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001340 error = process_generateRecordStatus(ctx, &s);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001341
1342 DVR_WRAPPER_DEBUG(1, "record(sn:%ld) state/time/size/pkts(%d/%ld/%lld/%u) (%d)\n",
1343 ctx->sn,
1344 s.state,
1345 s.info.time,
1346 s.info.size,
1347 s.info.pkts,
1348 error);
1349
1350 *status = s;
1351
1352 pthread_mutex_unlock(&ctx->lock);
1353
1354 return error;
1355}
1356
hualing chen4fe3bee2020-10-23 13:58:52 +08001357int dvr_wrapper_record_is_secure_mode(DVR_WrapperRecord_t rec)
1358{
1359 DVR_WrapperCtx_t *ctx;
1360 int error;
1361
1362 DVR_RETURN_IF_FALSE(rec);
1363
1364 ctx = ctx_getRecord((unsigned long)rec);
1365 DVR_RETURN_IF_FALSE(ctx);
1366
1367 pthread_mutex_lock(&ctx->lock);
1368 error = dvr_record_is_secure_mode(ctx->record.recorder);
1369 pthread_mutex_unlock(&ctx->lock);
1370 return error;
1371}
1372
hualing chen266b9502020-04-04 17:39:39 +08001373int dvr_wrapper_set_record_secure_buffer (DVR_WrapperRecord_t rec, uint8_t *p_secure_buf, uint32_t len)
1374{
1375 DVR_WrapperCtx_t *ctx;
1376 int error;
1377
1378 DVR_RETURN_IF_FALSE(rec);
1379 DVR_RETURN_IF_FALSE(p_secure_buf);
1380
1381 ctx = ctx_getRecord((unsigned long)rec);
1382 DVR_RETURN_IF_FALSE(ctx);
1383
1384 pthread_mutex_lock(&ctx->lock);
1385 error = dvr_record_set_secure_buffer(ctx->record.recorder, p_secure_buf, len);
1386 pthread_mutex_unlock(&ctx->lock);
1387 return error;
1388}
1389
1390int dvr_wrapper_set_record_decrypt_callback (DVR_WrapperRecord_t rec, DVR_CryptoFunction_t func, void *userdata)
1391{
1392 DVR_WrapperCtx_t *ctx;
1393 int error;
1394
1395 DVR_RETURN_IF_FALSE(rec);
1396 DVR_RETURN_IF_FALSE(func);
1397
1398 ctx = ctx_getRecord((unsigned long)rec);
1399 DVR_RETURN_IF_FALSE(ctx);
1400
1401 pthread_mutex_lock(&ctx->lock);
1402 error = dvr_record_set_encrypt_callback(ctx->record.recorder, func, userdata);
1403 pthread_mutex_unlock(&ctx->lock);
1404 return error;
1405}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001406
1407
1408int dvr_wrapper_open_playback (DVR_WrapperPlayback_t *playback, DVR_WrapperPlaybackOpenParams_t *params)
1409{
1410 DVR_WrapperCtx_t *ctx;
1411 DVR_PlaybackOpenParams_t open_param;
1412 int error;
1413
1414 DVR_RETURN_IF_FALSE(playback);
1415 DVR_RETURN_IF_FALSE(params);
1416 DVR_RETURN_IF_FALSE(params->playback_handle);
1417
1418 /*get a free ctx*/
1419 ctx = ctx_getPlayback(0);
1420 DVR_RETURN_IF_FALSE(ctx);
1421
1422 pthread_mutex_lock(&ctx->lock);
1423
hualing chena5f03222021-12-02 11:22:35 +08001424 DVR_WRAPPER_DEBUG(1, "open playback(dmx:%d) ..vendor[%d]params->block_size[%d].\n", params->dmx_dev_id, params->vendor, params->block_size);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001425
1426 ctx_reset(ctx);
1427
1428 ctx->playback.param_open = *params;
1429 ctx->playback.event_fn = params->event_fn;
1430 ctx->playback.event_userdata = params->event_userdata;
1431 ctx->current_segment_id = 0;
1432 INIT_LIST_HEAD(&ctx->segments);
1433 ctx->sn = get_sn();
1434
1435 wrapper_requestThreadFor(ctx);
1436
hualing chen266b9502020-04-04 17:39:39 +08001437 memset(&open_param, 0, sizeof(DVR_PlaybackOpenParams_t));
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001438 open_param.dmx_dev_id = params->dmx_dev_id;
1439 open_param.block_size = params->block_size;
1440 open_param.is_timeshift = params->is_timeshift;
1441 //open_param.notification_size = 10*1024; //not supported
1442 open_param.event_fn = wrapper_playback_event_handler;
1443 open_param.event_userdata = (void*)ctx->sn;
1444 /*open_param.has_pids = 0;*/
hualing chene3797f02021-01-13 14:53:28 +08001445 open_param.is_notify_time = params->is_notify_time;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001446 open_param.player_handle = (am_tsplayer_handle)params->playback_handle;
hualing chen90b3ae62021-03-30 10:49:28 +08001447 open_param.vendor = params->vendor;
1448
Yahui Han1fbf3292021-11-08 18:17:19 +08001449 if (params->keylen) {
1450 open_param.clearkey = params->clearkey;
1451 open_param.cleariv = params->cleariv;
1452 open_param.keylen = params->keylen;
1453 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001454
1455 error = dvr_playback_open(&ctx->playback.player, &open_param);
1456 if (error) {
1457 DVR_WRAPPER_DEBUG(1, "playback(dmx:%d) openned fail(error:%d).\n", params->dmx_dev_id, error);
1458 ctx_reset(ctx);
1459 pthread_mutex_unlock(&ctx->lock);
1460 wrapper_releaseThreadForType(ctx->type);
1461 return DVR_FAILURE;
1462 }
1463 if (params->is_timeshift)
1464 sn_timeshift_playback = ctx->sn;
1465
hualing chen266b9502020-04-04 17:39:39 +08001466 DVR_WRAPPER_DEBUG(1, "hanyh: playback(dmx:%d) openned ok(sn:%ld).\n", params->dmx_dev_id, ctx->sn);
1467 error = dvr_playback_set_decrypt_callback(ctx->playback.player, params->crypto_fn, params->crypto_data);
1468 if (error) {
1469 DVR_WRAPPER_DEBUG(1, "playback set deccrypt callback fail(error:%d).\n", error);
1470 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001471 pthread_mutex_unlock(&ctx->lock);
1472
1473 *playback = (DVR_WrapperPlayback_t)ctx->sn;
1474 return DVR_SUCCESS;
1475}
1476
1477int dvr_wrapper_close_playback (DVR_WrapperPlayback_t playback)
1478{
1479 DVR_WrapperCtx_t *ctx;
1480 int error;
1481
1482 DVR_RETURN_IF_FALSE(playback);
1483
1484 ctx = ctx_getPlayback((unsigned long)playback);
1485 DVR_RETURN_IF_FALSE(ctx);
1486
1487 pthread_mutex_lock(&ctx->lock);
1488 DVR_WRAPPER_DEBUG(1, "close playback(sn:%ld)\n", ctx->sn);
1489 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1490
1491 if (ctx->playback.param_open.is_timeshift)
1492 sn_timeshift_playback = 0;
1493
1494 /*try stop first*/
1495 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1496
1497 {
1498 /*remove all segments*/
1499 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1500
1501 list_for_each_entry(pseg, &ctx->segments, head) {
1502 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1503 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1504 ctx->sn, pseg->playback_info.segment_id, error);
1505 }
1506 ctx_freeSegments(ctx);
1507 }
1508
1509 error = dvr_playback_close(ctx->playback.player);
1510
1511 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) closed.\n", ctx->sn);
1512 ctx_reset(ctx);
1513 pthread_mutex_unlock(&ctx->lock);
1514
1515 wrapper_releaseThreadForType(ctx->type);
1516
1517 return error;
1518}
1519
1520int dvr_wrapper_start_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackFlag_t flags, DVR_PlaybackPids_t *p_pids)
1521{
1522 DVR_WrapperCtx_t *ctx;
Wentao MA9aa0aa02021-12-23 18:30:17 +08001523 int error=0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001524 uint64_t *p_segment_ids;
1525 uint32_t segment_nb;
1526 uint32_t i;
1527 DVR_RecordSegmentInfo_t seg_info_1st;
Wentao MA9aa0aa02021-12-23 18:30:17 +08001528 int got_1st_seg=0;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001529 DVR_WrapperCtx_t *ctx_record;/*for timeshift*/
hualing chenc110f952021-01-18 11:25:37 +08001530 DVR_Bool_t is_timeshift = DVR_FALSE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001531
1532 DVR_RETURN_IF_FALSE(playback);
1533 DVR_RETURN_IF_FALSE(p_pids);
1534
hualing chenc110f952021-01-18 11:25:37 +08001535 ctx_record = NULL;
1536
1537 /*lock the recorder to avoid changing the recording segments*/
1538 ctx_record = ctx_getRecord(sn_timeshift_record);
1539
1540 if (ctx_record) {
1541 pthread_mutex_lock(&ctx_record->lock);
1542 if (!ctx_valid(ctx_record)
1543 || ctx_record->sn != sn_timeshift_record) {
1544 DVR_WRAPPER_DEBUG(1, "timeshift, record is not for timeshifting, FATAL error found\n");
1545 pthread_mutex_unlock(&ctx_record->lock);
1546 is_timeshift = DVR_FALSE;
1547 } else {
1548 is_timeshift = DVR_TRUE;
1549 }
1550 }
1551
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001552 ctx = ctx_getPlayback((unsigned long)playback);
1553 DVR_RETURN_IF_FALSE(ctx);
1554
1555 pthread_mutex_lock(&ctx->lock);
1556
1557 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",
1558 ctx->sn,
1559 ctx->playback.param_open.location,
1560 flags,
1561 p_pids->video.pid, p_pids->video.format,
1562 p_pids->audio.pid, p_pids->audio.format,
1563 p_pids->ad.pid, p_pids->ad.format,
1564 p_pids->subtitle.pid, p_pids->subtitle.format,
1565 p_pids->pcr.pid);
1566
1567 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1568
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001569 if (ctx->playback.param_open.is_timeshift) {
1570 /*lock the recorder to avoid changing the recording segments*/
hualing chenc110f952021-01-18 11:25:37 +08001571 if (is_timeshift == DVR_FALSE) {
1572 DVR_WRAPPER_DEBUG(1, "timeshift, record is not for timeshifting, FATAL error return\n");
1573 pthread_mutex_unlock(&ctx->lock);
1574 return DVR_FAILURE;
1575 } else {
1576 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) record(sn:%ld) locked ok due to timeshift\n",
1577 ctx->sn, ctx_record->sn);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001578 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001579 }
1580
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001581 /*obtain all segments in a list*/
1582 segment_nb = 0;
1583 p_segment_ids = NULL;
1584 error = dvr_segment_get_list(ctx->playback.param_open.location, &segment_nb, &p_segment_ids);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001585 if (!error) {
1586 got_1st_seg = 0;
hualing chenb9a02922021-12-14 11:29:47 +08001587 struct list_head info_list; /**< segment list head*/
1588 INIT_LIST_HEAD(&info_list);
1589
hualing chenb9b358a2021-08-17 15:06:36 +08001590 DVR_WRAPPER_DEBUG(1, "get list segment_nb::%d",segment_nb);
hualing chenb9a02922021-12-14 11:29:47 +08001591 //we need free info list buf when we used end.
1592 error = dvr_segment_get_allInfo(ctx->playback.param_open.location, &info_list);
hualing chen926a8ec2021-12-20 20:38:24 +08001593 if (error == DVR_FAILURE) {
hualing chenb9a02922021-12-14 11:29:47 +08001594 error = DVR_FAILURE;
1595 DVR_WRAPPER_DEBUG(1, "fail to get all seg info (location:%s, seg:%llu), (error:%d)\n",
1596 ctx->playback.param_open.location, p_segment_ids[i], error);
1597 for (i = 0; i < segment_nb; i++) {
1598 DVR_RecordSegmentInfo_t seg_info;
1599 DVR_PlaybackSegmentFlag_t flags;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001600
hualing chenb9a02922021-12-14 11:29:47 +08001601 error = dvr_segment_get_info(ctx->playback.param_open.location, p_segment_ids[i], &seg_info);
1602 if (error) {
1603 error = DVR_FAILURE;
1604 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
1605 ctx->playback.param_open.location, p_segment_ids[i], error);
1606 break;
1607 }
1608 //add check if has audio or video pid. if not exist. not add segment to playback
1609 int ii = 0;
1610 int has_av = 0;
1611 for (ii = 0; ii < seg_info.nb_pids; ii++) {
1612 int type = (seg_info.pids[ii].type >> 24) & 0x0f;
1613 if (type == DVR_STREAM_TYPE_VIDEO ||
1614 type == DVR_STREAM_TYPE_AUDIO ||
1615 type == DVR_STREAM_TYPE_AD) {
1616 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1617 DVR_WRAPPER_DEBUG(1, "success to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info.pids[ii].type >> 24)&0x0f,seg_info.pids[ii].pid,
1618 DVR_STREAM_TYPE_VIDEO,
1619 DVR_STREAM_TYPE_AUDIO,
1620 DVR_STREAM_TYPE_AD);
1621 has_av = 1;
1622 //break;
1623 } else {
1624 DVR_WRAPPER_DEBUG(1, "error to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info.pids[ii].type >> 24)&0x0f,seg_info.pids[ii].pid,
1625 DVR_STREAM_TYPE_VIDEO,
1626 DVR_STREAM_TYPE_AUDIO,
1627 DVR_STREAM_TYPE_AD);
1628 }
1629 }
1630 if (has_av == 0) {
1631 DVR_WRAPPER_DEBUG(1, "fail to get seg av info \n");
1632 continue;
1633 } else {
1634 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1635 }
1636 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1637 error = wrapper_addPlaybackSegment(ctx, &seg_info, p_pids, flags);
1638 if (error)
1639 break;
1640 /*copy the 1st segment*/
1641 if (got_1st_seg == 0) {
1642 seg_info_1st = seg_info;
1643 got_1st_seg = 1;
1644 }
1645 }
1646 } else {
1647 for (i = 0; i < segment_nb; i++) {
1648 DVR_RecordSegmentInfo_t *seg_info;
1649 DVR_PlaybackSegmentFlag_t flags;
1650 int found = 0;
1651 list_for_each_entry(seg_info, &info_list, head)
1652 {
hualing chen8aed9582021-12-24 17:59:56 +08001653 if (seg_info->id == p_segment_ids[i]) {
hualing chenb9a02922021-12-14 11:29:47 +08001654 found = 1;
1655 DVR_WRAPPER_DEBUG(1, "get segment info::%d", i);
1656 break;
1657 }
1658 }
1659 if (!found) {
hualing chen8aed9582021-12-24 17:59:56 +08001660 //last info is not found if when recording occured power off.
1661 if (p_segment_ids[i] == segment_nb - 1) {
1662 DVR_RecordSegmentInfo_t seg_info;
1663 DVR_PlaybackSegmentFlag_t flags;
1664
1665 error = dvr_segment_get_info(ctx->playback.param_open.location, p_segment_ids[i], &seg_info);
1666 if (error) {
1667 error = DVR_FAILURE;
1668 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
1669 ctx->playback.param_open.location, p_segment_ids[i], error);
1670 break;
1671 }
1672 //
1673 //add check if has audio or video pid. if not exist. not add segment to playback
1674 int ii = 0;
1675 int has_av = 0;
1676 for (ii = 0; ii < seg_info.nb_pids; ii++) {
1677 int type = (seg_info.pids[ii].type >> 24) & 0x0f;
1678 if (type == DVR_STREAM_TYPE_VIDEO ||
1679 type == DVR_STREAM_TYPE_AUDIO ||
1680 type == DVR_STREAM_TYPE_AD) {
1681 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1682 DVR_WRAPPER_DEBUG(1, "success to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info.pids[ii].type >> 24)&0x0f,seg_info.pids[ii].pid,
1683 DVR_STREAM_TYPE_VIDEO,
1684 DVR_STREAM_TYPE_AUDIO,
1685 DVR_STREAM_TYPE_AD);
1686 has_av = 1;
1687 //break;
1688 } else {
1689 DVR_WRAPPER_DEBUG(1, "error to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info.pids[ii].type >> 24)&0x0f,seg_info.pids[ii].pid,
1690 DVR_STREAM_TYPE_VIDEO,
1691 DVR_STREAM_TYPE_AUDIO,
1692 DVR_STREAM_TYPE_AD);
1693 }
1694 }
1695 if (has_av == 0) {
1696 DVR_WRAPPER_DEBUG(1, "fail to get seg av info \n");
1697 continue;
1698 } else {
1699 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1700 }
1701 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1702 error = wrapper_addPlaybackSegment(ctx, &seg_info, p_pids, flags);
1703 if (error)
1704 break;
1705 }
hualing chenb9a02922021-12-14 11:29:47 +08001706 continue;
1707 }
1708
1709 //add check if has audio or video pid. if not exist. not add segment to playback
1710 int ii = 0;
1711 int has_av = 0;
1712 for (ii = 0; ii < seg_info->nb_pids; ii++) {
1713 int type = (seg_info->pids[ii].type >> 24) & 0x0f;
1714 if (type == DVR_STREAM_TYPE_VIDEO ||
1715 type == DVR_STREAM_TYPE_AUDIO ||
1716 type == DVR_STREAM_TYPE_AD) {
1717 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1718 DVR_WRAPPER_DEBUG(1, "success to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info->pids[ii].type >> 24)&0x0f,seg_info->pids[ii].pid,
1719 DVR_STREAM_TYPE_VIDEO,
1720 DVR_STREAM_TYPE_AUDIO,
1721 DVR_STREAM_TYPE_AD);
1722 has_av = 1;
1723 //break;
1724 } else {
1725 DVR_WRAPPER_DEBUG(1, "error to get seg av info type[0x%x][%d] [%d][%d][%d]\n",(seg_info->pids[ii].type >> 24)&0x0f,seg_info->pids[ii].pid,
1726 DVR_STREAM_TYPE_VIDEO,
1727 DVR_STREAM_TYPE_AUDIO,
1728 DVR_STREAM_TYPE_AD);
1729 }
1730 }
1731 if (has_av == 0) {
1732 DVR_WRAPPER_DEBUG(1, "fail to get seg av info \n");
1733 continue;
1734 } else {
1735 DVR_WRAPPER_DEBUG(1, "success to get seg av info \n");
1736 }
1737 flags = DVR_PLAYBACK_SEGMENT_DISPLAYABLE | DVR_PLAYBACK_SEGMENT_CONTINUOUS;
1738 error = wrapper_addPlaybackSegment(ctx, seg_info, p_pids, flags);
1739 if (error)
1740 break;
1741
1742 /*copy the 1st segment*/
1743 if (got_1st_seg == 0) {
1744 seg_info_1st = *seg_info;
1745 got_1st_seg = 1;
1746 }
hualing chen92f3a142020-07-08 20:59:33 +08001747 }
hualing chenb9a02922021-12-14 11:29:47 +08001748 //free list
1749 DVR_RecordSegmentInfo_t *segment = NULL;
1750 DVR_RecordSegmentInfo_t *segment_tmp = NULL;
1751 list_for_each_entry_safe(segment, segment_tmp, &info_list, head)
1752 {
1753 if (segment) {
1754 list_del(&segment->head);
1755 free(segment);
1756 }
1757 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001758 }
hualing chenb9a02922021-12-14 11:29:47 +08001759
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001760 free(p_segment_ids);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001761
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001762 /* return if no segment or fail to add */
1763 if (!error && got_1st_seg) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001764
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001765 /*copy the obsolete infomation, must for timeshifting*/
1766 if (ctx->playback.param_open.is_timeshift && ctx_record) {
1767 ctx->playback.obsolete = ctx_record->record.obsolete;
1768 }
1769
1770 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) (%d) segments added\n", ctx->sn, i);
1771
1772 ctx->playback.reach_end = DVR_FALSE;
1773 if ((flags&DVR_PLAYBACK_STARTED_PAUSEDLIVE) == DVR_PLAYBACK_STARTED_PAUSEDLIVE)
1774 ctx->playback.speed = 0.0f;
1775 else
1776 ctx->playback.speed = 100.0f;
1777
1778 ctx->playback.pids_req = *p_pids;
hualing chen03fd4942021-07-15 15:56:41 +08001779 //calualte segment id and pos
1780 if (dvr_playback_check_limit(ctx->playback.player)) {
1781 pthread_mutex_unlock(&ctx->lock);
1782 dvr_wrapper_seek_playback(playback, 0);
1783 pthread_mutex_lock(&ctx->lock);
1784 error = dvr_playback_start(ctx->playback.player, flags);
1785 } else {
1786 error = dvr_playback_seek(ctx->playback.player, seg_info_1st.id, 0);
1787 error = dvr_playback_start(ctx->playback.player, flags);
1788 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seek(seg:%llu 0) for start (%d)\n",
1789 ctx->sn, seg_info_1st.id, error);
1790 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001791 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) started (%d)\n", ctx->sn, error);
hualing chen451c8f72022-03-09 13:05:52 +08001792 } else {
1793 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) started (%d)got_1st_seg:%d\n", ctx->sn, error, got_1st_seg);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001794 }
1795 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001796
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08001797 if (ctx->playback.param_open.is_timeshift) {
1798 /*unlock the recorder locked above*/
1799 if (ctx_record && ctx_valid(ctx_record)) {
1800 pthread_mutex_unlock(&ctx_record->lock);
1801 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld), record(sn:%ld) unlocked ok due to timeshift\n",
1802 ctx->sn, ctx_record->sn);
1803 }
1804 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001805 pthread_mutex_unlock(&ctx->lock);
1806
1807 return error;
1808}
hualing chen002e5b92022-02-23 17:51:21 +08001809//stop record and playback
1810int dvr_wrapper_stop_timeshift (DVR_WrapperPlayback_t playback)
1811{
1812 DVR_WrapperCtx_t *ctx_record = NULL;/*for timeshift*/
1813 int error;
1814 DVR_WRAPPER_DEBUG(1, "stop timeshift record\n");
1815
1816 //stop timeshift record
1817 ctx_record = ctx_getRecord(sn_timeshift_record);
1818 error = dvr_wrapper_stop_record((DVR_WrapperRecord_t)sn_timeshift_record);
1819
1820 DVR_WRAPPER_DEBUG(1, "stop timeshift ...stop play\n");
1821 //stop play
1822 error = dvr_wrapper_stop_playback(playback);
1823 //del timeshift file
1824 if (ctx_record != NULL) {
1825 DVR_WRAPPER_DEBUG(1, "del timeshift(sn:%ld) ...3\n", ctx_record->sn);
1826 error = dvr_segment_del_by_location(ctx_record->record.param_open.location);
1827 }
1828 return error;
1829}
1830//start record and start playback
1831int dvr_wrapper_restart_timeshift(DVR_WrapperPlayback_t playback, DVR_PlaybackFlag_t flags, DVR_PlaybackPids_t *p_pids)
1832{
1833 DVR_WrapperCtx_t *ctx;
1834 DVR_RecordStartParams_t *start_param;
1835 int error;
1836
1837 ctx = ctx_getRecord((unsigned long)sn_timeshift_record);
1838 DVR_RETURN_IF_FALSE(ctx);
1839
1840 pthread_mutex_lock(&ctx->lock);
1841 DVR_WRAPPER_DEBUG(1, "restart record(sn:%ld, location:%s)...\n", ctx->sn, ctx->record.param_open.location);
1842 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1843
hualing chen451c8f72022-03-09 13:05:52 +08001844 {
1845 //clear old record status
1846 // struct {
1847 // DVR_WrapperRecordOpenParams_t param_open;
1848 // DVR_RecordStartParams_t param_start;
1849 // DVR_RecordStartParams_t param_update;
1850 // DVR_RecordHandle_t recorder;
1851 // DVR_RecordEventFunction_t event_fn;
1852 // void *event_userdata;
1853
1854 // /*total status = seg_status + status + obsolete*/
1855 // DVR_RecordStatus_t seg_status; /**<status of current segment*/
1856 // DVR_WrapperRecordStatus_t status; /**<status of remaining segments*/
1857 // uint64_t next_segment_id;
1858
1859 // DVR_WrapperInfo_t obsolete; /**<data obsolete due to the max limit*/
1860 // } record;
1861 memset(&(ctx->record.seg_status), 0, sizeof(DVR_RecordStatus_t));
1862 memset(&(ctx->record.status), 0, sizeof(DVR_WrapperRecordStatus_t));
1863 memset(&(ctx->record.obsolete), 0, sizeof(DVR_WrapperInfo_t));
1864 }
1865
hualing chen002e5b92022-02-23 17:51:21 +08001866 start_param = &ctx->record.param_start;
1867
1868 error = dvr_record_start_segment(ctx->record.recorder, start_param);
1869 {
1870 DVR_RecordSegmentInfo_t new_seg_info =
1871 { .id = start_param->segment.segment_id, };
1872 wrapper_addRecordSegment(ctx, &new_seg_info);
hualing chen451c8f72022-03-09 13:05:52 +08001873 DVR_WRAPPER_DEBUG(1, "re record(sn:%ld) started = (%d)start id[%lld]id+[%lld]update id[%lld]\n", ctx->sn, error, start_param->segment.segment_id, ctx->record.next_segment_id, ctx->record.param_update.segment.segment_id);
1874 ctx->record.next_segment_id = start_param->segment.segment_id + 1;
1875 DVR_RecordStartParams_t *update_param;
1876 update_param = &ctx->record.param_update;
1877 memcpy(update_param, start_param, sizeof(*update_param));
1878 int i = 0;
1879 for (i = 0; i < update_param->segment.nb_pids; i++)
1880 update_param->segment.pid_action[i] = DVR_RECORD_PID_KEEP;
hualing chen002e5b92022-02-23 17:51:21 +08001881 }
1882
1883 DVR_WRAPPER_DEBUG(1, "re record(sn:%ld) started = (%d)\n", ctx->sn, error);
1884
1885 pthread_mutex_unlock(&ctx->lock);
1886
1887 //start play
hualing chen451c8f72022-03-09 13:05:52 +08001888 DVR_WRAPPER_DEBUG(1, "re start play and clear old status\n");
1889 //clear play statue
1890 ctx = ctx_getPlayback((unsigned long)playback);
1891 if (ctx) {
1892 //clear old playback status
1893 // struct {
1894 // DVR_WrapperPlaybackOpenParams_t param_open;
1895 // DVR_PlaybackHandle_t player;
1896 // DVR_PlaybackEventFunction_t event_fn;
1897 // void *event_userdata;
1898
1899 // /*total status = seg_status + status*/
1900 // DVR_PlaybackStatus_t seg_status;
1901 // DVR_WrapperPlaybackStatus_t status;
1902 // DVR_PlaybackPids_t pids_req;
1903 // DVR_PlaybackEvent_t last_event;
1904 // float speed;
1905 // DVR_Bool_t reach_end;
1906
1907 // DVR_WrapperInfo_t obsolete;
1908 // DVR_Bool_t tf_full;
1909 // } playback;
1910 ctx->playback.tf_full == DVR_FALSE;
1911 ctx->playback.reach_end == DVR_FALSE;
1912 memset(&(ctx->playback.last_event), 0, sizeof(DVR_PlaybackEvent_t));
1913 memset(&(ctx->playback.seg_status), 0, sizeof(DVR_PlaybackStatus_t));
1914 memset(&(ctx->playback.status), 0, sizeof(DVR_WrapperPlaybackStatus_t));
1915 memset(&(ctx->playback.obsolete), 0, sizeof(DVR_WrapperInfo_t));
1916 }
hualing chen002e5b92022-02-23 17:51:21 +08001917 error = dvr_wrapper_start_playback(playback, flags, p_pids);
1918 return error;
1919}
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001920
1921int dvr_wrapper_stop_playback (DVR_WrapperPlayback_t playback)
1922{
1923 DVR_WrapperCtx_t *ctx;
1924 int error;
1925
1926 DVR_RETURN_IF_FALSE(playback);
1927
1928 ctx = ctx_getPlayback((unsigned long)playback);
1929 DVR_RETURN_IF_FALSE(ctx);
1930
1931 pthread_mutex_lock(&ctx->lock);
1932 DVR_WRAPPER_DEBUG(1, "stop playback(sn:%ld) ...\n", ctx->sn);
1933 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
1934
1935 error = dvr_playback_stop(ctx->playback.player, DVR_TRUE);
1936
1937 {
1938 /*remove all segments*/
1939 DVR_WrapperPlaybackSegmentInfo_t *pseg;
1940
1941 list_for_each_entry(pseg, &ctx->segments, head) {
1942 error = dvr_playback_remove_segment(ctx->playback.player, pseg->playback_info.segment_id);
1943 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) remove seg(%lld) (%d)\n",
1944 ctx->sn, pseg->playback_info.segment_id, error);
1945 }
1946 ctx_freeSegments(ctx);
1947 }
1948
1949 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) stopped (%d)\n", ctx->sn, error);
1950 pthread_mutex_unlock(&ctx->lock);
1951
1952 return error;
1953}
1954
1955int dvr_wrapper_pause_playback (DVR_WrapperPlayback_t playback)
1956{
1957 DVR_WrapperCtx_t *ctx;
1958 int error;
1959
1960 DVR_RETURN_IF_FALSE(playback);
1961
1962 ctx = ctx_getPlayback((unsigned long)playback);
1963 DVR_RETURN_IF_FALSE(ctx);
1964
1965 pthread_mutex_lock(&ctx->lock);
1966 DVR_WRAPPER_DEBUG(1, "pause playback(sn:%ld) ...\n", ctx->sn);
1967 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
hualing chen36e0dfd2020-05-02 16:33:06 +08001968 //clear end event
Zhiqiang Hanb723cdb2020-05-09 11:10:29 +08001969 if (ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_END)
hualing chen36e0dfd2020-05-02 16:33:06 +08001970 ctx->playback.last_event = DVR_PLAYBACK_EVENT_TRANSITION_OK;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001971
1972 error = dvr_playback_pause(ctx->playback.player, DVR_FALSE);
1973
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08001974 ctx->playback.speed = 0.0f;
1975
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08001976 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) paused (%d)\n", ctx->sn, error);
1977 pthread_mutex_unlock(&ctx->lock);
1978
1979 return error;
1980}
1981
1982int dvr_wrapper_resume_playback (DVR_WrapperPlayback_t playback)
1983{
1984 DVR_WrapperCtx_t *ctx;
1985 int error;
1986
1987 DVR_RETURN_IF_FALSE(playback);
1988
1989 ctx = ctx_getPlayback((unsigned long)playback);
1990 DVR_RETURN_IF_FALSE(ctx);
hualing chen03fd4942021-07-15 15:56:41 +08001991 //if set limit.we need check if seek to valid data when resume
1992 uint32_t time_offset = ctx->playback.status.info_cur.time + ctx->playback.status.info_obsolete.time;
1993 if (dvr_playback_check_limit(ctx->playback.player)) {
1994 int expired = dvr_playback_calculate_expiredlen(ctx->playback.player);
1995 if (expired > time_offset) {
1996 DVR_WRAPPER_DEBUG(1, "seek before resume reset offset playback(sn:%ld) (off:%d expired:%d)\n",
1997 ctx->sn, time_offset, expired);
1998 time_offset = expired;
1999 dvr_wrapper_seek_playback(playback, time_offset);
2000 }
2001 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002002 pthread_mutex_lock(&ctx->lock);
2003 DVR_WRAPPER_DEBUG(1, "resume playback(sn:%ld) ...\n", ctx->sn);
2004 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
2005
2006 error = dvr_playback_resume(ctx->playback.player);
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08002007 ctx->playback.speed = 100.0f;
2008
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002009 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) resumed (%d)\n", ctx->sn, error);
2010 pthread_mutex_unlock(&ctx->lock);
2011
2012 return error;
2013}
2014
2015int dvr_wrapper_set_playback_speed (DVR_WrapperPlayback_t playback, float speed)
2016{
2017 DVR_WrapperCtx_t *ctx;
2018 int error;
2019 DVR_PlaybackSpeed_t dvr_speed = {
2020 .speed = { speed },
2021 .mode = (speed > 0) ? DVR_PLAYBACK_FAST_FORWARD : DVR_PLAYBACK_FAST_BACKWARD
2022 };
2023
2024 DVR_RETURN_IF_FALSE(playback);
2025
2026 ctx = ctx_getPlayback((unsigned long)playback);
2027 DVR_RETURN_IF_FALSE(ctx);
2028
2029 pthread_mutex_lock(&ctx->lock);
hualing chenc70a8df2020-05-12 19:23:11 +08002030 DVR_WRAPPER_DEBUG(1, "speed playback(sn:%ld) (x%f) .(x%f)..\n", ctx->sn, speed, ctx->playback.speed);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002031 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
2032
2033 error = dvr_playback_set_speed(ctx->playback.player, dvr_speed);
2034
Zhiqiang Han3eb75f92020-04-08 10:07:55 +08002035 if (ctx->playback.speed != 0.0f && ctx->playback.speed != 100.0f
2036 && ctx->playback.last_event == DVR_PLAYBACK_EVENT_REACHED_BEGIN
2037 && ctx->playback.seg_status.state == DVR_PLAYBACK_STATE_PAUSE) {
2038 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, paused, do resume first\n", ctx->playback.speed, speed);
2039 error = dvr_playback_resume(ctx->playback.player);
2040 } else if (ctx->playback.speed == 0.0f
2041 && speed != 0.0f
2042 && speed != 100.0f) {
2043 /*libdvr do not support pause with speed=0, will not be here*/
2044 DVR_WRAPPER_DEBUG(1, "x%f -> x%f, do resume first\n", ctx->playback.speed, speed);
2045 error = dvr_playback_resume(ctx->playback.player);
2046 }
2047
2048 ctx->playback.speed = speed;
2049
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002050 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) speeded(x%f) (%d)\n",
2051 ctx->sn, speed, error);
2052 pthread_mutex_unlock(&ctx->lock);
2053
2054 return error;
2055}
2056
hualing chen03fd4942021-07-15 15:56:41 +08002057int dvr_wrapper_setlimit_playback (DVR_WrapperPlayback_t playback, uint64_t time, int32_t limit)
2058{
2059 DVR_WrapperCtx_t *ctx;
2060 int error;
2061
2062 DVR_RETURN_IF_FALSE(playback);
2063
2064 ctx = ctx_getPlayback((unsigned long)playback);
2065 DVR_RETURN_IF_FALSE(ctx);
2066
2067 pthread_mutex_lock(&ctx->lock);
2068
2069 DVR_WRAPPER_DEBUG(1, "setlimit playback(sn:%ld) (time:%lld limit:%d) ...\n", ctx->sn, time, limit);
2070 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
2071
2072 error = dvr_playback_setlimit(ctx->playback.player, time, limit);
2073 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) setlimit(time:%lld limit:%d) ...\n", ctx->sn, time, limit);
2074
2075 pthread_mutex_unlock(&ctx->lock);
2076
2077 return error;
2078}
2079
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002080int dvr_wrapper_seek_playback (DVR_WrapperPlayback_t playback, uint32_t time_offset)
2081{
2082 DVR_WrapperCtx_t *ctx;
2083 int error;
2084 DVR_WrapperPlaybackSegmentInfo_t *pseg;
2085 uint64_t segment_id;
2086 uint32_t off;
2087 uint64_t last_segment_id;
2088 uint32_t pre_off;
2089
2090 DVR_RETURN_IF_FALSE(playback);
2091
2092 ctx = ctx_getPlayback((unsigned long)playback);
2093 DVR_RETURN_IF_FALSE(ctx);
2094
2095 pthread_mutex_lock(&ctx->lock);
2096
2097 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (off:%d) ...\n", ctx->sn, time_offset);
2098 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
2099
2100 off = 0;
2101 segment_id = 0;
2102 pre_off = 0;
2103 last_segment_id = 0;
2104
hualing chen03fd4942021-07-15 15:56:41 +08002105 //if set limit info we need check ts data is
2106 //expired when seek
2107 if (dvr_playback_check_limit(ctx->playback.player)) {
2108 int expired = dvr_playback_calculate_expiredlen(ctx->playback.player);
2109 if (expired > time_offset) {
2110 DVR_WRAPPER_DEBUG(1, "seek reset offset playback(sn:%ld) (off:%d expired:%d)\n",
2111 ctx->sn, time_offset, expired);
2112 time_offset = expired;
2113 }
2114 }
2115
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002116 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2117 segment_id = pseg->seg_info.id;
2118
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002119 if ((ctx->playback.obsolete.time + pre_off + pseg->seg_info.duration) > time_offset)
2120 break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002121
2122 last_segment_id = pseg->seg_info.id;
2123 pre_off += pseg->seg_info.duration;
2124 }
2125
2126 if (last_segment_id == segment_id) {
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002127 /*1.only one seg with id:0, 2.offset exceeds the total duration*/
2128 off = time_offset;
2129 } else if (ctx->playback.obsolete.time >= time_offset) {
2130 off = 0;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002131 } else {
hualing chenda76fc52020-05-28 14:56:42 +08002132 off = time_offset - pre_off - ctx->playback.obsolete.time;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002133 }
2134
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002135 DVR_WRAPPER_DEBUG(1, "seek playback(sn:%ld) (seg:%lld, off:%d)\n",
2136 ctx->sn, segment_id, off);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002137 error = dvr_playback_seek(ctx->playback.player, segment_id, off);
2138 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) seeked(off:%d) (%d)\n", ctx->sn, time_offset, error);
2139
2140 pthread_mutex_unlock(&ctx->lock);
2141
2142 return error;
2143}
2144
2145int dvr_wrapper_update_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackPids_t *p_pids)
2146{
2147 DVR_WrapperCtx_t *ctx;
2148 int error;
2149 DVR_WrapperPlaybackSegmentInfo_t *pseg;
2150
2151 DVR_RETURN_IF_FALSE(playback);
2152 DVR_RETURN_IF_FALSE(p_pids);
2153
2154 ctx = ctx_getPlayback((unsigned long)playback);
2155 DVR_RETURN_IF_FALSE(ctx);
2156
2157 pthread_mutex_lock(&ctx->lock);
2158
2159 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) ...\n",
2160 ctx->sn,
2161 p_pids->video.pid, p_pids->video.format,
2162 p_pids->audio.pid, p_pids->audio.format);
2163 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
2164
2165 ctx->playback.pids_req = *p_pids;
2166
2167 error = 0;
2168 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2169 /*should update the whole list of segments*/
2170 /*if (pseg->seg_info.id == ctx->current_segment_id)*/ {
2171 /*list_for_each_entry_from(pseg, &ctx->segments, head)*/ {
2172 /*check udpate for pids*/
2173 if (memcmp(&pseg->playback_info.pids, p_pids, sizeof(*p_pids)) != 0) {
2174 pseg->playback_info.pids = *p_pids;
2175 error = dvr_playback_update_segment_pids(ctx->playback.player, pseg->seg_info.id, p_pids);
2176 if (error) {
2177 DVR_WRAPPER_DEBUG(1, "failed to playback(sn:%ld) update segment(id:%lld) pids (%d)\n",
2178 ctx->sn, pseg->seg_info.id, error);
2179 /*do not break, let list updated*/
2180 }
2181 }
2182 }
2183 /*break;*/
2184 }
2185 }
2186
2187 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) (%d)\n",
2188 ctx->sn,
2189 p_pids->video.pid, p_pids->video.format,
2190 p_pids->audio.pid, p_pids->audio.format,
2191 error);
2192
2193 pthread_mutex_unlock(&ctx->lock);
2194
2195 return error;
2196}
2197
hualing chena5f03222021-12-02 11:22:35 +08002198int dvr_wrapper_only_update_playback (DVR_WrapperPlayback_t playback, DVR_PlaybackPids_t *p_pids)
2199{
2200 DVR_WrapperCtx_t *ctx;
2201 int error;
2202 DVR_WrapperPlaybackSegmentInfo_t *pseg;
2203
2204 DVR_RETURN_IF_FALSE(playback);
2205 DVR_RETURN_IF_FALSE(p_pids);
2206
2207 ctx = ctx_getPlayback((unsigned long)playback);
2208 DVR_RETURN_IF_FALSE(ctx);
2209
2210 pthread_mutex_lock(&ctx->lock);
2211
2212 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) ...\n",
2213 ctx->sn,
2214 p_pids->video.pid, p_pids->video.format,
2215 p_pids->audio.pid, p_pids->audio.format);
2216 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
2217
2218 ctx->playback.pids_req = *p_pids;
2219
2220 error = 0;
2221 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2222 /*should update the whole list of segments*/
2223 /*if (pseg->seg_info.id == ctx->current_segment_id)*/ {
2224 /*list_for_each_entry_from(pseg, &ctx->segments, head)*/ {
2225 /*check udpate for pids*/
2226 if (memcmp(&pseg->playback_info.pids, p_pids, sizeof(*p_pids)) != 0) {
2227 pseg->playback_info.pids = *p_pids;
2228 error = dvr_playback_only_update_segment_pids(ctx->playback.player, pseg->seg_info.id, p_pids);
2229 if (error) {
2230 DVR_WRAPPER_DEBUG(1, "failed to playback(sn:%ld) update segment(id:%lld) pids (%d)\n",
2231 ctx->sn, pseg->seg_info.id, error);
2232 /*do not break, let list updated*/
2233 }
2234 }
2235 }
2236 /*break;*/
2237 }
2238 }
2239
2240 DVR_WRAPPER_DEBUG(1, "update playback(sn:%ld) v/a(%d:%d/%d:%d) (%d)\n",
2241 ctx->sn,
2242 p_pids->video.pid, p_pids->video.format,
2243 p_pids->audio.pid, p_pids->audio.format,
2244 error);
2245
2246 pthread_mutex_unlock(&ctx->lock);
2247
2248 return error;
2249}
2250
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002251int dvr_wrapper_get_playback_status(DVR_WrapperPlayback_t playback, DVR_WrapperPlaybackStatus_t *status)
2252{
2253 DVR_WrapperCtx_t *ctx;
2254 DVR_WrapperPlaybackStatus_t s;
2255 DVR_PlaybackStatus_t play_status;
2256 int error;
2257
2258 DVR_RETURN_IF_FALSE(playback);
2259 DVR_RETURN_IF_FALSE(status);
2260
2261 ctx = ctx_getPlayback((unsigned long)playback);
2262 DVR_RETURN_IF_FALSE(ctx);
2263
2264 pthread_mutex_lock(&ctx->lock);
2265
2266 DVR_WRAPPER_DEBUG(1, "get playback(sn:%ld) status ...\n", ctx->sn);
2267 DVR_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->lock);
2268
2269 error = dvr_playback_get_status(ctx->playback.player, &play_status);
2270 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) get status (%d)\n", ctx->sn, error);
2271
2272 ctx->playback.seg_status = play_status;
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002273 error = process_generatePlaybackStatus(ctx, &s);
2274
hualing chenb5cd42e2020-04-15 17:03:34 +08002275 if (ctx->playback.reach_end == DVR_TRUE && ctx->playback.param_open.is_timeshift == DVR_FALSE) {
2276 //reach end need set full time to cur.so app can exist playback.
2277 DVR_WRAPPER_DEBUG(1, "set cur time to full time, reach end occur");
2278 s.info_cur.time = s.info_full.time;
2279 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002280 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) state/cur/full/obsl(%d/%ld/%ld/%ld) (%d)\n",
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002281 ctx->sn,
2282 s.state,
2283 s.info_cur.time,
2284 s.info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002285 s.info_obsolete.time,
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002286 error);
2287
2288 *status = s;
2289
2290 pthread_mutex_unlock(&ctx->lock);
2291
2292 return error;
2293}
2294
hualing chen266b9502020-04-04 17:39:39 +08002295int dvr_wrapper_set_playback_secure_buffer (DVR_WrapperPlayback_t playback, uint8_t *p_secure_buf, uint32_t len)
2296{
2297 DVR_WrapperCtx_t *ctx;
2298 int error;
2299
2300 DVR_RETURN_IF_FALSE(playback);
2301 DVR_RETURN_IF_FALSE(p_secure_buf);
2302
2303 ctx = ctx_getPlayback((unsigned long)playback);
2304 DVR_RETURN_IF_FALSE(ctx);
2305
2306 pthread_mutex_lock(&ctx->lock);
2307 error = dvr_playback_set_secure_buffer(ctx->playback.player, p_secure_buf, len);
2308 pthread_mutex_unlock(&ctx->lock);
2309 return error;
2310}
2311
2312int dvr_wrapper_set_playback_decrypt_callback (DVR_WrapperPlayback_t playback, DVR_CryptoFunction_t func, void *userdata)
2313{
2314 DVR_WrapperCtx_t *ctx;
2315 int error;
2316
2317 DVR_RETURN_IF_FALSE(playback);
2318 DVR_RETURN_IF_FALSE(func);
2319
2320 ctx = ctx_getPlayback((unsigned long)playback);
2321 DVR_RETURN_IF_FALSE(ctx);
2322
2323 pthread_mutex_lock(&ctx->lock);
2324 error = dvr_playback_set_decrypt_callback(ctx->playback.player, func, userdata);
2325 pthread_mutex_unlock(&ctx->lock);
2326 return error;
2327}
2328
Zhiqiang Han620b9252021-11-09 14:23:20 +08002329int dvr_wrapper_segment_del_by_location (const char *location)
2330{
2331 char fpath[DVR_MAX_LOCATION_SIZE];
2332
2333 DVR_RETURN_IF_FALSE(location);
2334
2335 /*del the stats file*/
2336 sprintf(fpath, "%s.stats", location);
2337 unlink(fpath);
2338
2339 return dvr_segment_del_by_location(location);
2340}
2341
2342int dvr_wrapper_segment_get_info_by_location (const char *location, DVR_WrapperInfo_t *p_info)
2343{
2344 FILE *fp;
2345 char fpath[DVR_MAX_LOCATION_SIZE];
2346
2347 DVR_RETURN_IF_FALSE(location);
2348 DVR_RETURN_IF_FALSE(p_info);
2349
2350 if (p_info)
2351 memset(p_info, 0, sizeof(p_info[0]));
2352
2353 memset(fpath, 0, sizeof(fpath));
2354 sprintf(fpath, "%s.stats", location);
2355
2356 /*stats file exists*/
2357 if ((fp = fopen(fpath, "r"))) {
2358 char buf[256];
2359
2360 if (fgets(buf, sizeof(buf), fp) != NULL
2361 && (sscanf(buf, ":%llu:%lu:%u",
2362 &p_info->size,
2363 &p_info->time,
2364 &p_info->pkts) == 3)) {
2365 fclose(fp);
2366 DVR_WRAPPER_DEBUG(1, "rec(%s) t/s/p:(%lu/%llu/%u)\n", location, p_info->time, p_info->size, p_info->pkts);
2367 return DVR_SUCCESS;
2368 }
Zhiqiang Hanb9785922021-11-26 18:47:39 +08002369 fclose(fp);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002370 }
2371
2372 /*fallback, slow on mass files*/
Zhiqiang Hanb9785922021-11-26 18:47:39 +08002373 DVR_WRAPPER_DEBUG(1, "rec '%s.stats' invalid.\n", location);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002374
2375 int error;
2376 uint32_t n_ids;
2377 uint64_t *p_ids;
Zhiqiang Han620b9252021-11-09 14:23:20 +08002378
hualing chen8aed9582021-12-24 17:59:56 +08002379 error = dvr_segment_get_list(location, &n_ids, &p_ids);
hualing chenb9a02922021-12-14 11:29:47 +08002380
Zhiqiang Han620b9252021-11-09 14:23:20 +08002381 if (!error) {
2382 int i;
hualing chenb9a02922021-12-14 11:29:47 +08002383 struct list_head info_list; /**< segment list head*/
2384 INIT_LIST_HEAD(&info_list);
2385
2386 //we need free info list buf when we used end.
hualing chen8aed9582021-12-24 17:59:56 +08002387 error = dvr_segment_get_allInfo(location, &info_list);
2388 if (error == DVR_FAILURE) {
hualing chenb9a02922021-12-14 11:29:47 +08002389 DVR_RecordSegmentInfo_t info;
2390
2391 memset(&info, 0, sizeof(info));
2392 error = DVR_FAILURE;
2393 DVR_WRAPPER_DEBUG(1, "fail to get seg info (location:%s, seg:%llu), (error:%d)\n",
hualing chen8aed9582021-12-24 17:59:56 +08002394 location, 0, error);
hualing chenb9a02922021-12-14 11:29:47 +08002395
2396 for (i = 0; i < n_ids; i++) {
hualing chen8aed9582021-12-24 17:59:56 +08002397 error = dvr_segment_get_info(location, p_ids[i], &info);
hualing chenb9a02922021-12-14 11:29:47 +08002398 if (!error) {
2399 p_info->size += info.size;
2400 p_info->time += info.duration;
2401 p_info->pkts += info.nb_packets;
2402 } else {
hualing chen8aed9582021-12-24 17:59:56 +08002403 DVR_WRAPPER_DEBUG(1, "%s:%lld get seg info fail.\n", location, p_ids[i]);
hualing chenb9a02922021-12-14 11:29:47 +08002404 break;
2405 }
2406 }
2407 } else {
2408 DVR_WRAPPER_DEBUG(1, "get list segment_nb::%d",n_ids);
2409 for (i = 0; i < n_ids; i++) {
2410
2411 DVR_RecordSegmentInfo_t *seg_info;
2412 DVR_PlaybackSegmentFlag_t flags;
2413 int found = 0;
2414 list_for_each_entry(seg_info, &info_list, head)
2415 {
hualing chen8aed9582021-12-24 17:59:56 +08002416 if (seg_info->id == p_ids[i]) {
hualing chenb9a02922021-12-14 11:29:47 +08002417 found = 1;
2418 break;
2419 }
2420 }
2421 if (!found) {
hualing chen8aed9582021-12-24 17:59:56 +08002422 DVR_WRAPPER_DEBUG(1, "get segment info::%d [%d]n_ids[%d]error", i, p_ids[i], n_ids);
2423 if (p_ids[i] == n_ids - 1) {
2424 DVR_RecordSegmentInfo_t info;
2425 DVR_WRAPPER_DEBUG(1, "get last segment info::%d [%d]n_ids[%d] from subfile", i, p_ids[i], n_ids);
2426 error = dvr_segment_get_info(location, p_ids[i], &info);
2427 if (!error) {
2428 p_info->size += info.size;
2429 p_info->time += info.duration;
2430 p_info->pkts += info.nb_packets;
2431 } else {
2432 DVR_WRAPPER_DEBUG(1, "%s:%lld get seg info fail.\n", location, p_ids[i]);
2433 break;
2434 }
2435 }
hualing chenb9a02922021-12-14 11:29:47 +08002436 continue;
2437 }
2438
2439 if (!error) {
2440 p_info->size += seg_info->size;
2441 p_info->time += seg_info->duration;
2442 p_info->pkts += seg_info->nb_packets;
2443 } else {
hualing chen8aed9582021-12-24 17:59:56 +08002444 DVR_WRAPPER_DEBUG(1, "%s:%lld get seg info fail.\n", location, p_ids[i]);
hualing chenb9a02922021-12-14 11:29:47 +08002445 break;
2446 }
2447 }
2448 //free list
2449 DVR_RecordSegmentInfo_t *segment = NULL;
2450 DVR_RecordSegmentInfo_t *segment_tmp = NULL;
2451 list_for_each_entry_safe(segment, segment_tmp, &info_list, head)
2452 {
2453 if (segment) {
2454 list_del(&segment->head);
2455 free(segment);
2456 }
2457 }
2458 }
2459 free(p_ids);
Zhiqiang Hanb9785922021-11-26 18:47:39 +08002460 } else {
2461 n_ids = 0;
Zhiqiang Han620b9252021-11-09 14:23:20 +08002462 }
Zhiqiang Hanb9785922021-11-26 18:47:39 +08002463 DVR_WRAPPER_DEBUG(1, "rec(%s)... t/s/p:(%lu/%llu/%u) segs(%u) error(%d)\n", location, p_info->time, p_info->size, p_info->pkts, n_ids, error);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002464
2465 return (error)? DVR_FAILURE : DVR_SUCCESS;
2466}
2467
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002468static DVR_Result_t wrapper_record_event_handler(DVR_RecordEvent_t event, void *params, void *userdata)
2469{
2470 DVR_WrapperEventCtx_t evt;
2471
2472 DVR_RETURN_IF_FALSE(userdata);
2473
2474 evt.sn = (unsigned long)userdata;
2475 evt.type = W_REC;
2476 evt.record.event = event;
2477 evt.record.status = *(DVR_RecordStatus_t *)params;
2478 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, record, evt:0x%x]\n", evt.sn, evt.record.event);
2479 return ctx_addRecordEvent(&evt);
2480}
2481
2482static DVR_Result_t wrapper_playback_event_handler(DVR_PlaybackEvent_t event, void *params, void *userdata)
2483{
2484 DVR_WrapperEventCtx_t evt;
2485
2486 DVR_RETURN_IF_FALSE(userdata);
2487
2488 evt.sn = (unsigned long)userdata;
2489 evt.type = W_PLAYBACK;
2490 evt.playback.event = event;
2491 evt.playback.status = *(DVR_Play_Notify_t *)params;
2492 DVR_WRAPPER_DEBUG(1, "evt[sn:%ld, playbck, evt:0x%x]\n", evt.sn, evt.playback.event);
2493 return ctx_addPlaybackEvent(&evt);
2494}
2495
2496static inline int process_notifyRecord(DVR_WrapperCtx_t *ctx, DVR_RecordEvent_t evt, DVR_WrapperRecordStatus_t *status)
2497{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002498 DVR_WRAPPER_DEBUG(1, "notify(sn:%ld) evt(0x%x) statistic:time/size/pkts(%ld/%lld/%u) obsl:(%ld/%llu/%u)\n",
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002499 ctx->sn,
2500 evt,
2501 status->info.time,
2502 status->info.size,
2503 status->info.pkts,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002504 status->info_obsolete.time,
2505 status->info_obsolete.size,
2506 status->info_obsolete.pkts);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002507
2508 if (ctx->record.event_fn)
2509 return ctx->record.event_fn(evt, status, ctx->record.event_userdata);
2510 return 0;
2511}
2512
Zhiqiang Han620b9252021-11-09 14:23:20 +08002513static int wrapper_saveRecordStatistics(const char *location, DVR_WrapperRecordStatus_t *p_status)
2514{
2515 FILE *fp;
2516 char fpath[DVR_MAX_LOCATION_SIZE];
2517
2518 DVR_RETURN_IF_FALSE(location);
2519 DVR_RETURN_IF_FALSE(p_status);
2520
2521 sprintf(fpath, "%s.stats", location);
2522
2523 /*stats file*/
2524 if ((fp = fopen(fpath, "w"))) {
2525 char buf[256];
2526 snprintf(buf, sizeof(buf), ":%llu:%lu:%u\n",
2527 p_status->info.size - p_status->info_obsolete.size,
2528 p_status->info.time - p_status->info_obsolete.time,
2529 p_status->info.pkts - p_status->info_obsolete.pkts);
2530 fputs(buf, fp);
2531 fclose(fp);
2532 return DVR_SUCCESS;
2533 }
2534
2535 return DVR_FAILURE;
2536}
2537
2538
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002539static inline int record_startNextSegment(DVR_WrapperCtx_t *ctx)
2540{
2541 DVR_RecordStartParams_t param;
2542 DVR_RecordSegmentInfo_t seg_info;
2543 int i;
2544 int error;
2545
2546 memcpy(&param, &ctx->record.param_update, sizeof(param));
2547 memset(&ctx->record.param_update.segment, 0, sizeof(ctx->record.param_update.segment));
2548 ctx->record.param_update.segment.segment_id = ctx->record.next_segment_id++;
2549 for (i = 0; i < param.segment.nb_pids; i++) {
2550 if (param.segment.pid_action[i] != DVR_RECORD_PID_CLOSE) {
2551 ctx->record.param_update.segment.pids[ctx->record.param_update.segment.nb_pids] = param.segment.pids[i];
2552 ctx->record.param_update.segment.pid_action[ctx->record.param_update.segment.nb_pids] = DVR_RECORD_PID_KEEP;
2553 ctx->record.param_update.segment.nb_pids++;
2554 }
2555 }
2556 error = dvr_record_next_segment(ctx->record.recorder, &ctx->record.param_update, &seg_info);
2557 {
2558 DVR_RecordSegmentInfo_t new_seg_info =
2559 { .id = ctx->record.param_update.segment.segment_id, };
2560 wrapper_updateRecordSegment(ctx, &seg_info, U_ALL);
2561 wrapper_addRecordSegment(ctx, &new_seg_info);
2562 }
2563
Zhiqiang Hand977e972020-05-11 11:30:47 +08002564 DVR_WRAPPER_DEBUG(1, "record next segment(%llu)=(%d)\n", ctx->record.param_update.segment.segment_id, error);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002565 return error;
2566}
2567
2568static inline int record_removeSegment(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordSegmentInfo_t *pseg)
2569{
2570 return wrapper_removeRecordSegment(ctx, pseg);
2571}
2572
2573/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002574static int process_generateRecordStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperRecordStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002575{
2576 /*the current seg is not covered in the statistics*/
2577 DVR_WrapperRecordSegmentInfo_t *pseg;
2578
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002579 /*re-calculate the all segments*/
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002580 memset(&ctx->record.status, 0, sizeof(ctx->record.status));
2581
2582 ctx->record.status.state = ctx->record.seg_status.state;
2583 ctx->record.status.pids.nb_pids = ctx->record.seg_status.info.nb_pids;
2584 memcpy(ctx->record.status.pids.pids,
2585 ctx->record.seg_status.info.pids,
2586 sizeof(ctx->record.status.pids.pids));
2587 ctx->current_segment_id = ctx->record.seg_status.info.id;
2588
2589 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2590 if (pseg->info.id != ctx->record.seg_status.info.id) {
2591 ctx->record.status.info.time += pseg->info.duration;
2592 ctx->record.status.info.size += pseg->info.size;
2593 ctx->record.status.info.pkts += pseg->info.nb_packets;
2594 }
2595 }
2596
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002597 ctx->record.status.info_obsolete = ctx->record.obsolete;
2598
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002599 wrapper_updateRecordSegment(ctx, &ctx->record.seg_status.info, U_ALL);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002600
2601 if (status) {
2602 *status = ctx->record.status;
2603 status->info.time += ctx->record.seg_status.info.duration;
2604 status->info.size += ctx->record.seg_status.info.size;
2605 status->info.pkts += ctx->record.seg_status.info.nb_packets;
2606 }
2607
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002608 return DVR_SUCCESS;
2609}
2610
2611
2612static int process_handleRecordEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2613{
2614 DVR_WrapperRecordStatus_t status;
2615
2616 memset(&status, 0, sizeof(status));
2617
2618 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d)\n",
2619 evt->sn, evt->record.event, evt->record.status.state);
hualing chend3b55ab2021-05-06 09:56:27 +08002620 if (ctx->record.param_update.segment.segment_id != evt->record.status.info.id) {
2621 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) cur id:0x%x (event id:%d)\n",
Gong Ke2a0ebbe2021-05-25 15:22:50 +08002622 evt->sn, (int)ctx->record.param_update.segment.segment_id, (int)evt->record.status.info.id);
hualing chend3b55ab2021-05-06 09:56:27 +08002623 return 0;
2624 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002625 switch (evt->record.event)
2626 {
2627 case DVR_RECORD_EVENT_STATUS:
2628 {
2629 switch (evt->record.status.state)
2630 {
2631 case DVR_RECORD_STATE_OPENED:
2632 case DVR_RECORD_STATE_CLOSED:
2633 {
2634 ctx->record.seg_status = evt->record.status;
2635
2636 status.state = evt->record.status.state;
2637 process_notifyRecord(ctx, evt->record.event, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002638 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002639 } break;
2640 case DVR_RECORD_STATE_STARTED:
2641 {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002642 ctx->record.seg_status = evt->record.status;
2643
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002644 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002645 process_notifyRecord(ctx, evt->record.event, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002646 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002647
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002648 /*restart to next segment*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002649 if (ctx->record.param_open.segment_size
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002650 && evt->record.status.info.size >= ctx->record.param_open.segment_size) {
2651 DVR_WRAPPER_DEBUG(1, "start new segment for record(%lu), reaches segment size limit, cur(%zu) max(%lld)\n",
2652 ctx->sn,
2653 evt->record.status.info.size,
2654 ctx->record.param_open.segment_size);
Zhiqiang Hand977e972020-05-11 11:30:47 +08002655 if (record_startNextSegment(ctx) != DVR_SUCCESS) {
2656 /*should notify the recording's stop*/
2657 int error = dvr_record_close(ctx->record.recorder);
2658 DVR_WRAPPER_DEBUG(1, "stop record(%lu)=%d, failed to start new segment for recording.",
2659 ctx->sn, error);
2660 status.state = DVR_RECORD_STATE_CLOSED;
2661 process_notifyRecord(ctx, DVR_RECORD_EVENT_WRITE_ERROR, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002662 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Hand977e972020-05-11 11:30:47 +08002663 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002664 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002665
2666 if (ctx->record.param_open.is_timeshift
2667 && ctx->record.param_open.max_time
2668 && status.info.time >= ctx->record.param_open.max_time) {
2669 DVR_WrapperRecordSegmentInfo_t *pseg;
2670
2671 /*as the player do not support null playlist,
2672 there must be one segment existed at any time,
2673 we have to keep two segments before remove one*/
2674 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
2675 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
2676 /*only one segment, waiting for more*/
2677 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of max_time(%ld) of record < max size of segment(%lld)\n",
2678 status.info.size,
2679 ctx->record.param_open.max_time,
2680 ctx->record.param_open.segment_size);
2681 } else {
2682 /*timeshifting, remove the 1st segment and notify the player*/
2683 record_removeSegment(ctx, pseg);
2684
2685 process_generateRecordStatus(ctx, &status);
2686 process_notifyRecord(ctx, evt->record.event, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002687 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002688 }
2689 }
2690
2691 if (ctx->record.param_open.is_timeshift
2692 && ctx->record.param_open.max_size
2693 && status.info.size >= ctx->record.param_open.max_size) {
2694 DVR_WrapperRecordSegmentInfo_t *pseg;
2695
2696 /*as the player do not support null playlist,
2697 there must be one segment existed at any time,
2698 we have to keep two segments before remove one*/
2699 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
2700 if (pseg == list_first_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head)) {
2701 /*only one segment, waiting for more*/
2702 DVR_WRAPPER_DEBUG(1, "warning: the size(%lld) of record < max size of segment(%lld)\n",
2703 status.info.size,
2704 ctx->record.param_open.segment_size);
2705 } else {
2706 record_removeSegment(ctx, pseg);
2707
2708 process_generateRecordStatus(ctx, &status);
2709 process_notifyRecord(ctx, evt->record.event, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002710 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002711 }
2712 }
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002713 } break;
2714 case DVR_RECORD_STATE_STOPPED:
2715 {
2716 ctx->record.seg_status = evt->record.status;
2717
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002718 process_generateRecordStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002719 process_notifyRecord(ctx, evt->record.event, &status);
Zhiqiang Han620b9252021-11-09 14:23:20 +08002720 wrapper_saveRecordStatistics(ctx->record.param_open.location, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002721 } break;
2722 default:
2723 break;
2724 }
2725 } break;
hualing chen4b7c15d2020-04-07 16:13:48 +08002726 case DVR_RECORD_EVENT_WRITE_ERROR: {
2727 ctx->record.seg_status = evt->record.status;
2728 status.state = evt->record.status.state;
2729 process_notifyRecord(ctx, evt->record.event, &status);
2730 }break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002731 default:
2732 break;
2733 }
2734 return DVR_SUCCESS;
2735}
2736
2737static inline int process_notifyPlayback(DVR_WrapperCtx_t *ctx, DVR_PlaybackEvent_t evt, DVR_WrapperPlaybackStatus_t *status)
2738{
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002739 DVR_WRAPPER_DEBUG(1, "notify(sn:%ld) evt(0x%x) statistics:state/cur/full/obsl(%d/%ld/%ld/%ld)\n",
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002740 ctx->sn,
2741 evt,
2742 status->state,
2743 status->info_cur.time,
2744 status->info_full.time,
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002745 status->info_obsolete.time);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002746
2747 if (ctx->playback.event_fn)
2748 return ctx->playback.event_fn(evt, status, ctx->playback.event_userdata);
2749 return 0;
2750}
2751
2752/*should run periodically to update the current status*/
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002753static int process_generatePlaybackStatus(DVR_WrapperCtx_t *ctx, DVR_WrapperPlaybackStatus_t *status)
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002754{
2755 /*the current seg is not covered in the statistics*/
2756 DVR_WrapperPlaybackSegmentInfo_t *pseg;
2757
2758 memset(&ctx->playback.status, 0, sizeof(ctx->playback.status));
2759 ctx->playback.status.pids = ctx->playback.pids_req;
2760
2761 ctx->playback.status.state = ctx->playback.seg_status.state;
2762 ctx->playback.status.speed = ctx->playback.seg_status.speed;
2763 ctx->playback.status.flags = ctx->playback.seg_status.flags;
2764 ctx->current_segment_id = ctx->playback.seg_status.segment_id;
2765
2766 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
hualing chen451c8f72022-03-09 13:05:52 +08002767 if (pseg->seg_info.id == ctx->playback.seg_status.segment_id) {
2768 DVR_WRAPPER_DEBUG(1, "caulate cur time :[%lld]time[%d]\n", pseg->seg_info.id, pseg->seg_info.duration);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002769 break;
hualing chen451c8f72022-03-09 13:05:52 +08002770 }
2771
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002772 ctx->playback.status.info_cur.time += pseg->seg_info.duration;
2773 ctx->playback.status.info_cur.size += pseg->seg_info.size;
2774 ctx->playback.status.info_cur.pkts += pseg->seg_info.nb_packets;
2775 }
2776 list_for_each_entry_reverse(pseg, &ctx->segments, head) {
2777 ctx->playback.status.info_full.time += pseg->seg_info.duration;
2778 ctx->playback.status.info_full.size += pseg->seg_info.size;
2779 ctx->playback.status.info_full.pkts += pseg->seg_info.nb_packets;
hualing chen451c8f72022-03-09 13:05:52 +08002780 DVR_WRAPPER_DEBUG(1, "caulate full time :[%lld]time[%d]\n", pseg->seg_info.id, pseg->seg_info.duration);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002781 }
2782
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002783 if (status) {
2784 *status = ctx->playback.status;
2785 /*deal with current, lack size and pkts with the current*/
2786 status->info_cur.time += ctx->playback.seg_status.time_cur;
hualing chen56c0a162022-01-27 17:01:50 +08002787 //get last segment id
2788 DVR_WrapperRecordSegmentInfo_t *pseg;
2789
2790 pseg = list_last_entry(&ctx->segments, DVR_WrapperRecordSegmentInfo_t, head);
2791 if (ctx->playback.tf_full == DVR_TRUE && pseg->info.id == ctx->current_segment_id) {
2792 status->disguised_info_obsolete.time = ctx->playback.obsolete.time + ctx->playback.seg_status.time_cur;
2793 status->info_obsolete.time = ctx->playback.obsolete.time;
2794 DVR_WRAPPER_DEBUG(1, "warning change start time :id[%lld] [%d]cur[%d]\n", pseg->info.id, status->info_obsolete.time, status->info_cur.time);
2795 }
2796 else
2797 {
2798 DVR_WRAPPER_DEBUG(1, "warning not change start time :ctx->playback.tf_full[%d]id[%lld] [%lld] cur[%d]\n",ctx->playback.tf_full , pseg->info.id, ctx->current_segment_id, status->info_cur.time);
2799 status->info_obsolete.time = ctx->playback.obsolete.time;
2800 status->disguised_info_obsolete.time = ctx->playback.obsolete.time;
2801 }
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002802 }
2803
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002804 return DVR_SUCCESS;
2805}
2806
2807static int process_handlePlaybackEvent(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2808{
2809 DVR_WRAPPER_DEBUG(1, "evt (sn:%ld) 0x%x (state:%d) cur(%lld:%u/%u)\n",
2810 evt->sn, evt->playback.event,
2811 evt->playback.status.play_status.state,
2812 evt->playback.status.play_status.segment_id,
2813 evt->playback.status.play_status.time_cur,
2814 evt->playback.status.play_status.time_end);
2815
2816 /*evt PLAYTIME will break the last logic, do not save*/
hualing chene3797f02021-01-13 14:53:28 +08002817 if (evt->playback.event != DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME
2818 && evt->playback.event != DVR_PLAYBACK_EVENT_NODATA
2819 && evt->playback.event != DVR_PLAYBACK_EVENT_DATARESUME
2820 )
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002821 ctx->playback.last_event = evt->playback.event;
2822
2823 switch (evt->playback.event)
2824 {
2825 case DVR_PLAYBACK_EVENT_FIRST_FRAME:
2826 case DVR_PLAYBACK_EVENT_REACHED_END:
2827 case DVR_PLAYBACK_EVENT_TRANSITION_OK:
2828 case DVR_PLAYBACK_EVENT_NOTIFY_PLAYTIME:
hualing chenb5cd42e2020-04-15 17:03:34 +08002829 case DVR_PLAYBACK_EVENT_ERROR:
hualing chenf291cf32020-06-18 10:50:30 +08002830 case DVR_PLAYBACK_EVENT_REACHED_BEGIN:
hualing chene3797f02021-01-13 14:53:28 +08002831 case DVR_PLAYBACK_EVENT_NODATA:
2832 case DVR_PLAYBACK_EVENT_DATARESUME:
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002833 {
2834 DVR_WrapperPlaybackStatus_t status;
2835
2836 /*copy status of segment*/
2837 ctx->playback.seg_status = evt->playback.status.play_status;
2838
Zhiqiang Hanaeb0c712020-04-30 15:17:26 +08002839 /*generate status of the whole playback*/
2840 process_generatePlaybackStatus(ctx, &status);
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002841
2842 if (evt->playback.event == DVR_PLAYBACK_EVENT_REACHED_END) {
Zhiqiang Han31846002021-11-04 10:49:06 +08002843 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) event:0x%x\n", evt->sn, evt->playback.event);
hualing chenb9b358a2021-08-17 15:06:36 +08002844 if (ctx->playback.param_open.is_timeshift
2845 || ctx_isPlay_recording(ctx->playback.param_open.location)) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002846 /*wait for more data in recording*/
Zhiqiang Han31846002021-11-04 10:49:06 +08002847 }
2848 /*trust the low level, make NO check.
2849 As this evt is changed to only once due to some operations(paused) in low level.
2850 else if ((status.info_cur.time + DVR_PLAYBACK_END_GAP) >= ctx->playback.status.info_full.time) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002851 process_notifyPlayback(ctx, evt->playback.event, &status);
Zhiqiang Han31846002021-11-04 10:49:06 +08002852 }
2853 */
2854 else {
2855 process_notifyPlayback(ctx, evt->playback.event, &status);
hualing chenb5cd42e2020-04-15 17:03:34 +08002856 ctx->playback.reach_end = DVR_TRUE;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002857 }
hualing chenf291cf32020-06-18 10:50:30 +08002858 } else if (evt->playback.event != DVR_PLAYBACK_EVENT_REACHED_BEGIN) {
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002859 process_notifyPlayback(ctx, evt->playback.event, &status);
2860 }
2861 } break;
Zhiqiang Han2d8cd822020-03-16 13:58:10 +08002862 case DVR_PLAYBACK_EVENT_TRANSITION_FAILED:
2863 case DVR_PLAYBACK_EVENT_KEY_FAILURE:
2864 case DVR_PLAYBACK_EVENT_NO_KEY:
2865 {
2866 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) error event:0x%x\n", evt->sn, evt->playback.event);
2867 } break;
2868 default:
2869 {
2870 DVR_WRAPPER_DEBUG(1, "playback(sn:%ld) unknown event:0x%x\n", evt->sn, evt->playback.event);
2871 } break;
2872 }
2873 return 0;
2874}
2875
2876static inline int process_handleEvents(DVR_WrapperEventCtx_t *evt, DVR_WrapperCtx_t *ctx)
2877{
2878 return (evt->type == W_REC)? process_handleRecordEvent(evt, ctx) : process_handlePlaybackEvent(evt, ctx);
2879}
2880