1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 #include <stdlib.h>
19 #include <atomic>
20 #include <condition_variable>
21 #include <mutex>
22 #include <queue>
23 #include <thread>
24 
25 #include <android/hardware_buffer.h>
26 #include <jpeglib.h>
27 
28 #include "Buffer.h"
29 #include "FrameProvider.h"
30 #include "Utils.h"
31 
32 // Manages converting from formats available directly from the camera to standardized formats that
33 // transport mechanism eg: UVC over USB + host can understand.
34 namespace android {
35 namespace webcam {
36 
37 struct EncodeRequest {
38     EncodeRequest() = default;
EncodeRequestEncodeRequest39     EncodeRequest(HardwareBufferDesc& buffer, Buffer* producerBuffer, uint32_t rotation)
40         : srcBuffer(buffer), dstBuffer(producerBuffer), rotationDegrees(rotation) {}
41     HardwareBufferDesc srcBuffer;
42     Buffer* dstBuffer = nullptr;
43     uint32_t rotationDegrees = 0;
44 };
45 
46 struct I420 {
47     std::unique_ptr<uint8_t[]> y;
48     std::unique_ptr<uint8_t[]> u;
49     std::unique_ptr<uint8_t[]> v;
50     uint32_t yRowStride = 0;
51     uint32_t uRowStride = 0;
52     uint32_t vRowStride = 0;
53 };
54 
55 class EncoderCallback {
56   public:
57     // Callback called by encoder into client when encoding is finished.
58     virtual void onEncoded(Buffer* producerBuffer, HardwareBufferDesc& srcBuffer, bool success) = 0;
59     virtual ~EncoderCallback() = default;
60 };
61 
62 // Encoder for YUV_420_88 -> YUY2 / MJPEG conversion.
63 class Encoder {
64   public:
65     Encoder(CameraConfig& config, EncoderCallback* cb);
66     ~Encoder();
67 
68     [[nodiscard]] bool isInited() const;
69     void startEncoderThread();
70     void queueRequest(EncodeRequest& request);
71 
72   private:
73     // Main loop of the encoder thread. Calls EncoderCallback.onEncoded which might call back into
74     // java, so encoder thread must be registered with the JVM.
75     void encodeThreadLoop();
76 
77     void encode(EncodeRequest& request);
78 
79     int convertToI420(EncodeRequest& request);
80     uint32_t i420ToJpeg(EncodeRequest& request);
81 
82     void encodeToMJpeg(EncodeRequest& request);
83     void encodeToYUYV(EncodeRequest& request);
84 
85     static bool checkError(const char* msg, j_common_ptr jpeg_error_info_);
86 
87     std::mutex mRequestLock;
88     std::queue<EncodeRequest> mRequestQueue;    // guarded by mRequestLock
89     std::condition_variable mRequestCondition;  // guarded by mRequestLock
90 
91     std::thread mEncoderThread;
92     CameraConfig mConfig;
93     EncoderCallback* mCb = nullptr;
94     volatile bool mContinueEncoding = true;
95     bool mInited = false;
96     I420 mI420;
97 };
98 
99 }  // namespace webcam
100 }  // namespace android
101