Browse Source

更新

tags/V2.7.4^2
chenyukun 1 year ago
parent
commit
c9a1694495
29 changed files with 1646 additions and 209 deletions
  1. +61
    -38
      .idea/workspace.xml
  2. BIN
      common/__pycache__/Constant.cpython-38.pyc
  3. BIN
      common/__pycache__/YmlConstant.cpython-38.pyc
  4. +5
    -4
      concurrency/CommonThread.py
  5. +1
    -1
      concurrency/FileUploadThread.py
  6. +80
    -43
      concurrency/IntelligentRecognitionProcess.py
  7. BIN
      concurrency/__pycache__/CommonThread.cpython-38.pyc
  8. +1
    -1
      enums/BaiduSdkEnum.py
  9. +1
    -1
      enums/ExceptionEnum.py
  10. +3
    -3
      test/aliyun/vod.py
  11. +6
    -6
      test/aliyun/vodTest.py
  12. +3
    -3
      test/aliyun/voddemo.py
  13. +3
    -3
      test/aliyun/vodtest2.py
  14. +20
    -18
      test/序列化/Test.py
  15. +15
    -15
      test/线程/Test.py
  16. +46
    -28
      util/AliyunSdk.py
  17. +58
    -45
      util/Cv2Utils.py
  18. +26
    -0
      util/ModelUtils.py
  19. BIN
      util/__pycache__/LogUtils.cpython-38.pyc
  20. +730
    -0
      vodsdk/AliyunVodUploader.py
  21. +327
    -0
      vodsdk/AliyunVodUtils.py
  22. +87
    -0
      vodsdk/UploadAttachedMediaRequest.py
  23. +84
    -0
      vodsdk/UploadImageRequest.py
  24. +86
    -0
      vodsdk/UploadVideoRequest.py
  25. +3
    -0
      vodsdk/__init__.py
  26. BIN
      vodsdk/__pycache__/AliyunVodUploader.cpython-38.pyc
  27. BIN
      vodsdk/__pycache__/AliyunVodUtils.cpython-38.pyc
  28. BIN
      vodsdk/__pycache__/UploadVideoRequest.cpython-38.pyc
  29. BIN
      vodsdk/__pycache__/__init__.cpython-38.pyc

+ 61
- 38
.idea/workspace.xml View File

@@ -5,8 +5,26 @@
</component>
<component name="ChangeListManager">
<list default="true" id="4f7dccd9-8f92-4a6e-90cc-33890d102263" name="Changes" comment="Changes">
<change afterPath="$PROJECT_DIR$/vodsdk/AliyunVodUploader.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/vodsdk/AliyunVodUtils.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/vodsdk/UploadAttachedMediaRequest.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/vodsdk/UploadImageRequest.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/vodsdk/UploadVideoRequest.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/vodsdk/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/Constant.py" beforeDir="false" afterPath="$PROJECT_DIR$/common/Constant.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/concurrency/CommonThread.py" beforeDir="false" afterPath="$PROJECT_DIR$/concurrency/CommonThread.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/concurrency/FileUploadThread.py" beforeDir="false" afterPath="$PROJECT_DIR$/concurrency/FileUploadThread.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/concurrency/IntelligentRecognitionProcess.py" beforeDir="false" afterPath="$PROJECT_DIR$/concurrency/IntelligentRecognitionProcess.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enums/BaiduSdkEnum.py" beforeDir="false" afterPath="$PROJECT_DIR$/enums/BaiduSdkEnum.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enums/ExceptionEnum.py" beforeDir="false" afterPath="$PROJECT_DIR$/enums/ExceptionEnum.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test/aliyun/vod.py" beforeDir="false" afterPath="$PROJECT_DIR$/test/aliyun/vod.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test/aliyun/vodTest.py" beforeDir="false" afterPath="$PROJECT_DIR$/test/aliyun/vodTest.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test/aliyun/voddemo.py" beforeDir="false" afterPath="$PROJECT_DIR$/test/aliyun/voddemo.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test/aliyun/vodtest2.py" beforeDir="false" afterPath="$PROJECT_DIR$/test/aliyun/vodtest2.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test/序列化/Test.py" beforeDir="false" afterPath="$PROJECT_DIR$/test/序列化/Test.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test/线程/Test.py" beforeDir="false" afterPath="$PROJECT_DIR$/test/线程/Test.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/util/AliyunSdk.py" beforeDir="false" afterPath="$PROJECT_DIR$/util/AliyunSdk.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/util/Cv2Utils.py" beforeDir="false" afterPath="$PROJECT_DIR$/util/Cv2Utils.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/util/ModelUtils.py" beforeDir="false" afterPath="$PROJECT_DIR$/util/ModelUtils.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
@@ -136,7 +154,7 @@
"WebServerToolWindowPanel.toolwindow.show.date": "false",
"WebServerToolWindowPanel.toolwindow.show.permissions": "false",
"WebServerToolWindowPanel.toolwindow.show.size": "false",
"last_opened_file_path": "D:/tuoheng/fanbojiaoyu",
"last_opened_file_path": "D:/tuoheng/codenew/tuoheng_dsp",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
@@ -150,11 +168,11 @@
}]]></component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="D:\tuoheng\codenew\tuoheng_alg" />
<recent name="D:\tuoheng\codenew\tuoheng_alg\test\color" />
<recent name="D:\tuoheng\codenew\tuoheng_alg\test\cuda" />
<recent name="D:\tuoheng\codenew\tuoheng_alg\util" />
<recent name="D:\tuoheng\codenew\tuoheng_alg\test" />
<recent name="D:\tuoheng\codenew\tuoheng_alg\test\aliyun" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="D:\tuoheng\codenew\tuoheng_alg\font" />
@@ -163,8 +181,8 @@
<recent name="D:\work\alg\tuoheng_alg\image" />
</key>
</component>
<component name="RunManager" selected="Python.color_test">
<configuration name="IntelligentRecognitionProcess" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<component name="RunManager" selected="Python.Test (1)">
<configuration name="AliyunSdk" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="tuoheng_alg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
@@ -172,12 +190,12 @@
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/concurrency" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/concurrency/IntelligentRecognitionProcess.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/AliyunSdk.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
@@ -186,7 +204,7 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="color_test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<configuration name="Test (1)" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="tuoheng_alg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
@@ -194,12 +212,12 @@
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test/color" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test/线程" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/color/color_test.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/线程/Test.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
@@ -208,20 +226,20 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="editImage" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
<configuration name="Test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="tuoheng_alg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="$PROJECT_DIR$/../../../software/anaconda/envs/test/python.exe" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test/editimage" />
<option name="IS_MODULE_SDK" value="false" />
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test/序列化" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/editimage/editImage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/序列化/Test.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
@@ -230,7 +248,7 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="mysqltest" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
<configuration name="color_test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="tuoheng_alg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
@@ -238,12 +256,12 @@
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test/color" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/mysqltest.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/color/color_test.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
@@ -252,20 +270,20 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test (2)" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<configuration name="editImage" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
<module name="tuoheng_alg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test/进程" />
<option name="IS_MODULE_SDK" value="true" />
<option name="SDK_HOME" value="$PROJECT_DIR$/../../../software/anaconda/envs/test/python.exe" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test/editimage" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/进程/test.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/editimage/editImage.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
@@ -274,7 +292,7 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<configuration name="mysqltest" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
<module name="tuoheng_alg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
@@ -282,12 +300,12 @@
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test/集合" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/集合/test.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/mysqltest.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
@@ -296,7 +314,7 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test1" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<configuration name="test (2)" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="tuoheng_alg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
@@ -304,12 +322,12 @@
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test/cuda" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test/进程" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/cuda/test1.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/进程/test.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
@@ -321,19 +339,19 @@
<list>
<item itemvalue="Python.editImage" />
<item itemvalue="Python.mysqltest" />
<item itemvalue="Python.Test (1)" />
<item itemvalue="Python.AliyunSdk" />
<item itemvalue="Python.Test" />
<item itemvalue="Python.color_test" />
<item itemvalue="Python.test (2)" />
<item itemvalue="Python.IntelligentRecognitionProcess" />
<item itemvalue="Python.test" />
<item itemvalue="Python.test1" />
</list>
<recent_temporary>
<list>
<item itemvalue="Python.Test (1)" />
<item itemvalue="Python.AliyunSdk" />
<item itemvalue="Python.Test" />
<item itemvalue="Python.color_test" />
<item itemvalue="Python.test (2)" />
<item itemvalue="Python.IntelligentRecognitionProcess" />
<item itemvalue="Python.test" />
<item itemvalue="Python.test1" />
</list>
</recent_temporary>
</component>
@@ -489,7 +507,11 @@
<workItem from="1683506530261" duration="919000" />
<workItem from="1683507482567" duration="15434000" />
<workItem from="1683591783960" duration="1186000" />
<workItem from="1683677260592" duration="8827000" />
<workItem from="1683677260592" duration="21750000" />
<workItem from="1683762579964" duration="23871000" />
<workItem from="1683851036596" duration="51000" />
<workItem from="1683851900729" duration="83000" />
<workItem from="1683851995142" duration="23673000" />
</task>
<servers />
</component>
@@ -557,7 +579,7 @@
<SUITE FILE_PATH="coverage/tuoheng_alg$dsp_master.coverage" NAME="dsp_master 覆盖结果" MODIFIED="1680503755624" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
<SUITE FILE_PATH="coverage/tuoheng_alg$test.coverage" NAME="test 覆盖结果" MODIFIED="1682582986112" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test/集合" />
<SUITE FILE_PATH="coverage/tuoheng_alg$IntelligentRecognitionProcess.coverage" NAME="IntelligentRecognitionProcess 覆盖结果" MODIFIED="1682651444560" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/concurrency" />
<SUITE FILE_PATH="coverage/tuoheng_alg$Test.coverage" NAME="Test 覆盖结果" MODIFIED="1681810213173" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test/序列化" />
<SUITE FILE_PATH="coverage/tuoheng_alg$Test.coverage" NAME="Test 覆盖结果" MODIFIED="1683802532361" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test/序列化" />
<SUITE FILE_PATH="coverage/tuoheng_alg$mysqltest.coverage" NAME="mysqltest Coverage Results" MODIFIED="1660868712851" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test" />
<SUITE FILE_PATH="coverage/tuoheng_alg$asnyc__1_.coverage" NAME="asnyc (1) Coverage Results" MODIFIED="1663458917599" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test" />
<SUITE FILE_PATH="coverage/tuoheng_alg$cv2test1.coverage" NAME="cv2test1 覆盖结果" MODIFIED="1665738045603" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="/home/DATA/chenyukun/algSch/test/" />
@@ -576,6 +598,7 @@
<SUITE FILE_PATH="coverage/tuoheng_alg$gputest.coverage" NAME="gputest 覆盖结果" MODIFIED="1681950938970" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test/gpu" />
<SUITE FILE_PATH="coverage/tuoheng_alg$1.coverage" NAME="协程1 覆盖结果" MODIFIED="1667866542122" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test/协程" />
<SUITE FILE_PATH="coverage/tuoheng_alg___$3.coverage" NAME="协程3 覆盖结果" MODIFIED="1668147029048" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test/协程" />
<SUITE FILE_PATH="coverage/tuoheng_alg$AliyunSdk.coverage" NAME="AliyunSdk 覆盖结果" MODIFIED="1683803902993" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
<SUITE FILE_PATH="coverage/tuoheng_alg$asnyc.coverage" NAME="asnyc Coverage Results" MODIFIED="1663459033435" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test" />
<SUITE FILE_PATH="coverage/tuoheng_alg$5.coverage" NAME="视频添加图片水印5 Coverage Results" MODIFIED="1661905982885" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test" />
<SUITE FILE_PATH="coverage/tuoheng_alg$read.coverage" NAME="read Coverage Results" MODIFIED="1663640070956" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test" />
@@ -583,7 +606,7 @@
<SUITE FILE_PATH="coverage/tuoheng_alg$TimeUtils.coverage" NAME="TimeUtils Coverage Results" MODIFIED="1661222768678" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/util" />
<SUITE FILE_PATH="coverage/tuoheng_alg$producer_start1.coverage" NAME="producer_start1 覆盖结果" MODIFIED="1671428635702" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test/kafka" />
<SUITE FILE_PATH="coverage/tuoheng_alg___$producer_stop.coverage" NAME="producer_stop 覆盖结果" MODIFIED="1668522920533" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="/home/thsw/chenyukun/algSch" />
<SUITE FILE_PATH="coverage/tuoheng_alg$Test__1_.coverage" NAME="Test (1) 覆盖结果" MODIFIED="1681199611277" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test/线程" />
<SUITE FILE_PATH="coverage/tuoheng_alg$Test__1_.coverage" NAME="Test (1) 覆盖结果" MODIFIED="1683865962957" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test/线程" />
<SUITE FILE_PATH="coverage/tuoheng_alg$ffmpeg13.coverage" NAME="ffmpeg13 覆盖结果" MODIFIED="1675394160900" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test/ffmpeg11" />
<SUITE FILE_PATH="coverage/tuoheng_alg$KafkaUtils.coverage" NAME="KafkaUtils Coverage Results" MODIFIED="1663465345491" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/util" />
<SUITE FILE_PATH="coverage/tuoheng_alg$test__2_.coverage" NAME="test (2) 覆盖结果" MODIFIED="1683355406740" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test/进程" />

BIN
common/__pycache__/Constant.cpython-38.pyc View File


BIN
common/__pycache__/YmlConstant.cpython-38.pyc View File


+ 5
- 4
concurrency/CommonThread.py View File

@@ -4,18 +4,19 @@ from loguru import logger

class Common(Thread):

def __init__(self, content, func, args=()):
def __init__(self, content, func, param1, param2):
super(Common, self).__init__()
self.content = content
self.func = func
self.args = args
self.param1 = param1
self.param2 = param2
self.result = None

def get_result(self):
self.join(60 * 60 * 3)
self.join(60 * 60 * 12)
return self.result

def run(self):
logger.info("开始执行线程!")
self.result = self.func(self.args)
self.result = self.func(self.param1, self.param2)
logger.info("线程停止完成!")

+ 1
- 1
concurrency/FileUploadThread.py View File

@@ -113,7 +113,7 @@ class ImageFileUpload(FileUpload):
def run(self):
logger.info("启动图片上传线程, requestId:{}", self.msg.get("request_id"))
# 初始化oss客户端
aliyunOssSdk = AliyunOssSdk(self.content, logger, self.msg.get("request_id"))
aliyunOssSdk = AliyunOssSdk(self.content, self.msg.get("request_id"))
aliyunOssSdk.get_oss_bucket()
high_score_image = {}
with ThreadPoolExecutor(max_workers=5) as t:

+ 80
- 43
concurrency/IntelligentRecognitionProcess.py View File

@@ -4,7 +4,7 @@ import json
import os
import time
import copy
from concurrent.futures import ThreadPoolExecutor, as_completed
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED

import cv2
import numpy as np
@@ -13,6 +13,7 @@ from common import Constant
from multiprocessing import Process, Queue
from loguru import logger

from concurrency.CommonThread import Common
from concurrency.PullStreamThread import RecordingPullStreamThread
from concurrency.PullVideoStreamProcess import OnlinePullVideoStreamProcess, OfflinePullVideoStreamProcess
from concurrency.RecordingHeartbeatThread import RecordingHeartbeat
@@ -250,8 +251,12 @@ class IntelligentRecognitionProcess(Process):
for mod in frame[1]:
result = frame[3].submit(self.analyze, mod, or_frame, frame[2].w)
analyze_result.append(result)
results = wait(analyze_result, timeout=60, return_when=ALL_COMPLETED)
completed_futures = results.done
det_xywh = {}
for r in as_completed(analyze_result):
for r in completed_futures:
if r.exception():
raise r.exception()
p_result, timeOut, code, allowedList, label_arraylist, rainbows = r.result()
if allowedList is not None:
is_call_model = True
@@ -317,20 +322,25 @@ class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess):
self.pull_stream_timeout = int(self.content["service"]["cv2_pull_stream_timeout"])

# 停止任务方法
def stop_task(self, cv2tool, pullProcess, snalysisStatus, t):
def stop_task(self, cv2tool, pullProcess, snalysisStatus):
cv2tool.close()
pullProcess.sendCommand({"command": "stop_pull_stream"})
if not os.path.exists(self.orFilePath) or not os.path.exists(self.aiFilePath):
logger.error("原视频或AI视频不存在!requestId:{}", self.msg.get("request_id"))
raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0],
ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1])
aliyunVodSdk = ThAliyunVodSdk(self.content, logger, self.msg.get("request_id"))
upload_video_thread_or = t.submit(aliyunVodSdk.get_play_url, self.orFilePath, "orOnLineVideo")
upload_video_thread_ai = t.submit(aliyunVodSdk.get_play_url, self.aiFilePath, "aiOnLineVideo")
url_result = []
for url in as_completed([upload_video_thread_or, upload_video_thread_ai]):
url_result.append(url.result())
if len(url_result) != 2:
aliyunVodSdk = ThAliyunVodSdk(self.content, self.msg.get("request_id"))
upload_video_thread_or = Common(self.content, aliyunVodSdk.get_play_url, self.orFilePath,
"or_online_%s" % self.msg.get("request_id"))
upload_video_thread_ai = Common(self.content, aliyunVodSdk.get_play_url, self.aiFilePath,
"ai_online_%s" % self.msg.get("request_id"))
upload_video_thread_or.setDaemon(True)
upload_video_thread_ai.setDaemon(True)
upload_video_thread_or.start()
upload_video_thread_ai.start()
or_url = upload_video_thread_or.get_result()
ai_url = upload_video_thread_ai.get_result()
if or_url is None or ai_url is None:
logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", self.msg.get("request_id"))
raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1])
@@ -339,8 +349,8 @@ class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess):
self.sendResult({"feedback": message_feedback(self.msg.get("request_id"), snalysisStatus,
self.analyse_type,
progress=Constant.success_progess,
original_url=url_result[0],
sign_url=url_result[1],
original_url=or_url,
sign_url=ai_url,
analyse_time=TimeUtils.now_date_to_str())})

def start_pull_stream(self):
@@ -372,7 +382,7 @@ class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess):
task_frame = None
with ThreadPoolExecutor(max_workers=10) as t:
with ThreadPoolExecutor(max_workers=4) as tt:
with ThreadPoolExecutor(max_workers=5) as ttt:
with ThreadPoolExecutor(max_workers=10) as ttt:
while True:
self.checkPullProcess(pullProcess)
eBody = self.getEvent()
@@ -399,8 +409,11 @@ class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess):
frame_all.get("frame"))
write_ai_video_result = tt.submit(cv2tool.video_ai_write, frame_merge)
res = [push_stream_result, write_or_video_result, write_ai_video_result]
for re in as_completed(res):
re.result()
completed_results = wait(res, timeout=600, return_when=ALL_COMPLETED)
completed_futures = completed_results.done
for r in completed_futures:
if r.exception():
raise r.exception()
det_xywh = frame_all.get("det_xywh")
if len(det_xywh) > 0:
self.imageQueue.put({"image": frame_all})
@@ -409,11 +422,11 @@ class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess):
if status.get("status") == "1":
raise ServiceException(status.get("error").get("code"), status.get("error").get("msg"))
elif status.get("status") == "3":
self.stop_task(cv2tool, pullProcess, AnalysisStatus.TIMEOUT.value, t)
self.stop_task(cv2tool, pullProcess, AnalysisStatus.TIMEOUT.value)
break
elif status.get("status") == "9":
logger.info("实时任务正常结束:requestId: {}", self.msg.get("request_id"))
self.stop_task(cv2tool, pullProcess, AnalysisStatus.SUCCESS.value, t)
self.stop_task(cv2tool, pullProcess, AnalysisStatus.SUCCESS.value)
break
else:
raise Exception("未知拉流状态异常!")
@@ -470,16 +483,19 @@ class OfflineIntelligentRecognitionProcess(IntelligentRecognitionProcess):
self.aiFilePath = "%s%s%s%s%s" % (self.content["video"]["file_path"], random_time, "_on_ai_",
self.msg.get("request_id"), ".mp4")

def stop_task(self, cv2tool, pullProcess, analysisStatus, t):
def stop_task(self, cv2tool, pullProcess, analysisStatus):
cv2tool.close()
pullProcess.sendCommand({"command": "stop_pull_stream"})
if not os.path.exists(self.aiFilePath):
logger.error("AI视频不存在!requestId:{}", self.msg.get("request_id"))
raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0],
ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1])
aliyunVodSdk = ThAliyunVodSdk(self.content, logger, self.msg.get("request_id"))
upload_video_thread_ai = t.submit(aliyunVodSdk.get_play_url, self.aiFilePath, "aiOnLineVideo")
ai_play_url = upload_video_thread_ai.result()
aliyunVodSdk = ThAliyunVodSdk(self.content, self.msg.get("request_id"))
upload_video_thread_ai = Common(self.content, aliyunVodSdk.get_play_url, self.aiFilePath,
"ai_offLine_%s" % self.msg.get("request_id"))
upload_video_thread_ai.setDaemon(True)
upload_video_thread_ai.start()
ai_play_url = upload_video_thread_ai.get_result()
if ai_play_url is None:
logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", self.msg.get("request_id"))
raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
@@ -514,7 +530,7 @@ class OfflineIntelligentRecognitionProcess(IntelligentRecognitionProcess):
task_frame = None
with ThreadPoolExecutor(max_workers=10) as t:
with ThreadPoolExecutor(max_workers=3) as tt:
with ThreadPoolExecutor(max_workers=5) as ttt:
with ThreadPoolExecutor(max_workers=10) as ttt:
while True:
if not pullProcess.is_alive():
logger.info("拉流进程停止异常, requestId: {}", self.msg.get("request_id"))
@@ -541,8 +557,11 @@ class OfflineIntelligentRecognitionProcess(IntelligentRecognitionProcess):
push_stream_result = tt.submit(cv2tool.push_stream, frame_merge)
write_ai_video_result = tt.submit(cv2tool.video_ai_write, frame_merge)
res = [push_stream_result, write_ai_video_result]
for re in as_completed(res):
re.result()
completed_results = wait(res, timeout=600, return_when=ALL_COMPLETED)
completed_futures = completed_results.done
for r in completed_futures:
if r.exception():
raise r.exception()
det_xywh = frame_all.get("det_xywh")
if len(det_xywh) > 0:
self.imageQueue.put({"image": frame_all})
@@ -558,14 +577,14 @@ class OfflineIntelligentRecognitionProcess(IntelligentRecognitionProcess):
if status.get("status") == "1":
raise ServiceException(status.get("error").get("code"), status.get("error").get("msg"))
elif status.get("status") == "2":
self.stop_task(cv2tool, pullProcess, AnalysisStatus.SUCCESS.value, t)
self.stop_task(cv2tool, pullProcess, AnalysisStatus.SUCCESS.value)
break
elif status.get("status") == "3":
self.stop_task(cv2tool, pullProcess, AnalysisStatus.TIMEOUT.value, t)
self.stop_task(cv2tool, pullProcess, AnalysisStatus.TIMEOUT.value)
break
elif status.get("status") == "9":
logger.info("离线任务正常结束:requestId: {}", self.msg.get("request_id"))
self.stop_task(cv2tool, pullProcess, AnalysisStatus.SUCCESS.value, t)
self.stop_task(cv2tool, pullProcess, AnalysisStatus.SUCCESS.value)
break
logger.info("离线进程任务完成,requestId:{}", self.msg.get("request_id"))
except ServiceException as s:
@@ -787,8 +806,11 @@ class PhotosIntelligentRecognitionProcess(IntelligentRecognitionProcess):
for imageUrl in imageUrls:
obj = tt.submit(self.epidemic_prevention, imageUrl, mod, orc, model_type_code)
obj_list.append(obj)
for future in as_completed(obj_list):
future.result()
completed_results = wait(obj_list, timeout=120, return_when=ALL_COMPLETED)
completed_futures = completed_results.done
for r in completed_futures:
if r.exception():
raise r.exception()

def image_recognition(self, imageUrl, mod, model_type_code, aliyunOssSdk):
try:
@@ -865,8 +887,11 @@ class PhotosIntelligentRecognitionProcess(IntelligentRecognitionProcess):
for imageUrl in imageUrls:
obj = tt.submit(self.image_recognition, imageUrl, mod, model_type_code, aliyunOssSdk)
obj_list.append(obj)
for future in as_completed(obj_list):
future.result()
completed_results = wait(obj_list, timeout=120, return_when=ALL_COMPLETED)
completed_futures = completed_results.done
for r in completed_futures:
if r.exception():
raise r.exception()

'''
1. imageUrls: 图片url数组,多张图片
@@ -881,8 +906,11 @@ class PhotosIntelligentRecognitionProcess(IntelligentRecognitionProcess):
for imageUrl in imageUrls:
obj = tt.submit(self.baidu_recognition, imageUrl, mod, model_type_code, aliyunOssSdk, ttt)
obj_list.append(obj)
for future in as_completed(obj_list):
future.result()
completed_results = wait(obj_list, timeout=120, return_when=ALL_COMPLETED)
completed_futures = completed_results.done
for r in completed_futures:
if r.exception():
raise r.exception()

def baidu_recognition(self, imageUrl, mod, model_type_code, aliyunOssSdk, ttt):
try:
@@ -906,8 +934,11 @@ class PhotosIntelligentRecognitionProcess(IntelligentRecognitionProcess):
reuslt = ttt.submit(self.baidu_method, mod, target, imageUrl, img, aliyunOssSdk, model_type_code,
label_array, rainbows, person_label)
obj_list.append(reuslt)
for future in as_completed(obj_list):
future.result()
completed_results = wait(obj_list, timeout=120, return_when=ALL_COMPLETED)
completed_futures = completed_results.done
for r in completed_futures:
if r.exception():
raise r.exception()
except ServiceException as s:
raise s
except Exception as e:
@@ -1034,14 +1065,14 @@ class PhotosIntelligentRecognitionProcess(IntelligentRecognitionProcess):

def run(self):
with ThreadPoolExecutor(max_workers=5) as t:
with ThreadPoolExecutor(max_workers=5) as tt:
with ThreadPoolExecutor(max_workers=10) as tt:
with ThreadPoolExecutor(max_workers=5) as ttt:
try:
# 初始化日志
LogUtils.init_log(self.content)
model_array = self.get_model()
imageUrls = self.msg.get("image_urls")
aliyunOssSdk = AliyunOssSdk(self.content, logger, self.msg.get('request_id'))
aliyunOssSdk = AliyunOssSdk(self.content, self.msg.get('request_id'))
aliyunOssSdk.get_oss_bucket()
task_list = []
for model in model_array:
@@ -1065,8 +1096,11 @@ class PhotosIntelligentRecognitionProcess(IntelligentRecognitionProcess):
aliyunOssSdk, tt)
task_list.append(result)
if len(task_list) > 0:
for future in as_completed(task_list):
future.result()
completed_results = wait(task_list, timeout=120, return_when=ALL_COMPLETED)
completed_futures = completed_results.done
for r in completed_futures:
if r.exception():
raise r.exception()
logger.info("图片进程任务完成,requestId:{}", self.msg.get("request_id"))
self.sendResult(
{"feedback": message_feedback(self.msg.get("request_id"), AnalysisStatus.SUCCESS.value,
@@ -1167,9 +1201,12 @@ class ScreenRecordingProcess(Process):
logger.error("原视频不存在!requestId:{}", self.msg.get("request_id"))
raise ServiceException(ExceptionType.OR_VIDEO_DO_NOT_EXEIST_EXCEPTION.value[0],
ExceptionType.OR_VIDEO_DO_NOT_EXEIST_EXCEPTION.value[1])
aliyunVodSdk = ThAliyunVodSdk(self.content, logger, self.msg.get("request_id"))
upload_video_thread_or = t.submit(aliyunVodSdk.get_play_url, self.orFilePath, "orOnLineVideo")
or_play_url = upload_video_thread_or.result()
aliyunVodSdk = ThAliyunVodSdk(self.content, self.msg.get("request_id"))
upload_video_thread_or = Common(self.content, aliyunVodSdk.get_play_url, self.orFilePath,
"or_recording_%s" % self.msg.get("request_id"))
upload_video_thread_or.setDaemon(True)
upload_video_thread_or.start()
or_play_url = upload_video_thread_or.get_result()
if or_play_url is None:
logger.error("原视频上传VOD失败!原视频播放地址:{}, requestId: {}", or_play_url, self.msg.get("request_id"))
raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
@@ -1244,7 +1281,7 @@ class ScreenRecordingProcess(Process):
raise ServiceException(status.get("error").get("code"), status.get("error").get("msg"))
elif status.get("status") == "2":
cv2tool.close()
self.stop_task(hb, RecordingStatus.RECORDING_SUCCESS.value[0], t)
self.stop_task(hb, RecordingStatus.RECORDING_SUCCESS.value[0])
pullThread.join(10)
break
else:

BIN
concurrency/__pycache__/CommonThread.cpython-38.pyc View File


+ 1
- 1
enums/BaiduSdkEnum.py View File

@@ -79,7 +79,7 @@ class BaiduSdkErrorEnum(Enum):

IMAGE_SPLIT_LIMIT_REACHED = (282101, "image split limit reached", "长图片切分数量超限!", 1, 1)

TARGET_DETECT_ERROR = (282102, "target detect error", "未检测到图片中识别目标!", 2, 1) #
TARGET_DETECT_ERROR = (282102, "target detect error", "未检测到图片中识别目标!", 2, 1)

TARGET_RECOGNIZE_ERROR = (282103, "target recognize error", "图片目标识别错误!", 2, 1)


+ 1
- 1
enums/ExceptionEnum.py View File

@@ -21,7 +21,7 @@ class ExceptionType(Enum):

PUSH_STREAM_URL_EXCEPTION = ("SP007", "推流地址不能为空!")

PUSH_STREAM_TIME_EXCEPTION = ("SP008", "推流时间或原视频时间太短, 未生成分析结果, 建议延长推流时间或原视频时间!")
PUSH_STREAM_TIME_EXCEPTION = ("SP008", "未生成本地视频地址!")

AI_MODEL_MATCH_EXCEPTION = ("SP009", "未匹配到对应的AI模型!")


+ 3
- 3
test/aliyun/vod.py View File

@@ -4,9 +4,9 @@ import traceback
from aliyunsdkcore.client import AcsClient
from aliyunsdkvod.request.v20170321 import CreateUploadVideoRequest
from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest
from voduploadsdk.AliyunVodUtils import *
from voduploadsdk.AliyunVodUploader import AliyunVodUploader
from voduploadsdk.UploadVideoRequest import UploadVideoRequest
from vodsdk.AliyunVodUtils import *
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest

# # # 填入AccessKey信息
def init_vod_client(accessKeyId, accessKeySecret):

+ 6
- 6
test/aliyun/vodTest.py View File

@@ -10,9 +10,9 @@ from alibabacloud_darabonba_env.client import Client as EnvClient
from alibabacloud_vod20170321 import models as vod_20170321_models
from alibabacloud_tea_console.client import Client as ConsoleClient
from alibabacloud_tea_util.client import Client as UtilClient
from voduploadsdk.AliyunVodUtils import *
from voduploadsdk.AliyunVodUploader import AliyunVodUploader
from voduploadsdk.UploadVideoRequest import UploadVideoRequest
from vodsdk.AliyunVodUtils import *
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest

class Sample:
def __init__(self):
@@ -133,9 +133,9 @@ import traceback
from aliyunsdkcore.client import AcsClient
from aliyunsdkvod.request.v20170321 import CreateUploadVideoRequest
from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest
from voduploadsdk.AliyunVodUtils import *
from voduploadsdk.AliyunVodUploader import AliyunVodUploader
from voduploadsdk.UploadVideoRequest import UploadVideoRequest
from vodsdk.AliyunVodUtils import *
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest
# 获取播放地址
def init_vod_client(accessKeyId, accessKeySecret):
regionId = 'cn-shanghai' # 点播服务接入地域

+ 3
- 3
test/aliyun/voddemo.py View File

@@ -6,9 +6,9 @@ import json

from aliyunsdkcore.client import AcsClient
from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest
from voduploadsdk.AliyunVodUtils import *
from voduploadsdk.AliyunVodUploader import AliyunVodUploader
from voduploadsdk.UploadVideoRequest import UploadVideoRequest
from vodsdk.AliyunVodUtils import *
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest

'''
视频上传使用vod

+ 3
- 3
test/aliyun/vodtest2.py View File

@@ -3,9 +3,9 @@ import traceback
from aliyunsdkcore.client import AcsClient
from aliyunsdkvod.request.v20170321 import CreateUploadVideoRequest
from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest
from voduploadsdk.AliyunVodUtils import *
from voduploadsdk.AliyunVodUploader import AliyunVodUploader
from voduploadsdk.UploadVideoRequest import UploadVideoRequest
from vodsdk.AliyunVodUtils import *
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest
# 获取播放地址
def init_vod_client(accessKeyId, accessKeySecret):
regionId = 'cn-shanghai' # 点播服务接入地域

+ 20
- 18
test/序列化/Test.py View File

@@ -1,21 +1,23 @@
from loguru import logger
import pickle
from loguru import logger
# 定义一个类
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

# 创建一个Person实例
person = Person("Alice", 25)

# 使用Loguru的serialize方法将Person实例序列化为字节字符串
serialized_person = logger.serialize(person)
print(serialized_person)
# 使用pickle库将字节字符串反序列化为Python对象
deserialized_person = pickle.loads(serialized_person)

# 输出反序列化后的对象属性
print(deserialized_person.name) # Alice
print(deserialized_person.age) # 25
# class Person:
# def __init__(self, name, age):
# self.name = name
# self.age = age
#
# # 创建一个Person实例
# person = Person("Alice", 25)
#
# # 使用Loguru的serialize方法将Person实例序列化为字节字符串
# serialized_person = logger.serialize(person)
# print(serialized_person)
# # 使用pickle库将字节字符串反序列化为Python对象
# deserialized_person = pickle.loads(serialized_person)
#
# # 输出反序列化后的对象属性
# print(deserialized_person.name) # Alice
# print(deserialized_person.age) # 25
aa = {"name": "11111"}
logger.info(aa)

+ 15
- 15
test/线程/Test.py View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
import threading
import time
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import ThreadPoolExecutor, ALL_COMPLETED, wait


class Test(object):
@@ -24,21 +24,21 @@ class Test(object):
def bb():
print("!1111111111")

def aa(t):
while True:
t.submit(bb)
def aa(aa):
print(aa)
time.sleep(5)
return "1111"


# test = Test()
# test.process()
# print(3//2)
# with ThreadPoolExecutor(max_workers=10) as t:
# t.submit(aa, t)
# time.sleep(1000)
# codeArray=['']
# codeStr = ','.join(codeArray)
# print(codeStr)
aa={'aaaa': []}
aa["aaaa"].append("1111111")
aa["aaaa"].append("1111111")
aa["aaaa"].append("1111111")
print(aa)
with ThreadPoolExecutor(max_workers=10) as t:
aa = t.submit(aa, "aaa")
results = wait([aa], timeout=60, return_when=ALL_COMPLETED)
completed_futures = results.done
for f in completed_futures:
if f.exception():
raise f.exception()
else:
print(f"Task {f.result()} succeeded")

+ 46
- 28
util/AliyunSdk.py View File

@@ -1,31 +1,32 @@
# -*- coding: utf-8 -*-

import oss2
import time

from aliyunsdkvod.request.v20170321.GetPlayInfoRequest import GetPlayInfoRequest
from loguru import logger
from common import YmlConstant
from exception.CustomerException import ServiceException
from enums.ExceptionEnum import ExceptionType
import json
from aliyunsdkcore.client import AcsClient
from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest
from voduploadsdk.AliyunVodUtils import *
from voduploadsdk.AliyunVodUploader import AliyunVodUploader
from voduploadsdk.UploadVideoRequest import UploadVideoRequest

from util import LogUtils
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest

class AliyunOssSdk:

def __init__(self, context, log, requestId):
def __init__(self, context, requestId):
LogUtils.init_log(context)
self.__context = context
self.bucket = None
self.__logger = log
self.__requestId = requestId

def get_oss_bucket(self):
if self.bucket is None:
self.__logger.info("初始化oss桶, requestId:{}", self.__requestId)
logger.info("初始化oss桶, requestId:{}", self.__requestId)
auth = oss2.Auth(YmlConstant.get_aliyun_access_key(self.__context),
YmlConstant.get_aliyun_access_secret(self.__context))
self.bucket = oss2.Bucket(auth, YmlConstant.get_aliyun_oss_endpoint(self.__context),
@@ -33,29 +34,29 @@ class AliyunOssSdk:
connect_timeout=YmlConstant.get_aliyun_oss_connect_timeout(self.__context))

def sync_upload_file(self, updatePath, fileByte):
self.__logger.info("开始上传文件到oss, requestId:{}", self.__requestId)
logger.info("开始上传文件到oss, requestId:{}", self.__requestId)
self.get_oss_bucket()
MAX_RETRIES = 3
retry_count = 0
while True:
try:
self.bucket.put_object(updatePath, fileByte)
self.__logger.info("上传文件到oss成功! requestId:{}", self.__requestId)
logger.info("上传文件到oss成功! requestId:{}", self.__requestId)
break
except Exception as e:
retry_count += 1
time.sleep(1)
self.__logger.info("上传文件到oss失败, 重试次数:{}, requestId:{}", retry_count, self.__requestId)
logger.info("上传文件到oss失败, 重试次数:{}, requestId:{}", retry_count, self.__requestId)
if retry_count > MAX_RETRIES:
self.__logger.exception("上传文件到oss重试失败:{}, requestId:{}", e, self.__requestId)
logger.exception("上传文件到oss重试失败:{}, requestId:{}", e, self.__requestId)
raise e


class ThAliyunVodSdk:

def __init__(self, context, log, requestId):
def __init__(self, context, requestId):
LogUtils.init_log(context)
self.__context = context
self.__logger = log
self.__requestId = requestId

def init_vod_client(self, accessKeyId, accessKeySecret):
@@ -63,7 +64,7 @@ class ThAliyunVodSdk:
return AcsClient(accessKeyId, accessKeySecret, regionId, auto_retry=True, max_retry_time=3, timeout=30)

def get_play_info(self, videoId):
self.__logger.info("开始获取视频地址,videoId:{}, requestId:{}", videoId, self.__requestId)
logger.info("开始获取视频地址,videoId:{}, requestId:{}", videoId, self.__requestId)
start = time.time()
while True:
try:
@@ -75,33 +76,33 @@ class ThAliyunVodSdk:
request.set_AuthTimeout(3600 * 5)
response = json.loads(clt.do_action_with_exception(request))
play_url = response["PlayInfoList"]["PlayInfo"][0]["PlayURL"]
self.__logger.info("获取视频地址成功,视频地址: {}, requestId: {}", play_url, self.__requestId)
logger.info("获取视频地址成功,视频地址: {}, requestId: {}", play_url, self.__requestId)
return play_url
except Exception as e:
self.__logger.error("获取视频地址失败,5秒后重试, requestId: {}", self.__requestId)
logger.info("获取视频地址失败,5秒后重试, requestId: {}", self.__requestId)
time.sleep(5)
current_time = time.time()
if "HTTP Status: 403" not in str(e):
self.__logger.exception("获取视频地址失败: {}, requestId: {}", e, self.__requestId)
logger.error("获取视频地址失败: {}, requestId: {}", str(e), self.__requestId)
raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1])
if "HTTP Status: 403" in str(e) and ("UploadFail" in str(e) or "TranscodeFail" in str(e)):
self.__logger.exception("获取视频地址失败: {}, requestId: {}", e, self.__requestId)
logger.error("获取视频地址失败: {}, requestId: {}", str(e), self.__requestId)
raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1])
diff_time = current_time - start
if diff_time > 60 * 60 * 2:
self.__logger.exception("获取视频地址失败超时异常: {},超时时间:{}, requestId: {}", e, diff_time,
if diff_time > 60 * 60 * 5:
logger.error("获取视频地址失败超时异常: {},超时时间:{}, requestId: {}", str(e), diff_time,
self.__requestId)
raise ServiceException(ExceptionType.GET_VIDEO_URL_TIMEOUT_EXCEPTION.value[0],
ExceptionType.GET_VIDEO_URL_TIMEOUT_EXCEPTION.value[1])

def upload_local_video(self, filePath, file_title):
self.__logger.info("开始执行vod视频上传, filePath: {}, requestId: {}", filePath, self.__requestId)
logger.info("开始执行vod视频上传, filePath: {}, requestId: {}", filePath, self.__requestId)
uploader = AliyunVodUploader(YmlConstant.get_aliyun_access_key(self.__context),
YmlConstant.get_aliyun_access_secret(self.__context))
YmlConstant.get_aliyun_access_secret(self.__context), self.__requestId)
uploadVideoRequest: UploadVideoRequest = UploadVideoRequest(filePath, file_title)
self.__logger.info("视频分类:{}", YmlConstant.get_aliyun_vod_cateId(self.__context))
logger.info("视频分类:{}", YmlConstant.get_aliyun_vod_cateId(self.__context))
uploadVideoRequest.setCateId(YmlConstant.get_aliyun_vod_cateId(self.__context))
# 可以设置视频封面,如果是本地或网络图片可使用UploadImageRequest上传图片到视频点播,获取到ImageURL
# ImageURL示例:https://example.com/sample-****.jpg
@@ -113,14 +114,13 @@ class ThAliyunVodSdk:
while True:
try:
result = uploader.uploadLocalVideo(uploadVideoRequest)
self.__logger.info("vod视频上传成功, videoId:{}, requestId:{}", result.get("VideoId"), self.__requestId)
logger.info("vod视频上传成功, videoId:{}, requestId:{}", result.get("VideoId"), self.__requestId)
return result.get("VideoId")
except AliyunVodException as e:
except Exception as e:
retry_count += 1
time.sleep(3)
self.__logger.error("vod视频上传失败,重试次数:{}, requestId:{}", retry_count, self.__requestId)
time.sleep(1)
logger.error("vod视频上传失败:{},重试次数:{}, requestId:{}", str(e), retry_count, self.__requestId)
if retry_count >= MAX_RETRIES:
self.__logger.exception("vod视频上传重试失败: {}, requestId:{}", e.message, self.__requestId)
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])

@@ -129,3 +129,21 @@ class ThAliyunVodSdk:
if videoId is None or len(videoId) == 0:
return None
return self.get_play_info(videoId)

# if __name__ == "__main__":
# with open('/home/th/tuo_heng/prod/tuoheng_alg/dsp_application.yml', 'r', encoding='"utf-8"') as f:
# file_content = f.read()
# context = yaml.load(file_content, yaml.FullLoader)
# aliyunVodSdk = ThAliyunVodSdk(context, logger, "11111111111")
# aliyunVodSdk = ThAliyunVodSdk(context, logger, "11111111111")
#
# upload_video_thread_or = Common(context, aliyunVodSdk.get_play_url, '/home/th/tuo_heng/prod/dsp/video1/20230510185733460569_on_ai_592c3dd7eb404af9a744c5543e0e006a.mp4', "orOnLineVideo")
# upload_video_thread_ai = Common(context, aliyunVodSdk.get_play_url, '/home/th/tuo_heng/prod/dsp/video1/20230510185733460569_on_or_592c3dd7eb404af9a744c5543e0e006a.mp4', "aiOnLineVideo")
# upload_video_thread_or.setDaemon(True)
# upload_video_thread_ai.setDaemon(True)
# upload_video_thread_or.start()
# upload_video_thread_ai.start()
# or_url = upload_video_thread_or.get_result()
# ai_url = upload_video_thread_ai.get_result()
# print(or_url)
# print(ai_url)

+ 58
- 45
util/Cv2Utils.py View File

@@ -402,7 +402,7 @@ class Cv2Util():
'-r', str(self.fps),
'-i', '-', # 指定输入文件
'-g', str(self.fps),
'-maxrate', '8000k',
'-maxrate', '6000k',
# '-profile:v', 'high',
'-b:v', '5000k',
# '-crf', '18',
@@ -474,80 +474,93 @@ class Cv2Util():
if self.orFilePath is not None and self.or_video_file is None:
self.or_video_file = cv2.VideoWriter(self.orFilePath, cv2.VideoWriter_fourcc(*'mp4v'), self.fps,
(self.w, self.h))
# self.or_video_file.set(cv2.CAP_PROP_BITRATE, 5000)
if self.or_video_file is None:
self.__logger.error("or_video_file为空, requestId:{}", self.requestId)
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
except ServiceException as s:
if self.or_video_file:
self.or_video_file.release()
self.or_video_file = None
self.__logger.exception("构建OR文件写对象异常: {}, requestId:{}", s.msg, self.requestId)
raise s
except Exception as e:
if self.or_video_file:
self.or_video_file.release()
self.or_video_file = None
self.__logger.exception("构建OR文件写对象异常: {}, requestId:{}", e, self.requestId)
raise e
except:
if self.or_video_file:
self.or_video_file.release()
self.or_video_file = None
self.__logger.exception("构建OR文件写对象异常, requestId:{}", self.requestId)
raise Exception("构建OR文件写对象异常")


def build_ai_write(self):
try:
if self.aiFilePath is not None and self.ai_video_file is None:
self.ai_video_file = cv2.VideoWriter(self.aiFilePath, cv2.VideoWriter_fourcc(*'mp4v'), self.fps,
(self.w * 2, self.h))
# self.ai_video_file.set(cv2.CAP_PROP_BITRATE, 5000)
if self.ai_video_file is None:
self.__logger.error("ai_video_file为空, requestId:{}", self.requestId)
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
except ServiceException as s:
if self.ai_video_file:
self.ai_video_file.release()
self.ai_video_file = None
self.__logger.exception("构建AI文件写对象异常: {}, requestId:{}", s.msg, self.requestId)
raise s
except Exception as e:
if self.ai_video_file:
self.ai_video_file.release()
self.ai_video_file = None
self.__logger.exception("构建AI文件写对象异常: {}, requestId:{}", e, self.requestId)
raise e
except:
if self.ai_video_file:
self.ai_video_file.release()
self.ai_video_file = None
self.__logger.exception("构建AI文件写对象异常, requestId:{}", self.requestId)
raise Exception("构建AI文件写对象异常")

def video_or_write(self, frame):
try:
if self.or_video_file is None:
self.build_or_write()
self.or_video_file.write(frame)
except ServiceException as s:
raise s
except Exception as ex:
ai_retry_num = 0
while True:
try:
ai_retry_num += 1
if ai_retry_num > 3:
self.__logger.exception("重新写入原视频视频到本地,重试失败, requestId: {}", self.requestId)
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
self.or_video_file.write(frame)
self.__logger.info("重新写入原视频视到本地, 当前重试次数: {}, requestId: {}", ai_retry_num,
self.requestId)
break
except Exception as e:
self.__logger.exception("重新写入原视频视到本地:{}, 开始重试, 当前重试次数:{}, requestId: {}", e,
ai_retry_num, self.requestId)
ai_retry_num = 0
while True:
try:
if self.or_video_file is None:
self.build_or_write()
self.or_video_file.write(frame)
break
except ServiceException as s:
raise s
except Exception as ex:
if ai_retry_num > 3:
self.__logger.exception("重新写入原视频视频到本地, 重试失败, requestId: {}", self.requestId)
raise ex
finally:
ai_retry_num += 1

def video_ai_write(self, frame):
try:
if self.ai_video_file is None:
self.build_ai_write()
self.ai_video_file.write(frame)
except ServiceException as s:
raise s
except Exception as ex:
ai_retry_num = 0
while True:
try:
ai_retry_num += 1
if ai_retry_num > 3:
self.__logger.exception("重新写入分析后的视频到本地,重试失败, requestId: {}", self.requestId)
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
self.ai_video_file.write(frame)
self.__logger.info("重新写入分析后的视频到本地, 当前重试次数: {}, requestId: {}", ai_retry_num,
self.requestId)
break
except Exception as e:
self.__logger.exception("重新写入分析后的视频到本地:{}, 开始重试, 当前重试次数:{}, requestId: {}", e,
ai_retry_num, self.requestId)
ai_retry_num = 0
while True:
try:
if self.ai_video_file is None:
self.build_ai_write()
self.ai_video_file.write(frame)
break
except ServiceException as s:
raise s
except Exception as ex:
if ai_retry_num > 3:
self.__logger.exception("重新写入分析后的视频到本地,重试失败, requestId: {}", self.requestId)
raise ex
finally:
ai_retry_num += 1

def video_merge(self, frame1, frame2):
# frameLeft = cv2.resize(frame1, (int(self.width / 2), int(self.height / 2)), interpolation=cv2.INTER_LINEAR)

+ 26
- 0
util/ModelUtils.py View File

@@ -320,6 +320,8 @@ class RiverModel:
return AI_process([frame], self.model, self.segmodel, self.names, self.label_arraylist,
self.rainbows, objectPar=self.objectPar, font=self.digitFont, segPar=self.segPar,
mode=self.mode, postPar=copy.deepcopy(self.postPar))
except ServiceException as s:
raise s
except Exception as ee:
# self.num += 1
# cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame)
@@ -466,6 +468,8 @@ class HighWayModel:
self.rainbows, objectPar=copy.deepcopy(self.objectPar), font=self.digitFont,
segPar=copy.deepcopy(self.segPar),
mode=self.mode, postPar=copy.deepcopy(self.postPar))
except ServiceException as s:
raise s

except Exception as ee:
# self.num += 1
@@ -570,6 +574,8 @@ class ForestModel:
return AI_process_forest([frame], self.model, self.segmodel, self.names, self.label_arraylist,
self.rainbows, self.half, self.device, self.conf_thres, self.iou_thres,
[], font=self.digitFont, trtFlag_det=self.trtFlag_det)
except ServiceException as s:
raise s
except Exception as ee:
# self.num += 1
# cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame)
@@ -671,6 +677,8 @@ class VehicleModel:
return AI_process_forest([frame], self.model, self.segmodel, self.names, self.label_arraylist,
self.rainbows, self.half, self.device, self.conf_thres, self.iou_thres,
[], font=self.digitFont, trtFlag_det=self.trtFlag_det)
except ServiceException as s:
raise s
except Exception as ee:
# self.num += 1
# cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame)
@@ -774,6 +782,8 @@ class PedestrianModel:
return AI_process_forest([frame], self.model, self.segmodel, self.names, self.label_arraylist,
self.rainbows, self.half, self.device, self.conf_thres, self.iou_thres,
[], font=self.digitFont, trtFlag_det=self.trtFlag_det)
except ServiceException as s:
raise s
except Exception as ee:
# self.num += 1
# cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame)
@@ -876,6 +886,8 @@ class SmogfireModel:
return AI_process_forest([frame], self.model, self.segmodel, self.names, self.label_arraylist,
self.rainbows, self.half, self.device, self.conf_thres, self.iou_thres,
[], font=self.digitFont, trtFlag_det=self.trtFlag_det)
except ServiceException as s:
raise s
except Exception as ee:
# self.num += 1
# cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame)
@@ -979,6 +991,8 @@ class AnglerSwimmerModel:
return AI_process_forest([frame], self.model, self.segmodel, self.names, self.label_arraylist,
self.rainbows, self.half, self.device, self.conf_thres, self.iou_thres,
[], font=self.digitFont, trtFlag_det=self.trtFlag_det)
except ServiceException as s:
raise s
except Exception as ee:
# self.num += 1
# cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame)
@@ -1083,6 +1097,8 @@ class CountryRoadModel:
return AI_process_forest([frame], self.model, self.segmodel, self.names, self.label_arraylist,
self.rainbows, self.half, self.device, self.conf_thres, self.iou_thres,
[], font=self.digitFont, trtFlag_det=self.trtFlag_det)
except ServiceException as s:
raise s
except Exception as ee:
# self.num += 1
# cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame)
@@ -1187,6 +1203,8 @@ class ChannelEmergencyModel:
return AI_process_forest([frame], self.model, self.segmodel, self.names, self.label_arraylist,
self.rainbows, self.half, self.device, self.conf_thres, self.iou_thres,
[], font=self.digitFont, trtFlag_det=self.trtFlag_det)
except ServiceException as s:
raise s
except Exception as ee:
# self.num += 1
# cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame)
@@ -1269,6 +1287,8 @@ class ShipModel:
fontpath=self.fontPath)
self.label_arraylist = self.par["label_array"]
return OBB_infer(self.model, frame, self.par)
except ServiceException as s:
raise s
except Exception as ee:
# self.num += 1
# cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame)
@@ -1318,6 +1338,8 @@ class IMModel:
iou_thres=self.par['iou_thres'], nc=self.par[self.img_type]['nc']) # 后处理
dataBack = get_return_data(frame, boxes, modelType=self.img_type, plate_dilate=self.par['plate_dilate'])
return dataBack
except ServiceException as s:
raise s
except Exception as ee:
self.logger.exception("算法模型分析异常:{}, requestId:{}", ee, self.requestId)
raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0],
@@ -1380,6 +1402,8 @@ class OCR_Model:
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
par = [gray_frame, self.engine, self.context, self.converter, self.AlignCollate_normal, self.device]
return ocr_process(par)
except ServiceException as s:
raise s
except Exception as ee:
self.__logger.exception("ocr坐标识别异常:{}, requestId:{}", ee, self.requestId)
raise ServiceException(ExceptionType.COORDINATE_ACQUISITION_FAILED.value[0],
@@ -1416,6 +1440,8 @@ class BaiduAiImageModel:
+ " target: " + target)
return baiduEnum.value[2](self.__aipImageClassifyClient, self.__aipBodyAnalysisClient, url,
self.__requestId)
except ServiceException as s:
raise s
except Exception as ee:
self.logger.exception("算法模型分析异常:{}, requestId:{}", ee, self.requestId)
raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0],

BIN
util/__pycache__/LogUtils.cpython-38.pyc View File


+ 730
- 0
vodsdk/AliyunVodUploader.py View File

@@ -0,0 +1,730 @@
# -*- coding: UTF-8 -*-
import json
import oss2
import base64

import time

from aliyunsdkcore import client
from aliyunsdkvod.request.v20170321 import CreateUploadVideoRequest
from aliyunsdkvod.request.v20170321 import RefreshUploadVideoRequest
from aliyunsdkvod.request.v20170321 import CreateUploadImageRequest
from aliyunsdkvod.request.v20170321 import CreateUploadAttachedMediaRequest

from vodsdk.AliyunVodUtils import *
from loguru import logger

VOD_MAX_TITLE_LENGTH = 128
VOD_MAX_DESCRIPTION_LENGTH = 1024


class AliyunVodUploader:

def __init__(self, accessKeyId, accessKeySecret, requestId, ecsRegionId=None):
"""
constructor for VodUpload
:param accessKeyId: string, access key id
:param accessKeySecret: string, access key secret
:param ecsRegion: string, 部署迁移脚本的ECS所在的Region,详细参考:https://help.aliyun.com/document_detail/40654.html,如:cn-beijing
:return
"""
self.__requestId = requestId
# LogUtils.init_log(context)
self.__accessKeyId = accessKeyId
self.__accessKeySecret = accessKeySecret
self.__ecsRegion = ecsRegionId
self.__vodApiRegion = None
self.__connTimeout = 60
self.__bucketClient = None
self.__maxRetryTimes = 5
self.__vodClient = None
self.__EnableCrc = True

# 分片上传参数
self.__multipartThreshold = 10 * 1024 * 1024 # 分片上传的阈值,超过此值开启分片上传
self.__multipartPartSize = 10 * 1024 * 1024 # 分片大小,单位byte
self.__multipartThreadsNum = 3 # 分片上传时并行上传的线程数,暂时为串行上传,不支持并行,后续会支持。
# 设置apiRegion为cn-shanghai, 初始化客户端self.__vodClient
self.setApiRegion('cn-shanghai')
logger.info("初始化阿里云视频上传sdk,连接超时时间:{}, 重试次数:{}, requestId:{}", self.__connTimeout,
self.__maxRetryTimes, requestId)

def setApiRegion(self, apiRegion):
"""
设置VoD的接入地址,中国大陆为cn-shanghai,海外支持ap-southeast-1(新加坡)等区域,详情参考:https://help.aliyun.com/document_detail/98194.html
:param apiRegion: 接入地址的Region英文表示
:return:
"""
self.__vodApiRegion = apiRegion
self.__vodClient = self.__initVodClient()

def __initVodClient(self):
return client.AcsClient(self.__accessKeyId, self.__accessKeySecret, self.__vodApiRegion,
auto_retry=True, max_retry_time=self.__maxRetryTimes, timeout=self.__connTimeout)

def setMultipartUpload(self, multipartThreshold=10 * 1024 * 1024, multipartPartSize=10 * 1024 * 1024,
multipartThreadsNum=1):
if multipartThreshold > 0:
self.__multipartThreshold = multipartThreshold
if multipartPartSize > 0:
self.__multipartPartSize = multipartPartSize
if multipartThreadsNum > 0:
self.__multipartThreadsNum = multipartThreadsNum

def setEnableCrc(self, isEnable=False):
self.__EnableCrc = True if isEnable else False

@catch_error
def uploadLocalVideo(self, uploadVideoRequest, startUploadCallback=None):
"""
上传本地视频或音频文件到点播,最大支持48.8TB的单个文件,暂不支持断点续传
:param uploadVideoRequest: UploadVideoRequest类的实例,注意filePath为本地文件的绝对路径
:param startUploadCallback为获取到上传地址和凭证(uploadInfo)后开始进行文件上传时的回调,可用于记录上传日志等;uploadId为设置的上传ID,可用于关联导入视频。
:return
"""
uploadInfo = self.__createUploadVideo(uploadVideoRequest)
if startUploadCallback:
startUploadCallback(uploadVideoRequest.uploadId, uploadInfo)
headers = self.__getUploadHeaders(uploadVideoRequest)
self.__uploadOssObjectWithRetry(uploadVideoRequest.filePath, uploadInfo['UploadAddress']['FileName'],
uploadInfo, headers)
return uploadInfo

@catch_error
def uploadWebVideo(self, uploadVideoRequest, startUploadCallback=None):
"""
上传网络视频或音频文件到点播,最大支持48.8TB的单个文件(需本地磁盘空间足够);会先下载到本地临时目录,再上传到点播存储
:param uploadVideoRequest: UploadVideoRequest类的实例,注意filePath为网络文件的URL地址
:return
"""
# 下载文件
uploadVideoRequest = self.__downloadWebMedia(uploadVideoRequest)

# 上传到点播
uploadInfo = self.__createUploadVideo(uploadVideoRequest)
if startUploadCallback:
startUploadCallback(uploadVideoRequest.uploadId, uploadInfo)
headers = self.__getUploadHeaders(uploadVideoRequest)
self.__uploadOssObjectWithRetry(uploadVideoRequest.filePath, uploadInfo['UploadAddress']['FileName'],
uploadInfo, headers)

# 删除本地临时文件
os.remove(uploadVideoRequest.filePath)

return uploadInfo['VideoId']

@catch_error
def uploadLocalM3u8(self, uploadVideoRequest, sliceFilePaths=None):
"""
上传本地m3u8视频或音频文件到点播,m3u8文件和分片文件默认在同一目录
:param uploadVideoRequest: UploadVideoRequest类的实例,注意filePath为本地m3u8索引文件的绝对路径,
且m3u8文件的分片信息必须是相对地址,不能含有URL或本地绝对路径
:param sliceFilePaths: list, 分片文件的本地路径列表,例如:['/opt/m3u8_video/sample_001.ts', '/opt/m3u8_video/sample_002.ts']
sliceFilePaths为None时,会按照同一目录去解析分片地址;如不在同一目录等原因导致解析有误,可自行组装分片地址
:return
"""

if sliceFilePaths is None:
sliceFilePaths = self.parseLocalM3u8(uploadVideoRequest.filePath)

if (not isinstance(sliceFilePaths, list)) or len(sliceFilePaths) <= 0:
raise AliyunVodException('InvalidM3u8SliceFile', 'M3u8 slice files invalid',
'sliceFilePaths invalid or m3u8 index file error')

# 上传到点播的m3u8索引文件会重写,以此确保分片地址都为相对地址
downloader = AliyunVodDownloader()
m3u8LocalDir = downloader.getSaveLocalDir() + '/' + AliyunVodUtils.getStringMd5(uploadVideoRequest.fileName)
downloader.setSaveLocalDir(m3u8LocalDir)
m3u8LocalPath = m3u8LocalDir + '/' + os.path.basename(uploadVideoRequest.fileName)
self.__rewriteM3u8File(uploadVideoRequest.filePath, m3u8LocalPath, True)

# 获取上传凭证
uploadVideoRequest.setFilePath(m3u8LocalPath)
uploadInfo = self.__createUploadVideo(uploadVideoRequest)
uploadAddress = uploadInfo['UploadAddress']
headers = self.__getUploadHeaders(uploadVideoRequest)

# 依次上传分片文件
for sliceFilePath in sliceFilePaths:
tempFilePath, sliceFileName = AliyunVodUtils.getFileBriefPath(sliceFilePath)
self.__uploadOssObjectWithRetry(sliceFilePath, uploadAddress['ObjectPrefix'] + sliceFileName, uploadInfo,
headers)

# 上传m3u8文件
self.__uploadOssObjectWithRetry(m3u8LocalPath, uploadAddress['FileName'], uploadInfo, headers)

# 删除重写到本地的m3u8文件
if os.path.exists(m3u8LocalPath):
os.remove(m3u8LocalPath)
if not os.listdir(m3u8LocalDir):
os.rmdir(m3u8LocalDir)

return uploadInfo['VideoId']

@catch_error
def uploadWebM3u8(self, uploadVideoRequest, sliceFileUrls=None):
"""
上传网络m3u8视频或音频文件到点播,需本地磁盘空间足够,会先下载到本地临时目录,再上传到点播存储
:param uploadVideoRequest: UploadVideoRequest类的实例,注意filePath为m3u8网络文件的URL地址
:param sliceFileUrls: list, 分片文件的url,例如:['http://host/sample_001.ts', 'http://host/sample_002.ts']
sliceFileUrls为None时,会按照同一前缀解析分片地址;如分片路径和m3u8索引文件前缀不同等原因导致解析有误,可自行组装分片地址
:return
"""
if sliceFileUrls is None:
sliceFileUrls = self.parseWebM3u8(uploadVideoRequest.filePath)

if (not isinstance(sliceFileUrls, list)) or len(sliceFileUrls) <= 0:
raise AliyunVodException('InvalidM3u8SliceFile', 'M3u8 slice urls invalid',
'sliceFileUrls invalid or m3u8 index file error')

# 下载m3u8文件和所有ts分片文件到本地;上传到点播的m3u8索引文件会重写,以此确保分片地址都为相对地址
downloader = AliyunVodDownloader()
m3u8LocalDir = downloader.getSaveLocalDir() + '/' + AliyunVodUtils.getStringMd5(uploadVideoRequest.fileName)
downloader.setSaveLocalDir(m3u8LocalDir)
m3u8LocalPath = m3u8LocalDir + '/' + os.path.basename(uploadVideoRequest.fileName)
self.__rewriteM3u8File(uploadVideoRequest.filePath, m3u8LocalPath, False)

sliceList = []
for sliceFileUrl in sliceFileUrls:
tempFilePath, sliceFileName = AliyunVodUtils.getFileBriefPath(sliceFileUrl)
err, sliceLocalPath = downloader.downloadFile(sliceFileUrl, sliceFileName)
if sliceLocalPath is None:
raise AliyunVodException('FileDownloadError', 'Download M3u8 File Error', '')
sliceList.append((sliceLocalPath, sliceFileName))

# 获取上传凭证
uploadVideoRequest.setFilePath(m3u8LocalPath)
uploadInfo = self.__createUploadVideo(uploadVideoRequest)
uploadAddress = uploadInfo['UploadAddress']
headers = self.__getUploadHeaders(uploadVideoRequest)

# 依次上传分片文件
for sliceFile in sliceList:
self.__uploadOssObjectWithRetry(sliceFile[0], uploadAddress['ObjectPrefix'] + sliceFile[1], uploadInfo,
headers)

# 上传m3u8文件
self.__uploadOssObjectWithRetry(m3u8LocalPath, uploadAddress['FileName'], uploadInfo, headers)

# 删除下载到本地的m3u8文件和分片文件
if os.path.exists(m3u8LocalPath):
os.remove(m3u8LocalPath)
for sliceFile in sliceList:
if os.path.exists(sliceFile[0]):
os.remove(sliceFile[0])
if not os.listdir(m3u8LocalDir):
os.rmdir(m3u8LocalDir)

return uploadInfo['VideoId']

@catch_error
def uploadImage(self, uploadImageRequest, isLocalFile=True):
"""
上传图片文件到点播,不支持断点续传;该接口可支持上传本地图片或网络图片
:param uploadImageRequest: UploadImageRequest,注意filePath为本地文件的绝对路径或网络文件的URL地址
:param isLocalFile: bool, 是否为本地文件。True:本地文件,False:网络文件
:return
"""
# 网络图片需要先下载到本地
if not isLocalFile:
uploadImageRequest = self.__downloadWebMedia(uploadImageRequest)

# 上传到点播
uploadInfo = self.__createUploadImage(uploadImageRequest)
self.__uploadOssObject(uploadImageRequest.filePath, uploadInfo['UploadAddress']['FileName'], uploadInfo, None)

# 删除本地临时文件
if not isLocalFile:
os.remove(uploadImageRequest.filePath)

return uploadInfo['ImageId'], uploadInfo['ImageURL']

@catch_error
def uploadAttachedMedia(self, uploadAttachedRequest, isLocalFile=True):
"""
上传辅助媒资文件(如水印、字幕文件)到点播,不支持断点续传;该接口可支持上传本地或网络文件
:param uploadAttachedRequest: UploadAttachedMediaRequest,注意filePath为本地文件的绝对路径或网络文件的URL地址
:param isLocalFile: bool, 是否为本地文件。True:本地文件,False:网络文件
:return
"""
# 网络文件需要先下载到本地
if not isLocalFile:
uploadAttachedRequest = self.__downloadWebMedia(uploadAttachedRequest)

# 上传到点播
uploadInfo = self.__createUploadAttachedMedia(uploadAttachedRequest)
self.__uploadOssObject(uploadAttachedRequest.filePath, uploadInfo['UploadAddress']['FileName'], uploadInfo,
None)

# 删除本地临时文件
if not isLocalFile:
os.remove(uploadAttachedRequest.filePath)

result = {'MediaId': uploadInfo['MediaId'], 'MediaURL': uploadInfo['MediaURL'],
'FileURL': uploadInfo['FileURL']}
return result

@catch_error
def parseWebM3u8(self, m3u8FileUrl):
"""
解析网络m3u8文件得到所有分片文件地址,原理是将m3u8地址前缀拼接ts分片名称作为后者的下载url,适用于url不带签名或分片与m3u8文件签名相同的情况
本函数解析时会默认分片文件和m3u8文件位于同一目录,如不是则请自行拼接分片文件的地址列表
:param m3u8FileUrl: string, m3u8网络文件url,例如:http://host/sample.m3u8
:return sliceFileUrls
"""
sliceFileUrls = []
res = requests.get(m3u8FileUrl)
res.raise_for_status()
for line in res.iter_lines():
if line.startswith('#'):
continue
sliceFileUrl = AliyunVodUtils.replaceFileName(m3u8FileUrl, line.strip())
sliceFileUrls.append(sliceFileUrl)

return sliceFileUrls

@catch_error
def parseLocalM3u8(self, m3u8FilePath):
"""
解析本地m3u8文件得到所有分片文件地址,原理是将m3u8地址前缀拼接ts分片名称作为后者的本地路径
本函数解析时会默认分片文件和m3u8文件位于同一目录,如不是则请自行拼接分片文件的地址列表
:param m3u8FilePath: string, m3u8本地文件路径,例如:/opt/videos/sample.m3u8
:return sliceFilePaths
"""
sliceFilePaths = []
m3u8FilePath = AliyunVodUtils.toUnicode(m3u8FilePath)
for line in open(m3u8FilePath):
if line.startswith('#'):
continue
sliceFileName = line.strip()
sliceFilePath = AliyunVodUtils.replaceFileName(m3u8FilePath, sliceFileName)
sliceFilePaths.append(sliceFilePath)

return sliceFilePaths

# 定义进度条回调函数;consumedBytes: 已经上传的数据量,totalBytes:总数据量
def uploadProgressCallback(self, consumedBytes, totalBytes):
try:
if totalBytes:
rate = int(100 * (float(consumedBytes) / float(totalBytes)))
else:
rate = 0
logger.info('视频上传中: {} bytes, percent:{}{}, requestId:{}', consumedBytes, format(rate), '%',
self.__requestId)
except Exception as e:
logger.exception("打印视频上传进度回调方法异常: {}", e)
# print("[%s]uploaded %s bytes, percent %s%s" % (
# AliyunVodUtils.getCurrentTimeStr(), consumedBytes, format(rate), '%'))
# sys.stdout.flush()

def __downloadWebMedia(self, request):

# 下载媒体文件到本地临时目录
downloader = AliyunVodDownloader()
localFileName = "%s.%s" % (AliyunVodUtils.getStringMd5(request.fileName), request.mediaExt)
fileUrl = request.filePath
err, localFilePath = downloader.downloadFile(fileUrl, localFileName)
if err < 0:
raise AliyunVodException('FileDownloadError', 'Download File Error', '')

# 重新设置上传请求对象
request.setFilePath(localFilePath)
return request

def __rewriteM3u8File(self, srcM3u8File, dstM3u8File, isSrcLocal=True):
newM3u8Text = ''
if isSrcLocal:
for line in open(AliyunVodUtils.toUnicode(srcM3u8File)):
item = self.__processM3u8Line(line)
if item is not None:
newM3u8Text += item + "\n"
else:
res = requests.get(srcM3u8File)
res.raise_for_status()
for line in res.iter_lines():
item = self.__processM3u8Line(line)
if item is not None:
newM3u8Text += item + "\n"

AliyunVodUtils.mkDir(dstM3u8File)
with open(dstM3u8File, 'w') as f:
f.write(newM3u8Text)

def __processM3u8Line(self, line):
item = line.strip()
if len(item) <= 0:
return None

if item.startswith('#'):
return item

tempFilePath, fileName = AliyunVodUtils.getFileBriefPath(item)
return fileName

def __requestUploadInfo(self, request, mediaType):
request.set_accept_format('JSON')
result = json.loads(self.__vodClient.do_action_with_exception(request).decode('utf-8'))
result['OriUploadAddress'] = result['UploadAddress']
result['OriUploadAuth'] = result['UploadAuth']

result['UploadAddress'] = json.loads(base64.b64decode(result['OriUploadAddress']).decode('utf-8'))
result['UploadAuth'] = json.loads(base64.b64decode(result['OriUploadAuth']).decode('utf-8'))

result['MediaType'] = mediaType
if mediaType == 'video':
result['MediaId'] = result['VideoId']
elif mediaType == 'image':
result['MediaId'] = result['ImageId']
result['MediaURL'] = result['ImageURL']
return result

# 获取视频上传地址和凭证
def __createUploadVideo(self, uploadVideoRequest):
request = CreateUploadVideoRequest.CreateUploadVideoRequest()
title = AliyunVodUtils.subString(uploadVideoRequest.title, VOD_MAX_TITLE_LENGTH)
request.set_Title(title)
request.set_FileName(uploadVideoRequest.fileName)

if uploadVideoRequest.description:
description = AliyunVodUtils.subString(uploadVideoRequest.description, VOD_MAX_DESCRIPTION_LENGTH)
request.set_Description(description)
if uploadVideoRequest.coverURL:
request.set_CoverURL(uploadVideoRequest.coverURL)
if uploadVideoRequest.tags:
request.set_Tags(uploadVideoRequest.tags)
if uploadVideoRequest.cateId:
request.set_CateId(uploadVideoRequest.cateId)
if uploadVideoRequest.templateGroupId:
request.set_TemplateGroupId(uploadVideoRequest.templateGroupId)
if uploadVideoRequest.storageLocation:
request.set_StorageLocation(uploadVideoRequest.storageLocation)
if uploadVideoRequest.userData:
request.set_UserData(uploadVideoRequest.userData)
if uploadVideoRequest.appId:
request.set_AppId(uploadVideoRequest.appId)
if uploadVideoRequest.workflowId:
request.set_WorkflowId(uploadVideoRequest.workflowId)
# 根据request发送请求阿里云
result = self.__requestUploadInfo(request, 'video')
# logger.info("CreateUploadVideo, 获取响应体: {}, requestId:{}", result, self.__requestId)
logger.info("CreateUploadVideo, FilePath: {}, VideoId: {}, requestId:{}", uploadVideoRequest.filePath,
result['VideoId'], self.__requestId)
return result

# 刷新上传凭证
def __refresh_upload_video(self, videoId):
request = RefreshUploadVideoRequest.RefreshUploadVideoRequest();
request.set_VideoId(videoId)

result = self.__requestUploadInfo(request, 'video')
logger.info("RefreshUploadVideo, VideoId:{}, requestId:{}", result['VideoId'], self.__requestId)
return result

# 获取图片上传地址和凭证
def __createUploadImage(self, uploadImageRequest):
request = CreateUploadImageRequest.CreateUploadImageRequest()

request.set_ImageType(uploadImageRequest.imageType)
request.set_ImageExt(uploadImageRequest.imageExt)
if uploadImageRequest.title:
title = AliyunVodUtils.subString(uploadImageRequest.title, VOD_MAX_TITLE_LENGTH)
request.set_Title(title)
if uploadImageRequest.description:
description = AliyunVodUtils.subString(uploadImageRequest.description, VOD_MAX_DESCRIPTION_LENGTH)
request.set_Description(description)
if uploadImageRequest.tags:
request.set_Tags(uploadImageRequest.tags)
if uploadImageRequest.cateId:
request.set_CateId(uploadImageRequest.cateId)
if uploadImageRequest.storageLocation:
request.set_StorageLocation(uploadImageRequest.storageLocation)
if uploadImageRequest.userData:
request.set_UserData(uploadImageRequest.userData)
if uploadImageRequest.appId:
request.set_AppId(uploadImageRequest.appId)
if uploadImageRequest.workflowId:
request.set_WorkflowId(uploadImageRequest.workflowId)

result = self.__requestUploadInfo(request, 'image')
logger.info("CreateUploadImage, FilePath: %s, ImageId: %s, ImageUrl: %s" % (
uploadImageRequest.filePath, result['ImageId'], result['ImageURL']))
return result

def __createUploadAttachedMedia(self, uploadAttachedRequest):
request = CreateUploadAttachedMediaRequest.CreateUploadAttachedMediaRequest()
request.set_BusinessType(uploadAttachedRequest.businessType)
request.set_MediaExt(uploadAttachedRequest.mediaExt)

if uploadAttachedRequest.title:
title = AliyunVodUtils.subString(uploadAttachedRequest.title, VOD_MAX_TITLE_LENGTH)
request.set_Title(title)
if uploadAttachedRequest.description:
description = AliyunVodUtils.subString(uploadAttachedRequest.description, VOD_MAX_DESCRIPTION_LENGTH)
request.set_Description(description)
if uploadAttachedRequest.tags:
request.set_Tags(uploadAttachedRequest.tags)
if uploadAttachedRequest.cateId:
request.set_CateId(uploadAttachedRequest.cateId)
if uploadAttachedRequest.storageLocation:
request.set_StorageLocation(uploadAttachedRequest.storageLocation)
if uploadAttachedRequest.userData:
request.set_UserData(uploadAttachedRequest.userData)
if uploadAttachedRequest.appId:
request.set_AppId(uploadAttachedRequest.appId)
if uploadAttachedRequest.workflowId:
request.set_WorkflowId(uploadAttachedRequest.workflowId)

result = self.__requestUploadInfo(request, 'attached')
logger.info("CreateUploadImage, FilePath: %s, MediaId: %s, MediaURL: %s" % (
uploadAttachedRequest.filePath, result['MediaId'], result['MediaURL']))
return result

def __getUploadHeaders(self, uploadVideoRequest):
if uploadVideoRequest.isShowWatermark is None:
return None
else:
userData = "{\"Vod\":{\"UserData\":{\"IsShowWaterMark\": \"%s\"}}}" % (uploadVideoRequest.isShowWatermark)
return {'x-oss-notification': base64.b64encode(userData, 'utf-8')}

# uploadType,可选:multipart, put, web
def __uploadOssObjectWithRetry(self, filePath, object, uploadInfo, headers=None):
retryTimes = 0
while retryTimes < self.__maxRetryTimes:
try:
return self.__uploadOssObject(filePath, object, uploadInfo, headers)
except OssError as e:
# 上传凭证过期需要重新获取凭证
if e.code == 'SecurityTokenExpired' or e.code == 'InvalidAccessKeyId':
uploadInfo = self.__refresh_upload_video(uploadInfo['MediaId'])
except Exception as e:
raise e
except:
raise AliyunVodException('UnkownError', repr(e), traceback.format_exc())
finally:
retryTimes += 1
else:
raise Exception("重试超过限制")

def __uploadOssObject(self, filePath, object, uploadInfo, headers=None):
self.__createOssClient(uploadInfo['UploadAuth'], uploadInfo['UploadAddress'])
"""
p = os.path.dirname(os.path.realpath(__file__))
store = os.path.dirname(p) + '/osstmp'
return oss2.resumable_upload(self.__bucketClient, object, filePath,
store=oss2.ResumableStore(root=store), headers=headers,
multipart_threshold=self.__multipartThreshold, part_size=self.__multipartPartSize,
num_threads=self.__multipartThreadsNum, progress_callback=self.uploadProgressCallback)
"""
uploader = _VodResumableUploader(self.__bucketClient, filePath, object, uploadInfo, headers,
self.uploadProgressCallback, self.__refreshUploadAuth,
requestId=self.__requestId)
uploader.setMultipartInfo(self.__multipartThreshold, self.__multipartPartSize, self.__multipartThreadsNum)
uploader.setClientId(self.__accessKeyId)
res = uploader.upload()

uploadAddress = uploadInfo['UploadAddress']
bucketHost = uploadAddress['Endpoint'].replace('://', '://' + uploadAddress['Bucket'] + ".")
logger.info("UploadFile {} Finish, MediaId: {}, FilePath: {}, Destination: {}/{}, requestId:{}",
uploadInfo['MediaType'], uploadInfo['MediaId'], filePath, bucketHost, object, self.__requestId)
return res

# 使用上传凭证和地址信息初始化OSS客户端(注意需要先Base64解码并Json Decode再传入)
# 如果上传的ECS位于点播相同的存储区域(如上海),则可以指定internal为True,通过内网上传更快且免费
def __createOssClient(self, uploadAuth, uploadAddress):
auth = oss2.StsAuth(uploadAuth['AccessKeyId'], uploadAuth['AccessKeySecret'], uploadAuth['SecurityToken'])
endpoint = AliyunVodUtils.convertOssInternal(uploadAddress['Endpoint'], self.__ecsRegion)
self.__bucketClient = oss2.Bucket(auth, endpoint, uploadAddress['Bucket'],
connect_timeout=self.__connTimeout, enable_crc=self.__EnableCrc)
return self.__bucketClient

def __refreshUploadAuth(self, videoId):
uploadInfo = self.__refresh_upload_video(videoId)
uploadAuth = uploadInfo['UploadAuth']
uploadAddress = uploadInfo['UploadAddress']
return self.__createOssClient(uploadAuth, uploadAddress)


from oss2 import SizedFileAdapter, determine_part_size
from oss2.models import PartInfo
from aliyunsdkcore.utils import parameter_helper as helper


class _VodResumableUploader:
def __init__(self, bucket, filePath, object, uploadInfo, headers, progressCallback, refreshAuthCallback,
requestId=None):
self.__bucket = bucket
self.__filePath = filePath
self.__object = object
self.__uploadInfo = uploadInfo
self.__totalSize = None
self.__headers = headers
self.__mtime = os.path.getmtime(filePath)
self.__progressCallback = progressCallback
self.__refreshAuthCallback = refreshAuthCallback

self.__threshold = None
self.__partSize = None
self.__threadsNum = None
self.__uploadId = 0

self.__record = {}
self.__finishedSize = 0
self.__finishedParts = []
self.__filePartHash = None
self.__clientId = None
self.__requestId = requestId

def setMultipartInfo(self, threshold, partSize, threadsNum):
self.__threshold = threshold
self.__partSize = partSize
self.__threadsNum = threadsNum

def setClientId(self, clientId):
self.__clientId = clientId

def upload(self):
self.__totalSize = os.path.getsize(self.__filePath)
logger.info("上传视频路径: {}, 视频大小: {}, requestId:{}", self.__filePath, self.__totalSize, self.__requestId)
if self.__threshold and self.__totalSize <= self.__threshold:
return self.simpleUpload()
else:
return self.multipartUpload()

def simpleUpload(self):
with open(AliyunVodUtils.toUnicode(self.__filePath), 'rb') as f:
result = self.__bucket.put_object(self.__object, f, headers=self.__headers, progress_callback=None)
if self.__uploadInfo['MediaType'] == 'video':
self.__reportUploadProgress('put', 1, self.__totalSize)

return result

def multipartUpload(self):
psize = oss2.determine_part_size(self.__totalSize, preferred_size=self.__partSize)

# 初始化分片
self.__uploadId = self.__bucket.init_multipart_upload(self.__object).upload_id

startTime = time.time()
expireSeconds = 2500 # 上传凭证有效期3000秒,提前刷新
# 逐个上传分片
with open(AliyunVodUtils.toUnicode(self.__filePath), 'rb') as fileObj:
partNumber = 1
offset = 0

while offset < self.__totalSize:
uploadSize = min(psize, self.__totalSize - offset)
# logger.info("UploadPart, FilePath: %s, VideoId: %s, UploadId: %s, PartNumber: %s, PartSize: %s" % (self.__fileName, self.__videoId, self.__uploadId, partNumber, uploadSize))
result = self.__upload_part(partNumber, fileObj, uploadSize)
# print(result.request_id)
self.__finishedParts.append(PartInfo(partNumber, result.etag))
offset += uploadSize
partNumber += 1

# 上传进度回调
self.__progressCallback(offset, self.__totalSize)

if self.__uploadInfo['MediaType'] == 'video':
# 上报上传进度
self.__reportUploadProgress('multipart', partNumber - 1, offset)
# 检测上传凭证是否过期
nowTime = time.time()
if nowTime - startTime >= expireSeconds:
self.__bucket = self.__refreshAuthCallback(self.__uploadInfo['MediaId'])
startTime = nowTime

# 完成分片上传
self.__complete_multipart_upload()
return result

def __upload_part(self, partNumber, fileObj, uploadSize):
retry_num = 0
while True:
try:
return self.__bucket.upload_part(self.__object, self.__uploadId, partNumber,
SizedFileAdapter(fileObj, uploadSize))
except Exception as e:
logger.error("阿里云分片上传异常报错: {}, 当前重试次数:{} requestId:{}", str(e), retry_num + 1, self.__requestId)
if retry_num > 3:
raise Exception("阿里云分片上传异常")
except:
logger.error("阿里云完成分片上传异常报错, 当前重试次数:{}, requestId:{}", retry_num + 1, self.__requestId)
if retry_num > 3:
raise Exception("阿里云分片上传异常")
finally:
retry_num += 1
time.sleep(1)

def __complete_multipart_upload(self):
retry_num = 0
while True:
try:
self.__bucket.complete_multipart_upload(self.__object, self.__uploadId, self.__finishedParts,
headers=self.__headers)
break
except Exception as e:
logger.error("阿里云完成分片上传异常报错: {}, 当前重试次数:{}, requestId:{}", str(e), retry_num + 1, self.__requestId)
if retry_num > 5:
raise Exception("阿里云完成分片上传异常")
except:
logger.error("阿里云完成分片上传异常报错, 当前重试次数:{}, requestId:{}", retry_num + 1, self.__requestId)
if retry_num > 5:
raise Exception("阿里云完成分片上传异常")
finally:
time.sleep(1)
retry_num += 1

def __reportUploadProgress(self, uploadMethod, donePartsCount, doneBytes):
retry_num = 5
current_num = 0
while True:
try:
reportHost = 'vod.cn-shanghai.aliyuncs.com'
sdkVersion = '1.3.1'
reportKey = 'HBL9nnSwhtU2$STX'

uploadPoint = {'upMethod': uploadMethod, 'partSize': self.__partSize, 'doneBytes': doneBytes}
timestamp = int(time.time())
authInfo = AliyunVodUtils.getStringMd5("%s|%s|%s" % (self.__clientId, reportKey, timestamp))

fields = {'Action': 'ReportUploadProgress', 'Format': 'JSON', 'Version': '2017-03-21',
'Timestamp': helper.get_iso_8061_date(), 'SignatureNonce': helper.get_uuid(),
'VideoId': self.__uploadInfo['MediaId'], 'Source': 'PythonSDK', 'ClientId': self.__clientId,
'BusinessType': 'UploadVideo', 'TerminalType': 'PC', 'DeviceModel': 'Server',
'AppVersion': sdkVersion, 'AuthTimestamp': timestamp, 'AuthInfo': authInfo,

'FileName': self.__filePath,
'FileHash': self.__getFilePartHash(self.__clientId, self.__filePath, self.__totalSize),
'FileSize': self.__totalSize, 'FileCreateTime': timestamp, 'UploadRatio': 0,
'UploadId': self.__uploadId,
'DonePartsCount': donePartsCount, 'PartSize': self.__partSize,
'UploadPoint': json.dumps(uploadPoint),
'UploadAddress': self.__uploadInfo['OriUploadAddress']
}
requests.post('http://' + reportHost, fields, timeout=30)
break
except Exception as e:
current_num += 1
time.sleep(1)
logger.error("vod上报视频进度异常: {}, 当前重试次数:{}, requestId:{}", repr(e), current_num,
self.__requestId)
if current_num > retry_num:
logger.error("vod上报视频重试失败 {}, requestId:{}", repr(e), self.__requestId)
raise e

def __getFilePartHash(self, clientId, filePath, fileSize):
if self.__filePartHash:
return self.__filePartHash

length = 1 * 1024 * 1024
if fileSize < length:
length = fileSize

try:
fp = open(AliyunVodUtils.toUnicode(filePath), 'rb')
strVal = fp.read(length)
self.__filePartHash = AliyunVodUtils.getStringMd5(strVal, False)
fp.close()
except:
self.__filePartHash = "%s|%s|%s" % (clientId, filePath, self.__mtime)

return self.__filePartHash

+ 327
- 0
vodsdk/AliyunVodUtils.py View File

@@ -0,0 +1,327 @@
# -*- coding: UTF-8 -*-
import os, sys
import hashlib
import datetime
import functools
import logging
from loguru import logger
from oss2.exceptions import OssError
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkcore.acs_exception.exceptions import ClientException
import traceback
import requests

if sys.version_info[0] == 3:
import urllib.parse
else:
from urllib import unquote

VOD_PRINT_INFO_LOG_SWITCH = 1


class AliyunVodLog:
"""
VOD日志类,基于logging实现
"""

@staticmethod
def printLogStr(msg, *args, **kwargs):
if VOD_PRINT_INFO_LOG_SWITCH:
print("[%s]%s" % (AliyunVodUtils.getCurrentTimeStr(), msg))

@staticmethod
def info(msg, *args, **kwargs):
logging.info(msg, *args, **kwargs)
AliyunVodLog.printLogStr(msg, *args, **kwargs)

@staticmethod
def error(msg, *args, **kwargs):
logging.error(msg, *args, **kwargs)
AliyunVodLog.printLogStr(msg, *args, **kwargs)

@staticmethod
def warning(msg, *args, **kwargs):
logging.warning(msg, *args, **kwargs)
AliyunVodLog.printLogStr(msg, *args, **kwargs)


class AliyunVodUtils:
"""
VOD上传SDK的工具类,提供截取字符串、获取扩展名、获取文件名等静态函数
"""

# 截取字符串,在不超过最大字节数前提下确保中文字符不被截断出现乱码(先转换成unicode,再取子串,然后转换成utf-8)
@staticmethod
def subString(strVal, maxBytes, charSet='utf-8'):
i = maxBytes
if sys.version_info[0] == 3:
while len(strVal.encode(charSet)) > maxBytes:
if i < 0:
return ''
strVal = strVal[:i]
i -= 1
else:
while len(strVal) > maxBytes:
if i < 0:
return ''
strVal = strVal.decode(charSet)[:i].encode(charSet)
i -= 1
return strVal

@staticmethod
def getFileExtension(fileName):
end = fileName.rfind('?')
if end <= 0:
end = len(fileName)

i = fileName.rfind('.')
if i >= 0:
return fileName[i + 1:end].lower()
else:
return None

# urldecode
@staticmethod
def urlDecode(fileUrl):
if sys.version_info[0] == 3:
return urllib.parse.unquote(fileUrl)
else:
return unquote(fileUrl)

# urlencode
@staticmethod
def urlEncode(fileUrl):
if sys.version_info[0] == 3:
return urllib.parse.urlencode(fileUrl)
else:
return urllib.urlencode(fileUrl)

# 获取Url的摘要地址(去除?后的参数,如果有)以及文件名
@staticmethod
def getFileBriefPath(fileUrl):
# fileUrl = AliyunVodUtils.urlDecode(fileUrl)
i = fileUrl.rfind('?')
if i > 0:
briefPath = fileUrl[:i]
else:
briefPath = fileUrl

briefName = os.path.basename(briefPath)
return briefPath, AliyunVodUtils.urlDecode(briefName)

@staticmethod
def getStringMd5(strVal, isEncode=True):
m = hashlib.md5()
m.update(strVal.encode('utf-8') if isEncode else strVal)
return m.hexdigest()

@staticmethod
def getCurrentTimeStr():
now = datetime.datetime.now()
return now.strftime("%Y-%m-%d %H:%M:%S")

# 将oss地址转换为内网地址(如果脚本部署的ecs与oss bucket在同一区域)
@staticmethod
def convertOssInternal(ossUrl, ecsRegion=None, isVpc=False):
if (not ossUrl) or (not ecsRegion):
return ossUrl

availableRegions = ['cn-qingdao', 'cn-beijing', 'cn-zhangjiakou', 'cn-huhehaote', 'cn-hangzhou', 'cn-shanghai',
'cn-shenzhen',
'cn-hongkong', 'ap-southeast-1', 'ap-southeast-2', 'ap-southeast-3',
'ap-northeast-1', 'us-west-1', 'us-east-1', 'eu-central-1', 'me-east-1']
if ecsRegion not in availableRegions:
return ossUrl

ossUrl = ossUrl.replace("https:", "http:")
if isVpc:
return ossUrl.replace("oss-%s.aliyuncs.com" % (ecsRegion), "vpc100-oss-%s.aliyuncs.com" % (ecsRegion))
else:
return ossUrl.replace("oss-%s.aliyuncs.com" % (ecsRegion), "oss-%s-internal.aliyuncs.com" % (ecsRegion))

# 把输入转换为unicode
@staticmethod
def toUnicode(data):
if isinstance(data, bytes):
return data.decode('utf-8')
else:
return data

# 替换路径中的文件名;考虑分隔符为"/" 或 "\"(windows)
@staticmethod
def replaceFileName(filePath, replace):
if len(filePath) <= 0 or len(replace) <= 0:
return filePath

filePath = AliyunVodUtils.urlDecode(filePath)
separator = '/'
start = filePath.rfind(separator)
if start < 0:
separator = '\\'
start = filePath.rfind(separator)
if start < 0:
return None

result = "%s%s%s" % (filePath[0:start], separator, replace)
return result

# 创建文件中的目录
@staticmethod
def mkDir(filePath):
if len(filePath) <= 0:
return -1

separator = '/'
i = filePath.rfind(separator)
if i < 0:
separator = '\\'
i = filePath.rfind(separator)
if i < 0:
return -2

dirs = filePath[:i]
if os.path.exists(dirs) and os.path.isdir(dirs):
return 0

os.makedirs(dirs)
return 1


class AliyunVodException(Exception):
"""
VOD上传SDK的异常类,做统一的异常处理,外部捕获此异常即可
"""

def __init__(self, type, code, msg, http_status=None, request_id=None):
Exception.__init__(self)
self.type = type or 'UnkownError'
self.code = code
self.message = msg
self.http_status = http_status or 'NULL'
self.request_id = request_id or 'NULL'

def __str__(self):
return "Type: %s, Code: %s, Message: %s, HTTPStatus: %s, RequestId: %s" % (
self.type, self.code, self.message, str(self.http_status), self.request_id)


def catch_error(method):
"""
装饰器,将内部异常转换成统一的异常类AliyunVodException
"""

@functools.wraps(method)
def wrapper(self, *args, **kwargs):
try:
return method(self, *args, **kwargs)
except ServerException as e:
logger.error("阿里云ServerException异常, error_code: {}, error_msg:{}, status:{}, requestId:{}",
e.get_error_code(), e.get_error_msg(), e.get_http_status(), self.__requestId)
# 可能原因:AK错误、账号无权限、参数错误等
raise AliyunVodException('ServerException', e.get_error_code(), e.get_error_msg(), e.get_http_status(),
e.get_request_id())
except ClientException as e:
logger.error("阿里云ClientException异常, error_code: {}, error_msg:{}, requestId:{}", e.get_error_code(),
e.get_error_msg(), self.__requestId)
# 可能原因:本地网络故障(如不能连接外网)等
raise AliyunVodException('ClientException', e.get_error_code(), e.get_error_msg())
except OssError as e:
logger.error("阿里云OssError异常, error_code: {}, error_msg:{}, status:{}, requestId:{}", e.code, e.message,
e.status, self.__requestId)
# 可能原因:上传凭证过期等
raise AliyunVodException('OssError', e.code, e.message, e.status, e.request_id)
except IOError as e:
logger.error("阿里云IOError异常: {}, requestId:{}", traceback.format_exc(), self.__requestId)
# 可能原因:文件URL不能访问、本地文件无法读取等
raise AliyunVodException('IOError', repr(e), traceback.format_exc())
except OSError as e:
logger.error("阿里云OSError异常: {}, requestId:{}", traceback.format_exc(), self.__requestId)
# 可能原因:本地文件不存在等
raise AliyunVodException('OSError', repr(e), traceback.format_exc())
except AliyunVodException as e:
logger.error("阿里云VodException异常: {}, requestId:{}", e, self.__requestId)
# 可能原因:参数错误
raise e
except Exception as e:
logger.error("阿里云UnkownException异常: {}, requestId:{}", traceback.format_exc(), self.__requestId)
raise AliyunVodException('UnkownException', repr(e), traceback.format_exc())
except:
logger.error("阿里云UnkownError异常: {}, requestId:{}", traceback.format_exc(), self.__requestId)
raise AliyunVodException('UnkownError', 'UnkownError', traceback.format_exc())
return wrapper


class AliyunVodDownloader:
"""
VOD网络文件的下载类,上传网络文件时会先下载到本地临时目录,再上传到点播
"""

def __init__(self, localDir=None):
if localDir:
self.__localDir = localDir
else:
p = os.path.dirname(os.path.realpath(__file__))
self.__localDir = os.path.dirname(p) + '/dlfiles'

def setSaveLocalDir(self, localDir):
self.__localDir = localDir

def getSaveLocalDir(self):
return self.__localDir

def downloadFile(self, fileUrl, localFileName, fileSize=None):
localPath = self.__localDir + '/' + localFileName
logger.info("Download %s To %s" % (fileUrl, localPath))
try:
lsize = self.getFileSize(localPath)
if fileSize and lsize == fileSize:
logger.info('Download OK, File Exists')
return 0, localPath

AliyunVodUtils.mkDir(self.__localDir)

err, webPage = self.__openWebFile(fileUrl, lsize)
if err == 0:
logger.info('Download OK, File Exists')
webPage.close()
return 0, localPath

fileObj = open(localPath, 'ab+')
for chunk in webPage.iter_content(chunk_size=8 * 1024):
if chunk:
fileObj.write(chunk)
except Exception as e:
logger.error("Download fail: %s" % (e))
return -1, None

fileObj.close()
webPage.close()
logger.info('Download OK')
return 1, localPath

def getFileSize(self, filePath):
try:
lsize = os.stat(filePath).st_size
except:
lsize = 0

return lsize

def __openWebFile(self, fileUrl, offset):
webPage = None
try:
headers = {'Range': 'bytes=%d-' % offset}
webPage = requests.get(fileUrl, stream=True, headers=headers, timeout=120, verify=False)
status_code = webPage.status_code
err = -1
if status_code in [200, 206]:
err = 1
elif status_code == 416:
err = 0
else:
logger.error("Download offset %s fail, invalid url, status: %s" % (offset, status_code))
except Exception as e:
logger.error("Download offset %s fail: %s" % (offset, e))
err = -2
finally:
return err, webPage

+ 87
- 0
vodsdk/UploadAttachedMediaRequest.py View File

@@ -0,0 +1,87 @@
# -*- coding: UTF-8 -*-
"""
# Class UploadAttachedMediaRequest
#
# Aliyun VoD's Upload Attached Media(such as watermark,subtitle files) Request class, which wraps parameters to upload an media file into VoD.
# Users could pass parameters to AliyunVodUploader, including File Path,Title,etc. via an UploadAttachedMediaRequest instance.
# For more details, please check out the VoD API document: https://help.aliyun.com/document_detail/98467.html
"""

from vodsdk.AliyunVodUtils import *
class UploadAttachedMediaRequest:
def __init__(self, filePath, businessType, title=None, fileExt=None):
"""
constructor for UploadAttachedMediaRequest
:param filePath: string, 文件的绝对路径,或者网络文件的URL,必须含有扩展名
:return
"""
self.businessType = businessType
self.filePath = None
self.fileName = None
self.mediaExt = None
self.title = None
self.setFilePath(filePath, title, fileExt)

self.fileSize = None
self.cateId = None
self.tags = None
self.description = None
self.userData = None
self.storageLocation = None
self.appId = None
self.workflowId = None


def setFilePath(self, filePath, title=None, fileExt=None):
if fileExt is None:
fileExt = AliyunVodUtils.getFileExtension(filePath)
if not fileExt:
raise AliyunVodException('ParameterError', 'InvalidParameter', 'filePath has no Extension')

fileExt = fileExt.lstrip('.')
self.mediaExt = fileExt
self.filePath = AliyunVodUtils.toUnicode(filePath)

briefPath, briefName = AliyunVodUtils.getFileBriefPath(self.filePath)
self.fileName = briefPath
if fileExt and (not self.fileName.endswith('.' + fileExt)):
self.fileName = self.fileName + '.' + fileExt

if title:
self.title = title
else:
if self.title is None:
self.title = briefName


def setBusinessType(self, businessType):
self.businessType = businessType

def setTitle(self, title):
self.title = title

def setFileSize(self, fileSize):
self.fileSize = fileSize

def setCateId(self, cateId):
self.cateId = cateId

def setTags(self, tags):
self.tags = tags

def setDescription(self, description):
self.description = description

def setStorageLocation(self, storageLocation):
self.storageLocation = storageLocation

def setUserData(self, userData):
self.userData = userData

def setAppId(self, appId):
self.appId = appId

def setWorkflowId(self, workflowId):
self.workflowId = workflowId



+ 84
- 0
vodsdk/UploadImageRequest.py View File

@@ -0,0 +1,84 @@
# -*- coding: UTF-8 -*-
"""
# Class UploadImageRequest
#
# Aliyun VoD's Upload Image Request class, which wraps parameters to upload an image into VoD.
# Users could pass parameters to AliyunVodUploader, including File Path,Title,etc. via an UploadImageRequest instance.
# For more details, please check out the VoD API document: https://help.aliyun.com/document_detail/55619.html
"""

from vodsdk.AliyunVodUtils import *
class UploadImageRequest:
def __init__(self, filePath, title=None, fileExt=None):
"""
constructor for UploadVideoRequest
:param filePath: string, 文件的绝对路径,或者网络文件的URL,必须含有扩展名
:param title: string, 图片标题
:return
"""
self.filePath = None
self.fileName = None
self.imageExt = None
self.mediaExt = None
self.title = None
self.setFilePath(filePath, title, fileExt)

self.imageType = 'default'
self.cateId = None
self.tags = None
self.description = None
self.userData = None
self.storageLocation = None
self.appId = None
self.workflowId = None

def setFilePath(self, filePath, title=None, fileExt=None):
if fileExt is None:
fileExt = AliyunVodUtils.getFileExtension(filePath)
if not fileExt:
raise AliyunVodException('ParameterError', 'InvalidParameter', 'filePath has no Extension')

fileExt = fileExt.lstrip('.')
self.imageExt = fileExt
self.mediaExt = fileExt
self.filePath = AliyunVodUtils.toUnicode(filePath)

briefPath, briefName = AliyunVodUtils.getFileBriefPath(self.filePath)
self.fileName = briefPath

if fileExt and (not self.fileName.endswith('.' + fileExt)):
self.fileName = self.fileName + '.' + fileExt

if title:
self.title = title
else:
if self.title is None:
self.title = briefName

def setImageType(self, imageType):
self.imageType = imageType

def setTitle(self, title):
self.title = title

def setCateId(self, cateId):
self.cateId = cateId

def setTags(self, tags):
self.tags = tags

def setDescription(self, description):
self.description = description

def setStorageLocation(self, storageLocation):
self.storageLocation = storageLocation

def setUserData(self, userData):
self.userData = userData

def setAppId(self, appId):
self.appId = appId

def setWorkflowId(self, workflowId):
self.workflowId = workflowId

+ 86
- 0
vodsdk/UploadVideoRequest.py View File

@@ -0,0 +1,86 @@
# -*- coding: UTF-8 -*-
"""
# Class UploadVideoRequest
#
# Aliyun VoD's Upload Video Request class, which wraps parameters to upload a video into VoD.
# Users could pass parameters to AliyunVodUploader, including File Path,Title,etc. via an UploadVideoRequest instance.
# For more details, please check out the VoD API document: https://help.aliyun.com/document_detail/55407.html
"""

from vodsdk.AliyunVodUtils import *
class UploadVideoRequest:
def __init__(self, filePath, title=None, fileExt=None):
"""
constructor for UploadVideoRequest
:param filePath: string, 文件的绝对路径,或者网络文件的URL,必须含有扩展名
:param title: string, 视频标题,最长128字节,不传则使用文件名为标题
:return
"""
self.filePath = None
self.fileName = None
self.mediaExt = None
self.title = None
self.setFilePath(filePath, title, fileExt)
self.cateId = None
self.tags = None
self.description = None
self.coverURL = None
self.templateGroupId = None
self.isShowWatermark = None
self.userData = None
self.storageLocation = None
self.uploadId = None
self.appId = None
self.workflowId = None

def setFilePath(self, filePath, title=None, fileExt=None):
if fileExt is None:
fileExt = AliyunVodUtils.getFileExtension(filePath)
if not fileExt:
raise AliyunVodException('ParameterError', 'InvalidParameter', 'filePath has no Extension')

fileExt = fileExt.lstrip('.')
self.mediaExt = fileExt
self.filePath = AliyunVodUtils.toUnicode(filePath)

briefPath, briefName = AliyunVodUtils.getFileBriefPath(self.filePath)
self.fileName = briefPath
if fileExt and (not self.fileName.endswith('.' + fileExt)):
self.fileName = self.fileName + '.' + fileExt

if title:
self.title = title
else:
if self.title is None:
self.title = briefName


def setCateId(self, cateId):
self.cateId = cateId

def setTags(self, tags):
self.tags = tags

def setDescription(self, description):
self.description = description

def setCoverURL(self, coverURL):
self.coverURL = coverURL

def setTemplateGroupId(self, templateGroupId):
self.templateGroupId = templateGroupId
# 关闭水印,仅用于配置全局水印且转码模板开启水印后,单次上传时关闭水印
def shutdownWatermark(self):
self.isShowWatermark = False

# 设置上传ID,可用于关联导入视频
def setUploadId(self, uploadId):
self.uploadId = uploadId

def setAppId(self, appId):
self.appId = appId

def setWorkflowId(self, workflowId):
self.workflowId = workflowId

+ 3
- 0
vodsdk/__init__.py View File

@@ -0,0 +1,3 @@
__version__ = '1.3.1'



BIN
vodsdk/__pycache__/AliyunVodUploader.cpython-38.pyc View File


BIN
vodsdk/__pycache__/AliyunVodUtils.cpython-38.pyc View File


BIN
vodsdk/__pycache__/UploadVideoRequest.cpython-38.pyc View File


BIN
vodsdk/__pycache__/__init__.cpython-38.pyc View File


Loading…
Cancel
Save