Merge pull request #2837 from peterbrant14/Fix_RLV_Sync

Improve RLV Syncronization
This commit is contained in:
Alejandro Martinez
2020-01-08 16:10:02 -03:00
committed by GitHub
4 changed files with 86 additions and 13 deletions

View File

@@ -401,6 +401,13 @@ void ErgFile::parseTacx()
// if we got here and are still happy then it
// must have been a valid file.
if (happy) {
// Set the end point for the workout
ErgFilePoint end;
end.x = rdist;
end.y = Points.last().y;
end.val = Points.last().val;
Points.append(end);
valid = true;
// set ErgFile duration

View File

@@ -1667,9 +1667,14 @@ void TrainSidebar::guiUpdate() // refreshes the telemetry
displayLapDistance += distanceTick;
displayLapDistanceRemaining -= distanceTick;
if (!(status&RT_MODE_ERGO) && (context->currentVideoSyncFile())) {
displayWorkoutDistance = context->currentVideoSyncFile()->km + context->currentVideoSyncFile()->manualOffset;
if (!(status&RT_MODE_ERGO) && (context->currentVideoSyncFile()))
{
displayWorkoutDistance = context->currentVideoSyncFile()->km;
// If we reached the end of the RLV then stop
if (displayWorkoutDistance >= context->currentVideoSyncFile()->Distance) {
Stop(DEVICE_OK);
return;
}
// TODO : graphs to be shown at seek position
} else {
displayWorkoutDistance += distanceTick;

View File

@@ -72,6 +72,7 @@ void VideoSyncFile::parseRLV()
// running totals
double rdist = 0; // running total for distance
double rend = 0; // Length of entire course
// open the file for binary reading and open a datastream
QFile RLVFile(filename);
@@ -164,6 +165,8 @@ void VideoSyncFile::parseRLV()
{
// read in the mapping records
uint32_t PreviousFrameNbr=0;
double PreviousDistance=0;
for (unsigned int record=0; record < info.records; record++) {
// get the next record
if (sizeof(framemapping) != input.readRawData((char*)&framemapping, sizeof(framemapping))) {
@@ -171,11 +174,16 @@ void VideoSyncFile::parseRLV()
break;
}
if (record == 0) PreviousDistance = framemapping.distance;
VideoSyncFilePoint add;
if (format == RLV) {
double distance = framemapping.distance; // in meters per frame
rdist += distance * (double) (framemapping.frameNbr - PreviousFrameNbr);
// Calculate average distance per video frame between this sync point and the last
// using the formula (2a+b)/3 where a is the point of lower speed and b is the higher.
double distance = framemapping.distance;
double avgDistance = (qMin(distance, PreviousDistance)*2 + qMax(distance, PreviousDistance)) / 3;
rdist += avgDistance * (double) (framemapping.frameNbr - PreviousFrameNbr);
add.km = rdist / 1000.0;
// time
@@ -186,6 +194,7 @@ void VideoSyncFile::parseRLV()
// FIXME : do we have to consider video offset and weight ?
PreviousFrameNbr = framemapping.frameNbr;
PreviousDistance = distance;
}
Points.append(add);
@@ -220,6 +229,7 @@ void VideoSyncFile::parseRLV()
happy = false;
break;
}
if (courseInfo.end > rend) rend = courseInfo.end;
}
// FIXME : add those data to training messages
}
@@ -236,6 +246,17 @@ void VideoSyncFile::parseRLV()
} else happy = false;
}
// Make sure we have a sync point to represent the end of the course
// Some earlier rlvs don't supply an end point frame reference,
// so we need to assume the speed from the last ref point continues to the end
if ((!Points.isEmpty()) && (rend > Points.last().km * 1000) && Points.last().kph > 0) {
VideoSyncFilePoint add;
add.km = rend / 1000;
add.kph = Points.last().kph;
add.secs = Points.last().secs + ((add.km - Points.last().km) * 3600) / add.kph;
Points.append(add);
}
// done
RLVFile.close();

View File

@@ -206,8 +206,10 @@ void VideoWindow::resizeEvent(QResizeEvent * )
void VideoWindow::startPlayback()
{
if (context->currentVideoSyncFile())
if (context->currentVideoSyncFile()) {
context->currentVideoSyncFile()->manualOffset = 0.0;
context->currentVideoSyncFile()->km = 0.0;
}
#ifdef GC_VIDEO_VLC
if (!m) return; // ignore if no media selected
@@ -218,8 +220,12 @@ void VideoWindow::startPlayback()
/* set the media to playback */
libvlc_media_player_set_media (mp, m);
/* set the playback rate to the media default - since there may be a different one set from RLV */
libvlc_media_player_set_rate(mp, libvlc_media_player_get_fps(mp));
/* Reset playback rate */
/* If video speed will be controlled by a sync file, set almost stationary
until first telemetry update. Otherwise (re)set to normal rate */
if (context->currentVideoSyncFile() && context->currentVideoSyncFile()->Points.count() > 1)
libvlc_media_player_set_rate(mp, 0.1f);
else libvlc_media_player_set_rate(mp, 1.0f);
/* play the media_player */
libvlc_media_player_play (mp);
@@ -402,7 +408,8 @@ void VideoWindow::telemetryUpdate(RealtimeData rtd)
#endif
#ifdef GC_VIDEO_VLC
if (!m) return;
if (!m || !context->isRunning || context->isPaused)
return;
QList<ErgFilePoint> *ErgFilePoints = NULL;
if (context->currentErgFile()) {
@@ -431,11 +438,44 @@ void VideoWindow::telemetryUpdate(RealtimeData rtd)
while ((VideoSyncFiledataPoints[curPosition].km <= CurrentDistance) && (curPosition < VideoSyncFiledataPoints.count()-1))
curPosition++;
// update the rfp
float weighted_average = (VideoSyncFiledataPoints[curPosition].km - VideoSyncFiledataPoints[curPosition-1].km != 0.0)?(CurrentDistance-VideoSyncFiledataPoints[curPosition-1].km) / (VideoSyncFiledataPoints[curPosition].km - VideoSyncFiledataPoints[curPosition-1].km):0.0;
/* Create an RFP to represent where we are */
VideoSyncFilePoint syncPrevious = VideoSyncFiledataPoints[curPosition-1];
VideoSyncFilePoint syncNext = VideoSyncFiledataPoints[curPosition];
double syncKmDelta = syncNext.km - syncPrevious.km;
double syncKphDelta = syncNext.kph - syncPrevious.kph;
double syncTimeDelta = syncNext.secs - syncPrevious.secs;
double distanceFactor, speedFactor, timeFactor, timeExtra;
// Calculate how far we are between points in terms of distance
if (syncKmDelta == 0) distanceFactor = 0.0;
else distanceFactor = (CurrentDistance - syncPrevious.km) / syncKmDelta;
// Now create the appropriate factors and interpolate the
// video speed and time for the point we have reached.
// If there has been no acceleration we can just use use the distance factor
if (syncKphDelta == 0) {
// Constant filming speed
rfp.kph = syncPrevious.kph;
rfp.secs = syncPrevious.secs + syncTimeDelta * distanceFactor;
}
else {
// Calculate time difference because of change in speed
timeExtra = syncTimeDelta - ((syncKmDelta / syncPrevious.kph) * 3600);
if (syncKphDelta > 0) {
// The filming speed increased
speedFactor = qPow(distanceFactor, 0.66667);
timeFactor = qPow(distanceFactor, 0.33333);
rfp.kph = syncPrevious.kph + speedFactor * syncKphDelta;
}
else {
// The filming speed decreased
speedFactor = 1 - qPow(distanceFactor, 1.5);
timeFactor = qPow(distanceFactor, 3.0);
rfp.kph = syncNext.kph - speedFactor * syncKphDelta;
}
rfp.secs = syncPrevious.secs + (distanceFactor * (syncTimeDelta - timeExtra)) + (timeFactor * timeExtra);
}
rfp.km = CurrentDistance;
rfp.secs = VideoSyncFiledataPoints[curPosition-1].secs + weighted_average * (VideoSyncFiledataPoints[curPosition].secs - VideoSyncFiledataPoints[curPosition-1].secs);
rfp.kph = VideoSyncFiledataPoints[curPosition-1].kph + weighted_average * (VideoSyncFiledataPoints[curPosition].kph - VideoSyncFiledataPoints[curPosition-1].kph);
/*
//TODO : GPX file format