<div dir="ltr"><font face="monospace">Hello,<br><br>This mail is to discuss libcamera and Android 3A interface, inspired by David's AF and Paul's AE series. And maybe as a preparation for the design for AWB. There was a great discussion on the mailing list about how it can be translated back to Android. Because Android's 3A definition is somehow obscure and inconsistent among 3A. I think it might be good to have an overview of its problem and implications, for easier discussion and reference.<br><br>The article will try to have an overview among 3A in Android Camera3, especially its ambiguity, by categorizing the use cases of 3A in Android. And then to discuss possible design for libcamera as a super set, having a natural translation to Android, and to see if there is something mandatory or missing.<br>Note that there are tables in text which need a fixed-width font for a better view.<br><br>I will refer to the 3A definition in Android from the following documents.<br><a href="https://android.googlesource.com/platform/system/media/+/master/camera/docs">https://android.googlesource.com/platform/system/media/+/master/camera/docs</a><br><a href="https://source.android.com/devices/camera/camera3_3Amodes">https://source.android.com/devices/camera/camera3_3Amodes</a><br><br>In the Android Camera3, there seems to be 4 kinds of use cases that need interaction with the application, and have extensions on controls and states to take care of them. To help further the discussion, I will try to list and describe them briefly, and refer to them with A), B), C), D) for later context. The terms used in Android are sometimes ambiguous. I will try to introduce names to clarify if needed.<br><br>A) Avoid flickering when changing between Auto mode and Manual mode:<br><br>I quote Android's definition for AE here: "Since the camera device has a pipeline of in-flight requests, the settings that get locked do not necessarily correspond to the settings that were present in the latest capture result received from the camera device, since additional captures and AE updates may have occurred even before the result was sent out. If an application is switching between automatic and manual control and wishes to eliminate any flicker during the switch, the following procedure is recommended:"<br><br>1. Starting in auto-AE mode:<br>2. Lock AE<br>3. Wait for the first result to be output that has the AE locked<br>4. Copy exposure settings from that result into a request, set the request to manual AE<br>5. Submit the capture request, proceed to run manual AE as desired.<br><br>One may guess it's similar when changing from Manual to Auto. However, it's not defined clearly in the document:<br><br>1. Starting in Manual-AE mode:<br>2. Set a request to Auto-AE mode and AE lock on.<br>3. Wait for the first result to be output that has the AE locked<br>4. Unlock the AE, so AE can resume from where it was.<br><br>Note that AWB has a similar definition, but no corresponding definition for AF.<br><br>In the definition, the word "Lock" means the "locking down" the result of AE/AWB in Auto mode.<br>The following context will use the word as such. Sometimes Android uses "Lock" as a different meaning.<br>I will use "Metering Done" for that case to avoid ambiguity. See use case B) for details.<br><br>B) Metering a good state in Auto mode quickly and fix done for capture<br><br>The use case is defined by the usage of AEPrecaptureTrigger for AE-Auto mode and AFTrigger for AF-ContinuosVideo/Still mode. The application assumes the algorithm is in a mode, which updates its results continuously for preview. When the application needs a stable state to take a picture, it requests the algorithm to find a good state quickly (good exposure or lens position), and stay in the state. Application will read the frame, and then ask the algorithm to resume to continuous mode for preview. Note that the searching should avoid doing a full scan, but take advantage of current internal states, i.e., if the algorithm is already doing a search, it should follow the momentum to find the good state quickly.<br><br>Take AEPrecapture as an example. The application uses the following sequence:<br><br>1. Starting in auto-AE mode:<br>2. Set AEPrecaptureTrigger as START<br>3. Wait for the metering process done, and output AEState as Converged or FLASH_REQUIRED<br>4. Take a picture<br>5. Set AEPrecaptureTrigger as CANCEL to resume the AE process<br><br>For AF, AFTrigger with AF-ContinuosVideo/Still mode is the same use case.<br><br>The kind of use case implies an internal state for the metering progress. When the progress is done, the algorithm fixes the result of the algorithm, and waits for a resume.<br><br>The word and definition for the progress are very unclear. In AF, Android extends the AFState to indicate that the progress is done and result is fixed, by two special states: FOCUSED_LOCKED, and NOT_FOCUSED_LOCKED. However, the meaning of "Lock" is different from the case A), which is an immediate lock from application, instead of a state reported from the algorithm.<br><br>For AE, it's even worse. The document defines an internal lock which is not reporting back to the application, and assumes the application will understand and cancel the process. There are three ways to cancel the internal lock. I quote them them here:<br><br>  "When a precapture metering sequence is finished, the camera device may lock the auto-exposure routine internally to be able to accurately expose the subsequent still capture image (android.control.captureIntent == STILL_CAPTURE). For this case, the AE may not resume normal scan if no subsequent still capture is submitted. To ensure that the AE routine restarts normal scan, the application should submit a request with android.control.aeLock == true, followed by a request with android.control.aeLock == false, if the application decides not to submit a still capture request after the precapture sequence completes. Alternatively, for API level 23 or newer devices, the CANCEL can be used to unlock the camera device internally locked AE if the application doesn't submit a still capture request after the AE precapture trigger. Note that the CANCEL was added in API level 23, and must not be used in devices that have earlier API levels."<br><br>To clarify the ambiguity, I will use the word "Metering" for this kind of process. And use "Metering Done" for the fixed state at the end of the metering, to distinguish "Lock" from the use case A).<br><br>Note that AWB doesn't have a similar definition.<br><br>C) Trigger a full scan, and fix done<br><br>For AF only, AFTrigger defines the use case with AF-Auto/Macro mode. The case is similar to B). However, the algorithm doesn't run continuously, but only does a full scan when the application triggers it. Like the use case B), it will fix at a good state for the application to take pictures, and resume its state when the application cancels the progress.<br><br>Take AFTrigger as an example. The application uses the following sequence:<br><br>1. Starting in AF-Auto mode:<br>2. Set AFTrigger as START for a single request<br>3. Wait for the scan process done, and output AFState as FOCUSED_LOCKED or NOT_FOCUSED_LOCKED<br>4. Take a picture<br>5. Set AFTrigger as CANCEL to restore its state to AF_STATE_INACTIVE<br><br>Like use case B), Android extends the AFState to indicate that the scan progress is done and result is fixed, by two special states: FOCUSED_LOCKED, and NOT_FOCUSED_LOCKED. Moreover, it adds another AFState AF_STATE_ACTIVE_SCAN to indicate AF is performing the full scan, instead of quick metering of use case B).<br><br>Note that AE and AWB don't have the use case.<br><br>D) Combine of Lock and Metering/Fullscan<br><br>Although it sounds strange, Android allows a combination of Lock and Metering/Fullscan.<br>It's tricky, and implied in the AELock definition. I quote it from the document:<br><br>"If AE precapture is triggered (see android.control.aePrecaptureTrigger) when AE is already locked, the camera device will not change the exposure time (android.sensor.exposureTime) and sensitivity (android.sensor.sensitivity) parameters. The flash may be fired if the android.control.aeMode is ON_AUTO_FLASH/ON_AUTO_FLASH_REDEYE and the scene is too dark."<br><br>It implies if Lock and metering both exist, the Lock has higher priority and will lock the result controls (exposure, sensitivity) from the algorithm. On the other hand, the metering process will still continue until fixing the state as in B), even if it cannot change the controls. However, the metering process can change things which are not locked, like flash for AE in Android.<br><br>Also, according to "The Great AE Series", we can lock (in its term, Disabled) exposure time and analog gain independently.<br>Thus, I imagine there is a more generic way for the use case, for example.<br>The application can lock the analog gain, but the exposure time, and then start a metering process. Thus, the AE algorithm can only change the exposure time to find a good brightness as such:<br><br>1. Starting in AE-Manual mode<br>2. Lock analog gain with a fixed value<br>3. Start the AE Metering process<br>4. Wait for the metering process done, and output AEState as Converged<br>5. Take a picture<br>6. Unlock the analog gain<br>7. Cancel metering process to resume the AE for preview<br><br>I will refer to the four use cases as A), B), C). D), and I conclude them as the following table:<br>+--------------------+-----------+--------------------------+---------------+----------------+<br>| Algorithm/Use Case | (A)       | (B)                      | (C)           | (D)            |<br>+--------------------+-----------+--------------------------+---------------+----------------+<br>| AE                 | AELock +  | AEPrecapture +           | None          | AELock +       |<br>|                    | AE-Auto   | AE-Auto mode             |               | AEPrecapture + |<br>|                    | mode      |                          |               | AE-Auto mode   |<br>+--------------------+-----------+--------------------------+---------------+----------------+<br>| AF                 | None      | AFTrigger +              | AFTrigger +   | None           |<br>|                    |           | AF-ContinuousVideo/Still | AF-Auto/Macro |                |<br>|                    |           | mode                     | mode          |                |<br>+--------------------+-----------+--------------------------+---------------+----------------+<br>| AWB                | AWBLock + | None                     | None          | None           |<br>|                    | AWB-Auto  |                          |               |                |<br>|                    | mode      |                          |               |                |<br>+--------------------+-----------+--------------------------+---------------+----------------+<br><br>I can see the supported use cases are not consistent with all algorithms. For example, AF doesn't have lock function, AWB doesn't have Metering function, AE and AWB doesn't have full scan function, etc. The reason seems to be that Android doesn't think all of them are useful, and historically, each function is added incrementally.<br><br>In theory, the corresponding design for libcamera should be a superset for that of the Android Camera3, and covers all supported cases above. This left me with a question: whether it's useful to define an interface consistent to all algorithms, covering missing cases in the table? In more detail, the questions to ask are as follows, and some thoughts.<br><br>1. Should we add Lock for AF to support A) and D)?<br>  This seems to be reasonable to me. If we'd like to avoid flickers in AE and AWB, we'd like to avoid it in AF too.<br><br>2. Should we add Full Scan for AE to support C)? Should we add Metering and FullScan for AWB to support B) C) D)?<br>  This seems to depend on the implementation of AE and AWB. Need some advice here. In theory, the interface can define them and leave the implementation detail to 3A provider, i.e., Metering and Full Scan may have the same implementation internally.<br><br>3. Metering and FullScan are similar. Should they share the same interface?<br>If so, how to differentiate Metering and FullScan? How would this affect the translation to Android?<br><br>  In Android, it differentiates Metering and FullScan by extending AFMode. "ContinuousVideo" and "ContinuousStill" will do Metering when AFTrigger is started, but "Auto" and "Macro" will do Full Scan instead. In David's design, it is further divided into sub modes. I think it's good to follow the approach. Another way is to add an extra flag to distinguish them.<br><br>  Another problem is that Android extends AFState to express the progress of Metering/FullScan. AF_STATE_ACTIVE_SCAN for FullScanning, FOCUSED_LOCKED and NOT_FOCUSED_LOCKED for "Metering Done". Since in B) and C), it's a state for application to wait, the corresponding state should be added. However, the information seems to be orthogonal to the AFState. Maybe we can add an extra control for it, instead of extending AFState.<br><br>  For AFState translation to Android. If we merge definitions of Metering and FullScan, and differentiate them by modes or a flag, there will be a special case for translating AF_STATE_ACTIVE_SCAN and AF_STATE_PASSIVE_SCAN. See the AFState combination table in later context.<br><br>Some Pros and Cons of adding missing use cases to all 3A:<br>Pros:<br>  1. The interface can be consistent for all algorithms, since we don't need to rule out a function in AF, but another one in AE/AWB.<br>  2. Easier to understand and document common behavior.<br>  3. Application can treat 3A in a consistent way.<br>Cons:<br>  1. Maybe not all cases are meaningful, and the details would be left to the 3A implementor. For example, what's the difference between Metering and Full scan on AWB? Could they be the same implementation internally?<br><br>I think they are up for discussion. Still, based on the above, I draw out a most generic definition to cover everything, and check if there is anything missing. And then to see the influence on simplifying each case. The following are the controls I think needed.<br><br># Input Controls:<br>1. We need controls to choose Manual or Auto mode in A), for each algorithm<br><br>enum AFMode: {Manual, Auto}<br>enum AEMode: {Manual, Auto}<br>enum AWBMode: {Manual, Auto}<br><br>2. We need controls to hint the internal behavior for each algorithm<br><br>For AF:<br>enum AFHint: {ContinuousVideo, ContinuousStill, OnTrigger, MacroOnTrigger, ...}<br>Or a sub mode version:<br>enum AFHintMode: {Continuous, OnTrigger}<br>enum AFHintRange: {Full, Macro, Normal}<br>enum AFHintSpeed: {Fast, Normal}<br><br>For AWB:<br>enum AWBHint: {Normal, Incandescent, Fluorescent, ...}<br><br>For AE:<br>enum AEHintTargetFPS: Lower and upper limits of target FPS<br><br>3. We need controls to lock outputs of each algorithm<br><br>bool AFFocusLock<br>bool AWBCCMLock<br>bool AEExposureTimeLock<br>bool AEAnalogGainLockk<br><br>4. Controls to trigger Metering or Full scan<br><br>enum AFMeterMethod: {Meter, FullScan}<br>enum AEMeterMethod: {Meter, FullScan}<br>enum AWBMeterMethod: {Meter, FullScan}<br><br>enum AFMeteringTrigger: {Idle, MeterStart, Cancel}<br>enum AEMeteringTrigger: {Idle, MeterStart, Cancel}<br>enum AWBMeteringTrigger: {Idle, MeterStart, Cancel}<br><br># Output Controls from the camera<br>1. Controls reporting the 3A calculation state.<br><br>AFState: {Inactive, Searching, Converged, Fail}<br>AEState: {Inactive, Searching, Converged, Fail}<br>AWBState: {Inactive, Searching, Converged, Fail}<br><br>2. Controls reporting the Metering/FullScan state.</font><div><font face="monospace"><br>For all algorithms, when a Metering/FullScan is triggered, the corresponding MeteringState will change to Metering immediately, and the corresponding {AF/AE/AWB}State will change to Searching immediately.<br>When the Metering progress is done, the MeteringState is set to Done and {AF/AE/AWB}State will be set to Converged or Fail. The MeteringState will change back to None, when the Metering/FullScan is canceled by the application.<br><br>enum AFMeteringState: {None, Metering, Done}<br>enum AEMeteringState: {None, Metering, Done}<br>enum AWBMeteringState: {None, Metering, Done}<br><br>3. We need to define valid combinations of a 3A calculation status and a Metering State.<br>+--------------------------------+----------+-----------+-----------+------+<br>| MeteringState/{AF/AE/AWB}State | Inactive | Searching | Converged | Fail |<br>+--------------------------------+----------+-----------+-----------+------+<br>| None                           | Yes      | Yes       | Yes       | Yes  |<br>+--------------------------------+----------+-----------+-----------+------+<br>| Metering                       | No       | Yes       | No        | No   |<br>+--------------------------------+----------+-----------+-----------+------+<br>| Done                           | No       | No        | Yes       | Yes  |<br>+--------------------------------+----------+-----------+-----------+------+<br><br>With the above definition. I can redefine the sequence for the application to do four use cases above.<br>I use AE for example, but they should be consistent to 3A.<br><br>A) Avoid flickering when changing between Auto mode and Manual mode:<br><br>1. Starting in AEMode as "Auto":<br>2. Set AEExposureTimeLock and AEAnalogGainLock to "true"<br>3. Wait for the first result to be output that has the locks<br>4. Copy exposure/gain settings from that result into a request<br>5. Set the request with AEMode as "Manual"<br>5. Submit the capture request, proceed to run manual AE as desired.<br><br>B) Metering a good state in Auto mode quickly and fix done for capture<br><br>1. Starting AEMode as "Auto":<br>2. Set AEMeterMode as "Meter" and AEMeteringTrigger as "MeterStart"<br>3. Wait for the metering process done, and output MeteringState as "Done"<br>4. Take a picture<br>5. Set AEMeteringTrigger as "Cancel" to resume the AE process<br><br>C) Trigger a Full Scan, and fix done for capture<br><br>1. Starting AEMode as "Auto":<br>2. Set AEMeterMode as "FullScan" and AEMeteringTrigger as "MeterStart"<br>3. Wait for the metering process done, and output MeteringState as "Done"<br>4. Take a picture<br>5. Set AEMeteringTrigger as "Cancel" to resume the AE process<br><br>D) Combine of Lock and Metering/Fullscan<br><br>1. Starting in AEMode as "Manual" with a fixed value for analog gain<br>2. Set AEAnalogGainLock as "true"<br>3. Setting AEMode as "Auto", and AEMeteringTrigger as "MeteringStart"<br>4. Wait for the metering process done, and output AEMeteringState as "Done"<br>5. Take a picture<br>2. Set AEAnalogGainLock as "false"<br>6. Set AEMeteringTrigger as "Cancel" to resume the AE process<br><br># Finally we need to verify, in the defintion, if all states can be translated to Android without ambiguity, based on Android's requirements.<br><br>1. Translate AFState back to Android's version.</font></div><div><font face="monospace">Note that the "X" in the table means an invalid combination of MeteringState and AFState.<br>Since Android doesn't define Lock for AF, we can AFLock in the table. Note that when MeteringState is "Metering", we need to check the AFMeterMode to differentiate AF_STATE_ACTIVE_SCAN and AF_STATE_PASSIVE_SCAN.<br><br>+-----------------------------+-------------------+-----------------------+--------------------------+----------------------------+<br>| MeteringState/AFState       | Inactive          | Searching             | Converged                | Fail                       |<br>+-----------------------------+-------------------+-----------------------+--------------------------+----------------------------+<br>| None                        | AF_STATE_INACTIVE | AF_STATE_PASSIVE_SCAN | AF_STATE_PASSIVE_FOCUSED | AF_STATE_PASSIVE_UNFOCUSED |<br>+-----------------------------+-------------------+-----------------------+--------------------------+----------------------------+<br>| Metering with FullScan mode | X                 | AF_STATE_ACTIVE_SCAN  | X                        | X                          |<br>+-----------------------------+-------------------+-----------------------+--------------------------+----------------------------+<br>| Metering with Meter Mode    | X                 | AF_STATE_PASSIVE_SCAN | X                        | X                          |<br>+-----------------------------+-------------------+-----------------------+--------------------------+----------------------------+<br>| Done                        | X                 | X                     | AF_STATE_FOCUSED_LOCKED  | AF_STATE_UNFOCUSED_LOCKED  |<br>+-----------------------------+-------------------+-----------------------+--------------------------+----------------------------+<br><br>2. Translate AEState back to Android's version.</font></div><div><font face="monospace">Note that the "X" in the table means an invalid combination of MeteringState and AEState.<br>Since Android doesn't define Full Scan for AE, we can assume AEMeterMode is alway "Meter"</font></div><div><font face="monospace">The AELock will override the AEState according to Android's definition.</font></div><div><font face="monospace"><br>+-------------------------+-------------------+---------------------+--------------------+--------------------+<br>| MeteringState/AEState   | Inactive          | Searching           | Converged          | Fail               |<br>+-------------------------+-------------------+---------------------+--------------------+--------------------+<br>| None + Locked           | AE_STATE_LOCKED   | AE_STATE_LOCKED     | AE_STATE_LOCKED    | AE_STATE_LOCKED    |<br>+-------------------------+-------------------+---------------------+--------------------+--------------------+<br>| None + Unlocked         | AE_STATE_INACTIVE | AE_STATE_SEARCHING  | AE_STATE_CONVERGED | AE_STATE_CONVERGED |<br>+-------------------------+-------------------+---------------------+--------------------+--------------------+<br>| Metering + Locked       | AE_STATE_LOCKED   | AE_STATE_LOCKED     | AE_STATE_LOCKED    | AE_STATE_LOCKED    |<br>+-------------------------+-------------------+---------------------+--------------------+--------------------+<br>| Metering + Unlocked     | X                 | AE_STATE_PRECAPTURE | X                  | X                  |<br>+-------------------------+-------------------+---------------------+--------------------+--------------------+<br>| Done + Locked           | AE_STATE_LOCKED   | AE_STATE_LOCKED     | AE_STATE_LOCKED    | AE_STATE_LOCKED    |<br>+-------------------------+-------------------+---------------------+--------------------+--------------------+<br>| Done + Unlocked         | X                 | X                   | AE_STATE_CONVERGED | AE_STATE_CONVERGED |<br>+-------------------------+-------------------+---------------------+--------------------+--------------------+<br><br>3. Translate AWBState back to Android's version.<br>Since Android doesn't define Metering/FullScan for AWB, we can assume AWBMetering is never triggered.</font></div><div><span style="font-family:monospace">The AWBLock will override the AWBState according to Android's definition.</span></div><div><font face="monospace"><br>+-------------------------+-------------------+--------------------+---------------------+---------------------+<br>| MeteringState/AWBState  | Inactive          | Searching          | Converged           | Fail                |<br>+-------------------------+-------------------+--------------------+---------------------+---------------------+<br>| Locked                  | AWB_STATE_LOCKED  | AWB_STATE_LOCKED   | AWB_STATE_LOCKED    | AWB_STATE_LOCKED    |<br>+-------------------------+-------------------+--------------------+---------------------+---------------------+<br>| Unlocked                | AE_STATE_INACTIVE | AE_STATE_SEARCHING | AWB_STATE_CONVERGED | AWB_STATE_CONVERGED |<br>+-------------------------+-------------------+--------------------+---------------------+---------------------+<br><br>I think all Android states are covered. Base on the table, something to think when simplifying the definition:<br><br>1. The {AF/AE}MeteringState is a key to translate {AF/AE}State back to Android naturally, otherwise, some states will need special care: AE_STATE_PRECAPTURE, AF_STATE_PASSIVE_FOCUSED, AF_STATE_PASSIVE_UNFOCUSED, AF_STATE_ACTIVE_SCAN, etc.<br><br>2. The {AE/AWB}Lock will override the {AE/AWB}State to its locked state. If we'd like to remove the lock semantics, the translation of {AE/AWB}State needs special care. And also need a way to take care of the use case D).<br><br>3. Some states/flags can be safely removed without affecting the translation, for example: Fail state in {AE/AWB}State, and the FullScan mode for AE and AWB. As mentioned, I really have two minds on whether to reserve them and let the 3A provider decide the implementation details.<br><br>Hope this mail leads to something helpful. Please give me some comments if you will.</font><br></div></div>