foobar2000 SDK  2015-08-03
seekabilizer.cpp
Go to the documentation of this file.
1 #include "stdafx.h"
2 
3 enum {backread_on_seek = 1024};
4 
6 {
7  m_depth = m_cursor = 0;
8 
9  m_buffer.set_size(p_size);
10 }
11 
12 void seekabilizer_backbuffer::write(const void * p_buffer,t_size p_bytes)
13 {
14  if (p_bytes >= m_buffer.get_size())
15  {
16  memcpy(m_buffer.get_ptr(),(const t_uint8*)p_buffer + p_bytes - m_buffer.get_size(),m_buffer.get_size());
17  m_cursor = 0;
19  }
20  else
21  {
22  const t_uint8* sourceptr = (const t_uint8*) p_buffer;
23  t_size remaining = p_bytes;
24  while(remaining > 0)
25  {
26  t_size delta = m_buffer.get_size() - m_cursor;
27  if (delta > remaining) delta = remaining;
28 
29  memcpy(m_buffer.get_ptr() + m_cursor,sourceptr,delta);
30 
31  sourceptr += delta;
32  remaining -= delta;
33  m_cursor = (m_cursor + delta) % m_buffer.get_size();
34 
35  m_depth = pfc::min_t<t_size>(m_buffer.get_size(),m_depth + delta);
36 
37  }
38  }
39 }
40 
41 void seekabilizer_backbuffer::read(t_size p_backlogdepth,void * p_buffer,t_size p_bytes) const
42 {
43  assert(p_backlogdepth <= m_depth);
44  assert(p_backlogdepth >= p_bytes);
45 
46 
47  t_uint8* targetptr = (t_uint8*) p_buffer;
48  t_size remaining = p_bytes;
49  t_size cursor = (m_cursor + m_buffer.get_size() - p_backlogdepth) % m_buffer.get_size();
50 
51  while(remaining > 0)
52  {
53  t_size delta = m_buffer.get_size() - cursor;
54  if (delta > remaining) delta = remaining;
55 
56  memcpy(targetptr,m_buffer.get_ptr() + cursor,delta);
57 
58  targetptr += delta;
59  remaining -= delta;
60  cursor = (cursor + delta) % m_buffer.get_size();
61  }
62 }
63 
65 {
66  return m_depth;
67 }
68 
70 {
71  return m_buffer.get_size();
72 }
73 
75 {
76  m_depth = m_cursor = 0;
77 }
78 
79 
80 void seekabilizer::initialize(service_ptr_t<file> p_base,t_size p_buffer_size,abort_callback & p_abort) {
81  m_buffer.initialize(p_buffer_size);
82  m_file = p_base;
83  m_position = m_position_base = 0;
84  m_size = m_file->get_size(p_abort);
85 }
86 
87 void seekabilizer::g_seekabilize(service_ptr_t<file> & p_reader,t_size p_buffer_size,abort_callback & p_abort) {
88  if (p_reader.is_valid() && p_reader->is_remote() && p_buffer_size > 0) {
90  instance->initialize(p_reader,p_buffer_size,p_abort);
91  p_reader = instance.get_ptr();
92  }
93 }
94 
95 t_size seekabilizer::read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
96  p_abort.check_e();
97 
98  if (m_position > m_position_base + pfc::max_t<t_size>(m_buffer.get_max_depth(),backread_on_seek) && m_file->can_seek()) {
99  m_buffer.reset();
100  t_filesize target = m_position;
101  if (target < backread_on_seek) target = 0;
102  else target -= backread_on_seek;
103  m_file->seek(target,p_abort);
104  m_position_base = target;
105  }
106 
107  //seek ahead
108  while(m_position > m_position_base) {
109  enum {tempsize = 1024};
110  t_uint8 temp[tempsize];
111  t_size delta = (t_size) pfc::min_t<t_filesize>(tempsize,m_position - m_position_base);
112  t_size bytes_read = 0;
113  bytes_read = m_file->read(temp,delta,p_abort);
114  m_buffer.write(temp,bytes_read);
115  m_position_base += bytes_read;
116 
117  if (bytes_read < delta) {
118  return 0;
119  }
120  }
121 
122  t_size done = 0;
123  t_uint8 * targetptr = (t_uint8*) p_buffer;
124 
125  //try to read backbuffer
126  if (m_position < m_position_base) {
127  if (m_position_base - m_position > (t_filesize)m_buffer.get_depth()) throw exception_io_seek_out_of_range();
128  t_size backread_depth = (t_size) (m_position_base - m_position);
129  t_size delta = pfc::min_t<t_size>(backread_depth,p_bytes-done);
130  m_buffer.read(backread_depth,targetptr,delta);
131  done += delta;
132  m_position += delta;
133  }
134 
135  //regular read
136  if (done < p_bytes)
137  {
138  t_size bytes_read;
139  bytes_read = m_file->read(targetptr+done,p_bytes-done,p_abort);
140 
141  m_buffer.write(targetptr+done,bytes_read);
142 
143  done += bytes_read;
144  m_position += bytes_read;
145  m_position_base += bytes_read;
146  }
147 
148  return done;
149 }
150 
152  p_abort.check_e();
153  return m_size;
154 }
155 
157  p_abort.check_e();
158  return m_position;
159 }
160 
161 void seekabilizer::seek(t_filesize p_position,abort_callback & p_abort) {
162  assert(m_position_base >= m_buffer.get_depth());
163  p_abort.check_e();
164 
165  if (m_size != filesize_invalid && p_position > m_size) throw exception_io_seek_out_of_range();
166 
167  t_filesize lowest = m_position_base - m_buffer.get_depth();
168 
169  if (p_position < lowest) {
170  if (m_file->can_seek()) {
171  m_buffer.reset();
172  t_filesize target = p_position;
173  t_size delta = m_buffer.get_max_depth();
174  if (delta > backread_on_seek) delta = backread_on_seek;
175  if (target > delta) target -= delta;
176  else target = 0;
177  m_file->seek(target,p_abort);
178  m_position_base = target;
179  }
180  else {
181  m_buffer.reset();
182  m_file->reopen(p_abort);
183  m_position_base = 0;
184  }
185  }
186 
187  m_position = p_position;
188 }
189 
191 {
192  return true;
193 }
194 
195 bool seekabilizer::get_content_type(pfc::string_base & p_out) {return m_file->get_content_type(p_out);}
196 
197 bool seekabilizer::is_in_memory() {return false;}
198 
199 void seekabilizer::on_idle(abort_callback & p_abort) {return m_file->on_idle(p_abort);}
200 
202  p_abort.check_e();
203  return m_file->get_timestamp(p_abort);
204 }
205 
207  if (m_position_base - m_buffer.get_depth() == 0) {
208  seek(0,p_abort);
209  } else {
210  m_position = m_position_base = 0;
211  m_buffer.reset();
212  m_file->reopen(p_abort);
213  }
214 }
215 
217 {
218  return m_file->is_remote();
219 }
const t_item * get_ptr() const
Definition: array.h:213
uint8_t t_uint8
Definition: int_types.h:9
Template implementing reference-counting features of service_base. Intended for dynamic instantiation...
Definition: service_impl.h:4
t_size get_max_depth() const
void seek(HANDLE p_handle, t_sfilesize p_position, file::t_seek_mode p_mode)
t_filesize get_position(abort_callback &p_abort)
T * get_ptr() const
Definition: service.h:117
bool get_content_type(pfc::string_base &p_out)
pfc::array_t< t_uint8 > m_buffer
Definition: seekabilizer.h:11
static const t_filesize filesize_invalid
Invalid/unknown file size constant. Also see: t_filesize.
Definition: filesystem.h:16
t_filesize get_size(abort_callback &p_abort)
void write(const void *p_buffer, t_size p_bytes)
bool is_in_memory()
bool is_valid() const
Definition: service.h:119
static void g_seekabilize(service_ptr_t< file > &p_reader, t_size p_buffer_size, abort_callback &p_abort)
void on_idle(abort_callback &p_abort)
size_t t_size
Definition: int_types.h:48
t_filetimestamp get_timestamp(abort_callback &p_abort)
void set_size(t_size p_size)
Definition: array.h:104
void reopen(abort_callback &p_abort)
t_uint64 t_filetimestamp
Type used for file timestamp related variables. 64-bit value representing the number of 100-nanosecon...
Definition: filesystem.h:12
t_uint64 t_filesize
Type used for file size related variables.
Definition: filesystem.h:8
void read(t_size p_backlogdepth, void *p_buffer, t_size p_bytes) const
void seek(t_filesize p_position, abort_callback &p_abort)
void initialize(t_size p_size)
Definition: seekabilizer.cpp:5
t_size get_depth() const
t_size get_size() const
Definition: array.h:130
t_size read(void *p_buffer, t_size p_bytes, abort_callback &p_abort)
void initialize(service_ptr_t< file > p_base, t_size p_buffer_size, abort_callback &p_abort)