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}