FAQ  •  Register  •  Login

Aspect ratio issue with H265 to MPEG2 (Sony TV HX800)

<<

DenyAll

DLNA master

Posts: 2257

Joined: Fri Mar 08, 2013 11:16 pm

Location: Adelaide, Australia

Post Wed Aug 03, 2016 3:43 am

Re: Aspect ratio issue with H265 to MPEG2 (Sony TV HX800)

OK, it was a long shot - I was hoping the change of frame size may have fixed it (by reducing the height, I was hoping the width would be rounded to a frame size that's exactly 16:9).

The issue that I think we have here is that your TV doesn't like the DAR of 479:269 in the video stream (and the 1916 x 1076 frame size).

I fixed this in your sample.mkv by re-encoding the video and stretching it to 1920x1080 - the problem with that approach is that it (a) re-encodes the video (always results in a quality loss - whether perceivable or not is questionable) and (b) slightly distorts the video (stretches it). I used the command:

    ffmpeg -i sample.mkv -vf "scale=1920x1080,setsar=1:1,setdar=16:9" output.mkv

Another approach is to pad the video. This still re-encodes the video but doesn't stretch it. I used (but we didn't test on your TV):

    ffmpeg -i sample.mkv -vf "pad=1920:1080:2:2:black,setsar=1:1,setdar=16:9" output.mkv

ps. The setsar=1:1,setdar=16:9 components may not be needed in the above, but without your TV to test... also note that in both case the video is converted to h264 - not sure why, I suspect this is due to my ffmpeg version (requires libx265 is my guess).

So where to from here: this issue seems particular to your TV (video plays fine on my devices after transcoding). I'm not sure if you encoded you're own video or downloaded them but if encoding, make sure you set the video DAR to 16:9 and the frame size to 1920x1080. If downloaded, try downloading another HEVC version of the video (and check it with fmmpeg -i to see that the video stream DAR is 16:9). If you need to re-encode your existing videos, either method should work (I'd probably favor padding for 2 pixels), but you need to work out why its not encoding to h265 (try downloading zanoe's latest ffmpeg). I've probably gone as far as I can without having your TV.
DenyAll
Panasonic Viera FX800A | Panasonic Viera CS610A | Sony PS4 | Sony PS3 | Panasonic DMP-BD79 | Yamaha RX-V500D | iPad | Windows 10 | Serviio 1.10.1 Pro
WinHelper | MediaInfo

Beta Tester, Moderator
Please do not PM me for support as any solution cannot be shared with others.
<<

galmok

Serviio lover

Posts: 69

Joined: Thu Jul 28, 2011 9:35 pm

Post Wed Aug 03, 2016 9:17 am

Re: Aspect ratio issue with H265 to MPEG2 (Sony TV HX800)

Thank you for your analysis! I really appreciate your assistance here.

I think my solution will have to be to intercept the transcoding (the call to ffmpeg).

Is there an easy way to inercept the ffmpeg call and have it call something else instead?

If so, I'd create a script that examines the source video using ffmpeg and then adds the padding if necessary.
<<

DenyAll

DLNA master

Posts: 2257

Joined: Fri Mar 08, 2013 11:16 pm

Location: Adelaide, Australia

Post Thu Aug 04, 2016 5:53 am

Re: Aspect ratio issue with H265 to MPEG2 (Sony TV HX800)

Yes, you need a ffmpeg wrapper - search the forum but one quick on I found was jhb50's post here: viewtopic.php?f=3&t=21017&p=104608
DenyAll
Panasonic Viera FX800A | Panasonic Viera CS610A | Sony PS4 | Sony PS3 | Panasonic DMP-BD79 | Yamaha RX-V500D | iPad | Windows 10 | Serviio 1.10.1 Pro
WinHelper | MediaInfo

Beta Tester, Moderator
Please do not PM me for support as any solution cannot be shared with others.
<<

galmok

Serviio lover

Posts: 69

Joined: Thu Jul 28, 2011 9:35 pm

Post Thu Aug 04, 2016 10:56 am

Re: Aspect ratio issue with H265 to MPEG2 (Sony TV HX800)

Ok. Does it have to be an exe file? I have created a bat file, but Serviio stops without telling me why. I added it like this in the ServiioService.exe.vmoptions file:

-Dffmpeg.location=C:\Tools\FFMPEGWrapper\ffmpegwrap.bat


The log has this to say:

2016-08-04 12:36:28,258 DEBUG [FFMPEGWrapper] Invoking FFMPEG to check if it exists of path C:\Tools\FFMPEGWrapper\ffmpegwrap.bat
2016-08-04 12:36:28,261 DEBUG [ProcessExecutor] Starting C:\Tools\FFMPEGWrapper\ffmpegwrap.bat

I am not given any error codes or exceptions in the log. :-/

Changing the bat file to run ffmpeg directly works and shows this in the log:

2016-08-04 12:40:51,861 DEBUG [FFMPEGWrapper] Invoking FFMPEG to check if it exists of path C:\Tools\FFMPEGWrapper\ffmpegwrap.bat
2016-08-04 12:40:51,864 DEBUG [ProcessExecutor] Starting C:\Tools\FFMPEGWrapper\ffmpegwrap.bat
2016-08-04 12:40:51,906 INFO [FFMPEGWrapper] Found FFmpeg: C:\Tools\FFMPEGWrapper\ffmpegwrap.bat
2016-08-04 12:40:51,907 INFO [FFMPEGWrapper] FFmpeg details: [version=2.4.git, libRtpmPresent=true, libAssPresent=true, libShinePresent=false]

So while bat file execution works, my script seems not to respond as Serviio expects. I have checked both the errorlevel and stdout/stderr and it is identical. I am not sure how Serviio can tell the difference in how my bat file produces the output.
<<

galmok

Serviio lover

Posts: 69

Joined: Thu Jul 28, 2011 9:35 pm

Post Thu Aug 04, 2016 11:14 am

Re: Aspect ratio issue with H265 to MPEG2 (Sony TV HX800)

Ok, I just made a simple mistake and my wrapper works. But it seems Serviio is using the -complex_filter option and it conflicts with -vf:

Filtergraph 'pad=1920:1080:2:2:black,setsar=1/1,setdar=16/9' was specified through the -vf/-af/-filter option for output stream 0:0, which is fed from a complex filtergraph.
-vf/-af/-filter and -filter_complex cannot be used together for the same stream.


I guess I have to work out how to convert the vf argument into a complex_filter argument and merge it with any existing complex_filter argument. :-/
<<

galmok

Serviio lover

Posts: 69

Joined: Thu Jul 28, 2011 9:35 pm

Post Thu Aug 04, 2016 1:14 pm

Re: Aspect ratio issue with H265 to MPEG2 (Sony TV HX800)

I have now created a script to fix aspect ratio and padding. I have not experimented which is necessary and which is not ye, but I want to give the script to help others in the same situation:

First I have the bat file that acts as ffmpeg.exe:

  Code:
@echo off
echo Args^: %* >> C:\Tools\FFMPEGWrapper\ffmpegwrap.log
cscs /nl C:\Tools\FFMPEGWrapper\ffmpegwrap.cs %*
rem "C:\Program Files (x86)\Serviio\lib\ffmpeg.exe" %*
echo ErrorLevel^: %errorlevel% >> C:\Tools\FFMPEGWrapper\ffmpegwrap.log


The bat file is loaded by Serviio by modifying the ServiioService.exe.vmoptions file by adding this line:

-Dffmpeg.location=C:\Tools\FFMPEGWrapper\ffmpegwrap.bat

As can be seen, I am using cs-script (cscs) which means I programmed it in C# and can avoid having to compile an exe file for each change. It allows for easy modifications, like scripts usually allow for.

Here is the script that performs all the work. Please excuse the less than pretty code, but it was written with Notepad++ and it had a tendency to work against me:

  Code:
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System;
using System.Linq;

// Written by: galmok@gmail.com
public class Program {
   public static int Main(string[] argv) {
      //Console.WriteLine("Hello World");
      //foreach(var arg in argv)
      //   Console.WriteLine(arg);
      // find the argument after the "-i" argument
      var iIndex = Array.FindIndex(argv, e => e == "-i");
      if (iIndex >= 0) {
         string inputFile = argv[iIndex + 1]; // slightly weak point here. Should check out of bounds here.
         //Console.WriteLine("Input file: {0}", inputFile);
         string ffmpegInfo = Program.GetFFMPEGFileInformation(inputFile);
         //Console.WriteLine("FFMPEG Information: {0}", ffmpegInfo);
         string stream = ffmpegInfo
            .Split('\n')
            .Where(x => x.Trim().StartsWith("Stream"))
            .Where(x => x.Contains("Video:"))
            .Where(x => x.Contains(" hevc "))
            .Select(x => x)
            .FirstOrDefault();
         //Console.WriteLine("stream line: {0}", stream);
         if (!string.IsNullOrEmpty(stream))
         {
            // this is a h265 file that needs further checking.
            var parts = Regex.Matches(stream, @"[^,]+\(.+?\)|[^,]+")
               .Cast<Match>()
               .Select(m => m.Value)
               .Where(x => x.Contains("SAR"))
               .Where(x => x.Contains("DAR"))
               .ToList();
            foreach(var part in parts)
            {
               // Look for this: 1976x1076 [SAR 1:1 DAR 479:269]
               var m = Regex.Match(part, @"([0-9]+)x([0-9]+) \[SAR ([0-9]+):([0-9]+) DAR ([0-9]+):([0-9]+)\]");
               //Console.WriteLine("part: {0} {1}", part, m.Success);
               if (m.Success) {
                  var width = int.Parse(m.Groups[1].Value);
                  var height = int.Parse(m.Groups[2].Value);
                  var SARnum = double.Parse(m.Groups[3].Value);
                  var SARdenom = double.Parse(m.Groups[4].Value);
                  var DARnum = double.Parse(m.Groups[5].Value);
                  var DARdenom = double.Parse(m.Groups[6].Value);
                  //Console.WriteLine("width: {0} height: {1}", width, height);
                  //Console.WriteLine("SAR: {0}:{1} = {2} [{3}]", SARnum, SARdenom, SARnum/SARdenom, GetClosestAspectRatio(SARnum, SARdenom));
                  //Console.WriteLine("DAR: {0}:{1} = {2} [{3}]", DARnum, DARdenom, DARnum/DARdenom, GetClosestAspectRatio(DARnum, DARdenom));
                  int widthPad = (width % 16)==0? width:((width/16)+1)*16;
                  int heightPad = (height % 8)==0? height:((height/8)+1)*8;
                  //Console.WriteLine("widthPad: {0} heightPad: {1}", widthPad, heightPad);
                  
                  var padLeft = (widthPad-width)/2;
                  var padTop = (heightPad-height)/2;
                  var cfIndex = Array.FindIndex(argv, e => e == "-filter_complex");
                  if (cfIndex >= 0) {
                     // -vf argument conflicts with -filter_complex argument
                     // filter_complex example argument: [0:v]scale=1282:720[v]
                     // result like: [0:v]pad:1920x1080:2:2:black,setsar=ratio=1:1,setdar=ratio:16:9,scale=1282:720[v]
                     string cfParam = string.Format("pad={0}:{1}:{2}:{3}:black,setsar=ratio={4},setdar=ratio={5}", widthPad, heightPad, padLeft, padTop, GetClosestAspectRatio(SARnum, SARdenom), GetClosestAspectRatio(DARnum, DARdenom));
                     string oldCfParam = argv[cfIndex+1];
                     var tmp = argv.ToList();
                     m = Regex.Match(oldCfParam,@"(\[0:v\])(.*)");
                     if (m.Success) {
                        // video stream is already to be modified. Prepend my changes.
                        var part1 = m.Groups[1].Value;
                        var part2 = m.Groups[2].Value;
                        var newCfParam = string.Format("{0}{1},{2}", part1, cfParam, part2);
                        argv[cfIndex+1] = newCfParam;
                     } else {
                        // no video stream changes: Just add my changes.
                        argv[cfIndex+1] = string.Format("{0};[0:v] {1} [v]", oldCfParam, cfParam);
                     }
                  } else {
                     // construct: -vf "pad=1920:1080:2:2:black,setsar=1/1,setdar=16/9"
                     string vfArg = string.Format("pad={0}:{1}:{2}:{3}:black,setsar={4},setdar={5}", widthPad, heightPad, padLeft, padTop, GetClosestAspectRatio(SARnum, SARdenom), GetClosestAspectRatio(DARnum, DARdenom));
                     //Console.WriteLine("vfArg: {0}", vfArg);
                     var tmp = argv.ToList();
                     tmp.Insert(iIndex+2,"-vf");
                     tmp.Insert(iIndex+3,vfArg);
                     argv=tmp.ToArray();
                  }
                  foreach(var arg in argv)
                     Console.WriteLine("{0} => {1}", arg, EncodeParameterArgument(arg));
               }
            }
         }
      }
      // now run ffmpeg
      return RunFFMPEG(argv);
   }
   
   static string GetClosestAspectRatio(double num, double demon) {
      List<KeyValuePair<double,string>> knownAspects = new List<KeyValuePair<double,string>>{
         new KeyValuePair<double,string>((double)1, "1/1"),
         new KeyValuePair<double,string>((double)4/(double)3, "4/3"),
         new KeyValuePair<double,string>((double)16/(double)9, "16/9")
      };
      string result = null;
      double? dist = null;
      foreach(var aspect in knownAspects) {
         if (!dist.HasValue || Math.Abs(aspect.Key - (num/demon)) < (double)dist) {
            dist = Math.Abs(aspect.Key - (num/demon));
            result = aspect.Value;
         }
      }
      return result;
   }
   
   static string GetFFMPEGFileInformation(string filename) {
      var processStartInfo = new ProcessStartInfo
      {
         FileName = @"C:\Program Files (x86)\Serviio\lib\ffmpeg.exe",
         Arguments = "-i " + EncodeParameterArgument(filename),
         RedirectStandardOutput = false,
         RedirectStandardError = true,
         UseShellExecute = false
      };
      var process = Process.Start(processStartInfo);
      var output = process.StandardError.ReadToEnd();
      process.WaitForExit();
      return output;
   }
   
   static int RunFFMPEG(string[] argv)
   {
      var arguments = string.Join(" ", argv.Select(x => EncodeParameterArgument(x)));
      //Console.WriteLine("args: {0}", arguments);
      var processStartInfo = new ProcessStartInfo
      {
         FileName = @"C:\Program Files (x86)\Serviio\lib\ffmpeg.exe",
         Arguments = arguments,
         RedirectStandardOutput = false,
         RedirectStandardError = false,
         UseShellExecute = false
      };
      var process = new Process();
      process.StartInfo = processStartInfo;
      process.Start();
      process.WaitForExit();
      return process.ExitCode;
   }
   
   /// From StackOverflow.com:

   /// <summary>
   /// Encodes an argument for passing into a program
   /// </summary>
   /// <param name="original">The value that should be received by the program</param>
   /// <returns>The value which needs to be passed to the program for the original value
   /// to come through</returns>
   public static string EncodeParameterArgument(string original)
   {
      if( string.IsNullOrEmpty(original))
         return original;
      string value = Regex.Replace(original, @"(\\*)" + "\"", @"$1\$0");
      value = Regex.Replace(value, @"^(.*\s.*?)(\\*)$", "\"$1$2$2\"");
      return value;
   }
}


It will only modify arguments if there is a hevc (h265) video stream in the file that has SAR and DAR defined (I guess all files have them, but I check for it anyway). It will either add video filter (-vf) if -complex_filter is missing, will add video filter in complex_filter if there is only audio or will modify the existing video filter given with -complex_filter. It will lock aspect ratios to 1:1, 4:3 or 16:9 for both SAR and DAR. This may show not to be enough, but more aspect ratios are easily added.

At least I can have my hevc files with bad sizes/aspect ratios converted to mpeg2 in proper sizes/aspect ratios (at least good enough to allow my TV to show them properly).
<<

Solomonemee

Serviio newbie

Posts: 1

Joined: Fri Aug 12, 2016 9:20 am

Post Fri Aug 12, 2016 9:33 am

Re: Aspect ratio issue with H265 to MPEG2 (Sony TV HX800)

At first, I want to say that video aspect ratio is the proportion between width and height of the video image. It determines display effect directly when you play video files on various devices. Maybe you need a converter to help you change aspect ratio of video in almost all formats, such as MKV, MP4, AVI, MOV, WMV and even DV, MTS, H265 and VP9 video, and HD video formats.You can download some good software from internet,like factoryfab, dvdfab or something else.
<<

galmok

Serviio lover

Posts: 69

Joined: Thu Jul 28, 2011 9:35 pm

Post Sat Aug 13, 2016 7:29 am

Re: Aspect ratio issue with H265 to MPEG2 (Sony TV HX800)

Solomonemee wrote:At first, I want to say that video aspect ratio is the proportion between width and height of the video image. It determines display effect directly when you play video files on various devices. Maybe you need a converter to help you change aspect ratio of video in almost all formats, such as MKV, MP4, AVI, MOV, WMV and even DV, MTS, H265 and VP9 video, and HD video formats.You can download some good software from internet,like factoryfab, dvdfab or something else.


Thanks, but I am not going to modify my source material if I in any way can avoid it. My current solution has solved it quite nicely.
Previous

Return to Transcoding

Who is online

Users browsing this forum: No registered users and 11 guests

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.