Recherche avancée

Médias (1)

Mot : - Tags -/blender

Autres articles (70)

Sur d’autres sites (8266)

  • C++ FFMPEG not writing AVCC box information

    5 février 2017, par awr

    I’m trying to encode raw H264 into an mp4 container using the FFMPEG API in C++. It all works fine, however the AVCC box is empty, and it returns the error :
    [iso file] Box "avcC" size 8 invalid

    If I then use the command line tool on the output file :
    ffmpeg -i output.mp4 -vcodec copy fixed.mp4

    The output file works and AVCC is populated with the required information. I’m at a loss as to why this command line argument works but I’m unable to produce the same result using the API.

    What I do in the C++ code (also do things in between the function calls) :

    outputFormat_ = av_guess_format( "mp4", NULL, NULL ); //AV_CODEC_H264
    formatContext_ = avformat_alloc_context();
    formatContext_->oformat = outputFormat_;
    ...
    AVDictionary *opts = NULL;
    char tmpstr[50]; sprintf(tmpstr, "%i", muxRate * KILOBYTESTOBYTES);
    av_dict_set(&opts, "muxrate", tmpstr, 0);
    avformat_write_header( formatContext_, &opts);
    av_write_trailer(formatContext_);

    The output of this is correct, except it’s missing the AVCC information. Adding this is manually (and fixing the box lengths accordingly) lets me playback the video fine. Any idea why the API calls are not generating the AVCC info ?

    For reference, here’s the chars from the mp4 before the fix :
    .avc1.........................€.8.H...H..........................................ÿÿ....avcC....stts

    and after :
    avc1.........................€.8.H...H..........................................ÿÿ...!avcC.B€(ÿá..gB€(Ú.à.—•...hÎ<€....stts

  • C# .net mvc Process return encoding progress (FFMpeg) to client initiated with ajax

    19 décembre 2014, par user1585895

    I am using FFMpeg to encode wav to mp3s, and on completion download the final .zip to the client.

    All works great, and I can Debug.WriteLine the progress of the encoding, but I would like to return _percentage back to the client to do some UI updates based on the value of _percentage and if all encoding is done, Im not sure how to approach this.

    My thinking is as follows :

    • ajax post to CreateAndDownloadAlbum(List trackIds, int productId)
    • loop through List and create a new Process, run
      — parse StdError to get encoding percentage in myProcess_ErrorData(object source, DataReceivedEventArgs e)
      — send _percentage value at timed intervals back to CreateAndDownloadAlbum
      — update UI based on value of _percentage, when all is complete break and call public ActionResult SendFileDownload()

    Any input would be great.

    Thanks !

    front end AJAX call to post list of file Ids to download

    var data = $('#downloadAlbum').serialize();
    $.ajax({
       url: "/Admin/CreateAndDownloadAlbum",
       method: "POST",
       data: data,
       dataType: 'json',
       success: function(result) {
            // wait here for _percentage
            // if not 100, call again to get new _percentage value
            // if 100, update UI, move to next file being encoded
            // if all encoding is complete, call SendFileDownload() in controller
       }
    });

    then the controller code

    [HttpPost]
       public void CreateAndDownloadAlbum(List<trackstodownload> trackIds, int productId)
       {
           _numTracksToDownload = trackIds.Count;
           var product = _productRepository.GetProductById(productId);
           var artist = _artistRepository.GetArtistById(product.ArtistId);

           var folderGuid = Guid.NewGuid();
           _zipFolder = string.Concat(artist.ArtistName.ToUpper().Replace(" ", "_"), "[", product.ProductName.ToUpper().Replace(" ", "_"), "].zip");
           _mp3FolderPath = Server.MapPath("/Files/" + productId + "/" + folderGuid);
           _zipDownloadPath = Server.MapPath("/Delivery/" + _zipFolder);

           if (!Directory.Exists(Server.MapPath("/Files/" + productId + "/" + folderGuid)))
           {
               Directory.CreateDirectory(Server.MapPath("/Files/" + productId + "/" + folderGuid));
           }

           foreach (var z in trackIds)
           {
               var track = _trackRepository.GetTrackById(z.TrackId);
               var process = new Process();
               var startInfo = new ProcessStartInfo
               {
                   WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
                   FileName = "F:\\Development\\ffmpeg\\ffmpeg.exe",
                   RedirectStandardOutput = true,
                   RedirectStandardError = true,
                   UseShellExecute = false
               };
               var startFile = Path.Combine("F:\\Development","Files", track.ProductId.ToString(), track.TrackFileName);
               var endFile = Path.Combine("F:\\Development", "Files", track.ProductId.ToString(), folderGuid.ToString(), track.TrackFileName.Replace(".wav", ".mp3"));

               startInfo.Arguments = "-i " + startFile + " -b:a 320k " + endFile + " -stats";
               process.StartInfo = startInfo;
               process.EnableRaisingEvents = true;
               process.Exited += myProcess_exited;
               process.OutputDataReceived += myProcess_OutputData;
               process.ErrorDataReceived += myProcess_ErrorData;

               try
               {
                   process.Start();
                   process.BeginOutputReadLine();
                   process.BeginErrorReadLine();

                   if (process.HasExited == false)
                   {
                       process.WaitForExit();
                   }
               }
               catch (Exception)
               {

                   throw;
               }
           }

           SendFileDownload();

       }

       public ActionResult SendFileDownload()
       {
           // zip and move to delivery folder
           using (var zip = new ZipFile())
           {
               zip.AddDirectory(_mp3FolderPath, _zipFolder);
               zip.Save(_zipDownloadPath);
           }

           // delete items in temp guid folder
           var downloadedMessageInfo = new DirectoryInfo(_mp3FolderPath);
           foreach (var f in downloadedMessageInfo.GetFiles())
           {
               f.Delete();
           }

           // delete temp folder
           Directory.Delete(_mp3FolderPath);

           // download file
           string file = _zipDownloadPath;
           return File(file, "application/force-download", Path.GetFileName(file));

       }

       public void myProcess_exited(Object source, EventArgs e)
       {
           Debug.WriteLine("myProcess_exited ===================================");
           _duration = new TimeSpan(0, 0, 0);
           _frameTime = new TimeSpan(0, 0, 0);
           _percentage = 0;
           _numEncodedTracks++; // using this to tell me if all tracks have been encoded
       }

       public void myProcess_OutputData(object source, DataReceivedEventArgs e)
       {
       }

       public void myProcess_ErrorData(object source, DataReceivedEventArgs e)
       {
           string strMessage = e.Data;

           if (!string.IsNullOrEmpty(strMessage) &amp;&amp; (strMessage.Contains("Duration: ") || strMessage.Contains("size=")))
           {
               if (_duration != null)
               {
                   if (strMessage.Contains("Duration: "))
                   {
                       _strDuration = strMessage.Substring(strMessage.IndexOf("Duration: ") + ("Duration: ").Length,
                           ("00:00:00.00").Length);

                       char[] d_delHrMn = new char[] { ':' };
                       string[] d_tempHrMn = _strDuration.Split(d_delHrMn, StringSplitOptions.RemoveEmptyEntries);

                       char[] d_delSec = new char[] { '.' };
                       string[] d_tempSec = d_tempHrMn[2].Split(d_delSec, StringSplitOptions.RemoveEmptyEntries);

                       var d_hour = d_tempHrMn[0] == "0" ? 0 : Convert.ToInt32(d_tempHrMn[0]);
                       var d_min = d_tempHrMn[1] == "0" ? 0 : Convert.ToInt32(d_tempHrMn[1]);
                       var d_sec = d_tempSec[0] == "0" ? 0 : Convert.ToInt32(d_tempSec[0]);

                       _duration = new TimeSpan(d_hour, d_min, d_sec);
                   }
               }

               if (strMessage.Contains("size="))
               {
                   _strFrameTime = strMessage.Substring(strMessage.IndexOf("time=") + ("time=").Length,
                       ("00:00:00.00").Length);

                   char[] f_delHrMn = new char[] { ':' };
                   string[] f_tempHrMn = _strFrameTime.Split(f_delHrMn, StringSplitOptions.RemoveEmptyEntries);

                   char[] f_delSec = new char[] { '.' };
                   string[] f_tempSec = f_tempHrMn[2].Split(f_delSec, StringSplitOptions.RemoveEmptyEntries);

                   var f_hour = f_tempHrMn[0] == "0" ? 0 : Convert.ToInt32(f_tempHrMn[0]);
                   var f_min = f_tempHrMn[1] == "0" ? 0 : Convert.ToInt32(f_tempHrMn[1]);
                   var f_sec = f_tempSec[0] == "0" ? 0 : Convert.ToInt32(f_tempSec[0]);

                   _frameTime = new TimeSpan(f_hour, f_min, f_sec);

               }

               if (_strDuration != "00:00:00.00" &amp;&amp; _strFrameTime != "00:00:00.00" &amp;&amp; _percentage &lt; 100)
               {
                   _percentage = _frameTime.TotalMilliseconds / _duration.TotalMilliseconds * 100;
                   Debug.WriteLine(_percentage + " || " + _frameTime + " " + _duration);
               }
           }
       }
    </trackstodownload>
  • How to send encoded video (or audio) data from server to client in a way that's decodable by webcodecs API using minimal latency and data overhead

    11 janvier 2023, par Tiger Yang

    My question (read entire post for context) :

    &#xA;

    Given the unique circumstance of only ever decoding data from a specifically-configured encoder, what is the best way I can send the encoded bitstream along with the bare minimum extra bytes required to properly configure the decoder on the client's end (including only things that change per stream, and omitting things that don't, such as resolution) ? I'm a sucker for zero compromises, and I think I am willing to design my own minimal container format to accomplish this.

    &#xA;

    Context and problem :

    &#xA;

    I'm working on a remote desktop implementation that consists of a server that captures and encodes the display and speakers using FFmpeg and forwards it via pipe to a go (language) program which sends it on two unidirectional webtransport streams to my client, which I plan to decode using the webcodecs API. According to MDN, the video decoder needs to be fed via .configure() an object containing the following : https://developer.mozilla.org/en-US/docs/Web/API/VideoDecoder/configure before it's able to decode anything.

    &#xA;

    same goes for the audio decoder : https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder/configure

    &#xA;

    What I've tried so far :

    &#xA;

    Because this remote desktop will be for my personal use only, it would only ever receive streams from a specific encoder configured in a specific way encoding video at a specific resolution, framerate, color space, etc.. Therefore, I took my video capture FFmpeg command...

    &#xA;

    videoString := []string{&#xA;        "ffmpeg",&#xA;        "-init_hw_device", "d3d11va",&#xA;        "-filter_complex", "ddagrab=video_size=1920x1080:framerate=60",&#xA;        "-vcodec", "hevc_nvenc",&#xA;        "-tune", "ll",&#xA;        "-preset", "p7",&#xA;        "-spatial_aq", "1",&#xA;        "-temporal_aq", "1",&#xA;        "-forced-idr", "1",&#xA;        "-rc", "cbr",&#xA;        "-b:v", "500K",&#xA;        "-no-scenecut", "1",&#xA;        "-g", "216000",&#xA;        "-f", "hevc", "-",&#xA;    }&#xA;

    &#xA;

    ...and instructed it to write to an mp4 file instead of outputting to pipe, and then I had this webcodecs demo https://w3c.github.io/webcodecs/samples/video-decode-display/ demux it using mp4box.js. Knowing that the demo outputs a proper .configure() object, I blindly copied it and had my client configure using that every time. Sadly, it didn't work, and I since noticed that the "description" part of the configure object changes despite the encoder and parameters being the same.

    &#xA;

    I knew that mp4 files worked via mp4box, but they can't be streamed with low latency over a network, and additionally, ffmpeg's -f parameters specifies the muxer to use, but there are so many different types.

    &#xA;

    At this point, I think I'm completely out of my depth, so :

    &#xA;

    Given the unique circumstance of only ever decoding data from a specifically-configured encoder, what is the best way I can send the encoded bitstream along with the bare minimum extra bytes required to properly configure the decoder on the client's end (including only things that change per stream, and omitting things that don't, such as resolution) ? I'm a sucker for zero compromises, and I think I am willing to design my own minimal container format to accomplish this. (copied above)

    &#xA;