Skip to main content

rpfm_lib/files/video/
mod.rs

1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2026 Ismael Gutiérrez González. All rights reserved.
3//
4// This file is part of the Rusted PackFile Manager (RPFM) project,
5// which can be found here: https://github.com/Frodo45127/rpfm.
6//
7// This file is licensed under the MIT license, which can be found here:
8// https://github.com/Frodo45127/rpfm/blob/master/LICENSE.
9//---------------------------------------------------------------------------//
10
11//! CA_VP8 are a custom version of a VP8 video by CA. These files contain only video data, no audio.
12//!
13//! Within this module are functions to convert these files into IVF files, readable by tools such
14//! FFMpeg, VLC or MPV.
15//!
16//! These files can usually be found under the movies folder, with the extension `.ca_vp8`. This format
17//! is versioned through a `version` number in the file's header. This lib supports has support for reading
18//! and writing the versions 0 and 1.
19//!
20//! # CA_VP8 Structure
21//!
22//! ## Header
23//! ### V1
24//!
25//! | Bytes | Type     | Data                       |
26//! | ----- | -------- | -------------------------- |
27//! | 4     | StringU8 | Signature of the file.     |
28//! | 4     | [u32]    | Version of the file.       |
29//! | 4     | [u32]    | Length of the header.      |
30//! | 4     | StringU8 | FourCC of the video.       |
31//! | 2     | [u16]    | Width of the video.        |
32//! | 2     | [u16]    | Heigth of the video.       |
33//! | 4     | [f32]    | Milliseconds per frame.    |
34//! | 4     | [u32]    | Unknown.                   |
35//! | 4     | [u32]    | Number of frames - 1.      |
36//! | 4     | [u32]    | Offset of the frame table. |
37//! | 4     | [u32]    | Number of frames.          |
38//! | 4     | [u32]    | Largest frame.             |
39//! | 1     | [u8]     | Unknown value.             |
40//!
41//! ### V0
42//!
43//! | Bytes | Type     | Data                       |
44//! | ----- | -------- | -------------------------- |
45//! | 4     | StringU8 | Signature of the file.     |
46//! | 4     | [u32]    | Version of the file.       |
47//! | 4     | [u32]    | Length of the header - 8.  |
48//! | 4     | StringU8 | FourCC of the video.       |
49//! | 2     | [u16]    | Width of the video.        |
50//! | 2     | [u16]    | Heigth of the video.       |
51//! | 4     | [f32]    | Milliseconds per frame.    |
52//! | 4     | [u32]    | Unknown.                   |
53//! | 4     | [u32]    | Number of frames.          |
54//! | 4     | [u32]    | Offset of the frame table. |
55//! | 4     | [u32]    | Number of frames.          |
56//! | 4     | [u32]    | Largest frame.             |
57//!
58//! ## Frames Data
59//!
60//! This is valid for versions 0 and 1.
61//!
62//! | Bytes                                | Type                                         | Data                                                           |
63//! | ------------------------------------ | -------------------------------------------- | -------------------------------------------------------------- |
64//! | Frame table's offset - header length | &\[[u8]\]                                    | Frames data, concatenated.                                     |
65//! | Until the end of the file            | &\[[Frame Table Entry](#frame-table-entry)\] | List of entries with each frame metadata (position, size,...). |
66//!
67//! ## Frame Table Entry
68//!
69//! This is valid for versions 0 and 1.
70//!
71//! | Bytes      | Type      | Data                                             |
72//! | ---------- | --------- | ------------------------------------------------ |
73//! | 4          | [u32]     | Offset of the frame from the start of the file.  |
74//! | 4          | [u32]     | Size in bytes of the frame's data.               |
75//! | 4          | [u32]     | Optional. Unknown value. Only present sometimes. |
76//! | 1          | [bool]    | Is the frame a key frame?                        |
77//!
78//!
79//! Credits for this module:
80//! - Research and initial implementation for this was done by **John Sirett** here:
81//!   - <https://gitlab.com/johnsirett/ca_vp8-reverse>
82//!
83//! As such, the read/save functions for CaVp8 and Ivf in the submodules of this module (and only those functions)
84//! are an exception to the MIT license above and are under the CC-SA 4.0 license, available here:
85//! - <https://creativecommons.org/licenses/by-sa/4.0/>
86
87use getset::*;
88use serde_derive::{Serialize, Deserialize};
89
90use crate::binary::{ReadBytes, WriteBytes};
91use crate::error::{RLibError, Result};
92use crate::files::{DecodeableExtraData, Decodeable, EncodeableExtraData, Encodeable};
93
94/// Extensions used by CaVp8 Files.
95pub const EXTENSION: &str = ".ca_vp8";
96
97/// Signature/Magic Numbers/Whatever of a IVF video file.
98const SIGNATURE_IVF: &str = "DKIF";
99
100/// Signature/Magic Numbers/Whatever of a CaVp8 video file.
101const SIGNATURE_CAVP8: &str = "CAMV";
102
103mod ca_vp8;
104mod ivf;
105
106#[cfg(test)] mod ca_vp8_test;
107#[cfg(test)] mod ivf_test;
108
109//---------------------------------------------------------------------------//
110//                              Enum & Structs
111//---------------------------------------------------------------------------//
112
113/// This represents an entire CaVp8 File decoded in memory.
114#[derive(PartialEq, Clone, Debug, Getters, Setters, Serialize, Deserialize)]
115#[getset(get = "pub", set = "pub")]
116pub struct Video {
117
118    /// Format of the video file
119    format: SupportedFormats,
120
121    /// Version number.
122    version: u16,
123
124    /// Codec FourCC (usually 'VP80').
125    codec_four_cc: String,
126
127    /// Width of the video in pixels.
128    width: u16,
129
130    /// Height of the video in pixels.
131    height: u16,
132
133    /// Number of frames on the video.
134    num_frames: u32,
135
136    /// Framerate of the video.
137    framerate: f32,
138
139    /// Extra unknown data at the end of some headers.
140    extra_data: Option<(u8, u32, u32)>,
141
142    /// Frame Table of the video.
143    frame_table: Vec<Frame>,
144
145    /// Raw frame data of the video.
146    frame_data: Vec<u8>,
147}
148
149/// This struct contains the information needed to locate an specific frame from a video within the raw frame data.
150#[derive(PartialEq, Eq, Clone, Copy, Debug, Getters, Setters, Serialize, Deserialize)]
151#[getset(get = "pub", set = "pub")]
152pub struct Frame {
153
154    /// Offset on the data where the frame begins.
155    offset: u32,
156
157    /// Size of the frame.
158    size: u32,
159
160    /// If the frame is a key frame.
161    is_key_frame: bool,
162}
163
164/// This enum contains the list of formats this lib supports.
165#[derive(PartialEq, Eq, Clone, Copy, Debug, Default, Serialize, Deserialize)]
166pub enum SupportedFormats {
167
168    /// Used by CA in CaVp8 files.
169    #[default]
170    CaVp8,
171
172    /// VP8 IVF standard format.
173    Ivf,
174}
175
176//---------------------------------------------------------------------------//
177//                              Implementation
178//---------------------------------------------------------------------------//
179
180impl Decodeable for Video {
181
182    fn decode<R: ReadBytes>(data: &mut R, _extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
183        match &*data.read_string_u8(4)? {
184            SIGNATURE_IVF => Self::read_ivf(data),
185            SIGNATURE_CAVP8 => Self::read_cavp8(data),
186            _ => Err(RLibError::DecodingCAVP8UnsupportedFormat)
187        }
188    }
189}
190
191impl Encodeable for Video {
192    fn encode<W: WriteBytes>(&mut self, buffer: &mut W, _extra_data: &Option<EncodeableExtraData>) -> Result<()> {
193        match self.format {
194            SupportedFormats::CaVp8 => self.save_cavp8(buffer),
195            SupportedFormats::Ivf => self.save_ivf(buffer),
196        }
197    }
198}