Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/media/ffmpeg/src/swscale.rs
5394 views
1
// Copyright 2022 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
//! This module implements a lightweight and safe interface over the conversion functions of
6
//! `libswscale`. It is designed to concentrate all calls to unsafe methods in one place, while
7
//! providing a higher-level interface for converting decoded frames from one format to another.
8
9
use thiserror::Error as ThisError;
10
11
use crate::avcodec::AvError;
12
use crate::avcodec::AvFrame;
13
use crate::avcodec::Dimensions;
14
use crate::ffi;
15
16
/// A struct able to copy a decoded `AvFrame` into an `OutputBuffer`'s memory, converting the pixel
17
/// format if needed.
18
pub struct SwConverter {
19
sws_context: *mut ffi::SwsContext,
20
src_pix_format: ffi::AVPixelFormat,
21
dst_pix_format: ffi::AVPixelFormat,
22
}
23
24
#[derive(Debug, ThisError)]
25
pub enum ConversionError {
26
#[error("AvFrame's format {frame} does not match converter {converter} configuration")]
27
FormatMismatch {
28
frame: ffi::AVPixelFormat,
29
converter: ffi::AVPixelFormat,
30
},
31
#[error("source AvFrame's dimension {0:?} does not match destination's {1:?}")]
32
DimensionMismatch(Dimensions, Dimensions),
33
#[error("destination AvFrame needs to be refcounted with refcount=1")]
34
NotWritable,
35
#[error("error during conversion with libswscale: {0}")]
36
AvError(#[from] AvError),
37
}
38
39
impl Drop for SwConverter {
40
fn drop(&mut self) {
41
// SAFETY:
42
// Safe because `sws_context` is valid through the life of this object.
43
unsafe { ffi::sws_freeContext(self.sws_context) };
44
}
45
}
46
47
impl SwConverter {
48
/// Create a new format converter that will convert frames from `src_format` to `dst_format`.
49
///
50
/// `width` and `height` are the coded size of the frames to be converted. The source and target
51
/// must have the same size in pixels.
52
pub fn new(
53
width: usize,
54
height: usize,
55
src_pix_format: ffi::AVPixelFormat,
56
dst_pix_format: ffi::AVPixelFormat,
57
) -> anyhow::Result<Self> {
58
// SAFETY:
59
// Safe because we don't pass any non-null pointer to this function.
60
let sws_context = unsafe {
61
ffi::sws_getContext(
62
width as i32,
63
height as i32,
64
src_pix_format,
65
width as i32,
66
height as i32,
67
dst_pix_format,
68
0,
69
std::ptr::null_mut(),
70
std::ptr::null_mut(),
71
std::ptr::null_mut(),
72
)
73
};
74
75
if sws_context.is_null() {
76
anyhow::bail!("error while creating the SWS context")
77
}
78
79
Ok(Self {
80
sws_context,
81
src_pix_format,
82
dst_pix_format,
83
})
84
}
85
86
/// Copy `src` into `dst` while converting its pixel format according to the parameters the
87
/// frame converter was created with.
88
///
89
/// `dst` must be a [writable] frame with the same dimensions as `src` and the same format as
90
/// `dst_pix_format` passed to the constructor.
91
///
92
/// Note that empty `dst` is not currently allowed as this function does not handle allocation.
93
///
94
/// [writable]: AvFrame::is_writable
95
pub fn convert(&mut self, src: &AvFrame, dst: &mut AvFrame) -> Result<(), ConversionError> {
96
if src.format != self.src_pix_format {
97
return Err(ConversionError::FormatMismatch {
98
frame: src.format,
99
converter: self.src_pix_format,
100
});
101
}
102
103
if dst.format != self.dst_pix_format {
104
return Err(ConversionError::FormatMismatch {
105
frame: dst.format,
106
converter: self.dst_pix_format,
107
});
108
}
109
110
if src.dimensions() != dst.dimensions() {
111
return Err(ConversionError::DimensionMismatch(
112
src.dimensions(),
113
dst.dimensions(),
114
));
115
}
116
117
if !dst.is_writable() {
118
return Err(ConversionError::NotWritable);
119
}
120
121
// SAFETY:
122
// Safe because `sws_context`, `src_ref.data` and `dst_data` are all valid pointers, and
123
// we made sure the sizes provided are within the bounds of the buffers.
124
AvError::result(unsafe {
125
ffi::sws_scale(
126
self.sws_context,
127
src.data.as_ptr() as *const *const u8,
128
src.linesize.as_ptr(),
129
0,
130
src.height,
131
dst.data.as_ptr(),
132
dst.linesize.as_ptr(),
133
)
134
})
135
.map_err(Into::into)
136
}
137
}
138
139