summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@collabora.co.uk>2009-09-23 13:57:02 +0200
committerWim Taymans <wim@metal.(none)>2009-09-28 22:17:02 +0200
commit217315c20b136e90829b3f464f49d497546b09df (patch)
tree47ac8ae211c0b03bee779513ce6338f7f35fa7ab
parent7b9b8343ba03ef4ad19268b443c80d7538f6083c (diff)
avi: fix timestamping in some audio streams
For vbr audio streams we need to use the number of blocks to calculate the timestamps. When the allocation of additional index memory fails, don't throw away what we had before. Various cleanups.
-rw-r--r--gst/avi/gstavidemux.c191
1 files changed, 95 insertions, 96 deletions
diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c
index 0765bd856..9ec8d71df 100644
--- a/gst/avi/gstavidemux.c
+++ b/gst/avi/gstavidemux.c
@@ -53,7 +53,7 @@
53#include <gst/base/gstadapter.h> 53#include <gst/base/gstadapter.h>
54 54
55 55
56#define DIV_ROUND_UP(s,v) ((s) + ((v)-1) / (v)) 56#define DIV_ROUND_UP(s,v) (((s) + ((v)-1)) / (v))
57 57
58GST_DEBUG_CATEGORY_STATIC (avidemux_debug); 58GST_DEBUG_CATEGORY_STATIC (avidemux_debug);
59#define GST_CAT_DEFAULT avidemux_debug 59#define GST_CAT_DEFAULT avidemux_debug
@@ -1004,33 +1004,51 @@ gst_avi_demux_add_index (GstAviDemux * avi, GstAviStream * stream,
1004{ 1004{
1005 /* ensure index memory */ 1005 /* ensure index memory */
1006 if (G_UNLIKELY (stream->idx_n >= stream->idx_max)) { 1006 if (G_UNLIKELY (stream->idx_n >= stream->idx_max)) {
1007 guint idx_max = stream->idx_max;
1008 GstAviIndexEntry *new_idx;
1009
1007 /* we need to make some more room */ 1010 /* we need to make some more room */
1008 if (stream->idx_max == 0) { 1011 if (idx_max == 0) {
1009 /* initial size guess, assume each stream has an equal amount of entries, 1012 /* initial size guess, assume each stream has an equal amount of entries,
1010 * overshoot with at least 8K */ 1013 * overshoot with at least 8K */
1011 stream->idx_max = 1014 idx_max = (num / avi->num_streams) + (8192 / sizeof (GstAviIndexEntry));
1012 (num / avi->num_streams) + (8192 / sizeof (GstAviIndexEntry));
1013 } else { 1015 } else {
1014 stream->idx_max += 8192 / sizeof (GstAviIndexEntry); 1016 idx_max += 8192 / sizeof (GstAviIndexEntry);
1015 GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "expanded index to %u", 1017 GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "expanded index from %u to %u",
1016 stream->idx_max); 1018 stream->idx_max, idx_max);
1017 } 1019 }
1018 stream->index = g_try_renew (GstAviIndexEntry, stream->index, 1020 new_idx = g_try_renew (GstAviIndexEntry, stream->index, idx_max);
1019 stream->idx_max); 1021 /* out of memory, if this fails stream->index is untouched. */
1020 if (G_UNLIKELY (!stream->index)) 1022 if (G_UNLIKELY (!new_idx))
1021 return FALSE; 1023 return FALSE;
1024 /* use new index */
1025 stream->index = new_idx;
1026 stream->idx_max = idx_max;
1022 } 1027 }
1023 1028
1024 /* update stream stats and total size */ 1029 /* update entry total and stream stats. The entry total can be converted to
1025 entry->total = stream->total_bytes; 1030 * the timestamp of the entry easily. */
1026 stream->total_bytes += entry->size;
1027 if (stream->strh->type == GST_RIFF_FCC_auds) { 1031 if (stream->strh->type == GST_RIFF_FCC_auds) {
1028 gint blockalign = stream->strf.auds->blockalign; 1032 gint blockalign;
1033
1034 if (stream->is_vbr) {
1035 entry->total = stream->total_blocks;
1036 } else {
1037 entry->total = stream->total_bytes;
1038 }
1039 blockalign = stream->strf.auds->blockalign;
1029 if (blockalign > 0) 1040 if (blockalign > 0)
1030 stream->total_blocks += DIV_ROUND_UP (entry->size, blockalign); 1041 stream->total_blocks += DIV_ROUND_UP (entry->size, blockalign);
1031 else 1042 else
1032 stream->total_blocks++; 1043 stream->total_blocks++;
1044 } else {
1045 if (stream->is_vbr) {
1046 entry->total = stream->idx_n;
1047 } else {
1048 entry->total = stream->total_bytes;
1049 }
1033 } 1050 }
1051 stream->total_bytes += entry->size;
1034 if (ENTRY_IS_KEYFRAME (entry)) 1052 if (ENTRY_IS_KEYFRAME (entry))
1035 stream->n_keyframes++; 1053 stream->n_keyframes++;
1036 1054
@@ -1045,6 +1063,58 @@ gst_avi_demux_add_index (GstAviDemux * avi, GstAviStream * stream,
1045 return TRUE; 1063 return TRUE;
1046} 1064}
1047 1065
1066/* given @entry_n in @stream, calculate info such as timestamps and
1067 * offsets for the entry. */
1068static void
1069gst_avi_demux_get_buffer_info (GstAviDemux * avi, GstAviStream * stream,
1070 guint entry_n, GstClockTime * timestamp, GstClockTime * ts_end,
1071 guint64 * offset, guint64 * offset_end)
1072{
1073 GstAviIndexEntry *entry;
1074
1075 entry = &stream->index[entry_n];
1076
1077 if (stream->is_vbr) {
1078 /* VBR stream next timestamp */
1079 if (stream->strh->type == GST_RIFF_FCC_auds) {
1080 if (timestamp)
1081 *timestamp =
1082 avi_stream_convert_frames_to_time_unchecked (stream, entry->total);
1083 if (ts_end)
1084 *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
1085 entry->total + 1);
1086 } else {
1087 if (timestamp)
1088 *timestamp =
1089 avi_stream_convert_frames_to_time_unchecked (stream, entry_n);
1090 if (ts_end)
1091 *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
1092 entry_n + 1);
1093 }
1094 } else {
1095 /* constant rate stream */
1096 if (timestamp)
1097 *timestamp =
1098 avi_stream_convert_bytes_to_time_unchecked (stream, entry->total);
1099 if (ts_end)
1100 *ts_end = avi_stream_convert_bytes_to_time_unchecked (stream,
1101 entry->total + entry->size);
1102 }
1103 if (stream->strh->type == GST_RIFF_FCC_vids) {
1104 /* video offsets are the frame number */
1105 if (offset)
1106 *offset = entry_n;
1107 if (offset_end)
1108 *offset_end = entry_n + 1;
1109 } else {
1110 /* no offsets for audio */
1111 if (offset)
1112 *offset = -1;
1113 if (offset_end)
1114 *offset_end = -1;
1115 }
1116}
1117
1048/* collect and debug stats about the indexes for all streams. 1118/* collect and debug stats about the indexes for all streams.
1049 * This method is also responsible for filling in the stream duration 1119 * This method is also responsible for filling in the stream duration
1050 * as measured by the amount of index entries. */ 1120 * as measured by the amount of index entries. */
@@ -1058,9 +1128,7 @@ gst_avi_demux_do_index_stats (GstAviDemux * avi)
1058 1128
1059 /* get stream stats now */ 1129 /* get stream stats now */
1060 for (i = 0; i < avi->num_streams; i++) { 1130 for (i = 0; i < avi->num_streams; i++) {
1061 GstAviIndexEntry *entry;
1062 GstAviStream *stream; 1131 GstAviStream *stream;
1063 guint64 total;
1064 1132
1065 if (G_UNLIKELY (!(stream = &avi->stream[i]))) 1133 if (G_UNLIKELY (!(stream = &avi->stream[i])))
1066 continue; 1134 continue;
@@ -1069,24 +1137,11 @@ gst_avi_demux_do_index_stats (GstAviDemux * avi)
1069 if (G_UNLIKELY (!stream->index || stream->idx_n == 0)) 1137 if (G_UNLIKELY (!stream->index || stream->idx_n == 0))
1070 continue; 1138 continue;
1071 1139
1072 entry = &stream->index[stream->idx_n - 1]; 1140 /* we interested in the end_ts of the last entry, which is the total
1073 total = entry->total + entry->size; 1141 * duration of this stream */
1142 gst_avi_demux_get_buffer_info (avi, stream, stream->idx_n - 1,
1143 NULL, &stream->idx_duration, NULL, NULL);
1074 1144
1075 /* calculate duration */
1076 if (stream->is_vbr) {
1077 /* VBR stream next timestamp */
1078 if (stream->strh->type == GST_RIFF_FCC_auds) {
1079 stream->idx_duration =
1080 avi_stream_convert_frames_to_time_unchecked (stream, total);
1081 } else {
1082 stream->idx_duration =
1083 avi_stream_convert_frames_to_time_unchecked (stream, stream->idx_n);
1084 }
1085 } else {
1086 /* constant rate stream */
1087 stream->idx_duration = avi_stream_convert_bytes_to_time_unchecked (stream,
1088 total);
1089 }
1090#ifndef GST_DISABLE_GST_DEBUG 1145#ifndef GST_DISABLE_GST_DEBUG
1091 total_idx += stream->idx_n; 1146 total_idx += stream->idx_n;
1092 total_max += stream->idx_max; 1147 total_max += stream->idx_max;
@@ -2032,58 +2087,6 @@ gst_avi_demux_index_for_time (GstAviDemux * avi,
2032 return index; 2087 return index;
2033} 2088}
2034 2089
2035/* given @entry_n in @stream, calculate info such as timestamps and
2036 * offsets for the entry. */
2037static void
2038gst_avi_demux_get_buffer_info (GstAviDemux * avi, GstAviStream * stream,
2039 guint entry_n, GstClockTime * timestamp, GstClockTime * ts_end,
2040 guint64 * offset, guint64 * offset_end)
2041{
2042 GstAviIndexEntry *entry;
2043
2044 entry = &stream->index[entry_n];
2045
2046 if (stream->is_vbr) {
2047 /* VBR stream next timestamp */
2048 if (stream->strh->type == GST_RIFF_FCC_auds) {
2049 if (timestamp)
2050 *timestamp =
2051 avi_stream_convert_frames_to_time_unchecked (stream, entry->total);
2052 if (ts_end)
2053 *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
2054 entry->total + entry->size);
2055 } else {
2056 if (timestamp)
2057 *timestamp =
2058 avi_stream_convert_frames_to_time_unchecked (stream, entry_n);
2059 if (ts_end)
2060 *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
2061 entry_n + 1);
2062 }
2063 } else {
2064 /* constant rate stream */
2065 if (timestamp)
2066 *timestamp =
2067 avi_stream_convert_bytes_to_time_unchecked (stream, entry->total);
2068 if (ts_end)
2069 *ts_end = avi_stream_convert_bytes_to_time_unchecked (stream,
2070 entry->total + entry->size);
2071 }
2072 if (stream->strh->type == GST_RIFF_FCC_vids) {
2073 /* video offsets are the frame number */
2074 if (offset)
2075 *offset = entry_n;
2076 if (offset_end)
2077 *offset_end = entry_n + 1;
2078 } else {
2079 /* no offsets for audio */
2080 if (offset)
2081 *offset = -1;
2082 if (offset_end)
2083 *offset_end = -1;
2084 }
2085}
2086
2087static inline GstAviStream * 2090static inline GstAviStream *
2088gst_avi_demux_stream_for_id (GstAviDemux * avi, guint32 id) 2091gst_avi_demux_stream_for_id (GstAviDemux * avi, guint32 id)
2089{ 2092{
@@ -3525,7 +3528,8 @@ gst_avi_demux_combine_flows (GstAviDemux * avi, GstAviStream * stream,
3525 /* if we get here, all other pads were unlinked and we return 3528 /* if we get here, all other pads were unlinked and we return
3526 * NOT_LINKED then */ 3529 * NOT_LINKED then */
3527done: 3530done:
3528 GST_LOG_OBJECT (avi, "combined return %s", gst_flow_get_name (ret)); 3531 GST_LOG_OBJECT (avi, "combined %s to return %s",
3532 gst_flow_get_name (stream->last_flow), gst_flow_get_name (ret));
3529 return ret; 3533 return ret;
3530} 3534}
3531 3535
@@ -3737,23 +3741,20 @@ gst_avi_demux_loop_data (GstAviDemux * avi)
3737 3741
3738 gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad)); 3742 gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
3739 3743
3744 /* update current position in the segment */
3745 gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, timestamp);
3746
3740 GST_DEBUG_OBJECT (avi, "Pushing buffer of size %u, ts %" 3747 GST_DEBUG_OBJECT (avi, "Pushing buffer of size %u, ts %"
3741 GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT 3748 GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
3742 ", off_end %" G_GUINT64_FORMAT " on pad %s", 3749 ", off_end %" G_GUINT64_FORMAT,
3743 GST_BUFFER_SIZE (buf), GST_TIME_ARGS (timestamp), 3750 GST_BUFFER_SIZE (buf), GST_TIME_ARGS (timestamp),
3744 GST_TIME_ARGS (duration), GST_BUFFER_OFFSET (buf), 3751 GST_TIME_ARGS (duration), out_offset, out_offset_end);
3745 GST_BUFFER_OFFSET_END (buf), GST_PAD_NAME (stream->pad));
3746
3747 /* update current position in the segment */
3748 gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, timestamp);
3749 3752
3750 ret = gst_pad_push (stream->pad, buf); 3753 ret = gst_pad_push (stream->pad, buf);
3751 3754
3752 /* mark as processed, we increment the frame and byte counters then 3755 /* mark as processed, we increment the frame and byte counters then
3753 * leave the while loop and return the GstFlowReturn */ 3756 * leave the while loop and return the GstFlowReturn */
3754 processed = TRUE; 3757 processed = TRUE;
3755 GST_DEBUG_OBJECT (avi, "Processed buffer %u: %s", stream->current_entry,
3756 gst_flow_get_name (ret));
3757 3758
3758 if (avi->segment.rate < 0) { 3759 if (avi->segment.rate < 0) {
3759 if (timestamp > avi->segment.stop && ret == GST_FLOW_UNEXPECTED) { 3760 if (timestamp > avi->segment.stop && ret == GST_FLOW_UNEXPECTED) {
@@ -4072,8 +4073,6 @@ gst_avi_demux_loop (GstPad * pad)
4072 goto pause; 4073 goto pause;
4073 } 4074 }
4074 4075
4075 GST_LOG_OBJECT (avi, "state: %d res:%s", avi->state, gst_flow_get_name (res));
4076
4077 return; 4076 return;
4078 4077
4079 /* ERRORS */ 4078 /* ERRORS */