update regular expression for runtime parsing

1.update the CTC test script to resolve the issue in the regular expression when parsing the run time information for
MacOS and Linux
2.add support to dump out per frame rd data
3.add support to dump out temporal layer id into per frame rd data

Change-Id: If82f0fa4b64473f43477b789b0784e2a22aa4502
diff --git a/tools/convexhull_framework/src/AV2CTCTest.py b/tools/convexhull_framework/src/AV2CTCTest.py
index 166a7a7..48125fa 100644
--- a/tools/convexhull_framework/src/AV2CTCTest.py
+++ b/tools/convexhull_framework/src/AV2CTCTest.py
@@ -16,10 +16,10 @@
 import argparse
 from CalculateQualityMetrics import CalculateQualityMetric, GatherQualityMetrics
 from Utils import GetShortContentName, CreateNewSubfolder, SetupLogging, \
-     Cleanfolder, CreateClipList
+     Cleanfolder, CreateClipList, GetEncLogFile
 import Utils
 from Config import LogLevels, FrameNum, TEST_CONFIGURATIONS, QPs, WorkPath, \
-     Path_RDResults, LoggerName, QualityList, Platform
+     Path_RDResults, LoggerName, QualityList, Platform, MIN_GOP_LENGTH
 from EncDecUpscale import Encode, Decode, GetEncPerfFile, GetDecPerfFile
 
 ###############################################################################
@@ -32,8 +32,11 @@
 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
+    avg_file = os.path.join(Path_RDResults, filename)
+    filename = "Perframe_RDResults_%s_%s_%s_Preset_%s.csv" % \
+               (EncodeMethod, CodecName, test_cfg, EncodePreset)
+    perframe_data = os.path.join(Path_RDResults, filename)
+    return avg_file, perframe_data
 
 def GetBsReconFileName(EncodeMethod, CodecName, EncodePreset, test_cfg, clip, QP):
     basename = GetShortContentName(clip.file_name, False)
@@ -45,22 +48,22 @@
     dec = os.path.join(Path_DecodedYuv, filename)
     return bs, dec
 
-
 def setupWorkFolderStructure():
     global Path_Bitstreams, Path_DecodedYuv, Path_QualityLog, Path_TestLog,\
-           Path_CfgFiles, Path_TimingLog
+           Path_CfgFiles, Path_TimingLog, Path_EncLog
     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")
     Path_TimingLog = CreateNewSubfolder(WorkPath, "perfLogs")
+    Path_EncLog = CreateNewSubfolder(WorkPath, "encLogs")
 
 ###############################################################################
 ######### Major Functions #####################################################
 def CleanUp_workfolders():
     folders = [Path_Bitstreams, Path_DecodedYuv, Path_QualityLog,
-               Path_TestLog, Path_CfgFiles, Path_TimingLog]
+               Path_TestLog, Path_CfgFiles, Path_TimingLog, Path_EncLog]
     for folder in folders:
         Cleanfolder(folder)
 
@@ -74,7 +77,7 @@
             Utils.CmdLogger.write("============== Job Start =================\n")
         bsFile = Encode('aom', 'av1', preset, clip, test_cfg, QP,
                         FrameNum[test_cfg], Path_Bitstreams, Path_TimingLog,
-                        LogCmdOnly)
+                        Path_EncLog, LogCmdOnly)
         Utils.Logger.info("start decode file %s" % os.path.basename(bsFile))
         #decode
         decodedYUV = Decode('av1', bsFile, Path_DecodedYuv, Path_TimingLog,
@@ -99,7 +102,7 @@
         if Platform == "Windows":
             m = re.search(r"Execution time:\s+(\d+\.?\d*)", line)
         else:
-            m = re.search(r"User time (seconds):\s+(\d+\.?\d*)", line)
+            m = re.search(r"User time \(seconds\):\s+(\d+\.?\d*)", line)
         if m:
             enc_time = float(m.group(1))
     flog.close()
@@ -109,19 +112,56 @@
         if Platform == "Windows":
             m = re.search(r"Execution time:\s+(\d+\.?\d*)", line)
         else:
-            m = re.search(r"User time (seconds):\s+(\d+\.?\d*)", line)
+            m = re.search(r"User time \(seconds\):\s+(\d+\.?\d*)", line)
         if m:
             dec_time = float(m.group(1))
     flog.close()
     return enc_time, dec_time
 
+#TODO: This function needs to be revised later
+def GetTempLayerID(poc):
+    temp_layer_id = 0; mod = poc % MIN_GOP_LENGTH
+    if (mod == 0):
+        temp_layer_id = 0
+    elif (mod == 8):
+        temp_layer_id = 1
+    elif (mod == 4 or mod == 12):
+        temp_layer_id = 2
+    elif (mod == 2 or mod == 6 or mod == 10 or mod == 14):
+        temp_layer_id = 3
+    else:
+        temp_layer_id = 5
+    return temp_layer_id
+
+def GatherPerframeStat(test_cfg,EncodeMethod,CodecName,EncodePreset,clip,qp,enc_log,perframe_csv,perframe_vmaf_log):
+    enc_list = [''] * len(perframe_vmaf_log)
+    flog = open(enc_log, 'r')
+
+    for line in flog:
+        if line.startswith("POC"):
+            #POC:     0 [ KEY ][Q:143]:      40272 Bytes, 1282.9ms, 36.5632 dB(Y), 45.1323 dB(U), 46.6284 dB(V), 38.0736 dB(Avg)    [  0,  0,  0,  0,  0,  0,  0,]
+            m = re.search(r"POC:\s+(\d+)\s+\[( KEY |INTER)\]\[Q:\s*(\d+)\]:\s+(\d+)\s+Bytes,",line)
+            if m:
+                POC = m.group(1)
+                frame_type = m.group(2)
+                qindex = m.group(3)
+                frame_size = m.group(4)
+                if enc_list[int(POC)] == '':
+                    enc_list[int(POC)] = "%s,%s,%s,%s"%(POC,frame_type,qindex,frame_size)
+
+    for i in range(len(enc_list)):
+        #"TestCfg,EncodeMethod,CodecName,EncodePreset,Class,Res,Name,FPS,BitDepth,QP,POC,TempLayerId,FrameType,qindex,FrameSize")
+        perframe_csv.write("%s,%s,%s,%s,%s,%s,%s,%s,%d,%d,%s,%s\n"
+                           %(test_cfg,EncodeMethod,CodecName,EncodePreset,clip.file_class,str(clip.width)+"x"+str(clip.height),
+                             clip.file_name,clip.fps,clip.bit_depth,qp,enc_list[i],perframe_vmaf_log[i]))
+
 def GenerateSummaryRDDataFile(EncodeMethod, CodecName, EncodePreset,
-                              test_cfg, clip_list):
+                              test_cfg, clip_list, log_path):
     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_file, perframe_csvfile = GetRDResultCsvFile(EncodeMethod, CodecName, EncodePreset, test_cfg)
     csv = open(csv_file, 'wt')
     csv.write("TestCfg,EncodeMethod,CodecName,EncodePreset,Class,Res,Name,FPS,"\
               "Bit Depth,QP,")
@@ -134,6 +174,14 @@
     csv.write(",EncT[s],DecT[s],EncT[h]")
     csv.write('\n')
 
+    perframe_csv = open(perframe_csvfile, 'wt')
+    perframe_csv.write("TestCfg,EncodeMethod,CodecName,EncodePreset,Class,Res,Name,FPS," \
+                       "Bit Depth,QP,POC,FrameType,qindex,FrameSize")
+    for qty in QualityList:
+        if (qty != "Overall_PSNR" and qty != "Overall_APSNR" and not qty.startswith("APSNR")):
+            perframe_csv.write(',' + qty)
+    perframe_csv.write('\n')
+
     for clip in clip_list:
         for qp in QPs[test_cfg]:
             bs, dec = GetBsReconFileName(EncodeMethod, CodecName, EncodePreset,
@@ -141,7 +189,7 @@
             filesize = os.path.getsize(bs)
             bitrate = (filesize * 8 * (clip.fps_num / clip.fps_denom)
                        / FrameNum[test_cfg]) / 1000.0
-            quality = GatherQualityMetrics(dec, Path_QualityLog)
+            quality, perframe_vmaf_log = GatherQualityMetrics(dec, Path_QualityLog)
             csv.write("%s,%s,%s,%s,%s,%s,%s,%.2f,%d,%d,"
                       %(test_cfg,EncodeMethod,CodecName,EncodePreset,clip.file_class,
                         str(clip.width)+'x'+str(clip.height), clip.file_name,
@@ -156,7 +204,10 @@
             enc_time, dec_time = GatherPerfInfo(bs, Path_TimingLog)
             enc_hour = (enc_time / 3600.0)
             csv.write(",%.2f,%.2f,%.2f,\n"%(enc_time,dec_time,enc_hour))
-
+            if (EncodeMethod == 'aom'):
+                enc_log = GetEncLogFile(bs, log_path)
+                GatherPerframeStat(test_cfg,EncodeMethod,CodecName,EncodePreset,clip,qp,enc_log,perframe_csv,
+                                   perframe_vmaf_log)
     Utils.Logger.info("finish export RD results to file.")
     return
 
@@ -200,7 +251,7 @@
 ######################################
 if __name__ == "__main__":
     #sys.argv = ["", "-f", "encode", "-p","1"]
-    #sys.argv = ["", "-f", "summary", "-p", "1"]
+    #sys.argv = ["", "-f", "summary", "-p","1"]
     ParseArguments(sys.argv)
 
     # preparation for executing functions
@@ -220,7 +271,7 @@
         for test_cfg in TEST_CONFIGURATIONS:
             clip_list = CreateClipList(test_cfg)
             GenerateSummaryRDDataFile('aom', 'av1', EncodePreset,
-                                      test_cfg, clip_list)
+                                      test_cfg, clip_list, Path_EncLog)
         Utils.Logger.info("RD data summary file generated")
     else:
         Utils.Logger.error("invalid parameter value of Function")
diff --git a/tools/convexhull_framework/src/CalcQtyWithVmafTool.py b/tools/convexhull_framework/src/CalcQtyWithVmafTool.py
index a6c4fce..9b60cb1 100644
--- a/tools/convexhull_framework/src/CalcQtyWithVmafTool.py
+++ b/tools/convexhull_framework/src/CalcQtyWithVmafTool.py
@@ -28,8 +28,42 @@
 
 def ParseVMAFLogFile(vmaf_log):
     floats = len(VMAFMetricsFullList) * [0.0]
+    per_frame_log = []
     flog = open(vmaf_log, 'r')
     for line in flog:
+        m = re.search(r"<frame\s+frameNum=\"(\d+)\"",line)
+        if m:
+            frameNum = m.group(1)
+        m = re.search(r"<frame\s+(.*)\s+psnr_y=\"(\d+\.?\d*)\"",line)
+        if m:
+            psnr_y = m.group(2)
+        m = re.search(r"<frame\s+(.*)\s+psnr_cb=\"(\d+\.?\d*)\"", line)
+        if m:
+            psnr_cb = m.group(2)
+        m = re.search(r"<frame\s+(.*)\s+psnr_cr=\"(\d+\.?\d*)\"", line)
+        if m:
+            psnr_cr = m.group(2)
+        m = re.search(r"<frame\s+(.*)\s+float_ssim=\"(\d+\.?\d*)\"", line)
+        if m:
+            ssim = m.group(2)
+        m = re.search(r"<frame\s+(.*)\s+psnr_hvs=\"(\d+\.?\d*)\"", line)
+        if m:
+            psnr_hvs = m.group(2)
+        m = re.search(r"<frame\s+(.*)\s+float_ms_ssim=\"(\d+\.?\d*)\"", line)
+        if m:
+            ms_ssim = m.group(2)
+        m = re.search(r"<frame\s+(.*)\s+ciede2000=\"(\d+\.?\d*)\"", line)
+        if m:
+            ciede2000 = m.group(2)
+        m = re.search(r"<frame\s+(.*)\s+vmaf=\"(\d+\.?\d*)\"", line)
+        if m:
+            vmaf = m.group(2)
+        m = re.search(r"<frame\s+(.*)\s+vmaf_neg=\"(\d+\.?\d*)\"", line)
+        if m:
+            vmaf_neg = m.group(2)
+            per_frame_log.append("%s,%s,%s,%s,%s,%s,%s,%s,%s"%
+                                (psnr_y,psnr_cb,psnr_cr,ssim,ms_ssim,vmaf,vmaf_neg,psnr_hvs,
+                                 ciede2000))
         m = re.search(r"\"vmaf\".*\s+mean=\"(\d+\.?\d*)\"\s+",line)
         if m:
             floats[0] = m.group(1)
@@ -81,7 +115,7 @@
         print_str += "%s = %2.5f, " % (metrics, floats[idx])
     logger.info(print_str)
 
-    return floats[0:len(VMAFMetricsFullList)]
+    return floats[0:len(VMAFMetricsFullList)], per_frame_log
 
 
 def GetVMAFLogFile(recfile, path):
@@ -94,12 +128,12 @@
 def VMAF_CalQualityMetrics(origfile, recfile, fmt, num, w, h, bit_depth,
                            logfilePath, LogCmdOnly=False):
     vmaf_log = GetVMAFLogFile(recfile, logfilePath)
-    args = " -r %s -d %s --aom_ctc v1.0 -q  -o %s" \
+    args = " -r %s -d %s --aom_ctc v1.0 -q --threads 4 -o %s" \
            % (origfile, recfile, vmaf_log)
     cmd = VMAF + args
     ExecuteCmd(cmd, LogCmdOnly)
 
 def VMAF_GatherQualityMetrics(recfile, logfilePath):
     vmaf_log = GetVMAFLogFile(recfile, logfilePath)
-    results = ParseVMAFLogFile(vmaf_log)
-    return results
+    results, per_frame_log = ParseVMAFLogFile(vmaf_log)
+    return results, per_frame_log
diff --git a/tools/convexhull_framework/src/CalculateQualityMetrics.py b/tools/convexhull_framework/src/CalculateQualityMetrics.py
index cdf99a2..ada29c7 100644
--- a/tools/convexhull_framework/src/CalculateQualityMetrics.py
+++ b/tools/convexhull_framework/src/CalculateQualityMetrics.py
@@ -27,7 +27,7 @@
                            bit_depth, logfilePath, LogCmdOnly)
 
 def GatherQualityMetrics(reconYUV, logfilePath):
-    qresult = VMAF_GatherQualityMetrics(reconYUV, logfilePath)
+    qresult, per_frame_log = VMAF_GatherQualityMetrics(reconYUV, logfilePath)
     results = []
     for metric in QualityList:
         if metric in VMAFMetricsFullList:
@@ -37,4 +37,4 @@
             logger.error("invalid quality metrics in QualityList")
             results.append(0.0)
 
-    return results
+    return results, per_frame_log
diff --git a/tools/convexhull_framework/src/Config.py b/tools/convexhull_framework/src/Config.py
index 5931688..c10595e 100644
--- a/tools/convexhull_framework/src/Config.py
+++ b/tools/convexhull_framework/src/Config.py
@@ -20,7 +20,7 @@
 ######################################
 # configuration settings
 ######################################
-RootPath = "..\\"
+RootPath = "..//"
 BinPath = os.path.join(RootPath, 'bin')
 WorkPath = os.path.join(RootPath, 'test')
 SMOKE_TEST = False  # override some parameters to do a quick smoke test
@@ -35,7 +35,7 @@
 Platform = platform.system()
 
 ############ test contents #######################################
-ContentPath = "D:\\YUVs\\AV2-CTC"
+ContentPath = "D://YUVs//AV2-CTC"
 ############## Scaling settings ############################################
 # down scaling ratio
 DnScaleRatio = [1.0, 1.5, 2.0, 3.0, 4.0, 6.0]  # downscale ratio
@@ -64,6 +64,7 @@
     "AS" : [23, 31, 39, 47, 55, 63],
     "STILL" : [15, 23, 31, 39, 47, 55],
 }
+MIN_GOP_LENGTH = 16
 
 ######################## quality evalution config #############################
 QualityList = ['PSNR_Y','PSNR_U','PSNR_V','Overall_PSNR','SSIM_Y(dB)','MS-SSIM_Y(dB)','VMAF_Y',
diff --git a/tools/convexhull_framework/src/ConvexHullTest.py b/tools/convexhull_framework/src/ConvexHullTest.py
index 8c5feef..866927d 100644
--- a/tools/convexhull_framework/src/ConvexHullTest.py
+++ b/tools/convexhull_framework/src/ConvexHullTest.py
@@ -337,7 +337,7 @@
                 bitrate = (os.path.getsize(bs) * 8 * (clip.fps_num / clip.fps_denom)
                            / FrameNum['AS']) / 1000.0
                 bitratesKbps.append(bitrate)
-                quality = GatherQualityMetrics(reconyuv, Path_QualityLog)
+                quality, perframe_vmaf_log = GatherQualityMetrics(reconyuv, Path_QualityLog)
                 qualities.append(quality)
 
             sht.write_column(CvxH_WtRows[0], col, bitratesKbps)
diff --git a/tools/convexhull_framework/src/EncDecUpscale.py b/tools/convexhull_framework/src/EncDecUpscale.py
index 00e7cc2..f0ee617 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, Clip
+from Utils import GetShortContentName, Clip, GetEncLogFile
 import logging
 
 subloggername = "EncDecUpscale"
@@ -48,13 +48,14 @@
 ################################################################################
 ##################### Major Functions ##########################################
 def Encode(method, codec, preset, clip, test_cfg, qp, num, bs_path, perf_path,
-           LogCmdOnly=False):
+           log_path, LogCmdOnly=False):
     bsfile = GetBitstreamFile(method, codec, test_cfg, preset, clip.file_path,
                               qp, bs_path)
     enc_perf = GetEncPerfFile(bsfile, perf_path)
+    enc_log = GetEncLogFile(bsfile, log_path)
     # call VideoEncoder to do the encoding
     VideoEncode(method, codec, clip, test_cfg, qp, num, bsfile, preset, enc_perf,
-                LogCmdOnly)
+                enc_log, LogCmdOnly)
     return bsfile
 
 def Decode(codec, bsfile, path, perf_path, LogCmdOnly=False):
@@ -66,11 +67,11 @@
 
 def Run_EncDec_Upscale(method, codec, preset, clip, test_cfg, QP, num, outw,
                        outh, path_bs, path_decoded, path_upscaled, path_cfg,
-                       path_perf, upscale_algo, LogCmdOnly = False):
+                       path_perf, path_enc_log, 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,
-                    path_perf, LogCmdOnly)
+                    path_perf, path_enc_log, LogCmdOnly)
     logger.info("start decode file %s" % os.path.basename(bsFile))
     decodedYUV = Decode(codec, bsFile, path_decoded, path_perf, LogCmdOnly)
     logger.info("start upscale file %s" % os.path.basename(decodedYUV))
diff --git a/tools/convexhull_framework/src/ScalingTest.py b/tools/convexhull_framework/src/ScalingTest.py
index db1ad93..f6e4710 100644
--- a/tools/convexhull_framework/src/ScalingTest.py
+++ b/tools/convexhull_framework/src/ScalingTest.py
@@ -128,7 +128,7 @@
                  clip.bit_depth)
             upScalOut = GetUpScaledOutFile(ds_clip, clip.width, clip.height,
                                            up_algo, path_log)
-            qtys = GatherQualityMetrics(upScalOut, path_log)
+            qtys, perframe_vmaf_log = GatherQualityMetrics(upScalOut, path_log)
             sht.write_row(row, col, qtys)
             qualities.append(qtys)
         for x in range(len(QualityList)):
@@ -211,7 +211,7 @@
                                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)
+                qtys, perframe_vmaf_log = GatherQualityMetrics(upScalOut, path_log)
                 sht.write_row(row_clss + row_cont, col, qtys)
                 qualities.append(qtys)
 
diff --git a/tools/convexhull_framework/src/Utils.py b/tools/convexhull_framework/src/Utils.py
index e759612..f22012b 100644
--- a/tools/convexhull_framework/src/Utils.py
+++ b/tools/convexhull_framework/src/Utils.py
@@ -71,6 +71,10 @@
         name = basename
     return name
 
+def GetEncLogFile(bsfile, logpath):
+    filename = GetShortContentName(bsfile, False) + '_EncLog.txt'
+    return os.path.join(logpath, filename)
+
 def parseY4MHeader(y4m):
     """
     Parse y4m information from its header.
diff --git a/tools/convexhull_framework/src/VideoDecoder.py b/tools/convexhull_framework/src/VideoDecoder.py
index 21d372a..f2ecfba 100644
--- a/tools/convexhull_framework/src/VideoDecoder.py
+++ b/tools/convexhull_framework/src/VideoDecoder.py
@@ -20,6 +20,8 @@
     if EnableTimingInfo:
         if Platform == "Windows":
             cmd = "ptime " + cmd + " >%s"%dec_perf
+        elif Platform == "Darwin":
+            cmd = "gtime --verbose --output=%s "%dec_perf + cmd
         else:
             cmd = "/usr/bin/time --verbose --output=%s "%dec_perf + cmd
     ExecuteCmd(cmd, LogCmdOnly)
diff --git a/tools/convexhull_framework/src/VideoEncoder.py b/tools/convexhull_framework/src/VideoEncoder.py
index d9582b8..50f7d32 100644
--- a/tools/convexhull_framework/src/VideoEncoder.py
+++ b/tools/convexhull_framework/src/VideoEncoder.py
@@ -27,10 +27,10 @@
     return quantizer_to_qindex[QP]
 
 def EncodeWithAOM_AV1(clip, test_cfg, QP, framenum, outfile, preset, enc_perf,
-                      LogCmdOnly=False):
+                      enc_log, LogCmdOnly=False):
     args = " --verbose --codec=av1 -v --psnr --obu --frame-parallel=0" \
            " --cpu-used=%s --limit=%d --passes=1 --end-usage=q --i%s " \
-           " --end-usage=q --use-fixed-qp-offsets=1 --deltaq-mode=0 " \
+           " --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 --cq-level=%d -w %d -h %d" \
            % (preset, framenum, clip.fmt, clip.fps_num, clip.fps_denom,
@@ -56,39 +56,43 @@
     else:
         print("Unsupported Test Configuration %s" % test_cfg)
     args += " -o %s %s" % (outfile, clip.file_path)
-    cmd = AOMENC + args
+    cmd = AOMENC + args + "> %s 2>&1"%enc_log
     if (EnableTimingInfo):
         if Platform == "Windows":
             cmd = "ptime " + cmd + " >%s"%enc_perf
+        elif Platform == "Darwin":
+            cmd = "gtime --verbose --output=%s "%enc_perf + cmd
         else:
             cmd = "/usr/bin/time --verbose --output=%s "%enc_perf + cmd
     ExecuteCmd(cmd, LogCmdOnly)
 
 def EncodeWithSVT_AV1(clip, test_cfg, QP, framenum, outfile, preset, enc_perf,
-                      LogCmdOnly=False):
+                      enc_log, 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, clip.width, clip.height, outfile,
               clip.file_path)
-    cmd = SVTAV1 + args
+    cmd = SVTAV1 + args + "> %s 2>&1"%enc_log
     if EnableTimingInfo:
         if Platform == "Windows":
             cmd = "ptime " + cmd + " >%s"%enc_perf
+        elif Platform == "Darwin":
+            cmd = "gtime --verbose --output=%s "%enc_perf + cmd
         else:
-            cmd = "/usr/bin/time --verbose --output=%s"%enc_perf + cmd
+            cmd = "/usr/bin/time --verbose --output=%s "%enc_perf + cmd
     ExecuteCmd(cmd, LogCmdOnly)
 
 def VideoEncode(EncodeMethod, CodecName, clip, test_cfg, QP, framenum, outfile,
-                preset, enc_perf, LogCmdOnly=False):
+                preset, enc_perf, enc_log, LogCmdOnly=False):
     Utils.CmdLogger.write("::Encode\n")
     if CodecName == 'av1':
         if EncodeMethod == "aom":
             EncodeWithAOM_AV1(clip, test_cfg, QP, framenum, outfile, preset,
-                              enc_perf, LogCmdOnly)
+                              enc_perf, enc_log, LogCmdOnly)
         elif EncodeMethod == "svt":
             EncodeWithSVT_AV1(clip, test_cfg, QP, framenum, outfile, preset,
-                              enc_perf, LogCmdOnly)
+                              enc_perf, enc_log, LogCmdOnly)
         else:
             raise ValueError("invalid parameter for encode.")
     else: