Age | Commit message (Collapse) | Author |
|
Add ColorProcessing algorithm that is in charge to manage brightness,
contrast and saturation controls. These controls are currently based on
user controls.
Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Denoise and Sharpness filters will be applied by RkISP1 during the
demosaicing step. The denoise filter is responsible for removing noise
from the image, while the sharpness filter will enhance its acutance.
Add filter algorithm with denoise and sharpness values based on user
controls.
Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
The Defect Pixel Cluster Correction algorithm is responsible to minimize
the impact of defective pixels. The on-the-fly method is actually used,
based on coefficient provided by the tuning file.
Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
The Lens Shading Correction algorithm applies multipliers to all pixels
to compensate for the lens shading effect. The coefficients are
specified in a downscaled table in the YAML tuning file.
Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
The GammaSensorLinearization algorithm linearizes the sensor output to
compensate the sensor non-linearities by applying piecewise linear
functions to the red, green and blue channels.
Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
usage
The std::optional<T>::value_or(U &&default_value) function returns the
contained value if available, or default_value if the std::optional has
no value. If the desired default value is a default-constructed T, the
obvious option is to call std::optional<T>::value_or(T{}). This approach
has two drawbacks:
- The \a default_value T{} is constructed even if the std::optional
instance has a value, which impacts efficiency.
- The T{} default constructor needs to be spelled out explicitly in the
value_or() call, leading to long lines if the type is complex.
Introduce a defopt variable that solves these issues by providing a
value that can be passed to std::optional<T>::value_or() and get
implicitly converted to a default-constructed T.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
|
|
The SDLTexture::update() function isn't meant to modify the data it
receives. Make the Span type const to ensure this at compile time. While
at it, pass the Span by value instead of reference, as a Span is only a
pointer and size, which will fit in registers and will avoid pointer
dereferences in the callee.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
|
|
We were using the libjpeg functionality of SDL2_image only, instead just
use libjpeg directly to reduce our dependancy count, it is a more
commonly available library.
Signed-off-by: Eric Curtin <ecurtin@redhat.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
|
|
Replace the manual implementation of the readList() functions with
YamlObject::getList().
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
|
|
Allow to retrieve a YAML list of any already supported types in a
std::vector.
Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Use the convert_tuning.py script to convert all existing tuning files to
version 2.0.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
|
|
The existing tuning file format (version 1.0) requires the controller algorithms
to run in the same order as listed in the JSON structure. The JSON specification
does not mandate any such ordering, but the Boost JSON parser would maintain
this order.
In order to remove this reliance on the parser to provide ordering, introduce a
new version 2.0 format for the camera tuning file. In this version, the
algorithms are specified in a top level list node ("algorithms"), which does
require strict ordering of the elements.
A "version" node is added to distinguish between the version 1.0 and 2.0
formats. The absence of the "version" node implies version 1.0.
A "target" node is also added to specify the target platform for this
configuration.
Update the controller to support either version of the tuning file by looking
at the version node. CreateAlgorithm member function to now load and configure
each algorithm. Additionally, make CreateAlgorithm a private member, it does not
get called externally.
If a version 1.0 format tuning file is used, throw a warning message indicating
it will be soon deprecated.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
The Raspberry Pi IPA module depends on boost only to parse the JSON
tuning data files. As libcamera depends on libyaml, use the YamlParser
class to parse those files and drop the dependency on boost.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
|
|
Replace the Fatal log messages that cause an abort during tuning data
read with Error messages and proper error propagation to the caller.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
|
|
Update the AGC metering functions that deal with reading tuning data to
propagate errors to the caller, using std::tie and std::tuple to group
the error code and return value.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
|
|
When encountering errors, the Algorithm::read() function either uses
LOG(Fatal) or throws exceptions from the boost property_tree functions.
To prepare for replacing boost JSON parse with the YamlParser class,
give the Algorithm::read() function the ability to return an error code,
and propagate it all the way to the IPA module init() function.
All algorithm classes return a hardcoded 0 value for now, subsequent
commits will change that.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
|
|
Tuning data files mostly use spaces for indentation, with occasional
stray tabs. Use spaces consistently. This allows parsing the tuning
files with libyaml, preparing to replace the dependency on boost.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
|
|
The std::map container used to store dictionary items in YamlObject
doesn't preserve the YAML data order, as maps are ordered by key, not by
insertion order. While this is compliant with the YAML specification
which doesn't guarantee ordering of mappings, the Raspberry Pi IPA
relies on elements being ordered as in the YAML data. To replace the
dependency on boost with the YamlParser class, we thus need to guarantee
that the order is preserved.
Preserve the order by storing items in list_ unconditionally. Turn the
list_ vector from storing YamlObject unique pointers to storing
key-value pairs, with the key being absent when the object is a list,
not a dictionary.
The YamlObject implementation is updated to preserve the existing API,
with the only difference being that YamlObject::memberNames() now
returns member names in the same order as in the YAML file.
The ordering is an implementation detail, so changing it doesn't violate
the YAML specification. The documentation is not updated to reflect
this, as we don't want any new user to rely on a particular ordering.
This commit could be reverted if desired when the Raspberry Pi IPA
updates to a new tuning data format and drops support for the old
format.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
|
|
The YamlObject::get() function takes a default value and an optional
bool ok flag to handle parsing errors. This ad-hoc mechanism complicates
error handling in callers.
A better API is possible by dropping the default value and ok flag and
returning an std::optional. Not only does it simplify the calls, it also
lets callers handle errors through the standard std::optional class
instead of the current ad-hoc mechanism.
Provide a get() wrapper around std::optional::value_or() to further
simplify callers that don't need any specific error handling.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
|
|
Remove "Agc:" as that gets prefixed by the logging system.
s/AgcConfig/AgcMeteringMode/ and s/AgcConfig/AgcMeteringMode where appropriate.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Replace all #define constant values with equivalent constexpr definitions.
As a drive-by, remove the CAMERA_MODE_NAME_LEN constant as it is unused.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Replace all exception throw statements with LOG(RPi*, Fatal) error messages.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
s/Raspberry Pi (Trading) Limited/Raspberry Pi Ltd/ to reflect the new
Raspberry Pi entity name.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
As per the libcamera coding guidelines, rename all .hpp header files to .h.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Since the controller header files are now C++ specific, remove the extern "C"
declarations.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
As part of the on-going refactor efforts for the source files in
src/ipa/raspberrypi/, switch all C++ style comments to C style comments.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Refactor all the source files in src/ipa/raspberrypi/ to match the recommended
formatting guidelines for the libcamera project. The vast majority of changes
in this commit comprise of switching from snake_case to CamelCase, and starting
class member functions with a lower case character.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
"ipa_modules" stores the value of the ipas meson build option. IPAs are
enabled if and only if there is an enabled pipeline for an IPA listed in
"ipa_modules" array. It is basically the intersection of pipelines and
ipa_modules array.
In order to correctly report which IPAs get enabled, let's create a new
array storing this intersection.
Cc: Quentin Schulz <foss+libcamera@0leil.net>
Reported-by: Daniel Semkowicz <dse@thaumatec.com>
Signed-off-by: Quentin Schulz <quentin.schulz@theobroma-systems.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
|
|
CTS calculates FPS with a rounding formula: See
Camera2SurfaceViewTestCase.java:getSuitableFpsRangeForDuration()
fps = floor(1e9 / minFrameDuration + 0.05f)
The android adapter reports it as the AE target FPS. The patch adjusts the
reported minimum frame duration to match the reported FPS.
Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
|
|
Although resolutions (1600x1200) and (1280x960) are not mandatory to be
supported by the Android Camera3 specification, they are commonly used
by Android devices as viewfinder streams for 4:3 still capture.
Add them into stream resolution candidates.
Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
|
|
Previously the thumbnail buffer is destructed before even being used in
Exif. This patch moves the buffer into class Exif, so that the developer
won't need to worry about its lifetime.
Signed-off-by: Harvey Yang <chenghaoyang@chromium.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
|
|
The OpenGL ES shading language has no default precision declared
implicitly for floats in fragment shaders. The lack of an explicit
default precision results in shader compilation errors.
Specify a default precision of mediump for floats. This matches the
other fragment shaders, and is guaranteed by the OpenGL ES shader
language specification to be supported by all devices, while the higher
precision highp is optional.
Signed-off-by: Kunal Agarwal <kunalagarwal1072002@gmail.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Implement rkisp1 queueRequest() function to update each algorithm with user
controls.
Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Add queueRequest() function to the Algorithm class. The queueRequest() function
provides controls values coming from the application to each algorithm.
Each algorithm is responsible for retrieving the controls associated to them.
Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
The logic used to match asynchronous image and embedded buffers was being overly
aggressive by possibly allowing an unmatched image buffer to be sent to the IPA
if the matching embedded buffer had not yet been dequeued. This condition only
occurs when the system is heavily loaded and dropping frames.
Fix this by holding image buffer in the queue during these conditions until the
next embedded buffer dequeue event.
Reported-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Tested-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
SimpleConverter::formats() should return an empty vector if the input
format is not supported by the converter.
Signed-off-by: Xavier Roumegue <xavier.roumegue@oss.nxp.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Forward declarations of IPACameraSensorInfo and inclusion of
linux/rkisp1-config.h are not needed in headers that use them only for
arguments to functions defined by the Algorithm base class, as inclusion
of algorithm.h will bring the necessary declarations for function
arguments. Drop them.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Florian Sylvestre <fsylvestre@baylibre.com>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
|
|
The ControlList::contains(const ControlId &id) function isn't used, as
it has been replaced by usage of the get() function. Document get as
being the preferred way to check for the presence of a control in a
ControlList, and drop the contains() function.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
|
|
The ControlList::get(const Control<T> &ctrl) function has been modified
in commit 1c4d48018505 ("libcamera: controls: Use std::optional to
handle invalid control values") to return an std::optional<>, but its
documentation wasn't updated. Fix it.
Fixes: 1c4d48018505 ("libcamera: controls: Use std::optional to handle invalid control values")
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
|
|
The doxygen document blocks of various ControlList function qualify
functions with full template and return type specification. This isn't
needed, and the extra verbosity makes the documentation blocks more
difficult to read. Drop the template qualifiers and return types. The
generated documentation is not affected.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
|
|
The doxygen '\todo' directory doesn't need to be followed by a colon,
yet a few strayed occurrences have made their way in. Fix them.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
|
|
Some hardware supported by the rkisp1 driver, such as the ISP in the
i.MX8MP, don't have a self path. Although at the moment the driver still
exposes the self path, prepare the rkisp1 pipeline handler for when the
self path will be removed for devices that don't support it.
Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Use the std::vector::back() instead of [0] index which corresponds
to std::vector::push_back() for tracking of pads. This doesn't
introduce a functional change as the gst_libcamera_src_init() will
only add one pad but it helps with readability.
Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Now that the ControlList::get() function returns an instance of
std::optional<>, we can replace the ControlList::contains() calls with a
nullopt check on the return value of get(). This avoids double lookups
of controls through the code base.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
|
|
Previously, ControlList::get<T>() would use default constructed objects to
indicate that a ControlList does not have the requested Control. This has
several disadvantages: 1) It requires types to be default constructible,
2) it does not differentiate between a default constructed object and an
object that happens to have the same state as a default constructed object.
std::optional<T> additionally stores the information if the object is valid
or not, and therefore is more expressive than a default constructed object.
Signed-off-by: Christian Rauch <Rauch.Christian@gmx.de>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Support the X variants of the RGB pixel formats alongside the
equivalent Alpha component based versions.
The QImage::Format_RGB32 and QImage::Format_RGBX8888 formats only
specify that the alpha component must be 0xff. While the Qt
documentation doesn't guarantee that the alpha value will be ignored by
consumers, this seems to be the implemented behaviour, at least when
rendering with QPainter::drawImage().
The existing use of QImage::Format_RGBA8888 is updated to use the
QImage::Format_RGBX8888 variant to ensure that the image data is
visible.
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
|
|
Support the X variants of the RGB pixel formats
along side the equivalent Alpha component based versions.
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
|
|
Update the header orders to match the code style as decreed by
clang-format.
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
|
|
Fix the sort order of the Qt headers to match the expected
sort order from clang-format.
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
|