amlv4l2dec: add a new interface for getting and sending cc data [1/1]

PD#SH-19658

Problem:
add a new interface for getting and sending cc data

Solution:
add the process for getting and sending cc data

Verify:
yocto-4.0-smarthome

Signed-off-by: zengliang.li <zengliang.li@amlogic.com>
Change-Id: If7a0d23e872a95b99df995e276a0204672577066
diff --git a/src/aml_v4l2_calls.c b/src/aml_v4l2_calls.c
index c0b7cb2..7f0411b 100644
--- a/src/aml_v4l2_calls.c
+++ b/src/aml_v4l2_calls.c
@@ -185,6 +185,11 @@
     if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_SUBSCRIBE_EVENT, &sub) < 0)
         goto failed;
 
+    sub.type = V4L2_EVENT_PRIVATE_EXT_REPORT_DECINFO;
+    sub.id = AML_DECINFO_EVENT_CC;
+    if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_SUBSCRIBE_EVENT, &sub) < 0)
+    goto failed;
+
     v4l2object->can_wait_event = TRUE;
 
     return TRUE;
@@ -193,7 +198,7 @@
 failed:
 {
     GST_WARNING_OBJECT(e, "Cannot subscribe V4L2_EVENT_SOURCE_CHANGE or "
-                          "V4L2_EVENT_EOS event for device '%s'.",
+                          "V4L2_EVENT_EOS or V4L2_EVENT_PRIVATE_EXT_REPORT_DECINFO event for device '%s'.",
                        v4l2object->videodev);
     return TRUE;
 }
diff --git a/src/ext/videodev2.h b/src/ext/videodev2.h
index 9530213..15dfdfc 100644
--- a/src/ext/videodev2.h
+++ b/src/ext/videodev2.h
@@ -172,6 +172,20 @@
     V4L2_TUNER_RF = 5,
 };
 
+enum E_DECINFO_EVENT {
+    AML_DECINFO_EVENT_STREAM = 0,
+    AML_DECINFO_EVENT_STATISTIC,
+    AML_DECINFO_EVENT_AFD,
+    AML_DECINFO_EVENT_CC,
+    AML_DECINFO_EVENT_HDR10,
+    AML_DECINFO_EVENT_HDR10P,
+    AML_DECINFO_EVENT_CUVA,
+    AML_DECINFO_EVENT_DV,
+    AML_DECINFO_EVENT_FRAME,
+    AML_DECINFO_EVENT_COMPOSITE = 30,
+    AML_DECINFO_EVENT_BOTTOM = 31,
+};
+
 /* Deprecated, do not use */
 #define V4L2_TUNER_ADC V4L2_TUNER_SDR
 
@@ -2308,6 +2322,9 @@
 #define V4L2_EVENT_SOURCE_CHANGE 5
 #define V4L2_EVENT_MOTION_DET 6
 #define V4L2_EVENT_PRIVATE_START 0x08000000
+#define V4L2_EVENT_PRIVATE_EXT_VSC_BASE (V4L2_EVENT_PRIVATE_START + 0x2000)
+#define V4L2_EVENT_PRIVATE_EXT_REPORT_DECINFO (V4L2_EVENT_PRIVATE_EXT_VSC_BASE + 4)
+
 
 /* Payload for V4L2_EVENT_VSYNC */
 struct v4l2_event_vsync
diff --git a/src/gstamlv4l2bufferpool.c b/src/gstamlv4l2bufferpool.c
index 3b95429..a4f0716 100644
--- a/src/gstamlv4l2bufferpool.c
+++ b/src/gstamlv4l2bufferpool.c
@@ -68,6 +68,178 @@
 static gboolean gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(GstBufferPool *bpool);
 #endif
 
+#define MAX_CC_LEN 72
+#ifndef V4L2_CID_USER_AMLOGIC_BASE
+#define V4L2_CID_USER_AMLOGIC_BASE (V4L2_CID_USER_BASE + 0x1100)
+#define AML_V4L2_GET_DECINFO_SET (V4L2_CID_USER_AMLOGIC_BASE + 13)
+#endif
+
+enum E_DECINFO_CMD_GET {
+AML_DECINFO_GET_STREAM_TYPE = 0,
+AML_DECINFO_GET_STATISTIC_TYPE,
+AML_DECINFO_GET_AFD_TYPE,
+AML_DECINFO_GET_CC_TYPE,
+AML_DECINFO_GET_HDR10_TYPE,
+AML_DECINFO_GET_HDR10P_TYPE,
+AML_DECINFO_GET_CUVA_TYPE,
+AML_DECINFO_GET_DV_TYPE,
+AML_DECINFO_GET_FRAME_TYPE,
+AML_DECINFO_GET_COMPOSITE_TYPE = 30,
+AML_DECINFO_GET_CMD_BOTTOM = 31,
+};
+
+struct v4l_userdata_meta_data_t {
+__u32 poc_number;
+__u16 flags;
+__u16 video_format;
+__u16 extension_data;
+__u16 frame_type;
+__u32 vpts;
+__u32 vpts_valid;
+__u64 timestamp;
+__u32 records_in_que;
+unsigned long long priv_data;
+__u32 padding_data[64];
+};
+
+struct sei_usd_param_s {
+__u32 info_type; /* CC or AFD or aux data*/
+__u32 data_size; /* size of the data domain */
+__u64 data; /* pointer to data domain */
+__u64 v_addr; /* used for kernelspace data */
+struct v4l_userdata_meta_data_t meta_data; /* meta_data */
+};
+
+enum E_ASPECT_RATIO {
+ASPECT_RATIO_4_3,
+ASPECT_RATIO_16_9,
+ASPECT_UNDEFINED = 255
+};
+
+struct aspect_ratio_size {
+__s32 sar_width;
+__s32 sar_height;
+__s32 dar_width;
+__s32 dar_height;
+};
+
+struct dec_stream_info_s {
+__u32 info_type;
+char vdec_name[32];
+__u32 vdec_type;
+__u32 dual_core_flag;
+__u32 is_secure;
+__u32 profile_idc;
+__u32 level_idc;
+__u32 filed_flag;
+__u32 frame_width;
+__u32 frame_height;
+__u32 crop_top;
+__u32 crop_bottom;
+__u32 crop_left;
+__u32 crop_right;
+__u32 frame_rate;
+__u32 fence_enable;
+__u32 fast_output_enable;
+__u32 trick_mode;
+__u32 bit_depth;
+__u32 double_write_mode;
+__u32 error_handle_policy;
+enum E_ASPECT_RATIO eu_aspect_ratio;
+struct aspect_ratio_size ratio_size;
+char reserved[64];
+};
+
+struct dec_statistics_info_s {
+__u32 info_ype;
+__u32 total_decoded_frames;
+__u32 error_frames;
+__u32 drop_frames;
+__u32 i_decoded_frames;
+__u32 i_drop_frames;
+__u32 i_error_frames;
+__u32 p_decoded_frames;
+__u32 p_drop_frames;
+__u32 p_error_frames;
+__u32 b_decoded_frames;
+__u32 b_drop_frames;
+__u32 b_error_frames;
+__u32 av_resynch_counter;
+__u64 total_decoded_datasize;
+char reserved[64];
+};
+
+struct vframe_qos_s {
+__u32 num;
+__u32 type;
+__u32 size;
+__u32 pts;
+int max_qp;
+int avg_qp;
+int min_qp;
+int max_skip;
+int avg_skip;
+int min_skip;
+int max_mv;
+int min_mv;
+int avg_mv;
+int decode_buffer;
+} /*vframe_qos */;
+
+struct dec_frame_info_s {
+__u32 info_type;
+struct vframe_qos_s qos; /* qos */
+__u32 num;
+__u32 type;
+__s32 frame_poc;
+__u32 decode_time_cost;
+__u32 pic_width;
+__u32 pic_height;
+__u32 error_flag;
+__u32 status;
+__u32 bitrate;
+__u32 field_output_order;
+__u32 offset;
+__u32 ratio_control;
+__u32 vf_type;
+__u32 signal_type;
+__u32 ext_signal_type;
+__u32 pts;
+__u64 pts_us64;
+__u64 timestamp;
+__u32 frame_size;
+char reserved[64];
+};
+
+struct aux_data_static_t {
+__u32 info_type; /* HDR10 HLG FMM or IMAX */
+struct aml_vdec_hdr_infos hdr_info;
+};
+
+struct v4l_dec_data_extension {
+ulong ptr; /* for future extension */
+__u32 data_size;
+};
+
+/**
+* struct vdec_common_s - Structure used to receive infos from decoder
+*/
+struct vdec_common_s {
+      __u32 version_magic;
+      __u32 vdec_id;
+      __u32 type;
+      union {
+            struct dec_stream_info_s stream_info;
+            struct dec_frame_info_s frame_info;
+            struct dec_statistics_info_s decoder_statistics;
+            struct sei_usd_param_s usd_param;
+            struct aux_data_static_t aux_data;
+            struct v4l_dec_data_extension data_ext;
+            char raw_data[512];
+      } u;
+      __u32 size;
+};
+
 static gboolean
 gst_aml_v4l2_is_buffer_valid(GstBuffer *buffer, GstAmlV4l2MemoryGroup **out_group)
 {
@@ -1384,6 +1556,61 @@
     case V4L2_EVENT_EOS:
         return GST_AML_V4L2_FLOW_LAST_BUFFER;
         break;
+    case V4L2_EVENT_PRIVATE_EXT_REPORT_DECINFO:
+        if (evt.id == AML_DECINFO_EVENT_CC)
+        {
+           struct v4l2_ext_control control;
+           struct v4l2_ext_controls ctrls;
+           struct vdec_common_s vdec_comm;
+           char cc_data[MAX_CC_LEN] = {0};
+
+           memset(&ctrls, 0, sizeof(ctrls));
+           memset(&control, 0, sizeof(control));
+           memset(&vdec_comm, 0, sizeof(vdec_comm));
+
+           vdec_comm.type = AML_DECINFO_GET_CC_TYPE;
+           vdec_comm.u.usd_param.data = (void *)cc_data;
+           vdec_comm.u.usd_param.data_size = MAX_CC_LEN;
+
+           control.ptr = &vdec_comm;
+           control.id = AML_V4L2_GET_DECINFO_SET;
+           control.size = sizeof(struct vdec_common_s);
+
+           ctrls.count = 1;
+           ctrls.controls = &control;
+
+           if (v4l2object->ioctl (pool->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
+           {
+               GST_DEBUG("VIDIOC_S_EXT_CTRLS fail");
+           }
+           else
+           {
+              if (v4l2object->ioctl (pool->video_fd, VIDIOC_G_EXT_CTRLS, &ctrls) == 0)
+              {
+                  GstBuffer *cc_buffer = gst_buffer_new ();
+                  GstMemory *mem = gst_allocator_alloc (NULL, MAX_CC_LEN, NULL);
+                  gst_buffer_insert_memory (cc_buffer, -1, mem);
+                  gsize cc_size = gst_buffer_fill (cc_buffer, 0, vdec_comm.u.usd_param.data, vdec_comm.u.usd_param.data_size);
+                  GST_DEBUG("copy cc data size:%d",cc_size);
+                  cc_buffer->pts = vdec_comm.u.usd_param.meta_data.timestamp;
+                  pool->cc_buffer_list = g_list_append (pool->cc_buffer_list,cc_buffer);
+                  GST_DEBUG("cc_buffer_list size:%d",g_list_length(pool->cc_buffer_list));
+                  #if 0
+                  //dump decoder metadata
+                  GST_DEBUG("cc pack pts:%lld",vdec_comm.u.usd_param.meta_data.timestamp);
+                  int fd=open("/data/test/cc0.data",O_RDWR |O_CREAT|O_APPEND,0777);
+                  write(fd,vdec_comm.u.usd_param.data,vdec_comm.u.usd_param.data_size);
+                  close(fd);
+                  #endif
+              }
+              else
+              {
+                  GST_DEBUG("VIDIOC_G_EXT_CTRLS fail");
+              }
+           }
+           return GST_AML_V4L2_FLOW_CC_DATA;
+        }
+        break;
     default:
         break;
     }
@@ -1987,6 +2214,12 @@
 {
     GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
 
+    if (g_list_length (pool->cc_buffer_list) > 0)
+    {
+        g_list_free_full (pool->cc_buffer_list, (GDestroyNotify) gst_buffer_unref);
+        pool->cc_buffer_list = NULL;
+    }
+
     if (pool->video_fd >= 0)
         pool->obj->close(pool->video_fd);
 
@@ -2014,6 +2247,7 @@
     pool->empty = TRUE;
     GST_OBJECT_UNLOCK(pool);
     pool->orphaned = FALSE;
+    pool->cc_buffer_list = NULL;
 }
 
 static void
diff --git a/src/gstamlv4l2bufferpool.h b/src/gstamlv4l2bufferpool.h
index f351944..8babf22 100644
--- a/src/gstamlv4l2bufferpool.h
+++ b/src/gstamlv4l2bufferpool.h
@@ -50,6 +50,8 @@
  * occure for mem-2-mem devices. */
 #define GST_AML_V4L2_FLOW_SOURCE_CHANGE GST_FLOW_CUSTOM_SUCCESS_2
 
+#define GST_AML_V4L2_FLOW_CC_DATA (GST_FLOW_CUSTOM_SUCCESS_2+1)
+
 #define GST_AML_SPEC_FLOW_FOR_VBP 1
 
 struct _GstAmlV4l2BufferPool
@@ -65,6 +67,8 @@
     gboolean empty;
     GCond empty_cond;
 
+    GList *cc_buffer_list;
+
     gboolean orphaned;
 
     GstAmlV4l2Allocator *vallocator;
diff --git a/src/gstamlv4l2object.c b/src/gstamlv4l2object.c
index b31af56..c1fad8b 100644
--- a/src/gstamlv4l2object.c
+++ b/src/gstamlv4l2object.c
@@ -413,11 +413,17 @@
                                                          "TRUE for stream mode, FALSE for frame mode",
                                                          FALSE,
                                                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
     g_object_class_install_property(gobject_class, PROP_LOW_LATENCY_MODE,
                                     g_param_spec_boolean("low-latency-mode", "set low latency mode",
                                                          "enable is TURE, disable is FALSE, default is disable",
                                                          FALSE,
                                                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+   g_object_class_install_property (gobject_class, PROP_CC_DATA,
+                                    g_param_spec_boolean ("enable-cc-data",
+                                                          "enable get cc data",
+                                                          "0: disable; 1: enable", FALSE, G_PARAM_READWRITE));
 }
 
 /* Support for 32bit off_t, this wrapper is casting off_t to gint64 */
@@ -487,6 +493,7 @@
     v4l2object->keep_aspect = TRUE;
     v4l2object->stream_mode = FALSE;
     v4l2object->have_set_par = FALSE;
+    v4l2object->enable_cc_data = FALSE;
 
     v4l2object->n_v4l2_planes = 0;
 
@@ -692,6 +699,10 @@
         v4l2object->low_latency_mode = g_value_get_boolean(value);
         GST_DEBUG_OBJECT(v4l2object, "set low latency: %d",v4l2object->low_latency_mode);
         break;
+    case PROP_CC_DATA:
+        v4l2object->enable_cc_data = g_value_get_boolean(value);
+        GST_DEBUG_OBJECT(v4l2object, "enable cc data: %d",v4l2object->enable_cc_data);
+        break;
     default:
         return FALSE;
         break;
@@ -796,6 +807,9 @@
     case PROP_STREAM_MODE:
         g_value_set_boolean(value, v4l2object->stream_mode);
         break;
+    case PROP_CC_DATA:
+        g_value_set_boolean(value, v4l2object->enable_cc_data);
+        break;
     default:
         return FALSE;
         break;
diff --git a/src/gstamlv4l2object.h b/src/gstamlv4l2object.h
index 8fe08d7..82c5ba1 100644
--- a/src/gstamlv4l2object.h
+++ b/src/gstamlv4l2object.h
@@ -202,6 +202,7 @@
     GValue *par;
     gboolean have_set_par;
     GValue *fps;
+    gboolean enable_cc_data;
 
     /* funcs */
     GstAmlV4l2GetInOutFunction get_in_out_func;
@@ -265,7 +266,8 @@
         PROP_FORCE_ASPECT_RATIO, \
         PROP_DUMP_FRAME_LOCATION, \
         PROP_STREAM_MODE, \
-        PROP_LOW_LATENCY_MODE
+        PROP_LOW_LATENCY_MODE, \
+        PROP_CC_DATA
 
 /* create/destroy */
 GstAmlV4l2Object *gst_aml_v4l2_object_new(GstElement *element,
diff --git a/src/gstamlv4l2videodec.c b/src/gstamlv4l2videodec.c
index 415b187..b528334 100644
--- a/src/gstamlv4l2videodec.c
+++ b/src/gstamlv4l2videodec.c
@@ -57,6 +57,8 @@
     }
 #endif
 
+#define GST_AML_V4L2_CC_IMPORT_QUARK gst_aml_v4l2_buffer_pool_cc_import_quark ()
+
 #ifndef ABSDIFF
 #define ABSDIFF(a,b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
 #endif
@@ -143,6 +145,13 @@
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         }
         break;
+    case PROP_CC_DATA:
+        if (!gst_aml_v4l2_object_set_property_helper(self->v4l2capture,
+                                                     prop_id, value, pspec))
+        {
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        }
+        break;
 #if GST_IMPORT_LGE_PROP
     case LGE_RESOURCE_INFO:
     {
@@ -210,7 +219,13 @@
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         }
         break;
-
+    case PROP_CC_DATA:
+        if (!gst_aml_v4l2_object_get_property_helper(self->v4l2capture,
+                                                     prop_id, value, pspec))
+        {
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        }
+        break;
 #if GST_IMPORT_LGE_PROP
     case LGE_DECODE_SIZE:
     {
@@ -949,6 +964,57 @@
     }
 }
 
+static GQuark
+gst_aml_v4l2_buffer_pool_cc_import_quark (void)
+{
+  static GQuark quark = 0;
+
+  if (quark == 0)
+    quark = g_quark_from_string ("GstAmlV4l2BufferPoolCcUsePtrData");
+
+  return quark;
+}
+
+static gboolean
+foreach_cc_buffer_list_match_pts_func(GList *list , GstVideoCodecFrame *frame)
+{
+    GList *l;
+    if (g_list_length (list) > 0)
+    {
+        for (l = list; l != NULL; l = l->next)
+        {
+            GstBuffer *cc_buffer = l->data;
+            if (GST_BUFFER_TIMESTAMP (frame->output_buffer) == GST_BUFFER_TIMESTAMP (cc_buffer))
+            {
+                gst_mini_object_set_qdata (GST_MINI_OBJECT (frame->output_buffer), GST_AML_V4L2_CC_IMPORT_QUARK,
+                    gst_buffer_ref(cc_buffer), (GDestroyNotify) gst_buffer_unref);
+                #if 0
+                //Debug code:dump cc data
+                GstMapInfo gst_map;
+                gst_buffer_map(cc_buffer,&gst_map,GST_MAP_READ);
+                int fd=open("/data/test/cc1.data",O_RDWR |O_CREAT|O_APPEND,0777);
+                if (gst_map.size>0)
+                  write(fd,gst_map.data,gst_map.size);
+                close(fd);
+                gst_buffer_unmap(cc_buffer,&gst_map);
+                #endif
+                GST_DEBUG("match success");
+                return TRUE;
+            }
+            else
+            {
+                GST_DEBUG("match fail");
+            }
+        }
+        GST_WARNING("no match frame in the bufferlist");
+    }
+    else
+    {
+        GST_WARNING("list is null,can not foreach");
+    }
+    return FALSE;
+}
+
 static void
 gst_aml_v4l2_video_dec_loop(GstVideoDecoder *decoder)
 {
@@ -1106,6 +1172,7 @@
         }
 
         ret = gst_buffer_pool_acquire_buffer(pool, &buffer, NULL);
+
         //calculate a new pts for interlace stream
         if (ret == GST_FLOW_OK && self->v4l2capture->info.interlace_mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED)
         {
@@ -1146,6 +1213,12 @@
             }
         }
 
+        if (ret == GST_AML_V4L2_FLOW_CC_DATA)
+        {
+           GST_DEBUG_OBJECT(decoder, "continue get cc data ");
+           continue;
+        }
+
         if (ret == GST_AML_V4L2_FLOW_SOURCE_CHANGE)
         {
             GST_LOG_OBJECT(decoder, "Get GST_AML_V4L2_FLOW_SOURCE_CHANGE");
@@ -1173,7 +1246,7 @@
             return;
         }
 
-    } while (ret == GST_AML_V4L2_FLOW_CORRUPTED_BUFFER);
+    } while ((ret == GST_AML_V4L2_FLOW_CORRUPTED_BUFFER) || (ret == GST_AML_V4L2_FLOW_CC_DATA));
 
     if (ret != GST_FLOW_OK)
         goto beach;
@@ -1206,6 +1279,33 @@
         frame->pts = GST_BUFFER_TIMESTAMP(buffer);
         frame->duration = GST_BUFFER_DURATION(buffer);
         buffer = NULL;
+
+        GST_DEBUG_OBJECT (decoder,"enable_cc_data:%d",self->v4l2capture->enable_cc_data);
+        if (self->v4l2capture->enable_cc_data)
+        {
+            if (foreach_cc_buffer_list_match_pts_func(v4l2_pool->cc_buffer_list, frame))
+            {
+                GST_DEBUG("cc buffer and frame bind success");
+                GstBuffer *cc_buffer = gst_mini_object_get_qdata (GST_MINI_OBJECT (frame->output_buffer),
+                  GST_AML_V4L2_CC_IMPORT_QUARK);
+                #if 0
+                //Debug code:dump cc data
+                GstMapInfo gst_map;
+                gst_buffer_map(cc_buffer,&gst_map,GST_MAP_READ);
+                int fd=open("/data/test/cc2.data",O_RDWR |O_CREAT|O_APPEND,0777);
+                if (gst_map.size>0)
+                   write(fd,gst_map.data,gst_map.size);
+                close(fd);
+                gst_buffer_unmap(cc_buffer,&gst_map);
+                #endif
+                v4l2_pool->cc_buffer_list = g_list_remove(v4l2_pool->cc_buffer_list,cc_buffer);
+                gst_buffer_unref(cc_buffer);
+            }
+            else
+            {
+               GST_WARNING("bufferlist is empty or no match frame in the bufferlist");
+            }
+        }
         ret = gst_video_decoder_finish_frame(decoder, frame);
 
         if (ret != GST_FLOW_OK)