diff -r 761a8bbe4278 -r bca1fb717911 gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.c --- a/gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.c Thu Nov 09 19:45:27 2006 +0000 +++ b/gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.c Fri Nov 10 19:21:45 2006 +0000 @@ -87,15 +87,6 @@ GST_PAD_SOMETIMES, GST_STATIC_CAPS_ANY); -/* NUV Demux indexes init/dispose callers */ -static void gst_nuv_demux_index_init( nuv_demux_index **p_idx ); -static void gst_nuv_demux_index_clean( nuv_demux_index **p_idx ); - -/* NUV Demux indexes manipulation functions */ -//static gint64 gst_nuv_demux_index_find_offset( GstNuvDemux *nuv, gint64 i_offset ); -static void gst_nuv_demux_index_append( GstNuvDemux *nuv, gint64 i_time, gint64 i_offset ); -static gint64 gst_nuv_demux_index_convert_time( GstNuvDemux *nuv, gint64 i_time ); - /* NUV Demux plug-in time-line functions */ static void gst_nuv_demux_finalize (GObject * object); static GstStateChangeReturn gst_nuv_demux_change_state (GstElement * element, @@ -105,16 +96,12 @@ static GstFlowReturn gst_nuv_demux_play (GstPad * pad); static gboolean gst_nuv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active); +static gboolean gst_nuv_demux_sink_activate_push (GstPad * pad, + gboolean active); static gboolean gst_nuv_demux_sink_activate (GstPad * sinkpad); static GstFlowReturn gst_nuv_demux_read_bytes (GstNuvDemux * nuv, guint64 size, gboolean move, GstBuffer ** buffer); static void gst_nuv_demux_reset (GstNuvDemux * nuv); -static gboolean gst_nuv_demux_handle_sink_event (GstPad * sinkpad, - GstEvent * event); -static gboolean gst_nuv_demux_handle_audio_src_event (GstPad * sinkpad, - GstEvent * event); -static gboolean gst_nuv_demux_handle_video_src_event (GstPad * sinkpad, - GstEvent * event); static void gst_nuv_demux_destoy_src_pad (GstNuvDemux * nuv); static void gst_nuv_demux_send_eos (GstNuvDemux * nuv); @@ -182,11 +169,12 @@ gst_pad_set_activatepull_function (nuv->sinkpad, gst_nuv_demux_sink_activate_pull); + gst_pad_set_activatepush_function (nuv->sinkpad, + gst_nuv_demux_sink_activate_push); + gst_pad_set_chain_function (nuv->sinkpad, GST_DEBUG_FUNCPTR (gst_nuv_demux_chain)); - gst_pad_set_event_function (nuv->sinkpad, gst_nuv_demux_handle_sink_event); - gst_element_add_pad (GST_ELEMENT (nuv), nuv->sinkpad); gst_nuv_demux_index_init( &nuv->index_entries ); @@ -222,149 +210,6 @@ } -/***************************************************************************** - * Indexes (timecode offset conversion) functions - *****************************************************************************/ - -static void -gst_nuv_demux_index_init( nuv_demux_index **p_idx ) -{ - *p_idx = g_new0( nuv_demux_index, 1 ); - (*p_idx)->i_idx = 0; - (*p_idx)->i_idx_max = 0; -} - -static void -gst_nuv_demux_index_clean( nuv_demux_index **p_idx ) -{ - if ( *p_idx != NULL ) { - g_free( *p_idx ); - *p_idx = NULL; - } - -} - -static void -gst_nuv_demux_index_append( GstNuvDemux *nuv, gint64 i_time, gint64 i_offset ) -{ - nuv_demux_index *p_idx = nuv->index_entries; - - //if ( p_idx == NULL ) - // return; - - /* Be sure to append new entry (we don't insert point) */ - if( p_idx != NULL && p_idx->i_idx > 0 && p_idx->idx[p_idx->i_idx-1].i_time >= i_time ) - return; - - /* */ - if( p_idx->i_idx >= p_idx->i_idx_max ) - { - if( p_idx->i_idx >= DEMUX_INDEX_SIZE_MAX ) - { - /* Avoid too big index */ - const gint64 i_length = p_idx->idx[p_idx->i_idx-1].i_time - - p_idx->idx[0].i_time; - const gint i_count = DEMUX_INDEX_SIZE_MAX/2; - gint i, j; - - /* We try to reduce the resolution of the index by a factor 2 */ - for( i = 1, j = 1; i < p_idx->i_idx; i++ ) - { - if( p_idx->idx[i].i_time < j * i_length / i_count ) - continue; - - p_idx->idx[j++] = p_idx->idx[i]; - } - p_idx->i_idx = j; - - if( p_idx->i_idx > 3 * DEMUX_INDEX_SIZE_MAX / 4 ) - { - /* We haven't created enough space - * (This method won't create a good index but work for sure) */ - for( i = 0; i < p_idx->i_idx/2; i++ ) - p_idx->idx[i] = p_idx->idx[2*i]; - p_idx->i_idx /= 2; - } - } - else - { - p_idx->i_idx_max += 1000; - } - } - - /* */ - p_idx->idx[p_idx->i_idx].i_time = i_time; - p_idx->idx[p_idx->i_idx].i_offset = i_offset; - - p_idx->i_idx++; -} - -static gint64 -gst_nuv_demux_index_convert_time( GstNuvDemux *nuv, gint64 i_time ) -{ - nuv_demux_index *p_idx = nuv->index_entries; - - g_return_val_if_fail( p_idx != NULL , i_time ); - - gint i_min = 0; - gint i_max = p_idx->i_idx-1; - - /* Empty index */ - if( p_idx->i_idx <= 0 ) - return -1; - - /* Special border case */ - if( i_time <= p_idx->idx[0].i_time ) - return p_idx->idx[0].i_offset; - if( i_time >= p_idx->idx[i_max].i_time ) - return p_idx->idx[i_max].i_offset; - - /* Dicho */ - for( ;; ) - { - gint i_med; - - if( i_max - i_min <= 1 ) - break; - - i_med = (i_min+i_max)/2; - if( p_idx->idx[i_med].i_time < i_time ) - i_min = i_med; - else if( p_idx->idx[i_med].i_time > i_time ) - i_max = i_med; - else - return p_idx->idx[i_med].i_offset; - } - - /* return nearest in time */ - if( i_time - p_idx->idx[i_min].i_time < p_idx->idx[i_max].i_time - i_time ) - return p_idx->idx[i_min].i_offset; - else - return p_idx->idx[i_max].i_offset; -} - -/***************************************************************************** - * Utils functions - *****************************************************************************/ - -static gboolean -gst_nuv_demux_handle_sink_event (GstPad * sinkpad, GstEvent * event) -{ - gboolean res = FALSE; - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - res = TRUE; - break; - default: - return gst_pad_event_default (sinkpad, event); - break; - } - - gst_event_unref (event); - return res; -} - /* HeaderLoad: */ static GstFlowReturn @@ -384,7 +229,7 @@ h->i_height = GST_READ_UINT32_LE (&buffer->data[24]); h->i_width_desired = GST_READ_UINT32_LE (&buffer->data[28]); h->i_height_desired = GST_READ_UINT32_LE (&buffer->data[32]); - h->i_mode = buffer->data[36]; + h->i_mode = GPOINTER_TO_INT (buffer->data[36]); h->d_aspect = READ_DOUBLE_FROM_LE (&buffer->data[40]); h->d_fps = READ_DOUBLE_FROM_LE (&buffer->data[48]); h->i_video_blocks = GST_READ_UINT32_LE (&buffer->data[56]); @@ -462,15 +307,13 @@ h = g_new0 (nuv_frame_header, 1); data = buf->data; - h->i_type = data[0]; - h->i_compression = data[1]; - h->i_keyframe = data[2]; - h->i_filters = data[3]; - + h->i_type = GPOINTER_TO_INT (data[0]); + h->i_compression = GPOINTER_TO_INT (data[1]); + h->i_keyframe = GPOINTER_TO_INT (data[2]); + h->i_filters = GPOINTER_TO_INT (data[3]); h->i_timecode = GST_READ_UINT32_LE (&data[4]); - - h->i_length = GST_READ_UINT32_LE (&data[8]); + GST_DEBUG_OBJECT (nuv, "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%d l=%d", h->i_type, h->i_compression ? h->i_compression : ' ', @@ -535,20 +378,6 @@ return res; } -static gboolean -gst_nuv_demux_handle_audio_src_event (GstPad * pad, GstEvent * event) -{ - gst_event_unref (event); - return FALSE; -} - -static gboolean -gst_nuv_demux_handle_video_src_event (GstPad * pad, GstEvent * event) -{ - gst_event_unref (event); - return FALSE; -} - static void gst_nuv_demux_create_pads (GstNuvDemux * nuv) { @@ -563,14 +392,12 @@ "width", G_TYPE_INT, nuv->h->i_width, "height", G_TYPE_INT, nuv->h->i_height, "framerate", GST_TYPE_FRACTION, (gint) (nuv->h->d_fps * 1000.0f), 1000, + "format", GST_TYPE_FOURCC, nuv->eh->i_video_fcc, "pixel-aspect-ratio", GST_TYPE_FRACTION, (gint) (nuv->h->d_aspect * 1000.0f), 1000, NULL); gst_pad_use_fixed_caps (nuv->src_video_pad); gst_pad_set_caps (nuv->src_video_pad, video_caps); - - gst_pad_set_event_function (nuv->src_video_pad, - gst_nuv_demux_handle_video_src_event); gst_pad_set_active (nuv->src_video_pad, TRUE); gst_element_add_pad (GST_ELEMENT (nuv), nuv->src_video_pad); @@ -591,12 +418,8 @@ gst_pad_use_fixed_caps (nuv->src_audio_pad); gst_pad_set_caps (nuv->src_audio_pad, audio_caps); - - gst_pad_set_event_function (nuv->src_audio_pad, - gst_nuv_demux_handle_audio_src_event); gst_pad_set_active (nuv->src_audio_pad, TRUE); gst_element_add_pad (GST_ELEMENT (nuv), nuv->src_audio_pad); - gst_caps_unref (audio_caps); } @@ -608,6 +431,12 @@ { GstFlowReturn ret = GST_FLOW_OK; + if (nuv->fh != NULL) + { + g_free (nuv->fh); + nuv->fh = NULL; + } + ret = gst_nuv_demux_frame_header_load (nuv, &nuv->fh); if (ret != GST_FLOW_OK) return ret; @@ -622,38 +451,35 @@ GstFlowReturn ret = GST_FLOW_OK; GstBuffer *buf = NULL; nuv_frame_header *h = nuv->fh; - - gint64 table_timecode = 0; if (h->i_type == 'R') goto done; - table_timecode = h->i_timecode; - - /* append the frame's header timecode field, and the actual offset */ - if ( h->i_type == 'V' ) - gst_nuv_demux_index_append( nuv, h->i_timecode, nuv->video_offset ); - else if ( h->i_type == 'A' ) - gst_nuv_demux_index_append( nuv, h->i_timecode, nuv->audio_offset ); - if (h->i_length > 0) { ret = gst_nuv_demux_read_bytes (nuv, h->i_length, TRUE, &buf); if (ret != GST_FLOW_OK) return ret; - /* search for a valid timecode in the indexes list (find the nearest valid timecode) */ - if ( h->i_timecode < 0 ) { - /* convert this actual timecode to a valid index in the timecode's table */ - gint64 pos = gst_nuv_demux_index_convert_time( nuv, h->i_timecode ); + if ((h->i_type == 'V') || (h->i_type == 'A')) { + if (h->i_timecode < 0) { + nuv->last_time = 1; + h->i_timecode = 0; + } + else if (nuv->last_time == 1) + { + nuv->last_time = 0; + gst_pad_push_event (nuv->src_video_pad, + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, + GST_CLOCK_TIME_NONE, 0)); - /* just get the timecode from the timecode's table */ - table_timecode = nuv->index_entries->idx[pos].i_time * GST_MSECOND; - } else { - table_timecode = h->i_timecode * GST_MSECOND; - } - - GST_BUFFER_TIMESTAMP (buf) = table_timecode; - } + gst_pad_push_event (nuv->src_audio_pad, + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, + GST_CLOCK_TIME_NONE, 0)); + } + + GST_BUFFER_TIMESTAMP (buf) = h->i_timecode * GST_MSECOND; + } + } switch (h->i_type) { case 'V': @@ -664,14 +490,13 @@ if ( !gst_pad_is_linked( nuv->src_video_pad ) ) break; - //GST_PAD_STREAM_LOCK(nuv->src_video_pad); - GST_BUFFER_SIZE (buf) = h->i_length; gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_video_pad)); ret = gst_pad_push (nuv->src_video_pad, buf); - nuv->video_offset += h->i_length; - - //GST_PAD_STREAM_UNLOCK(nuv->src_video_pad); + if (ret != GST_FLOW_OK) { + GST_WARNING_OBJECT (nuv, "error pushing on srcpad %s, is linked? = %d", + gst_pad_get_name (nuv->src_video_pad), gst_pad_is_linked (nuv->src_video_pad)); + } break; } case 'A': @@ -682,42 +507,41 @@ if ( !gst_pad_is_linked( nuv->src_audio_pad ) ) break; - //GST_PAD_STREAM_LOCK(nuv->src_audio_pad); - GST_BUFFER_SIZE (buf) = h->i_length; gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_audio_pad)); ret = gst_pad_push (nuv->src_audio_pad, buf); - nuv->audio_offset += h->i_length; - - //GST_PAD_STREAM_UNLOCK(nuv->src_audio_pad); + if (ret != GST_FLOW_OK) { + GST_WARNING_OBJECT (nuv, "Error pushing on srcpad %s, is linked? = %d", + gst_pad_get_name (nuv->src_audio_pad), gst_pad_is_linked (nuv->src_audio_pad)); + } break; } case 'S': { switch (h->i_compression) { case 'V': - if ( !gst_pad_is_linked( nuv->src_video_pad ) ) - break; + if ( !gst_pad_is_linked( nuv->src_video_pad ) ) + break; - //GST_PAD_STREAM_LOCK(nuv->src_video_pad); + GST_DEBUG_OBJECT (nuv, "sending new video segment: %d", h->i_timecode); gst_pad_push_event (nuv->src_video_pad, - gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, table_timecode, + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, h->i_timecode * GST_MSECOND, GST_CLOCK_TIME_NONE, 0)); - //GST_PAD_STREAM_UNLOCK(nuv->src_video_pad); break; case 'A': if ( !gst_pad_is_linked( nuv->src_audio_pad ) ) break; - //GST_PAD_STREAM_LOCK(nuv->src_audio_pad); + GST_DEBUG_OBJECT (nuv, "sending new audio segment: %d", h->i_timecode); gst_pad_push_event (nuv->src_audio_pad, - gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, table_timecode, + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, GST_CLOCK_TIME_NONE, 0)); - //GST_PAD_STREAM_UNLOCK(nuv->src_audio_pad); break; default: break; } + if (buf != NULL) + gst_buffer_unref (buf); } default: if (buf != NULL) @@ -743,7 +567,7 @@ gst_nuv_demux_read_bytes (nuv, nuv->mpeg_data_size, TRUE, &nuv->mpeg_buffer); if (ret != GST_FLOW_OK) { - return ret; //GST_FLOW_ERROR; + return ret; } GST_BUFFER_SIZE (nuv->mpeg_buffer) = nuv->mpeg_data_size; nuv->state = GST_NUV_DEMUX_EXTEND_HEADER; @@ -904,7 +728,7 @@ case GST_NUV_DEMUX_MOVI: res = gst_nuv_demux_stream_data (nuv); - if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA) && (res != GST_FLOW_CUSTOM_ERROR)) { + if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) { goto pause; } break; @@ -959,11 +783,14 @@ if (nuv->mode == 0) { ret = gst_pad_pull_range (nuv->sinkpad, nuv->offset, size, buffer); if (ret == GST_FLOW_OK) { - if (move) { - nuv->offset += size; - } + if (move) { + nuv->offset += size; + } /* got eos */ } else if (ret == GST_FLOW_UNEXPECTED) { + if (buffer != NULL) + gst_buffer_unref (buffer); + gst_nuv_demux_send_eos (nuv); return GST_FLOW_WRONG_STATE; } @@ -972,17 +799,17 @@ return GST_FLOW_ERROR_NO_DATA; if (move) { - *buffer = gst_adapter_take_buffer (nuv->adapter, size); + guint8 *data = NULL; + data = (guint8 *) gst_adapter_take (nuv->adapter, size); + *buffer = gst_buffer_new (); + gst_buffer_set_data (*buffer, data, size); } else { guint8 *data = NULL; - data = (guint8 *) gst_adapter_peek (nuv->adapter, size); *buffer = gst_buffer_new (); gst_buffer_set_data (*buffer, data, size); } } - - return ret; } @@ -1009,7 +836,6 @@ } res = gst_pad_activate_push (sinkpad, TRUE); } - g_object_unref (nuv); return res; } @@ -1029,6 +855,22 @@ return TRUE; } +static gboolean +gst_nuv_demux_sink_activate_push (GstPad * pad, gboolean active) +{ + GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad)); + + if (active) { + GST_DEBUG_OBJECT (nuv, "activating push/chain function"); + } else { + GST_DEBUG_OBJECT (nuv, "deactivating push/chain function"); + } + + gst_object_unref (nuv); + + return TRUE; +} + static GstFlowReturn gst_nuv_demux_chain (GstPad * pad, GstBuffer * buf) { @@ -1036,6 +878,8 @@ gst_adapter_push (nuv->adapter, buf); + gst_object_unref (nuv); + return gst_nuv_demux_play (pad); } @@ -1051,8 +895,7 @@ nuv->state = GST_NUV_DEMUX_START; nuv->mode = 0; nuv->offset = 0; - nuv->video_offset = 0; - nuv->audio_offset = 0; + nuv->last_time = 0; if (nuv->adapter != NULL) gst_adapter_clear (nuv->adapter);