mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 08:08:42 +00:00
Merge pull request #2837 from peterbrant14/Fix_RLV_Sync
Improve RLV Syncronization
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user