[svn r57] Fixed problem with the audio frame timestamps.
1.1 --- a/gst-plugins-nuvdemux/src/gstnuvdemux.c Thu Oct 26 15:28:10 2006 +0100
1.2 +++ b/gst-plugins-nuvdemux/src/gstnuvdemux.c Thu Oct 26 18:55:14 2006 +0100
1.3 @@ -52,8 +52,7 @@
1.4 #include <gst/gstplugin.h>
1.5 #include <string.h>
1.6
1.7 -//#include "gst/gst-i18n-plugin.h"
1.8 -#include <glib/gi18n.h>
1.9 +#include "gst/gst-i18n-plugin.h"
1.10 #include "gstnuvdemux.h"
1.11
1.12 GST_DEBUG_CATEGORY_STATIC (nuvdemux_debug);
1.13 @@ -89,6 +88,15 @@
1.14 GST_STATIC_CAPS_ANY);
1.15
1.16 /* NUV Demux indexes init/dispose callers */
1.17 +static void gst_nuv_demux_index_init( nuv_demux_index *p_idx );
1.18 +static void gst_nuv_demux_index_clean( nuv_demux_index *p_idx );
1.19 +
1.20 +/* NUV Demux indexes manipulation functions */
1.21 +static gint64 gst_nuv_demux_index_find_offset( GstNuvDemux *nuv, gint64 i_offset );
1.22 +static void gst_nuv_demux_index_append( GstNuvDemux *nuv, gint64 i_time, gint64 i_offset );
1.23 +static gint64 gst_nuv_demux_index_convert_time( GstNuvDemux *nuv, gint64 i_time );
1.24 +
1.25 +/* NUV Demux plug-in time-line functions */
1.26 static void gst_nuv_demux_finalize (GObject * object);
1.27 static GstStateChangeReturn gst_nuv_demux_change_state (GstElement * element,
1.28 GstStateChange transition);
1.29 @@ -129,6 +137,17 @@
1.30 #define READ_DOUBLE_FROM_LE(d) *((gdouble* ) (d))
1.31 #endif /* G_BYTE_ORDER != G_BIG_ENDIAN */
1.32
1.33 +static gint32
1.34 +gst_nuv_demux_getdwle (void const * _p)
1.35 +{
1.36 + guint8 * p = (guint8 *)_p;
1.37 + g_print( "[%s] shifting bits: {%d, %d, %d, %d}\n", __FUNCTION__,
1.38 + ((guint32)p[3] << 24), ((guint32)p[2] << 16),
1.39 + ((guint32)p[1] << 8), p[0] );
1.40 + return ( ((guint32)p[3] << 24) | ((guint32)p[2] << 16)
1.41 + | ((guint32)p[1] << 8) | p[0] );
1.42 + //return ( (gint)p[3] | (gint)p[2] | (gint)p[1] | p[0] );
1.43 +}
1.44
1.45 static void
1.46 gst_nuv_demux_base_init (gpointer klass)
1.47 @@ -177,6 +196,8 @@
1.48 gst_pad_set_event_function (nuv->sinkpad, gst_nuv_demux_handle_sink_event);
1.49
1.50 gst_element_add_pad (GST_ELEMENT (nuv), nuv->sinkpad);
1.51 +
1.52 + gst_nuv_demux_index_init( nuv->index_entries );
1.53
1.54 nuv->adapter = NULL;
1.55 nuv->mpeg_buffer = NULL;
1.56 @@ -194,6 +215,11 @@
1.57 if (nuv->mpeg_buffer != NULL) {
1.58 gst_buffer_unref (nuv->mpeg_buffer);
1.59 }
1.60 +
1.61 + if ( nuv->index_entries != NULL ) {
1.62 + gst_nuv_demux_index_clean( nuv->index_entries );
1.63 + nuv->index_entries = NULL;
1.64 + }
1.65
1.66 gst_nuv_demux_destoy_src_pad (nuv);
1.67 gst_nuv_demux_reset (nuv);
1.68 @@ -203,8 +229,178 @@
1.69 G_OBJECT_CLASS (parent_class)->finalize (object);
1.70 }
1.71
1.72 +
1.73 /*****************************************************************************
1.74 - * Utils fucntions
1.75 + * Indexes (timecode offset conversion) functions
1.76 + *****************************************************************************/
1.77 +
1.78 +static void
1.79 +gst_nuv_demux_index_init( nuv_demux_index *p_idx )
1.80 +{
1.81 + p_idx = g_new0( nuv_demux_index, 1 );
1.82 + p_idx->i_idx = 0;
1.83 + p_idx->i_idx_max = 0;
1.84 + p_idx->idx = g_new0( nuv_demux_index_entry, DEMUX_INDEX_SIZE_MAX );
1.85 +}
1.86 +
1.87 +static void
1.88 +gst_nuv_demux_index_clean( nuv_demux_index *p_idx )
1.89 +{
1.90 + if( p_idx->idx )
1.91 + {
1.92 + g_free( p_idx->idx );
1.93 + }
1.94 +}
1.95 +
1.96 +static void
1.97 +gst_nuv_demux_index_append( GstNuvDemux *nuv, gint64 i_time, gint64 i_offset )
1.98 +{
1.99 + nuv_demux_index *p_idx = nuv->index_entries;
1.100 +
1.101 + if ( p_idx == NULL || p_idx->idx == NULL )
1.102 + return;
1.103 +
1.104 + /* Be sure to append new entry (we don't insert point) */
1.105 + if( p_idx != NULL && p_idx->i_idx > 0 && p_idx->idx[p_idx->i_idx-1].i_time >= i_time )
1.106 + return;
1.107 +
1.108 + /* */
1.109 + if( p_idx->i_idx >= p_idx->i_idx_max )
1.110 + {
1.111 + if( p_idx->i_idx >= DEMUX_INDEX_SIZE_MAX )
1.112 + {
1.113 + /* Avoid too big index */
1.114 + const gint64 i_length = p_idx->idx[p_idx->i_idx-1].i_time -
1.115 + p_idx->idx[0].i_time;
1.116 + const gint i_count = DEMUX_INDEX_SIZE_MAX/2;
1.117 + gint i, j;
1.118 +
1.119 + /* We try to reduce the resolution of the index by a factor 2 */
1.120 + for( i = 1, j = 1; i < p_idx->i_idx; i++ )
1.121 + {
1.122 + if( p_idx->idx[i].i_time < j * i_length / i_count )
1.123 + continue;
1.124 +
1.125 + p_idx->idx[j++] = p_idx->idx[i];
1.126 + }
1.127 + p_idx->i_idx = j;
1.128 +
1.129 + if( p_idx->i_idx > 3 * DEMUX_INDEX_SIZE_MAX / 4 )
1.130 + {
1.131 + /* We haven't created enough space
1.132 + * (This method won't create a good index but work for sure) */
1.133 + for( i = 0; i < p_idx->i_idx/2; i++ )
1.134 + p_idx->idx[i] = p_idx->idx[2*i];
1.135 + p_idx->i_idx /= 2;
1.136 + }
1.137 + }
1.138 + else
1.139 + {
1.140 + p_idx->i_idx_max += 1000;
1.141 + p_idx->idx = g_realloc( p_idx->idx,
1.142 + p_idx->i_idx_max*sizeof(nuv_demux_index_entry));
1.143 + }
1.144 + }
1.145 +
1.146 + /* */
1.147 + p_idx->idx[p_idx->i_idx].i_time = i_time;
1.148 + p_idx->idx[p_idx->i_idx].i_offset = i_offset;
1.149 +
1.150 + p_idx->i_idx++;
1.151 +}
1.152 +
1.153 +static gint64
1.154 +gst_nuv_demux_index_convert_time( GstNuvDemux *nuv, gint64 i_time )
1.155 +{
1.156 + nuv_demux_index *p_idx = nuv->index_entries;
1.157 +
1.158 + g_return_val_if_fail( p_idx != NULL, i_time );
1.159 +
1.160 + gint i_min = 0;
1.161 + gint i_max = p_idx->i_idx-1;
1.162 +
1.163 + /* Empty index */
1.164 + if( p_idx->i_idx <= 0 )
1.165 + return -1;
1.166 +
1.167 + /* Special border case */
1.168 + if( i_time <= p_idx->idx[0].i_time )
1.169 + return p_idx->idx[0].i_offset;
1.170 + if( i_time >= p_idx->idx[i_max].i_time )
1.171 + return p_idx->idx[i_max].i_offset;
1.172 +
1.173 + /* Dicho */
1.174 + for( ;; )
1.175 + {
1.176 + gint i_med;
1.177 +
1.178 + if( i_max - i_min <= 1 )
1.179 + break;
1.180 +
1.181 + i_med = (i_min+i_max)/2;
1.182 + if( p_idx->idx[i_med].i_time < i_time )
1.183 + i_min = i_med;
1.184 + else if( p_idx->idx[i_med].i_time > i_time )
1.185 + i_max = i_med;
1.186 + else
1.187 + return p_idx->idx[i_med].i_offset;
1.188 + }
1.189 +
1.190 + /* return nearest in time */
1.191 + if( i_time - p_idx->idx[i_min].i_time < p_idx->idx[i_max].i_time - i_time )
1.192 + return p_idx->idx[i_min].i_offset;
1.193 + else
1.194 + return p_idx->idx[i_max].i_offset;
1.195 +}
1.196 +
1.197 +static gint64
1.198 +gst_nuv_demux_index_find_offset( GstNuvDemux *nuv, gint64 i_offset )
1.199 +{
1.200 + nuv_demux_index *p_idx = nuv->index_entries;
1.201 +
1.202 + g_return_val_if_fail( p_idx != NULL, i_offset );
1.203 +
1.204 + gint i_min = 0;
1.205 + gint i_max = p_idx->i_idx-1;
1.206 +
1.207 + /* Empty index */
1.208 + if( p_idx->i_idx <= 0 )
1.209 + return -1;
1.210 +
1.211 + /* Special border case */
1.212 + if( i_offset <= p_idx->idx[0].i_offset )
1.213 + return p_idx->idx[0].i_offset;
1.214 + if( i_offset == p_idx->idx[i_max].i_offset )
1.215 + return p_idx->idx[i_max].i_offset;
1.216 + if( i_offset > p_idx->idx[i_max].i_offset )
1.217 + return -1;
1.218 +
1.219 + /* Dicho */
1.220 + for( ;; )
1.221 + {
1.222 + gint i_med;
1.223 +
1.224 + if ( i_max - i_min <= 1 )
1.225 + break;
1.226 +
1.227 + i_med = (i_min+i_max)/2;
1.228 + if( p_idx->idx[i_med].i_offset < i_offset )
1.229 + i_min = i_med;
1.230 + else if( p_idx->idx[i_med].i_offset > i_offset )
1.231 + i_max = i_med;
1.232 + else
1.233 + return p_idx->idx[i_med].i_offset;
1.234 + }
1.235 +
1.236 + /* return nearest */
1.237 + if( i_offset - p_idx->idx[i_min].i_offset < p_idx->idx[i_max].i_offset - i_offset )
1.238 + return p_idx->idx[i_min].i_offset;
1.239 + else
1.240 + return p_idx->idx[i_max].i_offset;
1.241 +}
1.242 +
1.243 +/*****************************************************************************
1.244 + * Utils functions
1.245 *****************************************************************************/
1.246
1.247 static gboolean
1.248 @@ -328,9 +524,9 @@
1.249 h->i_keyframe = data[2];
1.250 h->i_filters = data[3];
1.251
1.252 - h->i_timecode = GST_READ_UINT32_LE (&data[4]);
1.253 + h->i_timecode = gst_nuv_demux_getdwle( &data[4] ); //GST_READ_UINT32_LE (&data[4]);
1.254 h->i_length = GST_READ_UINT32_LE (&data[8]);
1.255 - GST_DEBUG_OBJECT (nuv, "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%u l=%u",
1.256 + GST_DEBUG_OBJECT (nuv, "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%d l=%d",
1.257 h->i_type,
1.258 h->i_compression ? h->i_compression : ' ',
1.259 h->i_keyframe ? h->i_keyframe : ' ',
1.260 @@ -427,6 +623,7 @@
1.261 gst_nuv_demux_handle_src_event);
1.262 gst_pad_set_active (nuv->src_video_pad, TRUE);
1.263 gst_element_add_pad (GST_ELEMENT (nuv), nuv->src_video_pad);
1.264 +
1.265 gst_caps_unref (video_caps);
1.266 }
1.267
1.268 @@ -450,6 +647,7 @@
1.269
1.270 gst_pad_set_event_function (nuv->src_audio_pad,
1.271 gst_nuv_demux_handle_src_event);
1.272 +
1.273 gst_caps_unref (audio_caps);
1.274 }
1.275
1.276 @@ -478,17 +676,36 @@
1.277
1.278 if (h->i_type == 'R')
1.279 goto done;
1.280 -
1.281 - ret = gst_nuv_demux_read_bytes (nuv, h->i_length, TRUE, &buf);
1.282 - if (ret != GST_FLOW_OK) {
1.283 - return ret;
1.284 +
1.285 + /* append the frame's header timecode field, and the actual offset */
1.286 + gst_nuv_demux_index_append( nuv, h->i_timecode, nuv->offset );
1.287 +
1.288 + if (h->i_length > 0) {
1.289 + ret = gst_nuv_demux_read_bytes (nuv, h->i_length, TRUE, &buf);
1.290 + if (ret != GST_FLOW_OK)
1.291 + return ret;
1.292 +
1.293 + /* search for a valid timecode in the indexes list (find the nearest valid timecode) */
1.294 + if ( h->i_timecode < 0 ) {
1.295 + /* convert this actual timecode to a valid index in the timecode's table */
1.296 + gint64 pos = gst_nuv_demux_index_convert_time( nuv, h->i_timecode );
1.297 +
1.298 + /* find the nearest empty frame slot */
1.299 + gint64 near_off = gst_nuv_demux_index_find_offset( nuv, pos );
1.300 +
1.301 + /* just get the timecode from the timecode's table */
1.302 + GST_BUFFER_TIMESTAMP (buf) = nuv->index_entries->idx[near_off].i_time * GST_MSECOND;
1.303 + } else {
1.304 + GST_BUFFER_TIMESTAMP (buf) = h->i_timecode * GST_MSECOND;
1.305 + }
1.306 }
1.307
1.308 - GST_BUFFER_TIMESTAMP (buf) = h->i_timecode * GST_MSECOND;
1.309 -
1.310 switch (h->i_type) {
1.311 case 'V':
1.312 {
1.313 + if (h->i_length == 0)
1.314 + break;
1.315 +
1.316 GST_BUFFER_OFFSET (buf) = nuv->video_offset;
1.317 gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_video_pad));
1.318 ret = gst_pad_push (nuv->src_video_pad, buf);
1.319 @@ -497,6 +714,9 @@
1.320 }
1.321 case 'A':
1.322 {
1.323 + if (h->i_length == 0)
1.324 + break;
1.325 +
1.326 GST_BUFFER_OFFSET (buf) = nuv->audio_offset;
1.327 gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_audio_pad));
1.328 ret = gst_pad_push (nuv->src_audio_pad, buf);
1.329 @@ -508,18 +728,22 @@
1.330 switch (h->i_compression) {
1.331 case 'V':
1.332 gst_pad_push_event (nuv->src_video_pad,
1.333 - gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0));
1.334 + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1,
1.335 + h->i_timecode));
1.336 break;
1.337 case 'A':
1.338 gst_pad_push_event (nuv->src_audio_pad,
1.339 gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0));
1.340 -
1.341 break;
1.342 default:
1.343 break;
1.344 }
1.345 + }
1.346 + default:
1.347 + if (buf != NULL)
1.348 + gst_buffer_unref (buf);
1.349 +
1.350 break;
1.351 - }
1.352 }
1.353
1.354 done:
1.355 @@ -700,7 +924,7 @@
1.356
1.357 case GST_NUV_DEMUX_MOVI:
1.358 res = gst_nuv_demux_stream_data (nuv);
1.359 - if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
1.360 + if ((res != GST_FLOW_OK) && (res != GST_FLOW_CUSTOM_ERROR)) {
1.361 goto pause;
1.362 }
1.363 break;
1.364 @@ -768,10 +992,7 @@
1.365 return GST_FLOW_ERROR_NO_DATA;
1.366
1.367 if (move) {
1.368 - guint8 *data = NULL;
1.369 - data = (guint8 *) gst_adapter_take (nuv->adapter, size);
1.370 - *buffer = gst_buffer_new ();
1.371 - gst_buffer_set_data (*buffer, data, size);
1.372 + *buffer = gst_adapter_take_buffer (nuv->adapter, size);
1.373 } else {
1.374 guint8 *data = NULL;
1.375
2.1 --- a/gst-plugins-nuvdemux/src/gstnuvdemux.h Thu Oct 26 15:28:10 2006 +0100
2.2 +++ b/gst-plugins-nuvdemux/src/gstnuvdemux.h Thu Oct 26 18:55:14 2006 +0100
2.3 @@ -38,6 +38,23 @@
2.4 #define GST_IS_NUV_DEMUX_CLASS(klass) \
2.5 (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_NUV_DEMUX))
2.6
2.7 +#define DEMUX_INDEX_SIZE_MAX (100000)
2.8 +
2.9 +/* Indexes (timecodes/offsets) conversion structures */
2.10 +typedef struct
2.11 +{
2.12 + gint64 i_time;
2.13 + gint64 i_offset;
2.14 +
2.15 +} nuv_demux_index_entry;
2.16 +
2.17 +typedef struct
2.18 +{
2.19 + gint i_idx;
2.20 + gint i_idx_max;
2.21 +
2.22 + nuv_demux_index_entry *idx;
2.23 +} nuv_demux_index;
2.24
2.25 /* */
2.26 typedef struct
2.27 @@ -92,9 +109,9 @@
2.28 0x02: gauss 5 pixel (8,1,1,1,1)/12
2.29 0x04: cartoon filter */
2.30
2.31 - guint32 i_timecode; /* ms */
2.32 + gint32 i_timecode; /* ms */
2.33
2.34 - guint32 i_length; /* V,A,T: length of following data
2.35 + gint i_length; /* V,A,T: length of following data
2.36 S: length of packet correl */
2.37 } nuv_frame_header;
2.38
2.39 @@ -160,6 +177,13 @@
2.40 nuv_header *h;
2.41 nuv_extended_header *eh;
2.42 nuv_frame_header *fh;
2.43 +
2.44 + /* index */
2.45 + nuv_demux_index *index_entries;
2.46 + guint index_size;
2.47 + guint64 index_offset;
2.48 + guint current_entry;
2.49 +
2.50 } GstNuvDemux;
2.51
2.52 typedef struct _GstNuvDemuxClass {