C# copywriting voice with pictures to generate video with one click

Master skip it, the function is too simple, I am embarrassed. .

This is my own need. It is very troublesome to make short videos of products, edit here and there, so I will make this simplest version first, and then I will enrich the functions step by step.

Requirements: Generate a video from several pictures, and the length of the video is subject to the voice generated by the content of the copywriting.

C# prepares the data, that is, the voice generated by the picture and copywriting of each frame of the video, and finally calls ffmpeg to generate the video, in the following order:

1. Prepare data files, agree on the first line of copy text, use this to generate voice files for video dubbing, and other lines of picture file names.

2. Analyze the data file and get the copy text and image array

private bool Parse()
        {
            if (!System.IO.File.Exists("source\data.txt"))
            {
                log("Cannot find the data file data.txt");
                return false;
            }
            int i = 0;
            Image img;
            ImgFileList = new List<string>();
            foreach (string line in System.IO.File.ReadLines("source\data.txt"))
            {
                if (i + + == 0)
                {
                    wenzi = line;
                    continue;
                }
                if (!System.IO.File.Exists(line))
                {
                    log("file: " + line + ", does not exist");
                    continue;
                }
                img = Image.FromFile(line);
                if (img == null)
                {
                    log("file: " + line + ", not a picture");
                    continue;
                }
                img. Dispose();
                ImgFileList. Add(line);
            }
            return ImgFileList. Count > 0;
        }

3. Call Baidu API to generate voice, store it in data\ee.mp3, and return the voice length.

private bool GetBaiDuAudio(string str,out int len,out string filename)
        {
            //Replace here with your own Baidu key
            const string API_KEY = "asdfasdfasdfasfdasfd";
            const string SECRET_KEY = "asdfasdfasfdasfd";
            var client = new Baidu.Aip.Speech.Tts(API_KEY, SECRET_KEY);
            client.Timeout = 60000; // modify the timeout

            // optional parameters
            var option = new Dictionary<string, object>()
            {
                {"spd", 5}, // speech rate
                {"vol", 5}, // volume
                {"per", 103}, // Speaker, 4: Emotional Yaya child voice
            };
            var result = client. Synthesis(str, option);
            if (result.ErrorCode == 0) // or result.Success
            {
                // get the current path
                string path = System.AppDomain.CurrentDomain.BaseDirectory;
                if (!Directory. Exists(path + "data"))
                {
                    Directory.CreateDirectory(path + "data");
                }
                File.WriteAllBytes("data\ee.mp3", result.Data);
                len = Mp3.GetLength("data\ee.mp3");
                filename = "data\ee.mp3";
                return true;
            }
            len = 0;
            filename = "";
            return false;
        }

Here I complain about the mp3 generated by Baidu, ffmpeg -i ee.mp3, but the length cannot be obtained. In order to obtain this length, it took a long time. The code to obtain the length of mp3 is as follows:

 public class APIClass
    {

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        // get the short file name
        public static extern int GetShortPathName(
            string lpszLongPath,
            string shortFile,
            int cchBuffer
            );

        [DllImport("winmm.dll", EntryPoint = "mciSendString", CharSet = CharSet.Auto)]
        public static extern int mciSendString(
            string lpstrCommand,
            string lpstrReturnString,
            int uReturnLength,
            int hwndCallback
            );
    }
    class Mp3
    {
        public static int GetLength(string filename)
        {
            string Name = "";
            Name = Name.PadLeft(260, Convert.ToChar(" "));
            APIClass. GetShortPathName(filename, Name, Name. Length);
            Name = GetCurrPath(Name);
            Name = "open " + Convert.ToChar(34) + Name + Convert.ToChar(34) + "alias media";
            APIClass.mciSendString(Name, "", 0, 0);
            string durLength = "";
            durLength = durLength.PadLeft(128, Convert.ToChar(" "));
            APIClass.mciSendString("status media length", durLength, durLength.Length, 0);
            APIClass.mciSendString("close media", "", 128, 0);
            APIClass.mciSendString("close all", "", 128, 0);
            durLength = durLength. Trim();
            if (durLength == "") return 0;
            return (int)(Convert. ToDouble(durLength));
        }
        private static string GetCurrPath(string name)
        {
            if (name. Length < 1) return "";
            name = name. Trim();
            name = name. Substring(0, name. Length - 1);
            return name;
        }
    }

The Mp3.GetLength function returns milliseconds.

4. Calculate how many frames of pictures are generated according to the length of the mp3, how many frames are generated for each source picture, and finally generate a picture.

The total number of pictures: mp3 length/40, 1000/40=25, we calculate according to 25 frames per second.

private void CreateImg()
        {
            //audion is the length of Baidu audio, in milliseconds
            //Several pictures are evenly distributed, based on 25 frames per second, that is, a picture in 40 milliseconds
            int photon = audiolen / ImgFileList.Count / 40;
            string file, extname, newfile;
            int n;
            int counta = 1;
            //Generate 1-n.jpg in the data directory
            for (int i = 0; i < ImgFileList. Count; i ++ )
            {
                file = ImgFileList[i];
                n = file.LastIndexOf(".");
                extname = file. Substring(n, file. Length - n);
                for (int j = 0; j < photon; j ++ )
                {
                    newfile = "data\" + counta + extname;
                    File. Copy(file, newfile);
                    counta++;
                }
            }
        }

The generated image is as follows

5. Call ffmpeg command line to generate video

Command: ffmpeg -f image2 -i data\%d.jpg -i data\ee.mp3 data\output.mp4

private string CreateVideo()
        {
            string DstFile = "data\output.mp4";
            string strCmd = string.Format("-f image2 -i {0} -i {1} {2} -y", "data\%d.jpg", audiofile, DstFile);
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.FileName = "ffmpeg.exe";//The name of the program to be executed
            p.StartInfo.Arguments = " " + strCmd;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = false;//may accept input from the calling program
            p.StartInfo.RedirectStandardOutput = false;//Get the output information by the calling program
            p.StartInfo.RedirectStandardError = false;//Redirect standard error output
            p.StartInfo.CreateNoWindow = false;//Do not display the program window

            p.Start();//Start the program
            p.WaitForExit();//Wait for the program to finish executing and exit the process

            if (System.IO.File.Exists(DstFile))
            {
                return DstFile;
            }
            return "";
        }

6. Operation screen

At this point, the video file is generated, and the length of the video exactly matches the length of the music.

The code has been uploaded to my resources. . .