Skip to content

Commit 2dc185d

Browse files
committed
refactor Streaming strategy to allow MP4 preview and rename legacy Streaming strategy to Sequential
1 parent 6fa6a84 commit 2dc185d

6 files changed

Lines changed: 164 additions & 7 deletions

File tree

src/ft/ftchunkmap.cc

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "retroshare/rspeers.h"
3333
#include "ftchunkmap.h"
3434
#include "util/rstime.h"
35+
#include "util/rsdebug.h"
3536

3637
static const uint32_t SOURCE_CHUNK_MAP_UPDATE_PERIOD = 60 ; //! TTL for chunkmap info
3738
static const uint32_t INACTIVE_CHUNK_TIME_LAPSE = 3600 ; //! TTL for an inactive chunk
@@ -599,14 +600,41 @@ uint32_t ChunkMap::getAvailableChunk(const RsPeerId& peer_id,bool& map_is_too_ol
599600
{
600601
uint32_t chosen_chunk_number ;
601602

603+
// Check high priority chunks first (regardless of strategy)
604+
if (!_high_priority_chunks.empty())
605+
{
606+
uint32_t j = 0;
607+
for(uint32_t i=0; i<_map.size(); ++i)
608+
{
609+
if(_map[i] == FileChunksInfo::CHUNK_OUTSTANDING && (peer_chunks->is_full || peer_chunks->cmap[i]))
610+
{
611+
if (i < _high_priority_chunks.size() && _high_priority_chunks[i])
612+
{
613+
RsDbg() << "STREAMING: ChunkMap::getAvailableChunk: PRIORITY returning chunk " << i << " for peer " << peer_id;
614+
return i;
615+
}
616+
else
617+
j++;
618+
}
619+
}
620+
}
621+
602622
switch(_strategy)
603623
{
604-
case FileChunksInfo::CHUNK_STRATEGY_STREAMING: chosen_chunk_number = 0 ;
624+
case FileChunksInfo::CHUNK_STRATEGY_SEQUENTIAL: chosen_chunk_number = 0 ;
605625
break ;
606626
case FileChunksInfo::CHUNK_STRATEGY_RANDOM: chosen_chunk_number = rand() % available_chunks ;
607627
break ;
608628
case FileChunksInfo::CHUNK_STRATEGY_PROGRESSIVE: chosen_chunk_number = rand() % std::min(available_chunks, available_chunks_before_max_dist+FT_CHUNKMAP_MAX_CHUNK_JUMP) ;
609629
break ;
630+
case FileChunksInfo::CHUNK_STRATEGY_STREAMING:
631+
{
632+
// Legacy heuristic removed.
633+
// Now relies on _high_priority_chunks (checked above)
634+
// or falls back to standard streaming (0).
635+
chosen_chunk_number = 0 ;
636+
}
637+
break ;
610638
default:
611639
chosen_chunk_number = 0 ;
612640
}
@@ -705,4 +733,15 @@ void ChunkMap::buildPlainMap(uint64_t size, CompressedChunkMap& map)
705733
map = CompressedChunkMap(n,~uint32_t(0)) ;
706734
}
707735

736+
void ChunkMap::setHighPriorityRange(uint32_t startChunk, uint32_t endChunk)
737+
{
738+
RsDbg() << "STREAMING: ChunkMap::setHighPriorityRange " << startChunk << " -> " << endChunk;
739+
740+
if (_high_priority_chunks.size() != _map.size())
741+
_high_priority_chunks.resize(_map.size(), false);
742+
743+
for (uint32_t i = startChunk; i <= endChunk && i < _high_priority_chunks.size(); ++i)
744+
_high_priority_chunks[i] = true;
745+
}
746+
708747

src/ft/ftchunkmap.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ class ChunkMap
178178
virtual void getAvailabilityMap(CompressedChunkMap& cmap) const ;
179179
void setAvailabilityMap(const CompressedChunkMap& cmap) ;
180180

181+
/// Sets a range of chunks to be downloaded with high priority (checked before strategy)
182+
void setHighPriorityRange(uint32_t startChunk, uint32_t endChunk);
183+
181184
/// Removes the source availability map. The map
182185
void removeFileSource(const RsPeerId& peer_id) ;
183186

@@ -250,6 +253,7 @@ class ChunkMap
250253
std::map<RsPeerId,Chunk> _active_chunks_feed ; //! vector of chunks being downloaded. Exactly 1 chunk per peer.
251254
std::map<ChunkNumber,ChunkDownloadInfo> _slices_to_download ; //! list of (slice offset,slice size) currently being downloaded
252255
std::vector<FileChunksInfo::ChunkState> _map ; //! vector of chunk state over the whole file
256+
std::vector<bool> _high_priority_chunks; //! boolean mask for high priority chunks
253257
std::map<RsPeerId,SourceChunksInfo> _peers_chunks_availability ; //! what does each source peer have
254258
uint64_t _total_downloaded ; //! completion for the file
255259
bool _file_is_complete ; //! set to true when the file is complete.

src/ft/ftcontroller.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1877,10 +1877,12 @@ bool ftController::saveList(bool &cleanup, std::list<RsItem *>& saveData)
18771877

18781878
switch(mDefaultChunkStrategy)
18791879
{
1880-
case FileChunksInfo::CHUNK_STRATEGY_STREAMING: configMap[default_chunk_strategy_ss] = "STREAMING" ;
1880+
case FileChunksInfo::CHUNK_STRATEGY_SEQUENTIAL: configMap[default_chunk_strategy_ss] = "SEQUENTIAL" ;
18811881
break ;
18821882
case FileChunksInfo::CHUNK_STRATEGY_RANDOM: configMap[default_chunk_strategy_ss] = "RANDOM" ;
18831883
break ;
1884+
case FileChunksInfo::CHUNK_STRATEGY_STREAMING: configMap[default_chunk_strategy_ss] = "STREAMING" ;
1885+
break ;
18841886

18851887
default:
18861888
case FileChunksInfo::CHUNK_STRATEGY_PROGRESSIVE:configMap[default_chunk_strategy_ss] = "PROGRESSIVE" ;
@@ -2165,6 +2167,11 @@ bool ftController::loadConfigMap(std::map<std::string, std::string> &configMap)
21652167
setDefaultChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_STREAMING) ;
21662168
std::cerr << "Note: loading default value for chunk strategy: streaming" << std::endl;
21672169
}
2170+
else if(mit->second == "SEQUENTIAL")
2171+
{
2172+
setDefaultChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_SEQUENTIAL) ;
2173+
std::cerr << "Note: loading default value for chunk strategy: sequential" << std::endl;
2174+
}
21682175
else if(mit->second == "RANDOM")
21692176
{
21702177
setDefaultChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_RANDOM) ;

src/ft/ftfilecreator.cc

Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <cerrno>
2424
#include <cstdio>
2525
#include <sys/stat.h>
26+
#include "util/rsdebug.h"
2627

2728
#include "ftfilecreator.h"
2829
#include "util/rstime.h"
@@ -49,8 +50,9 @@
4950
***********************************************************/
5051

5152
ftFileCreator::ftFileCreator(const std::string& path, uint64_t size, const RsFileHash& hash,bool assume_availability)
52-
: ftFileProvider(path,size,hash), chunkMap(size,assume_availability)
53+
: ftFileProvider(path,size,hash), chunkMap(size,assume_availability), _mp4_index_found(false), _mp4_index_offset(0)
5354
{
55+
RsDbg() << "STREAMING: ftFileCreator CONSTRUCTOR for " << path;
5456
/*
5557
* FIXME any inits to do?
5658
*/
@@ -239,6 +241,13 @@ bool ftFileCreator::addFileData(uint64_t offset, uint32_t chunk_size, void *data
239241
* Notify ftFileChunker about chunks received
240242
*/
241243
locked_notifyReceived(offset,chunk_size);
244+
245+
// MP4 Smart Preview hook
246+
RsDbg() << "STREAMING: addFileData offset=" << offset << " strat=" << chunkMap.getStrategy();
247+
if (!_mp4_index_found)
248+
{
249+
checkForMp4Index();
250+
}
242251

243252
complete = chunkMap.isComplete();
244253
}
@@ -497,15 +506,16 @@ void ftFileCreator::setChunkStrategy(FileChunksInfo::ChunkStrategy s)
497506
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
498507

499508
// Let's check, for safety.
500-
if(s != FileChunksInfo::CHUNK_STRATEGY_STREAMING && s != FileChunksInfo::CHUNK_STRATEGY_RANDOM && s != FileChunksInfo::CHUNK_STRATEGY_PROGRESSIVE)
509+
if(s != FileChunksInfo::CHUNK_STRATEGY_SEQUENTIAL && s != FileChunksInfo::CHUNK_STRATEGY_RANDOM && s != FileChunksInfo::CHUNK_STRATEGY_PROGRESSIVE && s != FileChunksInfo::CHUNK_STRATEGY_STREAMING)
501510
{
502-
std::cerr << "ftFileCreator::ERROR: invalid chunk strategy " << s << "!" << " setting default value " << FileChunksInfo::CHUNK_STRATEGY_STREAMING << std::endl ;
511+
std::cerr << "ftFileCreator::ERROR: invalid chunk strategy " << s << "!" << " setting default value " << FileChunksInfo::CHUNK_STRATEGY_SEQUENTIAL << std::endl ;
503512
s = FileChunksInfo::CHUNK_STRATEGY_PROGRESSIVE ;
504513
}
505514

506515
#ifdef FILE_DEBUG
507516
std::cerr << "ftFileCtreator: setting chunk strategy to " << s << std::endl ;
508517
#endif
518+
RsDbg() << "STREAMING: ftFileCreator::setChunkStrategy " << s;
509519
chunkMap.setStrategy(s) ;
510520
}
511521

@@ -761,5 +771,95 @@ bool ftFileCreator::verifyChunk(uint32_t chunk_number,const Sha1CheckSum& sum)
761771
return true ;
762772
}
763773

774+
bool ftFileCreator::checkForMp4Index()
775+
{
776+
int strat = (int)chunkMap.getStrategy();
777+
778+
// STRICT RULE: Only active in STREAMING_PRIO_END
779+
if (strat != FileChunksInfo::CHUNK_STRATEGY_STREAMING)
780+
{
781+
// RsDbg() << "STREAMING: ftFileCreator::checkForMp4Index ignored. Strategy=" << strat;
782+
return false;
783+
}
784+
785+
// Phase 1: Just log that we passed the guard
786+
RsDbg() << "STREAMING: ftFileCreator::checkForMp4Index RUNNING. Strategy=" << strat << ". Parsing loop start.";
787+
788+
// Phase 2: Atom Parsing (Observer Mode)
789+
if (_mp4_index_found) return true;
790+
791+
// Open file to read atoms
792+
FILE* f = fopen(file_name.c_str(), "rb");
793+
if (!f)
794+
{
795+
RsDbg() << "STREAMING: Failed to open file " << file_name;
796+
return false;
797+
}
798+
799+
uint64_t currentPos = 0;
800+
801+
// MP4 Atom Header
802+
struct {
803+
uint32_t size;
804+
char type[4];
805+
} header;
806+
807+
int safe_loop_count = 0;
808+
809+
while (true)
810+
{
811+
if (fseek(f, currentPos, SEEK_SET) != 0 || fread(&header, 1, 8, f) != 8)
812+
break;
813+
814+
uint32_t atomSize = be32toh(header.size);
815+
uint64_t realAtomSize = atomSize;
816+
817+
if (atomSize == 1) {
818+
uint64_t bigSize;
819+
if (fread(&bigSize, 1, 8, f) == 8) realAtomSize = be64toh(bigSize);
820+
}
821+
822+
// Create a null-terminated string for logging safely
823+
char typeStr[5] = {0};
824+
memcpy(typeStr, header.type, 4);
825+
826+
RsDbg() << "STREAMING: Found atom '" << typeStr << "' at " << currentPos << " size " << realAtomSize;
827+
828+
if (strncmp(header.type, "moov", 4) == 0) {
829+
RsDbg() << "STREAMING: MOOV atom found at " << currentPos << " (Beginning of file?). Stop.";
830+
_mp4_index_found = true;
831+
break;
832+
}
833+
834+
if (strncmp(header.type, "mdat", 4) == 0) {
835+
uint64_t predictedMoov = currentPos + realAtomSize;
836+
RsDbg() << "STREAMING: MDAT found. Size: " << realAtomSize << ". Predicted MOOV at: " << predictedMoov;
837+
838+
// Phase 3: Actuation
839+
// Calculate chunks covering the MOOV index (from predictedMoov to end of file)
840+
uint32_t chunkSize = ChunkMap::CHUNKMAP_FIXED_CHUNK_SIZE;
841+
uint32_t startChunk = predictedMoov / chunkSize;
842+
uint32_t endChunk = mSize / chunkSize;
843+
844+
RsDbg() << "STREAMING: Setting High Priority Range: " << startChunk << " -> " << endChunk;
845+
chunkMap.setHighPriorityRange(startChunk, endChunk);
846+
847+
_mp4_index_found = true;
848+
break;
849+
}
850+
851+
currentPos += realAtomSize;
852+
if (realAtomSize == 0 || currentPos >= mSize) break;
853+
854+
if (++safe_loop_count > 50) {
855+
RsDbg() << "STREAMING: Safety break (too many atoms)";
856+
break;
857+
}
858+
}
859+
860+
fclose(f);
861+
return false;
862+
}
863+
764864

765865

src/ft/ftfilecreator.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,14 @@ class ftFileCreator: public ftFileProvider
144144

145145
ChunkMap chunkMap ;
146146

147+
147148
rstime_t _last_recv_time_t ; /// last time stamp when data was received. Used for queue control.
148149
rstime_t _creation_time ; /// time at which the file creator was created. Used to spot long-inactive transfers.
150+
151+
// MP4 Smart Preview
152+
bool _mp4_index_found;
153+
uint64_t _mp4_index_offset;
154+
bool checkForMp4Index();
149155
};
150156

151157
#endif // FT_FILE_CREATOR_HEADER

src/retroshare/rstypes.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,9 +353,10 @@ struct FileChunksInfo : RsSerializable
353353

354354
enum ChunkStrategy : uint8_t
355355
{
356-
CHUNK_STRATEGY_STREAMING,
356+
CHUNK_STRATEGY_SEQUENTIAL,
357357
CHUNK_STRATEGY_RANDOM,
358-
CHUNK_STRATEGY_PROGRESSIVE
358+
CHUNK_STRATEGY_PROGRESSIVE,
359+
CHUNK_STRATEGY_STREAMING
359360
};
360361

361362
struct SliceInfo : RsSerializable

0 commit comments

Comments
 (0)