public Guid Add(AudioJobRequest request, ICollection <AudioTranscodingJob> jobs) { if (request == null) { throw new ArgumentNullException(nameof(request)); } if (jobs == null) { throw new ArgumentNullException(nameof(jobs)); } if (jobs.Count == 0) { throw new ArgumentException("Jobs parameter must contain at least 1 job", nameof(jobs)); } Guid jobCorrelationId = Guid.NewGuid(); using (var scope = TransactionUtils.CreateTransactionScope()) { using (var connection = _helper.GetConnection()) { connection.Execute( "INSERT INTO FfmpegAudioRequest (JobCorrelationId, SourceFilename, DestinationFilename, OutputFolder, Needed, Created) VALUES(@JobCorrelationId, @SourceFilename, @DestinationFilename, @OutputFolder, @Needed, @Created);", new { JobCorrelationId = jobCorrelationId, SourceFilename = string.Join(" ", request.SourceFilenames), request.DestinationFilename, request.Needed, request.OutputFolder, Created = DateTime.UtcNow }); foreach (AudioDestinationFormat target in request.Targets) { connection.Execute( "INSERT INTO FfmpegAudioRequestTargets (JobCorrelationId, Codec, Format, Bitrate) VALUES(@JobCorrelationId, @Codec, @Format, @Bitrate);", new { jobCorrelationId, Codec = target.AudioCodec.ToString(), Format = target.Format.ToString(), target.Bitrate }); } var jobId = connection.ExecuteScalar <int>( "INSERT INTO FfmpegJobs (JobCorrelationId, Created, Needed, JobState, JobType) VALUES(@JobCorrelationId, @Created, @Needed, @JobState, @JobType);SELECT @@IDENTITY;", new { JobCorrelationId = jobCorrelationId, Created = DateTimeOffset.UtcNow, request.Needed, JobState = TranscodingJobState.Queued, JobType = JobType.Audio }); foreach (AudioTranscodingJob transcodingJob in jobs) { connection.Execute( "INSERT INTO FfmpegTasks (FfmpegJobs_id, Arguments, TaskState, DestinationFilename, DestinationDurationSeconds, VerifyOutput) VALUES(@FfmpegJobsId, @Arguments, @TaskState, @DestinationFilename, @DestinationDurationSeconds, @VerifyOutput);", new { FfmpegJobsId = jobId, transcodingJob.Arguments, TaskState = TranscodingJobState.Queued, transcodingJob.DestinationFilename, transcodingJob.DestinationDurationSeconds, VerifyOutput = true }); } } scope.Complete(); return(jobCorrelationId); } }
private Guid HandleNewAudioJob(AudioJobRequestModel request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } AudioJobRequest jobRequest = new AudioJobRequest { Needed = request.Needed.LocalDateTime, Inpoint = request.Inpoint, Targets = request.Targets, SourceFilenames = request.SourceFilenames, OutputFolder = request.OutputFolder, DestinationFilename = request.DestinationFilenamePrefix }; Guid jobCorrelationId = Guid.NewGuid(); string sourceFilename = request.SourceFilenames.First(); string uniqueNamePart = Guid.NewGuid().ToString();//Used to avoid file collisions when transcoding the same file multiple times to the same location var frameCount = _helper.GetDuration(sourceFilename); var jobs = new List <AudioTranscodingJob>(); foreach (var target in request.Targets) { string extension = ContainerHelper.GetExtension(target.Format); string destinationFilename = $@"{request.DestinationFilenamePrefix}_{uniqueNamePart}_{target.Bitrate}.{extension}"; string destinationFullPath = $@"{request.OutputFolder}{Path.DirectorySeparatorChar}{destinationFilename}"; string arguments = string.Empty; string outputFullPath = Convert.ToBoolean(ConfigurationManager.AppSettings["TranscodeToLocalDisk"]) ? @"|TEMP|" : destinationFullPath; if (jobRequest.SourceFilenames.Count == 1) { if (target.Format == ContainerFormat.MP4) { arguments = $@"-y -xerror -i ""{sourceFilename}"" -c:a {target.AudioCodec.ToString().ToLowerInvariant()} -b:a {target .Bitrate}k -vn -movflags +faststart -map_metadata -1 -f {target.Format} ""{outputFullPath}"""; } else { arguments = $@"-y -xerror -i ""{sourceFilename}"" -c:a {target.AudioCodec.ToString().ToLowerInvariant()} -b:a {target .Bitrate}k -vn -map_metadata -1 -f {target.Format} ""{outputFullPath}"""; } } else { /*RESULT: * -y -xerror * -i "\\ondnas01\MediaCache\Test\test.mp3" -i "\\ondnas01\MediaCache\Test\radioavis.mp3" -i "\\ondnas01\MediaCache\Test\temp.mp3" * -filter_complex * [0:0][1:0][2:0]concat=n=3:a=1:v=0 * -c:a mp3 -b:a 64k -vn -map_metadata -1 -f MP3 \\ondnas01\MediaCache\Test\marvin\ffmpeg\test2.mp3 */ string filenameArguments = String.Empty, streams = String.Empty; int streamCount = 0; foreach (var filename in jobRequest.SourceFilenames) { filenameArguments += $@" -i ""{filename}"" "; streams = $"{streams}[{streamCount++}:0]"; } streams = $"{streams}concat=n={streamCount}:a=1:v=0"; if (target.Format == ContainerFormat.MP4) { arguments = $@"-y -xerror{filenameArguments}-filter_complex {streams} -c:a {target.AudioCodec.ToString().ToLowerInvariant()} -b:a {target .Bitrate}k -vn -movflags +faststart -map_metadata -1 -f {target.Format} ""{outputFullPath}"""; } else { arguments = $@"-y -xerror{filenameArguments}-filter_complex {streams} -c:a {target.AudioCodec.ToString().ToLowerInvariant()} -b:a {target .Bitrate}k -vn -map_metadata -1 -f {target.Format} ""{outputFullPath}"""; } } var transcodingJob = new AudioTranscodingJob { JobCorrelationId = jobCorrelationId, SourceFilename = sourceFilename, Needed = request.Needed.DateTime, State = TranscodingJobState.Queued, DestinationFilename = destinationFullPath, Bitrate = target.Bitrate, Arguments = arguments, DestinationDurationSeconds = frameCount }; jobs.Add(transcodingJob); } Directory.CreateDirectory(request.OutputFolder); if (!Directory.Exists(request.OutputFolder)) { throw new ArgumentException($@"Destination folder {request.OutputFolder} does not exist."); } return(_repository.Add(jobRequest, jobs)); }