/* Copyright 2009 Yorba Foundation * * This software is licensed under the GNU Lesser General Public License * (version 2.1 or later). See the COPYING file in this distribution. */ namespace Model { public class VideoTrack : Track { public VideoTrack(Model.Project project) { base(project, "Video Track"); } protected override string name() { return "video"; } public override MediaType media_type() { return MediaType.VIDEO; } protected override bool check(Clip clip) { Fraction rate1; Fraction rate2; if (!clip.clipfile.is_online()) return true; if (clips.size == 0) return true; if (!get_framerate(out rate2)) { error_occurred("Cannot get initial frame rate!", null); return false; } if (!clip.clipfile.get_frame_rate(out rate1)) { error_occurred("can't get frame rate", null); return false; } if (!rate1.equal(rate2)) { error_occurred("can't insert clip with different frame rate", null); return false; } return true; } /* It would be nice if we could query or seek in frames using GST_FORMAT_DEFAULT, or ask * GStreamer to convert frame->time and time->frame for us using gst_element_query_convert(). * Unfortunately there are several reasons we can't. * 1) It appears that position queries using GST_FORMAT_DEFAULT are broken since GstBaseSink * won't pass them upstream. * 2) Some codecs (e.g. theoradec) will convert between time and frames, but * others (e.g. ffmpegdec, dvdec) haven't implemented this conversion. * 3) Even when a codec will perform conversions, its frame->time and time->frame functions may * not be perfect inverses; see the comments in time_to_frame(), below. * * So instead we must convert manually using the frame rate. * * TODO: We should file GStreamer bugs for all of these. */ int64 frame_to_time(int frame) { Fraction rate; if (!get_framerate(out rate)) return 0; return (int64) Gst.util_uint64_scale(frame, Gst.SECOND * rate.denominator, rate.numerator); } int time_to_frame(int64 time) { Fraction rate; if (!get_framerate(out rate)) return 0; return time_to_frame_with_rate(time, rate); } public int get_current_frame(int64 time) { return time_to_frame(time); } public int64 previous_frame(int64 position) { int frame = time_to_frame(position); return frame_to_time(frame - 1); } public int64 next_frame(int64 position) { int frame = time_to_frame(position); return frame_to_time(frame + 1); } public bool get_framerate(out Fraction rate) { if (clips.size == 0) return false; foreach (Clip c in clips) { if (c.clipfile.is_online()) { bool can = c.clipfile.get_frame_rate(out rate); assert(can); return can; } } if (project.default_framerate.equal(Project.INVALID_FRAME_RATE)) return false; rate = project.default_framerate; return true; } } }