dataout: added segment implementation layer [1/2]
PD#SWPL-137949
Problem:
request for data output only
Solution:
optimized for segment layer
implemented output segment layer
Verify:
PB
Change-Id: Ia4c6a2ec451736e523c0ff5fc94226e95d7a9b7a
Signed-off-by: Zhiqiang Han <zhiqiang.han@amlogic.com>
diff --git a/Android.bp b/Android.bp
index d5644c5..591ef8b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -49,6 +49,7 @@
"src/list_file.c",
"src/record_device.c",
"src/segment.c",
+ "src/segment_dataout.c",
"src/am_crypt.c",
"src/dvr_mutex.c",
],
@@ -115,6 +116,7 @@
"src/list_file.c",
"src/record_device.c",
"src/segment.c",
+ "src/segment_dataout.c",
"src/am_crypt.c",
"src/dvr_mutex.c",
],
diff --git a/Makefile b/Makefile
index f35bbed..f7fb79f 100644
--- a/Makefile
+++ b/Makefile
@@ -16,8 +16,10 @@
src/dvr_wrapper.c\
src/list_file.c\
src/segment.c\
+ src/segment_dataout.c\
src/am_crypt.c\
src/dvr_mutex.c
+
LIBAMDVR_OBJS := $(patsubst %.c,%.o,$(LIBAMDVR_SRCS))
AM_FEND_TEST_SRCS := \
diff --git a/include/dvr_record.h b/include/dvr_record.h
index 626250a..f045fba 100644
--- a/include/dvr_record.h
+++ b/include/dvr_record.h
@@ -37,6 +37,7 @@
typedef enum {
DVR_RECORD_FLAG_SCRAMBLED = (1 << 0),
DVR_RECORD_FLAG_ACCURATE = (1 << 1),
+ DVR_RECORD_FLAG_DATAOUT = (1 << 2),
} DVR_RecordFlag_t;
/**\brief DVR crypto parity flag*/
@@ -239,6 +240,16 @@
*/
int dvr_record_discard_coming_data(DVR_RecordHandle_t handle, DVR_Bool_t discard);
+/**\brief control the recording logic
+ * \param[in] handle, DVR recording session handle
+ * \param[in] cmd, command
+ * \param[in/out] data, parameters
+ * \param[in/out] size, size of parameters
+ * \return DVR_SUCCESS on success
+ * \return error code on failure
+ */
+int dvr_record_ioctl(DVR_RecordHandle_t handle, unsigned int cmd, void *data, size_t size);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/dvr_wrapper.h b/include/dvr_wrapper.h
index e04654c..25e25ed 100644
--- a/include/dvr_wrapper.h
+++ b/include/dvr_wrapper.h
@@ -412,6 +412,17 @@
*/
int dvr_wrapper_property_get(const char* prop_name, char* prop_value, int length);
+/**
+ * Control the internal recording logic
+ * \param rec The record handle.
+ * \param cmd control command
+ * \param data control data
+ * \param size size of the control data
+ * \retval DVR_SUCCESS On success.
+ * \return Error code.
+ */
+int dvr_wrapper_ioctl_record(DVR_WrapperRecord_t rec, unsigned int cmd, void *data, size_t size);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/segment.h b/include/segment.h
index bcc2709..6e60507 100644
--- a/include/segment.h
+++ b/include/segment.h
@@ -11,24 +11,7 @@
#endif
#include "dvr_types.h"
-
-/**\brief Segment handle*/
-typedef void* Segment_Handle_t;
-
-/**\brief Segment open mode*/
-typedef enum {
- SEGMENT_MODE_READ, /**< Segment open read mode*/
- SEGMENT_MODE_WRITE, /**< Segment open write mode*/
- SEGMENT_MODE_MAX /**< Segment invalid open mode*/
-} Segment_OpenMode_t;
-
-/**\brief Segment open parameters*/
-typedef struct Segment_OpenParams_s {
- char location[DVR_MAX_LOCATION_SIZE]; /**< Segment file location*/
- uint64_t segment_id; /**< Segment index*/
- Segment_OpenMode_t mode; /**< Segment open mode*/
- DVR_Bool_t force_sysclock; /**< If ture, force to use system clock as PVR index time source. If false, libdvr can determine index time source based on actual situation*/
-} Segment_OpenParams_t;
+#include "segment_ops.h"
/**\brief Open a segment for a target giving some open parameters
* \param[out] p_handle, Return the handle of the newly created segment
diff --git a/include/segment_dataout.h b/include/segment_dataout.h
new file mode 100644
index 0000000..9a33876
--- /dev/null
+++ b/include/segment_dataout.h
@@ -0,0 +1,39 @@
+#ifndef _SEGMENT_DATAOUT_H_
+#define _SEGMENT_DATAOUT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "dvr_types.h"
+#include "segment_ops.h"
+
+/**
+ * Segment implementation 2
+ * for data loop out
+ */
+
+#define SEGMENT_DATAOUT_CMD_SET_CALLBACK 0x1001
+typedef struct Segment_DataoutCallback_s {
+ int (*callback)(unsigned char *buf, size_t size, void *priv);
+ void *priv;
+} Segment_DataoutCallback_t;
+
+
+
+int segment_dataout_open(Segment_OpenParams_t *params, Segment_Handle_t *p_handle);
+int segment_dataout_close(Segment_Handle_t handle);
+int segment_dataout_ioctl(Segment_Handle_t handle, int cmd, void *data, size_t size);
+ssize_t segment_dataout_write(Segment_Handle_t handle, void *buf, size_t count);
+loff_t segment_dataout_tell_total_time(Segment_Handle_t handle);
+int segment_dataout_store_info(Segment_Handle_t handle, Segment_StoreInfo_t *p_info);
+int segment_dataout_store_allInfo(Segment_Handle_t handle, Segment_StoreInfo_t *p_info);
+int segment_dataout_update_pts_force(Segment_Handle_t handle, uint64_t pts, loff_t offset);
+int segment_dataout_update_pts(Segment_Handle_t handle, uint64_t pts, loff_t offset);
+loff_t segment_dataout_tell_position(Segment_Handle_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/segment_ops.h b/include/segment_ops.h
new file mode 100644
index 0000000..79aaceb
--- /dev/null
+++ b/include/segment_ops.h
@@ -0,0 +1,197 @@
+/*
+ * \file
+ * Segment module
+ */
+
+#ifndef _SEGMENT_OPS_H_
+#define _SEGMENT_OPS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "dvr_types.h"
+
+/**\brief Segment handle*/
+typedef void* Segment_Handle_t;
+
+/**\brief Segment open mode*/
+typedef enum {
+ SEGMENT_MODE_READ, /**< Segment open read mode*/
+ SEGMENT_MODE_WRITE, /**< Segment open write mode*/
+ SEGMENT_MODE_MAX /**< Segment invalid open mode*/
+} Segment_OpenMode_t;
+
+/**\brief Segment open parameters*/
+typedef struct Segment_OpenParams_s {
+ char location[DVR_MAX_LOCATION_SIZE]; /**< Segment file location*/
+ uint64_t segment_id; /**< Segment index*/
+ Segment_OpenMode_t mode; /**< Segment open mode*/
+ DVR_Bool_t force_sysclock; /**< If ture, force to use system clock as PVR index time source. If false, libdvr can determine index time source based on actual situation*/
+} Segment_OpenParams_t;
+
+typedef struct Segment_Ops_s {
+
+ /**\brief Open a segment for a target giving some open parameters
+ * \param[out] p_handle, Return the handle of the newly created segment
+ * \param[in] params, Segment open parameters
+ * \return DVR_SUCCESS on success
+ * \return error code on failure
+ */
+ int (*segment_open)(Segment_OpenParams_t *params, Segment_Handle_t *p_handle);
+
+ /**\brief Close a segment
+ * \param[in] handle, Segment handle
+ * \return DVR_SUCCESS on success
+ * \return error code on failure
+ */
+ int (*segment_close)(Segment_Handle_t handle);
+
+ /**\brief control the giving segment
+ * \param[in] handle, Segment handle
+ * \param[in] cmd, The control command
+ * \param[in] data, The control data
+ * \param[in] size, Size of the control data
+ * \return DVR_SUCCESS on success
+ * \return error code on failure
+ */
+ int (*segment_ioctl)(Segment_Handle_t handle, int cmd, void *data, size_t size);
+
+ /**\brief Read data from the giving segment
+ * \param[out] buf, The buffer of data
+ * \param[in] handle, Segment handle
+ * \param[in] count, The data count
+ * \return The number of bytes read on success
+ * \return error code on failure
+ */
+ ssize_t (*segment_read)(Segment_Handle_t handle, void *buf, size_t count);
+
+ /**\brief Write data from the giving segment
+ * \param[in] buf, The buffer of data
+ * \param[in] handle, Segment handle
+ * \param[in] count, The data count
+ * \return The number of bytes write on success
+ * \return error code on failure
+ */
+ ssize_t (*segment_write)(Segment_Handle_t handle, void *buf, size_t count);
+
+ /**\brief force Update the pts and offset when record
+ * \param[in] handle, Segment handle
+ * \param[in] pts, Current pts
+ * \param[in] offset, Current segment offset
+ * \return DVR_SUCCESS on success
+ * \return error code on failure
+ */
+ int (*segment_update_pts_force)(Segment_Handle_t handle, uint64_t pts, loff_t offset);
+
+
+ /**\brief Update the pts and offset when record
+ * \param[in] handle, Segment handle
+ * \param[in] pts, Current pts
+ * \param[in] offset, Current segment offset
+ * \return DVR_SUCCESS on success
+ * \return error code on failure
+ */
+ int (*segment_update_pts)(Segment_Handle_t handle, uint64_t pts, loff_t offset);
+
+ /**\brief Seek the segment to the correct position which match the giving time
+ * \param[in] handle, Segment handle
+ * \param[in] time, The time offset
+ * \param[in] block_size, if block_size is > 0, we need aligned to block_size-byte boundary
+ * \return The segment current read position on success
+ * \return error code on failure
+ */
+ loff_t (*segment_seek)(Segment_Handle_t handle, uint64_t time, int block_size);
+
+ /**\brief Tell the current position for the giving segment
+ * \param[in] handle, Segment handle
+ * \return The segment current read position on success
+ * \return error code on failure
+ */
+ loff_t (*segment_tell_position)(Segment_Handle_t handle);
+
+ /**\brief Tell position time of the given segment's postion. Function is used for playback.
+ * \param[in] handle, Segment handle
+ * \param[in] position, Segment's file position
+ * \return position time in ms on success, or -1 on failure
+ */
+ loff_t (*segment_tell_position_time)(Segment_Handle_t handle, loff_t position);
+
+ /**\brief Tell current playback time of the given segment. Function is used for playback.
+ * \param[in] handle, Segment handle
+ * \return segment's current playback time in ms on success, or -1 on failure
+ */
+ loff_t (*segment_tell_current_time)(Segment_Handle_t handle);
+
+ /**\brief Tell total time of the given segment.
+ * \param[in] handle, Segment handle
+ * \return The segment's total time in ms on success, or -1 on failure
+ */
+ loff_t (*segment_tell_total_time)(Segment_Handle_t handle);
+
+ /**\brief Store the segment information to a file
+ * \param[in] handle, The segment handle
+ * \param[in] p_info, The segment information pointer
+ * \return DVR_SUCCESS On success
+ * \return Error code On failure
+ */
+ int (*segment_store_info)(Segment_Handle_t handle, Segment_StoreInfo_t *p_info);
+
+ /**\brief Store the segment all information to a file
+ * \param[in] handle, The segment handle
+ * \param[in] p_info, The segment information pointer
+ * \return DVR_SUCCESS On success
+ * \return Error code On failure
+ */
+ int (*segment_store_allInfo)(Segment_Handle_t handle, Segment_StoreInfo_t *p_info);
+
+ /**\brief Load the segment information from a file
+ * \param[in] handle, The segment handle
+ * \param[out] p_info, The segment information pointer
+ * \return DVR_SUCCESS On success
+ * \return Error code On failure
+ */
+ int (*segment_load_info)(Segment_Handle_t handle, Segment_StoreInfo_t *p_info);
+
+ /**\brief Load the segment information from a file
+ * \param[in] handle, The segment handle
+ * \param[out] p_info, The segment information pointer
+ * \return DVR_SUCCESS On success
+ * \return Error code On failure
+ */
+ int (*segment_load_allInfo)(Segment_Handle_t handle, struct list_head *list);
+
+
+ /**\brief Delete the segment information file
+ * \param[in] location, The record file's location
+ * \param[in] segment_id, The segment's index
+ * \return DVR_SUCCESS On success
+ * \return Error code On failure
+ */
+ int (*segment_delete)(const char *location, uint64_t segment_id);
+
+ /**\brief check the segment is ongoing file
+ * \param[in] handle, The segment handle
+ * \return DVR_SUCCESS On success
+ * \return Error code not ongoing
+ */
+ int (*segment_ongoing)(Segment_Handle_t handle);
+
+ /**\brief get current ongoing segment size
+ * \param[in] handle, The segment handle
+ * \return segment size
+ */
+ off_t (*segment_get_cur_segment_size)(Segment_Handle_t handle);
+
+ /**\brief get current ongoing segment id
+ * \param[in] handle, The segment handle
+ * \return segment id
+ */
+ uint64_t (*segment_get_cur_segment_id)(Segment_Handle_t handle);
+} Segment_Ops_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*END _SEGMENT_H_H_*/
diff --git a/src/dvr_record.c b/src/dvr_record.c
index 462ac75..07ae618 100644
--- a/src/dvr_record.c
+++ b/src/dvr_record.c
@@ -8,11 +8,13 @@
#include "dvr_crypto.h"
#include "dvb_utils.h"
#include "record_device.h"
-#include "segment.h"
#include <sys/time.h>
#include <sys/prctl.h>
#include "am_crypt.h"
+#include "segment.h"
+#include "segment_dataout.h"
+
#define CHECK_PTS_MAX_COUNT (20)
//#define DEBUG_PERFORMANCE
@@ -80,8 +82,31 @@
loff_t guarded_segment_size; /**< Guarded segment size in bytes. Libdvr will be forcely stopped to write anymore if current segment reaches this size*/
size_t secbuf_size; /**< DVR record secure buffer length*/
DVR_Bool_t discard_coming_data; /**< Whether to discard subsequent recording data due to exceeding total size limit too much.*/
+ Segment_Ops_t segment_ops;
+ struct list_head segment_ctrls;
} DVR_RecordContext_t;
+typedef struct {
+ struct list_head head;
+ unsigned int cmd;
+ void *data;
+ size_t size;
+} DVR_Control_t;
+
+#define SEG_CALL_INIT(_ops) Segment_Ops_t *ops = (_ops)
+#define SEG_CALL_RET_VALID(_name, _args, _ret, _def_ret) do {\
+ if (ops->segment_##_name)\
+ (_ret) = ops->segment_##_name _args;\
+ else\
+ (_ret) = (_def_ret);\
+ } while(0);
+#define SEG_CALL_RET(_name, _args, _ret) SEG_CALL_RET_VALID(_name, _args, _ret, _ret)
+#define SEG_CALL(_name, _args) do {\
+ if (ops->segment_##_name)\
+ ops->segment_##_name _args;\
+ } while(0)
+#define SEG_CALL_IS_VALID(_name) (!!ops->segment_##_name)
+
extern ssize_t record_device_read_ext(Record_DeviceHandle_t handle, size_t *buf, size_t *len);
static DVR_RecordContext_t record_ctx[MAX_DVR_RECORD_SESSION_COUNT] = {
@@ -93,6 +118,55 @@
}
};
+
+static int record_set_segment_ops(DVR_RecordContext_t *p_ctx, int flags)
+{
+ Segment_Ops_t *ops = &p_ctx->segment_ops;
+
+ memset(ops, 0, sizeof(Segment_Ops_t));
+
+ if (flags & DVR_RECORD_FLAG_DATAOUT) {
+ DVR_INFO("%s segment mode: dataout", __func__);
+ #define _SET(_op)\
+ ops->segment_##_op = segment_dataout_##_op
+ _SET(open);
+ _SET(close);
+ _SET(ioctl);
+ _SET(write);
+ _SET(update_pts);
+ _SET(update_pts_force);
+ _SET(tell_position);
+ _SET(tell_total_time);
+ _SET(store_info);
+ _SET(store_allInfo);
+ #undef _SET
+ } else {
+ #define _SET(_op)\
+ ops->segment_##_op = segment_##_op
+ _SET(open);
+ _SET(close);
+ _SET(read);
+ _SET(write);
+ _SET(update_pts);
+ _SET(update_pts_force);
+ _SET(seek);
+ _SET(tell_position);
+ _SET(tell_position_time);
+ _SET(tell_current_time);
+ _SET(tell_total_time);
+ _SET(store_info);
+ _SET(store_allInfo);
+ _SET(load_info);
+ _SET(load_allInfo);
+ _SET(delete);
+ _SET(ongoing);
+ _SET(get_cur_segment_size);
+ _SET(get_cur_segment_id);
+ #undef _SET
+ }
+ return DVR_SUCCESS;
+}
+
static int record_is_valid_pid(DVR_RecordContext_t *p_ctx, int pid)
{
int i;
@@ -114,6 +188,8 @@
int pid;
int adp_field_len;
+ SEG_CALL_INIT(&p_ctx->segment_ops);
+
pid = ((p[1] & 0x1f) << 8) | p[2];
if (pid == 0x1fff || !record_is_valid_pid(p_ctx, pid))
return has_pcr;
@@ -156,7 +232,8 @@
p_ctx->check_pts_count ++;
}
p_ctx->pts = pcr/90;
- segment_update_pts(p_ctx->segment_handle, pcr/90, pos);
+
+ SEG_CALL(update_pts, (p_ctx->segment_handle, pcr/90, pos));
}
return has_pcr;
}
@@ -168,7 +245,13 @@
loff_t pos;
int has_pcr = 0;
- pos = segment_tell_position(p_ctx->segment_handle);
+ SEG_CALL_INIT(&p_ctx->segment_ops);
+
+ SEG_CALL_RET_VALID(tell_position, (p_ctx->segment_handle), pos, -1);
+
+ if (pos == -1)
+ return has_pcr;
+
if (pos >= len) {
pos = pos - len;
}
@@ -212,6 +295,8 @@
DVR_NewDmxSecureBuffer_t new_dmx_secure_buf;
int first_read = 0;
+ SEG_CALL_INIT(&p_ctx->segment_ops);
+
prctl(PR_SET_NAME,"DvrRecording");
// Force to use LOCAL_CLOCK as index type if force_sysclock is on. Please
@@ -296,6 +381,7 @@
guarded_size_exceeded = DVR_TRUE;
}
/* Got data from device, record it */
+ ret = 0;
if (guarded_size_exceeded) {
len = 0;
ret = 0;
@@ -334,7 +420,7 @@
gettimeofday(&t3, NULL);
/* Out buffer length may not equal in buffer length */
if (crypto_params.output_size > 0) {
- ret = segment_write(p_ctx->segment_handle, buf_out, crypto_params.output_size);
+ SEG_CALL_RET(write, (p_ctx->segment_handle, buf_out, crypto_params.output_size), ret);
len = crypto_params.output_size;
} else {
len = 0;
@@ -345,14 +431,14 @@
am_crypt_des_crypt(p_ctx->cryptor, buf_out, buf, &crypt_len, 0);
len = crypt_len;
gettimeofday(&t3, NULL);
- ret = segment_write(p_ctx->segment_handle, buf_out, len);
+ SEG_CALL_RET(write, (p_ctx->segment_handle, buf_out, len), ret);
} else {
if (first_read == 0) {
first_read = 1;
DVR_INFO("%s:%d,first read ts", __func__,__LINE__);
}
gettimeofday(&t3, NULL);
- ret = segment_write(p_ctx->segment_handle, buf, len);
+ SEG_CALL_RET(write, (p_ctx->segment_handle, buf, len), ret);
}
gettimeofday(&t4, NULL);
//add DVR_RECORD_EVENT_WRITE_ERROR event if write error
@@ -367,10 +453,11 @@
DVR_INFO("%s,write error %d", __func__,__LINE__);
goto end;
}
- if (len>0) {
+
+ if (len > 0 && SEG_CALL_IS_VALID(tell_position)) {
/* Do time index */
uint8_t *index_buf = (p_ctx->enc_func || p_ctx->cryptor)? buf_out : buf;
- pos = segment_tell_position(p_ctx->segment_handle);
+ SEG_CALL_RET(tell_position, (p_ctx->segment_handle), pos);
has_pcr = record_do_pcr_index(p_ctx, index_buf, len);
if (has_pcr == 0 && p_ctx->index_type == DVR_INDEX_TYPE_INVALID) {
clock_gettime(CLOCK_MONOTONIC, &end_ts);
@@ -405,28 +492,30 @@
/*Duration need use pcr to calculate, todo...*/
if (p_ctx->index_type == DVR_INDEX_TYPE_PCR) {
- p_ctx->segment_info.duration = segment_tell_total_time(p_ctx->segment_handle);
+ SEG_CALL_RET(tell_total_time, (p_ctx->segment_handle), p_ctx->segment_info.duration);
if (pre_time == 0)
- pre_time = p_ctx->segment_info.duration;
+ pre_time = p_ctx->segment_info.duration;
} else if (p_ctx->index_type == DVR_INDEX_TYPE_LOCAL_CLOCK) {
clock_gettime(CLOCK_MONOTONIC, &end_ts);
p_ctx->segment_info.duration = (end_ts.tv_sec*1000 + end_ts.tv_nsec/1000000) -
(start_ts.tv_sec*1000 + start_ts.tv_nsec/1000000) + pcr_rec_len;
if (pre_time == 0)
pre_time = p_ctx->segment_info.duration;
- segment_update_pts(p_ctx->segment_handle, p_ctx->segment_info.duration, pos);
+ SEG_CALL(update_pts, (p_ctx->segment_handle, p_ctx->segment_info.duration, pos));
} else {
DVR_INFO("%s can NOT do time index", __func__);
}
if (p_ctx->index_type == DVR_INDEX_TYPE_PCR &&
p_ctx->check_pts_count == CHECK_PTS_MAX_COUNT) {
- DVR_INFO("%s change time from pcr to local time", __func__);
- if (pcr_rec_len == 0)
- pcr_rec_len = segment_tell_total_time(p_ctx->segment_handle);
- p_ctx->index_type = DVR_INDEX_TYPE_LOCAL_CLOCK;
- if (pcr_rec_len == 0)
- pcr_rec_len = segment_tell_total_time(p_ctx->segment_handle);
- clock_gettime(CLOCK_MONOTONIC, &start_ts);
+ DVR_INFO("%s change time from pcr to local time", __func__);
+ if (pcr_rec_len == 0) {
+ SEG_CALL_RET(tell_total_time, (p_ctx->segment_handle), pcr_rec_len);
+ }
+ p_ctx->index_type = DVR_INDEX_TYPE_LOCAL_CLOCK;
+ if (pcr_rec_len == 0) {
+ SEG_CALL_RET(tell_total_time, (p_ctx->segment_handle), pcr_rec_len);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &start_ts);
}
if (p_ctx->index_type == DVR_INDEX_TYPE_PCR ) {
@@ -435,8 +524,9 @@
(int)(start_no_pcr_ts.tv_sec*1000 + start_no_pcr_ts.tv_nsec/1000000);
if (diff > 3000) {
DVR_INFO("%s no pcr change time from pcr to local time diff[%d]", __func__, diff);
- if (pcr_rec_len == 0)
- pcr_rec_len = segment_tell_total_time(p_ctx->segment_handle);
+ if (pcr_rec_len == 0) {
+ SEG_CALL_RET(tell_total_time, (p_ctx->segment_handle), pcr_rec_len);
+ }
p_ctx->index_type = DVR_INDEX_TYPE_LOCAL_CLOCK;
}
}
@@ -445,9 +535,10 @@
if (p_ctx->segment_info.duration - pre_time > DVR_STORE_INFO_TIME) {
pre_time = p_ctx->segment_info.duration + DVR_STORE_INFO_TIME;
time_t duration = p_ctx->segment_info.duration;
- if (p_ctx->index_type == DVR_INDEX_TYPE_LOCAL_CLOCK)
- p_ctx->segment_info.duration = segment_tell_total_time(p_ctx->segment_handle);
- segment_store_info(p_ctx->segment_handle, &(p_ctx->segment_info));
+ if (p_ctx->index_type == DVR_INDEX_TYPE_LOCAL_CLOCK) {
+ SEG_CALL_RET(tell_total_time, (p_ctx->segment_handle), p_ctx->segment_info.duration);
+ }
+ SEG_CALL(store_info, (p_ctx->segment_handle, &p_ctx->segment_info));
p_ctx->segment_info.duration = duration;
}
} else {
@@ -472,9 +563,9 @@
p_ctx->last_send_time = p_ctx->segment_info.duration;
record_status.state = p_ctx->state;
record_status.info.id = p_ctx->segment_info.id;
- if (p_ctx->index_type == DVR_INDEX_TYPE_LOCAL_CLOCK)
- record_status.info.duration = segment_tell_total_time(p_ctx->segment_handle);
- else
+ if (p_ctx->index_type == DVR_INDEX_TYPE_LOCAL_CLOCK) {
+ SEG_CALL_RET(tell_total_time, (p_ctx->segment_handle), record_status.info.duration);
+ } else
record_status.info.duration = p_ctx->segment_info.duration;
record_status.info.size = p_ctx->segment_info.size;
record_status.info.nb_packets = p_ctx->segment_info.size/188;
@@ -583,6 +674,10 @@
}
p_ctx->discard_coming_data = DVR_FALSE;
DVR_INFO("%s, block_size:%d is_new:%d", __func__, p_ctx->block_size, p_ctx->is_new_dmx);
+
+ record_set_segment_ops(p_ctx, params->flags);
+ INIT_LIST_HEAD(&p_ctx->segment_ctrls);
+
*p_handle = p_ctx;
return DVR_SUCCESS;
}
@@ -614,6 +709,17 @@
DVR_INFO("%s, failed", __func__);
}
}
+
+ if (!list_empty(&p_ctx->segment_ctrls)) {
+ DVR_Control_t *pc, *pc_tmp;
+ list_for_each_entry_safe(pc, pc_tmp, &p_ctx->segment_ctrls, head) {
+ list_del(&pc->head);
+ if (pc->data)
+ free(pc->data);
+ free(pc);
+ }
+ }
+
memset(p_ctx, 0, sizeof(DVR_RecordContext_t));
p_ctx->state = DVR_RECORD_STATE_CLOSED;
return ret;
@@ -691,20 +797,33 @@
}
DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]);
+ SEG_CALL_INIT(&p_ctx->segment_ops);
+
DVR_INFO("%s , current state:%d pids:%d params->location:%s", __func__, p_ctx->state, params->segment.nb_pids, params->location);
DVR_RETURN_IF_FALSE(p_ctx->state != DVR_RECORD_STATE_STARTED);
DVR_RETURN_IF_FALSE(p_ctx->state != DVR_RECORD_STATE_CLOSED);
DVR_RETURN_IF_FALSE(params);
-
DVR_RETURN_IF_FALSE(strlen((const char *)params->location) < DVR_MAX_LOCATION_SIZE);
- memset(&open_params, 0, sizeof(open_params));
- memcpy(open_params.location, params->location, sizeof(params->location));
- open_params.segment_id = params->segment.segment_id;
- open_params.mode = SEGMENT_MODE_WRITE;
- open_params.force_sysclock = p_ctx->force_sysclock;
- ret = segment_open(&open_params, &p_ctx->segment_handle);
- DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
+ if (SEG_CALL_IS_VALID(open)) {
+ memset(&open_params, 0, sizeof(open_params));
+
+ memcpy(open_params.location, params->location, sizeof(params->location));
+ open_params.segment_id = params->segment.segment_id;
+ open_params.mode = SEGMENT_MODE_WRITE;
+ open_params.force_sysclock = p_ctx->force_sysclock;
+
+ SEG_CALL_RET(open, (&open_params, &p_ctx->segment_handle), ret);
+ DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
+
+ if (SEG_CALL_IS_VALID(ioctl)) {
+ DVR_Control_t *pc;
+ list_for_each_entry(pc, &p_ctx->segment_ctrls, head) {
+ SEG_CALL_RET(ioctl, (p_ctx->segment_handle, pc->cmd, pc->data, pc->size), ret);
+ DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
+ }
+ }
+ }
/*process params*/
{
@@ -728,7 +847,7 @@
DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
}
- ret = segment_store_info(p_ctx->segment_handle, &p_ctx->segment_info);
+ SEG_CALL_RET(store_info, (p_ctx->segment_handle, &p_ctx->segment_info), ret);
DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
p_ctx->state = DVR_RECORD_STATE_STARTED;
@@ -760,6 +879,8 @@
DVR_RETURN_IF_FALSE(p_info);
DVR_RETURN_IF_FALSE(!p_ctx->is_vod);
+ SEG_CALL_INIT(&p_ctx->segment_ops);
+
/*Stop the on going record segment*/
//ret = record_device_stop(p_ctx->dev_handle);
//DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
@@ -767,33 +888,45 @@
pthread_join(p_ctx->thread, NULL);
//add index file store
- pos = segment_tell_position(p_ctx->segment_handle);
- segment_update_pts_force(p_ctx->segment_handle, p_ctx->segment_info.duration, pos);
+ if (SEG_CALL_IS_VALID(update_pts_force)) {
+ SEG_CALL_RET_VALID(tell_position, (p_ctx->segment_handle), pos, -1);
+ if (pos != -1) {
+ SEG_CALL(update_pts_force, (p_ctx->segment_handle, p_ctx->segment_info.duration, pos));
+ }
+ }
- p_ctx->segment_info.duration = segment_tell_total_time(p_ctx->segment_handle);
+ SEG_CALL_RET(tell_total_time, (p_ctx->segment_handle), p_ctx->segment_info.duration);
+
/*Update segment info*/
memcpy(p_info, &p_ctx->segment_info, sizeof(p_ctx->segment_info));
- ret = segment_store_info(p_ctx->segment_handle, p_info);
+ SEG_CALL_RET(store_info, (p_ctx->segment_handle, p_info), ret);
DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
- segment_store_allInfo(p_ctx->segment_handle, p_info);
+
+ SEG_CALL(store_allInfo, (p_ctx->segment_handle, p_info));
+
DVR_INFO("%s dump segment info, id:%lld, nb_pids:%d, duration:%ld ms, size:%zu, nb_packets:%d params->segment.nb_pids:%d",
__func__, p_info->id, p_info->nb_pids, p_info->duration, p_info->size, p_info->nb_packets, params->segment.nb_pids);
/*Close current segment*/
- ret = segment_close(p_ctx->segment_handle);
+ SEG_CALL_RET(close, (p_ctx->segment_handle), ret);
DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
- /*Open the new record segment*/
- memset(&open_params, 0, sizeof(open_params));
- memcpy(open_params.location, p_ctx->location, sizeof(p_ctx->location));
- open_params.segment_id = params->segment.segment_id;
- open_params.mode = SEGMENT_MODE_WRITE;
- open_params.force_sysclock = p_ctx->force_sysclock;
- DVR_INFO("%s: p_ctx->location:%s params->location:%s", __func__, p_ctx->location,params->location);
+
p_ctx->last_send_size = 0;
p_ctx->last_send_time = 0;
- ret = segment_open(&open_params, &p_ctx->segment_handle);
- DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
+
+ /*Open the new record segment*/
+ if (SEG_CALL_IS_VALID(open)) {
+ memset(&open_params, 0, sizeof(open_params));
+ memcpy(open_params.location, p_ctx->location, sizeof(p_ctx->location));
+ open_params.segment_id = params->segment.segment_id;
+ open_params.mode = SEGMENT_MODE_WRITE;
+ open_params.force_sysclock = p_ctx->force_sysclock;
+ DVR_INFO("%s: p_ctx->location:%s params->location:%s", __func__, p_ctx->location,params->location);
+ SEG_CALL_RET(open, (&open_params, &p_ctx->segment_handle), ret);
+ DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
+ }
+
/*process params*/
{
//need all params??
@@ -830,11 +963,14 @@
//ret = record_device_start(p_ctx->dev_handle);
//DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
+
/*Update segment info*/
- ret = segment_store_info(p_ctx->segment_handle, &p_ctx->segment_info);
+ SEG_CALL_RET(store_info, (p_ctx->segment_handle, &p_ctx->segment_info), ret);
DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
- if (p_ctx->pts != ULLONG_MAX)
- segment_update_pts(p_ctx->segment_handle, p_ctx->pts, 0);
+
+ if (p_ctx->pts != ULLONG_MAX) {
+ SEG_CALL(update_pts, (p_ctx->segment_handle, p_ctx->pts, 0));
+ }
p_ctx->state = DVR_RECORD_STATE_STARTED;
pthread_create(&p_ctx->thread, NULL, record_thread, p_ctx);
@@ -846,7 +982,7 @@
DVR_RecordContext_t *p_ctx;
int ret = DVR_SUCCESS;
uint32_t i;
- loff_t pos;
+ loff_t pos = 0;
p_ctx = (DVR_RecordContext_t *)handle;
for (i = 0; i < MAX_DVR_RECORD_SESSION_COUNT; i++) {
@@ -866,9 +1002,10 @@
DVR_RETURN_IF_FALSE(p_ctx->state != DVR_RECORD_STATE_CLOSED);
DVR_RETURN_IF_FALSE(p_info);/*should support NULL*/
+ SEG_CALL_INIT(&p_ctx->segment_ops);
+
p_ctx->state = DVR_RECORD_STATE_STOPPED;
if (p_ctx->is_vod) {
- p_ctx->segment_info.duration = segment_tell_total_time(p_ctx->segment_handle);
p_ctx->segment_info.duration = 10*1000; //debug, should delete it
} else {
pthread_join(p_ctx->thread, NULL);
@@ -880,27 +1017,32 @@
}
//add index file store
- pos = segment_tell_position(p_ctx->segment_handle);
- segment_update_pts_force(p_ctx->segment_handle, p_ctx->segment_info.duration, pos);
- p_ctx->segment_info.duration = segment_tell_total_time(p_ctx->segment_handle);
+ if (SEG_CALL_IS_VALID(update_pts_force)) {
+ SEG_CALL_RET_VALID(tell_position, (p_ctx->segment_handle), pos, -1);
+ if (pos != -1) {
+ SEG_CALL(update_pts_force, (p_ctx->segment_handle, p_ctx->segment_info.duration, pos));
+ }
+ }
+
+ SEG_CALL_RET(tell_total_time, (p_ctx->segment_handle), p_ctx->segment_info.duration);
/*Update segment info*/
memcpy(p_info, &p_ctx->segment_info, sizeof(p_ctx->segment_info));
- ret = segment_store_info(p_ctx->segment_handle, p_info);
- //DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
+ SEG_CALL_RET(store_info, (p_ctx->segment_handle, p_info), ret);
if (ret != DVR_SUCCESS)
- goto end;
+ goto end;
- segment_store_allInfo(p_ctx->segment_handle, p_info);
+ SEG_CALL(store_allInfo, (p_ctx->segment_handle, p_info));
DVR_INFO("%s dump segment info, id:%lld, nb_pids:%d, duration:%ld ms, size:%zu, nb_packets:%d",
__func__, p_info->id, p_info->nb_pids, p_info->duration, p_info->size, p_info->nb_packets);
end:
- ret = segment_close(p_ctx->segment_handle);
+ SEG_CALL_RET(close, (p_ctx->segment_handle), ret);
p_ctx->segment_handle = NULL;
DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
+
return DVR_SUCCESS;
}
@@ -955,7 +1097,6 @@
{
DVR_RecordContext_t *p_ctx;
uint32_t i;
- off_t pos = 0;
int ret = DVR_SUCCESS;
int has_pcr;
@@ -968,13 +1109,14 @@
DVR_RETURN_IF_FALSE(buffer);
DVR_RETURN_IF_FALSE(len);
- pos = segment_tell_position(p_ctx->segment_handle);
+ SEG_CALL_INIT(&p_ctx->segment_ops);
+
has_pcr = record_do_pcr_index(p_ctx, buffer, len);
if (has_pcr == 0) {
/* Pull VOD record should use PCR time index */
DVR_INFO("%s has no pcr, can NOT do time index", __func__);
}
- ret = segment_write(p_ctx->segment_handle, buffer, len);
+ SEG_CALL_RET(write, (p_ctx->segment_handle, buffer, len), ret);
if (ret != len) {
DVR_INFO("%s write error ret:%d len:%d", __func__, ret, len);
}
@@ -1077,3 +1219,47 @@
return DVR_TRUE;
}
+
+int dvr_record_ioctl(DVR_RecordHandle_t handle, unsigned int cmd, void *data, size_t size)
+{
+ DVR_RecordContext_t *p_ctx;
+ int ret = DVR_FAILURE;
+ int i;
+
+ p_ctx = (DVR_RecordContext_t *)handle;
+ for (i = 0; i < MAX_DVR_RECORD_SESSION_COUNT; i++) {
+ if (p_ctx == &record_ctx[i])
+ break;
+ }
+ DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]);
+
+ SEG_CALL_INIT(&p_ctx->segment_ops);
+
+ if (SEG_CALL_IS_VALID(ioctl)) {
+ if (p_ctx->segment_handle) {
+ SEG_CALL_RET(ioctl, (p_ctx->segment_handle, cmd, data, size), ret);
+ } else {
+ DVR_Control_t *ctrl = (DVR_Control_t *)calloc(1, sizeof(DVR_Control_t));
+ if (ctrl) {
+ ctrl->cmd = cmd;
+ if (size) {
+ void *pdata = malloc(size);
+ if (pdata) {
+ memcpy(pdata, data, size);
+ ctrl->data = pdata;
+ ctrl->size = size;
+ } else {
+ free(ctrl);
+ ctrl = NULL;
+ }
+ }
+ }
+ if (ctrl) {
+ list_add_tail(&ctrl->head, &p_ctx->segment_ctrls);
+ ret = DVR_SUCCESS;
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/src/dvr_segment.c b/src/dvr_segment.c
index 7c39a64..db512b7 100644
--- a/src/dvr_segment.c
+++ b/src/dvr_segment.c
@@ -87,18 +87,17 @@
DIR *dir; // pointer to directory
struct dirent *entry; // pointer to file entry
- char *ext; // pointer to file extension
- char *loc_dname;
- int loc_dname_len;
- char *loc_fname;
- int loc_fname_len;
- char *path;
- int path_size;
+ char *loc_dname = NULL;
+ int loc_dname_len = 0;
+ char *loc_fname = NULL;
+ int loc_fname_len = 0;
+ char *path = NULL;
+ int path_size = 0;
/*get the dirname and filename*/
loc_fname = strrchr(location, '/');// fine last slash
- loc_fname_len = strlen(loc_fname);
if (loc_fname) {// skip the slash
+ loc_fname_len = strlen(loc_fname);
loc_fname += 1;
loc_fname_len -= 1;
}
diff --git a/src/dvr_wrapper.c b/src/dvr_wrapper.c
index 818b8d5..6bd0c31 100644
--- a/src/dvr_wrapper.c
+++ b/src/dvr_wrapper.c
@@ -3163,3 +3163,25 @@
return dvr_prop_read(prop_name,prop_value,length);
}
+int dvr_wrapper_ioctl_record(DVR_WrapperRecord_t rec, unsigned int cmd, void *data, size_t size)
+{
+ DVR_WrapperCtx_t *ctx;
+ int error;
+
+ DVR_RETURN_IF_FALSE(rec);
+
+ ctx = ctx_getRecord((unsigned long)rec);
+ DVR_RETURN_IF_FALSE(ctx);
+
+ wrapper_mutex_lock(&ctx->wrapper_lock);
+ DVR_WRAPPER_INFO("libdvr_api, ioctl_record (sn:%ld) cmd:%#x data:%p", ctx->sn, cmd, data);
+ WRAPPER_RETURN_IF_FALSE_WITH_UNLOCK(ctx_valid(ctx), &ctx->wrapper_lock);
+
+ error = dvr_record_ioctl(ctx->record.recorder, cmd, data, size);
+
+ DVR_WRAPPER_INFO("record(sn:%ld) ioctl_record = (%d)\n", ctx->sn, error);
+ wrapper_mutex_unlock(&ctx->wrapper_lock);
+
+ return error;
+
+}
diff --git a/src/segment_dataout.c b/src/segment_dataout.c
new file mode 100644
index 0000000..bad2928
--- /dev/null
+++ b/src/segment_dataout.c
@@ -0,0 +1,139 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "dvr_types.h"
+#include "segment_dataout.h"
+
+
+/**\brief Segment context*/
+typedef struct {
+ uint64_t segment_id;
+
+ uint64_t cur_time;
+ uint64_t size_written;
+ uint64_t pkts_written;
+
+ Segment_DataoutCallback_t dataout_callback;
+} Segment_Context_t;
+
+int segment_dataout_open(Segment_OpenParams_t *params, Segment_Handle_t *p_handle)
+{
+ Segment_Context_t *p_ctx;
+
+ DVR_RETURN_IF_FALSE(params);
+ DVR_RETURN_IF_FALSE(p_handle);
+
+ p_ctx = (void*)malloc(sizeof(Segment_Context_t));
+ DVR_RETURN_IF_FALSE(p_ctx);
+
+ memset(p_ctx, 0, sizeof(Segment_Context_t));
+
+ p_ctx->segment_id = params->segment_id;
+
+ *p_handle = (Segment_Handle_t)p_ctx;
+ return DVR_SUCCESS;
+}
+
+int segment_dataout_close(Segment_Handle_t handle)
+{
+ Segment_Context_t *p_ctx = (void *)handle;
+
+ DVR_RETURN_IF_FALSE(p_ctx);
+
+ free(p_ctx);
+ return DVR_SUCCESS;
+}
+
+int segment_dataout_ioctl(Segment_Handle_t handle, int cmd, void *data, size_t size)
+{
+ Segment_Context_t *p_ctx = (void *)handle;
+
+ DVR_RETURN_IF_FALSE(p_ctx);
+
+ switch (cmd) {
+ case SEGMENT_DATAOUT_CMD_SET_CALLBACK:
+ DVR_RETURN_IF_FALSE(data != NULL);
+ p_ctx->dataout_callback = *(Segment_DataoutCallback_t *)data;
+ break;
+
+ default:
+ return DVR_FAILURE;
+ }
+ return DVR_SUCCESS;
+}
+
+ssize_t segment_dataout_write(Segment_Handle_t handle, void *buf, size_t count)
+{
+ ssize_t len = 0;
+ Segment_Context_t *p_ctx = (Segment_Context_t *)handle;
+
+ DVR_RETURN_IF_FALSE(p_ctx);
+ DVR_RETURN_IF_FALSE(buf);
+
+ if (p_ctx->dataout_callback.callback)
+ len = p_ctx->dataout_callback.callback(buf, count, p_ctx->dataout_callback.priv);
+
+ p_ctx->size_written += count;
+
+ return count;
+}
+
+loff_t segment_dataout_tell_total_time(Segment_Handle_t handle)
+{
+ uint64_t pts = ULLONG_MAX;
+ Segment_Context_t *p_ctx = (Segment_Context_t *)handle;
+
+ DVR_RETURN_IF_FALSE(p_ctx);
+
+ pts = p_ctx->cur_time;
+
+ return pts;
+}
+
+int segment_dataout_store_info(Segment_Handle_t handle, Segment_StoreInfo_t *p_info)
+{
+ Segment_Context_t *p_ctx = (Segment_Context_t *)handle;
+
+ DVR_RETURN_IF_FALSE(p_ctx);
+ DVR_RETURN_IF_FALSE(p_info);
+
+ p_ctx->segment_id = p_info->id;
+ p_ctx->cur_time = p_info->duration;
+ p_ctx->size_written = p_info->size;
+ p_ctx->pkts_written = p_info->nb_packets;
+
+ return DVR_SUCCESS;
+}
+
+int segment_dataout_store_allInfo(Segment_Handle_t handle, Segment_StoreInfo_t *p_info)
+{
+ return segment_dataout_store_info(handle, p_info);
+}
+
+
+int segment_dataout_update_pts_force(Segment_Handle_t handle, uint64_t pts, loff_t offset)
+{
+ Segment_Context_t *p_ctx = (Segment_Context_t *)handle;
+ DVR_RETURN_IF_FALSE(p_ctx);
+
+ if (offset == p_ctx->size_written)
+ p_ctx->cur_time = pts;
+ return DVR_SUCCESS;
+}
+
+int segment_dataout_update_pts(Segment_Handle_t handle, uint64_t pts, loff_t offset)
+{
+ return segment_dataout_update_pts_force(handle, pts, offset);
+}
+
+loff_t segment_dataout_tell_position(Segment_Handle_t handle)
+{
+ loff_t pos;
+ Segment_Context_t *p_ctx = (Segment_Context_t *)handle;
+
+ DVR_RETURN_IF_FALSE(p_ctx);
+
+ pos = p_ctx->size_written;
+
+ return pos;
+}
diff --git a/test/dvr_wrapper_test/Android.bp b/test/dvr_wrapper_test/Android.bp
index 198b17f..83cd0b4 100644
--- a/test/dvr_wrapper_test/Android.bp
+++ b/test/dvr_wrapper_test/Android.bp
@@ -35,3 +35,36 @@
"vendor/amlogic/common/mediahal_sdk/include",
],
}
+
+cc_binary {
+ name: "dvr_wrapper_test.dataout",
+ proprietary: true,
+ compile_multilib: "32",
+
+ arch: {
+ x86: {
+ enabled: false,
+ },
+ x86_64: {
+ enabled: false,
+ },
+ },
+
+ srcs: [
+ "dvr_wrapper_test.dataout.c"
+ ],
+
+ shared_libs: [
+ "libutils",
+ "libcutils",
+ "liblog",
+ "libdl",
+ "libc",
+ "libamdvr",
+ ],
+
+ include_dirs: [
+ "hardware/amlogic/media/amcodec/include",
+ "vendor/amlogic/common/mediahal_sdk/include",
+ ],
+}
diff --git a/test/dvr_wrapper_test/dvr_wrapper_test.dataout.c b/test/dvr_wrapper_test/dvr_wrapper_test.dataout.c
new file mode 100644
index 0000000..4ad3561
--- /dev/null
+++ b/test/dvr_wrapper_test/dvr_wrapper_test.dataout.c
@@ -0,0 +1,268 @@
+/**
+ * \page dvb_wrapper_test
+ * \section Introduction
+ * test code with dvb_wrapper_xxxx APIs.
+ * It supports:
+ * \li Record
+ *
+ * \section Usage
+ *
+ * Help msg will be shown if the test runs without parameters.\n
+ * There are some general concepts for the parameters:
+ * \li assign value "1" to the parameter to enable a feature specified
+ * \li millisecond is used as time unit
+ * \li no limit to the parameter order
+ *
+ * For recording:
+ * \code
+ * dvr_wrapper_test.dataout [tsin=n] [dataout=<stdout>]
+ * \endcode
+ *
+ * \section ops Operations in the test:
+ * \li quit\n
+ * quit the test
+ * \endsection
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include "dvr_segment.h"
+#include "dvr_wrapper.h"
+#include "dvb_utils.h"
+#include "segment_dataout.h"
+
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+#define DMX_DEV_DVR 1
+
+#define REC_EVT(fmt, ...) fprintf(stderr, "recorder:" fmt, ##__VA_ARGS__)
+#define INF(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
+#define ERR(fmt, ...) fprintf(stderr, "error:" fmt, ##__VA_ARGS__)
+#define RESULT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
+
+static int ts_src=0;
+static FILE *dataout = NULL;
+static int flush_size = 10* 188 * 1024;
+static DVR_WrapperRecord_t recorder;
+
+
+static void display_usage(void)
+{
+ INF( "==================\n");
+ INF( "*quit\n");
+ INF( "==================\n");
+}
+
+int start_test(void)
+{
+ DVR_Bool_t go = DVR_TRUE;
+ char buf[256];
+
+ display_usage();
+
+ while (go) {
+ if (fgets(buf, sizeof(buf), stdin)) {
+
+ if (!strncmp(buf, "quit", 4)) {
+ go = DVR_FALSE;
+ continue;
+ }
+ else if (!strncmp(buf, "recpause", 8)) {
+ INF("rec paused.\n");
+ }
+ else if (!strncmp(buf, "recresume", 9)) {
+ INF("rec resumed.\n");
+ }
+ else {
+ ERR("Unknown command: %s\n", buf);
+ display_usage();
+ }
+ }
+ }
+
+ if (dataout && dataout != stdout) {
+ fclose(dataout);
+ dataout = NULL;
+ }
+
+ return 0;
+}
+
+static void log_rec_evt(DVR_WrapperRecordStatus_t *status, void *user)
+{
+ char *state[] = {
+ /*DVR_RECORD_STATE_OPENED*/ "open", /**< Record state is opened*/
+ /*DVR_RECORD_STATE_STARTED*/"start", /**< Record state is started*/
+ /*DVR_RECORD_STATE_STOPPED*/"stop", /**< Record state is stopped*/
+ /*DVR_RECORD_STATE_CLOSED*/ "close", /**< Record state is closed*/
+ };
+ REC_EVT("[%s] state[%s(0x%x)] time/size/pkts[%lu/%llu/%u]\n",
+ (char *)user,
+ state[status->state],
+ status->state,
+ status->info.time,
+ status->info.size,
+ status->info.pkts
+ );
+}
+
+static DVR_Result_t RecEventHandler(DVR_RecordEvent_t event, void *params, void *userdata)
+{
+ if (userdata != NULL)
+ {
+ DVR_WrapperRecordStatus_t *status = (DVR_WrapperRecordStatus_t *)params;
+
+ switch (event)
+ {
+ case DVR_RECORD_EVENT_STATUS:
+ log_rec_evt(status, userdata);
+ break;
+ default:
+ REC_EVT("Unhandled recording event 0x%x from (%s)\n", event, (char *)userdata);
+ break;
+ }
+ }
+ return DVR_SUCCESS;
+}
+
+static int data_cb(unsigned char *buf, size_t size, void *priv)
+{
+ INF("data(%d) priv(%s): %02x %02x %02x %02x\n", size, (char *)priv, buf[0], buf[1], buf[2], buf[3]);
+
+ if (dataout)
+ fwrite(buf, size, 1, dataout);
+
+ return size;
+}
+
+static int start_recording()
+{
+ DVR_WrapperRecordOpenParams_t rec_open_params;
+ DVR_WrapperRecordStartParams_t rec_start_params;
+ DVR_WrapperPidsInfo_t *pids_info;
+ char cmd[256];
+ int error = 0;
+
+ sprintf(cmd, "echo ts%d > /sys/class/stb/demux%d_source", ts_src, DMX_DEV_DVR);
+ //system(cmd);
+
+ dvb_set_demux_source(DMX_DEV_DVR, ts_src);
+
+ memset(&rec_open_params, 0, sizeof(DVR_WrapperRecordOpenParams_t));
+
+ rec_open_params.dmx_dev_id = DMX_DEV_DVR;
+ rec_open_params.segment_size = 0;/*infinite*/
+ rec_open_params.max_size = 0;/*infinite*/
+ rec_open_params.max_time = 0;/*infinite*/
+ rec_open_params.event_fn = RecEventHandler;
+ rec_open_params.event_userdata = "rec0";
+ rec_open_params.flags = DVR_RECORD_FLAG_DATAOUT;
+ rec_open_params.force_sysclock = DVR_TRUE;
+ rec_open_params.flush_size = flush_size;
+ snprintf(rec_open_params.location, DVR_MAX_LOCATION_SIZE, "%s", "dataout");
+
+ error = dvr_wrapper_open_record(&recorder, &rec_open_params);
+ if (error) {
+ ERR( "recorder open fail = (0x%x)\n", error);
+ return -1;
+ }
+
+ INF( "Starting %s recording %p [%ld secs/%llu bytes]\n",
+ "dataout",
+ recorder,
+ rec_open_params.max_time,
+ rec_open_params.max_size);
+
+ Segment_DataoutCallback_t dataout = { data_cb, "datacb_priv"};
+ error = dvr_wrapper_ioctl_record(recorder, SEGMENT_DATAOUT_CMD_SET_CALLBACK, &dataout, sizeof(dataout));
+ if (error) {
+ INF("Set dataout callback fail = (%#x)", error);
+ dvr_wrapper_close_record(recorder);
+ return -1;
+ }
+
+ memset(&rec_start_params, 0, sizeof(rec_start_params));
+
+ pids_info = &rec_start_params.pids_info;
+ pids_info->nb_pids = 1;
+ pids_info->pids[0].pid = 0x2000;
+ pids_info->pids[0].type = DVR_STREAM_TYPE_OTHER << 24;
+ error = dvr_wrapper_start_record(recorder, &rec_start_params);
+ if (error)
+ {
+ ERR( "recorder start fail = (0x%x)\n", error);
+ dvr_wrapper_close_record(recorder);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void usage(int argc, char *argv[])
+{
+ INF( "Usage: record : %s [tsin=n] [dataout=<stdout>]\n", argv[0]);
+}
+
+
+static void exit_helper() { if (dataout && dataout != stdout) fclose(dataout); }
+void sig_handler(int signo)
+{
+ if (signo == SIGTERM)
+ exit_helper();
+ exit(0);
+}
+
+int main(int argc, char **argv)
+{
+ int error;
+ int i;
+ int helper = 0;
+
+ for (i = 1; i < argc; i++) {
+ if (!strncmp(argv[i], "tsin", 4))
+ sscanf(argv[i], "tsin=%i", &ts_src);
+ else if (!strncmp(argv[i], "dataout=stdout", 14))
+ dataout = stdout;
+ else if (!strncmp(argv[i], "flush=", 6))
+ sscanf(argv[i], "flush=%i", &flush_size);
+ else if (!strncmp(argv[i], "help", 4)) {
+ usage(argc, argv);
+ exit(0);
+ }
+ }
+
+ if (argc == 1) {
+ usage(argc, argv);
+ exit(0);
+ }
+
+ if (helper) {
+ atexit(&exit_helper);
+ signal(SIGTERM, &sig_handler);
+ signal(SIGINT, &sig_handler);
+ }
+
+ error = start_recording();
+ if (error != 0) {
+ ERR("start_recording failed with return value %d",error);
+ }
+
+ //command loop
+ start_test();
+
+ error = dvr_wrapper_stop_record(recorder);
+ INF("stop record = (0x%x)\n", error);
+ error = dvr_wrapper_close_record(recorder);
+ INF("close record = (0x%x)\n", error);
+
+ return 0;
+}