优化Token溢出时的处理
Browse files- config.py +2 -0
- crazy_functions/test_project/cpp/longcode/jpgd.cpp +3276 -0
- crazy_functions/test_project/cpp/longcode/jpge.cpp +1049 -0
- crazy_functions/test_project/cpp/longcode/prod_cons.h +433 -0
- crazy_functions/高级功能函数模板.py +1 -1
- functional_crazy.py +7 -6
- main.py +62 -43
- predict.py +9 -3
- toolbox.py +12 -13
config.py
CHANGED
|
@@ -23,6 +23,8 @@ else:
|
|
| 23 |
|
| 24 |
|
| 25 |
# [step 3]>> 以下配置可以优化体验,但大部分场合下并不需要修改
|
|
|
|
|
|
|
| 26 |
|
| 27 |
# 发送请求到OpenAI后,等待多久判定为超时
|
| 28 |
TIMEOUT_SECONDS = 25
|
|
|
|
| 23 |
|
| 24 |
|
| 25 |
# [step 3]>> 以下配置可以优化体验,但大部分场合下并不需要修改
|
| 26 |
+
# 对话窗的高度
|
| 27 |
+
CHATBOT_HEIGHT = 1117
|
| 28 |
|
| 29 |
# 发送请求到OpenAI后,等待多久判定为超时
|
| 30 |
TIMEOUT_SECONDS = 25
|
crazy_functions/test_project/cpp/longcode/jpgd.cpp
ADDED
|
@@ -0,0 +1,3276 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// jpgd.cpp - C++ class for JPEG decompression.
|
| 2 |
+
// Public domain, Rich Geldreich <[email protected]>
|
| 3 |
+
// Last updated Apr. 16, 2011
|
| 4 |
+
// Alex Evans: Linear memory allocator (taken from jpge.h).
|
| 5 |
+
//
|
| 6 |
+
// Supports progressive and baseline sequential JPEG image files, and the most common chroma subsampling factors: Y, H1V1, H2V1, H1V2, and H2V2.
|
| 7 |
+
//
|
| 8 |
+
// Chroma upsampling quality: H2V2 is upsampled in the frequency domain, H2V1 and H1V2 are upsampled using point sampling.
|
| 9 |
+
// Chroma upsampling reference: "Fast Scheme for Image Size Change in the Compressed Domain"
|
| 10 |
+
// http://vision.ai.uiuc.edu/~dugad/research/dct/index.html
|
| 11 |
+
|
| 12 |
+
#include "jpgd.h"
|
| 13 |
+
#include <string.h>
|
| 14 |
+
|
| 15 |
+
#include <assert.h>
|
| 16 |
+
// BEGIN EPIC MOD
|
| 17 |
+
#define JPGD_ASSERT(x) { assert(x); CA_ASSUME(x); } (void)0
|
| 18 |
+
// END EPIC MOD
|
| 19 |
+
|
| 20 |
+
#ifdef _MSC_VER
|
| 21 |
+
#pragma warning (disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable
|
| 22 |
+
#endif
|
| 23 |
+
|
| 24 |
+
// Set to 1 to enable freq. domain chroma upsampling on images using H2V2 subsampling (0=faster nearest neighbor sampling).
|
| 25 |
+
// This is slower, but results in higher quality on images with highly saturated colors.
|
| 26 |
+
#define JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING 1
|
| 27 |
+
|
| 28 |
+
#define JPGD_TRUE (1)
|
| 29 |
+
#define JPGD_FALSE (0)
|
| 30 |
+
|
| 31 |
+
#define JPGD_MAX(a,b) (((a)>(b)) ? (a) : (b))
|
| 32 |
+
#define JPGD_MIN(a,b) (((a)<(b)) ? (a) : (b))
|
| 33 |
+
|
| 34 |
+
namespace jpgd {
|
| 35 |
+
|
| 36 |
+
static inline void *jpgd_malloc(size_t nSize) { return FMemory::Malloc(nSize); }
|
| 37 |
+
static inline void jpgd_free(void *p) { FMemory::Free(p); }
|
| 38 |
+
|
| 39 |
+
// BEGIN EPIC MOD
|
| 40 |
+
//@UE3 - use UE3 BGRA encoding instead of assuming RGBA
|
| 41 |
+
// stolen from IImageWrapper.h
|
| 42 |
+
enum ERGBFormatJPG
|
| 43 |
+
{
|
| 44 |
+
Invalid = -1,
|
| 45 |
+
RGBA = 0,
|
| 46 |
+
BGRA = 1,
|
| 47 |
+
Gray = 2,
|
| 48 |
+
};
|
| 49 |
+
static ERGBFormatJPG jpg_format;
|
| 50 |
+
// END EPIC MOD
|
| 51 |
+
|
| 52 |
+
// DCT coefficients are stored in this sequence.
|
| 53 |
+
static int g_ZAG[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 };
|
| 54 |
+
|
| 55 |
+
enum JPEG_MARKER
|
| 56 |
+
{
|
| 57 |
+
M_SOF0 = 0xC0, M_SOF1 = 0xC1, M_SOF2 = 0xC2, M_SOF3 = 0xC3, M_SOF5 = 0xC5, M_SOF6 = 0xC6, M_SOF7 = 0xC7, M_JPG = 0xC8,
|
| 58 |
+
M_SOF9 = 0xC9, M_SOF10 = 0xCA, M_SOF11 = 0xCB, M_SOF13 = 0xCD, M_SOF14 = 0xCE, M_SOF15 = 0xCF, M_DHT = 0xC4, M_DAC = 0xCC,
|
| 59 |
+
M_RST0 = 0xD0, M_RST1 = 0xD1, M_RST2 = 0xD2, M_RST3 = 0xD3, M_RST4 = 0xD4, M_RST5 = 0xD5, M_RST6 = 0xD6, M_RST7 = 0xD7,
|
| 60 |
+
M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_DNL = 0xDC, M_DRI = 0xDD, M_DHP = 0xDE, M_EXP = 0xDF,
|
| 61 |
+
M_APP0 = 0xE0, M_APP15 = 0xEF, M_JPG0 = 0xF0, M_JPG13 = 0xFD, M_COM = 0xFE, M_TEM = 0x01, M_ERROR = 0x100, RST0 = 0xD0
|
| 62 |
+
};
|
| 63 |
+
|
| 64 |
+
enum JPEG_SUBSAMPLING { JPGD_GRAYSCALE = 0, JPGD_YH1V1, JPGD_YH2V1, JPGD_YH1V2, JPGD_YH2V2 };
|
| 65 |
+
|
| 66 |
+
#define CONST_BITS 13
|
| 67 |
+
#define PASS1_BITS 2
|
| 68 |
+
#define SCALEDONE ((int32)1)
|
| 69 |
+
|
| 70 |
+
#define FIX_0_298631336 ((int32)2446) /* FIX(0.298631336) */
|
| 71 |
+
#define FIX_0_390180644 ((int32)3196) /* FIX(0.390180644) */
|
| 72 |
+
#define FIX_0_541196100 ((int32)4433) /* FIX(0.541196100) */
|
| 73 |
+
#define FIX_0_765366865 ((int32)6270) /* FIX(0.765366865) */
|
| 74 |
+
#define FIX_0_899976223 ((int32)7373) /* FIX(0.899976223) */
|
| 75 |
+
#define FIX_1_175875602 ((int32)9633) /* FIX(1.175875602) */
|
| 76 |
+
#define FIX_1_501321110 ((int32)12299) /* FIX(1.501321110) */
|
| 77 |
+
#define FIX_1_847759065 ((int32)15137) /* FIX(1.847759065) */
|
| 78 |
+
#define FIX_1_961570560 ((int32)16069) /* FIX(1.961570560) */
|
| 79 |
+
#define FIX_2_053119869 ((int32)16819) /* FIX(2.053119869) */
|
| 80 |
+
#define FIX_2_562915447 ((int32)20995) /* FIX(2.562915447) */
|
| 81 |
+
#define FIX_3_072711026 ((int32)25172) /* FIX(3.072711026) */
|
| 82 |
+
|
| 83 |
+
#define DESCALE(x,n) (((x) + (SCALEDONE << ((n)-1))) >> (n))
|
| 84 |
+
#define DESCALE_ZEROSHIFT(x,n) (((x) + (128 << (n)) + (SCALEDONE << ((n)-1))) >> (n))
|
| 85 |
+
|
| 86 |
+
#define MULTIPLY(var, cnst) ((var) * (cnst))
|
| 87 |
+
|
| 88 |
+
#define CLAMP(i) ((static_cast<uint>(i) > 255) ? (((~i) >> 31) & 0xFF) : (i))
|
| 89 |
+
|
| 90 |
+
// Compiler creates a fast path 1D IDCT for X non-zero columns
|
| 91 |
+
template <int NONZERO_COLS>
|
| 92 |
+
struct Row
|
| 93 |
+
{
|
| 94 |
+
static void idct(int* pTemp, const jpgd_block_t* pSrc)
|
| 95 |
+
{
|
| 96 |
+
// ACCESS_COL() will be optimized at compile time to either an array access, or 0.
|
| 97 |
+
#define ACCESS_COL(x) (((x) < NONZERO_COLS) ? (int)pSrc[x] : 0)
|
| 98 |
+
|
| 99 |
+
const int z2 = ACCESS_COL(2), z3 = ACCESS_COL(6);
|
| 100 |
+
|
| 101 |
+
const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
|
| 102 |
+
const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
|
| 103 |
+
const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
|
| 104 |
+
|
| 105 |
+
const int tmp0 = (ACCESS_COL(0) + ACCESS_COL(4)) << CONST_BITS;
|
| 106 |
+
const int tmp1 = (ACCESS_COL(0) - ACCESS_COL(4)) << CONST_BITS;
|
| 107 |
+
|
| 108 |
+
const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2;
|
| 109 |
+
|
| 110 |
+
const int atmp0 = ACCESS_COL(7), atmp1 = ACCESS_COL(5), atmp2 = ACCESS_COL(3), atmp3 = ACCESS_COL(1);
|
| 111 |
+
|
| 112 |
+
const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3;
|
| 113 |
+
const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602);
|
| 114 |
+
|
| 115 |
+
const int az1 = MULTIPLY(bz1, - FIX_0_899976223);
|
| 116 |
+
const int az2 = MULTIPLY(bz2, - FIX_2_562915447);
|
| 117 |
+
const int az3 = MULTIPLY(bz3, - FIX_1_961570560) + bz5;
|
| 118 |
+
const int az4 = MULTIPLY(bz4, - FIX_0_390180644) + bz5;
|
| 119 |
+
|
| 120 |
+
const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3;
|
| 121 |
+
const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4;
|
| 122 |
+
const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3;
|
| 123 |
+
const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4;
|
| 124 |
+
|
| 125 |
+
pTemp[0] = DESCALE(tmp10 + btmp3, CONST_BITS-PASS1_BITS);
|
| 126 |
+
pTemp[7] = DESCALE(tmp10 - btmp3, CONST_BITS-PASS1_BITS);
|
| 127 |
+
pTemp[1] = DESCALE(tmp11 + btmp2, CONST_BITS-PASS1_BITS);
|
| 128 |
+
pTemp[6] = DESCALE(tmp11 - btmp2, CONST_BITS-PASS1_BITS);
|
| 129 |
+
pTemp[2] = DESCALE(tmp12 + btmp1, CONST_BITS-PASS1_BITS);
|
| 130 |
+
pTemp[5] = DESCALE(tmp12 - btmp1, CONST_BITS-PASS1_BITS);
|
| 131 |
+
pTemp[3] = DESCALE(tmp13 + btmp0, CONST_BITS-PASS1_BITS);
|
| 132 |
+
pTemp[4] = DESCALE(tmp13 - btmp0, CONST_BITS-PASS1_BITS);
|
| 133 |
+
}
|
| 134 |
+
};
|
| 135 |
+
|
| 136 |
+
template <>
|
| 137 |
+
struct Row<0>
|
| 138 |
+
{
|
| 139 |
+
static void idct(int* pTemp, const jpgd_block_t* pSrc)
|
| 140 |
+
{
|
| 141 |
+
#ifdef _MSC_VER
|
| 142 |
+
pTemp; pSrc;
|
| 143 |
+
#endif
|
| 144 |
+
}
|
| 145 |
+
};
|
| 146 |
+
|
| 147 |
+
template <>
|
| 148 |
+
struct Row<1>
|
| 149 |
+
{
|
| 150 |
+
static void idct(int* pTemp, const jpgd_block_t* pSrc)
|
| 151 |
+
{
|
| 152 |
+
const int dcval = (pSrc[0] << PASS1_BITS);
|
| 153 |
+
|
| 154 |
+
pTemp[0] = dcval;
|
| 155 |
+
pTemp[1] = dcval;
|
| 156 |
+
pTemp[2] = dcval;
|
| 157 |
+
pTemp[3] = dcval;
|
| 158 |
+
pTemp[4] = dcval;
|
| 159 |
+
pTemp[5] = dcval;
|
| 160 |
+
pTemp[6] = dcval;
|
| 161 |
+
pTemp[7] = dcval;
|
| 162 |
+
}
|
| 163 |
+
};
|
| 164 |
+
|
| 165 |
+
// Compiler creates a fast path 1D IDCT for X non-zero rows
|
| 166 |
+
template <int NONZERO_ROWS>
|
| 167 |
+
struct Col
|
| 168 |
+
{
|
| 169 |
+
static void idct(uint8* pDst_ptr, const int* pTemp)
|
| 170 |
+
{
|
| 171 |
+
// ACCESS_ROW() will be optimized at compile time to either an array access, or 0.
|
| 172 |
+
#define ACCESS_ROW(x) (((x) < NONZERO_ROWS) ? pTemp[x * 8] : 0)
|
| 173 |
+
|
| 174 |
+
const int z2 = ACCESS_ROW(2);
|
| 175 |
+
const int z3 = ACCESS_ROW(6);
|
| 176 |
+
|
| 177 |
+
const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
|
| 178 |
+
const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
|
| 179 |
+
const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
|
| 180 |
+
|
| 181 |
+
const int tmp0 = (ACCESS_ROW(0) + ACCESS_ROW(4)) << CONST_BITS;
|
| 182 |
+
const int tmp1 = (ACCESS_ROW(0) - ACCESS_ROW(4)) << CONST_BITS;
|
| 183 |
+
|
| 184 |
+
const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2;
|
| 185 |
+
|
| 186 |
+
const int atmp0 = ACCESS_ROW(7), atmp1 = ACCESS_ROW(5), atmp2 = ACCESS_ROW(3), atmp3 = ACCESS_ROW(1);
|
| 187 |
+
|
| 188 |
+
const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3;
|
| 189 |
+
const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602);
|
| 190 |
+
|
| 191 |
+
const int az1 = MULTIPLY(bz1, - FIX_0_899976223);
|
| 192 |
+
const int az2 = MULTIPLY(bz2, - FIX_2_562915447);
|
| 193 |
+
const int az3 = MULTIPLY(bz3, - FIX_1_961570560) + bz5;
|
| 194 |
+
const int az4 = MULTIPLY(bz4, - FIX_0_390180644) + bz5;
|
| 195 |
+
|
| 196 |
+
const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3;
|
| 197 |
+
const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4;
|
| 198 |
+
const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3;
|
| 199 |
+
const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4;
|
| 200 |
+
|
| 201 |
+
int i = DESCALE_ZEROSHIFT(tmp10 + btmp3, CONST_BITS+PASS1_BITS+3);
|
| 202 |
+
pDst_ptr[8*0] = (uint8)CLAMP(i);
|
| 203 |
+
|
| 204 |
+
i = DESCALE_ZEROSHIFT(tmp10 - btmp3, CONST_BITS+PASS1_BITS+3);
|
| 205 |
+
pDst_ptr[8*7] = (uint8)CLAMP(i);
|
| 206 |
+
|
| 207 |
+
i = DESCALE_ZEROSHIFT(tmp11 + btmp2, CONST_BITS+PASS1_BITS+3);
|
| 208 |
+
pDst_ptr[8*1] = (uint8)CLAMP(i);
|
| 209 |
+
|
| 210 |
+
i = DESCALE_ZEROSHIFT(tmp11 - btmp2, CONST_BITS+PASS1_BITS+3);
|
| 211 |
+
pDst_ptr[8*6] = (uint8)CLAMP(i);
|
| 212 |
+
|
| 213 |
+
i = DESCALE_ZEROSHIFT(tmp12 + btmp1, CONST_BITS+PASS1_BITS+3);
|
| 214 |
+
pDst_ptr[8*2] = (uint8)CLAMP(i);
|
| 215 |
+
|
| 216 |
+
i = DESCALE_ZEROSHIFT(tmp12 - btmp1, CONST_BITS+PASS1_BITS+3);
|
| 217 |
+
pDst_ptr[8*5] = (uint8)CLAMP(i);
|
| 218 |
+
|
| 219 |
+
i = DESCALE_ZEROSHIFT(tmp13 + btmp0, CONST_BITS+PASS1_BITS+3);
|
| 220 |
+
pDst_ptr[8*3] = (uint8)CLAMP(i);
|
| 221 |
+
|
| 222 |
+
i = DESCALE_ZEROSHIFT(tmp13 - btmp0, CONST_BITS+PASS1_BITS+3);
|
| 223 |
+
pDst_ptr[8*4] = (uint8)CLAMP(i);
|
| 224 |
+
}
|
| 225 |
+
};
|
| 226 |
+
|
| 227 |
+
template <>
|
| 228 |
+
struct Col<1>
|
| 229 |
+
{
|
| 230 |
+
static void idct(uint8* pDst_ptr, const int* pTemp)
|
| 231 |
+
{
|
| 232 |
+
int dcval = DESCALE_ZEROSHIFT(pTemp[0], PASS1_BITS+3);
|
| 233 |
+
const uint8 dcval_clamped = (uint8)CLAMP(dcval);
|
| 234 |
+
pDst_ptr[0*8] = dcval_clamped;
|
| 235 |
+
pDst_ptr[1*8] = dcval_clamped;
|
| 236 |
+
pDst_ptr[2*8] = dcval_clamped;
|
| 237 |
+
pDst_ptr[3*8] = dcval_clamped;
|
| 238 |
+
pDst_ptr[4*8] = dcval_clamped;
|
| 239 |
+
pDst_ptr[5*8] = dcval_clamped;
|
| 240 |
+
pDst_ptr[6*8] = dcval_clamped;
|
| 241 |
+
pDst_ptr[7*8] = dcval_clamped;
|
| 242 |
+
}
|
| 243 |
+
};
|
| 244 |
+
|
| 245 |
+
static const uint8 s_idct_row_table[] =
|
| 246 |
+
{
|
| 247 |
+
1,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0, 2,1,0,0,0,0,0,0, 2,1,1,0,0,0,0,0, 2,2,1,0,0,0,0,0, 3,2,1,0,0,0,0,0, 4,2,1,0,0,0,0,0, 4,3,1,0,0,0,0,0,
|
| 248 |
+
4,3,2,0,0,0,0,0, 4,3,2,1,0,0,0,0, 4,3,2,1,1,0,0,0, 4,3,2,2,1,0,0,0, 4,3,3,2,1,0,0,0, 4,4,3,2,1,0,0,0, 5,4,3,2,1,0,0,0, 6,4,3,2,1,0,0,0,
|
| 249 |
+
6,5,3,2,1,0,0,0, 6,5,4,2,1,0,0,0, 6,5,4,3,1,0,0,0, 6,5,4,3,2,0,0,0, 6,5,4,3,2,1,0,0, 6,5,4,3,2,1,1,0, 6,5,4,3,2,2,1,0, 6,5,4,3,3,2,1,0,
|
| 250 |
+
6,5,4,4,3,2,1,0, 6,5,5,4,3,2,1,0, 6,6,5,4,3,2,1,0, 7,6,5,4,3,2,1,0, 8,6,5,4,3,2,1,0, 8,7,5,4,3,2,1,0, 8,7,6,4,3,2,1,0, 8,7,6,5,3,2,1,0,
|
| 251 |
+
8,7,6,5,4,2,1,0, 8,7,6,5,4,3,1,0, 8,7,6,5,4,3,2,0, 8,7,6,5,4,3,2,1, 8,7,6,5,4,3,2,2, 8,7,6,5,4,3,3,2, 8,7,6,5,4,4,3,2, 8,7,6,5,5,4,3,2,
|
| 252 |
+
8,7,6,6,5,4,3,2, 8,7,7,6,5,4,3,2, 8,8,7,6,5,4,3,2, 8,8,8,6,5,4,3,2, 8,8,8,7,5,4,3,2, 8,8,8,7,6,4,3,2, 8,8,8,7,6,5,3,2, 8,8,8,7,6,5,4,2,
|
| 253 |
+
8,8,8,7,6,5,4,3, 8,8,8,7,6,5,4,4, 8,8,8,7,6,5,5,4, 8,8,8,7,6,6,5,4, 8,8,8,7,7,6,5,4, 8,8,8,8,7,6,5,4, 8,8,8,8,8,6,5,4, 8,8,8,8,8,7,5,4,
|
| 254 |
+
8,8,8,8,8,7,6,4, 8,8,8,8,8,7,6,5, 8,8,8,8,8,7,6,6, 8,8,8,8,8,7,7,6, 8,8,8,8,8,8,7,6, 8,8,8,8,8,8,8,6, 8,8,8,8,8,8,8,7, 8,8,8,8,8,8,8,8,
|
| 255 |
+
};
|
| 256 |
+
|
| 257 |
+
static const uint8 s_idct_col_table[] = { 1, 1, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 };
|
| 258 |
+
|
| 259 |
+
void idct(const jpgd_block_t* pSrc_ptr, uint8* pDst_ptr, int block_max_zag)
|
| 260 |
+
{
|
| 261 |
+
JPGD_ASSERT(block_max_zag >= 1);
|
| 262 |
+
JPGD_ASSERT(block_max_zag <= 64);
|
| 263 |
+
|
| 264 |
+
if (block_max_zag == 1)
|
| 265 |
+
{
|
| 266 |
+
int k = ((pSrc_ptr[0] + 4) >> 3) + 128;
|
| 267 |
+
k = CLAMP(k);
|
| 268 |
+
k = k | (k<<8);
|
| 269 |
+
k = k | (k<<16);
|
| 270 |
+
|
| 271 |
+
for (int i = 8; i > 0; i--)
|
| 272 |
+
{
|
| 273 |
+
*(int*)&pDst_ptr[0] = k;
|
| 274 |
+
*(int*)&pDst_ptr[4] = k;
|
| 275 |
+
pDst_ptr += 8;
|
| 276 |
+
}
|
| 277 |
+
return;
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
int temp[64];
|
| 281 |
+
|
| 282 |
+
const jpgd_block_t* pSrc = pSrc_ptr;
|
| 283 |
+
int* pTemp = temp;
|
| 284 |
+
|
| 285 |
+
const uint8* pRow_tab = &s_idct_row_table[(block_max_zag - 1) * 8];
|
| 286 |
+
int i;
|
| 287 |
+
for (i = 8; i > 0; i--, pRow_tab++)
|
| 288 |
+
{
|
| 289 |
+
switch (*pRow_tab)
|
| 290 |
+
{
|
| 291 |
+
case 0: Row<0>::idct(pTemp, pSrc); break;
|
| 292 |
+
case 1: Row<1>::idct(pTemp, pSrc); break;
|
| 293 |
+
case 2: Row<2>::idct(pTemp, pSrc); break;
|
| 294 |
+
case 3: Row<3>::idct(pTemp, pSrc); break;
|
| 295 |
+
case 4: Row<4>::idct(pTemp, pSrc); break;
|
| 296 |
+
case 5: Row<5>::idct(pTemp, pSrc); break;
|
| 297 |
+
case 6: Row<6>::idct(pTemp, pSrc); break;
|
| 298 |
+
case 7: Row<7>::idct(pTemp, pSrc); break;
|
| 299 |
+
case 8: Row<8>::idct(pTemp, pSrc); break;
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
pSrc += 8;
|
| 303 |
+
pTemp += 8;
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
pTemp = temp;
|
| 307 |
+
|
| 308 |
+
const int nonzero_rows = s_idct_col_table[block_max_zag - 1];
|
| 309 |
+
for (i = 8; i > 0; i--)
|
| 310 |
+
{
|
| 311 |
+
switch (nonzero_rows)
|
| 312 |
+
{
|
| 313 |
+
case 1: Col<1>::idct(pDst_ptr, pTemp); break;
|
| 314 |
+
case 2: Col<2>::idct(pDst_ptr, pTemp); break;
|
| 315 |
+
case 3: Col<3>::idct(pDst_ptr, pTemp); break;
|
| 316 |
+
case 4: Col<4>::idct(pDst_ptr, pTemp); break;
|
| 317 |
+
case 5: Col<5>::idct(pDst_ptr, pTemp); break;
|
| 318 |
+
case 6: Col<6>::idct(pDst_ptr, pTemp); break;
|
| 319 |
+
case 7: Col<7>::idct(pDst_ptr, pTemp); break;
|
| 320 |
+
case 8: Col<8>::idct(pDst_ptr, pTemp); break;
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
pTemp++;
|
| 324 |
+
pDst_ptr++;
|
| 325 |
+
}
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
void idct_4x4(const jpgd_block_t* pSrc_ptr, uint8* pDst_ptr)
|
| 329 |
+
{
|
| 330 |
+
int temp[64];
|
| 331 |
+
int* pTemp = temp;
|
| 332 |
+
const jpgd_block_t* pSrc = pSrc_ptr;
|
| 333 |
+
|
| 334 |
+
for (int i = 4; i > 0; i--)
|
| 335 |
+
{
|
| 336 |
+
Row<4>::idct(pTemp, pSrc);
|
| 337 |
+
pSrc += 8;
|
| 338 |
+
pTemp += 8;
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
pTemp = temp;
|
| 342 |
+
for (int i = 8; i > 0; i--)
|
| 343 |
+
{
|
| 344 |
+
Col<4>::idct(pDst_ptr, pTemp);
|
| 345 |
+
pTemp++;
|
| 346 |
+
pDst_ptr++;
|
| 347 |
+
}
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
// Retrieve one character from the input stream.
|
| 351 |
+
inline uint jpeg_decoder::get_char()
|
| 352 |
+
{
|
| 353 |
+
// Any bytes remaining in buffer?
|
| 354 |
+
if (!m_in_buf_left)
|
| 355 |
+
{
|
| 356 |
+
// Try to get more bytes.
|
| 357 |
+
prep_in_buffer();
|
| 358 |
+
// Still nothing to get?
|
| 359 |
+
if (!m_in_buf_left)
|
| 360 |
+
{
|
| 361 |
+
// Pad the end of the stream with 0xFF 0xD9 (EOI marker)
|
| 362 |
+
int t = m_tem_flag;
|
| 363 |
+
m_tem_flag ^= 1;
|
| 364 |
+
if (t)
|
| 365 |
+
return 0xD9;
|
| 366 |
+
else
|
| 367 |
+
return 0xFF;
|
| 368 |
+
}
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
uint c = *m_pIn_buf_ofs++;
|
| 372 |
+
m_in_buf_left--;
|
| 373 |
+
|
| 374 |
+
return c;
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
// Same as previous method, except can indicate if the character is a pad character or not.
|
| 378 |
+
inline uint jpeg_decoder::get_char(bool *pPadding_flag)
|
| 379 |
+
{
|
| 380 |
+
if (!m_in_buf_left)
|
| 381 |
+
{
|
| 382 |
+
prep_in_buffer();
|
| 383 |
+
if (!m_in_buf_left)
|
| 384 |
+
{
|
| 385 |
+
*pPadding_flag = true;
|
| 386 |
+
int t = m_tem_flag;
|
| 387 |
+
m_tem_flag ^= 1;
|
| 388 |
+
if (t)
|
| 389 |
+
return 0xD9;
|
| 390 |
+
else
|
| 391 |
+
return 0xFF;
|
| 392 |
+
}
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
*pPadding_flag = false;
|
| 396 |
+
|
| 397 |
+
uint c = *m_pIn_buf_ofs++;
|
| 398 |
+
m_in_buf_left--;
|
| 399 |
+
|
| 400 |
+
return c;
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
// Inserts a previously retrieved character back into the input buffer.
|
| 404 |
+
inline void jpeg_decoder::stuff_char(uint8 q)
|
| 405 |
+
{
|
| 406 |
+
*(--m_pIn_buf_ofs) = q;
|
| 407 |
+
m_in_buf_left++;
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
// Retrieves one character from the input stream, but does not read past markers. Will continue to return 0xFF when a marker is encountered.
|
| 411 |
+
inline uint8 jpeg_decoder::get_octet()
|
| 412 |
+
{
|
| 413 |
+
bool padding_flag;
|
| 414 |
+
int c = get_char(&padding_flag);
|
| 415 |
+
|
| 416 |
+
if (c == 0xFF)
|
| 417 |
+
{
|
| 418 |
+
if (padding_flag)
|
| 419 |
+
return 0xFF;
|
| 420 |
+
|
| 421 |
+
c = get_char(&padding_flag);
|
| 422 |
+
if (padding_flag)
|
| 423 |
+
{
|
| 424 |
+
stuff_char(0xFF);
|
| 425 |
+
return 0xFF;
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
if (c == 0x00)
|
| 429 |
+
return 0xFF;
|
| 430 |
+
else
|
| 431 |
+
{
|
| 432 |
+
stuff_char(static_cast<uint8>(c));
|
| 433 |
+
stuff_char(0xFF);
|
| 434 |
+
return 0xFF;
|
| 435 |
+
}
|
| 436 |
+
}
|
| 437 |
+
|
| 438 |
+
return static_cast<uint8>(c);
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
// Retrieves a variable number of bits from the input stream. Does not recognize markers.
|
| 442 |
+
inline uint jpeg_decoder::get_bits(int num_bits)
|
| 443 |
+
{
|
| 444 |
+
if (!num_bits)
|
| 445 |
+
return 0;
|
| 446 |
+
|
| 447 |
+
uint i = m_bit_buf >> (32 - num_bits);
|
| 448 |
+
|
| 449 |
+
if ((m_bits_left -= num_bits) <= 0)
|
| 450 |
+
{
|
| 451 |
+
m_bit_buf <<= (num_bits += m_bits_left);
|
| 452 |
+
|
| 453 |
+
uint c1 = get_char();
|
| 454 |
+
uint c2 = get_char();
|
| 455 |
+
m_bit_buf = (m_bit_buf & 0xFFFF0000) | (c1 << 8) | c2;
|
| 456 |
+
|
| 457 |
+
m_bit_buf <<= -m_bits_left;
|
| 458 |
+
|
| 459 |
+
m_bits_left += 16;
|
| 460 |
+
|
| 461 |
+
JPGD_ASSERT(m_bits_left >= 0);
|
| 462 |
+
}
|
| 463 |
+
else
|
| 464 |
+
m_bit_buf <<= num_bits;
|
| 465 |
+
|
| 466 |
+
return i;
|
| 467 |
+
}
|
| 468 |
+
|
| 469 |
+
// Retrieves a variable number of bits from the input stream. Markers will not be read into the input bit buffer. Instead, an infinite number of all 1's will be returned when a marker is encountered.
|
| 470 |
+
inline uint jpeg_decoder::get_bits_no_markers(int num_bits)
|
| 471 |
+
{
|
| 472 |
+
if (!num_bits)
|
| 473 |
+
return 0;
|
| 474 |
+
|
| 475 |
+
uint i = m_bit_buf >> (32 - num_bits);
|
| 476 |
+
|
| 477 |
+
if ((m_bits_left -= num_bits) <= 0)
|
| 478 |
+
{
|
| 479 |
+
m_bit_buf <<= (num_bits += m_bits_left);
|
| 480 |
+
|
| 481 |
+
if ((m_in_buf_left < 2) || (m_pIn_buf_ofs[0] == 0xFF) || (m_pIn_buf_ofs[1] == 0xFF))
|
| 482 |
+
{
|
| 483 |
+
uint c1 = get_octet();
|
| 484 |
+
uint c2 = get_octet();
|
| 485 |
+
m_bit_buf |= (c1 << 8) | c2;
|
| 486 |
+
}
|
| 487 |
+
else
|
| 488 |
+
{
|
| 489 |
+
m_bit_buf |= ((uint)m_pIn_buf_ofs[0] << 8) | m_pIn_buf_ofs[1];
|
| 490 |
+
m_in_buf_left -= 2;
|
| 491 |
+
m_pIn_buf_ofs += 2;
|
| 492 |
+
}
|
| 493 |
+
|
| 494 |
+
m_bit_buf <<= -m_bits_left;
|
| 495 |
+
|
| 496 |
+
m_bits_left += 16;
|
| 497 |
+
|
| 498 |
+
JPGD_ASSERT(m_bits_left >= 0);
|
| 499 |
+
}
|
| 500 |
+
else
|
| 501 |
+
m_bit_buf <<= num_bits;
|
| 502 |
+
|
| 503 |
+
return i;
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
// Decodes a Huffman encoded symbol.
|
| 507 |
+
inline int jpeg_decoder::huff_decode(huff_tables *pH)
|
| 508 |
+
{
|
| 509 |
+
int symbol;
|
| 510 |
+
|
| 511 |
+
// Check first 8-bits: do we have a complete symbol?
|
| 512 |
+
if ((symbol = pH->look_up[m_bit_buf >> 24]) < 0)
|
| 513 |
+
{
|
| 514 |
+
// Decode more bits, use a tree traversal to find symbol.
|
| 515 |
+
int ofs = 23;
|
| 516 |
+
do
|
| 517 |
+
{
|
| 518 |
+
symbol = pH->tree[-(int)(symbol + ((m_bit_buf >> ofs) & 1))];
|
| 519 |
+
ofs--;
|
| 520 |
+
} while (symbol < 0);
|
| 521 |
+
|
| 522 |
+
get_bits_no_markers(8 + (23 - ofs));
|
| 523 |
+
}
|
| 524 |
+
else
|
| 525 |
+
get_bits_no_markers(pH->code_size[symbol]);
|
| 526 |
+
|
| 527 |
+
return symbol;
|
| 528 |
+
}
|
| 529 |
+
|
| 530 |
+
// Decodes a Huffman encoded symbol.
|
| 531 |
+
inline int jpeg_decoder::huff_decode(huff_tables *pH, int& extra_bits)
|
| 532 |
+
{
|
| 533 |
+
int symbol;
|
| 534 |
+
|
| 535 |
+
// Check first 8-bits: do we have a complete symbol?
|
| 536 |
+
if ((symbol = pH->look_up2[m_bit_buf >> 24]) < 0)
|
| 537 |
+
{
|
| 538 |
+
// Use a tree traversal to find symbol.
|
| 539 |
+
int ofs = 23;
|
| 540 |
+
do
|
| 541 |
+
{
|
| 542 |
+
symbol = pH->tree[-(int)(symbol + ((m_bit_buf >> ofs) & 1))];
|
| 543 |
+
ofs--;
|
| 544 |
+
} while (symbol < 0);
|
| 545 |
+
|
| 546 |
+
get_bits_no_markers(8 + (23 - ofs));
|
| 547 |
+
|
| 548 |
+
extra_bits = get_bits_no_markers(symbol & 0xF);
|
| 549 |
+
}
|
| 550 |
+
else
|
| 551 |
+
{
|
| 552 |
+
JPGD_ASSERT(((symbol >> 8) & 31) == pH->code_size[symbol & 255] + ((symbol & 0x8000) ? (symbol & 15) : 0));
|
| 553 |
+
|
| 554 |
+
if (symbol & 0x8000)
|
| 555 |
+
{
|
| 556 |
+
get_bits_no_markers((symbol >> 8) & 31);
|
| 557 |
+
extra_bits = symbol >> 16;
|
| 558 |
+
}
|
| 559 |
+
else
|
| 560 |
+
{
|
| 561 |
+
int code_size = (symbol >> 8) & 31;
|
| 562 |
+
int num_extra_bits = symbol & 0xF;
|
| 563 |
+
int bits = code_size + num_extra_bits;
|
| 564 |
+
if (bits <= (m_bits_left + 16))
|
| 565 |
+
extra_bits = get_bits_no_markers(bits) & ((1 << num_extra_bits) - 1);
|
| 566 |
+
else
|
| 567 |
+
{
|
| 568 |
+
get_bits_no_markers(code_size);
|
| 569 |
+
extra_bits = get_bits_no_markers(num_extra_bits);
|
| 570 |
+
}
|
| 571 |
+
}
|
| 572 |
+
|
| 573 |
+
symbol &= 0xFF;
|
| 574 |
+
}
|
| 575 |
+
|
| 576 |
+
return symbol;
|
| 577 |
+
}
|
| 578 |
+
|
| 579 |
+
// Tables and macro used to fully decode the DPCM differences.
|
| 580 |
+
static const int s_extend_test[16] = { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
|
| 581 |
+
static const int s_extend_offset[16] = { 0, -1, -3, -7, -15, -31, -63, -127, -255, -511, -1023, -2047, -4095, -8191, -16383, -32767 };
|
| 582 |
+
static const int s_extend_mask[] = { 0, (1<<0), (1<<1), (1<<2), (1<<3), (1<<4), (1<<5), (1<<6), (1<<7), (1<<8), (1<<9), (1<<10), (1<<11), (1<<12), (1<<13), (1<<14), (1<<15), (1<<16) };
|
| 583 |
+
#define HUFF_EXTEND(x,s) ((x) < s_extend_test[s] ? (x) + s_extend_offset[s] : (x))
|
| 584 |
+
|
| 585 |
+
// Clamps a value between 0-255.
|
| 586 |
+
inline uint8 jpeg_decoder::clamp(int i)
|
| 587 |
+
{
|
| 588 |
+
if (static_cast<uint>(i) > 255)
|
| 589 |
+
i = (((~i) >> 31) & 0xFF);
|
| 590 |
+
|
| 591 |
+
return static_cast<uint8>(i);
|
| 592 |
+
}
|
| 593 |
+
|
| 594 |
+
namespace DCT_Upsample
|
| 595 |
+
{
|
| 596 |
+
struct Matrix44
|
| 597 |
+
{
|
| 598 |
+
typedef int Element_Type;
|
| 599 |
+
enum { NUM_ROWS = 4, NUM_COLS = 4 };
|
| 600 |
+
|
| 601 |
+
Element_Type v[NUM_ROWS][NUM_COLS];
|
| 602 |
+
|
| 603 |
+
inline int rows() const { return NUM_ROWS; }
|
| 604 |
+
inline int cols() const { return NUM_COLS; }
|
| 605 |
+
|
| 606 |
+
inline const Element_Type & at(int r, int c) const { return v[r][c]; }
|
| 607 |
+
inline Element_Type & at(int r, int c) { return v[r][c]; }
|
| 608 |
+
|
| 609 |
+
inline Matrix44() { }
|
| 610 |
+
|
| 611 |
+
inline Matrix44& operator += (const Matrix44& a)
|
| 612 |
+
{
|
| 613 |
+
for (int r = 0; r < NUM_ROWS; r++)
|
| 614 |
+
{
|
| 615 |
+
at(r, 0) += a.at(r, 0);
|
| 616 |
+
at(r, 1) += a.at(r, 1);
|
| 617 |
+
at(r, 2) += a.at(r, 2);
|
| 618 |
+
at(r, 3) += a.at(r, 3);
|
| 619 |
+
}
|
| 620 |
+
return *this;
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
inline Matrix44& operator -= (const Matrix44& a)
|
| 624 |
+
{
|
| 625 |
+
for (int r = 0; r < NUM_ROWS; r++)
|
| 626 |
+
{
|
| 627 |
+
at(r, 0) -= a.at(r, 0);
|
| 628 |
+
at(r, 1) -= a.at(r, 1);
|
| 629 |
+
at(r, 2) -= a.at(r, 2);
|
| 630 |
+
at(r, 3) -= a.at(r, 3);
|
| 631 |
+
}
|
| 632 |
+
return *this;
|
| 633 |
+
}
|
| 634 |
+
|
| 635 |
+
friend inline Matrix44 operator + (const Matrix44& a, const Matrix44& b)
|
| 636 |
+
{
|
| 637 |
+
Matrix44 ret;
|
| 638 |
+
for (int r = 0; r < NUM_ROWS; r++)
|
| 639 |
+
{
|
| 640 |
+
ret.at(r, 0) = a.at(r, 0) + b.at(r, 0);
|
| 641 |
+
ret.at(r, 1) = a.at(r, 1) + b.at(r, 1);
|
| 642 |
+
ret.at(r, 2) = a.at(r, 2) + b.at(r, 2);
|
| 643 |
+
ret.at(r, 3) = a.at(r, 3) + b.at(r, 3);
|
| 644 |
+
}
|
| 645 |
+
return ret;
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
friend inline Matrix44 operator - (const Matrix44& a, const Matrix44& b)
|
| 649 |
+
{
|
| 650 |
+
Matrix44 ret;
|
| 651 |
+
for (int r = 0; r < NUM_ROWS; r++)
|
| 652 |
+
{
|
| 653 |
+
ret.at(r, 0) = a.at(r, 0) - b.at(r, 0);
|
| 654 |
+
ret.at(r, 1) = a.at(r, 1) - b.at(r, 1);
|
| 655 |
+
ret.at(r, 2) = a.at(r, 2) - b.at(r, 2);
|
| 656 |
+
ret.at(r, 3) = a.at(r, 3) - b.at(r, 3);
|
| 657 |
+
}
|
| 658 |
+
return ret;
|
| 659 |
+
}
|
| 660 |
+
|
| 661 |
+
static inline void add_and_store(jpgd_block_t* pDst, const Matrix44& a, const Matrix44& b)
|
| 662 |
+
{
|
| 663 |
+
for (int r = 0; r < 4; r++)
|
| 664 |
+
{
|
| 665 |
+
pDst[0*8 + r] = static_cast<jpgd_block_t>(a.at(r, 0) + b.at(r, 0));
|
| 666 |
+
pDst[1*8 + r] = static_cast<jpgd_block_t>(a.at(r, 1) + b.at(r, 1));
|
| 667 |
+
pDst[2*8 + r] = static_cast<jpgd_block_t>(a.at(r, 2) + b.at(r, 2));
|
| 668 |
+
pDst[3*8 + r] = static_cast<jpgd_block_t>(a.at(r, 3) + b.at(r, 3));
|
| 669 |
+
}
|
| 670 |
+
}
|
| 671 |
+
|
| 672 |
+
static inline void sub_and_store(jpgd_block_t* pDst, const Matrix44& a, const Matrix44& b)
|
| 673 |
+
{
|
| 674 |
+
for (int r = 0; r < 4; r++)
|
| 675 |
+
{
|
| 676 |
+
pDst[0*8 + r] = static_cast<jpgd_block_t>(a.at(r, 0) - b.at(r, 0));
|
| 677 |
+
pDst[1*8 + r] = static_cast<jpgd_block_t>(a.at(r, 1) - b.at(r, 1));
|
| 678 |
+
pDst[2*8 + r] = static_cast<jpgd_block_t>(a.at(r, 2) - b.at(r, 2));
|
| 679 |
+
pDst[3*8 + r] = static_cast<jpgd_block_t>(a.at(r, 3) - b.at(r, 3));
|
| 680 |
+
}
|
| 681 |
+
}
|
| 682 |
+
};
|
| 683 |
+
|
| 684 |
+
const int FRACT_BITS = 10;
|
| 685 |
+
const int SCALE = 1 << FRACT_BITS;
|
| 686 |
+
|
| 687 |
+
typedef int Temp_Type;
|
| 688 |
+
#define D(i) (((i) + (SCALE >> 1)) >> FRACT_BITS)
|
| 689 |
+
#define F(i) ((int)((i) * SCALE + .5f))
|
| 690 |
+
|
| 691 |
+
// Any decent C++ compiler will optimize this at compile time to a 0, or an array access.
|
| 692 |
+
#define AT(c, r) ((((c)>=NUM_COLS)||((r)>=NUM_ROWS)) ? 0 : pSrc[(c)+(r)*8])
|
| 693 |
+
|
| 694 |
+
// NUM_ROWS/NUM_COLS = # of non-zero rows/cols in input matrix
|
| 695 |
+
template<int NUM_ROWS, int NUM_COLS>
|
| 696 |
+
struct P_Q
|
| 697 |
+
{
|
| 698 |
+
static void calc(Matrix44& P, Matrix44& Q, const jpgd_block_t* pSrc)
|
| 699 |
+
{
|
| 700 |
+
// 4x8 = 4x8 times 8x8, matrix 0 is constant
|
| 701 |
+
const Temp_Type X000 = AT(0, 0);
|
| 702 |
+
const Temp_Type X001 = AT(0, 1);
|
| 703 |
+
const Temp_Type X002 = AT(0, 2);
|
| 704 |
+
const Temp_Type X003 = AT(0, 3);
|
| 705 |
+
const Temp_Type X004 = AT(0, 4);
|
| 706 |
+
const Temp_Type X005 = AT(0, 5);
|
| 707 |
+
const Temp_Type X006 = AT(0, 6);
|
| 708 |
+
const Temp_Type X007 = AT(0, 7);
|
| 709 |
+
const Temp_Type X010 = D(F(0.415735f) * AT(1, 0) + F(0.791065f) * AT(3, 0) + F(-0.352443f) * AT(5, 0) + F(0.277785f) * AT(7, 0));
|
| 710 |
+
const Temp_Type X011 = D(F(0.415735f) * AT(1, 1) + F(0.791065f) * AT(3, 1) + F(-0.352443f) * AT(5, 1) + F(0.277785f) * AT(7, 1));
|
| 711 |
+
const Temp_Type X012 = D(F(0.415735f) * AT(1, 2) + F(0.791065f) * AT(3, 2) + F(-0.352443f) * AT(5, 2) + F(0.277785f) * AT(7, 2));
|
| 712 |
+
const Temp_Type X013 = D(F(0.415735f) * AT(1, 3) + F(0.791065f) * AT(3, 3) + F(-0.352443f) * AT(5, 3) + F(0.277785f) * AT(7, 3));
|
| 713 |
+
const Temp_Type X014 = D(F(0.415735f) * AT(1, 4) + F(0.791065f) * AT(3, 4) + F(-0.352443f) * AT(5, 4) + F(0.277785f) * AT(7, 4));
|
| 714 |
+
const Temp_Type X015 = D(F(0.415735f) * AT(1, 5) + F(0.791065f) * AT(3, 5) + F(-0.352443f) * AT(5, 5) + F(0.277785f) * AT(7, 5));
|
| 715 |
+
const Temp_Type X016 = D(F(0.415735f) * AT(1, 6) + F(0.791065f) * AT(3, 6) + F(-0.352443f) * AT(5, 6) + F(0.277785f) * AT(7, 6));
|
| 716 |
+
const Temp_Type X017 = D(F(0.415735f) * AT(1, 7) + F(0.791065f) * AT(3, 7) + F(-0.352443f) * AT(5, 7) + F(0.277785f) * AT(7, 7));
|
| 717 |
+
const Temp_Type X020 = AT(4, 0);
|
| 718 |
+
const Temp_Type X021 = AT(4, 1);
|
| 719 |
+
const Temp_Type X022 = AT(4, 2);
|
| 720 |
+
const Temp_Type X023 = AT(4, 3);
|
| 721 |
+
const Temp_Type X024 = AT(4, 4);
|
| 722 |
+
const Temp_Type X025 = AT(4, 5);
|
| 723 |
+
const Temp_Type X026 = AT(4, 6);
|
| 724 |
+
const Temp_Type X027 = AT(4, 7);
|
| 725 |
+
const Temp_Type X030 = D(F(0.022887f) * AT(1, 0) + F(-0.097545f) * AT(3, 0) + F(0.490393f) * AT(5, 0) + F(0.865723f) * AT(7, 0));
|
| 726 |
+
const Temp_Type X031 = D(F(0.022887f) * AT(1, 1) + F(-0.097545f) * AT(3, 1) + F(0.490393f) * AT(5, 1) + F(0.865723f) * AT(7, 1));
|
| 727 |
+
const Temp_Type X032 = D(F(0.022887f) * AT(1, 2) + F(-0.097545f) * AT(3, 2) + F(0.490393f) * AT(5, 2) + F(0.865723f) * AT(7, 2));
|
| 728 |
+
const Temp_Type X033 = D(F(0.022887f) * AT(1, 3) + F(-0.097545f) * AT(3, 3) + F(0.490393f) * AT(5, 3) + F(0.865723f) * AT(7, 3));
|
| 729 |
+
const Temp_Type X034 = D(F(0.022887f) * AT(1, 4) + F(-0.097545f) * AT(3, 4) + F(0.490393f) * AT(5, 4) + F(0.865723f) * AT(7, 4));
|
| 730 |
+
const Temp_Type X035 = D(F(0.022887f) * AT(1, 5) + F(-0.097545f) * AT(3, 5) + F(0.490393f) * AT(5, 5) + F(0.865723f) * AT(7, 5));
|
| 731 |
+
const Temp_Type X036 = D(F(0.022887f) * AT(1, 6) + F(-0.097545f) * AT(3, 6) + F(0.490393f) * AT(5, 6) + F(0.865723f) * AT(7, 6));
|
| 732 |
+
const Temp_Type X037 = D(F(0.022887f) * AT(1, 7) + F(-0.097545f) * AT(3, 7) + F(0.490393f) * AT(5, 7) + F(0.865723f) * AT(7, 7));
|
| 733 |
+
|
| 734 |
+
// 4x4 = 4x8 times 8x4, matrix 1 is constant
|
| 735 |
+
P.at(0, 0) = X000;
|
| 736 |
+
P.at(0, 1) = D(X001 * F(0.415735f) + X003 * F(0.791065f) + X005 * F(-0.352443f) + X007 * F(0.277785f));
|
| 737 |
+
P.at(0, 2) = X004;
|
| 738 |
+
P.at(0, 3) = D(X001 * F(0.022887f) + X003 * F(-0.097545f) + X005 * F(0.490393f) + X007 * F(0.865723f));
|
| 739 |
+
P.at(1, 0) = X010;
|
| 740 |
+
P.at(1, 1) = D(X011 * F(0.415735f) + X013 * F(0.791065f) + X015 * F(-0.352443f) + X017 * F(0.277785f));
|
| 741 |
+
P.at(1, 2) = X014;
|
| 742 |
+
P.at(1, 3) = D(X011 * F(0.022887f) + X013 * F(-0.097545f) + X015 * F(0.490393f) + X017 * F(0.865723f));
|
| 743 |
+
P.at(2, 0) = X020;
|
| 744 |
+
P.at(2, 1) = D(X021 * F(0.415735f) + X023 * F(0.791065f) + X025 * F(-0.352443f) + X027 * F(0.277785f));
|
| 745 |
+
P.at(2, 2) = X024;
|
| 746 |
+
P.at(2, 3) = D(X021 * F(0.022887f) + X023 * F(-0.097545f) + X025 * F(0.490393f) + X027 * F(0.865723f));
|
| 747 |
+
P.at(3, 0) = X030;
|
| 748 |
+
P.at(3, 1) = D(X031 * F(0.415735f) + X033 * F(0.791065f) + X035 * F(-0.352443f) + X037 * F(0.277785f));
|
| 749 |
+
P.at(3, 2) = X034;
|
| 750 |
+
P.at(3, 3) = D(X031 * F(0.022887f) + X033 * F(-0.097545f) + X035 * F(0.490393f) + X037 * F(0.865723f));
|
| 751 |
+
// 40 muls 24 adds
|
| 752 |
+
|
| 753 |
+
// 4x4 = 4x8 times 8x4, matrix 1 is constant
|
| 754 |
+
Q.at(0, 0) = D(X001 * F(0.906127f) + X003 * F(-0.318190f) + X005 * F(0.212608f) + X007 * F(-0.180240f));
|
| 755 |
+
Q.at(0, 1) = X002;
|
| 756 |
+
Q.at(0, 2) = D(X001 * F(-0.074658f) + X003 * F(0.513280f) + X005 * F(0.768178f) + X007 * F(-0.375330f));
|
| 757 |
+
Q.at(0, 3) = X006;
|
| 758 |
+
Q.at(1, 0) = D(X011 * F(0.906127f) + X013 * F(-0.318190f) + X015 * F(0.212608f) + X017 * F(-0.180240f));
|
| 759 |
+
Q.at(1, 1) = X012;
|
| 760 |
+
Q.at(1, 2) = D(X011 * F(-0.074658f) + X013 * F(0.513280f) + X015 * F(0.768178f) + X017 * F(-0.375330f));
|
| 761 |
+
Q.at(1, 3) = X016;
|
| 762 |
+
Q.at(2, 0) = D(X021 * F(0.906127f) + X023 * F(-0.318190f) + X025 * F(0.212608f) + X027 * F(-0.180240f));
|
| 763 |
+
Q.at(2, 1) = X022;
|
| 764 |
+
Q.at(2, 2) = D(X021 * F(-0.074658f) + X023 * F(0.513280f) + X025 * F(0.768178f) + X027 * F(-0.375330f));
|
| 765 |
+
Q.at(2, 3) = X026;
|
| 766 |
+
Q.at(3, 0) = D(X031 * F(0.906127f) + X033 * F(-0.318190f) + X035 * F(0.212608f) + X037 * F(-0.180240f));
|
| 767 |
+
Q.at(3, 1) = X032;
|
| 768 |
+
Q.at(3, 2) = D(X031 * F(-0.074658f) + X033 * F(0.513280f) + X035 * F(0.768178f) + X037 * F(-0.375330f));
|
| 769 |
+
Q.at(3, 3) = X036;
|
| 770 |
+
// 40 muls 24 adds
|
| 771 |
+
}
|
| 772 |
+
};
|
| 773 |
+
|
| 774 |
+
template<int NUM_ROWS, int NUM_COLS>
|
| 775 |
+
struct R_S
|
| 776 |
+
{
|
| 777 |
+
static void calc(Matrix44& R, Matrix44& S, const jpgd_block_t* pSrc)
|
| 778 |
+
{
|
| 779 |
+
// 4x8 = 4x8 times 8x8, matrix 0 is constant
|
| 780 |
+
const Temp_Type X100 = D(F(0.906127f) * AT(1, 0) + F(-0.318190f) * AT(3, 0) + F(0.212608f) * AT(5, 0) + F(-0.180240f) * AT(7, 0));
|
| 781 |
+
const Temp_Type X101 = D(F(0.906127f) * AT(1, 1) + F(-0.318190f) * AT(3, 1) + F(0.212608f) * AT(5, 1) + F(-0.180240f) * AT(7, 1));
|
| 782 |
+
const Temp_Type X102 = D(F(0.906127f) * AT(1, 2) + F(-0.318190f) * AT(3, 2) + F(0.212608f) * AT(5, 2) + F(-0.180240f) * AT(7, 2));
|
| 783 |
+
const Temp_Type X103 = D(F(0.906127f) * AT(1, 3) + F(-0.318190f) * AT(3, 3) + F(0.212608f) * AT(5, 3) + F(-0.180240f) * AT(7, 3));
|
| 784 |
+
const Temp_Type X104 = D(F(0.906127f) * AT(1, 4) + F(-0.318190f) * AT(3, 4) + F(0.212608f) * AT(5, 4) + F(-0.180240f) * AT(7, 4));
|
| 785 |
+
const Temp_Type X105 = D(F(0.906127f) * AT(1, 5) + F(-0.318190f) * AT(3, 5) + F(0.212608f) * AT(5, 5) + F(-0.180240f) * AT(7, 5));
|
| 786 |
+
const Temp_Type X106 = D(F(0.906127f) * AT(1, 6) + F(-0.318190f) * AT(3, 6) + F(0.212608f) * AT(5, 6) + F(-0.180240f) * AT(7, 6));
|
| 787 |
+
const Temp_Type X107 = D(F(0.906127f) * AT(1, 7) + F(-0.318190f) * AT(3, 7) + F(0.212608f) * AT(5, 7) + F(-0.180240f) * AT(7, 7));
|
| 788 |
+
const Temp_Type X110 = AT(2, 0);
|
| 789 |
+
const Temp_Type X111 = AT(2, 1);
|
| 790 |
+
const Temp_Type X112 = AT(2, 2);
|
| 791 |
+
const Temp_Type X113 = AT(2, 3);
|
| 792 |
+
const Temp_Type X114 = AT(2, 4);
|
| 793 |
+
const Temp_Type X115 = AT(2, 5);
|
| 794 |
+
const Temp_Type X116 = AT(2, 6);
|
| 795 |
+
const Temp_Type X117 = AT(2, 7);
|
| 796 |
+
const Temp_Type X120 = D(F(-0.074658f) * AT(1, 0) + F(0.513280f) * AT(3, 0) + F(0.768178f) * AT(5, 0) + F(-0.375330f) * AT(7, 0));
|
| 797 |
+
const Temp_Type X121 = D(F(-0.074658f) * AT(1, 1) + F(0.513280f) * AT(3, 1) + F(0.768178f) * AT(5, 1) + F(-0.375330f) * AT(7, 1));
|
| 798 |
+
const Temp_Type X122 = D(F(-0.074658f) * AT(1, 2) + F(0.513280f) * AT(3, 2) + F(0.768178f) * AT(5, 2) + F(-0.375330f) * AT(7, 2));
|
| 799 |
+
const Temp_Type X123 = D(F(-0.074658f) * AT(1, 3) + F(0.513280f) * AT(3, 3) + F(0.768178f) * AT(5, 3) + F(-0.375330f) * AT(7, 3));
|
| 800 |
+
const Temp_Type X124 = D(F(-0.074658f) * AT(1, 4) + F(0.513280f) * AT(3, 4) + F(0.768178f) * AT(5, 4) + F(-0.375330f) * AT(7, 4));
|
| 801 |
+
const Temp_Type X125 = D(F(-0.074658f) * AT(1, 5) + F(0.513280f) * AT(3, 5) + F(0.768178f) * AT(5, 5) + F(-0.375330f) * AT(7, 5));
|
| 802 |
+
const Temp_Type X126 = D(F(-0.074658f) * AT(1, 6) + F(0.513280f) * AT(3, 6) + F(0.768178f) * AT(5, 6) + F(-0.375330f) * AT(7, 6));
|
| 803 |
+
const Temp_Type X127 = D(F(-0.074658f) * AT(1, 7) + F(0.513280f) * AT(3, 7) + F(0.768178f) * AT(5, 7) + F(-0.375330f) * AT(7, 7));
|
| 804 |
+
const Temp_Type X130 = AT(6, 0);
|
| 805 |
+
const Temp_Type X131 = AT(6, 1);
|
| 806 |
+
const Temp_Type X132 = AT(6, 2);
|
| 807 |
+
const Temp_Type X133 = AT(6, 3);
|
| 808 |
+
const Temp_Type X134 = AT(6, 4);
|
| 809 |
+
const Temp_Type X135 = AT(6, 5);
|
| 810 |
+
const Temp_Type X136 = AT(6, 6);
|
| 811 |
+
const Temp_Type X137 = AT(6, 7);
|
| 812 |
+
// 80 muls 48 adds
|
| 813 |
+
|
| 814 |
+
// 4x4 = 4x8 times 8x4, matrix 1 is constant
|
| 815 |
+
R.at(0, 0) = X100;
|
| 816 |
+
R.at(0, 1) = D(X101 * F(0.415735f) + X103 * F(0.791065f) + X105 * F(-0.352443f) + X107 * F(0.277785f));
|
| 817 |
+
R.at(0, 2) = X104;
|
| 818 |
+
R.at(0, 3) = D(X101 * F(0.022887f) + X103 * F(-0.097545f) + X105 * F(0.490393f) + X107 * F(0.865723f));
|
| 819 |
+
R.at(1, 0) = X110;
|
| 820 |
+
R.at(1, 1) = D(X111 * F(0.415735f) + X113 * F(0.791065f) + X115 * F(-0.352443f) + X117 * F(0.277785f));
|
| 821 |
+
R.at(1, 2) = X114;
|
| 822 |
+
R.at(1, 3) = D(X111 * F(0.022887f) + X113 * F(-0.097545f) + X115 * F(0.490393f) + X117 * F(0.865723f));
|
| 823 |
+
R.at(2, 0) = X120;
|
| 824 |
+
R.at(2, 1) = D(X121 * F(0.415735f) + X123 * F(0.791065f) + X125 * F(-0.352443f) + X127 * F(0.277785f));
|
| 825 |
+
R.at(2, 2) = X124;
|
| 826 |
+
R.at(2, 3) = D(X121 * F(0.022887f) + X123 * F(-0.097545f) + X125 * F(0.490393f) + X127 * F(0.865723f));
|
| 827 |
+
R.at(3, 0) = X130;
|
| 828 |
+
R.at(3, 1) = D(X131 * F(0.415735f) + X133 * F(0.791065f) + X135 * F(-0.352443f) + X137 * F(0.277785f));
|
| 829 |
+
R.at(3, 2) = X134;
|
| 830 |
+
R.at(3, 3) = D(X131 * F(0.022887f) + X133 * F(-0.097545f) + X135 * F(0.490393f) + X137 * F(0.865723f));
|
| 831 |
+
// 40 muls 24 adds
|
| 832 |
+
// 4x4 = 4x8 times 8x4, matrix 1 is constant
|
| 833 |
+
S.at(0, 0) = D(X101 * F(0.906127f) + X103 * F(-0.318190f) + X105 * F(0.212608f) + X107 * F(-0.180240f));
|
| 834 |
+
S.at(0, 1) = X102;
|
| 835 |
+
S.at(0, 2) = D(X101 * F(-0.074658f) + X103 * F(0.513280f) + X105 * F(0.768178f) + X107 * F(-0.375330f));
|
| 836 |
+
S.at(0, 3) = X106;
|
| 837 |
+
S.at(1, 0) = D(X111 * F(0.906127f) + X113 * F(-0.318190f) + X115 * F(0.212608f) + X117 * F(-0.180240f));
|
| 838 |
+
S.at(1, 1) = X112;
|
| 839 |
+
S.at(1, 2) = D(X111 * F(-0.074658f) + X113 * F(0.513280f) + X115 * F(0.768178f) + X117 * F(-0.375330f));
|
| 840 |
+
S.at(1, 3) = X116;
|
| 841 |
+
S.at(2, 0) = D(X121 * F(0.906127f) + X123 * F(-0.318190f) + X125 * F(0.212608f) + X127 * F(-0.180240f));
|
| 842 |
+
S.at(2, 1) = X122;
|
| 843 |
+
S.at(2, 2) = D(X121 * F(-0.074658f) + X123 * F(0.513280f) + X125 * F(0.768178f) + X127 * F(-0.375330f));
|
| 844 |
+
S.at(2, 3) = X126;
|
| 845 |
+
S.at(3, 0) = D(X131 * F(0.906127f) + X133 * F(-0.318190f) + X135 * F(0.212608f) + X137 * F(-0.180240f));
|
| 846 |
+
S.at(3, 1) = X132;
|
| 847 |
+
S.at(3, 2) = D(X131 * F(-0.074658f) + X133 * F(0.513280f) + X135 * F(0.768178f) + X137 * F(-0.375330f));
|
| 848 |
+
S.at(3, 3) = X136;
|
| 849 |
+
// 40 muls 24 adds
|
| 850 |
+
}
|
| 851 |
+
};
|
| 852 |
+
} // end namespace DCT_Upsample
|
| 853 |
+
|
| 854 |
+
// Unconditionally frees all allocated m_blocks.
|
| 855 |
+
void jpeg_decoder::free_all_blocks()
|
| 856 |
+
{
|
| 857 |
+
m_pStream = NULL;
|
| 858 |
+
for (mem_block *b = m_pMem_blocks; b; )
|
| 859 |
+
{
|
| 860 |
+
mem_block *n = b->m_pNext;
|
| 861 |
+
jpgd_free(b);
|
| 862 |
+
b = n;
|
| 863 |
+
}
|
| 864 |
+
m_pMem_blocks = NULL;
|
| 865 |
+
}
|
| 866 |
+
|
| 867 |
+
// This method handles all errors.
|
| 868 |
+
// It could easily be changed to use C++ exceptions.
|
| 869 |
+
void jpeg_decoder::stop_decoding(jpgd_status status)
|
| 870 |
+
{
|
| 871 |
+
m_error_code = status;
|
| 872 |
+
free_all_blocks();
|
| 873 |
+
longjmp(m_jmp_state, status);
|
| 874 |
+
|
| 875 |
+
// we shouldn't get here as longjmp shouldn't return, but we put it here to make it explicit
|
| 876 |
+
// that this function doesn't return, otherwise we get this error:
|
| 877 |
+
//
|
| 878 |
+
// error : function declared 'noreturn' should not return
|
| 879 |
+
exit(1);
|
| 880 |
+
}
|
| 881 |
+
|
| 882 |
+
void *jpeg_decoder::alloc(size_t nSize, bool zero)
|
| 883 |
+
{
|
| 884 |
+
nSize = (JPGD_MAX(nSize, 1) + 3) & ~3;
|
| 885 |
+
char *rv = NULL;
|
| 886 |
+
for (mem_block *b = m_pMem_blocks; b; b = b->m_pNext)
|
| 887 |
+
{
|
| 888 |
+
if ((b->m_used_count + nSize) <= b->m_size)
|
| 889 |
+
{
|
| 890 |
+
rv = b->m_data + b->m_used_count;
|
| 891 |
+
b->m_used_count += nSize;
|
| 892 |
+
break;
|
| 893 |
+
}
|
| 894 |
+
}
|
| 895 |
+
if (!rv)
|
| 896 |
+
{
|
| 897 |
+
int capacity = JPGD_MAX(32768 - 256, (nSize + 2047) & ~2047);
|
| 898 |
+
mem_block *b = (mem_block*)jpgd_malloc(sizeof(mem_block) + capacity);
|
| 899 |
+
if (!b) stop_decoding(JPGD_NOTENOUGHMEM);
|
| 900 |
+
b->m_pNext = m_pMem_blocks; m_pMem_blocks = b;
|
| 901 |
+
b->m_used_count = nSize;
|
| 902 |
+
b->m_size = capacity;
|
| 903 |
+
rv = b->m_data;
|
| 904 |
+
}
|
| 905 |
+
if (zero) memset(rv, 0, nSize);
|
| 906 |
+
return rv;
|
| 907 |
+
}
|
| 908 |
+
|
| 909 |
+
void jpeg_decoder::word_clear(void *p, uint16 c, uint n)
|
| 910 |
+
{
|
| 911 |
+
uint8 *pD = (uint8*)p;
|
| 912 |
+
const uint8 l = c & 0xFF, h = (c >> 8) & 0xFF;
|
| 913 |
+
while (n)
|
| 914 |
+
{
|
| 915 |
+
pD[0] = l; pD[1] = h; pD += 2;
|
| 916 |
+
n--;
|
| 917 |
+
}
|
| 918 |
+
}
|
| 919 |
+
|
| 920 |
+
// Refill the input buffer.
|
| 921 |
+
// This method will sit in a loop until (A) the buffer is full or (B)
|
| 922 |
+
// the stream's read() method reports and end of file condition.
|
| 923 |
+
void jpeg_decoder::prep_in_buffer()
|
| 924 |
+
{
|
| 925 |
+
m_in_buf_left = 0;
|
| 926 |
+
m_pIn_buf_ofs = m_in_buf;
|
| 927 |
+
|
| 928 |
+
if (m_eof_flag)
|
| 929 |
+
return;
|
| 930 |
+
|
| 931 |
+
do
|
| 932 |
+
{
|
| 933 |
+
int bytes_read = m_pStream->read(m_in_buf + m_in_buf_left, JPGD_IN_BUF_SIZE - m_in_buf_left, &m_eof_flag);
|
| 934 |
+
if (bytes_read == -1)
|
| 935 |
+
stop_decoding(JPGD_STREAM_READ);
|
| 936 |
+
|
| 937 |
+
m_in_buf_left += bytes_read;
|
| 938 |
+
} while ((m_in_buf_left < JPGD_IN_BUF_SIZE) && (!m_eof_flag));
|
| 939 |
+
|
| 940 |
+
m_total_bytes_read += m_in_buf_left;
|
| 941 |
+
|
| 942 |
+
// Pad the end of the block with M_EOI (prevents the decompressor from going off the rails if the stream is invalid).
|
| 943 |
+
// (This dates way back to when this decompressor was written in C/asm, and the all-asm Huffman decoder did some fancy things to increase perf.)
|
| 944 |
+
word_clear(m_pIn_buf_ofs + m_in_buf_left, 0xD9FF, 64);
|
| 945 |
+
}
|
| 946 |
+
|
| 947 |
+
// Read a Huffman code table.
|
| 948 |
+
void jpeg_decoder::read_dht_marker()
|
| 949 |
+
{
|
| 950 |
+
int i, index, count;
|
| 951 |
+
uint8 huff_num[17];
|
| 952 |
+
uint8 huff_val[256];
|
| 953 |
+
|
| 954 |
+
uint num_left = get_bits(16);
|
| 955 |
+
|
| 956 |
+
if (num_left < 2)
|
| 957 |
+
stop_decoding(JPGD_BAD_DHT_MARKER);
|
| 958 |
+
|
| 959 |
+
num_left -= 2;
|
| 960 |
+
|
| 961 |
+
while (num_left)
|
| 962 |
+
{
|
| 963 |
+
index = get_bits(8);
|
| 964 |
+
|
| 965 |
+
huff_num[0] = 0;
|
| 966 |
+
|
| 967 |
+
count = 0;
|
| 968 |
+
|
| 969 |
+
for (i = 1; i <= 16; i++)
|
| 970 |
+
{
|
| 971 |
+
huff_num[i] = static_cast<uint8>(get_bits(8));
|
| 972 |
+
count += huff_num[i];
|
| 973 |
+
}
|
| 974 |
+
|
| 975 |
+
if (count > 255)
|
| 976 |
+
stop_decoding(JPGD_BAD_DHT_COUNTS);
|
| 977 |
+
|
| 978 |
+
for (i = 0; i < count; i++)
|
| 979 |
+
huff_val[i] = static_cast<uint8>(get_bits(8));
|
| 980 |
+
|
| 981 |
+
i = 1 + 16 + count;
|
| 982 |
+
|
| 983 |
+
if (num_left < (uint)i)
|
| 984 |
+
stop_decoding(JPGD_BAD_DHT_MARKER);
|
| 985 |
+
|
| 986 |
+
num_left -= i;
|
| 987 |
+
|
| 988 |
+
if ((index & 0x10) > 0x10)
|
| 989 |
+
stop_decoding(JPGD_BAD_DHT_INDEX);
|
| 990 |
+
|
| 991 |
+
index = (index & 0x0F) + ((index & 0x10) >> 4) * (JPGD_MAX_HUFF_TABLES >> 1);
|
| 992 |
+
|
| 993 |
+
if (index >= JPGD_MAX_HUFF_TABLES)
|
| 994 |
+
stop_decoding(JPGD_BAD_DHT_INDEX);
|
| 995 |
+
|
| 996 |
+
if (!m_huff_num[index])
|
| 997 |
+
m_huff_num[index] = (uint8 *)alloc(17);
|
| 998 |
+
|
| 999 |
+
if (!m_huff_val[index])
|
| 1000 |
+
m_huff_val[index] = (uint8 *)alloc(256);
|
| 1001 |
+
|
| 1002 |
+
m_huff_ac[index] = (index & 0x10) != 0;
|
| 1003 |
+
memcpy(m_huff_num[index], huff_num, 17);
|
| 1004 |
+
memcpy(m_huff_val[index], huff_val, 256);
|
| 1005 |
+
}
|
| 1006 |
+
}
|
| 1007 |
+
|
| 1008 |
+
// Read a quantization table.
|
| 1009 |
+
void jpeg_decoder::read_dqt_marker()
|
| 1010 |
+
{
|
| 1011 |
+
int n, i, prec;
|
| 1012 |
+
uint num_left;
|
| 1013 |
+
uint temp;
|
| 1014 |
+
|
| 1015 |
+
num_left = get_bits(16);
|
| 1016 |
+
|
| 1017 |
+
if (num_left < 2)
|
| 1018 |
+
stop_decoding(JPGD_BAD_DQT_MARKER);
|
| 1019 |
+
|
| 1020 |
+
num_left -= 2;
|
| 1021 |
+
|
| 1022 |
+
while (num_left)
|
| 1023 |
+
{
|
| 1024 |
+
n = get_bits(8);
|
| 1025 |
+
prec = n >> 4;
|
| 1026 |
+
n &= 0x0F;
|
| 1027 |
+
|
| 1028 |
+
if (n >= JPGD_MAX_QUANT_TABLES)
|
| 1029 |
+
stop_decoding(JPGD_BAD_DQT_TABLE);
|
| 1030 |
+
|
| 1031 |
+
if (!m_quant[n])
|
| 1032 |
+
m_quant[n] = (jpgd_quant_t *)alloc(64 * sizeof(jpgd_quant_t));
|
| 1033 |
+
|
| 1034 |
+
// read quantization entries, in zag order
|
| 1035 |
+
for (i = 0; i < 64; i++)
|
| 1036 |
+
{
|
| 1037 |
+
temp = get_bits(8);
|
| 1038 |
+
|
| 1039 |
+
if (prec)
|
| 1040 |
+
temp = (temp << 8) + get_bits(8);
|
| 1041 |
+
|
| 1042 |
+
m_quant[n][i] = static_cast<jpgd_quant_t>(temp);
|
| 1043 |
+
}
|
| 1044 |
+
|
| 1045 |
+
i = 64 + 1;
|
| 1046 |
+
|
| 1047 |
+
if (prec)
|
| 1048 |
+
i += 64;
|
| 1049 |
+
|
| 1050 |
+
if (num_left < (uint)i)
|
| 1051 |
+
stop_decoding(JPGD_BAD_DQT_LENGTH);
|
| 1052 |
+
|
| 1053 |
+
num_left -= i;
|
| 1054 |
+
}
|
| 1055 |
+
}
|
| 1056 |
+
|
| 1057 |
+
// Read the start of frame (SOF) marker.
|
| 1058 |
+
void jpeg_decoder::read_sof_marker()
|
| 1059 |
+
{
|
| 1060 |
+
int i;
|
| 1061 |
+
uint num_left;
|
| 1062 |
+
|
| 1063 |
+
num_left = get_bits(16);
|
| 1064 |
+
|
| 1065 |
+
if (get_bits(8) != 8) /* precision: sorry, only 8-bit precision is supported right now */
|
| 1066 |
+
stop_decoding(JPGD_BAD_PRECISION);
|
| 1067 |
+
|
| 1068 |
+
m_image_y_size = get_bits(16);
|
| 1069 |
+
|
| 1070 |
+
if ((m_image_y_size < 1) || (m_image_y_size > JPGD_MAX_HEIGHT))
|
| 1071 |
+
stop_decoding(JPGD_BAD_HEIGHT);
|
| 1072 |
+
|
| 1073 |
+
m_image_x_size = get_bits(16);
|
| 1074 |
+
|
| 1075 |
+
if ((m_image_x_size < 1) || (m_image_x_size > JPGD_MAX_WIDTH))
|
| 1076 |
+
stop_decoding(JPGD_BAD_WIDTH);
|
| 1077 |
+
|
| 1078 |
+
m_comps_in_frame = get_bits(8);
|
| 1079 |
+
|
| 1080 |
+
if (m_comps_in_frame > JPGD_MAX_COMPONENTS)
|
| 1081 |
+
stop_decoding(JPGD_TOO_MANY_COMPONENTS);
|
| 1082 |
+
|
| 1083 |
+
if (num_left != (uint)(m_comps_in_frame * 3 + 8))
|
| 1084 |
+
stop_decoding(JPGD_BAD_SOF_LENGTH);
|
| 1085 |
+
|
| 1086 |
+
for (i = 0; i < m_comps_in_frame; i++)
|
| 1087 |
+
{
|
| 1088 |
+
m_comp_ident[i] = get_bits(8);
|
| 1089 |
+
m_comp_h_samp[i] = get_bits(4);
|
| 1090 |
+
m_comp_v_samp[i] = get_bits(4);
|
| 1091 |
+
m_comp_quant[i] = get_bits(8);
|
| 1092 |
+
}
|
| 1093 |
+
}
|
| 1094 |
+
|
| 1095 |
+
// Used to skip unrecognized markers.
|
| 1096 |
+
void jpeg_decoder::skip_variable_marker()
|
| 1097 |
+
{
|
| 1098 |
+
uint num_left;
|
| 1099 |
+
|
| 1100 |
+
num_left = get_bits(16);
|
| 1101 |
+
|
| 1102 |
+
if (num_left < 2)
|
| 1103 |
+
stop_decoding(JPGD_BAD_VARIABLE_MARKER);
|
| 1104 |
+
|
| 1105 |
+
num_left -= 2;
|
| 1106 |
+
|
| 1107 |
+
while (num_left)
|
| 1108 |
+
{
|
| 1109 |
+
get_bits(8);
|
| 1110 |
+
num_left--;
|
| 1111 |
+
}
|
| 1112 |
+
}
|
| 1113 |
+
|
| 1114 |
+
// Read a define restart interval (DRI) marker.
|
| 1115 |
+
void jpeg_decoder::read_dri_marker()
|
| 1116 |
+
{
|
| 1117 |
+
if (get_bits(16) != 4)
|
| 1118 |
+
stop_decoding(JPGD_BAD_DRI_LENGTH);
|
| 1119 |
+
|
| 1120 |
+
m_restart_interval = get_bits(16);
|
| 1121 |
+
}
|
| 1122 |
+
|
| 1123 |
+
// Read a start of scan (SOS) marker.
|
| 1124 |
+
void jpeg_decoder::read_sos_marker()
|
| 1125 |
+
{
|
| 1126 |
+
uint num_left;
|
| 1127 |
+
int i, ci, n, c, cc;
|
| 1128 |
+
|
| 1129 |
+
num_left = get_bits(16);
|
| 1130 |
+
|
| 1131 |
+
n = get_bits(8);
|
| 1132 |
+
|
| 1133 |
+
m_comps_in_scan = n;
|
| 1134 |
+
|
| 1135 |
+
num_left -= 3;
|
| 1136 |
+
|
| 1137 |
+
if ( (num_left != (uint)(n * 2 + 3)) || (n < 1) || (n > JPGD_MAX_COMPS_IN_SCAN) )
|
| 1138 |
+
stop_decoding(JPGD_BAD_SOS_LENGTH);
|
| 1139 |
+
|
| 1140 |
+
for (i = 0; i < n; i++)
|
| 1141 |
+
{
|
| 1142 |
+
cc = get_bits(8);
|
| 1143 |
+
c = get_bits(8);
|
| 1144 |
+
num_left -= 2;
|
| 1145 |
+
|
| 1146 |
+
for (ci = 0; ci < m_comps_in_frame; ci++)
|
| 1147 |
+
if (cc == m_comp_ident[ci])
|
| 1148 |
+
break;
|
| 1149 |
+
|
| 1150 |
+
if (ci >= m_comps_in_frame)
|
| 1151 |
+
stop_decoding(JPGD_BAD_SOS_COMP_ID);
|
| 1152 |
+
|
| 1153 |
+
m_comp_list[i] = ci;
|
| 1154 |
+
m_comp_dc_tab[ci] = (c >> 4) & 15;
|
| 1155 |
+
m_comp_ac_tab[ci] = (c & 15) + (JPGD_MAX_HUFF_TABLES >> 1);
|
| 1156 |
+
}
|
| 1157 |
+
|
| 1158 |
+
m_spectral_start = get_bits(8);
|
| 1159 |
+
m_spectral_end = get_bits(8);
|
| 1160 |
+
m_successive_high = get_bits(4);
|
| 1161 |
+
m_successive_low = get_bits(4);
|
| 1162 |
+
|
| 1163 |
+
if (!m_progressive_flag)
|
| 1164 |
+
{
|
| 1165 |
+
m_spectral_start = 0;
|
| 1166 |
+
m_spectral_end = 63;
|
| 1167 |
+
}
|
| 1168 |
+
|
| 1169 |
+
num_left -= 3;
|
| 1170 |
+
|
| 1171 |
+
while (num_left) /* read past whatever is num_left */
|
| 1172 |
+
{
|
| 1173 |
+
get_bits(8);
|
| 1174 |
+
num_left--;
|
| 1175 |
+
}
|
| 1176 |
+
}
|
| 1177 |
+
|
| 1178 |
+
// Finds the next marker.
|
| 1179 |
+
int jpeg_decoder::next_marker()
|
| 1180 |
+
{
|
| 1181 |
+
uint c, bytes;
|
| 1182 |
+
|
| 1183 |
+
bytes = 0;
|
| 1184 |
+
|
| 1185 |
+
do
|
| 1186 |
+
{
|
| 1187 |
+
do
|
| 1188 |
+
{
|
| 1189 |
+
bytes++;
|
| 1190 |
+
c = get_bits(8);
|
| 1191 |
+
} while (c != 0xFF);
|
| 1192 |
+
|
| 1193 |
+
do
|
| 1194 |
+
{
|
| 1195 |
+
c = get_bits(8);
|
| 1196 |
+
} while (c == 0xFF);
|
| 1197 |
+
|
| 1198 |
+
} while (c == 0);
|
| 1199 |
+
|
| 1200 |
+
// If bytes > 0 here, there where extra bytes before the marker (not good).
|
| 1201 |
+
|
| 1202 |
+
return c;
|
| 1203 |
+
}
|
| 1204 |
+
|
| 1205 |
+
// Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is
|
| 1206 |
+
// encountered.
|
| 1207 |
+
int jpeg_decoder::process_markers()
|
| 1208 |
+
{
|
| 1209 |
+
int c;
|
| 1210 |
+
|
| 1211 |
+
for ( ; ; )
|
| 1212 |
+
{
|
| 1213 |
+
c = next_marker();
|
| 1214 |
+
|
| 1215 |
+
switch (c)
|
| 1216 |
+
{
|
| 1217 |
+
case M_SOF0:
|
| 1218 |
+
case M_SOF1:
|
| 1219 |
+
case M_SOF2:
|
| 1220 |
+
case M_SOF3:
|
| 1221 |
+
case M_SOF5:
|
| 1222 |
+
case M_SOF6:
|
| 1223 |
+
case M_SOF7:
|
| 1224 |
+
// case M_JPG:
|
| 1225 |
+
case M_SOF9:
|
| 1226 |
+
case M_SOF10:
|
| 1227 |
+
case M_SOF11:
|
| 1228 |
+
case M_SOF13:
|
| 1229 |
+
case M_SOF14:
|
| 1230 |
+
case M_SOF15:
|
| 1231 |
+
case M_SOI:
|
| 1232 |
+
case M_EOI:
|
| 1233 |
+
case M_SOS:
|
| 1234 |
+
{
|
| 1235 |
+
return c;
|
| 1236 |
+
}
|
| 1237 |
+
case M_DHT:
|
| 1238 |
+
{
|
| 1239 |
+
read_dht_marker();
|
| 1240 |
+
break;
|
| 1241 |
+
}
|
| 1242 |
+
// No arithmitic support - dumb patents!
|
| 1243 |
+
case M_DAC:
|
| 1244 |
+
{
|
| 1245 |
+
stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT);
|
| 1246 |
+
break;
|
| 1247 |
+
}
|
| 1248 |
+
case M_DQT:
|
| 1249 |
+
{
|
| 1250 |
+
read_dqt_marker();
|
| 1251 |
+
break;
|
| 1252 |
+
}
|
| 1253 |
+
case M_DRI:
|
| 1254 |
+
{
|
| 1255 |
+
read_dri_marker();
|
| 1256 |
+
break;
|
| 1257 |
+
}
|
| 1258 |
+
//case M_APP0: /* no need to read the JFIF marker */
|
| 1259 |
+
|
| 1260 |
+
case M_JPG:
|
| 1261 |
+
case M_RST0: /* no parameters */
|
| 1262 |
+
case M_RST1:
|
| 1263 |
+
case M_RST2:
|
| 1264 |
+
case M_RST3:
|
| 1265 |
+
case M_RST4:
|
| 1266 |
+
case M_RST5:
|
| 1267 |
+
case M_RST6:
|
| 1268 |
+
case M_RST7:
|
| 1269 |
+
case M_TEM:
|
| 1270 |
+
{
|
| 1271 |
+
stop_decoding(JPGD_UNEXPECTED_MARKER);
|
| 1272 |
+
break;
|
| 1273 |
+
}
|
| 1274 |
+
default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */
|
| 1275 |
+
{
|
| 1276 |
+
skip_variable_marker();
|
| 1277 |
+
break;
|
| 1278 |
+
}
|
| 1279 |
+
}
|
| 1280 |
+
}
|
| 1281 |
+
}
|
| 1282 |
+
|
| 1283 |
+
// Finds the start of image (SOI) marker.
|
| 1284 |
+
// This code is rather defensive: it only checks the first 512 bytes to avoid
|
| 1285 |
+
// false positives.
|
| 1286 |
+
void jpeg_decoder::locate_soi_marker()
|
| 1287 |
+
{
|
| 1288 |
+
uint lastchar, thischar;
|
| 1289 |
+
uint bytesleft;
|
| 1290 |
+
|
| 1291 |
+
lastchar = get_bits(8);
|
| 1292 |
+
|
| 1293 |
+
thischar = get_bits(8);
|
| 1294 |
+
|
| 1295 |
+
/* ok if it's a normal JPEG file without a special header */
|
| 1296 |
+
|
| 1297 |
+
if ((lastchar == 0xFF) && (thischar == M_SOI))
|
| 1298 |
+
return;
|
| 1299 |
+
|
| 1300 |
+
bytesleft = 4096; //512;
|
| 1301 |
+
|
| 1302 |
+
for ( ; ; )
|
| 1303 |
+
{
|
| 1304 |
+
if (--bytesleft == 0)
|
| 1305 |
+
stop_decoding(JPGD_NOT_JPEG);
|
| 1306 |
+
|
| 1307 |
+
lastchar = thischar;
|
| 1308 |
+
|
| 1309 |
+
thischar = get_bits(8);
|
| 1310 |
+
|
| 1311 |
+
if (lastchar == 0xFF)
|
| 1312 |
+
{
|
| 1313 |
+
if (thischar == M_SOI)
|
| 1314 |
+
break;
|
| 1315 |
+
else if (thischar == M_EOI) // get_bits will keep returning M_EOI if we read past the end
|
| 1316 |
+
stop_decoding(JPGD_NOT_JPEG);
|
| 1317 |
+
}
|
| 1318 |
+
}
|
| 1319 |
+
|
| 1320 |
+
// Check the next character after marker: if it's not 0xFF, it can't be the start of the next marker, so the file is bad.
|
| 1321 |
+
thischar = (m_bit_buf >> 24) & 0xFF;
|
| 1322 |
+
|
| 1323 |
+
if (thischar != 0xFF)
|
| 1324 |
+
stop_decoding(JPGD_NOT_JPEG);
|
| 1325 |
+
}
|
| 1326 |
+
|
| 1327 |
+
// Find a start of frame (SOF) marker.
|
| 1328 |
+
void jpeg_decoder::locate_sof_marker()
|
| 1329 |
+
{
|
| 1330 |
+
locate_soi_marker();
|
| 1331 |
+
|
| 1332 |
+
int c = process_markers();
|
| 1333 |
+
|
| 1334 |
+
switch (c)
|
| 1335 |
+
{
|
| 1336 |
+
case M_SOF2:
|
| 1337 |
+
m_progressive_flag = JPGD_TRUE;
|
| 1338 |
+
case M_SOF0: /* baseline DCT */
|
| 1339 |
+
case M_SOF1: /* extended sequential DCT */
|
| 1340 |
+
{
|
| 1341 |
+
read_sof_marker();
|
| 1342 |
+
break;
|
| 1343 |
+
}
|
| 1344 |
+
case M_SOF9: /* Arithmitic coding */
|
| 1345 |
+
{
|
| 1346 |
+
stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT);
|
| 1347 |
+
break;
|
| 1348 |
+
}
|
| 1349 |
+
default:
|
| 1350 |
+
{
|
| 1351 |
+
stop_decoding(JPGD_UNSUPPORTED_MARKER);
|
| 1352 |
+
break;
|
| 1353 |
+
}
|
| 1354 |
+
}
|
| 1355 |
+
}
|
| 1356 |
+
|
| 1357 |
+
// Find a start of scan (SOS) marker.
|
| 1358 |
+
int jpeg_decoder::locate_sos_marker()
|
| 1359 |
+
{
|
| 1360 |
+
int c;
|
| 1361 |
+
|
| 1362 |
+
c = process_markers();
|
| 1363 |
+
|
| 1364 |
+
if (c == M_EOI)
|
| 1365 |
+
return JPGD_FALSE;
|
| 1366 |
+
else if (c != M_SOS)
|
| 1367 |
+
stop_decoding(JPGD_UNEXPECTED_MARKER);
|
| 1368 |
+
|
| 1369 |
+
read_sos_marker();
|
| 1370 |
+
|
| 1371 |
+
return JPGD_TRUE;
|
| 1372 |
+
}
|
| 1373 |
+
|
| 1374 |
+
// Reset everything to default/uninitialized state.
|
| 1375 |
+
void jpeg_decoder::init(jpeg_decoder_stream *pStream)
|
| 1376 |
+
{
|
| 1377 |
+
m_pMem_blocks = NULL;
|
| 1378 |
+
m_error_code = JPGD_SUCCESS;
|
| 1379 |
+
m_ready_flag = false;
|
| 1380 |
+
m_image_x_size = m_image_y_size = 0;
|
| 1381 |
+
m_pStream = pStream;
|
| 1382 |
+
m_progressive_flag = JPGD_FALSE;
|
| 1383 |
+
|
| 1384 |
+
memset(m_huff_ac, 0, sizeof(m_huff_ac));
|
| 1385 |
+
memset(m_huff_num, 0, sizeof(m_huff_num));
|
| 1386 |
+
memset(m_huff_val, 0, sizeof(m_huff_val));
|
| 1387 |
+
memset(m_quant, 0, sizeof(m_quant));
|
| 1388 |
+
|
| 1389 |
+
m_scan_type = 0;
|
| 1390 |
+
m_comps_in_frame = 0;
|
| 1391 |
+
|
| 1392 |
+
memset(m_comp_h_samp, 0, sizeof(m_comp_h_samp));
|
| 1393 |
+
memset(m_comp_v_samp, 0, sizeof(m_comp_v_samp));
|
| 1394 |
+
memset(m_comp_quant, 0, sizeof(m_comp_quant));
|
| 1395 |
+
memset(m_comp_ident, 0, sizeof(m_comp_ident));
|
| 1396 |
+
memset(m_comp_h_blocks, 0, sizeof(m_comp_h_blocks));
|
| 1397 |
+
memset(m_comp_v_blocks, 0, sizeof(m_comp_v_blocks));
|
| 1398 |
+
|
| 1399 |
+
m_comps_in_scan = 0;
|
| 1400 |
+
memset(m_comp_list, 0, sizeof(m_comp_list));
|
| 1401 |
+
memset(m_comp_dc_tab, 0, sizeof(m_comp_dc_tab));
|
| 1402 |
+
memset(m_comp_ac_tab, 0, sizeof(m_comp_ac_tab));
|
| 1403 |
+
|
| 1404 |
+
m_spectral_start = 0;
|
| 1405 |
+
m_spectral_end = 0;
|
| 1406 |
+
m_successive_low = 0;
|
| 1407 |
+
m_successive_high = 0;
|
| 1408 |
+
m_max_mcu_x_size = 0;
|
| 1409 |
+
m_max_mcu_y_size = 0;
|
| 1410 |
+
m_blocks_per_mcu = 0;
|
| 1411 |
+
m_max_blocks_per_row = 0;
|
| 1412 |
+
m_mcus_per_row = 0;
|
| 1413 |
+
m_mcus_per_col = 0;
|
| 1414 |
+
m_expanded_blocks_per_component = 0;
|
| 1415 |
+
m_expanded_blocks_per_mcu = 0;
|
| 1416 |
+
m_expanded_blocks_per_row = 0;
|
| 1417 |
+
m_freq_domain_chroma_upsample = false;
|
| 1418 |
+
|
| 1419 |
+
memset(m_mcu_org, 0, sizeof(m_mcu_org));
|
| 1420 |
+
|
| 1421 |
+
m_total_lines_left = 0;
|
| 1422 |
+
m_mcu_lines_left = 0;
|
| 1423 |
+
m_real_dest_bytes_per_scan_line = 0;
|
| 1424 |
+
m_dest_bytes_per_scan_line = 0;
|
| 1425 |
+
m_dest_bytes_per_pixel = 0;
|
| 1426 |
+
|
| 1427 |
+
memset(m_pHuff_tabs, 0, sizeof(m_pHuff_tabs));
|
| 1428 |
+
|
| 1429 |
+
memset(m_dc_coeffs, 0, sizeof(m_dc_coeffs));
|
| 1430 |
+
memset(m_ac_coeffs, 0, sizeof(m_ac_coeffs));
|
| 1431 |
+
memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu));
|
| 1432 |
+
|
| 1433 |
+
m_eob_run = 0;
|
| 1434 |
+
|
| 1435 |
+
memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu));
|
| 1436 |
+
|
| 1437 |
+
m_pIn_buf_ofs = m_in_buf;
|
| 1438 |
+
m_in_buf_left = 0;
|
| 1439 |
+
m_eof_flag = false;
|
| 1440 |
+
m_tem_flag = 0;
|
| 1441 |
+
|
| 1442 |
+
memset(m_in_buf_pad_start, 0, sizeof(m_in_buf_pad_start));
|
| 1443 |
+
memset(m_in_buf, 0, sizeof(m_in_buf));
|
| 1444 |
+
memset(m_in_buf_pad_end, 0, sizeof(m_in_buf_pad_end));
|
| 1445 |
+
|
| 1446 |
+
m_restart_interval = 0;
|
| 1447 |
+
m_restarts_left = 0;
|
| 1448 |
+
m_next_restart_num = 0;
|
| 1449 |
+
|
| 1450 |
+
m_max_mcus_per_row = 0;
|
| 1451 |
+
m_max_blocks_per_mcu = 0;
|
| 1452 |
+
m_max_mcus_per_col = 0;
|
| 1453 |
+
|
| 1454 |
+
memset(m_last_dc_val, 0, sizeof(m_last_dc_val));
|
| 1455 |
+
m_pMCU_coefficients = NULL;
|
| 1456 |
+
m_pSample_buf = NULL;
|
| 1457 |
+
|
| 1458 |
+
m_total_bytes_read = 0;
|
| 1459 |
+
|
| 1460 |
+
m_pScan_line_0 = NULL;
|
| 1461 |
+
m_pScan_line_1 = NULL;
|
| 1462 |
+
|
| 1463 |
+
// Ready the input buffer.
|
| 1464 |
+
prep_in_buffer();
|
| 1465 |
+
|
| 1466 |
+
// Prime the bit buffer.
|
| 1467 |
+
m_bits_left = 16;
|
| 1468 |
+
m_bit_buf = 0;
|
| 1469 |
+
|
| 1470 |
+
get_bits(16);
|
| 1471 |
+
get_bits(16);
|
| 1472 |
+
|
| 1473 |
+
for (int i = 0; i < JPGD_MAX_BLOCKS_PER_MCU; i++)
|
| 1474 |
+
m_mcu_block_max_zag[i] = 64;
|
| 1475 |
+
}
|
| 1476 |
+
|
| 1477 |
+
#define SCALEBITS 16
|
| 1478 |
+
#define ONE_HALF ((int) 1 << (SCALEBITS-1))
|
| 1479 |
+
#define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5f))
|
| 1480 |
+
|
| 1481 |
+
// Create a few tables that allow us to quickly convert YCbCr to RGB.
|
| 1482 |
+
void jpeg_decoder::create_look_ups()
|
| 1483 |
+
{
|
| 1484 |
+
for (int i = 0; i <= 255; i++)
|
| 1485 |
+
{
|
| 1486 |
+
int k = i - 128;
|
| 1487 |
+
m_crr[i] = ( FIX(1.40200f) * k + ONE_HALF) >> SCALEBITS;
|
| 1488 |
+
m_cbb[i] = ( FIX(1.77200f) * k + ONE_HALF) >> SCALEBITS;
|
| 1489 |
+
m_crg[i] = (-FIX(0.71414f)) * k;
|
| 1490 |
+
m_cbg[i] = (-FIX(0.34414f)) * k + ONE_HALF;
|
| 1491 |
+
}
|
| 1492 |
+
}
|
| 1493 |
+
|
| 1494 |
+
// This method throws back into the stream any bytes that where read
|
| 1495 |
+
// into the bit buffer during initial marker scanning.
|
| 1496 |
+
void jpeg_decoder::fix_in_buffer()
|
| 1497 |
+
{
|
| 1498 |
+
// In case any 0xFF's where pulled into the buffer during marker scanning.
|
| 1499 |
+
JPGD_ASSERT((m_bits_left & 7) == 0);
|
| 1500 |
+
|
| 1501 |
+
if (m_bits_left == 16)
|
| 1502 |
+
stuff_char( (uint8)(m_bit_buf & 0xFF));
|
| 1503 |
+
|
| 1504 |
+
if (m_bits_left >= 8)
|
| 1505 |
+
stuff_char( (uint8)((m_bit_buf >> 8) & 0xFF));
|
| 1506 |
+
|
| 1507 |
+
stuff_char((uint8)((m_bit_buf >> 16) & 0xFF));
|
| 1508 |
+
stuff_char((uint8)((m_bit_buf >> 24) & 0xFF));
|
| 1509 |
+
|
| 1510 |
+
m_bits_left = 16;
|
| 1511 |
+
get_bits_no_markers(16);
|
| 1512 |
+
get_bits_no_markers(16);
|
| 1513 |
+
}
|
| 1514 |
+
|
| 1515 |
+
void jpeg_decoder::transform_mcu(int mcu_row)
|
| 1516 |
+
{
|
| 1517 |
+
jpgd_block_t* pSrc_ptr = m_pMCU_coefficients;
|
| 1518 |
+
uint8* pDst_ptr = m_pSample_buf + mcu_row * m_blocks_per_mcu * 64;
|
| 1519 |
+
|
| 1520 |
+
for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
|
| 1521 |
+
{
|
| 1522 |
+
idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block]);
|
| 1523 |
+
pSrc_ptr += 64;
|
| 1524 |
+
pDst_ptr += 64;
|
| 1525 |
+
}
|
| 1526 |
+
}
|
| 1527 |
+
|
| 1528 |
+
static const uint8 s_max_rc[64] =
|
| 1529 |
+
{
|
| 1530 |
+
17, 18, 34, 50, 50, 51, 52, 52, 52, 68, 84, 84, 84, 84, 85, 86, 86, 86, 86, 86,
|
| 1531 |
+
102, 118, 118, 118, 118, 118, 118, 119, 120, 120, 120, 120, 120, 120, 120, 136,
|
| 1532 |
+
136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
|
| 1533 |
+
136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136
|
| 1534 |
+
};
|
| 1535 |
+
|
| 1536 |
+
void jpeg_decoder::transform_mcu_expand(int mcu_row)
|
| 1537 |
+
{
|
| 1538 |
+
jpgd_block_t* pSrc_ptr = m_pMCU_coefficients;
|
| 1539 |
+
uint8* pDst_ptr = m_pSample_buf + mcu_row * m_expanded_blocks_per_mcu * 64;
|
| 1540 |
+
|
| 1541 |
+
// Y IDCT
|
| 1542 |
+
int mcu_block;
|
| 1543 |
+
for (mcu_block = 0; mcu_block < m_expanded_blocks_per_component; mcu_block++)
|
| 1544 |
+
{
|
| 1545 |
+
idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block]);
|
| 1546 |
+
pSrc_ptr += 64;
|
| 1547 |
+
pDst_ptr += 64;
|
| 1548 |
+
}
|
| 1549 |
+
|
| 1550 |
+
// Chroma IDCT, with upsampling
|
| 1551 |
+
jpgd_block_t temp_block[64];
|
| 1552 |
+
|
| 1553 |
+
for (int i = 0; i < 2; i++)
|
| 1554 |
+
{
|
| 1555 |
+
DCT_Upsample::Matrix44 P, Q, R, S;
|
| 1556 |
+
|
| 1557 |
+
JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] >= 1);
|
| 1558 |
+
JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] <= 64);
|
| 1559 |
+
|
| 1560 |
+
switch (s_max_rc[m_mcu_block_max_zag[mcu_block++] - 1])
|
| 1561 |
+
{
|
| 1562 |
+
case 1*16+1:
|
| 1563 |
+
DCT_Upsample::P_Q<1, 1>::calc(P, Q, pSrc_ptr);
|
| 1564 |
+
DCT_Upsample::R_S<1, 1>::calc(R, S, pSrc_ptr);
|
| 1565 |
+
break;
|
| 1566 |
+
case 1*16+2:
|
| 1567 |
+
DCT_Upsample::P_Q<1, 2>::calc(P, Q, pSrc_ptr);
|
| 1568 |
+
DCT_Upsample::R_S<1, 2>::calc(R, S, pSrc_ptr);
|
| 1569 |
+
break;
|
| 1570 |
+
case 2*16+2:
|
| 1571 |
+
DCT_Upsample::P_Q<2, 2>::calc(P, Q, pSrc_ptr);
|
| 1572 |
+
DCT_Upsample::R_S<2, 2>::calc(R, S, pSrc_ptr);
|
| 1573 |
+
break;
|
| 1574 |
+
case 3*16+2:
|
| 1575 |
+
DCT_Upsample::P_Q<3, 2>::calc(P, Q, pSrc_ptr);
|
| 1576 |
+
DCT_Upsample::R_S<3, 2>::calc(R, S, pSrc_ptr);
|
| 1577 |
+
break;
|
| 1578 |
+
case 3*16+3:
|
| 1579 |
+
DCT_Upsample::P_Q<3, 3>::calc(P, Q, pSrc_ptr);
|
| 1580 |
+
DCT_Upsample::R_S<3, 3>::calc(R, S, pSrc_ptr);
|
| 1581 |
+
break;
|
| 1582 |
+
case 3*16+4:
|
| 1583 |
+
DCT_Upsample::P_Q<3, 4>::calc(P, Q, pSrc_ptr);
|
| 1584 |
+
DCT_Upsample::R_S<3, 4>::calc(R, S, pSrc_ptr);
|
| 1585 |
+
break;
|
| 1586 |
+
case 4*16+4:
|
| 1587 |
+
DCT_Upsample::P_Q<4, 4>::calc(P, Q, pSrc_ptr);
|
| 1588 |
+
DCT_Upsample::R_S<4, 4>::calc(R, S, pSrc_ptr);
|
| 1589 |
+
break;
|
| 1590 |
+
case 5*16+4:
|
| 1591 |
+
DCT_Upsample::P_Q<5, 4>::calc(P, Q, pSrc_ptr);
|
| 1592 |
+
DCT_Upsample::R_S<5, 4>::calc(R, S, pSrc_ptr);
|
| 1593 |
+
break;
|
| 1594 |
+
case 5*16+5:
|
| 1595 |
+
DCT_Upsample::P_Q<5, 5>::calc(P, Q, pSrc_ptr);
|
| 1596 |
+
DCT_Upsample::R_S<5, 5>::calc(R, S, pSrc_ptr);
|
| 1597 |
+
break;
|
| 1598 |
+
case 5*16+6:
|
| 1599 |
+
DCT_Upsample::P_Q<5, 6>::calc(P, Q, pSrc_ptr);
|
| 1600 |
+
DCT_Upsample::R_S<5, 6>::calc(R, S, pSrc_ptr);
|
| 1601 |
+
break;
|
| 1602 |
+
case 6*16+6:
|
| 1603 |
+
DCT_Upsample::P_Q<6, 6>::calc(P, Q, pSrc_ptr);
|
| 1604 |
+
DCT_Upsample::R_S<6, 6>::calc(R, S, pSrc_ptr);
|
| 1605 |
+
break;
|
| 1606 |
+
case 7*16+6:
|
| 1607 |
+
DCT_Upsample::P_Q<7, 6>::calc(P, Q, pSrc_ptr);
|
| 1608 |
+
DCT_Upsample::R_S<7, 6>::calc(R, S, pSrc_ptr);
|
| 1609 |
+
break;
|
| 1610 |
+
case 7*16+7:
|
| 1611 |
+
DCT_Upsample::P_Q<7, 7>::calc(P, Q, pSrc_ptr);
|
| 1612 |
+
DCT_Upsample::R_S<7, 7>::calc(R, S, pSrc_ptr);
|
| 1613 |
+
break;
|
| 1614 |
+
case 7*16+8:
|
| 1615 |
+
DCT_Upsample::P_Q<7, 8>::calc(P, Q, pSrc_ptr);
|
| 1616 |
+
DCT_Upsample::R_S<7, 8>::calc(R, S, pSrc_ptr);
|
| 1617 |
+
break;
|
| 1618 |
+
case 8*16+8:
|
| 1619 |
+
DCT_Upsample::P_Q<8, 8>::calc(P, Q, pSrc_ptr);
|
| 1620 |
+
DCT_Upsample::R_S<8, 8>::calc(R, S, pSrc_ptr);
|
| 1621 |
+
break;
|
| 1622 |
+
default:
|
| 1623 |
+
JPGD_ASSERT(false);
|
| 1624 |
+
}
|
| 1625 |
+
|
| 1626 |
+
DCT_Upsample::Matrix44 a(P + Q); P -= Q;
|
| 1627 |
+
DCT_Upsample::Matrix44& b = P;
|
| 1628 |
+
DCT_Upsample::Matrix44 c(R + S); R -= S;
|
| 1629 |
+
DCT_Upsample::Matrix44& d = R;
|
| 1630 |
+
|
| 1631 |
+
DCT_Upsample::Matrix44::add_and_store(temp_block, a, c);
|
| 1632 |
+
idct_4x4(temp_block, pDst_ptr);
|
| 1633 |
+
pDst_ptr += 64;
|
| 1634 |
+
|
| 1635 |
+
DCT_Upsample::Matrix44::sub_and_store(temp_block, a, c);
|
| 1636 |
+
idct_4x4(temp_block, pDst_ptr);
|
| 1637 |
+
pDst_ptr += 64;
|
| 1638 |
+
|
| 1639 |
+
DCT_Upsample::Matrix44::add_and_store(temp_block, b, d);
|
| 1640 |
+
idct_4x4(temp_block, pDst_ptr);
|
| 1641 |
+
pDst_ptr += 64;
|
| 1642 |
+
|
| 1643 |
+
DCT_Upsample::Matrix44::sub_and_store(temp_block, b, d);
|
| 1644 |
+
idct_4x4(temp_block, pDst_ptr);
|
| 1645 |
+
pDst_ptr += 64;
|
| 1646 |
+
|
| 1647 |
+
pSrc_ptr += 64;
|
| 1648 |
+
}
|
| 1649 |
+
}
|
| 1650 |
+
|
| 1651 |
+
// Loads and dequantizes the next row of (already decoded) coefficients.
|
| 1652 |
+
// Progressive images only.
|
| 1653 |
+
void jpeg_decoder::load_next_row()
|
| 1654 |
+
{
|
| 1655 |
+
int i;
|
| 1656 |
+
jpgd_block_t *p;
|
| 1657 |
+
jpgd_quant_t *q;
|
| 1658 |
+
int mcu_row, mcu_block, row_block = 0;
|
| 1659 |
+
int component_num, component_id;
|
| 1660 |
+
int block_x_mcu[JPGD_MAX_COMPONENTS];
|
| 1661 |
+
|
| 1662 |
+
memset(block_x_mcu, 0, JPGD_MAX_COMPONENTS * sizeof(int));
|
| 1663 |
+
|
| 1664 |
+
for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
|
| 1665 |
+
{
|
| 1666 |
+
int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0;
|
| 1667 |
+
|
| 1668 |
+
for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
|
| 1669 |
+
{
|
| 1670 |
+
component_id = m_mcu_org[mcu_block];
|
| 1671 |
+
q = m_quant[m_comp_quant[component_id]];
|
| 1672 |
+
|
| 1673 |
+
p = m_pMCU_coefficients + 64 * mcu_block;
|
| 1674 |
+
|
| 1675 |
+
jpgd_block_t* pAC = coeff_buf_getp(m_ac_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs);
|
| 1676 |
+
jpgd_block_t* pDC = coeff_buf_getp(m_dc_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs);
|
| 1677 |
+
p[0] = pDC[0];
|
| 1678 |
+
memcpy(&p[1], &pAC[1], 63 * sizeof(jpgd_block_t));
|
| 1679 |
+
|
| 1680 |
+
for (i = 63; i > 0; i--)
|
| 1681 |
+
if (p[g_ZAG[i]])
|
| 1682 |
+
break;
|
| 1683 |
+
|
| 1684 |
+
m_mcu_block_max_zag[mcu_block] = i + 1;
|
| 1685 |
+
|
| 1686 |
+
for ( ; i >= 0; i--)
|
| 1687 |
+
if (p[g_ZAG[i]])
|
| 1688 |
+
p[g_ZAG[i]] = static_cast<jpgd_block_t>(p[g_ZAG[i]] * q[i]);
|
| 1689 |
+
|
| 1690 |
+
row_block++;
|
| 1691 |
+
|
| 1692 |
+
if (m_comps_in_scan == 1)
|
| 1693 |
+
block_x_mcu[component_id]++;
|
| 1694 |
+
else
|
| 1695 |
+
{
|
| 1696 |
+
if (++block_x_mcu_ofs == m_comp_h_samp[component_id])
|
| 1697 |
+
{
|
| 1698 |
+
block_x_mcu_ofs = 0;
|
| 1699 |
+
|
| 1700 |
+
if (++block_y_mcu_ofs == m_comp_v_samp[component_id])
|
| 1701 |
+
{
|
| 1702 |
+
block_y_mcu_ofs = 0;
|
| 1703 |
+
|
| 1704 |
+
block_x_mcu[component_id] += m_comp_h_samp[component_id];
|
| 1705 |
+
}
|
| 1706 |
+
}
|
| 1707 |
+
}
|
| 1708 |
+
}
|
| 1709 |
+
|
| 1710 |
+
if (m_freq_domain_chroma_upsample)
|
| 1711 |
+
transform_mcu_expand(mcu_row);
|
| 1712 |
+
else
|
| 1713 |
+
transform_mcu(mcu_row);
|
| 1714 |
+
}
|
| 1715 |
+
|
| 1716 |
+
if (m_comps_in_scan == 1)
|
| 1717 |
+
m_block_y_mcu[m_comp_list[0]]++;
|
| 1718 |
+
else
|
| 1719 |
+
{
|
| 1720 |
+
for (component_num = 0; component_num < m_comps_in_scan; component_num++)
|
| 1721 |
+
{
|
| 1722 |
+
component_id = m_comp_list[component_num];
|
| 1723 |
+
|
| 1724 |
+
m_block_y_mcu[component_id] += m_comp_v_samp[component_id];
|
| 1725 |
+
}
|
| 1726 |
+
}
|
| 1727 |
+
}
|
| 1728 |
+
|
| 1729 |
+
// Restart interval processing.
|
| 1730 |
+
void jpeg_decoder::process_restart()
|
| 1731 |
+
{
|
| 1732 |
+
int i;
|
| 1733 |
+
int c = 0;
|
| 1734 |
+
|
| 1735 |
+
// Align to a byte boundry
|
| 1736 |
+
// FIXME: Is this really necessary? get_bits_no_markers() never reads in markers!
|
| 1737 |
+
//get_bits_no_markers(m_bits_left & 7);
|
| 1738 |
+
|
| 1739 |
+
// Let's scan a little bit to find the marker, but not _too_ far.
|
| 1740 |
+
// 1536 is a "fudge factor" that determines how much to scan.
|
| 1741 |
+
for (i = 1536; i > 0; i--)
|
| 1742 |
+
if (get_char() == 0xFF)
|
| 1743 |
+
break;
|
| 1744 |
+
|
| 1745 |
+
if (i == 0)
|
| 1746 |
+
stop_decoding(JPGD_BAD_RESTART_MARKER);
|
| 1747 |
+
|
| 1748 |
+
for ( ; i > 0; i--)
|
| 1749 |
+
if ((c = get_char()) != 0xFF)
|
| 1750 |
+
break;
|
| 1751 |
+
|
| 1752 |
+
if (i == 0)
|
| 1753 |
+
stop_decoding(JPGD_BAD_RESTART_MARKER);
|
| 1754 |
+
|
| 1755 |
+
// Is it the expected marker? If not, something bad happened.
|
| 1756 |
+
if (c != (m_next_restart_num + M_RST0))
|
| 1757 |
+
stop_decoding(JPGD_BAD_RESTART_MARKER);
|
| 1758 |
+
|
| 1759 |
+
// Reset each component's DC prediction values.
|
| 1760 |
+
memset(&m_last_dc_val, 0, m_comps_in_frame * sizeof(uint));
|
| 1761 |
+
|
| 1762 |
+
m_eob_run = 0;
|
| 1763 |
+
|
| 1764 |
+
m_restarts_left = m_restart_interval;
|
| 1765 |
+
|
| 1766 |
+
m_next_restart_num = (m_next_restart_num + 1) & 7;
|
| 1767 |
+
|
| 1768 |
+
// Get the bit buffer going again...
|
| 1769 |
+
|
| 1770 |
+
m_bits_left = 16;
|
| 1771 |
+
get_bits_no_markers(16);
|
| 1772 |
+
get_bits_no_markers(16);
|
| 1773 |
+
}
|
| 1774 |
+
|
| 1775 |
+
static inline int dequantize_ac(int c, int q) { c *= q; return c; }
|
| 1776 |
+
|
| 1777 |
+
// Decodes and dequantizes the next row of coefficients.
|
| 1778 |
+
void jpeg_decoder::decode_next_row()
|
| 1779 |
+
{
|
| 1780 |
+
int row_block = 0;
|
| 1781 |
+
|
| 1782 |
+
for (int mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
|
| 1783 |
+
{
|
| 1784 |
+
if ((m_restart_interval) && (m_restarts_left == 0))
|
| 1785 |
+
process_restart();
|
| 1786 |
+
|
| 1787 |
+
jpgd_block_t* p = m_pMCU_coefficients;
|
| 1788 |
+
for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++, p += 64)
|
| 1789 |
+
{
|
| 1790 |
+
int component_id = m_mcu_org[mcu_block];
|
| 1791 |
+
jpgd_quant_t* q = m_quant[m_comp_quant[component_id]];
|
| 1792 |
+
|
| 1793 |
+
int r, s;
|
| 1794 |
+
s = huff_decode(m_pHuff_tabs[m_comp_dc_tab[component_id]], r);
|
| 1795 |
+
s = HUFF_EXTEND(r, s);
|
| 1796 |
+
|
| 1797 |
+
m_last_dc_val[component_id] = (s += m_last_dc_val[component_id]);
|
| 1798 |
+
|
| 1799 |
+
p[0] = static_cast<jpgd_block_t>(s * q[0]);
|
| 1800 |
+
|
| 1801 |
+
int prev_num_set = m_mcu_block_max_zag[mcu_block];
|
| 1802 |
+
|
| 1803 |
+
huff_tables *pH = m_pHuff_tabs[m_comp_ac_tab[component_id]];
|
| 1804 |
+
|
| 1805 |
+
int k;
|
| 1806 |
+
for (k = 1; k < 64; k++)
|
| 1807 |
+
{
|
| 1808 |
+
int extra_bits;
|
| 1809 |
+
s = huff_decode(pH, extra_bits);
|
| 1810 |
+
|
| 1811 |
+
r = s >> 4;
|
| 1812 |
+
s &= 15;
|
| 1813 |
+
|
| 1814 |
+
if (s)
|
| 1815 |
+
{
|
| 1816 |
+
if (r)
|
| 1817 |
+
{
|
| 1818 |
+
if ((k + r) > 63)
|
| 1819 |
+
stop_decoding(JPGD_DECODE_ERROR);
|
| 1820 |
+
|
| 1821 |
+
if (k < prev_num_set)
|
| 1822 |
+
{
|
| 1823 |
+
int n = JPGD_MIN(r, prev_num_set - k);
|
| 1824 |
+
int kt = k;
|
| 1825 |
+
while (n--)
|
| 1826 |
+
p[g_ZAG[kt++]] = 0;
|
| 1827 |
+
}
|
| 1828 |
+
|
| 1829 |
+
k += r;
|
| 1830 |
+
}
|
| 1831 |
+
|
| 1832 |
+
s = HUFF_EXTEND(extra_bits, s);
|
| 1833 |
+
|
| 1834 |
+
JPGD_ASSERT(k < 64);
|
| 1835 |
+
|
| 1836 |
+
p[g_ZAG[k]] = static_cast<jpgd_block_t>(dequantize_ac(s, q[k])); //s * q[k];
|
| 1837 |
+
}
|
| 1838 |
+
else
|
| 1839 |
+
{
|
| 1840 |
+
if (r == 15)
|
| 1841 |
+
{
|
| 1842 |
+
if ((k + 16) > 64)
|
| 1843 |
+
stop_decoding(JPGD_DECODE_ERROR);
|
| 1844 |
+
|
| 1845 |
+
if (k < prev_num_set)
|
| 1846 |
+
{
|
| 1847 |
+
int n = JPGD_MIN(16, prev_num_set - k);
|
| 1848 |
+
int kt = k;
|
| 1849 |
+
while (n--)
|
| 1850 |
+
{
|
| 1851 |
+
JPGD_ASSERT(kt <= 63);
|
| 1852 |
+
p[g_ZAG[kt++]] = 0;
|
| 1853 |
+
}
|
| 1854 |
+
}
|
| 1855 |
+
|
| 1856 |
+
k += 16 - 1; // - 1 because the loop counter is k
|
| 1857 |
+
// BEGIN EPIC MOD
|
| 1858 |
+
JPGD_ASSERT(k < 64 && p[g_ZAG[k]] == 0);
|
| 1859 |
+
// END EPIC MOD
|
| 1860 |
+
}
|
| 1861 |
+
else
|
| 1862 |
+
break;
|
| 1863 |
+
}
|
| 1864 |
+
}
|
| 1865 |
+
|
| 1866 |
+
if (k < prev_num_set)
|
| 1867 |
+
{
|
| 1868 |
+
int kt = k;
|
| 1869 |
+
while (kt < prev_num_set)
|
| 1870 |
+
p[g_ZAG[kt++]] = 0;
|
| 1871 |
+
}
|
| 1872 |
+
|
| 1873 |
+
m_mcu_block_max_zag[mcu_block] = k;
|
| 1874 |
+
|
| 1875 |
+
row_block++;
|
| 1876 |
+
}
|
| 1877 |
+
|
| 1878 |
+
if (m_freq_domain_chroma_upsample)
|
| 1879 |
+
transform_mcu_expand(mcu_row);
|
| 1880 |
+
else
|
| 1881 |
+
transform_mcu(mcu_row);
|
| 1882 |
+
|
| 1883 |
+
m_restarts_left--;
|
| 1884 |
+
}
|
| 1885 |
+
}
|
| 1886 |
+
|
| 1887 |
+
// YCbCr H1V1 (1x1:1:1, 3 m_blocks per MCU) to RGB
|
| 1888 |
+
void jpeg_decoder::H1V1Convert()
|
| 1889 |
+
{
|
| 1890 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
| 1891 |
+
uint8 *d = m_pScan_line_0;
|
| 1892 |
+
uint8 *s = m_pSample_buf + row * 8;
|
| 1893 |
+
|
| 1894 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
| 1895 |
+
{
|
| 1896 |
+
for (int j = 0; j < 8; j++)
|
| 1897 |
+
{
|
| 1898 |
+
int y = s[j];
|
| 1899 |
+
int cb = s[64+j];
|
| 1900 |
+
int cr = s[128+j];
|
| 1901 |
+
|
| 1902 |
+
if (jpg_format == ERGBFormatJPG::BGRA)
|
| 1903 |
+
{
|
| 1904 |
+
d[0] = clamp(y + m_cbb[cb]);
|
| 1905 |
+
d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16));
|
| 1906 |
+
d[2] = clamp(y + m_crr[cr]);
|
| 1907 |
+
d[3] = 255;
|
| 1908 |
+
}
|
| 1909 |
+
else
|
| 1910 |
+
{
|
| 1911 |
+
d[0] = clamp(y + m_crr[cr]);
|
| 1912 |
+
d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16));
|
| 1913 |
+
d[2] = clamp(y + m_cbb[cb]);
|
| 1914 |
+
d[3] = 255;
|
| 1915 |
+
}
|
| 1916 |
+
d += 4;
|
| 1917 |
+
}
|
| 1918 |
+
|
| 1919 |
+
s += 64*3;
|
| 1920 |
+
}
|
| 1921 |
+
}
|
| 1922 |
+
|
| 1923 |
+
// YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB
|
| 1924 |
+
void jpeg_decoder::H2V1Convert()
|
| 1925 |
+
{
|
| 1926 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
| 1927 |
+
uint8 *d0 = m_pScan_line_0;
|
| 1928 |
+
uint8 *y = m_pSample_buf + row * 8;
|
| 1929 |
+
uint8 *c = m_pSample_buf + 2*64 + row * 8;
|
| 1930 |
+
|
| 1931 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
| 1932 |
+
{
|
| 1933 |
+
for (int l = 0; l < 2; l++)
|
| 1934 |
+
{
|
| 1935 |
+
for (int j = 0; j < 4; j++)
|
| 1936 |
+
{
|
| 1937 |
+
int cb = c[0];
|
| 1938 |
+
int cr = c[64];
|
| 1939 |
+
|
| 1940 |
+
int rc = m_crr[cr];
|
| 1941 |
+
int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
|
| 1942 |
+
int bc = m_cbb[cb];
|
| 1943 |
+
|
| 1944 |
+
int yy = y[j<<1];
|
| 1945 |
+
if (jpg_format == ERGBFormatJPG::BGRA)
|
| 1946 |
+
{
|
| 1947 |
+
d0[0] = clamp(yy+bc);
|
| 1948 |
+
d0[1] = clamp(yy+gc);
|
| 1949 |
+
d0[2] = clamp(yy+rc);
|
| 1950 |
+
d0[3] = 255;
|
| 1951 |
+
yy = y[(j<<1)+1];
|
| 1952 |
+
d0[4] = clamp(yy+bc);
|
| 1953 |
+
d0[5] = clamp(yy+gc);
|
| 1954 |
+
d0[6] = clamp(yy+rc);
|
| 1955 |
+
d0[7] = 255;
|
| 1956 |
+
}
|
| 1957 |
+
else
|
| 1958 |
+
{
|
| 1959 |
+
d0[0] = clamp(yy+rc);
|
| 1960 |
+
d0[1] = clamp(yy+gc);
|
| 1961 |
+
d0[2] = clamp(yy+bc);
|
| 1962 |
+
d0[3] = 255;
|
| 1963 |
+
yy = y[(j<<1)+1];
|
| 1964 |
+
d0[4] = clamp(yy+rc);
|
| 1965 |
+
d0[5] = clamp(yy+gc);
|
| 1966 |
+
d0[6] = clamp(yy+bc);
|
| 1967 |
+
d0[7] = 255;
|
| 1968 |
+
}
|
| 1969 |
+
|
| 1970 |
+
d0 += 8;
|
| 1971 |
+
|
| 1972 |
+
c++;
|
| 1973 |
+
}
|
| 1974 |
+
y += 64;
|
| 1975 |
+
}
|
| 1976 |
+
|
| 1977 |
+
y += 64*4 - 64*2;
|
| 1978 |
+
c += 64*4 - 8;
|
| 1979 |
+
}
|
| 1980 |
+
}
|
| 1981 |
+
|
| 1982 |
+
// YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB
|
| 1983 |
+
void jpeg_decoder::H1V2Convert()
|
| 1984 |
+
{
|
| 1985 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
| 1986 |
+
uint8 *d0 = m_pScan_line_0;
|
| 1987 |
+
uint8 *d1 = m_pScan_line_1;
|
| 1988 |
+
uint8 *y;
|
| 1989 |
+
uint8 *c;
|
| 1990 |
+
|
| 1991 |
+
if (row < 8)
|
| 1992 |
+
y = m_pSample_buf + row * 8;
|
| 1993 |
+
else
|
| 1994 |
+
y = m_pSample_buf + 64*1 + (row & 7) * 8;
|
| 1995 |
+
|
| 1996 |
+
c = m_pSample_buf + 64*2 + (row >> 1) * 8;
|
| 1997 |
+
|
| 1998 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
| 1999 |
+
{
|
| 2000 |
+
for (int j = 0; j < 8; j++)
|
| 2001 |
+
{
|
| 2002 |
+
int cb = c[0+j];
|
| 2003 |
+
int cr = c[64+j];
|
| 2004 |
+
|
| 2005 |
+
int rc = m_crr[cr];
|
| 2006 |
+
int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
|
| 2007 |
+
int bc = m_cbb[cb];
|
| 2008 |
+
|
| 2009 |
+
int yy = y[j];
|
| 2010 |
+
if (jpg_format == ERGBFormatJPG::BGRA)
|
| 2011 |
+
{
|
| 2012 |
+
d0[0] = clamp(yy+bc);
|
| 2013 |
+
d0[1] = clamp(yy+gc);
|
| 2014 |
+
d0[2] = clamp(yy+rc);
|
| 2015 |
+
d0[3] = 255;
|
| 2016 |
+
yy = y[8+j];
|
| 2017 |
+
d1[0] = clamp(yy+bc);
|
| 2018 |
+
d1[1] = clamp(yy+gc);
|
| 2019 |
+
d1[2] = clamp(yy+rc);
|
| 2020 |
+
d1[3] = 255;
|
| 2021 |
+
}
|
| 2022 |
+
else
|
| 2023 |
+
{
|
| 2024 |
+
d0[0] = clamp(yy+rc);
|
| 2025 |
+
d0[1] = clamp(yy+gc);
|
| 2026 |
+
d0[2] = clamp(yy+bc);
|
| 2027 |
+
d0[3] = 255;
|
| 2028 |
+
yy = y[8+j];
|
| 2029 |
+
d1[0] = clamp(yy+rc);
|
| 2030 |
+
d1[1] = clamp(yy+gc);
|
| 2031 |
+
d1[2] = clamp(yy+bc);
|
| 2032 |
+
d1[3] = 255;
|
| 2033 |
+
}
|
| 2034 |
+
|
| 2035 |
+
d0 += 4;
|
| 2036 |
+
d1 += 4;
|
| 2037 |
+
}
|
| 2038 |
+
|
| 2039 |
+
y += 64*4;
|
| 2040 |
+
c += 64*4;
|
| 2041 |
+
}
|
| 2042 |
+
}
|
| 2043 |
+
|
| 2044 |
+
// YCbCr H2V2 (2x2:1:1, 6 m_blocks per MCU) to RGB
|
| 2045 |
+
void jpeg_decoder::H2V2Convert()
|
| 2046 |
+
{
|
| 2047 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
| 2048 |
+
uint8 *d0 = m_pScan_line_0;
|
| 2049 |
+
uint8 *d1 = m_pScan_line_1;
|
| 2050 |
+
uint8 *y;
|
| 2051 |
+
uint8 *c;
|
| 2052 |
+
|
| 2053 |
+
if (row < 8)
|
| 2054 |
+
y = m_pSample_buf + row * 8;
|
| 2055 |
+
else
|
| 2056 |
+
y = m_pSample_buf + 64*2 + (row & 7) * 8;
|
| 2057 |
+
|
| 2058 |
+
c = m_pSample_buf + 64*4 + (row >> 1) * 8;
|
| 2059 |
+
|
| 2060 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
| 2061 |
+
{
|
| 2062 |
+
for (int l = 0; l < 2; l++)
|
| 2063 |
+
{
|
| 2064 |
+
for (int j = 0; j < 8; j += 2)
|
| 2065 |
+
{
|
| 2066 |
+
int cb = c[0];
|
| 2067 |
+
int cr = c[64];
|
| 2068 |
+
|
| 2069 |
+
int rc = m_crr[cr];
|
| 2070 |
+
int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
|
| 2071 |
+
int bc = m_cbb[cb];
|
| 2072 |
+
|
| 2073 |
+
int yy = y[j];
|
| 2074 |
+
if (jpg_format == ERGBFormatJPG::BGRA)
|
| 2075 |
+
{
|
| 2076 |
+
d0[0] = clamp(yy+bc);
|
| 2077 |
+
d0[1] = clamp(yy+gc);
|
| 2078 |
+
d0[2] = clamp(yy+rc);
|
| 2079 |
+
d0[3] = 255;
|
| 2080 |
+
yy = y[j+1];
|
| 2081 |
+
d0[4] = clamp(yy+bc);
|
| 2082 |
+
d0[5] = clamp(yy+gc);
|
| 2083 |
+
d0[6] = clamp(yy+rc);
|
| 2084 |
+
d0[7] = 255;
|
| 2085 |
+
yy = y[j+8];
|
| 2086 |
+
d1[0] = clamp(yy+bc);
|
| 2087 |
+
d1[1] = clamp(yy+gc);
|
| 2088 |
+
d1[2] = clamp(yy+rc);
|
| 2089 |
+
d1[3] = 255;
|
| 2090 |
+
yy = y[j+8+1];
|
| 2091 |
+
d1[4] = clamp(yy+bc);
|
| 2092 |
+
d1[5] = clamp(yy+gc);
|
| 2093 |
+
d1[6] = clamp(yy+rc);
|
| 2094 |
+
d1[7] = 255;
|
| 2095 |
+
}
|
| 2096 |
+
else
|
| 2097 |
+
{
|
| 2098 |
+
d0[0] = clamp(yy+rc);
|
| 2099 |
+
d0[1] = clamp(yy+gc);
|
| 2100 |
+
d0[2] = clamp(yy+bc);
|
| 2101 |
+
d0[3] = 255;
|
| 2102 |
+
yy = y[j+1];
|
| 2103 |
+
d0[4] = clamp(yy+rc);
|
| 2104 |
+
d0[5] = clamp(yy+gc);
|
| 2105 |
+
d0[6] = clamp(yy+bc);
|
| 2106 |
+
d0[7] = 255;
|
| 2107 |
+
yy = y[j+8];
|
| 2108 |
+
d1[0] = clamp(yy+rc);
|
| 2109 |
+
d1[1] = clamp(yy+gc);
|
| 2110 |
+
d1[2] = clamp(yy+bc);
|
| 2111 |
+
d1[3] = 255;
|
| 2112 |
+
yy = y[j+8+1];
|
| 2113 |
+
d1[4] = clamp(yy+rc);
|
| 2114 |
+
d1[5] = clamp(yy+gc);
|
| 2115 |
+
d1[6] = clamp(yy+bc);
|
| 2116 |
+
d1[7] = 255;
|
| 2117 |
+
}
|
| 2118 |
+
|
| 2119 |
+
d0 += 8;
|
| 2120 |
+
d1 += 8;
|
| 2121 |
+
|
| 2122 |
+
c++;
|
| 2123 |
+
}
|
| 2124 |
+
y += 64;
|
| 2125 |
+
}
|
| 2126 |
+
|
| 2127 |
+
y += 64*6 - 64*2;
|
| 2128 |
+
c += 64*6 - 8;
|
| 2129 |
+
}
|
| 2130 |
+
}
|
| 2131 |
+
|
| 2132 |
+
// Y (1 block per MCU) to 8-bit grayscale
|
| 2133 |
+
void jpeg_decoder::gray_convert()
|
| 2134 |
+
{
|
| 2135 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
| 2136 |
+
uint8 *d = m_pScan_line_0;
|
| 2137 |
+
uint8 *s = m_pSample_buf + row * 8;
|
| 2138 |
+
|
| 2139 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
| 2140 |
+
{
|
| 2141 |
+
*(uint *)d = *(uint *)s;
|
| 2142 |
+
*(uint *)(&d[4]) = *(uint *)(&s[4]);
|
| 2143 |
+
|
| 2144 |
+
s += 64;
|
| 2145 |
+
d += 8;
|
| 2146 |
+
}
|
| 2147 |
+
}
|
| 2148 |
+
|
| 2149 |
+
void jpeg_decoder::expanded_convert()
|
| 2150 |
+
{
|
| 2151 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
| 2152 |
+
|
| 2153 |
+
uint8* Py = m_pSample_buf + (row / 8) * 64 * m_comp_h_samp[0] + (row & 7) * 8;
|
| 2154 |
+
|
| 2155 |
+
uint8* d = m_pScan_line_0;
|
| 2156 |
+
|
| 2157 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
| 2158 |
+
{
|
| 2159 |
+
for (int k = 0; k < m_max_mcu_x_size; k += 8)
|
| 2160 |
+
{
|
| 2161 |
+
const int Y_ofs = k * 8;
|
| 2162 |
+
const int Cb_ofs = Y_ofs + 64 * m_expanded_blocks_per_component;
|
| 2163 |
+
const int Cr_ofs = Y_ofs + 64 * m_expanded_blocks_per_component * 2;
|
| 2164 |
+
for (int j = 0; j < 8; j++)
|
| 2165 |
+
{
|
| 2166 |
+
int y = Py[Y_ofs + j];
|
| 2167 |
+
int cb = Py[Cb_ofs + j];
|
| 2168 |
+
int cr = Py[Cr_ofs + j];
|
| 2169 |
+
|
| 2170 |
+
if (jpg_format == ERGBFormatJPG::BGRA)
|
| 2171 |
+
{
|
| 2172 |
+
d[0] = clamp(y + m_cbb[cb]);
|
| 2173 |
+
d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16));
|
| 2174 |
+
d[2] = clamp(y + m_crr[cr]);
|
| 2175 |
+
d[3] = 255;
|
| 2176 |
+
}
|
| 2177 |
+
else
|
| 2178 |
+
{
|
| 2179 |
+
d[0] = clamp(y + m_crr[cr]);
|
| 2180 |
+
d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16));
|
| 2181 |
+
d[2] = clamp(y + m_cbb[cb]);
|
| 2182 |
+
d[3] = 255;
|
| 2183 |
+
}
|
| 2184 |
+
|
| 2185 |
+
d += 4;
|
| 2186 |
+
}
|
| 2187 |
+
}
|
| 2188 |
+
|
| 2189 |
+
Py += 64 * m_expanded_blocks_per_mcu;
|
| 2190 |
+
}
|
| 2191 |
+
}
|
| 2192 |
+
|
| 2193 |
+
// Find end of image (EOI) marker, so we can return to the user the exact size of the input stream.
|
| 2194 |
+
void jpeg_decoder::find_eoi()
|
| 2195 |
+
{
|
| 2196 |
+
if (!m_progressive_flag)
|
| 2197 |
+
{
|
| 2198 |
+
// Attempt to read the EOI marker.
|
| 2199 |
+
//get_bits_no_markers(m_bits_left & 7);
|
| 2200 |
+
|
| 2201 |
+
// Prime the bit buffer
|
| 2202 |
+
m_bits_left = 16;
|
| 2203 |
+
get_bits(16);
|
| 2204 |
+
get_bits(16);
|
| 2205 |
+
|
| 2206 |
+
// The next marker _should_ be EOI
|
| 2207 |
+
process_markers();
|
| 2208 |
+
}
|
| 2209 |
+
|
| 2210 |
+
m_total_bytes_read -= m_in_buf_left;
|
| 2211 |
+
}
|
| 2212 |
+
|
| 2213 |
+
int jpeg_decoder::decode(const void** pScan_line, uint* pScan_line_len)
|
| 2214 |
+
{
|
| 2215 |
+
if ((m_error_code) || (!m_ready_flag))
|
| 2216 |
+
return JPGD_FAILED;
|
| 2217 |
+
|
| 2218 |
+
if (m_total_lines_left == 0)
|
| 2219 |
+
return JPGD_DONE;
|
| 2220 |
+
|
| 2221 |
+
if (m_mcu_lines_left == 0)
|
| 2222 |
+
{
|
| 2223 |
+
if (setjmp(m_jmp_state))
|
| 2224 |
+
return JPGD_FAILED;
|
| 2225 |
+
|
| 2226 |
+
if (m_progressive_flag)
|
| 2227 |
+
load_next_row();
|
| 2228 |
+
else
|
| 2229 |
+
decode_next_row();
|
| 2230 |
+
|
| 2231 |
+
// Find the EOI marker if that was the last row.
|
| 2232 |
+
if (m_total_lines_left <= m_max_mcu_y_size)
|
| 2233 |
+
find_eoi();
|
| 2234 |
+
|
| 2235 |
+
m_mcu_lines_left = m_max_mcu_y_size;
|
| 2236 |
+
}
|
| 2237 |
+
|
| 2238 |
+
if (m_freq_domain_chroma_upsample)
|
| 2239 |
+
{
|
| 2240 |
+
expanded_convert();
|
| 2241 |
+
*pScan_line = m_pScan_line_0;
|
| 2242 |
+
}
|
| 2243 |
+
else
|
| 2244 |
+
{
|
| 2245 |
+
switch (m_scan_type)
|
| 2246 |
+
{
|
| 2247 |
+
case JPGD_YH2V2:
|
| 2248 |
+
{
|
| 2249 |
+
if ((m_mcu_lines_left & 1) == 0)
|
| 2250 |
+
{
|
| 2251 |
+
H2V2Convert();
|
| 2252 |
+
*pScan_line = m_pScan_line_0;
|
| 2253 |
+
}
|
| 2254 |
+
else
|
| 2255 |
+
*pScan_line = m_pScan_line_1;
|
| 2256 |
+
|
| 2257 |
+
break;
|
| 2258 |
+
}
|
| 2259 |
+
case JPGD_YH2V1:
|
| 2260 |
+
{
|
| 2261 |
+
H2V1Convert();
|
| 2262 |
+
*pScan_line = m_pScan_line_0;
|
| 2263 |
+
break;
|
| 2264 |
+
}
|
| 2265 |
+
case JPGD_YH1V2:
|
| 2266 |
+
{
|
| 2267 |
+
if ((m_mcu_lines_left & 1) == 0)
|
| 2268 |
+
{
|
| 2269 |
+
H1V2Convert();
|
| 2270 |
+
*pScan_line = m_pScan_line_0;
|
| 2271 |
+
}
|
| 2272 |
+
else
|
| 2273 |
+
*pScan_line = m_pScan_line_1;
|
| 2274 |
+
|
| 2275 |
+
break;
|
| 2276 |
+
}
|
| 2277 |
+
case JPGD_YH1V1:
|
| 2278 |
+
{
|
| 2279 |
+
H1V1Convert();
|
| 2280 |
+
*pScan_line = m_pScan_line_0;
|
| 2281 |
+
break;
|
| 2282 |
+
}
|
| 2283 |
+
case JPGD_GRAYSCALE:
|
| 2284 |
+
{
|
| 2285 |
+
gray_convert();
|
| 2286 |
+
*pScan_line = m_pScan_line_0;
|
| 2287 |
+
|
| 2288 |
+
break;
|
| 2289 |
+
}
|
| 2290 |
+
}
|
| 2291 |
+
}
|
| 2292 |
+
|
| 2293 |
+
*pScan_line_len = m_real_dest_bytes_per_scan_line;
|
| 2294 |
+
|
| 2295 |
+
m_mcu_lines_left--;
|
| 2296 |
+
m_total_lines_left--;
|
| 2297 |
+
|
| 2298 |
+
return JPGD_SUCCESS;
|
| 2299 |
+
}
|
| 2300 |
+
|
| 2301 |
+
// Creates the tables needed for efficient Huffman decoding.
|
| 2302 |
+
void jpeg_decoder::make_huff_table(int index, huff_tables *pH)
|
| 2303 |
+
{
|
| 2304 |
+
int p, i, l, si;
|
| 2305 |
+
uint8 huffsize[257];
|
| 2306 |
+
uint huffcode[257];
|
| 2307 |
+
uint code;
|
| 2308 |
+
uint subtree;
|
| 2309 |
+
int code_size;
|
| 2310 |
+
int lastp;
|
| 2311 |
+
int nextfreeentry;
|
| 2312 |
+
int currententry;
|
| 2313 |
+
|
| 2314 |
+
pH->ac_table = m_huff_ac[index] != 0;
|
| 2315 |
+
|
| 2316 |
+
p = 0;
|
| 2317 |
+
|
| 2318 |
+
for (l = 1; l <= 16; l++)
|
| 2319 |
+
{
|
| 2320 |
+
for (i = 1; i <= m_huff_num[index][l]; i++)
|
| 2321 |
+
huffsize[p++] = static_cast<uint8>(l);
|
| 2322 |
+
}
|
| 2323 |
+
|
| 2324 |
+
huffsize[p] = 0;
|
| 2325 |
+
|
| 2326 |
+
lastp = p;
|
| 2327 |
+
|
| 2328 |
+
code = 0;
|
| 2329 |
+
si = huffsize[0];
|
| 2330 |
+
p = 0;
|
| 2331 |
+
|
| 2332 |
+
while (huffsize[p])
|
| 2333 |
+
{
|
| 2334 |
+
while (huffsize[p] == si)
|
| 2335 |
+
{
|
| 2336 |
+
huffcode[p++] = code;
|
| 2337 |
+
code++;
|
| 2338 |
+
}
|
| 2339 |
+
|
| 2340 |
+
code <<= 1;
|
| 2341 |
+
si++;
|
| 2342 |
+
}
|
| 2343 |
+
|
| 2344 |
+
memset(pH->look_up, 0, sizeof(pH->look_up));
|
| 2345 |
+
memset(pH->look_up2, 0, sizeof(pH->look_up2));
|
| 2346 |
+
memset(pH->tree, 0, sizeof(pH->tree));
|
| 2347 |
+
memset(pH->code_size, 0, sizeof(pH->code_size));
|
| 2348 |
+
|
| 2349 |
+
nextfreeentry = -1;
|
| 2350 |
+
|
| 2351 |
+
p = 0;
|
| 2352 |
+
|
| 2353 |
+
while (p < lastp)
|
| 2354 |
+
{
|
| 2355 |
+
i = m_huff_val[index][p];
|
| 2356 |
+
code = huffcode[p];
|
| 2357 |
+
code_size = huffsize[p];
|
| 2358 |
+
|
| 2359 |
+
pH->code_size[i] = static_cast<uint8>(code_size);
|
| 2360 |
+
|
| 2361 |
+
if (code_size <= 8)
|
| 2362 |
+
{
|
| 2363 |
+
code <<= (8 - code_size);
|
| 2364 |
+
|
| 2365 |
+
for (l = 1 << (8 - code_size); l > 0; l--)
|
| 2366 |
+
{
|
| 2367 |
+
JPGD_ASSERT(i < 256);
|
| 2368 |
+
|
| 2369 |
+
pH->look_up[code] = i;
|
| 2370 |
+
|
| 2371 |
+
bool has_extrabits = false;
|
| 2372 |
+
int extra_bits = 0;
|
| 2373 |
+
int num_extra_bits = i & 15;
|
| 2374 |
+
|
| 2375 |
+
int bits_to_fetch = code_size;
|
| 2376 |
+
if (num_extra_bits)
|
| 2377 |
+
{
|
| 2378 |
+
int total_codesize = code_size + num_extra_bits;
|
| 2379 |
+
if (total_codesize <= 8)
|
| 2380 |
+
{
|
| 2381 |
+
has_extrabits = true;
|
| 2382 |
+
extra_bits = ((1 << num_extra_bits) - 1) & (code >> (8 - total_codesize));
|
| 2383 |
+
JPGD_ASSERT(extra_bits <= 0x7FFF);
|
| 2384 |
+
bits_to_fetch += num_extra_bits;
|
| 2385 |
+
}
|
| 2386 |
+
}
|
| 2387 |
+
|
| 2388 |
+
if (!has_extrabits)
|
| 2389 |
+
pH->look_up2[code] = i | (bits_to_fetch << 8);
|
| 2390 |
+
else
|
| 2391 |
+
pH->look_up2[code] = i | 0x8000 | (extra_bits << 16) | (bits_to_fetch << 8);
|
| 2392 |
+
|
| 2393 |
+
code++;
|
| 2394 |
+
}
|
| 2395 |
+
}
|
| 2396 |
+
else
|
| 2397 |
+
{
|
| 2398 |
+
subtree = (code >> (code_size - 8)) & 0xFF;
|
| 2399 |
+
|
| 2400 |
+
currententry = pH->look_up[subtree];
|
| 2401 |
+
|
| 2402 |
+
if (currententry == 0)
|
| 2403 |
+
{
|
| 2404 |
+
pH->look_up[subtree] = currententry = nextfreeentry;
|
| 2405 |
+
pH->look_up2[subtree] = currententry = nextfreeentry;
|
| 2406 |
+
|
| 2407 |
+
nextfreeentry -= 2;
|
| 2408 |
+
}
|
| 2409 |
+
|
| 2410 |
+
code <<= (16 - (code_size - 8));
|
| 2411 |
+
|
| 2412 |
+
for (l = code_size; l > 9; l--)
|
| 2413 |
+
{
|
| 2414 |
+
if ((code & 0x8000) == 0)
|
| 2415 |
+
currententry--;
|
| 2416 |
+
|
| 2417 |
+
if (pH->tree[-currententry - 1] == 0)
|
| 2418 |
+
{
|
| 2419 |
+
pH->tree[-currententry - 1] = nextfreeentry;
|
| 2420 |
+
|
| 2421 |
+
currententry = nextfreeentry;
|
| 2422 |
+
|
| 2423 |
+
nextfreeentry -= 2;
|
| 2424 |
+
}
|
| 2425 |
+
else
|
| 2426 |
+
currententry = pH->tree[-currententry - 1];
|
| 2427 |
+
|
| 2428 |
+
code <<= 1;
|
| 2429 |
+
}
|
| 2430 |
+
|
| 2431 |
+
if ((code & 0x8000) == 0)
|
| 2432 |
+
currententry--;
|
| 2433 |
+
|
| 2434 |
+
pH->tree[-currententry - 1] = i;
|
| 2435 |
+
}
|
| 2436 |
+
|
| 2437 |
+
p++;
|
| 2438 |
+
}
|
| 2439 |
+
}
|
| 2440 |
+
|
| 2441 |
+
// Verifies the quantization tables needed for this scan are available.
|
| 2442 |
+
void jpeg_decoder::check_quant_tables()
|
| 2443 |
+
{
|
| 2444 |
+
for (int i = 0; i < m_comps_in_scan; i++)
|
| 2445 |
+
if (m_quant[m_comp_quant[m_comp_list[i]]] == NULL)
|
| 2446 |
+
stop_decoding(JPGD_UNDEFINED_QUANT_TABLE);
|
| 2447 |
+
}
|
| 2448 |
+
|
| 2449 |
+
// Verifies that all the Huffman tables needed for this scan are available.
|
| 2450 |
+
void jpeg_decoder::check_huff_tables()
|
| 2451 |
+
{
|
| 2452 |
+
for (int i = 0; i < m_comps_in_scan; i++)
|
| 2453 |
+
{
|
| 2454 |
+
if ((m_spectral_start == 0) && (m_huff_num[m_comp_dc_tab[m_comp_list[i]]] == NULL))
|
| 2455 |
+
stop_decoding(JPGD_UNDEFINED_HUFF_TABLE);
|
| 2456 |
+
|
| 2457 |
+
if ((m_spectral_end > 0) && (m_huff_num[m_comp_ac_tab[m_comp_list[i]]] == NULL))
|
| 2458 |
+
stop_decoding(JPGD_UNDEFINED_HUFF_TABLE);
|
| 2459 |
+
}
|
| 2460 |
+
|
| 2461 |
+
for (int i = 0; i < JPGD_MAX_HUFF_TABLES; i++)
|
| 2462 |
+
if (m_huff_num[i])
|
| 2463 |
+
{
|
| 2464 |
+
if (!m_pHuff_tabs[i])
|
| 2465 |
+
m_pHuff_tabs[i] = (huff_tables *)alloc(sizeof(huff_tables));
|
| 2466 |
+
|
| 2467 |
+
make_huff_table(i, m_pHuff_tabs[i]);
|
| 2468 |
+
}
|
| 2469 |
+
}
|
| 2470 |
+
|
| 2471 |
+
// Determines the component order inside each MCU.
|
| 2472 |
+
// Also calcs how many MCU's are on each row, etc.
|
| 2473 |
+
void jpeg_decoder::calc_mcu_block_order()
|
| 2474 |
+
{
|
| 2475 |
+
int component_num, component_id;
|
| 2476 |
+
int max_h_samp = 0, max_v_samp = 0;
|
| 2477 |
+
|
| 2478 |
+
for (component_id = 0; component_id < m_comps_in_frame; component_id++)
|
| 2479 |
+
{
|
| 2480 |
+
if (m_comp_h_samp[component_id] > max_h_samp)
|
| 2481 |
+
max_h_samp = m_comp_h_samp[component_id];
|
| 2482 |
+
|
| 2483 |
+
if (m_comp_v_samp[component_id] > max_v_samp)
|
| 2484 |
+
max_v_samp = m_comp_v_samp[component_id];
|
| 2485 |
+
}
|
| 2486 |
+
|
| 2487 |
+
for (component_id = 0; component_id < m_comps_in_frame; component_id++)
|
| 2488 |
+
{
|
| 2489 |
+
m_comp_h_blocks[component_id] = ((((m_image_x_size * m_comp_h_samp[component_id]) + (max_h_samp - 1)) / max_h_samp) + 7) / 8;
|
| 2490 |
+
m_comp_v_blocks[component_id] = ((((m_image_y_size * m_comp_v_samp[component_id]) + (max_v_samp - 1)) / max_v_samp) + 7) / 8;
|
| 2491 |
+
}
|
| 2492 |
+
|
| 2493 |
+
if (m_comps_in_scan == 1)
|
| 2494 |
+
{
|
| 2495 |
+
m_mcus_per_row = m_comp_h_blocks[m_comp_list[0]];
|
| 2496 |
+
m_mcus_per_col = m_comp_v_blocks[m_comp_list[0]];
|
| 2497 |
+
}
|
| 2498 |
+
else
|
| 2499 |
+
{
|
| 2500 |
+
m_mcus_per_row = (((m_image_x_size + 7) / 8) + (max_h_samp - 1)) / max_h_samp;
|
| 2501 |
+
m_mcus_per_col = (((m_image_y_size + 7) / 8) + (max_v_samp - 1)) / max_v_samp;
|
| 2502 |
+
}
|
| 2503 |
+
|
| 2504 |
+
if (m_comps_in_scan == 1)
|
| 2505 |
+
{
|
| 2506 |
+
m_mcu_org[0] = m_comp_list[0];
|
| 2507 |
+
|
| 2508 |
+
m_blocks_per_mcu = 1;
|
| 2509 |
+
}
|
| 2510 |
+
else
|
| 2511 |
+
{
|
| 2512 |
+
m_blocks_per_mcu = 0;
|
| 2513 |
+
|
| 2514 |
+
for (component_num = 0; component_num < m_comps_in_scan; component_num++)
|
| 2515 |
+
{
|
| 2516 |
+
int num_blocks;
|
| 2517 |
+
|
| 2518 |
+
component_id = m_comp_list[component_num];
|
| 2519 |
+
|
| 2520 |
+
num_blocks = m_comp_h_samp[component_id] * m_comp_v_samp[component_id];
|
| 2521 |
+
|
| 2522 |
+
while (num_blocks--)
|
| 2523 |
+
m_mcu_org[m_blocks_per_mcu++] = component_id;
|
| 2524 |
+
}
|
| 2525 |
+
}
|
| 2526 |
+
}
|
| 2527 |
+
|
| 2528 |
+
// Starts a new scan.
|
| 2529 |
+
int jpeg_decoder::init_scan()
|
| 2530 |
+
{
|
| 2531 |
+
if (!locate_sos_marker())
|
| 2532 |
+
return JPGD_FALSE;
|
| 2533 |
+
|
| 2534 |
+
calc_mcu_block_order();
|
| 2535 |
+
|
| 2536 |
+
check_huff_tables();
|
| 2537 |
+
|
| 2538 |
+
check_quant_tables();
|
| 2539 |
+
|
| 2540 |
+
memset(m_last_dc_val, 0, m_comps_in_frame * sizeof(uint));
|
| 2541 |
+
|
| 2542 |
+
m_eob_run = 0;
|
| 2543 |
+
|
| 2544 |
+
if (m_restart_interval)
|
| 2545 |
+
{
|
| 2546 |
+
m_restarts_left = m_restart_interval;
|
| 2547 |
+
m_next_restart_num = 0;
|
| 2548 |
+
}
|
| 2549 |
+
|
| 2550 |
+
fix_in_buffer();
|
| 2551 |
+
|
| 2552 |
+
return JPGD_TRUE;
|
| 2553 |
+
}
|
| 2554 |
+
|
| 2555 |
+
// Starts a frame. Determines if the number of components or sampling factors
|
| 2556 |
+
// are supported.
|
| 2557 |
+
void jpeg_decoder::init_frame()
|
| 2558 |
+
{
|
| 2559 |
+
int i;
|
| 2560 |
+
|
| 2561 |
+
if (m_comps_in_frame == 1)
|
| 2562 |
+
{
|
| 2563 |
+
if ((m_comp_h_samp[0] != 1) || (m_comp_v_samp[0] != 1))
|
| 2564 |
+
stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
|
| 2565 |
+
|
| 2566 |
+
m_scan_type = JPGD_GRAYSCALE;
|
| 2567 |
+
m_max_blocks_per_mcu = 1;
|
| 2568 |
+
m_max_mcu_x_size = 8;
|
| 2569 |
+
m_max_mcu_y_size = 8;
|
| 2570 |
+
}
|
| 2571 |
+
else if (m_comps_in_frame == 3)
|
| 2572 |
+
{
|
| 2573 |
+
if ( ((m_comp_h_samp[1] != 1) || (m_comp_v_samp[1] != 1)) ||
|
| 2574 |
+
((m_comp_h_samp[2] != 1) || (m_comp_v_samp[2] != 1)) )
|
| 2575 |
+
stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
|
| 2576 |
+
|
| 2577 |
+
if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1))
|
| 2578 |
+
{
|
| 2579 |
+
m_scan_type = JPGD_YH1V1;
|
| 2580 |
+
|
| 2581 |
+
m_max_blocks_per_mcu = 3;
|
| 2582 |
+
m_max_mcu_x_size = 8;
|
| 2583 |
+
m_max_mcu_y_size = 8;
|
| 2584 |
+
}
|
| 2585 |
+
else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1))
|
| 2586 |
+
{
|
| 2587 |
+
m_scan_type = JPGD_YH2V1;
|
| 2588 |
+
m_max_blocks_per_mcu = 4;
|
| 2589 |
+
m_max_mcu_x_size = 16;
|
| 2590 |
+
m_max_mcu_y_size = 8;
|
| 2591 |
+
}
|
| 2592 |
+
else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 2))
|
| 2593 |
+
{
|
| 2594 |
+
m_scan_type = JPGD_YH1V2;
|
| 2595 |
+
m_max_blocks_per_mcu = 4;
|
| 2596 |
+
m_max_mcu_x_size = 8;
|
| 2597 |
+
m_max_mcu_y_size = 16;
|
| 2598 |
+
}
|
| 2599 |
+
else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2))
|
| 2600 |
+
{
|
| 2601 |
+
m_scan_type = JPGD_YH2V2;
|
| 2602 |
+
m_max_blocks_per_mcu = 6;
|
| 2603 |
+
m_max_mcu_x_size = 16;
|
| 2604 |
+
m_max_mcu_y_size = 16;
|
| 2605 |
+
}
|
| 2606 |
+
else
|
| 2607 |
+
stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
|
| 2608 |
+
}
|
| 2609 |
+
else
|
| 2610 |
+
stop_decoding(JPGD_UNSUPPORTED_COLORSPACE);
|
| 2611 |
+
|
| 2612 |
+
m_max_mcus_per_row = (m_image_x_size + (m_max_mcu_x_size - 1)) / m_max_mcu_x_size;
|
| 2613 |
+
m_max_mcus_per_col = (m_image_y_size + (m_max_mcu_y_size - 1)) / m_max_mcu_y_size;
|
| 2614 |
+
|
| 2615 |
+
// These values are for the *destination* pixels: after conversion.
|
| 2616 |
+
if (m_scan_type == JPGD_GRAYSCALE)
|
| 2617 |
+
m_dest_bytes_per_pixel = 1;
|
| 2618 |
+
else
|
| 2619 |
+
m_dest_bytes_per_pixel = 4;
|
| 2620 |
+
|
| 2621 |
+
m_dest_bytes_per_scan_line = ((m_image_x_size + 15) & 0xFFF0) * m_dest_bytes_per_pixel;
|
| 2622 |
+
|
| 2623 |
+
m_real_dest_bytes_per_scan_line = (m_image_x_size * m_dest_bytes_per_pixel);
|
| 2624 |
+
|
| 2625 |
+
// Initialize two scan line buffers.
|
| 2626 |
+
m_pScan_line_0 = (uint8 *)alloc(m_dest_bytes_per_scan_line, true);
|
| 2627 |
+
if ((m_scan_type == JPGD_YH1V2) || (m_scan_type == JPGD_YH2V2))
|
| 2628 |
+
m_pScan_line_1 = (uint8 *)alloc(m_dest_bytes_per_scan_line, true);
|
| 2629 |
+
|
| 2630 |
+
m_max_blocks_per_row = m_max_mcus_per_row * m_max_blocks_per_mcu;
|
| 2631 |
+
|
| 2632 |
+
// Should never happen
|
| 2633 |
+
if (m_max_blocks_per_row > JPGD_MAX_BLOCKS_PER_ROW)
|
| 2634 |
+
stop_decoding(JPGD_ASSERTION_ERROR);
|
| 2635 |
+
|
| 2636 |
+
// Allocate the coefficient buffer, enough for one MCU
|
| 2637 |
+
m_pMCU_coefficients = (jpgd_block_t*)alloc(m_max_blocks_per_mcu * 64 * sizeof(jpgd_block_t));
|
| 2638 |
+
|
| 2639 |
+
for (i = 0; i < m_max_blocks_per_mcu; i++)
|
| 2640 |
+
m_mcu_block_max_zag[i] = 64;
|
| 2641 |
+
|
| 2642 |
+
m_expanded_blocks_per_component = m_comp_h_samp[0] * m_comp_v_samp[0];
|
| 2643 |
+
m_expanded_blocks_per_mcu = m_expanded_blocks_per_component * m_comps_in_frame;
|
| 2644 |
+
m_expanded_blocks_per_row = m_max_mcus_per_row * m_expanded_blocks_per_mcu;
|
| 2645 |
+
// Freq. domain chroma upsampling is only supported for H2V2 subsampling factor.
|
| 2646 |
+
// BEGIN EPIC MOD
|
| 2647 |
+
#if JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING
|
| 2648 |
+
m_freq_domain_chroma_upsample = (m_expanded_blocks_per_mcu == 4*3);
|
| 2649 |
+
#else
|
| 2650 |
+
m_freq_domain_chroma_upsample = 0;
|
| 2651 |
+
#endif
|
| 2652 |
+
// END EPIC MOD
|
| 2653 |
+
|
| 2654 |
+
if (m_freq_domain_chroma_upsample)
|
| 2655 |
+
m_pSample_buf = (uint8 *)alloc(m_expanded_blocks_per_row * 64);
|
| 2656 |
+
else
|
| 2657 |
+
m_pSample_buf = (uint8 *)alloc(m_max_blocks_per_row * 64);
|
| 2658 |
+
|
| 2659 |
+
m_total_lines_left = m_image_y_size;
|
| 2660 |
+
|
| 2661 |
+
m_mcu_lines_left = 0;
|
| 2662 |
+
|
| 2663 |
+
create_look_ups();
|
| 2664 |
+
}
|
| 2665 |
+
|
| 2666 |
+
// The coeff_buf series of methods originally stored the coefficients
|
| 2667 |
+
// into a "virtual" file which was located in EMS, XMS, or a disk file. A cache
|
| 2668 |
+
// was used to make this process more efficient. Now, we can store the entire
|
| 2669 |
+
// thing in RAM.
|
| 2670 |
+
jpeg_decoder::coeff_buf* jpeg_decoder::coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y)
|
| 2671 |
+
{
|
| 2672 |
+
coeff_buf* cb = (coeff_buf*)alloc(sizeof(coeff_buf));
|
| 2673 |
+
|
| 2674 |
+
cb->block_num_x = block_num_x;
|
| 2675 |
+
cb->block_num_y = block_num_y;
|
| 2676 |
+
cb->block_len_x = block_len_x;
|
| 2677 |
+
cb->block_len_y = block_len_y;
|
| 2678 |
+
cb->block_size = (block_len_x * block_len_y) * sizeof(jpgd_block_t);
|
| 2679 |
+
cb->pData = (uint8 *)alloc(cb->block_size * block_num_x * block_num_y, true);
|
| 2680 |
+
return cb;
|
| 2681 |
+
}
|
| 2682 |
+
|
| 2683 |
+
inline jpgd_block_t *jpeg_decoder::coeff_buf_getp(coeff_buf *cb, int block_x, int block_y)
|
| 2684 |
+
{
|
| 2685 |
+
JPGD_ASSERT((block_x < cb->block_num_x) && (block_y < cb->block_num_y));
|
| 2686 |
+
return (jpgd_block_t *)(cb->pData + block_x * cb->block_size + block_y * (cb->block_size * cb->block_num_x));
|
| 2687 |
+
}
|
| 2688 |
+
|
| 2689 |
+
// The following methods decode the various types of m_blocks encountered
|
| 2690 |
+
// in progressively encoded images.
|
| 2691 |
+
void jpeg_decoder::decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y)
|
| 2692 |
+
{
|
| 2693 |
+
int s, r;
|
| 2694 |
+
jpgd_block_t *p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y);
|
| 2695 |
+
|
| 2696 |
+
if ((s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_dc_tab[component_id]])) != 0)
|
| 2697 |
+
{
|
| 2698 |
+
r = pD->get_bits_no_markers(s);
|
| 2699 |
+
s = HUFF_EXTEND(r, s);
|
| 2700 |
+
}
|
| 2701 |
+
|
| 2702 |
+
pD->m_last_dc_val[component_id] = (s += pD->m_last_dc_val[component_id]);
|
| 2703 |
+
|
| 2704 |
+
p[0] = static_cast<jpgd_block_t>(s << pD->m_successive_low);
|
| 2705 |
+
}
|
| 2706 |
+
|
| 2707 |
+
void jpeg_decoder::decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y)
|
| 2708 |
+
{
|
| 2709 |
+
if (pD->get_bits_no_markers(1))
|
| 2710 |
+
{
|
| 2711 |
+
jpgd_block_t *p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y);
|
| 2712 |
+
|
| 2713 |
+
p[0] |= (1 << pD->m_successive_low);
|
| 2714 |
+
}
|
| 2715 |
+
}
|
| 2716 |
+
|
| 2717 |
+
void jpeg_decoder::decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y)
|
| 2718 |
+
{
|
| 2719 |
+
int k, s, r;
|
| 2720 |
+
|
| 2721 |
+
if (pD->m_eob_run)
|
| 2722 |
+
{
|
| 2723 |
+
pD->m_eob_run--;
|
| 2724 |
+
return;
|
| 2725 |
+
}
|
| 2726 |
+
|
| 2727 |
+
jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y);
|
| 2728 |
+
|
| 2729 |
+
for (k = pD->m_spectral_start; k <= pD->m_spectral_end; k++)
|
| 2730 |
+
{
|
| 2731 |
+
s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_ac_tab[component_id]]);
|
| 2732 |
+
|
| 2733 |
+
r = s >> 4;
|
| 2734 |
+
s &= 15;
|
| 2735 |
+
|
| 2736 |
+
if (s)
|
| 2737 |
+
{
|
| 2738 |
+
if ((k += r) > 63)
|
| 2739 |
+
pD->stop_decoding(JPGD_DECODE_ERROR);
|
| 2740 |
+
|
| 2741 |
+
r = pD->get_bits_no_markers(s);
|
| 2742 |
+
s = HUFF_EXTEND(r, s);
|
| 2743 |
+
|
| 2744 |
+
p[g_ZAG[k]] = static_cast<jpgd_block_t>(s << pD->m_successive_low);
|
| 2745 |
+
}
|
| 2746 |
+
else
|
| 2747 |
+
{
|
| 2748 |
+
if (r == 15)
|
| 2749 |
+
{
|
| 2750 |
+
if ((k += 15) > 63)
|
| 2751 |
+
pD->stop_decoding(JPGD_DECODE_ERROR);
|
| 2752 |
+
}
|
| 2753 |
+
else
|
| 2754 |
+
{
|
| 2755 |
+
pD->m_eob_run = 1 << r;
|
| 2756 |
+
|
| 2757 |
+
if (r)
|
| 2758 |
+
pD->m_eob_run += pD->get_bits_no_markers(r);
|
| 2759 |
+
|
| 2760 |
+
pD->m_eob_run--;
|
| 2761 |
+
|
| 2762 |
+
break;
|
| 2763 |
+
}
|
| 2764 |
+
}
|
| 2765 |
+
}
|
| 2766 |
+
}
|
| 2767 |
+
|
| 2768 |
+
void jpeg_decoder::decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y)
|
| 2769 |
+
{
|
| 2770 |
+
int s, k, r;
|
| 2771 |
+
int p1 = 1 << pD->m_successive_low;
|
| 2772 |
+
int m1 = (-1) << pD->m_successive_low;
|
| 2773 |
+
jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y);
|
| 2774 |
+
|
| 2775 |
+
k = pD->m_spectral_start;
|
| 2776 |
+
|
| 2777 |
+
if (pD->m_eob_run == 0)
|
| 2778 |
+
{
|
| 2779 |
+
for ( ; k <= pD->m_spectral_end; k++)
|
| 2780 |
+
{
|
| 2781 |
+
s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_ac_tab[component_id]]);
|
| 2782 |
+
|
| 2783 |
+
r = s >> 4;
|
| 2784 |
+
s &= 15;
|
| 2785 |
+
|
| 2786 |
+
if (s)
|
| 2787 |
+
{
|
| 2788 |
+
if (s != 1)
|
| 2789 |
+
pD->stop_decoding(JPGD_DECODE_ERROR);
|
| 2790 |
+
|
| 2791 |
+
if (pD->get_bits_no_markers(1))
|
| 2792 |
+
s = p1;
|
| 2793 |
+
else
|
| 2794 |
+
s = m1;
|
| 2795 |
+
}
|
| 2796 |
+
else
|
| 2797 |
+
{
|
| 2798 |
+
if (r != 15)
|
| 2799 |
+
{
|
| 2800 |
+
pD->m_eob_run = 1 << r;
|
| 2801 |
+
|
| 2802 |
+
if (r)
|
| 2803 |
+
pD->m_eob_run += pD->get_bits_no_markers(r);
|
| 2804 |
+
|
| 2805 |
+
break;
|
| 2806 |
+
}
|
| 2807 |
+
}
|
| 2808 |
+
|
| 2809 |
+
do
|
| 2810 |
+
{
|
| 2811 |
+
// BEGIN EPIC MOD
|
| 2812 |
+
JPGD_ASSERT(k < 64);
|
| 2813 |
+
// END EPIC MOD
|
| 2814 |
+
|
| 2815 |
+
jpgd_block_t *this_coef = p + g_ZAG[k];
|
| 2816 |
+
|
| 2817 |
+
if (*this_coef != 0)
|
| 2818 |
+
{
|
| 2819 |
+
if (pD->get_bits_no_markers(1))
|
| 2820 |
+
{
|
| 2821 |
+
if ((*this_coef & p1) == 0)
|
| 2822 |
+
{
|
| 2823 |
+
if (*this_coef >= 0)
|
| 2824 |
+
*this_coef = static_cast<jpgd_block_t>(*this_coef + p1);
|
| 2825 |
+
else
|
| 2826 |
+
*this_coef = static_cast<jpgd_block_t>(*this_coef + m1);
|
| 2827 |
+
}
|
| 2828 |
+
}
|
| 2829 |
+
}
|
| 2830 |
+
else
|
| 2831 |
+
{
|
| 2832 |
+
if (--r < 0)
|
| 2833 |
+
break;
|
| 2834 |
+
}
|
| 2835 |
+
|
| 2836 |
+
k++;
|
| 2837 |
+
|
| 2838 |
+
} while (k <= pD->m_spectral_end);
|
| 2839 |
+
|
| 2840 |
+
if ((s) && (k < 64))
|
| 2841 |
+
{
|
| 2842 |
+
p[g_ZAG[k]] = static_cast<jpgd_block_t>(s);
|
| 2843 |
+
}
|
| 2844 |
+
}
|
| 2845 |
+
}
|
| 2846 |
+
|
| 2847 |
+
if (pD->m_eob_run > 0)
|
| 2848 |
+
{
|
| 2849 |
+
for ( ; k <= pD->m_spectral_end; k++)
|
| 2850 |
+
{
|
| 2851 |
+
// BEGIN EPIC MOD
|
| 2852 |
+
JPGD_ASSERT(k < 64);
|
| 2853 |
+
// END EPIC MOD
|
| 2854 |
+
|
| 2855 |
+
jpgd_block_t *this_coef = p + g_ZAG[k];
|
| 2856 |
+
|
| 2857 |
+
if (*this_coef != 0)
|
| 2858 |
+
{
|
| 2859 |
+
if (pD->get_bits_no_markers(1))
|
| 2860 |
+
{
|
| 2861 |
+
if ((*this_coef & p1) == 0)
|
| 2862 |
+
{
|
| 2863 |
+
if (*this_coef >= 0)
|
| 2864 |
+
*this_coef = static_cast<jpgd_block_t>(*this_coef + p1);
|
| 2865 |
+
else
|
| 2866 |
+
*this_coef = static_cast<jpgd_block_t>(*this_coef + m1);
|
| 2867 |
+
}
|
| 2868 |
+
}
|
| 2869 |
+
}
|
| 2870 |
+
}
|
| 2871 |
+
|
| 2872 |
+
pD->m_eob_run--;
|
| 2873 |
+
}
|
| 2874 |
+
}
|
| 2875 |
+
|
| 2876 |
+
// Decode a scan in a progressively encoded image.
|
| 2877 |
+
void jpeg_decoder::decode_scan(pDecode_block_func decode_block_func)
|
| 2878 |
+
{
|
| 2879 |
+
int mcu_row, mcu_col, mcu_block;
|
| 2880 |
+
int block_x_mcu[JPGD_MAX_COMPONENTS], m_block_y_mcu[JPGD_MAX_COMPONENTS];
|
| 2881 |
+
|
| 2882 |
+
memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu));
|
| 2883 |
+
|
| 2884 |
+
for (mcu_col = 0; mcu_col < m_mcus_per_col; mcu_col++)
|
| 2885 |
+
{
|
| 2886 |
+
int component_num, component_id;
|
| 2887 |
+
|
| 2888 |
+
memset(block_x_mcu, 0, sizeof(block_x_mcu));
|
| 2889 |
+
|
| 2890 |
+
for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
|
| 2891 |
+
{
|
| 2892 |
+
int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0;
|
| 2893 |
+
|
| 2894 |
+
if ((m_restart_interval) && (m_restarts_left == 0))
|
| 2895 |
+
process_restart();
|
| 2896 |
+
|
| 2897 |
+
for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
|
| 2898 |
+
{
|
| 2899 |
+
component_id = m_mcu_org[mcu_block];
|
| 2900 |
+
|
| 2901 |
+
decode_block_func(this, component_id, block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs);
|
| 2902 |
+
|
| 2903 |
+
if (m_comps_in_scan == 1)
|
| 2904 |
+
block_x_mcu[component_id]++;
|
| 2905 |
+
else
|
| 2906 |
+
{
|
| 2907 |
+
if (++block_x_mcu_ofs == m_comp_h_samp[component_id])
|
| 2908 |
+
{
|
| 2909 |
+
block_x_mcu_ofs = 0;
|
| 2910 |
+
|
| 2911 |
+
if (++block_y_mcu_ofs == m_comp_v_samp[component_id])
|
| 2912 |
+
{
|
| 2913 |
+
block_y_mcu_ofs = 0;
|
| 2914 |
+
block_x_mcu[component_id] += m_comp_h_samp[component_id];
|
| 2915 |
+
}
|
| 2916 |
+
}
|
| 2917 |
+
}
|
| 2918 |
+
}
|
| 2919 |
+
|
| 2920 |
+
m_restarts_left--;
|
| 2921 |
+
}
|
| 2922 |
+
|
| 2923 |
+
if (m_comps_in_scan == 1)
|
| 2924 |
+
m_block_y_mcu[m_comp_list[0]]++;
|
| 2925 |
+
else
|
| 2926 |
+
{
|
| 2927 |
+
for (component_num = 0; component_num < m_comps_in_scan; component_num++)
|
| 2928 |
+
{
|
| 2929 |
+
component_id = m_comp_list[component_num];
|
| 2930 |
+
m_block_y_mcu[component_id] += m_comp_v_samp[component_id];
|
| 2931 |
+
}
|
| 2932 |
+
}
|
| 2933 |
+
}
|
| 2934 |
+
}
|
| 2935 |
+
|
| 2936 |
+
// Decode a progressively encoded image.
|
| 2937 |
+
void jpeg_decoder::init_progressive()
|
| 2938 |
+
{
|
| 2939 |
+
int i;
|
| 2940 |
+
|
| 2941 |
+
if (m_comps_in_frame == 4)
|
| 2942 |
+
stop_decoding(JPGD_UNSUPPORTED_COLORSPACE);
|
| 2943 |
+
|
| 2944 |
+
// Allocate the coefficient buffers.
|
| 2945 |
+
for (i = 0; i < m_comps_in_frame; i++)
|
| 2946 |
+
{
|
| 2947 |
+
m_dc_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 1, 1);
|
| 2948 |
+
m_ac_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 8, 8);
|
| 2949 |
+
}
|
| 2950 |
+
|
| 2951 |
+
for ( ; ; )
|
| 2952 |
+
{
|
| 2953 |
+
int dc_only_scan, refinement_scan;
|
| 2954 |
+
pDecode_block_func decode_block_func;
|
| 2955 |
+
|
| 2956 |
+
if (!init_scan())
|
| 2957 |
+
break;
|
| 2958 |
+
|
| 2959 |
+
dc_only_scan = (m_spectral_start == 0);
|
| 2960 |
+
refinement_scan = (m_successive_high != 0);
|
| 2961 |
+
|
| 2962 |
+
if ((m_spectral_start > m_spectral_end) || (m_spectral_end > 63))
|
| 2963 |
+
stop_decoding(JPGD_BAD_SOS_SPECTRAL);
|
| 2964 |
+
|
| 2965 |
+
if (dc_only_scan)
|
| 2966 |
+
{
|
| 2967 |
+
if (m_spectral_end)
|
| 2968 |
+
stop_decoding(JPGD_BAD_SOS_SPECTRAL);
|
| 2969 |
+
}
|
| 2970 |
+
else if (m_comps_in_scan != 1) /* AC scans can only contain one component */
|
| 2971 |
+
stop_decoding(JPGD_BAD_SOS_SPECTRAL);
|
| 2972 |
+
|
| 2973 |
+
if ((refinement_scan) && (m_successive_low != m_successive_high - 1))
|
| 2974 |
+
stop_decoding(JPGD_BAD_SOS_SUCCESSIVE);
|
| 2975 |
+
|
| 2976 |
+
if (dc_only_scan)
|
| 2977 |
+
{
|
| 2978 |
+
if (refinement_scan)
|
| 2979 |
+
decode_block_func = decode_block_dc_refine;
|
| 2980 |
+
else
|
| 2981 |
+
decode_block_func = decode_block_dc_first;
|
| 2982 |
+
}
|
| 2983 |
+
else
|
| 2984 |
+
{
|
| 2985 |
+
if (refinement_scan)
|
| 2986 |
+
decode_block_func = decode_block_ac_refine;
|
| 2987 |
+
else
|
| 2988 |
+
decode_block_func = decode_block_ac_first;
|
| 2989 |
+
}
|
| 2990 |
+
|
| 2991 |
+
decode_scan(decode_block_func);
|
| 2992 |
+
|
| 2993 |
+
m_bits_left = 16;
|
| 2994 |
+
get_bits(16);
|
| 2995 |
+
get_bits(16);
|
| 2996 |
+
}
|
| 2997 |
+
|
| 2998 |
+
m_comps_in_scan = m_comps_in_frame;
|
| 2999 |
+
|
| 3000 |
+
for (i = 0; i < m_comps_in_frame; i++)
|
| 3001 |
+
m_comp_list[i] = i;
|
| 3002 |
+
|
| 3003 |
+
calc_mcu_block_order();
|
| 3004 |
+
}
|
| 3005 |
+
|
| 3006 |
+
void jpeg_decoder::init_sequential()
|
| 3007 |
+
{
|
| 3008 |
+
if (!init_scan())
|
| 3009 |
+
stop_decoding(JPGD_UNEXPECTED_MARKER);
|
| 3010 |
+
}
|
| 3011 |
+
|
| 3012 |
+
void jpeg_decoder::decode_start()
|
| 3013 |
+
{
|
| 3014 |
+
init_frame();
|
| 3015 |
+
|
| 3016 |
+
if (m_progressive_flag)
|
| 3017 |
+
init_progressive();
|
| 3018 |
+
else
|
| 3019 |
+
init_sequential();
|
| 3020 |
+
}
|
| 3021 |
+
|
| 3022 |
+
void jpeg_decoder::decode_init(jpeg_decoder_stream *pStream)
|
| 3023 |
+
{
|
| 3024 |
+
init(pStream);
|
| 3025 |
+
locate_sof_marker();
|
| 3026 |
+
}
|
| 3027 |
+
|
| 3028 |
+
jpeg_decoder::jpeg_decoder(jpeg_decoder_stream *pStream)
|
| 3029 |
+
{
|
| 3030 |
+
if (setjmp(m_jmp_state))
|
| 3031 |
+
return;
|
| 3032 |
+
decode_init(pStream);
|
| 3033 |
+
}
|
| 3034 |
+
|
| 3035 |
+
int jpeg_decoder::begin_decoding()
|
| 3036 |
+
{
|
| 3037 |
+
if (m_ready_flag)
|
| 3038 |
+
return JPGD_SUCCESS;
|
| 3039 |
+
|
| 3040 |
+
if (m_error_code)
|
| 3041 |
+
return JPGD_FAILED;
|
| 3042 |
+
|
| 3043 |
+
if (setjmp(m_jmp_state))
|
| 3044 |
+
return JPGD_FAILED;
|
| 3045 |
+
|
| 3046 |
+
decode_start();
|
| 3047 |
+
|
| 3048 |
+
m_ready_flag = true;
|
| 3049 |
+
|
| 3050 |
+
return JPGD_SUCCESS;
|
| 3051 |
+
}
|
| 3052 |
+
|
| 3053 |
+
jpeg_decoder::~jpeg_decoder()
|
| 3054 |
+
{
|
| 3055 |
+
free_all_blocks();
|
| 3056 |
+
}
|
| 3057 |
+
|
| 3058 |
+
jpeg_decoder_file_stream::jpeg_decoder_file_stream()
|
| 3059 |
+
{
|
| 3060 |
+
m_pFile = NULL;
|
| 3061 |
+
m_eof_flag = false;
|
| 3062 |
+
m_error_flag = false;
|
| 3063 |
+
}
|
| 3064 |
+
|
| 3065 |
+
void jpeg_decoder_file_stream::close()
|
| 3066 |
+
{
|
| 3067 |
+
if (m_pFile)
|
| 3068 |
+
{
|
| 3069 |
+
fclose(m_pFile);
|
| 3070 |
+
m_pFile = NULL;
|
| 3071 |
+
}
|
| 3072 |
+
|
| 3073 |
+
m_eof_flag = false;
|
| 3074 |
+
m_error_flag = false;
|
| 3075 |
+
}
|
| 3076 |
+
|
| 3077 |
+
jpeg_decoder_file_stream::~jpeg_decoder_file_stream()
|
| 3078 |
+
{
|
| 3079 |
+
close();
|
| 3080 |
+
}
|
| 3081 |
+
|
| 3082 |
+
bool jpeg_decoder_file_stream::open(const char *Pfilename)
|
| 3083 |
+
{
|
| 3084 |
+
close();
|
| 3085 |
+
|
| 3086 |
+
m_eof_flag = false;
|
| 3087 |
+
m_error_flag = false;
|
| 3088 |
+
|
| 3089 |
+
#if defined(_MSC_VER)
|
| 3090 |
+
m_pFile = NULL;
|
| 3091 |
+
fopen_s(&m_pFile, Pfilename, "rb");
|
| 3092 |
+
#else
|
| 3093 |
+
m_pFile = fopen(Pfilename, "rb");
|
| 3094 |
+
#endif
|
| 3095 |
+
return m_pFile != NULL;
|
| 3096 |
+
}
|
| 3097 |
+
|
| 3098 |
+
int jpeg_decoder_file_stream::read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag)
|
| 3099 |
+
{
|
| 3100 |
+
if (!m_pFile)
|
| 3101 |
+
return -1;
|
| 3102 |
+
|
| 3103 |
+
if (m_eof_flag)
|
| 3104 |
+
{
|
| 3105 |
+
*pEOF_flag = true;
|
| 3106 |
+
return 0;
|
| 3107 |
+
}
|
| 3108 |
+
|
| 3109 |
+
if (m_error_flag)
|
| 3110 |
+
return -1;
|
| 3111 |
+
|
| 3112 |
+
int bytes_read = static_cast<int>(fread(pBuf, 1, max_bytes_to_read, m_pFile));
|
| 3113 |
+
if (bytes_read < max_bytes_to_read)
|
| 3114 |
+
{
|
| 3115 |
+
if (ferror(m_pFile))
|
| 3116 |
+
{
|
| 3117 |
+
m_error_flag = true;
|
| 3118 |
+
return -1;
|
| 3119 |
+
}
|
| 3120 |
+
|
| 3121 |
+
m_eof_flag = true;
|
| 3122 |
+
*pEOF_flag = true;
|
| 3123 |
+
}
|
| 3124 |
+
|
| 3125 |
+
return bytes_read;
|
| 3126 |
+
}
|
| 3127 |
+
|
| 3128 |
+
bool jpeg_decoder_mem_stream::open(const uint8 *pSrc_data, uint size)
|
| 3129 |
+
{
|
| 3130 |
+
close();
|
| 3131 |
+
m_pSrc_data = pSrc_data;
|
| 3132 |
+
m_ofs = 0;
|
| 3133 |
+
m_size = size;
|
| 3134 |
+
return true;
|
| 3135 |
+
}
|
| 3136 |
+
|
| 3137 |
+
int jpeg_decoder_mem_stream::read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag)
|
| 3138 |
+
{
|
| 3139 |
+
*pEOF_flag = false;
|
| 3140 |
+
|
| 3141 |
+
if (!m_pSrc_data)
|
| 3142 |
+
return -1;
|
| 3143 |
+
|
| 3144 |
+
uint bytes_remaining = m_size - m_ofs;
|
| 3145 |
+
if ((uint)max_bytes_to_read > bytes_remaining)
|
| 3146 |
+
{
|
| 3147 |
+
max_bytes_to_read = bytes_remaining;
|
| 3148 |
+
*pEOF_flag = true;
|
| 3149 |
+
}
|
| 3150 |
+
|
| 3151 |
+
memcpy(pBuf, m_pSrc_data + m_ofs, max_bytes_to_read);
|
| 3152 |
+
m_ofs += max_bytes_to_read;
|
| 3153 |
+
|
| 3154 |
+
return max_bytes_to_read;
|
| 3155 |
+
}
|
| 3156 |
+
|
| 3157 |
+
unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps)
|
| 3158 |
+
{
|
| 3159 |
+
if (!actual_comps)
|
| 3160 |
+
return NULL;
|
| 3161 |
+
*actual_comps = 0;
|
| 3162 |
+
|
| 3163 |
+
if ((!pStream) || (!width) || (!height) || (!req_comps))
|
| 3164 |
+
return NULL;
|
| 3165 |
+
|
| 3166 |
+
if ((req_comps != 1) && (req_comps != 3) && (req_comps != 4))
|
| 3167 |
+
return NULL;
|
| 3168 |
+
|
| 3169 |
+
jpeg_decoder decoder(pStream);
|
| 3170 |
+
if (decoder.get_error_code() != JPGD_SUCCESS)
|
| 3171 |
+
return NULL;
|
| 3172 |
+
|
| 3173 |
+
const int image_width = decoder.get_width(), image_height = decoder.get_height();
|
| 3174 |
+
*width = image_width;
|
| 3175 |
+
*height = image_height;
|
| 3176 |
+
*actual_comps = decoder.get_num_components();
|
| 3177 |
+
|
| 3178 |
+
if (decoder.begin_decoding() != JPGD_SUCCESS)
|
| 3179 |
+
return NULL;
|
| 3180 |
+
|
| 3181 |
+
const int dst_bpl = image_width * req_comps;
|
| 3182 |
+
|
| 3183 |
+
uint8 *pImage_data = (uint8*)jpgd_malloc(dst_bpl * image_height);
|
| 3184 |
+
if (!pImage_data)
|
| 3185 |
+
return NULL;
|
| 3186 |
+
|
| 3187 |
+
for (int y = 0; y < image_height; y++)
|
| 3188 |
+
{
|
| 3189 |
+
const uint8* pScan_line = 0;
|
| 3190 |
+
uint scan_line_len;
|
| 3191 |
+
if (decoder.decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS)
|
| 3192 |
+
{
|
| 3193 |
+
jpgd_free(pImage_data);
|
| 3194 |
+
return NULL;
|
| 3195 |
+
}
|
| 3196 |
+
|
| 3197 |
+
uint8 *pDst = pImage_data + y * dst_bpl;
|
| 3198 |
+
|
| 3199 |
+
if (((req_comps == 4) && (decoder.get_num_components() == 3)) ||
|
| 3200 |
+
((req_comps == 1) && (decoder.get_num_components() == 1)))
|
| 3201 |
+
{
|
| 3202 |
+
memcpy(pDst, pScan_line, dst_bpl);
|
| 3203 |
+
}
|
| 3204 |
+
else if (decoder.get_num_components() == 1)
|
| 3205 |
+
{
|
| 3206 |
+
if (req_comps == 3)
|
| 3207 |
+
{
|
| 3208 |
+
for (int x = 0; x < image_width; x++)
|
| 3209 |
+
{
|
| 3210 |
+
uint8 luma = pScan_line[x];
|
| 3211 |
+
pDst[0] = luma;
|
| 3212 |
+
pDst[1] = luma;
|
| 3213 |
+
pDst[2] = luma;
|
| 3214 |
+
pDst += 3;
|
| 3215 |
+
}
|
| 3216 |
+
}
|
| 3217 |
+
else
|
| 3218 |
+
{
|
| 3219 |
+
for (int x = 0; x < image_width; x++)
|
| 3220 |
+
{
|
| 3221 |
+
uint8 luma = pScan_line[x];
|
| 3222 |
+
pDst[0] = luma;
|
| 3223 |
+
pDst[1] = luma;
|
| 3224 |
+
pDst[2] = luma;
|
| 3225 |
+
pDst[3] = 255;
|
| 3226 |
+
pDst += 4;
|
| 3227 |
+
}
|
| 3228 |
+
}
|
| 3229 |
+
}
|
| 3230 |
+
else if (decoder.get_num_components() == 3)
|
| 3231 |
+
{
|
| 3232 |
+
if (req_comps == 1)
|
| 3233 |
+
{
|
| 3234 |
+
const int YR = 19595, YG = 38470, YB = 7471;
|
| 3235 |
+
for (int x = 0; x < image_width; x++)
|
| 3236 |
+
{
|
| 3237 |
+
int r = pScan_line[x*4+0];
|
| 3238 |
+
int g = pScan_line[x*4+1];
|
| 3239 |
+
int b = pScan_line[x*4+2];
|
| 3240 |
+
*pDst++ = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16);
|
| 3241 |
+
}
|
| 3242 |
+
}
|
| 3243 |
+
else
|
| 3244 |
+
{
|
| 3245 |
+
for (int x = 0; x < image_width; x++)
|
| 3246 |
+
{
|
| 3247 |
+
pDst[0] = pScan_line[x*4+0];
|
| 3248 |
+
pDst[1] = pScan_line[x*4+1];
|
| 3249 |
+
pDst[2] = pScan_line[x*4+2];
|
| 3250 |
+
pDst += 3;
|
| 3251 |
+
}
|
| 3252 |
+
}
|
| 3253 |
+
}
|
| 3254 |
+
}
|
| 3255 |
+
|
| 3256 |
+
return pImage_data;
|
| 3257 |
+
}
|
| 3258 |
+
|
| 3259 |
+
// BEGIN EPIC MOD
|
| 3260 |
+
unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps, int format)
|
| 3261 |
+
{
|
| 3262 |
+
jpg_format = (ERGBFormatJPG)format;
|
| 3263 |
+
// EMD EPIC MOD
|
| 3264 |
+
jpgd::jpeg_decoder_mem_stream mem_stream(pSrc_data, src_data_size);
|
| 3265 |
+
return decompress_jpeg_image_from_stream(&mem_stream, width, height, actual_comps, req_comps);
|
| 3266 |
+
}
|
| 3267 |
+
|
| 3268 |
+
unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps)
|
| 3269 |
+
{
|
| 3270 |
+
jpgd::jpeg_decoder_file_stream file_stream;
|
| 3271 |
+
if (!file_stream.open(pSrc_filename))
|
| 3272 |
+
return NULL;
|
| 3273 |
+
return decompress_jpeg_image_from_stream(&file_stream, width, height, actual_comps, req_comps);
|
| 3274 |
+
}
|
| 3275 |
+
|
| 3276 |
+
} // namespace jpgd
|
crazy_functions/test_project/cpp/longcode/jpge.cpp
ADDED
|
@@ -0,0 +1,1049 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// jpge.cpp - C++ class for JPEG compression.
|
| 2 |
+
// Public domain, Rich Geldreich <[email protected]>
|
| 3 |
+
// v1.01, Dec. 18, 2010 - Initial release
|
| 4 |
+
// v1.02, Apr. 6, 2011 - Removed 2x2 ordered dither in H2V1 chroma subsampling method load_block_16_8_8(). (The rounding factor was 2, when it should have been 1. Either way, it wasn't helping.)
|
| 5 |
+
// v1.03, Apr. 16, 2011 - Added support for optimized Huffman code tables, optimized dynamic memory allocation down to only 1 alloc.
|
| 6 |
+
// Also from Alex Evans: Added RGBA support, linear memory allocator (no longer needed in v1.03).
|
| 7 |
+
// v1.04, May. 19, 2012: Forgot to set m_pFile ptr to NULL in cfile_stream::close(). Thanks to Owen Kaluza for reporting this bug.
|
| 8 |
+
// Code tweaks to fix VS2008 static code analysis warnings (all looked harmless).
|
| 9 |
+
// Code review revealed method load_block_16_8_8() (used for the non-default H2V1 sampling mode to downsample chroma) somehow didn't get the rounding factor fix from v1.02.
|
| 10 |
+
|
| 11 |
+
#include "jpge.h"
|
| 12 |
+
|
| 13 |
+
#include <stdlib.h>
|
| 14 |
+
#include <string.h>
|
| 15 |
+
#if PLATFORM_WINDOWS
|
| 16 |
+
#include <malloc.h>
|
| 17 |
+
#endif
|
| 18 |
+
|
| 19 |
+
#define JPGE_MAX(a,b) (((a)>(b))?(a):(b))
|
| 20 |
+
#define JPGE_MIN(a,b) (((a)<(b))?(a):(b))
|
| 21 |
+
|
| 22 |
+
namespace jpge {
|
| 23 |
+
|
| 24 |
+
static inline void *jpge_malloc(size_t nSize) { return FMemory::Malloc(nSize); }
|
| 25 |
+
static inline void jpge_free(void *p) { FMemory::Free(p);; }
|
| 26 |
+
|
| 27 |
+
// Various JPEG enums and tables.
|
| 28 |
+
enum { M_SOF0 = 0xC0, M_DHT = 0xC4, M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_APP0 = 0xE0 };
|
| 29 |
+
enum { DC_LUM_CODES = 12, AC_LUM_CODES = 256, DC_CHROMA_CODES = 12, AC_CHROMA_CODES = 256, MAX_HUFF_SYMBOLS = 257, MAX_HUFF_CODESIZE = 32 };
|
| 30 |
+
|
| 31 |
+
static uint8 s_zag[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 };
|
| 32 |
+
static int16 s_std_lum_quant[64] = { 16,11,12,14,12,10,16,14,13,14,18,17,16,19,24,40,26,24,22,22,24,49,35,37,29,40,58,51,61,60,57,51,56,55,64,72,92,78,64,68,87,69,55,56,80,109,81,87,95,98,103,104,103,62,77,113,121,112,100,120,92,101,103,99 };
|
| 33 |
+
static int16 s_std_croma_quant[64] = { 17,18,18,24,21,24,47,26,26,47,99,66,56,66,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99 };
|
| 34 |
+
static uint8 s_dc_lum_bits[17] = { 0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 };
|
| 35 |
+
static uint8 s_dc_lum_val[DC_LUM_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
|
| 36 |
+
static uint8 s_ac_lum_bits[17] = { 0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d };
|
| 37 |
+
static uint8 s_ac_lum_val[AC_LUM_CODES] =
|
| 38 |
+
{
|
| 39 |
+
0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
|
| 40 |
+
0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
|
| 41 |
+
0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
|
| 42 |
+
0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
|
| 43 |
+
0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
|
| 44 |
+
0xf9,0xfa
|
| 45 |
+
};
|
| 46 |
+
static uint8 s_dc_chroma_bits[17] = { 0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 };
|
| 47 |
+
static uint8 s_dc_chroma_val[DC_CHROMA_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
|
| 48 |
+
static uint8 s_ac_chroma_bits[17] = { 0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77 };
|
| 49 |
+
static uint8 s_ac_chroma_val[AC_CHROMA_CODES] =
|
| 50 |
+
{
|
| 51 |
+
0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,
|
| 52 |
+
0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,
|
| 53 |
+
0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
|
| 54 |
+
0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,
|
| 55 |
+
0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
|
| 56 |
+
0xf9,0xfa
|
| 57 |
+
};
|
| 58 |
+
|
| 59 |
+
// Low-level helper functions.
|
| 60 |
+
template <class T> inline void clear_obj(T &obj) { memset(&obj, 0, sizeof(obj)); }
|
| 61 |
+
|
| 62 |
+
const int YR = 19595, YG = 38470, YB = 7471, CB_R = -11059, CB_G = -21709, CB_B = 32768, CR_R = 32768, CR_G = -27439, CR_B = -5329;
|
| 63 |
+
static inline uint8 clamp(int i) { if (static_cast<uint>(i) > 255U) { if (i < 0) i = 0; else if (i > 255) i = 255; } return static_cast<uint8>(i); }
|
| 64 |
+
|
| 65 |
+
static void RGB_to_YCC(uint8* pDst, const uint8 *pSrc, int num_pixels)
|
| 66 |
+
{
|
| 67 |
+
for ( ; num_pixels; pDst += 3, pSrc += 3, num_pixels--)
|
| 68 |
+
{
|
| 69 |
+
const int r = pSrc[0], g = pSrc[1], b = pSrc[2];
|
| 70 |
+
pDst[0] = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16);
|
| 71 |
+
pDst[1] = clamp(128 + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16));
|
| 72 |
+
pDst[2] = clamp(128 + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16));
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
static void RGB_to_Y(uint8* pDst, const uint8 *pSrc, int num_pixels)
|
| 77 |
+
{
|
| 78 |
+
for ( ; num_pixels; pDst++, pSrc += 3, num_pixels--)
|
| 79 |
+
pDst[0] = static_cast<uint8>((pSrc[0] * YR + pSrc[1] * YG + pSrc[2] * YB + 32768) >> 16);
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
static void RGBA_to_YCC(uint8* pDst, const uint8 *pSrc, int num_pixels)
|
| 83 |
+
{
|
| 84 |
+
for ( ; num_pixels; pDst += 3, pSrc += 4, num_pixels--)
|
| 85 |
+
{
|
| 86 |
+
const int r = pSrc[0], g = pSrc[1], b = pSrc[2];
|
| 87 |
+
pDst[0] = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16);
|
| 88 |
+
pDst[1] = clamp(128 + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16));
|
| 89 |
+
pDst[2] = clamp(128 + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16));
|
| 90 |
+
}
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
static void RGBA_to_Y(uint8* pDst, const uint8 *pSrc, int num_pixels)
|
| 94 |
+
{
|
| 95 |
+
for ( ; num_pixels; pDst++, pSrc += 4, num_pixels--)
|
| 96 |
+
pDst[0] = static_cast<uint8>((pSrc[0] * YR + pSrc[1] * YG + pSrc[2] * YB + 32768) >> 16);
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
static void Y_to_YCC(uint8* pDst, const uint8* pSrc, int num_pixels)
|
| 100 |
+
{
|
| 101 |
+
for( ; num_pixels; pDst += 3, pSrc++, num_pixels--) { pDst[0] = pSrc[0]; pDst[1] = 128; pDst[2] = 128; }
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
// Forward DCT - DCT derived from jfdctint.
|
| 105 |
+
#define CONST_BITS 13
|
| 106 |
+
#define ROW_BITS 2
|
| 107 |
+
#define DCT_DESCALE(x, n) (((x) + (((int32)1) << ((n) - 1))) >> (n))
|
| 108 |
+
#define DCT_MUL(var, c) (static_cast<int16>(var) * static_cast<int32>(c))
|
| 109 |
+
#define DCT1D(s0, s1, s2, s3, s4, s5, s6, s7) \
|
| 110 |
+
int32 t0 = s0 + s7, t7 = s0 - s7, t1 = s1 + s6, t6 = s1 - s6, t2 = s2 + s5, t5 = s2 - s5, t3 = s3 + s4, t4 = s3 - s4; \
|
| 111 |
+
int32 t10 = t0 + t3, t13 = t0 - t3, t11 = t1 + t2, t12 = t1 - t2; \
|
| 112 |
+
int32 u1 = DCT_MUL(t12 + t13, 4433); \
|
| 113 |
+
s2 = u1 + DCT_MUL(t13, 6270); \
|
| 114 |
+
s6 = u1 + DCT_MUL(t12, -15137); \
|
| 115 |
+
u1 = t4 + t7; \
|
| 116 |
+
int32 u2 = t5 + t6, u3 = t4 + t6, u4 = t5 + t7; \
|
| 117 |
+
int32 z5 = DCT_MUL(u3 + u4, 9633); \
|
| 118 |
+
t4 = DCT_MUL(t4, 2446); t5 = DCT_MUL(t5, 16819); \
|
| 119 |
+
t6 = DCT_MUL(t6, 25172); t7 = DCT_MUL(t7, 12299); \
|
| 120 |
+
u1 = DCT_MUL(u1, -7373); u2 = DCT_MUL(u2, -20995); \
|
| 121 |
+
u3 = DCT_MUL(u3, -16069); u4 = DCT_MUL(u4, -3196); \
|
| 122 |
+
u3 += z5; u4 += z5; \
|
| 123 |
+
s0 = t10 + t11; s1 = t7 + u1 + u4; s3 = t6 + u2 + u3; s4 = t10 - t11; s5 = t5 + u2 + u4; s7 = t4 + u1 + u3;
|
| 124 |
+
|
| 125 |
+
static void DCT2D(int32 *p)
|
| 126 |
+
{
|
| 127 |
+
int32 c, *q = p;
|
| 128 |
+
for (c = 7; c >= 0; c--, q += 8)
|
| 129 |
+
{
|
| 130 |
+
int32 s0 = q[0], s1 = q[1], s2 = q[2], s3 = q[3], s4 = q[4], s5 = q[5], s6 = q[6], s7 = q[7];
|
| 131 |
+
DCT1D(s0, s1, s2, s3, s4, s5, s6, s7);
|
| 132 |
+
q[0] = s0 << ROW_BITS; q[1] = DCT_DESCALE(s1, CONST_BITS-ROW_BITS); q[2] = DCT_DESCALE(s2, CONST_BITS-ROW_BITS); q[3] = DCT_DESCALE(s3, CONST_BITS-ROW_BITS);
|
| 133 |
+
q[4] = s4 << ROW_BITS; q[5] = DCT_DESCALE(s5, CONST_BITS-ROW_BITS); q[6] = DCT_DESCALE(s6, CONST_BITS-ROW_BITS); q[7] = DCT_DESCALE(s7, CONST_BITS-ROW_BITS);
|
| 134 |
+
}
|
| 135 |
+
for (q = p, c = 7; c >= 0; c--, q++)
|
| 136 |
+
{
|
| 137 |
+
int32 s0 = q[0*8], s1 = q[1*8], s2 = q[2*8], s3 = q[3*8], s4 = q[4*8], s5 = q[5*8], s6 = q[6*8], s7 = q[7*8];
|
| 138 |
+
DCT1D(s0, s1, s2, s3, s4, s5, s6, s7);
|
| 139 |
+
q[0*8] = DCT_DESCALE(s0, ROW_BITS+3); q[1*8] = DCT_DESCALE(s1, CONST_BITS+ROW_BITS+3); q[2*8] = DCT_DESCALE(s2, CONST_BITS+ROW_BITS+3); q[3*8] = DCT_DESCALE(s3, CONST_BITS+ROW_BITS+3);
|
| 140 |
+
q[4*8] = DCT_DESCALE(s4, ROW_BITS+3); q[5*8] = DCT_DESCALE(s5, CONST_BITS+ROW_BITS+3); q[6*8] = DCT_DESCALE(s6, CONST_BITS+ROW_BITS+3); q[7*8] = DCT_DESCALE(s7, CONST_BITS+ROW_BITS+3);
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
struct sym_freq { uint m_key, m_sym_index; };
|
| 145 |
+
|
| 146 |
+
// Radix sorts sym_freq[] array by 32-bit key m_key. Returns ptr to sorted values.
|
| 147 |
+
static inline sym_freq* radix_sort_syms(uint num_syms, sym_freq* pSyms0, sym_freq* pSyms1)
|
| 148 |
+
{
|
| 149 |
+
const uint cMaxPasses = 4;
|
| 150 |
+
uint32 hist[256 * cMaxPasses]; clear_obj(hist);
|
| 151 |
+
for (uint i = 0; i < num_syms; i++) { uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; hist[256*2 + ((freq >> 16) & 0xFF)]++; hist[256*3 + ((freq >> 24) & 0xFF)]++; }
|
| 152 |
+
sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1;
|
| 153 |
+
uint total_passes = cMaxPasses; while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--;
|
| 154 |
+
for (uint pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8)
|
| 155 |
+
{
|
| 156 |
+
const uint32* pHist = &hist[pass << 8];
|
| 157 |
+
uint offsets[256], cur_ofs = 0;
|
| 158 |
+
for (uint i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; }
|
| 159 |
+
for (uint i = 0; i < num_syms; i++)
|
| 160 |
+
pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i];
|
| 161 |
+
sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t;
|
| 162 |
+
}
|
| 163 |
+
return pCur_syms;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
// calculate_minimum_redundancy() originally written by: Alistair Moffat, [email protected], Jyrki Katajainen, [email protected], November 1996.
|
| 167 |
+
static void calculate_minimum_redundancy(sym_freq *A, int n)
|
| 168 |
+
{
|
| 169 |
+
int root, leaf, next, avbl, used, dpth;
|
| 170 |
+
if (n==0) return; else if (n==1) { A[0].m_key = 1; return; }
|
| 171 |
+
A[0].m_key += A[1].m_key; root = 0; leaf = 2;
|
| 172 |
+
for (next=1; next < n-1; next++)
|
| 173 |
+
{
|
| 174 |
+
if (leaf>=n || A[root].m_key<A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = next; } else A[next].m_key = A[leaf++].m_key;
|
| 175 |
+
if (leaf>=n || (root<next && A[root].m_key<A[leaf].m_key)) { A[next].m_key += A[root].m_key; A[root++].m_key = next; } else A[next].m_key += A[leaf++].m_key;
|
| 176 |
+
}
|
| 177 |
+
A[n-2].m_key = 0;
|
| 178 |
+
for (next=n-3; next>=0; next--) A[next].m_key = A[A[next].m_key].m_key+1;
|
| 179 |
+
avbl = 1; used = dpth = 0; root = n-2; next = n-1;
|
| 180 |
+
while (avbl>0)
|
| 181 |
+
{
|
| 182 |
+
while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; }
|
| 183 |
+
while (avbl>used) { A[next--].m_key = dpth; avbl--; }
|
| 184 |
+
avbl = 2*used; dpth++; used = 0;
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
// Limits canonical Huffman code table's max code size to max_code_size.
|
| 189 |
+
static void huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size)
|
| 190 |
+
{
|
| 191 |
+
if (code_list_len <= 1) return;
|
| 192 |
+
|
| 193 |
+
for (int i = max_code_size + 1; i <= MAX_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i];
|
| 194 |
+
|
| 195 |
+
uint32 total = 0;
|
| 196 |
+
for (int i = max_code_size; i > 0; i--)
|
| 197 |
+
total += (((uint32)pNum_codes[i]) << (max_code_size - i));
|
| 198 |
+
|
| 199 |
+
while (total != (1UL << max_code_size))
|
| 200 |
+
{
|
| 201 |
+
pNum_codes[max_code_size]--;
|
| 202 |
+
for (int i = max_code_size - 1; i > 0; i--)
|
| 203 |
+
{
|
| 204 |
+
if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; }
|
| 205 |
+
}
|
| 206 |
+
total--;
|
| 207 |
+
}
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
// Generates an optimized offman table.
|
| 211 |
+
void jpeg_encoder::optimize_huffman_table(int table_num, int table_len)
|
| 212 |
+
{
|
| 213 |
+
sym_freq syms0[MAX_HUFF_SYMBOLS], syms1[MAX_HUFF_SYMBOLS];
|
| 214 |
+
syms0[0].m_key = 1; syms0[0].m_sym_index = 0; // dummy symbol, assures that no valid code contains all 1's
|
| 215 |
+
int num_used_syms = 1;
|
| 216 |
+
const uint32 *pSym_count = &m_huff_count[table_num][0];
|
| 217 |
+
for (int i = 0; i < table_len; i++)
|
| 218 |
+
if (pSym_count[i]) { syms0[num_used_syms].m_key = pSym_count[i]; syms0[num_used_syms++].m_sym_index = i + 1; }
|
| 219 |
+
sym_freq* pSyms = radix_sort_syms(num_used_syms, syms0, syms1);
|
| 220 |
+
calculate_minimum_redundancy(pSyms, num_used_syms);
|
| 221 |
+
|
| 222 |
+
// Count the # of symbols of each code size.
|
| 223 |
+
int num_codes[1 + MAX_HUFF_CODESIZE]; clear_obj(num_codes);
|
| 224 |
+
for (int i = 0; i < num_used_syms; i++)
|
| 225 |
+
num_codes[pSyms[i].m_key]++;
|
| 226 |
+
|
| 227 |
+
const uint JPGE_CODE_SIZE_LIMIT = 16; // the maximum possible size of a JPEG Huffman code (valid range is [9,16] - 9 vs. 8 because of the dummy symbol)
|
| 228 |
+
huffman_enforce_max_code_size(num_codes, num_used_syms, JPGE_CODE_SIZE_LIMIT);
|
| 229 |
+
|
| 230 |
+
// Compute m_huff_bits array, which contains the # of symbols per code size.
|
| 231 |
+
clear_obj(m_huff_bits[table_num]);
|
| 232 |
+
for (int i = 1; i <= (int)JPGE_CODE_SIZE_LIMIT; i++)
|
| 233 |
+
m_huff_bits[table_num][i] = static_cast<uint8>(num_codes[i]);
|
| 234 |
+
|
| 235 |
+
// Remove the dummy symbol added above, which must be in largest bucket.
|
| 236 |
+
for (int i = JPGE_CODE_SIZE_LIMIT; i >= 1; i--)
|
| 237 |
+
{
|
| 238 |
+
if (m_huff_bits[table_num][i]) { m_huff_bits[table_num][i]--; break; }
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
// Compute the m_huff_val array, which contains the symbol indices sorted by code size (smallest to largest).
|
| 242 |
+
for (int i = num_used_syms - 1; i >= 1; i--)
|
| 243 |
+
m_huff_val[table_num][num_used_syms - 1 - i] = static_cast<uint8>(pSyms[i].m_sym_index - 1);
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
// JPEG marker generation.
|
| 247 |
+
void jpeg_encoder::emit_byte(uint8 i)
|
| 248 |
+
{
|
| 249 |
+
m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_obj(i);
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
void jpeg_encoder::emit_word(uint i)
|
| 253 |
+
{
|
| 254 |
+
emit_byte(uint8(i >> 8)); emit_byte(uint8(i & 0xFF));
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
void jpeg_encoder::emit_marker(int marker)
|
| 258 |
+
{
|
| 259 |
+
emit_byte(uint8(0xFF)); emit_byte(uint8(marker));
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
// Emit JFIF marker
|
| 263 |
+
void jpeg_encoder::emit_jfif_app0()
|
| 264 |
+
{
|
| 265 |
+
emit_marker(M_APP0);
|
| 266 |
+
emit_word(2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1);
|
| 267 |
+
emit_byte(0x4A); emit_byte(0x46); emit_byte(0x49); emit_byte(0x46); /* Identifier: ASCII "JFIF" */
|
| 268 |
+
emit_byte(0);
|
| 269 |
+
emit_byte(1); /* Major version */
|
| 270 |
+
emit_byte(1); /* Minor version */
|
| 271 |
+
emit_byte(0); /* Density unit */
|
| 272 |
+
emit_word(1);
|
| 273 |
+
emit_word(1);
|
| 274 |
+
emit_byte(0); /* No thumbnail image */
|
| 275 |
+
emit_byte(0);
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
// Emit quantization tables
|
| 279 |
+
void jpeg_encoder::emit_dqt()
|
| 280 |
+
{
|
| 281 |
+
for (int i = 0; i < ((m_num_components == 3) ? 2 : 1); i++)
|
| 282 |
+
{
|
| 283 |
+
emit_marker(M_DQT);
|
| 284 |
+
emit_word(64 + 1 + 2);
|
| 285 |
+
emit_byte(static_cast<uint8>(i));
|
| 286 |
+
for (int j = 0; j < 64; j++)
|
| 287 |
+
emit_byte(static_cast<uint8>(m_quantization_tables[i][j]));
|
| 288 |
+
}
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
// Emit start of frame marker
|
| 292 |
+
void jpeg_encoder::emit_sof()
|
| 293 |
+
{
|
| 294 |
+
emit_marker(M_SOF0); /* baseline */
|
| 295 |
+
emit_word(3 * m_num_components + 2 + 5 + 1);
|
| 296 |
+
emit_byte(8); /* precision */
|
| 297 |
+
emit_word(m_image_y);
|
| 298 |
+
emit_word(m_image_x);
|
| 299 |
+
emit_byte(m_num_components);
|
| 300 |
+
for (int i = 0; i < m_num_components; i++)
|
| 301 |
+
{
|
| 302 |
+
emit_byte(static_cast<uint8>(i + 1)); /* component ID */
|
| 303 |
+
emit_byte((m_comp_h_samp[i] << 4) + m_comp_v_samp[i]); /* h and v sampling */
|
| 304 |
+
emit_byte(i > 0); /* quant. table num */
|
| 305 |
+
}
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
// Emit Huffman table.
|
| 309 |
+
void jpeg_encoder::emit_dht(uint8 *bits, uint8 *val, int index, bool ac_flag)
|
| 310 |
+
{
|
| 311 |
+
emit_marker(M_DHT);
|
| 312 |
+
|
| 313 |
+
int length = 0;
|
| 314 |
+
for (int i = 1; i <= 16; i++)
|
| 315 |
+
length += bits[i];
|
| 316 |
+
|
| 317 |
+
emit_word(length + 2 + 1 + 16);
|
| 318 |
+
emit_byte(static_cast<uint8>(index + (ac_flag << 4)));
|
| 319 |
+
|
| 320 |
+
for (int i = 1; i <= 16; i++)
|
| 321 |
+
emit_byte(bits[i]);
|
| 322 |
+
|
| 323 |
+
for (int i = 0; i < length; i++)
|
| 324 |
+
emit_byte(val[i]);
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
// Emit all Huffman tables.
|
| 328 |
+
void jpeg_encoder::emit_dhts()
|
| 329 |
+
{
|
| 330 |
+
emit_dht(m_huff_bits[0+0], m_huff_val[0+0], 0, false);
|
| 331 |
+
emit_dht(m_huff_bits[2+0], m_huff_val[2+0], 0, true);
|
| 332 |
+
if (m_num_components == 3)
|
| 333 |
+
{
|
| 334 |
+
emit_dht(m_huff_bits[0+1], m_huff_val[0+1], 1, false);
|
| 335 |
+
emit_dht(m_huff_bits[2+1], m_huff_val[2+1], 1, true);
|
| 336 |
+
}
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
// emit start of scan
|
| 340 |
+
void jpeg_encoder::emit_sos()
|
| 341 |
+
{
|
| 342 |
+
emit_marker(M_SOS);
|
| 343 |
+
emit_word(2 * m_num_components + 2 + 1 + 3);
|
| 344 |
+
emit_byte(m_num_components);
|
| 345 |
+
for (int i = 0; i < m_num_components; i++)
|
| 346 |
+
{
|
| 347 |
+
emit_byte(static_cast<uint8>(i + 1));
|
| 348 |
+
if (i == 0)
|
| 349 |
+
emit_byte((0 << 4) + 0);
|
| 350 |
+
else
|
| 351 |
+
emit_byte((1 << 4) + 1);
|
| 352 |
+
}
|
| 353 |
+
emit_byte(0); /* spectral selection */
|
| 354 |
+
emit_byte(63);
|
| 355 |
+
emit_byte(0);
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
// Emit all markers at beginning of image file.
|
| 359 |
+
void jpeg_encoder::emit_markers()
|
| 360 |
+
{
|
| 361 |
+
emit_marker(M_SOI);
|
| 362 |
+
emit_jfif_app0();
|
| 363 |
+
emit_dqt();
|
| 364 |
+
emit_sof();
|
| 365 |
+
emit_dhts();
|
| 366 |
+
emit_sos();
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
// Compute the actual canonical Huffman codes/code sizes given the JPEG huff bits and val arrays.
|
| 370 |
+
void jpeg_encoder::compute_huffman_table(uint *codes, uint8 *code_sizes, uint8 *bits, uint8 *val)
|
| 371 |
+
{
|
| 372 |
+
int i, l, last_p, si;
|
| 373 |
+
uint8 huff_size[257];
|
| 374 |
+
uint huff_code[257];
|
| 375 |
+
uint code;
|
| 376 |
+
|
| 377 |
+
int p = 0;
|
| 378 |
+
for (l = 1; l <= 16; l++)
|
| 379 |
+
for (i = 1; i <= bits[l]; i++)
|
| 380 |
+
huff_size[p++] = (char)l;
|
| 381 |
+
|
| 382 |
+
huff_size[p] = 0; last_p = p; // write sentinel
|
| 383 |
+
|
| 384 |
+
code = 0; si = huff_size[0]; p = 0;
|
| 385 |
+
|
| 386 |
+
while (huff_size[p])
|
| 387 |
+
{
|
| 388 |
+
while (huff_size[p] == si)
|
| 389 |
+
huff_code[p++] = code++;
|
| 390 |
+
code <<= 1;
|
| 391 |
+
si++;
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
+
memset(codes, 0, sizeof(codes[0])*256);
|
| 395 |
+
memset(code_sizes, 0, sizeof(code_sizes[0])*256);
|
| 396 |
+
for (p = 0; p < last_p; p++)
|
| 397 |
+
{
|
| 398 |
+
codes[val[p]] = huff_code[p];
|
| 399 |
+
code_sizes[val[p]] = huff_size[p];
|
| 400 |
+
}
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
// Quantization table generation.
|
| 404 |
+
void jpeg_encoder::compute_quant_table(int32 *pDst, int16 *pSrc)
|
| 405 |
+
{
|
| 406 |
+
int32 q;
|
| 407 |
+
if (m_params.m_quality < 50)
|
| 408 |
+
q = 5000 / m_params.m_quality;
|
| 409 |
+
else
|
| 410 |
+
q = 200 - m_params.m_quality * 2;
|
| 411 |
+
for (int i = 0; i < 64; i++)
|
| 412 |
+
{
|
| 413 |
+
int32 j = *pSrc++; j = (j * q + 50L) / 100L;
|
| 414 |
+
*pDst++ = JPGE_MIN(JPGE_MAX(j, 1), 255);
|
| 415 |
+
}
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
// Higher-level methods.
|
| 419 |
+
void jpeg_encoder::first_pass_init()
|
| 420 |
+
{
|
| 421 |
+
m_bit_buffer = 0; m_bits_in = 0;
|
| 422 |
+
memset(m_last_dc_val, 0, 3 * sizeof(m_last_dc_val[0]));
|
| 423 |
+
m_mcu_y_ofs = 0;
|
| 424 |
+
m_pass_num = 1;
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
bool jpeg_encoder::second_pass_init()
|
| 428 |
+
{
|
| 429 |
+
compute_huffman_table(&m_huff_codes[0+0][0], &m_huff_code_sizes[0+0][0], m_huff_bits[0+0], m_huff_val[0+0]);
|
| 430 |
+
compute_huffman_table(&m_huff_codes[2+0][0], &m_huff_code_sizes[2+0][0], m_huff_bits[2+0], m_huff_val[2+0]);
|
| 431 |
+
if (m_num_components > 1)
|
| 432 |
+
{
|
| 433 |
+
compute_huffman_table(&m_huff_codes[0+1][0], &m_huff_code_sizes[0+1][0], m_huff_bits[0+1], m_huff_val[0+1]);
|
| 434 |
+
compute_huffman_table(&m_huff_codes[2+1][0], &m_huff_code_sizes[2+1][0], m_huff_bits[2+1], m_huff_val[2+1]);
|
| 435 |
+
}
|
| 436 |
+
first_pass_init();
|
| 437 |
+
emit_markers();
|
| 438 |
+
m_pass_num = 2;
|
| 439 |
+
return true;
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
bool jpeg_encoder::jpg_open(int p_x_res, int p_y_res, int src_channels)
|
| 443 |
+
{
|
| 444 |
+
m_num_components = 3;
|
| 445 |
+
switch (m_params.m_subsampling)
|
| 446 |
+
{
|
| 447 |
+
case Y_ONLY:
|
| 448 |
+
{
|
| 449 |
+
m_num_components = 1;
|
| 450 |
+
m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1;
|
| 451 |
+
m_mcu_x = 8; m_mcu_y = 8;
|
| 452 |
+
break;
|
| 453 |
+
}
|
| 454 |
+
case H1V1:
|
| 455 |
+
{
|
| 456 |
+
m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1;
|
| 457 |
+
m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1;
|
| 458 |
+
m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1;
|
| 459 |
+
m_mcu_x = 8; m_mcu_y = 8;
|
| 460 |
+
break;
|
| 461 |
+
}
|
| 462 |
+
case H2V1:
|
| 463 |
+
{
|
| 464 |
+
m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 1;
|
| 465 |
+
m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1;
|
| 466 |
+
m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1;
|
| 467 |
+
m_mcu_x = 16; m_mcu_y = 8;
|
| 468 |
+
break;
|
| 469 |
+
}
|
| 470 |
+
case H2V2:
|
| 471 |
+
{
|
| 472 |
+
m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 2;
|
| 473 |
+
m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1;
|
| 474 |
+
m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1;
|
| 475 |
+
m_mcu_x = 16; m_mcu_y = 16;
|
| 476 |
+
}
|
| 477 |
+
}
|
| 478 |
+
|
| 479 |
+
m_image_x = p_x_res; m_image_y = p_y_res;
|
| 480 |
+
m_image_bpp = src_channels;
|
| 481 |
+
m_image_bpl = m_image_x * src_channels;
|
| 482 |
+
m_image_x_mcu = (m_image_x + m_mcu_x - 1) & (~(m_mcu_x - 1));
|
| 483 |
+
m_image_y_mcu = (m_image_y + m_mcu_y - 1) & (~(m_mcu_y - 1));
|
| 484 |
+
m_image_bpl_xlt = m_image_x * m_num_components;
|
| 485 |
+
m_image_bpl_mcu = m_image_x_mcu * m_num_components;
|
| 486 |
+
m_mcus_per_row = m_image_x_mcu / m_mcu_x;
|
| 487 |
+
|
| 488 |
+
if ((m_mcu_lines[0] = static_cast<uint8*>(jpge_malloc(m_image_bpl_mcu * m_mcu_y))) == NULL) return false;
|
| 489 |
+
for (int i = 1; i < m_mcu_y; i++)
|
| 490 |
+
m_mcu_lines[i] = m_mcu_lines[i-1] + m_image_bpl_mcu;
|
| 491 |
+
|
| 492 |
+
compute_quant_table(m_quantization_tables[0], s_std_lum_quant);
|
| 493 |
+
compute_quant_table(m_quantization_tables[1], m_params.m_no_chroma_discrim_flag ? s_std_lum_quant : s_std_croma_quant);
|
| 494 |
+
|
| 495 |
+
m_out_buf_left = JPGE_OUT_BUF_SIZE;
|
| 496 |
+
m_pOut_buf = m_out_buf;
|
| 497 |
+
|
| 498 |
+
if (m_params.m_two_pass_flag)
|
| 499 |
+
{
|
| 500 |
+
clear_obj(m_huff_count);
|
| 501 |
+
first_pass_init();
|
| 502 |
+
}
|
| 503 |
+
else
|
| 504 |
+
{
|
| 505 |
+
memcpy(m_huff_bits[0+0], s_dc_lum_bits, 17); memcpy(m_huff_val [0+0], s_dc_lum_val, DC_LUM_CODES);
|
| 506 |
+
memcpy(m_huff_bits[2+0], s_ac_lum_bits, 17); memcpy(m_huff_val [2+0], s_ac_lum_val, AC_LUM_CODES);
|
| 507 |
+
memcpy(m_huff_bits[0+1], s_dc_chroma_bits, 17); memcpy(m_huff_val [0+1], s_dc_chroma_val, DC_CHROMA_CODES);
|
| 508 |
+
memcpy(m_huff_bits[2+1], s_ac_chroma_bits, 17); memcpy(m_huff_val [2+1], s_ac_chroma_val, AC_CHROMA_CODES);
|
| 509 |
+
if (!second_pass_init()) return false; // in effect, skip over the first pass
|
| 510 |
+
}
|
| 511 |
+
return m_all_stream_writes_succeeded;
|
| 512 |
+
}
|
| 513 |
+
|
| 514 |
+
void jpeg_encoder::load_block_8_8_grey(int x)
|
| 515 |
+
{
|
| 516 |
+
uint8 *pSrc;
|
| 517 |
+
sample_array_t *pDst = m_sample_array;
|
| 518 |
+
x <<= 3;
|
| 519 |
+
for (int i = 0; i < 8; i++, pDst += 8)
|
| 520 |
+
{
|
| 521 |
+
pSrc = m_mcu_lines[i] + x;
|
| 522 |
+
pDst[0] = pSrc[0] - 128; pDst[1] = pSrc[1] - 128; pDst[2] = pSrc[2] - 128; pDst[3] = pSrc[3] - 128;
|
| 523 |
+
pDst[4] = pSrc[4] - 128; pDst[5] = pSrc[5] - 128; pDst[6] = pSrc[6] - 128; pDst[7] = pSrc[7] - 128;
|
| 524 |
+
}
|
| 525 |
+
}
|
| 526 |
+
|
| 527 |
+
void jpeg_encoder::load_block_8_8(int x, int y, int c)
|
| 528 |
+
{
|
| 529 |
+
uint8 *pSrc;
|
| 530 |
+
sample_array_t *pDst = m_sample_array;
|
| 531 |
+
x = (x * (8 * 3)) + c;
|
| 532 |
+
y <<= 3;
|
| 533 |
+
for (int i = 0; i < 8; i++, pDst += 8)
|
| 534 |
+
{
|
| 535 |
+
pSrc = m_mcu_lines[y + i] + x;
|
| 536 |
+
pDst[0] = pSrc[0 * 3] - 128; pDst[1] = pSrc[1 * 3] - 128; pDst[2] = pSrc[2 * 3] - 128; pDst[3] = pSrc[3 * 3] - 128;
|
| 537 |
+
pDst[4] = pSrc[4 * 3] - 128; pDst[5] = pSrc[5 * 3] - 128; pDst[6] = pSrc[6 * 3] - 128; pDst[7] = pSrc[7 * 3] - 128;
|
| 538 |
+
}
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
void jpeg_encoder::load_block_16_8(int x, int c)
|
| 542 |
+
{
|
| 543 |
+
uint8 *pSrc1, *pSrc2;
|
| 544 |
+
sample_array_t *pDst = m_sample_array;
|
| 545 |
+
x = (x * (16 * 3)) + c;
|
| 546 |
+
int a = 0, b = 2;
|
| 547 |
+
for (int i = 0; i < 16; i += 2, pDst += 8)
|
| 548 |
+
{
|
| 549 |
+
pSrc1 = m_mcu_lines[i + 0] + x;
|
| 550 |
+
pSrc2 = m_mcu_lines[i + 1] + x;
|
| 551 |
+
pDst[0] = ((pSrc1[ 0 * 3] + pSrc1[ 1 * 3] + pSrc2[ 0 * 3] + pSrc2[ 1 * 3] + a) >> 2) - 128; pDst[1] = ((pSrc1[ 2 * 3] + pSrc1[ 3 * 3] + pSrc2[ 2 * 3] + pSrc2[ 3 * 3] + b) >> 2) - 128;
|
| 552 |
+
pDst[2] = ((pSrc1[ 4 * 3] + pSrc1[ 5 * 3] + pSrc2[ 4 * 3] + pSrc2[ 5 * 3] + a) >> 2) - 128; pDst[3] = ((pSrc1[ 6 * 3] + pSrc1[ 7 * 3] + pSrc2[ 6 * 3] + pSrc2[ 7 * 3] + b) >> 2) - 128;
|
| 553 |
+
pDst[4] = ((pSrc1[ 8 * 3] + pSrc1[ 9 * 3] + pSrc2[ 8 * 3] + pSrc2[ 9 * 3] + a) >> 2) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3] + pSrc2[10 * 3] + pSrc2[11 * 3] + b) >> 2) - 128;
|
| 554 |
+
pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3] + pSrc2[12 * 3] + pSrc2[13 * 3] + a) >> 2) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3] + pSrc2[14 * 3] + pSrc2[15 * 3] + b) >> 2) - 128;
|
| 555 |
+
int temp = a; a = b; b = temp;
|
| 556 |
+
}
|
| 557 |
+
}
|
| 558 |
+
|
| 559 |
+
void jpeg_encoder::load_block_16_8_8(int x, int c)
|
| 560 |
+
{
|
| 561 |
+
uint8 *pSrc1;
|
| 562 |
+
sample_array_t *pDst = m_sample_array;
|
| 563 |
+
x = (x * (16 * 3)) + c;
|
| 564 |
+
for (int i = 0; i < 8; i++, pDst += 8)
|
| 565 |
+
{
|
| 566 |
+
pSrc1 = m_mcu_lines[i + 0] + x;
|
| 567 |
+
pDst[0] = ((pSrc1[ 0 * 3] + pSrc1[ 1 * 3]) >> 1) - 128; pDst[1] = ((pSrc1[ 2 * 3] + pSrc1[ 3 * 3]) >> 1) - 128;
|
| 568 |
+
pDst[2] = ((pSrc1[ 4 * 3] + pSrc1[ 5 * 3]) >> 1) - 128; pDst[3] = ((pSrc1[ 6 * 3] + pSrc1[ 7 * 3]) >> 1) - 128;
|
| 569 |
+
pDst[4] = ((pSrc1[ 8 * 3] + pSrc1[ 9 * 3]) >> 1) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3]) >> 1) - 128;
|
| 570 |
+
pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3]) >> 1) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3]) >> 1) - 128;
|
| 571 |
+
}
|
| 572 |
+
}
|
| 573 |
+
|
| 574 |
+
void jpeg_encoder::load_quantized_coefficients(int component_num)
|
| 575 |
+
{
|
| 576 |
+
int32 *q = m_quantization_tables[component_num > 0];
|
| 577 |
+
int16 *pDst = m_coefficient_array;
|
| 578 |
+
for (int i = 0; i < 64; i++)
|
| 579 |
+
{
|
| 580 |
+
sample_array_t j = m_sample_array[s_zag[i]];
|
| 581 |
+
if (j < 0)
|
| 582 |
+
{
|
| 583 |
+
if ((j = -j + (*q >> 1)) < *q)
|
| 584 |
+
*pDst++ = 0;
|
| 585 |
+
else
|
| 586 |
+
*pDst++ = static_cast<int16>(-(j / *q));
|
| 587 |
+
}
|
| 588 |
+
else
|
| 589 |
+
{
|
| 590 |
+
if ((j = j + (*q >> 1)) < *q)
|
| 591 |
+
*pDst++ = 0;
|
| 592 |
+
else
|
| 593 |
+
*pDst++ = static_cast<int16>((j / *q));
|
| 594 |
+
}
|
| 595 |
+
q++;
|
| 596 |
+
}
|
| 597 |
+
}
|
| 598 |
+
|
| 599 |
+
void jpeg_encoder::flush_output_buffer()
|
| 600 |
+
{
|
| 601 |
+
if (m_out_buf_left != JPGE_OUT_BUF_SIZE)
|
| 602 |
+
m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_buf(m_out_buf, JPGE_OUT_BUF_SIZE - m_out_buf_left);
|
| 603 |
+
m_pOut_buf = m_out_buf;
|
| 604 |
+
m_out_buf_left = JPGE_OUT_BUF_SIZE;
|
| 605 |
+
}
|
| 606 |
+
|
| 607 |
+
void jpeg_encoder::put_bits(uint bits, uint len)
|
| 608 |
+
{
|
| 609 |
+
m_bit_buffer |= ((uint32)bits << (24 - (m_bits_in += len)));
|
| 610 |
+
while (m_bits_in >= 8)
|
| 611 |
+
{
|
| 612 |
+
uint8 c;
|
| 613 |
+
#define JPGE_PUT_BYTE(c) { *m_pOut_buf++ = (c); if (--m_out_buf_left == 0) flush_output_buffer(); }
|
| 614 |
+
JPGE_PUT_BYTE(c = (uint8)((m_bit_buffer >> 16) & 0xFF));
|
| 615 |
+
if (c == 0xFF) JPGE_PUT_BYTE(0);
|
| 616 |
+
m_bit_buffer <<= 8;
|
| 617 |
+
m_bits_in -= 8;
|
| 618 |
+
}
|
| 619 |
+
}
|
| 620 |
+
|
| 621 |
+
void jpeg_encoder::code_coefficients_pass_one(int component_num)
|
| 622 |
+
{
|
| 623 |
+
if (component_num >= 3) return; // just to shut up static analysis
|
| 624 |
+
int i, run_len, nbits, temp1;
|
| 625 |
+
int16 *src = m_coefficient_array;
|
| 626 |
+
uint32 *dc_count = component_num ? m_huff_count[0 + 1] : m_huff_count[0 + 0], *ac_count = component_num ? m_huff_count[2 + 1] : m_huff_count[2 + 0];
|
| 627 |
+
|
| 628 |
+
temp1 = src[0] - m_last_dc_val[component_num];
|
| 629 |
+
m_last_dc_val[component_num] = src[0];
|
| 630 |
+
if (temp1 < 0) temp1 = -temp1;
|
| 631 |
+
|
| 632 |
+
nbits = 0;
|
| 633 |
+
while (temp1)
|
| 634 |
+
{
|
| 635 |
+
nbits++; temp1 >>= 1;
|
| 636 |
+
}
|
| 637 |
+
|
| 638 |
+
dc_count[nbits]++;
|
| 639 |
+
for (run_len = 0, i = 1; i < 64; i++)
|
| 640 |
+
{
|
| 641 |
+
if ((temp1 = m_coefficient_array[i]) == 0)
|
| 642 |
+
run_len++;
|
| 643 |
+
else
|
| 644 |
+
{
|
| 645 |
+
while (run_len >= 16)
|
| 646 |
+
{
|
| 647 |
+
ac_count[0xF0]++;
|
| 648 |
+
run_len -= 16;
|
| 649 |
+
}
|
| 650 |
+
if (temp1 < 0) temp1 = -temp1;
|
| 651 |
+
nbits = 1;
|
| 652 |
+
while (temp1 >>= 1) nbits++;
|
| 653 |
+
ac_count[(run_len << 4) + nbits]++;
|
| 654 |
+
run_len = 0;
|
| 655 |
+
}
|
| 656 |
+
}
|
| 657 |
+
if (run_len) ac_count[0]++;
|
| 658 |
+
}
|
| 659 |
+
|
| 660 |
+
void jpeg_encoder::code_coefficients_pass_two(int component_num)
|
| 661 |
+
{
|
| 662 |
+
int i, j, run_len, nbits, temp1, temp2;
|
| 663 |
+
int16 *pSrc = m_coefficient_array;
|
| 664 |
+
uint *codes[2];
|
| 665 |
+
uint8 *code_sizes[2];
|
| 666 |
+
|
| 667 |
+
if (component_num == 0)
|
| 668 |
+
{
|
| 669 |
+
codes[0] = m_huff_codes[0 + 0]; codes[1] = m_huff_codes[2 + 0];
|
| 670 |
+
code_sizes[0] = m_huff_code_sizes[0 + 0]; code_sizes[1] = m_huff_code_sizes[2 + 0];
|
| 671 |
+
}
|
| 672 |
+
else
|
| 673 |
+
{
|
| 674 |
+
codes[0] = m_huff_codes[0 + 1]; codes[1] = m_huff_codes[2 + 1];
|
| 675 |
+
code_sizes[0] = m_huff_code_sizes[0 + 1]; code_sizes[1] = m_huff_code_sizes[2 + 1];
|
| 676 |
+
}
|
| 677 |
+
|
| 678 |
+
temp1 = temp2 = pSrc[0] - m_last_dc_val[component_num];
|
| 679 |
+
m_last_dc_val[component_num] = pSrc[0];
|
| 680 |
+
|
| 681 |
+
if (temp1 < 0)
|
| 682 |
+
{
|
| 683 |
+
temp1 = -temp1; temp2--;
|
| 684 |
+
}
|
| 685 |
+
|
| 686 |
+
nbits = 0;
|
| 687 |
+
while (temp1)
|
| 688 |
+
{
|
| 689 |
+
nbits++; temp1 >>= 1;
|
| 690 |
+
}
|
| 691 |
+
|
| 692 |
+
put_bits(codes[0][nbits], code_sizes[0][nbits]);
|
| 693 |
+
if (nbits) put_bits(temp2 & ((1 << nbits) - 1), nbits);
|
| 694 |
+
|
| 695 |
+
for (run_len = 0, i = 1; i < 64; i++)
|
| 696 |
+
{
|
| 697 |
+
if ((temp1 = m_coefficient_array[i]) == 0)
|
| 698 |
+
run_len++;
|
| 699 |
+
else
|
| 700 |
+
{
|
| 701 |
+
while (run_len >= 16)
|
| 702 |
+
{
|
| 703 |
+
put_bits(codes[1][0xF0], code_sizes[1][0xF0]);
|
| 704 |
+
run_len -= 16;
|
| 705 |
+
}
|
| 706 |
+
if ((temp2 = temp1) < 0)
|
| 707 |
+
{
|
| 708 |
+
temp1 = -temp1;
|
| 709 |
+
temp2--;
|
| 710 |
+
}
|
| 711 |
+
nbits = 1;
|
| 712 |
+
while (temp1 >>= 1)
|
| 713 |
+
nbits++;
|
| 714 |
+
j = (run_len << 4) + nbits;
|
| 715 |
+
put_bits(codes[1][j], code_sizes[1][j]);
|
| 716 |
+
put_bits(temp2 & ((1 << nbits) - 1), nbits);
|
| 717 |
+
run_len = 0;
|
| 718 |
+
}
|
| 719 |
+
}
|
| 720 |
+
if (run_len)
|
| 721 |
+
put_bits(codes[1][0], code_sizes[1][0]);
|
| 722 |
+
}
|
| 723 |
+
|
| 724 |
+
void jpeg_encoder::code_block(int component_num)
|
| 725 |
+
{
|
| 726 |
+
DCT2D(m_sample_array);
|
| 727 |
+
load_quantized_coefficients(component_num);
|
| 728 |
+
if (m_pass_num == 1)
|
| 729 |
+
code_coefficients_pass_one(component_num);
|
| 730 |
+
else
|
| 731 |
+
code_coefficients_pass_two(component_num);
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
void jpeg_encoder::process_mcu_row()
|
| 735 |
+
{
|
| 736 |
+
if (m_num_components == 1)
|
| 737 |
+
{
|
| 738 |
+
for (int i = 0; i < m_mcus_per_row; i++)
|
| 739 |
+
{
|
| 740 |
+
load_block_8_8_grey(i); code_block(0);
|
| 741 |
+
}
|
| 742 |
+
}
|
| 743 |
+
else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1))
|
| 744 |
+
{
|
| 745 |
+
for (int i = 0; i < m_mcus_per_row; i++)
|
| 746 |
+
{
|
| 747 |
+
load_block_8_8(i, 0, 0); code_block(0); load_block_8_8(i, 0, 1); code_block(1); load_block_8_8(i, 0, 2); code_block(2);
|
| 748 |
+
}
|
| 749 |
+
}
|
| 750 |
+
else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1))
|
| 751 |
+
{
|
| 752 |
+
for (int i = 0; i < m_mcus_per_row; i++)
|
| 753 |
+
{
|
| 754 |
+
load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0);
|
| 755 |
+
load_block_16_8_8(i, 1); code_block(1); load_block_16_8_8(i, 2); code_block(2);
|
| 756 |
+
}
|
| 757 |
+
}
|
| 758 |
+
else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2))
|
| 759 |
+
{
|
| 760 |
+
for (int i = 0; i < m_mcus_per_row; i++)
|
| 761 |
+
{
|
| 762 |
+
load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0);
|
| 763 |
+
load_block_8_8(i * 2 + 0, 1, 0); code_block(0); load_block_8_8(i * 2 + 1, 1, 0); code_block(0);
|
| 764 |
+
load_block_16_8(i, 1); code_block(1); load_block_16_8(i, 2); code_block(2);
|
| 765 |
+
}
|
| 766 |
+
}
|
| 767 |
+
}
|
| 768 |
+
|
| 769 |
+
bool jpeg_encoder::terminate_pass_one()
|
| 770 |
+
{
|
| 771 |
+
optimize_huffman_table(0+0, DC_LUM_CODES); optimize_huffman_table(2+0, AC_LUM_CODES);
|
| 772 |
+
if (m_num_components > 1)
|
| 773 |
+
{
|
| 774 |
+
optimize_huffman_table(0+1, DC_CHROMA_CODES); optimize_huffman_table(2+1, AC_CHROMA_CODES);
|
| 775 |
+
}
|
| 776 |
+
return second_pass_init();
|
| 777 |
+
}
|
| 778 |
+
|
| 779 |
+
bool jpeg_encoder::terminate_pass_two()
|
| 780 |
+
{
|
| 781 |
+
put_bits(0x7F, 7);
|
| 782 |
+
flush_output_buffer();
|
| 783 |
+
emit_marker(M_EOI);
|
| 784 |
+
m_pass_num++; // purposely bump up m_pass_num, for debugging
|
| 785 |
+
return true;
|
| 786 |
+
}
|
| 787 |
+
|
| 788 |
+
bool jpeg_encoder::process_end_of_image()
|
| 789 |
+
{
|
| 790 |
+
if (m_mcu_y_ofs)
|
| 791 |
+
{
|
| 792 |
+
if (m_mcu_y_ofs < 16) // check here just to shut up static analysis
|
| 793 |
+
{
|
| 794 |
+
for (int i = m_mcu_y_ofs; i < m_mcu_y; i++)
|
| 795 |
+
memcpy(m_mcu_lines[i], m_mcu_lines[m_mcu_y_ofs - 1], m_image_bpl_mcu);
|
| 796 |
+
}
|
| 797 |
+
|
| 798 |
+
process_mcu_row();
|
| 799 |
+
}
|
| 800 |
+
|
| 801 |
+
if (m_pass_num == 1)
|
| 802 |
+
return terminate_pass_one();
|
| 803 |
+
else
|
| 804 |
+
return terminate_pass_two();
|
| 805 |
+
}
|
| 806 |
+
|
| 807 |
+
void jpeg_encoder::load_mcu(const void *pSrc)
|
| 808 |
+
{
|
| 809 |
+
const uint8* Psrc = reinterpret_cast<const uint8*>(pSrc);
|
| 810 |
+
|
| 811 |
+
uint8* pDst = m_mcu_lines[m_mcu_y_ofs]; // OK to write up to m_image_bpl_xlt bytes to pDst
|
| 812 |
+
|
| 813 |
+
if (m_num_components == 1)
|
| 814 |
+
{
|
| 815 |
+
if (m_image_bpp == 4)
|
| 816 |
+
RGBA_to_Y(pDst, Psrc, m_image_x);
|
| 817 |
+
else if (m_image_bpp == 3)
|
| 818 |
+
RGB_to_Y(pDst, Psrc, m_image_x);
|
| 819 |
+
else
|
| 820 |
+
memcpy(pDst, Psrc, m_image_x);
|
| 821 |
+
}
|
| 822 |
+
else
|
| 823 |
+
{
|
| 824 |
+
if (m_image_bpp == 4)
|
| 825 |
+
RGBA_to_YCC(pDst, Psrc, m_image_x);
|
| 826 |
+
else if (m_image_bpp == 3)
|
| 827 |
+
RGB_to_YCC(pDst, Psrc, m_image_x);
|
| 828 |
+
else
|
| 829 |
+
Y_to_YCC(pDst, Psrc, m_image_x);
|
| 830 |
+
}
|
| 831 |
+
|
| 832 |
+
// Possibly duplicate pixels at end of scanline if not a multiple of 8 or 16
|
| 833 |
+
if (m_num_components == 1)
|
| 834 |
+
memset(m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt, pDst[m_image_bpl_xlt - 1], m_image_x_mcu - m_image_x);
|
| 835 |
+
else
|
| 836 |
+
{
|
| 837 |
+
const uint8 y = pDst[m_image_bpl_xlt - 3 + 0], cb = pDst[m_image_bpl_xlt - 3 + 1], cr = pDst[m_image_bpl_xlt - 3 + 2];
|
| 838 |
+
uint8 *q = m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt;
|
| 839 |
+
for (int i = m_image_x; i < m_image_x_mcu; i++)
|
| 840 |
+
{
|
| 841 |
+
*q++ = y; *q++ = cb; *q++ = cr;
|
| 842 |
+
}
|
| 843 |
+
}
|
| 844 |
+
|
| 845 |
+
if (++m_mcu_y_ofs == m_mcu_y)
|
| 846 |
+
{
|
| 847 |
+
process_mcu_row();
|
| 848 |
+
m_mcu_y_ofs = 0;
|
| 849 |
+
}
|
| 850 |
+
}
|
| 851 |
+
|
| 852 |
+
void jpeg_encoder::clear()
|
| 853 |
+
{
|
| 854 |
+
m_mcu_lines[0] = NULL;
|
| 855 |
+
m_pass_num = 0;
|
| 856 |
+
m_all_stream_writes_succeeded = true;
|
| 857 |
+
}
|
| 858 |
+
|
| 859 |
+
jpeg_encoder::jpeg_encoder()
|
| 860 |
+
{
|
| 861 |
+
clear();
|
| 862 |
+
}
|
| 863 |
+
|
| 864 |
+
jpeg_encoder::~jpeg_encoder()
|
| 865 |
+
{
|
| 866 |
+
deinit();
|
| 867 |
+
}
|
| 868 |
+
|
| 869 |
+
bool jpeg_encoder::init(output_stream *pStream, int64_t width, int64_t height, int64_t src_channels, const params &comp_params)
|
| 870 |
+
{
|
| 871 |
+
deinit();
|
| 872 |
+
if (((!pStream) || (width < 1) || (height < 1)) || ((src_channels != 1) && (src_channels != 3) && (src_channels != 4)) || (!comp_params.check_valid())) return false;
|
| 873 |
+
m_pStream = pStream;
|
| 874 |
+
m_params = comp_params;
|
| 875 |
+
return jpg_open(width, height, src_channels);
|
| 876 |
+
}
|
| 877 |
+
|
| 878 |
+
void jpeg_encoder::deinit()
|
| 879 |
+
{
|
| 880 |
+
jpge_free(m_mcu_lines[0]);
|
| 881 |
+
clear();
|
| 882 |
+
}
|
| 883 |
+
|
| 884 |
+
bool jpeg_encoder::process_scanline(const void* pScanline)
|
| 885 |
+
{
|
| 886 |
+
if ((m_pass_num < 1) || (m_pass_num > 2)) return false;
|
| 887 |
+
if (m_all_stream_writes_succeeded)
|
| 888 |
+
{
|
| 889 |
+
if (!pScanline)
|
| 890 |
+
{
|
| 891 |
+
if (!process_end_of_image()) return false;
|
| 892 |
+
}
|
| 893 |
+
else
|
| 894 |
+
{
|
| 895 |
+
load_mcu(pScanline);
|
| 896 |
+
}
|
| 897 |
+
}
|
| 898 |
+
return m_all_stream_writes_succeeded;
|
| 899 |
+
}
|
| 900 |
+
|
| 901 |
+
// Higher level wrappers/examples (optional).
|
| 902 |
+
#include <stdio.h>
|
| 903 |
+
|
| 904 |
+
class cfile_stream : public output_stream
|
| 905 |
+
{
|
| 906 |
+
cfile_stream(const cfile_stream &);
|
| 907 |
+
cfile_stream &operator= (const cfile_stream &);
|
| 908 |
+
|
| 909 |
+
FILE* m_pFile;
|
| 910 |
+
bool m_bStatus;
|
| 911 |
+
|
| 912 |
+
public:
|
| 913 |
+
cfile_stream() : m_pFile(NULL), m_bStatus(false) { }
|
| 914 |
+
|
| 915 |
+
virtual ~cfile_stream()
|
| 916 |
+
{
|
| 917 |
+
close();
|
| 918 |
+
}
|
| 919 |
+
|
| 920 |
+
bool open(const char *pFilename)
|
| 921 |
+
{
|
| 922 |
+
close();
|
| 923 |
+
#if defined(_MSC_VER)
|
| 924 |
+
if (fopen_s(&m_pFile, pFilename, "wb") != 0)
|
| 925 |
+
{
|
| 926 |
+
return false;
|
| 927 |
+
}
|
| 928 |
+
#else
|
| 929 |
+
m_pFile = fopen(pFilename, "wb");
|
| 930 |
+
#endif
|
| 931 |
+
m_bStatus = (m_pFile != NULL);
|
| 932 |
+
return m_bStatus;
|
| 933 |
+
}
|
| 934 |
+
|
| 935 |
+
bool close()
|
| 936 |
+
{
|
| 937 |
+
if (m_pFile)
|
| 938 |
+
{
|
| 939 |
+
if (fclose(m_pFile) == EOF)
|
| 940 |
+
{
|
| 941 |
+
m_bStatus = false;
|
| 942 |
+
}
|
| 943 |
+
m_pFile = NULL;
|
| 944 |
+
}
|
| 945 |
+
return m_bStatus;
|
| 946 |
+
}
|
| 947 |
+
|
| 948 |
+
virtual bool put_buf(const void* pBuf, int64_t len)
|
| 949 |
+
{
|
| 950 |
+
m_bStatus = m_bStatus && (fwrite(pBuf, len, 1, m_pFile) == 1);
|
| 951 |
+
return m_bStatus;
|
| 952 |
+
}
|
| 953 |
+
|
| 954 |
+
uint get_size() const
|
| 955 |
+
{
|
| 956 |
+
return m_pFile ? ftell(m_pFile) : 0;
|
| 957 |
+
}
|
| 958 |
+
};
|
| 959 |
+
|
| 960 |
+
// Writes JPEG image to file.
|
| 961 |
+
bool compress_image_to_jpeg_file(const char *pFilename, int64_t width, int64_t height, int64_t num_channels, const uint8 *pImage_data, const params &comp_params)
|
| 962 |
+
{
|
| 963 |
+
cfile_stream dst_stream;
|
| 964 |
+
if (!dst_stream.open(pFilename))
|
| 965 |
+
return false;
|
| 966 |
+
|
| 967 |
+
jpge::jpeg_encoder dst_image;
|
| 968 |
+
if (!dst_image.init(&dst_stream, width, height, num_channels, comp_params))
|
| 969 |
+
return false;
|
| 970 |
+
|
| 971 |
+
for (uint pass_index = 0; pass_index < dst_image.get_total_passes(); pass_index++)
|
| 972 |
+
{
|
| 973 |
+
for (int64_t i = 0; i < height; i++)
|
| 974 |
+
{
|
| 975 |
+
// i, width, and num_channels are all 64bit
|
| 976 |
+
const uint8* pBuf = pImage_data + i * width * num_channels;
|
| 977 |
+
if (!dst_image.process_scanline(pBuf))
|
| 978 |
+
return false;
|
| 979 |
+
}
|
| 980 |
+
if (!dst_image.process_scanline(NULL))
|
| 981 |
+
return false;
|
| 982 |
+
}
|
| 983 |
+
|
| 984 |
+
dst_image.deinit();
|
| 985 |
+
|
| 986 |
+
return dst_stream.close();
|
| 987 |
+
}
|
| 988 |
+
|
| 989 |
+
class memory_stream : public output_stream
|
| 990 |
+
{
|
| 991 |
+
memory_stream(const memory_stream &);
|
| 992 |
+
memory_stream &operator= (const memory_stream &);
|
| 993 |
+
|
| 994 |
+
uint8 *m_pBuf;
|
| 995 |
+
uint64_t m_buf_size, m_buf_ofs;
|
| 996 |
+
|
| 997 |
+
public:
|
| 998 |
+
memory_stream(void *pBuf, uint64_t buf_size) : m_pBuf(static_cast<uint8*>(pBuf)), m_buf_size(buf_size), m_buf_ofs(0) { }
|
| 999 |
+
|
| 1000 |
+
virtual ~memory_stream() { }
|
| 1001 |
+
|
| 1002 |
+
virtual bool put_buf(const void* pBuf, int64_t len)
|
| 1003 |
+
{
|
| 1004 |
+
uint64_t buf_remaining = m_buf_size - m_buf_ofs;
|
| 1005 |
+
if ((uint64_t)len > buf_remaining)
|
| 1006 |
+
return false;
|
| 1007 |
+
memcpy(m_pBuf + m_buf_ofs, pBuf, len);
|
| 1008 |
+
m_buf_ofs += len;
|
| 1009 |
+
return true;
|
| 1010 |
+
}
|
| 1011 |
+
|
| 1012 |
+
uint64_t get_size() const
|
| 1013 |
+
{
|
| 1014 |
+
return m_buf_ofs;
|
| 1015 |
+
}
|
| 1016 |
+
};
|
| 1017 |
+
|
| 1018 |
+
bool compress_image_to_jpeg_file_in_memory(void *pDstBuf, int64_t &buf_size, int64_t width, int64_t height, int64_t num_channels, const uint8 *pImage_data, const params &comp_params)
|
| 1019 |
+
{
|
| 1020 |
+
if ((!pDstBuf) || (!buf_size))
|
| 1021 |
+
return false;
|
| 1022 |
+
|
| 1023 |
+
memory_stream dst_stream(pDstBuf, buf_size);
|
| 1024 |
+
|
| 1025 |
+
buf_size = 0;
|
| 1026 |
+
|
| 1027 |
+
jpge::jpeg_encoder dst_image;
|
| 1028 |
+
if (!dst_image.init(&dst_stream, width, height, num_channels, comp_params))
|
| 1029 |
+
return false;
|
| 1030 |
+
|
| 1031 |
+
for (uint pass_index = 0; pass_index < dst_image.get_total_passes(); pass_index++)
|
| 1032 |
+
{
|
| 1033 |
+
for (int64_t i = 0; i < height; i++)
|
| 1034 |
+
{
|
| 1035 |
+
const uint8* pScanline = pImage_data + i * width * num_channels;
|
| 1036 |
+
if (!dst_image.process_scanline(pScanline))
|
| 1037 |
+
return false;
|
| 1038 |
+
}
|
| 1039 |
+
if (!dst_image.process_scanline(NULL))
|
| 1040 |
+
return false;
|
| 1041 |
+
}
|
| 1042 |
+
|
| 1043 |
+
dst_image.deinit();
|
| 1044 |
+
|
| 1045 |
+
buf_size = dst_stream.get_size();
|
| 1046 |
+
return true;
|
| 1047 |
+
}
|
| 1048 |
+
|
| 1049 |
+
} // namespace jpge
|
crazy_functions/test_project/cpp/longcode/prod_cons.h
ADDED
|
@@ -0,0 +1,433 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <atomic>
|
| 4 |
+
#include <utility>
|
| 5 |
+
#include <cstring>
|
| 6 |
+
#include <type_traits>
|
| 7 |
+
#include <cstdint>
|
| 8 |
+
|
| 9 |
+
#include "libipc/def.h"
|
| 10 |
+
|
| 11 |
+
#include "libipc/platform/detail.h"
|
| 12 |
+
#include "libipc/circ/elem_def.h"
|
| 13 |
+
#include "libipc/utility/log.h"
|
| 14 |
+
#include "libipc/utility/utility.h"
|
| 15 |
+
|
| 16 |
+
namespace ipc {
|
| 17 |
+
|
| 18 |
+
////////////////////////////////////////////////////////////////
|
| 19 |
+
/// producer-consumer implementation
|
| 20 |
+
////////////////////////////////////////////////////////////////
|
| 21 |
+
|
| 22 |
+
template <typename Flag>
|
| 23 |
+
struct prod_cons_impl;
|
| 24 |
+
|
| 25 |
+
template <>
|
| 26 |
+
struct prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
|
| 27 |
+
|
| 28 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
| 29 |
+
struct elem_t {
|
| 30 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> rd_; // read index
|
| 34 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
|
| 35 |
+
|
| 36 |
+
constexpr circ::u2_t cursor() const noexcept {
|
| 37 |
+
return 0;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
template <typename W, typename F, typename E>
|
| 41 |
+
bool push(W* /*wrapper*/, F&& f, E* elems) {
|
| 42 |
+
auto cur_wt = circ::index_of(wt_.load(std::memory_order_relaxed));
|
| 43 |
+
if (cur_wt == circ::index_of(rd_.load(std::memory_order_acquire) - 1)) {
|
| 44 |
+
return false; // full
|
| 45 |
+
}
|
| 46 |
+
std::forward<F>(f)(&(elems[cur_wt].data_));
|
| 47 |
+
wt_.fetch_add(1, std::memory_order_release);
|
| 48 |
+
return true;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
/**
|
| 52 |
+
* In single-single-unicast, 'force_push' means 'no reader' or 'the only one reader is dead'.
|
| 53 |
+
* So we could just disconnect all connections of receiver, and return false.
|
| 54 |
+
*/
|
| 55 |
+
template <typename W, typename F, typename E>
|
| 56 |
+
bool force_push(W* wrapper, F&&, E*) {
|
| 57 |
+
wrapper->elems()->disconnect_receiver(~static_cast<circ::cc_t>(0u));
|
| 58 |
+
return false;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
template <typename W, typename F, typename R, typename E>
|
| 62 |
+
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E* elems) {
|
| 63 |
+
auto cur_rd = circ::index_of(rd_.load(std::memory_order_relaxed));
|
| 64 |
+
if (cur_rd == circ::index_of(wt_.load(std::memory_order_acquire))) {
|
| 65 |
+
return false; // empty
|
| 66 |
+
}
|
| 67 |
+
std::forward<F>(f)(&(elems[cur_rd].data_));
|
| 68 |
+
std::forward<R>(out)(true);
|
| 69 |
+
rd_.fetch_add(1, std::memory_order_release);
|
| 70 |
+
return true;
|
| 71 |
+
}
|
| 72 |
+
};
|
| 73 |
+
|
| 74 |
+
template <>
|
| 75 |
+
struct prod_cons_impl<wr<relat::single, relat::multi , trans::unicast>>
|
| 76 |
+
: prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
|
| 77 |
+
|
| 78 |
+
template <typename W, typename F, typename E>
|
| 79 |
+
bool force_push(W* wrapper, F&&, E*) {
|
| 80 |
+
wrapper->elems()->disconnect_receiver(1);
|
| 81 |
+
return false;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
template <typename W, typename F, typename R,
|
| 85 |
+
template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
|
| 86 |
+
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
|
| 87 |
+
byte_t buff[DS];
|
| 88 |
+
for (unsigned k = 0;;) {
|
| 89 |
+
auto cur_rd = rd_.load(std::memory_order_relaxed);
|
| 90 |
+
if (circ::index_of(cur_rd) ==
|
| 91 |
+
circ::index_of(wt_.load(std::memory_order_acquire))) {
|
| 92 |
+
return false; // empty
|
| 93 |
+
}
|
| 94 |
+
std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
|
| 95 |
+
if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
|
| 96 |
+
std::forward<F>(f)(buff);
|
| 97 |
+
std::forward<R>(out)(true);
|
| 98 |
+
return true;
|
| 99 |
+
}
|
| 100 |
+
ipc::yield(k);
|
| 101 |
+
}
|
| 102 |
+
}
|
| 103 |
+
};
|
| 104 |
+
|
| 105 |
+
template <>
|
| 106 |
+
struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
|
| 107 |
+
: prod_cons_impl<wr<relat::single, relat::multi, trans::unicast>> {
|
| 108 |
+
|
| 109 |
+
using flag_t = std::uint64_t;
|
| 110 |
+
|
| 111 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
| 112 |
+
struct elem_t {
|
| 113 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
| 114 |
+
std::atomic<flag_t> f_ct_ { 0 }; // commit flag
|
| 115 |
+
};
|
| 116 |
+
|
| 117 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
|
| 118 |
+
|
| 119 |
+
template <typename W, typename F, typename E>
|
| 120 |
+
bool push(W* /*wrapper*/, F&& f, E* elems) {
|
| 121 |
+
circ::u2_t cur_ct, nxt_ct;
|
| 122 |
+
for (unsigned k = 0;;) {
|
| 123 |
+
cur_ct = ct_.load(std::memory_order_relaxed);
|
| 124 |
+
if (circ::index_of(nxt_ct = cur_ct + 1) ==
|
| 125 |
+
circ::index_of(rd_.load(std::memory_order_acquire))) {
|
| 126 |
+
return false; // full
|
| 127 |
+
}
|
| 128 |
+
if (ct_.compare_exchange_weak(cur_ct, nxt_ct, std::memory_order_acq_rel)) {
|
| 129 |
+
break;
|
| 130 |
+
}
|
| 131 |
+
ipc::yield(k);
|
| 132 |
+
}
|
| 133 |
+
auto* el = elems + circ::index_of(cur_ct);
|
| 134 |
+
std::forward<F>(f)(&(el->data_));
|
| 135 |
+
// set flag & try update wt
|
| 136 |
+
el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
|
| 137 |
+
while (1) {
|
| 138 |
+
auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
|
| 139 |
+
if (cur_ct != wt_.load(std::memory_order_relaxed)) {
|
| 140 |
+
return true;
|
| 141 |
+
}
|
| 142 |
+
if ((~cac_ct) != cur_ct) {
|
| 143 |
+
return true;
|
| 144 |
+
}
|
| 145 |
+
if (!el->f_ct_.compare_exchange_strong(cac_ct, 0, std::memory_order_relaxed)) {
|
| 146 |
+
return true;
|
| 147 |
+
}
|
| 148 |
+
wt_.store(nxt_ct, std::memory_order_release);
|
| 149 |
+
cur_ct = nxt_ct;
|
| 150 |
+
nxt_ct = cur_ct + 1;
|
| 151 |
+
el = elems + circ::index_of(cur_ct);
|
| 152 |
+
}
|
| 153 |
+
return true;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
template <typename W, typename F, typename E>
|
| 157 |
+
bool force_push(W* wrapper, F&&, E*) {
|
| 158 |
+
wrapper->elems()->disconnect_receiver(1);
|
| 159 |
+
return false;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
template <typename W, typename F, typename R,
|
| 163 |
+
template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
|
| 164 |
+
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
|
| 165 |
+
byte_t buff[DS];
|
| 166 |
+
for (unsigned k = 0;;) {
|
| 167 |
+
auto cur_rd = rd_.load(std::memory_order_relaxed);
|
| 168 |
+
auto cur_wt = wt_.load(std::memory_order_acquire);
|
| 169 |
+
auto id_rd = circ::index_of(cur_rd);
|
| 170 |
+
auto id_wt = circ::index_of(cur_wt);
|
| 171 |
+
if (id_rd == id_wt) {
|
| 172 |
+
auto* el = elems + id_wt;
|
| 173 |
+
auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
|
| 174 |
+
if ((~cac_ct) != cur_wt) {
|
| 175 |
+
return false; // empty
|
| 176 |
+
}
|
| 177 |
+
if (el->f_ct_.compare_exchange_weak(cac_ct, 0, std::memory_order_relaxed)) {
|
| 178 |
+
wt_.store(cur_wt + 1, std::memory_order_release);
|
| 179 |
+
}
|
| 180 |
+
k = 0;
|
| 181 |
+
}
|
| 182 |
+
else {
|
| 183 |
+
std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
|
| 184 |
+
if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
|
| 185 |
+
std::forward<F>(f)(buff);
|
| 186 |
+
std::forward<R>(out)(true);
|
| 187 |
+
return true;
|
| 188 |
+
}
|
| 189 |
+
ipc::yield(k);
|
| 190 |
+
}
|
| 191 |
+
}
|
| 192 |
+
}
|
| 193 |
+
};
|
| 194 |
+
|
| 195 |
+
template <>
|
| 196 |
+
struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
|
| 197 |
+
|
| 198 |
+
using rc_t = std::uint64_t;
|
| 199 |
+
|
| 200 |
+
enum : rc_t {
|
| 201 |
+
ep_mask = 0x00000000ffffffffull,
|
| 202 |
+
ep_incr = 0x0000000100000000ull
|
| 203 |
+
};
|
| 204 |
+
|
| 205 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
| 206 |
+
struct elem_t {
|
| 207 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
| 208 |
+
std::atomic<rc_t> rc_ { 0 }; // read-counter
|
| 209 |
+
};
|
| 210 |
+
|
| 211 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
|
| 212 |
+
alignas(cache_line_size) rc_t epoch_ { 0 }; // only one writer
|
| 213 |
+
|
| 214 |
+
circ::u2_t cursor() const noexcept {
|
| 215 |
+
return wt_.load(std::memory_order_acquire);
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
template <typename W, typename F, typename E>
|
| 219 |
+
bool push(W* wrapper, F&& f, E* elems) {
|
| 220 |
+
E* el;
|
| 221 |
+
for (unsigned k = 0;;) {
|
| 222 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
| 223 |
+
if (cc == 0) return false; // no reader
|
| 224 |
+
el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
|
| 225 |
+
// check all consumers have finished reading this element
|
| 226 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
| 227 |
+
circ::cc_t rem_cc = cur_rc & ep_mask;
|
| 228 |
+
if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch_)) {
|
| 229 |
+
return false; // has not finished yet
|
| 230 |
+
}
|
| 231 |
+
// consider rem_cc to be 0 here
|
| 232 |
+
if (el->rc_.compare_exchange_weak(
|
| 233 |
+
cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
|
| 234 |
+
break;
|
| 235 |
+
}
|
| 236 |
+
ipc::yield(k);
|
| 237 |
+
}
|
| 238 |
+
std::forward<F>(f)(&(el->data_));
|
| 239 |
+
wt_.fetch_add(1, std::memory_order_release);
|
| 240 |
+
return true;
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
template <typename W, typename F, typename E>
|
| 244 |
+
bool force_push(W* wrapper, F&& f, E* elems) {
|
| 245 |
+
E* el;
|
| 246 |
+
epoch_ += ep_incr;
|
| 247 |
+
for (unsigned k = 0;;) {
|
| 248 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
| 249 |
+
if (cc == 0) return false; // no reader
|
| 250 |
+
el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
|
| 251 |
+
// check all consumers have finished reading this element
|
| 252 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
| 253 |
+
circ::cc_t rem_cc = cur_rc & ep_mask;
|
| 254 |
+
if (cc & rem_cc) {
|
| 255 |
+
ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
|
| 256 |
+
cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
|
| 257 |
+
if (cc == 0) return false; // no reader
|
| 258 |
+
}
|
| 259 |
+
// just compare & exchange
|
| 260 |
+
if (el->rc_.compare_exchange_weak(
|
| 261 |
+
cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
|
| 262 |
+
break;
|
| 263 |
+
}
|
| 264 |
+
ipc::yield(k);
|
| 265 |
+
}
|
| 266 |
+
std::forward<F>(f)(&(el->data_));
|
| 267 |
+
wt_.fetch_add(1, std::memory_order_release);
|
| 268 |
+
return true;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
template <typename W, typename F, typename R, typename E>
|
| 272 |
+
bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E* elems) {
|
| 273 |
+
if (cur == cursor()) return false; // acquire
|
| 274 |
+
auto* el = elems + circ::index_of(cur++);
|
| 275 |
+
std::forward<F>(f)(&(el->data_));
|
| 276 |
+
for (unsigned k = 0;;) {
|
| 277 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
| 278 |
+
if ((cur_rc & ep_mask) == 0) {
|
| 279 |
+
std::forward<R>(out)(true);
|
| 280 |
+
return true;
|
| 281 |
+
}
|
| 282 |
+
auto nxt_rc = cur_rc & ~static_cast<rc_t>(wrapper->connected_id());
|
| 283 |
+
if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
|
| 284 |
+
std::forward<R>(out)((nxt_rc & ep_mask) == 0);
|
| 285 |
+
return true;
|
| 286 |
+
}
|
| 287 |
+
ipc::yield(k);
|
| 288 |
+
}
|
| 289 |
+
}
|
| 290 |
+
};
|
| 291 |
+
|
| 292 |
+
template <>
|
| 293 |
+
struct prod_cons_impl<wr<relat::multi, relat::multi, trans::broadcast>> {
|
| 294 |
+
|
| 295 |
+
using rc_t = std::uint64_t;
|
| 296 |
+
using flag_t = std::uint64_t;
|
| 297 |
+
|
| 298 |
+
enum : rc_t {
|
| 299 |
+
rc_mask = 0x00000000ffffffffull,
|
| 300 |
+
ep_mask = 0x00ffffffffffffffull,
|
| 301 |
+
ep_incr = 0x0100000000000000ull,
|
| 302 |
+
ic_mask = 0xff000000ffffffffull,
|
| 303 |
+
ic_incr = 0x0000000100000000ull
|
| 304 |
+
};
|
| 305 |
+
|
| 306 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
| 307 |
+
struct elem_t {
|
| 308 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
| 309 |
+
std::atomic<rc_t > rc_ { 0 }; // read-counter
|
| 310 |
+
std::atomic<flag_t> f_ct_ { 0 }; // commit flag
|
| 311 |
+
};
|
| 312 |
+
|
| 313 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
|
| 314 |
+
alignas(cache_line_size) std::atomic<rc_t> epoch_ { 0 };
|
| 315 |
+
|
| 316 |
+
circ::u2_t cursor() const noexcept {
|
| 317 |
+
return ct_.load(std::memory_order_acquire);
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
constexpr static rc_t inc_rc(rc_t rc) noexcept {
|
| 321 |
+
return (rc & ic_mask) | ((rc + ic_incr) & ~ic_mask);
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
constexpr static rc_t inc_mask(rc_t rc) noexcept {
|
| 325 |
+
return inc_rc(rc) & ~rc_mask;
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
template <typename W, typename F, typename E>
|
| 329 |
+
bool push(W* wrapper, F&& f, E* elems) {
|
| 330 |
+
E* el;
|
| 331 |
+
circ::u2_t cur_ct;
|
| 332 |
+
rc_t epoch = epoch_.load(std::memory_order_acquire);
|
| 333 |
+
for (unsigned k = 0;;) {
|
| 334 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
| 335 |
+
if (cc == 0) return false; // no reader
|
| 336 |
+
el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
|
| 337 |
+
// check all consumers have finished reading this element
|
| 338 |
+
auto cur_rc = el->rc_.load(std::memory_order_relaxed);
|
| 339 |
+
circ::cc_t rem_cc = cur_rc & rc_mask;
|
| 340 |
+
if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch)) {
|
| 341 |
+
return false; // has not finished yet
|
| 342 |
+
}
|
| 343 |
+
else if (!rem_cc) {
|
| 344 |
+
auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
|
| 345 |
+
if ((cur_fl != cur_ct) && cur_fl) {
|
| 346 |
+
return false; // full
|
| 347 |
+
}
|
| 348 |
+
}
|
| 349 |
+
// consider rem_cc to be 0 here
|
| 350 |
+
if (el->rc_.compare_exchange_weak(
|
| 351 |
+
cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed) &&
|
| 352 |
+
epoch_.compare_exchange_weak(epoch, epoch, std::memory_order_acq_rel)) {
|
| 353 |
+
break;
|
| 354 |
+
}
|
| 355 |
+
ipc::yield(k);
|
| 356 |
+
}
|
| 357 |
+
// only one thread/process would touch here at one time
|
| 358 |
+
ct_.store(cur_ct + 1, std::memory_order_release);
|
| 359 |
+
std::forward<F>(f)(&(el->data_));
|
| 360 |
+
// set flag & try update wt
|
| 361 |
+
el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
|
| 362 |
+
return true;
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
template <typename W, typename F, typename E>
|
| 366 |
+
bool force_push(W* wrapper, F&& f, E* elems) {
|
| 367 |
+
E* el;
|
| 368 |
+
circ::u2_t cur_ct;
|
| 369 |
+
rc_t epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
|
| 370 |
+
for (unsigned k = 0;;) {
|
| 371 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
| 372 |
+
if (cc == 0) return false; // no reader
|
| 373 |
+
el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
|
| 374 |
+
// check all consumers have finished reading this element
|
| 375 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
| 376 |
+
circ::cc_t rem_cc = cur_rc & rc_mask;
|
| 377 |
+
if (cc & rem_cc) {
|
| 378 |
+
ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
|
| 379 |
+
cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
|
| 380 |
+
if (cc == 0) return false; // no reader
|
| 381 |
+
}
|
| 382 |
+
// just compare & exchange
|
| 383 |
+
if (el->rc_.compare_exchange_weak(
|
| 384 |
+
cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed)) {
|
| 385 |
+
if (epoch == epoch_.load(std::memory_order_acquire)) {
|
| 386 |
+
break;
|
| 387 |
+
}
|
| 388 |
+
else if (push(wrapper, std::forward<F>(f), elems)) {
|
| 389 |
+
return true;
|
| 390 |
+
}
|
| 391 |
+
epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
|
| 392 |
+
}
|
| 393 |
+
ipc::yield(k);
|
| 394 |
+
}
|
| 395 |
+
// only one thread/process would touch here at one time
|
| 396 |
+
ct_.store(cur_ct + 1, std::memory_order_release);
|
| 397 |
+
std::forward<F>(f)(&(el->data_));
|
| 398 |
+
// set flag & try update wt
|
| 399 |
+
el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
|
| 400 |
+
return true;
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
template <typename W, typename F, typename R, typename E, std::size_t N>
|
| 404 |
+
bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E(& elems)[N]) {
|
| 405 |
+
auto* el = elems + circ::index_of(cur);
|
| 406 |
+
auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
|
| 407 |
+
if (cur_fl != ~static_cast<flag_t>(cur)) {
|
| 408 |
+
return false; // empty
|
| 409 |
+
}
|
| 410 |
+
++cur;
|
| 411 |
+
std::forward<F>(f)(&(el->data_));
|
| 412 |
+
for (unsigned k = 0;;) {
|
| 413 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
| 414 |
+
if ((cur_rc & rc_mask) == 0) {
|
| 415 |
+
std::forward<R>(out)(true);
|
| 416 |
+
el->f_ct_.store(cur + N - 1, std::memory_order_release);
|
| 417 |
+
return true;
|
| 418 |
+
}
|
| 419 |
+
auto nxt_rc = inc_rc(cur_rc) & ~static_cast<rc_t>(wrapper->connected_id());
|
| 420 |
+
bool last_one = false;
|
| 421 |
+
if ((last_one = (nxt_rc & rc_mask) == 0)) {
|
| 422 |
+
el->f_ct_.store(cur + N - 1, std::memory_order_release);
|
| 423 |
+
}
|
| 424 |
+
if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
|
| 425 |
+
std::forward<R>(out)(last_one);
|
| 426 |
+
return true;
|
| 427 |
+
}
|
| 428 |
+
ipc::yield(k);
|
| 429 |
+
}
|
| 430 |
+
}
|
| 431 |
+
};
|
| 432 |
+
|
| 433 |
+
} // namespace ipc
|
crazy_functions/高级功能函数模板.py
CHANGED
|
@@ -11,7 +11,7 @@ def 高阶功能模板函数(txt, top_p, temperature, chatbot, history, systemPr
|
|
| 11 |
for i in range(5):
|
| 12 |
currentMonth = (datetime.date.today() + datetime.timedelta(days=i)).month
|
| 13 |
currentDay = (datetime.date.today() + datetime.timedelta(days=i)).day
|
| 14 |
-
i_say = f'历史中哪些事件发生在{currentMonth}月{currentDay}日?列举两条并发送相关图片。发送图片时,请使用Markdown,将Unsplash API中的PUT_YOUR_QUERY_HERE
|
| 15 |
chatbot.append((i_say, "[Local Message] waiting gpt response."))
|
| 16 |
yield chatbot, history, '正常' # 由于请求gpt需要一段时间,我们先及时地做一次状态显示
|
| 17 |
|
|
|
|
| 11 |
for i in range(5):
|
| 12 |
currentMonth = (datetime.date.today() + datetime.timedelta(days=i)).month
|
| 13 |
currentDay = (datetime.date.today() + datetime.timedelta(days=i)).day
|
| 14 |
+
i_say = f'历史中哪些事件发生在{currentMonth}月{currentDay}日?列举两条并发送相关图片。发送图片时,请使用Markdown,将Unsplash API中的PUT_YOUR_QUERY_HERE替换成描述该事件的一个最重要的单词。'
|
| 15 |
chatbot.append((i_say, "[Local Message] waiting gpt response."))
|
| 16 |
yield chatbot, history, '正常' # 由于请求gpt需要一段时间,我们先及时地做一次状态显示
|
| 17 |
|
functional_crazy.py
CHANGED
|
@@ -19,10 +19,10 @@ def get_crazy_functionals():
|
|
| 19 |
|
| 20 |
function_plugins = {
|
| 21 |
"请解析并解构此项目本身": {
|
| 22 |
-
#
|
| 23 |
"Function": 解析项目本身
|
| 24 |
},
|
| 25 |
-
"解析整个
|
| 26 |
"Color": "stop", # 按钮颜色
|
| 27 |
"Function": 解析一个Python项目
|
| 28 |
},
|
|
@@ -32,9 +32,10 @@ def get_crazy_functionals():
|
|
| 32 |
},
|
| 33 |
"解析整个C++项目": {
|
| 34 |
"Color": "stop", # 按钮颜色
|
|
|
|
| 35 |
"Function": 解析一个C项目
|
| 36 |
},
|
| 37 |
-
"读
|
| 38 |
"Color": "stop", # 按钮颜色
|
| 39 |
"Function": 读文章写摘要
|
| 40 |
},
|
|
@@ -52,7 +53,7 @@ def get_crazy_functionals():
|
|
| 52 |
},
|
| 53 |
}
|
| 54 |
|
| 55 |
-
# VisibleLevel=1
|
| 56 |
if UserVisibleLevel >= 1:
|
| 57 |
from crazy_functions.批量总结PDF文档 import 批量总结PDF文档
|
| 58 |
from crazy_functions.批量总结PDF文档pdfminer import 批量总结PDF文档pdfminer
|
|
@@ -60,11 +61,11 @@ def get_crazy_functionals():
|
|
| 60 |
function_plugins.update({
|
| 61 |
"[仅供开发调试] 批量总结PDF文档": {
|
| 62 |
"Color": "stop",
|
| 63 |
-
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
|
| 64 |
-
"Function": HotReload(批量总结PDF文档)
|
| 65 |
},
|
| 66 |
"[仅供开发调试] 批量总结PDF文档pdfminer": {
|
| 67 |
"Color": "stop",
|
|
|
|
| 68 |
"Function": HotReload(批量总结PDF文档pdfminer)
|
| 69 |
},
|
| 70 |
"[仅供开发调试] 批量总结Word文档": {
|
|
|
|
| 19 |
|
| 20 |
function_plugins = {
|
| 21 |
"请解析并解构此项目本身": {
|
| 22 |
+
"AsButton": False, # 加入下拉菜单中
|
| 23 |
"Function": 解析项目本身
|
| 24 |
},
|
| 25 |
+
"解析整个Py项目": {
|
| 26 |
"Color": "stop", # 按钮颜色
|
| 27 |
"Function": 解析一个Python项目
|
| 28 |
},
|
|
|
|
| 32 |
},
|
| 33 |
"解析整个C++项目": {
|
| 34 |
"Color": "stop", # 按钮颜色
|
| 35 |
+
"AsButton": False, # 加入下拉菜单中
|
| 36 |
"Function": 解析一个C项目
|
| 37 |
},
|
| 38 |
+
"读Tex论文写摘要": {
|
| 39 |
"Color": "stop", # 按钮颜色
|
| 40 |
"Function": 读文章写摘要
|
| 41 |
},
|
|
|
|
| 53 |
},
|
| 54 |
}
|
| 55 |
|
| 56 |
+
# VisibleLevel=1 经过测试,但功能上距离达到完美状态还差一点点
|
| 57 |
if UserVisibleLevel >= 1:
|
| 58 |
from crazy_functions.批量总结PDF文档 import 批量总结PDF文档
|
| 59 |
from crazy_functions.批量总结PDF文档pdfminer import 批量总结PDF文档pdfminer
|
|
|
|
| 61 |
function_plugins.update({
|
| 62 |
"[仅供开发调试] 批量总结PDF文档": {
|
| 63 |
"Color": "stop",
|
| 64 |
+
"Function": HotReload(批量总结PDF文档) # HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
|
|
|
|
| 65 |
},
|
| 66 |
"[仅供开发调试] 批量总结PDF文档pdfminer": {
|
| 67 |
"Color": "stop",
|
| 68 |
+
"AsButton": False, # 加入下拉菜单中
|
| 69 |
"Function": HotReload(批量总结PDF文档pdfminer)
|
| 70 |
},
|
| 71 |
"[仅供开发调试] 批量总结Word文档": {
|
main.py
CHANGED
|
@@ -4,9 +4,8 @@ from predict import predict
|
|
| 4 |
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf
|
| 5 |
|
| 6 |
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
|
| 7 |
-
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION = \
|
| 8 |
-
get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION')
|
| 9 |
-
|
| 10 |
|
| 11 |
# 如果WEB_PORT是-1, 则随机选取WEB端口
|
| 12 |
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
|
|
@@ -17,18 +16,18 @@ title_html = """<h1 align="center">ChatGPT 学术优化</h1>"""
|
|
| 17 |
|
| 18 |
# 问询记录, python 版本建议3.9+(越新越好)
|
| 19 |
import logging
|
| 20 |
-
os.makedirs(
|
| 21 |
-
try:logging.basicConfig(filename=
|
| 22 |
-
except:logging.basicConfig(filename=
|
| 23 |
-
print(
|
| 24 |
|
| 25 |
# 一些普通功能模块
|
| 26 |
from functional import get_functionals
|
| 27 |
functional = get_functionals()
|
| 28 |
|
| 29 |
-
#
|
| 30 |
from functional_crazy import get_crazy_functionals
|
| 31 |
-
|
| 32 |
|
| 33 |
# 处理markdown文本格式的转变
|
| 34 |
gr.Chatbot.postprocess = format_io
|
|
@@ -40,11 +39,10 @@ set_theme = adjust_theme()
|
|
| 40 |
cancel_handles = []
|
| 41 |
with gr.Blocks(theme=set_theme, analytics_enabled=False) as demo:
|
| 42 |
gr.HTML(title_html)
|
| 43 |
-
with gr.Row():
|
| 44 |
with gr.Column(scale=2):
|
| 45 |
chatbot = gr.Chatbot()
|
| 46 |
-
chatbot.style(height=
|
| 47 |
-
chatbot.style()
|
| 48 |
history = gr.State([])
|
| 49 |
with gr.Column(scale=1):
|
| 50 |
with gr.Row():
|
|
@@ -66,49 +64,70 @@ with gr.Blocks(theme=set_theme, analytics_enabled=False) as demo:
|
|
| 66 |
with gr.Row():
|
| 67 |
gr.Markdown("注意:以下“红颜色”标识的函数插件需从input区读取路径作为参数.")
|
| 68 |
with gr.Row():
|
| 69 |
-
for k in
|
| 70 |
-
|
| 71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
with gr.Row():
|
| 73 |
-
with gr.Accordion("
|
| 74 |
-
file_upload = gr.Files(label=
|
| 75 |
with gr.Accordion("展开SysPrompt & GPT参数 & 交互界面布局", open=False):
|
| 76 |
system_prompt = gr.Textbox(show_label=True, placeholder=f"System Prompt", label="System prompt", value=initial_prompt)
|
| 77 |
top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
|
| 78 |
temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",)
|
| 79 |
-
checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区"],
|
| 80 |
-
value=["基础功能区", "函数插件区"], label="显示哪些功能区")
|
| 81 |
|
| 82 |
-
|
|
|
|
| 83 |
ret = {}
|
| 84 |
-
|
| 85 |
-
ret.update({
|
| 86 |
-
# if area_crazy_fn.visible != ("函数插件区" in a):
|
| 87 |
-
ret.update({area_crazy_fn: gr.update(visible=("函数插件区" in a))})
|
| 88 |
return ret
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
|
|
|
| 93 |
empty_txt_args = dict(fn=lambda: "", inputs=[], outputs=[txt]) # 用于在提交后清空输入栏
|
| 94 |
-
|
| 95 |
-
cancel_handles.append(txt.submit(**predict_args))
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
#
|
| 99 |
-
resetBtn.click(lambda: ([], [], "已重置"), None, [chatbot, history, statusDisplay])
|
| 100 |
for k in functional:
|
| 101 |
-
click_handle = functional[k]["Button"].click(predict,
|
| 102 |
-
[txt, top_p, temperature, chatbot, history, system_prompt, gr.State(True), gr.State(k)], [chatbot, history, statusDisplay], show_progress=True)
|
| 103 |
cancel_handles.append(click_handle)
|
|
|
|
| 104 |
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt], [chatbot, txt])
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
)
|
| 109 |
-
|
| 110 |
-
except: pass
|
| 111 |
cancel_handles.append(click_handle)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
|
| 113 |
|
| 114 |
# gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数
|
|
@@ -117,7 +136,7 @@ def auto_opentab_delay():
|
|
| 117 |
print(f"如果浏览器没有自动打开,请复制并转到以下URL: http://localhost:{PORT}")
|
| 118 |
def open():
|
| 119 |
time.sleep(2)
|
| 120 |
-
webbrowser.open_new_tab(f
|
| 121 |
threading.Thread(target=open, name="open-browser", daemon=True).start()
|
| 122 |
|
| 123 |
auto_opentab_delay()
|
|
|
|
| 4 |
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf
|
| 5 |
|
| 6 |
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
|
| 7 |
+
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION, CHATBOT_HEIGHT = \
|
| 8 |
+
get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION', 'CHATBOT_HEIGHT')
|
|
|
|
| 9 |
|
| 10 |
# 如果WEB_PORT是-1, 则随机选取WEB端口
|
| 11 |
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
|
|
|
|
| 16 |
|
| 17 |
# 问询记录, python 版本建议3.9+(越新越好)
|
| 18 |
import logging
|
| 19 |
+
os.makedirs("gpt_log", exist_ok=True)
|
| 20 |
+
try:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO, encoding="utf-8")
|
| 21 |
+
except:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO)
|
| 22 |
+
print("所有问询记录将自动保存在本地目录./gpt_log/chat_secrets.log, 请注意自我隐私保护哦!")
|
| 23 |
|
| 24 |
# 一些普通功能模块
|
| 25 |
from functional import get_functionals
|
| 26 |
functional = get_functionals()
|
| 27 |
|
| 28 |
+
# 高级函数插件
|
| 29 |
from functional_crazy import get_crazy_functionals
|
| 30 |
+
crazy_fns = get_crazy_functionals()
|
| 31 |
|
| 32 |
# 处理markdown文本格式的转变
|
| 33 |
gr.Chatbot.postprocess = format_io
|
|
|
|
| 39 |
cancel_handles = []
|
| 40 |
with gr.Blocks(theme=set_theme, analytics_enabled=False) as demo:
|
| 41 |
gr.HTML(title_html)
|
| 42 |
+
with gr.Row().style(equal_height=True):
|
| 43 |
with gr.Column(scale=2):
|
| 44 |
chatbot = gr.Chatbot()
|
| 45 |
+
chatbot.style(height=CHATBOT_HEIGHT)
|
|
|
|
| 46 |
history = gr.State([])
|
| 47 |
with gr.Column(scale=1):
|
| 48 |
with gr.Row():
|
|
|
|
| 64 |
with gr.Row():
|
| 65 |
gr.Markdown("注意:以下“红颜色”标识的函数插件需从input区读取路径作为参数.")
|
| 66 |
with gr.Row():
|
| 67 |
+
for k in crazy_fns:
|
| 68 |
+
if not crazy_fns[k].get("AsButton", True): continue
|
| 69 |
+
variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
|
| 70 |
+
crazy_fns[k]["Button"] = gr.Button(k, variant=variant)
|
| 71 |
+
with gr.Row():
|
| 72 |
+
with gr.Accordion("更多函数插件", open=True):
|
| 73 |
+
dropdown_fn_list = [k for k in crazy_fns.keys() if not crazy_fns[k].get("AsButton", True)]
|
| 74 |
+
with gr.Column(scale=1):
|
| 75 |
+
dropdown = gr.Dropdown(dropdown_fn_list, value=r"打开插件列表", label="").style(container=False)
|
| 76 |
+
with gr.Column(scale=1):
|
| 77 |
+
switchy_bt = gr.Button(r"请先从插件列表中选择", variant="secondary")
|
| 78 |
with gr.Row():
|
| 79 |
+
with gr.Accordion("点击展开“文件上传区”。上传本地文件可供红色函数插件调用。", open=False) as area_file_up:
|
| 80 |
+
file_upload = gr.Files(label="任何文件, 但推荐上传压缩文件(zip, tar)", file_count="multiple")
|
| 81 |
with gr.Accordion("展开SysPrompt & GPT参数 & 交互界面布局", open=False):
|
| 82 |
system_prompt = gr.Textbox(show_label=True, placeholder=f"System Prompt", label="System prompt", value=initial_prompt)
|
| 83 |
top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
|
| 84 |
temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",)
|
| 85 |
+
checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区"], value=["基础功能区", "函数插件区"], label="显示/隐藏功能区")
|
|
|
|
| 86 |
|
| 87 |
+
# 功能区显示开关与功能区的互动
|
| 88 |
+
def fn_area_visibility(a):
|
| 89 |
ret = {}
|
| 90 |
+
ret.update({area_basic_fn: gr.update(visible=("基础功能区" in a))})
|
| 91 |
+
ret.update({area_crazy_fn: gr.update(visible=("函数插件区" in a))})
|
|
|
|
|
|
|
| 92 |
return ret
|
| 93 |
+
checkboxes.select(fn_area_visibility, [checkboxes], [area_basic_fn, area_crazy_fn] )
|
| 94 |
+
# 整理反复出现的控件句柄组合
|
| 95 |
+
input_combo = [txt, top_p, temperature, chatbot, history, system_prompt]
|
| 96 |
+
output_combo = [chatbot, history, statusDisplay]
|
| 97 |
+
predict_args = dict(fn=predict, inputs=input_combo, outputs=output_combo, show_progress=True)
|
| 98 |
empty_txt_args = dict(fn=lambda: "", inputs=[], outputs=[txt]) # 用于在提交后清空输入栏
|
| 99 |
+
# 提交按钮、重置按钮
|
| 100 |
+
cancel_handles.append(txt.submit(**predict_args)) #; txt.submit(**empty_txt_args) 在提交后清空输入栏
|
| 101 |
+
cancel_handles.append(submitBtn.click(**predict_args)) #; submitBtn.click(**empty_txt_args) 在提交后清空输入栏
|
| 102 |
+
resetBtn.click(lambda: ([], [], "已重置"), None, output_combo)
|
| 103 |
+
# 基础功能区的回调函数注册
|
|
|
|
| 104 |
for k in functional:
|
| 105 |
+
click_handle = functional[k]["Button"].click(predict, [*input_combo, gr.State(True), gr.State(k)], output_combo, show_progress=True)
|
|
|
|
| 106 |
cancel_handles.append(click_handle)
|
| 107 |
+
# 文件上传区,接收文件后与chatbot的互动
|
| 108 |
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt], [chatbot, txt])
|
| 109 |
+
# 函数插件-固定按钮区
|
| 110 |
+
for k in crazy_fns:
|
| 111 |
+
if not crazy_fns[k].get("AsButton", True): continue
|
| 112 |
+
click_handle = crazy_fns[k]["Button"].click(crazy_fns[k]["Function"], [*input_combo, gr.State(PORT)], output_combo)
|
| 113 |
+
click_handle.then(on_report_generated, [file_upload, chatbot], [file_upload, chatbot])
|
|
|
|
| 114 |
cancel_handles.append(click_handle)
|
| 115 |
+
# 函数插件-下拉菜单与随变按钮的互动
|
| 116 |
+
def on_dropdown_changed(k):
|
| 117 |
+
variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
|
| 118 |
+
return {switchy_bt: gr.update(value=k, variant=variant)}
|
| 119 |
+
dropdown.select(on_dropdown_changed, [dropdown], [switchy_bt] )
|
| 120 |
+
# 随变按钮的回调函数注册
|
| 121 |
+
def route(k, *args, **kwargs):
|
| 122 |
+
if k in [r"打开插件列表", r"先从插件列表中选择"]: return
|
| 123 |
+
yield from crazy_fns[k]["Function"](*args, **kwargs)
|
| 124 |
+
click_handle = switchy_bt.click(route,[switchy_bt, *input_combo, gr.State(PORT)], output_combo)
|
| 125 |
+
click_handle.then(on_report_generated, [file_upload, chatbot], [file_upload, chatbot])
|
| 126 |
+
def expand_file_area(file_upload, area_file_up):
|
| 127 |
+
if len(file_upload)>0: return {area_file_up: gr.update(open=True)}
|
| 128 |
+
click_handle.then(expand_file_area, [file_upload, area_file_up], [area_file_up])
|
| 129 |
+
cancel_handles.append(click_handle)
|
| 130 |
+
# 终止按钮的回调函数注册
|
| 131 |
stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
|
| 132 |
|
| 133 |
# gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数
|
|
|
|
| 136 |
print(f"如果浏览器没有自动打开,请复制并转到以下URL: http://localhost:{PORT}")
|
| 137 |
def open():
|
| 138 |
time.sleep(2)
|
| 139 |
+
webbrowser.open_new_tab(f"http://localhost:{PORT}")
|
| 140 |
threading.Thread(target=open, name="open-browser", daemon=True).start()
|
| 141 |
|
| 142 |
auto_opentab_delay()
|
predict.py
CHANGED
|
@@ -96,13 +96,19 @@ def predict_no_ui_long_connection(inputs, top_p, temperature, history=[], sys_pr
|
|
| 96 |
except StopIteration: break
|
| 97 |
if len(chunk)==0: continue
|
| 98 |
if not chunk.startswith('data:'):
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
if len(delta) == 0: break
|
| 103 |
if "role" in delta: continue
|
| 104 |
if "content" in delta: result += delta["content"]; print(delta["content"], end='')
|
| 105 |
else: raise RuntimeError("意外Json结构:"+delta)
|
|
|
|
|
|
|
| 106 |
return result
|
| 107 |
|
| 108 |
|
|
|
|
| 96 |
except StopIteration: break
|
| 97 |
if len(chunk)==0: continue
|
| 98 |
if not chunk.startswith('data:'):
|
| 99 |
+
error_msg = get_full_error(chunk.encode('utf8'), stream_response).decode()
|
| 100 |
+
if "reduce the length" in error_msg:
|
| 101 |
+
raise ConnectionAbortedError("OpenAI拒绝了请求:" + error_msg)
|
| 102 |
+
else:
|
| 103 |
+
raise RuntimeError("OpenAI拒绝了请求:" + error_msg)
|
| 104 |
+
json_data = json.loads(chunk.lstrip('data:'))['choices'][0]
|
| 105 |
+
delta = json_data["delta"]
|
| 106 |
if len(delta) == 0: break
|
| 107 |
if "role" in delta: continue
|
| 108 |
if "content" in delta: result += delta["content"]; print(delta["content"], end='')
|
| 109 |
else: raise RuntimeError("意外Json结构:"+delta)
|
| 110 |
+
if json_data['finish_reason'] == 'length':
|
| 111 |
+
raise ConnectionAbortedError("正常结束,但显示Token不足。")
|
| 112 |
return result
|
| 113 |
|
| 114 |
|
toolbox.py
CHANGED
|
@@ -2,21 +2,21 @@ import markdown, mdtex2html, threading, importlib, traceback, importlib, inspect
|
|
| 2 |
from show_math import convert as convert_math
|
| 3 |
from functools import wraps
|
| 4 |
|
| 5 |
-
def get_reduce_token_percent(
|
| 6 |
try:
|
| 7 |
# text = "maximum context length is 4097 tokens. However, your messages resulted in 4870 tokens"
|
| 8 |
pattern = r"(\d+)\s+tokens\b"
|
| 9 |
match = re.findall(pattern, text)
|
| 10 |
-
|
| 11 |
-
max_limit = float(match[0]) -
|
| 12 |
current_tokens = float(match[1])
|
| 13 |
ratio = max_limit/current_tokens
|
| 14 |
assert ratio > 0 and ratio < 1
|
| 15 |
-
return ratio
|
| 16 |
except:
|
| 17 |
-
return 0.5
|
| 18 |
|
| 19 |
-
def predict_no_ui_but_counting_down(i_say, i_say_show_user, chatbot, top_p, temperature, history=[], sys_prompt='', long_connection=
|
| 20 |
"""
|
| 21 |
调用简单的predict_no_ui接口,但是依然保留了些许界面心跳功能,当对话太长时,会自动采用二分法截断
|
| 22 |
i_say: 当前输入
|
|
@@ -45,19 +45,18 @@ def predict_no_ui_but_counting_down(i_say, i_say_show_user, chatbot, top_p, temp
|
|
| 45 |
break
|
| 46 |
except ConnectionAbortedError as token_exceeded_error:
|
| 47 |
# 尝试计算比例,尽可能多地保留文本
|
| 48 |
-
p_ratio = get_reduce_token_percent(str(token_exceeded_error))
|
| 49 |
if len(history) > 0:
|
| 50 |
history = [his[ int(len(his) *p_ratio): ] for his in history if his is not None]
|
| 51 |
-
mutable[1] = 'Warning! History conversation is too long, cut into half. '
|
| 52 |
else:
|
| 53 |
i_say = i_say[: int(len(i_say) *p_ratio) ]
|
| 54 |
-
|
| 55 |
except TimeoutError as e:
|
| 56 |
-
mutable[0] = '[Local Message]
|
| 57 |
raise TimeoutError
|
| 58 |
except Exception as e:
|
| 59 |
-
mutable[0] = f'[Local Message]
|
| 60 |
-
raise RuntimeError(f'[Local Message]
|
| 61 |
# 创建新线程发出http请求
|
| 62 |
thread_name = threading.Thread(target=mt, args=(i_say, history)); thread_name.start()
|
| 63 |
# 原来的线程则负责持续更新UI,实现一个超时倒计时,并等待新线程的任务完成
|
|
@@ -286,7 +285,7 @@ def on_report_generated(files, chatbot):
|
|
| 286 |
report_files = find_recent_files('gpt_log')
|
| 287 |
if len(report_files) == 0: return report_files, chatbot
|
| 288 |
# files.extend(report_files)
|
| 289 |
-
chatbot.append(['汇总报告如何远程获取?', '
|
| 290 |
return report_files, chatbot
|
| 291 |
|
| 292 |
def get_conf(*args):
|
|
|
|
| 2 |
from show_math import convert as convert_math
|
| 3 |
from functools import wraps
|
| 4 |
|
| 5 |
+
def get_reduce_token_percent(text):
|
| 6 |
try:
|
| 7 |
# text = "maximum context length is 4097 tokens. However, your messages resulted in 4870 tokens"
|
| 8 |
pattern = r"(\d+)\s+tokens\b"
|
| 9 |
match = re.findall(pattern, text)
|
| 10 |
+
EXCEED_ALLO = 500 # 稍微留一点余地,否则在回复时会因余量太少出问题
|
| 11 |
+
max_limit = float(match[0]) - EXCEED_ALLO
|
| 12 |
current_tokens = float(match[1])
|
| 13 |
ratio = max_limit/current_tokens
|
| 14 |
assert ratio > 0 and ratio < 1
|
| 15 |
+
return ratio, str(int(current_tokens-max_limit))
|
| 16 |
except:
|
| 17 |
+
return 0.5, '不详'
|
| 18 |
|
| 19 |
+
def predict_no_ui_but_counting_down(i_say, i_say_show_user, chatbot, top_p, temperature, history=[], sys_prompt='', long_connection=True):
|
| 20 |
"""
|
| 21 |
调用简单的predict_no_ui接口,但是依然保留了些许界面心跳功能,当对话太长时,会自动采用二分法截断
|
| 22 |
i_say: 当前输入
|
|
|
|
| 45 |
break
|
| 46 |
except ConnectionAbortedError as token_exceeded_error:
|
| 47 |
# 尝试计算比例,尽可能多地保留文本
|
| 48 |
+
p_ratio, n_exceed = get_reduce_token_percent(str(token_exceeded_error))
|
| 49 |
if len(history) > 0:
|
| 50 |
history = [his[ int(len(his) *p_ratio): ] for his in history if his is not None]
|
|
|
|
| 51 |
else:
|
| 52 |
i_say = i_say[: int(len(i_say) *p_ratio) ]
|
| 53 |
+
mutable[1] = f'警告,文本过长将进行截断,Token溢出数:{n_exceed},截断比例:{(1-p_ratio):.0%}。'
|
| 54 |
except TimeoutError as e:
|
| 55 |
+
mutable[0] = '[Local Message] 请求超时。'
|
| 56 |
raise TimeoutError
|
| 57 |
except Exception as e:
|
| 58 |
+
mutable[0] = f'[Local Message] 异常:{str(e)}.'
|
| 59 |
+
raise RuntimeError(f'[Local Message] 异常:{str(e)}.')
|
| 60 |
# 创建新线程发出http请求
|
| 61 |
thread_name = threading.Thread(target=mt, args=(i_say, history)); thread_name.start()
|
| 62 |
# 原来的线程则负责持续更新UI,实现一个超时倒计时,并等待新线程的任务完成
|
|
|
|
| 285 |
report_files = find_recent_files('gpt_log')
|
| 286 |
if len(report_files) == 0: return report_files, chatbot
|
| 287 |
# files.extend(report_files)
|
| 288 |
+
chatbot.append(['汇总报告如何远程获取?', '汇总报告已经添加到右侧“文件上传区”(可能处于折叠状态),请查收。'])
|
| 289 |
return report_files, chatbot
|
| 290 |
|
| 291 |
def get_conf(*args):
|