├── LICENSE ├── README.md ├── esp32_arduino_ble_BME280.aia ├── esp32_arduino_ble_LED.aia ├── esp32_arduino_bluetooth_BME280.aia ├── esp32_arduino_bluetooth_LED.aia └── 通过WiFi接收视频 ├── ScreenShotSender.exe ├── ScreenShotSender ├── App.config ├── FormCaptureBox.Designer.cs ├── FormCaptureBox.cs ├── FormCaptureBox.resx ├── FormSenderMain.Designer.cs ├── FormSenderMain.cs ├── FormSenderMain.resx ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── ScreenShotSender.csproj ├── ScreenShotSender.csproj.user ├── ScreenShotSender.sln └── TCPSender.cs ├── arduino_ESP32 ├── include │ └── README ├── lib │ └── README ├── platformio.ini ├── src │ ├── DMADrawer.cpp │ ├── DMADrawer.h │ ├── TCPReceiver.h │ ├── main.cpp │ ├── tjpgdClass.cpp │ └── tjpgdClass.h └── test │ └── README └── esptouch.apk /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # arduino-ESP32-Tutorial 2 | -------------------------------------------------------------------------------- /esp32_arduino_ble_BME280.aia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modi12jin/arduino-ESP32-Tutorial/e2a96a2bac9e7c4f160b6980d68c5d741e5290e0/esp32_arduino_ble_BME280.aia -------------------------------------------------------------------------------- /esp32_arduino_ble_LED.aia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modi12jin/arduino-ESP32-Tutorial/e2a96a2bac9e7c4f160b6980d68c5d741e5290e0/esp32_arduino_ble_LED.aia -------------------------------------------------------------------------------- /esp32_arduino_bluetooth_BME280.aia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modi12jin/arduino-ESP32-Tutorial/e2a96a2bac9e7c4f160b6980d68c5d741e5290e0/esp32_arduino_bluetooth_BME280.aia -------------------------------------------------------------------------------- /esp32_arduino_bluetooth_LED.aia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modi12jin/arduino-ESP32-Tutorial/e2a96a2bac9e7c4f160b6980d68c5d741e5290e0/esp32_arduino_bluetooth_LED.aia -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modi12jin/arduino-ESP32-Tutorial/e2a96a2bac9e7c4f160b6980d68c5d741e5290e0/通过WiFi接收视频/ScreenShotSender.exe -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/FormCaptureBox.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ScreenShotSender 2 | { 3 | partial class FormCaptureBox 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.panel1 = new System.Windows.Forms.Panel(); 32 | this.lblSize = new System.Windows.Forms.Label(); 33 | this.panel1.SuspendLayout(); 34 | this.SuspendLayout(); 35 | // 36 | // panel1 37 | // 38 | this.panel1.BackColor = System.Drawing.SystemColors.Window; 39 | this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 40 | this.panel1.Controls.Add(this.lblSize); 41 | this.panel1.Cursor = System.Windows.Forms.Cursors.SizeAll; 42 | this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; 43 | this.panel1.Location = new System.Drawing.Point(0, 0); 44 | this.panel1.Name = "panel1"; 45 | this.panel1.Size = new System.Drawing.Size(283, 204); 46 | this.panel1.TabIndex = 0; 47 | this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form_MouseDown); 48 | this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form_MouseMove); 49 | // 50 | // lblSize 51 | // 52 | this.lblSize.AutoSize = true; 53 | this.lblSize.Location = new System.Drawing.Point(0, 0); 54 | this.lblSize.Name = "lblSize"; 55 | this.lblSize.Size = new System.Drawing.Size(23, 12); 56 | this.lblSize.TabIndex = 1; 57 | this.lblSize.Text = "0/0"; 58 | this.lblSize.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form_MouseDown); 59 | this.lblSize.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form_MouseMove); 60 | // 61 | // FormCaptureBox 62 | // 63 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 64 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 65 | this.ClientSize = new System.Drawing.Size(283, 204); 66 | this.Controls.Add(this.panel1); 67 | this.KeyPreview = true; 68 | this.MinimumSize = new System.Drawing.Size(21, 55); 69 | this.Name = "FormCaptureBox"; 70 | this.Opacity = 0.6D; 71 | this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; 72 | this.Text = "FormCaptureBox"; 73 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormCaptureBox_FormClosing); 74 | this.Load += new System.EventHandler(this.FormCaptureBox_Load); 75 | this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.FormCaptureBox_KeyDown); 76 | this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form_MouseDown); 77 | this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form_MouseMove); 78 | this.Resize += new System.EventHandler(this.FormCaptureBox_Resize); 79 | this.panel1.ResumeLayout(false); 80 | this.panel1.PerformLayout(); 81 | this.ResumeLayout(false); 82 | 83 | } 84 | 85 | #endregion 86 | 87 | private System.Windows.Forms.Panel panel1; 88 | private System.Windows.Forms.Label lblSize; 89 | } 90 | } -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/FormCaptureBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Drawing.Imaging; 7 | using System.Linq; 8 | using System.Runtime.InteropServices; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Windows.Forms; 12 | 13 | namespace ScreenShotSender 14 | { 15 | public partial class FormCaptureBox : Form 16 | { 17 | public FormCaptureBox() 18 | { 19 | InitializeComponent(); 20 | } 21 | 22 | private void FormCaptureBox_FormClosing(object sender, FormClosingEventArgs e) 23 | { 24 | if (e.CloseReason == CloseReason.UserClosing) 25 | { 26 | Hide(); 27 | e.Cancel = true; 28 | } 29 | } 30 | 31 | private Bitmap _bmp; 32 | private Point _mousePos; 33 | 34 | protected override bool ShowWithoutActivation => true; 35 | protected override CreateParams CreateParams 36 | { 37 | get { 38 | const int WS_BORDER = 0x00800000; 39 | CreateParams cp = base.CreateParams; 40 | cp.Style &= (~WS_BORDER); 41 | return cp; 42 | } 43 | } 44 | 45 | [DllImport("user32.dll", SetLastError = true)] 46 | [return: MarshalAs(UnmanagedType.Bool)] 47 | private static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags); 48 | private void SetTopMost() 49 | { 50 | const int HWND_TOPMOST = -1; 51 | const uint SWP_NOSIZE = 0x0001; 52 | const uint SWP_NOMOVE = 0x0002; 53 | const uint SWP_NOACTIVATE = 0x0010; 54 | const uint SWP_SHOWWINDOW = 0x0040; 55 | const uint SWP_NOSENDCHANGING = 0x0400; 56 | SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_SHOWWINDOW); 57 | } 58 | private void FormCaptureBox_Load(object sender, EventArgs e) 59 | { 60 | SetTopMost(); 61 | updateRegion(); 62 | } 63 | private void FormCaptureBox_Resize(object sender, EventArgs e) 64 | { 65 | updateRegion(); 66 | lblSize.Text = Width.ToString() + ":" + Height.ToString(); 67 | } 68 | private void updateRegion() 69 | { 70 | var path = new System.Drawing.Drawing2D.GraphicsPath(); 71 | path.AddRectangle(new Rectangle(0, 0, Width, Height)); 72 | path.AddRectangle(new Rectangle(30,30, Width-60,Height-60)); 73 | Region = new Region(path); 74 | } 75 | 76 | private void Form_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) 77 | { 78 | if ((e.Button & MouseButtons.Left) == MouseButtons.Left) _mousePos = new Point(e.X, e.Y); 79 | } 80 | 81 | private void Form_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) 82 | { 83 | if ((e.Button & MouseButtons.Left) == MouseButtons.Left) 84 | { 85 | Left += e.X - _mousePos.X; 86 | Top += e.Y - _mousePos.Y; 87 | } 88 | } 89 | 90 | public Bitmap CaptureFrame() 91 | { 92 | if (_bmp == null || _bmp.Size != Size) 93 | { 94 | _bmp = new Bitmap(Width, Height, PixelFormat.Format32bppArgb); 95 | } 96 | var g = Graphics.FromImage(_bmp); 97 | var upperLeftSource = this.Location; 98 | var upperLeftDestination = new Point(0, 0); 99 | g.CopyFromScreen( upperLeftSource 100 | , upperLeftDestination 101 | , this.Size 102 | , CopyPixelOperation.SourceCopy 103 | ); 104 | return _bmp; 105 | } 106 | 107 | private void FormCaptureBox_KeyDown(object sender, KeyEventArgs e) 108 | { 109 | int p = e.Control ? 10 : 1; 110 | if (e.Shift) 111 | { 112 | var tmp = Size; 113 | switch (e.KeyCode) 114 | { 115 | case Keys.Up: tmp.Height -= p; break; 116 | case Keys.Down: tmp.Height += p; break; 117 | case Keys.Left: tmp.Width -= p; break; 118 | case Keys.Right: tmp.Width += p; break; 119 | } 120 | Size = tmp; 121 | } 122 | else 123 | { 124 | var tmp = Location; 125 | switch (e.KeyCode) 126 | { 127 | case Keys.Up: tmp.Y -= p; break; 128 | case Keys.Down: tmp.Y += p; break; 129 | case Keys.Left: tmp.X -= p; break; 130 | case Keys.Right: tmp.X += p; break; 131 | } 132 | Location = tmp; 133 | } 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/FormCaptureBox.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/FormSenderMain.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ScreenShotSender 2 | { 3 | partial class FormSenderMain 4 | { 5 | /// 6 | /// 必要なデザイナー変数です。 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// 使用中のリソースをすべてクリーンアップします。 12 | /// 13 | /// マネージド リソースを破棄する場合は true を指定し、その他の場合は false を指定します。 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows フォーム デザイナーで生成されたコード 24 | 25 | /// 26 | /// デザイナー サポートに必要なメソッドです。このメソッドの内容を 27 | /// コード エディターで変更しないでください。 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | this.btnShowFrame = new System.Windows.Forms.Button(); 33 | this.btnStartStopr = new System.Windows.Forms.Button(); 34 | this.pnlTop1 = new System.Windows.Forms.Panel(); 35 | this.nudRow = new System.Windows.Forms.NumericUpDown(); 36 | this.label3 = new System.Windows.Forms.Label(); 37 | this.nudCol = new System.Windows.Forms.NumericUpDown(); 38 | this.label1 = new System.Windows.Forms.Label(); 39 | this.nudQuality = new System.Windows.Forms.NumericUpDown(); 40 | this.label2 = new System.Windows.Forms.Label(); 41 | this.nudHeight = new System.Windows.Forms.NumericUpDown(); 42 | this.nudWidth = new System.Windows.Forms.NumericUpDown(); 43 | this.pbPreview = new System.Windows.Forms.PictureBox(); 44 | this.timer1 = new System.Windows.Forms.Timer(this.components); 45 | this.pnlAll = new System.Windows.Forms.Panel(); 46 | this.pnlTop2 = new System.Windows.Forms.Panel(); 47 | this.lblHeight = new System.Windows.Forms.Label(); 48 | this.lblWidth = new System.Windows.Forms.Label(); 49 | this.tlpHost = new System.Windows.Forms.TableLayoutPanel(); 50 | this.pnlTop1.SuspendLayout(); 51 | ((System.ComponentModel.ISupportInitialize)(this.nudRow)).BeginInit(); 52 | ((System.ComponentModel.ISupportInitialize)(this.nudCol)).BeginInit(); 53 | ((System.ComponentModel.ISupportInitialize)(this.nudQuality)).BeginInit(); 54 | ((System.ComponentModel.ISupportInitialize)(this.nudHeight)).BeginInit(); 55 | ((System.ComponentModel.ISupportInitialize)(this.nudWidth)).BeginInit(); 56 | ((System.ComponentModel.ISupportInitialize)(this.pbPreview)).BeginInit(); 57 | this.pnlAll.SuspendLayout(); 58 | this.pnlTop2.SuspendLayout(); 59 | this.SuspendLayout(); 60 | // 61 | // btnShowFrame 62 | // 63 | this.btnShowFrame.Dock = System.Windows.Forms.DockStyle.Left; 64 | this.btnShowFrame.Location = new System.Drawing.Point(0, 0); 65 | this.btnShowFrame.Name = "btnShowFrame"; 66 | this.btnShowFrame.Size = new System.Drawing.Size(81, 19); 67 | this.btnShowFrame.TabIndex = 0; 68 | this.btnShowFrame.Text = "ShowBox"; 69 | this.btnShowFrame.UseVisualStyleBackColor = true; 70 | this.btnShowFrame.Click += new System.EventHandler(this.btnShowFrame_Click); 71 | // 72 | // btnStartStopr 73 | // 74 | this.btnStartStopr.Dock = System.Windows.Forms.DockStyle.Left; 75 | this.btnStartStopr.Location = new System.Drawing.Point(81, 0); 76 | this.btnStartStopr.Name = "btnStartStopr"; 77 | this.btnStartStopr.Size = new System.Drawing.Size(81, 19); 78 | this.btnStartStopr.TabIndex = 1; 79 | this.btnStartStopr.Text = "Connect"; 80 | this.btnStartStopr.UseVisualStyleBackColor = true; 81 | this.btnStartStopr.Click += new System.EventHandler(this.btnStartStop_Click); 82 | // 83 | // pnlTop1 84 | // 85 | this.pnlTop1.Controls.Add(this.nudRow); 86 | this.pnlTop1.Controls.Add(this.label3); 87 | this.pnlTop1.Controls.Add(this.nudCol); 88 | this.pnlTop1.Controls.Add(this.label1); 89 | this.pnlTop1.Controls.Add(this.btnStartStopr); 90 | this.pnlTop1.Controls.Add(this.btnShowFrame); 91 | this.pnlTop1.Dock = System.Windows.Forms.DockStyle.Top; 92 | this.pnlTop1.Location = new System.Drawing.Point(0, 0); 93 | this.pnlTop1.Name = "pnlTop1"; 94 | this.pnlTop1.Size = new System.Drawing.Size(334, 19); 95 | this.pnlTop1.TabIndex = 2; 96 | // 97 | // nudRow 98 | // 99 | this.nudRow.Dock = System.Windows.Forms.DockStyle.Left; 100 | this.nudRow.Location = new System.Drawing.Point(246, 0); 101 | this.nudRow.Margin = new System.Windows.Forms.Padding(2); 102 | this.nudRow.Maximum = new decimal(new int[] { 103 | 4, 104 | 0, 105 | 0, 106 | 0}); 107 | this.nudRow.Minimum = new decimal(new int[] { 108 | 1, 109 | 0, 110 | 0, 111 | 0}); 112 | this.nudRow.Name = "nudRow"; 113 | this.nudRow.Size = new System.Drawing.Size(41, 19); 114 | this.nudRow.TabIndex = 4; 115 | this.nudRow.Value = new decimal(new int[] { 116 | 1, 117 | 0, 118 | 0, 119 | 0}); 120 | this.nudRow.ValueChanged += new System.EventHandler(this.nudRow_ValueChanged); 121 | // 122 | // label3 123 | // 124 | this.label3.AutoSize = true; 125 | this.label3.Dock = System.Windows.Forms.DockStyle.Left; 126 | this.label3.Location = new System.Drawing.Point(223, 0); 127 | this.label3.MinimumSize = new System.Drawing.Size(0, 19); 128 | this.label3.Name = "label3"; 129 | this.label3.Size = new System.Drawing.Size(23, 19); 130 | this.label3.TabIndex = 7; 131 | this.label3.Text = "row"; 132 | this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleRight; 133 | // 134 | // nudCol 135 | // 136 | this.nudCol.Dock = System.Windows.Forms.DockStyle.Left; 137 | this.nudCol.Location = new System.Drawing.Point(182, 0); 138 | this.nudCol.Margin = new System.Windows.Forms.Padding(2); 139 | this.nudCol.Maximum = new decimal(new int[] { 140 | 4, 141 | 0, 142 | 0, 143 | 0}); 144 | this.nudCol.Minimum = new decimal(new int[] { 145 | 1, 146 | 0, 147 | 0, 148 | 0}); 149 | this.nudCol.Name = "nudCol"; 150 | this.nudCol.Size = new System.Drawing.Size(41, 19); 151 | this.nudCol.TabIndex = 3; 152 | this.nudCol.Value = new decimal(new int[] { 153 | 1, 154 | 0, 155 | 0, 156 | 0}); 157 | this.nudCol.ValueChanged += new System.EventHandler(this.nudCol_ValueChanged); 158 | // 159 | // label1 160 | // 161 | this.label1.AutoSize = true; 162 | this.label1.Dock = System.Windows.Forms.DockStyle.Left; 163 | this.label1.Location = new System.Drawing.Point(162, 0); 164 | this.label1.MinimumSize = new System.Drawing.Size(0, 19); 165 | this.label1.Name = "label1"; 166 | this.label1.Size = new System.Drawing.Size(20, 19); 167 | this.label1.TabIndex = 6; 168 | this.label1.Text = "col"; 169 | this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight; 170 | // 171 | // nudQuality 172 | // 173 | this.nudQuality.Dock = System.Windows.Forms.DockStyle.Left; 174 | this.nudQuality.Location = new System.Drawing.Point(195, 0); 175 | this.nudQuality.Margin = new System.Windows.Forms.Padding(1, 2, 1, 2); 176 | this.nudQuality.Name = "nudQuality"; 177 | this.nudQuality.Size = new System.Drawing.Size(43, 19); 178 | this.nudQuality.TabIndex = 14; 179 | this.nudQuality.Value = new decimal(new int[] { 180 | 60, 181 | 0, 182 | 0, 183 | 0}); 184 | this.nudQuality.ValueChanged += new System.EventHandler(this.nudQuality_ValueChanged); 185 | // 186 | // label2 187 | // 188 | this.label2.AutoSize = true; 189 | this.label2.Dock = System.Windows.Forms.DockStyle.Left; 190 | this.label2.Location = new System.Drawing.Point(154, 0); 191 | this.label2.MinimumSize = new System.Drawing.Size(0, 19); 192 | this.label2.Name = "label2"; 193 | this.label2.Size = new System.Drawing.Size(41, 19); 194 | this.label2.TabIndex = 13; 195 | this.label2.Text = "Quality"; 196 | this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleRight; 197 | // 198 | // nudHeight 199 | // 200 | this.nudHeight.Dock = System.Windows.Forms.DockStyle.Left; 201 | this.nudHeight.Location = new System.Drawing.Point(111, 0); 202 | this.nudHeight.Margin = new System.Windows.Forms.Padding(1, 2, 1, 2); 203 | this.nudHeight.Maximum = new decimal(new int[] { 204 | 240, 205 | 0, 206 | 0, 207 | 0}); 208 | this.nudHeight.Minimum = new decimal(new int[] { 209 | 8, 210 | 0, 211 | 0, 212 | 0}); 213 | this.nudHeight.Name = "nudHeight"; 214 | this.nudHeight.Size = new System.Drawing.Size(43, 19); 215 | this.nudHeight.TabIndex = 4; 216 | this.nudHeight.Value = new decimal(new int[] { 217 | 120, 218 | 0, 219 | 0, 220 | 0}); 221 | // 222 | // nudWidth 223 | // 224 | this.nudWidth.Dock = System.Windows.Forms.DockStyle.Left; 225 | this.nudWidth.Location = new System.Drawing.Point(32, 0); 226 | this.nudWidth.Margin = new System.Windows.Forms.Padding(1, 2, 1, 2); 227 | this.nudWidth.Maximum = new decimal(new int[] { 228 | 320, 229 | 0, 230 | 0, 231 | 0}); 232 | this.nudWidth.Minimum = new decimal(new int[] { 233 | 8, 234 | 0, 235 | 0, 236 | 0}); 237 | this.nudWidth.Name = "nudWidth"; 238 | this.nudWidth.Size = new System.Drawing.Size(43, 19); 239 | this.nudWidth.TabIndex = 3; 240 | this.nudWidth.Value = new decimal(new int[] { 241 | 160, 242 | 0, 243 | 0, 244 | 0}); 245 | // 246 | // pbPreview 247 | // 248 | this.pbPreview.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; 249 | this.pbPreview.Dock = System.Windows.Forms.DockStyle.Fill; 250 | this.pbPreview.Location = new System.Drawing.Point(0, 0); 251 | this.pbPreview.Name = "pbPreview"; 252 | this.pbPreview.Size = new System.Drawing.Size(334, 243); 253 | this.pbPreview.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; 254 | this.pbPreview.TabIndex = 3; 255 | this.pbPreview.TabStop = false; 256 | // 257 | // timer1 258 | // 259 | this.timer1.Interval = 1; 260 | this.timer1.Tick += new System.EventHandler(this.timer1_Tick); 261 | // 262 | // pnlAll 263 | // 264 | this.pnlAll.Controls.Add(this.pbPreview); 265 | this.pnlAll.Dock = System.Windows.Forms.DockStyle.Fill; 266 | this.pnlAll.Location = new System.Drawing.Point(0, 58); 267 | this.pnlAll.Name = "pnlAll"; 268 | this.pnlAll.Size = new System.Drawing.Size(334, 243); 269 | this.pnlAll.TabIndex = 4; 270 | // 271 | // pnlTop2 272 | // 273 | this.pnlTop2.Controls.Add(this.nudQuality); 274 | this.pnlTop2.Controls.Add(this.label2); 275 | this.pnlTop2.Controls.Add(this.nudHeight); 276 | this.pnlTop2.Controls.Add(this.lblHeight); 277 | this.pnlTop2.Controls.Add(this.nudWidth); 278 | this.pnlTop2.Controls.Add(this.lblWidth); 279 | this.pnlTop2.Dock = System.Windows.Forms.DockStyle.Top; 280 | this.pnlTop2.Location = new System.Drawing.Point(0, 41); 281 | this.pnlTop2.Name = "pnlTop2"; 282 | this.pnlTop2.Size = new System.Drawing.Size(334, 17); 283 | this.pnlTop2.TabIndex = 5; 284 | // 285 | // lblHeight 286 | // 287 | this.lblHeight.AutoSize = true; 288 | this.lblHeight.Dock = System.Windows.Forms.DockStyle.Left; 289 | this.lblHeight.Location = new System.Drawing.Point(75, 0); 290 | this.lblHeight.MinimumSize = new System.Drawing.Size(0, 19); 291 | this.lblHeight.Name = "lblHeight"; 292 | this.lblHeight.Size = new System.Drawing.Size(36, 19); 293 | this.lblHeight.TabIndex = 6; 294 | this.lblHeight.Text = "height"; 295 | this.lblHeight.TextAlign = System.Drawing.ContentAlignment.MiddleRight; 296 | // 297 | // lblWidth 298 | // 299 | this.lblWidth.AutoSize = true; 300 | this.lblWidth.Dock = System.Windows.Forms.DockStyle.Left; 301 | this.lblWidth.Location = new System.Drawing.Point(0, 0); 302 | this.lblWidth.MinimumSize = new System.Drawing.Size(0, 19); 303 | this.lblWidth.Name = "lblWidth"; 304 | this.lblWidth.Size = new System.Drawing.Size(32, 19); 305 | this.lblWidth.TabIndex = 5; 306 | this.lblWidth.Text = "width"; 307 | this.lblWidth.TextAlign = System.Drawing.ContentAlignment.MiddleRight; 308 | // 309 | // tlpHost 310 | // 311 | this.tlpHost.BackColor = System.Drawing.SystemColors.Control; 312 | this.tlpHost.ColumnCount = 1; 313 | this.tlpHost.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); 314 | this.tlpHost.Dock = System.Windows.Forms.DockStyle.Top; 315 | this.tlpHost.Location = new System.Drawing.Point(0, 19); 316 | this.tlpHost.Margin = new System.Windows.Forms.Padding(0); 317 | this.tlpHost.Name = "tlpHost"; 318 | this.tlpHost.RowCount = 1; 319 | this.tlpHost.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 18F)); 320 | this.tlpHost.Size = new System.Drawing.Size(334, 22); 321 | this.tlpHost.TabIndex = 3; 322 | // 323 | // FormSenderMain 324 | // 325 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 326 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 327 | this.ClientSize = new System.Drawing.Size(334, 301); 328 | this.Controls.Add(this.pnlAll); 329 | this.Controls.Add(this.pnlTop2); 330 | this.Controls.Add(this.tlpHost); 331 | this.Controls.Add(this.pnlTop1); 332 | this.Name = "FormSenderMain"; 333 | this.Text = "ScreenShotSender"; 334 | this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormSenderMain_FormClosed); 335 | this.Shown += new System.EventHandler(this.FormSenderMain_Shown); 336 | this.pnlTop1.ResumeLayout(false); 337 | this.pnlTop1.PerformLayout(); 338 | ((System.ComponentModel.ISupportInitialize)(this.nudRow)).EndInit(); 339 | ((System.ComponentModel.ISupportInitialize)(this.nudCol)).EndInit(); 340 | ((System.ComponentModel.ISupportInitialize)(this.nudQuality)).EndInit(); 341 | ((System.ComponentModel.ISupportInitialize)(this.nudHeight)).EndInit(); 342 | ((System.ComponentModel.ISupportInitialize)(this.nudWidth)).EndInit(); 343 | ((System.ComponentModel.ISupportInitialize)(this.pbPreview)).EndInit(); 344 | this.pnlAll.ResumeLayout(false); 345 | this.pnlTop2.ResumeLayout(false); 346 | this.pnlTop2.PerformLayout(); 347 | this.ResumeLayout(false); 348 | 349 | } 350 | 351 | #endregion 352 | 353 | private System.Windows.Forms.Button btnShowFrame; 354 | private System.Windows.Forms.Button btnStartStopr; 355 | private System.Windows.Forms.Panel pnlTop1; 356 | private System.Windows.Forms.PictureBox pbPreview; 357 | private System.Windows.Forms.Timer timer1; 358 | private System.Windows.Forms.Panel pnlAll; 359 | private System.Windows.Forms.NumericUpDown nudWidth; 360 | private System.Windows.Forms.NumericUpDown nudHeight; 361 | private System.Windows.Forms.Panel pnlTop2; 362 | private System.Windows.Forms.Label lblHeight; 363 | private System.Windows.Forms.Label lblWidth; 364 | private System.Windows.Forms.NumericUpDown nudQuality; 365 | private System.Windows.Forms.Label label2; 366 | private System.Windows.Forms.NumericUpDown nudRow; 367 | private System.Windows.Forms.TableLayoutPanel tlpHost; 368 | private System.Windows.Forms.NumericUpDown nudCol; 369 | private System.Windows.Forms.Label label3; 370 | private System.Windows.Forms.Label label1; 371 | } 372 | } 373 | 374 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/FormSenderMain.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Imaging; 5 | using System.IO; 6 | using System.Runtime.InteropServices; 7 | using System.Windows.Forms; 8 | 9 | namespace ScreenShotSender 10 | { 11 | public partial class FormSenderMain : Form 12 | { 13 | FormCaptureBox formCaptureBox = new FormCaptureBox(); 14 | ImageCodecInfo _jpgEncoder = null; 15 | Bitmap _resizeBmp; 16 | Graphics _gResizeBmp; 17 | EncoderParameters _encParams = new EncoderParameters(1); 18 | List _tbHosts = new List(); 19 | List _tcps = new List(); 20 | int _jpgQuality = 60; 21 | int _port = 63333; 22 | System.Diagnostics.Stopwatch _sw; 23 | Rectangle dstRect; 24 | 25 | public FormSenderMain() 26 | { 27 | InitializeComponent(); 28 | } 29 | 30 | private void FormSenderMain_FormClosed(object sender, FormClosedEventArgs e) 31 | { 32 | stop(); 33 | } 34 | 35 | 36 | [DllImport("user32.dll")] 37 | extern static IntPtr GetWindowDC(IntPtr hwnd); 38 | [DllImport("gdi32.dll")] 39 | extern static int GetDeviceCaps(IntPtr hdc, int index); 40 | [DllImport("user32.dll")] 41 | extern static int ReleaseDC(IntPtr hwnd, IntPtr hdc); 42 | 43 | private void FormSenderMain_Shown(object sender, EventArgs e) 44 | { 45 | const int LOGPIXELSX = 88; 46 | const int LOGPIXELSY = 90; 47 | var dc = GetWindowDC(IntPtr.Zero); 48 | var dpiX = GetDeviceCaps(dc, LOGPIXELSX); 49 | var dpiY = GetDeviceCaps(dc, LOGPIXELSY); 50 | ReleaseDC(IntPtr.Zero, dc); 51 | 52 | _sw = new System.Diagnostics.Stopwatch(); 53 | 54 | foreach (ImageCodecInfo ici in ImageCodecInfo.GetImageEncoders()) { 55 | if (ici.FormatID == ImageFormat.Jpeg.Guid) { 56 | _jpgEncoder = ici; 57 | break; 58 | } 59 | } 60 | _jpgQuality = (int)nudQuality.Value; 61 | _encParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, _jpgQuality); 62 | 63 | formCaptureBox.Location = new Point(Location.X + 10, Location.Y + Height); 64 | FrameVisible(true); 65 | 66 | formCaptureBox.Width = 320 * dpiX / 96; 67 | formCaptureBox.Height = 240 * dpiY/ 96; 68 | 69 | tlpHost.RowStyles[0].Height = 18 * dpiY / 96; 70 | 71 | for (int i = 0; i < nudRow.Maximum * nudCol.Maximum; i++) 72 | { 73 | var tb = new TextBox(); 74 | tb.Name = "tbHost" + i.ToString(); 75 | tb.Parent = tlpHost; 76 | tb.Dock = DockStyle.Fill; 77 | tb.Text = "192.168.1.1"; 78 | _tbHosts.Add(tb); 79 | _tcps.Add(new TCPSender()); 80 | } 81 | for (int idx = 0; idx < 4; idx++) 82 | { 83 | var cs = new ColumnStyle(); 84 | cs.SizeType = SizeType.Percent; 85 | cs.Width = tlpHost.ColumnStyles[0].Width; 86 | tlpHost.ColumnStyles.Add(cs); 87 | 88 | var rs = new RowStyle(); 89 | rs.SizeType = tlpHost.RowStyles[0].SizeType; 90 | rs.Height = tlpHost.RowStyles[0].Height; 91 | tlpHost.RowStyles.Add(rs); 92 | } 93 | tlpHost.Height = (int)(tlpHost.RowCount * tlpHost.RowStyles[0].Height) + 3; 94 | 95 | timer1.Enabled = true; 96 | } 97 | 98 | private void nudCol_ValueChanged(object sender, EventArgs e) 99 | { 100 | tlpHost.ColumnCount = (int)nudCol.Value; 101 | } 102 | 103 | private void nudRow_ValueChanged(object sender, EventArgs e) 104 | { 105 | tlpHost.RowCount = (int)nudRow.Value; 106 | tlpHost.Height = (int)(tlpHost.RowCount * tlpHost.RowStyles[0].Height) + 3; 107 | } 108 | 109 | private void nudQuality_ValueChanged(object sender, EventArgs e) 110 | { 111 | _jpgQuality = (int)nudQuality.Value; 112 | _encParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, _jpgQuality); 113 | } 114 | 115 | private void FrameVisible(bool flg) 116 | { 117 | formCaptureBox.Visible = flg; 118 | btnShowFrame.Text = flg ? "HideBox" : "ShowBox"; 119 | } 120 | 121 | private void btnShowFrame_Click(object sender, EventArgs e) 122 | { 123 | FrameVisible(!formCaptureBox.Visible); 124 | if (formCaptureBox.Visible) formCaptureBox.Focus(); 125 | } 126 | 127 | private void btnStartStop_Click(object sender, EventArgs e) 128 | { 129 | if (_sw.IsRunning) stop(); 130 | else start(); 131 | FrameVisible(!_sw.IsRunning); 132 | } 133 | 134 | void start() 135 | { 136 | nudRow.Enabled = false; 137 | nudCol.Enabled = false; 138 | int idx = 0; 139 | for (int row = 0; row < nudRow.Value; row++) 140 | { 141 | for (int col= 0; col < nudCol.Value; col++) 142 | { 143 | _tcps[idx].start(_tbHosts[idx].Text, _port); 144 | idx++; 145 | } 146 | } 147 | _sw.Start(); 148 | btnStartStopr.Text = "Disconnect"; 149 | } 150 | 151 | void stop() 152 | { 153 | _sw?.Stop(); 154 | foreach (var tcp in _tcps) 155 | { 156 | tcp?.stop(); 157 | } 158 | btnStartStopr.Text = "Connect"; 159 | nudRow.Enabled = true; 160 | nudCol.Enabled = true; 161 | } 162 | 163 | private void timer1_Tick(object sender, EventArgs e) 164 | { 165 | timer1.Enabled = false; 166 | 167 | var bmp = formCaptureBox.CaptureFrame(); 168 | pbPreview.Image = bmp; // _resizeBmp; 169 | pbPreview.Invalidate(); 170 | 171 | if (_resizeBmp == null || _resizeBmp.Width != nudWidth.Value || _resizeBmp.Height != nudHeight.Value) 172 | { 173 | _gResizeBmp?.Dispose(); 174 | _resizeBmp?.Dispose(); 175 | _resizeBmp = new Bitmap((int)nudWidth.Value, (int)nudHeight.Value, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 176 | _gResizeBmp = Graphics.FromImage(_resizeBmp); 177 | _gResizeBmp.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed; 178 | } 179 | 180 | dstRect.Width = (int)nudWidth.Value; 181 | dstRect.Height = (int)nudHeight.Value; 182 | 183 | int idx = 0; 184 | float y = 0; 185 | float wid = bmp.Width / (float)nudCol.Value; 186 | float hei = bmp.Height / (float)nudRow.Value; 187 | for (int row = 0; row < nudRow.Value; row++) 188 | { 189 | float x = 0; 190 | for (int col = 0; col < nudCol.Value; col++) 191 | { 192 | _gResizeBmp.DrawImage(bmp, dstRect, x, y, wid, hei, GraphicsUnit.Pixel); 193 | x += wid; 194 | if (_sw.IsRunning) tcpJPGPrepare(_resizeBmp, _tcps[idx]); 195 | idx++; 196 | } 197 | y += hei; 198 | } 199 | 200 | timer1.Enabled = true; 201 | } 202 | 203 | private void tcpJPGPrepare(Bitmap bmp, TCPSender tcp) 204 | { 205 | using (MemoryStream ms = new MemoryStream()) 206 | { 207 | byte[] rgbValues = { 0 }; 208 | ms.WriteByte(0x4A); // prefix "JPG" 3Byte 209 | ms.WriteByte(0x50); 210 | ms.WriteByte(0x47); 211 | ms.WriteByte(0); // data len 4Byte 212 | ms.WriteByte(0); 213 | ms.WriteByte(0); 214 | ms.WriteByte(0); 215 | bmp.Save(ms, _jpgEncoder, _encParams); 216 | ms.Capacity = (int)ms.Length; 217 | rgbValues = ms.GetBuffer(); 218 | { 219 | UInt32 len = (UInt32)(ms.Length - 7); 220 | rgbValues[3] = (byte)(len & 0xFF); 221 | rgbValues[4] = (byte)((len >> 8) & 0xFF); 222 | rgbValues[5] = (byte)((len >> 16) & 0xFF); 223 | rgbValues[6] = (byte)((len >> 24) & 0xFF); 224 | tcp.setData(rgbValues); 225 | } 226 | } 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/FormSenderMain.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace ScreenShotSender 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// アプリケーションのメイン エントリ ポイントです。 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | SetProcessDPIAware(); 18 | Application.EnableVisualStyles(); 19 | Application.SetCompatibleTextRenderingDefault(false); 20 | Application.Run(new FormSenderMain()); 21 | } 22 | 23 | [System.Runtime.InteropServices.DllImport("user32.dll")] 24 | private static extern bool SetProcessDPIAware(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 6 | // アセンブリに関連付けられている情報を変更するには、 7 | // これらの属性値を変更してください。 8 | [assembly: AssemblyTitle("ScreenShotSender")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ScreenShotSender")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから 18 | // 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、 19 | // その型の ComVisible 属性を true に設定してください。 20 | [assembly: ComVisible(false)] 21 | 22 | // このプロジェクトが COM に公開される場合、次の GUID が typelib の ID になります 23 | [assembly: Guid("19e12f0c-cdd2-4d92-bdc6-8a86b0cacd61")] 24 | 25 | // アセンブリのバージョン情報は次の 4 つの値で構成されています: 26 | // 27 | // メジャー バージョン 28 | // マイナー バージョン 29 | // ビルド番号 30 | // Revision 31 | // 32 | // すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます 33 | // 既定値にすることができます: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // このコードはツールによって生成されました。 4 | // ランタイム バージョン:4.0.30319.42000 5 | // 6 | // このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 7 | // コードが再生成されるときに損失したりします。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ScreenShotSender.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。 17 | /// 18 | // このクラスは StronglyTypedResourceBuilder クラスが ResGen 19 | // または Visual Studio のようなツールを使用して自動生成されました。 20 | // メンバーを追加または削除するには、.ResX ファイルを編集して、/str オプションと共に 21 | // ResGen を実行し直すか、または VS プロジェクトをビルドし直します。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// このクラスで使用されているキャッシュされた ResourceManager インスタンスを返します。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ScreenShotSender.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 厳密に型指定されたこのリソース クラスを使用して、すべての検索リソースに対し、 51 | /// 現在のスレッドの CurrentUICulture プロパティをオーバーライドします。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // このコードはツールによって生成されました。 4 | // ランタイム バージョン:4.0.30319.42000 5 | // 6 | // このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 7 | // コードが再生成されるときに損失したりします。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ScreenShotSender.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/ScreenShotSender.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {19E12F0C-CDD2-4D92-BDC6-8A86B0CACD61} 8 | WinExe 9 | ScreenShotSender 10 | ScreenShotSender 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | Form 52 | 53 | 54 | FormCaptureBox.cs 55 | 56 | 57 | Form 58 | 59 | 60 | FormSenderMain.cs 61 | 62 | 63 | 64 | 65 | 66 | FormCaptureBox.cs 67 | 68 | 69 | FormSenderMain.cs 70 | 71 | 72 | ResXFileCodeGenerator 73 | Resources.Designer.cs 74 | Designer 75 | 76 | 77 | True 78 | Resources.resx 79 | True 80 | 81 | 82 | SettingsSingleFileGenerator 83 | Settings.Designer.cs 84 | 85 | 86 | True 87 | Settings.settings 88 | True 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/ScreenShotSender.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | ShowAllFiles 5 | 6 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/ScreenShotSender.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2026 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScreenShotSender", "ScreenShotSender.csproj", "{19E12F0C-CDD2-4D92-BDC6-8A86B0CACD61}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {19E12F0C-CDD2-4D92-BDC6-8A86B0CACD61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {19E12F0C-CDD2-4D92-BDC6-8A86B0CACD61}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {19E12F0C-CDD2-4D92-BDC6-8A86B0CACD61}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {19E12F0C-CDD2-4D92-BDC6-8A86B0CACD61}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {7CE91F5B-AAE1-49DF-87B1-45644A742321} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /通过WiFi接收视频/ScreenShotSender/TCPSender.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Sockets; 3 | using System.Text; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace ScreenShotSender 8 | { 9 | public class TCPSender 10 | { 11 | private Task _task; 12 | private string _addr; 13 | private int _port; 14 | private byte[] _sendBuffer; 15 | private CancellationTokenSource _cts; 16 | 17 | public TCPSender() 18 | { 19 | } 20 | 21 | public void start(string addr, int port) 22 | { 23 | _addr = addr; 24 | _port = port; 25 | _cts = new CancellationTokenSource(); 26 | _task = Task.Run(() => { TaskClient(_cts.Token); }); 27 | } 28 | 29 | public void stop() 30 | { 31 | _cts?.Cancel(); 32 | } 33 | 34 | 35 | public void setData(byte[] src) 36 | { 37 | _sendBuffer = src; 38 | } 39 | 40 | private void TaskClient(CancellationToken ct) 41 | { 42 | byte[] resBytes = new byte[256]; 43 | while (!ct.IsCancellationRequested) 44 | { 45 | try 46 | { 47 | var client = new TcpClient(_addr, _port); 48 | var ns = client.GetStream(); 49 | client.NoDelay = true; 50 | ns.ReadTimeout = 2000; 51 | ns.WriteTimeout = 2000; 52 | var nodatacount = 0; 53 | while (!ct.IsCancellationRequested && client.Connected) 54 | { 55 | try 56 | { 57 | var res = ns.Read(resBytes, 0, resBytes.Length); 58 | if (0 < res) 59 | { 60 | nodatacount = 0; 61 | if (resBytes[0] == 0x4A // "JPG" 62 | && resBytes[1] == 0x50 63 | && resBytes[2] == 0x47 64 | && resBytes[3] == 0x0A) { 65 | var tmp = _sendBuffer; 66 | ns.Write(tmp, 0, tmp.Length); 67 | } 68 | else 69 | { 70 | Console.WriteLine("unknown cmd"); 71 | } 72 | } 73 | else 74 | { 75 | Thread.Sleep(1); 76 | if (++nodatacount > 1000) break; 77 | } 78 | } 79 | catch (Exception ex) 80 | { 81 | //Console.WriteLine(ex.Message); 82 | break; 83 | } 84 | } 85 | ns.Close(); 86 | client.Close(); 87 | } 88 | catch (Exception ex) 89 | { 90 | Console.WriteLine(ex.Message); 91 | } 92 | } 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /通过WiFi接收视频/arduino_ESP32/include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /通过WiFi接收视频/arduino_ESP32/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /通过WiFi接收视频/arduino_ESP32/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:esp32dev] 12 | platform = espressif32 13 | board = esp32dev 14 | framework = arduino 15 | -------------------------------------------------------------------------------- /通过WiFi接收视频/arduino_ESP32/src/DMADrawer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | original source is here. 3 | https://github.com/espressif/esp-idf/blob/master/examples/peripherals/spi_master/main/spi_master_example_main.c 4 | 5 | Modify by lovyan03 6 | */ 7 | 8 | #pragma GCC optimize ("O3") 9 | 10 | #include "DMADrawer.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | static spi_device_handle_t _spi = NULL; 19 | static spi_transaction_t trans[6]; 20 | static gpio_num_t tft_dc_pin, tft_cs_pin; 21 | static uint16_t* _pixBuf[2]; 22 | static uint16_t _lastX, _lastY, _lastW, _lastH; 23 | static uint8_t _pixFlip = 0; 24 | static bool _sent[6]; 25 | 26 | 27 | static void lcd_spi_pre_transfer_callback(spi_transaction_t *t) 28 | { 29 | int dc = (int)t->user; 30 | gpio_set_level(tft_dc_pin, dc); 31 | gpio_set_level(tft_cs_pin, 0); 32 | } 33 | static void lcd_spi_post_transfer_callback(spi_transaction_t *t) 34 | { 35 | gpio_set_level(tft_cs_pin, 1); 36 | } 37 | 38 | static spi_device_handle_t spi_start(uint32_t len, int spi_freq, int tft_mosi, int tft_miso, int tft_sclk, int tft_cs, int tft_dc) 39 | { 40 | tft_dc_pin = (gpio_num_t)tft_dc; 41 | tft_cs_pin = (gpio_num_t)tft_cs; 42 | esp_err_t ret; 43 | spi_device_handle_t hSpi; 44 | spi_bus_config_t buscfg = { 45 | .mosi_io_num = (gpio_num_t)tft_mosi, 46 | .miso_io_num = (gpio_num_t)tft_miso, 47 | .sclk_io_num = (gpio_num_t)tft_sclk, 48 | .quadwp_io_num = -1, 49 | .quadhd_io_num = -1, 50 | .max_transfer_sz = len + 8, 51 | .flags = SPICOMMON_BUSFLAG_MASTER, 52 | .intr_flags = 0}; 53 | ret = spi_bus_initialize(VSPI_HOST, &buscfg, 1); 54 | ESP_ERROR_CHECK(ret); 55 | 56 | spi_device_interface_config_t devcfg = { 57 | .command_bits = 0, 58 | .address_bits = 0, 59 | .dummy_bits = 0, 60 | .mode = 0, //SPI mode 0 61 | .duty_cycle_pos = 0, 62 | .cs_ena_pretrans = 0, 63 | .cs_ena_posttrans = 0, 64 | .clock_speed_hz = spi_freq, 65 | .input_delay_ns = 0, 66 | .spics_io_num = -1, 67 | .flags = SPI_DEVICE_NO_DUMMY, 68 | .queue_size = 7, //We want to be able to queue 7 transactions at a time 69 | .pre_cb = lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line 70 | .post_cb = lcd_spi_post_transfer_callback}; 71 | ret = spi_bus_add_device(VSPI_HOST, &devcfg, &hSpi); 72 | ESP_ERROR_CHECK(ret); 73 | return hSpi; 74 | } 75 | 76 | bool DMADrawer::setup(uint32_t bufsize, int spi_freq, int tft_mosi, int tft_miso, int tft_sclk, int tft_cs, int tft_dc) 77 | { 78 | for (int i = 0; i < 2; ++i) 79 | _pixBuf[i] = (uint16_t*)pvPortMallocCaps(bufsize, MALLOC_CAP_DMA); 80 | _lastX = -1; 81 | _lastY = -1; 82 | _lastW = -1; 83 | _lastH = -1; 84 | for (int i = 0; i < 6; ++i) { 85 | _sent[i] = false; 86 | trans[i].flags = SPI_TRANS_USE_TXDATA; 87 | trans[i].user = (void *)(i & 1); 88 | trans[i].cmd = trans[i].addr = trans[i].rxlength = 0; 89 | trans[i].length = (trans[i].user) ? 8 * 4 : 8; 90 | } 91 | trans[0].tx_data[0] = 0x2A; // Column address set 92 | trans[2].tx_data[0] = 0x2B; // Page address set 93 | trans[4].tx_data[0] = 0x2C; // Memory write 94 | trans[5].flags = 0; 95 | 96 | if (0 <= tft_dc) gpio_set_direction((gpio_num_t)tft_dc, GPIO_MODE_OUTPUT); 97 | if (_spi == NULL) { 98 | _spi = spi_start(bufsize, spi_freq, tft_mosi, tft_miso, tft_sclk, tft_cs, tft_dc); 99 | } 100 | 101 | return true; 102 | } 103 | 104 | void DMADrawer::close() 105 | { 106 | waitDraw(); 107 | for (int i = 0; i < 2; ++i) 108 | free(_pixBuf[i]); 109 | } 110 | 111 | uint16_t* DMADrawer::getNextBuffer() { 112 | return _pixBuf[_pixFlip]; 113 | } 114 | 115 | void DMADrawer::draw(uint16_t x, uint16_t y, uint16_t w, uint16_t h) 116 | { 117 | esp_err_t ret; 118 | spi_transaction_t *tr; 119 | for (uint8_t i = 0; i < 6; i++) 120 | { 121 | if (_sent[i]) { 122 | ret = spi_device_get_trans_result(_spi, &tr, portMAX_DELAY); 123 | assert(ret == ESP_OK); 124 | _sent[i] = false; 125 | } 126 | tr = &trans[i]; 127 | switch (i) { 128 | case 0: 129 | if (_lastX == x && _lastW == w) continue; 130 | break; 131 | 132 | case 1: 133 | if (_lastX == x && _lastW == w) continue; 134 | tr->tx_data[0] = x >> 8; //Start Col High 135 | tr->tx_data[1] = x & 0xFF; //Start Col Low 136 | tr->tx_data[2] = (x + w - 1) >> 8; //End Col High 137 | tr->tx_data[3] = (x + w - 1) & 0xFF; //End Col Low 138 | break; 139 | 140 | case 2: 141 | if (_lastY == y && _lastH == h) continue; 142 | break; 143 | 144 | case 3: 145 | if (_lastY == y && _lastH == h) continue; 146 | tr->tx_data[0] = y >> 8; //Start page high 147 | tr->tx_data[1] = y & 0xFF; //start page low 148 | tr->tx_data[2] = (y + h - 1) >> 8; //end page high 149 | tr->tx_data[3] = (y + h - 1) & 0xFF; //end page low 150 | break; 151 | 152 | case 5: 153 | tr->tx_buffer = _pixBuf[_pixFlip]; //finally send the line data 154 | tr->length = w * h * 16; //Data length, in bits 155 | _pixFlip = !_pixFlip; 156 | break; 157 | 158 | default: 159 | break; 160 | } 161 | tr->rxlength = 0; 162 | ret = spi_device_queue_trans(_spi, tr, portMAX_DELAY); 163 | assert(ret == ESP_OK); 164 | _sent[i] = true; 165 | } 166 | _lastX = x; 167 | _lastY = y; 168 | _lastW = w; 169 | _lastH = h; 170 | } 171 | 172 | void DMADrawer::waitDraw() 173 | { 174 | spi_transaction_t *rtrans; 175 | esp_err_t ret; 176 | for (uint8_t i = 0; i < 6; ++i) 177 | { 178 | if (!_sent[i]) continue; 179 | ret = spi_device_get_trans_result(_spi, &rtrans, portMAX_DELAY); 180 | assert(ret == ESP_OK); 181 | _sent[i] = false; 182 | } 183 | } 184 | 185 | -------------------------------------------------------------------------------- /通过WiFi接收视频/arduino_ESP32/src/DMADrawer.h: -------------------------------------------------------------------------------- 1 | #ifndef _DMADRAWER_H_ 2 | #define _DMADRAWER_H_ 3 | 4 | #include 5 | 6 | struct DMADrawer 7 | { 8 | static bool setup(uint32_t bufsize, int spi_freq, int tft_mosi, int tft_miso, int tft_sclk, int tft_cs, int tft_dc); 9 | static void close(); 10 | static uint16_t* getNextBuffer(); 11 | static void draw(uint16_t x, uint16_t y, uint16_t w, uint16_t h); 12 | static void waitDraw(); 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /通过WiFi接收视频/arduino_ESP32/src/TCPReceiver.h: -------------------------------------------------------------------------------- 1 | #ifndef _TCPRECEIVER_H_ 2 | #define _TCPRECEIVER_H_ 3 | 4 | #pragma GCC optimize ("O3") 5 | 6 | #include 7 | #include 8 | #include 9 | #include "tjpgdClass.h" 10 | #include "DMADrawer.h" 11 | 12 | #undef min 13 | 14 | class TCPReceiver 15 | { 16 | public: 17 | bool setup(uint16_t offset_x, uint16_t offset_y, uint16_t width, uint16_t height, uint32_t spi_freq, int spi_mosi, int spi_miso, int spi_sclk, int tft_cs, int tft_dc) 18 | { 19 | Serial.println("TCPReceiver setup."); 20 | 21 | _tft_offset_x = offset_x; 22 | _tft_offset_y = offset_y; 23 | _tft_width = width; 24 | _tft_height = height; 25 | 26 | _tcp.setNoDelay(true); 27 | _tcp.begin(63333); 28 | 29 | DMADrawer::setup(DMA_BUF_LEN, spi_freq, spi_mosi, spi_miso, spi_sclk, tft_cs, tft_dc); 30 | 31 | _jdec.multitask_begin(); 32 | 33 | Serial.println("TCPReceiver setup done."); 34 | return true; 35 | } 36 | 37 | bool loop() 38 | { 39 | static uint16_t waitCount = 0; 40 | 41 | if (SENDER_PREFIX_SIZE <= _client.available() 42 | && SENDER_PREFIX_SIZE == _client.read(_tcpBuf, SENDER_PREFIX_SIZE)) { 43 | waitCount = 0; 44 | if (_tcpBuf[0] == 'J' 45 | && _tcpBuf[1] == 'P' 46 | && _tcpBuf[2] == 'G') { 47 | _recv_remain = *(int32_t*)&_tcpBuf[3]; 48 | if (_recv_remain > 600) { 49 | if (drawJpg()) { 50 | ++_drawCount; 51 | } 52 | } else { 53 | Serial.println("jpg too short"); 54 | } 55 | if (0 < _recv_remain) { 56 | Serial.printf("clear remain data:%d\r\n", _recv_remain); 57 | int r; 58 | for (uint16_t retry = 1000; retry; --retry) { 59 | r = _client.read(_tcpBuf, _recv_remain < TCP_BUF_LEN ? _recv_remain : TCP_BUF_LEN); 60 | if (r > 0) { 61 | _recv_remain -= r; 62 | if (!_recv_remain) break; 63 | } else { 64 | delay(1); 65 | ++_delayCount; 66 | } 67 | } 68 | } 69 | } else { 70 | Serial.println("broken data"); 71 | delay(10); 72 | while (0 < _client.read(_tcpBuf, TCP_BUF_LEN)) delay(10); 73 | } 74 | } else 75 | if (!_client.connected()) { 76 | _client = _tcp.available(); 77 | _recv_requested = false; 78 | waitCount = 0; 79 | } else { 80 | if (++waitCount > 1000) { 81 | _recv_requested = false; 82 | } else { 83 | delay(1); 84 | ++_delayCount; 85 | } 86 | if (!_recv_requested) { 87 | while (0 < _client.read(_tcpBuf, TCP_BUF_LEN)); 88 | _recv_requested = true; 89 | waitCount = 0; 90 | Serial.println("data request"); 91 | _client.print("JPG\n"); 92 | } 93 | } 94 | 95 | if (_sec != millis() / 1000) { 96 | _sec = millis() / 1000; 97 | Serial.printf("%2d fps", _drawCount); 98 | if (_delayCount) Serial.printf(" / delay%3d", _delayCount); 99 | Serial.print("\r\n"); 100 | _drawCount = 0; 101 | _delayCount = 0; 102 | } 103 | 104 | return true; 105 | } 106 | private: 107 | enum 108 | { DMA_BUF_LEN = 320 * 48 * 2 // 320x48 16bit color 109 | , TCP_BUF_LEN = 512 110 | , SENDER_PREFIX_SIZE = 7 111 | }; 112 | 113 | WiFiServer _tcp; 114 | WiFiClient _client; 115 | TJpgD _jdec; 116 | int32_t _recv_remain = 0; 117 | uint32_t _sec = 0; 118 | uint16_t _tft_offset_x; 119 | uint16_t _tft_offset_y; 120 | uint16_t _tft_width; 121 | uint16_t _tft_height; 122 | uint16_t _out_width; 123 | uint16_t _out_height; 124 | int16_t _off_x; 125 | int16_t _off_y; 126 | int16_t _jpg_x; 127 | int16_t _jpg_y; 128 | uint16_t _drawCount = 0; 129 | uint16_t _delayCount = 0; 130 | uint8_t _rowskip = 2; 131 | uint8_t _tcpBuf[TCP_BUF_LEN]; 132 | bool _recv_requested = false; 133 | 134 | static uint16_t jpgRead(TJpgD *jdec, uint8_t *buf, uint16_t len) { 135 | TCPReceiver* me = (TCPReceiver*)jdec->device; 136 | WiFiClient* client = &me->_client; 137 | uint16_t retry; 138 | 139 | if (len == TJPGD_SZBUF) { 140 | if (me->_recv_requested) { 141 | me->_recv_requested = false; 142 | } else 143 | if (me->_recv_remain < TJPGD_SZBUF*2 && TJPGD_SZBUF < me->_recv_remain) { // dataend read tweak 144 | len = me->_recv_remain - len; 145 | } 146 | } else if (client->available() < len) { 147 | for (retry = 1000; client->available() < len && retry; --retry) { 148 | delay(1); 149 | ++me->_delayCount; 150 | } 151 | } 152 | 153 | int l = client->read(buf ? buf : me->_tcpBuf, len); 154 | if (l <= 0) { 155 | for (retry = 1000; retry; --retry) { 156 | delay(1); 157 | ++me->_delayCount; 158 | l = client->read(buf ? buf : me->_tcpBuf, len); 159 | if (l > 0) break; 160 | } 161 | } 162 | if (l <= 0) { 163 | Serial.printf("jpgRead error:%d:%d:%d\r\n", l, len, client->available()); 164 | return 0; 165 | } 166 | me->_recv_remain -= l; 167 | if (!me->_recv_requested && me->_recv_remain < 3) { 168 | if (me->_recv_remain >= client->available()) { 169 | client->print("JPG\n"); // request the next image from the client 170 | me->_recv_requested = true; 171 | } else { 172 | Serial.println("excessive request"); 173 | me->_recv_requested = true; 174 | } 175 | } 176 | return l; 177 | } 178 | 179 | static uint16_t jpgWrite(TJpgD *jdec, void *bitmap, JRECT *rect) { 180 | TCPReceiver* me = (TCPReceiver*)jdec->device; 181 | uint16_t *dst = DMADrawer::getNextBuffer(); 182 | uint_fast16_t x = rect->left; 183 | uint_fast16_t y = rect->top; 184 | uint_fast16_t w = rect->right + 1 - x; 185 | uint_fast16_t h = rect->bottom + 1 - y; 186 | uint_fast16_t outWidth = me->_out_width; 187 | uint_fast16_t outHeight = me->_out_height; 188 | uint16_t *data = (uint16_t*)bitmap; 189 | uint_fast16_t oL = 0, oR = 0; 190 | 191 | if (rect->right < me->_off_x) return 1; 192 | if (x >= (me->_off_x + outWidth)) return 1; 193 | if (rect->bottom < me->_off_y) return 1; 194 | if (y >= (me->_off_y + outHeight)) return 1; 195 | 196 | uint_fast16_t tmpy = y % ((1 + me->_rowskip) * jdec->msy << 3); 197 | if (me->_off_y > y) { 198 | uint_fast16_t linesToSkip = me->_off_y - y; 199 | data += linesToSkip * w; 200 | h -= linesToSkip; 201 | dst -= tmpy * outWidth; 202 | } else 203 | if (me->_off_y > (y - tmpy)) { 204 | uint_fast16_t linesToSkip = me->_off_y - (y - tmpy); 205 | dst -= linesToSkip * outWidth; 206 | } 207 | 208 | if (me->_off_x > x) { 209 | oL = me->_off_x - x; 210 | } 211 | if (rect->right >= (me->_off_x + outWidth)) { 212 | oR = (rect->right + 1) - (me->_off_x + outWidth); 213 | } 214 | 215 | int_fast16_t line = (w - ( oL + oR )) << 1; 216 | dst += oL + x - me->_off_x + outWidth * tmpy; 217 | data += oL; 218 | do { 219 | memcpy(dst, data, line); 220 | dst += outWidth; 221 | data += w; 222 | } while (--h); 223 | 224 | return 1; 225 | } 226 | 227 | static uint16_t jpgWriteRow(TJpgD *jdec, uint16_t y, uint8_t h) { 228 | TCPReceiver* me = (TCPReceiver*)jdec->device; 229 | 230 | int16_t outY = y - me->_off_y; 231 | if (outY < 0) { 232 | if (h <= - outY) return 1; 233 | h += outY; 234 | outY = 0; 235 | } 236 | if (me->_tft_height <= me->_jpg_y + outY) return 1; 237 | if (me->_tft_height < me->_jpg_y + outY + h) { 238 | h = me->_tft_height - (me->_jpg_y + outY); 239 | } 240 | 241 | DMADrawer::draw( me->_tft_offset_x + me->_jpg_x 242 | , me->_tft_offset_y + me->_jpg_y + outY 243 | , me->_out_width 244 | , h 245 | ); 246 | return 1; 247 | } 248 | 249 | bool drawJpg() { 250 | JRESULT jres = _jdec.prepare(jpgRead, this); 251 | if (jres != JDR_OK) { 252 | Serial.printf("prepare failed! %d\r\n", jres); 253 | return false; 254 | } 255 | _out_width = std::min(_jdec.width, _tft_width); 256 | _jpg_x = (_tft_width - _jdec.width) >> 1; 257 | if (0 > _jpg_x) { 258 | _off_x = - _jpg_x; 259 | _jpg_x = 0; 260 | } else { 261 | _off_x = 0; 262 | } 263 | _out_height = std::min(_jdec.height, _tft_height); 264 | _jpg_y = (_tft_height- _jdec.height) >> 1; 265 | if (0 > _jpg_y) { 266 | _off_y = - _jpg_y; 267 | _jpg_y = 0; 268 | } else { 269 | _off_y = 0; 270 | } 271 | 272 | jres = _jdec.decomp_multitask(jpgWrite, jpgWriteRow, _rowskip); 273 | if (jres != JDR_OK) { 274 | Serial.printf("decomp failed! %d\r\n", jres); 275 | return false; 276 | } 277 | return true; 278 | } 279 | }; 280 | 281 | #endif 282 | -------------------------------------------------------------------------------- /通过WiFi接收视频/arduino_ESP32/src/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma GCC optimize ("O3") 3 | 4 | #include 5 | 6 | TFT_eSPI Tft; 7 | 8 | #include 9 | #include 10 | 11 | #include "TCPReceiver.h" 12 | #include "DMADrawer.h" 13 | 14 | TCPReceiver recv; 15 | 16 | void setup(void) 17 | { 18 | Serial.begin(115200); 19 | Serial.flush(); 20 | Tft.begin(); 21 | 22 | Tft.setRotation(0); 23 | if (Tft.width() < Tft.height()) 24 | Tft.setRotation(1); 25 | 26 | int width = Tft.width(); 27 | int height = Tft.height(); 28 | if (width > 320) width = 320; 29 | if (height > 240) height = 240; 30 | 31 | Tft.setTextFont(2); 32 | 33 | Serial.println("WiFi begin."); 34 | Tft.println("WiFi begin."); 35 | //尝试连接到存储的AP 36 | WiFi.mode(WIFI_MODE_STA); 37 | WiFi.begin(); 38 | 39 | //等待10秒钟再连接 40 | for (int i = 0; WiFi.status() != WL_CONNECTED && i < 100; i++) { delay(100); } 41 | 42 | //如果无法连接,请启动SmartConfig 43 | // https://itunes.apple.com/app/id1071176700 44 | // https://play.google.com/store/apps/details?id=com.cmmakerclub.iot.esptouch 45 | if (WiFi.status() != WL_CONNECTED) { 46 | Serial.print("SmartConfig start."); 47 | Tft.println("SmartConfig start."); 48 | WiFi.mode(WIFI_MODE_APSTA); 49 | WiFi.beginSmartConfig(); 50 | 51 | while (WiFi.status() != WL_CONNECTED) { 52 | delay(100); 53 | } 54 | WiFi.stopSmartConfig(); 55 | WiFi.mode(WIFI_MODE_STA); 56 | } 57 | 58 | Serial.println(String("IP:") + WiFi.localIP().toString()); 59 | Tft.println(WiFi.localIP().toString()); 60 | 61 | setup_t s; 62 | Tft.getSetup(s); 63 | 64 | int spi_freq = SPI_FREQUENCY; 65 | //如果您进入80MHz的重启循环,请尝试降低到40MHz。 66 | //如果(spi_freq> 40000000)spi_freq = 40000000; 67 | 68 | recv.setup( s.r0_x_offset 69 | , s.r0_y_offset 70 | , width 71 | , height 72 | , spi_freq 73 | , TFT_MOSI 74 | , TFT_MISO 75 | , TFT_SCLK 76 | , TFT_CS 77 | , TFT_DC 78 | ); 79 | } 80 | 81 | void loop(void) 82 | { 83 | recv.loop(); 84 | } 85 | -------------------------------------------------------------------------------- /通过WiFi接收视频/arduino_ESP32/src/tjpgdClass.cpp: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / TJpgDec - Tiny JPEG Decompressor R0.01c (C)ChaN, 2019 3 | /-----------------------------------------------------------------------------/ 4 | / The TJpgDec is a generic JPEG decompressor module for tiny embedded systems. 5 | / This is a free software that opened for education, research and commercial 6 | / developments under license policy of following terms. 7 | / 8 | / Copyright (C) 2019, ChaN, all right reserved. 9 | / 10 | / * The TJpgDec module is a free software and there is NO WARRANTY. 11 | / * No restriction on use. You can use, modify and redistribute it for 12 | / personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. 13 | / * Redistributions of source code must retain the above copyright notice. 14 | / 15 | /-----------------------------------------------------------------------------/ 16 | / Oct 04, 2011 R0.01 First release. 17 | / Feb 19, 2012 R0.01a Fixed decompression fails when scan starts with an escape seq. 18 | / Sep 03, 2012 R0.01b Added JD_TBLCLIP option. 19 | / Mar 16, 2019 R0.01c Supprted stdint.h. 20 | /----------------------------------------------------------------------------/ 21 | / modify by lovyan03 22 | / May 29, 2019 Tweak for ArduinoESP32 23 | /----------------------------------------------------------------------------*/ 24 | 25 | #pragma GCC optimize ("O3") 26 | 27 | #include "tjpgdClass.h" 28 | 29 | #include 30 | #include 31 | 32 | /*-----------------------------------------------*/ 33 | /* Zigzag-order to raster-order conversion table */ 34 | /*-----------------------------------------------*/ 35 | 36 | #define ZIG(n) Zig[n] 37 | 38 | static const uint8_t Zig[64] = { /* Zigzag-order to raster-order conversion table */ 39 | 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 40 | 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 41 | 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 42 | 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 43 | }; 44 | 45 | 46 | 47 | /*-------------------------------------------------*/ 48 | /* Input scale factor of Arai algorithm */ 49 | /* (scaled up 16 bits for fixed point operations) */ 50 | /*-------------------------------------------------*/ 51 | 52 | #define IPSF(n) Ipsf[n] 53 | 54 | static const uint16_t Ipsf[64] = { /* See also aa_idct.png */ 55 | (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), 56 | (uint16_t)(1.38704*8192), (uint16_t)(1.92388*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.08979*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.38268*8192), 57 | (uint16_t)(1.30656*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.70711*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.36048*8192), 58 | (uint16_t)(1.17588*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.38268*8192), (uint16_t)(1.17588*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.32442*8192), 59 | (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), 60 | (uint16_t)(0.78570*8192), (uint16_t)(1.08979*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.61732*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.21677*8192), 61 | (uint16_t)(0.54120*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.29290*8192), (uint16_t)(0.14932*8192), 62 | (uint16_t)(0.27590*8192), (uint16_t)(0.38268*8192), (uint16_t)(0.36048*8192), (uint16_t)(0.32442*8192), (uint16_t)(0.27590*8192), (uint16_t)(0.21678*8192), (uint16_t)(0.14932*8192), (uint16_t)(0.07612*8192) 63 | }; 64 | 65 | 66 | 67 | /*---------------------------------------------*/ 68 | /* Output bayer pattern table */ 69 | /*---------------------------------------------*/ 70 | 71 | static const int8_t Bayer[8][16] = { 72 | { 0, 4, 1, 5,-2, 2,-1, 3, 1, 5, 0, 4,-1, 3,-2, 2}, 73 | { 1, 5, 0, 4,-1, 3,-2, 2, 0, 4, 1, 5,-2, 2,-1, 3}, 74 | { 2,-1, 3,-2, 5, 0, 4, 1, 3,-2, 2,-1, 4, 1, 5, 0}, 75 | { 3,-2, 2,-1, 4, 1, 5, 0, 2,-1, 3,-2, 5, 0, 4, 1}, 76 | { 4, 1, 5, 0, 2,-1, 3,-2, 5, 0, 4, 1, 3,-2, 2,-1}, 77 | { 5, 0, 4, 1, 3,-2, 2,-1, 4, 1, 5, 0, 2,-1, 3,-2}, 78 | {-2, 2,-1, 3, 1, 5, 0, 4,-1, 3,-2, 2, 0, 4, 1, 5}, 79 | {-1, 3,-2, 2, 0, 4, 1, 5,-2, 2,-1, 3, 1, 5, 0, 4} 80 | }; 81 | 82 | 83 | /*---------------------------------------------*/ 84 | /* Conversion table for fast clipping process */ 85 | /*---------------------------------------------*/ 86 | 87 | #if JD_TBLCLIP 88 | 89 | #define BYTECLIP(v) Clip8[(uint16_t)(v) & 0x3FF] 90 | 91 | static const uint8_t Clip8[1024] = { 92 | /* 0..255 */ 93 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 94 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 95 | 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96 | 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 97 | 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 98 | 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 99 | 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 100 | 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 101 | /* 256..511 */ 102 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 103 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 104 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 105 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 106 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 107 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 108 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 109 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 110 | /* -512..-257 */ 111 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119 | /* -256..-1 */ 120 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 121 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 128 | }; 129 | 130 | #else /* JD_TBLCLIP */ 131 | 132 | inline uint8_t BYTECLIP ( 133 | int32_t val 134 | ) 135 | { 136 | if (val < 0) val = 0; 137 | else if (val > 255) val = 255; 138 | 139 | return val; 140 | } 141 | 142 | #endif 143 | 144 | 145 | 146 | /*----------------------------------*/ 147 | /* Convert rgb24 to rgb565 with DMA */ 148 | /*----------------------------------*/ 149 | 150 | #define dma565Color(r, g, b) \ 151 | (uint16_t)( ((b >> 3) << 8) | ((g >> 2) << 13) | ((g >> 5) | ((r>>3)<<3))) 152 | 153 | 154 | /*-----------------------------------------------------------------------*/ 155 | /* Allocate a memory block from memory pool */ 156 | /*-----------------------------------------------------------------------*/ 157 | 158 | static void* alloc_pool ( /* Pointer to allocated memory block (NULL:no memory available) */ 159 | TJpgD* jd, /* Pointer to the decompressor object */ 160 | uint16_t nd /* Number of bytes to allocate */ 161 | ) 162 | { 163 | char *rp = 0; 164 | 165 | 166 | nd = (nd + 3) & ~3; /* Align block size to the word boundary */ 167 | 168 | if (jd->sz_pool >= nd) { 169 | jd->sz_pool -= nd; 170 | rp = (char*)jd->pool; /* Get start of available memory pool */ 171 | jd->pool = (void*)(rp + nd); /* Allocate requierd bytes */ 172 | } 173 | 174 | return (void*)rp; /* Return allocated memory block (NULL:no memory to allocate) */ 175 | } 176 | 177 | 178 | 179 | 180 | /*-----------------------------------------------------------------------*/ 181 | /* Create de-quantization and prescaling tables with a DQT segment */ 182 | /*-----------------------------------------------------------------------*/ 183 | 184 | static int create_qt_tbl ( /* 0:OK, !0:Failed */ 185 | TJpgD* jd, /* Pointer to the decompressor object */ 186 | const uint8_t* data, /* Pointer to the quantizer tables */ 187 | uint16_t ndata /* Size of input data */ 188 | ) 189 | { 190 | uint8_t d, z; 191 | int32_t *pb; 192 | 193 | do { /* Process all tables in the segment */ 194 | d = *data++; /* Get table property */ 195 | if (d & 0xF0) return JDR_FMT1; /* Err: not 8-bit resolution */ 196 | pb = (int32_t*)alloc_pool(jd, 64 * sizeof (int32_t));/* Allocate a memory block for the table */ 197 | if (!pb) return JDR_MEM1; /* Err: not enough memory */ 198 | jd->qttbl[d & 3] = pb; /* Register the table */ 199 | for (size_t i = 0; i < 64; ++i) { /* Load the table */ 200 | z = ZIG(i); /* Zigzag-order to raster-order conversion */ 201 | pb[z] = (int32_t)((uint32_t)data[i] * IPSF(z)); /* Apply scale factor of Arai algorithm to the de-quantizers */ 202 | } 203 | data += 64; 204 | } while (ndata -= 65); 205 | 206 | return JDR_OK; 207 | } 208 | 209 | 210 | 211 | 212 | /*-----------------------------------------------------------------------*/ 213 | /* Create huffman code tables with a DHT segment */ 214 | /*-----------------------------------------------------------------------*/ 215 | 216 | static int create_huffman_tbl ( /* 0:OK, !0:Failed */ 217 | TJpgD* jd, /* Pointer to the decompressor object */ 218 | const uint8_t* data, /* Pointer to the packed huffman tables */ 219 | uint16_t ndata /* Size of input data */ 220 | ) 221 | { 222 | uint_fast16_t d, b, np, cls, num, hc; 223 | uint8_t *pb, *pd; 224 | uint16_t *ph; 225 | 226 | 227 | do { /* Process all tables in the segment */ 228 | d = *data++; /* Get table number and class */ 229 | if (d & 0xEE) return JDR_FMT1; /* Err: invalid class/number */ 230 | cls = d >> 4; num = d & 0x0F; /* class = dc(0)/ac(1), table number = 0/1 */ 231 | pb = (uint8_t*)alloc_pool(jd, 16); /* Allocate a memory block for the bit distribution table */ 232 | if (!pb) return JDR_MEM1; /* Err: not enough memory */ 233 | jd->huffbits[num][cls] = pb - 1; 234 | np = 0; 235 | for (size_t i = 0; i < 16; ++i) { /* Load number of patterns for 1 to 16-bit code */ 236 | np += (pb[i] = data[i]); /* Get sum of code words for each code */ 237 | } 238 | 239 | ph = (uint16_t*)alloc_pool(jd, (uint16_t)(np * sizeof (uint16_t)));/* Allocate a memory block for the code word table */ 240 | if (!ph) return JDR_MEM1; /* Err: not enough memory */ 241 | jd->huffcode[num][cls] = ph - 1; 242 | hc = 0; 243 | for (size_t i = 0; i < 16; ++i) { /* Re-build huffman code word table */ 244 | b = pb[i]; 245 | while (b--) *ph++ = hc++; 246 | hc <<= 1; 247 | } 248 | 249 | pd = (uint8_t*)alloc_pool(jd, np); /* Allocate a memory block for the decoded data */ 250 | if (!pd) return JDR_MEM1; /* Err: not enough memory */ 251 | jd->huffdata[num][cls] = pd - 1; 252 | 253 | memcpy(pd, data += 16, np); /* Load decoded data corresponds to each code ward */ 254 | data += np; 255 | } while (ndata -= 17 + np); 256 | 257 | return JDR_OK; 258 | } 259 | 260 | 261 | 262 | 263 | /*-----------------------------------------------------------------------*/ 264 | /* Extract N bits from input stream */ 265 | /*-----------------------------------------------------------------------*/ 266 | 267 | static int16_t bitext ( /* >=0: extracted data, <0: error code */ 268 | TJpgD* jd, /* Pointer to the decompressor object */ 269 | int_fast16_t nbit /* Number of bits to extract (1 to 11) */ 270 | ) 271 | { 272 | uint8_t *dp; 273 | uint_fast8_t msk, s; 274 | uint_fast16_t dc, v; 275 | 276 | msk = jd->dmsk; dc = jd->dctr; dp = jd->dptr; /* Bit mask, number of data available, read ptr */ 277 | s = *dp; v = 0; 278 | size_t shift; 279 | do { 280 | if (!msk) { /* Next byte? */ 281 | bitext_goto: 282 | if (!dc) { /* No input data is available, re-fill input buffer */ 283 | dp = jd->inbuf; /* Top of input buffer */ 284 | dc = jd->infunc(jd, dp, TJPGD_SZBUF); 285 | if (!dc) return 0 - (int16_t)JDR_INP; /* Err: read error or wrong stream termination */ 286 | } else { 287 | ++dp; /* Next data ptr */ 288 | } 289 | --dc; /* Decrement number of available bytes */ 290 | if (!msk) { /* Not in flag sequence? */ 291 | msk = 8; /* Read from MSB */ 292 | s = *dp; /* Get next data byte */ 293 | if (s == 0xFF) { /* Is start of flag sequence? */ 294 | goto bitext_goto; /* Enter flag sequence */ 295 | } 296 | } else { /* Exit flag sequence */ 297 | if (*dp != 0) return 0 - (int32_t)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ 298 | *dp = s = 0xFF; /* The flag is a data 0xFF */ 299 | } 300 | } 301 | shift = msk < nbit ? msk : nbit; 302 | msk -= shift; 303 | if (shift == 8) v = (v << shift) | (s >> msk); 304 | else v = (v << shift) | ((s >> msk) & ((1 << shift) - 1)); /* Get a bit */ 305 | } while (nbit -= shift); 306 | jd->dmsk = msk; jd->dctr = dc; jd->dptr = dp; 307 | 308 | return v; 309 | } 310 | 311 | 312 | 313 | 314 | /*-----------------------------------------------------------------------*/ 315 | /* Extract a huffman decoded data from input stream */ 316 | /*-----------------------------------------------------------------------*/ 317 | 318 | static int16_t huffext ( /* >=0: decoded data, <0: error code */ 319 | TJpgD* jd, /* Pointer to the decompressor object */ 320 | const uint8_t* hbits, /* Pointer to the bit distribution table */ 321 | const uint16_t* hcode, /* Pointer to the code word table */ 322 | const uint8_t* hdata /* Pointer to the data table */ 323 | ) 324 | { 325 | uint_fast8_t msk, s, bl, nd; 326 | uint8_t *dp; 327 | uint_fast16_t dc, v; 328 | 329 | 330 | msk = jd->dmsk; dc = jd->dctr; dp = jd->dptr; /* Bit mask, number of data available, read ptr */ 331 | s = *dp; v = 0; 332 | bl = 16; /* Max code length */ 333 | do { 334 | if (!msk) { /* Next byte? */ 335 | huffext_goto: 336 | if (!dc) { /* No input data is available, re-fill input buffer */ 337 | dp = jd->inbuf; /* Top of input buffer */ 338 | dc = jd->infunc(jd, dp, TJPGD_SZBUF); 339 | if (!dc) return 0 - (int16_t)JDR_INP; /* Err: read error or wrong stream termination */ 340 | } else { 341 | ++dp; /* Next data ptr */ 342 | } 343 | --dc; /* Decrement number of available bytes */ 344 | if (!msk) { /* Not in flag sequence? */ 345 | msk = 8; /* Read from MSB */ 346 | s = *dp; /* Get next data byte */ 347 | if (s == 0xFF) { /* Is start of flag sequence? */ 348 | goto huffext_goto; /* Enter flag sequence, get trailing byte */ 349 | } 350 | } else { /* Exit flag sequence */ 351 | if (*dp != 0) return 0 - (int32_t)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ 352 | *dp = s = 0xFF; /* The flag is a data 0xFF */ 353 | } 354 | } 355 | v = (v << 1) | ((s >> (--msk)) & 1); /* Get a bit */ 356 | 357 | for (nd = *++hbits; nd; --nd) { /* Search the code word in this bit length */ 358 | ++hdata; 359 | if (v == *++hcode) { /* Matched? */ 360 | jd->dmsk = msk; jd->dctr = dc; jd->dptr = dp; 361 | return *hdata; /* Return the decoded data */ 362 | } 363 | } 364 | } while (--bl); 365 | 366 | return 0 - (int16_t)JDR_FMT1; /* Err: code not found (may be collapted data) */ 367 | } 368 | 369 | 370 | 371 | 372 | /*-----------------------------------------------------------------------*/ 373 | /* Apply Inverse-DCT in Arai Algorithm (see also aa_idct.png) */ 374 | /*-----------------------------------------------------------------------*/ 375 | 376 | static void block_idct ( 377 | int32_t* src, /* Input block data (de-quantized and pre-scaled for Arai Algorithm) */ 378 | uint8_t* dst /* Pointer to the destination to store the block as byte array */ 379 | ) 380 | { 381 | const int32_t M13 = (int32_t)(1.41421*256), M2 = (int32_t)(1.08239*256), M4 = (int32_t)(2.61313*256), M5 = (int32_t)(1.84776*256); 382 | int32_t v0, v1, v2, v3, v4, v5, v6, v7; 383 | int32_t t10, t11, t12, t13; 384 | 385 | /* Process columns */ 386 | for (size_t i = 0; i < 8; ++i) { 387 | /* Get and Process the odd elements */ 388 | v4 = src[8 * 7]; 389 | v5 = src[8 * 1]; 390 | v6 = src[8 * 5]; 391 | v7 = src[8 * 3]; 392 | 393 | t10 = v5 - v4; 394 | t11 = v5 + v4; 395 | t12 = v6 - v7; 396 | v7 += v6; 397 | v5 = (t11 - v7) * M13 >> 8; 398 | v7 += t11; 399 | t13 = (t10 + t12) * M5 >> 8; 400 | v6 = t13 - ((t12 * M4 >> 8) + v7); 401 | v5 -= v6; 402 | v4 = t13 - ((t10 * M2 >> 8) + v5); 403 | 404 | /* Get and Process the even elements */ 405 | v0 = src[8 * 0]; 406 | v2 = src[8 * 4]; 407 | t10 = v0 + v2; 408 | t12 = v0 - v2; 409 | 410 | v1 = src[8 * 2]; 411 | v3 = src[8 * 6]; 412 | t11 = (v1 - v3) * M13 >> 8; 413 | v3 += v1; 414 | t11 -= v3; 415 | 416 | v0 = t10 + v3; 417 | v3 = t10 - v3; 418 | v1 = t12 + t11; 419 | v2 = t12 - t11; 420 | 421 | /* Write-back transformed values */ 422 | src[8 * 0] = v0 + v7; 423 | src[8 * 7] = v0 - v7; 424 | src[8 * 1] = v1 + v6; 425 | src[8 * 6] = v1 - v6; 426 | src[8 * 2] = v2 + v5; 427 | src[8 * 5] = v2 - v5; 428 | src[8 * 3] = v3 + v4; 429 | src[8 * 4] = v3 - v4; 430 | 431 | ++src; /* Next column */ 432 | } 433 | 434 | /* Process rows */ 435 | src -= 8; 436 | for (size_t i = 0; i < 8; ++i) { 437 | /* Get and Process the odd elements */ 438 | v4 = src[7]; 439 | v5 = src[1]; 440 | v6 = src[5]; 441 | v7 = src[3]; 442 | t10 = v5 - v4; 443 | t11 = v5 + v4; 444 | t12 = v6 - v7; 445 | v7 += v6; 446 | v5 = (t11 - v7) * M13 >> 8; 447 | v7 += t11; 448 | t13 = (t10 + t12) * M5 >> 8; 449 | v6 = t13 - (t12 * M4 >> 8) - v7; 450 | v4 = t13 - (t10 * M2 >> 8); 451 | v5 -= v6; 452 | v4 -= v5; 453 | 454 | /* Get and Process the even elements */ 455 | v0 = src[0] + (128L << 8); /* remove DC offset (-128) here */ 456 | v2 = src[4]; 457 | t10 = v0 + v2; 458 | t12 = v0 - v2; 459 | 460 | v1 = src[2]; 461 | v3 = src[6]; 462 | t11 = (v1 - v3) * M13 >> 8; 463 | v3 += v1; 464 | t11 -= v3; 465 | 466 | v0 = t10 + v3; 467 | v3 = t10 - v3; 468 | v1 = t12 + t11; 469 | v2 = t12 - t11; 470 | 471 | /* Descale the transformed values 8 bits and output */ 472 | dst[0] = BYTECLIP((v0 + v7) >> 8); 473 | dst[7] = BYTECLIP((v0 - v7) >> 8); 474 | dst[1] = BYTECLIP((v1 + v6) >> 8); 475 | dst[6] = BYTECLIP((v1 - v6) >> 8); 476 | dst[2] = BYTECLIP((v2 + v5) >> 8); 477 | dst[5] = BYTECLIP((v2 - v5) >> 8); 478 | dst[3] = BYTECLIP((v3 + v4) >> 8); 479 | dst[4] = BYTECLIP((v3 - v4) >> 8); 480 | 481 | dst += 8; 482 | src += 8; /* Next row */ 483 | } 484 | } 485 | 486 | 487 | 488 | 489 | /*-----------------------------------------------------------------------*/ 490 | /* Load all blocks in the MCU into working buffer */ 491 | /*-----------------------------------------------------------------------*/ 492 | 493 | static JRESULT mcu_load ( 494 | TJpgD* jd, /* Pointer to the decompressor object */ 495 | uint8_t* bp, /* mcubuf */ 496 | int32_t* tmp /* Block working buffer for de-quantize and IDCT */ 497 | ) 498 | { 499 | int_fast16_t b, d, e; 500 | uint_fast8_t blk, nby, nbc, i, z; 501 | const uint8_t *hb, *hd; 502 | const uint16_t *hc; 503 | 504 | nby = jd->msx * jd->msy; /* Number of Y blocks (1, 2 or 4) */ 505 | nbc = 2; /* Number of C blocks (2) */ 506 | 507 | for (blk = 0; blk < nby + nbc; blk++) { 508 | size_t cmp = (blk < nby) ? 0 : blk - nby + 1; /* Component number 0:Y, 1:Cb, 2:Cr */ 509 | size_t id = cmp ? 1 : 0; /* Huffman table ID of the component */ 510 | 511 | /* Extract a DC element from input stream */ 512 | hb = jd->huffbits[id][0]; /* Huffman table for the DC element */ 513 | hc = jd->huffcode[id][0]; 514 | hd = jd->huffdata[id][0]; 515 | b = huffext(jd, hb, hc, hd); /* Extract a huffman coded data (bit length) */ 516 | if (b < 0) return (JRESULT)(-b); /* Err: invalid code or input */ 517 | d = jd->dcv[cmp]; /* DC value of previous block */ 518 | if (b) { /* If there is any difference from previous block */ 519 | e = bitext(jd, b); /* Extract data bits */ 520 | if (e < 0) return (JRESULT)(-e); /* Err: input */ 521 | b = 1 << (b - 1); /* MSB position */ 522 | if (!(e & b)) e -= (b << 1) - 1; /* Restore sign if needed */ 523 | d += e; /* Get current value */ 524 | jd->dcv[cmp] = d; /* Save current DC value for next block */ 525 | } 526 | const int32_t *dqf = jd->qttbl[jd->qtid[cmp]]; /* De-quantizer table ID for this component */ 527 | tmp[0] = d * dqf[0] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ 528 | 529 | /* Extract following 63 AC elements from input stream */ 530 | memset(&tmp[1], 0, 4 * 63); /* Clear rest of elements */ 531 | hb = jd->huffbits[id][1]; /* Huffman table for the AC elements */ 532 | hc = jd->huffcode[id][1]; 533 | hd = jd->huffdata[id][1]; 534 | i = 1; /* Top of the AC elements */ 535 | do { 536 | b = huffext(jd, hb, hc, hd); /* Extract a huffman coded value (zero runs and bit length) */ 537 | if (b == 0) break; /* EOB? */ 538 | if (b < 0) return (JRESULT)(-b); /* Err: invalid code or input error */ 539 | i += b >> 4; 540 | if (b &= 0x0F) { /* Bit length */ 541 | d = bitext(jd, b); /* Extract data bits */ 542 | if (d < 0) return (JRESULT)(-d);/* Err: input device */ 543 | b = 1 << (b - 1); /* MSB position */ 544 | if (!(d & b)) d -= (b << 1) - 1;/* Restore negative value if needed */ 545 | z = ZIG(i); /* Zigzag-order to raster-order converted index */ 546 | tmp[z] = d * dqf[z] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ 547 | } 548 | } while (++i < 64); /* Next AC element */ 549 | 550 | block_idct(tmp, bp); /* Apply IDCT and store the block to the MCU buffer */ 551 | 552 | bp += 64; /* Next block */ 553 | } 554 | 555 | return JDR_OK; /* All blocks have been loaded successfully */ 556 | } 557 | 558 | 559 | 560 | 561 | /*-----------------------------------------------------------------------*/ 562 | /* Output an MCU: Convert YCrCb to RGB and output it in RGB form */ 563 | /*-----------------------------------------------------------------------*/ 564 | 565 | static JRESULT mcu_output ( 566 | TJpgD* jd, /* Pointer to the decompressor object */ 567 | uint8_t* mcubuf, 568 | uint8_t* workbuf, 569 | uint16_t (*outfunc)(TJpgD*, void*, JRECT*), /* RGB output function */ 570 | uint_fast16_t x, /* MCU position in the image (left of the MCU) */ 571 | uint_fast16_t y /* MCU position in the image (top of the MCU) */ 572 | ) 573 | { 574 | // const int16_t CVACC = (sizeof (int16_t) > 2) ? 1024 : 128; 575 | uint_fast16_t ix, iy, mx, my, rx, ry; 576 | int32_t yy, cb, cr; 577 | uint8_t *py, *pc; 578 | uint16_t *rgb16; 579 | JRECT rect; 580 | 581 | mx = jd->msx * 8; my = jd->msy * 8; /* MCU size (pixel) */ 582 | rx = (x + mx <= jd->width) ? mx : jd->width - x; /* Output rectangular size (it may be clipped at right/bottom end) */ 583 | ry = (y + my <= jd->height) ? my : jd->height - y; 584 | 585 | rect.left = x; rect.right = x + rx - 1; /* Rectangular area in the frame buffer */ 586 | rect.top = y; rect.bottom = y + ry - 1; 587 | 588 | /* Build an RGB MCU from discrete comopnents */ 589 | rgb16 = (uint16_t*)workbuf; 590 | uint_fast8_t r,g,b; 591 | const int8_t* btbase = Bayer[jd->bayer]; 592 | const int8_t* btbl; 593 | uint_fast8_t ixshift = (mx == 16); 594 | uint_fast8_t iyshift = (my == 16); 595 | iy = 0; 596 | do { 597 | btbl = btbase + ((iy & 3) << 2); 598 | py = &mcubuf[((iy & 8) + iy) << 3]; 599 | pc = &mcubuf[((mx << iyshift) + (iy >> iyshift)) << 3]; 600 | ix = 0; 601 | do { 602 | do { 603 | yy = btbl[ix & 3] + py[ix]; /* Get Y component */ 604 | size_t idx = ix >> ixshift; 605 | cb = (pc[idx] - 128); /* Get Cb/Cr component and restore right level */ 606 | cr = (pc[idx + 64] - 128); 607 | 608 | /* Convert YCbCr to RGB */ 609 | r = BYTECLIP(yy + (((int32_t)(1.402 * 256) * cr) >> 8)); 610 | g = BYTECLIP(yy - (((int32_t)(0.34414 * 256) * cb 611 | + (int32_t)(0.71414 * 256) * cr) >> 8)); 612 | b = BYTECLIP(yy + (((int32_t)(1.772 * 256) * cb) >> 8)); 613 | *rgb16++ = dma565Color(r, g, b); 614 | } while (++ix & 7); 615 | py += 64 - 8; /* Jump to next block if double block heigt */ 616 | } while (ix != mx); 617 | } while (++iy != my); 618 | 619 | if (rx < mx) { 620 | uint16_t *s, *d; 621 | s = d = (uint16_t*)workbuf; 622 | for (size_t y = 1; y < ry; ++y) { 623 | memcpy(d += rx, s += mx, rx << 1); /* Copy effective pixels */ 624 | } 625 | } 626 | /* Output the RGB rectangular */ 627 | return outfunc(jd, workbuf, &rect) ? JDR_OK : JDR_INTR; 628 | } 629 | 630 | 631 | 632 | 633 | /*-----------------------------------------------------------------------*/ 634 | /* Process restart interval */ 635 | /*-----------------------------------------------------------------------*/ 636 | 637 | static JRESULT restart ( 638 | TJpgD* jd, /* Pointer to the decompressor object */ 639 | uint16_t rstn /* Expected restert sequense number */ 640 | ) 641 | { 642 | uint_fast16_t dc; 643 | uint16_t d; 644 | uint8_t *dp; 645 | 646 | 647 | /* Discard padding bits and get two bytes from the input stream */ 648 | dp = jd->dptr; dc = jd->dctr; 649 | d = 0; 650 | for (size_t i = 0; i < 2; i++) { 651 | if (!dc) { /* No input data is available, re-fill input buffer */ 652 | dp = jd->inbuf; 653 | dc = jd->infunc(jd, dp, TJPGD_SZBUF); 654 | if (!dc) return JDR_INP; 655 | } else { 656 | dp++; 657 | } 658 | dc--; 659 | d = (d << 8) | *dp; /* Get a byte */ 660 | } 661 | jd->dptr = dp; jd->dctr = dc; jd->dmsk = 0; 662 | 663 | /* Check the marker */ 664 | if ((d & 0xFFD8) != 0xFFD0 || (d & 7) != (rstn & 7)) { 665 | return JDR_FMT1; /* Err: expected RSTn marker is not detected (may be collapted data) */ 666 | } 667 | 668 | /* Reset DC offset */ 669 | jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; 670 | 671 | return JDR_OK; 672 | } 673 | 674 | 675 | 676 | 677 | /*-----------------------------------------------------------------------*/ 678 | /* Analyze the JPEG image and Initialize decompressor object */ 679 | /*-----------------------------------------------------------------------*/ 680 | 681 | #define LDB_WORD(ptr) (uint16_t)(((uint16_t)*((uint8_t*)(ptr))<<8)|(uint16_t)*(uint8_t*)((ptr)+1)) 682 | 683 | 684 | JRESULT TJpgD::prepare ( 685 | uint16_t (*infunc)(TJpgD*, uint8_t*, uint16_t), /* JPEG strem input function */ 686 | void* dev /* I/O device identifier for the session */ 687 | ) 688 | { 689 | uint8_t *seg, b; 690 | uint8_t marker; 691 | uint16_t i, j, len; 692 | JRESULT rc; 693 | 694 | const uint16_t sz_pool = 3100; 695 | static uint8_t pool[sz_pool]; 696 | 697 | 698 | if (!pool) return JDR_PAR; 699 | 700 | this->pool = pool; /* Work memroy */ 701 | this->sz_pool = sz_pool; /* Size of given work memory */ 702 | this->infunc = infunc; /* Stream input function */ 703 | this->device = dev; /* I/O device identifier */ 704 | this->nrst = 0; /* No restart interval (default) */ 705 | 706 | inbuf = seg = dptr = (uint8_t*)alloc_pool(this, TJPGD_SZBUF); /* Allocate stream input buffer */ 707 | if (!seg) return JDR_MEM1; 708 | 709 | dctr = infunc(this, dptr, TJPGD_SZBUF); 710 | seg = dptr; 711 | if (dctr <= 2) return JDR_INP;/* Check SOI marker */ 712 | if (LDB_WORD(seg) != 0xFFD8) return JDR_FMT1; /* Err: SOI is not detected */ 713 | dptr += 2; dctr -= 2; 714 | 715 | for (;;) { 716 | /* Get a JPEG marker */ 717 | if (dctr < 4) { 718 | if (4 > (TJPGD_SZBUF - (dptr - inbuf))) return JDR_MEM2; 719 | dctr += infunc(this, dptr + dctr, 4); 720 | if (dctr < 4) return JDR_INP; 721 | } 722 | seg = dptr; 723 | dptr += 4; 724 | dctr -= 4; 725 | 726 | if (*seg++ != 0xFF) return JDR_FMT1; 727 | marker = *(seg++); /* Marker */ 728 | len = LDB_WORD(seg); /* Length field */ 729 | if (len <= 2) return JDR_FMT1; 730 | len -= 2; /* Content size excluding length field */ 731 | 732 | /* Load segment data */ 733 | if (dctr < len) { 734 | if (len - dctr > (TJPGD_SZBUF - (dptr - inbuf))) return JDR_MEM2; 735 | dctr += infunc(this, dptr + dctr, len - dctr); 736 | if (dctr < len) return JDR_INP; 737 | } 738 | seg = dptr; 739 | dptr += len; 740 | dctr -= len; 741 | switch (marker) { 742 | case 0xC0: /* SOF0 (baseline JPEG) */ 743 | width = LDB_WORD(seg+3); /* Image width in unit of pixel */ 744 | height = LDB_WORD(seg+1); /* Image height in unit of pixel */ 745 | if (seg[5] != 3) return JDR_FMT3; /* Err: Supports only Y/Cb/Cr format */ 746 | 747 | /* Check three image components */ 748 | for (i = 0; i < 3; i++) { 749 | b = seg[7 + 3 * i]; /* Get sampling factor */ 750 | if (!i) { /* Y component */ 751 | if (b != 0x11 && b != 0x22 && b != 0x21) { /* Check sampling factor */ 752 | return JDR_FMT3; /* Err: Supports only 4:4:4, 4:2:0 or 4:2:2 */ 753 | } 754 | msx = b >> 4; msy = b & 15; /* Size of MCU [blocks] */ 755 | } else { /* Cb/Cr component */ 756 | if (b != 0x11) return JDR_FMT3; /* Err: Sampling factor of Cr/Cb must be 1 */ 757 | } 758 | b = seg[8 + 3 * i]; /* Get dequantizer table ID for this component */ 759 | if (b > 3) return JDR_FMT3; /* Err: Invalid ID */ 760 | qtid[i] = b; 761 | } 762 | break; 763 | 764 | case 0xDD: /* DRI */ 765 | /* Get restart interval (MCUs) */ 766 | nrst = LDB_WORD(seg); 767 | break; 768 | 769 | case 0xC4: /* DHT */ 770 | /* Create huffman tables */ 771 | rc = (JRESULT)create_huffman_tbl(this, seg, len); 772 | if (rc) return rc; 773 | break; 774 | 775 | case 0xDB: /* DQT */ 776 | /* Create de-quantizer tables */ 777 | rc = (JRESULT)create_qt_tbl(this, seg, len); 778 | if (rc) return rc; 779 | break; 780 | 781 | case 0xDA: /* SOS */ 782 | if (!width || !height) return JDR_FMT1; /* Err: Invalid image size */ 783 | 784 | if (seg[0] != 3) return JDR_FMT3; /* Err: Supports only three color components format */ 785 | 786 | /* Check if all tables corresponding to each components have been loaded */ 787 | for (i = 0; i < 3; i++) { 788 | b = seg[2 + 2 * i]; /* Get huffman table ID */ 789 | if (b != 0x00 && b != 0x11) return JDR_FMT3; /* Err: Different table number for DC/AC element */ 790 | b = i ? 1 : 0; 791 | if (!huffbits[b][0] || !huffbits[b][1]) { /* Check dc/ac huffman table for this component */ 792 | return JDR_FMT1; /* Err: Nnot loaded */ 793 | } 794 | if (!qttbl[qtid[i]]) { /* Check dequantizer table for this component */ 795 | return JDR_FMT1; /* Err: Not loaded */ 796 | } 797 | } 798 | 799 | /* Allocate working buffer for MCU and RGB */ 800 | if (!msy || !msx) return JDR_FMT1; /* Err: SOF0 has not been loaded */ 801 | dmsk = 0; 802 | --dptr; 803 | 804 | return JDR_OK; /* Initialization succeeded. Ready to decompress the JPEG image. */ 805 | 806 | case 0xC1: /* SOF1 */ 807 | case 0xC2: /* SOF2 */ 808 | case 0xC3: /* SOF3 */ 809 | case 0xC5: /* SOF5 */ 810 | case 0xC6: /* SOF6 */ 811 | case 0xC7: /* SOF7 */ 812 | case 0xC9: /* SOF9 */ 813 | case 0xCA: /* SOF10 */ 814 | case 0xCB: /* SOF11 */ 815 | case 0xCD: /* SOF13 */ 816 | case 0xCE: /* SOF14 */ 817 | case 0xCF: /* SOF15 */ 818 | case 0xD9: /* EOI */ 819 | return JDR_FMT3; /* Unsuppoted JPEG standard (may be progressive JPEG) */ 820 | 821 | default: /* Unknown segment (comment, exif or etc..) */ 822 | break; 823 | } 824 | } 825 | } 826 | 827 | 828 | 829 | 830 | /*-----------------------------------------------------------------------*/ 831 | /* Start to decompress the JPEG picture */ 832 | /*-----------------------------------------------------------------------*/ 833 | 834 | JRESULT TJpgD::decomp ( 835 | uint16_t (*outfunc)(TJpgD*, void*, JRECT*), /* RGB output function */ 836 | uint16_t (*linefunc)(TJpgD*,uint16_t,uint8_t), 837 | uint8_t lineskip /* linefunc skip number */ 838 | ) 839 | { 840 | uint16_t x, y, mx, my; 841 | uint16_t rst, rsc; 842 | JRESULT rc; 843 | uint8_t workbuf[512]; 844 | uint8_t mcubuf[384]; 845 | uint8_t yidx = 0; 846 | 847 | bayer = (bayer + 1) & 7; 848 | 849 | mx = msx * 8; my = msy * 8; /* Size of the MCU (pixel) */ 850 | uint16_t lasty = ((height - 1) / my) * my; 851 | 852 | dcv[2] = dcv[1] = dcv[0] = 0; /* Initialize DC values */ 853 | rst = rsc = 0; 854 | 855 | rc = JDR_OK; 856 | for (y = 0; y < height; y += my) { /* Vertical loop of MCUs */ 857 | for (x = 0; x < width; x += mx) { /* Horizontal loop of MCUs */ 858 | if (nrst && rst++ == nrst) { /* Process restart interval if enabled */ 859 | rc = restart(this, rsc++); 860 | if (rc != JDR_OK) return rc; 861 | rst = 1; 862 | } 863 | rc = mcu_load(this, mcubuf, (int32_t*)workbuf); /* Load an MCU (decompress huffman coded stream and apply IDCT) */ 864 | if (rc != JDR_OK) return rc; 865 | rc = mcu_output(this, mcubuf, (uint8_t*)workbuf, outfunc, x, y); /* Output the MCU (color space conversion, scaling and output) */ 866 | if (rc != JDR_OK) return rc; 867 | } 868 | if (linefunc && (yidx == lineskip || y == lasty)) { 869 | linefunc(this, y - yidx * my, yidx * my + ((height < y + my) ? height - y : my)); 870 | yidx = 0; 871 | } else { 872 | ++yidx; 873 | } 874 | } 875 | 876 | return rc; 877 | } 878 | 879 | 880 | 881 | 882 | 883 | 884 | typedef struct { 885 | uint8_t* mcubuf = NULL; 886 | uint16_t x = 0; 887 | uint16_t y = 0; 888 | uint8_t h = 0; 889 | volatile bool queue = false; 890 | } queue_t; 891 | 892 | typedef struct { 893 | TJpgD* jd; 894 | uint16_t (*outfunc)(TJpgD*, void*, JRECT*); 895 | uint16_t (*linefunc)(TJpgD*,uint16_t,uint8_t); 896 | QueueHandle_t sem; 897 | TaskHandle_t task; 898 | } param_task_output; 899 | 900 | static const uint8_t queue_max = 20; 901 | static param_task_output param; 902 | static uint8_t mcubufs[queue_max + 1][384]; 903 | static queue_t qwrites[queue_max]; 904 | static queue_t qline; 905 | static uint8_t qidx = 0; 906 | static uint8_t mcuidx = 0; 907 | 908 | static void task_output(void* arg) 909 | { 910 | uint8_t workbuf[512]; 911 | param_task_output* p = (param_task_output*)arg; 912 | queue_t* q; 913 | //Serial.println("task_output start"); 914 | for (;;) { 915 | if (!xQueueReceive(p->sem, &q, -1)) continue; 916 | if (!q) break; 917 | //Serial.printf("task work: X=%d,Y=%d\r\n",q->x,q->y); 918 | if (q->h == 0) { 919 | mcu_output(p->jd, q->mcubuf, workbuf, p->outfunc, q->x, q->y); 920 | } else { 921 | p->linefunc(p->jd, q->y, q->h); 922 | } 923 | q->queue = false; 924 | //Serial.println("task work done"); 925 | } 926 | vQueueDelete(p->sem); 927 | //Serial.println("task_output end"); 928 | vTaskDelete(NULL); 929 | } 930 | 931 | void TJpgD::multitask_begin () 932 | { 933 | param.sem = xQueueCreate(queue_max + 1, sizeof(queue_t*)); 934 | 935 | xTaskCreatePinnedToCore(task_output, "task_output", 1600, ¶m, 1, ¶m.task, 0); 936 | } 937 | 938 | void TJpgD::multitask_end () 939 | { 940 | queue_t* q = NULL; 941 | xQueueSend(param.sem, &q, 0); 942 | delay(10); 943 | } 944 | 945 | JRESULT TJpgD::decomp_multitask ( 946 | uint16_t (*outfunc)(TJpgD*, void*, JRECT*), /* RGB output function */ 947 | uint16_t (*linefunc)(TJpgD*,uint16_t,uint8_t), 948 | uint8_t lineskip /* linefunc skip number */ 949 | ) 950 | { 951 | uint16_t x, y, mx, my; 952 | uint16_t rst, rsc; 953 | JRESULT rc; 954 | uint8_t workbuf[512]; 955 | uint8_t yidx = 0; 956 | 957 | 958 | bayer = (bayer + 1) & 7; 959 | 960 | param.jd = this; 961 | param.outfunc = outfunc; 962 | param.linefunc = linefunc; 963 | queue_t* q = &qwrites[qidx]; 964 | queue_t* ql = &qline; 965 | queue_t* qtmp = NULL; 966 | 967 | mx = msx * 8; my = msy * 8; /* Size of the MCU (pixel) */ 968 | 969 | dcv[2] = dcv[1] = dcv[0] = 0; /* Initialize DC values */ 970 | rst = rsc = 0; 971 | uint16_t lasty = ((height - 1) / my) * my; 972 | 973 | rc = JDR_OK; 974 | for (y = 0; y < height; y += my) { /* Vertical loop of MCUs */ 975 | for (x = 0; x < width; x += mx) { /* Horizontal loop of MCUs */ 976 | if (nrst && rst++ == nrst) { /* Process restart interval if enabled */ 977 | rc = restart(this, rsc++); 978 | if (rc != JDR_OK) break; 979 | rst = 1; 980 | } 981 | rc = mcu_load(this, mcubufs[mcuidx], (int32_t*)workbuf); 982 | if (rc != JDR_OK) break; 983 | if (!q->queue) { 984 | //mcubufs[mcuidx][0] = 0; 985 | //mcubufs[mcuidx][1] = 0; 986 | q->mcubuf = mcubufs[mcuidx]; 987 | q->x = x; 988 | q->y = y; 989 | q->queue = true; 990 | xQueueSend(param.sem, &q, 0); 991 | mcuidx = (1 + mcuidx) % (queue_max + 1); 992 | qidx = (1 + qidx) % queue_max; 993 | q = &qwrites[qidx]; 994 | } else { 995 | while (ql->queue) taskYIELD(); 996 | //mcubufs[mcuidx][0] = 0xFF; 997 | //mcubufs[mcuidx][1] = 0xFF; 998 | rc = mcu_output(this, mcubufs[mcuidx], workbuf, outfunc, x, y); 999 | } 1000 | } 1001 | if (rc != JDR_OK) break; 1002 | if (linefunc && (yidx == lineskip || y == lasty)) { 1003 | while (ql->queue) taskYIELD(); 1004 | while (xQueueReceive(param.sem, &qtmp, 0)) { 1005 | //qtmp->mcubuf[0] = 0xFF; 1006 | //qtmp->mcubuf[1] = 0xFF; 1007 | mcu_output(this, qtmp->mcubuf, workbuf, outfunc, qtmp->x, qtmp->y); 1008 | qtmp->queue = false; 1009 | } 1010 | ql->h = (y == lasty) ? (yidx * my + height - y) : ((lineskip + 1) * my); 1011 | ql->y = y - yidx * my; 1012 | ql->queue = true; 1013 | xQueueSend(param.sem, &ql, 0); 1014 | yidx = 0; 1015 | } else { 1016 | ++yidx; 1017 | } 1018 | } 1019 | 1020 | return rc; 1021 | } 1022 | 1023 | 1024 | -------------------------------------------------------------------------------- /通过WiFi接收视频/arduino_ESP32/src/tjpgdClass.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / TJpgDec - Tiny JPEG Decompressor include file (C)ChaN, 2019 3 | /-----------------------------------------------------------------------------/ 4 | / modify by lovyan03 5 | / May 29, 2019 Tweak for ArduinoESP32 6 | /----------------------------------------------------------------------------*/ 7 | 8 | #ifndef _TJPGDEC_H_ 9 | #define _TJPGDEC_H_ 10 | /*---------------------------------------------------------------------------*/ 11 | /* System Configurations */ 12 | 13 | #define TJPGD_SZBUF 1426 /* Size of stream input buffer */ 14 | #define JD_FORMAT 0 /* Output pixel format 0:RGB888 (3 BYTE/pix), 1:RGB565 (1 WORD/pix) */ 15 | #define JD_TBLCLIP 0 /* Use table for saturation (might be a bit faster but increases 1K bytes of code size) */ 16 | 17 | /*---------------------------------------------------------------------------*/ 18 | 19 | 20 | #if defined(_WIN32) /* Main development platform */ 21 | typedef unsigned char uint8_t; 22 | typedef unsigned short uint16_t; 23 | typedef short int16_t; 24 | typedef unsigned long uint32_t; 25 | typedef long int32_t; 26 | #else 27 | #include "stdint.h" 28 | #endif 29 | 30 | /* Error code */ 31 | typedef enum { 32 | JDR_OK = 0, /* 0: Succeeded */ 33 | JDR_INTR, /* 1: Interrupted by output function */ 34 | JDR_INP, /* 2: Device error or wrong termination of input stream */ 35 | JDR_MEM1, /* 3: Insufficient memory pool for the image */ 36 | JDR_MEM2, /* 4: Insufficient stream input buffer */ 37 | JDR_PAR, /* 5: Parameter error */ 38 | JDR_FMT1, /* 6: Data format error (may be damaged data) */ 39 | JDR_FMT2, /* 7: Right format but not supported */ 40 | JDR_FMT3 /* 8: Not supported JPEG standard */ 41 | } JRESULT; 42 | 43 | /* Rectangular structure */ 44 | typedef struct { 45 | uint16_t left, right, top, bottom; 46 | } JRECT; 47 | 48 | /* Decompressor object structure */ 49 | typedef struct TJpgD TJpgD; 50 | struct TJpgD { 51 | uint_fast16_t dctr; /* Number of bytes available in the input buffer */ 52 | uint8_t* dptr; /* Current data read ptr */ 53 | uint8_t* inbuf; /* Bit stream input buffer */ 54 | uint_fast8_t dmsk; /* Current bit in the current read byte */ 55 | uint_fast8_t bayer; /* Output bayer gain */ 56 | uint_fast8_t msx, msy; /* MCU size in unit of block (width, height) */ 57 | uint8_t qtid[3]; /* Quantization table ID of each component */ 58 | int16_t dcv[3]; /* Previous DC element of each component */ 59 | uint16_t nrst; /* Restart inverval */ 60 | uint16_t width, height; /* Size of the input image (pixel) */ 61 | uint8_t* huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */ 62 | uint16_t* huffcode[2][2]; /* Huffman code word tables [id][dcac] */ 63 | uint8_t* huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */ 64 | int32_t* qttbl[4]; /* Dequantizer tables [id] */ 65 | void* pool; /* Pointer to available memory pool */ 66 | uint_fast16_t sz_pool; /* Size of momory pool (bytes available) */ 67 | uint16_t (*infunc)(TJpgD*, uint8_t*, uint16_t);/* Pointer to jpeg stream input function */ 68 | void* device; /* Pointer to I/O device identifiler for the session */ 69 | 70 | 71 | JRESULT prepare (uint16_t(*)(TJpgD*,uint8_t*,uint16_t), void*); 72 | JRESULT decomp (uint16_t(*)(TJpgD*,void*,JRECT*), uint16_t(*)(TJpgD*,uint16_t,uint8_t) = 0, uint8_t = 0); 73 | JRESULT decomp_multitask (uint16_t(*)(TJpgD*,void*,JRECT*), uint16_t(*)(TJpgD*,uint16_t,uint8_t) = 0, uint8_t = 0); 74 | static void multitask_begin (); 75 | static void multitask_end (); 76 | }; 77 | 78 | 79 | 80 | #endif /* _TJPGDEC */ 81 | -------------------------------------------------------------------------------- /通过WiFi接收视频/arduino_ESP32/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /通过WiFi接收视频/esptouch.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modi12jin/arduino-ESP32-Tutorial/e2a96a2bac9e7c4f160b6980d68c5d741e5290e0/通过WiFi接收视频/esptouch.apk --------------------------------------------------------------------------------