From: juan82.liu Date: Thu, 15 Dec 2016 19:11:10 +0000 (+0800) Subject: Patch for split codec_data from first frame X-Git-Tag: submit/tizen_3.0/20161226.123740~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F02%2F105202%2F4;p=platform%2Fcore%2Fapi%2Fmediacodec.git Patch for split codec_data from first frame Change-Id: I86fa797c3ad6690a6da33aaa8553a08488aabc25 --- diff --git a/include/media_codec_bitstream.h b/include/media_codec_bitstream.h index e8af1af..2898146 100755 --- a/include/media_codec_bitstream.h +++ b/include/media_codec_bitstream.h @@ -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 diff --git a/src/media_codec_bitstream.c b/src/media_codec_bitstream.c index e50baeb..373da79 100755 --- a/src/media_codec_bitstream.c +++ b/src/media_codec_bitstream.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include 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; + } + +} diff --git a/src/media_codec_port_gst.c b/src/media_codec_port_gst.c index fc9ddaf..d7856a3 100755 --- a/src/media_codec_port_gst.c +++ b/src/media_codec_port_gst.c @@ -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]);