+ return tracks - base;
+}
+
+void
+Timeline::assign_tracks ()
+{
+ /* Tracks are:
+ Video (mono or left-eye)
+ Video (right-eye)
+ Subtitle 1
+ Subtitle 2
+ Subtitle N
+ Atmos
+ Audio 1
+ Audio 2
+ Audio N
+ */
+
+ _tracks = 0;
+
+ for (TimelineViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
+ shared_ptr<TimelineContentView> c = dynamic_pointer_cast<TimelineContentView> (*i);
+ if (c) {
+ c->unset_track ();
+ }
+ }
+
+ /* Video */
+
+ bool have_3d = false;
+ BOOST_FOREACH (shared_ptr<TimelineView> i, _views) {
+ shared_ptr<TimelineVideoContentView> cv = dynamic_pointer_cast<TimelineVideoContentView> (i);
+ if (!cv) {
+ continue;
+ }
+
+ /* Video on tracks 0 and maybe 1 (left and right eye) */
+ if (cv->content()->video->frame_type() == VIDEO_FRAME_TYPE_3D_RIGHT) {
+ cv->set_track (1);
+ _tracks = max (_tracks, 2);
+ have_3d = true;
+ } else {
+ cv->set_track (0);
+ }
+ }
+
+ _tracks = max (_tracks, 1);
+
+ /* Subtitle */
+
+ int const subtitle_tracks = place<TimelineSubtitleContentView> (_views, _tracks);
+
+ /* Atmos */
+
+ bool have_atmos = false;
+ BOOST_FOREACH (shared_ptr<TimelineView> i, _views) {
+ shared_ptr<TimelineVideoContentView> cv = dynamic_pointer_cast<TimelineVideoContentView> (i);
+ if (!cv) {
+ continue;
+ }
+ if (dynamic_pointer_cast<TimelineAtmosContentView> (i)) {
+ cv->set_track (_tracks - 1);
+ have_atmos = true;
+ }
+ }
+
+ if (have_atmos) {
+ ++_tracks;
+ }
+
+ /* Audio */
+
+ place<TimelineAudioContentView> (_views, _tracks);
+
+ _labels_view->set_3d (have_3d);
+ _labels_view->set_subtitle_tracks (subtitle_tracks);
+ _labels_view->set_atmos (have_atmos);
+