Mercurial > foo_out_sdl
comparison foosdk/sdk/foobar2000/helpers/seekabilizer.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 1 #include "StdAfx.h" | |
| 2 | |
| 3 #include "seekabilizer.h" | |
| 4 | |
| 5 enum {backread_on_seek = 1024}; | |
| 6 | |
| 7 void seekabilizer_backbuffer::initialize(t_size p_size) | |
| 8 { | |
| 9 m_depth = m_cursor = 0; | |
| 10 | |
| 11 m_buffer.set_size(p_size); | |
| 12 } | |
| 13 | |
| 14 void seekabilizer_backbuffer::write(const void * p_buffer,t_size p_bytes) | |
| 15 { | |
| 16 if (p_bytes >= m_buffer.get_size()) | |
| 17 { | |
| 18 memcpy(m_buffer.get_ptr(),(const t_uint8*)p_buffer + p_bytes - m_buffer.get_size(),m_buffer.get_size()); | |
| 19 m_cursor = 0; | |
| 20 m_depth = m_buffer.get_size(); | |
| 21 } | |
| 22 else | |
| 23 { | |
| 24 const t_uint8* sourceptr = (const t_uint8*) p_buffer; | |
| 25 t_size remaining = p_bytes; | |
| 26 while(remaining > 0) | |
| 27 { | |
| 28 t_size delta = m_buffer.get_size() - m_cursor; | |
| 29 if (delta > remaining) delta = remaining; | |
| 30 | |
| 31 memcpy(m_buffer.get_ptr() + m_cursor,sourceptr,delta); | |
| 32 | |
| 33 sourceptr += delta; | |
| 34 remaining -= delta; | |
| 35 m_cursor = (m_cursor + delta) % m_buffer.get_size(); | |
| 36 | |
| 37 m_depth = pfc::min_t<t_size>(m_buffer.get_size(),m_depth + delta); | |
| 38 | |
| 39 } | |
| 40 } | |
| 41 } | |
| 42 | |
| 43 void seekabilizer_backbuffer::read(t_size p_backlogdepth,void * p_buffer,t_size p_bytes) const | |
| 44 { | |
| 45 PFC_ASSERT(p_backlogdepth <= m_depth); | |
| 46 PFC_ASSERT(p_backlogdepth >= p_bytes); | |
| 47 | |
| 48 | |
| 49 t_uint8* targetptr = (t_uint8*) p_buffer; | |
| 50 t_size remaining = p_bytes; | |
| 51 t_size cursor = (m_cursor + m_buffer.get_size() - p_backlogdepth) % m_buffer.get_size(); | |
| 52 | |
| 53 while(remaining > 0) | |
| 54 { | |
| 55 t_size delta = m_buffer.get_size() - cursor; | |
| 56 if (delta > remaining) delta = remaining; | |
| 57 | |
| 58 memcpy(targetptr,m_buffer.get_ptr() + cursor,delta); | |
| 59 | |
| 60 targetptr += delta; | |
| 61 remaining -= delta; | |
| 62 cursor = (cursor + delta) % m_buffer.get_size(); | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 t_size seekabilizer_backbuffer::get_depth() const | |
| 67 { | |
| 68 return m_depth; | |
| 69 } | |
| 70 | |
| 71 t_size seekabilizer_backbuffer::get_max_depth() const | |
| 72 { | |
| 73 return m_buffer.get_size(); | |
| 74 } | |
| 75 | |
| 76 void seekabilizer_backbuffer::reset() | |
| 77 { | |
| 78 m_depth = m_cursor = 0; | |
| 79 } | |
| 80 | |
| 81 | |
| 82 void seekabilizer::initialize(service_ptr_t<file> p_base,t_size p_buffer_size,abort_callback & p_abort) { | |
| 83 m_buffer.initialize(p_buffer_size); | |
| 84 m_file = p_base; | |
| 85 m_position = m_position_base = 0; | |
| 86 m_size = m_file->get_size(p_abort); | |
| 87 } | |
| 88 | |
| 89 void seekabilizer::g_seekabilize(service_ptr_t<file> & p_reader,t_size p_buffer_size,abort_callback & p_abort) { | |
| 90 if (p_reader.is_valid() && (p_reader->is_remote() || !p_reader->can_seek()) && p_buffer_size > 0) { | |
| 91 auto instance = fb2k::service_new<seekabilizer>(); | |
| 92 instance->initialize(p_reader,p_buffer_size,p_abort); | |
| 93 p_reader = instance.get_ptr(); | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 t_size seekabilizer::read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) { | |
| 98 p_abort.check_e(); | |
| 99 | |
| 100 if (m_position > m_position_base + pfc::max_t<t_size>(m_buffer.get_max_depth(),backread_on_seek) && m_file->can_seek()) { | |
| 101 m_buffer.reset(); | |
| 102 t_filesize target = m_position; | |
| 103 if (target < backread_on_seek) target = 0; | |
| 104 else target -= backread_on_seek; | |
| 105 m_file->seek(target,p_abort); | |
| 106 m_position_base = target; | |
| 107 } | |
| 108 | |
| 109 //seek ahead | |
| 110 while(m_position > m_position_base) { | |
| 111 enum {tempsize = 1024}; | |
| 112 t_uint8 temp[tempsize]; | |
| 113 t_size delta = (t_size) pfc::min_t<t_filesize>(tempsize,m_position - m_position_base); | |
| 114 t_size bytes_read = 0; | |
| 115 bytes_read = m_file->read(temp,delta,p_abort); | |
| 116 m_buffer.write(temp,bytes_read); | |
| 117 m_position_base += bytes_read; | |
| 118 | |
| 119 if (bytes_read < delta) { | |
| 120 return 0; | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 t_size done = 0; | |
| 125 t_uint8 * targetptr = (t_uint8*) p_buffer; | |
| 126 | |
| 127 //try to read backbuffer | |
| 128 if (m_position < m_position_base) { | |
| 129 if (m_position_base - m_position > (t_filesize)m_buffer.get_depth()) throw exception_io_seek_out_of_range(); | |
| 130 t_size backread_depth = (t_size) (m_position_base - m_position); | |
| 131 t_size delta = pfc::min_t<t_size>(backread_depth,p_bytes-done); | |
| 132 m_buffer.read(backread_depth,targetptr,delta); | |
| 133 done += delta; | |
| 134 m_position += delta; | |
| 135 } | |
| 136 | |
| 137 //regular read | |
| 138 if (done < p_bytes) | |
| 139 { | |
| 140 t_size bytes_read; | |
| 141 bytes_read = m_file->read(targetptr+done,p_bytes-done,p_abort); | |
| 142 | |
| 143 m_buffer.write(targetptr+done,bytes_read); | |
| 144 | |
| 145 done += bytes_read; | |
| 146 m_position += bytes_read; | |
| 147 m_position_base += bytes_read; | |
| 148 } | |
| 149 | |
| 150 return done; | |
| 151 } | |
| 152 | |
| 153 t_filesize seekabilizer::get_size(abort_callback & p_abort) { | |
| 154 p_abort.check_e(); | |
| 155 return m_size; | |
| 156 } | |
| 157 | |
| 158 t_filesize seekabilizer::get_position(abort_callback & p_abort) { | |
| 159 p_abort.check_e(); | |
| 160 return m_position; | |
| 161 } | |
| 162 | |
| 163 void seekabilizer::seek(t_filesize p_position,abort_callback & p_abort) { | |
| 164 PFC_ASSERT(m_position_base >= m_buffer.get_depth()); | |
| 165 p_abort.check_e(); | |
| 166 | |
| 167 if (m_size != filesize_invalid && p_position > m_size) throw exception_io_seek_out_of_range(); | |
| 168 | |
| 169 t_filesize lowest = m_position_base - m_buffer.get_depth(); | |
| 170 | |
| 171 if (p_position < lowest) { | |
| 172 if (m_file->can_seek()) { | |
| 173 m_buffer.reset(); | |
| 174 t_filesize target = p_position; | |
| 175 t_size delta = m_buffer.get_max_depth(); | |
| 176 if (delta > backread_on_seek) delta = backread_on_seek; | |
| 177 if (target > delta) target -= delta; | |
| 178 else target = 0; | |
| 179 m_file->seek(target,p_abort); | |
| 180 m_position_base = target; | |
| 181 } | |
| 182 else { | |
| 183 m_buffer.reset(); | |
| 184 m_file->reopen(p_abort); | |
| 185 m_position_base = 0; | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 m_position = p_position; | |
| 190 } | |
| 191 | |
| 192 bool seekabilizer::can_seek() | |
| 193 { | |
| 194 return true; | |
| 195 } | |
| 196 | |
| 197 bool seekabilizer::get_content_type(pfc::string_base & p_out) {return m_file->get_content_type(p_out);} | |
| 198 | |
| 199 bool seekabilizer::is_in_memory() {return false;} | |
| 200 | |
| 201 void seekabilizer::on_idle(abort_callback & p_abort) {return m_file->on_idle(p_abort);} | |
| 202 | |
| 203 t_filetimestamp seekabilizer::get_timestamp(abort_callback & p_abort) { | |
| 204 p_abort.check_e(); | |
| 205 return m_file->get_timestamp(p_abort); | |
| 206 } | |
| 207 | |
| 208 void seekabilizer::reopen(abort_callback & p_abort) { | |
| 209 if (m_position_base - m_buffer.get_depth() == 0) { | |
| 210 seek(0,p_abort); | |
| 211 } else { | |
| 212 m_position = m_position_base = 0; | |
| 213 m_buffer.reset(); | |
| 214 m_file->reopen(p_abort); | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 bool seekabilizer::is_remote() | |
| 219 { | |
| 220 return m_file->is_remote(); | |
| 221 } | |
| 222 | |
| 223 service_ptr seekabilizer::get_metadata(abort_callback& a) { | |
| 224 return m_file->get_metadata_(a); | |
| 225 } | |
| 226 | |
| 227 t_filestats2 seekabilizer::get_stats2(uint32_t s2flags, abort_callback& a) { | |
| 228 return m_file->get_stats2_(s2flags, a); | |
| 229 } | |
| 230 | |
| 231 size_t seekabilizer::lowLevelIO(const GUID& guid, size_t arg1, void* arg2, size_t arg2size, abort_callback& abort) { | |
| 232 return m_file->lowLevelIO_(guid, arg1, arg2, arg2size, abort); | |
| 233 } |
