Convert wma stream to mp3 stream with C# and ffmpe

2019-06-04 04:16发布

问题:

Is it possible to convert a wma stream to an mp3 stream real time?

I have tried doing something like this but not having any luck:



    WebRequest request = WebRequest.Create(wmaUrl);
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    int block = 32768;
    byte[] buffer = new byte[block];

    Process p = new Process();
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.ErrorDialog = false;
    p.StartInfo.RedirectStandardInput = true;
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.RedirectStandardError = true;
    p.StartInfo.FileName = "c:\\ffmpeg.exe";
    p.StartInfo.Arguments = "-i - -y -vn -acodec libspeex -ac 1 -ar 16000 -f mp3 ";

    StringBuilder output = new StringBuilder();

    p.OutputDataReceived += (sender, e) =>
    {
      if (e.Data != null)
      {
        output.AppendLine(e.Data);
        //eventually replace this with response.write code for a web request
      }
    };

    p.Start();
    StreamWriter ffmpegInput = p.StandardInput;

    p.BeginOutputReadLine();

    using (Stream dataStream = response.GetResponseStream())
    {
       int read = dataStream.Read(buffer, 0, block);

       while (read > 0)
       {
          ffmpegInput.Write(buffer);
          ffmpegInput.Flush();
          read = dataStream.Read(buffer, 0, block);
       }
    }

    ffmpegInput.Close();

    var getErrors = p.StandardError.ReadToEnd();

Just wondering if what I am trying to do is even possible (Convert byte blocks of wma to byte blocks of mp3). Open to any other possible C# solutions if they exist.

Thanks

回答1:

It looks like you want to take a WMA file as input and create an MP3 file as output. Further, it looks like you want to do this via stdin/stdout. I just tested this from the command line and it seems to work:

ffmpeg -i - -f mp3 - < in.wma > out.mp3

If this is your goal, there are a few problems with your command line:

p.StartInfo.FileName = "c:\\ffmpeg.exe";
p.StartInfo.Arguments = "-i - -y -vn -acodec libspeex -ac 1 -ar 16000 -f mp3 ";

"-f mp3" specifies an MP3 bitstream container but "-acodec libspeex" specifies Speex audio. I'm pretty sure you don't want this. Leave out that option and FFmpeg will just use MP3 audio for the MP3 container. Also, are you sure you want to resample to 16000 Hz, mono? Because that's what the "-ac 1 -ar 16000" options do.

One final problem: You're not providing a target. You probably need "-f mp3 -" if you want to specify stdout as the target.



回答2:

Just had the same problem.

As an input, you can directly include your URL. As the output, you use the -, that stands for standard output. This solution is for a conversion between mp3s, so I hope it works the same with videos.

Don't forget to include the process.EnableRaisingEvents = true; flag.


private void ConvertVideo(string srcURL)
{
    string ffmpegURL = @"C:\ffmpeg.exe";
    DirectoryInfo directoryInfo = new DirectoryInfo(@"C:\");

    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.FileName = ffmpegURL;
    startInfo.Arguments = string.Format("-i \"{0}\" -ar 44100 -f mp3 -", srcURL);
    startInfo.WorkingDirectory = directoryInfo.FullName;
    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardInput = true;
    startInfo.RedirectStandardError = true;
    startInfo.CreateNoWindow = false;
    startInfo.WindowStyle = ProcessWindowStyle.Normal;

    using (Process process = new Process())
    {
        process.StartInfo = startInfo;
        process.EnableRaisingEvents = true;
        process.ErrorDataReceived += new DataReceivedEventHandler(process_ErrorDataReceived);
        process.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
        process.Exited += new EventHandler(process_Exited);

        try
        {
            process.Start();
            process.BeginErrorReadLine();
            process.BeginOutputReadLine();
            process.WaitForExit();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
        finally
        {
            process.ErrorDataReceived -= new DataReceivedEventHandler(process_ErrorDataReceived);
            process.OutputDataReceived -= new DataReceivedEventHandler(process_OutputDataReceived);
            process.Exited -= new EventHandler(process_Exited);

        }
    }
}

void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    if (e.Data != null)
    {
        byte[] b = System.Text.Encoding.Unicode.GetBytes(e.Data);
        // If you are in ASP.Net, you do a 
        // Response.OutputStream.Write(b)
        // to send the converted stream as a response
    }
}


void process_Exited(object sender, EventArgs e)
{
    // Conversion is finished.
    // In ASP.Net, do a Response.End() here.
}

PS: I'm able to convert 'live' from an url with this stdout snippet, but the 'ASP' stuff is pseudo-code, not tried yet.