Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting Handbrake encoder to work

I am unable to get Handbrake to work for me in C#. It keeps throwing the error "Value cannot be null." . As you can see in the screenshot below, I've tried a couple of things based on what I know. I would appreciate any of your guidance to help me get this work.

Handbrake Encoder error

What I've tried so far (points are not relevant to the error displayed..Just FYI) :

  1. Installed handbrake on my pc
  2. Added a reference to HandBrakeInterop.dll
  3. Copied all the other required dlls to my debug folder and even tried adding them as references
  4. Tried changing debug versions from x86/x64

Where am I not on the right track?

Here's my code :

      HandBrake.Interop.HandBrakeInstance objHb = new HandBrake.Interop.HandBrakeInstance();
    HandBrake.Interop.Model.EncodeJob objJob = new HandBrake.Interop.Model.EncodeJob();
    objJob.SourceType = HandBrake.Interop.Model.SourceType.File;
    EncodingProfile objProfile = new EncodingProfile();
    objProfile.OutputFormat = Container.Mp4;
    objProfile.VideoEncodeRateType = VideoEncodeRateType.ConstantQuality;
    objProfile.IPod5GSupport = true;
    objProfile.PreferredExtension = OutputExtension.Mp4;
   // objJob.EncodingProfile = objProfile;
    objJob.SourcePath = AppDomain.CurrentDomain.BaseDirectory + "1.flv";
    objJob.OutputPath = AppDomain.CurrentDomain.BaseDirectory + "1.mp4";
    //objHb.Titles.Add(new HandBrake.Interop.SourceData.Title());

    XmlSerializer objSerializer = new XmlSerializer(typeof(EncodingProfile));


   MemoryStream mem=new MemoryStream(File.ReadAllBytes(AppDomain.CurrentDomain.BaseDirectory + "normal.xml"));
 var objPresetFromFile =  objSerializer.Deserialize(mem) as EncodingProfile;
 objJob.EncodingProfile = objPresetFromFile;
    objJob.UseDefaultChapterNames = true;
   // objJob.Title = 1;



    //HandBrake.Interop.Model.Encoders
    objHb.EncodeProgress += objHb_EncodeProgress;
    objHb.EncodeCompleted += objHb_EncodeCompleted;
    HandBrake.ApplicationServices.Parsing.Title title = new HandBrake.ApplicationServices.Parsing.Title();// new HandBrake.Interop.SourceData.Title();
    objHb.Initialize(5);
    //objHb.Titles = new System.Collections.Generic.List<HandBrake.Interop.SourceData.Title>();
    objHb.StartScan(AppDomain.CurrentDomain.BaseDirectory + "1.flv", 0);
    objJob.SourceType = HandBrake.Interop.Model.SourceType.File;
    objJob.RangeType = HandBrake.Interop.Model.VideoRangeType.Frames;

    objHb.StartEncode(objJob);

    Console.ReadLine();

EDIT : As requested,here's more info from the exception copied to clipboard

System.ArgumentNullException was unhandled
  HResult=-2147467261
  Message=Value cannot be null.
Parameter name: source
  Source=System.Core
  ParamName=source
  StackTrace:
       at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
       at HandBrake.Interop.HandBrakeInstance.GetTitle(Int32 titleNumber) in c:\HandBrake\Hudson\workspace\Release_WindowsGui64\0.9.9\win\CS\HandBrake.Interop\HandBrakeInterop\HandBrakeInstance.cs:line 1604
       at HandBrake.Interop.HandBrakeInstance.GetTitleIndex(Int32 titleNumber) in c:\HandBrake\Hudson\workspace\Release_WindowsGui64\0.9.9\win\CS\HandBrake.Interop\HandBrakeInterop\HandBrakeInstance.cs:line 1614
       at HandBrake.Interop.HandBrakeInstance.StartEncode(EncodeJob job, Boolean preview, Int32 previewNumber, Int32 previewSeconds, Double overallSelectedLengthSeconds) in c:\HandBrake\Hudson\workspace\Release_WindowsGui64\0.9.9\win\CS\HandBrake.Interop\HandBrakeInterop\HandBrakeInstance.cs:line 411
       at HandBrake.Interop.HandBrakeInstance.StartEncode(EncodeJob jobToStart) in c:\HandBrake\Hudson\workspace\Release_WindowsGui64\0.9.9\win\CS\HandBrake.Interop\HandBrakeInterop\HandBrakeInstance.cs:line 395
       at HandBrakeTest.Program.Main(String[] args) in c:\Users\user\Documents\Visual Studio 2012\Projects\HandBrakeTest\HandBrakeTest\Program.cs:line 53
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

Edit :

  1. Moved handbrakeinstance and encodingjob's instance outside main and made them static
  2. Calling StartEncode in scan completed event

Now, the exception is Nullreferenceexception with this in the details :

System.NullReferenceException was unhandled by user code
  HResult=-2147467261
  Message=Object reference not set to an instance of an object.
  Source=HandBrakeInterop
  StackTrace:
       at HandBrake.Interop.InteropUtilities.ReadStructure[T](IntPtr structPtr) in c:\HandBrake\Hudson\workspace\Release_WindowsGui64\0.9.9\win\CS\HandBrake.Interop\HandBrakeInterop\InteropUtilities.cs:line 31
       at HandBrake.Interop.HandBrakeInstance.StartEncode(EncodeJob job, Boolean preview, Int32 previewNumber, Int32 previewSeconds, Double overallSelectedLengthSeconds) in c:\HandBrake\Hudson\workspace\Release_WindowsGui64\0.9.9\win\CS\HandBrake.Interop\HandBrakeInterop\HandBrakeInstance.cs:line 412
       at HandBrake.Interop.HandBrakeInstance.StartEncode(EncodeJob jobToStart) in c:\HandBrake\Hudson\workspace\Release_WindowsGui64\0.9.9\win\CS\HandBrake.Interop\HandBrakeInterop\HandBrakeInstance.cs:line 395
       at HandBrakeTest.Program.objHb_ScanCompleted(Object sender, EventArgs e) in c:\Users\user\Documents\Visual Studio 2012\Projects\HandBrakeTest\HandBrakeTest\Program.cs:line 65
       at HandBrake.Interop.HandBrakeInstance.PollScanProgress() in c:\HandBrake\Hudson\workspace\Release_WindowsGui64\0.9.9\win\CS\HandBrake.Interop\HandBrakeInterop\HandBrakeInstance.cs:line 811
       at HandBrake.Interop.HandBrakeInstance.<StartScan>b__2(Object o, ElapsedEventArgs e) in c:\HandBrake\Hudson\workspace\Release_WindowsGui64\0.9.9\win\CS\HandBrake.Interop\HandBrakeInterop\HandBrakeInstance.cs:line 752
       at System.Timers.Timer.MyTimerCallback(Object state)
  InnerException: 

Thanks in advance.

like image 572
Josh Avatar asked May 26 '13 18:05

Josh


People also ask

Does HandBrake use CPU or GPU for encoding?

Video encoding is one of the most resource intensive activities for computers. HandBrake's software video encoders, video filters, audio encoders, and other processes benefit from fast CPU and memory. HandBrake's hardware video encoders also benefit from modern GPU hardware.

What encoder preset should I use HandBrake?

The x264 software encoder presents an excellent balance between speed and quality, and the H. 264/AVC video it creates is widely compatible with all modern devices. It is the default video encoder in most of HandBrake's official Presets .

What is start encode in HandBrake?

Starting the encodeThe Toolbar provides easy access to HandBrake's most common functions. Video encoding requires a lot of computer resources and can take awhile to complete. Some videos may take minutes to create; others may take hours. HandBrake reports its progress during encoding.


1 Answers

Yeah HandBrakeInterop isn't the easiest API to just write some code for; it's more geared toward full encoder GUIs right now; it doesn't fall back on defaults very well. You had a really good idea in just taking the EncodingProfile from the XML.

Here's a working, minimal project that interacts with HandBrakeInterop: http://engy.us/misc/HandBrakeInteropExample.zip

Some relevant bits:

instance = new HandBrakeInstance();
instance.Initialize(verbosity: 1);
instance.ScanCompleted += instance_ScanCompleted;
instance.StartScan(SourceFile, previewCount: 10);
  • 1 is the default verbosity. The "5" you were passing in isn't valid.
  • You'll probably want to pass in a real value for the previewCount on StartScan: it uses these static previews to do things like automatic cropping detection and combing detection.
var job = new EncodeJob
    {
        EncodingProfile = profile,
        RangeType = VideoRangeType.All,
        Title = 1,
        SourcePath = SourceFile,
        OutputPath = AppDomain.CurrentDomain.BaseDirectory + "Output.mp4",
        ChosenAudioTracks = new List { 1 },
        Subtitles = new Subtitles
            {
                SourceSubtitles = new List(),
                SrtSubtitles = new List()
            }
    };
  • You need to pass in which title to encode (1-based index). For files this is rarely relevant; the feature is designed for DVD/Blu-ray scans.
  • You have to pass in both a RangeType and the specifics for the range: for example if you pick a RangeType of Frames then you need to specify FramesStart and FramesEnd. RangeType.All is easiest since you don't need to specify anything extra.
  • You need to specify a list of the chosen audio tracks indices (1-based). Not normally useful for files, but for DVD/Blu-ray discs that have multiple languages.
  • Right now you have to give it something under Subtitles or it will crash out. This is actually a bug; there were a few cases I wasn't guarding correctly. I'll fix this up in the future.

Check out VidCoder if you want to see a full reference implementation of the API. HandBrake has started to use it some but it hasn't gotten around to all the features like static previews and pause/resume.

Update: The code required now looks completely different and targets HandBrake.ApplicationServices.dll. New minimal project: http://engy.us/misc/HBInteropExampleV3.zip

A notable difference is that the encode job is now specified in JSON. This is the exact same JSON blob that is spit out in the encode log in HandBrake/VidCoder, so you can steal it from there and tweak it.

like image 81
RandomEngy Avatar answered Sep 26 '22 15:09

RandomEngy