Class TVideo

Unit

Declaration

type TVideo = class(TObject)

Description

Video.

It can load movie from a sequence of image files. With the help of ffmpeg, it can also load any normal movie file format, like avi (compressed by anything ffmpeg can handle), OggTheora and many others. ffmpeg really handles probably everything you will ever want.

Video is stored simply as a sequence of uncompressed images in memory. This is not good for real movies, so don't even try to open any real, 2 hour, full dvd resolution movie — loading will take hours and you will clog your memory. This class is not supposed to be used in a real movie player.

However, this simple storage is perfect to load a short movie for some effect in a game, for example a simple movie with flames or smoke to be shown as texture in your 3D game. Memory and loading time is acceptable then, and you want to prepare all your textures before the game starts anyway (for a 3D game, there's no time to decode some movie format while playing...).

See example program castle_game_engine/examples/images_videos/simple_video_editor.lpr in our engine for example of a simple movie player/editor implemented on top of this class.

Note that some properties and methods of this class may look familiar to properties of TCastlePrecalculatedAnimation. And indeed they are familiar and work in an analogous way. Since both of these classes implement some sort of animation loading and playing, it's most sensible that some ideas find use in both of them. For example the idea of LoadFromFile / checking Loaded / Close. For example the idea that the programmer interface is mainly through ImageFromTime (like TCastlePrecalculatedAnimation.Scene). For example the way TimeLoop and TimeBackwards properties work.

Hierarchy

  • TObject
  • TVideo

Overview

Methods

Public constructor Create;
Public destructor Destroy; override;
Public function Count: Integer;
Public function Width: Cardinal;
Public function Height: Cardinal;
Public function IndexFromTime(const Time: TFloatTime): Integer;
Public function ImageFromTime(const Time: TFloatTime): TCastleImage;
Public function TimeDuration: Single;
Public procedure LoadFromFile(const URL: string; const ResizeToX: Cardinal = 0; const ResizeToY: Cardinal = 0; const Interpolation: TResizeInterpolation = riBilinear);
Public procedure SaveToFile(const URL: string);
Public procedure Resize(const ResizeToX, ResizeToY: Cardinal; const Interpolation: TResizeInterpolation = riBilinear);
Public procedure Close;
Public procedure MixWithSelfBackwards(const ProgressTitle: string);
Public procedure FadeWithSelf(FadeFrames: Cardinal; const ProgressTitle: string);
Public class function FrameIndexFromTime(const Time: TFloatTime; const ACount: Integer; const AFramesPerSecond: Single; const ATimeLoop, ATimeBackwards: boolean): Integer;
Public function AlphaChannel( const AlphaTolerance: Byte = DefaultAlphaTolerance): TAlphaChannel;
Public procedure FlipHorizontal;
Public procedure FlipVertical;

Properties

Public property Items [Index:Integer]: TCastleImage read GetItems;
Public property FramesPerSecond: Single read FFramesPerSecond;
Public property Loaded: boolean read FLoaded;
Public property TimeLoop: boolean read FTimeLoop write FTimeLoop default false;
Public property TimeBackwards: boolean read FTimeBackwards write FTimeBackwards default false;

Description

Methods

Public constructor Create;
 
Public destructor Destroy; override;
 
Public function Count: Integer;

Loaded video properties. Use these only when Loaded is True.

Time is supposed to be in seconds. (Actually, we don't care; but when the movie file says to play "25 frames per second", then we will make 25 frames per this Time unit. So you probably want to count the Time in seconds too.)

Count is always >= 1 when the video is loaded. That is, we don't allow videos with zero frames (I don't know if any movie format allows this.)

Public function Width: Cardinal;
 
Public function Height: Cardinal;
 
Public function IndexFromTime(const Time: TFloatTime): Integer;
 
Public function ImageFromTime(const Time: TFloatTime): TCastleImage;
 
Public function TimeDuration: Single;

Duration of the video. In seconds (or, more precisely, in the same time units as for ImageFromTime and other methods).

Note that this doesn't count the "backwards" running time, so it ignores TimeBackwards and TimeLoop values.

Use this only when Loaded.

Public procedure LoadFromFile(const URL: string; const ResizeToX: Cardinal = 0; const ResizeToY: Cardinal = 0; const Interpolation: TResizeInterpolation = riBilinear);

Loads video from file or URL.

URL is downloaded using CastleDownload unit. As always, if you all you care about is loading normal files, then just pass a normal filename (absolute or relative to the current directory) as the URL parameter.

Supported video formats:

  • We recognize video URLs by extension, and then try to load them through ffmpeg. So ffmpeg must be available on $PATH for this. See view3dscene docs for some links.

    Internally, for now we just use ffmpeg to decompose the video to single images, and then proceed to load this image sequence. So this takes some time and drains memory for longer movies, and it's not supposed to be really used to load longer movies.

    Of course, this may get improved (and some simple video formats may be handled without ffmpeg dependency) in the future, if the need arises. For now, it's enough for me — all I want is to load some simple texture movies (like smoke or fire or dense fog animations) to use as billboards in games. For such short movies, loading time and memory use are acceptable.

  • We can also load a sequence of images with a URL like image@counter(1).png.

    We use FormatNameCounter to recognize URLs with @counter(*) macro. If it contains @counter(*) macro, then we try to load image sequence starting from counter 1. If not, we just load a single image (and treat it as a movie with only one frame).

    Note that this allows you to have alpha channel for the video. Since we just load the sequence of images, they can have alpha channel just like any still image (e.g. PNG) can have it. So your animated texture of fire / smoke etc. will be rendered will all the features of alpha channel (blending or alha testing, depending on alpha channel type). I don't know if any video file format supports any kind of alpha channel, so using image sequence may be actually your only choice for videos with alpha channel.

Parameters ResizeToX, ResizeToY allow you to resize video frames. If one of them is non-zero, the appropriate video size (width and/or height) will be resized. Resizing quality is controlled by Interpolation parameter.

Public procedure SaveToFile(const URL: string);

Save video to file (or image sequence).

Handled formats: just like LoadFromFile. Also, just like LoadFromFile, we need ffmpeg on $PATH to save to any single-file movie format.

Public procedure Resize(const ResizeToX, ResizeToY: Cardinal; const Interpolation: TResizeInterpolation = riBilinear);
 
Public procedure Close;

Release all resources allocated by LoadFromFile. Loaded property changes to False after calling this.

It's safe to call this even if Loaded is already False — then this will do nothing.

Public procedure MixWithSelfBackwards(const ProgressTitle: string);

Mix the video with itself played backwards, to force the video to play seamless in a loop.

This edits the loaded video, such that every frame becomes a mix between itself and the corresponding frame from the second half of the video. This forces any movie to become seamless when played in a loop.

After this, the movie frames count is halved and TimeBackwards is set to True. This is to conserve memory (and running time of this function), since there's no point in keeping both halves of the movie anymore — they are identical (except reversed in time) after such operation.

Unfortunately, this doesn't look perfect, human eye can easily notice the extreme time points (in the middle and at the end), when objects in the video reverse their directions etc. So the video is seamless, and it's a better trick than just setting TimeBackwards := true, but it still doesn't really look good.

If ProgressTitle <> '' this will call Progress.Init/Step/Fini from CastleProgress to indicate progress of operation.

Public procedure FadeWithSelf(FadeFrames: Cardinal; const ProgressTitle: string);

Edit the video beginning to fade with the video ending, thus forcing the video to play seamless in a loop.

The idea is to take out last FadeFrames from the video (FadeFrames must be >= 0 and <= Count div 2). And then mix the beginning of the video, such that the beginning FadeFrames frames gradually fade from the original end of video to original begin of the video.

Video must be loaded when using this.

If ProgressTitle <> '' this will call Progress.Init/Step/Fini from CastleProgress to indicate progress of operation.

Exceptions raised
EInvalidFadeFrames
When FadeFrames is wrong.
Public class function FrameIndexFromTime(const Time: TFloatTime; const ACount: Integer; const AFramesPerSecond: Single; const ATimeLoop, ATimeBackwards: boolean): Integer;

Similar to IndexFromTime, this is a class method that calculates frame index using the same algorithm. (Actually, IndexFromTime just calls this, but this is implementation detail...).

The idea is that you can reuse the same algorithm in cases when you somehow have the video data but do not have an instance of TVideo class.

In particular, this public for TGLVideo.IndexFromTime, TGLVideo.GLTextureFromTime methods.

Public function AlphaChannel( const AlphaTolerance: Byte = DefaultAlphaTolerance): TAlphaChannel;

Alpha channel type of loaded video. See TCastleImage.AlphaChannel for precise meaning of this. Currently based on the first video image, so it's fast although in some cases possibly inaccurate.

Public procedure FlipHorizontal;
 
Public procedure FlipVertical;
 

Properties

Public property Items [Index:Integer]: TCastleImage read GetItems;
 
Public property FramesPerSecond: Single read FFramesPerSecond;

Number of frames per second for this video.

For formats with varying frame-rate (although we do not support any such format right now), this will be just average frame-rate. The idea is that this property is just to show the user, so (s)he can judge the quality of the video.

Public property Loaded: boolean read FLoaded;
 
Public property TimeLoop: boolean read FTimeLoop write FTimeLoop default false;

Play the video in a never-ending loop.

If True then IndexFromTime and ImageFromTime will return information that causes the video to be played in an infinite loop. This cooperates with TimeBackwards: If TimeBackwards is also True, then each loop step will play video once forward, and once backward — infinitely.

It's Ok to change the value of this property at any time (even when video is not yet loaded), since this doesn't really cause any internal recalculation. It only affects what *FromTime methods return.

Public property TimeBackwards: boolean read FTimeBackwards write FTimeBackwards default false;

Play the video backwards after playing it forward.

This cooperates with TimeLoop. If this is True and TimeLoop = False, video will be played once forward, once backward, and then stop. If this is True and TimeLoop = also True, then the video will be played forward, then backward, infinitely.

It's Ok to change the value of this property at any time (even when video is not yet loaded), since this doesn't really cause any internal recalculation. It only affects what *FromTime methods return.


Generated by PasDoc 0.14.0.