Skip to content

Commit 7ac57a4

Browse files
committed
opt code
1 parent 8f3c438 commit 7ac57a4

File tree

5 files changed

+159
-41
lines changed

5 files changed

+159
-41
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
则执行下面的命令即可,会得到一个`IMG_.MOV`的合并后的视频文件。
1212

1313
```
14-
ffmpeg-tool-rs combine -r IMG_\(\.\*\).MOV --reg-file-start=1767 --reg-file-end=1768
14+
ffmpeg-tool-rs combine -r IMG_\(\.\*\).MOV --reg-file-start=1767 --reg-file-end=1768 --same_param_index=1 --target_file_name=2222.mp4
1515
```
1616

1717
当然也可以指定生成后的文件名,需要跟上`--target_file_name=your_filename.MOV`
@@ -20,7 +20,7 @@ ffmpeg-tool-rs combine -r IMG_\(\.\*\).MOV --reg-file-start=1767 --reg-file-end=
2020
### 下载视频
2121

2222
```
23-
ffmpeg-tool-rs download --url=https://zmis.me/xxx.m3u8 --fast --folder=1222
23+
ffmpeg-tool-rs download --url=https://zmis.me/xxx.m3u8 --folder=1222
2424
```
2525

2626
### 截取视频

src/cmd.rs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ use serde::{Deserialize, Serialize};
33

44
#[derive(Debug, Deserialize, Serialize)]
55
pub struct VideoInfo {
6-
width: i32,
7-
height: i32,
8-
duration: i32, //毫秒
9-
video_rate: i32,
10-
audio_rate: i32,
11-
fps: f32,
6+
pub width: i32,
7+
pub height: i32,
8+
pub duration: i32, //毫秒
9+
pub video_rate: i32,
10+
pub audio_rate: i32,
11+
pub fps: f32,
1212
}
1313

1414
#[derive(Debug, Deserialize, Serialize)]
@@ -72,7 +72,7 @@ impl From<Ffprobe> for VideoInfo {
7272
pub mod cmd {
7373
use crate::cmd::{Ffprobe, VideoInfo};
7474
use std::env;
75-
use std::fmt::Error;
75+
use std::fmt::{format, Error};
7676
use std::fs::{self};
7777
use std::path::Path;
7878
use std::process::Command;
@@ -109,10 +109,10 @@ pub mod cmd {
109109
let clear_ext = vec!["ts", "m3u8", "txt"];
110110
let path_str = format!("./{}", folder_name.to_owned());
111111
let dir_path = Path::new(path_str.as_str());
112-
println!("now path {}, pass dir {}", current_dir.as_os_str().to_str().unwrap(), dir_path.clone());
112+
println!("now path {}, pass dir {:?}", current_dir.as_os_str().to_str().unwrap(), dir_path);
113113

114114
if !dir_path.is_dir() {
115-
println!("-----path: {} is not dir", dir_path.clone());
115+
println!("-----path: {:?} is not dir", dir_path);
116116
return false;
117117
}
118118
for i in clear_ext {
@@ -165,6 +165,37 @@ pub mod cmd {
165165
.status;
166166
if res.success() {
167167
Ok(true)
168+
} else {
169+
println!("ffmpeg error---{}", res.to_string());
170+
Ok(false)
171+
}
172+
}
173+
174+
// ffmpeg -i input.mp4 -b:v <视频码率> -b:a <音频码率> -r <帧率> output.mp4
175+
// ffmpeg -i input.mp4 -vf "scale=1280:720" -b:v 1500k -b:a 192k -r 30 -c:v libx264 -c:a aac output.mp4
176+
pub fn transcode_video_to_spec_params(file: String, target: String, a_b: i32, v_b: i32, fps: i32, width: i32, height: i32) -> Result<bool, Error> {
177+
let mut binding = Command::new("ffmpeg");
178+
let res = binding
179+
.arg("-i")
180+
.arg(file)
181+
.arg("-vf")
182+
.arg(format!("scale={}:{}", width, height))
183+
.arg("-b:v")
184+
.arg(v_b.to_string())
185+
.arg("-b:a")
186+
.arg(a_b.to_string())
187+
.arg("-r")
188+
.arg(fps.to_string())
189+
.arg("-c:v")
190+
.arg("libx264".to_string())
191+
.arg("-c:a")
192+
.arg("aac".to_string())
193+
.arg(target)
194+
.output()
195+
.unwrap()
196+
.status;
197+
if res.success() {
198+
Ok(true)
168199
} else {
169200
println!("{}", res.to_string());
170201
Ok(false)

src/combine.rs

Lines changed: 98 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
pub mod parse {
2-
use crate::cmd::cmd::{combine, combine_ts};
2+
use crate::cmd::cmd::{clear_temp_files, combine, combine_ts, get_video_info, transcode_video_to_spec_params};
33
use crate::common::now;
44
use crate::m3u8::HlsM3u8Method;
55
use openssl::symm::{decrypt, Cipher};
66
use std::fmt::Error;
77
use std::fs::File;
88
use std::io::prelude::*;
9+
use clap::builder::TypedValueParser;
10+
use reqwest::header::COOKIE;
911
use tempfile::tempdir;
1012

1113
pub fn get_reg_files(
@@ -59,18 +61,103 @@ pub mod parse {
5961
set_a_b: i32,
6062
set_v_b: i32,
6163
set_fps: i32,
64+
set_width: i32,
65+
set_height: i32,
6266
) -> Result<bool, Error> {
63-
white_to_files(files.clone(), file_name.clone()).expect("写入文件失败");
64-
if same_param_index == -1 && set_a_b == 0 && set_v_b == 0 && set_fps == 0 {
67+
if same_param_index == -1 && set_a_b == 0 && set_v_b == 0 && set_fps == 0
68+
&& set_width == 0 && set_height == 0 {
69+
white_to_files(files.clone(), file_name.clone()).expect("写入文件失败");
6570
return combine(file_name.clone(), target_file_name);
6671
}
67-
let mut audit_b = set_a_b;
68-
let mut video_b = set_v_b;
69-
let mut fps = set_fps;
70-
if same_param_index != -1 {}
72+
// 如果不指定视频参数相同的索引,那么就按照传过来的参数处理
73+
let mut a_b = 128000; // audio bitrate
74+
let mut v_b = 1200000; // video bitrate
75+
let mut fps = 30; // fps
76+
let mut width = 1280; // width
77+
let mut height = 720; // height
78+
if same_param_index != -1 {
79+
let info = get_video_info(&files.get(same_param_index as usize).unwrap().to_string());
80+
match info {
81+
Some(data_info) => {
82+
if data_info.audio_rate > 0 {
83+
a_b = data_info.audio_rate;
84+
}
85+
if data_info.fps > 0.0 {
86+
fps = data_info.fps as i32;
87+
}
88+
if data_info.video_rate > 0 {
89+
v_b = data_info.video_rate;
90+
}
91+
if data_info.width > 0 {
92+
width = data_info.width;
93+
}
94+
if data_info.height > 0 {
95+
height = data_info.height;
96+
}
97+
}
98+
None => {
99+
return Ok(false)
100+
}
101+
}
102+
} else {
103+
if set_a_b > 0 {
104+
a_b = set_a_b;
105+
}
106+
if set_fps > 0 {
107+
fps = set_fps;
108+
}
109+
if set_v_b > 0 {
110+
v_b = set_v_b;
111+
}
112+
if set_width > 0 {
113+
width = set_width
114+
}
115+
if set_height > 0 {
116+
height = set_height
117+
}
118+
}
119+
println!("ab {} vb {} fps {} width {} height {}", a_b, v_b, fps, width, height);
120+
transcode_videos_to_same_params(files.clone(), file_name.clone(), target_file_name, a_b, v_b, fps, width, height)
121+
}
122+
123+
// cargo run -- combine -r="/Users/meow.zang/RustroverProjects/ffmpeg-tool-rs/images/video/(.*).mp4" --reg-file-start=1 --reg-file-end=2 --same_param_index=1
124+
fn transcode_videos_to_same_params(files: Vec<String>, file: String, target: String, a_b: i32, v_b: i32, fps: i32, width: i32, height: i32) -> Result<bool, Error> {
125+
let mut index: i32 = 0;
126+
let mut result_files = vec![];
127+
// 先将ts文件转成mp4
128+
for i in files.clone() {
129+
let file_name = format!("_temp_{}.mp4", index);
130+
result_files.push(file_name.clone());
131+
let _ = transcode_video_to_spec_params(i.clone(), file_name.clone(), a_b, v_b, fps, width, height);
132+
index += 1;
133+
}
134+
// 在将mp4文件合并成一个文件
135+
let combine_res = mp4_files_combine_one(result_files.clone(), file, target);
136+
match combine_res {
137+
Ok(data) => {
138+
if data {
139+
// 清除文件
140+
let _ = clear_temp_video_files(result_files.clone());
141+
}
142+
Ok(data)
143+
}
144+
Err(e) => {
145+
Err(e)
146+
}
147+
}
148+
}
149+
150+
// 清理_temp_.mp4开头的文件
151+
fn clear_temp_video_files(files: Vec<String>) -> Result<bool, Error> {
71152
Ok(true)
72153
}
73154

155+
fn mp4_files_combine_one(mp4_files: Vec<String>, file: String, target: String) -> Result<bool, Error> {
156+
println!("file {}, target {}", file.clone(), target.clone());
157+
white_to_files(mp4_files.clone(), file.clone()).expect("写入文件失败");
158+
combine(file.clone(), target)
159+
}
160+
74161
async fn combine_without_crypto(
75162
reg_name: String,
76163
reg_start: i32,
@@ -149,7 +236,7 @@ pub mod parse {
149236
start_se as u8,
150237
&i,
151238
)
152-
.await;
239+
.await;
153240
start_se += 1;
154241
}
155242
return combine_without_crypto(
@@ -158,7 +245,7 @@ pub mod parse {
158245
reg_end,
159246
target_name,
160247
)
161-
.await;
248+
.await;
162249
}
163250

164251
pub async fn handle_combine_ts(
@@ -182,7 +269,7 @@ pub mod parse {
182269
iv.clone(),
183270
sequence,
184271
)
185-
.await
272+
.await
186273
}
187274
Some(HlsM3u8Method::SampleAes) => {
188275
println!("simple aes");
@@ -195,7 +282,7 @@ pub mod parse {
195282
iv.clone(),
196283
sequence,
197284
)
198-
.await
285+
.await
199286
}
200287
None => {
201288
println!("no crypto");

src/download.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,6 @@ impl BaseInfo {
5050
}
5151
}
5252

53-
// pub fn read_base_info(file_name: String) -> Result<BaseInfo, dyn std::error::Error> {
54-
// let mut file = std::fs::File::open(file_name.clone())?;
55-
// let mut contents = String::new();
56-
// file.read_to_string(&mut contents)?;
57-
//
58-
// // 使用 serde_json 來解析 JSON
59-
// return serde_json::from_str(&contents)?;
60-
// }
61-
6253
fn read_base_info(file_name: &str) -> Result<BaseInfo, std::io::Error> {
6354
let path = std::path::Path::new(file_name);
6455
let mut file = std::fs::File::open(path)?;

src/main.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,29 @@ pub struct CombineArgs {
7171
#[arg(long = "target_file_name", default_value_t = String::from(""))]
7272
target_file_name: String,
7373

74-
/// 相同视频参数,如果指定,则根据指定视频的视频码率、音频码率、fps进行合并, 则后面set开头的参数均被覆盖
74+
/// 相同视频参数,如果指定,则根据指定视频的视频码率、音频码率、fps进行合并, 则后面set开头的参数均被覆盖, 从0开始
7575
#[arg(long = "same_param_index", default_value_t = - 1)]
7676
same_param_index: i32,
7777

7878
/// 指定fps
7979
#[arg(long = "set_fps", default_value_t = 0)]
8080
set_fps: i32,
8181

82-
/// 指定音频码率, audio bitrate
82+
/// 指定音频码率, audio bitrate,单位:k
8383
#[arg(long = "set_a_b", default_value_t = 0)]
8484
set_a_b: i32,
8585

86-
/// 指定视频码率, video bitrate
86+
/// 指定视频码率, video bitrate,单位:k
8787
#[arg(long = "set_v_b", default_value_t = 0)]
8888
set_v_b: i32,
89+
90+
/// 指定视频高度,单位:k
91+
#[arg(long = "set_height", default_value_t = 0)]
92+
set_height: i32,
93+
94+
/// 指定视频宽度,单位:k
95+
#[arg(long = "set_width", default_value_t = 0)]
96+
set_width: i32,
8997
}
9098

9199
#[derive(clapArgs)]
@@ -94,9 +102,9 @@ pub struct DownloadArgs {
94102
#[arg(long = "url", default_value_t = String::from(""))]
95103
url: String,
96104

97-
/// 设置为true则会优化加速下载
98-
#[arg(long = "fast")]
99-
fast: bool,
105+
/// 使用ffmpeg下载
106+
#[arg(long = "ffmpeg_download")]
107+
ffmpeg_download: bool,
100108

101109
/// 输出的文件名
102110
#[arg(long = "target_file_name", default_value_t = String::from(""))]
@@ -142,6 +150,8 @@ pub async fn main() {
142150
args.set_a_b,
143151
args.set_v_b,
144152
args.set_fps,
153+
args.set_width,
154+
args.set_height,
145155
)
146156
.expect("合并文件失败");
147157
if res {
@@ -182,8 +192,7 @@ pub async fn main() {
182192
let file_name = get_file_name(args.target_file_name.to_owned());
183193
println!("download file name: {}", file_name.clone());
184194
let res;
185-
if args.fast {
186-
println!("now is fast mod");
195+
if !args.ffmpeg_download {
187196
match create_folder(folder_name.clone()) {
188197
Ok(dir_status) => {
189198
if dir_status {
@@ -216,8 +225,8 @@ pub async fn main() {
216225
return;
217226
}
218227
}
219-
_ => {
220-
println!("出错");
228+
Err(e) => {
229+
println!("出错,{}", e);
221230
return;
222231
}
223232
}

0 commit comments

Comments
 (0)