working av1 and h264 decoder, h265 is fucked up for some reason and idk why??

This commit is contained in:
l1npengtul
2025-11-14 18:01:47 +09:00
parent 3848c416d8
commit ab2bedfbf1
211 changed files with 400 additions and 165 deletions
Generated
+6 -6
View File
@@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1755020227, "lastModified": 1762482733,
"narHash": "sha256-gGmm+h0t6rY88RPTaIm3su95QvQIVjAJx558YUG4Id8=", "narHash": "sha256-g/da4FzvckvbiZT075Sb1/YDNDr+tGQgh4N8i5ceYMg=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "695d5db1b8b20b73292501683a524e0bd79074fb", "rev": "e1ebeec86b771e9d387dd02d82ffdc77ac753abc",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -62,11 +62,11 @@
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1755052812, "lastModified": 1762828736,
"narHash": "sha256-Tjw2YP7Hz8+ibE8wJ+Ps65vh1lzAe5ozmoo9sdQ7rGg=", "narHash": "sha256-RxtFHWZpKwVcWHhx88E2NhWuBbgYVqIoIDynGs5FoJs=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "433023cba5f4fa66b8b0fdbb8f91d420c9cc2527", "rev": "8d5baa5628f6dbd7ce6beca3c299bae27755204c",
"type": "github" "type": "github"
}, },
"original": { "original": {
+77 -79
View File
@@ -5,102 +5,100 @@
rust-overlay.url = "github:oxalica/rust-overlay"; rust-overlay.url = "github:oxalica/rust-overlay";
}; };
outputs = outputs = {
{ self,
self, nixpkgs,
nixpkgs, rust-overlay,
rust-overlay, flake-utils,
flake-utils, ...
... }:
}:
flake-utils.lib.eachDefaultSystem ( flake-utils.lib.eachDefaultSystem (
system: system: let
let
pkgs = import nixpkgs { pkgs = import nixpkgs {
inherit system; inherit system;
overlays = [ rust-overlay.overlays.default ]; overlays = [rust-overlay.overlays.default];
config.allowUnfree = true; config.allowUnfree = true;
}; };
rustshell = pkgs.mkShell.override { rustshell = pkgs.mkShell.override {
stdenv = pkgs.gccStdenv; stdenv = pkgs.gccStdenv;
}; };
rustbin = pkgs.rust-bin.selectLatestNightlyWith ( rustbin = pkgs.rust-bin.selectLatestNightlyWith (
toolchain: toolchain:
toolchain.default.override { toolchain.default.override {
extensions = [ extensions = [
"rust-src" "rust-src"
"clippy" "clippy"
"rustfmt" "rustfmt"
"miri" "miri"
"rust-analyzer" "rust-analyzer"
]; ];
} }
); );
in in {
{
formatter = pkgs.alejandra; formatter = pkgs.alejandra;
devShells.default = rustshell { devShells.default = rustshell {
packages = [ packages =
rustbin [
] rustbin
++ (with pkgs; [ ]
llvmPackages_21.clangWithLibcAndBasicRtAndLibcxx ++ (with pkgs; [
pkg-config llvmPackages_21.clangWithLibcAndBasicRtAndLibcxx
cmake pkg-config
vcpkg cmake
lldb vcpkg
rustPlatform.bindgenHook lldb
xmlstarlet rustPlatform.bindgenHook
opencv xmlstarlet
alsa-lib opencv
systemdLibs alsa-lib
cmake systemdLibs
fontconfig cmake
linuxHeaders fontconfig
v4l-utils linuxHeaders
libv4l v4l-utils
pipewire libv4l
rustup pipewire
gcc rustup
ffmpeg-full gcc
nasm ffmpeg_8-full
libGL nasm
flite libGL
quirc flite
lcevcdec quirc
xz lcevcdec
celt xz
opencore-amr celt
snappy opencore-amr
codec2 snappy
gsm codec2
ilbc gsm
lame ilbc
libtheora lame
libogg libtheora
twolame libogg
vo-amrwbenc twolame
vvenc vo-amrwbenc
xavs vvenc
xvidcore xavs
soxr xvidcore
libvdpau soxr
jetbrains.rust-rover libvdpau
]); gmp
openapv
svt-av1
]);
env.RUST_SRC_PATH = "${rustbin}/lib/rustlib/src/rust/library"; env.RUST_SRC_PATH = "${rustbin}/lib/rustlib/src/rust/library";
env.LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; env.LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib";
shellHook = shellHook = let
let pathToRustProject = "/project/component[@name='RustProjectSettings']";
pathToRustProject = "/project/component[@name='RustProjectSettings']"; in ''
in echo "WONDERHOOOOOY!!!!"
'' xmlstarlet edit --inplace --update "${pathToRustProject}/option[@name='explicitPathToStdlib']/@value" --value "${rustbin}/lib/rustlib/src/rust/library" .idea/workspace.xml
echo "WONDERHOOOOOY!!!!" xmlstarlet edit --inplace --update "${pathToRustProject}/option[@name='toolchainHomeDirectory']/@value" --value "${rustbin}/bin" .idea/workspace.xml
xmlstarlet edit --inplace --update "${pathToRustProject}/option[@name='explicitPathToStdlib']/@value" --value "${rustbin}/lib/rustlib/src/rust/library" .idea/workspace.xml '';
xmlstarlet edit --inplace --update "${pathToRustProject}/option[@name='toolchainHomeDirectory']/@value" --value "${rustbin}/bin" .idea/workspace.xml
'';
}; };
} }
); );
+1 -1
View File
@@ -47,7 +47,7 @@ pub trait CodecAsync: Codec {
async fn set_format_async(&self, format: CameraFormat) -> Result<(), NokhwaError>; async fn set_format_async(&self, format: CameraFormat) -> Result<(), NokhwaError>;
fn set_config_async(&mut self, config: Self::Config) -> Result<(), NokhwaError> { fn set_config_async(&mut self, config: Self::Config) -> Result<(), NokhwaError> {
self.set_config(config) self.set_config(&config)
} }
fn send_item_async(&mut self, input: Self::Input<'_>) -> Result<(), NokhwaError>; fn send_item_async(&mut self, input: Self::Input<'_>) -> Result<(), NokhwaError>;
+14 -2
View File
@@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::frame_format::{CustomFrameFormat, FrameFormat}; use crate::frame_format::{CustomFrameFormat, FrameFormat};
use std::fmt::Debug;
use thiserror::Error;
use crate::pixel_destination::PixelDestination; use crate::pixel_destination::PixelDestination;
use crate::types::Backends; use crate::types::Backends;
use std::fmt::Debug;
use thiserror::Error;
pub type NokhwaResult<T> = Result<T, NokhwaError>; pub type NokhwaResult<T> = Result<T, NokhwaError>;
@@ -85,7 +85,19 @@ pub enum NokhwaError {
DecoderDestinationHintRequired, DecoderDestinationHintRequired,
#[error("Decoder already deinitialized. Unusable, please make a new decoder.")] #[error("Decoder already deinitialized. Unusable, please make a new decoder.")]
DecoderAlreadyDeinitialized, DecoderAlreadyDeinitialized,
#[error(
"Decoder requires more data to process - not actual error - please send more data to decode: {0}"
)]
DecoderNeedsMoreData(String),
} }
impl NokhwaError {
#[must_use]
pub fn is_needs_more(&self) -> bool {
matches!(self, NokhwaError::DecoderNeedsMoreData(_))
}
}
// //
// pub enum InitializeError {} // pub enum InitializeError {}
// //
+40 -14
View File
@@ -90,11 +90,31 @@ pub struct FrameBuffer<'a> {
impl<'a> FrameBuffer<'a> { impl<'a> FrameBuffer<'a> {
/// Creates a new buffer with a [`&[u8]`]. /// Creates a new buffer with a [`&[u8]`].
#[must_use] #[must_use]
#[inline]
pub fn new(buffer: Cow<'a, [u8]>, metadata: Option<Metadata>) -> Self { pub fn new(buffer: Cow<'a, [u8]>, metadata: Option<Metadata>) -> Self {
Self { buffer, metadata } Self { buffer, metadata }
} }
#[must_use]
pub fn from_buffer(buffer: &'a [u8], metadata: Option<Metadata>) -> Self {
FrameBuffer {
buffer: Cow::Borrowed(buffer),
metadata,
}
}
#[must_use]
pub fn from_cow(buffer: Cow<'a, [u8]>, metadata: Option<Metadata>) -> Self {
FrameBuffer { buffer, metadata }
}
#[must_use]
pub fn from_vec(buffer: Vec<u8>, metadata: Option<Metadata>) -> Self {
FrameBuffer {
buffer: Cow::Owned(buffer),
metadata,
}
}
/// Get the data of this buffer. /// Get the data of this buffer.
#[must_use] #[must_use]
pub fn buffer(&'a self) -> &'a [u8] { pub fn buffer(&'a self) -> &'a [u8] {
@@ -147,22 +167,28 @@ impl Deref for FrameBuffer<'_> {
} }
} }
impl From<Vec<u8>> for FrameBuffer<'_> {
fn from(value: Vec<u8>) -> Self {
let buffer = Cow::Owned(value);
FrameBuffer {
buffer,
metadata: None,
}
}
}
impl<'a> From<&'a [u8]> for FrameBuffer<'a> { impl<'a> From<&'a [u8]> for FrameBuffer<'a> {
fn from(value: &'a [u8]) -> Self { fn from(value: &'a [u8]) -> Self {
let buffer = Cow::Borrowed(value);
FrameBuffer { FrameBuffer {
buffer, buffer: Cow::Borrowed(value),
metadata: None,
}
}
}
impl From<Vec<u8>> for FrameBuffer<'static> {
fn from(value: Vec<u8>) -> Self {
FrameBuffer {
buffer: Cow::Owned(value),
metadata: None,
}
}
}
impl<'a> From<Cow<'a, [u8]>> for FrameBuffer<'a> {
fn from(value: Cow<'a, [u8]>) -> Self {
FrameBuffer {
buffer: value,
metadata: None, metadata: None,
} }
} }
+17 -17
View File
@@ -1,14 +1,14 @@
[package] [package]
name = "nokhwa-decoders" name = "nokhwa-decoders"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
[features] [features]
ffmpeg = [ "ffmpeg-the-third" ] ffmpeg = ["ffmpeg-the-third"]
yuyv = [ "dcv-color-primitives", "yuv" ] yuyv = ["dcv-color-primitives", "yuv"]
mjpeg = [ "zune-jpeg", "zune-core" ] mjpeg = ["zune-jpeg", "zune-core"]
luma = [ "nokhwa-iter-extensions", "itermore" ] luma = ["nokhwa-iter-extensions", "itermore"]
# static = ["ffmpeg-the-third/static"] static = ["ffmpeg-the-third/static"]
#async = [] #async = []
[dependencies] [dependencies]
@@ -16,38 +16,38 @@ bytemuck = "1.23"
[dependencies.nokhwa-core] [dependencies.nokhwa-core]
version = "0.2" version = "0.2"
path = "../nokhwa-core" path = "../nokhwa-core"
[dependencies.ffmpeg-the-third] [dependencies.ffmpeg-the-third]
version = "4.0.0" version = "4.0.0"
optional = true optional = true
[dependencies.yuv] [dependencies.yuv]
version = "0.8" version = "0.8"
optional = true optional = true
[dependencies.dcv-color-primitives] [dependencies.dcv-color-primitives]
version = "0.7" version = "0.7"
optional = true optional = true
[dependencies.zune-jpeg] [dependencies.zune-jpeg]
version = "0.5.0-rc9" version = "0.5.0-rc9"
optional = true optional = true
[dependencies.zune-core] [dependencies.zune-core]
version = "0.5.0-rc2" version = "0.5.0-rc2"
optional = true optional = true
[dependencies.itermore] [dependencies.itermore]
version = "0.8" version = "0.8"
features = [ "array_chunks" ] features = ["array_chunks"]
optional = true optional = true
[dependencies.nokhwa-iter-extensions] [dependencies.nokhwa-iter-extensions]
version = "0.1" version = "0.1"
path = "../nokhwa-iter-extensions" path = "../nokhwa-iter-extensions"
optional = true optional = true
[dev-dependencies.image] [dev-dependencies.image]
workspace = true workspace = true
features = [ "png", "jpeg", "avif" ] features = ["png", "jpeg", "avif"]
+232 -43
View File
@@ -3,8 +3,8 @@ use ffmpeg_the_third::codec::{Context, Id};
use ffmpeg_the_third::color::{Range, Space}; use ffmpeg_the_third::color::{Range, Space};
use ffmpeg_the_third::decoder::{Video, find}; use ffmpeg_the_third::decoder::{Video, find};
use ffmpeg_the_third::ffi::{ use ffmpeg_the_third::ffi::{
AVCodecID, AVCodecParameters, AVPacketSideData, AVPixelFormat, av_frame_alloc, AVCodecID, AVCodecParameters, AVMediaType, AVPacketSideData, AVPixelFormat, AVRational,
av_image_fill_arrays, av_packet_side_data_free, avcodec_parameters_alloc, av_frame_alloc, av_image_fill_arrays, av_packet_side_data_free, avcodec_parameters_alloc,
avcodec_parameters_free, avcodec_parameters_free,
}; };
use ffmpeg_the_third::format::Pixel as FfmpegPixel; use ffmpeg_the_third::format::Pixel as FfmpegPixel;
@@ -53,8 +53,20 @@ fn create_video(config: &FfmpegConfig) -> Result<Video, NokhwaError> {
)) ))
})?; })?;
let frame_rate = AVRational {
num: config.frame_rate.numerator(),
den: config.frame_rate.denominator(),
};
let codec_i32 = unsafe { transmute::<AVCodecID, i32>(AVCodecID::from(id)) };
let intermediate_config = IntermediateDecoderConfig {
config: config.ffmpeg_codec_low_level.clone(),
resolution: config.resolution,
frame_rate,
format: codec_i32,
};
video video
.set_parameters(config.ffmpeg_codec_low_level.clone()) .set_parameters(intermediate_config)
.map_err(|why| NokhwaError::DecoderInvalidConfiguration(why.to_string()))?; .map_err(|why| NokhwaError::DecoderInvalidConfiguration(why.to_string()))?;
let threading_kind = config.parallelism.behavior; let threading_kind = config.parallelism.behavior;
@@ -120,12 +132,8 @@ pub struct FfmpegOutputMeta<'a> {
pub timestamp: Option<i64>, pub timestamp: Option<i64>,
pub pts: Option<i64>, pub pts: Option<i64>,
pub is_key: bool,
pub is_corrupt: bool, pub is_corrupt: bool,
pub is_empty: bool, pub is_empty: bool,
pub is_top_first: bool,
pub is_interlaced: bool,
pub has_palatte_changed: bool,
pub color_space: Space, pub color_space: Space,
pub color_range: Range, pub color_range: Range,
@@ -144,19 +152,25 @@ pub struct FfmpegDecoder {
decoder: Video, decoder: Video,
sws: ScalerContext, sws: ScalerContext,
config: FfmpegConfig, config: FfmpegConfig,
last_used_format: FfmpegPixel, last_used_out_format: FfmpegPixel,
last_used_in_format: FfmpegPixel,
} }
impl FfmpegDecoder { impl FfmpegDecoder {
pub fn new(config: FfmpegConfig) -> Result<Self, NokhwaError> { pub fn new(config: FfmpegConfig) -> Result<Self, NokhwaError> {
let decoder = create_video(&config)?; let decoder = create_video(&config)?;
let sws = create_sws(&config, decoder.format(), decoder.format())?; let last_used_in_format = match decoder.format() {
let last_used_format = decoder.format(); FfmpegPixel::None => FfmpegPixel::RGB24,
px => px,
};
let last_used_out_format = FfmpegPixel::RGB24;
let sws = create_sws(&config, last_used_in_format, last_used_out_format)?;
Ok(FfmpegDecoder { Ok(FfmpegDecoder {
decoder, decoder,
sws, sws,
config, config,
last_used_format, last_used_out_format,
last_used_in_format,
}) })
} }
@@ -187,8 +201,12 @@ impl Decoder for FfmpegDecoder {
fn set_config(&mut self, config: Self::Config) -> Result<(), NokhwaError> { fn set_config(&mut self, config: Self::Config) -> Result<(), NokhwaError> {
self.decoder = create_video(&config)?; self.decoder = create_video(&config)?;
self.sws = create_sws(&config, self.decoder.format(), self.last_used_format)?; let last_used_in_format = match self.decoder.format() {
FfmpegPixel::None => FfmpegPixel::RGB24,
px => px,
};
self.sws = create_sws(&config, last_used_in_format, self.last_used_out_format)?;
self.last_used_in_format = last_used_in_format;
self.config = config; self.config = config;
Ok(()) Ok(())
} }
@@ -202,9 +220,6 @@ impl Decoder for FfmpegDecoder {
let buffer = buffer.as_mut(); let buffer = buffer.as_mut();
let dest_as_ffmpeg = convert_destination_pixel_format_to_av_pxfmt(destination_format); let dest_as_ffmpeg = convert_destination_pixel_format_to_av_pxfmt(destination_format);
if self.last_used_format != dest_as_ffmpeg {
self.sws = create_sws(&self.config, self.decoder.format(), self.last_used_format)?;
}
let packet = Packet::borrow(to_decode.buffer()); let packet = Packet::borrow(to_decode.buffer());
self.decoder self.decoder
@@ -216,9 +231,14 @@ impl Decoder for FfmpegDecoder {
self.decoder.width(), self.decoder.width(),
self.decoder.width(), self.decoder.width(),
); );
self.decoder
.receive_frame(&mut frame) if let Err(why) = self.decoder.receive_frame(&mut frame) {
.map_err(|why| NokhwaError::Decoder(why.to_string()))?; if let ffmpeg_the_third::util::error::Error::Other { errno: 11 } = why {
return Err(NokhwaError::DecoderNeedsMoreData(why.to_string()));
} else {
return Err(NokhwaError::Decoder(why.to_string()));
}
}
let receiver_avframe = unsafe { av_frame_alloc() }; let receiver_avframe = unsafe { av_frame_alloc() };
let dest_resolution = self let dest_resolution = self
@@ -226,10 +246,10 @@ impl Decoder for FfmpegDecoder {
.ffmpeg_scaler_low_level .ffmpeg_scaler_low_level
.destionation_resolution .destionation_resolution
.unwrap_or(self.config.resolution); .unwrap_or(self.config.resolution);
let av_pixel_format: AVPixelFormat = dest_as_ffmpeg.into();
unsafe { unsafe {
(*receiver_avframe).width = dest_resolution.width() as i32; (*receiver_avframe).width = dest_resolution.width() as i32;
(*receiver_avframe).height = dest_resolution.height() as i32; (*receiver_avframe).height = dest_resolution.height() as i32;
let av_pixel_format: AVPixelFormat = dest_as_ffmpeg.into();
(*receiver_avframe).format = av_pixel_format as i32; (*receiver_avframe).format = av_pixel_format as i32;
} }
let imgbuf = unsafe { let imgbuf = unsafe {
@@ -237,7 +257,7 @@ impl Decoder for FfmpegDecoder {
(&mut (*receiver_avframe).data) as *mut *mut u8, (&mut (*receiver_avframe).data) as *mut *mut u8,
(&mut (*receiver_avframe).linesize) as *mut i32, (&mut (*receiver_avframe).linesize) as *mut i32,
buffer.as_ptr(), buffer.as_ptr(),
self.decoder.format().into(), av_pixel_format,
dest_resolution.width() as i32, dest_resolution.width() as i32,
dest_resolution.height() as i32, dest_resolution.height() as i32,
1, 1,
@@ -250,19 +270,31 @@ impl Decoder for FfmpegDecoder {
} }
let mut receiver_frame = unsafe { frame::Video::wrap(receiver_avframe) }; let mut receiver_frame = unsafe { frame::Video::wrap(receiver_avframe) };
// remake swscontext in case we are being gooned
let new_in_format = match frame.format() {
FfmpegPixel::None => {
return Err(NokhwaError::Decoder(
"Received None format from ffmpeg buffer. Invalid - cannot use sws".to_string(),
));
}
fmt => fmt,
};
if new_in_format != self.last_used_in_format
|| receiver_frame.format() != self.last_used_out_format
{
self.sws = create_sws(&self.config, new_in_format, receiver_frame.format())?;
self.last_used_in_format = new_in_format;
self.last_used_out_format = receiver_frame.format();
}
self.sws self.sws
.run(&frame, &mut receiver_frame) .run(&frame, &mut receiver_frame)
.map_err(|why| NokhwaError::Decoder(why.to_string()))?; .map_err(|why| NokhwaError::Decoder(why.to_string()))?;
let metadata = receiver_frame.metadata().to_owned(); let metadata = receiver_frame.metadata().to_owned();
let timestamp = receiver_frame.timestamp(); let timestamp = receiver_frame.timestamp();
let pts = receiver_frame.pts(); let pts = receiver_frame.pts();
let is_key = receiver_frame.is_key();
let is_corrupt = receiver_frame.is_corrupt(); let is_corrupt = receiver_frame.is_corrupt();
let is_empty = unsafe { receiver_frame.is_empty() }; let is_empty = unsafe { receiver_frame.is_empty() };
let is_top_first = receiver_frame.is_top_first();
let is_interlaced = receiver_frame.is_interlaced();
let has_palatte_changed = receiver_frame.has_palette_changed();
let color_space = receiver_frame.color_space(); let color_space = receiver_frame.color_space();
let color_range = receiver_frame.color_range(); let color_range = receiver_frame.color_range();
let color_primaries = receiver_frame.color_primaries(); let color_primaries = receiver_frame.color_primaries();
@@ -278,12 +310,8 @@ impl Decoder for FfmpegDecoder {
metadata, metadata,
timestamp, timestamp,
pts, pts,
is_key,
is_corrupt, is_corrupt,
is_empty, is_empty,
is_top_first,
is_interlaced,
has_palatte_changed,
color_space, color_space,
color_range, color_range,
color_primaries, color_primaries,
@@ -408,6 +436,7 @@ where
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct FfmpegDecoderConfig { pub struct FfmpegDecoderConfig {
pub codec_tag: Option<u32>,
pub bit_rate: Option<i64>, pub bit_rate: Option<i64>,
pub profile: Option<i32>, pub profile: Option<i32>,
pub level: Option<i32>, pub level: Option<i32>,
@@ -425,53 +454,71 @@ pub struct FfmpegDecoderConfig {
pub extra_data: Option<SideData<u8>>, pub extra_data: Option<SideData<u8>>,
} }
impl AsPtr<AVCodecParameters> for FfmpegDecoderConfig { #[derive(Clone, Debug)]
struct IntermediateDecoderConfig {
pub(crate) config: FfmpegDecoderConfig,
pub(crate) resolution: Resolution,
pub(crate) frame_rate: AVRational,
pub(crate) format: i32,
}
impl AsPtr<AVCodecParameters> for IntermediateDecoderConfig {
fn as_ptr(&self) -> *const AVCodecParameters { fn as_ptr(&self) -> *const AVCodecParameters {
let parameters = unsafe { avcodec_parameters_alloc() }; let parameters = unsafe { avcodec_parameters_alloc() };
unsafe { unsafe {
if let Some(bit_rate) = self.bit_rate { (*parameters).width = self.resolution.width() as i32;
(*parameters).height = self.resolution.height() as i32;
(*parameters).format = self.format;
(*parameters).codec_type = AVMediaType::AVMEDIA_TYPE_VIDEO;
(*parameters).framerate = self.frame_rate;
if let Some(codec_tag) = self.config.codec_tag {
(*parameters).codec_tag = codec_tag;
}
if let Some(bit_rate) = self.config.bit_rate {
(*parameters).bit_rate = bit_rate; (*parameters).bit_rate = bit_rate;
} }
if let Some(profile) = self.profile { if let Some(profile) = self.config.profile {
(*parameters).profile = profile; (*parameters).profile = profile;
} }
if let Some(level) = self.level { if let Some(level) = self.config.level {
(*parameters).level = level; (*parameters).level = level;
} }
if let Some(aspect_ratio) = self.aspect_ratio { if let Some(aspect_ratio) = self.config.aspect_ratio {
(*parameters).sample_aspect_ratio = aspect_ratio.into(); (*parameters).sample_aspect_ratio = aspect_ratio.into();
} }
if let Some(field_order) = self.field_order { if let Some(field_order) = self.config.field_order {
(*parameters).field_order = field_order.into(); (*parameters).field_order = field_order.into();
} }
if let Some(color_range) = self.color_range { if let Some(color_range) = self.config.color_range {
(*parameters).color_range = color_range.into(); (*parameters).color_range = color_range.into();
} }
if let Some(color_primaries) = self.color_primaries { if let Some(color_primaries) = self.config.color_primaries {
(*parameters).color_primaries = color_primaries.into(); (*parameters).color_primaries = color_primaries.into();
} }
if let Some(color_transfer) = self.color_transfer_characteristics { if let Some(color_transfer) = self.config.color_transfer_characteristics {
(*parameters).color_trc = color_transfer.into(); (*parameters).color_trc = color_transfer.into();
} }
if let Some(chroma_location) = self.chroma_location { if let Some(chroma_location) = self.config.chroma_location {
(*parameters).chroma_location = chroma_location.into(); (*parameters).chroma_location = chroma_location.into();
} }
if let Some(coded_side_data) = self.coded_side_data { if let Some(coded_side_data) = self.config.coded_side_data {
(*parameters).coded_side_data = coded_side_data.pointer.as_ptr(); (*parameters).coded_side_data = coded_side_data.pointer.as_ptr();
(*parameters).nb_coded_side_data = coded_side_data.length as i32; (*parameters).nb_coded_side_data = coded_side_data.length as i32;
} }
if let Some(extra_data) = self.extra_data { if let Some(extra_data) = self.config.extra_data {
(*parameters).extradata = extra_data.pointer.as_ptr(); (*parameters).extradata = extra_data.pointer.as_ptr();
(*parameters).extradata_size = extra_data.length as i32; (*parameters).extradata_size = extra_data.length as i32;
} }
@@ -604,4 +651,146 @@ const fn is_little_endian() -> bool {
} }
#[cfg(test)] #[cfg(test)]
mod test {} mod test {
use ffmpeg_the_third::{codec::Context, format::input, media::Type, threading::Config};
use image::{ImageFormat, Rgb};
use nokhwa_core::{
decoder::Decoder,
frame_buffer::FrameBuffer,
frame_format::FrameFormat,
types::{FrameRate, Resolution},
};
use crate::ffmpeg::{
FfmpegConfig, FfmpegDecoder, FfmpegDecoderConfig, FfmpegScalerConfig, Parallelism,
};
#[test]
pub fn test_h264() {
ffmpeg_the_third::init().unwrap();
let file = "test_images/ffmpeg/h264/test.h264";
let output_dir = "test_images/ffmpeg/h264/out";
let decoder_cfg = FfmpegConfig {
custom_frame_format_map: None,
frame_format: FrameFormat::AVC1,
resolution: Resolution::new(498, 348),
frame_rate: FrameRate::from_fps(30),
parallelism: Parallelism::default(),
ffmpeg_codec_low_level: FfmpegDecoderConfig::default(),
ffmpeg_scaler_low_level: FfmpegScalerConfig::default(),
side_data_check_list: Vec::default(),
};
let mut decoder = FfmpegDecoder::new(decoder_cfg).unwrap();
let mut ictx = input(file).unwrap();
for maybe_frame in ictx.packets() {
let (_stream, packet) = maybe_frame.unwrap();
let decoded =
decoder.decode::<Rgb<u8>>(FrameBuffer::from_buffer(packet.data().unwrap(), None));
match decoded {
Ok(decoded) => {
let index = packet.position();
decoded
.save_with_format(format!("{output_dir}/{index}.png"), ImageFormat::Png)
.unwrap();
}
Err(why) => {
if why.is_needs_more() {
continue;
} else {
panic!("aaa {why}");
}
}
}
}
}
#[test]
pub fn test_h265() {
ffmpeg_the_third::init().unwrap();
let file = "test_images/ffmpeg/h265/out.h265";
let output_dir = "test_images/ffmpeg/h265/out";
let decoder_cfg = FfmpegConfig {
custom_frame_format_map: None,
frame_format: FrameFormat::H265,
resolution: Resolution::new(498, 348),
frame_rate: FrameRate::from_fps(30),
parallelism: Parallelism::default(),
ffmpeg_codec_low_level: FfmpegDecoderConfig::default(),
ffmpeg_scaler_low_level: FfmpegScalerConfig::default(),
side_data_check_list: Vec::default(),
};
let mut decoder = FfmpegDecoder::new(decoder_cfg).unwrap();
let mut ictx = input(file).unwrap();
for maybe_frame in ictx.packets() {
let (_stream, packet) = maybe_frame.unwrap();
let decoded =
decoder.decode::<Rgb<u8>>(FrameBuffer::from_buffer(packet.data().unwrap(), None));
match decoded {
Ok(decoded) => {
let index = packet.position();
decoded
.save_with_format(format!("{output_dir}/{index}.png"), ImageFormat::Png)
.unwrap();
}
Err(why) => {
if why.is_needs_more() {
continue;
} else {
panic!("aaa {why}");
}
}
}
}
}
#[test]
pub fn test_av1() {
ffmpeg_the_third::init().unwrap();
let file = "test_images/ffmpeg/av1/test.ivf";
let output_dir = "test_images/ffmpeg/av1/out";
let decoder_cfg = FfmpegConfig {
custom_frame_format_map: None,
frame_format: FrameFormat::AV1,
resolution: Resolution::new(320, 320),
frame_rate: FrameRate::from_fps(10),
parallelism: Parallelism::default(),
ffmpeg_codec_low_level: FfmpegDecoderConfig::default(),
ffmpeg_scaler_low_level: FfmpegScalerConfig::default(),
side_data_check_list: Vec::default(),
};
let mut decoder = FfmpegDecoder::new(decoder_cfg).unwrap();
let mut ictx = input(file).unwrap();
for maybe_frame in ictx.packets() {
let (_stream, packet) = maybe_frame.unwrap();
let decoded =
decoder.decode::<Rgb<u8>>(FrameBuffer::from_buffer(packet.data().unwrap(), None));
match decoded {
Ok(decoded) => {
let index = packet.position();
decoded
.save_with_format(format!("{output_dir}/{index}.png"), ImageFormat::Png)
.unwrap();
}
Err(why) => {
if why.is_needs_more() {
continue;
} else {
panic!("aaa {why}");
}
}
}
}
}
}
+2 -2
View File
@@ -1,8 +1,8 @@
#[cfg(feature = "ffmpeg")] #[cfg(feature = "ffmpeg")]
pub mod ffmpeg; pub mod ffmpeg;
#[cfg(feature = "luma")]
pub mod luma;
#[cfg(feature = "mjpeg")] #[cfg(feature = "mjpeg")]
pub mod mjpeg; pub mod mjpeg;
#[cfg(feature = "yuyv")] #[cfg(feature = "yuyv")]
pub mod yuv; pub mod yuv;
#[cfg(feature = "luma")]
pub mod luma;
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Some files were not shown because too many files have changed in this diff Show More