#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)
{
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;
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");
stacked_length += nal_length;
count++;
+ LOGD("codec_data length : %d", codec_length);
+
if ((stacked_length >= byte_length) || count > 5)
break;
}
*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)
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;
+ }
+
+}
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);
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;
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;
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);
}
}
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;
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;
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");
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;
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]);