Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support trick play and gif exportion #26

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ class MVYEffectView: UIView {
switch decoderWorkType.type {
case .normal, .reverse:
slowPlayProgressView(isHidden: true)
case .slow:
case .slow, .fast:
slowPlayProgressView(isHidden: false)
slowPlayProgressView?.update(decoderWorkType: decoderWorkType)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class MVYEffectViewController: UIViewController {
// 显示第一帧
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
switch self.decoderWorkType.type {
case .normal, .slow:
case .normal, .slow, .fast:
self.videoSeeker?.setSeekTime(0)
case .reverse:
self.videoSeeker?.setSeekTime(self.totalDuration)
Expand Down Expand Up @@ -201,13 +201,17 @@ extension MVYEffectViewController {
func play(startTime: Int64) {
switch decoderWorkType.type {
case .normal:
NSLog("Normal Playing");
videoPlayer?.startPlay(withSeekTime: startTime)

case .reverse:
videoPlayer?.startReversePlay(withSeekTime: startTime)

case .slow:
videoPlayer?.startSlowPlay(withSeekTime: startTime, slowTime: decoderWorkType.slowDecoderRange)

case .fast:
videoPlayer?.startFastPlay(withSeekTime: startTime, slowTime: decoderWorkType.slowDecoderRange)
}
}

Expand Down Expand Up @@ -430,6 +434,11 @@ extension MVYEffectViewController {
if let setDecoderWorkTypeBlock = self.setDecoderWorkTypeBlock {
setDecoderWorkTypeBlock(self.decoderWorkType)
}
} else if effectCell.effectType == -4 {
decoderWorkType.type = .fast
if let setDecoderWorkTypeBlock = self.setDecoderWorkTypeBlock {
setDecoderWorkTypeBlock(self.decoderWorkType)
}
}

effectView!.update(decoderWorkType: decoderWorkType)
Expand Down Expand Up @@ -524,6 +533,14 @@ extension MVYEffectViewController {
data3.effectColor = UIColor.init(red: 0x7c/0xff, green: 0xcf/0xff, blue: 0x30/0xff, alpha: 1)
datas.append(data3)

let data4 = MVYEffectCellModel()
data4.thumbnail = "\(Bundle.main.bundlePath)/TimeEffectResources/icon/慢动作@2x.png"
data4.selectedThumbnail = "\(Bundle.main.bundlePath)/TimeEffectResources/icon/慢动作_selected@2x.png"
data4.text = "快动作"
data4.effectType = -4
data4.effectColor = UIColor.init(red: 0x7c/0xff, green: 0xcf/0xff, blue: 0x30/0xff, alpha: 1)
datas.append(data4)

return datas
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ enum MVYDecoderWokType: Int {
case normal // 正常解码
case reverse // 倒序解码
case slow // 慢速解码
case fast // fast play
}

class MVYDecoderWorkTypeModel {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,10 @@ extension MVYEditViewController {
mediaPlayer?.startReversePlay()

case .slow:
mediaPlayer?.startSlowPlay(withSlowTime: decoderWorkType.slowDecoderRange)
mediaPlayer?.startSlowPlay(withSeekTime: 0, slowTime: NSMakeRange(0, 500));

case .fast:
mediaPlayer?.startFastPlay(withSeekTime: 0, slowTime: NSMakeRange(0, 500));
}

if #available(iOS 10.0, *) { // 打开扬声器
Expand Down
118 changes: 110 additions & 8 deletions MVYShortVideoEditorIOS/Page/OutputPage/MVYOutputViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ class MVYOutputViewController: UIViewController {
// 音量处理完成后的原始音频
var volumeOriginAudioPath = ""

// normalized audio path
var normalizedAudioPath = ""

// 剪切完成后的背景音乐
var cutMusicPath = ""

Expand Down Expand Up @@ -115,6 +118,8 @@ class MVYOutputViewController: UIViewController {
self.decoderWorkType = decoderWorkType

self.effectProcessBlock = effectProcessBlock

self.decoderWorkType = decoderWorkType
}

override func viewDidLoad() {
Expand Down Expand Up @@ -174,13 +179,16 @@ extension MVYOutputViewController: MVYVideoDecoderDelegate, MVYAudioDecoderDeleg

switch decoderWorkType.type {
case .normal:
videoDecoder.startDecode(withSeekTime: 0)
videoDecoder.startDecode(withSeekTime: 0, withSpeed:1.0)

case .reverse:
videoDecoder.startReverseDecode(withSeekTime: 0)

case .slow:
videoDecoder.startSlowDecode(withSeekTime: 0, slowTime: decoderWorkType.slowDecoderRange)
videoDecoder.startDecode(withSeekTime: 0, withSpeed: 2.0)

case .fast:
videoDecoder.startDecode(withSeekTime: 0, withSpeed: 0.5)
}
}

Expand All @@ -191,7 +199,7 @@ extension MVYOutputViewController: MVYVideoDecoderDelegate, MVYAudioDecoderDeleg
case .normal, .reverse:
audioDecoder.startDecode(withSeekTime: 0)

case .slow:
case .slow, .fast:
audioDecoder.startSlowDecode(withSeekTime: 0, slowTime: decoderWorkType.slowDecoderRange)
}

Expand Down Expand Up @@ -359,6 +367,43 @@ extension MVYOutputViewController {
}
}

private func fastSlowAudio(inputAudioPath:String){
let uuid = UUID().uuidString.filter { (c) -> Bool in return c != "-" }
let audioFileName = "\(uuid).wav"
let audioPath = "\(NSTemporaryDirectory())\(audioFileName)"
var speed = "\(1.0)"
if decoderWorkType.type == .slow{
NSLog("Set audio speed 0.5")
speed = "\(0.5)"
}
else if decoderWorkType.type == .fast{
NSLog("Set audio speed 2.0")
speed = "\(2.0)"
}

let fastSlowCMD = MVYFFmpegCMD.adjustSpeedCMD(withSpeed: speed, inputAudioPath: inputAudioPath, outputAudioPath: audioPath)
NSLog("Ajust audio speed")
MVYFFmpegCMD.exec(fastSlowCMD){ (result) in

NSLog("Ajust Audio speed return %d", result)

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
if result == 0 {
self.normalizedAudioPath = audioPath
self.audioNextStepProcess()

} else {
MBProgressHUD.hide(for: self.view, animated: true)
let alert = UIAlertController.init(title: "错误", message: "audio speed ajust", preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "取消", style: .cancel, handler: { (action) in
self.dismiss(animated: true , completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
}
}
}

// 音量调节
private func setOriginAudioVolume(inputAudioPath:String) {

Expand Down Expand Up @@ -522,6 +567,31 @@ extension MVYOutputViewController {
}
}

private func exportGif(inputVideoPath:String){
let uuid = UUID().uuidString.filter { (c) -> Bool in return c != "-" }
let gifName = "\(uuid).gif"
let gifPath = "\(NSTemporaryDirectory())\(gifName)"
let cmd = MVYFFmpegCMD.exportGifCMD(withInputVideoPath: inputVideoPath, outputGifPath: gifPath)
NSLog("Export gif from video \(cmd!)")
MVYFFmpegCMD.exec(cmd) { (result) in

NSLog("export gif result: %d", result)

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
if result == 0 {
NSLog("export gif success")
} else {
MBProgressHUD.hide(for: self.view, animated: true)
let alert = UIAlertController.init(title: "错误", message: "export gif ", preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "取消", style: .cancel, handler: { (action) in
self.dismiss(animated: true , completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
}
}
}

// 音频下一步处理
private func audioNextStepProcess() {
if audioPaths.count > 0 {
Expand All @@ -530,22 +600,52 @@ extension MVYOutputViewController {
return
}

if decoderWorkType.type == .slow || decoderWorkType.type == .fast {
if normalizedAudioPath == "" {
NSLog("Ajust audio speed now for concated audio")
fastSlowAudio(inputAudioPath: concatOriginAudioPath)
return
}
else{
NSLog("Audio speed is ajusted already")
}
}
else
{
normalizedAudioPath = concatOriginAudioPath
}

if audioVolume != 1 {
if volumeOriginAudioPath == "" {
setOriginAudioVolume(inputAudioPath: concatOriginAudioPath)
setOriginAudioVolume(inputAudioPath: normalizedAudioPath)
return
}
} else {
volumeOriginAudioPath = concatOriginAudioPath
volumeOriginAudioPath = normalizedAudioPath
}
} else {
if decoderWorkType.type == .slow || decoderWorkType.type == .fast {
if normalizedAudioPath == "" {
NSLog("Ajust audio speed now for the whole audio")
fastSlowAudio(inputAudioPath: audioPaths[0])
return
}
else{
NSLog("Audio speed is ajusted already")
}
}
else
{
normalizedAudioPath = audioPaths[0]
}

if audioVolume != 1 {
if volumeOriginAudioPath == "" {
setOriginAudioVolume(inputAudioPath: audioPaths[0])
setOriginAudioVolume(inputAudioPath: normalizedAudioPath)
return
}
} else {
volumeOriginAudioPath = concatOriginAudioPath
volumeOriginAudioPath = normalizedAudioPath
}
}

Expand All @@ -571,7 +671,9 @@ extension MVYOutputViewController {
} else {
mixAudioPath = volumeOriginAudioPath
}

// demo how to generate the gif file;
exportGif(inputVideoPath: self.videoPaths[0])

// 开始解码
startDecodeVideo()
startDecodeAudio()
Expand Down
6 changes: 6 additions & 0 deletions MediaDecoder/MediaDecoder/Cmd/MVYFFmpegCMD.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,18 @@ typedef void (^ MVYFFmpegCMDCallback)(int ret);
// 设置音量
+ (NSString *)increaseVolumeCMDWithVolume:(NSString *)volume inputAudioPath:(NSString *)inputAudioPath outputAudioPath:(NSString *)outputAudioPath;

// adjust audio speed
+ (NSString *)adjustSpeedCMDWithSpeed:(NSString *)speed inputAudioPath:(NSString *)inputAudioPath outputAudioPath:(NSString *)outputAudioPath;

// 拼接音频
+ (NSString *)concatAudioCMDWithInputAudioPath:(NSArray<NSString *> *)inputAudioPath outputAudioPath:(NSString *)outputAudioPath;

// 混合音频
+ (NSString *)mixAudioCMDWithInputMajorAudioPath:(NSString *)inputMajorAudioPath inputMinorAudioPath:(NSString *)inputMinorAudioPath outputAudioPath:(NSString *)outputAudioPath;

// export gif
+ (NSString *)exportGifCMDWithInputVideoPath:(NSString *)inputVideoPath outputGifPath:(NSString *)outputGifPath;

// 秒 -> 时分秒
+ (NSString *)getMMSSFromSS:(NSString *)totalTime;

Expand Down
17 changes: 17 additions & 0 deletions MediaDecoder/MediaDecoder/Cmd/MVYFFmpegCMD.m
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,23 @@ + (NSString *)increaseVolumeCMDWithVolume:(NSString *)volume inputAudioPath:(NSS
"\"%@\"", inputAudioPath, volume, outputAudioPath];
}

+ (NSString *)adjustSpeedCMDWithSpeed:(NSString *)speed inputAudioPath:(NSString *)inputAudioPath outputAudioPath:(NSString *)outputAudioPath{
return [NSString stringWithFormat:@"ffmpeg -threads 4 "
"-i \"%@\" "
"-filter:a \"atempo=%@\" "
"-acodec pcm_s16le "
"-ac 1 "
"-ar 44100 "
"\"%@\"", inputAudioPath, speed, outputAudioPath];
}

+ (NSString *)exportGifCMDWithInputVideoPath:(NSString *)inputVideoPath outputGifPath:(NSString *)outputGifPath{
return [NSString stringWithFormat:@"ffmpeg -threads 4 -ss 0 -t 2 "
"-i \"%@\" "
"-vf \"fps=5,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse\" "
"\"%@\"", inputVideoPath, outputGifPath];
}

// 拼接音频
+ (NSString *)concatAudioCMDWithInputAudioPath:(NSArray<NSString *> *)inputAudioPath outputAudioPath:(NSString *)outputAudioPath {
NSMutableString *inputMS = [[NSMutableString alloc] init];
Expand Down
2 changes: 1 addition & 1 deletion MediaDecoder/MediaDecoder/Decoder/MVYVideoDecoder+Slow.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ - (void)startSlowDecodeWithSeekTime:(int64_t)seekTime slowTimeRange:(NSRange)_sl
frame.offset = offsetTime;

return frame;
}];
} withSpeed:1.0f];
}

@end
4 changes: 2 additions & 2 deletions MediaDecoder/MediaDecoder/Decoder/MVYVideoDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@
- (void)destroyNativeVideoDecoder;

// 从指定时间开始解码
- (void)startDecodeWithSeekTime:(int64_t)seekTime;
- (void)startDecodeWithSeekTime:(int64_t)seekTime handleVideoFrame:(MVYVideoFrame *(^)(MVYVideoFrame *))handleVideoFrame;
- (void)startDecodeWithSeekTime:(int64_t)seekTime withSpeed:(float)speed;
- (void)startDecodeWithSeekTime:(int64_t)seekTime handleVideoFrame:(MVYVideoFrame *(^)(MVYVideoFrame *))handleVideoFrame withSpeed:(float)speed;

// 停止解码器
- (void)stopDecoder;
Expand Down
10 changes: 5 additions & 5 deletions MediaDecoder/MediaDecoder/Decoder/MVYVideoDecoder.m
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ - (void)destroyNativeVideoDecoder {
}

// 从指定时间开始解码
- (void)startDecodeWithSeekTime:(int64_t)seekTime handleVideoFrame:(MVYVideoFrame *(^)(MVYVideoFrame *))handleVideoFrame {
- (void)startDecodeWithSeekTime:(int64_t)seekTime handleVideoFrame:(MVYVideoFrame *(^)(MVYVideoFrame *))handleVideoFrame withSpeed:(float)speed {
_isDecodeStop = false;

_seekTime = seekTime;
Expand Down Expand Up @@ -249,11 +249,11 @@ - (void)startDecodeWithSeekTime:(int64_t)seekTime handleVideoFrame:(MVYVideoFram
for (MVYVideoFrame *frame in frames) {

// 设置全局 pts 和 length 数据
frame.globalPts = frame.pts;
frame.globalPts = frame.pts * speed;
for (int x = 0; x < i; x++) {
frame.globalPts += [videoLengths[x] longValue];
}
frame.globalLength = totalVideoLength;
frame.globalLength = totalVideoLength * speed;

if (self.decoderDelegate != NULL) {
if (handleVideoFrame != NULL) {
Expand Down Expand Up @@ -298,8 +298,8 @@ - (void)startDecodeWithSeekTime:(int64_t)seekTime handleVideoFrame:(MVYVideoFram
});
}

- (void)startDecodeWithSeekTime:(int64_t)seekTime {
[self startDecodeWithSeekTime:seekTime handleVideoFrame:nil];
- (void)startDecodeWithSeekTime:(int64_t)seekTime withSpeed:(float)speed{
[self startDecodeWithSeekTime:seekTime handleVideoFrame:nil withSpeed:speed];
}

// 停止解码器
Expand Down
4 changes: 2 additions & 2 deletions MediaDecoder/MediaDecoder/Player/MVYAudioPlayer.m
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ - (void)loopPlayDecoderFrame {
return;
}

NSLog(@"%@ 播放一帧 globalPts : %d duration : %d globalLength : %d offset : %d", TAG, frame.globalPts, frame.duration, frame.offset, frame.globalLength);

//NSLog(@"%@ 播放一帧 globalPts : %d duration : %d globalLength : %d", TAG, frame.globalPts, frame.duration, frame.globalLength);
if (self.playerFirstFrameTime == 0) {
_playerFirstFrameTime = [NSDate date].timeIntervalSince1970 * 1000 - _seekTime;
}
Expand Down
3 changes: 3 additions & 0 deletions MediaDecoder/MediaDecoder/Player/MVYMediaPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
- (void)startSlowPlayWithSeekTime:(int64_t)seekTime slowTimeRange:(NSRange)slowTimeRange;
- (void)startSlowPlayWithSlowTimeRange:(NSRange)slowTimeRange;

// start play fast
- (void)startFastPlayWithSeekTime:(int64_t)seekTime slowTimeRange:(NSRange)slowTimeRange;

// 停止播放
- (void)stopPlay;

Expand Down
Loading