Пример #1
0
        /// <summary>
        /// The hb_set_anamorphic_size_native.
        /// </summary>
        /// <param name="job">
        /// The job.
        /// </param>
        /// <param name="title">
        /// The title.
        /// </param>
        /// <returns>
        /// The <see cref="AnamorphicResult"/> object.
        /// </returns>
        public static AnamorphicResult hb_set_anamorphic_size(PictureSettingsJob job, PictureSettingsTitle title)
        {
            int outputHeight = 0;
            int outputParHeight = 0;
            int outputParWidth = 0;
            int outputWidth = 0;

            hb_job_s nativeJob = new hb_job_s
                                     {
                                         modulus = job.Modulus.HasValue ? job.Modulus.Value : 16,
                                         anamorphic =
                                             new hb_anamorphic_substruct
                                                 {
                                                     par_width = job.ParW,
                                                     par_height = job.ParH,
                                                     itu_par = 0,
                                                     mode = (int)job.AnamorphicMode,
                                                     dar_width = 0,
                                                     dar_height = 0,
                                                     keep_display_aspect = job.KeepDisplayAspect ? 1 : 0
                                                 },
                                         maxWidth = title.Width,
                                         maxHeight = title.Height,
                                         keep_ratio = job.KeepDisplayAspect ? 1 : 0,
                                         width = job.Width,
                                         height = job.Height,
                                         crop = new[] { job.Crop.Top, job.Crop.Bottom, job.Crop.Left, job.Crop.Right }
                                     };

            hb_title_s title_s = new hb_title_s
                                     {
                                         crop = new[] { job.Crop.Top, job.Crop.Bottom, job.Crop.Left, job.Crop.Right },
                                         width = title.Width,
                                         height = title.Height,
                                         pixel_aspect_width = title.ParW,
                                         pixel_aspect_height = title.ParH,
                                         aspect = 0
                                     };

            IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(hb_title_s)));
            Marshal.StructureToPtr(title_s, pointer, false);
            nativeJob.title = pointer;

            HBFunctions.hb_set_anamorphic_size(
                ref nativeJob, ref outputWidth, ref outputHeight, ref outputParWidth, ref outputParHeight);

            return new AnamorphicResult { OutputWidth = outputWidth, OutputHeight = outputHeight, OutputParWidth = outputParWidth, OutputParHeight = outputParHeight };
        }
Пример #2
0
 public static extern void hb_set_size(ref hb_job_s param0, double ratio, int pixels);
Пример #3
0
 public static extern void hb_set_anamorphic_size(ref hb_job_s job, ref int output_width, ref int output_height, ref int output_par_width, ref int output_par_height);
Пример #4
0
 public static extern void hb_add_filter(ref hb_job_s job, ref hb_filter_object_s filter, IntPtr settings);
Пример #5
0
 public static extern void hb_job_set_advanced_opts(ref hb_job_s job, IntPtr advanced_opts);
Пример #6
0
 public static extern void hb_get_preview(IntPtr hbHandle, ref hb_job_s title, int preview, IntPtr buffer);
Пример #7
0
 /// <summary>
 /// Applies the encoding job to the native memory structure and returns a list of memory
 /// locations allocated during this.
 /// </summary>
 /// <param name="nativeJob">The native structure to apply to job info to.</param>
 /// <param name="job">The job info to apply.</param>
 /// <returns>The list of memory locations allocated for the job.</returns>
 private List<IntPtr> ApplyJob(ref hb_job_s nativeJob, EncodeJob job)
 {
     return this.ApplyJob(ref nativeJob, job, false, 0, 0, 0);
 }
Пример #8
0
 public static extern void hb_get_preview(IntPtr hbHandle, ref hb_job_s title, int preview, IntPtr buffer);
Пример #9
0
 public static extern void hb_set_anamorphic_size(ref hb_job_s job, ref int output_width, ref int output_height, ref int output_par_width, ref int output_par_height);
Пример #10
0
 public static extern void hb_set_size(ref hb_job_s param0, double ratio, int pixels);
Пример #11
0
 public static extern void hb_job_set_advanced_opts(ref hb_job_s job, IntPtr advanced_opts);
Пример #12
0
 public static extern void hb_job_close(ref hb_job_s job);
Пример #13
0
        /// <summary>
        /// Applies the encoding job to the native memory structure and returns a list of memory
        /// locations allocated during this.
        /// </summary>
        /// <param name="nativeJob">The native structure to apply to job info to.</param>
        /// <param name="job">The job info to apply.</param>
        /// <param name="preview">True if this is a preview encode.</param>
        /// <param name="previewNumber">The preview number (0-based) to encode.</param>
        /// <param name="previewSeconds">The number of seconds in the preview.</param>
        /// <param name="overallSelectedLengthSeconds">The currently selected encode length. Used in preview
        /// for calculating bitrate when the target size would be wrong.</param>
        /// <returns>The list of memory locations allocated for the job.</returns>
        private List<IntPtr> ApplyJob(ref hb_job_s nativeJob, EncodeJob job, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds)
        {
            var allocatedMemory = new List<IntPtr>();
            Title title = this.GetTitle(job.Title);
            hb_title_s originalTitle = this.GetOriginalTitle(job.Title);

            EncodingProfile profile = job.EncodingProfile;

            if (preview)
            {
                nativeJob.start_at_preview = previewNumber + 1;
                nativeJob.seek_points = this.previewCount;

                // There are 90,000 PTS per second.
                nativeJob.pts_to_stop = previewSeconds * 90000;
            }
            else
            {
                switch (job.RangeType)
                {
                    case VideoRangeType.All:
                        break;
                    case VideoRangeType.Chapters:
                        if (job.ChapterStart > 0 && job.ChapterEnd > 0)
                        {
                            nativeJob.chapter_start = job.ChapterStart;
                            nativeJob.chapter_end = job.ChapterEnd;
                        }
                        else
                        {
                            nativeJob.chapter_start = 1;
                            nativeJob.chapter_end = title.Chapters.Count;
                        }

                        break;
                    case VideoRangeType.Seconds:
                        if (job.SecondsStart < 0 || job.SecondsEnd < 0 || job.SecondsStart >= job.SecondsEnd)
                        {
                            throw new ArgumentException("Seconds range " + job.SecondsStart + "-" + job.SecondsEnd + " is invalid.", "job");
                        }

                        // If they've selected the "full" title duration, leave off the arguments to make it clean
                        if (job.SecondsStart > 0 || job.SecondsEnd < title.Duration.TotalSeconds)
                        {
                            // For some reason "pts_to_stop" actually means the number of pts to stop AFTER the start point.
                            nativeJob.pts_to_start = (int)(job.SecondsStart * 90000);
                            nativeJob.pts_to_stop = (int)((job.SecondsEnd - job.SecondsStart) * 90000);
                        }
                        break;
                    case VideoRangeType.Frames:
                        if (job.FramesStart < 0 || job.FramesEnd < 0 || job.FramesStart >= job.FramesEnd)
                        {
                            throw new ArgumentException("Frames range " + job.FramesStart + "-" + job.FramesEnd + " is invalid.", "job");
                        }

                        // "frame_to_stop" actually means the number of frames total to encode AFTER the start point.
                        nativeJob.frame_to_start = job.FramesStart;
                        nativeJob.frame_to_stop = job.FramesEnd - job.FramesStart;
                        break;
                }
            }

            // Chapter markers
            nativeJob.chapter_markers = profile.IncludeChapterMarkers ? 1 : 0;

            List<IntPtr> nativeChapters = nativeJob.list_chapter.ToIntPtrList();

            if (!preview && profile.IncludeChapterMarkers)
            {
                int numChapters = title.Chapters.Count;

                if (job.UseDefaultChapterNames)
                {
                    for (int i = 0; i < numChapters; i++)
                    {
                        if (i < nativeChapters.Count)
                        {
                            HBFunctions.hb_chapter_set_title(nativeChapters[i], "Chapter " + (i + 1));
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < numChapters; i++)
                    {
                        if (i < nativeChapters.Count && i < job.CustomChapterNames.Count)
                        {
                            IntPtr chapterNamePtr;

                            if (string.IsNullOrWhiteSpace(job.CustomChapterNames[i]))
                            {
                                chapterNamePtr = InteropUtilities.CreateUtf8Ptr("Chapter " + (i + 1));
                            }
                            else
                            {
                                chapterNamePtr = InteropUtilities.CreateUtf8Ptr(job.CustomChapterNames[i]);
                            }

                            HBFunctions.hb_chapter_set_title__ptr(nativeChapters[i], chapterNamePtr);
                            Marshal.FreeHGlobal(chapterNamePtr);
                        }
                    }
                }
            }

            Cropping crop = GetCropping(profile, title);

            nativeJob.crop[0] = crop.Top;
            nativeJob.crop[1] = crop.Bottom;
            nativeJob.crop[2] = crop.Left;
            nativeJob.crop[3] = crop.Right;

            var filterList = new List<hb_filter_object_s>();

            // FILTERS: These must be added in the correct order since we cannot depend on the automatic ordering in hb_add_filter . Ordering is determined
            // by the order they show up in the filters enum.

            // Detelecine
            if (profile.Detelecine != Detelecine.Off)
            {
                string settings = null;
                if (profile.Detelecine == Detelecine.Custom)
                {
                    settings = profile.CustomDetelecine;
                }

                this.AddFilter(filterList, (int)hb_filter_ids.HB_FILTER_DETELECINE, settings, allocatedMemory);
            }

            // Decomb
            if (profile.Decomb != Decomb.Off)
            {
                string settings = null;
                switch (profile.Decomb)
                {
                    case Decomb.Default:
                        break;
                    case Decomb.Fast:
                        settings = "7:2:6:9:1:80";
                        break;
                    case Decomb.Bob:
                        settings = "455";
                        break;
                    case Decomb.Custom:
                        settings = profile.CustomDecomb;
                        break;
                    default:
                        break;
                }

                this.AddFilter(filterList, (int)hb_filter_ids.HB_FILTER_DECOMB, settings, allocatedMemory);
            }

            // Deinterlace
            if (profile.Deinterlace != Deinterlace.Off)
            {
                nativeJob.deinterlace = 1;
                string settings = null;

                switch (profile.Deinterlace)
                {
                    case Deinterlace.Fast:
                        settings = "0";
                        break;
                    case Deinterlace.Slow:
                        settings = "1";
                        break;
                    case Deinterlace.Slower:
                        settings = "3";
                        break;
                    case Deinterlace.Bob:
                        settings = "15";
                        break;
                    case Deinterlace.Custom:
                        settings = profile.CustomDeinterlace;
                        break;
                    default:
                        break;
                }

                this.AddFilter(filterList, (int)hb_filter_ids.HB_FILTER_DEINTERLACE, settings, allocatedMemory);
            }
            else
            {
                nativeJob.deinterlace = 0;
            }

            // VFR
            if (profile.Framerate == 0)
            {
                if (profile.ConstantFramerate)
                {
                    // CFR with "Same as Source". Use the title rate
                    nativeJob.cfr = 1;
                    nativeJob.vrate = originalTitle.rate;
                    nativeJob.vrate_base = originalTitle.rate_base;
                }
                else
                {
                    // Pure VFR "Same as Source"
                    nativeJob.cfr = 0;
                }
            }
            else
            {
                // Specified framerate
                if (profile.ConstantFramerate)
                {
                    // Mark as pure CFR
                    nativeJob.cfr = 1;
                }
                else
                {
                    // Mark as peak framerate
                    nativeJob.cfr = 2;
                }

                nativeJob.vrate = 27000000;
                nativeJob.vrate_base = Converters.FramerateToVrate(profile.Framerate);
            }

            string vfrSettings = string.Format(CultureInfo.InvariantCulture, "{0}:{1}:{2}", nativeJob.cfr, nativeJob.vrate, nativeJob.vrate_base);
            this.AddFilter(filterList, (int)hb_filter_ids.HB_FILTER_VFR, vfrSettings, allocatedMemory);

            // Deblock
            if (profile.Deblock > 0)
            {
                this.AddFilter(filterList, (int)hb_filter_ids.HB_FILTER_DEBLOCK, profile.Deblock.ToString(CultureInfo.InvariantCulture), allocatedMemory);
            }

            // Denoise
            if (profile.Denoise != Denoise.Off)
            {
                string settings = null;
                switch (profile.Denoise)
                {
                    case Denoise.Weak:
                        settings = "2:1:1:2:3:3";
                        break;
                    case Denoise.Medium:
                        settings = "3:2:2:2:3:3";
                        break;
                    case Denoise.Strong:
                        settings = "7:7:7:5:5:5";
                        break;
                    case Denoise.Custom:
                        settings = profile.CustomDenoise;
                        break;
                    default:
                        break;
                }

                this.AddFilter(filterList, (int)hb_filter_ids.HB_FILTER_DENOISE, settings, allocatedMemory);
            }

            // Crop/scale
            int width = profile.Width;
            int height = profile.Height;

            int cropHorizontal = crop.Left + crop.Right;
            int cropVertical = crop.Top + crop.Bottom;

            if (width == 0)
            {
                width = title.Resolution.Width - cropHorizontal;
            }

            if (profile.MaxWidth > 0 && width > profile.MaxWidth)
            {
                width = profile.MaxWidth;
            }

            if (height == 0)
            {
                height = title.Resolution.Height - cropVertical;
            }

            if (profile.MaxHeight > 0 && height > profile.MaxHeight)
            {
                height = profile.MaxHeight;
            }

            // The job width can sometimes start not clean, due to interference from
            // preview generation. We reset it here to allow good calculations.
            nativeJob.width = width;
            nativeJob.height = height;

            nativeJob.grayscale = profile.Grayscale ? 1 : 0;

            switch (profile.Anamorphic)
            {
                case Anamorphic.None:
                    nativeJob.anamorphic.mode = 0;

                    Size outputSize = CalculateNonAnamorphicOutput(profile, title);
                    width = outputSize.Width;
                    height = outputSize.Height;

                    nativeJob.anamorphic.keep_display_aspect = profile.KeepDisplayAspect ? 1 : 0;

                    nativeJob.width = width;
                    nativeJob.height = height;

                    nativeJob.maxWidth = profile.MaxWidth;
                    nativeJob.maxHeight = profile.MaxHeight;

                    break;
                case Anamorphic.Strict:
                    nativeJob.anamorphic.mode = 1;

                    nativeJob.anamorphic.par_width = title.ParVal.Width;
                    nativeJob.anamorphic.par_height = title.ParVal.Height;
                    break;
                case Anamorphic.Loose:
                    nativeJob.anamorphic.mode = 2;

                    nativeJob.modulus = profile.Modulus;

                    nativeJob.width = width;

                    nativeJob.maxWidth = profile.MaxWidth;

                    nativeJob.anamorphic.par_width = title.ParVal.Width;
                    nativeJob.anamorphic.par_height = title.ParVal.Height;
                    break;
                case Anamorphic.Custom:
                    nativeJob.anamorphic.mode = 3;

                    nativeJob.modulus = profile.Modulus;

                    if (profile.UseDisplayWidth)
                    {
                        if (profile.KeepDisplayAspect)
                        {
                            int cropWidth = title.Resolution.Width - cropHorizontal;
                            int cropHeight = title.Resolution.Height - cropVertical;

                            double displayAspect = ((double)(cropWidth * title.ParVal.Width)) / (cropHeight * title.ParVal.Height);
                            int displayWidth = profile.DisplayWidth;

                            if (profile.Height > 0)
                            {
                                displayWidth = (int)((double)profile.Height * displayAspect);
                            }
                            else if (displayWidth > 0)
                            {
                                height = (int)((double)displayWidth / displayAspect);
                            }
                            else
                            {
                                displayWidth = (int)((double)height * displayAspect);
                            }

                            nativeJob.anamorphic.dar_width = displayWidth;
                            nativeJob.anamorphic.dar_height = height;
                            nativeJob.anamorphic.keep_display_aspect = 1;
                        }
                        else
                        {
                            nativeJob.anamorphic.dar_width = profile.DisplayWidth;
                            nativeJob.anamorphic.dar_height = height;
                            nativeJob.anamorphic.keep_display_aspect = 0;
                        }
                    }
                    else
                    {
                        nativeJob.anamorphic.par_width = profile.PixelAspectX;
                        nativeJob.anamorphic.par_height = profile.PixelAspectY;
                        nativeJob.anamorphic.keep_display_aspect = 0;
                    }

                    nativeJob.width = width;
                    nativeJob.height = height;

                    nativeJob.maxWidth = profile.MaxWidth;
                    nativeJob.maxHeight = profile.MaxHeight;

                    break;
                default:
                    break;
            }

            // Need to fix up values before adding crop/scale filter
            if (profile.Anamorphic != Anamorphic.None)
            {
                int anamorphicWidth = 0, anamorphicHeight = 0, anamorphicParWidth = 0, anamorphicParHeight = 0;

                HBFunctions.hb_set_anamorphic_size(ref nativeJob, ref anamorphicWidth, ref anamorphicHeight, ref anamorphicParWidth, ref anamorphicParHeight);
                nativeJob.width = anamorphicWidth;
                nativeJob.height = anamorphicHeight;
                nativeJob.anamorphic.par_width = anamorphicParWidth;
                nativeJob.anamorphic.par_height = anamorphicParHeight;
            }

            string cropScaleSettings = string.Format(
                CultureInfo.InvariantCulture,
                "{0}:{1}:{2}:{3}:{4}:{5}",
                nativeJob.width,
                nativeJob.height,
                nativeJob.crop[0],
                nativeJob.crop[1],
                nativeJob.crop[2],
                nativeJob.crop[3]);
            this.AddFilter(filterList, (int)hb_filter_ids.HB_FILTER_CROP_SCALE, cropScaleSettings, allocatedMemory);

            HBVideoEncoder videoEncoder = Encoders.VideoEncoders.FirstOrDefault(e => e.ShortName == profile.VideoEncoder);
            if (videoEncoder == null)
            {
                throw new ArgumentException("Video encoder " + profile.VideoEncoder + " not recognized.");
            }

            nativeJob.vcodec = videoEncoder.Id;

            // areBframes
            // color_matrix
            List<hb_audio_s> titleAudio = originalTitle.list_audio.ToList<hb_audio_s>();

            var audioList = new List<hb_audio_s>();
            int numTracks = 0;

            List<Tuple<AudioEncoding, int>> outputTrackList = this.GetOutputTracks(job, title);

            if (!string.IsNullOrEmpty(profile.AudioEncoderFallback))
            {
                HBAudioEncoder audioEncoder = Encoders.GetAudioEncoder(profile.AudioEncoderFallback);
                if (audioEncoder == null)
                {
                    throw new ArgumentException("Unrecognized fallback audio encoder: " + profile.AudioEncoderFallback);
                }

                nativeJob.acodec_fallback = Encoders.GetAudioEncoder(profile.AudioEncoderFallback).Id;
            }

            nativeJob.acodec_copy_mask = (int)NativeConstants.HB_ACODEC_ANY;

            foreach (Tuple<AudioEncoding, int> outputTrack in outputTrackList)
            {
                audioList.Add(this.ConvertAudioBack(outputTrack.Item1, titleAudio[outputTrack.Item2 - 1], numTracks++, allocatedMemory));
            }

            NativeList nativeAudioList = InteropUtilities.ConvertListBack<hb_audio_s>(audioList);
            nativeJob.list_audio = nativeAudioList.Ptr;
            allocatedMemory.AddRange(nativeAudioList.AllocatedMemory);

            if (job.Subtitles != null)
            {
                if (job.Subtitles.SourceSubtitles != null && job.Subtitles.SourceSubtitles.Count > 0)
                {
                    List<hb_subtitle_s> titleSubtitles = originalTitle.list_subtitle.ToList<hb_subtitle_s>();

                    foreach (SourceSubtitle sourceSubtitle in job.Subtitles.SourceSubtitles)
                    {
                        if (sourceSubtitle.TrackNumber == 0)
                        {
                            // Use subtitle search.
                            nativeJob.select_subtitle_config.force = sourceSubtitle.Forced ? 1 : 0;
                            nativeJob.select_subtitle_config.default_track = sourceSubtitle.Default ? 1 : 0;

                            if (!sourceSubtitle.BurnedIn)
                            {
                                nativeJob.select_subtitle_config.dest = hb_subtitle_config_s_subdest.PASSTHRUSUB;
                            }

                            nativeJob.indepth_scan = 1;
                        }
                        else
                        {
                            // Use specified subtitle.
                            hb_subtitle_s nativeSubtitle = titleSubtitles[sourceSubtitle.TrackNumber - 1];
                            var subtitleConfig = new hb_subtitle_config_s();

                            subtitleConfig.force = sourceSubtitle.Forced ? 1 : 0;
                            subtitleConfig.default_track = sourceSubtitle.Default ? 1 : 0;

                            bool supportsBurn = nativeSubtitle.source == hb_subtitle_s_subsource.VOBSUB || nativeSubtitle.source == hb_subtitle_s_subsource.SSASUB || nativeSubtitle.source == hb_subtitle_s_subsource.PGSSUB;
                            if (supportsBurn && sourceSubtitle.BurnedIn)
                            {
                                subtitleConfig.dest = hb_subtitle_config_s_subdest.RENDERSUB;
                            }
                            else
                            {
                                subtitleConfig.dest = hb_subtitle_config_s_subdest.PASSTHRUSUB;
                            }

                            int subtitleAddSucceded = HBFunctions.hb_subtitle_add(ref nativeJob, ref subtitleConfig, sourceSubtitle.TrackNumber - 1);
                            if (subtitleAddSucceded == 0)
                            {
                                System.Diagnostics.Debug.WriteLine("Subtitle add failed");
                            }
                        }
                    }
                }

                if (job.Subtitles.SrtSubtitles != null)
                {
                    foreach (SrtSubtitle srtSubtitle in job.Subtitles.SrtSubtitles)
                    {
                        var subtitleConfig = new hb_subtitle_config_s();

                        subtitleConfig.src_codeset = srtSubtitle.CharacterCode;
                        subtitleConfig.src_filename = srtSubtitle.FileName;
                        subtitleConfig.offset = srtSubtitle.Offset;
                        subtitleConfig.default_track = srtSubtitle.Default ? 1 : 0;

                        int srtAddSucceded = HBFunctions.hb_srt_add(ref nativeJob, ref subtitleConfig, srtSubtitle.LanguageCode);
                        if (srtAddSucceded == 0)
                        {
                            System.Diagnostics.Debug.WriteLine("SRT add failed");
                        }
                    }
                }

                bool hasBurnedSubtitle = job.Subtitles.SourceSubtitles != null && job.Subtitles.SourceSubtitles.Any(s => s.BurnedIn);
                if (hasBurnedSubtitle)
                {
                    this.AddFilter(filterList, (int)hb_filter_ids.HB_FILTER_RENDER_SUB, string.Format(CultureInfo.InvariantCulture, "{0}:{1}:{2}:{3}", crop.Top, crop.Bottom, crop.Left, crop.Right), allocatedMemory);
                }
            }

            // Construct final filter list
            nativeJob.list_filter = this.ConvertFilterListToNative(filterList, allocatedMemory).Ptr;

            if (profile.ScaleMethod == ScaleMethod.Bicubic)
            {
                HBFunctions.hb_get_opencl_env();
                nativeJob.use_opencl = 1;
            }
            else
            {
                nativeJob.use_opencl = 0;
            }

            nativeJob.qsv.decode = profile.QsvDecode ? 1 : 0;
            nativeJob.use_hwd = job.DxvaDecoding ? 1 : 0;

            #pragma warning disable 612, 618
            if (profile.OutputFormat == Container.Mp4)
            {
                nativeJob.mux = HBFunctions.hb_container_get_from_name("av_mp4");
            }
            else if (profile.OutputFormat == Container.Mkv)
            {
                nativeJob.mux = HBFunctions.hb_container_get_from_name("av_mkv");
            }
            #pragma warning restore 612, 618

            if (profile.ContainerName != null)
            {
                nativeJob.mux = HBFunctions.hb_container_get_from_name(profile.ContainerName);
            }

            if (job.OutputPath == null)
            {
                nativeJob.file = IntPtr.Zero;
            }
            else
            {
                IntPtr outputPathPtr = InteropUtilities.CreateUtf8Ptr(job.OutputPath);
                allocatedMemory.Add(outputPathPtr);
                nativeJob.file = outputPathPtr;
            }

            nativeJob.largeFileSize = profile.LargeFile ? 1 : 0;
            nativeJob.mp4_optimize = profile.Optimize ? 1 : 0;
            nativeJob.ipod_atom = profile.IPod5GSupport ? 1 : 0;

            if (title.AngleCount > 1)
            {
                nativeJob.angle = job.Angle;
            }

            switch (profile.VideoEncodeRateType)
            {
                case VideoEncodeRateType.ConstantQuality:
                    nativeJob.vquality = (float)profile.Quality;
                    nativeJob.vbitrate = 0;
                    break;
                case VideoEncodeRateType.AverageBitrate:
                    nativeJob.vquality = -1;
                    nativeJob.vbitrate = profile.VideoBitrate;
                    break;
                case VideoEncodeRateType.TargetSize:
                    nativeJob.vquality = -1;
                    nativeJob.vbitrate = this.CalculateBitrate(job, profile.TargetSize, overallSelectedLengthSeconds);
                    break;
                default:
                    break;
            }

            // frames_to_skip

            return allocatedMemory;
        }
Пример #14
0
 public static extern void hb_add(IntPtr hbHandle, ref hb_job_s job);
Пример #15
0
 public static extern void hb_set_job(IntPtr hbHandle, int title_index, ref hb_job_s job);
Пример #16
0
 public static extern void hb_job_set_encoder_options(ref hb_job_s job, IntPtr advanced_opts);
Пример #17
0
 public static extern void hb_add(IntPtr hbHandle, ref hb_job_s job);
Пример #18
0
 /// <summary>
 /// Adds a filter to the given filter list.
 /// </summary>
 /// <param name="job">
 /// The job.
 /// </param>
 /// <param name="filterType">
 /// The type of filter.
 /// </param>
 /// <param name="settings">
 /// Settings for the filter.
 /// </param>
 /// <param name="allocatedMemory">
 /// The list of allocated memory.
 /// </param>
 private void AddFilter(hb_job_s job, int filterType, string settings, List<IntPtr> allocatedMemory)
 {
     IntPtr settingsNativeString = Marshal.StringToHGlobalAnsi(settings);
     hb_filter_object_s filter = HBFunctions.hb_filter_init(filterType);
     HBFunctions.hb_add_filter(ref job, filter, settingsNativeString);
     allocatedMemory.Add(settingsNativeString);
 }
Пример #19
0
 public static extern int hb_subtitle_add(ref hb_job_s job, ref hb_subtitle_config_s subtitleConfig, int track);
Пример #20
0
        /// <summary>
        /// Applies the encoding job to the native memory structure and returns a list of memory
        /// locations allocated during this.
        /// </summary>
        /// <param name="nativeJob">The native structure to apply to job info to.</param>
        /// <param name="job">The job info to apply.</param>
        /// <param name="preview">True if this is a preview encode.</param>
        /// <param name="previewNumber">The preview number (0-based) to encode.</param>
        /// <param name="previewSeconds">The number of seconds in the preview.</param>
        /// <param name="overallSelectedLengthSeconds">The currently selected encode length. Used in preview
        /// for calculating bitrate when the target size would be wrong.</param>
        /// <returns>The list of memory locations allocated for the job.</returns>
        private List<IntPtr> ApplyJob(ref hb_job_s nativeJob, EncodeJob job, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds)
        {
            var allocatedMemory = new List<IntPtr>();
            Title title = this.GetTitle(job.Title);
            hb_title_s originalTitle = this.GetOriginalTitle(job.Title);

            EncodingProfile profile = job.EncodingProfile;

            if (preview)
            {
                nativeJob.start_at_preview = previewNumber + 1;
                nativeJob.seek_points = this.previewCount;

                // There are 90,000 PTS per second.
                nativeJob.pts_to_stop = previewSeconds * 90000;
            }
            else
            {
                switch (job.RangeType)
                {
                    case VideoRangeType.Chapters:

                        if (job.ChapterStart > 0 && job.ChapterEnd > 0)
                        {
                            nativeJob.chapter_start = job.ChapterStart;
                            nativeJob.chapter_end = job.ChapterEnd;
                        }
                        else
                        {
                            nativeJob.chapter_start = 1;
                            nativeJob.chapter_end = title.Chapters.Count;
                        }

                        break;
                    case VideoRangeType.Seconds:
                        if (job.SecondsStart < 0 || job.SecondsEnd < 0 || job.SecondsStart >= job.SecondsEnd)
                        {
                            throw new ArgumentException("Seconds range " + job.SecondsStart + "-" + job.SecondsEnd + " is invalid.", "job");
                        }

                        // For some reason "pts_to_stop" actually means the number of pts to stop AFTER the start point.
                        nativeJob.pts_to_start = (int)(job.SecondsStart * 90000);
                        nativeJob.pts_to_stop = (int)((job.SecondsEnd - job.SecondsStart) * 90000);
                        break;
                    case VideoRangeType.Frames:
                        if (job.FramesStart < 0 || job.FramesEnd < 0 || job.FramesStart >= job.FramesEnd)
                        {
                            throw new ArgumentException("Frames range " + job.FramesStart + "-" + job.FramesEnd + " is invalid.", "job");
                        }

                        // "frame_to_stop" actually means the number of frames total to encode AFTER the start point.
                        nativeJob.frame_to_start = job.FramesStart;
                        nativeJob.frame_to_stop = job.FramesEnd - job.FramesStart;
                        break;
                }
            }

            nativeJob.chapter_markers = profile.IncludeChapterMarkers ? 1 : 0;

            Cropping crop;

            if (profile.CustomCropping)
            {
                crop = profile.Cropping;
            }
            else
            {
                crop = title.AutoCropDimensions;
            }

            nativeJob.crop[0] = crop.Top;
            nativeJob.crop[1] = crop.Bottom;
            nativeJob.crop[2] = crop.Left;
            nativeJob.crop[3] = crop.Right;

            if (profile.Deinterlace != Deinterlace.Off)
            {
                nativeJob.deinterlace = 1;
                string settings = null;

                switch (profile.Deinterlace)
                {
                    case Deinterlace.Fast:
                        settings = "-1";
                        break;
                    case Deinterlace.Slow:
                        settings = "2";
                        break;
                    case Deinterlace.Slower:
                        settings = "0";
                        break;
                    case Deinterlace.Custom:
                        settings = profile.CustomDeinterlace;
                        break;
                    default:
                        break;
                }

                this.AddFilter(nativeJob, NativeConstants.HB_FILTER_DEINTERLACE, settings, allocatedMemory);
            }
            else
            {
                nativeJob.deinterlace = 0;
            }

            if (profile.Detelecine != Detelecine.Off)
            {
                string settings = null;
                if (profile.Detelecine == Detelecine.Custom)
                {
                    settings = profile.CustomDetelecine;
                }

                this.AddFilter(nativeJob, NativeConstants.HB_FILTER_DETELECINE, settings, allocatedMemory);
            }

            if (profile.Decomb != Decomb.Off)
            {
                string settings = null;
                if (profile.Decomb == Decomb.Custom)
                {
                    settings = profile.CustomDecomb;
                }

                this.AddFilter(nativeJob, NativeConstants.HB_FILTER_DECOMB, settings, allocatedMemory);
            }

            if (profile.Deblock > 0)
            {
                this.AddFilter(nativeJob, NativeConstants.HB_FILTER_DEBLOCK, profile.Deblock.ToString(), allocatedMemory);
            }

            if (profile.Denoise != Denoise.Off)
            {
                string settings = null;
                switch (profile.Denoise)
                {
                    case Denoise.Weak:
                        settings = "2:1:2:3";
                        break;
                    case Denoise.Medium:
                        settings = "3:2:2:3";
                        break;
                    case Denoise.Strong:
                        settings = "7:7:5:5";
                        break;
                    case Denoise.Custom:
                        settings = profile.CustomDenoise;
                        break;
                    default:
                        break;
                }

                this.AddFilter(nativeJob, NativeConstants.HB_FILTER_DENOISE, settings, allocatedMemory);
            }

            int width = profile.Width;
            int height = profile.Height;

            int cropHorizontal = crop.Left + crop.Right;
            int cropVertical = crop.Top + crop.Bottom;

            if (width == 0)
            {
                width = title.Resolution.Width - cropHorizontal;
            }

            if (profile.MaxWidth > 0 && width > profile.MaxWidth)
            {
                width = profile.MaxWidth;
            }

            if (height == 0)
            {
                height = title.Resolution.Height - cropVertical;
            }

            if (profile.MaxHeight > 0 && height > profile.MaxHeight)
            {
                height = profile.MaxHeight;
            }

            nativeJob.grayscale = profile.Grayscale ? 1 : 0;

            switch (profile.Anamorphic)
            {
                case Anamorphic.None:
                    nativeJob.anamorphic.mode = 0;

                    Size outputSize = CalculateNonAnamorphicOutput(profile, title);
                    width = outputSize.Width;
                    height = outputSize.Height;

                    nativeJob.anamorphic.keep_display_aspect = profile.KeepDisplayAspect ? 1 : 0;
                    break;
                case Anamorphic.Strict:
                    nativeJob.anamorphic.mode = 1;
                    break;
                case Anamorphic.Loose:
                    nativeJob.anamorphic.mode = 2;
                    break;
                case Anamorphic.Custom:
                    nativeJob.anamorphic.mode = 3;

                    nativeJob.modulus = profile.Modulus;

                    if (profile.UseDisplayWidth)
                    {
                        if (profile.KeepDisplayAspect)
                        {
                            int cropWidth = title.Resolution.Width - cropHorizontal;
                            int cropHeight = title.Resolution.Height - cropVertical;

                            double displayAspect = ((double)(cropWidth * title.ParVal.Width)) / (cropHeight * title.ParVal.Height);
                            int displayWidth = profile.DisplayWidth;

                            if (profile.Height > 0)
                            {
                                displayWidth = (int)((double)profile.Height * displayAspect);
                            }
                            else if (displayWidth > 0)
                            {
                                height = (int)((double)displayWidth / displayAspect);
                            }
                            else
                            {
                                displayWidth = (int)((double)cropHeight * displayAspect);
                            }

                            nativeJob.anamorphic.dar_width = displayWidth;
                            nativeJob.anamorphic.dar_height = height;
                            nativeJob.anamorphic.keep_display_aspect = 1;
                        }

                        nativeJob.anamorphic.dar_width = profile.DisplayWidth;
                        nativeJob.anamorphic.dar_height = height;
                        nativeJob.anamorphic.keep_display_aspect = profile.KeepDisplayAspect ? 1 : 0;
                    }
                    else
                    {
                        nativeJob.anamorphic.par_width = profile.PixelAspectX;
                        nativeJob.anamorphic.par_height = profile.PixelAspectY;
                        nativeJob.anamorphic.keep_display_aspect = 0;
                    }

                    break;
                default:
                    break;
            }

            nativeJob.width = width;
            nativeJob.height = height;

            nativeJob.maxWidth = profile.MaxWidth;
            nativeJob.maxHeight = profile.MaxHeight;

            HBVideoEncoder videoEncoder = Encoders.VideoEncoders.FirstOrDefault(e => e.ShortName == profile.VideoEncoder);
            if (videoEncoder == null)
            {
                throw new ArgumentException("Video encoder " + profile.VideoEncoder + " not recognized.");
            }

            nativeJob.vcodec = videoEncoder.Id;

            if (profile.Framerate == 0)
            {
                nativeJob.cfr = 0;
            }
            else
            {
                if (profile.PeakFramerate)
                {
                    nativeJob.cfr = 2;
                }
                else
                {
                    nativeJob.cfr = 1;
                }

                nativeJob.vrate = 27000000;
                nativeJob.vrate_base = Converters.FramerateToVrate(profile.Framerate);
            }

            // vfr
            // areBframes
            // color_matrix
            List<hb_audio_s> titleAudio = InteropUtilities.ConvertList<hb_audio_s>(originalTitle.list_audio);

            var audioList = new List<hb_audio_s>();
            int numTracks = 0;

            List<Tuple<AudioEncoding, int>> outputTrackList = this.GetOutputTracks(job, title);

            if (profile.AudioEncoderFallback != null)
            {
                nativeJob.acodec_fallback = Encoders.GetAudioEncoder(profile.AudioEncoderFallback).Id;
            }

            nativeJob.acodec_copy_mask = (int)NativeConstants.HB_ACODEC_ANY;

            foreach (Tuple<AudioEncoding, int> outputTrack in outputTrackList)
            {
                audioList.Add(this.ConvertAudioBack(outputTrack.Item1, titleAudio[outputTrack.Item2 - 1], numTracks++, allocatedMemory));
            }

            NativeList nativeAudioList = InteropUtilities.ConvertListBack<hb_audio_s>(audioList);
            nativeJob.list_audio = nativeAudioList.ListPtr;
            allocatedMemory.AddRange(nativeAudioList.AllocatedMemory);

            // Create a new empty list
            int totalSubtitles = 0;
            if (job.Subtitles != null)
            {
                if (job.Subtitles.SourceSubtitles != null)
                {
                    totalSubtitles += job.Subtitles.SourceSubtitles.Count;
                }

                if (job.Subtitles.SrtSubtitles != null)
                {
                    totalSubtitles += job.Subtitles.SrtSubtitles.Count;
                }
            }

            NativeList nativeSubtitleList = InteropUtilities.CreateNativeList(totalSubtitles + 2);
            nativeJob.list_subtitle = nativeSubtitleList.ListPtr;
            allocatedMemory.AddRange(nativeSubtitleList.AllocatedMemory);

            if (job.Subtitles != null)
            {
                if (job.Subtitles.SourceSubtitles != null && job.Subtitles.SourceSubtitles.Count > 0)
                {
                    List<hb_subtitle_s> titleSubtitles = InteropUtilities.ConvertList<hb_subtitle_s>(originalTitle.list_subtitle);

                    foreach (SourceSubtitle sourceSubtitle in job.Subtitles.SourceSubtitles)
                    {
                        if (sourceSubtitle.TrackNumber == 0)
                        {
                            // Use subtitle search.
                            nativeJob.select_subtitle_config.force = sourceSubtitle.Forced ? 1 : 0;
                            nativeJob.select_subtitle_config.default_track = sourceSubtitle.Default ? 1 : 0;

                            if (!sourceSubtitle.BurnedIn)
                            {
                                nativeJob.select_subtitle_config.dest = hb_subtitle_config_s_subdest.PASSTHRUSUB;
                            }

                            nativeJob.indepth_scan = 1;
                        }
                        else
                        {
                            // Use specified subtitle.
                            hb_subtitle_s nativeSubtitle = titleSubtitles[sourceSubtitle.TrackNumber - 1];
                            var subtitleConfig = new hb_subtitle_config_s();

                            subtitleConfig.force = sourceSubtitle.Forced ? 1 : 0;
                            subtitleConfig.default_track = sourceSubtitle.Default ? 1 : 0;

                            bool supportsBurn = nativeSubtitle.source == hb_subtitle_s_subsource.VOBSUB || nativeSubtitle.source == hb_subtitle_s_subsource.SSASUB;
                            if (supportsBurn && sourceSubtitle.BurnedIn)
                            {
                                subtitleConfig.dest = hb_subtitle_config_s_subdest.RENDERSUB;
                            }
                            else
                            {
                                subtitleConfig.dest = hb_subtitle_config_s_subdest.PASSTHRUSUB;
                            }

                            int subtitleAddSucceded = HBFunctions.hb_subtitle_add(ref nativeJob, ref subtitleConfig, sourceSubtitle.TrackNumber - 1);
                            if (subtitleAddSucceded == 0)
                            {
                                System.Diagnostics.Debug.WriteLine("Subtitle add failed");
                            }
                        }
                    }
                }

                if (job.Subtitles.SrtSubtitles != null)
                {
                    foreach (SrtSubtitle srtSubtitle in job.Subtitles.SrtSubtitles)
                    {
                        var subtitleConfig = new hb_subtitle_config_s();

                        subtitleConfig.src_codeset = srtSubtitle.CharacterCode;
                        subtitleConfig.src_filename = srtSubtitle.FileName;
                        subtitleConfig.offset = srtSubtitle.Offset;
                        subtitleConfig.default_track = srtSubtitle.Default ? 1 : 0;

                        int srtAddSucceded = HBFunctions.hb_srt_add(ref nativeJob, ref subtitleConfig, srtSubtitle.LanguageCode);
                        if (srtAddSucceded == 0)
                        {
                            System.Diagnostics.Debug.WriteLine("SRT add failed");
                        }
                    }
                }
            }

            if (profile.OutputFormat == Container.Mp4)
            {
                nativeJob.mux = NativeConstants.HB_MUX_MP4;
            }
            else
            {
                nativeJob.mux = NativeConstants.HB_MUX_MKV;
            }

            nativeJob.file = job.OutputPath;

            nativeJob.largeFileSize = profile.LargeFile ? 1 : 0;
            nativeJob.mp4_optimize = profile.Optimize ? 1 : 0;
            nativeJob.ipod_atom = profile.IPod5GSupport ? 1 : 0;

            if (title.AngleCount > 1)
            {
                nativeJob.angle = job.Angle;
            }

            switch (profile.VideoEncodeRateType)
            {
                case VideoEncodeRateType.ConstantQuality:
                    nativeJob.vquality = (float)profile.Quality;
                    nativeJob.vbitrate = 0;
                    break;
                case VideoEncodeRateType.AverageBitrate:
                    nativeJob.vquality = -1;
                    nativeJob.vbitrate = profile.VideoBitrate;
                    break;
                case VideoEncodeRateType.TargetSize:
                    nativeJob.vquality = -1;
                    nativeJob.vbitrate = this.CalculateBitrate(job, profile.TargetSize, overallSelectedLengthSeconds);
                    break;
                default:
                    break;
            }

            // frames_to_skip

            return allocatedMemory;
        }
Пример #21
0
 public static extern int hb_srt_add(ref hb_job_s job, ref hb_subtitle_config_s subtitleConfig, string lang);
Пример #22
0
 public static extern void hb_job_reset(ref hb_job_s job);
Пример #23
0
 public static extern void hb_autopassthru_apply_settings(ref hb_job_s job);
Пример #24
0
 public static extern void hb_job_set_file(ref hb_job_s job, IntPtr file);
Пример #25
0
 public static extern void hb_job_reset(ref hb_job_s job);
Пример #26
0
 public static extern void hb_autopassthru_apply_settings(ref hb_job_s job);
Пример #27
0
 public static extern void hb_job_set_encoder_options(ref hb_job_s job, IntPtr advanced_opts);
Пример #28
0
 public static extern void hb_set_job(IntPtr hbHandle, int title_index, ref hb_job_s job);
Пример #29
0
 public static extern void hb_job_set_file(ref hb_job_s job, IntPtr file);
Пример #30
0
 public static extern int hb_srt_add(ref hb_job_s job, ref hb_subtitle_config_s subtitleConfig, string lang);
Пример #31
0
 public static extern void hb_add_filter(ref hb_job_s job, ref hb_filter_object_s filter, IntPtr settings);
Пример #32
0
 public static extern int hb_subtitle_add(ref hb_job_s job, ref hb_subtitle_config_s subtitleConfig, int track);
Пример #33
0
 public static extern void hb_job_close(ref hb_job_s job);