diff options
-rw-r--r-- | gst/avi/gstavidemux.c | 1037 | ||||
-rw-r--r-- | gst/avi/gstavidemux.h | 8 |
2 files changed, 297 insertions, 748 deletions
diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c index 94917c59d..43a8a16cb 100644 --- a/gst/avi/gstavidemux.c +++ b/gst/avi/gstavidemux.c | |||
@@ -220,31 +220,37 @@ gst_avi_demux_finalize (GObject * object) | |||
220 | } | 220 | } |
221 | 221 | ||
222 | static void | 222 | static void |
223 | gst_avi_demux_reset_stream (GstAviDemux * avi, GstAviStream * stream) | ||
224 | { | ||
225 | g_free (stream->strh); | ||
226 | g_free (stream->strf.data); | ||
227 | g_free (stream->name); | ||
228 | g_free (stream->index); | ||
229 | g_free (stream->indexes); | ||
230 | if (stream->initdata) | ||
231 | gst_buffer_unref (stream->initdata); | ||
232 | if (stream->extradata) | ||
233 | gst_buffer_unref (stream->extradata); | ||
234 | if (stream->pad) { | ||
235 | gst_pad_set_active (stream->pad, FALSE); | ||
236 | gst_element_remove_pad (GST_ELEMENT (avi), stream->pad); | ||
237 | } | ||
238 | if (stream->taglist) { | ||
239 | gst_tag_list_free (stream->taglist); | ||
240 | stream->taglist = NULL; | ||
241 | } | ||
242 | memset (stream, 0, sizeof (GstAviStream)); | ||
243 | } | ||
244 | |||
245 | static void | ||
223 | gst_avi_demux_reset (GstAviDemux * avi) | 246 | gst_avi_demux_reset (GstAviDemux * avi) |
224 | { | 247 | { |
225 | gint i; | 248 | gint i; |
226 | 249 | ||
227 | GST_DEBUG ("AVI: reset"); | 250 | GST_DEBUG ("AVI: reset"); |
228 | 251 | ||
229 | for (i = 0; i < avi->num_streams; i++) { | 252 | for (i = 0; i < avi->num_streams; i++) |
230 | g_free (avi->stream[i].strh); | 253 | gst_avi_demux_reset_stream (avi, &avi->stream[i]); |
231 | g_free (avi->stream[i].strf.data); | ||
232 | if (avi->stream[i].name) | ||
233 | g_free (avi->stream[i].name); | ||
234 | if (avi->stream[i].initdata) | ||
235 | gst_buffer_unref (avi->stream[i].initdata); | ||
236 | if (avi->stream[i].extradata) | ||
237 | gst_buffer_unref (avi->stream[i].extradata); | ||
238 | if (avi->stream[i].pad) { | ||
239 | gst_pad_set_active (avi->stream[i].pad, FALSE); | ||
240 | gst_element_remove_pad (GST_ELEMENT (avi), avi->stream[i].pad); | ||
241 | } | ||
242 | if (avi->stream[i].taglist) { | ||
243 | gst_tag_list_free (avi->stream[i].taglist); | ||
244 | avi->stream[i].taglist = NULL; | ||
245 | } | ||
246 | } | ||
247 | memset (&avi->stream, 0, sizeof (avi->stream)); | ||
248 | 254 | ||
249 | avi->header_state = GST_AVI_DEMUX_HEADER_TAG_LIST; | 255 | avi->header_state = GST_AVI_DEMUX_HEADER_TAG_LIST; |
250 | avi->num_streams = 0; | 256 | avi->num_streams = 0; |
@@ -255,9 +261,6 @@ gst_avi_demux_reset (GstAviDemux * avi) | |||
255 | avi->state = GST_AVI_DEMUX_START; | 261 | avi->state = GST_AVI_DEMUX_START; |
256 | avi->offset = 0; | 262 | avi->offset = 0; |
257 | 263 | ||
258 | //g_free (avi->index_entries); | ||
259 | //avi->index_entries = NULL; | ||
260 | //avi->index_size = 0; | ||
261 | avi->index_offset = 0; | 264 | avi->index_offset = 0; |
262 | g_free (avi->avih); | 265 | g_free (avi->avih); |
263 | avi->avih = NULL; | 266 | avi->avih = NULL; |
@@ -310,14 +313,16 @@ static inline GstClockTime | |||
310 | avi_stream_convert_bytes_to_time_unchecked (GstAviStream * stream, | 313 | avi_stream_convert_bytes_to_time_unchecked (GstAviStream * stream, |
311 | guint64 bytes) | 314 | guint64 bytes) |
312 | { | 315 | { |
313 | return gst_util_uint64_scale (bytes, GST_SECOND, stream->strf.auds->av_bps); | 316 | return gst_util_uint64_scale_int (bytes, GST_SECOND, |
317 | stream->strf.auds->av_bps); | ||
314 | } | 318 | } |
315 | 319 | ||
316 | static inline guint64 | 320 | static inline guint64 |
317 | avi_stream_convert_time_to_bytes_unchecked (GstAviStream * stream, | 321 | avi_stream_convert_time_to_bytes_unchecked (GstAviStream * stream, |
318 | GstClockTime time) | 322 | GstClockTime time) |
319 | { | 323 | { |
320 | return gst_util_uint64_scale (time, stream->strf.auds->av_bps, GST_SECOND); | 324 | return gst_util_uint64_scale_int (time, stream->strf.auds->av_bps, |
325 | GST_SECOND); | ||
321 | } | 326 | } |
322 | 327 | ||
323 | /* assumes stream->strh->rate != 0 */ | 328 | /* assumes stream->strh->rate != 0 */ |
@@ -369,8 +374,8 @@ gst_avi_demux_src_convert (GstPad * pad, | |||
369 | case GST_FORMAT_TIME: | 374 | case GST_FORMAT_TIME: |
370 | switch (*dest_format) { | 375 | switch (*dest_format) { |
371 | case GST_FORMAT_BYTES: | 376 | case GST_FORMAT_BYTES: |
372 | *dest_value = gst_util_uint64_scale (src_value, | 377 | *dest_value = gst_util_uint64_scale_int (src_value, |
373 | (guint64) stream->strf.auds->av_bps, GST_SECOND); | 378 | stream->strf.auds->av_bps, GST_SECOND); |
374 | break; | 379 | break; |
375 | case GST_FORMAT_DEFAULT: | 380 | case GST_FORMAT_DEFAULT: |
376 | *dest_value = | 381 | *dest_value = |
@@ -1729,8 +1734,6 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf) | |||
1729 | if (stream->pad) | 1734 | if (stream->pad) |
1730 | gst_object_unref (stream->pad); | 1735 | gst_object_unref (stream->pad); |
1731 | pad = stream->pad = gst_pad_new_from_template (templ, padname); | 1736 | pad = stream->pad = gst_pad_new_from_template (templ, padname); |
1732 | stream->last_flow = GST_FLOW_OK; | ||
1733 | stream->discont = TRUE; | ||
1734 | g_free (padname); | 1737 | g_free (padname); |
1735 | 1738 | ||
1736 | gst_pad_use_fixed_caps (pad); | 1739 | gst_pad_use_fixed_caps (pad); |
@@ -1752,16 +1755,31 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf) | |||
1752 | #endif | 1755 | #endif |
1753 | 1756 | ||
1754 | stream->num = avi->num_streams; | 1757 | stream->num = avi->num_streams; |
1758 | |||
1759 | stream->start_entry = 0; | ||
1760 | stream->step_entry = 0; | ||
1761 | stream->stop_entry = 0; | ||
1762 | |||
1763 | stream->current_entry = -1; | ||
1764 | stream->current_total = 0; | ||
1765 | |||
1766 | stream->last_flow = GST_FLOW_OK; | ||
1767 | stream->discont = TRUE; | ||
1768 | |||
1755 | stream->total_bytes = 0; | 1769 | stream->total_bytes = 0; |
1756 | stream->idx_n = 0; | ||
1757 | stream->total_blocks = 0; | 1770 | stream->total_blocks = 0; |
1758 | stream->current_entry = 0; | 1771 | stream->n_keyframes = 0; |
1759 | stream->current_total = 0; | 1772 | |
1773 | stream->idx_n = 0; | ||
1774 | stream->idx_max = 0; | ||
1775 | |||
1760 | gst_pad_set_element_private (pad, stream); | 1776 | gst_pad_set_element_private (pad, stream); |
1761 | avi->num_streams++; | 1777 | avi->num_streams++; |
1778 | |||
1762 | gst_pad_set_caps (pad, caps); | 1779 | gst_pad_set_caps (pad, caps); |
1763 | gst_pad_set_active (pad, TRUE); | 1780 | gst_pad_set_active (pad, TRUE); |
1764 | gst_element_add_pad (GST_ELEMENT (avi), pad); | 1781 | gst_element_add_pad (GST_ELEMENT (avi), pad); |
1782 | |||
1765 | GST_LOG_OBJECT (element, "Added pad %s with caps %" GST_PTR_FORMAT, | 1783 | GST_LOG_OBJECT (element, "Added pad %s with caps %" GST_PTR_FORMAT, |
1766 | GST_PAD_NAME (pad), caps); | 1784 | GST_PAD_NAME (pad), caps); |
1767 | gst_caps_unref (caps); | 1785 | gst_caps_unref (caps); |
@@ -1792,15 +1810,7 @@ fail: | |||
1792 | gst_buffer_unref (sub); | 1810 | gst_buffer_unref (sub); |
1793 | g_free (vprp); | 1811 | g_free (vprp); |
1794 | g_free (codec_name); | 1812 | g_free (codec_name); |
1795 | g_free (stream->strh); | 1813 | gst_avi_demux_reset_stream (avi, stream); |
1796 | g_free (stream->strf.data); | ||
1797 | g_free (stream->name); | ||
1798 | g_free (stream->indexes); | ||
1799 | if (stream->initdata) | ||
1800 | gst_buffer_unref (stream->initdata); | ||
1801 | if (stream->extradata) | ||
1802 | gst_buffer_unref (stream->extradata); | ||
1803 | memset (stream, 0, sizeof (GstAviStream)); | ||
1804 | avi->num_streams++; | 1814 | avi->num_streams++; |
1805 | return FALSE; | 1815 | return FALSE; |
1806 | } | 1816 | } |
@@ -1918,12 +1928,14 @@ gst_avi_demux_index_entry_search (GstAviIndexEntry * entry, guint64 * total) | |||
1918 | } | 1928 | } |
1919 | 1929 | ||
1920 | /* | 1930 | /* |
1921 | * gst_avi_index_entry: | 1931 | * gst_avi_demux_index_for_time: |
1922 | * @avi: Avi object | 1932 | * @avi: Avi object |
1923 | * @stream: the stream | 1933 | * @stream: the stream |
1924 | * @time: seek time position | 1934 | * @time: a time position |
1925 | * | 1935 | * |
1926 | * Finds the index entry which time is less or equal than the requested time. | 1936 | * Finds the index entry which time is less or equal than the requested time. |
1937 | * Try to avoid binary search when we can convert the time to an index | ||
1938 | * position directly (for example for video frames with a fixed duration). | ||
1927 | * | 1939 | * |
1928 | * Returns: the found position in the index. | 1940 | * Returns: the found position in the index. |
1929 | */ | 1941 | */ |
@@ -1982,6 +1994,8 @@ gst_avi_demux_index_for_time (GstAviDemux * avi, | |||
1982 | return index; | 1994 | return index; |
1983 | } | 1995 | } |
1984 | 1996 | ||
1997 | /* given @entry_n in @stream, calculate info such as timestamps and | ||
1998 | * offsets for the entry. */ | ||
1985 | static void | 1999 | static void |
1986 | gst_avi_demux_get_buffer_info (GstAviDemux * avi, GstAviStream * stream, | 2000 | gst_avi_demux_get_buffer_info (GstAviDemux * avi, GstAviStream * stream, |
1987 | guint entry_n, GstClockTime * timestamp, GstClockTime * ts_end, | 2001 | guint entry_n, GstClockTime * timestamp, GstClockTime * ts_end, |
@@ -2032,6 +2046,136 @@ gst_avi_demux_get_buffer_info (GstAviDemux * avi, GstAviStream * stream, | |||
2032 | } | 2046 | } |
2033 | } | 2047 | } |
2034 | 2048 | ||
2049 | /* collect and debug stats about the indexes for all streams. | ||
2050 | * This method is also responsible for filling in the stream duration | ||
2051 | * as measured by the amount of index entries. */ | ||
2052 | static void | ||
2053 | gst_avi_demux_do_index_stats (GstAviDemux * avi) | ||
2054 | { | ||
2055 | guint i; | ||
2056 | #ifndef GST_DISABLE_GST_DEBUG | ||
2057 | guint total_idx = 0, total_max = 0; | ||
2058 | #endif | ||
2059 | |||
2060 | /* get stream stats now */ | ||
2061 | for (i = 0; i < avi->num_streams; i++) { | ||
2062 | GstAviIndexEntry *entry; | ||
2063 | GstAviStream *stream; | ||
2064 | guint64 total; | ||
2065 | |||
2066 | if (G_UNLIKELY (!(stream = &avi->stream[i]))) | ||
2067 | continue; | ||
2068 | if (G_UNLIKELY (!stream->strh)) | ||
2069 | continue; | ||
2070 | if (G_UNLIKELY (!stream->index || stream->idx_n == 0)) | ||
2071 | continue; | ||
2072 | |||
2073 | entry = &stream->index[stream->idx_n - 1]; | ||
2074 | total = entry->total + entry->size; | ||
2075 | |||
2076 | /* calculate duration */ | ||
2077 | if (stream->is_vbr) { | ||
2078 | /* VBR stream next timestamp */ | ||
2079 | if (stream->strh->type == GST_RIFF_FCC_auds) { | ||
2080 | stream->idx_duration = | ||
2081 | avi_stream_convert_frames_to_time_unchecked (stream, total); | ||
2082 | } else { | ||
2083 | stream->idx_duration = | ||
2084 | avi_stream_convert_frames_to_time_unchecked (stream, stream->idx_n); | ||
2085 | } | ||
2086 | } else { | ||
2087 | /* constant rate stream */ | ||
2088 | stream->idx_duration = avi_stream_convert_bytes_to_time_unchecked (stream, | ||
2089 | total); | ||
2090 | } | ||
2091 | #ifndef GST_DISABLE_GST_DEBUG | ||
2092 | total_idx += stream->idx_n; | ||
2093 | total_max += stream->idx_max; | ||
2094 | #endif | ||
2095 | GST_INFO_OBJECT (avi, "Stream %d, dur %" GST_TIME_FORMAT ", %6u entries, " | ||
2096 | "%5u keyframes, entry size = %2u, total size = %10u, allocated %10u", | ||
2097 | i, GST_TIME_ARGS (stream->idx_duration), stream->idx_n, | ||
2098 | stream->n_keyframes, (guint) sizeof (GstAviIndexEntry), | ||
2099 | (guint) (stream->idx_n * sizeof (GstAviIndexEntry)), | ||
2100 | (guint) (stream->idx_max * sizeof (GstAviIndexEntry))); | ||
2101 | } | ||
2102 | #ifndef GST_DISABLE_GST_DEBUG | ||
2103 | total_idx *= sizeof (GstAviIndexEntry); | ||
2104 | total_max *= sizeof (GstAviIndexEntry); | ||
2105 | #endif | ||
2106 | GST_INFO_OBJECT (avi, "%u bytes for index vs %u ideally, %u wasted", | ||
2107 | total_max, total_idx, total_max - total_idx); | ||
2108 | } | ||
2109 | |||
2110 | /* add an entry to the index of a stream. @num should be an estimate of the | ||
2111 | * total amount of index entries for all streams and is used to dynamically | ||
2112 | * allocate memory for the index entries. */ | ||
2113 | static inline gboolean | ||
2114 | gst_avi_demux_add_index (GstAviDemux * avi, GstAviStream * stream, | ||
2115 | guint num, GstAviIndexEntry * entry) | ||
2116 | { | ||
2117 | /* ensure index memory */ | ||
2118 | if (G_UNLIKELY (stream->idx_n >= stream->idx_max)) { | ||
2119 | /* we need to make some more room */ | ||
2120 | if (stream->idx_max == 0) { | ||
2121 | /* initial size guess, assume each stream has an equal amount of entries, | ||
2122 | * overshoot with at least 8K */ | ||
2123 | stream->idx_max = | ||
2124 | (num / avi->num_streams) + (8192 / sizeof (GstAviIndexEntry)); | ||
2125 | } else { | ||
2126 | stream->idx_max += 8192 / sizeof (GstAviIndexEntry); | ||
2127 | GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "expanded index to %u", | ||
2128 | stream->idx_max); | ||
2129 | } | ||
2130 | stream->index = g_try_renew (GstAviIndexEntry, stream->index, | ||
2131 | stream->idx_max); | ||
2132 | if (G_UNLIKELY (!stream->index)) | ||
2133 | return FALSE; | ||
2134 | } | ||
2135 | |||
2136 | /* update stream stats and total size */ | ||
2137 | entry->total = stream->total_bytes; | ||
2138 | stream->total_bytes += entry->size; | ||
2139 | if (stream->strh->type == GST_RIFF_FCC_auds) { | ||
2140 | gint blockalign = stream->strf.auds->blockalign; | ||
2141 | if (blockalign > 0) | ||
2142 | stream->total_blocks += DIV_ROUND_UP (entry->size, blockalign); | ||
2143 | else | ||
2144 | stream->total_blocks++; | ||
2145 | } | ||
2146 | if (ENTRY_IS_KEYFRAME (entry)) | ||
2147 | stream->n_keyframes++; | ||
2148 | |||
2149 | /* and add */ | ||
2150 | GST_LOG_OBJECT (avi, | ||
2151 | "Adding stream %u, index entry %d, kf %d, size %u " | ||
2152 | ", offset %" G_GUINT64_FORMAT ", total %" G_GUINT64_FORMAT, stream->num, | ||
2153 | stream->idx_n, ENTRY_IS_KEYFRAME (entry), entry->size, entry->offset, | ||
2154 | entry->total); | ||
2155 | stream->index[stream->idx_n++] = *entry; | ||
2156 | |||
2157 | return TRUE; | ||
2158 | } | ||
2159 | |||
2160 | static inline GstAviStream * | ||
2161 | gst_avi_demux_stream_for_id (GstAviDemux * avi, guint32 id) | ||
2162 | { | ||
2163 | guint stream_nr; | ||
2164 | GstAviStream *stream; | ||
2165 | |||
2166 | /* get the stream for this entry */ | ||
2167 | stream_nr = CHUNKID_TO_STREAMNR (id); | ||
2168 | if (G_UNLIKELY (stream_nr >= avi->num_streams)) { | ||
2169 | GST_WARNING_OBJECT (avi, "invalid stream nr %d", stream_nr); | ||
2170 | return NULL; | ||
2171 | } | ||
2172 | stream = &avi->stream[stream_nr]; | ||
2173 | if (G_UNLIKELY (!stream->strh)) { | ||
2174 | GST_WARNING_OBJECT (avi, "Unhandled stream %d, skipping", stream_nr); | ||
2175 | return NULL; | ||
2176 | } | ||
2177 | return stream; | ||
2178 | } | ||
2035 | 2179 | ||
2036 | /* | 2180 | /* |
2037 | * gst_avi_demux_parse_index: | 2181 | * gst_avi_demux_parse_index: |
@@ -2041,7 +2185,7 @@ gst_avi_demux_get_buffer_info (GstAviDemux * avi, GstAviStream * stream, | |||
2041 | * Read index entries from the provided buffer. | 2185 | * Read index entries from the provided buffer. |
2042 | * The buffer should contain a GST_RIFF_TAG_idx1 chunk. | 2186 | * The buffer should contain a GST_RIFF_TAG_idx1 chunk. |
2043 | */ | 2187 | */ |
2044 | static void | 2188 | static gboolean |
2045 | gst_avi_demux_parse_index (GstAviDemux * avi, GstBuffer * buf) | 2189 | gst_avi_demux_parse_index (GstAviDemux * avi, GstBuffer * buf) |
2046 | { | 2190 | { |
2047 | guint64 pos_before; | 2191 | guint64 pos_before; |
@@ -2051,9 +2195,8 @@ gst_avi_demux_parse_index (GstAviDemux * avi, GstBuffer * buf) | |||
2051 | gst_riff_index_entry *index; | 2195 | gst_riff_index_entry *index; |
2052 | GstClockTime stamp; | 2196 | GstClockTime stamp; |
2053 | GstAviStream *stream; | 2197 | GstAviStream *stream; |
2054 | #ifndef GST_DISABLE_GST_DEBUG | 2198 | GstAviIndexEntry entry; |
2055 | guint total_idx = 0, total_max = 0; | 2199 | guint32 id; |
2056 | #endif | ||
2057 | 2200 | ||
2058 | if (!buf) | 2201 | if (!buf) |
2059 | goto empty_list; | 2202 | goto empty_list; |
@@ -2063,20 +2206,27 @@ gst_avi_demux_parse_index (GstAviDemux * avi, GstBuffer * buf) | |||
2063 | 2206 | ||
2064 | stamp = gst_util_get_timestamp (); | 2207 | stamp = gst_util_get_timestamp (); |
2065 | 2208 | ||
2209 | /* see how many items in the index */ | ||
2066 | num = size / sizeof (gst_riff_index_entry); | 2210 | num = size / sizeof (gst_riff_index_entry); |
2067 | if (num == 0) | 2211 | if (num == 0) |
2068 | goto empty_list; | 2212 | goto empty_list; |
2069 | 2213 | ||
2070 | index = (gst_riff_index_entry *) data; | 2214 | GST_INFO_OBJECT (avi, "Parsing index, nr_entries = %6d", num); |
2071 | 2215 | ||
2216 | index = (gst_riff_index_entry *) data; | ||
2072 | pos_before = avi->offset; | 2217 | pos_before = avi->offset; |
2073 | GST_INFO_OBJECT (avi, "Parsing index, nr_entries = %6d", num); | ||
2074 | 2218 | ||
2075 | for (i = 0, n = 0; i < num; i++) { | 2219 | /* figure out if the index is 0 based or relative to the MOVI start */ |
2076 | GstAviIndexEntry entry; | 2220 | entry.offset = GST_READ_UINT32_LE (&index[0].offset); |
2077 | guint32 id; | 2221 | if (entry.offset < avi->offset) { |
2078 | guint stream_nr; | 2222 | avi->index_offset = avi->offset + 8; |
2223 | GST_DEBUG ("index_offset = %" G_GUINT64_FORMAT, avi->index_offset); | ||
2224 | } else { | ||
2225 | avi->index_offset = 0; | ||
2226 | GST_DEBUG ("index is 0 based"); | ||
2227 | } | ||
2079 | 2228 | ||
2229 | for (i = 0, n = 0; i < num; i++) { | ||
2080 | id = GST_READ_UINT32_LE (&index[i].id); | 2230 | id = GST_READ_UINT32_LE (&index[i].id); |
2081 | entry.offset = GST_READ_UINT32_LE (&index[i].offset); | 2231 | entry.offset = GST_READ_UINT32_LE (&index[i].offset); |
2082 | 2232 | ||
@@ -2085,148 +2235,53 @@ gst_avi_demux_parse_index (GstAviDemux * avi, GstBuffer * buf) | |||
2085 | (entry.offset == 0 && n > 0))) | 2235 | (entry.offset == 0 && n > 0))) |
2086 | continue; | 2236 | continue; |
2087 | 2237 | ||
2088 | /* figure out if the index is 0 based or relative to the MOVI start */ | ||
2089 | if (G_UNLIKELY (n == 0)) { | ||
2090 | if (entry.offset < pos_before) | ||
2091 | avi->index_offset = pos_before + 8; | ||
2092 | else | ||
2093 | avi->index_offset = 0; | ||
2094 | GST_DEBUG ("index_offset = %" G_GUINT64_FORMAT, avi->index_offset); | ||
2095 | } | ||
2096 | |||
2097 | /* get the stream for this entry */ | 2238 | /* get the stream for this entry */ |
2098 | stream_nr = CHUNKID_TO_STREAMNR (id); | 2239 | stream = gst_avi_demux_stream_for_id (avi, id); |
2099 | if (G_UNLIKELY (stream_nr >= avi->num_streams)) { | 2240 | if (G_UNLIKELY (!stream)) |
2100 | GST_WARNING_OBJECT (avi, | ||
2101 | "Index entry %d has invalid stream nr %d", i, stream_nr); | ||
2102 | continue; | 2241 | continue; |
2103 | } | 2242 | |
2104 | stream = &avi->stream[stream_nr]; | 2243 | /* handle offset and size */ |
2105 | if (G_UNLIKELY (!stream->strh)) { | 2244 | entry.offset += avi->index_offset + 8; |
2106 | GST_WARNING_OBJECT (avi, "Unhandled stream %d, skipping", stream_nr); | 2245 | entry.size = GST_READ_UINT32_LE (&index[i].size); |
2107 | continue; | ||
2108 | } | ||
2109 | 2246 | ||
2110 | /* handle flags */ | 2247 | /* handle flags */ |
2111 | if (stream->strh->type == GST_RIFF_FCC_auds) { | 2248 | if (stream->strh->type == GST_RIFF_FCC_auds) { |
2112 | /* all audio frames are keyframes */ | 2249 | /* all audio frames are keyframes */ |
2113 | ENTRY_SET_KEYFRAME (&entry); | 2250 | ENTRY_SET_KEYFRAME (&entry); |
2114 | stream->n_keyframes++; | ||
2115 | } else { | 2251 | } else { |
2116 | guint32 flags; | 2252 | guint32 flags; |
2117 | /* else read flags */ | 2253 | /* else read flags */ |
2118 | flags = GST_READ_UINT32_LE (&index[i].flags); | 2254 | flags = GST_READ_UINT32_LE (&index[i].flags); |
2119 | if (flags & GST_RIFF_IF_KEYFRAME) { | 2255 | if (flags & GST_RIFF_IF_KEYFRAME) { |
2120 | ENTRY_SET_KEYFRAME (&entry); | 2256 | ENTRY_SET_KEYFRAME (&entry); |
2121 | stream->n_keyframes++; | ||
2122 | } else { | 2257 | } else { |
2123 | ENTRY_UNSET_KEYFRAME (&entry); | 2258 | ENTRY_UNSET_KEYFRAME (&entry); |
2124 | } | 2259 | } |
2125 | } | 2260 | } |
2126 | 2261 | ||
2127 | /* handle size */ | 2262 | /* and add */ |
2128 | entry.size = GST_READ_UINT32_LE (&index[i].size); | 2263 | if (G_UNLIKELY (!gst_avi_demux_add_index (avi, stream, num, &entry))) |
2129 | 2264 | goto out_of_mem; | |
2130 | /* update stats */ | ||
2131 | entry.total = stream->total_bytes; | ||
2132 | stream->total_bytes += entry.size; | ||
2133 | if (stream->strh->type == GST_RIFF_FCC_auds) { | ||
2134 | gint blockalign = stream->strf.auds->blockalign; | ||
2135 | if (blockalign > 0) | ||
2136 | stream->total_blocks += DIV_ROUND_UP (entry.size, blockalign); | ||
2137 | else | ||
2138 | stream->total_blocks++; | ||
2139 | } | ||
2140 | |||
2141 | /* add to the index */ | ||
2142 | if (G_UNLIKELY (stream->idx_n >= stream->idx_max)) { | ||
2143 | /* we need to make some more room */ | ||
2144 | if (stream->idx_max == 0) { | ||
2145 | /* initial size guess, assume each stream has an equal amount of entries, | ||
2146 | * overshoot with at least 8K */ | ||
2147 | stream->idx_max = | ||
2148 | (num / avi->num_streams) + (8192 / sizeof (GstAviIndexEntry)); | ||
2149 | } else { | ||
2150 | stream->idx_max += 8192 / sizeof (GstAviIndexEntry); | ||
2151 | GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "expanded index to %u", | ||
2152 | stream->idx_max); | ||
2153 | } | ||
2154 | stream->index = g_try_renew (GstAviIndexEntry, stream->index, | ||
2155 | stream->idx_max); | ||
2156 | if (G_UNLIKELY (!stream->index)) | ||
2157 | goto out_of_mem; | ||
2158 | } | ||
2159 | |||
2160 | GST_LOG_OBJECT (avi, | ||
2161 | "Adding stream %u, index entry %d, kf %d, size %u " | ||
2162 | ", offset %" G_GUINT64_FORMAT ", total %" G_GUINT64_FORMAT, stream_nr, | ||
2163 | stream->idx_n, ENTRY_IS_KEYFRAME (&entry), entry.size, entry.offset, | ||
2164 | entry.total); | ||
2165 | |||
2166 | /* and copy */ | ||
2167 | stream->index[stream->idx_n++] = entry; | ||
2168 | 2265 | ||
2169 | n++; | 2266 | n++; |
2170 | } | 2267 | } |
2171 | /* get stream stats now */ | 2268 | /* get stream stats now */ |
2172 | for (i = 0; i < avi->num_streams; i++) { | 2269 | gst_avi_demux_do_index_stats (avi); |
2173 | GstAviIndexEntry *entry; | ||
2174 | guint64 total; | ||
2175 | |||
2176 | if (G_UNLIKELY (!(stream = &avi->stream[i]))) | ||
2177 | continue; | ||
2178 | if (G_UNLIKELY (!stream->strh)) | ||
2179 | continue; | ||
2180 | if (G_UNLIKELY (!stream->index || stream->idx_n == 0)) | ||
2181 | continue; | ||
2182 | |||
2183 | entry = &stream->index[stream->idx_n - 1]; | ||
2184 | total = entry->total + entry->size; | ||
2185 | |||
2186 | /* calculate duration */ | ||
2187 | if (stream->is_vbr) { | ||
2188 | /* VBR stream next timestamp */ | ||
2189 | if (stream->strh->type == GST_RIFF_FCC_auds) { | ||
2190 | stream->idx_duration = | ||
2191 | avi_stream_convert_frames_to_time_unchecked (stream, total); | ||
2192 | } else { | ||
2193 | stream->idx_duration = | ||
2194 | avi_stream_convert_frames_to_time_unchecked (stream, stream->idx_n); | ||
2195 | } | ||
2196 | } else { | ||
2197 | /* constant rate stream */ | ||
2198 | stream->idx_duration = avi_stream_convert_bytes_to_time_unchecked (stream, | ||
2199 | total); | ||
2200 | } | ||
2201 | #ifndef GST_DISABLE_GST_DEBUG | ||
2202 | total_idx += stream->idx_n; | ||
2203 | total_max += stream->idx_max; | ||
2204 | #endif | ||
2205 | GST_INFO_OBJECT (avi, "Stream %d, dur %" GST_TIME_FORMAT ", %6u entries, " | ||
2206 | "%5u keyframes, entry size = %2u, total size = %10u, allocated %10u", | ||
2207 | i, GST_TIME_ARGS (stream->idx_duration), stream->idx_n, | ||
2208 | stream->n_keyframes, (guint) sizeof (GstAviIndexEntry), | ||
2209 | (guint) (stream->idx_n * sizeof (GstAviIndexEntry)), | ||
2210 | (guint) (stream->idx_max * sizeof (GstAviIndexEntry))); | ||
2211 | } | ||
2212 | #ifndef GST_DISABLE_GST_DEBUG | ||
2213 | total_idx *= sizeof (GstAviIndexEntry); | ||
2214 | total_max *= sizeof (GstAviIndexEntry); | ||
2215 | #endif | ||
2216 | GST_INFO_OBJECT (avi, "%u bytes for index vs %u ideally, %u wasted", | ||
2217 | total_max, total_idx, total_max - total_idx); | ||
2218 | 2270 | ||
2219 | stamp = gst_util_get_timestamp () - stamp; | 2271 | stamp = gst_util_get_timestamp () - stamp; |
2220 | GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "parsing index %" GST_TIME_FORMAT, | 2272 | GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "parsing index %" GST_TIME_FORMAT, |
2221 | GST_TIME_ARGS (stamp)); | 2273 | GST_TIME_ARGS (stamp)); |
2222 | 2274 | ||
2223 | return; | 2275 | /* we have an index now */ |
2276 | avi->have_index = TRUE; | ||
2277 | |||
2278 | return TRUE; | ||
2224 | 2279 | ||
2225 | /* ERRORS */ | 2280 | /* ERRORS */ |
2226 | empty_list: | 2281 | empty_list: |
2227 | { | 2282 | { |
2228 | GST_DEBUG_OBJECT (avi, "empty index"); | 2283 | GST_DEBUG_OBJECT (avi, "empty index"); |
2229 | return; | 2284 | return FALSE; |
2230 | } | 2285 | } |
2231 | out_of_mem: | 2286 | out_of_mem: |
2232 | { | 2287 | { |
@@ -2234,7 +2289,7 @@ out_of_mem: | |||
2234 | ("Cannot allocate memory for %u*%u=%u bytes", | 2289 | ("Cannot allocate memory for %u*%u=%u bytes", |
2235 | (guint) sizeof (GstAviIndexEntry), num, | 2290 | (guint) sizeof (GstAviIndexEntry), num, |
2236 | (guint) sizeof (GstAviIndexEntry) * num)); | 2291 | (guint) sizeof (GstAviIndexEntry) * num)); |
2237 | return; | 2292 | return FALSE; |
2238 | } | 2293 | } |
2239 | } | 2294 | } |
2240 | 2295 | ||
@@ -2344,148 +2399,6 @@ zero_index: | |||
2344 | } | 2399 | } |
2345 | } | 2400 | } |
2346 | 2401 | ||
2347 | #if 0 | ||
2348 | /* | ||
2349 | * Sync to next data chunk. | ||
2350 | */ | ||
2351 | static gboolean | ||
2352 | gst_avi_demux_skip (GstAviDemux * avi, gboolean prevent_eos) | ||
2353 | { | ||
2354 | GstRiffRead *riff = GST_RIFF_READ (avi); | ||
2355 | |||
2356 | if (prevent_eos) { | ||
2357 | guint64 pos, length; | ||
2358 | guint size; | ||
2359 | guint8 *data; | ||
2360 | |||
2361 | pos = gst_bytestream_tell (riff->bs); | ||
2362 | length = gst_bytestream_length (riff->bs); | ||
2363 | |||
2364 | if (pos + 8 > length) | ||
2365 | return FALSE; | ||
2366 | |||
2367 | if (gst_bytestream_peek_bytes (riff->bs, &data, 8) != 8) | ||
2368 | return FALSE; | ||
2369 | |||
2370 | size = GST_READ_UINT32_LE (&data[4]); | ||
2371 | if (size & 1) | ||
2372 | size++; | ||
2373 | |||
2374 | /* Note, we're going to skip which might involve seeks. Therefore, | ||
2375 | * we need 1 byte more! */ | ||
2376 | if (pos + 8 + size >= length) | ||
2377 | return FALSE; | ||
2378 | } | ||
2379 | |||
2380 | return gst_riff_read_skip (riff); | ||
2381 | } | ||
2382 | |||
2383 | static gboolean | ||
2384 | gst_avi_demux_sync (GstAviDemux * avi, guint32 * ret_tag, gboolean prevent_eos) | ||
2385 | { | ||
2386 | GstRiffRead *riff = GST_RIFF_READ (avi); | ||
2387 | guint32 tag; | ||
2388 | guint64 length = gst_bytestream_length (riff->bs); | ||
2389 | |||
2390 | if (prevent_eos && gst_bytestream_tell (riff->bs) + 12 >= length) | ||
2391 | return FALSE; | ||
2392 | |||
2393 | /* peek first (for the end of this 'list/movi' section) */ | ||
2394 | if (!(tag = gst_riff_peek_tag (riff, &avi->level_up))) | ||
2395 | return FALSE; | ||
2396 | |||
2397 | /* if we're at top-level, we didn't read the 'movi' | ||
2398 | * list tag yet. This can also be 'AVIX' in case of | ||
2399 | * openDML-2.0 AVI files. Lastly, it might be idx1, | ||
2400 | * in which case we skip it so we come at EOS. */ | ||
2401 | while (1) { | ||
2402 | if (prevent_eos && gst_bytestream_tell (riff->bs) + 12 >= length) | ||
2403 | return FALSE; | ||
2404 | |||
2405 | if (!(tag = gst_riff_peek_tag (riff, NULL))) | ||
2406 | return FALSE; | ||
2407 | |||
2408 | switch (tag) { | ||
2409 | case GST_RIFF_TAG_LIST: | ||
2410 | if (!(tag = gst_riff_peek_list (riff))) | ||
2411 | return FALSE; | ||
2412 | |||
2413 | switch (tag) { | ||
2414 | case GST_RIFF_LIST_AVIX: | ||
2415 | if (!gst_riff_read_list (riff, &tag)) | ||
2416 | return FALSE; | ||
2417 | break; | ||
2418 | |||
2419 | case GST_RIFF_LIST_movi: | ||
2420 | if (!gst_riff_read_list (riff, &tag)) | ||
2421 | return FALSE; | ||
2422 | /* fall-through */ | ||
2423 | |||
2424 | case GST_RIFF_rec: | ||
2425 | goto done; | ||
2426 | |||
2427 | default: | ||
2428 | GST_WARNING ("Unknown list %" GST_FOURCC_FORMAT " before AVI data", | ||
2429 | GST_FOURCC_ARGS (tag)); | ||
2430 | /* fall-through */ | ||
2431 | |||
2432 | case GST_RIFF_TAG_JUNK: | ||
2433 | if (!gst_avi_demux_skip (avi, prevent_eos)) | ||
2434 | return FALSE; | ||
2435 | break; | ||
2436 | } | ||
2437 | break; | ||
2438 | |||
2439 | default: | ||
2440 | if ((tag & 0xff) >= '0' && (tag & 0xff) <= '9' && | ||
2441 | ((tag >> 8) & 0xff) >= '0' && ((tag >> 8) & 0xff) <= '9') { | ||
2442 | goto done; | ||
2443 | } | ||
2444 | /* pass-through */ | ||
2445 | |||
2446 | case GST_RIFF_TAG_idx1: | ||
2447 | case GST_RIFF_TAG_JUNK: | ||
2448 | if (!gst_avi_demux_skip (avi, prevent_eos)) { | ||
2449 | return FALSE; | ||
2450 | } | ||
2451 | break; | ||
2452 | } | ||
2453 | } | ||
2454 | done: | ||
2455 | /* And then, we get the data */ | ||
2456 | if (prevent_eos && gst_bytestream_tell (riff->bs) + 12 >= length) | ||
2457 | return FALSE; | ||
2458 | |||
2459 | if (!(tag = gst_riff_peek_tag (riff, NULL))) | ||
2460 | return FALSE; | ||
2461 | |||
2462 | /* Support for rec-list files */ | ||
2463 | switch (tag) { | ||
2464 | case GST_RIFF_TAG_LIST: | ||
2465 | if (!(tag = gst_riff_peek_list (riff))) | ||
2466 | return FALSE; | ||
2467 | if (tag == GST_RIFF_rec) { | ||
2468 | /* Simply skip the list */ | ||
2469 | if (!gst_riff_read_list (riff, &tag)) | ||
2470 | return FALSE; | ||
2471 | if (!(tag = gst_riff_peek_tag (riff, NULL))) | ||
2472 | return FALSE; | ||
2473 | } | ||
2474 | break; | ||
2475 | |||
2476 | case GST_RIFF_TAG_JUNK: | ||
2477 | gst_avi_demux_skip (avi, prevent_eos); | ||
2478 | return FALSE; | ||
2479 | } | ||
2480 | |||
2481 | if (ret_tag) | ||
2482 | *ret_tag = tag; | ||
2483 | |||
2484 | return TRUE; | ||
2485 | } | ||
2486 | #endif | ||
2487 | |||
2488 | #if 0 | ||
2489 | /* | 2402 | /* |
2490 | * gst_avi_demux_peek_tag: | 2403 | * gst_avi_demux_peek_tag: |
2491 | * | 2404 | * |
@@ -2498,6 +2411,7 @@ gst_avi_demux_peek_tag (GstAviDemux * avi, guint64 offset, guint32 * tag, | |||
2498 | GstFlowReturn res = GST_FLOW_OK; | 2411 | GstFlowReturn res = GST_FLOW_OK; |
2499 | GstBuffer *buf = NULL; | 2412 | GstBuffer *buf = NULL; |
2500 | guint bufsize; | 2413 | guint bufsize; |
2414 | guint8 *bufdata; | ||
2501 | 2415 | ||
2502 | res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf); | 2416 | res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf); |
2503 | if (res != GST_FLOW_OK) | 2417 | if (res != GST_FLOW_OK) |
@@ -2507,12 +2421,15 @@ gst_avi_demux_peek_tag (GstAviDemux * avi, guint64 offset, guint32 * tag, | |||
2507 | if (bufsize != 8) | 2421 | if (bufsize != 8) |
2508 | goto wrong_size; | 2422 | goto wrong_size; |
2509 | 2423 | ||
2510 | *tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); | 2424 | bufdata = GST_BUFFER_DATA (buf); |
2511 | *size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4); | 2425 | |
2426 | *tag = GST_READ_UINT32_LE (bufdata); | ||
2427 | *size = GST_READ_UINT32_LE (bufdata + 4); | ||
2512 | 2428 | ||
2513 | GST_LOG_OBJECT (avi, "Tag[%" GST_FOURCC_FORMAT "] (size:%d) %" | 2429 | GST_LOG_OBJECT (avi, "Tag[%" GST_FOURCC_FORMAT "] (size:%d) %" |
2514 | G_GINT64_FORMAT " -- %" G_GINT64_FORMAT, GST_FOURCC_ARGS (*tag), | 2430 | G_GINT64_FORMAT " -- %" G_GINT64_FORMAT, GST_FOURCC_ARGS (*tag), |
2515 | *size, offset + 8, offset + 8 + (gint64) * size); | 2431 | *size, offset + 8, offset + 8 + (gint64) * size); |
2432 | |||
2516 | done: | 2433 | done: |
2517 | gst_buffer_unref (buf); | 2434 | gst_buffer_unref (buf); |
2518 | 2435 | ||
@@ -2531,9 +2448,7 @@ wrong_size: | |||
2531 | goto done; | 2448 | goto done; |
2532 | } | 2449 | } |
2533 | } | 2450 | } |
2534 | #endif | ||
2535 | 2451 | ||
2536 | #if 0 | ||
2537 | /* | 2452 | /* |
2538 | * gst_avi_demux_next_data_buffer: | 2453 | * gst_avi_demux_next_data_buffer: |
2539 | * | 2454 | * |
@@ -2563,132 +2478,63 @@ gst_avi_demux_next_data_buffer (GstAviDemux * avi, guint64 * offset, | |||
2563 | 2478 | ||
2564 | return res; | 2479 | return res; |
2565 | } | 2480 | } |
2566 | #endif | ||
2567 | 2481 | ||
2568 | #if 0 | ||
2569 | /* | 2482 | /* |
2570 | * gst_avi_demux_stream_scan: | 2483 | * gst_avi_demux_stream_scan: |
2571 | * @avi: calling element (used for debugging/errors). | 2484 | * @avi: calling element (used for debugging/errors). |
2572 | * @index: list of index entries, returned by this function. | ||
2573 | * @alloc_list: list of allocated data, returned by this function. | ||
2574 | * | 2485 | * |
2575 | * Scan the file for all chunks to "create" a new index. | 2486 | * Scan the file for all chunks to "create" a new index. |
2576 | * Return value indicates if we can continue reading the stream. It | ||
2577 | * does not say anything about whether we created an index. | ||
2578 | * | ||
2579 | * pull-range based | 2487 | * pull-range based |
2580 | */ | 2488 | */ |
2581 | static gboolean | 2489 | static gboolean |
2582 | gst_avi_demux_stream_scan (GstAviDemux * avi, | 2490 | gst_avi_demux_stream_scan (GstAviDemux * avi) |
2583 | GList ** index, GList ** alloc_list) | ||
2584 | { | 2491 | { |
2585 | GstFlowReturn res; | 2492 | GstFlowReturn res; |
2586 | gst_avi_index_entry *entry, *entries = NULL; | ||
2587 | GstAviStream *stream; | 2493 | GstAviStream *stream; |
2588 | GstFormat format; | 2494 | GstFormat format; |
2589 | guint64 pos = avi->offset; | 2495 | guint64 pos; |
2590 | guint64 length; | 2496 | guint64 length; |
2591 | gint64 tmplength; | 2497 | gint64 tmplength; |
2592 | guint32 tag = 0; | 2498 | guint32 tag = 0; |
2593 | GList *list = NULL; | 2499 | guint num; |
2594 | guint index_size = 0; | ||
2595 | 2500 | ||
2596 | /* FIXME: | 2501 | /* FIXME: |
2597 | * - implement non-seekable source support. | 2502 | * - implement non-seekable source support. |
2598 | */ | 2503 | */ |
2599 | GST_DEBUG_OBJECT (avi, | 2504 | GST_DEBUG_OBJECT (avi, |
2600 | "Creating index %s existing index, starting at offset %" G_GUINT64_FORMAT, | 2505 | "Creating index starting at offset %" G_GUINT64_FORMAT, pos); |
2601 | ((*index) ? "with" : "without"), pos); | ||
2602 | 2506 | ||
2507 | /* get the size of the file */ | ||
2603 | format = GST_FORMAT_BYTES; | 2508 | format = GST_FORMAT_BYTES; |
2604 | if (!gst_pad_query_peer_duration (avi->sinkpad, &format, &tmplength)) | 2509 | if (!gst_pad_query_peer_duration (avi->sinkpad, &format, &tmplength)) |
2605 | return FALSE; | 2510 | return FALSE; |
2606 | |||
2607 | length = tmplength; | 2511 | length = tmplength; |
2608 | 2512 | ||
2609 | if (*index) { | 2513 | /* guess the total amount of entries we expect */ |
2610 | entry = g_list_last (*index)->data; | 2514 | num = 16000; |
2611 | pos = entry->offset + avi->index_offset + entry->size; | ||
2612 | if (entry->size & 1) | ||
2613 | pos++; | ||
2614 | |||
2615 | if (pos >= length) { | ||
2616 | GST_LOG_OBJECT (avi, "Complete index, we're done"); | ||
2617 | return TRUE; | ||
2618 | } | ||
2619 | |||
2620 | GST_LOG_OBJECT (avi, "Incomplete index, seeking to last valid entry @ %" | ||
2621 | G_GUINT64_FORMAT " of %" G_GUINT64_FORMAT " (%" | ||
2622 | G_GUINT64_FORMAT "+%u)", pos, length, entry->offset, entry->size); | ||
2623 | } | ||
2624 | 2515 | ||
2625 | while (TRUE) { | 2516 | while (TRUE) { |
2626 | guint stream_nr; | 2517 | GstAviIndexEntry entry; |
2627 | guint size = 0; | 2518 | guint size = 0; |
2628 | 2519 | ||
2520 | /* start reading data buffers to find the id and offset */ | ||
2629 | res = gst_avi_demux_next_data_buffer (avi, &pos, &tag, &size); | 2521 | res = gst_avi_demux_next_data_buffer (avi, &pos, &tag, &size); |
2630 | if (G_UNLIKELY (res != GST_FLOW_OK)) | 2522 | if (G_UNLIKELY (res != GST_FLOW_OK)) |
2631 | break; | 2523 | break; |
2632 | 2524 | ||
2633 | /* check valid stream */ | 2525 | /* get stream */ |
2634 | stream_nr = CHUNKID_TO_STREAMNR (tag); | 2526 | stream = gst_avi_demux_stream_for_id (avi, tag); |
2635 | if (G_UNLIKELY (stream_nr >= avi->num_streams)) { | 2527 | if (G_UNLIKELY (!stream)) |
2636 | GST_WARNING_OBJECT (avi, | ||
2637 | "Index entry has invalid stream nr %d", stream_nr); | ||
2638 | goto next; | ||
2639 | } | ||
2640 | |||
2641 | stream = &avi->stream[stream_nr]; | ||
2642 | if (G_UNLIKELY (stream->pad == NULL)) { | ||
2643 | GST_WARNING_OBJECT (avi, | ||
2644 | "Stream %d does not have an output pad, can't create new index", | ||
2645 | stream_nr); | ||
2646 | goto next; | 2528 | goto next; |
2647 | } | ||
2648 | |||
2649 | /* pre-allocate */ | ||
2650 | if (G_UNLIKELY (index_size % 1024 == 0)) { | ||
2651 | entries = g_new (gst_avi_index_entry, 1024); | ||
2652 | *alloc_list = g_list_prepend (*alloc_list, entries); | ||
2653 | } | ||
2654 | entry = &entries[index_size % 1024]; | ||
2655 | 2529 | ||
2656 | entry->index_nr = index_size++; | 2530 | /* we can't figure out the keyframes, assume they all are */ |
2657 | entry->stream_nr = stream_nr; | 2531 | entry.flags = GST_AVI_KEYFRAME; |
2658 | entry->flags = GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME; | 2532 | entry.offset = pos; |
2659 | entry->offset = pos - avi->index_offset; | 2533 | entry.size = size; |
2660 | entry->size = size; | ||
2661 | 2534 | ||
2662 | /* timestamps, get timestamps of two consecutive frames to calculate | 2535 | /* and add to the index of this stream */ |
2663 | * timestamp and duration. */ | 2536 | if (G_UNLIKELY (!gst_avi_demux_add_index (avi, stream, num, &entry))) |
2664 | format = GST_FORMAT_TIME; | 2537 | goto out_of_mem; |
2665 | if (stream->is_vbr) { | ||
2666 | /* VBR stream */ | ||
2667 | entry->ts = avi_stream_convert_frames_to_time_unchecked (stream, | ||
2668 | stream->idx_n); | ||
2669 | entry->dur = avi_stream_convert_frames_to_time_unchecked (stream, | ||
2670 | stream->idx_n + 1); | ||
2671 | } else { | ||
2672 | /* constant rate stream */ | ||
2673 | entry->ts = avi_stream_convert_bytes_to_time_unchecked (stream, | ||
2674 | stream->total_bytes); | ||
2675 | entry->dur = avi_stream_convert_bytes_to_time_unchecked (stream, | ||
2676 | stream->total_bytes + entry->size); | ||
2677 | } | ||
2678 | entry->dur -= entry->ts; | ||
2679 | |||
2680 | /* stream position */ | ||
2681 | entry->bytes_before = stream->total_bytes; | ||
2682 | stream->total_bytes += entry->size; | ||
2683 | entry->frames_before = stream->idx_n; | ||
2684 | stream->idx_n++; | ||
2685 | stream->idx_duration = entry->ts + entry->dur; | ||
2686 | |||
2687 | list = g_list_prepend (list, entry); | ||
2688 | GST_DEBUG_OBJECT (avi, "Added index entry %d (in stream: %d), offset %" | ||
2689 | G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT " for stream %d", | ||
2690 | index_size - 1, entry->frames_before, entry->offset, | ||
2691 | GST_TIME_ARGS (entry->ts), entry->stream_nr); | ||
2692 | 2538 | ||
2693 | next: | 2539 | next: |
2694 | /* update position */ | 2540 | /* update position */ |
@@ -2699,314 +2545,47 @@ gst_avi_demux_stream_scan (GstAviDemux * avi, | |||
2699 | break; | 2545 | break; |
2700 | } | 2546 | } |
2701 | } | 2547 | } |
2548 | /* collect stats */ | ||
2549 | gst_avi_demux_do_index_stats (avi); | ||
2702 | 2550 | ||
2703 | /* FIXME: why is this disabled */ | 2551 | /* we have an index now */ |
2704 | #if 0 | 2552 | avi->have_index = TRUE; |
2705 | while (gst_avi_demux_sync (avi, &tag, TRUE)) { | ||
2706 | guint stream_nr = CHUNKID_TO_STREAMNR (tag); | ||
2707 | guint8 *data; | ||
2708 | GstFormat format = GST_FORMAT_TIME; | ||
2709 | |||
2710 | if (stream_nr >= avi->num_streams) | ||
2711 | goto next; | ||
2712 | stream = &avi->stream[stream_nr]; | ||
2713 | |||
2714 | /* get chunk size */ | ||
2715 | if (gst_bytestream_peek_bytes (riff->bs, &data, 8) != 8) | ||
2716 | goto next; | ||
2717 | |||
2718 | /* fill in */ | ||
2719 | entry->index_nr = index_size++; | ||
2720 | entry->stream_nr = stream_nr; | ||
2721 | entry->flags = GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME; | ||
2722 | entry->offset = gst_bytestream_tell (riff->bs) + 8 - avi->index_offset; | ||
2723 | entry->size = GST_READ_UINT32_LE (&data[4]); | ||
2724 | |||
2725 | /* timestamps */ | ||
2726 | if (stream->is_vbr) { | ||
2727 | /* VBR stream */ | ||
2728 | entry->ts = avi_stream_convert_frames_to_time_unchecked (stream, | ||
2729 | stream->idx_n); | ||
2730 | entry->dur = avi_stream_convert_frames_to_time_unchecked (stream, | ||
2731 | stream->idx_n + 1); | ||
2732 | } else { | ||
2733 | /* constant rate stream */ | ||
2734 | entry->ts = avi_stream_convert_bytes_to_time_unchecked (stream, | ||
2735 | stream->total_bytes); | ||
2736 | entry->dur = avi_stream_convert_bytes_to_time_unchecked (stream, | ||
2737 | stream->total_bytes + entry->size); | ||
2738 | } | ||
2739 | entry->dur -= entry->ts; | ||
2740 | |||
2741 | /* stream position */ | ||
2742 | entry->bytes_before = stream->total_bytes; | ||
2743 | stream->total_bytes += entry->size; | ||
2744 | entry->frames_before = stream->idx_n; | ||
2745 | stream->idx_n++; | ||
2746 | |||
2747 | list = g_list_prepend (list, entry); | ||
2748 | GST_DEBUG_OBJECT (avi, "Added index entry %d (in stream: %d), offset %" | ||
2749 | G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT " for stream %d", | ||
2750 | index_size - 1, entry->frames_before, entry->offset, | ||
2751 | GST_TIME_ARGS (entry->ts), entry->stream_nr); | ||
2752 | |||
2753 | next: | ||
2754 | if (!gst_avi_demux_skip (avi, TRUE)) | ||
2755 | break; | ||
2756 | } | ||
2757 | /* seek back */ | ||
2758 | if (!(event = gst_riff_read_seek (riff, pos))) { | ||
2759 | g_list_free (list); | ||
2760 | return FALSE; | ||
2761 | } | ||
2762 | gst_event_unref (event); | ||
2763 | |||
2764 | #endif | ||
2765 | |||
2766 | GST_DEBUG_OBJECT (avi, "index created, %d items", index_size); | ||
2767 | |||
2768 | *index = g_list_concat (*index, g_list_reverse (list)); | ||
2769 | |||
2770 | return TRUE; | ||
2771 | } | ||
2772 | #endif | ||
2773 | |||
2774 | #if 0 | ||
2775 | /* | ||
2776 | * gst_avi_demux_massage_index: | ||
2777 | * @avi: calling element (used for debugging/errors). | ||
2778 | * | ||
2779 | * We're going to go over each entry in the index and finetune | ||
2780 | * some things we don't like about AVI. For example, a single | ||
2781 | * chunk might be too long. Also, individual streams might be | ||
2782 | * out-of-sync. In the first case, we cut the chunk in several | ||
2783 | * smaller pieces. In the second case, we re-order chunk reading | ||
2784 | * order. The end result should be a smoother playing AVI. | ||
2785 | */ | ||
2786 | static gboolean | ||
2787 | gst_avi_demux_massage_index (GstAviDemux * avi, | ||
2788 | GList * list, GList * alloc_list) | ||
2789 | { | ||
2790 | gst_avi_index_entry *entry; | ||
2791 | GstAviStream *stream; | ||
2792 | guint i; | ||
2793 | GList *node; | ||
2794 | gint64 delay = G_GINT64_CONSTANT (0); | ||
2795 | GstClockTime stamp; | ||
2796 | |||
2797 | stamp = gst_util_get_timestamp (); | ||
2798 | |||
2799 | GST_LOG_OBJECT (avi, "Starting index massage, nr_entries = %d", | ||
2800 | list ? g_list_length (list) : 0); | ||
2801 | |||
2802 | if (list) { | ||
2803 | #ifndef GST_DISABLE_GST_DEBUG | ||
2804 | guint num_added_total = 0; | ||
2805 | guint num_per_stream[GST_AVI_DEMUX_MAX_STREAMS] = { 0, }; | ||
2806 | #endif | ||
2807 | GST_LOG_OBJECT (avi, | ||
2808 | "I'm now going to cut large chunks into smaller pieces"); | ||
2809 | |||
2810 | /* cut chunks in small (seekable) pieces | ||
2811 | * FIXME: this should be a property where a value of | ||
2812 | * GST_CLOCK_TIME_NONE would disable the chunking | ||
2813 | */ | ||
2814 | #define MAX_DURATION (GST_SECOND / 2) | ||
2815 | for (i = 0; i < avi->num_streams; i++) { | ||
2816 | /* only chop streams that have exactly *one* chunk */ | ||
2817 | if (avi->stream[i].idx_n != 1) | ||
2818 | continue; | ||
2819 | |||
2820 | for (node = list; node != NULL; node = node->next) { | ||
2821 | entry = node->data; | ||
2822 | |||
2823 | if (entry->stream_nr != i) | ||
2824 | continue; | ||
2825 | |||
2826 | /* check for max duration of a single buffer. I suppose that | ||
2827 | * the allocation of index entries could be improved. */ | ||
2828 | stream = &avi->stream[entry->stream_nr]; | ||
2829 | if (entry->dur > MAX_DURATION | ||
2830 | && stream->strh->type == GST_RIFF_FCC_auds) { | ||
2831 | guint32 ideal_size; | ||
2832 | gst_avi_index_entry *entries; | ||
2833 | guint old_size, num_added; | ||
2834 | GList *node2; | ||
2835 | |||
2836 | /* cut in 1/10th of a second */ | ||
2837 | ideal_size = stream->strf.auds->av_bps / 10; | ||
2838 | |||
2839 | /* ensure chunk size is multiple of blockalign */ | ||
2840 | if (stream->strf.auds->blockalign > 1) | ||
2841 | ideal_size -= ideal_size % stream->strf.auds->blockalign; | ||
2842 | |||
2843 | /* copy index */ | ||
2844 | old_size = entry->size; | ||
2845 | num_added = (entry->size - 1) / ideal_size; | ||
2846 | avi->index_size += num_added; | ||
2847 | entries = g_malloc (sizeof (gst_avi_index_entry) * num_added); | ||
2848 | alloc_list = g_list_prepend (alloc_list, entries); | ||
2849 | for (node2 = node->next; node2 != NULL; node2 = node2->next) { | ||
2850 | gst_avi_index_entry *entry2 = node2->data; | ||
2851 | |||
2852 | entry2->index_nr += num_added; | ||
2853 | if (entry2->stream_nr == entry->stream_nr) | ||
2854 | entry2->frames_before += num_added; | ||
2855 | } | ||
2856 | |||
2857 | /* new sized index chunks */ | ||
2858 | for (i = 0; i < num_added + 1; i++) { | ||
2859 | gst_avi_index_entry *entry2; | ||
2860 | |||
2861 | if (i == 0) { | ||
2862 | entry2 = entry; | ||
2863 | } else { | ||
2864 | entry2 = &entries[i - 1]; | ||
2865 | list = g_list_insert_before (list, node->next, entry2); | ||
2866 | entry = node->data; | ||
2867 | node = node->next; | ||
2868 | memcpy (entry2, entry, sizeof (gst_avi_index_entry)); | ||
2869 | } | ||
2870 | |||
2871 | if (old_size >= ideal_size) { | ||
2872 | entry2->size = ideal_size; | ||
2873 | old_size -= ideal_size; | ||
2874 | } else { | ||
2875 | entry2->size = old_size; | ||
2876 | } | ||
2877 | |||
2878 | entry2->dur = GST_SECOND * entry2->size / stream->strf.auds->av_bps; | ||
2879 | if (i != 0) { | ||
2880 | entry2->index_nr++; | ||
2881 | entry2->ts += entry->dur; | ||
2882 | entry2->offset += entry->size; | ||
2883 | entry2->bytes_before += entry->size; | ||
2884 | entry2->frames_before++; | ||
2885 | } | ||
2886 | } | ||
2887 | #ifndef GST_DISABLE_GST_DEBUG | ||
2888 | num_added_total += num_added; | ||
2889 | #endif | ||
2890 | } | ||
2891 | } | ||
2892 | } | ||
2893 | #ifndef GST_DISABLE_GST_DEBUG | ||
2894 | if (num_added_total) | ||
2895 | GST_LOG ("added %u new index entries", num_added_total); | ||
2896 | #endif | ||
2897 | |||
2898 | GST_LOG_OBJECT (avi, "I'm now going to reorder the index entries for time"); | ||
2899 | |||
2900 | /* re-order for time */ | ||
2901 | list = g_list_sort (list, (GCompareFunc) sort); | ||
2902 | |||
2903 | /* make a continous array out of the list */ | ||
2904 | avi->index_size = g_list_length (list); | ||
2905 | avi->index_entries = g_try_new (gst_avi_index_entry, avi->index_size); | ||
2906 | if (!avi->index_entries) | ||
2907 | goto out_of_mem; | ||
2908 | |||
2909 | entry = (gst_avi_index_entry *) (list->data); | ||
2910 | delay = entry->ts; | ||
2911 | |||
2912 | GST_LOG_OBJECT (avi, | ||
2913 | "Building index array, nr_entries = %d (time offset = %" | ||
2914 | GST_TIME_FORMAT, avi->index_size, GST_TIME_ARGS (delay)); | ||
2915 | |||
2916 | for (i = 0, node = list; node != NULL; node = node->next, i++) { | ||
2917 | entry = node->data; | ||
2918 | entry->index_nr = i; | ||
2919 | entry->ts -= delay; | ||
2920 | memcpy (&avi->index_entries[i], entry, sizeof (gst_avi_index_entry)); | ||
2921 | #ifndef GST_DISABLE_GST_DEBUG | ||
2922 | num_per_stream[entry->stream_nr]++; | ||
2923 | #endif | ||
2924 | |||
2925 | GST_LOG_OBJECT (avi, "Sorted index entry %3d for stream %d of size %6u" | ||
2926 | " at offset %7" G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT | ||
2927 | " dur %" GST_TIME_FORMAT, | ||
2928 | avi->index_entries[i].index_nr, entry->stream_nr, entry->size, | ||
2929 | entry->offset, GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (entry->dur)); | ||
2930 | } | ||
2931 | if (delay) { | ||
2932 | for (i = 0; i < avi->num_streams; i++) { | ||
2933 | stream = &avi->stream[i]; | ||
2934 | stream->idx_duration -= delay; | ||
2935 | } | ||
2936 | } | ||
2937 | #ifndef GST_DISABLE_GST_DEBUG | ||
2938 | { | ||
2939 | gchar str[GST_AVI_DEMUX_MAX_STREAMS * (1 + 6 + 2)]; | ||
2940 | gchar *pad_name; | ||
2941 | |||
2942 | for (i = 0; i < avi->num_streams; i++) { | ||
2943 | if (!avi->stream[i].pad) | ||
2944 | continue; | ||
2945 | pad_name = GST_OBJECT_NAME (avi->stream[i].pad); | ||
2946 | sprintf (&str[i * (1 + 6 + 2)], " %6u %c", num_per_stream[i], | ||
2947 | pad_name[0]); | ||
2948 | } | ||
2949 | GST_LOG_OBJECT (avi, "indizies per stream:%20s", str); | ||
2950 | } | ||
2951 | #endif | ||
2952 | |||
2953 | GST_LOG_OBJECT (avi, "Freeing original index list"); | ||
2954 | /* all the node->data in list point to alloc_list chunks */ | ||
2955 | |||
2956 | g_list_free (list); | ||
2957 | } | ||
2958 | if (alloc_list) { | ||
2959 | g_list_foreach (alloc_list, (GFunc) g_free, NULL); | ||
2960 | g_list_free (alloc_list); | ||
2961 | } | ||
2962 | #ifndef GST_DISABLE_GST_DEBUG | ||
2963 | for (i = 0; i < avi->num_streams; i++) { | ||
2964 | GST_LOG_OBJECT (avi, "Stream %d, %d frames, %8" G_GUINT64_FORMAT " bytes", | ||
2965 | i, avi->stream[i].idx_n, avi->stream[i].total_bytes); | ||
2966 | } | ||
2967 | #endif | ||
2968 | |||
2969 | GST_LOG_OBJECT (avi, "Index massaging done"); | ||
2970 | |||
2971 | stamp = gst_util_get_timestamp () - stamp; | ||
2972 | |||
2973 | GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "massaging index %" GST_TIME_FORMAT, | ||
2974 | GST_TIME_ARGS (stamp)); | ||
2975 | 2553 | ||
2976 | return TRUE; | 2554 | return TRUE; |
2977 | 2555 | ||
2978 | /* ERRORS */ | 2556 | /* ERRORS */ |
2979 | out_of_mem: | 2557 | out_of_mem: |
2980 | { | 2558 | { |
2981 | GST_WARNING_OBJECT (avi, "Out of memory for %" G_GSIZE_FORMAT " bytes", | 2559 | GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL), |
2982 | sizeof (gst_avi_index_entry) * avi->index_size); | 2560 | ("Cannot allocate memory for %u*%u=%u bytes", |
2561 | (guint) sizeof (GstAviIndexEntry), num, | ||
2562 | (guint) sizeof (GstAviIndexEntry) * num)); | ||
2983 | return FALSE; | 2563 | return FALSE; |
2984 | } | 2564 | } |
2985 | } | 2565 | } |
2986 | #endif | ||
2987 | 2566 | ||
2988 | static void | 2567 | static void |
2989 | gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi) | 2568 | gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi) |
2990 | { | 2569 | { |
2991 | gint stream; | 2570 | guint i; |
2992 | GstClockTime total; | 2571 | GstClockTime total; |
2572 | GstAviStream *stream; | ||
2993 | 2573 | ||
2994 | total = GST_CLOCK_TIME_NONE; | 2574 | total = GST_CLOCK_TIME_NONE; |
2995 | 2575 | ||
2996 | /* all streams start at a timestamp 0 */ | 2576 | /* all streams start at a timestamp 0 */ |
2997 | for (stream = 0; stream < avi->num_streams; stream++) { | 2577 | for (i = 0; i < avi->num_streams; i++) { |
2998 | GstClockTime duration, hduration; | 2578 | GstClockTime duration, hduration; |
2999 | GstAviStream *streamc = &avi->stream[stream]; | 2579 | gst_riff_strh *strh; |
3000 | gst_riff_strh *strh = streamc->strh; | ||
3001 | 2580 | ||
3002 | if (!strh) | 2581 | stream = &avi->stream[i]; |
2582 | if (G_UNLIKELY (!stream || !(strh = stream->strh))) | ||
3003 | continue; | 2583 | continue; |
3004 | 2584 | ||
3005 | /* get header duration for the stream */ | 2585 | /* get header duration for the stream */ |
3006 | hduration = streamc->hdr_duration; | 2586 | hduration = stream->hdr_duration; |
3007 | 2587 | /* index duration calculated during parsing */ | |
3008 | /* index duration calculated during parsing, invariant under massage */ | 2588 | duration = stream->idx_duration; |
3009 | duration = streamc->idx_duration; | ||
3010 | 2589 | ||
3011 | /* now pick a good duration */ | 2590 | /* now pick a good duration */ |
3012 | if (GST_CLOCK_TIME_IS_VALID (duration)) { | 2591 | if (GST_CLOCK_TIME_IS_VALID (duration)) { |
@@ -3018,7 +2597,7 @@ gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi) | |||
3018 | duration = hduration; | 2597 | duration = hduration; |
3019 | } | 2598 | } |
3020 | /* set duration for the stream */ | 2599 | /* set duration for the stream */ |
3021 | streamc->duration = duration; | 2600 | stream->duration = duration; |
3022 | 2601 | ||
3023 | /* find total duration */ | 2602 | /* find total duration */ |
3024 | if (total == GST_CLOCK_TIME_NONE || duration > total) | 2603 | if (total == GST_CLOCK_TIME_NONE || duration > total) |
@@ -3027,12 +2606,12 @@ gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi) | |||
3027 | 2606 | ||
3028 | if (GST_CLOCK_TIME_IS_VALID (total) && (total > 0)) { | 2607 | if (GST_CLOCK_TIME_IS_VALID (total) && (total > 0)) { |
3029 | /* now update the duration for those streams where we had none */ | 2608 | /* now update the duration for those streams where we had none */ |
3030 | for (stream = 0; stream < avi->num_streams; stream++) { | 2609 | for (i = 0; i < avi->num_streams; i++) { |
3031 | GstAviStream *streamc = &avi->stream[stream]; | 2610 | stream = &avi->stream[i]; |
3032 | 2611 | ||
3033 | if (!GST_CLOCK_TIME_IS_VALID (streamc->duration) | 2612 | if (!GST_CLOCK_TIME_IS_VALID (stream->duration) |
3034 | || streamc->duration == 0) { | 2613 | || stream->duration == 0) { |
3035 | streamc->duration = total; | 2614 | stream->duration = total; |
3036 | 2615 | ||
3037 | GST_INFO ("Stream %d duration according to total: %" GST_TIME_FORMAT, | 2616 | GST_INFO ("Stream %d duration according to total: %" GST_TIME_FORMAT, |
3038 | stream, GST_TIME_ARGS (total)); | 2617 | stream, GST_TIME_ARGS (total)); |
@@ -3265,34 +2844,6 @@ skipping_done: | |||
3265 | GST_DEBUG ("Found movi chunk. Starting to stream data"); | 2844 | GST_DEBUG ("Found movi chunk. Starting to stream data"); |
3266 | avi->state = GST_AVI_DEMUX_MOVI; | 2845 | avi->state = GST_AVI_DEMUX_MOVI; |
3267 | 2846 | ||
3268 | #if 0 | ||
3269 | /*GList *index = NULL, *alloc = NULL; */ | ||
3270 | |||
3271 | /* ######################## this need to be integrated with the state */ | ||
3272 | /* create or read stream index (for seeking) */ | ||
3273 | if (avi->stream[0].indexes != NULL) { | ||
3274 | gst_avi_demux_read_subindexes_push (avi, &index, &alloc); | ||
3275 | } | ||
3276 | if (!index) { | ||
3277 | if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX) { | ||
3278 | gst_avi_demux_stream_index (avi, &index, &alloc); | ||
3279 | } | ||
3280 | /* some indexes are incomplete, continue streaming from there */ | ||
3281 | if (!index) | ||
3282 | gst_avi_demux_stream_scan (avi, &index, &alloc); | ||
3283 | } | ||
3284 | |||
3285 | /* this is a fatal error */ | ||
3286 | if (!index) | ||
3287 | goto no_index; | ||
3288 | |||
3289 | if (!gst_avi_demux_massage_index (avi, index, alloc)) | ||
3290 | goto no_index; | ||
3291 | |||
3292 | gst_avi_demux_calculate_durations_from_index (avi); | ||
3293 | /* ######################## */ | ||
3294 | #endif | ||
3295 | |||
3296 | /* create initial NEWSEGMENT event */ | 2847 | /* create initial NEWSEGMENT event */ |
3297 | if ((stop = avi->segment.stop) == GST_CLOCK_TIME_NONE) | 2848 | if ((stop = avi->segment.stop) == GST_CLOCK_TIME_NONE) |
3298 | stop = avi->segment.duration; | 2849 | stop = avi->segment.duration; |
@@ -3360,9 +2911,6 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi) | |||
3360 | GstFlowReturn res; | 2911 | GstFlowReturn res; |
3361 | GstBuffer *buf, *sub = NULL; | 2912 | GstBuffer *buf, *sub = NULL; |
3362 | guint32 tag; | 2913 | guint32 tag; |
3363 | #if 0 | ||
3364 | GList *index = NULL, *alloc = NULL; | ||
3365 | #endif | ||
3366 | guint offset = 4; | 2914 | guint offset = 4; |
3367 | gint64 stop; | 2915 | gint64 stop; |
3368 | GstElement *element = GST_ELEMENT_CAST (avi); | 2916 | GstElement *element = GST_ELEMENT_CAST (avi); |
@@ -3487,6 +3035,7 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi) | |||
3487 | /* Now, find the data (i.e. skip all junk between header and data) */ | 3035 | /* Now, find the data (i.e. skip all junk between header and data) */ |
3488 | do { | 3036 | do { |
3489 | guint size; | 3037 | guint size; |
3038 | guint8 *data; | ||
3490 | guint32 tag, ltag; | 3039 | guint32 tag, ltag; |
3491 | 3040 | ||
3492 | res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf); | 3041 | res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf); |
@@ -3500,13 +3049,15 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi) | |||
3500 | return GST_FLOW_ERROR; | 3049 | return GST_FLOW_ERROR; |
3501 | } | 3050 | } |
3502 | 3051 | ||
3503 | tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); | 3052 | data = GST_BUFFER_DATA (buf); |
3504 | size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4); | 3053 | |
3505 | ltag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 8); | 3054 | tag = GST_READ_UINT32_LE (data); |
3055 | size = GST_READ_UINT32_LE (data + 4); | ||
3056 | ltag = GST_READ_UINT32_LE (data + 8); | ||
3506 | 3057 | ||
3507 | GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u", | 3058 | GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u", |
3508 | GST_FOURCC_ARGS (tag), size); | 3059 | GST_FOURCC_ARGS (tag), size); |
3509 | GST_MEMDUMP ("Tag content", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); | 3060 | GST_MEMDUMP ("Tag content", data, GST_BUFFER_SIZE (buf)); |
3510 | gst_buffer_unref (buf); | 3061 | gst_buffer_unref (buf); |
3511 | 3062 | ||
3512 | switch (tag) { | 3063 | switch (tag) { |
@@ -3571,22 +3122,23 @@ skipping_done: | |||
3571 | /* we read a super index already (gst_avi_demux_parse_superindex() ) */ | 3122 | /* we read a super index already (gst_avi_demux_parse_superindex() ) */ |
3572 | gst_avi_demux_read_subindexes_pull (avi, &index, &alloc); | 3123 | gst_avi_demux_read_subindexes_pull (avi, &index, &alloc); |
3573 | } | 3124 | } |
3574 | if (!index) { | ||
3575 | #endif | 3125 | #endif |
3576 | if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX) { | 3126 | if (!avi->have_index) { |
3127 | if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX) | ||
3577 | gst_avi_demux_stream_index (avi); | 3128 | gst_avi_demux_stream_index (avi); |
3578 | } | ||
3579 | #if 0 | ||
3580 | /* some indexes are incomplete, continue streaming from there */ | ||
3581 | if (!index) | ||
3582 | gst_avi_demux_stream_scan (avi, &index, &alloc); | ||
3583 | } | ||
3584 | 3129 | ||
3585 | /* this is a fatal error */ | 3130 | /* still no index, scan */ |
3586 | if (!index) | 3131 | if (!avi->have_index) { |
3587 | goto no_index; | 3132 | gst_avi_demux_stream_scan (avi); |
3588 | #endif | ||
3589 | 3133 | ||
3134 | /* still no index.. this is a fatal error for now. | ||
3135 | * FIXME, we should switch to plain push mode without seeking | ||
3136 | * instead of failing. */ | ||
3137 | if (!avi->have_index) | ||
3138 | goto no_index; | ||
3139 | } | ||
3140 | } | ||
3141 | /* use the indexes now to construct nice durations */ | ||
3590 | gst_avi_demux_calculate_durations_from_index (avi); | 3142 | gst_avi_demux_calculate_durations_from_index (avi); |
3591 | 3143 | ||
3592 | /* create initial NEWSEGMENT event */ | 3144 | /* create initial NEWSEGMENT event */ |
@@ -3595,9 +3147,9 @@ skipping_done: | |||
3595 | 3147 | ||
3596 | GST_DEBUG_OBJECT (avi, "segment stop %" G_GINT64_FORMAT, stop); | 3148 | GST_DEBUG_OBJECT (avi, "segment stop %" G_GINT64_FORMAT, stop); |
3597 | 3149 | ||
3598 | /* do initial seek to the configured segment values */ | 3150 | /* do initial seek to the default segment values */ |
3599 | gst_avi_demux_do_seek (avi, &avi->segment); | 3151 | gst_avi_demux_do_seek (avi, &avi->segment); |
3600 | 3152 | /* prepare initial segment */ | |
3601 | if (avi->seek_event) | 3153 | if (avi->seek_event) |
3602 | gst_event_unref (avi->seek_event); | 3154 | gst_event_unref (avi->seek_event); |
3603 | avi->seek_event = gst_event_new_new_segment | 3155 | avi->seek_event = gst_event_new_new_segment |
@@ -3654,19 +3206,13 @@ no_streams: | |||
3654 | GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No streams found")); | 3206 | GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No streams found")); |
3655 | return GST_FLOW_ERROR; | 3207 | return GST_FLOW_ERROR; |
3656 | } | 3208 | } |
3657 | #if 0 | ||
3658 | no_index: | 3209 | no_index: |
3659 | { | 3210 | { |
3660 | GST_WARNING ("file without or too big index"); | 3211 | GST_WARNING ("file without or too big index"); |
3661 | g_list_free (index); | ||
3662 | g_list_foreach (alloc, (GFunc) g_free, NULL); | ||
3663 | g_list_free (alloc); | ||
3664 | |||
3665 | GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), | 3212 | GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), |
3666 | ("Could not get/create index")); | 3213 | ("Could not get/create index")); |
3667 | return GST_FLOW_ERROR; | 3214 | return GST_FLOW_ERROR; |
3668 | } | 3215 | } |
3669 | #endif | ||
3670 | pull_range_failed: | 3216 | pull_range_failed: |
3671 | { | 3217 | { |
3672 | GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), | 3218 | GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), |
@@ -3786,6 +3332,7 @@ gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment) | |||
3786 | /* get the entry index for the requested position */ | 3332 | /* get the entry index for the requested position */ |
3787 | index = gst_avi_demux_index_for_time (avi, ostream, seek_time); | 3333 | index = gst_avi_demux_index_for_time (avi, ostream, seek_time); |
3788 | 3334 | ||
3335 | /* move to previous keyframe */ | ||
3789 | if (!ENTRY_IS_KEYFRAME (&ostream->index[index])) | 3336 | if (!ENTRY_IS_KEYFRAME (&ostream->index[index])) |
3790 | index = gst_avi_demux_index_prev (avi, ostream, index, TRUE); | 3337 | index = gst_avi_demux_index_prev (avi, ostream, index, TRUE); |
3791 | 3338 | ||
@@ -4226,13 +3773,12 @@ gst_avi_demux_loop_data (GstAviDemux * avi) | |||
4226 | } | 3773 | } |
4227 | } | 3774 | } |
4228 | 3775 | ||
4229 | /* correct for index offset */ | ||
4230 | offset += avi->index_offset + 8; | ||
4231 | |||
4232 | GST_LOG ("reading buffer (size=%d), stream %d, pos %" | 3776 | GST_LOG ("reading buffer (size=%d), stream %d, pos %" |
4233 | G_GUINT64_FORMAT " (%llx), kf %d", size, stream_num, offset, | 3777 | G_GUINT64_FORMAT " (%llx), kf %d", size, stream_num, offset, |
4234 | offset, keyframe); | 3778 | offset, keyframe); |
4235 | 3779 | ||
3780 | /* FIXME, check large chunks and cut them up */ | ||
3781 | |||
4236 | /* pull in the data */ | 3782 | /* pull in the data */ |
4237 | ret = gst_pad_pull_range (avi->sinkpad, offset, size, &buf); | 3783 | ret = gst_pad_pull_range (avi->sinkpad, offset, size, &buf); |
4238 | if (ret != GST_FLOW_OK) | 3784 | if (ret != GST_FLOW_OK) |
@@ -4457,6 +4003,7 @@ gst_avi_demux_stream_data (GstAviDemux * avi) | |||
4457 | if (G_UNLIKELY (format != GST_FORMAT_TIME)) | 4003 | if (G_UNLIKELY (format != GST_FORMAT_TIME)) |
4458 | goto wrong_format; | 4004 | goto wrong_format; |
4459 | 4005 | ||
4006 | /* increment our positions */ | ||
4460 | stream->current_entry++; | 4007 | stream->current_entry++; |
4461 | stream->current_total += size; | 4008 | stream->current_total += size; |
4462 | 4009 | ||
diff --git a/gst/avi/gstavidemux.h b/gst/avi/gstavidemux.h index ff4235ff9..66537a6d7 100644 --- a/gst/avi/gstavidemux.h +++ b/gst/avi/gstavidemux.h | |||
@@ -57,9 +57,9 @@ typedef struct { | |||
57 | } GstAviIndexEntry; | 57 | } GstAviIndexEntry; |
58 | 58 | ||
59 | #define GST_AVI_KEYFRAME 1 | 59 | #define GST_AVI_KEYFRAME 1 |
60 | #define ENTRY_IS_KEYFRAME(e) (((e)->flags & GST_AVI_KEYFRAME) == GST_AVI_KEYFRAME) | 60 | #define ENTRY_IS_KEYFRAME(e) ((e)->flags == GST_AVI_KEYFRAME) |
61 | #define ENTRY_SET_KEYFRAME(e) ((e)->flags |= GST_AVI_KEYFRAME) | 61 | #define ENTRY_SET_KEYFRAME(e) ((e)->flags = GST_AVI_KEYFRAME) |
62 | #define ENTRY_UNSET_KEYFRAME(e) ((e)->flags &= ~(GST_AVI_KEYFRAME)) | 62 | #define ENTRY_UNSET_KEYFRAME(e) ((e)->flags = 0) |
63 | 63 | ||
64 | typedef struct { | 64 | typedef struct { |
65 | /* index of this streamcontext */ | 65 | /* index of this streamcontext */ |
@@ -149,6 +149,8 @@ typedef struct _GstAviDemux { | |||
149 | guint64 offset; | 149 | guint64 offset; |
150 | gboolean abort_buffering; | 150 | gboolean abort_buffering; |
151 | 151 | ||
152 | /* when we loaded the indexes */ | ||
153 | gboolean have_index; | ||
152 | /* index offset in the file */ | 154 | /* index offset in the file */ |
153 | guint64 index_offset; | 155 | guint64 index_offset; |
154 | 156 | ||