add support for AV2 CTC test for RA and LD configuration
1. use a class to define the clip information
2. add support for using HDRConvert to do downscaling and upscaling.
3. use vmaf_rc to calculate all quality metrics
4. add support for regular AV2 CTC test for RA and LD
5. add all AV2 CTC test clip names and y4m files
Change-Id: If0d25fa16ca06dccfb532e7a60c94d50c132d189
diff --git a/tools/convexhull_framework/README.TXT b/tools/convexhull_framework/README.TXT
index 22e1314..599dd1d 100644
--- a/tools/convexhull_framework/README.TXT
+++ b/tools/convexhull_framework/README.TXT
@@ -10,13 +10,11 @@
Prerequisites
1. Inside ./bin folder, make sure you have executables for all external tools,
- such as vmafossexec, ffmpeg, HDRMetrics, encoder, decoder, etc. You can get
- the pre-build binary or source code for the following tools that are needed:
- ffmpeg: https://ffmpeg.org/download.html
+ such as vmaf_rc, HDRConvert, encoder, decoder, etc. You can get the pre-build
+ binaries or source code for the following tools that are needed:
vmaf tools: https://github.com/Netflix/vmaf
- HDRMetrics: https://gitlab.com/standards/HDRTools
+ HDRConvert: https://gitlab.com/standards/HDRTools
libaom AV1 encoder/decoder: https://aomedia.googlesource.com/aom/
- SVT HEVC encoder: https://github.com/OpenVisualCloud/SVT-HEVC
SVT AV1 encoder: https://github.com/OpenVisualCloud/SVT-AV1
Please always follow the manual of these tools to update the command
parameters used in the script
@@ -25,9 +23,10 @@
(vmaf_v0.6.1.pkl.model, vmaf_v0.6.1.pkl) are used and stored under the ./bin
folder.
-3. HDRMetrics requires a template config file (HDRMetricsYUV420_template.cfg).
- It is also located under the ./bin folder. Test framework will generate
- individual config file based on this template.
+3. HDRConvert is used to perform downscale and upscale operation. It requires
+ a template config file (HDRConvScalerY4MFile.cfg). It is also located under
+ the ./bin folder. Test framework will generate individual config file based
+ on this template.
4. VBA macro binary file (vbaProject-AV2.bin) for bdrate calculation is also
stored under ./bin folder, which is needed for BDRATE calculation inside the
@@ -36,45 +35,42 @@
5. Test framework is implemented in python 3. It requires few extra python
packages, such as xlrd, xlsxwriter, argparse, etc.
-Things you need to update inside ./src/Config.py to configure the test.
-1. Update the Clips table following the existing example to provide the list of
- video sequences that you want to test. The first value is the yuv file name
- without .yuv suffix. All test video sequences should be in the folder
- specified by ContentPath. Test framework will extract the string before the
- first "_" as the short name to identify the test sequence and use that to
- generate file name of other intermediate files, so please make sure the short
- name of the test sequence is unique. Currently only 8 bit yuv sequences in
- yuv420p format are supported.
+Things you need to update to configure the test.
+1. Update the test clips table in AV2CTCVideo.py file following the existing
+ example to provide the list and classes of video sequences that you want to
+ test. Currently, only .y4m files are supported. Test script will parse the
+ y4m file header to get the basic information of the video clip, such as
+ resolution, frame rate, bit depth and color format, etc.
-2. Update FrameNum to specify number of frames you want to process.
+2. Update the test configuration list in ./src/Config.py to specify the test
+ configurations. Currently, supported test configurations include Random Access
+ (RA), Low Delay (LD) and Adaptive Streaming (AS).
-3. Update DnScaleRatio list to provide the list of downscaling ratios.
+3. Update FrameNum in ./src/Config.py to specify number of frames you want to
+ process.
-4. Update DnScalingAlgos and UpScalingAlgos list to specify downscaling/upscaling
- filter types that you want to test. The name of the filter types is that
- supported by ffmpeg. The size of these two lists must be the same. Filter
- types for downscaling and upscaling can be different.
+4. Update DnScaleRatio list in ./src/Config.py to provide the list of downscaling
+ ratios used for adaptive streaming (convex hull) test configuration.
-5. Update QPs list to specify the list of QPs you want to test for different
- codecs. QPs must be in the valid QP range for different coding standards.
- For example, [0, 51] for hevc and [0, 63] for AV1
+5. Update DnScalingAlgos and UpScalingAlgos list in ./src/Config.py to specify
+ downscaling/upscaling filter types that you want to test. The name of the
+ filter types is that supported by HDRConvert. The size of these two lists
+ must be the same. Filter types for downscaling and upscaling can be different.
+ Right now, only the lanczos filter is supported.
-6. Update QualityEvalMethods to specify tools you want to use to calculate
- quality metrics in the QualityList. Currently, only VMAF and HDRTools are
- supported. You also need to update QualityList and QualityEvalMethods to
- specify what quality metrics you want to calculate. Test framework will filter
- out other metrics and only report the metrics that are specified.
+6. Update QPs list in ./src/Config.py to specify the list of QPs you want to
+ test for different codecs. QPs must be in the valid QP range for different
+ coding standards. For example, [0, 63] for AV1.
-7. Update LogCmdOnly flag. When it is set to True, the test framework will only
- capture all process command sequences into a log file (under ./test/testLogs
- folder with time stamp) without actually running it on your system. This
- feature is to support the use case in which actual processing tasks need to
- distributed on to a server cluster and executed in parallel.
+7. Update QualityList in ./src/Config.py to specify quality metrics you want to
+ calculate. Currently, only VMAF_RC is supported for quality metrics calculation.
+ It supports PSNR (for Y, U, V planes), SSIM, MS-SSIM and VMAF for Y plane only.
8. Update SMOKE_TEST flag, It is used for sanity check purpose, in which only
few frames are processed to reduce the test time.
-Command lines for running the tests:
+Sample command lines for running the adaptive streaming (convex hull) test:
+"python ConvexHullTest.py [options]"
below is the full command line options in help message:
-h, --help show this help message and exit
-f, --function function to run: clean, scaling, sumscaling,
@@ -84,12 +80,20 @@
-s, --SaveMemory [0|1] save memory mode will delete most files in
intermediate steps and keeps only necessary ones
for RD calculation. It is false by default
+ -CmdOnly, --LogCmdOnly LogCmdOnly mode will only capture the command
+ sequences in the command log file instead of
+ actually run it. It is false by default
-l, --LoggingLevel logging level: 0:No Logging, 1: Critical, 2: Error,
3:Warning, 4: Info, 5: Debug
- -c, --CodecName CodecName: av1 or hevc
- -m, --EncodeMethod EncodeMethod: ffmpeg, aom, svt
- -p, --EncodePreset EncodePreset: medium, slow, fast, etc for ffmpeg,
- 0,1,2... for aom and svt
+ -c, --CodecName CodecName: av1
+ -m, --EncodeMethod EncodeMethod: aom, svt
+ -p, --EncodePreset EncodePreset: 0,1,2... for aom and svt
+
+when LogCmdOnly is set to True, the test framework will only capture all process
+command sequences into a log file (under ./test/testLogs folder with time stamp)
+without actually running it on your system. This feature is to support the use
+case in which actual processing tasks need to distributed on to a server cluster
+and executed in parallel.
Sample command for typical operations:
1. python ConvexHullTest.py -f clean
@@ -97,14 +101,13 @@
2. python ConvexHullTest.py -f scaling
This command will run the standalone downscaling and upscaling tests.
- Downscaled YUV files are stored under
- ./test/downscaledYUVs folder. Upscaled YUV files are stored under
- ./test/upscaledYUVs folder. Quality metrics log files are stored under
- ./test/qualityLogs folder. Other processing logs and command logs are stored
- under ./test/testLogs folder. In case HDRMetric is used, individual config
- files are generated and stored under ./test/configFiles folder. All
- intermediate file names indicate the input, output resolution and filter types
- that are used.
+ Downscaled YUV files are stored under ./test/downscaledYUVs folder.
+ Upscaled YUV files are stored under ./test/upscaledYUVs folder.
+ Quality metrics log files are stored under ./test/qualityLogs folder.
+ Other processing logs and command logs are stored under ./test/testLogs folder.
+ For using HDRConvert, individual config files are generated and stored under
+ ./test/configFiles folder. All intermediate file names indicate the input,
+ output resolution and filter types that are used.
3. python ConvexHullTest.py -f sumscaling
This command will summarize the quality metrics for the scaling test into
@@ -112,18 +115,17 @@
each individual test sequence and also excel file that summarizes quality
result for all test sequences based on classes.
-4. python ConvexHullTest.py -f encode -c hevc -m ffmpeg -p medium
+4. python ConvexHullTest.py -f encode -c av1 -m aom -p 1
This command will run the encoding test. It actually contains downscale
- (optional), encode, decode, upscale, quality metrics steps. Different
- encoding method and codec name can be specified. For a particular encoder,
- encoding preset should also be specified. Downscale step will be skipped if
- downscaled yuv files already generated in ./test/downscaledYUVs. Encoded
+ (optional), encode, decode, upscale, quality metrics steps. Right now, only
+ av1 encoding/decoding with libaom is supported. Downscale step will be skipped
+ if downscaled yuv files already generated in ./test/downscaledYUVs. Encoded
bitstreams are stored under ./test/bitstreams folder. Decoded YUV files are
stored under ./test/decodedYUVs folder. Decoded and then upscaled YUV files
are stored under ./test/decUpscaledYUVs folder. Quality logs are stored under
./test/qualityLogs folder.
-5. python ConvexHullTest.py -f convexhull -c hevc -m ffmpeg -p medium
+5. python ConvexHullTest.py -f convexhull -c av1 -m aom -p 1
This command will summarize the per sequence quality result based on
different scaling ratios and scaling filter types.
Please make sure the same encoding method/codec name/preset are used as the
@@ -139,7 +141,7 @@
calculate bdrate between two encoding runs to evaluate the quality impact on
overall convex hull from a coding tool.
-6. python ConvexHullTest.py -f summary -c hevc -m ffmpeg -p medium
+6. python ConvexHullTest.py -f summary -c av1 -m aom -p 1
This command will summarize the quality metrics across all test sequences
into an excel file stored under the ./analysis/summary folder. BDRATE between
different resolutions will be calculated. Average result based on content
@@ -165,3 +167,35 @@
a sample command is:
python ConvexHullBDRate.py -i1 ConvexHullRD_ffmpeg_hevc_medium.xlsx
-i2 ConvexHullRD_ffmpeg_hevc_veryslow.xlsx -o ConvexHullBDRate.xlsm
+
+Sample command lines for running the regular AV2 CTC test:
+"python AV2CTCTest.py [options]"
+
+below is the full command line options in help message:
+
+ -h, --help show this help message and exit
+ -f, --function function to run: clean, encode, summary
+ -s, --SaveMemory [0|1] save memory mode will delete most files in
+ intermediate steps and keeps only necessary ones
+ for RD calculation. It is false by default
+ -CmdOnly, --LogCmdOnly LogCmdOnly mode will only capture the command
+ sequences in the command log file instead of
+ actually run it. It is false by default
+ -l, --LoggingLevel logging level: 0:No Logging, 1: Critical, 2: Error,
+ 3:Warning, 4: Info, 5: Debug
+ -p, --EncodePreset EncodePreset: 0,1,2... for aom
+
+Sample command for typical operations:
+1. python AV2CTCTest.py -f clean
+ This command will clean up all intermediate files under ./test folder
+
+2. python AV2CTCTest.py -f encode -p 1
+ This command will run the encoding test. It actually contains encode, decode,
+ and quality metrics steps. Right now, only av1 encoding/decoding with libaom
+ is supported. Encoded bitstreams are stored under ./test/bitstreams folder.
+ Decoded YUV files are stored under ./test/decodedYUVs folder. Quality logs
+ are stored under ./test/qualityLogs folder.
+
+3. python AV2CTCTest.py -f summary -p 1
+ This command will summarize the quality metrics across all test sequences
+ into an csv file stored under the ./analysis/summary folder.
diff --git a/tools/convexhull_framework/bin/HDRConvScalerY4MFile.cfg b/tools/convexhull_framework/bin/HDRConvScalerY4MFile.cfg
new file mode 100644
index 0000000..466ae7f
--- /dev/null
+++ b/tools/convexhull_framework/bin/HDRConvScalerY4MFile.cfg
@@ -0,0 +1,88 @@
+# HDRConvert default configuration file
+# format: parameter=value or parameter="stringvalue", no SPACES!
+
+###############################################################################
+#
+# Input/output file parameters
+#
+###############################################################################
+SourceFile="D:\YUVs\AV2-CTC\a1_4k\Crosswalk_3840x2160_5994fps_10bit_420.y4m"
+OutputFile="Crosswalk_1920x1080_5994fps_10bit_420.y4m" # Scaled YUV file
+
+SourceWidth=3840 # input frame height
+SourceHeight=2160 # input frame height
+OutputWidth=1920 # input frame height
+OutputHeight=1080 # input frame height
+ScalingMode=3 # Scaling Filter Mode
+LanczosLobes=5
+SourceRate=59.94 # input frame rate
+SourceInterleaved=0 # Interleaved or Planar data
+SourceChromaFormat=1 # Input chroma format
+ # 0 : 400
+ # 1 : 420
+ # 2 : 422
+ # 3 : 444
+SourceBitDepthCmp0=10 # Input bit depth of luma component
+SourceBitDepthCmp1=10 # Input bit depth of u/cb component
+SourceBitDepthCmp2=10 # Input bit depth of v/cr component
+SourceFourCCCode=6 # FourCC code for input source
+ # 0: UYVY
+ # 1: YUY2
+ # 2: YUYV
+ # 3: YVYU
+ # 4: BGR
+ # 5: V210
+ # 6: Y444I
+SourceColorSpace=0 # 0: CM_YUV
+ # 1: CM_RGB
+ # 2: CM_XYZ
+
+SourceColorPrimaries=0 # 0: BT.709
+ # 1: BT.2020
+ # 2: P3D60
+ # 3: P3D65
+ # 4: None
+SourceTransferFunction=0
+OutputRate=59.94 # output frame rate
+OutputChromaFormat=1 # Output Chroma format
+ # 0 : 400
+ # 1 : 420
+ # 2 : 422
+ # 3 : 444
+
+OutputBitDepthCmp0=10 # bit depth of luma component for distortion computation
+OutputBitDepthCmp1=10 # bit depth of u/cb component for distortion computation
+OutputBitDepthCmp2=10 # bit depth of v/cr component for distortion computation
+OutputColorSpace=0 # 0: CM_YUV
+ # 1: CM_RGB
+ # 2: CM_XYZ
+
+OutputColorPrimaries=0 # 0: BT.709
+ # 1: BT.2020
+ # 2: P3D60
+ # 3: P3D65
+ # 4: None
+
+NumberOfFrames=1 # number of frames to process
+InputFileHeader=0 # Input File header to be skipped (in bytes).
+StartFrame=0 # Number of frames to skip before start
+
+SilentMode=1 # Enable Silent mode
+
+OutputTransferFunction=0 # Transfer Function
+ # 0: NULL (no new TF applied)
+ # 1: PQ
+ # 2: PH
+
+USeSingleTransferStep=1 # Use a single step or two step process for the application of the PQ TF
+TransformPrecision=0 # Use fixed (0) or high precision for color transform
+ChromaDownsampleFilter=6 # 444 to 420 conversion filters
+ # 0: Nearest Neighbor
+ # 1: Bilinear
+ # 2: H={1, 6, 1} and V={1, 1}
+ # 3: H={1, 2, 1} and V={1, 1}
+ChromaUpsampleFilter=0 # 420 to 444 conversion filters
+ # 0 : Nearest Neighbor
+ # 1 : 4-tap in w14548
+SetOutputSinglePrec=0 # Set OpenEXR output file precision
+ # 0: HALF, 1: SINGLE
\ No newline at end of file
diff --git a/tools/convexhull_framework/bin/HDRMetricsYUV420_template.cfg b/tools/convexhull_framework/bin/HDRMetricsYUV420_template.cfg
deleted file mode 100644
index 3a21c63..0000000
--- a/tools/convexhull_framework/bin/HDRMetricsYUV420_template.cfg
+++ /dev/null
@@ -1,99 +0,0 @@
-# HDRMetrics default configuration file
-# format: parameter=value or parameter="stringvalue", no SPACES!
-
-###############################################################################
-#
-# Input file information
-#
-###############################################################################
-Input0File="" # 1st Input file name
-Input1File="" # 2nd Input file name
-LogFile="" # Output Log file name
-NumberOfFrames=10 # Number of frames to process
-SilentMode=0 # Enable Silent mode
-MaxSampleValue=10000.0 # Maximum sample value for floating point (openEXR) data files
-###############################################################################
-#
-# Metrics
-#
-###############################################################################
-EnableMSSSIM=1 # Enable MSSSIM computation
-EnableSSIM=1 # Enable SSIM computation
-
-###############################################################################
-#
-# First input parameters
-#
-###############################################################################
-Input0Width=1280 # 1st Input source width
-Input0Height=720 # 1st Input source height
-Input0ChromaFormat=1 # 1st Input Chroma Format
- # 0 : 400
- # 1 : 420
- # 2 : 422
- # 3 : 444
-Input0Interleaved=0 # 1st Input Interleaved Source
-Input0FourCCCode=0 # 1st Input Pixel Format
- # 0: UYVY
- # 1: YUY2
- # 2: YUYV
- # 3: YVYU
- # 4: BGR
- # 5: V210
- # 6: Y444I
-Input0BitDepthCmp0=8 # 1st Input Bitdepth Cmp0
-Input0BitDepthCmp1=8 # 1st Input Bitdepth Cmp1
-Input0BitDepthCmp2=8 # 1st Input Bitdepth Cmp2
-Input0ColorSpace=0 # 1st Input Color Space
- # 0: YUV
- # 1: RGB
- # 2: XYZ
-Input0ColorPrimaries=0 # 1st Input Color Primaries
- # 0: BT.709
- # 1: BT.2020
- # 2: P3D60
- # 3: P3D65
- # 4: None
-Input0FileHeader=0 # 1st Input Header (bytes)
-Input0StartFrame=0 # 1st Input Start Frame
-Input0FrameSkip=0 # 1st Input Frame Skipping
-Input0Rate=24.0 # 1st Input Frame Rate
-
-###############################################################################
-#
-# Second input source parameters
-#
-###############################################################################
-Input1Width=1280 # 2nd Input source width
-Input1Height=720 # 2nd Input source height
-Input1ChromaFormat=1 # 2nd Input Chroma Format
- # 0 : 400
- # 1 : 420
- # 2 : 422
- # 3 : 444
-Input1Interleaved=0 # 2nd Input Interleaved Source
-Input1FourCCCode=0 # 2nd Input Pixel Format
- # 0: UYVY
- # 1: YUY2
- # 2: YUYV
- # 3: YVYU
- # 4: BGR
- # 5: V210
- # 6: Y444I
-Input1BitDepthCmp0=8 # 2nd Input Bitdepth Cmp0
-Input1BitDepthCmp1=8 # 2nd Input Bitdepth Cmp1
-Input1BitDepthCmp2=8 # 2nd Input Bitdepth Cmp2
-Input1ColorSpace=0 # 2nd Input Color Space
- # 0: YUV
- # 1: RGB
- # 2: XYZ
-Input1ColorPrimaries=0 # 2nd Input Color Primaries
- # 0: BT.709
- # 1: BT.2020
- # 2: P3D60
- # 3: P3D65
- # 4: None
-Input1FileHeader=0 # 2nd Input Header (bytes)
-Input1StartFrame=0 # 2nd Input Start Frame
-Input1FrameSkip=0 # 2nd Input Frame Skipping
-Input0Rate=24.0 # 2nd Input Frame Rate
diff --git a/tools/convexhull_framework/src/AV2CTCTest.py b/tools/convexhull_framework/src/AV2CTCTest.py
new file mode 100644
index 0000000..7efc8c3
--- /dev/null
+++ b/tools/convexhull_framework/src/AV2CTCTest.py
@@ -0,0 +1,183 @@
+#!/usr/bin/env python
+## Copyright (c) 2019, Alliance for Open Media. All rights reserved
+##
+## This source code is subject to the terms of the BSD 2 Clause License and
+## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+## was not distributed with this source code in the LICENSE file, you can
+## obtain it at www.aomedia.org/license/software. If the Alliance for Open
+## Media Patent License 1.0 was not distributed with this source code in the
+## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+##
+__author__ = "maggie.sun@intel.com, ryan.lei@intel.com"
+
+import os
+import sys
+import argparse
+from CalculateQualityMetrics import CalculateQualityMetric, GatherQualityMetrics
+from Utils import GetShortContentName, CreateNewSubfolder, SetupLogging, \
+ Cleanfolder, CreateClipList
+import Utils
+from Config import LogLevels, FrameNum, TEST_CONFIGURATIONS, QPs, WorkPath, \
+ Path_RDResults, LoggerName,QualityList
+from EncDecUpscale import Encode, Decode
+
+###############################################################################
+##### Helper Functions ########################################################
+def CleanIntermediateFiles():
+ folders = [Path_DecodedYuv, Path_CfgFiles]
+ for folder in folders:
+ Cleanfolder(folder)
+
+def GetRDResultCsvFile(EncodeMethod, CodecName, EncodePreset, test_cfg):
+ filename = "RDResults_%s_%s_%s_Preset_%s.csv" % \
+ (EncodeMethod, CodecName, test_cfg, EncodePreset)
+ file = os.path.join(Path_RDResults, filename)
+ return file
+
+def GetBsReconFileName(EncodeMethod, CodecName, EncodePreset, test_cfg, clip, QP):
+ basename = GetShortContentName(clip.file_name, False)
+ filename = "%s_%s_%s_%s_Preset_%s_QP_%d.ivf" % \
+ (basename, EncodeMethod, CodecName, test_cfg, EncodePreset, QP)
+ bs = os.path.join(Path_Bitstreams, filename)
+ filename = "%s_%s_%s_%s_Preset_%s_QP_%d_Decoded.y4m" % \
+ (basename, EncodeMethod, CodecName, test_cfg, EncodePreset, QP)
+ dec = os.path.join(Path_DecodedYuv, filename)
+ return bs, dec
+
+
+def setupWorkFolderStructure():
+ global Path_Bitstreams, Path_DecodedYuv, Path_QualityLog, Path_TestLog,\
+ Path_CfgFiles
+ Path_Bitstreams = CreateNewSubfolder(WorkPath, "bistreams")
+ Path_DecodedYuv = CreateNewSubfolder(WorkPath, "decodedYUVs")
+ Path_QualityLog = CreateNewSubfolder(WorkPath, "qualityLogs")
+ Path_TestLog = CreateNewSubfolder(WorkPath, 'testLogs')
+ Path_CfgFiles = CreateNewSubfolder(WorkPath, "configFiles")
+
+###############################################################################
+######### Major Functions #####################################################
+def CleanUp_workfolders():
+ folders = [Path_Bitstreams, Path_DecodedYuv, Path_QualityLog,
+ Path_TestLog, Path_CfgFiles]
+ for folder in folders:
+ Cleanfolder(folder)
+
+def Run_Encode_Test(test_cfg, clip, preset, LogCmdOnly = False):
+ Utils.Logger.info("start running %s encode tests with %s"
+ % (test_cfg, clip.file_name))
+
+ for QP in QPs:
+ Utils.Logger.info("start encode with QP %d" % (QP))
+ #encode
+ if LogCmdOnly:
+ Utils.CmdLogger.write("============== Job Start =================n")
+ bsFile = Encode('aom', 'av1', preset, clip, test_cfg, QP, FrameNum,
+ Path_Bitstreams, LogCmdOnly)
+ Utils.Logger.info("start decode file %s" % os.path.basename(bsFile))
+ #decode
+ decodedYUV = Decode('av1', bsFile, Path_DecodedYuv, LogCmdOnly)
+ #calcualte quality distortion
+ Utils.Logger.info("start quality metric calculation")
+ CalculateQualityMetric(clip.file_path, FrameNum, decodedYUV, clip.fmt,
+ clip.width, clip.height, clip.bit_depth,
+ Path_QualityLog, LogCmdOnly)
+ if SaveMemory:
+ Cleanfolder(Path_DecodedYuv)
+ Utils.Logger.info("finish running encode with QP %d" % (QP))
+ if LogCmdOnly:
+ Utils.CmdLogger.write("============== Job End ===================\n\n")
+
+def GenerateSummaryRDDataFile(EncodeMethod, CodecName, EncodePreset,
+ test_cfg, clip_list):
+ Utils.Logger.info("start saving RD results to excel file.......")
+ if not os.path.exists(Path_RDResults):
+ os.makedirs(Path_RDResults)
+
+ csv_file = GetRDResultCsvFile(EncodeMethod, CodecName, EncodePreset, test_cfg)
+ csv = open(csv_file, 'wt')
+ csv.write("File,Class,Width,Height,TestCfg,EncodeMethod,CodecName,"\
+ "EncodePreset,QP,Bitrate(kbps)")
+ for qty in QualityList:
+ csv.write(',' + qty)
+ csv.write('\n')
+
+ for clip in clip_list:
+ for qp in QPs:
+ bs, dec = GetBsReconFileName(EncodeMethod, CodecName, EncodePreset,
+ test_cfg, clip, qp)
+ bitrate = (os.path.getsize(bs) * 8 * (clip.fps_num / clip.fps_denom)
+ / FrameNum) / 1000.0
+ quality = GatherQualityMetrics(dec, Path_QualityLog)
+ csv.write("%s,%s,%d,%d,%s,%s,%s,%s,%d,%.4f"
+ %(clip.file_name, clip.file_class, clip.width, clip.height,
+ test_cfg, EncodeMethod, CodecName,EncodePreset,qp,bitrate))
+ for qty in quality:
+ csv.write(",%.4f"%qty)
+ csv.write("\n")
+
+ Utils.Logger.info("finish export RD results to file.")
+ return
+
+def ParseArguments(raw_args):
+ parser = argparse.ArgumentParser(prog='AV2CTCTestTest.py',
+ usage='%(prog)s [options]',
+ description='')
+ parser.add_argument('-f', '--function', dest='Function', type=str,
+ required=True, metavar='',
+ choices=["clean", "encode", "summary"],
+ help="function to run: clean, encode, summary")
+ parser.add_argument('-s', "--SaveMemory", dest='SaveMemory', type=bool,
+ default=False, metavar='',
+ help="save memory mode will delete most files in"
+ " intermediate steps and keeps only necessary "
+ "ones for RD calculation. It is false by default")
+ parser.add_argument('-CmdOnly', "--LogCmdOnly", dest='LogCmdOnly', type=bool,
+ default=False, metavar='',
+ help="LogCmdOnly mode will only capture the command sequences"
+ "It is false by default")
+ parser.add_argument('-l', "--LoggingLevel", dest='LogLevel', type=int,
+ default=3, choices=range(len(LogLevels)), metavar='',
+ help="logging level: 0:No Logging, 1: Critical, 2: Error,"
+ " 3: Warning, 4: Info, 5: Debug")
+ parser.add_argument('-p', "--EncodePreset", dest='EncodePreset', type=str,
+ metavar='', help="EncodePreset: 0,1,2... for aom")
+ if len(raw_args) == 1:
+ parser.print_help()
+ sys.exit(1)
+ args = parser.parse_args(raw_args[1:])
+
+ global Function, SaveMemory, LogLevel, EncodePreset, LogCmdOnly
+ Function = args.Function
+ SaveMemory = args.SaveMemory
+ LogLevel = args.LogLevel
+ EncodePreset = args.EncodePreset
+ LogCmdOnly = args.LogCmdOnly
+
+######################################
+# main
+######################################
+if __name__ == "__main__":
+ #sys.argv = ["", "-f", "encode", "-p","6"]
+ #sys.argv = ["", "-f", "summary", "-p", "6"]
+ ParseArguments(sys.argv)
+
+ # preparation for executing functions
+ setupWorkFolderStructure()
+ if Function != 'clean':
+ SetupLogging(LogLevel, LogCmdOnly, LoggerName, Path_TestLog)
+ clip_list = CreateClipList('RA')
+
+ # execute functions
+ if Function == 'clean':
+ CleanUp_workfolders()
+ elif Function == 'encode':
+ for test_cfg in TEST_CONFIGURATIONS:
+ for clip in clip_list:
+ Run_Encode_Test(test_cfg, clip, EncodePreset, LogCmdOnly)
+ elif Function == 'summary':
+ for test_cfg in TEST_CONFIGURATIONS:
+ GenerateSummaryRDDataFile('aom', 'av1', EncodePreset,
+ test_cfg, clip_list)
+ Utils.Logger.info("RD data summary file generated")
+ else:
+ Utils.Logger.error("invalid parameter value of Function")
diff --git a/tools/convexhull_framework/src/AV2CTCVideo.py b/tools/convexhull_framework/src/AV2CTCVideo.py
new file mode 100644
index 0000000..9d6b4b7
--- /dev/null
+++ b/tools/convexhull_framework/src/AV2CTCVideo.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+## Copyright (c) 2019, Alliance for Open Media. All rights reserved
+##
+## This source code is subject to the terms of the BSD 2 Clause License and
+## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+## was not distributed with this source code in the LICENSE file, you can
+## obtain it at www.aomedia.org/license/software. If the Alliance for Open
+## Media Patent License 1.0 was not distributed with this source code in the
+## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+##
+__author__ = "maggie.sun@intel.com, ryan.lei@intel.com"
+
+"""
+Python file for definition of AV2 CTC testing clips/sets
+"""
+
+#TEST_SET = ["a1_4k", "a2_2k", "a3_720p", "a4_360p", "a5_270p", "b1_syn", "hdr"]
+CTC_TEST_SET = ["a5_270p"]
+AS_TEST_SET = ["a1_4k"]
+Y4M_CLIPs = {
+"a1_4k" : ["Crosswalk_3840x2160_5994fps_10bit_420.y4m"],
+'''
+"a1_4k" : ["BoxingPractice_3840x2160_5994fps_10bit_420.y4m", "Crosswalk_3840x2160_5994fps_10bit_420.y4m",
+ "FoodMarket2_3840x2160_5994fps_10bit_420.y4m", "Neon1224_3840x2160_2997fps.y4m",
+ "NocturneDance_3840x2160p_10bit_60fps.y4m", "PierSeaSide_3840x2160_2997fps_10bit_420.y4m",
+ "Tango_3840x2160_5994fps_10bit_420.y4m", "TimeLapse_3840x2160_5994fps_10bit_420.y4m"],
+'''
+"a2_2k" : ["Aerial3200_1920x1080_5994_10bit_420.y4m", "Boat_1920x1080_60fps_10bit_420.y4m",
+ "crowd_run_1080p50.y4m", "FoodMarket_1920x1080_60fps_10bit_420.y4m",
+ "Meridian_talk_sdr_1080p_10bit.y4m", "old_town_cross_1080p50.y4m",
+ "pedestrian_area_1080p25.y4m", "raw_1080x1920@30.walking.in.street.y4m",
+ "RitualDance_1920x1080_60fps_10bit_420.y4m", "riverbed_1080p25.y4m",
+ "rush_field_cuts_1080p.y4m", "Skater227_1920x1080_30fps.y4m",
+ "TunnelFlag_1920x1080_60fps_10bit_420.y4m", "Vertical_bees_2997_1080x1920.y4m",
+ "Vertical_Carnaby_5994_1080x1920.y4m", "WorldCup_1920x1080_30p.y4m",
+ "WorldCup_far_1920x1080_30p.y4m"],
+"a3_720p" : ["controlled_burn_720p_420.y4m", "Johnny_1280x720_60.y4m",
+ "KristenAndSara_1280x720_60.y4m", "Netflix_DrivingPOV_720p_60fps_10bit_420.y4m",
+ "Netflix_RollerCoaster_720p_60fps_10bit_420.y4m", "vidyo3_720p_60fps.y4m",
+ "vidyo4_720p_60fps.y4m", "west_wind_easy_720p_420.y4m"],
+"a4_360p" : ["blue_sky_360p25.y4m", "red_kayak_360p.y4m",
+ "snow_mnt_640x360p.y4m", "speed_bag_640x360p.y4m",
+ "stockholm_640x360p60.y4m", "touchdown_pass_640x360p30.y4m"],
+"a5_270p" : ["FourPeople_480x270_60.y4m", "park_joy_480x270_50.y4m",
+ "sparks_elevator_480x270p_60.y4m", "Vertical_Bayshore_2997_270x480.y4m"],
+"b1_syn" : ["AOV5_1920x1080_60_8bit_420.y4m", "baolei_2048x1080_60fps.y4m",
+ "cosmos_log_2048x858_25_8bit_sdr.y4m", "EuroTruckSimulator2.y4m",
+ "GlassHalf_1920x1080p_24p_8b_420.y4m", "life_1080p30.y4m",
+ "MINECRAFT_1080p_60_8bit.y4m", "MissionControlClip3_1920x1080_60_420.y4m",
+ "sol_levante_dragons_sdr_1920x1080_24_10bit_full.y4m", "sol_levante_face_sdr_1920x1080_24_10bit.y4m",
+ "wikipedia_1920x1080p30.y4m"],
+"hdr" : ["cosmos_caterpillar_2048x858p24_hdr10.y4m", "cosmos_tree_trunk_2048x858p24_hdr10.y4m",
+ "meridian_shore_1920x1080p60_hdr10.y4m", "meridian_talk_1920x1080p60_hdr10.y4m",
+ "merid_road_3840x2160p60_hdr10.y4m", "nocturne_dance_3840x2160_hdr10.y4m",
+ "nocturne_room_3840x2160_hdr10.y4m", "sol_levante_dragons_1920x1080p24_hdr10.y4m",
+ "sol_levante_face_1920x1080p24_hdr10.y4m", "sparks_truck_2048x1080p60_hdr10.y4m",
+ "sparks_welding_4096x2160p60_hdr10.y4m"],
+}
diff --git a/tools/convexhull_framework/src/CalcQtyWithFfmpeg.py b/tools/convexhull_framework/src/CalcQtyWithFfmpeg.py
deleted file mode 100644
index 0aa1301..0000000
--- a/tools/convexhull_framework/src/CalcQtyWithFfmpeg.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env python
-## Copyright (c) 2019, Alliance for Open Media. All rights reserved
-##
-## This source code is subject to the terms of the BSD 2 Clause License and
-## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
-## was not distributed with this source code in the LICENSE file, you can
-## obtain it at www.aomedia.org/license/software. If the Alliance for Open
-## Media Patent License 1.0 was not distributed with this source code in the
-## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
-##
-__author__ = "maggie.sun@intel.com, ryan.lei@intel.com"
-
-import os
-import re
-import logging
-from Config import BinPath, LoggerName, LogCmdOnly, FFMPEG
-from Utils import GetShortContentName, ExecuteCmd
-
-subloggername = "CalcQtyMetrics_FFMPEGTool"
-loggername = LoggerName + '.' + '%s' % subloggername
-logger = logging.getLogger(loggername)
-
-
-FFMPEGMetricsFullList = ['PSNR_Y', 'PSNR_U', 'PSNR_V']
-
-def ParseFfmpegLogFile(psnr_log):
- floats = len(FFMPEGMetricsFullList) * [0.0]
- flog = open(psnr_log, 'r')
- cnt = 0
- for line in flog:
- cnt += 1
- item = re.findall(r"psnr_y:(\d+\.?\d*)", line)
- floats[0] += 0 if len(item) == 0 else float(item[0])
- item = re.findall(r"psnr_u:(\d+\.?\d*)", line)
- floats[1] += 0 if len(item) == 0 else float(item[0])
- item = re.findall(r"psnr_v:(\d+\.?\d*)", line)
- floats[2] += 0 if len(item) == 0 else float(item[0])
-
- floats = [float(i) / cnt for i in floats]
-
- print_str = "FFMPEG quality metrics: "
- for metrics, idx in zip(FFMPEGMetricsFullList, range(len(FFMPEGMetricsFullList))):
- print_str += "%s = %2.5f, " % (metrics, floats[idx])
- logger.info(print_str)
-
- return floats[0:len(FFMPEGMetricsFullList)]
-
-
-def GetFfmpegLogFile(recfile, path):
- filename = GetShortContentName(recfile, False) + '_psnr.log'
- file = os.path.join(path, filename)
- return file
-
-################################################################################
-##################### Exposed Functions ########################################
-def FFMPEG_CalQualityMetrics(origfile, recfile, num, w, h, logfilePath):
- #calculate psnr using ffmpeg filter to get psnr_u and psnr_v
- #here we have to pass the psnr_log file name to FFMPEG without the target
- #log path first, then copy the result psnr log to the target log path after
- #the ffmpeg call. it doesn't work if the full path is directly passed to FFMPEG
- psnr_log = GetFfmpegLogFile(recfile, BinPath)
- psnr_log = os.path.basename(psnr_log)
- args = " -s %dx%d -pix_fmt yuv420p -i %s -s %dx%d -pix_fmt yuv420p -i %s" \
- " -frames:v %d -lavfi psnr=%s -f null -" % \
- (w, h, origfile, w, h, recfile, num, psnr_log)
- cmd = FFMPEG + args
- ExecuteCmd(cmd, LogCmdOnly)
- #move the psnr log to the target log path
- target = os.path.join(logfilePath, psnr_log)
- cmd = "move %s %s" % (psnr_log, target)
- ExecuteCmd(cmd, LogCmdOnly)
-
-def FFMPEG_GatherQualityMetrics(recfile, logfilePath):
- psnr_log = GetFfmpegLogFile(recfile, logfilePath)
- results = ParseFfmpegLogFile(psnr_log)
- return results
diff --git a/tools/convexhull_framework/src/CalcQtyWithHdrTools.py b/tools/convexhull_framework/src/CalcQtyWithHdrTools.py
deleted file mode 100644
index 9593c87..0000000
--- a/tools/convexhull_framework/src/CalcQtyWithHdrTools.py
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env python
-## Copyright (c) 2019, Alliance for Open Media. All rights reserved
-##
-## This source code is subject to the terms of the BSD 2 Clause License and
-## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
-## was not distributed with this source code in the LICENSE file, you can
-## obtain it at www.aomedia.org/license/software. If the Alliance for Open
-## Media Patent License 1.0 was not distributed with this source code in the
-## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
-##
-__author__ = "maggie.sun@intel.com, ryan.lei@intel.com"
-
-from shutil import copyfile
-import fileinput
-import os
-import re
-from Utils import GetShortContentName, ExecuteCmd
-from Config import BinPath, LogCmdOnly, LoggerName, HDRTool
-import logging
-
-subloggername = "HDRToolsRun"
-loggername = LoggerName + '.' + '%s' % subloggername
-logger = logging.getLogger(loggername)
-
-
-HDRToolsConfigFileTemplate = os.path.join(BinPath, 'HDRMetricsYUV420_template.cfg')
-HDRToolsMetricsFullList = ['PSNR_Y', 'PSNR_U', 'PSNR_V', 'MS-SSIM_Y', 'MS-SSIM_U',
- 'MS-SSIM_V', 'SSIM_Y', 'SSIM_U', 'SSIM_V']
-
-def GenerateCfgFile(orig_file, rec_file, num, w, h, configpath):
- filename = GetShortContentName(rec_file, False) + '_hdrtools.cfg'
- cfgfile = os.path.join(configpath, filename)
- copyfile(HDRToolsConfigFileTemplate, cfgfile)
- fp = fileinput.input(cfgfile, inplace=1)
- for line in fp:
- if 'Input0File=' in line:
- line = 'Input0File="%s"\n' % orig_file
- if 'Input1File=' in line:
- line = 'Input1File="%s"\n' % rec_file
- if 'NumberOfFrames=' in line:
- line = 'NumberOfFrames=%d\n' % num
- if 'Input0Width=' in line:
- line = 'Input0Width=%d\n' % w
- if 'Input1Width=' in line:
- line = 'Input1Width=%d\n' % w
- if 'Input0Height=' in line:
- line = 'Input0Height=%d\n' % h
- if 'Input1Height=' in line:
- line = 'Input1Height=%d\n' % h
- print(line, end='')
- fp.close()
- return cfgfile
-
-def ParseHDRToolLogFile(logfile):
- flog = open(logfile, 'r')
- pattern = re.compile(r'\d+\.?\d*')
- floats = len(HDRToolsMetricsFullList) * [0.0]
- for line in flog:
- if 'D_Avg' in line:
- floats = [float(i) for i in pattern.findall(line)]
- break
-
- print_str = "HDRTools qty metrics: "
- for metrics, idx in zip(HDRToolsMetricsFullList,
- range(len(HDRToolsMetricsFullList))):
- print_str += "%s = %2.5f, " % (metrics, floats[idx])
- logger.info(print_str)
- return floats[0:len(HDRToolsMetricsFullList)]
-
-def GetHDRLogFile(recfile, path):
- filename = GetShortContentName(recfile, False) + '_hdrtools.log'
- file = os.path.join(path, filename)
- return file
-
-################################################################################
-##################### Exposed Functions ########################################
-def HDRTool_CalQualityMetrics(origfile, recfile, num, w, h, logfilepath,
- cfgfilepath):
- cfgFile = GenerateCfgFile(origfile, recfile, num, w, h, cfgfilepath)
- logfile = GetHDRLogFile(recfile, logfilepath)
- args = " -f %s > %s" % (cfgFile, logfile)
- cmd = HDRTool + args
- ExecuteCmd(cmd, LogCmdOnly)
-
-def HDRTool_GatherQualityMetrics(recfile, logfilepath):
- logfile = GetHDRLogFile(recfile, logfilepath)
- results = ParseHDRToolLogFile(logfile)
- return results
diff --git a/tools/convexhull_framework/src/CalcQtyWithVmafTool.py b/tools/convexhull_framework/src/CalcQtyWithVmafTool.py
index 46efc1e..c38211a 100644
--- a/tools/convexhull_framework/src/CalcQtyWithVmafTool.py
+++ b/tools/convexhull_framework/src/CalcQtyWithVmafTool.py
@@ -13,7 +13,7 @@
import os
import re
import logging
-from Config import BinPath, LoggerName, LogCmdOnly, VMAF
+from Config import BinPath, LoggerName, VMAF
from Utils import GetShortContentName, ExecuteCmd
subloggername = "CalcQtyMetrics_VMAFTool"
@@ -21,24 +21,43 @@
logger = logging.getLogger(loggername)
Model_Pkg_File = os.path.join(BinPath, 'vmaf_v0.6.1.pkl')
-VMAFMetricsFullList = ['VMAF_Y', 'PSNR_Y', 'SSIM_Y', 'MS-SSIM_Y']
+VMAFMetricsFullList = ['VMAF_Y', 'PSNR_Y', 'PSNR_U', 'PSNR_V', 'SSIM_Y', 'MS-SSIM_Y']
def ParseVMAFLogFile(vmaf_log):
floats = len(VMAFMetricsFullList) * [0.0]
flog = open(vmaf_log, 'r')
for line in flog:
+ '''
if 'aggregateVMAF' in line:
- item = re.findall(r"aggregateVMAF=\"(\d+\.?\d*)\"", line)
+ item = re.findall(r"aggregateVMAF=\"([+|-]?\d+\.?\d*)\"", line)
floats[0] = 0 if len(item) == 0 else item[0]
- item = re.findall(r"aggregatePSNR=\"(\d+\.?\d*)\"", line)
+ item = re.findall(r"aggregatePSNR=\"([+|-]?\d+\.?\d*)\"", line)
floats[1] = 0 if len(item) == 0 else item[0]
- item = re.findall(r"aggregateSSIM=\"(\d+\.?\d*)\"", line)
+ item = re.findall(r"aggregateSSIM=\"([+|-]?\d+\.?\d*)\"", line)
floats[2] = 0 if len(item) == 0 else item[0]
- item = re.findall(r"aggregateMS_SSIM=\"(\d+\.?\d*)\"", line)
+ item = re.findall(r"aggregateMS_SSIM=\"([+|-]?\d+\.?\d*)\"", line)
floats[3] = 0 if len(item) == 0 else item[0]
break
+ '''
+ m = re.search(r"\"vmaf\".*mean=\"(\d+\.?\d*)\"\s+",line)
+ if m:
+ floats[0] = m.group(1)
+ m = re.search(r"\"psnr_y\".*mean=\"(\d+\.?\d*)\"\s+", line)
+ if m:
+ floats[1] = m.group(1)
+ m = re.search(r"\"psnr_cb\".*mean=\"(\d+\.?\d*)\"\s+", line)
+ if m:
+ floats[2] = m.group(1)
+ m = re.search(r"\"psnr_cr\".*mean=\"(\d+\.?\d*)\"\s+", line)
+ if m:
+ floats[3] = m.group(1)
+ m = re.search(r"\"float_ssim\".*mean=\"(\d+\.?\d*)\"\s+", line)
+ if m:
+ floats[4] = m.group(1)
+ m = re.search(r"\"float_ms_ssim\".*mean=\"(\d+\.?\d*)\"\s+", line)
+ if m:
+ floats[5] = m.group(1)
flog.close()
-
floats = [float(i) for i in floats]
print_str = "VMAF quality metrics: "
@@ -56,10 +75,13 @@
################################################################################
##################### Exposed Functions ########################################
-def VMAF_CalQualityMetrics(origfile, recfile, num, w, h, logfilePath):
+def VMAF_CalQualityMetrics(origfile, recfile, fmt, num, w, h, bit_depth,
+ logfilePath, LogCmdOnly=False):
vmaf_log = GetVMAFLogFile(recfile, logfilePath)
- args = " yuv420p %d %d %s %s %s --log %s --psnr --ssim --ms-ssim "\
- % (w, h, origfile, recfile, Model_Pkg_File, vmaf_log)
+ args = " -r %s -d %s --feature psnr --feature float_ssim " \
+ " --feature float_ms_ssim -q --xml" \
+ " --model path=%s:name=vmaf -o %s"\
+ % (origfile, recfile, Model_Pkg_File, vmaf_log)
cmd = VMAF + args
ExecuteCmd(cmd, LogCmdOnly)
diff --git a/tools/convexhull_framework/src/CalculateQualityMetrics.py b/tools/convexhull_framework/src/CalculateQualityMetrics.py
index 4f61fa2..cdf99a2 100644
--- a/tools/convexhull_framework/src/CalculateQualityMetrics.py
+++ b/tools/convexhull_framework/src/CalculateQualityMetrics.py
@@ -11,63 +11,30 @@
__author__ = "maggie.sun@intel.com, ryan.lei@intel.com"
import logging
-from Config import QualityList, LoggerName, QualityEvalMethods
+from Config import QualityList, LoggerName
import Utils
from CalcQtyWithVmafTool import VMAF_CalQualityMetrics, VMAF_GatherQualityMetrics,\
VMAFMetricsFullList
-from CalcQtyWithHdrTools import HDRTool_CalQualityMetrics, HDRToolsMetricsFullList,\
- HDRTool_GatherQualityMetrics
-from CalcQtyWithFfmpeg import FFMPEG_GatherQualityMetrics, FFMPEGMetricsFullList,\
- FFMPEG_CalQualityMetrics
subloggername = "CalcQtyMetrics"
loggername = LoggerName + '.' + '%s' % subloggername
logger = logging.getLogger(loggername)
-MetricsFullDict = {'VMAF': VMAFMetricsFullList, 'HDRTools': HDRToolsMetricsFullList,
- 'FFMPEG': FFMPEGMetricsFullList}
-
-def CalculateQualityMetric(content, framenum, reconYUV, width, height, logfilePath,
- cfgfilePath):
+def CalculateQualityMetric(src_file, framenum, reconYUV, fmt, width, height,
+ bit_depth, logfilePath, LogCmdOnly=False):
Utils.CmdLogger.write("::Quality Metrics\n")
-
- methods_torun = list(set(QualityEvalMethods)) # remove duplicate items
- for method in methods_torun:
- if method == 'VMAF':
- VMAF_CalQualityMetrics(content, reconYUV, framenum, width, height,
- logfilePath)
- elif method == 'HDRTools':
- HDRTool_CalQualityMetrics(content, reconYUV, framenum, width, height,
- logfilePath, cfgfilePath)
- elif method == 'FFMPEG':
- FFMPEG_CalQualityMetrics(content, reconYUV, framenum, width, height,
- logfilePath)
- else:
- logger.error("invalid quality evaluation method: %s !" % method)
- return
+ VMAF_CalQualityMetrics(src_file, reconYUV, fmt, framenum, width, height,
+ bit_depth, logfilePath, LogCmdOnly)
def GatherQualityMetrics(reconYUV, logfilePath):
- methods_torun = list(set(QualityEvalMethods)) # remove duplicate items
- qresult_dict = {}
- for method in methods_torun:
- if method == 'VMAF':
- qresult_dict[method] = VMAF_GatherQualityMetrics(reconYUV, logfilePath)
- elif method == 'HDRTools':
- qresult_dict[method] = HDRTool_GatherQualityMetrics(reconYUV, logfilePath)
- elif method == 'FFMPEG':
- qresult_dict[method] = FFMPEG_GatherQualityMetrics(reconYUV, logfilePath)
- else:
- logger.error("invalid quality evaluation method: %s !" % method)
- return
-
+ qresult = VMAF_GatherQualityMetrics(reconYUV, logfilePath)
results = []
- for metric, method in zip(QualityList, QualityEvalMethods):
- mfullList = MetricsFullDict[method]
- if metric in mfullList:
- indx = mfullList.index(metric)
- results.append(qresult_dict[method][indx])
+ for metric in QualityList:
+ if metric in VMAFMetricsFullList:
+ indx = VMAFMetricsFullList.index(metric)
+ results.append(qresult[indx])
else:
logger.error("invalid quality metrics in QualityList")
- results.append('none')
+ results.append(0.0)
return results
diff --git a/tools/convexhull_framework/src/Config.py b/tools/convexhull_framework/src/Config.py
index 2fc154c..3ad8b06 100644
--- a/tools/convexhull_framework/src/Config.py
+++ b/tools/convexhull_framework/src/Config.py
@@ -11,6 +11,10 @@
__author__ = "maggie.sun@intel.com, ryan.lei@intel.com"
import os
+import AV2CTCVideo
+
+#TEST_CONFIGURATIONS = ["RA","LD", "AS"]
+TEST_CONFIGURATIONS = ["RA"]
######################################
# configuration settings
@@ -19,74 +23,16 @@
BinPath = os.path.join(RootPath, 'bin')
WorkPath = os.path.join(RootPath, 'test')
SMOKE_TEST = False # override some parameters to do a quick smoke test
-FrameNum = 10
+FrameNum = 2
if SMOKE_TEST:
FrameNum = 2
############ test contents #######################################
-ContentPath = "..\\video"
-# when Have_Class_Subfolder is set to True, test clips are put in subfolders
-# under ContentPath, each subfolder name represents a class. Class name in the
-# table of Clips is the subfolder name
-Have_Class_Subfolder = False
-Clips = {
-# basename class width height framerate bitdepth fmt
- #"CrowdRun": ["ClassB", 1920, 1080, 30, 8, "yuv420p"],
- #"BasketballDrive": ["ClassB", 1920, 1080, 30, 8, "yuv420p"],
- #"NetflixCrosswalk_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080,
- #30, 8, "yuv420p"],
- "CrowdRun_1920x1080": ["ClassB", 1920, 1080, 30, 8, "yuv420p"],
-}
-'''
- "aspen_1080p_60f": ["ClassB", 1920, 1080, 30, 8,
- "yuv420p"],
- "dark720p_60f": ["ClassB", 1280, 720, 30, 8,
- "yuv420p"],
- "DOTA2_60f_420": ["ClassB", 1920, 1080, 30, 8,
- "yuv420p"],
- "duckstakeoff_1080p50_60f": ["ClassB", 1920, 1080, 30, 8,
- "yuv420p"],
- "KristenAndSara_1280x720_60f": ["ClassB", 1280, 720, 30, 8,
- "yuv420p"],
- "life_1080p30_60f": ["ClassB", 1920, 1080, 30, 8,
- "yuv420p"],
- "MINECRAFT_60f_420": ["ClassB", 1920, 1080, 30, 8,
- "yuv420p"],
- "NetflixAerial_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080,
- 30, 8, "yuv420p"],
- "NetflixBoat_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080,
- 30, 8, "yuv420p"],
- "NetflixCrosswalk_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080,
- 30, 8, "yuv420p"],
- "NetflixDrivingPOV_1280x720_60fps_8bit_420_60f": ["ClassB", 1280, 720,
- 30, 8, "yuv420p"],
- "NetflixFoodMarket_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080,
- 30, 8, "yuv420p"],
- "NetflixPierSeaside_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080,
- 30, 8, "yuv420p"],
- "NetflixRollerCoaster_1280x720_60fps_8bit_420_60f": ["ClassB", 1280, 720,
- 30, 8, "yuv420p"],
- "NetflixSquareAndTimelapse_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920,
- 1080, 30, 8, "yuv420p"],
- "NetflixTunnelFlag_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920,
- 1080, 30, 8, "yuv420p"],
- "rushhour_1080p25_60f": ["ClassB", 1920, 1080, 30, 8,
- "yuv420p"],
- "STARCRAFT_60f_420": ["ClassB", 1920, 1080, 30, 8,
- "yuv420p"],
- "touchdownpass_1080p_60f": ["ClassB", 1920, 1080, 30, 8,
- "yuv420p"],
- "vidyo1_720p_60fps_60f": ["ClassB", 1280, 720, 30, 8,
- "yuv420p"],
- "vidyo4_720p_60fps_60f": ["ClassB", 1280, 720, 30, 8,
- "yuv420p"],
- "wikipedia_420": ["ClassB", 1920, 1080, 30, 8,
- "yuv420p"],
-'''
+ContentPath = "D:\\YUVs\\AV2-CTC"
############## Scaling settings ############################################
# down scaling ratio
-DnScaleRatio = [1.0, 1.5, 2.0, 2.5, 3.0, 4.0] #, 6.0] # downscale ratio
+DnScaleRatio = [1.0, 1.5, 2.0, 3.0, 4.0, 6.0] # downscale ratio
#down and up scaling algorithm, the 2 lists should be of same size
DnScalingAlgos = ['lanczos'] #['bicubic', 'bilinear', 'gauss', 'lanczos', 'sinc']
UpScalingAlgos = ['lanczos'] #['bicubic', 'bilinear', 'gauss', 'lanczos', 'sinc']
@@ -94,29 +40,22 @@
if SMOKE_TEST:
DnScalingAlgos = ['bicubic', 'lanczos', 'sinc']
UpScalingAlgos = ['bicubic', 'lanczos', 'sinc']
+HDRToolsConfigFileTemplate = os.path.join(BinPath, 'HDRConvScalerY4MFile.cfg')
+HDRConvert = os.path.join(BinPath, 'HDRConvert.exe')
##################### Encode Config ########################################
-EncodeMethods = ["ffmpeg", "aom", "svt"]
-CodecNames = ["hevc", "av1"]
-SUFFIX = {"hevc": ".265", "av1": ".ivf"}
+EncodeMethods = ["aom", "svt"]
+CodecNames = ["av1"]
+SUFFIX = {"av1": ".ivf"}
FFMPEG = os.path.join(BinPath, 'ffmpeg.exe')
AOMENC = os.path.join(BinPath, 'aomenc.exe')
SVTAV1 = os.path.join(BinPath, 'SvtAv1EncApp.exe')
-SVTHEVC = os.path.join(BinPath, 'SvtHevcEncApp.exe')
AOMDEC = os.path.join(BinPath, 'aomdec.exe')
-
-QPs = list(range(22, 51, 5)) # total 6 QPs
-if SMOKE_TEST:
- QPs = list(range(12, 45, 10)) # total 4 QPs
-
+QPs = [23, 31, 39, 47, 55, 63]
######################## quality evalution config #############################
QualityList = ['VMAF_Y', 'PSNR_Y', 'PSNR_U', 'PSNR_V', 'SSIM_Y', 'MS-SSIM_Y']
-# method should be one of 'VMAF', 'FFMPEG' or 'HDRTools'
-QualityEvalMethods = ['VMAF', 'HDRTools', 'HDRTools', 'HDRTools', 'HDRTools',
- 'HDRTools']
-VMAF = os.path.join(BinPath, 'vmafossexec.exe')
-HDRTool = os.path.join(BinPath, 'HDRMetrics.exe')
-CalcBDRateInExcel = False
+VMAF = os.path.join(BinPath, 'vmaf_rc.exe')
+CalcBDRateInExcel = True
EnablePreInterpolation = True
######################## config for exporting data to excel #################
@@ -166,6 +105,5 @@
len(QualityList)) * i + ScalQty_startCol + 1
for i in range(len(DnScalingAlgos))]
######################## logging #########################################
-LoggerName = "ConvexHullTest"
+LoggerName = "AV2CTC"
LogLevels = ['NONE', 'CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG']
-LogCmdOnly = False
diff --git a/tools/convexhull_framework/src/ConvexHullTest.py b/tools/convexhull_framework/src/ConvexHullTest.py
index 8493db1..80e131d 100644
--- a/tools/convexhull_framework/src/ConvexHullTest.py
+++ b/tools/convexhull_framework/src/ConvexHullTest.py
@@ -20,21 +20,21 @@
from EncDecUpscale import Run_EncDec_Upscale, GetBsReconFileName
from VideoScaler import GetDownScaledOutFile, DownScaling
from CalculateQualityMetrics import CalculateQualityMetric, GatherQualityMetrics
-from Utils import GetShortContentName, GetVideoInfo, CreateChart_Scatter,\
+from Utils import GetShortContentName, CreateChart_Scatter,\
AddSeriesToChart_Scatter, InsertChartsToSheet, CreateNewSubfolder,\
- GetContents, SetupLogging, UpdateChart, AddSeriesToChart_Scatter_Rows,\
- Cleanfolder
-from PostAnalysis_Summary import GenerateSummaryRDDataExcelFile,\
- GenerateSummaryConvexHullExcelFile
+ SetupLogging, UpdateChart, AddSeriesToChart_Scatter_Rows,\
+ Cleanfolder, CreateClipList, Clip
+from PostAnalysis_Summary import GenerateSumRDExcelFile,\
+ GenerateSumCvxHullExcelFile
from ScalingTest import Run_Scaling_Test, SaveScalingResultsToExcel
import Utils
-from Config import LogLevels, FrameNum, DnScaleRatio, QPs, CvxH_WtCols,\
- CvxH_WtRows, QualityList, LineColors, DnScalingAlgos, UpScalingAlgos,\
- ContentPath, SummaryOutPath, WorkPath, Path_RDResults, Clips, \
- ConvexHullColor, EncodeMethods, CodecNames, LoggerName, LogCmdOnly, \
- TargetQtyMetrics, CvxHDataRows, CvxHDataStartRow, CvxHDataStartCol, \
- CvxHDataNum, Int_ConvexHullColor, EnablePreInterpolation
from operator import itemgetter
+from Config import LogLevels, FrameNum, QPs, CvxH_WtCols,\
+ CvxH_WtRows, QualityList, LineColors, SummaryOutPath, WorkPath, \
+ Path_RDResults, DnScalingAlgos, UpScalingAlgos, ConvexHullColor, \
+ EncodeMethods, CodecNames, LoggerName, DnScaleRatio, TargetQtyMetrics, \
+ CvxHDataRows, CvxHDataStartRow, CvxHDataStartCol, CvxHDataNum, \
+ Int_ConvexHullColor, EnablePreInterpolation
###############################################################################
##### Helper Functions ########################################################
@@ -46,16 +46,16 @@
for folder in folders:
Cleanfolder(folder)
-def GetRDResultExcelFile(content):
- contentBaseName = GetShortContentName(content)
+def GetRDResultExcelFile(clip):
+ contentBaseName = GetShortContentName(clip.file_name, False)
filename = "RDResults_%s_%s_%s_%s.xlsx" % (contentBaseName, EncodeMethod,
CodecName, EncodePreset)
file = os.path.join(Path_RDResults, filename)
return file
def setupWorkFolderStructure():
- global Path_Bitstreams, Path_DecodedYuv, Path_UpScaleYuv, Path_DnScaleYuv,\
- Path_QualityLog, Path_TestLog, Path_CfgFiles, Path_DecUpScaleYuv
+ global Path_Bitstreams, Path_DecodedYuv, Path_UpScaleYuv, Path_DnScaleYuv, \
+ Path_QualityLog, Path_TestLog, Path_CfgFiles, Path_DecUpScaleYuv
Path_Bitstreams = CreateNewSubfolder(WorkPath, "bistreams")
Path_DecodedYuv = CreateNewSubfolder(WorkPath, "decodedYUVs")
Path_UpScaleYuv = CreateNewSubfolder(WorkPath, "upscaledYUVs")
@@ -112,13 +112,15 @@
return lower, upper
-def LookUpQPAndResolutionInConvexHull(qtyvals, qtyhull, qtycvhQPs, qtycvhRes):
+def LookUpQPAndResInCvxHull(qtyvals, qtyhull, qtycvhQPs, qtycvhRes):
cvhqtys = [h[1] for h in qtyhull]
qtyQPs = []; qtyRes = []
for val in qtyvals:
closest_idx = min(range(len(cvhqtys)), key=lambda i: abs(cvhqtys[i] - val))
- if (closest_idx == 0 and val > cvhqtys[0]) or (closest_idx == (len(qtyvals) - 1) and val < cvhqtys[-1]):
- Utils.Logger.info("the give value of quality metric is out of range of convex hull test quality values.")
+ if (closest_idx == 0 and val > cvhqtys[0]) or \
+ (closest_idx == (len(qtyvals) - 1) and val < cvhqtys[-1]):
+ Utils.Logger.info("the give value of quality metric is out of range"\
+ "of convex hull test quality values.")
qtyQPs.append(qtycvhQPs[closest_idx])
qtyRes.append(qtycvhRes[closest_idx])
@@ -180,18 +182,22 @@
# find out QP/resolution for given qty metric and qty value
startrow_fdout = endrow + 1
- sht.write(startrow_fdout, CvxHDataStartCol, " Find out QP/resolution for given quality metrics:")
+ sht.write(startrow_fdout, CvxHDataStartCol,
+ " Find out QP/resolution for given quality metrics:")
numitem_fdout = 4 # qtymetric values, QP, resolution, one empty row
- startrows_fdout = [startrow_fdout + 1 + i * numitem_fdout for i in range(len(tgtqmetrics))]
+ startrows_fdout = [startrow_fdout + 1 + i * numitem_fdout
+ for i in range(len(tgtqmetrics))]
for metric, idx in zip(tgtqmetrics, range(len(tgtqmetrics))):
if metric not in QualityList:
- Utils.Logger.error("wrong qty metric name. should be one of the name in QualityList.")
+ Utils.Logger.error("wrong qty metric name. should be one of the" \
+ " name in QualityList.")
return endrow
qtyvals = tgtqmetrics[metric]
- qtyQPs, qtyRes = LookUpQPAndResolutionInConvexHull(qtyvals, hull[metric],
- cvh_QPs[metric], cvh_Res_txt[metric])
+ qtyQPs, qtyRes = LookUpQPAndResInCvxHull(qtyvals, hull[metric],
+ cvh_QPs[metric],
+ cvh_Res_txt[metric])
# write the look up result into excel file
startrow = startrows_fdout[idx]
sht.write(startrow, CvxHDataStartCol, metric)
@@ -215,46 +221,40 @@
for folder in folders:
Cleanfolder(folder)
-def Run_ConvexHull_Test(content, dnScalAlgo, upScalAlgo):
- Utils.Logger.info("%s %s start running xcode tests with %s" %
- (EncodeMethod, CodecName, os.path.basename(content)))
- cls, width, height, fr, bitdepth, fmt, totalnum = GetVideoInfo(content, Clips)
- if totalnum < FrameNum:
- Utils.Logger.error("content %s includes total %d frames < specified % frames!"
- % (content, totalnum, FrameNum))
- return
-
- DnScaledRes = [(int(width / ratio), int(height / ratio)) for ratio in DnScaleRatio]
+def Run_ConvexHull_Test(clip, dnScalAlgo, upScalAlgo, LogCmdOnly = False):
+ Utils.Logger.info("start encode %s" % clip.file_name)
+ DnScaledRes = [(int(clip.width / ratio), int(clip.height / ratio)) for ratio in
+ DnScaleRatio]
for i in range(len(DnScaledRes)):
if SaveMemory:
CleanIntermediateFiles()
DnScaledW = DnScaledRes[i][0]
DnScaledH = DnScaledRes[i][1]
- #downscaling if the downscaled file does not exist
- dnscalyuv = GetDownScaledOutFile(content, width, height, DnScaledW,
- DnScaledH, Path_DnScaleYuv, dnScalAlgo)
+ # downscaling if the downscaled file does not exist
+ dnscalyuv = GetDownScaledOutFile(clip, DnScaledW, DnScaledH,
+ Path_DnScaleYuv, dnScalAlgo)
if not os.path.isfile(dnscalyuv):
- dnscalyuv = DownScaling(content, FrameNum, width, height, DnScaledW,
- DnScaledH, Path_DnScaleYuv, dnScalAlgo)
-
+ dnscalyuv = DownScaling(clip, FrameNum, DnScaledW, DnScaledH,
+ Path_DnScaleYuv, dnScalAlgo, LogCmdOnly)
+ ds_clip = Clip(GetShortContentName(dnscalyuv, False)+'.y4m', dnscalyuv,
+ "", DnScaledW, DnScaledH, clip.fmt, clip.fps_num,
+ clip.fps_denom, clip.bit_depth)
for QP in QPs:
- Utils.Logger.info("start transcode and upscale for %dx%d and QP %d"
- % (DnScaledW, DnScaledH, QP))
- #transcode and upscaling
+ Utils.Logger.info("start encode and upscale for QP %d" % QP)
+ #encode and upscaling
reconyuv = Run_EncDec_Upscale(EncodeMethod, CodecName, EncodePreset,
- dnscalyuv, QP, FrameNum, fr, DnScaledW,
- DnScaledH, width, height, Path_Bitstreams,
+ ds_clip, 'AS', QP, FrameNum, clip.width,
+ clip.height, Path_Bitstreams,
Path_DecodedYuv, Path_DecUpScaleYuv,
- upScalAlgo)
+ Path_CfgFiles, upScalAlgo, LogCmdOnly)
#calcualte quality distortion
- Utils.Logger.info("start quality metric calculation for %dx%d and QP %d"
- % (DnScaledW, DnScaledH, QP))
- CalculateQualityMetric(content, FrameNum, reconyuv, width, height,
- Path_QualityLog, Path_CfgFiles)
-
- if SaveMemory:
- Cleanfolder(Path_DnScaleYuv)
-
+ Utils.Logger.info("start quality metric calculation")
+ CalculateQualityMetric(clip.file_path, FrameNum, reconyuv,
+ clip.fmt, clip.width, clip.height,
+ clip.bit_depth, Path_QualityLog, LogCmdOnly)
+ if SaveMemory:
+ Cleanfolder(Path_DnScaleYuv)
+ Utils.Logger.info("finish running encode test.")
Utils.Logger.info("finish running encode test.")
def Interpolate(RDPoints):
@@ -294,16 +294,16 @@
Utils.Logger.info("start saving RD results to excel file.......")
if not os.path.exists(Path_RDResults):
os.makedirs(Path_RDResults)
- excFile = GetRDResultExcelFile(content)
+ excFile = GetRDResultExcelFile(clip)
wb = xlsxwriter.Workbook(excFile)
shts = []
for i in range(len(dnScAlgos)):
shtname = dnScAlgos[i] + '--' + upScAlgos[i]
shts.append(wb.add_worksheet(shtname))
- cls, width, height, fr, bitdepth, fmt, totalnum = GetVideoInfo(content, Clips)
- DnScaledRes = [(int(width / ratio), int(height / ratio)) for ratio in DnScaleRatio]
- contentname = GetShortContentName(content)
+ DnScaledRes = [(int(clip.width / ratio), int(clip.height / ratio))
+ for ratio in DnScaleRatio]
+ contentname = GetShortContentName(clip.file_name)
for sht, indx in zip(shts, list(range(len(dnScAlgos)))):
# write QP
sht.write(1, 0, "QP")
@@ -328,12 +328,13 @@
bitratesKbps = []; qualities = []
for qp in QPs:
- bs, reconyuv = GetBsReconFileName(EncodeMethod, CodecName,
- EncodePreset, content, width,
- height, DnScaledW, DnScaledH,
- dnScAlgos[indx], upScAlgos[indx],
- qp, Path_Bitstreams)
- bitrate = (os.path.getsize(bs) * 8 * fr / FrameNum) / 1000.0
+ bs, reconyuv = GetBsReconFileName(EncodeMethod, CodecName, 'AS',
+ EncodePreset, clip, DnScaledW,
+ DnScaledH, dnScAlgos[indx],
+ upScAlgos[indx], qp,
+ Path_Bitstreams)
+ bitrate = (os.path.getsize(bs) * 8 * (clip.fps_num / clip.fps_denom)
+ / FrameNum) / 1000.0
bitratesKbps.append(bitrate)
quality = GatherQualityMetrics(reconyuv, Path_QualityLog)
qualities.append(quality)
@@ -397,26 +398,29 @@
help="save memory mode will delete most files in"
" intermediate steps and keeps only necessary "
"ones for RD calculation. It is false by default")
+ parser.add_argument('-CmdOnly', "--LogCmdOnly", dest='LogCmdOnly', type=bool,
+ default=False, metavar='',
+ help="LogCmdOnly mode will only capture the command sequences"
+ "It is false by default")
parser.add_argument('-l', "--LoggingLevel", dest='LogLevel', type=int,
default=3, choices=range(len(LogLevels)), metavar='',
help="logging level: 0:No Logging, 1: Critical, 2: Error,"
" 3: Warning, 4: Info, 5: Debug")
parser.add_argument('-c', "--CodecName", dest='CodecName', type=str,
choices=CodecNames, metavar='',
- help="CodecName: av1 or hevc")
+ help="CodecName: av1")
parser.add_argument('-m', "--EncodeMethod", dest='EncodeMethod', type=str,
choices=EncodeMethods, metavar='',
- help="EncodeMethod: ffmpeg, aom, svt")
+ help="EncodeMethod: aom, svt")
parser.add_argument('-p', "--EncodePreset", dest='EncodePreset', type=str,
- metavar='', help="EncodePreset: medium, slow, fast, etc"
- " for ffmpeg, 0,1,2... for aom and svt")
+ metavar='', help="EncodePreset: 0,1,2... for aom and svt")
if len(raw_args) == 1:
parser.print_help()
sys.exit(1)
args = parser.parse_args(raw_args[1:])
global Function, KeepUpscaledOutput, SaveMemory, LogLevel, CodecName,\
- EncodeMethod, EncodePreset
+ EncodeMethod, EncodePreset, LogCmdOnly
Function = args.Function
KeepUpscaledOutput = args.KeepUpscaledOutput
SaveMemory = args.SaveMemory
@@ -424,15 +428,17 @@
CodecName = args.CodecName
EncodeMethod = args.EncodeMethod
EncodePreset = args.EncodePreset
+ LogCmdOnly = args.LogCmdOnly
######################################
# main
######################################
if __name__ == "__main__":
+ #sys.argv = ["","-f","clean"]
#sys.argv = ["","-f","scaling"]
#sys.argv = ["", "-f", "sumscaling"]
- #sys.argv = ["", "-f", "encode","-c","av1","-m","aom","-p","1"]
+ #sys.argv = ["", "-f", "encode","-c","av1","-m","aom","-p","6"]
#sys.argv = ["", "-f", "convexhull","-c","av1","-m","aom","-p","6"]
#sys.argv = ["", "-f", "summary", "-c", "av1", "-m", "aom", "-p", "6"]
ParseArguments(sys.argv)
@@ -441,41 +447,43 @@
setupWorkFolderStructure()
if Function != 'clean':
SetupLogging(LogLevel, LogCmdOnly, LoggerName, Path_TestLog)
- Contents = GetContents(ContentPath, Clips)
+ clip_list = CreateClipList('AS')
# execute functions
if Function == 'clean':
CleanUp_workfolders()
elif Function == 'scaling':
- for content in Contents:
+ for clip in clip_list:
for dnScaleAlgo, upScaleAlgo in zip(DnScalingAlgos, UpScalingAlgos):
- Run_Scaling_Test(content, dnScaleAlgo, upScaleAlgo,
+ Run_Scaling_Test(clip, dnScaleAlgo, upScaleAlgo,
Path_DnScaleYuv, Path_UpScaleYuv, Path_QualityLog,
- Path_CfgFiles, SaveMemory, KeepUpscaledOutput)
+ Path_CfgFiles, SaveMemory, KeepUpscaledOutput,
+ LogCmdOnly)
elif Function == 'sumscaling':
- SaveScalingResultsToExcel(DnScalingAlgos, UpScalingAlgos, Path_QualityLog)
+ SaveScalingResultsToExcel(DnScalingAlgos, UpScalingAlgos, clip_list,
+ Path_QualityLog)
elif Function == 'encode':
- for content in Contents:
+ for clip in clip_list:
for dnScalAlgo, upScalAlgo in zip(DnScalingAlgos, UpScalingAlgos):
- Run_ConvexHull_Test(content, dnScalAlgo, upScalAlgo)
+ Run_ConvexHull_Test(clip, dnScalAlgo, upScalAlgo, LogCmdOnly)
elif Function == 'convexhull':
- for content in Contents:
- SaveConvexHullResultsToExcel(content, DnScalingAlgos, UpScalingAlgos,
+ for clip in clip_list:
+ SaveConvexHullResultsToExcel(clip, DnScalingAlgos, UpScalingAlgos,
EnablePreInterpolation)
elif Function == 'summary':
RDResultFilesGenerated = []
- for content in Contents:
- RDResultFilesGenerated.append(GetRDResultExcelFile(content))
+ for clip in clip_list:
+ RDResultFilesGenerated.append(GetRDResultExcelFile(clip))
- RDsmfile = GenerateSummaryRDDataExcelFile(EncodeMethod, CodecName, EncodePreset,
- SummaryOutPath, RDResultFilesGenerated,
- ContentPath, Clips)
+ RDsmfile = GenerateSumRDExcelFile(EncodeMethod, CodecName, EncodePreset,
+ SummaryOutPath, RDResultFilesGenerated,
+ clip_list)
Utils.Logger.info("RD data summary file generated: %s" % RDsmfile)
- CvxHsmfile = GenerateSummaryConvexHullExcelFile(EncodeMethod, CodecName,
- EncodePreset, SummaryOutPath,
- RDResultFilesGenerated,
- EnablePreInterpolation)
+ CvxHsmfile = GenerateSumCvxHullExcelFile(EncodeMethod, CodecName,
+ EncodePreset, SummaryOutPath,
+ RDResultFilesGenerated,
+ EnablePreInterpolation)
Utils.Logger.info("Convel hull summary file generated: %s" % CvxHsmfile)
else:
Utils.Logger.error("invalid parameter value of Function")
diff --git a/tools/convexhull_framework/src/EncDecUpscale.py b/tools/convexhull_framework/src/EncDecUpscale.py
index 812eade..66d623a 100644
--- a/tools/convexhull_framework/src/EncDecUpscale.py
+++ b/tools/convexhull_framework/src/EncDecUpscale.py
@@ -15,7 +15,7 @@
from VideoDecoder import VideoDecode
from VideoScaler import UpScaling, GetDownScaledOutFile, GetUpScaledOutFile
from Config import SUFFIX, LoggerName
-from Utils import GetShortContentName
+from Utils import GetShortContentName, Clip
import logging
subloggername = "EncDecUpscale"
@@ -24,62 +24,67 @@
################################################################################
##################### Internal Helper Functions ################################
-def GetBitstreamFile(method, codec, preset, yuvfile, qp, outpath):
+def GetBitstreamFile(method, codec, test_cfg, preset, yuvfile, qp, outpath):
bs_suffix = SUFFIX[codec]
- Prefix_EncodeCfg = '_%s_%s_Preset_%s' % (method, codec, preset)
+ Prefix_EncodeCfg = '_%s_%s_%s_Preset_%s' % (method, codec, test_cfg, preset)
filename = GetShortContentName(yuvfile, False) + Prefix_EncodeCfg + "_QP_"\
+ str(qp) + bs_suffix
filename = os.path.join(outpath, filename)
return filename
def GetDecodedFile(bsfile, outpath):
- filename = GetShortContentName(bsfile, False) + '_Decoded.yuv'
+ filename = GetShortContentName(bsfile, False) + '_Decoded.y4m'
decodedfile = os.path.join(outpath, filename)
return decodedfile
################################################################################
##################### Major Functions ##########################################
-def Encode(method, codec, preset, input, qp, num, framerate, width, height, path):
- bsfile = GetBitstreamFile(method, codec, preset, input, qp, path)
+def Encode(method, codec, preset, clip, test_cfg, qp, num, path,
+ LogCmdOnly=False):
+ bsfile = GetBitstreamFile(method, codec, test_cfg, preset, clip.file_path,
+ qp, path)
# call VideoEncoder to do the encoding
- VideoEncode(method, codec, input, qp, num, framerate, width, height, bsfile,
- preset)
+ VideoEncode(method, codec, clip, test_cfg, qp, num, bsfile, preset,
+ LogCmdOnly)
return bsfile
-
-def Decode(codec, bsfile, path):
+def Decode(codec, bsfile, path, LogCmdOnly=False):
decodedfile = GetDecodedFile(bsfile, path)
#call VideoDecoder to do the decoding
- VideoDecode(codec, bsfile, decodedfile)
+ VideoDecode(codec, bsfile, decodedfile, LogCmdOnly)
return decodedfile
-
-def Run_EncDec_Upscale(method, codec, preset, input, QP, num, framerate, inw,
- inh, outw, outh, path_bs, path_decoded,
- path_upscaled, algo):
- logger.info("%s %s start encode file %s with QP = %d"
- % (method, codec, os.path.basename(input), QP))
- bsFile = Encode(method, codec, preset, input, QP, num, framerate, inw, inh,
- path_bs)
+def Run_EncDec_Upscale(method, codec, preset, clip, test_cfg, QP, num, outw,
+ outh, path_bs, path_decoded, path_upscaled, path_cfg,
+ upscale_algo, LogCmdOnly = False):
+ logger.info("%s %s start encode file %s with QP = %d" %
+ (method, codec, clip.file_name, QP))
+ bsFile = Encode(method, codec, preset, clip, test_cfg, QP, num, path_bs,
+ LogCmdOnly)
logger.info("start decode file %s" % os.path.basename(bsFile))
- decodedYUV = Decode(codec, bsFile, path_decoded)
+ decodedYUV = Decode(codec, bsFile, path_decoded, LogCmdOnly)
logger.info("start upscale file %s" % os.path.basename(decodedYUV))
- upscaledYUV = UpScaling(decodedYUV, num, inw, inh, outw, outh, path_upscaled,
- algo)
+ dec_clip = Clip(GetShortContentName(decodedYUV, False) + '.y4m',
+ decodedYUV, clip.file_class, clip.width, clip.height,
+ clip.fmt, clip.fps_num, clip.fps_denom, clip.bit_depth)
+ upscaledYUV = UpScaling(dec_clip, num, outw, outh, path_upscaled, path_cfg,
+ upscale_algo, LogCmdOnly)
logger.info("finish Run Encode, Decode and Upscale")
return upscaledYUV
-def GetBsReconFileName(encmethod, codecname, preset, content, width, height,
- dnwidth, dnheight, dnScAlgo,
- upScAlgo, qp, path_bs):
- dsyuv_name = GetDownScaledOutFile(content, width, height, dnwidth, dnheight,
- path_bs, dnScAlgo)
+def GetBsReconFileName(encmethod, codecname, test_cfg, preset, clip, dw, dh,
+ dnScAlgo, upScAlgo, qp, path_bs):
+ dsyuv_name = GetDownScaledOutFile(clip, dw, dh, path_bs, dnScAlgo)
# return bitstream file with absolute path
- bs = GetBitstreamFile(encmethod, codecname, preset, dsyuv_name, qp, path_bs)
+ bs = GetBitstreamFile(encmethod, codecname, test_cfg, preset, dsyuv_name,
+ qp, path_bs)
decoded = GetDecodedFile(bs, path_bs)
- reconfilename = GetUpScaledOutFile(decoded, dnwidth, dnheight, width, height,
- path_bs, upScAlgo)
+ ds_clip = Clip(GetShortContentName(decoded, False) + '.y4m',
+ decoded, clip.file_class, dw, dh, clip.fmt, clip.fps_num,
+ clip.fps_denom, clip.bit_depth)
+ reconfilename = GetUpScaledOutFile(ds_clip, clip.width, clip.height,
+ upScAlgo, path_bs)
# return only Recon yuv file name w/o path
- reconfilename = GetShortContentName(reconfilename, False)
+ reconfilename = GetShortContentName(reconfilename, False) + '.y4m'
return bs, reconfilename
diff --git a/tools/convexhull_framework/src/PostAnalysis_Summary.py b/tools/convexhull_framework/src/PostAnalysis_Summary.py
index 290c8c9..c686b48 100644
--- a/tools/convexhull_framework/src/PostAnalysis_Summary.py
+++ b/tools/convexhull_framework/src/PostAnalysis_Summary.py
@@ -79,11 +79,11 @@
# copy the results data from each content's result file to corresponding
# location in summary excel file
- for (cls, contents), row_class in zip(ContentsDict.items(), Rows_Class):
+ for (cls, clip_list), row_class in zip(ClipDict.items(), Rows_Class):
sht.write(row_class, 0, cls)
- rows_content = [i * len(QPs) for i in range(len(contents))]
- for content, row_cont in zip(contents, rows_content):
- key = GetShortContentName(content)
+ rows_content = [i * len(QPs) for i in range(len(clip_list))]
+ for clip, row_cont in zip(clip_list, rows_content):
+ key = GetShortContentName(clip.file_name)
sht.write(row_class + row_cont, 1, key)
rdwb = None
for resfile in resultfiles:
@@ -97,7 +97,7 @@
assert rdwb is not None
if rdwb is None:
logger.warning("not find convex hull result file for content:%s"
- % content)
+ % clip.file_name)
def CalBDRateWithExcel_OneSheet(sht, cols, cols_bdmtrs, cellformat):
row_refst = 0
@@ -106,8 +106,8 @@
sht.write(0, cols_bd, 'BD-Rate %.2f vs. %.2f' % (DnScaleRatio[residx],
DnScaleRatio[0]))
sht.write_row(1, cols_bd, QualityList)
- for (cls, contents), row_class in zip(ContentsDict.items(), Rows_Class):
- rows_content = [i * len(QPs) for i in range(len(contents))]
+ for (cls, clip_list), row_class in zip(ClipDict.items(), Rows_Class):
+ rows_content = [i * len(QPs) for i in range(len(clip_list))]
for row_cont in rows_content:
for y in range(len(QualityList)):
refbr_b = xlrd.cellnameabs(row_class + row_cont + row_refst,
@@ -150,10 +150,10 @@
sht.write(0, cols_bd, 'BD-Rate %.2f vs. %.2f' % (DnScaleRatio[residx],
DnScaleRatio[0]))
sht.write_row(1, cols_bd, QualityList)
- for (cls, contents), row_class in zip(ContentsDict.items(), Rows_Class):
- rows_content = [i * len(QPs) for i in range(len(contents))]
- for row_cont, content in zip(rows_content, contents):
- key = GetShortContentName(content)
+ for (cls, clip_list), row_class in zip(ClipDict.items(), Rows_Class):
+ rows_content = [i * len(QPs) for i in range(len(clip_list))]
+ for row_cont, clip in zip(rows_content, clip_list):
+ key = GetShortContentName(clip.file_name)
for resfile in resultfiles:
if key in resfile:
rdwb = xlrd.open_workbook(resfile)
@@ -214,16 +214,16 @@
startrow = 3
step = len(QPs)
- rows_class_avg = [startrow + step * i for i in range(len(ContentsDict))]
+ rows_class_avg = [startrow + step * i for i in range(len(ClipDict))]
totalnum_content = 0
- for (cls, contents), row_class, rdclassrow in zip(ContentsDict.items(),
+ for (cls, clip_list), row_class, rdclassrow in zip(ClipDict.items(),
rows_class_avg,
Rows_Class):
avg_sht.write(row_class, 0, cls)
- totalnum_content = totalnum_content + len(contents)
- avg_sht.write(row_class, 1, len(contents))
+ totalnum_content = totalnum_content + len(clip_list)
+ avg_sht.write(row_class, 1, len(clip_list))
avg_sht.write_column(row_class, 2, QPs)
- rows_content = [i * len(QPs) for i in range(len(contents))]
+ rows_content = [i * len(QPs) for i in range(len(clip_list))]
for rdcol, col_res, residx in zip(rdcols, cols_res, range(len(DnScaleRatio))):
for i in range(len(QPs)):
@@ -293,7 +293,7 @@
cols_upscl_bd = [step_upscl * i for i in range(len(upScalAlgos))]
step_res = len(upScalAlgos) * step_upscl + colintval_dnscalres
cols_res_bd = [step_res * i + startcol for i in range(len(DnScaleRatio) - 1)]
- rows_class_rdavg = [startrow + i for i in range(len(ContentsDict))]
+ rows_class_rdavg = [startrow + i for i in range(len(ClipDict))]
for residx, col_res_bd in zip(range(1, len(DnScaleRatio)), cols_res_bd):
bdavg_sht.write(0, col_res_bd, 'BD-Rate %.2f vs. %.2f'
@@ -303,13 +303,13 @@
bdavg_sht.write_row(2, col_res_bd + col_upscl_bd, QualityList)
totalnum_content = 0
- for (cls, contents), row_class, rdclassrow in zip(ContentsDict.items(),
+ for (cls, clip_list), row_class, rdclassrow in zip(ClipDict.items(),
rows_class_rdavg,
Rows_Class):
bdavg_sht.write(row_class, 0, cls)
- totalnum_content = totalnum_content + len(contents)
- bdavg_sht.write(row_class, 1, len(contents))
- rows_content = [i * len(QPs) for i in range(len(contents))]
+ totalnum_content = totalnum_content + len(clip_list)
+ bdavg_sht.write(row_class, 1, len(clip_list))
+ rows_content = [i * len(QPs) for i in range(len(clip_list))]
sum_rows = [rdclassrow + row_cont for row_cont in rows_content]
for rdcol, col_res in zip(rd_cols_bdmtrs, cols_res_bd):
# write average bd rate
@@ -350,8 +350,8 @@
# resultfiles is a list of all convex hull RD result files generated by
# runninging '-f convexhull'
# summary_outpath is the folder where output summary file will be
-def GenerateSummaryRDDataExcelFile(encMethod, codecName, preset, summary_outpath,
- resultfiles, content_path, clips):
+def GenerateSumRDExcelFile(encMethod, codecName, preset, summary_outpath,
+ resultfiles, clip_list):
global dnScalAlgos, upScalAlgos
# find all scaling algos tested in results file,
@@ -377,10 +377,8 @@
colInterval = 2
rowstart = 2
# to generate rows number of starting of each class: Rows_Class
- global ContentsDict, Rows_Class
- ContentsDict, Rows_Class = CalcRowsClassAndContentDict(rowstart,
- content_path,
- clips, len(QPs))
+ global ClipDict, Rows_Class
+ ClipDict, Rows_Class = CalcRowsClassAndContentDict(rowstart, clip_list, len(QPs))
# cols is column number of results files
step = colInterval + 1 + len(QualityList) # 1 is for bitrate
sum_wtcols = [step * i + colstart for i in range(len(DnScaleRatio))]
@@ -413,9 +411,8 @@
wb.close()
return smfile
-def GenerateSummaryConvexHullExcelFile(encMethod, codecName, preset,
- summary_outpath, resultfiles,
- EnablePreInterpolation = False):
+def GenerateSumCvxHullExcelFile(encMethod, codecName, preset, summary_outpath,
+ resultfiles, EnablePreInterpolation = False):
if not os.path.exists(summary_outpath):
os.makedirs(summary_outpath)
smfile = GetConvexHullDataSummaryFileName(encMethod, codecName, preset,
@@ -449,10 +446,10 @@
# location in summary excel file
row = 1
rdcolstart = CvxHDataStartCol + 1
- for (cls, contents) in ContentsDict.items():
+ for (cls, clip_list) in ClipDict.items():
sht.write(row, 0, cls)
- for content in contents:
- key = GetShortContentName(content)
+ for clip in clip_list:
+ key = GetShortContentName(clip.file_name)
sht.write(row, 1, key)
for resfile in resultfiles:
if key in resfile:
diff --git a/tools/convexhull_framework/src/ScalingTest.py b/tools/convexhull_framework/src/ScalingTest.py
index aa26d80..510b075 100644
--- a/tools/convexhull_framework/src/ScalingTest.py
+++ b/tools/convexhull_framework/src/ScalingTest.py
@@ -15,11 +15,14 @@
import xlrd
import logging
from CalculateQualityMetrics import CalculateQualityMetric, GatherQualityMetrics
-from VideoScaler import GetDownScaledOutFile, DownScaling, UpScaling, GetUpScaledOutFile
-from Config import DnScaleRatio, FrameNum, Clips, QualityList, LoggerName, Path_ScalingResults, ScalQty_WtCols, \
- ScalQty_startRow, LineColors, ScalSumQty_WtCols, ContentPath
-from Utils import GetVideoInfo, Cleanfolder, GetShortContentName, CreateChart_Scatter, AddSeriesToChart_Scatter, UpdateChart, \
- InsertChartsToSheet, CalcRowsClassAndContentDict, GetContents, CreateChart_Line, AddSeriesToChart_Line
+from VideoScaler import GetDownScaledOutFile, DownScaling, UpScaling,\
+ GetUpScaledOutFile
+from Config import DnScaleRatio, FrameNum, QualityList, LoggerName,\
+ Path_ScalingResults, ScalQty_WtCols, ScalQty_startRow, LineColors, \
+ ScalSumQty_WtCols
+from Utils import Cleanfolder, GetShortContentName, CreateChart_Scatter, \
+ AddSeriesToChart_Scatter, UpdateChart, InsertChartsToSheet, \
+ CalcRowsClassAndContentDict, Clip
subloggername = "ScalingTest"
loggername = LoggerName + '.' + '%s' % subloggername
@@ -34,22 +37,17 @@
return file
def GetScalingResultExcelFile_PerContent(content):
- filename = GetShortContentName(content)
+ filename = GetShortContentName(content, False)
filename = "ScalingResults_%s.xlsx" % filename
file = os.path.join(Path_ScalingResults, filename)
return file
-def Run_Scaling_Test(content, dnScalAlgo, upScalAlgo, path_dnscl, path_upscl,
- path_log, path_cfg, savememory, keepupscaledyuv):
+def Run_Scaling_Test(clip, dnScalAlgo, upScalAlgo, path_dnscl, path_upscl,
+ path_log, path_cfg, savememory, keepupscaledyuv,
+ LogCmdOnly=False):
logger.info("start running scaling tests with content %s"
- % os.path.basename(content))
- cls, width, height, fr, bitdepth, fmt, totalnum = GetVideoInfo(content, Clips)
- if totalnum < FrameNum:
- logger.error("content %s includes total %d frames < specified % frames!"
- % (content, totalnum, FrameNum))
- return
-
- DnScaledRes = [(int(width / ratio), int(height / ratio))
+ % os.path.basename(clip.file_name))
+ DnScaledRes = [(int(clip.width / ratio), int(clip.height / ratio))
for ratio in DnScaleRatio]
for i in range(len(DnScaledRes)):
if savememory:
@@ -59,39 +57,38 @@
DnScaledW = DnScaledRes[i][0]
DnScaledH = DnScaledRes[i][1]
- logger.info("start downscaling content to %dx%d"
- % (DnScaledW, DnScaledH))
+ logger.info("start downscaling content to %dx%d" % (DnScaledW, DnScaledH))
# downscaling
- dnscalyuv = GetDownScaledOutFile(content, width, height, DnScaledW,
- DnScaledH, path_dnscl, dnScalAlgo)
+ dnscalyuv = GetDownScaledOutFile(clip, DnScaledW, DnScaledH,
+ path_dnscl, dnScalAlgo)
if not os.path.isfile(dnscalyuv):
- dnscalyuv = DownScaling(content, FrameNum, width, height, DnScaledW,
- DnScaledH, path_dnscl, dnScalAlgo)
-
- upscaleyuv = UpScaling(dnscalyuv, FrameNum, DnScaledW, DnScaledH, width,
- height, path_upscl, upScalAlgo)
-
- CalculateQualityMetric(content, FrameNum, upscaleyuv, width, height,
- path_log, path_cfg)
-
+ dnscalyuv = DownScaling(clip, FrameNum, DnScaledW, DnScaledH,
+ path_dnscl, path_cfg, dnScalAlgo, LogCmdOnly)
+ dnscaled_clip = Clip(GetShortContentName(dnscalyuv, False)+'.y4m',
+ dnscalyuv, "", DnScaledW, DnScaledH,
+ clip.fmt, clip.fps_num, clip.fps_denom,
+ clip.bit_depth)
+ upscaleyuv = UpScaling(dnscaled_clip, FrameNum, clip.width, clip.height,
+ path_upscl, path_cfg, upScalAlgo, LogCmdOnly)
+ CalculateQualityMetric(clip.file_path, FrameNum, upscaleyuv, clip.fmt,
+ clip.width, clip.height, clip.bit_depth,
+ path_log, LogCmdOnly)
if savememory:
Cleanfolder(path_dnscl)
logger.info("finish running scaling test.")
-def GeneratePerContentExcelFile(dnScalAlgos, upScalAlgos, content, scaleRatios,
- path_log):
- contshortname = GetShortContentName(content)
- logger.info("start generate excel file for content :%s" % contshortname)
- excFile = GetScalingResultExcelFile_PerContent(content)
+def GeneratePerClipExcelFile(dnScalAlgos, upScalAlgos, clip, path_log):
+ logger.info("start generate excel file for content :%s" % clip.file_name)
+ excFile = GetScalingResultExcelFile_PerContent(clip.file_name)
wb = xlsxwriter.Workbook(excFile)
- shtname = contshortname
+ shtname = GetShortContentName(clip.file_name)
sht = wb.add_worksheet(shtname)
sht.write(1, 0, 'Content Name')
- sht.write(2, 0, contshortname)
+ sht.write(2, 0, clip.file_name)
sht.write(1, 1, 'Scaling Ratio')
- sht.write_column(2, 1, scaleRatios)
+ sht.write_column(2, 1, DnScaleRatio)
pre_title = ['Width', 'Height', 'DnScaledWidth', 'DnScaledHeight']
sht.write_row(1, 2, pre_title)
for dn_algo, up_algo, col in zip(dnScalAlgos, upScalAlgos, ScalQty_WtCols):
@@ -99,13 +96,12 @@
sht.write(0, col, algos)
sht.write_row(1, col, QualityList)
- cls, w, h, fr, bitdepth, fmt, totalnum = GetVideoInfo(content, Clips)
- rows = [ScalQty_startRow + i for i in range(len(scaleRatios))]
+ rows = [ScalQty_startRow + i for i in range(len(DnScaleRatio))]
continfos = []
- for ratio, row in zip(scaleRatios, rows):
- dw = int(w / ratio)
- dh = int(h / ratio)
- info = [w, h, dw, dh]
+ for ratio, row in zip(DnScaleRatio, rows):
+ dw = int(clip.width / ratio)
+ dh = int(clip.height / ratio)
+ info = [clip.width, clip.height, dw, dh]
sht.write_row(row, 2, info)
continfos.append(info)
@@ -121,15 +117,17 @@
range(len(dnScalAlgos))):
qualities = []
seriname = dn_algo + '--' + up_algo
- for ratio, row, idx in zip(scaleRatios, rows, range(len(scaleRatios))):
+ for ratio, row, idx in zip(DnScaleRatio, rows, range(len(DnScaleRatio))):
w = continfos[idx][0]
h = continfos[idx][1]
dw = continfos[idx][2]
dh = continfos[idx][3]
- dnScalOut = GetDownScaledOutFile(content, w, h, dw, dh,
- path_log, dn_algo)
- upScalOut = GetUpScaledOutFile(dnScalOut, dw, dh, w, h,
- path_log, up_algo)
+ dnScalOut = GetDownScaledOutFile(clip, dw, dh, path_log, dn_algo)
+ ds_clip = Clip(GetShortContentName(dnScalOut, False) + '.y4m',
+ dnScalOut, "", dw, dh, clip.fmt, clip.fps_num, clip.fps_denom,
+ clip.bit_depth)
+ upScalOut = GetUpScaledOutFile(ds_clip, clip.width, clip.height,
+ up_algo, path_log)
qtys = GatherQualityMetrics(upScalOut, path_log)
sht.write_row(row, col, qtys)
qualities.append(qtys)
@@ -175,16 +173,15 @@
sht.write_row(1, col, QualityList)
content_infos = {}; totalnum_contents = 0
- for (clss, contents), row_clss in zip(ContentsDict.items(), Rows_Class):
+ for (clss, clip_list), row_clss in zip(ClipDict.items(), Rows_Class):
sht.write(row_clss, 0, clss)
- totalnum_contents = totalnum_contents + len(contents)
- for content, row_cont in zip(contents, range(len(contents))):
- cl, w, h, fr, bitdepth, fmt, totalnum = GetVideoInfo(content, Clips)
- dw = int(w / ratio)
- dh = int(h / ratio)
- shortcntname = GetShortContentName(content)
+ totalnum_contents = totalnum_contents + len(clip_list)
+ for clip, row_cont in zip(clip_list, range(len(clip_list))):
+ dw = int(clip.width / ratio)
+ dh = int(clip.height / ratio)
+ shortcntname = GetShortContentName(clip.file_name, False)
sht.write(row_clss + row_cont, 2, shortcntname)
- infos = [w, h, dw, dh]
+ infos = [clip.width, clip.height, dw, dh]
sht.write_row(row_clss + row_cont, 3, infos)
content_infos[shortcntname] = infos
@@ -202,17 +199,18 @@
range(len(dnScalAlgos))):
qualities = []
seriname = dn_algo + '--' + up_algo
- for (clss, contents), row_clss in zip(ContentsDict.items(), Rows_Class):
- for content, row_cont in zip(contents, range(len(contents))):
- key = GetShortContentName(content)
+ for (clss, clip_list), row_clss in zip(ClipDict.items(), Rows_Class):
+ for clip, row_cont in zip(clip_list, range(len(clip_list))):
+ key = GetShortContentName(clip.file_name, False)
w = content_infos[key][0]
h = content_infos[key][1]
dw = content_infos[key][2]
dh = content_infos[key][3]
- dnScalOut = GetDownScaledOutFile(content, w, h, dw, dh,
- path_log, dn_algo)
- upScalOut = GetUpScaledOutFile(dnScalOut, dw, dh, w, h,
- path_log, up_algo)
+ dnScalOut = GetDownScaledOutFile(clip, dw, dh, path_log, dn_algo)
+ ds_clip = Clip(GetShortContentName(dnScalOut, False) + '.y4m',
+ dnScalOut, clss, dw, dh, clip.fmt, clip.fps_num,
+ clip.fps_denom, clip.bit_depth)
+ upScalOut = GetUpScaledOutFile(ds_clip, w, h, up_algo, path_log)
qtys = GatherQualityMetrics(upScalOut, path_log)
sht.write_row(row_clss + row_cont, col, qtys)
qualities.append(qtys)
@@ -260,7 +258,7 @@
sht.write(0, col, algos)
sht.write_row(1, col, StatsMetrics)
- step = len(ContentsDict) + 1 # 1 extra row for total of each class
+ step = len(ClipDict) + 1 # 1 extra row for total of each class
startrow = 2
rows_qtymtr = [startrow + step * i for i in range(len(QualityList))]
for qty, row_qm, y in zip(QualityList, rows_qtymtr, range(len(QualityList))):
@@ -272,11 +270,11 @@
#charts.append(chart)
totalnum_contents = 0
- for (cls, contents), idx, rdrow_cls in zip(ContentsDict.items(),
- range(len(ContentsDict)),
+ for (cls, clip_list), idx, rdrow_cls in zip(ClipDict.items(),
+ range(len(ClipDict)),
Rows_Class):
sht.write(row_qm + idx, 1, cls)
- num_content = len(contents)
+ num_content = len(clip_list)
totalnum_contents = totalnum_contents + num_content
sht.write(row_qm + idx, 2, num_content)
for rdcol, wtcol in zip(ScalSumQty_WtCols, cols_avg):
@@ -302,7 +300,7 @@
sht.write(row_qm + idx, wtcol + 3, formula)
#write total contents statistics
- wtrow = row_qm + len(ContentsDict)
+ wtrow = row_qm + len(ClipDict)
sht.write(wtrow, 1, 'Total')
sht.write(wtrow, 2, totalnum_contents)
for rdcol, wtcol in zip(ScalSumQty_WtCols, cols_avg):
@@ -330,28 +328,25 @@
logger.info("finish average sheet for ratio:%2.2f." % ratio)
-
-def SaveScalingResultsToExcel(dnScalAlgos, upScalAlgos, path_log):
+def SaveScalingResultsToExcel(dnScalAlgos, upScalAlgos, clip_list, path_log):
logger.info("start saving scaling quality results to excel files.......")
if not os.path.exists(Path_ScalingResults):
os.makedirs(Path_ScalingResults)
logger.info("start generating per content scaling quality excel file.......")
- contents = GetContents(ContentPath, Clips)
- for content in contents:
- GeneratePerContentExcelFile(dnScalAlgos, upScalAlgos, content,
- DnScaleRatio, path_log)
+ for clip in clip_list:
+ GeneratePerClipExcelFile(dnScalAlgos, upScalAlgos, clip, path_log)
scaleRatios = DnScaleRatio
- scaleRatios.remove(1.0)
+ if (1.0 in scaleRatios):
+ scaleRatios.remove(1.0)
logger.info("start generating scaling quality summary excel file.......")
- sumexcFile = GetScalingResultExcelFile(len(scaleRatios), len(DnScaleRatio))
+ sumexcFile = GetScalingResultExcelFile(len(scaleRatios), len(dnScalAlgos))
wb = xlsxwriter.Workbook(sumexcFile)
# to generate rows number of starting of each class: Rows_Class
- global ContentsDict, Rows_Class
- ContentsDict, Rows_Class = CalcRowsClassAndContentDict(ScalQty_startRow,
- ContentPath, Clips)
-
+ global ClipDict, Rows_Class
+ ClipDict, Rows_Class = CalcRowsClassAndContentDict(ScalQty_startRow,
+ clip_list)
sumShts = []
for ratio in scaleRatios:
sht = GenerateSummarySheet(wb, dnScalAlgos, upScalAlgos, ratio, path_log)
diff --git a/tools/convexhull_framework/src/Utils.py b/tools/convexhull_framework/src/Utils.py
index ccac884..7023239 100644
--- a/tools/convexhull_framework/src/Utils.py
+++ b/tools/convexhull_framework/src/Utils.py
@@ -12,10 +12,36 @@
import os
import re
+import sys
import subprocess
import time
import logging
-from Config import LogLevels, Have_Class_Subfolder
+from Config import LogLevels, ContentPath
+from AV2CTCVideo import Y4M_CLIPs, CTC_TEST_SET, AS_TEST_SET
+
+class Clip:
+ file_name = ""
+ file_path = ""
+ file_class = ""
+ width = 0
+ height = 0
+ fmt = ""
+ fps_num = 0
+ fps_denom = 0
+ fps = 0
+ bit_depth = 0
+
+ def __init__(self, Name="", Path = "", Class="", Width=0, Height=0, Fmt="", FPS_num=0, FPS_denom=0, Bit_depth=0):
+ self.file_name = Name
+ self.file_path = Path
+ self.file_class = Class
+ self.width = Width
+ self.height = Height
+ self.fmt = Fmt
+ self.fps_num = FPS_num
+ self.fps_denom = FPS_denom
+ self.fps = round(self.fps_num / self.fps_denom)
+ self.bit_depth = Bit_depth
def Cleanfolder(folder):
if os.path.isdir(folder):
@@ -44,73 +70,64 @@
name = basename
return name
-def GetContents(contentpath, clips):
- contents = []
- for key, val in clips.items():
- folder = contentpath
- if Have_Class_Subfolder:
- cls = val[0]
- folder = os.path.join(contentpath, cls)
+def parseY4MHeader(y4m):
+ """
+ Parse y4m information from its header.
+ """
+ w = 0; h = 0; fps_num = 0; fps_denom = 0; fr = 0; fmt = "420"; bit_depth = 8;
+ #print("parsing " + y4m)
+ with open(y4m, 'rb') as f:
+ line = f.readline().decode('utf-8')
+ #YUV4MPEG2 W4096 H2160 F30000:1001 Ip A0:0 C420p10 XYSCSS=420P10
+ m = re.search(r"W([0-9]+) H([0-9]+) F([0-9]+)\:([0-9]+)", line)
+ if m:
+ w = int(m.group(1))
+ h = int(m.group(2))
+ fps_num = float(m.group(3))
+ fps_denom = float(m.group(4))
+ fps = round(fps_num / fps_denom)
+ m = re.search(r"C([0-9]+)p([0-9]+)", line)
+ if m:
+ fmt = m.group(1)
+ bit_depth = int(m.group(2))
+ if w == 0 or h == 0 or fps == 0:
+ print("Failed to parse the input y4m file!\n")
+ sys.exit()
+ return (w, h, fps_num, fps_denom, fps, fmt, bit_depth)
- file = os.path.join(folder, key) + ".yuv"
- if os.path.isfile(file):
- contents.append(file)
+def CreateClipList(test_cfg):
+ clip_list = []; test_set = []
+ #[filename, class, width, height, fps_num, fps_denom, bitdepth, fmt]
+ test_set = AS_TEST_SET if (test_cfg == 'AS') else CTC_TEST_SET
- return contents
+ for cls in test_set:
+ for file in Y4M_CLIPs[cls]:
+ y4m = os.path.join(ContentPath, cls, file)
+ w, h, fps_num, fps_denom, fps, fmt, bit_depth = parseY4MHeader(y4m)
+ clip = Clip(file, y4m, cls, w, h, fmt, fps_num, fps_denom, bit_depth)
+ clip_list.append(clip)
+ return clip_list
-def GetVideoInfo(content, Clips):
- basename = GetShortContentName(content, False)
- cls = Clips[basename][0]
- width = Clips[basename][1]
- height = Clips[basename][2]
- fr = Clips[basename][3]
- bitdepth = Clips[basename][4]
- fmt = Clips[basename][5]
-
- #default for 8 bit 420
- RatioForFrameSize = 3/2
- if fmt == 'yuv422p':
- RatioForFrameSize = 2
- elif fmt == 'yuv444p':
- RatioForFrameSize = 3
- if bitdepth > 8:
- RatioForFrameSize *= 2
-
- totalnum = os.path.getsize(content) / (width * height * RatioForFrameSize)
-
- return cls, width, height, fr, bitdepth, fmt, totalnum
-
-def GetContentDict(contentpath, clips):
+def GetContentDict(clip_list):
dict = {}
-
- if Have_Class_Subfolder:
- for key, val in clips.items():
- cls = val[0]
- folder = os.path.join(contentpath, cls)
- file = os.path.join(folder, key) + ".yuv"
- if os.path.isfile(file):
- if cls in dict:
- if file not in dict[cls]:
- dict[cls].append(file)
- else:
- dict[cls] = [file]
- else:
- # this is for case no subfolder/class. As * is forbidden for folder name,
- # no folder will be same as this
- cls = "*All"
- dict[cls] = GetContents(contentpath, clips)
-
+ for clip in clip_list:
+ cls = clip.file_class
+ file = clip.file_path
+ if os.path.isfile(file):
+ if cls in dict:
+ if clip not in dict[cls]:
+ dict[cls].append(clip)
+ else:
+ dict[cls] = [clip]
return dict
-def CalcRowsClassAndContentDict(rowstart, content_path, clips, times=1):
- contentsdict = GetContentDict(content_path, clips)
-
+def CalcRowsClassAndContentDict(rowstart, clip_list, times=1):
+ contentsdict = GetContentDict(clip_list)
ofstc = rowstart
rows_class = []
- for cls, contents in contentsdict.items():
+ for cls, clips in contentsdict.items():
rows_class.append(ofstc)
- ofstc = ofstc + len(contents) * times
-
+ ofstc = ofstc + len(clips) * times
return contentsdict, rows_class
@@ -223,13 +240,13 @@
if logcmdonly or level != 0:
global CmdLogger
- logfilename = os.path.join(path, 'ConvexHullTestCmd_%s.log'
- % time.strftime("%Y%m%d-%H%M%S"))
+ logfilename = os.path.join(path, '%s_TestCmd_%s.log'
+ % (name, time.strftime("%Y%m%d-%H%M%S")))
CmdLogger = open(logfilename, 'w')
if level != 0:
- logfilename = os.path.join(path, 'ConvexHullTest_%s.log'
- % time.strftime("%Y%m%d-%H%M%S"))
+ logfilename = os.path.join(path, '%s_Test_%s.log'
+ % (name, time.strftime("%Y%m%d-%H%M%S")))
hdlr = logging.FileHandler(logfilename)
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
hdlr.setFormatter(formatter)
diff --git a/tools/convexhull_framework/src/VideoDecoder.py b/tools/convexhull_framework/src/VideoDecoder.py
index 84146bd..8841d3b 100644
--- a/tools/convexhull_framework/src/VideoDecoder.py
+++ b/tools/convexhull_framework/src/VideoDecoder.py
@@ -11,23 +11,17 @@
__author__ = "maggie.sun@intel.com, ryan.lei@intel.com"
import Utils
-from Config import BinPath, LogCmdOnly, FFMPEG, AOMDEC
+from Config import AOMDEC
from Utils import ExecuteCmd
-#use ffmpeg to decode bitstream
-def DecodeWithFfmpeg(infile, outfile):
- args = " -y -i %s -pix_fmt yuv420p -c:v rawvideo %s" % (infile, outfile)
- cmd = FFMPEG + args
- ExecuteCmd(cmd, LogCmdOnly)
-
-def DecodeWithAOM(infile, outfile):
- args = " --codec=av1 --i420 --rawvideo --summary -o %s %s" % (outfile, infile)
+def DecodeWithAOM(infile, outfile, LogCmdOnly=False):
+ args = " --codec=av1 --summary -o %s %s" % (outfile, infile)
cmd = AOMDEC + args
ExecuteCmd(cmd, LogCmdOnly)
-def VideoDecode(codec, infile, outfile):
+def VideoDecode(codec, infile, outfile, LogCmdOnly=False):
Utils.CmdLogger.write("::Decode\n")
- if codec == 'AV1':
- DecodeWithAOM(infile, outfile)
+ if codec == 'av1':
+ DecodeWithAOM(infile, outfile, LogCmdOnly)
else:
- DecodeWithFfmpeg(infile, outfile)
+ raise ValueError("invalid parameter for decode.")
diff --git a/tools/convexhull_framework/src/VideoEncoder.py b/tools/convexhull_framework/src/VideoEncoder.py
index 412e710..89e7c43 100644
--- a/tools/convexhull_framework/src/VideoEncoder.py
+++ b/tools/convexhull_framework/src/VideoEncoder.py
@@ -11,72 +11,53 @@
__author__ = "maggie.sun@intel.com, ryan.lei@intel.com"
import Utils
-from Config import BinPath, LogCmdOnly, FFMPEG, AOMENC, SVTAV1, SVTHEVC
+from Config import AOMENC, SVTAV1
from Utils import ExecuteCmd
-#use ffmpeg to encode video
-def EncodeWithFfmpeg_HEVC(infile, QP, num,fr, width, height, outfile, preset):
- EncodeProfile = 'main'
- args = " -y -s %dx%d -pix_fmt yuv420p -r %s -i %s -frames:v %d -g %d -bf 7" \
- " -bsf:v hevc_mp4toannexb -c:v libx265 -preset %s -profile:v %s " \
- "-x265-params \"qp=%d:aq-mode=0:b-adapt=0:bframes=7:b-pyramid=1:" \
- "no-scenecut=1:no-open-gop=1:input-depth=8:output-depth=8\" %s" % (
- width, height, fr, infile, num, int(2 * fr), # gop size = 2 seconds
- preset, EncodeProfile, (QP+3), outfile)
- cmd = FFMPEG + args
- ExecuteCmd(cmd, LogCmdOnly)
+def EncodeWithAOM_AV1(clip, test_cfg, QP, framenum, outfile, preset,
+ LogCmdOnly=False):
+ args = " --verbose --codec=av1 -v --psnr --obu --frame-parallel=0" \
+ " --cpu-used=%s --limit=%d --auto-alt-ref=1 --passes=1" \
+ " --end-usage=q --i%s --threads=1 --end-usage=q" \
+ " --use-fixed-qp-offsets=1 --deltaq-mode=0 --enable-tpl-model=0" \
+ " --enable-keyframe-filtering=0 --fps=%d/%d --input-bit-depth=%d" \
+ " --bit-depth=%d --qp=%d -w %d -h %d" \
+ % (preset, framenum, clip.fmt, clip.fps_num, clip.fps_denom, clip.bit_depth,
+ clip.bit_depth, 4*QP, clip.width, clip.height)
-def EncodeWithAOM_AV1(infile, QP, framenum, framerate, width, height, outfile,
- preset):
- args = " --verbose --codec=av1 -v --psnr --ivf --frame-parallel=0 --cpu-used=%s" \
- " --limit=%d --auto-alt-ref=1 --passes=1 --end-usage=q --i420" \
- " --min-gf-interval=16 --max-gf-interval=16 --gf-min-pyr-height=4 " \
- " --gf-max-pyr-height=4 --threads=1 --lag-in-frames=19 --end-usage=q " \
- " --kf-min-dist=65 --kf-max-dist=65 --use-fixed-qp-offsets=1 --deltaq-mode=0 " \
- " --enable-tpl-model=0 --enable-keyframe-filtering=0 " \
- " --fps=60/1 --input-bit-depth=8 --qp=%d -w %d -h %d -o %s %s"\
- % (preset, framenum, 4*QP, width, height, outfile, infile)
+ if test_cfg == "RA" or test_cfg == "AS":
+ args += " --min-gf-interval=16 --max-gf-interval=16 --gf-min-pyr-height=4" \
+ " --gf-max-pyr-height=4 --kf-min-dist=65 --kf-max-dist=65" \
+ " --lag-in-frames=19"
+ elif test_cfg == "LD":
+ args += " --kf-min-dist=9999 --kf-max-dist=9999 --lag-in-frames=0" \
+ " --subgop-config-str=ld"
+ else:
+ print("Unsupported Test Configuration %s" % test_cfg)
+ args += " -o %s %s" % (outfile, clip.file_path)
cmd = AOMENC + args
ExecuteCmd(cmd, LogCmdOnly)
-def EncodeWithSVT_AV1(infile, QP, framenum, framerate, width, height, outfile,
- preset):
+def EncodeWithSVT_AV1(clip, test_cfg, QP, framenum, outfile, preset,
+ LogCmdOnly=False):
+ #TODO: update svt parameters
args = " --preset %s --scm 2 --lookahead 0 --hierarchical-levels 3 -n %d" \
" --keyint 255 -rc 0 -q %d -w %d -h %d -b %s -i %s"\
- % (str(preset), framenum, QP, width, height, outfile, infile)
+ % (str(preset), framenum, QP, clip.width, clip.height, outfile,
+ clip.file_path)
cmd = SVTAV1 + args
ExecuteCmd(cmd, LogCmdOnly)
-def EncodeWithSVT_HEVC(infile, QP, framenum, framerate, width, height, outfile,
- preset):
- args = " -i %s -w %d -h %d -encMode %s -hierarchical-levels 3" \
- " -intra-period 100 -scd 0 -rc 0 -q %d -n %d -b %s"\
- % (infile, width, height, preset, QP, framenum, outfile)
- cmd = SVTHEVC + args
- ExecuteCmd(cmd, LogCmdOnly)
-
-def VideoEncode(EncodeMethod, CodecName, infile, QP, framenum, framerate, width,
- height, outfile, preset):
+def VideoEncode(EncodeMethod, CodecName, clip, test_cfg, QP, framenum, outfile,
+ preset, LogCmdOnly=False):
Utils.CmdLogger.write("::Encode\n")
- if EncodeMethod == "ffmpeg":
- if CodecName == 'hevc':
- EncodeWithFfmpeg_HEVC(infile, QP, framenum, framerate, width, height,
- outfile, preset)
- else:
- raise ValueError("invalid parameter for encode.")
- elif EncodeMethod == "aom":
- if CodecName == 'av1':
- EncodeWithAOM_AV1(infile, QP, framenum, framerate, width, height,
- outfile, preset)
- else:
- raise ValueError("invalid parameter for encode.")
- elif EncodeMethod == "svt":
- if CodecName == 'av1':
- EncodeWithSVT_AV1(infile, QP, framenum, framerate, width, height,
- outfile, preset)
- elif CodecName == 'hevc':
- EncodeWithSVT_HEVC(infile, QP, framenum, framerate, width, height,
- outfile, preset)
+ if CodecName == 'av1':
+ if EncodeMethod == "aom":
+ EncodeWithAOM_AV1(clip, test_cfg, QP, framenum, outfile, preset,
+ LogCmdOnly)
+ elif EncodeMethod == "svt":
+ EncodeWithSVT_AV1(clip, test_cfg, QP, framenum, outfile, preset,
+ LogCmdOnly)
else:
raise ValueError("invalid parameter for encode.")
else:
diff --git a/tools/convexhull_framework/src/VideoScaler.py b/tools/convexhull_framework/src/VideoScaler.py
index 51e85c0..25af1b3 100644
--- a/tools/convexhull_framework/src/VideoScaler.py
+++ b/tools/convexhull_framework/src/VideoScaler.py
@@ -13,77 +13,124 @@
import os
import Utils
import logging
-from Config import BinPath, LogCmdOnly, LoggerName, FFMPEG
+import fileinput
+from shutil import copyfile
+from Config import LoggerName, FFMPEG, HDRToolsConfigFileTemplate, HDRConvert
from Utils import GetShortContentName, ExecuteCmd
subloggername = "VideoScaler"
loggername = LoggerName + '.' + '%s' % subloggername
logger = logging.getLogger(loggername)
-def ValidAlgo_ffmpeg(algo):
- if (algo == 'bicubic' or algo == 'lanczos' or algo == 'sinc' or
- algo == 'bilinear' or algo == 'spline' or algo == 'gauss' or
- algo == 'bicublin' or algo == 'neighbor'):
- return True
- else:
- return False
+def GenerateCfgFile(clip, outw, outh, algo, outfile, num, configpath):
+ contentBaseName = GetShortContentName(clip.file_name, False)
+ cfg_filename = contentBaseName + ('_Scaled_%s_%dx%d.cfg'% (algo, outw, outh))
+ fmt = 1
+ if (clip.fmt == '400'):
+ fmt = 0
+ elif (clip.fmt == '420'):
+ fmt = 1
+ elif (clip.fmt == '422'):
+ fmt = 2
+ elif (clip.fmt == '444'):
+ fmt = 3
-#use ffmpeg to do image rescaling for yuv420 8bit
-def RescaleWithFfmpeg(infile, inw, inh, outw, outh, algo, outfile, num, app_path):
- args = " -y -s:v %dx%d -i %s -vf scale=%dx%d -c:v rawvideo -pix_fmt yuv420p" \
- " -sws_flags %s+accurate_rnd+full_chroma_int+full_chroma_inp+bitexact"\
- "+print_info -sws_dither none" \
- % (inw, inh, infile, outw, outh, algo)
- if (algo == 'lanczos'):
- args += " -param0 5 "
- args += " -frames %d %s" % (num, outfile)
- cmd = FFMPEG + args
+ cfgfile = os.path.join(configpath, cfg_filename)
+ copyfile(HDRToolsConfigFileTemplate, cfgfile)
+ fp = fileinput.input(cfgfile, inplace=1)
+ for line in fp:
+ if 'SourceFile=' in line:
+ line = 'SourceFile="%s"\n' % clip.file_path
+ if 'OutputFile=' in line:
+ line = 'OutputFile="%s"\n' % outfile
+ if 'SourceWidth=' in line:
+ line = 'SourceWidth=%d\n' % clip.width
+ if 'SourceHeight=' in line:
+ line = 'SourceHeight=%d\n' % clip.height
+ if 'OutputWidth=' in line:
+ line = 'OutputWidth=%d\n' % outw
+ if 'OutputHeight=' in line:
+ line = 'OutputHeight=%d\n' % outh
+ if 'ScalingMode=' in line:
+ line = 'ScalingMode=3\n'
+ if 'LanczosLobes=' in line:
+ line = 'LanczosLobes=5\n'
+ if 'SourceRate=' in line:
+ line = 'SourceRate=%4.4f\n' % (float)(clip.fps_num / clip.fps_denom)
+ if 'SourceChromaFormat=' in line:
+ line = 'SourceChromaFormat=%d\n' % fmt
+ if 'SourceBitDepthCmp0=' in line:
+ line = 'SourceBitDepthCmp0=%d\n' % clip.bit_depth
+ if 'SourceBitDepthCmp1=' in line:
+ line = 'SourceBitDepthCmp1=%d\n' % clip.bit_depth
+ if 'SourceBitDepthCmp2=' in line:
+ line = 'SourceBitDepthCmp2=%d\n' % clip.bit_depth
+ if 'OutputRate=' in line:
+ line = 'OutputRate=%4.4f\n' % (float)(clip.fps_num / clip.fps_denom)
+ if 'OutputChromaFormat=' in line:
+ line = 'OutputChromaFormat=%d\n' % fmt
+ if 'OutputBitDepthCmp0=' in line:
+ line = 'OutputBitDepthCmp0=%d\n' % clip.bit_depth
+ if 'OutputBitDepthCmp1=' in line:
+ line = 'OutputBitDepthCmp1=%d\n' % clip.bit_depth
+ if 'OutputBitDepthCmp2=' in line:
+ line = 'OutputBitDepthCmp2=%d\n' % clip.bit_depth
+ if 'NumberOfFrames=' in line:
+ line = 'NumberOfFrames=%d\n' % num
+ print(line, end='')
+ fp.close()
+ return cfgfile
+
+def RescaleWithHDRTool(clip, outw, outh, algo, outfile, num, cfg_path,
+ LogCmdOnly = False):
+ cfg_file = GenerateCfgFile(clip, outw, outh, algo, outfile, num, cfg_path)
+ args = " -f %s" % cfg_file
+ cmd = HDRConvert + args
ExecuteCmd(cmd, LogCmdOnly)
-def VideoRescaling(infile, num, inw, inh, outw, outh, outfile, algo):
- if ValidAlgo_ffmpeg(algo):
- RescaleWithFfmpeg(infile, inw, inh, outw, outh, algo, outfile, num, BinPath)
+def VideoRescaling(clip, num, outw, outh, outfile, algo, cfg_path,
+ LogCmdOnly = False):
+ RescaleWithHDRTool(clip, outw, outh, algo, outfile, num, cfg_path, LogCmdOnly)
# add other tools for scaling here later
- else:
- logger.error("unsupported scaling algorithm.")
####################################################################################
##################### Major Functions ################################################
-def GetDownScaledOutFile(input, inw, inh, dnw, dnh, path, algo):
- contentBaseName = GetShortContentName(input)
- actual_algo = 'None' if inw == dnw and inh == dnh else algo
- filename = contentBaseName + ('_DnScaled_%s_%dx%d.yuv' % (actual_algo, dnw,
+def GetDownScaledOutFile(clip, dnw, dnh, path, algo):
+ contentBaseName = GetShortContentName(clip.file_name, False)
+ actual_algo = 'None' if clip.width == dnw and clip.height == dnh else algo
+ filename = contentBaseName + ('_Scaled_%s_%dx%d.y4m' % (actual_algo, dnw,
dnh))
dnscaledout = os.path.join(path, filename)
return dnscaledout
-def GetUpScaledOutFile(infile, inw, inh, outw, outh, path, algo):
- actual_algo = 'None' if inw == outw and inh == outh else algo
- filename = GetShortContentName(infile, False) + ('_UpScaled_%s_%dx%d.yuv'
- % (actual_algo, outw, outh))
+def GetUpScaledOutFile(clip, outw, outh, algo, path):
+ actual_algo = 'None' if clip.width == outw and clip.height == outh else algo
+ filename = GetShortContentName(clip.file_name, False) + \
+ ('_Scaled_%s_%dx%d.y4m' % (actual_algo, outw, outh))
upscaledout = os.path.join(path, filename)
return upscaledout
-def DownScaling(input, num, inw, inh, outw, outh, path, algo):
- dnScalOut = GetDownScaledOutFile(input, inw, inh, outw, outh, path, algo)
+def DownScaling(clip, num, outw, outh, path, cfg_path, algo, LogCmdOnly = False):
+ dnScalOut = GetDownScaledOutFile(clip, outw, outh, path, algo)
Utils.CmdLogger.write("::Downscaling\n")
- if (inw == outw and inh == outh):
- cmd = "copy %s %s" % (input, dnScalOut)
+ if (clip.width == outw and clip.height == outh):
+ cmd = "copy %s %s" % (clip.file_path, dnScalOut)
ExecuteCmd(cmd, LogCmdOnly)
else:
# call separate process to do the downscaling
- VideoRescaling(input, num, inw, inh, outw, outh, dnScalOut, algo)
+ VideoRescaling(clip, num, outw, outh, dnScalOut, algo, cfg_path,
+ LogCmdOnly)
return dnScalOut
-def UpScaling(infile, num, inw, inh, outw, outh, path, algo):
- upScaleOut = GetUpScaledOutFile(infile, inw, inh, outw, outh, path, algo)
-
+def UpScaling(clip, num, outw, outh, path, cfg_path, algo, LogCmdOnly = False):
+ upScaleOut = GetUpScaledOutFile(clip, outw, outh, algo, path)
Utils.CmdLogger.write("::Upscaling\n")
- if (inw == outw and inh == outh):
- cmd = "copy %s %s" % (infile, upScaleOut)
+ if (clip.width == outw and clip.height == outh):
+ cmd = "copy %s %s" % (clip.file_path, upScaleOut)
ExecuteCmd(cmd, LogCmdOnly)
else:
# call separate process to do the upscaling
- VideoRescaling(infile, num, inw, inh, outw, outh, upScaleOut, algo)
+ VideoRescaling(clip, num, outw, outh, upScaleOut, algo, cfg_path,
+ LogCmdOnly)
return upScaleOut