Patch for split codec_data from first frame 02/105202/4
authorjuan82.liu <juan82.liu@samsung.com>
Thu, 15 Dec 2016 19:11:10 +0000 (03:11 +0800)
committerjuan82.liu <juan82.liu@samsung.com>
Thu, 15 Dec 2016 23:50:43 +0000 (07:50 +0800)
Change-Id: I86fa797c3ad6690a6da33aaa8553a08488aabc25

include/media_codec_bitstream.h
src/media_codec_bitstream.c
src/media_codec_port_gst.c

index e8af1af..2898146 100755 (executable)
@@ -99,6 +99,8 @@ int _mc_check_valid_h263_frame(unsigned char *p, int size);
 bool _mc_check_h263_out_bytestream(unsigned char *p, int buf_length, bool* need_sync_flag);
 int _mc_check_mpeg4_out_bytestream(unsigned char *buf, int buf_length, bool* need_codec_data, bool *need_sync_flag);
 
+int _mc_get_h264_codecdata_size(guint8 *data, int size);
+
 #ifdef __cplusplus
 }
 #endif
index e50baeb..373da79 100755 (executable)
@@ -17,6 +17,8 @@
 #include <stdio.h>
 #include <dlog.h>
 #include <media_codec_bitstream.h>
+#include <gst/base/gstbytereader.h>
+#include <gst/base/gstbitreader.h>
 
 void mc_init_bits(mc_bitstream_t *stream, unsigned char *data, int size)
 {
@@ -182,15 +184,25 @@ int __mc_decode_sps(mc_bitstream_t *pstream, int *width, int *height)
        return ret;
 }
 
+int __mc_scan_for_h264_start_codes(const guint8 * data, guint size)
+{
+       GstByteReader br;
+       gst_byte_reader_init(&br, data, size);
+
+       /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */
+       return gst_byte_reader_masked_scan_uint32(&br, 0xffffff00, 0x00000100, 0, size);
+}
+
 int _mc_check_h264_bytestream(unsigned char *nal, int byte_length, bool port, bool *codec_config, bool *sync_flag, bool *slice)
 {
-       int ret = MC_ERROR_NONE;
+       int ret = 0; /* (ret <= 0)==>>error occured;  (ret > 0)==>>codec data size */
        int stacked_length = 0;
        int nal_length = 0;
        unsigned int syntax = 0;
        unsigned int state = 0;
        int count = 0;
        int nal_unit_type = 0;
+       int codec_length = 0;
 
        mc_bitstream_t pstream;
 
@@ -211,10 +223,12 @@ int _mc_check_h264_bytestream(unsigned char *nal, int byte_length, bool port, bo
                                if ((ret = __mc_decode_sps(&pstream, NULL, NULL)) != MC_ERROR_NONE)
                                        return ret;
                                state |= MC_EXIST_SPS;
+                               codec_length += nal_length;
                                break;
                        case NAL_PICTURE_PARAMETER_SET:
                                LOGD("nal_unit_type : PPS");
                                state |= MC_EXIST_PPS;
+                               codec_length += nal_length;
                                break;
                        case NAL_SLICE_IDR:
                                LOGD("nal_unit_type : IDR");
@@ -231,6 +245,8 @@ int _mc_check_h264_bytestream(unsigned char *nal, int byte_length, bool port, bo
                        stacked_length += nal_length;
                        count++;
 
+                       LOGD("codec_data length : %d", codec_length);
+
                        if ((stacked_length >= byte_length) || count > 5)
                                break;
                }
@@ -257,7 +273,7 @@ int _mc_check_h264_bytestream(unsigned char *nal, int byte_length, bool port, bo
                *slice = CHECK_VALID_PACKET(state, MC_EXIST_SLICE) ? 1 : 0;
        }
 
-       return ret;
+       return codec_length;
 }
 
 int _mc_check_valid_h263_frame(unsigned char *p, int size)
@@ -367,3 +383,75 @@ bool _mc_check_h263_out_bytestream(unsigned char *p, int buf_length, bool* need_
        return TRUE;
 }
 
+int _mc_get_h264_codecdata_size(guint8 *data, int size)
+{
+       int offset = 0;
+       int data_size = 0;
+       bool is_bytestream = FALSE;
+
+       if ((offset = __mc_scan_for_h264_start_codes(data, size)) == -1) {
+               /*Packetized Format*/
+               is_bytestream = FALSE;
+       } else {
+               /*Byte-Stream Format*/
+               is_bytestream = TRUE;
+       }
+
+       if (is_bytestream) {
+               /*Byte-Stream Format*/
+               data_size = _mc_check_h264_bytestream(data, size, 0, NULL, NULL, NULL);
+               if (data_size <= 0) {
+                       LOGE("No valid SPS/PPS ...");
+                       return MC_INVALID_IN_BUF;
+               }
+               return data_size;
+       } else {
+               /*Packetized Format*/
+               int num_sps = 0, num_pps = 0;
+               int nalu_size = 0;
+               int i = 0;
+               unsigned int state = 0;
+               GstBitReader br;
+
+               offset = 0;
+               /* parse the avcC data */
+               if (size < 7) { /* when numSPS==0 and numPPS==0, length is 7 bytes */
+                       LOGE("If contains codec_data, size should over 7 bytes ...");
+                       return MC_INVALID_IN_BUF;
+               }
+               /* parse the version, this must be 1 */
+               if (data[0] != 1) {
+                       LOGE("If contains codec_data, first byte must be 1 ...");
+                       return MC_INVALID_IN_BUF;
+               }
+
+               num_sps = data[5] & 0x1f;
+               offset = 6;
+               for (i = 0; i < num_sps; i++) {
+                       gst_bit_reader_init(&br, data + offset, size - offset);
+                       nalu_size = gst_bit_reader_get_bits_uint32_unchecked(&br, 2 * 8);
+
+                       offset += nalu_size + 2;
+                       state |= MC_EXIST_SPS;
+               }
+
+               num_pps = data[offset];
+               offset++;
+
+               for (i = 0; i < num_pps; i++) {
+                       gst_bit_reader_init(&br, data + offset, size - offset);
+                       nalu_size = gst_bit_reader_get_bits_uint32_unchecked(&br, 2 * 8);
+
+                       offset += nalu_size + 2;
+                       state |= MC_EXIST_PPS;
+               }
+
+               if (CHECK_VALID_PACKET(state, MC_VALID_HEADER)) {
+                       LOGD("Found valid SPS/PPS data...\n");
+                       return offset;
+               }
+
+               return MC_INVALID_IN_BUF;
+       }
+
+}
index fc9ddaf..d7856a3 100755 (executable)
@@ -60,6 +60,8 @@ static GstMCBuffer *gst_mediacodec_buffer_new(mc_gst_core_t* core, media_packet_
 static void gst_mediacodec_buffer_finalize(GstMCBuffer *buffer);
 static int __mc_set_caps_streamheader(mc_gst_core_t *core, GstMCBuffer*buff, guint streamheader_size);
 static int __mc_set_caps_codecdata(mc_gst_core_t *core, GstMCBuffer*buff, guint codecdata_size);
+static void __mc_push_output_to_queue(mc_gst_core_t *core, media_packet_h out_pkt);
+static int __mc_gst_create_eos_packet(media_format_h fmt, media_packet_h *out_pkt);
 
 static gint __gst_handle_stream_error(mc_gst_core_t *core, GError *error, GstMessage *message);
 static gint __gst_transform_gsterror(mc_gst_core_t *core, GstMessage *message, GError *error);
@@ -717,9 +719,46 @@ int __mc_set_caps_streamheader(mc_gst_core_t *core, GstMCBuffer*buff, guint stre
        return ret;
 }
 
+int __mc_get_codecdata_size(mc_gst_core_t *core, GstMCBuffer *buff, unsigned int *size)
+{
+       void *data = NULL;
+       uint64_t data_size = 0;
+       uint64_t codec_size = 0;
+       int ret = MC_ERROR_NONE;
+
+       media_packet_get_buffer_size(buff->pkt, &data_size);
+       media_packet_get_buffer_data_ptr(buff->pkt, &data);
+
+       switch (core->codec_id) {
+       case MEDIACODEC_H264:
+               codec_size = _mc_get_h264_codecdata_size(data, data_size);
+               break;
+       case MEDIACODEC_H263:
+               /* Not need codec data */
+               codec_size = 0;
+               break;
+       case MEDIACODEC_MPEG4:
+               codec_size = _mc_check_mpeg4_out_bytestream(data, data_size, NULL, NULL);
+               break;
+       default:
+               LOGE("Current not support yet (0x%x) !", core->codec_id);
+               return MC_NOT_SUPPORTED;
+               break;
+       }
+
+       if (codec_size < 0) {
+               LOGE("No valid codec data!");
+               ret = MC_INVALID_IN_BUF;
+       }
+
+       *size = codec_size;
+
+       return ret;
+}
+
 int __mc_set_caps_codecdata(mc_gst_core_t *core, GstMCBuffer *buff, guint fixed_size)
 {
-       int ret = MEDIA_PACKET_ERROR_NONE;
+       int ret = MC_ERROR_NONE;
        void *codec_data = NULL;
        unsigned int codec_data_size = 0;
        GstBuffer *codecdata_buffer;
@@ -733,26 +772,35 @@ int __mc_set_caps_codecdata(mc_gst_core_t *core, GstMCBuffer *buff, guint fixed_
                memcpy(data, codec_data, codec_data_size);
                codecdata_buffer = gst_buffer_new_wrapped(data, codec_data_size);
                gst_caps_set_simple(core->caps, "codec_data", GST_TYPE_BUFFER, codecdata_buffer, NULL);
-               LOGD("set codec data : %" G_GSIZE_FORMAT "",  gst_buffer_get_size(codecdata_buffer));
+               LOGD("set codec data : %" G_GSIZE_FORMAT "", gst_buffer_get_size(codecdata_buffer));
                gst_buffer_unref(codecdata_buffer);
        } else {                                        /* get the codec data from media_packet_get_buffer_data_ptr() */
-               uint64_t buffer_size;
+               uint64_t buffer_size = 0;
+               void *buff_data = NULL;
+
                media_packet_get_buffer_size(buff->pkt, &buffer_size);
-               media_packet_get_buffer_data_ptr(buff->pkt, &codec_data);
+               media_packet_get_buffer_data_ptr(buff->pkt, &buff_data);
+
+               ret = __mc_get_codecdata_size(core, buff, &codec_data_size);
+               LOGD("First Frame contains codec_data_size= %d", codec_data_size);
 
-               if (codec_data_size > fixed_size) {
-                       data = g_malloc0(fixed_size);
+               if ((ret == MC_ERROR_NONE) && (codec_data_size > 0)) {
+                       data = g_malloc0(codec_data_size);
                        gst_buffer_map(buff->buffer, &map, GST_MAP_READ);
                        memcpy(data, map.data, codec_data_size);
-                       codecdata_buffer = gst_buffer_new_wrapped(data, buffer_size);
+                       codecdata_buffer = gst_buffer_new_wrapped(data, codec_data_size);
                        gst_buffer_unmap(buff->buffer, &map);
                        gst_caps_set_simple(core->caps, "codec_data", GST_TYPE_BUFFER, codecdata_buffer, NULL);
                        gst_buffer_unref(codecdata_buffer);
 
-                       gst_buffer_replace_memory(buff->buffer, 0,
-                                       gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, codec_data + fixed_size , buffer_size - fixed_size, 0,
-                                               buffer_size - fixed_size, buff, (GDestroyNotify)gst_mediacodec_buffer_finalize));
-                       LOGD("set codec data from packet: %" G_GSIZE_FORMAT "",  gst_buffer_get_size(buff->buffer));
+                       GstMemory *memory = NULL;
+                       memory = gst_buffer_peek_memory(buff->buffer, 0);
+                       gst_memory_resize(memory, codec_data_size, buffer_size - codec_data_size);
+                       LOGD("First frame remained size : %d", gst_buffer_get_size(buff->buffer));
+               } else {
+                       if (ret != MC_ERROR_NONE) {
+                               LOGE("No valid codec data in the packet!");
+                       }
                }
        }
        return ret;
@@ -1377,6 +1425,7 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                                core->vtable = vdec_h263_sw_vtable;
                                core->caps = gst_caps_new_simple(core->mime,
                                                "variant", G_TYPE_STRING, "itu",
+                                               "framerate", GST_TYPE_FRACTION, 30, 1,
                                                NULL);
                        }
                }
@@ -1417,7 +1466,9 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                                core->vtable = vdec_h264_sw_vtable;
                                core->caps = gst_caps_new_simple(core->mime,
                                                "alignment", G_TYPE_STRING, "au",
-                                               "stream-format", G_TYPE_STRING, "byte-stream", NULL);
+                                               "stream-format", G_TYPE_STRING, "byte-stream",
+                                               "framerate", GST_TYPE_FRACTION, 30, 1,
+                                               NULL);
                        }
                }
                break;
@@ -1971,6 +2022,32 @@ STATE_CHANGE_FAILED:
        return MC_ERROR;
 }
 
+void __mc_push_output_to_queue(mc_gst_core_t *core, media_packet_h out_pkt)
+{
+       g_mutex_lock(&core->ports[1]->mutex);
+
+       /* push it to output buffer queue */
+       g_queue_push_tail(core->ports[1]->queue, out_pkt);
+       g_cond_broadcast(&core->out_buffer_cond);
+       g_atomic_int_inc(&core->ftb_count);
+
+       GstBuffer *buffer = NULL;
+       media_packet_get_extra(out_pkt, (void**)&buffer);
+       if (buffer) {
+               LOGD("dq : %d TIMESTAMP = %"GST_TIME_FORMAT " DURATION = %"GST_TIME_FORMAT,
+                       core->ftb_count, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)), GST_TIME_ARGS(GST_BUFFER_DURATION(buffer)));
+       } else {
+               LOGD("dq : %d ", core->ftb_count);
+       }
+
+       g_mutex_unlock(&core->ports[1]->mutex);
+
+       if (core->user_cb[_MEDIACODEC_EVENT_TYPE_FILLBUFFER]) {
+               ((mc_fill_buffer_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_FILLBUFFER])
+                       (out_pkt, core->user_data[_MEDIACODEC_EVENT_TYPE_FILLBUFFER]);
+       }
+}
+
 void __mc_gst_buffer_add(GstElement *element, GstBuffer *buffer, GstPad *pad, gpointer data)
 {
        guint n;
@@ -2011,22 +2088,7 @@ void __mc_gst_buffer_add(GstElement *element, GstBuffer *buffer, GstPad *pad, gp
                        core->need_sync_flag = false;
                }
 
-               g_mutex_lock(&core->ports[1]->mutex);
-
-               /* push it to output buffer queue */
-               g_queue_push_tail(core->ports[1]->queue, out_pkt);
-               g_cond_broadcast(&core->out_buffer_cond);
-
-               g_atomic_int_inc(&core->ftb_count);
-               LOGD("dq : %d TIMESTAMP = %"GST_TIME_FORMAT " DURATION = %"GST_TIME_FORMAT,
-                       core->ftb_count, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)), GST_TIME_ARGS(GST_BUFFER_DURATION(buffer)));
-
-               g_mutex_unlock(&core->ports[1]->mutex);
-
-               if (core->user_cb[_MEDIACODEC_EVENT_TYPE_FILLBUFFER]) {
-                       ((mc_fill_buffer_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_FILLBUFFER])
-                               (out_pkt, core->user_data[_MEDIACODEC_EVENT_TYPE_FILLBUFFER]);
-               }
+               __mc_push_output_to_queue(core, out_pkt);
        } else {
                gst_buffer_unref(buffer);
                LOGE("Failed to dequeue output packet");
@@ -2180,6 +2242,36 @@ media_packet_h __mc_gst_make_media_packet(mc_gst_core_t *core, unsigned char *da
        return pkt;
 }
 
+int __mc_gst_create_eos_packet(media_format_h fmt, media_packet_h *out_pkt)
+{
+       media_packet_h mediabuf = NULL;
+       int ret = MC_ERROR_NONE;
+
+       MEDIACODEC_FENTER();
+       if (media_packet_create_alloc(fmt, NULL, NULL, &mediabuf)) {
+               LOGE("media_packet_create_alloc failed\n");
+               ret = MC_ERROR;
+               goto ERROR;
+       }
+
+       if (media_packet_set_flags(mediabuf, MEDIA_PACKET_END_OF_STREAM)) {
+               LOGE("unable to set EOS flag\n");
+               ret = MC_ERROR;
+               goto ERROR;
+       }
+
+       *out_pkt = mediabuf;
+       MEDIACODEC_FLEAVE();
+
+       return ret;
+ERROR:
+       if (mediabuf)
+               media_packet_destroy(mediabuf);
+       *out_pkt = NULL;
+       MEDIACODEC_FLEAVE();
+       return ret;
+}
+
 gboolean __mc_gst_bus_callback(GstBus *bus, GstMessage *msg, gpointer data)
 {
        int ret  = MC_ERROR_NONE;
@@ -2191,6 +2283,14 @@ gboolean __mc_gst_bus_callback(GstBus *bus, GstMessage *msg, gpointer data)
        case GST_MESSAGE_EOS:
                _mc_send_eos_signal(core);
 
+               media_packet_h out_pkt = NULL;
+               if (MC_ERROR_NONE == __mc_gst_create_eos_packet(core->output_fmt, &out_pkt)) {
+                       __mc_push_output_to_queue(core, out_pkt);
+                       LOGD("send eos packet.");
+               } else {
+                       LOGE("failed to create eos packet.");
+               }
+
                if (core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS]) {
                        LOGD("eos callback invoked");
                        ((mc_eos_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS])(core->user_data[_MEDIACODEC_EVENT_TYPE_EOS]);