• Unity 利用FFmpeg实现录屏、直播推流、音频视频格式转换、剪裁等功能


    目录

    一、FFmpeg简介。

    二、FFmpeg常用参数及命令。

    三、FFmpeg在Unity 3D中的使用。

      1、FFmpeg 录屏。

      2、FFmpeg 推流。

      3、FFmpeg 其他功能简述。

    一、FFmpeg简介

    对于FFmpeg,其官网上是这样介绍的:

    FFmpeg is the leading multimedia framework, able to decode, encode, transcode, mux, demux, stream, filter and play pretty much anything that humans and machines have created.

    FFmpeg能够实现对视频音频编码、解码、转码、流传输等等一系列功能。它包含有libavcodec, libavutil, libavformat, libavfilter, libavdevice, libswscale,libswresample 库。其中:

    libavcodec      是一个包含用于音频/视频编解码器的解码器和编码器的库。
    libavutil       是一个包含简化编程功能的库,包括随机数生成器,数据结构,数学例程,核心多媒体实用程序等等。
    libavformat     是一个包含多媒体容器格式的解复用器和复用器的库。
    libavdevice     是一个包含输入和输出设备的库,用于从许多常见的多媒体输入/输出软件框架中获取和呈现,包括Video4Linux,Video4Linux2,VfW和ALSA。
    libavfilter     是一个包含媒体过滤器的库。
    libswscale      是一个执行高度优化的图像缩放和色彩空间/像素格式转换操作的库。
    libswresample   是一个执行高度优化的音频重采样,重新矩阵化和样本格式转换操作的库。

    二、FFmpeg常用参数及命令

    1、命令的格式:

    ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_optionsoutput_url} ...

    2、常用参数:

    -f fmt (input/output)	强制设定输入或输出文件格式。通常会自动检测输入文件的格式,并从输出文件的文件扩展名猜测格式,因此大多数情况下不需要这个选项。
    -i url (input)          输入
    -y (global)             在没有请求的情况下覆盖输出文件。
    -n (global)             不要覆盖输出文件,如果指定的输出文件已经存在,则会立即退出。
    -stream_loop number 	设定输入流循环的次数。循环0表示没有循环,循环1表示无限循环
    -codec/-c               设置编码格式
    -r fps 	                设置帧速率
    -vcodec codec (output)	设置视频编码格式,同-codec:v
    -pix_fmt format         设置像素格式
    -ar freq                设置音频采样频率
    -aq q (output)	        设置音频质量
    -acodec codec	        设置音频编解码器,同-codec:a

    3、常用命令

    (1)将视频的帧速率改为24

    ffmpeg -i input.avi -r 24 output.avi
    

    (2)视频格式转换,将avi转成mp4

    ffmpeg -i input.avi output.mp4 
    

    (3)从视频中提取音频

    ffmpeg -i test.mp4 -acodec libmp3lame output.mp3

    (4)视频剪切

    ffmpeg -ss 00:00:15 -t 00:00:05 -i input.mp4 -vcodec copy -acodec copy output.mp4 
    

    (5)视频添加Logo

    ffmpeg -i input.mp4 -i Logo.png -filter_complex overlay output.mp4 
    

    (6)视频去掉Logo

    ffmpeg -i input.mp4 -vf delogo=0:0:220:90:100:1 output.mp4 
    

    (7)将100张图片合成视频,并为其添加背景音频(注意:图片要放在同一个文件夹下,并将图片按001--100的格式命名)

    ffmpeg -i 001.mp3 -i %3d.jpg -s 1024x768 -author fy -vcodec mpeg4 darkdoor.avi
    

    (8)将视频每隔一秒抽取一张图片,保存名字为 foo-001.jpegfoo-002.jpeg, 等

    ffmpeg -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
    

      

    (2019.03.29 更新)

     三、FFmpeg在Unity 3D中的使用

    有网友问我如何在Unity中使用FFmpeg呢,趁今天老大出差了,忙里偷闲更新一下博客。

    使用FFmpeg首先得有FFmpeg,可以直接从官网免费下载,也可以从Unity Store花费85美元下载插件FFmpeg Unity Bind,

    如果你有插件FFmpeg Unity Bind,那你就不用再往下看了,因为本文使用的就是FFmpeg Unity Bind的思想:用命令行参数实现FFmpeg的调用。

    1、命令行调用FFmpeg的核心代码如下:

         public static void Execute(string command)
            {
                if (isRunning)
                    return;
    
                //Clear output buffer
                buffer = new StringBuilder(short.MaxValue);
    
                new Thread(() =>
                {
                    isRunning = true;
                    Thread.CurrentThread.IsBackground = true;
    
                    //Execute binary
                    p = new Process();
                    p.StartInfo.RedirectStandardOutput = true;
                    p.StartInfo.RedirectStandardError = true;
                    p.StartInfo.UseShellExecute = false;
                    p.StartInfo.CreateNoWindow = true;
                    p.StartInfo.FileName = binaryPath;
                    p.StartInfo.Arguments = command;
    
    
                    p.StartInfo.RedirectStandardInput = true;//这句一定需要,用于模拟该进程控制台的输入
    
                    p.OutputDataReceived += (s, e) =>
                    {
                        callback(FFmpegParser.COMMAND_CODE + FFmpegParser.PROGRESS_CODE + AppendLog(e.Data));
                    };
                    p.ErrorDataReceived += (s, e) =>
                    {
    
                        if (!string.IsNullOrEmpty(e.Data) && e.Data.ToLower().Contains("error"))
                            callback(FFmpegParser.ERROR_CODE + AppendLog(e.Data));
                        else
                            callback(FFmpegParser.COMMAND_CODE + FFmpegParser.PROGRESS_CODE + AppendLog(e.Data));
                    };
    
                    p.Start();
    
                    callback(FFmpegParser.COMMAND_CODE + FFmpegParser.START_CODE + "
    Started
    ");
    
                    p.BeginOutputReadLine();
                    p.BeginErrorReadLine();
    
                    p.WaitForExit();
    
                    if (isStopProcessWhatIthink)
                    {
                        callback(FFmpegParser.COMMAND_CODE + FFmpegParser.SUCCESS_CODE + AppendLog("主动关闭 FFmpeg 进程") );
                        isStopProcessWhatIthink = false;
                    }
                    else
                    {
                        callback(FFmpegParser.COMMAND_CODE +
                                 (p.ExitCode == 0 ?
                                  FFmpegParser.SUCCESS_CODE + AppendLog("Success!") :
                                  FFmpegParser.FAILURE_CODE + AppendLog("Failure. Search details above")));
                        p.Close();
                    }
                    callback(FFmpegParser.COMMAND_CODE + FFmpegParser.FINISH_CODE + "
    Finished
    ");
                    isRunning = false;
                }).Start();
            }
    
            /// <summary>
            /// 主动退出进程
            /// </summary>
            public static void CloseFFmpegProcess()
            {
                if (p!=null)
                {
                    try
                    {
    
                        p.StandardInput.WriteLine("q");//在这个进程的控制台中模拟输入q,用于暂停录制
                        p.Close();
                        p.Dispose();
    
                        isRunning = false;
    
    
                        isStopProcessWhatIthink = true;
                        p = null;
                        UnityEngine.Debug.Log("主动退出FFmpeg进程");
                    }
                    catch (Exception)
                    {
                        UnityEngine.Debug.Log("No process to kill");
                    }
    
                }
                else
                {
                    UnityEngine.Debug.Log("FFmpeg process is null");
    
                }
            }

    2、FFmpeg 录屏、推流常用命令

            //推流命令
            //-re -i C:output.mp4  -vcodec libx264 -acodec copy  -f flv -y rtmp://***/live/chid
            //拉流
            //-i rtmp://127.0.0.1/live/chid -acodec copy -vcodec copy -f flv -y chid.mp4
            //-i rtmp://127.0.0.1/live/chid -c copy dump.flv
    
            // rtsp 推流
            // -i C:output.mp4  -vcodec libx264 -f rtsp rtsp://***/myid
            //-f gdigrab -i desktop -vcodec libx264 -preset ultrafast -acodec libmp3lame -ar 44100 -ac 1 -f rtsp rtsp://***/myid
            //推 摄像头
            //-f dshow -i video="HD Pro Webcam C920" -vcodec libx264 -acodec copy -preset:v ultrafast -tune:v zerolatency -f rtsp rtsp://***/myid
            //音视频录制
            //-f dshow -video_size 1680x1050 -framerate 30 -pixel_format yuv420p -i audio="麦克风 (HD Pro Webcam C920)" av-out.mp4

    //-f fmt 指定格式(音视频的格式) //dshow //-i 输入 //-vcodec 强制使用codec编解码方式('copy' to copy stream) //libx264 //-acodec 指定音频编码('copy' to copy stream) //copy //-preset //-tune //-y 覆盖已有文件 //-c //传输的图像为灰色的解决办法,添加:-pix_fmt yuv420p //录制桌面:desktop //录制窗口:title=窗口名 // av_interleaved_write_frame(): Broken pipe 问题:在-f rtsp后面加一个-rtsp_transport tcp //录制整个程序窗口 //string command = "-f gdigrab -i title=test -vcodec libx264 -preset ultrafast -pix_fmt yuv420p -acodec libmp3lame -ar 44100 -ac 1 -f rtsp -rtsp_transport tcp rtsp://***/myid"; //录制某一区域(这里是摄像头区域) //-offset_x 10 -offset_y 20 -video_size 640x480 从屏幕的(10,20)点处开始,抓取640x480的屏幕 //-s 640x480 指定分辨率 (640x480) //-r 60 设置帧率 (和程序的fps保持一致,解决Past duration 0.692253 too large的问题) //string command = "-f gdigrab -offset_x 920 -offset_y 85 -video_size 320*240 -s 320*240 -i title=test -vcodec libx264 -preset ultrafast -pix_fmt yuv420p -r 60 -acodec libmp3lame -ar 44100 -ac 1 -f rtsp -rtsp_transport tcp rtsp://***/myid"; //string command = "-f gdigrab -offset_x 920 -offset_y 85 -video_size 320*240 -s 320*240 -i title=test -f dshow -i audio=""+ micName + "" -vcodec libx264 -preset ultrafast -pix_fmt yuv420p -r 60 -acodec aac -ar 16000 -ac 1 -f rtsp -rtsp_transport tcp rtsp://***/myid"; //输入交换视频和音频的位置,画面不卡顿了 //string command = "-f dshow -i audio="" + micName + "" -f gdigrab -offset_x 920 -offset_y 85 -video_size 320*240 -s 320*240 -i title=test -vcodec libx264 -preset ultrafast -pix_fmt yuv420p -f rtsp -rtsp_transport tcp "+ ClientController.rtspId; //FFmpegCommands.DirectInput(command); //-re(输入)主要用于模拟抓取设备或实时输入流(例如,从文件读取时)。不应与实际的抓取设备或实时输入流一起使用(它可能导致数据包丢失)。默认情况下,ffmpeg尝试尽快读取输入。此选项将减慢输入读取到输入的本机帧速率。它对于实时输出(例如直播)非常有用。 //string command = "-re -i "" + path + "" -vcodec libx264 -preset ultrafast -pix_fmt yuv420p -f rtsp -rtsp_transport tcp " +ClientController.rtspId;

    3、完整源码示例  

    点击这里获取你想要的源码。

  • 相关阅读:
    java内存管理的一些基础,内存溢出的解决方案
    设计模式中类的关系 .
    一个很郁闷的问题,Java中的僵死进程
    quartzscheduler的集群化配置
    转 : 敏捷开发的原则 .
    如何进行单元测试
    欢迎来到地狱 WriteUp(2019暑假CTF第一周misc)
    20181218小黄衫获得感想和阶段性总结
    2019暑假Java学习笔记(一)
    2019“嘉韦思杯”3.30初赛一部分Write Up
  • 原文地址:https://www.cnblogs.com/Jason-c/p/10219609.html
Copyright © 2020-2023  润新知