qcamera stream
parent
3ab69d1d15
commit
e9bec22a98
|
@ -4,8 +4,8 @@
|
|||
"private": true,
|
||||
"homepage": "https://community.comma.ai/cabana",
|
||||
"dependencies": {
|
||||
"@commaai/comma-api": "^1.2.2",
|
||||
"@commaai/hls.js": "^0.12.5",
|
||||
"@commaai/comma-api": "^1.3.1",
|
||||
"@commaai/hls.js": "^0.12.6",
|
||||
"@commaai/log_reader": "^0.5.5",
|
||||
"@commaai/my-comma-auth": "^1.1.4",
|
||||
"@commaai/pandajs": "^0.3.4",
|
||||
|
@ -34,7 +34,6 @@
|
|||
"font-awesome": "^4.7.0",
|
||||
"github-api": "^3.0.0",
|
||||
"global": "^4.3.2",
|
||||
"hls": "0.0.1",
|
||||
"husky": "^0.14.3",
|
||||
"int64-buffer": "^0.1.9",
|
||||
"js-cookie": "^2.1.4",
|
||||
|
|
|
@ -54,6 +54,7 @@ export default class CanExplorer extends Component {
|
|||
selectedMessages: [],
|
||||
route: null,
|
||||
canFrameOffset: 0,
|
||||
routeInitTime: 0,
|
||||
firstCanTime: null,
|
||||
lastBusTime: null,
|
||||
selectedMessage: null,
|
||||
|
@ -494,12 +495,15 @@ export default class CanExplorer extends Component {
|
|||
}
|
||||
|
||||
maxByteStateChangeCount = e.data.maxByteStateChangeCount;
|
||||
const { newMessages, newThumbnails, isFinished } = e.data;
|
||||
const { newMessages, newThumbnails, isFinished, routeInitTime } = e.data;
|
||||
if (maxByteStateChangeCount > this.state.maxByteStateChangeCount) {
|
||||
this.setState({ maxByteStateChangeCount });
|
||||
} else {
|
||||
maxByteStateChangeCount = this.state.maxByteStateChangeCount;
|
||||
}
|
||||
if (routeInitTime !== this.state.routeInitTime) {
|
||||
this.setState({ routeInitTime });
|
||||
}
|
||||
|
||||
this.addMessagesToDataCache(part, newMessages, newThumbnails);
|
||||
|
||||
|
@ -1366,6 +1370,7 @@ export default class CanExplorer extends Component {
|
|||
routeStartTime={
|
||||
route ? route.start_time : Moment()
|
||||
}
|
||||
routeInitTime={ this.state.routeInitTime }
|
||||
partsCount={route ? route.proclog : 0}
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
@ -463,7 +463,6 @@ export default class Explorer extends Component {
|
|||
(this.props.currentParts[1] + 1) * 60
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="cabana-explorer">
|
||||
<div className={cx('cabana-explorer-signals', signalsExpandedClass)}>
|
||||
|
@ -488,8 +487,8 @@ export default class Explorer extends Component {
|
|||
userSeekIndex={this.state.userSeekIndex}
|
||||
playing={this.state.playing}
|
||||
url={this.props.url}
|
||||
canFrameOffset={this.props.canFrameOffset}
|
||||
firstCanTime={this.props.firstCanTime}
|
||||
routeInitTime={this.props.routeInitTime}
|
||||
onVideoClick={this.onVideoClick}
|
||||
onPlaySeek={this.onPlaySeek}
|
||||
onUserSeek={this.onUserSeek}
|
||||
|
|
|
@ -9,11 +9,11 @@ export default class HLS extends Component {
|
|||
playbackSpeed: PropTypes.number.isRequired,
|
||||
playing: PropTypes.bool.isRequired,
|
||||
onVideoElementAvailable: PropTypes.func,
|
||||
onStartTimeAvailable: PropTypes.func,
|
||||
onClick: PropTypes.func,
|
||||
onLoadStart: PropTypes.func,
|
||||
onLoadEnd: PropTypes.func,
|
||||
onPlaySeek: PropTypes.func,
|
||||
segmentProgress: PropTypes.func,
|
||||
onRestart: PropTypes.func
|
||||
};
|
||||
|
||||
|
@ -38,7 +38,12 @@ export default class HLS extends Component {
|
|||
componentDidMount() {
|
||||
this.player = new Hls({
|
||||
enableWorker: false,
|
||||
disablePtsDtsCorrectionInMp4Remux: true
|
||||
disablePtsDtsCorrectionInMp4Remux: false,
|
||||
debug: true
|
||||
});
|
||||
this.player.on(Hls.Events.INIT_PTS_FOUND, (event, data) => {
|
||||
const time = data.initPTS/90000;
|
||||
this.props.onStartTimeAvailable(time);
|
||||
});
|
||||
this.player.on(Hls.Events.ERROR, (event, data) => {
|
||||
if (data.fatal) {
|
||||
|
@ -89,7 +94,6 @@ export default class HLS extends Component {
|
|||
this.player.loadSource(source);
|
||||
this.player.attachMedia(this.videoElement);
|
||||
this.props.onVideoElementAvailable(this.videoElement);
|
||||
this.videoElement.currentTime = this.props.startTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,9 @@ export default class RouteVideoSync extends Component {
|
|||
shouldShowJpeg: true,
|
||||
isLoading: true,
|
||||
videoElement: null,
|
||||
source: null,
|
||||
videoStartTime: null,
|
||||
offset: 0,
|
||||
};
|
||||
|
||||
this.onLoadStart = this.onLoadStart.bind(this);
|
||||
|
@ -59,29 +62,51 @@ export default class RouteVideoSync extends Component {
|
|||
this.onUserSeek = this.onUserSeek.bind(this);
|
||||
this.onPlaySeek = this.onPlaySeek.bind(this);
|
||||
this.ratioTime = this.ratioTime.bind(this);
|
||||
this.onStartTimeAvailable = this.onStartTimeAvailable.bind(this);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.setState({source: VideoApi(
|
||||
this.props.url,
|
||||
process.env.REACT_APP_VIDEO_CDN
|
||||
).getQcameraStreamIndexUrl()});
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { userSeekTime } = this.props;
|
||||
const { videoElement } = this.state;
|
||||
const { videoElement, videoStartTime } = this.state;
|
||||
|
||||
if (
|
||||
prevProps.userSeekTime
|
||||
&& userSeekTime !== prevProps.userSeekTime
|
||||
) {
|
||||
if (videoElement) {
|
||||
videoElement.currentTime = userSeekTime;
|
||||
videoElement.currentTime = userSeekTime - this.state.offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (!prevProps.routeInitTime && this.props.routeInitTime) {
|
||||
this.updateOffset();
|
||||
}
|
||||
}
|
||||
|
||||
onVideoElementAvailable(videoElement) {
|
||||
this.setState({ videoElement });
|
||||
}
|
||||
|
||||
onStartTimeAvailable(videoStartTime) {
|
||||
this.setState({ videoStartTime }, () => this.updateOffset());
|
||||
}
|
||||
|
||||
updateOffset() {
|
||||
if (this.props.routeInitTime && this.state.videoStartTime) {
|
||||
this.setState({ offset: this.state.videoStartTime - this.props.routeInitTime });
|
||||
}
|
||||
}
|
||||
onUserSeek(ratio) {
|
||||
/* ratio in [0,1] */
|
||||
|
||||
const { videoElement } = this.state;
|
||||
const { videoElement, videoStartTime } = this.state;
|
||||
const { onUserSeek } = this.props;
|
||||
const seekTime = this.ratioTime(ratio);
|
||||
const funcSeekToRatio = () => onUserSeek(seekTime);
|
||||
|
@ -89,7 +114,7 @@ export default class RouteVideoSync extends Component {
|
|||
if (Number.isNaN(videoElement.duration)) {
|
||||
return;
|
||||
}
|
||||
videoElement.currentTime = seekTime;
|
||||
videoElement.currentTime = seekTime - this.state.offset;
|
||||
|
||||
if (ratio !== 0) {
|
||||
funcSeekToRatio();
|
||||
|
@ -97,9 +122,8 @@ export default class RouteVideoSync extends Component {
|
|||
}
|
||||
|
||||
onPlaySeek(offset) {
|
||||
const { onPlaySeek } = this.props;
|
||||
this.seekTime = offset;
|
||||
onPlaySeek(offset);
|
||||
this.seekTime = offset + this.state.offset;
|
||||
this.props.onPlaySeek(this.seekTime);
|
||||
}
|
||||
|
||||
onLoadStart() {
|
||||
|
@ -182,7 +206,8 @@ export default class RouteVideoSync extends Component {
|
|||
const {
|
||||
isLoading,
|
||||
shouldShowJpeg,
|
||||
videoElement
|
||||
videoElement,
|
||||
videoStartTime,
|
||||
} = this.state;
|
||||
const {
|
||||
userSeekTime,
|
||||
|
@ -194,6 +219,7 @@ export default class RouteVideoSync extends Component {
|
|||
startTime,
|
||||
segment
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className="cabana-explorer-visuals-camera">
|
||||
{isLoading ? this.loadingOverlay() : null}
|
||||
|
@ -206,27 +232,24 @@ export default class RouteVideoSync extends Component {
|
|||
) : null}
|
||||
<HLS
|
||||
className={css(Styles.hls)}
|
||||
source={VideoApi(
|
||||
url,
|
||||
process.env.REACT_APP_VIDEO_CDN
|
||||
).getRearCameraStreamIndexUrl()}
|
||||
source={this.state.source}
|
||||
startTime={startTime || 0}
|
||||
videoLength={this.videoLength()}
|
||||
playbackSpeed={playSpeed}
|
||||
onVideoElementAvailable={this.onVideoElementAvailable}
|
||||
playing={playing}
|
||||
onStartTimeAvailable={this.onStartTimeAvailable}
|
||||
onClick={onVideoClick}
|
||||
onLoadStart={this.onLoadStart}
|
||||
onLoadEnd={this.onLoadEnd}
|
||||
onUserSeek={this.onUserSeek}
|
||||
onPlaySeek={this.onPlaySeek}
|
||||
segmentProgress={this.segmentProgress}
|
||||
/>
|
||||
<RouteSeeker
|
||||
className={css(Styles.seekBar)}
|
||||
nearestFrameTime={userSeekTime}
|
||||
segmentProgress={this.segmentProgress}
|
||||
startTime={this.startTime()}
|
||||
startTime={this.startTime() - this.state.offset}
|
||||
videoLength={this.videoLength()}
|
||||
segmentIndices={segmentIndices}
|
||||
onUserSeek={this.onUserSeek}
|
||||
|
|
|
@ -28,7 +28,7 @@ function sendBatch(entry) {
|
|||
entry.messages = {};
|
||||
entry.thumbnails = [];
|
||||
|
||||
let { maxByteStateChangeCount } = entry.options;
|
||||
let { maxByteStateChangeCount, routeInitTime } = entry.options;
|
||||
const newMaxByteStateChangeCount = DbcUtils.findMaxByteStateChangeCount(
|
||||
messages
|
||||
);
|
||||
|
@ -48,7 +48,8 @@ function sendBatch(entry) {
|
|||
newMessages: messages,
|
||||
newThumbnails: thumbnails,
|
||||
isFinished: entry.ended,
|
||||
maxByteStateChangeCount
|
||||
maxByteStateChangeCount,
|
||||
routeInitTime,
|
||||
});
|
||||
|
||||
if (entry.ended) {
|
||||
|
@ -93,7 +94,7 @@ function insertEventData(src, part, entry, logTime, getData) {
|
|||
time: logTime,
|
||||
address,
|
||||
data: getData(),
|
||||
timeStart: entry.options.canStartTime
|
||||
timeStart: entry.options.routeInitTime
|
||||
};
|
||||
|
||||
entry.messages[id].entries.push(msgEntry);
|
||||
|
@ -124,7 +125,7 @@ function insertCanMessage(entry, logTime, msg) {
|
|||
time: logTime,
|
||||
address,
|
||||
data: msg.Dat,
|
||||
timeStart: entry.options.canStartTime
|
||||
timeStart: entry.options.routeInitTime
|
||||
};
|
||||
|
||||
entry.messages[id].entries.push(msgEntry);
|
||||
|
@ -164,8 +165,8 @@ async function loadData(entry) {
|
|||
}
|
||||
if ('InitData' in msg) {
|
||||
const monoTime = msg.LogMonoTime / 1e9;
|
||||
if (entry.options.canStartTime == null) {
|
||||
entry.options.canStartTime = monoTime;
|
||||
if (entry.options.routeInitTime == null) {
|
||||
entry.options.routeInitTime = monoTime;
|
||||
}
|
||||
} else if ('Can' in msg) {
|
||||
const monoTime = msg.LogMonoTime / 1000000000;
|
||||
|
@ -244,7 +245,7 @@ async function loadData(entry) {
|
|||
partial(getThermalFreeSpace, msg.Thermal)
|
||||
);
|
||||
} else if ('Thumbnail' in msg) {
|
||||
const monoTime = msg.LogMonoTime / 1000000000 - entry.options.canStartTime;
|
||||
const monoTime = msg.LogMonoTime / 1000000000 - entry.options.routeInitTime;
|
||||
const data = new Uint8Array(msg.Thumbnail.Thumbnail);
|
||||
entry.thumbnails.push({ data, monoTime });
|
||||
} else {
|
||||
|
|
23
yarn.lock
23
yarn.lock
|
@ -928,10 +928,20 @@
|
|||
joi-browser "^13.4.0"
|
||||
querystringify "^2.1.1"
|
||||
|
||||
"@commaai/hls.js@^0.12.5":
|
||||
version "0.12.5"
|
||||
resolved "https://registry.yarnpkg.com/@commaai/hls.js/-/hls.js-0.12.5.tgz#891e47124b4e9e2a1528463613bf415ff252d2ec"
|
||||
integrity sha512-aZcwFrhHSGVpi76cHMjT1wQ6Pe0AVv3s0TdzNGFA6LpCb6WCFy2EF9H8QCtNlAviccYnAw4XQrJ+hHToUp4QnA==
|
||||
"@commaai/comma-api@^1.3.1":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@commaai/comma-api/-/comma-api-1.3.1.tgz#b9f94beb1a3a6f7257683025422bbce5455fc137"
|
||||
integrity sha512-S2cosuSobuY+mlMxy2Dpt6pK2wrymNcbN3Xz6f8i6072H7t33RK3DQgtTByOPoz4iDuVVQrgAexkP3zwXOUm8Q==
|
||||
dependencies:
|
||||
babel-runtime "^6.26.0"
|
||||
config-request "^0.5.1"
|
||||
joi-browser "^13.4.0"
|
||||
querystringify "^2.1.1"
|
||||
|
||||
"@commaai/hls.js@^0.12.6":
|
||||
version "0.12.6"
|
||||
resolved "https://registry.yarnpkg.com/@commaai/hls.js/-/hls.js-0.12.6.tgz#adffabb407b71e9bb3cd60e5e7309b3a9831a5f7"
|
||||
integrity sha512-yJHlG5A8zlemSF6A88reyy5RnCcLrUT/qYqXwoRz2dk4O3bZ226EOvI801ngOaeaI/CUq3Hf/K24yXR0/g4WOA==
|
||||
dependencies:
|
||||
eventemitter3 "3.1.0"
|
||||
url-toolkit "^2.1.6"
|
||||
|
@ -6130,11 +6140,6 @@ hex-color-regex@^1.1.0:
|
|||
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
|
||||
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
|
||||
|
||||
hls@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hls/-/hls-0.0.1.tgz#3433be0d4b1305db312c966527fbb156e7ed79ca"
|
||||
integrity sha1-NDO+DUsTBdsxLJZlJ/uxVufteco=
|
||||
|
||||
hmac-drbg@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
|
||||
|
|
Loading…
Reference in New Issue